// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) /* Copyright 2024 NXP */ #include #include #include #include #include #include "enetc_pf_common.h" #define ENETC_SI_MAX_RING_NUM 8 static void enetc4_get_port_caps(struct enetc_pf *pf) { struct enetc_hw *hw = &pf->si->hw; u32 val; val = enetc_port_rd(hw, ENETC4_ECAPR1); pf->caps.num_vsi = (val & ECAPR1_NUM_VSI) >> 24; pf->caps.num_msix = ((val & ECAPR1_NUM_MSIX) >> 12) + 1; val = enetc_port_rd(hw, ENETC4_ECAPR2); pf->caps.num_rx_bdr = (val & ECAPR2_NUM_RX_BDR) >> 16; pf->caps.num_tx_bdr = val & ECAPR2_NUM_TX_BDR; val = enetc_port_rd(hw, ENETC4_PMCAPR); pf->caps.half_duplex = (val & PMCAPR_HD) ? 1 : 0; } static void enetc4_pf_set_si_primary_mac(struct enetc_hw *hw, int si, const u8 *addr) { u16 lower = get_unaligned_le16(addr + 4); u32 upper = get_unaligned_le32(addr); if (si != 0) { __raw_writel(upper, hw->port + ENETC4_PSIPMAR0(si)); __raw_writew(lower, hw->port + ENETC4_PSIPMAR1(si)); } else { __raw_writel(upper, hw->port + ENETC4_PMAR0); __raw_writew(lower, hw->port + ENETC4_PMAR1); } } static void enetc4_pf_get_si_primary_mac(struct enetc_hw *hw, int si, u8 *addr) { u32 upper; u16 lower; upper = __raw_readl(hw->port + ENETC4_PSIPMAR0(si)); lower = __raw_readw(hw->port + ENETC4_PSIPMAR1(si)); put_unaligned_le32(upper, addr); put_unaligned_le16(lower, addr + 4); } static const struct enetc_pf_ops enetc4_pf_ops = { .set_si_primary_mac = enetc4_pf_set_si_primary_mac, .get_si_primary_mac = enetc4_pf_get_si_primary_mac, }; static int enetc4_pf_struct_init(struct enetc_si *si) { struct enetc_pf *pf = enetc_si_priv(si); pf->si = si; pf->total_vfs = pci_sriov_get_totalvfs(si->pdev); pf->ops = &enetc4_pf_ops; enetc4_get_port_caps(pf); return 0; } static u32 enetc4_psicfgr0_val_construct(bool is_vf, u32 num_tx_bdr, u32 num_rx_bdr) { u32 val; val = ENETC_PSICFGR0_SET_TXBDR(num_tx_bdr); val |= ENETC_PSICFGR0_SET_RXBDR(num_rx_bdr); val |= ENETC_PSICFGR0_SIVC(ENETC_VLAN_TYPE_C | ENETC_VLAN_TYPE_S); if (is_vf) val |= ENETC_PSICFGR0_VTE | ENETC_PSICFGR0_SIVIE; return val; } static void enetc4_default_rings_allocation(struct enetc_pf *pf) { struct enetc_hw *hw = &pf->si->hw; u32 num_rx_bdr, num_tx_bdr, val; u32 vf_tx_bdr, vf_rx_bdr; int i, rx_rem, tx_rem; if (pf->caps.num_rx_bdr < ENETC_SI_MAX_RING_NUM + pf->caps.num_vsi) num_rx_bdr = pf->caps.num_rx_bdr - pf->caps.num_vsi; else num_rx_bdr = ENETC_SI_MAX_RING_NUM; if (pf->caps.num_tx_bdr < ENETC_SI_MAX_RING_NUM + pf->caps.num_vsi) num_tx_bdr = pf->caps.num_tx_bdr - pf->caps.num_vsi; else num_tx_bdr = ENETC_SI_MAX_RING_NUM; val = enetc4_psicfgr0_val_construct(false, num_tx_bdr, num_rx_bdr); enetc_port_wr(hw, ENETC4_PSICFGR0(0), val); num_rx_bdr = pf->caps.num_rx_bdr - num_rx_bdr; rx_rem = num_rx_bdr % pf->caps.num_vsi; num_rx_bdr = num_rx_bdr / pf->caps.num_vsi; num_tx_bdr = pf->caps.num_tx_bdr - num_tx_bdr; tx_rem = num_tx_bdr % pf->caps.num_vsi; num_tx_bdr = num_tx_bdr / pf->caps.num_vsi; for (i = 0; i < pf->caps.num_vsi; i++) { vf_tx_bdr = (i < tx_rem) ? num_tx_bdr + 1 : num_tx_bdr; vf_rx_bdr = (i < rx_rem) ? num_rx_bdr + 1 : num_rx_bdr; val = enetc4_psicfgr0_val_construct(true, vf_tx_bdr, vf_rx_bdr); enetc_port_wr(hw, ENETC4_PSICFGR0(i + 1), val); } } static void enetc4_allocate_si_rings(struct enetc_pf *pf) { enetc4_default_rings_allocation(pf); } static void enetc4_pf_set_si_vlan_promisc(struct enetc_hw *hw, int si, bool en) { u32 val = enetc_port_rd(hw, ENETC4_PSIPVMR); if (en) val |= BIT(si); else val &= ~BIT(si); enetc_port_wr(hw, ENETC4_PSIPVMR, val); } static void enetc4_set_default_si_vlan_promisc(struct enetc_pf *pf) { struct enetc_hw *hw = &pf->si->hw; int num_si = pf->caps.num_vsi + 1; int i; /* enforce VLAN promiscuous mode for all SIs */ for (i = 0; i < num_si; i++) enetc4_pf_set_si_vlan_promisc(hw, i, true); } /* Allocate the number of MSI-X vectors for per SI. */ static void enetc4_set_si_msix_num(struct enetc_pf *pf) { struct enetc_hw *hw = &pf->si->hw; int i, num_msix, total_si; u32 val; total_si = pf->caps.num_vsi + 1; num_msix = pf->caps.num_msix / total_si + pf->caps.num_msix % total_si - 1; val = num_msix & PSICFGR2_NUM_MSIX; enetc_port_wr(hw, ENETC4_PSICFGR2(0), val); num_msix = pf->caps.num_msix / total_si - 1; val = num_msix & PSICFGR2_NUM_MSIX; for (i = 0; i < pf->caps.num_vsi; i++) enetc_port_wr(hw, ENETC4_PSICFGR2(i + 1), val); } static void enetc4_enable_all_si(struct enetc_pf *pf) { struct enetc_hw *hw = &pf->si->hw; int num_si = pf->caps.num_vsi + 1; u32 si_bitmap = 0; int i; /* Master enable for all SIs */ for (i = 0; i < num_si; i++) si_bitmap |= PMR_SI_EN(i); enetc_port_wr(hw, ENETC4_PMR, si_bitmap); } static void enetc4_configure_port_si(struct enetc_pf *pf) { struct enetc_hw *hw = &pf->si->hw; enetc4_allocate_si_rings(pf); /* Outer VLAN tag will be used for VLAN filtering */ enetc_port_wr(hw, ENETC4_PSIVLANFMR, PSIVLANFMR_VS); enetc4_set_default_si_vlan_promisc(pf); /* Disable SI MAC multicast & unicast promiscuous */ enetc_port_wr(hw, ENETC4_PSIPMMR, 0); enetc4_set_si_msix_num(pf); enetc4_enable_all_si(pf); } static void enetc4_pf_reset_tc_msdu(struct enetc_hw *hw) { u32 val = ENETC_MAC_MAXFRM_SIZE; int tc; val = u32_replace_bits(val, SDU_TYPE_MPDU, PTCTMSDUR_SDU_TYPE); for (tc = 0; tc < ENETC_NUM_TC; tc++) enetc_port_wr(hw, ENETC4_PTCTMSDUR(tc), val); } static void enetc4_set_trx_frame_size(struct enetc_pf *pf) { struct enetc_si *si = pf->si; enetc_port_mac_wr(si, ENETC4_PM_MAXFRM(0), ENETC_SET_MAXFRM(ENETC_MAC_MAXFRM_SIZE)); enetc4_pf_reset_tc_msdu(&si->hw); } static void enetc4_set_rss_key(struct enetc_hw *hw, const u8 *bytes) { int i; for (i = 0; i < ENETC_RSSHASH_KEY_SIZE / 4; i++) enetc_port_wr(hw, ENETC4_PRSSKR(i), ((u32 *)bytes)[i]); } static void enetc4_set_default_rss_key(struct enetc_pf *pf) { u8 hash_key[ENETC_RSSHASH_KEY_SIZE] = {0}; struct enetc_hw *hw = &pf->si->hw; /* set up hash key */ get_random_bytes(hash_key, ENETC_RSSHASH_KEY_SIZE); enetc4_set_rss_key(hw, hash_key); } static void enetc4_enable_trx(struct enetc_pf *pf) { struct enetc_hw *hw = &pf->si->hw; /* Enable port transmit/receive */ enetc_port_wr(hw, ENETC4_POR, 0); } static void enetc4_configure_port(struct enetc_pf *pf) { enetc4_configure_port_si(pf); enetc4_set_trx_frame_size(pf); enetc4_set_default_rss_key(pf); enetc4_enable_trx(pf); } static int enetc4_pf_init(struct enetc_pf *pf) { struct device *dev = &pf->si->pdev->dev; int err; /* Initialize the MAC address for PF and VFs */ err = enetc_setup_mac_addresses(dev->of_node, pf); if (err) { dev_err(dev, "Failed to set MAC addresses\n"); return err; } enetc4_configure_port(pf); return 0; } static const struct net_device_ops enetc4_ndev_ops = { .ndo_open = enetc_open, .ndo_stop = enetc_close, .ndo_start_xmit = enetc_xmit, .ndo_get_stats = enetc_get_stats, .ndo_set_mac_address = enetc_pf_set_mac_addr, }; static struct phylink_pcs * enetc4_pl_mac_select_pcs(struct phylink_config *config, phy_interface_t iface) { struct enetc_pf *pf = phylink_to_enetc_pf(config); return pf->pcs; } static void enetc4_mac_config(struct enetc_pf *pf, unsigned int mode, phy_interface_t phy_mode) { struct enetc_ndev_priv *priv = netdev_priv(pf->si->ndev); struct enetc_si *si = pf->si; u32 val; val = enetc_port_mac_rd(si, ENETC4_PM_IF_MODE(0)); val &= ~(PM_IF_MODE_IFMODE | PM_IF_MODE_ENA); switch (phy_mode) { case PHY_INTERFACE_MODE_RGMII: case PHY_INTERFACE_MODE_RGMII_ID: case PHY_INTERFACE_MODE_RGMII_RXID: case PHY_INTERFACE_MODE_RGMII_TXID: val |= IFMODE_RGMII; /* We need to enable auto-negotiation for the MAC * if its RGMII interface support In-Band status. */ if (phylink_autoneg_inband(mode)) val |= PM_IF_MODE_ENA; break; case PHY_INTERFACE_MODE_RMII: val |= IFMODE_RMII; break; case PHY_INTERFACE_MODE_SGMII: case PHY_INTERFACE_MODE_2500BASEX: val |= IFMODE_SGMII; break; case PHY_INTERFACE_MODE_10GBASER: case PHY_INTERFACE_MODE_XGMII: case PHY_INTERFACE_MODE_USXGMII: val |= IFMODE_XGMII; break; default: dev_err(priv->dev, "Unsupported PHY mode:%d\n", phy_mode); return; } enetc_port_mac_wr(si, ENETC4_PM_IF_MODE(0), val); } static void enetc4_pl_mac_config(struct phylink_config *config, unsigned int mode, const struct phylink_link_state *state) { struct enetc_pf *pf = phylink_to_enetc_pf(config); enetc4_mac_config(pf, mode, state->interface); } static void enetc4_set_port_speed(struct enetc_ndev_priv *priv, int speed) { u32 old_speed = priv->speed; u32 val; if (speed == old_speed) return; val = enetc_port_rd(&priv->si->hw, ENETC4_PCR); val &= ~PCR_PSPEED; switch (speed) { case SPEED_100: case SPEED_1000: case SPEED_2500: case SPEED_10000: val |= (PCR_PSPEED & PCR_PSPEED_VAL(speed)); break; case SPEED_10: default: val |= (PCR_PSPEED & PCR_PSPEED_VAL(SPEED_10)); } priv->speed = speed; enetc_port_wr(&priv->si->hw, ENETC4_PCR, val); } static void enetc4_set_rgmii_mac(struct enetc_pf *pf, int speed, int duplex) { struct enetc_si *si = pf->si; u32 old_val, val; old_val = enetc_port_mac_rd(si, ENETC4_PM_IF_MODE(0)); val = old_val & ~(PM_IF_MODE_ENA | PM_IF_MODE_M10 | PM_IF_MODE_REVMII); switch (speed) { case SPEED_1000: val = u32_replace_bits(val, SSP_1G, PM_IF_MODE_SSP); break; case SPEED_100: val = u32_replace_bits(val, SSP_100M, PM_IF_MODE_SSP); break; case SPEED_10: val = u32_replace_bits(val, SSP_10M, PM_IF_MODE_SSP); } val = u32_replace_bits(val, duplex == DUPLEX_FULL ? 0 : 1, PM_IF_MODE_HD); if (val == old_val) return; enetc_port_mac_wr(si, ENETC4_PM_IF_MODE(0), val); } static void enetc4_set_rmii_mac(struct enetc_pf *pf, int speed, int duplex) { struct enetc_si *si = pf->si; u32 old_val, val; old_val = enetc_port_mac_rd(si, ENETC4_PM_IF_MODE(0)); val = old_val & ~(PM_IF_MODE_ENA | PM_IF_MODE_SSP); switch (speed) { case SPEED_100: val &= ~PM_IF_MODE_M10; break; case SPEED_10: val |= PM_IF_MODE_M10; } val = u32_replace_bits(val, duplex == DUPLEX_FULL ? 0 : 1, PM_IF_MODE_HD); if (val == old_val) return; enetc_port_mac_wr(si, ENETC4_PM_IF_MODE(0), val); } static void enetc4_set_hd_flow_control(struct enetc_pf *pf, bool enable) { struct enetc_si *si = pf->si; u32 old_val, val; if (!pf->caps.half_duplex) return; old_val = enetc_port_mac_rd(si, ENETC4_PM_CMD_CFG(0)); val = u32_replace_bits(old_val, enable ? 1 : 0, PM_CMD_CFG_HD_FCEN); if (val == old_val) return; enetc_port_mac_wr(si, ENETC4_PM_CMD_CFG(0), val); } static void enetc4_set_rx_pause(struct enetc_pf *pf, bool rx_pause) { struct enetc_si *si = pf->si; u32 old_val, val; old_val = enetc_port_mac_rd(si, ENETC4_PM_CMD_CFG(0)); val = u32_replace_bits(old_val, rx_pause ? 0 : 1, PM_CMD_CFG_PAUSE_IGN); if (val == old_val) return; enetc_port_mac_wr(si, ENETC4_PM_CMD_CFG(0), val); } static void enetc4_set_tx_pause(struct enetc_pf *pf, int num_rxbdr, bool tx_pause) { u32 pause_off_thresh = 0, pause_on_thresh = 0; u32 init_quanta = 0, refresh_quanta = 0; struct enetc_hw *hw = &pf->si->hw; u32 rbmr, old_rbmr; int i; for (i = 0; i < num_rxbdr; i++) { old_rbmr = enetc_rxbdr_rd(hw, i, ENETC_RBMR); rbmr = u32_replace_bits(old_rbmr, tx_pause ? 1 : 0, ENETC_RBMR_CM); if (rbmr == old_rbmr) continue; enetc_rxbdr_wr(hw, i, ENETC_RBMR, rbmr); } if (tx_pause) { /* When the port first enters congestion, send a PAUSE request * with the maximum number of quanta. When the port exits * congestion, it will automatically send a PAUSE frame with * zero quanta. */ init_quanta = 0xffff; /* Also, set up the refresh timer to send follow-up PAUSE * frames at half the quanta value, in case the congestion * condition persists. */ refresh_quanta = 0xffff / 2; /* Start emitting PAUSE frames when 3 large frames (or more * smaller frames) have accumulated in the FIFO waiting to be * DMAed to the RX ring. */ pause_on_thresh = 3 * ENETC_MAC_MAXFRM_SIZE; pause_off_thresh = 1 * ENETC_MAC_MAXFRM_SIZE; } enetc_port_mac_wr(pf->si, ENETC4_PM_PAUSE_QUANTA(0), init_quanta); enetc_port_mac_wr(pf->si, ENETC4_PM_PAUSE_THRESH(0), refresh_quanta); enetc_port_wr(hw, ENETC4_PPAUONTR, pause_on_thresh); enetc_port_wr(hw, ENETC4_PPAUOFFTR, pause_off_thresh); } static void enetc4_enable_mac(struct enetc_pf *pf, bool en) { struct enetc_si *si = pf->si; u32 val; val = enetc_port_mac_rd(si, ENETC4_PM_CMD_CFG(0)); val &= ~(PM_CMD_CFG_TX_EN | PM_CMD_CFG_RX_EN); val |= en ? (PM_CMD_CFG_TX_EN | PM_CMD_CFG_RX_EN) : 0; enetc_port_mac_wr(si, ENETC4_PM_CMD_CFG(0), val); } static void enetc4_pl_mac_link_up(struct phylink_config *config, struct phy_device *phy, unsigned int mode, phy_interface_t interface, int speed, int duplex, bool tx_pause, bool rx_pause) { struct enetc_pf *pf = phylink_to_enetc_pf(config); struct enetc_si *si = pf->si; struct enetc_ndev_priv *priv; bool hd_fc = false; priv = netdev_priv(si->ndev); enetc4_set_port_speed(priv, speed); if (!phylink_autoneg_inband(mode) && phy_interface_mode_is_rgmii(interface)) enetc4_set_rgmii_mac(pf, speed, duplex); if (interface == PHY_INTERFACE_MODE_RMII) enetc4_set_rmii_mac(pf, speed, duplex); if (duplex == DUPLEX_FULL) { /* When preemption is enabled, generation of PAUSE frames * must be disabled, as stated in the IEEE 802.3 standard. */ if (priv->active_offloads & ENETC_F_QBU) tx_pause = false; } else { /* DUPLEX_HALF */ if (tx_pause || rx_pause) hd_fc = true; /* As per 802.3 annex 31B, PAUSE frames are only supported * when the link is configured for full duplex operation. */ tx_pause = false; rx_pause = false; } enetc4_set_hd_flow_control(pf, hd_fc); enetc4_set_tx_pause(pf, priv->num_rx_rings, tx_pause); enetc4_set_rx_pause(pf, rx_pause); enetc4_enable_mac(pf, true); } static void enetc4_pl_mac_link_down(struct phylink_config *config, unsigned int mode, phy_interface_t interface) { struct enetc_pf *pf = phylink_to_enetc_pf(config); enetc4_enable_mac(pf, false); } static const struct phylink_mac_ops enetc_pl_mac_ops = { .mac_select_pcs = enetc4_pl_mac_select_pcs, .mac_config = enetc4_pl_mac_config, .mac_link_up = enetc4_pl_mac_link_up, .mac_link_down = enetc4_pl_mac_link_down, }; static void enetc4_pci_remove(void *data) { struct pci_dev *pdev = data; enetc_pci_remove(pdev); } static int enetc4_link_init(struct enetc_ndev_priv *priv, struct device_node *node) { struct enetc_pf *pf = enetc_si_priv(priv->si); struct device *dev = priv->dev; int err; err = of_get_phy_mode(node, &pf->if_mode); if (err) { dev_err(dev, "Failed to get PHY mode\n"); return err; } err = enetc_mdiobus_create(pf, node); if (err) { dev_err(dev, "Failed to create MDIO bus\n"); return err; } err = enetc_phylink_create(priv, node, &enetc_pl_mac_ops); if (err) { dev_err(dev, "Failed to create phylink\n"); goto err_phylink_create; } return 0; err_phylink_create: enetc_mdiobus_destroy(pf); return err; } static void enetc4_link_deinit(struct enetc_ndev_priv *priv) { struct enetc_pf *pf = enetc_si_priv(priv->si); enetc_phylink_destroy(priv); enetc_mdiobus_destroy(pf); } static int enetc4_pf_netdev_create(struct enetc_si *si) { struct device *dev = &si->pdev->dev; struct enetc_ndev_priv *priv; struct net_device *ndev; int err; ndev = alloc_etherdev_mqs(sizeof(struct enetc_ndev_priv), si->num_tx_rings, si->num_rx_rings); if (!ndev) return -ENOMEM; priv = netdev_priv(ndev); priv->ref_clk = devm_clk_get_optional(dev, "ref"); if (IS_ERR(priv->ref_clk)) { dev_err(dev, "Get reference clock failed\n"); err = PTR_ERR(priv->ref_clk); goto err_clk_get; } enetc_pf_netdev_setup(si, ndev, &enetc4_ndev_ops); enetc_init_si_rings_params(priv); err = enetc_configure_si(priv); if (err) { dev_err(dev, "Failed to configure SI\n"); goto err_config_si; } err = enetc_alloc_msix(priv); if (err) { dev_err(dev, "Failed to alloc MSI-X\n"); goto err_alloc_msix; } err = enetc4_link_init(priv, dev->of_node); if (err) goto err_link_init; err = register_netdev(ndev); if (err) { dev_err(dev, "Failed to register netdev\n"); goto err_reg_netdev; } return 0; err_reg_netdev: enetc4_link_deinit(priv); err_link_init: enetc_free_msix(priv); err_alloc_msix: err_config_si: err_clk_get: mutex_destroy(&priv->mm_lock); free_netdev(ndev); return err; } static void enetc4_pf_netdev_destroy(struct enetc_si *si) { struct enetc_ndev_priv *priv = netdev_priv(si->ndev); struct net_device *ndev = si->ndev; unregister_netdev(ndev); enetc_free_msix(priv); free_netdev(ndev); } static int enetc4_pf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct device *dev = &pdev->dev; struct enetc_si *si; struct enetc_pf *pf; int err; err = enetc_pci_probe(pdev, KBUILD_MODNAME, sizeof(*pf)); if (err) return dev_err_probe(dev, err, "PCIe probing failed\n"); err = devm_add_action_or_reset(dev, enetc4_pci_remove, pdev); if (err) return dev_err_probe(dev, err, "Add enetc4_pci_remove() action failed\n"); /* si is the private data. */ si = pci_get_drvdata(pdev); if (!si->hw.port || !si->hw.global) return dev_err_probe(dev, -ENODEV, "Couldn't map PF only space\n"); si->revision = enetc_get_ip_revision(&si->hw); err = enetc_get_driver_data(si); if (err) return dev_err_probe(dev, err, "Could not get VF driver data\n"); err = enetc4_pf_struct_init(si); if (err) return err; pf = enetc_si_priv(si); err = enetc4_pf_init(pf); if (err) return err; enetc_get_si_caps(si); return enetc4_pf_netdev_create(si); } static void enetc4_pf_remove(struct pci_dev *pdev) { struct enetc_si *si = pci_get_drvdata(pdev); enetc4_pf_netdev_destroy(si); } static const struct pci_device_id enetc4_pf_id_table[] = { { PCI_DEVICE(NXP_ENETC_VENDOR_ID, NXP_ENETC_PF_DEV_ID) }, { 0, } /* End of table. */ }; MODULE_DEVICE_TABLE(pci, enetc4_pf_id_table); static struct pci_driver enetc4_pf_driver = { .name = KBUILD_MODNAME, .id_table = enetc4_pf_id_table, .probe = enetc4_pf_probe, .remove = enetc4_pf_remove, }; module_pci_driver(enetc4_pf_driver); MODULE_DESCRIPTION("ENETC4 PF Driver"); MODULE_LICENSE("Dual BSD/GPL");