xref: /openbmc/linux/drivers/infiniband/hw/hfi1/qsfp.c (revision 145eba1a)
1*145eba1aSCai Huoqing // SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause
2f48ad614SDennis Dalessandro /*
3f48ad614SDennis Dalessandro  * Copyright(c) 2015, 2016 Intel Corporation.
4f48ad614SDennis Dalessandro  */
5f48ad614SDennis Dalessandro 
6f48ad614SDennis Dalessandro #include <linux/delay.h>
7f48ad614SDennis Dalessandro #include <linux/pci.h>
8f48ad614SDennis Dalessandro #include <linux/vmalloc.h>
9f48ad614SDennis Dalessandro 
10f48ad614SDennis Dalessandro #include "hfi.h"
11dba715f0SDean Luick 
12dba715f0SDean Luick /* for the given bus number, return the CSR for reading an i2c line */
i2c_in_csr(u32 bus_num)13dba715f0SDean Luick static inline u32 i2c_in_csr(u32 bus_num)
14dba715f0SDean Luick {
15dba715f0SDean Luick 	return bus_num ? ASIC_QSFP2_IN : ASIC_QSFP1_IN;
16dba715f0SDean Luick }
17dba715f0SDean Luick 
18dba715f0SDean Luick /* for the given bus number, return the CSR for writing an i2c line */
i2c_oe_csr(u32 bus_num)19dba715f0SDean Luick static inline u32 i2c_oe_csr(u32 bus_num)
20dba715f0SDean Luick {
21dba715f0SDean Luick 	return bus_num ? ASIC_QSFP2_OE : ASIC_QSFP1_OE;
22dba715f0SDean Luick }
23dba715f0SDean Luick 
hfi1_setsda(void * data,int state)24dba715f0SDean Luick static void hfi1_setsda(void *data, int state)
25dba715f0SDean Luick {
26dba715f0SDean Luick 	struct hfi1_i2c_bus *bus = (struct hfi1_i2c_bus *)data;
27dba715f0SDean Luick 	struct hfi1_devdata *dd = bus->controlling_dd;
28dba715f0SDean Luick 	u64 reg;
29dba715f0SDean Luick 	u32 target_oe;
30dba715f0SDean Luick 
31dba715f0SDean Luick 	target_oe = i2c_oe_csr(bus->num);
32dba715f0SDean Luick 	reg = read_csr(dd, target_oe);
33dba715f0SDean Luick 	/*
34dba715f0SDean Luick 	 * The OE bit value is inverted and connected to the pin.  When
35dba715f0SDean Luick 	 * OE is 0 the pin is left to be pulled up, when the OE is 1
36dba715f0SDean Luick 	 * the pin is driven low.  This matches the "open drain" or "open
37dba715f0SDean Luick 	 * collector" convention.
38dba715f0SDean Luick 	 */
39dba715f0SDean Luick 	if (state)
40dba715f0SDean Luick 		reg &= ~QSFP_HFI0_I2CDAT;
41dba715f0SDean Luick 	else
42dba715f0SDean Luick 		reg |= QSFP_HFI0_I2CDAT;
43dba715f0SDean Luick 	write_csr(dd, target_oe, reg);
44dba715f0SDean Luick 	/* do a read to force the write into the chip */
45dba715f0SDean Luick 	(void)read_csr(dd, target_oe);
46dba715f0SDean Luick }
47dba715f0SDean Luick 
hfi1_setscl(void * data,int state)48dba715f0SDean Luick static void hfi1_setscl(void *data, int state)
49dba715f0SDean Luick {
50dba715f0SDean Luick 	struct hfi1_i2c_bus *bus = (struct hfi1_i2c_bus *)data;
51dba715f0SDean Luick 	struct hfi1_devdata *dd = bus->controlling_dd;
52dba715f0SDean Luick 	u64 reg;
53dba715f0SDean Luick 	u32 target_oe;
54dba715f0SDean Luick 
55dba715f0SDean Luick 	target_oe = i2c_oe_csr(bus->num);
56dba715f0SDean Luick 	reg = read_csr(dd, target_oe);
57dba715f0SDean Luick 	/*
58dba715f0SDean Luick 	 * The OE bit value is inverted and connected to the pin.  When
59dba715f0SDean Luick 	 * OE is 0 the pin is left to be pulled up, when the OE is 1
60dba715f0SDean Luick 	 * the pin is driven low.  This matches the "open drain" or "open
61dba715f0SDean Luick 	 * collector" convention.
62dba715f0SDean Luick 	 */
63dba715f0SDean Luick 	if (state)
64dba715f0SDean Luick 		reg &= ~QSFP_HFI0_I2CCLK;
65dba715f0SDean Luick 	else
66dba715f0SDean Luick 		reg |= QSFP_HFI0_I2CCLK;
67dba715f0SDean Luick 	write_csr(dd, target_oe, reg);
68dba715f0SDean Luick 	/* do a read to force the write into the chip */
69dba715f0SDean Luick 	(void)read_csr(dd, target_oe);
70dba715f0SDean Luick }
71dba715f0SDean Luick 
hfi1_getsda(void * data)72dba715f0SDean Luick static int hfi1_getsda(void *data)
73dba715f0SDean Luick {
74dba715f0SDean Luick 	struct hfi1_i2c_bus *bus = (struct hfi1_i2c_bus *)data;
75dba715f0SDean Luick 	u64 reg;
76dba715f0SDean Luick 	u32 target_in;
77dba715f0SDean Luick 
78dba715f0SDean Luick 	hfi1_setsda(data, 1);	/* clear OE so we do not pull line down */
79dba715f0SDean Luick 	udelay(2);		/* 1us pull up + 250ns hold */
80dba715f0SDean Luick 
81dba715f0SDean Luick 	target_in = i2c_in_csr(bus->num);
82dba715f0SDean Luick 	reg = read_csr(bus->controlling_dd, target_in);
83dba715f0SDean Luick 	return !!(reg & QSFP_HFI0_I2CDAT);
84dba715f0SDean Luick }
85dba715f0SDean Luick 
hfi1_getscl(void * data)86dba715f0SDean Luick static int hfi1_getscl(void *data)
87dba715f0SDean Luick {
88dba715f0SDean Luick 	struct hfi1_i2c_bus *bus = (struct hfi1_i2c_bus *)data;
89dba715f0SDean Luick 	u64 reg;
90dba715f0SDean Luick 	u32 target_in;
91dba715f0SDean Luick 
92dba715f0SDean Luick 	hfi1_setscl(data, 1);	/* clear OE so we do not pull line down */
93dba715f0SDean Luick 	udelay(2);		/* 1us pull up + 250ns hold */
94dba715f0SDean Luick 
95dba715f0SDean Luick 	target_in = i2c_in_csr(bus->num);
96dba715f0SDean Luick 	reg = read_csr(bus->controlling_dd, target_in);
97dba715f0SDean Luick 	return !!(reg & QSFP_HFI0_I2CCLK);
98dba715f0SDean Luick }
99f48ad614SDennis Dalessandro 
100f48ad614SDennis Dalessandro /*
101dba715f0SDean Luick  * Allocate and initialize the given i2c bus number.
102dba715f0SDean Luick  * Returns NULL on failure.
103f48ad614SDennis Dalessandro  */
init_i2c_bus(struct hfi1_devdata * dd,struct hfi1_asic_data * ad,int num)104dba715f0SDean Luick static struct hfi1_i2c_bus *init_i2c_bus(struct hfi1_devdata *dd,
105dba715f0SDean Luick 					 struct hfi1_asic_data *ad, int num)
106dba715f0SDean Luick {
107dba715f0SDean Luick 	struct hfi1_i2c_bus *bus;
108dba715f0SDean Luick 	int ret;
109dba715f0SDean Luick 
110dba715f0SDean Luick 	bus = kzalloc(sizeof(*bus), GFP_KERNEL);
111dba715f0SDean Luick 	if (!bus)
112dba715f0SDean Luick 		return NULL;
113dba715f0SDean Luick 
114dba715f0SDean Luick 	bus->controlling_dd = dd;
115dba715f0SDean Luick 	bus->num = num;	/* our bus number */
116dba715f0SDean Luick 
117dba715f0SDean Luick 	bus->algo.setsda = hfi1_setsda;
118dba715f0SDean Luick 	bus->algo.setscl = hfi1_setscl;
119dba715f0SDean Luick 	bus->algo.getsda = hfi1_getsda;
120dba715f0SDean Luick 	bus->algo.getscl = hfi1_getscl;
121dba715f0SDean Luick 	bus->algo.udelay = 5;
122d5cf683eSDean Luick 	bus->algo.timeout = usecs_to_jiffies(100000);
123dba715f0SDean Luick 	bus->algo.data = bus;
124dba715f0SDean Luick 
125dba715f0SDean Luick 	bus->adapter.owner = THIS_MODULE;
126dba715f0SDean Luick 	bus->adapter.algo_data = &bus->algo;
127dba715f0SDean Luick 	bus->adapter.dev.parent = &dd->pcidev->dev;
128dba715f0SDean Luick 	snprintf(bus->adapter.name, sizeof(bus->adapter.name),
129dba715f0SDean Luick 		 "hfi1_i2c%d", num);
130dba715f0SDean Luick 
131dba715f0SDean Luick 	ret = i2c_bit_add_bus(&bus->adapter);
132dba715f0SDean Luick 	if (ret) {
133dba715f0SDean Luick 		dd_dev_info(dd, "%s: unable to add i2c bus %d, err %d\n",
134dba715f0SDean Luick 			    __func__, num, ret);
135dba715f0SDean Luick 		kfree(bus);
136dba715f0SDean Luick 		return NULL;
137dba715f0SDean Luick 	}
138dba715f0SDean Luick 
139dba715f0SDean Luick 	return bus;
140dba715f0SDean Luick }
141dba715f0SDean Luick 
142dba715f0SDean Luick /*
143dba715f0SDean Luick  * Initialize i2c buses.
144dba715f0SDean Luick  * Return 0 on success, -errno on error.
145dba715f0SDean Luick  */
set_up_i2c(struct hfi1_devdata * dd,struct hfi1_asic_data * ad)146dba715f0SDean Luick int set_up_i2c(struct hfi1_devdata *dd, struct hfi1_asic_data *ad)
147dba715f0SDean Luick {
148dba715f0SDean Luick 	ad->i2c_bus0 = init_i2c_bus(dd, ad, 0);
149dba715f0SDean Luick 	ad->i2c_bus1 = init_i2c_bus(dd, ad, 1);
150dba715f0SDean Luick 	if (!ad->i2c_bus0 || !ad->i2c_bus1)
151dba715f0SDean Luick 		return -ENOMEM;
152dba715f0SDean Luick 	return 0;
153dba715f0SDean Luick };
154dba715f0SDean Luick 
clean_i2c_bus(struct hfi1_i2c_bus * bus)155dba715f0SDean Luick static void clean_i2c_bus(struct hfi1_i2c_bus *bus)
156dba715f0SDean Luick {
157dba715f0SDean Luick 	if (bus) {
158dba715f0SDean Luick 		i2c_del_adapter(&bus->adapter);
159dba715f0SDean Luick 		kfree(bus);
160dba715f0SDean Luick 	}
161dba715f0SDean Luick }
162dba715f0SDean Luick 
clean_up_i2c(struct hfi1_devdata * dd,struct hfi1_asic_data * ad)163dba715f0SDean Luick void clean_up_i2c(struct hfi1_devdata *dd, struct hfi1_asic_data *ad)
164dba715f0SDean Luick {
165e9777ad4SSebastian Sanchez 	if (!ad)
166e9777ad4SSebastian Sanchez 		return;
167dba715f0SDean Luick 	clean_i2c_bus(ad->i2c_bus0);
168dba715f0SDean Luick 	ad->i2c_bus0 = NULL;
169dba715f0SDean Luick 	clean_i2c_bus(ad->i2c_bus1);
170dba715f0SDean Luick 	ad->i2c_bus1 = NULL;
171dba715f0SDean Luick }
172dba715f0SDean Luick 
i2c_bus_write(struct hfi1_devdata * dd,struct hfi1_i2c_bus * i2c,u8 slave_addr,int offset,int offset_size,u8 * data,u16 len)173dba715f0SDean Luick static int i2c_bus_write(struct hfi1_devdata *dd, struct hfi1_i2c_bus *i2c,
174dba715f0SDean Luick 			 u8 slave_addr, int offset, int offset_size,
175dba715f0SDean Luick 			 u8 *data, u16 len)
176dba715f0SDean Luick {
177dba715f0SDean Luick 	int ret;
178dba715f0SDean Luick 	int num_msgs;
179dba715f0SDean Luick 	u8 offset_bytes[2];
180dba715f0SDean Luick 	struct i2c_msg msgs[2];
181dba715f0SDean Luick 
182dba715f0SDean Luick 	switch (offset_size) {
183dba715f0SDean Luick 	case 0:
184dba715f0SDean Luick 		num_msgs = 1;
185dba715f0SDean Luick 		msgs[0].addr = slave_addr;
186dba715f0SDean Luick 		msgs[0].flags = 0;
187dba715f0SDean Luick 		msgs[0].len = len;
188dba715f0SDean Luick 		msgs[0].buf = data;
189dba715f0SDean Luick 		break;
190dba715f0SDean Luick 	case 2:
191dba715f0SDean Luick 		offset_bytes[1] = (offset >> 8) & 0xff;
1926f24b159SGustavo A. R. Silva 		fallthrough;
193dba715f0SDean Luick 	case 1:
194dba715f0SDean Luick 		num_msgs = 2;
195dba715f0SDean Luick 		offset_bytes[0] = offset & 0xff;
196dba715f0SDean Luick 
197dba715f0SDean Luick 		msgs[0].addr = slave_addr;
198dba715f0SDean Luick 		msgs[0].flags = 0;
199dba715f0SDean Luick 		msgs[0].len = offset_size;
200dba715f0SDean Luick 		msgs[0].buf = offset_bytes;
201dba715f0SDean Luick 
202dba715f0SDean Luick 		msgs[1].addr = slave_addr;
20390eef9f7SZheng Yongjun 		msgs[1].flags = I2C_M_NOSTART;
204dba715f0SDean Luick 		msgs[1].len = len;
205dba715f0SDean Luick 		msgs[1].buf = data;
206dba715f0SDean Luick 		break;
207dba715f0SDean Luick 	default:
208dba715f0SDean Luick 		return -EINVAL;
209dba715f0SDean Luick 	}
210dba715f0SDean Luick 
211dba715f0SDean Luick 	i2c->controlling_dd = dd;
212dba715f0SDean Luick 	ret = i2c_transfer(&i2c->adapter, msgs, num_msgs);
213dba715f0SDean Luick 	if (ret != num_msgs) {
214dba715f0SDean Luick 		dd_dev_err(dd, "%s: bus %d, i2c slave 0x%x, offset 0x%x, len 0x%x; write failed, ret %d\n",
215dba715f0SDean Luick 			   __func__, i2c->num, slave_addr, offset, len, ret);
216dba715f0SDean Luick 		return ret < 0 ? ret : -EIO;
217dba715f0SDean Luick 	}
218dba715f0SDean Luick 	return 0;
219dba715f0SDean Luick }
220dba715f0SDean Luick 
i2c_bus_read(struct hfi1_devdata * dd,struct hfi1_i2c_bus * bus,u8 slave_addr,int offset,int offset_size,u8 * data,u16 len)221dba715f0SDean Luick static int i2c_bus_read(struct hfi1_devdata *dd, struct hfi1_i2c_bus *bus,
222dba715f0SDean Luick 			u8 slave_addr, int offset, int offset_size,
223dba715f0SDean Luick 			u8 *data, u16 len)
224dba715f0SDean Luick {
225dba715f0SDean Luick 	int ret;
226dba715f0SDean Luick 	int num_msgs;
227dba715f0SDean Luick 	u8 offset_bytes[2];
228dba715f0SDean Luick 	struct i2c_msg msgs[2];
229dba715f0SDean Luick 
230dba715f0SDean Luick 	switch (offset_size) {
231dba715f0SDean Luick 	case 0:
232dba715f0SDean Luick 		num_msgs = 1;
233dba715f0SDean Luick 		msgs[0].addr = slave_addr;
234dba715f0SDean Luick 		msgs[0].flags = I2C_M_RD;
235dba715f0SDean Luick 		msgs[0].len = len;
236dba715f0SDean Luick 		msgs[0].buf = data;
237dba715f0SDean Luick 		break;
238dba715f0SDean Luick 	case 2:
239dba715f0SDean Luick 		offset_bytes[1] = (offset >> 8) & 0xff;
2406f24b159SGustavo A. R. Silva 		fallthrough;
241dba715f0SDean Luick 	case 1:
242dba715f0SDean Luick 		num_msgs = 2;
243dba715f0SDean Luick 		offset_bytes[0] = offset & 0xff;
244dba715f0SDean Luick 
245dba715f0SDean Luick 		msgs[0].addr = slave_addr;
246dba715f0SDean Luick 		msgs[0].flags = 0;
247dba715f0SDean Luick 		msgs[0].len = offset_size;
248dba715f0SDean Luick 		msgs[0].buf = offset_bytes;
249dba715f0SDean Luick 
250dba715f0SDean Luick 		msgs[1].addr = slave_addr;
25190eef9f7SZheng Yongjun 		msgs[1].flags = I2C_M_RD;
252dba715f0SDean Luick 		msgs[1].len = len;
253dba715f0SDean Luick 		msgs[1].buf = data;
254dba715f0SDean Luick 		break;
255dba715f0SDean Luick 	default:
256dba715f0SDean Luick 		return -EINVAL;
257dba715f0SDean Luick 	}
258dba715f0SDean Luick 
259dba715f0SDean Luick 	bus->controlling_dd = dd;
260dba715f0SDean Luick 	ret = i2c_transfer(&bus->adapter, msgs, num_msgs);
261dba715f0SDean Luick 	if (ret != num_msgs) {
262dba715f0SDean Luick 		dd_dev_err(dd, "%s: bus %d, i2c slave 0x%x, offset 0x%x, len 0x%x; read failed, ret %d\n",
263dba715f0SDean Luick 			   __func__, bus->num, slave_addr, offset, len, ret);
264dba715f0SDean Luick 		return ret < 0 ? ret : -EIO;
265dba715f0SDean Luick 	}
266dba715f0SDean Luick 	return 0;
267dba715f0SDean Luick }
268f48ad614SDennis Dalessandro 
269f48ad614SDennis Dalessandro /*
270f48ad614SDennis Dalessandro  * Raw i2c write.  No set-up or lock checking.
271dba715f0SDean Luick  *
272dba715f0SDean Luick  * Return 0 on success, -errno on error.
273f48ad614SDennis Dalessandro  */
__i2c_write(struct hfi1_pportdata * ppd,u32 target,int i2c_addr,int offset,void * bp,int len)274f48ad614SDennis Dalessandro static int __i2c_write(struct hfi1_pportdata *ppd, u32 target, int i2c_addr,
275f48ad614SDennis Dalessandro 		       int offset, void *bp, int len)
276f48ad614SDennis Dalessandro {
277f48ad614SDennis Dalessandro 	struct hfi1_devdata *dd = ppd->dd;
278dba715f0SDean Luick 	struct hfi1_i2c_bus *bus;
279dba715f0SDean Luick 	u8 slave_addr;
280dba715f0SDean Luick 	int offset_size;
281f48ad614SDennis Dalessandro 
282dba715f0SDean Luick 	bus = target ? dd->asic_data->i2c_bus1 : dd->asic_data->i2c_bus0;
283dba715f0SDean Luick 	slave_addr = (i2c_addr & 0xff) >> 1; /* convert to 7-bit addr */
284dba715f0SDean Luick 	offset_size = (i2c_addr >> 8) & 0x3;
285dba715f0SDean Luick 	return i2c_bus_write(dd, bus, slave_addr, offset, offset_size, bp, len);
286f48ad614SDennis Dalessandro }
287f48ad614SDennis Dalessandro 
288f48ad614SDennis Dalessandro /*
289f48ad614SDennis Dalessandro  * Caller must hold the i2c chain resource.
290dba715f0SDean Luick  *
291dba715f0SDean Luick  * Return number of bytes written, or -errno.
292f48ad614SDennis Dalessandro  */
i2c_write(struct hfi1_pportdata * ppd,u32 target,int i2c_addr,int offset,void * bp,int len)293f48ad614SDennis Dalessandro int i2c_write(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, int offset,
294f48ad614SDennis Dalessandro 	      void *bp, int len)
295f48ad614SDennis Dalessandro {
296f48ad614SDennis Dalessandro 	int ret;
297f48ad614SDennis Dalessandro 
298f48ad614SDennis Dalessandro 	if (!check_chip_resource(ppd->dd, i2c_target(target), __func__))
299f48ad614SDennis Dalessandro 		return -EACCES;
300f48ad614SDennis Dalessandro 
301dba715f0SDean Luick 	ret = __i2c_write(ppd, target, i2c_addr, offset, bp, len);
302dba715f0SDean Luick 	if (ret)
303f48ad614SDennis Dalessandro 		return ret;
304f48ad614SDennis Dalessandro 
305dba715f0SDean Luick 	return len;
306f48ad614SDennis Dalessandro }
307f48ad614SDennis Dalessandro 
308f48ad614SDennis Dalessandro /*
309f48ad614SDennis Dalessandro  * Raw i2c read.  No set-up or lock checking.
310dba715f0SDean Luick  *
311dba715f0SDean Luick  * Return 0 on success, -errno on error.
312f48ad614SDennis Dalessandro  */
__i2c_read(struct hfi1_pportdata * ppd,u32 target,int i2c_addr,int offset,void * bp,int len)313f48ad614SDennis Dalessandro static int __i2c_read(struct hfi1_pportdata *ppd, u32 target, int i2c_addr,
314f48ad614SDennis Dalessandro 		      int offset, void *bp, int len)
315f48ad614SDennis Dalessandro {
316f48ad614SDennis Dalessandro 	struct hfi1_devdata *dd = ppd->dd;
317dba715f0SDean Luick 	struct hfi1_i2c_bus *bus;
318dba715f0SDean Luick 	u8 slave_addr;
319dba715f0SDean Luick 	int offset_size;
320f48ad614SDennis Dalessandro 
321dba715f0SDean Luick 	bus = target ? dd->asic_data->i2c_bus1 : dd->asic_data->i2c_bus0;
322dba715f0SDean Luick 	slave_addr = (i2c_addr & 0xff) >> 1; /* convert to 7-bit addr */
323dba715f0SDean Luick 	offset_size = (i2c_addr >> 8) & 0x3;
324dba715f0SDean Luick 	return i2c_bus_read(dd, bus, slave_addr, offset, offset_size, bp, len);
325f48ad614SDennis Dalessandro }
326f48ad614SDennis Dalessandro 
327f48ad614SDennis Dalessandro /*
328f48ad614SDennis Dalessandro  * Caller must hold the i2c chain resource.
329dba715f0SDean Luick  *
330dba715f0SDean Luick  * Return number of bytes read, or -errno.
331f48ad614SDennis Dalessandro  */
i2c_read(struct hfi1_pportdata * ppd,u32 target,int i2c_addr,int offset,void * bp,int len)332f48ad614SDennis Dalessandro int i2c_read(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, int offset,
333f48ad614SDennis Dalessandro 	     void *bp, int len)
334f48ad614SDennis Dalessandro {
335f48ad614SDennis Dalessandro 	int ret;
336f48ad614SDennis Dalessandro 
337f48ad614SDennis Dalessandro 	if (!check_chip_resource(ppd->dd, i2c_target(target), __func__))
338f48ad614SDennis Dalessandro 		return -EACCES;
339f48ad614SDennis Dalessandro 
340dba715f0SDean Luick 	ret = __i2c_read(ppd, target, i2c_addr, offset, bp, len);
341dba715f0SDean Luick 	if (ret)
342f48ad614SDennis Dalessandro 		return ret;
343f48ad614SDennis Dalessandro 
344dba715f0SDean Luick 	return len;
345f48ad614SDennis Dalessandro }
346f48ad614SDennis Dalessandro 
347f48ad614SDennis Dalessandro /*
348f48ad614SDennis Dalessandro  * Write page n, offset m of QSFP memory as defined by SFF 8636
349f48ad614SDennis Dalessandro  * by writing @addr = ((256 * n) + m)
350f48ad614SDennis Dalessandro  *
351f48ad614SDennis Dalessandro  * Caller must hold the i2c chain resource.
352dba715f0SDean Luick  *
353dba715f0SDean Luick  * Return number of bytes written or -errno.
354f48ad614SDennis Dalessandro  */
qsfp_write(struct hfi1_pportdata * ppd,u32 target,int addr,void * bp,int len)355f48ad614SDennis Dalessandro int qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
356f48ad614SDennis Dalessandro 	       int len)
357f48ad614SDennis Dalessandro {
358f48ad614SDennis Dalessandro 	int count = 0;
359f48ad614SDennis Dalessandro 	int offset;
360f48ad614SDennis Dalessandro 	int nwrite;
361dba715f0SDean Luick 	int ret = 0;
362f48ad614SDennis Dalessandro 	u8 page;
363f48ad614SDennis Dalessandro 
364f48ad614SDennis Dalessandro 	if (!check_chip_resource(ppd->dd, i2c_target(target), __func__))
365f48ad614SDennis Dalessandro 		return -EACCES;
366f48ad614SDennis Dalessandro 
367f48ad614SDennis Dalessandro 	while (count < len) {
368f48ad614SDennis Dalessandro 		/*
369f48ad614SDennis Dalessandro 		 * Set the qsfp page based on a zero-based address
370f48ad614SDennis Dalessandro 		 * and a page size of QSFP_PAGESIZE bytes.
371f48ad614SDennis Dalessandro 		 */
372f48ad614SDennis Dalessandro 		page = (u8)(addr / QSFP_PAGESIZE);
373f48ad614SDennis Dalessandro 
374f48ad614SDennis Dalessandro 		ret = __i2c_write(ppd, target, QSFP_DEV | QSFP_OFFSET_SIZE,
375f48ad614SDennis Dalessandro 				  QSFP_PAGE_SELECT_BYTE_OFFS, &page, 1);
376dba715f0SDean Luick 		/* QSFPs require a 5-10msec delay after write operations */
377dba715f0SDean Luick 		mdelay(5);
378dba715f0SDean Luick 		if (ret) {
379f48ad614SDennis Dalessandro 			hfi1_dev_porterr(ppd->dd, ppd->port,
380f48ad614SDennis Dalessandro 					 "QSFP chain %d can't write QSFP_PAGE_SELECT_BYTE: %d\n",
381f48ad614SDennis Dalessandro 					 target, ret);
382f48ad614SDennis Dalessandro 			break;
383f48ad614SDennis Dalessandro 		}
384f48ad614SDennis Dalessandro 
385f48ad614SDennis Dalessandro 		offset = addr % QSFP_PAGESIZE;
386f48ad614SDennis Dalessandro 		nwrite = len - count;
387f48ad614SDennis Dalessandro 		/* truncate write to boundary if crossing boundary */
388f48ad614SDennis Dalessandro 		if (((addr % QSFP_RW_BOUNDARY) + nwrite) > QSFP_RW_BOUNDARY)
389f48ad614SDennis Dalessandro 			nwrite = QSFP_RW_BOUNDARY - (addr % QSFP_RW_BOUNDARY);
390f48ad614SDennis Dalessandro 
391f48ad614SDennis Dalessandro 		ret = __i2c_write(ppd, target, QSFP_DEV | QSFP_OFFSET_SIZE,
392f48ad614SDennis Dalessandro 				  offset, bp + count, nwrite);
393dba715f0SDean Luick 		/* QSFPs require a 5-10msec delay after write operations */
394dba715f0SDean Luick 		mdelay(5);
395dba715f0SDean Luick 		if (ret)	/* stop on error */
396f48ad614SDennis Dalessandro 			break;
397f48ad614SDennis Dalessandro 
398dba715f0SDean Luick 		count += nwrite;
399dba715f0SDean Luick 		addr += nwrite;
400f48ad614SDennis Dalessandro 	}
401f48ad614SDennis Dalessandro 
402f48ad614SDennis Dalessandro 	if (ret < 0)
403f48ad614SDennis Dalessandro 		return ret;
404f48ad614SDennis Dalessandro 	return count;
405f48ad614SDennis Dalessandro }
406f48ad614SDennis Dalessandro 
407f48ad614SDennis Dalessandro /*
408f48ad614SDennis Dalessandro  * Perform a stand-alone single QSFP write.  Acquire the resource, do the
40921a4c95dSTadeusz Struk  * write, then release the resource.
410f48ad614SDennis Dalessandro  */
one_qsfp_write(struct hfi1_pportdata * ppd,u32 target,int addr,void * bp,int len)411f48ad614SDennis Dalessandro int one_qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
412f48ad614SDennis Dalessandro 		   int len)
413f48ad614SDennis Dalessandro {
414f48ad614SDennis Dalessandro 	struct hfi1_devdata *dd = ppd->dd;
415f48ad614SDennis Dalessandro 	u32 resource = qsfp_resource(dd);
416f48ad614SDennis Dalessandro 	int ret;
417f48ad614SDennis Dalessandro 
418f48ad614SDennis Dalessandro 	ret = acquire_chip_resource(dd, resource, QSFP_WAIT);
419f48ad614SDennis Dalessandro 	if (ret)
420f48ad614SDennis Dalessandro 		return ret;
421f48ad614SDennis Dalessandro 	ret = qsfp_write(ppd, target, addr, bp, len);
422f48ad614SDennis Dalessandro 	release_chip_resource(dd, resource);
423f48ad614SDennis Dalessandro 
424f48ad614SDennis Dalessandro 	return ret;
425f48ad614SDennis Dalessandro }
426f48ad614SDennis Dalessandro 
427f48ad614SDennis Dalessandro /*
428f48ad614SDennis Dalessandro  * Access page n, offset m of QSFP memory as defined by SFF 8636
429f48ad614SDennis Dalessandro  * by reading @addr = ((256 * n) + m)
430f48ad614SDennis Dalessandro  *
431f48ad614SDennis Dalessandro  * Caller must hold the i2c chain resource.
432dba715f0SDean Luick  *
433dba715f0SDean Luick  * Return the number of bytes read or -errno.
434f48ad614SDennis Dalessandro  */
qsfp_read(struct hfi1_pportdata * ppd,u32 target,int addr,void * bp,int len)435f48ad614SDennis Dalessandro int qsfp_read(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
436f48ad614SDennis Dalessandro 	      int len)
437f48ad614SDennis Dalessandro {
438f48ad614SDennis Dalessandro 	int count = 0;
439f48ad614SDennis Dalessandro 	int offset;
440f48ad614SDennis Dalessandro 	int nread;
441dba715f0SDean Luick 	int ret = 0;
442f48ad614SDennis Dalessandro 	u8 page;
443f48ad614SDennis Dalessandro 
444f48ad614SDennis Dalessandro 	if (!check_chip_resource(ppd->dd, i2c_target(target), __func__))
445f48ad614SDennis Dalessandro 		return -EACCES;
446f48ad614SDennis Dalessandro 
447f48ad614SDennis Dalessandro 	while (count < len) {
448f48ad614SDennis Dalessandro 		/*
449f48ad614SDennis Dalessandro 		 * Set the qsfp page based on a zero-based address
450f48ad614SDennis Dalessandro 		 * and a page size of QSFP_PAGESIZE bytes.
451f48ad614SDennis Dalessandro 		 */
452f48ad614SDennis Dalessandro 		page = (u8)(addr / QSFP_PAGESIZE);
453f48ad614SDennis Dalessandro 		ret = __i2c_write(ppd, target, QSFP_DEV | QSFP_OFFSET_SIZE,
454f48ad614SDennis Dalessandro 				  QSFP_PAGE_SELECT_BYTE_OFFS, &page, 1);
455dba715f0SDean Luick 		/* QSFPs require a 5-10msec delay after write operations */
456dba715f0SDean Luick 		mdelay(5);
457dba715f0SDean Luick 		if (ret) {
458f48ad614SDennis Dalessandro 			hfi1_dev_porterr(ppd->dd, ppd->port,
459f48ad614SDennis Dalessandro 					 "QSFP chain %d can't write QSFP_PAGE_SELECT_BYTE: %d\n",
460f48ad614SDennis Dalessandro 					 target, ret);
461f48ad614SDennis Dalessandro 			break;
462f48ad614SDennis Dalessandro 		}
463f48ad614SDennis Dalessandro 
464f48ad614SDennis Dalessandro 		offset = addr % QSFP_PAGESIZE;
465f48ad614SDennis Dalessandro 		nread = len - count;
466f48ad614SDennis Dalessandro 		/* truncate read to boundary if crossing boundary */
467f48ad614SDennis Dalessandro 		if (((addr % QSFP_RW_BOUNDARY) + nread) > QSFP_RW_BOUNDARY)
468f48ad614SDennis Dalessandro 			nread = QSFP_RW_BOUNDARY - (addr % QSFP_RW_BOUNDARY);
469f48ad614SDennis Dalessandro 
470f48ad614SDennis Dalessandro 		ret = __i2c_read(ppd, target, QSFP_DEV | QSFP_OFFSET_SIZE,
471f48ad614SDennis Dalessandro 				 offset, bp + count, nread);
472dba715f0SDean Luick 		if (ret)	/* stop on error */
473f48ad614SDennis Dalessandro 			break;
474f48ad614SDennis Dalessandro 
475dba715f0SDean Luick 		count += nread;
476dba715f0SDean Luick 		addr += nread;
477f48ad614SDennis Dalessandro 	}
478f48ad614SDennis Dalessandro 
479f48ad614SDennis Dalessandro 	if (ret < 0)
480f48ad614SDennis Dalessandro 		return ret;
481f48ad614SDennis Dalessandro 	return count;
482f48ad614SDennis Dalessandro }
483f48ad614SDennis Dalessandro 
484f48ad614SDennis Dalessandro /*
485f48ad614SDennis Dalessandro  * Perform a stand-alone single QSFP read.  Acquire the resource, do the
486f48ad614SDennis Dalessandro  * read, then release the resource.
487f48ad614SDennis Dalessandro  */
one_qsfp_read(struct hfi1_pportdata * ppd,u32 target,int addr,void * bp,int len)488f48ad614SDennis Dalessandro int one_qsfp_read(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
489f48ad614SDennis Dalessandro 		  int len)
490f48ad614SDennis Dalessandro {
491f48ad614SDennis Dalessandro 	struct hfi1_devdata *dd = ppd->dd;
492f48ad614SDennis Dalessandro 	u32 resource = qsfp_resource(dd);
493f48ad614SDennis Dalessandro 	int ret;
494f48ad614SDennis Dalessandro 
495f48ad614SDennis Dalessandro 	ret = acquire_chip_resource(dd, resource, QSFP_WAIT);
496f48ad614SDennis Dalessandro 	if (ret)
497f48ad614SDennis Dalessandro 		return ret;
498f48ad614SDennis Dalessandro 	ret = qsfp_read(ppd, target, addr, bp, len);
499f48ad614SDennis Dalessandro 	release_chip_resource(dd, resource);
500f48ad614SDennis Dalessandro 
501f48ad614SDennis Dalessandro 	return ret;
502f48ad614SDennis Dalessandro }
503f48ad614SDennis Dalessandro 
504f48ad614SDennis Dalessandro /*
505f48ad614SDennis Dalessandro  * This function caches the QSFP memory range in 128 byte chunks.
506f48ad614SDennis Dalessandro  * As an example, the next byte after address 255 is byte 128 from
507f48ad614SDennis Dalessandro  * upper page 01H (if existing) rather than byte 0 from lower page 00H.
508f48ad614SDennis Dalessandro  * Access page n, offset m of QSFP memory as defined by SFF 8636
509f48ad614SDennis Dalessandro  * in the cache by reading byte ((128 * n) + m)
510f48ad614SDennis Dalessandro  * The calls to qsfp_{read,write} in this function correctly handle the
511f48ad614SDennis Dalessandro  * address map difference between this mapping and the mapping implemented
512f48ad614SDennis Dalessandro  * by those functions
513f48ad614SDennis Dalessandro  *
514f48ad614SDennis Dalessandro  * The caller must be holding the QSFP i2c chain resource.
515f48ad614SDennis Dalessandro  */
refresh_qsfp_cache(struct hfi1_pportdata * ppd,struct qsfp_data * cp)516f48ad614SDennis Dalessandro int refresh_qsfp_cache(struct hfi1_pportdata *ppd, struct qsfp_data *cp)
517f48ad614SDennis Dalessandro {
518f48ad614SDennis Dalessandro 	u32 target = ppd->dd->hfi1_id;
519f48ad614SDennis Dalessandro 	int ret;
520f48ad614SDennis Dalessandro 	unsigned long flags;
521f48ad614SDennis Dalessandro 	u8 *cache = &cp->cache[0];
522f48ad614SDennis Dalessandro 
523f48ad614SDennis Dalessandro 	/* ensure sane contents on invalid reads, for cable swaps */
524f48ad614SDennis Dalessandro 	memset(cache, 0, (QSFP_MAX_NUM_PAGES * 128));
525f48ad614SDennis Dalessandro 	spin_lock_irqsave(&ppd->qsfp_info.qsfp_lock, flags);
526f48ad614SDennis Dalessandro 	ppd->qsfp_info.cache_valid = 0;
527f48ad614SDennis Dalessandro 	spin_unlock_irqrestore(&ppd->qsfp_info.qsfp_lock, flags);
528f48ad614SDennis Dalessandro 
529f48ad614SDennis Dalessandro 	if (!qsfp_mod_present(ppd)) {
530f48ad614SDennis Dalessandro 		ret = -ENODEV;
531f48ad614SDennis Dalessandro 		goto bail;
532f48ad614SDennis Dalessandro 	}
533f48ad614SDennis Dalessandro 
534f48ad614SDennis Dalessandro 	ret = qsfp_read(ppd, target, 0, cache, QSFP_PAGESIZE);
535f48ad614SDennis Dalessandro 	if (ret != QSFP_PAGESIZE) {
536f48ad614SDennis Dalessandro 		dd_dev_info(ppd->dd,
537f48ad614SDennis Dalessandro 			    "%s: Page 0 read failed, expected %d, got %d\n",
538f48ad614SDennis Dalessandro 			    __func__, QSFP_PAGESIZE, ret);
539f48ad614SDennis Dalessandro 		goto bail;
540f48ad614SDennis Dalessandro 	}
541f48ad614SDennis Dalessandro 
542f48ad614SDennis Dalessandro 	/* Is paging enabled? */
543f48ad614SDennis Dalessandro 	if (!(cache[2] & 4)) {
544f48ad614SDennis Dalessandro 		/* Paging enabled, page 03 required */
545f48ad614SDennis Dalessandro 		if ((cache[195] & 0xC0) == 0xC0) {
546f48ad614SDennis Dalessandro 			/* all */
547f48ad614SDennis Dalessandro 			ret = qsfp_read(ppd, target, 384, cache + 256, 128);
548f48ad614SDennis Dalessandro 			if (ret <= 0 || ret != 128) {
549f48ad614SDennis Dalessandro 				dd_dev_info(ppd->dd, "%s failed\n", __func__);
550f48ad614SDennis Dalessandro 				goto bail;
551f48ad614SDennis Dalessandro 			}
552f48ad614SDennis Dalessandro 			ret = qsfp_read(ppd, target, 640, cache + 384, 128);
553f48ad614SDennis Dalessandro 			if (ret <= 0 || ret != 128) {
554f48ad614SDennis Dalessandro 				dd_dev_info(ppd->dd, "%s failed\n", __func__);
555f48ad614SDennis Dalessandro 				goto bail;
556f48ad614SDennis Dalessandro 			}
557f48ad614SDennis Dalessandro 			ret = qsfp_read(ppd, target, 896, cache + 512, 128);
558f48ad614SDennis Dalessandro 			if (ret <= 0 || ret != 128) {
559f48ad614SDennis Dalessandro 				dd_dev_info(ppd->dd, "%s failed\n", __func__);
560f48ad614SDennis Dalessandro 				goto bail;
561f48ad614SDennis Dalessandro 			}
562f48ad614SDennis Dalessandro 		} else if ((cache[195] & 0x80) == 0x80) {
563f48ad614SDennis Dalessandro 			/* only page 2 and 3 */
564f48ad614SDennis Dalessandro 			ret = qsfp_read(ppd, target, 640, cache + 384, 128);
565f48ad614SDennis Dalessandro 			if (ret <= 0 || ret != 128) {
566f48ad614SDennis Dalessandro 				dd_dev_info(ppd->dd, "%s failed\n", __func__);
567f48ad614SDennis Dalessandro 				goto bail;
568f48ad614SDennis Dalessandro 			}
569f48ad614SDennis Dalessandro 			ret = qsfp_read(ppd, target, 896, cache + 512, 128);
570f48ad614SDennis Dalessandro 			if (ret <= 0 || ret != 128) {
571f48ad614SDennis Dalessandro 				dd_dev_info(ppd->dd, "%s failed\n", __func__);
572f48ad614SDennis Dalessandro 				goto bail;
573f48ad614SDennis Dalessandro 			}
574f48ad614SDennis Dalessandro 		} else if ((cache[195] & 0x40) == 0x40) {
575f48ad614SDennis Dalessandro 			/* only page 1 and 3 */
576f48ad614SDennis Dalessandro 			ret = qsfp_read(ppd, target, 384, cache + 256, 128);
577f48ad614SDennis Dalessandro 			if (ret <= 0 || ret != 128) {
578f48ad614SDennis Dalessandro 				dd_dev_info(ppd->dd, "%s failed\n", __func__);
579f48ad614SDennis Dalessandro 				goto bail;
580f48ad614SDennis Dalessandro 			}
581f48ad614SDennis Dalessandro 			ret = qsfp_read(ppd, target, 896, cache + 512, 128);
582f48ad614SDennis Dalessandro 			if (ret <= 0 || ret != 128) {
583f48ad614SDennis Dalessandro 				dd_dev_info(ppd->dd, "%s failed\n", __func__);
584f48ad614SDennis Dalessandro 				goto bail;
585f48ad614SDennis Dalessandro 			}
586f48ad614SDennis Dalessandro 		} else {
587f48ad614SDennis Dalessandro 			/* only page 3 */
588f48ad614SDennis Dalessandro 			ret = qsfp_read(ppd, target, 896, cache + 512, 128);
589f48ad614SDennis Dalessandro 			if (ret <= 0 || ret != 128) {
590f48ad614SDennis Dalessandro 				dd_dev_info(ppd->dd, "%s failed\n", __func__);
591f48ad614SDennis Dalessandro 				goto bail;
592f48ad614SDennis Dalessandro 			}
593f48ad614SDennis Dalessandro 		}
594f48ad614SDennis Dalessandro 	}
595f48ad614SDennis Dalessandro 
596f48ad614SDennis Dalessandro 	spin_lock_irqsave(&ppd->qsfp_info.qsfp_lock, flags);
597f48ad614SDennis Dalessandro 	ppd->qsfp_info.cache_valid = 1;
598f48ad614SDennis Dalessandro 	ppd->qsfp_info.cache_refresh_required = 0;
599f48ad614SDennis Dalessandro 	spin_unlock_irqrestore(&ppd->qsfp_info.qsfp_lock, flags);
600f48ad614SDennis Dalessandro 
601f48ad614SDennis Dalessandro 	return 0;
602f48ad614SDennis Dalessandro 
603f48ad614SDennis Dalessandro bail:
604f48ad614SDennis Dalessandro 	memset(cache, 0, (QSFP_MAX_NUM_PAGES * 128));
605f48ad614SDennis Dalessandro 	return ret;
606f48ad614SDennis Dalessandro }
607f48ad614SDennis Dalessandro 
608f48ad614SDennis Dalessandro const char * const hfi1_qsfp_devtech[16] = {
609f48ad614SDennis Dalessandro 	"850nm VCSEL", "1310nm VCSEL", "1550nm VCSEL", "1310nm FP",
610f48ad614SDennis Dalessandro 	"1310nm DFB", "1550nm DFB", "1310nm EML", "1550nm EML",
611f48ad614SDennis Dalessandro 	"Cu Misc", "1490nm DFB", "Cu NoEq", "Cu Eq",
612f48ad614SDennis Dalessandro 	"Undef", "Cu Active BothEq", "Cu FarEq", "Cu NearEq"
613f48ad614SDennis Dalessandro };
614f48ad614SDennis Dalessandro 
615f48ad614SDennis Dalessandro #define QSFP_DUMP_CHUNK 16 /* Holds longest string */
616f48ad614SDennis Dalessandro #define QSFP_DEFAULT_HDR_CNT 224
617f48ad614SDennis Dalessandro 
618f48ad614SDennis Dalessandro #define QSFP_PWR(pbyte) (((pbyte) >> 6) & 3)
619f48ad614SDennis Dalessandro #define QSFP_HIGH_PWR(pbyte) ((pbyte) & 3)
620f48ad614SDennis Dalessandro /* For use with QSFP_HIGH_PWR macro */
621f48ad614SDennis Dalessandro #define QSFP_HIGH_PWR_UNUSED	0 /* Bits [1:0] = 00 implies low power module */
622f48ad614SDennis Dalessandro 
623f48ad614SDennis Dalessandro /*
624f48ad614SDennis Dalessandro  * Takes power class byte [Page 00 Byte 129] in SFF 8636
625f48ad614SDennis Dalessandro  * Returns power class as integer (1 through 7, per SFF 8636 rev 2.4)
626f48ad614SDennis Dalessandro  */
get_qsfp_power_class(u8 power_byte)627f48ad614SDennis Dalessandro int get_qsfp_power_class(u8 power_byte)
628f48ad614SDennis Dalessandro {
629f48ad614SDennis Dalessandro 	if (QSFP_HIGH_PWR(power_byte) == QSFP_HIGH_PWR_UNUSED)
630f48ad614SDennis Dalessandro 		/* power classes count from 1, their bit encodings from 0 */
631f48ad614SDennis Dalessandro 		return (QSFP_PWR(power_byte) + 1);
632f48ad614SDennis Dalessandro 	/*
633f48ad614SDennis Dalessandro 	 * 00 in the high power classes stands for unused, bringing
634f48ad614SDennis Dalessandro 	 * balance to the off-by-1 offset above, we add 4 here to
635f48ad614SDennis Dalessandro 	 * account for the difference between the low and high power
636f48ad614SDennis Dalessandro 	 * groups
637f48ad614SDennis Dalessandro 	 */
638f48ad614SDennis Dalessandro 	return (QSFP_HIGH_PWR(power_byte) + 4);
639f48ad614SDennis Dalessandro }
640f48ad614SDennis Dalessandro 
qsfp_mod_present(struct hfi1_pportdata * ppd)641f48ad614SDennis Dalessandro int qsfp_mod_present(struct hfi1_pportdata *ppd)
642f48ad614SDennis Dalessandro {
643f48ad614SDennis Dalessandro 	struct hfi1_devdata *dd = ppd->dd;
644f48ad614SDennis Dalessandro 	u64 reg;
645f48ad614SDennis Dalessandro 
646f48ad614SDennis Dalessandro 	reg = read_csr(dd, dd->hfi1_id ? ASIC_QSFP2_IN : ASIC_QSFP1_IN);
647f48ad614SDennis Dalessandro 	return !(reg & QSFP_HFI0_MODPRST_N);
648f48ad614SDennis Dalessandro }
649f48ad614SDennis Dalessandro 
650f48ad614SDennis Dalessandro /*
651f48ad614SDennis Dalessandro  * This function maps QSFP memory addresses in 128 byte chunks in the following
652f48ad614SDennis Dalessandro  * fashion per the CableInfo SMA query definition in the IBA 1.3 spec/OPA Gen 1
653f48ad614SDennis Dalessandro  * spec
654f48ad614SDennis Dalessandro  * For addr 000-127, lower page 00h
655f48ad614SDennis Dalessandro  * For addr 128-255, upper page 00h
656f48ad614SDennis Dalessandro  * For addr 256-383, upper page 01h
657f48ad614SDennis Dalessandro  * For addr 384-511, upper page 02h
658f48ad614SDennis Dalessandro  * For addr 512-639, upper page 03h
659f48ad614SDennis Dalessandro  *
660f48ad614SDennis Dalessandro  * For addresses beyond this range, it returns the invalid range of data buffer
661f48ad614SDennis Dalessandro  * set to 0.
662f48ad614SDennis Dalessandro  * For upper pages that are optional, if they are not valid, returns the
663f48ad614SDennis Dalessandro  * particular range of bytes in the data buffer set to 0.
664f48ad614SDennis Dalessandro  */
get_cable_info(struct hfi1_devdata * dd,u32 port_num,u32 addr,u32 len,u8 * data)665f48ad614SDennis Dalessandro int get_cable_info(struct hfi1_devdata *dd, u32 port_num, u32 addr, u32 len,
666f48ad614SDennis Dalessandro 		   u8 *data)
667f48ad614SDennis Dalessandro {
668f48ad614SDennis Dalessandro 	struct hfi1_pportdata *ppd;
669140690eaSEaswar Hariharan 	u32 excess_len = len;
670140690eaSEaswar Hariharan 	int ret = 0, offset = 0;
671f48ad614SDennis Dalessandro 
672f48ad614SDennis Dalessandro 	if (port_num > dd->num_pports || port_num < 1) {
673f48ad614SDennis Dalessandro 		dd_dev_info(dd, "%s: Invalid port number %d\n",
674f48ad614SDennis Dalessandro 			    __func__, port_num);
675f48ad614SDennis Dalessandro 		ret = -EINVAL;
676f48ad614SDennis Dalessandro 		goto set_zeroes;
677f48ad614SDennis Dalessandro 	}
678f48ad614SDennis Dalessandro 
679f48ad614SDennis Dalessandro 	ppd = dd->pport + (port_num - 1);
680f48ad614SDennis Dalessandro 	if (!qsfp_mod_present(ppd)) {
681f48ad614SDennis Dalessandro 		ret = -ENODEV;
682f48ad614SDennis Dalessandro 		goto set_zeroes;
683f48ad614SDennis Dalessandro 	}
684f48ad614SDennis Dalessandro 
685f48ad614SDennis Dalessandro 	if (!ppd->qsfp_info.cache_valid) {
686f48ad614SDennis Dalessandro 		ret = -EINVAL;
687f48ad614SDennis Dalessandro 		goto set_zeroes;
688f48ad614SDennis Dalessandro 	}
689f48ad614SDennis Dalessandro 
690f48ad614SDennis Dalessandro 	if (addr >= (QSFP_MAX_NUM_PAGES * 128)) {
691f48ad614SDennis Dalessandro 		ret = -ERANGE;
692f48ad614SDennis Dalessandro 		goto set_zeroes;
693f48ad614SDennis Dalessandro 	}
694f48ad614SDennis Dalessandro 
695f48ad614SDennis Dalessandro 	if ((addr + len) > (QSFP_MAX_NUM_PAGES * 128)) {
696f48ad614SDennis Dalessandro 		excess_len = (addr + len) - (QSFP_MAX_NUM_PAGES * 128);
697f48ad614SDennis Dalessandro 		memcpy(data, &ppd->qsfp_info.cache[addr], (len - excess_len));
698f48ad614SDennis Dalessandro 		data += (len - excess_len);
699f48ad614SDennis Dalessandro 		goto set_zeroes;
700f48ad614SDennis Dalessandro 	}
701f48ad614SDennis Dalessandro 
702f48ad614SDennis Dalessandro 	memcpy(data, &ppd->qsfp_info.cache[addr], len);
703140690eaSEaswar Hariharan 
704140690eaSEaswar Hariharan 	if (addr <= QSFP_MONITOR_VAL_END &&
705140690eaSEaswar Hariharan 	    (addr + len) >= QSFP_MONITOR_VAL_START) {
706140690eaSEaswar Hariharan 		/* Overlap with the dynamic channel monitor range */
707140690eaSEaswar Hariharan 		if (addr < QSFP_MONITOR_VAL_START) {
708140690eaSEaswar Hariharan 			if (addr + len <= QSFP_MONITOR_VAL_END)
709140690eaSEaswar Hariharan 				len = addr + len - QSFP_MONITOR_VAL_START;
710140690eaSEaswar Hariharan 			else
711140690eaSEaswar Hariharan 				len = QSFP_MONITOR_RANGE;
712140690eaSEaswar Hariharan 			offset = QSFP_MONITOR_VAL_START - addr;
713140690eaSEaswar Hariharan 			addr = QSFP_MONITOR_VAL_START;
714140690eaSEaswar Hariharan 		} else if (addr == QSFP_MONITOR_VAL_START) {
715140690eaSEaswar Hariharan 			offset = 0;
716140690eaSEaswar Hariharan 			if (addr + len > QSFP_MONITOR_VAL_END)
717140690eaSEaswar Hariharan 				len = QSFP_MONITOR_RANGE;
718140690eaSEaswar Hariharan 		} else {
719140690eaSEaswar Hariharan 			offset = 0;
720140690eaSEaswar Hariharan 			if (addr + len > QSFP_MONITOR_VAL_END)
721140690eaSEaswar Hariharan 				len = QSFP_MONITOR_VAL_END - addr + 1;
722140690eaSEaswar Hariharan 		}
723140690eaSEaswar Hariharan 		/* Refresh the values of the dynamic monitors from the cable */
724140690eaSEaswar Hariharan 		ret = one_qsfp_read(ppd, dd->hfi1_id, addr, data + offset, len);
725140690eaSEaswar Hariharan 		if (ret != len) {
726140690eaSEaswar Hariharan 			ret = -EAGAIN;
727140690eaSEaswar Hariharan 			goto set_zeroes;
728140690eaSEaswar Hariharan 		}
729140690eaSEaswar Hariharan 	}
730140690eaSEaswar Hariharan 
731f48ad614SDennis Dalessandro 	return 0;
732f48ad614SDennis Dalessandro 
733f48ad614SDennis Dalessandro set_zeroes:
734f48ad614SDennis Dalessandro 	memset(data, 0, excess_len);
735f48ad614SDennis Dalessandro 	return ret;
736f48ad614SDennis Dalessandro }
737f48ad614SDennis Dalessandro 
738f48ad614SDennis Dalessandro static const char *pwr_codes[8] = {"N/AW",
739f48ad614SDennis Dalessandro 				  "1.5W",
740f48ad614SDennis Dalessandro 				  "2.0W",
741f48ad614SDennis Dalessandro 				  "2.5W",
742f48ad614SDennis Dalessandro 				  "3.5W",
743f48ad614SDennis Dalessandro 				  "4.0W",
744f48ad614SDennis Dalessandro 				  "4.5W",
745f48ad614SDennis Dalessandro 				  "5.0W"
746f48ad614SDennis Dalessandro 				 };
747f48ad614SDennis Dalessandro 
qsfp_dump(struct hfi1_pportdata * ppd,char * buf,int len)748f48ad614SDennis Dalessandro int qsfp_dump(struct hfi1_pportdata *ppd, char *buf, int len)
749f48ad614SDennis Dalessandro {
750f48ad614SDennis Dalessandro 	u8 *cache = &ppd->qsfp_info.cache[0];
751f48ad614SDennis Dalessandro 	u8 bin_buff[QSFP_DUMP_CHUNK];
752f48ad614SDennis Dalessandro 	char lenstr[6];
753f48ad614SDennis Dalessandro 	int sofar;
754f48ad614SDennis Dalessandro 	int bidx = 0;
755f48ad614SDennis Dalessandro 	u8 *atten = &cache[QSFP_ATTEN_OFFS];
756f48ad614SDennis Dalessandro 	u8 *vendor_oui = &cache[QSFP_VOUI_OFFS];
757f48ad614SDennis Dalessandro 	u8 power_byte = 0;
758f48ad614SDennis Dalessandro 
759f48ad614SDennis Dalessandro 	sofar = 0;
760f48ad614SDennis Dalessandro 	lenstr[0] = ' ';
761f48ad614SDennis Dalessandro 	lenstr[1] = '\0';
762f48ad614SDennis Dalessandro 
763f48ad614SDennis Dalessandro 	if (ppd->qsfp_info.cache_valid) {
764f48ad614SDennis Dalessandro 		if (QSFP_IS_CU(cache[QSFP_MOD_TECH_OFFS]))
765c078f0ddSTadeusz Struk 			snprintf(lenstr, sizeof(lenstr), "%dM ",
766c078f0ddSTadeusz Struk 				 cache[QSFP_MOD_LEN_OFFS]);
767f48ad614SDennis Dalessandro 
768f48ad614SDennis Dalessandro 		power_byte = cache[QSFP_MOD_PWR_OFFS];
769f48ad614SDennis Dalessandro 		sofar += scnprintf(buf + sofar, len - sofar, "PWR:%.3sW\n",
770f48ad614SDennis Dalessandro 				pwr_codes[get_qsfp_power_class(power_byte)]);
771f48ad614SDennis Dalessandro 
772f48ad614SDennis Dalessandro 		sofar += scnprintf(buf + sofar, len - sofar, "TECH:%s%s\n",
773f48ad614SDennis Dalessandro 				lenstr,
774f48ad614SDennis Dalessandro 			hfi1_qsfp_devtech[(cache[QSFP_MOD_TECH_OFFS]) >> 4]);
775f48ad614SDennis Dalessandro 
776f48ad614SDennis Dalessandro 		sofar += scnprintf(buf + sofar, len - sofar, "Vendor:%.*s\n",
777f48ad614SDennis Dalessandro 				   QSFP_VEND_LEN, &cache[QSFP_VEND_OFFS]);
778f48ad614SDennis Dalessandro 
779f48ad614SDennis Dalessandro 		sofar += scnprintf(buf + sofar, len - sofar, "OUI:%06X\n",
780f48ad614SDennis Dalessandro 				   QSFP_OUI(vendor_oui));
781f48ad614SDennis Dalessandro 
782f48ad614SDennis Dalessandro 		sofar += scnprintf(buf + sofar, len - sofar, "Part#:%.*s\n",
783f48ad614SDennis Dalessandro 				   QSFP_PN_LEN, &cache[QSFP_PN_OFFS]);
784f48ad614SDennis Dalessandro 
785f48ad614SDennis Dalessandro 		sofar += scnprintf(buf + sofar, len - sofar, "Rev:%.*s\n",
786f48ad614SDennis Dalessandro 				   QSFP_REV_LEN, &cache[QSFP_REV_OFFS]);
787f48ad614SDennis Dalessandro 
788f48ad614SDennis Dalessandro 		if (QSFP_IS_CU(cache[QSFP_MOD_TECH_OFFS]))
789f48ad614SDennis Dalessandro 			sofar += scnprintf(buf + sofar, len - sofar,
790f48ad614SDennis Dalessandro 				"Atten:%d, %d\n",
791f48ad614SDennis Dalessandro 				QSFP_ATTEN_SDR(atten),
792f48ad614SDennis Dalessandro 				QSFP_ATTEN_DDR(atten));
793f48ad614SDennis Dalessandro 
794f48ad614SDennis Dalessandro 		sofar += scnprintf(buf + sofar, len - sofar, "Serial:%.*s\n",
795f48ad614SDennis Dalessandro 				   QSFP_SN_LEN, &cache[QSFP_SN_OFFS]);
796f48ad614SDennis Dalessandro 
797f48ad614SDennis Dalessandro 		sofar += scnprintf(buf + sofar, len - sofar, "Date:%.*s\n",
798f48ad614SDennis Dalessandro 				   QSFP_DATE_LEN, &cache[QSFP_DATE_OFFS]);
799f48ad614SDennis Dalessandro 
800f48ad614SDennis Dalessandro 		sofar += scnprintf(buf + sofar, len - sofar, "Lot:%.*s\n",
801f48ad614SDennis Dalessandro 				   QSFP_LOT_LEN, &cache[QSFP_LOT_OFFS]);
802f48ad614SDennis Dalessandro 
803f48ad614SDennis Dalessandro 		while (bidx < QSFP_DEFAULT_HDR_CNT) {
804f48ad614SDennis Dalessandro 			int iidx;
805f48ad614SDennis Dalessandro 
806f48ad614SDennis Dalessandro 			memcpy(bin_buff, &cache[bidx], QSFP_DUMP_CHUNK);
807f48ad614SDennis Dalessandro 			for (iidx = 0; iidx < QSFP_DUMP_CHUNK; ++iidx) {
808f48ad614SDennis Dalessandro 				sofar += scnprintf(buf + sofar, len - sofar,
809f48ad614SDennis Dalessandro 					" %02X", bin_buff[iidx]);
810f48ad614SDennis Dalessandro 			}
811f48ad614SDennis Dalessandro 			sofar += scnprintf(buf + sofar, len - sofar, "\n");
812f48ad614SDennis Dalessandro 			bidx += QSFP_DUMP_CHUNK;
813f48ad614SDennis Dalessandro 		}
814f48ad614SDennis Dalessandro 	}
815f48ad614SDennis Dalessandro 	return sofar;
816f48ad614SDennis Dalessandro }
817