* [PATCH net-next v3 0/8] TXGBE PHYLINK support
@ 2023-04-19 8:27 Jiawen Wu
2023-04-19 8:27 ` [PATCH net-next v3 1/8] net: txgbe: Add software nodes to support phylink Jiawen Wu
` (8 more replies)
0 siblings, 9 replies; 28+ messages in thread
From: Jiawen Wu @ 2023-04-19 8:27 UTC (permalink / raw)
To: netdev, linux; +Cc: linux-i2c, linux-gpio, olteanv, mengyuanlou, Jiawen Wu
Implement I2C, SFP, GPIO and PHYLINK to setup TXGBE link and switch link
rate based on optical module information.
Because our I2C and PCS are based on Synopsys Designware IP-core, extend
the i2c-designware and pcs-xpcs driver to realize our functions.
v2 -> v3:
- delete own I2C bus master driver, support it in i2c-designware
- delete own PCS functions, remove pma configuration and 1000BASE-X mode
- add basic function for 10GBASE-R interface in pcs-xpcs
- add helper to get txgbe pointer from netdev
v1 -> v2:
- add comments to indicate GPIO lines
- add I2C write operation support
- modify GPIO direction functions
- rename functions related to PHY interface
- add condition on interface changing to re-config PCS
- add to set advertise and fix to get status for 1000BASE-X mode
- other redundant codes remove
Jiawen Wu (8):
net: txgbe: Add software nodes to support phylink
i2c: designware: Add driver support for Wangxun 10Gb NIC
net: txgbe: Register I2C platform device
net: txgbe: Add SFP module identify
net: txgbe: Support GPIO to SFP socket
net: pcs: Add 10GBASE-R mode for Synopsys Designware XPCS
net: txgbe: Implement phylink pcs
net: txgbe: Support phylink MAC layer
drivers/i2c/busses/i2c-designware-common.c | 4 +
drivers/i2c/busses/i2c-designware-core.h | 1 +
drivers/i2c/busses/i2c-designware-master.c | 91 ++-
drivers/i2c/busses/i2c-designware-platdrv.c | 36 +-
drivers/net/ethernet/wangxun/Kconfig | 6 +
drivers/net/ethernet/wangxun/libwx/wx_lib.c | 3 +-
drivers/net/ethernet/wangxun/libwx/wx_type.h | 3 +
drivers/net/ethernet/wangxun/txgbe/Makefile | 1 +
.../ethernet/wangxun/txgbe/txgbe_ethtool.c | 28 +
.../net/ethernet/wangxun/txgbe/txgbe_main.c | 63 +-
.../net/ethernet/wangxun/txgbe/txgbe_phy.c | 585 ++++++++++++++++++
.../net/ethernet/wangxun/txgbe/txgbe_phy.h | 10 +
.../net/ethernet/wangxun/txgbe/txgbe_type.h | 92 +++
drivers/net/pcs/pcs-xpcs.c | 58 ++
include/linux/pcs/pcs-xpcs.h | 1 +
include/linux/platform_data/i2c-dw.h | 15 +
16 files changed, 960 insertions(+), 37 deletions(-)
create mode 100644 drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
create mode 100644 drivers/net/ethernet/wangxun/txgbe/txgbe_phy.h
create mode 100644 include/linux/platform_data/i2c-dw.h
--
2.27.0
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH net-next v3 1/8] net: txgbe: Add software nodes to support phylink
2023-04-19 8:27 [PATCH net-next v3 0/8] TXGBE PHYLINK support Jiawen Wu
@ 2023-04-19 8:27 ` Jiawen Wu
2023-04-19 20:53 ` Andrew Lunn
2023-04-19 8:27 ` [PATCH net-next v3 2/8] i2c: designware: Add driver support for Wangxun 10Gb NIC Jiawen Wu
` (7 subsequent siblings)
8 siblings, 1 reply; 28+ messages in thread
From: Jiawen Wu @ 2023-04-19 8:27 UTC (permalink / raw)
To: netdev, linux; +Cc: linux-i2c, linux-gpio, olteanv, mengyuanlou, Jiawen Wu
Register software nodes for GPIO, I2C, SFP and PHYLINK. Define the
device properties.
Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
---
drivers/net/ethernet/wangxun/libwx/wx_type.h | 1 +
drivers/net/ethernet/wangxun/txgbe/Makefile | 1 +
.../net/ethernet/wangxun/txgbe/txgbe_main.c | 20 ++++-
.../net/ethernet/wangxun/txgbe/txgbe_phy.c | 88 +++++++++++++++++++
.../net/ethernet/wangxun/txgbe/txgbe_phy.h | 10 +++
.../net/ethernet/wangxun/txgbe/txgbe_type.h | 49 +++++++++++
6 files changed, 168 insertions(+), 1 deletion(-)
create mode 100644 drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
create mode 100644 drivers/net/ethernet/wangxun/txgbe/txgbe_phy.h
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h
index 32f952d93009..97bce855bc60 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_type.h
+++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h
@@ -611,6 +611,7 @@ enum wx_isb_idx {
struct wx {
u8 __iomem *hw_addr;
+ void *priv;
struct pci_dev *pdev;
struct net_device *netdev;
struct wx_bus_info bus;
diff --git a/drivers/net/ethernet/wangxun/txgbe/Makefile b/drivers/net/ethernet/wangxun/txgbe/Makefile
index 6db14a2cb2d0..7507f762edfe 100644
--- a/drivers/net/ethernet/wangxun/txgbe/Makefile
+++ b/drivers/net/ethernet/wangxun/txgbe/Makefile
@@ -8,4 +8,5 @@ obj-$(CONFIG_TXGBE) += txgbe.o
txgbe-objs := txgbe_main.o \
txgbe_hw.o \
+ txgbe_phy.o \
txgbe_ethtool.o
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
index 5b8a121fb496..dbd4d409d93b 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
@@ -15,6 +15,7 @@
#include "../libwx/wx_hw.h"
#include "txgbe_type.h"
#include "txgbe_hw.h"
+#include "txgbe_phy.h"
#include "txgbe_ethtool.h"
char txgbe_driver_name[] = "txgbe";
@@ -513,6 +514,7 @@ static int txgbe_probe(struct pci_dev *pdev,
struct net_device *netdev;
int err, expected_gts;
struct wx *wx = NULL;
+ struct txgbe *txgbe;
u16 eeprom_verh = 0, eeprom_verl = 0, offset = 0;
u16 eeprom_cfg_blkh = 0, eeprom_cfg_blkl = 0;
@@ -663,10 +665,21 @@ static int txgbe_probe(struct pci_dev *pdev,
"0x%08x", etrack_id);
}
- err = register_netdev(netdev);
+ txgbe = devm_kzalloc(&pdev->dev, sizeof(*txgbe), GFP_KERNEL);
+ if (!txgbe)
+ return -ENOMEM;
+
+ txgbe->wx = wx;
+ wx->priv = txgbe;
+
+ err = txgbe_init_phy(txgbe);
if (err)
goto err_release_hw;
+ err = register_netdev(netdev);
+ if (err)
+ goto err_remove_phy;
+
pci_set_drvdata(pdev, wx);
netif_tx_stop_all_queues(netdev);
@@ -694,6 +707,8 @@ static int txgbe_probe(struct pci_dev *pdev,
return 0;
+err_remove_phy:
+ txgbe_remove_phy(txgbe);
err_release_hw:
wx_clear_interrupt_scheme(wx);
wx_control_hw(wx, false);
@@ -719,11 +734,14 @@ static int txgbe_probe(struct pci_dev *pdev,
static void txgbe_remove(struct pci_dev *pdev)
{
struct wx *wx = pci_get_drvdata(pdev);
+ struct txgbe *txgbe = wx->priv;
struct net_device *netdev;
netdev = wx->netdev;
unregister_netdev(netdev);
+ txgbe_remove_phy(txgbe);
+
pci_release_selected_regions(pdev,
pci_select_bars(pdev, IORESOURCE_MEM));
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
new file mode 100644
index 000000000000..39762c7fc851
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2015 - 2023 Beijing WangXun Technology Co., Ltd. */
+
+#include <linux/gpio/property.h>
+#include <linux/i2c.h>
+#include <linux/pci.h>
+
+#include "../libwx/wx_type.h"
+#include "txgbe_type.h"
+#include "txgbe_phy.h"
+
+static int txgbe_swnodes_register(struct txgbe *txgbe)
+{
+ struct txgbe_nodes *nodes = &txgbe->nodes;
+ struct pci_dev *pdev = txgbe->wx->pdev;
+ struct software_node *swnodes;
+ u32 id;
+
+ id = (pdev->bus->number << 8) | pdev->devfn;
+
+ snprintf(nodes->gpio_name, sizeof(nodes->gpio_name), "txgbe_gpio-%x", id);
+ snprintf(nodes->i2c_name, sizeof(nodes->i2c_name), "txgbe_i2c-%x", id);
+ snprintf(nodes->sfp_name, sizeof(nodes->sfp_name), "txgbe_sfp-%x", id);
+ snprintf(nodes->phylink_name, sizeof(nodes->phylink_name), "txgbe_phylink-%x", id);
+
+ swnodes = nodes->swnodes;
+
+ /* GPIO 0: tx fault
+ * GPIO 1: tx disable
+ * GPIO 2: sfp module absent
+ * GPIO 3: rx signal lost
+ * GPIO 4: rate select, 1G(0) 10G(1)
+ * GPIO 5: rate select, 1G(0) 10G(1)
+ */
+ nodes->gpio_props[0] = PROPERTY_ENTRY_STRING("pinctrl-names", "default");
+ swnodes[SWNODE_GPIO] = NODE_PROP(nodes->gpio_name, nodes->gpio_props);
+ nodes->gpio0_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_GPIO], 0, GPIO_ACTIVE_HIGH);
+ nodes->gpio1_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_GPIO], 1, GPIO_ACTIVE_HIGH);
+ nodes->gpio2_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_GPIO], 2, GPIO_ACTIVE_LOW);
+ nodes->gpio3_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_GPIO], 3, GPIO_ACTIVE_HIGH);
+ nodes->gpio4_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_GPIO], 4, GPIO_ACTIVE_HIGH);
+ nodes->gpio5_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_GPIO], 5, GPIO_ACTIVE_HIGH);
+
+ nodes->i2c_props[0] = PROPERTY_ENTRY_STRING("compatible", "snps,designware-i2c");
+ nodes->i2c_props[1] = PROPERTY_ENTRY_U32("clock-frequency", I2C_MAX_STANDARD_MODE_FREQ);
+ swnodes[SWNODE_I2C] = NODE_PROP(nodes->i2c_name, nodes->i2c_props);
+ nodes->i2c_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_I2C]);
+
+ nodes->sfp_props[0] = PROPERTY_ENTRY_STRING("compatible", "sff,sfp");
+ nodes->sfp_props[1] = PROPERTY_ENTRY_REF_ARRAY("i2c-bus", nodes->i2c_ref);
+ nodes->sfp_props[2] = PROPERTY_ENTRY_REF_ARRAY("tx-fault-gpios", nodes->gpio0_ref);
+ nodes->sfp_props[3] = PROPERTY_ENTRY_REF_ARRAY("tx-disable-gpios", nodes->gpio1_ref);
+ nodes->sfp_props[4] = PROPERTY_ENTRY_REF_ARRAY("mod-def0-gpios", nodes->gpio2_ref);
+ nodes->sfp_props[5] = PROPERTY_ENTRY_REF_ARRAY("los-gpios", nodes->gpio3_ref);
+ nodes->sfp_props[6] = PROPERTY_ENTRY_REF_ARRAY("rate-select1-gpios", nodes->gpio4_ref);
+ nodes->sfp_props[7] = PROPERTY_ENTRY_REF_ARRAY("rate-select0-gpios", nodes->gpio5_ref);
+ swnodes[SWNODE_SFP] = NODE_PROP(nodes->sfp_name, nodes->sfp_props);
+ nodes->sfp_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_SFP]);
+
+ nodes->phylink_props[0] = PROPERTY_ENTRY_STRING("managed", "in-band-status");
+ nodes->phylink_props[1] = PROPERTY_ENTRY_REF_ARRAY("sfp", nodes->sfp_ref);
+ swnodes[SWNODE_PHYLINK] = NODE_PROP(nodes->phylink_name, nodes->phylink_props);
+
+ nodes->group[SWNODE_GPIO] = &swnodes[SWNODE_GPIO];
+ nodes->group[SWNODE_I2C] = &swnodes[SWNODE_I2C];
+ nodes->group[SWNODE_SFP] = &swnodes[SWNODE_SFP];
+ nodes->group[SWNODE_PHYLINK] = &swnodes[SWNODE_PHYLINK];
+
+ return software_node_register_node_group(nodes->group);
+}
+
+int txgbe_init_phy(struct txgbe *txgbe)
+{
+ int ret;
+
+ ret = txgbe_swnodes_register(txgbe);
+ if (ret) {
+ wx_err(txgbe->wx, "failed to register software nodes\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+void txgbe_remove_phy(struct txgbe *txgbe)
+{
+ software_node_unregister_node_group(txgbe->nodes.group);
+}
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.h
new file mode 100644
index 000000000000..1ab592124986
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2015 - 2023 Beijing WangXun Technology Co., Ltd. */
+
+#ifndef _TXGBE_PHY_H_
+#define _TXGBE_PHY_H_
+
+int txgbe_init_phy(struct txgbe *txgbe);
+void txgbe_remove_phy(struct txgbe *txgbe);
+
+#endif /* _TXGBE_NODE_H_ */
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
index 63a1c733718d..51bbecb28433 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
@@ -4,6 +4,8 @@
#ifndef _TXGBE_TYPE_H_
#define _TXGBE_TYPE_H_
+#include <linux/property.h>
+
/* Device IDs */
#define TXGBE_DEV_ID_SP1000 0x1001
#define TXGBE_DEV_ID_WX1820 0x2001
@@ -99,4 +101,51 @@
extern char txgbe_driver_name[];
+static inline struct txgbe *netdev_to_txgbe(struct net_device *netdev)
+{
+ struct wx *wx = netdev_priv(netdev);
+
+ return wx->priv;
+}
+
+#define NODE_PROP(_NAME, _PROP) \
+ (const struct software_node) { \
+ .name = _NAME, \
+ .properties = _PROP, \
+ }
+
+enum txgbe_swnodes {
+ SWNODE_GPIO = 0,
+ SWNODE_I2C,
+ SWNODE_SFP,
+ SWNODE_PHYLINK,
+ SWNODE_MAX
+};
+
+struct txgbe_nodes {
+ char gpio_name[32];
+ char i2c_name[32];
+ char sfp_name[32];
+ char phylink_name[32];
+ struct property_entry gpio_props[1];
+ struct property_entry i2c_props[2];
+ struct property_entry sfp_props[8];
+ struct property_entry phylink_props[2];
+ struct software_node_ref_args i2c_ref[1];
+ struct software_node_ref_args gpio0_ref[1];
+ struct software_node_ref_args gpio1_ref[1];
+ struct software_node_ref_args gpio2_ref[1];
+ struct software_node_ref_args gpio3_ref[1];
+ struct software_node_ref_args gpio4_ref[1];
+ struct software_node_ref_args gpio5_ref[1];
+ struct software_node_ref_args sfp_ref[1];
+ struct software_node swnodes[SWNODE_MAX];
+ const struct software_node *group[SWNODE_MAX + 1];
+};
+
+struct txgbe {
+ struct wx *wx;
+ struct txgbe_nodes nodes;
+};
+
#endif /* _TXGBE_TYPE_H_ */
--
2.27.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH net-next v3 2/8] i2c: designware: Add driver support for Wangxun 10Gb NIC
2023-04-19 8:27 [PATCH net-next v3 0/8] TXGBE PHYLINK support Jiawen Wu
2023-04-19 8:27 ` [PATCH net-next v3 1/8] net: txgbe: Add software nodes to support phylink Jiawen Wu
@ 2023-04-19 8:27 ` Jiawen Wu
2023-04-19 14:36 ` Jarkko Nikula
2023-04-19 20:58 ` Andrew Lunn
2023-04-19 8:27 ` [PATCH net-next v3 3/8] net: txgbe: Register I2C platform device Jiawen Wu
` (6 subsequent siblings)
8 siblings, 2 replies; 28+ messages in thread
From: Jiawen Wu @ 2023-04-19 8:27 UTC (permalink / raw)
To: netdev, linux
Cc: linux-i2c, linux-gpio, olteanv, mengyuanlou, Jiawen Wu,
Jarkko Nikula
Wangxun 10Gb ethernet chip is connected to Designware I2C, to communicate
with SFP.
Add platform data to pass IOMEM base address, board flag and other
parameters, since resource address was mapped on ethernet driver.
The exists IP limitations are dealt as workarounds:
- IP does not support interrupt mode, it works on polling mode.
- I2C cannot read continuously, only one byte can at a time.
- Additionally set FIFO depth address the chip issue.
Cc: Jarkko Nikula <jarkko.nikula@linux.intel.com>
Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
---
drivers/i2c/busses/i2c-designware-common.c | 4 +
drivers/i2c/busses/i2c-designware-core.h | 1 +
drivers/i2c/busses/i2c-designware-master.c | 91 ++++++++++++++++++++-
drivers/i2c/busses/i2c-designware-platdrv.c | 36 +++++++-
include/linux/platform_data/i2c-dw.h | 15 ++++
5 files changed, 143 insertions(+), 4 deletions(-)
create mode 100644 include/linux/platform_data/i2c-dw.h
diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c
index 0dc6b1ce663f..e4faab4655cb 100644
--- a/drivers/i2c/busses/i2c-designware-common.c
+++ b/drivers/i2c/busses/i2c-designware-common.c
@@ -588,6 +588,10 @@ int i2c_dw_set_fifo_size(struct dw_i2c_dev *dev)
if (ret)
return ret;
+ /* workaround for IP hardware issue */
+ if ((dev->flags & MODEL_MASK) == MODEL_WANGXUN_SP)
+ param |= 0x80800;
+
tx_fifo_depth = ((param >> 16) & 0xff) + 1;
rx_fifo_depth = ((param >> 8) & 0xff) + 1;
if (!dev->tx_fifo_depth) {
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index 050d8c63ad3c..c686198e12d2 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -303,6 +303,7 @@ struct dw_i2c_dev {
#define MODEL_MSCC_OCELOT BIT(8)
#define MODEL_BAIKAL_BT1 BIT(9)
#define MODEL_AMD_NAVI_GPU BIT(10)
+#define MODEL_WANGXUN_SP BIT(11)
#define MODEL_MASK GENMASK(11, 8)
/*
diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c
index 55ea91a63382..21e350203247 100644
--- a/drivers/i2c/busses/i2c-designware-master.c
+++ b/drivers/i2c/busses/i2c-designware-master.c
@@ -354,6 +354,75 @@ static int amd_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msgs,
return 0;
}
+static int i2c_dw_poll_tx_empty(struct dw_i2c_dev *dev)
+{
+ u32 val;
+
+ return regmap_read_poll_timeout(dev->map, DW_IC_RAW_INTR_STAT, val,
+ val & DW_IC_INTR_TX_EMPTY,
+ 100, 1000);
+}
+
+static int i2c_dw_poll_rx_full(struct dw_i2c_dev *dev)
+{
+ u32 val;
+
+ return regmap_read_poll_timeout(dev->map, DW_IC_RAW_INTR_STAT, val,
+ val & DW_IC_INTR_RX_FULL,
+ 100, 1000);
+}
+
+static int txgbe_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msgs,
+ int num_msgs)
+{
+ struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
+ int msg_idx, buf_len, data_idx, ret;
+ unsigned int val;
+ u8 dev_addr;
+ u8 *buf;
+
+ dev->msgs = msgs;
+ dev->msgs_num = num_msgs;
+ i2c_dw_xfer_init(dev);
+ regmap_write(dev->map, DW_IC_INTR_MASK, 0);
+
+ dev_addr = msgs[0].buf[0];
+
+ for (msg_idx = 0; msg_idx < num_msgs; msg_idx++) {
+ buf = msgs[msg_idx].buf;
+ buf_len = msgs[msg_idx].len;
+
+ for (data_idx = 0; data_idx < buf_len; data_idx++) {
+ if (msgs[msg_idx].flags & I2C_M_RD) {
+ ret = i2c_dw_poll_tx_empty(dev);
+ if (ret)
+ return ret;
+
+ regmap_write(dev->map, DW_IC_DATA_CMD,
+ (dev_addr + data_idx) | BIT(9));
+ regmap_write(dev->map, DW_IC_DATA_CMD, 0x100 | BIT(9));
+
+ ret = i2c_dw_poll_rx_full(dev);
+ if (ret)
+ return ret;
+
+ regmap_read(dev->map, DW_IC_DATA_CMD, &val);
+ buf[data_idx] = 0xFF & val;
+ } else {
+ ret = i2c_dw_poll_tx_empty(dev);
+ if (ret)
+ return ret;
+
+ regmap_write(dev->map, DW_IC_DATA_CMD, buf[data_idx]);
+ if (data_idx == (buf_len - 1))
+ regmap_write(dev->map, DW_IC_DATA_CMD, BIT(9));
+ }
+ }
+ }
+
+ return num_msgs;
+}
+
/*
* Initiate (and continue) low level master read/write transaction.
* This function is only called from i2c_dw_isr, and pumping i2c_msg
@@ -568,6 +637,11 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
goto done_nolock;
}
+ if ((dev->flags & MODEL_MASK) == MODEL_WANGXUN_SP) {
+ ret = txgbe_i2c_dw_xfer_quirk(adap, msgs, num);
+ goto done_nolock;
+ }
+
reinit_completion(&dev->cmd_complete);
dev->msgs = msgs;
dev->msgs_num = num;
@@ -848,7 +922,7 @@ static int i2c_dw_init_recovery_info(struct dw_i2c_dev *dev)
return 0;
}
-static int amd_i2c_adap_quirk(struct dw_i2c_dev *dev)
+static int poll_i2c_adap_quirk(struct dw_i2c_dev *dev)
{
struct i2c_adapter *adap = &dev->adapter;
int ret;
@@ -862,6 +936,17 @@ static int amd_i2c_adap_quirk(struct dw_i2c_dev *dev)
return ret;
}
+static bool i2c_is_model_poll(struct dw_i2c_dev *dev)
+{
+ switch (dev->flags & MODEL_MASK) {
+ case MODEL_AMD_NAVI_GPU:
+ case MODEL_WANGXUN_SP:
+ return true;
+ default:
+ return false;
+ }
+}
+
int i2c_dw_probe_master(struct dw_i2c_dev *dev)
{
struct i2c_adapter *adap = &dev->adapter;
@@ -917,8 +1002,8 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev)
adap->dev.parent = dev->dev;
i2c_set_adapdata(adap, dev);
- if ((dev->flags & MODEL_MASK) == MODEL_AMD_NAVI_GPU)
- return amd_i2c_adap_quirk(dev);
+ if (i2c_is_model_poll(dev))
+ return poll_i2c_adap_quirk(dev);
if (dev->flags & ACCESS_NO_IRQ_SUSPEND) {
irq_flags = IRQF_NO_SUSPEND;
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index 74182db03a88..10b2c61b279f 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -23,6 +23,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
+#include <linux/platform_data/i2c-dw.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
@@ -179,12 +180,14 @@ static void dw_i2c_plat_pm_cleanup(struct dw_i2c_dev *dev)
static int dw_i2c_plat_request_regs(struct dw_i2c_dev *dev)
{
struct platform_device *pdev = to_platform_device(dev->dev);
- int ret;
+ int ret = 0;
switch (dev->flags & MODEL_MASK) {
case MODEL_BAIKAL_BT1:
ret = bt1_i2c_request_regs(dev);
break;
+ case MODEL_WANGXUN_SP:
+ break;
default:
dev->base = devm_platform_ioremap_resource(pdev, 0);
ret = PTR_ERR_OR_ZERO(dev->base);
@@ -194,6 +197,35 @@ static int dw_i2c_plat_request_regs(struct dw_i2c_dev *dev)
return ret;
}
+static void dw_i2c_get_plat_data(struct dw_i2c_dev *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev->dev);
+ struct dw_i2c_platform_data *pdata;
+
+ pdata = dev_get_platdata(&pdev->dev);
+ if (!pdata)
+ return;
+
+ dev->flags |= pdata->flags;
+ dev->base = pdata->base;
+
+ if (pdata->ss_hcnt && pdata->ss_lcnt) {
+ dev->ss_hcnt = pdata->ss_hcnt;
+ dev->ss_lcnt = pdata->ss_lcnt;
+ } else {
+ dev->ss_hcnt = 6;
+ dev->ss_lcnt = 8;
+ }
+
+ if (pdata->fs_hcnt && pdata->fs_lcnt) {
+ dev->fs_hcnt = pdata->fs_hcnt;
+ dev->fs_lcnt = pdata->fs_lcnt;
+ } else {
+ dev->fs_hcnt = 6;
+ dev->fs_lcnt = 8;
+ }
+}
+
static const struct dmi_system_id dw_i2c_hwmon_class_dmi[] = {
{
.ident = "Qtechnology QT5222",
@@ -282,6 +314,8 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
dev->irq = irq;
platform_set_drvdata(pdev, dev);
+ dw_i2c_get_plat_data(dev);
+
ret = dw_i2c_plat_request_regs(dev);
if (ret)
return ret;
diff --git a/include/linux/platform_data/i2c-dw.h b/include/linux/platform_data/i2c-dw.h
new file mode 100644
index 000000000000..f4552df08084
--- /dev/null
+++ b/include/linux/platform_data/i2c-dw.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _LINUX_I2C_DW_H
+#define _LINUX_I2C_DW_H
+
+struct dw_i2c_platform_data {
+ void __iomem *base;
+ unsigned int flags;
+ unsigned int ss_hcnt;
+ unsigned int ss_lcnt;
+ unsigned int fs_hcnt;
+ unsigned int fs_lcnt;
+};
+
+#endif /* _LINUX_I2C_DW_H */
--
2.27.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH net-next v3 3/8] net: txgbe: Register I2C platform device
2023-04-19 8:27 [PATCH net-next v3 0/8] TXGBE PHYLINK support Jiawen Wu
2023-04-19 8:27 ` [PATCH net-next v3 1/8] net: txgbe: Add software nodes to support phylink Jiawen Wu
2023-04-19 8:27 ` [PATCH net-next v3 2/8] i2c: designware: Add driver support for Wangxun 10Gb NIC Jiawen Wu
@ 2023-04-19 8:27 ` Jiawen Wu
2023-04-19 8:27 ` [PATCH net-next v3 4/8] net: txgbe: Add SFP module identify Jiawen Wu
` (5 subsequent siblings)
8 siblings, 0 replies; 28+ messages in thread
From: Jiawen Wu @ 2023-04-19 8:27 UTC (permalink / raw)
To: netdev, linux; +Cc: linux-i2c, linux-gpio, olteanv, mengyuanlou, Jiawen Wu
Register the platform device to use Designware I2C bus master driver.
Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
---
drivers/net/ethernet/wangxun/Kconfig | 1 +
.../net/ethernet/wangxun/txgbe/txgbe_phy.c | 50 +++++++++++++++++++
.../net/ethernet/wangxun/txgbe/txgbe_type.h | 4 ++
3 files changed, 55 insertions(+)
diff --git a/drivers/net/ethernet/wangxun/Kconfig b/drivers/net/ethernet/wangxun/Kconfig
index c9d88673d306..8acd6a0d84dc 100644
--- a/drivers/net/ethernet/wangxun/Kconfig
+++ b/drivers/net/ethernet/wangxun/Kconfig
@@ -40,6 +40,7 @@ config NGBE
config TXGBE
tristate "Wangxun(R) 10GbE PCI Express adapters support"
depends on PCI
+ select I2C_DESIGNWARE_PLATFORM
select LIBWX
help
This driver supports Wangxun(R) 10GbE PCI Express family of
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
index 39762c7fc851..8bb7f1d9acc7 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
@@ -1,6 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2015 - 2023 Beijing WangXun Technology Co., Ltd. */
+#include <linux/platform_data/i2c-dw.h>
+#include <linux/platform_device.h>
#include <linux/gpio/property.h>
#include <linux/i2c.h>
#include <linux/pci.h>
@@ -69,6 +71,40 @@ static int txgbe_swnodes_register(struct txgbe *txgbe)
return software_node_register_node_group(nodes->group);
}
+static int txgbe_i2c_register(struct txgbe *txgbe)
+{
+ struct pci_dev *pdev = txgbe->wx->pdev;
+ struct dw_i2c_platform_data pdata = {};
+ struct platform_device_info info = {};
+ struct platform_device *i2c_dev;
+ struct resource res = {};
+
+ pdata.base = txgbe->wx->hw_addr + TXGBE_I2C_BASE;
+ pdata.flags = BIT(11); /* MODEL_WANGXUN_SP */
+ pdata.ss_hcnt = 600;
+ pdata.ss_lcnt = 600;
+
+ info.parent = &pdev->dev;
+ info.fwnode = software_node_fwnode(txgbe->nodes.group[SWNODE_I2C]);
+ info.name = "i2c_designware";
+ info.id = (pdev->bus->number << 8) | pdev->devfn;
+ info.data = &pdata;
+ info.size_data = sizeof(pdata);
+
+ res.start = pdev->irq;
+ res.end = pdev->irq;
+ res.flags = IORESOURCE_IRQ;
+ info.res = &res;
+ info.num_res = 1;
+ i2c_dev = platform_device_register_full(&info);
+ if (IS_ERR(i2c_dev))
+ return PTR_ERR(i2c_dev);
+
+ txgbe->i2c_dev = i2c_dev;
+
+ return 0;
+}
+
int txgbe_init_phy(struct txgbe *txgbe)
{
int ret;
@@ -79,10 +115,24 @@ int txgbe_init_phy(struct txgbe *txgbe)
return ret;
}
+ ret = txgbe_i2c_register(txgbe);
+ if (ret) {
+ wx_err(txgbe->wx, "failed to init i2c interface: %d\n", ret);
+ goto err;
+ }
+
return 0;
+
+err:
+ txgbe_remove_phy(txgbe);
+
+ return ret;
}
void txgbe_remove_phy(struct txgbe *txgbe)
{
+ if (txgbe->i2c_dev)
+ platform_device_unregister(txgbe->i2c_dev);
+
software_node_unregister_node_group(txgbe->nodes.group);
}
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
index 51bbecb28433..771aefbc7c80 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
@@ -55,6 +55,9 @@
#define TXGBE_TS_CTL 0x10300
#define TXGBE_TS_CTL_EVAL_MD BIT(31)
+/* I2C registers */
+#define TXGBE_I2C_BASE 0x14900
+
/* Part Number String Length */
#define TXGBE_PBANUM_LENGTH 32
@@ -146,6 +149,7 @@ struct txgbe_nodes {
struct txgbe {
struct wx *wx;
struct txgbe_nodes nodes;
+ struct platform_device *i2c_dev;
};
#endif /* _TXGBE_TYPE_H_ */
--
2.27.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH net-next v3 4/8] net: txgbe: Add SFP module identify
2023-04-19 8:27 [PATCH net-next v3 0/8] TXGBE PHYLINK support Jiawen Wu
` (2 preceding siblings ...)
2023-04-19 8:27 ` [PATCH net-next v3 3/8] net: txgbe: Register I2C platform device Jiawen Wu
@ 2023-04-19 8:27 ` Jiawen Wu
2023-04-19 13:55 ` Vladimir Oltean
2023-04-19 8:27 ` [PATCH net-next v3 5/8] net: txgbe: Support GPIO to SFP socket Jiawen Wu
` (4 subsequent siblings)
8 siblings, 1 reply; 28+ messages in thread
From: Jiawen Wu @ 2023-04-19 8:27 UTC (permalink / raw)
To: netdev, linux; +Cc: linux-i2c, linux-gpio, olteanv, mengyuanlou, Jiawen Wu
Register SFP platform device to get modules information.
Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
---
drivers/net/ethernet/wangxun/Kconfig | 1 +
.../net/ethernet/wangxun/txgbe/txgbe_phy.c | 27 +++++++++++++++++++
.../net/ethernet/wangxun/txgbe/txgbe_type.h | 1 +
3 files changed, 29 insertions(+)
diff --git a/drivers/net/ethernet/wangxun/Kconfig b/drivers/net/ethernet/wangxun/Kconfig
index 8acd6a0d84dc..d2dbaf19e53d 100644
--- a/drivers/net/ethernet/wangxun/Kconfig
+++ b/drivers/net/ethernet/wangxun/Kconfig
@@ -42,6 +42,7 @@ config TXGBE
depends on PCI
select I2C_DESIGNWARE_PLATFORM
select LIBWX
+ select SFP
help
This driver supports Wangxun(R) 10GbE PCI Express family of
adapters.
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
index 8bb7f1d9acc7..faa0479f1df3 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
@@ -105,6 +105,25 @@ static int txgbe_i2c_register(struct txgbe *txgbe)
return 0;
}
+static int txgbe_sfp_register(struct txgbe *txgbe)
+{
+ struct pci_dev *pdev = txgbe->wx->pdev;
+ struct platform_device_info info = {};
+ struct platform_device *sfp_dev;
+
+ info.parent = &pdev->dev;
+ info.fwnode = software_node_fwnode(txgbe->nodes.group[SWNODE_SFP]);
+ info.name = "sfp";
+ info.id = (pdev->bus->number << 8) | pdev->devfn;
+ sfp_dev = platform_device_register_full(&info);
+ if (IS_ERR(sfp_dev))
+ return PTR_ERR(sfp_dev);
+
+ txgbe->sfp_dev = sfp_dev;
+
+ return 0;
+}
+
int txgbe_init_phy(struct txgbe *txgbe)
{
int ret;
@@ -121,6 +140,12 @@ int txgbe_init_phy(struct txgbe *txgbe)
goto err;
}
+ ret = txgbe_sfp_register(txgbe);
+ if (ret) {
+ wx_err(txgbe->wx, "failed to register sfp\n");
+ goto err;
+ }
+
return 0;
err:
@@ -131,6 +156,8 @@ int txgbe_init_phy(struct txgbe *txgbe)
void txgbe_remove_phy(struct txgbe *txgbe)
{
+ if (txgbe->sfp_dev)
+ platform_device_unregister(txgbe->sfp_dev);
if (txgbe->i2c_dev)
platform_device_unregister(txgbe->i2c_dev);
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
index 771aefbc7c80..aa94c4fce311 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
@@ -149,6 +149,7 @@ struct txgbe_nodes {
struct txgbe {
struct wx *wx;
struct txgbe_nodes nodes;
+ struct platform_device *sfp_dev;
struct platform_device *i2c_dev;
};
--
2.27.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH net-next v3 5/8] net: txgbe: Support GPIO to SFP socket
2023-04-19 8:27 [PATCH net-next v3 0/8] TXGBE PHYLINK support Jiawen Wu
` (3 preceding siblings ...)
2023-04-19 8:27 ` [PATCH net-next v3 4/8] net: txgbe: Add SFP module identify Jiawen Wu
@ 2023-04-19 8:27 ` Jiawen Wu
2023-04-19 8:27 ` [PATCH net-next v3 6/8] net: pcs: Add 10GBASE-R mode for Synopsys Designware XPCS Jiawen Wu
` (3 subsequent siblings)
8 siblings, 0 replies; 28+ messages in thread
From: Jiawen Wu @ 2023-04-19 8:27 UTC (permalink / raw)
To: netdev, linux; +Cc: linux-i2c, linux-gpio, olteanv, mengyuanlou, Jiawen Wu
Register GPIO chip and handle GPIO IRQ for SFP socket.
Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
---
drivers/net/ethernet/wangxun/Kconfig | 2 +
drivers/net/ethernet/wangxun/libwx/wx_lib.c | 3 +-
drivers/net/ethernet/wangxun/libwx/wx_type.h | 2 +
.../net/ethernet/wangxun/txgbe/txgbe_main.c | 20 +-
.../net/ethernet/wangxun/txgbe/txgbe_phy.c | 228 ++++++++++++++++++
.../net/ethernet/wangxun/txgbe/txgbe_type.h | 27 +++
6 files changed, 263 insertions(+), 19 deletions(-)
diff --git a/drivers/net/ethernet/wangxun/Kconfig b/drivers/net/ethernet/wangxun/Kconfig
index d2dbaf19e53d..9b69c3d53d65 100644
--- a/drivers/net/ethernet/wangxun/Kconfig
+++ b/drivers/net/ethernet/wangxun/Kconfig
@@ -41,6 +41,8 @@ config TXGBE
tristate "Wangxun(R) 10GbE PCI Express adapters support"
depends on PCI
select I2C_DESIGNWARE_PLATFORM
+ select GPIOLIB_IRQCHIP
+ select GPIOLIB
select LIBWX
select SFP
help
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.c b/drivers/net/ethernet/wangxun/libwx/wx_lib.c
index eb89a274083e..dff0d573ee33 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_lib.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.c
@@ -1348,7 +1348,8 @@ void wx_free_irq(struct wx *wx)
free_irq(entry->vector, q_vector);
}
- free_irq(wx->msix_entries[vector].vector, wx);
+ if (wx->mac.type == wx_mac_em)
+ free_irq(wx->msix_entries[vector].vector, wx);
}
EXPORT_SYMBOL(wx_free_irq);
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h
index 97bce855bc60..d151d6f79022 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_type.h
+++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h
@@ -79,7 +79,9 @@
#define WX_GPIO_INTMASK 0x14834
#define WX_GPIO_INTTYPE_LEVEL 0x14838
#define WX_GPIO_POLARITY 0x1483C
+#define WX_GPIO_INTSTATUS 0x14844
#define WX_GPIO_EOI 0x1484C
+#define WX_GPIO_EXT 0x14850
/*********************** Transmit DMA registers **************************/
/* transmit global control */
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
index dbd4d409d93b..b1ede19f4ff8 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
@@ -82,6 +82,8 @@ static int txgbe_enumerate_functions(struct wx *wx)
**/
static void txgbe_irq_enable(struct wx *wx, bool queues)
{
+ wr32(wx, WX_PX_MISC_IEN, TXGBE_PX_MISC_IEN_MASK);
+
/* unmask interrupt */
wx_intr_enable(wx, TXGBE_INTR_MISC(wx));
if (queues)
@@ -129,17 +131,6 @@ static irqreturn_t txgbe_intr(int __always_unused irq, void *data)
return IRQ_HANDLED;
}
-static irqreturn_t txgbe_msix_other(int __always_unused irq, void *data)
-{
- struct wx *wx = data;
-
- /* re-enable the original interrupt state */
- if (netif_running(wx->netdev))
- txgbe_irq_enable(wx, false);
-
- return IRQ_HANDLED;
-}
-
/**
* txgbe_request_msix_irqs - Initialize MSI-X interrupts
* @wx: board private structure
@@ -171,13 +162,6 @@ static int txgbe_request_msix_irqs(struct wx *wx)
}
}
- err = request_irq(wx->msix_entries[vector].vector,
- txgbe_msix_other, 0, netdev->name, wx);
- if (err) {
- wx_err(wx, "request_irq for msix_other failed: %d\n", err);
- goto free_queue_irqs;
- }
-
return 0;
free_queue_irqs:
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
index faa0479f1df3..d98d283dd0db 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
@@ -3,11 +3,15 @@
#include <linux/platform_data/i2c-dw.h>
#include <linux/platform_device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/machine.h>
+#include <linux/gpio/driver.h>
#include <linux/gpio/property.h>
#include <linux/i2c.h>
#include <linux/pci.h>
#include "../libwx/wx_type.h"
+#include "../libwx/wx_hw.h"
#include "txgbe_type.h"
#include "txgbe_phy.h"
@@ -105,6 +109,224 @@ static int txgbe_i2c_register(struct txgbe *txgbe)
return 0;
}
+static int txgbe_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+ struct wx *wx = gpiochip_get_data(chip);
+ struct txgbe *txgbe = wx->priv;
+ int val;
+
+ val = rd32m(wx, WX_GPIO_EXT, BIT(offset));
+
+ txgbe->gpio_orig &= ~BIT(offset);
+ txgbe->gpio_orig |= val;
+
+ return !!(val & BIT(offset));
+}
+
+static int txgbe_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
+{
+ struct wx *wx = gpiochip_get_data(chip);
+ u32 val;
+
+ val = rd32(wx, WX_GPIO_DDR);
+ if (BIT(offset) & val)
+ return GPIO_LINE_DIRECTION_OUT;
+
+ return GPIO_LINE_DIRECTION_IN;
+}
+
+static int txgbe_gpio_direction_in(struct gpio_chip *chip, unsigned int offset)
+{
+ struct wx *wx = gpiochip_get_data(chip);
+
+ wr32m(wx, WX_GPIO_DDR, BIT(offset), 0);
+
+ return 0;
+}
+
+static int txgbe_gpio_direction_out(struct gpio_chip *chip, unsigned int offset,
+ int val)
+{
+ struct wx *wx = gpiochip_get_data(chip);
+ u32 mask;
+
+ mask = BIT(offset) | BIT(offset - 1);
+ if (val)
+ wr32m(wx, WX_GPIO_DR, mask, mask);
+ else
+ wr32m(wx, WX_GPIO_DR, mask, 0);
+
+ wr32m(wx, WX_GPIO_DDR, BIT(offset), BIT(offset));
+
+ return 0;
+}
+
+static void txgbe_gpio_irq_ack(struct irq_data *d)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ irq_hw_number_t hwirq = irqd_to_hwirq(d);
+ struct wx *wx = gpiochip_get_data(gc);
+
+ wr32(wx, WX_GPIO_EOI, BIT(hwirq));
+}
+
+static void txgbe_gpio_irq_mask(struct irq_data *d)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ irq_hw_number_t hwirq = irqd_to_hwirq(d);
+ struct wx *wx = gpiochip_get_data(gc);
+
+ gpiochip_disable_irq(gc, hwirq);
+
+ wr32m(wx, WX_GPIO_INTMASK, BIT(hwirq), BIT(hwirq));
+}
+
+static void txgbe_gpio_irq_unmask(struct irq_data *d)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ irq_hw_number_t hwirq = irqd_to_hwirq(d);
+ struct wx *wx = gpiochip_get_data(gc);
+
+ gpiochip_enable_irq(gc, hwirq);
+
+ wr32m(wx, WX_GPIO_INTMASK, BIT(hwirq), 0);
+}
+
+static int txgbe_gpio_set_type(struct irq_data *d, unsigned int type)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ irq_hw_number_t hwirq = irqd_to_hwirq(d);
+ struct wx *wx = gpiochip_get_data(gc);
+ u32 level, polarity;
+
+ level = rd32(wx, WX_GPIO_INTTYPE_LEVEL);
+ polarity = rd32(wx, WX_GPIO_POLARITY);
+
+ switch (type) {
+ case IRQ_TYPE_EDGE_BOTH:
+ level |= BIT(hwirq);
+ break;
+ case IRQ_TYPE_EDGE_RISING:
+ level |= BIT(hwirq);
+ polarity |= BIT(hwirq);
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ level |= BIT(hwirq);
+ polarity &= ~BIT(hwirq);
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ level &= ~BIT(hwirq);
+ polarity |= BIT(hwirq);
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ level &= ~BIT(hwirq);
+ polarity &= ~BIT(hwirq);
+ break;
+ }
+
+ if (type & IRQ_TYPE_LEVEL_MASK)
+ irq_set_handler_locked(d, handle_level_irq);
+ else if (type & IRQ_TYPE_EDGE_BOTH)
+ irq_set_handler_locked(d, handle_edge_irq);
+
+ wr32m(wx, WX_GPIO_INTEN, BIT(hwirq), BIT(hwirq));
+ wr32(wx, WX_GPIO_INTTYPE_LEVEL, level);
+ if (type != IRQ_TYPE_EDGE_BOTH)
+ wr32(wx, WX_GPIO_POLARITY, polarity);
+
+ return 0;
+}
+
+static const struct irq_chip txgbe_gpio_irq_chip = {
+ .name = "txgbe_gpio_irq",
+ .irq_ack = txgbe_gpio_irq_ack,
+ .irq_mask = txgbe_gpio_irq_mask,
+ .irq_unmask = txgbe_gpio_irq_unmask,
+ .irq_set_type = txgbe_gpio_set_type,
+ .flags = IRQCHIP_IMMUTABLE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
+};
+
+static void txgbe_irq_handler(struct irq_desc *desc)
+{
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ struct wx *wx = irq_desc_get_handler_data(desc);
+ struct txgbe *txgbe = wx->priv;
+ irq_hw_number_t hwirq;
+ unsigned long gpioirq;
+ struct gpio_chip *gc;
+ u32 gpio;
+
+ chained_irq_enter(chip, desc);
+
+ gpioirq = rd32(wx, WX_GPIO_INTSTATUS);
+
+ /* workaround for hysteretic gpio interrupts */
+ gpio = rd32(wx, WX_GPIO_EXT);
+ if (!gpioirq)
+ gpioirq = txgbe->gpio_orig ^ gpio;
+
+ gc = txgbe->gpio;
+ for_each_set_bit(hwirq, &gpioirq, gc->ngpio)
+ generic_handle_domain_irq(gc->irq.domain, hwirq);
+
+ chained_irq_exit(chip, desc);
+
+ /* unmask interrupt */
+ if (netif_running(wx->netdev))
+ wx_intr_enable(wx, TXGBE_INTR_MISC(wx));
+}
+
+static int txgbe_gpio_init(struct txgbe *txgbe)
+{
+ struct gpio_irq_chip *girq;
+ struct wx *wx = txgbe->wx;
+ struct pci_dev *pdev;
+ struct gpio_chip *gc;
+ int ret;
+
+ pdev = wx->pdev;
+ txgbe->gpio_orig = 0;
+
+ gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL);
+ if (!gc)
+ return -ENOMEM;
+
+ gc->label = devm_kasprintf(&pdev->dev, GFP_KERNEL, "txgbe_gpio-%x",
+ (pdev->bus->number << 8) | pdev->devfn);
+ gc->base = -1;
+ gc->ngpio = 6;
+ gc->owner = THIS_MODULE;
+ gc->parent = &pdev->dev;
+ gc->fwnode = software_node_fwnode(txgbe->nodes.group[SWNODE_GPIO]);
+ gc->get = txgbe_gpio_get;
+ gc->get_direction = txgbe_gpio_get_direction;
+ gc->direction_input = txgbe_gpio_direction_in;
+ gc->direction_output = txgbe_gpio_direction_out;
+ gc->can_sleep = false;
+
+ girq = &gc->irq;
+ gpio_irq_chip_set_chip(girq, &txgbe_gpio_irq_chip);
+ girq->parent_handler = txgbe_irq_handler;
+ girq->parent_handler_data = wx;
+ girq->num_parents = 1;
+ girq->parents = devm_kcalloc(&pdev->dev, 1, sizeof(*girq->parents),
+ GFP_KERNEL);
+ if (!girq->parents)
+ return -ENOMEM;
+ girq->parents[0] = wx->msix_entries[wx->num_q_vectors].vector;
+ girq->default_type = IRQ_TYPE_NONE;
+ girq->handler = handle_bad_irq;
+
+ ret = devm_gpiochip_add_data(&pdev->dev, gc, wx);
+ if (ret)
+ return ret;
+
+ txgbe->gpio = gc;
+
+ return 0;
+}
+
static int txgbe_sfp_register(struct txgbe *txgbe)
{
struct pci_dev *pdev = txgbe->wx->pdev;
@@ -140,6 +362,12 @@ int txgbe_init_phy(struct txgbe *txgbe)
goto err;
}
+ ret = txgbe_gpio_init(txgbe);
+ if (ret) {
+ wx_err(txgbe->wx, "failed to init gpio\n");
+ goto err;
+ }
+
ret = txgbe_sfp_register(txgbe);
if (ret) {
wx_err(txgbe->wx, "failed to register sfp\n");
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
index aa94c4fce311..334803e6a5de 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
@@ -55,6 +55,31 @@
#define TXGBE_TS_CTL 0x10300
#define TXGBE_TS_CTL_EVAL_MD BIT(31)
+/* GPIO register bit */
+#define TXGBE_GPIOBIT_0 BIT(0) /* I:tx fault */
+#define TXGBE_GPIOBIT_1 BIT(1) /* O:tx disabled */
+#define TXGBE_GPIOBIT_2 BIT(2) /* I:sfp module absent */
+#define TXGBE_GPIOBIT_3 BIT(3) /* I:rx signal lost */
+#define TXGBE_GPIOBIT_4 BIT(4) /* O:rate select, 1G(0) 10G(1) */
+#define TXGBE_GPIOBIT_5 BIT(5) /* O:rate select, 1G(0) 10G(1) */
+
+/* Extended Interrupt Enable Set */
+#define TXGBE_PX_MISC_ETH_LKDN BIT(8)
+#define TXGBE_PX_MISC_DEV_RST BIT(10)
+#define TXGBE_PX_MISC_ETH_EVENT BIT(17)
+#define TXGBE_PX_MISC_ETH_LK BIT(18)
+#define TXGBE_PX_MISC_ETH_AN BIT(19)
+#define TXGBE_PX_MISC_INT_ERR BIT(20)
+#define TXGBE_PX_MISC_GPIO BIT(26)
+#define TXGBE_PX_MISC_IEN_MASK ( \
+ TXGBE_PX_MISC_ETH_LKDN | \
+ TXGBE_PX_MISC_DEV_RST | \
+ TXGBE_PX_MISC_ETH_EVENT | \
+ TXGBE_PX_MISC_ETH_LK | \
+ TXGBE_PX_MISC_ETH_AN | \
+ TXGBE_PX_MISC_INT_ERR | \
+ TXGBE_PX_MISC_GPIO)
+
/* I2C registers */
#define TXGBE_I2C_BASE 0x14900
@@ -151,6 +176,8 @@ struct txgbe {
struct txgbe_nodes nodes;
struct platform_device *sfp_dev;
struct platform_device *i2c_dev;
+ struct gpio_chip *gpio;
+ u32 gpio_orig;
};
#endif /* _TXGBE_TYPE_H_ */
--
2.27.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH net-next v3 6/8] net: pcs: Add 10GBASE-R mode for Synopsys Designware XPCS
2023-04-19 8:27 [PATCH net-next v3 0/8] TXGBE PHYLINK support Jiawen Wu
` (4 preceding siblings ...)
2023-04-19 8:27 ` [PATCH net-next v3 5/8] net: txgbe: Support GPIO to SFP socket Jiawen Wu
@ 2023-04-19 8:27 ` Jiawen Wu
2023-04-19 13:19 ` Vladimir Oltean
2023-04-19 8:27 ` [PATCH net-next v3 7/8] net: txgbe: Implement phylink pcs Jiawen Wu
` (2 subsequent siblings)
8 siblings, 1 reply; 28+ messages in thread
From: Jiawen Wu @ 2023-04-19 8:27 UTC (permalink / raw)
To: netdev, linux
Cc: linux-i2c, linux-gpio, olteanv, mengyuanlou, Jiawen Wu,
Jose Abreu
Add basic support for XPCS using 10GBASE-R interface. This mode will
be extended to use interrupt, so set pcs.poll false. And avoid soft
reset so that the device using this mode is in the default configuration.
Cc: Jose Abreu <Jose.Abreu@synopsys.com>
Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
---
drivers/net/pcs/pcs-xpcs.c | 58 ++++++++++++++++++++++++++++++++++++
include/linux/pcs/pcs-xpcs.h | 1 +
2 files changed, 59 insertions(+)
diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c
index 539cd43eae8d..58a417edfb4d 100644
--- a/drivers/net/pcs/pcs-xpcs.c
+++ b/drivers/net/pcs/pcs-xpcs.c
@@ -64,6 +64,16 @@ static const int xpcs_xlgmii_features[] = {
__ETHTOOL_LINK_MODE_MASK_NBITS,
};
+static const int xpcs_10gbaser_features[] = {
+ ETHTOOL_LINK_MODE_Pause_BIT,
+ ETHTOOL_LINK_MODE_Asym_Pause_BIT,
+ ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
+ ETHTOOL_LINK_MODE_10000baseLR_Full_BIT,
+ ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT,
+ ETHTOOL_LINK_MODE_10000baseER_Full_BIT,
+ __ETHTOOL_LINK_MODE_MASK_NBITS,
+};
+
static const int xpcs_sgmii_features[] = {
ETHTOOL_LINK_MODE_Pause_BIT,
ETHTOOL_LINK_MODE_Asym_Pause_BIT,
@@ -106,6 +116,10 @@ static const phy_interface_t xpcs_xlgmii_interfaces[] = {
PHY_INTERFACE_MODE_XLGMII,
};
+static const phy_interface_t xpcs_10gbaser_interfaces[] = {
+ PHY_INTERFACE_MODE_10GBASER,
+};
+
static const phy_interface_t xpcs_sgmii_interfaces[] = {
PHY_INTERFACE_MODE_SGMII,
};
@@ -123,6 +137,7 @@ enum {
DW_XPCS_USXGMII,
DW_XPCS_10GKR,
DW_XPCS_XLGMII,
+ DW_XPCS_10GBASER,
DW_XPCS_SGMII,
DW_XPCS_1000BASEX,
DW_XPCS_2500BASEX,
@@ -246,6 +261,7 @@ static int xpcs_soft_reset(struct dw_xpcs *xpcs,
switch (compat->an_mode) {
case DW_AN_C73:
+ case DW_10GBASER:
dev = MDIO_MMD_PCS;
break;
case DW_AN_C37_SGMII:
@@ -872,6 +888,8 @@ int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface,
return -ENODEV;
switch (compat->an_mode) {
+ case DW_10GBASER:
+ break;
case DW_AN_C73:
if (phylink_autoneg_inband(mode)) {
ret = xpcs_config_aneg_c73(xpcs, compat);
@@ -919,6 +937,29 @@ static int xpcs_config(struct phylink_pcs *pcs, unsigned int mode,
return xpcs_do_config(xpcs, interface, mode, advertising);
}
+static int xpcs_get_state_10gbaser(struct dw_xpcs *xpcs,
+ struct phylink_link_state *state)
+{
+ int ret;
+
+ state->link = false;
+
+ ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_STAT1);
+ if (ret < 0)
+ return ret;
+
+ if (ret & MDIO_STAT1_LSTATUS)
+ state->link = true;
+
+ if (state->link) {
+ state->pause = MLO_PAUSE_TX | MLO_PAUSE_RX;
+ state->duplex = DUPLEX_FULL;
+ state->speed = SPEED_10000;
+ }
+
+ return 0;
+}
+
static int xpcs_get_state_c73(struct dw_xpcs *xpcs,
struct phylink_link_state *state,
const struct xpcs_compat *compat)
@@ -1033,6 +1074,14 @@ static void xpcs_get_state(struct phylink_pcs *pcs,
return;
switch (compat->an_mode) {
+ case DW_10GBASER:
+ ret = xpcs_get_state_10gbaser(xpcs, state);
+ if (ret) {
+ pr_err("xpcs_get_state_10gbaser returned %pe\n",
+ ERR_PTR(ret));
+ return;
+ }
+ break;
case DW_AN_C73:
ret = xpcs_get_state_c73(xpcs, state, compat);
if (ret) {
@@ -1188,6 +1237,12 @@ static const struct xpcs_compat synopsys_xpcs_compat[DW_XPCS_INTERFACE_MAX] = {
.num_interfaces = ARRAY_SIZE(xpcs_xlgmii_interfaces),
.an_mode = DW_AN_C73,
},
+ [DW_XPCS_10GBASER] = {
+ .supported = xpcs_10gbaser_features,
+ .interface = xpcs_10gbaser_interfaces,
+ .num_interfaces = ARRAY_SIZE(xpcs_10gbaser_interfaces),
+ .an_mode = DW_10GBASER,
+ },
[DW_XPCS_SGMII] = {
.supported = xpcs_sgmii_features,
.interface = xpcs_sgmii_interfaces,
@@ -1290,6 +1345,9 @@ struct dw_xpcs *xpcs_create(struct mdio_device *mdiodev,
}
xpcs->pcs.ops = &xpcs_phylink_ops;
+ if (compat->an_mode == DW_10GBASER)
+ return xpcs;
+
xpcs->pcs.poll = true;
ret = xpcs_soft_reset(xpcs, compat);
diff --git a/include/linux/pcs/pcs-xpcs.h b/include/linux/pcs/pcs-xpcs.h
index d2da1e0b4a92..61df0c717a0e 100644
--- a/include/linux/pcs/pcs-xpcs.h
+++ b/include/linux/pcs/pcs-xpcs.h
@@ -18,6 +18,7 @@
#define DW_AN_C37_SGMII 2
#define DW_2500BASEX 3
#define DW_AN_C37_1000BASEX 4
+#define DW_10GBASER 5
struct xpcs_id;
--
2.27.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH net-next v3 7/8] net: txgbe: Implement phylink pcs
2023-04-19 8:27 [PATCH net-next v3 0/8] TXGBE PHYLINK support Jiawen Wu
` (5 preceding siblings ...)
2023-04-19 8:27 ` [PATCH net-next v3 6/8] net: pcs: Add 10GBASE-R mode for Synopsys Designware XPCS Jiawen Wu
@ 2023-04-19 8:27 ` Jiawen Wu
2023-04-19 8:27 ` [PATCH net-next v3 8/8] net: txgbe: Support phylink MAC layer Jiawen Wu
2023-04-19 13:39 ` [PATCH net-next v3 0/8] TXGBE PHYLINK support Vladimir Oltean
8 siblings, 0 replies; 28+ messages in thread
From: Jiawen Wu @ 2023-04-19 8:27 UTC (permalink / raw)
To: netdev, linux; +Cc: linux-i2c, linux-gpio, olteanv, mengyuanlou, Jiawen Wu
Register MDIO bus for PCS layer to use Synopsys designware XPCS, support
10GBASE-R interface to the controller.
Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
---
drivers/net/ethernet/wangxun/Kconfig | 1 +
.../net/ethernet/wangxun/txgbe/txgbe_phy.c | 86 +++++++++++++++++++
.../net/ethernet/wangxun/txgbe/txgbe_type.h | 6 ++
3 files changed, 93 insertions(+)
diff --git a/drivers/net/ethernet/wangxun/Kconfig b/drivers/net/ethernet/wangxun/Kconfig
index 9b69c3d53d65..dde979b623fa 100644
--- a/drivers/net/ethernet/wangxun/Kconfig
+++ b/drivers/net/ethernet/wangxun/Kconfig
@@ -43,6 +43,7 @@ config TXGBE
select I2C_DESIGNWARE_PLATFORM
select GPIOLIB_IRQCHIP
select GPIOLIB
+ select PCS_XPCS
select LIBWX
select SFP
help
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
index d98d283dd0db..6dc5e2f5ae59 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
@@ -7,6 +7,8 @@
#include <linux/gpio/machine.h>
#include <linux/gpio/driver.h>
#include <linux/gpio/property.h>
+#include <linux/pcs/pcs-xpcs.h>
+#include <linux/mdio.h>
#include <linux/i2c.h>
#include <linux/pci.h>
@@ -75,6 +77,82 @@ static int txgbe_swnodes_register(struct txgbe *txgbe)
return software_node_register_node_group(nodes->group);
}
+static int txgbe_pcs_read(struct mii_bus *bus, int addr, int devnum, int regnum)
+{
+ struct wx *wx = bus->priv;
+ u32 offset, val;
+
+ offset = devnum << 16 | regnum;
+
+ /* Set the LAN port indicator to IDA_ADDR */
+ wr32(wx, TXGBE_XPCS_IDA_ADDR, offset);
+
+ /* Read the data from IDA_DATA register */
+ val = rd32(wx, TXGBE_XPCS_IDA_DATA);
+
+ return (u16)val;
+}
+
+static int txgbe_pcs_write(struct mii_bus *bus, int addr, int devnum, int regnum, u16 val)
+{
+ struct wx *wx = bus->priv;
+ u32 offset;
+
+ offset = devnum << 16 | regnum;
+
+ /* Set the LAN port indicator to IDA_ADDR */
+ wr32(wx, TXGBE_XPCS_IDA_ADDR, offset);
+
+ /* Write the data to IDA_DATA register */
+ wr32(wx, TXGBE_XPCS_IDA_DATA, val);
+
+ return 0;
+}
+
+static int txgbe_mdio_pcs_init(struct txgbe *txgbe)
+{
+ struct mdio_device *mdiodev;
+ struct wx *wx = txgbe->wx;
+ struct mii_bus *mii_bus;
+ struct dw_xpcs *xpcs;
+ struct pci_dev *pdev;
+ int ret = 0;
+
+ pdev = wx->pdev;
+
+ mii_bus = devm_mdiobus_alloc(&pdev->dev);
+ if (!mii_bus)
+ return -ENOMEM;
+
+ mii_bus->name = "txgbe_pcs_mdio_bus";
+ mii_bus->read_c45 = &txgbe_pcs_read;
+ mii_bus->write_c45 = &txgbe_pcs_write;
+ mii_bus->parent = &pdev->dev;
+ mii_bus->phy_mask = ~0;
+ mii_bus->priv = wx;
+ snprintf(mii_bus->id, MII_BUS_ID_SIZE, "txgbe_pcs-%x",
+ (pdev->bus->number << 8) | pdev->devfn);
+
+ ret = devm_mdiobus_register(&pdev->dev, mii_bus);
+ if (ret)
+ return ret;
+
+ mdiodev = mdio_device_create(mii_bus, 0);
+ if (IS_ERR(mdiodev))
+ return PTR_ERR(mdiodev);
+
+ xpcs = xpcs_create(mdiodev, PHY_INTERFACE_MODE_10GBASER);
+ if (IS_ERR_OR_NULL(xpcs)) {
+ mdio_device_free(mdiodev);
+ return PTR_ERR(xpcs);
+ }
+
+ txgbe->mdiodev = mdiodev;
+ txgbe->xpcs = xpcs;
+
+ return 0;
+}
+
static int txgbe_i2c_register(struct txgbe *txgbe)
{
struct pci_dev *pdev = txgbe->wx->pdev;
@@ -356,6 +434,12 @@ int txgbe_init_phy(struct txgbe *txgbe)
return ret;
}
+ ret = txgbe_mdio_pcs_init(txgbe);
+ if (ret) {
+ wx_err(txgbe->wx, "failed to init mdio pcs: %d\n", ret);
+ goto err;
+ }
+
ret = txgbe_i2c_register(txgbe);
if (ret) {
wx_err(txgbe->wx, "failed to init i2c interface: %d\n", ret);
@@ -384,6 +468,8 @@ int txgbe_init_phy(struct txgbe *txgbe)
void txgbe_remove_phy(struct txgbe *txgbe)
{
+ if (txgbe->xpcs)
+ xpcs_destroy(txgbe->xpcs);
if (txgbe->sfp_dev)
platform_device_unregister(txgbe->sfp_dev);
if (txgbe->i2c_dev)
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
index 334803e6a5de..89a635593ae2 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
@@ -83,6 +83,10 @@
/* I2C registers */
#define TXGBE_I2C_BASE 0x14900
+/************************************** ETH PHY ******************************/
+#define TXGBE_XPCS_IDA_ADDR 0x13000
+#define TXGBE_XPCS_IDA_DATA 0x13004
+
/* Part Number String Length */
#define TXGBE_PBANUM_LENGTH 32
@@ -174,6 +178,8 @@ struct txgbe_nodes {
struct txgbe {
struct wx *wx;
struct txgbe_nodes nodes;
+ struct mdio_device *mdiodev;
+ struct dw_xpcs *xpcs;
struct platform_device *sfp_dev;
struct platform_device *i2c_dev;
struct gpio_chip *gpio;
--
2.27.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH net-next v3 8/8] net: txgbe: Support phylink MAC layer
2023-04-19 8:27 [PATCH net-next v3 0/8] TXGBE PHYLINK support Jiawen Wu
` (6 preceding siblings ...)
2023-04-19 8:27 ` [PATCH net-next v3 7/8] net: txgbe: Implement phylink pcs Jiawen Wu
@ 2023-04-19 8:27 ` Jiawen Wu
2023-04-19 13:39 ` [PATCH net-next v3 0/8] TXGBE PHYLINK support Vladimir Oltean
8 siblings, 0 replies; 28+ messages in thread
From: Jiawen Wu @ 2023-04-19 8:27 UTC (permalink / raw)
To: netdev, linux; +Cc: linux-i2c, linux-gpio, olteanv, mengyuanlou, Jiawen Wu
Add phylink support to Wangxun 10Gb Ethernet controller for the 10GBASE-R
interface.
Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
---
drivers/net/ethernet/wangxun/Kconfig | 1 +
.../ethernet/wangxun/txgbe/txgbe_ethtool.c | 28 +++++
.../net/ethernet/wangxun/txgbe/txgbe_main.c | 23 ++--
.../net/ethernet/wangxun/txgbe/txgbe_phy.c | 108 +++++++++++++++++-
.../net/ethernet/wangxun/txgbe/txgbe_type.h | 5 +
5 files changed, 151 insertions(+), 14 deletions(-)
diff --git a/drivers/net/ethernet/wangxun/Kconfig b/drivers/net/ethernet/wangxun/Kconfig
index dde979b623fa..e303bff0b13a 100644
--- a/drivers/net/ethernet/wangxun/Kconfig
+++ b/drivers/net/ethernet/wangxun/Kconfig
@@ -43,6 +43,7 @@ config TXGBE
select I2C_DESIGNWARE_PLATFORM
select GPIOLIB_IRQCHIP
select GPIOLIB
+ select PHYLINK
select PCS_XPCS
select LIBWX
select SFP
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c
index d914e9a05404..859da112586a 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c
@@ -6,11 +6,39 @@
#include <linux/netdevice.h>
#include "../libwx/wx_ethtool.h"
+#include "../libwx/wx_type.h"
+#include "txgbe_type.h"
#include "txgbe_ethtool.h"
+static int txgbe_nway_reset(struct net_device *netdev)
+{
+ struct txgbe *txgbe = netdev_to_txgbe(netdev);
+
+ return phylink_ethtool_nway_reset(txgbe->phylink);
+}
+
+static int txgbe_get_link_ksettings(struct net_device *netdev,
+ struct ethtool_link_ksettings *cmd)
+{
+ struct txgbe *txgbe = netdev_to_txgbe(netdev);
+
+ return phylink_ethtool_ksettings_get(txgbe->phylink, cmd);
+}
+
+static int txgbe_set_link_ksettings(struct net_device *netdev,
+ const struct ethtool_link_ksettings *cmd)
+{
+ struct txgbe *txgbe = netdev_to_txgbe(netdev);
+
+ return phylink_ethtool_ksettings_set(txgbe->phylink, cmd);
+}
+
static const struct ethtool_ops txgbe_ethtool_ops = {
.get_drvinfo = wx_get_drvinfo,
+ .nway_reset = txgbe_nway_reset,
.get_link = ethtool_op_get_link,
+ .get_link_ksettings = txgbe_get_link_ksettings,
+ .set_link_ksettings = txgbe_set_link_ksettings,
};
void txgbe_set_ethtool_ops(struct net_device *netdev)
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
index b1ede19f4ff8..04091355a5d8 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
@@ -7,6 +7,7 @@
#include <linux/netdevice.h>
#include <linux/string.h>
#include <linux/etherdevice.h>
+#include <linux/phylink.h>
#include <net/ip.h>
#include <linux/if_vlan.h>
@@ -204,7 +205,8 @@ static int txgbe_request_irq(struct wx *wx)
static void txgbe_up_complete(struct wx *wx)
{
- u32 reg;
+ struct net_device *netdev = wx->netdev;
+ struct txgbe *txgbe = netdev_to_txgbe(netdev);
wx_control_hw(wx, true);
wx_configure_vectors(wx);
@@ -213,24 +215,16 @@ static void txgbe_up_complete(struct wx *wx)
smp_mb__before_atomic();
wx_napi_enable_all(wx);
+ phylink_start(txgbe->phylink);
+
/* clear any pending interrupts, may auto mask */
rd32(wx, WX_PX_IC(0));
rd32(wx, WX_PX_IC(1));
rd32(wx, WX_PX_MISC_IC);
txgbe_irq_enable(wx, true);
- /* Configure MAC Rx and Tx when link is up */
- reg = rd32(wx, WX_MAC_RX_CFG);
- wr32(wx, WX_MAC_RX_CFG, reg);
- wr32(wx, WX_MAC_PKT_FLT, WX_MAC_PKT_FLT_PR);
- reg = rd32(wx, WX_MAC_WDG_TIMEOUT);
- wr32(wx, WX_MAC_WDG_TIMEOUT, reg);
- reg = rd32(wx, WX_MAC_TX_CFG);
- wr32(wx, WX_MAC_TX_CFG, (reg & ~WX_MAC_TX_CFG_SPEED_MASK) | WX_MAC_TX_CFG_SPEED_10G);
-
/* enable transmits */
- netif_tx_start_all_queues(wx->netdev);
- netif_carrier_on(wx->netdev);
+ netif_tx_start_all_queues(netdev);
}
static void txgbe_reset(struct wx *wx)
@@ -264,7 +258,6 @@ static void txgbe_disable_device(struct wx *wx)
wx_disable_rx_queue(wx, wx->rx_ring[i]);
netif_tx_stop_all_queues(netdev);
- netif_carrier_off(netdev);
netif_tx_disable(netdev);
wx_irq_disable(wx);
@@ -295,8 +288,12 @@ static void txgbe_disable_device(struct wx *wx)
static void txgbe_down(struct wx *wx)
{
+ struct net_device *netdev = wx->netdev;
+ struct txgbe *txgbe = netdev_to_txgbe(netdev);
+
txgbe_disable_device(wx);
txgbe_reset(wx);
+ phylink_stop(txgbe->phylink);
wx_clean_all_tx_rings(wx);
wx_clean_all_rx_rings(wx);
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
index 6dc5e2f5ae59..0e2e9f6e69c3 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
@@ -8,11 +8,13 @@
#include <linux/gpio/driver.h>
#include <linux/gpio/property.h>
#include <linux/pcs/pcs-xpcs.h>
+#include <linux/phylink.h>
#include <linux/mdio.h>
#include <linux/i2c.h>
#include <linux/pci.h>
#include "../libwx/wx_type.h"
+#include "../libwx/wx_lib.h"
#include "../libwx/wx_hw.h"
#include "txgbe_type.h"
#include "txgbe_phy.h"
@@ -153,6 +155,95 @@ static int txgbe_mdio_pcs_init(struct txgbe *txgbe)
return 0;
}
+static struct phylink_pcs *txgbe_phylink_mac_select(struct phylink_config *config,
+ phy_interface_t interface)
+{
+ struct txgbe *txgbe = netdev_to_txgbe(to_net_dev(config->dev));
+
+ return &txgbe->xpcs->pcs;
+}
+
+static void txgbe_mac_config(struct phylink_config *config, unsigned int mode,
+ const struct phylink_link_state *state)
+{
+}
+
+static void txgbe_mac_link_down(struct phylink_config *config,
+ unsigned int mode, phy_interface_t interface)
+{
+ struct wx *wx = netdev_priv(to_net_dev(config->dev));
+
+ wr32m(wx, WX_MAC_TX_CFG, WX_MAC_TX_CFG_TE, 0);
+}
+
+static void txgbe_mac_link_up(struct phylink_config *config,
+ struct phy_device *phy,
+ unsigned int mode, phy_interface_t interface,
+ int speed, int duplex,
+ bool tx_pause, bool rx_pause)
+{
+ struct wx *wx = netdev_priv(to_net_dev(config->dev));
+ u32 txcfg, wdg;
+
+ txcfg = rd32(wx, WX_MAC_TX_CFG);
+ txcfg &= ~WX_MAC_TX_CFG_SPEED_MASK;
+
+ switch (speed) {
+ case SPEED_10000:
+ txcfg |= WX_MAC_TX_CFG_SPEED_10G;
+ break;
+ case SPEED_1000:
+ case SPEED_100:
+ case SPEED_10:
+ txcfg |= WX_MAC_TX_CFG_SPEED_1G;
+ break;
+ default:
+ break;
+ }
+
+ wr32(wx, WX_MAC_TX_CFG, txcfg | WX_MAC_TX_CFG_TE);
+
+ /* Re configure MAC Rx */
+ wr32m(wx, WX_MAC_RX_CFG, WX_MAC_RX_CFG_RE, WX_MAC_RX_CFG_RE);
+ wr32(wx, WX_MAC_PKT_FLT, WX_MAC_PKT_FLT_PR);
+ wdg = rd32(wx, WX_MAC_WDG_TIMEOUT);
+ wr32(wx, WX_MAC_WDG_TIMEOUT, wdg);
+}
+
+static const struct phylink_mac_ops txgbe_mac_ops = {
+ .mac_select_pcs = txgbe_phylink_mac_select,
+ .mac_config = txgbe_mac_config,
+ .mac_link_down = txgbe_mac_link_down,
+ .mac_link_up = txgbe_mac_link_up,
+};
+
+static int txgbe_phylink_init(struct txgbe *txgbe)
+{
+ struct phylink_config *config;
+ struct fwnode_handle *fwnode;
+ struct wx *wx = txgbe->wx;
+ phy_interface_t phy_mode;
+ struct phylink *phylink;
+
+ config = devm_kzalloc(&wx->pdev->dev, sizeof(*config), GFP_KERNEL);
+ if (!config)
+ return -ENOMEM;
+
+ config->dev = &wx->netdev->dev;
+ config->type = PHYLINK_NETDEV;
+ config->mac_capabilities = MAC_10000FD | MAC_1000FD | MAC_SYM_PAUSE | MAC_ASYM_PAUSE;
+ phy_mode = PHY_INTERFACE_MODE_10GBASER;
+ __set_bit(PHY_INTERFACE_MODE_10GBASER, config->supported_interfaces);
+ fwnode = software_node_fwnode(txgbe->nodes.group[SWNODE_PHYLINK]);
+ phylink = phylink_create(config, fwnode, phy_mode, &txgbe_mac_ops);
+ if (IS_ERR(phylink))
+ return PTR_ERR(phylink);
+
+ txgbe->phylink = phylink;
+
+ return 0;
+}
+
static int txgbe_i2c_register(struct txgbe *txgbe)
{
struct pci_dev *pdev = txgbe->wx->pdev;
@@ -333,7 +424,9 @@ static void txgbe_irq_handler(struct irq_desc *desc)
irq_hw_number_t hwirq;
unsigned long gpioirq;
struct gpio_chip *gc;
- u32 gpio;
+ u32 gpio, eicr, reg;
+
+ eicr = wx_misc_isb(wx, WX_ISB_MISC);
chained_irq_enter(chip, desc);
@@ -350,6 +443,11 @@ static void txgbe_irq_handler(struct irq_desc *desc)
chained_irq_exit(chip, desc);
+ if (eicr & (TXGBE_PX_MISC_ETH_LK | TXGBE_PX_MISC_ETH_LKDN)) {
+ reg = rd32(wx, TXGBE_CFG_PORT_ST);
+ phylink_mac_change(txgbe->phylink, !!(reg & TXGBE_CFG_PORT_ST_LINK_UP));
+ }
+
/* unmask interrupt */
if (netif_running(wx->netdev))
wx_intr_enable(wx, TXGBE_INTR_MISC(wx));
@@ -440,6 +538,12 @@ int txgbe_init_phy(struct txgbe *txgbe)
goto err;
}
+ ret = txgbe_phylink_init(txgbe);
+ if (ret) {
+ wx_err(txgbe->wx, "failed to init phylink\n");
+ goto err;
+ }
+
ret = txgbe_i2c_register(txgbe);
if (ret) {
wx_err(txgbe->wx, "failed to init i2c interface: %d\n", ret);
@@ -468,6 +572,8 @@ int txgbe_init_phy(struct txgbe *txgbe)
void txgbe_remove_phy(struct txgbe *txgbe)
{
+ if (txgbe->phylink)
+ phylink_destroy(txgbe->phylink);
if (txgbe->xpcs)
xpcs_destroy(txgbe->xpcs);
if (txgbe->sfp_dev)
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
index 89a635593ae2..95ed19912a34 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
@@ -80,6 +80,10 @@
TXGBE_PX_MISC_INT_ERR | \
TXGBE_PX_MISC_GPIO)
+/* Port cfg registers */
+#define TXGBE_CFG_PORT_ST 0x14404
+#define TXGBE_CFG_PORT_ST_LINK_UP BIT(0)
+
/* I2C registers */
#define TXGBE_I2C_BASE 0x14900
@@ -180,6 +184,7 @@ struct txgbe {
struct txgbe_nodes nodes;
struct mdio_device *mdiodev;
struct dw_xpcs *xpcs;
+ struct phylink *phylink;
struct platform_device *sfp_dev;
struct platform_device *i2c_dev;
struct gpio_chip *gpio;
--
2.27.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* Re: [PATCH net-next v3 6/8] net: pcs: Add 10GBASE-R mode for Synopsys Designware XPCS
2023-04-19 8:27 ` [PATCH net-next v3 6/8] net: pcs: Add 10GBASE-R mode for Synopsys Designware XPCS Jiawen Wu
@ 2023-04-19 13:19 ` Vladimir Oltean
2023-04-20 1:56 ` Jiawen Wu
0 siblings, 1 reply; 28+ messages in thread
From: Vladimir Oltean @ 2023-04-19 13:19 UTC (permalink / raw)
To: Jiawen Wu; +Cc: netdev, linux, linux-i2c, linux-gpio, mengyuanlou, Jose Abreu
On Wed, Apr 19, 2023 at 04:27:37PM +0800, Jiawen Wu wrote:
> Add basic support for XPCS using 10GBASE-R interface. This mode will
> be extended to use interrupt, so set pcs.poll false. And avoid soft
> reset so that the device using this mode is in the default configuration.
I'm not clear why the xpcs_soft_reset() call is avoided. Isn't the
out-of-reset configuration the "default" one?
> +static int xpcs_get_state_10gbaser(struct dw_xpcs *xpcs,
> + struct phylink_link_state *state)
> +{
> + int ret;
> +
> + state->link = false;
> +
> + ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_STAT1);
> + if (ret < 0)
> + return ret;
> +
> + if (ret & MDIO_STAT1_LSTATUS)
> + state->link = true;
> +
> + if (state->link) {
It seems pointless to open a new "if" statement when this would have
sufficed:
if (ret & MDIO_STAT1_LSTATUS) {
state->link = true;
state->pause = MLO_PAUSE_TX | MLO_PAUSE_RX;
...
}
> + state->pause = MLO_PAUSE_TX | MLO_PAUSE_RX;
> + state->duplex = DUPLEX_FULL;
> + state->speed = SPEED_10000;
> + }
> +
> + return 0;
> +}
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH net-next v3 0/8] TXGBE PHYLINK support
2023-04-19 8:27 [PATCH net-next v3 0/8] TXGBE PHYLINK support Jiawen Wu
` (7 preceding siblings ...)
2023-04-19 8:27 ` [PATCH net-next v3 8/8] net: txgbe: Support phylink MAC layer Jiawen Wu
@ 2023-04-19 13:39 ` Vladimir Oltean
8 siblings, 0 replies; 28+ messages in thread
From: Vladimir Oltean @ 2023-04-19 13:39 UTC (permalink / raw)
To: Jiawen Wu; +Cc: netdev, linux, linux-i2c, linux-gpio, mengyuanlou
On Wed, Apr 19, 2023 at 04:27:31PM +0800, Jiawen Wu wrote:
> Implement I2C, SFP, GPIO and PHYLINK to setup TXGBE link and switch link
> rate based on optical module information.
>
> Because our I2C and PCS are based on Synopsys Designware IP-core, extend
> the i2c-designware and pcs-xpcs driver to realize our functions.
For next patch versions, please copy the maintainers/reviewers listed
under "SFF/SFP/SFP+ MODULE SUPPORT", "SOFTWARE NODES AND DEVICE PROPERTIES",
"ETHERNET PHY LIBRARY".
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH net-next v3 4/8] net: txgbe: Add SFP module identify
2023-04-19 8:27 ` [PATCH net-next v3 4/8] net: txgbe: Add SFP module identify Jiawen Wu
@ 2023-04-19 13:55 ` Vladimir Oltean
0 siblings, 0 replies; 28+ messages in thread
From: Vladimir Oltean @ 2023-04-19 13:55 UTC (permalink / raw)
To: Jiawen Wu; +Cc: netdev, linux, linux-i2c, linux-gpio, mengyuanlou
On Wed, Apr 19, 2023 at 04:27:35PM +0800, Jiawen Wu wrote:
> + ret = txgbe_sfp_register(txgbe);
> + if (ret) {
> + wx_err(txgbe->wx, "failed to register sfp\n");
> + goto err;
> + }
The usual error handling pattern is to jump to specific labels within
the error unwind code path (which duplicates the normal teardown path
except for the first operation), rather than calling the single cleanup
function - here txgbe_remove_phy() - and filling that with "if" conditions.
Normally (at least in the networking layer except for Qdiscs, that's all
I know), one would expect that if txgbe_init_phy() fails, txgbe_remove_phy()
is never called. So, given that expectation, txgbe->sfp_dev would never
be NULL.
> +
> return 0;
>
> err:
> @@ -131,6 +156,8 @@ int txgbe_init_phy(struct txgbe *txgbe)
>
> void txgbe_remove_phy(struct txgbe *txgbe)
> {
> + if (txgbe->sfp_dev)
> + platform_device_unregister(txgbe->sfp_dev);
> if (txgbe->i2c_dev)
> platform_device_unregister(txgbe->i2c_dev);
>
> diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
> index 771aefbc7c80..aa94c4fce311 100644
> --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
> +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
> @@ -149,6 +149,7 @@ struct txgbe_nodes {
> struct txgbe {
> struct wx *wx;
> struct txgbe_nodes nodes;
> + struct platform_device *sfp_dev;
> struct platform_device *i2c_dev;
> };
>
> --
> 2.27.0
>
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH net-next v3 2/8] i2c: designware: Add driver support for Wangxun 10Gb NIC
2023-04-19 8:27 ` [PATCH net-next v3 2/8] i2c: designware: Add driver support for Wangxun 10Gb NIC Jiawen Wu
@ 2023-04-19 14:36 ` Jarkko Nikula
2023-04-20 10:49 ` Jiawen Wu
2023-04-19 20:58 ` Andrew Lunn
1 sibling, 1 reply; 28+ messages in thread
From: Jarkko Nikula @ 2023-04-19 14:36 UTC (permalink / raw)
To: Jiawen Wu, netdev, linux; +Cc: linux-i2c, linux-gpio, olteanv, mengyuanlou
Hi
On 4/19/23 11:27, Jiawen Wu wrote:
> Wangxun 10Gb ethernet chip is connected to Designware I2C, to communicate
> with SFP.
>
> Add platform data to pass IOMEM base address, board flag and other
> parameters, since resource address was mapped on ethernet driver.
>
> The exists IP limitations are dealt as workarounds:
> - IP does not support interrupt mode, it works on polling mode.
> - I2C cannot read continuously, only one byte can at a time.
> - Additionally set FIFO depth address the chip issue.
>
> Cc: Jarkko Nikula <jarkko.nikula@linux.intel.com>
>
> Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
> ---
> drivers/i2c/busses/i2c-designware-common.c | 4 +
> drivers/i2c/busses/i2c-designware-core.h | 1 +
> drivers/i2c/busses/i2c-designware-master.c | 91 ++++++++++++++++++++-
> drivers/i2c/busses/i2c-designware-platdrv.c | 36 +++++++-
> include/linux/platform_data/i2c-dw.h | 15 ++++
> 5 files changed, 143 insertions(+), 4 deletions(-)
> create mode 100644 include/linux/platform_data/i2c-dw.h
>
> diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c
> index 0dc6b1ce663f..e4faab4655cb 100644
> --- a/drivers/i2c/busses/i2c-designware-common.c
> +++ b/drivers/i2c/busses/i2c-designware-common.c
> @@ -588,6 +588,10 @@ int i2c_dw_set_fifo_size(struct dw_i2c_dev *dev)
> if (ret)
> return ret;
>
> + /* workaround for IP hardware issue */
> + if ((dev->flags & MODEL_MASK) == MODEL_WANGXUN_SP)
> + param |= 0x80800;
> +
What is the issue here? Is register DW_IC_COMP_PARAM_1 implemented? If
not then I think safer is not to even read it lines before this added test.
> +static int txgbe_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msgs,
> + int num_msgs)
> +{
> + struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
> + int msg_idx, buf_len, data_idx, ret;
> + unsigned int val;
> + u8 dev_addr;
> + u8 *buf;
> +
> + dev->msgs = msgs;
> + dev->msgs_num = num_msgs;
> + i2c_dw_xfer_init(dev);
> + regmap_write(dev->map, DW_IC_INTR_MASK, 0);
> +
> + dev_addr = msgs[0].buf[0];
> +
> + for (msg_idx = 0; msg_idx < num_msgs; msg_idx++) {
> + buf = msgs[msg_idx].buf;
> + buf_len = msgs[msg_idx].len;
> +
> + for (data_idx = 0; data_idx < buf_len; data_idx++) {
> + if (msgs[msg_idx].flags & I2C_M_RD) {
> + ret = i2c_dw_poll_tx_empty(dev);
> + if (ret)
> + return ret;
> +
> + regmap_write(dev->map, DW_IC_DATA_CMD,
> + (dev_addr + data_idx) | BIT(9));
> + regmap_write(dev->map, DW_IC_DATA_CMD, 0x100 | BIT(9));
> +
Am I wrong but this looks tailored to the use-case rather than generic
implementation? I don't understand what is this write command with data
(dev_addr + data_idx) + STOP followed by read command with STOP.
DW_IC_DATA_CMD upper bits have following meaning:
BIT(8) == 0x100: 1 = read, 0 = write
BIT(9): Stop issued after this byte
BIT(10): RESTART is issued before the byte is sent or received
> + } else {
> + ret = i2c_dw_poll_tx_empty(dev);
> + if (ret)
> + return ret;
> +
> + regmap_write(dev->map, DW_IC_DATA_CMD, buf[data_idx]);
> + if (data_idx == (buf_len - 1))
> + regmap_write(dev->map, DW_IC_DATA_CMD, BIT(9));
I think these separate writes must be combined if I'm not wrong? I
believe this cause needless extra zero byte + STOP transferred on the
bus instead of last buffer byte + STOP?
> --- a/drivers/i2c/busses/i2c-designware-platdrv.c
> +++ b/drivers/i2c/busses/i2c-designware-platdrv.c
> +static void dw_i2c_get_plat_data(struct dw_i2c_dev *dev)
> +{
> + struct platform_device *pdev = to_platform_device(dev->dev);
> + struct dw_i2c_platform_data *pdata;
> +
> + pdata = dev_get_platdata(&pdev->dev);
> + if (!pdata)
> + return;
> +
> + dev->flags |= pdata->flags;
> + dev->base = pdata->base;
> +
> + if (pdata->ss_hcnt && pdata->ss_lcnt) {
> + dev->ss_hcnt = pdata->ss_hcnt;
> + dev->ss_lcnt = pdata->ss_lcnt;
> + } else {
> + dev->ss_hcnt = 6;
> + dev->ss_lcnt = 8;
> + }
> +
> + if (pdata->fs_hcnt && pdata->fs_lcnt) {
> + dev->fs_hcnt = pdata->fs_hcnt;
> + dev->fs_lcnt = pdata->fs_lcnt;
> + } else {
> + dev->fs_hcnt = 6;
> + dev->fs_lcnt = 8;
> + }
> +}
> +
> static const struct dmi_system_id dw_i2c_hwmon_class_dmi[] = {
> {
> .ident = "Qtechnology QT5222",
> @@ -282,6 +314,8 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
> dev->irq = irq;
> platform_set_drvdata(pdev, dev);
>
> + dw_i2c_get_plat_data(dev);
> +
Instead of this added code would it be possible to use generic timing
parameters which can come either from firmware or code? Those are
handled already here by the call to i2c_parse_fw_timings().
Then drivers/i2c/busses/i2c-designware-master.c:
i2c_dw_set_timings_master() takes care of calculating Designware
specific hcnt/lcnt timing parameters from those generic values.
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH net-next v3 1/8] net: txgbe: Add software nodes to support phylink
2023-04-19 8:27 ` [PATCH net-next v3 1/8] net: txgbe: Add software nodes to support phylink Jiawen Wu
@ 2023-04-19 20:53 ` Andrew Lunn
0 siblings, 0 replies; 28+ messages in thread
From: Andrew Lunn @ 2023-04-19 20:53 UTC (permalink / raw)
To: Jiawen Wu; +Cc: netdev, linux, linux-i2c, linux-gpio, olteanv, mengyuanlou
On Wed, Apr 19, 2023 at 04:27:32PM +0800, Jiawen Wu wrote:
> Register software nodes for GPIO, I2C, SFP and PHYLINK. Define the
> device properties.
>
> Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Andrew
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH net-next v3 2/8] i2c: designware: Add driver support for Wangxun 10Gb NIC
2023-04-19 8:27 ` [PATCH net-next v3 2/8] i2c: designware: Add driver support for Wangxun 10Gb NIC Jiawen Wu
2023-04-19 14:36 ` Jarkko Nikula
@ 2023-04-19 20:58 ` Andrew Lunn
2023-04-20 10:29 ` Jiawen Wu
1 sibling, 1 reply; 28+ messages in thread
From: Andrew Lunn @ 2023-04-19 20:58 UTC (permalink / raw)
To: Jiawen Wu
Cc: netdev, linux, linux-i2c, linux-gpio, olteanv, mengyuanlou,
Jarkko Nikula
On Wed, Apr 19, 2023 at 04:27:33PM +0800, Jiawen Wu wrote:
> Wangxun 10Gb ethernet chip is connected to Designware I2C, to communicate
> with SFP.
>
> Add platform data to pass IOMEM base address, board flag and other
> parameters, since resource address was mapped on ethernet driver.
>
> The exists IP limitations are dealt as workarounds:
> - IP does not support interrupt mode, it works on polling mode.
> - I2C cannot read continuously, only one byte can at a time.
Are you really sure about that?
It is a major limitation for SFP devices. It means you cannot access
the diagnostics, since you need to perform an atomic 2 byte read.
Or maybe i'm understanding you wrong.
Andrew
^ permalink raw reply [flat|nested] 28+ messages in thread
* RE: [PATCH net-next v3 6/8] net: pcs: Add 10GBASE-R mode for Synopsys Designware XPCS
2023-04-19 13:19 ` Vladimir Oltean
@ 2023-04-20 1:56 ` Jiawen Wu
2023-04-20 8:03 ` Vladimir Oltean
0 siblings, 1 reply; 28+ messages in thread
From: Jiawen Wu @ 2023-04-20 1:56 UTC (permalink / raw)
To: 'Vladimir Oltean'
Cc: netdev, linux, linux-i2c, linux-gpio, mengyuanlou,
'Jose Abreu'
On Wednesday, April 19, 2023 9:20 PM, Vladimir Oltean wrote:
> On Wed, Apr 19, 2023 at 04:27:37PM +0800, Jiawen Wu wrote:
> > Add basic support for XPCS using 10GBASE-R interface. This mode will
> > be extended to use interrupt, so set pcs.poll false. And avoid soft
> > reset so that the device using this mode is in the default configuration.
>
> I'm not clear why the xpcs_soft_reset() call is avoided. Isn't the
> out-of-reset configuration the "default" one?
>
Theoretically so, I need to configure 10GBASE-R mode after reset. But this
configuration involves board info to configure PMA, etc., I'd like to implement
it in the next patch. Now the "default" configuration refers to the mode in
which the firmware is configured.
> > +static int xpcs_get_state_10gbaser(struct dw_xpcs *xpcs,
> > + struct phylink_link_state *state)
> > +{
> > + int ret;
> > +
> > + state->link = false;
> > +
> > + ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_STAT1);
> > + if (ret < 0)
> > + return ret;
> > +
> > + if (ret & MDIO_STAT1_LSTATUS)
> > + state->link = true;
> > +
> > + if (state->link) {
>
> It seems pointless to open a new "if" statement when this would have
> sufficed:
>
> if (ret & MDIO_STAT1_LSTATUS) {
> state->link = true;
> state->pause = MLO_PAUSE_TX | MLO_PAUSE_RX;
> ...
> }
>
> > + state->pause = MLO_PAUSE_TX | MLO_PAUSE_RX;
> > + state->duplex = DUPLEX_FULL;
> > + state->speed = SPEED_10000;
> > + }
> > +
> > + return 0;
> > +}
>
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH net-next v3 6/8] net: pcs: Add 10GBASE-R mode for Synopsys Designware XPCS
2023-04-20 1:56 ` Jiawen Wu
@ 2023-04-20 8:03 ` Vladimir Oltean
2023-04-20 8:38 ` Jiawen Wu
0 siblings, 1 reply; 28+ messages in thread
From: Vladimir Oltean @ 2023-04-20 8:03 UTC (permalink / raw)
To: Jiawen Wu
Cc: netdev, linux, linux-i2c, linux-gpio, mengyuanlou,
'Jose Abreu'
On Thu, Apr 20, 2023 at 09:56:26AM +0800, Jiawen Wu wrote:
> On Wednesday, April 19, 2023 9:20 PM, Vladimir Oltean wrote:
> > On Wed, Apr 19, 2023 at 04:27:37PM +0800, Jiawen Wu wrote:
> > > Add basic support for XPCS using 10GBASE-R interface. This mode will
> > > be extended to use interrupt, so set pcs.poll false. And avoid soft
> > > reset so that the device using this mode is in the default configuration.
> >
> > I'm not clear why the xpcs_soft_reset() call is avoided. Isn't the
> > out-of-reset configuration the "default" one?
>
> Theoretically so, I need to configure 10GBASE-R mode after reset. But this
> configuration involves board info to configure PMA, etc., I'd like to implement
> it in the next patch. Now the "default" configuration refers to the mode in
> which the firmware is configured.
How much extra complexity are we talking about, to not depend on the
configuration done by the bootloader?
^ permalink raw reply [flat|nested] 28+ messages in thread
* RE: [PATCH net-next v3 6/8] net: pcs: Add 10GBASE-R mode for Synopsys Designware XPCS
2023-04-20 8:03 ` Vladimir Oltean
@ 2023-04-20 8:38 ` Jiawen Wu
2023-04-20 8:52 ` Vladimir Oltean
0 siblings, 1 reply; 28+ messages in thread
From: Jiawen Wu @ 2023-04-20 8:38 UTC (permalink / raw)
To: 'Vladimir Oltean'
Cc: netdev, linux, linux-i2c, linux-gpio, mengyuanlou,
'Jose Abreu'
On Thursday, April 20, 2023 4:03 PM, Vladimir Oltean wrote:
> On Thu, Apr 20, 2023 at 09:56:26AM +0800, Jiawen Wu wrote:
> > On Wednesday, April 19, 2023 9:20 PM, Vladimir Oltean wrote:
> > > On Wed, Apr 19, 2023 at 04:27:37PM +0800, Jiawen Wu wrote:
> > > > Add basic support for XPCS using 10GBASE-R interface. This mode will
> > > > be extended to use interrupt, so set pcs.poll false. And avoid soft
> > > > reset so that the device using this mode is in the default configuration.
> > >
> > > I'm not clear why the xpcs_soft_reset() call is avoided. Isn't the
> > > out-of-reset configuration the "default" one?
> >
> > Theoretically so, I need to configure 10GBASE-R mode after reset. But this
> > configuration involves board info to configure PMA, etc., I'd like to implement
> > it in the next patch. Now the "default" configuration refers to the mode in
> > which the firmware is configured.
>
> How much extra complexity are we talking about, to not depend on the
> configuration done by the bootloader?
>
It needs to implement compat->pma_config, and add a flag in struct dw_xpcs
to indicate board with specific pma configuration. For 10GBASE-R interface, it
relatively simple, but a bit more complicate for 1000BASE-X since there are
logic conflicts in xpcs_do_config(), I haven't resolved yet.
In addition, reconfiguring XPCS will cause some known issues that I need to
workaround in the ethernet driver. So I'd like to add configuration when I
implement rate switching.
There is a piece codes for my test:
+static int xpcs_read_pma(struct dw_xpcs *xpcs, int reg)
+{
+ return xpcs_read(xpcs, MDIO_MMD_PMAPMD, DW_PMA_MMD + reg);
+}
+
+static int xpcs_write_pma(struct dw_xpcs *xpcs, int reg, u16 val)
+{
+ return xpcs_write(xpcs, MDIO_MMD_PMAPMD, DW_PMA_MMD + reg, val);
+}
+
+static int xpcs_poll_power_up(struct dw_xpcs *xpcs)
+{
+ int val, ret;
+
+ /* Wait xpcs power-up good */
+ ret = read_poll_timeout(xpcs_read_vpcs, val,
+ (val & DW_VR_XS_PCS_DIG_STS_PSEQ_ST) ==
+ DW_VR_XS_PCS_DIG_STS_PSEQ_ST_GOOD,
+ 10000, 1000000, false,
+ xpcs, DW_VR_XS_PCS_DIG_STS);
+ if (ret < 0)
+ pr_err("%s: xpcs power-up timeout\n", __func__);
+
+ return ret;
+}
+
+static int xpcs_pma_init_done(struct dw_xpcs *xpcs)
+{
+ int val, ret;
+
+ xpcs_write_vpcs(xpcs, DW_VR_XS_PCS_DIG_CTRL1,
+ DW_VR_XS_PCS_DIG_CTRL1_VR_RST |
+ DW_VR_XS_PCS_DIG_CTRL1_EN_VSMMD1);
+
+ /* wait pma initialization done */
+ ret = read_poll_timeout(xpcs_read_vpcs, val,
+ !(val & DW_VR_XS_PCS_DIG_CTRL1_VR_RST),
+ 100000, 10000000, false,
+ xpcs, DW_VR_XS_PCS_DIG_CTRL1);
+ if (ret < 0)
+ pr_err("%s: xpcs pma initialization timeout\n", __func__);
+
+ return ret;
+}
+
+static int xpcs_10gbaser_pma_config_wx(struct dw_xpcs *xpcs)
+{
+ int val, ret;
+
+ ret = xpcs_poll_power_up(xpcs);
+ if (ret < 0)
+ return ret;
+
+ xpcs_write(xpcs, MDIO_MMD_PCS, MDIO_CTRL2, MDIO_PCS_CTRL2_10GBR);
+ val = xpcs_read(xpcs, MDIO_MMD_PMAPMD, MDIO_CTRL1);
+ val |= MDIO_CTRL1_SPEED10G;
+ xpcs_write(xpcs, MDIO_MMD_PMAPMD, MDIO_CTRL1, val);
+
+ xpcs_write_pma(xpcs, DW_VR_XS_PMA_MPLLA_CTL0, 0x21);
+ xpcs_write_pma(xpcs, DW_VR_XS_PMA_MPLLA_CTL3, 0);
+ val = xpcs_read_pma(xpcs, DW_VR_XS_PMA_TX_GENCTL1);
+ val = u16_replace_bits(val, 0x5, DW_VR_XS_PMA_TX_GENCTL1_VBOOST_LVL);
+ xpcs_write_pma(xpcs, DW_VR_XS_PMA_TX_GENCTL1, val);
+ xpcs_write_pma(xpcs, DW_VR_XS_PMA_MISC_CTL0, 0xCF00);
+ xpcs_write_pma(xpcs, DW_VR_XS_PMA_VCO_CAL_LD0, 0x549);
+ xpcs_write_pma(xpcs, DW_VR_XS_PMA_VCO_CAL_REF0, 0x29);
+ xpcs_write_pma(xpcs, DW_VR_XS_PMA_TX_RATE_CTL, 0);
+ xpcs_write_pma(xpcs, DW_VR_XS_PMA_RX_RATE_CTL, 0);
+ xpcs_write_pma(xpcs, DW_VR_XS_PMA_TX_GEN_CTL2, 0x300);
+ xpcs_write_pma(xpcs, DW_VR_XS_PMA_RX_GEN_CTL2, 0x300);
+ xpcs_write_pma(xpcs, DW_VR_XS_PMA_MPLLA_CTL2, 0x600);
+
+ xpcs_write_pma(xpcs, DW_VR_XS_PMA_RX_EQ_CTL0, 0x45);
+ val = xpcs_read_pma(xpcs, DW_VR_XS_PMA_RX_EQ_ATTN_CTL);
+ val &= ~DW_VR_XS_PMA_RX_EQ_ATTN_LVL0;
+ xpcs_write_pma(xpcs, DW_VR_XS_PMA_RX_EQ_ATTN_CTL, val);
+ xpcs_write_pma(xpcs, DW_VR_XS_PMA_DFE_TAP_CTL0, 0xBE);
+ val = xpcs_read_pma(xpcs, DW_VR_XS_PMA_AFE_DFE_ENABLE);
+ val &= ~(DW_VR_XS_PMA_DFE_EN_0 | DW_VR_XS_PMA_AFE_EN_0);
+ xpcs_write_pma(xpcs, DW_VR_XS_PMA_AFE_DFE_ENABLE, val);
+ val = xpcs_read_pma(xpcs, DW_VR_XS_PMA_RX_EQ_CTL4);
+ val &= ~DW_VR_XS_PMA_RX_EQ_CTL4_CONT_ADAPT0;
+ xpcs_write_pma(xpcs, DW_VR_XS_PMA_RX_EQ_CTL4, val);
+
+ return xpcs_pma_init_done(xpcs);
+}
+
+static int xpcs_10gbaser_pma_config(struct dw_xpcs *xpcs)
+{
+ if (xpcs->flags & DW_MODEL_WANGXUN_SP)
+ return xpcs_10gbaser_pma_config_wx(xpcs);
+
+ return 0;
+}
+
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH net-next v3 6/8] net: pcs: Add 10GBASE-R mode for Synopsys Designware XPCS
2023-04-20 8:38 ` Jiawen Wu
@ 2023-04-20 8:52 ` Vladimir Oltean
2023-04-20 9:32 ` Jiawen Wu
0 siblings, 1 reply; 28+ messages in thread
From: Vladimir Oltean @ 2023-04-20 8:52 UTC (permalink / raw)
To: Jiawen Wu
Cc: netdev, linux, linux-i2c, linux-gpio, mengyuanlou,
'Jose Abreu'
On Thu, Apr 20, 2023 at 04:38:48PM +0800, Jiawen Wu wrote:
> It needs to implement compat->pma_config, and add a flag in struct dw_xpcs
> to indicate board with specific pma configuration. For 10GBASE-R interface, it
> relatively simple, but a bit more complicate for 1000BASE-X since there are
> logic conflicts in xpcs_do_config(), I haven't resolved yet.
>
> In addition, reconfiguring XPCS will cause some known issues that I need to
> workaround in the ethernet driver. So I'd like to add configuration when I
> implement rate switching.
>
> There is a piece codes for my test:
The PMA initialization procedure looks pretty clean to me (although I'm
not clear why it depends upon xpcs->flags & DW_MODEL_WANGXUN_SP when the
registers seem to be present in the common databook), and having it in
the XPCS driver seems much preferable to depending on an unknown previous
initialization stage.
Could you detail a bit the known issues and the 1000BASE-X conflicts in
xpcs_do_config()?
^ permalink raw reply [flat|nested] 28+ messages in thread
* RE: [PATCH net-next v3 6/8] net: pcs: Add 10GBASE-R mode for Synopsys Designware XPCS
2023-04-20 8:52 ` Vladimir Oltean
@ 2023-04-20 9:32 ` Jiawen Wu
0 siblings, 0 replies; 28+ messages in thread
From: Jiawen Wu @ 2023-04-20 9:32 UTC (permalink / raw)
To: 'Vladimir Oltean'
Cc: netdev, linux, linux-i2c, linux-gpio, mengyuanlou,
'Jose Abreu'
On Thursday, April 20, 2023 4:52 PM, Vladimir Oltean wrote:
> On Thu, Apr 20, 2023 at 04:38:48PM +0800, Jiawen Wu wrote:
> > It needs to implement compat->pma_config, and add a flag in struct dw_xpcs
> > to indicate board with specific pma configuration. For 10GBASE-R interface, it
> > relatively simple, but a bit more complicate for 1000BASE-X since there are
> > logic conflicts in xpcs_do_config(), I haven't resolved yet.
> >
> > In addition, reconfiguring XPCS will cause some known issues that I need to
> > workaround in the ethernet driver. So I'd like to add configuration when I
> > implement rate switching.
> >
> > There is a piece codes for my test:
>
> The PMA initialization procedure looks pretty clean to me (although I'm
> not clear why it depends upon xpcs->flags & DW_MODEL_WANGXUN_SP when the
> registers seem to be present in the common databook), and having it in
> the XPCS driver seems much preferable to depending on an unknown previous
> initialization stage.
The values configured in PMA depend on the board signal quality, Synopsys once
provided the values based on our board information, but we don't know the details
of the computation. So I don't think it's universal.
>
> Could you detail a bit the known issues and the 1000BASE-X conflicts in
> xpcs_do_config()?
>
Known issue is that traffic must be totally stopped while the PMA is being configured.
And XPCS should add a judgment that PMA only need to be reconfigured when
interface is changed.
In 1000BASE-X interface, for my current testing, PMA configuration should precede
AN configuration, and need to set PCS_DIG_CTRL1 reg? My test code for AN config:
+static int xpcs_config_aneg_c37_1000basex_wx(struct dw_xpcs *xpcs, unsigned int mode,
+ const unsigned long *advertising)
+{
+
+ xpcs_write(xpcs, MDIO_MMD_PCS, DW_VR_MII_DIG_CTRL1, 0x3002);
+ xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL, 0x0109);
+ xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1, 0x0200);
+ ret = xpcs_read(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1);
+ ret |= BMCR_ANENABLE;
+ xpcs_write(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1, ret);
+}
^ permalink raw reply [flat|nested] 28+ messages in thread
* RE: [PATCH net-next v3 2/8] i2c: designware: Add driver support for Wangxun 10Gb NIC
2023-04-19 20:58 ` Andrew Lunn
@ 2023-04-20 10:29 ` Jiawen Wu
2023-04-20 13:22 ` Andrew Lunn
2023-04-21 6:52 ` Jarkko Nikula
0 siblings, 2 replies; 28+ messages in thread
From: Jiawen Wu @ 2023-04-20 10:29 UTC (permalink / raw)
To: 'Andrew Lunn'
Cc: netdev, linux, linux-i2c, linux-gpio, olteanv, mengyuanlou,
'Jarkko Nikula'
On Thursday, April 20, 2023 4:58 AM, Andrew Lunn wrote:
> On Wed, Apr 19, 2023 at 04:27:33PM +0800, Jiawen Wu wrote:
> > Wangxun 10Gb ethernet chip is connected to Designware I2C, to communicate
> > with SFP.
> >
> > Add platform data to pass IOMEM base address, board flag and other
> > parameters, since resource address was mapped on ethernet driver.
> >
> > The exists IP limitations are dealt as workarounds:
> > - IP does not support interrupt mode, it works on polling mode.
> > - I2C cannot read continuously, only one byte can at a time.
>
> Are you really sure about that?
>
> It is a major limitation for SFP devices. It means you cannot access
> the diagnostics, since you need to perform an atomic 2 byte read.
>
> Or maybe i'm understanding you wrong.
>
> Andrew
>
Maybe I'm a little confused about this. Every time I read a byte info, I have to
write a 'read command'. It can normally get the information for SFP devices.
But I'm not sure if this is regular I2C behavior.
^ permalink raw reply [flat|nested] 28+ messages in thread
* RE: [PATCH net-next v3 2/8] i2c: designware: Add driver support for Wangxun 10Gb NIC
2023-04-19 14:36 ` Jarkko Nikula
@ 2023-04-20 10:49 ` Jiawen Wu
0 siblings, 0 replies; 28+ messages in thread
From: Jiawen Wu @ 2023-04-20 10:49 UTC (permalink / raw)
To: 'Jarkko Nikula'
Cc: linux-i2c, linux-gpio, olteanv, mengyuanlou, netdev, linux
> > --- a/drivers/i2c/busses/i2c-designware-platdrv.c
> > +++ b/drivers/i2c/busses/i2c-designware-platdrv.c
>
> > +static void dw_i2c_get_plat_data(struct dw_i2c_dev *dev)
> > +{
> > + struct platform_device *pdev = to_platform_device(dev->dev);
> > + struct dw_i2c_platform_data *pdata;
> > +
> > + pdata = dev_get_platdata(&pdev->dev);
> > + if (!pdata)
> > + return;
> > +
> > + dev->flags |= pdata->flags;
> > + dev->base = pdata->base;
> > +
> > + if (pdata->ss_hcnt && pdata->ss_lcnt) {
> > + dev->ss_hcnt = pdata->ss_hcnt;
> > + dev->ss_lcnt = pdata->ss_lcnt;
> > + } else {
> > + dev->ss_hcnt = 6;
> > + dev->ss_lcnt = 8;
> > + }
> > +
> > + if (pdata->fs_hcnt && pdata->fs_lcnt) {
> > + dev->fs_hcnt = pdata->fs_hcnt;
> > + dev->fs_lcnt = pdata->fs_lcnt;
> > + } else {
> > + dev->fs_hcnt = 6;
> > + dev->fs_lcnt = 8;
> > + }
> > +}
> > +
> > static const struct dmi_system_id dw_i2c_hwmon_class_dmi[] = {
> > {
> > .ident = "Qtechnology QT5222",
> > @@ -282,6 +314,8 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
> > dev->irq = irq;
> > platform_set_drvdata(pdev, dev);
> >
> > + dw_i2c_get_plat_data(dev);
> > +
> Instead of this added code would it be possible to use generic timing
> parameters which can come either from firmware or code? Those are
> handled already here by the call to i2c_parse_fw_timings().
>
> Then drivers/i2c/busses/i2c-designware-master.c:
> i2c_dw_set_timings_master() takes care of calculating Designware
> specific hcnt/lcnt timing parameters from those generic values.
>
I am confused about why fs_hcnt/fs_lcnt must be set when I use the
standard mode?
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH net-next v3 2/8] i2c: designware: Add driver support for Wangxun 10Gb NIC
2023-04-20 10:29 ` Jiawen Wu
@ 2023-04-20 13:22 ` Andrew Lunn
2023-04-21 2:20 ` Jiawen Wu
2023-04-21 6:52 ` Jarkko Nikula
1 sibling, 1 reply; 28+ messages in thread
From: Andrew Lunn @ 2023-04-20 13:22 UTC (permalink / raw)
To: Jiawen Wu
Cc: netdev, linux, linux-i2c, linux-gpio, olteanv, mengyuanlou,
'Jarkko Nikula'
On Thu, Apr 20, 2023 at 06:29:11PM +0800, Jiawen Wu wrote:
> On Thursday, April 20, 2023 4:58 AM, Andrew Lunn wrote:
> > On Wed, Apr 19, 2023 at 04:27:33PM +0800, Jiawen Wu wrote:
> > > Wangxun 10Gb ethernet chip is connected to Designware I2C, to communicate
> > > with SFP.
> > >
> > > Add platform data to pass IOMEM base address, board flag and other
> > > parameters, since resource address was mapped on ethernet driver.
> > >
> > > The exists IP limitations are dealt as workarounds:
> > > - IP does not support interrupt mode, it works on polling mode.
> > > - I2C cannot read continuously, only one byte can at a time.
> >
> > Are you really sure about that?
> >
> > It is a major limitation for SFP devices. It means you cannot access
> > the diagnostics, since you need to perform an atomic 2 byte read.
> >
> > Or maybe i'm understanding you wrong.
> >
> > Andrew
> >
>
> Maybe I'm a little confused about this. Every time I read a byte info, I have to
> write a 'read command'. It can normally get the information for SFP devices.
> But I'm not sure if this is regular I2C behavior.
I don't know this hardware, so i cannot say what a 'read command'
actually does. Can you put a bus pirate or similar sort of device on
the bus and look at the actual I2C signals. Is it performing one I2C
transaction per byte? If so, that is not good.
The diagnostic values, things like temperature sensor, voltage sensor,
received signal power are all 16 bits. You cannot read them using two
time one byte reads. Say the first read sees a 16bit value of 0x00FF,
but only reads the first byte. The second read sees a 16bit value of
0x0100 but only reads the second byte. You end up with 0x0000. When
you do a multi byte read, the SFP should do an atomic read of the
sensor, so you would see either 0x00FF, or 0x0100.
If your hardware can only do single byte reads, please make sure the
I2C framework knows this. The SFP driver should then refuse to access
the diagnostic parts of the SFP, because your I2C bus master hardware
is too broken. The rest of the SFP should still work.
Andrew.
^ permalink raw reply [flat|nested] 28+ messages in thread
* RE: [PATCH net-next v3 2/8] i2c: designware: Add driver support for Wangxun 10Gb NIC
2023-04-20 13:22 ` Andrew Lunn
@ 2023-04-21 2:20 ` Jiawen Wu
2023-04-21 12:15 ` Andrew Lunn
0 siblings, 1 reply; 28+ messages in thread
From: Jiawen Wu @ 2023-04-21 2:20 UTC (permalink / raw)
To: 'Andrew Lunn'
Cc: netdev, linux, linux-i2c, linux-gpio, olteanv, mengyuanlou,
'Jarkko Nikula'
On Thursday, April 20, 2023 9:23 PM, Andrew Lunn wrote:
> On Thu, Apr 20, 2023 at 06:29:11PM +0800, Jiawen Wu wrote:
> > On Thursday, April 20, 2023 4:58 AM, Andrew Lunn wrote:
> > > On Wed, Apr 19, 2023 at 04:27:33PM +0800, Jiawen Wu wrote:
> > > > Wangxun 10Gb ethernet chip is connected to Designware I2C, to communicate
> > > > with SFP.
> > > >
> > > > Add platform data to pass IOMEM base address, board flag and other
> > > > parameters, since resource address was mapped on ethernet driver.
> > > >
> > > > The exists IP limitations are dealt as workarounds:
> > > > - IP does not support interrupt mode, it works on polling mode.
> > > > - I2C cannot read continuously, only one byte can at a time.
> > >
> > > Are you really sure about that?
> > >
> > > It is a major limitation for SFP devices. It means you cannot access
> > > the diagnostics, since you need to perform an atomic 2 byte read.
> > >
> > > Or maybe i'm understanding you wrong.
> > >
> > > Andrew
> > >
> >
> > Maybe I'm a little confused about this. Every time I read a byte info, I have to
> > write a 'read command'. It can normally get the information for SFP devices.
> > But I'm not sure if this is regular I2C behavior.
>
> I don't know this hardware, so i cannot say what a 'read command'
> actually does. Can you put a bus pirate or similar sort of device on
> the bus and look at the actual I2C signals. Is it performing one I2C
> transaction per byte? If so, that is not good.
>
> The diagnostic values, things like temperature sensor, voltage sensor,
> received signal power are all 16 bits. You cannot read them using two
> time one byte reads. Say the first read sees a 16bit value of 0x00FF,
> but only reads the first byte. The second read sees a 16bit value of
> 0x0100 but only reads the second byte. You end up with 0x0000. When
> you do a multi byte read, the SFP should do an atomic read of the
> sensor, so you would see either 0x00FF, or 0x0100.
>
> If your hardware can only do single byte reads, please make sure the
> I2C framework knows this. The SFP driver should then refuse to access
> the diagnostic parts of the SFP, because your I2C bus master hardware
> is too broken. The rest of the SFP should still work.
>
> Andrew.
>
You may have misunderstood. If you want to read a 16-bit message, the
size of 'i2c_msg.len' is set to 2 in the array that 'flags = I2C_M_RD'.
For example in sfp_i2c_read(), block_size limits the message length of every
time call i2c_transfer() to read, usually it is 16. The one-byte read limit I
mentioned means that during the 16-byte read, I2C device needs to write a
read command and then read the message 16 times to fill the 16-byte buffer,
instead of reading 16 bytes at once after stop command writes.
Before I thought this behavior might be strange, so I mentioned in the commit.
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH net-next v3 2/8] i2c: designware: Add driver support for Wangxun 10Gb NIC
2023-04-20 10:29 ` Jiawen Wu
2023-04-20 13:22 ` Andrew Lunn
@ 2023-04-21 6:52 ` Jarkko Nikula
2023-04-21 12:22 ` Andrew Lunn
1 sibling, 1 reply; 28+ messages in thread
From: Jarkko Nikula @ 2023-04-21 6:52 UTC (permalink / raw)
To: Jiawen Wu, 'Andrew Lunn'
Cc: netdev, linux, linux-i2c, linux-gpio, olteanv, mengyuanlou
On 4/20/23 13:29, Jiawen Wu wrote:
> On Thursday, April 20, 2023 4:58 AM, Andrew Lunn wrote:
>> On Wed, Apr 19, 2023 at 04:27:33PM +0800, Jiawen Wu wrote:
>>> Wangxun 10Gb ethernet chip is connected to Designware I2C, to communicate
>>> with SFP.
>>>
>>> Add platform data to pass IOMEM base address, board flag and other
>>> parameters, since resource address was mapped on ethernet driver.
>>>
>>> The exists IP limitations are dealt as workarounds:
>>> - IP does not support interrupt mode, it works on polling mode.
>>> - I2C cannot read continuously, only one byte can at a time.
>>
>> Are you really sure about that?
>>
>> It is a major limitation for SFP devices. It means you cannot access
>> the diagnostics, since you need to perform an atomic 2 byte read.
>>
>> Or maybe i'm understanding you wrong.
>>
>> Andrew
>>
>
> Maybe I'm a little confused about this. Every time I read a byte info, I have to
> write a 'read command'. It can normally get the information for SFP devices.
> But I'm not sure if this is regular I2C behavior.
>
I agree, IC_DATA_CMD operation is obscure. In order to read from the
bus, writes with BIT(8) set is required into IC_DATA_CMD, wait
(irq/poll) DW_IC_INTR_RX_FULL is set in DW_IC_RAW_INTR_STAT and then
read back received data from IC_DATA_CMD while taking into count FIFO sizes.
Full documentation of this IP is in DesignWare DW_apb_i2c Databook. You
may try to get access to Synopsys or try to find if older version of it
is available somewhere.
https://www.synopsys.com/dw/ipdir.php?c=DW_apb_i2c
Plain register specifications can be found from some of the Intel
datasheets. For example chapter 13.2 I2C Memory Mapped Registers
Summary, page 667 in a datasheet below:
https://cdrdv2-public.intel.com/743845/743845_001.pdf
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH net-next v3 2/8] i2c: designware: Add driver support for Wangxun 10Gb NIC
2023-04-21 2:20 ` Jiawen Wu
@ 2023-04-21 12:15 ` Andrew Lunn
0 siblings, 0 replies; 28+ messages in thread
From: Andrew Lunn @ 2023-04-21 12:15 UTC (permalink / raw)
To: Jiawen Wu
Cc: netdev, linux, linux-i2c, linux-gpio, olteanv, mengyuanlou,
'Jarkko Nikula'
On Fri, Apr 21, 2023 at 10:20:17AM +0800, Jiawen Wu wrote:
> On Thursday, April 20, 2023 9:23 PM, Andrew Lunn wrote:
> > On Thu, Apr 20, 2023 at 06:29:11PM +0800, Jiawen Wu wrote:
> > > On Thursday, April 20, 2023 4:58 AM, Andrew Lunn wrote:
> > > > On Wed, Apr 19, 2023 at 04:27:33PM +0800, Jiawen Wu wrote:
> > > > > Wangxun 10Gb ethernet chip is connected to Designware I2C, to communicate
> > > > > with SFP.
> > > > >
> > > > > Add platform data to pass IOMEM base address, board flag and other
> > > > > parameters, since resource address was mapped on ethernet driver.
> > > > >
> > > > > The exists IP limitations are dealt as workarounds:
> > > > > - IP does not support interrupt mode, it works on polling mode.
> > > > > - I2C cannot read continuously, only one byte can at a time.
> > > >
> > > > Are you really sure about that?
> > > >
> > > > It is a major limitation for SFP devices. It means you cannot access
> > > > the diagnostics, since you need to perform an atomic 2 byte read.
> > > >
> > > > Or maybe i'm understanding you wrong.
> > > >
> > > > Andrew
> > > >
> > >
> > > Maybe I'm a little confused about this. Every time I read a byte info, I have to
> > > write a 'read command'. It can normally get the information for SFP devices.
> > > But I'm not sure if this is regular I2C behavior.
> >
> > I don't know this hardware, so i cannot say what a 'read command'
> > actually does. Can you put a bus pirate or similar sort of device on
> > the bus and look at the actual I2C signals. Is it performing one I2C
> > transaction per byte? If so, that is not good.
....
> You may have misunderstood. If you want to read a 16-bit message, the
> size of 'i2c_msg.len' is set to 2 in the array that 'flags = I2C_M_RD'.
The SFP driver uses a mixture of message lengths, due to SFP bugs. But
in general it will do 16 byte block reads, except for when it needs
smaller quantity of bytes.
However, your wording was:
> > > Every time I read a byte info, I have to write a 'read command'.
This suggests you are reading one byte at a time with each read
command. I just want to make sure that is not one I2C transaction per
byte.
Andrew.
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH net-next v3 2/8] i2c: designware: Add driver support for Wangxun 10Gb NIC
2023-04-21 6:52 ` Jarkko Nikula
@ 2023-04-21 12:22 ` Andrew Lunn
2023-04-21 13:00 ` Jarkko Nikula
0 siblings, 1 reply; 28+ messages in thread
From: Andrew Lunn @ 2023-04-21 12:22 UTC (permalink / raw)
To: Jarkko Nikula
Cc: Jiawen Wu, netdev, linux, linux-i2c, linux-gpio, olteanv,
mengyuanlou
On Fri, Apr 21, 2023 at 09:52:02AM +0300, Jarkko Nikula wrote:
> On 4/20/23 13:29, Jiawen Wu wrote:
> > On Thursday, April 20, 2023 4:58 AM, Andrew Lunn wrote:
> > > On Wed, Apr 19, 2023 at 04:27:33PM +0800, Jiawen Wu wrote:
> > > > Wangxun 10Gb ethernet chip is connected to Designware I2C, to communicate
> > > > with SFP.
> > > >
> > > > Add platform data to pass IOMEM base address, board flag and other
> > > > parameters, since resource address was mapped on ethernet driver.
> > > >
> > > > The exists IP limitations are dealt as workarounds:
> > > > - IP does not support interrupt mode, it works on polling mode.
> > > > - I2C cannot read continuously, only one byte can at a time.
> > >
> > > Are you really sure about that?
> > >
> > > It is a major limitation for SFP devices. It means you cannot access
> > > the diagnostics, since you need to perform an atomic 2 byte read.
> > >
> > > Or maybe i'm understanding you wrong.
> > >
> > > Andrew
> > >
> >
> > Maybe I'm a little confused about this. Every time I read a byte info, I have to
> > write a 'read command'. It can normally get the information for SFP devices.
> > But I'm not sure if this is regular I2C behavior.
> >
> I agree, IC_DATA_CMD operation is obscure. In order to read from the bus,
> writes with BIT(8) set is required into IC_DATA_CMD, wait (irq/poll)
> DW_IC_INTR_RX_FULL is set in DW_IC_RAW_INTR_STAT and then read back received
> data from IC_DATA_CMD while taking into count FIFO sizes.
Just for my understanding, this read command just allows access to the
data in the FIFO. It has nothing to do with I2C bus transactions.
You also mention FIFO depth. So you should not need to do this per
byte, you can read upto the full depth of the FIFO before having to do
the read command, poll/irq cycle again?
Andrew
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH net-next v3 2/8] i2c: designware: Add driver support for Wangxun 10Gb NIC
2023-04-21 12:22 ` Andrew Lunn
@ 2023-04-21 13:00 ` Jarkko Nikula
0 siblings, 0 replies; 28+ messages in thread
From: Jarkko Nikula @ 2023-04-21 13:00 UTC (permalink / raw)
To: Andrew Lunn
Cc: Jiawen Wu, netdev, linux, linux-i2c, linux-gpio, olteanv,
mengyuanlou
On 4/21/23 15:22, Andrew Lunn wrote:
> On Fri, Apr 21, 2023 at 09:52:02AM +0300, Jarkko Nikula wrote:
>> I agree, IC_DATA_CMD operation is obscure. In order to read from the bus,
>> writes with BIT(8) set is required into IC_DATA_CMD, wait (irq/poll)
>> DW_IC_INTR_RX_FULL is set in DW_IC_RAW_INTR_STAT and then read back received
>> data from IC_DATA_CMD while taking into count FIFO sizes.
>
> Just for my understanding, this read command just allows access to the
> data in the FIFO. It has nothing to do with I2C bus transactions.
>
Not only but it controls both the bus transactions and data to/from FIFO.
> You also mention FIFO depth. So you should not need to do this per
> byte, you can read upto the full depth of the FIFO before having to do
> the read command, poll/irq cycle again?
>
Commands need to be written to IC_DATA_CMD for each byte and no more
than is the FIFO depth. Like writing n read commands to it, wait for
RX_FULL and read as many bytes as available, continue waiting if not done.
It perhaps best explained by looking at
drivers/i2c/busses/i2c-designware-master.c: i2c_dw_xfer_msg() and
i2c_dw_read().
^ permalink raw reply [flat|nested] 28+ messages in thread
end of thread, other threads:[~2023-04-21 13:00 UTC | newest]
Thread overview: 28+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-04-19 8:27 [PATCH net-next v3 0/8] TXGBE PHYLINK support Jiawen Wu
2023-04-19 8:27 ` [PATCH net-next v3 1/8] net: txgbe: Add software nodes to support phylink Jiawen Wu
2023-04-19 20:53 ` Andrew Lunn
2023-04-19 8:27 ` [PATCH net-next v3 2/8] i2c: designware: Add driver support for Wangxun 10Gb NIC Jiawen Wu
2023-04-19 14:36 ` Jarkko Nikula
2023-04-20 10:49 ` Jiawen Wu
2023-04-19 20:58 ` Andrew Lunn
2023-04-20 10:29 ` Jiawen Wu
2023-04-20 13:22 ` Andrew Lunn
2023-04-21 2:20 ` Jiawen Wu
2023-04-21 12:15 ` Andrew Lunn
2023-04-21 6:52 ` Jarkko Nikula
2023-04-21 12:22 ` Andrew Lunn
2023-04-21 13:00 ` Jarkko Nikula
2023-04-19 8:27 ` [PATCH net-next v3 3/8] net: txgbe: Register I2C platform device Jiawen Wu
2023-04-19 8:27 ` [PATCH net-next v3 4/8] net: txgbe: Add SFP module identify Jiawen Wu
2023-04-19 13:55 ` Vladimir Oltean
2023-04-19 8:27 ` [PATCH net-next v3 5/8] net: txgbe: Support GPIO to SFP socket Jiawen Wu
2023-04-19 8:27 ` [PATCH net-next v3 6/8] net: pcs: Add 10GBASE-R mode for Synopsys Designware XPCS Jiawen Wu
2023-04-19 13:19 ` Vladimir Oltean
2023-04-20 1:56 ` Jiawen Wu
2023-04-20 8:03 ` Vladimir Oltean
2023-04-20 8:38 ` Jiawen Wu
2023-04-20 8:52 ` Vladimir Oltean
2023-04-20 9:32 ` Jiawen Wu
2023-04-19 8:27 ` [PATCH net-next v3 7/8] net: txgbe: Implement phylink pcs Jiawen Wu
2023-04-19 8:27 ` [PATCH net-next v3 8/8] net: txgbe: Support phylink MAC layer Jiawen Wu
2023-04-19 13:39 ` [PATCH net-next v3 0/8] TXGBE PHYLINK support Vladimir Oltean
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).