Skip to content

Commit 4f10614

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

File tree

2 files changed

+281
-0
lines changed

2 files changed

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

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)