Skip to content

Commit b380e95

Browse files
committed
optoe: Add CMIS Bank support for transceivers with >8 lanes
Signed-off-by: Wataru Ishida <[email protected]>
1 parent db23435 commit b380e95

File tree

2 files changed

+308
-0
lines changed

2 files changed

+308
-0
lines changed
Lines changed: 307 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,307 @@
1+
From d654fd07f90bda8565ebbb18979dfee8d8fff3da Mon Sep 17 00:00:00 2001
2+
From: Wataru Ishida <[email protected]>
3+
Date: Wed, 2 Apr 2025 07:10:10 +0000
4+
Subject: [PATCH] optoe: Add CMIS Bank support for transceivers with >8 lanes
5+
6+
This patch adds CMIS Bank support to the 'optoe3' device class in order
7+
to enable access to CMIS transceivers with more than 8 lanes (e.g., OSFP-XD, CPO OEs).
8+
9+
- Bank support is enabled only for the 'optoe3' dev class.
10+
- The default bank size is set to 4, and can be modified via the 'bank_size' sysfs entry.
11+
- For 'optoe3', the 'write_max' value is updated to 2 to comply with CMIS requirements,
12+
which mandate that both bank and page values be updated in a single WRITE operation.
13+
14+
Signed-off-by: Wataru Ishida <[email protected]>
15+
---
16+
drivers/misc/eeprom/optoe.c | 142 ++++++++++++++++++++++++++++--------
17+
1 file changed, 112 insertions(+), 30 deletions(-)
18+
19+
diff --git a/drivers/misc/eeprom/optoe.c b/drivers/misc/eeprom/optoe.c
20+
index 22d2c0cd4..f5be0d9b7 100644
21+
--- a/drivers/misc/eeprom/optoe.c
22+
+++ b/drivers/misc/eeprom/optoe.c
23+
@@ -150,6 +150,12 @@ struct optoe_platform_data {
24+
25+
/* fundamental unit of addressing for EEPROM */
26+
#define OPTOE_PAGE_SIZE 128
27+
+
28+
+#define OPTOE_DEFAULT_BANK_SIZE 4
29+
+#define OPTOE_MAX_SUPPORTED_BANK_SIZE 8
30+
+#define OPTOE_NON_BANKED_PAGE_SIZE 16 /* page 00h-0Fh are not banked */
31+
+#define OPTOE_BANKED_PAGE_SIZE 240 /* page 10h-FFh are banked */
32+
+
33+
/*
34+
* Single address devices (eg QSFP) have 256 pages, plus the unpaged
35+
* low 128 bytes. If the device does not support paging, it is
36+
@@ -168,6 +174,7 @@ struct optoe_platform_data {
37+
#define TWO_ADDR_NO_0X51_SIZE (2 * OPTOE_PAGE_SIZE)
38+
39+
/* a few constants to find our way around the EEPROM */
40+
+#define OPTOE_BANK_SELECT_REG 0x7E
41+
#define OPTOE_PAGE_SELECT_REG 0x7F
42+
#define ONE_ADDR_PAGEABLE_REG 0x02
43+
#define QSFP_NOT_PAGEABLE (1<<2)
44+
@@ -195,6 +202,7 @@ struct optoe_data {
45+
u8 *writebuf;
46+
unsigned int write_max;
47+
unsigned int write_timeout;
48+
+ unsigned int bank_size; /* 0 means bank is not supported */
49+
50+
unsigned int num_addresses;
51+
52+
@@ -245,13 +253,19 @@ static const struct i2c_device_id optoe_ids[] = {
53+
};
54+
MODULE_DEVICE_TABLE(i2c, optoe_ids);
55+
56+
+static uint32_t one_addr_eeprom_size_with_bank(uint32_t bank_size)
57+
+{
58+
+ bank_size = bank_size == 0 ? 1 : bank_size;
59+
+ return (bank_size * OPTOE_BANKED_PAGE_SIZE + OPTOE_NON_BANKED_PAGE_SIZE + 1) * OPTOE_PAGE_SIZE;
60+
+}
61+
+
62+
/*-------------------------------------------------------------------------*/
63+
/*
64+
* This routine computes the addressing information to be used for
65+
* a given r/w request.
66+
*
67+
* Task is to calculate the client (0 = i2c addr 50, 1 = i2c addr 51),
68+
- * the page, and the offset.
69+
+ * the bank, the page, and the offset.
70+
*
71+
* Handles both single address (eg QSFP) and two address (eg SFP).
72+
* For SFP, offset 0-255 are on client[0], >255 is on client[1]
73+
@@ -274,7 +288,7 @@ MODULE_DEVICE_TABLE(i2c, optoe_ids);
74+
*/
75+
76+
static uint8_t optoe_translate_offset(struct optoe_data *optoe,
77+
- loff_t *offset, struct i2c_client **client)
78+
+ loff_t *offset, struct i2c_client **client, uint8_t *bank)
79+
{
80+
unsigned int page = 0;
81+
82+
@@ -301,8 +315,9 @@ static uint8_t optoe_translate_offset(struct optoe_data *optoe,
83+
page = (*offset >> 7)-1;
84+
/* 0x80 places the offset in the top half, offset is last 7 bits */
85+
*offset = OPTOE_PAGE_SIZE + (*offset & 0x7f);
86+
-
87+
- return page; /* note also returning client and offset */
88+
+ *bank = page < OPTOE_PAGE_SIZE ? 0 : (page - OPTOE_NON_BANKED_PAGE_SIZE) / OPTOE_BANKED_PAGE_SIZE;
89+
+ page = page - *bank * OPTOE_BANKED_PAGE_SIZE;
90+
+ return page; /* note also returning client, bank and offset */
91+
}
92+
93+
static ssize_t optoe_eeprom_read(struct optoe_data *optoe,
94+
@@ -511,21 +526,38 @@ static ssize_t optoe_eeprom_update_client(struct optoe_data *optoe,
95+
{
96+
struct i2c_client *client;
97+
ssize_t retval = 0;
98+
- uint8_t page = 0;
99+
+ uint8_t page = 0, bank = 0;
100+
loff_t phy_offset = off;
101+
int ret = 0;
102+
103+
- page = optoe_translate_offset(optoe, &phy_offset, &client);
104+
+ page = optoe_translate_offset(optoe, &phy_offset, &client, &bank);
105+
dev_dbg(&client->dev,
106+
- "%s off %lld page:%d phy_offset:%lld, count:%ld, opcode:%d\n",
107+
- __func__, off, page, phy_offset, (long int) count, opcode);
108+
+ "%s off %lld bank:%d page:%d phy_offset:%lld, count:%ld, opcode:%d\n",
109+
+ __func__, off, bank, page, phy_offset, (long int) count, opcode);
110+
if (page > 0) {
111+
- ret = optoe_eeprom_write(optoe, client, &page,
112+
- OPTOE_PAGE_SELECT_REG, 1);
113+
+ /*
114+
+ * CMIS 5.3 8.2.15 Page Mapping
115+
+ *
116+
+ * For an arbitrary Page Address change or for just a Bank Index change,
117+
+ * a host must write both BankSelect and PageSelect in one WRITE access,
118+
+ * even if the PageSelect value does not change.
119+
+ * The module does not begin processing the BankSelect value until after the PageSelect register has been written.
120+
+ *
121+
+ * For just a Page Index change (mapping another Page in the current Bank),
122+
+ * or for mapping an arbitrary unbanked Page to Upper Memory, a host may WRITE only the PageSelect Byte.
123+
+ */
124+
+ if (bank > 0) {
125+
+ char buf[2] = {bank, page};
126+
+ ret = optoe_eeprom_write(optoe, client, buf,
127+
+ OPTOE_BANK_SELECT_REG, 2);
128+
+ } else {
129+
+ ret = optoe_eeprom_write(optoe, client, &page,
130+
+ OPTOE_PAGE_SELECT_REG, 1);
131+
+ }
132+
if (ret < 0) {
133+
dev_dbg(&client->dev,
134+
- "Write page register for page %d failed ret:%d!\n",
135+
- page, ret);
136+
+ "Write page register for bank %d, page %d failed ret:%d!\n",
137+
+ bank, page, ret);
138+
return ret;
139+
}
140+
}
141+
@@ -552,14 +584,14 @@ static ssize_t optoe_eeprom_update_client(struct optoe_data *optoe,
142+
}
143+
144+
145+
- if (page > 0) {
146+
- /* return the page register to page 0 (why?) */
147+
- page = 0;
148+
- ret = optoe_eeprom_write(optoe, client, &page,
149+
- OPTOE_PAGE_SELECT_REG, 1);
150+
+ if (page > 0 || bank > 0) {
151+
+ /* return the page register to bank 0, page 0 (why?) */
152+
+ char buf[2] = {0, 0};
153+
+ ret = optoe_eeprom_write(optoe, client, buf,
154+
+ OPTOE_BANK_SELECT_REG, 2);
155+
if (ret < 0) {
156+
dev_err(&client->dev,
157+
- "Restore page register to 0 failed:%d!\n", ret);
158+
+ "Restore bank, page register to (0, 0) failed:%d!\n", ret);
159+
/* error only if nothing has been transferred */
160+
if (retval == 0)
161+
retval = ret;
162+
@@ -622,8 +654,10 @@ static ssize_t optoe_page_legal(struct optoe_data *optoe,
163+
/* if no pages needed, we're good */
164+
if ((off + len) <= ONE_ADDR_EEPROM_UNPAGED_SIZE)
165+
return len;
166+
+
167+
+ maxlen = one_addr_eeprom_size_with_bank(optoe->bank_size);
168+
/* if offset exceeds possible pages, we're not good */
169+
- if (off >= ONE_ADDR_EEPROM_SIZE)
170+
+ if (off >= maxlen)
171+
return OPTOE_EOF;
172+
/* in between, are pages supported? */
173+
status = optoe_eeprom_read(optoe, client, &regval,
174+
@@ -665,7 +699,7 @@ static ssize_t optoe_page_legal(struct optoe_data *optoe,
175+
maxlen = ONE_ADDR_EEPROM_UNPAGED_SIZE - off;
176+
} else {
177+
/* Pages supported, trim len to the end of pages */
178+
- maxlen = ONE_ADDR_EEPROM_SIZE - off;
179+
+ maxlen = maxlen - off;
180+
}
181+
len = (len > maxlen) ? maxlen : len;
182+
dev_dbg(&client->dev,
183+
@@ -995,6 +1029,44 @@ static ssize_t set_port_name(struct device *dev,
184+
return count;
185+
}
186+
187+
+static ssize_t show_bank_size(struct device *dev,
188+
+ struct device_attribute *dattr, char *buf)
189+
+{
190+
+ struct i2c_client *client = to_i2c_client(dev);
191+
+ struct optoe_data *optoe = i2c_get_clientdata(client);
192+
+ ssize_t count;
193+
+
194+
+ mutex_lock(&optoe->lock);
195+
+ count = sprintf(buf, "%u\n", optoe->bank_size);
196+
+ mutex_unlock(&optoe->lock);
197+
+
198+
+ return count;
199+
+}
200+
+
201+
+static ssize_t set_bank_size(struct device *dev,
202+
+ struct device_attribute *attr,
203+
+ const char *buf, size_t count)
204+
+{
205+
+ struct i2c_client *client = to_i2c_client(dev);
206+
+ struct optoe_data *optoe = i2c_get_clientdata(client);
207+
+ unsigned int bank_size;
208+
+
209+
+ // setting bank size is only supported for the CMIS device
210+
+ if (optoe->dev_class != CMIS_ADDR) {
211+
+ return -EINVAL;
212+
+ }
213+
+
214+
+ if (kstrtouint(buf, 0, &bank_size) != 0 ||
215+
+ bank_size < 0 || bank_size > OPTOE_MAX_SUPPORTED_BANK_SIZE)
216+
+ return -EINVAL;
217+
+
218+
+ mutex_lock(&optoe->lock);
219+
+ optoe->bank_size = bank_size;
220+
+ mutex_unlock(&optoe->lock);
221+
+
222+
+ return count;
223+
+}
224+
+
225+
static DEVICE_ATTR(port_name, 0644, show_port_name, set_port_name);
226+
#endif /* if NOT defined EEPROM_CLASS, the common case */
227+
228+
@@ -1003,6 +1075,7 @@ static DEVICE_ATTR(write_timeout, 0644, show_dev_write_timeout_size,
229+
static DEVICE_ATTR(write_max, 0644, show_dev_write_max_size,
230+
set_dev_write_max_size);
231+
static DEVICE_ATTR(dev_class, 0644, show_dev_class, set_dev_class);
232+
+static DEVICE_ATTR(bank_size, 0644, show_bank_size, set_bank_size);
233+
234+
static struct attribute *optoe_attrs[] = {
235+
#ifndef EEPROM_CLASS
236+
@@ -1011,6 +1084,7 @@ static struct attribute *optoe_attrs[] = {
237+
&dev_attr_write_timeout.attr,
238+
&dev_attr_write_max.attr,
239+
&dev_attr_dev_class.attr,
240+
+ &dev_attr_bank_size.attr,
241+
NULL,
242+
};
243+
244+
@@ -1027,6 +1101,17 @@ static int optoe_probe(struct i2c_client *client,
245+
struct optoe_data *optoe;
246+
int num_addresses = 0;
247+
char port_name[MAX_PORT_NAME_LEN];
248+
+ /*
249+
+ * NOTE: AN-2079
250+
+ * Finisar recommends that the host implement 1 byte writes
251+
+ * only since this module only supports 32 byte page boundaries.
252+
+ * 2 byte writes are acceptable for PE and Vout changes per
253+
+ * Application Note AN-2071.
254+
+ *
255+
+ * use 2 bytes for CMIS devices since CMIS 5.3 requires write both BankSelect and PageSlect in one WRITE acess.
256+
+ * see the comment in optoe_eeprom_update_client().
257+
+ */
258+
+ unsigned int write_max;
259+
260+
if (client->addr != 0x50) {
261+
dev_dbg(&client->dev, "probe, bad i2c addr: 0x%x\n",
262+
@@ -1097,19 +1182,25 @@ static int optoe_probe(struct i2c_client *client,
263+
(strcmp(client->name, "sff8436") == 0)) {
264+
/* one-address (eg QSFP) family */
265+
optoe->dev_class = ONE_ADDR;
266+
+ optoe->bank_size = 0;
267+
chip.byte_len = ONE_ADDR_EEPROM_SIZE;
268+
num_addresses = 1;
269+
+ write_max = 1;
270+
} else if ((strcmp(client->name, "optoe2") == 0) ||
271+
(strcmp(client->name, "24c04") == 0)) {
272+
/* SFP family */
273+
optoe->dev_class = TWO_ADDR;
274+
+ optoe->bank_size = 0;
275+
chip.byte_len = TWO_ADDR_EEPROM_SIZE;
276+
num_addresses = 2;
277+
+ write_max = 1;
278+
} else if (strcmp(client->name, "optoe3") == 0) {
279+
/* CMIS spec */
280+
optoe->dev_class = CMIS_ADDR;
281+
- chip.byte_len = ONE_ADDR_EEPROM_SIZE;
282+
+ optoe->bank_size = OPTOE_DEFAULT_BANK_SIZE;
283+
+ chip.byte_len = one_addr_eeprom_size_with_bank(OPTOE_MAX_SUPPORTED_BANK_SIZE);
284+
num_addresses = 1;
285+
+ write_max = 2;
286+
} else { /* those were the only choices */
287+
err = -EINVAL;
288+
goto exit;
289+
@@ -1139,15 +1230,6 @@ static int optoe_probe(struct i2c_client *client,
290+
I2C_FUNC_SMBUS_WRITE_WORD_DATA) ||
291+
i2c_check_functionality(client->adapter,
292+
I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) {
293+
- /*
294+
- * NOTE: AN-2079
295+
- * Finisar recommends that the host implement 1 byte writes
296+
- * only since this module only supports 32 byte page boundaries.
297+
- * 2 byte writes are acceptable for PE and Vout changes per
298+
- * Application Note AN-2071.
299+
- */
300+
- unsigned int write_max = 1;
301+
-
302+
optoe->bin.write = optoe_bin_write;
303+
optoe->bin.attr.mode |= 0200;
304+
305+
--
306+
2.25.1
307+

patch/series

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ driver-support-optoe-twoaddr-a2h-access.patch
3434
driver-support-optoe-oneaddr-pageable.patch
3535
driver-support-optoe-update-to-linux-6.1.patch
3636
driver-support-optoe-dynamic-write-timeout.patch
37+
driver-support-optoe-bank-support.patch
3738
driver-net-tg3-add-param-short-preamble-and-reset.patch
3839
driver-net-tg3-change-dma-mask-for-57766.patch
3940
0004-dt-bindings-hwmon-Add-missing-documentation-for-lm75.patch

0 commit comments

Comments
 (0)