2023-10-17 09:43:50

by Raju Lakkaraju

[permalink] [raw]
Subject: [PATCH net-next V1 0/7] Add support to PHYLINK and SFP for PCI11x1x chips

This patch series adds support to phylink and sfp pluggable module.
Add software-nodes to hold the network interface phylink, sfp, i2c and gpio
configuration and integrates the PCI1x1x chip i2c driver and gpio driver to
access the sfp module eeprom data.

Tested on chip PCI11010 Rev-B with Bridgeport Evaluation board Rev-1 with
following SFP modules:

1. FS's 2.5G SFP (SFP-2.5G-T) with 2.5 Gbps speed (interface 2500Base-X)

2. Mellanox DAC10G SFP (MC3309130-001) at 2.5 Gbps speed (interface 2500Base-X)
and 1Gpbs speed (interface 1000Base-X)

3. Axcen's 1G SFP (AXGT-R1T4-05I1) at 1G/100M/10M bps speed (interface SGMII)

4. Fiber 1G SFP (AXGE-1354-0531) at 1Gpbs speed (interface 1000Base-X)

Change Log:
===========
V0 -> V1:
- Integrate with Synopsys DesignWare XPCS drivers
- Based on external review comments,
- Changes made to SGMII interface support only 1G/100M/10M bps speed
- Changes made to 2500Base-X interface support only 2.5Gbps speed
- Add check for not is_sgmii_en with is_sfp_support_en support
- Change the "pci11x1x_strap_get_status" function return type from void to
int
- Add ethtool phylink wol, eee, pause get/set functions

Raju Lakkaraju (7):
net: lan743x: Create separate PCS power reset function
net: lan743x: Create separate Link Speed Duplex state function
net: lan743x: Add SFP support check flag
net: lan743x: Add support to software-nodes for sfp and phylink
net: lan743x: Register the platform device for sfp pluggable module
net: lan743x: Add support to the phylink framework
net: lan743x: Add support to ethtool phylink get and set settings

drivers/net/ethernet/microchip/Kconfig | 9 +-
.../net/ethernet/microchip/lan743x_ethtool.c | 85 +-
drivers/net/ethernet/microchip/lan743x_main.c | 1090 ++++++++++++-----
drivers/net/ethernet/microchip/lan743x_main.h | 49 +
4 files changed, 868 insertions(+), 365 deletions(-)

--
2.34.1


2023-10-17 09:44:05

by Raju Lakkaraju

[permalink] [raw]
Subject: [PATCH net-next V1 1/7] net: lan743x: Create separate PCS power reset function

Create separate PCS power reset function from lan743x_sgmii_config () to use
as subroutine.

Signed-off-by: Raju Lakkaraju <[email protected]>
---
drivers/net/ethernet/microchip/lan743x_main.c | 55 ++++++++++---------
1 file changed, 29 insertions(+), 26 deletions(-)

diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c
index f940895b14e8..1432032b795b 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.c
+++ b/drivers/net/ethernet/microchip/lan743x_main.c
@@ -1145,12 +1145,39 @@ static int lan743x_pcs_seq_state(struct lan743x_adapter *adapter, u8 state)
return 0;
}

+static int lan743x_pcs_power_reset(struct lan743x_adapter *adapter)
+{
+ int mii_ctl;
+ int ret;
+
+ /* SGMII/1000/2500BASE-X PCS power down */
+ mii_ctl = lan743x_sgmii_read(adapter, MDIO_MMD_VEND2, MII_BMCR);
+ if (mii_ctl < 0)
+ return mii_ctl;
+
+ mii_ctl |= BMCR_PDOWN;
+ ret = lan743x_sgmii_write(adapter, MDIO_MMD_VEND2, MII_BMCR, mii_ctl);
+ if (ret < 0)
+ return ret;
+
+ ret = lan743x_pcs_seq_state(adapter, PCS_POWER_STATE_DOWN);
+ if (ret < 0)
+ return ret;
+
+ /* SGMII/1000/2500BASE-X PCS power up */
+ mii_ctl &= ~BMCR_PDOWN;
+ ret = lan743x_sgmii_write(adapter, MDIO_MMD_VEND2, MII_BMCR, mii_ctl);
+ if (ret < 0)
+ return ret;
+
+ return lan743x_pcs_seq_state(adapter, PCS_POWER_STATE_UP);
+}
+
static int lan743x_sgmii_config(struct lan743x_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
struct phy_device *phydev = netdev->phydev;
enum lan743x_sgmii_lsd lsd = POWER_DOWN;
- int mii_ctl;
bool status;
int ret;

@@ -1207,31 +1234,7 @@ static int lan743x_sgmii_config(struct lan743x_adapter *adapter)
netif_dbg(adapter, drv, adapter->netdev,
"SGMII 1G mode enable\n");

- /* SGMII/1000/2500BASE-X PCS power down */
- mii_ctl = lan743x_sgmii_read(adapter, MDIO_MMD_VEND2, MII_BMCR);
- if (mii_ctl < 0)
- return mii_ctl;
-
- mii_ctl |= BMCR_PDOWN;
- ret = lan743x_sgmii_write(adapter, MDIO_MMD_VEND2, MII_BMCR, mii_ctl);
- if (ret < 0)
- return ret;
-
- ret = lan743x_pcs_seq_state(adapter, PCS_POWER_STATE_DOWN);
- if (ret < 0)
- return ret;
-
- /* SGMII/1000/2500BASE-X PCS power up */
- mii_ctl &= ~BMCR_PDOWN;
- ret = lan743x_sgmii_write(adapter, MDIO_MMD_VEND2, MII_BMCR, mii_ctl);
- if (ret < 0)
- return ret;
-
- ret = lan743x_pcs_seq_state(adapter, PCS_POWER_STATE_UP);
- if (ret < 0)
- return ret;
-
- return 0;
+ return lan743x_pcs_power_reset(adapter);
}

static void lan743x_mac_set_address(struct lan743x_adapter *adapter,
--
2.34.1

2023-10-17 09:44:15

by Raju Lakkaraju

[permalink] [raw]
Subject: [PATCH net-next V1 3/7] net: lan743x: Add SFP support check flag

PCI11x1x chip support the Pluggable module (SFP) depend on Board requirement.
sfp support information programmed in eeprom.
Flag "is_sfp_support_en" update on "STRAP" register.

Signed-off-by: Raju Lakkaraju <[email protected]>
---
drivers/net/ethernet/microchip/lan743x_main.c | 27 ++++++++++++++++---
drivers/net/ethernet/microchip/lan743x_main.h | 3 +++
2 files changed, 27 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c
index e47f0ae1770d..eee3fe7e0c66 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.c
+++ b/drivers/net/ethernet/microchip/lan743x_main.c
@@ -25,7 +25,7 @@
#define PCS_POWER_STATE_DOWN 0x6
#define PCS_POWER_STATE_UP 0x4

-static void pci11x1x_strap_get_status(struct lan743x_adapter *adapter)
+static int pci11x1x_strap_get_status(struct lan743x_adapter *adapter)
{
u32 chip_rev;
u32 cfg_load;
@@ -38,7 +38,7 @@ static void pci11x1x_strap_get_status(struct lan743x_adapter *adapter)
if (ret < 0) {
netif_err(adapter, drv, adapter->netdev,
"Sys Lock acquire failed ret:%d\n", ret);
- return;
+ return ret;
}

cfg_load = lan743x_csr_read(adapter, ETH_SYS_CONFIG_LOAD_STARTED_REG);
@@ -52,6 +52,11 @@ static void pci11x1x_strap_get_status(struct lan743x_adapter *adapter)
adapter->is_sgmii_en = true;
else
adapter->is_sgmii_en = false;
+
+ if ((strap & STRAP_SFP_USE_EN_) && (strap & STRAP_SFP_EN_))
+ adapter->is_sfp_support_en = true;
+ else
+ adapter->is_sfp_support_en = false;
} else {
chip_rev = lan743x_csr_read(adapter, FPGA_REV);
if (chip_rev) {
@@ -63,8 +68,21 @@ static void pci11x1x_strap_get_status(struct lan743x_adapter *adapter)
adapter->is_sgmii_en = false;
}
}
+
+ if (adapter->is_pci11x1x && !adapter->is_sgmii_en &&
+ adapter->is_sfp_support_en) {
+ netif_err(adapter, drv, adapter->netdev,
+ "Invalid eeprom sgmii support configuration\n");
+ return -EINVAL;
+ }
+
netif_dbg(adapter, drv, adapter->netdev,
"SGMII I/F %sable\n", adapter->is_sgmii_en ? "En" : "Dis");
+ netif_dbg(adapter, drv, adapter->netdev,
+ "SFP support %sable\n", adapter->is_sfp_support_en ?
+ "En" : "Dis");
+
+ return 0;
}

