visorchannel_funcs.c revision d9355f8934a4c54d81a29ae7bd5ae4329c02aa48
1/* visorchannel_funcs.c 2 * 3 * Copyright � 2010 - 2013 UNISYS CORPORATION 4 * All rights reserved. 5 * 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. 10 * 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 15 * details. 16 */ 17 18/* 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.) 23 */ 24 25#include "globals.h" 26#include "visorchannel.h" 27#include "guidutils.h" 28 29#define MYDRVNAME "visorchannel" 30 31struct VISORCHANNEL_Tag { 32 MEMREGION *memregion; /* from visor_memregion_create() */ 33 CHANNEL_HEADER chan_hdr; 34 GUID guid; 35 ulong size; 36 BOOL needs_lock; 37 spinlock_t insert_lock; 38 spinlock_t remove_lock; 39 40 struct { 41 SIGNAL_QUEUE_HEADER req_queue; 42 SIGNAL_QUEUE_HEADER rsp_queue; 43 SIGNAL_QUEUE_HEADER event_queue; 44 SIGNAL_QUEUE_HEADER ack_queue; 45 } safe_uis_queue; 46}; 47 48/* Creates the VISORCHANNEL abstraction for a data area in memory, but does 49 * NOT modify this data area. 50 */ 51static VISORCHANNEL * 52visorchannel_create_guts(HOSTADDRESS physaddr, ulong channelBytes, 53 VISORCHANNEL *parent, ulong off, GUID guid, 54 BOOL needs_lock) 55{ 56 VISORCHANNEL *p = NULL; 57 void *rc = NULL; 58 59 p = kmalloc(sizeof(VISORCHANNEL), GFP_KERNEL|__GFP_NORETRY); 60 if (p == NULL) 61 FAIL("allocation failed", 0); 62 p->memregion = NULL; 63 p->needs_lock = needs_lock; 64 spin_lock_init(&p->insert_lock); 65 spin_lock_init(&p->remove_lock); 66 67 /* prepare chan_hdr (abstraction to read/write channel memory) */ 68 if (parent == NULL) 69 p->memregion = 70 visor_memregion_create(physaddr, sizeof(CHANNEL_HEADER)); 71 else 72 p->memregion = 73 visor_memregion_create_overlapped(parent->memregion, 74 off, 75 sizeof(CHANNEL_HEADER)); 76 if (p->memregion == NULL) 77 FAIL("visor_memregion_create failed", 0); 78 if (visor_memregion_read(p->memregion, 0, &p->chan_hdr, 79 sizeof(CHANNEL_HEADER)) < 0) 80 FAIL("visor_memregion_read failed", 0); 81 if (channelBytes == 0) 82 /* we had better be a CLIENT of this channel */ 83 channelBytes = (ulong) p->chan_hdr.Size; 84 if (STRUCTSEQUAL(guid, Guid0)) 85 /* we had better be a CLIENT of this channel */ 86 guid = p->chan_hdr.Type; 87 if (visor_memregion_resize(p->memregion, channelBytes) < 0) 88 FAIL("visor_memregion_resize failed", 0); 89 p->size = channelBytes; 90 p->guid = guid; 91 92 rc = p; 93Away: 94 95 if (rc == NULL) { 96 if (p != NULL) { 97 visorchannel_destroy(p); 98 p = NULL; 99 } 100 } 101 return rc; 102} 103 104VISORCHANNEL * 105visorchannel_create(HOSTADDRESS physaddr, ulong channelBytes, GUID guid) 106{ 107 return visorchannel_create_guts(physaddr, channelBytes, NULL, 0, guid, 108 FALSE); 109} 110EXPORT_SYMBOL_GPL(visorchannel_create); 111 112VISORCHANNEL * 113visorchannel_create_with_lock(HOSTADDRESS physaddr, ulong channelBytes, 114 GUID guid) 115{ 116 return visorchannel_create_guts(physaddr, channelBytes, NULL, 0, guid, 117 TRUE); 118} 119EXPORT_SYMBOL_GPL(visorchannel_create_with_lock); 120 121VISORCHANNEL * 122visorchannel_create_overlapped(ulong channelBytes, 123 VISORCHANNEL *parent, ulong off, GUID guid) 124{ 125 return visorchannel_create_guts(0, channelBytes, parent, off, guid, 126 FALSE); 127} 128EXPORT_SYMBOL_GPL(visorchannel_create_overlapped); 129 130VISORCHANNEL * 131visorchannel_create_overlapped_with_lock(ulong channelBytes, 132 VISORCHANNEL *parent, ulong off, 133 GUID guid) 134{ 135 return visorchannel_create_guts(0, channelBytes, parent, off, guid, 136 TRUE); 137} 138EXPORT_SYMBOL_GPL(visorchannel_create_overlapped_with_lock); 139 140void 141visorchannel_destroy(VISORCHANNEL *channel) 142{ 143 if (channel == NULL) 144 return; 145 if (channel->memregion != NULL) { 146 visor_memregion_destroy(channel->memregion); 147 channel->memregion = NULL; 148 } 149 kfree(channel); 150} 151EXPORT_SYMBOL_GPL(visorchannel_destroy); 152 153HOSTADDRESS 154visorchannel_get_physaddr(VISORCHANNEL *channel) 155{ 156 return visor_memregion_get_physaddr(channel->memregion); 157} 158EXPORT_SYMBOL_GPL(visorchannel_get_physaddr); 159 160ulong 161visorchannel_get_nbytes(VISORCHANNEL *channel) 162{ 163 return channel->size; 164} 165EXPORT_SYMBOL_GPL(visorchannel_get_nbytes); 166 167char * 168visorchannel_GUID_id(GUID *guid, char *s) 169{ 170 return GUID_format1(guid, s); 171} 172EXPORT_SYMBOL_GPL(visorchannel_GUID_id); 173 174char * 175visorchannel_id(VISORCHANNEL *channel, char *s) 176{ 177 return visorchannel_GUID_id(&channel->guid, s); 178} 179EXPORT_SYMBOL_GPL(visorchannel_id); 180 181char * 182visorchannel_zoneid(VISORCHANNEL *channel, char *s) 183{ 184 return visorchannel_GUID_id(&channel->chan_hdr.ZoneGuid, s); 185} 186EXPORT_SYMBOL_GPL(visorchannel_zoneid); 187 188HOSTADDRESS 189visorchannel_get_clientpartition(VISORCHANNEL *channel) 190{ 191 return channel->chan_hdr.PartitionHandle; 192} 193EXPORT_SYMBOL_GPL(visorchannel_get_clientpartition); 194 195GUID 196visorchannel_get_GUID(VISORCHANNEL *channel) 197{ 198 return channel->guid; 199} 200EXPORT_SYMBOL_GPL(visorchannel_get_GUID); 201 202MEMREGION * 203visorchannel_get_memregion(VISORCHANNEL *channel) 204{ 205 return channel->memregion; 206} 207EXPORT_SYMBOL_GPL(visorchannel_get_memregion); 208 209int 210visorchannel_read(VISORCHANNEL *channel, ulong offset, 211 void *local, ulong nbytes) 212{ 213 int rc = visor_memregion_read(channel->memregion, offset, 214 local, nbytes); 215 if ((rc >= 0) && (offset == 0) && (nbytes >= sizeof(CHANNEL_HEADER))) 216 memcpy(&channel->chan_hdr, local, sizeof(CHANNEL_HEADER)); 217 return rc; 218} 219EXPORT_SYMBOL_GPL(visorchannel_read); 220 221int 222visorchannel_write(VISORCHANNEL *channel, ulong offset, 223 void *local, ulong nbytes) 224{ 225 if (offset == 0 && nbytes >= sizeof(CHANNEL_HEADER)) 226 memcpy(&channel->chan_hdr, local, sizeof(CHANNEL_HEADER)); 227 return visor_memregion_write(channel->memregion, offset, local, nbytes); 228} 229EXPORT_SYMBOL_GPL(visorchannel_write); 230 231int 232visorchannel_clear(VISORCHANNEL *channel, ulong offset, U8 ch, ulong nbytes) 233{ 234 int rc = -1; 235 int bufsize = 65536; 236 int written = 0; 237 U8 *buf = vmalloc(bufsize); 238 239 if (buf == NULL) { 240 ERRDRV("%s failed memory allocation", __func__); 241 RETINT(-1); 242 } 243 memset(buf, ch, bufsize); 244 while (nbytes > 0) { 245 ulong thisbytes = bufsize; 246 int x = -1; 247 if (nbytes < thisbytes) 248 thisbytes = nbytes; 249 x = visor_memregion_write(channel->memregion, offset + written, 250 buf, thisbytes); 251 if (x < 0) 252 RETINT(x); 253 written += thisbytes; 254 nbytes -= thisbytes; 255 } 256 RETINT(0); 257 258Away: 259 if (buf != NULL) { 260 vfree(buf); 261 buf = NULL; 262 } 263 return rc; 264} 265EXPORT_SYMBOL_GPL(visorchannel_clear); 266 267void * 268visorchannel_get_header(VISORCHANNEL *channel) 269{ 270 return (void *) &(channel->chan_hdr); 271} 272EXPORT_SYMBOL_GPL(visorchannel_get_header); 273 274/** Return offset of a specific SIGNAL_QUEUE_HEADER from the beginning of a 275 * channel header 276 */ 277#define SIG_QUEUE_OFFSET(chan_hdr, q) \ 278 ((chan_hdr)->oChannelSpace + ((q) * sizeof(SIGNAL_QUEUE_HEADER))) 279 280/** Return offset of a specific queue entry (data) from the beginning of a 281 * channel header 282 */ 283#define SIG_DATA_OFFSET(chan_hdr, q, sig_hdr, slot) \ 284 (SIG_QUEUE_OFFSET(chan_hdr, q) + (sig_hdr)->oSignalBase + \ 285 ((slot) * (sig_hdr)->SignalSize)) 286 287/** Write the contents of a specific field within a SIGNAL_QUEUE_HEADER back 288 * into host memory 289 */ 290#define SIG_WRITE_FIELD(channel, queue, sig_hdr, FIELD) \ 291 (visor_memregion_write(channel->memregion, \ 292 SIG_QUEUE_OFFSET(&channel->chan_hdr, queue)+ \ 293 offsetof(SIGNAL_QUEUE_HEADER, FIELD), \ 294 &((sig_hdr)->FIELD), \ 295 sizeof((sig_hdr)->FIELD)) >= 0) 296 297static BOOL 298sig_read_header(VISORCHANNEL *channel, U32 queue, 299 SIGNAL_QUEUE_HEADER *sig_hdr) 300{ 301 BOOL rc = FALSE; 302 303 if (channel->chan_hdr.oChannelSpace < sizeof(CHANNEL_HEADER)) 304 FAIL("oChannelSpace too small", FALSE); 305 306 /* Read the appropriate SIGNAL_QUEUE_HEADER into local memory. */ 307 308 if (visor_memregion_read(channel->memregion, 309 SIG_QUEUE_OFFSET(&channel->chan_hdr, queue), 310 sig_hdr, sizeof(SIGNAL_QUEUE_HEADER)) < 0) { 311 ERRDRV("queue=%d SIG_QUEUE_OFFSET=%d", 312 queue, (int)SIG_QUEUE_OFFSET(&channel->chan_hdr, queue)); 313 FAIL("visor_memregion_read of signal queue failed", FALSE); 314 } 315 rc = TRUE; 316Away: 317 return rc; 318} 319 320static BOOL 321sig_do_data(VISORCHANNEL *channel, U32 queue, 322 SIGNAL_QUEUE_HEADER *sig_hdr, U32 slot, void *data, BOOL is_write) 323{ 324 BOOL rc = FALSE; 325 int signal_data_offset = SIG_DATA_OFFSET(&channel->chan_hdr, queue, 326 sig_hdr, slot); 327 if (is_write) { 328 if (visor_memregion_write(channel->memregion, 329 signal_data_offset, 330 data, sig_hdr->SignalSize) < 0) 331 FAIL("visor_memregion_write of signal data failed", 332 FALSE); 333 } else { 334 if (visor_memregion_read(channel->memregion, signal_data_offset, 335 data, sig_hdr->SignalSize) < 0) 336 FAIL("visor_memregion_read of signal data failed", 337 FALSE); 338 } 339 rc = TRUE; 340Away: 341 return rc; 342} 343 344static inline BOOL 345sig_read_data(VISORCHANNEL *channel, U32 queue, 346 SIGNAL_QUEUE_HEADER *sig_hdr, U32 slot, void *data) 347{ 348 return sig_do_data(channel, queue, sig_hdr, slot, data, FALSE); 349} 350 351static inline BOOL 352sig_write_data(VISORCHANNEL *channel, U32 queue, 353 SIGNAL_QUEUE_HEADER *sig_hdr, U32 slot, void *data) 354{ 355 return sig_do_data(channel, queue, sig_hdr, slot, data, TRUE); 356} 357 358static inline unsigned char 359safe_sig_queue_validate(pSIGNAL_QUEUE_HEADER psafe_sqh, 360 pSIGNAL_QUEUE_HEADER punsafe_sqh, 361 U32 *phead, U32 *ptail) 362{ 363 if ((*phead >= psafe_sqh->MaxSignalSlots) 364 || (*ptail >= psafe_sqh->MaxSignalSlots)) { 365 /* Choose 0 or max, maybe based on current tail value */ 366 *phead = 0; 367 *ptail = 0; 368 369 /* Sync with client as necessary */ 370 punsafe_sqh->Head = *phead; 371 punsafe_sqh->Tail = *ptail; 372 373 ERRDRV("safe_sig_queue_validate: head = 0x%x, tail = 0x%x, MaxSlots = 0x%x", 374 *phead, *ptail, psafe_sqh->MaxSignalSlots); 375 return 0; 376 } 377 return 1; 378} /* end safe_sig_queue_validate */ 379 380BOOL 381visorchannel_signalremove(VISORCHANNEL *channel, U32 queue, void *msg) 382{ 383 BOOL rc = FALSE; 384 SIGNAL_QUEUE_HEADER sig_hdr; 385 386 if (channel->needs_lock) 387 spin_lock(&channel->remove_lock); 388 389 if (!sig_read_header(channel, queue, &sig_hdr)) { 390 rc = FALSE; 391 goto Away; 392 } 393 if (sig_hdr.Head == sig_hdr.Tail) { 394 rc = FALSE; /* no signals to remove */ 395 goto Away; 396 } 397 sig_hdr.Tail = (sig_hdr.Tail + 1) % sig_hdr.MaxSignalSlots; 398 if (!sig_read_data(channel, queue, &sig_hdr, sig_hdr.Tail, msg)) 399 FAIL("sig_read_data failed", FALSE); 400 sig_hdr.NumSignalsReceived++; 401 402 /* For each data field in SIGNAL_QUEUE_HEADER that was modified, 403 * update host memory. 404 */ 405 MEMORYBARRIER; 406 if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, Tail)) 407 FAIL("visor_memregion_write of Tail failed", FALSE); 408 if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, NumSignalsReceived)) 409 FAIL("visor_memregion_write of NumSignalsReceived failed", 410 FALSE); 411 rc = TRUE; 412Away: 413 if (channel->needs_lock) 414 spin_unlock(&channel->remove_lock); 415 416 return rc; 417} 418EXPORT_SYMBOL_GPL(visorchannel_signalremove); 419 420BOOL 421visorchannel_signalinsert(VISORCHANNEL *channel, U32 queue, void *msg) 422{ 423 BOOL rc = FALSE; 424 SIGNAL_QUEUE_HEADER sig_hdr; 425 426 if (channel->needs_lock) 427 spin_lock(&channel->insert_lock); 428 429 if (!sig_read_header(channel, queue, &sig_hdr)) { 430 rc = FALSE; 431 goto Away; 432 } 433 434 sig_hdr.Head = ((sig_hdr.Head + 1) % sig_hdr.MaxSignalSlots); 435 if (sig_hdr.Head == sig_hdr.Tail) { 436 sig_hdr.NumOverflows++; 437 if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, NumOverflows)) 438 FAIL("visor_memregion_write of NumOverflows failed", 439 FALSE); 440 rc = FALSE; 441 goto Away; 442 } 443 444 if (!sig_write_data(channel, queue, &sig_hdr, sig_hdr.Head, msg)) 445 FAIL("sig_write_data failed", FALSE); 446 sig_hdr.NumSignalsSent++; 447 448 /* For each data field in SIGNAL_QUEUE_HEADER that was modified, 449 * update host memory. 450 */ 451 MEMORYBARRIER; 452 if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, Head)) 453 FAIL("visor_memregion_write of Head failed", FALSE); 454 if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, NumSignalsSent)) 455 FAIL("visor_memregion_write of NumSignalsSent failed", FALSE); 456 rc = TRUE; 457Away: 458 if (channel->needs_lock) 459 spin_unlock(&channel->insert_lock); 460 461 return rc; 462} 463EXPORT_SYMBOL_GPL(visorchannel_signalinsert); 464 465 466int 467visorchannel_signalqueue_slots_avail(VISORCHANNEL *channel, U32 queue) 468{ 469 SIGNAL_QUEUE_HEADER sig_hdr; 470 U32 slots_avail, slots_used; 471 U32 head, tail; 472 473 if (!sig_read_header(channel, queue, &sig_hdr)) 474 return 0; 475 head = sig_hdr.Head; 476 tail = sig_hdr.Tail; 477 if (head < tail) 478 head = head + sig_hdr.MaxSignalSlots; 479 slots_used = (head - tail); 480 slots_avail = sig_hdr.MaxSignals - slots_used; 481 return (int) slots_avail; 482} 483EXPORT_SYMBOL_GPL(visorchannel_signalqueue_slots_avail); 484 485int 486visorchannel_signalqueue_max_slots(VISORCHANNEL *channel, U32 queue) 487{ 488 SIGNAL_QUEUE_HEADER sig_hdr; 489 if (!sig_read_header(channel, queue, &sig_hdr)) 490 return 0; 491 return (int) sig_hdr.MaxSignals; 492} 493EXPORT_SYMBOL_GPL(visorchannel_signalqueue_max_slots); 494 495static void 496sigqueue_debug(SIGNAL_QUEUE_HEADER *q, int which, struct seq_file *seq) 497{ 498 seq_printf(seq, "Signal Queue #%d\n", which); 499 seq_printf(seq, " VersionId = %lu\n", (ulong) q->VersionId); 500 seq_printf(seq, " Type = %lu\n", (ulong) q->Type); 501 seq_printf(seq, " oSignalBase = %llu\n", 502 (long long) q->oSignalBase); 503 seq_printf(seq, " SignalSize = %lu\n", (ulong) q->SignalSize); 504 seq_printf(seq, " MaxSignalSlots = %lu\n", 505 (ulong) q->MaxSignalSlots); 506 seq_printf(seq, " MaxSignals = %lu\n", (ulong) q->MaxSignals); 507 seq_printf(seq, " FeatureFlags = %-16.16Lx\n", 508 (long long) q->FeatureFlags); 509 seq_printf(seq, " NumSignalsSent = %llu\n", 510 (long long) q->NumSignalsSent); 511 seq_printf(seq, " NumSignalsReceived = %llu\n", 512 (long long) q->NumSignalsReceived); 513 seq_printf(seq, " NumOverflows = %llu\n", 514 (long long) q->NumOverflows); 515 seq_printf(seq, " Head = %lu\n", (ulong) q->Head); 516 seq_printf(seq, " Tail = %lu\n", (ulong) q->Tail); 517} 518 519void 520visorchannel_debug(VISORCHANNEL *channel, int nQueues, 521 struct seq_file *seq, U32 off) 522{ 523 HOSTADDRESS addr = 0; 524 ulong nbytes = 0, nbytes_region = 0; 525 MEMREGION *memregion = NULL; 526 CHANNEL_HEADER hdr; 527 CHANNEL_HEADER *phdr = &hdr; 528 char s[99]; 529 int i = 0; 530 int errcode = 0; 531 532 if (channel == NULL) { 533 ERRDRV("%s no channel", __func__); 534 return; 535 } 536 memregion = channel->memregion; 537 if (memregion == NULL) { 538 ERRDRV("%s no memregion", __func__); 539 return; 540 } 541 addr = visor_memregion_get_physaddr(memregion); 542 nbytes_region = visor_memregion_get_nbytes(memregion); 543 errcode = visorchannel_read(channel, off, 544 phdr, sizeof(CHANNEL_HEADER)); 545 if (errcode < 0) { 546 seq_printf(seq, 547 "Read of channel header failed with errcode=%d)\n", 548 errcode); 549 if (off == 0) { 550 phdr = &channel->chan_hdr; 551 seq_puts(seq, "(following data may be stale)\n"); 552 } else 553 return; 554 } 555 nbytes = (ulong) (phdr->Size); 556 seq_printf(seq, "--- Begin channel @0x%-16.16Lx for 0x%lx bytes (region=0x%lx bytes) ---\n", 557 addr + off, nbytes, nbytes_region); 558 seq_printf(seq, "Type = %s\n", GUID_format2(&phdr->Type, s)); 559 seq_printf(seq, "ZoneGuid = %s\n", 560 GUID_format2(&phdr->ZoneGuid, s)); 561 seq_printf(seq, "Signature = 0x%-16.16Lx\n", 562 (long long) phdr->Signature); 563 seq_printf(seq, "LegacyState = %lu\n", (ulong) phdr->LegacyState); 564 seq_printf(seq, "SrvState = %lu\n", (ulong) phdr->SrvState); 565 seq_printf(seq, "CliStateBoot = %lu\n", (ulong) phdr->CliStateBoot); 566 seq_printf(seq, "CliStateOS = %lu\n", (ulong) phdr->CliStateOS); 567 seq_printf(seq, "HeaderSize = %lu\n", (ulong) phdr->HeaderSize); 568 seq_printf(seq, "Size = %llu\n", (long long) phdr->Size); 569 seq_printf(seq, "Features = 0x%-16.16llx\n", 570 (long long) phdr->Features); 571 seq_printf(seq, "PartitionHandle = 0x%-16.16llx\n", 572 (long long) phdr->PartitionHandle); 573 seq_printf(seq, "Handle = 0x%-16.16llx\n", 574 (long long) phdr->Handle); 575 seq_printf(seq, "VersionId = %lu\n", (ulong) phdr->VersionId); 576 seq_printf(seq, "oChannelSpace = %llu\n", 577 (long long) phdr->oChannelSpace); 578 if ((phdr->oChannelSpace == 0) || (errcode < 0)) 579 ; 580 else 581 for (i = 0; i < nQueues; i++) { 582 SIGNAL_QUEUE_HEADER q; 583 errcode = visorchannel_read(channel, 584 off + phdr->oChannelSpace + 585 (i * sizeof(q)), 586 &q, sizeof(q)); 587 if (errcode < 0) { 588 seq_printf(seq, 589 "failed to read signal queue #%d from channel @0x%-16.16Lx errcode=%d\n", 590 i, addr, errcode); 591 continue; 592 } 593 sigqueue_debug(&q, i, seq); 594 } 595 seq_printf(seq, "--- End channel @0x%-16.16Lx for 0x%lx bytes ---\n", 596 addr + off, nbytes); 597} 598EXPORT_SYMBOL_GPL(visorchannel_debug); 599 600void 601visorchannel_dump_section(VISORCHANNEL *chan, char *s, 602 int off, int len, struct seq_file *seq) 603{ 604 char *buf, *tbuf, *fmtbuf; 605 int fmtbufsize = 0; 606 int i; 607 int errcode = 0; 608 609 fmtbufsize = 100 * COVQ(len, 16); 610 buf = kmalloc(len, GFP_KERNEL|__GFP_NORETRY); 611 fmtbuf = kmalloc(fmtbufsize, GFP_KERNEL|__GFP_NORETRY); 612 if (buf == NULL || fmtbuf == NULL) 613 goto Away; 614 615 errcode = visorchannel_read(chan, off, buf, len); 616 if (errcode < 0) { 617 ERRDRV("%s failed to read %s from channel errcode=%d", 618 s, __func__, errcode); 619 goto Away; 620 } 621 seq_printf(seq, "channel %s:\n", s); 622 tbuf = buf; 623 while (len > 0) { 624 i = (len < 16) ? len : 16; 625 hex_dump_to_buffer(tbuf, i, 16, 1, fmtbuf, fmtbufsize, TRUE); 626 seq_printf(seq, "%s\n", fmtbuf); 627 tbuf += 16; 628 len -= 16; 629 } 630 631Away: 632 if (buf != NULL) { 633 kfree(buf); 634 buf = NULL; 635 } 636 if (fmtbuf != NULL) { 637 kfree(fmtbuf); 638 fmtbuf = NULL; 639 } 640} 641EXPORT_SYMBOL_GPL(visorchannel_dump_section); 642