Skip to content

Commit

Permalink
net: enetc: add preliminary support for i.MX95 ENETC PF
Browse files Browse the repository at this point in the history
The i.MX95 ENETC has been upgraded to revision 4.1, which is different
from the LS1028A ENETC (revision 1.0) except for the SI part. Therefore,
the fsl-enetc driver is incompatible with i.MX95 ENETC PF. So add new
nxp-enetc4 driver to support i.MX95 ENETC PF, and this driver will be
used to support the ENETC PF with major revision 4 for other SoCs in the
future.

Currently, the nxp-enetc4 driver only supports basic transmission feature
for i.MX95 ENETC PF, the more basic and advanced features will be added
in the subsequent patches. In addition, PCS support has not been added
yet, so 10G ENETC (ENETC instance 2) is not supported now.

Signed-off-by: Wei Fang <wei.fang@nxp.com>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Wei Fang authored and David S. Miller committed Nov 4, 2024
1 parent 9e7f211 commit 99100d0
Show file tree
Hide file tree
Showing 14 changed files with 1,113 additions and 28 deletions.
17 changes: 17 additions & 0 deletions drivers/net/ethernet/freescale/enetc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,23 @@ config FSL_ENETC

If compiled as module (M), the module name is fsl-enetc.

config NXP_ENETC4
tristate "ENETC4 PF driver"
depends on PCI_MSI
select MDIO_DEVRES
select FSL_ENETC_CORE
select FSL_ENETC_MDIO
select NXP_ENETC_PF_COMMON
select PHYLINK
select DIMLIB
help
This driver supports NXP ENETC devices with major revision 4. ENETC is
as the NIC functionality in NETC, it supports virtualization/isolation
based on PCIe Single Root IO Virtualization (SR-IOV) and a full range
of TSN standards and NIC offload capabilities.

If compiled as module (M), the module name is nxp-enetc4.

config FSL_ENETC_VF
tristate "ENETC VF driver"
depends on PCI_MSI
Expand Down
3 changes: 3 additions & 0 deletions drivers/net/ethernet/freescale/enetc/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ fsl-enetc-y := enetc_pf.o
fsl-enetc-$(CONFIG_PCI_IOV) += enetc_msg.o
fsl-enetc-$(CONFIG_FSL_ENETC_QOS) += enetc_qos.o

obj-$(CONFIG_NXP_ENETC4) += nxp-enetc4.o
nxp-enetc4-y := enetc4_pf.o

obj-$(CONFIG_FSL_ENETC_VF) += fsl-enetc-vf.o
fsl-enetc-vf-y := enetc_vf.o

Expand Down
86 changes: 77 additions & 9 deletions drivers/net/ethernet/freescale/enetc/enetc.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "enetc.h"
#include <linux/bpf_trace.h>
#include <linux/clk.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/vmalloc.h>
Expand All @@ -21,7 +22,7 @@ void enetc_port_mac_wr(struct enetc_si *si, u32 reg, u32 val)
{
enetc_port_wr(&si->hw, reg, val);
if (si->hw_features & ENETC_SI_F_QBU)
enetc_port_wr(&si->hw, reg + ENETC_PMAC_OFFSET, val);
enetc_port_wr(&si->hw, reg + si->drvdata->pmac_offset, val);
}
EXPORT_SYMBOL_GPL(enetc_port_mac_wr);

Expand Down Expand Up @@ -700,8 +701,9 @@ static void enetc_rx_dim_work(struct work_struct *w)
net_dim_get_rx_moderation(dim->mode, dim->profile_ix);
struct enetc_int_vector *v =
container_of(dim, struct enetc_int_vector, rx_dim);
struct enetc_ndev_priv *priv = netdev_priv(v->rx_ring.ndev);

v->rx_ictt = enetc_usecs_to_cycles(moder.usec);
v->rx_ictt = enetc_usecs_to_cycles(moder.usec, priv->sysclk_freq);
dim->state = DIM_START_MEASURE;
}

Expand Down Expand Up @@ -1736,9 +1738,15 @@ void enetc_get_si_caps(struct enetc_si *si)
si->num_rx_rings = (val >> 16) & 0xff;
si->num_tx_rings = val & 0xff;