static bool is_pci11x1x_chip(struct lan743x_adapter *adapter)
@@ -3259,7 +3277,9 @@ static int lan743x_hardware_init(struct lan743x_adapter *adapter,
adapter->max_tx_channels = PCI11X1X_MAX_TX_CHANNELS;
adapter->used_tx_channels = PCI11X1X_USED_TX_CHANNELS;
adapter->max_vector_count = PCI11X1X_MAX_VECTOR_COUNT;
- pci11x1x_strap_get_status(adapter);
+ ret = pci11x1x_strap_get_status(adapter);
+ if (ret < 0)
+ return ret;
spin_lock_init(&adapter->eth_syslock_spinlock);
mutex_init(&adapter->sgmii_rw_lock);
} else {
@@ -3414,6 +3434,7 @@ static int lan743x_pcidev_probe(struct pci_dev *pdev,
NETIF_MSG_LINK | NETIF_MSG_IFUP |
NETIF_MSG_IFDOWN | NETIF_MSG_TX_QUEUED;
netdev->max_mtu = LAN743X_MAX_FRAME_SIZE;
+ adapter->is_sfp_support_en = false;

of_get_mac_address(pdev->dev.of_node, adapter->mac_address);

diff --git a/drivers/net/ethernet/microchip/lan743x_main.h b/drivers/net/ethernet/microchip/lan743x_main.h
index 52609fc13ad9..6a3a45b98140 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.h
+++ b/drivers/net/ethernet/microchip/lan743x_main.h
@@ -34,6 +34,8 @@

#define STRAP_READ (0x0C)
#define STRAP_READ_USE_SGMII_EN_ BIT(22)
+#define STRAP_SFP_USE_EN_ BIT(31)
+#define STRAP_SFP_EN_ BIT(15)
#define STRAP_READ_SGMII_EN_ BIT(6)
#define STRAP_READ_SGMII_REFCLK_ BIT(5)
#define STRAP_READ_SGMII_2_5G_ BIT(4)
@@ -1038,6 +1040,7 @@ struct lan743x_adapter {
u8 max_tx_channels;
u8 used_tx_channels;
u8 max_vector_count;
+ bool is_sfp_support_en;

#define LAN743X_ADAPTER_FLAG_OTP BIT(0)
u32 flags;
--
2.34.1

2023-10-17 09:44:18

by Raju Lakkaraju

[permalink] [raw]
Subject: [PATCH net-next V1 4/7] net: lan743x: Add support to software-nodes for sfp and phylink

Register software nodes and define the device properties.
software-node contains following properties.
- gpio pin details
- i2c bus information
- sfp signals
- phylink mode

Signed-off-by: Raju Lakkaraju <[email protected]>
---
drivers/net/ethernet/microchip/Kconfig | 5 +-
drivers/net/ethernet/microchip/lan743x_main.c | 235 +++++++++++++++++-
drivers/net/ethernet/microchip/lan743x_main.h | 36 +++
3 files changed, 272 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ethernet/microchip/Kconfig b/drivers/net/ethernet/microchip/Kconfig
index 43ba71e82260..c50970705e88 100644
--- a/drivers/net/ethernet/microchip/Kconfig
+++ b/drivers/net/ethernet/microchip/Kconfig
@@ -50,8 +50,11 @@ config LAN743X
select FIXED_PHY
select CRC16
select CRC32
+ select I2C_PCI1XXXX
+ select GP_PCI1XXXX
help
- Support for the Microchip LAN743x PCI Express Gigabit Ethernet chip
+ Support for the Microchip LAN743x and PCI11x1x families of PCI
+ Express Ethernet devices

To compile this driver as a module, choose M here. The module will be
called lan743x.
diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c
index eee3fe7e0c66..71cce7722a21 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.c
+++ b/drivers/net/ethernet/microchip/lan743x_main.c
@@ -15,6 +15,9 @@
#include <linux/rtnetlink.h>
#include <linux/iopoll.h>
#include <linux/crc16.h>
+#include <linux/i2c.h>
+#include <linux/gpio/machine.h>
+#include <linux/auxiliary_bus.h>
#include "lan743x_main.h"
#include "lan743x_ethtool.h"

@@ -24,6 +27,46 @@
#define MMD_ACCESS_READ_INC 3
#define PCS_POWER_STATE_DOWN 0x6
#define PCS_POWER_STATE_UP 0x4
+#define PCI1XXXX_VENDOR_ID 0x1055
+#define PCI1XXXX_BR_PERIF_ID 0xA00C
+#define PCI1XXXX_PERIF_I2C_ID 0xA003
+#define PCI1XXXX_PERIF_GPIO_ID 0xA005
+#define PCI1XXXX_DEV_MASK GENMASK(7, 4)
+#define PCI11X1X_TX_FAULT_GPIO 46
+#define PCI11X1X_TX_DIS_GPIO 47
+#define PCI11X1X_RATE_SEL0_GPIO 48
+#define PCI11X1X_LOS_GPIO 49
+#define PCI11X1X_MOD_DEF0_GPIO 51
+
+#define NODE_PROP(_NAME, _PROP) \
+ ((const struct software_node) { \
+ .name = _NAME, \
+ .properties = _PROP, \
+ })
+
+struct pci1xxxx_i2c {
+ struct completion i2c_xfer_done;
+ bool i2c_xfer_in_progress;
+ struct i2c_adapter adap;
+ void __iomem *i2c_base;
+ u32 freq;
+ u32 flags;
+};
+
+struct gp_aux_data_type {
+ int irq_num;
+ resource_size_t region_start;
+ resource_size_t region_length;
+};
+
+struct auxiliary_device_wrapper {
+ struct auxiliary_device aux_dev;
+ struct gp_aux_data_type gp_aux_data;
+};
+
+struct aux_bus_device {
+ struct auxiliary_device_wrapper *aux_device_wrapper[2];
+};

static int pci11x1x_strap_get_status(struct lan743x_adapter *adapter)
{
@@ -105,6 +148,91 @@ static void lan743x_pci_cleanup(struct lan743x_adapter *adapter)
pci_disable_device(adapter->pdev);
}

+static void *pci1xxxx_perif_drvdata_get(struct lan743x_adapter *adapter,
+ u16 perif_id)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ struct pci_bus *perif_bus;
+ struct pci_dev *perif_dev;
+ struct pci_dev *br_dev;
+ struct pci_bus *br_bus;
+ struct pci_dev *dev;
+
+ /* PCI11x1x devices' PCIe topology consists of a top level pcie
+ * switch with up to four downstream ports, some of which have
+ * integrated endpoints connected to them. One of the downstream ports
+ * has an embedded single function pcie ethernet controller which is
+ * handled by this driver. Another downstream port has an
+ * embedded multifunction pcie endpoint, with four pcie functions
+ * (the "peripheral controllers": I2C controller, GPIO controller,
+ * UART controllers, SPIcontrollers)
+ * The code below navigates the PCI11x1x topology
+ * to find (by matching its PCI device ID) the peripheral controller
+ * that should be paired to the embedded ethernet controller.
+ */
+ br_dev = pci_upstream_bridge(pdev);
+ if (!br_dev) {
+ netif_err(adapter, drv, adapter->netdev,
+ "upstream bridge not found\n");
+ return br_dev;
+ }
+
+ br_bus = br_dev->bus;
+ list_for_each_entry(dev, &br_bus->devices, bus_list) {
+ if (dev->vendor == PCI1XXXX_VENDOR_ID &&
+ (dev->device & ~PCI1XXXX_DEV_MASK) ==
+ PCI1XXXX_BR_PERIF_ID) {
+ perif_bus = dev->subordinate;
+ list_for_each_entry(perif_dev, &perif_bus->devices,
+ bus_list) {
+ if (perif_dev->vendor == PCI1XXXX_VENDOR_ID &&
+ (perif_dev->device & ~PCI1XXXX_DEV_MASK) ==
+ perif_id)
+ return pci_get_drvdata(perif_dev);
+ }
+ }
+ }
+
+ netif_err(adapter, drv, adapter->netdev,
+ "pci1xxxx peripheral (0x%X) device not found\n", perif_id);
+
+ return NULL;
+}
+
+static int pci1xxxx_i2c_adapter_get(struct lan743x_adapter *adapter)
+{
+ struct pci1xxxx_i2c *i2c_drvdata;
+
+ i2c_drvdata = pci1xxxx_perif_drvdata_get(adapter, PCI1XXXX_PERIF_I2C_ID);
+ if (!i2c_drvdata)
+ return -EPROBE_DEFER;
+
+ adapter->i2c_adap = &i2c_drvdata->adap;
+ snprintf(adapter->nodes->i2c_name, sizeof(adapter->nodes->i2c_name),
+ adapter->i2c_adap->name);
+ netif_dbg(adapter, drv, adapter->netdev, "Found %s\n",
+ adapter->i2c_adap->name);
+
+ return 0;
+}
+
+static int pci1xxxx_gpio_dev_get(struct lan743x_adapter *adapter)
+{
+ struct aux_bus_device *aux_bus;
+ struct device *gpio_dev;
+
+ aux_bus = pci1xxxx_perif_drvdata_get(adapter, PCI1XXXX_PERIF_GPIO_ID);
+ if (!aux_bus)
+ return -EPROBE_DEFER;
+
+ gpio_dev = &aux_bus->aux_device_wrapper[1]->aux_dev.dev;
+ snprintf(adapter->nodes->gpio_name, sizeof(adapter->nodes->gpio_name),
+ dev_name(gpio_dev));
+ netif_dbg(adapter, drv, adapter->netdev, "Found %s\n",
+ adapter->nodes->gpio_name);
+ return 0;
+}
+
static int lan743x_pci_init(struct lan743x_adapter *adapter,
struct pci_dev *pdev)
{
@@ -3045,6 +3173,90 @@ static int lan743x_rx_open(struct lan743x_rx *rx)
return ret;
}

+static int lan743x_swnodes_register(struct lan743x_adapter *adapter)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ struct lan743x_sw_nodes *nodes;
+ struct software_node *swnodes;
+ int ret;
+ u32 id;
+
+ nodes = kzalloc(sizeof(*nodes), GFP_KERNEL);
+ if (!nodes)
+ return -ENOMEM;
+
+ adapter->nodes = nodes;
+
+ ret = pci1xxxx_gpio_dev_get(adapter);
+ if (ret < 0)
+ return ret;
+
+ ret = pci1xxxx_i2c_adapter_get(adapter);
+ if (ret < 0)
+ return ret;
+
+ id = (pdev->bus->number << 8) | pdev->devfn;
+ snprintf(nodes->sfp_name, sizeof(nodes->sfp_name),
+ "sfp-%d", id);
+ snprintf(nodes->phylink_name, sizeof(nodes->phylink_name),
+ "mchp-pci1xxxx-phylink-%d", id);
+
+ swnodes = nodes->swnodes;
+
+ nodes->gpio_props[0] = PROPERTY_ENTRY_STRING("pinctrl-names",
+ "default");
+ swnodes[SWNODE_GPIO] = NODE_PROP(nodes->gpio_name, nodes->gpio_props);
+
+ nodes->tx_fault_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_GPIO],
+ PCI11X1X_TX_FAULT_GPIO,
+ GPIO_ACTIVE_HIGH);
+ nodes->tx_disable_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_GPIO],
+ PCI11X1X_TX_DIS_GPIO,
+ GPIO_ACTIVE_HIGH);
+ nodes->mod_def0_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_GPIO],
+ PCI11X1X_MOD_DEF0_GPIO,
+ GPIO_ACTIVE_LOW);
+ nodes->los_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_GPIO],
+ PCI11X1X_LOS_GPIO,
+ GPIO_ACTIVE_HIGH);
+ nodes->rate_sel0_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_GPIO],
+ PCI11X1X_RATE_SEL0_GPIO,
+ GPIO_ACTIVE_HIGH);
+
+ nodes->i2c_props[0] = PROPERTY_ENTRY_STRING("pinctrl-names", "default");
+ 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->tx_fault_ref);
+ nodes->sfp_props[3] = PROPERTY_ENTRY_REF_ARRAY("tx-disable-gpios",
+ nodes->tx_disable_ref);
+ nodes->sfp_props[4] = PROPERTY_ENTRY_REF_ARRAY("mod-def0-gpios",
+ nodes->mod_def0_ref);
+ nodes->sfp_props[5] = PROPERTY_ENTRY_REF_ARRAY("los-gpios",
+ nodes->los_ref);
+ nodes->sfp_props[6] = PROPERTY_ENTRY_REF_ARRAY("rate-select0-gpios",
+ nodes->rate_sel0_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);
+}
+
static int lan743x_netdev_close(struct net_device *netdev)
{
struct lan743x_adapter *adapter = netdev_priv(netdev);
@@ -3260,6 +3472,14 @@ static void lan743x_full_cleanup(struct lan743x_adapter *adapter)
{
unregister_netdev(adapter->netdev);

+ if (adapter->i2c_adap)
+ adapter->i2c_adap = NULL;
+
+ if (adapter->nodes)
+ software_node_unregister_node_group(adapter->nodes->group);
+
+ kfree(adapter->nodes);
+
lan743x_mdiobus_cleanup(adapter);
lan743x_hardware_cleanup(adapter);
lan743x_pci_cleanup(adapter);
@@ -3299,9 +3519,18 @@ static int lan743x_hardware_init(struct lan743x_adapter *adapter,
if (ret)
return ret;

- ret = lan743x_phy_init(adapter);
- if (ret)
- return ret;
+ if (adapter->is_sfp_support_en) {
+ ret = lan743x_swnodes_register(adapter);
+ if (ret) {
+ netdev_err(adapter->netdev,
+ "failed to register software nodes\n");
+ return ret;
+ }
+ } else {
+ ret = lan743x_phy_init(adapter);
+ if (ret)
+ return ret;
+ }

ret = lan743x_ptp_init(adapter);
if (ret)
diff --git a/drivers/net/ethernet/microchip/lan743x_main.h b/drivers/net/ethernet/microchip/lan743x_main.h
index 6a3a45b98140..450d8984cdb5 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.h
+++ b/drivers/net/ethernet/microchip/lan743x_main.h
@@ -5,6 +5,7 @@
#define _LAN743X_H

#include <linux/phy.h>
+#include <linux/property.h>
#include "lan743x_ptp.h"

#define DRIVER_AUTHOR "Bryan Whitehead <[email protected]>"
@@ -1008,6 +1009,39 @@ enum lan743x_sgmii_lsd {
LINK_2500_SLAVE
};

+enum lan743x_swnodes {
+ SWNODE_GPIO = 0,
+ SWNODE_I2C,
+ SWNODE_SFP,
+ SWNODE_PHYLINK,
+ SWNODE_MAX
+};
+
+#define I2C_DRV_NAME 48
+#define GPIO_DRV_NAME 32
+#define SFP_NODE_NAME 32
+#define PHYLINK_NODE_NAME 32
+
+struct lan743x_sw_nodes {
+ char gpio_name[GPIO_DRV_NAME];
+ char i2c_name[I2C_DRV_NAME];
+ char sfp_name[SFP_NODE_NAME];
+ char phylink_name[PHYLINK_NODE_NAME];
+ struct property_entry gpio_props[1];
+ struct property_entry i2c_props[1];
+ 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 tx_fault_ref[1];
+ struct software_node_ref_args tx_disable_ref[1];
+ struct software_node_ref_args mod_def0_ref[1];
+ struct software_node_ref_args los_ref[1];
+ struct software_node_ref_args rate_sel0_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 lan743x_adapter {
struct net_device *netdev;
struct mii_bus *mdiobus;
@@ -1046,6 +1080,8 @@ struct lan743x_adapter {
u32 flags;
u32 hw_cfg;
phy_interface_t phy_interface;
+ struct lan743x_sw_nodes *nodes;
+ struct i2c_adapter *i2c_adap;
};

#define LAN743X_COMPONENT_FLAG_RX(channel) BIT(20 + (channel))
--
2.34.1

2023-10-17 09:44:37

by Raju Lakkaraju

[permalink] [raw]
Subject: [PATCH net-next V1 5/7] net: lan743x: Register the platform device for sfp pluggable module

Add support for sfp pluggable module as platform device handle the gpio
input and output signals and i2c bus access the sfp eeprom data.

Signed-off-by: Raju Lakkaraju <[email protected]>
---
drivers/net/ethernet/microchip/Kconfig | 2 +-
drivers/net/ethernet/microchip/lan743x_main.c | 41 +++++++++++++++++++
drivers/net/ethernet/microchip/lan743x_main.h | 1 +
3 files changed, 43 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/microchip/Kconfig b/drivers/net/ethernet/microchip/Kconfig
index c50970705e88..f26368b7b834 100644
--- a/drivers/net/ethernet/microchip/Kconfig
+++ b/drivers/net/ethernet/microchip/Kconfig
@@ -46,12 +46,12 @@ config LAN743X
tristate "LAN743x support"
depends on PCI
depends on PTP_1588_CLOCK_OPTIONAL
- select PHYLIB
select FIXED_PHY
select CRC16
select CRC32
select I2C_PCI1XXXX
select GP_PCI1XXXX
+ select SFP
help
Support for the Microchip LAN743x and PCI11x1x families of PCI
Express Ethernet devices
diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c
index 71cce7722a21..a4baa00273f7 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.c
+++ b/drivers/net/ethernet/microchip/lan743x_main.c
@@ -18,6 +18,7 @@
#include <linux/i2c.h>
#include <linux/gpio/machine.h>
#include <linux/auxiliary_bus.h>
+#include <linux/platform_device.h>
#include "lan743x_main.h"
#include "lan743x_ethtool.h"

@@ -3257,6 +3258,31 @@ static int lan743x_swnodes_register(struct lan743x_adapter *adapter)
return software_node_register_node_group(nodes->group);
}

+static int lan743x_sfp_register(struct lan743x_adapter *adapter)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ struct platform_device_info sfp_info;
+ struct platform_device *sfp_dev;
+
+ memset(&sfp_info, 0, sizeof(sfp_info));
+ sfp_info.parent = &adapter->pdev->dev;
+ sfp_info.fwnode = software_node_fwnode(adapter->nodes->group[SWNODE_SFP]);
+ sfp_info.name = "sfp";
+ sfp_info.id = (pdev->bus->number << 8) | pdev->devfn;
+ sfp_dev = platform_device_register_full(&sfp_info);
+ if (IS_ERR(sfp_dev)) {
+ netif_err(adapter, drv, adapter->netdev,
+ "Failed to register SFP device\n");
+ return PTR_ERR(sfp_dev);
+ }
+
+ adapter->sfp_dev = sfp_dev;
+ netif_dbg(adapter, drv, adapter->netdev,
+ "SFP platform device registered");
+
+ return 0;
+}
+
static int lan743x_netdev_close(struct net_device *netdev)
{
struct lan743x_adapter *adapter = netdev_priv(netdev);
@@ -3472,6 +3498,9 @@ static void lan743x_full_cleanup(struct lan743x_adapter *adapter)
{
unregister_netdev(adapter->netdev);

+ if (adapter->sfp_dev)
+ platform_device_unregister(adapter->sfp_dev);
+
if (adapter->i2c_adap)
adapter->i2c_adap = NULL;

@@ -3689,6 +3718,18 @@ static int lan743x_pcidev_probe(struct pci_dev *pdev,
NETIF_F_HW_CSUM | NETIF_F_RXCSUM;
adapter->netdev->hw_features = adapter->netdev->features;

+ if (adapter->is_sfp_support_en) {
+ adapter->i2c_adap->dev.fwnode =
+ software_node_fwnode(adapter->nodes->group[SWNODE_I2C]);
+
+ ret = lan743x_sfp_register(adapter);
+ if (ret < 0) {
+ netif_err(adapter, probe, netdev,
+ "failed to sfp register (%d)\n", ret);
+ goto cleanup_hardware;
+ }
+ }
+
/* carrier off reporting is important to ethtool even BEFORE open */
netif_carrier_off(netdev);

diff --git a/drivers/net/ethernet/microchip/lan743x_main.h b/drivers/net/ethernet/microchip/lan743x_main.h
index 450d8984cdb5..9746e36baaac 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.h
+++ b/drivers/net/ethernet/microchip/lan743x_main.h
@@ -1082,6 +1082,7 @@ struct lan743x_adapter {
phy_interface_t phy_interface;
struct lan743x_sw_nodes *nodes;
struct i2c_adapter *i2c_adap;
+ struct platform_device *sfp_dev;
};

#define LAN743X_COMPONENT_FLAG_RX(channel) BIT(20 + (channel))
--
2.34.1

2023-10-17 09:44:38

by Raju Lakkaraju

[permalink] [raw]
Subject: [PATCH net-next V1 7/7] net: lan743x: Add support to ethtool phylink get and set settings

Add support to ethtool phylink functions:
- get/set settings like speed, duplex etc.
- get/set the wake-on-lan (WOL)
- get/set the energy-efficient ethernet (EEE)
- get/set the pause

Signed-off-by: Raju Lakkaraju <[email protected]>
---
Change Log:
===========
V0 -> V1:
- Remove the phylib ethtool functions and support the phylink ethtool

.../net/ethernet/microchip/lan743x_ethtool.c | 85 ++++++++-----------
1 file changed, 34 insertions(+), 51 deletions(-)

diff --git a/drivers/net/ethernet/microchip/lan743x_ethtool.c b/drivers/net/ethernet/microchip/lan743x_ethtool.c
index 9f825d0c6dec..349630baa29a 100644
--- a/drivers/net/ethernet/microchip/lan743x_ethtool.c
+++ b/drivers/net/ethernet/microchip/lan743x_ethtool.c
@@ -1055,19 +1055,10 @@ static int lan743x_ethtool_get_eee(struct net_device *netdev,
struct ethtool_eee *eee)
{
struct lan743x_adapter *adapter = netdev_priv(netdev);
- struct phy_device *phydev = netdev->phydev;
u32 buf;
int ret;

- if (!phydev)
- return -EIO;
- if (!phydev->drv) {
- netif_err(adapter, drv, adapter->netdev,
- "Missing PHY Driver\n");
- return -EIO;
- }
-
- ret = phy_ethtool_get_eee(phydev, eee);
+ ret = phylink_ethtool_get_eee(adapter->phylink, eee);
if (ret < 0)
return ret;

@@ -1093,32 +1084,15 @@ static int lan743x_ethtool_set_eee(struct net_device *netdev,
struct ethtool_eee *eee)
{
struct lan743x_adapter *adapter;
- struct phy_device *phydev;
u32 buf = 0;
- int ret = 0;

if (!netdev)
return -EINVAL;
adapter = netdev_priv(netdev);
if (!adapter)
return -EINVAL;
- phydev = netdev->phydev;
- if (!phydev)
- return -EIO;
- if (!phydev->drv) {
- netif_err(adapter, drv, adapter->netdev,
- "Missing PHY Driver\n");
- return -EIO;
- }

if (eee->eee_enabled) {
- ret = phy_init_eee(phydev, false);
- if (ret) {
- netif_err(adapter, drv, adapter->netdev,
- "EEE initialization failed\n");
- return ret;
- }
-
buf = (u32)eee->tx_lpi_timer;
lan743x_csr_write(adapter, MAC_EEE_TX_LPI_REQ_DLY_CNT, buf);

@@ -1131,7 +1105,23 @@ static int lan743x_ethtool_set_eee(struct net_device *netdev,
lan743x_csr_write(adapter, MAC_CR, buf);
}

- return phy_ethtool_set_eee(phydev, eee);
+ return phylink_ethtool_set_eee(adapter->phylink, eee);
+}
+
+static int lan743x_ethtool_set_link_ksettings(struct net_device *netdev,
+ const struct ethtool_link_ksettings *cmd)
+{
+ struct lan743x_adapter *adapter = netdev_priv(netdev);
+
+ return phylink_ethtool_ksettings_set(adapter->phylink, cmd);
+}
+
+static int lan743x_ethtool_get_link_ksettings(struct net_device *netdev,
+ struct ethtool_link_ksettings *cmd)
+{
+ struct lan743x_adapter *adapter = netdev_priv(netdev);
+
+ return phylink_ethtool_ksettings_get(adapter->phylink, cmd);
}

#ifdef CONFIG_PM
@@ -1143,8 +1133,7 @@ static void lan743x_ethtool_get_wol(struct net_device *netdev,
wol->supported = 0;
wol->wolopts = 0;

- if (netdev->phydev)
- phy_ethtool_get_wol(netdev->phydev, wol);
+ phylink_ethtool_get_wol(adapter->phylink, wol);

wol->supported |= WAKE_BCAST | WAKE_UCAST | WAKE_MCAST |
WAKE_MAGIC | WAKE_PHY | WAKE_ARP;
@@ -1161,8 +1150,18 @@ static int lan743x_ethtool_set_wol(struct net_device *netdev,
struct ethtool_wolinfo *wol)
{
struct lan743x_adapter *adapter = netdev_priv(netdev);
+ int ret;

adapter->wolopts = 0;
+
+ /* Pass the order to phylink layer */
+ ret = phylink_ethtool_set_wol(adapter->phylink, wol);
+ /* Don't manage WoL on MAC if handled by the PHY
+ * or if there's a failure in talking to the PHY
+ */
+ if (!ret || ret != -EOPNOTSUPP)
+ return ret;
+
if (wol->wolopts & WAKE_UCAST)
adapter->wolopts |= WAKE_UCAST;
if (wol->wolopts & WAKE_MCAST)
@@ -1185,8 +1184,7 @@ static int lan743x_ethtool_set_wol(struct net_device *netdev,

device_set_wakeup_enable(&adapter->pdev->dev, (bool)wol->wolopts);

- return netdev->phydev ? phy_ethtool_set_wol(netdev->phydev, wol)
- : -ENETDOWN;
+ return 0;
}
#endif /* CONFIG_PM */

@@ -1342,28 +1340,16 @@ static void lan743x_get_pauseparam(struct net_device *dev,
struct ethtool_pauseparam *pause)
{
struct lan743x_adapter *adapter = netdev_priv(dev);
- struct lan743x_phy *phy = &adapter->phy;

- if (phy->fc_request_control & FLOW_CTRL_TX)
- pause->tx_pause = 1;
- if (phy->fc_request_control & FLOW_CTRL_RX)
- pause->rx_pause = 1;
- pause->autoneg = phy->fc_autoneg;
+ phylink_ethtool_get_pauseparam(adapter->phylink, pause);
}

static int lan743x_set_pauseparam(struct net_device *dev,
struct ethtool_pauseparam *pause)
{
struct lan743x_adapter *adapter = netdev_priv(dev);
- struct phy_device *phydev = dev->phydev;
struct lan743x_phy *phy = &adapter->phy;

- if (!phydev)
- return -ENODEV;
-
- if (!phy_validate_pause(phydev, pause))
- return -EINVAL;
-
phy->fc_request_control = 0;
if (pause->rx_pause)
phy->fc_request_control |= FLOW_CTRL_RX;
@@ -1376,10 +1362,7 @@ static int lan743x_set_pauseparam(struct net_device *dev,
if (pause->autoneg == AUTONEG_DISABLE)
lan743x_mac_flow_ctrl_set_enables(adapter, pause->tx_pause,
pause->rx_pause);
- else
- phy_set_asym_pause(phydev, pause->rx_pause, pause->tx_pause);
-
- return 0;
+ return phylink_ethtool_set_pauseparam(adapter->phylink, pause);
}

const struct ethtool_ops lan743x_ethtool_ops = {
@@ -1404,8 +1387,8 @@ const struct ethtool_ops lan743x_ethtool_ops = {
.get_ts_info = lan743x_ethtool_get_ts_info,
.get_eee = lan743x_ethtool_get_eee,
.set_eee = lan743x_ethtool_set_eee,
- .get_link_ksettings = phy_ethtool_get_link_ksettings,
- .set_link_ksettings = phy_ethtool_set_link_ksettings,
+ .get_link_ksettings = lan743x_ethtool_get_link_ksettings,
+ .set_link_ksettings = lan743x_ethtool_set_link_ksettings,
.get_regs_len = lan743x_get_regs_len,
.get_regs = lan743x_get_regs,
.get_pauseparam = lan743x_get_pauseparam,
--
2.34.1

2023-10-17 09:45:00

by Raju Lakkaraju

[permalink] [raw]
Subject: [PATCH net-next V1 6/7] net: lan743x: Add support to the phylink framework

Phylink framework is added since it is required for sfp support of
PCI11x1x boards with sfp cages

Signed-off-by: Raju Lakkaraju <[email protected]>
---
Change Log:
===========
V0 -> V1:
- Remove the phylib functions and support the phylink fully

drivers/net/ethernet/microchip/Kconfig | 2 +
drivers/net/ethernet/microchip/lan743x_main.c | 741 +++++++++++-------
drivers/net/ethernet/microchip/lan743x_main.h | 9 +
3 files changed, 460 insertions(+), 292 deletions(-)

diff --git a/drivers/net/ethernet/microchip/Kconfig b/drivers/net/ethernet/microchip/Kconfig
index f26368b7b834..5dc2c97d7129 100644
--- a/drivers/net/ethernet/microchip/Kconfig
+++ b/drivers/net/ethernet/microchip/Kconfig
@@ -52,6 +52,8 @@ config LAN743X
select I2C_PCI1XXXX
select GP_PCI1XXXX
select SFP
+ select PCS_XPCS
+ select PHYLINK
help
Support for the Microchip LAN743x and PCI11x1x families of PCI
Express Ethernet devices
diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c
index a4baa00273f7..d6823ac6407c 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.c
+++ b/drivers/net/ethernet/microchip/lan743x_main.c
@@ -19,6 +19,7 @@
#include <linux/gpio/machine.h>
#include <linux/auxiliary_bus.h>
#include <linux/platform_device.h>
+#include <linux/pcs/pcs-xpcs.h>
#include "lan743x_main.h"
#include "lan743x_ethtool.h"

@@ -1173,6 +1174,28 @@ static int lan743x_get_lsd(int speed, int duplex, u8 mss)
return lsd;
}

+static int pci11x1x_pcs_read(struct mii_bus *bus, int addr, int devnum,
+ int regnum)
+{
+ struct lan743x_adapter *adapter = bus->priv;
+
+ if (addr)
+ return -EOPNOTSUPP;
+
+ return lan743x_sgmii_read(adapter, devnum, regnum);
+}
+
+static int pci11x1x_pcs_write(struct mii_bus *bus, int addr, int devnum,
+ int regnum, u16 val)
+{
+ struct lan743x_adapter *adapter = bus->priv;
+
+ if (addr)
+ return -EOPNOTSUPP;
+
+ return lan743x_sgmii_write(adapter, devnum, regnum, val);
+}
+
static int lan743x_sgmii_mpll_set(struct lan743x_adapter *adapter,
u16 baud)
{
@@ -1241,73 +1264,6 @@ static int lan743x_is_sgmii_2_5G_mode(struct lan743x_adapter *adapter,
return 0;
}

-static int lan743x_sgmii_aneg_update(struct lan743x_adapter *adapter)
-{
- enum lan743x_sgmii_lsd lsd = adapter->sgmii_lsd;
- int mii_ctrl;
- int dgt_ctrl;
- int an_ctrl;
- int ret;
-
- if (lsd == LINK_2500_MASTER || lsd == LINK_2500_SLAVE)
- /* Switch to 2.5 Gbps */
- ret = lan743x_sgmii_2_5G_mode_set(adapter, true);
- else
- /* Switch to 10/100/1000 Mbps clock */
- ret = lan743x_sgmii_2_5G_mode_set(adapter, false);
- if (ret < 0)
- return ret;
-
- /* Enable SGMII Auto NEG */
- mii_ctrl = lan743x_sgmii_read(adapter, MDIO_MMD_VEND2, MII_BMCR);
- if (mii_ctrl < 0)
- return mii_ctrl;
-
- an_ctrl = lan743x_sgmii_read(adapter, MDIO_MMD_VEND2, VR_MII_AN_CTRL);
- if (an_ctrl < 0)
- return an_ctrl;
-
- dgt_ctrl = lan743x_sgmii_read(adapter, MDIO_MMD_VEND2,
- VR_MII_DIG_CTRL1);
- if (dgt_ctrl < 0)
- return dgt_ctrl;
-
- if (lsd == LINK_2500_MASTER || lsd == LINK_2500_SLAVE) {
- mii_ctrl &= ~(BMCR_ANENABLE | BMCR_ANRESTART | BMCR_SPEED100);
- mii_ctrl |= BMCR_SPEED1000;
- dgt_ctrl |= VR_MII_DIG_CTRL1_CL37_TMR_OVR_RIDE_;
- dgt_ctrl &= ~VR_MII_DIG_CTRL1_MAC_AUTO_SW_;
- /* In order for Auto-Negotiation to operate properly at
- * 2.5 Gbps the 1.6ms link timer values must be adjusted
- * The VR_MII_LINK_TIMER_CTRL Register must be set to
- * 16'h7A1 and The CL37_TMR_OVR_RIDE bit of the
- * VR_MII_DIG_CTRL1 Register set to 1
- */
- ret = lan743x_sgmii_write(adapter, MDIO_MMD_VEND2,
- VR_MII_LINK_TIMER_CTRL, 0x7A1);
- if (ret < 0)
- return ret;
- } else {
- mii_ctrl |= (BMCR_ANENABLE | BMCR_ANRESTART);
- an_ctrl &= ~VR_MII_AN_CTRL_SGMII_LINK_STS_;
- dgt_ctrl &= ~VR_MII_DIG_CTRL1_CL37_TMR_OVR_RIDE_;
- dgt_ctrl |= VR_MII_DIG_CTRL1_MAC_AUTO_SW_;
- }
-
- ret = lan743x_sgmii_write(adapter, MDIO_MMD_VEND2, MII_BMCR,
- mii_ctrl);
- if (ret < 0)
- return ret;
-
- ret = lan743x_sgmii_write(adapter, MDIO_MMD_VEND2,
- VR_MII_DIG_CTRL1, dgt_ctrl);
- if (ret < 0)
- return ret;
-
- return lan743x_sgmii_write(adapter, MDIO_MMD_VEND2,
- VR_MII_AN_CTRL, an_ctrl);
-}
-
static int lan743x_pcs_seq_state(struct lan743x_adapter *adapter, u8 state)
{
u8 wait_cnt = 0;
@@ -1356,49 +1312,6 @@ static int lan743x_pcs_power_reset(struct lan743x_adapter *adapter)
return lan743x_pcs_seq_state(adapter, PCS_POWER_STATE_UP);
}

-static int lan743x_sgmii_config(struct lan743x_adapter *adapter)
-{
- struct net_device *netdev = adapter->netdev;
- struct phy_device *phydev = netdev->phydev;
- bool status;
- int ret;
-
- ret = lan743x_get_lsd(phydev->speed, phydev->duplex,
- phydev->master_slave_state);
- if (ret < 0) {
- netif_err(adapter, drv, adapter->netdev,
- "error %d link-speed-duplex(LSD) invalid\n", ret);
- return ret;
- }
-
- adapter->sgmii_lsd = ret;
- netif_dbg(adapter, drv, adapter->netdev,
- "Link Speed Duplex (lsd) : 0x%X\n", adapter->sgmii_lsd);
-
- ret = lan743x_sgmii_aneg_update(adapter);
- if (ret < 0) {
- netif_err(adapter, drv, adapter->netdev,
- "error %d SGMII cfg failed\n", ret);
- return ret;
- }
-
- ret = lan743x_is_sgmii_2_5G_mode(adapter, &status);
- if (ret < 0) {
- netif_err(adapter, drv, adapter->netdev,
- "erro %d SGMII get mode failed\n", ret);
- return ret;
- }
-
- if (status)
- netif_dbg(adapter, drv, adapter->netdev,
- "SGMII 2.5G mode enable\n");
- else
- netif_dbg(adapter, drv, adapter->netdev,
- "SGMII 1G mode enable\n");
-
- return lan743x_pcs_power_reset(adapter);
-}
-
static void lan743x_mac_set_address(struct lan743x_adapter *adapter,
u8 *addr)
{
@@ -1535,113 +1448,6 @@ static int lan743x_mac_set_mtu(struct lan743x_adapter *adapter, int new_mtu)
return 0;
}

-/* PHY */
-static int lan743x_phy_reset(struct lan743x_adapter *adapter)
-{
- u32 data;
-
- /* Only called with in probe, and before mdiobus_register */
-
- data = lan743x_csr_read(adapter, PMT_CTL);
- data |= PMT_CTL_ETH_PHY_RST_;
- lan743x_csr_write(adapter, PMT_CTL, data);
-
- return readx_poll_timeout(LAN743X_CSR_READ_OP, PMT_CTL, data,
- (!(data & PMT_CTL_ETH_PHY_RST_) &&
- (data & PMT_CTL_READY_)),
- 50000, 1000000);
-}
-
-static void lan743x_phy_update_flowcontrol(struct lan743x_adapter *adapter,
- u16 local_adv, u16 remote_adv)
-{
- struct lan743x_phy *phy = &adapter->phy;
- u8 cap;
-
- if (phy->fc_autoneg)
- cap = mii_resolve_flowctrl_fdx(local_adv, remote_adv);
- else
- cap = phy->fc_request_control;
-
- lan743x_mac_flow_ctrl_set_enables(adapter,
- cap & FLOW_CTRL_TX,
- cap & FLOW_CTRL_RX);
-}
-
-static int lan743x_phy_init(struct lan743x_adapter *adapter)
-{
- return lan743x_phy_reset(adapter);
-}
-
-static void lan743x_phy_link_status_change(struct net_device *netdev)
-{
- struct lan743x_adapter *adapter = netdev_priv(netdev);
- struct phy_device *phydev = netdev->phydev;
- u32 data;
-
- phy_print_status(phydev);
- if (phydev->state == PHY_RUNNING) {
- int remote_advertisement = 0;
- int local_advertisement = 0;
-
- data = lan743x_csr_read(adapter, MAC_CR);
-
- /* set duplex mode */
- if (phydev->duplex)
- data |= MAC_CR_DPX_;
- else
- data &= ~MAC_CR_DPX_;
-
- /* set bus speed */
- switch (phydev->speed) {
- case SPEED_10:
- data &= ~MAC_CR_CFG_H_;
- data &= ~MAC_CR_CFG_L_;
- break;
- case SPEED_100:
- data &= ~MAC_CR_CFG_H_;
- data |= MAC_CR_CFG_L_;
- break;
- case SPEED_1000:
- data |= MAC_CR_CFG_H_;
- data &= ~MAC_CR_CFG_L_;
- break;
- case SPEED_2500:
- data |= MAC_CR_CFG_H_;
- data |= MAC_CR_CFG_L_;
- break;
- }
- lan743x_csr_write(adapter, MAC_CR, data);
-
- local_advertisement =
- linkmode_adv_to_mii_adv_t(phydev->advertising);
- remote_advertisement =
- linkmode_adv_to_mii_adv_t(phydev->lp_advertising);
-
- lan743x_phy_update_flowcontrol(adapter, local_advertisement,
- remote_advertisement);
- lan743x_ptp_update_latency(adapter, phydev->speed);
- if (phydev->interface == PHY_INTERFACE_MODE_SGMII ||
- phydev->interface == PHY_INTERFACE_MODE_1000BASEX ||
- phydev->interface == PHY_INTERFACE_MODE_2500BASEX)
- lan743x_sgmii_config(adapter);
- }
-}
-
-static void lan743x_phy_close(struct lan743x_adapter *adapter)
-{
- struct net_device *netdev = adapter->netdev;
- struct phy_device *phydev = netdev->phydev;
-
- phy_stop(netdev->phydev);
- phy_disconnect(netdev->phydev);
-
- /* using phydev here as phy_disconnect NULLs netdev->phydev */
- if (phy_is_pseudo_fixed_link(phydev))
- fixed_phy_unregister(phydev);
-
-}
-
static void lan743x_phy_interface_select(struct lan743x_adapter *adapter)
{
u32 id_rev;
@@ -1650,7 +1456,11 @@ static void lan743x_phy_interface_select(struct lan743x_adapter *adapter)
data = lan743x_csr_read(adapter, MAC_CR);
id_rev = adapter->csr.id_rev & ID_REV_ID_MASK_;

- if (adapter->is_pci11x1x && adapter->is_sgmii_en)
+ if (adapter->is_pci11x1x &&
+ adapter->is_sgmii_en &&
+ adapter->is_sfp_support_en)
+ adapter->phy_interface = PHY_INTERFACE_MODE_2500BASEX;
+ else if (adapter->is_pci11x1x && adapter->is_sgmii_en)
adapter->phy_interface = PHY_INTERFACE_MODE_SGMII;
else if (id_rev == ID_REV_ID_LAN7430_)
adapter->phy_interface = PHY_INTERFACE_MODE_GMII;
@@ -1658,65 +1468,9 @@ static void lan743x_phy_interface_select(struct lan743x_adapter *adapter)
adapter->phy_interface = PHY_INTERFACE_MODE_MII;
else
adapter->phy_interface = PHY_INTERFACE_MODE_RGMII;
-}
-
-static int lan743x_phy_open(struct lan743x_adapter *adapter)
-{
- struct net_device *netdev = adapter->netdev;
- struct lan743x_phy *phy = &adapter->phy;
- struct fixed_phy_status fphy_status = {
- .link = 1,
- .speed = SPEED_1000,
- .duplex = DUPLEX_FULL,
- };
- struct phy_device *phydev;
- int ret = -EIO;
-
- /* try devicetree phy, or fixed link */
- phydev = of_phy_get_and_connect(netdev, adapter->pdev->dev.of_node,
- lan743x_phy_link_status_change);
-
- if (!phydev) {
- /* try internal phy */
- phydev = phy_find_first(adapter->mdiobus);
- if (!phydev) {
- if ((adapter->csr.id_rev & ID_REV_ID_MASK_) ==
- ID_REV_ID_LAN7431_) {
- phydev = fixed_phy_register(PHY_POLL,
- &fphy_status, NULL);
- if (IS_ERR(phydev)) {
- netdev_err(netdev, "No PHY/fixed_PHY found\n");
- return PTR_ERR(phydev);
- }
- } else {
- goto return_error;
- }
- }
-
- lan743x_phy_interface_select(adapter);
-
- ret = phy_connect_direct(netdev, phydev,
- lan743x_phy_link_status_change,
- adapter->phy_interface);
- if (ret)
- goto return_error;
- }
-
- /* MAC doesn't support 1000T Half */
- phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT);
-
- /* support both flow controls */
- phy_support_asym_pause(phydev);
- phy->fc_request_control = (FLOW_CTRL_RX | FLOW_CTRL_TX);
- phy->fc_autoneg = phydev->autoneg;
-
- phy_start(phydev);
- phy_start_aneg(phydev);
- phy_attached_info(phydev);
- return 0;

-return_error:
- return ret;
+ netif_dbg(adapter, drv, adapter->netdev,
+ "selected phy interface: 0x%X\n", adapter->phy_interface);
}

static void lan743x_rfe_open(struct lan743x_adapter *adapter)
@@ -3283,6 +3037,375 @@ static int lan743x_sfp_register(struct lan743x_adapter *adapter)
return 0;
}

+void lan743x_mac_cfg_update(struct lan743x_adapter *adapter, bool link,
+ int speed, const unsigned long *advertise)
+{
+ int mac_cr;
+
+ mac_cr = lan743x_csr_read(adapter, MAC_CR);
+ mac_cr &= ~(MAC_CR_CFG_H_ | MAC_CR_CFG_L_);
+ if (link) {
+ if (speed == SPEED_2500)
+ mac_cr |= (MAC_CR_CFG_H_ | MAC_CR_CFG_L_);
+ else if (speed == SPEED_1000)
+ mac_cr |= (MAC_CR_CFG_H_);
+ else if (speed == SPEED_100)
+ mac_cr |= (MAC_CR_CFG_L_);
+ } else if (test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, advertise) ||
+ test_bit(ETHTOOL_LINK_MODE_2500baseX_Full_BIT, advertise)) {
+ mac_cr |= (MAC_CR_CFG_H_ | MAC_CR_CFG_L_);
+ adapter->sgmii_lsd = LINK_2500_MASTER;
+ } else if (test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, advertise) ||
+ test_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, advertise)) {
+ mac_cr |= (MAC_CR_CFG_H_);
+ adapter->sgmii_lsd = LINK_1000_MASTER;
+ } else if (test_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, advertise) ||
+ test_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, advertise) ||
+ test_bit(ETHTOOL_LINK_MODE_100baseFX_Full_BIT, advertise) ||
+ test_bit(ETHTOOL_LINK_MODE_100baseFX_Half_BIT, advertise)) {
+ mac_cr |= (MAC_CR_CFG_L_);
+ adapter->sgmii_lsd = LINK_1000_MASTER;
+ } else {
+ adapter->sgmii_lsd = LINK_1000_MASTER;
+ }
+
+ lan743x_csr_write(adapter, MAC_CR, mac_cr);
+}
+
+static int lan743x_phylink_sgmii_config(struct lan743x_adapter *adapter)
+{
+ int ret;
+
+ ret = lan743x_get_lsd(SPEED_1000, DUPLEX_FULL,
+ MASTER_SLAVE_STATE_MASTER);
+ if (ret < 0) {
+ netif_err(adapter, drv, adapter->netdev,
+ "error %d link-speed-duplex(LSD) invalid\n", ret);
+ return ret;
+ }
+
+ adapter->sgmii_lsd = ret;
+ netif_dbg(adapter, drv, adapter->netdev,
+ "Link Speed Duplex (lsd) : 0x%X\n", adapter->sgmii_lsd);
+
+ /* Switch to serial bit rate of 1.25 Gbps */
+ ret = lan743x_sgmii_2_5G_mode_set(adapter, false);
+ if (ret < 0)
+ return ret;
+
+ return lan743x_pcs_power_reset(adapter);
+}
+
+static int lan743x_phylink_1000basex_config(struct lan743x_adapter *adapter)
+{
+ u32 sgmii_ctl;
+ int ret;
+
+ ret = lan743x_get_lsd(SPEED_1000, DUPLEX_FULL,
+ MASTER_SLAVE_STATE_MASTER);
+ if (ret < 0) {
+ netif_err(adapter, drv, adapter->netdev,
+ "error %d link-speed-duplex(LSD) invalid\n", ret);
+ return ret;
+ }
+
+ adapter->sgmii_lsd = ret;
+ netif_dbg(adapter, drv, adapter->netdev,
+ "Link Speed Duplex (lsd) : 0x%X\n", adapter->sgmii_lsd);
+
+ /* LINK_STATUS_SOURCE 1000BASE-X PCS link status */
+ sgmii_ctl = lan743x_csr_read(adapter, SGMII_CTL);
+ sgmii_ctl |= SGMII_CTL_LINK_STATUS_SOURCE_;
+ lan743x_csr_write(adapter, SGMII_CTL, sgmii_ctl);
+ sgmii_ctl = lan743x_csr_read(adapter, SGMII_CTL);
+
+ /* Switch to serial bit rate of 1.25 Gbps */
+ ret = lan743x_sgmii_2_5G_mode_set(adapter, false);
+ if (ret < 0)
+ return ret;
+
+ return lan743x_pcs_power_reset(adapter);
+}
+
+static int lan743x_phylink_2500basex_config(struct lan743x_adapter *adapter)
+{
+ u32 sgmii_ctl;
+ int ret;
+
+ ret = lan743x_get_lsd(SPEED_2500, DUPLEX_FULL,
+ MASTER_SLAVE_STATE_MASTER);
+ if (ret < 0) {
+ netif_err(adapter, drv, adapter->netdev,
+ "error %d link-speed-duplex(LSD) invalid\n", ret);
+ return ret;
+ }
+
+ adapter->sgmii_lsd = ret;
+ netif_dbg(adapter, drv, adapter->netdev,
+ "Link Speed Duplex (lsd) : 0x%X\n", adapter->sgmii_lsd);
+
+ /* LINK_STATUS_SOURCE 2500BASE-X PCS link status */
+ sgmii_ctl = lan743x_csr_read(adapter, SGMII_CTL);
+ sgmii_ctl |= SGMII_CTL_LINK_STATUS_SOURCE_;
+ lan743x_csr_write(adapter, SGMII_CTL, sgmii_ctl);
+ sgmii_ctl = lan743x_csr_read(adapter, SGMII_CTL);
+
+ /* Switch to serial bit rate of 3.125 Gbps */
+ ret = lan743x_sgmii_2_5G_mode_set(adapter, true);
+ if (ret < 0)
+ return ret;
+
+ return lan743x_pcs_power_reset(adapter);
+}
+
+static struct phylink_pcs *lan743x_phylink_mac_select(struct phylink_config *config,
+ phy_interface_t interface)
+{
+ struct net_device *netdev = to_net_dev(config->dev);
+ struct lan743x_adapter *adapter = netdev_priv(netdev);
+
+ if (adapter->xpcs)
+ return &adapter->xpcs->pcs;
+
+ return NULL;
+}
+
+static void lan743x_phylink_mac_config(struct phylink_config *config,
+ unsigned int link_an_mode,
+ const struct phylink_link_state *state)
+{
+ struct net_device *netdev = to_net_dev(config->dev);
+ struct lan743x_adapter *adapter = netdev_priv(netdev);
+ bool status;
+ int ret;
+
+ lan743x_mac_cfg_update(adapter, state->link, state->speed,
+ state->advertising);
+
+ switch (state->interface) {
+ case PHY_INTERFACE_MODE_2500BASEX:
+ lan743x_phylink_2500basex_config(adapter);
+ break;
+ case PHY_INTERFACE_MODE_1000BASEX:
+ lan743x_phylink_1000basex_config(adapter);
+ break;
+ case PHY_INTERFACE_MODE_SGMII:
+ lan743x_phylink_sgmii_config(adapter);
+ break;
+ default:
+ netif_dbg(adapter, drv, adapter->netdev,
+ "RGMII/GMII/MII mode enable\n");
+ return;
+ }
+
+ ret = lan743x_is_sgmii_2_5G_mode(adapter, &status);
+ if (ret < 0)
+ netif_err(adapter, drv, adapter->netdev,
+ "erro %d SGMII get mode failed\n", ret);
+
+ if (status)
+ netif_dbg(adapter, drv, adapter->netdev,
+ "SGMII 2.5G mode enable\n");
+ else
+ netif_dbg(adapter, drv, adapter->netdev,
+ "SGMII 1G mode enable\n");
+}
+
+static void lan743x_phylink_mac_link_down(struct phylink_config *config,
+ unsigned int link_an_mode,
+ phy_interface_t interface)
+{
+ netif_tx_stop_all_queues(to_net_dev(config->dev));
+}
+
+static void lan743x_phylink_mac_link_up(struct phylink_config *config,
+ struct phy_device *phydev,
+ unsigned int link_an_mode,
+ phy_interface_t interface,
+ int speed, int duplex,
+ bool tx_pause, bool rx_pause)
+{
+ struct net_device *netdev = to_net_dev(config->dev);
+ struct lan743x_adapter *adapter = netdev_priv(netdev);
+ struct lan743x_phy *phy = &adapter->phy;
+ u32 remote_adv;
+ u32 local_adv;
+ u8 cap = 0;
+ int mac_cr;
+
+ mac_cr = lan743x_csr_read(adapter, MAC_CR);
+ mac_cr &= ~(MAC_CR_CFG_H_ | MAC_CR_CFG_L_);
+ if (speed == SPEED_2500)
+ mac_cr |= (MAC_CR_CFG_H_ | MAC_CR_CFG_L_);
+ else if (speed == SPEED_1000)
+ mac_cr |= (MAC_CR_CFG_H_);
+ else if (speed == SPEED_100)
+ mac_cr |= (MAC_CR_CFG_L_);
+
+ lan743x_csr_write(adapter, MAC_CR, mac_cr);
+
+ /* Flow Control operation */
+ if (phydev) {
+ local_adv = linkmode_adv_to_mii_adv_t(phydev->advertising);
+ remote_adv = linkmode_adv_to_mii_adv_t(phydev->lp_advertising);
+
+ if (phy->fc_autoneg)
+ cap = mii_resolve_flowctrl_fdx(local_adv, remote_adv);
+ else
+ cap = phy->fc_request_control;
+ } else {
+ if (tx_pause)
+ cap |= FLOW_CTRL_TX;
+ if (rx_pause)
+ cap |= FLOW_CTRL_RX;
+ }
+
+ lan743x_mac_flow_ctrl_set_enables(adapter,
+ cap & FLOW_CTRL_TX,
+ cap & FLOW_CTRL_RX);
+
+ lan743x_rfe_update_mac_address(adapter);
+
+ netif_tx_wake_all_queues(to_net_dev(config->dev));
+}
+
+static const struct phylink_mac_ops lan743x_phylink_mac_ops = {
+ .mac_select_pcs = lan743x_phylink_mac_select,
+ .mac_config = lan743x_phylink_mac_config,
+ .mac_link_down = lan743x_phylink_mac_link_down,
+ .mac_link_up = lan743x_phylink_mac_link_up,
+};
+
+static int lan743x_phylink_create(struct net_device *netdev)
+{
+ struct lan743x_adapter *adapter = netdev_priv(netdev);
+ struct fwnode_handle *fwnode = NULL;
+ struct phylink *phylink;
+ int ret;
+
+ adapter->phylink_config.dev = &netdev->dev;
+ adapter->phylink_config.type = PHYLINK_NETDEV;
+ adapter->phylink_config.mac_managed_pm = true;
+
+ adapter->phylink_config.mac_capabilities = MAC_ASYM_PAUSE |
+ MAC_SYM_PAUSE | MAC_10 | MAC_100 | MAC_1000FD | MAC_2500FD;
+
+ /* Config serdes Interface */
+ if (adapter->phy_interface == PHY_INTERFACE_MODE_NA)
+ lan743x_phy_interface_select(adapter);
+
+ if (adapter->is_sgmii_en) {
+ __set_bit(PHY_INTERFACE_MODE_SGMII,
+ adapter->phylink_config.supported_interfaces);
+ __set_bit(PHY_INTERFACE_MODE_1000BASEX,
+ adapter->phylink_config.supported_interfaces);
+ __set_bit(PHY_INTERFACE_MODE_2500BASEX,
+ adapter->phylink_config.supported_interfaces);
+ } else {
+ switch (adapter->phy_interface) {
+ case PHY_INTERFACE_MODE_GMII:
+ __set_bit(PHY_INTERFACE_MODE_GMII,
+ adapter->phylink_config.supported_interfaces);
+ break;
+ case PHY_INTERFACE_MODE_MII:
+ __set_bit(PHY_INTERFACE_MODE_MII,
+ adapter->phylink_config.supported_interfaces);
+ break;
+ default:
+ __set_bit(PHY_INTERFACE_MODE_RGMII,
+ adapter->phylink_config.supported_interfaces);
+ }
+ }
+
+ if (adapter->nodes) {
+ fwnode = software_node_fwnode(adapter->nodes->group[SWNODE_PHYLINK]);
+ if (!fwnode)
+ return -ENODEV;
+ }
+
+ phylink = phylink_create(&adapter->phylink_config,
+ fwnode,
+ adapter->phy_interface,
+ &lan743x_phylink_mac_ops);
+
+ if (IS_ERR(phylink)) {
+ ret = PTR_ERR(phylink);
+ netdev_err(netdev, "Could not create phylink (%pe)\n", phylink);
+ return ret;
+ }
+
+ adapter->phylink = phylink;
+ netdev_dbg(netdev, "lan743x phylink created");
+
+ return 0;
+}
+
+static bool lan743x_phy_handle_exists(struct device_node *dn)
+{
+ dn = of_parse_phandle(dn, "phy-handle", 0);
+ of_node_put(dn);
+ if (IS_ERR(dn))
+ return false;
+
+ return true;
+}
+
+static int lan743x_phylink_connect(struct lan743x_adapter *adapter)
+{
+ struct device_node *dn = adapter->pdev->dev.of_node;
+ struct net_device *dev = adapter->netdev;
+ struct fixed_phy_status fphy_status = {
+ .link = 1,
+ .speed = SPEED_1000,
+ .duplex = DUPLEX_FULL,
+ };
+ struct phy_device *phydev;
+ int ret;
+
+ if (!adapter->is_sfp_support_en) {
+ if (dn)
+ ret = phylink_of_phy_connect(adapter->phylink, dn, 0);
+
+ if (!dn || (ret && !lan743x_phy_handle_exists(dn))) {
+ phydev = phy_find_first(adapter->mdiobus);
+ if (!phydev) {
+ if ((adapter->csr.id_rev & ID_REV_ID_MASK_) ==
+ ID_REV_ID_LAN7431_) {
+ phydev = fixed_phy_register(PHY_POLL,
+ &fphy_status,
+ NULL);
+ if (IS_ERR(phydev)) {
+ netdev_err(dev,
+ "No PHY/fixed_PHY found\n");
+ return PTR_ERR(phydev);
+ }
+ } else {
+ netdev_err(dev, "no PHY found\n");
+ return -ENXIO;
+ }
+ }
+
+ /* attach the mac to the phy */
+ ret = phylink_connect_phy(adapter->phylink, phydev);
+ }
+
+ if (ret) {
+ netdev_err(dev, "Could not attach PHY (%d)\n", ret);
+ return ret;
+ }
+ }
+
+ phylink_start(adapter->phylink);
+
+ return 0;
+}
+
+static void lan743x_phylink_close(struct lan743x_adapter *adapter)
+{
+ phylink_stop(adapter->phylink);
+ phylink_disconnect_phy(adapter->phylink);
+}
+
static int lan743x_netdev_close(struct net_device *netdev)
{
struct lan743x_adapter *adapter = netdev_priv(netdev);
@@ -3296,7 +3419,7 @@ static int lan743x_netdev_close(struct net_device *netdev)

lan743x_ptp_close(adapter);

- lan743x_phy_close(adapter);
+ lan743x_phylink_close(adapter);

lan743x_mac_close(adapter);

@@ -3319,13 +3442,13 @@ static int lan743x_netdev_open(struct net_device *netdev)
if (ret)
goto close_intr;

- ret = lan743x_phy_open(adapter);
+ ret = lan743x_phylink_connect(adapter);
if (ret)
goto close_mac;

ret = lan743x_ptp_open(adapter);
if (ret)
- goto close_phy;
+ goto close_phylink;

lan743x_rfe_open(adapter);

@@ -3355,8 +3478,8 @@ static int lan743x_netdev_open(struct net_device *netdev)
}
lan743x_ptp_close(adapter);

-close_phy:
- lan743x_phy_close(adapter);
+close_phylink:
+ lan743x_phylink_close(adapter);

close_mac:
lan743x_mac_close(adapter);
@@ -3385,11 +3508,14 @@ static netdev_tx_t lan743x_netdev_xmit_frame(struct sk_buff *skb,
static int lan743x_netdev_ioctl(struct net_device *netdev,
struct ifreq *ifr, int cmd)
{
+ struct lan743x_adapter *adapter = netdev_priv(netdev);
+
if (!netif_running(netdev))
return -EINVAL;
if (cmd == SIOCSHWTSTAMP)
return lan743x_ptp_ioctl(netdev, ifr, cmd);
- return phy_mii_ioctl(netdev->phydev, ifr, cmd);
+
+ return phylink_mii_ioctl(adapter->phylink, ifr, cmd);
}

static void lan743x_netdev_set_multicast(struct net_device *netdev)
@@ -3491,6 +3617,9 @@ static void lan743x_hardware_cleanup(struct lan743x_adapter *adapter)

static void lan743x_mdiobus_cleanup(struct lan743x_adapter *adapter)
{
+ if (adapter->xpcs)
+ xpcs_destroy(adapter->xpcs);
+
mdiobus_unregister(adapter->mdiobus);
}

@@ -3498,6 +3627,8 @@ static void lan743x_full_cleanup(struct lan743x_adapter *adapter)
{
unregister_netdev(adapter->netdev);

+ phylink_destroy(adapter->phylink);
+
if (adapter->sfp_dev)
platform_device_unregister(adapter->sfp_dev);

@@ -3548,17 +3679,13 @@ static int lan743x_hardware_init(struct lan743x_adapter *adapter,
if (ret)
return ret;

- if (adapter->is_sfp_support_en) {
+ if (adapter->is_sfp_support_en && !adapter->nodes) {
ret = lan743x_swnodes_register(adapter);
if (ret) {
netdev_err(adapter->netdev,
"failed to register software nodes\n");
return ret;
}
- } else {
- ret = lan743x_phy_init(adapter);
- if (ret)
- return ret;
}

ret = lan743x_ptp_init(adapter);
@@ -3588,6 +3715,7 @@ static int lan743x_hardware_init(struct lan743x_adapter *adapter,

static int lan743x_mdiobus_init(struct lan743x_adapter *adapter)
{
+ struct dw_xpcs *xpcs;
u32 sgmii_ctl;
int ret;

@@ -3608,8 +3736,14 @@ static int lan743x_mdiobus_init(struct lan743x_adapter *adapter)
"SGMII operation\n");
adapter->mdiobus->read = lan743x_mdiobus_read_c22;
adapter->mdiobus->write = lan743x_mdiobus_write_c22;
- adapter->mdiobus->read_c45 = lan743x_mdiobus_read_c45;
- adapter->mdiobus->write_c45 = lan743x_mdiobus_write_c45;
+ if (adapter->is_sfp_support_en) {
+ adapter->mdiobus->read_c45 = pci11x1x_pcs_read;
+ adapter->mdiobus->write_c45 = pci11x1x_pcs_write;
+ } else {
+ adapter->mdiobus->read_c45 = lan743x_mdiobus_read_c45;
+ adapter->mdiobus->write_c45 = lan743x_mdiobus_write_c45;
+ }
+
adapter->mdiobus->name = "lan743x-mdiobus-c45";
netif_dbg(adapter, drv, adapter->netdev,
"lan743x-mdiobus-c45\n");
@@ -3645,9 +3779,26 @@ static int lan743x_mdiobus_init(struct lan743x_adapter *adapter)
ret = mdiobus_register(adapter->mdiobus);
if (ret < 0)
goto return_error;
+
+ if (adapter->is_sfp_support_en) {
+ if (!adapter->phy_interface)
+ lan743x_phy_interface_select(adapter);
+
+ xpcs = xpcs_create_mdiodev(adapter->mdiobus, 0,
+ adapter->phy_interface);
+ if (IS_ERR(xpcs)) {
+ netdev_err(adapter->netdev,
+ "failed to create xpcs\n");
+ return PTR_ERR(xpcs);
+ }
+
+ adapter->xpcs = xpcs;
+ }
+
return 0;

return_error:
+ mdiobus_free(adapter->mdiobus);
return ret;
}

@@ -3717,6 +3868,15 @@ static int lan743x_pcidev_probe(struct pci_dev *pdev,
adapter->netdev->features = NETIF_F_SG | NETIF_F_TSO |
NETIF_F_HW_CSUM | NETIF_F_RXCSUM;
adapter->netdev->hw_features = adapter->netdev->features;
+ /* Default Link-Speed-Duplex (LSD) state */
+ adapter->sgmii_lsd = LINK_2500_MASTER;
+
+ ret = lan743x_phylink_create(adapter->netdev);
+ if (ret < 0) {
+ netif_err(adapter, probe, netdev,
+ "failed to setup phylink (%d)\n", ret);
+ goto cleanup_hardware;
+ }

if (adapter->is_sfp_support_en) {
adapter->i2c_adap->dev.fwnode =
@@ -3730,9 +3890,6 @@ static int lan743x_pcidev_probe(struct pci_dev *pdev,
}
}

- /* carrier off reporting is important to ethtool even BEFORE open */
- netif_carrier_off(netdev);
-
ret = register_netdev(adapter->netdev);
if (ret < 0)
goto cleanup_mdiobus;
diff --git a/drivers/net/ethernet/microchip/lan743x_main.h b/drivers/net/ethernet/microchip/lan743x_main.h
index 9746e36baaac..aab3c1567310 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.h
+++ b/drivers/net/ethernet/microchip/lan743x_main.h
@@ -6,6 +6,7 @@

#include <linux/phy.h>
#include <linux/property.h>
+#include <linux/phylink.h>
#include "lan743x_ptp.h"

#define DRIVER_AUTHOR "Bryan Whitehead <[email protected]>"
@@ -317,6 +318,9 @@
/* Vendor Specific SGMII MMD details */
#define SR_VSMMD_PCS_ID1 0x0004
#define SR_VSMMD_PCS_ID2 0x0005
+#define SR_MII_CTRL MII_BMCR
+#define SR_MII_STS MII_BMSR
+#define SR_MII_STS_LINK_STS_ BIT(2)
#define SR_VSMMD_STS 0x0008
#define SR_VSMMD_CTRL 0x0009

@@ -1083,6 +1087,9 @@ struct lan743x_adapter {
struct lan743x_sw_nodes *nodes;
struct i2c_adapter *i2c_adap;
struct platform_device *sfp_dev;
+ struct dw_xpcs *xpcs;
+ struct phylink *phylink;
+ struct phylink_config phylink_config;
};

#define LAN743X_COMPONENT_FLAG_RX(channel) BIT(20 + (channel))
@@ -1203,5 +1210,7 @@ void lan743x_hs_syslock_release(struct lan743x_adapter *adapter);
void lan743x_mac_flow_ctrl_set_enables(struct lan743x_adapter *adapter,
bool tx_enable, bool rx_enable);
int lan743x_sgmii_read(struct lan743x_adapter *adapter, u8 mmd, u16 addr);
+void lan743x_mac_cfg_update(struct lan743x_adapter *adapter, bool link,
+ int speed, const unsigned long *advertise);

#endif /* _LAN743X_H */
--
2.34.1

2023-10-17 10:46:26

by Russell King (Oracle)

[permalink] [raw]
Subject: Re: [PATCH net-next V1 6/7] net: lan743x: Add support to the phylink framework

On Tue, Oct 17, 2023 at 03:12:07PM +0530, Raju Lakkaraju wrote:
> +static void lan743x_phylink_mac_config(struct phylink_config *config,
> + unsigned int link_an_mode,
> + const struct phylink_link_state *state)
> +{
> + struct net_device *netdev = to_net_dev(config->dev);
> + struct lan743x_adapter *adapter = netdev_priv(netdev);
> + bool status;
> + int ret;
> +
> + lan743x_mac_cfg_update(adapter, state->link, state->speed,
> + state->advertising);

Another case of not reading the phylink documentation... :( I *really*
don't see why we bother to write documentation, from my experience, it
seems to be totally a write-only thing... no one seems to bother
reading it.

/**
* mac_config() - configure the MAC for the selected mode and state
* @config: a pointer to a &struct phylink_config.
* @mode: one of %MLO_AN_FIXED, %MLO_AN_PHY, %MLO_AN_INBAND.
* @state: a pointer to a &struct phylink_link_state.
*
* Note - not all members of @state are valid. In particular,
* @state->lp_advertising, @state->link, @state->an_complete are never
* guaranteed to be correct, and so any mac_config() implementation must
* never reference these fields.
...
* The action performed depends on the currently selected mode:
*
* %MLO_AN_FIXED, %MLO_AN_PHY:
...
* Valid state members: interface, advertising.
* Deprecated state members: speed, duplex, pause.
...
* %MLO_AN_INBAND:
...
* Valid state members: interface, an_enabled, pause, advertising.

So "link" and "speed" are not valid. They're certainly not valid now
that the pre-March 2020 legacy support has been removed.

The only time that you get to know what speed the link is operating at
is after the link has been negotiated and is up - and you will be told
via the mac_link_up() function (or in the case of a PCS, via the
pcs_link_up() function.) You can't know before that point what speed
the link will be operating at because its dependent on the results of
link negotiation.

I haven't bothered to look more deeply at this patch, because I regard
any patch that gets this wrong to be utter trash (sorry that's a bit
hard, but I see people not bothering to read documentation all too
often and it pisses me off that I've gone to the bother of writing it
and it just gets ignored.)

--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!