xref: /openbmc/linux/drivers/infiniband/hw/hfi1/qsfp.c (revision f48ad614)
1f48ad614SDennis Dalessandro /*
2f48ad614SDennis Dalessandro  * Copyright(c) 2015, 2016 Intel Corporation.
3f48ad614SDennis Dalessandro  *
4f48ad614SDennis Dalessandro  * This file is provided under a dual BSD/GPLv2 license.  When using or
5f48ad614SDennis Dalessandro  * redistributing this file, you may do so under either license.
6f48ad614SDennis Dalessandro  *
7f48ad614SDennis Dalessandro  * GPL LICENSE SUMMARY
8f48ad614SDennis Dalessandro  *
9f48ad614SDennis Dalessandro  * This program is free software; you can redistribute it and/or modify
10f48ad614SDennis Dalessandro  * it under the terms of version 2 of the GNU General Public License as
11f48ad614SDennis Dalessandro  * published by the Free Software Foundation.
12f48ad614SDennis Dalessandro  *
13f48ad614SDennis Dalessandro  * This program is distributed in the hope that it will be useful, but
14f48ad614SDennis Dalessandro  * WITHOUT ANY WARRANTY; without even the implied warranty of
15f48ad614SDennis Dalessandro  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16f48ad614SDennis Dalessandro  * General Public License for more details.
17f48ad614SDennis Dalessandro  *
18f48ad614SDennis Dalessandro  * BSD LICENSE
19f48ad614SDennis Dalessandro  *
20f48ad614SDennis Dalessandro  * Redistribution and use in source and binary forms, with or without
21f48ad614SDennis Dalessandro  * modification, are permitted provided that the following conditions
22f48ad614SDennis Dalessandro  * are met:
23f48ad614SDennis Dalessandro  *
24f48ad614SDennis Dalessandro  *  - Redistributions of source code must retain the above copyright
25f48ad614SDennis Dalessandro  *    notice, this list of conditions and the following disclaimer.
26f48ad614SDennis Dalessandro  *  - Redistributions in binary form must reproduce the above copyright
27f48ad614SDennis Dalessandro  *    notice, this list of conditions and the following disclaimer in
28f48ad614SDennis Dalessandro  *    the documentation and/or other materials provided with the
29f48ad614SDennis Dalessandro  *    distribution.
30f48ad614SDennis Dalessandro  *  - Neither the name of Intel Corporation nor the names of its
31f48ad614SDennis Dalessandro  *    contributors may be used to endorse or promote products derived
32f48ad614SDennis Dalessandro  *    from this software without specific prior written permission.
33f48ad614SDennis Dalessandro  *
34f48ad614SDennis Dalessandro  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
35f48ad614SDennis Dalessandro  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
36f48ad614SDennis Dalessandro  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
37f48ad614SDennis Dalessandro  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
38f48ad614SDennis Dalessandro  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
39f48ad614SDennis Dalessandro  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
40f48ad614SDennis Dalessandro  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
41f48ad614SDennis Dalessandro  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
42f48ad614SDennis Dalessandro  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
43f48ad614SDennis Dalessandro  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
44f48ad614SDennis Dalessandro  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
45f48ad614SDennis Dalessandro  *
46f48ad614SDennis Dalessandro  */
47f48ad614SDennis Dalessandro 
48f48ad614SDennis Dalessandro #include <linux/delay.h>
49f48ad614SDennis Dalessandro #include <linux/pci.h>
50f48ad614SDennis Dalessandro #include <linux/vmalloc.h>
51f48ad614SDennis Dalessandro 
52f48ad614SDennis Dalessandro #include "hfi.h"
53f48ad614SDennis Dalessandro #include "twsi.h"
54f48ad614SDennis Dalessandro 
55f48ad614SDennis Dalessandro /*
56f48ad614SDennis Dalessandro  * QSFP support for hfi driver, using "Two Wire Serial Interface" driver
57f48ad614SDennis Dalessandro  * in twsi.c
58f48ad614SDennis Dalessandro  */
59f48ad614SDennis Dalessandro #define I2C_MAX_RETRY 4
60f48ad614SDennis Dalessandro 
61f48ad614SDennis Dalessandro /*
62f48ad614SDennis Dalessandro  * Raw i2c write.  No set-up or lock checking.
63f48ad614SDennis Dalessandro  */
64f48ad614SDennis Dalessandro static int __i2c_write(struct hfi1_pportdata *ppd, u32 target, int i2c_addr,
65f48ad614SDennis Dalessandro 		       int offset, void *bp, int len)
66f48ad614SDennis Dalessandro {
67f48ad614SDennis Dalessandro 	struct hfi1_devdata *dd = ppd->dd;
68f48ad614SDennis Dalessandro 	int ret, cnt;
69f48ad614SDennis Dalessandro 	u8 *buff = bp;
70f48ad614SDennis Dalessandro 
71f48ad614SDennis Dalessandro 	cnt = 0;
72f48ad614SDennis Dalessandro 	while (cnt < len) {
73f48ad614SDennis Dalessandro 		int wlen = len - cnt;
74f48ad614SDennis Dalessandro 
75f48ad614SDennis Dalessandro 		ret = hfi1_twsi_blk_wr(dd, target, i2c_addr, offset,
76f48ad614SDennis Dalessandro 				       buff + cnt, wlen);
77f48ad614SDennis Dalessandro 		if (ret) {
78f48ad614SDennis Dalessandro 			/* hfi1_twsi_blk_wr() 1 for error, else 0 */
79f48ad614SDennis Dalessandro 			return -EIO;
80f48ad614SDennis Dalessandro 		}
81f48ad614SDennis Dalessandro 		offset += wlen;
82f48ad614SDennis Dalessandro 		cnt += wlen;
83f48ad614SDennis Dalessandro 	}
84f48ad614SDennis Dalessandro 
85f48ad614SDennis Dalessandro 	/* Must wait min 20us between qsfp i2c transactions */
86f48ad614SDennis Dalessandro 	udelay(20);
87f48ad614SDennis Dalessandro 
88f48ad614SDennis Dalessandro 	return cnt;
89f48ad614SDennis Dalessandro }
90f48ad614SDennis Dalessandro 
91f48ad614SDennis Dalessandro /*
92f48ad614SDennis Dalessandro  * Caller must hold the i2c chain resource.
93f48ad614SDennis Dalessandro  */
94f48ad614SDennis Dalessandro int i2c_write(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, int offset,
95f48ad614SDennis Dalessandro 	      void *bp, int len)
96f48ad614SDennis Dalessandro {
97f48ad614SDennis Dalessandro 	int ret;
98f48ad614SDennis Dalessandro 
99f48ad614SDennis Dalessandro 	if (!check_chip_resource(ppd->dd, i2c_target(target), __func__))
100f48ad614SDennis Dalessandro 		return -EACCES;
101f48ad614SDennis Dalessandro 
102f48ad614SDennis Dalessandro 	/* make sure the TWSI bus is in a sane state */
103f48ad614SDennis Dalessandro 	ret = hfi1_twsi_reset(ppd->dd, target);
104f48ad614SDennis Dalessandro 	if (ret) {
105f48ad614SDennis Dalessandro 		hfi1_dev_porterr(ppd->dd, ppd->port,
106f48ad614SDennis Dalessandro 				 "I2C chain %d write interface reset failed\n",
107f48ad614SDennis Dalessandro 				 target);
108f48ad614SDennis Dalessandro 		return ret;
109f48ad614SDennis Dalessandro 	}
110f48ad614SDennis Dalessandro 
111f48ad614SDennis Dalessandro 	return __i2c_write(ppd, target, i2c_addr, offset, bp, len);
112f48ad614SDennis Dalessandro }
113f48ad614SDennis Dalessandro 
114f48ad614SDennis Dalessandro /*
115f48ad614SDennis Dalessandro  * Raw i2c read.  No set-up or lock checking.
116f48ad614SDennis Dalessandro  */
117f48ad614SDennis Dalessandro static int __i2c_read(struct hfi1_pportdata *ppd, u32 target, int i2c_addr,
118f48ad614SDennis Dalessandro 		      int offset, void *bp, int len)
119f48ad614SDennis Dalessandro {
120f48ad614SDennis Dalessandro 	struct hfi1_devdata *dd = ppd->dd;
121f48ad614SDennis Dalessandro 	int ret, cnt, pass = 0;
122f48ad614SDennis Dalessandro 	int orig_offset = offset;
123f48ad614SDennis Dalessandro 
124f48ad614SDennis Dalessandro 	cnt = 0;
125f48ad614SDennis Dalessandro 	while (cnt < len) {
126f48ad614SDennis Dalessandro 		int rlen = len - cnt;
127f48ad614SDennis Dalessandro 
128f48ad614SDennis Dalessandro 		ret = hfi1_twsi_blk_rd(dd, target, i2c_addr, offset,
129f48ad614SDennis Dalessandro 				       bp + cnt, rlen);
130f48ad614SDennis Dalessandro 		/* Some QSFP's fail first try. Retry as experiment */
131f48ad614SDennis Dalessandro 		if (ret && cnt == 0 && ++pass < I2C_MAX_RETRY)
132f48ad614SDennis Dalessandro 			continue;
133f48ad614SDennis Dalessandro 		if (ret) {
134f48ad614SDennis Dalessandro 			/* hfi1_twsi_blk_rd() 1 for error, else 0 */
135f48ad614SDennis Dalessandro 			ret = -EIO;
136f48ad614SDennis Dalessandro 			goto exit;
137f48ad614SDennis Dalessandro 		}
138f48ad614SDennis Dalessandro 		offset += rlen;
139f48ad614SDennis Dalessandro 		cnt += rlen;
140f48ad614SDennis Dalessandro 	}
141f48ad614SDennis Dalessandro 
142f48ad614SDennis Dalessandro 	ret = cnt;
143f48ad614SDennis Dalessandro 
144f48ad614SDennis Dalessandro exit:
145f48ad614SDennis Dalessandro 	if (ret < 0) {
146f48ad614SDennis Dalessandro 		hfi1_dev_porterr(dd, ppd->port,
147f48ad614SDennis Dalessandro 				 "I2C chain %d read failed, addr 0x%x, offset 0x%x, len %d\n",
148f48ad614SDennis Dalessandro 				 target, i2c_addr, orig_offset, len);
149f48ad614SDennis Dalessandro 	}
150f48ad614SDennis Dalessandro 
151f48ad614SDennis Dalessandro 	/* Must wait min 20us between qsfp i2c transactions */
152f48ad614SDennis Dalessandro 	udelay(20);
153f48ad614SDennis Dalessandro 
154f48ad614SDennis Dalessandro 	return ret;
155f48ad614SDennis Dalessandro }
156f48ad614SDennis Dalessandro 
157f48ad614SDennis Dalessandro /*
158f48ad614SDennis Dalessandro  * Caller must hold the i2c chain resource.
159f48ad614SDennis Dalessandro  */
160f48ad614SDennis Dalessandro int i2c_read(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, int offset,
161f48ad614SDennis Dalessandro 	     void *bp, int len)
162f48ad614SDennis Dalessandro {
163f48ad614SDennis Dalessandro 	int ret;
164f48ad614SDennis Dalessandro 
165f48ad614SDennis Dalessandro 	if (!check_chip_resource(ppd->dd, i2c_target(target), __func__))
166f48ad614SDennis Dalessandro 		return -EACCES;
167f48ad614SDennis Dalessandro 
168f48ad614SDennis Dalessandro 	/* make sure the TWSI bus is in a sane state */
169f48ad614SDennis Dalessandro 	ret = hfi1_twsi_reset(ppd->dd, target);
170f48ad614SDennis Dalessandro 	if (ret) {
171f48ad614SDennis Dalessandro 		hfi1_dev_porterr(ppd->dd, ppd->port,
172f48ad614SDennis Dalessandro 				 "I2C chain %d read interface reset failed\n",
173f48ad614SDennis Dalessandro 				 target);
174f48ad614SDennis Dalessandro 		return ret;
175f48ad614SDennis Dalessandro 	}
176f48ad614SDennis Dalessandro 
177f48ad614SDennis Dalessandro 	return __i2c_read(ppd, target, i2c_addr, offset, bp, len);
178f48ad614SDennis Dalessandro }
179f48ad614SDennis Dalessandro 
180f48ad614SDennis Dalessandro /*
181f48ad614SDennis Dalessandro  * Write page n, offset m of QSFP memory as defined by SFF 8636
182f48ad614SDennis Dalessandro  * by writing @addr = ((256 * n) + m)
183f48ad614SDennis Dalessandro  *
184f48ad614SDennis Dalessandro  * Caller must hold the i2c chain resource.
185f48ad614SDennis Dalessandro  */
186f48ad614SDennis Dalessandro int qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
187f48ad614SDennis Dalessandro 	       int len)
188f48ad614SDennis Dalessandro {
189f48ad614SDennis Dalessandro 	int count = 0;
190f48ad614SDennis Dalessandro 	int offset;
191f48ad614SDennis Dalessandro 	int nwrite;
192f48ad614SDennis Dalessandro 	int ret;
193f48ad614SDennis Dalessandro 	u8 page;
194f48ad614SDennis Dalessandro 
195f48ad614SDennis Dalessandro 	if (!check_chip_resource(ppd->dd, i2c_target(target), __func__))
196f48ad614SDennis Dalessandro 		return -EACCES;
197f48ad614SDennis Dalessandro 
198f48ad614SDennis Dalessandro 	/* make sure the TWSI bus is in a sane state */
199f48ad614SDennis Dalessandro 	ret = hfi1_twsi_reset(ppd->dd, target);
200f48ad614SDennis Dalessandro 	if (ret) {
201f48ad614SDennis Dalessandro 		hfi1_dev_porterr(ppd->dd, ppd->port,
202f48ad614SDennis Dalessandro 				 "QSFP chain %d write interface reset failed\n",
203f48ad614SDennis Dalessandro 				 target);
204f48ad614SDennis Dalessandro 		return ret;
205f48ad614SDennis Dalessandro 	}
206f48ad614SDennis Dalessandro 
207f48ad614SDennis Dalessandro 	while (count < len) {
208f48ad614SDennis Dalessandro 		/*
209f48ad614SDennis Dalessandro 		 * Set the qsfp page based on a zero-based address
210f48ad614SDennis Dalessandro 		 * and a page size of QSFP_PAGESIZE bytes.
211f48ad614SDennis Dalessandro 		 */
212f48ad614SDennis Dalessandro 		page = (u8)(addr / QSFP_PAGESIZE);
213f48ad614SDennis Dalessandro 
214f48ad614SDennis Dalessandro 		ret = __i2c_write(ppd, target, QSFP_DEV | QSFP_OFFSET_SIZE,
215f48ad614SDennis Dalessandro 				  QSFP_PAGE_SELECT_BYTE_OFFS, &page, 1);
216f48ad614SDennis Dalessandro 		if (ret != 1) {
217f48ad614SDennis Dalessandro 			hfi1_dev_porterr(ppd->dd, ppd->port,
218f48ad614SDennis Dalessandro 					 "QSFP chain %d can't write QSFP_PAGE_SELECT_BYTE: %d\n",
219f48ad614SDennis Dalessandro 					 target, ret);
220f48ad614SDennis Dalessandro 			ret = -EIO;
221f48ad614SDennis Dalessandro 			break;
222f48ad614SDennis Dalessandro 		}
223f48ad614SDennis Dalessandro 
224f48ad614SDennis Dalessandro 		offset = addr % QSFP_PAGESIZE;
225f48ad614SDennis Dalessandro 		nwrite = len - count;
226f48ad614SDennis Dalessandro 		/* truncate write to boundary if crossing boundary */
227f48ad614SDennis Dalessandro 		if (((addr % QSFP_RW_BOUNDARY) + nwrite) > QSFP_RW_BOUNDARY)
228f48ad614SDennis Dalessandro 			nwrite = QSFP_RW_BOUNDARY - (addr % QSFP_RW_BOUNDARY);
229f48ad614SDennis Dalessandro 
230f48ad614SDennis Dalessandro 		ret = __i2c_write(ppd, target, QSFP_DEV | QSFP_OFFSET_SIZE,
231f48ad614SDennis Dalessandro 				  offset, bp + count, nwrite);
232f48ad614SDennis Dalessandro 		if (ret <= 0)	/* stop on error or nothing written */
233f48ad614SDennis Dalessandro 			break;
234f48ad614SDennis Dalessandro 
235f48ad614SDennis Dalessandro 		count += ret;
236f48ad614SDennis Dalessandro 		addr += ret;
237f48ad614SDennis Dalessandro 	}
238f48ad614SDennis Dalessandro 
239f48ad614SDennis Dalessandro 	if (ret < 0)
240f48ad614SDennis Dalessandro 		return ret;
241f48ad614SDennis Dalessandro 	return count;
242f48ad614SDennis Dalessandro }
243f48ad614SDennis Dalessandro 
244f48ad614SDennis Dalessandro /*
245f48ad614SDennis Dalessandro  * Perform a stand-alone single QSFP write.  Acquire the resource, do the
246f48ad614SDennis Dalessandro  * read, then release the resource.
247f48ad614SDennis Dalessandro  */
248f48ad614SDennis Dalessandro int one_qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
249f48ad614SDennis Dalessandro 		   int len)
250f48ad614SDennis Dalessandro {
251f48ad614SDennis Dalessandro 	struct hfi1_devdata *dd = ppd->dd;
252f48ad614SDennis Dalessandro 	u32 resource = qsfp_resource(dd);
253f48ad614SDennis Dalessandro 	int ret;
254f48ad614SDennis Dalessandro 
255f48ad614SDennis Dalessandro 	ret = acquire_chip_resource(dd, resource, QSFP_WAIT);
256f48ad614SDennis Dalessandro 	if (ret)
257f48ad614SDennis Dalessandro 		return ret;
258f48ad614SDennis Dalessandro 	ret = qsfp_write(ppd, target, addr, bp, len);
259f48ad614SDennis Dalessandro 	release_chip_resource(dd, resource);
260f48ad614SDennis Dalessandro 
261f48ad614SDennis Dalessandro 	return ret;
262f48ad614SDennis Dalessandro }
263f48ad614SDennis Dalessandro 
264f48ad614SDennis Dalessandro /*
265f48ad614SDennis Dalessandro  * Access page n, offset m of QSFP memory as defined by SFF 8636
266f48ad614SDennis Dalessandro  * by reading @addr = ((256 * n) + m)
267f48ad614SDennis Dalessandro  *
268f48ad614SDennis Dalessandro  * Caller must hold the i2c chain resource.
269f48ad614SDennis Dalessandro  */
270f48ad614SDennis Dalessandro int qsfp_read(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
271f48ad614SDennis Dalessandro 	      int len)
272f48ad614SDennis Dalessandro {
273f48ad614SDennis Dalessandro 	int count = 0;
274f48ad614SDennis Dalessandro 	int offset;
275f48ad614SDennis Dalessandro 	int nread;
276f48ad614SDennis Dalessandro 	int ret;
277f48ad614SDennis Dalessandro 	u8 page;
278f48ad614SDennis Dalessandro 
279f48ad614SDennis Dalessandro 	if (!check_chip_resource(ppd->dd, i2c_target(target), __func__))
280f48ad614SDennis Dalessandro 		return -EACCES;
281f48ad614SDennis Dalessandro 
282f48ad614SDennis Dalessandro 	/* make sure the TWSI bus is in a sane state */
283f48ad614SDennis Dalessandro 	ret = hfi1_twsi_reset(ppd->dd, target);
284f48ad614SDennis Dalessandro 	if (ret) {
285f48ad614SDennis Dalessandro 		hfi1_dev_porterr(ppd->dd, ppd->port,
286f48ad614SDennis Dalessandro 				 "QSFP chain %d read interface reset failed\n",
287f48ad614SDennis Dalessandro 				 target);
288f48ad614SDennis Dalessandro 		return ret;
289f48ad614SDennis Dalessandro 	}
290f48ad614SDennis Dalessandro 
291f48ad614SDennis Dalessandro 	while (count < len) {
292f48ad614SDennis Dalessandro 		/*
293f48ad614SDennis Dalessandro 		 * Set the qsfp page based on a zero-based address
294f48ad614SDennis Dalessandro 		 * and a page size of QSFP_PAGESIZE bytes.
295f48ad614SDennis Dalessandro 		 */
296f48ad614SDennis Dalessandro 		page = (u8)(addr / QSFP_PAGESIZE);
297f48ad614SDennis Dalessandro 		ret = __i2c_write(ppd, target, QSFP_DEV | QSFP_OFFSET_SIZE,
298f48ad614SDennis Dalessandro 				  QSFP_PAGE_SELECT_BYTE_OFFS, &page, 1);
299f48ad614SDennis Dalessandro 		if (ret != 1) {
300f48ad614SDennis Dalessandro 			hfi1_dev_porterr(ppd->dd, ppd->port,
301f48ad614SDennis Dalessandro 					 "QSFP chain %d can't write QSFP_PAGE_SELECT_BYTE: %d\n",
302f48ad614SDennis Dalessandro 					 target, ret);
303f48ad614SDennis Dalessandro 			ret = -EIO;
304f48ad614SDennis Dalessandro 			break;
305f48ad614SDennis Dalessandro 		}
306f48ad614SDennis Dalessandro 
307f48ad614SDennis Dalessandro 		offset = addr % QSFP_PAGESIZE;
308f48ad614SDennis Dalessandro 		nread = len - count;
309f48ad614SDennis Dalessandro 		/* truncate read to boundary if crossing boundary */
310f48ad614SDennis Dalessandro 		if (((addr % QSFP_RW_BOUNDARY) + nread) > QSFP_RW_BOUNDARY)
311f48ad614SDennis Dalessandro 			nread = QSFP_RW_BOUNDARY - (addr % QSFP_RW_BOUNDARY);
312f48ad614SDennis Dalessandro 
313f48ad614SDennis Dalessandro 		/* QSFPs require a 5-10msec delay after write operations */
314f48ad614SDennis Dalessandro 		mdelay(5);
315f48ad614SDennis Dalessandro 		ret = __i2c_read(ppd, target, QSFP_DEV | QSFP_OFFSET_SIZE,
316f48ad614SDennis Dalessandro 				 offset, bp + count, nread);
317f48ad614SDennis Dalessandro 		if (ret <= 0)	/* stop on error or nothing read */
318f48ad614SDennis Dalessandro 			break;
319f48ad614SDennis Dalessandro 
320f48ad614SDennis Dalessandro 		count += ret;
321f48ad614SDennis Dalessandro 		addr += ret;
322f48ad614SDennis Dalessandro 	}
323f48ad614SDennis Dalessandro 
324f48ad614SDennis Dalessandro 	if (ret < 0)
325f48ad614SDennis Dalessandro 		return ret;
326f48ad614SDennis Dalessandro 	return count;
327f48ad614SDennis Dalessandro }
328f48ad614SDennis Dalessandro 
329f48ad614SDennis Dalessandro /*
330f48ad614SDennis Dalessandro  * Perform a stand-alone single QSFP read.  Acquire the resource, do the
331f48ad614SDennis Dalessandro  * read, then release the resource.
332f48ad614SDennis Dalessandro  */
333f48ad614SDennis Dalessandro int one_qsfp_read(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
334f48ad614SDennis Dalessandro 		  int len)
335f48ad614SDennis Dalessandro {
336f48ad614SDennis Dalessandro 	struct hfi1_devdata *dd = ppd->dd;
337f48ad614SDennis Dalessandro 	u32 resource = qsfp_resource(dd);
338f48ad614SDennis Dalessandro 	int ret;
339f48ad614SDennis Dalessandro 
340f48ad614SDennis Dalessandro 	ret = acquire_chip_resource(dd, resource, QSFP_WAIT);
341f48ad614SDennis Dalessandro 	if (ret)
342f48ad614SDennis Dalessandro 		return ret;
343f48ad614SDennis Dalessandro 	ret = qsfp_read(ppd, target, addr, bp, len);
344f48ad614SDennis Dalessandro 	release_chip_resource(dd, resource);
345f48ad614SDennis Dalessandro 
346f48ad614SDennis Dalessandro 	return ret;
347f48ad614SDennis Dalessandro }
348f48ad614SDennis Dalessandro 
349f48ad614SDennis Dalessandro /*
350f48ad614SDennis Dalessandro  * This function caches the QSFP memory range in 128 byte chunks.
351f48ad614SDennis Dalessandro  * As an example, the next byte after address 255 is byte 128 from
352f48ad614SDennis Dalessandro  * upper page 01H (if existing) rather than byte 0 from lower page 00H.
353f48ad614SDennis Dalessandro  * Access page n, offset m of QSFP memory as defined by SFF 8636
354f48ad614SDennis Dalessandro  * in the cache by reading byte ((128 * n) + m)
355f48ad614SDennis Dalessandro  * The calls to qsfp_{read,write} in this function correctly handle the
356f48ad614SDennis Dalessandro  * address map difference between this mapping and the mapping implemented
357f48ad614SDennis Dalessandro  * by those functions
358f48ad614SDennis Dalessandro  *
359f48ad614SDennis Dalessandro  * The caller must be holding the QSFP i2c chain resource.
360f48ad614SDennis Dalessandro  */
361f48ad614SDennis Dalessandro int refresh_qsfp_cache(struct hfi1_pportdata *ppd, struct qsfp_data *cp)
362f48ad614SDennis Dalessandro {
363f48ad614SDennis Dalessandro 	u32 target = ppd->dd->hfi1_id;
364f48ad614SDennis Dalessandro 	int ret;
365f48ad614SDennis Dalessandro 	unsigned long flags;
366f48ad614SDennis Dalessandro 	u8 *cache = &cp->cache[0];
367f48ad614SDennis Dalessandro 
368f48ad614SDennis Dalessandro 	/* ensure sane contents on invalid reads, for cable swaps */
369f48ad614SDennis Dalessandro 	memset(cache, 0, (QSFP_MAX_NUM_PAGES * 128));
370f48ad614SDennis Dalessandro 	spin_lock_irqsave(&ppd->qsfp_info.qsfp_lock, flags);
371f48ad614SDennis Dalessandro 	ppd->qsfp_info.cache_valid = 0;
372f48ad614SDennis Dalessandro 	spin_unlock_irqrestore(&ppd->qsfp_info.qsfp_lock, flags);
373f48ad614SDennis Dalessandro 
374f48ad614SDennis Dalessandro 	if (!qsfp_mod_present(ppd)) {
375f48ad614SDennis Dalessandro 		ret = -ENODEV;
376f48ad614SDennis Dalessandro 		goto bail;
377f48ad614SDennis Dalessandro 	}
378f48ad614SDennis Dalessandro 
379f48ad614SDennis Dalessandro 	ret = qsfp_read(ppd, target, 0, cache, QSFP_PAGESIZE);
380f48ad614SDennis Dalessandro 	if (ret != QSFP_PAGESIZE) {
381f48ad614SDennis Dalessandro 		dd_dev_info(ppd->dd,
382f48ad614SDennis Dalessandro 			    "%s: Page 0 read failed, expected %d, got %d\n",
383f48ad614SDennis Dalessandro 			    __func__, QSFP_PAGESIZE, ret);
384f48ad614SDennis Dalessandro 		goto bail;
385f48ad614SDennis Dalessandro 	}
386f48ad614SDennis Dalessandro 
387f48ad614SDennis Dalessandro 	/* Is paging enabled? */
388f48ad614SDennis Dalessandro 	if (!(cache[2] & 4)) {
389f48ad614SDennis Dalessandro 		/* Paging enabled, page 03 required */
390f48ad614SDennis Dalessandro 		if ((cache[195] & 0xC0) == 0xC0) {
391f48ad614SDennis Dalessandro 			/* all */
392f48ad614SDennis Dalessandro 			ret = qsfp_read(ppd, target, 384, cache + 256, 128);
393f48ad614SDennis Dalessandro 			if (ret <= 0 || ret != 128) {
394f48ad614SDennis Dalessandro 				dd_dev_info(ppd->dd, "%s failed\n", __func__);
395f48ad614SDennis Dalessandro 				goto bail;
396f48ad614SDennis Dalessandro 			}
397f48ad614SDennis Dalessandro 			ret = qsfp_read(ppd, target, 640, cache + 384, 128);
398f48ad614SDennis Dalessandro 			if (ret <= 0 || ret != 128) {
399f48ad614SDennis Dalessandro 				dd_dev_info(ppd->dd, "%s failed\n", __func__);
400f48ad614SDennis Dalessandro 				goto bail;
401f48ad614SDennis Dalessandro 			}
402f48ad614SDennis Dalessandro 			ret = qsfp_read(ppd, target, 896, cache + 512, 128);
403f48ad614SDennis Dalessandro 			if (ret <= 0 || ret != 128) {
404f48ad614SDennis Dalessandro 				dd_dev_info(ppd->dd, "%s failed\n", __func__);
405f48ad614SDennis Dalessandro 				goto bail;
406f48ad614SDennis Dalessandro 			}
407f48ad614SDennis Dalessandro 		} else if ((cache[195] & 0x80) == 0x80) {
408f48ad614SDennis Dalessandro 			/* only page 2 and 3 */
409f48ad614SDennis Dalessandro 			ret = qsfp_read(ppd, target, 640, cache + 384, 128);
410f48ad614SDennis Dalessandro 			if (ret <= 0 || ret != 128) {
411f48ad614SDennis Dalessandro 				dd_dev_info(ppd->dd, "%s failed\n", __func__);
412f48ad614SDennis Dalessandro 				goto bail;
413f48ad614SDennis Dalessandro 			}
414f48ad614SDennis Dalessandro 			ret = qsfp_read(ppd, target, 896, cache + 512, 128);
415f48ad614SDennis Dalessandro 			if (ret <= 0 || ret != 128) {
416f48ad614SDennis Dalessandro 				dd_dev_info(ppd->dd, "%s failed\n", __func__);
417f48ad614SDennis Dalessandro 				goto bail;
418f48ad614SDennis Dalessandro 			}
419f48ad614SDennis Dalessandro 		} else if ((cache[195] & 0x40) == 0x40) {
420f48ad614SDennis Dalessandro 			/* only page 1 and 3 */
421f48ad614SDennis Dalessandro 			ret = qsfp_read(ppd, target, 384, cache + 256, 128);
422f48ad614SDennis Dalessandro 			if (ret <= 0 || ret != 128) {
423f48ad614SDennis Dalessandro 				dd_dev_info(ppd->dd, "%s failed\n", __func__);
424f48ad614SDennis Dalessandro 				goto bail;
425f48ad614SDennis Dalessandro 			}
426f48ad614SDennis Dalessandro 			ret = qsfp_read(ppd, target, 896, cache + 512, 128);
427f48ad614SDennis Dalessandro 			if (ret <= 0 || ret != 128) {
428f48ad614SDennis Dalessandro 				dd_dev_info(ppd->dd, "%s failed\n", __func__);
429f48ad614SDennis Dalessandro 				goto bail;
430f48ad614SDennis Dalessandro 			}
431f48ad614SDennis Dalessandro 		} else {
432f48ad614SDennis Dalessandro 			/* only page 3 */
433f48ad614SDennis Dalessandro 			ret = qsfp_read(ppd, target, 896, cache + 512, 128);
434f48ad614SDennis Dalessandro 			if (ret <= 0 || ret != 128) {
435f48ad614SDennis Dalessandro 				dd_dev_info(ppd->dd, "%s failed\n", __func__);
436f48ad614SDennis Dalessandro 				goto bail;
437f48ad614SDennis Dalessandro 			}
438f48ad614SDennis Dalessandro 		}
439f48ad614SDennis Dalessandro 	}
440f48ad614SDennis Dalessandro 
441f48ad614SDennis Dalessandro 	spin_lock_irqsave(&ppd->qsfp_info.qsfp_lock, flags);
442f48ad614SDennis Dalessandro 	ppd->qsfp_info.cache_valid = 1;
443f48ad614SDennis Dalessandro 	ppd->qsfp_info.cache_refresh_required = 0;
444f48ad614SDennis Dalessandro 	spin_unlock_irqrestore(&ppd->qsfp_info.qsfp_lock, flags);
445f48ad614SDennis Dalessandro 
446f48ad614SDennis Dalessandro 	return 0;
447f48ad614SDennis Dalessandro 
448f48ad614SDennis Dalessandro bail:
449f48ad614SDennis Dalessandro 	memset(cache, 0, (QSFP_MAX_NUM_PAGES * 128));
450f48ad614SDennis Dalessandro 	return ret;
451f48ad614SDennis Dalessandro }
452f48ad614SDennis Dalessandro 
453f48ad614SDennis Dalessandro const char * const hfi1_qsfp_devtech[16] = {
454f48ad614SDennis Dalessandro 	"850nm VCSEL", "1310nm VCSEL", "1550nm VCSEL", "1310nm FP",
455f48ad614SDennis Dalessandro 	"1310nm DFB", "1550nm DFB", "1310nm EML", "1550nm EML",
456f48ad614SDennis Dalessandro 	"Cu Misc", "1490nm DFB", "Cu NoEq", "Cu Eq",
457f48ad614SDennis Dalessandro 	"Undef", "Cu Active BothEq", "Cu FarEq", "Cu NearEq"
458f48ad614SDennis Dalessandro };
459f48ad614SDennis Dalessandro 
460f48ad614SDennis Dalessandro #define QSFP_DUMP_CHUNK 16 /* Holds longest string */
461f48ad614SDennis Dalessandro #define QSFP_DEFAULT_HDR_CNT 224
462f48ad614SDennis Dalessandro 
463f48ad614SDennis Dalessandro #define QSFP_PWR(pbyte) (((pbyte) >> 6) & 3)
464f48ad614SDennis Dalessandro #define QSFP_HIGH_PWR(pbyte) ((pbyte) & 3)
465f48ad614SDennis Dalessandro /* For use with QSFP_HIGH_PWR macro */
466f48ad614SDennis Dalessandro #define QSFP_HIGH_PWR_UNUSED	0 /* Bits [1:0] = 00 implies low power module */
467f48ad614SDennis Dalessandro 
468f48ad614SDennis Dalessandro /*
469f48ad614SDennis Dalessandro  * Takes power class byte [Page 00 Byte 129] in SFF 8636
470f48ad614SDennis Dalessandro  * Returns power class as integer (1 through 7, per SFF 8636 rev 2.4)
471f48ad614SDennis Dalessandro  */
472f48ad614SDennis Dalessandro int get_qsfp_power_class(u8 power_byte)
473f48ad614SDennis Dalessandro {
474f48ad614SDennis Dalessandro 	if (QSFP_HIGH_PWR(power_byte) == QSFP_HIGH_PWR_UNUSED)
475f48ad614SDennis Dalessandro 		/* power classes count from 1, their bit encodings from 0 */
476f48ad614SDennis Dalessandro 		return (QSFP_PWR(power_byte) + 1);
477f48ad614SDennis Dalessandro 	/*
478f48ad614SDennis Dalessandro 	 * 00 in the high power classes stands for unused, bringing
479f48ad614SDennis Dalessandro 	 * balance to the off-by-1 offset above, we add 4 here to
480f48ad614SDennis Dalessandro 	 * account for the difference between the low and high power
481f48ad614SDennis Dalessandro 	 * groups
482f48ad614SDennis Dalessandro 	 */
483f48ad614SDennis Dalessandro 	return (QSFP_HIGH_PWR(power_byte) + 4);
484f48ad614SDennis Dalessandro }
485f48ad614SDennis Dalessandro 
486f48ad614SDennis Dalessandro int qsfp_mod_present(struct hfi1_pportdata *ppd)
487f48ad614SDennis Dalessandro {
488f48ad614SDennis Dalessandro 	struct hfi1_devdata *dd = ppd->dd;
489f48ad614SDennis Dalessandro 	u64 reg;
490f48ad614SDennis Dalessandro 
491f48ad614SDennis Dalessandro 	reg = read_csr(dd, dd->hfi1_id ? ASIC_QSFP2_IN : ASIC_QSFP1_IN);
492f48ad614SDennis Dalessandro 	return !(reg & QSFP_HFI0_MODPRST_N);
493f48ad614SDennis Dalessandro }
494f48ad614SDennis Dalessandro 
495f48ad614SDennis Dalessandro /*
496f48ad614SDennis Dalessandro  * This function maps QSFP memory addresses in 128 byte chunks in the following
497f48ad614SDennis Dalessandro  * fashion per the CableInfo SMA query definition in the IBA 1.3 spec/OPA Gen 1
498f48ad614SDennis Dalessandro  * spec
499f48ad614SDennis Dalessandro  * For addr 000-127, lower page 00h
500f48ad614SDennis Dalessandro  * For addr 128-255, upper page 00h
501f48ad614SDennis Dalessandro  * For addr 256-383, upper page 01h
502f48ad614SDennis Dalessandro  * For addr 384-511, upper page 02h
503f48ad614SDennis Dalessandro  * For addr 512-639, upper page 03h
504f48ad614SDennis Dalessandro  *
505f48ad614SDennis Dalessandro  * For addresses beyond this range, it returns the invalid range of data buffer
506f48ad614SDennis Dalessandro  * set to 0.
507f48ad614SDennis Dalessandro  * For upper pages that are optional, if they are not valid, returns the
508f48ad614SDennis Dalessandro  * particular range of bytes in the data buffer set to 0.
509f48ad614SDennis Dalessandro  */
510f48ad614SDennis Dalessandro int get_cable_info(struct hfi1_devdata *dd, u32 port_num, u32 addr, u32 len,
511f48ad614SDennis Dalessandro 		   u8 *data)
512f48ad614SDennis Dalessandro {
513f48ad614SDennis Dalessandro 	struct hfi1_pportdata *ppd;
514f48ad614SDennis Dalessandro 	u32 excess_len = 0;
515f48ad614SDennis Dalessandro 	int ret = 0;
516f48ad614SDennis Dalessandro 
517f48ad614SDennis Dalessandro 	if (port_num > dd->num_pports || port_num < 1) {
518f48ad614SDennis Dalessandro 		dd_dev_info(dd, "%s: Invalid port number %d\n",
519f48ad614SDennis Dalessandro 			    __func__, port_num);
520f48ad614SDennis Dalessandro 		ret = -EINVAL;
521f48ad614SDennis Dalessandro 		goto set_zeroes;
522f48ad614SDennis Dalessandro 	}
523f48ad614SDennis Dalessandro 
524f48ad614SDennis Dalessandro 	ppd = dd->pport + (port_num - 1);
525f48ad614SDennis Dalessandro 	if (!qsfp_mod_present(ppd)) {
526f48ad614SDennis Dalessandro 		ret = -ENODEV;
527f48ad614SDennis Dalessandro 		goto set_zeroes;
528f48ad614SDennis Dalessandro 	}
529f48ad614SDennis Dalessandro 
530f48ad614SDennis Dalessandro 	if (!ppd->qsfp_info.cache_valid) {
531f48ad614SDennis Dalessandro 		ret = -EINVAL;
532f48ad614SDennis Dalessandro 		goto set_zeroes;
533f48ad614SDennis Dalessandro 	}
534f48ad614SDennis Dalessandro 
535f48ad614SDennis Dalessandro 	if (addr >= (QSFP_MAX_NUM_PAGES * 128)) {
536f48ad614SDennis Dalessandro 		ret = -ERANGE;
537f48ad614SDennis Dalessandro 		goto set_zeroes;
538f48ad614SDennis Dalessandro 	}
539f48ad614SDennis Dalessandro 
540f48ad614SDennis Dalessandro 	if ((addr + len) > (QSFP_MAX_NUM_PAGES * 128)) {
541f48ad614SDennis Dalessandro 		excess_len = (addr + len) - (QSFP_MAX_NUM_PAGES * 128);
542f48ad614SDennis Dalessandro 		memcpy(data, &ppd->qsfp_info.cache[addr], (len - excess_len));
543f48ad614SDennis Dalessandro 		data += (len - excess_len);
544f48ad614SDennis Dalessandro 		goto set_zeroes;
545f48ad614SDennis Dalessandro 	}
546f48ad614SDennis Dalessandro 
547f48ad614SDennis Dalessandro 	memcpy(data, &ppd->qsfp_info.cache[addr], len);
548f48ad614SDennis Dalessandro 	return 0;
549f48ad614SDennis Dalessandro 
550f48ad614SDennis Dalessandro set_zeroes:
551f48ad614SDennis Dalessandro 	memset(data, 0, excess_len);
552f48ad614SDennis Dalessandro 	return ret;
553f48ad614SDennis Dalessandro }
554f48ad614SDennis Dalessandro 
555f48ad614SDennis Dalessandro static const char *pwr_codes[8] = {"N/AW",
556f48ad614SDennis Dalessandro 				  "1.5W",
557f48ad614SDennis Dalessandro 				  "2.0W",
558f48ad614SDennis Dalessandro 				  "2.5W",
559f48ad614SDennis Dalessandro 				  "3.5W",
560f48ad614SDennis Dalessandro 				  "4.0W",
561f48ad614SDennis Dalessandro 				  "4.5W",
562f48ad614SDennis Dalessandro 				  "5.0W"
563f48ad614SDennis Dalessandro 				 };
564f48ad614SDennis Dalessandro 
565f48ad614SDennis Dalessandro int qsfp_dump(struct hfi1_pportdata *ppd, char *buf, int len)
566f48ad614SDennis Dalessandro {
567f48ad614SDennis Dalessandro 	u8 *cache = &ppd->qsfp_info.cache[0];
568f48ad614SDennis Dalessandro 	u8 bin_buff[QSFP_DUMP_CHUNK];
569f48ad614SDennis Dalessandro 	char lenstr[6];
570f48ad614SDennis Dalessandro 	int sofar;
571f48ad614SDennis Dalessandro 	int bidx = 0;
572f48ad614SDennis Dalessandro 	u8 *atten = &cache[QSFP_ATTEN_OFFS];
573f48ad614SDennis Dalessandro 	u8 *vendor_oui = &cache[QSFP_VOUI_OFFS];
574f48ad614SDennis Dalessandro 	u8 power_byte = 0;
575f48ad614SDennis Dalessandro 
576f48ad614SDennis Dalessandro 	sofar = 0;
577f48ad614SDennis Dalessandro 	lenstr[0] = ' ';
578f48ad614SDennis Dalessandro 	lenstr[1] = '\0';
579f48ad614SDennis Dalessandro 
580f48ad614SDennis Dalessandro 	if (ppd->qsfp_info.cache_valid) {
581f48ad614SDennis Dalessandro 		if (QSFP_IS_CU(cache[QSFP_MOD_TECH_OFFS]))
582f48ad614SDennis Dalessandro 			sprintf(lenstr, "%dM ", cache[QSFP_MOD_LEN_OFFS]);
583f48ad614SDennis Dalessandro 
584f48ad614SDennis Dalessandro 		power_byte = cache[QSFP_MOD_PWR_OFFS];
585f48ad614SDennis Dalessandro 		sofar += scnprintf(buf + sofar, len - sofar, "PWR:%.3sW\n",
586f48ad614SDennis Dalessandro 				pwr_codes[get_qsfp_power_class(power_byte)]);
587f48ad614SDennis Dalessandro 
588f48ad614SDennis Dalessandro 		sofar += scnprintf(buf + sofar, len - sofar, "TECH:%s%s\n",
589f48ad614SDennis Dalessandro 				lenstr,
590f48ad614SDennis Dalessandro 			hfi1_qsfp_devtech[(cache[QSFP_MOD_TECH_OFFS]) >> 4]);
591f48ad614SDennis Dalessandro 
592f48ad614SDennis Dalessandro 		sofar += scnprintf(buf + sofar, len - sofar, "Vendor:%.*s\n",
593f48ad614SDennis Dalessandro 				   QSFP_VEND_LEN, &cache[QSFP_VEND_OFFS]);
594f48ad614SDennis Dalessandro 
595f48ad614SDennis Dalessandro 		sofar += scnprintf(buf + sofar, len - sofar, "OUI:%06X\n",
596f48ad614SDennis Dalessandro 				   QSFP_OUI(vendor_oui));
597f48ad614SDennis Dalessandro 
598f48ad614SDennis Dalessandro 		sofar += scnprintf(buf + sofar, len - sofar, "Part#:%.*s\n",
599f48ad614SDennis Dalessandro 				   QSFP_PN_LEN, &cache[QSFP_PN_OFFS]);
600f48ad614SDennis Dalessandro 
601f48ad614SDennis Dalessandro 		sofar += scnprintf(buf + sofar, len - sofar, "Rev:%.*s\n",
602f48ad614SDennis Dalessandro 				   QSFP_REV_LEN, &cache[QSFP_REV_OFFS]);
603f48ad614SDennis Dalessandro 
604f48ad614SDennis Dalessandro 		if (QSFP_IS_CU(cache[QSFP_MOD_TECH_OFFS]))
605f48ad614SDennis Dalessandro 			sofar += scnprintf(buf + sofar, len - sofar,
606f48ad614SDennis Dalessandro 				"Atten:%d, %d\n",
607f48ad614SDennis Dalessandro 				QSFP_ATTEN_SDR(atten),
608f48ad614SDennis Dalessandro 				QSFP_ATTEN_DDR(atten));
609f48ad614SDennis Dalessandro 
610f48ad614SDennis Dalessandro 		sofar += scnprintf(buf + sofar, len - sofar, "Serial:%.*s\n",
611f48ad614SDennis Dalessandro 				   QSFP_SN_LEN, &cache[QSFP_SN_OFFS]);
612f48ad614SDennis Dalessandro 
613f48ad614SDennis Dalessandro 		sofar += scnprintf(buf + sofar, len - sofar, "Date:%.*s\n",
614f48ad614SDennis Dalessandro 				   QSFP_DATE_LEN, &cache[QSFP_DATE_OFFS]);
615f48ad614SDennis Dalessandro 
616f48ad614SDennis Dalessandro 		sofar += scnprintf(buf + sofar, len - sofar, "Lot:%.*s\n",
617f48ad614SDennis Dalessandro 				   QSFP_LOT_LEN, &cache[QSFP_LOT_OFFS]);
618f48ad614SDennis Dalessandro 
619f48ad614SDennis Dalessandro 		while (bidx < QSFP_DEFAULT_HDR_CNT) {
620f48ad614SDennis Dalessandro 			int iidx;
621f48ad614SDennis Dalessandro 
622f48ad614SDennis Dalessandro 			memcpy(bin_buff, &cache[bidx], QSFP_DUMP_CHUNK);
623f48ad614SDennis Dalessandro 			for (iidx = 0; iidx < QSFP_DUMP_CHUNK; ++iidx) {
624f48ad614SDennis Dalessandro 				sofar += scnprintf(buf + sofar, len - sofar,
625f48ad614SDennis Dalessandro 					" %02X", bin_buff[iidx]);
626f48ad614SDennis Dalessandro 			}
627f48ad614SDennis Dalessandro 			sofar += scnprintf(buf + sofar, len - sofar, "\n");
628f48ad614SDennis Dalessandro 			bidx += QSFP_DUMP_CHUNK;
629f48ad614SDennis Dalessandro 		}
630f48ad614SDennis Dalessandro 	}
631f48ad614SDennis Dalessandro 	return sofar;
632f48ad614SDennis Dalessandro }
633