Skip to content

Commit 28fa045

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

File tree

2 files changed

+278
-0
lines changed

2 files changed

+278
-0
lines changed
Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,277 @@
1+
From 3a34a141d5882a15a81603b65d697cdc68867ee6 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 | 124 ++++++++++++++++++++++++++++++------
17+
1 file changed, 103 insertions(+), 21 deletions(-)
18+
19+
diff --git a/drivers/misc/eeprom/optoe.c b/drivers/misc/eeprom/optoe.c
20+
index 22d2c0cd4..71bd90204 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 0
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+
@@ -553,13 +585,18 @@ static ssize_t optoe_eeprom_update_client(struct optoe_data *optoe,
142+
143+
144+
if (page > 0) {
145+
- /* return the page register to page 0 (why?) */
146+
- page = 0;
147+
- ret = optoe_eeprom_write(optoe, client, &page,
148+
- OPTOE_PAGE_SELECT_REG, 1);
149+
+ if (bank > 0) {
150+
+ char buf[2] = {0, 0};
151+
+ ret = optoe_eeprom_write(optoe, client, buf,
152+
+ OPTOE_BANK_SELECT_REG, 2);
153+
+ } else {
154+
+ page = 0;
155+
+ ret = optoe_eeprom_write(optoe, client, &page,
156+
+ OPTOE_PAGE_SELECT_REG, 1);
157+
+ }
158+
if (ret < 0) {
159+
dev_err(&client->dev,
160+
- "Restore page register to 0 failed:%d!\n", ret);
161+
+ "Restore bank, page register to (0, 0) failed:%d!\n", ret);
162+
/* error only if nothing has been transferred */
163+
if (retval == 0)
164+
retval = ret;
165+
@@ -622,8 +659,10 @@ static ssize_t optoe_page_legal(struct optoe_data *optoe,
166+
/* if no pages needed, we're good */
167+
if ((off + len) <= ONE_ADDR_EEPROM_UNPAGED_SIZE)
168+
return len;
169+
+
170+
+ maxlen = one_addr_eeprom_size_with_bank(optoe->bank_size);
171+
/* if offset exceeds possible pages, we're not good */
172+
- if (off >= ONE_ADDR_EEPROM_SIZE)
173+
+ if (off >= maxlen)
174+
return OPTOE_EOF;
175+
/* in between, are pages supported? */
176+
status = optoe_eeprom_read(optoe, client, &regval,
177+
@@ -665,7 +704,7 @@ static ssize_t optoe_page_legal(struct optoe_data *optoe,
178+
maxlen = ONE_ADDR_EEPROM_UNPAGED_SIZE - off;
179+
} else {
180+
/* Pages supported, trim len to the end of pages */
181+
- maxlen = ONE_ADDR_EEPROM_SIZE - off;
182+
+ maxlen = maxlen - off;
183+
}
184+
len = (len > maxlen) ? maxlen : len;
185+
dev_dbg(&client->dev,
186+
@@ -995,6 +1034,47 @@ static ssize_t set_port_name(struct device *dev,
187+
return count;
188+
}
189+
190+
+static ssize_t show_bank_size(struct device *dev,
191+
+ struct device_attribute *dattr, char *buf)
192+
+{
193+
+ struct i2c_client *client = to_i2c_client(dev);
194+
+ struct optoe_data *optoe = i2c_get_clientdata(client);
195+
+ ssize_t count;
196+
+
197+
+ mutex_lock(&optoe->lock);
198+
+ count = sprintf(buf, "%u\n", optoe->bank_size);
199+
+ mutex_unlock(&optoe->lock);
200+
+
201+
+ return count;
202+
+}
203+
+
204+
+static ssize_t set_bank_size(struct device *dev,
205+
+ struct device_attribute *attr,
206+
+ const char *buf, size_t count)
207+
+{
208+
+ struct i2c_client *client = to_i2c_client(dev);
209+
+ struct optoe_data *optoe = i2c_get_clientdata(client);
210+
+ unsigned int bank_size;
211+
+
212+
+ // setting bank size is only supported for the CMIS device
213+
+ if (optoe->dev_class != CMIS_ADDR) {
214+
+ return -EINVAL;
215+
+ }
216+
+
217+
+ if (kstrtouint(buf, 0, &bank_size) != 0 ||
218+
+ bank_size < 0 || bank_size > OPTOE_MAX_SUPPORTED_BANK_SIZE)
219+
+ return -EINVAL;
220+
+
221+
+ mutex_lock(&optoe->lock);
222+
+ optoe->bank_size = bank_size;
223+
+ if (optoe->bank_size > 0 && optoe->write_max == 1) {
224+
+ optoe->write_max = 2;
225+
+ }
226+
+ mutex_unlock(&optoe->lock);
227+
+
228+
+ return count;
229+
+}
230+
+
231+
static DEVICE_ATTR(port_name, 0644, show_port_name, set_port_name);
232+
#endif /* if NOT defined EEPROM_CLASS, the common case */
233+
234+
@@ -1003,6 +1083,7 @@ static DEVICE_ATTR(write_timeout, 0644, show_dev_write_timeout_size,
235+
static DEVICE_ATTR(write_max, 0644, show_dev_write_max_size,
236+
set_dev_write_max_size);
237+
static DEVICE_ATTR(dev_class, 0644, show_dev_class, set_dev_class);
238+
+static DEVICE_ATTR(bank_size, 0644, show_bank_size, set_bank_size);
239+
240+
static struct attribute *optoe_attrs[] = {
241+
#ifndef EEPROM_CLASS
242+
@@ -1011,6 +1092,7 @@ static struct attribute *optoe_attrs[] = {
243+
&dev_attr_write_timeout.attr,
244+
&dev_attr_write_max.attr,
245+
&dev_attr_dev_class.attr,
246+
+ &dev_attr_bank_size.attr,
247+
NULL,
248+
};
249+
250+
@@ -1027,7 +1109,6 @@ static int optoe_probe(struct i2c_client *client,
251+
struct optoe_data *optoe;
252+
int num_addresses = 0;
253+
char port_name[MAX_PORT_NAME_LEN];
254+
-
255+
if (client->addr != 0x50) {
256+
dev_dbg(&client->dev, "probe, bad i2c addr: 0x%x\n",
257+
client->addr);
258+
@@ -1108,7 +1189,7 @@ static int optoe_probe(struct i2c_client *client,
259+
} else if (strcmp(client->name, "optoe3") == 0) {
260+
/* CMIS spec */
261+
optoe->dev_class = CMIS_ADDR;
262+
- chip.byte_len = ONE_ADDR_EEPROM_SIZE;
263+
+ chip.byte_len = one_addr_eeprom_size_with_bank(OPTOE_MAX_SUPPORTED_BANK_SIZE);
264+
num_addresses = 1;
265+
} else { /* those were the only choices */
266+
err = -EINVAL;
267+
@@ -1120,6 +1201,7 @@ static int optoe_probe(struct i2c_client *client,
268+
optoe->chip = chip;
269+
optoe->num_addresses = num_addresses;
270+
optoe->write_timeout = OPTOE_DEFAULT_WRITE_TIMEOUT;
271+
+ optoe->bank_size = OPTOE_DEFAULT_BANK_SIZE;
272+
memcpy(optoe->port_name, port_name, MAX_PORT_NAME_LEN);
273+
274+
/*
275+
--
276+
2.25.1
277+

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)