Skip to content

Commit aae983b

Browse files
SFP driver to perform EEPROM dump on AXI memory interface (#231)
NET:ETH:PHY: enabling SFP eeprom dump from AXI memory interface --------- Co-authored-by: Narayan, Preetam <[email protected]>
1 parent 9658d8b commit aae983b

File tree

4 files changed

+202
-23
lines changed

4 files changed

+202
-23
lines changed

arch/arm64/boot/dts/intel/socfpga_agilex5_eth_1p10g.dtsi

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,6 @@
6060
reg-names = "ptp_bridge";
6161
};
6262

63-
qsfp_eth0: qsfp-eth0 {
64-
compatible = "intel,qsfp-mem";
65-
reg-names = "qsfp-mem-ctrl";
66-
reg = <0x44040000 0x00001000>;
67-
status = "okay";
68-
};
69-
7063
sfp_eth0: sfp-eth0 {
7164
compatible = "altera,sfp-mem";
7265
reg-names = "sfp-mem-ctrl";
@@ -89,9 +82,6 @@
8982
interrupt-names = "dma0_tx_irq", "dma0_rx_irq";
9083
interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
9184
status = "okay";
92-
qsfp-lane = <0x0>;
93-
sfp-lane = <0x0>;
94-
qsfp = <&qsfp_eth0>;
9585
sfp = <&sfp_eth0>;
9686
fec-type="no-fec";
9787
phy-mode = "10gbase-r";

drivers/net/ethernet/altera/intel_fpga_gts_ethtool.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <linux/netdevice.h>
1818
#include <linux/phy.h>
1919
#include <linux/sfp.h>
20+
#include <linux/phy/sfp-mem.h>
2021
#include <linux/phylink.h>
2122
#include "altera_eth_dma.h"
2223
#include "intel_fpga_eth_main.h"
@@ -94,10 +95,16 @@ static void gts_gstrings(struct net_device *dev, u32 stringset, u8 *buf)
9495
memcpy(buf, stat_gstrings, GTS_STATS_LEN * ETH_GSTRING_LEN);
9596
}
9697