val = enetc_rd(hw, ENETC_SIRFSCAPR);
si->num_fs_entries = ENETC_SIRFSCAPR_GET_NUM_RFS(val);
si->num_fs_entries = min(si->num_fs_entries, ENETC_MAX_RFS_SIZE);
val = enetc_rd(hw, ENETC_SIPCAPR0);
if (val & ENETC_SIPCAPR0_RFS) {
val = enetc_rd(hw, ENETC_SIRFSCAPR);
si->num_fs_entries = ENETC_SIRFSCAPR_GET_NUM_RFS(val);
si->num_fs_entries = min(si->num_fs_entries, ENETC_MAX_RFS_SIZE);
} else {
/* ENETC which not supports RFS */
si->num_fs_entries = 0;
}

si->num_rss = 0;
val = enetc_rd(hw, ENETC_SIPCAPR0);
Expand Down Expand Up @@ -2066,7 +2074,10 @@ int enetc_configure_si(struct enetc_ndev_priv *priv)
/* enable SI */
enetc_wr(hw, ENETC_SIMR, ENETC_SIMR_EN);

if (si->num_rss) {
/* TODO: RSS support for i.MX95 will be supported later, and the
* is_enetc_rev1() condition will be removed
*/
if (si->num_rss && is_enetc_rev1(si)) {
err = enetc_setup_default_rss_table(si, priv->num_rx_rings);
if (err)
return err;
Expand All @@ -2090,9 +2101,9 @@ void enetc_init_si_rings_params(struct enetc_ndev_priv *priv)
*/
priv->num_rx_rings = min_t(int, cpus, si->num_rx_rings);
priv->num_tx_rings = si->num_tx_rings;
priv->bdr_int_num = cpus;
priv->bdr_int_num = priv->num_rx_rings;
priv->ic_mode = ENETC_IC_RX_ADAPTIVE | ENETC_IC_TX_MANUAL;
priv->tx_ictt = ENETC_TXIC_TIMETHR;
priv->tx_ictt = enetc_usecs_to_cycles(600, priv->sysclk_freq);
}
EXPORT_SYMBOL_GPL(enetc_init_si_rings_params);

Expand Down Expand Up @@ -2501,10 +2512,14 @@ int enetc_open(struct net_device *ndev)

extended = !!(priv->active_offloads & ENETC_F_RX_TSTAMP);

err = enetc_setup_irqs(priv);
err = clk_prepare_enable(priv->ref_clk);
if (err)
return err;

err = enetc_setup_irqs(priv);
if (err)
goto err_setup_irqs;

err = enetc_phylink_connect(ndev);
if (err)
goto err_phy_connect;
Expand Down Expand Up @@ -2536,6 +2551,8 @@ int enetc_open(struct net_device *ndev)
phylink_disconnect_phy(priv->phylink);
err_phy_connect:
enetc_free_irqs(priv);
err_setup_irqs:
clk_disable_unprepare(priv->ref_clk);

return err;
}
Expand Down Expand Up @@ -2589,6 +2606,7 @@ int enetc_close(struct net_device *ndev)
enetc_assign_tx_resources(priv, NULL);

enetc_free_irqs(priv);
clk_disable_unprepare(priv->ref_clk);

return 0;
}
Expand Down Expand Up @@ -3254,5 +3272,55 @@ void enetc_pci_remove(struct pci_dev *pdev)
}
EXPORT_SYMBOL_GPL(enetc_pci_remove);

static const struct enetc_drvdata enetc_pf_data = {
.sysclk_freq = ENETC_CLK_400M,
.pmac_offset = ENETC_PMAC_OFFSET,
.eth_ops = &enetc_pf_ethtool_ops,
};

static const struct enetc_drvdata enetc4_pf_data = {
.sysclk_freq = ENETC_CLK_333M,
.pmac_offset = ENETC4_PMAC_OFFSET,
.eth_ops = &enetc4_pf_ethtool_ops,
};

static const struct enetc_drvdata enetc_vf_data = {
.sysclk_freq = ENETC_CLK_400M,
.eth_ops = &enetc_vf_ethtool_ops,
};

static const struct enetc_platform_info enetc_info[] = {
{ .revision = ENETC_REV_1_0,
.dev_id = ENETC_DEV_ID_PF,
.data = &enetc_pf_data,
},
{ .revision = ENETC_REV_4_1,
.dev_id = NXP_ENETC_PF_DEV_ID,
.data = &enetc4_pf_data,
},
{ .revision = ENETC_REV_1_0,
.dev_id = ENETC_DEV_ID_VF,
.data = &enetc_vf_data,
},
};

