aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/netlink/specs/fou.yaml18
-rw-r--r--MAINTAINERS1
-rw-r--r--drivers/net/ethernet/freescale/fec_main.c5
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lib/macsec_fs.c1
-rw-r--r--drivers/net/ethernet/wangxun/Kconfig1
-rw-r--r--drivers/net/ethernet/wangxun/libwx/wx_type.h28
-rw-r--r--drivers/net/ethernet/wangxun/ngbe/ngbe_mdio.c84
-rw-r--r--drivers/net/ethernet/wangxun/ngbe/ngbe_type.h19
-rw-r--r--drivers/net/ethernet/wangxun/txgbe/txgbe_hw.c41
-rw-r--r--drivers/net/ethernet/wangxun/txgbe/txgbe_hw.h2
-rw-r--r--drivers/net/ethernet/wangxun/txgbe/txgbe_main.c56
-rw-r--r--drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c176
-rw-r--r--drivers/net/pcs/Makefile2
-rw-r--r--drivers/net/pcs/pcs-xpcs-wx.c209
-rw-r--r--drivers/net/pcs/pcs-xpcs.c112
-rw-r--r--drivers/net/pcs/pcs-xpcs.h17
-rw-r--r--include/linux/pcs/pcs-xpcs.h8
-rw-r--r--lib/checksum_kunit.c54
-rw-r--r--tools/net/ynl/generated/ethtool-user.h4
-rw-r--r--tools/net/ynl/generated/fou-user.h6
-rw-r--r--tools/net/ynl/lib/ynl.py7
-rwxr-xr-xtools/net/ynl/ynl-gen-c.py16
22 files changed, 742 insertions, 125 deletions
diff --git a/Documentation/netlink/specs/fou.yaml b/Documentation/netlink/specs/fou.yaml
index 3e13826a3fdf..0af5ab842c04 100644
--- a/Documentation/netlink/specs/fou.yaml
+++ b/Documentation/netlink/specs/fou.yaml
@@ -107,16 +107,16 @@ operations:
flags: [ admin-perm ]
do:
- request: &select_attrs
+ request: &select_attrs
attributes:
- - af
- - ifindex
- - port
- - peer_port
- - local_v4
- - peer_v4
- - local_v6
- - peer_v6
+ - af
+ - ifindex
+ - port
+ - peer_port
+ - local_v4
+ - peer_v4
+ - local_v6
+ - peer_v6
-
name: get
diff --git a/MAINTAINERS b/MAINTAINERS
index dfc2ba0c20f3..5f527a9ae4b2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -22925,6 +22925,7 @@ S: Maintained
W: https://www.net-swift.com
F: Documentation/networking/device_drivers/ethernet/wangxun/*
F: drivers/net/ethernet/wangxun/
+F: drivers/net/pcs/pcs-xpcs-wx.c
WATCHDOG DEVICE DRIVERS
M: Wim Van Sebroeck <[email protected]>
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 8909899e9a31..77c8e9cfb445 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -1590,9 +1590,12 @@ fec_enet_run_xdp(struct fec_enet_private *fep, struct bpf_prog *prog,
break;
case XDP_TX:
+ rxq->stats[RX_XDP_TX]++;
err = fec_enet_xdp_tx_xmit(fep, cpu, xdp, sync);
- if (unlikely(err))
+ if (unlikely(err)) {
+ rxq->stats[RX_XDP_TX_ERRORS]++;
goto xdp_err;
+ }
ret = FEC_ENET_XDP_TX;
break;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/macsec_fs.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/macsec_fs.c
index 2f2cb67717cd..4a078113e292 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/macsec_fs.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/macsec_fs.c
@@ -278,6 +278,7 @@ static int macsec_fs_tx_create_crypto_table_groups(struct mlx5_macsec_flow_table
if (!in) {
kfree(ft->g);
+ ft->g = NULL;
return -ENOMEM;
}
diff --git a/drivers/net/ethernet/wangxun/Kconfig b/drivers/net/ethernet/wangxun/Kconfig
index 39596cd13539..23cd610bd376 100644
--- a/drivers/net/ethernet/wangxun/Kconfig
+++ b/drivers/net/ethernet/wangxun/Kconfig
@@ -41,6 +41,7 @@ config TXGBE
tristate "Wangxun(R) 10GbE PCI Express adapters support"
depends on PCI
depends on COMMON_CLK
+ select MARVELL_10G_PHY
select REGMAP
select I2C
select I2C_DESIGNWARE_PLATFORM
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h
index 1de88a33a698..c5cbd177ef62 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_type.h
+++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h
@@ -205,6 +205,8 @@
#define WX_TSC_CTL 0x1D000
#define WX_TSC_CTL_TX_DIS BIT(1)
#define WX_TSC_CTL_TSEC_DIS BIT(0)
+#define WX_TSC_ST 0x1D004
+#define WX_TSC_ST_SECTX_RDY BIT(0)
#define WX_TSC_BUF_AE 0x1D00C
#define WX_TSC_BUF_AE_THR GENMASK(9, 0)
@@ -231,6 +233,24 @@
#define WX_MAC_WDG_TIMEOUT 0x1100C
#define WX_MAC_RX_FLOW_CTRL 0x11090
#define WX_MAC_RX_FLOW_CTRL_RFE BIT(0) /* receive fc enable */
+/* MDIO Registers */
+#define WX_MSCA 0x11200
+#define WX_MSCA_RA(v) FIELD_PREP(U16_MAX, v)
+#define WX_MSCA_PA(v) FIELD_PREP(GENMASK(20, 16), v)
+#define WX_MSCA_DA(v) FIELD_PREP(GENMASK(25, 21), v)
+#define WX_MSCC 0x11204
+#define WX_MSCC_CMD(v) FIELD_PREP(GENMASK(17, 16), v)
+
+enum WX_MSCA_CMD_value {
+ WX_MSCA_CMD_RSV = 0,
+ WX_MSCA_CMD_WRITE,
+ WX_MSCA_CMD_POST_READ,
+ WX_MSCA_CMD_READ,
+};
+
+#define WX_MSCC_SADDR BIT(18)
+#define WX_MSCC_BUSY BIT(22)
+#define WX_MDIO_CLK(v) FIELD_PREP(GENMASK(21, 19), v)
#define WX_MMC_CONTROL 0x11800
#define WX_MMC_CONTROL_RSTONRD BIT(2) /* reset on read */
@@ -580,6 +600,13 @@ enum wx_mac_type {
wx_mac_em
};
+enum sp_media_type {
+ sp_media_unknown = 0,
+ sp_media_fiber,
+ sp_media_copper,
+ sp_media_backplane
+};
+
enum em_mac_type {
em_mac_type_unknown = 0,
em_mac_type_mdi,
@@ -827,6 +854,7 @@ struct wx {
struct wx_bus_info bus;
struct wx_mac_info mac;
enum em_mac_type mac_type;
+ enum sp_media_type media_type;
struct wx_eeprom_info eeprom;
struct wx_addr_filter_info addr_ctrl;
struct wx_mac_addr *mac_table;
diff --git a/drivers/net/ethernet/wangxun/ngbe/ngbe_mdio.c b/drivers/net/ethernet/wangxun/ngbe/ngbe_mdio.c
index fe20f02ecb3a..591f5b7b6da6 100644
--- a/drivers/net/ethernet/wangxun/ngbe/ngbe_mdio.c
+++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_mdio.c
@@ -37,24 +37,24 @@ static int ngbe_phy_read_reg_mdi_c22(struct mii_bus *bus, int phy_addr, int regn
wr32(wx, NGBE_MDIO_CLAUSE_SELECT, 0xF);
/* setup and write the address cycle command */
- command = NGBE_MSCA_RA(regnum) |
- NGBE_MSCA_PA(phy_addr) |
- NGBE_MSCA_DA(device_type);
- wr32(wx, NGBE_MSCA, command);
- command = NGBE_MSCC_CMD(NGBE_MSCA_CMD_READ) |
- NGBE_MSCC_BUSY |
- NGBE_MDIO_CLK(6);
- wr32(wx, NGBE_MSCC, command);
+ command = WX_MSCA_RA(regnum) |
+ WX_MSCA_PA(phy_addr) |
+ WX_MSCA_DA(device_type);
+ wr32(wx, WX_MSCA, command);
+ command = WX_MSCC_CMD(WX_MSCA_CMD_READ) |
+ WX_MSCC_BUSY |
+ WX_MDIO_CLK(6);
+ wr32(wx, WX_MSCC, command);
/* wait to complete */
- ret = read_poll_timeout(rd32, val, !(val & NGBE_MSCC_BUSY), 1000,
- 100000, false, wx, NGBE_MSCC);
+ ret = read_poll_timeout(rd32, val, !(val & WX_MSCC_BUSY), 1000,
+ 100000, false, wx, WX_MSCC);
if (ret) {
wx_err(wx, "Mdio read c22 command did not complete.\n");
return ret;
}
- return (u16)rd32(wx, NGBE_MSCC);
+ return (u16)rd32(wx, WX_MSCC);
}
static int ngbe_phy_write_reg_mdi_c22(struct mii_bus *bus, int phy_addr, int regnum, u16 value)
@@ -65,19 +65,19 @@ static int ngbe_phy_write_reg_mdi_c22(struct mii_bus *bus, int phy_addr, int reg
wr32(wx, NGBE_MDIO_CLAUSE_SELECT, 0xF);
/* setup and write the address cycle command */
- command = NGBE_MSCA_RA(regnum) |
- NGBE_MSCA_PA(phy_addr) |
- NGBE_MSCA_DA(device_type);
- wr32(wx, NGBE_MSCA, command);
+ command = WX_MSCA_RA(regnum) |
+ WX_MSCA_PA(phy_addr) |
+ WX_MSCA_DA(device_type);
+ wr32(wx, WX_MSCA, command);
command = value |
- NGBE_MSCC_CMD(NGBE_MSCA_CMD_WRITE) |
- NGBE_MSCC_BUSY |
- NGBE_MDIO_CLK(6);
- wr32(wx, NGBE_MSCC, command);
+ WX_MSCC_CMD(WX_MSCA_CMD_WRITE) |
+ WX_MSCC_BUSY |
+ WX_MDIO_CLK(6);
+ wr32(wx, WX_MSCC, command);
/* wait to complete */
- ret = read_poll_timeout(rd32, val, !(val & NGBE_MSCC_BUSY), 1000,
- 100000, false, wx, NGBE_MSCC);
+ ret = read_poll_timeout(rd32, val, !(val & WX_MSCC_BUSY), 1000,
+ 100000, false, wx, WX_MSCC);
if (ret)
wx_err(wx, "Mdio write c22 command did not complete.\n");
@@ -92,24 +92,24 @@ static int ngbe_phy_read_reg_mdi_c45(struct mii_bus *bus, int phy_addr, int devn
wr32(wx, NGBE_MDIO_CLAUSE_SELECT, 0x0);
/* setup and write the address cycle command */
- command = NGBE_MSCA_RA(regnum) |
- NGBE_MSCA_PA(phy_addr) |
- NGBE_MSCA_DA(devnum);
- wr32(wx, NGBE_MSCA, command);
- command = NGBE_MSCC_CMD(NGBE_MSCA_CMD_READ) |
- NGBE_MSCC_BUSY |
- NGBE_MDIO_CLK(6);
- wr32(wx, NGBE_MSCC, command);
+ command = WX_MSCA_RA(regnum) |
+ WX_MSCA_PA(phy_addr) |
+ WX_MSCA_DA(devnum);
+ wr32(wx, WX_MSCA, command);
+ command = WX_MSCC_CMD(WX_MSCA_CMD_READ) |
+ WX_MSCC_BUSY |
+ WX_MDIO_CLK(6);
+ wr32(wx, WX_MSCC, command);
/* wait to complete */
- ret = read_poll_timeout(rd32, val, !(val & NGBE_MSCC_BUSY), 1000,
- 100000, false, wx, NGBE_MSCC);
+ ret = read_poll_timeout(rd32, val, !(val & WX_MSCC_BUSY), 1000,
+ 100000, false, wx, WX_MSCC);
if (ret) {
wx_err(wx, "Mdio read c45 command did not complete.\n");
return ret;
}
- return (u16)rd32(wx, NGBE_MSCC);
+ return (u16)rd32(wx, WX_MSCC);
}
static int ngbe_phy_write_reg_mdi_c45(struct mii_bus *bus, int phy_addr,
@@ -121,19 +121,19 @@ static int ngbe_phy_write_reg_mdi_c45(struct mii_bus *bus, int phy_addr,
wr32(wx, NGBE_MDIO_CLAUSE_SELECT, 0x0);
/* setup and write the address cycle command */
- command = NGBE_MSCA_RA(regnum) |
- NGBE_MSCA_PA(phy_addr) |
- NGBE_MSCA_DA(devnum);
- wr32(wx, NGBE_MSCA, command);
+ command = WX_MSCA_RA(regnum) |
+ WX_MSCA_PA(phy_addr) |
+ WX_MSCA_DA(devnum);
+ wr32(wx, WX_MSCA, command);
command = value |
- NGBE_MSCC_CMD(NGBE_MSCA_CMD_WRITE) |
- NGBE_MSCC_BUSY |
- NGBE_MDIO_CLK(6);
- wr32(wx, NGBE_MSCC, command);
+ WX_MSCC_CMD(WX_MSCA_CMD_WRITE) |
+ WX_MSCC_BUSY |
+ WX_MDIO_CLK(6);
+ wr32(wx, WX_MSCC, command);
/* wait to complete */
- ret = read_poll_timeout(rd32, val, !(val & NGBE_MSCC_BUSY), 1000,
- 100000, false, wx, NGBE_MSCC);
+ ret = read_poll_timeout(rd32, val, !(val & WX_MSCC_BUSY), 1000,
+ 100000, false, wx, WX_MSCC);
if (ret)
wx_err(wx, "Mdio write c45 command did not complete.\n");
diff --git a/drivers/net/ethernet/wangxun/ngbe/ngbe_type.h b/drivers/net/ethernet/wangxun/ngbe/ngbe_type.h
index b70eca397b67..72c8cd2d5575 100644
--- a/drivers/net/ethernet/wangxun/ngbe/ngbe_type.h
+++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_type.h
@@ -59,25 +59,6 @@
#define NGBE_EEPROM_VERSION_L 0x1D
#define NGBE_EEPROM_VERSION_H 0x1E
-/* mdio access */
-#define NGBE_MSCA 0x11200
-#define NGBE_MSCA_RA(v) FIELD_PREP(U16_MAX, v)
-#define NGBE_MSCA_PA(v) FIELD_PREP(GENMASK(20, 16), v)
-#define NGBE_MSCA_DA(v) FIELD_PREP(GENMASK(25, 21), v)
-#define NGBE_MSCC 0x11204
-#define NGBE_MSCC_CMD(v) FIELD_PREP(GENMASK(17, 16), v)
-
-enum NGBE_MSCA_CMD_value {
- NGBE_MSCA_CMD_RSV = 0,
- NGBE_MSCA_CMD_WRITE,
- NGBE_MSCA_CMD_POST_READ,
- NGBE_MSCA_CMD_READ,
-};
-
-#define NGBE_MSCC_SADDR BIT(18)
-#define NGBE_MSCC_BUSY BIT(22)
-#define NGBE_MDIO_CLK(v) FIELD_PREP(GENMASK(21, 19), v)
-
/* Media-dependent registers. */
#define NGBE_MDIO_CLAUSE_SELECT 0x11220
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.c
index 6e130d1f7a7b..372745250270 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.c
@@ -14,6 +14,34 @@
#include "txgbe_hw.h"
/**
+ * txgbe_disable_sec_tx_path - Stops the transmit data path
+ * @wx: pointer to hardware structure
+ *
+ * Stops the transmit data path and waits for the HW to internally empty
+ * the tx security block
+ **/
+int txgbe_disable_sec_tx_path(struct wx *wx)
+{
+ int val;
+
+ wr32m(wx, WX_TSC_CTL, WX_TSC_CTL_TX_DIS, WX_TSC_CTL_TX_DIS);
+ return read_poll_timeout(rd32, val, val & WX_TSC_ST_SECTX_RDY,
+ 1000, 20000, false, wx, WX_TSC_ST);
+}
+
+/**
+ * txgbe_enable_sec_tx_path - Enables the transmit data path
+ * @wx: pointer to hardware structure
+ *
+ * Enables the transmit data path.
+ **/
+void txgbe_enable_sec_tx_path(struct wx *wx)
+{
+ wr32m(wx, WX_TSC_CTL, WX_TSC_CTL_TX_DIS, 0);
+ WX_WRITE_FLUSH(wx);
+}
+
+/**
* txgbe_init_thermal_sensor_thresh - Inits thermal sensor thresholds
* @wx: pointer to hardware structure
*
@@ -257,17 +285,20 @@ static void txgbe_reset_misc(struct wx *wx)
int txgbe_reset_hw(struct wx *wx)
{
int status;
- u32 val;
/* Call adapter stop to disable tx/rx and clear interrupts */
status = wx_stop_adapter(wx);
if (status != 0)
return status;
- val = WX_MIS_RST_LAN_RST(wx->bus.func);
- wr32(wx, WX_MIS_RST, val | rd32(wx, WX_MIS_RST));
- WX_WRITE_FLUSH(wx);
- usleep_range(10, 100);
+ if (wx->media_type != sp_media_copper) {
+ u32 val;
+
+ val = WX_MIS_RST_LAN_RST(wx->bus.func);
+ wr32(wx, WX_MIS_RST, val | rd32(wx, WX_MIS_RST));
+ WX_WRITE_FLUSH(wx);
+ usleep_range(10, 100);
+ }
status = wx_check_flash_load(wx, TXGBE_SPI_ILDR_STATUS_LAN_SW_RST(wx->bus.func));
if (status != 0)
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.h
index e82f65dff8a6..abc729eb187a 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.h
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.h
@@ -4,6 +4,8 @@
#ifndef _TXGBE_HW_H_
#define _TXGBE_HW_H_
+int txgbe_disable_sec_tx_path(struct wx *wx);
+void txgbe_enable_sec_tx_path(struct wx *wx);
int txgbe_read_pba_string(struct wx *wx, u8 *pba_num, u32 pba_num_size);
int txgbe_validate_eeprom_checksum(struct wx *wx, u16 *checksum_val);
int txgbe_reset_hw(struct wx *wx);
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
index 46eba6d6188b..5c3aed516ac2 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
@@ -301,6 +301,49 @@ static void txgbe_down(struct wx *wx)
}
/**
+ * txgbe_init_type_code - Initialize the shared code
+ * @wx: pointer to hardware structure
+ **/
+static void txgbe_init_type_code(struct wx *wx)
+{
+ u8 device_type = wx->subsystem_device_id & 0xF0;
+
+ switch (wx->device_id) {
+ case TXGBE_DEV_ID_SP1000:
+ case TXGBE_DEV_ID_WX1820:
+ wx->mac.type = wx_mac_sp;
+ break;
+ default:
+ wx->mac.type = wx_mac_unknown;
+ break;
+ }
+
+ switch (device_type) {
+ case TXGBE_ID_SFP:
+ wx->media_type = sp_media_fiber;
+ break;
+ case TXGBE_ID_XAUI:
+ case TXGBE_ID_SGMII:
+ wx->media_type = sp_media_copper;
+ break;
+ case TXGBE_ID_KR_KX_KX4:
+ case TXGBE_ID_MAC_XAUI:
+ case TXGBE_ID_MAC_SGMII:
+ wx->media_type = sp_media_backplane;
+ break;
+ case TXGBE_ID_SFI_XAUI:
+ if (wx->bus.func == 0)
+ wx->media_type = sp_media_fiber;
+ else
+ wx->media_type = sp_media_copper;
+ break;
+ default:
+ wx->media_type = sp_media_unknown;
+ break;
+ }
+}
+
+/**
* txgbe_sw_init - Initialize general software structures (struct wx)
* @wx: board private structure to initialize
**/
@@ -324,15 +367,7 @@ static int txgbe_sw_init(struct wx *wx)
return err;
}
- switch (wx->device_id) {
- case TXGBE_DEV_ID_SP1000:
- case TXGBE_DEV_ID_WX1820:
- wx->mac.type = wx_mac_sp;
- break;
- default:
- wx->mac.type = wx_mac_unknown;
- break;
- }
+ txgbe_init_type_code(wx);
/* Set common capability flags and settings */
wx->max_q_vectors = TXGBE_MAX_MSIX_VECTORS;
@@ -663,6 +698,9 @@ static int txgbe_probe(struct pci_dev *pdev,
"0x%08x", etrack_id);
}
+ if (etrack_id < 0x20010)
+ dev_warn(&pdev->dev, "Please upgrade the firmware to 0x20010 or above.\n");
+
txgbe = devm_kzalloc(&pdev->dev, sizeof(*txgbe), GFP_KERNEL);
if (!txgbe) {
err = -ENOMEM;
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
index 819d1db34643..4159c84035fd 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
@@ -18,6 +18,7 @@
#include "../libwx/wx_hw.h"
#include "txgbe_type.h"
#include "txgbe_phy.h"
+#include "txgbe_hw.h"
static int txgbe_swnodes_register(struct txgbe *txgbe)
{
@@ -160,7 +161,10 @@ static struct phylink_pcs *txgbe_phylink_mac_select(struct phylink_config *confi
{
struct txgbe *txgbe = netdev_to_txgbe(to_net_dev(config->dev));
- return &txgbe->xpcs->pcs;
+ if (interface == PHY_INTERFACE_MODE_10GBASER)
+ return &txgbe->xpcs->pcs;
+
+ return NULL;
}
static void txgbe_mac_config(struct phylink_config *config, unsigned int mode,
@@ -210,8 +214,32 @@ static void txgbe_mac_link_up(struct phylink_config *config,
wr32(wx, WX_MAC_WDG_TIMEOUT, wdg);
}
+static int txgbe_mac_prepare(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);
+ wr32m(wx, WX_MAC_RX_CFG, WX_MAC_RX_CFG_RE, 0);
+
+ return txgbe_disable_sec_tx_path(wx);
+}
+
+static int txgbe_mac_finish(struct phylink_config *config, unsigned int mode,
+ phy_interface_t interface)
+{
+ struct wx *wx = netdev_priv(to_net_dev(config->dev));
+
+ txgbe_enable_sec_tx_path(wx);
+ wr32m(wx, WX_MAC_RX_CFG, WX_MAC_RX_CFG_RE, WX_MAC_RX_CFG_RE);
+
+ return 0;
+}
+
static const struct phylink_mac_ops txgbe_mac_ops = {
.mac_select_pcs = txgbe_phylink_mac_select,
+ .mac_prepare = txgbe_mac_prepare,
+ .mac_finish = txgbe_mac_finish,
.mac_config = txgbe_mac_config,
.mac_link_down = txgbe_mac_link_down,
.mac_link_up = txgbe_mac_link_up,
@@ -219,8 +247,8 @@ static const struct phylink_mac_ops txgbe_mac_ops = {
static int txgbe_phylink_init(struct txgbe *txgbe)
{
+ struct fwnode_handle *fwnode = NULL;
struct phylink_config *config;
- struct fwnode_handle *fwnode;
struct wx *wx = txgbe->wx;
phy_interface_t phy_mode;
struct phylink *phylink;
@@ -231,14 +259,34 @@ static int txgbe_phylink_init(struct txgbe *txgbe)
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]);
+ config->mac_capabilities = MAC_10000FD | MAC_1000FD | MAC_100FD |
+ MAC_SYM_PAUSE | MAC_ASYM_PAUSE;
+
+ if (wx->media_type == sp_media_copper) {
+ phy_mode = PHY_INTERFACE_MODE_XAUI;
+ __set_bit(PHY_INTERFACE_MODE_XAUI, config->supported_interfaces);
+ } else {
+ phy_mode = PHY_INTERFACE_MODE_10GBASER;
+ fwnode = software_node_fwnode(txgbe->nodes.group[SWNODE_PHYLINK]);
+ __set_bit(PHY_INTERFACE_MODE_10GBASER, config->supported_interfaces);
+ __set_bit(PHY_INTERFACE_MODE_1000BASEX, config->supported_interfaces);
+ __set_bit(PHY_INTERFACE_MODE_SGMII, config->supported_interfaces);
+ }
+
phylink = phylink_create(config, fwnode, phy_mode, &txgbe_mac_ops);
if (IS_ERR(phylink))
return PTR_ERR(phylink);
+ if (wx->phydev) {
+ int ret;
+
+ ret = phylink_connect_phy(phylink, wx->phydev);
+ if (ret) {
+ phylink_destroy(phylink);
+ return ret;
+ }
+ }
+
txgbe->phylink = phylink;
return 0;
@@ -431,7 +479,8 @@ 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)) {
+ if (eicr & (TXGBE_PX_MISC_ETH_LK | TXGBE_PX_MISC_ETH_LKDN |
+ TXGBE_PX_MISC_ETH_AN)) {
u32 reg = rd32(wx, TXGBE_CFG_PORT_ST);
phylink_mac_change(txgbe->phylink, !!(reg & TXGBE_CFG_PORT_ST_LINK_UP));
@@ -598,10 +647,117 @@ static int txgbe_sfp_register(struct txgbe *txgbe)
return 0;
}
+static int txgbe_phy_read(struct mii_bus *bus, int phy_addr,
+ int devnum, int regnum)
+{
+ struct wx *wx = bus->priv;
+ u32 val, command;
+ int ret;
+
+ /* setup and write the address cycle command */
+ command = WX_MSCA_RA(regnum) |
+ WX_MSCA_PA(phy_addr) |
+ WX_MSCA_DA(devnum);
+ wr32(wx, WX_MSCA, command);
+
+ command = WX_MSCC_CMD(WX_MSCA_CMD_READ) | WX_MSCC_BUSY;
+ wr32(wx, WX_MSCC, command);
+
+ /* wait to complete */
+ ret = read_poll_timeout(rd32, val, !(val & WX_MSCC_BUSY), 1000,
+ 100000, false, wx, WX_MSCC);
+ if (ret) {
+ wx_err(wx, "Mdio read c45 command did not complete.\n");
+ return ret;
+ }
+
+ return (u16)rd32(wx, WX_MSCC);
+}
+
+static int txgbe_phy_write(struct mii_bus *bus, int phy_addr,
+ int devnum, int regnum, u16 value)
+{
+ struct wx *wx = bus->priv;
+ int ret, command;
+ u16 val;
+
+ /* setup and write the address cycle command */
+ command = WX_MSCA_RA(regnum) |
+ WX_MSCA_PA(phy_addr) |
+ WX_MSCA_DA(devnum);
+ wr32(wx, WX_MSCA, command);
+
+ command = value | WX_MSCC_CMD(WX_MSCA_CMD_WRITE) | WX_MSCC_BUSY;
+ wr32(wx, WX_MSCC, command);
+
+ /* wait to complete */
+ ret = read_poll_timeout(rd32, val, !(val & WX_MSCC_BUSY), 1000,
+ 100000, false, wx, WX_MSCC);
+ if (ret)
+ wx_err(wx, "Mdio write c45 command did not complete.\n");
+
+ return ret;
+}
+
+static int txgbe_ext_phy_init(struct txgbe *txgbe)
+{
+ struct phy_device *phydev;
+ struct mii_bus *mii_bus;
+ struct pci_dev *pdev;
+ struct wx *wx;
+ int ret = 0;
+
+ wx = txgbe->wx;
+ pdev = wx->pdev;
+
+ mii_bus = devm_mdiobus_alloc(&pdev->dev);
+ if (!mii_bus)
+ return -ENOMEM;
+
+ mii_bus->name = "txgbe_mii_bus";
+ mii_bus->read_c45 = &txgbe_phy_read;
+ mii_bus->write_c45 = &txgbe_phy_write;
+ mii_bus->parent = &pdev->dev;
+ mii_bus->phy_mask = GENMASK(31, 1);
+ mii_bus->priv = wx;
+ snprintf(mii_bus->id, MII_BUS_ID_SIZE, "txgbe-%x",
+ (pdev->bus->number << 8) | pdev->devfn);
+
+ ret = devm_mdiobus_register(&pdev->dev, mii_bus);
+ if (ret) {
+ wx_err(wx, "failed to register MDIO bus: %d\n", ret);
+ return ret;
+ }
+
+ phydev = phy_find_first(mii_bus);
+ if (!phydev) {
+ wx_err(wx, "no PHY found\n");
+ return -ENODEV;
+ }
+
+ phy_attached_info(phydev);
+
+ wx->link = 0;
+ wx->speed = 0;
+ wx->duplex = 0;
+ wx->phydev = phydev;
+
+ ret = txgbe_phylink_init(txgbe);
+ if (ret) {
+ wx_err(wx, "failed to init phylink: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
int txgbe_init_phy(struct txgbe *txgbe)
{
int ret;
+ if (txgbe->wx->media_type == sp_media_copper)
+ return txgbe_ext_phy_init(txgbe);
+
ret = txgbe_swnodes_register(txgbe);
if (ret) {
wx_err(txgbe->wx, "failed to register software nodes\n");
@@ -663,6 +819,12 @@ err_unregister_swnode:
void txgbe_remove_phy(struct txgbe *txgbe)
{
+ if (txgbe->wx->media_type == sp_media_copper) {
+ phylink_disconnect_phy(txgbe->phylink);
+ phylink_destroy(txgbe->phylink);
+ return;
+ }
+
platform_device_unregister(txgbe->sfp_dev);
platform_device_unregister(txgbe->i2c_dev);
clkdev_drop(txgbe->clock);
diff --git a/drivers/net/pcs/Makefile b/drivers/net/pcs/Makefile
index ea662a7989b2..fb1694192ae6 100644
--- a/drivers/net/pcs/Makefile
+++ b/drivers/net/pcs/Makefile
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
# Makefile for Linux PCS drivers
-pcs_xpcs-$(CONFIG_PCS_XPCS) := pcs-xpcs.o pcs-xpcs-nxp.o
+pcs_xpcs-$(CONFIG_PCS_XPCS) := pcs-xpcs.o pcs-xpcs-nxp.o pcs-xpcs-wx.o
obj-$(CONFIG_PCS_XPCS) += pcs_xpcs.o
obj-$(CONFIG_PCS_LYNX) += pcs-lynx.o
diff --git a/drivers/net/pcs/pcs-xpcs-wx.c b/drivers/net/pcs/pcs-xpcs-wx.c
new file mode 100644
index 000000000000..19c75886f070
--- /dev/null
+++ b/drivers/net/pcs/pcs-xpcs-wx.c
@@ -0,0 +1,209 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2015 - 2023 Beijing WangXun Technology Co., Ltd. */
+
+#include <linux/pcs/pcs-xpcs.h>
+#include <linux/mdio.h>
+#include "pcs-xpcs.h"
+
+/* VR_XS_PMA_MMD */
+#define TXGBE_PMA_MMD 0x8020
+#define TXGBE_TX_GENCTL1 0x11
+#define TXGBE_TX_GENCTL1_VBOOST_LVL GENMASK(10, 8)
+#define TXGBE_TX_GENCTL1_VBOOST_EN0 BIT(4)
+#define TXGBE_TX_GEN_CTL2 0x12
+#define TXGBE_TX_GEN_CTL2_TX0_WIDTH(v) FIELD_PREP(GENMASK(9, 8), v)
+#define TXGBE_TX_RATE_CTL 0x14
+#define TXGBE_TX_RATE_CTL_TX0_RATE(v) FIELD_PREP(GENMASK(2, 0), v)
+#define TXGBE_RX_GEN_CTL2 0x32
+#define TXGBE_RX_GEN_CTL2_RX0_WIDTH(v) FIELD_PREP(GENMASK(9, 8), v)
+#define TXGBE_RX_GEN_CTL3 0x33
+#define TXGBE_RX_GEN_CTL3_LOS_TRSHLD0 GENMASK(2, 0)
+#define TXGBE_RX_RATE_CTL 0x34
+#define TXGBE_RX_RATE_CTL_RX0_RATE(v) FIELD_PREP(GENMASK(1, 0), v)
+#define TXGBE_RX_EQ_ATTN_CTL 0x37
+#define TXGBE_RX_EQ_ATTN_LVL0 GENMASK(2, 0)
+#define TXGBE_RX_EQ_CTL0 0x38
+#define TXGBE_RX_EQ_CTL0_VGA1_GAIN(v) FIELD_PREP(GENMASK(15, 12), v)
+#define TXGBE_RX_EQ_CTL0_VGA2_GAIN(v) FIELD_PREP(GENMASK(11, 8), v)
+#define TXGBE_RX_EQ_CTL0_CTLE_POLE(v) FIELD_PREP(GENMASK(7, 5), v)
+#define TXGBE_RX_EQ_CTL0_CTLE_BOOST(v) FIELD_PREP(GENMASK(4, 0), v)
+#define TXGBE_RX_EQ_CTL4 0x3C
+#define TXGBE_RX_EQ_CTL4_CONT_OFF_CAN0 BIT(4)
+#define TXGBE_RX_EQ_CTL4_CONT_ADAPT0 BIT(0)
+#define TXGBE_AFE_DFE_ENABLE 0x3D
+#define TXGBE_DFE_EN_0 BIT(4)
+#define TXGBE_AFE_EN_0 BIT(0)
+#define TXGBE_DFE_TAP_CTL0 0x3E
+#define TXGBE_MPLLA_CTL0 0x51
+#define TXGBE_MPLLA_CTL2 0x53
+#define TXGBE_MPLLA_CTL2_DIV16P5_CLK_EN BIT(10)
+#define TXGBE_MPLLA_CTL2_DIV10_CLK_EN BIT(9)
+#define TXGBE_MPLLA_CTL3 0x57
+#define TXGBE_MISC_CTL0 0x70
+#define TXGBE_MISC_CTL0_PLL BIT(15)
+#define TXGBE_MISC_CTL0_CR_PARA_SEL BIT(14)
+#define TXGBE_MISC_CTL0_RX_VREF(v) FIELD_PREP(GENMASK(12, 8), v)
+#define TXGBE_VCO_CAL_LD0 0x72
+#define TXGBE_VCO_CAL_REF0 0x76
+
+static int txgbe_read_pma(struct dw_xpcs *xpcs, int reg)
+{
+ return xpcs_read(xpcs, MDIO_MMD_PMAPMD, TXGBE_PMA_MMD + reg);
+}
+
+static int txgbe_write_pma(struct dw_xpcs *xpcs, int reg, u16 val)
+{
+ return xpcs_write(xpcs, MDIO_MMD_PMAPMD, TXGBE_PMA_MMD + reg, val);
+}
+
+static void txgbe_pma_config_10gbaser(struct dw_xpcs *xpcs)
+{
+ int val;
+
+ txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL0, 0x21);
+ txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL3, 0);
+ val = txgbe_read_pma(xpcs, TXGBE_TX_GENCTL1);
+ val = u16_replace_bits(val, 0x5, TXGBE_TX_GENCTL1_VBOOST_LVL);
+ txgbe_write_pma(xpcs, TXGBE_TX_GENCTL1, val);
+ txgbe_write_pma(xpcs, TXGBE_MISC_CTL0, TXGBE_MISC_CTL0_PLL |
+ TXGBE_MISC_CTL0_CR_PARA_SEL | TXGBE_MISC_CTL0_RX_VREF(0xF));
+ txgbe_write_pma(xpcs, TXGBE_VCO_CAL_LD0, 0x549);
+ txgbe_write_pma(xpcs, TXGBE_VCO_CAL_REF0, 0x29);
+ txgbe_write_pma(xpcs, TXGBE_TX_RATE_CTL, 0);
+ txgbe_write_pma(xpcs, TXGBE_RX_RATE_CTL, 0);
+ txgbe_write_pma(xpcs, TXGBE_TX_GEN_CTL2, TXGBE_TX_GEN_CTL2_TX0_WIDTH(3));
+ txgbe_write_pma(xpcs, TXGBE_RX_GEN_CTL2, TXGBE_RX_GEN_CTL2_RX0_WIDTH(3));
+ txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL2, TXGBE_MPLLA_CTL2_DIV16P5_CLK_EN |
+ TXGBE_MPLLA_CTL2_DIV10_CLK_EN);
+
+ txgbe_write_pma(xpcs, TXGBE_RX_EQ_CTL0, TXGBE_RX_EQ_CTL0_CTLE_POLE(2) |
+ TXGBE_RX_EQ_CTL0_CTLE_BOOST(5));
+ val = txgbe_read_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL);
+ val &= ~TXGBE_RX_EQ_ATTN_LVL0;
+ txgbe_write_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL, val);
+ txgbe_write_pma(xpcs, TXGBE_DFE_TAP_CTL0, 0xBE);
+ val = txgbe_read_pma(xpcs, TXGBE_AFE_DFE_ENABLE);
+ val &= ~(TXGBE_DFE_EN_0 | TXGBE_AFE_EN_0);
+ txgbe_write_pma(xpcs, TXGBE_AFE_DFE_ENABLE, val);
+ val = txgbe_read_pma(xpcs, TXGBE_RX_EQ_CTL4);
+ val &= ~TXGBE_RX_EQ_CTL4_CONT_ADAPT0;
+ txgbe_write_pma(xpcs, TXGBE_RX_EQ_CTL4, val);
+}
+
+static void txgbe_pma_config_1g(struct dw_xpcs *xpcs)
+{
+ int val;
+
+ val = txgbe_read_pma(xpcs, TXGBE_TX_GENCTL1);
+ val = u16_replace_bits(val, 0x5, TXGBE_TX_GENCTL1_VBOOST_LVL);
+ val &= ~TXGBE_TX_GENCTL1_VBOOST_EN0;
+ txgbe_write_pma(xpcs, TXGBE_TX_GENCTL1, val);
+ txgbe_write_pma(xpcs, TXGBE_MISC_CTL0, TXGBE_MISC_CTL0_PLL |
+ TXGBE_MISC_CTL0_CR_PARA_SEL | TXGBE_MISC_CTL0_RX_VREF(0xF));
+
+ txgbe_write_pma(xpcs, TXGBE_RX_EQ_CTL0, TXGBE_RX_EQ_CTL0_VGA1_GAIN(7) |
+ TXGBE_RX_EQ_CTL0_VGA2_GAIN(7) | TXGBE_RX_EQ_CTL0_CTLE_BOOST(6));
+ val = txgbe_read_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL);
+ val &= ~TXGBE_RX_EQ_ATTN_LVL0;
+ txgbe_write_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL, val);
+ txgbe_write_pma(xpcs, TXGBE_DFE_TAP_CTL0, 0);
+ val = txgbe_read_pma(xpcs, TXGBE_RX_GEN_CTL3);
+ val = u16_replace_bits(val, 0x4, TXGBE_RX_GEN_CTL3_LOS_TRSHLD0);
+ txgbe_write_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL, val);
+
+ txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL0, 0x20);
+ txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL3, 0x46);
+ txgbe_write_pma(xpcs, TXGBE_VCO_CAL_LD0, 0x540);
+ txgbe_write_pma(xpcs, TXGBE_VCO_CAL_REF0, 0x2A);
+ txgbe_write_pma(xpcs, TXGBE_AFE_DFE_ENABLE, 0);
+ txgbe_write_pma(xpcs, TXGBE_RX_EQ_CTL4, TXGBE_RX_EQ_CTL4_CONT_OFF_CAN0);
+ txgbe_write_pma(xpcs, TXGBE_TX_RATE_CTL, TXGBE_TX_RATE_CTL_TX0_RATE(3));
+ txgbe_write_pma(xpcs, TXGBE_RX_RATE_CTL, TXGBE_RX_RATE_CTL_RX0_RATE(3));
+ txgbe_write_pma(xpcs, TXGBE_TX_GEN_CTL2, TXGBE_TX_GEN_CTL2_TX0_WIDTH(1));
+ txgbe_write_pma(xpcs, TXGBE_RX_GEN_CTL2, TXGBE_RX_GEN_CTL2_RX0_WIDTH(1));
+ txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL2, TXGBE_MPLLA_CTL2_DIV10_CLK_EN);
+}
+
+static int txgbe_pcs_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_PSEQ_ST) == DW_PSEQ_ST_GOOD,
+ 10000, 1000000, false,
+ xpcs, DW_VR_XS_PCS_DIG_STS);
+ if (ret < 0)
+ dev_err(&xpcs->mdiodev->dev, "xpcs power-up timeout\n");
+
+ return ret;
+}
+
+static int txgbe_pma_init_done(struct dw_xpcs *xpcs)
+{
+ int val, ret;
+
+ xpcs_write_vpcs(xpcs, DW_VR_XS_PCS_DIG_CTRL1, DW_VR_RST | DW_EN_VSMMD1);
+
+ /* wait pma initialization done */
+ ret = read_poll_timeout(xpcs_read_vpcs, val, !(val & DW_VR_RST),
+ 100000, 10000000, false,
+ xpcs, DW_VR_XS_PCS_DIG_CTRL1);
+ if (ret < 0)
+ dev_err(&xpcs->mdiodev->dev, "xpcs pma initialization timeout\n");
+
+ return ret;
+}
+
+static bool txgbe_xpcs_mode_quirk(struct dw_xpcs *xpcs)
+{
+ int ret;
+
+ /* When txgbe do LAN reset, PCS will change to default 10GBASE-R mode */
+ ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_CTRL2);
+ ret &= MDIO_PCS_CTRL2_TYPE;
+ if ((ret == MDIO_PCS_CTRL2_10GBR &&
+ xpcs->interface != PHY_INTERFACE_MODE_10GBASER) ||
+ xpcs->interface == PHY_INTERFACE_MODE_SGMII)
+ return true;
+
+ return false;
+}
+
+int txgbe_xpcs_switch_mode(struct dw_xpcs *xpcs, phy_interface_t interface)
+{
+ int val, ret;
+
+ switch (interface) {
+ case PHY_INTERFACE_MODE_10GBASER:
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_1000BASEX:
+ break;
+ default:
+ return 0;
+ }
+
+ if (xpcs->interface == interface && !txgbe_xpcs_mode_quirk(xpcs))
+ return 0;
+
+ xpcs->interface = interface;
+
+ ret = txgbe_pcs_poll_power_up(xpcs);
+ if (ret < 0)
+ return ret;
+
+ if (interface == PHY_INTERFACE_MODE_10GBASER) {
+ 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);
+ txgbe_pma_config_10gbaser(xpcs);
+ } else {
+ xpcs_write(xpcs, MDIO_MMD_PCS, MDIO_CTRL2, MDIO_PCS_CTRL2_10GBX);
+ xpcs_write(xpcs, MDIO_MMD_PMAPMD, MDIO_CTRL1, 0);
+ xpcs_write(xpcs, MDIO_MMD_PCS, MDIO_CTRL1, 0);
+ txgbe_pma_config_1g(xpcs);
+ }
+
+ return txgbe_pma_init_done(xpcs);
+}
diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c
index 44b037646865..4dbc21f604f2 100644
--- a/drivers/net/pcs/pcs-xpcs.c
+++ b/drivers/net/pcs/pcs-xpcs.c
@@ -228,16 +228,39 @@ static int xpcs_write_vendor(struct dw_xpcs *xpcs, int dev, int reg,
return xpcs_write(xpcs, dev, DW_VENDOR | reg, val);
}
-static int xpcs_read_vpcs(struct dw_xpcs *xpcs, int reg)
+int xpcs_read_vpcs(struct dw_xpcs *xpcs, int reg)
{
return xpcs_read_vendor(xpcs, MDIO_MMD_PCS, reg);
}
-static int xpcs_write_vpcs(struct dw_xpcs *xpcs, int reg, u16 val)
+int xpcs_write_vpcs(struct dw_xpcs *xpcs, int reg, u16 val)
{
return xpcs_write_vendor(xpcs, MDIO_MMD_PCS, reg, val);
}
+static int xpcs_dev_flag(struct dw_xpcs *xpcs)
+{
+ int ret, oui;
+
+ ret = xpcs_read(xpcs, MDIO_MMD_PMAPMD, MDIO_DEVID1);
+ if (ret < 0)
+ return ret;
+
+ oui = ret;
+
+ ret = xpcs_read(xpcs, MDIO_MMD_PMAPMD, MDIO_DEVID2);
+ if (ret < 0)
+ return ret;
+
+ ret = (ret >> 10) & 0x3F;
+ oui |= ret << 16;
+
+ if (oui == DW_OUI_WX)
+ xpcs->dev_flag = DW_DEV_TXGBE;
+
+ return 0;
+}
+
static int xpcs_poll_reset(struct dw_xpcs *xpcs, int dev)
{
/* Poll until the reset bit clears (50ms per retry == 0.6 sec) */
@@ -660,7 +683,10 @@ EXPORT_SYMBOL_GPL(xpcs_config_eee);
static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs,
unsigned int neg_mode)
{
- int ret, mdio_ctrl;
+ int ret, mdio_ctrl, tx_conf;
+
+ if (xpcs->dev_flag == DW_DEV_TXGBE)
+ xpcs_write_vpcs(xpcs, DW_VR_XS_PCS_DIG_CTRL1, DW_CL37_BP | DW_EN_VSMMD1);
/* For AN for C37 SGMII mode, the settings are :-
* 1) VR_MII_MMD_CTRL Bit(12) [AN_ENABLE] = 0b (Disable SGMII AN in case
@@ -697,9 +723,15 @@ static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs,
ret |= (DW_VR_MII_PCS_MODE_C37_SGMII <<
DW_VR_MII_AN_CTRL_PCS_MODE_SHIFT &
DW_VR_MII_PCS_MODE_MASK);
- ret |= (DW_VR_MII_TX_CONFIG_MAC_SIDE_SGMII <<
- DW_VR_MII_AN_CTRL_TX_CONFIG_SHIFT &
- DW_VR_MII_TX_CONFIG_MASK);
+ if (xpcs->dev_flag == DW_DEV_TXGBE) {
+ ret |= DW_VR_MII_AN_CTRL_8BIT;
+ /* Hardware requires it to be PHY side SGMII */
+ tx_conf = DW_VR_MII_TX_CONFIG_PHY_SIDE_SGMII;
+ } else {
+ tx_conf = DW_VR_MII_TX_CONFIG_MAC_SIDE_SGMII;
+ }
+ ret |= tx_conf << DW_VR_MII_AN_CTRL_TX_CONFIG_SHIFT &
+ DW_VR_MII_TX_CONFIG_MASK;
ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL, ret);
if (ret < 0)
return ret;
@@ -713,6 +745,9 @@ static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs,
else
ret &= ~DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW;
+ if (xpcs->dev_flag == DW_DEV_TXGBE)
+ ret |= DW_VR_MII_DIG_CTRL1_PHY_MODE_CTRL;
+
ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1, ret);
if (ret < 0)
return ret;
@@ -732,6 +767,9 @@ static int xpcs_config_aneg_c37_1000basex(struct dw_xpcs *xpcs,
int ret, mdio_ctrl, adv;
bool changed = 0;
+ if (xpcs->dev_flag == DW_DEV_TXGBE)
+ xpcs_write_vpcs(xpcs, DW_VR_XS_PCS_DIG_CTRL1, DW_CL37_BP | DW_EN_VSMMD1);
+
/* According to Chap 7.12, to set 1000BASE-X C37 AN, AN must
* be disabled first:-
* 1) VR_MII_MMD_CTRL Bit(12)[AN_ENABLE] = 0b
@@ -753,6 +791,8 @@ static int xpcs_config_aneg_c37_1000basex(struct dw_xpcs *xpcs,
return ret;
ret &= ~DW_VR_MII_PCS_MODE_MASK;
+ if (!xpcs->pcs.poll)
+ ret |= DW_VR_MII_AN_INTR_EN;
ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL, ret);
if (ret < 0)
return ret;
@@ -818,6 +858,12 @@ int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface,
if (!compat)
return -ENODEV;
+ if (xpcs->dev_flag == DW_DEV_TXGBE) {
+ ret = txgbe_xpcs_switch_mode(xpcs, interface);
+ if (ret)
+ return ret;
+ }
+
switch (compat->an_mode) {
case DW_10GBASER:
break;
@@ -977,6 +1023,33 @@ static int xpcs_get_state_c37_sgmii(struct dw_xpcs *xpcs,
state->duplex = DUPLEX_FULL;
else
state->duplex = DUPLEX_HALF;
+ } else if (ret == DW_VR_MII_AN_STS_C37_ANCMPLT_INTR) {
+ int speed, duplex;
+
+ state->link = true;
+
+ speed = xpcs_read(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1);
+ if (speed < 0)
+ return speed;
+
+ speed &= SGMII_SPEED_SS13 | SGMII_SPEED_SS6;
+ if (speed == SGMII_SPEED_SS6)
+ state->speed = SPEED_1000;
+ else if (speed == SGMII_SPEED_SS13)
+ state->speed = SPEED_100;
+ else if (speed == 0)
+ state->speed = SPEED_10;
+
+ duplex = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_ADVERTISE);
+ if (duplex < 0)
+ return duplex;
+
+ if (duplex & DW_FULL_DUPLEX)
+ state->duplex = DUPLEX_FULL;
+ else if (duplex & DW_HALF_DUPLEX)
+ state->duplex = DUPLEX_HALF;
+
+ xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS, 0);
}
return 0;
@@ -1000,6 +1073,17 @@ static int xpcs_get_state_c37_1000basex(struct dw_xpcs *xpcs,
if (bmsr < 0)
return bmsr;
+ /* Clear AN complete interrupt */
+ if (!xpcs->pcs.poll) {
+ int an_intr;
+
+ an_intr = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS);
+ if (an_intr & DW_VR_MII_AN_STS_C37_ANCMPLT_INTR) {
+ an_intr &= ~DW_VR_MII_AN_STS_C37_ANCMPLT_INTR;
+ xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS, an_intr);
+ }
+ }
+
phylink_mii_c22_pcs_decode_state(state, bmsr, lpa);
}
@@ -1284,16 +1368,20 @@ static struct dw_xpcs *xpcs_create(struct mdio_device *mdiodev,
goto out;
}
+ ret = xpcs_dev_flag(xpcs);
+ if (ret)
+ goto out;
+
xpcs->pcs.ops = &xpcs_phylink_ops;
xpcs->pcs.neg_mode = true;
- if (compat->an_mode == DW_10GBASER)
- return xpcs;
- xpcs->pcs.poll = true;
+ if (xpcs->dev_flag != DW_DEV_TXGBE) {
+ xpcs->pcs.poll = true;
- ret = xpcs_soft_reset(xpcs, compat);
- if (ret)
- goto out;
+ ret = xpcs_soft_reset(xpcs, compat);
+ if (ret)
+ goto out;
+ }
return xpcs;
}
diff --git a/drivers/net/pcs/pcs-xpcs.h b/drivers/net/pcs/pcs-xpcs.h
index 68c6b5a62088..39a90417e535 100644
--- a/drivers/net/pcs/pcs-xpcs.h
+++ b/drivers/net/pcs/pcs-xpcs.h
@@ -15,8 +15,14 @@
/* VR_XS_PCS */
#define DW_USXGMII_RST BIT(10)
#define DW_USXGMII_EN BIT(9)
+#define DW_VR_XS_PCS_DIG_CTRL1 0x0000
+#define DW_VR_RST BIT(15)
+#define DW_EN_VSMMD1 BIT(13)
+#define DW_CL37_BP BIT(12)
#define DW_VR_XS_PCS_DIG_STS 0x0010
#define DW_RXFIFO_ERR GENMASK(6, 5)
+#define DW_PSEQ_ST GENMASK(4, 2)
+#define DW_PSEQ_ST_GOOD FIELD_PREP(GENMASK(4, 2), 0x4)
/* SR_MII */
#define DW_USXGMII_FULL BIT(8)
@@ -61,12 +67,14 @@
/* VR_MII_DIG_CTRL1 */
#define DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW BIT(9)
+#define DW_VR_MII_DIG_CTRL1_PHY_MODE_CTRL BIT(0)
/* VR_MII_DIG_CTRL2 */
#define DW_VR_MII_DIG_CTRL2_TX_POL_INV BIT(4)
#define DW_VR_MII_DIG_CTRL2_RX_POL_INV BIT(0)
/* VR_MII_AN_CTRL */
+#define DW_VR_MII_AN_CTRL_8BIT BIT(8)
#define DW_VR_MII_AN_CTRL_TX_CONFIG_SHIFT 3
#define DW_VR_MII_TX_CONFIG_MASK BIT(3)
#define DW_VR_MII_TX_CONFIG_PHY_SIDE_SGMII 0x1
@@ -75,8 +83,10 @@
#define DW_VR_MII_PCS_MODE_MASK GENMASK(2, 1)
#define DW_VR_MII_PCS_MODE_C37_1000BASEX 0x0
#define DW_VR_MII_PCS_MODE_C37_SGMII 0x2
+#define DW_VR_MII_AN_INTR_EN BIT(0)
/* VR_MII_AN_INTR_STS */
+#define DW_VR_MII_AN_STS_C37_ANCMPLT_INTR BIT(0)
#define DW_VR_MII_AN_STS_C37_ANSGM_FD BIT(1)
#define DW_VR_MII_AN_STS_C37_ANSGM_SP_SHIFT 2
#define DW_VR_MII_AN_STS_C37_ANSGM_SP GENMASK(3, 2)
@@ -90,6 +100,10 @@
#define SGMII_SPEED_SS13 BIT(13) /* SGMII speed along with SS6 */
#define SGMII_SPEED_SS6 BIT(6) /* SGMII speed along with SS13 */
+/* SR MII MMD AN Advertisement defines */
+#define DW_HALF_DUPLEX BIT(6)
+#define DW_FULL_DUPLEX BIT(5)
+
/* VR MII EEE Control 0 defines */
#define DW_VR_MII_EEE_LTX_EN BIT(0) /* LPI Tx Enable */
#define DW_VR_MII_EEE_LRX_EN BIT(1) /* LPI Rx Enable */
@@ -106,6 +120,9 @@
int xpcs_read(struct dw_xpcs *xpcs, int dev, u32 reg);
int xpcs_write(struct dw_xpcs *xpcs, int dev, u32 reg, u16 val);
+int xpcs_read_vpcs(struct dw_xpcs *xpcs, int reg);
+int xpcs_write_vpcs(struct dw_xpcs *xpcs, int reg, u16 val);
int nxp_sja1105_sgmii_pma_config(struct dw_xpcs *xpcs);
int nxp_sja1110_sgmii_pma_config(struct dw_xpcs *xpcs);
int nxp_sja1110_2500basex_pma_config(struct dw_xpcs *xpcs);
+int txgbe_xpcs_switch_mode(struct dw_xpcs *xpcs, phy_interface_t interface);
diff --git a/include/linux/pcs/pcs-xpcs.h b/include/linux/pcs/pcs-xpcs.h
index ff99cf7a5d0d..da3a6c30f6d2 100644
--- a/include/linux/pcs/pcs-xpcs.h
+++ b/include/linux/pcs/pcs-xpcs.h
@@ -20,12 +20,20 @@
#define DW_AN_C37_1000BASEX 4
#define DW_10GBASER 5
+/* device vendor OUI */
+#define DW_OUI_WX 0x0018fc80
+
+/* dev_flag */
+#define DW_DEV_TXGBE BIT(0)
+
struct xpcs_id;
struct dw_xpcs {
struct mdio_device *mdiodev;
const struct xpcs_id *id;
struct phylink_pcs pcs;
+ phy_interface_t interface;
+ int dev_flag;
};
int xpcs_get_an_mode(struct dw_xpcs *xpcs, phy_interface_t interface);
diff --git a/lib/checksum_kunit.c b/lib/checksum_kunit.c
index ace3c4799fe1..0eed92b77ba3 100644
--- a/lib/checksum_kunit.c
+++ b/lib/checksum_kunit.c
@@ -10,7 +10,8 @@
#define MAX_ALIGN 64
#define TEST_BUFLEN (MAX_LEN + MAX_ALIGN)
-static const __wsum random_init_sum = 0x2847aab;
+/* Values for a little endian CPU. Byte swap each half on big endian CPU. */
+static const u32 random_init_sum = 0x2847aab;
static const u8 random_buf[] = {
0xac, 0xd7, 0x76, 0x69, 0x6e, 0xf2, 0x93, 0x2c, 0x1f, 0xe0, 0xde, 0x86,
0x8f, 0x54, 0x33, 0x90, 0x95, 0xbf, 0xff, 0xb9, 0xea, 0x62, 0x6e, 0xb5,
@@ -56,7 +57,9 @@ static const u8 random_buf[] = {
0xe1, 0xdf, 0x4b, 0xe1, 0x81, 0xe2, 0x17, 0x02, 0x7b, 0x58, 0x8b, 0x92,
0x1a, 0xac, 0x46, 0xdd, 0x2e, 0xce, 0x40, 0x09
};
-static const __sum16 expected_results[] = {
+
+/* Values for a little endian CPU. Byte swap on big endian CPU. */
+static const u16 expected_results[] = {
0x82d0, 0x8224, 0xab23, 0xaaad, 0x41ad, 0x413f, 0x4f3e, 0x4eab, 0x22ab,
0x228c, 0x428b, 0x41ad, 0xbbac, 0xbb1d, 0x671d, 0x66ea, 0xd6e9, 0xd654,
0x1754, 0x1655, 0x5d54, 0x5c6a, 0xfa69, 0xf9fb, 0x44fb, 0x4428, 0xf527,
@@ -115,7 +118,9 @@ static const __sum16 expected_results[] = {
0x1d47, 0x3c46, 0x3bc5, 0x59c4, 0x59ad, 0x57ad, 0x5732, 0xff31, 0xfea6,
0x6ca6, 0x6c8c, 0xc08b, 0xc045, 0xe344, 0xe316, 0x1516, 0x14d6,
};
-static const __wsum init_sums_no_overflow[] = {
+
+/* Values for a little endian CPU. Byte swap each half on big endian CPU. */
+static const u32 init_sums_no_overflow[] = {
0xffffffff, 0xfffffffb, 0xfffffbfb, 0xfffffbf7, 0xfffff7f7, 0xfffff7f3,
0xfffff3f3, 0xfffff3ef, 0xffffefef, 0xffffefeb, 0xffffebeb, 0xffffebe7,
0xffffe7e7, 0xffffe7e3, 0xffffe3e3, 0xffffe3df, 0xffffdfdf, 0xffffdfdb,
@@ -208,7 +213,21 @@ static u8 tmp_buf[TEST_BUFLEN];
#define full_csum(buff, len, sum) csum_fold(csum_partial(buff, len, sum))
-#define CHECK_EQ(lhs, rhs) KUNIT_ASSERT_EQ(test, lhs, rhs)
+#define CHECK_EQ(lhs, rhs) KUNIT_ASSERT_EQ(test, (__force u64)lhs, (__force u64)rhs)
+
+static __sum16 to_sum16(u16 x)
+{
+ return (__force __sum16)le16_to_cpu((__force __le16)x);
+}
+
+/* This function swaps the bytes inside each half of a __wsum */
+static __wsum to_wsum(u32 x)
+{
+ u16 hi = le16_to_cpu((__force __le16)(x >> 16));
+ u16 lo = le16_to_cpu((__force __le16)x);
+
+ return (__force __wsum)((hi << 16) | lo);
+}
static void assert_setup_correct(struct kunit *test)
{
@@ -226,7 +245,8 @@ static void assert_setup_correct(struct kunit *test)
static void test_csum_fixed_random_inputs(struct kunit *test)
{
int len, align;
- __wsum result, expec, sum;
+ __wsum sum;
+ __sum16 result, expec;
assert_setup_correct(test);
for (align = 0; align < TEST_BUFLEN; ++align) {
@@ -237,9 +257,9 @@ static void test_csum_fixed_random_inputs(struct kunit *test)
/*
* Test the precomputed random input.
*/
- sum = random_init_sum;
+ sum = to_wsum(random_init_sum);
result = full_csum(&tmp_buf[align], len, sum);
- expec = expected_results[len];
+ expec = to_sum16(expected_results[len]);
CHECK_EQ(result, expec);
}
}
@@ -251,7 +271,8 @@ static void test_csum_fixed_random_inputs(struct kunit *test)
static void test_csum_all_carry_inputs(struct kunit *test)
{
int len, align;
- __wsum result, expec, sum;
+ __wsum sum;
+ __sum16 result, expec;
assert_setup_correct(test);
memset(tmp_buf, 0xff, TEST_BUFLEN);
@@ -261,9 +282,9 @@ static void test_csum_all_carry_inputs(struct kunit *test)
/*
* All carries from input and initial sum.
*/
- sum = 0xffffffff;
+ sum = to_wsum(0xffffffff);
result = full_csum(&tmp_buf[align], len, sum);
- expec = (len & 1) ? 0xff00 : 0;
+ expec = to_sum16((len & 1) ? 0xff00 : 0);
CHECK_EQ(result, expec);
/*
@@ -272,11 +293,11 @@ static void test_csum_all_carry_inputs(struct kunit *test)
sum = 0;
result = full_csum(&tmp_buf[align], len, sum);
if (len & 1)
- expec = 0xff00;
+ expec = to_sum16(0xff00);
else if (len)
expec = 0;
else
- expec = 0xffff;
+ expec = to_sum16(0xffff);
CHECK_EQ(result, expec);
}
}
@@ -290,7 +311,8 @@ static void test_csum_all_carry_inputs(struct kunit *test)
static void test_csum_no_carry_inputs(struct kunit *test)
{
int len, align;
- __wsum result, expec, sum;
+ __wsum sum;
+ __sum16 result, expec;
assert_setup_correct(test);
memset(tmp_buf, 0x4, TEST_BUFLEN);
@@ -300,7 +322,7 @@ static void test_csum_no_carry_inputs(struct kunit *test)
/*
* Expect no carries.
*/
- sum = init_sums_no_overflow[len];
+ sum = to_wsum(init_sums_no_overflow[len]);
result = full_csum(&tmp_buf[align], len, sum);
expec = 0;
CHECK_EQ(result, expec);
@@ -308,9 +330,9 @@ static void test_csum_no_carry_inputs(struct kunit *test)
/*
* Expect one carry.
*/
- sum = init_sums_no_overflow[len] + 1;
+ sum = to_wsum(init_sums_no_overflow[len] + 1);
result = full_csum(&tmp_buf[align], len, sum);
- expec = len ? 0xfffe : 0xffff;
+ expec = to_sum16(len ? 0xfffe : 0xffff);
CHECK_EQ(result, expec);
}
}
diff --git a/tools/net/ynl/generated/ethtool-user.h b/tools/net/ynl/generated/ethtool-user.h
index d7d4ba855f43..ddc1a5209992 100644
--- a/tools/net/ynl/generated/ethtool-user.h
+++ b/tools/net/ynl/generated/ethtool-user.h
@@ -1422,6 +1422,7 @@ ethtool_wol_set_req_set_sopass(struct ethtool_wol_set_req *req,
const void *sopass, size_t len)
{
free(req->sopass);
+ req->_present.sopass_len = len;
req->sopass = malloc(req->_present.sopass_len);
memcpy(req->sopass, sopass, req->_present.sopass_len);
}
@@ -4071,6 +4072,7 @@ ethtool_fec_set_req_set_stats_corrected(struct ethtool_fec_set_req *req,
const void *corrected, size_t len)
{
free(req->stats.corrected);
+ req->stats._present.corrected_len = len;
req->stats.corrected = malloc(req->stats._present.corrected_len);
memcpy(req->stats.corrected, corrected, req->stats._present.corrected_len);
}
@@ -4079,6 +4081,7 @@ ethtool_fec_set_req_set_stats_uncorr(struct ethtool_fec_set_req *req,
const void *uncorr, size_t len)
{
free(req->stats.uncorr);
+ req->stats._present.uncorr_len = len;
req->stats.uncorr = malloc(req->stats._present.uncorr_len);
memcpy(req->stats.uncorr, uncorr, req->stats._present.uncorr_len);
}
@@ -4087,6 +4090,7 @@ ethtool_fec_set_req_set_stats_corr_bits(struct ethtool_fec_set_req *req,
const void *corr_bits, size_t len)
{
free(req->stats.corr_bits);
+ req->stats._present.corr_bits_len = len;
req->stats.corr_bits = malloc(req->stats._present.corr_bits_len);
memcpy(req->stats.corr_bits, corr_bits, req->stats._present.corr_bits_len);
}
diff --git a/tools/net/ynl/generated/fou-user.h b/tools/net/ynl/generated/fou-user.h
index d8ab50579cd1..a8f860892540 100644
--- a/tools/net/ynl/generated/fou-user.h
+++ b/tools/net/ynl/generated/fou-user.h
@@ -91,6 +91,7 @@ fou_add_req_set_local_v6(struct fou_add_req *req, const void *local_v6,
size_t len)
{
free(req->local_v6);
+ req->_present.local_v6_len = len;
req->local_v6 = malloc(req->_present.local_v6_len);
memcpy(req->local_v6, local_v6, req->_present.local_v6_len);
}
@@ -99,6 +100,7 @@ fou_add_req_set_peer_v6(struct fou_add_req *req, const void *peer_v6,
size_t len)
{
free(req->peer_v6);
+ req->_present.peer_v6_len = len;
req->peer_v6 = malloc(req->_present.peer_v6_len);
memcpy(req->peer_v6, peer_v6, req->_present.peer_v6_len);
}
@@ -192,6 +194,7 @@ fou_del_req_set_local_v6(struct fou_del_req *req, const void *local_v6,
size_t len)
{
free(req->local_v6);
+ req->_present.local_v6_len = len;
req->local_v6 = malloc(req->_present.local_v6_len);
memcpy(req->local_v6, local_v6, req->_present.local_v6_len);
}
@@ -200,6 +203,7 @@ fou_del_req_set_peer_v6(struct fou_del_req *req, const void *peer_v6,
size_t len)
{
free(req->peer_v6);
+ req->_present.peer_v6_len = len;
req->peer_v6 = malloc(req->_present.peer_v6_len);
memcpy(req->peer_v6, peer_v6, req->_present.peer_v6_len);
}
@@ -280,6 +284,7 @@ fou_get_req_set_local_v6(struct fou_get_req *req, const void *local_v6,
size_t len)
{
free(req->local_v6);
+ req->_present.local_v6_len = len;
req->local_v6 = malloc(req->_present.local_v6_len);
memcpy(req->local_v6, local_v6, req->_present.local_v6_len);
}
@@ -288,6 +293,7 @@ fou_get_req_set_peer_v6(struct fou_get_req *req, const void *peer_v6,
size_t len)
{
free(req->peer_v6);
+ req->_present.peer_v6_len = len;
req->peer_v6 = malloc(req->_present.peer_v6_len);
memcpy(req->peer_v6, peer_v6, req->_present.peer_v6_len);
}
diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py
index 6951bcc7efdc..fa4f1c28efc5 100644
--- a/tools/net/ynl/lib/ynl.py
+++ b/tools/net/ynl/lib/ynl.py
@@ -410,7 +410,12 @@ class YnlFamily(SpecFamily):
elif attr["type"] == 'string':
attr_payload = str(value).encode('ascii') + b'\x00'
elif attr["type"] == 'binary':
- attr_payload = bytes.fromhex(value)
+ if isinstance(value, bytes):
+ attr_payload = value
+ elif isinstance(value, str):
+ attr_payload = bytes.fromhex(value)
+ else:
+ raise Exception(f'Unknown type for binary attribute, value: {value}')
elif attr['type'] in NlAttr.type_formats:
format = NlAttr.get_format(attr['type'], attr.byte_order)
attr_payload = format.pack(int(value))
diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py
index bdff8dfc29c9..9209bdcca9c6 100755
--- a/tools/net/ynl/ynl-gen-c.py
+++ b/tools/net/ynl/ynl-gen-c.py
@@ -428,6 +428,7 @@ class TypeBinary(Type):
def _setter_lines(self, ri, member, presence):
return [f"free({member});",
+ f"{presence}_len = len;",
f"{member} = malloc({presence}_len);",
f'memcpy({member}, {self.c_name}, {presence}_len);']
@@ -614,7 +615,7 @@ class Struct:
self.attr_list = []
self.attrs = dict()
- if type_list:
+ if type_list is not None:
for t in type_list:
self.attr_list.append((t, self.attr_set[t]),)
else:
@@ -977,7 +978,9 @@ class Family(SpecFamily):
for op_mode in ['do', 'dump']:
if op_mode in op:
- global_set.update(op[op_mode].get('request', []))
+ req = op[op_mode].get('request')
+ if req:
+ global_set.update(req.get('attributes', []))
self.global_policy = []
self.global_policy_set = attr_set_name
@@ -1540,7 +1543,14 @@ def parse_rsp_msg(ri, deref=False):
ri.cw.write_func_prot('int', f'{op_prefix(ri, "reply", deref=deref)}_parse', func_args)
- _multi_parse(ri, ri.struct["reply"], init_lines, local_vars)
+ if ri.struct["reply"].member_list():
+ _multi_parse(ri, ri.struct["reply"], init_lines, local_vars)
+ else:
+ # Empty reply
+ ri.cw.block_start()
+ ri.cw.p('return MNL_CB_OK;')
+ ri.cw.block_end()
+ ri.cw.nl()
def print_req(ri):