diff options
Diffstat (limited to 'drivers/infiniband/hw/qib/qib_qsfp.c')
-rw-r--r-- | drivers/infiniband/hw/qib/qib_qsfp.c | 564 |
1 files changed, 564 insertions, 0 deletions
diff --git a/drivers/infiniband/hw/qib/qib_qsfp.c b/drivers/infiniband/hw/qib/qib_qsfp.c new file mode 100644 index 000000000000..35b3604b691d --- /dev/null +++ b/drivers/infiniband/hw/qib/qib_qsfp.c | |||
@@ -0,0 +1,564 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2006, 2007, 2008, 2009 QLogic Corporation. All rights reserved. | ||
3 | * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the | ||
9 | * OpenIB.org BSD license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or | ||
12 | * without modification, are permitted provided that the following | ||
13 | * conditions are met: | ||
14 | * | ||
15 | * - Redistributions of source code must retain the above | ||
16 | * copyright notice, this list of conditions and the following | ||
17 | * disclaimer. | ||
18 | * | ||
19 | * - Redistributions in binary form must reproduce the above | ||
20 | * copyright notice, this list of conditions and the following | ||
21 | * disclaimer in the documentation and/or other materials | ||
22 | * provided with the distribution. | ||
23 | * | ||
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
28 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
29 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
30 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
31 | * SOFTWARE. | ||
32 | */ | ||
33 | |||
34 | #include <linux/delay.h> | ||
35 | #include <linux/pci.h> | ||
36 | #include <linux/vmalloc.h> | ||
37 | |||
38 | #include "qib.h" | ||
39 | #include "qib_qsfp.h" | ||
40 | |||
41 | /* | ||
42 | * QSFP support for ib_qib driver, using "Two Wire Serial Interface" driver | ||
43 | * in qib_twsi.c | ||
44 | */ | ||
45 | #define QSFP_MAX_RETRY 4 | ||
46 | |||
47 | static int qsfp_read(struct qib_pportdata *ppd, int addr, void *bp, int len) | ||
48 | { | ||
49 | struct qib_devdata *dd = ppd->dd; | ||
50 | u32 out, mask; | ||
51 | int ret, cnt, pass = 0; | ||
52 | int stuck = 0; | ||
53 | u8 *buff = bp; | ||
54 | |||
55 | ret = mutex_lock_interruptible(&dd->eep_lock); | ||
56 | if (ret) | ||
57 | goto no_unlock; | ||
58 | |||
59 | if (dd->twsi_eeprom_dev == QIB_TWSI_NO_DEV) { | ||
60 | ret = -ENXIO; | ||
61 | goto bail; | ||
62 | } | ||
63 | |||
64 | /* | ||
65 | * We presume, if we are called at all, that this board has | ||
66 | * QSFP. This is on the same i2c chain as the legacy parts, | ||
67 | * but only responds if the module is selected via GPIO pins. | ||
68 | * Further, there are very long setup and hold requirements | ||
69 | * on MODSEL. | ||
70 | */ | ||
71 | mask = QSFP_GPIO_MOD_SEL_N | QSFP_GPIO_MOD_RST_N | QSFP_GPIO_LP_MODE; | ||
72 | out = QSFP_GPIO_MOD_RST_N | QSFP_GPIO_LP_MODE; | ||
73 | if (ppd->hw_pidx) { | ||
74 | mask <<= QSFP_GPIO_PORT2_SHIFT; | ||
75 | out <<= QSFP_GPIO_PORT2_SHIFT; | ||
76 | } | ||
77 | |||
78 | dd->f_gpio_mod(dd, out, mask, mask); | ||
79 | |||
80 | /* | ||
81 | * Module could take up to 2 Msec to respond to MOD_SEL, and there | ||
82 | * is no way to tell if it is ready, so we must wait. | ||
83 | */ | ||
84 | msleep(2); | ||
85 | |||
86 | /* Make sure TWSI bus is in sane state. */ | ||
87 | ret = qib_twsi_reset(dd); | ||
88 | if (ret) { | ||
89 | qib_dev_porterr(dd, ppd->port, | ||
90 | "QSFP interface Reset for read failed\n"); | ||
91 | ret = -EIO; | ||
92 | stuck = 1; | ||
93 | goto deselect; | ||
94 | } | ||
95 | |||
96 | /* All QSFP modules are at A0 */ | ||
97 | |||
98 | cnt = 0; | ||
99 | while (cnt < len) { | ||
100 | unsigned in_page; | ||
101 | int wlen = len - cnt; | ||
102 | in_page = addr % QSFP_PAGESIZE; | ||
103 | if ((in_page + wlen) > QSFP_PAGESIZE) | ||
104 | wlen = QSFP_PAGESIZE - in_page; | ||
105 | ret = qib_twsi_blk_rd(dd, QSFP_DEV, addr, buff + cnt, wlen); | ||
106 | /* Some QSFP's fail first try. Retry as experiment */ | ||
107 | if (ret && cnt == 0 && ++pass < QSFP_MAX_RETRY) | ||
108 | continue; | ||
109 | if (ret) { | ||
110 | /* qib_twsi_blk_rd() 1 for error, else 0 */ | ||
111 | ret = -EIO; | ||
112 | goto deselect; | ||
113 | } | ||
114 | addr += wlen; | ||
115 | cnt += wlen; | ||
116 | } | ||
117 | ret = cnt; | ||
118 | |||
119 | deselect: | ||
120 | /* | ||
121 | * Module could take up to 10 uSec after transfer before | ||
122 | * ready to respond to MOD_SEL negation, and there is no way | ||
123 | * to tell if it is ready, so we must wait. | ||
124 | */ | ||
125 | udelay(10); | ||
126 | /* set QSFP MODSEL, RST. LP all high */ | ||
127 | dd->f_gpio_mod(dd, mask, mask, mask); | ||
128 | |||
129 | /* | ||
130 | * Module could take up to 2 Msec to respond to MOD_SEL | ||
131 | * going away, and there is no way to tell if it is ready. | ||
132 | * so we must wait. | ||
133 | */ | ||
134 | if (stuck) | ||
135 | qib_dev_err(dd, "QSFP interface bus stuck non-idle\n"); | ||
136 | |||
137 | if (pass >= QSFP_MAX_RETRY && ret) | ||
138 | qib_dev_porterr(dd, ppd->port, "QSFP failed even retrying\n"); | ||
139 | else if (pass) | ||
140 | qib_dev_porterr(dd, ppd->port, "QSFP retries: %d\n", pass); | ||
141 | |||
142 | msleep(2); | ||
143 | |||
144 | bail: | ||
145 | mutex_unlock(&dd->eep_lock); | ||
146 | |||
147 | no_unlock: | ||
148 | return ret; | ||
149 | } | ||
150 | |||
151 | /* | ||
152 | * qsfp_write | ||
153 | * We do not ordinarily write the QSFP, but this is needed to select | ||
154 | * the page on non-flat QSFPs, and possibly later unusual cases | ||
155 | */ | ||
156 | static int qib_qsfp_write(struct qib_pportdata *ppd, int addr, void *bp, | ||
157 | int len) | ||
158 | { | ||
159 | struct qib_devdata *dd = ppd->dd; | ||
160 | u32 out, mask; | ||
161 | int ret, cnt; | ||
162 | u8 *buff = bp; | ||
163 | |||
164 | ret = mutex_lock_interruptible(&dd->eep_lock); | ||
165 | if (ret) | ||
166 | goto no_unlock; | ||
167 | |||
168 | if (dd->twsi_eeprom_dev == QIB_TWSI_NO_DEV) { | ||
169 | ret = -ENXIO; | ||
170 | goto bail; | ||
171 | } | ||
172 | |||
173 | /* | ||
174 | * We presume, if we are called at all, that this board has | ||
175 | * QSFP. This is on the same i2c chain as the legacy parts, | ||
176 | * but only responds if the module is selected via GPIO pins. | ||
177 | * Further, there are very long setup and hold requirements | ||
178 | * on MODSEL. | ||
179 | */ | ||
180 | mask = QSFP_GPIO_MOD_SEL_N | QSFP_GPIO_MOD_RST_N | QSFP_GPIO_LP_MODE; | ||
181 | out = QSFP_GPIO_MOD_RST_N | QSFP_GPIO_LP_MODE; | ||
182 | if (ppd->hw_pidx) { | ||
183 | mask <<= QSFP_GPIO_PORT2_SHIFT; | ||
184 | out <<= QSFP_GPIO_PORT2_SHIFT; | ||
185 | } | ||
186 | dd->f_gpio_mod(dd, out, mask, mask); | ||
187 | |||
188 | /* | ||
189 | * Module could take up to 2 Msec to respond to MOD_SEL, | ||
190 | * and there is no way to tell if it is ready, so we must wait. | ||
191 | */ | ||
192 | msleep(2); | ||
193 | |||
194 | /* Make sure TWSI bus is in sane state. */ | ||
195 | ret = qib_twsi_reset(dd); | ||
196 | if (ret) { | ||
197 | qib_dev_porterr(dd, ppd->port, | ||
198 | "QSFP interface Reset for write failed\n"); | ||
199 | ret = -EIO; | ||
200 | goto deselect; | ||
201 | } | ||
202 | |||
203 | /* All QSFP modules are at A0 */ | ||
204 | |||
205 | cnt = 0; | ||
206 | while (cnt < len) { | ||
207 | unsigned in_page; | ||
208 | int wlen = len - cnt; | ||
209 | in_page = addr % QSFP_PAGESIZE; | ||
210 | if ((in_page + wlen) > QSFP_PAGESIZE) | ||
211 | wlen = QSFP_PAGESIZE - in_page; | ||
212 | ret = qib_twsi_blk_wr(dd, QSFP_DEV, addr, buff + cnt, wlen); | ||
213 | if (ret) { | ||
214 | /* qib_twsi_blk_wr() 1 for error, else 0 */ | ||
215 | ret = -EIO; | ||
216 | goto deselect; | ||
217 | } | ||
218 | addr += wlen; | ||
219 | cnt += wlen; | ||
220 | } | ||
221 | ret = cnt; | ||
222 | |||
223 | deselect: | ||
224 | /* | ||
225 | * Module could take up to 10 uSec after transfer before | ||
226 | * ready to respond to MOD_SEL negation, and there is no way | ||
227 | * to tell if it is ready, so we must wait. | ||
228 | */ | ||
229 | udelay(10); | ||
230 | /* set QSFP MODSEL, RST, LP high */ | ||
231 | dd->f_gpio_mod(dd, mask, mask, mask); | ||
232 | /* | ||
233 | * Module could take up to 2 Msec to respond to MOD_SEL | ||
234 | * going away, and there is no way to tell if it is ready. | ||
235 | * so we must wait. | ||
236 | */ | ||
237 | msleep(2); | ||
238 | |||
239 | bail: | ||
240 | mutex_unlock(&dd->eep_lock); | ||
241 | |||
242 | no_unlock: | ||
243 | return ret; | ||
244 | } | ||
245 | |||
246 | /* | ||
247 | * For validation, we want to check the checksums, even of the | ||
248 | * fields we do not otherwise use. This function reads the bytes from | ||
249 | * <first> to <next-1> and returns the 8lsbs of the sum, or <0 for errors | ||
250 | */ | ||
251 | static int qsfp_cks(struct qib_pportdata *ppd, int first, int next) | ||
252 | { | ||
253 | int ret; | ||
254 | u16 cks; | ||
255 | u8 bval; | ||
256 | |||
257 | cks = 0; | ||
258 | while (first < next) { | ||
259 | ret = qsfp_read(ppd, first, &bval, 1); | ||
260 | if (ret < 0) | ||
261 | goto bail; | ||
262 | cks += bval; | ||
263 | ++first; | ||
264 | } | ||
265 | ret = cks & 0xFF; | ||
266 | bail: | ||
267 | return ret; | ||
268 | |||
269 | } | ||
270 | |||
271 | int qib_refresh_qsfp_cache(struct qib_pportdata *ppd, struct qib_qsfp_cache *cp) | ||
272 | { | ||
273 | int ret; | ||
274 | int idx; | ||
275 | u16 cks; | ||
276 | u32 mask; | ||
277 | u8 peek[4]; | ||
278 | |||
279 | /* ensure sane contents on invalid reads, for cable swaps */ | ||
280 | memset(cp, 0, sizeof(*cp)); | ||
281 | |||
282 | mask = QSFP_GPIO_MOD_PRS_N; | ||
283 | if (ppd->hw_pidx) | ||
284 | mask <<= QSFP_GPIO_PORT2_SHIFT; | ||
285 | |||
286 | ret = ppd->dd->f_gpio_mod(ppd->dd, 0, 0, 0); | ||
287 | if (ret & mask) { | ||
288 | ret = -ENODEV; | ||
289 | goto bail; | ||
290 | } | ||
291 | |||
292 | ret = qsfp_read(ppd, 0, peek, 3); | ||
293 | if (ret < 0) | ||
294 | goto bail; | ||
295 | if ((peek[0] & 0xFE) != 0x0C) | ||
296 | qib_dev_porterr(ppd->dd, ppd->port, | ||
297 | "QSFP byte0 is 0x%02X, S/B 0x0C/D\n", peek[0]); | ||
298 | |||
299 | if ((peek[2] & 2) == 0) { | ||
300 | /* | ||
301 | * If cable is paged, rather than "flat memory", we need to | ||
302 | * set the page to zero, Even if it already appears to be zero. | ||
303 | */ | ||
304 | u8 poke = 0; | ||
305 | ret = qib_qsfp_write(ppd, 127, &poke, 1); | ||
306 | udelay(50); | ||
307 | if (ret != 1) { | ||
308 | qib_dev_porterr(ppd->dd, ppd->port, | ||
309 | "Failed QSFP Page set\n"); | ||
310 | goto bail; | ||
311 | } | ||
312 | } | ||
313 | |||
314 | ret = qsfp_read(ppd, QSFP_MOD_ID_OFFS, &cp->id, 1); | ||
315 | if (ret < 0) | ||
316 | goto bail; | ||
317 | if ((cp->id & 0xFE) != 0x0C) | ||
318 | qib_dev_porterr(ppd->dd, ppd->port, | ||
319 | "QSFP ID byte is 0x%02X, S/B 0x0C/D\n", cp->id); | ||
320 | cks = cp->id; | ||
321 | |||
322 | ret = qsfp_read(ppd, QSFP_MOD_PWR_OFFS, &cp->pwr, 1); | ||
323 | if (ret < 0) | ||
324 | goto bail; | ||
325 | cks += cp->pwr; | ||
326 | |||
327 | ret = qsfp_cks(ppd, QSFP_MOD_PWR_OFFS + 1, QSFP_MOD_LEN_OFFS); | ||
328 | if (ret < 0) | ||
329 | goto bail; | ||
330 | cks += ret; | ||
331 | |||
332 | ret = qsfp_read(ppd, QSFP_MOD_LEN_OFFS, &cp->len, 1); | ||
333 | if (ret < 0) | ||
334 | goto bail; | ||
335 | cks += cp->len; | ||
336 | |||
337 | ret = qsfp_read(ppd, QSFP_MOD_TECH_OFFS, &cp->tech, 1); | ||
338 | if (ret < 0) | ||
339 | goto bail; | ||
340 | cks += cp->tech; | ||
341 | |||
342 | ret = qsfp_read(ppd, QSFP_VEND_OFFS, &cp->vendor, QSFP_VEND_LEN); | ||
343 | if (ret < 0) | ||
344 | goto bail; | ||
345 | for (idx = 0; idx < QSFP_VEND_LEN; ++idx) | ||
346 | cks += cp->vendor[idx]; | ||
347 | |||
348 | ret = qsfp_read(ppd, QSFP_IBXCV_OFFS, &cp->xt_xcv, 1); | ||
349 | if (ret < 0) | ||
350 | goto bail; | ||
351 | cks += cp->xt_xcv; | ||
352 | |||
353 | ret = qsfp_read(ppd, QSFP_VOUI_OFFS, &cp->oui, QSFP_VOUI_LEN); | ||
354 | if (ret < 0) | ||
355 | goto bail; | ||
356 | for (idx = 0; idx < QSFP_VOUI_LEN; ++idx) | ||
357 | cks += cp->oui[idx]; | ||
358 | |||
359 | ret = qsfp_read(ppd, QSFP_PN_OFFS, &cp->partnum, QSFP_PN_LEN); | ||
360 | if (ret < 0) | ||
361 | goto bail; | ||
362 | for (idx = 0; idx < QSFP_PN_LEN; ++idx) | ||
363 | cks += cp->partnum[idx]; | ||
364 | |||
365 | ret = qsfp_read(ppd, QSFP_REV_OFFS, &cp->rev, QSFP_REV_LEN); | ||
366 | if (ret < 0) | ||
367 | goto bail; | ||
368 | for (idx = 0; idx < QSFP_REV_LEN; ++idx) | ||
369 | cks += cp->rev[idx]; | ||
370 | |||
371 | ret = qsfp_read(ppd, QSFP_ATTEN_OFFS, &cp->atten, QSFP_ATTEN_LEN); | ||
372 | if (ret < 0) | ||
373 | goto bail; | ||
374 | for (idx = 0; idx < QSFP_ATTEN_LEN; ++idx) | ||
375 | cks += cp->atten[idx]; | ||
376 | |||
377 | ret = qsfp_cks(ppd, QSFP_ATTEN_OFFS + QSFP_ATTEN_LEN, QSFP_CC_OFFS); | ||
378 | if (ret < 0) | ||
379 | goto bail; | ||
380 | cks += ret; | ||
381 | |||
382 | cks &= 0xFF; | ||
383 | ret = qsfp_read(ppd, QSFP_CC_OFFS, &cp->cks1, 1); | ||
384 | if (ret < 0) | ||
385 | goto bail; | ||
386 | if (cks != cp->cks1) | ||
387 | qib_dev_porterr(ppd->dd, ppd->port, | ||
388 | "QSFP cks1 is %02X, computed %02X\n", cp->cks1, | ||
389 | cks); | ||
390 | |||
391 | /* Second checksum covers 192 to (serial, date, lot) */ | ||
392 | ret = qsfp_cks(ppd, QSFP_CC_OFFS + 1, QSFP_SN_OFFS); | ||
393 | if (ret < 0) | ||
394 | goto bail; | ||
395 | cks = ret; | ||
396 | |||
397 | ret = qsfp_read(ppd, QSFP_SN_OFFS, &cp->serial, QSFP_SN_LEN); | ||
398 | if (ret < 0) | ||
399 | goto bail; | ||
400 | for (idx = 0; idx < QSFP_SN_LEN; ++idx) | ||
401 | cks += cp->serial[idx]; | ||
402 | |||
403 | ret = qsfp_read(ppd, QSFP_DATE_OFFS, &cp->date, QSFP_DATE_LEN); | ||
404 | if (ret < 0) | ||
405 | goto bail; | ||
406 | for (idx = 0; idx < QSFP_DATE_LEN; ++idx) | ||
407 | cks += cp->date[idx]; | ||
408 | |||
409 | ret = qsfp_read(ppd, QSFP_LOT_OFFS, &cp->lot, QSFP_LOT_LEN); | ||
410 | if (ret < 0) | ||
411 | goto bail; | ||
412 | for (idx = 0; idx < QSFP_LOT_LEN; ++idx) | ||
413 | cks += cp->lot[idx]; | ||
414 | |||
415 | ret = qsfp_cks(ppd, QSFP_LOT_OFFS + QSFP_LOT_LEN, QSFP_CC_EXT_OFFS); | ||
416 | if (ret < 0) | ||
417 | goto bail; | ||
418 | cks += ret; | ||
419 | |||
420 | ret = qsfp_read(ppd, QSFP_CC_EXT_OFFS, &cp->cks2, 1); | ||
421 | if (ret < 0) | ||
422 | goto bail; | ||
423 | cks &= 0xFF; | ||
424 | if (cks != cp->cks2) | ||
425 | qib_dev_porterr(ppd->dd, ppd->port, | ||
426 | "QSFP cks2 is %02X, computed %02X\n", cp->cks2, | ||
427 | cks); | ||
428 | return 0; | ||
429 | |||
430 | bail: | ||
431 | cp->id = 0; | ||
432 | return ret; | ||
433 | } | ||
434 | |||
435 | const char * const qib_qsfp_devtech[16] = { | ||
436 | "850nm VCSEL", "1310nm VCSEL", "1550nm VCSEL", "1310nm FP", | ||
437 | "1310nm DFB", "1550nm DFB", "1310nm EML", "1550nm EML", | ||
438 | "Cu Misc", "1490nm DFB", "Cu NoEq", "Cu Eq", | ||
439 | "Undef", "Cu Active BothEq", "Cu FarEq", "Cu NearEq" | ||
440 | }; | ||
441 | |||
442 | #define QSFP_DUMP_CHUNK 16 /* Holds longest string */ | ||
443 | #define QSFP_DEFAULT_HDR_CNT 224 | ||
444 | |||
445 | static const char *pwr_codes = "1.5W2.0W2.5W3.5W"; | ||
446 | |||
447 | /* | ||
448 | * Initialize structures that control access to QSFP. Called once per port | ||
449 | * on cards that support QSFP. | ||
450 | */ | ||
451 | void qib_qsfp_init(struct qib_qsfp_data *qd, | ||
452 | void (*fevent)(struct work_struct *)) | ||
453 | { | ||
454 | u32 mask, highs; | ||
455 | int pins; | ||
456 | |||
457 | struct qib_devdata *dd = qd->ppd->dd; | ||
458 | |||
459 | /* Initialize work struct for later QSFP events */ | ||
460 | INIT_WORK(&qd->work, fevent); | ||
461 | |||
462 | /* | ||
463 | * Later, we may want more validation. For now, just set up pins and | ||
464 | * blip reset. If module is present, call qib_refresh_qsfp_cache(), | ||
465 | * to do further init. | ||
466 | */ | ||
467 | mask = QSFP_GPIO_MOD_SEL_N | QSFP_GPIO_MOD_RST_N | QSFP_GPIO_LP_MODE; | ||
468 | highs = mask - QSFP_GPIO_MOD_RST_N; | ||
469 | if (qd->ppd->hw_pidx) { | ||
470 | mask <<= QSFP_GPIO_PORT2_SHIFT; | ||
471 | highs <<= QSFP_GPIO_PORT2_SHIFT; | ||
472 | } | ||
473 | dd->f_gpio_mod(dd, highs, mask, mask); | ||
474 | udelay(20); /* Generous RST dwell */ | ||
475 | |||
476 | dd->f_gpio_mod(dd, mask, mask, mask); | ||
477 | /* Spec says module can take up to two seconds! */ | ||
478 | mask = QSFP_GPIO_MOD_PRS_N; | ||
479 | if (qd->ppd->hw_pidx) | ||
480 | mask <<= QSFP_GPIO_PORT2_SHIFT; | ||
481 | |||
482 | /* Do not try to wait here. Better to let event handle it */ | ||
483 | pins = dd->f_gpio_mod(dd, 0, 0, 0); | ||
484 | if (pins & mask) | ||
485 | goto bail; | ||
486 | /* We see a module, but it may be unwise to look yet. Just schedule */ | ||
487 | qd->t_insert = get_jiffies_64(); | ||
488 | schedule_work(&qd->work); | ||
489 | bail: | ||
490 | return; | ||
491 | } | ||
492 | |||
493 | void qib_qsfp_deinit(struct qib_qsfp_data *qd) | ||
494 | { | ||
495 | /* | ||
496 | * There is nothing to do here for now. our | ||
497 | * work is scheduled with schedule_work(), and | ||
498 | * flush_scheduled_work() from remove_one will | ||
499 | * block until all work ssetup with schedule_work() | ||
500 | * completes. | ||
501 | */ | ||
502 | } | ||
503 | |||
504 | int qib_qsfp_dump(struct qib_pportdata *ppd, char *buf, int len) | ||
505 | { | ||
506 | struct qib_qsfp_cache cd; | ||
507 | u8 bin_buff[QSFP_DUMP_CHUNK]; | ||
508 | char lenstr[6]; | ||
509 | int sofar, ret; | ||
510 | int bidx = 0; | ||
511 | |||
512 | sofar = 0; | ||
513 | ret = qib_refresh_qsfp_cache(ppd, &cd); | ||
514 | if (ret < 0) | ||
515 | goto bail; | ||
516 | |||
517 | lenstr[0] = ' '; | ||
518 | lenstr[1] = '\0'; | ||
519 | if (QSFP_IS_CU(cd.tech)) | ||
520 | sprintf(lenstr, "%dM ", cd.len); | ||
521 | |||
522 | sofar += scnprintf(buf + sofar, len - sofar, "PWR:%.3sW\n", pwr_codes + | ||
523 | (QSFP_PWR(cd.pwr) * 4)); | ||
524 | |||
525 | sofar += scnprintf(buf + sofar, len - sofar, "TECH:%s%s\n", lenstr, | ||
526 | qib_qsfp_devtech[cd.tech >> 4]); | ||
527 | |||
528 | sofar += scnprintf(buf + sofar, len - sofar, "Vendor:%.*s\n", | ||
529 | QSFP_VEND_LEN, cd.vendor); | ||
530 | |||
531 | sofar += scnprintf(buf + sofar, len - sofar, "OUI:%06X\n", | ||
532 | QSFP_OUI(cd.oui)); | ||
533 | |||
534 | sofar += scnprintf(buf + sofar, len - sofar, "Part#:%.*s\n", | ||
535 | QSFP_PN_LEN, cd.partnum); | ||
536 | sofar += scnprintf(buf + sofar, len - sofar, "Rev:%.*s\n", | ||
537 | QSFP_REV_LEN, cd.rev); | ||
538 | if (QSFP_IS_CU(cd.tech)) | ||
539 | sofar += scnprintf(buf + sofar, len - sofar, "Atten:%d, %d\n", | ||
540 | QSFP_ATTEN_SDR(cd.atten), | ||
541 | QSFP_ATTEN_DDR(cd.atten)); | ||
542 | sofar += scnprintf(buf + sofar, len - sofar, "Serial:%.*s\n", | ||
543 | QSFP_SN_LEN, cd.serial); | ||
544 | sofar += scnprintf(buf + sofar, len - sofar, "Date:%.*s\n", | ||
545 | QSFP_DATE_LEN, cd.date); | ||
546 | sofar += scnprintf(buf + sofar, len - sofar, "Lot:%.*s\n", | ||
547 | QSFP_LOT_LEN, cd.date); | ||
548 | |||
549 | while (bidx < QSFP_DEFAULT_HDR_CNT) { | ||
550 | int iidx; | ||
551 | ret = qsfp_read(ppd, bidx, bin_buff, QSFP_DUMP_CHUNK); | ||
552 | if (ret < 0) | ||
553 | goto bail; | ||
554 | for (iidx = 0; iidx < ret; ++iidx) { | ||
555 | sofar += scnprintf(buf + sofar, len-sofar, " %02X", | ||
556 | bin_buff[iidx]); | ||
557 | } | ||
558 | sofar += scnprintf(buf + sofar, len - sofar, "\n"); | ||
559 | bidx += QSFP_DUMP_CHUNK; | ||
560 | } | ||
561 | ret = sofar; | ||
562 | bail: | ||
563 | return ret; | ||
564 | } | ||