int enetc_get_driver_data(struct enetc_si *si)
{
u16 dev_id = si->pdev->device;
int i;

for (i = 0; i < ARRAY_SIZE(enetc_info); i++) {
if (si->revision == enetc_info[i].revision &&
dev_id == enetc_info[i].dev_id) {
si->drvdata = enetc_info[i].data;

return 0;
}
}

return -ERANGE;
}
EXPORT_SYMBOL_GPL(enetc_get_driver_data);

MODULE_DESCRIPTION("NXP ENETC Ethernet driver");
MODULE_LICENSE("Dual BSD/GPL");
30 changes: 28 additions & 2 deletions drivers/net/ethernet/freescale/enetc/enetc.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <net/xdp.h>

#include "enetc_hw.h"
#include "enetc4_hw.h"

#define ENETC_MAC_MAXFRM_SIZE 9600
#define ENETC_MAX_MTU (ENETC_MAC_MAXFRM_SIZE - \
Expand Down Expand Up @@ -231,6 +232,18 @@ enum enetc_errata {
#define ENETC_SI_F_QBV BIT(1)
#define ENETC_SI_F_QBU BIT(2)

struct enetc_drvdata {
u32 pmac_offset; /* Only valid for PSI which supports 802.1Qbu */
u64 sysclk_freq;
const struct ethtool_ops *eth_ops;
};

struct enetc_platform_info {
u16 revision;
u16 dev_id;
const struct enetc_drvdata *data;
};

/* PCI IEP device data */
struct enetc_si {
struct pci_dev *pdev;
Expand All @@ -246,11 +259,18 @@ struct enetc_si {
int num_fs_entries;
int num_rss; /* number of RSS buckets */
unsigned short pad;
u16 revision;
int hw_features;
const struct enetc_drvdata *drvdata;
};

#define ENETC_SI_ALIGN 32

static inline bool is_enetc_rev1(struct enetc_si *si)
{
return si->pdev->revision == ENETC_REV1;
}

static inline void *enetc_si_priv(const struct enetc_si *si)
{
return (char *)si + ALIGN(sizeof(struct enetc_si), ENETC_SI_ALIGN);
Expand Down Expand Up @@ -302,7 +322,7 @@ struct enetc_cls_rule {
int used;
};

#define ENETC_MAX_BDR_INT 2 /* fixed to max # of available cpus */
#define ENETC_MAX_BDR_INT 6 /* fixed to max # of available cpus */
struct psfp_cap {
u32 max_streamid;
u32 max_psfp_filter;
Expand Down Expand Up @@ -341,7 +361,6 @@ enum enetc_ic_mode {

#define ENETC_RXIC_PKTTHR min_t(u32, 256, ENETC_RX_RING_DEFAULT_SIZE / 2)
#define ENETC_TXIC_PKTTHR min_t(u32, 128, ENETC_TX_RING_DEFAULT_SIZE / 2)
#define ENETC_TXIC_TIMETHR enetc_usecs_to_cycles(600)

struct enetc_ndev_priv {
struct net_device *ndev;
Expand Down Expand Up @@ -389,6 +408,9 @@ struct enetc_ndev_priv {
* and link state updates
*/
struct mutex mm_lock;

struct clk *ref_clk; /* RGMII/RMII reference clock */
u64 sysclk_freq; /* NETC system clock frequency */
};

/* Messaging */
Expand Down Expand Up @@ -418,6 +440,7 @@ void enetc_init_si_rings_params(struct enetc_ndev_priv *priv);
int enetc_alloc_si_resources(struct enetc_ndev_priv *priv);
void enetc_free_si_resources(struct enetc_ndev_priv *priv);
int enetc_configure_si(struct enetc_ndev_priv *priv);
int enetc_get_driver_data(struct enetc_si *si);

int enetc_open(struct net_device *ndev);
int enetc_close(struct net_device *ndev);
Expand All @@ -434,6 +457,9 @@ int enetc_xdp_xmit(struct net_device *ndev, int num_frames,
struct xdp_frame **frames, u32 flags);

/* ethtool */
extern const struct ethtool_ops enetc_pf_ethtool_ops;
extern const struct ethtool_ops enetc4_pf_ethtool_ops;
extern const struct ethtool_ops enetc_vf_ethtool_ops;
void enetc_set_ethtool_ops(struct net_device *ndev);
void enetc_mm_link_state_update(struct enetc_ndev_priv *priv, bool link);
void enetc_mm_commit_preemptible_tcs(struct enetc_ndev_priv *priv);
Expand Down
Loading

0 comments on commit 99100d0

Please sign in to comment.