98+
static int gts_get_eeprom_len(struct net_device *dev)
99+
{
100+
return A0_EEPROM_SIZE;
101+
}
102+
97103
static int gts_get_module_info (struct net_device *dev,
98104
struct ethtool_modinfo *info)
99105
{
100106
intel_fpga_xtile_eth_private *priv = netdev_priv(dev);
107+
101108
if (!priv)
102109
return -ENODEV;
103110

@@ -112,6 +119,7 @@ static int gts_get_module_eeprom(struct net_device *dev,
112119
struct ethtool_eeprom *eeprom, u8 *data)
113120
{
114121
intel_fpga_xtile_eth_private *priv = netdev_priv(dev);
122+
115123
if (!priv)
116124
return -ENODEV;
117125

@@ -122,6 +130,21 @@ static int gts_get_module_eeprom(struct net_device *dev,
122130
return sfp_get_module_eeprom(priv->dev->sfp_bus, eeprom, data);
123131
}
124132

133+
static int gts_get_module_eeprom_by_page(struct net_device *dev,
134+
const struct ethtool_module_eeprom *page,
135+
struct netlink_ext_ack *extack)
136+
{
137+
intel_fpga_xtile_eth_private *priv = netdev_priv(dev);
138+
139+
if (!priv)
140+
return -ENODEV;
141+
142+
if (!priv->phylink || !priv->dev || !priv->dev->sfp_bus) {
143+
return -ENODEV;
144+
}
145+
return sfp_get_module_eeprom_by_page(priv->dev->sfp_bus, page, extack);
146+
}
147+
125148
static void gts_fill_stats(struct net_device *dev,
126149
struct ethtool_stats *dummy,
127150
u64 *buf)
@@ -1690,7 +1713,10 @@ static const struct ethtool_ops gts_ethtool_ops = {
16901713
.get_link_ksettings = gts_get_link_ksettings,
16911714
.set_link_ksettings = gts_set_link_ksettings,
16921715
.get_module_info = gts_get_module_info,
1716+
.get_eeprom = gts_get_module_eeprom,
1717+
.get_eeprom_len = gts_get_eeprom_len,
16931718
.get_module_eeprom = gts_get_module_eeprom,
1719+
.get_module_eeprom_by_page = gts_get_module_eeprom_by_page,
16941720

16951721
};
16961722

drivers/net/phy/sfp-mem-core.c

Lines changed: 140 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
#include <linux/regmap.h>
1616
#include <linux/uaccess.h>
1717
#include <linux/phy/sfp-mem.h>
18+
#include <linux/sfp.h>
19+
#include <linux/ethtool.h>
1820

1921
#define CONF_OFF 0x20
2022
#define CONF_RST_CON BIT(1)
@@ -87,8 +89,8 @@
8789
#define MULTI_PAGE_SEL 0x40
8890
#define A0_END_ADDR 0x880
8991

90-
#define MODE_SEL BIT(11)
91-
#define PAGE_SEL BIT(1)
92+
#define MODE_SEL BIT(2)
93+
#define PAGE_SEL BIT(11)
9294
#define A2_START_ADDR 0x100
9395
#define A2_END_ADDR 0x700
9496

@@ -306,15 +308,6 @@ static void sfp_check_hotplug(struct work_struct *work)
306308
schedule_delayed_work(&sfp->dwork, msecs_to_jiffies(SFP_CHECK_TIME));
307309
}
308310

309-
int sfp_init_work(struct sfp *sfp)
310-
{
311-
sfp->init = SFP_INIT_RESET;
312-
313-
INIT_DELAYED_WORK(&sfp->dwork, sfp_check_hotplug);
314-
schedule_delayed_work(&sfp->dwork, msecs_to_jiffies(SFP_CHECK_TIME));
315-
return 0;
316-
}
317-
EXPORT_SYMBOL_GPL(sfp_init_work);
318311

319312
int sfp_register_regmap(struct sfp *sfp)
320313
{
@@ -333,4 +326,140 @@ void sfp_remove_device(struct sfp *sfp)
333326
cancel_delayed_work_sync(&sfp->dwork);
334327
}
335328
EXPORT_SYMBOL_GPL(sfp_remove_device);
329+
330+
/* copy the A0, A2 page content */
331+
static void sfp_page_copy(struct sfp *sfp)
332+
{
333+
u32 *page;
334+
335+
page = (u32*)sfp->a0_page.a0_page;
336+
for(u16 update_eeprom = 0, pg_byte = 0;
337+
update_eeprom < sizeof(sfp->a0_page); pg_byte += 1, update_eeprom += 4)
338+
page[pg_byte] =
339+
readl(sfp->base + A0_START_ADDR + update_eeprom);
340+
341+
page = (u32*)sfp->a2_page.a2_page;
342+
for(u16 update_eeprom = 0, pg_byte = 0;
343+
update_eeprom < sizeof(sfp->a2_page); pg_byte += 1, update_eeprom += 4)
344+
page[pg_byte] =
345+
readl(sfp->base + A2_START_ADDR + update_eeprom);
346+
}
347+
348+
static int sfp_module_info(struct sfp *sfp, struct ethtool_modinfo *modinfo)
349+
{
350+
/* Atleast A0 page update is completed */
351+
if (!(sfp->init >= SFP_A0PAGE_UPDATE_COMPLETE))
352+
return -EIO;
353+
354+
sfp_page_copy(sfp);
355+
356+
if ((sfp->a0_page.a0.ext.sff8472_compliance) &&
357+
(!((sfp->a0_page.a0.ext.diagmon) & SFP_DIAGMON_ADDRMODE))) {
358+
modinfo->type = ETH_MODULE_SFF_8472;
359+
//modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
360+
modinfo->eeprom_len = A0_EEPROM_SIZE + A2_EEPROM_SIZE;
361+
} else {
362+
modinfo->type = ETH_MODULE_SFF_8079;
363+
modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
364+
}
365+
366+
return 0;
367+
}
368+
369+
static int sfp_module_eeprom_calc(struct sfp *sfp,
370+
u16 offset,
371+
u16 len_dump,
372+
u8 *data)
373+
{
374+
u16 from_offset = offset;
375+
u16 til_offset = offset + len_dump;
376+
377+
if ( (len_dump == 0) || (til_offset > sizeof(sfp->a0_page) + sizeof(sfp->a2_page)) )
378+
return -EINVAL;
379+
380+
/* offset is within A0 page size */
381+
if (til_offset <= ETH_MODULE_SFF_8079_LEN) {
382+
/* copy from the offset the desired length */
383+
memcpy(data, (u8*)sfp->a0_page.a0_page + from_offset, len_dump);
384+
}
385+
386+
/* offset requested is on A2 page range */
387+
else if ((from_offset >= ETH_MODULE_SFF_8079_LEN) && (til_offset <= A2_EEPROM_SIZE)) {
388+
memcpy(data,
389+
(u8*)sfp->a2_page.a2_page + from_offset,
390+
len_dump);
391+
}
392+
else {
393+
/* requested dump covers both A0 and A2 */
394+
u16 len;
395+
396+
len = ETH_MODULE_SFF_8079_LEN - from_offset;
397+
memcpy (data,
398+
(u8*)sfp->a0_page.a0_page + from_offset,
399+
len);
400+
401+
memcpy(data + len + 1, (u8*)sfp->a2_page.a2_page, len_dump - len);
402+
}
403+
404+
return 0;
405+
}
406+
407+
static int sfp_module_eeprom(struct sfp *sfp,
408+
struct ethtool_eeprom *ee,
409+
u8 *data)
410+
{
411+
sfp_page_copy(sfp);
412+
413+
return sfp_module_eeprom_calc(sfp, ee->offset, ee->len, data);
414+
}
415+
416+
static int sfp_module_eeprom_by_page(struct sfp *sfp,
417+
const struct ethtool_module_eeprom *page_data,
418+
struct netlink_ext_ack *extack)
419+
{
420+
int ret = 0;
421+
u16 abs_offset;
422+
423+
if ((page_data->page == 0) && (page_data->length == 1))
424+
return 0;
425+
426+
abs_offset = (page_data->page * ETH_MODULE_EEPROM_PAGE_LEN) + page_data->offset;
427+
428+
if (abs_offset > ETH_MODULE_EEPROM_PAGE_LEN)
429+
return -EINVAL;
430+
431+
ret = sfp_module_eeprom_calc(sfp, page_data->offset,
432+
page_data->length, page_data->data);
433+
434+
return ret;
435+
}
436+
437+
static void unused_func(struct sfp *sfp)
438+
{
439+
return;
440+
}
441+
442+
static const struct sfp_socket_ops sfp_module_ops = {
443+
.start = unused_func,
444+
.stop = unused_func,
445+
.attach = unused_func,
446+
.module_info = sfp_module_info,
447+
.module_eeprom = sfp_module_eeprom,
448+
.module_eeprom_by_page = sfp_module_eeprom_by_page,
449+
};
450+
451+
int sfp_init_work(struct sfp *sfp)
452+
{
453+
sfp->init = SFP_INIT_RESET;
454+
455+
sfp->sfp_bus = sfp_register_socket(sfp->dev, sfp, &sfp_module_ops);
456+
if (!sfp->sfp_bus)
457+
return -ENOMEM;
458+
459+
INIT_DELAYED_WORK(&sfp->dwork, sfp_check_hotplug);
460+
schedule_delayed_work(&sfp->dwork, msecs_to_jiffies(SFP_CHECK_TIME));
461+
return 0;
462+
}
463+
EXPORT_SYMBOL_GPL(sfp_init_work);
464+
336465
MODULE_LICENSE("GPL");

include/linux/phy/sfp-mem.h

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@
1717
#include <linux/netdevice.h>
1818
#include <linux/regmap.h>
1919
#include <linux/uaccess.h>
20+
#include <linux/sfp.h>
21+
22+
#define IP_IRRESPONSIVE 0
23+
#define IP_RESPONSE_TOLERANCE_LIMIT 100
24+
25+
#define A0_EEPROM_SIZE (ETH_MODULE_SFF_8472_LEN/2)
26+
#define IMPLEMENTED_A2PAGES 4 /* changing this macro enables to dump A2 multiple pages */
27+
#define A2_EEPROM_SIZE (ETH_MODULE_SFF_8472_LEN/2) * IMPLEMENTED_A2PAGES
2028

2129
enum sfp_init_status {
2230
SFP_INIT_RESET = 0,
@@ -29,6 +37,15 @@ enum sfp_init_status {
2937
SFP_A2_UPDATE_ERROR,
3038
};
3139

40+
union sfp_a2_page {
41+
u8 a2_page[A2_EEPROM_SIZE];
42+
};
43+
44+
union sfp_a0_page {
45+
u8 a0_page[A0_EEPROM_SIZE];
46+
struct sfp_eeprom_id a0;
47+
};
48+
3249
/**
3350
* struct sfp - device private data structure
3451
* @base: base address of the device.
@@ -46,6 +63,9 @@ struct sfp {
4663
enum sfp_init_status init;
4764
struct mutex lock;
4865
u32 tolerance_count;
66+
struct sfp_bus *sfp_bus;
67+
union sfp_a0_page a0_page;
68+
union sfp_a2_page a2_page;
4969
};
5070

5171
int sfp_init_work(struct sfp *qsfp);
@@ -54,7 +74,21 @@ void sfp_remove_device(struct sfp *qsfp);
5474
bool check_sfp_plugin(struct sfp *qsfp);
5575
extern const struct attribute_group *sfp_mem_groups[];
5676

57-
#define IP_IRRESPONSIVE 0
58-
#define IP_RESPONSE_TOLERANCE_LIMIT 100
77+
struct sfp_socket_ops {
78+
void (*attach)(struct sfp *sfp);
79+
void (*detach)(struct sfp *sfp);
80+
void (*start)(struct sfp *sfp);
81+
void (*stop)(struct sfp *sfp);
82+
void (*set_signal_rate)(struct sfp *sfp, unsigned int rate_kbd);
83+
int (*module_info)(struct sfp *sfp, struct ethtool_modinfo *modinfo);
84+
int (*module_eeprom)(struct sfp *sfp, struct ethtool_eeprom *ee,
85+
u8 *data);
86+
int (*module_eeprom_by_page)(struct sfp *sfp,
87+
const struct ethtool_module_eeprom *page,
88+
struct netlink_ext_ack *extack);
89+
};
90+
91+
struct sfp_bus *sfp_register_socket(struct device *dev, struct sfp *sfp,
92+
const struct sfp_socket_ops *ops);
5993

6094
#endif //__LINUX_SFP_MEM_H

0 commit comments

Comments
 (0)