1 /* visorchannel_funcs.c
3 * Copyright © 2010 - 2013 UNISYS CORPORATION
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or (at
9 * your option) any later version.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
14 * NON INFRINGEMENT. See the GNU General Public License for more
19 * This provides Supervisor channel communication primitives, which are
20 * independent of the mechanism used to access the channel data. All channel
21 * data is accessed using the memregion abstraction. (memregion has both
22 * a CM2 implementation and a direct memory implementation.)
26 #include "visorchannel.h"
27 #include "guidutils.h"
29 #define MYDRVNAME "visorchannel"
31 struct VISORCHANNEL_Tag
{
32 MEMREGION
*memregion
; /* from visor_memregion_create() */
33 CHANNEL_HEADER chan_hdr
;
37 spinlock_t insert_lock
;
38 spinlock_t remove_lock
;
41 SIGNAL_QUEUE_HEADER req_queue
;
42 SIGNAL_QUEUE_HEADER rsp_queue
;
43 SIGNAL_QUEUE_HEADER event_queue
;
44 SIGNAL_QUEUE_HEADER ack_queue
;
48 /* Creates the VISORCHANNEL abstraction for a data area in memory, but does
49 * NOT modify this data area.
52 visorchannel_create_guts(HOSTADDRESS physaddr
, ulong channelBytes
,
53 VISORCHANNEL
*parent
, ulong off
, GUID guid
,
56 VISORCHANNEL
*p
= NULL
;
59 p
= kmalloc(sizeof(VISORCHANNEL
), GFP_KERNEL
|__GFP_NORETRY
);
61 ERRDRV("allocation failed: (status=0)\n");
66 p
->needs_lock
= needs_lock
;
67 spin_lock_init(&p
->insert_lock
);
68 spin_lock_init(&p
->remove_lock
);
70 /* prepare chan_hdr (abstraction to read/write channel memory) */
73 visor_memregion_create(physaddr
, sizeof(CHANNEL_HEADER
));
76 visor_memregion_create_overlapped(parent
->memregion
,
78 sizeof(CHANNEL_HEADER
));
79 if (p
->memregion
== NULL
) {
80 ERRDRV("visor_memregion_create failed failed: (status=0)\n");
84 if (visor_memregion_read(p
->memregion
, 0, &p
->chan_hdr
,
85 sizeof(CHANNEL_HEADER
)) < 0) {
86 ERRDRV("visor_memregion_read failed: (status=0)\n");
90 if (channelBytes
== 0)
91 /* we had better be a CLIENT of this channel */
92 channelBytes
= (ulong
) p
->chan_hdr
.Size
;
93 if (STRUCTSEQUAL(guid
, Guid0
))
94 /* we had better be a CLIENT of this channel */
95 guid
= p
->chan_hdr
.Type
;
96 if (visor_memregion_resize(p
->memregion
, channelBytes
) < 0) {
97 ERRDRV("visor_memregion_resize failed: (status=0)\n");
101 p
->size
= channelBytes
;
109 visorchannel_destroy(p
);
117 visorchannel_create(HOSTADDRESS physaddr
, ulong channelBytes
, GUID guid
)
119 return visorchannel_create_guts(physaddr
, channelBytes
, NULL
, 0, guid
,
122 EXPORT_SYMBOL_GPL(visorchannel_create
);
125 visorchannel_create_with_lock(HOSTADDRESS physaddr
, ulong channelBytes
,
128 return visorchannel_create_guts(physaddr
, channelBytes
, NULL
, 0, guid
,
131 EXPORT_SYMBOL_GPL(visorchannel_create_with_lock
);
134 visorchannel_create_overlapped(ulong channelBytes
,
135 VISORCHANNEL
*parent
, ulong off
, GUID guid
)
137 return visorchannel_create_guts(0, channelBytes
, parent
, off
, guid
,
140 EXPORT_SYMBOL_GPL(visorchannel_create_overlapped
);
143 visorchannel_create_overlapped_with_lock(ulong channelBytes
,
144 VISORCHANNEL
*parent
, ulong off
,
147 return visorchannel_create_guts(0, channelBytes
, parent
, off
, guid
,
150 EXPORT_SYMBOL_GPL(visorchannel_create_overlapped_with_lock
);
153 visorchannel_destroy(VISORCHANNEL
*channel
)
157 if (channel
->memregion
!= NULL
) {
158 visor_memregion_destroy(channel
->memregion
);
159 channel
->memregion
= NULL
;
163 EXPORT_SYMBOL_GPL(visorchannel_destroy
);
166 visorchannel_get_physaddr(VISORCHANNEL
*channel
)
168 return visor_memregion_get_physaddr(channel
->memregion
);
170 EXPORT_SYMBOL_GPL(visorchannel_get_physaddr
);
173 visorchannel_get_nbytes(VISORCHANNEL
*channel
)
175 return channel
->size
;
177 EXPORT_SYMBOL_GPL(visorchannel_get_nbytes
);
180 visorchannel_GUID_id(GUID
*guid
, char *s
)
182 return GUID_format1(guid
, s
);
184 EXPORT_SYMBOL_GPL(visorchannel_GUID_id
);
187 visorchannel_id(VISORCHANNEL
*channel
, char *s
)
189 return visorchannel_GUID_id(&channel
->guid
, s
);
191 EXPORT_SYMBOL_GPL(visorchannel_id
);
194 visorchannel_zoneid(VISORCHANNEL
*channel
, char *s
)
196 return visorchannel_GUID_id(&channel
->chan_hdr
.ZoneGuid
, s
);
198 EXPORT_SYMBOL_GPL(visorchannel_zoneid
);
201 visorchannel_get_clientpartition(VISORCHANNEL
*channel
)
203 return channel
->chan_hdr
.PartitionHandle
;
205 EXPORT_SYMBOL_GPL(visorchannel_get_clientpartition
);
208 visorchannel_get_GUID(VISORCHANNEL
*channel
)
210 return channel
->guid
;
212 EXPORT_SYMBOL_GPL(visorchannel_get_GUID
);
215 visorchannel_get_memregion(VISORCHANNEL
*channel
)
217 return channel
->memregion
;
219 EXPORT_SYMBOL_GPL(visorchannel_get_memregion
);
222 visorchannel_read(VISORCHANNEL
*channel
, ulong offset
,
223 void *local
, ulong nbytes
)
225 int rc
= visor_memregion_read(channel
->memregion
, offset
,
227 if ((rc
>= 0) && (offset
== 0) && (nbytes
>= sizeof(CHANNEL_HEADER
)))
228 memcpy(&channel
->chan_hdr
, local
, sizeof(CHANNEL_HEADER
));
231 EXPORT_SYMBOL_GPL(visorchannel_read
);
234 visorchannel_write(VISORCHANNEL
*channel
, ulong offset
,
235 void *local
, ulong nbytes
)
237 if (offset
== 0 && nbytes
>= sizeof(CHANNEL_HEADER
))
238 memcpy(&channel
->chan_hdr
, local
, sizeof(CHANNEL_HEADER
));
239 return visor_memregion_write(channel
->memregion
, offset
, local
, nbytes
);
241 EXPORT_SYMBOL_GPL(visorchannel_write
);
244 visorchannel_clear(VISORCHANNEL
*channel
, ulong offset
, U8 ch
, ulong nbytes
)
249 U8
*buf
= vmalloc(bufsize
);
252 ERRDRV("%s failed memory allocation", __func__
);
255 memset(buf
, ch
, bufsize
);
257 ulong thisbytes
= bufsize
;
259 if (nbytes
< thisbytes
)
261 x
= visor_memregion_write(channel
->memregion
, offset
+ written
,
265 written
+= thisbytes
;
277 EXPORT_SYMBOL_GPL(visorchannel_clear
);
280 visorchannel_get_header(VISORCHANNEL
*channel
)
282 return (void *) &(channel
->chan_hdr
);
284 EXPORT_SYMBOL_GPL(visorchannel_get_header
);
286 /** Return offset of a specific SIGNAL_QUEUE_HEADER from the beginning of a
289 #define SIG_QUEUE_OFFSET(chan_hdr, q) \
290 ((chan_hdr)->oChannelSpace + ((q) * sizeof(SIGNAL_QUEUE_HEADER)))
292 /** Return offset of a specific queue entry (data) from the beginning of a
295 #define SIG_DATA_OFFSET(chan_hdr, q, sig_hdr, slot) \
296 (SIG_QUEUE_OFFSET(chan_hdr, q) + (sig_hdr)->oSignalBase + \
297 ((slot) * (sig_hdr)->SignalSize))
299 /** Write the contents of a specific field within a SIGNAL_QUEUE_HEADER back
302 #define SIG_WRITE_FIELD(channel, queue, sig_hdr, FIELD) \
303 (visor_memregion_write(channel->memregion, \
304 SIG_QUEUE_OFFSET(&channel->chan_hdr, queue)+ \
305 offsetof(SIGNAL_QUEUE_HEADER, FIELD), \
306 &((sig_hdr)->FIELD), \
307 sizeof((sig_hdr)->FIELD)) >= 0)
310 sig_read_header(VISORCHANNEL
*channel
, U32 queue
,
311 SIGNAL_QUEUE_HEADER
*sig_hdr
)
315 if (channel
->chan_hdr
.oChannelSpace
< sizeof(CHANNEL_HEADER
)) {
316 ERRDRV("oChannelSpace too small: (status=%d)\n", rc
);
320 /* Read the appropriate SIGNAL_QUEUE_HEADER into local memory. */
322 if (visor_memregion_read(channel
->memregion
,
323 SIG_QUEUE_OFFSET(&channel
->chan_hdr
, queue
),
324 sig_hdr
, sizeof(SIGNAL_QUEUE_HEADER
)) < 0) {
325 ERRDRV("queue=%d SIG_QUEUE_OFFSET=%d",
326 queue
, (int)SIG_QUEUE_OFFSET(&channel
->chan_hdr
, queue
));
327 ERRDRV("visor_memregion_read of signal queue failed: (status=%d)\n", rc
);
336 sig_do_data(VISORCHANNEL
*channel
, U32 queue
,
337 SIGNAL_QUEUE_HEADER
*sig_hdr
, U32 slot
, void *data
, BOOL is_write
)
340 int signal_data_offset
= SIG_DATA_OFFSET(&channel
->chan_hdr
, queue
,
343 if (visor_memregion_write(channel
->memregion
,
345 data
, sig_hdr
->SignalSize
) < 0) {
346 ERRDRV("visor_memregion_write of signal data failed: (status=%d)\n", rc
);
350 if (visor_memregion_read(channel
->memregion
, signal_data_offset
,
351 data
, sig_hdr
->SignalSize
) < 0) {
352 ERRDRV("visor_memregion_read of signal data failed: (status=%d)\n", rc
);
362 sig_read_data(VISORCHANNEL
*channel
, U32 queue
,
363 SIGNAL_QUEUE_HEADER
*sig_hdr
, U32 slot
, void *data
)
365 return sig_do_data(channel
, queue
, sig_hdr
, slot
, data
, FALSE
);
369 sig_write_data(VISORCHANNEL
*channel
, U32 queue
,
370 SIGNAL_QUEUE_HEADER
*sig_hdr
, U32 slot
, void *data
)
372 return sig_do_data(channel
, queue
, sig_hdr
, slot
, data
, TRUE
);
375 static inline unsigned char
376 safe_sig_queue_validate(pSIGNAL_QUEUE_HEADER psafe_sqh
,
377 pSIGNAL_QUEUE_HEADER punsafe_sqh
,
378 U32
*phead
, U32
*ptail
)
380 if ((*phead
>= psafe_sqh
->MaxSignalSlots
)
381 || (*ptail
>= psafe_sqh
->MaxSignalSlots
)) {
382 /* Choose 0 or max, maybe based on current tail value */
386 /* Sync with client as necessary */
387 punsafe_sqh
->Head
= *phead
;
388 punsafe_sqh
->Tail
= *ptail
;
390 ERRDRV("safe_sig_queue_validate: head = 0x%x, tail = 0x%x, MaxSlots = 0x%x",
391 *phead
, *ptail
, psafe_sqh
->MaxSignalSlots
);
395 } /* end safe_sig_queue_validate */
398 visorchannel_signalremove(VISORCHANNEL
*channel
, U32 queue
, void *msg
)
401 SIGNAL_QUEUE_HEADER sig_hdr
;
403 if (channel
->needs_lock
)
404 spin_lock(&channel
->remove_lock
);
406 if (!sig_read_header(channel
, queue
, &sig_hdr
)) {
410 if (sig_hdr
.Head
== sig_hdr
.Tail
) {
411 rc
= FALSE
; /* no signals to remove */
414 sig_hdr
.Tail
= (sig_hdr
.Tail
+ 1) % sig_hdr
.MaxSignalSlots
;
415 if (!sig_read_data(channel
, queue
, &sig_hdr
, sig_hdr
.Tail
, msg
)) {
416 ERRDRV("sig_read_data failed: (status=%d)\n", rc
);
419 sig_hdr
.NumSignalsReceived
++;
421 /* For each data field in SIGNAL_QUEUE_HEADER that was modified,
422 * update host memory.
425 if (!SIG_WRITE_FIELD(channel
, queue
, &sig_hdr
, Tail
)) {
426 ERRDRV("visor_memregion_write of Tail failed: (status=%d)\n",
430 if (!SIG_WRITE_FIELD(channel
, queue
, &sig_hdr
, NumSignalsReceived
)) {
431 ERRDRV("visor_memregion_write of NumSignalsReceived failed: (status=%d)\n", rc
);
436 if (channel
->needs_lock
)
437 spin_unlock(&channel
->remove_lock
);
441 EXPORT_SYMBOL_GPL(visorchannel_signalremove
);
444 visorchannel_signalinsert(VISORCHANNEL
*channel
, U32 queue
, void *msg
)
447 SIGNAL_QUEUE_HEADER sig_hdr
;
449 if (channel
->needs_lock
)
450 spin_lock(&channel
->insert_lock
);
452 if (!sig_read_header(channel
, queue
, &sig_hdr
)) {
457 sig_hdr
.Head
= ((sig_hdr
.Head
+ 1) % sig_hdr
.MaxSignalSlots
);
458 if (sig_hdr
.Head
== sig_hdr
.Tail
) {
459 sig_hdr
.NumOverflows
++;
460 if (!SIG_WRITE_FIELD(channel
, queue
, &sig_hdr
, NumOverflows
)) {
461 ERRDRV("visor_memregion_write of NumOverflows failed: (status=%d)\n", rc
);
468 if (!sig_write_data(channel
, queue
, &sig_hdr
, sig_hdr
.Head
, msg
)) {
469 ERRDRV("sig_write_data failed: (status=%d)\n", rc
);
472 sig_hdr
.NumSignalsSent
++;
474 /* For each data field in SIGNAL_QUEUE_HEADER that was modified,
475 * update host memory.
478 if (!SIG_WRITE_FIELD(channel
, queue
, &sig_hdr
, Head
)) {
479 ERRDRV("visor_memregion_write of Head failed: (status=%d)\n",
483 if (!SIG_WRITE_FIELD(channel
, queue
, &sig_hdr
, NumSignalsSent
)) {
484 ERRDRV("visor_memregion_write of NumSignalsSent failed: (status=%d)\n", rc
);
489 if (channel
->needs_lock
)
490 spin_unlock(&channel
->insert_lock
);
494 EXPORT_SYMBOL_GPL(visorchannel_signalinsert
);
498 visorchannel_signalqueue_slots_avail(VISORCHANNEL
*channel
, U32 queue
)
500 SIGNAL_QUEUE_HEADER sig_hdr
;
501 U32 slots_avail
, slots_used
;
504 if (!sig_read_header(channel
, queue
, &sig_hdr
))
509 head
= head
+ sig_hdr
.MaxSignalSlots
;
510 slots_used
= (head
- tail
);
511 slots_avail
= sig_hdr
.MaxSignals
- slots_used
;
512 return (int) slots_avail
;
514 EXPORT_SYMBOL_GPL(visorchannel_signalqueue_slots_avail
);
517 visorchannel_signalqueue_max_slots(VISORCHANNEL
*channel
, U32 queue
)
519 SIGNAL_QUEUE_HEADER sig_hdr
;
520 if (!sig_read_header(channel
, queue
, &sig_hdr
))
522 return (int) sig_hdr
.MaxSignals
;
524 EXPORT_SYMBOL_GPL(visorchannel_signalqueue_max_slots
);
527 sigqueue_debug(SIGNAL_QUEUE_HEADER
*q
, int which
, struct seq_file
*seq
)
529 seq_printf(seq
, "Signal Queue #%d\n", which
);
530 seq_printf(seq
, " VersionId = %lu\n", (ulong
) q
->VersionId
);
531 seq_printf(seq
, " Type = %lu\n", (ulong
) q
->Type
);
532 seq_printf(seq
, " oSignalBase = %llu\n",
533 (long long) q
->oSignalBase
);
534 seq_printf(seq
, " SignalSize = %lu\n", (ulong
) q
->SignalSize
);
535 seq_printf(seq
, " MaxSignalSlots = %lu\n",
536 (ulong
) q
->MaxSignalSlots
);
537 seq_printf(seq
, " MaxSignals = %lu\n", (ulong
) q
->MaxSignals
);
538 seq_printf(seq
, " FeatureFlags = %-16.16Lx\n",
539 (long long) q
->FeatureFlags
);
540 seq_printf(seq
, " NumSignalsSent = %llu\n",
541 (long long) q
->NumSignalsSent
);
542 seq_printf(seq
, " NumSignalsReceived = %llu\n",
543 (long long) q
->NumSignalsReceived
);
544 seq_printf(seq
, " NumOverflows = %llu\n",
545 (long long) q
->NumOverflows
);
546 seq_printf(seq
, " Head = %lu\n", (ulong
) q
->Head
);
547 seq_printf(seq
, " Tail = %lu\n", (ulong
) q
->Tail
);
551 visorchannel_debug(VISORCHANNEL
*channel
, int nQueues
,
552 struct seq_file
*seq
, U32 off
)
554 HOSTADDRESS addr
= 0;
555 ulong nbytes
= 0, nbytes_region
= 0;
556 MEMREGION
*memregion
= NULL
;
558 CHANNEL_HEADER
*phdr
= &hdr
;
563 if (channel
== NULL
) {
564 ERRDRV("%s no channel", __func__
);
567 memregion
= channel
->memregion
;
568 if (memregion
== NULL
) {
569 ERRDRV("%s no memregion", __func__
);
572 addr
= visor_memregion_get_physaddr(memregion
);
573 nbytes_region
= visor_memregion_get_nbytes(memregion
);
574 errcode
= visorchannel_read(channel
, off
,
575 phdr
, sizeof(CHANNEL_HEADER
));
578 "Read of channel header failed with errcode=%d)\n",
581 phdr
= &channel
->chan_hdr
;
582 seq_puts(seq
, "(following data may be stale)\n");
586 nbytes
= (ulong
) (phdr
->Size
);
587 seq_printf(seq
, "--- Begin channel @0x%-16.16Lx for 0x%lx bytes (region=0x%lx bytes) ---\n",
588 addr
+ off
, nbytes
, nbytes_region
);
589 seq_printf(seq
, "Type = %s\n", GUID_format2(&phdr
->Type
, s
));
590 seq_printf(seq
, "ZoneGuid = %s\n",
591 GUID_format2(&phdr
->ZoneGuid
, s
));
592 seq_printf(seq
, "Signature = 0x%-16.16Lx\n",
593 (long long) phdr
->Signature
);
594 seq_printf(seq
, "LegacyState = %lu\n", (ulong
) phdr
->LegacyState
);
595 seq_printf(seq
, "SrvState = %lu\n", (ulong
) phdr
->SrvState
);
596 seq_printf(seq
, "CliStateBoot = %lu\n", (ulong
) phdr
->CliStateBoot
);
597 seq_printf(seq
, "CliStateOS = %lu\n", (ulong
) phdr
->CliStateOS
);
598 seq_printf(seq
, "HeaderSize = %lu\n", (ulong
) phdr
->HeaderSize
);
599 seq_printf(seq
, "Size = %llu\n", (long long) phdr
->Size
);
600 seq_printf(seq
, "Features = 0x%-16.16llx\n",
601 (long long) phdr
->Features
);
602 seq_printf(seq
, "PartitionHandle = 0x%-16.16llx\n",
603 (long long) phdr
->PartitionHandle
);
604 seq_printf(seq
, "Handle = 0x%-16.16llx\n",
605 (long long) phdr
->Handle
);
606 seq_printf(seq
, "VersionId = %lu\n", (ulong
) phdr
->VersionId
);
607 seq_printf(seq
, "oChannelSpace = %llu\n",
608 (long long) phdr
->oChannelSpace
);
609 if ((phdr
->oChannelSpace
== 0) || (errcode
< 0))
612 for (i
= 0; i
< nQueues
; i
++) {
613 SIGNAL_QUEUE_HEADER q
;
614 errcode
= visorchannel_read(channel
,
615 off
+ phdr
->oChannelSpace
+
620 "failed to read signal queue #%d from channel @0x%-16.16Lx errcode=%d\n",
624 sigqueue_debug(&q
, i
, seq
);
626 seq_printf(seq
, "--- End channel @0x%-16.16Lx for 0x%lx bytes ---\n",
629 EXPORT_SYMBOL_GPL(visorchannel_debug
);
632 visorchannel_dump_section(VISORCHANNEL
*chan
, char *s
,
633 int off
, int len
, struct seq_file
*seq
)
635 char *buf
, *tbuf
, *fmtbuf
;
640 fmtbufsize
= 100 * COVQ(len
, 16);
641 buf
= kmalloc(len
, GFP_KERNEL
|__GFP_NORETRY
);
642 fmtbuf
= kmalloc(fmtbufsize
, GFP_KERNEL
|__GFP_NORETRY
);
643 if (buf
== NULL
|| fmtbuf
== NULL
)
646 errcode
= visorchannel_read(chan
, off
, buf
, len
);
648 ERRDRV("%s failed to read %s from channel errcode=%d",
649 s
, __func__
, errcode
);
652 seq_printf(seq
, "channel %s:\n", s
);
655 i
= (len
< 16) ? len
: 16;
656 hex_dump_to_buffer(tbuf
, i
, 16, 1, fmtbuf
, fmtbufsize
, TRUE
);
657 seq_printf(seq
, "%s\n", fmtbuf
);
667 if (fmtbuf
!= NULL
) {
672 EXPORT_SYMBOL_GPL(visorchannel_dump_section
);