int qib_refresh_qsfp_cache(struct qib_pportdata *ppd, struct qib_qsfp_cache *cp) { int ret; int idx; u16 cks; u8 peek[4]; /* ensure sane contents on invalid reads, for cable swaps */ memset(cp, 0, sizeof(*cp)); if (!qib_qsfp_mod_present(ppd)) { qib_dbg("No QSFP module in %d:%d\n", ppd->dd->unit, ppd->port); ret = -ENODEV; goto bail; } ret = qsfp_read(ppd, 0, peek, 3); if (ret < 0) goto bail; if ((peek[0] & 0xFE) != 0x0C) qib_dev_porterr(ppd->dd, ppd->port, "QSFP byte0 is 0x%02X, S/B 0x0C/D\n", peek[0]); if ((peek[2] & 2) == 0) { /* * If cable is paged, rather than "flat memory", we need to * set the page to zero, Even if it already appears to be zero. */ u8 poke = 0; ret = qib_qsfp_write(ppd, 127, &poke, 1); udelay(50); if (ret != 1) { qib_dev_porterr(ppd->dd, ppd->port, "Failed QSFP Page set\n"); goto bail; } } ret = qsfp_read(ppd, QSFP_MOD_ID_OFFS, &cp->id, 1); if (ret < 0) goto bail; if ((cp->id & 0xFE) != 0x0C) qib_dev_porterr(ppd->dd, ppd->port, "QSFP ID byte is 0x%02X, S/B 0x0C/D\n", cp->id); cks = cp->id; ret = qsfp_read(ppd, QSFP_MOD_PWR_OFFS, &cp->pwr, 1); if (ret < 0) goto bail; cks += cp->pwr; ret = qsfp_cks(ppd, QSFP_MOD_PWR_OFFS + 1, QSFP_MOD_LEN_OFFS); if (ret < 0) goto bail; cks += ret; ret = qsfp_read(ppd, QSFP_MOD_LEN_OFFS, &cp->len, 1); if (ret < 0) goto bail; cks += cp->len; ret = qsfp_read(ppd, QSFP_MOD_TECH_OFFS, &cp->tech, 1); if (ret < 0) goto bail; cks += cp->tech; ret = qsfp_read(ppd, QSFP_VEND_OFFS, &cp->vendor, QSFP_VEND_LEN); if (ret < 0) goto bail; for (idx = 0; idx < QSFP_VEND_LEN; ++idx) cks += cp->vendor[idx]; ret = qsfp_read(ppd, QSFP_IBXCV_OFFS, &cp->xt_xcv, 1); if (ret < 0) goto bail; cks += cp->xt_xcv; ret = qsfp_read(ppd, QSFP_VOUI_OFFS, &cp->oui, QSFP_VOUI_LEN); if (ret < 0) goto bail; for (idx = 0; idx < QSFP_VOUI_LEN; ++idx) cks += cp->oui[idx]; ret = qsfp_read(ppd, QSFP_PN_OFFS, &cp->partnum, QSFP_PN_LEN); if (ret < 0) goto bail; for (idx = 0; idx < QSFP_PN_LEN; ++idx) cks += cp->partnum[idx]; ret = qsfp_read(ppd, QSFP_REV_OFFS, &cp->rev, QSFP_REV_LEN); if (ret < 0) goto bail; for (idx = 0; idx < QSFP_REV_LEN; ++idx) cks += cp->rev[idx]; ret = qsfp_read(ppd, QSFP_ATTEN_OFFS, &cp->atten, QSFP_ATTEN_LEN); if (ret < 0) goto bail; for (idx = 0; idx < QSFP_ATTEN_LEN; ++idx) cks += cp->atten[idx]; ret = qsfp_cks(ppd, QSFP_ATTEN_OFFS + QSFP_ATTEN_LEN, QSFP_CC_OFFS); if (ret < 0) goto bail; cks += ret; cks &= 0xFF; ret = qsfp_read(ppd, QSFP_CC_OFFS, &cp->cks1, 1); if (ret < 0) goto bail; if (cks != cp->cks1) qib_dev_porterr(ppd->dd, ppd->port, "QSFP cks1 is %02X, computed %02X\n", cp->cks1, cks); /* Second checksum covers 192 to (serial, date, lot) */ ret = qsfp_cks(ppd, QSFP_CC_OFFS + 1, QSFP_SN_OFFS); if (ret < 0) goto bail; cks = ret; ret = qsfp_read(ppd, QSFP_SN_OFFS, &cp->serial, QSFP_SN_LEN); if (ret < 0) goto bail; for (idx = 0; idx < QSFP_SN_LEN; ++idx) cks += cp->serial[idx]; ret = qsfp_read(ppd, QSFP_DATE_OFFS, &cp->date, QSFP_DATE_LEN); if (ret < 0) goto bail; for (idx = 0; idx < QSFP_DATE_LEN; ++idx) cks += cp->date[idx]; ret = qsfp_read(ppd, QSFP_LOT_OFFS, &cp->lot, QSFP_LOT_LEN); if (ret < 0) goto bail; for (idx = 0; idx < QSFP_LOT_LEN; ++idx) cks += cp->lot[idx]; ret = qsfp_cks(ppd, QSFP_LOT_OFFS + QSFP_LOT_LEN, QSFP_CC_EXT_OFFS); if (ret < 0) goto bail; cks += ret; ret = qsfp_read(ppd, QSFP_CC_EXT_OFFS, &cp->cks2, 1); if (ret < 0) goto bail; cks &= 0xFF; if (cks != cp->cks2) qib_dev_porterr(ppd->dd, ppd->port, "QSFP cks2 is %02X, computed %02X\n", cp->cks2, cks); return 0; bail: cp->id = 0; return ret; }
static int qsfp_read(struct qib_pportdata *ppd, int addr, void *bp, int len) { struct qib_devdata *dd = ppd->dd; u32 out, mask; int ret, cnt, pass = 0; int stuck = 0; u8 *buff = bp; qib_cdbg(VERBOSE, "Grabbing Mutex for QSFP in %d:%d\n", dd->unit, ppd->port); ret = mutex_lock_interruptible(&dd->eep_lock); if (ret) goto no_unlock; if (dd->twsi_eeprom_dev == QIB_TWSI_NO_DEV) { qib_dbg("QSFP read on board without QSFP\n"); ret = -ENXIO; goto bail; } /* * We presume, if we are called at all, that this board has * QSFP. This is on the same i2c chain as the legacy parts, * but only responds if the module is selected via GPIO pins. * Further, there are very long setup and hold requirements * on MODSEL. */ mask = QSFP_GPIO_MOD_SEL_N | QSFP_GPIO_MOD_RST_N | QSFP_GPIO_LP_MODE; out = QSFP_GPIO_MOD_RST_N | QSFP_GPIO_LP_MODE; if (ppd->hw_pidx) { mask <<= QSFP_GPIO_PORT2_SHIFT; out <<= QSFP_GPIO_PORT2_SHIFT; } dd->f_gpio_mod(dd, out, mask, mask); /* * Module could take up to 2 Msec to respond to MOD_SEL, and there * is no way to tell if it is ready, so we must wait. */ msleep(2); /* Make sure TWSI bus is in sane state. */ ret = qib_twsi_reset(dd); if (ret) { qib_dev_porterr(dd, ppd->port, "QSFP interface Reset for read failed\n"); ret = -EIO; stuck = 1; goto deselect; } /* All QSFP modules are at A0 */ cnt = 0; while (cnt < len) { unsigned in_page; int wlen = len - cnt; in_page = addr % QSFP_PAGESIZE; if ((in_page + wlen) > QSFP_PAGESIZE) wlen = QSFP_PAGESIZE - in_page; ret = qib_twsi_blk_rd(dd, QSFP_DEV, addr, buff + cnt, wlen); /* Some QSFP's fail first try. Retry as experiment */ if (ret && cnt == 0 && ++pass < QSFP_MAX_RETRY) continue; if (ret) { /* qib_twsi_blk_rd() 1 for error, else 0 */ ret = -EIO; goto deselect; } addr += wlen; cnt += wlen; } ret = cnt; deselect: /* * Module could take up to 10 uSec after transfer before * ready to respond to MOD_SEL negation, and there is no way * to tell if it is ready, so we must wait. */ udelay(10); /* set QSFP MODSEL, RST. LP all high */ dd->f_gpio_mod(dd, mask, mask, mask); /* * Module could take up to 2 Msec to respond to MOD_SEL * going away, and there is no way to tell if it is ready. * so we must wait. */ if (stuck) qib_dev_err(dd, "QSFP interface bus stuck non-idle\n"); if (pass >= QSFP_MAX_RETRY && ret) qib_dev_porterr(dd, ppd->port, "QSFP failed even retrying\n"); else if (pass) qib_dev_porterr(dd, ppd->port, "QSFP retries: %d\n", pass); msleep(2); bail: mutex_unlock(&dd->eep_lock); qib_cdbg(VERBOSE, "Released Mutex for QSFP %d:%d, ret %d\n", dd->unit, ppd->port, ret); no_unlock: return ret; }
/* * qsfp_write * We do not ordinarily write the QSFP, but this is needed to select * the page on non-flat QSFPs, and possibly later unusual cases */ static int qib_qsfp_write(struct qib_pportdata *ppd, int addr, void *bp, int len) { struct qib_devdata *dd = ppd->dd; u32 out, mask; int ret, cnt; u8 *buff = bp; ret = mutex_lock_interruptible(&dd->eep_lock); if (ret) goto no_unlock; if (dd->twsi_eeprom_dev == QIB_TWSI_NO_DEV) { ret = -ENXIO; goto bail; } /* * We presume, if we are called at all, that this board has * QSFP. This is on the same i2c chain as the legacy parts, * but only responds if the module is selected via GPIO pins. * Further, there are very long setup and hold requirements * on MODSEL. */ mask = QSFP_GPIO_MOD_SEL_N | QSFP_GPIO_MOD_RST_N | QSFP_GPIO_LP_MODE; out = QSFP_GPIO_MOD_RST_N | QSFP_GPIO_LP_MODE; if (ppd->hw_pidx) { mask <<= QSFP_GPIO_PORT2_SHIFT; out <<= QSFP_GPIO_PORT2_SHIFT; } dd->f_gpio_mod(dd, out, mask, mask); /* * Module could take up to 2 Msec to respond to MOD_SEL, * and there is no way to tell if it is ready, so we must wait. */ msleep(2); /* Make sure TWSI bus is in sane state. */ ret = qib_twsi_reset(dd); if (ret) { qib_dev_porterr(dd, ppd->port, "QSFP interface Reset for write failed\n"); ret = -EIO; goto deselect; } /* All QSFP modules are at A0 */ cnt = 0; while (cnt < len) { unsigned in_page; int wlen = len - cnt; in_page = addr % QSFP_PAGESIZE; if ((in_page + wlen) > QSFP_PAGESIZE) wlen = QSFP_PAGESIZE - in_page; ret = qib_twsi_blk_wr(dd, QSFP_DEV, addr, buff + cnt, wlen); if (ret) { /* qib_twsi_blk_wr() 1 for error, else 0 */ ret = -EIO; goto deselect; } addr += wlen; cnt += wlen; } ret = cnt; deselect: /* * Module could take up to 10 uSec after transfer before * ready to respond to MOD_SEL negation, and there is no way * to tell if it is ready, so we must wait. */ udelay(10); /* set QSFP MODSEL, RST, LP high */ dd->f_gpio_mod(dd, mask, mask, mask); /* * Module could take up to 2 Msec to respond to MOD_SEL * going away, and there is no way to tell if it is ready. * so we must wait. */ msleep(2); bail: mutex_unlock(&dd->eep_lock); no_unlock: return ret; }