diff options
Diffstat (limited to 'drivers/net/ethernet')
190 files changed, 17023 insertions, 7227 deletions
diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig index 1917da784191..323ec56e8a74 100644 --- a/drivers/net/ethernet/Kconfig +++ b/drivers/net/ethernet/Kconfig @@ -132,16 +132,6 @@ source "drivers/net/ethernet/mscc/Kconfig" source "drivers/net/ethernet/microsoft/Kconfig" source "drivers/net/ethernet/moxa/Kconfig" source "drivers/net/ethernet/myricom/Kconfig" - -config FEALNX - tristate "Myson MTD-8xx PCI Ethernet support" - depends on PCI - select CRC32 - select MII - help - Say Y here to support the Myson MTD-800 family of PCI-based Ethernet - cards. <http://www.myson.com.tw/> - source "drivers/net/ethernet/ni/Kconfig" source "drivers/net/ethernet/natsemi/Kconfig" source "drivers/net/ethernet/neterion/Kconfig" diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile index 0d872d4efcd1..2fedbaa545eb 100644 --- a/drivers/net/ethernet/Makefile +++ b/drivers/net/ethernet/Makefile @@ -64,7 +64,6 @@ obj-$(CONFIG_NET_VENDOR_MICROCHIP) += microchip/ obj-$(CONFIG_NET_VENDOR_MICROSEMI) += mscc/ obj-$(CONFIG_NET_VENDOR_MOXART) += moxa/ obj-$(CONFIG_NET_VENDOR_MYRI) += myricom/ -obj-$(CONFIG_FEALNX) += fealnx.o obj-$(CONFIG_NET_VENDOR_NATSEMI) += natsemi/ obj-$(CONFIG_NET_VENDOR_NETERION) += neterion/ obj-$(CONFIG_NET_VENDOR_NETRONOME) += netronome/ diff --git a/drivers/net/ethernet/adi/adin1110.c b/drivers/net/ethernet/adi/adin1110.c index aaee7c4248e6..1c0015b55993 100644 --- a/drivers/net/ethernet/adi/adin1110.c +++ b/drivers/net/ethernet/adi/adin1110.c @@ -196,7 +196,7 @@ static int adin1110_read_reg(struct adin1110_priv *priv, u16 reg, u32 *val) { u32 header_len = ADIN1110_RD_HEADER_LEN; u32 read_len = ADIN1110_REG_LEN; - struct spi_transfer t[2] = {0}; + struct spi_transfer t = {0}; int ret; priv->data[0] = ADIN1110_CD | FIELD_GET(GENMASK(12, 8), reg); @@ -209,17 +209,15 @@ static int adin1110_read_reg(struct adin1110_priv *priv, u16 reg, u32 *val) header_len++; } - t[0].tx_buf = &priv->data[0]; - t[0].len = header_len; - if (priv->append_crc) read_len++; memset(&priv->data[header_len], 0, read_len); - t[1].rx_buf = &priv->data[header_len]; - t[1].len = read_len; + t.tx_buf = &priv->data[0]; + t.rx_buf = &priv->data[0]; + t.len = read_len + header_len; - ret = spi_sync_transfer(priv->spidev, t, 2); + ret = spi_sync_transfer(priv->spidev, &t, 1); if (ret) return ret; @@ -296,7 +294,7 @@ static int adin1110_read_fifo(struct adin1110_port_priv *port_priv) { struct adin1110_priv *priv = port_priv->priv; u32 header_len = ADIN1110_RD_HEADER_LEN; - struct spi_transfer t[2] = {0}; + struct spi_transfer t; u32 frame_size_no_fcs; struct sk_buff *rxb; u32 frame_size; @@ -327,12 +325,7 @@ static int adin1110_read_fifo(struct adin1110_port_priv *port_priv) return ret; frame_size_no_fcs = frame_size - ADIN1110_FRAME_HEADER_LEN - ADIN1110_FEC_LEN; - - rxb = netdev_alloc_skb(port_priv->netdev, round_len); - if (!rxb) - return -ENOMEM; - - memset(priv->data, 0, round_len + ADIN1110_RD_HEADER_LEN); + memset(priv->data, 0, ADIN1110_RD_HEADER_LEN); priv->data[0] = ADIN1110_CD | FIELD_GET(GENMASK(12, 8), reg); priv->data[1] = FIELD_GET(GENMASK(7, 0), reg); @@ -342,21 +335,23 @@ static int adin1110_read_fifo(struct adin1110_port_priv *port_priv) header_len++; } - skb_put(rxb, frame_size_no_fcs + ADIN1110_FRAME_HEADER_LEN); + rxb = netdev_alloc_skb(port_priv->netdev, round_len + header_len); + if (!rxb) + return -ENOMEM; - t[0].tx_buf = &priv->data[0]; - t[0].len = header_len; + skb_put(rxb, frame_size_no_fcs + header_len + ADIN1110_FRAME_HEADER_LEN); - t[1].rx_buf = &rxb->data[0]; - t[1].len = round_len; + t.tx_buf = &priv->data[0]; + t.rx_buf = &rxb->data[0]; + t.len = header_len + round_len; - ret = spi_sync_transfer(priv->spidev, t, 2); + ret = spi_sync_transfer(priv->spidev, &t, 1); if (ret) { kfree_skb(rxb); return ret; } - skb_pull(rxb, ADIN1110_FRAME_HEADER_LEN); + skb_pull(rxb, header_len + ADIN1110_FRAME_HEADER_LEN); rxb->protocol = eth_type_trans(rxb, port_priv->netdev); if ((port_priv->flags & IFF_ALLMULTI && rxb->pkt_type == PACKET_MULTICAST) || @@ -1087,9 +1082,30 @@ static void adin1110_adjust_link(struct net_device *dev) */ static int adin1110_check_spi(struct adin1110_priv *priv) { + struct gpio_desc *reset_gpio; int ret; u32 val; + reset_gpio = devm_gpiod_get_optional(&priv->spidev->dev, "reset", + GPIOD_OUT_LOW); + if (reset_gpio) { + /* MISO pin is used for internal configuration, can't have + * anyone else disturbing the SDO line. + */ + spi_bus_lock(priv->spidev->controller); + + gpiod_set_value(reset_gpio, 1); + fsleep(10000); + gpiod_set_value(reset_gpio, 0); + + /* Need to wait 90 ms before interacting with + * the MAC after a HW reset. + */ + fsleep(90000); + + spi_bus_unlock(priv->spidev->controller); + } + ret = adin1110_read_reg(priv, ADIN1110_PHY_ID, &val); if (ret < 0) return ret; @@ -1169,6 +1185,11 @@ static int adin1110_port_bridge_leave(struct adin1110_port_priv *port_priv, return ret; } +static bool adin1110_port_dev_check(const struct net_device *dev) +{ + return dev->netdev_ops == &adin1110_netdev_ops; +} + static int adin1110_netdevice_event(struct notifier_block *unused, unsigned long event, void *ptr) { @@ -1177,6 +1198,9 @@ static int adin1110_netdevice_event(struct notifier_block *unused, struct netdev_notifier_changeupper_info *info = ptr; int ret = 0; + if (!adin1110_port_dev_check(dev)) + return NOTIFY_DONE; + switch (event) { case NETDEV_CHANGEUPPER: if (netif_is_bridge_master(info->upper_dev)) { @@ -1202,11 +1226,6 @@ static void adin1110_disconnect_phy(void *data) phy_disconnect(data); } -static bool adin1110_port_dev_check(const struct net_device *dev) -{ - return dev->netdev_ops == &adin1110_netdev_ops; -} - static int adin1110_port_set_forwarding_state(struct adin1110_port_priv *port_priv) { struct adin1110_priv *priv = port_priv->priv; diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-pci.c b/drivers/net/ethernet/amd/xgbe/xgbe-pci.c index 2af3da4b2d05..f409d7bd1f1e 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-pci.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-pci.c @@ -285,6 +285,9 @@ static int xgbe_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* Yellow Carp devices do not need cdr workaround */ pdata->vdata->an_cdr_workaround = 0; + + /* Yellow Carp devices do not need rrc */ + pdata->vdata->enable_rrc = 0; } else { pdata->xpcs_window_def_reg = PCS_V2_WINDOW_DEF; pdata->xpcs_window_sel_reg = PCS_V2_WINDOW_SELECT; @@ -483,6 +486,7 @@ static struct xgbe_version_data xgbe_v2a = { .tx_desc_prefetch = 5, .rx_desc_prefetch = 5, .an_cdr_workaround = 1, + .enable_rrc = 1, }; static struct xgbe_version_data xgbe_v2b = { @@ -498,6 +502,7 @@ static struct xgbe_version_data xgbe_v2b = { .tx_desc_prefetch = 5, .rx_desc_prefetch = 5, .an_cdr_workaround = 1, + .enable_rrc = 1, }; static const struct pci_device_id xgbe_pci_table[] = { diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c index 2156600641b6..4064c3e3dd49 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c @@ -239,6 +239,7 @@ enum xgbe_sfp_speed { #define XGBE_SFP_BASE_BR_1GBE_MAX 0x0d #define XGBE_SFP_BASE_BR_10GBE_MIN 0x64 #define XGBE_SFP_BASE_BR_10GBE_MAX 0x68 +#define XGBE_MOLEX_SFP_BASE_BR_10GBE_MAX 0x78 #define XGBE_SFP_BASE_CU_CABLE_LEN 18 @@ -284,6 +285,8 @@ struct xgbe_sfp_eeprom { #define XGBE_BEL_FUSE_VENDOR "BEL-FUSE " #define XGBE_BEL_FUSE_PARTNO "1GBT-SFP06 " +#define XGBE_MOLEX_VENDOR "Molex Inc. " + struct xgbe_sfp_ascii { union { char vendor[XGBE_SFP_BASE_VENDOR_NAME_LEN + 1]; @@ -834,7 +837,11 @@ static bool xgbe_phy_sfp_bit_rate(struct xgbe_sfp_eeprom *sfp_eeprom, break; case XGBE_SFP_SPEED_10000: min = XGBE_SFP_BASE_BR_10GBE_MIN; - max = XGBE_SFP_BASE_BR_10GBE_MAX; + if (memcmp(&sfp_eeprom->base[XGBE_SFP_BASE_VENDOR_NAME], + XGBE_MOLEX_VENDOR, XGBE_SFP_BASE_VENDOR_NAME_LEN) == 0) + max = XGBE_MOLEX_SFP_BASE_BR_10GBE_MAX; + else + max = XGBE_SFP_BASE_BR_10GBE_MAX; break; default: return false; @@ -1151,7 +1158,10 @@ static void xgbe_phy_sfp_parse_eeprom(struct xgbe_prv_data *pdata) } /* Determine the type of SFP */ - if (sfp_base[XGBE_SFP_BASE_10GBE_CC] & XGBE_SFP_BASE_10GBE_CC_SR) + if (phy_data->sfp_cable == XGBE_SFP_CABLE_PASSIVE && + xgbe_phy_sfp_bit_rate(sfp_eeprom, XGBE_SFP_SPEED_10000)) + phy_data->sfp_base = XGBE_SFP_BASE_10000_CR; + else if (sfp_base[XGBE_SFP_BASE_10GBE_CC] & XGBE_SFP_BASE_10GBE_CC_SR) phy_data->sfp_base = XGBE_SFP_BASE_10000_SR; else if (sfp_base[XGBE_SFP_BASE_10GBE_CC] & XGBE_SFP_BASE_10GBE_CC_LR) phy_data->sfp_base = XGBE_SFP_BASE_10000_LR; @@ -1167,9 +1177,6 @@ static void xgbe_phy_sfp_parse_eeprom(struct xgbe_prv_data *pdata) phy_data->sfp_base = XGBE_SFP_BASE_1000_CX; else if (sfp_base[XGBE_SFP_BASE_1GBE_CC] & XGBE_SFP_BASE_1GBE_CC_T) phy_data->sfp_base = XGBE_SFP_BASE_1000_T; - else if ((phy_data->sfp_cable == XGBE_SFP_CABLE_PASSIVE) && - xgbe_phy_sfp_bit_rate(sfp_eeprom, XGBE_SFP_SPEED_10000)) - phy_data->sfp_base = XGBE_SFP_BASE_10000_CR; switch (phy_data->sfp_base) { case XGBE_SFP_BASE_1000_T: @@ -1979,6 +1986,10 @@ static void xgbe_phy_rx_reset(struct xgbe_prv_data *pdata) static void xgbe_phy_pll_ctrl(struct xgbe_prv_data *pdata, bool enable) { + /* PLL_CTRL feature needs to be enabled for fixed PHY modes (Non-Autoneg) only */ + if (pdata->phy.autoneg != AUTONEG_DISABLE) + return; + XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_VEND2_PMA_MISC_CTRL0, XGBE_PMA_PLL_CTRL_MASK, enable ? XGBE_PMA_PLL_CTRL_ENABLE @@ -1989,7 +2000,7 @@ static void xgbe_phy_pll_ctrl(struct xgbe_prv_data *pdata, bool enable) } static void xgbe_phy_perform_ratechange(struct xgbe_prv_data *pdata, - unsigned int cmd, unsigned int sub_cmd) + enum xgbe_mb_cmd cmd, enum xgbe_mb_subcmd sub_cmd) { unsigned int s0 = 0; unsigned int wait; @@ -2029,14 +2040,16 @@ static void xgbe_phy_perform_ratechange(struct xgbe_prv_data *pdata, xgbe_phy_rx_reset(pdata); reenable_pll: - /* Enable PLL re-initialization */ - xgbe_phy_pll_ctrl(pdata, true); + /* Enable PLL re-initialization, not needed for PHY Power Off and RRC cmds */ + if (cmd != XGBE_MB_CMD_POWER_OFF && + cmd != XGBE_MB_CMD_RRC) + xgbe_phy_pll_ctrl(pdata, true); } static void xgbe_phy_rrc(struct xgbe_prv_data *pdata) { /* Receiver Reset Cycle */ - xgbe_phy_perform_ratechange(pdata, 5, 0); + xgbe_phy_perform_ratechange(pdata, XGBE_MB_CMD_RRC, XGBE_MB_SUBCMD_NONE); netif_dbg(pdata, link, pdata->netdev, "receiver reset complete\n"); } @@ -2046,7 +2059,7 @@ static void xgbe_phy_power_off(struct xgbe_prv_data *pdata) struct xgbe_phy_data *phy_data = pdata->phy_data; /* Power off */ - xgbe_phy_perform_ratechange(pdata, 0, 0); + xgbe_phy_perform_ratechange(pdata, XGBE_MB_CMD_POWER_OFF, XGBE_MB_SUBCMD_NONE); phy_data->cur_mode = XGBE_MODE_UNKNOWN; @@ -2061,14 +2074,17 @@ static void xgbe_phy_sfi_mode(struct xgbe_prv_data *pdata) /* 10G/SFI */ if (phy_data->sfp_cable != XGBE_SFP_CABLE_PASSIVE) { - xgbe_phy_perform_ratechange(pdata, 3, 0); + xgbe_phy_perform_ratechange(pdata, XGBE_MB_CMD_SET_10G_SFI, XGBE_MB_SUBCMD_ACTIVE); } else { if (phy_data->sfp_cable_len <= 1) - xgbe_phy_perform_ratechange(pdata, 3, 1); + xgbe_phy_perform_ratechange(pdata, XGBE_MB_CMD_SET_10G_SFI, + XGBE_MB_SUBCMD_PASSIVE_1M); else if (phy_data->sfp_cable_len <= 3) - xgbe_phy_perform_ratechange(pdata, 3, 2); + xgbe_phy_perform_ratechange(pdata, XGBE_MB_CMD_SET_10G_SFI, + XGBE_MB_SUBCMD_PASSIVE_3M); else - xgbe_phy_perform_ratechange(pdata, 3, 3); + xgbe_phy_perform_ratechange(pdata, XGBE_MB_CMD_SET_10G_SFI, + XGBE_MB_SUBCMD_PASSIVE_OTHER); } phy_data->cur_mode = XGBE_MODE_SFI; @@ -2083,7 +2099,7 @@ static void xgbe_phy_x_mode(struct xgbe_prv_data *pdata) xgbe_phy_set_redrv_mode(pdata); /* 1G/X */ - xgbe_phy_perform_ratechange(pdata, 1, 3); + xgbe_phy_perform_ratechange(pdata, XGBE_MB_CMD_SET_1G, XGBE_MB_SUBCMD_1G_KX); phy_data->cur_mode = XGBE_MODE_X; @@ -2097,7 +2113,7 @@ static void xgbe_phy_sgmii_1000_mode(struct xgbe_prv_data *pdata) xgbe_phy_set_redrv_mode(pdata); /* 1G/SGMII */ - xgbe_phy_perform_ratechange(pdata, 1, 2); + xgbe_phy_perform_ratechange(pdata, XGBE_MB_CMD_SET_1G, XGBE_MB_SUBCMD_1G_SGMII); phy_data->cur_mode = XGBE_MODE_SGMII_1000; @@ -2111,7 +2127,7 @@ static void xgbe_phy_sgmii_100_mode(struct xgbe_prv_data *pdata) xgbe_phy_set_redrv_mode(pdata); /* 100M/SGMII */ - xgbe_phy_perform_ratechange(pdata, 1, 1); + xgbe_phy_perform_ratechange(pdata, XGBE_MB_CMD_SET_1G, XGBE_MB_SUBCMD_100MBITS); phy_data->cur_mode = XGBE_MODE_SGMII_100; @@ -2125,7 +2141,7 @@ static void xgbe_phy_kr_mode(struct xgbe_prv_data *pdata) xgbe_phy_set_redrv_mode(pdata); /* 10G/KR */ - xgbe_phy_perform_ratechange(pdata, 4, 0); + xgbe_phy_perform_ratechange(pdata, XGBE_MB_CMD_SET_10G_KR, XGBE_MB_SUBCMD_NONE); phy_data->cur_mode = XGBE_MODE_KR; @@ -2139,7 +2155,7 @@ static void xgbe_phy_kx_2500_mode(struct xgbe_prv_data *pdata) xgbe_phy_set_redrv_mode(pdata); /* 2.5G/KX */ - xgbe_phy_perform_ratechange(pdata, 2, 0); + xgbe_phy_perform_ratechange(pdata, XGBE_MB_CMD_SET_2_5G, XGBE_MB_SUBCMD_NONE); phy_data->cur_mode = XGBE_MODE_KX_2500; @@ -2153,7 +2169,7 @@ static void xgbe_phy_kx_1000_mode(struct xgbe_prv_data *pdata) xgbe_phy_set_redrv_mode(pdata); /* 1G/KX */ - xgbe_phy_perform_ratechange(pdata, 1, 3); + xgbe_phy_perform_ratechange(pdata, XGBE_MB_CMD_SET_1G, XGBE_MB_SUBCMD_1G_KX); phy_data->cur_mode = XGBE_MODE_KX_1000; @@ -2640,7 +2656,7 @@ static int xgbe_phy_link_status(struct xgbe_prv_data *pdata, int *an_restart) } /* No link, attempt a receiver reset cycle */ - if (phy_data->rrc_count++ > XGBE_RRC_FREQUENCY) { + if (pdata->vdata->enable_rrc && phy_data->rrc_count++ > XGBE_RRC_FREQUENCY) { phy_data->rrc_count = 0; xgbe_phy_rrc(pdata); } diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h index b875c430222e..71f24cb47935 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -611,6 +611,31 @@ enum xgbe_mdio_mode { XGBE_MDIO_MODE_CL45, }; +enum xgbe_mb_cmd { + XGBE_MB_CMD_POWER_OFF = 0, + XGBE_MB_CMD_SET_1G, + XGBE_MB_CMD_SET_2_5G, + XGBE_MB_CMD_SET_10G_SFI, + XGBE_MB_CMD_SET_10G_KR, + XGBE_MB_CMD_RRC +}; + +enum xgbe_mb_subcmd { + XGBE_MB_SUBCMD_NONE = 0, + + /* 10GbE SFP subcommands */ + XGBE_MB_SUBCMD_ACTIVE = 0, + XGBE_MB_SUBCMD_PASSIVE_1M, + XGBE_MB_SUBCMD_PASSIVE_3M, + XGBE_MB_SUBCMD_PASSIVE_OTHER, + + /* 1GbE Mode subcommands */ + XGBE_MB_SUBCMD_10MBITS = 0, + XGBE_MB_SUBCMD_100MBITS, + XGBE_MB_SUBCMD_1G_SGMII, + XGBE_MB_SUBCMD_1G_KX +}; + struct xgbe_phy { struct ethtool_link_ksettings lks; @@ -1013,6 +1038,7 @@ struct xgbe_version_data { unsigned int tx_desc_prefetch; unsigned int rx_desc_prefetch; unsigned int an_cdr_workaround; + unsigned int enable_rrc; }; struct xgbe_prv_data { diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_macsec.c b/drivers/net/ethernet/aquantia/atlantic/aq_macsec.c index 3d0e16791e1c..a0180811305d 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_macsec.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_macsec.c @@ -1394,26 +1394,57 @@ static void aq_check_txsa_expiration(struct aq_nic_s *nic) egress_sa_threshold_expired); } +#define AQ_LOCKED_MDO_DEF(mdo) \ +static int aq_locked_mdo_##mdo(struct macsec_context *ctx) \ +{ \ + struct aq_nic_s *nic = netdev_priv(ctx->netdev); \ + int ret; \ + mutex_lock(&nic->macsec_mutex); \ + ret = aq_mdo_##mdo(ctx); \ + mutex_unlock(&nic->macsec_mutex); \ + return ret; \ +} + +AQ_LOCKED_MDO_DEF(dev_open) +AQ_LOCKED_MDO_DEF(dev_stop) +AQ_LOCKED_MDO_DEF(add_secy) +AQ_LOCKED_MDO_DEF(upd_secy) +AQ_LOCKED_MDO_DEF(del_secy) +AQ_LOCKED_MDO_DEF(add_rxsc) +AQ_LOCKED_MDO_DEF(upd_rxsc) +AQ_LOCKED_MDO_DEF(del_rxsc) +AQ_LOCKED_MDO_DEF(add_rxsa) +AQ_LOCKED_MDO_DEF(upd_rxsa) +AQ_LOCKED_MDO_DEF(del_rxsa) +AQ_LOCKED_MDO_DEF(add_txsa) +AQ_LOCKED_MDO_DEF(upd_txsa) +AQ_LOCKED_MDO_DEF(del_txsa) +AQ_LOCKED_MDO_DEF(get_dev_stats) +AQ_LOCKED_MDO_DEF(get_tx_sc_stats) +AQ_LOCKED_MDO_DEF(get_tx_sa_stats) +AQ_LOCKED_MDO_DEF(get_rx_sc_stats) +AQ_LOCKED_MDO_DEF(get_rx_sa_stats) + const struct macsec_ops aq_macsec_ops = { - .mdo_dev_open = aq_mdo_dev_open, - .mdo_dev_stop = aq_mdo_dev_stop, - .mdo_add_secy = aq_mdo_add_secy, - .mdo_upd_secy = aq_mdo_upd_secy, - .mdo_del_secy = aq_mdo_del_secy, - .mdo_add_rxsc = aq_mdo_add_rxsc, - .mdo_upd_rxsc = aq_mdo_upd_rxsc, - .mdo_del_rxsc = aq_mdo_del_rxsc, - .mdo_add_rxsa = aq_mdo_add_rxsa, - .mdo_upd_rxsa = aq_mdo_upd_rxsa, - .mdo_del_rxsa = aq_mdo_del_rxsa, - .mdo_add_txsa = aq_mdo_add_txsa, - .mdo_upd_txsa = aq_mdo_upd_txsa, - .mdo_del_txsa = aq_mdo_del_txsa, - .mdo_get_dev_stats = aq_mdo_get_dev_stats, - .mdo_get_tx_sc_stats = aq_mdo_get_tx_sc_stats, - .mdo_get_tx_sa_stats = aq_mdo_get_tx_sa_stats, - .mdo_get_rx_sc_stats = aq_mdo_get_rx_sc_stats, - .mdo_get_rx_sa_stats = aq_mdo_get_rx_sa_stats, + .mdo_dev_open = aq_locked_mdo_dev_open, + .mdo_dev_stop = aq_locked_mdo_dev_stop, + .mdo_add_secy = aq_locked_mdo_add_secy, + .mdo_upd_secy = aq_locked_mdo_upd_secy, + .mdo_del_secy = aq_locked_mdo_del_secy, + .mdo_add_rxsc = aq_locked_mdo_add_rxsc, + .mdo_upd_rxsc = aq_locked_mdo_upd_rxsc, + .mdo_del_rxsc = aq_locked_mdo_del_rxsc, + .mdo_add_rxsa = aq_locked_mdo_add_rxsa, + .mdo_upd_rxsa = aq_locked_mdo_upd_rxsa, + .mdo_del_rxsa = aq_locked_mdo_del_rxsa, + .mdo_add_txsa = aq_locked_mdo_add_txsa, + .mdo_upd_txsa = aq_locked_mdo_upd_txsa, + .mdo_del_txsa = aq_locked_mdo_del_txsa, + .mdo_get_dev_stats = aq_locked_mdo_get_dev_stats, + .mdo_get_tx_sc_stats = aq_locked_mdo_get_tx_sc_stats, + .mdo_get_tx_sa_stats = aq_locked_mdo_get_tx_sa_stats, + .mdo_get_rx_sc_stats = aq_locked_mdo_get_rx_sc_stats, + .mdo_get_rx_sa_stats = aq_locked_mdo_get_rx_sa_stats, }; int aq_macsec_init(struct aq_nic_s *nic) @@ -1435,6 +1466,7 @@ int aq_macsec_init(struct aq_nic_s *nic) nic->ndev->features |= NETIF_F_HW_MACSEC; nic->ndev->macsec_ops = &aq_macsec_ops; + mutex_init(&nic->macsec_mutex); return 0; } @@ -1458,7 +1490,7 @@ int aq_macsec_enable(struct aq_nic_s *nic) if (!nic->macsec_cfg) return 0; - rtnl_lock(); + mutex_lock(&nic->macsec_mutex); if (nic->aq_fw_ops->send_macsec_req) { struct macsec_cfg_request cfg = { 0 }; @@ -1507,7 +1539,7 @@ int aq_macsec_enable(struct aq_nic_s *nic) ret = aq_apply_macsec_cfg(nic); unlock: - rtnl_unlock(); + mutex_unlock(&nic->macsec_mutex); return ret; } @@ -1519,9 +1551,9 @@ void aq_macsec_work(struct aq_nic_s *nic) if (!netif_carrier_ok(nic->ndev)) return; - rtnl_lock(); + mutex_lock(&nic->macsec_mutex); aq_check_txsa_expiration(nic); - rtnl_unlock(); + mutex_unlock(&nic->macsec_mutex); } int aq_macsec_rx_sa_cnt(struct aq_nic_s *nic) @@ -1532,21 +1564,30 @@ int aq_macsec_rx_sa_cnt(struct aq_nic_s *nic) if (!cfg) return 0; + mutex_lock(&nic->macsec_mutex); + for (i = 0; i < AQ_MACSEC_MAX_SC; i++) { if (!test_bit(i, &cfg->rxsc_idx_busy)) continue; cnt += hweight_long(cfg->aq_rxsc[i].rx_sa_idx_busy); } + mutex_unlock(&nic->macsec_mutex); return cnt; } int aq_macsec_tx_sc_cnt(struct aq_nic_s *nic) { + int cnt; + if (!nic->macsec_cfg) return 0; - return hweight_long(nic->macsec_cfg->txsc_idx_busy); + mutex_lock(&nic->macsec_mutex); + cnt = hweight_long(nic->macsec_cfg->txsc_idx_busy); + mutex_unlock(&nic->macsec_mutex); + + return cnt; } int aq_macsec_tx_sa_cnt(struct aq_nic_s *nic) @@ -1557,12 +1598,15 @@ int aq_macsec_tx_sa_cnt(struct aq_nic_s *nic) if (!cfg) return 0; + mutex_lock(&nic->macsec_mutex); + for (i = 0; i < AQ_MACSEC_MAX_SC; i++) { if (!test_bit(i, &cfg->txsc_idx_busy)) continue; cnt += hweight_long(cfg->aq_txsc[i].tx_sa_idx_busy); } + mutex_unlock(&nic->macsec_mutex); return cnt; } @@ -1634,6 +1678,8 @@ u64 *aq_macsec_get_stats(struct aq_nic_s *nic, u64 *data) if (!cfg) return data; + mutex_lock(&nic->macsec_mutex); + aq_macsec_update_stats(nic); common_stats = &cfg->stats; @@ -1716,5 +1762,7 @@ u64 *aq_macsec_get_stats(struct aq_nic_s *nic, u64 *data) data += i; + mutex_unlock(&nic->macsec_mutex); + return data; } diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h index 935ba889bd9a..ad33f8586532 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h @@ -157,6 +157,8 @@ struct aq_nic_s { struct mutex fwreq_mutex; #if IS_ENABLED(CONFIG_MACSEC) struct aq_macsec_cfg *macsec_cfg; + /* mutex to protect data in macsec_cfg */ + struct mutex macsec_mutex; #endif /* PTP support */ struct aq_ptp_s *aq_ptp; diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig index 56e0fb07aec7..f4e1ca68d831 100644 --- a/drivers/net/ethernet/broadcom/Kconfig +++ b/drivers/net/ethernet/broadcom/Kconfig @@ -53,8 +53,8 @@ config B44_PCI config BCM4908_ENET tristate "Broadcom BCM4908 internal mac support" - depends on ARCH_BCM4908 || COMPILE_TEST - default y if ARCH_BCM4908 + depends on ARCH_BCMBCA || COMPILE_TEST + default y if ARCH_BCMBCA help This driver supports Ethernet controller integrated into Broadcom BCM4908 family SoCs. diff --git a/drivers/net/ethernet/broadcom/Makefile b/drivers/net/ethernet/broadcom/Makefile index 2e6c5f258a1f..0ddfb5b5d53c 100644 --- a/drivers/net/ethernet/broadcom/Makefile +++ b/drivers/net/ethernet/broadcom/Makefile @@ -17,8 +17,3 @@ obj-$(CONFIG_BGMAC_BCMA) += bgmac-bcma.o bgmac-bcma-mdio.o obj-$(CONFIG_BGMAC_PLATFORM) += bgmac-platform.o obj-$(CONFIG_SYSTEMPORT) += bcmsysport.o obj-$(CONFIG_BNXT) += bnxt/ - -# FIXME: temporarily silence -Warray-bounds on non W=1+ builds -ifndef KBUILD_EXTRA_WARN -CFLAGS_tg3.o += -Wno-array-bounds -endif diff --git a/drivers/net/ethernet/broadcom/bcm4908_enet.c b/drivers/net/ethernet/broadcom/bcm4908_enet.c index 93ccf549e2ed..b0aac0bcb060 100644 --- a/drivers/net/ethernet/broadcom/bcm4908_enet.c +++ b/drivers/net/ethernet/broadcom/bcm4908_enet.c @@ -36,13 +36,24 @@ #define ENET_MAX_ETH_OVERHEAD (ETH_HLEN + BRCM_MAX_TAG_LEN + VLAN_HLEN + \ ETH_FCS_LEN + 4) /* 32 */ +#define ENET_RX_SKB_BUF_SIZE (NET_SKB_PAD + NET_IP_ALIGN + \ + ETH_HLEN + BRCM_MAX_TAG_LEN + VLAN_HLEN + \ + ENET_MTU_MAX + ETH_FCS_LEN + 4) +#define ENET_RX_SKB_BUF_ALLOC_SIZE (SKB_DATA_ALIGN(ENET_RX_SKB_BUF_SIZE) + \ + SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) +#define ENET_RX_BUF_DMA_OFFSET (NET_SKB_PAD + NET_IP_ALIGN) +#define ENET_RX_BUF_DMA_SIZE (ENET_RX_SKB_BUF_SIZE - ENET_RX_BUF_DMA_OFFSET) + struct bcm4908_enet_dma_ring_bd { __le32 ctl; __le32 addr; } __packed; struct bcm4908_enet_dma_ring_slot { - struct sk_buff *skb; + union { + void *buf; /* RX */ + struct sk_buff *skb; /* TX */ + }; unsigned int len; dma_addr_t dma_addr; }; @@ -260,22 +271,21 @@ static int bcm4908_enet_dma_alloc_rx_buf(struct bcm4908_enet *enet, unsigned int u32 tmp; int err; - slot->len = ENET_MTU_MAX + ENET_MAX_ETH_OVERHEAD; - - slot->skb = netdev_alloc_skb(enet->netdev, slot->len); - if (!slot->skb) + slot->buf = napi_alloc_frag(ENET_RX_SKB_BUF_ALLOC_SIZE); + if (!slot->buf) return -ENOMEM; - slot->dma_addr = dma_map_single(dev, slot->skb->data, slot->len, DMA_FROM_DEVICE); + slot->dma_addr = dma_map_single(dev, slot->buf + ENET_RX_BUF_DMA_OFFSET, + ENET_RX_BUF_DMA_SIZE, DMA_FROM_DEVICE); err = dma_mapping_error(dev, slot->dma_addr); if (err) { dev_err(dev, "Failed to map DMA buffer: %d\n", err); - kfree_skb(slot->skb); - slot->skb = NULL; + skb_free_frag(slot->buf); + slot->buf = NULL; return err; } - tmp = slot->len << DMA_CTL_LEN_DESC_BUFLENGTH_SHIFT; + tmp = ENET_RX_BUF_DMA_SIZE << DMA_CTL_LEN_DESC_BUFLENGTH_SHIFT; tmp |= DMA_CTL_STATUS_OWN; if (idx == enet->rx_ring.length - 1) tmp |= DMA_CTL_STATUS_WRAP; @@ -315,11 +325,11 @@ static void bcm4908_enet_dma_uninit(struct bcm4908_enet *enet) for (i = rx_ring->length - 1; i >= 0; i--) { slot = &rx_ring->slots[i]; - if (!slot->skb) + if (!slot->buf) continue; dma_unmap_single(dev, slot->dma_addr, slot->len, DMA_FROM_DEVICE); - kfree_skb(slot->skb); - slot->skb = NULL; + skb_free_frag(slot->buf); + slot->buf = NULL; } } @@ -561,8 +571,6 @@ static netdev_tx_t bcm4908_enet_start_xmit(struct sk_buff *skb, struct net_devic if (++ring->write_idx == ring->length - 1) ring->write_idx = 0; - enet->netdev->stats.tx_bytes += skb->len; - enet->netdev->stats.tx_packets++; return NETDEV_TX_OK; } @@ -577,6 +585,7 @@ static int bcm4908_enet_poll_rx(struct napi_struct *napi, int weight) while (handled < weight) { struct bcm4908_enet_dma_ring_bd *buf_desc; struct bcm4908_enet_dma_ring_slot slot; + struct sk_buff *skb; u32 ctl; int len; int err; @@ -600,16 +609,24 @@ static int bcm4908_enet_poll_rx(struct napi_struct *napi, int weight) if (len < ETH_ZLEN || (ctl & (DMA_CTL_STATUS_SOP | DMA_CTL_STATUS_EOP)) != (DMA_CTL_STATUS_SOP | DMA_CTL_STATUS_EOP)) { - kfree_skb(slot.skb); + skb_free_frag(slot.buf); enet->netdev->stats.rx_dropped++; break; } - dma_unmap_single(dev, slot.dma_addr, slot.len, DMA_FROM_DEVICE); + dma_unmap_single(dev, slot.dma_addr, ENET_RX_BUF_DMA_SIZE, DMA_FROM_DEVICE); + + skb = build_skb(slot.buf, ENET_RX_SKB_BUF_ALLOC_SIZE); + if (unlikely(!skb)) { + skb_free_frag(slot.buf); + enet->netdev->stats.rx_dropped++; + break; + } + skb_reserve(skb, ENET_RX_BUF_DMA_OFFSET); + skb_put(skb, len - ETH_FCS_LEN); + skb->protocol = eth_type_trans(skb, enet->netdev); - skb_put(slot.skb, len - ETH_FCS_LEN); - slot.skb->protocol = eth_type_trans(slot.skb, enet->netdev); - netif_receive_skb(slot.skb); + netif_receive_skb(skb); enet->netdev->stats.rx_packets++; enet->netdev->stats.rx_bytes += len; @@ -635,6 +652,7 @@ static int bcm4908_enet_poll_tx(struct napi_struct *napi, int weight) struct bcm4908_enet_dma_ring_bd *buf_desc; struct bcm4908_enet_dma_ring_slot *slot; struct device *dev = enet->dev; + unsigned int bytes = 0; int handled = 0; while (handled < weight && tx_ring->read_idx != tx_ring->write_idx) { @@ -645,12 +663,17 @@ static int bcm4908_enet_poll_tx(struct napi_struct *napi, int weight) dma_unmap_single(dev, slot->dma_addr, slot->len, DMA_TO_DEVICE); dev_kfree_skb(slot->skb); - if (++tx_ring->read_idx == tx_ring->length) - tx_ring->read_idx = 0; handled++; + bytes += slot->len; + + if (++tx_ring->read_idx == tx_ring->length) + tx_ring->read_idx = 0; } + enet->netdev->stats.tx_packets += handled; + enet->netdev->stats.tx_bytes += bytes; + if (handled < weight) { napi_complete_done(napi, handled); bcm4908_enet_dma_ring_intrs_on(enet, tx_ring); diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c index 867f14c30e09..425d6ccd5413 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.c +++ b/drivers/net/ethernet/broadcom/bcmsysport.c @@ -1991,6 +1991,9 @@ static int bcm_sysport_open(struct net_device *dev) goto out_clk_disable; } + /* Indicate that the MAC is responsible for PHY PM */ + phydev->mac_managed_pm = true; + /* Reset house keeping link status */ priv->old_duplex = -1; priv->old_link = -1; diff --git a/drivers/net/ethernet/broadcom/bcmsysport.h b/drivers/net/ethernet/broadcom/bcmsysport.h index 16b73bb9acc7..5af16e5f9ad0 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.h +++ b/drivers/net/ethernet/broadcom/bcmsysport.h @@ -484,7 +484,7 @@ struct bcm_rsb { /* Number of Receive hardware descriptor words */ #define SP_NUM_HW_RX_DESC_WORDS 1024 -#define SP_LT_NUM_HW_RX_DESC_WORDS 256 +#define SP_LT_NUM_HW_RX_DESC_WORDS 512 /* Internal linked-list RAM size */ #define SP_NUM_TX_DESC 1536 diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c index fec57f1982c8..dbe310144780 100644 --- a/drivers/net/ethernet/broadcom/bnx2.c +++ b/drivers/net/ethernet/broadcom/bnx2.c @@ -5415,8 +5415,9 @@ bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size) bp->rx_buf_use_size = rx_size; /* hw alignment + build_skb() overhead*/ - bp->rx_buf_size = SKB_DATA_ALIGN(bp->rx_buf_use_size + BNX2_RX_ALIGN) + - NET_SKB_PAD + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + bp->rx_buf_size = kmalloc_size_roundup( + SKB_DATA_ALIGN(bp->rx_buf_use_size + BNX2_RX_ALIGN) + + NET_SKB_PAD + SKB_DATA_ALIGN(sizeof(struct skb_shared_info))); bp->rx_jumbo_thresh = rx_size - BNX2_RX_OFFSET; bp->rx_ring_size = size; bp->rx_max_ring = bnx2_find_max_ring(size, BNX2_MAX_RX_RINGS); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index eed98c10ca9d..04cf7684f1b0 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -3874,7 +3874,7 @@ static void bnxt_init_vnics(struct bnxt *bp) if (bp->vnic_info[i].rss_hash_key) { if (i == 0) - prandom_bytes(vnic->rss_hash_key, + get_random_bytes(vnic->rss_hash_key, HW_HASH_KEY_SIZE); else memcpy(vnic->rss_hash_key, diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index b1b17f911300..91a1ba0a914d 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -2116,6 +2116,7 @@ struct bnxt { #define BNXT_PHY_FL_NO_FCS PORT_PHY_QCAPS_RESP_FLAGS_NO_FCS #define BNXT_PHY_FL_NO_PAUSE (PORT_PHY_QCAPS_RESP_FLAGS2_PAUSE_UNSUPPORTED << 8) #define BNXT_PHY_FL_NO_PFC (PORT_PHY_QCAPS_RESP_FLAGS2_PFC_UNSUPPORTED << 8) +#define BNXT_PHY_FL_BANK_SEL (PORT_PHY_QCAPS_RESP_FLAGS2_BANK_ADDR_SUPPORTED << 8) u8 num_tests; struct bnxt_test_info *test_info; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c index a36803e79e92..8a6f788f6294 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c @@ -613,6 +613,7 @@ static int bnxt_dl_reload_up(struct devlink *dl, enum devlink_reload_action acti static bool bnxt_nvm_test(struct bnxt *bp, struct netlink_ext_ack *extack) { + bool rc = false; u32 datalen; u16 index; u8 *buf; @@ -632,20 +633,20 @@ static bool bnxt_nvm_test(struct bnxt *bp, struct netlink_ext_ack *extack) if (bnxt_get_nvram_item(bp->dev, index, 0, datalen, buf)) { NL_SET_ERR_MSG_MOD(extack, "nvm test vpd read error"); - goto err; + goto done; } if (bnxt_flash_nvram(bp->dev, BNX_DIR_TYPE_VPD, BNX_DIR_ORDINAL_FIRST, BNX_DIR_EXT_NONE, 0, 0, buf, datalen)) { NL_SET_ERR_MSG_MOD(extack, "nvm test vpd write error"); - goto err; + goto done; } - return true; + rc = true; -err: +done: kfree(buf); - return false; + return rc; } static bool bnxt_dl_selftest_check(struct devlink *dl, unsigned int id, diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index f57e524c7e30..cc89e5eabcb9 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -2514,6 +2514,7 @@ static int bnxt_flash_firmware_from_file(struct net_device *dev, #define MSG_INTERNAL_ERR "PKG install error : Internal error" #define MSG_NO_PKG_UPDATE_AREA_ERR "PKG update area not created in nvram" #define MSG_NO_SPACE_ERR "PKG insufficient update area in nvram" +#define MSG_RESIZE_UPDATE_ERR "Resize UPDATE entry error" #define MSG_ANTI_ROLLBACK_ERR "HWRM_NVM_INSTALL_UPDATE failure due to Anti-rollback detected" #define MSG_GENERIC_FAILURE_ERR "HWRM_NVM_INSTALL_UPDATE failure" @@ -2564,6 +2565,32 @@ static int nvm_update_err_to_stderr(struct net_device *dev, u8 result, #define BNXT_NVM_MORE_FLAG (cpu_to_le16(NVM_MODIFY_REQ_FLAGS_BATCH_MODE)) #define BNXT_NVM_LAST_FLAG (cpu_to_le16(NVM_MODIFY_REQ_FLAGS_BATCH_LAST)) +static int bnxt_resize_update_entry(struct net_device *dev, size_t fw_size, + struct netlink_ext_ack *extack) +{ + u32 item_len; + int rc; + + rc = bnxt_find_nvram_item(dev, BNX_DIR_TYPE_UPDATE, + BNX_DIR_ORDINAL_FIRST, BNX_DIR_EXT_NONE, NULL, + &item_len, NULL); + if (rc) { + BNXT_NVM_ERR_MSG(dev, extack, MSG_NO_PKG_UPDATE_AREA_ERR); + return rc; + } + + if (fw_size > item_len) { + rc = bnxt_flash_nvram(dev, BNX_DIR_TYPE_UPDATE, + BNX_DIR_ORDINAL_FIRST, 0, 1, + round_up(fw_size, 4096), NULL, 0); + if (rc) { + BNXT_NVM_ERR_MSG(dev, extack, MSG_RESIZE_UPDATE_ERR); + return rc; + } + } + return 0; +} + int bnxt_flash_package_from_fw_obj(struct net_device *dev, const struct firmware *fw, u32 install_type, struct netlink_ext_ack *extack) { @@ -2580,6 +2607,11 @@ int bnxt_flash_package_from_fw_obj(struct net_device *dev, const struct firmware u16 index; int rc; + /* resize before flashing larger image than available space */ + rc = bnxt_resize_update_entry(dev, fw->size, extack); + if (rc) + return rc; + bnxt_hwrm_fw_set_time(bp); rc = hwrm_req_init(bp, modify, HWRM_NVM_MODIFY); @@ -3146,8 +3178,9 @@ static int bnxt_get_eee(struct net_device *dev, struct ethtool_eee *edata) } static int bnxt_read_sfp_module_eeprom_info(struct bnxt *bp, u16 i2c_addr, - u16 page_number, u16 start_addr, - u16 data_length, u8 *buf) + u16 page_number, u8 bank, + u16 start_addr, u16 data_length, + u8 *buf) { struct hwrm_port_phy_i2c_read_output *output; struct hwrm_port_phy_i2c_read_input *req; @@ -3168,8 +3201,13 @@ static int bnxt_read_sfp_module_eeprom_info(struct bnxt *bp, u16 i2c_addr, data_length -= xfer_size; req->page_offset = cpu_to_le16(start_addr + byte_offset); req->data_length = xfer_size; - req->enables = cpu_to_le32(start_addr + byte_offset ? - PORT_PHY_I2C_READ_REQ_ENABLES_PAGE_OFFSET : 0); + req->enables = + cpu_to_le32((start_addr + byte_offset ? + PORT_PHY_I2C_READ_REQ_ENABLES_PAGE_OFFSET : + 0) | + (bank ? + PORT_PHY_I2C_READ_REQ_ENABLES_BANK_NUMBER : + 0)); rc = hwrm_req_send(bp, req); if (!rc) memcpy(buf + byte_offset, output->data, xfer_size); @@ -3199,7 +3237,7 @@ static int bnxt_get_module_info(struct net_device *dev, if (bp->hwrm_spec_code < 0x10202) return -EOPNOTSUPP; - rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A0, 0, 0, + rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A0, 0, 0, 0, SFF_DIAG_SUPPORT_OFFSET + 1, data); if (!rc) { @@ -3244,7 +3282,7 @@ static int bnxt_get_module_eeprom(struct net_device *dev, if (start < ETH_MODULE_SFF_8436_LEN) { if (start + eeprom->len > ETH_MODULE_SFF_8436_LEN) length = ETH_MODULE_SFF_8436_LEN - start; - rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A0, 0, + rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A0, 0, 0, start, length, data); if (rc) return rc; @@ -3256,12 +3294,68 @@ static int bnxt_get_module_eeprom(struct net_device *dev, /* Read A2 portion of the EEPROM */ if (length) { start -= ETH_MODULE_SFF_8436_LEN; - rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A2, 0, + rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A2, 0, 0, start, length, data); } return rc; } +static int bnxt_get_module_status(struct bnxt *bp, struct netlink_ext_ack *extack) +{ + if (bp->link_info.module_status <= + PORT_PHY_QCFG_RESP_MODULE_STATUS_WARNINGMSG) + return 0; + + switch (bp->link_info.module_status) { + case PORT_PHY_QCFG_RESP_MODULE_STATUS_PWRDOWN: + NL_SET_ERR_MSG_MOD(extack, "Transceiver module is powering down"); + break; + case PORT_PHY_QCFG_RESP_MODULE_STATUS_NOTINSERTED: + NL_SET_ERR_MSG_MOD(extack, "Transceiver module not inserted"); + break; + case PORT_PHY_QCFG_RESP_MODULE_STATUS_CURRENTFAULT: + NL_SET_ERR_MSG_MOD(extack, "Transceiver module disabled due to current fault"); + break; + default: + NL_SET_ERR_MSG_MOD(extack, "Unknown error"); + break; + } + return -EINVAL; +} + +static int bnxt_get_module_eeprom_by_page(struct net_device *dev, + const struct ethtool_module_eeprom *page_data, + struct netlink_ext_ack *extack) +{ + struct bnxt *bp = netdev_priv(dev); + int rc; + + rc = bnxt_get_module_status(bp, extack); + if (rc) + return rc; + + if (bp->hwrm_spec_code < 0x10202) { + NL_SET_ERR_MSG_MOD(extack, "Firmware version too old"); + return -EINVAL; + } + + if (page_data->bank && !(bp->phy_flags & BNXT_PHY_FL_BANK_SEL)) { + NL_SET_ERR_MSG_MOD(extack, "Firmware not capable for bank selection"); + return -EINVAL; + } + + rc = bnxt_read_sfp_module_eeprom_info(bp, page_data->i2c_address << 1, + page_data->page, page_data->bank, + page_data->offset, + page_data->length, + page_data->data); + if (rc) { + NL_SET_ERR_MSG_MOD(extack, "Module`s eeprom read failed"); + return rc; + } + return page_data->length; +} + static int bnxt_nway_reset(struct net_device *dev) { int rc = 0; @@ -4071,6 +4165,7 @@ const struct ethtool_ops bnxt_ethtool_ops = { .set_eee = bnxt_set_eee, .get_module_info = bnxt_get_module_info, .get_module_eeprom = bnxt_get_module_eeprom, + .get_module_eeprom_by_page = bnxt_get_module_eeprom_by_page, .nway_reset = bnxt_nway_reset, .set_phys_id = bnxt_set_phys_id, .self_test = bnxt_self_test, diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h index b753032a1047..184dd8d11cd3 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h @@ -254,6 +254,8 @@ struct cmd_nums { #define HWRM_PORT_DSC_DUMP 0xd9UL #define HWRM_PORT_EP_TX_QCFG 0xdaUL #define HWRM_PORT_EP_TX_CFG 0xdbUL + #define HWRM_PORT_CFG 0xdcUL + #define HWRM_PORT_QCFG 0xddUL #define HWRM_TEMP_MONITOR_QUERY 0xe0UL #define HWRM_REG_POWER_QUERY 0xe1UL #define HWRM_CORE_FREQUENCY_QUERY 0xe2UL @@ -379,6 +381,8 @@ struct cmd_nums { #define HWRM_FUNC_BACKING_STORE_QCAPS_V2 0x1a8UL #define HWRM_FUNC_DBR_PACING_NQLIST_QUERY 0x1a9UL #define HWRM_FUNC_DBR_RECOVERY_COMPLETED 0x1aaUL + #define HWRM_FUNC_SYNCE_CFG 0x1abUL + #define HWRM_FUNC_SYNCE_QCFG 0x1acUL #define HWRM_SELFTEST_QLIST 0x200UL #define HWRM_SELFTEST_EXEC 0x201UL #define HWRM_SELFTEST_IRQ 0x202UL @@ -417,6 +421,8 @@ struct cmd_nums { #define HWRM_TF_SESSION_RESC_FREE 0x2ceUL #define HWRM_TF_SESSION_RESC_FLUSH 0x2cfUL #define HWRM_TF_SESSION_RESC_INFO 0x2d0UL + #define HWRM_TF_SESSION_HOTUP_STATE_SET 0x2d1UL + #define HWRM_TF_SESSION_HOTUP_STATE_GET 0x2d2UL #define HWRM_TF_TBL_TYPE_GET 0x2daUL #define HWRM_TF_TBL_TYPE_SET 0x2dbUL #define HWRM_TF_TBL_TYPE_BULK_GET 0x2dcUL @@ -440,6 +446,25 @@ struct cmd_nums { #define HWRM_TF_GLOBAL_CFG_GET 0x2fdUL #define HWRM_TF_IF_TBL_SET 0x2feUL #define HWRM_TF_IF_TBL_GET 0x2ffUL + #define HWRM_TFC_TBL_SCOPE_QCAPS 0x380UL + #define HWRM_TFC_TBL_SCOPE_ID_ALLOC 0x381UL + #define HWRM_TFC_TBL_SCOPE_CONFIG 0x382UL + #define HWRM_TFC_TBL_SCOPE_DECONFIG 0x383UL + #define HWRM_TFC_TBL_SCOPE_FID_ADD 0x384UL + #define HWRM_TFC_TBL_SCOPE_FID_REM 0x385UL + #define HWRM_TFC_TBL_SCOPE_POOL_ALLOC 0x386UL + #define HWRM_TFC_TBL_SCOPE_POOL_FREE 0x387UL + #define HWRM_TFC_SESSION_ID_ALLOC 0x388UL + #define HWRM_TFC_SESSION_FID_ADD 0x389UL + #define HWRM_TFC_SESSION_FID_REM 0x38aUL + #define HWRM_TFC_IDENT_ALLOC 0x38bUL + #define HWRM_TFC_IDENT_FREE 0x38cUL + #define HWRM_TFC_IDX_TBL_ALLOC 0x38dUL + #define HWRM_TFC_IDX_TBL_ALLOC_SET 0x38eUL + #define HWRM_TFC_IDX_TBL_SET 0x38fUL + #define HWRM_TFC_IDX_TBL_GET 0x390UL + #define HWRM_TFC_IDX_TBL_FREE 0x391UL + #define HWRM_TFC_GLOBAL_ID_ALLOC 0x392UL #define HWRM_SV 0x400UL #define HWRM_DBG_READ_DIRECT 0xff10UL #define HWRM_DBG_READ_INDIRECT 0xff11UL @@ -546,8 +571,8 @@ struct hwrm_err_output { #define HWRM_VERSION_MAJOR 1 #define HWRM_VERSION_MINOR 10 #define HWRM_VERSION_UPDATE 2 -#define HWRM_VERSION_RSVD 95 -#define HWRM_VERSION_STR "1.10.2.95" +#define HWRM_VERSION_RSVD 118 +#define HWRM_VERSION_STR "1.10.2.118" /* hwrm_ver_get_input (size:192b/24B) */ struct hwrm_ver_get_input { @@ -1657,6 +1682,10 @@ struct hwrm_func_qcaps_output { #define FUNC_QCAPS_RESP_FLAGS_EXT2_DBR_PACING_EXT_SUPPORTED 0x8UL #define FUNC_QCAPS_RESP_FLAGS_EXT2_SW_DBR_DROP_RECOVERY_SUPPORTED 0x10UL #define FUNC_QCAPS_RESP_FLAGS_EXT2_GENERIC_STATS_SUPPORTED 0x20UL + #define FUNC_QCAPS_RESP_FLAGS_EXT2_UDP_GSO_SUPPORTED 0x40UL + #define FUNC_QCAPS_RESP_FLAGS_EXT2_SYNCE_SUPPORTED 0x80UL + #define FUNC_QCAPS_RESP_FLAGS_EXT2_DBR_PACING_V0_SUPPORTED 0x100UL + #define FUNC_QCAPS_RESP_FLAGS_EXT2_TX_PKT_TS_CMPL_SUPPORTED 0x200UL __le16 tunnel_disable_flag; #define FUNC_QCAPS_RESP_TUNNEL_DISABLE_FLAG_DISABLE_VXLAN 0x1UL #define FUNC_QCAPS_RESP_TUNNEL_DISABLE_FLAG_DISABLE_NGE 0x2UL @@ -1804,7 +1833,20 @@ struct hwrm_func_qcfg_output { #define FUNC_QCFG_RESP_MPC_CHNLS_TE_CFA_ENABLED 0x4UL #define FUNC_QCFG_RESP_MPC_CHNLS_RE_CFA_ENABLED 0x8UL #define FUNC_QCFG_RESP_MPC_CHNLS_PRIMATE_ENABLED 0x10UL - u8 unused_2[3]; + u8 db_page_size; + #define FUNC_QCFG_RESP_DB_PAGE_SIZE_4KB 0x0UL + #define FUNC_QCFG_RESP_DB_PAGE_SIZE_8KB 0x1UL + #define FUNC_QCFG_RESP_DB_PAGE_SIZE_16KB 0x2UL + #define FUNC_QCFG_RESP_DB_PAGE_SIZE_32KB 0x3UL + #define FUNC_QCFG_RESP_DB_PAGE_SIZE_64KB 0x4UL + #define FUNC_QCFG_RESP_DB_PAGE_SIZE_128KB 0x5UL + #define FUNC_QCFG_RESP_DB_PAGE_SIZE_256KB 0x6UL + #define FUNC_QCFG_RESP_DB_PAGE_SIZE_512KB 0x7UL + #define FUNC_QCFG_RESP_DB_PAGE_SIZE_1MB 0x8UL + #define FUNC_QCFG_RESP_DB_PAGE_SIZE_2MB 0x9UL + #define FUNC_QCFG_RESP_DB_PAGE_SIZE_4MB 0xaUL + #define FUNC_QCFG_RESP_DB_PAGE_SIZE_LAST FUNC_QCFG_RESP_DB_PAGE_SIZE_4MB + u8 unused_2[2]; __le32 partition_min_bw; #define FUNC_QCFG_RESP_PARTITION_MIN_BW_BW_VALUE_MASK 0xfffffffUL #define FUNC_QCFG_RESP_PARTITION_MIN_BW_BW_VALUE_SFT 0 @@ -1876,6 +1918,7 @@ struct hwrm_func_cfg_input { #define FUNC_CFG_REQ_FLAGS_PPP_PUSH_MODE_DISABLE 0x10000000UL #define FUNC_CFG_REQ_FLAGS_BD_METADATA_ENABLE 0x20000000UL #define FUNC_CFG_REQ_FLAGS_BD_METADATA_DISABLE 0x40000000UL + #define FUNC_CFG_REQ_FLAGS_KEY_CTX_ASSETS_TEST 0x80000000UL __le32 enables; #define FUNC_CFG_REQ_ENABLES_ADMIN_MTU 0x1UL #define FUNC_CFG_REQ_ENABLES_MRU 0x2UL @@ -2021,12 +2064,26 @@ struct hwrm_func_cfg_input { __le16 num_tx_key_ctxs; __le16 num_rx_key_ctxs; __le32 enables2; - #define FUNC_CFG_REQ_ENABLES2_KDNET 0x1UL + #define FUNC_CFG_REQ_ENABLES2_KDNET 0x1UL + #define FUNC_CFG_REQ_ENABLES2_DB_PAGE_SIZE 0x2UL u8 port_kdnet_mode; #define FUNC_CFG_REQ_PORT_KDNET_MODE_DISABLED 0x0UL #define FUNC_CFG_REQ_PORT_KDNET_MODE_ENABLED 0x1UL #define FUNC_CFG_REQ_PORT_KDNET_MODE_LAST FUNC_CFG_REQ_PORT_KDNET_MODE_ENABLED - u8 unused_0[7]; + u8 db_page_size; + #define FUNC_CFG_REQ_DB_PAGE_SIZE_4KB 0x0UL + #define FUNC_CFG_REQ_DB_PAGE_SIZE_8KB 0x1UL + #define FUNC_CFG_REQ_DB_PAGE_SIZE_16KB 0x2UL + #define FUNC_CFG_REQ_DB_PAGE_SIZE_32KB 0x3UL + #define FUNC_CFG_REQ_DB_PAGE_SIZE_64KB 0x4UL + #define FUNC_CFG_REQ_DB_PAGE_SIZE_128KB 0x5UL + #define FUNC_CFG_REQ_DB_PAGE_SIZE_256KB 0x6UL + #define FUNC_CFG_REQ_DB_PAGE_SIZE_512KB 0x7UL + #define FUNC_CFG_REQ_DB_PAGE_SIZE_1MB 0x8UL + #define FUNC_CFG_REQ_DB_PAGE_SIZE_2MB 0x9UL + #define FUNC_CFG_REQ_DB_PAGE_SIZE_4MB 0xaUL + #define FUNC_CFG_REQ_DB_PAGE_SIZE_LAST FUNC_CFG_REQ_DB_PAGE_SIZE_4MB + u8 unused_0[6]; }; /* hwrm_func_cfg_output (size:128b/16B) */ @@ -2060,10 +2117,9 @@ struct hwrm_func_qstats_input { __le64 resp_addr; __le16 fid; u8 flags; - #define FUNC_QSTATS_REQ_FLAGS_UNUSED 0x0UL - #define FUNC_QSTATS_REQ_FLAGS_ROCE_ONLY 0x1UL - #define FUNC_QSTATS_REQ_FLAGS_COUNTER_MASK 0x2UL - #define FUNC_QSTATS_REQ_FLAGS_LAST FUNC_QSTATS_REQ_FLAGS_COUNTER_MASK + #define FUNC_QSTATS_REQ_FLAGS_ROCE_ONLY 0x1UL + #define FUNC_QSTATS_REQ_FLAGS_COUNTER_MASK 0x2UL + #define FUNC_QSTATS_REQ_FLAGS_L2_ONLY 0x4UL u8 unused_0[5]; }; @@ -2093,7 +2149,8 @@ struct hwrm_func_qstats_output { __le64 rx_agg_bytes; __le64 rx_agg_events; __le64 rx_agg_aborts; - u8 unused_0[7]; + u8 clear_seq; + u8 unused_0[6]; u8 valid; }; @@ -2106,10 +2163,8 @@ struct hwrm_func_qstats_ext_input { __le64 resp_addr; __le16 fid; u8 flags; - #define FUNC_QSTATS_EXT_REQ_FLAGS_UNUSED 0x0UL - #define FUNC_QSTATS_EXT_REQ_FLAGS_ROCE_ONLY 0x1UL - #define FUNC_QSTATS_EXT_REQ_FLAGS_COUNTER_MASK 0x2UL - #define FUNC_QSTATS_EXT_REQ_FLAGS_LAST FUNC_QSTATS_EXT_REQ_FLAGS_COUNTER_MASK + #define FUNC_QSTATS_EXT_REQ_FLAGS_ROCE_ONLY 0x1UL + #define FUNC_QSTATS_EXT_REQ_FLAGS_COUNTER_MASK 0x2UL u8 unused_0[1]; __le32 enables; #define FUNC_QSTATS_EXT_REQ_ENABLES_SCHQ_ID 0x1UL @@ -2210,6 +2265,7 @@ struct hwrm_func_drv_rgtr_input { #define FUNC_DRV_RGTR_REQ_FLAGS_FAST_RESET_SUPPORT 0x80UL #define FUNC_DRV_RGTR_REQ_FLAGS_RSS_STRICT_HASH_TYPE_SUPPORT 0x100UL #define FUNC_DRV_RGTR_REQ_FLAGS_NPAR_1_2_SUPPORT 0x200UL + #define FUNC_DRV_RGTR_REQ_FLAGS_ASYM_QUEUE_CFG_SUPPORT 0x400UL __le32 enables; #define FUNC_DRV_RGTR_REQ_ENABLES_OS_TYPE 0x1UL #define FUNC_DRV_RGTR_REQ_ENABLES_VER 0x2UL @@ -3155,19 +3211,23 @@ struct hwrm_func_ptp_pin_qcfg_output { #define FUNC_PTP_PIN_QCFG_RESP_PIN1_USAGE_SYNC_OUT 0x4UL #define FUNC_PTP_PIN_QCFG_RESP_PIN1_USAGE_LAST FUNC_PTP_PIN_QCFG_RESP_PIN1_USAGE_SYNC_OUT u8 pin2_usage; - #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_NONE 0x0UL - #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_PPS_IN 0x1UL - #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_PPS_OUT 0x2UL - #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_SYNC_IN 0x3UL - #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_SYNC_OUT 0x4UL - #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_LAST FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_SYNC_OUT + #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_NONE 0x0UL + #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_PPS_IN 0x1UL + #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_PPS_OUT 0x2UL + #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_SYNC_IN 0x3UL + #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_SYNC_OUT 0x4UL + #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_SYNCE_PRIMARY_CLOCK_OUT 0x5UL + #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_SYNCE_SECONDARY_CLOCK_OUT 0x6UL + #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_LAST FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_SYNCE_SECONDARY_CLOCK_OUT u8 pin3_usage; - #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_NONE 0x0UL - #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_PPS_IN 0x1UL - #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_PPS_OUT 0x2UL - #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_SYNC_IN 0x3UL - #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_SYNC_OUT 0x4UL - #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_LAST FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_SYNC_OUT + #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_NONE 0x0UL + #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_PPS_IN 0x1UL + #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_PPS_OUT 0x2UL + #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_SYNC_IN 0x3UL + #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_SYNC_OUT 0x4UL + #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_SYNCE_PRIMARY_CLOCK_OUT 0x5UL + #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_SYNCE_SECONDARY_CLOCK_OUT 0x6UL + #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_LAST FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_SYNCE_SECONDARY_CLOCK_OUT u8 unused_0; u8 valid; }; @@ -3215,23 +3275,27 @@ struct hwrm_func_ptp_pin_cfg_input { #define FUNC_PTP_PIN_CFG_REQ_PIN2_STATE_ENABLED 0x1UL #define FUNC_PTP_PIN_CFG_REQ_PIN2_STATE_LAST FUNC_PTP_PIN_CFG_REQ_PIN2_STATE_ENABLED u8 pin2_usage; - #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_NONE 0x0UL - #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_PPS_IN 0x1UL - #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_PPS_OUT 0x2UL - #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_SYNC_IN 0x3UL - #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_SYNC_OUT 0x4UL - #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_LAST FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_SYNC_OUT + #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_NONE 0x0UL + #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_PPS_IN 0x1UL + #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_PPS_OUT 0x2UL + #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_SYNC_IN 0x3UL + #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_SYNC_OUT 0x4UL + #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_SYNCE_PRIMARY_CLOCK_OUT 0x5UL + #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_SYNCE_SECONDARY_CLOCK_OUT 0x6UL + #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_LAST FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_SYNCE_SECONDARY_CLOCK_OUT u8 pin3_state; #define FUNC_PTP_PIN_CFG_REQ_PIN3_STATE_DISABLED 0x0UL #define FUNC_PTP_PIN_CFG_REQ_PIN3_STATE_ENABLED 0x1UL #define FUNC_PTP_PIN_CFG_REQ_PIN3_STATE_LAST FUNC_PTP_PIN_CFG_REQ_PIN3_STATE_ENABLED u8 pin3_usage; - #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_NONE 0x0UL - #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_PPS_IN 0x1UL - #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_PPS_OUT 0x2UL - #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_SYNC_IN 0x3UL - #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_SYNC_OUT 0x4UL - #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_LAST FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_SYNC_OUT + #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_NONE 0x0UL + #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_PPS_IN 0x1UL + #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_PPS_OUT 0x2UL + #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_SYNC_IN 0x3UL + #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_SYNC_OUT 0x4UL + #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_SYNCE_PRIMARY_CLOCK_OUT 0x5UL + #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_SYNCE_SECONDARY_CLOCK_OUT 0x6UL + #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_LAST FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_SYNCE_SECONDARY_CLOCK_OUT u8 unused_0[4]; }; @@ -3319,9 +3383,9 @@ struct hwrm_func_ptp_ts_query_output { __le16 seq_id; __le16 resp_len; __le64 pps_event_ts; - __le64 ptm_res_local_ts; - __le64 ptm_pmstr_ts; - __le32 ptm_mstr_prop_dly; + __le64 ptm_local_ts; + __le64 ptm_system_ts; + __le32 ptm_link_delay; u8 unused_0[3]; u8 valid; }; @@ -3417,7 +3481,9 @@ struct hwrm_func_backing_store_cfg_v2_input { #define FUNC_BACKING_STORE_CFG_V2_REQ_TYPE_LAST FUNC_BACKING_STORE_CFG_V2_REQ_TYPE_INVALID __le16 instance; __le32 flags; - #define FUNC_BACKING_STORE_CFG_V2_REQ_FLAGS_PREBOOT_MODE 0x1UL + #define FUNC_BACKING_STORE_CFG_V2_REQ_FLAGS_PREBOOT_MODE 0x1UL + #define FUNC_BACKING_STORE_CFG_V2_REQ_FLAGS_BS_CFG_ALL_DONE 0x2UL + #define FUNC_BACKING_STORE_CFG_V2_REQ_FLAGS_BS_EXTEND 0x4UL __le64 page_dir; __le32 num_entries; __le16 entry_size; @@ -3853,7 +3919,7 @@ struct hwrm_port_phy_qcfg_input { u8 unused_0[6]; }; -/* hwrm_port_phy_qcfg_output (size:768b/96B) */ +/* hwrm_port_phy_qcfg_output (size:832b/104B) */ struct hwrm_port_phy_qcfg_output { __le16 error_code; __le16 req_type; @@ -4150,6 +4216,9 @@ struct hwrm_port_phy_qcfg_output { #define PORT_PHY_QCFG_RESP_LINK_PARTNER_PAM4_ADV_SPEEDS_50GB 0x1UL #define PORT_PHY_QCFG_RESP_LINK_PARTNER_PAM4_ADV_SPEEDS_100GB 0x2UL #define PORT_PHY_QCFG_RESP_LINK_PARTNER_PAM4_ADV_SPEEDS_200GB 0x4UL + u8 link_down_reason; + #define PORT_PHY_QCFG_RESP_LINK_DOWN_REASON_RF 0x1UL + u8 unused_0[7]; u8 valid; }; @@ -4422,9 +4491,7 @@ struct hwrm_port_qstats_input { __le64 resp_addr; __le16 port_id; u8 flags; - #define PORT_QSTATS_REQ_FLAGS_UNUSED 0x0UL - #define PORT_QSTATS_REQ_FLAGS_COUNTER_MASK 0x1UL - #define PORT_QSTATS_REQ_FLAGS_LAST PORT_QSTATS_REQ_FLAGS_COUNTER_MASK + #define PORT_QSTATS_REQ_FLAGS_COUNTER_MASK 0x1UL u8 unused_0[5]; __le64 tx_stat_host_addr; __le64 rx_stat_host_addr; @@ -4552,9 +4619,7 @@ struct hwrm_port_qstats_ext_input { __le16 tx_stat_size; __le16 rx_stat_size; u8 flags; - #define PORT_QSTATS_EXT_REQ_FLAGS_UNUSED 0x0UL - #define PORT_QSTATS_EXT_REQ_FLAGS_COUNTER_MASK 0x1UL - #define PORT_QSTATS_EXT_REQ_FLAGS_LAST PORT_QSTATS_EXT_REQ_FLAGS_COUNTER_MASK + #define PORT_QSTATS_EXT_REQ_FLAGS_COUNTER_MASK 0x1UL u8 unused_0; __le64 tx_stat_host_addr; __le64 rx_stat_host_addr; @@ -4613,9 +4678,7 @@ struct hwrm_port_ecn_qstats_input { __le16 port_id; __le16 ecn_stat_buf_size; u8 flags; - #define PORT_ECN_QSTATS_REQ_FLAGS_UNUSED 0x0UL - #define PORT_ECN_QSTATS_REQ_FLAGS_COUNTER_MASK 0x1UL - #define PORT_ECN_QSTATS_REQ_FLAGS_LAST PORT_ECN_QSTATS_REQ_FLAGS_COUNTER_MASK + #define PORT_ECN_QSTATS_REQ_FLAGS_COUNTER_MASK 0x1UL u8 unused_0[3]; __le64 ecn_stat_host_addr; }; @@ -4814,8 +4877,9 @@ struct hwrm_port_phy_qcaps_output { #define PORT_PHY_QCAPS_RESP_SUPPORTED_PAM4_SPEEDS_FORCE_MODE_100G 0x2UL #define PORT_PHY_QCAPS_RESP_SUPPORTED_PAM4_SPEEDS_FORCE_MODE_200G 0x4UL __le16 flags2; - #define PORT_PHY_QCAPS_RESP_FLAGS2_PAUSE_UNSUPPORTED 0x1UL - #define PORT_PHY_QCAPS_RESP_FLAGS2_PFC_UNSUPPORTED 0x2UL + #define PORT_PHY_QCAPS_RESP_FLAGS2_PAUSE_UNSUPPORTED 0x1UL + #define PORT_PHY_QCAPS_RESP_FLAGS2_PFC_UNSUPPORTED 0x2UL + #define PORT_PHY_QCAPS_RESP_FLAGS2_BANK_ADDR_SUPPORTED 0x4UL u8 internal_port_cnt; u8 valid; }; @@ -4830,9 +4894,10 @@ struct hwrm_port_phy_i2c_read_input { __le32 flags; __le32 enables; #define PORT_PHY_I2C_READ_REQ_ENABLES_PAGE_OFFSET 0x1UL + #define PORT_PHY_I2C_READ_REQ_ENABLES_BANK_NUMBER 0x2UL __le16 port_id; u8 i2c_slave_addr; - u8 unused_0; + u8 bank_number; __le16 page_number; __le16 page_offset; u8 data_length; @@ -6537,6 +6602,7 @@ struct hwrm_vnic_qcaps_output { #define VNIC_QCAPS_RESP_FLAGS_RSS_IPSEC_ESP_SPI_IPV4_CAP 0x400000UL #define VNIC_QCAPS_RESP_FLAGS_RSS_IPSEC_AH_SPI_IPV6_CAP 0x800000UL #define VNIC_QCAPS_RESP_FLAGS_RSS_IPSEC_ESP_SPI_IPV6_CAP 0x1000000UL + #define VNIC_QCAPS_RESP_FLAGS_OUTERMOST_RSS_TRUSTED_VF_CAP 0x2000000UL __le16 max_aggs_supported; u8 unused_1[5]; u8 valid; @@ -6827,6 +6893,7 @@ struct hwrm_ring_alloc_input { #define RING_ALLOC_REQ_FLAGS_RX_SOP_PAD 0x1UL #define RING_ALLOC_REQ_FLAGS_DISABLE_CQ_OVERFLOW_DETECTION 0x2UL #define RING_ALLOC_REQ_FLAGS_NQ_DBR_PACING 0x4UL + #define RING_ALLOC_REQ_FLAGS_TX_PKT_TS_CMPL_ENABLE 0x8UL __le64 page_tbl_addr; __le32 fbo; u8 page_size; @@ -7626,7 +7693,10 @@ struct hwrm_cfa_ntuple_filter_alloc_input { #define CFA_NTUPLE_FILTER_ALLOC_REQ_IP_PROTOCOL_UNKNOWN 0x0UL #define CFA_NTUPLE_FILTER_ALLOC_REQ_IP_PROTOCOL_TCP 0x6UL #define CFA_NTUPLE_FILTER_ALLOC_REQ_IP_PROTOCOL_UDP 0x11UL - #define CFA_NTUPLE_FILTER_ALLOC_REQ_IP_PROTOCOL_LAST CFA_NTUPLE_FILTER_ALLOC_REQ_IP_PROTOCOL_UDP + #define CFA_NTUPLE_FILTER_ALLOC_REQ_IP_PROTOCOL_ICMP 0x1UL + #define CFA_NTUPLE_FILTER_ALLOC_REQ_IP_PROTOCOL_ICMPV6 0x3aUL + #define CFA_NTUPLE_FILTER_ALLOC_REQ_IP_PROTOCOL_RSVD 0xffUL + #define CFA_NTUPLE_FILTER_ALLOC_REQ_IP_PROTOCOL_LAST CFA_NTUPLE_FILTER_ALLOC_REQ_IP_PROTOCOL_RSVD __le16 dst_id; __le16 mirror_vnic_id; u8 tunnel_type; @@ -8337,6 +8407,7 @@ struct hwrm_cfa_adv_flow_mgnt_qcaps_output { #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_LAG_SUPPORTED 0x20000UL #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_NTUPLE_FLOW_NO_L2CTX_SUPPORTED 0x40000UL #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_NIC_FLOW_STATS_SUPPORTED 0x80000UL + #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_NTUPLE_FLOW_RX_EXT_IP_PROTO_SUPPORTED 0x100000UL u8 unused_0[3]; u8 valid; }; @@ -8355,7 +8426,9 @@ struct hwrm_tunnel_dst_port_query_input { #define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_IPGRE_V1 0xaUL #define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_L2_ETYPE 0xbUL #define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_VXLAN_GPE_V6 0xcUL - #define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_LAST TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_VXLAN_GPE_V6 + #define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_CUSTOM_GRE 0xdUL + #define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_ECPRI 0xeUL + #define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_LAST TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_ECPRI u8 unused_0[7]; }; @@ -8367,7 +8440,16 @@ struct hwrm_tunnel_dst_port_query_output { __le16 resp_len; __le16 tunnel_dst_port_id; __be16 tunnel_dst_port_val; - u8 unused_0[3]; + u8 upar_in_use; + #define TUNNEL_DST_PORT_QUERY_RESP_UPAR_IN_USE_UPAR0 0x1UL + #define TUNNEL_DST_PORT_QUERY_RESP_UPAR_IN_USE_UPAR1 0x2UL + #define TUNNEL_DST_PORT_QUERY_RESP_UPAR_IN_USE_UPAR2 0x4UL + #define TUNNEL_DST_PORT_QUERY_RESP_UPAR_IN_USE_UPAR3 0x8UL + #define TUNNEL_DST_PORT_QUERY_RESP_UPAR_IN_USE_UPAR4 0x10UL + #define TUNNEL_DST_PORT_QUERY_RESP_UPAR_IN_USE_UPAR5 0x20UL + #define TUNNEL_DST_PORT_QUERY_RESP_UPAR_IN_USE_UPAR6 0x40UL + #define TUNNEL_DST_PORT_QUERY_RESP_UPAR_IN_USE_UPAR7 0x80UL + u8 unused_0[2]; u8 valid; }; @@ -8385,7 +8467,9 @@ struct hwrm_tunnel_dst_port_alloc_input { #define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_IPGRE_V1 0xaUL #define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_L2_ETYPE 0xbUL #define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_VXLAN_GPE_V6 0xcUL - #define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_LAST TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_VXLAN_GPE_V6 + #define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_CUSTOM_GRE 0xdUL + #define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_ECPRI 0xeUL + #define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_LAST TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_ECPRI u8 unused_0; __be16 tunnel_dst_port_val; u8 unused_1[4]; @@ -8398,7 +8482,21 @@ struct hwrm_tunnel_dst_port_alloc_output { __le16 seq_id; __le16 resp_len; __le16 tunnel_dst_port_id; - u8 unused_0[5]; + u8 error_info; + #define TUNNEL_DST_PORT_ALLOC_RESP_ERROR_INFO_SUCCESS 0x0UL + #define TUNNEL_DST_PORT_ALLOC_RESP_ERROR_INFO_ERR_ALLOCATED 0x1UL + #define TUNNEL_DST_PORT_ALLOC_RESP_ERROR_INFO_ERR_NO_RESOURCE 0x2UL + #define TUNNEL_DST_PORT_ALLOC_RESP_ERROR_INFO_LAST TUNNEL_DST_PORT_ALLOC_RESP_ERROR_INFO_ERR_NO_RESOURCE + u8 upar_in_use; + #define TUNNEL_DST_PORT_ALLOC_RESP_UPAR_IN_USE_UPAR0 0x1UL + #define TUNNEL_DST_PORT_ALLOC_RESP_UPAR_IN_USE_UPAR1 0x2UL + #define TUNNEL_DST_PORT_ALLOC_RESP_UPAR_IN_USE_UPAR2 0x4UL + #define TUNNEL_DST_PORT_ALLOC_RESP_UPAR_IN_USE_UPAR3 0x8UL + #define TUNNEL_DST_PORT_ALLOC_RESP_UPAR_IN_USE_UPAR4 0x10UL + #define TUNNEL_DST_PORT_ALLOC_RESP_UPAR_IN_USE_UPAR5 0x20UL + #define TUNNEL_DST_PORT_ALLOC_RESP_UPAR_IN_USE_UPAR6 0x40UL + #define TUNNEL_DST_PORT_ALLOC_RESP_UPAR_IN_USE_UPAR7 0x80UL + u8 unused_0[3]; u8 valid; }; @@ -8416,7 +8514,9 @@ struct hwrm_tunnel_dst_port_free_input { #define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_IPGRE_V1 0xaUL #define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_L2_ETYPE 0xbUL #define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_VXLAN_GPE_V6 0xcUL - #define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_LAST TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_VXLAN_GPE_V6 + #define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_CUSTOM_GRE 0xdUL + #define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_ECPRI 0xeUL + #define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_LAST TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_ECPRI u8 unused_0; __le16 tunnel_dst_port_id; u8 unused_1[4]; @@ -8428,7 +8528,12 @@ struct hwrm_tunnel_dst_port_free_output { __le16 req_type; __le16 seq_id; __le16 resp_len; - u8 unused_1[7]; + u8 error_info; + #define TUNNEL_DST_PORT_FREE_RESP_ERROR_INFO_SUCCESS 0x0UL + #define TUNNEL_DST_PORT_FREE_RESP_ERROR_INFO_ERR_NOT_OWNER 0x1UL + #define TUNNEL_DST_PORT_FREE_RESP_ERROR_INFO_ERR_NOT_ALLOCATED 0x2UL + #define TUNNEL_DST_PORT_FREE_RESP_ERROR_INFO_LAST TUNNEL_DST_PORT_FREE_RESP_ERROR_INFO_ERR_NOT_ALLOCATED + u8 unused_1[6]; u8 valid; }; @@ -8686,9 +8791,7 @@ struct hwrm_stat_generic_qstats_input { __le64 resp_addr; __le16 generic_stat_size; u8 flags; - #define STAT_GENERIC_QSTATS_REQ_FLAGS_COUNTER 0x0UL - #define STAT_GENERIC_QSTATS_REQ_FLAGS_COUNTER_MASK 0x1UL - #define STAT_GENERIC_QSTATS_REQ_FLAGS_LAST STAT_GENERIC_QSTATS_REQ_FLAGS_COUNTER_MASK + #define STAT_GENERIC_QSTATS_REQ_FLAGS_COUNTER_MASK 0x1UL u8 unused_0[5]; __le64 generic_stat_host_addr; }; @@ -10202,6 +10305,7 @@ struct fw_status_reg { #define FW_STATUS_REG_SHUTDOWN 0x100000UL #define FW_STATUS_REG_CRASHED_NO_MASTER 0x200000UL #define FW_STATUS_REG_RECOVERING 0x400000UL + #define FW_STATUS_REG_MANU_DEBUG_STATUS 0x800000UL }; /* hcomm_status (size:64b/8B) */ diff --git a/drivers/net/ethernet/broadcom/cnic.c b/drivers/net/ethernet/broadcom/cnic.c index e86503d97f32..2198e35d9e18 100644 --- a/drivers/net/ethernet/broadcom/cnic.c +++ b/drivers/net/ethernet/broadcom/cnic.c @@ -4105,8 +4105,7 @@ static int cnic_cm_alloc_mem(struct cnic_dev *dev) for (i = 0; i < MAX_CM_SK_TBL_SZ; i++) atomic_set(&cp->csk_tbl[i].ref_count, 0); - port_id = prandom_u32(); - port_id %= CNIC_LOCAL_PORT_RANGE; + port_id = prandom_u32_max(CNIC_LOCAL_PORT_RANGE); if (cnic_init_id_tbl(&cp->csk_port_tbl, CNIC_LOCAL_PORT_RANGE, CNIC_LOCAL_PORT_MIN, port_id)) { cnic_cm_free_mem(dev); @@ -4165,7 +4164,7 @@ static int cnic_cm_init_bnx2_hw(struct cnic_dev *dev) { u32 seed; - seed = prandom_u32(); + seed = get_random_u32(); cnic_ctx_wr(dev, 45, 0, seed); return 0; } diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 25c450606985..a8ce8d0cf9c4 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -1387,7 +1387,8 @@ static int bcmgenet_validate_flow(struct net_device *dev, struct ethtool_usrip4_spec *l4_mask; struct ethhdr *eth_mask; - if (cmd->fs.location >= MAX_NUM_OF_FS_RULES) { + if (cmd->fs.location >= MAX_NUM_OF_FS_RULES && + cmd->fs.location != RX_CLS_LOC_ANY) { netdev_err(dev, "rxnfc: Invalid location (%d)\n", cmd->fs.location); return -EINVAL; @@ -1452,7 +1453,7 @@ static int bcmgenet_insert_flow(struct net_device *dev, { struct bcmgenet_priv *priv = netdev_priv(dev); struct bcmgenet_rxnfc_rule *loc_rule; - int err; + int err, i; if (priv->hw_params->hfb_filter_size < 128) { netdev_err(dev, "rxnfc: Not supported by this device\n"); @@ -1470,7 +1471,29 @@ static int bcmgenet_insert_flow(struct net_device *dev, if (err) return err; - loc_rule = &priv->rxnfc_rules[cmd->fs.location]; + if (cmd->fs.location == RX_CLS_LOC_ANY) { + list_for_each_entry(loc_rule, &priv->rxnfc_list, list) { + cmd->fs.location = loc_rule->fs.location; + err = memcmp(&loc_rule->fs, &cmd->fs, + sizeof(struct ethtool_rx_flow_spec)); + if (!err) + /* rule exists so return current location */ + return 0; + } + for (i = 0; i < MAX_NUM_OF_FS_RULES; i++) { + loc_rule = &priv->rxnfc_rules[i]; + if (loc_rule->state == BCMGENET_RXNFC_STATE_UNUSED) { + cmd->fs.location = i; + break; + } + } + if (i == MAX_NUM_OF_FS_RULES) { + cmd->fs.location = RX_CLS_LOC_ANY; + return -ENOSPC; + } + } else { + loc_rule = &priv->rxnfc_rules[cmd->fs.location]; + } if (loc_rule->state == BCMGENET_RXNFC_STATE_ENABLED) bcmgenet_hfb_disable_filter(priv, cmd->fs.location); if (loc_rule->state != BCMGENET_RXNFC_STATE_UNUSED) { @@ -1583,7 +1606,7 @@ static int bcmgenet_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, break; case ETHTOOL_GRXCLSRLCNT: cmd->rule_cnt = bcmgenet_get_num_flows(priv); - cmd->data = MAX_NUM_OF_FS_RULES; + cmd->data = MAX_NUM_OF_FS_RULES | RX_CLS_LOC_SPECIAL; break; case ETHTOOL_GRXCLSRULE: err = bcmgenet_get_flow(dev, cmd, cmd->fs.location); diff --git a/drivers/net/ethernet/brocade/bna/bfa_msgq.c b/drivers/net/ethernet/brocade/bna/bfa_msgq.c index 47125f419530..fa40d5ec6f1c 100644 --- a/drivers/net/ethernet/brocade/bna/bfa_msgq.c +++ b/drivers/net/ethernet/brocade/bna/bfa_msgq.c @@ -202,7 +202,6 @@ static void __cmd_copy(struct bfa_msgq_cmdq *cmdq, struct bfa_msgq_cmd_entry *cmd) { size_t len = cmd->msg_size; - int num_entries = 0; size_t to_copy; u8 *src, *dst; @@ -219,7 +218,6 @@ __cmd_copy(struct bfa_msgq_cmdq *cmdq, struct bfa_msgq_cmd_entry *cmd) BFA_MSGQ_INDX_ADD(cmdq->producer_index, 1, cmdq->depth); dst = (u8 *)cmdq->addr.kva; dst += (cmdq->producer_index * BFI_MSGQ_CMD_ENTRY_SIZE); - num_entries++; } } diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index 51c9fd6f68a4..4f63f1ba3161 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -806,6 +806,7 @@ static int macb_mii_probe(struct net_device *dev) bp->phylink_config.dev = &dev->dev; bp->phylink_config.type = PHYLINK_NETDEV; + bp->phylink_config.mac_managed_pm = true; if (bp->phy_interface == PHY_INTERFACE_MODE_SGMII) { bp->phylink_config.poll_fixed_state = true; diff --git a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.c b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.c index f90bfba4b303..c2e7037c7ba1 100644 --- a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.c +++ b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.c @@ -1063,7 +1063,7 @@ static void chtls_pass_accept_rpl(struct sk_buff *skb, opt2 |= WND_SCALE_EN_V(WSCALE_OK(tp)); rpl5->opt0 = cpu_to_be64(opt0); rpl5->opt2 = cpu_to_be32(opt2); - rpl5->iss = cpu_to_be32((prandom_u32() & ~7UL) - 1); + rpl5->iss = cpu_to_be32((get_random_u32() & ~7UL) - 1); set_wr_txq(skb, CPL_PRIORITY_SETUP, csk->port_id); t4_set_arp_err_handler(skb, sk, chtls_accept_rpl_arp_failure); cxgb4_l2t_send(csk->egress_dev, skb, csk->l2t_entry); @@ -1466,7 +1466,7 @@ static void make_established(struct sock *sk, u32 snd_isn, unsigned int opt) tp->write_seq = snd_isn; tp->snd_nxt = snd_isn; tp->snd_una = snd_isn; - inet_sk(sk)->inet_id = prandom_u32(); + inet_sk(sk)->inet_id = get_random_u16(); assign_rxopt(sk, opt); if (tp->rcv_wnd > (RCV_BUFSIZ_M << 10)) diff --git a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_io.c b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_io.c index 539992dad8ba..a4256087ac82 100644 --- a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_io.c +++ b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_io.c @@ -919,8 +919,8 @@ static int csk_wait_memory(struct chtls_dev *cdev, current_timeo = *timeo_p; noblock = (*timeo_p ? false : true); if (csk_mem_free(cdev, sk)) { - current_timeo = (prandom_u32() % (HZ / 5)) + 2; - vm_wait = (prandom_u32() % (HZ / 5)) + 2; + current_timeo = prandom_u32_max(HZ / 5) + 2; + vm_wait = prandom_u32_max(HZ / 5) + 2; } add_wait_queue(sk_sleep(sk), &wait); diff --git a/drivers/net/ethernet/cisco/enic/enic.h b/drivers/net/ethernet/cisco/enic/enic.h index a0964b629ffc..300ad05ee05b 100644 --- a/drivers/net/ethernet/cisco/enic/enic.h +++ b/drivers/net/ethernet/cisco/enic/enic.h @@ -226,21 +226,6 @@ static inline unsigned int enic_cq_wq(struct enic *enic, unsigned int wq) return enic->rq_count + wq; } -static inline unsigned int enic_legacy_io_intr(void) -{ - return 0; -} - -static inline unsigned int enic_legacy_err_intr(void) -{ - return 1; -} - -static inline unsigned int enic_legacy_notify_intr(void) -{ - return 2; -} - static inline unsigned int enic_msix_rq_intr(struct enic *enic, unsigned int rq) { @@ -258,6 +243,10 @@ static inline unsigned int enic_msix_err_intr(struct enic *enic) return enic->rq_count + enic->wq_count; } +#define ENIC_LEGACY_IO_INTR 0 +#define ENIC_LEGACY_ERR_INTR 1 +#define ENIC_LEGACY_NOTIFY_INTR 2 + static inline unsigned int enic_msix_notify_intr(struct enic *enic) { return enic->rq_count + enic->wq_count + 1; @@ -267,7 +256,7 @@ static inline bool enic_is_err_intr(struct enic *enic, int intr) { switch (vnic_dev_get_intr_mode(enic->vdev)) { case VNIC_DEV_INTR_MODE_INTX: - return intr == enic_legacy_err_intr(); + return intr == ENIC_LEGACY_ERR_INTR; case VNIC_DEV_INTR_MODE_MSIX: return intr == enic_msix_err_intr(enic); case VNIC_DEV_INTR_MODE_MSI: @@ -280,7 +269,7 @@ static inline bool enic_is_notify_intr(struct enic *enic, int intr) { switch (vnic_dev_get_intr_mode(enic->vdev)) { case VNIC_DEV_INTR_MODE_INTX: - return intr == enic_legacy_notify_intr(); + return intr == ENIC_LEGACY_NOTIFY_INTR; case VNIC_DEV_INTR_MODE_MSIX: return intr == enic_msix_notify_intr(enic); case VNIC_DEV_INTR_MODE_MSI: diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c index 29500d32e362..37bd38d772e8 100644 --- a/drivers/net/ethernet/cisco/enic/enic_main.c +++ b/drivers/net/ethernet/cisco/enic/enic_main.c @@ -448,9 +448,9 @@ static irqreturn_t enic_isr_legacy(int irq, void *data) { struct net_device *netdev = data; struct enic *enic = netdev_priv(netdev); - unsigned int io_intr = enic_legacy_io_intr(); - unsigned int err_intr = enic_legacy_err_intr(); - unsigned int notify_intr = enic_legacy_notify_intr(); + unsigned int io_intr = ENIC_LEGACY_IO_INTR; + unsigned int err_intr = ENIC_LEGACY_ERR_INTR; + unsigned int notify_intr = ENIC_LEGACY_NOTIFY_INTR; u32 pba; vnic_intr_mask(&enic->intr[io_intr]); @@ -1507,7 +1507,7 @@ static int enic_poll(struct napi_struct *napi, int budget) struct enic *enic = netdev_priv(netdev); unsigned int cq_rq = enic_cq_rq(enic, 0); unsigned int cq_wq = enic_cq_wq(enic, 0); - unsigned int intr = enic_legacy_io_intr(); + unsigned int intr = ENIC_LEGACY_IO_INTR; unsigned int rq_work_to_do = budget; unsigned int wq_work_to_do = ENIC_WQ_NAPI_BUDGET; unsigned int work_done, rq_work_done = 0, wq_work_done; @@ -1856,8 +1856,7 @@ static int enic_dev_notify_set(struct enic *enic) spin_lock_bh(&enic->devcmd_lock); switch (vnic_dev_get_intr_mode(enic->vdev)) { case VNIC_DEV_INTR_MODE_INTX: - err = vnic_dev_notify_set(enic->vdev, - enic_legacy_notify_intr()); + err = vnic_dev_notify_set(enic->vdev, ENIC_LEGACY_NOTIFY_INTR); break; case VNIC_DEV_INTR_MODE_MSIX: err = vnic_dev_notify_set(enic->vdev, diff --git a/drivers/net/ethernet/dlink/dl2k.c b/drivers/net/ethernet/dlink/dl2k.c index 2c67a857a42f..db6615aa921b 100644 --- a/drivers/net/ethernet/dlink/dl2k.c +++ b/drivers/net/ethernet/dlink/dl2k.c @@ -814,7 +814,6 @@ rio_free_tx (struct net_device *dev, int irq) { struct netdev_private *np = netdev_priv(dev); int entry = np->old_tx % TX_RING_SIZE; - int tx_use = 0; unsigned long flag = 0; if (irq) @@ -839,7 +838,6 @@ rio_free_tx (struct net_device *dev, int irq) np->tx_skbuff[entry] = NULL; entry = (entry + 1) % TX_RING_SIZE; - tx_use++; } if (irq) spin_unlock(&np->tx_lock); diff --git a/drivers/net/ethernet/fealnx.c b/drivers/net/ethernet/fealnx.c deleted file mode 100644 index ed18450fd2cc..000000000000 --- a/drivers/net/ethernet/fealnx.c +++ /dev/null @@ -1,1953 +0,0 @@ -/* - Written 1998-2000 by Donald Becker. - - This software may be used and distributed according to the terms of - the GNU General Public License (GPL), incorporated herein by reference. - Drivers based on or derived from this code fall under the GPL and must - retain the authorship, copyright and license notice. This file is not - a complete program and may only be used when the entire operating - system is licensed under the GPL. - - The author may be reached as becker@scyld.com, or C/O - Scyld Computing Corporation - 410 Severn Ave., Suite 210 - Annapolis MD 21403 - - Support information and updates available at - http://www.scyld.com/network/pci-skeleton.html - - Linux kernel updates: - - Version 2.51, Nov 17, 2001 (jgarzik): - - Add ethtool support - - Replace some MII-related magic numbers with constants - -*/ - -#define DRV_NAME "fealnx" - -static int debug; /* 1-> print debug message */ -static int max_interrupt_work = 20; - -/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). */ -static int multicast_filter_limit = 32; - -/* Set the copy breakpoint for the copy-only-tiny-frames scheme. */ -/* Setting to > 1518 effectively disables this feature. */ -static int rx_copybreak; - -/* Used to pass the media type, etc. */ -/* Both 'options[]' and 'full_duplex[]' should exist for driver */ -/* interoperability. */ -/* The media type is usually passed in 'options[]'. */ -#define MAX_UNITS 8 /* More are supported, limit only on options */ -static int options[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 }; -static int full_duplex[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 }; - -/* Operational parameters that are set at compile time. */ -/* Keep the ring sizes a power of two for compile efficiency. */ -/* The compiler will convert <unsigned>'%'<2^N> into a bit mask. */ -/* Making the Tx ring too large decreases the effectiveness of channel */ -/* bonding and packet priority. */ -/* There are no ill effects from too-large receive rings. */ -// 88-12-9 modify, -// #define TX_RING_SIZE 16 -// #define RX_RING_SIZE 32 -#define TX_RING_SIZE 6 -#define RX_RING_SIZE 12 -#define TX_TOTAL_SIZE TX_RING_SIZE*sizeof(struct fealnx_desc) -#define RX_TOTAL_SIZE RX_RING_SIZE*sizeof(struct fealnx_desc) - -/* Operational parameters that usually are not changed. */ -/* Time in jiffies before concluding the transmitter is hung. */ -#define TX_TIMEOUT (2*HZ) - -#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */ - - -/* Include files, designed to support most kernel versions 2.0.0 and later. */ -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/timer.h> -#include <linux/errno.h> -#include <linux/ioport.h> -#include <linux/interrupt.h> -#include <linux/pci.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> -#include <linux/init.h> -#include <linux/mii.h> -#include <linux/ethtool.h> -#include <linux/crc32.h> -#include <linux/delay.h> -#include <linux/bitops.h> - -#include <asm/processor.h> /* Processor type for cache alignment. */ -#include <asm/io.h> -#include <linux/uaccess.h> -#include <asm/byteorder.h> - -/* This driver was written to use PCI memory space, however some x86 systems - work only with I/O space accesses. */ -#ifndef __alpha__ -#define USE_IO_OPS -#endif - -/* Kernel compatibility defines, some common to David Hinds' PCMCIA package. */ -/* This is only in the support-all-kernels source code. */ - -#define RUN_AT(x) (jiffies + (x)) - -MODULE_AUTHOR("Myson or whoever"); -MODULE_DESCRIPTION("Myson MTD-8xx 100/10M Ethernet PCI Adapter Driver"); -MODULE_LICENSE("GPL"); -module_param(max_interrupt_work, int, 0); -module_param(debug, int, 0); -module_param(rx_copybreak, int, 0); -module_param(multicast_filter_limit, int, 0); -module_param_array(options, int, NULL, 0); -module_param_array(full_duplex, int, NULL, 0); -MODULE_PARM_DESC(max_interrupt_work, "fealnx maximum events handled per interrupt"); -MODULE_PARM_DESC(debug, "fealnx enable debugging (0-1)"); -MODULE_PARM_DESC(rx_copybreak, "fealnx copy breakpoint for copy-only-tiny-frames"); -MODULE_PARM_DESC(multicast_filter_limit, "fealnx maximum number of filtered multicast addresses"); -MODULE_PARM_DESC(options, "fealnx: Bits 0-3: media type, bit 17: full duplex"); -MODULE_PARM_DESC(full_duplex, "fealnx full duplex setting(s) (1)"); - -enum { - MIN_REGION_SIZE = 136, -}; - -/* A chip capabilities table, matching the entries in pci_tbl[] above. */ -enum chip_capability_flags { - HAS_MII_XCVR, - HAS_CHIP_XCVR, -}; - -/* 89/6/13 add, */ -/* for different PHY */ -enum phy_type_flags { - MysonPHY = 1, - AhdocPHY = 2, - SeeqPHY = 3, - MarvellPHY = 4, - Myson981 = 5, - LevelOnePHY = 6, - OtherPHY = 10, -}; - -struct chip_info { - char *chip_name; - int flags; -}; - -static const struct chip_info skel_netdrv_tbl[] = { - { "100/10M Ethernet PCI Adapter", HAS_MII_XCVR }, - { "100/10M Ethernet PCI Adapter", HAS_CHIP_XCVR }, - { "1000/100/10M Ethernet PCI Adapter", HAS_MII_XCVR }, -}; - -/* Offsets to the Command and Status Registers. */ -enum fealnx_offsets { - PAR0 = 0x0, /* physical address 0-3 */ - PAR1 = 0x04, /* physical address 4-5 */ - MAR0 = 0x08, /* multicast address 0-3 */ - MAR1 = 0x0C, /* multicast address 4-7 */ - FAR0 = 0x10, /* flow-control address 0-3 */ - FAR1 = 0x14, /* flow-control address 4-5 */ - TCRRCR = 0x18, /* receive & transmit configuration */ - BCR = 0x1C, /* bus command */ - TXPDR = 0x20, /* transmit polling demand */ - RXPDR = 0x24, /* receive polling demand */ - RXCWP = 0x28, /* receive current word pointer */ - TXLBA = 0x2C, /* transmit list base address */ - RXLBA = 0x30, /* receive list base address */ - ISR = 0x34, /* interrupt status */ - IMR = 0x38, /* interrupt mask */ - FTH = 0x3C, /* flow control high/low threshold */ - MANAGEMENT = 0x40, /* bootrom/eeprom and mii management */ - TALLY = 0x44, /* tally counters for crc and mpa */ - TSR = 0x48, /* tally counter for transmit status */ - BMCRSR = 0x4c, /* basic mode control and status */ - PHYIDENTIFIER = 0x50, /* phy identifier */ - ANARANLPAR = 0x54, /* auto-negotiation advertisement and link - partner ability */ - ANEROCR = 0x58, /* auto-negotiation expansion and pci conf. */ - BPREMRPSR = 0x5c, /* bypass & receive error mask and phy status */ -}; - -/* Bits in the interrupt status/enable registers. */ -/* The bits in the Intr Status/Enable registers, mostly interrupt sources. */ -enum intr_status_bits { - RFCON = 0x00020000, /* receive flow control xon packet */ - RFCOFF = 0x00010000, /* receive flow control xoff packet */ - LSCStatus = 0x00008000, /* link status change */ - ANCStatus = 0x00004000, /* autonegotiation completed */ - FBE = 0x00002000, /* fatal bus error */ - FBEMask = 0x00001800, /* mask bit12-11 */ - ParityErr = 0x00000000, /* parity error */ - TargetErr = 0x00001000, /* target abort */ - MasterErr = 0x00000800, /* master error */ - TUNF = 0x00000400, /* transmit underflow */ - ROVF = 0x00000200, /* receive overflow */ - ETI = 0x00000100, /* transmit early int */ - ERI = 0x00000080, /* receive early int */ - CNTOVF = 0x00000040, /* counter overflow */ - RBU = 0x00000020, /* receive buffer unavailable */ - TBU = 0x00000010, /* transmit buffer unavilable */ - TI = 0x00000008, /* transmit interrupt */ - RI = 0x00000004, /* receive interrupt */ - RxErr = 0x00000002, /* receive error */ -}; - -/* Bits in the NetworkConfig register, W for writing, R for reading */ -/* FIXME: some names are invented by me. Marked with (name?) */ -/* If you have docs and know bit names, please fix 'em */ -enum rx_mode_bits { - CR_W_ENH = 0x02000000, /* enhanced mode (name?) */ - CR_W_FD = 0x00100000, /* full duplex */ - CR_W_PS10 = 0x00080000, /* 10 mbit */ - CR_W_TXEN = 0x00040000, /* tx enable (name?) */ - CR_W_PS1000 = 0x00010000, /* 1000 mbit */ - /* CR_W_RXBURSTMASK= 0x00000e00, Im unsure about this */ - CR_W_RXMODEMASK = 0x000000e0, - CR_W_PROM = 0x00000080, /* promiscuous mode */ - CR_W_AB = 0x00000040, /* accept broadcast */ - CR_W_AM = 0x00000020, /* accept mutlicast */ - CR_W_ARP = 0x00000008, /* receive runt pkt */ - CR_W_ALP = 0x00000004, /* receive long pkt */ - CR_W_SEP = 0x00000002, /* receive error pkt */ - CR_W_RXEN = 0x00000001, /* rx enable (unicast?) (name?) */ - - CR_R_TXSTOP = 0x04000000, /* tx stopped (name?) */ - CR_R_FD = 0x00100000, /* full duplex detected */ - CR_R_PS10 = 0x00080000, /* 10 mbit detected */ - CR_R_RXSTOP = 0x00008000, /* rx stopped (name?) */ -}; - -/* The Tulip Rx and Tx buffer descriptors. */ -struct fealnx_desc { - s32 status; - s32 control; - u32 buffer; - u32 next_desc; - struct fealnx_desc *next_desc_logical; - struct sk_buff *skbuff; - u32 reserved1; - u32 reserved2; -}; - -/* Bits in network_desc.status */ -enum rx_desc_status_bits { - RXOWN = 0x80000000, /* own bit */ - FLNGMASK = 0x0fff0000, /* frame length */ - FLNGShift = 16, - MARSTATUS = 0x00004000, /* multicast address received */ - BARSTATUS = 0x00002000, /* broadcast address received */ - PHYSTATUS = 0x00001000, /* physical address received */ - RXFSD = 0x00000800, /* first descriptor */ - RXLSD = 0x00000400, /* last descriptor */ - ErrorSummary = 0x80, /* error summary */ - RUNTPKT = 0x40, /* runt packet received */ - LONGPKT = 0x20, /* long packet received */ - FAE = 0x10, /* frame align error */ - CRC = 0x08, /* crc error */ - RXER = 0x04, /* receive error */ -}; - -enum rx_desc_control_bits { - RXIC = 0x00800000, /* interrupt control */ - RBSShift = 0, -}; - -enum tx_desc_status_bits { - TXOWN = 0x80000000, /* own bit */ - JABTO = 0x00004000, /* jabber timeout */ - CSL = 0x00002000, /* carrier sense lost */ - LC = 0x00001000, /* late collision */ - EC = 0x00000800, /* excessive collision */ - UDF = 0x00000400, /* fifo underflow */ - DFR = 0x00000200, /* deferred */ - HF = 0x00000100, /* heartbeat fail */ - NCRMask = 0x000000ff, /* collision retry count */ - NCRShift = 0, -}; - -enum tx_desc_control_bits { - TXIC = 0x80000000, /* interrupt control */ - ETIControl = 0x40000000, /* early transmit interrupt */ - TXLD = 0x20000000, /* last descriptor */ - TXFD = 0x10000000, /* first descriptor */ - CRCEnable = 0x08000000, /* crc control */ - PADEnable = 0x04000000, /* padding control */ - RetryTxLC = 0x02000000, /* retry late collision */ - PKTSMask = 0x3ff800, /* packet size bit21-11 */ - PKTSShift = 11, - TBSMask = 0x000007ff, /* transmit buffer bit 10-0 */ - TBSShift = 0, -}; - -/* BootROM/EEPROM/MII Management Register */ -#define MASK_MIIR_MII_READ 0x00000000 -#define MASK_MIIR_MII_WRITE 0x00000008 -#define MASK_MIIR_MII_MDO 0x00000004 -#define MASK_MIIR_MII_MDI 0x00000002 -#define MASK_MIIR_MII_MDC 0x00000001 - -/* ST+OP+PHYAD+REGAD+TA */ -#define OP_READ 0x6000 /* ST:01+OP:10+PHYAD+REGAD+TA:Z0 */ -#define OP_WRITE 0x5002 /* ST:01+OP:01+PHYAD+REGAD+TA:10 */ - -/* ------------------------------------------------------------------------- */ -/* Constants for Myson PHY */ -/* ------------------------------------------------------------------------- */ -#define MysonPHYID 0xd0000302 -/* 89-7-27 add, (begin) */ -#define MysonPHYID0 0x0302 -#define StatusRegister 18 -#define SPEED100 0x0400 // bit10 -#define FULLMODE 0x0800 // bit11 -/* 89-7-27 add, (end) */ - -/* ------------------------------------------------------------------------- */ -/* Constants for Seeq 80225 PHY */ -/* ------------------------------------------------------------------------- */ -#define SeeqPHYID0 0x0016 - -#define MIIRegister18 18 -#define SPD_DET_100 0x80 -#define DPLX_DET_FULL 0x40 - -/* ------------------------------------------------------------------------- */ -/* Constants for Ahdoc 101 PHY */ -/* ------------------------------------------------------------------------- */ -#define AhdocPHYID0 0x0022 - -#define DiagnosticReg 18 -#define DPLX_FULL 0x0800 -#define Speed_100 0x0400 - -/* 89/6/13 add, */ -/* -------------------------------------------------------------------------- */ -/* Constants */ -/* -------------------------------------------------------------------------- */ -#define MarvellPHYID0 0x0141 -#define LevelOnePHYID0 0x0013 - -#define MII1000BaseTControlReg 9 -#define MII1000BaseTStatusReg 10 -#define SpecificReg 17 - -/* for 1000BaseT Control Register */ -#define PHYAbletoPerform1000FullDuplex 0x0200 -#define PHYAbletoPerform1000HalfDuplex 0x0100 -#define PHY1000AbilityMask 0x300 - -// for phy specific status register, marvell phy. -#define SpeedMask 0x0c000 -#define Speed_1000M 0x08000 -#define Speed_100M 0x4000 -#define Speed_10M 0 -#define Full_Duplex 0x2000 - -// 89/12/29 add, for phy specific status register, levelone phy, (begin) -#define LXT1000_100M 0x08000 -#define LXT1000_1000M 0x0c000 -#define LXT1000_Full 0x200 -// 89/12/29 add, for phy specific status register, levelone phy, (end) - -/* for 3-in-1 case, BMCRSR register */ -#define LinkIsUp2 0x00040000 - -/* for PHY */ -#define LinkIsUp 0x0004 - - -struct netdev_private { - /* Descriptor rings first for alignment. */ - struct fealnx_desc *rx_ring; - struct fealnx_desc *tx_ring; - - dma_addr_t rx_ring_dma; - dma_addr_t tx_ring_dma; - - spinlock_t lock; - - /* Media monitoring timer. */ - struct timer_list timer; - - /* Reset timer */ - struct timer_list reset_timer; - int reset_timer_armed; - unsigned long crvalue_sv; - unsigned long imrvalue_sv; - - /* Frequently used values: keep some adjacent for cache effect. */ - int flags; - struct pci_dev *pci_dev; - unsigned long crvalue; - unsigned long bcrvalue; - unsigned long imrvalue; - struct fealnx_desc *cur_rx; - struct fealnx_desc *lack_rxbuf; - int really_rx_count; - struct fealnx_desc *cur_tx; - struct fealnx_desc *cur_tx_copy; - int really_tx_count; - int free_tx_count; - unsigned int rx_buf_sz; /* Based on MTU+slack. */ - - /* These values are keep track of the transceiver/media in use. */ - unsigned int linkok; - unsigned int line_speed; - unsigned int duplexmode; - unsigned int default_port:4; /* Last dev->if_port value. */ - unsigned int PHYType; - - /* MII transceiver section. */ - int mii_cnt; /* MII device addresses. */ - unsigned char phys[2]; /* MII device addresses. */ - struct mii_if_info mii; - void __iomem *mem; -}; - - -static int mdio_read(struct net_device *dev, int phy_id, int location); -static void mdio_write(struct net_device *dev, int phy_id, int location, int value); -static int netdev_open(struct net_device *dev); -static void getlinktype(struct net_device *dev); -static void getlinkstatus(struct net_device *dev); -static void netdev_timer(struct timer_list *t); -static void reset_timer(struct timer_list *t); -static void fealnx_tx_timeout(struct net_device *dev, unsigned int txqueue); -static void init_ring(struct net_device *dev); -static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t intr_handler(int irq, void *dev_instance); -static int netdev_rx(struct net_device *dev); -static void set_rx_mode(struct net_device *dev); -static void __set_rx_mode(struct net_device *dev); -static struct net_device_stats *get_stats(struct net_device *dev); -static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static const struct ethtool_ops netdev_ethtool_ops; -static int netdev_close(struct net_device *dev); -static void reset_rx_descriptors(struct net_device *dev); -static void reset_tx_descriptors(struct net_device *dev); - -static void stop_nic_rx(void __iomem *ioaddr, long crvalue) -{ - int delay = 0x1000; - iowrite32(crvalue & ~(CR_W_RXEN), ioaddr + TCRRCR); - while (--delay) { - if ( (ioread32(ioaddr + TCRRCR) & CR_R_RXSTOP) == CR_R_RXSTOP) - break; - } -} - - -static void stop_nic_rxtx(void __iomem *ioaddr, long crvalue) -{ - int delay = 0x1000; - iowrite32(crvalue & ~(CR_W_RXEN+CR_W_TXEN), ioaddr + TCRRCR); - while (--delay) { - if ( (ioread32(ioaddr + TCRRCR) & (CR_R_RXSTOP+CR_R_TXSTOP)) - == (CR_R_RXSTOP+CR_R_TXSTOP) ) - break; - } -} - -static const struct net_device_ops netdev_ops = { - .ndo_open = netdev_open, - .ndo_stop = netdev_close, - .ndo_start_xmit = start_tx, - .ndo_get_stats = get_stats, - .ndo_set_rx_mode = set_rx_mode, - .ndo_eth_ioctl = mii_ioctl, - .ndo_tx_timeout = fealnx_tx_timeout, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, -}; - -static int fealnx_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct netdev_private *np; - int i, option, err, irq; - static int card_idx = -1; - char boardname[12]; - void __iomem *ioaddr; - unsigned long len; - unsigned int chip_id = ent->driver_data; - struct net_device *dev; - void *ring_space; - dma_addr_t ring_dma; - u8 addr[ETH_ALEN]; -#ifdef USE_IO_OPS - int bar = 0; -#else - int bar = 1; -#endif - - card_idx++; - sprintf(boardname, "fealnx%d", card_idx); - - option = card_idx < MAX_UNITS ? options[card_idx] : 0; - - i = pci_enable_device(pdev); - if (i) return i; - pci_set_master(pdev); - - len = pci_resource_len(pdev, bar); - if (len < MIN_REGION_SIZE) { - dev_err(&pdev->dev, - "region size %ld too small, aborting\n", len); - return -ENODEV; - } - - i = pci_request_regions(pdev, boardname); - if (i) - return i; - - irq = pdev->irq; - - ioaddr = pci_iomap(pdev, bar, len); - if (!ioaddr) { - err = -ENOMEM; - goto err_out_res; - } - - dev = alloc_etherdev(sizeof(struct netdev_private)); - if (!dev) { - err = -ENOMEM; - goto err_out_unmap; - } - SET_NETDEV_DEV(dev, &pdev->dev); - - /* read ethernet id */ - for (i = 0; i < 6; ++i) - addr[i] = ioread8(ioaddr + PAR0 + i); - eth_hw_addr_set(dev, addr); - - /* Reset the chip to erase previous misconfiguration. */ - iowrite32(0x00000001, ioaddr + BCR); - - /* Make certain the descriptor lists are aligned. */ - np = netdev_priv(dev); - np->mem = ioaddr; - spin_lock_init(&np->lock); - np->pci_dev = pdev; - np->flags = skel_netdrv_tbl[chip_id].flags; - pci_set_drvdata(pdev, dev); - np->mii.dev = dev; - np->mii.mdio_read = mdio_read; - np->mii.mdio_write = mdio_write; - np->mii.phy_id_mask = 0x1f; - np->mii.reg_num_mask = 0x1f; - - ring_space = dma_alloc_coherent(&pdev->dev, RX_TOTAL_SIZE, &ring_dma, - GFP_KERNEL); - if (!ring_space) { - err = -ENOMEM; - goto err_out_free_dev; - } - np->rx_ring = ring_space; - np->rx_ring_dma = ring_dma; - - ring_space = dma_alloc_coherent(&pdev->dev, TX_TOTAL_SIZE, &ring_dma, - GFP_KERNEL); - if (!ring_space) { - err = -ENOMEM; - goto err_out_free_rx; - } - np->tx_ring = ring_space; - np->tx_ring_dma = ring_dma; - - /* find the connected MII xcvrs */ - if (np->flags == HAS_MII_XCVR) { - int phy, phy_idx = 0; - - for (phy = 1; phy < 32 && phy_idx < ARRAY_SIZE(np->phys); - phy++) { - int mii_status = mdio_read(dev, phy, 1); - - if (mii_status != 0xffff && mii_status != 0x0000) { - np->phys[phy_idx++] = phy; - dev_info(&pdev->dev, - "MII PHY found at address %d, status " - "0x%4.4x.\n", phy, mii_status); - /* get phy type */ - { - unsigned int data; - - data = mdio_read(dev, np->phys[0], 2); - if (data == SeeqPHYID0) - np->PHYType = SeeqPHY; - else if (data == AhdocPHYID0) - np->PHYType = AhdocPHY; - else if (data == MarvellPHYID0) - np->PHYType = MarvellPHY; - else if (data == MysonPHYID0) - np->PHYType = Myson981; - else if (data == LevelOnePHYID0) - np->PHYType = LevelOnePHY; - else - np->PHYType = OtherPHY; - } - } - } - - np->mii_cnt = phy_idx; - if (phy_idx == 0) - dev_warn(&pdev->dev, - "MII PHY not found -- this device may " - "not operate correctly.\n"); - } else { - np->phys[0] = 32; -/* 89/6/23 add, (begin) */ - /* get phy type */ - if (ioread32(ioaddr + PHYIDENTIFIER) == MysonPHYID) - np->PHYType = MysonPHY; - else - np->PHYType = OtherPHY; - } - np->mii.phy_id = np->phys[0]; - - if (dev->mem_start) - option = dev->mem_start; - - /* The lower four bits are the media type. */ - if (option > 0) { - if (option & 0x200) - np->mii.full_duplex = 1; - np->default_port = option & 15; - } - - if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0) - np->mii.full_duplex = full_duplex[card_idx]; - - if (np->mii.full_duplex) { - dev_info(&pdev->dev, "Media type forced to Full Duplex.\n"); -/* 89/6/13 add, (begin) */ -// if (np->PHYType==MarvellPHY) - if ((np->PHYType == MarvellPHY) || (np->PHYType == LevelOnePHY)) { - unsigned int data; - - data = mdio_read(dev, np->phys[0], 9); - data = (data & 0xfcff) | 0x0200; - mdio_write(dev, np->phys[0], 9, data); - } -/* 89/6/13 add, (end) */ - if (np->flags == HAS_MII_XCVR) - mdio_write(dev, np->phys[0], MII_ADVERTISE, ADVERTISE_FULL); - else - iowrite32(ADVERTISE_FULL, ioaddr + ANARANLPAR); - np->mii.force_media = 1; - } - - dev->netdev_ops = &netdev_ops; - dev->ethtool_ops = &netdev_ethtool_ops; - dev->watchdog_timeo = TX_TIMEOUT; - - err = register_netdev(dev); - if (err) - goto err_out_free_tx; - - printk(KERN_INFO "%s: %s at %p, %pM, IRQ %d.\n", - dev->name, skel_netdrv_tbl[chip_id].chip_name, ioaddr, - dev->dev_addr, irq); - - return 0; - -err_out_free_tx: - dma_free_coherent(&pdev->dev, TX_TOTAL_SIZE, np->tx_ring, - np->tx_ring_dma); -err_out_free_rx: - dma_free_coherent(&pdev->dev, RX_TOTAL_SIZE, np->rx_ring, - np->rx_ring_dma); -err_out_free_dev: - free_netdev(dev); -err_out_unmap: - pci_iounmap(pdev, ioaddr); -err_out_res: - pci_release_regions(pdev); - return err; -} - - -static void fealnx_remove_one(struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - - if (dev) { - struct netdev_private *np = netdev_priv(dev); - - dma_free_coherent(&pdev->dev, TX_TOTAL_SIZE, np->tx_ring, - np->tx_ring_dma); - dma_free_coherent(&pdev->dev, RX_TOTAL_SIZE, np->rx_ring, - np->rx_ring_dma); - unregister_netdev(dev); - pci_iounmap(pdev, np->mem); - free_netdev(dev); - pci_release_regions(pdev); - } else - printk(KERN_ERR "fealnx: remove for unknown device\n"); -} - - -static ulong m80x_send_cmd_to_phy(void __iomem *miiport, int opcode, int phyad, int regad) -{ - ulong miir; - int i; - unsigned int mask, data; - - /* enable MII output */ - miir = (ulong) ioread32(miiport); - miir &= 0xfffffff0; - - miir |= MASK_MIIR_MII_WRITE + MASK_MIIR_MII_MDO; - - /* send 32 1's preamble */ - for (i = 0; i < 32; i++) { - /* low MDC; MDO is already high (miir) */ - miir &= ~MASK_MIIR_MII_MDC; - iowrite32(miir, miiport); - - /* high MDC */ - miir |= MASK_MIIR_MII_MDC; - iowrite32(miir, miiport); - } - - /* calculate ST+OP+PHYAD+REGAD+TA */ - data = opcode | (phyad << 7) | (regad << 2); - - /* sent out */ - mask = 0x8000; - while (mask) { - /* low MDC, prepare MDO */ - miir &= ~(MASK_MIIR_MII_MDC + MASK_MIIR_MII_MDO); - if (mask & data) - miir |= MASK_MIIR_MII_MDO; - - iowrite32(miir, miiport); - /* high MDC */ - miir |= MASK_MIIR_MII_MDC; - iowrite32(miir, miiport); - udelay(30); - - /* next */ - mask >>= 1; - if (mask == 0x2 && opcode == OP_READ) - miir &= ~MASK_MIIR_MII_WRITE; - } - return miir; -} - - -static int mdio_read(struct net_device *dev, int phyad, int regad) -{ - struct netdev_private *np = netdev_priv(dev); - void __iomem *miiport = np->mem + MANAGEMENT; - ulong miir; - unsigned int mask, data; - - miir = m80x_send_cmd_to_phy(miiport, OP_READ, phyad, regad); - - /* read data */ - mask = 0x8000; - data = 0; - while (mask) { - /* low MDC */ - miir &= ~MASK_MIIR_MII_MDC; - iowrite32(miir, miiport); - - /* read MDI */ - miir = ioread32(miiport); - if (miir & MASK_MIIR_MII_MDI) - data |= mask; - - /* high MDC, and wait */ - miir |= MASK_MIIR_MII_MDC; - iowrite32(miir, miiport); - udelay(30); - - /* next */ - mask >>= 1; - } - - /* low MDC */ - miir &= ~MASK_MIIR_MII_MDC; - iowrite32(miir, miiport); - - return data & 0xffff; -} - - -static void mdio_write(struct net_device *dev, int phyad, int regad, int data) -{ - struct netdev_private *np = netdev_priv(dev); - void __iomem *miiport = np->mem + MANAGEMENT; - ulong miir; - unsigned int mask; - - miir = m80x_send_cmd_to_phy(miiport, OP_WRITE, phyad, regad); - - /* write data */ - mask = 0x8000; - while (mask) { - /* low MDC, prepare MDO */ - miir &= ~(MASK_MIIR_MII_MDC + MASK_MIIR_MII_MDO); - if (mask & data) - miir |= MASK_MIIR_MII_MDO; - iowrite32(miir, miiport); - - /* high MDC */ - miir |= MASK_MIIR_MII_MDC; - iowrite32(miir, miiport); - - /* next */ - mask >>= 1; - } - - /* low MDC */ - miir &= ~MASK_MIIR_MII_MDC; - iowrite32(miir, miiport); -} - - -static int netdev_open(struct net_device *dev) -{ - struct netdev_private *np = netdev_priv(dev); - void __iomem *ioaddr = np->mem; - const int irq = np->pci_dev->irq; - int rc, i; - - iowrite32(0x00000001, ioaddr + BCR); /* Reset */ - - rc = request_irq(irq, intr_handler, IRQF_SHARED, dev->name, dev); - if (rc) - return -EAGAIN; - - for (i = 0; i < 3; i++) - iowrite16(((const unsigned short *)dev->dev_addr)[i], - ioaddr + PAR0 + i*2); - - init_ring(dev); - - iowrite32(np->rx_ring_dma, ioaddr + RXLBA); - iowrite32(np->tx_ring_dma, ioaddr + TXLBA); - - /* Initialize other registers. */ - /* Configure the PCI bus bursts and FIFO thresholds. - 486: Set 8 longword burst. - 586: no burst limit. - Burst length 5:3 - 0 0 0 1 - 0 0 1 4 - 0 1 0 8 - 0 1 1 16 - 1 0 0 32 - 1 0 1 64 - 1 1 0 128 - 1 1 1 256 - Wait the specified 50 PCI cycles after a reset by initializing - Tx and Rx queues and the address filter list. - FIXME (Ueimor): optimistic for alpha + posted writes ? */ - - np->bcrvalue = 0x10; /* little-endian, 8 burst length */ -#ifdef __BIG_ENDIAN - np->bcrvalue |= 0x04; /* big-endian */ -#endif - -#if defined(__i386__) && !defined(MODULE) && !defined(CONFIG_UML) - if (boot_cpu_data.x86 <= 4) - np->crvalue = 0xa00; - else -#endif - np->crvalue = 0xe00; /* rx 128 burst length */ - - -// 89/12/29 add, -// 90/1/16 modify, -// np->imrvalue=FBE|TUNF|CNTOVF|RBU|TI|RI; - np->imrvalue = TUNF | CNTOVF | RBU | TI | RI; - if (np->pci_dev->device == 0x891) { - np->bcrvalue |= 0x200; /* set PROG bit */ - np->crvalue |= CR_W_ENH; /* set enhanced bit */ - np->imrvalue |= ETI; - } - iowrite32(np->bcrvalue, ioaddr + BCR); - - if (dev->if_port == 0) - dev->if_port = np->default_port; - - iowrite32(0, ioaddr + RXPDR); -// 89/9/1 modify, -// np->crvalue = 0x00e40001; /* tx store and forward, tx/rx enable */ - np->crvalue |= 0x00e40001; /* tx store and forward, tx/rx enable */ - np->mii.full_duplex = np->mii.force_media; - getlinkstatus(dev); - if (np->linkok) - getlinktype(dev); - __set_rx_mode(dev); - - netif_start_queue(dev); - - /* Clear and Enable interrupts by setting the interrupt mask. */ - iowrite32(FBE | TUNF | CNTOVF | RBU | TI | RI, ioaddr + ISR); - iowrite32(np->imrvalue, ioaddr + IMR); - - if (debug) - printk(KERN_DEBUG "%s: Done netdev_open().\n", dev->name); - - /* Set the timer to check for link beat. */ - timer_setup(&np->timer, netdev_timer, 0); - np->timer.expires = RUN_AT(3 * HZ); - - /* timer handler */ - add_timer(&np->timer); - - timer_setup(&np->reset_timer, reset_timer, 0); - np->reset_timer_armed = 0; - return rc; -} - - -static void getlinkstatus(struct net_device *dev) -/* function: Routine will read MII Status Register to get link status. */ -/* input : dev... pointer to the adapter block. */ -/* output : none. */ -{ - struct netdev_private *np = netdev_priv(dev); - unsigned int i, DelayTime = 0x1000; - - np->linkok = 0; - - if (np->PHYType == MysonPHY) { - for (i = 0; i < DelayTime; ++i) { - if (ioread32(np->mem + BMCRSR) & LinkIsUp2) { - np->linkok = 1; - return; - } - udelay(100); - } - } else { - for (i = 0; i < DelayTime; ++i) { - if (mdio_read(dev, np->phys[0], MII_BMSR) & BMSR_LSTATUS) { - np->linkok = 1; - return; - } - udelay(100); - } - } -} - - -static void getlinktype(struct net_device *dev) -{ - struct netdev_private *np = netdev_priv(dev); - - if (np->PHYType == MysonPHY) { /* 3-in-1 case */ - if (ioread32(np->mem + TCRRCR) & CR_R_FD) - np->duplexmode = 2; /* full duplex */ - else - np->duplexmode = 1; /* half duplex */ - if (ioread32(np->mem + TCRRCR) & CR_R_PS10) - np->line_speed = 1; /* 10M */ - else - np->line_speed = 2; /* 100M */ - } else { - if (np->PHYType == SeeqPHY) { /* this PHY is SEEQ 80225 */ - unsigned int data; - - data = mdio_read(dev, np->phys[0], MIIRegister18); - if (data & SPD_DET_100) - np->line_speed = 2; /* 100M */ - else - np->line_speed = 1; /* 10M */ - if (data & DPLX_DET_FULL) - np->duplexmode = 2; /* full duplex mode */ - else - np->duplexmode = 1; /* half duplex mode */ - } else if (np->PHYType == AhdocPHY) { - unsigned int data; - - data = mdio_read(dev, np->phys[0], DiagnosticReg); - if (data & Speed_100) - np->line_speed = 2; /* 100M */ - else - np->line_speed = 1; /* 10M */ - if (data & DPLX_FULL) - np->duplexmode = 2; /* full duplex mode */ - else - np->duplexmode = 1; /* half duplex mode */ - } -/* 89/6/13 add, (begin) */ - else if (np->PHYType == MarvellPHY) { - unsigned int data; - - data = mdio_read(dev, np->phys[0], SpecificReg); - if (data & Full_Duplex) - np->duplexmode = 2; /* full duplex mode */ - else - np->duplexmode = 1; /* half duplex mode */ - data &= SpeedMask; - if (data == Speed_1000M) - np->line_speed = 3; /* 1000M */ - else if (data == Speed_100M) - np->line_speed = 2; /* 100M */ - else - np->line_speed = 1; /* 10M */ - } -/* 89/6/13 add, (end) */ -/* 89/7/27 add, (begin) */ - else if (np->PHYType == Myson981) { - unsigned int data; - - data = mdio_read(dev, np->phys[0], StatusRegister); - - if (data & SPEED100) - np->line_speed = 2; - else - np->line_speed = 1; - - if (data & FULLMODE) - np->duplexmode = 2; - else - np->duplexmode = 1; - } -/* 89/7/27 add, (end) */ -/* 89/12/29 add */ - else if (np->PHYType == LevelOnePHY) { - unsigned int data; - - data = mdio_read(dev, np->phys[0], SpecificReg); - if (data & LXT1000_Full) - np->duplexmode = 2; /* full duplex mode */ - else - np->duplexmode = 1; /* half duplex mode */ - data &= SpeedMask; - if (data == LXT1000_1000M) - np->line_speed = 3; /* 1000M */ - else if (data == LXT1000_100M) - np->line_speed = 2; /* 100M */ - else - np->line_speed = 1; /* 10M */ - } - np->crvalue &= (~CR_W_PS10) & (~CR_W_FD) & (~CR_W_PS1000); - if (np->line_speed == 1) - np->crvalue |= CR_W_PS10; - else if (np->line_speed == 3) - np->crvalue |= CR_W_PS1000; - if (np->duplexmode == 2) - np->crvalue |= CR_W_FD; - } -} - - -/* Take lock before calling this */ -static void allocate_rx_buffers(struct net_device *dev) -{ - struct netdev_private *np = netdev_priv(dev); - - /* allocate skb for rx buffers */ - while (np->really_rx_count != RX_RING_SIZE) { - struct sk_buff *skb; - - skb = netdev_alloc_skb(dev, np->rx_buf_sz); - if (skb == NULL) - break; /* Better luck next round. */ - - while (np->lack_rxbuf->skbuff) - np->lack_rxbuf = np->lack_rxbuf->next_desc_logical; - - np->lack_rxbuf->skbuff = skb; - np->lack_rxbuf->buffer = dma_map_single(&np->pci_dev->dev, - skb->data, - np->rx_buf_sz, - DMA_FROM_DEVICE); - np->lack_rxbuf->status = RXOWN; - ++np->really_rx_count; - } -} - - -static void netdev_timer(struct timer_list *t) -{ - struct netdev_private *np = from_timer(np, t, timer); - struct net_device *dev = np->mii.dev; - void __iomem *ioaddr = np->mem; - int old_crvalue = np->crvalue; - unsigned int old_linkok = np->linkok; - unsigned long flags; - - if (debug) - printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x " - "config %8.8x.\n", dev->name, ioread32(ioaddr + ISR), - ioread32(ioaddr + TCRRCR)); - - spin_lock_irqsave(&np->lock, flags); - - if (np->flags == HAS_MII_XCVR) { - getlinkstatus(dev); - if ((old_linkok == 0) && (np->linkok == 1)) { /* we need to detect the media type again */ - getlinktype(dev); - if (np->crvalue != old_crvalue) { - stop_nic_rxtx(ioaddr, np->crvalue); - iowrite32(np->crvalue, ioaddr + TCRRCR); - } - } - } - - allocate_rx_buffers(dev); - - spin_unlock_irqrestore(&np->lock, flags); - - np->timer.expires = RUN_AT(10 * HZ); - add_timer(&np->timer); -} - - -/* Take lock before calling */ -/* Reset chip and disable rx, tx and interrupts */ -static void reset_and_disable_rxtx(struct net_device *dev) -{ - struct netdev_private *np = netdev_priv(dev); - void __iomem *ioaddr = np->mem; - int delay=51; - - /* Reset the chip's Tx and Rx processes. */ - stop_nic_rxtx(ioaddr, 0); - - /* Disable interrupts by clearing the interrupt mask. */ - iowrite32(0, ioaddr + IMR); - - /* Reset the chip to erase previous misconfiguration. */ - iowrite32(0x00000001, ioaddr + BCR); - - /* Ueimor: wait for 50 PCI cycles (and flush posted writes btw). - We surely wait too long (address+data phase). Who cares? */ - while (--delay) { - ioread32(ioaddr + BCR); - rmb(); - } -} - - -/* Take lock before calling */ -/* Restore chip after reset */ -static void enable_rxtx(struct net_device *dev) -{ - struct netdev_private *np = netdev_priv(dev); - void __iomem *ioaddr = np->mem; - - reset_rx_descriptors(dev); - - iowrite32(np->tx_ring_dma + ((char*)np->cur_tx - (char*)np->tx_ring), - ioaddr + TXLBA); - iowrite32(np->rx_ring_dma + ((char*)np->cur_rx - (char*)np->rx_ring), - ioaddr + RXLBA); - - iowrite32(np->bcrvalue, ioaddr + BCR); - - iowrite32(0, ioaddr + RXPDR); - __set_rx_mode(dev); /* changes np->crvalue, writes it into TCRRCR */ - - /* Clear and Enable interrupts by setting the interrupt mask. */ - iowrite32(FBE | TUNF | CNTOVF | RBU | TI | RI, ioaddr + ISR); - iowrite32(np->imrvalue, ioaddr + IMR); - - iowrite32(0, ioaddr + TXPDR); -} - - -static void reset_timer(struct timer_list *t) -{ - struct netdev_private *np = from_timer(np, t, reset_timer); - struct net_device *dev = np->mii.dev; - unsigned long flags; - - printk(KERN_WARNING "%s: resetting tx and rx machinery\n", dev->name); - - spin_lock_irqsave(&np->lock, flags); - np->crvalue = np->crvalue_sv; - np->imrvalue = np->imrvalue_sv; - - reset_and_disable_rxtx(dev); - /* works for me without this: - reset_tx_descriptors(dev); */ - enable_rxtx(dev); - netif_start_queue(dev); /* FIXME: or netif_wake_queue(dev); ? */ - - np->reset_timer_armed = 0; - - spin_unlock_irqrestore(&np->lock, flags); -} - - -static void fealnx_tx_timeout(struct net_device *dev, unsigned int txqueue) -{ - struct netdev_private *np = netdev_priv(dev); - void __iomem *ioaddr = np->mem; - unsigned long flags; - int i; - - printk(KERN_WARNING - "%s: Transmit timed out, status %8.8x, resetting...\n", - dev->name, ioread32(ioaddr + ISR)); - - { - printk(KERN_DEBUG " Rx ring %p: ", np->rx_ring); - for (i = 0; i < RX_RING_SIZE; i++) - printk(KERN_CONT " %8.8x", - (unsigned int) np->rx_ring[i].status); - printk(KERN_CONT "\n"); - printk(KERN_DEBUG " Tx ring %p: ", np->tx_ring); - for (i = 0; i < TX_RING_SIZE; i++) - printk(KERN_CONT " %4.4x", np->tx_ring[i].status); - printk(KERN_CONT "\n"); - } - - spin_lock_irqsave(&np->lock, flags); - - reset_and_disable_rxtx(dev); - reset_tx_descriptors(dev); - enable_rxtx(dev); - - spin_unlock_irqrestore(&np->lock, flags); - - netif_trans_update(dev); /* prevent tx timeout */ - dev->stats.tx_errors++; - netif_wake_queue(dev); /* or .._start_.. ?? */ -} - - -/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ -static void init_ring(struct net_device *dev) -{ - struct netdev_private *np = netdev_priv(dev); - int i; - - /* initialize rx variables */ - np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); - np->cur_rx = &np->rx_ring[0]; - np->lack_rxbuf = np->rx_ring; - np->really_rx_count = 0; - - /* initial rx descriptors. */ - for (i = 0; i < RX_RING_SIZE; i++) { - np->rx_ring[i].status = 0; - np->rx_ring[i].control = np->rx_buf_sz << RBSShift; - np->rx_ring[i].next_desc = np->rx_ring_dma + - (i + 1)*sizeof(struct fealnx_desc); - np->rx_ring[i].next_desc_logical = &np->rx_ring[i + 1]; - np->rx_ring[i].skbuff = NULL; - } - - /* for the last rx descriptor */ - np->rx_ring[i - 1].next_desc = np->rx_ring_dma; - np->rx_ring[i - 1].next_desc_logical = np->rx_ring; - - /* allocate skb for rx buffers */ - for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb = netdev_alloc_skb(dev, np->rx_buf_sz); - - if (skb == NULL) { - np->lack_rxbuf = &np->rx_ring[i]; - break; - } - - ++np->really_rx_count; - np->rx_ring[i].skbuff = skb; - np->rx_ring[i].buffer = dma_map_single(&np->pci_dev->dev, - skb->data, - np->rx_buf_sz, - DMA_FROM_DEVICE); - np->rx_ring[i].status = RXOWN; - np->rx_ring[i].control |= RXIC; - } - - /* initialize tx variables */ - np->cur_tx = &np->tx_ring[0]; - np->cur_tx_copy = &np->tx_ring[0]; - np->really_tx_count = 0; - np->free_tx_count = TX_RING_SIZE; - - for (i = 0; i < TX_RING_SIZE; i++) { - np->tx_ring[i].status = 0; - /* do we need np->tx_ring[i].control = XXX; ?? */ - np->tx_ring[i].next_desc = np->tx_ring_dma + - (i + 1)*sizeof(struct fealnx_desc); - np->tx_ring[i].next_desc_logical = &np->tx_ring[i + 1]; - np->tx_ring[i].skbuff = NULL; - } - - /* for the last tx descriptor */ - np->tx_ring[i - 1].next_desc = np->tx_ring_dma; - np->tx_ring[i - 1].next_desc_logical = &np->tx_ring[0]; -} - - -static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev) -{ - struct netdev_private *np = netdev_priv(dev); - unsigned long flags; - - spin_lock_irqsave(&np->lock, flags); - - np->cur_tx_copy->skbuff = skb; - -#define one_buffer -#define BPT 1022 -#if defined(one_buffer) - np->cur_tx_copy->buffer = dma_map_single(&np->pci_dev->dev, skb->data, - skb->len, DMA_TO_DEVICE); - np->cur_tx_copy->control = TXIC | TXLD | TXFD | CRCEnable | PADEnable; - np->cur_tx_copy->control |= (skb->len << PKTSShift); /* pkt size */ - np->cur_tx_copy->control |= (skb->len << TBSShift); /* buffer size */ -// 89/12/29 add, - if (np->pci_dev->device == 0x891) - np->cur_tx_copy->control |= ETIControl | RetryTxLC; - np->cur_tx_copy->status = TXOWN; - np->cur_tx_copy = np->cur_tx_copy->next_desc_logical; - --np->free_tx_count; -#elif defined(two_buffer) - if (skb->len > BPT) { - struct fealnx_desc *next; - - /* for the first descriptor */ - np->cur_tx_copy->buffer = dma_map_single(&np->pci_dev->dev, - skb->data, BPT, - DMA_TO_DEVICE); - np->cur_tx_copy->control = TXIC | TXFD | CRCEnable | PADEnable; - np->cur_tx_copy->control |= (skb->len << PKTSShift); /* pkt size */ - np->cur_tx_copy->control |= (BPT << TBSShift); /* buffer size */ - - /* for the last descriptor */ - next = np->cur_tx_copy->next_desc_logical; - next->skbuff = skb; - next->control = TXIC | TXLD | CRCEnable | PADEnable; - next->control |= (skb->len << PKTSShift); /* pkt size */ - next->control |= ((skb->len - BPT) << TBSShift); /* buf size */ -// 89/12/29 add, - if (np->pci_dev->device == 0x891) - np->cur_tx_copy->control |= ETIControl | RetryTxLC; - next->buffer = dma_map_single(&ep->pci_dev->dev, - skb->data + BPT, skb->len - BPT, - DMA_TO_DEVICE); - - next->status = TXOWN; - np->cur_tx_copy->status = TXOWN; - - np->cur_tx_copy = next->next_desc_logical; - np->free_tx_count -= 2; - } else { - np->cur_tx_copy->buffer = dma_map_single(&np->pci_dev->dev, - skb->data, skb->len, - DMA_TO_DEVICE); - np->cur_tx_copy->control = TXIC | TXLD | TXFD | CRCEnable | PADEnable; - np->cur_tx_copy->control |= (skb->len << PKTSShift); /* pkt size */ - np->cur_tx_copy->control |= (skb->len << TBSShift); /* buffer size */ -// 89/12/29 add, - if (np->pci_dev->device == 0x891) - np->cur_tx_copy->control |= ETIControl | RetryTxLC; - np->cur_tx_copy->status = TXOWN; - np->cur_tx_copy = np->cur_tx_copy->next_desc_logical; - --np->free_tx_count; - } -#endif - - if (np->free_tx_count < 2) - netif_stop_queue(dev); - ++np->really_tx_count; - iowrite32(0, np->mem + TXPDR); - - spin_unlock_irqrestore(&np->lock, flags); - return NETDEV_TX_OK; -} - - -/* Take lock before calling */ -/* Chip probably hosed tx ring. Clean up. */ -static void reset_tx_descriptors(struct net_device *dev) -{ - struct netdev_private *np = netdev_priv(dev); - struct fealnx_desc *cur; - int i; - - /* initialize tx variables */ - np->cur_tx = &np->tx_ring[0]; - np->cur_tx_copy = &np->tx_ring[0]; - np->really_tx_count = 0; - np->free_tx_count = TX_RING_SIZE; - - for (i = 0; i < TX_RING_SIZE; i++) { - cur = &np->tx_ring[i]; - if (cur->skbuff) { - dma_unmap_single(&np->pci_dev->dev, cur->buffer, - cur->skbuff->len, DMA_TO_DEVICE); - dev_kfree_skb_any(cur->skbuff); - cur->skbuff = NULL; - } - cur->status = 0; - cur->control = 0; /* needed? */ - /* probably not needed. We do it for purely paranoid reasons */ - cur->next_desc = np->tx_ring_dma + - (i + 1)*sizeof(struct fealnx_desc); - cur->next_desc_logical = &np->tx_ring[i + 1]; - } - /* for the last tx descriptor */ - np->tx_ring[TX_RING_SIZE - 1].next_desc = np->tx_ring_dma; - np->tx_ring[TX_RING_SIZE - 1].next_desc_logical = &np->tx_ring[0]; -} - - -/* Take lock and stop rx before calling this */ -static void reset_rx_descriptors(struct net_device *dev) -{ - struct netdev_private *np = netdev_priv(dev); - struct fealnx_desc *cur = np->cur_rx; - int i; - - allocate_rx_buffers(dev); - - for (i = 0; i < RX_RING_SIZE; i++) { - if (cur->skbuff) - cur->status = RXOWN; - cur = cur->next_desc_logical; - } - - iowrite32(np->rx_ring_dma + ((char*)np->cur_rx - (char*)np->rx_ring), - np->mem + RXLBA); -} - - -/* The interrupt handler does all of the Rx thread work and cleans up - after the Tx thread. */ -static irqreturn_t intr_handler(int irq, void *dev_instance) -{ - struct net_device *dev = (struct net_device *) dev_instance; - struct netdev_private *np = netdev_priv(dev); - void __iomem *ioaddr = np->mem; - long boguscnt = max_interrupt_work; - unsigned int num_tx = 0; - int handled = 0; - - spin_lock(&np->lock); - - iowrite32(0, ioaddr + IMR); - - do { - u32 intr_status = ioread32(ioaddr + ISR); - - /* Acknowledge all of the current interrupt sources ASAP. */ - iowrite32(intr_status, ioaddr + ISR); - - if (debug) - printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n", dev->name, - intr_status); - - if (!(intr_status & np->imrvalue)) - break; - - handled = 1; - -// 90/1/16 delete, -// -// if (intr_status & FBE) -// { /* fatal error */ -// stop_nic_tx(ioaddr, 0); -// stop_nic_rx(ioaddr, 0); -// break; -// }; - - if (intr_status & TUNF) - iowrite32(0, ioaddr + TXPDR); - - if (intr_status & CNTOVF) { - /* missed pkts */ - dev->stats.rx_missed_errors += - ioread32(ioaddr + TALLY) & 0x7fff; - - /* crc error */ - dev->stats.rx_crc_errors += - (ioread32(ioaddr + TALLY) & 0x7fff0000) >> 16; - } - - if (intr_status & (RI | RBU)) { - if (intr_status & RI) - netdev_rx(dev); - else { - stop_nic_rx(ioaddr, np->crvalue); - reset_rx_descriptors(dev); - iowrite32(np->crvalue, ioaddr + TCRRCR); - } - } - - while (np->really_tx_count) { - long tx_status = np->cur_tx->status; - long tx_control = np->cur_tx->control; - - if (!(tx_control & TXLD)) { /* this pkt is combined by two tx descriptors */ - struct fealnx_desc *next; - - next = np->cur_tx->next_desc_logical; - tx_status = next->status; - tx_control = next->control; - } - - if (tx_status & TXOWN) - break; - - if (!(np->crvalue & CR_W_ENH)) { - if (tx_status & (CSL | LC | EC | UDF | HF)) { - dev->stats.tx_errors++; - if (tx_status & EC) - dev->stats.tx_aborted_errors++; - if (tx_status & CSL) - dev->stats.tx_carrier_errors++; - if (tx_status & LC) - dev->stats.tx_window_errors++; - if (tx_status & UDF) - dev->stats.tx_fifo_errors++; - if ((tx_status & HF) && np->mii.full_duplex == 0) - dev->stats.tx_heartbeat_errors++; - - } else { - dev->stats.tx_bytes += - ((tx_control & PKTSMask) >> PKTSShift); - - dev->stats.collisions += - ((tx_status & NCRMask) >> NCRShift); - dev->stats.tx_packets++; - } - } else { - dev->stats.tx_bytes += - ((tx_control & PKTSMask) >> PKTSShift); - dev->stats.tx_packets++; - } - - /* Free the original skb. */ - dma_unmap_single(&np->pci_dev->dev, - np->cur_tx->buffer, - np->cur_tx->skbuff->len, - DMA_TO_DEVICE); - dev_consume_skb_irq(np->cur_tx->skbuff); - np->cur_tx->skbuff = NULL; - --np->really_tx_count; - if (np->cur_tx->control & TXLD) { - np->cur_tx = np->cur_tx->next_desc_logical; - ++np->free_tx_count; - } else { - np->cur_tx = np->cur_tx->next_desc_logical; - np->cur_tx = np->cur_tx->next_desc_logical; - np->free_tx_count += 2; - } - num_tx++; - } /* end of for loop */ - - if (num_tx && np->free_tx_count >= 2) - netif_wake_queue(dev); - - /* read transmit status for enhanced mode only */ - if (np->crvalue & CR_W_ENH) { - long data; - - data = ioread32(ioaddr + TSR); - dev->stats.tx_errors += (data & 0xff000000) >> 24; - dev->stats.tx_aborted_errors += - (data & 0xff000000) >> 24; - dev->stats.tx_window_errors += - (data & 0x00ff0000) >> 16; - dev->stats.collisions += (data & 0x0000ffff); - } - - if (--boguscnt < 0) { - printk(KERN_WARNING "%s: Too much work at interrupt, " - "status=0x%4.4x.\n", dev->name, intr_status); - if (!np->reset_timer_armed) { - np->reset_timer_armed = 1; - np->reset_timer.expires = RUN_AT(HZ/2); - add_timer(&np->reset_timer); - stop_nic_rxtx(ioaddr, 0); - netif_stop_queue(dev); - /* or netif_tx_disable(dev); ?? */ - /* Prevent other paths from enabling tx,rx,intrs */ - np->crvalue_sv = np->crvalue; - np->imrvalue_sv = np->imrvalue; - np->crvalue &= ~(CR_W_TXEN | CR_W_RXEN); /* or simply = 0? */ - np->imrvalue = 0; - } - - break; - } - } while (1); - - /* read the tally counters */ - /* missed pkts */ - dev->stats.rx_missed_errors += ioread32(ioaddr + TALLY) & 0x7fff; - - /* crc error */ - dev->stats.rx_crc_errors += - (ioread32(ioaddr + TALLY) & 0x7fff0000) >> 16; - - if (debug) - printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", - dev->name, ioread32(ioaddr + ISR)); - - iowrite32(np->imrvalue, ioaddr + IMR); - - spin_unlock(&np->lock); - - return IRQ_RETVAL(handled); -} - - -/* This routine is logically part of the interrupt handler, but separated - for clarity and better register allocation. */ -static int netdev_rx(struct net_device *dev) -{ - struct netdev_private *np = netdev_priv(dev); - void __iomem *ioaddr = np->mem; - - /* If EOP is set on the next entry, it's a new packet. Send it up. */ - while (!(np->cur_rx->status & RXOWN) && np->cur_rx->skbuff) { - s32 rx_status = np->cur_rx->status; - - if (np->really_rx_count == 0) - break; - - if (debug) - printk(KERN_DEBUG " netdev_rx() status was %8.8x.\n", rx_status); - - if ((!((rx_status & RXFSD) && (rx_status & RXLSD))) || - (rx_status & ErrorSummary)) { - if (rx_status & ErrorSummary) { /* there was a fatal error */ - if (debug) - printk(KERN_DEBUG - "%s: Receive error, Rx status %8.8x.\n", - dev->name, rx_status); - - dev->stats.rx_errors++; /* end of a packet. */ - if (rx_status & (LONGPKT | RUNTPKT)) - dev->stats.rx_length_errors++; - if (rx_status & RXER) - dev->stats.rx_frame_errors++; - if (rx_status & CRC) - dev->stats.rx_crc_errors++; - } else { - int need_to_reset = 0; - int desno = 0; - - if (rx_status & RXFSD) { /* this pkt is too long, over one rx buffer */ - struct fealnx_desc *cur; - - /* check this packet is received completely? */ - cur = np->cur_rx; - while (desno <= np->really_rx_count) { - ++desno; - if ((!(cur->status & RXOWN)) && - (cur->status & RXLSD)) - break; - /* goto next rx descriptor */ - cur = cur->next_desc_logical; - } - if (desno > np->really_rx_count) - need_to_reset = 1; - } else /* RXLSD did not find, something error */ - need_to_reset = 1; - - if (need_to_reset == 0) { - int i; - - dev->stats.rx_length_errors++; - - /* free all rx descriptors related this long pkt */ - for (i = 0; i < desno; ++i) { - if (!np->cur_rx->skbuff) { - printk(KERN_DEBUG - "%s: I'm scared\n", dev->name); - break; - } - np->cur_rx->status = RXOWN; - np->cur_rx = np->cur_rx->next_desc_logical; - } - continue; - } else { /* rx error, need to reset this chip */ - stop_nic_rx(ioaddr, np->crvalue); - reset_rx_descriptors(dev); - iowrite32(np->crvalue, ioaddr + TCRRCR); - } - break; /* exit the while loop */ - } - } else { /* this received pkt is ok */ - - struct sk_buff *skb; - /* Omit the four octet CRC from the length. */ - short pkt_len = ((rx_status & FLNGMASK) >> FLNGShift) - 4; - -#ifndef final_version - if (debug) - printk(KERN_DEBUG " netdev_rx() normal Rx pkt length %d" - " status %x.\n", pkt_len, rx_status); -#endif - - /* Check if the packet is long enough to accept without copying - to a minimally-sized skbuff. */ - if (pkt_len < rx_copybreak && - (skb = netdev_alloc_skb(dev, pkt_len + 2)) != NULL) { - skb_reserve(skb, 2); /* 16 byte align the IP header */ - dma_sync_single_for_cpu(&np->pci_dev->dev, - np->cur_rx->buffer, - np->rx_buf_sz, - DMA_FROM_DEVICE); - /* Call copy + cksum if available. */ - -#if ! defined(__alpha__) - skb_copy_to_linear_data(skb, - np->cur_rx->skbuff->data, pkt_len); - skb_put(skb, pkt_len); -#else - skb_put_data(skb, np->cur_rx->skbuff->data, - pkt_len); -#endif - dma_sync_single_for_device(&np->pci_dev->dev, - np->cur_rx->buffer, - np->rx_buf_sz, - DMA_FROM_DEVICE); - } else { - dma_unmap_single(&np->pci_dev->dev, - np->cur_rx->buffer, - np->rx_buf_sz, - DMA_FROM_DEVICE); - skb_put(skb = np->cur_rx->skbuff, pkt_len); - np->cur_rx->skbuff = NULL; - --np->really_rx_count; - } - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - dev->stats.rx_packets++; - dev->stats.rx_bytes += pkt_len; - } - - np->cur_rx = np->cur_rx->next_desc_logical; - } /* end of while loop */ - - /* allocate skb for rx buffers */ - allocate_rx_buffers(dev); - - return 0; -} - - -static struct net_device_stats *get_stats(struct net_device *dev) -{ - struct netdev_private *np = netdev_priv(dev); - void __iomem *ioaddr = np->mem; - - /* The chip only need report frame silently dropped. */ - if (netif_running(dev)) { - dev->stats.rx_missed_errors += - ioread32(ioaddr + TALLY) & 0x7fff; - dev->stats.rx_crc_errors += - (ioread32(ioaddr + TALLY) & 0x7fff0000) >> 16; - } - - return &dev->stats; -} - - -/* for dev->set_multicast_list */ -static void set_rx_mode(struct net_device *dev) -{ - spinlock_t *lp = &((struct netdev_private *)netdev_priv(dev))->lock; - unsigned long flags; - spin_lock_irqsave(lp, flags); - __set_rx_mode(dev); - spin_unlock_irqrestore(lp, flags); -} - - -/* Take lock before calling */ -static void __set_rx_mode(struct net_device *dev) -{ - struct netdev_private *np = netdev_priv(dev); - void __iomem *ioaddr = np->mem; - u32 mc_filter[2]; /* Multicast hash filter */ - u32 rx_mode; - - if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ - memset(mc_filter, 0xff, sizeof(mc_filter)); - rx_mode = CR_W_PROM | CR_W_AB | CR_W_AM; - } else if ((netdev_mc_count(dev) > multicast_filter_limit) || - (dev->flags & IFF_ALLMULTI)) { - /* Too many to match, or accept all multicasts. */ - memset(mc_filter, 0xff, sizeof(mc_filter)); - rx_mode = CR_W_AB | CR_W_AM; - } else { - struct netdev_hw_addr *ha; - - memset(mc_filter, 0, sizeof(mc_filter)); - netdev_for_each_mc_addr(ha, dev) { - unsigned int bit; - bit = (ether_crc(ETH_ALEN, ha->addr) >> 26) ^ 0x3F; - mc_filter[bit >> 5] |= (1 << bit); - } - rx_mode = CR_W_AB | CR_W_AM; - } - - stop_nic_rxtx(ioaddr, np->crvalue); - - iowrite32(mc_filter[0], ioaddr + MAR0); - iowrite32(mc_filter[1], ioaddr + MAR1); - np->crvalue &= ~CR_W_RXMODEMASK; - np->crvalue |= rx_mode; - iowrite32(np->crvalue, ioaddr + TCRRCR); -} - -static void netdev_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) -{ - struct netdev_private *np = netdev_priv(dev); - - strscpy(info->driver, DRV_NAME, sizeof(info->driver)); - strscpy(info->bus_info, pci_name(np->pci_dev), sizeof(info->bus_info)); -} - -static int netdev_get_link_ksettings(struct net_device *dev, - struct ethtool_link_ksettings *cmd) -{ - struct netdev_private *np = netdev_priv(dev); - - spin_lock_irq(&np->lock); - mii_ethtool_get_link_ksettings(&np->mii, cmd); - spin_unlock_irq(&np->lock); - - return 0; -} - -static int netdev_set_link_ksettings(struct net_device *dev, - const struct ethtool_link_ksettings *cmd) -{ - struct netdev_private *np = netdev_priv(dev); - int rc; - - spin_lock_irq(&np->lock); - rc = mii_ethtool_set_link_ksettings(&np->mii, cmd); - spin_unlock_irq(&np->lock); - - return rc; -} - -static int netdev_nway_reset(struct net_device *dev) -{ - struct netdev_private *np = netdev_priv(dev); - return mii_nway_restart(&np->mii); -} - -static u32 netdev_get_link(struct net_device *dev) -{ - struct netdev_private *np = netdev_priv(dev); - return mii_link_ok(&np->mii); -} - -static u32 netdev_get_msglevel(struct net_device *dev) -{ - return debug; -} - -static void netdev_set_msglevel(struct net_device *dev, u32 value) -{ - debug = value; -} - -static const struct ethtool_ops netdev_ethtool_ops = { - .get_drvinfo = netdev_get_drvinfo, - .nway_reset = netdev_nway_reset, - .get_link = netdev_get_link, - .get_msglevel = netdev_get_msglevel, - .set_msglevel = netdev_set_msglevel, - .get_link_ksettings = netdev_get_link_ksettings, - .set_link_ksettings = netdev_set_link_ksettings, -}; - -static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct netdev_private *np = netdev_priv(dev); - int rc; - - if (!netif_running(dev)) - return -EINVAL; - - spin_lock_irq(&np->lock); - rc = generic_mii_ioctl(&np->mii, if_mii(rq), cmd, NULL); - spin_unlock_irq(&np->lock); - - return rc; -} - - -static int netdev_close(struct net_device *dev) -{ - struct netdev_private *np = netdev_priv(dev); - void __iomem *ioaddr = np->mem; - int i; - - netif_stop_queue(dev); - - /* Disable interrupts by clearing the interrupt mask. */ - iowrite32(0x0000, ioaddr + IMR); - - /* Stop the chip's Tx and Rx processes. */ - stop_nic_rxtx(ioaddr, 0); - - del_timer_sync(&np->timer); - del_timer_sync(&np->reset_timer); - - free_irq(np->pci_dev->irq, dev); - - /* Free all the skbuffs in the Rx queue. */ - for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb = np->rx_ring[i].skbuff; - - np->rx_ring[i].status = 0; - if (skb) { - dma_unmap_single(&np->pci_dev->dev, - np->rx_ring[i].buffer, np->rx_buf_sz, - DMA_FROM_DEVICE); - dev_kfree_skb(skb); - np->rx_ring[i].skbuff = NULL; - } - } - - for (i = 0; i < TX_RING_SIZE; i++) { - struct sk_buff *skb = np->tx_ring[i].skbuff; - - if (skb) { - dma_unmap_single(&np->pci_dev->dev, - np->tx_ring[i].buffer, skb->len, - DMA_TO_DEVICE); - dev_kfree_skb(skb); - np->tx_ring[i].skbuff = NULL; - } - } - - return 0; -} - -static const struct pci_device_id fealnx_pci_tbl[] = { - {0x1516, 0x0800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x1516, 0x0803, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, - {0x1516, 0x0891, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, - {} /* terminate list */ -}; -MODULE_DEVICE_TABLE(pci, fealnx_pci_tbl); - - -static struct pci_driver fealnx_driver = { - .name = "fealnx", - .id_table = fealnx_pci_tbl, - .probe = fealnx_init_one, - .remove = fealnx_remove_one, -}; - -module_pci_driver(fealnx_driver); diff --git a/drivers/net/ethernet/freescale/dpaa/Kconfig b/drivers/net/ethernet/freescale/dpaa/Kconfig index 0e1439fd00bd..2b560661c82a 100644 --- a/drivers/net/ethernet/freescale/dpaa/Kconfig +++ b/drivers/net/ethernet/freescale/dpaa/Kconfig @@ -2,8 +2,8 @@ menuconfig FSL_DPAA_ETH tristate "DPAA Ethernet" depends on FSL_DPAA && FSL_FMAN - select PHYLIB - select FIXED_PHY + select PHYLINK + select PCS_LYNX help Data Path Acceleration Architecture Ethernet driver, supporting the Freescale QorIQ chips. diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c index 31cfa121333d..3f8032947d86 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c @@ -221,8 +221,8 @@ static int dpaa_netdev_init(struct net_device *net_dev, net_dev->netdev_ops = dpaa_ops; mac_addr = mac_dev->addr; - net_dev->mem_start = (unsigned long)mac_dev->vaddr; - net_dev->mem_end = (unsigned long)mac_dev->vaddr_end; + net_dev->mem_start = (unsigned long)priv->mac_dev->res->start; + net_dev->mem_end = (unsigned long)priv->mac_dev->res->end; net_dev->min_mtu = ETH_MIN_MTU; net_dev->max_mtu = dpaa_get_max_mtu(); @@ -264,8 +264,19 @@ static int dpaa_netdev_init(struct net_device *net_dev, net_dev->needed_headroom = priv->tx_headroom; net_dev->watchdog_timeo = msecs_to_jiffies(tx_timeout); - mac_dev->net_dev = net_dev; + /* The rest of the config is filled in by the mac device already */ + mac_dev->phylink_config.dev = &net_dev->dev; + mac_dev->phylink_config.type = PHYLINK_NETDEV; mac_dev->update_speed = dpaa_eth_cgr_set_speed; + mac_dev->phylink = phylink_create(&mac_dev->phylink_config, + dev_fwnode(mac_dev->dev), + mac_dev->phy_if, + mac_dev->phylink_ops); + if (IS_ERR(mac_dev->phylink)) { + err = PTR_ERR(mac_dev->phylink); + dev_err_probe(dev, err, "Could not create phylink\n"); + return err; + } /* start without the RUNNING flag, phylib controls it later */ netif_carrier_off(net_dev); @@ -273,6 +284,7 @@ static int dpaa_netdev_init(struct net_device *net_dev, err = register_netdev(net_dev); if (err < 0) { dev_err(dev, "register_netdev() = %d\n", err); + phylink_destroy(mac_dev->phylink); return err; } @@ -294,8 +306,7 @@ static int dpaa_stop(struct net_device *net_dev) */ msleep(200); - if (mac_dev->phy_dev) - phy_stop(mac_dev->phy_dev); + phylink_stop(mac_dev->phylink); mac_dev->disable(mac_dev->fman_mac); for (i = 0; i < ARRAY_SIZE(mac_dev->port); i++) { @@ -304,8 +315,7 @@ static int dpaa_stop(struct net_device *net_dev) err = error; } - if (net_dev->phydev) - phy_disconnect(net_dev->phydev); + phylink_disconnect_phy(mac_dev->phylink); net_dev->phydev = NULL; msleep(200); @@ -833,10 +843,10 @@ static int dpaa_eth_cgr_init(struct dpaa_priv *priv) /* Set different thresholds based on the configured MAC speed. * This may turn suboptimal if the MAC is reconfigured at another - * speed, so MACs must call dpaa_eth_cgr_set_speed in their adjust_link + * speed, so MACs must call dpaa_eth_cgr_set_speed in their link_up * callback. */ - if (priv->mac_dev->if_support & SUPPORTED_10000baseT_Full) + if (priv->mac_dev->phylink_config.mac_capabilities & MAC_10000FD) cs_th = DPAA_CS_THRESHOLD_10G; else cs_th = DPAA_CS_THRESHOLD_1G; @@ -865,7 +875,7 @@ out_error: static void dpaa_eth_cgr_set_speed(struct mac_device *mac_dev, int speed) { - struct net_device *net_dev = mac_dev->net_dev; + struct net_device *net_dev = to_net_dev(mac_dev->phylink_config.dev); struct dpaa_priv *priv = netdev_priv(net_dev); struct qm_mcc_initcgr opts = { }; u32 cs_th; @@ -2904,58 +2914,6 @@ static void dpaa_eth_napi_disable(struct dpaa_priv *priv) } } -static void dpaa_adjust_link(struct net_device *net_dev) -{ - struct mac_device *mac_dev; - struct dpaa_priv *priv; - - priv = netdev_priv(net_dev); - mac_dev = priv->mac_dev; - mac_dev->adjust_link(mac_dev); -} - -/* The Aquantia PHYs are capable of performing rate adaptation */ -#define PHY_VEND_AQUANTIA 0x03a1b400 -#define PHY_VEND_AQUANTIA2 0x31c31c00 - -static int dpaa_phy_init(struct net_device *net_dev) -{ - __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; - struct mac_device *mac_dev; - struct phy_device *phy_dev; - struct dpaa_priv *priv; - u32 phy_vendor; - - priv = netdev_priv(net_dev); - mac_dev = priv->mac_dev; - - phy_dev = of_phy_connect(net_dev, mac_dev->phy_node, - &dpaa_adjust_link, 0, - mac_dev->phy_if); - if (!phy_dev) { - netif_err(priv, ifup, net_dev, "init_phy() failed\n"); - return -ENODEV; - } - - phy_vendor = phy_dev->drv->phy_id & GENMASK(31, 10); - /* Unless the PHY is capable of rate adaptation */ - if (mac_dev->phy_if != PHY_INTERFACE_MODE_XGMII || - (phy_vendor != PHY_VEND_AQUANTIA && - phy_vendor != PHY_VEND_AQUANTIA2)) { - /* remove any features not supported by the controller */ - ethtool_convert_legacy_u32_to_link_mode(mask, - mac_dev->if_support); - linkmode_and(phy_dev->supported, phy_dev->supported, mask); - } - - phy_support_asym_pause(phy_dev); - - mac_dev->phy_dev = phy_dev; - net_dev->phydev = phy_dev; - - return 0; -} - static int dpaa_open(struct net_device *net_dev) { struct mac_device *mac_dev; @@ -2966,7 +2924,8 @@ static int dpaa_open(struct net_device *net_dev) mac_dev = priv->mac_dev; dpaa_eth_napi_enable(priv); - err = dpaa_phy_init(net_dev); + err = phylink_of_phy_connect(mac_dev->phylink, + mac_dev->dev->of_node, 0); if (err) goto phy_init_failed; @@ -2981,7 +2940,7 @@ static int dpaa_open(struct net_device *net_dev) netif_err(priv, ifup, net_dev, "mac_dev->enable() = %d\n", err); goto mac_start_failed; } - phy_start(priv->mac_dev->phy_dev); + phylink_start(mac_dev->phylink); netif_tx_start_all_queues(net_dev); @@ -2990,6 +2949,7 @@ static int dpaa_open(struct net_device *net_dev) mac_start_failed: for (i = 0; i < ARRAY_SIZE(mac_dev->port); i++) fman_port_disable(mac_dev->port[i]); + phylink_disconnect_phy(mac_dev->phylink); phy_init_failed: dpaa_eth_napi_disable(priv); @@ -3145,10 +3105,12 @@ static int dpaa_ts_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) static int dpaa_ioctl(struct net_device *net_dev, struct ifreq *rq, int cmd) { int ret = -EINVAL; + struct dpaa_priv *priv = netdev_priv(net_dev); if (cmd == SIOCGMIIREG) { if (net_dev->phydev) - return phy_mii_ioctl(net_dev->phydev, rq, cmd); + return phylink_mii_ioctl(priv->mac_dev->phylink, rq, + cmd); } if (cmd == SIOCSHWTSTAMP) @@ -3551,6 +3513,7 @@ static int dpaa_remove(struct platform_device *pdev) dev_set_drvdata(dev, NULL); unregister_netdev(net_dev); + phylink_destroy(priv->mac_dev->phylink); err = dpaa_fq_free(dev, &priv->dpaa_fq_list); diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth_sysfs.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth_sysfs.c index 258eb6c8f4c0..4fee74c024bd 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth_sysfs.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth_sysfs.c @@ -18,7 +18,7 @@ static ssize_t dpaa_eth_show_addr(struct device *dev, if (mac_dev) return sprintf(buf, "%llx", - (unsigned long long)mac_dev->vaddr); + (unsigned long long)mac_dev->res->start); else return sprintf(buf, "none"); } diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c b/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c index 769e936a263c..9c71cbbb13d8 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c @@ -54,27 +54,19 @@ static char dpaa_stats_global[][ETH_GSTRING_LEN] = { static int dpaa_get_link_ksettings(struct net_device *net_dev, struct ethtool_link_ksettings *cmd) { - if (!net_dev->phydev) - return 0; + struct dpaa_priv *priv = netdev_priv(net_dev); + struct mac_device *mac_dev = priv->mac_dev; - phy_ethtool_ksettings_get(net_dev->phydev, cmd); - - return 0; + return phylink_ethtool_ksettings_get(mac_dev->phylink, cmd); } static int dpaa_set_link_ksettings(struct net_device *net_dev, const struct ethtool_link_ksettings *cmd) { - int err; - - if (!net_dev->phydev) - return -ENODEV; - - err = phy_ethtool_ksettings_set(net_dev->phydev, cmd); - if (err < 0) - netdev_err(net_dev, "phy_ethtool_ksettings_set() = %d\n", err); + struct dpaa_priv *priv = netdev_priv(net_dev); + struct mac_device *mac_dev = priv->mac_dev; - return err; + return phylink_ethtool_ksettings_set(mac_dev->phylink, cmd); } static void dpaa_get_drvinfo(struct net_device *net_dev, @@ -99,80 +91,28 @@ static void dpaa_set_msglevel(struct net_device *net_dev, static int dpaa_nway_reset(struct net_device *net_dev) { - int err; - - if (!net_dev->phydev) - return -ENODEV; - - err = 0; - if (net_dev->phydev->autoneg) { - err = phy_start_aneg(net_dev->phydev); - if (err < 0) - netdev_err(net_dev, "phy_start_aneg() = %d\n", - err); - } + struct dpaa_priv *priv = netdev_priv(net_dev); + struct mac_device *mac_dev = priv->mac_dev; - return err; + return phylink_ethtool_nway_reset(mac_dev->phylink); } static void dpaa_get_pauseparam(struct net_device *net_dev, struct ethtool_pauseparam *epause) { - struct mac_device *mac_dev; - struct dpaa_priv *priv; - - priv = netdev_priv(net_dev); - mac_dev = priv->mac_dev; - - if (!net_dev->phydev) - return; + struct dpaa_priv *priv = netdev_priv(net_dev); + struct mac_device *mac_dev = priv->mac_dev; - epause->autoneg = mac_dev->autoneg_pause; - epause->rx_pause = mac_dev->rx_pause_active; - epause->tx_pause = mac_dev->tx_pause_active; + phylink_ethtool_get_pauseparam(mac_dev->phylink, epause); } static int dpaa_set_pauseparam(struct net_device *net_dev, struct ethtool_pauseparam *epause) { - struct mac_device *mac_dev; - struct phy_device *phydev; - bool rx_pause, tx_pause; - struct dpaa_priv *priv; - int err; - - priv = netdev_priv(net_dev); - mac_dev = priv->mac_dev; - - phydev = net_dev->phydev; - if (!phydev) { - netdev_err(net_dev, "phy device not initialized\n"); - return -ENODEV; - } - - if (!phy_validate_pause(phydev, epause)) - return -EINVAL; - - /* The MAC should know how to handle PAUSE frame autonegotiation before - * adjust_link is triggered by a forced renegotiation of sym/asym PAUSE - * settings. - */ - mac_dev->autoneg_pause = !!epause->autoneg; - mac_dev->rx_pause_req = !!epause->rx_pause; - mac_dev->tx_pause_req = !!epause->tx_pause; - - /* Determine the sym/asym advertised PAUSE capabilities from the desired - * rx/tx pause settings. - */ - - phy_set_asym_pause(phydev, epause->rx_pause, epause->tx_pause); - - fman_get_pause_cfg(mac_dev, &rx_pause, &tx_pause); - err = fman_set_mac_active_pause(mac_dev, rx_pause, tx_pause); - if (err < 0) - netdev_err(net_dev, "set_mac_active_pause() = %d\n", err); + struct dpaa_priv *priv = netdev_priv(net_dev); + struct mac_device *mac_dev = priv->mac_dev; - return err; + return phylink_ethtool_set_pauseparam(mac_dev->phylink, epause); } static int dpaa_get_sset_count(struct net_device *net_dev, int type) diff --git a/drivers/net/ethernet/freescale/dpaa2/Makefile b/drivers/net/ethernet/freescale/dpaa2/Makefile index 3d9842af7f10..1b05ba8d1cbf 100644 --- a/drivers/net/ethernet/freescale/dpaa2/Makefile +++ b/drivers/net/ethernet/freescale/dpaa2/Makefile @@ -7,7 +7,7 @@ obj-$(CONFIG_FSL_DPAA2_ETH) += fsl-dpaa2-eth.o obj-$(CONFIG_FSL_DPAA2_PTP_CLOCK) += fsl-dpaa2-ptp.o obj-$(CONFIG_FSL_DPAA2_SWITCH) += fsl-dpaa2-switch.o -fsl-dpaa2-eth-objs := dpaa2-eth.o dpaa2-ethtool.o dpni.o dpaa2-mac.o dpmac.o dpaa2-eth-devlink.o +fsl-dpaa2-eth-objs := dpaa2-eth.o dpaa2-ethtool.o dpni.o dpaa2-mac.o dpmac.o dpaa2-eth-devlink.o dpaa2-xsk.o fsl-dpaa2-eth-${CONFIG_FSL_DPAA2_ETH_DCB} += dpaa2-eth-dcb.o fsl-dpaa2-eth-${CONFIG_DEBUG_FS} += dpaa2-eth-debugfs.o fsl-dpaa2-ptp-objs := dpaa2-ptp.o dprtc.o diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-debugfs.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-debugfs.c index 8356af4631fd..1af254caeb0d 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-debugfs.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-debugfs.c @@ -98,14 +98,14 @@ static int dpaa2_dbg_ch_show(struct seq_file *file, void *offset) int i; seq_printf(file, "Channel stats for %s:\n", priv->net_dev->name); - seq_printf(file, "%s%16s%16s%16s%16s%16s%16s\n", - "CHID", "CPU", "Deq busy", "Frames", "CDANs", + seq_printf(file, "%s %5s%16s%16s%16s%16s%16s%16s\n", + "IDX", "CHID", "CPU", "Deq busy", "Frames", "CDANs", "Avg Frm/CDAN", "Buf count"); for (i = 0; i < priv->num_channels; i++) { ch = priv->channel[i]; - seq_printf(file, "%4d%16d%16llu%16llu%16llu%16llu%16d\n", - ch->ch_id, + seq_printf(file, "%3s%d%6d%16d%16llu%16llu%16llu%16llu%16d\n", + "CH#", i, ch->ch_id, ch->nctx.desired_cpu, ch->stats.dequeue_portal_busy, ch->stats.frames, @@ -119,6 +119,51 @@ static int dpaa2_dbg_ch_show(struct seq_file *file, void *offset) DEFINE_SHOW_ATTRIBUTE(dpaa2_dbg_ch); +static int dpaa2_dbg_bp_show(struct seq_file *file, void *offset) +{ + struct dpaa2_eth_priv *priv = (struct dpaa2_eth_priv *)file->private; + int i, j, num_queues, buf_cnt; + struct dpaa2_eth_bp *bp; + char ch_name[10]; + int err; + + /* Print out the header */ + seq_printf(file, "Buffer pool info for %s:\n", priv->net_dev->name); + seq_printf(file, "%s %10s%15s", "IDX", "BPID", "Buf count"); + num_queues = dpaa2_eth_queue_count(priv); + for (i = 0; i < num_queues; i++) { + snprintf(ch_name, sizeof(ch_name), "CH#%d", i); + seq_printf(file, "%10s", ch_name); + } + seq_printf(file, "\n"); + + /* For each buffer pool, print out its BPID, the number of buffers in + * that buffer pool and the channels which are using it. + */ + for (i = 0; i < priv->num_bps; i++) { + bp = priv->bp[i]; + + err = dpaa2_io_query_bp_count(NULL, bp->bpid, &buf_cnt); + if (err) { + netdev_warn(priv->net_dev, "Buffer count query error %d\n", err); + return err; + } + + seq_printf(file, "%3s%d%10d%15d", "BP#", i, bp->bpid, buf_cnt); + for (j = 0; j < num_queues; j++) { + if (priv->channel[j]->bp == bp) + seq_printf(file, "%10s", "x"); + else + seq_printf(file, "%10s", ""); + } + seq_printf(file, "\n"); + } + + return 0; +} + +DEFINE_SHOW_ATTRIBUTE(dpaa2_dbg_bp); + void dpaa2_dbg_add(struct dpaa2_eth_priv *priv) { struct fsl_mc_device *dpni_dev; @@ -139,6 +184,10 @@ void dpaa2_dbg_add(struct dpaa2_eth_priv *priv) /* per-fq stats file */ debugfs_create_file("ch_stats", 0444, dir, priv, &dpaa2_dbg_ch_fops); + + /* per buffer pool stats file */ + debugfs_create_file("bp_stats", 0444, dir, priv, &dpaa2_dbg_bp_fops); + } void dpaa2_dbg_remove(struct dpaa2_eth_priv *priv) diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-trace.h b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-trace.h index 5fb5f14e01ec..9b43fadb9b11 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-trace.h +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-trace.h @@ -73,6 +73,14 @@ DEFINE_EVENT(dpaa2_eth_fd, dpaa2_tx_fd, TP_ARGS(netdev, fd) ); +/* Tx (egress) XSK fd */ +DEFINE_EVENT(dpaa2_eth_fd, dpaa2_tx_xsk_fd, + TP_PROTO(struct net_device *netdev, + const struct dpaa2_fd *fd), + + TP_ARGS(netdev, fd) +); + /* Rx fd */ DEFINE_EVENT(dpaa2_eth_fd, dpaa2_rx_fd, TP_PROTO(struct net_device *netdev, @@ -81,6 +89,14 @@ DEFINE_EVENT(dpaa2_eth_fd, dpaa2_rx_fd, TP_ARGS(netdev, fd) ); +/* Rx XSK fd */ +DEFINE_EVENT(dpaa2_eth_fd, dpaa2_rx_xsk_fd, + TP_PROTO(struct net_device *netdev, + const struct dpaa2_fd *fd), + + TP_ARGS(netdev, fd) +); + /* Tx confirmation fd */ DEFINE_EVENT(dpaa2_eth_fd, dpaa2_tx_conf_fd, TP_PROTO(struct net_device *netdev, @@ -90,57 +106,81 @@ DEFINE_EVENT(dpaa2_eth_fd, dpaa2_tx_conf_fd, ); /* Log data about raw buffers. Useful for tracing DPBP content. */ -TRACE_EVENT(dpaa2_eth_buf_seed, - /* Trace function prototype */ - TP_PROTO(struct net_device *netdev, - /* virtual address and size */ - void *vaddr, - size_t size, - /* dma map address and size */ - dma_addr_t dma_addr, - size_t map_size, - /* buffer pool id, if relevant */ - u16 bpid), - - /* Repeat argument list here */ - TP_ARGS(netdev, vaddr, size, dma_addr, map_size, bpid), - - /* A structure containing the relevant information we want - * to record. Declare name and type for each normal element, - * name, type and size for arrays. Use __string for variable - * length strings. - */ - TP_STRUCT__entry( - __field(void *, vaddr) - __field(size_t, size) - __field(dma_addr_t, dma_addr) - __field(size_t, map_size) - __field(u16, bpid) - __string(name, netdev->name) - ), - - /* The function that assigns values to the above declared - * fields - */ - TP_fast_assign( - __entry->vaddr = vaddr; - __entry->size = size; - __entry->dma_addr = dma_addr; - __entry->map_size = map_size; - __entry->bpid = bpid; - __assign_str(name, netdev->name); - ), - - /* This is what gets printed when the trace event is - * triggered. - */ - TP_printk(TR_BUF_FMT, - __get_str(name), - __entry->vaddr, - __entry->size, - &__entry->dma_addr, - __entry->map_size, - __entry->bpid) +DECLARE_EVENT_CLASS(dpaa2_eth_buf, + /* Trace function prototype */ + TP_PROTO(struct net_device *netdev, + /* virtual address and size */ + void *vaddr, + size_t size, + /* dma map address and size */ + dma_addr_t dma_addr, + size_t map_size, + /* buffer pool id, if relevant */ + u16 bpid), + + /* Repeat argument list here */ + TP_ARGS(netdev, vaddr, size, dma_addr, map_size, bpid), + + /* A structure containing the relevant information we want + * to record. Declare name and type for each normal element, + * name, type and size for arrays. Use __string for variable + * length strings. + */ + TP_STRUCT__entry( + __field(void *, vaddr) + __field(size_t, size) + __field(dma_addr_t, dma_addr) + __field(size_t, map_size) + __field(u16, bpid) + __string(name, netdev->name) + ), + + /* The function that assigns values to the above declared + * fields + */ + TP_fast_assign( + __entry->vaddr = vaddr; + __entry->size = size; + __entry->dma_addr = dma_addr; + __entry->map_size = map_size; + __entry->bpid = bpid; + __assign_str(name, netdev->name); + ), + + /* This is what gets printed when the trace event is + * triggered. + */ + TP_printk(TR_BUF_FMT, + __get_str(name), + __entry->vaddr, + __entry->size, + &__entry->dma_addr, + __entry->map_size, + __entry->bpid) +); + +/* Main memory buff seeding */ +DEFINE_EVENT(dpaa2_eth_buf, dpaa2_eth_buf_seed, + TP_PROTO(struct net_device *netdev, + void *vaddr, + size_t size, + dma_addr_t dma_addr, + size_t map_size, + u16 bpid), + + TP_ARGS(netdev, vaddr, size, dma_addr, map_size, bpid) +); + +/* UMEM buff seeding on AF_XDP fast path */ +DEFINE_EVENT(dpaa2_eth_buf, dpaa2_xsk_buf_seed, + TP_PROTO(struct net_device *netdev, + void *vaddr, + size_t size, + dma_addr_t dma_addr, + size_t map_size, + u16 bpid), + + TP_ARGS(netdev, vaddr, size, dma_addr, map_size, bpid) ); /* If only one event of a certain type needs to be declared, use TRACE_EVENT(). diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c index 8d029addddad..281d7e3905c1 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) /* Copyright 2014-2016 Freescale Semiconductor Inc. - * Copyright 2016-2020 NXP + * Copyright 2016-2022 NXP */ #include <linux/init.h> #include <linux/module.h> @@ -19,6 +19,7 @@ #include <net/pkt_cls.h> #include <net/sock.h> #include <net/tso.h> +#include <net/xdp_sock_drv.h> #include "dpaa2-eth.h" @@ -104,8 +105,8 @@ static void dpaa2_ptp_onestep_reg_update_method(struct dpaa2_eth_priv *priv) priv->dpaa2_set_onestep_params_cb = dpaa2_update_ptp_onestep_direct; } -static void *dpaa2_iova_to_virt(struct iommu_domain *domain, - dma_addr_t iova_addr) +void *dpaa2_iova_to_virt(struct iommu_domain *domain, + dma_addr_t iova_addr) { phys_addr_t phys_addr; @@ -279,23 +280,33 @@ static struct sk_buff *dpaa2_eth_build_frag_skb(struct dpaa2_eth_priv *priv, * be released in the pool */ static void dpaa2_eth_free_bufs(struct dpaa2_eth_priv *priv, u64 *buf_array, - int count) + int count, bool xsk_zc) { struct device *dev = priv->net_dev->dev.parent; + struct dpaa2_eth_swa *swa; + struct xdp_buff *xdp_buff; void *vaddr; int i; for (i = 0; i < count; i++) { vaddr = dpaa2_iova_to_virt(priv->iommu_domain, buf_array[i]); - dma_unmap_page(dev, buf_array[i], priv->rx_buf_size, - DMA_BIDIRECTIONAL); - free_pages((unsigned long)vaddr, 0); + + if (!xsk_zc) { + dma_unmap_page(dev, buf_array[i], priv->rx_buf_size, + DMA_BIDIRECTIONAL); + free_pages((unsigned long)vaddr, 0); + } else { + swa = (struct dpaa2_eth_swa *) + (vaddr + DPAA2_ETH_RX_HWA_SIZE); + xdp_buff = swa->xsk.xdp_buff; + xsk_buff_free(xdp_buff); + } } } -static void dpaa2_eth_recycle_buf(struct dpaa2_eth_priv *priv, - struct dpaa2_eth_channel *ch, - dma_addr_t addr) +void dpaa2_eth_recycle_buf(struct dpaa2_eth_priv *priv, + struct dpaa2_eth_channel *ch, + dma_addr_t addr) { int retries = 0; int err; @@ -304,7 +315,7 @@ static void dpaa2_eth_recycle_buf(struct dpaa2_eth_priv *priv, if (ch->recycled_bufs_cnt < DPAA2_ETH_BUFS_PER_CMD) return; - while ((err = dpaa2_io_service_release(ch->dpio, priv->bpid, + while ((err = dpaa2_io_service_release(ch->dpio, ch->bp->bpid, ch->recycled_bufs, ch->recycled_bufs_cnt)) == -EBUSY) { if (retries++ >= DPAA2_ETH_SWP_BUSY_RETRIES) @@ -313,7 +324,8 @@ static void dpaa2_eth_recycle_buf(struct dpaa2_eth_priv *priv, } if (err) { - dpaa2_eth_free_bufs(priv, ch->recycled_bufs, ch->recycled_bufs_cnt); + dpaa2_eth_free_bufs(priv, ch->recycled_bufs, + ch->recycled_bufs_cnt, ch->xsk_zc); ch->buf_count -= ch->recycled_bufs_cnt; } @@ -377,10 +389,10 @@ static void dpaa2_eth_xdp_tx_flush(struct dpaa2_eth_priv *priv, fq->xdp_tx_fds.num = 0; } -static void dpaa2_eth_xdp_enqueue(struct dpaa2_eth_priv *priv, - struct dpaa2_eth_channel *ch, - struct dpaa2_fd *fd, - void *buf_start, u16 queue_id) +void dpaa2_eth_xdp_enqueue(struct dpaa2_eth_priv *priv, + struct dpaa2_eth_channel *ch, + struct dpaa2_fd *fd, + void *buf_start, u16 queue_id) { struct dpaa2_faead *faead; struct dpaa2_fd *dest_fd; @@ -485,19 +497,15 @@ out: return xdp_act; } -static struct sk_buff *dpaa2_eth_copybreak(struct dpaa2_eth_channel *ch, - const struct dpaa2_fd *fd, - void *fd_vaddr) +struct sk_buff *dpaa2_eth_alloc_skb(struct dpaa2_eth_priv *priv, + struct dpaa2_eth_channel *ch, + const struct dpaa2_fd *fd, u32 fd_length, + void *fd_vaddr) { u16 fd_offset = dpaa2_fd_get_offset(fd); - struct dpaa2_eth_priv *priv = ch->priv; - u32 fd_length = dpaa2_fd_get_len(fd); struct sk_buff *skb = NULL; unsigned int skb_len; - if (fd_length > priv->rx_copybreak) - return NULL; - skb_len = fd_length + dpaa2_eth_needed_headroom(NULL); skb = napi_alloc_skb(&ch->napi, skb_len); @@ -514,11 +522,66 @@ static struct sk_buff *dpaa2_eth_copybreak(struct dpaa2_eth_channel *ch, return skb; } +static struct sk_buff *dpaa2_eth_copybreak(struct dpaa2_eth_channel *ch, + const struct dpaa2_fd *fd, + void *fd_vaddr) +{ + struct dpaa2_eth_priv *priv = ch->priv; + u32 fd_length = dpaa2_fd_get_len(fd); + + if (fd_length > priv->rx_copybreak) + return NULL; + + return dpaa2_eth_alloc_skb(priv, ch, fd, fd_length, fd_vaddr); +} + +void dpaa2_eth_receive_skb(struct dpaa2_eth_priv *priv, + struct dpaa2_eth_channel *ch, + const struct dpaa2_fd *fd, void *vaddr, + struct dpaa2_eth_fq *fq, + struct rtnl_link_stats64 *percpu_stats, + struct sk_buff *skb) +{ + struct dpaa2_fas *fas; + u32 status = 0; + + fas = dpaa2_get_fas(vaddr, false); + prefetch(fas); + prefetch(skb->data); + + /* Get the timestamp value */ + if (priv->rx_tstamp) { + struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb); + __le64 *ts = dpaa2_get_ts(vaddr, false); + u64 ns; + + memset(shhwtstamps, 0, sizeof(*shhwtstamps)); + + ns = DPAA2_PTP_CLK_PERIOD_NS * le64_to_cpup(ts); + shhwtstamps->hwtstamp = ns_to_ktime(ns); + } + + /* Check if we need to validate the L4 csum */ + if (likely(dpaa2_fd_get_frc(fd) & DPAA2_FD_FRC_FASV)) { + status = le32_to_cpu(fas->status); + dpaa2_eth_validate_rx_csum(priv, status, skb); + } + + skb->protocol = eth_type_trans(skb, priv->net_dev); + skb_record_rx_queue(skb, fq->flowid); + + percpu_stats->rx_packets++; + percpu_stats->rx_bytes += dpaa2_fd_get_len(fd); + ch->stats.bytes_per_cdan += dpaa2_fd_get_len(fd); + + list_add_tail(&skb->list, ch->rx_list); +} + /* Main Rx frame processing routine */ -static void dpaa2_eth_rx(struct dpaa2_eth_priv *priv, - struct dpaa2_eth_channel *ch, - const struct dpaa2_fd *fd, - struct dpaa2_eth_fq *fq) +void dpaa2_eth_rx(struct dpaa2_eth_priv *priv, + struct dpaa2_eth_channel *ch, + const struct dpaa2_fd *fd, + struct dpaa2_eth_fq *fq) { dma_addr_t addr = dpaa2_fd_get_addr(fd); u8 fd_format = dpaa2_fd_get_format(fd); @@ -527,9 +590,7 @@ static void dpaa2_eth_rx(struct dpaa2_eth_priv *priv, struct rtnl_link_stats64 *percpu_stats; struct dpaa2_eth_drv_stats *percpu_extras; struct device *dev = priv->net_dev->dev.parent; - struct dpaa2_fas *fas; void *buf_data; - u32 status = 0; u32 xdp_act; /* Tracing point */ @@ -539,8 +600,6 @@ static void dpaa2_eth_rx(struct dpaa2_eth_priv *priv, dma_sync_single_for_cpu(dev, addr, priv->rx_buf_size, DMA_BIDIRECTIONAL); - fas = dpaa2_get_fas(vaddr, false); - prefetch(fas); buf_data = vaddr + dpaa2_fd_get_offset(fd); prefetch(buf_data); @@ -578,35 +637,7 @@ static void dpaa2_eth_rx(struct dpaa2_eth_priv *priv, if (unlikely(!skb)) goto err_build_skb; - prefetch(skb->data); - - /* Get the timestamp value */ - if (priv->rx_tstamp) { - struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb); - __le64 *ts = dpaa2_get_ts(vaddr, false); - u64 ns; - - memset(shhwtstamps, 0, sizeof(*shhwtstamps)); - - ns = DPAA2_PTP_CLK_PERIOD_NS * le64_to_cpup(ts); - shhwtstamps->hwtstamp = ns_to_ktime(ns); - } - - /* Check if we need to validate the L4 csum */ - if (likely(dpaa2_fd_get_frc(fd) & DPAA2_FD_FRC_FASV)) { - status = le32_to_cpu(fas->status); - dpaa2_eth_validate_rx_csum(priv, status, skb); - } - - skb->protocol = eth_type_trans(skb, priv->net_dev); - skb_record_rx_queue(skb, fq->flowid); - - percpu_stats->rx_packets++; - percpu_stats->rx_bytes += dpaa2_fd_get_len(fd); - ch->stats.bytes_per_cdan += dpaa2_fd_get_len(fd); - - list_add_tail(&skb->list, ch->rx_list); - + dpaa2_eth_receive_skb(priv, ch, fd, vaddr, fq, percpu_stats, skb); return; err_build_skb: @@ -827,7 +858,7 @@ static void dpaa2_eth_enable_tx_tstamp(struct dpaa2_eth_priv *priv, } } -static void *dpaa2_eth_sgt_get(struct dpaa2_eth_priv *priv) +void *dpaa2_eth_sgt_get(struct dpaa2_eth_priv *priv) { struct dpaa2_eth_sgt_cache *sgt_cache; void *sgt_buf = NULL; @@ -849,7 +880,7 @@ static void *dpaa2_eth_sgt_get(struct dpaa2_eth_priv *priv) return sgt_buf; } -static void dpaa2_eth_sgt_recycle(struct dpaa2_eth_priv *priv, void *sgt_buf) +void dpaa2_eth_sgt_recycle(struct dpaa2_eth_priv *priv, void *sgt_buf) { struct dpaa2_eth_sgt_cache *sgt_cache; @@ -1084,9 +1115,10 @@ static int dpaa2_eth_build_single_fd(struct dpaa2_eth_priv *priv, * This can be called either from dpaa2_eth_tx_conf() or on the error path of * dpaa2_eth_tx(). */ -static void dpaa2_eth_free_tx_fd(struct dpaa2_eth_priv *priv, - struct dpaa2_eth_fq *fq, - const struct dpaa2_fd *fd, bool in_napi) +void dpaa2_eth_free_tx_fd(struct dpaa2_eth_priv *priv, + struct dpaa2_eth_channel *ch, + struct dpaa2_eth_fq *fq, + const struct dpaa2_fd *fd, bool in_napi) { struct device *dev = priv->net_dev->dev.parent; dma_addr_t fd_addr, sg_addr; @@ -1153,6 +1185,10 @@ static void dpaa2_eth_free_tx_fd(struct dpaa2_eth_priv *priv, if (!swa->tso.is_last_fd) should_free_skb = 0; + } else if (swa->type == DPAA2_ETH_SWA_XSK) { + /* Unmap the SGT Buffer */ + dma_unmap_single(dev, fd_addr, swa->xsk.sgt_size, + DMA_BIDIRECTIONAL); } else { skb = swa->single.skb; @@ -1170,6 +1206,12 @@ static void dpaa2_eth_free_tx_fd(struct dpaa2_eth_priv *priv, return; } + if (swa->type == DPAA2_ETH_SWA_XSK) { + ch->xsk_tx_pkts_sent++; + dpaa2_eth_sgt_recycle(priv, buffer_start); + return; + } + if (swa->type != DPAA2_ETH_SWA_XDP && in_napi) { fq->dq_frames++; fq->dq_bytes += fd_len; @@ -1344,7 +1386,7 @@ err_alloc_tso_hdr: err_sgt_get: /* Free all the other FDs that were already fully created */ for (i = 0; i < index; i++) - dpaa2_eth_free_tx_fd(priv, NULL, &fd_start[i], false); + dpaa2_eth_free_tx_fd(priv, NULL, NULL, &fd_start[i], false); return err; } @@ -1460,7 +1502,7 @@ static netdev_tx_t __dpaa2_eth_tx(struct sk_buff *skb, if (unlikely(err < 0)) { percpu_stats->tx_errors++; /* Clean up everything, including freeing the skb */ - dpaa2_eth_free_tx_fd(priv, fq, fd, false); + dpaa2_eth_free_tx_fd(priv, NULL, fq, fd, false); netdev_tx_completed_queue(nq, 1, fd_len); } else { percpu_stats->tx_packets += total_enqueued; @@ -1553,7 +1595,7 @@ static void dpaa2_eth_tx_conf(struct dpaa2_eth_priv *priv, /* Check frame errors in the FD field */ fd_errors = dpaa2_fd_get_ctrl(fd) & DPAA2_FD_TX_ERR_MASK; - dpaa2_eth_free_tx_fd(priv, fq, fd, true); + dpaa2_eth_free_tx_fd(priv, ch, fq, fd, true); if (likely(!fd_errors)) return; @@ -1631,44 +1673,76 @@ static int dpaa2_eth_set_tx_csum(struct dpaa2_eth_priv *priv, bool enable) * to the specified buffer pool */ static int dpaa2_eth_add_bufs(struct dpaa2_eth_priv *priv, - struct dpaa2_eth_channel *ch, u16 bpid) + struct dpaa2_eth_channel *ch) { + struct xdp_buff *xdp_buffs[DPAA2_ETH_BUFS_PER_CMD]; struct device *dev = priv->net_dev->dev.parent; u64 buf_array[DPAA2_ETH_BUFS_PER_CMD]; + struct dpaa2_eth_swa *swa; struct page *page; dma_addr_t addr; int retries = 0; - int i, err; - - for (i = 0; i < DPAA2_ETH_BUFS_PER_CMD; i++) { - /* Allocate buffer visible to WRIOP + skb shared info + - * alignment padding - */ - /* allocate one page for each Rx buffer. WRIOP sees - * the entire page except for a tailroom reserved for - * skb shared info + int i = 0, err; + u32 batch; + + /* Allocate buffers visible to WRIOP */ + if (!ch->xsk_zc) { + for (i = 0; i < DPAA2_ETH_BUFS_PER_CMD; i++) { + /* Also allocate skb shared info and alignment padding. + * There is one page for each Rx buffer. WRIOP sees + * the entire page except for a tailroom reserved for + * skb shared info + */ + page = dev_alloc_pages(0); + if (!page) + goto err_alloc; + + addr = dma_map_page(dev, page, 0, priv->rx_buf_size, + DMA_BIDIRECTIONAL); + if (unlikely(dma_mapping_error(dev, addr))) + goto err_map; + + buf_array[i] = addr; + + /* tracing point */ + trace_dpaa2_eth_buf_seed(priv->net_dev, + page_address(page), + DPAA2_ETH_RX_BUF_RAW_SIZE, + addr, priv->rx_buf_size, + ch->bp->bpid); + } + } else if (xsk_buff_can_alloc(ch->xsk_pool, DPAA2_ETH_BUFS_PER_CMD)) { + /* Allocate XSK buffers for AF_XDP fast path in batches + * of DPAA2_ETH_BUFS_PER_CMD. Bail out if the UMEM cannot + * provide enough buffers at the moment */ - page = dev_alloc_pages(0); - if (!page) + batch = xsk_buff_alloc_batch(ch->xsk_pool, xdp_buffs, + DPAA2_ETH_BUFS_PER_CMD); + if (!batch) goto err_alloc; - addr = dma_map_page(dev, page, 0, priv->rx_buf_size, - DMA_BIDIRECTIONAL); - if (unlikely(dma_mapping_error(dev, addr))) - goto err_map; + for (i = 0; i < batch; i++) { + swa = (struct dpaa2_eth_swa *)(xdp_buffs[i]->data_hard_start + + DPAA2_ETH_RX_HWA_SIZE); + swa->xsk.xdp_buff = xdp_buffs[i]; + + addr = xsk_buff_xdp_get_frame_dma(xdp_buffs[i]); + if (unlikely(dma_mapping_error(dev, addr))) + goto err_map; - buf_array[i] = addr; + buf_array[i] = addr; - /* tracing point */ - trace_dpaa2_eth_buf_seed(priv->net_dev, page_address(page), - DPAA2_ETH_RX_BUF_RAW_SIZE, - addr, priv->rx_buf_size, - bpid); + trace_dpaa2_xsk_buf_seed(priv->net_dev, + xdp_buffs[i]->data_hard_start, + DPAA2_ETH_RX_BUF_RAW_SIZE, + addr, priv->rx_buf_size, + ch->bp->bpid); + } } release_bufs: /* In case the portal is busy, retry until successful */ - while ((err = dpaa2_io_service_release(ch->dpio, bpid, + while ((err = dpaa2_io_service_release(ch->dpio, ch->bp->bpid, buf_array, i)) == -EBUSY) { if (retries++ >= DPAA2_ETH_SWP_BUSY_RETRIES) break; @@ -1679,14 +1753,19 @@ release_bufs: * not much else we can do about it */ if (err) { - dpaa2_eth_free_bufs(priv, buf_array, i); + dpaa2_eth_free_bufs(priv, buf_array, i, ch->xsk_zc); return 0; } return i; err_map: - __free_pages(page, 0); + if (!ch->xsk_zc) { + __free_pages(page, 0); + } else { + for (; i < batch; i++) + xsk_buff_free(xdp_buffs[i]); + } err_alloc: /* If we managed to allocate at least some buffers, * release them to hardware @@ -1697,39 +1776,64 @@ err_alloc: return 0; } -static int dpaa2_eth_seed_pool(struct dpaa2_eth_priv *priv, u16 bpid) +static int dpaa2_eth_seed_pool(struct dpaa2_eth_priv *priv, + struct dpaa2_eth_channel *ch) { - int i, j; + int i; int new_count; - for (j = 0; j < priv->num_channels; j++) { - for (i = 0; i < DPAA2_ETH_NUM_BUFS; - i += DPAA2_ETH_BUFS_PER_CMD) { - new_count = dpaa2_eth_add_bufs(priv, priv->channel[j], bpid); - priv->channel[j]->buf_count += new_count; + for (i = 0; i < DPAA2_ETH_NUM_BUFS; i += DPAA2_ETH_BUFS_PER_CMD) { + new_count = dpaa2_eth_add_bufs(priv, ch); + ch->buf_count += new_count; - if (new_count < DPAA2_ETH_BUFS_PER_CMD) { - return -ENOMEM; - } - } + if (new_count < DPAA2_ETH_BUFS_PER_CMD) + return -ENOMEM; } return 0; } +static void dpaa2_eth_seed_pools(struct dpaa2_eth_priv *priv) +{ + struct net_device *net_dev = priv->net_dev; + struct dpaa2_eth_channel *channel; + int i, err = 0; + + for (i = 0; i < priv->num_channels; i++) { + channel = priv->channel[i]; + + err = dpaa2_eth_seed_pool(priv, channel); + + /* Not much to do; the buffer pool, though not filled up, + * may still contain some buffers which would enable us + * to limp on. + */ + if (err) + netdev_err(net_dev, "Buffer seeding failed for DPBP %d (bpid=%d)\n", + channel->bp->dev->obj_desc.id, + channel->bp->bpid); + } +} + /* - * Drain the specified number of buffers from the DPNI's private buffer pool. + * Drain the specified number of buffers from one of the DPNI's private buffer + * pools. * @count must not exceeed DPAA2_ETH_BUFS_PER_CMD */ -static void dpaa2_eth_drain_bufs(struct dpaa2_eth_priv *priv, int count) +static void dpaa2_eth_drain_bufs(struct dpaa2_eth_priv *priv, int bpid, + int count) { u64 buf_array[DPAA2_ETH_BUFS_PER_CMD]; + bool xsk_zc = false; int retries = 0; - int ret; + int i, ret; + + for (i = 0; i < priv->num_channels; i++) + if (priv->channel[i]->bp->bpid == bpid) + xsk_zc = priv->channel[i]->xsk_zc; do { - ret = dpaa2_io_service_acquire(NULL, priv->bpid, - buf_array, count); + ret = dpaa2_io_service_acquire(NULL, bpid, buf_array, count); if (ret < 0) { if (ret == -EBUSY && retries++ < DPAA2_ETH_SWP_BUSY_RETRIES) @@ -1737,28 +1841,40 @@ static void dpaa2_eth_drain_bufs(struct dpaa2_eth_priv *priv, int count) netdev_err(priv->net_dev, "dpaa2_io_service_acquire() failed\n"); return; } - dpaa2_eth_free_bufs(priv, buf_array, ret); + dpaa2_eth_free_bufs(priv, buf_array, ret, xsk_zc); retries = 0; } while (ret); } -static void dpaa2_eth_drain_pool(struct dpaa2_eth_priv *priv) +static void dpaa2_eth_drain_pool(struct dpaa2_eth_priv *priv, int bpid) { int i; - dpaa2_eth_drain_bufs(priv, DPAA2_ETH_BUFS_PER_CMD); - dpaa2_eth_drain_bufs(priv, 1); + /* Drain the buffer pool */ + dpaa2_eth_drain_bufs(priv, bpid, DPAA2_ETH_BUFS_PER_CMD); + dpaa2_eth_drain_bufs(priv, bpid, 1); + /* Setup to zero the buffer count of all channels which were + * using this buffer pool. + */ for (i = 0; i < priv->num_channels; i++) - priv->channel[i]->buf_count = 0; + if (priv->channel[i]->bp->bpid == bpid) + priv->channel[i]->buf_count = 0; +} + +static void dpaa2_eth_drain_pools(struct dpaa2_eth_priv *priv) +{ + int i; + + for (i = 0; i < priv->num_bps; i++) + dpaa2_eth_drain_pool(priv, priv->bp[i]->bpid); } /* Function is called from softirq context only, so we don't need to guard * the access to percpu count */ static int dpaa2_eth_refill_pool(struct dpaa2_eth_priv *priv, - struct dpaa2_eth_channel *ch, - u16 bpid) + struct dpaa2_eth_channel *ch) { int new_count; @@ -1766,7 +1882,7 @@ static int dpaa2_eth_refill_pool(struct dpaa2_eth_priv *priv, return 0; do { - new_count = dpaa2_eth_add_bufs(priv, ch, bpid); + new_count = dpaa2_eth_add_bufs(priv, ch); if (unlikely(!new_count)) { /* Out of memory; abort for now, we'll try later on */ break; @@ -1830,6 +1946,7 @@ static int dpaa2_eth_poll(struct napi_struct *napi, int budget) struct dpaa2_eth_fq *fq, *txc_fq = NULL; struct netdev_queue *nq; int store_cleaned, work_done; + bool work_done_zc = false; struct list_head rx_list; int retries = 0; u16 flowid; @@ -1842,13 +1959,22 @@ static int dpaa2_eth_poll(struct napi_struct *napi, int budget) INIT_LIST_HEAD(&rx_list); ch->rx_list = &rx_list; + if (ch->xsk_zc) { + work_done_zc = dpaa2_xsk_tx(priv, ch); + /* If we reached the XSK Tx per NAPI threshold, we're done */ + if (work_done_zc) { + work_done = budget; + goto out; + } + } + do { err = dpaa2_eth_pull_channel(ch); if (unlikely(err)) break; /* Refill pool if appropriate */ - dpaa2_eth_refill_pool(priv, ch, priv->bpid); + dpaa2_eth_refill_pool(priv, ch); store_cleaned = dpaa2_eth_consume_frames(ch, &fq); if (store_cleaned <= 0) @@ -1894,6 +2020,11 @@ static int dpaa2_eth_poll(struct napi_struct *napi, int budget) out: netif_receive_skb_list(ch->rx_list); + if (ch->xsk_tx_pkts_sent) { + xsk_tx_completed(ch->xsk_pool, ch->xsk_tx_pkts_sent); + ch->xsk_tx_pkts_sent = 0; + } + if (txc_fq && txc_fq->dq_frames) { nq = netdev_get_tx_queue(priv->net_dev, txc_fq->flowid); netdev_tx_completed_queue(nq, txc_fq->dq_frames, @@ -2047,15 +2178,7 @@ static int dpaa2_eth_open(struct net_device *net_dev) struct dpaa2_eth_priv *priv = netdev_priv(net_dev); int err; - err = dpaa2_eth_seed_pool(priv, priv->bpid); - if (err) { - /* Not much to do; the buffer pool, though not filled up, - * may still contain some buffers which would enable us - * to limp on. - */ - netdev_err(net_dev, "Buffer seeding failed for DPBP %d (bpid=%d)\n", - priv->dpbp_dev->obj_desc.id, priv->bpid); - } + dpaa2_eth_seed_pools(priv); if (!dpaa2_eth_is_type_phy(priv)) { /* We'll only start the txqs when the link is actually ready; @@ -2088,7 +2211,7 @@ static int dpaa2_eth_open(struct net_device *net_dev) enable_err: dpaa2_eth_disable_ch_napi(priv); - dpaa2_eth_drain_pool(priv); + dpaa2_eth_drain_pools(priv); return err; } @@ -2193,7 +2316,7 @@ static int dpaa2_eth_stop(struct net_device *net_dev) dpaa2_eth_disable_ch_napi(priv); /* Empty the buffer pool */ - dpaa2_eth_drain_pool(priv); + dpaa2_eth_drain_pools(priv); /* Empty the Scatter-Gather Buffer cache */ dpaa2_eth_sgt_cache_drain(priv); @@ -2602,7 +2725,7 @@ static int dpaa2_eth_setup_xdp(struct net_device *dev, struct bpf_prog *prog) need_update = (!!priv->xdp_prog != !!prog); if (up) - dpaa2_eth_stop(dev); + dev_close(dev); /* While in xdp mode, enforce a maximum Rx frame size based on MTU. * Also, when switching between xdp/non-xdp modes we need to reconfigure @@ -2630,7 +2753,7 @@ static int dpaa2_eth_setup_xdp(struct net_device *dev, struct bpf_prog *prog) } if (up) { - err = dpaa2_eth_open(dev); + err = dev_open(dev, NULL); if (err) return err; } @@ -2641,7 +2764,7 @@ out_err: if (prog) bpf_prog_sub(prog, priv->num_channels); if (up) - dpaa2_eth_open(dev); + dev_open(dev, NULL); return err; } @@ -2651,6 +2774,8 @@ static int dpaa2_eth_xdp(struct net_device *dev, struct netdev_bpf *xdp) switch (xdp->command) { case XDP_SETUP_PROG: return dpaa2_eth_setup_xdp(dev, xdp->prog); + case XDP_SETUP_XSK_POOL: + return dpaa2_xsk_setup_pool(dev, xdp->xsk.pool, xdp->xsk.queue_id); default: return -EINVAL; } @@ -2881,6 +3006,7 @@ static const struct net_device_ops dpaa2_eth_ops = { .ndo_change_mtu = dpaa2_eth_change_mtu, .ndo_bpf = dpaa2_eth_xdp, .ndo_xdp_xmit = dpaa2_eth_xdp_xmit, + .ndo_xsk_wakeup = dpaa2_xsk_wakeup, .ndo_setup_tc = dpaa2_eth_setup_tc, .ndo_vlan_rx_add_vid = dpaa2_eth_rx_add_vid, .ndo_vlan_rx_kill_vid = dpaa2_eth_rx_kill_vid @@ -2895,7 +3021,11 @@ static void dpaa2_eth_cdan_cb(struct dpaa2_io_notification_ctx *ctx) /* Update NAPI statistics */ ch->stats.cdan++; - napi_schedule(&ch->napi); + /* NAPI can also be scheduled from the AF_XDP Tx path. Mark a missed + * so that it can be rescheduled again. + */ + if (!napi_if_scheduled_mark_missed(&ch->napi)) + napi_schedule(&ch->napi); } /* Allocate and configure a DPCON object */ @@ -3204,13 +3334,14 @@ static void dpaa2_eth_setup_fqs(struct dpaa2_eth_priv *priv) dpaa2_eth_set_fq_affinity(priv); } -/* Allocate and configure one buffer pool for each interface */ -static int dpaa2_eth_setup_dpbp(struct dpaa2_eth_priv *priv) +/* Allocate and configure a buffer pool */ +struct dpaa2_eth_bp *dpaa2_eth_allocate_dpbp(struct dpaa2_eth_priv *priv) { - int err; - struct fsl_mc_device *dpbp_dev; struct device *dev = priv->net_dev->dev.parent; + struct fsl_mc_device *dpbp_dev; struct dpbp_attr dpbp_attrs; + struct dpaa2_eth_bp *bp; + int err; err = fsl_mc_object_allocate(to_fsl_mc_device(dev), FSL_MC_POOL_DPBP, &dpbp_dev); @@ -3219,12 +3350,16 @@ static int dpaa2_eth_setup_dpbp(struct dpaa2_eth_priv *priv) err = -EPROBE_DEFER; else dev_err(dev, "DPBP device allocation failed\n"); - return err; + return ERR_PTR(err); } - priv->dpbp_dev = dpbp_dev; + bp = kzalloc(sizeof(*bp), GFP_KERNEL); + if (!bp) { + err = -ENOMEM; + goto err_alloc; + } - err = dpbp_open(priv->mc_io, 0, priv->dpbp_dev->obj_desc.id, + err = dpbp_open(priv->mc_io, 0, dpbp_dev->obj_desc.id, &dpbp_dev->mc_handle); if (err) { dev_err(dev, "dpbp_open() failed\n"); @@ -3249,9 +3384,11 @@ static int dpaa2_eth_setup_dpbp(struct dpaa2_eth_priv *priv) dev_err(dev, "dpbp_get_attributes() failed\n"); goto err_get_attr; } - priv->bpid = dpbp_attrs.bpid; - return 0; + bp->dev = dpbp_dev; + bp->bpid = dpbp_attrs.bpid; + + return bp; err_get_attr: dpbp_disable(priv->mc_io, 0, dpbp_dev->mc_handle); @@ -3259,17 +3396,58 @@ err_enable: err_reset: dpbp_close(priv->mc_io, 0, dpbp_dev->mc_handle); err_open: + kfree(bp); +err_alloc: fsl_mc_object_free(dpbp_dev); - return err; + return ERR_PTR(err); } -static void dpaa2_eth_free_dpbp(struct dpaa2_eth_priv *priv) +static int dpaa2_eth_setup_default_dpbp(struct dpaa2_eth_priv *priv) { - dpaa2_eth_drain_pool(priv); - dpbp_disable(priv->mc_io, 0, priv->dpbp_dev->mc_handle); - dpbp_close(priv->mc_io, 0, priv->dpbp_dev->mc_handle); - fsl_mc_object_free(priv->dpbp_dev); + struct dpaa2_eth_bp *bp; + int i; + + bp = dpaa2_eth_allocate_dpbp(priv); + if (IS_ERR(bp)) + return PTR_ERR(bp); + + priv->bp[DPAA2_ETH_DEFAULT_BP_IDX] = bp; + priv->num_bps++; + + for (i = 0; i < priv->num_channels; i++) + priv->channel[i]->bp = bp; + + return 0; +} + +void dpaa2_eth_free_dpbp(struct dpaa2_eth_priv *priv, struct dpaa2_eth_bp *bp) +{ + int idx_bp; + + /* Find the index at which this BP is stored */ + for (idx_bp = 0; idx_bp < priv->num_bps; idx_bp++) + if (priv->bp[idx_bp] == bp) + break; + + /* Drain the pool and disable the associated MC object */ + dpaa2_eth_drain_pool(priv, bp->bpid); + dpbp_disable(priv->mc_io, 0, bp->dev->mc_handle); + dpbp_close(priv->mc_io, 0, bp->dev->mc_handle); + fsl_mc_object_free(bp->dev); + kfree(bp); + + /* Move the last in use DPBP over in this position */ + priv->bp[idx_bp] = priv->bp[priv->num_bps - 1]; + priv->num_bps--; +} + +static void dpaa2_eth_free_dpbps(struct dpaa2_eth_priv *priv) +{ + int i; + + for (i = 0; i < priv->num_bps; i++) + dpaa2_eth_free_dpbp(priv, priv->bp[i]); } static int dpaa2_eth_set_buffer_layout(struct dpaa2_eth_priv *priv) @@ -4154,15 +4332,16 @@ out: */ static int dpaa2_eth_bind_dpni(struct dpaa2_eth_priv *priv) { + struct dpaa2_eth_bp *bp = priv->bp[DPAA2_ETH_DEFAULT_BP_IDX]; struct net_device *net_dev = priv->net_dev; + struct dpni_pools_cfg pools_params = { 0 }; struct device *dev = net_dev->dev.parent; - struct dpni_pools_cfg pools_params; struct dpni_error_cfg err_cfg; int err = 0; int i; pools_params.num_dpbp = 1; - pools_params.pools[0].dpbp_id = priv->dpbp_dev->obj_desc.id; + pools_params.pools[0].dpbp_id = bp->dev->obj_desc.id; pools_params.pools[0].backup_pool = 0; pools_params.pools[0].buffer_size = priv->rx_buf_size; err = dpni_set_pools(priv->mc_io, 0, priv->mc_token, &pools_params); @@ -4641,7 +4820,7 @@ static int dpaa2_eth_probe(struct fsl_mc_device *dpni_dev) dpaa2_eth_setup_fqs(priv); - err = dpaa2_eth_setup_dpbp(priv); + err = dpaa2_eth_setup_default_dpbp(priv); if (err) goto err_dpbp_setup; @@ -4777,7 +4956,7 @@ err_alloc_percpu_extras: err_alloc_percpu_stats: dpaa2_eth_del_ch_napi(priv); err_bind: - dpaa2_eth_free_dpbp(priv); + dpaa2_eth_free_dpbps(priv); err_dpbp_setup: dpaa2_eth_free_dpio(priv); err_dpio_setup: @@ -4830,7 +5009,7 @@ static int dpaa2_eth_remove(struct fsl_mc_device *ls_dev) free_percpu(priv->percpu_extras); dpaa2_eth_del_ch_napi(priv); - dpaa2_eth_free_dpbp(priv); + dpaa2_eth_free_dpbps(priv); dpaa2_eth_free_dpio(priv); dpaa2_eth_free_dpni(priv); if (priv->onestep_reg_base) diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h index 447718483ef4..5d0fc432e5b2 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ /* Copyright 2014-2016 Freescale Semiconductor Inc. - * Copyright 2016-2020 NXP + * Copyright 2016-2022 NXP */ #ifndef __DPAA2_ETH_H @@ -53,6 +53,12 @@ */ #define DPAA2_ETH_TXCONF_PER_NAPI 256 +/* Maximum number of Tx frames to be processed in a single NAPI + * call when AF_XDP is running. Bind it to DPAA2_ETH_TXCONF_PER_NAPI + * to maximize the throughput. + */ +#define DPAA2_ETH_TX_ZC_PER_NAPI DPAA2_ETH_TXCONF_PER_NAPI + /* Buffer qouta per channel. We want to keep in check number of ingress frames * in flight: for small sized frames, congestion group taildrop may kick in * first; for large sizes, Rx FQ taildrop threshold will ensure only a @@ -109,6 +115,14 @@ #define DPAA2_ETH_RX_BUF_ALIGN_REV1 256 #define DPAA2_ETH_RX_BUF_ALIGN 64 +/* The firmware allows assigning multiple buffer pools to a single DPNI - + * maximum 8 DPBP objects. By default, only the first DPBP (idx 0) is used for + * all queues. Thus, when enabling AF_XDP we must accommodate up to 9 DPBPs + * object: the default and 8 other distinct buffer pools, one for each queue. + */ +#define DPAA2_ETH_DEFAULT_BP_IDX 0 +#define DPAA2_ETH_MAX_BPS 9 + /* We are accommodating a skb backpointer and some S/G info * in the frame's software annotation. The hardware * options are either 0 or 64, so we choose the latter. @@ -122,6 +136,7 @@ enum dpaa2_eth_swa_type { DPAA2_ETH_SWA_SINGLE, DPAA2_ETH_SWA_SG, DPAA2_ETH_SWA_XDP, + DPAA2_ETH_SWA_XSK, DPAA2_ETH_SWA_SW_TSO, }; @@ -144,6 +159,10 @@ struct dpaa2_eth_swa { struct xdp_frame *xdpf; } xdp; struct { + struct xdp_buff *xdp_buff; + int sgt_size; + } xsk; + struct { struct sk_buff *skb; int num_sg; int sgt_size; @@ -421,12 +440,19 @@ enum dpaa2_eth_fq_type { }; struct dpaa2_eth_priv; +struct dpaa2_eth_channel; +struct dpaa2_eth_fq; struct dpaa2_eth_xdp_fds { struct dpaa2_fd fds[DEV_MAP_BULK_SIZE]; ssize_t num; }; +typedef void dpaa2_eth_consume_cb_t(struct dpaa2_eth_priv *priv, + struct dpaa2_eth_channel *ch, + const struct dpaa2_fd *fd, + struct dpaa2_eth_fq *fq); + struct dpaa2_eth_fq { u32 fqid; u32 tx_qdbin; @@ -439,10 +465,7 @@ struct dpaa2_eth_fq { struct dpaa2_eth_channel *channel; enum dpaa2_eth_fq_type type; - void (*consume)(struct dpaa2_eth_priv *priv, - struct dpaa2_eth_channel *ch, - const struct dpaa2_fd *fd, - struct dpaa2_eth_fq *fq); + dpaa2_eth_consume_cb_t *consume; struct dpaa2_eth_fq_stats stats; struct dpaa2_eth_xdp_fds xdp_redirect_fds; @@ -454,6 +477,11 @@ struct dpaa2_eth_ch_xdp { unsigned int res; }; +struct dpaa2_eth_bp { + struct fsl_mc_device *dev; + int bpid; +}; + struct dpaa2_eth_channel { struct dpaa2_io_notification_ctx nctx; struct fsl_mc_device *dpcon; @@ -472,6 +500,11 @@ struct dpaa2_eth_channel { /* Buffers to be recycled back in the buffer pool */ u64 recycled_bufs[DPAA2_ETH_BUFS_PER_CMD]; int recycled_bufs_cnt; + + bool xsk_zc; + int xsk_tx_pkts_sent; + struct xsk_buff_pool *xsk_pool; + struct dpaa2_eth_bp *bp; }; struct dpaa2_eth_dist_fields { @@ -506,7 +539,7 @@ struct dpaa2_eth_trap_data { #define DPAA2_ETH_DEFAULT_COPYBREAK 512 -#define DPAA2_ETH_ENQUEUE_MAX_FDS 200 +#define DPAA2_ETH_ENQUEUE_MAX_FDS 256 struct dpaa2_eth_fds { struct dpaa2_fd array[DPAA2_ETH_ENQUEUE_MAX_FDS]; }; @@ -535,14 +568,16 @@ struct dpaa2_eth_priv { u8 ptp_correction_off; void (*dpaa2_set_onestep_params_cb)(struct dpaa2_eth_priv *priv, u32 offset, u8 udp); - struct fsl_mc_device *dpbp_dev; u16 rx_buf_size; - u16 bpid; struct iommu_domain *iommu_domain; enum hwtstamp_tx_types tx_tstamp_type; /* Tx timestamping type */ bool rx_tstamp; /* Rx timestamping enabled */ + /* Buffer pool management */ + struct dpaa2_eth_bp *bp[DPAA2_ETH_MAX_BPS]; + int num_bps; + u16 tx_qdid; struct fsl_mc_io *mc_io; /* Cores which have an affine DPIO/DPCON. @@ -771,4 +806,54 @@ void dpaa2_eth_dl_traps_unregister(struct dpaa2_eth_priv *priv); struct dpaa2_eth_trap_item *dpaa2_eth_dl_get_trap(struct dpaa2_eth_priv *priv, struct dpaa2_fapr *fapr); + +struct dpaa2_eth_bp *dpaa2_eth_allocate_dpbp(struct dpaa2_eth_priv *priv); +void dpaa2_eth_free_dpbp(struct dpaa2_eth_priv *priv, struct dpaa2_eth_bp *bp); + +struct sk_buff *dpaa2_eth_alloc_skb(struct dpaa2_eth_priv *priv, + struct dpaa2_eth_channel *ch, + const struct dpaa2_fd *fd, u32 fd_length, + void *fd_vaddr); + +void dpaa2_eth_receive_skb(struct dpaa2_eth_priv *priv, + struct dpaa2_eth_channel *ch, + const struct dpaa2_fd *fd, void *vaddr, + struct dpaa2_eth_fq *fq, + struct rtnl_link_stats64 *percpu_stats, + struct sk_buff *skb); + +void dpaa2_eth_rx(struct dpaa2_eth_priv *priv, + struct dpaa2_eth_channel *ch, + const struct dpaa2_fd *fd, + struct dpaa2_eth_fq *fq); + +struct dpaa2_eth_bp *dpaa2_eth_allocate_dpbp(struct dpaa2_eth_priv *priv); +void dpaa2_eth_free_dpbp(struct dpaa2_eth_priv *priv, + struct dpaa2_eth_bp *bp); + +void *dpaa2_iova_to_virt(struct iommu_domain *domain, dma_addr_t iova_addr); +void dpaa2_eth_recycle_buf(struct dpaa2_eth_priv *priv, + struct dpaa2_eth_channel *ch, + dma_addr_t addr); + +void dpaa2_eth_xdp_enqueue(struct dpaa2_eth_priv *priv, + struct dpaa2_eth_channel *ch, + struct dpaa2_fd *fd, + void *buf_start, u16 queue_id); + +int dpaa2_xsk_wakeup(struct net_device *dev, u32 qid, u32 flags); +int dpaa2_xsk_setup_pool(struct net_device *dev, struct xsk_buff_pool *pool, u16 qid); + +void dpaa2_eth_free_tx_fd(struct dpaa2_eth_priv *priv, + struct dpaa2_eth_channel *ch, + struct dpaa2_eth_fq *fq, + const struct dpaa2_fd *fd, bool in_napi); +bool dpaa2_xsk_tx(struct dpaa2_eth_priv *priv, + struct dpaa2_eth_channel *ch); + +/* SGT (Scatter-Gather Table) cache management */ +void *dpaa2_eth_sgt_get(struct dpaa2_eth_priv *priv); + +void dpaa2_eth_sgt_recycle(struct dpaa2_eth_priv *priv, void *sgt_buf); + #endif /* __DPAA2_H */ diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c index eea7d7a07c00..32a38a03db57 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) /* Copyright 2014-2016 Freescale Semiconductor Inc. - * Copyright 2016 NXP - * Copyright 2020 NXP + * Copyright 2016-2022 NXP */ #include <linux/net_tstamp.h> @@ -227,17 +226,8 @@ static void dpaa2_eth_get_ethtool_stats(struct net_device *net_dev, struct ethtool_stats *stats, u64 *data) { - int i = 0; - int j, k, err; - int num_cnt; - union dpni_statistics dpni_stats; - u32 fcnt, bcnt; - u32 fcnt_rx_total = 0, fcnt_tx_total = 0; - u32 bcnt_rx_total = 0, bcnt_tx_total = 0; - u32 buf_cnt; struct dpaa2_eth_priv *priv = netdev_priv(net_dev); - struct dpaa2_eth_drv_stats *extras; - struct dpaa2_eth_ch_stats *ch_stats; + union dpni_statistics dpni_stats; int dpni_stats_page_size[DPNI_STATISTICS_CNT] = { sizeof(dpni_stats.page_0), sizeof(dpni_stats.page_1), @@ -247,6 +237,13 @@ static void dpaa2_eth_get_ethtool_stats(struct net_device *net_dev, sizeof(dpni_stats.page_5), sizeof(dpni_stats.page_6), }; + u32 fcnt_rx_total = 0, fcnt_tx_total = 0; + u32 bcnt_rx_total = 0, bcnt_tx_total = 0; + struct dpaa2_eth_ch_stats *ch_stats; + struct dpaa2_eth_drv_stats *extras; + u32 buf_cnt, buf_cnt_total = 0; + int j, k, err, num_cnt, i = 0; + u32 fcnt, bcnt; memset(data, 0, sizeof(u64) * (DPAA2_ETH_NUM_STATS + DPAA2_ETH_NUM_EXTRA_STATS)); @@ -308,12 +305,15 @@ static void dpaa2_eth_get_ethtool_stats(struct net_device *net_dev, *(data + i++) = fcnt_tx_total; *(data + i++) = bcnt_tx_total; - err = dpaa2_io_query_bp_count(NULL, priv->bpid, &buf_cnt); - if (err) { - netdev_warn(net_dev, "Buffer count query error %d\n", err); - return; + for (j = 0; j < priv->num_bps; j++) { + err = dpaa2_io_query_bp_count(NULL, priv->bp[j]->bpid, &buf_cnt); + if (err) { + netdev_warn(net_dev, "Buffer count query error %d\n", err); + return; + } + buf_cnt_total += buf_cnt; } - *(data + i++) = buf_cnt; + *(data + i++) = buf_cnt_total; if (dpaa2_eth_has_mac(priv)) dpaa2_mac_get_ethtool_stats(priv->mac, data + i); @@ -876,6 +876,29 @@ restore_rx_usecs: return err; } +static void dpaa2_eth_get_channels(struct net_device *net_dev, + struct ethtool_channels *channels) +{ + struct dpaa2_eth_priv *priv = netdev_priv(net_dev); + int queue_count = dpaa2_eth_queue_count(priv); + + channels->max_rx = queue_count; + channels->max_tx = queue_count; + channels->rx_count = queue_count; + channels->tx_count = queue_count; + + /* Tx confirmation and Rx error */ + channels->max_other = queue_count + 1; + channels->max_combined = channels->max_rx + + channels->max_tx + + channels->max_other; + /* Tx conf and Rx err */ + channels->other_count = queue_count + 1; + channels->combined_count = channels->rx_count + + channels->tx_count + + channels->other_count; +} + const struct ethtool_ops dpaa2_ethtool_ops = { .supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS | ETHTOOL_COALESCE_USE_ADAPTIVE_RX, @@ -896,4 +919,5 @@ const struct ethtool_ops dpaa2_ethtool_ops = { .set_tunable = dpaa2_eth_set_tunable, .get_coalesce = dpaa2_eth_get_coalesce, .set_coalesce = dpaa2_eth_set_coalesce, + .get_channels = dpaa2_eth_get_channels, }; diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-xsk.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-xsk.c new file mode 100644 index 000000000000..051748b997f3 --- /dev/null +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-xsk.c @@ -0,0 +1,454 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* Copyright 2022 NXP + */ +#include <linux/filter.h> +#include <linux/compiler.h> +#include <linux/bpf_trace.h> +#include <net/xdp.h> +#include <net/xdp_sock_drv.h> + +#include "dpaa2-eth.h" + +static void dpaa2_eth_setup_consume_func(struct dpaa2_eth_priv *priv, + struct dpaa2_eth_channel *ch, + enum dpaa2_eth_fq_type type, + dpaa2_eth_consume_cb_t *consume) +{ + struct dpaa2_eth_fq *fq; + int i; + + for (i = 0; i < priv->num_fqs; i++) { + fq = &priv->fq[i]; + + if (fq->type != type) + continue; + if (fq->channel != ch) + continue; + + fq->consume = consume; + } +} + +static u32 dpaa2_xsk_run_xdp(struct dpaa2_eth_priv *priv, + struct dpaa2_eth_channel *ch, + struct dpaa2_eth_fq *rx_fq, + struct dpaa2_fd *fd, void *vaddr) +{ + dma_addr_t addr = dpaa2_fd_get_addr(fd); + struct bpf_prog *xdp_prog; + struct xdp_buff *xdp_buff; + struct dpaa2_eth_swa *swa; + u32 xdp_act = XDP_PASS; + int err; + + xdp_prog = READ_ONCE(ch->xdp.prog); + if (!xdp_prog) + goto out; + + swa = (struct dpaa2_eth_swa *)(vaddr + DPAA2_ETH_RX_HWA_SIZE + + ch->xsk_pool->umem->headroom); + xdp_buff = swa->xsk.xdp_buff; + + xdp_buff->data_hard_start = vaddr; + xdp_buff->data = vaddr + dpaa2_fd_get_offset(fd); + xdp_buff->data_end = xdp_buff->data + dpaa2_fd_get_len(fd); + xdp_set_data_meta_invalid(xdp_buff); + xdp_buff->rxq = &ch->xdp_rxq; + + xsk_buff_dma_sync_for_cpu(xdp_buff, ch->xsk_pool); + xdp_act = bpf_prog_run_xdp(xdp_prog, xdp_buff); + + /* xdp.data pointer may have changed */ + dpaa2_fd_set_offset(fd, xdp_buff->data - vaddr); + dpaa2_fd_set_len(fd, xdp_buff->data_end - xdp_buff->data); + + if (likely(xdp_act == XDP_REDIRECT)) { + err = xdp_do_redirect(priv->net_dev, xdp_buff, xdp_prog); + if (unlikely(err)) { + ch->stats.xdp_drop++; + dpaa2_eth_recycle_buf(priv, ch, addr); + } else { + ch->buf_count--; + ch->stats.xdp_redirect++; + } + + goto xdp_redir; + } + + switch (xdp_act) { + case XDP_PASS: + break; + case XDP_TX: + dpaa2_eth_xdp_enqueue(priv, ch, fd, vaddr, rx_fq->flowid); + break; + default: + bpf_warn_invalid_xdp_action(priv->net_dev, xdp_prog, xdp_act); + fallthrough; + case XDP_ABORTED: + trace_xdp_exception(priv->net_dev, xdp_prog, xdp_act); + fallthrough; + case XDP_DROP: + dpaa2_eth_recycle_buf(priv, ch, addr); + ch->stats.xdp_drop++; + break; + } + +xdp_redir: + ch->xdp.res |= xdp_act; +out: + return xdp_act; +} + +/* Rx frame processing routine for the AF_XDP fast path */ +static void dpaa2_xsk_rx(struct dpaa2_eth_priv *priv, + struct dpaa2_eth_channel *ch, + const struct dpaa2_fd *fd, + struct dpaa2_eth_fq *fq) +{ + dma_addr_t addr = dpaa2_fd_get_addr(fd); + u8 fd_format = dpaa2_fd_get_format(fd); + struct rtnl_link_stats64 *percpu_stats; + u32 fd_length = dpaa2_fd_get_len(fd); + struct sk_buff *skb; + void *vaddr; + u32 xdp_act; + + trace_dpaa2_rx_xsk_fd(priv->net_dev, fd); + + vaddr = dpaa2_iova_to_virt(priv->iommu_domain, addr); + percpu_stats = this_cpu_ptr(priv->percpu_stats); + + if (fd_format != dpaa2_fd_single) { + WARN_ON(priv->xdp_prog); + /* AF_XDP doesn't support any other formats */ + goto err_frame_format; + } + + xdp_act = dpaa2_xsk_run_xdp(priv, ch, fq, (struct dpaa2_fd *)fd, vaddr); + if (xdp_act != XDP_PASS) { + percpu_stats->rx_packets++; + percpu_stats->rx_bytes += dpaa2_fd_get_len(fd); + return; + } + + /* Build skb */ + skb = dpaa2_eth_alloc_skb(priv, ch, fd, fd_length, vaddr); + if (!skb) + /* Nothing else we can do, recycle the buffer and + * drop the frame. + */ + goto err_alloc_skb; + + /* Send the skb to the Linux networking stack */ + dpaa2_eth_receive_skb(priv, ch, fd, vaddr, fq, percpu_stats, skb); + + return; + +err_alloc_skb: + dpaa2_eth_recycle_buf(priv, ch, addr); +err_frame_format: + percpu_stats->rx_dropped++; +} + +static void dpaa2_xsk_set_bp_per_qdbin(struct dpaa2_eth_priv *priv, + struct dpni_pools_cfg *pools_params) +{ + int curr_bp = 0, i, j; + + pools_params->pool_options = DPNI_POOL_ASSOC_QDBIN; + for (i = 0; i < priv->num_bps; i++) { + for (j = 0; j < priv->num_channels; j++) + if (priv->bp[i] == priv->channel[j]->bp) + pools_params->pools[curr_bp].priority_mask |= (1 << j); + if (!pools_params->pools[curr_bp].priority_mask) + continue; + + pools_params->pools[curr_bp].dpbp_id = priv->bp[i]->bpid; + pools_params->pools[curr_bp].buffer_size = priv->rx_buf_size; + pools_params->pools[curr_bp++].backup_pool = 0; + } + pools_params->num_dpbp = curr_bp; +} + +static int dpaa2_xsk_disable_pool(struct net_device *dev, u16 qid) +{ + struct xsk_buff_pool *pool = xsk_get_pool_from_qid(dev, qid); + struct dpaa2_eth_priv *priv = netdev_priv(dev); + struct dpni_pools_cfg pools_params = { 0 }; + struct dpaa2_eth_channel *ch; + int err; + bool up; + + ch = priv->channel[qid]; + if (!ch->xsk_pool) + return -EINVAL; + + up = netif_running(dev); + if (up) + dev_close(dev); + + xsk_pool_dma_unmap(pool, 0); + err = xdp_rxq_info_reg_mem_model(&ch->xdp_rxq, + MEM_TYPE_PAGE_ORDER0, NULL); + if (err) + netdev_err(dev, "xsk_rxq_info_reg_mem_model() failed (err = %d)\n", + err); + + dpaa2_eth_free_dpbp(priv, ch->bp); + + ch->xsk_zc = false; + ch->xsk_pool = NULL; + ch->xsk_tx_pkts_sent = 0; + ch->bp = priv->bp[DPAA2_ETH_DEFAULT_BP_IDX]; + + dpaa2_eth_setup_consume_func(priv, ch, DPAA2_RX_FQ, dpaa2_eth_rx); + + dpaa2_xsk_set_bp_per_qdbin(priv, &pools_params); + err = dpni_set_pools(priv->mc_io, 0, priv->mc_token, &pools_params); + if (err) + netdev_err(dev, "dpni_set_pools() failed\n"); + + if (up) { + err = dev_open(dev, NULL); + if (err) + return err; + } + + return 0; +} + +static int dpaa2_xsk_enable_pool(struct net_device *dev, + struct xsk_buff_pool *pool, + u16 qid) +{ + struct dpaa2_eth_priv *priv = netdev_priv(dev); + struct dpni_pools_cfg pools_params = { 0 }; + struct dpaa2_eth_channel *ch; + int err, err2; + bool up; + + if (priv->dpni_attrs.wriop_version < DPAA2_WRIOP_VERSION(3, 0, 0)) { + netdev_err(dev, "AF_XDP zero-copy not supported on devices <= WRIOP(3, 0, 0)\n"); + return -EOPNOTSUPP; + } + + if (priv->dpni_attrs.num_queues > 8) { + netdev_err(dev, "AF_XDP zero-copy not supported on DPNI with more then 8 queues\n"); + return -EOPNOTSUPP; + } + + up = netif_running(dev); + if (up) + dev_close(dev); + + err = xsk_pool_dma_map(pool, priv->net_dev->dev.parent, 0); + if (err) { + netdev_err(dev, "xsk_pool_dma_map() failed (err = %d)\n", + err); + goto err_dma_unmap; + } + + ch = priv->channel[qid]; + err = xdp_rxq_info_reg_mem_model(&ch->xdp_rxq, MEM_TYPE_XSK_BUFF_POOL, NULL); + if (err) { + netdev_err(dev, "xdp_rxq_info_reg_mem_model() failed (err = %d)\n", err); + goto err_mem_model; + } + xsk_pool_set_rxq_info(pool, &ch->xdp_rxq); + + priv->bp[priv->num_bps] = dpaa2_eth_allocate_dpbp(priv); + if (IS_ERR(priv->bp[priv->num_bps])) { + err = PTR_ERR(priv->bp[priv->num_bps]); + goto err_bp_alloc; + } + ch->xsk_zc = true; + ch->xsk_pool = pool; + ch->bp = priv->bp[priv->num_bps++]; + + dpaa2_eth_setup_consume_func(priv, ch, DPAA2_RX_FQ, dpaa2_xsk_rx); + + dpaa2_xsk_set_bp_per_qdbin(priv, &pools_params); + err = dpni_set_pools(priv->mc_io, 0, priv->mc_token, &pools_params); + if (err) { + netdev_err(dev, "dpni_set_pools() failed\n"); + goto err_set_pools; + } + + if (up) { + err = dev_open(dev, NULL); + if (err) + return err; + } + + return 0; + +err_set_pools: + err2 = dpaa2_xsk_disable_pool(dev, qid); + if (err2) + netdev_err(dev, "dpaa2_xsk_disable_pool() failed %d\n", err2); +err_bp_alloc: + err2 = xdp_rxq_info_reg_mem_model(&priv->channel[qid]->xdp_rxq, + MEM_TYPE_PAGE_ORDER0, NULL); + if (err2) + netdev_err(dev, "xsk_rxq_info_reg_mem_model() failed with %d)\n", err2); +err_mem_model: + xsk_pool_dma_unmap(pool, 0); +err_dma_unmap: + if (up) + dev_open(dev, NULL); + + return err; +} + +int dpaa2_xsk_setup_pool(struct net_device *dev, struct xsk_buff_pool *pool, u16 qid) +{ + return pool ? dpaa2_xsk_enable_pool(dev, pool, qid) : + dpaa2_xsk_disable_pool(dev, qid); +} + +int dpaa2_xsk_wakeup(struct net_device *dev, u32 qid, u32 flags) +{ + struct dpaa2_eth_priv *priv = netdev_priv(dev); + struct dpaa2_eth_channel *ch = priv->channel[qid]; + + if (!priv->link_state.up) + return -ENETDOWN; + + if (!priv->xdp_prog) + return -EINVAL; + + if (!ch->xsk_zc) + return -EINVAL; + + /* We do not have access to a per channel SW interrupt, so instead we + * schedule a NAPI instance. + */ + if (!napi_if_scheduled_mark_missed(&ch->napi)) + napi_schedule(&ch->napi); + + return 0; +} + +static int dpaa2_xsk_tx_build_fd(struct dpaa2_eth_priv *priv, + struct dpaa2_eth_channel *ch, + struct dpaa2_fd *fd, + struct xdp_desc *xdp_desc) +{ + struct device *dev = priv->net_dev->dev.parent; + struct dpaa2_sg_entry *sgt; + struct dpaa2_eth_swa *swa; + void *sgt_buf = NULL; + dma_addr_t sgt_addr; + int sgt_buf_size; + dma_addr_t addr; + int err = 0; + + /* Prepare the HW SGT structure */ + sgt_buf_size = priv->tx_data_offset + sizeof(struct dpaa2_sg_entry); + sgt_buf = dpaa2_eth_sgt_get(priv); + if (unlikely(!sgt_buf)) + return -ENOMEM; + sgt = (struct dpaa2_sg_entry *)(sgt_buf + priv->tx_data_offset); + + /* Get the address of the XSK Tx buffer */ + addr = xsk_buff_raw_get_dma(ch->xsk_pool, xdp_desc->addr); + xsk_buff_raw_dma_sync_for_device(ch->xsk_pool, addr, xdp_desc->len); + + /* Fill in the HW SGT structure */ + dpaa2_sg_set_addr(sgt, addr); + dpaa2_sg_set_len(sgt, xdp_desc->len); + dpaa2_sg_set_final(sgt, true); + + /* Store the necessary info in the SGT buffer */ + swa = (struct dpaa2_eth_swa *)sgt_buf; + swa->type = DPAA2_ETH_SWA_XSK; + swa->xsk.sgt_size = sgt_buf_size; + + /* Separately map the SGT buffer */ + sgt_addr = dma_map_single(dev, sgt_buf, sgt_buf_size, DMA_BIDIRECTIONAL); + if (unlikely(dma_mapping_error(dev, sgt_addr))) { + err = -ENOMEM; + goto sgt_map_failed; + } + + /* Initialize FD fields */ + memset(fd, 0, sizeof(struct dpaa2_fd)); + dpaa2_fd_set_offset(fd, priv->tx_data_offset); + dpaa2_fd_set_format(fd, dpaa2_fd_sg); + dpaa2_fd_set_addr(fd, sgt_addr); + dpaa2_fd_set_len(fd, xdp_desc->len); + dpaa2_fd_set_ctrl(fd, FD_CTRL_PTA); + + return 0; + +sgt_map_failed: + dpaa2_eth_sgt_recycle(priv, sgt_buf); + + return err; +} + +bool dpaa2_xsk_tx(struct dpaa2_eth_priv *priv, + struct dpaa2_eth_channel *ch) +{ + struct xdp_desc *xdp_descs = ch->xsk_pool->tx_descs; + struct dpaa2_eth_drv_stats *percpu_extras; + struct rtnl_link_stats64 *percpu_stats; + int budget = DPAA2_ETH_TX_ZC_PER_NAPI; + int total_enqueued, enqueued; + int retries, max_retries; + struct dpaa2_eth_fq *fq; + struct dpaa2_fd *fds; + int batch, i, err; + + percpu_stats = this_cpu_ptr(priv->percpu_stats); + percpu_extras = this_cpu_ptr(priv->percpu_extras); + fds = (this_cpu_ptr(priv->fd))->array; + + /* Use the FQ with the same idx as the affine CPU */ + fq = &priv->fq[ch->nctx.desired_cpu]; + + batch = xsk_tx_peek_release_desc_batch(ch->xsk_pool, budget); + if (!batch) + return false; + + /* Create a FD for each XSK frame to be sent */ + for (i = 0; i < batch; i++) { + err = dpaa2_xsk_tx_build_fd(priv, ch, &fds[i], &xdp_descs[i]); + if (err) { + batch = i; + break; + } + + trace_dpaa2_tx_xsk_fd(priv->net_dev, &fds[i]); + } + + /* Enqueue all the created FDs */ + max_retries = batch * DPAA2_ETH_ENQUEUE_RETRIES; + total_enqueued = 0; + enqueued = 0; + retries = 0; + while (total_enqueued < batch && retries < max_retries) { + err = priv->enqueue(priv, fq, &fds[total_enqueued], 0, + batch - total_enqueued, &enqueued); + if (err == -EBUSY) { + retries++; + continue; + } + + total_enqueued += enqueued; + } + percpu_extras->tx_portal_busy += retries; + + /* Update statistics */ + percpu_stats->tx_packets += total_enqueued; + for (i = 0; i < total_enqueued; i++) + percpu_stats->tx_bytes += dpaa2_fd_get_len(&fds[i]); + for (i = total_enqueued; i < batch; i++) { + dpaa2_eth_free_tx_fd(priv, ch, fq, &fds[i], false); + percpu_stats->tx_errors++; + } + + xsk_tx_release(ch->xsk_pool); + + return total_enqueued == budget; +} diff --git a/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h b/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h index 828f538097af..be9492b8d5dc 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h +++ b/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h @@ -13,10 +13,12 @@ #define DPNI_VER_MINOR 0 #define DPNI_CMD_BASE_VERSION 1 #define DPNI_CMD_2ND_VERSION 2 +#define DPNI_CMD_3RD_VERSION 3 #define DPNI_CMD_ID_OFFSET 4 #define DPNI_CMD(id) (((id) << DPNI_CMD_ID_OFFSET) | DPNI_CMD_BASE_VERSION) #define DPNI_CMD_V2(id) (((id) << DPNI_CMD_ID_OFFSET) | DPNI_CMD_2ND_VERSION) +#define DPNI_CMD_V3(id) (((id) << DPNI_CMD_ID_OFFSET) | DPNI_CMD_3RD_VERSION) #define DPNI_CMDID_OPEN DPNI_CMD(0x801) #define DPNI_CMDID_CLOSE DPNI_CMD(0x800) @@ -39,7 +41,7 @@ #define DPNI_CMDID_GET_IRQ_STATUS DPNI_CMD(0x016) #define DPNI_CMDID_CLEAR_IRQ_STATUS DPNI_CMD(0x017) -#define DPNI_CMDID_SET_POOLS DPNI_CMD(0x200) +#define DPNI_CMDID_SET_POOLS DPNI_CMD_V3(0x200) #define DPNI_CMDID_SET_ERRORS_BEHAVIOR DPNI_CMD(0x20B) #define DPNI_CMDID_GET_QDID DPNI_CMD(0x210) @@ -115,14 +117,19 @@ struct dpni_cmd_open { }; #define DPNI_BACKUP_POOL(val, order) (((val) & 0x1) << (order)) + +struct dpni_cmd_pool { + __le16 dpbp_id; + u8 priority_mask; + u8 pad; +}; + struct dpni_cmd_set_pools { - /* cmd word 0 */ u8 num_dpbp; u8 backup_pool_mask; - __le16 pad; - /* cmd word 0..4 */ - __le32 dpbp_id[DPNI_MAX_DPBP]; - /* cmd word 4..6 */ + u8 pad; + u8 pool_options; + struct dpni_cmd_pool pool[DPNI_MAX_DPBP]; __le16 buffer_size[DPNI_MAX_DPBP]; }; diff --git a/drivers/net/ethernet/freescale/dpaa2/dpni.c b/drivers/net/ethernet/freescale/dpaa2/dpni.c index 6c3b36f20fb8..02601a283b59 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpni.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpni.c @@ -173,8 +173,12 @@ int dpni_set_pools(struct fsl_mc_io *mc_io, token); cmd_params = (struct dpni_cmd_set_pools *)cmd.params; cmd_params->num_dpbp = cfg->num_dpbp; + cmd_params->pool_options = cfg->pool_options; for (i = 0; i < DPNI_MAX_DPBP; i++) { - cmd_params->dpbp_id[i] = cpu_to_le32(cfg->pools[i].dpbp_id); + cmd_params->pool[i].dpbp_id = + cpu_to_le16(cfg->pools[i].dpbp_id); + cmd_params->pool[i].priority_mask = + cfg->pools[i].priority_mask; cmd_params->buffer_size[i] = cpu_to_le16(cfg->pools[i].buffer_size); cmd_params->backup_pool_mask |= diff --git a/drivers/net/ethernet/freescale/dpaa2/dpni.h b/drivers/net/ethernet/freescale/dpaa2/dpni.h index 6fffd519aa00..5c0a1d5ac934 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpni.h +++ b/drivers/net/ethernet/freescale/dpaa2/dpni.h @@ -92,19 +92,28 @@ int dpni_close(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token); +#define DPNI_POOL_ASSOC_QPRI 0 +#define DPNI_POOL_ASSOC_QDBIN 1 + /** * struct dpni_pools_cfg - Structure representing buffer pools configuration * @num_dpbp: Number of DPBPs + * @pool_options: Buffer assignment options. + * This field is a combination of DPNI_POOL_ASSOC_flags * @pools: Array of buffer pools parameters; The number of valid entries * must match 'num_dpbp' value * @pools.dpbp_id: DPBP object ID + * @pools.priority: Priority mask that indicates TC's used with this buffer. + * If set to 0x00 MC will assume value 0xff. * @pools.buffer_size: Buffer size * @pools.backup_pool: Backup pool */ struct dpni_pools_cfg { u8 num_dpbp; + u8 pool_options; struct { int dpbp_id; + u8 priority_mask; u16 buffer_size; int backup_pool; } pools[DPNI_MAX_DPBP]; diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c index 54bc92fc6bf0..f8c06c3f9464 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc.c +++ b/drivers/net/ethernet/freescale/enetc/enetc.c @@ -2090,7 +2090,12 @@ static void enetc_setup_rxbdr(struct enetc_hw *hw, struct enetc_bdr *rx_ring) else enetc_rxbdr_wr(hw, idx, ENETC_RBBSR, ENETC_RXB_DMA_SIZE); + /* Also prepare the consumer index in case page allocation never + * succeeds. In that case, hardware will never advance producer index + * to match consumer index, and will drop all frames. + */ enetc_rxbdr_wr(hw, idx, ENETC_RBPIR, 0); + enetc_rxbdr_wr(hw, idx, ENETC_RBCIR, 1); /* enable Rx ints by setting pkt thr to 1 */ enetc_rxbdr_wr(hw, idx, ENETC_RBICR0, ENETC_RBICR0_ICEN | 0x1); diff --git a/drivers/net/ethernet/freescale/enetc/enetc_qos.c b/drivers/net/ethernet/freescale/enetc/enetc_qos.c index e6416332ec79..a842e1999122 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_qos.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c @@ -7,7 +7,6 @@ #include <linux/math64.h> #include <linux/refcount.h> #include <net/pkt_cls.h> -#include <net/pkt_sched.h> #include <net/tc_act/tc_gate.h> static u16 enetc_get_max_gcl_len(struct enetc_hw *hw) diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h index 33f84a30e167..476e3863a310 100644 --- a/drivers/net/ethernet/freescale/fec.h +++ b/drivers/net/ethernet/freescale/fec.h @@ -658,6 +658,8 @@ struct fec_enet_private { unsigned int reload_period; int pps_enable; unsigned int next_counter; + struct hrtimer perout_timer; + u64 perout_stime; struct imx_sc_ipc *ipc_handle; diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 98d5cd313fdd..34566c007069 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -365,16 +365,6 @@ static void swap_buffer(void *bufaddr, int len) swab32s(buf); } -static void swap_buffer2(void *dst_buf, void *src_buf, int len) -{ - int i; - unsigned int *src = src_buf; - unsigned int *dst = dst_buf; - - for (i = 0; i < len; i += 4, src++, dst++) - *dst = swab32p(src); -} - static void fec_dump(struct net_device *ndev) { struct fec_enet_private *fep = netdev_priv(ndev); @@ -1494,53 +1484,6 @@ static void fec_enet_tx(struct net_device *ndev) fec_enet_tx_queue(ndev, i); } -static int __maybe_unused -fec_enet_new_rxbdp(struct net_device *ndev, struct bufdesc *bdp, struct sk_buff *skb) -{ - struct fec_enet_private *fep = netdev_priv(ndev); - int off; - - off = ((unsigned long)skb->data) & fep->rx_align; - if (off) - skb_reserve(skb, fep->rx_align + 1 - off); - - bdp->cbd_bufaddr = cpu_to_fec32(dma_map_single(&fep->pdev->dev, skb->data, FEC_ENET_RX_FRSIZE - fep->rx_align, DMA_FROM_DEVICE)); - if (dma_mapping_error(&fep->pdev->dev, fec32_to_cpu(bdp->cbd_bufaddr))) { - if (net_ratelimit()) - netdev_err(ndev, "Rx DMA memory map failed\n"); - return -ENOMEM; - } - - return 0; -} - -static bool __maybe_unused -fec_enet_copybreak(struct net_device *ndev, struct sk_buff **skb, - struct bufdesc *bdp, u32 length, bool swap) -{ - struct fec_enet_private *fep = netdev_priv(ndev); - struct sk_buff *new_skb; - - if (length > fep->rx_copybreak) - return false; - - new_skb = netdev_alloc_skb(ndev, length); - if (!new_skb) - return false; - - dma_sync_single_for_cpu(&fep->pdev->dev, - fec32_to_cpu(bdp->cbd_bufaddr), - FEC_ENET_RX_FRSIZE - fep->rx_align, - DMA_FROM_DEVICE); - if (!swap) - memcpy(new_skb->data, (*skb)->data, length); - else - swap_buffer2(new_skb->data, (*skb)->data, length); - *skb = new_skb; - - return true; -} - static void fec_enet_update_cbd(struct fec_enet_priv_rx_q *rxq, struct bufdesc *bdp, int index) { @@ -2432,6 +2375,31 @@ static u32 fec_enet_register_offset[] = { IEEE_R_DROP, IEEE_R_FRAME_OK, IEEE_R_CRC, IEEE_R_ALIGN, IEEE_R_MACERR, IEEE_R_FDXFC, IEEE_R_OCTETS_OK }; +/* for i.MX6ul */ +static u32 fec_enet_register_offset_6ul[] = { + FEC_IEVENT, FEC_IMASK, FEC_R_DES_ACTIVE_0, FEC_X_DES_ACTIVE_0, + FEC_ECNTRL, FEC_MII_DATA, FEC_MII_SPEED, FEC_MIB_CTRLSTAT, FEC_R_CNTRL, + FEC_X_CNTRL, FEC_ADDR_LOW, FEC_ADDR_HIGH, FEC_OPD, FEC_TXIC0, FEC_RXIC0, + FEC_HASH_TABLE_HIGH, FEC_HASH_TABLE_LOW, FEC_GRP_HASH_TABLE_HIGH, + FEC_GRP_HASH_TABLE_LOW, FEC_X_WMRK, FEC_R_DES_START_0, + FEC_X_DES_START_0, FEC_R_BUFF_SIZE_0, FEC_R_FIFO_RSFL, FEC_R_FIFO_RSEM, + FEC_R_FIFO_RAEM, FEC_R_FIFO_RAFL, FEC_RACC, + RMON_T_DROP, RMON_T_PACKETS, RMON_T_BC_PKT, RMON_T_MC_PKT, + RMON_T_CRC_ALIGN, RMON_T_UNDERSIZE, RMON_T_OVERSIZE, RMON_T_FRAG, + RMON_T_JAB, RMON_T_COL, RMON_T_P64, RMON_T_P65TO127, RMON_T_P128TO255, + RMON_T_P256TO511, RMON_T_P512TO1023, RMON_T_P1024TO2047, + RMON_T_P_GTE2048, RMON_T_OCTETS, + IEEE_T_DROP, IEEE_T_FRAME_OK, IEEE_T_1COL, IEEE_T_MCOL, IEEE_T_DEF, + IEEE_T_LCOL, IEEE_T_EXCOL, IEEE_T_MACERR, IEEE_T_CSERR, IEEE_T_SQE, + IEEE_T_FDXFC, IEEE_T_OCTETS_OK, + RMON_R_PACKETS, RMON_R_BC_PKT, RMON_R_MC_PKT, RMON_R_CRC_ALIGN, + RMON_R_UNDERSIZE, RMON_R_OVERSIZE, RMON_R_FRAG, RMON_R_JAB, + RMON_R_RESVD_O, RMON_R_P64, RMON_R_P65TO127, RMON_R_P128TO255, + RMON_R_P256TO511, RMON_R_P512TO1023, RMON_R_P1024TO2047, + RMON_R_P_GTE2048, RMON_R_OCTETS, + IEEE_R_DROP, IEEE_R_FRAME_OK, IEEE_R_CRC, IEEE_R_ALIGN, IEEE_R_MACERR, + IEEE_R_FDXFC, IEEE_R_OCTETS_OK +}; #else static __u32 fec_enet_register_version = 1; static u32 fec_enet_register_offset[] = { @@ -2456,7 +2424,24 @@ static void fec_enet_get_regs(struct net_device *ndev, u32 *buf = (u32 *)regbuf; u32 i, off; int ret; +#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ + defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_ARM) || \ + defined(CONFIG_ARM64) || defined(CONFIG_COMPILE_TEST) + u32 *reg_list; + u32 reg_cnt; + if (!of_machine_is_compatible("fsl,imx6ul")) { + reg_list = fec_enet_register_offset; + reg_cnt = ARRAY_SIZE(fec_enet_register_offset); + } else { + reg_list = fec_enet_register_offset_6ul; + reg_cnt = ARRAY_SIZE(fec_enet_register_offset_6ul); + } +#else + /* coldfire */ + static u32 *reg_list = fec_enet_register_offset; + static const u32 reg_cnt = ARRAY_SIZE(fec_enet_register_offset); +#endif ret = pm_runtime_resume_and_get(dev); if (ret < 0) return; @@ -2465,8 +2450,8 @@ static void fec_enet_get_regs(struct net_device *ndev, memset(buf, 0, regs->len); - for (i = 0; i < ARRAY_SIZE(fec_enet_register_offset); i++) { - off = fec_enet_register_offset[i]; + for (i = 0; i < reg_cnt; i++) { + off = reg_list[i]; if ((off == FEC_R_BOUND || off == FEC_R_FSTART) && !(fep->quirks & FEC_QUIRK_HAS_FRREG)) diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c index cffd9ad499dd..67aa694a62ec 100644 --- a/drivers/net/ethernet/freescale/fec_ptp.c +++ b/drivers/net/ethernet/freescale/fec_ptp.c @@ -88,6 +88,9 @@ #define FEC_CHANNLE_0 0 #define DEFAULT_PPS_CHANNEL FEC_CHANNLE_0 +#define FEC_PTP_MAX_NSEC_PERIOD 4000000000ULL +#define FEC_PTP_MAX_NSEC_COUNTER 0x80000000ULL + /** * fec_ptp_enable_pps * @fep: the fec_enet_private structure handle @@ -198,6 +201,78 @@ static int fec_ptp_enable_pps(struct fec_enet_private *fep, uint enable) return 0; } +static int fec_ptp_pps_perout(struct fec_enet_private *fep) +{ + u32 compare_val, ptp_hc, temp_val; + u64 curr_time; + unsigned long flags; + + spin_lock_irqsave(&fep->tmreg_lock, flags); + + /* Update time counter */ + timecounter_read(&fep->tc); + + /* Get the current ptp hardware time counter */ + temp_val = readl(fep->hwp + FEC_ATIME_CTRL); + temp_val |= FEC_T_CTRL_CAPTURE; + writel(temp_val, fep->hwp + FEC_ATIME_CTRL); + if (fep->quirks & FEC_QUIRK_BUG_CAPTURE) + udelay(1); + + ptp_hc = readl(fep->hwp + FEC_ATIME); + + /* Convert the ptp local counter to 1588 timestamp */ + curr_time = timecounter_cyc2time(&fep->tc, ptp_hc); + + /* If the pps start time less than current time add 100ms, just return. + * Because the software might not able to set the comparison time into + * the FEC_TCCR register in time and missed the start time. + */ + if (fep->perout_stime < curr_time + 100 * NSEC_PER_MSEC) { + dev_err(&fep->pdev->dev, "Current time is too close to the start time!\n"); + spin_unlock_irqrestore(&fep->tmreg_lock, flags); + return -1; + } + + compare_val = fep->perout_stime - curr_time + ptp_hc; + compare_val &= fep->cc.mask; + + writel(compare_val, fep->hwp + FEC_TCCR(fep->pps_channel)); + fep->next_counter = (compare_val + fep->reload_period) & fep->cc.mask; + + /* Enable compare event when overflow */ + temp_val = readl(fep->hwp + FEC_ATIME_CTRL); + temp_val |= FEC_T_CTRL_PINPER; + writel(temp_val, fep->hwp + FEC_ATIME_CTRL); + + /* Compare channel setting. */ + temp_val = readl(fep->hwp + FEC_TCSR(fep->pps_channel)); + temp_val |= (1 << FEC_T_TF_OFFSET | 1 << FEC_T_TIE_OFFSET); + temp_val &= ~(1 << FEC_T_TDRE_OFFSET); + temp_val &= ~(FEC_T_TMODE_MASK); + temp_val |= (FEC_TMODE_TOGGLE << FEC_T_TMODE_OFFSET); + writel(temp_val, fep->hwp + FEC_TCSR(fep->pps_channel)); + + /* Write the second compare event timestamp and calculate + * the third timestamp. Refer the TCCR register detail in the spec. + */ + writel(fep->next_counter, fep->hwp + FEC_TCCR(fep->pps_channel)); + fep->next_counter = (fep->next_counter + fep->reload_period) & fep->cc.mask; + spin_unlock_irqrestore(&fep->tmreg_lock, flags); + + return 0; +} + +static enum hrtimer_restart fec_ptp_pps_perout_handler(struct hrtimer *timer) +{ + struct fec_enet_private *fep = container_of(timer, + struct fec_enet_private, perout_timer); + + fec_ptp_pps_perout(fep); + + return HRTIMER_NORESTART; +} + /** * fec_ptp_read - read raw cycle counter (to be used by time counter) * @cc: the cyclecounter structure @@ -425,6 +500,17 @@ static int fec_ptp_settime(struct ptp_clock_info *ptp, return 0; } +static int fec_ptp_pps_disable(struct fec_enet_private *fep, uint channel) +{ + unsigned long flags; + + spin_lock_irqsave(&fep->tmreg_lock, flags); + writel(0, fep->hwp + FEC_TCSR(channel)); + spin_unlock_irqrestore(&fep->tmreg_lock, flags); + + return 0; +} + /** * fec_ptp_enable * @ptp: the ptp clock structure @@ -437,14 +523,84 @@ static int fec_ptp_enable(struct ptp_clock_info *ptp, { struct fec_enet_private *fep = container_of(ptp, struct fec_enet_private, ptp_caps); + ktime_t timeout; + struct timespec64 start_time, period; + u64 curr_time, delta, period_ns; + unsigned long flags; int ret = 0; if (rq->type == PTP_CLK_REQ_PPS) { ret = fec_ptp_enable_pps(fep, on); return ret; + } else if (rq->type == PTP_CLK_REQ_PEROUT) { + /* Reject requests with unsupported flags */ + if (rq->perout.flags) + return -EOPNOTSUPP; + + if (rq->perout.index != DEFAULT_PPS_CHANNEL) + return -EOPNOTSUPP; + + fep->pps_channel = DEFAULT_PPS_CHANNEL; + period.tv_sec = rq->perout.period.sec; + period.tv_nsec = rq->perout.period.nsec; + period_ns = timespec64_to_ns(&period); + + /* FEC PTP timer only has 31 bits, so if the period exceed + * 4s is not supported. + */ + if (period_ns > FEC_PTP_MAX_NSEC_PERIOD) { + dev_err(&fep->pdev->dev, "The period must equal to or less than 4s!\n"); + return -EOPNOTSUPP; + } + + fep->reload_period = div_u64(period_ns, 2); + if (on && fep->reload_period) { + /* Convert 1588 timestamp to ns*/ + start_time.tv_sec = rq->perout.start.sec; + start_time.tv_nsec = rq->perout.start.nsec; + fep->perout_stime = timespec64_to_ns(&start_time); + + mutex_lock(&fep->ptp_clk_mutex); + if (!fep->ptp_clk_on) { + dev_err(&fep->pdev->dev, "Error: PTP clock is closed!\n"); + mutex_unlock(&fep->ptp_clk_mutex); + return -EOPNOTSUPP; + } + spin_lock_irqsave(&fep->tmreg_lock, flags); + /* Read current timestamp */ + curr_time = timecounter_read(&fep->tc); + spin_unlock_irqrestore(&fep->tmreg_lock, flags); + mutex_unlock(&fep->ptp_clk_mutex); + + /* Calculate time difference */ + delta = fep->perout_stime - curr_time; + + if (fep->perout_stime <= curr_time) { + dev_err(&fep->pdev->dev, "Start time must larger than current time!\n"); + return -EINVAL; + } + + /* Because the timer counter of FEC only has 31-bits, correspondingly, + * the time comparison register FEC_TCCR also only low 31 bits can be + * set. If the start time of pps signal exceeds current time more than + * 0x80000000 ns, a software timer is used and the timer expires about + * 1 second before the start time to be able to set FEC_TCCR. + */ + if (delta > FEC_PTP_MAX_NSEC_COUNTER) { + timeout = ns_to_ktime(delta - NSEC_PER_SEC); + hrtimer_start(&fep->perout_timer, timeout, HRTIMER_MODE_REL); + } else { + return fec_ptp_pps_perout(fep); + } + } else { + fec_ptp_pps_disable(fep, fep->pps_channel); + } + + return 0; + } else { + return -EOPNOTSUPP; } - return -EOPNOTSUPP; } /** @@ -583,7 +739,7 @@ void fec_ptp_init(struct platform_device *pdev, int irq_idx) fep->ptp_caps.max_adj = 250000000; fep->ptp_caps.n_alarm = 0; fep->ptp_caps.n_ext_ts = 0; - fep->ptp_caps.n_per_out = 0; + fep->ptp_caps.n_per_out = 1; fep->ptp_caps.n_pins = 0; fep->ptp_caps.pps = 1; fep->ptp_caps.adjfreq = fec_ptp_adjfreq; @@ -605,6 +761,9 @@ void fec_ptp_init(struct platform_device *pdev, int irq_idx) INIT_DELAYED_WORK(&fep->time_keep, fec_time_keep); + hrtimer_init(&fep->perout_timer, CLOCK_REALTIME, HRTIMER_MODE_REL); + fep->perout_timer.function = fec_ptp_pps_perout_handler; + irq = platform_get_irq_byname_optional(pdev, "pps"); if (irq < 0) irq = platform_get_irq_optional(pdev, irq_idx); @@ -634,6 +793,7 @@ void fec_ptp_stop(struct platform_device *pdev) struct fec_enet_private *fep = netdev_priv(ndev); cancel_delayed_work_sync(&fep->time_keep); + hrtimer_cancel(&fep->perout_timer); if (fep->ptp_clock) ptp_clock_unregister(fep->ptp_clock); } diff --git a/drivers/net/ethernet/freescale/fman/Kconfig b/drivers/net/ethernet/freescale/fman/Kconfig index 48bf8088795d..e76a3d262b2b 100644 --- a/drivers/net/ethernet/freescale/fman/Kconfig +++ b/drivers/net/ethernet/freescale/fman/Kconfig @@ -3,7 +3,9 @@ config FSL_FMAN tristate "FMan support" depends on FSL_SOC || ARCH_LAYERSCAPE || COMPILE_TEST select GENERIC_ALLOCATOR - select PHYLIB + select PHYLINK + select PCS + select PCS_LYNX select CRC32 default n help diff --git a/drivers/net/ethernet/freescale/fman/fman_dtsec.c b/drivers/net/ethernet/freescale/fman/fman_dtsec.c index 6617932fd3fd..3c87820ca202 100644 --- a/drivers/net/ethernet/freescale/fman/fman_dtsec.c +++ b/drivers/net/ethernet/freescale/fman/fman_dtsec.c @@ -17,6 +17,7 @@ #include <linux/crc32.h> #include <linux/of_mdio.h> #include <linux/mii.h> +#include <linux/netdevice.h> /* TBI register addresses */ #define MII_TBICON 0x11 @@ -29,9 +30,6 @@ #define TBICON_CLK_SELECT 0x0020 /* Clock select */ #define TBICON_MI_MODE 0x0010 /* GMII mode (TBI if not set) */ -#define TBIANA_SGMII 0x4001 -#define TBIANA_1000X 0x01a0 - /* Interrupt Mask Register (IMASK) */ #define DTSEC_IMASK_BREN 0x80000000 #define DTSEC_IMASK_RXCEN 0x40000000 @@ -92,9 +90,10 @@ #define DTSEC_ECNTRL_GMIIM 0x00000040 #define DTSEC_ECNTRL_TBIM 0x00000020 -#define DTSEC_ECNTRL_SGMIIM 0x00000002 #define DTSEC_ECNTRL_RPM 0x00000010 #define DTSEC_ECNTRL_R100M 0x00000008 +#define DTSEC_ECNTRL_RMM 0x00000004 +#define DTSEC_ECNTRL_SGMIIM 0x00000002 #define DTSEC_ECNTRL_QSGMIIM 0x00000001 #define TCTRL_TTSE 0x00000040 @@ -318,7 +317,8 @@ struct fman_mac { void *fm; struct fman_rev_info fm_rev_info; bool basex_if; - struct phy_device *tbiphy; + struct mdio_device *tbidev; + struct phylink_pcs pcs; }; static void set_dflts(struct dtsec_cfg *cfg) @@ -356,56 +356,14 @@ static int init(struct dtsec_regs __iomem *regs, struct dtsec_cfg *cfg, phy_interface_t iface, u16 iface_speed, u64 addr, u32 exception_mask, u8 tbi_addr) { - bool is_rgmii, is_sgmii, is_qsgmii; enet_addr_t eth_addr; - u32 tmp; + u32 tmp = 0; int i; /* Soft reset */ iowrite32be(MACCFG1_SOFT_RESET, ®s->maccfg1); iowrite32be(0, ®s->maccfg1); - /* dtsec_id2 */ - tmp = ioread32be(®s->tsec_id2); - - /* check RGMII support */ - if (iface == PHY_INTERFACE_MODE_RGMII || - iface == PHY_INTERFACE_MODE_RGMII_ID || - iface == PHY_INTERFACE_MODE_RGMII_RXID || - iface == PHY_INTERFACE_MODE_RGMII_TXID || - iface == PHY_INTERFACE_MODE_RMII) - if (tmp & DTSEC_ID2_INT_REDUCED_OFF) - return -EINVAL; - - if (iface == PHY_INTERFACE_MODE_SGMII || - iface == PHY_INTERFACE_MODE_MII) - if (tmp & DTSEC_ID2_INT_REDUCED_OFF) - return -EINVAL; - - is_rgmii = iface == PHY_INTERFACE_MODE_RGMII || - iface == PHY_INTERFACE_MODE_RGMII_ID || - iface == PHY_INTERFACE_MODE_RGMII_RXID || - iface == PHY_INTERFACE_MODE_RGMII_TXID; - is_sgmii = iface == PHY_INTERFACE_MODE_SGMII; - is_qsgmii = iface == PHY_INTERFACE_MODE_QSGMII; - - tmp = 0; - if (is_rgmii || iface == PHY_INTERFACE_MODE_GMII) - tmp |= DTSEC_ECNTRL_GMIIM; - if (is_sgmii) - tmp |= (DTSEC_ECNTRL_SGMIIM | DTSEC_ECNTRL_TBIM); - if (is_qsgmii) - tmp |= (DTSEC_ECNTRL_SGMIIM | DTSEC_ECNTRL_TBIM | - DTSEC_ECNTRL_QSGMIIM); - if (is_rgmii) - tmp |= DTSEC_ECNTRL_RPM; - if (iface_speed == SPEED_100) - tmp |= DTSEC_ECNTRL_R100M; - - iowrite32be(tmp, ®s->ecntrl); - - tmp = 0; - if (cfg->tx_pause_time) tmp |= cfg->tx_pause_time; if (cfg->tx_pause_time_extd) @@ -446,17 +404,10 @@ static int init(struct dtsec_regs __iomem *regs, struct dtsec_cfg *cfg, tmp = 0; - if (iface_speed < SPEED_1000) - tmp |= MACCFG2_NIBBLE_MODE; - else if (iface_speed == SPEED_1000) - tmp |= MACCFG2_BYTE_MODE; - tmp |= (cfg->preamble_len << MACCFG2_PREAMBLE_LENGTH_SHIFT) & MACCFG2_PREAMBLE_LENGTH_MASK; if (cfg->tx_pad_crc) tmp |= MACCFG2_PAD_CRC_EN; - /* Full Duplex */ - tmp |= MACCFG2_FULL_DUPLEX; iowrite32be(tmp, ®s->maccfg2); tmp = (((cfg->non_back_to_back_ipg1 << @@ -525,10 +476,6 @@ static void set_bucket(struct dtsec_regs __iomem *regs, int bucket, static int check_init_parameters(struct fman_mac *dtsec) { - if (dtsec->max_speed >= SPEED_10000) { - pr_err("1G MAC driver supports 1G or lower speeds\n"); - return -EINVAL; - } if ((dtsec->dtsec_drv_param)->rx_prepend > MAX_PACKET_ALIGNMENT) { pr_err("packetAlignmentPadding can't be > than %d\n", @@ -630,22 +577,10 @@ static int get_exception_flag(enum fman_mac_exceptions exception) return bit_mask; } -static bool is_init_done(struct dtsec_cfg *dtsec_drv_params) -{ - /* Checks if dTSEC driver parameters were initialized */ - if (!dtsec_drv_params) - return true; - - return false; -} - static u16 dtsec_get_max_frame_length(struct fman_mac *dtsec) { struct dtsec_regs __iomem *regs = dtsec->regs; - if (is_init_done(dtsec->dtsec_drv_param)) - return 0; - return (u16)ioread32be(®s->maxfrm); } @@ -682,6 +617,7 @@ static void dtsec_isr(void *handle) dtsec->exception_cb(dtsec->dev_id, FM_MAC_EX_1G_COL_RET_LMT); if (event & DTSEC_IMASK_XFUNEN) { /* FM_TX_LOCKUP_ERRATA_DTSEC6 Errata workaround */ + /* FIXME: This races with the rest of the driver! */ if (dtsec->fm_rev_info.major == 2) { u32 tpkt1, tmp_reg1, tpkt2, tmp_reg2, i; /* a. Write 0x00E0_0C00 to DTSEC_ID @@ -814,6 +750,43 @@ static void free_init_resources(struct fman_mac *dtsec) dtsec->unicast_addr_hash = NULL; } +static struct fman_mac *pcs_to_dtsec(struct phylink_pcs *pcs) +{ + return container_of(pcs, struct fman_mac, pcs); +} + +static void dtsec_pcs_get_state(struct phylink_pcs *pcs, + struct phylink_link_state *state) +{ + struct fman_mac *dtsec = pcs_to_dtsec(pcs); + + phylink_mii_c22_pcs_get_state(dtsec->tbidev, state); +} + +static int dtsec_pcs_config(struct phylink_pcs *pcs, unsigned int mode, + phy_interface_t interface, + const unsigned long *advertising, + bool permit_pause_to_mac) +{ + struct fman_mac *dtsec = pcs_to_dtsec(pcs); + + return phylink_mii_c22_pcs_config(dtsec->tbidev, mode, interface, + advertising); +} + +static void dtsec_pcs_an_restart(struct phylink_pcs *pcs) +{ + struct fman_mac *dtsec = pcs_to_dtsec(pcs); + + phylink_mii_c22_pcs_an_restart(dtsec->tbidev); +} + +static const struct phylink_pcs_ops dtsec_pcs_ops = { + .pcs_get_state = dtsec_pcs_get_state, + .pcs_config = dtsec_pcs_config, + .pcs_an_restart = dtsec_pcs_an_restart, +}; + static void graceful_start(struct fman_mac *dtsec) { struct dtsec_regs __iomem *regs = dtsec->regs; @@ -854,36 +827,11 @@ static void graceful_stop(struct fman_mac *dtsec) static int dtsec_enable(struct fman_mac *dtsec) { - struct dtsec_regs __iomem *regs = dtsec->regs; - u32 tmp; - - if (!is_init_done(dtsec->dtsec_drv_param)) - return -EINVAL; - - /* Enable */ - tmp = ioread32be(®s->maccfg1); - tmp |= MACCFG1_RX_EN | MACCFG1_TX_EN; - iowrite32be(tmp, ®s->maccfg1); - - /* Graceful start - clear the graceful Rx/Tx stop bit */ - graceful_start(dtsec); - return 0; } static void dtsec_disable(struct fman_mac *dtsec) { - struct dtsec_regs __iomem *regs = dtsec->regs; - u32 tmp; - - WARN_ON_ONCE(!is_init_done(dtsec->dtsec_drv_param)); - - /* Graceful stop - Assert the graceful Rx/Tx stop bit */ - graceful_stop(dtsec); - - tmp = ioread32be(®s->maccfg1); - tmp &= ~(MACCFG1_RX_EN | MACCFG1_TX_EN); - iowrite32be(tmp, ®s->maccfg1); } static int dtsec_set_tx_pause_frames(struct fman_mac *dtsec, @@ -894,11 +842,6 @@ static int dtsec_set_tx_pause_frames(struct fman_mac *dtsec, struct dtsec_regs __iomem *regs = dtsec->regs; u32 ptv = 0; - if (!is_init_done(dtsec->dtsec_drv_param)) - return -EINVAL; - - graceful_stop(dtsec); - if (pause_time) { /* FM_BAD_TX_TS_IN_B_2_B_ERRATA_DTSEC_A003 Errata workaround */ if (dtsec->fm_rev_info.major == 2 && pause_time <= 320) { @@ -919,8 +862,6 @@ static int dtsec_set_tx_pause_frames(struct fman_mac *dtsec, iowrite32be(ioread32be(®s->maccfg1) & ~MACCFG1_TX_FLOW, ®s->maccfg1); - graceful_start(dtsec); - return 0; } @@ -929,11 +870,6 @@ static int dtsec_accept_rx_pause_frames(struct fman_mac *dtsec, bool en) struct dtsec_regs __iomem *regs = dtsec->regs; u32 tmp; - if (!is_init_done(dtsec->dtsec_drv_param)) - return -EINVAL; - - graceful_stop(dtsec); - tmp = ioread32be(®s->maccfg1); if (en) tmp |= MACCFG1_RX_FLOW; @@ -941,17 +877,125 @@ static int dtsec_accept_rx_pause_frames(struct fman_mac *dtsec, bool en) tmp &= ~MACCFG1_RX_FLOW; iowrite32be(tmp, ®s->maccfg1); + return 0; +} + +static struct phylink_pcs *dtsec_select_pcs(struct phylink_config *config, + phy_interface_t iface) +{ + struct fman_mac *dtsec = fman_config_to_mac(config)->fman_mac; + + switch (iface) { + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_1000BASEX: + case PHY_INTERFACE_MODE_2500BASEX: + return &dtsec->pcs; + default: + return NULL; + } +} + +static void dtsec_mac_config(struct phylink_config *config, unsigned int mode, + const struct phylink_link_state *state) +{ + struct mac_device *mac_dev = fman_config_to_mac(config); + struct dtsec_regs __iomem *regs = mac_dev->fman_mac->regs; + u32 tmp; + + switch (state->interface) { + case PHY_INTERFACE_MODE_RMII: + tmp = DTSEC_ECNTRL_RMM; + break; + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: + tmp = DTSEC_ECNTRL_GMIIM | DTSEC_ECNTRL_RPM; + break; + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_1000BASEX: + case PHY_INTERFACE_MODE_2500BASEX: + tmp = DTSEC_ECNTRL_TBIM | DTSEC_ECNTRL_SGMIIM; + break; + default: + dev_warn(mac_dev->dev, "cannot configure dTSEC for %s\n", + phy_modes(state->interface)); + return; + } + + iowrite32be(tmp, ®s->ecntrl); +} + +static void dtsec_link_up(struct phylink_config *config, struct phy_device *phy, + unsigned int mode, phy_interface_t interface, + int speed, int duplex, bool tx_pause, bool rx_pause) +{ + struct mac_device *mac_dev = fman_config_to_mac(config); + struct fman_mac *dtsec = mac_dev->fman_mac; + struct dtsec_regs __iomem *regs = dtsec->regs; + u16 pause_time = tx_pause ? FSL_FM_PAUSE_TIME_ENABLE : + FSL_FM_PAUSE_TIME_DISABLE; + u32 tmp; + + dtsec_set_tx_pause_frames(dtsec, 0, pause_time, 0); + dtsec_accept_rx_pause_frames(dtsec, rx_pause); + + tmp = ioread32be(®s->ecntrl); + if (speed == SPEED_100) + tmp |= DTSEC_ECNTRL_R100M; + else + tmp &= ~DTSEC_ECNTRL_R100M; + iowrite32be(tmp, ®s->ecntrl); + + tmp = ioread32be(®s->maccfg2); + tmp &= ~(MACCFG2_NIBBLE_MODE | MACCFG2_BYTE_MODE | MACCFG2_FULL_DUPLEX); + if (speed >= SPEED_1000) + tmp |= MACCFG2_BYTE_MODE; + else + tmp |= MACCFG2_NIBBLE_MODE; + + if (duplex == DUPLEX_FULL) + tmp |= MACCFG2_FULL_DUPLEX; + + iowrite32be(tmp, ®s->maccfg2); + + mac_dev->update_speed(mac_dev, speed); + + /* Enable */ + tmp = ioread32be(®s->maccfg1); + tmp |= MACCFG1_RX_EN | MACCFG1_TX_EN; + iowrite32be(tmp, ®s->maccfg1); + + /* Graceful start - clear the graceful Rx/Tx stop bit */ graceful_start(dtsec); +} - return 0; +static void dtsec_link_down(struct phylink_config *config, unsigned int mode, + phy_interface_t interface) +{ + struct fman_mac *dtsec = fman_config_to_mac(config)->fman_mac; + struct dtsec_regs __iomem *regs = dtsec->regs; + u32 tmp; + + /* Graceful stop - Assert the graceful Rx/Tx stop bit */ + graceful_stop(dtsec); + + tmp = ioread32be(®s->maccfg1); + tmp &= ~(MACCFG1_RX_EN | MACCFG1_TX_EN); + iowrite32be(tmp, ®s->maccfg1); } +static const struct phylink_mac_ops dtsec_mac_ops = { + .validate = phylink_generic_validate, + .mac_select_pcs = dtsec_select_pcs, + .mac_config = dtsec_mac_config, + .mac_link_up = dtsec_link_up, + .mac_link_down = dtsec_link_down, +}; + static int dtsec_modify_mac_address(struct fman_mac *dtsec, const enet_addr_t *enet_addr) { - if (!is_init_done(dtsec->dtsec_drv_param)) - return -EINVAL; - graceful_stop(dtsec); /* Initialize MAC Station Address registers (1 & 2) @@ -975,9 +1019,6 @@ static int dtsec_add_hash_mac_address(struct fman_mac *dtsec, u32 crc = 0xFFFFFFFF; bool mcast, ghtx; - if (!is_init_done(dtsec->dtsec_drv_param)) - return -EINVAL; - addr = ENET_ADDR_TO_UINT64(*eth_addr); ghtx = (bool)((ioread32be(®s->rctrl) & RCTRL_GHTX) ? true : false); @@ -1037,9 +1078,6 @@ static int dtsec_set_allmulti(struct fman_mac *dtsec, bool enable) u32 tmp; struct dtsec_regs __iomem *regs = dtsec->regs; - if (!is_init_done(dtsec->dtsec_drv_param)) - return -EINVAL; - tmp = ioread32be(®s->rctrl); if (enable) tmp |= RCTRL_MPROM; @@ -1056,9 +1094,6 @@ static int dtsec_set_tstamp(struct fman_mac *dtsec, bool enable) struct dtsec_regs __iomem *regs = dtsec->regs; u32 rctrl, tctrl; - if (!is_init_done(dtsec->dtsec_drv_param)) - return -EINVAL; - rctrl = ioread32be(®s->rctrl); tctrl = ioread32be(®s->tctrl); @@ -1087,9 +1122,6 @@ static int dtsec_del_hash_mac_address(struct fman_mac *dtsec, u32 crc = 0xFFFFFFFF; bool mcast, ghtx; - if (!is_init_done(dtsec->dtsec_drv_param)) - return -EINVAL; - addr = ENET_ADDR_TO_UINT64(*eth_addr); ghtx = (bool)((ioread32be(®s->rctrl) & RCTRL_GHTX) ? true : false); @@ -1153,9 +1185,6 @@ static int dtsec_set_promiscuous(struct fman_mac *dtsec, bool new_val) struct dtsec_regs __iomem *regs = dtsec->regs; u32 tmp; - if (!is_init_done(dtsec->dtsec_drv_param)) - return -EINVAL; - /* Set unicast promiscuous */ tmp = ioread32be(®s->rctrl); if (new_val) @@ -1177,90 +1206,12 @@ static int dtsec_set_promiscuous(struct fman_mac *dtsec, bool new_val) return 0; } -static int dtsec_adjust_link(struct fman_mac *dtsec, u16 speed) -{ - struct dtsec_regs __iomem *regs = dtsec->regs; - u32 tmp; - - if (!is_init_done(dtsec->dtsec_drv_param)) - return -EINVAL; - - graceful_stop(dtsec); - - tmp = ioread32be(®s->maccfg2); - - /* Full Duplex */ - tmp |= MACCFG2_FULL_DUPLEX; - - tmp &= ~(MACCFG2_NIBBLE_MODE | MACCFG2_BYTE_MODE); - if (speed < SPEED_1000) - tmp |= MACCFG2_NIBBLE_MODE; - else if (speed == SPEED_1000) - tmp |= MACCFG2_BYTE_MODE; - iowrite32be(tmp, ®s->maccfg2); - - tmp = ioread32be(®s->ecntrl); - if (speed == SPEED_100) - tmp |= DTSEC_ECNTRL_R100M; - else - tmp &= ~DTSEC_ECNTRL_R100M; - iowrite32be(tmp, ®s->ecntrl); - - graceful_start(dtsec); - - return 0; -} - -static int dtsec_restart_autoneg(struct fman_mac *dtsec) -{ - u16 tmp_reg16; - - if (!is_init_done(dtsec->dtsec_drv_param)) - return -EINVAL; - - tmp_reg16 = phy_read(dtsec->tbiphy, MII_BMCR); - - tmp_reg16 &= ~(BMCR_SPEED100 | BMCR_SPEED1000); - tmp_reg16 |= (BMCR_ANENABLE | BMCR_ANRESTART | - BMCR_FULLDPLX | BMCR_SPEED1000); - - phy_write(dtsec->tbiphy, MII_BMCR, tmp_reg16); - - return 0; -} - -static void adjust_link_dtsec(struct mac_device *mac_dev) -{ - struct phy_device *phy_dev = mac_dev->phy_dev; - struct fman_mac *fman_mac; - bool rx_pause, tx_pause; - int err; - - fman_mac = mac_dev->fman_mac; - if (!phy_dev->link) { - dtsec_restart_autoneg(fman_mac); - - return; - } - - dtsec_adjust_link(fman_mac, phy_dev->speed); - mac_dev->update_speed(mac_dev, phy_dev->speed); - fman_get_pause_cfg(mac_dev, &rx_pause, &tx_pause); - err = fman_set_mac_active_pause(mac_dev, rx_pause, tx_pause); - if (err < 0) - dev_err(mac_dev->dev, "fman_set_mac_active_pause() = %d\n", - err); -} - static int dtsec_set_exception(struct fman_mac *dtsec, enum fman_mac_exceptions exception, bool enable) { struct dtsec_regs __iomem *regs = dtsec->regs; u32 bit_mask = 0; - if (!is_init_done(dtsec->dtsec_drv_param)) - return -EINVAL; - if (exception != FM_MAC_EX_1G_1588_TS_RX_ERR) { bit_mask = get_exception_flag(exception); if (bit_mask) { @@ -1310,12 +1261,9 @@ static int dtsec_init(struct fman_mac *dtsec) { struct dtsec_regs __iomem *regs = dtsec->regs; struct dtsec_cfg *dtsec_drv_param; - u16 max_frm_ln; + u16 max_frm_ln, tbicon; int err; - if (is_init_done(dtsec->dtsec_drv_param)) - return -EINVAL; - if (DEFAULT_RESET_ON_INIT && (fman_reset_mac(dtsec->fm, dtsec->mac_id) != 0)) { pr_err("Can't reset MAC!\n"); @@ -1330,38 +1278,19 @@ static int dtsec_init(struct fman_mac *dtsec) err = init(dtsec->regs, dtsec_drv_param, dtsec->phy_if, dtsec->max_speed, dtsec->addr, dtsec->exceptions, - dtsec->tbiphy->mdio.addr); + dtsec->tbidev->addr); if (err) { free_init_resources(dtsec); pr_err("DTSEC version doesn't support this i/f mode\n"); return err; } - if (dtsec->phy_if == PHY_INTERFACE_MODE_SGMII) { - u16 tmp_reg16; - - /* Configure the TBI PHY Control Register */ - tmp_reg16 = TBICON_CLK_SELECT | TBICON_SOFT_RESET; - phy_write(dtsec->tbiphy, MII_TBICON, tmp_reg16); + /* Configure the TBI PHY Control Register */ + tbicon = TBICON_CLK_SELECT | TBICON_SOFT_RESET; + mdiodev_write(dtsec->tbidev, MII_TBICON, tbicon); - tmp_reg16 = TBICON_CLK_SELECT; - phy_write(dtsec->tbiphy, MII_TBICON, tmp_reg16); - - tmp_reg16 = (BMCR_RESET | BMCR_ANENABLE | - BMCR_FULLDPLX | BMCR_SPEED1000); - phy_write(dtsec->tbiphy, MII_BMCR, tmp_reg16); - - if (dtsec->basex_if) - tmp_reg16 = TBIANA_1000X; - else - tmp_reg16 = TBIANA_SGMII; - phy_write(dtsec->tbiphy, MII_ADVERTISE, tmp_reg16); - - tmp_reg16 = (BMCR_ANENABLE | BMCR_ANRESTART | - BMCR_FULLDPLX | BMCR_SPEED1000); - - phy_write(dtsec->tbiphy, MII_BMCR, tmp_reg16); - } + tbicon = TBICON_CLK_SELECT; + mdiodev_write(dtsec->tbidev, MII_TBICON, tbicon); /* Max Frame Length */ max_frm_ln = (u16)ioread32be(®s->maxfrm); @@ -1406,6 +1335,8 @@ static int dtsec_free(struct fman_mac *dtsec) kfree(dtsec->dtsec_drv_param); dtsec->dtsec_drv_param = NULL; + if (!IS_ERR_OR_NULL(dtsec->tbidev)) + put_device(&dtsec->tbidev->dev); kfree(dtsec); return 0; @@ -1434,7 +1365,6 @@ static struct fman_mac *dtsec_config(struct mac_device *mac_dev, dtsec->regs = mac_dev->vaddr; dtsec->addr = ENET_ADDR_TO_UINT64(mac_dev->addr); - dtsec->max_speed = params->max_speed; dtsec->phy_if = mac_dev->phy_if; dtsec->mac_id = params->mac_id; dtsec->exceptions = (DTSEC_IMASK_BREN | @@ -1457,7 +1387,6 @@ static struct fman_mac *dtsec_config(struct mac_device *mac_dev, dtsec->en_tsu_err_exception = dtsec->dtsec_drv_param->ptp_exception_en; dtsec->fm = params->fm; - dtsec->basex_if = params->basex_if; /* Save FMan revision */ fman_get_revision(dtsec->fm, &dtsec->fm_rev_info); @@ -1476,18 +1405,18 @@ int dtsec_initialization(struct mac_device *mac_dev, int err; struct fman_mac *dtsec; struct device_node *phy_node; + unsigned long capabilities; + unsigned long *supported; + mac_dev->phylink_ops = &dtsec_mac_ops; mac_dev->set_promisc = dtsec_set_promiscuous; mac_dev->change_addr = dtsec_modify_mac_address; mac_dev->add_hash_mac_addr = dtsec_add_hash_mac_address; mac_dev->remove_hash_mac_addr = dtsec_del_hash_mac_address; - mac_dev->set_tx_pause = dtsec_set_tx_pause_frames; - mac_dev->set_rx_pause = dtsec_accept_rx_pause_frames; mac_dev->set_exception = dtsec_set_exception; mac_dev->set_allmulti = dtsec_set_allmulti; mac_dev->set_tstamp = dtsec_set_tstamp; mac_dev->set_multi = fman_set_multi; - mac_dev->adjust_link = adjust_link_dtsec; mac_dev->enable = dtsec_enable; mac_dev->disable = dtsec_disable; @@ -1502,19 +1431,56 @@ int dtsec_initialization(struct mac_device *mac_dev, dtsec->dtsec_drv_param->tx_pad_crc = true; phy_node = of_parse_phandle(mac_node, "tbi-handle", 0); - if (!phy_node) { - pr_err("TBI PHY node is not available\n"); + if (!phy_node || of_device_is_available(phy_node)) { + of_node_put(phy_node); err = -EINVAL; + dev_err_probe(mac_dev->dev, err, + "TBI PCS node is not available\n"); goto _return_fm_mac_free; } - dtsec->tbiphy = of_phy_find_device(phy_node); - if (!dtsec->tbiphy) { - pr_err("of_phy_find_device (TBI PHY) failed\n"); - err = -EINVAL; + dtsec->tbidev = of_mdio_find_device(phy_node); + of_node_put(phy_node); + if (!dtsec->tbidev) { + err = -EPROBE_DEFER; + dev_err_probe(mac_dev->dev, err, + "could not find mdiodev for PCS\n"); goto _return_fm_mac_free; } - put_device(&dtsec->tbiphy->mdio.dev); + dtsec->pcs.ops = &dtsec_pcs_ops; + dtsec->pcs.poll = true; + + supported = mac_dev->phylink_config.supported_interfaces; + + /* FIXME: Can we use DTSEC_ID2_INT_FULL_OFF to determine if these are + * supported? If not, we can determine support via the phy if SerDes + * support is added. + */ + if (mac_dev->phy_if == PHY_INTERFACE_MODE_SGMII || + mac_dev->phy_if == PHY_INTERFACE_MODE_1000BASEX) { + __set_bit(PHY_INTERFACE_MODE_SGMII, supported); + __set_bit(PHY_INTERFACE_MODE_1000BASEX, supported); + } else if (mac_dev->phy_if == PHY_INTERFACE_MODE_2500BASEX) { + __set_bit(PHY_INTERFACE_MODE_2500BASEX, supported); + } + + if (!(ioread32be(&dtsec->regs->tsec_id2) & DTSEC_ID2_INT_REDUCED_OFF)) { + phy_interface_set_rgmii(supported); + + /* DTSEC_ID2_INT_REDUCED_OFF indicates that the dTSEC supports + * RMII and RGMII. However, the only SoCs which support RMII + * are the P1017 and P1023. Avoid advertising this mode on + * other SoCs. This is a bit of a moot point, since there's no + * in-tree support for ethernet on these platforms... + */ + if (of_machine_is_compatible("fsl,P1023") || + of_machine_is_compatible("fsl,P1023RDB")) + __set_bit(PHY_INTERFACE_MODE_RMII, supported); + } + + capabilities = MAC_SYM_PAUSE | MAC_ASYM_PAUSE; + capabilities |= MAC_10 | MAC_100 | MAC_1000FD | MAC_2500FD; + mac_dev->phylink_config.mac_capabilities = capabilities; err = dtsec_init(dtsec); if (err < 0) diff --git a/drivers/net/ethernet/freescale/fman/fman_mac.h b/drivers/net/ethernet/freescale/fman/fman_mac.h index 65887a3160d7..e5d6cddea731 100644 --- a/drivers/net/ethernet/freescale/fman/fman_mac.h +++ b/drivers/net/ethernet/freescale/fman/fman_mac.h @@ -170,20 +170,10 @@ struct fman_mac_params { * 0 - FM_MAX_NUM_OF_10G_MACS */ u8 mac_id; - /* Note that the speed should indicate the maximum rate that - * this MAC should support rather than the actual speed; - */ - u16 max_speed; /* A handle to the FM object this port related to */ void *fm; fman_mac_exception_cb *event_cb; /* MDIO Events Callback Routine */ fman_mac_exception_cb *exception_cb;/* Exception Callback Routine */ - /* SGMII/QSGII interface with 1000BaseX auto-negotiation between MAC - * and phy or backplane; Note: 1000BaseX auto-negotiation relates only - * to interface between MAC and phy/backplane, SGMII phy can still - * synchronize with far-end phy at 10Mbps, 100Mbps or 1000Mbps - */ - bool basex_if; }; struct eth_hash_t { diff --git a/drivers/net/ethernet/freescale/fman/fman_memac.c b/drivers/net/ethernet/freescale/fman/fman_memac.c index 32d26cf17843..9349f841bd06 100644 --- a/drivers/net/ethernet/freescale/fman/fman_memac.c +++ b/drivers/net/ethernet/freescale/fman/fman_memac.c @@ -11,42 +11,12 @@ #include <linux/slab.h> #include <linux/io.h> +#include <linux/pcs-lynx.h> #include <linux/phy.h> #include <linux/phy_fixed.h> +#include <linux/phy/phy.h> #include <linux/of_mdio.h> -/* PCS registers */ -#define MDIO_SGMII_CR 0x00 -#define MDIO_SGMII_DEV_ABIL_SGMII 0x04 -#define MDIO_SGMII_LINK_TMR_L 0x12 -#define MDIO_SGMII_LINK_TMR_H 0x13 -#define MDIO_SGMII_IF_MODE 0x14 - -/* SGMII Control defines */ -#define SGMII_CR_AN_EN 0x1000 -#define SGMII_CR_RESTART_AN 0x0200 -#define SGMII_CR_FD 0x0100 -#define SGMII_CR_SPEED_SEL1_1G 0x0040 -#define SGMII_CR_DEF_VAL (SGMII_CR_AN_EN | SGMII_CR_FD | \ - SGMII_CR_SPEED_SEL1_1G) - -/* SGMII Device Ability for SGMII defines */ -#define MDIO_SGMII_DEV_ABIL_SGMII_MODE 0x4001 -#define MDIO_SGMII_DEV_ABIL_BASEX_MODE 0x01A0 - -/* Link timer define */ -#define LINK_TMR_L 0xa120 -#define LINK_TMR_H 0x0007 -#define LINK_TMR_L_BASEX 0xaf08 -#define LINK_TMR_H_BASEX 0x002f - -/* SGMII IF Mode defines */ -#define IF_MODE_USE_SGMII_AN 0x0002 -#define IF_MODE_SGMII_EN 0x0001 -#define IF_MODE_SGMII_SPEED_100M 0x0004 -#define IF_MODE_SGMII_SPEED_1G 0x0008 -#define IF_MODE_SGMII_DUPLEX_HALF 0x0010 - /* Num of additional exact match MAC adr regs */ #define MEMAC_NUM_OF_PADDRS 7 @@ -308,9 +278,6 @@ struct fman_mac { struct memac_regs __iomem *regs; /* MAC address of device */ u64 addr; - /* Ethernet physical interface */ - phy_interface_t phy_if; - u16 max_speed; struct mac_device *dev_id; /* device cookie used by the exception cbs */ fman_mac_exception_cb *exception_cb; fman_mac_exception_cb *event_cb; @@ -323,9 +290,12 @@ struct fman_mac { struct memac_cfg *memac_drv_param; void *fm; struct fman_rev_info fm_rev_info; - bool basex_if; - struct phy_device *pcsphy; + struct phy *serdes; + struct phylink_pcs *sgmii_pcs; + struct phylink_pcs *qsgmii_pcs; + struct phylink_pcs *xfi_pcs; bool allmulti_enabled; + bool rgmii_no_half_duplex; }; static void add_addr_in_paddr(struct memac_regs __iomem *regs, const u8 *adr, @@ -383,7 +353,6 @@ static void set_exception(struct memac_regs __iomem *regs, u32 val, } static int init(struct memac_regs __iomem *regs, struct memac_cfg *cfg, - phy_interface_t phy_if, u16 speed, bool slow_10g_if, u32 exceptions) { u32 tmp; @@ -411,41 +380,6 @@ static int init(struct memac_regs __iomem *regs, struct memac_cfg *cfg, iowrite32be((u32)cfg->pause_quanta, ®s->pause_quanta[0]); iowrite32be((u32)0, ®s->pause_thresh[0]); - /* IF_MODE */ - tmp = 0; - switch (phy_if) { - case PHY_INTERFACE_MODE_XGMII: - tmp |= IF_MODE_10G; - break; - case PHY_INTERFACE_MODE_MII: - tmp |= IF_MODE_MII; - break; - default: - tmp |= IF_MODE_GMII; - if (phy_if == PHY_INTERFACE_MODE_RGMII || - phy_if == PHY_INTERFACE_MODE_RGMII_ID || - phy_if == PHY_INTERFACE_MODE_RGMII_RXID || - phy_if == PHY_INTERFACE_MODE_RGMII_TXID) - tmp |= IF_MODE_RGMII | IF_MODE_RGMII_AUTO; - } - iowrite32be(tmp, ®s->if_mode); - - /* TX_FIFO_SECTIONS */ - tmp = 0; - if (phy_if == PHY_INTERFACE_MODE_XGMII) { - if (slow_10g_if) { - tmp |= (TX_FIFO_SECTIONS_TX_AVAIL_SLOW_10G | - TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_10G); - } else { - tmp |= (TX_FIFO_SECTIONS_TX_AVAIL_10G | - TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_10G); - } - } else { - tmp |= (TX_FIFO_SECTIONS_TX_AVAIL_1G | - TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_1G); - } - iowrite32be(tmp, ®s->tx_fifo_sections); - /* clear all pending events and set-up interrupts */ iowrite32be(0xffffffff, ®s->ievent); set_exception(regs, exceptions, true); @@ -485,93 +419,6 @@ static u32 get_mac_addr_hash_code(u64 eth_addr) return xor_val; } -static void setup_sgmii_internal_phy(struct fman_mac *memac, - struct fixed_phy_status *fixed_link) -{ - u16 tmp_reg16; - - if (WARN_ON(!memac->pcsphy)) - return; - - /* SGMII mode */ - tmp_reg16 = IF_MODE_SGMII_EN; - if (!fixed_link) - /* AN enable */ - tmp_reg16 |= IF_MODE_USE_SGMII_AN; - else { - switch (fixed_link->speed) { - case 10: - /* For 10M: IF_MODE[SPEED_10M] = 0 */ - break; - case 100: - tmp_reg16 |= IF_MODE_SGMII_SPEED_100M; - break; - case 1000: - default: - tmp_reg16 |= IF_MODE_SGMII_SPEED_1G; - break; - } - if (!fixed_link->duplex) - tmp_reg16 |= IF_MODE_SGMII_DUPLEX_HALF; - } - phy_write(memac->pcsphy, MDIO_SGMII_IF_MODE, tmp_reg16); - - /* Device ability according to SGMII specification */ - tmp_reg16 = MDIO_SGMII_DEV_ABIL_SGMII_MODE; - phy_write(memac->pcsphy, MDIO_SGMII_DEV_ABIL_SGMII, tmp_reg16); - - /* Adjust link timer for SGMII - - * According to Cisco SGMII specification the timer should be 1.6 ms. - * The link_timer register is configured in units of the clock. - * - When running as 1G SGMII, Serdes clock is 125 MHz, so - * unit = 1 / (125*10^6 Hz) = 8 ns. - * 1.6 ms in units of 8 ns = 1.6ms / 8ns = 2*10^5 = 0x30d40 - * - When running as 2.5G SGMII, Serdes clock is 312.5 MHz, so - * unit = 1 / (312.5*10^6 Hz) = 3.2 ns. - * 1.6 ms in units of 3.2 ns = 1.6ms / 3.2ns = 5*10^5 = 0x7a120. - * Since link_timer value of 1G SGMII will be too short for 2.5 SGMII, - * we always set up here a value of 2.5 SGMII. - */ - phy_write(memac->pcsphy, MDIO_SGMII_LINK_TMR_H, LINK_TMR_H); - phy_write(memac->pcsphy, MDIO_SGMII_LINK_TMR_L, LINK_TMR_L); - - if (!fixed_link) - /* Restart AN */ - tmp_reg16 = SGMII_CR_DEF_VAL | SGMII_CR_RESTART_AN; - else - /* AN disabled */ - tmp_reg16 = SGMII_CR_DEF_VAL & ~SGMII_CR_AN_EN; - phy_write(memac->pcsphy, 0x0, tmp_reg16); -} - -static void setup_sgmii_internal_phy_base_x(struct fman_mac *memac) -{ - u16 tmp_reg16; - - /* AN Device capability */ - tmp_reg16 = MDIO_SGMII_DEV_ABIL_BASEX_MODE; - phy_write(memac->pcsphy, MDIO_SGMII_DEV_ABIL_SGMII, tmp_reg16); - - /* Adjust link timer for SGMII - - * For Serdes 1000BaseX auto-negotiation the timer should be 10 ms. - * The link_timer register is configured in units of the clock. - * - When running as 1G SGMII, Serdes clock is 125 MHz, so - * unit = 1 / (125*10^6 Hz) = 8 ns. - * 10 ms in units of 8 ns = 10ms / 8ns = 1250000 = 0x1312d0 - * - When running as 2.5G SGMII, Serdes clock is 312.5 MHz, so - * unit = 1 / (312.5*10^6 Hz) = 3.2 ns. - * 10 ms in units of 3.2 ns = 10ms / 3.2ns = 3125000 = 0x2faf08. - * Since link_timer value of 1G SGMII will be too short for 2.5 SGMII, - * we always set up here a value of 2.5 SGMII. - */ - phy_write(memac->pcsphy, MDIO_SGMII_LINK_TMR_H, LINK_TMR_H_BASEX); - phy_write(memac->pcsphy, MDIO_SGMII_LINK_TMR_L, LINK_TMR_L_BASEX); - - /* Restart AN */ - tmp_reg16 = SGMII_CR_DEF_VAL | SGMII_CR_RESTART_AN; - phy_write(memac->pcsphy, 0x0, tmp_reg16); -} - static int check_init_parameters(struct fman_mac *memac) { if (!memac->exception_cb) { @@ -677,41 +524,31 @@ static void free_init_resources(struct fman_mac *memac) memac->unicast_addr_hash = NULL; } -static bool is_init_done(struct memac_cfg *memac_drv_params) -{ - /* Checks if mEMAC driver parameters were initialized */ - if (!memac_drv_params) - return true; - - return false; -} - static int memac_enable(struct fman_mac *memac) { - struct memac_regs __iomem *regs = memac->regs; - u32 tmp; + int ret; - if (!is_init_done(memac->memac_drv_param)) - return -EINVAL; + ret = phy_init(memac->serdes); + if (ret) { + dev_err(memac->dev_id->dev, + "could not initialize serdes: %pe\n", ERR_PTR(ret)); + return ret; + } - tmp = ioread32be(®s->command_config); - tmp |= CMD_CFG_RX_EN | CMD_CFG_TX_EN; - iowrite32be(tmp, ®s->command_config); + ret = phy_power_on(memac->serdes); + if (ret) { + dev_err(memac->dev_id->dev, + "could not power on serdes: %pe\n", ERR_PTR(ret)); + phy_exit(memac->serdes); + } - return 0; + return ret; } static void memac_disable(struct fman_mac *memac) - { - struct memac_regs __iomem *regs = memac->regs; - u32 tmp; - - WARN_ON_ONCE(!is_init_done(memac->memac_drv_param)); - - tmp = ioread32be(®s->command_config); - tmp &= ~(CMD_CFG_RX_EN | CMD_CFG_TX_EN); - iowrite32be(tmp, ®s->command_config); + phy_power_off(memac->serdes); + phy_exit(memac->serdes); } static int memac_set_promiscuous(struct fman_mac *memac, bool new_val) @@ -719,9 +556,6 @@ static int memac_set_promiscuous(struct fman_mac *memac, bool new_val) struct memac_regs __iomem *regs = memac->regs; u32 tmp; - if (!is_init_done(memac->memac_drv_param)) - return -EINVAL; - tmp = ioread32be(®s->command_config); if (new_val) tmp |= CMD_CFG_PROMIS_EN; @@ -733,73 +567,12 @@ static int memac_set_promiscuous(struct fman_mac *memac, bool new_val) return 0; } -static int memac_adjust_link(struct fman_mac *memac, u16 speed) -{ - struct memac_regs __iomem *regs = memac->regs; - u32 tmp; - - if (!is_init_done(memac->memac_drv_param)) - return -EINVAL; - - tmp = ioread32be(®s->if_mode); - - /* Set full duplex */ - tmp &= ~IF_MODE_HD; - - if (phy_interface_mode_is_rgmii(memac->phy_if)) { - /* Configure RGMII in manual mode */ - tmp &= ~IF_MODE_RGMII_AUTO; - tmp &= ~IF_MODE_RGMII_SP_MASK; - /* Full duplex */ - tmp |= IF_MODE_RGMII_FD; - - switch (speed) { - case SPEED_1000: - tmp |= IF_MODE_RGMII_1000; - break; - case SPEED_100: - tmp |= IF_MODE_RGMII_100; - break; - case SPEED_10: - tmp |= IF_MODE_RGMII_10; - break; - default: - break; - } - } - - iowrite32be(tmp, ®s->if_mode); - - return 0; -} - -static void adjust_link_memac(struct mac_device *mac_dev) -{ - struct phy_device *phy_dev = mac_dev->phy_dev; - struct fman_mac *fman_mac; - bool rx_pause, tx_pause; - int err; - - fman_mac = mac_dev->fman_mac; - memac_adjust_link(fman_mac, phy_dev->speed); - mac_dev->update_speed(mac_dev, phy_dev->speed); - - fman_get_pause_cfg(mac_dev, &rx_pause, &tx_pause); - err = fman_set_mac_active_pause(mac_dev, rx_pause, tx_pause); - if (err < 0) - dev_err(mac_dev->dev, "fman_set_mac_active_pause() = %d\n", - err); -} - static int memac_set_tx_pause_frames(struct fman_mac *memac, u8 priority, u16 pause_time, u16 thresh_time) { struct memac_regs __iomem *regs = memac->regs; u32 tmp; - if (!is_init_done(memac->memac_drv_param)) - return -EINVAL; - tmp = ioread32be(®s->tx_fifo_sections); GET_TX_EMPTY_DEFAULT_VALUE(tmp); @@ -834,9 +607,6 @@ static int memac_accept_rx_pause_frames(struct fman_mac *memac, bool en) struct memac_regs __iomem *regs = memac->regs; u32 tmp; - if (!is_init_done(memac->memac_drv_param)) - return -EINVAL; - tmp = ioread32be(®s->command_config); if (en) tmp &= ~CMD_CFG_PAUSE_IGNORE; @@ -848,12 +618,175 @@ static int memac_accept_rx_pause_frames(struct fman_mac *memac, bool en) return 0; } +static void memac_validate(struct phylink_config *config, + unsigned long *supported, + struct phylink_link_state *state) +{ + struct fman_mac *memac = fman_config_to_mac(config)->fman_mac; + unsigned long caps = config->mac_capabilities; + + if (phy_interface_mode_is_rgmii(state->interface) && + memac->rgmii_no_half_duplex) + caps &= ~(MAC_10HD | MAC_100HD); + + phylink_validate_mask_caps(supported, state, caps); +} + +/** + * memac_if_mode() - Convert an interface mode into an IF_MODE config + * @interface: A phy interface mode + * + * Return: A configuration word, suitable for programming into the lower bits + * of %IF_MODE. + */ +static u32 memac_if_mode(phy_interface_t interface) +{ + switch (interface) { + case PHY_INTERFACE_MODE_MII: + return IF_MODE_MII; + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: + return IF_MODE_GMII | IF_MODE_RGMII; + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_1000BASEX: + case PHY_INTERFACE_MODE_QSGMII: + return IF_MODE_GMII; + case PHY_INTERFACE_MODE_10GBASER: + return IF_MODE_10G; + default: + WARN_ON_ONCE(1); + return 0; + } +} + +static struct phylink_pcs *memac_select_pcs(struct phylink_config *config, + phy_interface_t iface) +{ + struct fman_mac *memac = fman_config_to_mac(config)->fman_mac; + + switch (iface) { + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_1000BASEX: + return memac->sgmii_pcs; + case PHY_INTERFACE_MODE_QSGMII: + return memac->qsgmii_pcs; + case PHY_INTERFACE_MODE_10GBASER: + return memac->xfi_pcs; + default: + return NULL; + } +} + +static int memac_prepare(struct phylink_config *config, unsigned int mode, + phy_interface_t iface) +{ + struct fman_mac *memac = fman_config_to_mac(config)->fman_mac; + + switch (iface) { + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_1000BASEX: + case PHY_INTERFACE_MODE_QSGMII: + case PHY_INTERFACE_MODE_10GBASER: + return phy_set_mode_ext(memac->serdes, PHY_MODE_ETHERNET, + iface); + default: + return 0; + } +} + +static void memac_mac_config(struct phylink_config *config, unsigned int mode, + const struct phylink_link_state *state) +{ + struct mac_device *mac_dev = fman_config_to_mac(config); + struct memac_regs __iomem *regs = mac_dev->fman_mac->regs; + u32 tmp = ioread32be(®s->if_mode); + + tmp &= ~(IF_MODE_MASK | IF_MODE_RGMII); + tmp |= memac_if_mode(state->interface); + if (phylink_autoneg_inband(mode)) + tmp |= IF_MODE_RGMII_AUTO; + iowrite32be(tmp, ®s->if_mode); +} + +static void memac_link_up(struct phylink_config *config, struct phy_device *phy, + unsigned int mode, phy_interface_t interface, + int speed, int duplex, bool tx_pause, bool rx_pause) +{ + struct mac_device *mac_dev = fman_config_to_mac(config); + struct fman_mac *memac = mac_dev->fman_mac; + struct memac_regs __iomem *regs = memac->regs; + u32 tmp = memac_if_mode(interface); + u16 pause_time = tx_pause ? FSL_FM_PAUSE_TIME_ENABLE : + FSL_FM_PAUSE_TIME_DISABLE; + + memac_set_tx_pause_frames(memac, 0, pause_time, 0); + memac_accept_rx_pause_frames(memac, rx_pause); + + if (duplex == DUPLEX_HALF) + tmp |= IF_MODE_HD; + + switch (speed) { + case SPEED_1000: + tmp |= IF_MODE_RGMII_1000; + break; + case SPEED_100: + tmp |= IF_MODE_RGMII_100; + break; + case SPEED_10: + tmp |= IF_MODE_RGMII_10; + break; + } + iowrite32be(tmp, ®s->if_mode); + + /* TODO: EEE? */ + + if (speed == SPEED_10000) { + if (memac->fm_rev_info.major == 6 && + memac->fm_rev_info.minor == 4) + tmp = TX_FIFO_SECTIONS_TX_AVAIL_SLOW_10G; + else + tmp = TX_FIFO_SECTIONS_TX_AVAIL_10G; + tmp |= TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_10G; + } else { + tmp = TX_FIFO_SECTIONS_TX_AVAIL_1G | + TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_1G; + } + iowrite32be(tmp, ®s->tx_fifo_sections); + + mac_dev->update_speed(mac_dev, speed); + + tmp = ioread32be(®s->command_config); + tmp |= CMD_CFG_RX_EN | CMD_CFG_TX_EN; + iowrite32be(tmp, ®s->command_config); +} + +static void memac_link_down(struct phylink_config *config, unsigned int mode, + phy_interface_t interface) +{ + struct fman_mac *memac = fman_config_to_mac(config)->fman_mac; + struct memac_regs __iomem *regs = memac->regs; + u32 tmp; + + /* TODO: graceful */ + tmp = ioread32be(®s->command_config); + tmp &= ~(CMD_CFG_RX_EN | CMD_CFG_TX_EN); + iowrite32be(tmp, ®s->command_config); +} + +static const struct phylink_mac_ops memac_mac_ops = { + .validate = memac_validate, + .mac_select_pcs = memac_select_pcs, + .mac_prepare = memac_prepare, + .mac_config = memac_mac_config, + .mac_link_up = memac_link_up, + .mac_link_down = memac_link_down, +}; + static int memac_modify_mac_address(struct fman_mac *memac, const enet_addr_t *enet_addr) { - if (!is_init_done(memac->memac_drv_param)) - return -EINVAL; - add_addr_in_paddr(memac->regs, (const u8 *)(*enet_addr), 0); return 0; @@ -867,9 +800,6 @@ static int memac_add_hash_mac_address(struct fman_mac *memac, u32 hash; u64 addr; - if (!is_init_done(memac->memac_drv_param)) - return -EINVAL; - addr = ENET_ADDR_TO_UINT64(*eth_addr); if (!(addr & GROUP_ADDRESS)) { @@ -898,9 +828,6 @@ static int memac_set_allmulti(struct fman_mac *memac, bool enable) u32 entry; struct memac_regs __iomem *regs = memac->regs; - if (!is_init_done(memac->memac_drv_param)) - return -EINVAL; - if (enable) { for (entry = 0; entry < HASH_TABLE_SIZE; entry++) iowrite32be(entry | HASH_CTRL_MCAST_EN, @@ -930,9 +857,6 @@ static int memac_del_hash_mac_address(struct fman_mac *memac, u32 hash; u64 addr; - if (!is_init_done(memac->memac_drv_param)) - return -EINVAL; - addr = ENET_ADDR_TO_UINT64(*eth_addr); hash = get_mac_addr_hash_code(addr) & HASH_CTRL_ADDR_MASK; @@ -960,9 +884,6 @@ static int memac_set_exception(struct fman_mac *memac, { u32 bit_mask = 0; - if (!is_init_done(memac->memac_drv_param)) - return -EINVAL; - bit_mask = get_exception_flag(exception); if (bit_mask) { if (enable) @@ -981,25 +902,16 @@ static int memac_set_exception(struct fman_mac *memac, static int memac_init(struct fman_mac *memac) { struct memac_cfg *memac_drv_param; - u8 i; enet_addr_t eth_addr; - bool slow_10g_if = false; - struct fixed_phy_status *fixed_link = NULL; int err; u32 reg32 = 0; - if (is_init_done(memac->memac_drv_param)) - return -EINVAL; - err = check_init_parameters(memac); if (err) return err; memac_drv_param = memac->memac_drv_param; - if (memac->fm_rev_info.major == 6 && memac->fm_rev_info.minor == 4) - slow_10g_if = true; - /* First, reset the MAC if desired. */ if (memac_drv_param->reset_on_init) { err = reset(memac->regs); @@ -1015,10 +927,7 @@ static int memac_init(struct fman_mac *memac) add_addr_in_paddr(memac->regs, (const u8 *)eth_addr, 0); } - fixed_link = memac_drv_param->fixed_link; - - init(memac->regs, memac->memac_drv_param, memac->phy_if, - memac->max_speed, slow_10g_if, memac->exceptions); + init(memac->regs, memac->memac_drv_param, memac->exceptions); /* FM_RX_FIFO_CORRUPT_ERRATA_10GMAC_A006320 errata workaround * Exists only in FMan 6.0 and 6.3. @@ -1034,33 +943,6 @@ static int memac_init(struct fman_mac *memac) iowrite32be(reg32, &memac->regs->command_config); } - if (memac->phy_if == PHY_INTERFACE_MODE_SGMII) { - /* Configure internal SGMII PHY */ - if (memac->basex_if) - setup_sgmii_internal_phy_base_x(memac); - else - setup_sgmii_internal_phy(memac, fixed_link); - } else if (memac->phy_if == PHY_INTERFACE_MODE_QSGMII) { - /* Configure 4 internal SGMII PHYs */ - for (i = 0; i < 4; i++) { - u8 qsmgii_phy_addr, phy_addr; - /* QSGMII PHY address occupies 3 upper bits of 5-bit - * phy_address; the lower 2 bits are used to extend - * register address space and access each one of 4 - * ports inside QSGMII. - */ - phy_addr = memac->pcsphy->mdio.addr; - qsmgii_phy_addr = (u8)((phy_addr << 2) | i); - memac->pcsphy->mdio.addr = qsmgii_phy_addr; - if (memac->basex_if) - setup_sgmii_internal_phy_base_x(memac); - else - setup_sgmii_internal_phy(memac, fixed_link); - - memac->pcsphy->mdio.addr = phy_addr; - } - } - /* Max Frame Length */ err = fman_set_mac_max_frame(memac->fm, memac->mac_id, memac_drv_param->max_frame_length); @@ -1089,19 +971,28 @@ static int memac_init(struct fman_mac *memac) fman_register_intr(memac->fm, FMAN_MOD_MAC, memac->mac_id, FMAN_INTR_TYPE_NORMAL, memac_exception, memac); - kfree(memac_drv_param); - memac->memac_drv_param = NULL; - return 0; } +static void pcs_put(struct phylink_pcs *pcs) +{ + struct mdio_device *mdiodev; + + if (IS_ERR_OR_NULL(pcs)) + return; + + mdiodev = lynx_get_mdio_device(pcs); + lynx_pcs_destroy(pcs); + mdio_device_free(mdiodev); +} + static int memac_free(struct fman_mac *memac) { free_init_resources(memac); - if (memac->pcsphy) - put_device(&memac->pcsphy->mdio.dev); - + pcs_put(memac->sgmii_pcs); + pcs_put(memac->qsgmii_pcs); + pcs_put(memac->xfi_pcs); kfree(memac->memac_drv_param); kfree(memac); @@ -1134,8 +1025,6 @@ static struct fman_mac *memac_config(struct mac_device *mac_dev, memac->addr = ENET_ADDR_TO_UINT64(mac_dev->addr); memac->regs = mac_dev->vaddr; - memac->max_speed = params->max_speed; - memac->phy_if = mac_dev->phy_if; memac->mac_id = params->mac_id; memac->exceptions = (MEMAC_IMASK_TSECC_ER | MEMAC_IMASK_TECC_ER | MEMAC_IMASK_RECC_ER | MEMAC_IMASK_MGI); @@ -1143,7 +1032,6 @@ static struct fman_mac *memac_config(struct mac_device *mac_dev, memac->event_cb = params->event_cb; memac->dev_id = mac_dev; memac->fm = params->fm; - memac->basex_if = params->basex_if; /* Save FMan revision */ fman_get_revision(memac->fm, &memac->fm_rev_info); @@ -1151,101 +1039,221 @@ static struct fman_mac *memac_config(struct mac_device *mac_dev, return memac; } +static struct phylink_pcs *memac_pcs_create(struct device_node *mac_node, + int index) +{ + struct device_node *node; + struct mdio_device *mdiodev = NULL; + struct phylink_pcs *pcs; + + node = of_parse_phandle(mac_node, "pcsphy-handle", index); + if (node && of_device_is_available(node)) + mdiodev = of_mdio_find_device(node); + of_node_put(node); + + if (!mdiodev) + return ERR_PTR(-EPROBE_DEFER); + + pcs = lynx_pcs_create(mdiodev); + return pcs; +} + +static bool memac_supports(struct mac_device *mac_dev, phy_interface_t iface) +{ + /* If there's no serdes device, assume that it's been configured for + * whatever the default interface mode is. + */ + if (!mac_dev->fman_mac->serdes) + return mac_dev->phy_if == iface; + /* Otherwise, ask the serdes */ + return !phy_validate(mac_dev->fman_mac->serdes, PHY_MODE_ETHERNET, + iface, NULL); +} + int memac_initialization(struct mac_device *mac_dev, struct device_node *mac_node, struct fman_mac_params *params) { int err; - struct device_node *phy_node; - struct fixed_phy_status *fixed_link; + struct device_node *fixed; + struct phylink_pcs *pcs; struct fman_mac *memac; + unsigned long capabilities; + unsigned long *supported; + mac_dev->phylink_ops = &memac_mac_ops; mac_dev->set_promisc = memac_set_promiscuous; mac_dev->change_addr = memac_modify_mac_address; mac_dev->add_hash_mac_addr = memac_add_hash_mac_address; mac_dev->remove_hash_mac_addr = memac_del_hash_mac_address; - mac_dev->set_tx_pause = memac_set_tx_pause_frames; - mac_dev->set_rx_pause = memac_accept_rx_pause_frames; mac_dev->set_exception = memac_set_exception; mac_dev->set_allmulti = memac_set_allmulti; mac_dev->set_tstamp = memac_set_tstamp; mac_dev->set_multi = fman_set_multi; - mac_dev->adjust_link = adjust_link_memac; mac_dev->enable = memac_enable; mac_dev->disable = memac_disable; - if (params->max_speed == SPEED_10000) - mac_dev->phy_if = PHY_INTERFACE_MODE_XGMII; - mac_dev->fman_mac = memac_config(mac_dev, params); - if (!mac_dev->fman_mac) { - err = -EINVAL; - goto _return; - } + if (!mac_dev->fman_mac) + return -EINVAL; memac = mac_dev->fman_mac; memac->memac_drv_param->max_frame_length = fman_get_max_frm(); memac->memac_drv_param->reset_on_init = true; - if (memac->phy_if == PHY_INTERFACE_MODE_SGMII || - memac->phy_if == PHY_INTERFACE_MODE_QSGMII) { - phy_node = of_parse_phandle(mac_node, "pcsphy-handle", 0); - if (!phy_node) { - pr_err("PCS PHY node is not available\n"); - err = -EINVAL; + + err = of_property_match_string(mac_node, "pcs-handle-names", "xfi"); + if (err >= 0) { + memac->xfi_pcs = memac_pcs_create(mac_node, err); + if (IS_ERR(memac->xfi_pcs)) { + err = PTR_ERR(memac->xfi_pcs); + dev_err_probe(mac_dev->dev, err, "missing xfi pcs\n"); goto _return_fm_mac_free; } + } else if (err != -EINVAL && err != -ENODATA) { + goto _return_fm_mac_free; + } - memac->pcsphy = of_phy_find_device(phy_node); - if (!memac->pcsphy) { - pr_err("of_phy_find_device (PCS PHY) failed\n"); - err = -EINVAL; + err = of_property_match_string(mac_node, "pcs-handle-names", "qsgmii"); + if (err >= 0) { + memac->qsgmii_pcs = memac_pcs_create(mac_node, err); + if (IS_ERR(memac->qsgmii_pcs)) { + err = PTR_ERR(memac->qsgmii_pcs); + dev_err_probe(mac_dev->dev, err, + "missing qsgmii pcs\n"); goto _return_fm_mac_free; } + } else if (err != -EINVAL && err != -ENODATA) { + goto _return_fm_mac_free; } - if (!mac_dev->phy_node && of_phy_is_fixed_link(mac_node)) { - struct phy_device *phy; + /* For compatibility, if pcs-handle-names is missing, we assume this + * phy is the first one in pcsphy-handle + */ + err = of_property_match_string(mac_node, "pcs-handle-names", "sgmii"); + if (err == -EINVAL || err == -ENODATA) + pcs = memac_pcs_create(mac_node, 0); + else if (err < 0) + goto _return_fm_mac_free; + else + pcs = memac_pcs_create(mac_node, err); - err = of_phy_register_fixed_link(mac_node); - if (err) - goto _return_fm_mac_free; + if (IS_ERR(pcs)) { + err = PTR_ERR(pcs); + dev_err_probe(mac_dev->dev, err, "missing pcs\n"); + goto _return_fm_mac_free; + } - fixed_link = kzalloc(sizeof(*fixed_link), GFP_KERNEL); - if (!fixed_link) { - err = -ENOMEM; - goto _return_fm_mac_free; - } + /* If err is set here, it means that pcs-handle-names was missing above + * (and therefore that xfi_pcs cannot be set). If we are defaulting to + * XGMII, assume this is for XFI. Otherwise, assume it is for SGMII. + */ + if (err && mac_dev->phy_if == PHY_INTERFACE_MODE_XGMII) + memac->xfi_pcs = pcs; + else + memac->sgmii_pcs = pcs; + + memac->serdes = devm_of_phy_get(mac_dev->dev, mac_node, "serdes"); + err = PTR_ERR(memac->serdes); + if (err == -ENODEV || err == -ENOSYS) { + dev_dbg(mac_dev->dev, "could not get (optional) serdes\n"); + memac->serdes = NULL; + } else if (IS_ERR(memac->serdes)) { + dev_err_probe(mac_dev->dev, err, "could not get serdes\n"); + goto _return_fm_mac_free; + } - mac_dev->phy_node = of_node_get(mac_node); - phy = of_phy_find_device(mac_dev->phy_node); - if (!phy) { - err = -EINVAL; - of_node_put(mac_dev->phy_node); - goto _return_fixed_link_free; - } + /* The internal connection to the serdes is XGMII, but this isn't + * really correct for the phy mode (which is the external connection). + * However, this is how all older device trees say that they want + * 10GBASE-R (aka XFI), so just convert it for them. + */ + if (mac_dev->phy_if == PHY_INTERFACE_MODE_XGMII) + mac_dev->phy_if = PHY_INTERFACE_MODE_10GBASER; + + /* TODO: The following interface modes are supported by (some) hardware + * but not by this driver: + * - 1000BASE-KX + * - 10GBASE-KR + * - XAUI/HiGig + */ + supported = mac_dev->phylink_config.supported_interfaces; - fixed_link->link = phy->link; - fixed_link->speed = phy->speed; - fixed_link->duplex = phy->duplex; - fixed_link->pause = phy->pause; - fixed_link->asym_pause = phy->asym_pause; + /* Note that half duplex is only supported on 10/100M interfaces. */ - put_device(&phy->mdio.dev); - memac->memac_drv_param->fixed_link = fixed_link; + if (memac->sgmii_pcs && + (memac_supports(mac_dev, PHY_INTERFACE_MODE_SGMII) || + memac_supports(mac_dev, PHY_INTERFACE_MODE_1000BASEX))) { + __set_bit(PHY_INTERFACE_MODE_SGMII, supported); + __set_bit(PHY_INTERFACE_MODE_1000BASEX, supported); } + if (memac->sgmii_pcs && + memac_supports(mac_dev, PHY_INTERFACE_MODE_2500BASEX)) + __set_bit(PHY_INTERFACE_MODE_2500BASEX, supported); + + if (memac->qsgmii_pcs && + memac_supports(mac_dev, PHY_INTERFACE_MODE_QSGMII)) + __set_bit(PHY_INTERFACE_MODE_QSGMII, supported); + else if (mac_dev->phy_if == PHY_INTERFACE_MODE_QSGMII) + dev_warn(mac_dev->dev, "no QSGMII pcs specified\n"); + + if (memac->xfi_pcs && + memac_supports(mac_dev, PHY_INTERFACE_MODE_10GBASER)) { + __set_bit(PHY_INTERFACE_MODE_10GBASER, supported); + } else { + /* From what I can tell, no 10g macs support RGMII. */ + phy_interface_set_rgmii(supported); + __set_bit(PHY_INTERFACE_MODE_MII, supported); + } + + capabilities = MAC_SYM_PAUSE | MAC_ASYM_PAUSE | MAC_10 | MAC_100; + capabilities |= MAC_1000FD | MAC_2500FD | MAC_10000FD; + + /* These SoCs don't support half duplex at all; there's no different + * FMan version or compatible, so we just have to check the machine + * compatible instead + */ + if (of_machine_is_compatible("fsl,ls1043a") || + of_machine_is_compatible("fsl,ls1046a") || + of_machine_is_compatible("fsl,B4QDS")) + capabilities &= ~(MAC_10HD | MAC_100HD); + + mac_dev->phylink_config.mac_capabilities = capabilities; + + /* The T2080 and T4240 don't support half duplex RGMII. There is no + * other way to identify these SoCs, so just use the machine + * compatible. + */ + if (of_machine_is_compatible("fsl,T2080QDS") || + of_machine_is_compatible("fsl,T2080RDB") || + of_machine_is_compatible("fsl,T2081QDS") || + of_machine_is_compatible("fsl,T4240QDS") || + of_machine_is_compatible("fsl,T4240RDB")) + memac->rgmii_no_half_duplex = true; + + /* Most boards should use MLO_AN_INBAND, but existing boards don't have + * a managed property. Default to MLO_AN_INBAND if nothing else is + * specified. We need to be careful and not enable this if we have a + * fixed link or if we are using MII or RGMII, since those + * configurations modes don't use in-band autonegotiation. + */ + fixed = of_get_child_by_name(mac_node, "fixed-link"); + if (!fixed && !of_property_read_bool(mac_node, "fixed-link") && + !of_property_read_bool(mac_node, "managed") && + mac_dev->phy_if != PHY_INTERFACE_MODE_MII && + !phy_interface_mode_is_rgmii(mac_dev->phy_if)) + mac_dev->phylink_config.ovr_an_inband = true; + of_node_put(fixed); + err = memac_init(mac_dev->fman_mac); if (err < 0) - goto _return_fixed_link_free; + goto _return_fm_mac_free; dev_info(mac_dev->dev, "FMan MEMAC\n"); - goto _return; + return 0; -_return_fixed_link_free: - kfree(fixed_link); _return_fm_mac_free: memac_free(mac_dev->fman_mac); -_return: return err; } diff --git a/drivers/net/ethernet/freescale/fman/fman_tgec.c b/drivers/net/ethernet/freescale/fman/fman_tgec.c index 5a4be54ad459..c265b7f19a4d 100644 --- a/drivers/net/ethernet/freescale/fman/fman_tgec.c +++ b/drivers/net/ethernet/freescale/fman/fman_tgec.c @@ -13,6 +13,7 @@ #include <linux/bitrev.h> #include <linux/io.h> #include <linux/crc32.h> +#include <linux/netdevice.h> /* Transmit Inter-Packet Gap Length Register (TX_IPG_LENGTH) */ #define TGEC_TX_IPG_LENGTH_MASK 0x000003ff @@ -243,10 +244,6 @@ static int init(struct tgec_regs __iomem *regs, struct tgec_cfg *cfg, static int check_init_parameters(struct fman_mac *tgec) { - if (tgec->max_speed < SPEED_10000) { - pr_err("10G MAC driver only support 10G speed\n"); - return -EINVAL; - } if (!tgec->exception_cb) { pr_err("uninitialized exception_cb\n"); return -EINVAL; @@ -384,40 +381,13 @@ static void free_init_resources(struct fman_mac *tgec) tgec->unicast_addr_hash = NULL; } -static bool is_init_done(struct tgec_cfg *cfg) -{ - /* Checks if tGEC driver parameters were initialized */ - if (!cfg) - return true; - - return false; -} - static int tgec_enable(struct fman_mac *tgec) { - struct tgec_regs __iomem *regs = tgec->regs; - u32 tmp; - - if (!is_init_done(tgec->cfg)) - return -EINVAL; - - tmp = ioread32be(®s->command_config); - tmp |= CMD_CFG_RX_EN | CMD_CFG_TX_EN; - iowrite32be(tmp, ®s->command_config); - return 0; } static void tgec_disable(struct fman_mac *tgec) { - struct tgec_regs __iomem *regs = tgec->regs; - u32 tmp; - - WARN_ON_ONCE(!is_init_done(tgec->cfg)); - - tmp = ioread32be(®s->command_config); - tmp &= ~(CMD_CFG_RX_EN | CMD_CFG_TX_EN); - iowrite32be(tmp, ®s->command_config); } static int tgec_set_promiscuous(struct fman_mac *tgec, bool new_val) @@ -425,9 +395,6 @@ static int tgec_set_promiscuous(struct fman_mac *tgec, bool new_val) struct tgec_regs __iomem *regs = tgec->regs; u32 tmp; - if (!is_init_done(tgec->cfg)) - return -EINVAL; - tmp = ioread32be(®s->command_config); if (new_val) tmp |= CMD_CFG_PROMIS_EN; @@ -444,9 +411,6 @@ static int tgec_set_tx_pause_frames(struct fman_mac *tgec, { struct tgec_regs __iomem *regs = tgec->regs; - if (!is_init_done(tgec->cfg)) - return -EINVAL; - iowrite32be((u32)pause_time, ®s->pause_quant); return 0; @@ -457,9 +421,6 @@ static int tgec_accept_rx_pause_frames(struct fman_mac *tgec, bool en) struct tgec_regs __iomem *regs = tgec->regs; u32 tmp; - if (!is_init_done(tgec->cfg)) - return -EINVAL; - tmp = ioread32be(®s->command_config); if (!en) tmp |= CMD_CFG_PAUSE_IGNORE; @@ -470,12 +431,53 @@ static int tgec_accept_rx_pause_frames(struct fman_mac *tgec, bool en) return 0; } +static void tgec_mac_config(struct phylink_config *config, unsigned int mode, + const struct phylink_link_state *state) +{ +} + +static void tgec_link_up(struct phylink_config *config, struct phy_device *phy, + unsigned int mode, phy_interface_t interface, + int speed, int duplex, bool tx_pause, bool rx_pause) +{ + struct mac_device *mac_dev = fman_config_to_mac(config); + struct fman_mac *tgec = mac_dev->fman_mac; + struct tgec_regs __iomem *regs = tgec->regs; + u16 pause_time = tx_pause ? FSL_FM_PAUSE_TIME_ENABLE : + FSL_FM_PAUSE_TIME_DISABLE; + u32 tmp; + + tgec_set_tx_pause_frames(tgec, 0, pause_time, 0); + tgec_accept_rx_pause_frames(tgec, rx_pause); + mac_dev->update_speed(mac_dev, speed); + + tmp = ioread32be(®s->command_config); + tmp |= CMD_CFG_RX_EN | CMD_CFG_TX_EN; + iowrite32be(tmp, ®s->command_config); +} + +static void tgec_link_down(struct phylink_config *config, unsigned int mode, + phy_interface_t interface) +{ + struct fman_mac *tgec = fman_config_to_mac(config)->fman_mac; + struct tgec_regs __iomem *regs = tgec->regs; + u32 tmp; + + tmp = ioread32be(®s->command_config); + tmp &= ~(CMD_CFG_RX_EN | CMD_CFG_TX_EN); + iowrite32be(tmp, ®s->command_config); +} + +static const struct phylink_mac_ops tgec_mac_ops = { + .validate = phylink_generic_validate, + .mac_config = tgec_mac_config, + .mac_link_up = tgec_link_up, + .mac_link_down = tgec_link_down, +}; + static int tgec_modify_mac_address(struct fman_mac *tgec, const enet_addr_t *p_enet_addr) { - if (!is_init_done(tgec->cfg)) - return -EINVAL; - tgec->addr = ENET_ADDR_TO_UINT64(*p_enet_addr); set_mac_address(tgec->regs, (const u8 *)(*p_enet_addr)); @@ -490,9 +492,6 @@ static int tgec_add_hash_mac_address(struct fman_mac *tgec, u32 crc = 0xFFFFFFFF, hash; u64 addr; - if (!is_init_done(tgec->cfg)) - return -EINVAL; - addr = ENET_ADDR_TO_UINT64(*eth_addr); if (!(addr & GROUP_ADDRESS)) { @@ -525,9 +524,6 @@ static int tgec_set_allmulti(struct fman_mac *tgec, bool enable) u32 entry; struct tgec_regs __iomem *regs = tgec->regs; - if (!is_init_done(tgec->cfg)) - return -EINVAL; - if (enable) { for (entry = 0; entry < TGEC_HASH_TABLE_SIZE; entry++) iowrite32be(entry | TGEC_HASH_MCAST_EN, @@ -548,9 +544,6 @@ static int tgec_set_tstamp(struct fman_mac *tgec, bool enable) struct tgec_regs __iomem *regs = tgec->regs; u32 tmp; - if (!is_init_done(tgec->cfg)) - return -EINVAL; - tmp = ioread32be(®s->command_config); if (enable) @@ -572,9 +565,6 @@ static int tgec_del_hash_mac_address(struct fman_mac *tgec, u32 crc = 0xFFFFFFFF, hash; u64 addr; - if (!is_init_done(tgec->cfg)) - return -EINVAL; - addr = ((*(u64 *)eth_addr) >> 16); /* CRC calculation */ @@ -601,22 +591,12 @@ static int tgec_del_hash_mac_address(struct fman_mac *tgec, return 0; } -static void tgec_adjust_link(struct mac_device *mac_dev) -{ - struct phy_device *phy_dev = mac_dev->phy_dev; - - mac_dev->update_speed(mac_dev, phy_dev->speed); -} - static int tgec_set_exception(struct fman_mac *tgec, enum fman_mac_exceptions exception, bool enable) { struct tgec_regs __iomem *regs = tgec->regs; u32 bit_mask = 0; - if (!is_init_done(tgec->cfg)) - return -EINVAL; - bit_mask = get_exception_flag(exception); if (bit_mask) { if (enable) @@ -641,9 +621,6 @@ static int tgec_init(struct fman_mac *tgec) enet_addr_t eth_addr; int err; - if (is_init_done(tgec->cfg)) - return -EINVAL; - if (DEFAULT_RESET_ON_INIT && (fman_reset_mac(tgec->fm, tgec->mac_id) != 0)) { pr_err("Can't reset MAC!\n"); @@ -753,7 +730,6 @@ static struct fman_mac *tgec_config(struct mac_device *mac_dev, tgec->regs = mac_dev->vaddr; tgec->addr = ENET_ADDR_TO_UINT64(mac_dev->addr); - tgec->max_speed = params->max_speed; tgec->mac_id = params->mac_id; tgec->exceptions = (TGEC_IMASK_MDIO_SCAN_EVENT | TGEC_IMASK_REM_FAULT | @@ -788,17 +764,15 @@ int tgec_initialization(struct mac_device *mac_dev, int err; struct fman_mac *tgec; + mac_dev->phylink_ops = &tgec_mac_ops; mac_dev->set_promisc = tgec_set_promiscuous; mac_dev->change_addr = tgec_modify_mac_address; mac_dev->add_hash_mac_addr = tgec_add_hash_mac_address; mac_dev->remove_hash_mac_addr = tgec_del_hash_mac_address; - mac_dev->set_tx_pause = tgec_set_tx_pause_frames; - mac_dev->set_rx_pause = tgec_accept_rx_pause_frames; mac_dev->set_exception = tgec_set_exception; mac_dev->set_allmulti = tgec_set_allmulti; mac_dev->set_tstamp = tgec_set_tstamp; mac_dev->set_multi = fman_set_multi; - mac_dev->adjust_link = tgec_adjust_link; mac_dev->enable = tgec_enable; mac_dev->disable = tgec_disable; @@ -808,6 +782,19 @@ int tgec_initialization(struct mac_device *mac_dev, goto _return; } + /* The internal connection to the serdes is XGMII, but this isn't + * really correct for the phy mode (which is the external connection). + * However, this is how all older device trees say that they want + * XAUI, so just convert it for them. + */ + if (mac_dev->phy_if == PHY_INTERFACE_MODE_XGMII) + mac_dev->phy_if = PHY_INTERFACE_MODE_XAUI; + + __set_bit(PHY_INTERFACE_MODE_XAUI, + mac_dev->phylink_config.supported_interfaces); + mac_dev->phylink_config.mac_capabilities = + MAC_SYM_PAUSE | MAC_ASYM_PAUSE | MAC_10000FD; + tgec = mac_dev->fman_mac; tgec->cfg->max_frame_length = fman_get_max_frm(); err = tgec_init(tgec); diff --git a/drivers/net/ethernet/freescale/fman/mac.c b/drivers/net/ethernet/freescale/fman/mac.c index 7b7526fd7da3..c6496a498726 100644 --- a/drivers/net/ethernet/freescale/fman/mac.c +++ b/drivers/net/ethernet/freescale/fman/mac.c @@ -15,6 +15,7 @@ #include <linux/phy.h> #include <linux/netdevice.h> #include <linux/phy_fixed.h> +#include <linux/phylink.h> #include <linux/etherdevice.h> #include <linux/libfdt_env.h> @@ -93,130 +94,8 @@ int fman_set_multi(struct net_device *net_dev, struct mac_device *mac_dev) return 0; } -/** - * fman_set_mac_active_pause - * @mac_dev: A pointer to the MAC device - * @rx: Pause frame setting for RX - * @tx: Pause frame setting for TX - * - * Set the MAC RX/TX PAUSE frames settings - * - * Avoid redundant calls to FMD, if the MAC driver already contains the desired - * active PAUSE settings. Otherwise, the new active settings should be reflected - * in FMan. - * - * Return: 0 on success; Error code otherwise. - */ -int fman_set_mac_active_pause(struct mac_device *mac_dev, bool rx, bool tx) -{ - struct fman_mac *fman_mac = mac_dev->fman_mac; - int err = 0; - - if (rx != mac_dev->rx_pause_active) { - err = mac_dev->set_rx_pause(fman_mac, rx); - if (likely(err == 0)) - mac_dev->rx_pause_active = rx; - } - - if (tx != mac_dev->tx_pause_active) { - u16 pause_time = (tx ? FSL_FM_PAUSE_TIME_ENABLE : - FSL_FM_PAUSE_TIME_DISABLE); - - err = mac_dev->set_tx_pause(fman_mac, 0, pause_time, 0); - - if (likely(err == 0)) - mac_dev->tx_pause_active = tx; - } - - return err; -} -EXPORT_SYMBOL(fman_set_mac_active_pause); - -/** - * fman_get_pause_cfg - * @mac_dev: A pointer to the MAC device - * @rx_pause: Return value for RX setting - * @tx_pause: Return value for TX setting - * - * Determine the MAC RX/TX PAUSE frames settings based on PHY - * autonegotiation or values set by eththool. - * - * Return: Pointer to FMan device. - */ -void fman_get_pause_cfg(struct mac_device *mac_dev, bool *rx_pause, - bool *tx_pause) -{ - struct phy_device *phy_dev = mac_dev->phy_dev; - u16 lcl_adv, rmt_adv; - u8 flowctrl; - - *rx_pause = *tx_pause = false; - - if (!phy_dev->duplex) - return; - - /* If PAUSE autonegotiation is disabled, the TX/RX PAUSE settings - * are those set by ethtool. - */ - if (!mac_dev->autoneg_pause) { - *rx_pause = mac_dev->rx_pause_req; - *tx_pause = mac_dev->tx_pause_req; - return; - } - - /* Else if PAUSE autonegotiation is enabled, the TX/RX PAUSE - * settings depend on the result of the link negotiation. - */ - - /* get local capabilities */ - lcl_adv = linkmode_adv_to_lcl_adv_t(phy_dev->advertising); - - /* get link partner capabilities */ - rmt_adv = 0; - if (phy_dev->pause) - rmt_adv |= LPA_PAUSE_CAP; - if (phy_dev->asym_pause) - rmt_adv |= LPA_PAUSE_ASYM; - - /* Calculate TX/RX settings based on local and peer advertised - * symmetric/asymmetric PAUSE capabilities. - */ - flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv); - if (flowctrl & FLOW_CTRL_RX) - *rx_pause = true; - if (flowctrl & FLOW_CTRL_TX) - *tx_pause = true; -} -EXPORT_SYMBOL(fman_get_pause_cfg); - -#define DTSEC_SUPPORTED \ - (SUPPORTED_10baseT_Half \ - | SUPPORTED_10baseT_Full \ - | SUPPORTED_100baseT_Half \ - | SUPPORTED_100baseT_Full \ - | SUPPORTED_Autoneg \ - | SUPPORTED_Pause \ - | SUPPORTED_Asym_Pause \ - | SUPPORTED_FIBRE \ - | SUPPORTED_MII) - static DEFINE_MUTEX(eth_lock); -static const u16 phy2speed[] = { - [PHY_INTERFACE_MODE_MII] = SPEED_100, - [PHY_INTERFACE_MODE_GMII] = SPEED_1000, - [PHY_INTERFACE_MODE_SGMII] = SPEED_1000, - [PHY_INTERFACE_MODE_TBI] = SPEED_1000, - [PHY_INTERFACE_MODE_RMII] = SPEED_100, - [PHY_INTERFACE_MODE_RGMII] = SPEED_1000, - [PHY_INTERFACE_MODE_RGMII_ID] = SPEED_1000, - [PHY_INTERFACE_MODE_RGMII_RXID] = SPEED_1000, - [PHY_INTERFACE_MODE_RGMII_TXID] = SPEED_1000, - [PHY_INTERFACE_MODE_RTBI] = SPEED_1000, - [PHY_INTERFACE_MODE_QSGMII] = SPEED_1000, - [PHY_INTERFACE_MODE_XGMII] = SPEED_10000 -}; - static struct platform_device *dpaa_eth_add_device(int fman_id, struct mac_device *mac_dev) { @@ -263,8 +142,8 @@ no_mem: } static const struct of_device_id mac_match[] = { - { .compatible = "fsl,fman-dtsec", .data = dtsec_initialization }, - { .compatible = "fsl,fman-xgec", .data = tgec_initialization }, + { .compatible = "fsl,fman-dtsec", .data = dtsec_initialization }, + { .compatible = "fsl,fman-xgec", .data = tgec_initialization }, { .compatible = "fsl,fman-memac", .data = memac_initialization }, {} }; @@ -279,7 +158,6 @@ static int mac_probe(struct platform_device *_of_dev) struct device_node *mac_node, *dev_node; struct mac_device *mac_dev; struct platform_device *of_dev; - struct resource *res; struct mac_priv_s *priv; struct fman_mac_params params; u32 val; @@ -296,6 +174,7 @@ static int mac_probe(struct platform_device *_of_dev) priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; + platform_set_drvdata(_of_dev, mac_dev); /* Save private information */ mac_dev->priv = priv; @@ -338,24 +217,25 @@ static int mac_probe(struct platform_device *_of_dev) of_node_put(dev_node); /* Get the address of the memory mapped registers */ - res = platform_get_mem_or_io(_of_dev, 0); - if (!res) { + mac_dev->res = platform_get_mem_or_io(_of_dev, 0); + if (!mac_dev->res) { dev_err(dev, "could not get registers\n"); return -EINVAL; } - err = devm_request_resource(dev, fman_get_mem_region(priv->fman), res); + err = devm_request_resource(dev, fman_get_mem_region(priv->fman), + mac_dev->res); if (err) { dev_err_probe(dev, err, "could not request resource\n"); return err; } - mac_dev->vaddr = devm_ioremap(dev, res->start, resource_size(res)); + mac_dev->vaddr = devm_ioremap(dev, mac_dev->res->start, + resource_size(mac_dev->res)); if (!mac_dev->vaddr) { dev_err(dev, "devm_ioremap() failed\n"); return -EIO; } - mac_dev->vaddr_end = mac_dev->vaddr + resource_size(res); if (!of_device_is_available(mac_node)) return -ENODEV; @@ -424,57 +304,21 @@ static int mac_probe(struct platform_device *_of_dev) } mac_dev->phy_if = phy_if; - priv->speed = phy2speed[mac_dev->phy_if]; - params.max_speed = priv->speed; - mac_dev->if_support = DTSEC_SUPPORTED; - /* We don't support half-duplex in SGMII mode */ - if (mac_dev->phy_if == PHY_INTERFACE_MODE_SGMII) - mac_dev->if_support &= ~(SUPPORTED_10baseT_Half | - SUPPORTED_100baseT_Half); - - /* Gigabit support (no half-duplex) */ - if (params.max_speed == 1000) - mac_dev->if_support |= SUPPORTED_1000baseT_Full; - - /* The 10G interface only supports one mode */ - if (mac_dev->phy_if == PHY_INTERFACE_MODE_XGMII) - mac_dev->if_support = SUPPORTED_10000baseT_Full; - - /* Get the rest of the PHY information */ - mac_dev->phy_node = of_parse_phandle(mac_node, "phy-handle", 0); - - params.basex_if = false; params.mac_id = priv->cell_index; params.fm = (void *)priv->fman; params.exception_cb = mac_exception; params.event_cb = mac_exception; err = init(mac_dev, mac_node, ¶ms); - if (err < 0) { - dev_err(dev, "mac_dev->init() = %d\n", err); - of_node_put(mac_dev->phy_node); - return err; - } - - /* pause frame autonegotiation enabled */ - mac_dev->autoneg_pause = true; - - /* By intializing the values to false, force FMD to enable PAUSE frames - * on RX and TX - */ - mac_dev->rx_pause_req = true; - mac_dev->tx_pause_req = true; - mac_dev->rx_pause_active = false; - mac_dev->tx_pause_active = false; - err = fman_set_mac_active_pause(mac_dev, true, true); if (err < 0) - dev_err(dev, "fman_set_mac_active_pause() = %d\n", err); + return err; if (!is_zero_ether_addr(mac_dev->addr)) dev_info(dev, "FMan MAC address: %pM\n", mac_dev->addr); priv->eth_dev = dpaa_eth_add_device(fman_id, mac_dev); if (IS_ERR(priv->eth_dev)) { + err = PTR_ERR(priv->eth_dev); dev_err(dev, "failed to add Ethernet platform device for MAC %d\n", priv->cell_index); priv->eth_dev = NULL; diff --git a/drivers/net/ethernet/freescale/fman/mac.h b/drivers/net/ethernet/freescale/fman/mac.h index b95d384271bd..ad06f8d7924b 100644 --- a/drivers/net/ethernet/freescale/fman/mac.h +++ b/drivers/net/ethernet/freescale/fman/mac.h @@ -9,6 +9,7 @@ #include <linux/device.h> #include <linux/if_ether.h> #include <linux/phy.h> +#include <linux/phylink.h> #include <linux/list.h> #include "fman_port.h" @@ -20,36 +21,26 @@ struct mac_priv_s; struct mac_device { void __iomem *vaddr; - void __iomem *vaddr_end; struct device *dev; + struct resource *res; u8 addr[ETH_ALEN]; struct fman_port *port[2]; - u32 if_support; - struct phy_device *phy_dev; + struct phylink *phylink; + struct phylink_config phylink_config; phy_interface_t phy_if; - struct device_node *phy_node; - struct net_device *net_dev; - bool autoneg_pause; - bool rx_pause_req; - bool tx_pause_req; - bool rx_pause_active; - bool tx_pause_active; bool promisc; bool allmulti; + const struct phylink_mac_ops *phylink_ops; int (*enable)(struct fman_mac *mac_dev); void (*disable)(struct fman_mac *mac_dev); - void (*adjust_link)(struct mac_device *mac_dev); int (*set_promisc)(struct fman_mac *mac_dev, bool enable); int (*change_addr)(struct fman_mac *mac_dev, const enet_addr_t *enet_addr); int (*set_allmulti)(struct fman_mac *mac_dev, bool enable); int (*set_tstamp)(struct fman_mac *mac_dev, bool enable); int (*set_multi)(struct net_device *net_dev, struct mac_device *mac_dev); - int (*set_rx_pause)(struct fman_mac *mac_dev, bool en); - int (*set_tx_pause)(struct fman_mac *mac_dev, u8 priority, - u16 pause_time, u16 thresh_time); int (*set_exception)(struct fman_mac *mac_dev, enum fman_mac_exceptions exception, bool enable); int (*add_hash_mac_addr)(struct fman_mac *mac_dev, @@ -63,6 +54,12 @@ struct mac_device { struct mac_priv_s *priv; }; +static inline struct mac_device +*fman_config_to_mac(struct phylink_config *config) +{ + return container_of(config, struct mac_device, phylink_config); +} + struct dpaa_eth_data { struct mac_device *mac_dev; int mac_hw_id; diff --git a/drivers/net/ethernet/hisilicon/hns/hnae.c b/drivers/net/ethernet/hisilicon/hns/hnae.c index 00fafc0f8512..430eccea8e5e 100644 --- a/drivers/net/ethernet/hisilicon/hns/hnae.c +++ b/drivers/net/ethernet/hisilicon/hns/hnae.c @@ -419,8 +419,10 @@ int hnae_ae_register(struct hnae_ae_dev *hdev, struct module *owner) hdev->cls_dev.release = hnae_release; (void)dev_set_name(&hdev->cls_dev, "hnae%d", hdev->id); ret = device_register(&hdev->cls_dev); - if (ret) + if (ret) { + put_device(&hdev->cls_dev); return ret; + } __module_get(THIS_MODULE); diff --git a/drivers/net/ethernet/huawei/hinic/hinic_debugfs.c b/drivers/net/ethernet/huawei/hinic/hinic_debugfs.c index 19eb839177ec..061952c6c21a 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_debugfs.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_debugfs.c @@ -85,6 +85,7 @@ static int hinic_dbg_get_func_table(struct hinic_dev *nic_dev, int idx) struct tag_sml_funcfg_tbl *funcfg_table_elem; struct hinic_cmd_lt_rd *read_data; u16 out_size = sizeof(*read_data); + int ret = ~0; int err; read_data = kzalloc(sizeof(*read_data), GFP_KERNEL); @@ -111,20 +112,25 @@ static int hinic_dbg_get_func_table(struct hinic_dev *nic_dev, int idx) switch (idx) { case VALID: - return funcfg_table_elem->dw0.bs.valid; + ret = funcfg_table_elem->dw0.bs.valid; + break; case RX_MODE: - return funcfg_table_elem->dw0.bs.nic_rx_mode; + ret = funcfg_table_elem->dw0.bs.nic_rx_mode; + break; case MTU: - return funcfg_table_elem->dw1.bs.mtu; + ret = funcfg_table_elem->dw1.bs.mtu; + break; case RQ_DEPTH: - return funcfg_table_elem->dw13.bs.cfg_rq_depth; + ret = funcfg_table_elem->dw13.bs.cfg_rq_depth; + break; case QUEUE_NUM: - return funcfg_table_elem->dw13.bs.cfg_q_num; + ret = funcfg_table_elem->dw13.bs.cfg_q_num; + break; } kfree(read_data); - return ~0; + return ret; } static ssize_t hinic_dbg_cmd_read(struct file *filp, char __user *buffer, size_t count, diff --git a/drivers/net/ethernet/huawei/hinic/hinic_dev.h b/drivers/net/ethernet/huawei/hinic/hinic_dev.h index a4fbf44f944c..52ea97c818b8 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_dev.h +++ b/drivers/net/ethernet/huawei/hinic/hinic_dev.h @@ -22,6 +22,10 @@ #define LP_PKT_CNT 64 +#define HINIC_MAX_JUMBO_FRAME_SIZE 15872 +#define HINIC_MAX_MTU_SIZE (HINIC_MAX_JUMBO_FRAME_SIZE - ETH_HLEN - ETH_FCS_LEN) +#define HINIC_MIN_MTU_SIZE 256 + enum hinic_flags { HINIC_LINK_UP = BIT(0), HINIC_INTF_UP = BIT(1), diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_cmdq.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_cmdq.c index 78190e88cd75..d39eec9c62bf 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_hw_cmdq.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_cmdq.c @@ -924,7 +924,7 @@ int hinic_init_cmdqs(struct hinic_cmdqs *cmdqs, struct hinic_hwif *hwif, err_set_cmdq_depth: hinic_ceq_unregister_cb(&func_to_io->ceqs, HINIC_CEQ_CMDQ); - + free_cmdq(&cmdqs->cmdq[HINIC_CMDQ_SYNC]); err_cmdq_ctxt: hinic_wqs_cmdq_free(&cmdqs->cmdq_pages, cmdqs->saved_wqs, HINIC_MAX_CMDQ_TYPES); diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c index 94f470556295..27795288c586 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c @@ -877,7 +877,7 @@ int hinic_set_interrupt_cfg(struct hinic_hwdev *hwdev, if (err) return -EINVAL; - interrupt_info->lli_credit_cnt = temp_info.lli_timer_cnt; + interrupt_info->lli_credit_cnt = temp_info.lli_credit_cnt; interrupt_info->lli_timer_cnt = temp_info.lli_timer_cnt; err = hinic_msg_to_mgmt(&pfhwdev->pf_to_mgmt, HINIC_MOD_COMM, diff --git a/drivers/net/ethernet/huawei/hinic/hinic_main.c b/drivers/net/ethernet/huawei/hinic/hinic_main.c index e1f54a2f28b2..9d4d795e1081 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_main.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_main.c @@ -1187,7 +1187,8 @@ static int nic_dev_init(struct pci_dev *pdev) else netdev->netdev_ops = &hinicvf_netdev_ops; - netdev->max_mtu = ETH_MAX_MTU; + netdev->max_mtu = HINIC_MAX_MTU_SIZE; + netdev->min_mtu = HINIC_MIN_MTU_SIZE; nic_dev = netdev_priv(netdev); nic_dev->netdev = netdev; diff --git a/drivers/net/ethernet/huawei/hinic/hinic_port.c b/drivers/net/ethernet/huawei/hinic/hinic_port.c index 28ae6f1201a8..0a39c3dffa9a 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_port.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_port.c @@ -17,9 +17,6 @@ #include "hinic_port.h" #include "hinic_dev.h" -#define HINIC_MIN_MTU_SIZE 256 -#define HINIC_MAX_JUMBO_FRAME_SIZE 15872 - enum mac_op { MAC_DEL, MAC_SET, @@ -147,24 +144,12 @@ int hinic_port_get_mac(struct hinic_dev *nic_dev, u8 *addr) **/ int hinic_port_set_mtu(struct hinic_dev *nic_dev, int new_mtu) { - struct net_device *netdev = nic_dev->netdev; struct hinic_hwdev *hwdev = nic_dev->hwdev; struct hinic_port_mtu_cmd port_mtu_cmd; struct hinic_hwif *hwif = hwdev->hwif; u16 out_size = sizeof(port_mtu_cmd); struct pci_dev *pdev = hwif->pdev; - int err, max_frame; - - if (new_mtu < HINIC_MIN_MTU_SIZE) { - netif_err(nic_dev, drv, netdev, "mtu < MIN MTU size"); - return -EINVAL; - } - - max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN; - if (max_frame > HINIC_MAX_JUMBO_FRAME_SIZE) { - netif_err(nic_dev, drv, netdev, "mtu > MAX MTU size"); - return -EINVAL; - } + int err; port_mtu_cmd.func_idx = HINIC_HWIF_FUNC_IDX(hwif); port_mtu_cmd.mtu = new_mtu; diff --git a/drivers/net/ethernet/huawei/hinic/hinic_sriov.c b/drivers/net/ethernet/huawei/hinic/hinic_sriov.c index a5f08b969e3f..f7e05b41385b 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_sriov.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_sriov.c @@ -1174,7 +1174,6 @@ int hinic_vf_func_init(struct hinic_hwdev *hwdev) dev_err(&hwdev->hwif->pdev->dev, "Failed to register VF, err: %d, status: 0x%x, out size: 0x%x\n", err, register_info.status, out_size); - hinic_unregister_vf_mbox_cb(hwdev, HINIC_MOD_L2NIC); return -EIO; } } else { diff --git a/drivers/net/ethernet/ibm/ehea/ehea_main.c b/drivers/net/ethernet/ibm/ehea/ehea_main.c index 294bdbbeacc3..b4aff59b3eb4 100644 --- a/drivers/net/ethernet/ibm/ehea/ehea_main.c +++ b/drivers/net/ethernet/ibm/ehea/ehea_main.c @@ -2900,6 +2900,7 @@ static struct device *ehea_register_port(struct ehea_port *port, ret = of_device_register(&port->ofdev); if (ret) { pr_err("failed to register device. ret=%d\n", ret); + put_device(&port->ofdev.dev); goto out; } diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c index 3b14dc93f59d..7d79006250ae 100644 --- a/drivers/net/ethernet/ibm/ibmveth.c +++ b/drivers/net/ethernet/ibm/ibmveth.c @@ -690,8 +690,7 @@ static int ibmveth_close(struct net_device *netdev) napi_disable(&adapter->napi); - if (!adapter->pool_config) - netif_tx_stop_all_queues(netdev); + netif_tx_stop_all_queues(netdev); h_vio_signal(adapter->vdev->unit_address, VIO_IRQ_DISABLE); @@ -799,9 +798,7 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data) if (netif_running(dev)) { restart = 1; - adapter->pool_config = 1; ibmveth_close(dev); - adapter->pool_config = 0; } set_attr = 0; @@ -883,9 +880,7 @@ static int ibmveth_set_tso(struct net_device *dev, u32 data) if (netif_running(dev)) { restart = 1; - adapter->pool_config = 1; ibmveth_close(dev); - adapter->pool_config = 0; } set_attr = 0; @@ -1535,9 +1530,7 @@ static int ibmveth_change_mtu(struct net_device *dev, int new_mtu) only the buffer pools necessary to hold the new MTU */ if (netif_running(adapter->netdev)) { need_restart = 1; - adapter->pool_config = 1; ibmveth_close(adapter->netdev); - adapter->pool_config = 0; } /* Look for an active buffer pool that can hold the new MTU */ @@ -1701,7 +1694,6 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id) adapter->vdev = dev; adapter->netdev = netdev; adapter->mcastFilterSize = be32_to_cpu(*mcastFilterSize_p); - adapter->pool_config = 0; ibmveth_init_link_settings(netdev); netif_napi_add_weight(netdev, &adapter->napi, ibmveth_poll, 16); @@ -1841,9 +1833,7 @@ static ssize_t veth_pool_store(struct kobject *kobj, struct attribute *attr, return -ENOMEM; } pool->active = 1; - adapter->pool_config = 1; ibmveth_close(netdev); - adapter->pool_config = 0; if ((rc = ibmveth_open(netdev))) return rc; } else { @@ -1869,10 +1859,8 @@ static ssize_t veth_pool_store(struct kobject *kobj, struct attribute *attr, } if (netif_running(netdev)) { - adapter->pool_config = 1; ibmveth_close(netdev); pool->active = 0; - adapter->pool_config = 0; if ((rc = ibmveth_open(netdev))) return rc; } @@ -1883,9 +1871,7 @@ static ssize_t veth_pool_store(struct kobject *kobj, struct attribute *attr, return -EINVAL; } else { if (netif_running(netdev)) { - adapter->pool_config = 1; ibmveth_close(netdev); - adapter->pool_config = 0; pool->size = value; if ((rc = ibmveth_open(netdev))) return rc; @@ -1898,9 +1884,7 @@ static ssize_t veth_pool_store(struct kobject *kobj, struct attribute *attr, return -EINVAL; } else { if (netif_running(netdev)) { - adapter->pool_config = 1; ibmveth_close(netdev); - adapter->pool_config = 0; pool->buff_size = value; if ((rc = ibmveth_open(netdev))) return rc; diff --git a/drivers/net/ethernet/ibm/ibmveth.h b/drivers/net/ethernet/ibm/ibmveth.h index daf6f615c03f..4f8357187292 100644 --- a/drivers/net/ethernet/ibm/ibmveth.h +++ b/drivers/net/ethernet/ibm/ibmveth.h @@ -146,7 +146,6 @@ struct ibmveth_adapter { dma_addr_t filter_list_dma; struct ibmveth_buff_pool rx_buff_pool[IBMVETH_NUM_BUFF_POOLS]; struct ibmveth_rx_q rx_queue; - int pool_config; int rx_csum; int large_send; bool is_active_trunk; diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 7e75706f76db..4a6a6e48c615 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -2183,9 +2183,6 @@ static int i40e_set_ringparam(struct net_device *netdev, err = i40e_setup_rx_descriptors(&rx_rings[i]); if (err) goto rx_unwind; - err = i40e_alloc_rx_bi(&rx_rings[i]); - if (err) - goto rx_unwind; /* now allocate the Rx buffers to make sure the OS * has enough memory, any failure here means abort @@ -3188,10 +3185,17 @@ static int i40e_get_rss_hash_opts(struct i40e_pf *pf, struct ethtool_rxnfc *cmd) if (cmd->flow_type == TCP_V4_FLOW || cmd->flow_type == UDP_V4_FLOW) { - if (i_set & I40E_L3_SRC_MASK) - cmd->data |= RXH_IP_SRC; - if (i_set & I40E_L3_DST_MASK) - cmd->data |= RXH_IP_DST; + if (hw->mac.type == I40E_MAC_X722) { + if (i_set & I40E_X722_L3_SRC_MASK) + cmd->data |= RXH_IP_SRC; + if (i_set & I40E_X722_L3_DST_MASK) + cmd->data |= RXH_IP_DST; + } else { + if (i_set & I40E_L3_SRC_MASK) + cmd->data |= RXH_IP_SRC; + if (i_set & I40E_L3_DST_MASK) + cmd->data |= RXH_IP_DST; + } } else if (cmd->flow_type == TCP_V6_FLOW || cmd->flow_type == UDP_V6_FLOW) { if (i_set & I40E_L3_V6_SRC_MASK) @@ -3549,12 +3553,15 @@ static int i40e_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd, /** * i40e_get_rss_hash_bits - Read RSS Hash bits from register + * @hw: hw structure * @nfc: pointer to user request * @i_setc: bits currently set * * Returns value of bits to be set per user request **/ -static u64 i40e_get_rss_hash_bits(struct ethtool_rxnfc *nfc, u64 i_setc) +static u64 i40e_get_rss_hash_bits(struct i40e_hw *hw, + struct ethtool_rxnfc *nfc, + u64 i_setc) { u64 i_set = i_setc; u64 src_l3 = 0, dst_l3 = 0; @@ -3573,8 +3580,13 @@ static u64 i40e_get_rss_hash_bits(struct ethtool_rxnfc *nfc, u64 i_setc) dst_l3 = I40E_L3_V6_DST_MASK; } else if (nfc->flow_type == TCP_V4_FLOW || nfc->flow_type == UDP_V4_FLOW) { - src_l3 = I40E_L3_SRC_MASK; - dst_l3 = I40E_L3_DST_MASK; + if (hw->mac.type == I40E_MAC_X722) { + src_l3 = I40E_X722_L3_SRC_MASK; + dst_l3 = I40E_X722_L3_DST_MASK; + } else { + src_l3 = I40E_L3_SRC_MASK; + dst_l3 = I40E_L3_DST_MASK; + } } else { /* Any other flow type are not supported here */ return i_set; @@ -3592,6 +3604,7 @@ static u64 i40e_get_rss_hash_bits(struct ethtool_rxnfc *nfc, u64 i_setc) return i_set; } +#define FLOW_PCTYPES_SIZE 64 /** * i40e_set_rss_hash_opt - Enable/Disable flow types for RSS hash * @pf: pointer to the physical function struct @@ -3604,9 +3617,11 @@ static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc) struct i40e_hw *hw = &pf->hw; u64 hena = (u64)i40e_read_rx_ctl(hw, I40E_PFQF_HENA(0)) | ((u64)i40e_read_rx_ctl(hw, I40E_PFQF_HENA(1)) << 32); - u8 flow_pctype = 0; + DECLARE_BITMAP(flow_pctypes, FLOW_PCTYPES_SIZE); u64 i_set, i_setc; + bitmap_zero(flow_pctypes, FLOW_PCTYPES_SIZE); + if (pf->flags & I40E_FLAG_MFP_ENABLED) { dev_err(&pf->pdev->dev, "Change of RSS hash input set is not supported when MFP mode is enabled\n"); @@ -3622,36 +3637,35 @@ static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc) switch (nfc->flow_type) { case TCP_V4_FLOW: - flow_pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP; + set_bit(I40E_FILTER_PCTYPE_NONF_IPV4_TCP, flow_pctypes); if (pf->hw_features & I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE) - hena |= - BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK); + set_bit(I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK, + flow_pctypes); break; case TCP_V6_FLOW: - flow_pctype = I40E_FILTER_PCTYPE_NONF_IPV6_TCP; - if (pf->hw_features & I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE) - hena |= - BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK); + set_bit(I40E_FILTER_PCTYPE_NONF_IPV6_TCP, flow_pctypes); if (pf->hw_features & I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE) - hena |= - BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK); + set_bit(I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK, + flow_pctypes); break; case UDP_V4_FLOW: - flow_pctype = I40E_FILTER_PCTYPE_NONF_IPV4_UDP; - if (pf->hw_features & I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE) - hena |= - BIT_ULL(I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP) | - BIT_ULL(I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP); - + set_bit(I40E_FILTER_PCTYPE_NONF_IPV4_UDP, flow_pctypes); + if (pf->hw_features & I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE) { + set_bit(I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP, + flow_pctypes); + set_bit(I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP, + flow_pctypes); + } hena |= BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV4); break; case UDP_V6_FLOW: - flow_pctype = I40E_FILTER_PCTYPE_NONF_IPV6_UDP; - if (pf->hw_features & I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE) - hena |= - BIT_ULL(I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP) | - BIT_ULL(I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP); - + set_bit(I40E_FILTER_PCTYPE_NONF_IPV6_UDP, flow_pctypes); + if (pf->hw_features & I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE) { + set_bit(I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP, + flow_pctypes); + set_bit(I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP, + flow_pctypes); + } hena |= BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV6); break; case AH_ESP_V4_FLOW: @@ -3684,17 +3698,20 @@ static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc) return -EINVAL; } - if (flow_pctype) { - i_setc = (u64)i40e_read_rx_ctl(hw, I40E_GLQF_HASH_INSET(0, - flow_pctype)) | - ((u64)i40e_read_rx_ctl(hw, I40E_GLQF_HASH_INSET(1, - flow_pctype)) << 32); - i_set = i40e_get_rss_hash_bits(nfc, i_setc); - i40e_write_rx_ctl(hw, I40E_GLQF_HASH_INSET(0, flow_pctype), - (u32)i_set); - i40e_write_rx_ctl(hw, I40E_GLQF_HASH_INSET(1, flow_pctype), - (u32)(i_set >> 32)); - hena |= BIT_ULL(flow_pctype); + if (bitmap_weight(flow_pctypes, FLOW_PCTYPES_SIZE)) { + u8 flow_id; + + for_each_set_bit(flow_id, flow_pctypes, FLOW_PCTYPES_SIZE) { + i_setc = (u64)i40e_read_rx_ctl(hw, I40E_GLQF_HASH_INSET(0, flow_id)) | + ((u64)i40e_read_rx_ctl(hw, I40E_GLQF_HASH_INSET(1, flow_id)) << 32); + i_set = i40e_get_rss_hash_bits(&pf->hw, nfc, i_setc); + + i40e_write_rx_ctl(hw, I40E_GLQF_HASH_INSET(0, flow_id), + (u32)i_set); + i40e_write_rx_ctl(hw, I40E_GLQF_HASH_INSET(1, flow_id), + (u32)(i_set >> 32)); + hena |= BIT_ULL(flow_id); + } } i40e_write_rx_ctl(hw, I40E_PFQF_HENA(0), (u32)hena); diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 2c07fa8ecfc8..b5dcd15ced36 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -3566,12 +3566,8 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring) if (ring->vsi->type == I40E_VSI_MAIN) xdp_rxq_info_unreg_mem_model(&ring->xdp_rxq); - kfree(ring->rx_bi); ring->xsk_pool = i40e_xsk_pool(ring); if (ring->xsk_pool) { - ret = i40e_alloc_rx_bi_zc(ring); - if (ret) - return ret; ring->rx_buf_len = xsk_pool_get_rx_frame_size(ring->xsk_pool); /* For AF_XDP ZC, we disallow packets to span on @@ -3589,9 +3585,6 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring) ring->queue_index); } else { - ret = i40e_alloc_rx_bi(ring); - if (ret) - return ret; ring->rx_buf_len = vsi->rx_buf_len; if (ring->vsi->type == I40E_VSI_MAIN) { ret = xdp_rxq_info_reg_mem_model(&ring->xdp_rxq, @@ -13296,6 +13289,14 @@ static int i40e_xdp_setup(struct i40e_vsi *vsi, struct bpf_prog *prog, i40e_reset_and_rebuild(pf, true, true); } + if (!i40e_enabled_xdp_vsi(vsi) && prog) { + if (i40e_realloc_rx_bi_zc(vsi, true)) + return -ENOMEM; + } else if (i40e_enabled_xdp_vsi(vsi) && !prog) { + if (i40e_realloc_rx_bi_zc(vsi, false)) + return -ENOMEM; + } + for (i = 0; i < vsi->num_queue_pairs; i++) WRITE_ONCE(vsi->rx_rings[i]->xdp_prog, vsi->xdp_prog); @@ -13528,6 +13529,7 @@ int i40e_queue_pair_disable(struct i40e_vsi *vsi, int queue_pair) i40e_queue_pair_disable_irq(vsi, queue_pair); err = i40e_queue_pair_toggle_rings(vsi, queue_pair, false /* off */); + i40e_clean_rx_ring(vsi->rx_rings[queue_pair]); i40e_queue_pair_toggle_napi(vsi, queue_pair, false /* off */); i40e_queue_pair_clean_rings(vsi, queue_pair); i40e_queue_pair_reset_stats(vsi, queue_pair); diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 69e67eb6aea7..b97c95f89fa0 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -1457,14 +1457,6 @@ err: return -ENOMEM; } -int i40e_alloc_rx_bi(struct i40e_ring *rx_ring) -{ - unsigned long sz = sizeof(*rx_ring->rx_bi) * rx_ring->count; - - rx_ring->rx_bi = kzalloc(sz, GFP_KERNEL); - return rx_ring->rx_bi ? 0 : -ENOMEM; -} - static void i40e_clear_rx_bi(struct i40e_ring *rx_ring) { memset(rx_ring->rx_bi, 0, sizeof(*rx_ring->rx_bi) * rx_ring->count); @@ -1593,6 +1585,11 @@ int i40e_setup_rx_descriptors(struct i40e_ring *rx_ring) rx_ring->xdp_prog = rx_ring->vsi->xdp_prog; + rx_ring->rx_bi = + kcalloc(rx_ring->count, sizeof(*rx_ring->rx_bi), GFP_KERNEL); + if (!rx_ring->rx_bi) + return -ENOMEM; + return 0; } diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethernet/intel/i40e/i40e_txrx.h index 41f86e9535a0..768290dc6f48 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.h +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.h @@ -469,7 +469,6 @@ int __i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size); bool __i40e_chk_linearize(struct sk_buff *skb); int i40e_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **frames, u32 flags); -int i40e_alloc_rx_bi(struct i40e_ring *rx_ring); /** * i40e_get_head - Retrieve head from head writeback diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index 7b3f30beb757..388c3d36d96a 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -1404,6 +1404,10 @@ struct i40e_lldp_variables { #define I40E_PFQF_CTL_0_HASHLUTSIZE_512 0x00010000 /* INPUT SET MASK for RSS, flow director, and flexible payload */ +#define I40E_X722_L3_SRC_SHIFT 49 +#define I40E_X722_L3_SRC_MASK (0x3ULL << I40E_X722_L3_SRC_SHIFT) +#define I40E_X722_L3_DST_SHIFT 41 +#define I40E_X722_L3_DST_MASK (0x3ULL << I40E_X722_L3_DST_SHIFT) #define I40E_L3_SRC_SHIFT 47 #define I40E_L3_SRC_MASK (0x3ULL << I40E_L3_SRC_SHIFT) #define I40E_L3_V6_SRC_SHIFT 43 diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 7e9f6a69eb10..72ddcefc45b1 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -1536,10 +1536,12 @@ bool i40e_reset_vf(struct i40e_vf *vf, bool flr) if (test_bit(__I40E_VF_RESETS_DISABLED, pf->state)) return true; - /* If the VFs have been disabled, this means something else is - * resetting the VF, so we shouldn't continue. - */ - if (test_and_set_bit(__I40E_VF_DISABLE, pf->state)) + /* Bail out if VFs are disabled. */ + if (test_bit(__I40E_VF_DISABLE, pf->state)) + return true; + + /* If VF is being reset already we don't need to continue. */ + if (test_and_set_bit(I40E_VF_STATE_RESETTING, &vf->vf_states)) return true; i40e_trigger_vf_reset(vf, flr); @@ -1576,7 +1578,7 @@ bool i40e_reset_vf(struct i40e_vf *vf, bool flr) i40e_cleanup_reset_vf(vf); i40e_flush(hw); - clear_bit(__I40E_VF_DISABLE, pf->state); + clear_bit(I40E_VF_STATE_RESETTING, &vf->vf_states); return true; } @@ -1609,8 +1611,12 @@ bool i40e_reset_all_vfs(struct i40e_pf *pf, bool flr) return false; /* Begin reset on all VFs at once */ - for (v = 0; v < pf->num_alloc_vfs; v++) - i40e_trigger_vf_reset(&pf->vf[v], flr); + for (v = 0; v < pf->num_alloc_vfs; v++) { + vf = &pf->vf[v]; + /* If VF is being reset no need to trigger reset again */ + if (!test_bit(I40E_VF_STATE_RESETTING, &vf->vf_states)) + i40e_trigger_vf_reset(&pf->vf[v], flr); + } /* HW requires some time to make sure it can flush the FIFO for a VF * when it resets it. Poll the VPGEN_VFRSTAT register for each VF in @@ -1626,9 +1632,11 @@ bool i40e_reset_all_vfs(struct i40e_pf *pf, bool flr) */ while (v < pf->num_alloc_vfs) { vf = &pf->vf[v]; - reg = rd32(hw, I40E_VPGEN_VFRSTAT(vf->vf_id)); - if (!(reg & I40E_VPGEN_VFRSTAT_VFRD_MASK)) - break; + if (!test_bit(I40E_VF_STATE_RESETTING, &vf->vf_states)) { + reg = rd32(hw, I40E_VPGEN_VFRSTAT(vf->vf_id)); + if (!(reg & I40E_VPGEN_VFRSTAT_VFRD_MASK)) + break; + } /* If the current VF has finished resetting, move on * to the next VF in sequence. @@ -1656,6 +1664,10 @@ bool i40e_reset_all_vfs(struct i40e_pf *pf, bool flr) if (pf->vf[v].lan_vsi_idx == 0) continue; + /* If VF is reset in another thread just continue */ + if (test_bit(I40E_VF_STATE_RESETTING, &vf->vf_states)) + continue; + i40e_vsi_stop_rings_no_wait(pf->vsi[pf->vf[v].lan_vsi_idx]); } @@ -1667,6 +1679,10 @@ bool i40e_reset_all_vfs(struct i40e_pf *pf, bool flr) if (pf->vf[v].lan_vsi_idx == 0) continue; + /* If VF is reset in another thread just continue */ + if (test_bit(I40E_VF_STATE_RESETTING, &vf->vf_states)) + continue; + i40e_vsi_wait_queues_disabled(pf->vsi[pf->vf[v].lan_vsi_idx]); } @@ -1676,8 +1692,13 @@ bool i40e_reset_all_vfs(struct i40e_pf *pf, bool flr) mdelay(50); /* Finish the reset on each VF */ - for (v = 0; v < pf->num_alloc_vfs; v++) + for (v = 0; v < pf->num_alloc_vfs; v++) { + /* If VF is reset in another thread just continue */ + if (test_bit(I40E_VF_STATE_RESETTING, &vf->vf_states)) + continue; + i40e_cleanup_reset_vf(&pf->vf[v]); + } i40e_flush(hw); clear_bit(__I40E_VF_DISABLE, pf->state); diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h index a554d0a0b09b..358bbdb58795 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h @@ -39,6 +39,7 @@ enum i40e_vf_states { I40E_VF_STATE_MC_PROMISC, I40E_VF_STATE_UC_PROMISC, I40E_VF_STATE_PRE_ENABLE, + I40E_VF_STATE_RESETTING }; /* VF capabilities */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_xsk.c b/drivers/net/ethernet/intel/i40e/i40e_xsk.c index 6d4009e0cbd6..cd7b52fb6b46 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_xsk.c +++ b/drivers/net/ethernet/intel/i40e/i40e_xsk.c @@ -10,14 +10,6 @@ #include "i40e_txrx_common.h" #include "i40e_xsk.h" -int i40e_alloc_rx_bi_zc(struct i40e_ring *rx_ring) -{ - unsigned long sz = sizeof(*rx_ring->rx_bi_zc) * rx_ring->count; - - rx_ring->rx_bi_zc = kzalloc(sz, GFP_KERNEL); - return rx_ring->rx_bi_zc ? 0 : -ENOMEM; -} - void i40e_clear_rx_bi_zc(struct i40e_ring *rx_ring) { memset(rx_ring->rx_bi_zc, 0, @@ -30,6 +22,58 @@ static struct xdp_buff **i40e_rx_bi(struct i40e_ring *rx_ring, u32 idx) } /** + * i40e_realloc_rx_xdp_bi - reallocate SW ring for either XSK or normal buffer + * @rx_ring: Current rx ring + * @pool_present: is pool for XSK present + * + * Try allocating memory and return ENOMEM, if failed to allocate. + * If allocation was successful, substitute buffer with allocated one. + * Returns 0 on success, negative on failure + */ +static int i40e_realloc_rx_xdp_bi(struct i40e_ring *rx_ring, bool pool_present) +{ + size_t elem_size = pool_present ? sizeof(*rx_ring->rx_bi_zc) : + sizeof(*rx_ring->rx_bi); + void *sw_ring = kcalloc(rx_ring->count, elem_size, GFP_KERNEL); + + if (!sw_ring) + return -ENOMEM; + + if (pool_present) { + kfree(rx_ring->rx_bi); + rx_ring->rx_bi = NULL; + rx_ring->rx_bi_zc = sw_ring; + } else { + kfree(rx_ring->rx_bi_zc); + rx_ring->rx_bi_zc = NULL; + rx_ring->rx_bi = sw_ring; + } + return 0; +} + +/** + * i40e_realloc_rx_bi_zc - reallocate rx SW rings + * @vsi: Current VSI + * @zc: is zero copy set + * + * Reallocate buffer for rx_rings that might be used by XSK. + * XDP requires more memory, than rx_buf provides. + * Returns 0 on success, negative on failure + */ +int i40e_realloc_rx_bi_zc(struct i40e_vsi *vsi, bool zc) +{ + struct i40e_ring *rx_ring; + unsigned long q; + + for_each_set_bit(q, vsi->af_xdp_zc_qps, vsi->alloc_queue_pairs) { + rx_ring = vsi->rx_rings[q]; + if (i40e_realloc_rx_xdp_bi(rx_ring, zc)) + return -ENOMEM; + } + return 0; +} + +/** * i40e_xsk_pool_enable - Enable/associate an AF_XDP buffer pool to a * certain ring/qid * @vsi: Current VSI @@ -69,6 +113,10 @@ static int i40e_xsk_pool_enable(struct i40e_vsi *vsi, if (err) return err; + err = i40e_realloc_rx_xdp_bi(vsi->rx_rings[qid], true); + if (err) + return err; + err = i40e_queue_pair_enable(vsi, qid); if (err) return err; @@ -113,6 +161,9 @@ static int i40e_xsk_pool_disable(struct i40e_vsi *vsi, u16 qid) xsk_pool_dma_unmap(pool, I40E_RX_DMA_ATTR); if (if_running) { + err = i40e_realloc_rx_xdp_bi(vsi->rx_rings[qid], false); + if (err) + return err; err = i40e_queue_pair_enable(vsi, qid); if (err) return err; diff --git a/drivers/net/ethernet/intel/i40e/i40e_xsk.h b/drivers/net/ethernet/intel/i40e/i40e_xsk.h index bb962987f300..821df248f8be 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_xsk.h +++ b/drivers/net/ethernet/intel/i40e/i40e_xsk.h @@ -32,7 +32,7 @@ int i40e_clean_rx_irq_zc(struct i40e_ring *rx_ring, int budget); bool i40e_clean_xdp_tx_irq(struct i40e_vsi *vsi, struct i40e_ring *tx_ring); int i40e_xsk_wakeup(struct net_device *dev, u32 queue_id, u32 flags); -int i40e_alloc_rx_bi_zc(struct i40e_ring *rx_ring); +int i40e_realloc_rx_bi_zc(struct i40e_vsi *vsi, bool zc); void i40e_clear_rx_bi_zc(struct i40e_ring *rx_ring); #endif /* _I40E_XSK_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index 001500afc4a6..f88ee051e71c 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -137,6 +137,21 @@ */ #define ICE_BW_KBPS_DIVISOR 125 +/* Default recipes have priority 4 and below, hence priority values between 5..7 + * can be used as filter priority for advanced switch filter (advanced switch + * filters need new recipe to be created for specified extraction sequence + * because default recipe extraction sequence does not represent custom + * extraction) + */ +#define ICE_SWITCH_FLTR_PRIO_QUEUE 7 +/* prio 6 is reserved for future use (e.g. switch filter with L3 fields + + * (Optional: IP TOS/TTL) + L4 fields + (optionally: TCP fields such as + * SYN/FIN/RST)) + */ +#define ICE_SWITCH_FLTR_PRIO_RSVD 6 +#define ICE_SWITCH_FLTR_PRIO_VSI 5 +#define ICE_SWITCH_FLTR_PRIO_QGRP ICE_SWITCH_FLTR_PRIO_VSI + /* Macro for each VSI in a PF */ #define ice_for_each_vsi(pf, i) \ for ((i) = 0; (i) < (pf)->num_alloc_vsi; (i)++) @@ -594,6 +609,8 @@ struct ice_pf { u16 num_dmac_chnl_fltrs; struct hlist_head tc_flower_fltr_list; + u64 supported_rxdids; + __le64 nvm_phy_type_lo; /* NVM PHY type low */ __le64 nvm_phy_type_hi; /* NVM PHY type high */ struct ice_link_default_override_tlv link_dflt_override; diff --git a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h index d16738a3d3a7..a92dc9a16035 100644 --- a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h +++ b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h @@ -110,6 +110,9 @@ #define PRTDCB_TUP2TC 0x001D26C0 #define GL_PREEXT_L2_PMASK0(_i) (0x0020F0FC + ((_i) * 4)) #define GL_PREEXT_L2_PMASK1(_i) (0x0020F108 + ((_i) * 4)) +#define GLFLXP_RXDID_FLAGS(_i, _j) (0x0045D000 + ((_i) * 4 + (_j) * 256)) +#define GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_S 0 +#define GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_M ICE_M(0x3F, 0) #define GLFLXP_RXDID_FLX_WRD_0(_i) (0x0045c800 + ((_i) * 4)) #define GLFLXP_RXDID_FLX_WRD_0_PROT_MDID_S 0 #define GLFLXP_RXDID_FLX_WRD_0_PROT_MDID_M ICE_M(0xFF, 0) diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 0f6718719453..df65e829ea33 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -8283,7 +8283,7 @@ static void ice_rem_all_chnl_fltrs(struct ice_pf *pf) rule.rid = fltr->rid; rule.rule_id = fltr->rule_id; - rule.vsi_handle = fltr->dest_id; + rule.vsi_handle = fltr->dest_vsi_handle; status = ice_rem_adv_rule_by_id(&pf->hw, &rule); if (status) { if (status == -ENOENT) diff --git a/drivers/net/ethernet/intel/ice/ice_tc_lib.c b/drivers/net/ethernet/intel/ice/ice_tc_lib.c index f68c555be4e9..faba0f857cd9 100644 --- a/drivers/net/ethernet/intel/ice/ice_tc_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_tc_lib.c @@ -724,7 +724,7 @@ ice_eswitch_add_tc_fltr(struct ice_vsi *vsi, struct ice_tc_flower_fltr *fltr) */ fltr->rid = rule_added.rid; fltr->rule_id = rule_added.rule_id; - fltr->dest_id = rule_added.vsi_handle; + fltr->dest_vsi_handle = rule_added.vsi_handle; exit: kfree(list); @@ -732,6 +732,116 @@ exit: } /** + * ice_locate_vsi_using_queue - locate VSI using queue (forward to queue action) + * @vsi: Pointer to VSI + * @tc_fltr: Pointer to tc_flower_filter + * + * Locate the VSI using specified queue. When ADQ is not enabled, always + * return input VSI, otherwise locate corresponding VSI based on per channel + * offset and qcount + */ +static struct ice_vsi * +ice_locate_vsi_using_queue(struct ice_vsi *vsi, + struct ice_tc_flower_fltr *tc_fltr) +{ + int num_tc, tc, queue; + + /* if ADQ is not active, passed VSI is the candidate VSI */ + if (!ice_is_adq_active(vsi->back)) + return vsi; + + /* Locate the VSI (it could still be main PF VSI or CHNL_VSI depending + * upon queue number) + */ + num_tc = vsi->mqprio_qopt.qopt.num_tc; + queue = tc_fltr->action.fwd.q.queue; + + for (tc = 0; tc < num_tc; tc++) { + int qcount = vsi->mqprio_qopt.qopt.count[tc]; + int offset = vsi->mqprio_qopt.qopt.offset[tc]; + + if (queue >= offset && queue < offset + qcount) { + /* for non-ADQ TCs, passed VSI is the candidate VSI */ + if (tc < ICE_CHNL_START_TC) + return vsi; + else + return vsi->tc_map_vsi[tc]; + } + } + return NULL; +} + +static struct ice_rx_ring * +ice_locate_rx_ring_using_queue(struct ice_vsi *vsi, + struct ice_tc_flower_fltr *tc_fltr) +{ + u16 queue = tc_fltr->action.fwd.q.queue; + + return queue < vsi->num_rxq ? vsi->rx_rings[queue] : NULL; +} + +/** + * ice_tc_forward_action - Determine destination VSI and queue for the action + * @vsi: Pointer to VSI + * @tc_fltr: Pointer to TC flower filter structure + * + * Validates the tc forward action and determines the destination VSI and queue + * for the forward action. + */ +static struct ice_vsi * +ice_tc_forward_action(struct ice_vsi *vsi, struct ice_tc_flower_fltr *tc_fltr) +{ + struct ice_rx_ring *ring = NULL; + struct ice_vsi *ch_vsi = NULL; + struct ice_pf *pf = vsi->back; + struct device *dev; + u32 tc_class; + + dev = ice_pf_to_dev(pf); + + /* Get the destination VSI and/or destination queue and validate them */ + switch (tc_fltr->action.fltr_act) { + case ICE_FWD_TO_VSI: + tc_class = tc_fltr->action.fwd.tc.tc_class; + /* Select the destination VSI */ + if (tc_class < ICE_CHNL_START_TC) { + NL_SET_ERR_MSG_MOD(tc_fltr->extack, + "Unable to add filter because of unsupported destination"); + return ERR_PTR(-EOPNOTSUPP); + } + /* Locate ADQ VSI depending on hw_tc number */ + ch_vsi = vsi->tc_map_vsi[tc_class]; + break; + case ICE_FWD_TO_Q: + /* Locate the Rx queue */ + ring = ice_locate_rx_ring_using_queue(vsi, tc_fltr); + if (!ring) { + dev_err(dev, + "Unable to locate Rx queue for action fwd_to_queue: %u\n", + tc_fltr->action.fwd.q.queue); + return ERR_PTR(-EINVAL); + } + /* Determine destination VSI even though the action is + * FWD_TO_QUEUE, because QUEUE is associated with VSI + */ + ch_vsi = tc_fltr->dest_vsi; + break; + default: + dev_err(dev, + "Unable to add filter because of unsupported action %u (supported actions: fwd to tc, fwd to queue)\n", + tc_fltr->action.fltr_act); + return ERR_PTR(-EINVAL); + } + /* Must have valid ch_vsi (it could be main VSI or ADQ VSI) */ + if (!ch_vsi) { + dev_err(dev, + "Unable to add filter because specified destination VSI doesn't exist\n"); + return ERR_PTR(-EINVAL); + } + return ch_vsi; +} + +/** * ice_add_tc_flower_adv_fltr - add appropriate filter rules * @vsi: Pointer to VSI * @tc_fltr: Pointer to TC flower filter structure @@ -772,11 +882,10 @@ ice_add_tc_flower_adv_fltr(struct ice_vsi *vsi, return -EOPNOTSUPP; } - /* get the channel (aka ADQ VSI) */ - if (tc_fltr->dest_vsi) - ch_vsi = tc_fltr->dest_vsi; - else - ch_vsi = vsi->tc_map_vsi[tc_fltr->action.tc_class]; + /* validate forwarding action VSI and queue */ + ch_vsi = ice_tc_forward_action(vsi, tc_fltr); + if (IS_ERR(ch_vsi)) + return PTR_ERR(ch_vsi); lkups_cnt = ice_tc_count_lkups(flags, headers, tc_fltr); list = kcalloc(lkups_cnt, sizeof(*list), GFP_ATOMIC); @@ -790,30 +899,40 @@ ice_add_tc_flower_adv_fltr(struct ice_vsi *vsi, } rule_info.sw_act.fltr_act = tc_fltr->action.fltr_act; - if (tc_fltr->action.tc_class >= ICE_CHNL_START_TC) { - if (!ch_vsi) { - NL_SET_ERR_MSG_MOD(tc_fltr->extack, "Unable to add filter because specified destination doesn't exist"); - ret = -EINVAL; - goto exit; - } + /* specify the cookie as filter_rule_id */ + rule_info.fltr_rule_id = tc_fltr->cookie; - rule_info.sw_act.fltr_act = ICE_FWD_TO_VSI; + switch (tc_fltr->action.fltr_act) { + case ICE_FWD_TO_VSI: rule_info.sw_act.vsi_handle = ch_vsi->idx; - rule_info.priority = 7; + rule_info.priority = ICE_SWITCH_FLTR_PRIO_VSI; rule_info.sw_act.src = hw->pf_id; rule_info.rx = true; dev_dbg(dev, "add switch rule for TC:%u vsi_idx:%u, lkups_cnt:%u\n", - tc_fltr->action.tc_class, + tc_fltr->action.fwd.tc.tc_class, rule_info.sw_act.vsi_handle, lkups_cnt); - } else { + break; + case ICE_FWD_TO_Q: + /* HW queue number in global space */ + rule_info.sw_act.fwd_id.q_id = tc_fltr->action.fwd.q.hw_queue; + rule_info.sw_act.vsi_handle = ch_vsi->idx; + rule_info.priority = ICE_SWITCH_FLTR_PRIO_QUEUE; + rule_info.sw_act.src = hw->pf_id; + rule_info.rx = true; + dev_dbg(dev, "add switch rule action to forward to queue:%u (HW queue %u), lkups_cnt:%u\n", + tc_fltr->action.fwd.q.queue, + tc_fltr->action.fwd.q.hw_queue, lkups_cnt); + break; + default: rule_info.sw_act.flag |= ICE_FLTR_TX; + /* In case of Tx (LOOKUP_TX), src needs to be src VSI */ rule_info.sw_act.src = vsi->idx; + /* 'Rx' is false, direction of rule(LOOKUPTRX) */ rule_info.rx = false; + rule_info.priority = ICE_SWITCH_FLTR_PRIO_VSI; + break; } - /* specify the cookie as filter_rule_id */ - rule_info.fltr_rule_id = tc_fltr->cookie; - ret = ice_add_adv_rule(hw, list, lkups_cnt, &rule_info, &rule_added); if (ret == -EEXIST) { NL_SET_ERR_MSG_MOD(tc_fltr->extack, @@ -831,19 +950,14 @@ ice_add_tc_flower_adv_fltr(struct ice_vsi *vsi, */ tc_fltr->rid = rule_added.rid; tc_fltr->rule_id = rule_added.rule_id; - if (tc_fltr->action.tc_class > 0 && ch_vsi) { - /* For PF ADQ, VSI type is set as ICE_VSI_CHNL, and - * for PF ADQ filter, it is not yet set in tc_fltr, - * hence store the dest_vsi ptr in tc_fltr - */ - if (ch_vsi->type == ICE_VSI_CHNL) - tc_fltr->dest_vsi = ch_vsi; + tc_fltr->dest_vsi_handle = rule_added.vsi_handle; + if (tc_fltr->action.fltr_act == ICE_FWD_TO_VSI || + tc_fltr->action.fltr_act == ICE_FWD_TO_Q) { + tc_fltr->dest_vsi = ch_vsi; /* keep track of advanced switch filter for - * destination VSI (channel VSI) + * destination VSI */ ch_vsi->num_chnl_fltr++; - /* in this case, dest_id is VSI handle (sw handle) */ - tc_fltr->dest_id = rule_added.vsi_handle; /* keeps track of channel filters for PF VSI */ if (vsi->type == ICE_VSI_PF && @@ -851,10 +965,22 @@ ice_add_tc_flower_adv_fltr(struct ice_vsi *vsi, ICE_TC_FLWR_FIELD_ENC_DST_MAC))) pf->num_dmac_chnl_fltrs++; } - dev_dbg(dev, "added switch rule (lkups_cnt %u, flags 0x%x) for TC %u, rid %u, rule_id %u, vsi_idx %u\n", - lkups_cnt, flags, - tc_fltr->action.tc_class, rule_added.rid, - rule_added.rule_id, rule_added.vsi_handle); + switch (tc_fltr->action.fltr_act) { + case ICE_FWD_TO_VSI: + dev_dbg(dev, "added switch rule (lkups_cnt %u, flags 0x%x), action is forward to TC %u, rid %u, rule_id %u, vsi_idx %u\n", + lkups_cnt, flags, + tc_fltr->action.fwd.tc.tc_class, rule_added.rid, + rule_added.rule_id, rule_added.vsi_handle); + break; + case ICE_FWD_TO_Q: + dev_dbg(dev, "added switch rule (lkups_cnt %u, flags 0x%x), action is forward to queue: %u (HW queue %u) , rid %u, rule_id %u\n", + lkups_cnt, flags, tc_fltr->action.fwd.q.queue, + tc_fltr->action.fwd.q.hw_queue, rule_added.rid, + rule_added.rule_id); + break; + default: + break; + } exit: kfree(list); return ret; @@ -1455,43 +1581,15 @@ ice_add_switch_fltr(struct ice_vsi *vsi, struct ice_tc_flower_fltr *fltr) } /** - * ice_handle_tclass_action - Support directing to a traffic class + * ice_prep_adq_filter - Prepare ADQ filter with the required additional headers * @vsi: Pointer to VSI - * @cls_flower: Pointer to TC flower offload structure * @fltr: Pointer to TC flower filter structure * - * Support directing traffic to a traffic class + * Prepare ADQ filter with the required additional header fields */ static int -ice_handle_tclass_action(struct ice_vsi *vsi, - struct flow_cls_offload *cls_flower, - struct ice_tc_flower_fltr *fltr) +ice_prep_adq_filter(struct ice_vsi *vsi, struct ice_tc_flower_fltr *fltr) { - int tc = tc_classid_to_hwtc(vsi->netdev, cls_flower->classid); - struct ice_vsi *main_vsi; - - if (tc < 0) { - NL_SET_ERR_MSG_MOD(fltr->extack, "Unable to add filter because specified destination is invalid"); - return -EINVAL; - } - if (!tc) { - NL_SET_ERR_MSG_MOD(fltr->extack, "Unable to add filter because of invalid destination"); - return -EINVAL; - } - - if (!(vsi->all_enatc & BIT(tc))) { - NL_SET_ERR_MSG_MOD(fltr->extack, "Unable to add filter because of non-existence destination"); - return -EINVAL; - } - - /* Redirect to a TC class or Queue Group */ - main_vsi = ice_get_main_vsi(vsi->back); - if (!main_vsi || !main_vsi->netdev) { - NL_SET_ERR_MSG_MOD(fltr->extack, - "Unable to add filter because of invalid netdevice"); - return -EINVAL; - } - if ((fltr->flags & ICE_TC_FLWR_FIELD_TENANT_ID) && (fltr->flags & (ICE_TC_FLWR_FIELD_DST_MAC | ICE_TC_FLWR_FIELD_SRC_MAC))) { @@ -1503,9 +1601,8 @@ ice_handle_tclass_action(struct ice_vsi *vsi, /* For ADQ, filter must include dest MAC address, otherwise unwanted * packets with unrelated MAC address get delivered to ADQ VSIs as long * as remaining filter criteria is satisfied such as dest IP address - * and dest/src L4 port. Following code is trying to handle: - * 1. For non-tunnel, if user specify MAC addresses, use them (means - * this code won't do anything + * and dest/src L4 port. Below code handles the following cases: + * 1. For non-tunnel, if user specify MAC addresses, use them. * 2. For non-tunnel, if user didn't specify MAC address, add implicit * dest MAC to be lower netdev's active unicast MAC address * 3. For tunnel, as of now TC-filter through flower classifier doesn't @@ -1528,35 +1625,97 @@ ice_handle_tclass_action(struct ice_vsi *vsi, eth_broadcast_addr(fltr->outer_headers.l2_mask.dst_mac); } - /* validate specified dest MAC address, make sure either it belongs to - * lower netdev or any of MACVLAN. MACVLANs MAC address are added as - * unicast MAC filter destined to main VSI. - */ - if (!ice_mac_fltr_exist(&main_vsi->back->hw, - fltr->outer_headers.l2_key.dst_mac, - main_vsi->idx)) { - NL_SET_ERR_MSG_MOD(fltr->extack, - "Unable to add filter because legacy MAC filter for specified destination doesn't exist"); - return -EINVAL; - } - /* Make sure VLAN is already added to main VSI, before allowing ADQ to * add a VLAN based filter such as MAC + VLAN + L4 port. */ if (fltr->flags & ICE_TC_FLWR_FIELD_VLAN) { u16 vlan_id = be16_to_cpu(fltr->outer_headers.vlan_hdr.vlan_id); - if (!ice_vlan_fltr_exist(&main_vsi->back->hw, vlan_id, - main_vsi->idx)) { + if (!ice_vlan_fltr_exist(&vsi->back->hw, vlan_id, vsi->idx)) { NL_SET_ERR_MSG_MOD(fltr->extack, "Unable to add filter because legacy VLAN filter for specified destination doesn't exist"); return -EINVAL; } } + return 0; +} + +/** + * ice_handle_tclass_action - Support directing to a traffic class + * @vsi: Pointer to VSI + * @cls_flower: Pointer to TC flower offload structure + * @fltr: Pointer to TC flower filter structure + * + * Support directing traffic to a traffic class/queue-set + */ +static int +ice_handle_tclass_action(struct ice_vsi *vsi, + struct flow_cls_offload *cls_flower, + struct ice_tc_flower_fltr *fltr) +{ + int tc = tc_classid_to_hwtc(vsi->netdev, cls_flower->classid); + + /* user specified hw_tc (must be non-zero for ADQ TC), action is forward + * to hw_tc (i.e. ADQ channel number) + */ + if (tc < ICE_CHNL_START_TC) { + NL_SET_ERR_MSG_MOD(fltr->extack, + "Unable to add filter because of unsupported destination"); + return -EOPNOTSUPP; + } + if (!(vsi->all_enatc & BIT(tc))) { + NL_SET_ERR_MSG_MOD(fltr->extack, + "Unable to add filter because of non-existence destination"); + return -EINVAL; + } fltr->action.fltr_act = ICE_FWD_TO_VSI; - fltr->action.tc_class = tc; + fltr->action.fwd.tc.tc_class = tc; - return 0; + return ice_prep_adq_filter(vsi, fltr); +} + +static int +ice_tc_forward_to_queue(struct ice_vsi *vsi, struct ice_tc_flower_fltr *fltr, + struct flow_action_entry *act) +{ + struct ice_vsi *ch_vsi = NULL; + u16 queue = act->rx_queue; + + if (queue > vsi->num_rxq) { + NL_SET_ERR_MSG_MOD(fltr->extack, + "Unable to add filter because specified queue is invalid"); + return -EINVAL; + } + fltr->action.fltr_act = ICE_FWD_TO_Q; + fltr->action.fwd.q.queue = queue; + /* determine corresponding HW queue */ + fltr->action.fwd.q.hw_queue = vsi->rxq_map[queue]; + + /* If ADQ is configured, and the queue belongs to ADQ VSI, then prepare + * ADQ switch filter + */ + ch_vsi = ice_locate_vsi_using_queue(vsi, fltr); + if (!ch_vsi) + return -EINVAL; + fltr->dest_vsi = ch_vsi; + if (!ice_is_chnl_fltr(fltr)) + return 0; + + return ice_prep_adq_filter(vsi, fltr); +} + +static int +ice_tc_parse_action(struct ice_vsi *vsi, struct ice_tc_flower_fltr *fltr, + struct flow_action_entry *act) +{ + switch (act->id) { + case FLOW_ACTION_RX_QUEUE_MAPPING: + /* forward to queue */ + return ice_tc_forward_to_queue(vsi, fltr, act); + default: + NL_SET_ERR_MSG_MOD(fltr->extack, "Unsupported TC action"); + return -EOPNOTSUPP; + } } /** @@ -1575,7 +1734,7 @@ ice_parse_tc_flower_actions(struct ice_vsi *vsi, struct flow_rule *rule = flow_cls_offload_flow_rule(cls_flower); struct flow_action *flow_action = &rule->action; struct flow_action_entry *act; - int i; + int i, err; if (cls_flower->classid) return ice_handle_tclass_action(vsi, cls_flower, fltr); @@ -1584,21 +1743,13 @@ ice_parse_tc_flower_actions(struct ice_vsi *vsi, return -EINVAL; flow_action_for_each(i, act, flow_action) { - if (ice_is_eswitch_mode_switchdev(vsi->back)) { - int err = ice_eswitch_tc_parse_action(fltr, act); - - if (err) - return err; - continue; - } - /* Allow only one rule per filter */ - - /* Drop action */ - if (act->id == FLOW_ACTION_DROP) { - NL_SET_ERR_MSG_MOD(fltr->extack, "Unsupported action DROP"); - return -EINVAL; - } - fltr->action.fltr_act = ICE_FWD_TO_VSI; + if (ice_is_eswitch_mode_switchdev(vsi->back)) + err = ice_eswitch_tc_parse_action(fltr, act); + else + err = ice_tc_parse_action(vsi, fltr, act); + if (err) + return err; + continue; } return 0; } @@ -1618,7 +1769,7 @@ static int ice_del_tc_fltr(struct ice_vsi *vsi, struct ice_tc_flower_fltr *fltr) rule_rem.rid = fltr->rid; rule_rem.rule_id = fltr->rule_id; - rule_rem.vsi_handle = fltr->dest_id; + rule_rem.vsi_handle = fltr->dest_vsi_handle; err = ice_rem_adv_rule_by_id(&pf->hw, &rule_rem); if (err) { if (err == -ENOENT) { diff --git a/drivers/net/ethernet/intel/ice/ice_tc_lib.h b/drivers/net/ethernet/intel/ice/ice_tc_lib.h index 92642faad595..d916d1e92aa3 100644 --- a/drivers/net/ethernet/intel/ice/ice_tc_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_tc_lib.h @@ -45,7 +45,20 @@ struct ice_indr_block_priv { }; struct ice_tc_flower_action { - u32 tc_class; + /* forward action specific params */ + union { + struct { + u32 tc_class; /* forward to hw_tc */ + u32 rsvd; + } tc; + struct { + u16 queue; /* forward to queue */ + /* To add filter in HW, absolute queue number in global + * space of queues (between 0...N) is needed + */ + u16 hw_queue; + } q; + } fwd; enum ice_sw_fwd_act_type fltr_act; }; @@ -131,11 +144,11 @@ struct ice_tc_flower_fltr { */ u16 rid; u16 rule_id; - /* this could be queue/vsi_idx (sw handle)/queue_group, depending upon - * destination type + /* VSI handle of the destination VSI (it could be main PF VSI, CHNL_VSI, + * VF VSI) */ - u16 dest_id; - /* if dest_id is vsi_idx, then need to store destination VSI ptr */ + u16 dest_vsi_handle; + /* ptr to destination VSI */ struct ice_vsi *dest_vsi; /* direction of fltr for eswitch use case */ enum ice_eswitch_fltr_direction direction; @@ -162,12 +175,23 @@ struct ice_tc_flower_fltr { * @f: Pointer to tc-flower filter * * Criteria to determine of given filter is valid channel filter - * or not is based on its "destination". If destination is hw_tc (aka tc_class) - * and it is non-zero, then it is valid channel (aka ADQ) filter + * or not is based on its destination. + * For forward to VSI action, if destination is valid hw_tc (aka tc_class) + * and in supported range of TCs for ADQ, then return true. + * For forward to queue, as long as dest_vsi is valid and it is of type + * VSI_CHNL (PF ADQ VSI is of type VSI_CHNL), return true. + * NOTE: For forward to queue, correct dest_vsi is still set in tc_fltr based + * on destination queue specified. */ static inline bool ice_is_chnl_fltr(struct ice_tc_flower_fltr *f) { - return !!f->action.tc_class; + if (f->action.fltr_act == ICE_FWD_TO_VSI) + return f->action.fwd.tc.tc_class >= ICE_CHNL_START_TC && + f->action.fwd.tc.tc_class < ICE_CHNL_MAX_TC; + else if (f->action.fltr_act == ICE_FWD_TO_Q) + return f->dest_vsi && f->dest_vsi->type == ICE_VSI_CHNL; + + return false; } /** diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl.c b/drivers/net/ethernet/intel/ice/ice_virtchnl.c index 2b4c791b6cba..c1fa94381f4e 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl.c +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl.c @@ -462,6 +462,9 @@ static int ice_vc_get_vf_res_msg(struct ice_vf *vf, u8 *msg) vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RSS_REG; } + if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RX_FLEX_DESC) + vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RX_FLEX_DESC; + if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_FDIR_PF) vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_FDIR_PF; @@ -1618,6 +1621,9 @@ static int ice_vc_cfg_qs_msg(struct ice_vf *vf, u8 *msg) } for (i = 0; i < qci->num_queue_pairs; i++) { + struct ice_hw *hw; + u32 rxdid; + u16 pf_q; qpi = &qci->qpair[i]; if (qpi->txq.vsi_id != qci->vsi_id || qpi->rxq.vsi_id != qci->vsi_id || @@ -1686,6 +1692,25 @@ static int ice_vc_cfg_qs_msg(struct ice_vf *vf, u8 *msg) goto error_param; } } + + /* VF Rx queue RXDID configuration */ + pf_q = vsi->rxq_map[qpi->rxq.queue_id]; + rxdid = qpi->rxq.rxdid; + hw = &vsi->back->hw; + + /* If Rx flex desc is supported, select RXDID for Rx queues. + * Otherwise, use legacy 32byte descriptor format. + * Legacy 16byte descriptor is not supported. If this RXDID + * is selected, return error. + */ + if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RX_FLEX_DESC) { + if (!(BIT(rxdid) & pf->supported_rxdids)) + goto error_param; + } else { + rxdid = ICE_RXDID_LEGACY_1; + } + + ice_write_qrxflxp_cntxt(hw, pf_q, rxdid, 0x03, false); } /* send the response to the VF */ @@ -2457,6 +2482,62 @@ error_param: } /** + * ice_vc_query_rxdid - query RXDID supported by DDP package + * @vf: pointer to VF info + * + * Called from VF to query a bitmap of supported flexible + * descriptor RXDIDs of a DDP package. + */ +static int ice_vc_query_rxdid(struct ice_vf *vf) +{ + enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; + struct virtchnl_supported_rxdids *rxdid = NULL; + struct ice_hw *hw = &vf->pf->hw; + struct ice_pf *pf = vf->pf; + int len = 0; + int ret, i; + u32 regval; + + if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto err; + } + + if (!(vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RX_FLEX_DESC)) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto err; + } + + len = sizeof(struct virtchnl_supported_rxdids); + rxdid = kzalloc(len, GFP_KERNEL); + if (!rxdid) { + v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY; + len = 0; + goto err; + } + + /* Read flexiflag registers to determine whether the + * corresponding RXDID is configured and supported or not. + * Since Legacy 16byte descriptor format is not supported, + * start from Legacy 32byte descriptor. + */ + for (i = ICE_RXDID_LEGACY_1; i < ICE_FLEX_DESC_RXDID_MAX_NUM; i++) { + regval = rd32(hw, GLFLXP_RXDID_FLAGS(i, 0)); + if ((regval >> GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_S) + & GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_M) + rxdid->supported_rxdids |= BIT(i); + } + + pf->supported_rxdids = rxdid->supported_rxdids; + +err: + ret = ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_GET_SUPPORTED_RXDIDS, + v_ret, (u8 *)rxdid, len); + kfree(rxdid); + return ret; +} + +/** * ice_vf_init_vlan_stripping - enable/disable VLAN stripping on initialization * @vf: VF to enable/disable VLAN stripping for on initialization * @@ -3490,6 +3571,7 @@ static const struct ice_virtchnl_ops ice_virtchnl_dflt_ops = { .cfg_promiscuous_mode_msg = ice_vc_cfg_promiscuous_mode_msg, .add_vlan_msg = ice_vc_add_vlan_msg, .remove_vlan_msg = ice_vc_remove_vlan_msg, + .query_rxdid = ice_vc_query_rxdid, .ena_vlan_stripping = ice_vc_ena_vlan_stripping, .dis_vlan_stripping = ice_vc_dis_vlan_stripping, .handle_rss_cfg_msg = ice_vc_handle_rss_cfg, @@ -3624,6 +3706,7 @@ static const struct ice_virtchnl_ops ice_virtchnl_repr_ops = { .cfg_promiscuous_mode_msg = ice_vc_repr_cfg_promiscuous_mode, .add_vlan_msg = ice_vc_add_vlan_msg, .remove_vlan_msg = ice_vc_remove_vlan_msg, + .query_rxdid = ice_vc_query_rxdid, .ena_vlan_stripping = ice_vc_ena_vlan_stripping, .dis_vlan_stripping = ice_vc_dis_vlan_stripping, .handle_rss_cfg_msg = ice_vc_handle_rss_cfg, @@ -3764,6 +3847,9 @@ error_handler: case VIRTCHNL_OP_DEL_VLAN: err = ops->remove_vlan_msg(vf, msg); break; + case VIRTCHNL_OP_GET_SUPPORTED_RXDIDS: + err = ops->query_rxdid(vf); + break; case VIRTCHNL_OP_ENABLE_VLAN_STRIPPING: err = ops->ena_vlan_stripping(vf); break; diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl.h b/drivers/net/ethernet/intel/ice/ice_virtchnl.h index b5a3fd8adbb4..4867a92ebefb 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl.h +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl.h @@ -17,6 +17,7 @@ * broadcast, and 16 for additional unicast/multicast filters */ #define ICE_MAX_MACADDR_PER_VF 18 +#define ICE_FLEX_DESC_RXDID_MAX_NUM 64 struct ice_virtchnl_ops { int (*get_ver_msg)(struct ice_vf *vf, u8 *msg); @@ -35,6 +36,7 @@ struct ice_virtchnl_ops { int (*cfg_promiscuous_mode_msg)(struct ice_vf *vf, u8 *msg); int (*add_vlan_msg)(struct ice_vf *vf, u8 *msg); int (*remove_vlan_msg)(struct ice_vf *vf, u8 *msg); + int (*query_rxdid)(struct ice_vf *vf); int (*ena_vlan_stripping)(struct ice_vf *vf); int (*dis_vlan_stripping)(struct ice_vf *vf); int (*handle_rss_cfg_msg)(struct ice_vf *vf, u8 *msg, bool add); diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_allowlist.c b/drivers/net/ethernet/intel/ice/ice_virtchnl_allowlist.c index 5a82216e7d03..7d547fa616fa 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl_allowlist.c +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_allowlist.c @@ -70,6 +70,11 @@ static const u32 rss_pf_allowlist_opcodes[] = { VIRTCHNL_OP_GET_RSS_HENA_CAPS, VIRTCHNL_OP_SET_RSS_HENA, }; +/* VIRTCHNL_VF_OFFLOAD_RX_FLEX_DESC */ +static const u32 rx_flex_desc_allowlist_opcodes[] = { + VIRTCHNL_OP_GET_SUPPORTED_RXDIDS, +}; + /* VIRTCHNL_VF_OFFLOAD_ADV_RSS_PF */ static const u32 adv_rss_pf_allowlist_opcodes[] = { VIRTCHNL_OP_ADD_RSS_CFG, VIRTCHNL_OP_DEL_RSS_CFG, @@ -96,6 +101,7 @@ static const struct allowlist_opcode_info allowlist_opcodes[] = { ALLOW_ITEM(VIRTCHNL_VF_OFFLOAD_REQ_QUEUES, req_queues_allowlist_opcodes), ALLOW_ITEM(VIRTCHNL_VF_OFFLOAD_VLAN, vlan_allowlist_opcodes), ALLOW_ITEM(VIRTCHNL_VF_OFFLOAD_RSS_PF, rss_pf_allowlist_opcodes), + ALLOW_ITEM(VIRTCHNL_VF_OFFLOAD_RX_FLEX_DESC, rx_flex_desc_allowlist_opcodes), ALLOW_ITEM(VIRTCHNL_VF_OFFLOAD_ADV_RSS_PF, adv_rss_pf_allowlist_opcodes), ALLOW_ITEM(VIRTCHNL_VF_OFFLOAD_FDIR_PF, fdir_pf_allowlist_opcodes), ALLOW_ITEM(VIRTCHNL_VF_OFFLOAD_VLAN_V2, vlan_v2_allowlist_opcodes), diff --git a/drivers/net/ethernet/lantiq_etop.c b/drivers/net/ethernet/lantiq_etop.c index 59aab4086dcc..f5961bdcc480 100644 --- a/drivers/net/ethernet/lantiq_etop.c +++ b/drivers/net/ethernet/lantiq_etop.c @@ -485,7 +485,6 @@ ltq_etop_tx(struct sk_buff *skb, struct net_device *dev) len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) || ch->skb[ch->dma.desc]) { - dev_kfree_skb_any(skb); netdev_err(dev, "tx ring full\n"); netif_tx_stop_queue(txq); return NETDEV_TX_BUSY; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mcs.c b/drivers/net/ethernet/marvell/octeontx2/af/mcs.c index 5ba618aed6ad..4a343f853b28 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mcs.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/mcs.c @@ -1182,8 +1182,10 @@ static int mcs_register_interrupts(struct mcs *mcs) mcs_reg_write(mcs, MCSX_PAB_TX_SLAVE_PAB_INT_ENB, 0xff); mcs->tx_sa_active = alloc_mem(mcs, mcs->hw->sc_entries); - if (!mcs->tx_sa_active) + if (!mcs->tx_sa_active) { + ret = -ENOMEM; goto exit; + } return ret; exit: diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c index 64f3acd7f67b..9ec5f38d38a8 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c @@ -133,7 +133,7 @@ static int cn10k_mcs_alloc_rsrc(struct otx2_nic *pfvf, enum mcs_direction dir, default: ret = -EINVAL; goto fail; - }; + } mutex_unlock(&mbox->lock); @@ -284,7 +284,7 @@ static int cn10k_mcs_write_sc_cam(struct otx2_nic *pfvf, sc_req = otx2_mbox_alloc_msg_mcs_rx_sc_cam_write(mbox); if (!sc_req) { - return -ENOMEM; + ret = -ENOMEM; goto fail; } @@ -594,7 +594,7 @@ static int cn10k_mcs_ena_dis_flowid(struct otx2_nic *pfvf, u16 hw_flow_id, req = otx2_mbox_alloc_msg_mcs_flowid_ena_entry(mbox); if (!req) { - return -ENOMEM; + ret = -ENOMEM; goto fail; } @@ -815,6 +815,7 @@ free_flowid: cn10k_mcs_free_rsrc(pfvf, MCS_TX, MCS_RSRC_TYPE_FLOWID, txsc->hw_flow_id, false); fail: + kfree(txsc); return ERR_PTR(ret); } @@ -870,6 +871,7 @@ free_flowid: cn10k_mcs_free_rsrc(pfvf, MCS_RX, MCS_RSRC_TYPE_FLOWID, rxsc->hw_flow_id, false); fail: + kfree(rxsc); return ERR_PTR(ret); } @@ -1653,6 +1655,7 @@ int cn10k_mcs_init(struct otx2_nic *pfvf) return 0; fail: dev_err(pfvf->dev, "Cannot notify PN wrapped event\n"); + mutex_unlock(&mbox->lock); return 0; } diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c index 5803d7f9137c..892ca88e0cf4 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c @@ -2810,7 +2810,7 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id) err = register_netdev(netdev); if (err) { dev_err(dev, "Failed to register netdevice\n"); - goto err_del_mcam_entries; + goto err_mcs_free; } err = otx2_wq_init(pf); @@ -2849,6 +2849,8 @@ err_mcam_flow_del: otx2_mcam_flow_del(pf); err_unreg_netdev: unregister_netdev(netdev); +err_mcs_free: + cn10k_mcs_free(pf); err_del_mcam_entries: otx2_mcam_flow_del(pf); err_ptp_destroy: diff --git a/drivers/net/ethernet/marvell/prestera/prestera_matchall.c b/drivers/net/ethernet/marvell/prestera/prestera_matchall.c index 6f2b95a5263e..1da9c1bc1ee9 100644 --- a/drivers/net/ethernet/marvell/prestera/prestera_matchall.c +++ b/drivers/net/ethernet/marvell/prestera/prestera_matchall.c @@ -96,6 +96,8 @@ int prestera_mall_replace(struct prestera_flow_block *block, list_for_each_entry(binding, &block->binding_list, list) { err = prestera_span_rule_add(binding, port, block->ingress); + if (err == -EEXIST) + return err; if (err) goto rollback; } diff --git a/drivers/net/ethernet/marvell/prestera/prestera_router_hw.c b/drivers/net/ethernet/marvell/prestera/prestera_router_hw.c index 4f65df0ae5e8..aa080dc57ff0 100644 --- a/drivers/net/ethernet/marvell/prestera/prestera_router_hw.c +++ b/drivers/net/ethernet/marvell/prestera/prestera_router_hw.c @@ -498,8 +498,8 @@ prestera_nexthop_group_get(struct prestera_switch *sw, refcount_inc(&nh_grp->refcount); } else { nh_grp = __prestera_nexthop_group_create(sw, key); - if (IS_ERR(nh_grp)) - return ERR_CAST(nh_grp); + if (!nh_grp) + return ERR_PTR(-ENOMEM); refcount_set(&nh_grp->refcount, 1); } @@ -651,7 +651,7 @@ prestera_fib_node_create(struct prestera_switch *sw, case PRESTERA_FIB_TYPE_UC_NH: fib_node->info.nh_grp = prestera_nexthop_group_get(sw, nh_grp_key); - if (!fib_node->info.nh_grp) + if (IS_ERR(fib_node->info.nh_grp)) goto err_nh_grp_get; grp_id = fib_node->info.nh_grp->grp_id; diff --git a/drivers/net/ethernet/marvell/prestera/prestera_span.c b/drivers/net/ethernet/marvell/prestera/prestera_span.c index f0e9d6ea88c5..1005182ce3bc 100644 --- a/drivers/net/ethernet/marvell/prestera/prestera_span.c +++ b/drivers/net/ethernet/marvell/prestera/prestera_span.c @@ -107,7 +107,7 @@ static int prestera_span_put(struct prestera_switch *sw, u8 span_id) entry = prestera_span_entry_find_by_id(sw->span, span_id); if (!entry) - return false; + return -ENOENT; if (!refcount_dec_and_test(&entry->ref_count)) return 0; @@ -151,6 +151,9 @@ int prestera_span_rule_del(struct prestera_flow_block_binding *binding, { int err; + if (binding->span_id == PRESTERA_SPAN_INVALID_ID) + return -ENOENT; + err = prestera_hw_span_unbind(binding->port, ingress); if (err) return err; diff --git a/drivers/net/ethernet/mediatek/Makefile b/drivers/net/ethernet/mediatek/Makefile index fe66ba8793cf..45ba0970504a 100644 --- a/drivers/net/ethernet/mediatek/Makefile +++ b/drivers/net/ethernet/mediatek/Makefile @@ -11,8 +11,3 @@ mtk_eth-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed_debugfs.o endif obj-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed_ops.o obj-$(CONFIG_NET_MEDIATEK_STAR_EMAC) += mtk_star_emac.o - -# FIXME: temporarily silence -Warray-bounds on non W=1+ builds -ifndef KBUILD_EXTRA_WARN -CFLAGS_mtk_ppe.o += -Wno-array-bounds -endif diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index 4fba7cb0144b..7cd381530aa4 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -4060,19 +4060,23 @@ static int mtk_probe(struct platform_device *pdev) eth->irq[i] = platform_get_irq(pdev, i); if (eth->irq[i] < 0) { dev_err(&pdev->dev, "no IRQ%d resource found\n", i); - return -ENXIO; + err = -ENXIO; + goto err_wed_exit; } } for (i = 0; i < ARRAY_SIZE(eth->clks); i++) { eth->clks[i] = devm_clk_get(eth->dev, mtk_clks_source_name[i]); if (IS_ERR(eth->clks[i])) { - if (PTR_ERR(eth->clks[i]) == -EPROBE_DEFER) - return -EPROBE_DEFER; + if (PTR_ERR(eth->clks[i]) == -EPROBE_DEFER) { + err = -EPROBE_DEFER; + goto err_wed_exit; + } if (eth->soc->required_clks & BIT(i)) { dev_err(&pdev->dev, "clock %s not found\n", mtk_clks_source_name[i]); - return -EINVAL; + err = -EINVAL; + goto err_wed_exit; } eth->clks[i] = NULL; } @@ -4083,7 +4087,7 @@ static int mtk_probe(struct platform_device *pdev) err = mtk_hw_init(eth); if (err) - return err; + goto err_wed_exit; eth->hwlro = MTK_HAS_CAPS(eth->soc->caps, MTK_HWLRO); @@ -4179,6 +4183,8 @@ err_free_dev: mtk_free_dev(eth); err_deinit_hw: mtk_hw_deinit(eth); +err_wed_exit: + mtk_wed_exit(); return err; } @@ -4198,6 +4204,7 @@ static int mtk_remove(struct platform_device *pdev) phylink_disconnect_phy(mac->phylink); } + mtk_wed_exit(); mtk_hw_deinit(eth); netif_napi_del(ð->tx_napi); diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c index ae00e572390d..2d8ca99f2467 100644 --- a/drivers/net/ethernet/mediatek/mtk_ppe.c +++ b/drivers/net/ethernet/mediatek/mtk_ppe.c @@ -397,12 +397,6 @@ int mtk_foe_entry_set_wdma(struct mtk_eth *eth, struct mtk_foe_entry *entry, return 0; } -static inline bool mtk_foe_entry_usable(struct mtk_foe_entry *entry) -{ - return !(entry->ib1 & MTK_FOE_IB1_STATIC) && - FIELD_GET(MTK_FOE_IB1_STATE, entry->ib1) != MTK_FOE_STATE_BIND; -} - static bool mtk_flow_entry_match(struct mtk_eth *eth, struct mtk_flow_entry *entry, struct mtk_foe_entry *data) diff --git a/drivers/net/ethernet/mediatek/mtk_wed.c b/drivers/net/ethernet/mediatek/mtk_wed.c index 099b6e0df619..65e01bf4b4d2 100644 --- a/drivers/net/ethernet/mediatek/mtk_wed.c +++ b/drivers/net/ethernet/mediatek/mtk_wed.c @@ -1072,16 +1072,16 @@ void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth, pdev = of_find_device_by_node(np); if (!pdev) - return; + goto err_of_node_put; get_device(&pdev->dev); irq = platform_get_irq(pdev, 0); if (irq < 0) - return; + goto err_put_device; regs = syscon_regmap_lookup_by_phandle(np, NULL); if (IS_ERR(regs)) - return; + goto err_put_device; rcu_assign_pointer(mtk_soc_wed_ops, &wed_ops); @@ -1124,8 +1124,16 @@ void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth, hw_list[index] = hw; + mutex_unlock(&hw_lock); + + return; + unlock: mutex_unlock(&hw_lock); +err_put_device: + put_device(&pdev->dev); +err_of_node_put: + of_node_put(np); } void mtk_wed_exit(void) @@ -1146,6 +1154,7 @@ void mtk_wed_exit(void) hw_list[i] = NULL; debugfs_remove(hw->debugfs_dir); put_device(hw->dev); + of_node_put(hw->node); kfree(hw); } } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index 0377392848d9..46ba4c2faad2 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -2004,7 +2004,7 @@ void mlx5_cmd_init_async_ctx(struct mlx5_core_dev *dev, ctx->dev = dev; /* Starts at 1 to avoid doing wake_up if we are not cleaning up */ atomic_set(&ctx->num_inflight, 1); - init_waitqueue_head(&ctx->wait); + init_completion(&ctx->inflight_done); } EXPORT_SYMBOL(mlx5_cmd_init_async_ctx); @@ -2018,8 +2018,8 @@ EXPORT_SYMBOL(mlx5_cmd_init_async_ctx); */ void mlx5_cmd_cleanup_async_ctx(struct mlx5_async_ctx *ctx) { - atomic_dec(&ctx->num_inflight); - wait_event(ctx->wait, atomic_read(&ctx->num_inflight) == 0); + if (!atomic_dec_and_test(&ctx->num_inflight)) + wait_for_completion(&ctx->inflight_done); } EXPORT_SYMBOL(mlx5_cmd_cleanup_async_ctx); @@ -2032,7 +2032,7 @@ static void mlx5_cmd_exec_cb_handler(int status, void *_work) status = cmd_status_err(ctx->dev, status, work->opcode, work->out); work->user_callback(status, work); if (atomic_dec_and_test(&ctx->num_inflight)) - wake_up(&ctx->wait); + complete(&ctx->inflight_done); } int mlx5_cmd_exec_cb(struct mlx5_async_ctx *ctx, void *in, int in_size, @@ -2050,7 +2050,7 @@ int mlx5_cmd_exec_cb(struct mlx5_async_ctx *ctx, void *in, int in_size, ret = cmd_exec(ctx->dev, in, in_size, out, out_size, mlx5_cmd_exec_cb_handler, work, false); if (ret && atomic_dec_and_test(&ctx->num_inflight)) - wake_up(&ctx->wait); + complete(&ctx->inflight_done); return ret; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.h b/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.h index 5bce554e131a..cc7efde88ac3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.h @@ -6,6 +6,7 @@ #include "en.h" #include "en_stats.h" +#include "en/txrx.h" #include <linux/ptp_classify.h> #define MLX5E_PTP_CHANNEL_IX 0 @@ -68,6 +69,14 @@ static inline bool mlx5e_use_ptpsq(struct sk_buff *skb) fk.ports.dst == htons(PTP_EV_PORT)); } +static inline bool mlx5e_ptpsq_fifo_has_room(struct mlx5e_txqsq *sq) +{ + if (!sq->ptpsq) + return true; + + return mlx5e_skb_fifo_has_room(&sq->ptpsq->skb_fifo); +} + int mlx5e_ptp_open(struct mlx5e_priv *priv, struct mlx5e_params *params, u8 lag_port, struct mlx5e_ptp **cp); void mlx5e_ptp_close(struct mlx5e_ptp *c); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/meter.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/meter.c index a53e205f4a89..be74e1403328 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/meter.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/meter.c @@ -115,6 +115,7 @@ mlx5e_tc_meter_modify(struct mlx5_core_dev *mdev, struct mlx5e_flow_meters *flow_meters; u8 cir_man, cir_exp, cbs_man, cbs_exp; struct mlx5_aso_wqe *aso_wqe; + unsigned long expires; struct mlx5_aso *aso; u64 rate, burst; u8 ds_cnt; @@ -187,7 +188,12 @@ mlx5e_tc_meter_modify(struct mlx5_core_dev *mdev, mlx5_aso_post_wqe(aso, true, &aso_wqe->ctrl); /* With newer FW, the wait for the first ASO WQE is more than 2us, put the wait 10ms. */ - err = mlx5_aso_poll_cq(aso, true, 10); + expires = jiffies + msecs_to_jiffies(10); + do { + err = mlx5_aso_poll_cq(aso, true); + if (err) + usleep_range(2, 10); + } while (err && time_is_after_jiffies(expires)); mutex_unlock(&flow_meters->aso_lock); return err; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h index 10c9a8a79d00..2e42d7c5451e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h @@ -96,6 +96,7 @@ struct mlx5e_tc_flow { struct encap_flow_item encaps[MLX5_MAX_FLOW_FWD_VPORTS]; struct mlx5e_tc_flow *peer_flow; struct mlx5e_mod_hdr_handle *mh; /* attached mod header instance */ + struct mlx5e_mod_hdr_handle *slow_mh; /* attached mod header instance for slow path */ struct mlx5e_hairpin_entry *hpe; /* attached hairpin instance */ struct list_head hairpin; /* flows sharing the same hairpin */ struct list_head peer; /* flows with peer flow */ @@ -111,6 +112,7 @@ struct mlx5e_tc_flow { struct completion del_hw_done; struct mlx5_flow_attr *attr; struct list_head attrs; + u32 chain_mapping; }; struct mlx5_flow_handle * diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h b/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h index 4456ad5cedf1..cb164b62f543 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h @@ -58,6 +58,12 @@ bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq, int napi_budget); void mlx5e_free_txqsq_descs(struct mlx5e_txqsq *sq); static inline bool +mlx5e_skb_fifo_has_room(struct mlx5e_skb_fifo *fifo) +{ + return (*fifo->pc - *fifo->cc) < fifo->mask; +} + +static inline bool mlx5e_wqc_has_room_for(struct mlx5_wq_cyc *wq, u16 cc, u16 pc, u16 n) { return (mlx5_wq_cyc_ctr2ix(wq, cc - pc) >= n) || (cc == pc); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c index 2a8fd7020622..a715601865d3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c @@ -101,7 +101,6 @@ static bool mlx5e_ipsec_update_esn_state(struct mlx5e_ipsec_sa_entry *sa_entry) struct xfrm_replay_state_esn *replay_esn; u32 seq_bottom = 0; u8 overlap; - u32 *esn; if (!(sa_entry->x->props.flags & XFRM_STATE_ESN)) { sa_entry->esn_state.trigger = 0; @@ -116,11 +115,9 @@ static bool mlx5e_ipsec_update_esn_state(struct mlx5e_ipsec_sa_entry *sa_entry) sa_entry->esn_state.esn = xfrm_replay_seqhi(sa_entry->x, htonl(seq_bottom)); - esn = &sa_entry->esn_state.esn; sa_entry->esn_state.trigger = 1; if (unlikely(overlap && seq_bottom < MLX5E_IPSEC_ESN_SCOPE_MID)) { - ++(*esn); sa_entry->esn_state.overlap = 0; return true; } else if (unlikely(!overlap && diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c index 5da746da898d..2ef36cb9555a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c @@ -432,7 +432,7 @@ static int mlx5e_macsec_update_rx_sa(struct mlx5e_macsec *macsec, bool active) { struct mlx5_core_dev *mdev = macsec->mdev; - struct mlx5_macsec_obj_attrs attrs; + struct mlx5_macsec_obj_attrs attrs = {}; int err = 0; if (rx_sa->active != active) @@ -444,7 +444,7 @@ static int mlx5e_macsec_update_rx_sa(struct mlx5e_macsec *macsec, return 0; } - attrs.sci = rx_sa->sci; + attrs.sci = cpu_to_be64((__force u64)rx_sa->sci); attrs.enc_key_id = rx_sa->enc_key_id; err = mlx5e_macsec_create_object(mdev, &attrs, false, &rx_sa->macsec_obj_id); if (err) @@ -999,11 +999,11 @@ static int mlx5e_macsec_upd_rxsa(struct macsec_context *ctx) } rx_sa = rx_sc->rx_sa[assoc_num]; - if (rx_sa) { + if (!rx_sa) { netdev_err(ctx->netdev, - "MACsec offload rx_sc sci %lld rx_sa %d already exist\n", + "MACsec offload rx_sc sci %lld rx_sa %d doesn't exist\n", sci, assoc_num); - err = -EEXIST; + err = -EINVAL; goto out; } @@ -1055,11 +1055,11 @@ static int mlx5e_macsec_del_rxsa(struct macsec_context *ctx) } rx_sa = rx_sc->rx_sa[assoc_num]; - if (rx_sa) { + if (!rx_sa) { netdev_err(ctx->netdev, - "MACsec offload rx_sc sci %lld rx_sa %d already exist\n", + "MACsec offload rx_sc sci %lld rx_sa %d doesn't exist\n", sci, assoc_num); - err = -EEXIST; + err = -EINVAL; goto out; } @@ -1405,7 +1405,7 @@ static int macsec_aso_set_arm_event(struct mlx5_core_dev *mdev, struct mlx5e_mac MLX5_ACCESS_ASO_OPC_MOD_MACSEC); macsec_aso_build_ctrl(aso, &aso_wqe->aso_ctrl, in); mlx5_aso_post_wqe(maso, false, &aso_wqe->ctrl); - err = mlx5_aso_poll_cq(maso, false, 10); + err = mlx5_aso_poll_cq(maso, false); mutex_unlock(&aso->aso_lock); return err; @@ -1430,7 +1430,7 @@ static int macsec_aso_query(struct mlx5_core_dev *mdev, struct mlx5e_macsec *mac macsec_aso_build_wqe_ctrl_seg(aso, &aso_wqe->aso_ctrl, NULL); mlx5_aso_post_wqe(maso, false, &aso_wqe->ctrl); - err = mlx5_aso_poll_cq(maso, false, 10); + err = mlx5_aso_poll_cq(maso, false); if (err) goto err_out; @@ -1846,25 +1846,16 @@ err_hash: void mlx5e_macsec_cleanup(struct mlx5e_priv *priv) { struct mlx5e_macsec *macsec = priv->macsec; - struct mlx5_core_dev *mdev = macsec->mdev; + struct mlx5_core_dev *mdev = priv->mdev; if (!macsec) return; mlx5_notifier_unregister(mdev, &macsec->nb); - mlx5e_macsec_fs_cleanup(macsec->macsec_fs); - - /* Cleanup workqueue */ destroy_workqueue(macsec->wq); - mlx5e_macsec_aso_cleanup(&macsec->aso, mdev); - - priv->macsec = NULL; - rhashtable_destroy(&macsec->sci_hash); - mutex_destroy(&macsec->lock); - kfree(macsec); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec_fs.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec_fs.c index 13dc628b988a..1ac0cf04e811 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec_fs.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec_fs.c @@ -1180,7 +1180,7 @@ macsec_fs_rx_add_rule(struct mlx5e_macsec_fs *macsec_fs, rx_rule->rule[0] = rule; /* Rx crypto table without SCI rule */ - if (cpu_to_be64((__force u64)attrs->sci) & ntohs(MACSEC_PORT_ES)) { + if ((cpu_to_be64((__force u64)attrs->sci) & 0xFFFF) == ntohs(MACSEC_PORT_ES)) { memset(spec, 0, sizeof(struct mlx5_flow_spec)); memset(&dest, 0, sizeof(struct mlx5_flow_destination)); memset(&flow_act, 0, sizeof(flow_act)); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 70a7a61f9708..dd6fea9e9a5b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -1405,8 +1405,13 @@ mlx5e_tc_offload_to_slow_path(struct mlx5_eswitch *esw, struct mlx5e_tc_flow *flow, struct mlx5_flow_spec *spec) { + struct mlx5e_tc_mod_hdr_acts mod_acts = {}; + struct mlx5e_mod_hdr_handle *mh = NULL; struct mlx5_flow_attr *slow_attr; struct mlx5_flow_handle *rule; + bool fwd_and_modify_cap; + u32 chain_mapping = 0; + int err; slow_attr = mlx5_alloc_flow_attr(MLX5_FLOW_NAMESPACE_FDB); if (!slow_attr) @@ -1417,13 +1422,56 @@ mlx5e_tc_offload_to_slow_path(struct mlx5_eswitch *esw, slow_attr->esw_attr->split_count = 0; slow_attr->flags |= MLX5_ATTR_FLAG_SLOW_PATH; + fwd_and_modify_cap = MLX5_CAP_ESW_FLOWTABLE((esw)->dev, fdb_modify_header_fwd_to_table); + if (!fwd_and_modify_cap) + goto skip_restore; + + err = mlx5_chains_get_chain_mapping(esw_chains(esw), flow->attr->chain, &chain_mapping); + if (err) + goto err_get_chain; + + err = mlx5e_tc_match_to_reg_set(esw->dev, &mod_acts, MLX5_FLOW_NAMESPACE_FDB, + CHAIN_TO_REG, chain_mapping); + if (err) + goto err_reg_set; + + mh = mlx5e_mod_hdr_attach(esw->dev, get_mod_hdr_table(flow->priv, flow), + MLX5_FLOW_NAMESPACE_FDB, &mod_acts); + if (IS_ERR(mh)) { + err = PTR_ERR(mh); + goto err_attach; + } + + slow_attr->action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR; + slow_attr->modify_hdr = mlx5e_mod_hdr_get(mh); + +skip_restore: rule = mlx5e_tc_offload_fdb_rules(esw, flow, spec, slow_attr); - if (!IS_ERR(rule)) - flow_flag_set(flow, SLOW); + if (IS_ERR(rule)) { + err = PTR_ERR(rule); + goto err_offload; + } + flow->slow_mh = mh; + flow->chain_mapping = chain_mapping; + flow_flag_set(flow, SLOW); + + mlx5e_mod_hdr_dealloc(&mod_acts); kfree(slow_attr); return rule; + +err_offload: + if (fwd_and_modify_cap) + mlx5e_mod_hdr_detach(esw->dev, get_mod_hdr_table(flow->priv, flow), mh); +err_attach: +err_reg_set: + if (fwd_and_modify_cap) + mlx5_chains_put_chain_mapping(esw_chains(esw), chain_mapping); +err_get_chain: + mlx5e_mod_hdr_dealloc(&mod_acts); + kfree(slow_attr); + return ERR_PTR(err); } void mlx5e_tc_unoffload_from_slow_path(struct mlx5_eswitch *esw, @@ -1441,7 +1489,17 @@ void mlx5e_tc_unoffload_from_slow_path(struct mlx5_eswitch *esw, slow_attr->action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; slow_attr->esw_attr->split_count = 0; slow_attr->flags |= MLX5_ATTR_FLAG_SLOW_PATH; + if (flow->slow_mh) { + slow_attr->action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR; + slow_attr->modify_hdr = mlx5e_mod_hdr_get(flow->slow_mh); + } mlx5e_tc_unoffload_fdb_rules(esw, flow, slow_attr); + if (flow->slow_mh) { + mlx5e_mod_hdr_detach(esw->dev, get_mod_hdr_table(flow->priv, flow), flow->slow_mh); + mlx5_chains_put_chain_mapping(esw_chains(esw), flow->chain_mapping); + flow->chain_mapping = 0; + flow->slow_mh = NULL; + } flow_flag_clear(flow, SLOW); kfree(slow_attr); } @@ -3575,6 +3633,10 @@ mlx5e_clone_flow_attr_for_post_act(struct mlx5_flow_attr *attr, attr2->action = 0; attr2->flags = 0; attr2->parse_attr = parse_attr; + attr2->esw_attr->out_count = 0; + attr2->esw_attr->split_count = 0; + attr2->dest_chain = 0; + attr2->dest_ft = NULL; return attr2; } @@ -4008,6 +4070,7 @@ parse_tc_fdb_actions(struct mlx5e_priv *priv, struct mlx5e_tc_flow_parse_attr *parse_attr; struct mlx5_flow_attr *attr = flow->attr; struct mlx5_esw_flow_attr *esw_attr; + struct net_device *filter_dev; int err; err = flow_action_supported(flow_action, extack); @@ -4016,6 +4079,7 @@ parse_tc_fdb_actions(struct mlx5e_priv *priv, esw_attr = attr->esw_attr; parse_attr = attr->parse_attr; + filter_dev = parse_attr->filter_dev; parse_state = &parse_attr->parse_state; mlx5e_tc_act_init_parse_state(parse_state, flow, flow_action, extack); parse_state->ct_priv = get_ct_priv(priv); @@ -4025,13 +4089,21 @@ parse_tc_fdb_actions(struct mlx5e_priv *priv, return err; /* Forward to/from internal port can only have 1 dest */ - if ((netif_is_ovs_master(parse_attr->filter_dev) || esw_attr->dest_int_port) && + if ((netif_is_ovs_master(filter_dev) || esw_attr->dest_int_port) && esw_attr->out_count > 1) { NL_SET_ERR_MSG_MOD(extack, "Rules with internal port can have only one destination"); return -EOPNOTSUPP; } + /* Forward from tunnel/internal port to internal port is not supported */ + if ((mlx5e_get_tc_tun(filter_dev) || netif_is_ovs_master(filter_dev)) && + esw_attr->dest_int_port) { + NL_SET_ERR_MSG_MOD(extack, + "Forwarding from tunnel/internal port to internal port is not supported"); + return -EOPNOTSUPP; + } + err = actions_prepare_mod_hdr_actions(priv, flow, attr, extack); if (err) return err; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c index bf2232a2a836..6adca01fbdc9 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c @@ -392,6 +392,11 @@ mlx5e_txwqe_complete(struct mlx5e_txqsq *sq, struct sk_buff *skb, if (unlikely(sq->ptpsq)) { mlx5e_skb_cb_hwtstamp_init(skb); mlx5e_skb_fifo_push(&sq->ptpsq->skb_fifo, skb); + if (!netif_tx_queue_stopped(sq->txq) && + !mlx5e_skb_fifo_has_room(&sq->ptpsq->skb_fifo)) { + netif_tx_stop_queue(sq->txq); + sq->stats->stopped++; + } skb_get(skb); } @@ -868,6 +873,7 @@ bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq, int napi_budget) if (netif_tx_queue_stopped(sq->txq) && mlx5e_wqc_has_room_for(&sq->wq, sq->cc, sq->pc, sq->stop_room) && + mlx5e_ptpsq_fifo_has_room(sq) && !test_bit(MLX5E_SQ_STATE_RECOVERING, &sq->state)) { netif_tx_wake_queue(sq->txq); stats->wake++; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c index e8896f368362..07c583996c29 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c @@ -358,6 +358,23 @@ static int mlx5_pci_link_toggle(struct mlx5_core_dev *dev) err = -ETIMEDOUT; } + do { + err = pci_read_config_word(dev->pdev, PCI_DEVICE_ID, ®16); + if (err) + return err; + if (reg16 == dev_id) + break; + msleep(20); + } while (!time_after(jiffies, timeout)); + + if (reg16 == dev_id) { + mlx5_core_info(dev, "Firmware responds to PCI config cycles again\n"); + } else { + mlx5_core_err(dev, "Firmware is not responsive (0x%04x) after %llu ms\n", + reg16, mlx5_tout_ms(dev, PCI_TOGGLE)); + err = -ETIMEDOUT; + } + restore: list_for_each_entry(sdev, &bridge_bus->devices, bus_list) { pci_cfg_access_unlock(sdev); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/aso.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/aso.c index 21e14507ff5c..c971ff04dd04 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/aso.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/aso.c @@ -3,6 +3,7 @@ #include <linux/mlx5/device.h> #include <linux/mlx5/transobj.h> +#include "clock.h" #include "aso.h" #include "wq.h" @@ -179,6 +180,7 @@ static int create_aso_sq(struct mlx5_core_dev *mdev, int pdn, { void *in, *sqc, *wq; int inlen, err; + u8 ts_format; inlen = MLX5_ST_SZ_BYTES(create_sq_in) + sizeof(u64) * sq->wq_ctrl.buf.npages; @@ -195,6 +197,11 @@ static int create_aso_sq(struct mlx5_core_dev *mdev, int pdn, MLX5_SET(sqc, sqc, state, MLX5_SQC_STATE_RST); MLX5_SET(sqc, sqc, flush_in_error_en, 1); + ts_format = mlx5_is_real_time_sq(mdev) ? + MLX5_TIMESTAMP_FORMAT_REAL_TIME : + MLX5_TIMESTAMP_FORMAT_FREE_RUNNING; + MLX5_SET(sqc, sqc, ts_format, ts_format); + MLX5_SET(wq, wq, wq_type, MLX5_WQ_TYPE_CYCLIC); MLX5_SET(wq, wq, uar_page, mdev->mlx5e_res.hw_objs.bfreg.index); MLX5_SET(wq, wq, log_wq_pg_sz, sq->wq_ctrl.buf.page_shift - @@ -381,20 +388,12 @@ void mlx5_aso_post_wqe(struct mlx5_aso *aso, bool with_data, WRITE_ONCE(doorbell_cseg, NULL); } -int mlx5_aso_poll_cq(struct mlx5_aso *aso, bool with_data, u32 interval_ms) +int mlx5_aso_poll_cq(struct mlx5_aso *aso, bool with_data) { struct mlx5_aso_cq *cq = &aso->cq; struct mlx5_cqe64 *cqe; - unsigned long expires; cqe = mlx5_cqwq_get_cqe(&cq->wq); - - expires = jiffies + msecs_to_jiffies(interval_ms); - while (!cqe && time_is_after_jiffies(expires)) { - usleep_range(2, 10); - cqe = mlx5_cqwq_get_cqe(&cq->wq); - } - if (!cqe) return -ETIMEDOUT; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/aso.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/aso.h index d854e01d7fc5..2d40dcf9d42e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/aso.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/aso.h @@ -83,7 +83,7 @@ void mlx5_aso_build_wqe(struct mlx5_aso *aso, u8 ds_cnt, u32 obj_id, u32 opc_mode); void mlx5_aso_post_wqe(struct mlx5_aso *aso, bool with_data, struct mlx5_wqe_ctrl_seg *doorbell_cseg); -int mlx5_aso_poll_cq(struct mlx5_aso *aso, bool with_data, u32 interval_ms); +int mlx5_aso_poll_cq(struct mlx5_aso *aso, bool with_data); struct mlx5_aso *mlx5_aso_create(struct mlx5_core_dev *mdev, u32 pdn); void mlx5_aso_destroy(struct mlx5_aso *aso); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/mpfs.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/mpfs.c index 839a01da110f..8ff16318e32d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/mpfs.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/mpfs.c @@ -122,7 +122,7 @@ void mlx5_mpfs_cleanup(struct mlx5_core_dev *dev) { struct mlx5_mpfs *mpfs = dev->priv.mpfs; - if (!MLX5_ESWITCH_MANAGER(dev)) + if (!mpfs) return; WARN_ON(!hlist_empty(mpfs->hash)); @@ -137,7 +137,7 @@ int mlx5_mpfs_add_mac(struct mlx5_core_dev *dev, u8 *mac) int err = 0; u32 index; - if (!MLX5_ESWITCH_MANAGER(dev)) + if (!mpfs) return 0; mutex_lock(&mpfs->lock); @@ -185,7 +185,7 @@ int mlx5_mpfs_del_mac(struct mlx5_core_dev *dev, u8 *mac) int err = 0; u32 index; - if (!MLX5_ESWITCH_MANAGER(dev)) + if (!mpfs) return 0; mutex_lock(&mpfs->lock); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index 0b459d841c3a..283c4cc28944 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -1872,6 +1872,10 @@ static void mlx5_pci_resume(struct pci_dev *pdev) err = mlx5_load_one(dev, false); + if (!err) + devlink_health_reporter_state_update(dev->priv.health.fw_fatal_reporter, + DEVLINK_HEALTH_REPORTER_STATE_HEALTHY); + mlx5_pci_trace(dev, "Done, err = %d, device %s\n", err, !err ? "recovered" : "Failed"); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_rule.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_rule.c index ddfaf7891188..91ff19f67695 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_rule.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_rule.c @@ -1200,7 +1200,8 @@ free_rule: } remove_from_nic_tbl: - mlx5dr_matcher_remove_from_tbl_nic(dmn, nic_matcher); + if (!nic_matcher->rules) + mlx5dr_matcher_remove_from_tbl_nic(dmn, nic_matcher); free_hw_ste: mlx5dr_domain_nic_unlock(nic_dmn); diff --git a/drivers/net/ethernet/mellanox/mlxsw/i2c.c b/drivers/net/ethernet/mellanox/mlxsw/i2c.c index 716c73e4fd59..f5f5f8dc3d19 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/i2c.c +++ b/drivers/net/ethernet/mellanox/mlxsw/i2c.c @@ -740,15 +740,13 @@ errout: return err; } -static int mlxsw_i2c_remove(struct i2c_client *client) +static void mlxsw_i2c_remove(struct i2c_client *client) { struct mlxsw_i2c *mlxsw_i2c = i2c_get_clientdata(client); mlxsw_core_bus_device_unregister(mlxsw_i2c->core, false); mlxsw_i2c_irq_fini(mlxsw_i2c); mutex_destroy(&mlxsw_i2c->cmd.lock); - - return 0; } int mlxsw_i2c_driver_register(struct i2c_driver *i2c_driver) diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index 0777bed5bb1a..b74f30ec629a 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -4620,6 +4620,7 @@ MLXSW_ITEM32(reg, ptys, an_status, 0x04, 28, 4); #define MLXSW_REG_PTYS_EXT_ETH_SPEED_100GAUI_2_100GBASE_CR2_KR2 BIT(10) #define MLXSW_REG_PTYS_EXT_ETH_SPEED_200GAUI_4_200GBASE_CR4_KR4 BIT(12) #define MLXSW_REG_PTYS_EXT_ETH_SPEED_400GAUI_8 BIT(15) +#define MLXSW_REG_PTYS_EXT_ETH_SPEED_800GAUI_8 BIT(19) /* reg_ptys_ext_eth_proto_cap * Extended Ethernet port supported speeds and protocols. diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ethtool.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ethtool.c index dcd79d7e2af4..472830d07ac1 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ethtool.c @@ -1672,6 +1672,19 @@ mlxsw_sp2_mask_ethtool_400gaui_8[] = { #define MLXSW_SP2_MASK_ETHTOOL_400GAUI_8_LEN \ ARRAY_SIZE(mlxsw_sp2_mask_ethtool_400gaui_8) +static const enum ethtool_link_mode_bit_indices +mlxsw_sp2_mask_ethtool_800gaui_8[] = { + ETHTOOL_LINK_MODE_800000baseCR8_Full_BIT, + ETHTOOL_LINK_MODE_800000baseKR8_Full_BIT, + ETHTOOL_LINK_MODE_800000baseDR8_Full_BIT, + ETHTOOL_LINK_MODE_800000baseDR8_2_Full_BIT, + ETHTOOL_LINK_MODE_800000baseSR8_Full_BIT, + ETHTOOL_LINK_MODE_800000baseVR8_Full_BIT, +}; + +#define MLXSW_SP2_MASK_ETHTOOL_800GAUI_8_LEN \ + ARRAY_SIZE(mlxsw_sp2_mask_ethtool_800gaui_8) + #define MLXSW_SP_PORT_MASK_WIDTH_1X BIT(0) #define MLXSW_SP_PORT_MASK_WIDTH_2X BIT(1) #define MLXSW_SP_PORT_MASK_WIDTH_4X BIT(2) @@ -1820,6 +1833,14 @@ static const struct mlxsw_sp2_port_link_mode mlxsw_sp2_port_link_mode[] = { .speed = SPEED_400000, .width = 8, }, + { + .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_800GAUI_8, + .mask_ethtool = mlxsw_sp2_mask_ethtool_800gaui_8, + .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_800GAUI_8_LEN, + .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_8X, + .speed = SPEED_800000, + .width = 8, + }, }; #define MLXSW_SP2_PORT_LINK_MODE_LEN ARRAY_SIZE(mlxsw_sp2_port_link_mode) diff --git a/drivers/net/ethernet/micrel/ksz884x.c b/drivers/net/ethernet/micrel/ksz884x.c index 468520079c65..e6acd1e7b263 100644 --- a/drivers/net/ethernet/micrel/ksz884x.c +++ b/drivers/net/ethernet/micrel/ksz884x.c @@ -6851,7 +6851,7 @@ static int pcidev_init(struct pci_dev *pdev, const struct pci_device_id *id) char banner[sizeof(version)]; struct ksz_switch *sw = NULL; - result = pci_enable_device(pdev); + result = pcim_enable_device(pdev); if (result) return result; diff --git a/drivers/net/ethernet/microchip/Kconfig b/drivers/net/ethernet/microchip/Kconfig index ed7a35c3ceac..24c994baad13 100644 --- a/drivers/net/ethernet/microchip/Kconfig +++ b/drivers/net/ethernet/microchip/Kconfig @@ -57,5 +57,6 @@ config LAN743X source "drivers/net/ethernet/microchip/lan966x/Kconfig" source "drivers/net/ethernet/microchip/sparx5/Kconfig" +source "drivers/net/ethernet/microchip/vcap/Kconfig" endif # NET_VENDOR_MICROCHIP diff --git a/drivers/net/ethernet/microchip/Makefile b/drivers/net/ethernet/microchip/Makefile index 9faa41436198..bbd349264e6f 100644 --- a/drivers/net/ethernet/microchip/Makefile +++ b/drivers/net/ethernet/microchip/Makefile @@ -11,3 +11,4 @@ lan743x-objs := lan743x_main.o lan743x_ethtool.o lan743x_ptp.o obj-$(CONFIG_LAN966X_SWITCH) += lan966x/ obj-$(CONFIG_SPARX5_SWITCH) += sparx5/ +obj-$(CONFIG_VCAP) += vcap/ diff --git a/drivers/net/ethernet/microchip/lan743x_ethtool.c b/drivers/net/ethernet/microchip/lan743x_ethtool.c index c739d60ee17d..88f9484cc2a7 100644 --- a/drivers/net/ethernet/microchip/lan743x_ethtool.c +++ b/drivers/net/ethernet/microchip/lan743x_ethtool.c @@ -1233,6 +1233,50 @@ static void lan743x_get_regs(struct net_device *dev, lan743x_common_regs(dev, regs, p); } +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; +} + +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; + + if (pause->tx_pause) + phy->fc_request_control |= FLOW_CTRL_TX; + + phy->fc_autoneg = pause->autoneg; + + 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; +} + const struct ethtool_ops lan743x_ethtool_ops = { .get_drvinfo = lan743x_ethtool_get_drvinfo, .get_msglevel = lan743x_ethtool_get_msglevel, @@ -1259,6 +1303,8 @@ const struct ethtool_ops lan743x_ethtool_ops = { .set_link_ksettings = phy_ethtool_set_link_ksettings, .get_regs_len = lan743x_get_regs_len, .get_regs = lan743x_get_regs, + .get_pauseparam = lan743x_get_pauseparam, + .set_pauseparam = lan743x_set_pauseparam, #ifdef CONFIG_PM .get_wol = lan743x_ethtool_get_wol, .set_wol = lan743x_ethtool_set_wol, diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c index 50eeecba1f18..c0f8ba601c01 100644 --- a/drivers/net/ethernet/microchip/lan743x_main.c +++ b/drivers/net/ethernet/microchip/lan743x_main.c @@ -1326,8 +1326,8 @@ static void lan743x_mac_close(struct lan743x_adapter *adapter) 1, 1000, 20000, 100); } -static void lan743x_mac_flow_ctrl_set_enables(struct lan743x_adapter *adapter, - bool tx_enable, bool rx_enable) +void lan743x_mac_flow_ctrl_set_enables(struct lan743x_adapter *adapter, + bool tx_enable, bool rx_enable) { u32 flow_setting = 0; diff --git a/drivers/net/ethernet/microchip/lan743x_main.h b/drivers/net/ethernet/microchip/lan743x_main.h index 67877d3b6dd9..bc5eea4c7b40 100644 --- a/drivers/net/ethernet/microchip/lan743x_main.h +++ b/drivers/net/ethernet/microchip/lan743x_main.h @@ -1159,5 +1159,7 @@ u32 lan743x_csr_read(struct lan743x_adapter *adapter, int offset); void lan743x_csr_write(struct lan743x_adapter *adapter, int offset, u32 data); int lan743x_hs_syslock_acquire(struct lan743x_adapter *adapter, u16 timeout); 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); #endif /* _LAN743X_H */ diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c b/drivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c index e58a27fd8b50..fea42542be28 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c @@ -656,7 +656,15 @@ void lan966x_stats_get(struct net_device *dev, stats->rx_dropped = dev->stats.rx_dropped + lan966x->stats[idx + SYS_COUNT_RX_LONG] + lan966x->stats[idx + SYS_COUNT_DR_LOCAL] + - lan966x->stats[idx + SYS_COUNT_DR_TAIL]; + lan966x->stats[idx + SYS_COUNT_DR_TAIL] + + lan966x->stats[idx + SYS_COUNT_RX_RED_PRIO_0] + + lan966x->stats[idx + SYS_COUNT_RX_RED_PRIO_1] + + lan966x->stats[idx + SYS_COUNT_RX_RED_PRIO_2] + + lan966x->stats[idx + SYS_COUNT_RX_RED_PRIO_3] + + lan966x->stats[idx + SYS_COUNT_RX_RED_PRIO_4] + + lan966x->stats[idx + SYS_COUNT_RX_RED_PRIO_5] + + lan966x->stats[idx + SYS_COUNT_RX_RED_PRIO_6] + + lan966x->stats[idx + SYS_COUNT_RX_RED_PRIO_7]; for (i = 0; i < LAN966X_NUM_TC; i++) { stats->rx_dropped += diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c b/drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c index 7e4061c854f0..a42035cec611 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c @@ -309,6 +309,7 @@ static void lan966x_fdma_tx_disable(struct lan966x_tx *tx) lan966x, FDMA_CH_DB_DISCARD); tx->activated = false; + tx->last_in_use = -1; } static void lan966x_fdma_tx_reload(struct lan966x_tx *tx) @@ -687,17 +688,14 @@ static int lan966x_qsys_sw_status(struct lan966x *lan966x) static int lan966x_fdma_reload(struct lan966x *lan966x, int new_mtu) { - void *rx_dcbs, *tx_dcbs, *tx_dcbs_buf; - dma_addr_t rx_dma, tx_dma; + dma_addr_t rx_dma; + void *rx_dcbs; u32 size; int err; /* Store these for later to free them */ rx_dma = lan966x->rx.dma; - tx_dma = lan966x->tx.dma; rx_dcbs = lan966x->rx.dcbs; - tx_dcbs = lan966x->tx.dcbs; - tx_dcbs_buf = lan966x->tx.dcbs_buf; napi_synchronize(&lan966x->napi); napi_disable(&lan966x->napi); @@ -715,17 +713,6 @@ static int lan966x_fdma_reload(struct lan966x *lan966x, int new_mtu) size = ALIGN(size, PAGE_SIZE); dma_free_coherent(lan966x->dev, size, rx_dcbs, rx_dma); - lan966x_fdma_tx_disable(&lan966x->tx); - err = lan966x_fdma_tx_alloc(&lan966x->tx); - if (err) - goto restore_tx; - - size = sizeof(struct lan966x_tx_dcb) * FDMA_DCB_MAX; - size = ALIGN(size, PAGE_SIZE); - dma_free_coherent(lan966x->dev, size, tx_dcbs, tx_dma); - - kfree(tx_dcbs_buf); - lan966x_fdma_wakeup_netdev(lan966x); napi_enable(&lan966x->napi); @@ -735,11 +722,6 @@ restore: lan966x->rx.dcbs = rx_dcbs; lan966x_fdma_rx_start(&lan966x->rx); -restore_tx: - lan966x->tx.dma = tx_dma; - lan966x->tx.dcbs = tx_dcbs; - lan966x->tx.dcbs_buf = tx_dcbs_buf; - return err; } diff --git a/drivers/net/ethernet/microchip/sparx5/Kconfig b/drivers/net/ethernet/microchip/sparx5/Kconfig index cc5e48e1bb4c..98e27530a91f 100644 --- a/drivers/net/ethernet/microchip/sparx5/Kconfig +++ b/drivers/net/ethernet/microchip/sparx5/Kconfig @@ -9,5 +9,6 @@ config SPARX5_SWITCH select PHYLINK select PHY_SPARX5_SERDES select RESET_CONTROLLER + select VCAP help This driver supports the Sparx5 network switch device. diff --git a/drivers/net/ethernet/microchip/sparx5/Makefile b/drivers/net/ethernet/microchip/sparx5/Makefile index d1c6ad966747..ee2c42f66742 100644 --- a/drivers/net/ethernet/microchip/sparx5/Makefile +++ b/drivers/net/ethernet/microchip/sparx5/Makefile @@ -5,7 +5,11 @@ obj-$(CONFIG_SPARX5_SWITCH) += sparx5-switch.o -sparx5-switch-objs := sparx5_main.o sparx5_packet.o \ +sparx5-switch-y := sparx5_main.o sparx5_packet.o \ sparx5_netdev.o sparx5_phylink.o sparx5_port.o sparx5_mactable.o sparx5_vlan.o \ sparx5_switchdev.o sparx5_calendar.o sparx5_ethtool.o sparx5_fdma.o \ - sparx5_ptp.o sparx5_pgid.o sparx5_tc.o sparx5_qos.o + sparx5_ptp.o sparx5_pgid.o sparx5_tc.o sparx5_qos.o \ + sparx5_vcap_impl.o sparx5_vcap_ag_api.o sparx5_tc_flower.o + +# Provide include files +ccflags-y += -I$(srctree)/drivers/net/ethernet/microchip/vcap diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_main.c b/drivers/net/ethernet/microchip/sparx5/sparx5_main.c index 62a325e96345..0b70c00c6eaa 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_main.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_main.c @@ -672,6 +672,14 @@ static int sparx5_start(struct sparx5 *sparx5) sparx5_board_init(sparx5); err = sparx5_register_notifier_blocks(sparx5); + if (err) + return err; + + err = sparx5_vcap_init(sparx5); + if (err) { + sparx5_unregister_notifier_blocks(sparx5); + return err; + } /* Start Frame DMA with fallback to register based INJ/XTR */ err = -ENXIO; @@ -906,6 +914,7 @@ static int mchp_sparx5_remove(struct platform_device *pdev) sparx5_ptp_deinit(sparx5); sparx5_fdma_stop(sparx5); sparx5_cleanup_ports(sparx5); + sparx5_vcap_destroy(sparx5); /* Unregister netdevs */ sparx5_unregister_notifier_blocks(sparx5); diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_main.h b/drivers/net/ethernet/microchip/sparx5/sparx5_main.h index 7a83222caa73..2ab22a7b799e 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_main.h +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_main.h @@ -288,6 +288,8 @@ struct sparx5 { struct mutex ptp_lock; /* lock for ptp interface state */ u16 ptp_skbs; int ptp_irq; + /* VCAP */ + struct vcap_control *vcap_ctrl; /* PGID allocation map */ u8 pgid_map[PGID_TABLE_SIZE]; }; @@ -382,6 +384,10 @@ void sparx5_ptp_txtstamp_release(struct sparx5_port *port, struct sk_buff *skb); irqreturn_t sparx5_ptp_irq_handler(int irq, void *args); +/* sparx5_vcap_impl.c */ +int sparx5_vcap_init(struct sparx5 *sparx5); +void sparx5_vcap_destroy(struct sparx5 *sparx5); + /* sparx5_pgid.c */ enum sparx5_pgid_type { SPX5_PGID_FREE, diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_main_regs.h b/drivers/net/ethernet/microchip/sparx5/sparx5_main_regs.h index fa2eb70f487a..c42195f4ec4d 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_main_regs.h +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_main_regs.h @@ -4,8 +4,8 @@ * Copyright (c) 2021 Microchip Technology Inc. */ -/* This file is autogenerated by cml-utils 2022-02-26 14:15:01 +0100. - * Commit ID: 98bdd3d171cc2a1afd30d241d41a4281d471a48c (dirty) +/* This file is autogenerated by cml-utils 2022-09-12 14:22:42 +0200. + * Commit ID: 06aecbca4eab6e85d87f665fe6b6348c48146245 */ #ifndef _SPARX5_MAIN_REGS_H_ @@ -171,6 +171,162 @@ enum sparx5_target { /* ANA_AC:STAT_CNT_CFG_PORT:STAT_LSB_CNT */ #define ANA_AC_PORT_STAT_LSB_CNT(g, r) __REG(TARGET_ANA_AC, 0, 1, 843776, g, 70, 64, 20, r, 4, 4) +/* ANA_ACL:COMMON:VCAP_S2_CFG */ +#define ANA_ACL_VCAP_S2_CFG(r) __REG(TARGET_ANA_ACL, 0, 1, 32768, 0, 1, 592, 0, r, 70, 4) + +#define ANA_ACL_VCAP_S2_CFG_SEC_ROUTE_HANDLING_ENA BIT(28) +#define ANA_ACL_VCAP_S2_CFG_SEC_ROUTE_HANDLING_ENA_SET(x)\ + FIELD_PREP(ANA_ACL_VCAP_S2_CFG_SEC_ROUTE_HANDLING_ENA, x) +#define ANA_ACL_VCAP_S2_CFG_SEC_ROUTE_HANDLING_ENA_GET(x)\ + FIELD_GET(ANA_ACL_VCAP_S2_CFG_SEC_ROUTE_HANDLING_ENA, x) + +#define ANA_ACL_VCAP_S2_CFG_SEC_TYPE_OAM_ENA GENMASK(27, 26) +#define ANA_ACL_VCAP_S2_CFG_SEC_TYPE_OAM_ENA_SET(x)\ + FIELD_PREP(ANA_ACL_VCAP_S2_CFG_SEC_TYPE_OAM_ENA, x) +#define ANA_ACL_VCAP_S2_CFG_SEC_TYPE_OAM_ENA_GET(x)\ + FIELD_GET(ANA_ACL_VCAP_S2_CFG_SEC_TYPE_OAM_ENA, x) + +#define ANA_ACL_VCAP_S2_CFG_SEC_TYPE_IP6_TCPUDP_OTHER_ENA GENMASK(25, 24) +#define ANA_ACL_VCAP_S2_CFG_SEC_TYPE_IP6_TCPUDP_OTHER_ENA_SET(x)\ + FIELD_PREP(ANA_ACL_VCAP_S2_CFG_SEC_TYPE_IP6_TCPUDP_OTHER_ENA, x) +#define ANA_ACL_VCAP_S2_CFG_SEC_TYPE_IP6_TCPUDP_OTHER_ENA_GET(x)\ + FIELD_GET(ANA_ACL_VCAP_S2_CFG_SEC_TYPE_IP6_TCPUDP_OTHER_ENA, x) + +#define ANA_ACL_VCAP_S2_CFG_SEC_TYPE_IP6_VID_ENA GENMASK(23, 22) +#define ANA_ACL_VCAP_S2_CFG_SEC_TYPE_IP6_VID_ENA_SET(x)\ + FIELD_PREP(ANA_ACL_VCAP_S2_CFG_SEC_TYPE_IP6_VID_ENA, x) +#define ANA_ACL_VCAP_S2_CFG_SEC_TYPE_IP6_VID_ENA_GET(x)\ + FIELD_GET(ANA_ACL_VCAP_S2_CFG_SEC_TYPE_IP6_VID_ENA, x) + +#define ANA_ACL_VCAP_S2_CFG_SEC_TYPE_IP6_STD_ENA GENMASK(21, 20) +#define ANA_ACL_VCAP_S2_CFG_SEC_TYPE_IP6_STD_ENA_SET(x)\ + FIELD_PREP(ANA_ACL_VCAP_S2_CFG_SEC_TYPE_IP6_STD_ENA, x) +#define ANA_ACL_VCAP_S2_CFG_SEC_TYPE_IP6_STD_ENA_GET(x)\ + FIELD_GET(ANA_ACL_VCAP_S2_CFG_SEC_TYPE_IP6_STD_ENA, x) + +#define ANA_ACL_VCAP_S2_CFG_SEC_TYPE_IP6_TCPUDP_ENA GENMASK(19, 18) +#define ANA_ACL_VCAP_S2_CFG_SEC_TYPE_IP6_TCPUDP_ENA_SET(x)\ + FIELD_PREP(ANA_ACL_VCAP_S2_CFG_SEC_TYPE_IP6_TCPUDP_ENA, x) +#define ANA_ACL_VCAP_S2_CFG_SEC_TYPE_IP6_TCPUDP_ENA_GET(x)\ + FIELD_GET(ANA_ACL_VCAP_S2_CFG_SEC_TYPE_IP6_TCPUDP_ENA, x) + +#define ANA_ACL_VCAP_S2_CFG_SEC_TYPE_IP_7TUPLE_ENA GENMASK(17, 16) +#define ANA_ACL_VCAP_S2_CFG_SEC_TYPE_IP_7TUPLE_ENA_SET(x)\ + FIELD_PREP(ANA_ACL_VCAP_S2_CFG_SEC_TYPE_IP_7TUPLE_ENA, x) +#define ANA_ACL_VCAP_S2_CFG_SEC_TYPE_IP_7TUPLE_ENA_GET(x)\ + FIELD_GET(ANA_ACL_VCAP_S2_CFG_SEC_TYPE_IP_7TUPLE_ENA, x) + +#define ANA_ACL_VCAP_S2_CFG_SEC_TYPE_IP4_VID_ENA GENMASK(15, 14) +#define ANA_ACL_VCAP_S2_CFG_SEC_TYPE_IP4_VID_ENA_SET(x)\ + FIELD_PREP(ANA_ACL_VCAP_S2_CFG_SEC_TYPE_IP4_VID_ENA, x) +#define ANA_ACL_VCAP_S2_CFG_SEC_TYPE_IP4_VID_ENA_GET(x)\ + FIELD_GET(ANA_ACL_VCAP_S2_CFG_SEC_TYPE_IP4_VID_ENA, x) + +#define ANA_ACL_VCAP_S2_CFG_SEC_TYPE_IP4_TCPUDP_ENA GENMASK(13, 12) +#define ANA_ACL_VCAP_S2_CFG_SEC_TYPE_IP4_TCPUDP_ENA_SET(x)\ + FIELD_PREP(ANA_ACL_VCAP_S2_CFG_SEC_TYPE_IP4_TCPUDP_ENA, x) +#define ANA_ACL_VCAP_S2_CFG_SEC_TYPE_IP4_TCPUDP_ENA_GET(x)\ + FIELD_GET(ANA_ACL_VCAP_S2_CFG_SEC_TYPE_IP4_TCPUDP_ENA, x) + +#define ANA_ACL_VCAP_S2_CFG_SEC_TYPE_IP4_OTHER_ENA GENMASK(11, 10) +#define ANA_ACL_VCAP_S2_CFG_SEC_TYPE_IP4_OTHER_ENA_SET(x)\ + FIELD_PREP(ANA_ACL_VCAP_S2_CFG_SEC_TYPE_IP4_OTHER_ENA, x) +#define ANA_ACL_VCAP_S2_CFG_SEC_TYPE_IP4_OTHER_ENA_GET(x)\ + FIELD_GET(ANA_ACL_VCAP_S2_CFG_SEC_TYPE_IP4_OTHER_ENA, x) + +#define ANA_ACL_VCAP_S2_CFG_SEC_TYPE_ARP_ENA GENMASK(9, 8) +#define ANA_ACL_VCAP_S2_CFG_SEC_TYPE_ARP_ENA_SET(x)\ + FIELD_PREP(ANA_ACL_VCAP_S2_CFG_SEC_TYPE_ARP_ENA, x) +#define ANA_ACL_VCAP_S2_CFG_SEC_TYPE_ARP_ENA_GET(x)\ + FIELD_GET(ANA_ACL_VCAP_S2_CFG_SEC_TYPE_ARP_ENA, x) + +#define ANA_ACL_VCAP_S2_CFG_SEC_TYPE_MAC_SNAP_ENA GENMASK(7, 6) +#define ANA_ACL_VCAP_S2_CFG_SEC_TYPE_MAC_SNAP_ENA_SET(x)\ + FIELD_PREP(ANA_ACL_VCAP_S2_CFG_SEC_TYPE_MAC_SNAP_ENA, x) +#define ANA_ACL_VCAP_S2_CFG_SEC_TYPE_MAC_SNAP_ENA_GET(x)\ + FIELD_GET(ANA_ACL_VCAP_S2_CFG_SEC_TYPE_MAC_SNAP_ENA, x) + +#define ANA_ACL_VCAP_S2_CFG_SEC_TYPE_MAC_LLC_ENA GENMASK(5, 4) +#define ANA_ACL_VCAP_S2_CFG_SEC_TYPE_MAC_LLC_ENA_SET(x)\ + FIELD_PREP(ANA_ACL_VCAP_S2_CFG_SEC_TYPE_MAC_LLC_ENA, x) +#define ANA_ACL_VCAP_S2_CFG_SEC_TYPE_MAC_LLC_ENA_GET(x)\ + FIELD_GET(ANA_ACL_VCAP_S2_CFG_SEC_TYPE_MAC_LLC_ENA, x) + +#define ANA_ACL_VCAP_S2_CFG_SEC_ENA GENMASK(3, 0) +#define ANA_ACL_VCAP_S2_CFG_SEC_ENA_SET(x)\ + FIELD_PREP(ANA_ACL_VCAP_S2_CFG_SEC_ENA, x) +#define ANA_ACL_VCAP_S2_CFG_SEC_ENA_GET(x)\ + FIELD_GET(ANA_ACL_VCAP_S2_CFG_SEC_ENA, x) + +/* ANA_ACL:COMMON:SWAP_IP_CTRL */ +#define ANA_ACL_SWAP_IP_CTRL __REG(TARGET_ANA_ACL, 0, 1, 32768, 0, 1, 592, 412, 0, 1, 4) + +#define ANA_ACL_SWAP_IP_CTRL_DMAC_REPL_OFFSET_VAL GENMASK(23, 18) +#define ANA_ACL_SWAP_IP_CTRL_DMAC_REPL_OFFSET_VAL_SET(x)\ + FIELD_PREP(ANA_ACL_SWAP_IP_CTRL_DMAC_REPL_OFFSET_VAL, x) +#define ANA_ACL_SWAP_IP_CTRL_DMAC_REPL_OFFSET_VAL_GET(x)\ + FIELD_GET(ANA_ACL_SWAP_IP_CTRL_DMAC_REPL_OFFSET_VAL, x) + +#define ANA_ACL_SWAP_IP_CTRL_IP_SWAP_IP6_HOPC_VAL GENMASK(17, 10) +#define ANA_ACL_SWAP_IP_CTRL_IP_SWAP_IP6_HOPC_VAL_SET(x)\ + FIELD_PREP(ANA_ACL_SWAP_IP_CTRL_IP_SWAP_IP6_HOPC_VAL, x) +#define ANA_ACL_SWAP_IP_CTRL_IP_SWAP_IP6_HOPC_VAL_GET(x)\ + FIELD_GET(ANA_ACL_SWAP_IP_CTRL_IP_SWAP_IP6_HOPC_VAL, x) + +#define ANA_ACL_SWAP_IP_CTRL_IP_SWAP_IP4_TTL_VAL GENMASK(9, 2) +#define ANA_ACL_SWAP_IP_CTRL_IP_SWAP_IP4_TTL_VAL_SET(x)\ + FIELD_PREP(ANA_ACL_SWAP_IP_CTRL_IP_SWAP_IP4_TTL_VAL, x) +#define ANA_ACL_SWAP_IP_CTRL_IP_SWAP_IP4_TTL_VAL_GET(x)\ + FIELD_GET(ANA_ACL_SWAP_IP_CTRL_IP_SWAP_IP4_TTL_VAL, x) + +#define ANA_ACL_SWAP_IP_CTRL_IP_SWAP_IP6_HOPC_ENA BIT(1) +#define ANA_ACL_SWAP_IP_CTRL_IP_SWAP_IP6_HOPC_ENA_SET(x)\ + FIELD_PREP(ANA_ACL_SWAP_IP_CTRL_IP_SWAP_IP6_HOPC_ENA, x) +#define ANA_ACL_SWAP_IP_CTRL_IP_SWAP_IP6_HOPC_ENA_GET(x)\ + FIELD_GET(ANA_ACL_SWAP_IP_CTRL_IP_SWAP_IP6_HOPC_ENA, x) + +#define ANA_ACL_SWAP_IP_CTRL_IP_SWAP_IP4_TTL_ENA BIT(0) +#define ANA_ACL_SWAP_IP_CTRL_IP_SWAP_IP4_TTL_ENA_SET(x)\ + FIELD_PREP(ANA_ACL_SWAP_IP_CTRL_IP_SWAP_IP4_TTL_ENA, x) +#define ANA_ACL_SWAP_IP_CTRL_IP_SWAP_IP4_TTL_ENA_GET(x)\ + FIELD_GET(ANA_ACL_SWAP_IP_CTRL_IP_SWAP_IP4_TTL_ENA, x) + +/* ANA_ACL:COMMON:VCAP_S2_RLEG_STAT */ +#define ANA_ACL_VCAP_S2_RLEG_STAT(r) __REG(TARGET_ANA_ACL, 0, 1, 32768, 0, 1, 592, 424, r, 4, 4) + +#define ANA_ACL_VCAP_S2_RLEG_STAT_IRLEG_STAT_MASK GENMASK(12, 6) +#define ANA_ACL_VCAP_S2_RLEG_STAT_IRLEG_STAT_MASK_SET(x)\ + FIELD_PREP(ANA_ACL_VCAP_S2_RLEG_STAT_IRLEG_STAT_MASK, x) +#define ANA_ACL_VCAP_S2_RLEG_STAT_IRLEG_STAT_MASK_GET(x)\ + FIELD_GET(ANA_ACL_VCAP_S2_RLEG_STAT_IRLEG_STAT_MASK, x) + +#define ANA_ACL_VCAP_S2_RLEG_STAT_ERLEG_STAT_MASK GENMASK(5, 0) +#define ANA_ACL_VCAP_S2_RLEG_STAT_ERLEG_STAT_MASK_SET(x)\ + FIELD_PREP(ANA_ACL_VCAP_S2_RLEG_STAT_ERLEG_STAT_MASK, x) +#define ANA_ACL_VCAP_S2_RLEG_STAT_ERLEG_STAT_MASK_GET(x)\ + FIELD_GET(ANA_ACL_VCAP_S2_RLEG_STAT_ERLEG_STAT_MASK, x) + +/* ANA_ACL:COMMON:VCAP_S2_FRAGMENT_CFG */ +#define ANA_ACL_VCAP_S2_FRAGMENT_CFG __REG(TARGET_ANA_ACL, 0, 1, 32768, 0, 1, 592, 440, 0, 1, 4) + +#define ANA_ACL_VCAP_S2_FRAGMENT_CFG_L4_MIN_LEN GENMASK(9, 5) +#define ANA_ACL_VCAP_S2_FRAGMENT_CFG_L4_MIN_LEN_SET(x)\ + FIELD_PREP(ANA_ACL_VCAP_S2_FRAGMENT_CFG_L4_MIN_LEN, x) +#define ANA_ACL_VCAP_S2_FRAGMENT_CFG_L4_MIN_LEN_GET(x)\ + FIELD_GET(ANA_ACL_VCAP_S2_FRAGMENT_CFG_L4_MIN_LEN, x) + +#define ANA_ACL_VCAP_S2_FRAGMENT_CFG_FRAGMENT_OFFSET_THRES_DIS BIT(4) +#define ANA_ACL_VCAP_S2_FRAGMENT_CFG_FRAGMENT_OFFSET_THRES_DIS_SET(x)\ + FIELD_PREP(ANA_ACL_VCAP_S2_FRAGMENT_CFG_FRAGMENT_OFFSET_THRES_DIS, x) +#define ANA_ACL_VCAP_S2_FRAGMENT_CFG_FRAGMENT_OFFSET_THRES_DIS_GET(x)\ + FIELD_GET(ANA_ACL_VCAP_S2_FRAGMENT_CFG_FRAGMENT_OFFSET_THRES_DIS, x) + +#define ANA_ACL_VCAP_S2_FRAGMENT_CFG_FRAGMENT_OFFSET_THRES GENMASK(3, 0) +#define ANA_ACL_VCAP_S2_FRAGMENT_CFG_FRAGMENT_OFFSET_THRES_SET(x)\ + FIELD_PREP(ANA_ACL_VCAP_S2_FRAGMENT_CFG_FRAGMENT_OFFSET_THRES, x) +#define ANA_ACL_VCAP_S2_FRAGMENT_CFG_FRAGMENT_OFFSET_THRES_GET(x)\ + FIELD_GET(ANA_ACL_VCAP_S2_FRAGMENT_CFG_FRAGMENT_OFFSET_THRES, x) + /* ANA_ACL:COMMON:OWN_UPSID */ #define ANA_ACL_OWN_UPSID(r) __REG(TARGET_ANA_ACL, 0, 1, 32768, 0, 1, 592, 580, r, 3, 4) @@ -180,6 +336,174 @@ enum sparx5_target { #define ANA_ACL_OWN_UPSID_OWN_UPSID_GET(x)\ FIELD_GET(ANA_ACL_OWN_UPSID_OWN_UPSID, x) +/* ANA_ACL:KEY_SEL:VCAP_S2_KEY_SEL */ +#define ANA_ACL_VCAP_S2_KEY_SEL(g, r) __REG(TARGET_ANA_ACL, 0, 1, 34200, g, 134, 16, 0, r, 4, 4) + +#define ANA_ACL_VCAP_S2_KEY_SEL_KEY_SEL_ENA BIT(13) +#define ANA_ACL_VCAP_S2_KEY_SEL_KEY_SEL_ENA_SET(x)\ + FIELD_PREP(ANA_ACL_VCAP_S2_KEY_SEL_KEY_SEL_ENA, x) +#define ANA_ACL_VCAP_S2_KEY_SEL_KEY_SEL_ENA_GET(x)\ + FIELD_GET(ANA_ACL_VCAP_S2_KEY_SEL_KEY_SEL_ENA, x) + +#define ANA_ACL_VCAP_S2_KEY_SEL_IGR_PORT_MASK_SEL BIT(12) +#define ANA_ACL_VCAP_S2_KEY_SEL_IGR_PORT_MASK_SEL_SET(x)\ + FIELD_PREP(ANA_ACL_VCAP_S2_KEY_SEL_IGR_PORT_MASK_SEL, x) +#define ANA_ACL_VCAP_S2_KEY_SEL_IGR_PORT_MASK_SEL_GET(x)\ + FIELD_GET(ANA_ACL_VCAP_S2_KEY_SEL_IGR_PORT_MASK_SEL, x) + +#define ANA_ACL_VCAP_S2_KEY_SEL_NON_ETH_KEY_SEL GENMASK(11, 10) +#define ANA_ACL_VCAP_S2_KEY_SEL_NON_ETH_KEY_SEL_SET(x)\ + FIELD_PREP(ANA_ACL_VCAP_S2_KEY_SEL_NON_ETH_KEY_SEL, x) +#define ANA_ACL_VCAP_S2_KEY_SEL_NON_ETH_KEY_SEL_GET(x)\ + FIELD_GET(ANA_ACL_VCAP_S2_KEY_SEL_NON_ETH_KEY_SEL, x) + +#define ANA_ACL_VCAP_S2_KEY_SEL_IP4_MC_KEY_SEL GENMASK(9, 8) +#define ANA_ACL_VCAP_S2_KEY_SEL_IP4_MC_KEY_SEL_SET(x)\ + FIELD_PREP(ANA_ACL_VCAP_S2_KEY_SEL_IP4_MC_KEY_SEL, x) +#define ANA_ACL_VCAP_S2_KEY_SEL_IP4_MC_KEY_SEL_GET(x)\ + FIELD_GET(ANA_ACL_VCAP_S2_KEY_SEL_IP4_MC_KEY_SEL, x) + +#define ANA_ACL_VCAP_S2_KEY_SEL_IP4_UC_KEY_SEL GENMASK(7, 6) +#define ANA_ACL_VCAP_S2_KEY_SEL_IP4_UC_KEY_SEL_SET(x)\ + FIELD_PREP(ANA_ACL_VCAP_S2_KEY_SEL_IP4_UC_KEY_SEL, x) +#define ANA_ACL_VCAP_S2_KEY_SEL_IP4_UC_KEY_SEL_GET(x)\ + FIELD_GET(ANA_ACL_VCAP_S2_KEY_SEL_IP4_UC_KEY_SEL, x) + +#define ANA_ACL_VCAP_S2_KEY_SEL_IP6_MC_KEY_SEL GENMASK(5, 3) +#define ANA_ACL_VCAP_S2_KEY_SEL_IP6_MC_KEY_SEL_SET(x)\ + FIELD_PREP(ANA_ACL_VCAP_S2_KEY_SEL_IP6_MC_KEY_SEL, x) +#define ANA_ACL_VCAP_S2_KEY_SEL_IP6_MC_KEY_SEL_GET(x)\ + FIELD_GET(ANA_ACL_VCAP_S2_KEY_SEL_IP6_MC_KEY_SEL, x) + +#define ANA_ACL_VCAP_S2_KEY_SEL_IP6_UC_KEY_SEL GENMASK(2, 1) +#define ANA_ACL_VCAP_S2_KEY_SEL_IP6_UC_KEY_SEL_SET(x)\ + FIELD_PREP(ANA_ACL_VCAP_S2_KEY_SEL_IP6_UC_KEY_SEL, x) +#define ANA_ACL_VCAP_S2_KEY_SEL_IP6_UC_KEY_SEL_GET(x)\ + FIELD_GET(ANA_ACL_VCAP_S2_KEY_SEL_IP6_UC_KEY_SEL, x) + +#define ANA_ACL_VCAP_S2_KEY_SEL_ARP_KEY_SEL BIT(0) +#define ANA_ACL_VCAP_S2_KEY_SEL_ARP_KEY_SEL_SET(x)\ + FIELD_PREP(ANA_ACL_VCAP_S2_KEY_SEL_ARP_KEY_SEL, x) +#define ANA_ACL_VCAP_S2_KEY_SEL_ARP_KEY_SEL_GET(x)\ + FIELD_GET(ANA_ACL_VCAP_S2_KEY_SEL_ARP_KEY_SEL, x) + +/* ANA_ACL:CNT_A:CNT_A */ +#define ANA_ACL_CNT_A(g) __REG(TARGET_ANA_ACL, 0, 1, 0, g, 4096, 4, 0, 0, 1, 4) + +/* ANA_ACL:CNT_B:CNT_B */ +#define ANA_ACL_CNT_B(g) __REG(TARGET_ANA_ACL, 0, 1, 16384, g, 4096, 4, 0, 0, 1, 4) + +/* ANA_ACL:STICKY:SEC_LOOKUP_STICKY */ +#define ANA_ACL_SEC_LOOKUP_STICKY(r) __REG(TARGET_ANA_ACL, 0, 1, 36408, 0, 1, 16, 0, r, 4, 4) + +#define ANA_ACL_SEC_LOOKUP_STICKY_KEY_SEL_CLM_STICKY BIT(17) +#define ANA_ACL_SEC_LOOKUP_STICKY_KEY_SEL_CLM_STICKY_SET(x)\ + FIELD_PREP(ANA_ACL_SEC_LOOKUP_STICKY_KEY_SEL_CLM_STICKY, x) +#define ANA_ACL_SEC_LOOKUP_STICKY_KEY_SEL_CLM_STICKY_GET(x)\ + FIELD_GET(ANA_ACL_SEC_LOOKUP_STICKY_KEY_SEL_CLM_STICKY, x) + +#define ANA_ACL_SEC_LOOKUP_STICKY_KEY_SEL_IRLEG_STICKY BIT(16) +#define ANA_ACL_SEC_LOOKUP_STICKY_KEY_SEL_IRLEG_STICKY_SET(x)\ + FIELD_PREP(ANA_ACL_SEC_LOOKUP_STICKY_KEY_SEL_IRLEG_STICKY, x) +#define ANA_ACL_SEC_LOOKUP_STICKY_KEY_SEL_IRLEG_STICKY_GET(x)\ + FIELD_GET(ANA_ACL_SEC_LOOKUP_STICKY_KEY_SEL_IRLEG_STICKY, x) + +#define ANA_ACL_SEC_LOOKUP_STICKY_KEY_SEL_ERLEG_STICKY BIT(15) +#define ANA_ACL_SEC_LOOKUP_STICKY_KEY_SEL_ERLEG_STICKY_SET(x)\ + FIELD_PREP(ANA_ACL_SEC_LOOKUP_STICKY_KEY_SEL_ERLEG_STICKY, x) +#define ANA_ACL_SEC_LOOKUP_STICKY_KEY_SEL_ERLEG_STICKY_GET(x)\ + FIELD_GET(ANA_ACL_SEC_LOOKUP_STICKY_KEY_SEL_ERLEG_STICKY, x) + +#define ANA_ACL_SEC_LOOKUP_STICKY_KEY_SEL_PORT_STICKY BIT(14) +#define ANA_ACL_SEC_LOOKUP_STICKY_KEY_SEL_PORT_STICKY_SET(x)\ + FIELD_PREP(ANA_ACL_SEC_LOOKUP_STICKY_KEY_SEL_PORT_STICKY, x) +#define ANA_ACL_SEC_LOOKUP_STICKY_KEY_SEL_PORT_STICKY_GET(x)\ + FIELD_GET(ANA_ACL_SEC_LOOKUP_STICKY_KEY_SEL_PORT_STICKY, x) + +#define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_CUSTOM2_STICKY BIT(13) +#define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_CUSTOM2_STICKY_SET(x)\ + FIELD_PREP(ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_CUSTOM2_STICKY, x) +#define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_CUSTOM2_STICKY_GET(x)\ + FIELD_GET(ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_CUSTOM2_STICKY, x) + +#define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_CUSTOM1_STICKY BIT(12) +#define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_CUSTOM1_STICKY_SET(x)\ + FIELD_PREP(ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_CUSTOM1_STICKY, x) +#define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_CUSTOM1_STICKY_GET(x)\ + FIELD_GET(ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_CUSTOM1_STICKY, x) + +#define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_OAM_STICKY BIT(11) +#define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_OAM_STICKY_SET(x)\ + FIELD_PREP(ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_OAM_STICKY, x) +#define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_OAM_STICKY_GET(x)\ + FIELD_GET(ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_OAM_STICKY, x) + +#define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP6_VID_STICKY BIT(10) +#define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP6_VID_STICKY_SET(x)\ + FIELD_PREP(ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP6_VID_STICKY, x) +#define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP6_VID_STICKY_GET(x)\ + FIELD_GET(ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP6_VID_STICKY, x) + +#define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP6_STD_STICKY BIT(9) +#define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP6_STD_STICKY_SET(x)\ + FIELD_PREP(ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP6_STD_STICKY, x) +#define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP6_STD_STICKY_GET(x)\ + FIELD_GET(ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP6_STD_STICKY, x) + +#define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP6_TCPUDP_STICKY BIT(8) +#define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP6_TCPUDP_STICKY_SET(x)\ + FIELD_PREP(ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP6_TCPUDP_STICKY, x) +#define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP6_TCPUDP_STICKY_GET(x)\ + FIELD_GET(ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP6_TCPUDP_STICKY, x) + +#define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP_7TUPLE_STICKY BIT(7) +#define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP_7TUPLE_STICKY_SET(x)\ + FIELD_PREP(ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP_7TUPLE_STICKY, x) +#define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP_7TUPLE_STICKY_GET(x)\ + FIELD_GET(ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP_7TUPLE_STICKY, x) + +#define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP4_VID_STICKY BIT(6) +#define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP4_VID_STICKY_SET(x)\ + FIELD_PREP(ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP4_VID_STICKY, x) +#define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP4_VID_STICKY_GET(x)\ + FIELD_GET(ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP4_VID_STICKY, x) + +#define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP4_TCPUDP_STICKY BIT(5) +#define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP4_TCPUDP_STICKY_SET(x)\ + FIELD_PREP(ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP4_TCPUDP_STICKY, x) +#define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP4_TCPUDP_STICKY_GET(x)\ + FIELD_GET(ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP4_TCPUDP_STICKY, x) + +#define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP4_OTHER_STICKY BIT(4) +#define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP4_OTHER_STICKY_SET(x)\ + FIELD_PREP(ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP4_OTHER_STICKY, x) +#define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP4_OTHER_STICKY_GET(x)\ + FIELD_GET(ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP4_OTHER_STICKY, x) + +#define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_ARP_STICKY BIT(3) +#define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_ARP_STICKY_SET(x)\ + FIELD_PREP(ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_ARP_STICKY, x) +#define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_ARP_STICKY_GET(x)\ + FIELD_GET(ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_ARP_STICKY, x) + +#define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_MAC_SNAP_STICKY BIT(2) +#define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_MAC_SNAP_STICKY_SET(x)\ + FIELD_PREP(ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_MAC_SNAP_STICKY, x) +#define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_MAC_SNAP_STICKY_GET(x)\ + FIELD_GET(ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_MAC_SNAP_STICKY, x) + +#define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_MAC_LLC_STICKY BIT(1) +#define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_MAC_LLC_STICKY_SET(x)\ + FIELD_PREP(ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_MAC_LLC_STICKY, x) +#define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_MAC_LLC_STICKY_GET(x)\ + FIELD_GET(ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_MAC_LLC_STICKY, x) + +#define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_MAC_ETYPE_STICKY BIT(0) +#define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_MAC_ETYPE_STICKY_SET(x)\ + FIELD_PREP(ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_MAC_ETYPE_STICKY, x) +#define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_MAC_ETYPE_STICKY_GET(x)\ + FIELD_GET(ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_MAC_ETYPE_STICKY, x) + /* ANA_AC_POL:POL_ALL_CFG:POL_UPD_INT_CFG */ #define ANA_AC_POL_POL_UPD_INT_CFG __REG(TARGET_ANA_AC_POL, 0, 1, 75968, 0, 1, 1160, 1148, 0, 1, 4) @@ -5039,6 +5363,138 @@ enum sparx5_target { #define REW_RAM_INIT_RAM_CFG_HOOK_GET(x)\ FIELD_GET(REW_RAM_INIT_RAM_CFG_HOOK, x) +/* VCAP_SUPER:VCAP_CORE_CFG:VCAP_UPDATE_CTRL */ +#define VCAP_SUPER_CTRL __REG(TARGET_VCAP_SUPER, 0, 1, 0, 0, 1, 8, 0, 0, 1, 4) + +#define VCAP_SUPER_CTRL_UPDATE_CMD GENMASK(24, 22) +#define VCAP_SUPER_CTRL_UPDATE_CMD_SET(x)\ + FIELD_PREP(VCAP_SUPER_CTRL_UPDATE_CMD, x) +#define VCAP_SUPER_CTRL_UPDATE_CMD_GET(x)\ + FIELD_GET(VCAP_SUPER_CTRL_UPDATE_CMD, x) + +#define VCAP_SUPER_CTRL_UPDATE_ENTRY_DIS BIT(21) +#define VCAP_SUPER_CTRL_UPDATE_ENTRY_DIS_SET(x)\ + FIELD_PREP(VCAP_SUPER_CTRL_UPDATE_ENTRY_DIS, x) +#define VCAP_SUPER_CTRL_UPDATE_ENTRY_DIS_GET(x)\ + FIELD_GET(VCAP_SUPER_CTRL_UPDATE_ENTRY_DIS, x) + +#define VCAP_SUPER_CTRL_UPDATE_ACTION_DIS BIT(20) +#define VCAP_SUPER_CTRL_UPDATE_ACTION_DIS_SET(x)\ + FIELD_PREP(VCAP_SUPER_CTRL_UPDATE_ACTION_DIS, x) +#define VCAP_SUPER_CTRL_UPDATE_ACTION_DIS_GET(x)\ + FIELD_GET(VCAP_SUPER_CTRL_UPDATE_ACTION_DIS, x) + +#define VCAP_SUPER_CTRL_UPDATE_CNT_DIS BIT(19) +#define VCAP_SUPER_CTRL_UPDATE_CNT_DIS_SET(x)\ + FIELD_PREP(VCAP_SUPER_CTRL_UPDATE_CNT_DIS, x) +#define VCAP_SUPER_CTRL_UPDATE_CNT_DIS_GET(x)\ + FIELD_GET(VCAP_SUPER_CTRL_UPDATE_CNT_DIS, x) + +#define VCAP_SUPER_CTRL_UPDATE_ADDR GENMASK(18, 3) +#define VCAP_SUPER_CTRL_UPDATE_ADDR_SET(x)\ + FIELD_PREP(VCAP_SUPER_CTRL_UPDATE_ADDR, x) +#define VCAP_SUPER_CTRL_UPDATE_ADDR_GET(x)\ + FIELD_GET(VCAP_SUPER_CTRL_UPDATE_ADDR, x) + +#define VCAP_SUPER_CTRL_UPDATE_SHOT BIT(2) +#define VCAP_SUPER_CTRL_UPDATE_SHOT_SET(x)\ + FIELD_PREP(VCAP_SUPER_CTRL_UPDATE_SHOT, x) +#define VCAP_SUPER_CTRL_UPDATE_SHOT_GET(x)\ + FIELD_GET(VCAP_SUPER_CTRL_UPDATE_SHOT, x) + +#define VCAP_SUPER_CTRL_CLEAR_CACHE BIT(1) +#define VCAP_SUPER_CTRL_CLEAR_CACHE_SET(x)\ + FIELD_PREP(VCAP_SUPER_CTRL_CLEAR_CACHE, x) +#define VCAP_SUPER_CTRL_CLEAR_CACHE_GET(x)\ + FIELD_GET(VCAP_SUPER_CTRL_CLEAR_CACHE, x) + +#define VCAP_SUPER_CTRL_MV_TRAFFIC_IGN BIT(0) +#define VCAP_SUPER_CTRL_MV_TRAFFIC_IGN_SET(x)\ + FIELD_PREP(VCAP_SUPER_CTRL_MV_TRAFFIC_IGN, x) +#define VCAP_SUPER_CTRL_MV_TRAFFIC_IGN_GET(x)\ + FIELD_GET(VCAP_SUPER_CTRL_MV_TRAFFIC_IGN, x) + +/* VCAP_SUPER:VCAP_CORE_CFG:VCAP_MV_CFG */ +#define VCAP_SUPER_CFG __REG(TARGET_VCAP_SUPER, 0, 1, 0, 0, 1, 8, 4, 0, 1, 4) + +#define VCAP_SUPER_CFG_MV_NUM_POS GENMASK(31, 16) +#define VCAP_SUPER_CFG_MV_NUM_POS_SET(x)\ + FIELD_PREP(VCAP_SUPER_CFG_MV_NUM_POS, x) +#define VCAP_SUPER_CFG_MV_NUM_POS_GET(x)\ + FIELD_GET(VCAP_SUPER_CFG_MV_NUM_POS, x) + +#define VCAP_SUPER_CFG_MV_SIZE GENMASK(15, 0) +#define VCAP_SUPER_CFG_MV_SIZE_SET(x)\ + FIELD_PREP(VCAP_SUPER_CFG_MV_SIZE, x) +#define VCAP_SUPER_CFG_MV_SIZE_GET(x)\ + FIELD_GET(VCAP_SUPER_CFG_MV_SIZE, x) + +/* VCAP_SUPER:VCAP_CORE_CACHE:VCAP_ENTRY_DAT */ +#define VCAP_SUPER_VCAP_ENTRY_DAT(r) __REG(TARGET_VCAP_SUPER, 0, 1, 8, 0, 1, 904, 0, r, 64, 4) + +/* VCAP_SUPER:VCAP_CORE_CACHE:VCAP_MASK_DAT */ +#define VCAP_SUPER_VCAP_MASK_DAT(r) __REG(TARGET_VCAP_SUPER, 0, 1, 8, 0, 1, 904, 256, r, 64, 4) + +/* VCAP_SUPER:VCAP_CORE_CACHE:VCAP_ACTION_DAT */ +#define VCAP_SUPER_VCAP_ACTION_DAT(r) __REG(TARGET_VCAP_SUPER, 0, 1, 8, 0, 1, 904, 512, r, 64, 4) + +/* VCAP_SUPER:VCAP_CORE_CACHE:VCAP_CNT_DAT */ +#define VCAP_SUPER_VCAP_CNT_DAT(r) __REG(TARGET_VCAP_SUPER, 0, 1, 8, 0, 1, 904, 768, r, 32, 4) + +/* VCAP_SUPER:VCAP_CORE_CACHE:VCAP_CNT_FW_DAT */ +#define VCAP_SUPER_VCAP_CNT_FW_DAT __REG(TARGET_VCAP_SUPER, 0, 1, 8, 0, 1, 904, 896, 0, 1, 4) + +/* VCAP_SUPER:VCAP_CORE_CACHE:VCAP_TG_DAT */ +#define VCAP_SUPER_VCAP_TG_DAT __REG(TARGET_VCAP_SUPER, 0, 1, 8, 0, 1, 904, 900, 0, 1, 4) + +/* VCAP_SUPER:VCAP_CORE_MAP:VCAP_CORE_IDX */ +#define VCAP_SUPER_IDX __REG(TARGET_VCAP_SUPER, 0, 1, 912, 0, 1, 8, 0, 0, 1, 4) + +#define VCAP_SUPER_IDX_CORE_IDX GENMASK(3, 0) +#define VCAP_SUPER_IDX_CORE_IDX_SET(x)\ + FIELD_PREP(VCAP_SUPER_IDX_CORE_IDX, x) +#define VCAP_SUPER_IDX_CORE_IDX_GET(x)\ + FIELD_GET(VCAP_SUPER_IDX_CORE_IDX, x) + +/* VCAP_SUPER:VCAP_CORE_MAP:VCAP_CORE_MAP */ +#define VCAP_SUPER_MAP __REG(TARGET_VCAP_SUPER, 0, 1, 912, 0, 1, 8, 4, 0, 1, 4) + +#define VCAP_SUPER_MAP_CORE_MAP GENMASK(2, 0) +#define VCAP_SUPER_MAP_CORE_MAP_SET(x)\ + FIELD_PREP(VCAP_SUPER_MAP_CORE_MAP, x) +#define VCAP_SUPER_MAP_CORE_MAP_GET(x)\ + FIELD_GET(VCAP_SUPER_MAP_CORE_MAP, x) + +/* VCAP_SUPER:VCAP_CONST:VCAP_VER */ +#define VCAP_SUPER_VCAP_VER __REG(TARGET_VCAP_SUPER, 0, 1, 924, 0, 1, 40, 0, 0, 1, 4) + +/* VCAP_SUPER:VCAP_CONST:ENTRY_WIDTH */ +#define VCAP_SUPER_ENTRY_WIDTH __REG(TARGET_VCAP_SUPER, 0, 1, 924, 0, 1, 40, 4, 0, 1, 4) + +/* VCAP_SUPER:VCAP_CONST:ENTRY_CNT */ +#define VCAP_SUPER_ENTRY_CNT __REG(TARGET_VCAP_SUPER, 0, 1, 924, 0, 1, 40, 8, 0, 1, 4) + +/* VCAP_SUPER:VCAP_CONST:ENTRY_SWCNT */ +#define VCAP_SUPER_ENTRY_SWCNT __REG(TARGET_VCAP_SUPER, 0, 1, 924, 0, 1, 40, 12, 0, 1, 4) + +/* VCAP_SUPER:VCAP_CONST:ENTRY_TG_WIDTH */ +#define VCAP_SUPER_ENTRY_TG_WIDTH __REG(TARGET_VCAP_SUPER, 0, 1, 924, 0, 1, 40, 16, 0, 1, 4) + +/* VCAP_SUPER:VCAP_CONST:ACTION_DEF_CNT */ +#define VCAP_SUPER_ACTION_DEF_CNT __REG(TARGET_VCAP_SUPER, 0, 1, 924, 0, 1, 40, 20, 0, 1, 4) + +/* VCAP_SUPER:VCAP_CONST:ACTION_WIDTH */ +#define VCAP_SUPER_ACTION_WIDTH __REG(TARGET_VCAP_SUPER, 0, 1, 924, 0, 1, 40, 24, 0, 1, 4) + +/* VCAP_SUPER:VCAP_CONST:CNT_WIDTH */ +#define VCAP_SUPER_CNT_WIDTH __REG(TARGET_VCAP_SUPER, 0, 1, 924, 0, 1, 40, 28, 0, 1, 4) + +/* VCAP_SUPER:VCAP_CONST:CORE_CNT */ +#define VCAP_SUPER_CORE_CNT __REG(TARGET_VCAP_SUPER, 0, 1, 924, 0, 1, 40, 32, 0, 1, 4) + +/* VCAP_SUPER:VCAP_CONST:IF_CNT */ +#define VCAP_SUPER_IF_CNT __REG(TARGET_VCAP_SUPER, 0, 1, 924, 0, 1, 40, 36, 0, 1, 4) + /* VCAP_SUPER:RAM_CTRL:RAM_INIT */ #define VCAP_SUPER_RAM_INIT __REG(TARGET_VCAP_SUPER, 0, 1, 1120, 0, 1, 4, 0, 0, 1, 4) diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_tc.c b/drivers/net/ethernet/microchip/sparx5/sparx5_tc.c index e05429c751ee..9432251b8322 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_tc.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_tc.c @@ -10,6 +10,50 @@ #include "sparx5_main.h" #include "sparx5_qos.h" +/* tc block handling */ +static LIST_HEAD(sparx5_block_cb_list); + +static int sparx5_tc_block_cb(enum tc_setup_type type, + void *type_data, + void *cb_priv, bool ingress) +{ + struct net_device *ndev = cb_priv; + + if (type == TC_SETUP_CLSFLOWER) + return sparx5_tc_flower(ndev, type_data, ingress); + return -EOPNOTSUPP; +} + +static int sparx5_tc_block_cb_ingress(enum tc_setup_type type, + void *type_data, + void *cb_priv) +{ + return sparx5_tc_block_cb(type, type_data, cb_priv, true); +} + +static int sparx5_tc_block_cb_egress(enum tc_setup_type type, + void *type_data, + void *cb_priv) +{ + return sparx5_tc_block_cb(type, type_data, cb_priv, false); +} + +static int sparx5_tc_setup_block(struct net_device *ndev, + struct flow_block_offload *fbo) +{ + flow_setup_cb_t *cb; + + if (fbo->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS) + cb = sparx5_tc_block_cb_ingress; + else if (fbo->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS) + cb = sparx5_tc_block_cb_egress; + else + return -EOPNOTSUPP; + + return flow_block_cb_setup_simple(fbo, &sparx5_block_cb_list, + cb, ndev, ndev, false); +} + static void sparx5_tc_get_layer_and_idx(u32 parent, u32 portno, u32 *layer, u32 *idx) { @@ -111,6 +155,8 @@ int sparx5_port_setup_tc(struct net_device *ndev, enum tc_setup_type type, void *type_data) { switch (type) { + case TC_SETUP_BLOCK: + return sparx5_tc_setup_block(ndev, type_data); case TC_SETUP_QDISC_MQPRIO: return sparx5_tc_setup_qdisc_mqprio(ndev, type_data); case TC_SETUP_QDISC_TBF: diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_tc.h b/drivers/net/ethernet/microchip/sparx5/sparx5_tc.h index 5b55e11b77e1..2b07a93fc9b7 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_tc.h +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_tc.h @@ -7,9 +7,23 @@ #ifndef __SPARX5_TC_H__ #define __SPARX5_TC_H__ +#include <net/flow_offload.h> #include <linux/netdevice.h> +/* Controls how PORT_MASK is applied */ +enum SPX5_PORT_MASK_MODE { + SPX5_PMM_OR_DSTMASK, + SPX5_PMM_AND_VLANMASK, + SPX5_PMM_REPLACE_PGID, + SPX5_PMM_REPLACE_ALL, + SPX5_PMM_REDIR_PGID, + SPX5_PMM_OR_PGID_MASK, +}; + int sparx5_port_setup_tc(struct net_device *ndev, enum tc_setup_type type, void *type_data); +int sparx5_tc_flower(struct net_device *ndev, struct flow_cls_offload *fco, + bool ingress); + #endif /* __SPARX5_TC_H__ */ diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_tc_flower.c b/drivers/net/ethernet/microchip/sparx5/sparx5_tc_flower.c new file mode 100644 index 000000000000..626558a5c850 --- /dev/null +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_tc_flower.c @@ -0,0 +1,217 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Microchip VCAP API + * + * Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries. + */ + +#include <net/tcp.h> + +#include "sparx5_tc.h" +#include "vcap_api.h" +#include "vcap_api_client.h" +#include "sparx5_main.h" +#include "sparx5_vcap_impl.h" + +struct sparx5_tc_flower_parse_usage { + struct flow_cls_offload *fco; + struct flow_rule *frule; + struct vcap_rule *vrule; + unsigned int used_keys; +}; + +static int sparx5_tc_flower_handler_ethaddr_usage(struct sparx5_tc_flower_parse_usage *st) +{ + enum vcap_key_field smac_key = VCAP_KF_L2_SMAC; + enum vcap_key_field dmac_key = VCAP_KF_L2_DMAC; + struct flow_match_eth_addrs match; + struct vcap_u48_key smac, dmac; + int err = 0; + + flow_rule_match_eth_addrs(st->frule, &match); + + if (!is_zero_ether_addr(match.mask->src)) { + vcap_netbytes_copy(smac.value, match.key->src, ETH_ALEN); + vcap_netbytes_copy(smac.mask, match.mask->src, ETH_ALEN); + err = vcap_rule_add_key_u48(st->vrule, smac_key, &smac); + if (err) + goto out; + } + + if (!is_zero_ether_addr(match.mask->dst)) { + vcap_netbytes_copy(dmac.value, match.key->dst, ETH_ALEN); + vcap_netbytes_copy(dmac.mask, match.mask->dst, ETH_ALEN); + err = vcap_rule_add_key_u48(st->vrule, dmac_key, &dmac); + if (err) + goto out; + } + + st->used_keys |= BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS); + + return err; + +out: + NL_SET_ERR_MSG_MOD(st->fco->common.extack, "eth_addr parse error"); + return err; +} + +static int (*sparx5_tc_flower_usage_handlers[])(struct sparx5_tc_flower_parse_usage *st) = { + /* More dissector handlers will be added here later */ + [FLOW_DISSECTOR_KEY_ETH_ADDRS] = sparx5_tc_flower_handler_ethaddr_usage, +}; + +static int sparx5_tc_use_dissectors(struct flow_cls_offload *fco, + struct vcap_admin *admin, + struct vcap_rule *vrule) +{ + struct sparx5_tc_flower_parse_usage state = { + .fco = fco, + .vrule = vrule, + }; + int idx, err = 0; + + state.frule = flow_cls_offload_flow_rule(fco); + for (idx = 0; idx < ARRAY_SIZE(sparx5_tc_flower_usage_handlers); ++idx) { + if (!flow_rule_match_key(state.frule, idx)) + continue; + if (!sparx5_tc_flower_usage_handlers[idx]) + continue; + err = sparx5_tc_flower_usage_handlers[idx](&state); + if (err) + return err; + } + return err; +} + +static int sparx5_tc_flower_replace(struct net_device *ndev, + struct flow_cls_offload *fco, + struct vcap_admin *admin) +{ + struct sparx5_port *port = netdev_priv(ndev); + struct flow_action_entry *act; + struct vcap_control *vctrl; + struct flow_rule *frule; + struct vcap_rule *vrule; + int err, idx; + + frule = flow_cls_offload_flow_rule(fco); + if (!flow_action_has_entries(&frule->action)) { + NL_SET_ERR_MSG_MOD(fco->common.extack, "No actions"); + return -EINVAL; + } + + if (!flow_action_basic_hw_stats_check(&frule->action, fco->common.extack)) + return -EOPNOTSUPP; + + vctrl = port->sparx5->vcap_ctrl; + vrule = vcap_alloc_rule(vctrl, ndev, fco->common.chain_index, VCAP_USER_TC, + fco->common.prio, 0); + if (IS_ERR(vrule)) + return PTR_ERR(vrule); + + vrule->cookie = fco->cookie; + sparx5_tc_use_dissectors(fco, admin, vrule); + flow_action_for_each(idx, act, &frule->action) { + switch (act->id) { + case FLOW_ACTION_TRAP: + err = vcap_rule_add_action_bit(vrule, + VCAP_AF_CPU_COPY_ENA, + VCAP_BIT_1); + if (err) + goto out; + err = vcap_rule_add_action_u32(vrule, + VCAP_AF_CPU_QUEUE_NUM, 0); + if (err) + goto out; + err = vcap_rule_add_action_u32(vrule, VCAP_AF_MASK_MODE, + SPX5_PMM_REPLACE_ALL); + if (err) + goto out; + /* For now the actionset is hardcoded */ + err = vcap_set_rule_set_actionset(vrule, + VCAP_AFS_BASE_TYPE); + if (err) + goto out; + break; + case FLOW_ACTION_ACCEPT: + /* For now the actionset is hardcoded */ + err = vcap_set_rule_set_actionset(vrule, + VCAP_AFS_BASE_TYPE); + if (err) + goto out; + break; + default: + NL_SET_ERR_MSG_MOD(fco->common.extack, + "Unsupported TC action"); + err = -EOPNOTSUPP; + goto out; + } + } + /* For now the keyset is hardcoded */ + err = vcap_set_rule_set_keyset(vrule, VCAP_KFS_MAC_ETYPE); + if (err) { + NL_SET_ERR_MSG_MOD(fco->common.extack, + "No matching port keyset for filter protocol and keys"); + goto out; + } + err = vcap_val_rule(vrule, ETH_P_ALL); + if (err) { + vcap_set_tc_exterr(fco, vrule); + goto out; + } + err = vcap_add_rule(vrule); + if (err) + NL_SET_ERR_MSG_MOD(fco->common.extack, + "Could not add the filter"); +out: + vcap_free_rule(vrule); + return err; +} + +static int sparx5_tc_flower_destroy(struct net_device *ndev, + struct flow_cls_offload *fco, + struct vcap_admin *admin) +{ + struct sparx5_port *port = netdev_priv(ndev); + struct vcap_control *vctrl; + int err = -ENOENT, rule_id; + + vctrl = port->sparx5->vcap_ctrl; + while (true) { + rule_id = vcap_lookup_rule_by_cookie(vctrl, fco->cookie); + if (rule_id <= 0) + break; + err = vcap_del_rule(vctrl, ndev, rule_id); + if (err) { + pr_err("%s:%d: could not delete rule %d\n", + __func__, __LINE__, rule_id); + break; + } + } + return err; +} + +int sparx5_tc_flower(struct net_device *ndev, struct flow_cls_offload *fco, + bool ingress) +{ + struct sparx5_port *port = netdev_priv(ndev); + struct vcap_control *vctrl; + struct vcap_admin *admin; + int err = -EINVAL; + + /* Get vcap instance from the chain id */ + vctrl = port->sparx5->vcap_ctrl; + admin = vcap_find_admin(vctrl, fco->common.chain_index); + if (!admin) { + NL_SET_ERR_MSG_MOD(fco->common.extack, "Invalid chain"); + return err; + } + + switch (fco->command) { + case FLOW_CLS_REPLACE: + return sparx5_tc_flower_replace(ndev, fco, admin); + case FLOW_CLS_DESTROY: + return sparx5_tc_flower_destroy(ndev, fco, admin); + default: + return -EOPNOTSUPP; + } +} diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_ag_api.c b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_ag_api.c new file mode 100644 index 000000000000..1bd987c664e8 --- /dev/null +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_ag_api.c @@ -0,0 +1,1351 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* Copyright (C) 2022 Microchip Technology Inc. and its subsidiaries. + * Microchip VCAP API + */ + +/* This file is autogenerated by cml-utils 2022-10-13 10:04:41 +0200. + * Commit ID: fd7cafd175899f0672c73afb3a30fc872500ae86 + */ + +#include <linux/types.h> +#include <linux/kernel.h> + +#include "vcap_api.h" +#include "sparx5_vcap_ag_api.h" + +/* keyfields */ +static const struct vcap_field is2_mac_etype_keyfield[] = { + [VCAP_KF_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 0, + .width = 4, + }, + [VCAP_KF_LOOKUP_FIRST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 4, + .width = 1, + }, + [VCAP_KF_LOOKUP_PAG] = { + .type = VCAP_FIELD_U32, + .offset = 5, + .width = 8, + }, + [VCAP_KF_IF_IGR_PORT_MASK_L3] = { + .type = VCAP_FIELD_BIT, + .offset = 13, + .width = 1, + }, + [VCAP_KF_IF_IGR_PORT_MASK_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 14, + .width = 4, + }, + [VCAP_KF_IF_IGR_PORT_MASK_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 18, + .width = 2, + }, + [VCAP_KF_IF_IGR_PORT_MASK] = { + .type = VCAP_FIELD_U32, + .offset = 20, + .width = 32, + }, + [VCAP_KF_L2_MC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 52, + .width = 1, + }, + [VCAP_KF_L2_BC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 53, + .width = 1, + }, + [VCAP_KF_8021Q_VLAN_TAGGED_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 54, + .width = 1, + }, + [VCAP_KF_ISDX_GT0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 55, + .width = 1, + }, + [VCAP_KF_ISDX_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 56, + .width = 12, + }, + [VCAP_KF_8021Q_VID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 68, + .width = 13, + }, + [VCAP_KF_8021Q_DEI_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 81, + .width = 1, + }, + [VCAP_KF_8021Q_PCP_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 82, + .width = 3, + }, + [VCAP_KF_L2_FWD_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 85, + .width = 1, + }, + [VCAP_KF_L3_RT_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 88, + .width = 1, + }, + [VCAP_KF_L3_DST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 89, + .width = 1, + }, + [VCAP_KF_L2_DMAC] = { + .type = VCAP_FIELD_U48, + .offset = 90, + .width = 48, + }, + [VCAP_KF_L2_SMAC] = { + .type = VCAP_FIELD_U48, + .offset = 138, + .width = 48, + }, + [VCAP_KF_ETYPE_LEN_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 186, + .width = 1, + }, + [VCAP_KF_ETYPE] = { + .type = VCAP_FIELD_U32, + .offset = 187, + .width = 16, + }, + [VCAP_KF_L2_PAYLOAD_ETYPE] = { + .type = VCAP_FIELD_U64, + .offset = 203, + .width = 64, + }, + [VCAP_KF_L4_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 267, + .width = 16, + }, + [VCAP_KF_OAM_CCM_CNTS_EQ0] = { + .type = VCAP_FIELD_BIT, + .offset = 283, + .width = 1, + }, + [VCAP_KF_OAM_Y1731_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 284, + .width = 1, + }, +}; + +static const struct vcap_field is2_arp_keyfield[] = { + [VCAP_KF_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 0, + .width = 4, + }, + [VCAP_KF_LOOKUP_FIRST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 4, + .width = 1, + }, + [VCAP_KF_LOOKUP_PAG] = { + .type = VCAP_FIELD_U32, + .offset = 5, + .width = 8, + }, + [VCAP_KF_IF_IGR_PORT_MASK_L3] = { + .type = VCAP_FIELD_BIT, + .offset = 13, + .width = 1, + }, + [VCAP_KF_IF_IGR_PORT_MASK_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 14, + .width = 4, + }, + [VCAP_KF_IF_IGR_PORT_MASK_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 18, + .width = 2, + }, + [VCAP_KF_IF_IGR_PORT_MASK] = { + .type = VCAP_FIELD_U32, + .offset = 20, + .width = 32, + }, + [VCAP_KF_L2_MC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 52, + .width = 1, + }, + [VCAP_KF_L2_BC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 53, + .width = 1, + }, + [VCAP_KF_8021Q_VLAN_TAGGED_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 54, + .width = 1, + }, + [VCAP_KF_ISDX_GT0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 55, + .width = 1, + }, + [VCAP_KF_ISDX_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 56, + .width = 12, + }, + [VCAP_KF_8021Q_VID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 68, + .width = 13, + }, + [VCAP_KF_8021Q_DEI_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 81, + .width = 1, + }, + [VCAP_KF_8021Q_PCP_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 82, + .width = 3, + }, + [VCAP_KF_L2_FWD_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 85, + .width = 1, + }, + [VCAP_KF_L2_SMAC] = { + .type = VCAP_FIELD_U48, + .offset = 86, + .width = 48, + }, + [VCAP_KF_ARP_ADDR_SPACE_OK_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 134, + .width = 1, + }, + [VCAP_KF_ARP_PROTO_SPACE_OK_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 135, + .width = 1, + }, + [VCAP_KF_ARP_LEN_OK_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 136, + .width = 1, + }, + [VCAP_KF_ARP_TGT_MATCH_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 137, + .width = 1, + }, + [VCAP_KF_ARP_SENDER_MATCH_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 138, + .width = 1, + }, + [VCAP_KF_ARP_OPCODE_UNKNOWN_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 139, + .width = 1, + }, + [VCAP_KF_ARP_OPCODE] = { + .type = VCAP_FIELD_U32, + .offset = 140, + .width = 2, + }, + [VCAP_KF_L3_IP4_DIP] = { + .type = VCAP_FIELD_U32, + .offset = 142, + .width = 32, + }, + [VCAP_KF_L3_IP4_SIP] = { + .type = VCAP_FIELD_U32, + .offset = 174, + .width = 32, + }, + [VCAP_KF_L3_DIP_EQ_SIP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 206, + .width = 1, + }, + [VCAP_KF_L4_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 207, + .width = 16, + }, +}; + +static const struct vcap_field is2_ip4_tcp_udp_keyfield[] = { + [VCAP_KF_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 0, + .width = 4, + }, + [VCAP_KF_LOOKUP_FIRST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 4, + .width = 1, + }, + [VCAP_KF_LOOKUP_PAG] = { + .type = VCAP_FIELD_U32, + .offset = 5, + .width = 8, + }, + [VCAP_KF_IF_IGR_PORT_MASK_L3] = { + .type = VCAP_FIELD_BIT, + .offset = 13, + .width = 1, + }, + [VCAP_KF_IF_IGR_PORT_MASK_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 14, + .width = 4, + }, + [VCAP_KF_IF_IGR_PORT_MASK_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 18, + .width = 2, + }, + [VCAP_KF_IF_IGR_PORT_MASK] = { + .type = VCAP_FIELD_U32, + .offset = 20, + .width = 32, + }, + [VCAP_KF_L2_MC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 52, + .width = 1, + }, + [VCAP_KF_L2_BC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 53, + .width = 1, + }, + [VCAP_KF_8021Q_VLAN_TAGGED_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 54, + .width = 1, + }, + [VCAP_KF_ISDX_GT0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 55, + .width = 1, + }, + [VCAP_KF_ISDX_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 56, + .width = 12, + }, + [VCAP_KF_8021Q_VID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 68, + .width = 13, + }, + [VCAP_KF_8021Q_DEI_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 81, + .width = 1, + }, + [VCAP_KF_8021Q_PCP_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 82, + .width = 3, + }, + [VCAP_KF_L2_FWD_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 85, + .width = 1, + }, + [VCAP_KF_L3_RT_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 88, + .width = 1, + }, + [VCAP_KF_L3_DST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 89, + .width = 1, + }, + [VCAP_KF_IP4_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 90, + .width = 1, + }, + [VCAP_KF_L3_FRAGMENT_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 91, + .width = 2, + }, + [VCAP_KF_L3_FRAG_INVLD_L4_LEN] = { + .type = VCAP_FIELD_BIT, + .offset = 93, + .width = 1, + }, + [VCAP_KF_L3_OPTIONS_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 94, + .width = 1, + }, + [VCAP_KF_L3_TTL_GT0] = { + .type = VCAP_FIELD_BIT, + .offset = 95, + .width = 1, + }, + [VCAP_KF_L3_TOS] = { + .type = VCAP_FIELD_U32, + .offset = 96, + .width = 8, + }, + [VCAP_KF_L3_IP4_DIP] = { + .type = VCAP_FIELD_U32, + .offset = 104, + .width = 32, + }, + [VCAP_KF_L3_IP4_SIP] = { + .type = VCAP_FIELD_U32, + .offset = 136, + .width = 32, + }, + [VCAP_KF_L3_DIP_EQ_SIP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 168, + .width = 1, + }, + [VCAP_KF_TCP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 169, + .width = 1, + }, + [VCAP_KF_L4_DPORT] = { + .type = VCAP_FIELD_U32, + .offset = 170, + .width = 16, + }, + [VCAP_KF_L4_SPORT] = { + .type = VCAP_FIELD_U32, + .offset = 186, + .width = 16, + }, + [VCAP_KF_L4_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 202, + .width = 16, + }, + [VCAP_KF_L4_SPORT_EQ_DPORT_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 218, + .width = 1, + }, + [VCAP_KF_L4_SEQUENCE_EQ0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 219, + .width = 1, + }, + [VCAP_KF_L4_FIN] = { + .type = VCAP_FIELD_BIT, + .offset = 220, + .width = 1, + }, + [VCAP_KF_L4_SYN] = { + .type = VCAP_FIELD_BIT, + .offset = 221, + .width = 1, + }, + [VCAP_KF_L4_RST] = { + .type = VCAP_FIELD_BIT, + .offset = 222, + .width = 1, + }, + [VCAP_KF_L4_PSH] = { + .type = VCAP_FIELD_BIT, + .offset = 223, + .width = 1, + }, + [VCAP_KF_L4_ACK] = { + .type = VCAP_FIELD_BIT, + .offset = 224, + .width = 1, + }, + [VCAP_KF_L4_URG] = { + .type = VCAP_FIELD_BIT, + .offset = 225, + .width = 1, + }, + [VCAP_KF_L4_PAYLOAD] = { + .type = VCAP_FIELD_U64, + .offset = 226, + .width = 64, + }, +}; + +static const struct vcap_field is2_ip4_other_keyfield[] = { + [VCAP_KF_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 0, + .width = 4, + }, + [VCAP_KF_LOOKUP_FIRST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 4, + .width = 1, + }, + [VCAP_KF_LOOKUP_PAG] = { + .type = VCAP_FIELD_U32, + .offset = 5, + .width = 8, + }, + [VCAP_KF_IF_IGR_PORT_MASK_L3] = { + .type = VCAP_FIELD_BIT, + .offset = 13, + .width = 1, + }, + [VCAP_KF_IF_IGR_PORT_MASK_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 14, + .width = 4, + }, + [VCAP_KF_IF_IGR_PORT_MASK_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 18, + .width = 2, + }, + [VCAP_KF_IF_IGR_PORT_MASK] = { + .type = VCAP_FIELD_U32, + .offset = 20, + .width = 32, + }, + [VCAP_KF_L2_MC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 52, + .width = 1, + }, + [VCAP_KF_L2_BC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 53, + .width = 1, + }, + [VCAP_KF_8021Q_VLAN_TAGGED_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 54, + .width = 1, + }, + [VCAP_KF_ISDX_GT0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 55, + .width = 1, + }, + [VCAP_KF_ISDX_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 56, + .width = 12, + }, + [VCAP_KF_8021Q_VID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 68, + .width = 13, + }, + [VCAP_KF_8021Q_DEI_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 81, + .width = 1, + }, + [VCAP_KF_8021Q_PCP_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 82, + .width = 3, + }, + [VCAP_KF_L2_FWD_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 85, + .width = 1, + }, + [VCAP_KF_L3_RT_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 88, + .width = 1, + }, + [VCAP_KF_L3_DST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 89, + .width = 1, + }, + [VCAP_KF_IP4_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 90, + .width = 1, + }, + [VCAP_KF_L3_FRAGMENT_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 91, + .width = 2, + }, + [VCAP_KF_L3_FRAG_INVLD_L4_LEN] = { + .type = VCAP_FIELD_BIT, + .offset = 93, + .width = 1, + }, + [VCAP_KF_L3_OPTIONS_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 94, + .width = 1, + }, + [VCAP_KF_L3_TTL_GT0] = { + .type = VCAP_FIELD_BIT, + .offset = 95, + .width = 1, + }, + [VCAP_KF_L3_TOS] = { + .type = VCAP_FIELD_U32, + .offset = 96, + .width = 8, + }, + [VCAP_KF_L3_IP4_DIP] = { + .type = VCAP_FIELD_U32, + .offset = 104, + .width = 32, + }, + [VCAP_KF_L3_IP4_SIP] = { + .type = VCAP_FIELD_U32, + .offset = 136, + .width = 32, + }, + [VCAP_KF_L3_DIP_EQ_SIP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 168, + .width = 1, + }, + [VCAP_KF_L3_IP_PROTO] = { + .type = VCAP_FIELD_U32, + .offset = 169, + .width = 8, + }, + [VCAP_KF_L4_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 177, + .width = 16, + }, + [VCAP_KF_L3_PAYLOAD] = { + .type = VCAP_FIELD_U112, + .offset = 193, + .width = 96, + }, +}; + +static const struct vcap_field is2_ip6_std_keyfield[] = { + [VCAP_KF_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 0, + .width = 4, + }, + [VCAP_KF_LOOKUP_FIRST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 4, + .width = 1, + }, + [VCAP_KF_LOOKUP_PAG] = { + .type = VCAP_FIELD_U32, + .offset = 5, + .width = 8, + }, + [VCAP_KF_IF_IGR_PORT_MASK_L3] = { + .type = VCAP_FIELD_BIT, + .offset = 13, + .width = 1, + }, + [VCAP_KF_IF_IGR_PORT_MASK_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 14, + .width = 4, + }, + [VCAP_KF_IF_IGR_PORT_MASK_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 18, + .width = 2, + }, + [VCAP_KF_IF_IGR_PORT_MASK] = { + .type = VCAP_FIELD_U32, + .offset = 20, + .width = 32, + }, + [VCAP_KF_L2_MC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 52, + .width = 1, + }, + [VCAP_KF_L2_BC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 53, + .width = 1, + }, + [VCAP_KF_8021Q_VLAN_TAGGED_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 54, + .width = 1, + }, + [VCAP_KF_ISDX_GT0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 55, + .width = 1, + }, + [VCAP_KF_ISDX_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 56, + .width = 12, + }, + [VCAP_KF_8021Q_VID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 68, + .width = 13, + }, + [VCAP_KF_8021Q_DEI_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 81, + .width = 1, + }, + [VCAP_KF_8021Q_PCP_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 82, + .width = 3, + }, + [VCAP_KF_L2_FWD_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 85, + .width = 1, + }, + [VCAP_KF_L3_RT_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 88, + .width = 1, + }, + [VCAP_KF_L3_TTL_GT0] = { + .type = VCAP_FIELD_BIT, + .offset = 90, + .width = 1, + }, + [VCAP_KF_L3_IP6_SIP] = { + .type = VCAP_FIELD_U128, + .offset = 91, + .width = 128, + }, + [VCAP_KF_L3_DIP_EQ_SIP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 219, + .width = 1, + }, + [VCAP_KF_L3_IP_PROTO] = { + .type = VCAP_FIELD_U32, + .offset = 220, + .width = 8, + }, + [VCAP_KF_L4_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 228, + .width = 16, + }, + [VCAP_KF_L3_PAYLOAD] = { + .type = VCAP_FIELD_U48, + .offset = 244, + .width = 40, + }, +}; + +static const struct vcap_field is2_ip_7tuple_keyfield[] = { + [VCAP_KF_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 0, + .width = 2, + }, + [VCAP_KF_LOOKUP_FIRST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 2, + .width = 1, + }, + [VCAP_KF_LOOKUP_PAG] = { + .type = VCAP_FIELD_U32, + .offset = 3, + .width = 8, + }, + [VCAP_KF_IF_IGR_PORT_MASK_L3] = { + .type = VCAP_FIELD_BIT, + .offset = 11, + .width = 1, + }, + [VCAP_KF_IF_IGR_PORT_MASK_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 12, + .width = 4, + }, + [VCAP_KF_IF_IGR_PORT_MASK_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 16, + .width = 2, + }, + [VCAP_KF_IF_IGR_PORT_MASK] = { + .type = VCAP_FIELD_U72, + .offset = 18, + .width = 65, + }, + [VCAP_KF_L2_MC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 83, + .width = 1, + }, + [VCAP_KF_L2_BC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 84, + .width = 1, + }, + [VCAP_KF_8021Q_VLAN_TAGGED_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 85, + .width = 1, + }, + [VCAP_KF_ISDX_GT0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 86, + .width = 1, + }, + [VCAP_KF_ISDX_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 87, + .width = 12, + }, + [VCAP_KF_8021Q_VID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 99, + .width = 13, + }, + [VCAP_KF_8021Q_DEI_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 112, + .width = 1, + }, + [VCAP_KF_8021Q_PCP_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 113, + .width = 3, + }, + [VCAP_KF_L2_FWD_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 116, + .width = 1, + }, + [VCAP_KF_L3_RT_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 119, + .width = 1, + }, + [VCAP_KF_L3_DST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 120, + .width = 1, + }, + [VCAP_KF_L2_DMAC] = { + .type = VCAP_FIELD_U48, + .offset = 121, + .width = 48, + }, + [VCAP_KF_L2_SMAC] = { + .type = VCAP_FIELD_U48, + .offset = 169, + .width = 48, + }, + [VCAP_KF_IP4_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 217, + .width = 1, + }, + [VCAP_KF_L3_TTL_GT0] = { + .type = VCAP_FIELD_BIT, + .offset = 218, + .width = 1, + }, + [VCAP_KF_L3_TOS] = { + .type = VCAP_FIELD_U32, + .offset = 219, + .width = 8, + }, + [VCAP_KF_L3_IP6_DIP] = { + .type = VCAP_FIELD_U128, + .offset = 227, + .width = 128, + }, + [VCAP_KF_L3_IP6_SIP] = { + .type = VCAP_FIELD_U128, + .offset = 355, + .width = 128, + }, + [VCAP_KF_L3_DIP_EQ_SIP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 483, + .width = 1, + }, + [VCAP_KF_TCP_UDP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 484, + .width = 1, + }, + [VCAP_KF_TCP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 485, + .width = 1, + }, + [VCAP_KF_L4_DPORT] = { + .type = VCAP_FIELD_U32, + .offset = 486, + .width = 16, + }, + [VCAP_KF_L4_SPORT] = { + .type = VCAP_FIELD_U32, + .offset = 502, + .width = 16, + }, + [VCAP_KF_L4_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 518, + .width = 16, + }, + [VCAP_KF_L4_SPORT_EQ_DPORT_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 534, + .width = 1, + }, + [VCAP_KF_L4_SEQUENCE_EQ0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 535, + .width = 1, + }, + [VCAP_KF_L4_FIN] = { + .type = VCAP_FIELD_BIT, + .offset = 536, + .width = 1, + }, + [VCAP_KF_L4_SYN] = { + .type = VCAP_FIELD_BIT, + .offset = 537, + .width = 1, + }, + [VCAP_KF_L4_RST] = { + .type = VCAP_FIELD_BIT, + .offset = 538, + .width = 1, + }, + [VCAP_KF_L4_PSH] = { + .type = VCAP_FIELD_BIT, + .offset = 539, + .width = 1, + }, + [VCAP_KF_L4_ACK] = { + .type = VCAP_FIELD_BIT, + .offset = 540, + .width = 1, + }, + [VCAP_KF_L4_URG] = { + .type = VCAP_FIELD_BIT, + .offset = 541, + .width = 1, + }, + [VCAP_KF_L4_PAYLOAD] = { + .type = VCAP_FIELD_U64, + .offset = 542, + .width = 64, + }, +}; + +/* keyfield_set */ +static const struct vcap_set is2_keyfield_set[] = { + [VCAP_KFS_MAC_ETYPE] = { + .type_id = 0, + .sw_per_item = 6, + .sw_cnt = 2, + }, + [VCAP_KFS_ARP] = { + .type_id = 3, + .sw_per_item = 6, + .sw_cnt = 2, + }, + [VCAP_KFS_IP4_TCP_UDP] = { + .type_id = 4, + .sw_per_item = 6, + .sw_cnt = 2, + }, + [VCAP_KFS_IP4_OTHER] = { + .type_id = 5, + .sw_per_item = 6, + .sw_cnt = 2, + }, + [VCAP_KFS_IP6_STD] = { + .type_id = 6, + .sw_per_item = 6, + .sw_cnt = 2, + }, + [VCAP_KFS_IP_7TUPLE] = { + .type_id = 1, + .sw_per_item = 12, + .sw_cnt = 1, + }, +}; + +/* keyfield_set map */ +static const struct vcap_field *is2_keyfield_set_map[] = { + [VCAP_KFS_MAC_ETYPE] = is2_mac_etype_keyfield, + [VCAP_KFS_ARP] = is2_arp_keyfield, + [VCAP_KFS_IP4_TCP_UDP] = is2_ip4_tcp_udp_keyfield, + [VCAP_KFS_IP4_OTHER] = is2_ip4_other_keyfield, + [VCAP_KFS_IP6_STD] = is2_ip6_std_keyfield, + [VCAP_KFS_IP_7TUPLE] = is2_ip_7tuple_keyfield, +}; + +/* keyfield_set map sizes */ +static int is2_keyfield_set_map_size[] = { + [VCAP_KFS_MAC_ETYPE] = ARRAY_SIZE(is2_mac_etype_keyfield), + [VCAP_KFS_ARP] = ARRAY_SIZE(is2_arp_keyfield), + [VCAP_KFS_IP4_TCP_UDP] = ARRAY_SIZE(is2_ip4_tcp_udp_keyfield), + [VCAP_KFS_IP4_OTHER] = ARRAY_SIZE(is2_ip4_other_keyfield), + [VCAP_KFS_IP6_STD] = ARRAY_SIZE(is2_ip6_std_keyfield), + [VCAP_KFS_IP_7TUPLE] = ARRAY_SIZE(is2_ip_7tuple_keyfield), +}; + +/* actionfields */ +static const struct vcap_field is2_base_type_actionfield[] = { + [VCAP_AF_PIPELINE_FORCE_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 1, + .width = 1, + }, + [VCAP_AF_PIPELINE_PT] = { + .type = VCAP_FIELD_U32, + .offset = 2, + .width = 5, + }, + [VCAP_AF_HIT_ME_ONCE] = { + .type = VCAP_FIELD_BIT, + .offset = 7, + .width = 1, + }, + [VCAP_AF_INTR_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 8, + .width = 1, + }, + [VCAP_AF_CPU_COPY_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 9, + .width = 1, + }, + [VCAP_AF_CPU_QUEUE_NUM] = { + .type = VCAP_FIELD_U32, + .offset = 10, + .width = 3, + }, + [VCAP_AF_LRN_DIS] = { + .type = VCAP_FIELD_BIT, + .offset = 14, + .width = 1, + }, + [VCAP_AF_RT_DIS] = { + .type = VCAP_FIELD_BIT, + .offset = 15, + .width = 1, + }, + [VCAP_AF_POLICE_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 16, + .width = 1, + }, + [VCAP_AF_POLICE_IDX] = { + .type = VCAP_FIELD_U32, + .offset = 17, + .width = 6, + }, + [VCAP_AF_IGNORE_PIPELINE_CTRL] = { + .type = VCAP_FIELD_BIT, + .offset = 23, + .width = 1, + }, + [VCAP_AF_MASK_MODE] = { + .type = VCAP_FIELD_U32, + .offset = 27, + .width = 3, + }, + [VCAP_AF_PORT_MASK] = { + .type = VCAP_FIELD_U72, + .offset = 30, + .width = 68, + }, + [VCAP_AF_MIRROR_PROBE] = { + .type = VCAP_FIELD_U32, + .offset = 111, + .width = 2, + }, + [VCAP_AF_MATCH_ID] = { + .type = VCAP_FIELD_U32, + .offset = 159, + .width = 16, + }, + [VCAP_AF_MATCH_ID_MASK] = { + .type = VCAP_FIELD_U32, + .offset = 175, + .width = 16, + }, + [VCAP_AF_CNT_ID] = { + .type = VCAP_FIELD_U32, + .offset = 191, + .width = 12, + }, +}; + +/* actionfield_set */ +static const struct vcap_set is2_actionfield_set[] = { + [VCAP_AFS_BASE_TYPE] = { + .type_id = -1, + .sw_per_item = 3, + .sw_cnt = 4, + }, +}; + +/* actionfield_set map */ +static const struct vcap_field *is2_actionfield_set_map[] = { + [VCAP_AFS_BASE_TYPE] = is2_base_type_actionfield, +}; + +/* actionfield_set map size */ +static int is2_actionfield_set_map_size[] = { + [VCAP_AFS_BASE_TYPE] = ARRAY_SIZE(is2_base_type_actionfield), +}; + +/* Type Groups */ +static const struct vcap_typegroup is2_x12_keyfield_set_typegroups[] = { + { + .offset = 0, + .width = 3, + .value = 4, + }, + { + .offset = 156, + .width = 1, + .value = 0, + }, + { + .offset = 312, + .width = 2, + .value = 0, + }, + { + .offset = 468, + .width = 1, + .value = 0, + }, + {} +}; + +static const struct vcap_typegroup is2_x6_keyfield_set_typegroups[] = { + { + .offset = 0, + .width = 2, + .value = 2, + }, + { + .offset = 156, + .width = 1, + .value = 0, + }, + {} +}; + +static const struct vcap_typegroup is2_x3_keyfield_set_typegroups[] = { + {} +}; + +static const struct vcap_typegroup is2_x1_keyfield_set_typegroups[] = { + {} +}; + +static const struct vcap_typegroup *is2_keyfield_set_typegroups[] = { + [12] = is2_x12_keyfield_set_typegroups, + [6] = is2_x6_keyfield_set_typegroups, + [3] = is2_x3_keyfield_set_typegroups, + [1] = is2_x1_keyfield_set_typegroups, + [13] = NULL, +}; + +static const struct vcap_typegroup is2_x3_actionfield_set_typegroups[] = { + { + .offset = 0, + .width = 2, + .value = 2, + }, + { + .offset = 110, + .width = 1, + .value = 0, + }, + { + .offset = 220, + .width = 1, + .value = 0, + }, + {} +}; + +static const struct vcap_typegroup is2_x1_actionfield_set_typegroups[] = { + {} +}; + +static const struct vcap_typegroup *is2_actionfield_set_typegroups[] = { + [3] = is2_x3_actionfield_set_typegroups, + [1] = is2_x1_actionfield_set_typegroups, + [13] = NULL, +}; + +/* Keyfieldset names */ +static const char * const vcap_keyfield_set_names[] = { + [VCAP_KFS_NO_VALUE] = "(None)", + [VCAP_KFS_ARP] = "VCAP_KFS_ARP", + [VCAP_KFS_IP4_OTHER] = "VCAP_KFS_IP4_OTHER", + [VCAP_KFS_IP4_TCP_UDP] = "VCAP_KFS_IP4_TCP_UDP", + [VCAP_KFS_IP6_STD] = "VCAP_KFS_IP6_STD", + [VCAP_KFS_IP_7TUPLE] = "VCAP_KFS_IP_7TUPLE", + [VCAP_KFS_MAC_ETYPE] = "VCAP_KFS_MAC_ETYPE", +}; + +/* Actionfieldset names */ +static const char * const vcap_actionfield_set_names[] = { + [VCAP_AFS_NO_VALUE] = "(None)", + [VCAP_AFS_BASE_TYPE] = "VCAP_AFS_BASE_TYPE", +}; + +/* Keyfield names */ +static const char * const vcap_keyfield_names[] = { + [VCAP_KF_NO_VALUE] = "(None)", + [VCAP_KF_8021Q_DEI_CLS] = "8021Q_DEI_CLS", + [VCAP_KF_8021Q_PCP_CLS] = "8021Q_PCP_CLS", + [VCAP_KF_8021Q_VID_CLS] = "8021Q_VID_CLS", + [VCAP_KF_8021Q_VLAN_TAGGED_IS] = "8021Q_VLAN_TAGGED_IS", + [VCAP_KF_ARP_ADDR_SPACE_OK_IS] = "ARP_ADDR_SPACE_OK_IS", + [VCAP_KF_ARP_LEN_OK_IS] = "ARP_LEN_OK_IS", + [VCAP_KF_ARP_OPCODE] = "ARP_OPCODE", + [VCAP_KF_ARP_OPCODE_UNKNOWN_IS] = "ARP_OPCODE_UNKNOWN_IS", + [VCAP_KF_ARP_PROTO_SPACE_OK_IS] = "ARP_PROTO_SPACE_OK_IS", + [VCAP_KF_ARP_SENDER_MATCH_IS] = "ARP_SENDER_MATCH_IS", + [VCAP_KF_ARP_TGT_MATCH_IS] = "ARP_TGT_MATCH_IS", + [VCAP_KF_ETYPE] = "ETYPE", + [VCAP_KF_ETYPE_LEN_IS] = "ETYPE_LEN_IS", + [VCAP_KF_IF_IGR_PORT_MASK] = "IF_IGR_PORT_MASK", + [VCAP_KF_IF_IGR_PORT_MASK_L3] = "IF_IGR_PORT_MASK_L3", + [VCAP_KF_IF_IGR_PORT_MASK_RNG] = "IF_IGR_PORT_MASK_RNG", + [VCAP_KF_IF_IGR_PORT_MASK_SEL] = "IF_IGR_PORT_MASK_SEL", + [VCAP_KF_IP4_IS] = "IP4_IS", + [VCAP_KF_ISDX_CLS] = "ISDX_CLS", + [VCAP_KF_ISDX_GT0_IS] = "ISDX_GT0_IS", + [VCAP_KF_L2_BC_IS] = "L2_BC_IS", + [VCAP_KF_L2_DMAC] = "L2_DMAC", + [VCAP_KF_L2_FWD_IS] = "L2_FWD_IS", + [VCAP_KF_L2_MC_IS] = "L2_MC_IS", + [VCAP_KF_L2_PAYLOAD_ETYPE] = "L2_PAYLOAD_ETYPE", + [VCAP_KF_L2_SMAC] = "L2_SMAC", + [VCAP_KF_L3_DIP_EQ_SIP_IS] = "L3_DIP_EQ_SIP_IS", + [VCAP_KF_L3_DST_IS] = "L3_DST_IS", + [VCAP_KF_L3_FRAGMENT_TYPE] = "L3_FRAGMENT_TYPE", + [VCAP_KF_L3_FRAG_INVLD_L4_LEN] = "L3_FRAG_INVLD_L4_LEN", + [VCAP_KF_L3_IP4_DIP] = "L3_IP4_DIP", + [VCAP_KF_L3_IP4_SIP] = "L3_IP4_SIP", + [VCAP_KF_L3_IP6_DIP] = "L3_IP6_DIP", + [VCAP_KF_L3_IP6_SIP] = "L3_IP6_SIP", + [VCAP_KF_L3_IP_PROTO] = "L3_IP_PROTO", + [VCAP_KF_L3_OPTIONS_IS] = "L3_OPTIONS_IS", + [VCAP_KF_L3_PAYLOAD] = "L3_PAYLOAD", + [VCAP_KF_L3_RT_IS] = "L3_RT_IS", + [VCAP_KF_L3_TOS] = "L3_TOS", + [VCAP_KF_L3_TTL_GT0] = "L3_TTL_GT0", + [VCAP_KF_L4_ACK] = "L4_ACK", + [VCAP_KF_L4_DPORT] = "L4_DPORT", + [VCAP_KF_L4_FIN] = "L4_FIN", + [VCAP_KF_L4_PAYLOAD] = "L4_PAYLOAD", + [VCAP_KF_L4_PSH] = "L4_PSH", + [VCAP_KF_L4_RNG] = "L4_RNG", + [VCAP_KF_L4_RST] = "L4_RST", + [VCAP_KF_L4_SEQUENCE_EQ0_IS] = "L4_SEQUENCE_EQ0_IS", + [VCAP_KF_L4_SPORT] = "L4_SPORT", + [VCAP_KF_L4_SPORT_EQ_DPORT_IS] = "L4_SPORT_EQ_DPORT_IS", + [VCAP_KF_L4_SYN] = "L4_SYN", + [VCAP_KF_L4_URG] = "L4_URG", + [VCAP_KF_LOOKUP_FIRST_IS] = "LOOKUP_FIRST_IS", + [VCAP_KF_LOOKUP_PAG] = "LOOKUP_PAG", + [VCAP_KF_OAM_CCM_CNTS_EQ0] = "OAM_CCM_CNTS_EQ0", + [VCAP_KF_OAM_Y1731_IS] = "OAM_Y1731_IS", + [VCAP_KF_TCP_IS] = "TCP_IS", + [VCAP_KF_TCP_UDP_IS] = "TCP_UDP_IS", + [VCAP_KF_TYPE] = "TYPE", +}; + +/* Actionfield names */ +static const char * const vcap_actionfield_names[] = { + [VCAP_AF_NO_VALUE] = "(None)", + [VCAP_AF_CNT_ID] = "CNT_ID", + [VCAP_AF_CPU_COPY_ENA] = "CPU_COPY_ENA", + [VCAP_AF_CPU_QUEUE_NUM] = "CPU_QUEUE_NUM", + [VCAP_AF_HIT_ME_ONCE] = "HIT_ME_ONCE", + [VCAP_AF_IGNORE_PIPELINE_CTRL] = "IGNORE_PIPELINE_CTRL", + [VCAP_AF_INTR_ENA] = "INTR_ENA", + [VCAP_AF_LRN_DIS] = "LRN_DIS", + [VCAP_AF_MASK_MODE] = "MASK_MODE", + [VCAP_AF_MATCH_ID] = "MATCH_ID", + [VCAP_AF_MATCH_ID_MASK] = "MATCH_ID_MASK", + [VCAP_AF_MIRROR_PROBE] = "MIRROR_PROBE", + [VCAP_AF_PIPELINE_FORCE_ENA] = "PIPELINE_FORCE_ENA", + [VCAP_AF_PIPELINE_PT] = "PIPELINE_PT", + [VCAP_AF_POLICE_ENA] = "POLICE_ENA", + [VCAP_AF_POLICE_IDX] = "POLICE_IDX", + [VCAP_AF_PORT_MASK] = "PORT_MASK", + [VCAP_AF_RT_DIS] = "RT_DIS", +}; + +/* VCAPs */ +const struct vcap_info sparx5_vcaps[] = { + [VCAP_TYPE_IS2] = { + .name = "is2", + .rows = 256, + .sw_count = 12, + .sw_width = 52, + .sticky_width = 1, + .act_width = 110, + .default_cnt = 73, + .require_cnt_dis = 0, + .version = 1, + .keyfield_set = is2_keyfield_set, + .keyfield_set_size = ARRAY_SIZE(is2_keyfield_set), + .actionfield_set = is2_actionfield_set, + .actionfield_set_size = ARRAY_SIZE(is2_actionfield_set), + .keyfield_set_map = is2_keyfield_set_map, + .keyfield_set_map_size = is2_keyfield_set_map_size, + .actionfield_set_map = is2_actionfield_set_map, + .actionfield_set_map_size = is2_actionfield_set_map_size, + .keyfield_set_typegroups = is2_keyfield_set_typegroups, + .actionfield_set_typegroups = is2_actionfield_set_typegroups, + }, +}; + +const struct vcap_statistics sparx5_vcap_stats = { + .name = "sparx5", + .count = 1, + .keyfield_set_names = vcap_keyfield_set_names, + .actionfield_set_names = vcap_actionfield_set_names, + .keyfield_names = vcap_keyfield_names, + .actionfield_names = vcap_actionfield_names, +}; diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_ag_api.h b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_ag_api.h new file mode 100644 index 000000000000..7d106f1276fe --- /dev/null +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_ag_api.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* Copyright (C) 2022 Microchip Technology Inc. and its subsidiaries. + * Microchip VCAP API + */ + +/* This file is autogenerated by cml-utils 2022-10-13 10:04:41 +0200. + * Commit ID: fd7cafd175899f0672c73afb3a30fc872500ae86 + */ + +#ifndef __SPARX5_VCAP_AG_API_H__ +#define __SPARX5_VCAP_AG_API_H__ + +/* VCAPs */ +extern const struct vcap_info sparx5_vcaps[]; +extern const struct vcap_statistics sparx5_vcap_stats; + +#endif /* __SPARX5_VCAP_AG_API_H__ */ + diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c new file mode 100644 index 000000000000..50153264179e --- /dev/null +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c @@ -0,0 +1,527 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Microchip Sparx5 Switch driver VCAP implementation + * + * Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries. + * + * The Sparx5 Chip Register Model can be browsed at this location: + * https://github.com/microchip-ung/sparx-5_reginfo + */ + +#include <linux/types.h> +#include <linux/list.h> + +#include "vcap_api.h" +#include "vcap_api_client.h" +#include "sparx5_main_regs.h" +#include "sparx5_main.h" +#include "sparx5_vcap_impl.h" +#include "sparx5_vcap_ag_api.h" + +#define SUPER_VCAP_BLK_SIZE 3072 /* addresses per Super VCAP block */ +#define STREAMSIZE (64 * 4) /* bytes in the VCAP cache area */ + +#define SPARX5_IS2_LOOKUPS 4 + +/* IS2 port keyset selection control */ + +/* IS2 non-ethernet traffic type keyset generation */ +enum vcap_is2_port_sel_noneth { + VCAP_IS2_PS_NONETH_MAC_ETYPE, + VCAP_IS2_PS_NONETH_CUSTOM_1, + VCAP_IS2_PS_NONETH_CUSTOM_2, + VCAP_IS2_PS_NONETH_NO_LOOKUP +}; + +/* IS2 IPv4 unicast traffic type keyset generation */ +enum vcap_is2_port_sel_ipv4_uc { + VCAP_IS2_PS_IPV4_UC_MAC_ETYPE, + VCAP_IS2_PS_IPV4_UC_IP4_TCP_UDP_OTHER, + VCAP_IS2_PS_IPV4_UC_IP_7TUPLE, +}; + +/* IS2 IPv4 multicast traffic type keyset generation */ +enum vcap_is2_port_sel_ipv4_mc { + VCAP_IS2_PS_IPV4_MC_MAC_ETYPE, + VCAP_IS2_PS_IPV4_MC_IP4_TCP_UDP_OTHER, + VCAP_IS2_PS_IPV4_MC_IP_7TUPLE, + VCAP_IS2_PS_IPV4_MC_IP4_VID, +}; + +/* IS2 IPv6 unicast traffic type keyset generation */ +enum vcap_is2_port_sel_ipv6_uc { + VCAP_IS2_PS_IPV6_UC_MAC_ETYPE, + VCAP_IS2_PS_IPV6_UC_IP_7TUPLE, + VCAP_IS2_PS_IPV6_UC_IP6_STD, + VCAP_IS2_PS_IPV6_UC_IP4_TCP_UDP_OTHER, +}; + +/* IS2 IPv6 multicast traffic type keyset generation */ +enum vcap_is2_port_sel_ipv6_mc { + VCAP_IS2_PS_IPV6_MC_MAC_ETYPE, + VCAP_IS2_PS_IPV6_MC_IP_7TUPLE, + VCAP_IS2_PS_IPV6_MC_IP6_VID, + VCAP_IS2_PS_IPV6_MC_IP6_STD, + VCAP_IS2_PS_IPV6_MC_IP4_TCP_UDP_OTHER, +}; + +/* IS2 ARP traffic type keyset generation */ +enum vcap_is2_port_sel_arp { + VCAP_IS2_PS_ARP_MAC_ETYPE, + VCAP_IS2_PS_ARP_ARP, +}; + +static struct sparx5_vcap_inst { + enum vcap_type vtype; /* type of vcap */ + int vinst; /* instance number within the same type */ + int lookups; /* number of lookups in this vcap type */ + int lookups_per_instance; /* number of lookups in this instance */ + int first_cid; /* first chain id in this vcap */ + int last_cid; /* last chain id in this vcap */ + int count; /* number of available addresses, not in super vcap */ + int map_id; /* id in the super vcap block mapping (if applicable) */ + int blockno; /* starting block in super vcap (if applicable) */ + int blocks; /* number of blocks in super vcap (if applicable) */ +} sparx5_vcap_inst_cfg[] = { + { + .vtype = VCAP_TYPE_IS2, /* IS2-0 */ + .vinst = 0, + .map_id = 4, + .lookups = SPARX5_IS2_LOOKUPS, + .lookups_per_instance = SPARX5_IS2_LOOKUPS / 2, + .first_cid = SPARX5_VCAP_CID_IS2_L0, + .last_cid = SPARX5_VCAP_CID_IS2_L2 - 1, + .blockno = 0, /* Maps block 0-1 */ + .blocks = 2, + }, + { + .vtype = VCAP_TYPE_IS2, /* IS2-1 */ + .vinst = 1, + .map_id = 5, + .lookups = SPARX5_IS2_LOOKUPS, + .lookups_per_instance = SPARX5_IS2_LOOKUPS / 2, + .first_cid = SPARX5_VCAP_CID_IS2_L2, + .last_cid = SPARX5_VCAP_CID_IS2_MAX, + .blockno = 2, /* Maps block 2-3 */ + .blocks = 2, + }, +}; + +/* Await the super VCAP completion of the current operation */ +static void sparx5_vcap_wait_super_update(struct sparx5 *sparx5) +{ + u32 value; + + read_poll_timeout(spx5_rd, value, + !VCAP_SUPER_CTRL_UPDATE_SHOT_GET(value), 500, 10000, + false, sparx5, VCAP_SUPER_CTRL); +} + +/* Initializing a VCAP address range: only IS2 for now */ +static void _sparx5_vcap_range_init(struct sparx5 *sparx5, + struct vcap_admin *admin, + u32 addr, u32 count) +{ + u32 size = count - 1; + + spx5_wr(VCAP_SUPER_CFG_MV_NUM_POS_SET(0) | + VCAP_SUPER_CFG_MV_SIZE_SET(size), + sparx5, VCAP_SUPER_CFG); + spx5_wr(VCAP_SUPER_CTRL_UPDATE_CMD_SET(VCAP_CMD_INITIALIZE) | + VCAP_SUPER_CTRL_UPDATE_ENTRY_DIS_SET(0) | + VCAP_SUPER_CTRL_UPDATE_ACTION_DIS_SET(0) | + VCAP_SUPER_CTRL_UPDATE_CNT_DIS_SET(0) | + VCAP_SUPER_CTRL_UPDATE_ADDR_SET(addr) | + VCAP_SUPER_CTRL_CLEAR_CACHE_SET(true) | + VCAP_SUPER_CTRL_UPDATE_SHOT_SET(true), + sparx5, VCAP_SUPER_CTRL); + sparx5_vcap_wait_super_update(sparx5); +} + +/* Initializing VCAP rule data area */ +static void sparx5_vcap_block_init(struct sparx5 *sparx5, + struct vcap_admin *admin) +{ + _sparx5_vcap_range_init(sparx5, admin, admin->first_valid_addr, + admin->last_valid_addr - + admin->first_valid_addr); +} + +/* Get the keyset name from the sparx5 VCAP model */ +static const char *sparx5_vcap_keyset_name(struct net_device *ndev, + enum vcap_keyfield_set keyset) +{ + struct sparx5_port *port = netdev_priv(ndev); + + return port->sparx5->vcap_ctrl->stats->keyfield_set_names[keyset]; +} + +/* Check if this is the first lookup of IS2 */ +static bool sparx5_vcap_is2_is_first_chain(struct vcap_rule *rule) +{ + return (rule->vcap_chain_id >= SPARX5_VCAP_CID_IS2_L0 && + rule->vcap_chain_id < SPARX5_VCAP_CID_IS2_L1) || + ((rule->vcap_chain_id >= SPARX5_VCAP_CID_IS2_L2 && + rule->vcap_chain_id < SPARX5_VCAP_CID_IS2_L3)); +} + +/* Set the narrow range ingress port mask on a rule */ +static void sparx5_vcap_add_range_port_mask(struct vcap_rule *rule, + struct net_device *ndev) +{ + struct sparx5_port *port = netdev_priv(ndev); + u32 port_mask; + u32 range; + + range = port->portno / BITS_PER_TYPE(u32); + /* Port bit set to match-any */ + port_mask = ~BIT(port->portno % BITS_PER_TYPE(u32)); + vcap_rule_add_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK_SEL, 0, 0xf); + vcap_rule_add_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK_RNG, range, 0xf); + vcap_rule_add_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK, 0, port_mask); +} + +/* Set the wide range ingress port mask on a rule */ +static void sparx5_vcap_add_wide_port_mask(struct vcap_rule *rule, + struct net_device *ndev) +{ + struct sparx5_port *port = netdev_priv(ndev); + struct vcap_u72_key port_mask; + u32 range; + + /* Port bit set to match-any */ + memset(port_mask.value, 0, sizeof(port_mask.value)); + memset(port_mask.mask, 0xff, sizeof(port_mask.mask)); + range = port->portno / BITS_PER_BYTE; + port_mask.mask[range] = ~BIT(port->portno % BITS_PER_BYTE); + vcap_rule_add_key_u72(rule, VCAP_KF_IF_IGR_PORT_MASK, &port_mask); +} + +/* API callback used for validating a field keyset (check the port keysets) */ +static enum vcap_keyfield_set +sparx5_vcap_validate_keyset(struct net_device *ndev, + struct vcap_admin *admin, + struct vcap_rule *rule, + struct vcap_keyset_list *kslist, + u16 l3_proto) +{ + if (!kslist || kslist->cnt == 0) + return VCAP_KFS_NO_VALUE; + /* for now just return whatever the API suggests */ + return kslist->keysets[0]; +} + +/* API callback used for adding default fields to a rule */ +static void sparx5_vcap_add_default_fields(struct net_device *ndev, + struct vcap_admin *admin, + struct vcap_rule *rule) +{ + const struct vcap_field *field; + + field = vcap_lookup_keyfield(rule, VCAP_KF_IF_IGR_PORT_MASK); + if (field && field->width == SPX5_PORTS) + sparx5_vcap_add_wide_port_mask(rule, ndev); + else if (field && field->width == BITS_PER_TYPE(u32)) + sparx5_vcap_add_range_port_mask(rule, ndev); + else + pr_err("%s:%d: %s: could not add an ingress port mask for: %s\n", + __func__, __LINE__, netdev_name(ndev), + sparx5_vcap_keyset_name(ndev, rule->keyset)); + /* add the lookup bit */ + if (sparx5_vcap_is2_is_first_chain(rule)) + vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS, VCAP_BIT_1); + else + vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS, VCAP_BIT_0); +} + +/* API callback used for erasing the vcap cache area (not the register area) */ +static void sparx5_vcap_cache_erase(struct vcap_admin *admin) +{ + memset(admin->cache.keystream, 0, STREAMSIZE); + memset(admin->cache.maskstream, 0, STREAMSIZE); + memset(admin->cache.actionstream, 0, STREAMSIZE); + memset(&admin->cache.counter, 0, sizeof(admin->cache.counter)); +} + +/* API callback used for writing to the VCAP cache */ +static void sparx5_vcap_cache_write(struct net_device *ndev, + struct vcap_admin *admin, + enum vcap_selection sel, + u32 start, + u32 count) +{ + struct sparx5_port *port = netdev_priv(ndev); + struct sparx5 *sparx5 = port->sparx5; + u32 *keystr, *mskstr, *actstr; + int idx; + + keystr = &admin->cache.keystream[start]; + mskstr = &admin->cache.maskstream[start]; + actstr = &admin->cache.actionstream[start]; + switch (sel) { + case VCAP_SEL_ENTRY: + for (idx = 0; idx < count; ++idx) { + /* Avoid 'match-off' by setting value & mask */ + spx5_wr(keystr[idx] & mskstr[idx], sparx5, + VCAP_SUPER_VCAP_ENTRY_DAT(idx)); + spx5_wr(~mskstr[idx], sparx5, + VCAP_SUPER_VCAP_MASK_DAT(idx)); + } + break; + case VCAP_SEL_ACTION: + for (idx = 0; idx < count; ++idx) + spx5_wr(actstr[idx], sparx5, + VCAP_SUPER_VCAP_ACTION_DAT(idx)); + break; + case VCAP_SEL_ALL: + pr_err("%s:%d: cannot write all streams at once\n", + __func__, __LINE__); + break; + default: + break; + } +} + +/* API callback used for reading from the VCAP into the VCAP cache */ +static void sparx5_vcap_cache_read(struct net_device *ndev, + struct vcap_admin *admin, + enum vcap_selection sel, u32 start, + u32 count) +{ + /* this will be added later */ +} + +/* API callback used for initializing a VCAP address range */ +static void sparx5_vcap_range_init(struct net_device *ndev, + struct vcap_admin *admin, u32 addr, + u32 count) +{ + struct sparx5_port *port = netdev_priv(ndev); + struct sparx5 *sparx5 = port->sparx5; + + _sparx5_vcap_range_init(sparx5, admin, addr, count); +} + +/* API callback used for updating the VCAP cache */ +static void sparx5_vcap_update(struct net_device *ndev, + struct vcap_admin *admin, enum vcap_command cmd, + enum vcap_selection sel, u32 addr) +{ + struct sparx5_port *port = netdev_priv(ndev); + struct sparx5 *sparx5 = port->sparx5; + bool clear; + + clear = (cmd == VCAP_CMD_INITIALIZE); + spx5_wr(VCAP_SUPER_CFG_MV_NUM_POS_SET(0) | + VCAP_SUPER_CFG_MV_SIZE_SET(0), sparx5, VCAP_SUPER_CFG); + spx5_wr(VCAP_SUPER_CTRL_UPDATE_CMD_SET(cmd) | + VCAP_SUPER_CTRL_UPDATE_ENTRY_DIS_SET((VCAP_SEL_ENTRY & sel) == 0) | + VCAP_SUPER_CTRL_UPDATE_ACTION_DIS_SET((VCAP_SEL_ACTION & sel) == 0) | + VCAP_SUPER_CTRL_UPDATE_CNT_DIS_SET((VCAP_SEL_COUNTER & sel) == 0) | + VCAP_SUPER_CTRL_UPDATE_ADDR_SET(addr) | + VCAP_SUPER_CTRL_CLEAR_CACHE_SET(clear) | + VCAP_SUPER_CTRL_UPDATE_SHOT_SET(true), + sparx5, VCAP_SUPER_CTRL); + sparx5_vcap_wait_super_update(sparx5); +} + +/* API callback used for moving a block of rules in the VCAP */ +static void sparx5_vcap_move(struct net_device *ndev, struct vcap_admin *admin, + u32 addr, int offset, int count) +{ + /* this will be added later */ +} + +/* Provide port information via a callback interface */ +static int sparx5_port_info(struct net_device *ndev, enum vcap_type vtype, + int (*pf)(void *out, int arg, const char *fmt, ...), + void *out, int arg) +{ + /* this will be added later */ + return 0; +} + +/* API callback operations: only IS2 is supported for now */ +static struct vcap_operations sparx5_vcap_ops = { + .validate_keyset = sparx5_vcap_validate_keyset, + .add_default_fields = sparx5_vcap_add_default_fields, + .cache_erase = sparx5_vcap_cache_erase, + .cache_write = sparx5_vcap_cache_write, + .cache_read = sparx5_vcap_cache_read, + .init = sparx5_vcap_range_init, + .update = sparx5_vcap_update, + .move = sparx5_vcap_move, + .port_info = sparx5_port_info, +}; + +/* Enable lookups per port and set the keyset generation: only IS2 for now */ +static void sparx5_vcap_port_key_selection(struct sparx5 *sparx5, + struct vcap_admin *admin) +{ + int portno, lookup; + u32 keysel; + + /* enable all 4 lookups on all ports */ + for (portno = 0; portno < SPX5_PORTS; ++portno) + spx5_wr(ANA_ACL_VCAP_S2_CFG_SEC_ENA_SET(0xf), sparx5, + ANA_ACL_VCAP_S2_CFG(portno)); + + /* all traffic types generate the MAC_ETYPE keyset for now in all + * lookups on all ports + */ + keysel = ANA_ACL_VCAP_S2_KEY_SEL_KEY_SEL_ENA_SET(true) | + ANA_ACL_VCAP_S2_KEY_SEL_NON_ETH_KEY_SEL_SET(VCAP_IS2_PS_NONETH_MAC_ETYPE) | + ANA_ACL_VCAP_S2_KEY_SEL_IP4_MC_KEY_SEL_SET(VCAP_IS2_PS_IPV4_MC_MAC_ETYPE) | + ANA_ACL_VCAP_S2_KEY_SEL_IP4_UC_KEY_SEL_SET(VCAP_IS2_PS_IPV4_UC_MAC_ETYPE) | + ANA_ACL_VCAP_S2_KEY_SEL_IP6_MC_KEY_SEL_SET(VCAP_IS2_PS_IPV6_MC_MAC_ETYPE) | + ANA_ACL_VCAP_S2_KEY_SEL_IP6_UC_KEY_SEL_SET(VCAP_IS2_PS_IPV6_UC_MAC_ETYPE) | + ANA_ACL_VCAP_S2_KEY_SEL_ARP_KEY_SEL_SET(VCAP_IS2_PS_ARP_MAC_ETYPE); + for (lookup = 0; lookup < admin->lookups; ++lookup) { + for (portno = 0; portno < SPX5_PORTS; ++portno) { + spx5_wr(keysel, sparx5, + ANA_ACL_VCAP_S2_KEY_SEL(portno, lookup)); + } + } +} + +/* Disable lookups per port and set the keyset generation: only IS2 for now */ +static void sparx5_vcap_port_key_deselection(struct sparx5 *sparx5, + struct vcap_admin *admin) +{ + int portno; + + for (portno = 0; portno < SPX5_PORTS; ++portno) + spx5_rmw(ANA_ACL_VCAP_S2_CFG_SEC_ENA_SET(0), + ANA_ACL_VCAP_S2_CFG_SEC_ENA, + sparx5, + ANA_ACL_VCAP_S2_CFG(portno)); +} + +static void sparx5_vcap_admin_free(struct vcap_admin *admin) +{ + if (!admin) + return; + kfree(admin->cache.keystream); + kfree(admin->cache.maskstream); + kfree(admin->cache.actionstream); + kfree(admin); +} + +/* Allocate a vcap instance with a rule list and a cache area */ +static struct vcap_admin * +sparx5_vcap_admin_alloc(struct sparx5 *sparx5, struct vcap_control *ctrl, + const struct sparx5_vcap_inst *cfg) +{ + struct vcap_admin *admin; + + admin = kzalloc(sizeof(*admin), GFP_KERNEL); + if (!admin) + return ERR_PTR(-ENOMEM); + INIT_LIST_HEAD(&admin->list); + INIT_LIST_HEAD(&admin->rules); + admin->vtype = cfg->vtype; + admin->vinst = cfg->vinst; + admin->lookups = cfg->lookups; + admin->lookups_per_instance = cfg->lookups_per_instance; + admin->first_cid = cfg->first_cid; + admin->last_cid = cfg->last_cid; + admin->cache.keystream = + kzalloc(STREAMSIZE, GFP_KERNEL); + admin->cache.maskstream = + kzalloc(STREAMSIZE, GFP_KERNEL); + admin->cache.actionstream = + kzalloc(STREAMSIZE, GFP_KERNEL); + if (!admin->cache.keystream || !admin->cache.maskstream || + !admin->cache.actionstream) { + sparx5_vcap_admin_free(admin); + return ERR_PTR(-ENOMEM); + } + return admin; +} + +/* Do block allocations and provide addresses for VCAP instances */ +static void sparx5_vcap_block_alloc(struct sparx5 *sparx5, + struct vcap_admin *admin, + const struct sparx5_vcap_inst *cfg) +{ + int idx; + + /* Super VCAP block mapping and address configuration. Block 0 + * is assigned addresses 0 through 3071, block 1 is assigned + * addresses 3072 though 6143, and so on. + */ + for (idx = cfg->blockno; idx < cfg->blockno + cfg->blocks; ++idx) { + spx5_wr(VCAP_SUPER_IDX_CORE_IDX_SET(idx), sparx5, + VCAP_SUPER_IDX); + spx5_wr(VCAP_SUPER_MAP_CORE_MAP_SET(cfg->map_id), sparx5, + VCAP_SUPER_MAP); + } + admin->first_valid_addr = cfg->blockno * SUPER_VCAP_BLK_SIZE; + admin->last_used_addr = admin->first_valid_addr + + cfg->blocks * SUPER_VCAP_BLK_SIZE; + admin->last_valid_addr = admin->last_used_addr - 1; +} + +/* Allocate a vcap control and vcap instances and configure the system */ +int sparx5_vcap_init(struct sparx5 *sparx5) +{ + const struct sparx5_vcap_inst *cfg; + struct vcap_control *ctrl; + struct vcap_admin *admin; + int err = 0, idx; + + /* Create a VCAP control instance that owns the platform specific VCAP + * model with VCAP instances and information about keysets, keys, + * actionsets and actions + * - Create administrative state for each available VCAP + * - Lists of rules + * - Address information + * - Initialize VCAP blocks + * - Configure port keysets + */ + ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); + if (!ctrl) + return -ENOMEM; + + sparx5->vcap_ctrl = ctrl; + /* select the sparx5 VCAP model */ + ctrl->vcaps = sparx5_vcaps; + ctrl->stats = &sparx5_vcap_stats; + /* Setup callbacks to allow the API to use the VCAP HW */ + ctrl->ops = &sparx5_vcap_ops; + + INIT_LIST_HEAD(&ctrl->list); + for (idx = 0; idx < ARRAY_SIZE(sparx5_vcap_inst_cfg); ++idx) { + cfg = &sparx5_vcap_inst_cfg[idx]; + admin = sparx5_vcap_admin_alloc(sparx5, ctrl, cfg); + if (IS_ERR(admin)) { + err = PTR_ERR(admin); + pr_err("%s:%d: vcap allocation failed: %d\n", + __func__, __LINE__, err); + return err; + } + sparx5_vcap_block_alloc(sparx5, admin, cfg); + sparx5_vcap_block_init(sparx5, admin); + if (cfg->vinst == 0) + sparx5_vcap_port_key_selection(sparx5, admin); + list_add_tail(&admin->list, &ctrl->list); + } + + return err; +} + +void sparx5_vcap_destroy(struct sparx5 *sparx5) +{ + struct vcap_control *ctrl = sparx5->vcap_ctrl; + struct vcap_admin *admin, *admin_next; + + if (!ctrl) + return; + + list_for_each_entry_safe(admin, admin_next, &ctrl->list, list) { + sparx5_vcap_port_key_deselection(sparx5, admin); + vcap_del_rules(ctrl, admin); + list_del(&admin->list); + sparx5_vcap_admin_free(admin); + } + kfree(ctrl); +} diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.h b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.h new file mode 100644 index 000000000000..8e44ebd76b41 --- /dev/null +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Microchip Sparx5 Switch driver VCAP implementation + * + * Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries. + * + * The Sparx5 Chip Register Model can be browsed at this location: + * https://github.com/microchip-ung/sparx-5_reginfo + */ + +#ifndef __SPARX5_VCAP_IMPL_H__ +#define __SPARX5_VCAP_IMPL_H__ + +#define SPARX5_VCAP_CID_IS2_L0 VCAP_CID_INGRESS_STAGE2_L0 /* IS2 lookup 0 */ +#define SPARX5_VCAP_CID_IS2_L1 VCAP_CID_INGRESS_STAGE2_L1 /* IS2 lookup 1 */ +#define SPARX5_VCAP_CID_IS2_L2 VCAP_CID_INGRESS_STAGE2_L2 /* IS2 lookup 2 */ +#define SPARX5_VCAP_CID_IS2_L3 VCAP_CID_INGRESS_STAGE2_L3 /* IS2 lookup 3 */ +#define SPARX5_VCAP_CID_IS2_MAX \ + (VCAP_CID_INGRESS_STAGE2_L3 + VCAP_CID_LOOKUP_SIZE - 1) /* IS2 Max */ + +#endif /* __SPARX5_VCAP_IMPL_H__ */ diff --git a/drivers/net/ethernet/microchip/vcap/Kconfig b/drivers/net/ethernet/microchip/vcap/Kconfig new file mode 100644 index 000000000000..1af30a358a15 --- /dev/null +++ b/drivers/net/ethernet/microchip/vcap/Kconfig @@ -0,0 +1,52 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Microchip VCAP API configuration +# + +if NET_VENDOR_MICROCHIP + +config VCAP + bool "VCAP (Versatile Content-Aware Processor) library" + help + Provides the basic VCAP functionality for multiple Microchip switchcores + + A VCAP is essentially a TCAM with rules consisting of + + - Programmable key fields + - Programmable action fields + - A counter (which may be only one bit wide) + + Besides this each VCAP has: + + - A number of lookups + - A keyset configuration per port per lookup + + The VCAP implementation provides switchcore independent handling of rules + and supports: + + - Creating and deleting rules + - Updating and getting rules + + The platform specific configuration as well as the platform specific model + of the VCAP instances are attached to the VCAP API and a client can then + access rules via the API in a platform independent way, with the + limitations that each VCAP has in terms of its supported keys and actions. + + Different switchcores will have different VCAP instances with different + characteristics. Look in the datasheet for the VCAP specifications for the + specific switchcore. + +config VCAP_KUNIT_TEST + bool "KUnit test for VCAP library" if !KUNIT_ALL_TESTS + depends on KUNIT + depends on KUNIT=y && VCAP=y && y + default KUNIT_ALL_TESTS + help + This builds unit tests for the VCAP library. + + For more information on KUnit and unit tests in general, please refer + to the KUnit documentation in Documentation/dev-tools/kunit/. + + If unsure, say N. + +endif # NET_VENDOR_MICROCHIP diff --git a/drivers/net/ethernet/microchip/vcap/Makefile b/drivers/net/ethernet/microchip/vcap/Makefile new file mode 100644 index 000000000000..b377569f92d8 --- /dev/null +++ b/drivers/net/ethernet/microchip/vcap/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Makefile for the Microchip VCAP API +# + +obj-$(CONFIG_VCAP) += vcap.o +obj-$(CONFIG_VCAP_KUNIT_TEST) += vcap_model_kunit.o + +vcap-y += vcap_api.o diff --git a/drivers/net/ethernet/microchip/vcap/vcap_ag_api.h b/drivers/net/ethernet/microchip/vcap/vcap_ag_api.h new file mode 100644 index 000000000000..804d57b9b60a --- /dev/null +++ b/drivers/net/ethernet/microchip/vcap/vcap_ag_api.h @@ -0,0 +1,326 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* Copyright (C) 2022 Microchip Technology Inc. and its subsidiaries. + * Microchip VCAP API + */ + +/* This file is autogenerated by cml-utils 2022-10-13 10:04:41 +0200. + * Commit ID: fd7cafd175899f0672c73afb3a30fc872500ae86 + */ + +#ifndef __VCAP_AG_API__ +#define __VCAP_AG_API__ + +enum vcap_type { + VCAP_TYPE_IS2, + VCAP_TYPE_MAX +}; + +/* Keyfieldset names with origin information */ +enum vcap_keyfield_set { + VCAP_KFS_NO_VALUE, /* initial value */ + VCAP_KFS_ARP, /* sparx5 is2 X6 */ + VCAP_KFS_IP4_OTHER, /* sparx5 is2 X6 */ + VCAP_KFS_IP4_TCP_UDP, /* sparx5 is2 X6 */ + VCAP_KFS_IP6_STD, /* sparx5 is2 X6 */ + VCAP_KFS_IP_7TUPLE, /* sparx5 is2 X12 */ + VCAP_KFS_MAC_ETYPE, /* sparx5 is2 X6 */ +}; + +/* List of keyfields with description + * + * Keys ending in _IS are booleans derived from frame data + * Keys ending in _CLS are classified frame data + * + * VCAP_KF_8021Q_DEI_CLS: W1, sparx5: is2 + * Classified DEI + * VCAP_KF_8021Q_PCP_CLS: W3, sparx5: is2 + * Classified PCP + * VCAP_KF_8021Q_VID_CLS: W13, sparx5: is2 + * Classified VID + * VCAP_KF_8021Q_VLAN_TAGGED_IS: W1, sparx5: is2 + * Sparx5: Set if frame was received with a VLAN tag, LAN966x: Set if frame has + * one or more Q-tags. Independent of port VLAN awareness + * VCAP_KF_ARP_ADDR_SPACE_OK_IS: W1, sparx5: is2 + * Set if hardware address is Ethernet + * VCAP_KF_ARP_LEN_OK_IS: W1, sparx5: is2 + * Set if hardware address length = 6 (Ethernet) and IP address length = 4 (IP). + * VCAP_KF_ARP_OPCODE: W2, sparx5: is2 + * ARP opcode + * VCAP_KF_ARP_OPCODE_UNKNOWN_IS: W1, sparx5: is2 + * Set if not one of the codes defined in VCAP_KF_ARP_OPCODE + * VCAP_KF_ARP_PROTO_SPACE_OK_IS: W1, sparx5: is2 + * Set if protocol address space is 0x0800 + * VCAP_KF_ARP_SENDER_MATCH_IS: W1, sparx5: is2 + * Sender Hardware Address = SMAC (ARP) + * VCAP_KF_ARP_TGT_MATCH_IS: W1, sparx5: is2 + * Target Hardware Address = SMAC (RARP) + * VCAP_KF_ETYPE: W16, sparx5: is2 + * Ethernet type + * VCAP_KF_ETYPE_LEN_IS: W1, sparx5: is2 + * Set if frame has EtherType >= 0x600 + * VCAP_KF_IF_IGR_PORT_MASK: sparx5 is2 W32, sparx5 is2 W65 + * Ingress port mask, one bit per port/erleg + * VCAP_KF_IF_IGR_PORT_MASK_L3: W1, sparx5: is2 + * If set, IF_IGR_PORT_MASK, IF_IGR_PORT_MASK_RNG, and IF_IGR_PORT_MASK_SEL are + * used to specify L3 interfaces + * VCAP_KF_IF_IGR_PORT_MASK_RNG: W4, sparx5: is2 + * Range selector for IF_IGR_PORT_MASK. Specifies which group of 32 ports are + * available in IF_IGR_PORT_MASK + * VCAP_KF_IF_IGR_PORT_MASK_SEL: W2, sparx5: is2 + * Mode selector for IF_IGR_PORT_MASK, applicable when IF_IGR_PORT_MASK_L3 == 0. + * Mapping: 0: DEFAULT 1: LOOPBACK 2: MASQUERADE 3: CPU_VD + * VCAP_KF_IP4_IS: W1, sparx5: is2 + * Set if frame has EtherType = 0x800 and IP version = 4 + * VCAP_KF_ISDX_CLS: W12, sparx5: is2 + * Classified ISDX + * VCAP_KF_ISDX_GT0_IS: W1, sparx5: is2 + * Set if classified ISDX > 0 + * VCAP_KF_L2_BC_IS: W1, sparx5: is2 + * Set if frame’s destination MAC address is the broadcast address + * (FF-FF-FF-FF-FF-FF). + * VCAP_KF_L2_DMAC: W48, sparx5: is2 + * Destination MAC address + * VCAP_KF_L2_FWD_IS: W1, sparx5: is2 + * Set if the frame is allowed to be forwarded to front ports + * VCAP_KF_L2_MC_IS: W1, sparx5: is2 + * Set if frame’s destination MAC address is a multicast address (bit 40 = 1). + * VCAP_KF_L2_PAYLOAD_ETYPE: W64, sparx5: is2 + * Byte 0-7 of L2 payload after Type/Len field and overloading for OAM + * VCAP_KF_L2_SMAC: W48, sparx5: is2 + * Source MAC address + * VCAP_KF_L3_DIP_EQ_SIP_IS: W1, sparx5: is2 + * Set if Src IP matches Dst IP address + * VCAP_KF_L3_DST_IS: W1, sparx5: is2 + * Set if lookup is done for egress router leg + * VCAP_KF_L3_FRAGMENT_TYPE: W2, sparx5: is2 + * L3 Fragmentation type (none, initial, suspicious, valid follow up) + * VCAP_KF_L3_FRAG_INVLD_L4_LEN: W1, sparx5: is2 + * Set if frame's L4 length is less than ANA_CL:COMMON:CLM_FRAGMENT_CFG.L4_MIN_L + * EN + * VCAP_KF_L3_IP4_DIP: W32, sparx5: is2 + * Destination IPv4 Address + * VCAP_KF_L3_IP4_SIP: W32, sparx5: is2 + * Source IPv4 Address + * VCAP_KF_L3_IP6_DIP: W128, sparx5: is2 + * Sparx5: Full IPv6 DIP, LAN966x: Either Full IPv6 DIP or a subset depending on + * frame type + * VCAP_KF_L3_IP6_SIP: W128, sparx5: is2 + * Sparx5: Full IPv6 SIP, LAN966x: Either Full IPv6 SIP or a subset depending on + * frame type + * VCAP_KF_L3_IP_PROTO: W8, sparx5: is2 + * IPv4 frames: IP protocol. IPv6 frames: Next header, same as for IPV4 + * VCAP_KF_L3_OPTIONS_IS: W1, sparx5: is2 + * Set if IPv4 frame contains options (IP len > 5) + * VCAP_KF_L3_PAYLOAD: sparx5 is2 W96, sparx5 is2 W40 + * Sparx5: Payload bytes after IP header. IPv4: IPv4 options are not parsed so + * payload is always taken 20 bytes after the start of the IPv4 header, LAN966x: + * Bytes 0-6 after IP header + * VCAP_KF_L3_RT_IS: W1, sparx5: is2 + * Set if frame has hit a router leg + * VCAP_KF_L3_TOS: W8, sparx5: is2 + * Sparx5: Frame's IPv4/IPv6 DSCP and ECN fields, LAN966x: IP TOS field + * VCAP_KF_L3_TTL_GT0: W1, sparx5: is2 + * Set if IPv4 TTL / IPv6 hop limit is greater than 0 + * VCAP_KF_L4_ACK: W1, sparx5: is2 + * Sparx5 and LAN966x: TCP flag ACK, LAN966x only: PTP over UDP: flagField bit 2 + * (unicastFlag) + * VCAP_KF_L4_DPORT: W16, sparx5: is2 + * Sparx5: TCP/UDP destination port. Overloading for IP_7TUPLE: Non-TCP/UDP IP + * frames: L4_DPORT = L3_IP_PROTO, LAN966x: TCP/UDP destination port + * VCAP_KF_L4_FIN: W1, sparx5: is2 + * TCP flag FIN, LAN966x: TCP flag FIN, and for PTP over UDP: messageType bit 1 + * VCAP_KF_L4_PAYLOAD: W64, sparx5: is2 + * Payload bytes after TCP/UDP header Overloading for IP_7TUPLE: Non TCP/UDP + * frames: Payload bytes 0–7 after IP header. IPv4 options are not parsed so + * payload is always taken 20 bytes after the start of the IPv4 header for non + * TCP/UDP IPv4 frames + * VCAP_KF_L4_PSH: W1, sparx5: is2 + * Sparx5: TCP flag PSH, LAN966x: TCP: TCP flag PSH. PTP over UDP: flagField bit + * 1 (twoStepFlag) + * VCAP_KF_L4_RNG: W16, sparx5: is2 + * Range checker bitmask (one for each range checker). Input into range checkers + * is taken from classified results (VID, DSCP) and frame (SPORT, DPORT, ETYPE, + * outer VID, inner VID) + * VCAP_KF_L4_RST: W1, sparx5: is2 + * Sparx5: TCP flag RST , LAN966x: TCP: TCP flag RST. PTP over UDP: messageType + * bit 3 + * VCAP_KF_L4_SEQUENCE_EQ0_IS: W1, sparx5: is2 + * Set if TCP sequence number is 0, LAN966x: Overlayed with PTP over UDP: + * messageType bit 0 + * VCAP_KF_L4_SPORT: W16, sparx5: is2 + * TCP/UDP source port + * VCAP_KF_L4_SPORT_EQ_DPORT_IS: W1, sparx5: is2 + * Set if UDP or TCP source port equals UDP or TCP destination port + * VCAP_KF_L4_SYN: W1, sparx5: is2 + * Sparx5: TCP flag SYN, LAN966x: TCP: TCP flag SYN. PTP over UDP: messageType + * bit 2 + * VCAP_KF_L4_URG: W1, sparx5: is2 + * Sparx5: TCP flag URG, LAN966x: TCP: TCP flag URG. PTP over UDP: flagField bit + * 7 (reserved) + * VCAP_KF_LOOKUP_FIRST_IS: W1, sparx5: is2 + * Selects between entries relevant for first and second lookup. Set for first + * lookup, cleared for second lookup. + * VCAP_KF_LOOKUP_PAG: W8, sparx5: is2 + * Classified Policy Association Group: chains rules from IS1/CLM to IS2 + * VCAP_KF_OAM_CCM_CNTS_EQ0: W1, sparx5: is2 + * Dual-ended loss measurement counters in CCM frames are all zero + * VCAP_KF_OAM_Y1731_IS: W1, sparx5: is2 + * Set if frame’s EtherType = 0x8902 + * VCAP_KF_TCP_IS: W1, sparx5: is2 + * Set if frame is IPv4 TCP frame (IP protocol = 6) or IPv6 TCP frames (Next + * header = 6) + * VCAP_KF_TCP_UDP_IS: W1, sparx5: is2 + * Set if frame is IPv4/IPv6 TCP or UDP frame (IP protocol/next header equals 6 + * or 17) + * VCAP_KF_TYPE: sparx5 is2 W4, sparx5 is2 W2 + * Keyset type id - set by the API + */ + +/* Keyfield names */ +enum vcap_key_field { + VCAP_KF_NO_VALUE, /* initial value */ + VCAP_KF_8021Q_DEI_CLS, + VCAP_KF_8021Q_PCP_CLS, + VCAP_KF_8021Q_VID_CLS, + VCAP_KF_8021Q_VLAN_TAGGED_IS, + VCAP_KF_ARP_ADDR_SPACE_OK_IS, + VCAP_KF_ARP_LEN_OK_IS, + VCAP_KF_ARP_OPCODE, + VCAP_KF_ARP_OPCODE_UNKNOWN_IS, + VCAP_KF_ARP_PROTO_SPACE_OK_IS, + VCAP_KF_ARP_SENDER_MATCH_IS, + VCAP_KF_ARP_TGT_MATCH_IS, + VCAP_KF_ETYPE, + VCAP_KF_ETYPE_LEN_IS, + VCAP_KF_IF_IGR_PORT_MASK, + VCAP_KF_IF_IGR_PORT_MASK_L3, + VCAP_KF_IF_IGR_PORT_MASK_RNG, + VCAP_KF_IF_IGR_PORT_MASK_SEL, + VCAP_KF_IP4_IS, + VCAP_KF_ISDX_CLS, + VCAP_KF_ISDX_GT0_IS, + VCAP_KF_L2_BC_IS, + VCAP_KF_L2_DMAC, + VCAP_KF_L2_FWD_IS, + VCAP_KF_L2_MC_IS, + VCAP_KF_L2_PAYLOAD_ETYPE, + VCAP_KF_L2_SMAC, + VCAP_KF_L3_DIP_EQ_SIP_IS, + VCAP_KF_L3_DST_IS, + VCAP_KF_L3_FRAGMENT_TYPE, + VCAP_KF_L3_FRAG_INVLD_L4_LEN, + VCAP_KF_L3_IP4_DIP, + VCAP_KF_L3_IP4_SIP, + VCAP_KF_L3_IP6_DIP, + VCAP_KF_L3_IP6_SIP, + VCAP_KF_L3_IP_PROTO, + VCAP_KF_L3_OPTIONS_IS, + VCAP_KF_L3_PAYLOAD, + VCAP_KF_L3_RT_IS, + VCAP_KF_L3_TOS, + VCAP_KF_L3_TTL_GT0, + VCAP_KF_L4_ACK, + VCAP_KF_L4_DPORT, + VCAP_KF_L4_FIN, + VCAP_KF_L4_PAYLOAD, + VCAP_KF_L4_PSH, + VCAP_KF_L4_RNG, + VCAP_KF_L4_RST, + VCAP_KF_L4_SEQUENCE_EQ0_IS, + VCAP_KF_L4_SPORT, + VCAP_KF_L4_SPORT_EQ_DPORT_IS, + VCAP_KF_L4_SYN, + VCAP_KF_L4_URG, + VCAP_KF_LOOKUP_FIRST_IS, + VCAP_KF_LOOKUP_PAG, + VCAP_KF_OAM_CCM_CNTS_EQ0, + VCAP_KF_OAM_Y1731_IS, + VCAP_KF_TCP_IS, + VCAP_KF_TCP_UDP_IS, + VCAP_KF_TYPE, +}; + +/* Actionset names with origin information */ +enum vcap_actionfield_set { + VCAP_AFS_NO_VALUE, /* initial value */ + VCAP_AFS_BASE_TYPE, /* sparx5 is2 X3 */ +}; + +/* List of actionfields with description + * + * VCAP_AF_CNT_ID: W12, sparx5: is2 + * Counter ID, used per lookup to index the 4K frame counters (ANA_ACL:CNT_TBL). + * Multiple VCAP IS2 entries can use the same counter. + * VCAP_AF_CPU_COPY_ENA: W1, sparx5: is2 + * Setting this bit to 1 causes all frames that hit this action to be copied to + * the CPU extraction queue specified in CPU_QUEUE_NUM. + * VCAP_AF_CPU_QUEUE_NUM: W3, sparx5: is2 + * CPU queue number. Used when CPU_COPY_ENA is set. + * VCAP_AF_HIT_ME_ONCE: W1, sparx5: is2 + * Setting this bit to 1 causes the first frame that hits this action where the + * HIT_CNT counter is zero to be copied to the CPU extraction queue specified in + * CPU_QUEUE_NUM. The HIT_CNT counter is then incremented and any frames that + * hit this action later are not copied to the CPU. To re-enable the HIT_ME_ONCE + * functionality, the HIT_CNT counter must be cleared. + * VCAP_AF_IGNORE_PIPELINE_CTRL: W1, sparx5: is2 + * Ignore ingress pipeline control. This enforces the use of the VCAP IS2 action + * even when the pipeline control has terminated the frame before VCAP IS2. + * VCAP_AF_INTR_ENA: W1, sparx5: is2 + * If set, an interrupt is triggered when this rule is hit + * VCAP_AF_LRN_DIS: W1, sparx5: is2 + * Setting this bit to 1 disables learning of frames hitting this action. + * VCAP_AF_MASK_MODE: W3, sparx5: is2 + * Controls the PORT_MASK use. Sparx5: 0: OR_DSTMASK, 1: AND_VLANMASK, 2: + * REPLACE_PGID, 3: REPLACE_ALL, 4: REDIR_PGID, 5: OR_PGID_MASK, 6: VSTAX, 7: + * Not applicable. LAN966X: 0: No action, 1: Permit/deny (AND), 2: Policy + * forwarding (DMAC lookup), 3: Redirect. The CPU port is untouched by + * MASK_MODE. + * VCAP_AF_MATCH_ID: W16, sparx5: is2 + * Logical ID for the entry. The MATCH_ID is extracted together with the frame + * if the frame is forwarded to the CPU (CPU_COPY_ENA). The result is placed in + * IFH.CL_RSLT. + * VCAP_AF_MATCH_ID_MASK: W16, sparx5: is2 + * Mask used by MATCH_ID. + * VCAP_AF_MIRROR_PROBE: W2, sparx5: is2 + * Mirroring performed according to configuration of a mirror probe. 0: No + * mirroring. 1: Mirror probe 0. 2: Mirror probe 1. 3: Mirror probe 2 + * VCAP_AF_PIPELINE_FORCE_ENA: W1, sparx5: is2 + * If set, use PIPELINE_PT unconditionally and set PIPELINE_ACT = NONE if + * PIPELINE_PT == NONE. Overrules previous settings of pipeline point. + * VCAP_AF_PIPELINE_PT: W5, sparx5: is2 + * Pipeline point used if PIPELINE_FORCE_ENA is set + * VCAP_AF_POLICE_ENA: W1, sparx5: is2 + * Setting this bit to 1 causes frames that hit this action to be policed by the + * ACL policer specified in POLICE_IDX. Only applies to the first lookup. + * VCAP_AF_POLICE_IDX: W6, sparx5: is2 + * Selects VCAP policer used when policing frames (POLICE_ENA) + * VCAP_AF_PORT_MASK: W68, sparx5: is2 + * Port mask applied to the forwarding decision based on MASK_MODE. + * VCAP_AF_RT_DIS: W1, sparx5: is2 + * If set, routing is disallowed. Only applies when IS_INNER_ACL is 0. See also + * IGR_ACL_ENA, EGR_ACL_ENA, and RLEG_STAT_IDX. + */ + +/* Actionfield names */ +enum vcap_action_field { + VCAP_AF_NO_VALUE, /* initial value */ + VCAP_AF_CNT_ID, + VCAP_AF_CPU_COPY_ENA, + VCAP_AF_CPU_QUEUE_NUM, + VCAP_AF_HIT_ME_ONCE, + VCAP_AF_IGNORE_PIPELINE_CTRL, + VCAP_AF_INTR_ENA, + VCAP_AF_LRN_DIS, + VCAP_AF_MASK_MODE, + VCAP_AF_MATCH_ID, + VCAP_AF_MATCH_ID_MASK, + VCAP_AF_MIRROR_PROBE, + VCAP_AF_PIPELINE_FORCE_ENA, + VCAP_AF_PIPELINE_PT, + VCAP_AF_POLICE_ENA, + VCAP_AF_POLICE_IDX, + VCAP_AF_PORT_MASK, + VCAP_AF_RT_DIS, +}; + +#endif /* __VCAP_AG_API__ */ diff --git a/drivers/net/ethernet/microchip/vcap/vcap_ag_api_kunit.h b/drivers/net/ethernet/microchip/vcap/vcap_ag_api_kunit.h new file mode 100644 index 000000000000..e538ca725687 --- /dev/null +++ b/drivers/net/ethernet/microchip/vcap/vcap_ag_api_kunit.h @@ -0,0 +1,643 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* Copyright (C) 2022 Microchip Technology Inc. and its subsidiaries. + * Microchip VCAP API interface for kunit testing + * This is a different interface, to be able to include different VCAPs + */ + +/* Use same include guard as the official API to be able to override it */ +#ifndef __VCAP_AG_API__ +#define __VCAP_AG_API__ + +enum vcap_type { + VCAP_TYPE_ES2, + VCAP_TYPE_IS0, + VCAP_TYPE_IS2, + VCAP_TYPE_MAX +}; + +/* Keyfieldset names with origin information */ +enum vcap_keyfield_set { + VCAP_KFS_NO_VALUE, /* initial value */ + VCAP_KFS_ARP, /* sparx5 is2 X6, sparx5 es2 X6 */ + VCAP_KFS_ETAG, /* sparx5 is0 X2 */ + VCAP_KFS_IP4_OTHER, /* sparx5 is2 X6, sparx5 es2 X6 */ + VCAP_KFS_IP4_TCP_UDP, /* sparx5 is2 X6, sparx5 es2 X6 */ + VCAP_KFS_IP4_VID, /* sparx5 es2 X3 */ + VCAP_KFS_IP6_STD, /* sparx5 is2 X6 */ + VCAP_KFS_IP6_VID, /* sparx5 is2 X6, sparx5 es2 X6 */ + VCAP_KFS_IP_7TUPLE, /* sparx5 is2 X12, sparx5 es2 X12 */ + VCAP_KFS_LL_FULL, /* sparx5 is0 X6 */ + VCAP_KFS_MAC_ETYPE, /* sparx5 is2 X6, sparx5 es2 X6 */ + VCAP_KFS_MLL, /* sparx5 is0 X3 */ + VCAP_KFS_NORMAL, /* sparx5 is0 X6 */ + VCAP_KFS_NORMAL_5TUPLE_IP4, /* sparx5 is0 X6 */ + VCAP_KFS_NORMAL_7TUPLE, /* sparx5 is0 X12 */ + VCAP_KFS_PURE_5TUPLE_IP4, /* sparx5 is0 X3 */ + VCAP_KFS_TRI_VID, /* sparx5 is0 X2 */ +}; + +/* List of keyfields with description + * + * Keys ending in _IS are booleans derived from frame data + * Keys ending in _CLS are classified frame data + * + * VCAP_KF_8021BR_ECID_BASE: W12, sparx5: is0 + * Used by 802.1BR Bridge Port Extension in an E-Tag + * VCAP_KF_8021BR_ECID_EXT: W8, sparx5: is0 + * Used by 802.1BR Bridge Port Extension in an E-Tag + * VCAP_KF_8021BR_E_TAGGED: W1, sparx5: is0 + * Set for frames containing an E-TAG (802.1BR Ethertype 893f) + * VCAP_KF_8021BR_GRP: W2, sparx5: is0 + * E-Tag group bits in 802.1BR Bridge Port Extension + * VCAP_KF_8021BR_IGR_ECID_BASE: W12, sparx5: is0 + * Used by 802.1BR Bridge Port Extension in an E-Tag + * VCAP_KF_8021BR_IGR_ECID_EXT: W8, sparx5: is0 + * Used by 802.1BR Bridge Port Extension in an E-Tag + * VCAP_KF_8021Q_DEI0: W1, sparx5: is0 + * First DEI in multiple vlan tags (outer tag or default port tag) + * VCAP_KF_8021Q_DEI1: W1, sparx5: is0 + * Second DEI in multiple vlan tags (inner tag) + * VCAP_KF_8021Q_DEI2: W1, sparx5: is0 + * Third DEI in multiple vlan tags (not always available) + * VCAP_KF_8021Q_DEI_CLS: W1, sparx5: is2/es2 + * Classified DEI + * VCAP_KF_8021Q_PCP0: W3, sparx5: is0 + * First PCP in multiple vlan tags (outer tag or default port tag) + * VCAP_KF_8021Q_PCP1: W3, sparx5: is0 + * Second PCP in multiple vlan tags (inner tag) + * VCAP_KF_8021Q_PCP2: W3, sparx5: is0 + * Third PCP in multiple vlan tags (not always available) + * VCAP_KF_8021Q_PCP_CLS: W3, sparx5: is2/es2 + * Classified PCP + * VCAP_KF_8021Q_TPID0: W3, sparx5: is0 + * First TPIC in multiple vlan tags (outer tag or default port tag) + * VCAP_KF_8021Q_TPID1: W3, sparx5: is0 + * Second TPID in multiple vlan tags (inner tag) + * VCAP_KF_8021Q_TPID2: W3, sparx5: is0 + * Third TPID in multiple vlan tags (not always available) + * VCAP_KF_8021Q_VID0: W12, sparx5: is0 + * First VID in multiple vlan tags (outer tag or default port tag) + * VCAP_KF_8021Q_VID1: W12, sparx5: is0 + * Second VID in multiple vlan tags (inner tag) + * VCAP_KF_8021Q_VID2: W12, sparx5: is0 + * Third VID in multiple vlan tags (not always available) + * VCAP_KF_8021Q_VID_CLS: W13, sparx5: is2/es2 + * Classified VID + * VCAP_KF_8021Q_VLAN_TAGGED_IS: W1, sparx5: is2/es2 + * Sparx5: Set if frame was received with a VLAN tag, LAN966x: Set if frame has + * one or more Q-tags. Independent of port VLAN awareness + * VCAP_KF_8021Q_VLAN_TAGS: W3, sparx5: is0 + * Number of VLAN tags in frame: 0: Untagged, 1: Single tagged, 3: Double + * tagged, 7: Triple tagged + * VCAP_KF_ACL_GRP_ID: W8, sparx5: es2 + * Used in interface map table + * VCAP_KF_ARP_ADDR_SPACE_OK_IS: W1, sparx5: is2/es2 + * Set if hardware address is Ethernet + * VCAP_KF_ARP_LEN_OK_IS: W1, sparx5: is2/es2 + * Set if hardware address length = 6 (Ethernet) and IP address length = 4 (IP). + * VCAP_KF_ARP_OPCODE: W2, sparx5: is2/es2 + * ARP opcode + * VCAP_KF_ARP_OPCODE_UNKNOWN_IS: W1, sparx5: is2/es2 + * Set if not one of the codes defined in VCAP_KF_ARP_OPCODE + * VCAP_KF_ARP_PROTO_SPACE_OK_IS: W1, sparx5: is2/es2 + * Set if protocol address space is 0x0800 + * VCAP_KF_ARP_SENDER_MATCH_IS: W1, sparx5: is2/es2 + * Sender Hardware Address = SMAC (ARP) + * VCAP_KF_ARP_TGT_MATCH_IS: W1, sparx5: is2/es2 + * Target Hardware Address = SMAC (RARP) + * VCAP_KF_COSID_CLS: W3, sparx5: es2 + * Class of service + * VCAP_KF_DST_ENTRY: W1, sparx5: is0 + * Selects whether the frame’s destination or source information is used for + * fields L2_SMAC and L3_IP4_SIP + * VCAP_KF_ES0_ISDX_KEY_ENA: W1, sparx5: es2 + * The value taken from the IFH .FWD.ES0_ISDX_KEY_ENA + * VCAP_KF_ETYPE: W16, sparx5: is0/is2/es2 + * Ethernet type + * VCAP_KF_ETYPE_LEN_IS: W1, sparx5: is0/is2/es2 + * Set if frame has EtherType >= 0x600 + * VCAP_KF_ETYPE_MPLS: W2, sparx5: is0 + * Type of MPLS Ethertype (or not) + * VCAP_KF_IF_EGR_PORT_MASK: W32, sparx5: es2 + * Egress port mask, one bit per port + * VCAP_KF_IF_EGR_PORT_MASK_RNG: W3, sparx5: es2 + * Select which 32 port group is available in IF_EGR_PORT (or virtual ports or + * CPU queue) + * VCAP_KF_IF_IGR_PORT: sparx5 is0 W7, sparx5 es2 W9 + * Sparx5: Logical ingress port number retrieved from + * ANA_CL::PORT_ID_CFG.LPORT_NUM or ERLEG, LAN966x: ingress port nunmber + * VCAP_KF_IF_IGR_PORT_MASK: sparx5 is0 W65, sparx5 is2 W32, sparx5 is2 W65 + * Ingress port mask, one bit per port/erleg + * VCAP_KF_IF_IGR_PORT_MASK_L3: W1, sparx5: is2 + * If set, IF_IGR_PORT_MASK, IF_IGR_PORT_MASK_RNG, and IF_IGR_PORT_MASK_SEL are + * used to specify L3 interfaces + * VCAP_KF_IF_IGR_PORT_MASK_RNG: W4, sparx5: is2 + * Range selector for IF_IGR_PORT_MASK. Specifies which group of 32 ports are + * available in IF_IGR_PORT_MASK + * VCAP_KF_IF_IGR_PORT_MASK_SEL: W2, sparx5: is0/is2 + * Mode selector for IF_IGR_PORT_MASK, applicable when IF_IGR_PORT_MASK_L3 == 0. + * Mapping: 0: DEFAULT 1: LOOPBACK 2: MASQUERADE 3: CPU_VD + * VCAP_KF_IF_IGR_PORT_SEL: W1, sparx5: es2 + * Selector for IF_IGR_PORT: physical port number or ERLEG + * VCAP_KF_IP4_IS: W1, sparx5: is0/is2/es2 + * Set if frame has EtherType = 0x800 and IP version = 4 + * VCAP_KF_IP_MC_IS: W1, sparx5: is0 + * Set if frame is IPv4 frame and frame’s destination MAC address is an IPv4 + * multicast address (0x01005E0 /25). Set if frame is IPv6 frame and frame’s + * destination MAC address is an IPv6 multicast address (0x3333/16). + * VCAP_KF_IP_PAYLOAD_5TUPLE: W32, sparx5: is0 + * Payload bytes after IP header + * VCAP_KF_IP_SNAP_IS: W1, sparx5: is0 + * Set if frame is IPv4, IPv6, or SNAP frame + * VCAP_KF_ISDX_CLS: W12, sparx5: is2/es2 + * Classified ISDX + * VCAP_KF_ISDX_GT0_IS: W1, sparx5: is2/es2 + * Set if classified ISDX > 0 + * VCAP_KF_L2_BC_IS: W1, sparx5: is0/is2/es2 + * Set if frame’s destination MAC address is the broadcast address + * (FF-FF-FF-FF-FF-FF). + * VCAP_KF_L2_DMAC: W48, sparx5: is0/is2/es2 + * Destination MAC address + * VCAP_KF_L2_FWD_IS: W1, sparx5: is2 + * Set if the frame is allowed to be forwarded to front ports + * VCAP_KF_L2_MC_IS: W1, sparx5: is0/is2/es2 + * Set if frame’s destination MAC address is a multicast address (bit 40 = 1). + * VCAP_KF_L2_PAYLOAD_ETYPE: W64, sparx5: is2/es2 + * Byte 0-7 of L2 payload after Type/Len field and overloading for OAM + * VCAP_KF_L2_SMAC: W48, sparx5: is0/is2/es2 + * Source MAC address + * VCAP_KF_L3_DIP_EQ_SIP_IS: W1, sparx5: is2/es2 + * Set if Src IP matches Dst IP address + * VCAP_KF_L3_DMAC_DIP_MATCH: W1, sparx5: is2 + * Match found in DIP security lookup in ANA_L3 + * VCAP_KF_L3_DPL_CLS: W1, sparx5: es2 + * The frames drop precedence level + * VCAP_KF_L3_DSCP: W6, sparx5: is0 + * Frame’s DSCP value + * VCAP_KF_L3_DST_IS: W1, sparx5: is2 + * Set if lookup is done for egress router leg + * VCAP_KF_L3_FRAGMENT_TYPE: W2, sparx5: is0/is2/es2 + * L3 Fragmentation type (none, initial, suspicious, valid follow up) + * VCAP_KF_L3_FRAG_INVLD_L4_LEN: W1, sparx5: is0/is2 + * Set if frame's L4 length is less than ANA_CL:COMMON:CLM_FRAGMENT_CFG.L4_MIN_L + * EN + * VCAP_KF_L3_IP4_DIP: W32, sparx5: is0/is2/es2 + * Destination IPv4 Address + * VCAP_KF_L3_IP4_SIP: W32, sparx5: is0/is2/es2 + * Source IPv4 Address + * VCAP_KF_L3_IP6_DIP: W128, sparx5: is0/is2/es2 + * Sparx5: Full IPv6 DIP, LAN966x: Either Full IPv6 DIP or a subset depending on + * frame type + * VCAP_KF_L3_IP6_SIP: W128, sparx5: is0/is2/es2 + * Sparx5: Full IPv6 SIP, LAN966x: Either Full IPv6 SIP or a subset depending on + * frame type + * VCAP_KF_L3_IP_PROTO: W8, sparx5: is0/is2/es2 + * IPv4 frames: IP protocol. IPv6 frames: Next header, same as for IPV4 + * VCAP_KF_L3_OPTIONS_IS: W1, sparx5: is0/is2/es2 + * Set if IPv4 frame contains options (IP len > 5) + * VCAP_KF_L3_PAYLOAD: sparx5 is2 W96, sparx5 is2 W40, sparx5 es2 W96 + * Sparx5: Payload bytes after IP header. IPv4: IPv4 options are not parsed so + * payload is always taken 20 bytes after the start of the IPv4 header, LAN966x: + * Bytes 0-6 after IP header + * VCAP_KF_L3_RT_IS: W1, sparx5: is2/es2 + * Set if frame has hit a router leg + * VCAP_KF_L3_SMAC_SIP_MATCH: W1, sparx5: is2 + * Match found in SIP security lookup in ANA_L3 + * VCAP_KF_L3_TOS: W8, sparx5: is2/es2 + * Sparx5: Frame's IPv4/IPv6 DSCP and ECN fields, LAN966x: IP TOS field + * VCAP_KF_L3_TTL_GT0: W1, sparx5: is2/es2 + * Set if IPv4 TTL / IPv6 hop limit is greater than 0 + * VCAP_KF_L4_ACK: W1, sparx5: is2/es2 + * Sparx5 and LAN966x: TCP flag ACK, LAN966x only: PTP over UDP: flagField bit 2 + * (unicastFlag) + * VCAP_KF_L4_DPORT: W16, sparx5: is2/es2 + * Sparx5: TCP/UDP destination port. Overloading for IP_7TUPLE: Non-TCP/UDP IP + * frames: L4_DPORT = L3_IP_PROTO, LAN966x: TCP/UDP destination port + * VCAP_KF_L4_FIN: W1, sparx5: is2/es2 + * TCP flag FIN, LAN966x: TCP flag FIN, and for PTP over UDP: messageType bit 1 + * VCAP_KF_L4_PAYLOAD: W64, sparx5: is2/es2 + * Payload bytes after TCP/UDP header Overloading for IP_7TUPLE: Non TCP/UDP + * frames: Payload bytes 0–7 after IP header. IPv4 options are not parsed so + * payload is always taken 20 bytes after the start of the IPv4 header for non + * TCP/UDP IPv4 frames + * VCAP_KF_L4_PSH: W1, sparx5: is2/es2 + * Sparx5: TCP flag PSH, LAN966x: TCP: TCP flag PSH. PTP over UDP: flagField bit + * 1 (twoStepFlag) + * VCAP_KF_L4_RNG: sparx5 is0 W8, sparx5 is2 W16, sparx5 es2 W16 + * Range checker bitmask (one for each range checker). Input into range checkers + * is taken from classified results (VID, DSCP) and frame (SPORT, DPORT, ETYPE, + * outer VID, inner VID) + * VCAP_KF_L4_RST: W1, sparx5: is2/es2 + * Sparx5: TCP flag RST , LAN966x: TCP: TCP flag RST. PTP over UDP: messageType + * bit 3 + * VCAP_KF_L4_SEQUENCE_EQ0_IS: W1, sparx5: is2/es2 + * Set if TCP sequence number is 0, LAN966x: Overlayed with PTP over UDP: + * messageType bit 0 + * VCAP_KF_L4_SPORT: W16, sparx5: is0/is2/es2 + * TCP/UDP source port + * VCAP_KF_L4_SPORT_EQ_DPORT_IS: W1, sparx5: is2/es2 + * Set if UDP or TCP source port equals UDP or TCP destination port + * VCAP_KF_L4_SYN: W1, sparx5: is2/es2 + * Sparx5: TCP flag SYN, LAN966x: TCP: TCP flag SYN. PTP over UDP: messageType + * bit 2 + * VCAP_KF_L4_URG: W1, sparx5: is2/es2 + * Sparx5: TCP flag URG, LAN966x: TCP: TCP flag URG. PTP over UDP: flagField bit + * 7 (reserved) + * VCAP_KF_LOOKUP_FIRST_IS: W1, sparx5: is0/is2/es2 + * Selects between entries relevant for first and second lookup. Set for first + * lookup, cleared for second lookup. + * VCAP_KF_LOOKUP_GEN_IDX: W12, sparx5: is0 + * Generic index - for chaining CLM instances + * VCAP_KF_LOOKUP_GEN_IDX_SEL: W2, sparx5: is0 + * Select the mode of the Generic Index + * VCAP_KF_LOOKUP_PAG: W8, sparx5: is2 + * Classified Policy Association Group: chains rules from IS1/CLM to IS2 + * VCAP_KF_OAM_CCM_CNTS_EQ0: W1, sparx5: is2/es2 + * Dual-ended loss measurement counters in CCM frames are all zero + * VCAP_KF_OAM_MEL_FLAGS: W7, sparx5: is0 + * Encoding of MD level/MEG level (MEL) + * VCAP_KF_OAM_Y1731_IS: W1, sparx5: is0/is2/es2 + * Set if frame’s EtherType = 0x8902 + * VCAP_KF_PROT_ACTIVE: W1, sparx5: es2 + * Protection is active + * VCAP_KF_TCP_IS: W1, sparx5: is0/is2/es2 + * Set if frame is IPv4 TCP frame (IP protocol = 6) or IPv6 TCP frames (Next + * header = 6) + * VCAP_KF_TCP_UDP_IS: W1, sparx5: is0/is2/es2 + * Set if frame is IPv4/IPv6 TCP or UDP frame (IP protocol/next header equals 6 + * or 17) + * VCAP_KF_TYPE: sparx5 is0 W2, sparx5 is0 W1, sparx5 is2 W4, sparx5 is2 W2, + * sparx5 es2 W3 + * Keyset type id - set by the API + */ + +/* Keyfield names */ +enum vcap_key_field { + VCAP_KF_NO_VALUE, /* initial value */ + VCAP_KF_8021BR_ECID_BASE, + VCAP_KF_8021BR_ECID_EXT, + VCAP_KF_8021BR_E_TAGGED, + VCAP_KF_8021BR_GRP, + VCAP_KF_8021BR_IGR_ECID_BASE, + VCAP_KF_8021BR_IGR_ECID_EXT, + VCAP_KF_8021Q_DEI0, + VCAP_KF_8021Q_DEI1, + VCAP_KF_8021Q_DEI2, + VCAP_KF_8021Q_DEI_CLS, + VCAP_KF_8021Q_PCP0, + VCAP_KF_8021Q_PCP1, + VCAP_KF_8021Q_PCP2, + VCAP_KF_8021Q_PCP_CLS, + VCAP_KF_8021Q_TPID0, + VCAP_KF_8021Q_TPID1, + VCAP_KF_8021Q_TPID2, + VCAP_KF_8021Q_VID0, + VCAP_KF_8021Q_VID1, + VCAP_KF_8021Q_VID2, + VCAP_KF_8021Q_VID_CLS, + VCAP_KF_8021Q_VLAN_TAGGED_IS, + VCAP_KF_8021Q_VLAN_TAGS, + VCAP_KF_ACL_GRP_ID, + VCAP_KF_ARP_ADDR_SPACE_OK_IS, + VCAP_KF_ARP_LEN_OK_IS, + VCAP_KF_ARP_OPCODE, + VCAP_KF_ARP_OPCODE_UNKNOWN_IS, + VCAP_KF_ARP_PROTO_SPACE_OK_IS, + VCAP_KF_ARP_SENDER_MATCH_IS, + VCAP_KF_ARP_TGT_MATCH_IS, + VCAP_KF_COSID_CLS, + VCAP_KF_DST_ENTRY, + VCAP_KF_ES0_ISDX_KEY_ENA, + VCAP_KF_ETYPE, + VCAP_KF_ETYPE_LEN_IS, + VCAP_KF_ETYPE_MPLS, + VCAP_KF_IF_EGR_PORT_MASK, + VCAP_KF_IF_EGR_PORT_MASK_RNG, + VCAP_KF_IF_IGR_PORT, + VCAP_KF_IF_IGR_PORT_MASK, + VCAP_KF_IF_IGR_PORT_MASK_L3, + VCAP_KF_IF_IGR_PORT_MASK_RNG, + VCAP_KF_IF_IGR_PORT_MASK_SEL, + VCAP_KF_IF_IGR_PORT_SEL, + VCAP_KF_IP4_IS, + VCAP_KF_IP_MC_IS, + VCAP_KF_IP_PAYLOAD_5TUPLE, + VCAP_KF_IP_SNAP_IS, + VCAP_KF_ISDX_CLS, + VCAP_KF_ISDX_GT0_IS, + VCAP_KF_L2_BC_IS, + VCAP_KF_L2_DMAC, + VCAP_KF_L2_FWD_IS, + VCAP_KF_L2_MC_IS, + VCAP_KF_L2_PAYLOAD_ETYPE, + VCAP_KF_L2_SMAC, + VCAP_KF_L3_DIP_EQ_SIP_IS, + VCAP_KF_L3_DMAC_DIP_MATCH, + VCAP_KF_L3_DPL_CLS, + VCAP_KF_L3_DSCP, + VCAP_KF_L3_DST_IS, + VCAP_KF_L3_FRAGMENT_TYPE, + VCAP_KF_L3_FRAG_INVLD_L4_LEN, + VCAP_KF_L3_IP4_DIP, + VCAP_KF_L3_IP4_SIP, + VCAP_KF_L3_IP6_DIP, + VCAP_KF_L3_IP6_SIP, + VCAP_KF_L3_IP_PROTO, + VCAP_KF_L3_OPTIONS_IS, + VCAP_KF_L3_PAYLOAD, + VCAP_KF_L3_RT_IS, + VCAP_KF_L3_SMAC_SIP_MATCH, + VCAP_KF_L3_TOS, + VCAP_KF_L3_TTL_GT0, + VCAP_KF_L4_ACK, + VCAP_KF_L4_DPORT, + VCAP_KF_L4_FIN, + VCAP_KF_L4_PAYLOAD, + VCAP_KF_L4_PSH, + VCAP_KF_L4_RNG, + VCAP_KF_L4_RST, + VCAP_KF_L4_SEQUENCE_EQ0_IS, + VCAP_KF_L4_SPORT, + VCAP_KF_L4_SPORT_EQ_DPORT_IS, + VCAP_KF_L4_SYN, + VCAP_KF_L4_URG, + VCAP_KF_LOOKUP_FIRST_IS, + VCAP_KF_LOOKUP_GEN_IDX, + VCAP_KF_LOOKUP_GEN_IDX_SEL, + VCAP_KF_LOOKUP_PAG, + VCAP_KF_MIRROR_ENA, + VCAP_KF_OAM_CCM_CNTS_EQ0, + VCAP_KF_OAM_MEL_FLAGS, + VCAP_KF_OAM_Y1731_IS, + VCAP_KF_PROT_ACTIVE, + VCAP_KF_TCP_IS, + VCAP_KF_TCP_UDP_IS, + VCAP_KF_TYPE, +}; + +/* Actionset names with origin information */ +enum vcap_actionfield_set { + VCAP_AFS_NO_VALUE, /* initial value */ + VCAP_AFS_BASE_TYPE, /* sparx5 is2 X3, sparx5 es2 X3 */ + VCAP_AFS_CLASSIFICATION, /* sparx5 is0 X2 */ + VCAP_AFS_CLASS_REDUCED, /* sparx5 is0 X1 */ + VCAP_AFS_FULL, /* sparx5 is0 X3 */ + VCAP_AFS_MLBS, /* sparx5 is0 X2 */ + VCAP_AFS_MLBS_REDUCED, /* sparx5 is0 X1 */ +}; + +/* List of actionfields with description + * + * VCAP_AF_CLS_VID_SEL: W3, sparx5: is0 + * Controls the classified VID: 0: VID_NONE: No action. 1: VID_ADD: New VID = + * old VID + VID_VAL. 2: VID_REPLACE: New VID = VID_VAL. 3: VID_FIRST_TAG: New + * VID = VID from frame's first tag (outer tag) if available, otherwise VID_VAL. + * 4: VID_SECOND_TAG: New VID = VID from frame's second tag (middle tag) if + * available, otherwise VID_VAL. 5: VID_THIRD_TAG: New VID = VID from frame's + * third tag (inner tag) if available, otherwise VID_VAL. + * VCAP_AF_CNT_ID: sparx5 is2 W12, sparx5 es2 W11 + * Counter ID, used per lookup to index the 4K frame counters (ANA_ACL:CNT_TBL). + * Multiple VCAP IS2 entries can use the same counter. + * VCAP_AF_COPY_PORT_NUM: W7, sparx5: es2 + * QSYS port number when FWD_MODE is redirect or copy + * VCAP_AF_COPY_QUEUE_NUM: W16, sparx5: es2 + * QSYS queue number when FWD_MODE is redirect or copy + * VCAP_AF_CPU_COPY_ENA: W1, sparx5: is2/es2 + * Setting this bit to 1 causes all frames that hit this action to be copied to + * the CPU extraction queue specified in CPU_QUEUE_NUM. + * VCAP_AF_CPU_QUEUE_NUM: W3, sparx5: is2/es2 + * CPU queue number. Used when CPU_COPY_ENA is set. + * VCAP_AF_DEI_ENA: W1, sparx5: is0 + * If set, use DEI_VAL as classified DEI value. Otherwise, DEI from basic + * classification is used + * VCAP_AF_DEI_VAL: W1, sparx5: is0 + * See DEI_ENA + * VCAP_AF_DP_ENA: W1, sparx5: is0 + * If set, use DP_VAL as classified drop precedence level. Otherwise, drop + * precedence level from basic classification is used. + * VCAP_AF_DP_VAL: W2, sparx5: is0 + * See DP_ENA. + * VCAP_AF_DSCP_ENA: W1, sparx5: is0 + * If set, use DSCP_VAL as classified DSCP value. Otherwise, DSCP value from + * basic classification is used. + * VCAP_AF_DSCP_VAL: W6, sparx5: is0 + * See DSCP_ENA. + * VCAP_AF_ES2_REW_CMD: W3, sparx5: es2 + * Command forwarded to REW: 0: No action. 1: SWAP MAC addresses. 2: Do L2CP + * DMAC translation when entering or leaving a tunnel. + * VCAP_AF_FWD_MODE: W2, sparx5: es2 + * Forward selector: 0: Forward. 1: Discard. 2: Redirect. 3: Copy. + * VCAP_AF_HIT_ME_ONCE: W1, sparx5: is2/es2 + * Setting this bit to 1 causes the first frame that hits this action where the + * HIT_CNT counter is zero to be copied to the CPU extraction queue specified in + * CPU_QUEUE_NUM. The HIT_CNT counter is then incremented and any frames that + * hit this action later are not copied to the CPU. To re-enable the HIT_ME_ONCE + * functionality, the HIT_CNT counter must be cleared. + * VCAP_AF_IGNORE_PIPELINE_CTRL: W1, sparx5: is2/es2 + * Ignore ingress pipeline control. This enforces the use of the VCAP IS2 action + * even when the pipeline control has terminated the frame before VCAP IS2. + * VCAP_AF_INTR_ENA: W1, sparx5: is2/es2 + * If set, an interrupt is triggered when this rule is hit + * VCAP_AF_ISDX_ADD_REPLACE_SEL: W1, sparx5: is0 + * Controls the classified ISDX. 0: New ISDX = old ISDX + ISDX_VAL. 1: New ISDX + * = ISDX_VAL. + * VCAP_AF_ISDX_VAL: W12, sparx5: is0 + * See isdx_add_replace_sel + * VCAP_AF_LRN_DIS: W1, sparx5: is2 + * Setting this bit to 1 disables learning of frames hitting this action. + * VCAP_AF_MAP_IDX: W9, sparx5: is0 + * Index for QoS mapping table lookup + * VCAP_AF_MAP_KEY: W3, sparx5: is0 + * Key type for QoS mapping table lookup. 0: DEI0, PCP0 (outer tag). 1: DEI1, + * PCP1 (middle tag). 2: DEI2, PCP2 (inner tag). 3: MPLS TC. 4: PCP0 (outer + * tag). 5: E-DEI, E-PCP (E-TAG). 6: DSCP if available, otherwise none. 7: DSCP + * if available, otherwise DEI0, PCP0 (outer tag) if available using MAP_IDX+8, + * otherwise none + * VCAP_AF_MAP_LOOKUP_SEL: W2, sparx5: is0 + * Selects which of the two QoS Mapping Table lookups that MAP_KEY and MAP_IDX + * are applied to. 0: No changes to the QoS Mapping Table lookup. 1: Update key + * type and index for QoS Mapping Table lookup #0. 2: Update key type and index + * for QoS Mapping Table lookup #1. 3: Reserved. + * VCAP_AF_MASK_MODE: W3, sparx5: is0/is2 + * Controls the PORT_MASK use. Sparx5: 0: OR_DSTMASK, 1: AND_VLANMASK, 2: + * REPLACE_PGID, 3: REPLACE_ALL, 4: REDIR_PGID, 5: OR_PGID_MASK, 6: VSTAX, 7: + * Not applicable. LAN966X: 0: No action, 1: Permit/deny (AND), 2: Policy + * forwarding (DMAC lookup), 3: Redirect. The CPU port is untouched by + * MASK_MODE. + * VCAP_AF_MATCH_ID: W16, sparx5: is0/is2 + * Logical ID for the entry. The MATCH_ID is extracted together with the frame + * if the frame is forwarded to the CPU (CPU_COPY_ENA). The result is placed in + * IFH.CL_RSLT. + * VCAP_AF_MATCH_ID_MASK: W16, sparx5: is0/is2 + * Mask used by MATCH_ID. + * VCAP_AF_MIRROR_PROBE: W2, sparx5: is2 + * Mirroring performed according to configuration of a mirror probe. 0: No + * mirroring. 1: Mirror probe 0. 2: Mirror probe 1. 3: Mirror probe 2 + * VCAP_AF_MIRROR_PROBE_ID: W2, sparx5: es2 + * Signals a mirror probe to be placed in the IFH. Only possible when FWD_MODE + * is copy. 0: No mirroring. 1–3: Use mirror probe 0-2. + * VCAP_AF_NXT_IDX: W12, sparx5: is0 + * Index used as part of key (field G_IDX) in the next lookup. + * VCAP_AF_NXT_IDX_CTRL: W3, sparx5: is0 + * Controls the generation of the G_IDX used in the VCAP CLM next lookup + * VCAP_AF_PAG_OVERRIDE_MASK: W8, sparx5: is0 + * Bits set in this mask will override PAG_VAL from port profile. ï€ New PAG = + * (PAG (input) AND ~PAG_OVERRIDE_MASK) OR (PAG_VAL AND PAG_OVERRIDE_MASK) + * VCAP_AF_PAG_VAL: W8, sparx5: is0 + * See PAG_OVERRIDE_MASK. + * VCAP_AF_PCP_ENA: W1, sparx5: is0 + * If set, use PCP_VAL as classified PCP value. Otherwise, PCP from basic + * classification is used. + * VCAP_AF_PCP_VAL: W3, sparx5: is0 + * See PCP_ENA. + * VCAP_AF_PIPELINE_FORCE_ENA: sparx5 is0 W2, sparx5 is2 W1 + * If set, use PIPELINE_PT unconditionally and set PIPELINE_ACT = NONE if + * PIPELINE_PT == NONE. Overrules previous settings of pipeline point. + * VCAP_AF_PIPELINE_PT: W5, sparx5: is0/is2 + * Pipeline point used if PIPELINE_FORCE_ENA is set + * VCAP_AF_POLICE_ENA: W1, sparx5: is2/es2 + * Setting this bit to 1 causes frames that hit this action to be policed by the + * ACL policer specified in POLICE_IDX. Only applies to the first lookup. + * VCAP_AF_POLICE_IDX: W6, sparx5: is2/es2 + * Selects VCAP policer used when policing frames (POLICE_ENA) + * VCAP_AF_POLICE_REMARK: W1, sparx5: es2 + * If set, frames exceeding policer rates are marked as yellow but not + * discarded. + * VCAP_AF_PORT_MASK: sparx5 is0 W65, sparx5 is2 W68 + * Port mask applied to the forwarding decision based on MASK_MODE. + * VCAP_AF_QOS_ENA: W1, sparx5: is0 + * If set, use QOS_VAL as classified QoS class. Otherwise, QoS class from basic + * classification is used. + * VCAP_AF_QOS_VAL: W3, sparx5: is0 + * See QOS_ENA. + * VCAP_AF_RT_DIS: W1, sparx5: is2 + * If set, routing is disallowed. Only applies when IS_INNER_ACL is 0. See also + * IGR_ACL_ENA, EGR_ACL_ENA, and RLEG_STAT_IDX. + * VCAP_AF_TYPE: W1, sparx5: is0 + * Actionset type id - Set by the API + * VCAP_AF_VID_VAL: W13, sparx5: is0 + * New VID Value + */ + +/* Actionfield names */ +enum vcap_action_field { + VCAP_AF_NO_VALUE, /* initial value */ + VCAP_AF_ACL_MAC, + VCAP_AF_ACL_RT_MODE, + VCAP_AF_CLS_VID_SEL, + VCAP_AF_CNT_ID, + VCAP_AF_COPY_PORT_NUM, + VCAP_AF_COPY_QUEUE_NUM, + VCAP_AF_COSID_ENA, + VCAP_AF_COSID_VAL, + VCAP_AF_CPU_COPY_ENA, + VCAP_AF_CPU_DIS, + VCAP_AF_CPU_ENA, + VCAP_AF_CPU_Q, + VCAP_AF_CPU_QUEUE_NUM, + VCAP_AF_CUSTOM_ACE_ENA, + VCAP_AF_CUSTOM_ACE_OFFSET, + VCAP_AF_DEI_ENA, + VCAP_AF_DEI_VAL, + VCAP_AF_DLB_OFFSET, + VCAP_AF_DMAC_OFFSET_ENA, + VCAP_AF_DP_ENA, + VCAP_AF_DP_VAL, + VCAP_AF_DSCP_ENA, + VCAP_AF_DSCP_VAL, + VCAP_AF_EGR_ACL_ENA, + VCAP_AF_ES2_REW_CMD, + VCAP_AF_FWD_DIS, + VCAP_AF_FWD_MODE, + VCAP_AF_FWD_TYPE, + VCAP_AF_GVID_ADD_REPLACE_SEL, + VCAP_AF_HIT_ME_ONCE, + VCAP_AF_IGNORE_PIPELINE_CTRL, + VCAP_AF_IGR_ACL_ENA, + VCAP_AF_INJ_MASQ_ENA, + VCAP_AF_INJ_MASQ_LPORT, + VCAP_AF_INJ_MASQ_PORT, + VCAP_AF_INTR_ENA, + VCAP_AF_ISDX_ADD_REPLACE_SEL, + VCAP_AF_ISDX_VAL, + VCAP_AF_IS_INNER_ACL, + VCAP_AF_L3_MAC_UPDATE_DIS, + VCAP_AF_LOG_MSG_INTERVAL, + VCAP_AF_LPM_AFFIX_ENA, + VCAP_AF_LPM_AFFIX_VAL, + VCAP_AF_LPORT_ENA, + VCAP_AF_LRN_DIS, + VCAP_AF_MAP_IDX, + VCAP_AF_MAP_KEY, + VCAP_AF_MAP_LOOKUP_SEL, + VCAP_AF_MASK_MODE, + VCAP_AF_MATCH_ID, + VCAP_AF_MATCH_ID_MASK, + VCAP_AF_MIP_SEL, + VCAP_AF_MIRROR_PROBE, + VCAP_AF_MIRROR_PROBE_ID, + VCAP_AF_MPLS_IP_CTRL_ENA, + VCAP_AF_MPLS_MEP_ENA, + VCAP_AF_MPLS_MIP_ENA, + VCAP_AF_MPLS_OAM_FLAVOR, + VCAP_AF_MPLS_OAM_TYPE, + VCAP_AF_NUM_VLD_LABELS, + VCAP_AF_NXT_IDX, + VCAP_AF_NXT_IDX_CTRL, + VCAP_AF_NXT_KEY_TYPE, + VCAP_AF_NXT_NORMALIZE, + VCAP_AF_NXT_NORM_W16_OFFSET, + VCAP_AF_NXT_NORM_W32_OFFSET, + VCAP_AF_NXT_OFFSET_FROM_TYPE, + VCAP_AF_NXT_TYPE_AFTER_OFFSET, + VCAP_AF_OAM_IP_BFD_ENA, + VCAP_AF_OAM_TWAMP_ENA, + VCAP_AF_OAM_Y1731_SEL, + VCAP_AF_PAG_OVERRIDE_MASK, + VCAP_AF_PAG_VAL, + VCAP_AF_PCP_ENA, + VCAP_AF_PCP_VAL, + VCAP_AF_PIPELINE_ACT_SEL, + VCAP_AF_PIPELINE_FORCE_ENA, + VCAP_AF_PIPELINE_PT, + VCAP_AF_PIPELINE_PT_REDUCED, + VCAP_AF_POLICE_ENA, + VCAP_AF_POLICE_IDX, + VCAP_AF_POLICE_REMARK, + VCAP_AF_PORT_MASK, + VCAP_AF_PTP_MASTER_SEL, + VCAP_AF_QOS_ENA, + VCAP_AF_QOS_VAL, + VCAP_AF_REW_CMD, + VCAP_AF_RLEG_DMAC_CHK_DIS, + VCAP_AF_RLEG_STAT_IDX, + VCAP_AF_RSDX_ENA, + VCAP_AF_RSDX_VAL, + VCAP_AF_RSVD_LBL_VAL, + VCAP_AF_RT_DIS, + VCAP_AF_RT_SEL, + VCAP_AF_S2_KEY_SEL_ENA, + VCAP_AF_S2_KEY_SEL_IDX, + VCAP_AF_SAM_SEQ_ENA, + VCAP_AF_SIP_IDX, + VCAP_AF_SWAP_MAC_ENA, + VCAP_AF_TCP_UDP_DPORT, + VCAP_AF_TCP_UDP_ENA, + VCAP_AF_TCP_UDP_SPORT, + VCAP_AF_TC_ENA, + VCAP_AF_TC_LABEL, + VCAP_AF_TPID_SEL, + VCAP_AF_TTL_DECR_DIS, + VCAP_AF_TTL_ENA, + VCAP_AF_TTL_LABEL, + VCAP_AF_TTL_UPDATE_ENA, + VCAP_AF_TYPE, + VCAP_AF_VID_VAL, + VCAP_AF_VLAN_POP_CNT, + VCAP_AF_VLAN_POP_CNT_ENA, + VCAP_AF_VLAN_PUSH_CNT, + VCAP_AF_VLAN_PUSH_CNT_ENA, + VCAP_AF_VLAN_WAS_TAGGED, +}; + +#endif /* __VCAP_AG_API__ */ diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api.c b/drivers/net/ethernet/microchip/vcap/vcap_api.c new file mode 100644 index 000000000000..d255bc7deae7 --- /dev/null +++ b/drivers/net/ethernet/microchip/vcap/vcap_api.c @@ -0,0 +1,1184 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Microchip VCAP API + * + * Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries. + */ + +#include <linux/types.h> + +#include "vcap_api.h" +#include "vcap_api_client.h" + +#define to_intrule(rule) container_of((rule), struct vcap_rule_internal, data) + +/* Private VCAP API rule data */ +struct vcap_rule_internal { + struct vcap_rule data; /* provided by the client */ + struct list_head list; /* for insertion in the vcap admin list of rules */ + struct vcap_admin *admin; /* vcap hw instance */ + struct net_device *ndev; /* the interface that the rule applies to */ + struct vcap_control *vctrl; /* the client control */ + u32 sort_key; /* defines the position in the VCAP */ + int keyset_sw; /* subwords in a keyset */ + int actionset_sw; /* subwords in an actionset */ + int keyset_sw_regs; /* registers in a subword in an keyset */ + int actionset_sw_regs; /* registers in a subword in an actionset */ + int size; /* the size of the rule: max(entry, action) */ + u32 addr; /* address in the VCAP at insertion */ +}; + +/* Moving a rule in the VCAP address space */ +struct vcap_rule_move { + int addr; /* address to move */ + int offset; /* change in address */ + int count; /* blocksize of addresses to move */ +}; + +/* Bit iterator for the VCAP cache streams */ +struct vcap_stream_iter { + u32 offset; /* bit offset from the stream start */ + u32 sw_width; /* subword width in bits */ + u32 regs_per_sw; /* registers per subword */ + u32 reg_idx; /* current register index */ + u32 reg_bitpos; /* bit offset in current register */ + const struct vcap_typegroup *tg; /* current typegroup */ +}; + +static void vcap_iter_set(struct vcap_stream_iter *itr, int sw_width, + const struct vcap_typegroup *tg, u32 offset) +{ + memset(itr, 0, sizeof(*itr)); + itr->offset = offset; + itr->sw_width = sw_width; + itr->regs_per_sw = DIV_ROUND_UP(sw_width, 32); + itr->tg = tg; +} + +static void vcap_iter_skip_tg(struct vcap_stream_iter *itr) +{ + /* Compensate the field offset for preceding typegroups. + * A typegroup table ends with an all-zero terminator. + */ + while (itr->tg->width && itr->offset >= itr->tg->offset) { + itr->offset += itr->tg->width; + itr->tg++; /* next typegroup */ + } +} + +static void vcap_iter_update(struct vcap_stream_iter *itr) +{ + int sw_idx, sw_bitpos; + + /* Calculate the subword index and bitposition for current bit */ + sw_idx = itr->offset / itr->sw_width; + sw_bitpos = itr->offset % itr->sw_width; + /* Calculate the register index and bitposition for current bit */ + itr->reg_idx = (sw_idx * itr->regs_per_sw) + (sw_bitpos / 32); + itr->reg_bitpos = sw_bitpos % 32; +} + +static void vcap_iter_init(struct vcap_stream_iter *itr, int sw_width, + const struct vcap_typegroup *tg, u32 offset) +{ + vcap_iter_set(itr, sw_width, tg, offset); + vcap_iter_skip_tg(itr); + vcap_iter_update(itr); +} + +static void vcap_iter_next(struct vcap_stream_iter *itr) +{ + itr->offset++; + vcap_iter_skip_tg(itr); + vcap_iter_update(itr); +} + +static void vcap_set_bit(u32 *stream, struct vcap_stream_iter *itr, bool value) +{ + u32 mask = BIT(itr->reg_bitpos); + u32 *p = &stream[itr->reg_idx]; + + if (value) + *p |= mask; + else + *p &= ~mask; +} + +static void vcap_encode_bit(u32 *stream, struct vcap_stream_iter *itr, bool val) +{ + /* When intersected by a type group field, stream the type group bits + * before continuing with the value bit + */ + while (itr->tg->width && + itr->offset >= itr->tg->offset && + itr->offset < itr->tg->offset + itr->tg->width) { + int tg_bitpos = itr->tg->offset - itr->offset; + + vcap_set_bit(stream, itr, (itr->tg->value >> tg_bitpos) & 0x1); + itr->offset++; + vcap_iter_update(itr); + } + vcap_set_bit(stream, itr, val); +} + +static void vcap_encode_field(u32 *stream, struct vcap_stream_iter *itr, + int width, const u8 *value) +{ + int idx; + + /* Loop over the field value bits and add the value bits one by one to + * the output stream. + */ + for (idx = 0; idx < width; idx++) { + u8 bidx = idx & GENMASK(2, 0); + + /* Encode one field value bit */ + vcap_encode_bit(stream, itr, (value[idx / 8] >> bidx) & 0x1); + vcap_iter_next(itr); + } +} + +static void vcap_encode_typegroups(u32 *stream, int sw_width, + const struct vcap_typegroup *tg, + bool mask) +{ + struct vcap_stream_iter iter; + int idx; + + /* Mask bits must be set to zeros (inverted later when writing to the + * mask cache register), so that the mask typegroup bits consist of + * match-1 or match-0, or both + */ + vcap_iter_set(&iter, sw_width, tg, 0); + while (iter.tg->width) { + /* Set position to current typegroup bit */ + iter.offset = iter.tg->offset; + vcap_iter_update(&iter); + for (idx = 0; idx < iter.tg->width; idx++) { + /* Iterate over current typegroup bits. Mask typegroup + * bits are always set + */ + if (mask) + vcap_set_bit(stream, &iter, 0x1); + else + vcap_set_bit(stream, &iter, + (iter.tg->value >> idx) & 0x1); + iter.offset++; + vcap_iter_update(&iter); + } + iter.tg++; /* next typegroup */ + } +} + +/* Return the list of keyfields for the keyset */ +static const struct vcap_field *vcap_keyfields(struct vcap_control *vctrl, + enum vcap_type vt, + enum vcap_keyfield_set keyset) +{ + /* Check that the keyset exists in the vcap keyset list */ + if (keyset >= vctrl->vcaps[vt].keyfield_set_size) + return NULL; + return vctrl->vcaps[vt].keyfield_set_map[keyset]; +} + +/* Return the keyset information for the keyset */ +static const struct vcap_set *vcap_keyfieldset(struct vcap_control *vctrl, + enum vcap_type vt, + enum vcap_keyfield_set keyset) +{ + const struct vcap_set *kset; + + /* Check that the keyset exists in the vcap keyset list */ + if (keyset >= vctrl->vcaps[vt].keyfield_set_size) + return NULL; + kset = &vctrl->vcaps[vt].keyfield_set[keyset]; + if (kset->sw_per_item == 0 || kset->sw_per_item > vctrl->vcaps[vt].sw_count) + return NULL; + return kset; +} + +/* Return the typegroup table for the matching keyset (using subword size) */ +static const struct vcap_typegroup * +vcap_keyfield_typegroup(struct vcap_control *vctrl, + enum vcap_type vt, enum vcap_keyfield_set keyset) +{ + const struct vcap_set *kset = vcap_keyfieldset(vctrl, vt, keyset); + + /* Check that the keyset is valid */ + if (!kset) + return NULL; + return vctrl->vcaps[vt].keyfield_set_typegroups[kset->sw_per_item]; +} + +/* Return the number of keyfields in the keyset */ +static int vcap_keyfield_count(struct vcap_control *vctrl, + enum vcap_type vt, enum vcap_keyfield_set keyset) +{ + /* Check that the keyset exists in the vcap keyset list */ + if (keyset >= vctrl->vcaps[vt].keyfield_set_size) + return 0; + return vctrl->vcaps[vt].keyfield_set_map_size[keyset]; +} + +static void vcap_encode_keyfield(struct vcap_rule_internal *ri, + const struct vcap_client_keyfield *kf, + const struct vcap_field *rf, + const struct vcap_typegroup *tgt) +{ + int sw_width = ri->vctrl->vcaps[ri->admin->vtype].sw_width; + struct vcap_cache_data *cache = &ri->admin->cache; + struct vcap_stream_iter iter; + const u8 *value, *mask; + + /* Encode the fields for the key and the mask in their respective + * streams, respecting the subword width. + */ + switch (kf->ctrl.type) { + case VCAP_FIELD_BIT: + value = &kf->data.u1.value; + mask = &kf->data.u1.mask; + break; + case VCAP_FIELD_U32: + value = (const u8 *)&kf->data.u32.value; + mask = (const u8 *)&kf->data.u32.mask; + break; + case VCAP_FIELD_U48: + value = kf->data.u48.value; + mask = kf->data.u48.mask; + break; + case VCAP_FIELD_U56: + value = kf->data.u56.value; + mask = kf->data.u56.mask; + break; + case VCAP_FIELD_U64: + value = kf->data.u64.value; + mask = kf->data.u64.mask; + break; + case VCAP_FIELD_U72: + value = kf->data.u72.value; + mask = kf->data.u72.mask; + break; + case VCAP_FIELD_U112: + value = kf->data.u112.value; + mask = kf->data.u112.mask; + break; + case VCAP_FIELD_U128: + value = kf->data.u128.value; + mask = kf->data.u128.mask; + break; + } + vcap_iter_init(&iter, sw_width, tgt, rf->offset); + vcap_encode_field(cache->keystream, &iter, rf->width, value); + vcap_iter_init(&iter, sw_width, tgt, rf->offset); + vcap_encode_field(cache->maskstream, &iter, rf->width, mask); +} + +static void vcap_encode_keyfield_typegroups(struct vcap_control *vctrl, + struct vcap_rule_internal *ri, + const struct vcap_typegroup *tgt) +{ + int sw_width = vctrl->vcaps[ri->admin->vtype].sw_width; + struct vcap_cache_data *cache = &ri->admin->cache; + + /* Encode the typegroup bits for the key and the mask in their streams, + * respecting the subword width. + */ + vcap_encode_typegroups(cache->keystream, sw_width, tgt, false); + vcap_encode_typegroups(cache->maskstream, sw_width, tgt, true); +} + +static int vcap_encode_rule_keyset(struct vcap_rule_internal *ri) +{ + const struct vcap_client_keyfield *ckf; + const struct vcap_typegroup *tg_table; + const struct vcap_field *kf_table; + int keyset_size; + + /* Get a valid set of fields for the specific keyset */ + kf_table = vcap_keyfields(ri->vctrl, ri->admin->vtype, ri->data.keyset); + if (!kf_table) { + pr_err("%s:%d: no fields available for this keyset: %d\n", + __func__, __LINE__, ri->data.keyset); + return -EINVAL; + } + /* Get a valid typegroup for the specific keyset */ + tg_table = vcap_keyfield_typegroup(ri->vctrl, ri->admin->vtype, + ri->data.keyset); + if (!tg_table) { + pr_err("%s:%d: no typegroups available for this keyset: %d\n", + __func__, __LINE__, ri->data.keyset); + return -EINVAL; + } + /* Get a valid size for the specific keyset */ + keyset_size = vcap_keyfield_count(ri->vctrl, ri->admin->vtype, + ri->data.keyset); + if (keyset_size == 0) { + pr_err("%s:%d: zero field count for this keyset: %d\n", + __func__, __LINE__, ri->data.keyset); + return -EINVAL; + } + /* Iterate over the keyfields (key, mask) in the rule + * and encode these bits + */ + if (list_empty(&ri->data.keyfields)) { + pr_err("%s:%d: no keyfields in the rule\n", __func__, __LINE__); + return -EINVAL; + } + list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list) { + /* Check that the client entry exists in the keyset */ + if (ckf->ctrl.key >= keyset_size) { + pr_err("%s:%d: key %d is not in vcap\n", + __func__, __LINE__, ckf->ctrl.key); + return -EINVAL; + } + vcap_encode_keyfield(ri, ckf, &kf_table[ckf->ctrl.key], tg_table); + } + /* Add typegroup bits to the key/mask bitstreams */ + vcap_encode_keyfield_typegroups(ri->vctrl, ri, tg_table); + return 0; +} + +/* Return the list of actionfields for the actionset */ +static const struct vcap_field * +vcap_actionfields(struct vcap_control *vctrl, + enum vcap_type vt, enum vcap_actionfield_set actionset) +{ + /* Check that the actionset exists in the vcap actionset list */ + if (actionset >= vctrl->vcaps[vt].actionfield_set_size) + return NULL; + return vctrl->vcaps[vt].actionfield_set_map[actionset]; +} + +static const struct vcap_set * +vcap_actionfieldset(struct vcap_control *vctrl, + enum vcap_type vt, enum vcap_actionfield_set actionset) +{ + const struct vcap_set *aset; + + /* Check that the actionset exists in the vcap actionset list */ + if (actionset >= vctrl->vcaps[vt].actionfield_set_size) + return NULL; + aset = &vctrl->vcaps[vt].actionfield_set[actionset]; + if (aset->sw_per_item == 0 || aset->sw_per_item > vctrl->vcaps[vt].sw_count) + return NULL; + return aset; +} + +/* Return the typegroup table for the matching actionset (using subword size) */ +static const struct vcap_typegroup * +vcap_actionfield_typegroup(struct vcap_control *vctrl, + enum vcap_type vt, enum vcap_actionfield_set actionset) +{ + const struct vcap_set *aset = vcap_actionfieldset(vctrl, vt, actionset); + + /* Check that the actionset is valid */ + if (!aset) + return NULL; + return vctrl->vcaps[vt].actionfield_set_typegroups[aset->sw_per_item]; +} + +/* Return the number of actionfields in the actionset */ +static int vcap_actionfield_count(struct vcap_control *vctrl, + enum vcap_type vt, + enum vcap_actionfield_set actionset) +{ + /* Check that the actionset exists in the vcap actionset list */ + if (actionset >= vctrl->vcaps[vt].actionfield_set_size) + return 0; + return vctrl->vcaps[vt].actionfield_set_map_size[actionset]; +} + +static void vcap_encode_actionfield(struct vcap_rule_internal *ri, + const struct vcap_client_actionfield *af, + const struct vcap_field *rf, + const struct vcap_typegroup *tgt) +{ + int act_width = ri->vctrl->vcaps[ri->admin->vtype].act_width; + + struct vcap_cache_data *cache = &ri->admin->cache; + struct vcap_stream_iter iter; + const u8 *value; + + /* Encode the action field in the stream, respecting the subword width */ + switch (af->ctrl.type) { + case VCAP_FIELD_BIT: + value = &af->data.u1.value; + break; + case VCAP_FIELD_U32: + value = (const u8 *)&af->data.u32.value; + break; + case VCAP_FIELD_U48: + value = af->data.u48.value; + break; + case VCAP_FIELD_U56: + value = af->data.u56.value; + break; + case VCAP_FIELD_U64: + value = af->data.u64.value; + break; + case VCAP_FIELD_U72: + value = af->data.u72.value; + break; + case VCAP_FIELD_U112: + value = af->data.u112.value; + break; + case VCAP_FIELD_U128: + value = af->data.u128.value; + break; + } + vcap_iter_init(&iter, act_width, tgt, rf->offset); + vcap_encode_field(cache->actionstream, &iter, rf->width, value); +} + +static void vcap_encode_actionfield_typegroups(struct vcap_rule_internal *ri, + const struct vcap_typegroup *tgt) +{ + int sw_width = ri->vctrl->vcaps[ri->admin->vtype].act_width; + struct vcap_cache_data *cache = &ri->admin->cache; + + /* Encode the typegroup bits for the actionstream respecting the subword + * width. + */ + vcap_encode_typegroups(cache->actionstream, sw_width, tgt, false); +} + +static int vcap_encode_rule_actionset(struct vcap_rule_internal *ri) +{ + const struct vcap_client_actionfield *caf; + const struct vcap_typegroup *tg_table; + const struct vcap_field *af_table; + int actionset_size; + + /* Get a valid set of actionset fields for the specific actionset */ + af_table = vcap_actionfields(ri->vctrl, ri->admin->vtype, + ri->data.actionset); + if (!af_table) { + pr_err("%s:%d: no fields available for this actionset: %d\n", + __func__, __LINE__, ri->data.actionset); + return -EINVAL; + } + /* Get a valid typegroup for the specific actionset */ + tg_table = vcap_actionfield_typegroup(ri->vctrl, ri->admin->vtype, + ri->data.actionset); + if (!tg_table) { + pr_err("%s:%d: no typegroups available for this actionset: %d\n", + __func__, __LINE__, ri->data.actionset); + return -EINVAL; + } + /* Get a valid actionset size for the specific actionset */ + actionset_size = vcap_actionfield_count(ri->vctrl, ri->admin->vtype, + ri->data.actionset); + if (actionset_size == 0) { + pr_err("%s:%d: zero field count for this actionset: %d\n", + __func__, __LINE__, ri->data.actionset); + return -EINVAL; + } + /* Iterate over the actionfields in the rule + * and encode these bits + */ + if (list_empty(&ri->data.actionfields)) + pr_warn("%s:%d: no actionfields in the rule\n", + __func__, __LINE__); + list_for_each_entry(caf, &ri->data.actionfields, ctrl.list) { + /* Check that the client action exists in the actionset */ + if (caf->ctrl.action >= actionset_size) { + pr_err("%s:%d: action %d is not in vcap\n", + __func__, __LINE__, caf->ctrl.action); + return -EINVAL; + } + vcap_encode_actionfield(ri, caf, &af_table[caf->ctrl.action], + tg_table); + } + /* Add typegroup bits to the entry bitstreams */ + vcap_encode_actionfield_typegroups(ri, tg_table); + return 0; +} + +static int vcap_encode_rule(struct vcap_rule_internal *ri) +{ + int err; + + err = vcap_encode_rule_keyset(ri); + if (err) + return err; + err = vcap_encode_rule_actionset(ri); + if (err) + return err; + return 0; +} + +static int vcap_api_check(struct vcap_control *ctrl) +{ + if (!ctrl) { + pr_err("%s:%d: vcap control is missing\n", __func__, __LINE__); + return -EINVAL; + } + if (!ctrl->ops || !ctrl->ops->validate_keyset || + !ctrl->ops->add_default_fields || !ctrl->ops->cache_erase || + !ctrl->ops->cache_write || !ctrl->ops->cache_read || + !ctrl->ops->init || !ctrl->ops->update || !ctrl->ops->move || + !ctrl->ops->port_info) { + pr_err("%s:%d: client operations are missing\n", + __func__, __LINE__); + return -ENOENT; + } + return 0; +} + +static void vcap_erase_cache(struct vcap_rule_internal *ri) +{ + ri->vctrl->ops->cache_erase(ri->admin); +} + +/* Update the keyset for the rule */ +int vcap_set_rule_set_keyset(struct vcap_rule *rule, + enum vcap_keyfield_set keyset) +{ + struct vcap_rule_internal *ri = to_intrule(rule); + const struct vcap_set *kset; + int sw_width; + + kset = vcap_keyfieldset(ri->vctrl, ri->admin->vtype, keyset); + /* Check that the keyset is valid */ + if (!kset) + return -EINVAL; + ri->keyset_sw = kset->sw_per_item; + sw_width = ri->vctrl->vcaps[ri->admin->vtype].sw_width; + ri->keyset_sw_regs = DIV_ROUND_UP(sw_width, 32); + ri->data.keyset = keyset; + return 0; +} +EXPORT_SYMBOL_GPL(vcap_set_rule_set_keyset); + +/* Update the actionset for the rule */ +int vcap_set_rule_set_actionset(struct vcap_rule *rule, + enum vcap_actionfield_set actionset) +{ + struct vcap_rule_internal *ri = to_intrule(rule); + const struct vcap_set *aset; + int act_width; + + aset = vcap_actionfieldset(ri->vctrl, ri->admin->vtype, actionset); + /* Check that the actionset is valid */ + if (!aset) + return -EINVAL; + ri->actionset_sw = aset->sw_per_item; + act_width = ri->vctrl->vcaps[ri->admin->vtype].act_width; + ri->actionset_sw_regs = DIV_ROUND_UP(act_width, 32); + ri->data.actionset = actionset; + return 0; +} +EXPORT_SYMBOL_GPL(vcap_set_rule_set_actionset); + +/* Find a rule with a provided rule id */ +static struct vcap_rule_internal *vcap_lookup_rule(struct vcap_control *vctrl, + u32 id) +{ + struct vcap_rule_internal *ri; + struct vcap_admin *admin; + + /* Look for the rule id in all vcaps */ + list_for_each_entry(admin, &vctrl->list, list) + list_for_each_entry(ri, &admin->rules, list) + if (ri->data.id == id) + return ri; + return NULL; +} + +/* Find a rule id with a provided cookie */ +int vcap_lookup_rule_by_cookie(struct vcap_control *vctrl, u64 cookie) +{ + struct vcap_rule_internal *ri; + struct vcap_admin *admin; + + /* Look for the rule id in all vcaps */ + list_for_each_entry(admin, &vctrl->list, list) + list_for_each_entry(ri, &admin->rules, list) + if (ri->data.cookie == cookie) + return ri->data.id; + return -ENOENT; +} +EXPORT_SYMBOL_GPL(vcap_lookup_rule_by_cookie); + +/* Make a shallow copy of the rule without the fields */ +static struct vcap_rule_internal *vcap_dup_rule(struct vcap_rule_internal *ri) +{ + struct vcap_rule_internal *duprule; + + /* Allocate the client part */ + duprule = kzalloc(sizeof(*duprule), GFP_KERNEL); + if (!duprule) + return ERR_PTR(-ENOMEM); + *duprule = *ri; + /* Not inserted in the VCAP */ + INIT_LIST_HEAD(&duprule->list); + /* No elements in these lists */ + INIT_LIST_HEAD(&duprule->data.keyfields); + INIT_LIST_HEAD(&duprule->data.actionfields); + return duprule; +} + +/* Write VCAP cache content to the VCAP HW instance */ +static int vcap_write_rule(struct vcap_rule_internal *ri) +{ + struct vcap_admin *admin = ri->admin; + int sw_idx, ent_idx = 0, act_idx = 0; + u32 addr = ri->addr; + + if (!ri->size || !ri->keyset_sw_regs || !ri->actionset_sw_regs) { + pr_err("%s:%d: rule is empty\n", __func__, __LINE__); + return -EINVAL; + } + /* Use the values in the streams to write the VCAP cache */ + for (sw_idx = 0; sw_idx < ri->size; sw_idx++, addr++) { + ri->vctrl->ops->cache_write(ri->ndev, admin, + VCAP_SEL_ENTRY, ent_idx, + ri->keyset_sw_regs); + ri->vctrl->ops->cache_write(ri->ndev, admin, + VCAP_SEL_ACTION, act_idx, + ri->actionset_sw_regs); + ri->vctrl->ops->update(ri->ndev, admin, VCAP_CMD_WRITE, + VCAP_SEL_ALL, addr); + ent_idx += ri->keyset_sw_regs; + act_idx += ri->actionset_sw_regs; + } + return 0; +} + +/* Lookup a vcap instance using chain id */ +struct vcap_admin *vcap_find_admin(struct vcap_control *vctrl, int cid) +{ + struct vcap_admin *admin; + + if (vcap_api_check(vctrl)) + return NULL; + + list_for_each_entry(admin, &vctrl->list, list) { + if (cid >= admin->first_cid && cid <= admin->last_cid) + return admin; + } + return NULL; +} +EXPORT_SYMBOL_GPL(vcap_find_admin); + +/* Check if there is room for a new rule */ +static int vcap_rule_space(struct vcap_admin *admin, int size) +{ + if (admin->last_used_addr - size < admin->first_valid_addr) { + pr_err("%s:%d: No room for rule size: %u, %u\n", + __func__, __LINE__, size, admin->first_valid_addr); + return -ENOSPC; + } + return 0; +} + +/* Add the keyset typefield to the list of rule keyfields */ +static int vcap_add_type_keyfield(struct vcap_rule *rule) +{ + struct vcap_rule_internal *ri = to_intrule(rule); + enum vcap_keyfield_set keyset = rule->keyset; + enum vcap_type vt = ri->admin->vtype; + const struct vcap_field *fields; + const struct vcap_set *kset; + int ret = -EINVAL; + + kset = vcap_keyfieldset(ri->vctrl, vt, keyset); + if (!kset) + return ret; + if (kset->type_id == (u8)-1) /* No type field is needed */ + return 0; + + fields = vcap_keyfields(ri->vctrl, vt, keyset); + if (!fields) + return -EINVAL; + if (fields[VCAP_KF_TYPE].width > 1) { + ret = vcap_rule_add_key_u32(rule, VCAP_KF_TYPE, + kset->type_id, 0xff); + } else { + if (kset->type_id) + ret = vcap_rule_add_key_bit(rule, VCAP_KF_TYPE, + VCAP_BIT_1); + else + ret = vcap_rule_add_key_bit(rule, VCAP_KF_TYPE, + VCAP_BIT_0); + } + return 0; +} + +/* Validate a rule with respect to available port keys */ +int vcap_val_rule(struct vcap_rule *rule, u16 l3_proto) +{ + struct vcap_rule_internal *ri = to_intrule(rule); + enum vcap_keyfield_set keysets[10]; + struct vcap_keyset_list kslist; + int ret; + + /* This validation will be much expanded later */ + ret = vcap_api_check(ri->vctrl); + if (ret) + return ret; + if (!ri->admin) { + ri->data.exterr = VCAP_ERR_NO_ADMIN; + return -EINVAL; + } + if (!ri->ndev) { + ri->data.exterr = VCAP_ERR_NO_NETDEV; + return -EINVAL; + } + if (ri->data.keyset == VCAP_KFS_NO_VALUE) { + ri->data.exterr = VCAP_ERR_NO_KEYSET_MATCH; + return -EINVAL; + } + /* prepare for keyset validation */ + keysets[0] = ri->data.keyset; + kslist.keysets = keysets; + kslist.cnt = 1; + /* Pick a keyset that is supported in the port lookups */ + ret = ri->vctrl->ops->validate_keyset(ri->ndev, ri->admin, rule, &kslist, + l3_proto); + if (ret < 0) { + pr_err("%s:%d: keyset validation failed: %d\n", + __func__, __LINE__, ret); + ri->data.exterr = VCAP_ERR_NO_PORT_KEYSET_MATCH; + return ret; + } + if (ri->data.actionset == VCAP_AFS_NO_VALUE) { + ri->data.exterr = VCAP_ERR_NO_ACTIONSET_MATCH; + return -EINVAL; + } + vcap_add_type_keyfield(rule); + /* Add default fields to this rule */ + ri->vctrl->ops->add_default_fields(ri->ndev, ri->admin, rule); + + /* Rule size is the maximum of the entry and action subword count */ + ri->size = max(ri->keyset_sw, ri->actionset_sw); + + /* Finally check if there is room for the rule in the VCAP */ + return vcap_rule_space(ri->admin, ri->size); +} +EXPORT_SYMBOL_GPL(vcap_val_rule); + +/* calculate the address of the next rule after this (lower address and prio) */ +static u32 vcap_next_rule_addr(u32 addr, struct vcap_rule_internal *ri) +{ + return ((addr - ri->size) / ri->size) * ri->size; +} + +/* Assign a unique rule id and autogenerate one if id == 0 */ +static u32 vcap_set_rule_id(struct vcap_rule_internal *ri) +{ + u32 next_id; + + if (ri->data.id != 0) + return ri->data.id; + + next_id = ri->vctrl->rule_id + 1; + + for (next_id = ri->vctrl->rule_id + 1; next_id < ~0; ++next_id) { + if (!vcap_lookup_rule(ri->vctrl, next_id)) { + ri->data.id = next_id; + ri->vctrl->rule_id = next_id; + break; + } + } + return ri->data.id; +} + +static int vcap_insert_rule(struct vcap_rule_internal *ri, + struct vcap_rule_move *move) +{ + struct vcap_admin *admin = ri->admin; + struct vcap_rule_internal *duprule; + + /* Only support appending rules for now */ + ri->addr = vcap_next_rule_addr(admin->last_used_addr, ri); + admin->last_used_addr = ri->addr; + /* Add a shallow copy of the rule to the VCAP list */ + duprule = vcap_dup_rule(ri); + if (IS_ERR(duprule)) + return PTR_ERR(duprule); + list_add_tail(&duprule->list, &admin->rules); + return 0; +} + +static void vcap_move_rules(struct vcap_rule_internal *ri, + struct vcap_rule_move *move) +{ + ri->vctrl->ops->move(ri->ndev, ri->admin, move->addr, + move->offset, move->count); +} + +/* Encode and write a validated rule to the VCAP */ +int vcap_add_rule(struct vcap_rule *rule) +{ + struct vcap_rule_internal *ri = to_intrule(rule); + struct vcap_rule_move move = {0}; + int ret; + + ret = vcap_api_check(ri->vctrl); + if (ret) + return ret; + /* Insert the new rule in the list of vcap rules */ + ret = vcap_insert_rule(ri, &move); + if (ret < 0) { + pr_err("%s:%d: could not insert rule in vcap list: %d\n", + __func__, __LINE__, ret); + goto out; + } + if (move.count > 0) + vcap_move_rules(ri, &move); + ret = vcap_encode_rule(ri); + if (ret) { + pr_err("%s:%d: rule encoding error: %d\n", __func__, __LINE__, ret); + goto out; + } + + ret = vcap_write_rule(ri); + if (ret) + pr_err("%s:%d: rule write error: %d\n", __func__, __LINE__, ret); +out: + return ret; +} +EXPORT_SYMBOL_GPL(vcap_add_rule); + +/* Allocate a new rule with the provided arguments */ +struct vcap_rule *vcap_alloc_rule(struct vcap_control *vctrl, + struct net_device *ndev, int vcap_chain_id, + enum vcap_user user, u16 priority, + u32 id) +{ + struct vcap_rule_internal *ri; + struct vcap_admin *admin; + int maxsize; + + if (!ndev) + return ERR_PTR(-ENODEV); + /* Get the VCAP instance */ + admin = vcap_find_admin(vctrl, vcap_chain_id); + if (!admin) + return ERR_PTR(-ENOENT); + /* Sanity check that this VCAP is supported on this platform */ + if (vctrl->vcaps[admin->vtype].rows == 0) + return ERR_PTR(-EINVAL); + /* Check if a rule with this id already exists */ + if (vcap_lookup_rule(vctrl, id)) + return ERR_PTR(-EEXIST); + /* Check if there is room for the rule in the block(s) of the VCAP */ + maxsize = vctrl->vcaps[admin->vtype].sw_count; /* worst case rule size */ + if (vcap_rule_space(admin, maxsize)) + return ERR_PTR(-ENOSPC); + /* Create a container for the rule and return it */ + ri = kzalloc(sizeof(*ri), GFP_KERNEL); + if (!ri) + return ERR_PTR(-ENOMEM); + ri->data.vcap_chain_id = vcap_chain_id; + ri->data.user = user; + ri->data.priority = priority; + ri->data.id = id; + ri->data.keyset = VCAP_KFS_NO_VALUE; + ri->data.actionset = VCAP_AFS_NO_VALUE; + INIT_LIST_HEAD(&ri->list); + INIT_LIST_HEAD(&ri->data.keyfields); + INIT_LIST_HEAD(&ri->data.actionfields); + ri->ndev = ndev; + ri->admin = admin; /* refer to the vcap instance */ + ri->vctrl = vctrl; /* refer to the client */ + if (vcap_set_rule_id(ri) == 0) + goto out_free; + vcap_erase_cache(ri); + return (struct vcap_rule *)ri; + +out_free: + kfree(ri); + return ERR_PTR(-EINVAL); +} +EXPORT_SYMBOL_GPL(vcap_alloc_rule); + +/* Free mem of a rule owned by client after the rule as been added to the VCAP */ +void vcap_free_rule(struct vcap_rule *rule) +{ + struct vcap_rule_internal *ri = to_intrule(rule); + struct vcap_client_actionfield *caf, *next_caf; + struct vcap_client_keyfield *ckf, *next_ckf; + + /* Deallocate the list of keys and actions */ + list_for_each_entry_safe(ckf, next_ckf, &ri->data.keyfields, ctrl.list) { + list_del(&ckf->ctrl.list); + kfree(ckf); + } + list_for_each_entry_safe(caf, next_caf, &ri->data.actionfields, ctrl.list) { + list_del(&caf->ctrl.list); + kfree(caf); + } + /* Deallocate the rule */ + kfree(rule); +} +EXPORT_SYMBOL_GPL(vcap_free_rule); + +/* Delete rule in a VCAP instance */ +int vcap_del_rule(struct vcap_control *vctrl, struct net_device *ndev, u32 id) +{ + struct vcap_rule_internal *ri, *elem; + struct vcap_admin *admin; + int err; + + /* This will later also handle rule moving */ + if (!ndev) + return -ENODEV; + err = vcap_api_check(vctrl); + if (err) + return err; + /* Look for the rule id in all vcaps */ + ri = vcap_lookup_rule(vctrl, id); + if (!ri) + return -EINVAL; + admin = ri->admin; + list_del(&ri->list); + + /* delete the rule in the cache */ + vctrl->ops->init(ndev, admin, ri->addr, ri->size); + if (list_empty(&admin->rules)) { + admin->last_used_addr = admin->last_valid_addr; + } else { + /* update the address range end marker from the last rule in the list */ + elem = list_last_entry(&admin->rules, struct vcap_rule_internal, list); + admin->last_used_addr = elem->addr; + } + kfree(ri); + return 0; +} +EXPORT_SYMBOL_GPL(vcap_del_rule); + +/* Delete all rules in the VCAP instance */ +int vcap_del_rules(struct vcap_control *vctrl, struct vcap_admin *admin) +{ + struct vcap_rule_internal *ri, *next_ri; + int ret = vcap_api_check(vctrl); + + if (ret) + return ret; + list_for_each_entry_safe(ri, next_ri, &admin->rules, list) { + vctrl->ops->init(ri->ndev, admin, ri->addr, ri->size); + list_del(&ri->list); + kfree(ri); + } + admin->last_used_addr = admin->last_valid_addr; + return 0; +} +EXPORT_SYMBOL_GPL(vcap_del_rules); + +/* Find information on a key field in a rule */ +const struct vcap_field *vcap_lookup_keyfield(struct vcap_rule *rule, + enum vcap_key_field key) +{ + struct vcap_rule_internal *ri = to_intrule(rule); + enum vcap_keyfield_set keyset = rule->keyset; + enum vcap_type vt = ri->admin->vtype; + const struct vcap_field *fields; + + if (keyset == VCAP_KFS_NO_VALUE) + return NULL; + fields = vcap_keyfields(ri->vctrl, vt, keyset); + if (!fields) + return NULL; + return &fields[key]; +} +EXPORT_SYMBOL_GPL(vcap_lookup_keyfield); + +static void vcap_copy_from_client_keyfield(struct vcap_rule *rule, + struct vcap_client_keyfield *field, + struct vcap_client_keyfield_data *data) +{ + /* This will be expanded later to handle different vcap memory layouts */ + memcpy(&field->data, data, sizeof(field->data)); +} + +static int vcap_rule_add_key(struct vcap_rule *rule, + enum vcap_key_field key, + enum vcap_field_type ftype, + struct vcap_client_keyfield_data *data) +{ + struct vcap_client_keyfield *field; + + /* More validation will be added here later */ + field = kzalloc(sizeof(*field), GFP_KERNEL); + if (!field) + return -ENOMEM; + field->ctrl.key = key; + field->ctrl.type = ftype; + vcap_copy_from_client_keyfield(rule, field, data); + list_add_tail(&field->ctrl.list, &rule->keyfields); + return 0; +} + +static void vcap_rule_set_key_bitsize(struct vcap_u1_key *u1, enum vcap_bit val) +{ + switch (val) { + case VCAP_BIT_0: + u1->value = 0; + u1->mask = 1; + break; + case VCAP_BIT_1: + u1->value = 1; + u1->mask = 1; + break; + case VCAP_BIT_ANY: + u1->value = 0; + u1->mask = 0; + break; + } +} + +/* Add a bit key with value and mask to the rule */ +int vcap_rule_add_key_bit(struct vcap_rule *rule, enum vcap_key_field key, + enum vcap_bit val) +{ + struct vcap_client_keyfield_data data; + + vcap_rule_set_key_bitsize(&data.u1, val); + return vcap_rule_add_key(rule, key, VCAP_FIELD_BIT, &data); +} +EXPORT_SYMBOL_GPL(vcap_rule_add_key_bit); + +/* Add a 32 bit key field with value and mask to the rule */ +int vcap_rule_add_key_u32(struct vcap_rule *rule, enum vcap_key_field key, + u32 value, u32 mask) +{ + struct vcap_client_keyfield_data data; + + data.u32.value = value; + data.u32.mask = mask; + return vcap_rule_add_key(rule, key, VCAP_FIELD_U32, &data); +} +EXPORT_SYMBOL_GPL(vcap_rule_add_key_u32); + +/* Add a 48 bit key with value and mask to the rule */ +int vcap_rule_add_key_u48(struct vcap_rule *rule, enum vcap_key_field key, + struct vcap_u48_key *fieldval) +{ + struct vcap_client_keyfield_data data; + + memcpy(&data.u48, fieldval, sizeof(data.u48)); + return vcap_rule_add_key(rule, key, VCAP_FIELD_U48, &data); +} +EXPORT_SYMBOL_GPL(vcap_rule_add_key_u48); + +/* Add a 72 bit key with value and mask to the rule */ +int vcap_rule_add_key_u72(struct vcap_rule *rule, enum vcap_key_field key, + struct vcap_u72_key *fieldval) +{ + struct vcap_client_keyfield_data data; + + memcpy(&data.u72, fieldval, sizeof(data.u72)); + return vcap_rule_add_key(rule, key, VCAP_FIELD_U72, &data); +} +EXPORT_SYMBOL_GPL(vcap_rule_add_key_u72); + +static void vcap_copy_from_client_actionfield(struct vcap_rule *rule, + struct vcap_client_actionfield *field, + struct vcap_client_actionfield_data *data) +{ + /* This will be expanded later to handle different vcap memory layouts */ + memcpy(&field->data, data, sizeof(field->data)); +} + +static int vcap_rule_add_action(struct vcap_rule *rule, + enum vcap_action_field action, + enum vcap_field_type ftype, + struct vcap_client_actionfield_data *data) +{ + struct vcap_client_actionfield *field; + + /* More validation will be added here later */ + field = kzalloc(sizeof(*field), GFP_KERNEL); + if (!field) + return -ENOMEM; + field->ctrl.action = action; + field->ctrl.type = ftype; + vcap_copy_from_client_actionfield(rule, field, data); + list_add_tail(&field->ctrl.list, &rule->actionfields); + return 0; +} + +static void vcap_rule_set_action_bitsize(struct vcap_u1_action *u1, + enum vcap_bit val) +{ + switch (val) { + case VCAP_BIT_0: + u1->value = 0; + break; + case VCAP_BIT_1: + u1->value = 1; + break; + case VCAP_BIT_ANY: + u1->value = 0; + break; + } +} + +/* Add a bit action with value to the rule */ +int vcap_rule_add_action_bit(struct vcap_rule *rule, + enum vcap_action_field action, + enum vcap_bit val) +{ + struct vcap_client_actionfield_data data; + + vcap_rule_set_action_bitsize(&data.u1, val); + return vcap_rule_add_action(rule, action, VCAP_FIELD_BIT, &data); +} +EXPORT_SYMBOL_GPL(vcap_rule_add_action_bit); + +/* Add a 32 bit action field with value to the rule */ +int vcap_rule_add_action_u32(struct vcap_rule *rule, + enum vcap_action_field action, + u32 value) +{ + struct vcap_client_actionfield_data data; + + data.u32.value = value; + return vcap_rule_add_action(rule, action, VCAP_FIELD_U32, &data); +} +EXPORT_SYMBOL_GPL(vcap_rule_add_action_u32); + +/* Copy to host byte order */ +void vcap_netbytes_copy(u8 *dst, u8 *src, int count) +{ + int idx; + + for (idx = 0; idx < count; ++idx, ++dst) + *dst = src[count - idx - 1]; +} +EXPORT_SYMBOL_GPL(vcap_netbytes_copy); + +/* Convert validation error code into tc extact error message */ +void vcap_set_tc_exterr(struct flow_cls_offload *fco, struct vcap_rule *vrule) +{ + switch (vrule->exterr) { + case VCAP_ERR_NONE: + break; + case VCAP_ERR_NO_ADMIN: + NL_SET_ERR_MSG_MOD(fco->common.extack, + "Missing VCAP instance"); + break; + case VCAP_ERR_NO_NETDEV: + NL_SET_ERR_MSG_MOD(fco->common.extack, + "Missing network interface"); + break; + case VCAP_ERR_NO_KEYSET_MATCH: + NL_SET_ERR_MSG_MOD(fco->common.extack, + "No keyset matched the filter keys"); + break; + case VCAP_ERR_NO_ACTIONSET_MATCH: + NL_SET_ERR_MSG_MOD(fco->common.extack, + "No actionset matched the filter actions"); + break; + case VCAP_ERR_NO_PORT_KEYSET_MATCH: + NL_SET_ERR_MSG_MOD(fco->common.extack, + "No port keyset matched the filter keys"); + break; + } +} +EXPORT_SYMBOL_GPL(vcap_set_tc_exterr); + +#ifdef CONFIG_VCAP_KUNIT_TEST +#include "vcap_api_kunit.c" +#endif diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api.h b/drivers/net/ethernet/microchip/vcap/vcap_api.h new file mode 100644 index 000000000000..eb2eae75c7e8 --- /dev/null +++ b/drivers/net/ethernet/microchip/vcap/vcap_api.h @@ -0,0 +1,272 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* Copyright (C) 2022 Microchip Technology Inc. and its subsidiaries. + * Microchip VCAP API + */ + +#ifndef __VCAP_API__ +#define __VCAP_API__ + +#include <linux/types.h> +#include <linux/list.h> +#include <linux/netdevice.h> + +/* Use the generated API model */ +#ifdef CONFIG_VCAP_KUNIT_TEST +#include "vcap_ag_api_kunit.h" +#endif +#include "vcap_ag_api.h" + +#define VCAP_CID_LOOKUP_SIZE 100000 /* Chains in a lookup */ +#define VCAP_CID_INGRESS_L0 1000000 /* Ingress Stage 1 Lookup 0 */ +#define VCAP_CID_INGRESS_L1 1100000 /* Ingress Stage 1 Lookup 1 */ +#define VCAP_CID_INGRESS_L2 1200000 /* Ingress Stage 1 Lookup 2 */ +#define VCAP_CID_INGRESS_L3 1300000 /* Ingress Stage 1 Lookup 3 */ +#define VCAP_CID_INGRESS_L4 1400000 /* Ingress Stage 1 Lookup 4 */ +#define VCAP_CID_INGRESS_L5 1500000 /* Ingress Stage 1 Lookup 5 */ + +#define VCAP_CID_PREROUTING_IPV6 3000000 /* Prerouting Stage */ +#define VCAP_CID_PREROUTING 6000000 /* Prerouting Stage */ + +#define VCAP_CID_INGRESS_STAGE2_L0 8000000 /* Ingress Stage 2 Lookup 0 */ +#define VCAP_CID_INGRESS_STAGE2_L1 8100000 /* Ingress Stage 2 Lookup 1 */ +#define VCAP_CID_INGRESS_STAGE2_L2 8200000 /* Ingress Stage 2 Lookup 2 */ +#define VCAP_CID_INGRESS_STAGE2_L3 8300000 /* Ingress Stage 2 Lookup 3 */ + +#define VCAP_CID_EGRESS_L0 10000000 /* Egress Lookup 0 */ +#define VCAP_CID_EGRESS_L1 10100000 /* Egress Lookup 1 */ + +#define VCAP_CID_EGRESS_STAGE2_L0 20000000 /* Egress Stage 2 Lookup 0 */ +#define VCAP_CID_EGRESS_STAGE2_L1 20100000 /* Egress Stage 2 Lookup 1 */ + +/* Known users of the VCAP API */ +enum vcap_user { + VCAP_USER_PTP, + VCAP_USER_MRP, + VCAP_USER_CFM, + VCAP_USER_VLAN, + VCAP_USER_QOS, + VCAP_USER_VCAP_UTIL, + VCAP_USER_TC, + VCAP_USER_TC_EXTRA, + + /* add new users above here */ + + /* used to define VCAP_USER_MAX below */ + __VCAP_USER_AFTER_LAST, + VCAP_USER_MAX = __VCAP_USER_AFTER_LAST - 1, +}; + +/* VCAP information used for displaying data */ +struct vcap_statistics { + char *name; + int count; + const char * const *keyfield_set_names; + const char * const *actionfield_set_names; + const char * const *keyfield_names; + const char * const *actionfield_names; +}; + +/* VCAP key/action field type, position and width */ +struct vcap_field { + u16 type; + u16 width; + u16 offset; +}; + +/* VCAP keyset or actionset type and width */ +struct vcap_set { + u8 type_id; + u8 sw_per_item; + u8 sw_cnt; +}; + +/* VCAP typegroup position and bitvalue */ +struct vcap_typegroup { + u16 offset; + u16 width; + u16 value; +}; + +/* VCAP model data */ +struct vcap_info { + char *name; /* user-friendly name */ + u16 rows; /* number of row in instance */ + u16 sw_count; /* maximum subwords used per rule */ + u16 sw_width; /* bits per subword in a keyset */ + u16 sticky_width; /* sticky bits per rule */ + u16 act_width; /* bits per subword in an actionset */ + u16 default_cnt; /* number of default rules */ + u16 require_cnt_dis; /* not used */ + u16 version; /* vcap rtl version */ + const struct vcap_set *keyfield_set; /* keysets */ + int keyfield_set_size; /* number of keysets */ + const struct vcap_set *actionfield_set; /* actionsets */ + int actionfield_set_size; /* number of actionsets */ + /* map of keys per keyset */ + const struct vcap_field **keyfield_set_map; + /* number of entries in the above map */ + int *keyfield_set_map_size; + /* map of actions per actionset */ + const struct vcap_field **actionfield_set_map; + /* number of entries in the above map */ + int *actionfield_set_map_size; + /* map of keyset typegroups per subword size */ + const struct vcap_typegroup **keyfield_set_typegroups; + /* map of actionset typegroups per subword size */ + const struct vcap_typegroup **actionfield_set_typegroups; +}; + +enum vcap_field_type { + VCAP_FIELD_BIT, + VCAP_FIELD_U32, + VCAP_FIELD_U48, + VCAP_FIELD_U56, + VCAP_FIELD_U64, + VCAP_FIELD_U72, + VCAP_FIELD_U112, + VCAP_FIELD_U128, +}; + +/* VCAP rule data towards the VCAP cache */ +struct vcap_cache_data { + u32 *keystream; + u32 *maskstream; + u32 *actionstream; + u32 counter; + bool sticky; +}; + +/* Selects which part of the rule must be updated */ +enum vcap_selection { + VCAP_SEL_ENTRY = 0x01, + VCAP_SEL_ACTION = 0x02, + VCAP_SEL_COUNTER = 0x04, + VCAP_SEL_ALL = 0xff, +}; + +/* Commands towards the VCAP cache */ +enum vcap_command { + VCAP_CMD_WRITE = 0, + VCAP_CMD_READ = 1, + VCAP_CMD_MOVE_DOWN = 2, + VCAP_CMD_MOVE_UP = 3, + VCAP_CMD_INITIALIZE = 4, +}; + +enum vcap_rule_error { + VCAP_ERR_NONE = 0, /* No known error */ + VCAP_ERR_NO_ADMIN, /* No admin instance */ + VCAP_ERR_NO_NETDEV, /* No netdev instance */ + VCAP_ERR_NO_KEYSET_MATCH, /* No keyset matched the rule keys */ + VCAP_ERR_NO_ACTIONSET_MATCH, /* No actionset matched the rule actions */ + VCAP_ERR_NO_PORT_KEYSET_MATCH, /* No port keyset matched the rule keys */ +}; + +/* Administration of each VCAP instance */ +struct vcap_admin { + struct list_head list; /* for insertion in vcap_control */ + struct list_head rules; /* list of rules */ + enum vcap_type vtype; /* type of vcap */ + int vinst; /* instance number within the same type */ + int first_cid; /* first chain id in this vcap */ + int last_cid; /* last chain id in this vcap */ + int tgt_inst; /* hardware instance number */ + int lookups; /* number of lookups in this vcap type */ + int lookups_per_instance; /* number of lookups in this instance */ + int last_valid_addr; /* top of address range to be used */ + int first_valid_addr; /* bottom of address range to be used */ + int last_used_addr; /* address of lowest added rule */ + bool w32be; /* vcap uses "32bit-word big-endian" encoding */ + struct vcap_cache_data cache; /* encoded rule data */ +}; + +/* Client supplied VCAP rule data */ +struct vcap_rule { + int vcap_chain_id; /* chain used for this rule */ + enum vcap_user user; /* rule owner */ + u16 priority; + u32 id; /* vcap rule id, must be unique, 0 will auto-generate a value */ + u64 cookie; /* used by the client to identify the rule */ + struct list_head keyfields; /* list of vcap_client_keyfield */ + struct list_head actionfields; /* list of vcap_client_actionfield */ + enum vcap_keyfield_set keyset; /* keyset used: may be derived from fields */ + enum vcap_actionfield_set actionset; /* actionset used: may be derived from fields */ + enum vcap_rule_error exterr; /* extended error - used by TC */ + u64 client; /* space for client defined data */ +}; + +/* List of keysets */ +struct vcap_keyset_list { + int max; /* size of the keyset list */ + int cnt; /* count of keysets actually in the list */ + enum vcap_keyfield_set *keysets; /* the list of keysets */ +}; + +/* Client supplied VCAP callback operations */ +struct vcap_operations { + /* validate port keyset operation */ + enum vcap_keyfield_set (*validate_keyset) + (struct net_device *ndev, + struct vcap_admin *admin, + struct vcap_rule *rule, + struct vcap_keyset_list *kslist, + u16 l3_proto); + /* add default rule fields for the selected keyset operations */ + void (*add_default_fields) + (struct net_device *ndev, + struct vcap_admin *admin, + struct vcap_rule *rule); + /* cache operations */ + void (*cache_erase) + (struct vcap_admin *admin); + void (*cache_write) + (struct net_device *ndev, + struct vcap_admin *admin, + enum vcap_selection sel, + u32 idx, u32 count); + void (*cache_read) + (struct net_device *ndev, + struct vcap_admin *admin, + enum vcap_selection sel, + u32 idx, + u32 count); + /* block operations */ + void (*init) + (struct net_device *ndev, + struct vcap_admin *admin, + u32 addr, + u32 count); + void (*update) + (struct net_device *ndev, + struct vcap_admin *admin, + enum vcap_command cmd, + enum vcap_selection sel, + u32 addr); + void (*move) + (struct net_device *ndev, + struct vcap_admin *admin, + u32 addr, + int offset, + int count); + /* informational */ + int (*port_info) + (struct net_device *ndev, + enum vcap_type vtype, + int (*pf)(void *out, int arg, const char *fmt, ...), + void *out, + int arg); +}; + +/* VCAP API Client control interface */ +struct vcap_control { + u32 rule_id; /* last used rule id (unique across VCAP instances) */ + struct vcap_operations *ops; /* client supplied operations */ + const struct vcap_info *vcaps; /* client supplied vcap models */ + const struct vcap_statistics *stats; /* client supplied vcap stats */ + struct list_head list; /* list of vcap instances */ +}; + +/* Set client control interface on the API */ +int vcap_api_set_client(struct vcap_control *vctrl); + +#endif /* __VCAP_API__ */ diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api_client.h b/drivers/net/ethernet/microchip/vcap/vcap_api_client.h new file mode 100644 index 000000000000..5df6808679ff --- /dev/null +++ b/drivers/net/ethernet/microchip/vcap/vcap_api_client.h @@ -0,0 +1,202 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (C) 2022 Microchip Technology Inc. and its subsidiaries. + * Microchip VCAP API + */ + +#ifndef __VCAP_API_CLIENT__ +#define __VCAP_API_CLIENT__ + +#include <linux/types.h> +#include <linux/list.h> +#include <linux/netdevice.h> +#include <net/flow_offload.h> + +#include "vcap_api.h" + +/* Client supplied VCAP rule key control part */ +struct vcap_client_keyfield_ctrl { + struct list_head list; /* For insertion into a rule */ + enum vcap_key_field key; + enum vcap_field_type type; +}; + +struct vcap_u1_key { + u8 value; + u8 mask; +}; + +struct vcap_u32_key { + u32 value; + u32 mask; +}; + +struct vcap_u48_key { + u8 value[6]; + u8 mask[6]; +}; + +struct vcap_u56_key { + u8 value[7]; + u8 mask[7]; +}; + +struct vcap_u64_key { + u8 value[8]; + u8 mask[8]; +}; + +struct vcap_u72_key { + u8 value[9]; + u8 mask[9]; +}; + +struct vcap_u112_key { + u8 value[14]; + u8 mask[14]; +}; + +struct vcap_u128_key { + u8 value[16]; + u8 mask[16]; +}; + +/* Client supplied VCAP rule field data */ +struct vcap_client_keyfield_data { + union { + struct vcap_u1_key u1; + struct vcap_u32_key u32; + struct vcap_u48_key u48; + struct vcap_u56_key u56; + struct vcap_u64_key u64; + struct vcap_u72_key u72; + struct vcap_u112_key u112; + struct vcap_u128_key u128; + }; +}; + +/* Client supplied VCAP rule key (value, mask) */ +struct vcap_client_keyfield { + struct vcap_client_keyfield_ctrl ctrl; + struct vcap_client_keyfield_data data; +}; + +/* Client supplied VCAP rule action control part */ +struct vcap_client_actionfield_ctrl { + struct list_head list; /* For insertion into a rule */ + enum vcap_action_field action; + enum vcap_field_type type; +}; + +struct vcap_u1_action { + u8 value; +}; + +struct vcap_u32_action { + u32 value; +}; + +struct vcap_u48_action { + u8 value[6]; +}; + +struct vcap_u56_action { + u8 value[7]; +}; + +struct vcap_u64_action { + u8 value[8]; +}; + +struct vcap_u72_action { + u8 value[9]; +}; + +struct vcap_u112_action { + u8 value[14]; +}; + +struct vcap_u128_action { + u8 value[16]; +}; + +struct vcap_client_actionfield_data { + union { + struct vcap_u1_action u1; + struct vcap_u32_action u32; + struct vcap_u48_action u48; + struct vcap_u56_action u56; + struct vcap_u64_action u64; + struct vcap_u72_action u72; + struct vcap_u112_action u112; + struct vcap_u128_action u128; + }; +}; + +struct vcap_client_actionfield { + struct vcap_client_actionfield_ctrl ctrl; + struct vcap_client_actionfield_data data; +}; + +enum vcap_bit { + VCAP_BIT_ANY, + VCAP_BIT_0, + VCAP_BIT_1 +}; + +/* VCAP rule operations */ +/* Allocate a rule and fill in the basic information */ +struct vcap_rule *vcap_alloc_rule(struct vcap_control *vctrl, + struct net_device *ndev, + int vcap_chain_id, + enum vcap_user user, + u16 priority, + u32 id); +/* Free mem of a rule owned by client */ +void vcap_free_rule(struct vcap_rule *rule); +/* Validate a rule before adding it to the VCAP */ +int vcap_val_rule(struct vcap_rule *rule, u16 l3_proto); +/* Add rule to a VCAP instance */ +int vcap_add_rule(struct vcap_rule *rule); +/* Delete rule in a VCAP instance */ +int vcap_del_rule(struct vcap_control *vctrl, struct net_device *ndev, u32 id); + +/* Update the keyset for the rule */ +int vcap_set_rule_set_keyset(struct vcap_rule *rule, + enum vcap_keyfield_set keyset); +/* Update the actionset for the rule */ +int vcap_set_rule_set_actionset(struct vcap_rule *rule, + enum vcap_actionfield_set actionset); + +/* VCAP rule field operations */ +int vcap_rule_add_key_bit(struct vcap_rule *rule, enum vcap_key_field key, + enum vcap_bit val); +int vcap_rule_add_key_u32(struct vcap_rule *rule, enum vcap_key_field key, + u32 value, u32 mask); +int vcap_rule_add_key_u48(struct vcap_rule *rule, enum vcap_key_field key, + struct vcap_u48_key *fieldval); +int vcap_rule_add_key_u72(struct vcap_rule *rule, enum vcap_key_field key, + struct vcap_u72_key *fieldval); +int vcap_rule_add_action_bit(struct vcap_rule *rule, + enum vcap_action_field action, enum vcap_bit val); +int vcap_rule_add_action_u32(struct vcap_rule *rule, + enum vcap_action_field action, u32 value); + +/* VCAP lookup operations */ +/* Lookup a vcap instance using chain id */ +struct vcap_admin *vcap_find_admin(struct vcap_control *vctrl, int cid); +/* Find information on a key field in a rule */ +const struct vcap_field *vcap_lookup_keyfield(struct vcap_rule *rule, + enum vcap_key_field key); +/* Find a rule id with a provided cookie */ +int vcap_lookup_rule_by_cookie(struct vcap_control *vctrl, u64 cookie); + +/* Copy to host byte order */ +void vcap_netbytes_copy(u8 *dst, u8 *src, int count); + +/* Convert validation error code into tc extact error message */ +void vcap_set_tc_exterr(struct flow_cls_offload *fco, struct vcap_rule *vrule); + +/* Cleanup a VCAP instance */ +int vcap_del_rules(struct vcap_control *vctrl, struct vcap_admin *admin); + +#endif /* __VCAP_API_CLIENT__ */ diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api_kunit.c b/drivers/net/ethernet/microchip/vcap/vcap_api_kunit.c new file mode 100644 index 000000000000..b01a6e5039b0 --- /dev/null +++ b/drivers/net/ethernet/microchip/vcap/vcap_api_kunit.c @@ -0,0 +1,933 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* Copyright (C) 2022 Microchip Technology Inc. and its subsidiaries. + * Microchip VCAP API kunit test suite + */ + +#include <kunit/test.h> +#include "vcap_api.h" +#include "vcap_api_client.h" +#include "vcap_model_kunit.h" + +/* First we have the test infrastructure that emulates the platform + * implementation + */ +#define TEST_BUF_CNT 100 +#define TEST_BUF_SZ 350 +#define STREAMWSIZE 64 + +static u32 test_updateaddr[STREAMWSIZE] = {}; +static int test_updateaddridx; +static int test_cache_erase_count; +static u32 test_init_start; +static u32 test_init_count; +static u32 test_hw_counter_id; +static struct vcap_cache_data test_hw_cache; + +/* Callback used by the VCAP API */ +static enum vcap_keyfield_set test_val_keyset(struct net_device *ndev, + struct vcap_admin *admin, + struct vcap_rule *rule, + struct vcap_keyset_list *kslist, + u16 l3_proto) +{ + int idx; + + if (kslist->cnt > 0) { + switch (admin->vtype) { + case VCAP_TYPE_IS0: + for (idx = 0; idx < kslist->cnt; idx++) { + if (kslist->keysets[idx] == VCAP_KFS_ETAG) + return kslist->keysets[idx]; + if (kslist->keysets[idx] == VCAP_KFS_PURE_5TUPLE_IP4) + return kslist->keysets[idx]; + if (kslist->keysets[idx] == VCAP_KFS_NORMAL_5TUPLE_IP4) + return kslist->keysets[idx]; + if (kslist->keysets[idx] == VCAP_KFS_NORMAL_7TUPLE) + return kslist->keysets[idx]; + } + break; + case VCAP_TYPE_IS2: + for (idx = 0; idx < kslist->cnt; idx++) { + if (kslist->keysets[idx] == VCAP_KFS_MAC_ETYPE) + return kslist->keysets[idx]; + if (kslist->keysets[idx] == VCAP_KFS_ARP) + return kslist->keysets[idx]; + if (kslist->keysets[idx] == VCAP_KFS_IP_7TUPLE) + return kslist->keysets[idx]; + } + break; + default: + pr_info("%s:%d: no validation for VCAP %d\n", + __func__, __LINE__, admin->vtype); + break; + } + } + return -EINVAL; +} + +/* Callback used by the VCAP API */ +static void test_add_def_fields(struct net_device *ndev, + struct vcap_admin *admin, + struct vcap_rule *rule) +{ + if (admin->vinst == 0 || admin->vinst == 2) + vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS, VCAP_BIT_1); + else + vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS, VCAP_BIT_0); +} + +/* Callback used by the VCAP API */ +static void test_cache_erase(struct vcap_admin *admin) +{ + if (test_cache_erase_count) { + memset(admin->cache.keystream, 0, test_cache_erase_count); + memset(admin->cache.maskstream, 0, test_cache_erase_count); + memset(admin->cache.actionstream, 0, test_cache_erase_count); + test_cache_erase_count = 0; + } +} + +/* Callback used by the VCAP API */ +static void test_cache_init(struct net_device *ndev, struct vcap_admin *admin, + u32 start, u32 count) +{ + test_init_start = start; + test_init_count = count; +} + +/* Callback used by the VCAP API */ +static void test_cache_read(struct net_device *ndev, struct vcap_admin *admin, + enum vcap_selection sel, u32 start, u32 count) +{ + u32 *keystr, *mskstr, *actstr; + int idx; + + pr_debug("%s:%d: %d %d\n", __func__, __LINE__, start, count); + switch (sel) { + case VCAP_SEL_ENTRY: + keystr = &admin->cache.keystream[start]; + mskstr = &admin->cache.maskstream[start]; + for (idx = 0; idx < count; ++idx) { + pr_debug("%s:%d: keydata[%02d]: 0x%08x\n", __func__, + __LINE__, start + idx, keystr[idx]); + } + for (idx = 0; idx < count; ++idx) { + /* Invert the mask before decoding starts */ + mskstr[idx] = ~mskstr[idx]; + pr_debug("%s:%d: mskdata[%02d]: 0x%08x\n", __func__, + __LINE__, start + idx, mskstr[idx]); + } + break; + case VCAP_SEL_ACTION: + actstr = &admin->cache.actionstream[start]; + for (idx = 0; idx < count; ++idx) { + pr_debug("%s:%d: actdata[%02d]: 0x%08x\n", __func__, + __LINE__, start + idx, actstr[idx]); + } + break; + case VCAP_SEL_COUNTER: + pr_debug("%s:%d\n", __func__, __LINE__); + test_hw_counter_id = start; + admin->cache.counter = test_hw_cache.counter; + admin->cache.sticky = test_hw_cache.sticky; + break; + case VCAP_SEL_ALL: + pr_debug("%s:%d\n", __func__, __LINE__); + break; + } +} + +/* Callback used by the VCAP API */ +static void test_cache_write(struct net_device *ndev, struct vcap_admin *admin, + enum vcap_selection sel, u32 start, u32 count) +{ + u32 *keystr, *mskstr, *actstr; + int idx; + + switch (sel) { + case VCAP_SEL_ENTRY: + keystr = &admin->cache.keystream[start]; + mskstr = &admin->cache.maskstream[start]; + for (idx = 0; idx < count; ++idx) { + pr_debug("%s:%d: keydata[%02d]: 0x%08x\n", __func__, + __LINE__, start + idx, keystr[idx]); + } + for (idx = 0; idx < count; ++idx) { + /* Invert the mask before encoding starts */ + mskstr[idx] = ~mskstr[idx]; + pr_debug("%s:%d: mskdata[%02d]: 0x%08x\n", __func__, + __LINE__, start + idx, mskstr[idx]); + } + break; + case VCAP_SEL_ACTION: + actstr = &admin->cache.actionstream[start]; + for (idx = 0; idx < count; ++idx) { + pr_debug("%s:%d: actdata[%02d]: 0x%08x\n", __func__, + __LINE__, start + idx, actstr[idx]); + } + break; + case VCAP_SEL_COUNTER: + pr_debug("%s:%d\n", __func__, __LINE__); + test_hw_counter_id = start; + test_hw_cache.counter = admin->cache.counter; + test_hw_cache.sticky = admin->cache.sticky; + break; + case VCAP_SEL_ALL: + pr_err("%s:%d: cannot write all streams at once\n", + __func__, __LINE__); + break; + } +} + +/* Callback used by the VCAP API */ +static void test_cache_update(struct net_device *ndev, struct vcap_admin *admin, + enum vcap_command cmd, + enum vcap_selection sel, u32 addr) +{ + if (test_updateaddridx < ARRAY_SIZE(test_updateaddr)) + test_updateaddr[test_updateaddridx] = addr; + else + pr_err("%s:%d: overflow: %d\n", __func__, __LINE__, test_updateaddridx); + test_updateaddridx++; +} + +static void test_cache_move(struct net_device *ndev, struct vcap_admin *admin, + u32 addr, int offset, int count) +{ +} + +/* Provide port information via a callback interface */ +static int vcap_test_port_info(struct net_device *ndev, enum vcap_type vtype, + int (*pf)(void *out, int arg, const char *fmt, ...), + void *out, int arg) +{ + return 0; +} + +struct vcap_operations test_callbacks = { + .validate_keyset = test_val_keyset, + .add_default_fields = test_add_def_fields, + .cache_erase = test_cache_erase, + .cache_write = test_cache_write, + .cache_read = test_cache_read, + .init = test_cache_init, + .update = test_cache_update, + .move = test_cache_move, + .port_info = vcap_test_port_info, +}; + +struct vcap_control test_vctrl = { + .vcaps = kunit_test_vcaps, + .stats = &kunit_test_vcap_stats, + .ops = &test_callbacks, +}; + +static void vcap_test_api_init(struct vcap_admin *admin) +{ + /* Initialize the shared objects */ + INIT_LIST_HEAD(&test_vctrl.list); + INIT_LIST_HEAD(&admin->list); + INIT_LIST_HEAD(&admin->rules); + list_add_tail(&admin->list, &test_vctrl.list); + memset(test_updateaddr, 0, sizeof(test_updateaddr)); + test_updateaddridx = 0; +} + +/* Define the test cases. */ + +static void vcap_api_set_bit_1_test(struct kunit *test) +{ + struct vcap_stream_iter iter = { + .offset = 35, + .sw_width = 52, + .reg_idx = 1, + .reg_bitpos = 20, + .tg = 0 + }; + u32 stream[2] = {0}; + + vcap_set_bit(stream, &iter, 1); + + KUNIT_EXPECT_EQ(test, (u32)0x0, stream[0]); + KUNIT_EXPECT_EQ(test, (u32)BIT(20), stream[1]); +} + +static void vcap_api_set_bit_0_test(struct kunit *test) +{ + struct vcap_stream_iter iter = { + .offset = 35, + .sw_width = 52, + .reg_idx = 2, + .reg_bitpos = 11, + .tg = 0 + }; + u32 stream[3] = {~0, ~0, ~0}; + + vcap_set_bit(stream, &iter, 0); + + KUNIT_EXPECT_EQ(test, (u32)~0, stream[0]); + KUNIT_EXPECT_EQ(test, (u32)~0, stream[1]); + KUNIT_EXPECT_EQ(test, (u32)~BIT(11), stream[2]); +} + +static void vcap_api_iterator_init_test(struct kunit *test) +{ + struct vcap_stream_iter iter; + struct vcap_typegroup typegroups[] = { + { .offset = 0, .width = 2, .value = 2, }, + { .offset = 156, .width = 1, .value = 0, }, + { .offset = 0, .width = 0, .value = 0, }, + }; + struct vcap_typegroup typegroups2[] = { + { .offset = 0, .width = 3, .value = 4, }, + { .offset = 49, .width = 2, .value = 0, }, + { .offset = 98, .width = 2, .value = 0, }, + }; + + vcap_iter_init(&iter, 52, typegroups, 86); + + KUNIT_EXPECT_EQ(test, 52, iter.sw_width); + KUNIT_EXPECT_EQ(test, 86 + 2, iter.offset); + KUNIT_EXPECT_EQ(test, 3, iter.reg_idx); + KUNIT_EXPECT_EQ(test, 4, iter.reg_bitpos); + + vcap_iter_init(&iter, 49, typegroups2, 134); + + KUNIT_EXPECT_EQ(test, 49, iter.sw_width); + KUNIT_EXPECT_EQ(test, 134 + 7, iter.offset); + KUNIT_EXPECT_EQ(test, 5, iter.reg_idx); + KUNIT_EXPECT_EQ(test, 11, iter.reg_bitpos); +} + +static void vcap_api_iterator_next_test(struct kunit *test) +{ + struct vcap_stream_iter iter; + struct vcap_typegroup typegroups[] = { + { .offset = 0, .width = 4, .value = 8, }, + { .offset = 49, .width = 1, .value = 0, }, + { .offset = 98, .width = 2, .value = 0, }, + { .offset = 147, .width = 3, .value = 0, }, + { .offset = 196, .width = 2, .value = 0, }, + { .offset = 245, .width = 1, .value = 0, }, + }; + int idx; + + vcap_iter_init(&iter, 49, typegroups, 86); + + KUNIT_EXPECT_EQ(test, 49, iter.sw_width); + KUNIT_EXPECT_EQ(test, 86 + 5, iter.offset); + KUNIT_EXPECT_EQ(test, 3, iter.reg_idx); + KUNIT_EXPECT_EQ(test, 10, iter.reg_bitpos); + + vcap_iter_next(&iter); + + KUNIT_EXPECT_EQ(test, 91 + 1, iter.offset); + KUNIT_EXPECT_EQ(test, 3, iter.reg_idx); + KUNIT_EXPECT_EQ(test, 11, iter.reg_bitpos); + + for (idx = 0; idx < 6; idx++) + vcap_iter_next(&iter); + + KUNIT_EXPECT_EQ(test, 92 + 6 + 2, iter.offset); + KUNIT_EXPECT_EQ(test, 4, iter.reg_idx); + KUNIT_EXPECT_EQ(test, 2, iter.reg_bitpos); +} + +static void vcap_api_encode_typegroups_test(struct kunit *test) +{ + u32 stream[12] = {0}; + struct vcap_typegroup typegroups[] = { + { .offset = 0, .width = 4, .value = 8, }, + { .offset = 49, .width = 1, .value = 1, }, + { .offset = 98, .width = 2, .value = 3, }, + { .offset = 147, .width = 3, .value = 5, }, + { .offset = 196, .width = 2, .value = 2, }, + { .offset = 245, .width = 5, .value = 27, }, + { .offset = 0, .width = 0, .value = 0, }, + }; + + vcap_encode_typegroups(stream, 49, typegroups, false); + + KUNIT_EXPECT_EQ(test, (u32)0x8, stream[0]); + KUNIT_EXPECT_EQ(test, (u32)0x0, stream[1]); + KUNIT_EXPECT_EQ(test, (u32)0x1, stream[2]); + KUNIT_EXPECT_EQ(test, (u32)0x0, stream[3]); + KUNIT_EXPECT_EQ(test, (u32)0x3, stream[4]); + KUNIT_EXPECT_EQ(test, (u32)0x0, stream[5]); + KUNIT_EXPECT_EQ(test, (u32)0x5, stream[6]); + KUNIT_EXPECT_EQ(test, (u32)0x0, stream[7]); + KUNIT_EXPECT_EQ(test, (u32)0x2, stream[8]); + KUNIT_EXPECT_EQ(test, (u32)0x0, stream[9]); + KUNIT_EXPECT_EQ(test, (u32)27, stream[10]); + KUNIT_EXPECT_EQ(test, (u32)0x0, stream[11]); +} + +static void vcap_api_encode_bit_test(struct kunit *test) +{ + struct vcap_stream_iter iter; + u32 stream[4] = {0}; + struct vcap_typegroup typegroups[] = { + { .offset = 0, .width = 4, .value = 8, }, + { .offset = 49, .width = 1, .value = 1, }, + { .offset = 98, .width = 2, .value = 3, }, + { .offset = 147, .width = 3, .value = 5, }, + { .offset = 196, .width = 2, .value = 2, }, + { .offset = 245, .width = 1, .value = 0, }, + }; + + vcap_iter_init(&iter, 49, typegroups, 44); + + KUNIT_EXPECT_EQ(test, 48, iter.offset); + KUNIT_EXPECT_EQ(test, 1, iter.reg_idx); + KUNIT_EXPECT_EQ(test, 16, iter.reg_bitpos); + + vcap_encode_bit(stream, &iter, 1); + + KUNIT_EXPECT_EQ(test, (u32)0x0, stream[0]); + KUNIT_EXPECT_EQ(test, (u32)BIT(16), stream[1]); + KUNIT_EXPECT_EQ(test, (u32)0x0, stream[2]); +} + +static void vcap_api_encode_field_test(struct kunit *test) +{ + struct vcap_stream_iter iter; + u32 stream[16] = {0}; + struct vcap_typegroup typegroups[] = { + { .offset = 0, .width = 4, .value = 8, }, + { .offset = 49, .width = 1, .value = 1, }, + { .offset = 98, .width = 2, .value = 3, }, + { .offset = 147, .width = 3, .value = 5, }, + { .offset = 196, .width = 2, .value = 2, }, + { .offset = 245, .width = 5, .value = 27, }, + { .offset = 0, .width = 0, .value = 0, }, + }; + struct vcap_field rf = { + .type = VCAP_FIELD_U32, + .offset = 86, + .width = 4, + }; + u8 value[] = {0x5}; + + vcap_iter_init(&iter, 49, typegroups, rf.offset); + + KUNIT_EXPECT_EQ(test, 91, iter.offset); + KUNIT_EXPECT_EQ(test, 3, iter.reg_idx); + KUNIT_EXPECT_EQ(test, 10, iter.reg_bitpos); + + vcap_encode_field(stream, &iter, rf.width, value); + + KUNIT_EXPECT_EQ(test, (u32)0x0, stream[0]); + KUNIT_EXPECT_EQ(test, (u32)0x0, stream[1]); + KUNIT_EXPECT_EQ(test, (u32)0x0, stream[2]); + KUNIT_EXPECT_EQ(test, (u32)(0x5 << 10), stream[3]); + KUNIT_EXPECT_EQ(test, (u32)0x0, stream[4]); + + vcap_encode_typegroups(stream, 49, typegroups, false); + + KUNIT_EXPECT_EQ(test, (u32)0x8, stream[0]); + KUNIT_EXPECT_EQ(test, (u32)0x0, stream[1]); + KUNIT_EXPECT_EQ(test, (u32)0x1, stream[2]); + KUNIT_EXPECT_EQ(test, (u32)(0x5 << 10), stream[3]); + KUNIT_EXPECT_EQ(test, (u32)0x3, stream[4]); + KUNIT_EXPECT_EQ(test, (u32)0x0, stream[5]); + KUNIT_EXPECT_EQ(test, (u32)0x5, stream[6]); + KUNIT_EXPECT_EQ(test, (u32)0x0, stream[7]); + KUNIT_EXPECT_EQ(test, (u32)0x2, stream[8]); + KUNIT_EXPECT_EQ(test, (u32)0x0, stream[9]); + KUNIT_EXPECT_EQ(test, (u32)27, stream[10]); + KUNIT_EXPECT_EQ(test, (u32)0x0, stream[11]); +} + +/* In this testcase the subword is smaller than a register */ +static void vcap_api_encode_short_field_test(struct kunit *test) +{ + struct vcap_stream_iter iter; + int sw_width = 21; + u32 stream[6] = {0}; + struct vcap_typegroup tgt[] = { + { .offset = 0, .width = 3, .value = 7, }, + { .offset = 21, .width = 2, .value = 3, }, + { .offset = 42, .width = 1, .value = 1, }, + { .offset = 0, .width = 0, .value = 0, }, + }; + struct vcap_field rf = { + .type = VCAP_FIELD_U32, + .offset = 25, + .width = 4, + }; + u8 value[] = {0x5}; + + vcap_iter_init(&iter, sw_width, tgt, rf.offset); + + KUNIT_EXPECT_EQ(test, 1, iter.regs_per_sw); + KUNIT_EXPECT_EQ(test, 21, iter.sw_width); + KUNIT_EXPECT_EQ(test, 25 + 3 + 2, iter.offset); + KUNIT_EXPECT_EQ(test, 1, iter.reg_idx); + KUNIT_EXPECT_EQ(test, 25 + 3 + 2 - sw_width, iter.reg_bitpos); + + vcap_encode_field(stream, &iter, rf.width, value); + + KUNIT_EXPECT_EQ(test, (u32)0x0, stream[0]); + KUNIT_EXPECT_EQ(test, (u32)(0x5 << (25 + 3 + 2 - sw_width)), stream[1]); + KUNIT_EXPECT_EQ(test, (u32)0x0, stream[2]); + KUNIT_EXPECT_EQ(test, (u32)0x0, stream[3]); + KUNIT_EXPECT_EQ(test, (u32)0x0, stream[4]); + KUNIT_EXPECT_EQ(test, (u32)0x0, stream[5]); + + vcap_encode_typegroups(stream, sw_width, tgt, false); + + KUNIT_EXPECT_EQ(test, (u32)7, stream[0]); + KUNIT_EXPECT_EQ(test, (u32)((0x5 << (25 + 3 + 2 - sw_width)) + 3), stream[1]); + KUNIT_EXPECT_EQ(test, (u32)1, stream[2]); + KUNIT_EXPECT_EQ(test, (u32)0, stream[3]); + KUNIT_EXPECT_EQ(test, (u32)0, stream[4]); + KUNIT_EXPECT_EQ(test, (u32)0, stream[5]); +} + +static void vcap_api_encode_keyfield_test(struct kunit *test) +{ + u32 keywords[16] = {0}; + u32 maskwords[16] = {0}; + struct vcap_admin admin = { + .vtype = VCAP_TYPE_IS2, + .cache = { + .keystream = keywords, + .maskstream = maskwords, + .actionstream = keywords, + }, + }; + struct vcap_rule_internal rule = { + .admin = &admin, + .data = { + .keyset = VCAP_KFS_MAC_ETYPE, + }, + .vctrl = &test_vctrl, + }; + struct vcap_client_keyfield ckf = { + .ctrl.list = {}, + .ctrl.key = VCAP_KF_ISDX_CLS, + .ctrl.type = VCAP_FIELD_U32, + .data.u32.value = 0xeef014a1, + .data.u32.mask = 0xfff, + }; + struct vcap_field rf = { + .type = VCAP_FIELD_U32, + .offset = 56, + .width = 12, + }; + struct vcap_typegroup tgt[] = { + { .offset = 0, .width = 2, .value = 2, }, + { .offset = 156, .width = 1, .value = 1, }, + { .offset = 0, .width = 0, .value = 0, }, + }; + + vcap_test_api_init(&admin); + vcap_encode_keyfield(&rule, &ckf, &rf, tgt); + + /* Key */ + KUNIT_EXPECT_EQ(test, (u32)0x0, keywords[0]); + KUNIT_EXPECT_EQ(test, (u32)0x0, keywords[1]); + KUNIT_EXPECT_EQ(test, (u32)(0x04a1 << 6), keywords[2]); + KUNIT_EXPECT_EQ(test, (u32)0x0, keywords[3]); + KUNIT_EXPECT_EQ(test, (u32)0x0, keywords[4]); + KUNIT_EXPECT_EQ(test, (u32)0x0, keywords[5]); + KUNIT_EXPECT_EQ(test, (u32)0x0, keywords[6]); + + /* Mask */ + KUNIT_EXPECT_EQ(test, (u32)0x0, maskwords[0]); + KUNIT_EXPECT_EQ(test, (u32)0x0, maskwords[1]); + KUNIT_EXPECT_EQ(test, (u32)(0x0fff << 6), maskwords[2]); + KUNIT_EXPECT_EQ(test, (u32)0x0, maskwords[3]); + KUNIT_EXPECT_EQ(test, (u32)0x0, maskwords[4]); + KUNIT_EXPECT_EQ(test, (u32)0x0, maskwords[5]); + KUNIT_EXPECT_EQ(test, (u32)0x0, maskwords[6]); +} + +static void vcap_api_encode_max_keyfield_test(struct kunit *test) +{ + int idx; + u32 keywords[6] = {0}; + u32 maskwords[6] = {0}; + struct vcap_admin admin = { + .vtype = VCAP_TYPE_IS2, + /* IS2 sw_width = 52 bit */ + .cache = { + .keystream = keywords, + .maskstream = maskwords, + .actionstream = keywords, + }, + }; + struct vcap_rule_internal rule = { + .admin = &admin, + .data = { + .keyset = VCAP_KFS_IP_7TUPLE, + }, + .vctrl = &test_vctrl, + }; + struct vcap_client_keyfield ckf = { + .ctrl.list = {}, + .ctrl.key = VCAP_KF_L3_IP6_DIP, + .ctrl.type = VCAP_FIELD_U128, + .data.u128.value = { 0xa1, 0xa2, 0xa3, 0xa4, 0, 0, 0x43, 0, + 0, 0, 0, 0, 0, 0, 0x78, 0x8e, }, + .data.u128.mask = { 0xff, 0xff, 0xff, 0xff, 0, 0, 0xff, 0, + 0, 0, 0, 0, 0, 0, 0xff, 0xff }, + }; + struct vcap_field rf = { + .type = VCAP_FIELD_U128, + .offset = 0, + .width = 128, + }; + struct vcap_typegroup tgt[] = { + { .offset = 0, .width = 2, .value = 2, }, + { .offset = 156, .width = 1, .value = 1, }, + { .offset = 0, .width = 0, .value = 0, }, + }; + u32 keyres[] = { + 0x928e8a84, + 0x000c0002, + 0x00000010, + 0x00000000, + 0x0239e000, + 0x00000000, + }; + u32 mskres[] = { + 0xfffffffc, + 0x000c0003, + 0x0000003f, + 0x00000000, + 0x03fffc00, + 0x00000000, + }; + + vcap_encode_keyfield(&rule, &ckf, &rf, tgt); + + /* Key */ + for (idx = 0; idx < ARRAY_SIZE(keyres); ++idx) + KUNIT_EXPECT_EQ(test, keyres[idx], keywords[idx]); + /* Mask */ + for (idx = 0; idx < ARRAY_SIZE(mskres); ++idx) + KUNIT_EXPECT_EQ(test, mskres[idx], maskwords[idx]); +} + +static void vcap_api_encode_actionfield_test(struct kunit *test) +{ + u32 actwords[16] = {0}; + int sw_width = 21; + struct vcap_admin admin = { + .vtype = VCAP_TYPE_ES2, /* act_width = 21 */ + .cache = { + .actionstream = actwords, + }, + }; + struct vcap_rule_internal rule = { + .admin = &admin, + .data = { + .actionset = VCAP_AFS_BASE_TYPE, + }, + .vctrl = &test_vctrl, + }; + struct vcap_client_actionfield caf = { + .ctrl.list = {}, + .ctrl.action = VCAP_AF_POLICE_IDX, + .ctrl.type = VCAP_FIELD_U32, + .data.u32.value = 0x67908032, + }; + struct vcap_field rf = { + .type = VCAP_FIELD_U32, + .offset = 35, + .width = 6, + }; + struct vcap_typegroup tgt[] = { + { .offset = 0, .width = 2, .value = 2, }, + { .offset = 21, .width = 1, .value = 1, }, + { .offset = 42, .width = 1, .value = 0, }, + { .offset = 0, .width = 0, .value = 0, }, + }; + + vcap_encode_actionfield(&rule, &caf, &rf, tgt); + + /* Action */ + KUNIT_EXPECT_EQ(test, (u32)0x0, actwords[0]); + KUNIT_EXPECT_EQ(test, (u32)((0x32 << (35 + 2 + 1 - sw_width)) & 0x1fffff), actwords[1]); + KUNIT_EXPECT_EQ(test, (u32)((0x32 >> ((2 * sw_width) - 38 - 1))), actwords[2]); + KUNIT_EXPECT_EQ(test, (u32)0x0, actwords[3]); + KUNIT_EXPECT_EQ(test, (u32)0x0, actwords[4]); + KUNIT_EXPECT_EQ(test, (u32)0x0, actwords[5]); + KUNIT_EXPECT_EQ(test, (u32)0x0, actwords[6]); +} + +static void vcap_api_keyfield_typegroup_test(struct kunit *test) +{ + const struct vcap_typegroup *tg; + + tg = vcap_keyfield_typegroup(&test_vctrl, VCAP_TYPE_IS2, VCAP_KFS_MAC_ETYPE); + KUNIT_EXPECT_PTR_NE(test, NULL, tg); + KUNIT_EXPECT_EQ(test, 0, tg[0].offset); + KUNIT_EXPECT_EQ(test, 2, tg[0].width); + KUNIT_EXPECT_EQ(test, 2, tg[0].value); + KUNIT_EXPECT_EQ(test, 156, tg[1].offset); + KUNIT_EXPECT_EQ(test, 1, tg[1].width); + KUNIT_EXPECT_EQ(test, 0, tg[1].value); + KUNIT_EXPECT_EQ(test, 0, tg[2].offset); + KUNIT_EXPECT_EQ(test, 0, tg[2].width); + KUNIT_EXPECT_EQ(test, 0, tg[2].value); + + tg = vcap_keyfield_typegroup(&test_vctrl, VCAP_TYPE_ES2, VCAP_KFS_LL_FULL); + KUNIT_EXPECT_PTR_EQ(test, NULL, tg); +} + +static void vcap_api_actionfield_typegroup_test(struct kunit *test) +{ + const struct vcap_typegroup *tg; + + tg = vcap_actionfield_typegroup(&test_vctrl, VCAP_TYPE_IS0, VCAP_AFS_FULL); + KUNIT_EXPECT_PTR_NE(test, NULL, tg); + KUNIT_EXPECT_EQ(test, 0, tg[0].offset); + KUNIT_EXPECT_EQ(test, 3, tg[0].width); + KUNIT_EXPECT_EQ(test, 4, tg[0].value); + KUNIT_EXPECT_EQ(test, 110, tg[1].offset); + KUNIT_EXPECT_EQ(test, 2, tg[1].width); + KUNIT_EXPECT_EQ(test, 0, tg[1].value); + KUNIT_EXPECT_EQ(test, 220, tg[2].offset); + KUNIT_EXPECT_EQ(test, 2, tg[2].width); + KUNIT_EXPECT_EQ(test, 0, tg[2].value); + KUNIT_EXPECT_EQ(test, 0, tg[3].offset); + KUNIT_EXPECT_EQ(test, 0, tg[3].width); + KUNIT_EXPECT_EQ(test, 0, tg[3].value); + + tg = vcap_actionfield_typegroup(&test_vctrl, VCAP_TYPE_IS2, VCAP_AFS_CLASSIFICATION); + KUNIT_EXPECT_PTR_EQ(test, NULL, tg); +} + +static void vcap_api_vcap_keyfields_test(struct kunit *test) +{ + const struct vcap_field *ft; + + ft = vcap_keyfields(&test_vctrl, VCAP_TYPE_IS2, VCAP_KFS_MAC_ETYPE); + KUNIT_EXPECT_PTR_NE(test, NULL, ft); + + /* Keyset that is not available and within the maximum keyset enum value */ + ft = vcap_keyfields(&test_vctrl, VCAP_TYPE_ES2, VCAP_KFS_PURE_5TUPLE_IP4); + KUNIT_EXPECT_PTR_EQ(test, NULL, ft); + + /* Keyset that is not available and beyond the maximum keyset enum value */ + ft = vcap_keyfields(&test_vctrl, VCAP_TYPE_ES2, VCAP_KFS_LL_FULL); + KUNIT_EXPECT_PTR_EQ(test, NULL, ft); +} + +static void vcap_api_vcap_actionfields_test(struct kunit *test) +{ + const struct vcap_field *ft; + + ft = vcap_actionfields(&test_vctrl, VCAP_TYPE_IS0, VCAP_AFS_FULL); + KUNIT_EXPECT_PTR_NE(test, NULL, ft); + + ft = vcap_actionfields(&test_vctrl, VCAP_TYPE_IS2, VCAP_AFS_FULL); + KUNIT_EXPECT_PTR_EQ(test, NULL, ft); + + ft = vcap_actionfields(&test_vctrl, VCAP_TYPE_IS2, VCAP_AFS_CLASSIFICATION); + KUNIT_EXPECT_PTR_EQ(test, NULL, ft); +} + +static void vcap_api_encode_rule_keyset_test(struct kunit *test) +{ + u32 keywords[16] = {0}; + u32 maskwords[16] = {0}; + struct vcap_admin admin = { + .vtype = VCAP_TYPE_IS2, + .cache = { + .keystream = keywords, + .maskstream = maskwords, + }, + }; + struct vcap_rule_internal rule = { + .admin = &admin, + .data = { + .keyset = VCAP_KFS_MAC_ETYPE, + }, + .vctrl = &test_vctrl, + }; + struct vcap_client_keyfield ckf[] = { + { + .ctrl.key = VCAP_KF_TYPE, + .ctrl.type = VCAP_FIELD_U32, + .data.u32.value = 0x00, + .data.u32.mask = 0x0f, + }, + { + .ctrl.key = VCAP_KF_LOOKUP_FIRST_IS, + .ctrl.type = VCAP_FIELD_BIT, + .data.u1.value = 0x01, + .data.u1.mask = 0x01, + }, + { + .ctrl.key = VCAP_KF_IF_IGR_PORT_MASK_L3, + .ctrl.type = VCAP_FIELD_BIT, + .data.u1.value = 0x00, + .data.u1.mask = 0x01, + }, + { + .ctrl.key = VCAP_KF_IF_IGR_PORT_MASK_RNG, + .ctrl.type = VCAP_FIELD_U32, + .data.u32.value = 0x00, + .data.u32.mask = 0x0f, + }, + { + .ctrl.key = VCAP_KF_IF_IGR_PORT_MASK, + .ctrl.type = VCAP_FIELD_U72, + .data.u72.value = {0x0, 0x00, 0x00, 0x00}, + .data.u72.mask = {0xfd, 0xff, 0xff, 0xff}, + }, + { + .ctrl.key = VCAP_KF_L2_DMAC, + .ctrl.type = VCAP_FIELD_U48, + /* Opposite endianness */ + .data.u48.value = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, + .data.u48.mask = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + }, + { + .ctrl.key = VCAP_KF_ETYPE_LEN_IS, + .ctrl.type = VCAP_FIELD_BIT, + .data.u1.value = 0x01, + .data.u1.mask = 0x01, + }, + { + .ctrl.key = VCAP_KF_ETYPE, + .ctrl.type = VCAP_FIELD_U32, + .data.u32.value = 0xaabb, + .data.u32.mask = 0xffff, + }, + }; + int idx; + int ret; + + /* Empty entry list */ + INIT_LIST_HEAD(&rule.data.keyfields); + ret = vcap_encode_rule_keyset(&rule); + KUNIT_EXPECT_EQ(test, -EINVAL, ret); + + for (idx = 0; idx < ARRAY_SIZE(ckf); idx++) + list_add_tail(&ckf[idx].ctrl.list, &rule.data.keyfields); + ret = vcap_encode_rule_keyset(&rule); + KUNIT_EXPECT_EQ(test, 0, ret); + + /* The key and mask values below are from an actual Sparx5 rule config */ + /* Key */ + KUNIT_EXPECT_EQ(test, (u32)0x00000042, keywords[0]); + KUNIT_EXPECT_EQ(test, (u32)0x00000000, keywords[1]); + KUNIT_EXPECT_EQ(test, (u32)0x00000000, keywords[2]); + KUNIT_EXPECT_EQ(test, (u32)0x00020100, keywords[3]); + KUNIT_EXPECT_EQ(test, (u32)0x60504030, keywords[4]); + KUNIT_EXPECT_EQ(test, (u32)0x00000000, keywords[5]); + KUNIT_EXPECT_EQ(test, (u32)0x00000000, keywords[6]); + KUNIT_EXPECT_EQ(test, (u32)0x0002aaee, keywords[7]); + KUNIT_EXPECT_EQ(test, (u32)0x00000000, keywords[8]); + KUNIT_EXPECT_EQ(test, (u32)0x00000000, keywords[9]); + KUNIT_EXPECT_EQ(test, (u32)0x00000000, keywords[10]); + KUNIT_EXPECT_EQ(test, (u32)0x00000000, keywords[11]); + + /* Mask: they will be inverted when applied to the register */ + KUNIT_EXPECT_EQ(test, (u32)~0x00b07f80, maskwords[0]); + KUNIT_EXPECT_EQ(test, (u32)~0xfff00000, maskwords[1]); + KUNIT_EXPECT_EQ(test, (u32)~0xfffffffc, maskwords[2]); + KUNIT_EXPECT_EQ(test, (u32)~0xfff000ff, maskwords[3]); + KUNIT_EXPECT_EQ(test, (u32)~0x00000000, maskwords[4]); + KUNIT_EXPECT_EQ(test, (u32)~0xfffffff0, maskwords[5]); + KUNIT_EXPECT_EQ(test, (u32)~0xfffffffe, maskwords[6]); + KUNIT_EXPECT_EQ(test, (u32)~0xfffc0001, maskwords[7]); + KUNIT_EXPECT_EQ(test, (u32)~0xffffffff, maskwords[8]); + KUNIT_EXPECT_EQ(test, (u32)~0xffffffff, maskwords[9]); + KUNIT_EXPECT_EQ(test, (u32)~0xffffffff, maskwords[10]); + KUNIT_EXPECT_EQ(test, (u32)~0xffffffff, maskwords[11]); +} + +static void vcap_api_encode_rule_actionset_test(struct kunit *test) +{ + u32 actwords[16] = {0}; + struct vcap_admin admin = { + .vtype = VCAP_TYPE_IS2, + .cache = { + .actionstream = actwords, + }, + }; + struct vcap_rule_internal rule = { + .admin = &admin, + .data = { + .actionset = VCAP_AFS_BASE_TYPE, + }, + .vctrl = &test_vctrl, + }; + struct vcap_client_actionfield caf[] = { + { + .ctrl.action = VCAP_AF_MATCH_ID, + .ctrl.type = VCAP_FIELD_U32, + .data.u32.value = 0x01, + }, + { + .ctrl.action = VCAP_AF_MATCH_ID_MASK, + .ctrl.type = VCAP_FIELD_U32, + .data.u32.value = 0x01, + }, + { + .ctrl.action = VCAP_AF_CNT_ID, + .ctrl.type = VCAP_FIELD_U32, + .data.u32.value = 0x64, + }, + }; + int idx; + int ret; + + /* Empty entry list */ + INIT_LIST_HEAD(&rule.data.actionfields); + ret = vcap_encode_rule_actionset(&rule); + /* We allow rules with no actions */ + KUNIT_EXPECT_EQ(test, 0, ret); + + for (idx = 0; idx < ARRAY_SIZE(caf); idx++) + list_add_tail(&caf[idx].ctrl.list, &rule.data.actionfields); + ret = vcap_encode_rule_actionset(&rule); + KUNIT_EXPECT_EQ(test, 0, ret); + + /* The action values below are from an actual Sparx5 rule config */ + KUNIT_EXPECT_EQ(test, (u32)0x00000002, actwords[0]); + KUNIT_EXPECT_EQ(test, (u32)0x00000000, actwords[1]); + KUNIT_EXPECT_EQ(test, (u32)0x00000000, actwords[2]); + KUNIT_EXPECT_EQ(test, (u32)0x00000000, actwords[3]); + KUNIT_EXPECT_EQ(test, (u32)0x00000000, actwords[4]); + KUNIT_EXPECT_EQ(test, (u32)0x00100000, actwords[5]); + KUNIT_EXPECT_EQ(test, (u32)0x06400010, actwords[6]); + KUNIT_EXPECT_EQ(test, (u32)0x00000000, actwords[7]); + KUNIT_EXPECT_EQ(test, (u32)0x00000000, actwords[8]); + KUNIT_EXPECT_EQ(test, (u32)0x00000000, actwords[9]); + KUNIT_EXPECT_EQ(test, (u32)0x00000000, actwords[10]); + KUNIT_EXPECT_EQ(test, (u32)0x00000000, actwords[11]); +} + +static struct kunit_case vcap_api_encoding_test_cases[] = { + KUNIT_CASE(vcap_api_set_bit_1_test), + KUNIT_CASE(vcap_api_set_bit_0_test), + KUNIT_CASE(vcap_api_iterator_init_test), + KUNIT_CASE(vcap_api_iterator_next_test), + KUNIT_CASE(vcap_api_encode_typegroups_test), + KUNIT_CASE(vcap_api_encode_bit_test), + KUNIT_CASE(vcap_api_encode_field_test), + KUNIT_CASE(vcap_api_encode_short_field_test), + KUNIT_CASE(vcap_api_encode_keyfield_test), + KUNIT_CASE(vcap_api_encode_max_keyfield_test), + KUNIT_CASE(vcap_api_encode_actionfield_test), + KUNIT_CASE(vcap_api_keyfield_typegroup_test), + KUNIT_CASE(vcap_api_actionfield_typegroup_test), + KUNIT_CASE(vcap_api_vcap_keyfields_test), + KUNIT_CASE(vcap_api_vcap_actionfields_test), + KUNIT_CASE(vcap_api_encode_rule_keyset_test), + KUNIT_CASE(vcap_api_encode_rule_actionset_test), + {} +}; + +static struct kunit_suite vcap_api_encoding_test_suite = { + .name = "VCAP_API_Encoding_Testsuite", + .test_cases = vcap_api_encoding_test_cases, +}; + +kunit_test_suite(vcap_api_encoding_test_suite); diff --git a/drivers/net/ethernet/microchip/vcap/vcap_model_kunit.c b/drivers/net/ethernet/microchip/vcap/vcap_model_kunit.c new file mode 100644 index 000000000000..5d681d2697cd --- /dev/null +++ b/drivers/net/ethernet/microchip/vcap/vcap_model_kunit.c @@ -0,0 +1,5570 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* Copyright (C) 2022 Microchip Technology Inc. and its subsidiaries. + * Microchip VCAP API Test VCAP Model Data + */ + +#include <linux/types.h> +#include <linux/kernel.h> + +#include "vcap_api.h" +#include "vcap_model_kunit.h" + +/* keyfields */ +static const struct vcap_field is0_mll_keyfield[] = { + [VCAP_KF_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 0, + .width = 2, + }, + [VCAP_KF_LOOKUP_FIRST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 2, + .width = 1, + }, + [VCAP_KF_IF_IGR_PORT] = { + .type = VCAP_FIELD_U32, + .offset = 3, + .width = 7, + }, + [VCAP_KF_8021Q_VLAN_TAGS] = { + .type = VCAP_FIELD_U32, + .offset = 10, + .width = 3, + }, + [VCAP_KF_8021Q_TPID0] = { + .type = VCAP_FIELD_U32, + .offset = 13, + .width = 3, + }, + [VCAP_KF_8021Q_VID0] = { + .type = VCAP_FIELD_U32, + .offset = 16, + .width = 12, + }, + [VCAP_KF_8021Q_TPID1] = { + .type = VCAP_FIELD_U32, + .offset = 28, + .width = 3, + }, + [VCAP_KF_8021Q_VID1] = { + .type = VCAP_FIELD_U32, + .offset = 31, + .width = 12, + }, + [VCAP_KF_L2_DMAC] = { + .type = VCAP_FIELD_U48, + .offset = 43, + .width = 48, + }, + [VCAP_KF_L2_SMAC] = { + .type = VCAP_FIELD_U48, + .offset = 91, + .width = 48, + }, + [VCAP_KF_ETYPE_MPLS] = { + .type = VCAP_FIELD_U32, + .offset = 139, + .width = 2, + }, + [VCAP_KF_L4_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 141, + .width = 8, + }, +}; + +static const struct vcap_field is0_tri_vid_keyfield[] = { + [VCAP_KF_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 0, + .width = 2, + }, + [VCAP_KF_LOOKUP_FIRST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 2, + .width = 1, + }, + [VCAP_KF_IF_IGR_PORT] = { + .type = VCAP_FIELD_U32, + .offset = 3, + .width = 7, + }, + [VCAP_KF_LOOKUP_GEN_IDX_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 10, + .width = 2, + }, + [VCAP_KF_LOOKUP_GEN_IDX] = { + .type = VCAP_FIELD_U32, + .offset = 12, + .width = 12, + }, + [VCAP_KF_8021Q_VLAN_TAGS] = { + .type = VCAP_FIELD_U32, + .offset = 24, + .width = 3, + }, + [VCAP_KF_8021Q_TPID0] = { + .type = VCAP_FIELD_U32, + .offset = 27, + .width = 3, + }, + [VCAP_KF_8021Q_PCP0] = { + .type = VCAP_FIELD_U32, + .offset = 30, + .width = 3, + }, + [VCAP_KF_8021Q_DEI0] = { + .type = VCAP_FIELD_BIT, + .offset = 33, + .width = 1, + }, + [VCAP_KF_8021Q_VID0] = { + .type = VCAP_FIELD_U32, + .offset = 34, + .width = 12, + }, + [VCAP_KF_8021Q_TPID1] = { + .type = VCAP_FIELD_U32, + .offset = 46, + .width = 3, + }, + [VCAP_KF_8021Q_PCP1] = { + .type = VCAP_FIELD_U32, + .offset = 49, + .width = 3, + }, + [VCAP_KF_8021Q_DEI1] = { + .type = VCAP_FIELD_BIT, + .offset = 52, + .width = 1, + }, + [VCAP_KF_8021Q_VID1] = { + .type = VCAP_FIELD_U32, + .offset = 53, + .width = 12, + }, + [VCAP_KF_8021Q_TPID2] = { + .type = VCAP_FIELD_U32, + .offset = 65, + .width = 3, + }, + [VCAP_KF_8021Q_PCP2] = { + .type = VCAP_FIELD_U32, + .offset = 68, + .width = 3, + }, + [VCAP_KF_8021Q_DEI2] = { + .type = VCAP_FIELD_BIT, + .offset = 71, + .width = 1, + }, + [VCAP_KF_8021Q_VID2] = { + .type = VCAP_FIELD_U32, + .offset = 72, + .width = 12, + }, + [VCAP_KF_L4_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 84, + .width = 8, + }, + [VCAP_KF_OAM_Y1731_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 92, + .width = 1, + }, + [VCAP_KF_OAM_MEL_FLAGS] = { + .type = VCAP_FIELD_U32, + .offset = 93, + .width = 7, + }, +}; + +static const struct vcap_field is0_ll_full_keyfield[] = { + [VCAP_KF_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 0, + .width = 2, + }, + [VCAP_KF_LOOKUP_FIRST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 2, + .width = 1, + }, + [VCAP_KF_IF_IGR_PORT] = { + .type = VCAP_FIELD_U32, + .offset = 3, + .width = 7, + }, + [VCAP_KF_8021Q_VLAN_TAGS] = { + .type = VCAP_FIELD_U32, + .offset = 10, + .width = 3, + }, + [VCAP_KF_8021Q_TPID0] = { + .type = VCAP_FIELD_U32, + .offset = 13, + .width = 3, + }, + [VCAP_KF_8021Q_PCP0] = { + .type = VCAP_FIELD_U32, + .offset = 16, + .width = 3, + }, + [VCAP_KF_8021Q_DEI0] = { + .type = VCAP_FIELD_BIT, + .offset = 19, + .width = 1, + }, + [VCAP_KF_8021Q_VID0] = { + .type = VCAP_FIELD_U32, + .offset = 20, + .width = 12, + }, + [VCAP_KF_8021Q_TPID1] = { + .type = VCAP_FIELD_U32, + .offset = 32, + .width = 3, + }, + [VCAP_KF_8021Q_PCP1] = { + .type = VCAP_FIELD_U32, + .offset = 35, + .width = 3, + }, + [VCAP_KF_8021Q_DEI1] = { + .type = VCAP_FIELD_BIT, + .offset = 38, + .width = 1, + }, + [VCAP_KF_8021Q_VID1] = { + .type = VCAP_FIELD_U32, + .offset = 39, + .width = 12, + }, + [VCAP_KF_8021Q_TPID2] = { + .type = VCAP_FIELD_U32, + .offset = 51, + .width = 3, + }, + [VCAP_KF_8021Q_PCP2] = { + .type = VCAP_FIELD_U32, + .offset = 54, + .width = 3, + }, + [VCAP_KF_8021Q_DEI2] = { + .type = VCAP_FIELD_BIT, + .offset = 57, + .width = 1, + }, + [VCAP_KF_8021Q_VID2] = { + .type = VCAP_FIELD_U32, + .offset = 58, + .width = 12, + }, + [VCAP_KF_L2_DMAC] = { + .type = VCAP_FIELD_U48, + .offset = 70, + .width = 48, + }, + [VCAP_KF_L2_SMAC] = { + .type = VCAP_FIELD_U48, + .offset = 118, + .width = 48, + }, + [VCAP_KF_ETYPE_LEN_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 166, + .width = 1, + }, + [VCAP_KF_ETYPE] = { + .type = VCAP_FIELD_U32, + .offset = 167, + .width = 16, + }, + [VCAP_KF_IP_SNAP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 183, + .width = 1, + }, + [VCAP_KF_IP4_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 184, + .width = 1, + }, + [VCAP_KF_L3_FRAGMENT_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 185, + .width = 2, + }, + [VCAP_KF_L3_FRAG_INVLD_L4_LEN] = { + .type = VCAP_FIELD_BIT, + .offset = 187, + .width = 1, + }, + [VCAP_KF_L3_OPTIONS_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 188, + .width = 1, + }, + [VCAP_KF_L3_DSCP] = { + .type = VCAP_FIELD_U32, + .offset = 189, + .width = 6, + }, + [VCAP_KF_L3_IP4_DIP] = { + .type = VCAP_FIELD_U32, + .offset = 195, + .width = 32, + }, + [VCAP_KF_L3_IP4_SIP] = { + .type = VCAP_FIELD_U32, + .offset = 227, + .width = 32, + }, + [VCAP_KF_TCP_UDP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 259, + .width = 1, + }, + [VCAP_KF_TCP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 260, + .width = 1, + }, + [VCAP_KF_L4_SPORT] = { + .type = VCAP_FIELD_U32, + .offset = 261, + .width = 16, + }, + [VCAP_KF_L4_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 277, + .width = 8, + }, +}; + +static const struct vcap_field is0_normal_keyfield[] = { + [VCAP_KF_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 0, + .width = 2, + }, + [VCAP_KF_LOOKUP_FIRST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 2, + .width = 1, + }, + [VCAP_KF_LOOKUP_GEN_IDX_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 3, + .width = 2, + }, + [VCAP_KF_LOOKUP_GEN_IDX] = { + .type = VCAP_FIELD_U32, + .offset = 5, + .width = 12, + }, + [VCAP_KF_IF_IGR_PORT_MASK_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 17, + .width = 2, + }, + [VCAP_KF_IF_IGR_PORT_MASK] = { + .type = VCAP_FIELD_U72, + .offset = 19, + .width = 65, + }, + [VCAP_KF_L2_MC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 84, + .width = 1, + }, + [VCAP_KF_L2_BC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 85, + .width = 1, + }, + [VCAP_KF_8021Q_VLAN_TAGS] = { + .type = VCAP_FIELD_U32, + .offset = 86, + .width = 3, + }, + [VCAP_KF_8021Q_TPID0] = { + .type = VCAP_FIELD_U32, + .offset = 89, + .width = 3, + }, + [VCAP_KF_8021Q_PCP0] = { + .type = VCAP_FIELD_U32, + .offset = 92, + .width = 3, + }, + [VCAP_KF_8021Q_DEI0] = { + .type = VCAP_FIELD_BIT, + .offset = 95, + .width = 1, + }, + [VCAP_KF_8021Q_VID0] = { + .type = VCAP_FIELD_U32, + .offset = 96, + .width = 12, + }, + [VCAP_KF_8021Q_TPID1] = { + .type = VCAP_FIELD_U32, + .offset = 108, + .width = 3, + }, + [VCAP_KF_8021Q_PCP1] = { + .type = VCAP_FIELD_U32, + .offset = 111, + .width = 3, + }, + [VCAP_KF_8021Q_DEI1] = { + .type = VCAP_FIELD_BIT, + .offset = 114, + .width = 1, + }, + [VCAP_KF_8021Q_VID1] = { + .type = VCAP_FIELD_U32, + .offset = 115, + .width = 12, + }, + [VCAP_KF_8021Q_TPID2] = { + .type = VCAP_FIELD_U32, + .offset = 127, + .width = 3, + }, + [VCAP_KF_8021Q_PCP2] = { + .type = VCAP_FIELD_U32, + .offset = 130, + .width = 3, + }, + [VCAP_KF_8021Q_DEI2] = { + .type = VCAP_FIELD_BIT, + .offset = 133, + .width = 1, + }, + [VCAP_KF_8021Q_VID2] = { + .type = VCAP_FIELD_U32, + .offset = 134, + .width = 12, + }, + [VCAP_KF_DST_ENTRY] = { + .type = VCAP_FIELD_BIT, + .offset = 146, + .width = 1, + }, + [VCAP_KF_L2_SMAC] = { + .type = VCAP_FIELD_U48, + .offset = 147, + .width = 48, + }, + [VCAP_KF_IP_MC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 195, + .width = 1, + }, + [VCAP_KF_ETYPE_LEN_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 196, + .width = 1, + }, + [VCAP_KF_ETYPE] = { + .type = VCAP_FIELD_U32, + .offset = 197, + .width = 16, + }, + [VCAP_KF_IP_SNAP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 213, + .width = 1, + }, + [VCAP_KF_IP4_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 214, + .width = 1, + }, + [VCAP_KF_L3_FRAGMENT_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 215, + .width = 2, + }, + [VCAP_KF_L3_FRAG_INVLD_L4_LEN] = { + .type = VCAP_FIELD_BIT, + .offset = 217, + .width = 1, + }, + [VCAP_KF_L3_OPTIONS_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 218, + .width = 1, + }, + [VCAP_KF_L3_DSCP] = { + .type = VCAP_FIELD_U32, + .offset = 219, + .width = 6, + }, + [VCAP_KF_L3_IP4_SIP] = { + .type = VCAP_FIELD_U32, + .offset = 225, + .width = 32, + }, + [VCAP_KF_TCP_UDP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 257, + .width = 1, + }, + [VCAP_KF_TCP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 258, + .width = 1, + }, + [VCAP_KF_L4_SPORT] = { + .type = VCAP_FIELD_U32, + .offset = 259, + .width = 16, + }, + [VCAP_KF_L4_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 275, + .width = 8, + }, +}; + +static const struct vcap_field is0_normal_7tuple_keyfield[] = { + [VCAP_KF_TYPE] = { + .type = VCAP_FIELD_BIT, + .offset = 0, + .width = 1, + }, + [VCAP_KF_LOOKUP_FIRST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 1, + .width = 1, + }, + [VCAP_KF_LOOKUP_GEN_IDX_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 2, + .width = 2, + }, + [VCAP_KF_LOOKUP_GEN_IDX] = { + .type = VCAP_FIELD_U32, + .offset = 4, + .width = 12, + }, + [VCAP_KF_IF_IGR_PORT_MASK_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 16, + .width = 2, + }, + [VCAP_KF_IF_IGR_PORT_MASK] = { + .type = VCAP_FIELD_U72, + .offset = 18, + .width = 65, + }, + [VCAP_KF_L2_MC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 83, + .width = 1, + }, + [VCAP_KF_L2_BC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 84, + .width = 1, + }, + [VCAP_KF_8021Q_VLAN_TAGS] = { + .type = VCAP_FIELD_U32, + .offset = 85, + .width = 3, + }, + [VCAP_KF_8021Q_TPID0] = { + .type = VCAP_FIELD_U32, + .offset = 88, + .width = 3, + }, + [VCAP_KF_8021Q_PCP0] = { + .type = VCAP_FIELD_U32, + .offset = 91, + .width = 3, + }, + [VCAP_KF_8021Q_DEI0] = { + .type = VCAP_FIELD_BIT, + .offset = 94, + .width = 1, + }, + [VCAP_KF_8021Q_VID0] = { + .type = VCAP_FIELD_U32, + .offset = 95, + .width = 12, + }, + [VCAP_KF_8021Q_TPID1] = { + .type = VCAP_FIELD_U32, + .offset = 107, + .width = 3, + }, + [VCAP_KF_8021Q_PCP1] = { + .type = VCAP_FIELD_U32, + .offset = 110, + .width = 3, + }, + [VCAP_KF_8021Q_DEI1] = { + .type = VCAP_FIELD_BIT, + .offset = 113, + .width = 1, + }, + [VCAP_KF_8021Q_VID1] = { + .type = VCAP_FIELD_U32, + .offset = 114, + .width = 12, + }, + [VCAP_KF_8021Q_TPID2] = { + .type = VCAP_FIELD_U32, + .offset = 126, + .width = 3, + }, + [VCAP_KF_8021Q_PCP2] = { + .type = VCAP_FIELD_U32, + .offset = 129, + .width = 3, + }, + [VCAP_KF_8021Q_DEI2] = { + .type = VCAP_FIELD_BIT, + .offset = 132, + .width = 1, + }, + [VCAP_KF_8021Q_VID2] = { + .type = VCAP_FIELD_U32, + .offset = 133, + .width = 12, + }, + [VCAP_KF_L2_DMAC] = { + .type = VCAP_FIELD_U48, + .offset = 145, + .width = 48, + }, + [VCAP_KF_L2_SMAC] = { + .type = VCAP_FIELD_U48, + .offset = 193, + .width = 48, + }, + [VCAP_KF_IP_MC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 241, + .width = 1, + }, + [VCAP_KF_ETYPE_LEN_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 242, + .width = 1, + }, + [VCAP_KF_ETYPE] = { + .type = VCAP_FIELD_U32, + .offset = 243, + .width = 16, + }, + [VCAP_KF_IP_SNAP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 259, + .width = 1, + }, + [VCAP_KF_IP4_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 260, + .width = 1, + }, + [VCAP_KF_L3_FRAGMENT_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 261, + .width = 2, + }, + [VCAP_KF_L3_FRAG_INVLD_L4_LEN] = { + .type = VCAP_FIELD_BIT, + .offset = 263, + .width = 1, + }, + [VCAP_KF_L3_OPTIONS_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 264, + .width = 1, + }, + [VCAP_KF_L3_DSCP] = { + .type = VCAP_FIELD_U32, + .offset = 265, + .width = 6, + }, + [VCAP_KF_L3_IP6_DIP] = { + .type = VCAP_FIELD_U128, + .offset = 271, + .width = 128, + }, + [VCAP_KF_L3_IP6_SIP] = { + .type = VCAP_FIELD_U128, + .offset = 399, + .width = 128, + }, + [VCAP_KF_TCP_UDP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 527, + .width = 1, + }, + [VCAP_KF_TCP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 528, + .width = 1, + }, + [VCAP_KF_L4_SPORT] = { + .type = VCAP_FIELD_U32, + .offset = 529, + .width = 16, + }, + [VCAP_KF_L4_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 545, + .width = 8, + }, +}; + +static const struct vcap_field is0_normal_5tuple_ip4_keyfield[] = { + [VCAP_KF_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 0, + .width = 2, + }, + [VCAP_KF_LOOKUP_FIRST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 2, + .width = 1, + }, + [VCAP_KF_LOOKUP_GEN_IDX_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 3, + .width = 2, + }, + [VCAP_KF_LOOKUP_GEN_IDX] = { + .type = VCAP_FIELD_U32, + .offset = 5, + .width = 12, + }, + [VCAP_KF_IF_IGR_PORT_MASK_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 17, + .width = 2, + }, + [VCAP_KF_IF_IGR_PORT_MASK] = { + .type = VCAP_FIELD_U72, + .offset = 19, + .width = 65, + }, + [VCAP_KF_L2_MC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 84, + .width = 1, + }, + [VCAP_KF_L2_BC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 85, + .width = 1, + }, + [VCAP_KF_8021Q_VLAN_TAGS] = { + .type = VCAP_FIELD_U32, + .offset = 86, + .width = 3, + }, + [VCAP_KF_8021Q_TPID0] = { + .type = VCAP_FIELD_U32, + .offset = 89, + .width = 3, + }, + [VCAP_KF_8021Q_PCP0] = { + .type = VCAP_FIELD_U32, + .offset = 92, + .width = 3, + }, + [VCAP_KF_8021Q_DEI0] = { + .type = VCAP_FIELD_BIT, + .offset = 95, + .width = 1, + }, + [VCAP_KF_8021Q_VID0] = { + .type = VCAP_FIELD_U32, + .offset = 96, + .width = 12, + }, + [VCAP_KF_8021Q_TPID1] = { + .type = VCAP_FIELD_U32, + .offset = 108, + .width = 3, + }, + [VCAP_KF_8021Q_PCP1] = { + .type = VCAP_FIELD_U32, + .offset = 111, + .width = 3, + }, + [VCAP_KF_8021Q_DEI1] = { + .type = VCAP_FIELD_BIT, + .offset = 114, + .width = 1, + }, + [VCAP_KF_8021Q_VID1] = { + .type = VCAP_FIELD_U32, + .offset = 115, + .width = 12, + }, + [VCAP_KF_8021Q_TPID2] = { + .type = VCAP_FIELD_U32, + .offset = 127, + .width = 3, + }, + [VCAP_KF_8021Q_PCP2] = { + .type = VCAP_FIELD_U32, + .offset = 130, + .width = 3, + }, + [VCAP_KF_8021Q_DEI2] = { + .type = VCAP_FIELD_BIT, + .offset = 133, + .width = 1, + }, + [VCAP_KF_8021Q_VID2] = { + .type = VCAP_FIELD_U32, + .offset = 134, + .width = 12, + }, + [VCAP_KF_IP_MC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 146, + .width = 1, + }, + [VCAP_KF_IP4_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 147, + .width = 1, + }, + [VCAP_KF_L3_FRAGMENT_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 148, + .width = 2, + }, + [VCAP_KF_L3_FRAG_INVLD_L4_LEN] = { + .type = VCAP_FIELD_BIT, + .offset = 150, + .width = 1, + }, + [VCAP_KF_L3_OPTIONS_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 151, + .width = 1, + }, + [VCAP_KF_L3_DSCP] = { + .type = VCAP_FIELD_U32, + .offset = 152, + .width = 6, + }, + [VCAP_KF_L3_IP4_DIP] = { + .type = VCAP_FIELD_U32, + .offset = 158, + .width = 32, + }, + [VCAP_KF_L3_IP4_SIP] = { + .type = VCAP_FIELD_U32, + .offset = 190, + .width = 32, + }, + [VCAP_KF_L3_IP_PROTO] = { + .type = VCAP_FIELD_U32, + .offset = 222, + .width = 8, + }, + [VCAP_KF_TCP_UDP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 230, + .width = 1, + }, + [VCAP_KF_TCP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 231, + .width = 1, + }, + [VCAP_KF_L4_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 232, + .width = 8, + }, + [VCAP_KF_IP_PAYLOAD_5TUPLE] = { + .type = VCAP_FIELD_U32, + .offset = 240, + .width = 32, + }, +}; + +static const struct vcap_field is0_pure_5tuple_ip4_keyfield[] = { + [VCAP_KF_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 0, + .width = 2, + }, + [VCAP_KF_LOOKUP_FIRST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 2, + .width = 1, + }, + [VCAP_KF_LOOKUP_GEN_IDX_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 3, + .width = 2, + }, + [VCAP_KF_LOOKUP_GEN_IDX] = { + .type = VCAP_FIELD_U32, + .offset = 5, + .width = 12, + }, + [VCAP_KF_L3_FRAGMENT_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 17, + .width = 2, + }, + [VCAP_KF_L3_FRAG_INVLD_L4_LEN] = { + .type = VCAP_FIELD_BIT, + .offset = 19, + .width = 1, + }, + [VCAP_KF_L3_OPTIONS_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 20, + .width = 1, + }, + [VCAP_KF_L3_DSCP] = { + .type = VCAP_FIELD_U32, + .offset = 21, + .width = 6, + }, + [VCAP_KF_L3_IP4_DIP] = { + .type = VCAP_FIELD_U32, + .offset = 27, + .width = 32, + }, + [VCAP_KF_L3_IP4_SIP] = { + .type = VCAP_FIELD_U32, + .offset = 59, + .width = 32, + }, + [VCAP_KF_L3_IP_PROTO] = { + .type = VCAP_FIELD_U32, + .offset = 91, + .width = 8, + }, + [VCAP_KF_L4_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 99, + .width = 8, + }, + [VCAP_KF_IP_PAYLOAD_5TUPLE] = { + .type = VCAP_FIELD_U32, + .offset = 107, + .width = 32, + }, +}; + +static const struct vcap_field is0_etag_keyfield[] = { + [VCAP_KF_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 0, + .width = 2, + }, + [VCAP_KF_LOOKUP_FIRST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 2, + .width = 1, + }, + [VCAP_KF_IF_IGR_PORT] = { + .type = VCAP_FIELD_U32, + .offset = 3, + .width = 7, + }, + [VCAP_KF_8021BR_E_TAGGED] = { + .type = VCAP_FIELD_BIT, + .offset = 10, + .width = 1, + }, + [VCAP_KF_8021BR_GRP] = { + .type = VCAP_FIELD_U32, + .offset = 11, + .width = 2, + }, + [VCAP_KF_8021BR_ECID_EXT] = { + .type = VCAP_FIELD_U32, + .offset = 13, + .width = 8, + }, + [VCAP_KF_8021BR_ECID_BASE] = { + .type = VCAP_FIELD_U32, + .offset = 21, + .width = 12, + }, + [VCAP_KF_8021BR_IGR_ECID_EXT] = { + .type = VCAP_FIELD_U32, + .offset = 33, + .width = 8, + }, + [VCAP_KF_8021BR_IGR_ECID_BASE] = { + .type = VCAP_FIELD_U32, + .offset = 41, + .width = 12, + }, +}; + +static const struct vcap_field is2_mac_etype_keyfield[] = { + [VCAP_KF_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 0, + .width = 4, + }, + [VCAP_KF_LOOKUP_FIRST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 4, + .width = 1, + }, + [VCAP_KF_LOOKUP_PAG] = { + .type = VCAP_FIELD_U32, + .offset = 5, + .width = 8, + }, + [VCAP_KF_IF_IGR_PORT_MASK_L3] = { + .type = VCAP_FIELD_BIT, + .offset = 13, + .width = 1, + }, + [VCAP_KF_IF_IGR_PORT_MASK_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 14, + .width = 4, + }, + [VCAP_KF_IF_IGR_PORT_MASK_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 18, + .width = 2, + }, + [VCAP_KF_IF_IGR_PORT_MASK] = { + .type = VCAP_FIELD_U32, + .offset = 20, + .width = 32, + }, + [VCAP_KF_L2_MC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 52, + .width = 1, + }, + [VCAP_KF_L2_BC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 53, + .width = 1, + }, + [VCAP_KF_8021Q_VLAN_TAGGED_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 54, + .width = 1, + }, + [VCAP_KF_ISDX_GT0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 55, + .width = 1, + }, + [VCAP_KF_ISDX_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 56, + .width = 12, + }, + [VCAP_KF_8021Q_VID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 68, + .width = 13, + }, + [VCAP_KF_8021Q_DEI_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 81, + .width = 1, + }, + [VCAP_KF_8021Q_PCP_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 82, + .width = 3, + }, + [VCAP_KF_L2_FWD_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 85, + .width = 1, + }, + [VCAP_KF_L3_SMAC_SIP_MATCH] = { + .type = VCAP_FIELD_BIT, + .offset = 86, + .width = 1, + }, + [VCAP_KF_L3_DMAC_DIP_MATCH] = { + .type = VCAP_FIELD_BIT, + .offset = 87, + .width = 1, + }, + [VCAP_KF_L3_RT_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 88, + .width = 1, + }, + [VCAP_KF_L3_DST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 89, + .width = 1, + }, + [VCAP_KF_L2_DMAC] = { + .type = VCAP_FIELD_U48, + .offset = 90, + .width = 48, + }, + [VCAP_KF_L2_SMAC] = { + .type = VCAP_FIELD_U48, + .offset = 138, + .width = 48, + }, + [VCAP_KF_ETYPE_LEN_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 186, + .width = 1, + }, + [VCAP_KF_ETYPE] = { + .type = VCAP_FIELD_U32, + .offset = 187, + .width = 16, + }, + [VCAP_KF_L2_PAYLOAD_ETYPE] = { + .type = VCAP_FIELD_U64, + .offset = 203, + .width = 64, + }, + [VCAP_KF_L4_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 267, + .width = 16, + }, + [VCAP_KF_OAM_CCM_CNTS_EQ0] = { + .type = VCAP_FIELD_BIT, + .offset = 283, + .width = 1, + }, + [VCAP_KF_OAM_Y1731_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 284, + .width = 1, + }, +}; + +static const struct vcap_field is2_arp_keyfield[] = { + [VCAP_KF_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 0, + .width = 4, + }, + [VCAP_KF_LOOKUP_FIRST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 4, + .width = 1, + }, + [VCAP_KF_LOOKUP_PAG] = { + .type = VCAP_FIELD_U32, + .offset = 5, + .width = 8, + }, + [VCAP_KF_IF_IGR_PORT_MASK_L3] = { + .type = VCAP_FIELD_BIT, + .offset = 13, + .width = 1, + }, + [VCAP_KF_IF_IGR_PORT_MASK_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 14, + .width = 4, + }, + [VCAP_KF_IF_IGR_PORT_MASK_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 18, + .width = 2, + }, + [VCAP_KF_IF_IGR_PORT_MASK] = { + .type = VCAP_FIELD_U32, + .offset = 20, + .width = 32, + }, + [VCAP_KF_L2_MC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 52, + .width = 1, + }, + [VCAP_KF_L2_BC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 53, + .width = 1, + }, + [VCAP_KF_8021Q_VLAN_TAGGED_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 54, + .width = 1, + }, + [VCAP_KF_ISDX_GT0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 55, + .width = 1, + }, + [VCAP_KF_ISDX_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 56, + .width = 12, + }, + [VCAP_KF_8021Q_VID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 68, + .width = 13, + }, + [VCAP_KF_8021Q_DEI_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 81, + .width = 1, + }, + [VCAP_KF_8021Q_PCP_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 82, + .width = 3, + }, + [VCAP_KF_L2_FWD_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 85, + .width = 1, + }, + [VCAP_KF_L2_SMAC] = { + .type = VCAP_FIELD_U48, + .offset = 86, + .width = 48, + }, + [VCAP_KF_ARP_ADDR_SPACE_OK_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 134, + .width = 1, + }, + [VCAP_KF_ARP_PROTO_SPACE_OK_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 135, + .width = 1, + }, + [VCAP_KF_ARP_LEN_OK_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 136, + .width = 1, + }, + [VCAP_KF_ARP_TGT_MATCH_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 137, + .width = 1, + }, + [VCAP_KF_ARP_SENDER_MATCH_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 138, + .width = 1, + }, + [VCAP_KF_ARP_OPCODE_UNKNOWN_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 139, + .width = 1, + }, + [VCAP_KF_ARP_OPCODE] = { + .type = VCAP_FIELD_U32, + .offset = 140, + .width = 2, + }, + [VCAP_KF_L3_IP4_DIP] = { + .type = VCAP_FIELD_U32, + .offset = 142, + .width = 32, + }, + [VCAP_KF_L3_IP4_SIP] = { + .type = VCAP_FIELD_U32, + .offset = 174, + .width = 32, + }, + [VCAP_KF_L3_DIP_EQ_SIP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 206, + .width = 1, + }, + [VCAP_KF_L4_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 207, + .width = 16, + }, +}; + +static const struct vcap_field is2_ip4_tcp_udp_keyfield[] = { + [VCAP_KF_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 0, + .width = 4, + }, + [VCAP_KF_LOOKUP_FIRST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 4, + .width = 1, + }, + [VCAP_KF_LOOKUP_PAG] = { + .type = VCAP_FIELD_U32, + .offset = 5, + .width = 8, + }, + [VCAP_KF_IF_IGR_PORT_MASK_L3] = { + .type = VCAP_FIELD_BIT, + .offset = 13, + .width = 1, + }, + [VCAP_KF_IF_IGR_PORT_MASK_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 14, + .width = 4, + }, + [VCAP_KF_IF_IGR_PORT_MASK_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 18, + .width = 2, + }, + [VCAP_KF_IF_IGR_PORT_MASK] = { + .type = VCAP_FIELD_U32, + .offset = 20, + .width = 32, + }, + [VCAP_KF_L2_MC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 52, + .width = 1, + }, + [VCAP_KF_L2_BC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 53, + .width = 1, + }, + [VCAP_KF_8021Q_VLAN_TAGGED_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 54, + .width = 1, + }, + [VCAP_KF_ISDX_GT0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 55, + .width = 1, + }, + [VCAP_KF_ISDX_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 56, + .width = 12, + }, + [VCAP_KF_8021Q_VID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 68, + .width = 13, + }, + [VCAP_KF_8021Q_DEI_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 81, + .width = 1, + }, + [VCAP_KF_8021Q_PCP_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 82, + .width = 3, + }, + [VCAP_KF_L2_FWD_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 85, + .width = 1, + }, + [VCAP_KF_L3_SMAC_SIP_MATCH] = { + .type = VCAP_FIELD_BIT, + .offset = 86, + .width = 1, + }, + [VCAP_KF_L3_DMAC_DIP_MATCH] = { + .type = VCAP_FIELD_BIT, + .offset = 87, + .width = 1, + }, + [VCAP_KF_L3_RT_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 88, + .width = 1, + }, + [VCAP_KF_L3_DST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 89, + .width = 1, + }, + [VCAP_KF_IP4_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 90, + .width = 1, + }, + [VCAP_KF_L3_FRAGMENT_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 91, + .width = 2, + }, + [VCAP_KF_L3_FRAG_INVLD_L4_LEN] = { + .type = VCAP_FIELD_BIT, + .offset = 93, + .width = 1, + }, + [VCAP_KF_L3_OPTIONS_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 94, + .width = 1, + }, + [VCAP_KF_L3_TTL_GT0] = { + .type = VCAP_FIELD_BIT, + .offset = 95, + .width = 1, + }, + [VCAP_KF_L3_TOS] = { + .type = VCAP_FIELD_U32, + .offset = 96, + .width = 8, + }, + [VCAP_KF_L3_IP4_DIP] = { + .type = VCAP_FIELD_U32, + .offset = 104, + .width = 32, + }, + [VCAP_KF_L3_IP4_SIP] = { + .type = VCAP_FIELD_U32, + .offset = 136, + .width = 32, + }, + [VCAP_KF_L3_DIP_EQ_SIP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 168, + .width = 1, + }, + [VCAP_KF_TCP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 169, + .width = 1, + }, + [VCAP_KF_L4_DPORT] = { + .type = VCAP_FIELD_U32, + .offset = 170, + .width = 16, + }, + [VCAP_KF_L4_SPORT] = { + .type = VCAP_FIELD_U32, + .offset = 186, + .width = 16, + }, + [VCAP_KF_L4_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 202, + .width = 16, + }, + [VCAP_KF_L4_SPORT_EQ_DPORT_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 218, + .width = 1, + }, + [VCAP_KF_L4_SEQUENCE_EQ0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 219, + .width = 1, + }, + [VCAP_KF_L4_FIN] = { + .type = VCAP_FIELD_BIT, + .offset = 220, + .width = 1, + }, + [VCAP_KF_L4_SYN] = { + .type = VCAP_FIELD_BIT, + .offset = 221, + .width = 1, + }, + [VCAP_KF_L4_RST] = { + .type = VCAP_FIELD_BIT, + .offset = 222, + .width = 1, + }, + [VCAP_KF_L4_PSH] = { + .type = VCAP_FIELD_BIT, + .offset = 223, + .width = 1, + }, + [VCAP_KF_L4_ACK] = { + .type = VCAP_FIELD_BIT, + .offset = 224, + .width = 1, + }, + [VCAP_KF_L4_URG] = { + .type = VCAP_FIELD_BIT, + .offset = 225, + .width = 1, + }, + [VCAP_KF_L4_PAYLOAD] = { + .type = VCAP_FIELD_U64, + .offset = 226, + .width = 64, + }, +}; + +static const struct vcap_field is2_ip4_other_keyfield[] = { + [VCAP_KF_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 0, + .width = 4, + }, + [VCAP_KF_LOOKUP_FIRST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 4, + .width = 1, + }, + [VCAP_KF_LOOKUP_PAG] = { + .type = VCAP_FIELD_U32, + .offset = 5, + .width = 8, + }, + [VCAP_KF_IF_IGR_PORT_MASK_L3] = { + .type = VCAP_FIELD_BIT, + .offset = 13, + .width = 1, + }, + [VCAP_KF_IF_IGR_PORT_MASK_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 14, + .width = 4, + }, + [VCAP_KF_IF_IGR_PORT_MASK_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 18, + .width = 2, + }, + [VCAP_KF_IF_IGR_PORT_MASK] = { + .type = VCAP_FIELD_U32, + .offset = 20, + .width = 32, + }, + [VCAP_KF_L2_MC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 52, + .width = 1, + }, + [VCAP_KF_L2_BC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 53, + .width = 1, + }, + [VCAP_KF_8021Q_VLAN_TAGGED_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 54, + .width = 1, + }, + [VCAP_KF_ISDX_GT0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 55, + .width = 1, + }, + [VCAP_KF_ISDX_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 56, + .width = 12, + }, + [VCAP_KF_8021Q_VID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 68, + .width = 13, + }, + [VCAP_KF_8021Q_DEI_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 81, + .width = 1, + }, + [VCAP_KF_8021Q_PCP_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 82, + .width = 3, + }, + [VCAP_KF_L2_FWD_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 85, + .width = 1, + }, + [VCAP_KF_L3_SMAC_SIP_MATCH] = { + .type = VCAP_FIELD_BIT, + .offset = 86, + .width = 1, + }, + [VCAP_KF_L3_DMAC_DIP_MATCH] = { + .type = VCAP_FIELD_BIT, + .offset = 87, + .width = 1, + }, + [VCAP_KF_L3_RT_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 88, + .width = 1, + }, + [VCAP_KF_L3_DST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 89, + .width = 1, + }, + [VCAP_KF_IP4_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 90, + .width = 1, + }, + [VCAP_KF_L3_FRAGMENT_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 91, + .width = 2, + }, + [VCAP_KF_L3_FRAG_INVLD_L4_LEN] = { + .type = VCAP_FIELD_BIT, + .offset = 93, + .width = 1, + }, + [VCAP_KF_L3_OPTIONS_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 94, + .width = 1, + }, + [VCAP_KF_L3_TTL_GT0] = { + .type = VCAP_FIELD_BIT, + .offset = 95, + .width = 1, + }, + [VCAP_KF_L3_TOS] = { + .type = VCAP_FIELD_U32, + .offset = 96, + .width = 8, + }, + [VCAP_KF_L3_IP4_DIP] = { + .type = VCAP_FIELD_U32, + .offset = 104, + .width = 32, + }, + [VCAP_KF_L3_IP4_SIP] = { + .type = VCAP_FIELD_U32, + .offset = 136, + .width = 32, + }, + [VCAP_KF_L3_DIP_EQ_SIP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 168, + .width = 1, + }, + [VCAP_KF_L3_IP_PROTO] = { + .type = VCAP_FIELD_U32, + .offset = 169, + .width = 8, + }, + [VCAP_KF_L4_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 177, + .width = 16, + }, + [VCAP_KF_L3_PAYLOAD] = { + .type = VCAP_FIELD_U112, + .offset = 193, + .width = 96, + }, +}; + +static const struct vcap_field is2_ip6_std_keyfield[] = { + [VCAP_KF_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 0, + .width = 4, + }, + [VCAP_KF_LOOKUP_FIRST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 4, + .width = 1, + }, + [VCAP_KF_LOOKUP_PAG] = { + .type = VCAP_FIELD_U32, + .offset = 5, + .width = 8, + }, + [VCAP_KF_IF_IGR_PORT_MASK_L3] = { + .type = VCAP_FIELD_BIT, + .offset = 13, + .width = 1, + }, + [VCAP_KF_IF_IGR_PORT_MASK_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 14, + .width = 4, + }, + [VCAP_KF_IF_IGR_PORT_MASK_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 18, + .width = 2, + }, + [VCAP_KF_IF_IGR_PORT_MASK] = { + .type = VCAP_FIELD_U32, + .offset = 20, + .width = 32, + }, + [VCAP_KF_L2_MC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 52, + .width = 1, + }, + [VCAP_KF_L2_BC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 53, + .width = 1, + }, + [VCAP_KF_8021Q_VLAN_TAGGED_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 54, + .width = 1, + }, + [VCAP_KF_ISDX_GT0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 55, + .width = 1, + }, + [VCAP_KF_ISDX_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 56, + .width = 12, + }, + [VCAP_KF_8021Q_VID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 68, + .width = 13, + }, + [VCAP_KF_8021Q_DEI_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 81, + .width = 1, + }, + [VCAP_KF_8021Q_PCP_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 82, + .width = 3, + }, + [VCAP_KF_L2_FWD_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 85, + .width = 1, + }, + [VCAP_KF_L3_SMAC_SIP_MATCH] = { + .type = VCAP_FIELD_BIT, + .offset = 86, + .width = 1, + }, + [VCAP_KF_L3_DMAC_DIP_MATCH] = { + .type = VCAP_FIELD_BIT, + .offset = 87, + .width = 1, + }, + [VCAP_KF_L3_RT_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 88, + .width = 1, + }, + [VCAP_KF_L3_DST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 89, + .width = 1, + }, + [VCAP_KF_L3_TTL_GT0] = { + .type = VCAP_FIELD_BIT, + .offset = 90, + .width = 1, + }, + [VCAP_KF_L3_IP6_SIP] = { + .type = VCAP_FIELD_U128, + .offset = 91, + .width = 128, + }, + [VCAP_KF_L3_DIP_EQ_SIP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 219, + .width = 1, + }, + [VCAP_KF_L3_IP_PROTO] = { + .type = VCAP_FIELD_U32, + .offset = 220, + .width = 8, + }, + [VCAP_KF_L4_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 228, + .width = 16, + }, + [VCAP_KF_L3_PAYLOAD] = { + .type = VCAP_FIELD_U48, + .offset = 244, + .width = 40, + }, +}; + +static const struct vcap_field is2_ip_7tuple_keyfield[] = { + [VCAP_KF_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 0, + .width = 2, + }, + [VCAP_KF_LOOKUP_FIRST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 2, + .width = 1, + }, + [VCAP_KF_LOOKUP_PAG] = { + .type = VCAP_FIELD_U32, + .offset = 3, + .width = 8, + }, + [VCAP_KF_IF_IGR_PORT_MASK_L3] = { + .type = VCAP_FIELD_BIT, + .offset = 11, + .width = 1, + }, + [VCAP_KF_IF_IGR_PORT_MASK_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 12, + .width = 4, + }, + [VCAP_KF_IF_IGR_PORT_MASK_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 16, + .width = 2, + }, + [VCAP_KF_IF_IGR_PORT_MASK] = { + .type = VCAP_FIELD_U72, + .offset = 18, + .width = 65, + }, + [VCAP_KF_L2_MC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 83, + .width = 1, + }, + [VCAP_KF_L2_BC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 84, + .width = 1, + }, + [VCAP_KF_8021Q_VLAN_TAGGED_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 85, + .width = 1, + }, + [VCAP_KF_ISDX_GT0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 86, + .width = 1, + }, + [VCAP_KF_ISDX_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 87, + .width = 12, + }, + [VCAP_KF_8021Q_VID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 99, + .width = 13, + }, + [VCAP_KF_8021Q_DEI_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 112, + .width = 1, + }, + [VCAP_KF_8021Q_PCP_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 113, + .width = 3, + }, + [VCAP_KF_L2_FWD_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 116, + .width = 1, + }, + [VCAP_KF_L3_SMAC_SIP_MATCH] = { + .type = VCAP_FIELD_BIT, + .offset = 117, + .width = 1, + }, + [VCAP_KF_L3_DMAC_DIP_MATCH] = { + .type = VCAP_FIELD_BIT, + .offset = 118, + .width = 1, + }, + [VCAP_KF_L3_RT_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 119, + .width = 1, + }, + [VCAP_KF_L3_DST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 120, + .width = 1, + }, + [VCAP_KF_L2_DMAC] = { + .type = VCAP_FIELD_U48, + .offset = 121, + .width = 48, + }, + [VCAP_KF_L2_SMAC] = { + .type = VCAP_FIELD_U48, + .offset = 169, + .width = 48, + }, + [VCAP_KF_IP4_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 217, + .width = 1, + }, + [VCAP_KF_L3_TTL_GT0] = { + .type = VCAP_FIELD_BIT, + .offset = 218, + .width = 1, + }, + [VCAP_KF_L3_TOS] = { + .type = VCAP_FIELD_U32, + .offset = 219, + .width = 8, + }, + [VCAP_KF_L3_IP6_DIP] = { + .type = VCAP_FIELD_U128, + .offset = 227, + .width = 128, + }, + [VCAP_KF_L3_IP6_SIP] = { + .type = VCAP_FIELD_U128, + .offset = 355, + .width = 128, + }, + [VCAP_KF_L3_DIP_EQ_SIP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 483, + .width = 1, + }, + [VCAP_KF_TCP_UDP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 484, + .width = 1, + }, + [VCAP_KF_TCP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 485, + .width = 1, + }, + [VCAP_KF_L4_DPORT] = { + .type = VCAP_FIELD_U32, + .offset = 486, + .width = 16, + }, + [VCAP_KF_L4_SPORT] = { + .type = VCAP_FIELD_U32, + .offset = 502, + .width = 16, + }, + [VCAP_KF_L4_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 518, + .width = 16, + }, + [VCAP_KF_L4_SPORT_EQ_DPORT_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 534, + .width = 1, + }, + [VCAP_KF_L4_SEQUENCE_EQ0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 535, + .width = 1, + }, + [VCAP_KF_L4_FIN] = { + .type = VCAP_FIELD_BIT, + .offset = 536, + .width = 1, + }, + [VCAP_KF_L4_SYN] = { + .type = VCAP_FIELD_BIT, + .offset = 537, + .width = 1, + }, + [VCAP_KF_L4_RST] = { + .type = VCAP_FIELD_BIT, + .offset = 538, + .width = 1, + }, + [VCAP_KF_L4_PSH] = { + .type = VCAP_FIELD_BIT, + .offset = 539, + .width = 1, + }, + [VCAP_KF_L4_ACK] = { + .type = VCAP_FIELD_BIT, + .offset = 540, + .width = 1, + }, + [VCAP_KF_L4_URG] = { + .type = VCAP_FIELD_BIT, + .offset = 541, + .width = 1, + }, + [VCAP_KF_L4_PAYLOAD] = { + .type = VCAP_FIELD_U64, + .offset = 542, + .width = 64, + }, +}; + +static const struct vcap_field is2_ip6_vid_keyfield[] = { + [VCAP_KF_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 0, + .width = 4, + }, + [VCAP_KF_LOOKUP_FIRST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 4, + .width = 1, + }, + [VCAP_KF_LOOKUP_PAG] = { + .type = VCAP_FIELD_U32, + .offset = 5, + .width = 8, + }, + [VCAP_KF_ISDX_GT0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 13, + .width = 1, + }, + [VCAP_KF_ISDX_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 14, + .width = 12, + }, + [VCAP_KF_8021Q_VID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 26, + .width = 13, + }, + [VCAP_KF_L3_SMAC_SIP_MATCH] = { + .type = VCAP_FIELD_BIT, + .offset = 39, + .width = 1, + }, + [VCAP_KF_L3_DMAC_DIP_MATCH] = { + .type = VCAP_FIELD_BIT, + .offset = 40, + .width = 1, + }, + [VCAP_KF_L3_RT_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 41, + .width = 1, + }, + [VCAP_KF_L3_DST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 42, + .width = 1, + }, + [VCAP_KF_L3_IP6_DIP] = { + .type = VCAP_FIELD_U128, + .offset = 43, + .width = 128, + }, + [VCAP_KF_L3_IP6_SIP] = { + .type = VCAP_FIELD_U128, + .offset = 171, + .width = 128, + }, +}; + +static const struct vcap_field es2_mac_etype_keyfield[] = { + [VCAP_KF_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 0, + .width = 3, + }, + [VCAP_KF_LOOKUP_FIRST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 3, + .width = 1, + }, + [VCAP_KF_ACL_GRP_ID] = { + .type = VCAP_FIELD_U32, + .offset = 4, + .width = 8, + }, + [VCAP_KF_PROT_ACTIVE] = { + .type = VCAP_FIELD_BIT, + .offset = 12, + .width = 1, + }, + [VCAP_KF_L2_MC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 13, + .width = 1, + }, + [VCAP_KF_L2_BC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 14, + .width = 1, + }, + [VCAP_KF_ISDX_GT0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 15, + .width = 1, + }, + [VCAP_KF_ISDX_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 16, + .width = 12, + }, + [VCAP_KF_8021Q_VLAN_TAGGED_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 28, + .width = 1, + }, + [VCAP_KF_8021Q_VID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 29, + .width = 13, + }, + [VCAP_KF_IF_EGR_PORT_MASK_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 42, + .width = 3, + }, + [VCAP_KF_IF_EGR_PORT_MASK] = { + .type = VCAP_FIELD_U32, + .offset = 45, + .width = 32, + }, + [VCAP_KF_IF_IGR_PORT_SEL] = { + .type = VCAP_FIELD_BIT, + .offset = 77, + .width = 1, + }, + [VCAP_KF_IF_IGR_PORT] = { + .type = VCAP_FIELD_U32, + .offset = 78, + .width = 9, + }, + [VCAP_KF_8021Q_PCP_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 87, + .width = 3, + }, + [VCAP_KF_8021Q_DEI_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 90, + .width = 1, + }, + [VCAP_KF_COSID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 91, + .width = 3, + }, + [VCAP_KF_L3_DPL_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 94, + .width = 1, + }, + [VCAP_KF_L3_RT_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 95, + .width = 1, + }, + [VCAP_KF_ES0_ISDX_KEY_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 96, + .width = 1, + }, + [VCAP_KF_MIRROR_ENA] = { + .type = VCAP_FIELD_U32, + .offset = 97, + .width = 2, + }, + [VCAP_KF_L2_DMAC] = { + .type = VCAP_FIELD_U48, + .offset = 99, + .width = 48, + }, + [VCAP_KF_L2_SMAC] = { + .type = VCAP_FIELD_U48, + .offset = 147, + .width = 48, + }, + [VCAP_KF_ETYPE_LEN_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 195, + .width = 1, + }, + [VCAP_KF_ETYPE] = { + .type = VCAP_FIELD_U32, + .offset = 196, + .width = 16, + }, + [VCAP_KF_L2_PAYLOAD_ETYPE] = { + .type = VCAP_FIELD_U64, + .offset = 212, + .width = 64, + }, + [VCAP_KF_OAM_CCM_CNTS_EQ0] = { + .type = VCAP_FIELD_BIT, + .offset = 276, + .width = 1, + }, + [VCAP_KF_OAM_Y1731_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 277, + .width = 1, + }, +}; + +static const struct vcap_field es2_arp_keyfield[] = { + [VCAP_KF_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 0, + .width = 3, + }, + [VCAP_KF_LOOKUP_FIRST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 3, + .width = 1, + }, + [VCAP_KF_ACL_GRP_ID] = { + .type = VCAP_FIELD_U32, + .offset = 4, + .width = 8, + }, + [VCAP_KF_PROT_ACTIVE] = { + .type = VCAP_FIELD_BIT, + .offset = 12, + .width = 1, + }, + [VCAP_KF_L2_MC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 13, + .width = 1, + }, + [VCAP_KF_L2_BC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 14, + .width = 1, + }, + [VCAP_KF_ISDX_GT0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 15, + .width = 1, + }, + [VCAP_KF_ISDX_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 16, + .width = 12, + }, + [VCAP_KF_8021Q_VLAN_TAGGED_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 28, + .width = 1, + }, + [VCAP_KF_8021Q_VID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 29, + .width = 13, + }, + [VCAP_KF_IF_EGR_PORT_MASK_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 42, + .width = 3, + }, + [VCAP_KF_IF_EGR_PORT_MASK] = { + .type = VCAP_FIELD_U32, + .offset = 45, + .width = 32, + }, + [VCAP_KF_IF_IGR_PORT_SEL] = { + .type = VCAP_FIELD_BIT, + .offset = 77, + .width = 1, + }, + [VCAP_KF_IF_IGR_PORT] = { + .type = VCAP_FIELD_U32, + .offset = 78, + .width = 9, + }, + [VCAP_KF_8021Q_PCP_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 87, + .width = 3, + }, + [VCAP_KF_8021Q_DEI_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 90, + .width = 1, + }, + [VCAP_KF_COSID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 91, + .width = 3, + }, + [VCAP_KF_L3_DPL_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 94, + .width = 1, + }, + [VCAP_KF_ES0_ISDX_KEY_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 95, + .width = 1, + }, + [VCAP_KF_MIRROR_ENA] = { + .type = VCAP_FIELD_U32, + .offset = 96, + .width = 2, + }, + [VCAP_KF_L2_SMAC] = { + .type = VCAP_FIELD_U48, + .offset = 98, + .width = 48, + }, + [VCAP_KF_ARP_ADDR_SPACE_OK_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 146, + .width = 1, + }, + [VCAP_KF_ARP_PROTO_SPACE_OK_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 147, + .width = 1, + }, + [VCAP_KF_ARP_LEN_OK_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 148, + .width = 1, + }, + [VCAP_KF_ARP_TGT_MATCH_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 149, + .width = 1, + }, + [VCAP_KF_ARP_SENDER_MATCH_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 150, + .width = 1, + }, + [VCAP_KF_ARP_OPCODE_UNKNOWN_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 151, + .width = 1, + }, + [VCAP_KF_ARP_OPCODE] = { + .type = VCAP_FIELD_U32, + .offset = 152, + .width = 2, + }, + [VCAP_KF_L3_IP4_DIP] = { + .type = VCAP_FIELD_U32, + .offset = 154, + .width = 32, + }, + [VCAP_KF_L3_IP4_SIP] = { + .type = VCAP_FIELD_U32, + .offset = 186, + .width = 32, + }, + [VCAP_KF_L3_DIP_EQ_SIP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 218, + .width = 1, + }, +}; + +static const struct vcap_field es2_ip4_tcp_udp_keyfield[] = { + [VCAP_KF_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 0, + .width = 3, + }, + [VCAP_KF_LOOKUP_FIRST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 3, + .width = 1, + }, + [VCAP_KF_ACL_GRP_ID] = { + .type = VCAP_FIELD_U32, + .offset = 4, + .width = 8, + }, + [VCAP_KF_PROT_ACTIVE] = { + .type = VCAP_FIELD_BIT, + .offset = 12, + .width = 1, + }, + [VCAP_KF_L2_MC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 13, + .width = 1, + }, + [VCAP_KF_L2_BC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 14, + .width = 1, + }, + [VCAP_KF_ISDX_GT0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 15, + .width = 1, + }, + [VCAP_KF_ISDX_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 16, + .width = 12, + }, + [VCAP_KF_8021Q_VLAN_TAGGED_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 28, + .width = 1, + }, + [VCAP_KF_8021Q_VID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 29, + .width = 13, + }, + [VCAP_KF_IF_EGR_PORT_MASK_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 42, + .width = 3, + }, + [VCAP_KF_IF_EGR_PORT_MASK] = { + .type = VCAP_FIELD_U32, + .offset = 45, + .width = 32, + }, + [VCAP_KF_IF_IGR_PORT_SEL] = { + .type = VCAP_FIELD_BIT, + .offset = 77, + .width = 1, + }, + [VCAP_KF_IF_IGR_PORT] = { + .type = VCAP_FIELD_U32, + .offset = 78, + .width = 9, + }, + [VCAP_KF_8021Q_PCP_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 87, + .width = 3, + }, + [VCAP_KF_8021Q_DEI_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 90, + .width = 1, + }, + [VCAP_KF_COSID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 91, + .width = 3, + }, + [VCAP_KF_L3_DPL_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 94, + .width = 1, + }, + [VCAP_KF_L3_RT_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 95, + .width = 1, + }, + [VCAP_KF_ES0_ISDX_KEY_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 96, + .width = 1, + }, + [VCAP_KF_MIRROR_ENA] = { + .type = VCAP_FIELD_U32, + .offset = 97, + .width = 2, + }, + [VCAP_KF_IP4_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 99, + .width = 1, + }, + [VCAP_KF_L3_FRAGMENT_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 100, + .width = 2, + }, + [VCAP_KF_L3_OPTIONS_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 102, + .width = 1, + }, + [VCAP_KF_L3_TTL_GT0] = { + .type = VCAP_FIELD_BIT, + .offset = 103, + .width = 1, + }, + [VCAP_KF_L3_TOS] = { + .type = VCAP_FIELD_U32, + .offset = 104, + .width = 8, + }, + [VCAP_KF_L3_IP4_DIP] = { + .type = VCAP_FIELD_U32, + .offset = 112, + .width = 32, + }, + [VCAP_KF_L3_IP4_SIP] = { + .type = VCAP_FIELD_U32, + .offset = 144, + .width = 32, + }, + [VCAP_KF_L3_DIP_EQ_SIP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 176, + .width = 1, + }, + [VCAP_KF_TCP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 177, + .width = 1, + }, + [VCAP_KF_L4_DPORT] = { + .type = VCAP_FIELD_U32, + .offset = 178, + .width = 16, + }, + [VCAP_KF_L4_SPORT] = { + .type = VCAP_FIELD_U32, + .offset = 194, + .width = 16, + }, + [VCAP_KF_L4_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 210, + .width = 16, + }, + [VCAP_KF_L4_SPORT_EQ_DPORT_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 226, + .width = 1, + }, + [VCAP_KF_L4_SEQUENCE_EQ0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 227, + .width = 1, + }, + [VCAP_KF_L4_FIN] = { + .type = VCAP_FIELD_BIT, + .offset = 228, + .width = 1, + }, + [VCAP_KF_L4_SYN] = { + .type = VCAP_FIELD_BIT, + .offset = 229, + .width = 1, + }, + [VCAP_KF_L4_RST] = { + .type = VCAP_FIELD_BIT, + .offset = 230, + .width = 1, + }, + [VCAP_KF_L4_PSH] = { + .type = VCAP_FIELD_BIT, + .offset = 231, + .width = 1, + }, + [VCAP_KF_L4_ACK] = { + .type = VCAP_FIELD_BIT, + .offset = 232, + .width = 1, + }, + [VCAP_KF_L4_URG] = { + .type = VCAP_FIELD_BIT, + .offset = 233, + .width = 1, + }, + [VCAP_KF_L4_PAYLOAD] = { + .type = VCAP_FIELD_U64, + .offset = 234, + .width = 64, + }, +}; + +static const struct vcap_field es2_ip4_other_keyfield[] = { + [VCAP_KF_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 0, + .width = 3, + }, + [VCAP_KF_LOOKUP_FIRST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 3, + .width = 1, + }, + [VCAP_KF_ACL_GRP_ID] = { + .type = VCAP_FIELD_U32, + .offset = 4, + .width = 8, + }, + [VCAP_KF_PROT_ACTIVE] = { + .type = VCAP_FIELD_BIT, + .offset = 12, + .width = 1, + }, + [VCAP_KF_L2_MC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 13, + .width = 1, + }, + [VCAP_KF_L2_BC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 14, + .width = 1, + }, + [VCAP_KF_ISDX_GT0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 15, + .width = 1, + }, + [VCAP_KF_ISDX_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 16, + .width = 12, + }, + [VCAP_KF_8021Q_VLAN_TAGGED_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 28, + .width = 1, + }, + [VCAP_KF_8021Q_VID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 29, + .width = 13, + }, + [VCAP_KF_IF_EGR_PORT_MASK_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 42, + .width = 3, + }, + [VCAP_KF_IF_EGR_PORT_MASK] = { + .type = VCAP_FIELD_U32, + .offset = 45, + .width = 32, + }, + [VCAP_KF_IF_IGR_PORT_SEL] = { + .type = VCAP_FIELD_BIT, + .offset = 77, + .width = 1, + }, + [VCAP_KF_IF_IGR_PORT] = { + .type = VCAP_FIELD_U32, + .offset = 78, + .width = 9, + }, + [VCAP_KF_8021Q_PCP_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 87, + .width = 3, + }, + [VCAP_KF_8021Q_DEI_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 90, + .width = 1, + }, + [VCAP_KF_COSID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 91, + .width = 3, + }, + [VCAP_KF_L3_DPL_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 94, + .width = 1, + }, + [VCAP_KF_L3_RT_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 95, + .width = 1, + }, + [VCAP_KF_ES0_ISDX_KEY_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 96, + .width = 1, + }, + [VCAP_KF_MIRROR_ENA] = { + .type = VCAP_FIELD_U32, + .offset = 97, + .width = 2, + }, + [VCAP_KF_IP4_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 99, + .width = 1, + }, + [VCAP_KF_L3_FRAGMENT_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 100, + .width = 2, + }, + [VCAP_KF_L3_OPTIONS_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 102, + .width = 1, + }, + [VCAP_KF_L3_TTL_GT0] = { + .type = VCAP_FIELD_BIT, + .offset = 103, + .width = 1, + }, + [VCAP_KF_L3_TOS] = { + .type = VCAP_FIELD_U32, + .offset = 104, + .width = 8, + }, + [VCAP_KF_L3_IP4_DIP] = { + .type = VCAP_FIELD_U32, + .offset = 112, + .width = 32, + }, + [VCAP_KF_L3_IP4_SIP] = { + .type = VCAP_FIELD_U32, + .offset = 144, + .width = 32, + }, + [VCAP_KF_L3_DIP_EQ_SIP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 176, + .width = 1, + }, + [VCAP_KF_L3_IP_PROTO] = { + .type = VCAP_FIELD_U32, + .offset = 177, + .width = 8, + }, + [VCAP_KF_L3_PAYLOAD] = { + .type = VCAP_FIELD_U112, + .offset = 185, + .width = 96, + }, +}; + +static const struct vcap_field es2_ip_7tuple_keyfield[] = { + [VCAP_KF_LOOKUP_FIRST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 0, + .width = 1, + }, + [VCAP_KF_ACL_GRP_ID] = { + .type = VCAP_FIELD_U32, + .offset = 1, + .width = 8, + }, + [VCAP_KF_PROT_ACTIVE] = { + .type = VCAP_FIELD_BIT, + .offset = 9, + .width = 1, + }, + [VCAP_KF_L2_MC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 10, + .width = 1, + }, + [VCAP_KF_L2_BC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 11, + .width = 1, + }, + [VCAP_KF_ISDX_GT0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 12, + .width = 1, + }, + [VCAP_KF_ISDX_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 13, + .width = 12, + }, + [VCAP_KF_8021Q_VLAN_TAGGED_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 25, + .width = 1, + }, + [VCAP_KF_8021Q_VID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 26, + .width = 13, + }, + [VCAP_KF_IF_EGR_PORT_MASK_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 39, + .width = 3, + }, + [VCAP_KF_IF_EGR_PORT_MASK] = { + .type = VCAP_FIELD_U32, + .offset = 42, + .width = 32, + }, + [VCAP_KF_IF_IGR_PORT_SEL] = { + .type = VCAP_FIELD_BIT, + .offset = 74, + .width = 1, + }, + [VCAP_KF_IF_IGR_PORT] = { + .type = VCAP_FIELD_U32, + .offset = 75, + .width = 9, + }, + [VCAP_KF_8021Q_PCP_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 84, + .width = 3, + }, + [VCAP_KF_8021Q_DEI_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 87, + .width = 1, + }, + [VCAP_KF_COSID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 88, + .width = 3, + }, + [VCAP_KF_L3_DPL_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 91, + .width = 1, + }, + [VCAP_KF_L3_RT_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 92, + .width = 1, + }, + [VCAP_KF_ES0_ISDX_KEY_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 93, + .width = 1, + }, + [VCAP_KF_MIRROR_ENA] = { + .type = VCAP_FIELD_U32, + .offset = 94, + .width = 2, + }, + [VCAP_KF_L2_DMAC] = { + .type = VCAP_FIELD_U48, + .offset = 96, + .width = 48, + }, + [VCAP_KF_L2_SMAC] = { + .type = VCAP_FIELD_U48, + .offset = 144, + .width = 48, + }, + [VCAP_KF_IP4_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 192, + .width = 1, + }, + [VCAP_KF_L3_TTL_GT0] = { + .type = VCAP_FIELD_BIT, + .offset = 193, + .width = 1, + }, + [VCAP_KF_L3_TOS] = { + .type = VCAP_FIELD_U32, + .offset = 194, + .width = 8, + }, + [VCAP_KF_L3_IP6_DIP] = { + .type = VCAP_FIELD_U128, + .offset = 202, + .width = 128, + }, + [VCAP_KF_L3_IP6_SIP] = { + .type = VCAP_FIELD_U128, + .offset = 330, + .width = 128, + }, + [VCAP_KF_L3_DIP_EQ_SIP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 458, + .width = 1, + }, + [VCAP_KF_TCP_UDP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 459, + .width = 1, + }, + [VCAP_KF_TCP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 460, + .width = 1, + }, + [VCAP_KF_L4_DPORT] = { + .type = VCAP_FIELD_U32, + .offset = 461, + .width = 16, + }, + [VCAP_KF_L4_SPORT] = { + .type = VCAP_FIELD_U32, + .offset = 477, + .width = 16, + }, + [VCAP_KF_L4_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 493, + .width = 16, + }, + [VCAP_KF_L4_SPORT_EQ_DPORT_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 509, + .width = 1, + }, + [VCAP_KF_L4_SEQUENCE_EQ0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 510, + .width = 1, + }, + [VCAP_KF_L4_FIN] = { + .type = VCAP_FIELD_BIT, + .offset = 511, + .width = 1, + }, + [VCAP_KF_L4_SYN] = { + .type = VCAP_FIELD_BIT, + .offset = 512, + .width = 1, + }, + [VCAP_KF_L4_RST] = { + .type = VCAP_FIELD_BIT, + .offset = 513, + .width = 1, + }, + [VCAP_KF_L4_PSH] = { + .type = VCAP_FIELD_BIT, + .offset = 514, + .width = 1, + }, + [VCAP_KF_L4_ACK] = { + .type = VCAP_FIELD_BIT, + .offset = 515, + .width = 1, + }, + [VCAP_KF_L4_URG] = { + .type = VCAP_FIELD_BIT, + .offset = 516, + .width = 1, + }, + [VCAP_KF_L4_PAYLOAD] = { + .type = VCAP_FIELD_U64, + .offset = 517, + .width = 64, + }, +}; + +static const struct vcap_field es2_ip4_vid_keyfield[] = { + [VCAP_KF_LOOKUP_FIRST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 0, + .width = 1, + }, + [VCAP_KF_ACL_GRP_ID] = { + .type = VCAP_FIELD_U32, + .offset = 1, + .width = 8, + }, + [VCAP_KF_PROT_ACTIVE] = { + .type = VCAP_FIELD_BIT, + .offset = 9, + .width = 1, + }, + [VCAP_KF_L2_MC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 10, + .width = 1, + }, + [VCAP_KF_L2_BC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 11, + .width = 1, + }, + [VCAP_KF_ISDX_GT0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 12, + .width = 1, + }, + [VCAP_KF_ISDX_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 13, + .width = 12, + }, + [VCAP_KF_8021Q_VLAN_TAGGED_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 25, + .width = 1, + }, + [VCAP_KF_8021Q_VID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 26, + .width = 13, + }, + [VCAP_KF_8021Q_PCP_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 39, + .width = 3, + }, + [VCAP_KF_8021Q_DEI_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 42, + .width = 1, + }, + [VCAP_KF_COSID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 43, + .width = 3, + }, + [VCAP_KF_L3_DPL_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 46, + .width = 1, + }, + [VCAP_KF_L3_RT_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 47, + .width = 1, + }, + [VCAP_KF_ES0_ISDX_KEY_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 48, + .width = 1, + }, + [VCAP_KF_MIRROR_ENA] = { + .type = VCAP_FIELD_U32, + .offset = 49, + .width = 2, + }, + [VCAP_KF_IP4_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 51, + .width = 1, + }, + [VCAP_KF_L3_IP4_DIP] = { + .type = VCAP_FIELD_U32, + .offset = 52, + .width = 32, + }, + [VCAP_KF_L3_IP4_SIP] = { + .type = VCAP_FIELD_U32, + .offset = 84, + .width = 32, + }, + [VCAP_KF_L4_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 116, + .width = 16, + }, +}; + +static const struct vcap_field es2_ip6_vid_keyfield[] = { + [VCAP_KF_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 0, + .width = 3, + }, + [VCAP_KF_LOOKUP_FIRST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 3, + .width = 1, + }, + [VCAP_KF_ACL_GRP_ID] = { + .type = VCAP_FIELD_U32, + .offset = 4, + .width = 8, + }, + [VCAP_KF_PROT_ACTIVE] = { + .type = VCAP_FIELD_BIT, + .offset = 12, + .width = 1, + }, + [VCAP_KF_L2_MC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 13, + .width = 1, + }, + [VCAP_KF_L2_BC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 14, + .width = 1, + }, + [VCAP_KF_ISDX_GT0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 15, + .width = 1, + }, + [VCAP_KF_ISDX_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 16, + .width = 12, + }, + [VCAP_KF_8021Q_VLAN_TAGGED_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 28, + .width = 1, + }, + [VCAP_KF_8021Q_VID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 29, + .width = 13, + }, + [VCAP_KF_L3_RT_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 42, + .width = 1, + }, + [VCAP_KF_L3_IP6_DIP] = { + .type = VCAP_FIELD_U128, + .offset = 43, + .width = 128, + }, + [VCAP_KF_L3_IP6_SIP] = { + .type = VCAP_FIELD_U128, + .offset = 171, + .width = 128, + }, +}; + +/* keyfield_set */ +static const struct vcap_set is0_keyfield_set[] = { + [VCAP_KFS_MLL] = { + .type_id = 0, + .sw_per_item = 3, + .sw_cnt = 4, + }, + [VCAP_KFS_TRI_VID] = { + .type_id = 0, + .sw_per_item = 2, + .sw_cnt = 6, + }, + [VCAP_KFS_LL_FULL] = { + .type_id = 0, + .sw_per_item = 6, + .sw_cnt = 2, + }, + [VCAP_KFS_NORMAL] = { + .type_id = 1, + .sw_per_item = 6, + .sw_cnt = 2, + }, + [VCAP_KFS_NORMAL_7TUPLE] = { + .type_id = 0, + .sw_per_item = 12, + .sw_cnt = 1, + }, + [VCAP_KFS_NORMAL_5TUPLE_IP4] = { + .type_id = 2, + .sw_per_item = 6, + .sw_cnt = 2, + }, + [VCAP_KFS_PURE_5TUPLE_IP4] = { + .type_id = 2, + .sw_per_item = 3, + .sw_cnt = 4, + }, + [VCAP_KFS_ETAG] = { + .type_id = 3, + .sw_per_item = 2, + .sw_cnt = 6, + }, +}; + +static const struct vcap_set is2_keyfield_set[] = { + [VCAP_KFS_MAC_ETYPE] = { + .type_id = 0, + .sw_per_item = 6, + .sw_cnt = 2, + }, + [VCAP_KFS_ARP] = { + .type_id = 3, + .sw_per_item = 6, + .sw_cnt = 2, + }, + [VCAP_KFS_IP4_TCP_UDP] = { + .type_id = 4, + .sw_per_item = 6, + .sw_cnt = 2, + }, + [VCAP_KFS_IP4_OTHER] = { + .type_id = 5, + .sw_per_item = 6, + .sw_cnt = 2, + }, + [VCAP_KFS_IP6_STD] = { + .type_id = 6, + .sw_per_item = 6, + .sw_cnt = 2, + }, + [VCAP_KFS_IP_7TUPLE] = { + .type_id = 1, + .sw_per_item = 12, + .sw_cnt = 1, + }, + [VCAP_KFS_IP6_VID] = { + .type_id = 9, + .sw_per_item = 6, + .sw_cnt = 2, + }, +}; + +static const struct vcap_set es2_keyfield_set[] = { + [VCAP_KFS_MAC_ETYPE] = { + .type_id = 0, + .sw_per_item = 6, + .sw_cnt = 2, + }, + [VCAP_KFS_ARP] = { + .type_id = 1, + .sw_per_item = 6, + .sw_cnt = 2, + }, + [VCAP_KFS_IP4_TCP_UDP] = { + .type_id = 2, + .sw_per_item = 6, + .sw_cnt = 2, + }, + [VCAP_KFS_IP4_OTHER] = { + .type_id = 3, + .sw_per_item = 6, + .sw_cnt = 2, + }, + [VCAP_KFS_IP_7TUPLE] = { + .type_id = -1, + .sw_per_item = 12, + .sw_cnt = 1, + }, + [VCAP_KFS_IP4_VID] = { + .type_id = -1, + .sw_per_item = 3, + .sw_cnt = 4, + }, + [VCAP_KFS_IP6_VID] = { + .type_id = 5, + .sw_per_item = 6, + .sw_cnt = 2, + }, +}; + +/* keyfield_set map */ +static const struct vcap_field *is0_keyfield_set_map[] = { + [VCAP_KFS_MLL] = is0_mll_keyfield, + [VCAP_KFS_TRI_VID] = is0_tri_vid_keyfield, + [VCAP_KFS_LL_FULL] = is0_ll_full_keyfield, + [VCAP_KFS_NORMAL] = is0_normal_keyfield, + [VCAP_KFS_NORMAL_7TUPLE] = is0_normal_7tuple_keyfield, + [VCAP_KFS_NORMAL_5TUPLE_IP4] = is0_normal_5tuple_ip4_keyfield, + [VCAP_KFS_PURE_5TUPLE_IP4] = is0_pure_5tuple_ip4_keyfield, + [VCAP_KFS_ETAG] = is0_etag_keyfield, +}; + +static const struct vcap_field *is2_keyfield_set_map[] = { + [VCAP_KFS_MAC_ETYPE] = is2_mac_etype_keyfield, + [VCAP_KFS_ARP] = is2_arp_keyfield, + [VCAP_KFS_IP4_TCP_UDP] = is2_ip4_tcp_udp_keyfield, + [VCAP_KFS_IP4_OTHER] = is2_ip4_other_keyfield, + [VCAP_KFS_IP6_STD] = is2_ip6_std_keyfield, + [VCAP_KFS_IP_7TUPLE] = is2_ip_7tuple_keyfield, + [VCAP_KFS_IP6_VID] = is2_ip6_vid_keyfield, +}; + +static const struct vcap_field *es2_keyfield_set_map[] = { + [VCAP_KFS_MAC_ETYPE] = es2_mac_etype_keyfield, + [VCAP_KFS_ARP] = es2_arp_keyfield, + [VCAP_KFS_IP4_TCP_UDP] = es2_ip4_tcp_udp_keyfield, + [VCAP_KFS_IP4_OTHER] = es2_ip4_other_keyfield, + [VCAP_KFS_IP_7TUPLE] = es2_ip_7tuple_keyfield, + [VCAP_KFS_IP4_VID] = es2_ip4_vid_keyfield, + [VCAP_KFS_IP6_VID] = es2_ip6_vid_keyfield, +}; + +/* keyfield_set map sizes */ +static int is0_keyfield_set_map_size[] = { + [VCAP_KFS_MLL] = ARRAY_SIZE(is0_mll_keyfield), + [VCAP_KFS_TRI_VID] = ARRAY_SIZE(is0_tri_vid_keyfield), + [VCAP_KFS_LL_FULL] = ARRAY_SIZE(is0_ll_full_keyfield), + [VCAP_KFS_NORMAL] = ARRAY_SIZE(is0_normal_keyfield), + [VCAP_KFS_NORMAL_7TUPLE] = ARRAY_SIZE(is0_normal_7tuple_keyfield), + [VCAP_KFS_NORMAL_5TUPLE_IP4] = ARRAY_SIZE(is0_normal_5tuple_ip4_keyfield), + [VCAP_KFS_PURE_5TUPLE_IP4] = ARRAY_SIZE(is0_pure_5tuple_ip4_keyfield), + [VCAP_KFS_ETAG] = ARRAY_SIZE(is0_etag_keyfield), +}; + +static int is2_keyfield_set_map_size[] = { + [VCAP_KFS_MAC_ETYPE] = ARRAY_SIZE(is2_mac_etype_keyfield), + [VCAP_KFS_ARP] = ARRAY_SIZE(is2_arp_keyfield), + [VCAP_KFS_IP4_TCP_UDP] = ARRAY_SIZE(is2_ip4_tcp_udp_keyfield), + [VCAP_KFS_IP4_OTHER] = ARRAY_SIZE(is2_ip4_other_keyfield), + [VCAP_KFS_IP6_STD] = ARRAY_SIZE(is2_ip6_std_keyfield), + [VCAP_KFS_IP_7TUPLE] = ARRAY_SIZE(is2_ip_7tuple_keyfield), + [VCAP_KFS_IP6_VID] = ARRAY_SIZE(is2_ip6_vid_keyfield), +}; + +static int es2_keyfield_set_map_size[] = { + [VCAP_KFS_MAC_ETYPE] = ARRAY_SIZE(es2_mac_etype_keyfield), + [VCAP_KFS_ARP] = ARRAY_SIZE(es2_arp_keyfield), + [VCAP_KFS_IP4_TCP_UDP] = ARRAY_SIZE(es2_ip4_tcp_udp_keyfield), + [VCAP_KFS_IP4_OTHER] = ARRAY_SIZE(es2_ip4_other_keyfield), + [VCAP_KFS_IP_7TUPLE] = ARRAY_SIZE(es2_ip_7tuple_keyfield), + [VCAP_KFS_IP4_VID] = ARRAY_SIZE(es2_ip4_vid_keyfield), + [VCAP_KFS_IP6_VID] = ARRAY_SIZE(es2_ip6_vid_keyfield), +}; + +/* actionfields */ +static const struct vcap_field is0_mlbs_actionfield[] = { + [VCAP_AF_TYPE] = { + .type = VCAP_FIELD_BIT, + .offset = 0, + .width = 1, + }, + [VCAP_AF_COSID_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 1, + .width = 1, + }, + [VCAP_AF_COSID_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 2, + .width = 3, + }, + [VCAP_AF_QOS_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 5, + .width = 1, + }, + [VCAP_AF_QOS_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 6, + .width = 3, + }, + [VCAP_AF_DP_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 9, + .width = 1, + }, + [VCAP_AF_DP_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 10, + .width = 2, + }, + [VCAP_AF_MAP_LOOKUP_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 12, + .width = 2, + }, + [VCAP_AF_MAP_KEY] = { + .type = VCAP_FIELD_U32, + .offset = 14, + .width = 3, + }, + [VCAP_AF_MAP_IDX] = { + .type = VCAP_FIELD_U32, + .offset = 17, + .width = 9, + }, + [VCAP_AF_CLS_VID_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 26, + .width = 3, + }, + [VCAP_AF_GVID_ADD_REPLACE_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 29, + .width = 3, + }, + [VCAP_AF_VID_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 32, + .width = 13, + }, + [VCAP_AF_ISDX_ADD_REPLACE_SEL] = { + .type = VCAP_FIELD_BIT, + .offset = 45, + .width = 1, + }, + [VCAP_AF_ISDX_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 46, + .width = 12, + }, + [VCAP_AF_FWD_DIS] = { + .type = VCAP_FIELD_BIT, + .offset = 58, + .width = 1, + }, + [VCAP_AF_CPU_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 59, + .width = 1, + }, + [VCAP_AF_CPU_Q] = { + .type = VCAP_FIELD_U32, + .offset = 60, + .width = 3, + }, + [VCAP_AF_OAM_Y1731_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 63, + .width = 3, + }, + [VCAP_AF_OAM_TWAMP_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 66, + .width = 1, + }, + [VCAP_AF_OAM_IP_BFD_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 67, + .width = 1, + }, + [VCAP_AF_TC_LABEL] = { + .type = VCAP_FIELD_U32, + .offset = 68, + .width = 3, + }, + [VCAP_AF_TTL_LABEL] = { + .type = VCAP_FIELD_U32, + .offset = 71, + .width = 3, + }, + [VCAP_AF_NUM_VLD_LABELS] = { + .type = VCAP_FIELD_U32, + .offset = 74, + .width = 2, + }, + [VCAP_AF_FWD_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 76, + .width = 3, + }, + [VCAP_AF_MPLS_OAM_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 79, + .width = 3, + }, + [VCAP_AF_MPLS_MEP_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 82, + .width = 1, + }, + [VCAP_AF_MPLS_MIP_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 83, + .width = 1, + }, + [VCAP_AF_MPLS_OAM_FLAVOR] = { + .type = VCAP_FIELD_BIT, + .offset = 84, + .width = 1, + }, + [VCAP_AF_MPLS_IP_CTRL_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 85, + .width = 1, + }, + [VCAP_AF_PAG_OVERRIDE_MASK] = { + .type = VCAP_FIELD_U32, + .offset = 86, + .width = 8, + }, + [VCAP_AF_PAG_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 94, + .width = 8, + }, + [VCAP_AF_S2_KEY_SEL_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 102, + .width = 1, + }, + [VCAP_AF_S2_KEY_SEL_IDX] = { + .type = VCAP_FIELD_U32, + .offset = 103, + .width = 6, + }, + [VCAP_AF_PIPELINE_FORCE_ENA] = { + .type = VCAP_FIELD_U32, + .offset = 109, + .width = 2, + }, + [VCAP_AF_PIPELINE_ACT_SEL] = { + .type = VCAP_FIELD_BIT, + .offset = 111, + .width = 1, + }, + [VCAP_AF_PIPELINE_PT] = { + .type = VCAP_FIELD_U32, + .offset = 112, + .width = 5, + }, + [VCAP_AF_NXT_KEY_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 117, + .width = 5, + }, + [VCAP_AF_NXT_NORM_W16_OFFSET] = { + .type = VCAP_FIELD_U32, + .offset = 122, + .width = 5, + }, + [VCAP_AF_NXT_OFFSET_FROM_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 127, + .width = 2, + }, + [VCAP_AF_NXT_TYPE_AFTER_OFFSET] = { + .type = VCAP_FIELD_U32, + .offset = 129, + .width = 2, + }, + [VCAP_AF_NXT_NORMALIZE] = { + .type = VCAP_FIELD_BIT, + .offset = 131, + .width = 1, + }, + [VCAP_AF_NXT_IDX_CTRL] = { + .type = VCAP_FIELD_U32, + .offset = 132, + .width = 3, + }, + [VCAP_AF_NXT_IDX] = { + .type = VCAP_FIELD_U32, + .offset = 135, + .width = 12, + }, +}; + +static const struct vcap_field is0_mlbs_reduced_actionfield[] = { + [VCAP_AF_TYPE] = { + .type = VCAP_FIELD_BIT, + .offset = 0, + .width = 1, + }, + [VCAP_AF_COSID_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 1, + .width = 1, + }, + [VCAP_AF_COSID_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 2, + .width = 3, + }, + [VCAP_AF_QOS_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 5, + .width = 1, + }, + [VCAP_AF_QOS_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 6, + .width = 3, + }, + [VCAP_AF_DP_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 9, + .width = 1, + }, + [VCAP_AF_DP_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 10, + .width = 2, + }, + [VCAP_AF_MAP_LOOKUP_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 12, + .width = 2, + }, + [VCAP_AF_ISDX_ADD_REPLACE_SEL] = { + .type = VCAP_FIELD_BIT, + .offset = 14, + .width = 1, + }, + [VCAP_AF_ISDX_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 15, + .width = 12, + }, + [VCAP_AF_FWD_DIS] = { + .type = VCAP_FIELD_BIT, + .offset = 27, + .width = 1, + }, + [VCAP_AF_CPU_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 28, + .width = 1, + }, + [VCAP_AF_CPU_Q] = { + .type = VCAP_FIELD_U32, + .offset = 29, + .width = 3, + }, + [VCAP_AF_TC_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 32, + .width = 1, + }, + [VCAP_AF_TTL_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 33, + .width = 1, + }, + [VCAP_AF_FWD_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 34, + .width = 3, + }, + [VCAP_AF_MPLS_OAM_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 37, + .width = 3, + }, + [VCAP_AF_MPLS_MEP_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 40, + .width = 1, + }, + [VCAP_AF_MPLS_MIP_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 41, + .width = 1, + }, + [VCAP_AF_MPLS_OAM_FLAVOR] = { + .type = VCAP_FIELD_BIT, + .offset = 42, + .width = 1, + }, + [VCAP_AF_MPLS_IP_CTRL_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 43, + .width = 1, + }, + [VCAP_AF_PIPELINE_FORCE_ENA] = { + .type = VCAP_FIELD_U32, + .offset = 44, + .width = 2, + }, + [VCAP_AF_PIPELINE_ACT_SEL] = { + .type = VCAP_FIELD_BIT, + .offset = 46, + .width = 1, + }, + [VCAP_AF_PIPELINE_PT_REDUCED] = { + .type = VCAP_FIELD_U32, + .offset = 47, + .width = 3, + }, + [VCAP_AF_NXT_KEY_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 50, + .width = 5, + }, + [VCAP_AF_NXT_NORM_W32_OFFSET] = { + .type = VCAP_FIELD_U32, + .offset = 55, + .width = 2, + }, + [VCAP_AF_NXT_TYPE_AFTER_OFFSET] = { + .type = VCAP_FIELD_U32, + .offset = 57, + .width = 2, + }, + [VCAP_AF_NXT_NORMALIZE] = { + .type = VCAP_FIELD_BIT, + .offset = 59, + .width = 1, + }, + [VCAP_AF_NXT_IDX_CTRL] = { + .type = VCAP_FIELD_U32, + .offset = 60, + .width = 3, + }, + [VCAP_AF_NXT_IDX] = { + .type = VCAP_FIELD_U32, + .offset = 63, + .width = 12, + }, +}; + +static const struct vcap_field is0_classification_actionfield[] = { + [VCAP_AF_TYPE] = { + .type = VCAP_FIELD_BIT, + .offset = 0, + .width = 1, + }, + [VCAP_AF_DSCP_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 1, + .width = 1, + }, + [VCAP_AF_DSCP_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 2, + .width = 6, + }, + [VCAP_AF_COSID_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 8, + .width = 1, + }, + [VCAP_AF_COSID_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 9, + .width = 3, + }, + [VCAP_AF_QOS_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 12, + .width = 1, + }, + [VCAP_AF_QOS_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 13, + .width = 3, + }, + [VCAP_AF_DP_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 16, + .width = 1, + }, + [VCAP_AF_DP_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 17, + .width = 2, + }, + [VCAP_AF_DEI_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 19, + .width = 1, + }, + [VCAP_AF_DEI_VAL] = { + .type = VCAP_FIELD_BIT, + .offset = 20, + .width = 1, + }, + [VCAP_AF_PCP_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 21, + .width = 1, + }, + [VCAP_AF_PCP_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 22, + .width = 3, + }, + [VCAP_AF_MAP_LOOKUP_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 25, + .width = 2, + }, + [VCAP_AF_MAP_KEY] = { + .type = VCAP_FIELD_U32, + .offset = 27, + .width = 3, + }, + [VCAP_AF_MAP_IDX] = { + .type = VCAP_FIELD_U32, + .offset = 30, + .width = 9, + }, + [VCAP_AF_CLS_VID_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 39, + .width = 3, + }, + [VCAP_AF_GVID_ADD_REPLACE_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 42, + .width = 3, + }, + [VCAP_AF_VID_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 45, + .width = 13, + }, + [VCAP_AF_VLAN_POP_CNT_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 58, + .width = 1, + }, + [VCAP_AF_VLAN_POP_CNT] = { + .type = VCAP_FIELD_U32, + .offset = 59, + .width = 2, + }, + [VCAP_AF_VLAN_PUSH_CNT_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 61, + .width = 1, + }, + [VCAP_AF_VLAN_PUSH_CNT] = { + .type = VCAP_FIELD_U32, + .offset = 62, + .width = 2, + }, + [VCAP_AF_TPID_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 64, + .width = 2, + }, + [VCAP_AF_VLAN_WAS_TAGGED] = { + .type = VCAP_FIELD_U32, + .offset = 66, + .width = 2, + }, + [VCAP_AF_ISDX_ADD_REPLACE_SEL] = { + .type = VCAP_FIELD_BIT, + .offset = 68, + .width = 1, + }, + [VCAP_AF_ISDX_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 69, + .width = 12, + }, + [VCAP_AF_RT_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 81, + .width = 2, + }, + [VCAP_AF_LPM_AFFIX_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 83, + .width = 1, + }, + [VCAP_AF_LPM_AFFIX_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 84, + .width = 10, + }, + [VCAP_AF_RLEG_DMAC_CHK_DIS] = { + .type = VCAP_FIELD_BIT, + .offset = 94, + .width = 1, + }, + [VCAP_AF_TTL_DECR_DIS] = { + .type = VCAP_FIELD_BIT, + .offset = 95, + .width = 1, + }, + [VCAP_AF_L3_MAC_UPDATE_DIS] = { + .type = VCAP_FIELD_BIT, + .offset = 96, + .width = 1, + }, + [VCAP_AF_FWD_DIS] = { + .type = VCAP_FIELD_BIT, + .offset = 97, + .width = 1, + }, + [VCAP_AF_CPU_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 98, + .width = 1, + }, + [VCAP_AF_CPU_Q] = { + .type = VCAP_FIELD_U32, + .offset = 99, + .width = 3, + }, + [VCAP_AF_MIP_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 102, + .width = 2, + }, + [VCAP_AF_OAM_Y1731_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 104, + .width = 3, + }, + [VCAP_AF_OAM_TWAMP_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 107, + .width = 1, + }, + [VCAP_AF_OAM_IP_BFD_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 108, + .width = 1, + }, + [VCAP_AF_PAG_OVERRIDE_MASK] = { + .type = VCAP_FIELD_U32, + .offset = 109, + .width = 8, + }, + [VCAP_AF_PAG_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 117, + .width = 8, + }, + [VCAP_AF_S2_KEY_SEL_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 125, + .width = 1, + }, + [VCAP_AF_S2_KEY_SEL_IDX] = { + .type = VCAP_FIELD_U32, + .offset = 126, + .width = 6, + }, + [VCAP_AF_INJ_MASQ_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 132, + .width = 1, + }, + [VCAP_AF_INJ_MASQ_PORT] = { + .type = VCAP_FIELD_U32, + .offset = 133, + .width = 7, + }, + [VCAP_AF_LPORT_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 140, + .width = 1, + }, + [VCAP_AF_INJ_MASQ_LPORT] = { + .type = VCAP_FIELD_U32, + .offset = 141, + .width = 7, + }, + [VCAP_AF_PIPELINE_FORCE_ENA] = { + .type = VCAP_FIELD_U32, + .offset = 148, + .width = 2, + }, + [VCAP_AF_PIPELINE_ACT_SEL] = { + .type = VCAP_FIELD_BIT, + .offset = 150, + .width = 1, + }, + [VCAP_AF_PIPELINE_PT] = { + .type = VCAP_FIELD_U32, + .offset = 151, + .width = 5, + }, + [VCAP_AF_NXT_KEY_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 156, + .width = 5, + }, + [VCAP_AF_NXT_NORM_W16_OFFSET] = { + .type = VCAP_FIELD_U32, + .offset = 161, + .width = 5, + }, + [VCAP_AF_NXT_OFFSET_FROM_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 166, + .width = 2, + }, + [VCAP_AF_NXT_TYPE_AFTER_OFFSET] = { + .type = VCAP_FIELD_U32, + .offset = 168, + .width = 2, + }, + [VCAP_AF_NXT_NORMALIZE] = { + .type = VCAP_FIELD_BIT, + .offset = 170, + .width = 1, + }, + [VCAP_AF_NXT_IDX_CTRL] = { + .type = VCAP_FIELD_U32, + .offset = 171, + .width = 3, + }, + [VCAP_AF_NXT_IDX] = { + .type = VCAP_FIELD_U32, + .offset = 174, + .width = 12, + }, +}; + +static const struct vcap_field is0_full_actionfield[] = { + [VCAP_AF_DSCP_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 0, + .width = 1, + }, + [VCAP_AF_DSCP_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 1, + .width = 6, + }, + [VCAP_AF_COSID_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 7, + .width = 1, + }, + [VCAP_AF_COSID_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 8, + .width = 3, + }, + [VCAP_AF_QOS_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 11, + .width = 1, + }, + [VCAP_AF_QOS_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 12, + .width = 3, + }, + [VCAP_AF_DP_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 15, + .width = 1, + }, + [VCAP_AF_DP_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 16, + .width = 2, + }, + [VCAP_AF_DEI_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 18, + .width = 1, + }, + [VCAP_AF_DEI_VAL] = { + .type = VCAP_FIELD_BIT, + .offset = 19, + .width = 1, + }, + [VCAP_AF_PCP_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 20, + .width = 1, + }, + [VCAP_AF_PCP_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 21, + .width = 3, + }, + [VCAP_AF_MAP_LOOKUP_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 24, + .width = 2, + }, + [VCAP_AF_MAP_KEY] = { + .type = VCAP_FIELD_U32, + .offset = 26, + .width = 3, + }, + [VCAP_AF_MAP_IDX] = { + .type = VCAP_FIELD_U32, + .offset = 29, + .width = 9, + }, + [VCAP_AF_CLS_VID_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 38, + .width = 3, + }, + [VCAP_AF_GVID_ADD_REPLACE_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 41, + .width = 3, + }, + [VCAP_AF_VID_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 44, + .width = 13, + }, + [VCAP_AF_VLAN_POP_CNT_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 57, + .width = 1, + }, + [VCAP_AF_VLAN_POP_CNT] = { + .type = VCAP_FIELD_U32, + .offset = 58, + .width = 2, + }, + [VCAP_AF_VLAN_PUSH_CNT_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 60, + .width = 1, + }, + [VCAP_AF_VLAN_PUSH_CNT] = { + .type = VCAP_FIELD_U32, + .offset = 61, + .width = 2, + }, + [VCAP_AF_TPID_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 63, + .width = 2, + }, + [VCAP_AF_VLAN_WAS_TAGGED] = { + .type = VCAP_FIELD_U32, + .offset = 65, + .width = 2, + }, + [VCAP_AF_ISDX_ADD_REPLACE_SEL] = { + .type = VCAP_FIELD_BIT, + .offset = 67, + .width = 1, + }, + [VCAP_AF_ISDX_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 68, + .width = 12, + }, + [VCAP_AF_MASK_MODE] = { + .type = VCAP_FIELD_U32, + .offset = 80, + .width = 3, + }, + [VCAP_AF_PORT_MASK] = { + .type = VCAP_FIELD_U72, + .offset = 83, + .width = 65, + }, + [VCAP_AF_RT_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 148, + .width = 2, + }, + [VCAP_AF_LPM_AFFIX_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 150, + .width = 1, + }, + [VCAP_AF_LPM_AFFIX_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 151, + .width = 10, + }, + [VCAP_AF_RLEG_DMAC_CHK_DIS] = { + .type = VCAP_FIELD_BIT, + .offset = 161, + .width = 1, + }, + [VCAP_AF_TTL_DECR_DIS] = { + .type = VCAP_FIELD_BIT, + .offset = 162, + .width = 1, + }, + [VCAP_AF_L3_MAC_UPDATE_DIS] = { + .type = VCAP_FIELD_BIT, + .offset = 163, + .width = 1, + }, + [VCAP_AF_CPU_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 164, + .width = 1, + }, + [VCAP_AF_CPU_Q] = { + .type = VCAP_FIELD_U32, + .offset = 165, + .width = 3, + }, + [VCAP_AF_MIP_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 168, + .width = 2, + }, + [VCAP_AF_OAM_Y1731_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 170, + .width = 3, + }, + [VCAP_AF_OAM_TWAMP_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 173, + .width = 1, + }, + [VCAP_AF_OAM_IP_BFD_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 174, + .width = 1, + }, + [VCAP_AF_RSVD_LBL_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 175, + .width = 4, + }, + [VCAP_AF_TC_LABEL] = { + .type = VCAP_FIELD_U32, + .offset = 179, + .width = 3, + }, + [VCAP_AF_TTL_LABEL] = { + .type = VCAP_FIELD_U32, + .offset = 182, + .width = 3, + }, + [VCAP_AF_NUM_VLD_LABELS] = { + .type = VCAP_FIELD_U32, + .offset = 185, + .width = 2, + }, + [VCAP_AF_FWD_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 187, + .width = 3, + }, + [VCAP_AF_MPLS_OAM_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 190, + .width = 3, + }, + [VCAP_AF_MPLS_MEP_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 193, + .width = 1, + }, + [VCAP_AF_MPLS_MIP_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 194, + .width = 1, + }, + [VCAP_AF_MPLS_OAM_FLAVOR] = { + .type = VCAP_FIELD_BIT, + .offset = 195, + .width = 1, + }, + [VCAP_AF_MPLS_IP_CTRL_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 196, + .width = 1, + }, + [VCAP_AF_CUSTOM_ACE_ENA] = { + .type = VCAP_FIELD_U32, + .offset = 197, + .width = 5, + }, + [VCAP_AF_CUSTOM_ACE_OFFSET] = { + .type = VCAP_FIELD_U32, + .offset = 202, + .width = 2, + }, + [VCAP_AF_PAG_OVERRIDE_MASK] = { + .type = VCAP_FIELD_U32, + .offset = 204, + .width = 8, + }, + [VCAP_AF_PAG_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 212, + .width = 8, + }, + [VCAP_AF_S2_KEY_SEL_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 220, + .width = 1, + }, + [VCAP_AF_S2_KEY_SEL_IDX] = { + .type = VCAP_FIELD_U32, + .offset = 221, + .width = 6, + }, + [VCAP_AF_INJ_MASQ_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 227, + .width = 1, + }, + [VCAP_AF_INJ_MASQ_PORT] = { + .type = VCAP_FIELD_U32, + .offset = 228, + .width = 7, + }, + [VCAP_AF_LPORT_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 235, + .width = 1, + }, + [VCAP_AF_INJ_MASQ_LPORT] = { + .type = VCAP_FIELD_U32, + .offset = 236, + .width = 7, + }, + [VCAP_AF_MATCH_ID] = { + .type = VCAP_FIELD_U32, + .offset = 243, + .width = 16, + }, + [VCAP_AF_MATCH_ID_MASK] = { + .type = VCAP_FIELD_U32, + .offset = 259, + .width = 16, + }, + [VCAP_AF_PIPELINE_FORCE_ENA] = { + .type = VCAP_FIELD_U32, + .offset = 275, + .width = 2, + }, + [VCAP_AF_PIPELINE_ACT_SEL] = { + .type = VCAP_FIELD_BIT, + .offset = 277, + .width = 1, + }, + [VCAP_AF_PIPELINE_PT] = { + .type = VCAP_FIELD_U32, + .offset = 278, + .width = 5, + }, + [VCAP_AF_NXT_KEY_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 283, + .width = 5, + }, + [VCAP_AF_NXT_NORM_W16_OFFSET] = { + .type = VCAP_FIELD_U32, + .offset = 288, + .width = 5, + }, + [VCAP_AF_NXT_OFFSET_FROM_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 293, + .width = 2, + }, + [VCAP_AF_NXT_TYPE_AFTER_OFFSET] = { + .type = VCAP_FIELD_U32, + .offset = 295, + .width = 2, + }, + [VCAP_AF_NXT_NORMALIZE] = { + .type = VCAP_FIELD_BIT, + .offset = 297, + .width = 1, + }, + [VCAP_AF_NXT_IDX_CTRL] = { + .type = VCAP_FIELD_U32, + .offset = 298, + .width = 3, + }, + [VCAP_AF_NXT_IDX] = { + .type = VCAP_FIELD_U32, + .offset = 301, + .width = 12, + }, +}; + +static const struct vcap_field is0_class_reduced_actionfield[] = { + [VCAP_AF_TYPE] = { + .type = VCAP_FIELD_BIT, + .offset = 0, + .width = 1, + }, + [VCAP_AF_COSID_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 1, + .width = 1, + }, + [VCAP_AF_COSID_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 2, + .width = 3, + }, + [VCAP_AF_QOS_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 5, + .width = 1, + }, + [VCAP_AF_QOS_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 6, + .width = 3, + }, + [VCAP_AF_DP_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 9, + .width = 1, + }, + [VCAP_AF_DP_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 10, + .width = 2, + }, + [VCAP_AF_MAP_LOOKUP_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 12, + .width = 2, + }, + [VCAP_AF_MAP_KEY] = { + .type = VCAP_FIELD_U32, + .offset = 14, + .width = 3, + }, + [VCAP_AF_CLS_VID_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 17, + .width = 3, + }, + [VCAP_AF_GVID_ADD_REPLACE_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 20, + .width = 3, + }, + [VCAP_AF_VID_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 23, + .width = 13, + }, + [VCAP_AF_VLAN_POP_CNT_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 36, + .width = 1, + }, + [VCAP_AF_VLAN_POP_CNT] = { + .type = VCAP_FIELD_U32, + .offset = 37, + .width = 2, + }, + [VCAP_AF_VLAN_PUSH_CNT_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 39, + .width = 1, + }, + [VCAP_AF_VLAN_PUSH_CNT] = { + .type = VCAP_FIELD_U32, + .offset = 40, + .width = 2, + }, + [VCAP_AF_TPID_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 42, + .width = 2, + }, + [VCAP_AF_VLAN_WAS_TAGGED] = { + .type = VCAP_FIELD_U32, + .offset = 44, + .width = 2, + }, + [VCAP_AF_ISDX_ADD_REPLACE_SEL] = { + .type = VCAP_FIELD_BIT, + .offset = 46, + .width = 1, + }, + [VCAP_AF_ISDX_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 47, + .width = 12, + }, + [VCAP_AF_FWD_DIS] = { + .type = VCAP_FIELD_BIT, + .offset = 59, + .width = 1, + }, + [VCAP_AF_CPU_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 60, + .width = 1, + }, + [VCAP_AF_CPU_Q] = { + .type = VCAP_FIELD_U32, + .offset = 61, + .width = 3, + }, + [VCAP_AF_MIP_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 64, + .width = 2, + }, + [VCAP_AF_OAM_Y1731_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 66, + .width = 3, + }, + [VCAP_AF_LPORT_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 69, + .width = 1, + }, + [VCAP_AF_INJ_MASQ_LPORT] = { + .type = VCAP_FIELD_U32, + .offset = 70, + .width = 7, + }, + [VCAP_AF_PIPELINE_FORCE_ENA] = { + .type = VCAP_FIELD_U32, + .offset = 77, + .width = 2, + }, + [VCAP_AF_PIPELINE_ACT_SEL] = { + .type = VCAP_FIELD_BIT, + .offset = 79, + .width = 1, + }, + [VCAP_AF_PIPELINE_PT] = { + .type = VCAP_FIELD_U32, + .offset = 80, + .width = 5, + }, + [VCAP_AF_NXT_KEY_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 85, + .width = 5, + }, + [VCAP_AF_NXT_IDX_CTRL] = { + .type = VCAP_FIELD_U32, + .offset = 90, + .width = 3, + }, + [VCAP_AF_NXT_IDX] = { + .type = VCAP_FIELD_U32, + .offset = 93, + .width = 12, + }, +}; + +static const struct vcap_field is2_base_type_actionfield[] = { + [VCAP_AF_IS_INNER_ACL] = { + .type = VCAP_FIELD_BIT, + .offset = 0, + .width = 1, + }, + [VCAP_AF_PIPELINE_FORCE_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 1, + .width = 1, + }, + [VCAP_AF_PIPELINE_PT] = { + .type = VCAP_FIELD_U32, + .offset = 2, + .width = 5, + }, + [VCAP_AF_HIT_ME_ONCE] = { + .type = VCAP_FIELD_BIT, + .offset = 7, + .width = 1, + }, + [VCAP_AF_INTR_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 8, + .width = 1, + }, + [VCAP_AF_CPU_COPY_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 9, + .width = 1, + }, + [VCAP_AF_CPU_QUEUE_NUM] = { + .type = VCAP_FIELD_U32, + .offset = 10, + .width = 3, + }, + [VCAP_AF_CPU_DIS] = { + .type = VCAP_FIELD_BIT, + .offset = 13, + .width = 1, + }, + [VCAP_AF_LRN_DIS] = { + .type = VCAP_FIELD_BIT, + .offset = 14, + .width = 1, + }, + [VCAP_AF_RT_DIS] = { + .type = VCAP_FIELD_BIT, + .offset = 15, + .width = 1, + }, + [VCAP_AF_POLICE_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 16, + .width = 1, + }, + [VCAP_AF_POLICE_IDX] = { + .type = VCAP_FIELD_U32, + .offset = 17, + .width = 6, + }, + [VCAP_AF_IGNORE_PIPELINE_CTRL] = { + .type = VCAP_FIELD_BIT, + .offset = 23, + .width = 1, + }, + [VCAP_AF_DLB_OFFSET] = { + .type = VCAP_FIELD_U32, + .offset = 24, + .width = 3, + }, + [VCAP_AF_MASK_MODE] = { + .type = VCAP_FIELD_U32, + .offset = 27, + .width = 3, + }, + [VCAP_AF_PORT_MASK] = { + .type = VCAP_FIELD_U72, + .offset = 30, + .width = 68, + }, + [VCAP_AF_RSDX_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 98, + .width = 1, + }, + [VCAP_AF_RSDX_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 99, + .width = 12, + }, + [VCAP_AF_MIRROR_PROBE] = { + .type = VCAP_FIELD_U32, + .offset = 111, + .width = 2, + }, + [VCAP_AF_REW_CMD] = { + .type = VCAP_FIELD_U32, + .offset = 113, + .width = 11, + }, + [VCAP_AF_TTL_UPDATE_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 124, + .width = 1, + }, + [VCAP_AF_SAM_SEQ_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 125, + .width = 1, + }, + [VCAP_AF_TCP_UDP_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 126, + .width = 1, + }, + [VCAP_AF_TCP_UDP_DPORT] = { + .type = VCAP_FIELD_U32, + .offset = 127, + .width = 16, + }, + [VCAP_AF_TCP_UDP_SPORT] = { + .type = VCAP_FIELD_U32, + .offset = 143, + .width = 16, + }, + [VCAP_AF_MATCH_ID] = { + .type = VCAP_FIELD_U32, + .offset = 159, + .width = 16, + }, + [VCAP_AF_MATCH_ID_MASK] = { + .type = VCAP_FIELD_U32, + .offset = 175, + .width = 16, + }, + [VCAP_AF_CNT_ID] = { + .type = VCAP_FIELD_U32, + .offset = 191, + .width = 12, + }, + [VCAP_AF_SWAP_MAC_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 203, + .width = 1, + }, + [VCAP_AF_ACL_RT_MODE] = { + .type = VCAP_FIELD_U32, + .offset = 204, + .width = 4, + }, + [VCAP_AF_ACL_MAC] = { + .type = VCAP_FIELD_U48, + .offset = 208, + .width = 48, + }, + [VCAP_AF_DMAC_OFFSET_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 256, + .width = 1, + }, + [VCAP_AF_PTP_MASTER_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 257, + .width = 2, + }, + [VCAP_AF_LOG_MSG_INTERVAL] = { + .type = VCAP_FIELD_U32, + .offset = 259, + .width = 4, + }, + [VCAP_AF_SIP_IDX] = { + .type = VCAP_FIELD_U32, + .offset = 263, + .width = 5, + }, + [VCAP_AF_RLEG_STAT_IDX] = { + .type = VCAP_FIELD_U32, + .offset = 268, + .width = 3, + }, + [VCAP_AF_IGR_ACL_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 271, + .width = 1, + }, + [VCAP_AF_EGR_ACL_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 272, + .width = 1, + }, +}; + +static const struct vcap_field es2_base_type_actionfield[] = { + [VCAP_AF_HIT_ME_ONCE] = { + .type = VCAP_FIELD_BIT, + .offset = 0, + .width = 1, + }, + [VCAP_AF_INTR_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 1, + .width = 1, + }, + [VCAP_AF_FWD_MODE] = { + .type = VCAP_FIELD_U32, + .offset = 2, + .width = 2, + }, + [VCAP_AF_COPY_QUEUE_NUM] = { + .type = VCAP_FIELD_U32, + .offset = 4, + .width = 16, + }, + [VCAP_AF_COPY_PORT_NUM] = { + .type = VCAP_FIELD_U32, + .offset = 20, + .width = 7, + }, + [VCAP_AF_MIRROR_PROBE_ID] = { + .type = VCAP_FIELD_U32, + .offset = 27, + .width = 2, + }, + [VCAP_AF_CPU_COPY_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 29, + .width = 1, + }, + [VCAP_AF_CPU_QUEUE_NUM] = { + .type = VCAP_FIELD_U32, + .offset = 30, + .width = 3, + }, + [VCAP_AF_POLICE_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 33, + .width = 1, + }, + [VCAP_AF_POLICE_REMARK] = { + .type = VCAP_FIELD_BIT, + .offset = 34, + .width = 1, + }, + [VCAP_AF_POLICE_IDX] = { + .type = VCAP_FIELD_U32, + .offset = 35, + .width = 6, + }, + [VCAP_AF_ES2_REW_CMD] = { + .type = VCAP_FIELD_U32, + .offset = 41, + .width = 3, + }, + [VCAP_AF_CNT_ID] = { + .type = VCAP_FIELD_U32, + .offset = 44, + .width = 11, + }, + [VCAP_AF_IGNORE_PIPELINE_CTRL] = { + .type = VCAP_FIELD_BIT, + .offset = 55, + .width = 1, + }, +}; + +/* actionfield_set */ +static const struct vcap_set is0_actionfield_set[] = { + [VCAP_AFS_MLBS] = { + .type_id = 0, + .sw_per_item = 2, + .sw_cnt = 6, + }, + [VCAP_AFS_MLBS_REDUCED] = { + .type_id = 0, + .sw_per_item = 1, + .sw_cnt = 12, + }, + [VCAP_AFS_CLASSIFICATION] = { + .type_id = 1, + .sw_per_item = 2, + .sw_cnt = 6, + }, + [VCAP_AFS_FULL] = { + .type_id = -1, + .sw_per_item = 3, + .sw_cnt = 4, + }, + [VCAP_AFS_CLASS_REDUCED] = { + .type_id = 1, + .sw_per_item = 1, + .sw_cnt = 12, + }, +}; + +static const struct vcap_set is2_actionfield_set[] = { + [VCAP_AFS_BASE_TYPE] = { + .type_id = -1, + .sw_per_item = 3, + .sw_cnt = 4, + }, +}; + +static const struct vcap_set es2_actionfield_set[] = { + [VCAP_AFS_BASE_TYPE] = { + .type_id = -1, + .sw_per_item = 3, + .sw_cnt = 4, + }, +}; + +/* actionfield_set map */ +static const struct vcap_field *is0_actionfield_set_map[] = { + [VCAP_AFS_MLBS] = is0_mlbs_actionfield, + [VCAP_AFS_MLBS_REDUCED] = is0_mlbs_reduced_actionfield, + [VCAP_AFS_CLASSIFICATION] = is0_classification_actionfield, + [VCAP_AFS_FULL] = is0_full_actionfield, + [VCAP_AFS_CLASS_REDUCED] = is0_class_reduced_actionfield, +}; + +static const struct vcap_field *is2_actionfield_set_map[] = { + [VCAP_AFS_BASE_TYPE] = is2_base_type_actionfield, +}; + +static const struct vcap_field *es2_actionfield_set_map[] = { + [VCAP_AFS_BASE_TYPE] = es2_base_type_actionfield, +}; + +/* actionfield_set map size */ +static int is0_actionfield_set_map_size[] = { + [VCAP_AFS_MLBS] = ARRAY_SIZE(is0_mlbs_actionfield), + [VCAP_AFS_MLBS_REDUCED] = ARRAY_SIZE(is0_mlbs_reduced_actionfield), + [VCAP_AFS_CLASSIFICATION] = ARRAY_SIZE(is0_classification_actionfield), + [VCAP_AFS_FULL] = ARRAY_SIZE(is0_full_actionfield), + [VCAP_AFS_CLASS_REDUCED] = ARRAY_SIZE(is0_class_reduced_actionfield), +}; + +static int is2_actionfield_set_map_size[] = { + [VCAP_AFS_BASE_TYPE] = ARRAY_SIZE(is2_base_type_actionfield), +}; + +static int es2_actionfield_set_map_size[] = { + [VCAP_AFS_BASE_TYPE] = ARRAY_SIZE(es2_base_type_actionfield), +}; + +/* Type Groups */ +static const struct vcap_typegroup is0_x12_keyfield_set_typegroups[] = { + { + .offset = 0, + .width = 5, + .value = 16, + }, + { + .offset = 52, + .width = 1, + .value = 0, + }, + { + .offset = 104, + .width = 2, + .value = 0, + }, + { + .offset = 156, + .width = 3, + .value = 0, + }, + { + .offset = 208, + .width = 2, + .value = 0, + }, + { + .offset = 260, + .width = 1, + .value = 0, + }, + { + .offset = 312, + .width = 4, + .value = 0, + }, + { + .offset = 364, + .width = 1, + .value = 0, + }, + { + .offset = 416, + .width = 2, + .value = 0, + }, + { + .offset = 468, + .width = 3, + .value = 0, + }, + { + .offset = 520, + .width = 2, + .value = 0, + }, + { + .offset = 572, + .width = 1, + .value = 0, + }, + {} +}; + +static const struct vcap_typegroup is0_x6_keyfield_set_typegroups[] = { + { + .offset = 0, + .width = 4, + .value = 8, + }, + { + .offset = 52, + .width = 1, + .value = 0, + }, + { + .offset = 104, + .width = 2, + .value = 0, + }, + { + .offset = 156, + .width = 3, + .value = 0, + }, + { + .offset = 208, + .width = 2, + .value = 0, + }, + { + .offset = 260, + .width = 1, + .value = 0, + }, + {} +}; + +static const struct vcap_typegroup is0_x3_keyfield_set_typegroups[] = { + { + .offset = 0, + .width = 3, + .value = 4, + }, + { + .offset = 52, + .width = 2, + .value = 0, + }, + { + .offset = 104, + .width = 2, + .value = 0, + }, + {} +}; + +static const struct vcap_typegroup is0_x2_keyfield_set_typegroups[] = { + { + .offset = 0, + .width = 2, + .value = 2, + }, + { + .offset = 52, + .width = 1, + .value = 0, + }, + {} +}; + +static const struct vcap_typegroup is0_x1_keyfield_set_typegroups[] = { + {} +}; + +static const struct vcap_typegroup is2_x12_keyfield_set_typegroups[] = { + { + .offset = 0, + .width = 3, + .value = 4, + }, + { + .offset = 156, + .width = 1, + .value = 0, + }, + { + .offset = 312, + .width = 2, + .value = 0, + }, + { + .offset = 468, + .width = 1, + .value = 0, + }, + {} +}; + +static const struct vcap_typegroup is2_x6_keyfield_set_typegroups[] = { + { + .offset = 0, + .width = 2, + .value = 2, + }, + { + .offset = 156, + .width = 1, + .value = 0, + }, + {} +}; + +static const struct vcap_typegroup is2_x3_keyfield_set_typegroups[] = { + {} +}; + +static const struct vcap_typegroup is2_x1_keyfield_set_typegroups[] = { + {} +}; + +static const struct vcap_typegroup es2_x12_keyfield_set_typegroups[] = { + { + .offset = 0, + .width = 3, + .value = 4, + }, + { + .offset = 156, + .width = 1, + .value = 0, + }, + { + .offset = 312, + .width = 2, + .value = 0, + }, + { + .offset = 468, + .width = 1, + .value = 0, + }, + {} +}; + +static const struct vcap_typegroup es2_x6_keyfield_set_typegroups[] = { + { + .offset = 0, + .width = 2, + .value = 2, + }, + { + .offset = 156, + .width = 1, + .value = 0, + }, + {} +}; + +static const struct vcap_typegroup es2_x3_keyfield_set_typegroups[] = { + { + .offset = 0, + .width = 1, + .value = 1, + }, + {} +}; + +static const struct vcap_typegroup es2_x1_keyfield_set_typegroups[] = { + {} +}; + +static const struct vcap_typegroup *is0_keyfield_set_typegroups[] = { + [12] = is0_x12_keyfield_set_typegroups, + [6] = is0_x6_keyfield_set_typegroups, + [3] = is0_x3_keyfield_set_typegroups, + [2] = is0_x2_keyfield_set_typegroups, + [1] = is0_x1_keyfield_set_typegroups, + [13] = NULL, +}; + +static const struct vcap_typegroup *is2_keyfield_set_typegroups[] = { + [12] = is2_x12_keyfield_set_typegroups, + [6] = is2_x6_keyfield_set_typegroups, + [3] = is2_x3_keyfield_set_typegroups, + [1] = is2_x1_keyfield_set_typegroups, + [13] = NULL, +}; + +static const struct vcap_typegroup *es2_keyfield_set_typegroups[] = { + [12] = es2_x12_keyfield_set_typegroups, + [6] = es2_x6_keyfield_set_typegroups, + [3] = es2_x3_keyfield_set_typegroups, + [1] = es2_x1_keyfield_set_typegroups, + [13] = NULL, +}; + +static const struct vcap_typegroup is0_x3_actionfield_set_typegroups[] = { + { + .offset = 0, + .width = 3, + .value = 4, + }, + { + .offset = 110, + .width = 2, + .value = 0, + }, + { + .offset = 220, + .width = 2, + .value = 0, + }, + {} +}; + +static const struct vcap_typegroup is0_x2_actionfield_set_typegroups[] = { + { + .offset = 0, + .width = 2, + .value = 2, + }, + { + .offset = 110, + .width = 1, + .value = 0, + }, + {} +}; + +static const struct vcap_typegroup is0_x1_actionfield_set_typegroups[] = { + { + .offset = 0, + .width = 1, + .value = 1, + }, + {} +}; + +static const struct vcap_typegroup is2_x3_actionfield_set_typegroups[] = { + { + .offset = 0, + .width = 2, + .value = 2, + }, + { + .offset = 110, + .width = 1, + .value = 0, + }, + { + .offset = 220, + .width = 1, + .value = 0, + }, + {} +}; + +static const struct vcap_typegroup is2_x1_actionfield_set_typegroups[] = { + {} +}; + +static const struct vcap_typegroup es2_x3_actionfield_set_typegroups[] = { + { + .offset = 0, + .width = 2, + .value = 2, + }, + { + .offset = 21, + .width = 1, + .value = 0, + }, + { + .offset = 42, + .width = 1, + .value = 0, + }, + {} +}; + +static const struct vcap_typegroup es2_x1_actionfield_set_typegroups[] = { + {} +}; + +static const struct vcap_typegroup *is0_actionfield_set_typegroups[] = { + [3] = is0_x3_actionfield_set_typegroups, + [2] = is0_x2_actionfield_set_typegroups, + [1] = is0_x1_actionfield_set_typegroups, + [13] = NULL, +}; + +static const struct vcap_typegroup *is2_actionfield_set_typegroups[] = { + [3] = is2_x3_actionfield_set_typegroups, + [1] = is2_x1_actionfield_set_typegroups, + [13] = NULL, +}; + +static const struct vcap_typegroup *es2_actionfield_set_typegroups[] = { + [3] = es2_x3_actionfield_set_typegroups, + [1] = es2_x1_actionfield_set_typegroups, + [13] = NULL, +}; + +/* Keyfieldset names */ +static const char * const vcap_keyfield_set_names[] = { + [VCAP_KFS_NO_VALUE] = "(None)", + [VCAP_KFS_ARP] = "VCAP_KFS_ARP", + [VCAP_KFS_ETAG] = "VCAP_KFS_ETAG", + [VCAP_KFS_IP4_OTHER] = "VCAP_KFS_IP4_OTHER", + [VCAP_KFS_IP4_TCP_UDP] = "VCAP_KFS_IP4_TCP_UDP", + [VCAP_KFS_IP4_VID] = "VCAP_KFS_IP4_VID", + [VCAP_KFS_IP6_STD] = "VCAP_KFS_IP6_STD", + [VCAP_KFS_IP6_VID] = "VCAP_KFS_IP6_VID", + [VCAP_KFS_IP_7TUPLE] = "VCAP_KFS_IP_7TUPLE", + [VCAP_KFS_LL_FULL] = "VCAP_KFS_LL_FULL", + [VCAP_KFS_MAC_ETYPE] = "VCAP_KFS_MAC_ETYPE", + [VCAP_KFS_MLL] = "VCAP_KFS_MLL", + [VCAP_KFS_NORMAL] = "VCAP_KFS_NORMAL", + [VCAP_KFS_NORMAL_5TUPLE_IP4] = "VCAP_KFS_NORMAL_5TUPLE_IP4", + [VCAP_KFS_NORMAL_7TUPLE] = "VCAP_KFS_NORMAL_7TUPLE", + [VCAP_KFS_PURE_5TUPLE_IP4] = "VCAP_KFS_PURE_5TUPLE_IP4", + [VCAP_KFS_TRI_VID] = "VCAP_KFS_TRI_VID", +}; + +/* Actionfieldset names */ +static const char * const vcap_actionfield_set_names[] = { + [VCAP_AFS_NO_VALUE] = "(None)", + [VCAP_AFS_BASE_TYPE] = "VCAP_AFS_BASE_TYPE", + [VCAP_AFS_CLASSIFICATION] = "VCAP_AFS_CLASSIFICATION", + [VCAP_AFS_CLASS_REDUCED] = "VCAP_AFS_CLASS_REDUCED", + [VCAP_AFS_FULL] = "VCAP_AFS_FULL", + [VCAP_AFS_MLBS] = "VCAP_AFS_MLBS", + [VCAP_AFS_MLBS_REDUCED] = "VCAP_AFS_MLBS_REDUCED", +}; + +/* Keyfield names */ +static const char * const vcap_keyfield_names[] = { + [VCAP_KF_NO_VALUE] = "(None)", + [VCAP_KF_8021BR_ECID_BASE] = "8021BR_ECID_BASE", + [VCAP_KF_8021BR_ECID_EXT] = "8021BR_ECID_EXT", + [VCAP_KF_8021BR_E_TAGGED] = "8021BR_E_TAGGED", + [VCAP_KF_8021BR_GRP] = "8021BR_GRP", + [VCAP_KF_8021BR_IGR_ECID_BASE] = "8021BR_IGR_ECID_BASE", + [VCAP_KF_8021BR_IGR_ECID_EXT] = "8021BR_IGR_ECID_EXT", + [VCAP_KF_8021Q_DEI0] = "8021Q_DEI0", + [VCAP_KF_8021Q_DEI1] = "8021Q_DEI1", + [VCAP_KF_8021Q_DEI2] = "8021Q_DEI2", + [VCAP_KF_8021Q_DEI_CLS] = "8021Q_DEI_CLS", + [VCAP_KF_8021Q_PCP0] = "8021Q_PCP0", + [VCAP_KF_8021Q_PCP1] = "8021Q_PCP1", + [VCAP_KF_8021Q_PCP2] = "8021Q_PCP2", + [VCAP_KF_8021Q_PCP_CLS] = "8021Q_PCP_CLS", + [VCAP_KF_8021Q_TPID0] = "8021Q_TPID0", + [VCAP_KF_8021Q_TPID1] = "8021Q_TPID1", + [VCAP_KF_8021Q_TPID2] = "8021Q_TPID2", + [VCAP_KF_8021Q_VID0] = "8021Q_VID0", + [VCAP_KF_8021Q_VID1] = "8021Q_VID1", + [VCAP_KF_8021Q_VID2] = "8021Q_VID2", + [VCAP_KF_8021Q_VID_CLS] = "8021Q_VID_CLS", + [VCAP_KF_8021Q_VLAN_TAGGED_IS] = "8021Q_VLAN_TAGGED_IS", + [VCAP_KF_8021Q_VLAN_TAGS] = "8021Q_VLAN_TAGS", + [VCAP_KF_ACL_GRP_ID] = "ACL_GRP_ID", + [VCAP_KF_ARP_ADDR_SPACE_OK_IS] = "ARP_ADDR_SPACE_OK_IS", + [VCAP_KF_ARP_LEN_OK_IS] = "ARP_LEN_OK_IS", + [VCAP_KF_ARP_OPCODE] = "ARP_OPCODE", + [VCAP_KF_ARP_OPCODE_UNKNOWN_IS] = "ARP_OPCODE_UNKNOWN_IS", + [VCAP_KF_ARP_PROTO_SPACE_OK_IS] = "ARP_PROTO_SPACE_OK_IS", + [VCAP_KF_ARP_SENDER_MATCH_IS] = "ARP_SENDER_MATCH_IS", + [VCAP_KF_ARP_TGT_MATCH_IS] = "ARP_TGT_MATCH_IS", + [VCAP_KF_COSID_CLS] = "COSID_CLS", + [VCAP_KF_DST_ENTRY] = "DST_ENTRY", + [VCAP_KF_ES0_ISDX_KEY_ENA] = "ES0_ISDX_KEY_ENA", + [VCAP_KF_ETYPE] = "ETYPE", + [VCAP_KF_ETYPE_LEN_IS] = "ETYPE_LEN_IS", + [VCAP_KF_ETYPE_MPLS] = "ETYPE_MPLS", + [VCAP_KF_IF_EGR_PORT_MASK] = "IF_EGR_PORT_MASK", + [VCAP_KF_IF_EGR_PORT_MASK_RNG] = "IF_EGR_PORT_MASK_RNG", + [VCAP_KF_IF_IGR_PORT] = "IF_IGR_PORT", + [VCAP_KF_IF_IGR_PORT_MASK] = "IF_IGR_PORT_MASK", + [VCAP_KF_IF_IGR_PORT_MASK_L3] = "IF_IGR_PORT_MASK_L3", + [VCAP_KF_IF_IGR_PORT_MASK_RNG] = "IF_IGR_PORT_MASK_RNG", + [VCAP_KF_IF_IGR_PORT_MASK_SEL] = "IF_IGR_PORT_MASK_SEL", + [VCAP_KF_IF_IGR_PORT_SEL] = "IF_IGR_PORT_SEL", + [VCAP_KF_IP4_IS] = "IP4_IS", + [VCAP_KF_IP_MC_IS] = "IP_MC_IS", + [VCAP_KF_IP_PAYLOAD_5TUPLE] = "IP_PAYLOAD_5TUPLE", + [VCAP_KF_IP_SNAP_IS] = "IP_SNAP_IS", + [VCAP_KF_ISDX_CLS] = "ISDX_CLS", + [VCAP_KF_ISDX_GT0_IS] = "ISDX_GT0_IS", + [VCAP_KF_L2_BC_IS] = "L2_BC_IS", + [VCAP_KF_L2_DMAC] = "L2_DMAC", + [VCAP_KF_L2_FWD_IS] = "L2_FWD_IS", + [VCAP_KF_L2_MC_IS] = "L2_MC_IS", + [VCAP_KF_L2_PAYLOAD_ETYPE] = "L2_PAYLOAD_ETYPE", + [VCAP_KF_L2_SMAC] = "L2_SMAC", + [VCAP_KF_L3_DIP_EQ_SIP_IS] = "L3_DIP_EQ_SIP_IS", + [VCAP_KF_L3_DMAC_DIP_MATCH] = "L3_DMAC_DIP_MATCH", + [VCAP_KF_L3_DPL_CLS] = "L3_DPL_CLS", + [VCAP_KF_L3_DSCP] = "L3_DSCP", + [VCAP_KF_L3_DST_IS] = "L3_DST_IS", + [VCAP_KF_L3_FRAGMENT_TYPE] = "L3_FRAGMENT_TYPE", + [VCAP_KF_L3_FRAG_INVLD_L4_LEN] = "L3_FRAG_INVLD_L4_LEN", + [VCAP_KF_L3_IP4_DIP] = "L3_IP4_DIP", + [VCAP_KF_L3_IP4_SIP] = "L3_IP4_SIP", + [VCAP_KF_L3_IP6_DIP] = "L3_IP6_DIP", + [VCAP_KF_L3_IP6_SIP] = "L3_IP6_SIP", + [VCAP_KF_L3_IP_PROTO] = "L3_IP_PROTO", + [VCAP_KF_L3_OPTIONS_IS] = "L3_OPTIONS_IS", + [VCAP_KF_L3_PAYLOAD] = "L3_PAYLOAD", + [VCAP_KF_L3_RT_IS] = "L3_RT_IS", + [VCAP_KF_L3_SMAC_SIP_MATCH] = "L3_SMAC_SIP_MATCH", + [VCAP_KF_L3_TOS] = "L3_TOS", + [VCAP_KF_L3_TTL_GT0] = "L3_TTL_GT0", + [VCAP_KF_L4_ACK] = "L4_ACK", + [VCAP_KF_L4_DPORT] = "L4_DPORT", + [VCAP_KF_L4_FIN] = "L4_FIN", + [VCAP_KF_L4_PAYLOAD] = "L4_PAYLOAD", + [VCAP_KF_L4_PSH] = "L4_PSH", + [VCAP_KF_L4_RNG] = "L4_RNG", + [VCAP_KF_L4_RST] = "L4_RST", + [VCAP_KF_L4_SEQUENCE_EQ0_IS] = "L4_SEQUENCE_EQ0_IS", + [VCAP_KF_L4_SPORT] = "L4_SPORT", + [VCAP_KF_L4_SPORT_EQ_DPORT_IS] = "L4_SPORT_EQ_DPORT_IS", + [VCAP_KF_L4_SYN] = "L4_SYN", + [VCAP_KF_L4_URG] = "L4_URG", + [VCAP_KF_LOOKUP_FIRST_IS] = "LOOKUP_FIRST_IS", + [VCAP_KF_LOOKUP_GEN_IDX] = "LOOKUP_GEN_IDX", + [VCAP_KF_LOOKUP_GEN_IDX_SEL] = "LOOKUP_GEN_IDX_SEL", + [VCAP_KF_LOOKUP_PAG] = "LOOKUP_PAG", + [VCAP_KF_MIRROR_ENA] = "MIRROR_ENA", + [VCAP_KF_OAM_CCM_CNTS_EQ0] = "OAM_CCM_CNTS_EQ0", + [VCAP_KF_OAM_MEL_FLAGS] = "OAM_MEL_FLAGS", + [VCAP_KF_OAM_Y1731_IS] = "OAM_Y1731_IS", + [VCAP_KF_PROT_ACTIVE] = "PROT_ACTIVE", + [VCAP_KF_TCP_IS] = "TCP_IS", + [VCAP_KF_TCP_UDP_IS] = "TCP_UDP_IS", + [VCAP_KF_TYPE] = "TYPE", +}; + +/* Actionfield names */ +static const char * const vcap_actionfield_names[] = { + [VCAP_AF_NO_VALUE] = "(None)", + [VCAP_AF_ACL_MAC] = "ACL_MAC", + [VCAP_AF_ACL_RT_MODE] = "ACL_RT_MODE", + [VCAP_AF_CLS_VID_SEL] = "CLS_VID_SEL", + [VCAP_AF_CNT_ID] = "CNT_ID", + [VCAP_AF_COPY_PORT_NUM] = "COPY_PORT_NUM", + [VCAP_AF_COPY_QUEUE_NUM] = "COPY_QUEUE_NUM", + [VCAP_AF_COSID_ENA] = "COSID_ENA", + [VCAP_AF_COSID_VAL] = "COSID_VAL", + [VCAP_AF_CPU_COPY_ENA] = "CPU_COPY_ENA", + [VCAP_AF_CPU_DIS] = "CPU_DIS", + [VCAP_AF_CPU_ENA] = "CPU_ENA", + [VCAP_AF_CPU_Q] = "CPU_Q", + [VCAP_AF_CPU_QUEUE_NUM] = "CPU_QUEUE_NUM", + [VCAP_AF_CUSTOM_ACE_ENA] = "CUSTOM_ACE_ENA", + [VCAP_AF_CUSTOM_ACE_OFFSET] = "CUSTOM_ACE_OFFSET", + [VCAP_AF_DEI_ENA] = "DEI_ENA", + [VCAP_AF_DEI_VAL] = "DEI_VAL", + [VCAP_AF_DLB_OFFSET] = "DLB_OFFSET", + [VCAP_AF_DMAC_OFFSET_ENA] = "DMAC_OFFSET_ENA", + [VCAP_AF_DP_ENA] = "DP_ENA", + [VCAP_AF_DP_VAL] = "DP_VAL", + [VCAP_AF_DSCP_ENA] = "DSCP_ENA", + [VCAP_AF_DSCP_VAL] = "DSCP_VAL", + [VCAP_AF_EGR_ACL_ENA] = "EGR_ACL_ENA", + [VCAP_AF_ES2_REW_CMD] = "ES2_REW_CMD", + [VCAP_AF_FWD_DIS] = "FWD_DIS", + [VCAP_AF_FWD_MODE] = "FWD_MODE", + [VCAP_AF_FWD_TYPE] = "FWD_TYPE", + [VCAP_AF_GVID_ADD_REPLACE_SEL] = "GVID_ADD_REPLACE_SEL", + [VCAP_AF_HIT_ME_ONCE] = "HIT_ME_ONCE", + [VCAP_AF_IGNORE_PIPELINE_CTRL] = "IGNORE_PIPELINE_CTRL", + [VCAP_AF_IGR_ACL_ENA] = "IGR_ACL_ENA", + [VCAP_AF_INJ_MASQ_ENA] = "INJ_MASQ_ENA", + [VCAP_AF_INJ_MASQ_LPORT] = "INJ_MASQ_LPORT", + [VCAP_AF_INJ_MASQ_PORT] = "INJ_MASQ_PORT", + [VCAP_AF_INTR_ENA] = "INTR_ENA", + [VCAP_AF_ISDX_ADD_REPLACE_SEL] = "ISDX_ADD_REPLACE_SEL", + [VCAP_AF_ISDX_VAL] = "ISDX_VAL", + [VCAP_AF_IS_INNER_ACL] = "IS_INNER_ACL", + [VCAP_AF_L3_MAC_UPDATE_DIS] = "L3_MAC_UPDATE_DIS", + [VCAP_AF_LOG_MSG_INTERVAL] = "LOG_MSG_INTERVAL", + [VCAP_AF_LPM_AFFIX_ENA] = "LPM_AFFIX_ENA", + [VCAP_AF_LPM_AFFIX_VAL] = "LPM_AFFIX_VAL", + [VCAP_AF_LPORT_ENA] = "LPORT_ENA", + [VCAP_AF_LRN_DIS] = "LRN_DIS", + [VCAP_AF_MAP_IDX] = "MAP_IDX", + [VCAP_AF_MAP_KEY] = "MAP_KEY", + [VCAP_AF_MAP_LOOKUP_SEL] = "MAP_LOOKUP_SEL", + [VCAP_AF_MASK_MODE] = "MASK_MODE", + [VCAP_AF_MATCH_ID] = "MATCH_ID", + [VCAP_AF_MATCH_ID_MASK] = "MATCH_ID_MASK", + [VCAP_AF_MIP_SEL] = "MIP_SEL", + [VCAP_AF_MIRROR_PROBE] = "MIRROR_PROBE", + [VCAP_AF_MIRROR_PROBE_ID] = "MIRROR_PROBE_ID", + [VCAP_AF_MPLS_IP_CTRL_ENA] = "MPLS_IP_CTRL_ENA", + [VCAP_AF_MPLS_MEP_ENA] = "MPLS_MEP_ENA", + [VCAP_AF_MPLS_MIP_ENA] = "MPLS_MIP_ENA", + [VCAP_AF_MPLS_OAM_FLAVOR] = "MPLS_OAM_FLAVOR", + [VCAP_AF_MPLS_OAM_TYPE] = "MPLS_OAM_TYPE", + [VCAP_AF_NUM_VLD_LABELS] = "NUM_VLD_LABELS", + [VCAP_AF_NXT_IDX] = "NXT_IDX", + [VCAP_AF_NXT_IDX_CTRL] = "NXT_IDX_CTRL", + [VCAP_AF_NXT_KEY_TYPE] = "NXT_KEY_TYPE", + [VCAP_AF_NXT_NORMALIZE] = "NXT_NORMALIZE", + [VCAP_AF_NXT_NORM_W16_OFFSET] = "NXT_NORM_W16_OFFSET", + [VCAP_AF_NXT_NORM_W32_OFFSET] = "NXT_NORM_W32_OFFSET", + [VCAP_AF_NXT_OFFSET_FROM_TYPE] = "NXT_OFFSET_FROM_TYPE", + [VCAP_AF_NXT_TYPE_AFTER_OFFSET] = "NXT_TYPE_AFTER_OFFSET", + [VCAP_AF_OAM_IP_BFD_ENA] = "OAM_IP_BFD_ENA", + [VCAP_AF_OAM_TWAMP_ENA] = "OAM_TWAMP_ENA", + [VCAP_AF_OAM_Y1731_SEL] = "OAM_Y1731_SEL", + [VCAP_AF_PAG_OVERRIDE_MASK] = "PAG_OVERRIDE_MASK", + [VCAP_AF_PAG_VAL] = "PAG_VAL", + [VCAP_AF_PCP_ENA] = "PCP_ENA", + [VCAP_AF_PCP_VAL] = "PCP_VAL", + [VCAP_AF_PIPELINE_ACT_SEL] = "PIPELINE_ACT_SEL", + [VCAP_AF_PIPELINE_FORCE_ENA] = "PIPELINE_FORCE_ENA", + [VCAP_AF_PIPELINE_PT] = "PIPELINE_PT", + [VCAP_AF_PIPELINE_PT_REDUCED] = "PIPELINE_PT_REDUCED", + [VCAP_AF_POLICE_ENA] = "POLICE_ENA", + [VCAP_AF_POLICE_IDX] = "POLICE_IDX", + [VCAP_AF_POLICE_REMARK] = "POLICE_REMARK", + [VCAP_AF_PORT_MASK] = "PORT_MASK", + [VCAP_AF_PTP_MASTER_SEL] = "PTP_MASTER_SEL", + [VCAP_AF_QOS_ENA] = "QOS_ENA", + [VCAP_AF_QOS_VAL] = "QOS_VAL", + [VCAP_AF_REW_CMD] = "REW_CMD", + [VCAP_AF_RLEG_DMAC_CHK_DIS] = "RLEG_DMAC_CHK_DIS", + [VCAP_AF_RLEG_STAT_IDX] = "RLEG_STAT_IDX", + [VCAP_AF_RSDX_ENA] = "RSDX_ENA", + [VCAP_AF_RSDX_VAL] = "RSDX_VAL", + [VCAP_AF_RSVD_LBL_VAL] = "RSVD_LBL_VAL", + [VCAP_AF_RT_DIS] = "RT_DIS", + [VCAP_AF_RT_SEL] = "RT_SEL", + [VCAP_AF_S2_KEY_SEL_ENA] = "S2_KEY_SEL_ENA", + [VCAP_AF_S2_KEY_SEL_IDX] = "S2_KEY_SEL_IDX", + [VCAP_AF_SAM_SEQ_ENA] = "SAM_SEQ_ENA", + [VCAP_AF_SIP_IDX] = "SIP_IDX", + [VCAP_AF_SWAP_MAC_ENA] = "SWAP_MAC_ENA", + [VCAP_AF_TCP_UDP_DPORT] = "TCP_UDP_DPORT", + [VCAP_AF_TCP_UDP_ENA] = "TCP_UDP_ENA", + [VCAP_AF_TCP_UDP_SPORT] = "TCP_UDP_SPORT", + [VCAP_AF_TC_ENA] = "TC_ENA", + [VCAP_AF_TC_LABEL] = "TC_LABEL", + [VCAP_AF_TPID_SEL] = "TPID_SEL", + [VCAP_AF_TTL_DECR_DIS] = "TTL_DECR_DIS", + [VCAP_AF_TTL_ENA] = "TTL_ENA", + [VCAP_AF_TTL_LABEL] = "TTL_LABEL", + [VCAP_AF_TTL_UPDATE_ENA] = "TTL_UPDATE_ENA", + [VCAP_AF_TYPE] = "TYPE", + [VCAP_AF_VID_VAL] = "VID_VAL", + [VCAP_AF_VLAN_POP_CNT] = "VLAN_POP_CNT", + [VCAP_AF_VLAN_POP_CNT_ENA] = "VLAN_POP_CNT_ENA", + [VCAP_AF_VLAN_PUSH_CNT] = "VLAN_PUSH_CNT", + [VCAP_AF_VLAN_PUSH_CNT_ENA] = "VLAN_PUSH_CNT_ENA", + [VCAP_AF_VLAN_WAS_TAGGED] = "VLAN_WAS_TAGGED", +}; + +/* VCAPs */ +const struct vcap_info kunit_test_vcaps[] = { + [VCAP_TYPE_IS0] = { + .name = "is0", + .rows = 1024, + .sw_count = 12, + .sw_width = 52, + .sticky_width = 1, + .act_width = 110, + .default_cnt = 140, + .require_cnt_dis = 0, + .version = 1, + .keyfield_set = is0_keyfield_set, + .keyfield_set_size = ARRAY_SIZE(is0_keyfield_set), + .actionfield_set = is0_actionfield_set, + .actionfield_set_size = ARRAY_SIZE(is0_actionfield_set), + .keyfield_set_map = is0_keyfield_set_map, + .keyfield_set_map_size = is0_keyfield_set_map_size, + .actionfield_set_map = is0_actionfield_set_map, + .actionfield_set_map_size = is0_actionfield_set_map_size, + .keyfield_set_typegroups = is0_keyfield_set_typegroups, + .actionfield_set_typegroups = is0_actionfield_set_typegroups, + }, + [VCAP_TYPE_IS2] = { + .name = "is2", + .rows = 256, + .sw_count = 12, + .sw_width = 52, + .sticky_width = 1, + .act_width = 110, + .default_cnt = 73, + .require_cnt_dis = 0, + .version = 1, + .keyfield_set = is2_keyfield_set, + .keyfield_set_size = ARRAY_SIZE(is2_keyfield_set), + .actionfield_set = is2_actionfield_set, + .actionfield_set_size = ARRAY_SIZE(is2_actionfield_set), + .keyfield_set_map = is2_keyfield_set_map, + .keyfield_set_map_size = is2_keyfield_set_map_size, + .actionfield_set_map = is2_actionfield_set_map, + .actionfield_set_map_size = is2_actionfield_set_map_size, + .keyfield_set_typegroups = is2_keyfield_set_typegroups, + .actionfield_set_typegroups = is2_actionfield_set_typegroups, + }, + [VCAP_TYPE_ES2] = { + .name = "es2", + .rows = 1024, + .sw_count = 12, + .sw_width = 52, + .sticky_width = 1, + .act_width = 21, + .default_cnt = 74, + .require_cnt_dis = 0, + .version = 1, + .keyfield_set = es2_keyfield_set, + .keyfield_set_size = ARRAY_SIZE(es2_keyfield_set), + .actionfield_set = es2_actionfield_set, + .actionfield_set_size = ARRAY_SIZE(es2_actionfield_set), + .keyfield_set_map = es2_keyfield_set_map, + .keyfield_set_map_size = es2_keyfield_set_map_size, + .actionfield_set_map = es2_actionfield_set_map, + .actionfield_set_map_size = es2_actionfield_set_map_size, + .keyfield_set_typegroups = es2_keyfield_set_typegroups, + .actionfield_set_typegroups = es2_actionfield_set_typegroups, + }, +}; + +const struct vcap_statistics kunit_test_vcap_stats = { + .name = "kunit_test", + .count = 3, + .keyfield_set_names = vcap_keyfield_set_names, + .actionfield_set_names = vcap_actionfield_set_names, + .keyfield_names = vcap_keyfield_names, + .actionfield_names = vcap_actionfield_names, +}; diff --git a/drivers/net/ethernet/microchip/vcap/vcap_model_kunit.h b/drivers/net/ethernet/microchip/vcap/vcap_model_kunit.h new file mode 100644 index 000000000000..b5a74f0eef9b --- /dev/null +++ b/drivers/net/ethernet/microchip/vcap/vcap_model_kunit.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* Copyright (C) 2022 Microchip Technology Inc. and its subsidiaries. + * Microchip VCAP test model interface for kunit testing + */ + +#ifndef __VCAP_MODEL_KUNIT_H__ +#define __VCAP_MODEL_KUNIT_H__ +extern const struct vcap_info kunit_test_vcaps[]; +extern const struct vcap_statistics kunit_test_vcap_stats; +#endif /* __VCAP_MODEL_KUNIT_H__ */ diff --git a/drivers/net/ethernet/netronome/nfp/flower/lag_conf.c b/drivers/net/ethernet/netronome/nfp/flower/lag_conf.c index e92860e20a24..88d6d992e7d0 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/lag_conf.c +++ b/drivers/net/ethernet/netronome/nfp/flower/lag_conf.c @@ -154,10 +154,11 @@ nfp_fl_lag_find_group_for_master_with_lag(struct nfp_fl_lag *lag, return NULL; } -int nfp_flower_lag_populate_pre_action(struct nfp_app *app, - struct net_device *master, - struct nfp_fl_pre_lag *pre_act, - struct netlink_ext_ack *extack) +static int nfp_fl_lag_get_group_info(struct nfp_app *app, + struct net_device *netdev, + __be16 *group_id, + u8 *batch_ver, + u8 *group_inst) { struct nfp_flower_priv *priv = app->priv; struct nfp_fl_lag_group *group = NULL; @@ -165,23 +166,52 @@ int nfp_flower_lag_populate_pre_action(struct nfp_app *app, mutex_lock(&priv->nfp_lag.lock); group = nfp_fl_lag_find_group_for_master_with_lag(&priv->nfp_lag, - master); + netdev); if (!group) { mutex_unlock(&priv->nfp_lag.lock); - NL_SET_ERR_MSG_MOD(extack, "invalid entry: group does not exist for LAG action"); return -ENOENT; } - pre_act->group_id = cpu_to_be16(group->group_id); - temp_vers = cpu_to_be32(priv->nfp_lag.batch_ver << - NFP_FL_PRE_LAG_VER_OFF); - memcpy(pre_act->lag_version, &temp_vers, 3); - pre_act->instance = group->group_inst; + if (group_id) + *group_id = cpu_to_be16(group->group_id); + + if (batch_ver) { + temp_vers = cpu_to_be32(priv->nfp_lag.batch_ver << + NFP_FL_PRE_LAG_VER_OFF); + memcpy(batch_ver, &temp_vers, 3); + } + + if (group_inst) + *group_inst = group->group_inst; + mutex_unlock(&priv->nfp_lag.lock); return 0; } +int nfp_flower_lag_populate_pre_action(struct nfp_app *app, + struct net_device *master, + struct nfp_fl_pre_lag *pre_act, + struct netlink_ext_ack *extack) +{ + if (nfp_fl_lag_get_group_info(app, master, &pre_act->group_id, + pre_act->lag_version, + &pre_act->instance)) { + NL_SET_ERR_MSG_MOD(extack, "invalid entry: group does not exist for LAG action"); + return -ENOENT; + } + + return 0; +} + +void nfp_flower_lag_get_info_from_netdev(struct nfp_app *app, + struct net_device *netdev, + struct nfp_tun_neigh_lag *lag) +{ + nfp_fl_lag_get_group_info(app, netdev, NULL, + lag->lag_version, &lag->lag_instance); +} + int nfp_flower_lag_get_output_id(struct nfp_app *app, struct net_device *master) { struct nfp_flower_priv *priv = app->priv; diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.c b/drivers/net/ethernet/netronome/nfp/flower/main.c index 4d960a9641b3..83eaa5ae3cd4 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/main.c +++ b/drivers/net/ethernet/netronome/nfp/flower/main.c @@ -76,7 +76,9 @@ nfp_flower_get_internal_port_id(struct nfp_app *app, struct net_device *netdev) u32 nfp_flower_get_port_id_from_netdev(struct nfp_app *app, struct net_device *netdev) { + struct nfp_flower_priv *priv = app->priv; int ext_port; + int gid; if (nfp_netdev_is_nfp_repr(netdev)) { return nfp_repr_get_port_id(netdev); @@ -86,6 +88,13 @@ u32 nfp_flower_get_port_id_from_netdev(struct nfp_app *app, return 0; return nfp_flower_internal_port_get_port_id(ext_port); + } else if (netif_is_lag_master(netdev) && + priv->flower_ext_feats & NFP_FL_FEATS_TUNNEL_NEIGH_LAG) { + gid = nfp_flower_lag_get_output_id(app, netdev); + if (gid < 0) + return 0; + + return (NFP_FL_LAG_OUT | gid); } return 0; diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.h b/drivers/net/ethernet/netronome/nfp/flower/main.h index cb799d18682d..40372545148e 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/main.h +++ b/drivers/net/ethernet/netronome/nfp/flower/main.h @@ -52,6 +52,7 @@ struct nfp_app; #define NFP_FL_FEATS_QOS_PPS BIT(9) #define NFP_FL_FEATS_QOS_METER BIT(10) #define NFP_FL_FEATS_DECAP_V2 BIT(11) +#define NFP_FL_FEATS_TUNNEL_NEIGH_LAG BIT(12) #define NFP_FL_FEATS_HOST_ACK BIT(31) #define NFP_FL_ENABLE_FLOW_MERGE BIT(0) @@ -69,7 +70,8 @@ struct nfp_app; NFP_FL_FEATS_VLAN_QINQ | \ NFP_FL_FEATS_QOS_PPS | \ NFP_FL_FEATS_QOS_METER | \ - NFP_FL_FEATS_DECAP_V2) + NFP_FL_FEATS_DECAP_V2 | \ + NFP_FL_FEATS_TUNNEL_NEIGH_LAG) struct nfp_fl_mask_id { struct circ_buf mask_id_free_list; @@ -104,6 +106,16 @@ struct nfp_fl_tunnel_offloads { }; /** + * struct nfp_tun_neigh_lag - lag info + * @lag_version: lag version + * @lag_instance: lag instance + */ +struct nfp_tun_neigh_lag { + u8 lag_version[3]; + u8 lag_instance; +}; + +/** * struct nfp_tun_neigh - basic neighbour data * @dst_addr: Destination MAC address * @src_addr: Source MAC address @@ -133,12 +145,14 @@ struct nfp_tun_neigh_ext { * @src_ipv4: Source IPv4 address * @common: Neighbour/route common info * @ext: Neighbour/route extended info + * @lag: lag port info */ struct nfp_tun_neigh_v4 { __be32 dst_ipv4; __be32 src_ipv4; struct nfp_tun_neigh common; struct nfp_tun_neigh_ext ext; + struct nfp_tun_neigh_lag lag; }; /** @@ -147,12 +161,14 @@ struct nfp_tun_neigh_v4 { * @src_ipv6: Source IPv6 address * @common: Neighbour/route common info * @ext: Neighbour/route extended info + * @lag: lag port info */ struct nfp_tun_neigh_v6 { struct in6_addr dst_ipv6; struct in6_addr src_ipv6; struct nfp_tun_neigh common; struct nfp_tun_neigh_ext ext; + struct nfp_tun_neigh_lag lag; }; /** @@ -647,6 +663,9 @@ int nfp_flower_lag_populate_pre_action(struct nfp_app *app, struct netlink_ext_ack *extack); int nfp_flower_lag_get_output_id(struct nfp_app *app, struct net_device *master); +void nfp_flower_lag_get_info_from_netdev(struct nfp_app *app, + struct net_device *netdev, + struct nfp_tun_neigh_lag *lag); void nfp_flower_qos_init(struct nfp_app *app); void nfp_flower_qos_cleanup(struct nfp_app *app); int nfp_flower_setup_qos_offload(struct nfp_app *app, struct net_device *netdev, diff --git a/drivers/net/ethernet/netronome/nfp/flower/offload.c b/drivers/net/ethernet/netronome/nfp/flower/offload.c index 3ab3e4536b99..8593cafa6368 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/offload.c +++ b/drivers/net/ethernet/netronome/nfp/flower/offload.c @@ -373,10 +373,10 @@ nfp_flower_calculate_key_layers(struct nfp_app *app, if (ipv6_tun) { key_layer_two |= NFP_FLOWER_LAYER2_TUN_IPV6; key_size += - sizeof(struct nfp_flower_ipv6_udp_tun); + sizeof(struct nfp_flower_ipv6_gre_tun); } else { key_size += - sizeof(struct nfp_flower_ipv4_udp_tun); + sizeof(struct nfp_flower_ipv4_gre_tun); } if (enc_op.key) { diff --git a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c index 52f67157bd0f..a8678d5612ee 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c +++ b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c @@ -290,6 +290,11 @@ nfp_flower_xmit_tun_conf(struct nfp_app *app, u8 mtype, u16 plen, void *pdata, mtype == NFP_FLOWER_CMSG_TYPE_TUN_NEIGH_V6)) plen -= sizeof(struct nfp_tun_neigh_ext); + if (!(priv->flower_ext_feats & NFP_FL_FEATS_TUNNEL_NEIGH_LAG) && + (mtype == NFP_FLOWER_CMSG_TYPE_TUN_NEIGH || + mtype == NFP_FLOWER_CMSG_TYPE_TUN_NEIGH_V6)) + plen -= sizeof(struct nfp_tun_neigh_lag); + skb = nfp_flower_cmsg_alloc(app, plen, mtype, flag); if (!skb) return -ENOMEM; @@ -468,6 +473,7 @@ nfp_tun_write_neigh(struct net_device *netdev, struct nfp_app *app, neigh_table_params); if (!nn_entry && !neigh_invalid) { struct nfp_tun_neigh_ext *ext; + struct nfp_tun_neigh_lag *lag; struct nfp_tun_neigh *common; nn_entry = kzalloc(sizeof(*nn_entry) + neigh_size, @@ -488,6 +494,7 @@ nfp_tun_write_neigh(struct net_device *netdev, struct nfp_app *app, payload->dst_ipv6 = flowi6->daddr; common = &payload->common; ext = &payload->ext; + lag = &payload->lag; mtype = NFP_FLOWER_CMSG_TYPE_TUN_NEIGH_V6; } else { struct flowi4 *flowi4 = (struct flowi4 *)flow; @@ -498,6 +505,7 @@ nfp_tun_write_neigh(struct net_device *netdev, struct nfp_app *app, payload->dst_ipv4 = flowi4->daddr; common = &payload->common; ext = &payload->ext; + lag = &payload->lag; mtype = NFP_FLOWER_CMSG_TYPE_TUN_NEIGH; } ext->host_ctx = cpu_to_be32(U32_MAX); @@ -505,6 +513,9 @@ nfp_tun_write_neigh(struct net_device *netdev, struct nfp_app *app, ext->vlan_tci = cpu_to_be16(U16_MAX); ether_addr_copy(common->src_addr, netdev->dev_addr); neigh_ha_snapshot(common->dst_addr, neigh, netdev); + + if ((port_id & NFP_FL_LAG_OUT) == NFP_FL_LAG_OUT) + nfp_flower_lag_get_info_from_netdev(app, netdev, lag); common->port_id = cpu_to_be32(port_id); if (rhashtable_insert_fast(&priv->neigh_table, @@ -547,13 +558,38 @@ nfp_tun_write_neigh(struct net_device *netdev, struct nfp_app *app, if (nn_entry->flow) list_del(&nn_entry->list_head); kfree(nn_entry); - } else if (nn_entry && !neigh_invalid && override) { - mtype = is_ipv6 ? NFP_FLOWER_CMSG_TYPE_TUN_NEIGH_V6 : - NFP_FLOWER_CMSG_TYPE_TUN_NEIGH; - nfp_tun_link_predt_entries(app, nn_entry); - nfp_flower_xmit_tun_conf(app, mtype, neigh_size, - nn_entry->payload, - GFP_ATOMIC); + } else if (nn_entry && !neigh_invalid) { + struct nfp_tun_neigh *common; + u8 dst_addr[ETH_ALEN]; + bool is_mac_change; + + if (is_ipv6) { + struct nfp_tun_neigh_v6 *payload; + + payload = (struct nfp_tun_neigh_v6 *)nn_entry->payload; + common = &payload->common; + mtype = NFP_FLOWER_CMSG_TYPE_TUN_NEIGH_V6; + } else { + struct nfp_tun_neigh_v4 *payload; + + payload = (struct nfp_tun_neigh_v4 *)nn_entry->payload; + common = &payload->common; + mtype = NFP_FLOWER_CMSG_TYPE_TUN_NEIGH; + } + + ether_addr_copy(dst_addr, common->dst_addr); + neigh_ha_snapshot(common->dst_addr, neigh, netdev); + is_mac_change = !ether_addr_equal(dst_addr, common->dst_addr); + if (override || is_mac_change) { + if (is_mac_change && nn_entry->flow) { + list_del(&nn_entry->list_head); + nn_entry->flow = NULL; + } + nfp_tun_link_predt_entries(app, nn_entry); + nfp_flower_xmit_tun_conf(app, mtype, neigh_size, + nn_entry->payload, + GFP_ATOMIC); + } } spin_unlock_bh(&priv->predt_lock); @@ -593,8 +629,7 @@ nfp_tun_neigh_event_handler(struct notifier_block *nb, unsigned long event, app_priv = container_of(nb, struct nfp_flower_priv, tun.neigh_nb); app = app_priv->app; - if (!nfp_netdev_is_nfp_repr(n->dev) && - !nfp_flower_internal_port_can_offload(app, n->dev)) + if (!nfp_flower_get_port_id_from_netdev(app, n->dev)) return NOTIFY_DONE; #if IS_ENABLED(CONFIG_INET) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.c b/drivers/net/ethernet/netronome/nfp/nfp_main.c index e66e548919d4..71301dbd8fb5 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.c @@ -716,16 +716,26 @@ static u64 nfp_net_pf_get_app_cap(struct nfp_pf *pf) return val; } -static int nfp_pf_cfg_hwinfo(struct nfp_pf *pf, bool sp_indiff) +static void nfp_pf_cfg_hwinfo(struct nfp_pf *pf) { struct nfp_nsp *nsp; char hwinfo[32]; + bool sp_indiff; int err; nsp = nfp_nsp_open(pf->cpp); if (IS_ERR(nsp)) - return PTR_ERR(nsp); + return; + + if (!nfp_nsp_has_hwinfo_set(nsp)) + goto end; + sp_indiff = (nfp_net_pf_get_app_id(pf) == NFP_APP_FLOWER_NIC) || + (nfp_net_pf_get_app_cap(pf) & NFP_NET_APP_CAP_SP_INDIFF); + + /* No need to clean `sp_indiff` in driver, management firmware + * will do it when application firmware is unloaded. + */ snprintf(hwinfo, sizeof(hwinfo), "sp_indiff=%d", sp_indiff); err = nfp_nsp_hwinfo_set(nsp, hwinfo, sizeof(hwinfo)); /* Not a fatal error, no need to return error to stop driver from loading */ @@ -739,21 +749,8 @@ static int nfp_pf_cfg_hwinfo(struct nfp_pf *pf, bool sp_indiff) pf->eth_tbl = __nfp_eth_read_ports(pf->cpp, nsp); } +end: nfp_nsp_close(nsp); - return 0; -} - -static int nfp_pf_nsp_cfg(struct nfp_pf *pf) -{ - bool sp_indiff = (nfp_net_pf_get_app_id(pf) == NFP_APP_FLOWER_NIC) || - (nfp_net_pf_get_app_cap(pf) & NFP_NET_APP_CAP_SP_INDIFF); - - return nfp_pf_cfg_hwinfo(pf, sp_indiff); -} - -static void nfp_pf_nsp_clean(struct nfp_pf *pf) -{ - nfp_pf_cfg_hwinfo(pf, false); } static int nfp_pci_probe(struct pci_dev *pdev, @@ -856,13 +853,11 @@ static int nfp_pci_probe(struct pci_dev *pdev, goto err_fw_unload; } - err = nfp_pf_nsp_cfg(pf); - if (err) - goto err_fw_unload; + nfp_pf_cfg_hwinfo(pf); err = nfp_net_pci_probe(pf); if (err) - goto err_nsp_clean; + goto err_fw_unload; err = nfp_hwmon_register(pf); if (err) { @@ -874,8 +869,6 @@ static int nfp_pci_probe(struct pci_dev *pdev, err_net_remove: nfp_net_pci_remove(pf); -err_nsp_clean: - nfp_pf_nsp_clean(pf); err_fw_unload: kfree(pf->rtbl); nfp_mip_close(pf->mip); @@ -915,7 +908,6 @@ static void __nfp_pci_shutdown(struct pci_dev *pdev, bool unload_fw) nfp_net_pci_remove(pf); - nfp_pf_nsp_clean(pf); vfree(pf->dumpspec); kfree(pf->rtbl); nfp_mip_close(pf->mip); diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.c b/drivers/net/ethernet/pensando/ionic/ionic_dev.c index 9d0514cfeb5c..626b9113e7c4 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_dev.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.c @@ -481,6 +481,20 @@ int ionic_dev_cmd_vf_getattr(struct ionic *ionic, int vf, u8 attr, return err; } +void ionic_vf_start(struct ionic *ionic) +{ + union ionic_dev_cmd cmd = { + .vf_ctrl.opcode = IONIC_CMD_VF_CTRL, + .vf_ctrl.ctrl_opcode = IONIC_VF_CTRL_START_ALL, + }; + + if (!(ionic->ident.dev.capabilities & cpu_to_le64(IONIC_DEV_CAP_VF_CTRL))) + return; + + ionic_dev_cmd_go(&ionic->idev, &cmd); + ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT); +} + /* LIF commands */ void ionic_dev_cmd_queue_identify(struct ionic_dev *idev, u16 lif_type, u8 qtype, u8 qver) diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.h b/drivers/net/ethernet/pensando/ionic/ionic_dev.h index 563c302eb033..2a1d7b9c07e7 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_dev.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.h @@ -124,6 +124,8 @@ static_assert(sizeof(struct ionic_vf_setattr_cmd) == 64); static_assert(sizeof(struct ionic_vf_setattr_comp) == 16); static_assert(sizeof(struct ionic_vf_getattr_cmd) == 64); static_assert(sizeof(struct ionic_vf_getattr_comp) == 16); +static_assert(sizeof(struct ionic_vf_ctrl_cmd) == 64); +static_assert(sizeof(struct ionic_vf_ctrl_comp) == 16); #endif /* __CHECKER__ */ struct ionic_devinfo { @@ -324,6 +326,7 @@ int ionic_dev_cmd_vf_getattr(struct ionic *ionic, int vf, u8 attr, struct ionic_vf_getattr_comp *comp); void ionic_dev_cmd_queue_identify(struct ionic_dev *idev, u16 lif_type, u8 qtype, u8 qver); +void ionic_vf_start(struct ionic *ionic); void ionic_dev_cmd_lif_identify(struct ionic_dev *idev, u8 type, u8 ver); void ionic_dev_cmd_lif_init(struct ionic_dev *idev, u16 lif_index, dma_addr_t addr); diff --git a/drivers/net/ethernet/pensando/ionic/ionic_if.h b/drivers/net/ethernet/pensando/ionic/ionic_if.h index 4a90f611c611..eac09b2375b8 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_if.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_if.h @@ -8,7 +8,7 @@ #define IONIC_DEV_INFO_VERSION 1 #define IONIC_IFNAMSIZ 16 -/** +/* * enum ionic_cmd_opcode - Device commands */ enum ionic_cmd_opcode { @@ -54,6 +54,7 @@ enum ionic_cmd_opcode { /* SR/IOV commands */ IONIC_CMD_VF_GETATTR = 60, IONIC_CMD_VF_SETATTR = 61, + IONIC_CMD_VF_CTRL = 62, /* QoS commands */ IONIC_CMD_QOS_CLASS_IDENTIFY = 240, @@ -200,6 +201,7 @@ struct ionic_dev_reset_comp { }; #define IONIC_IDENTITY_VERSION_1 1 +#define IONIC_DEV_IDENTITY_VERSION_2 2 /** * struct ionic_dev_identify_cmd - Driver/device identify command @@ -254,6 +256,14 @@ union ionic_drv_identity { }; /** + * enum ionic_dev_capability - Device capabilities + * @IONIC_DEV_CAP_VF_CTRL: Device supports VF ctrl operations + */ +enum ionic_dev_capability { + IONIC_DEV_CAP_VF_CTRL = BIT(0), +}; + +/** * union ionic_dev_identity - device identity information * @version: Version of device identify * @type: Identify type (0 for now) @@ -273,6 +283,7 @@ union ionic_drv_identity { * @hwstamp_mask: Bitmask for subtraction of hardware tick values. * @hwstamp_mult: Hardware tick to nanosecond multiplier. * @hwstamp_shift: Hardware tick to nanosecond divisor (power of two). + * @capabilities: Device capabilities */ union ionic_dev_identity { struct { @@ -290,6 +301,7 @@ union ionic_dev_identity { __le64 hwstamp_mask; __le32 hwstamp_mult; __le32 hwstamp_shift; + __le64 capabilities; }; __le32 words[478]; }; @@ -2044,6 +2056,35 @@ struct ionic_vf_getattr_comp { u8 color; }; +enum ionic_vf_ctrl_opcode { + IONIC_VF_CTRL_START_ALL = 0, + IONIC_VF_CTRL_START = 1, +}; + +/** + * struct ionic_vf_ctrl_cmd - VF control command + * @opcode: Opcode for the command + * @vf_index: VF Index. It is unused if op START_ALL is used. + * @ctrl_opcode: VF control operation type + */ +struct ionic_vf_ctrl_cmd { + u8 opcode; + u8 ctrl_opcode; + __le16 vf_index; + /* private: */ + u8 rsvd1[60]; +}; + +/** + * struct ionic_vf_ctrl_comp - VF_CTRL command completion. + * @status: Status of the command (enum ionic_status_code) + */ +struct ionic_vf_ctrl_comp { + u8 status; + /* private: */ + u8 rsvd[15]; +}; + /** * struct ionic_qos_identify_cmd - QoS identify command * @opcode: opcode @@ -2865,6 +2906,7 @@ union ionic_dev_cmd { struct ionic_vf_setattr_cmd vf_setattr; struct ionic_vf_getattr_cmd vf_getattr; + struct ionic_vf_ctrl_cmd vf_ctrl; struct ionic_lif_identify_cmd lif_identify; struct ionic_lif_init_cmd lif_init; @@ -2903,6 +2945,7 @@ union ionic_dev_cmd_comp { struct ionic_vf_setattr_comp vf_setattr; struct ionic_vf_getattr_comp vf_getattr; + struct ionic_vf_ctrl_comp vf_ctrl; struct ionic_lif_identify_comp lif_identify; struct ionic_lif_init_comp lif_init; diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c index 5d58fd99be3c..4dd16c487f2b 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c @@ -1491,7 +1491,13 @@ static int ionic_init_nic_features(struct ionic_lif *lif) NETIF_F_RXCSUM | NETIF_F_TSO | NETIF_F_TSO6 | - NETIF_F_TSO_ECN; + NETIF_F_TSO_ECN | + NETIF_F_GSO_GRE | + NETIF_F_GSO_GRE_CSUM | + NETIF_F_GSO_IPXIP4 | + NETIF_F_GSO_IPXIP6 | + NETIF_F_GSO_UDP_TUNNEL | + NETIF_F_GSO_UDP_TUNNEL_CSUM; if (lif->nxqs > 1) features |= NETIF_F_RXHASH; @@ -2220,7 +2226,7 @@ static int ionic_eth_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd } } -static int ionic_update_cached_vf_config(struct ionic *ionic, int vf) +static int ionic_get_fw_vf_config(struct ionic *ionic, int vf, struct ionic_vf *vfdata) { struct ionic_vf_getattr_comp comp = { 0 }; int err; @@ -2231,14 +2237,14 @@ static int ionic_update_cached_vf_config(struct ionic *ionic, int vf) if (err && comp.status != IONIC_RC_ENOSUPP) goto err_out; if (!err) - ionic->vfs[vf].vlanid = comp.vlanid; + vfdata->vlanid = comp.vlanid; attr = IONIC_VF_ATTR_SPOOFCHK; err = ionic_dev_cmd_vf_getattr(ionic, vf, attr, &comp); if (err && comp.status != IONIC_RC_ENOSUPP) goto err_out; if (!err) - ionic->vfs[vf].spoofchk = comp.spoofchk; + vfdata->spoofchk = comp.spoofchk; attr = IONIC_VF_ATTR_LINKSTATE; err = ionic_dev_cmd_vf_getattr(ionic, vf, attr, &comp); @@ -2247,13 +2253,13 @@ static int ionic_update_cached_vf_config(struct ionic *ionic, int vf) if (!err) { switch (comp.linkstate) { case IONIC_VF_LINK_STATUS_UP: - ionic->vfs[vf].linkstate = IFLA_VF_LINK_STATE_ENABLE; + vfdata->linkstate = IFLA_VF_LINK_STATE_ENABLE; break; case IONIC_VF_LINK_STATUS_DOWN: - ionic->vfs[vf].linkstate = IFLA_VF_LINK_STATE_DISABLE; + vfdata->linkstate = IFLA_VF_LINK_STATE_DISABLE; break; case IONIC_VF_LINK_STATUS_AUTO: - ionic->vfs[vf].linkstate = IFLA_VF_LINK_STATE_AUTO; + vfdata->linkstate = IFLA_VF_LINK_STATE_AUTO; break; default: dev_warn(ionic->dev, "Unexpected link state %u\n", comp.linkstate); @@ -2266,21 +2272,21 @@ static int ionic_update_cached_vf_config(struct ionic *ionic, int vf) if (err && comp.status != IONIC_RC_ENOSUPP) goto err_out; if (!err) - ionic->vfs[vf].maxrate = comp.maxrate; + vfdata->maxrate = comp.maxrate; attr = IONIC_VF_ATTR_TRUST; err = ionic_dev_cmd_vf_getattr(ionic, vf, attr, &comp); if (err && comp.status != IONIC_RC_ENOSUPP) goto err_out; if (!err) - ionic->vfs[vf].trusted = comp.trust; + vfdata->trusted = comp.trust; attr = IONIC_VF_ATTR_MAC; err = ionic_dev_cmd_vf_getattr(ionic, vf, attr, &comp); if (err && comp.status != IONIC_RC_ENOSUPP) goto err_out; if (!err) - ether_addr_copy(ionic->vfs[vf].macaddr, comp.macaddr); + ether_addr_copy(vfdata->macaddr, comp.macaddr); err_out: if (err) @@ -2295,6 +2301,7 @@ static int ionic_get_vf_config(struct net_device *netdev, { struct ionic_lif *lif = netdev_priv(netdev); struct ionic *ionic = lif->ionic; + struct ionic_vf vfdata = { 0 }; int ret = 0; if (!netif_device_present(netdev)) @@ -2308,14 +2315,14 @@ static int ionic_get_vf_config(struct net_device *netdev, ivf->vf = vf; ivf->qos = 0; - ret = ionic_update_cached_vf_config(ionic, vf); + ret = ionic_get_fw_vf_config(ionic, vf, &vfdata); if (!ret) { - ivf->vlan = le16_to_cpu(ionic->vfs[vf].vlanid); - ivf->spoofchk = ionic->vfs[vf].spoofchk; - ivf->linkstate = ionic->vfs[vf].linkstate; - ivf->max_tx_rate = le32_to_cpu(ionic->vfs[vf].maxrate); - ivf->trusted = ionic->vfs[vf].trusted; - ether_addr_copy(ivf->mac, ionic->vfs[vf].macaddr); + ivf->vlan = le16_to_cpu(vfdata.vlanid); + ivf->spoofchk = vfdata.spoofchk; + ivf->linkstate = vfdata.linkstate; + ivf->max_tx_rate = le32_to_cpu(vfdata.maxrate); + ivf->trusted = vfdata.trusted; + ether_addr_copy(ivf->mac, vfdata.macaddr); } } @@ -2562,6 +2569,76 @@ static int ionic_set_vf_link_state(struct net_device *netdev, int vf, int set) return ret; } +static void ionic_vf_attr_replay(struct ionic_lif *lif) +{ + struct ionic_vf_setattr_cmd vfc = { }; + struct ionic *ionic = lif->ionic; + struct ionic_vf *v; + int i; + + if (!ionic->vfs) + return; + + down_read(&ionic->vf_op_lock); + + for (i = 0; i < ionic->num_vfs; i++) { + v = &ionic->vfs[i]; + + if (v->stats_pa) { + vfc.attr = IONIC_VF_ATTR_STATSADDR; + vfc.stats_pa = cpu_to_le64(v->stats_pa); + ionic_set_vf_config(ionic, i, &vfc); + vfc.stats_pa = 0; + } + + if (!is_zero_ether_addr(v->macaddr)) { + vfc.attr = IONIC_VF_ATTR_MAC; + ether_addr_copy(vfc.macaddr, v->macaddr); + ionic_set_vf_config(ionic, i, &vfc); + eth_zero_addr(vfc.macaddr); + } + + if (v->vlanid) { + vfc.attr = IONIC_VF_ATTR_VLAN; + vfc.vlanid = v->vlanid; + ionic_set_vf_config(ionic, i, &vfc); + vfc.vlanid = 0; + } + + if (v->maxrate) { + vfc.attr = IONIC_VF_ATTR_RATE; + vfc.maxrate = v->maxrate; + ionic_set_vf_config(ionic, i, &vfc); + vfc.maxrate = 0; + } + + if (v->spoofchk) { + vfc.attr = IONIC_VF_ATTR_SPOOFCHK; + vfc.spoofchk = v->spoofchk; + ionic_set_vf_config(ionic, i, &vfc); + vfc.spoofchk = 0; + } + + if (v->trusted) { + vfc.attr = IONIC_VF_ATTR_TRUST; + vfc.trust = v->trusted; + ionic_set_vf_config(ionic, i, &vfc); + vfc.trust = 0; + } + + if (v->linkstate) { + vfc.attr = IONIC_VF_ATTR_LINKSTATE; + vfc.linkstate = v->linkstate; + ionic_set_vf_config(ionic, i, &vfc); + vfc.linkstate = 0; + } + } + + up_read(&ionic->vf_op_lock); + + ionic_vf_start(ionic); +} + static const struct net_device_ops ionic_netdev_ops = { .ndo_open = ionic_open, .ndo_stop = ionic_stop, @@ -2817,11 +2894,15 @@ err_out: * than the full array, but leave the qcq shells in place */ for (i = lif->nxqs; i < lif->ionic->ntxqs_per_lif; i++) { - lif->txqcqs[i]->flags &= ~IONIC_QCQ_F_INTR; - ionic_qcq_free(lif, lif->txqcqs[i]); + if (lif->txqcqs && lif->txqcqs[i]) { + lif->txqcqs[i]->flags &= ~IONIC_QCQ_F_INTR; + ionic_qcq_free(lif, lif->txqcqs[i]); + } - lif->rxqcqs[i]->flags &= ~IONIC_QCQ_F_INTR; - ionic_qcq_free(lif, lif->rxqcqs[i]); + if (lif->rxqcqs && lif->rxqcqs[i]) { + lif->rxqcqs[i]->flags &= ~IONIC_QCQ_F_INTR; + ionic_qcq_free(lif, lif->rxqcqs[i]); + } } if (err) @@ -3038,6 +3119,8 @@ static void ionic_lif_handle_fw_up(struct ionic_lif *lif) if (err) goto err_qcqs_free; + ionic_vf_attr_replay(lif); + if (lif->registered) ionic_lif_set_netdev_info(lif); diff --git a/drivers/net/ethernet/pensando/ionic/ionic_main.c b/drivers/net/ethernet/pensando/ionic/ionic_main.c index 56f93b030551..ed9d8c995236 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_main.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_main.c @@ -533,7 +533,7 @@ int ionic_identify(struct ionic *ionic) sz = min(sizeof(ident->drv), sizeof(idev->dev_cmd_regs->data)); memcpy_toio(&idev->dev_cmd_regs->data, &ident->drv, sz); - ionic_dev_cmd_identify(idev, IONIC_IDENTITY_VERSION_1); + ionic_dev_cmd_identify(idev, IONIC_DEV_IDENTITY_VERSION_2); err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT); if (!err) { sz = min(sizeof(ident->dev), sizeof(idev->dev_cmd_regs->data)); diff --git a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c index c03986bf2628..0c3977416cd1 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c @@ -348,16 +348,25 @@ void ionic_rx_fill(struct ionic_queue *q) struct ionic_rxq_sg_desc *sg_desc; struct ionic_rxq_sg_elem *sg_elem; struct ionic_buf_info *buf_info; + unsigned int fill_threshold; struct ionic_rxq_desc *desc; unsigned int remain_len; unsigned int frag_len; unsigned int nfrags; + unsigned int n_fill; unsigned int i, j; unsigned int len; + n_fill = ionic_q_space_avail(q); + + fill_threshold = min_t(unsigned int, IONIC_RX_FILL_THRESHOLD, + q->num_descs / IONIC_RX_FILL_DIV); + if (n_fill < fill_threshold) + return; + len = netdev->mtu + ETH_HLEN + VLAN_HLEN; - for (i = ionic_q_space_avail(q); i; i--) { + for (i = n_fill; i; i--) { nfrags = 0; remain_len = len; desc_info = &q->info[q->head_idx]; @@ -511,7 +520,6 @@ int ionic_rx_napi(struct napi_struct *napi, int budget) struct ionic_cq *cq = napi_to_cq(napi); struct ionic_dev *idev; struct ionic_lif *lif; - u16 rx_fill_threshold; u32 work_done = 0; u32 flags = 0; @@ -521,10 +529,7 @@ int ionic_rx_napi(struct napi_struct *napi, int budget) work_done = ionic_cq_service(cq, budget, ionic_rx_service, NULL, NULL); - rx_fill_threshold = min_t(u16, IONIC_RX_FILL_THRESHOLD, - cq->num_descs / IONIC_RX_FILL_DIV); - if (work_done && ionic_q_space_avail(cq->bound_q) >= rx_fill_threshold) - ionic_rx_fill(cq->bound_q); + ionic_rx_fill(cq->bound_q); if (work_done < budget && napi_complete_done(napi, work_done)) { ionic_dim_update(qcq, IONIC_LIF_F_RX_DIM_INTR); @@ -550,7 +555,6 @@ int ionic_txrx_napi(struct napi_struct *napi, int budget) struct ionic_dev *idev; struct ionic_lif *lif; struct ionic_cq *txcq; - u16 rx_fill_threshold; u32 rx_work_done = 0; u32 tx_work_done = 0; u32 flags = 0; @@ -565,10 +569,7 @@ int ionic_txrx_napi(struct napi_struct *napi, int budget) rx_work_done = ionic_cq_service(rxcq, budget, ionic_rx_service, NULL, NULL); - rx_fill_threshold = min_t(u16, IONIC_RX_FILL_THRESHOLD, - rxcq->num_descs / IONIC_RX_FILL_DIV); - if (rx_work_done && ionic_q_space_avail(rxcq->bound_q) >= rx_fill_threshold) - ionic_rx_fill(rxcq->bound_q); + ionic_rx_fill(rxcq->bound_q); if (rx_work_done < budget && napi_complete_done(napi, rx_work_done)) { ionic_dim_update(qcq, 0); @@ -925,8 +926,12 @@ static int ionic_tx_tso(struct ionic_queue *q, struct sk_buff *skb) len = skb->len; mss = skb_shinfo(skb)->gso_size; - outer_csum = (skb_shinfo(skb)->gso_type & SKB_GSO_GRE_CSUM) || - (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM); + outer_csum = (skb_shinfo(skb)->gso_type & (SKB_GSO_GRE | + SKB_GSO_GRE_CSUM | + SKB_GSO_IPXIP4 | + SKB_GSO_IPXIP6 | + SKB_GSO_UDP_TUNNEL | + SKB_GSO_UDP_TUNNEL_CSUM)); has_vlan = !!skb_vlan_tag_present(skb); vlan_tci = skb_vlan_tag_get(skb); encap = skb->encapsulation; diff --git a/drivers/net/ethernet/rocker/rocker_main.c b/drivers/net/ethernet/rocker/rocker_main.c index 023682cd2768..9e59669a93dd 100644 --- a/drivers/net/ethernet/rocker/rocker_main.c +++ b/drivers/net/ethernet/rocker/rocker_main.c @@ -129,7 +129,7 @@ static int rocker_reg_test(const struct rocker *rocker) u64 test_reg; u64 rnd; - rnd = prandom_u32(); + rnd = get_random_u32(); rnd >>= 1; rocker_write32(rocker, TEST_REG, rnd); test_reg = rocker_read32(rocker, TEST_REG); @@ -139,9 +139,9 @@ static int rocker_reg_test(const struct rocker *rocker) return -EIO; } - rnd = prandom_u32(); + rnd = get_random_u32(); rnd <<= 31; - rnd |= prandom_u32(); + rnd |= get_random_u32(); rocker_write64(rocker, TEST_REG64, rnd); test_reg = rocker_read64(rocker, TEST_REG64); if (test_reg != rnd * 2) { @@ -224,7 +224,7 @@ static int rocker_dma_test_offset(const struct rocker *rocker, if (err) goto unmap; - prandom_bytes(buf, ROCKER_TEST_DMA_BUF_SIZE); + get_random_bytes(buf, ROCKER_TEST_DMA_BUF_SIZE); for (i = 0; i < ROCKER_TEST_DMA_BUF_SIZE; i++) expect[i] = ~buf[i]; err = rocker_dma_test_one(rocker, wait, ROCKER_TEST_DMA_CTRL_INVERT, diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index d1e1aa19a68e..7022fb2005a2 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -3277,6 +3277,30 @@ static int efx_ef10_set_mac_address(struct efx_nic *efx) bool was_enabled = efx->port_enabled; int rc; +#ifdef CONFIG_SFC_SRIOV + /* If this function is a VF and we have access to the parent PF, + * then use the PF control path to attempt to change the VF MAC address. + */ + if (efx->pci_dev->is_virtfn && efx->pci_dev->physfn) { + struct efx_nic *efx_pf = pci_get_drvdata(efx->pci_dev->physfn); + struct efx_ef10_nic_data *nic_data = efx->nic_data; + u8 mac[ETH_ALEN]; + + /* net_dev->dev_addr can be zeroed by efx_net_stop in + * efx_ef10_sriov_set_vf_mac, so pass in a copy. + */ + ether_addr_copy(mac, efx->net_dev->dev_addr); + + rc = efx_ef10_sriov_set_vf_mac(efx_pf, nic_data->vf_index, mac); + if (!rc) + return 0; + + netif_dbg(efx, drv, efx->net_dev, + "Updating VF mac via PF failed (%d), setting directly\n", + rc); + } +#endif + efx_device_detach_sync(efx); efx_net_stop(efx->net_dev); @@ -3297,40 +3321,6 @@ static int efx_ef10_set_mac_address(struct efx_nic *efx) efx_net_open(efx->net_dev); efx_device_attach_if_not_resetting(efx); -#ifdef CONFIG_SFC_SRIOV - if (efx->pci_dev->is_virtfn && efx->pci_dev->physfn) { - struct efx_ef10_nic_data *nic_data = efx->nic_data; - struct pci_dev *pci_dev_pf = efx->pci_dev->physfn; - - if (rc == -EPERM) { - struct efx_nic *efx_pf; - - /* Switch to PF and change MAC address on vport */ - efx_pf = pci_get_drvdata(pci_dev_pf); - - rc = efx_ef10_sriov_set_vf_mac(efx_pf, - nic_data->vf_index, - efx->net_dev->dev_addr); - } else if (!rc) { - struct efx_nic *efx_pf = pci_get_drvdata(pci_dev_pf); - struct efx_ef10_nic_data *nic_data = efx_pf->nic_data; - unsigned int i; - - /* MAC address successfully changed by VF (with MAC - * spoofing) so update the parent PF if possible. - */ - for (i = 0; i < efx_pf->vf_count; ++i) { - struct ef10_vf *vf = nic_data->vf + i; - - if (vf->efx == efx) { - ether_addr_copy(vf->mac, - efx->net_dev->dev_addr); - return 0; - } - } - } - } else -#endif if (rc == -EPERM) { netif_err(efx, drv, efx->net_dev, "Cannot change MAC address; use sfboot to enable" diff --git a/drivers/net/ethernet/sfc/ef100_ethtool.c b/drivers/net/ethernet/sfc/ef100_ethtool.c index 135ece2f1375..702abbe59b76 100644 --- a/drivers/net/ethernet/sfc/ef100_ethtool.c +++ b/drivers/net/ethernet/sfc/ef100_ethtool.c @@ -43,8 +43,6 @@ const struct ethtool_ops ef100_ethtool_ops = { .get_pauseparam = efx_ethtool_get_pauseparam, .set_pauseparam = efx_ethtool_set_pauseparam, .get_sset_count = efx_ethtool_get_sset_count, - .get_priv_flags = efx_ethtool_get_priv_flags, - .set_priv_flags = efx_ethtool_set_priv_flags, .self_test = efx_ethtool_self_test, .get_strings = efx_ethtool_get_strings, .get_link_ksettings = efx_ethtool_get_link_ksettings, diff --git a/drivers/net/ethernet/sfc/ethtool_common.c b/drivers/net/ethernet/sfc/ethtool_common.c index 6649a2327d03..a8cbceeb301b 100644 --- a/drivers/net/ethernet/sfc/ethtool_common.c +++ b/drivers/net/ethernet/sfc/ethtool_common.c @@ -101,14 +101,6 @@ static const struct efx_sw_stat_desc efx_sw_stat_desc[] = { #define EFX_ETHTOOL_SW_STAT_COUNT ARRAY_SIZE(efx_sw_stat_desc) -static const char efx_ethtool_priv_flags_strings[][ETH_GSTRING_LEN] = { - "log-tc-errors", -}; - -#define EFX_ETHTOOL_PRIV_FLAGS_LOG_TC_ERRS BIT(0) - -#define EFX_ETHTOOL_PRIV_FLAGS_COUNT ARRAY_SIZE(efx_ethtool_priv_flags_strings) - void efx_ethtool_get_drvinfo(struct net_device *net_dev, struct ethtool_drvinfo *info) { @@ -460,8 +452,6 @@ int efx_ethtool_get_sset_count(struct net_device *net_dev, int string_set) efx_ptp_describe_stats(efx, NULL); case ETH_SS_TEST: return efx_ethtool_fill_self_tests(efx, NULL, NULL, NULL); - case ETH_SS_PRIV_FLAGS: - return EFX_ETHTOOL_PRIV_FLAGS_COUNT; default: return -EINVAL; } @@ -488,39 +478,12 @@ void efx_ethtool_get_strings(struct net_device *net_dev, case ETH_SS_TEST: efx_ethtool_fill_self_tests(efx, NULL, strings, NULL); break; - case ETH_SS_PRIV_FLAGS: - for (i = 0; i < EFX_ETHTOOL_PRIV_FLAGS_COUNT; i++) - strscpy(strings + i * ETH_GSTRING_LEN, - efx_ethtool_priv_flags_strings[i], - ETH_GSTRING_LEN); - break; default: /* No other string sets */ break; } } -u32 efx_ethtool_get_priv_flags(struct net_device *net_dev) -{ - struct efx_nic *efx = efx_netdev_priv(net_dev); - u32 ret_flags = 0; - - if (efx->log_tc_errs) - ret_flags |= EFX_ETHTOOL_PRIV_FLAGS_LOG_TC_ERRS; - - return ret_flags; -} - -int efx_ethtool_set_priv_flags(struct net_device *net_dev, u32 flags) -{ - struct efx_nic *efx = efx_netdev_priv(net_dev); - - efx->log_tc_errs = - !!(flags & EFX_ETHTOOL_PRIV_FLAGS_LOG_TC_ERRS); - - return 0; -} - void efx_ethtool_get_stats(struct net_device *net_dev, struct ethtool_stats *stats, u64 *data) diff --git a/drivers/net/ethernet/sfc/ethtool_common.h b/drivers/net/ethernet/sfc/ethtool_common.h index 0afc74021a5e..659491932101 100644 --- a/drivers/net/ethernet/sfc/ethtool_common.h +++ b/drivers/net/ethernet/sfc/ethtool_common.h @@ -27,8 +27,6 @@ int efx_ethtool_fill_self_tests(struct efx_nic *efx, int efx_ethtool_get_sset_count(struct net_device *net_dev, int string_set); void efx_ethtool_get_strings(struct net_device *net_dev, u32 string_set, u8 *strings); -u32 efx_ethtool_get_priv_flags(struct net_device *net_dev); -int efx_ethtool_set_priv_flags(struct net_device *net_dev, u32 flags); void efx_ethtool_get_stats(struct net_device *net_dev, struct ethtool_stats *stats __attribute__ ((unused)), u64 *data); diff --git a/drivers/net/ethernet/sfc/filter.h b/drivers/net/ethernet/sfc/filter.h index be72e71da027..5f201a547e5b 100644 --- a/drivers/net/ethernet/sfc/filter.h +++ b/drivers/net/ethernet/sfc/filter.h @@ -162,9 +162,9 @@ struct efx_filter_spec { u32 priority:2; u32 flags:6; u32 dmaq_id:12; - u32 vport_id; u32 rss_context; - __be16 outer_vid __aligned(4); /* allow jhash2() of match values */ + u32 vport_id; + __be16 outer_vid; __be16 inner_vid; u8 loc_mac[ETH_ALEN]; u8 rem_mac[ETH_ALEN]; diff --git a/drivers/net/ethernet/sfc/mae.c b/drivers/net/ethernet/sfc/mae.c index 874c765b2465..6f472ea0638a 100644 --- a/drivers/net/ethernet/sfc/mae.c +++ b/drivers/net/ethernet/sfc/mae.c @@ -265,9 +265,8 @@ int efx_mae_match_check_caps(struct efx_nic *efx, rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_INGRESS_PORT], ingress_port_mask_type); if (rc) { - efx_tc_err(efx, "No support for %s mask in field ingress_port\n", - mask_type_name(ingress_port_mask_type)); - NL_SET_ERR_MSG_MOD(extack, "Unsupported mask type for ingress_port"); + NL_SET_ERR_MSG_FMT_MOD(extack, "No support for %s mask in field ingress_port", + mask_type_name(ingress_port_mask_type)); return rc; } return 0; diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index 2e9ba0cfe848..7ef823d7a89a 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -855,7 +855,6 @@ enum efx_xdp_tx_queues_mode { * @timer_max_ns: Interrupt timer maximum value, in nanoseconds * @irq_rx_adaptive: Adaptive IRQ moderation enabled for RX event queues * @irqs_hooked: Channel interrupts are hooked - * @log_tc_errs: Error logging for TC filter insertion is enabled * @irq_rx_mod_step_us: Step size for IRQ moderation for RX event queues * @irq_rx_moderation_us: IRQ moderation time for RX event queues * @msg_enable: Log message enable flags @@ -1018,7 +1017,6 @@ struct efx_nic { unsigned int timer_max_ns; bool irq_rx_adaptive; bool irqs_hooked; - bool log_tc_errs; unsigned int irq_mod_step_us; unsigned int irq_rx_moderation_us; u32 msg_enable; diff --git a/drivers/net/ethernet/sfc/rx_common.c b/drivers/net/ethernet/sfc/rx_common.c index 4826e6a7e4ce..9220afeddee8 100644 --- a/drivers/net/ethernet/sfc/rx_common.c +++ b/drivers/net/ethernet/sfc/rx_common.c @@ -660,17 +660,17 @@ bool efx_filter_spec_equal(const struct efx_filter_spec *left, (EFX_FILTER_FLAG_RX | EFX_FILTER_FLAG_TX))) return false; - return memcmp(&left->outer_vid, &right->outer_vid, + return memcmp(&left->vport_id, &right->vport_id, sizeof(struct efx_filter_spec) - - offsetof(struct efx_filter_spec, outer_vid)) == 0; + offsetof(struct efx_filter_spec, vport_id)) == 0; } u32 efx_filter_spec_hash(const struct efx_filter_spec *spec) { - BUILD_BUG_ON(offsetof(struct efx_filter_spec, outer_vid) & 3); - return jhash2((const u32 *)&spec->outer_vid, + BUILD_BUG_ON(offsetof(struct efx_filter_spec, vport_id) & 3); + return jhash2((const u32 *)&spec->vport_id, (sizeof(struct efx_filter_spec) - - offsetof(struct efx_filter_spec, outer_vid)) / 4, + offsetof(struct efx_filter_spec, vport_id)) / 4, 0); } diff --git a/drivers/net/ethernet/sfc/tc.c b/drivers/net/ethernet/sfc/tc.c index 3478860d4023..b21a961eabb1 100644 --- a/drivers/net/ethernet/sfc/tc.c +++ b/drivers/net/ethernet/sfc/tc.c @@ -137,17 +137,16 @@ static int efx_tc_flower_parse_match(struct efx_nic *efx, flow_rule_match_control(rule, &fm); if (fm.mask->flags) { - efx_tc_err(efx, "Unsupported match on control.flags %#x\n", - fm.mask->flags); - NL_SET_ERR_MSG_MOD(extack, "Unsupported match on control.flags"); + NL_SET_ERR_MSG_FMT_MOD(extack, "Unsupported match on control.flags %#x", + fm.mask->flags); return -EOPNOTSUPP; } } if (dissector->used_keys & ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) | BIT(FLOW_DISSECTOR_KEY_BASIC))) { - efx_tc_err(efx, "Unsupported flower keys %#x\n", dissector->used_keys); - NL_SET_ERR_MSG_MOD(extack, "Unsupported flower keys encountered"); + NL_SET_ERR_MSG_FMT_MOD(extack, "Unsupported flower keys %#x", + dissector->used_keys); return -EOPNOTSUPP; } @@ -156,11 +155,11 @@ static int efx_tc_flower_parse_match(struct efx_nic *efx, flow_rule_match_basic(rule, &fm); if (fm.mask->n_proto) { - EFX_TC_ERR_MSG(efx, extack, "Unsupported eth_proto match\n"); + NL_SET_ERR_MSG_MOD(extack, "Unsupported eth_proto match"); return -EOPNOTSUPP; } if (fm.mask->ip_proto) { - EFX_TC_ERR_MSG(efx, extack, "Unsupported ip_proto match\n"); + NL_SET_ERR_MSG_MOD(extack, "Unsupported ip_proto match"); return -EOPNOTSUPP; } } @@ -200,13 +199,9 @@ static int efx_tc_flower_replace(struct efx_nic *efx, if (efv != from_efv) { /* can't happen */ - efx_tc_err(efx, "for %s efv is %snull but from_efv is %snull\n", - netdev_name(net_dev), efv ? "non-" : "", - from_efv ? "non-" : ""); - if (efv) - NL_SET_ERR_MSG_MOD(extack, "vfrep filter has PF net_dev (can't happen)"); - else - NL_SET_ERR_MSG_MOD(extack, "PF filter has vfrep net_dev (can't happen)"); + NL_SET_ERR_MSG_FMT_MOD(extack, "for %s efv is %snull but from_efv is %snull (can't happen)", + netdev_name(net_dev), efv ? "non-" : "", + from_efv ? "non-" : ""); return -EINVAL; } @@ -214,7 +209,7 @@ static int efx_tc_flower_replace(struct efx_nic *efx, memset(&match, 0, sizeof(match)); rc = efx_tc_flower_external_mport(efx, from_efv); if (rc < 0) { - EFX_TC_ERR_MSG(efx, extack, "Failed to identify ingress m-port"); + NL_SET_ERR_MSG_MOD(extack, "Failed to identify ingress m-port"); return rc; } match.value.ingress_port = rc; @@ -224,7 +219,7 @@ static int efx_tc_flower_replace(struct efx_nic *efx, return rc; if (tc->common.chain_index) { - EFX_TC_ERR_MSG(efx, extack, "No support for nonzero chain_index"); + NL_SET_ERR_MSG_MOD(extack, "No support for nonzero chain_index"); return -EOPNOTSUPP; } match.mask.recirc_id = 0xff; @@ -261,7 +256,7 @@ static int efx_tc_flower_replace(struct efx_nic *efx, if (!act) { /* more actions after a non-pipe action */ - EFX_TC_ERR_MSG(efx, extack, "Action follows non-pipe action"); + NL_SET_ERR_MSG_MOD(extack, "Action follows non-pipe action"); rc = -EINVAL; goto release; } @@ -270,7 +265,7 @@ static int efx_tc_flower_replace(struct efx_nic *efx, case FLOW_ACTION_DROP: rc = efx_mae_alloc_action_set(efx, act); if (rc) { - EFX_TC_ERR_MSG(efx, extack, "Failed to write action set to hw (drop)"); + NL_SET_ERR_MSG_MOD(extack, "Failed to write action set to hw (drop)"); goto release; } list_add_tail(&act->list, &rule->acts.list); @@ -281,20 +276,20 @@ static int efx_tc_flower_replace(struct efx_nic *efx, save = *act; to_efv = efx_tc_flower_lookup_efv(efx, fa->dev); if (IS_ERR(to_efv)) { - EFX_TC_ERR_MSG(efx, extack, "Mirred egress device not on switch"); + NL_SET_ERR_MSG_MOD(extack, "Mirred egress device not on switch"); rc = PTR_ERR(to_efv); goto release; } rc = efx_tc_flower_external_mport(efx, to_efv); if (rc < 0) { - EFX_TC_ERR_MSG(efx, extack, "Failed to identify egress m-port"); + NL_SET_ERR_MSG_MOD(extack, "Failed to identify egress m-port"); goto release; } act->dest_mport = rc; act->deliver = 1; rc = efx_mae_alloc_action_set(efx, act); if (rc) { - EFX_TC_ERR_MSG(efx, extack, "Failed to write action set to hw (mirred)"); + NL_SET_ERR_MSG_MOD(extack, "Failed to write action set to hw (mirred)"); goto release; } list_add_tail(&act->list, &rule->acts.list); @@ -310,9 +305,9 @@ static int efx_tc_flower_replace(struct efx_nic *efx, *act = save; break; default: - efx_tc_err(efx, "Unhandled action %u\n", fa->id); + NL_SET_ERR_MSG_FMT_MOD(extack, "Unhandled action %u", + fa->id); rc = -EOPNOTSUPP; - NL_SET_ERR_MSG_MOD(extack, "Unsupported action"); goto release; } } @@ -334,7 +329,7 @@ static int efx_tc_flower_replace(struct efx_nic *efx, act->deliver = 1; rc = efx_mae_alloc_action_set(efx, act); if (rc) { - EFX_TC_ERR_MSG(efx, extack, "Failed to write action set to hw (deliver)"); + NL_SET_ERR_MSG_MOD(extack, "Failed to write action set to hw (deliver)"); goto release; } list_add_tail(&act->list, &rule->acts.list); @@ -349,13 +344,13 @@ static int efx_tc_flower_replace(struct efx_nic *efx, rc = efx_mae_alloc_action_set_list(efx, &rule->acts); if (rc) { - EFX_TC_ERR_MSG(efx, extack, "Failed to write action set list to hw"); + NL_SET_ERR_MSG_MOD(extack, "Failed to write action set list to hw"); goto release; } rc = efx_mae_insert_rule(efx, &rule->match, EFX_TC_PRIO_TC, rule->acts.fw_id, &rule->fw_id); if (rc) { - EFX_TC_ERR_MSG(efx, extack, "Failed to insert rule in hw"); + NL_SET_ERR_MSG_MOD(extack, "Failed to insert rule in hw"); goto release_acts; } return 0; diff --git a/drivers/net/ethernet/sfc/tc.h b/drivers/net/ethernet/sfc/tc.h index 196fd74ed973..4373c3243e3c 100644 --- a/drivers/net/ethernet/sfc/tc.h +++ b/drivers/net/ethernet/sfc/tc.h @@ -15,24 +15,6 @@ #include <linux/rhashtable.h> #include "net_driver.h" -/* Error reporting: convenience macros. For indicating why a given filter - * insertion is not supported; errors in internal operation or in the - * hardware should be netif_err()s instead. - */ -/* Used when error message is constant. */ -#define EFX_TC_ERR_MSG(efx, extack, message) do { \ - NL_SET_ERR_MSG_MOD(extack, message); \ - if (efx->log_tc_errs) \ - netif_info(efx, drv, efx->net_dev, "%s\n", message); \ -} while (0) -/* Used when error message is not constant; caller should also supply a - * constant extack message with NL_SET_ERR_MSG_MOD(). - */ -#define efx_tc_err(efx, fmt, args...) do { \ -if (efx->log_tc_errs) \ - netif_info(efx, drv, efx->net_dev, fmt, ##args);\ -} while (0) - struct efx_tc_action_set { u16 deliver:1; u32 dest_mport; diff --git a/drivers/net/ethernet/smsc/Kconfig b/drivers/net/ethernet/smsc/Kconfig index 2524c907f386..5f22a8a4d27b 100644 --- a/drivers/net/ethernet/smsc/Kconfig +++ b/drivers/net/ethernet/smsc/Kconfig @@ -75,20 +75,6 @@ config EPIC100 More specific information and updates are available from <http://www.scyld.com/network/epic100.html>. -config SMC911X - tristate "SMSC LAN911[5678] support" - select CRC32 - select MII - depends on (ARM || SUPERH || COMPILE_TEST) - help - This is a driver for SMSC's LAN911x series of Ethernet chipsets - including the new LAN9115, LAN9116, LAN9117, and LAN9118. - Say Y here if you want it compiled into the kernel. - - This driver is also available as a module. The module will be - called smc911x. If you want to compile it as a module, say M - here and read <file:Documentation/kbuild/modules.rst> - config SMSC911X tristate "SMSC LAN911x/LAN921x families embedded ethernet support" depends on HAS_IOMEM diff --git a/drivers/net/ethernet/smsc/Makefile b/drivers/net/ethernet/smsc/Makefile index 4105912b1629..1501fa364c13 100644 --- a/drivers/net/ethernet/smsc/Makefile +++ b/drivers/net/ethernet/smsc/Makefile @@ -8,5 +8,4 @@ obj-$(CONFIG_SMC91X) += smc91x.o obj-$(CONFIG_PCMCIA_SMC91C92) += smc91c92_cs.o obj-$(CONFIG_EPIC100) += epic100.o obj-$(CONFIG_SMSC9420) += smsc9420.o -obj-$(CONFIG_SMC911X) += smc911x.o obj-$(CONFIG_SMSC911X) += smsc911x.o diff --git a/drivers/net/ethernet/smsc/smc911x.c b/drivers/net/ethernet/smsc/smc911x.c deleted file mode 100644 index 52ecfb461c41..000000000000 --- a/drivers/net/ethernet/smsc/smc911x.c +++ /dev/null @@ -1,2198 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * smc911x.c - * This is a driver for SMSC's LAN911{5,6,7,8} single-chip Ethernet devices. - * - * Copyright (C) 2005 Sensoria Corp - * Derived from the unified SMC91x driver by Nicolas Pitre - * and the smsc911x.c reference driver by SMSC - * - * Arguments: - * watchdog = TX watchdog timeout - * tx_fifo_kb = Size of TX FIFO in KB - * - * History: - * 04/16/05 Dustin McIntire Initial version - */ -static const char version[] = - "smc911x.c: v1.0 04-16-2005 by Dustin McIntire <dustin@sensoria.com>\n"; - -/* Debugging options */ -#define ENABLE_SMC_DEBUG_RX 0 -#define ENABLE_SMC_DEBUG_TX 0 -#define ENABLE_SMC_DEBUG_DMA 0 -#define ENABLE_SMC_DEBUG_PKTS 0 -#define ENABLE_SMC_DEBUG_MISC 0 -#define ENABLE_SMC_DEBUG_FUNC 0 - -#define SMC_DEBUG_RX ((ENABLE_SMC_DEBUG_RX ? 1 : 0) << 0) -#define SMC_DEBUG_TX ((ENABLE_SMC_DEBUG_TX ? 1 : 0) << 1) -#define SMC_DEBUG_DMA ((ENABLE_SMC_DEBUG_DMA ? 1 : 0) << 2) -#define SMC_DEBUG_PKTS ((ENABLE_SMC_DEBUG_PKTS ? 1 : 0) << 3) -#define SMC_DEBUG_MISC ((ENABLE_SMC_DEBUG_MISC ? 1 : 0) << 4) -#define SMC_DEBUG_FUNC ((ENABLE_SMC_DEBUG_FUNC ? 1 : 0) << 5) - -#ifndef SMC_DEBUG -#define SMC_DEBUG ( SMC_DEBUG_RX | \ - SMC_DEBUG_TX | \ - SMC_DEBUG_DMA | \ - SMC_DEBUG_PKTS | \ - SMC_DEBUG_MISC | \ - SMC_DEBUG_FUNC \ - ) -#endif - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/delay.h> -#include <linux/interrupt.h> -#include <linux/errno.h> -#include <linux/ioport.h> -#include <linux/crc32.h> -#include <linux/device.h> -#include <linux/platform_device.h> -#include <linux/spinlock.h> -#include <linux/ethtool.h> -#include <linux/mii.h> -#include <linux/workqueue.h> - -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> - -#include <linux/dmaengine.h> - -#include <asm/io.h> - -#include "smc911x.h" - -/* - * Transmit timeout, default 5 seconds. - */ -static int watchdog = 5000; -module_param(watchdog, int, 0400); -MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds"); - -static int tx_fifo_kb=8; -module_param(tx_fifo_kb, int, 0400); -MODULE_PARM_DESC(tx_fifo_kb,"transmit FIFO size in KB (1<x<15)(default=8)"); - -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:smc911x"); - -/* - * The internal workings of the driver. If you are changing anything - * here with the SMC stuff, you should have the datasheet and know - * what you are doing. - */ -#define CARDNAME "smc911x" - -/* - * Use power-down feature of the chip - */ -#define POWER_DOWN 1 - -#if SMC_DEBUG > 0 -#define DBG(n, dev, args...) \ - do { \ - if (SMC_DEBUG & (n)) \ - netdev_dbg(dev, args); \ - } while (0) - -#define PRINTK(dev, args...) netdev_info(dev, args) -#else -#define DBG(n, dev, args...) \ - while (0) { \ - netdev_dbg(dev, args); \ - } -#define PRINTK(dev, args...) netdev_dbg(dev, args) -#endif - -#if SMC_DEBUG_PKTS > 0 -static void PRINT_PKT(u_char *buf, int length) -{ - int i; - int remainder; - int lines; - - lines = length / 16; - remainder = length % 16; - - for (i = 0; i < lines ; i ++) { - int cur; - printk(KERN_DEBUG); - for (cur = 0; cur < 8; cur++) { - u_char a, b; - a = *buf++; - b = *buf++; - pr_cont("%02x%02x ", a, b); - } - pr_cont("\n"); - } - printk(KERN_DEBUG); - for (i = 0; i < remainder/2 ; i++) { - u_char a, b; - a = *buf++; - b = *buf++; - pr_cont("%02x%02x ", a, b); - } - pr_cont("\n"); -} -#else -static inline void PRINT_PKT(u_char *buf, int length) { } -#endif - - -/* this enables an interrupt in the interrupt mask register */ -#define SMC_ENABLE_INT(lp, x) do { \ - unsigned int __mask; \ - __mask = SMC_GET_INT_EN((lp)); \ - __mask |= (x); \ - SMC_SET_INT_EN((lp), __mask); \ -} while (0) - -/* this disables an interrupt from the interrupt mask register */ -#define SMC_DISABLE_INT(lp, x) do { \ - unsigned int __mask; \ - __mask = SMC_GET_INT_EN((lp)); \ - __mask &= ~(x); \ - SMC_SET_INT_EN((lp), __mask); \ -} while (0) - -/* - * this does a soft reset on the device - */ -static void smc911x_reset(struct net_device *dev) -{ - struct smc911x_local *lp = netdev_priv(dev); - unsigned int reg, timeout=0, resets=1, irq_cfg; - unsigned long flags; - - DBG(SMC_DEBUG_FUNC, dev, "--> %s\n", __func__); - - /* Take out of PM setting first */ - if ((SMC_GET_PMT_CTRL(lp) & PMT_CTRL_READY_) == 0) { - /* Write to the bytetest will take out of powerdown */ - SMC_SET_BYTE_TEST(lp, 0); - timeout=10; - do { - udelay(10); - reg = SMC_GET_PMT_CTRL(lp) & PMT_CTRL_READY_; - } while (--timeout && !reg); - if (timeout == 0) { - PRINTK(dev, "smc911x_reset timeout waiting for PM restore\n"); - return; - } - } - - /* Disable all interrupts */ - spin_lock_irqsave(&lp->lock, flags); - SMC_SET_INT_EN(lp, 0); - spin_unlock_irqrestore(&lp->lock, flags); - - while (resets--) { - SMC_SET_HW_CFG(lp, HW_CFG_SRST_); - timeout=10; - do { - udelay(10); - reg = SMC_GET_HW_CFG(lp); - /* If chip indicates reset timeout then try again */ - if (reg & HW_CFG_SRST_TO_) { - PRINTK(dev, "chip reset timeout, retrying...\n"); - resets++; - break; - } - } while (--timeout && (reg & HW_CFG_SRST_)); - } - if (timeout == 0) { - PRINTK(dev, "smc911x_reset timeout waiting for reset\n"); - return; - } - - /* make sure EEPROM has finished loading before setting GPIO_CFG */ - timeout=1000; - while (--timeout && (SMC_GET_E2P_CMD(lp) & E2P_CMD_EPC_BUSY_)) - udelay(10); - - if (timeout == 0){ - PRINTK(dev, "smc911x_reset timeout waiting for EEPROM busy\n"); - return; - } - - /* Initialize interrupts */ - SMC_SET_INT_EN(lp, 0); - SMC_ACK_INT(lp, -1); - - /* Reset the FIFO level and flow control settings */ - SMC_SET_HW_CFG(lp, (lp->tx_fifo_kb & 0xF) << 16); -//TODO: Figure out what appropriate pause time is - SMC_SET_FLOW(lp, FLOW_FCPT_ | FLOW_FCEN_); - SMC_SET_AFC_CFG(lp, lp->afc_cfg); - - - /* Set to LED outputs */ - SMC_SET_GPIO_CFG(lp, 0x70070000); - - /* - * Deassert IRQ for 1*10us for edge type interrupts - * and drive IRQ pin push-pull - */ - irq_cfg = (1 << 24) | INT_CFG_IRQ_EN_ | INT_CFG_IRQ_TYPE_; -#ifdef SMC_DYNAMIC_BUS_CONFIG - if (lp->cfg.irq_polarity) - irq_cfg |= INT_CFG_IRQ_POL_; -#endif - SMC_SET_IRQ_CFG(lp, irq_cfg); - - /* clear anything saved */ - if (lp->pending_tx_skb != NULL) { - dev_kfree_skb (lp->pending_tx_skb); - lp->pending_tx_skb = NULL; - dev->stats.tx_errors++; - dev->stats.tx_aborted_errors++; - } -} - -/* - * Enable Interrupts, Receive, and Transmit - */ -static void smc911x_enable(struct net_device *dev) -{ - struct smc911x_local *lp = netdev_priv(dev); - unsigned mask, cfg, cr; - unsigned long flags; - - DBG(SMC_DEBUG_FUNC, dev, "--> %s\n", __func__); - - spin_lock_irqsave(&lp->lock, flags); - - SMC_SET_MAC_ADDR(lp, dev->dev_addr); - - /* Enable TX */ - cfg = SMC_GET_HW_CFG(lp); - cfg &= HW_CFG_TX_FIF_SZ_ | 0xFFF; - cfg |= HW_CFG_SF_; - SMC_SET_HW_CFG(lp, cfg); - SMC_SET_FIFO_TDA(lp, 0xFF); - /* Update TX stats on every 64 packets received or every 1 sec */ - SMC_SET_FIFO_TSL(lp, 64); - SMC_SET_GPT_CFG(lp, GPT_CFG_TIMER_EN_ | 10000); - - SMC_GET_MAC_CR(lp, cr); - cr |= MAC_CR_TXEN_ | MAC_CR_HBDIS_; - SMC_SET_MAC_CR(lp, cr); - SMC_SET_TX_CFG(lp, TX_CFG_TX_ON_); - - /* Add 2 byte padding to start of packets */ - SMC_SET_RX_CFG(lp, (2<<8) & RX_CFG_RXDOFF_); - - /* Turn on receiver and enable RX */ - if (cr & MAC_CR_RXEN_) - DBG(SMC_DEBUG_RX, dev, "Receiver already enabled\n"); - - SMC_SET_MAC_CR(lp, cr | MAC_CR_RXEN_); - - /* Interrupt on every received packet */ - SMC_SET_FIFO_RSA(lp, 0x01); - SMC_SET_FIFO_RSL(lp, 0x00); - - /* now, enable interrupts */ - mask = INT_EN_TDFA_EN_ | INT_EN_TSFL_EN_ | INT_EN_RSFL_EN_ | - INT_EN_GPT_INT_EN_ | INT_EN_RXDFH_INT_EN_ | INT_EN_RXE_EN_ | - INT_EN_PHY_INT_EN_; - if (IS_REV_A(lp->revision)) - mask|=INT_EN_RDFL_EN_; - else { - mask|=INT_EN_RDFO_EN_; - } - SMC_ENABLE_INT(lp, mask); - - spin_unlock_irqrestore(&lp->lock, flags); -} - -/* - * this puts the device in an inactive state - */ -static void smc911x_shutdown(struct net_device *dev) -{ - struct smc911x_local *lp = netdev_priv(dev); - unsigned cr; - unsigned long flags; - - DBG(SMC_DEBUG_FUNC, dev, "%s: --> %s\n", CARDNAME, __func__); - - /* Disable IRQ's */ - SMC_SET_INT_EN(lp, 0); - - /* Turn of Rx and TX */ - spin_lock_irqsave(&lp->lock, flags); - SMC_GET_MAC_CR(lp, cr); - cr &= ~(MAC_CR_TXEN_ | MAC_CR_RXEN_ | MAC_CR_HBDIS_); - SMC_SET_MAC_CR(lp, cr); - SMC_SET_TX_CFG(lp, TX_CFG_STOP_TX_); - spin_unlock_irqrestore(&lp->lock, flags); -} - -static inline void smc911x_drop_pkt(struct net_device *dev) -{ - struct smc911x_local *lp = netdev_priv(dev); - unsigned int fifo_count, timeout, reg; - - DBG(SMC_DEBUG_FUNC | SMC_DEBUG_RX, dev, "%s: --> %s\n", - CARDNAME, __func__); - fifo_count = SMC_GET_RX_FIFO_INF(lp) & 0xFFFF; - if (fifo_count <= 4) { - /* Manually dump the packet data */ - while (fifo_count--) - SMC_GET_RX_FIFO(lp); - } else { - /* Fast forward through the bad packet */ - SMC_SET_RX_DP_CTRL(lp, RX_DP_CTRL_FFWD_BUSY_); - timeout=50; - do { - udelay(10); - reg = SMC_GET_RX_DP_CTRL(lp) & RX_DP_CTRL_FFWD_BUSY_; - } while (--timeout && reg); - if (timeout == 0) { - PRINTK(dev, "timeout waiting for RX fast forward\n"); - } - } -} - -/* - * This is the procedure to handle the receipt of a packet. - * It should be called after checking for packet presence in - * the RX status FIFO. It must be called with the spin lock - * already held. - */ -static inline void smc911x_rcv(struct net_device *dev) -{ - struct smc911x_local *lp = netdev_priv(dev); - unsigned int pkt_len, status; - struct sk_buff *skb; - unsigned char *data; - - DBG(SMC_DEBUG_FUNC | SMC_DEBUG_RX, dev, "--> %s\n", - __func__); - status = SMC_GET_RX_STS_FIFO(lp); - DBG(SMC_DEBUG_RX, dev, "Rx pkt len %d status 0x%08x\n", - (status & 0x3fff0000) >> 16, status & 0xc000ffff); - pkt_len = (status & RX_STS_PKT_LEN_) >> 16; - if (status & RX_STS_ES_) { - /* Deal with a bad packet */ - dev->stats.rx_errors++; - if (status & RX_STS_CRC_ERR_) - dev->stats.rx_crc_errors++; - else { - if (status & RX_STS_LEN_ERR_) - dev->stats.rx_length_errors++; - if (status & RX_STS_MCAST_) - dev->stats.multicast++; - } - /* Remove the bad packet data from the RX FIFO */ - smc911x_drop_pkt(dev); - } else { - /* Receive a valid packet */ - /* Alloc a buffer with extra room for DMA alignment */ - skb = netdev_alloc_skb(dev, pkt_len+32); - if (unlikely(skb == NULL)) { - PRINTK(dev, "Low memory, rcvd packet dropped.\n"); - dev->stats.rx_dropped++; - smc911x_drop_pkt(dev); - return; - } - /* Align IP header to 32 bits - * Note that the device is configured to add a 2 - * byte padding to the packet start, so we really - * want to write to the orignal data pointer */ - data = skb->data; - skb_reserve(skb, 2); - skb_put(skb,pkt_len-4); -#ifdef SMC_USE_DMA - { - unsigned int fifo; - /* Lower the FIFO threshold if possible */ - fifo = SMC_GET_FIFO_INT(lp); - if (fifo & 0xFF) fifo--; - DBG(SMC_DEBUG_RX, dev, "Setting RX stat FIFO threshold to %d\n", - fifo & 0xff); - SMC_SET_FIFO_INT(lp, fifo); - /* Setup RX DMA */ - SMC_SET_RX_CFG(lp, RX_CFG_RX_END_ALGN16_ | ((2<<8) & RX_CFG_RXDOFF_)); - lp->rxdma_active = 1; - lp->current_rx_skb = skb; - SMC_PULL_DATA(lp, data, (pkt_len+2+15) & ~15); - /* Packet processing deferred to DMA RX interrupt */ - } -#else - SMC_SET_RX_CFG(lp, RX_CFG_RX_END_ALGN4_ | ((2<<8) & RX_CFG_RXDOFF_)); - SMC_PULL_DATA(lp, data, pkt_len+2+3); - - DBG(SMC_DEBUG_PKTS, dev, "Received packet\n"); - PRINT_PKT(data, min(pkt_len - 4, 64U)); - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - dev->stats.rx_packets++; - dev->stats.rx_bytes += pkt_len-4; -#endif - } -} - -/* - * This is called to actually send a packet to the chip. - */ -static void smc911x_hardware_send_pkt(struct net_device *dev) -{ - struct smc911x_local *lp = netdev_priv(dev); - struct sk_buff *skb; - unsigned int cmdA, cmdB, len; - unsigned char *buf; - - DBG(SMC_DEBUG_FUNC | SMC_DEBUG_TX, dev, "--> %s\n", __func__); - BUG_ON(lp->pending_tx_skb == NULL); - - skb = lp->pending_tx_skb; - lp->pending_tx_skb = NULL; - - /* cmdA {25:24] data alignment [20:16] start offset [10:0] buffer length */ - /* cmdB {31:16] pkt tag [10:0] length */ -#ifdef SMC_USE_DMA - /* 16 byte buffer alignment mode */ - buf = (char*)((u32)(skb->data) & ~0xF); - len = (skb->len + 0xF + ((u32)skb->data & 0xF)) & ~0xF; - cmdA = (1<<24) | (((u32)skb->data & 0xF)<<16) | - TX_CMD_A_INT_FIRST_SEG_ | TX_CMD_A_INT_LAST_SEG_ | - skb->len; -#else - buf = (char *)((uintptr_t)skb->data & ~0x3); - len = (skb->len + 3 + ((uintptr_t)skb->data & 3)) & ~0x3; - cmdA = (((uintptr_t)skb->data & 0x3) << 16) | - TX_CMD_A_INT_FIRST_SEG_ | TX_CMD_A_INT_LAST_SEG_ | - skb->len; -#endif - /* tag is packet length so we can use this in stats update later */ - cmdB = (skb->len << 16) | (skb->len & 0x7FF); - - DBG(SMC_DEBUG_TX, dev, "TX PKT LENGTH 0x%04x (%d) BUF 0x%p CMDA 0x%08x CMDB 0x%08x\n", - len, len, buf, cmdA, cmdB); - SMC_SET_TX_FIFO(lp, cmdA); - SMC_SET_TX_FIFO(lp, cmdB); - - DBG(SMC_DEBUG_PKTS, dev, "Transmitted packet\n"); - PRINT_PKT(buf, min(len, 64U)); - - /* Send pkt via PIO or DMA */ -#ifdef SMC_USE_DMA - lp->current_tx_skb = skb; - SMC_PUSH_DATA(lp, buf, len); - /* DMA complete IRQ will free buffer and set jiffies */ -#else - SMC_PUSH_DATA(lp, buf, len); - netif_trans_update(dev); - dev_kfree_skb_irq(skb); -#endif - if (!lp->tx_throttle) { - netif_wake_queue(dev); - } - SMC_ENABLE_INT(lp, INT_EN_TDFA_EN_ | INT_EN_TSFL_EN_); -} - -/* - * Since I am not sure if I will have enough room in the chip's ram - * to store the packet, I call this routine which either sends it - * now, or set the card to generates an interrupt when ready - * for the packet. - */ -static netdev_tx_t -smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct smc911x_local *lp = netdev_priv(dev); - unsigned int free; - unsigned long flags; - - DBG(SMC_DEBUG_FUNC | SMC_DEBUG_TX, dev, "--> %s\n", - __func__); - - spin_lock_irqsave(&lp->lock, flags); - - BUG_ON(lp->pending_tx_skb != NULL); - - free = SMC_GET_TX_FIFO_INF(lp) & TX_FIFO_INF_TDFREE_; - DBG(SMC_DEBUG_TX, dev, "TX free space %d\n", free); - - /* Turn off the flow when running out of space in FIFO */ - if (free <= SMC911X_TX_FIFO_LOW_THRESHOLD) { - DBG(SMC_DEBUG_TX, dev, "Disabling data flow due to low FIFO space (%d)\n", - free); - /* Reenable when at least 1 packet of size MTU present */ - SMC_SET_FIFO_TDA(lp, (SMC911X_TX_FIFO_LOW_THRESHOLD)/64); - lp->tx_throttle = 1; - netif_stop_queue(dev); - } - - /* Drop packets when we run out of space in TX FIFO - * Account for overhead required for: - * - * Tx command words 8 bytes - * Start offset 15 bytes - * End padding 15 bytes - */ - if (unlikely(free < (skb->len + 8 + 15 + 15))) { - netdev_warn(dev, "No Tx free space %d < %d\n", - free, skb->len); - lp->pending_tx_skb = NULL; - dev->stats.tx_errors++; - dev->stats.tx_dropped++; - spin_unlock_irqrestore(&lp->lock, flags); - dev_kfree_skb_any(skb); - return NETDEV_TX_OK; - } - -#ifdef SMC_USE_DMA - { - /* If the DMA is already running then defer this packet Tx until - * the DMA IRQ starts it - */ - if (lp->txdma_active) { - DBG(SMC_DEBUG_TX | SMC_DEBUG_DMA, dev, "Tx DMA running, deferring packet\n"); - lp->pending_tx_skb = skb; - netif_stop_queue(dev); - spin_unlock_irqrestore(&lp->lock, flags); - return NETDEV_TX_OK; - } else { - DBG(SMC_DEBUG_TX | SMC_DEBUG_DMA, dev, "Activating Tx DMA\n"); - lp->txdma_active = 1; - } - } -#endif - lp->pending_tx_skb = skb; - smc911x_hardware_send_pkt(dev); - spin_unlock_irqrestore(&lp->lock, flags); - - return NETDEV_TX_OK; -} - -/* - * This handles a TX status interrupt, which is only called when: - * - a TX error occurred, or - * - TX of a packet completed. - */ -static void smc911x_tx(struct net_device *dev) -{ - struct smc911x_local *lp = netdev_priv(dev); - unsigned int tx_status; - - DBG(SMC_DEBUG_FUNC | SMC_DEBUG_TX, dev, "--> %s\n", - __func__); - - /* Collect the TX status */ - while (((SMC_GET_TX_FIFO_INF(lp) & TX_FIFO_INF_TSUSED_) >> 16) != 0) { - DBG(SMC_DEBUG_TX, dev, "Tx stat FIFO used 0x%04x\n", - (SMC_GET_TX_FIFO_INF(lp) & TX_FIFO_INF_TSUSED_) >> 16); - tx_status = SMC_GET_TX_STS_FIFO(lp); - dev->stats.tx_packets++; - dev->stats.tx_bytes+=tx_status>>16; - DBG(SMC_DEBUG_TX, dev, "Tx FIFO tag 0x%04x status 0x%04x\n", - (tx_status & 0xffff0000) >> 16, - tx_status & 0x0000ffff); - /* count Tx errors, but ignore lost carrier errors when in - * full-duplex mode */ - if ((tx_status & TX_STS_ES_) && !(lp->ctl_rfduplx && - !(tx_status & 0x00000306))) { - dev->stats.tx_errors++; - } - if (tx_status & TX_STS_MANY_COLL_) { - dev->stats.collisions+=16; - dev->stats.tx_aborted_errors++; - } else { - dev->stats.collisions+=(tx_status & TX_STS_COLL_CNT_) >> 3; - } - /* carrier error only has meaning for half-duplex communication */ - if ((tx_status & (TX_STS_LOC_ | TX_STS_NO_CARR_)) && - !lp->ctl_rfduplx) { - dev->stats.tx_carrier_errors++; - } - if (tx_status & TX_STS_LATE_COLL_) { - dev->stats.collisions++; - dev->stats.tx_aborted_errors++; - } - } -} - - -/*---PHY CONTROL AND CONFIGURATION-----------------------------------------*/ -/* - * Reads a register from the MII Management serial interface - */ - -static int smc911x_phy_read(struct net_device *dev, int phyaddr, int phyreg) -{ - struct smc911x_local *lp = netdev_priv(dev); - unsigned int phydata; - - SMC_GET_MII(lp, phyreg, phyaddr, phydata); - - DBG(SMC_DEBUG_MISC, dev, "%s: phyaddr=0x%x, phyreg=0x%02x, phydata=0x%04x\n", - __func__, phyaddr, phyreg, phydata); - return phydata; -} - - -/* - * Writes a register to the MII Management serial interface - */ -static void smc911x_phy_write(struct net_device *dev, int phyaddr, int phyreg, - int phydata) -{ - struct smc911x_local *lp = netdev_priv(dev); - - DBG(SMC_DEBUG_MISC, dev, "%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n", - __func__, phyaddr, phyreg, phydata); - - SMC_SET_MII(lp, phyreg, phyaddr, phydata); -} - -/* - * Finds and reports the PHY address (115 and 117 have external - * PHY interface 118 has internal only - */ -static void smc911x_phy_detect(struct net_device *dev) -{ - struct smc911x_local *lp = netdev_priv(dev); - int phyaddr; - unsigned int cfg, id1, id2; - - DBG(SMC_DEBUG_FUNC, dev, "--> %s\n", __func__); - - lp->phy_type = 0; - - /* - * Scan all 32 PHY addresses if necessary, starting at - * PHY#1 to PHY#31, and then PHY#0 last. - */ - switch(lp->version) { - case CHIP_9115: - case CHIP_9117: - case CHIP_9215: - case CHIP_9217: - cfg = SMC_GET_HW_CFG(lp); - if (cfg & HW_CFG_EXT_PHY_DET_) { - cfg &= ~HW_CFG_PHY_CLK_SEL_; - cfg |= HW_CFG_PHY_CLK_SEL_CLK_DIS_; - SMC_SET_HW_CFG(lp, cfg); - udelay(10); /* Wait for clocks to stop */ - - cfg |= HW_CFG_EXT_PHY_EN_; - SMC_SET_HW_CFG(lp, cfg); - udelay(10); /* Wait for clocks to stop */ - - cfg &= ~HW_CFG_PHY_CLK_SEL_; - cfg |= HW_CFG_PHY_CLK_SEL_EXT_PHY_; - SMC_SET_HW_CFG(lp, cfg); - udelay(10); /* Wait for clocks to stop */ - - cfg |= HW_CFG_SMI_SEL_; - SMC_SET_HW_CFG(lp, cfg); - - for (phyaddr = 1; phyaddr < 32; ++phyaddr) { - - /* Read the PHY identifiers */ - SMC_GET_PHY_ID1(lp, phyaddr & 31, id1); - SMC_GET_PHY_ID2(lp, phyaddr & 31, id2); - - /* Make sure it is a valid identifier */ - if (id1 != 0x0000 && id1 != 0xffff && - id1 != 0x8000 && id2 != 0x0000 && - id2 != 0xffff && id2 != 0x8000) { - /* Save the PHY's address */ - lp->mii.phy_id = phyaddr & 31; - lp->phy_type = id1 << 16 | id2; - break; - } - } - if (phyaddr < 32) - /* Found an external PHY */ - break; - } - fallthrough; - default: - /* Internal media only */ - SMC_GET_PHY_ID1(lp, 1, id1); - SMC_GET_PHY_ID2(lp, 1, id2); - /* Save the PHY's address */ - lp->mii.phy_id = 1; - lp->phy_type = id1 << 16 | id2; - } - - DBG(SMC_DEBUG_MISC, dev, "phy_id1=0x%x, phy_id2=0x%x phyaddr=0x%x\n", - id1, id2, lp->mii.phy_id); -} - -/* - * Sets the PHY to a configuration as determined by the user. - * Called with spin_lock held. - */ -static int smc911x_phy_fixed(struct net_device *dev) -{ - struct smc911x_local *lp = netdev_priv(dev); - int phyaddr = lp->mii.phy_id; - int bmcr; - - DBG(SMC_DEBUG_FUNC, dev, "--> %s\n", __func__); - - /* Enter Link Disable state */ - SMC_GET_PHY_BMCR(lp, phyaddr, bmcr); - bmcr |= BMCR_PDOWN; - SMC_SET_PHY_BMCR(lp, phyaddr, bmcr); - - /* - * Set our fixed capabilities - * Disable auto-negotiation - */ - bmcr &= ~BMCR_ANENABLE; - if (lp->ctl_rfduplx) - bmcr |= BMCR_FULLDPLX; - - if (lp->ctl_rspeed == 100) - bmcr |= BMCR_SPEED100; - - /* Write our capabilities to the phy control register */ - SMC_SET_PHY_BMCR(lp, phyaddr, bmcr); - - /* Re-Configure the Receive/Phy Control register */ - bmcr &= ~BMCR_PDOWN; - SMC_SET_PHY_BMCR(lp, phyaddr, bmcr); - - return 1; -} - -/** - * smc911x_phy_reset - reset the phy - * @dev: net device - * @phy: phy address - * - * Issue a software reset for the specified PHY and - * wait up to 100ms for the reset to complete. We should - * not access the PHY for 50ms after issuing the reset. - * - * The time to wait appears to be dependent on the PHY. - * - */ -static int smc911x_phy_reset(struct net_device *dev, int phy) -{ - struct smc911x_local *lp = netdev_priv(dev); - int timeout; - unsigned long flags; - unsigned int reg; - - DBG(SMC_DEBUG_FUNC, dev, "--> %s()\n", __func__); - - spin_lock_irqsave(&lp->lock, flags); - reg = SMC_GET_PMT_CTRL(lp); - reg &= ~0xfffff030; - reg |= PMT_CTRL_PHY_RST_; - SMC_SET_PMT_CTRL(lp, reg); - spin_unlock_irqrestore(&lp->lock, flags); - for (timeout = 2; timeout; timeout--) { - msleep(50); - spin_lock_irqsave(&lp->lock, flags); - reg = SMC_GET_PMT_CTRL(lp); - spin_unlock_irqrestore(&lp->lock, flags); - if (!(reg & PMT_CTRL_PHY_RST_)) { - /* extra delay required because the phy may - * not be completed with its reset - * when PHY_BCR_RESET_ is cleared. 256us - * should suffice, but use 500us to be safe - */ - udelay(500); - break; - } - } - - return reg & PMT_CTRL_PHY_RST_; -} - -/** - * smc911x_phy_powerdown - powerdown phy - * @dev: net device - * @phy: phy address - * - * Power down the specified PHY - */ -static void smc911x_phy_powerdown(struct net_device *dev, int phy) -{ - struct smc911x_local *lp = netdev_priv(dev); - unsigned int bmcr; - - /* Enter Link Disable state */ - SMC_GET_PHY_BMCR(lp, phy, bmcr); - bmcr |= BMCR_PDOWN; - SMC_SET_PHY_BMCR(lp, phy, bmcr); -} - -/** - * smc911x_phy_check_media - check the media status and adjust BMCR - * @dev: net device - * @init: set true for initialisation - * - * Select duplex mode depending on negotiation state. This - * also updates our carrier state. - */ -static void smc911x_phy_check_media(struct net_device *dev, int init) -{ - struct smc911x_local *lp = netdev_priv(dev); - int phyaddr = lp->mii.phy_id; - unsigned int bmcr, cr; - - DBG(SMC_DEBUG_FUNC, dev, "--> %s\n", __func__); - - if (mii_check_media(&lp->mii, netif_msg_link(lp), init)) { - /* duplex state has changed */ - SMC_GET_PHY_BMCR(lp, phyaddr, bmcr); - SMC_GET_MAC_CR(lp, cr); - if (lp->mii.full_duplex) { - DBG(SMC_DEBUG_MISC, dev, "Configuring for full-duplex mode\n"); - bmcr |= BMCR_FULLDPLX; - cr |= MAC_CR_RCVOWN_; - } else { - DBG(SMC_DEBUG_MISC, dev, "Configuring for half-duplex mode\n"); - bmcr &= ~BMCR_FULLDPLX; - cr &= ~MAC_CR_RCVOWN_; - } - SMC_SET_PHY_BMCR(lp, phyaddr, bmcr); - SMC_SET_MAC_CR(lp, cr); - } -} - -/* - * Configures the specified PHY through the MII management interface - * using Autonegotiation. - * Calls smc911x_phy_fixed() if the user has requested a certain config. - * If RPC ANEG bit is set, the media selection is dependent purely on - * the selection by the MII (either in the MII BMCR reg or the result - * of autonegotiation.) If the RPC ANEG bit is cleared, the selection - * is controlled by the RPC SPEED and RPC DPLX bits. - */ -static void smc911x_phy_configure(struct work_struct *work) -{ - struct smc911x_local *lp = container_of(work, struct smc911x_local, - phy_configure); - struct net_device *dev = lp->netdev; - int phyaddr = lp->mii.phy_id; - int my_phy_caps; /* My PHY capabilities */ - int my_ad_caps; /* My Advertised capabilities */ - int status __always_unused; - unsigned long flags; - - DBG(SMC_DEBUG_FUNC, dev, "--> %s()\n", __func__); - - /* - * We should not be called if phy_type is zero. - */ - if (lp->phy_type == 0) - return; - - if (smc911x_phy_reset(dev, phyaddr)) { - netdev_info(dev, "PHY reset timed out\n"); - return; - } - spin_lock_irqsave(&lp->lock, flags); - - /* - * Enable PHY Interrupts (for register 18) - * Interrupts listed here are enabled - */ - SMC_SET_PHY_INT_MASK(lp, phyaddr, PHY_INT_MASK_ENERGY_ON_ | - PHY_INT_MASK_ANEG_COMP_ | PHY_INT_MASK_REMOTE_FAULT_ | - PHY_INT_MASK_LINK_DOWN_); - - /* If the user requested no auto neg, then go set his request */ - if (lp->mii.force_media) { - smc911x_phy_fixed(dev); - goto smc911x_phy_configure_exit; - } - - /* Copy our capabilities from MII_BMSR to MII_ADVERTISE */ - SMC_GET_PHY_BMSR(lp, phyaddr, my_phy_caps); - if (!(my_phy_caps & BMSR_ANEGCAPABLE)) { - netdev_info(dev, "Auto negotiation NOT supported\n"); - smc911x_phy_fixed(dev); - goto smc911x_phy_configure_exit; - } - - /* CSMA capable w/ both pauses */ - my_ad_caps = ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; - - if (my_phy_caps & BMSR_100BASE4) - my_ad_caps |= ADVERTISE_100BASE4; - if (my_phy_caps & BMSR_100FULL) - my_ad_caps |= ADVERTISE_100FULL; - if (my_phy_caps & BMSR_100HALF) - my_ad_caps |= ADVERTISE_100HALF; - if (my_phy_caps & BMSR_10FULL) - my_ad_caps |= ADVERTISE_10FULL; - if (my_phy_caps & BMSR_10HALF) - my_ad_caps |= ADVERTISE_10HALF; - - /* Disable capabilities not selected by our user */ - if (lp->ctl_rspeed != 100) - my_ad_caps &= ~(ADVERTISE_100BASE4|ADVERTISE_100FULL|ADVERTISE_100HALF); - - if (!lp->ctl_rfduplx) - my_ad_caps &= ~(ADVERTISE_100FULL|ADVERTISE_10FULL); - - /* Update our Auto-Neg Advertisement Register */ - SMC_SET_PHY_MII_ADV(lp, phyaddr, my_ad_caps); - lp->mii.advertising = my_ad_caps; - - /* - * Read the register back. Without this, it appears that when - * auto-negotiation is restarted, sometimes it isn't ready and - * the link does not come up. - */ - udelay(10); - SMC_GET_PHY_MII_ADV(lp, phyaddr, status); - - DBG(SMC_DEBUG_MISC, dev, "phy caps=0x%04x\n", my_phy_caps); - DBG(SMC_DEBUG_MISC, dev, "phy advertised caps=0x%04x\n", my_ad_caps); - - /* Restart auto-negotiation process in order to advertise my caps */ - SMC_SET_PHY_BMCR(lp, phyaddr, BMCR_ANENABLE | BMCR_ANRESTART); - - smc911x_phy_check_media(dev, 1); - -smc911x_phy_configure_exit: - spin_unlock_irqrestore(&lp->lock, flags); -} - -/* - * smc911x_phy_interrupt - * - * Purpose: Handle interrupts relating to PHY register 18. This is - * called from the "hard" interrupt handler under our private spinlock. - */ -static void smc911x_phy_interrupt(struct net_device *dev) -{ - struct smc911x_local *lp = netdev_priv(dev); - int phyaddr = lp->mii.phy_id; - int status __always_unused; - - DBG(SMC_DEBUG_FUNC, dev, "--> %s\n", __func__); - - if (lp->phy_type == 0) - return; - - smc911x_phy_check_media(dev, 0); - /* read to clear status bits */ - SMC_GET_PHY_INT_SRC(lp, phyaddr,status); - DBG(SMC_DEBUG_MISC, dev, "PHY interrupt status 0x%04x\n", - status & 0xffff); - DBG(SMC_DEBUG_MISC, dev, "AFC_CFG 0x%08x\n", - SMC_GET_AFC_CFG(lp)); -} - -/*--- END PHY CONTROL AND CONFIGURATION-------------------------------------*/ - -/* - * This is the main routine of the driver, to handle the device when - * it needs some attention. - */ -static irqreturn_t smc911x_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct smc911x_local *lp = netdev_priv(dev); - unsigned int status, mask, timeout; - unsigned int rx_overrun=0, cr, pkts; - unsigned long flags; - - DBG(SMC_DEBUG_FUNC, dev, "--> %s\n", __func__); - - spin_lock_irqsave(&lp->lock, flags); - - /* Spurious interrupt check */ - if ((SMC_GET_IRQ_CFG(lp) & (INT_CFG_IRQ_INT_ | INT_CFG_IRQ_EN_)) != - (INT_CFG_IRQ_INT_ | INT_CFG_IRQ_EN_)) { - spin_unlock_irqrestore(&lp->lock, flags); - return IRQ_NONE; - } - - mask = SMC_GET_INT_EN(lp); - SMC_SET_INT_EN(lp, 0); - - /* set a timeout value, so I don't stay here forever */ - timeout = 8; - - - do { - status = SMC_GET_INT(lp); - - DBG(SMC_DEBUG_MISC, dev, "INT 0x%08x MASK 0x%08x OUTSIDE MASK 0x%08x\n", - status, mask, status & ~mask); - - status &= mask; - if (!status) - break; - - /* Handle SW interrupt condition */ - if (status & INT_STS_SW_INT_) { - SMC_ACK_INT(lp, INT_STS_SW_INT_); - mask &= ~INT_EN_SW_INT_EN_; - } - /* Handle various error conditions */ - if (status & INT_STS_RXE_) { - SMC_ACK_INT(lp, INT_STS_RXE_); - dev->stats.rx_errors++; - } - if (status & INT_STS_RXDFH_INT_) { - SMC_ACK_INT(lp, INT_STS_RXDFH_INT_); - dev->stats.rx_dropped+=SMC_GET_RX_DROP(lp); - } - /* Undocumented interrupt-what is the right thing to do here? */ - if (status & INT_STS_RXDF_INT_) { - SMC_ACK_INT(lp, INT_STS_RXDF_INT_); - } - - /* Rx Data FIFO exceeds set level */ - if (status & INT_STS_RDFL_) { - if (IS_REV_A(lp->revision)) { - rx_overrun=1; - SMC_GET_MAC_CR(lp, cr); - cr &= ~MAC_CR_RXEN_; - SMC_SET_MAC_CR(lp, cr); - DBG(SMC_DEBUG_RX, dev, "RX overrun\n"); - dev->stats.rx_errors++; - dev->stats.rx_fifo_errors++; - } - SMC_ACK_INT(lp, INT_STS_RDFL_); - } - if (status & INT_STS_RDFO_) { - if (!IS_REV_A(lp->revision)) { - SMC_GET_MAC_CR(lp, cr); - cr &= ~MAC_CR_RXEN_; - SMC_SET_MAC_CR(lp, cr); - rx_overrun=1; - DBG(SMC_DEBUG_RX, dev, "RX overrun\n"); - dev->stats.rx_errors++; - dev->stats.rx_fifo_errors++; - } - SMC_ACK_INT(lp, INT_STS_RDFO_); - } - /* Handle receive condition */ - if ((status & INT_STS_RSFL_) || rx_overrun) { - unsigned int fifo; - DBG(SMC_DEBUG_RX, dev, "RX irq\n"); - fifo = SMC_GET_RX_FIFO_INF(lp); - pkts = (fifo & RX_FIFO_INF_RXSUSED_) >> 16; - DBG(SMC_DEBUG_RX, dev, "Rx FIFO pkts %d, bytes %d\n", - pkts, fifo & 0xFFFF); - if (pkts != 0) { -#ifdef SMC_USE_DMA - unsigned int fifo; - if (lp->rxdma_active){ - DBG(SMC_DEBUG_RX | SMC_DEBUG_DMA, dev, - "RX DMA active\n"); - /* The DMA is already running so up the IRQ threshold */ - fifo = SMC_GET_FIFO_INT(lp) & ~0xFF; - fifo |= pkts & 0xFF; - DBG(SMC_DEBUG_RX, dev, - "Setting RX stat FIFO threshold to %d\n", - fifo & 0xff); - SMC_SET_FIFO_INT(lp, fifo); - } else -#endif - smc911x_rcv(dev); - } - SMC_ACK_INT(lp, INT_STS_RSFL_); - } - /* Handle transmit FIFO available */ - if (status & INT_STS_TDFA_) { - DBG(SMC_DEBUG_TX, dev, "TX data FIFO space available irq\n"); - SMC_SET_FIFO_TDA(lp, 0xFF); - lp->tx_throttle = 0; -#ifdef SMC_USE_DMA - if (!lp->txdma_active) -#endif - netif_wake_queue(dev); - SMC_ACK_INT(lp, INT_STS_TDFA_); - } - /* Handle transmit done condition */ -#if 1 - if (status & (INT_STS_TSFL_ | INT_STS_GPT_INT_)) { - DBG(SMC_DEBUG_TX | SMC_DEBUG_MISC, dev, - "Tx stat FIFO limit (%d) /GPT irq\n", - (SMC_GET_FIFO_INT(lp) & 0x00ff0000) >> 16); - smc911x_tx(dev); - SMC_SET_GPT_CFG(lp, GPT_CFG_TIMER_EN_ | 10000); - SMC_ACK_INT(lp, INT_STS_TSFL_); - SMC_ACK_INT(lp, INT_STS_TSFL_ | INT_STS_GPT_INT_); - } -#else - if (status & INT_STS_TSFL_) { - DBG(SMC_DEBUG_TX, dev, "TX status FIFO limit (%d) irq\n", ?); - smc911x_tx(dev); - SMC_ACK_INT(lp, INT_STS_TSFL_); - } - - if (status & INT_STS_GPT_INT_) { - DBG(SMC_DEBUG_RX, dev, "IRQ_CFG 0x%08x FIFO_INT 0x%08x RX_CFG 0x%08x\n", - SMC_GET_IRQ_CFG(lp), - SMC_GET_FIFO_INT(lp), - SMC_GET_RX_CFG(lp)); - DBG(SMC_DEBUG_RX, dev, "Rx Stat FIFO Used 0x%02x Data FIFO Used 0x%04x Stat FIFO 0x%08x\n", - (SMC_GET_RX_FIFO_INF(lp) & 0x00ff0000) >> 16, - SMC_GET_RX_FIFO_INF(lp) & 0xffff, - SMC_GET_RX_STS_FIFO_PEEK(lp)); - SMC_SET_GPT_CFG(lp, GPT_CFG_TIMER_EN_ | 10000); - SMC_ACK_INT(lp, INT_STS_GPT_INT_); - } -#endif - - /* Handle PHY interrupt condition */ - if (status & INT_STS_PHY_INT_) { - DBG(SMC_DEBUG_MISC, dev, "PHY irq\n"); - smc911x_phy_interrupt(dev); - SMC_ACK_INT(lp, INT_STS_PHY_INT_); - } - } while (--timeout); - - /* restore mask state */ - SMC_SET_INT_EN(lp, mask); - - DBG(SMC_DEBUG_MISC, dev, "Interrupt done (%d loops)\n", - 8-timeout); - - spin_unlock_irqrestore(&lp->lock, flags); - - return IRQ_HANDLED; -} - -#ifdef SMC_USE_DMA -static void -smc911x_tx_dma_irq(void *data) -{ - struct smc911x_local *lp = data; - struct net_device *dev = lp->netdev; - struct sk_buff *skb = lp->current_tx_skb; - unsigned long flags; - - DBG(SMC_DEBUG_FUNC, dev, "--> %s\n", __func__); - - DBG(SMC_DEBUG_TX | SMC_DEBUG_DMA, dev, "TX DMA irq handler\n"); - BUG_ON(skb == NULL); - dma_unmap_single(lp->dev, tx_dmabuf, tx_dmalen, DMA_TO_DEVICE); - netif_trans_update(dev); - dev_kfree_skb_irq(skb); - lp->current_tx_skb = NULL; - if (lp->pending_tx_skb != NULL) - smc911x_hardware_send_pkt(dev); - else { - DBG(SMC_DEBUG_TX | SMC_DEBUG_DMA, dev, - "No pending Tx packets. DMA disabled\n"); - spin_lock_irqsave(&lp->lock, flags); - lp->txdma_active = 0; - if (!lp->tx_throttle) { - netif_wake_queue(dev); - } - spin_unlock_irqrestore(&lp->lock, flags); - } - - DBG(SMC_DEBUG_TX | SMC_DEBUG_DMA, dev, - "TX DMA irq completed\n"); -} -static void -smc911x_rx_dma_irq(void *data) -{ - struct smc911x_local *lp = data; - struct net_device *dev = lp->netdev; - struct sk_buff *skb = lp->current_rx_skb; - unsigned long flags; - unsigned int pkts; - - DBG(SMC_DEBUG_FUNC, dev, "--> %s\n", __func__); - DBG(SMC_DEBUG_RX | SMC_DEBUG_DMA, dev, "RX DMA irq handler\n"); - dma_unmap_single(lp->dev, rx_dmabuf, rx_dmalen, DMA_FROM_DEVICE); - BUG_ON(skb == NULL); - lp->current_rx_skb = NULL; - PRINT_PKT(skb->data, skb->len); - skb->protocol = eth_type_trans(skb, dev); - dev->stats.rx_packets++; - dev->stats.rx_bytes += skb->len; - netif_rx(skb); - - spin_lock_irqsave(&lp->lock, flags); - pkts = (SMC_GET_RX_FIFO_INF(lp) & RX_FIFO_INF_RXSUSED_) >> 16; - if (pkts != 0) { - smc911x_rcv(dev); - }else { - lp->rxdma_active = 0; - } - spin_unlock_irqrestore(&lp->lock, flags); - DBG(SMC_DEBUG_RX | SMC_DEBUG_DMA, dev, - "RX DMA irq completed. DMA RX FIFO PKTS %d\n", - pkts); -} -#endif /* SMC_USE_DMA */ - -#ifdef CONFIG_NET_POLL_CONTROLLER -/* - * Polling receive - used by netconsole and other diagnostic tools - * to allow network i/o with interrupts disabled. - */ -static void smc911x_poll_controller(struct net_device *dev) -{ - disable_irq(dev->irq); - smc911x_interrupt(dev->irq, dev); - enable_irq(dev->irq); -} -#endif - -/* Our watchdog timed out. Called by the networking layer */ -static void smc911x_timeout(struct net_device *dev, unsigned int txqueue) -{ - struct smc911x_local *lp = netdev_priv(dev); - int status, mask; - unsigned long flags; - - DBG(SMC_DEBUG_FUNC, dev, "--> %s\n", __func__); - - spin_lock_irqsave(&lp->lock, flags); - status = SMC_GET_INT(lp); - mask = SMC_GET_INT_EN(lp); - spin_unlock_irqrestore(&lp->lock, flags); - DBG(SMC_DEBUG_MISC, dev, "INT 0x%02x MASK 0x%02x\n", - status, mask); - - /* Dump the current TX FIFO contents and restart */ - mask = SMC_GET_TX_CFG(lp); - SMC_SET_TX_CFG(lp, mask | TX_CFG_TXS_DUMP_ | TX_CFG_TXD_DUMP_); - /* - * Reconfiguring the PHY doesn't seem like a bad idea here, but - * smc911x_phy_configure() calls msleep() which calls schedule_timeout() - * which calls schedule(). Hence we use a work queue. - */ - if (lp->phy_type != 0) - schedule_work(&lp->phy_configure); - - /* We can accept TX packets again */ - netif_trans_update(dev); /* prevent tx timeout */ - netif_wake_queue(dev); -} - -/* - * This routine will, depending on the values passed to it, - * either make it accept multicast packets, go into - * promiscuous mode (for TCPDUMP and cousins) or accept - * a select set of multicast packets - */ -static void smc911x_set_multicast_list(struct net_device *dev) -{ - struct smc911x_local *lp = netdev_priv(dev); - unsigned int multicast_table[2]; - unsigned int mcr, update_multicast = 0; - unsigned long flags; - - DBG(SMC_DEBUG_FUNC, dev, "--> %s\n", __func__); - - spin_lock_irqsave(&lp->lock, flags); - SMC_GET_MAC_CR(lp, mcr); - spin_unlock_irqrestore(&lp->lock, flags); - - if (dev->flags & IFF_PROMISC) { - - DBG(SMC_DEBUG_MISC, dev, "RCR_PRMS\n"); - mcr |= MAC_CR_PRMS_; - } - /* - * Here, I am setting this to accept all multicast packets. - * I don't need to zero the multicast table, because the flag is - * checked before the table is - */ - else if (dev->flags & IFF_ALLMULTI || netdev_mc_count(dev) > 16) { - DBG(SMC_DEBUG_MISC, dev, "RCR_ALMUL\n"); - mcr |= MAC_CR_MCPAS_; - } - - /* - * This sets the internal hardware table to filter out unwanted - * multicast packets before they take up memory. - * - * The SMC chip uses a hash table where the high 6 bits of the CRC of - * address are the offset into the table. If that bit is 1, then the - * multicast packet is accepted. Otherwise, it's dropped silently. - * - * To use the 6 bits as an offset into the table, the high 1 bit is - * the number of the 32 bit register, while the low 5 bits are the bit - * within that register. - */ - else if (!netdev_mc_empty(dev)) { - struct netdev_hw_addr *ha; - - /* Set the Hash perfec mode */ - mcr |= MAC_CR_HPFILT_; - - /* start with a table of all zeros: reject all */ - memset(multicast_table, 0, sizeof(multicast_table)); - - netdev_for_each_mc_addr(ha, dev) { - u32 position; - - /* upper 6 bits are used as hash index */ - position = ether_crc(ETH_ALEN, ha->addr)>>26; - - multicast_table[position>>5] |= 1 << (position&0x1f); - } - - /* be sure I get rid of flags I might have set */ - mcr &= ~(MAC_CR_PRMS_ | MAC_CR_MCPAS_); - - /* now, the table can be loaded into the chipset */ - update_multicast = 1; - } else { - DBG(SMC_DEBUG_MISC, dev, "~(MAC_CR_PRMS_|MAC_CR_MCPAS_)\n"); - mcr &= ~(MAC_CR_PRMS_ | MAC_CR_MCPAS_); - - /* - * since I'm disabling all multicast entirely, I need to - * clear the multicast list - */ - memset(multicast_table, 0, sizeof(multicast_table)); - update_multicast = 1; - } - - spin_lock_irqsave(&lp->lock, flags); - SMC_SET_MAC_CR(lp, mcr); - if (update_multicast) { - DBG(SMC_DEBUG_MISC, dev, - "update mcast hash table 0x%08x 0x%08x\n", - multicast_table[0], multicast_table[1]); - SMC_SET_HASHL(lp, multicast_table[0]); - SMC_SET_HASHH(lp, multicast_table[1]); - } - spin_unlock_irqrestore(&lp->lock, flags); -} - - -/* - * Open and Initialize the board - * - * Set up everything, reset the card, etc.. - */ -static int -smc911x_open(struct net_device *dev) -{ - struct smc911x_local *lp = netdev_priv(dev); - - DBG(SMC_DEBUG_FUNC, dev, "--> %s\n", __func__); - - /* reset the hardware */ - smc911x_reset(dev); - - /* Configure the PHY, initialize the link state */ - smc911x_phy_configure(&lp->phy_configure); - - /* Turn on Tx + Rx */ - smc911x_enable(dev); - - netif_start_queue(dev); - - return 0; -} - -/* - * smc911x_close - * - * this makes the board clean up everything that it can - * and not talk to the outside world. Caused by - * an 'ifconfig ethX down' - */ -static int smc911x_close(struct net_device *dev) -{ - struct smc911x_local *lp = netdev_priv(dev); - - DBG(SMC_DEBUG_FUNC, dev, "--> %s\n", __func__); - - netif_stop_queue(dev); - netif_carrier_off(dev); - - /* clear everything */ - smc911x_shutdown(dev); - - if (lp->phy_type != 0) { - /* We need to ensure that no calls to - * smc911x_phy_configure are pending. - */ - cancel_work_sync(&lp->phy_configure); - smc911x_phy_powerdown(dev, lp->mii.phy_id); - } - - if (lp->pending_tx_skb) { - dev_kfree_skb(lp->pending_tx_skb); - lp->pending_tx_skb = NULL; - } - - return 0; -} - -/* - * Ethtool support - */ -static int -smc911x_ethtool_get_link_ksettings(struct net_device *dev, - struct ethtool_link_ksettings *cmd) -{ - struct smc911x_local *lp = netdev_priv(dev); - int status; - unsigned long flags; - u32 supported; - - DBG(SMC_DEBUG_FUNC, dev, "--> %s\n", __func__); - - if (lp->phy_type != 0) { - spin_lock_irqsave(&lp->lock, flags); - mii_ethtool_get_link_ksettings(&lp->mii, cmd); - spin_unlock_irqrestore(&lp->lock, flags); - } else { - supported = SUPPORTED_10baseT_Half | - SUPPORTED_10baseT_Full | - SUPPORTED_TP | SUPPORTED_AUI; - - if (lp->ctl_rspeed == 10) - cmd->base.speed = SPEED_10; - else if (lp->ctl_rspeed == 100) - cmd->base.speed = SPEED_100; - - cmd->base.autoneg = AUTONEG_DISABLE; - cmd->base.port = 0; - SMC_GET_PHY_SPECIAL(lp, lp->mii.phy_id, status); - cmd->base.duplex = - (status & (PHY_SPECIAL_SPD_10FULL_ | PHY_SPECIAL_SPD_100FULL_)) ? - DUPLEX_FULL : DUPLEX_HALF; - - ethtool_convert_legacy_u32_to_link_mode( - cmd->link_modes.supported, supported); - - } - - return 0; -} - -static int -smc911x_ethtool_set_link_ksettings(struct net_device *dev, - const struct ethtool_link_ksettings *cmd) -{ - struct smc911x_local *lp = netdev_priv(dev); - int ret; - unsigned long flags; - - if (lp->phy_type != 0) { - spin_lock_irqsave(&lp->lock, flags); - ret = mii_ethtool_set_link_ksettings(&lp->mii, cmd); - spin_unlock_irqrestore(&lp->lock, flags); - } else { - if (cmd->base.autoneg != AUTONEG_DISABLE || - cmd->base.speed != SPEED_10 || - (cmd->base.duplex != DUPLEX_HALF && - cmd->base.duplex != DUPLEX_FULL) || - (cmd->base.port != PORT_TP && - cmd->base.port != PORT_AUI)) - return -EINVAL; - - lp->ctl_rfduplx = cmd->base.duplex == DUPLEX_FULL; - - ret = 0; - } - - return ret; -} - -static void -smc911x_ethtool_getdrvinfo(struct net_device *dev, struct ethtool_drvinfo *info) -{ - strscpy(info->driver, CARDNAME, sizeof(info->driver)); - strscpy(info->version, version, sizeof(info->version)); - strscpy(info->bus_info, dev_name(dev->dev.parent), - sizeof(info->bus_info)); -} - -static int smc911x_ethtool_nwayreset(struct net_device *dev) -{ - struct smc911x_local *lp = netdev_priv(dev); - int ret = -EINVAL; - unsigned long flags; - - if (lp->phy_type != 0) { - spin_lock_irqsave(&lp->lock, flags); - ret = mii_nway_restart(&lp->mii); - spin_unlock_irqrestore(&lp->lock, flags); - } - - return ret; -} - -static u32 smc911x_ethtool_getmsglevel(struct net_device *dev) -{ - struct smc911x_local *lp = netdev_priv(dev); - return lp->msg_enable; -} - -static void smc911x_ethtool_setmsglevel(struct net_device *dev, u32 level) -{ - struct smc911x_local *lp = netdev_priv(dev); - lp->msg_enable = level; -} - -static int smc911x_ethtool_getregslen(struct net_device *dev) -{ - /* System regs + MAC regs + PHY regs */ - return (((E2P_CMD - ID_REV)/4 + 1) + - (WUCSR - MAC_CR)+1 + 32) * sizeof(u32); -} - -static void smc911x_ethtool_getregs(struct net_device *dev, - struct ethtool_regs *regs, void *buf) -{ - struct smc911x_local *lp = netdev_priv(dev); - unsigned long flags; - u32 reg,i,j=0; - u32 *data = (u32*)buf; - - regs->version = lp->version; - for(i=ID_REV;i<=E2P_CMD;i+=4) { - data[j++] = SMC_inl(lp, i); - } - for(i=MAC_CR;i<=WUCSR;i++) { - spin_lock_irqsave(&lp->lock, flags); - SMC_GET_MAC_CSR(lp, i, reg); - spin_unlock_irqrestore(&lp->lock, flags); - data[j++] = reg; - } - for(i=0;i<=31;i++) { - spin_lock_irqsave(&lp->lock, flags); - SMC_GET_MII(lp, i, lp->mii.phy_id, reg); - spin_unlock_irqrestore(&lp->lock, flags); - data[j++] = reg & 0xFFFF; - } -} - -static int smc911x_ethtool_wait_eeprom_ready(struct net_device *dev) -{ - struct smc911x_local *lp = netdev_priv(dev); - unsigned int timeout; - int e2p_cmd; - - e2p_cmd = SMC_GET_E2P_CMD(lp); - for(timeout=10;(e2p_cmd & E2P_CMD_EPC_BUSY_) && timeout; timeout--) { - if (e2p_cmd & E2P_CMD_EPC_TIMEOUT_) { - PRINTK(dev, "%s timeout waiting for EEPROM to respond\n", - __func__); - return -EFAULT; - } - mdelay(1); - e2p_cmd = SMC_GET_E2P_CMD(lp); - } - if (timeout == 0) { - PRINTK(dev, "%s timeout waiting for EEPROM CMD not busy\n", - __func__); - return -ETIMEDOUT; - } - return 0; -} - -static inline int smc911x_ethtool_write_eeprom_cmd(struct net_device *dev, - int cmd, int addr) -{ - struct smc911x_local *lp = netdev_priv(dev); - int ret; - - if ((ret = smc911x_ethtool_wait_eeprom_ready(dev))!=0) - return ret; - SMC_SET_E2P_CMD(lp, E2P_CMD_EPC_BUSY_ | - ((cmd) & (0x7<<28)) | - ((addr) & 0xFF)); - return 0; -} - -static inline int smc911x_ethtool_read_eeprom_byte(struct net_device *dev, - u8 *data) -{ - struct smc911x_local *lp = netdev_priv(dev); - int ret; - - if ((ret = smc911x_ethtool_wait_eeprom_ready(dev))!=0) - return ret; - *data = SMC_GET_E2P_DATA(lp); - return 0; -} - -static inline int smc911x_ethtool_write_eeprom_byte(struct net_device *dev, - u8 data) -{ - struct smc911x_local *lp = netdev_priv(dev); - int ret; - - if ((ret = smc911x_ethtool_wait_eeprom_ready(dev))!=0) - return ret; - SMC_SET_E2P_DATA(lp, data); - return 0; -} - -static int smc911x_ethtool_geteeprom(struct net_device *dev, - struct ethtool_eeprom *eeprom, u8 *data) -{ - u8 eebuf[SMC911X_EEPROM_LEN]; - int i, ret; - - for(i=0;i<SMC911X_EEPROM_LEN;i++) { - if ((ret=smc911x_ethtool_write_eeprom_cmd(dev, E2P_CMD_EPC_CMD_READ_, i ))!=0) - return ret; - if ((ret=smc911x_ethtool_read_eeprom_byte(dev, &eebuf[i]))!=0) - return ret; - } - memcpy(data, eebuf+eeprom->offset, eeprom->len); - return 0; -} - -static int smc911x_ethtool_seteeprom(struct net_device *dev, - struct ethtool_eeprom *eeprom, u8 *data) -{ - int i, ret; - - /* Enable erase */ - if ((ret=smc911x_ethtool_write_eeprom_cmd(dev, E2P_CMD_EPC_CMD_EWEN_, 0 ))!=0) - return ret; - for(i=eeprom->offset;i<(eeprom->offset+eeprom->len);i++) { - /* erase byte */ - if ((ret=smc911x_ethtool_write_eeprom_cmd(dev, E2P_CMD_EPC_CMD_ERASE_, i ))!=0) - return ret; - /* write byte */ - if ((ret=smc911x_ethtool_write_eeprom_byte(dev, *data))!=0) - return ret; - if ((ret=smc911x_ethtool_write_eeprom_cmd(dev, E2P_CMD_EPC_CMD_WRITE_, i ))!=0) - return ret; - } - return 0; -} - -static int smc911x_ethtool_geteeprom_len(struct net_device *dev) -{ - return SMC911X_EEPROM_LEN; -} - -static const struct ethtool_ops smc911x_ethtool_ops = { - .get_drvinfo = smc911x_ethtool_getdrvinfo, - .get_msglevel = smc911x_ethtool_getmsglevel, - .set_msglevel = smc911x_ethtool_setmsglevel, - .nway_reset = smc911x_ethtool_nwayreset, - .get_link = ethtool_op_get_link, - .get_regs_len = smc911x_ethtool_getregslen, - .get_regs = smc911x_ethtool_getregs, - .get_eeprom_len = smc911x_ethtool_geteeprom_len, - .get_eeprom = smc911x_ethtool_geteeprom, - .set_eeprom = smc911x_ethtool_seteeprom, - .get_link_ksettings = smc911x_ethtool_get_link_ksettings, - .set_link_ksettings = smc911x_ethtool_set_link_ksettings, -}; - -/* - * smc911x_findirq - * - * This routine has a simple purpose -- make the SMC chip generate an - * interrupt, so an auto-detect routine can detect it, and find the IRQ, - */ -static int smc911x_findirq(struct net_device *dev) -{ - struct smc911x_local *lp = netdev_priv(dev); - int timeout = 20; - unsigned long cookie; - - DBG(SMC_DEBUG_FUNC, dev, "--> %s\n", __func__); - - cookie = probe_irq_on(); - - /* - * Force a SW interrupt - */ - - SMC_SET_INT_EN(lp, INT_EN_SW_INT_EN_); - - /* - * Wait until positive that the interrupt has been generated - */ - do { - int int_status; - udelay(10); - int_status = SMC_GET_INT_EN(lp); - if (int_status & INT_EN_SW_INT_EN_) - break; /* got the interrupt */ - } while (--timeout); - - /* - * there is really nothing that I can do here if timeout fails, - * as autoirq_report will return a 0 anyway, which is what I - * want in this case. Plus, the clean up is needed in both - * cases. - */ - - /* and disable all interrupts again */ - SMC_SET_INT_EN(lp, 0); - - /* and return what I found */ - return probe_irq_off(cookie); -} - -static const struct net_device_ops smc911x_netdev_ops = { - .ndo_open = smc911x_open, - .ndo_stop = smc911x_close, - .ndo_start_xmit = smc911x_hard_start_xmit, - .ndo_tx_timeout = smc911x_timeout, - .ndo_set_rx_mode = smc911x_set_multicast_list, - .ndo_validate_addr = eth_validate_addr, - .ndo_set_mac_address = eth_mac_addr, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = smc911x_poll_controller, -#endif -}; - -/* - * Function: smc911x_probe(unsigned long ioaddr) - * - * Purpose: - * Tests to see if a given ioaddr points to an SMC911x chip. - * Returns a 0 on success - * - * Algorithm: - * (1) see if the endian word is OK - * (1) see if I recognize the chip ID in the appropriate register - * - * Here I do typical initialization tasks. - * - * o Initialize the structure if needed - * o print out my vanity message if not done so already - * o print out what type of hardware is detected - * o print out the ethernet address - * o find the IRQ - * o set up my private data - * o configure the dev structure with my subroutines - * o actually GRAB the irq. - * o GRAB the region - */ -static int smc911x_probe(struct net_device *dev) -{ - struct smc911x_local *lp = netdev_priv(dev); - int i, retval; - unsigned int val, chip_id, revision; - const char *version_string; - unsigned long irq_flags; -#ifdef SMC_USE_DMA - struct dma_slave_config config; - dma_cap_mask_t mask; -#endif - u8 addr[ETH_ALEN]; - - DBG(SMC_DEBUG_FUNC, dev, "--> %s\n", __func__); - - /* First, see if the endian word is recognized */ - val = SMC_GET_BYTE_TEST(lp); - DBG(SMC_DEBUG_MISC, dev, "%s: endian probe returned 0x%04x\n", - CARDNAME, val); - if (val != 0x87654321) { - netdev_err(dev, "Invalid chip endian 0x%08x\n", val); - retval = -ENODEV; - goto err_out; - } - - /* - * check if the revision register is something that I - * recognize. These might need to be added to later, - * as future revisions could be added. - */ - chip_id = SMC_GET_PN(lp); - DBG(SMC_DEBUG_MISC, dev, "%s: id probe returned 0x%04x\n", - CARDNAME, chip_id); - for(i=0;chip_ids[i].id != 0; i++) { - if (chip_ids[i].id == chip_id) break; - } - if (!chip_ids[i].id) { - netdev_err(dev, "Unknown chip ID %04x\n", chip_id); - retval = -ENODEV; - goto err_out; - } - version_string = chip_ids[i].name; - - revision = SMC_GET_REV(lp); - DBG(SMC_DEBUG_MISC, dev, "%s: revision = 0x%04x\n", CARDNAME, revision); - - /* At this point I'll assume that the chip is an SMC911x. */ - DBG(SMC_DEBUG_MISC, dev, "%s: Found a %s\n", - CARDNAME, chip_ids[i].name); - - /* Validate the TX FIFO size requested */ - if ((tx_fifo_kb < 2) || (tx_fifo_kb > 14)) { - netdev_err(dev, "Invalid TX FIFO size requested %d\n", - tx_fifo_kb); - retval = -EINVAL; - goto err_out; - } - - /* fill in some of the fields */ - lp->version = chip_ids[i].id; - lp->revision = revision; - lp->tx_fifo_kb = tx_fifo_kb; - /* Reverse calculate the RX FIFO size from the TX */ - lp->tx_fifo_size=(lp->tx_fifo_kb<<10) - 512; - lp->rx_fifo_size= ((0x4000 - 512 - lp->tx_fifo_size) / 16) * 15; - - /* Set the automatic flow control values */ - switch(lp->tx_fifo_kb) { - /* - * AFC_HI is about ((Rx Data Fifo Size)*2/3)/64 - * AFC_LO is AFC_HI/2 - * BACK_DUR is about 5uS*(AFC_LO) rounded down - */ - case 2:/* 13440 Rx Data Fifo Size */ - lp->afc_cfg=0x008C46AF;break; - case 3:/* 12480 Rx Data Fifo Size */ - lp->afc_cfg=0x0082419F;break; - case 4:/* 11520 Rx Data Fifo Size */ - lp->afc_cfg=0x00783C9F;break; - case 5:/* 10560 Rx Data Fifo Size */ - lp->afc_cfg=0x006E374F;break; - case 6:/* 9600 Rx Data Fifo Size */ - lp->afc_cfg=0x0064328F;break; - case 7:/* 8640 Rx Data Fifo Size */ - lp->afc_cfg=0x005A2D7F;break; - case 8:/* 7680 Rx Data Fifo Size */ - lp->afc_cfg=0x0050287F;break; - case 9:/* 6720 Rx Data Fifo Size */ - lp->afc_cfg=0x0046236F;break; - case 10:/* 5760 Rx Data Fifo Size */ - lp->afc_cfg=0x003C1E6F;break; - case 11:/* 4800 Rx Data Fifo Size */ - lp->afc_cfg=0x0032195F;break; - /* - * AFC_HI is ~1520 bytes less than RX Data Fifo Size - * AFC_LO is AFC_HI/2 - * BACK_DUR is about 5uS*(AFC_LO) rounded down - */ - case 12:/* 3840 Rx Data Fifo Size */ - lp->afc_cfg=0x0024124F;break; - case 13:/* 2880 Rx Data Fifo Size */ - lp->afc_cfg=0x0015073F;break; - case 14:/* 1920 Rx Data Fifo Size */ - lp->afc_cfg=0x0006032F;break; - default: - PRINTK(dev, "ERROR -- no AFC_CFG setting found"); - break; - } - - DBG(SMC_DEBUG_MISC | SMC_DEBUG_TX | SMC_DEBUG_RX, dev, - "%s: tx_fifo %d rx_fifo %d afc_cfg 0x%08x\n", CARDNAME, - lp->tx_fifo_size, lp->rx_fifo_size, lp->afc_cfg); - - spin_lock_init(&lp->lock); - - /* Get the MAC address */ - SMC_GET_MAC_ADDR(lp, addr); - eth_hw_addr_set(dev, addr); - - /* now, reset the chip, and put it into a known state */ - smc911x_reset(dev); - - /* - * If dev->irq is 0, then the device has to be banged on to see - * what the IRQ is. - * - * Specifying an IRQ is done with the assumption that the user knows - * what (s)he is doing. No checking is done!!!! - */ - if (dev->irq < 1) { - int trials; - - trials = 3; - while (trials--) { - dev->irq = smc911x_findirq(dev); - if (dev->irq) - break; - /* kick the card and try again */ - smc911x_reset(dev); - } - } - if (dev->irq == 0) { - netdev_warn(dev, "Couldn't autodetect your IRQ. Use irq=xx.\n"); - retval = -ENODEV; - goto err_out; - } - dev->irq = irq_canonicalize(dev->irq); - - dev->netdev_ops = &smc911x_netdev_ops; - dev->watchdog_timeo = msecs_to_jiffies(watchdog); - dev->ethtool_ops = &smc911x_ethtool_ops; - - INIT_WORK(&lp->phy_configure, smc911x_phy_configure); - lp->mii.phy_id_mask = 0x1f; - lp->mii.reg_num_mask = 0x1f; - lp->mii.force_media = 0; - lp->mii.full_duplex = 0; - lp->mii.dev = dev; - lp->mii.mdio_read = smc911x_phy_read; - lp->mii.mdio_write = smc911x_phy_write; - - /* - * Locate the phy, if any. - */ - smc911x_phy_detect(dev); - - /* Set default parameters */ - lp->msg_enable = NETIF_MSG_LINK; - lp->ctl_rfduplx = 1; - lp->ctl_rspeed = 100; - -#ifdef SMC_DYNAMIC_BUS_CONFIG - irq_flags = lp->cfg.irq_flags; -#else - irq_flags = IRQF_SHARED | SMC_IRQ_SENSE; -#endif - - /* Grab the IRQ */ - retval = request_irq(dev->irq, smc911x_interrupt, - irq_flags, dev->name, dev); - if (retval) - goto err_out; - -#ifdef SMC_USE_DMA - - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - lp->rxdma = dma_request_channel(mask, NULL, NULL); - lp->txdma = dma_request_channel(mask, NULL, NULL); - lp->rxdma_active = 0; - lp->txdma_active = 0; - - memset(&config, 0, sizeof(config)); - config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - config.src_addr = lp->physaddr + RX_DATA_FIFO; - config.dst_addr = lp->physaddr + TX_DATA_FIFO; - config.src_maxburst = 32; - config.dst_maxburst = 32; - retval = dmaengine_slave_config(lp->rxdma, &config); - if (retval) { - dev_err(lp->dev, "dma rx channel configuration failed: %d\n", - retval); - goto err_out; - } - retval = dmaengine_slave_config(lp->txdma, &config); - if (retval) { - dev_err(lp->dev, "dma tx channel configuration failed: %d\n", - retval); - goto err_out; - } -#endif - - retval = register_netdev(dev); - if (retval == 0) { - /* now, print out the card info, in a short format.. */ - netdev_info(dev, "%s (rev %d) at %#lx IRQ %d", - version_string, lp->revision, - dev->base_addr, dev->irq); - -#ifdef SMC_USE_DMA - if (lp->rxdma) - pr_cont(" RXDMA %p", lp->rxdma); - - if (lp->txdma) - pr_cont(" TXDMA %p", lp->txdma); -#endif - pr_cont("\n"); - if (!is_valid_ether_addr(dev->dev_addr)) { - netdev_warn(dev, "Invalid ethernet MAC address. Please set using ifconfig\n"); - } else { - /* Print the Ethernet address */ - netdev_info(dev, "Ethernet addr: %pM\n", - dev->dev_addr); - } - - if (lp->phy_type == 0) { - PRINTK(dev, "No PHY found\n"); - } else if ((lp->phy_type & ~0xff) == LAN911X_INTERNAL_PHY_ID) { - PRINTK(dev, "LAN911x Internal PHY\n"); - } else { - PRINTK(dev, "External PHY 0x%08x\n", lp->phy_type); - } - } - -err_out: -#ifdef SMC_USE_DMA - if (retval) { - if (lp->rxdma) - dma_release_channel(lp->rxdma); - if (lp->txdma) - dma_release_channel(lp->txdma); - } -#endif - return retval; -} - -/* - * smc911x_drv_probe(void) - * - * Output: - * 0 --> there is a device - * anything else, error - */ -static int smc911x_drv_probe(struct platform_device *pdev) -{ - struct net_device *ndev; - struct resource *res; - struct smc911x_local *lp; - void __iomem *addr; - int ret; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - ret = -ENODEV; - goto out; - } - - /* - * Request the regions. - */ - if (!request_mem_region(res->start, SMC911X_IO_EXTENT, CARDNAME)) { - ret = -EBUSY; - goto out; - } - - ndev = alloc_etherdev(sizeof(struct smc911x_local)); - if (!ndev) { - ret = -ENOMEM; - goto release_1; - } - SET_NETDEV_DEV(ndev, &pdev->dev); - - ndev->dma = (unsigned char)-1; - ndev->irq = platform_get_irq(pdev, 0); - if (ndev->irq < 0) { - ret = ndev->irq; - goto release_both; - } - - lp = netdev_priv(ndev); - lp->netdev = ndev; -#ifdef SMC_DYNAMIC_BUS_CONFIG - { - struct smc911x_platdata *pd = dev_get_platdata(&pdev->dev); - if (!pd) { - ret = -EINVAL; - goto release_both; - } - memcpy(&lp->cfg, pd, sizeof(lp->cfg)); - } -#endif - - addr = ioremap(res->start, SMC911X_IO_EXTENT); - if (!addr) { - ret = -ENOMEM; - goto release_both; - } - - platform_set_drvdata(pdev, ndev); - lp->base = addr; - ndev->base_addr = res->start; - ret = smc911x_probe(ndev); - if (ret != 0) { - iounmap(addr); -release_both: - free_netdev(ndev); -release_1: - release_mem_region(res->start, SMC911X_IO_EXTENT); -out: - pr_info("%s: not found (%d).\n", CARDNAME, ret); - } -#ifdef SMC_USE_DMA - else { - lp->physaddr = res->start; - lp->dev = &pdev->dev; - } -#endif - - return ret; -} - -static int smc911x_drv_remove(struct platform_device *pdev) -{ - struct net_device *ndev = platform_get_drvdata(pdev); - struct smc911x_local *lp = netdev_priv(ndev); - struct resource *res; - - DBG(SMC_DEBUG_FUNC, ndev, "--> %s\n", __func__); - - unregister_netdev(ndev); - - free_irq(ndev->irq, ndev); - -#ifdef SMC_USE_DMA - { - if (lp->rxdma) - dma_release_channel(lp->rxdma); - if (lp->txdma) - dma_release_channel(lp->txdma); - } -#endif - iounmap(lp->base); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, SMC911X_IO_EXTENT); - - free_netdev(ndev); - return 0; -} - -static int smc911x_drv_suspend(struct platform_device *dev, pm_message_t state) -{ - struct net_device *ndev = platform_get_drvdata(dev); - struct smc911x_local *lp = netdev_priv(ndev); - - DBG(SMC_DEBUG_FUNC, ndev, "--> %s\n", __func__); - if (ndev) { - if (netif_running(ndev)) { - netif_device_detach(ndev); - smc911x_shutdown(ndev); -#if POWER_DOWN - /* Set D2 - Energy detect only setting */ - SMC_SET_PMT_CTRL(lp, 2<<12); -#endif - } - } - return 0; -} - -static int smc911x_drv_resume(struct platform_device *dev) -{ - struct net_device *ndev = platform_get_drvdata(dev); - - DBG(SMC_DEBUG_FUNC, ndev, "--> %s\n", __func__); - if (ndev) { - struct smc911x_local *lp = netdev_priv(ndev); - - if (netif_running(ndev)) { - smc911x_reset(ndev); - if (lp->phy_type != 0) - smc911x_phy_configure(&lp->phy_configure); - smc911x_enable(ndev); - netif_device_attach(ndev); - } - } - return 0; -} - -static struct platform_driver smc911x_driver = { - .probe = smc911x_drv_probe, - .remove = smc911x_drv_remove, - .suspend = smc911x_drv_suspend, - .resume = smc911x_drv_resume, - .driver = { - .name = CARDNAME, - }, -}; - -module_platform_driver(smc911x_driver); diff --git a/drivers/net/ethernet/smsc/smc911x.h b/drivers/net/ethernet/smsc/smc911x.h deleted file mode 100644 index d4edcc0da87c..000000000000 --- a/drivers/net/ethernet/smsc/smc911x.h +++ /dev/null @@ -1,901 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/*------------------------------------------------------------------------ - . smc911x.h - macros for SMSC's LAN911{5,6,7,8} single-chip Ethernet device. - . - . Copyright (C) 2005 Sensoria Corp. - . Derived from the unified SMC91x driver by Nicolas Pitre - . - . - . Information contained in this file was obtained from the LAN9118 - . manual from SMC. To get a copy, if you really want one, you can find - . information under www.smsc.com. - . - . Authors - . Dustin McIntire <dustin@sensoria.com> - . - ---------------------------------------------------------------------------*/ -#ifndef _SMC911X_H_ -#define _SMC911X_H_ - -#include <linux/smc911x.h> -/* - * Use the DMA feature on PXA chips - */ -#ifdef CONFIG_ARCH_PXA - #define SMC_USE_PXA_DMA 1 - #define SMC_USE_16BIT 0 - #define SMC_USE_32BIT 1 - #define SMC_IRQ_SENSE IRQF_TRIGGER_FALLING -#elif defined(CONFIG_SH_MAGIC_PANEL_R2) - #define SMC_USE_16BIT 0 - #define SMC_USE_32BIT 1 - #define SMC_IRQ_SENSE IRQF_TRIGGER_LOW -#elif defined(CONFIG_ARCH_OMAP3) - #define SMC_USE_16BIT 0 - #define SMC_USE_32BIT 1 - #define SMC_IRQ_SENSE IRQF_TRIGGER_LOW - #define SMC_MEM_RESERVED 1 -#elif defined(CONFIG_ARCH_OMAP2) - #define SMC_USE_16BIT 0 - #define SMC_USE_32BIT 1 - #define SMC_IRQ_SENSE IRQF_TRIGGER_LOW - #define SMC_MEM_RESERVED 1 -#else -/* - * Default configuration - */ - -#define SMC_DYNAMIC_BUS_CONFIG -#endif - -#ifdef SMC_USE_PXA_DMA -#define SMC_USE_DMA -#endif - -/* store this information for the driver.. */ -struct smc911x_local { - /* - * If I have to wait until the DMA is finished and ready to reload a - * packet, I will store the skbuff here. Then, the DMA will send it - * out and free it. - */ - struct sk_buff *pending_tx_skb; - - /* version/revision of the SMC911x chip */ - u16 version; - u16 revision; - - /* FIFO sizes */ - int tx_fifo_kb; - int tx_fifo_size; - int rx_fifo_size; - int afc_cfg; - - /* Contains the current active receive/phy mode */ - int ctl_rfduplx; - int ctl_rspeed; - - u32 msg_enable; - u32 phy_type; - struct mii_if_info mii; - - /* work queue */ - struct work_struct phy_configure; - - int tx_throttle; - spinlock_t lock; - - struct net_device *netdev; - -#ifdef SMC_USE_DMA - /* DMA needs the physical address of the chip */ - u_long physaddr; - struct dma_chan *rxdma; - struct dma_chan *txdma; - int rxdma_active; - int txdma_active; - struct sk_buff *current_rx_skb; - struct sk_buff *current_tx_skb; - struct device *dev; -#endif - void __iomem *base; -#ifdef SMC_DYNAMIC_BUS_CONFIG - struct smc911x_platdata cfg; -#endif -}; - -/* - * Define the bus width specific IO macros - */ - -#ifdef SMC_DYNAMIC_BUS_CONFIG -static inline unsigned int SMC_inl(struct smc911x_local *lp, int reg) -{ - void __iomem *ioaddr = lp->base + reg; - - if (lp->cfg.flags & SMC911X_USE_32BIT) - return readl(ioaddr); - - if (lp->cfg.flags & SMC911X_USE_16BIT) - return readw(ioaddr) | (readw(ioaddr + 2) << 16); - - BUG(); -} - -static inline void SMC_outl(unsigned int value, struct smc911x_local *lp, - int reg) -{ - void __iomem *ioaddr = lp->base + reg; - - if (lp->cfg.flags & SMC911X_USE_32BIT) { - writel(value, ioaddr); - return; - } - - if (lp->cfg.flags & SMC911X_USE_16BIT) { - writew(value & 0xffff, ioaddr); - writew(value >> 16, ioaddr + 2); - return; - } - - BUG(); -} - -static inline void SMC_insl(struct smc911x_local *lp, int reg, - void *addr, unsigned int count) -{ - void __iomem *ioaddr = lp->base + reg; - - if (lp->cfg.flags & SMC911X_USE_32BIT) { - ioread32_rep(ioaddr, addr, count); - return; - } - - if (lp->cfg.flags & SMC911X_USE_16BIT) { - ioread16_rep(ioaddr, addr, count * 2); - return; - } - - BUG(); -} - -static inline void SMC_outsl(struct smc911x_local *lp, int reg, - void *addr, unsigned int count) -{ - void __iomem *ioaddr = lp->base + reg; - - if (lp->cfg.flags & SMC911X_USE_32BIT) { - iowrite32_rep(ioaddr, addr, count); - return; - } - - if (lp->cfg.flags & SMC911X_USE_16BIT) { - iowrite16_rep(ioaddr, addr, count * 2); - return; - } - - BUG(); -} -#else -#if SMC_USE_16BIT -#define SMC_inl(lp, r) ((readw((lp)->base + (r)) & 0xFFFF) + (readw((lp)->base + (r) + 2) << 16)) -#define SMC_outl(v, lp, r) \ - do{ \ - writew(v & 0xFFFF, (lp)->base + (r)); \ - writew(v >> 16, (lp)->base + (r) + 2); \ - } while (0) -#define SMC_insl(lp, r, p, l) ioread16_rep((short*)((lp)->base + (r)), p, l*2) -#define SMC_outsl(lp, r, p, l) iowrite16_rep((short*)((lp)->base + (r)), p, l*2) - -#elif SMC_USE_32BIT -#define SMC_inl(lp, r) readl((lp)->base + (r)) -#define SMC_outl(v, lp, r) writel(v, (lp)->base + (r)) -#define SMC_insl(lp, r, p, l) ioread32_rep((int*)((lp)->base + (r)), p, l) -#define SMC_outsl(lp, r, p, l) iowrite32_rep((int*)((lp)->base + (r)), p, l) - -#endif /* SMC_USE_16BIT */ -#endif /* SMC_DYNAMIC_BUS_CONFIG */ - - -#ifdef SMC_USE_PXA_DMA - -/* - * Use a DMA for RX and TX packets. - */ -#include <linux/dma-mapping.h> - -static dma_addr_t rx_dmabuf, tx_dmabuf; -static int rx_dmalen, tx_dmalen; -static void smc911x_rx_dma_irq(void *data); -static void smc911x_tx_dma_irq(void *data); - -#ifdef SMC_insl -#undef SMC_insl -#define SMC_insl(lp, r, p, l) \ - smc_pxa_dma_insl(lp, lp->physaddr, r, lp->rxdma, p, l) - -static inline void -smc_pxa_dma_insl(struct smc911x_local *lp, u_long physaddr, - int reg, struct dma_chan *dma, u_char *buf, int len) -{ - struct dma_async_tx_descriptor *tx; - - /* 64 bit alignment is required for memory to memory DMA */ - if ((long)buf & 4) { - *((u32 *)buf) = SMC_inl(lp, reg); - buf += 4; - len--; - } - - len *= 4; - rx_dmabuf = dma_map_single(lp->dev, buf, len, DMA_FROM_DEVICE); - rx_dmalen = len; - tx = dmaengine_prep_slave_single(dma, rx_dmabuf, rx_dmalen, - DMA_DEV_TO_MEM, 0); - if (tx) { - tx->callback = smc911x_rx_dma_irq; - tx->callback_param = lp; - dmaengine_submit(tx); - dma_async_issue_pending(dma); - } -} -#endif - -#ifdef SMC_outsl -#undef SMC_outsl -#define SMC_outsl(lp, r, p, l) \ - smc_pxa_dma_outsl(lp, lp->physaddr, r, lp->txdma, p, l) - -static inline void -smc_pxa_dma_outsl(struct smc911x_local *lp, u_long physaddr, - int reg, struct dma_chan *dma, u_char *buf, int len) -{ - struct dma_async_tx_descriptor *tx; - - /* 64 bit alignment is required for memory to memory DMA */ - if ((long)buf & 4) { - SMC_outl(*((u32 *)buf), lp, reg); - buf += 4; - len--; - } - - len *= 4; - tx_dmabuf = dma_map_single(lp->dev, buf, len, DMA_TO_DEVICE); - tx_dmalen = len; - tx = dmaengine_prep_slave_single(dma, tx_dmabuf, tx_dmalen, - DMA_DEV_TO_MEM, 0); - if (tx) { - tx->callback = smc911x_tx_dma_irq; - tx->callback_param = lp; - dmaengine_submit(tx); - dma_async_issue_pending(dma); - } -} -#endif -#endif /* SMC_USE_PXA_DMA */ - - -/* Chip Parameters and Register Definitions */ - -#define SMC911X_TX_FIFO_LOW_THRESHOLD (1536*2) - -#define SMC911X_IO_EXTENT 0x100 - -#define SMC911X_EEPROM_LEN 7 - -/* Below are the register offsets and bit definitions - * of the Lan911x memory space - */ -#define RX_DATA_FIFO (0x00) - -#define TX_DATA_FIFO (0x20) -#define TX_CMD_A_INT_ON_COMP_ (0x80000000) -#define TX_CMD_A_INT_BUF_END_ALGN_ (0x03000000) -#define TX_CMD_A_INT_4_BYTE_ALGN_ (0x00000000) -#define TX_CMD_A_INT_16_BYTE_ALGN_ (0x01000000) -#define TX_CMD_A_INT_32_BYTE_ALGN_ (0x02000000) -#define TX_CMD_A_INT_DATA_OFFSET_ (0x001F0000) -#define TX_CMD_A_INT_FIRST_SEG_ (0x00002000) -#define TX_CMD_A_INT_LAST_SEG_ (0x00001000) -#define TX_CMD_A_BUF_SIZE_ (0x000007FF) -#define TX_CMD_B_PKT_TAG_ (0xFFFF0000) -#define TX_CMD_B_ADD_CRC_DISABLE_ (0x00002000) -#define TX_CMD_B_DISABLE_PADDING_ (0x00001000) -#define TX_CMD_B_PKT_BYTE_LENGTH_ (0x000007FF) - -#define RX_STATUS_FIFO (0x40) -#define RX_STS_PKT_LEN_ (0x3FFF0000) -#define RX_STS_ES_ (0x00008000) -#define RX_STS_BCST_ (0x00002000) -#define RX_STS_LEN_ERR_ (0x00001000) -#define RX_STS_RUNT_ERR_ (0x00000800) -#define RX_STS_MCAST_ (0x00000400) -#define RX_STS_TOO_LONG_ (0x00000080) -#define RX_STS_COLL_ (0x00000040) -#define RX_STS_ETH_TYPE_ (0x00000020) -#define RX_STS_WDOG_TMT_ (0x00000010) -#define RX_STS_MII_ERR_ (0x00000008) -#define RX_STS_DRIBBLING_ (0x00000004) -#define RX_STS_CRC_ERR_ (0x00000002) -#define RX_STATUS_FIFO_PEEK (0x44) -#define TX_STATUS_FIFO (0x48) -#define TX_STS_TAG_ (0xFFFF0000) -#define TX_STS_ES_ (0x00008000) -#define TX_STS_LOC_ (0x00000800) -#define TX_STS_NO_CARR_ (0x00000400) -#define TX_STS_LATE_COLL_ (0x00000200) -#define TX_STS_MANY_COLL_ (0x00000100) -#define TX_STS_COLL_CNT_ (0x00000078) -#define TX_STS_MANY_DEFER_ (0x00000004) -#define TX_STS_UNDERRUN_ (0x00000002) -#define TX_STS_DEFERRED_ (0x00000001) -#define TX_STATUS_FIFO_PEEK (0x4C) -#define ID_REV (0x50) -#define ID_REV_CHIP_ID_ (0xFFFF0000) /* RO */ -#define ID_REV_REV_ID_ (0x0000FFFF) /* RO */ - -#define INT_CFG (0x54) -#define INT_CFG_INT_DEAS_ (0xFF000000) /* R/W */ -#define INT_CFG_INT_DEAS_CLR_ (0x00004000) -#define INT_CFG_INT_DEAS_STS_ (0x00002000) -#define INT_CFG_IRQ_INT_ (0x00001000) /* RO */ -#define INT_CFG_IRQ_EN_ (0x00000100) /* R/W */ -#define INT_CFG_IRQ_POL_ (0x00000010) /* R/W Not Affected by SW Reset */ -#define INT_CFG_IRQ_TYPE_ (0x00000001) /* R/W Not Affected by SW Reset */ - -#define INT_STS (0x58) -#define INT_STS_SW_INT_ (0x80000000) /* R/WC */ -#define INT_STS_TXSTOP_INT_ (0x02000000) /* R/WC */ -#define INT_STS_RXSTOP_INT_ (0x01000000) /* R/WC */ -#define INT_STS_RXDFH_INT_ (0x00800000) /* R/WC */ -#define INT_STS_RXDF_INT_ (0x00400000) /* R/WC */ -#define INT_STS_TX_IOC_ (0x00200000) /* R/WC */ -#define INT_STS_RXD_INT_ (0x00100000) /* R/WC */ -#define INT_STS_GPT_INT_ (0x00080000) /* R/WC */ -#define INT_STS_PHY_INT_ (0x00040000) /* RO */ -#define INT_STS_PME_INT_ (0x00020000) /* R/WC */ -#define INT_STS_TXSO_ (0x00010000) /* R/WC */ -#define INT_STS_RWT_ (0x00008000) /* R/WC */ -#define INT_STS_RXE_ (0x00004000) /* R/WC */ -#define INT_STS_TXE_ (0x00002000) /* R/WC */ -//#define INT_STS_ERX_ (0x00001000) /* R/WC */ -#define INT_STS_TDFU_ (0x00000800) /* R/WC */ -#define INT_STS_TDFO_ (0x00000400) /* R/WC */ -#define INT_STS_TDFA_ (0x00000200) /* R/WC */ -#define INT_STS_TSFF_ (0x00000100) /* R/WC */ -#define INT_STS_TSFL_ (0x00000080) /* R/WC */ -//#define INT_STS_RXDF_ (0x00000040) /* R/WC */ -#define INT_STS_RDFO_ (0x00000040) /* R/WC */ -#define INT_STS_RDFL_ (0x00000020) /* R/WC */ -#define INT_STS_RSFF_ (0x00000010) /* R/WC */ -#define INT_STS_RSFL_ (0x00000008) /* R/WC */ -#define INT_STS_GPIO2_INT_ (0x00000004) /* R/WC */ -#define INT_STS_GPIO1_INT_ (0x00000002) /* R/WC */ -#define INT_STS_GPIO0_INT_ (0x00000001) /* R/WC */ - -#define INT_EN (0x5C) -#define INT_EN_SW_INT_EN_ (0x80000000) /* R/W */ -#define INT_EN_TXSTOP_INT_EN_ (0x02000000) /* R/W */ -#define INT_EN_RXSTOP_INT_EN_ (0x01000000) /* R/W */ -#define INT_EN_RXDFH_INT_EN_ (0x00800000) /* R/W */ -//#define INT_EN_RXDF_INT_EN_ (0x00400000) /* R/W */ -#define INT_EN_TIOC_INT_EN_ (0x00200000) /* R/W */ -#define INT_EN_RXD_INT_EN_ (0x00100000) /* R/W */ -#define INT_EN_GPT_INT_EN_ (0x00080000) /* R/W */ -#define INT_EN_PHY_INT_EN_ (0x00040000) /* R/W */ -#define INT_EN_PME_INT_EN_ (0x00020000) /* R/W */ -#define INT_EN_TXSO_EN_ (0x00010000) /* R/W */ -#define INT_EN_RWT_EN_ (0x00008000) /* R/W */ -#define INT_EN_RXE_EN_ (0x00004000) /* R/W */ -#define INT_EN_TXE_EN_ (0x00002000) /* R/W */ -//#define INT_EN_ERX_EN_ (0x00001000) /* R/W */ -#define INT_EN_TDFU_EN_ (0x00000800) /* R/W */ -#define INT_EN_TDFO_EN_ (0x00000400) /* R/W */ -#define INT_EN_TDFA_EN_ (0x00000200) /* R/W */ -#define INT_EN_TSFF_EN_ (0x00000100) /* R/W */ -#define INT_EN_TSFL_EN_ (0x00000080) /* R/W */ -//#define INT_EN_RXDF_EN_ (0x00000040) /* R/W */ -#define INT_EN_RDFO_EN_ (0x00000040) /* R/W */ -#define INT_EN_RDFL_EN_ (0x00000020) /* R/W */ -#define INT_EN_RSFF_EN_ (0x00000010) /* R/W */ -#define INT_EN_RSFL_EN_ (0x00000008) /* R/W */ -#define INT_EN_GPIO2_INT_ (0x00000004) /* R/W */ -#define INT_EN_GPIO1_INT_ (0x00000002) /* R/W */ -#define INT_EN_GPIO0_INT_ (0x00000001) /* R/W */ - -#define BYTE_TEST (0x64) -#define FIFO_INT (0x68) -#define FIFO_INT_TX_AVAIL_LEVEL_ (0xFF000000) /* R/W */ -#define FIFO_INT_TX_STS_LEVEL_ (0x00FF0000) /* R/W */ -#define FIFO_INT_RX_AVAIL_LEVEL_ (0x0000FF00) /* R/W */ -#define FIFO_INT_RX_STS_LEVEL_ (0x000000FF) /* R/W */ - -#define RX_CFG (0x6C) -#define RX_CFG_RX_END_ALGN_ (0xC0000000) /* R/W */ -#define RX_CFG_RX_END_ALGN4_ (0x00000000) /* R/W */ -#define RX_CFG_RX_END_ALGN16_ (0x40000000) /* R/W */ -#define RX_CFG_RX_END_ALGN32_ (0x80000000) /* R/W */ -#define RX_CFG_RX_DMA_CNT_ (0x0FFF0000) /* R/W */ -#define RX_CFG_RX_DUMP_ (0x00008000) /* R/W */ -#define RX_CFG_RXDOFF_ (0x00001F00) /* R/W */ -//#define RX_CFG_RXBAD_ (0x00000001) /* R/W */ - -#define TX_CFG (0x70) -//#define TX_CFG_TX_DMA_LVL_ (0xE0000000) /* R/W */ -//#define TX_CFG_TX_DMA_CNT_ (0x0FFF0000) /* R/W Self Clearing */ -#define TX_CFG_TXS_DUMP_ (0x00008000) /* Self Clearing */ -#define TX_CFG_TXD_DUMP_ (0x00004000) /* Self Clearing */ -#define TX_CFG_TXSAO_ (0x00000004) /* R/W */ -#define TX_CFG_TX_ON_ (0x00000002) /* R/W */ -#define TX_CFG_STOP_TX_ (0x00000001) /* Self Clearing */ - -#define HW_CFG (0x74) -#define HW_CFG_TTM_ (0x00200000) /* R/W */ -#define HW_CFG_SF_ (0x00100000) /* R/W */ -#define HW_CFG_TX_FIF_SZ_ (0x000F0000) /* R/W */ -#define HW_CFG_TR_ (0x00003000) /* R/W */ -#define HW_CFG_PHY_CLK_SEL_ (0x00000060) /* R/W */ -#define HW_CFG_PHY_CLK_SEL_INT_PHY_ (0x00000000) /* R/W */ -#define HW_CFG_PHY_CLK_SEL_EXT_PHY_ (0x00000020) /* R/W */ -#define HW_CFG_PHY_CLK_SEL_CLK_DIS_ (0x00000040) /* R/W */ -#define HW_CFG_SMI_SEL_ (0x00000010) /* R/W */ -#define HW_CFG_EXT_PHY_DET_ (0x00000008) /* RO */ -#define HW_CFG_EXT_PHY_EN_ (0x00000004) /* R/W */ -#define HW_CFG_32_16_BIT_MODE_ (0x00000004) /* RO */ -#define HW_CFG_SRST_TO_ (0x00000002) /* RO */ -#define HW_CFG_SRST_ (0x00000001) /* Self Clearing */ - -#define RX_DP_CTRL (0x78) -#define RX_DP_CTRL_RX_FFWD_ (0x80000000) /* R/W */ -#define RX_DP_CTRL_FFWD_BUSY_ (0x80000000) /* RO */ - -#define RX_FIFO_INF (0x7C) -#define RX_FIFO_INF_RXSUSED_ (0x00FF0000) /* RO */ -#define RX_FIFO_INF_RXDUSED_ (0x0000FFFF) /* RO */ - -#define TX_FIFO_INF (0x80) -#define TX_FIFO_INF_TSUSED_ (0x00FF0000) /* RO */ -#define TX_FIFO_INF_TDFREE_ (0x0000FFFF) /* RO */ - -#define PMT_CTRL (0x84) -#define PMT_CTRL_PM_MODE_ (0x00003000) /* Self Clearing */ -#define PMT_CTRL_PHY_RST_ (0x00000400) /* Self Clearing */ -#define PMT_CTRL_WOL_EN_ (0x00000200) /* R/W */ -#define PMT_CTRL_ED_EN_ (0x00000100) /* R/W */ -#define PMT_CTRL_PME_TYPE_ (0x00000040) /* R/W Not Affected by SW Reset */ -#define PMT_CTRL_WUPS_ (0x00000030) /* R/WC */ -#define PMT_CTRL_WUPS_NOWAKE_ (0x00000000) /* R/WC */ -#define PMT_CTRL_WUPS_ED_ (0x00000010) /* R/WC */ -#define PMT_CTRL_WUPS_WOL_ (0x00000020) /* R/WC */ -#define PMT_CTRL_WUPS_MULTI_ (0x00000030) /* R/WC */ -#define PMT_CTRL_PME_IND_ (0x00000008) /* R/W */ -#define PMT_CTRL_PME_POL_ (0x00000004) /* R/W */ -#define PMT_CTRL_PME_EN_ (0x00000002) /* R/W Not Affected by SW Reset */ -#define PMT_CTRL_READY_ (0x00000001) /* RO */ - -#define GPIO_CFG (0x88) -#define GPIO_CFG_LED3_EN_ (0x40000000) /* R/W */ -#define GPIO_CFG_LED2_EN_ (0x20000000) /* R/W */ -#define GPIO_CFG_LED1_EN_ (0x10000000) /* R/W */ -#define GPIO_CFG_GPIO2_INT_POL_ (0x04000000) /* R/W */ -#define GPIO_CFG_GPIO1_INT_POL_ (0x02000000) /* R/W */ -#define GPIO_CFG_GPIO0_INT_POL_ (0x01000000) /* R/W */ -#define GPIO_CFG_EEPR_EN_ (0x00700000) /* R/W */ -#define GPIO_CFG_GPIOBUF2_ (0x00040000) /* R/W */ -#define GPIO_CFG_GPIOBUF1_ (0x00020000) /* R/W */ -#define GPIO_CFG_GPIOBUF0_ (0x00010000) /* R/W */ -#define GPIO_CFG_GPIODIR2_ (0x00000400) /* R/W */ -#define GPIO_CFG_GPIODIR1_ (0x00000200) /* R/W */ -#define GPIO_CFG_GPIODIR0_ (0x00000100) /* R/W */ -#define GPIO_CFG_GPIOD4_ (0x00000010) /* R/W */ -#define GPIO_CFG_GPIOD3_ (0x00000008) /* R/W */ -#define GPIO_CFG_GPIOD2_ (0x00000004) /* R/W */ -#define GPIO_CFG_GPIOD1_ (0x00000002) /* R/W */ -#define GPIO_CFG_GPIOD0_ (0x00000001) /* R/W */ - -#define GPT_CFG (0x8C) -#define GPT_CFG_TIMER_EN_ (0x20000000) /* R/W */ -#define GPT_CFG_GPT_LOAD_ (0x0000FFFF) /* R/W */ - -#define GPT_CNT (0x90) -#define GPT_CNT_GPT_CNT_ (0x0000FFFF) /* RO */ - -#define ENDIAN (0x98) -#define FREE_RUN (0x9C) -#define RX_DROP (0xA0) -#define MAC_CSR_CMD (0xA4) -#define MAC_CSR_CMD_CSR_BUSY_ (0x80000000) /* Self Clearing */ -#define MAC_CSR_CMD_R_NOT_W_ (0x40000000) /* R/W */ -#define MAC_CSR_CMD_CSR_ADDR_ (0x000000FF) /* R/W */ - -#define MAC_CSR_DATA (0xA8) -#define AFC_CFG (0xAC) -#define AFC_CFG_AFC_HI_ (0x00FF0000) /* R/W */ -#define AFC_CFG_AFC_LO_ (0x0000FF00) /* R/W */ -#define AFC_CFG_BACK_DUR_ (0x000000F0) /* R/W */ -#define AFC_CFG_FCMULT_ (0x00000008) /* R/W */ -#define AFC_CFG_FCBRD_ (0x00000004) /* R/W */ -#define AFC_CFG_FCADD_ (0x00000002) /* R/W */ -#define AFC_CFG_FCANY_ (0x00000001) /* R/W */ - -#define E2P_CMD (0xB0) -#define E2P_CMD_EPC_BUSY_ (0x80000000) /* Self Clearing */ -#define E2P_CMD_EPC_CMD_ (0x70000000) /* R/W */ -#define E2P_CMD_EPC_CMD_READ_ (0x00000000) /* R/W */ -#define E2P_CMD_EPC_CMD_EWDS_ (0x10000000) /* R/W */ -#define E2P_CMD_EPC_CMD_EWEN_ (0x20000000) /* R/W */ -#define E2P_CMD_EPC_CMD_WRITE_ (0x30000000) /* R/W */ -#define E2P_CMD_EPC_CMD_WRAL_ (0x40000000) /* R/W */ -#define E2P_CMD_EPC_CMD_ERASE_ (0x50000000) /* R/W */ -#define E2P_CMD_EPC_CMD_ERAL_ (0x60000000) /* R/W */ -#define E2P_CMD_EPC_CMD_RELOAD_ (0x70000000) /* R/W */ -#define E2P_CMD_EPC_TIMEOUT_ (0x00000200) /* RO */ -#define E2P_CMD_MAC_ADDR_LOADED_ (0x00000100) /* RO */ -#define E2P_CMD_EPC_ADDR_ (0x000000FF) /* R/W */ - -#define E2P_DATA (0xB4) -#define E2P_DATA_EEPROM_DATA_ (0x000000FF) /* R/W */ -/* end of LAN register offsets and bit definitions */ - -/* - **************************************************************************** - **************************************************************************** - * MAC Control and Status Register (Indirect Address) - * Offset (through the MAC_CSR CMD and DATA port) - **************************************************************************** - **************************************************************************** - * - */ -#define MAC_CR (0x01) /* R/W */ - -/* MAC_CR - MAC Control Register */ -#define MAC_CR_RXALL_ (0x80000000) -// TODO: delete this bit? It is not described in the data sheet. -#define MAC_CR_HBDIS_ (0x10000000) -#define MAC_CR_RCVOWN_ (0x00800000) -#define MAC_CR_LOOPBK_ (0x00200000) -#define MAC_CR_FDPX_ (0x00100000) -#define MAC_CR_MCPAS_ (0x00080000) -#define MAC_CR_PRMS_ (0x00040000) -#define MAC_CR_INVFILT_ (0x00020000) -#define MAC_CR_PASSBAD_ (0x00010000) -#define MAC_CR_HFILT_ (0x00008000) -#define MAC_CR_HPFILT_ (0x00002000) -#define MAC_CR_LCOLL_ (0x00001000) -#define MAC_CR_BCAST_ (0x00000800) -#define MAC_CR_DISRTY_ (0x00000400) -#define MAC_CR_PADSTR_ (0x00000100) -#define MAC_CR_BOLMT_MASK_ (0x000000C0) -#define MAC_CR_DFCHK_ (0x00000020) -#define MAC_CR_TXEN_ (0x00000008) -#define MAC_CR_RXEN_ (0x00000004) - -#define ADDRH (0x02) /* R/W mask 0x0000FFFFUL */ -#define ADDRL (0x03) /* R/W mask 0xFFFFFFFFUL */ -#define HASHH (0x04) /* R/W */ -#define HASHL (0x05) /* R/W */ - -#define MII_ACC (0x06) /* R/W */ -#define MII_ACC_PHY_ADDR_ (0x0000F800) -#define MII_ACC_MIIRINDA_ (0x000007C0) -#define MII_ACC_MII_WRITE_ (0x00000002) -#define MII_ACC_MII_BUSY_ (0x00000001) - -#define MII_DATA (0x07) /* R/W mask 0x0000FFFFUL */ - -#define FLOW (0x08) /* R/W */ -#define FLOW_FCPT_ (0xFFFF0000) -#define FLOW_FCPASS_ (0x00000004) -#define FLOW_FCEN_ (0x00000002) -#define FLOW_FCBSY_ (0x00000001) - -#define VLAN1 (0x09) /* R/W mask 0x0000FFFFUL */ -#define VLAN1_VTI1_ (0x0000ffff) - -#define VLAN2 (0x0A) /* R/W mask 0x0000FFFFUL */ -#define VLAN2_VTI2_ (0x0000ffff) - -#define WUFF (0x0B) /* WO */ - -#define WUCSR (0x0C) /* R/W */ -#define WUCSR_GUE_ (0x00000200) -#define WUCSR_WUFR_ (0x00000040) -#define WUCSR_MPR_ (0x00000020) -#define WUCSR_WAKE_EN_ (0x00000004) -#define WUCSR_MPEN_ (0x00000002) - -/* - **************************************************************************** - * Chip Specific MII Defines - **************************************************************************** - * - * Phy register offsets and bit definitions - * - */ - -#define PHY_MODE_CTRL_STS ((u32)17) /* Mode Control/Status Register */ -//#define MODE_CTRL_STS_FASTRIP_ ((u16)0x4000) -#define MODE_CTRL_STS_EDPWRDOWN_ ((u16)0x2000) -//#define MODE_CTRL_STS_LOWSQEN_ ((u16)0x0800) -//#define MODE_CTRL_STS_MDPREBP_ ((u16)0x0400) -//#define MODE_CTRL_STS_FARLOOPBACK_ ((u16)0x0200) -//#define MODE_CTRL_STS_FASTEST_ ((u16)0x0100) -//#define MODE_CTRL_STS_REFCLKEN_ ((u16)0x0010) -//#define MODE_CTRL_STS_PHYADBP_ ((u16)0x0008) -//#define MODE_CTRL_STS_FORCE_G_LINK_ ((u16)0x0004) -#define MODE_CTRL_STS_ENERGYON_ ((u16)0x0002) - -#define PHY_INT_SRC ((u32)29) -#define PHY_INT_SRC_ENERGY_ON_ ((u16)0x0080) -#define PHY_INT_SRC_ANEG_COMP_ ((u16)0x0040) -#define PHY_INT_SRC_REMOTE_FAULT_ ((u16)0x0020) -#define PHY_INT_SRC_LINK_DOWN_ ((u16)0x0010) -#define PHY_INT_SRC_ANEG_LP_ACK_ ((u16)0x0008) -#define PHY_INT_SRC_PAR_DET_FAULT_ ((u16)0x0004) -#define PHY_INT_SRC_ANEG_PGRX_ ((u16)0x0002) - -#define PHY_INT_MASK ((u32)30) -#define PHY_INT_MASK_ENERGY_ON_ ((u16)0x0080) -#define PHY_INT_MASK_ANEG_COMP_ ((u16)0x0040) -#define PHY_INT_MASK_REMOTE_FAULT_ ((u16)0x0020) -#define PHY_INT_MASK_LINK_DOWN_ ((u16)0x0010) -#define PHY_INT_MASK_ANEG_LP_ACK_ ((u16)0x0008) -#define PHY_INT_MASK_PAR_DET_FAULT_ ((u16)0x0004) -#define PHY_INT_MASK_ANEG_PGRX_ ((u16)0x0002) - -#define PHY_SPECIAL ((u32)31) -#define PHY_SPECIAL_ANEG_DONE_ ((u16)0x1000) -#define PHY_SPECIAL_RES_ ((u16)0x0040) -#define PHY_SPECIAL_RES_MASK_ ((u16)0x0FE1) -#define PHY_SPECIAL_SPD_ ((u16)0x001C) -#define PHY_SPECIAL_SPD_10HALF_ ((u16)0x0004) -#define PHY_SPECIAL_SPD_10FULL_ ((u16)0x0014) -#define PHY_SPECIAL_SPD_100HALF_ ((u16)0x0008) -#define PHY_SPECIAL_SPD_100FULL_ ((u16)0x0018) - -#define LAN911X_INTERNAL_PHY_ID (0x0007C000) - -/* Chip ID values */ -#define CHIP_9115 0x0115 -#define CHIP_9116 0x0116 -#define CHIP_9117 0x0117 -#define CHIP_9118 0x0118 -#define CHIP_9211 0x9211 -#define CHIP_9215 0x115A -#define CHIP_9217 0x117A -#define CHIP_9218 0x118A - -struct chip_id { - u16 id; - char *name; -}; - -static const struct chip_id chip_ids[] = { - { CHIP_9115, "LAN9115" }, - { CHIP_9116, "LAN9116" }, - { CHIP_9117, "LAN9117" }, - { CHIP_9118, "LAN9118" }, - { CHIP_9211, "LAN9211" }, - { CHIP_9215, "LAN9215" }, - { CHIP_9217, "LAN9217" }, - { CHIP_9218, "LAN9218" }, - { 0, NULL }, -}; - -#define IS_REV_A(x) ((x & 0xFFFF)==0) - -/* - * Macros to abstract register access according to the data bus - * capabilities. Please use those and not the in/out primitives. - */ -/* FIFO read/write macros */ -#define SMC_PUSH_DATA(lp, p, l) SMC_outsl( lp, TX_DATA_FIFO, p, (l) >> 2 ) -#define SMC_PULL_DATA(lp, p, l) SMC_insl ( lp, RX_DATA_FIFO, p, (l) >> 2 ) -#define SMC_SET_TX_FIFO(lp, x) SMC_outl( x, lp, TX_DATA_FIFO ) -#define SMC_GET_RX_FIFO(lp) SMC_inl( lp, RX_DATA_FIFO ) - - -/* I/O mapped register read/write macros */ -#define SMC_GET_TX_STS_FIFO(lp) SMC_inl( lp, TX_STATUS_FIFO ) -#define SMC_GET_RX_STS_FIFO(lp) SMC_inl( lp, RX_STATUS_FIFO ) -#define SMC_GET_RX_STS_FIFO_PEEK(lp) SMC_inl( lp, RX_STATUS_FIFO_PEEK ) -#define SMC_GET_PN(lp) (SMC_inl( lp, ID_REV ) >> 16) -#define SMC_GET_REV(lp) (SMC_inl( lp, ID_REV ) & 0xFFFF) -#define SMC_GET_IRQ_CFG(lp) SMC_inl( lp, INT_CFG ) -#define SMC_SET_IRQ_CFG(lp, x) SMC_outl( x, lp, INT_CFG ) -#define SMC_GET_INT(lp) SMC_inl( lp, INT_STS ) -#define SMC_ACK_INT(lp, x) SMC_outl( x, lp, INT_STS ) -#define SMC_GET_INT_EN(lp) SMC_inl( lp, INT_EN ) -#define SMC_SET_INT_EN(lp, x) SMC_outl( x, lp, INT_EN ) -#define SMC_GET_BYTE_TEST(lp) SMC_inl( lp, BYTE_TEST ) -#define SMC_SET_BYTE_TEST(lp, x) SMC_outl( x, lp, BYTE_TEST ) -#define SMC_GET_FIFO_INT(lp) SMC_inl( lp, FIFO_INT ) -#define SMC_SET_FIFO_INT(lp, x) SMC_outl( x, lp, FIFO_INT ) -#define SMC_SET_FIFO_TDA(lp, x) \ - do { \ - unsigned long __flags; \ - int __mask; \ - local_irq_save(__flags); \ - __mask = SMC_GET_FIFO_INT((lp)) & ~(0xFF<<24); \ - SMC_SET_FIFO_INT( (lp), __mask | (x)<<24 ); \ - local_irq_restore(__flags); \ - } while (0) -#define SMC_SET_FIFO_TSL(lp, x) \ - do { \ - unsigned long __flags; \ - int __mask; \ - local_irq_save(__flags); \ - __mask = SMC_GET_FIFO_INT((lp)) & ~(0xFF<<16); \ - SMC_SET_FIFO_INT( (lp), __mask | (((x) & 0xFF)<<16)); \ - local_irq_restore(__flags); \ - } while (0) -#define SMC_SET_FIFO_RSA(lp, x) \ - do { \ - unsigned long __flags; \ - int __mask; \ - local_irq_save(__flags); \ - __mask = SMC_GET_FIFO_INT((lp)) & ~(0xFF<<8); \ - SMC_SET_FIFO_INT( (lp), __mask | (((x) & 0xFF)<<8)); \ - local_irq_restore(__flags); \ - } while (0) -#define SMC_SET_FIFO_RSL(lp, x) \ - do { \ - unsigned long __flags; \ - int __mask; \ - local_irq_save(__flags); \ - __mask = SMC_GET_FIFO_INT((lp)) & ~0xFF; \ - SMC_SET_FIFO_INT( (lp),__mask | ((x) & 0xFF)); \ - local_irq_restore(__flags); \ - } while (0) -#define SMC_GET_RX_CFG(lp) SMC_inl( lp, RX_CFG ) -#define SMC_SET_RX_CFG(lp, x) SMC_outl( x, lp, RX_CFG ) -#define SMC_GET_TX_CFG(lp) SMC_inl( lp, TX_CFG ) -#define SMC_SET_TX_CFG(lp, x) SMC_outl( x, lp, TX_CFG ) -#define SMC_GET_HW_CFG(lp) SMC_inl( lp, HW_CFG ) -#define SMC_SET_HW_CFG(lp, x) SMC_outl( x, lp, HW_CFG ) -#define SMC_GET_RX_DP_CTRL(lp) SMC_inl( lp, RX_DP_CTRL ) -#define SMC_SET_RX_DP_CTRL(lp, x) SMC_outl( x, lp, RX_DP_CTRL ) -#define SMC_GET_PMT_CTRL(lp) SMC_inl( lp, PMT_CTRL ) -#define SMC_SET_PMT_CTRL(lp, x) SMC_outl( x, lp, PMT_CTRL ) -#define SMC_GET_GPIO_CFG(lp) SMC_inl( lp, GPIO_CFG ) -#define SMC_SET_GPIO_CFG(lp, x) SMC_outl( x, lp, GPIO_CFG ) -#define SMC_GET_RX_FIFO_INF(lp) SMC_inl( lp, RX_FIFO_INF ) -#define SMC_SET_RX_FIFO_INF(lp, x) SMC_outl( x, lp, RX_FIFO_INF ) -#define SMC_GET_TX_FIFO_INF(lp) SMC_inl( lp, TX_FIFO_INF ) -#define SMC_SET_TX_FIFO_INF(lp, x) SMC_outl( x, lp, TX_FIFO_INF ) -#define SMC_GET_GPT_CFG(lp) SMC_inl( lp, GPT_CFG ) -#define SMC_SET_GPT_CFG(lp, x) SMC_outl( x, lp, GPT_CFG ) -#define SMC_GET_RX_DROP(lp) SMC_inl( lp, RX_DROP ) -#define SMC_SET_RX_DROP(lp, x) SMC_outl( x, lp, RX_DROP ) -#define SMC_GET_MAC_CMD(lp) SMC_inl( lp, MAC_CSR_CMD ) -#define SMC_SET_MAC_CMD(lp, x) SMC_outl( x, lp, MAC_CSR_CMD ) -#define SMC_GET_MAC_DATA(lp) SMC_inl( lp, MAC_CSR_DATA ) -#define SMC_SET_MAC_DATA(lp, x) SMC_outl( x, lp, MAC_CSR_DATA ) -#define SMC_GET_AFC_CFG(lp) SMC_inl( lp, AFC_CFG ) -#define SMC_SET_AFC_CFG(lp, x) SMC_outl( x, lp, AFC_CFG ) -#define SMC_GET_E2P_CMD(lp) SMC_inl( lp, E2P_CMD ) -#define SMC_SET_E2P_CMD(lp, x) SMC_outl( x, lp, E2P_CMD ) -#define SMC_GET_E2P_DATA(lp) SMC_inl( lp, E2P_DATA ) -#define SMC_SET_E2P_DATA(lp, x) SMC_outl( x, lp, E2P_DATA ) - -/* MAC register read/write macros */ -#define SMC_GET_MAC_CSR(lp,a,v) \ - do { \ - while (SMC_GET_MAC_CMD((lp)) & MAC_CSR_CMD_CSR_BUSY_); \ - SMC_SET_MAC_CMD((lp),MAC_CSR_CMD_CSR_BUSY_ | \ - MAC_CSR_CMD_R_NOT_W_ | (a) ); \ - while (SMC_GET_MAC_CMD((lp)) & MAC_CSR_CMD_CSR_BUSY_); \ - v = SMC_GET_MAC_DATA((lp)); \ - } while (0) -#define SMC_SET_MAC_CSR(lp,a,v) \ - do { \ - while (SMC_GET_MAC_CMD((lp)) & MAC_CSR_CMD_CSR_BUSY_); \ - SMC_SET_MAC_DATA((lp), v); \ - SMC_SET_MAC_CMD((lp), MAC_CSR_CMD_CSR_BUSY_ | (a) ); \ - while (SMC_GET_MAC_CMD((lp)) & MAC_CSR_CMD_CSR_BUSY_); \ - } while (0) -#define SMC_GET_MAC_CR(lp, x) SMC_GET_MAC_CSR( (lp), MAC_CR, x ) -#define SMC_SET_MAC_CR(lp, x) SMC_SET_MAC_CSR( (lp), MAC_CR, x ) -#define SMC_GET_ADDRH(lp, x) SMC_GET_MAC_CSR( (lp), ADDRH, x ) -#define SMC_SET_ADDRH(lp, x) SMC_SET_MAC_CSR( (lp), ADDRH, x ) -#define SMC_GET_ADDRL(lp, x) SMC_GET_MAC_CSR( (lp), ADDRL, x ) -#define SMC_SET_ADDRL(lp, x) SMC_SET_MAC_CSR( (lp), ADDRL, x ) -#define SMC_GET_HASHH(lp, x) SMC_GET_MAC_CSR( (lp), HASHH, x ) -#define SMC_SET_HASHH(lp, x) SMC_SET_MAC_CSR( (lp), HASHH, x ) -#define SMC_GET_HASHL(lp, x) SMC_GET_MAC_CSR( (lp), HASHL, x ) -#define SMC_SET_HASHL(lp, x) SMC_SET_MAC_CSR( (lp), HASHL, x ) -#define SMC_GET_MII_ACC(lp, x) SMC_GET_MAC_CSR( (lp), MII_ACC, x ) -#define SMC_SET_MII_ACC(lp, x) SMC_SET_MAC_CSR( (lp), MII_ACC, x ) -#define SMC_GET_MII_DATA(lp, x) SMC_GET_MAC_CSR( (lp), MII_DATA, x ) -#define SMC_SET_MII_DATA(lp, x) SMC_SET_MAC_CSR( (lp), MII_DATA, x ) -#define SMC_GET_FLOW(lp, x) SMC_GET_MAC_CSR( (lp), FLOW, x ) -#define SMC_SET_FLOW(lp, x) SMC_SET_MAC_CSR( (lp), FLOW, x ) -#define SMC_GET_VLAN1(lp, x) SMC_GET_MAC_CSR( (lp), VLAN1, x ) -#define SMC_SET_VLAN1(lp, x) SMC_SET_MAC_CSR( (lp), VLAN1, x ) -#define SMC_GET_VLAN2(lp, x) SMC_GET_MAC_CSR( (lp), VLAN2, x ) -#define SMC_SET_VLAN2(lp, x) SMC_SET_MAC_CSR( (lp), VLAN2, x ) -#define SMC_SET_WUFF(lp, x) SMC_SET_MAC_CSR( (lp), WUFF, x ) -#define SMC_GET_WUCSR(lp, x) SMC_GET_MAC_CSR( (lp), WUCSR, x ) -#define SMC_SET_WUCSR(lp, x) SMC_SET_MAC_CSR( (lp), WUCSR, x ) - -/* PHY register read/write macros */ -#define SMC_GET_MII(lp,a,phy,v) \ - do { \ - u32 __v; \ - do { \ - SMC_GET_MII_ACC((lp), __v); \ - } while ( __v & MII_ACC_MII_BUSY_ ); \ - SMC_SET_MII_ACC( (lp), ((phy)<<11) | ((a)<<6) | \ - MII_ACC_MII_BUSY_); \ - do { \ - SMC_GET_MII_ACC( (lp), __v); \ - } while ( __v & MII_ACC_MII_BUSY_ ); \ - SMC_GET_MII_DATA((lp), v); \ - } while (0) -#define SMC_SET_MII(lp,a,phy,v) \ - do { \ - u32 __v; \ - do { \ - SMC_GET_MII_ACC((lp), __v); \ - } while ( __v & MII_ACC_MII_BUSY_ ); \ - SMC_SET_MII_DATA((lp), v); \ - SMC_SET_MII_ACC( (lp), ((phy)<<11) | ((a)<<6) | \ - MII_ACC_MII_BUSY_ | \ - MII_ACC_MII_WRITE_ ); \ - do { \ - SMC_GET_MII_ACC((lp), __v); \ - } while ( __v & MII_ACC_MII_BUSY_ ); \ - } while (0) -#define SMC_GET_PHY_BMCR(lp,phy,x) SMC_GET_MII( (lp), MII_BMCR, phy, x ) -#define SMC_SET_PHY_BMCR(lp,phy,x) SMC_SET_MII( (lp), MII_BMCR, phy, x ) -#define SMC_GET_PHY_BMSR(lp,phy,x) SMC_GET_MII( (lp), MII_BMSR, phy, x ) -#define SMC_GET_PHY_ID1(lp,phy,x) SMC_GET_MII( (lp), MII_PHYSID1, phy, x ) -#define SMC_GET_PHY_ID2(lp,phy,x) SMC_GET_MII( (lp), MII_PHYSID2, phy, x ) -#define SMC_GET_PHY_MII_ADV(lp,phy,x) SMC_GET_MII( (lp), MII_ADVERTISE, phy, x ) -#define SMC_SET_PHY_MII_ADV(lp,phy,x) SMC_SET_MII( (lp), MII_ADVERTISE, phy, x ) -#define SMC_GET_PHY_MII_LPA(lp,phy,x) SMC_GET_MII( (lp), MII_LPA, phy, x ) -#define SMC_SET_PHY_MII_LPA(lp,phy,x) SMC_SET_MII( (lp), MII_LPA, phy, x ) -#define SMC_GET_PHY_CTRL_STS(lp,phy,x) SMC_GET_MII( (lp), PHY_MODE_CTRL_STS, phy, x ) -#define SMC_SET_PHY_CTRL_STS(lp,phy,x) SMC_SET_MII( (lp), PHY_MODE_CTRL_STS, phy, x ) -#define SMC_GET_PHY_INT_SRC(lp,phy,x) SMC_GET_MII( (lp), PHY_INT_SRC, phy, x ) -#define SMC_SET_PHY_INT_SRC(lp,phy,x) SMC_SET_MII( (lp), PHY_INT_SRC, phy, x ) -#define SMC_GET_PHY_INT_MASK(lp,phy,x) SMC_GET_MII( (lp), PHY_INT_MASK, phy, x ) -#define SMC_SET_PHY_INT_MASK(lp,phy,x) SMC_SET_MII( (lp), PHY_INT_MASK, phy, x ) -#define SMC_GET_PHY_SPECIAL(lp,phy,x) SMC_GET_MII( (lp), PHY_SPECIAL, phy, x ) - - - -/* Misc read/write macros */ - -#ifndef SMC_GET_MAC_ADDR -#define SMC_GET_MAC_ADDR(lp, addr) \ - do { \ - unsigned int __v; \ - \ - SMC_GET_MAC_CSR((lp), ADDRL, __v); \ - addr[0] = __v; addr[1] = __v >> 8; \ - addr[2] = __v >> 16; addr[3] = __v >> 24; \ - SMC_GET_MAC_CSR((lp), ADDRH, __v); \ - addr[4] = __v; addr[5] = __v >> 8; \ - } while (0) -#endif - -#define SMC_SET_MAC_ADDR(lp, addr) \ - do { \ - SMC_SET_MAC_CSR((lp), ADDRL, \ - addr[0] | \ - (addr[1] << 8) | \ - (addr[2] << 16) | \ - (addr[3] << 24)); \ - SMC_SET_MAC_CSR((lp), ADDRH, addr[4]|(addr[5] << 8));\ - } while (0) - - -#define SMC_WRITE_EEPROM_CMD(lp, cmd, addr) \ - do { \ - while (SMC_GET_E2P_CMD((lp)) & MAC_CSR_CMD_CSR_BUSY_); \ - SMC_SET_MAC_CMD((lp), MAC_CSR_CMD_R_NOT_W_ | a ); \ - while (SMC_GET_MAC_CMD((lp)) & MAC_CSR_CMD_CSR_BUSY_); \ - } while (0) - -#endif /* _SMC911X_H_ */ diff --git a/drivers/net/ethernet/socionext/netsec.c b/drivers/net/ethernet/socionext/netsec.c index 2240f6d0b89b..9b46579b5a10 100644 --- a/drivers/net/ethernet/socionext/netsec.c +++ b/drivers/net/ethernet/socionext/netsec.c @@ -1961,11 +1961,13 @@ static int netsec_register_mdio(struct netsec_priv *priv, u32 phy_addr) ret = PTR_ERR(priv->phydev); dev_err(priv->dev, "get_phy_device err(%d)\n", ret); priv->phydev = NULL; + mdiobus_unregister(bus); return -ENODEV; } ret = phy_device_register(priv->phydev); if (ret) { + phy_device_free(priv->phydev); mdiobus_unregister(bus); dev_err(priv->dev, "phy_device_register err(%d)\n", ret); diff --git a/drivers/net/ethernet/socionext/sni_ave.c b/drivers/net/ethernet/socionext/sni_ave.c index 1fa09b49ba7f..c6a6c9ed5365 100644 --- a/drivers/net/ethernet/socionext/sni_ave.c +++ b/drivers/net/ethernet/socionext/sni_ave.c @@ -1229,6 +1229,8 @@ static int ave_init(struct net_device *ndev) phy_support_asym_pause(phydev); + phydev->mac_managed_pm = true; + phy_attached_info(phydev); return 0; @@ -1756,16 +1758,14 @@ static int ave_resume(struct device *dev) ave_global_reset(ndev); + ret = phy_init_hw(ndev->phydev); + if (ret) + return ret; + ave_ethtool_get_wol(ndev, &wol); wol.wolopts = priv->wolopts; __ave_ethtool_set_wol(ndev, &wol); - if (ndev->phydev) { - ret = phy_resume(ndev->phydev); - if (ret) - return ret; - } - if (netif_running(ndev)) { ret = ave_open(ndev); netif_device_attach(ndev); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c index f7269d79a385..6656d76b6766 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c @@ -1243,6 +1243,12 @@ static const struct rk_gmac_ops rk3588_ops = { .set_rgmii_speed = rk3588_set_gmac_speed, .set_rmii_speed = rk3588_set_gmac_speed, .set_clock_selection = rk3588_set_clock_selection, + .regs_valid = true, + .regs = { + 0xfe1b0000, /* gmac0 */ + 0xfe1c0000, /* gmac1 */ + 0x0, /* sentinel */ + }, }; #define RV1108_GRF_GMAC_CON0 0X0900 diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h index 71dad409f78b..ccd49346d3b3 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h @@ -331,9 +331,7 @@ enum power_event { #define MTL_RXQ_DMA_MAP0 0x00000c30 /* queue 0 to 3 */ #define MTL_RXQ_DMA_MAP1 0x00000c34 /* queue 4 to 7 */ -#define MTL_RXQ_DMA_Q04MDMACH_MASK GENMASK(3, 0) -#define MTL_RXQ_DMA_Q04MDMACH(x) ((x) << 0) -#define MTL_RXQ_DMA_QXMDMACH_MASK(x) GENMASK(11 + (8 * ((x) - 1)), 8 * (x)) +#define MTL_RXQ_DMA_QXMDMACH_MASK(x) (0xf << 8 * (x)) #define MTL_RXQ_DMA_QXMDMACH(chan, q) ((chan) << (8 * (q))) #define MTL_CHAN_BASE_ADDR 0x00000d00 diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c index c25bfecb4a2d..513f6ea335a8 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c @@ -214,26 +214,17 @@ static void dwmac4_map_mtl_dma(struct mac_device_info *hw, u32 queue, u32 chan) void __iomem *ioaddr = hw->pcsr; u32 value; - if (queue < 4) + if (queue < 4) { value = readl(ioaddr + MTL_RXQ_DMA_MAP0); - else - value = readl(ioaddr + MTL_RXQ_DMA_MAP1); - - if (queue == 0 || queue == 4) { - value &= ~MTL_RXQ_DMA_Q04MDMACH_MASK; - value |= MTL_RXQ_DMA_Q04MDMACH(chan); - } else if (queue > 4) { - value &= ~MTL_RXQ_DMA_QXMDMACH_MASK(queue - 4); - value |= MTL_RXQ_DMA_QXMDMACH(chan, queue - 4); - } else { value &= ~MTL_RXQ_DMA_QXMDMACH_MASK(queue); value |= MTL_RXQ_DMA_QXMDMACH(chan, queue); - } - - if (queue < 4) writel(value, ioaddr + MTL_RXQ_DMA_MAP0); - else + } else { + value = readl(ioaddr + MTL_RXQ_DMA_MAP1); + value &= ~MTL_RXQ_DMA_QXMDMACH_MASK(queue - 4); + value |= MTL_RXQ_DMA_QXMDMACH(chan, queue - 4); writel(value, ioaddr + MTL_RXQ_DMA_MAP1); + } } static void dwmac4_config_cbs(struct mac_device_info *hw, diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 65c96773c6d2..8273e6a175c8 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -1214,6 +1214,7 @@ static int stmmac_phy_setup(struct stmmac_priv *priv) if (priv->plat->tx_queues_to_use > 1) priv->phylink_config.mac_capabilities &= ~(MAC_10HD | MAC_100HD | MAC_1000HD); + priv->phylink_config.mac_managed_pm = true; phylink = phylink_create(&priv->phylink_config, fwnode, mode, &stmmac_phylink_mac_ops); diff --git a/drivers/net/ethernet/sun/sunhme.c b/drivers/net/ethernet/sun/sunhme.c index 62deed210a95..1c16548415cd 100644 --- a/drivers/net/ethernet/sun/sunhme.c +++ b/drivers/net/ethernet/sun/sunhme.c @@ -1328,7 +1328,7 @@ static int happy_meal_init(struct happy_meal *hp) void __iomem *erxregs = hp->erxregs; void __iomem *bregs = hp->bigmacregs; void __iomem *tregs = hp->tcvregs; - const char *bursts; + const char *bursts = "64"; u32 regtmp, rxcfg; /* If auto-negotiation timer is running, kill it. */ @@ -2896,8 +2896,8 @@ static int happy_meal_pci_probe(struct pci_dev *pdev, hpreg_res = devm_request_region(&pdev->dev, pci_resource_start(pdev, 0), pci_resource_len(pdev, 0), DRV_NAME); - if (IS_ERR(hpreg_res)) { - err = PTR_ERR(hpreg_res); + if (!hpreg_res) { + err = -EBUSY; dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting.\n"); goto err_out_clear_quattro; } diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c index 3cbe4ec46234..7f86068f3ff6 100644 --- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c +++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c @@ -2476,7 +2476,10 @@ static int am65_cpsw_nuss_register_devlink(struct am65_cpsw_common *common) port = am65_common_get_port(common, i); dl_port = &port->devlink_port; - attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL; + if (port->ndev) + attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL; + else + attrs.flavour = DEVLINK_PORT_FLAVOUR_UNUSED; attrs.phys.port_number = port->port_id; attrs.switch_id.id_len = sizeof(resource_size_t); memcpy(attrs.switch_id.id, common->switch_id, attrs.switch_id.id_len); diff --git a/drivers/net/ethernet/wangxun/Kconfig b/drivers/net/ethernet/wangxun/Kconfig index f5d43d8c9629..565fa826b056 100644 --- a/drivers/net/ethernet/wangxun/Kconfig +++ b/drivers/net/ethernet/wangxun/Kconfig @@ -16,6 +16,11 @@ config NET_VENDOR_WANGXUN if NET_VENDOR_WANGXUN +config LIBWX + tristate + help + Common library for Wangxun(R) Ethernet drivers. + config NGBE tristate "Wangxun(R) GbE PCI Express adapters support" depends on PCI @@ -32,6 +37,7 @@ config NGBE config TXGBE tristate "Wangxun(R) 10GbE PCI Express adapters support" depends on PCI + select LIBWX help This driver supports Wangxun(R) 10GbE PCI Express family of adapters. diff --git a/drivers/net/ethernet/wangxun/Makefile b/drivers/net/ethernet/wangxun/Makefile index ac3fb06b233c..ca19311dbe38 100644 --- a/drivers/net/ethernet/wangxun/Makefile +++ b/drivers/net/ethernet/wangxun/Makefile @@ -3,5 +3,6 @@ # Makefile for the Wangxun network device drivers. # +obj-$(CONFIG_LIBWX) += libwx/ obj-$(CONFIG_TXGBE) += txgbe/ obj-$(CONFIG_NGBE) += ngbe/ diff --git a/drivers/net/ethernet/wangxun/libwx/Makefile b/drivers/net/ethernet/wangxun/libwx/Makefile new file mode 100644 index 000000000000..1ed5e23af944 --- /dev/null +++ b/drivers/net/ethernet/wangxun/libwx/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0 +# Copyright (c) 2015 - 2022 Beijing WangXun Technology Co., Ltd. +# + +obj-$(CONFIG_LIBWX) += libwx.o + +libwx-objs := wx_hw.o diff --git a/drivers/net/ethernet/wangxun/libwx/wx_hw.c b/drivers/net/ethernet/wangxun/libwx/wx_hw.c new file mode 100644 index 000000000000..8dbbac862f27 --- /dev/null +++ b/drivers/net/ethernet/wangxun/libwx/wx_hw.c @@ -0,0 +1,475 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2015 - 2022 Beijing WangXun Technology Co., Ltd. */ + +#include <linux/etherdevice.h> +#include <linux/if_ether.h> +#include <linux/iopoll.h> +#include <linux/pci.h> + +#include "wx_type.h" +#include "wx_hw.h" + +static void wx_intr_disable(struct wx_hw *wxhw, u64 qmask) +{ + u32 mask; + + mask = (qmask & 0xFFFFFFFF); + if (mask) + wr32(wxhw, WX_PX_IMS(0), mask); + + if (wxhw->mac.type == wx_mac_sp) { + mask = (qmask >> 32); + if (mask) + wr32(wxhw, WX_PX_IMS(1), mask); + } +} + +/* cmd_addr is used for some special command: + * 1. to be sector address, when implemented erase sector command + * 2. to be flash address when implemented read, write flash address + */ +static int wx_fmgr_cmd_op(struct wx_hw *wxhw, u32 cmd, u32 cmd_addr) +{ + u32 cmd_val = 0, val = 0; + + cmd_val = WX_SPI_CMD_CMD(cmd) | + WX_SPI_CMD_CLK(WX_SPI_CLK_DIV) | + cmd_addr; + wr32(wxhw, WX_SPI_CMD, cmd_val); + + return read_poll_timeout(rd32, val, (val & 0x1), 10, 100000, + false, wxhw, WX_SPI_STATUS); +} + +static int wx_flash_read_dword(struct wx_hw *wxhw, u32 addr, u32 *data) +{ + int ret = 0; + + ret = wx_fmgr_cmd_op(wxhw, WX_SPI_CMD_READ_DWORD, addr); + if (ret < 0) + return ret; + + *data = rd32(wxhw, WX_SPI_DATA); + + return ret; +} + +int wx_check_flash_load(struct wx_hw *hw, u32 check_bit) +{ + u32 reg = 0; + int err = 0; + + /* if there's flash existing */ + if (!(rd32(hw, WX_SPI_STATUS) & + WX_SPI_STATUS_FLASH_BYPASS)) { + /* wait hw load flash done */ + err = read_poll_timeout(rd32, reg, !(reg & check_bit), 20000, 2000000, + false, hw, WX_SPI_ILDR_STATUS); + if (err < 0) + wx_err(hw, "Check flash load timeout.\n"); + } + + return err; +} +EXPORT_SYMBOL(wx_check_flash_load); + +/** + * wx_get_mac_addr - Generic get MAC address + * @wxhw: pointer to hardware structure + * @mac_addr: Adapter MAC address + * + * Reads the adapter's MAC address from first Receive Address Register (RAR0) + * A reset of the adapter must be performed prior to calling this function + * in order for the MAC address to have been loaded from the EEPROM into RAR0 + **/ +void wx_get_mac_addr(struct wx_hw *wxhw, u8 *mac_addr) +{ + u32 rar_high; + u32 rar_low; + u16 i; + + wr32(wxhw, WX_PSR_MAC_SWC_IDX, 0); + rar_high = rd32(wxhw, WX_PSR_MAC_SWC_AD_H); + rar_low = rd32(wxhw, WX_PSR_MAC_SWC_AD_L); + + for (i = 0; i < 2; i++) + mac_addr[i] = (u8)(rar_high >> (1 - i) * 8); + + for (i = 0; i < 4; i++) + mac_addr[i + 2] = (u8)(rar_low >> (3 - i) * 8); +} +EXPORT_SYMBOL(wx_get_mac_addr); + +/** + * wx_set_rar - Set Rx address register + * @wxhw: pointer to hardware structure + * @index: Receive address register to write + * @addr: Address to put into receive address register + * @pools: VMDq "set" or "pool" index + * @enable_addr: set flag that address is active + * + * Puts an ethernet address into a receive address register. + **/ +int wx_set_rar(struct wx_hw *wxhw, u32 index, u8 *addr, u64 pools, + u32 enable_addr) +{ + u32 rar_entries = wxhw->mac.num_rar_entries; + u32 rar_low, rar_high; + + /* Make sure we are using a valid rar index range */ + if (index >= rar_entries) { + wx_err(wxhw, "RAR index %d is out of range.\n", index); + return -EINVAL; + } + + /* select the MAC address */ + wr32(wxhw, WX_PSR_MAC_SWC_IDX, index); + + /* setup VMDq pool mapping */ + wr32(wxhw, WX_PSR_MAC_SWC_VM_L, pools & 0xFFFFFFFF); + if (wxhw->mac.type == wx_mac_sp) + wr32(wxhw, WX_PSR_MAC_SWC_VM_H, pools >> 32); + + /* HW expects these in little endian so we reverse the byte + * order from network order (big endian) to little endian + * + * Some parts put the VMDq setting in the extra RAH bits, + * so save everything except the lower 16 bits that hold part + * of the address and the address valid bit. + */ + rar_low = ((u32)addr[5] | + ((u32)addr[4] << 8) | + ((u32)addr[3] << 16) | + ((u32)addr[2] << 24)); + rar_high = ((u32)addr[1] | + ((u32)addr[0] << 8)); + if (enable_addr != 0) + rar_high |= WX_PSR_MAC_SWC_AD_H_AV; + + wr32(wxhw, WX_PSR_MAC_SWC_AD_L, rar_low); + wr32m(wxhw, WX_PSR_MAC_SWC_AD_H, + (WX_PSR_MAC_SWC_AD_H_AD(~0) | + WX_PSR_MAC_SWC_AD_H_ADTYPE(~0) | + WX_PSR_MAC_SWC_AD_H_AV), + rar_high); + + return 0; +} +EXPORT_SYMBOL(wx_set_rar); + +/** + * wx_clear_rar - Remove Rx address register + * @wxhw: pointer to hardware structure + * @index: Receive address register to write + * + * Clears an ethernet address from a receive address register. + **/ +int wx_clear_rar(struct wx_hw *wxhw, u32 index) +{ + u32 rar_entries = wxhw->mac.num_rar_entries; + + /* Make sure we are using a valid rar index range */ + if (index >= rar_entries) { + wx_err(wxhw, "RAR index %d is out of range.\n", index); + return -EINVAL; + } + + /* Some parts put the VMDq setting in the extra RAH bits, + * so save everything except the lower 16 bits that hold part + * of the address and the address valid bit. + */ + wr32(wxhw, WX_PSR_MAC_SWC_IDX, index); + + wr32(wxhw, WX_PSR_MAC_SWC_VM_L, 0); + wr32(wxhw, WX_PSR_MAC_SWC_VM_H, 0); + + wr32(wxhw, WX_PSR_MAC_SWC_AD_L, 0); + wr32m(wxhw, WX_PSR_MAC_SWC_AD_H, + (WX_PSR_MAC_SWC_AD_H_AD(~0) | + WX_PSR_MAC_SWC_AD_H_ADTYPE(~0) | + WX_PSR_MAC_SWC_AD_H_AV), + 0); + + return 0; +} +EXPORT_SYMBOL(wx_clear_rar); + +/** + * wx_clear_vmdq - Disassociate a VMDq pool index from a rx address + * @wxhw: pointer to hardware struct + * @rar: receive address register index to disassociate + * @vmdq: VMDq pool index to remove from the rar + **/ +static int wx_clear_vmdq(struct wx_hw *wxhw, u32 rar, u32 __maybe_unused vmdq) +{ + u32 rar_entries = wxhw->mac.num_rar_entries; + u32 mpsar_lo, mpsar_hi; + + /* Make sure we are using a valid rar index range */ + if (rar >= rar_entries) { + wx_err(wxhw, "RAR index %d is out of range.\n", rar); + return -EINVAL; + } + + wr32(wxhw, WX_PSR_MAC_SWC_IDX, rar); + mpsar_lo = rd32(wxhw, WX_PSR_MAC_SWC_VM_L); + mpsar_hi = rd32(wxhw, WX_PSR_MAC_SWC_VM_H); + + if (!mpsar_lo && !mpsar_hi) + return 0; + + /* was that the last pool using this rar? */ + if (mpsar_lo == 0 && mpsar_hi == 0 && rar != 0) + wx_clear_rar(wxhw, rar); + + return 0; +} + +/** + * wx_init_uta_tables - Initialize the Unicast Table Array + * @wxhw: pointer to hardware structure + **/ +static void wx_init_uta_tables(struct wx_hw *wxhw) +{ + int i; + + wx_dbg(wxhw, " Clearing UTA\n"); + + for (i = 0; i < 128; i++) + wr32(wxhw, WX_PSR_UC_TBL(i), 0); +} + +/** + * wx_init_rx_addrs - Initializes receive address filters. + * @wxhw: pointer to hardware structure + * + * Places the MAC address in receive address register 0 and clears the rest + * of the receive address registers. Clears the multicast table. Assumes + * the receiver is in reset when the routine is called. + **/ +void wx_init_rx_addrs(struct wx_hw *wxhw) +{ + u32 rar_entries = wxhw->mac.num_rar_entries; + u32 psrctl; + int i; + + /* If the current mac address is valid, assume it is a software override + * to the permanent address. + * Otherwise, use the permanent address from the eeprom. + */ + if (!is_valid_ether_addr(wxhw->mac.addr)) { + /* Get the MAC address from the RAR0 for later reference */ + wx_get_mac_addr(wxhw, wxhw->mac.addr); + wx_dbg(wxhw, "Keeping Current RAR0 Addr = %pM\n", wxhw->mac.addr); + } else { + /* Setup the receive address. */ + wx_dbg(wxhw, "Overriding MAC Address in RAR[0]\n"); + wx_dbg(wxhw, "New MAC Addr = %pM\n", wxhw->mac.addr); + + wx_set_rar(wxhw, 0, wxhw->mac.addr, 0, WX_PSR_MAC_SWC_AD_H_AV); + + if (wxhw->mac.type == wx_mac_sp) { + /* clear VMDq pool/queue selection for RAR 0 */ + wx_clear_vmdq(wxhw, 0, WX_CLEAR_VMDQ_ALL); + } + } + + /* Zero out the other receive addresses. */ + wx_dbg(wxhw, "Clearing RAR[1-%d]\n", rar_entries - 1); + for (i = 1; i < rar_entries; i++) { + wr32(wxhw, WX_PSR_MAC_SWC_IDX, i); + wr32(wxhw, WX_PSR_MAC_SWC_AD_L, 0); + wr32(wxhw, WX_PSR_MAC_SWC_AD_H, 0); + } + + /* Clear the MTA */ + wxhw->addr_ctrl.mta_in_use = 0; + psrctl = rd32(wxhw, WX_PSR_CTL); + psrctl &= ~(WX_PSR_CTL_MO | WX_PSR_CTL_MFE); + psrctl |= wxhw->mac.mc_filter_type << WX_PSR_CTL_MO_SHIFT; + wr32(wxhw, WX_PSR_CTL, psrctl); + wx_dbg(wxhw, " Clearing MTA\n"); + for (i = 0; i < wxhw->mac.mcft_size; i++) + wr32(wxhw, WX_PSR_MC_TBL(i), 0); + + wx_init_uta_tables(wxhw); +} +EXPORT_SYMBOL(wx_init_rx_addrs); + +void wx_disable_rx(struct wx_hw *wxhw) +{ + u32 pfdtxgswc; + u32 rxctrl; + + rxctrl = rd32(wxhw, WX_RDB_PB_CTL); + if (rxctrl & WX_RDB_PB_CTL_RXEN) { + pfdtxgswc = rd32(wxhw, WX_PSR_CTL); + if (pfdtxgswc & WX_PSR_CTL_SW_EN) { + pfdtxgswc &= ~WX_PSR_CTL_SW_EN; + wr32(wxhw, WX_PSR_CTL, pfdtxgswc); + wxhw->mac.set_lben = true; + } else { + wxhw->mac.set_lben = false; + } + rxctrl &= ~WX_RDB_PB_CTL_RXEN; + wr32(wxhw, WX_RDB_PB_CTL, rxctrl); + + if (!(((wxhw->subsystem_device_id & WX_NCSI_MASK) == WX_NCSI_SUP) || + ((wxhw->subsystem_device_id & WX_WOL_MASK) == WX_WOL_SUP))) { + /* disable mac receiver */ + wr32m(wxhw, WX_MAC_RX_CFG, + WX_MAC_RX_CFG_RE, 0); + } + } +} +EXPORT_SYMBOL(wx_disable_rx); + +/** + * wx_disable_pcie_master - Disable PCI-express master access + * @wxhw: pointer to hardware structure + * + * Disables PCI-Express master access and verifies there are no pending + * requests. + **/ +int wx_disable_pcie_master(struct wx_hw *wxhw) +{ + int status = 0; + u32 val; + + /* Always set this bit to ensure any future transactions are blocked */ + pci_clear_master(wxhw->pdev); + + /* Exit if master requests are blocked */ + if (!(rd32(wxhw, WX_PX_TRANSACTION_PENDING))) + return 0; + + /* Poll for master request bit to clear */ + status = read_poll_timeout(rd32, val, !val, 100, WX_PCI_MASTER_DISABLE_TIMEOUT, + false, wxhw, WX_PX_TRANSACTION_PENDING); + if (status < 0) + wx_err(wxhw, "PCIe transaction pending bit did not clear.\n"); + + return status; +} +EXPORT_SYMBOL(wx_disable_pcie_master); + +/** + * wx_stop_adapter - Generic stop Tx/Rx units + * @wxhw: pointer to hardware structure + * + * Sets the adapter_stopped flag within wx_hw struct. Clears interrupts, + * disables transmit and receive units. The adapter_stopped flag is used by + * the shared code and drivers to determine if the adapter is in a stopped + * state and should not touch the hardware. + **/ +int wx_stop_adapter(struct wx_hw *wxhw) +{ + u16 i; + + /* Set the adapter_stopped flag so other driver functions stop touching + * the hardware + */ + wxhw->adapter_stopped = true; + + /* Disable the receive unit */ + wx_disable_rx(wxhw); + + /* Set interrupt mask to stop interrupts from being generated */ + wx_intr_disable(wxhw, WX_INTR_ALL); + + /* Clear any pending interrupts, flush previous writes */ + wr32(wxhw, WX_PX_MISC_IC, 0xffffffff); + wr32(wxhw, WX_BME_CTL, 0x3); + + /* Disable the transmit unit. Each queue must be disabled. */ + for (i = 0; i < wxhw->mac.max_tx_queues; i++) { + wr32m(wxhw, WX_PX_TR_CFG(i), + WX_PX_TR_CFG_SWFLSH | WX_PX_TR_CFG_ENABLE, + WX_PX_TR_CFG_SWFLSH); + } + + /* Disable the receive unit by stopping each queue */ + for (i = 0; i < wxhw->mac.max_rx_queues; i++) { + wr32m(wxhw, WX_PX_RR_CFG(i), + WX_PX_RR_CFG_RR_EN, 0); + } + + /* flush all queues disables */ + WX_WRITE_FLUSH(wxhw); + + /* Prevent the PCI-E bus from hanging by disabling PCI-E master + * access and verify no pending requests + */ + return wx_disable_pcie_master(wxhw); +} +EXPORT_SYMBOL(wx_stop_adapter); + +void wx_reset_misc(struct wx_hw *wxhw) +{ + int i; + + /* receive packets that size > 2048 */ + wr32m(wxhw, WX_MAC_RX_CFG, WX_MAC_RX_CFG_JE, WX_MAC_RX_CFG_JE); + + /* clear counters on read */ + wr32m(wxhw, WX_MMC_CONTROL, + WX_MMC_CONTROL_RSTONRD, WX_MMC_CONTROL_RSTONRD); + + wr32m(wxhw, WX_MAC_RX_FLOW_CTRL, + WX_MAC_RX_FLOW_CTRL_RFE, WX_MAC_RX_FLOW_CTRL_RFE); + + wr32(wxhw, WX_MAC_PKT_FLT, WX_MAC_PKT_FLT_PR); + + wr32m(wxhw, WX_MIS_RST_ST, + WX_MIS_RST_ST_RST_INIT, 0x1E00); + + /* errata 4: initialize mng flex tbl and wakeup flex tbl*/ + wr32(wxhw, WX_PSR_MNG_FLEX_SEL, 0); + for (i = 0; i < 16; i++) { + wr32(wxhw, WX_PSR_MNG_FLEX_DW_L(i), 0); + wr32(wxhw, WX_PSR_MNG_FLEX_DW_H(i), 0); + wr32(wxhw, WX_PSR_MNG_FLEX_MSK(i), 0); + } + wr32(wxhw, WX_PSR_LAN_FLEX_SEL, 0); + for (i = 0; i < 16; i++) { + wr32(wxhw, WX_PSR_LAN_FLEX_DW_L(i), 0); + wr32(wxhw, WX_PSR_LAN_FLEX_DW_H(i), 0); + wr32(wxhw, WX_PSR_LAN_FLEX_MSK(i), 0); + } + + /* set pause frame dst mac addr */ + wr32(wxhw, WX_RDB_PFCMACDAL, 0xC2000001); + wr32(wxhw, WX_RDB_PFCMACDAH, 0x0180); +} +EXPORT_SYMBOL(wx_reset_misc); + +int wx_sw_init(struct wx_hw *wxhw) +{ + struct pci_dev *pdev = wxhw->pdev; + u32 ssid = 0; + int err = 0; + + wxhw->vendor_id = pdev->vendor; + wxhw->device_id = pdev->device; + wxhw->revision_id = pdev->revision; + wxhw->oem_svid = pdev->subsystem_vendor; + wxhw->oem_ssid = pdev->subsystem_device; + wxhw->bus.device = PCI_SLOT(pdev->devfn); + wxhw->bus.func = PCI_FUNC(pdev->devfn); + + if (wxhw->oem_svid == PCI_VENDOR_ID_WANGXUN) { + wxhw->subsystem_vendor_id = pdev->subsystem_vendor; + wxhw->subsystem_device_id = pdev->subsystem_device; + } else { + err = wx_flash_read_dword(wxhw, 0xfffdc, &ssid); + if (!err) + wxhw->subsystem_device_id = swab16((u16)ssid); + + return err; + } + + return 0; +} +EXPORT_SYMBOL(wx_sw_init); + +MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/wangxun/libwx/wx_hw.h b/drivers/net/ethernet/wangxun/libwx/wx_hw.h new file mode 100644 index 000000000000..58a943dc76c1 --- /dev/null +++ b/drivers/net/ethernet/wangxun/libwx/wx_hw.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2015 - 2022 Beijing WangXun Technology Co., Ltd. */ + +#ifndef _WX_HW_H_ +#define _WX_HW_H_ + +int wx_check_flash_load(struct wx_hw *hw, u32 check_bit); +void wx_get_mac_addr(struct wx_hw *wxhw, u8 *mac_addr); +int wx_set_rar(struct wx_hw *wxhw, u32 index, u8 *addr, u64 pools, u32 enable_addr); +int wx_clear_rar(struct wx_hw *wxhw, u32 index); +void wx_init_rx_addrs(struct wx_hw *wxhw); +void wx_disable_rx(struct wx_hw *wxhw); +int wx_disable_pcie_master(struct wx_hw *wxhw); +int wx_stop_adapter(struct wx_hw *wxhw); +void wx_reset_misc(struct wx_hw *wxhw); +int wx_sw_init(struct wx_hw *wxhw); + +#endif /* _WX_HW_H_ */ diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h new file mode 100644 index 000000000000..790497cec603 --- /dev/null +++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h @@ -0,0 +1,237 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2015 - 2022 Beijing WangXun Technology Co., Ltd. */ + +#ifndef _WX_TYPE_H_ +#define _WX_TYPE_H_ + +/* Vendor ID */ +#ifndef PCI_VENDOR_ID_WANGXUN +#define PCI_VENDOR_ID_WANGXUN 0x8088 +#endif + +#define WX_NCSI_SUP 0x8000 +#define WX_NCSI_MASK 0x8000 +#define WX_WOL_SUP 0x4000 +#define WX_WOL_MASK 0x4000 + +/**************** Global Registers ****************************/ +/* chip control Registers */ +#define WX_MIS_PWR 0x10000 +#define WX_MIS_RST 0x1000C +#define WX_MIS_RST_LAN_RST(_i) BIT((_i) + 1) +#define WX_MIS_RST_ST 0x10030 +#define WX_MIS_RST_ST_RST_INI_SHIFT 8 +#define WX_MIS_RST_ST_RST_INIT (0xFF << WX_MIS_RST_ST_RST_INI_SHIFT) + +/* FMGR Registers */ +#define WX_SPI_CMD 0x10104 +#define WX_SPI_CMD_READ_DWORD 0x1 +#define WX_SPI_CLK_DIV 0x3 +#define WX_SPI_CMD_CMD(_v) (((_v) & 0x7) << 28) +#define WX_SPI_CMD_CLK(_v) (((_v) & 0x7) << 25) +#define WX_SPI_CMD_ADDR(_v) (((_v) & 0xFFFFFF)) +#define WX_SPI_DATA 0x10108 +#define WX_SPI_DATA_BYPASS BIT(31) +#define WX_SPI_DATA_STATUS(_v) (((_v) & 0xFF) << 16) +#define WX_SPI_DATA_OP_DONE BIT(0) +#define WX_SPI_STATUS 0x1010C +#define WX_SPI_STATUS_OPDONE BIT(0) +#define WX_SPI_STATUS_FLASH_BYPASS BIT(31) +#define WX_SPI_ILDR_STATUS 0x10120 + +/* Sensors for PVT(Process Voltage Temperature) */ +#define WX_TS_EN 0x10304 +#define WX_TS_EN_ENA BIT(0) +#define WX_TS_ALARM_THRE 0x1030C +#define WX_TS_DALARM_THRE 0x10310 +#define WX_TS_INT_EN 0x10314 +#define WX_TS_INT_EN_DALARM_INT_EN BIT(1) +#define WX_TS_INT_EN_ALARM_INT_EN BIT(0) +#define WX_TS_ALARM_ST 0x10318 +#define WX_TS_ALARM_ST_DALARM BIT(1) +#define WX_TS_ALARM_ST_ALARM BIT(0) + +/*********************** Transmit DMA registers **************************/ +/* transmit global control */ +#define WX_TDM_CTL 0x18000 +/* TDM CTL BIT */ +#define WX_TDM_CTL_TE BIT(0) /* Transmit Enable */ + +/***************************** RDB registers *********************************/ +/* receive packet buffer */ +#define WX_RDB_PB_CTL 0x19000 +#define WX_RDB_PB_CTL_RXEN BIT(31) /* Enable Receiver */ +#define WX_RDB_PB_CTL_DISABLED BIT(0) +/* statistic */ +#define WX_RDB_PFCMACDAL 0x19210 +#define WX_RDB_PFCMACDAH 0x19214 + +/******************************* PSR Registers *******************************/ +/* psr control */ +#define WX_PSR_CTL 0x15000 +/* Header split receive */ +#define WX_PSR_CTL_SW_EN BIT(18) +#define WX_PSR_CTL_RSC_ACK BIT(17) +#define WX_PSR_CTL_RSC_DIS BIT(16) +#define WX_PSR_CTL_PCSD BIT(13) +#define WX_PSR_CTL_IPPCSE BIT(12) +#define WX_PSR_CTL_BAM BIT(10) +#define WX_PSR_CTL_UPE BIT(9) +#define WX_PSR_CTL_MPE BIT(8) +#define WX_PSR_CTL_MFE BIT(7) +#define WX_PSR_CTL_MO_SHIFT 5 +#define WX_PSR_CTL_MO (0x3 << WX_PSR_CTL_MO_SHIFT) +#define WX_PSR_CTL_TPE BIT(4) +/* mcasst/ucast overflow tbl */ +#define WX_PSR_MC_TBL(_i) (0x15200 + ((_i) * 4)) +#define WX_PSR_UC_TBL(_i) (0x15400 + ((_i) * 4)) + +/* Management */ +#define WX_PSR_MNG_FLEX_SEL 0x1582C +#define WX_PSR_MNG_FLEX_DW_L(_i) (0x15A00 + ((_i) * 16)) +#define WX_PSR_MNG_FLEX_DW_H(_i) (0x15A04 + ((_i) * 16)) +#define WX_PSR_MNG_FLEX_MSK(_i) (0x15A08 + ((_i) * 16)) +#define WX_PSR_LAN_FLEX_SEL 0x15B8C +#define WX_PSR_LAN_FLEX_DW_L(_i) (0x15C00 + ((_i) * 16)) +#define WX_PSR_LAN_FLEX_DW_H(_i) (0x15C04 + ((_i) * 16)) +#define WX_PSR_LAN_FLEX_MSK(_i) (0x15C08 + ((_i) * 16)) + +/* mac switcher */ +#define WX_PSR_MAC_SWC_AD_L 0x16200 +#define WX_PSR_MAC_SWC_AD_H 0x16204 +#define WX_PSR_MAC_SWC_AD_H_AD(v) (((v) & 0xFFFF)) +#define WX_PSR_MAC_SWC_AD_H_ADTYPE(v) (((v) & 0x1) << 30) +#define WX_PSR_MAC_SWC_AD_H_AV BIT(31) +#define WX_PSR_MAC_SWC_VM_L 0x16208 +#define WX_PSR_MAC_SWC_VM_H 0x1620C +#define WX_PSR_MAC_SWC_IDX 0x16210 +#define WX_CLEAR_VMDQ_ALL 0xFFFFFFFFU + +/************************************* ETH MAC *****************************/ +#define WX_MAC_TX_CFG 0x11000 +#define WX_MAC_TX_CFG_TE BIT(0) +#define WX_MAC_RX_CFG 0x11004 +#define WX_MAC_RX_CFG_RE BIT(0) +#define WX_MAC_RX_CFG_JE BIT(8) +#define WX_MAC_PKT_FLT 0x11008 +#define WX_MAC_PKT_FLT_PR BIT(0) /* promiscuous mode */ +#define WX_MAC_RX_FLOW_CTRL 0x11090 +#define WX_MAC_RX_FLOW_CTRL_RFE BIT(0) /* receive fc enable */ +#define WX_MMC_CONTROL 0x11800 +#define WX_MMC_CONTROL_RSTONRD BIT(2) /* reset on read */ + +/********************************* BAR registers ***************************/ +/* Interrupt Registers */ +#define WX_BME_CTL 0x12020 +#define WX_PX_MISC_IC 0x100 +#define WX_PX_IMS(_i) (0x140 + (_i) * 4) +#define WX_PX_TRANSACTION_PENDING 0x168 + +/* transmit DMA Registers */ +#define WX_PX_TR_CFG(_i) (0x03010 + ((_i) * 0x40)) +/* Transmit Config masks */ +#define WX_PX_TR_CFG_ENABLE BIT(0) /* Ena specific Tx Queue */ +#define WX_PX_TR_CFG_TR_SIZE_SHIFT 1 /* tx desc number per ring */ +#define WX_PX_TR_CFG_SWFLSH BIT(26) /* Tx Desc. wr-bk flushing */ +#define WX_PX_TR_CFG_WTHRESH_SHIFT 16 /* shift to WTHRESH bits */ +#define WX_PX_TR_CFG_THRE_SHIFT 8 + +/* Receive DMA Registers */ +#define WX_PX_RR_CFG(_i) (0x01010 + ((_i) * 0x40)) +/* PX_RR_CFG bit definitions */ +#define WX_PX_RR_CFG_RR_EN BIT(0) + +/* Number of 80 microseconds we wait for PCI Express master disable */ +#define WX_PCI_MASTER_DISABLE_TIMEOUT 80000 + +/* Bus parameters */ +struct wx_bus_info { + u8 func; + u16 device; +}; + +struct wx_thermal_sensor_data { + s16 temp; + s16 alarm_thresh; + s16 dalarm_thresh; +}; + +enum wx_mac_type { + wx_mac_unknown = 0, + wx_mac_sp, + wx_mac_em +}; + +struct wx_mac_info { + enum wx_mac_type type; + bool set_lben; + u8 addr[ETH_ALEN]; + u8 perm_addr[ETH_ALEN]; + s32 mc_filter_type; + u32 mcft_size; + u32 num_rar_entries; + u32 max_tx_queues; + u32 max_rx_queues; + struct wx_thermal_sensor_data sensor; +}; + +struct wx_addr_filter_info { + u32 num_mc_addrs; + u32 mta_in_use; + bool user_set_promisc; +}; + +struct wx_hw { + u8 __iomem *hw_addr; + struct pci_dev *pdev; + struct wx_bus_info bus; + struct wx_mac_info mac; + struct wx_addr_filter_info addr_ctrl; + u16 device_id; + u16 vendor_id; + u16 subsystem_device_id; + u16 subsystem_vendor_id; + u8 revision_id; + u16 oem_ssid; + u16 oem_svid; + bool adapter_stopped; +}; + +#define WX_INTR_ALL (~0ULL) + +/* register operations */ +#define wr32(a, reg, value) writel((value), ((a)->hw_addr + (reg))) +#define rd32(a, reg) readl((a)->hw_addr + (reg)) + +static inline u32 +rd32m(struct wx_hw *wxhw, u32 reg, u32 mask) +{ + u32 val; + + val = rd32(wxhw, reg); + return val & mask; +} + +static inline void +wr32m(struct wx_hw *wxhw, u32 reg, u32 mask, u32 field) +{ + u32 val; + + val = rd32(wxhw, reg); + val = ((val & ~mask) | (field & mask)); + + wr32(wxhw, reg, val); +} + +/* On some domestic CPU platforms, sometimes IO is not synchronized with + * flushing memory, here use readl() to flush PCI read and write. + */ +#define WX_WRITE_FLUSH(H) rd32(H, WX_MIS_PWR) + +#define wx_err(wxhw, fmt, arg...) \ + dev_err(&(wxhw)->pdev->dev, fmt, ##arg) + +#define wx_dbg(wxhw, fmt, arg...) \ + dev_dbg(&(wxhw)->pdev->dev, fmt, ##arg) + +#endif /* _WX_TYPE_H_ */ diff --git a/drivers/net/ethernet/wangxun/txgbe/Makefile b/drivers/net/ethernet/wangxun/txgbe/Makefile index 431303ca75b4..78484c58b78b 100644 --- a/drivers/net/ethernet/wangxun/txgbe/Makefile +++ b/drivers/net/ethernet/wangxun/txgbe/Makefile @@ -6,4 +6,5 @@ obj-$(CONFIG_TXGBE) += txgbe.o -txgbe-objs := txgbe_main.o +txgbe-objs := txgbe_main.o \ + txgbe_hw.o diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe.h b/drivers/net/ethernet/wangxun/txgbe/txgbe.h index 38ddbde0ed0f..52e350f9a7d9 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe.h +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe.h @@ -4,19 +4,37 @@ #ifndef _TXGBE_H_ #define _TXGBE_H_ -#include "txgbe_type.h" - #define TXGBE_MAX_FDIR_INDICES 63 #define TXGBE_MAX_RX_QUEUES (TXGBE_MAX_FDIR_INDICES + 1) #define TXGBE_MAX_TX_QUEUES (TXGBE_MAX_FDIR_INDICES + 1) +#define TXGBE_SP_MAX_TX_QUEUES 128 +#define TXGBE_SP_MAX_RX_QUEUES 128 +#define TXGBE_SP_RAR_ENTRIES 128 +#define TXGBE_SP_MC_TBL_SIZE 128 + +struct txgbe_mac_addr { + u8 addr[ETH_ALEN]; + u16 state; /* bitmask */ + u64 pools; +}; + +#define TXGBE_MAC_STATE_DEFAULT 0x1 +#define TXGBE_MAC_STATE_MODIFIED 0x2 +#define TXGBE_MAC_STATE_IN_USE 0x4 + /* board specific private data structure */ struct txgbe_adapter { u8 __iomem *io_addr; /* Mainly for iounmap use */ /* OS defined structs */ struct net_device *netdev; struct pci_dev *pdev; + + /* structs defined in txgbe_type.h */ + struct txgbe_hw hw; + u16 msg_enable; + struct txgbe_mac_addr *mac_table; }; extern char txgbe_driver_name[]; diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.c new file mode 100644 index 000000000000..c7c92c0ec561 --- /dev/null +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.c @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2015 - 2022 Beijing WangXun Technology Co., Ltd. */ + +#include <linux/etherdevice.h> +#include <linux/if_ether.h> +#include <linux/string.h> +#include <linux/iopoll.h> +#include <linux/types.h> +#include <linux/pci.h> + +#include "../libwx/wx_type.h" +#include "../libwx/wx_hw.h" +#include "txgbe_type.h" +#include "txgbe_hw.h" +#include "txgbe.h" + +/** + * txgbe_init_thermal_sensor_thresh - Inits thermal sensor thresholds + * @hw: pointer to hardware structure + * + * Inits the thermal sensor thresholds according to the NVM map + * and save off the threshold and location values into mac.thermal_sensor_data + **/ +static void txgbe_init_thermal_sensor_thresh(struct txgbe_hw *hw) +{ + struct wx_hw *wxhw = &hw->wxhw; + struct wx_thermal_sensor_data *data = &wxhw->mac.sensor; + + memset(data, 0, sizeof(struct wx_thermal_sensor_data)); + + /* Only support thermal sensors attached to SP physical port 0 */ + if (wxhw->bus.func) + return; + + wr32(wxhw, TXGBE_TS_CTL, TXGBE_TS_CTL_EVAL_MD); + + wr32(wxhw, WX_TS_INT_EN, + WX_TS_INT_EN_ALARM_INT_EN | WX_TS_INT_EN_DALARM_INT_EN); + wr32(wxhw, WX_TS_EN, WX_TS_EN_ENA); + + data->alarm_thresh = 100; + wr32(wxhw, WX_TS_ALARM_THRE, 677); + data->dalarm_thresh = 90; + wr32(wxhw, WX_TS_DALARM_THRE, 614); +} + +static void txgbe_reset_misc(struct txgbe_hw *hw) +{ + struct wx_hw *wxhw = &hw->wxhw; + + wx_reset_misc(wxhw); + txgbe_init_thermal_sensor_thresh(hw); +} + +/** + * txgbe_reset_hw - Perform hardware reset + * @hw: pointer to hardware structure + * + * Resets the hardware by resetting the transmit and receive units, masks + * and clears all interrupts, perform a PHY reset, and perform a link (MAC) + * reset. + **/ +int txgbe_reset_hw(struct txgbe_hw *hw) +{ + struct wx_hw *wxhw = &hw->wxhw; + u32 reset = 0; + int status; + + /* Call adapter stop to disable tx/rx and clear interrupts */ + status = wx_stop_adapter(wxhw); + if (status != 0) + return status; + + reset = WX_MIS_RST_LAN_RST(wxhw->bus.func); + wr32(wxhw, WX_MIS_RST, reset | rd32(wxhw, WX_MIS_RST)); + + WX_WRITE_FLUSH(wxhw); + usleep_range(10, 100); + + status = wx_check_flash_load(wxhw, TXGBE_SPI_ILDR_STATUS_LAN_SW_RST(wxhw->bus.func)); + if (status != 0) + return status; + + txgbe_reset_misc(hw); + + /* Store the permanent mac address */ + wx_get_mac_addr(wxhw, wxhw->mac.perm_addr); + + /* Store MAC address from RAR0, clear receive address registers, and + * clear the multicast table. Also reset num_rar_entries to 128, + * since we modify this value when programming the SAN MAC address. + */ + wxhw->mac.num_rar_entries = TXGBE_SP_RAR_ENTRIES; + wx_init_rx_addrs(wxhw); + + pci_set_master(wxhw->pdev); + + return 0; +} diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.h new file mode 100644 index 000000000000..155f18ea4b8c --- /dev/null +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2015 - 2022 Beijing WangXun Technology Co., Ltd. */ + +#ifndef _TXGBE_HW_H_ +#define _TXGBE_HW_H_ + +int txgbe_reset_hw(struct txgbe_hw *hw); + +#endif /* _TXGBE_HW_H_ */ diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c index d3b9f73ecba4..adfa4e7d0d52 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c @@ -8,7 +8,12 @@ #include <linux/string.h> #include <linux/aer.h> #include <linux/etherdevice.h> +#include <net/ip.h> +#include "../libwx/wx_type.h" +#include "../libwx/wx_hw.h" +#include "txgbe_type.h" +#include "txgbe_hw.h" #include "txgbe.h" char txgbe_driver_name[] = "txgbe"; @@ -30,6 +35,276 @@ static const struct pci_device_id txgbe_pci_tbl[] = { #define DEFAULT_DEBUG_LEVEL_SHIFT 3 +static void txgbe_check_minimum_link(struct txgbe_adapter *adapter) +{ + struct pci_dev *pdev; + + pdev = adapter->pdev; + pcie_print_link_status(pdev); +} + +/** + * txgbe_enumerate_functions - Get the number of ports this device has + * @adapter: adapter structure + * + * This function enumerates the phsyical functions co-located on a single slot, + * in order to determine how many ports a device has. This is most useful in + * determining the required GT/s of PCIe bandwidth necessary for optimal + * performance. + **/ +static int txgbe_enumerate_functions(struct txgbe_adapter *adapter) +{ + struct pci_dev *entry, *pdev = adapter->pdev; + int physfns = 0; + + list_for_each_entry(entry, &pdev->bus->devices, bus_list) { + /* When the devices on the bus don't all match our device ID, + * we can't reliably determine the correct number of + * functions. This can occur if a function has been direct + * attached to a virtual machine using VT-d. + */ + if (entry->vendor != pdev->vendor || + entry->device != pdev->device) + return -EINVAL; + + physfns++; + } + + return physfns; +} + +static void txgbe_sync_mac_table(struct txgbe_adapter *adapter) +{ + struct txgbe_hw *hw = &adapter->hw; + struct wx_hw *wxhw = &hw->wxhw; + int i; + + for (i = 0; i < wxhw->mac.num_rar_entries; i++) { + if (adapter->mac_table[i].state & TXGBE_MAC_STATE_MODIFIED) { + if (adapter->mac_table[i].state & TXGBE_MAC_STATE_IN_USE) { + wx_set_rar(wxhw, i, + adapter->mac_table[i].addr, + adapter->mac_table[i].pools, + WX_PSR_MAC_SWC_AD_H_AV); + } else { + wx_clear_rar(wxhw, i); + } + adapter->mac_table[i].state &= ~(TXGBE_MAC_STATE_MODIFIED); + } + } +} + +/* this function destroys the first RAR entry */ +static void txgbe_mac_set_default_filter(struct txgbe_adapter *adapter, + u8 *addr) +{ + struct wx_hw *wxhw = &adapter->hw.wxhw; + + memcpy(&adapter->mac_table[0].addr, addr, ETH_ALEN); + adapter->mac_table[0].pools = 1ULL; + adapter->mac_table[0].state = (TXGBE_MAC_STATE_DEFAULT | + TXGBE_MAC_STATE_IN_USE); + wx_set_rar(wxhw, 0, adapter->mac_table[0].addr, + adapter->mac_table[0].pools, + WX_PSR_MAC_SWC_AD_H_AV); +} + +static void txgbe_flush_sw_mac_table(struct txgbe_adapter *adapter) +{ + struct wx_hw *wxhw = &adapter->hw.wxhw; + u32 i; + + for (i = 0; i < wxhw->mac.num_rar_entries; i++) { + adapter->mac_table[i].state |= TXGBE_MAC_STATE_MODIFIED; + adapter->mac_table[i].state &= ~TXGBE_MAC_STATE_IN_USE; + memset(adapter->mac_table[i].addr, 0, ETH_ALEN); + adapter->mac_table[i].pools = 0; + } + txgbe_sync_mac_table(adapter); +} + +static int txgbe_del_mac_filter(struct txgbe_adapter *adapter, u8 *addr, u16 pool) +{ + struct wx_hw *wxhw = &adapter->hw.wxhw; + u32 i; + + if (is_zero_ether_addr(addr)) + return -EINVAL; + + /* search table for addr, if found, set to 0 and sync */ + for (i = 0; i < wxhw->mac.num_rar_entries; i++) { + if (ether_addr_equal(addr, adapter->mac_table[i].addr)) { + if (adapter->mac_table[i].pools & (1ULL << pool)) { + adapter->mac_table[i].state |= TXGBE_MAC_STATE_MODIFIED; + adapter->mac_table[i].state &= ~TXGBE_MAC_STATE_IN_USE; + adapter->mac_table[i].pools &= ~(1ULL << pool); + txgbe_sync_mac_table(adapter); + } + return 0; + } + + if (adapter->mac_table[i].pools != (1 << pool)) + continue; + if (!ether_addr_equal(addr, adapter->mac_table[i].addr)) + continue; + + adapter->mac_table[i].state |= TXGBE_MAC_STATE_MODIFIED; + adapter->mac_table[i].state &= ~TXGBE_MAC_STATE_IN_USE; + memset(adapter->mac_table[i].addr, 0, ETH_ALEN); + adapter->mac_table[i].pools = 0; + txgbe_sync_mac_table(adapter); + return 0; + } + return -ENOMEM; +} + +static void txgbe_reset(struct txgbe_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + struct txgbe_hw *hw = &adapter->hw; + u8 old_addr[ETH_ALEN]; + int err; + + err = txgbe_reset_hw(hw); + if (err != 0) + dev_err(&adapter->pdev->dev, "Hardware Error: %d\n", err); + + /* do not flush user set addresses */ + memcpy(old_addr, &adapter->mac_table[0].addr, netdev->addr_len); + txgbe_flush_sw_mac_table(adapter); + txgbe_mac_set_default_filter(adapter, old_addr); +} + +static void txgbe_disable_device(struct txgbe_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + struct wx_hw *wxhw = &adapter->hw.wxhw; + + wx_disable_pcie_master(wxhw); + /* disable receives */ + wx_disable_rx(wxhw); + + netif_carrier_off(netdev); + netif_tx_disable(netdev); + + if (wxhw->bus.func < 2) + wr32m(wxhw, TXGBE_MIS_PRB_CTL, TXGBE_MIS_PRB_CTL_LAN_UP(wxhw->bus.func), 0); + else + dev_err(&adapter->pdev->dev, + "%s: invalid bus lan id %d\n", + __func__, wxhw->bus.func); + + if (!(((wxhw->subsystem_device_id & WX_NCSI_MASK) == WX_NCSI_SUP) || + ((wxhw->subsystem_device_id & WX_WOL_MASK) == WX_WOL_SUP))) { + /* disable mac transmiter */ + wr32m(wxhw, WX_MAC_TX_CFG, WX_MAC_TX_CFG_TE, 0); + } + + /* Disable the Tx DMA engine */ + wr32m(wxhw, WX_TDM_CTL, WX_TDM_CTL_TE, 0); +} + +static void txgbe_down(struct txgbe_adapter *adapter) +{ + txgbe_disable_device(adapter); + txgbe_reset(adapter); +} + +/** + * txgbe_sw_init - Initialize general software structures (struct txgbe_adapter) + * @adapter: board private structure to initialize + **/ +static int txgbe_sw_init(struct txgbe_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + struct txgbe_hw *hw = &adapter->hw; + struct wx_hw *wxhw = &hw->wxhw; + int err; + + wxhw->hw_addr = adapter->io_addr; + wxhw->pdev = pdev; + + /* PCI config space info */ + err = wx_sw_init(wxhw); + if (err < 0) { + netif_err(adapter, probe, adapter->netdev, + "read of internal subsystem device id failed\n"); + return err; + } + + switch (wxhw->device_id) { + case TXGBE_DEV_ID_SP1000: + case TXGBE_DEV_ID_WX1820: + wxhw->mac.type = wx_mac_sp; + break; + default: + wxhw->mac.type = wx_mac_unknown; + break; + } + + wxhw->mac.num_rar_entries = TXGBE_SP_RAR_ENTRIES; + wxhw->mac.max_tx_queues = TXGBE_SP_MAX_TX_QUEUES; + wxhw->mac.max_rx_queues = TXGBE_SP_MAX_RX_QUEUES; + wxhw->mac.mcft_size = TXGBE_SP_MC_TBL_SIZE; + + adapter->mac_table = kcalloc(wxhw->mac.num_rar_entries, + sizeof(struct txgbe_mac_addr), + GFP_KERNEL); + if (!adapter->mac_table) { + netif_err(adapter, probe, adapter->netdev, + "mac_table allocation failed\n"); + return -ENOMEM; + } + + return 0; +} + +/** + * txgbe_open - Called when a network interface is made active + * @netdev: network interface device structure + * + * Returns 0 on success, negative value on failure + * + * The open entry point is called when a network interface is made + * active by the system (IFF_UP). + **/ +static int txgbe_open(struct net_device *netdev) +{ + return 0; +} + +/** + * txgbe_close_suspend - actions necessary to both suspend and close flows + * @adapter: the private adapter struct + * + * This function should contain the necessary work common to both suspending + * and closing of the device. + */ +static void txgbe_close_suspend(struct txgbe_adapter *adapter) +{ + txgbe_disable_device(adapter); +} + +/** + * txgbe_close - Disables a network interface + * @netdev: network interface device structure + * + * Returns 0, this is not allowed to fail + * + * The close entry point is called when an interface is de-activated + * by the OS. The hardware is still under the drivers control, but + * needs to be disabled. A global MAC reset is issued to stop the + * hardware, and all transmit and receive resources are freed. + **/ +static int txgbe_close(struct net_device *netdev) +{ + struct txgbe_adapter *adapter = netdev_priv(netdev); + + txgbe_down(adapter); + + return 0; +} + static void txgbe_dev_shutdown(struct pci_dev *pdev, bool *enable_wake) { struct txgbe_adapter *adapter = pci_get_drvdata(pdev); @@ -37,6 +312,11 @@ static void txgbe_dev_shutdown(struct pci_dev *pdev, bool *enable_wake) netif_device_detach(netdev); + rtnl_lock(); + if (netif_running(netdev)) + txgbe_close_suspend(adapter); + rtnl_unlock(); + pci_disable_device(pdev); } @@ -52,6 +332,47 @@ static void txgbe_shutdown(struct pci_dev *pdev) } } +static netdev_tx_t txgbe_xmit_frame(struct sk_buff *skb, + struct net_device *netdev) +{ + return NETDEV_TX_OK; +} + +/** + * txgbe_set_mac - Change the Ethernet Address of the NIC + * @netdev: network interface device structure + * @p: pointer to an address structure + * + * Returns 0 on success, negative on failure + **/ +static int txgbe_set_mac(struct net_device *netdev, void *p) +{ + struct txgbe_adapter *adapter = netdev_priv(netdev); + struct wx_hw *wxhw = &adapter->hw.wxhw; + struct sockaddr *addr = p; + int retval; + + retval = eth_prepare_mac_addr_change(netdev, addr); + if (retval) + return retval; + + txgbe_del_mac_filter(adapter, wxhw->mac.addr, 0); + eth_hw_addr_set(netdev, addr->sa_data); + memcpy(wxhw->mac.addr, addr->sa_data, netdev->addr_len); + + txgbe_mac_set_default_filter(adapter, wxhw->mac.addr); + + return 0; +} + +static const struct net_device_ops txgbe_netdev_ops = { + .ndo_open = txgbe_open, + .ndo_stop = txgbe_close, + .ndo_start_xmit = txgbe_xmit_frame, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = txgbe_set_mac, +}; + /** * txgbe_probe - Device Initialization Routine * @pdev: PCI device information struct @@ -67,8 +388,10 @@ static int txgbe_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent) { struct txgbe_adapter *adapter = NULL; + struct txgbe_hw *hw = NULL; + struct wx_hw *wxhw = NULL; struct net_device *netdev; - int err; + int err, expected_gts; err = pci_enable_device_mem(pdev); if (err) @@ -107,6 +430,9 @@ static int txgbe_probe(struct pci_dev *pdev, adapter = netdev_priv(netdev); adapter->netdev = netdev; adapter->pdev = pdev; + hw = &adapter->hw; + wxhw = &hw->wxhw; + adapter->msg_enable = (1 << DEFAULT_DEBUG_LEVEL_SHIFT) - 1; adapter->io_addr = devm_ioremap(&pdev->dev, pci_resource_start(pdev, 0), @@ -116,12 +442,58 @@ static int txgbe_probe(struct pci_dev *pdev, goto err_pci_release_regions; } + netdev->netdev_ops = &txgbe_netdev_ops; + + /* setup the private structure */ + err = txgbe_sw_init(adapter); + if (err) + goto err_free_mac_table; + + /* check if flash load is done after hw power up */ + err = wx_check_flash_load(wxhw, TXGBE_SPI_ILDR_STATUS_PERST); + if (err) + goto err_free_mac_table; + err = wx_check_flash_load(wxhw, TXGBE_SPI_ILDR_STATUS_PWRRST); + if (err) + goto err_free_mac_table; + + err = txgbe_reset_hw(hw); + if (err) { + dev_err(&pdev->dev, "HW Init failed: %d\n", err); + goto err_free_mac_table; + } + netdev->features |= NETIF_F_HIGHDMA; + eth_hw_addr_set(netdev, wxhw->mac.perm_addr); + txgbe_mac_set_default_filter(adapter, wxhw->mac.perm_addr); + + err = register_netdev(netdev); + if (err) + goto err_free_mac_table; + pci_set_drvdata(pdev, adapter); + /* calculate the expected PCIe bandwidth required for optimal + * performance. Note that some older parts will never have enough + * bandwidth due to being older generation PCIe parts. We clamp these + * parts to ensure that no warning is displayed, as this could confuse + * users otherwise. + */ + expected_gts = txgbe_enumerate_functions(adapter) * 10; + + /* don't check link if we failed to enumerate functions */ + if (expected_gts > 0) + txgbe_check_minimum_link(adapter); + else + dev_warn(&pdev->dev, "Failed to enumerate PF devices.\n"); + + netif_info(adapter, probe, netdev, "%pM\n", netdev->dev_addr); + return 0; +err_free_mac_table: + kfree(adapter->mac_table); err_pci_release_regions: pci_disable_pcie_error_reporting(pdev); pci_release_selected_regions(pdev, @@ -142,9 +514,17 @@ err_pci_disable_dev: **/ static void txgbe_remove(struct pci_dev *pdev) { + struct txgbe_adapter *adapter = pci_get_drvdata(pdev); + struct net_device *netdev; + + netdev = adapter->netdev; + unregister_netdev(netdev); + pci_release_selected_regions(pdev, pci_select_bars(pdev, IORESOURCE_MEM)); + kfree(adapter->mac_table); + pci_disable_pcie_error_reporting(pdev); pci_disable_device(pdev); diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h index b2e329f50bae..4082d3b76709 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h @@ -4,15 +4,6 @@ #ifndef _TXGBE_TYPE_H_ #define _TXGBE_TYPE_H_ -#include <linux/types.h> -#include <linux/netdevice.h> - -/************ txgbe_register.h ************/ -/* Vendor ID */ -#ifndef PCI_VENDOR_ID_WANGXUN -#define PCI_VENDOR_ID_WANGXUN 0x8088 -#endif - /* Device IDs */ #define TXGBE_DEV_ID_SP1000 0x1001 #define TXGBE_DEV_ID_WX1820 0x2001 @@ -42,16 +33,28 @@ #define TXGBE_ID_WX1820_MAC_SGMII 0x2060 #define TXGBE_ID_MAC_SGMII 0x60 -#define TXGBE_NCSI_SUP 0x8000 -#define TXGBE_NCSI_MASK 0x8000 -#define TXGBE_WOL_SUP 0x4000 -#define TXGBE_WOL_MASK 0x4000 -#define TXGBE_DEV_MASK 0xf0 - /* Combined interface*/ #define TXGBE_ID_SFI_XAUI 0x50 /* Revision ID */ #define TXGBE_SP_MPW 1 +/**************** SP Registers ****************************/ +/* chip control Registers */ +#define TXGBE_MIS_PRB_CTL 0x10010 +#define TXGBE_MIS_PRB_CTL_LAN_UP(_i) BIT(1 - (_i)) +/* FMGR Registers */ +#define TXGBE_SPI_ILDR_STATUS 0x10120 +#define TXGBE_SPI_ILDR_STATUS_PERST BIT(0) /* PCIE_PERST is done */ +#define TXGBE_SPI_ILDR_STATUS_PWRRST BIT(1) /* Power on reset is done */ +#define TXGBE_SPI_ILDR_STATUS_LAN_SW_RST(_i) BIT((_i) + 9) /* lan soft reset done */ + +/* Sensors for PVT(Process Voltage Temperature) */ +#define TXGBE_TS_CTL 0x10300 +#define TXGBE_TS_CTL_EVAL_MD BIT(31) + +struct txgbe_hw { + struct wx_hw wxhw; +}; + #endif /* _TXGBE_TYPE_H_ */ |