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