1 /* visorchannel_funcs.c
2 *
3 * Copyright (C) 2010 - 2015 UNISYS CORPORATION
4 * All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
13 * NON INFRINGEMENT. See the GNU General Public License for more
14 * details.
15 */
16
17 /*
18 * This provides Supervisor channel communication primitives, which are
19 * independent of the mechanism used to access the channel data.
20 */
21
22 #include <linux/uuid.h>
23 #include <linux/io.h>
24
25 #include "version.h"
26 #include "visorbus.h"
27 #include "controlvmchannel.h"
28
29 #define MYDRVNAME "visorchannel"
30
31 #define SPAR_CONSOLEVIDEO_CHANNEL_PROTOCOL_GUID \
32 UUID_LE(0x3cd6e705, 0xd6a2, 0x4aa5, \
33 0xad, 0x5c, 0x7b, 0x8, 0x88, 0x9d, 0xff, 0xe2)
34 static const uuid_le spar_video_guid = SPAR_CONSOLEVIDEO_CHANNEL_PROTOCOL_GUID;
35
36 struct visorchannel {
37 u64 physaddr;
38 ulong nbytes;
39 void *mapped;
40 bool requested;
41 struct channel_header chan_hdr;
42 uuid_le guid;
43 ulong size;
44 bool needs_lock; /* channel creator knows if more than one
45 * thread will be inserting or removing */
46 spinlock_t insert_lock; /* protect head writes in chan_hdr */
47 spinlock_t remove_lock; /* protect tail writes in chan_hdr */
48
49 struct {
50 struct signal_queue_header req_queue;
51 struct signal_queue_header rsp_queue;
52 struct signal_queue_header event_queue;
53 struct signal_queue_header ack_queue;
54 } safe_uis_queue;
55 uuid_le type;
56 uuid_le inst;
57 };
58
59 /* Creates the struct visorchannel abstraction for a data area in memory,
60 * but does NOT modify this data area.
61 */
62 static struct visorchannel *
visorchannel_create_guts(u64 physaddr,unsigned long channel_bytes,gfp_t gfp,unsigned long off,uuid_le guid,bool needs_lock)63 visorchannel_create_guts(u64 physaddr, unsigned long channel_bytes,
64 gfp_t gfp, unsigned long off,
65 uuid_le guid, bool needs_lock)
66 {
67 struct visorchannel *channel;
68 int err;
69 size_t size = sizeof(struct channel_header);
70
71 if (physaddr == 0)
72 return NULL;
73
74 channel = kzalloc(sizeof(*channel), gfp);
75 if (!channel)
76 goto cleanup;
77
78 channel->needs_lock = needs_lock;
79 spin_lock_init(&channel->insert_lock);
80 spin_lock_init(&channel->remove_lock);
81
82 /* Video driver constains the efi framebuffer so it will get a
83 * conflict resource when requesting its full mem region. Since
84 * we are only using the efi framebuffer for video we can ignore
85 * this. Remember that we haven't requested it so we don't try to
86 * release later on.
87 */
88 channel->requested = request_mem_region(physaddr, size, MYDRVNAME);
89 if (!channel->requested) {
90 if (uuid_le_cmp(guid, spar_video_guid)) {
91 /* Not the video channel we care about this */
92 goto cleanup;
93 }
94 }
95
96 channel->mapped = memremap(physaddr, size, MEMREMAP_WB);
97 if (!channel->mapped) {
98 release_mem_region(physaddr, size);
99 goto cleanup;
100 }
101
102 channel->physaddr = physaddr;
103 channel->nbytes = size;
104
105 err = visorchannel_read(channel, 0, &channel->chan_hdr,
106 sizeof(struct channel_header));
107 if (err)
108 goto cleanup;
109
110 /* we had better be a CLIENT of this channel */
111 if (channel_bytes == 0)
112 channel_bytes = (ulong)channel->chan_hdr.size;
113 if (uuid_le_cmp(guid, NULL_UUID_LE) == 0)
114 guid = channel->chan_hdr.chtype;
115
116 memunmap(channel->mapped);
117 if (channel->requested)
118 release_mem_region(channel->physaddr, channel->nbytes);
119 channel->mapped = NULL;
120 channel->requested = request_mem_region(channel->physaddr,
121 channel_bytes, MYDRVNAME);
122 if (!channel->requested) {
123 if (uuid_le_cmp(guid, spar_video_guid)) {
124 /* Different we care about this */
125 goto cleanup;
126 }
127 }
128
129 channel->mapped = memremap(channel->physaddr, channel_bytes,
130 MEMREMAP_WB);
131 if (!channel->mapped) {
132 release_mem_region(channel->physaddr, channel_bytes);
133 goto cleanup;
134 }
135
136 channel->nbytes = channel_bytes;
137
138 channel->size = channel_bytes;
139 channel->guid = guid;
140 return channel;
141
142 cleanup:
143 visorchannel_destroy(channel);
144 return NULL;
145 }
146
147 struct visorchannel *
visorchannel_create(u64 physaddr,unsigned long channel_bytes,gfp_t gfp,uuid_le guid)148 visorchannel_create(u64 physaddr, unsigned long channel_bytes,
149 gfp_t gfp, uuid_le guid)
150 {
151 return visorchannel_create_guts(physaddr, channel_bytes, gfp, 0, guid,
152 false);
153 }
154 EXPORT_SYMBOL_GPL(visorchannel_create);
155
156 struct visorchannel *
visorchannel_create_with_lock(u64 physaddr,unsigned long channel_bytes,gfp_t gfp,uuid_le guid)157 visorchannel_create_with_lock(u64 physaddr, unsigned long channel_bytes,
158 gfp_t gfp, uuid_le guid)
159 {
160 return visorchannel_create_guts(physaddr, channel_bytes, gfp, 0, guid,
161 true);
162 }
163 EXPORT_SYMBOL_GPL(visorchannel_create_with_lock);
164
165 void
visorchannel_destroy(struct visorchannel * channel)166 visorchannel_destroy(struct visorchannel *channel)
167 {
168 if (!channel)
169 return;
170 if (channel->mapped) {
171 memunmap(channel->mapped);
172 if (channel->requested)
173 release_mem_region(channel->physaddr, channel->nbytes);
174 }
175 kfree(channel);
176 }
177 EXPORT_SYMBOL_GPL(visorchannel_destroy);
178
179 u64
visorchannel_get_physaddr(struct visorchannel * channel)180 visorchannel_get_physaddr(struct visorchannel *channel)
181 {
182 return channel->physaddr;
183 }
184 EXPORT_SYMBOL_GPL(visorchannel_get_physaddr);
185
186 ulong
visorchannel_get_nbytes(struct visorchannel * channel)187 visorchannel_get_nbytes(struct visorchannel *channel)
188 {
189 return channel->size;
190 }
191 EXPORT_SYMBOL_GPL(visorchannel_get_nbytes);
192
193 char *
visorchannel_uuid_id(uuid_le * guid,char * s)194 visorchannel_uuid_id(uuid_le *guid, char *s)
195 {
196 sprintf(s, "%pUL", guid);
197 return s;
198 }
199 EXPORT_SYMBOL_GPL(visorchannel_uuid_id);
200
201 char *
visorchannel_id(struct visorchannel * channel,char * s)202 visorchannel_id(struct visorchannel *channel, char *s)
203 {
204 return visorchannel_uuid_id(&channel->guid, s);
205 }
206 EXPORT_SYMBOL_GPL(visorchannel_id);
207
208 char *
visorchannel_zoneid(struct visorchannel * channel,char * s)209 visorchannel_zoneid(struct visorchannel *channel, char *s)
210 {
211 return visorchannel_uuid_id(&channel->chan_hdr.zone_uuid, s);
212 }
213 EXPORT_SYMBOL_GPL(visorchannel_zoneid);
214
215 u64
visorchannel_get_clientpartition(struct visorchannel * channel)216 visorchannel_get_clientpartition(struct visorchannel *channel)
217 {
218 return channel->chan_hdr.partition_handle;
219 }
220 EXPORT_SYMBOL_GPL(visorchannel_get_clientpartition);
221
222 int
visorchannel_set_clientpartition(struct visorchannel * channel,u64 partition_handle)223 visorchannel_set_clientpartition(struct visorchannel *channel,
224 u64 partition_handle)
225 {
226 channel->chan_hdr.partition_handle = partition_handle;
227 return 0;
228 }
229 EXPORT_SYMBOL_GPL(visorchannel_set_clientpartition);
230
231 uuid_le
visorchannel_get_uuid(struct visorchannel * channel)232 visorchannel_get_uuid(struct visorchannel *channel)
233 {
234 return channel->guid;
235 }
236 EXPORT_SYMBOL_GPL(visorchannel_get_uuid);
237
238 int
visorchannel_read(struct visorchannel * channel,ulong offset,void * local,ulong nbytes)239 visorchannel_read(struct visorchannel *channel, ulong offset,
240 void *local, ulong nbytes)
241 {
242 if (offset + nbytes > channel->nbytes)
243 return -EIO;
244
245 memcpy(local, channel->mapped + offset, nbytes);
246
247 return 0;
248 }
249 EXPORT_SYMBOL_GPL(visorchannel_read);
250
251 int
visorchannel_write(struct visorchannel * channel,ulong offset,void * local,ulong nbytes)252 visorchannel_write(struct visorchannel *channel, ulong offset,
253 void *local, ulong nbytes)
254 {
255 size_t chdr_size = sizeof(struct channel_header);
256 size_t copy_size;
257
258 if (offset + nbytes > channel->nbytes)
259 return -EIO;
260
261 if (offset < chdr_size) {
262 copy_size = min(chdr_size - offset, nbytes);
263 memcpy(((char *)(&channel->chan_hdr)) + offset,
264 local, copy_size);
265 }
266
267 memcpy(channel->mapped + offset, local, nbytes);
268
269 return 0;
270 }
271 EXPORT_SYMBOL_GPL(visorchannel_write);
272
273 int
visorchannel_clear(struct visorchannel * channel,ulong offset,u8 ch,ulong nbytes)274 visorchannel_clear(struct visorchannel *channel, ulong offset, u8 ch,
275 ulong nbytes)
276 {
277 int err;
278 int bufsize = PAGE_SIZE;
279 int written = 0;
280 u8 *buf;
281
282 buf = (u8 *)__get_free_page(GFP_KERNEL);
283 if (!buf)
284 return -ENOMEM;
285
286 memset(buf, ch, bufsize);
287
288 while (nbytes > 0) {
289 int thisbytes = bufsize;
290
291 if (nbytes < thisbytes)
292 thisbytes = nbytes;
293 err = visorchannel_write(channel, offset + written,
294 buf, thisbytes);
295 if (err)
296 goto cleanup;
297
298 written += thisbytes;
299 nbytes -= thisbytes;
300 }
301 err = 0;
302
303 cleanup:
304 free_page((unsigned long)buf);
305 return err;
306 }
307 EXPORT_SYMBOL_GPL(visorchannel_clear);
308
309 void __iomem *
visorchannel_get_header(struct visorchannel * channel)310 visorchannel_get_header(struct visorchannel *channel)
311 {
312 return (void __iomem *)&channel->chan_hdr;
313 }
314 EXPORT_SYMBOL_GPL(visorchannel_get_header);
315
316 /** Return offset of a specific SIGNAL_QUEUE_HEADER from the beginning of a
317 * channel header
318 */
319 #define SIG_QUEUE_OFFSET(chan_hdr, q) \
320 ((chan_hdr)->ch_space_offset + \
321 ((q) * sizeof(struct signal_queue_header)))
322
323 /** Return offset of a specific queue entry (data) from the beginning of a
324 * channel header
325 */
326 #define SIG_DATA_OFFSET(chan_hdr, q, sig_hdr, slot) \
327 (SIG_QUEUE_OFFSET(chan_hdr, q) + (sig_hdr)->sig_base_offset + \
328 ((slot) * (sig_hdr)->signal_size))
329
330 /** Write the contents of a specific field within a SIGNAL_QUEUE_HEADER back
331 * into host memory
332 */
333 #define SIG_WRITE_FIELD(channel, queue, sig_hdr, FIELD) \
334 (visorchannel_write(channel, \
335 SIG_QUEUE_OFFSET(&channel->chan_hdr, queue) +\
336 offsetof(struct signal_queue_header, FIELD), \
337 &((sig_hdr)->FIELD), \
338 sizeof((sig_hdr)->FIELD)) >= 0)
339
340 static bool
sig_read_header(struct visorchannel * channel,u32 queue,struct signal_queue_header * sig_hdr)341 sig_read_header(struct visorchannel *channel, u32 queue,
342 struct signal_queue_header *sig_hdr)
343 {
344 int err;
345
346 if (channel->chan_hdr.ch_space_offset < sizeof(struct channel_header))
347 return false;
348
349 /* Read the appropriate SIGNAL_QUEUE_HEADER into local memory. */
350 err = visorchannel_read(channel,
351 SIG_QUEUE_OFFSET(&channel->chan_hdr, queue),
352 sig_hdr, sizeof(struct signal_queue_header));
353 if (err)
354 return false;
355
356 return true;
357 }
358
359 static inline bool
sig_read_data(struct visorchannel * channel,u32 queue,struct signal_queue_header * sig_hdr,u32 slot,void * data)360 sig_read_data(struct visorchannel *channel, u32 queue,
361 struct signal_queue_header *sig_hdr, u32 slot, void *data)
362 {
363 int err;
364 int signal_data_offset = SIG_DATA_OFFSET(&channel->chan_hdr, queue,
365 sig_hdr, slot);
366
367 err = visorchannel_read(channel, signal_data_offset,
368 data, sig_hdr->signal_size);
369 if (err)
370 return false;
371
372 return true;
373 }
374
375 static inline bool
sig_write_data(struct visorchannel * channel,u32 queue,struct signal_queue_header * sig_hdr,u32 slot,void * data)376 sig_write_data(struct visorchannel *channel, u32 queue,
377 struct signal_queue_header *sig_hdr, u32 slot, void *data)
378 {
379 int err;
380 int signal_data_offset = SIG_DATA_OFFSET(&channel->chan_hdr, queue,
381 sig_hdr, slot);
382
383 err = visorchannel_write(channel, signal_data_offset,
384 data, sig_hdr->signal_size);
385 if (err)
386 return false;
387
388 return true;
389 }
390
391 static bool
signalremove_inner(struct visorchannel * channel,u32 queue,void * msg)392 signalremove_inner(struct visorchannel *channel, u32 queue, void *msg)
393 {
394 struct signal_queue_header sig_hdr;
395
396 if (!sig_read_header(channel, queue, &sig_hdr))
397 return false;
398 if (sig_hdr.head == sig_hdr.tail)
399 return false; /* no signals to remove */
400
401 sig_hdr.tail = (sig_hdr.tail + 1) % sig_hdr.max_slots;
402 if (!sig_read_data(channel, queue, &sig_hdr, sig_hdr.tail, msg))
403 return false;
404 sig_hdr.num_received++;
405
406 /* For each data field in SIGNAL_QUEUE_HEADER that was modified,
407 * update host memory.
408 */
409 mb(); /* required for channel synch */
410 if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, tail))
411 return false;
412 if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, num_received))
413 return false;
414 return true;
415 }
416
417 bool
visorchannel_signalremove(struct visorchannel * channel,u32 queue,void * msg)418 visorchannel_signalremove(struct visorchannel *channel, u32 queue, void *msg)
419 {
420 bool rc;
421 unsigned long flags;
422
423 if (channel->needs_lock) {
424 spin_lock_irqsave(&channel->remove_lock, flags);
425 rc = signalremove_inner(channel, queue, msg);
426 spin_unlock_irqrestore(&channel->remove_lock, flags);
427 } else {
428 rc = signalremove_inner(channel, queue, msg);
429 }
430
431 return rc;
432 }
433 EXPORT_SYMBOL_GPL(visorchannel_signalremove);
434
435 bool
visorchannel_signalempty(struct visorchannel * channel,u32 queue)436 visorchannel_signalempty(struct visorchannel *channel, u32 queue)
437 {
438 unsigned long flags = 0;
439 struct signal_queue_header sig_hdr;
440 bool rc = false;
441
442 if (channel->needs_lock)
443 spin_lock_irqsave(&channel->remove_lock, flags);
444
445 if (!sig_read_header(channel, queue, &sig_hdr))
446 rc = true;
447 if (sig_hdr.head == sig_hdr.tail)
448 rc = true;
449 if (channel->needs_lock)
450 spin_unlock_irqrestore(&channel->remove_lock, flags);
451
452 return rc;
453 }
454 EXPORT_SYMBOL_GPL(visorchannel_signalempty);
455
456 static bool
signalinsert_inner(struct visorchannel * channel,u32 queue,void * msg)457 signalinsert_inner(struct visorchannel *channel, u32 queue, void *msg)
458 {
459 struct signal_queue_header sig_hdr;
460
461 if (!sig_read_header(channel, queue, &sig_hdr))
462 return false;
463
464 sig_hdr.head = ((sig_hdr.head + 1) % sig_hdr.max_slots);
465 if (sig_hdr.head == sig_hdr.tail) {
466 sig_hdr.num_overflows++;
467 visorchannel_write(channel,
468 SIG_QUEUE_OFFSET(&channel->chan_hdr, queue) +
469 offsetof(struct signal_queue_header,
470 num_overflows),
471 &sig_hdr.num_overflows,
472 sizeof(sig_hdr.num_overflows));
473 return false;
474 }
475
476 if (!sig_write_data(channel, queue, &sig_hdr, sig_hdr.head, msg))
477 return false;
478
479 sig_hdr.num_sent++;
480
481 /* For each data field in SIGNAL_QUEUE_HEADER that was modified,
482 * update host memory.
483 */
484 mb(); /* required for channel synch */
485 if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, head))
486 return false;
487 if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, num_sent))
488 return false;
489
490 return true;
491 }
492
493 bool
visorchannel_signalinsert(struct visorchannel * channel,u32 queue,void * msg)494 visorchannel_signalinsert(struct visorchannel *channel, u32 queue, void *msg)
495 {
496 bool rc;
497 unsigned long flags;
498
499 if (channel->needs_lock) {
500 spin_lock_irqsave(&channel->insert_lock, flags);
501 rc = signalinsert_inner(channel, queue, msg);
502 spin_unlock_irqrestore(&channel->insert_lock, flags);
503 } else {
504 rc = signalinsert_inner(channel, queue, msg);
505 }
506
507 return rc;
508 }
509 EXPORT_SYMBOL_GPL(visorchannel_signalinsert);
510
511 int
visorchannel_signalqueue_slots_avail(struct visorchannel * channel,u32 queue)512 visorchannel_signalqueue_slots_avail(struct visorchannel *channel, u32 queue)
513 {
514 struct signal_queue_header sig_hdr;
515 u32 slots_avail, slots_used;
516 u32 head, tail;
517
518 if (!sig_read_header(channel, queue, &sig_hdr))
519 return 0;
520 head = sig_hdr.head;
521 tail = sig_hdr.tail;
522 if (head < tail)
523 head = head + sig_hdr.max_slots;
524 slots_used = (head - tail);
525 slots_avail = sig_hdr.max_signals - slots_used;
526 return (int)slots_avail;
527 }
528 EXPORT_SYMBOL_GPL(visorchannel_signalqueue_slots_avail);
529
530 int
visorchannel_signalqueue_max_slots(struct visorchannel * channel,u32 queue)531 visorchannel_signalqueue_max_slots(struct visorchannel *channel, u32 queue)
532 {
533 struct signal_queue_header sig_hdr;
534
535 if (!sig_read_header(channel, queue, &sig_hdr))
536 return 0;
537 return (int)sig_hdr.max_signals;
538 }
539 EXPORT_SYMBOL_GPL(visorchannel_signalqueue_max_slots);
540
541 static void
sigqueue_debug(struct signal_queue_header * q,int which,struct seq_file * seq)542 sigqueue_debug(struct signal_queue_header *q, int which, struct seq_file *seq)
543 {
544 seq_printf(seq, "Signal Queue #%d\n", which);
545 seq_printf(seq, " VersionId = %lu\n", (ulong)q->version);
546 seq_printf(seq, " Type = %lu\n", (ulong)q->chtype);
547 seq_printf(seq, " oSignalBase = %llu\n",
548 (long long)q->sig_base_offset);
549 seq_printf(seq, " SignalSize = %lu\n", (ulong)q->signal_size);
550 seq_printf(seq, " MaxSignalSlots = %lu\n",
551 (ulong)q->max_slots);
552 seq_printf(seq, " MaxSignals = %lu\n", (ulong)q->max_signals);
553 seq_printf(seq, " FeatureFlags = %-16.16Lx\n",
554 (long long)q->features);
555 seq_printf(seq, " NumSignalsSent = %llu\n",
556 (long long)q->num_sent);
557 seq_printf(seq, " NumSignalsReceived = %llu\n",
558 (long long)q->num_received);
559 seq_printf(seq, " NumOverflows = %llu\n",
560 (long long)q->num_overflows);
561 seq_printf(seq, " Head = %lu\n", (ulong)q->head);
562 seq_printf(seq, " Tail = %lu\n", (ulong)q->tail);
563 }
564
565 void
visorchannel_debug(struct visorchannel * channel,int num_queues,struct seq_file * seq,u32 off)566 visorchannel_debug(struct visorchannel *channel, int num_queues,
567 struct seq_file *seq, u32 off)
568 {
569 u64 addr = 0;
570 ulong nbytes = 0, nbytes_region = 0;
571 struct channel_header hdr;
572 struct channel_header *phdr = &hdr;
573 int i = 0;
574 int errcode = 0;
575
576 if (!channel)
577 return;
578
579 addr = visorchannel_get_physaddr(channel);
580 nbytes_region = visorchannel_get_nbytes(channel);
581 errcode = visorchannel_read(channel, off,
582 phdr, sizeof(struct channel_header));
583 if (errcode < 0) {
584 seq_printf(seq,
585 "Read of channel header failed with errcode=%d)\n",
586 errcode);
587 if (off == 0) {
588 phdr = &channel->chan_hdr;
589 seq_puts(seq, "(following data may be stale)\n");
590 } else {
591 return;
592 }
593 }
594 nbytes = (ulong)(phdr->size);
595 seq_printf(seq, "--- Begin channel @0x%-16.16Lx for 0x%lx bytes (region=0x%lx bytes) ---\n",
596 addr + off, nbytes, nbytes_region);
597 seq_printf(seq, "Type = %pUL\n", &phdr->chtype);
598 seq_printf(seq, "ZoneGuid = %pUL\n", &phdr->zone_uuid);
599 seq_printf(seq, "Signature = 0x%-16.16Lx\n",
600 (long long)phdr->signature);
601 seq_printf(seq, "LegacyState = %lu\n", (ulong)phdr->legacy_state);
602 seq_printf(seq, "SrvState = %lu\n", (ulong)phdr->srv_state);
603 seq_printf(seq, "CliStateBoot = %lu\n", (ulong)phdr->cli_state_boot);
604 seq_printf(seq, "CliStateOS = %lu\n", (ulong)phdr->cli_state_os);
605 seq_printf(seq, "HeaderSize = %lu\n", (ulong)phdr->header_size);
606 seq_printf(seq, "Size = %llu\n", (long long)phdr->size);
607 seq_printf(seq, "Features = 0x%-16.16llx\n",
608 (long long)phdr->features);
609 seq_printf(seq, "PartitionHandle = 0x%-16.16llx\n",
610 (long long)phdr->partition_handle);
611 seq_printf(seq, "Handle = 0x%-16.16llx\n",
612 (long long)phdr->handle);
613 seq_printf(seq, "VersionId = %lu\n", (ulong)phdr->version_id);
614 seq_printf(seq, "oChannelSpace = %llu\n",
615 (long long)phdr->ch_space_offset);
616 if ((phdr->ch_space_offset == 0) || (errcode < 0))
617 ;
618 else
619 for (i = 0; i < num_queues; i++) {
620 struct signal_queue_header q;
621
622 errcode = visorchannel_read(channel,
623 off +
624 phdr->ch_space_offset +
625 (i * sizeof(q)),
626 &q, sizeof(q));
627 if (errcode < 0) {
628 seq_printf(seq,
629 "failed to read signal queue #%d from channel @0x%-16.16Lx errcode=%d\n",
630 i, addr, errcode);
631 continue;
632 }
633 sigqueue_debug(&q, i, seq);
634 }
635 seq_printf(seq, "--- End channel @0x%-16.16Lx for 0x%lx bytes ---\n",
636 addr + off, nbytes);
637 }
638 EXPORT_SYMBOL_GPL(visorchannel_debug);
639