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