162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2006, 2007, 2008, 2009 QLogic Corporation. All rights reserved. 362306a36Sopenharmony_ci * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * This software is available to you under a choice of one of two 662306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 762306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 862306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 962306a36Sopenharmony_ci * OpenIB.org BSD license below: 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1262306a36Sopenharmony_ci * without modification, are permitted provided that the following 1362306a36Sopenharmony_ci * conditions are met: 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * - Redistributions of source code must retain the above 1662306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 1762306a36Sopenharmony_ci * disclaimer. 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 2062306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2162306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials 2262306a36Sopenharmony_ci * provided with the distribution. 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2562306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2662306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2762306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 2862306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 2962306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 3062306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3162306a36Sopenharmony_ci * SOFTWARE. 3262306a36Sopenharmony_ci */ 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#include <linux/delay.h> 3562306a36Sopenharmony_ci#include <linux/pci.h> 3662306a36Sopenharmony_ci#include <linux/vmalloc.h> 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#include "qib.h" 3962306a36Sopenharmony_ci#include "qib_qsfp.h" 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/* 4262306a36Sopenharmony_ci * QSFP support for ib_qib driver, using "Two Wire Serial Interface" driver 4362306a36Sopenharmony_ci * in qib_twsi.c 4462306a36Sopenharmony_ci */ 4562306a36Sopenharmony_ci#define QSFP_MAX_RETRY 4 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic int qsfp_read(struct qib_pportdata *ppd, int addr, void *bp, int len) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci struct qib_devdata *dd = ppd->dd; 5062306a36Sopenharmony_ci u32 out, mask; 5162306a36Sopenharmony_ci int ret, cnt, pass = 0; 5262306a36Sopenharmony_ci int stuck = 0; 5362306a36Sopenharmony_ci u8 *buff = bp; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci ret = mutex_lock_interruptible(&dd->eep_lock); 5662306a36Sopenharmony_ci if (ret) 5762306a36Sopenharmony_ci goto no_unlock; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci if (dd->twsi_eeprom_dev == QIB_TWSI_NO_DEV) { 6062306a36Sopenharmony_ci ret = -ENXIO; 6162306a36Sopenharmony_ci goto bail; 6262306a36Sopenharmony_ci } 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci /* 6562306a36Sopenharmony_ci * We presume, if we are called at all, that this board has 6662306a36Sopenharmony_ci * QSFP. This is on the same i2c chain as the legacy parts, 6762306a36Sopenharmony_ci * but only responds if the module is selected via GPIO pins. 6862306a36Sopenharmony_ci * Further, there are very long setup and hold requirements 6962306a36Sopenharmony_ci * on MODSEL. 7062306a36Sopenharmony_ci */ 7162306a36Sopenharmony_ci mask = QSFP_GPIO_MOD_SEL_N | QSFP_GPIO_MOD_RST_N | QSFP_GPIO_LP_MODE; 7262306a36Sopenharmony_ci out = QSFP_GPIO_MOD_RST_N | QSFP_GPIO_LP_MODE; 7362306a36Sopenharmony_ci if (ppd->hw_pidx) { 7462306a36Sopenharmony_ci mask <<= QSFP_GPIO_PORT2_SHIFT; 7562306a36Sopenharmony_ci out <<= QSFP_GPIO_PORT2_SHIFT; 7662306a36Sopenharmony_ci } 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci dd->f_gpio_mod(dd, out, mask, mask); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci /* 8162306a36Sopenharmony_ci * Module could take up to 2 Msec to respond to MOD_SEL, and there 8262306a36Sopenharmony_ci * is no way to tell if it is ready, so we must wait. 8362306a36Sopenharmony_ci */ 8462306a36Sopenharmony_ci msleep(20); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci /* Make sure TWSI bus is in sane state. */ 8762306a36Sopenharmony_ci ret = qib_twsi_reset(dd); 8862306a36Sopenharmony_ci if (ret) { 8962306a36Sopenharmony_ci qib_dev_porterr(dd, ppd->port, 9062306a36Sopenharmony_ci "QSFP interface Reset for read failed\n"); 9162306a36Sopenharmony_ci ret = -EIO; 9262306a36Sopenharmony_ci stuck = 1; 9362306a36Sopenharmony_ci goto deselect; 9462306a36Sopenharmony_ci } 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci /* All QSFP modules are at A0 */ 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci cnt = 0; 9962306a36Sopenharmony_ci while (cnt < len) { 10062306a36Sopenharmony_ci unsigned in_page; 10162306a36Sopenharmony_ci int wlen = len - cnt; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci in_page = addr % QSFP_PAGESIZE; 10462306a36Sopenharmony_ci if ((in_page + wlen) > QSFP_PAGESIZE) 10562306a36Sopenharmony_ci wlen = QSFP_PAGESIZE - in_page; 10662306a36Sopenharmony_ci ret = qib_twsi_blk_rd(dd, QSFP_DEV, addr, buff + cnt, wlen); 10762306a36Sopenharmony_ci /* Some QSFP's fail first try. Retry as experiment */ 10862306a36Sopenharmony_ci if (ret && cnt == 0 && ++pass < QSFP_MAX_RETRY) 10962306a36Sopenharmony_ci continue; 11062306a36Sopenharmony_ci if (ret) { 11162306a36Sopenharmony_ci /* qib_twsi_blk_rd() 1 for error, else 0 */ 11262306a36Sopenharmony_ci ret = -EIO; 11362306a36Sopenharmony_ci goto deselect; 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci addr += wlen; 11662306a36Sopenharmony_ci cnt += wlen; 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci ret = cnt; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cideselect: 12162306a36Sopenharmony_ci /* 12262306a36Sopenharmony_ci * Module could take up to 10 uSec after transfer before 12362306a36Sopenharmony_ci * ready to respond to MOD_SEL negation, and there is no way 12462306a36Sopenharmony_ci * to tell if it is ready, so we must wait. 12562306a36Sopenharmony_ci */ 12662306a36Sopenharmony_ci udelay(10); 12762306a36Sopenharmony_ci /* set QSFP MODSEL, RST. LP all high */ 12862306a36Sopenharmony_ci dd->f_gpio_mod(dd, mask, mask, mask); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci /* 13162306a36Sopenharmony_ci * Module could take up to 2 Msec to respond to MOD_SEL 13262306a36Sopenharmony_ci * going away, and there is no way to tell if it is ready. 13362306a36Sopenharmony_ci * so we must wait. 13462306a36Sopenharmony_ci */ 13562306a36Sopenharmony_ci if (stuck) 13662306a36Sopenharmony_ci qib_dev_err(dd, "QSFP interface bus stuck non-idle\n"); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci if (pass >= QSFP_MAX_RETRY && ret) 13962306a36Sopenharmony_ci qib_dev_porterr(dd, ppd->port, "QSFP failed even retrying\n"); 14062306a36Sopenharmony_ci else if (pass) 14162306a36Sopenharmony_ci qib_dev_porterr(dd, ppd->port, "QSFP retries: %d\n", pass); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci msleep(20); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cibail: 14662306a36Sopenharmony_ci mutex_unlock(&dd->eep_lock); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cino_unlock: 14962306a36Sopenharmony_ci return ret; 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci/* 15362306a36Sopenharmony_ci * qsfp_write 15462306a36Sopenharmony_ci * We do not ordinarily write the QSFP, but this is needed to select 15562306a36Sopenharmony_ci * the page on non-flat QSFPs, and possibly later unusual cases 15662306a36Sopenharmony_ci */ 15762306a36Sopenharmony_cistatic int qib_qsfp_write(struct qib_pportdata *ppd, int addr, void *bp, 15862306a36Sopenharmony_ci int len) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci struct qib_devdata *dd = ppd->dd; 16162306a36Sopenharmony_ci u32 out, mask; 16262306a36Sopenharmony_ci int ret, cnt; 16362306a36Sopenharmony_ci u8 *buff = bp; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci ret = mutex_lock_interruptible(&dd->eep_lock); 16662306a36Sopenharmony_ci if (ret) 16762306a36Sopenharmony_ci goto no_unlock; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci if (dd->twsi_eeprom_dev == QIB_TWSI_NO_DEV) { 17062306a36Sopenharmony_ci ret = -ENXIO; 17162306a36Sopenharmony_ci goto bail; 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci /* 17562306a36Sopenharmony_ci * We presume, if we are called at all, that this board has 17662306a36Sopenharmony_ci * QSFP. This is on the same i2c chain as the legacy parts, 17762306a36Sopenharmony_ci * but only responds if the module is selected via GPIO pins. 17862306a36Sopenharmony_ci * Further, there are very long setup and hold requirements 17962306a36Sopenharmony_ci * on MODSEL. 18062306a36Sopenharmony_ci */ 18162306a36Sopenharmony_ci mask = QSFP_GPIO_MOD_SEL_N | QSFP_GPIO_MOD_RST_N | QSFP_GPIO_LP_MODE; 18262306a36Sopenharmony_ci out = QSFP_GPIO_MOD_RST_N | QSFP_GPIO_LP_MODE; 18362306a36Sopenharmony_ci if (ppd->hw_pidx) { 18462306a36Sopenharmony_ci mask <<= QSFP_GPIO_PORT2_SHIFT; 18562306a36Sopenharmony_ci out <<= QSFP_GPIO_PORT2_SHIFT; 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci dd->f_gpio_mod(dd, out, mask, mask); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci /* 19062306a36Sopenharmony_ci * Module could take up to 2 Msec to respond to MOD_SEL, 19162306a36Sopenharmony_ci * and there is no way to tell if it is ready, so we must wait. 19262306a36Sopenharmony_ci */ 19362306a36Sopenharmony_ci msleep(20); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci /* Make sure TWSI bus is in sane state. */ 19662306a36Sopenharmony_ci ret = qib_twsi_reset(dd); 19762306a36Sopenharmony_ci if (ret) { 19862306a36Sopenharmony_ci qib_dev_porterr(dd, ppd->port, 19962306a36Sopenharmony_ci "QSFP interface Reset for write failed\n"); 20062306a36Sopenharmony_ci ret = -EIO; 20162306a36Sopenharmony_ci goto deselect; 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci /* All QSFP modules are at A0 */ 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci cnt = 0; 20762306a36Sopenharmony_ci while (cnt < len) { 20862306a36Sopenharmony_ci unsigned in_page; 20962306a36Sopenharmony_ci int wlen = len - cnt; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci in_page = addr % QSFP_PAGESIZE; 21262306a36Sopenharmony_ci if ((in_page + wlen) > QSFP_PAGESIZE) 21362306a36Sopenharmony_ci wlen = QSFP_PAGESIZE - in_page; 21462306a36Sopenharmony_ci ret = qib_twsi_blk_wr(dd, QSFP_DEV, addr, buff + cnt, wlen); 21562306a36Sopenharmony_ci if (ret) { 21662306a36Sopenharmony_ci /* qib_twsi_blk_wr() 1 for error, else 0 */ 21762306a36Sopenharmony_ci ret = -EIO; 21862306a36Sopenharmony_ci goto deselect; 21962306a36Sopenharmony_ci } 22062306a36Sopenharmony_ci addr += wlen; 22162306a36Sopenharmony_ci cnt += wlen; 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci ret = cnt; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_cideselect: 22662306a36Sopenharmony_ci /* 22762306a36Sopenharmony_ci * Module could take up to 10 uSec after transfer before 22862306a36Sopenharmony_ci * ready to respond to MOD_SEL negation, and there is no way 22962306a36Sopenharmony_ci * to tell if it is ready, so we must wait. 23062306a36Sopenharmony_ci */ 23162306a36Sopenharmony_ci udelay(10); 23262306a36Sopenharmony_ci /* set QSFP MODSEL, RST, LP high */ 23362306a36Sopenharmony_ci dd->f_gpio_mod(dd, mask, mask, mask); 23462306a36Sopenharmony_ci /* 23562306a36Sopenharmony_ci * Module could take up to 2 Msec to respond to MOD_SEL 23662306a36Sopenharmony_ci * going away, and there is no way to tell if it is ready. 23762306a36Sopenharmony_ci * so we must wait. 23862306a36Sopenharmony_ci */ 23962306a36Sopenharmony_ci msleep(20); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cibail: 24262306a36Sopenharmony_ci mutex_unlock(&dd->eep_lock); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cino_unlock: 24562306a36Sopenharmony_ci return ret; 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci/* 24962306a36Sopenharmony_ci * For validation, we want to check the checksums, even of the 25062306a36Sopenharmony_ci * fields we do not otherwise use. This function reads the bytes from 25162306a36Sopenharmony_ci * <first> to <next-1> and returns the 8lsbs of the sum, or <0 for errors 25262306a36Sopenharmony_ci */ 25362306a36Sopenharmony_cistatic int qsfp_cks(struct qib_pportdata *ppd, int first, int next) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci int ret; 25662306a36Sopenharmony_ci u16 cks; 25762306a36Sopenharmony_ci u8 bval; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci cks = 0; 26062306a36Sopenharmony_ci while (first < next) { 26162306a36Sopenharmony_ci ret = qsfp_read(ppd, first, &bval, 1); 26262306a36Sopenharmony_ci if (ret < 0) 26362306a36Sopenharmony_ci goto bail; 26462306a36Sopenharmony_ci cks += bval; 26562306a36Sopenharmony_ci ++first; 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci ret = cks & 0xFF; 26862306a36Sopenharmony_cibail: 26962306a36Sopenharmony_ci return ret; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci} 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ciint qib_refresh_qsfp_cache(struct qib_pportdata *ppd, struct qib_qsfp_cache *cp) 27462306a36Sopenharmony_ci{ 27562306a36Sopenharmony_ci int ret; 27662306a36Sopenharmony_ci int idx; 27762306a36Sopenharmony_ci u16 cks; 27862306a36Sopenharmony_ci u8 peek[4]; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci /* ensure sane contents on invalid reads, for cable swaps */ 28162306a36Sopenharmony_ci memset(cp, 0, sizeof(*cp)); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci if (!qib_qsfp_mod_present(ppd)) { 28462306a36Sopenharmony_ci ret = -ENODEV; 28562306a36Sopenharmony_ci goto bail; 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci ret = qsfp_read(ppd, 0, peek, 3); 28962306a36Sopenharmony_ci if (ret < 0) 29062306a36Sopenharmony_ci goto bail; 29162306a36Sopenharmony_ci if ((peek[0] & 0xFE) != 0x0C) 29262306a36Sopenharmony_ci qib_dev_porterr(ppd->dd, ppd->port, 29362306a36Sopenharmony_ci "QSFP byte0 is 0x%02X, S/B 0x0C/D\n", peek[0]); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci if ((peek[2] & 4) == 0) { 29662306a36Sopenharmony_ci /* 29762306a36Sopenharmony_ci * If cable is paged, rather than "flat memory", we need to 29862306a36Sopenharmony_ci * set the page to zero, Even if it already appears to be zero. 29962306a36Sopenharmony_ci */ 30062306a36Sopenharmony_ci u8 poke = 0; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci ret = qib_qsfp_write(ppd, 127, &poke, 1); 30362306a36Sopenharmony_ci udelay(50); 30462306a36Sopenharmony_ci if (ret != 1) { 30562306a36Sopenharmony_ci qib_dev_porterr(ppd->dd, ppd->port, 30662306a36Sopenharmony_ci "Failed QSFP Page set\n"); 30762306a36Sopenharmony_ci goto bail; 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci ret = qsfp_read(ppd, QSFP_MOD_ID_OFFS, &cp->id, 1); 31262306a36Sopenharmony_ci if (ret < 0) 31362306a36Sopenharmony_ci goto bail; 31462306a36Sopenharmony_ci if ((cp->id & 0xFE) != 0x0C) 31562306a36Sopenharmony_ci qib_dev_porterr(ppd->dd, ppd->port, 31662306a36Sopenharmony_ci "QSFP ID byte is 0x%02X, S/B 0x0C/D\n", cp->id); 31762306a36Sopenharmony_ci cks = cp->id; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci ret = qsfp_read(ppd, QSFP_MOD_PWR_OFFS, &cp->pwr, 1); 32062306a36Sopenharmony_ci if (ret < 0) 32162306a36Sopenharmony_ci goto bail; 32262306a36Sopenharmony_ci cks += cp->pwr; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci ret = qsfp_cks(ppd, QSFP_MOD_PWR_OFFS + 1, QSFP_MOD_LEN_OFFS); 32562306a36Sopenharmony_ci if (ret < 0) 32662306a36Sopenharmony_ci goto bail; 32762306a36Sopenharmony_ci cks += ret; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci ret = qsfp_read(ppd, QSFP_MOD_LEN_OFFS, &cp->len, 1); 33062306a36Sopenharmony_ci if (ret < 0) 33162306a36Sopenharmony_ci goto bail; 33262306a36Sopenharmony_ci cks += cp->len; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci ret = qsfp_read(ppd, QSFP_MOD_TECH_OFFS, &cp->tech, 1); 33562306a36Sopenharmony_ci if (ret < 0) 33662306a36Sopenharmony_ci goto bail; 33762306a36Sopenharmony_ci cks += cp->tech; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci ret = qsfp_read(ppd, QSFP_VEND_OFFS, &cp->vendor, QSFP_VEND_LEN); 34062306a36Sopenharmony_ci if (ret < 0) 34162306a36Sopenharmony_ci goto bail; 34262306a36Sopenharmony_ci for (idx = 0; idx < QSFP_VEND_LEN; ++idx) 34362306a36Sopenharmony_ci cks += cp->vendor[idx]; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci ret = qsfp_read(ppd, QSFP_IBXCV_OFFS, &cp->xt_xcv, 1); 34662306a36Sopenharmony_ci if (ret < 0) 34762306a36Sopenharmony_ci goto bail; 34862306a36Sopenharmony_ci cks += cp->xt_xcv; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci ret = qsfp_read(ppd, QSFP_VOUI_OFFS, &cp->oui, QSFP_VOUI_LEN); 35162306a36Sopenharmony_ci if (ret < 0) 35262306a36Sopenharmony_ci goto bail; 35362306a36Sopenharmony_ci for (idx = 0; idx < QSFP_VOUI_LEN; ++idx) 35462306a36Sopenharmony_ci cks += cp->oui[idx]; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci ret = qsfp_read(ppd, QSFP_PN_OFFS, &cp->partnum, QSFP_PN_LEN); 35762306a36Sopenharmony_ci if (ret < 0) 35862306a36Sopenharmony_ci goto bail; 35962306a36Sopenharmony_ci for (idx = 0; idx < QSFP_PN_LEN; ++idx) 36062306a36Sopenharmony_ci cks += cp->partnum[idx]; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci ret = qsfp_read(ppd, QSFP_REV_OFFS, &cp->rev, QSFP_REV_LEN); 36362306a36Sopenharmony_ci if (ret < 0) 36462306a36Sopenharmony_ci goto bail; 36562306a36Sopenharmony_ci for (idx = 0; idx < QSFP_REV_LEN; ++idx) 36662306a36Sopenharmony_ci cks += cp->rev[idx]; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci ret = qsfp_read(ppd, QSFP_ATTEN_OFFS, &cp->atten, QSFP_ATTEN_LEN); 36962306a36Sopenharmony_ci if (ret < 0) 37062306a36Sopenharmony_ci goto bail; 37162306a36Sopenharmony_ci for (idx = 0; idx < QSFP_ATTEN_LEN; ++idx) 37262306a36Sopenharmony_ci cks += cp->atten[idx]; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci ret = qsfp_cks(ppd, QSFP_ATTEN_OFFS + QSFP_ATTEN_LEN, QSFP_CC_OFFS); 37562306a36Sopenharmony_ci if (ret < 0) 37662306a36Sopenharmony_ci goto bail; 37762306a36Sopenharmony_ci cks += ret; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci cks &= 0xFF; 38062306a36Sopenharmony_ci ret = qsfp_read(ppd, QSFP_CC_OFFS, &cp->cks1, 1); 38162306a36Sopenharmony_ci if (ret < 0) 38262306a36Sopenharmony_ci goto bail; 38362306a36Sopenharmony_ci if (cks != cp->cks1) 38462306a36Sopenharmony_ci qib_dev_porterr(ppd->dd, ppd->port, 38562306a36Sopenharmony_ci "QSFP cks1 is %02X, computed %02X\n", cp->cks1, 38662306a36Sopenharmony_ci cks); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci /* Second checksum covers 192 to (serial, date, lot) */ 38962306a36Sopenharmony_ci ret = qsfp_cks(ppd, QSFP_CC_OFFS + 1, QSFP_SN_OFFS); 39062306a36Sopenharmony_ci if (ret < 0) 39162306a36Sopenharmony_ci goto bail; 39262306a36Sopenharmony_ci cks = ret; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci ret = qsfp_read(ppd, QSFP_SN_OFFS, &cp->serial, QSFP_SN_LEN); 39562306a36Sopenharmony_ci if (ret < 0) 39662306a36Sopenharmony_ci goto bail; 39762306a36Sopenharmony_ci for (idx = 0; idx < QSFP_SN_LEN; ++idx) 39862306a36Sopenharmony_ci cks += cp->serial[idx]; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci ret = qsfp_read(ppd, QSFP_DATE_OFFS, &cp->date, QSFP_DATE_LEN); 40162306a36Sopenharmony_ci if (ret < 0) 40262306a36Sopenharmony_ci goto bail; 40362306a36Sopenharmony_ci for (idx = 0; idx < QSFP_DATE_LEN; ++idx) 40462306a36Sopenharmony_ci cks += cp->date[idx]; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci ret = qsfp_read(ppd, QSFP_LOT_OFFS, &cp->lot, QSFP_LOT_LEN); 40762306a36Sopenharmony_ci if (ret < 0) 40862306a36Sopenharmony_ci goto bail; 40962306a36Sopenharmony_ci for (idx = 0; idx < QSFP_LOT_LEN; ++idx) 41062306a36Sopenharmony_ci cks += cp->lot[idx]; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci ret = qsfp_cks(ppd, QSFP_LOT_OFFS + QSFP_LOT_LEN, QSFP_CC_EXT_OFFS); 41362306a36Sopenharmony_ci if (ret < 0) 41462306a36Sopenharmony_ci goto bail; 41562306a36Sopenharmony_ci cks += ret; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci ret = qsfp_read(ppd, QSFP_CC_EXT_OFFS, &cp->cks2, 1); 41862306a36Sopenharmony_ci if (ret < 0) 41962306a36Sopenharmony_ci goto bail; 42062306a36Sopenharmony_ci cks &= 0xFF; 42162306a36Sopenharmony_ci if (cks != cp->cks2) 42262306a36Sopenharmony_ci qib_dev_porterr(ppd->dd, ppd->port, 42362306a36Sopenharmony_ci "QSFP cks2 is %02X, computed %02X\n", cp->cks2, 42462306a36Sopenharmony_ci cks); 42562306a36Sopenharmony_ci return 0; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_cibail: 42862306a36Sopenharmony_ci cp->id = 0; 42962306a36Sopenharmony_ci return ret; 43062306a36Sopenharmony_ci} 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ciconst char * const qib_qsfp_devtech[16] = { 43362306a36Sopenharmony_ci "850nm VCSEL", "1310nm VCSEL", "1550nm VCSEL", "1310nm FP", 43462306a36Sopenharmony_ci "1310nm DFB", "1550nm DFB", "1310nm EML", "1550nm EML", 43562306a36Sopenharmony_ci "Cu Misc", "1490nm DFB", "Cu NoEq", "Cu Eq", 43662306a36Sopenharmony_ci "Undef", "Cu Active BothEq", "Cu FarEq", "Cu NearEq" 43762306a36Sopenharmony_ci}; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci#define QSFP_DUMP_CHUNK 16 /* Holds longest string */ 44062306a36Sopenharmony_ci#define QSFP_DEFAULT_HDR_CNT 224 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_cistatic const char *pwr_codes = "1.5W2.0W2.5W3.5W"; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ciint qib_qsfp_mod_present(struct qib_pportdata *ppd) 44562306a36Sopenharmony_ci{ 44662306a36Sopenharmony_ci u32 mask; 44762306a36Sopenharmony_ci int ret; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci mask = QSFP_GPIO_MOD_PRS_N << 45062306a36Sopenharmony_ci (ppd->hw_pidx * QSFP_GPIO_PORT2_SHIFT); 45162306a36Sopenharmony_ci ret = ppd->dd->f_gpio_mod(ppd->dd, 0, 0, 0); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci return !((ret & mask) >> 45462306a36Sopenharmony_ci ((ppd->hw_pidx * QSFP_GPIO_PORT2_SHIFT) + 3)); 45562306a36Sopenharmony_ci} 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci/* 45862306a36Sopenharmony_ci * Initialize structures that control access to QSFP. Called once per port 45962306a36Sopenharmony_ci * on cards that support QSFP. 46062306a36Sopenharmony_ci */ 46162306a36Sopenharmony_civoid qib_qsfp_init(struct qib_qsfp_data *qd, 46262306a36Sopenharmony_ci void (*fevent)(struct work_struct *)) 46362306a36Sopenharmony_ci{ 46462306a36Sopenharmony_ci u32 mask, highs; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci struct qib_devdata *dd = qd->ppd->dd; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci /* Initialize work struct for later QSFP events */ 46962306a36Sopenharmony_ci INIT_WORK(&qd->work, fevent); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci /* 47262306a36Sopenharmony_ci * Later, we may want more validation. For now, just set up pins and 47362306a36Sopenharmony_ci * blip reset. If module is present, call qib_refresh_qsfp_cache(), 47462306a36Sopenharmony_ci * to do further init. 47562306a36Sopenharmony_ci */ 47662306a36Sopenharmony_ci mask = QSFP_GPIO_MOD_SEL_N | QSFP_GPIO_MOD_RST_N | QSFP_GPIO_LP_MODE; 47762306a36Sopenharmony_ci highs = mask - QSFP_GPIO_MOD_RST_N; 47862306a36Sopenharmony_ci if (qd->ppd->hw_pidx) { 47962306a36Sopenharmony_ci mask <<= QSFP_GPIO_PORT2_SHIFT; 48062306a36Sopenharmony_ci highs <<= QSFP_GPIO_PORT2_SHIFT; 48162306a36Sopenharmony_ci } 48262306a36Sopenharmony_ci dd->f_gpio_mod(dd, highs, mask, mask); 48362306a36Sopenharmony_ci udelay(20); /* Generous RST dwell */ 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci dd->f_gpio_mod(dd, mask, mask, mask); 48662306a36Sopenharmony_ci} 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ciint qib_qsfp_dump(struct qib_pportdata *ppd, char *buf, int len) 48962306a36Sopenharmony_ci{ 49062306a36Sopenharmony_ci struct qib_qsfp_cache cd; 49162306a36Sopenharmony_ci u8 bin_buff[QSFP_DUMP_CHUNK]; 49262306a36Sopenharmony_ci char lenstr[6]; 49362306a36Sopenharmony_ci int sofar, ret; 49462306a36Sopenharmony_ci int bidx = 0; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci sofar = 0; 49762306a36Sopenharmony_ci ret = qib_refresh_qsfp_cache(ppd, &cd); 49862306a36Sopenharmony_ci if (ret < 0) 49962306a36Sopenharmony_ci goto bail; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci lenstr[0] = ' '; 50262306a36Sopenharmony_ci lenstr[1] = '\0'; 50362306a36Sopenharmony_ci if (QSFP_IS_CU(cd.tech)) 50462306a36Sopenharmony_ci sprintf(lenstr, "%dM ", cd.len); 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci sofar += scnprintf(buf + sofar, len - sofar, "PWR:%.3sW\n", pwr_codes + 50762306a36Sopenharmony_ci (QSFP_PWR(cd.pwr) * 4)); 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci sofar += scnprintf(buf + sofar, len - sofar, "TECH:%s%s\n", lenstr, 51062306a36Sopenharmony_ci qib_qsfp_devtech[cd.tech >> 4]); 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci sofar += scnprintf(buf + sofar, len - sofar, "Vendor:%.*s\n", 51362306a36Sopenharmony_ci QSFP_VEND_LEN, cd.vendor); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci sofar += scnprintf(buf + sofar, len - sofar, "OUI:%06X\n", 51662306a36Sopenharmony_ci QSFP_OUI(cd.oui)); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci sofar += scnprintf(buf + sofar, len - sofar, "Part#:%.*s\n", 51962306a36Sopenharmony_ci QSFP_PN_LEN, cd.partnum); 52062306a36Sopenharmony_ci sofar += scnprintf(buf + sofar, len - sofar, "Rev:%.*s\n", 52162306a36Sopenharmony_ci QSFP_REV_LEN, cd.rev); 52262306a36Sopenharmony_ci if (QSFP_IS_CU(cd.tech)) 52362306a36Sopenharmony_ci sofar += scnprintf(buf + sofar, len - sofar, "Atten:%d, %d\n", 52462306a36Sopenharmony_ci QSFP_ATTEN_SDR(cd.atten), 52562306a36Sopenharmony_ci QSFP_ATTEN_DDR(cd.atten)); 52662306a36Sopenharmony_ci sofar += scnprintf(buf + sofar, len - sofar, "Serial:%.*s\n", 52762306a36Sopenharmony_ci QSFP_SN_LEN, cd.serial); 52862306a36Sopenharmony_ci sofar += scnprintf(buf + sofar, len - sofar, "Date:%.*s\n", 52962306a36Sopenharmony_ci QSFP_DATE_LEN, cd.date); 53062306a36Sopenharmony_ci sofar += scnprintf(buf + sofar, len - sofar, "Lot:%.*s\n", 53162306a36Sopenharmony_ci QSFP_LOT_LEN, cd.lot); 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci while (bidx < QSFP_DEFAULT_HDR_CNT) { 53462306a36Sopenharmony_ci int iidx; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci ret = qsfp_read(ppd, bidx, bin_buff, QSFP_DUMP_CHUNK); 53762306a36Sopenharmony_ci if (ret < 0) 53862306a36Sopenharmony_ci goto bail; 53962306a36Sopenharmony_ci for (iidx = 0; iidx < ret; ++iidx) { 54062306a36Sopenharmony_ci sofar += scnprintf(buf + sofar, len-sofar, " %02X", 54162306a36Sopenharmony_ci bin_buff[iidx]); 54262306a36Sopenharmony_ci } 54362306a36Sopenharmony_ci sofar += scnprintf(buf + sofar, len - sofar, "\n"); 54462306a36Sopenharmony_ci bidx += QSFP_DUMP_CHUNK; 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci ret = sofar; 54762306a36Sopenharmony_cibail: 54862306a36Sopenharmony_ci return ret; 54962306a36Sopenharmony_ci} 550