Commit 95b33c0b authored by Po Liu's avatar Po Liu

enetc: add support tsn capabilities qbv/qci/qbu/cbs

Support Qbv/Qci/Qbu/Credit Base Shaper etc.
This patch using the generic netlink adapt layer driver net/tsn/*
and include/net/tsn.h interface load by user space. The user space
refer the include/uapi/linux/tsn.h.
Signed-off-by: default avatarPo Liu <Po.Liu@nxp.com>
parent fb1919ab
......@@ -60,3 +60,13 @@ config FSL_ENETC_QOS
enable/disable from user space via Qos commands(tc). In the kernel
side, it can be loaded by Qos driver. Currently, it is only support
taprio(802.1Qbv) and Credit Based Shaper(802.1Qbu).
config ENETC_TSN
bool "TSN Support for NXP ENETC driver"
default n
depends on TSN && FSL_ENETC
help
This driver supports TSN on Freescale ENETC driver. Provide
interface to config the tsn capabilities of ENETC. The interface link
to the /net/tsn/* and include/net/tsn.h. User space refer the
include/uapi/linux/tsn.h.
......@@ -6,6 +6,7 @@ obj-$(CONFIG_FSL_ENETC) += fsl-enetc.o
fsl-enetc-y := enetc_pf.o enetc_mdio.o $(common-objs)
fsl-enetc-$(CONFIG_PCI_IOV) += enetc_msg.o
fsl-enetc-$(CONFIG_FSL_ENETC_QOS) += enetc_qos.o
fsl-enetc-$(CONFIG_ENETC_TSN) += enetc_tsn.o
obj-$(CONFIG_FSL_ENETC_VF) += fsl-enetc-vf.o
fsl-enetc-vf-y := enetc_vf.o $(common-objs)
......
......@@ -145,7 +145,8 @@ static int enetc_map_tx_buffs(struct enetc_bdr *tx_ring, struct sk_buff *skb,
do_tstamp = (active_offloads & ENETC_F_TX_TSTAMP) &&
(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP);
tx_swbd->do_tstamp = do_tstamp;
tx_swbd->check_wb = tx_swbd->do_tstamp;
tx_swbd->qbv_en = !!(active_offloads & ENETC_F_QBV);
tx_swbd->check_wb = tx_swbd->do_tstamp || tx_swbd->qbv_en;
if (do_vlan || do_tstamp)
flags |= ENETC_TXBD_FLAGS_EX;
......@@ -342,7 +343,7 @@ static void enetc_tstamp_tx(struct sk_buff *skb, u64 tstamp)
static bool enetc_clean_tx_ring(struct enetc_bdr *tx_ring, int napi_budget)
{
struct net_device *ndev = tx_ring->ndev;
int tx_frm_cnt = 0, tx_byte_cnt = 0;
int tx_frm_cnt = 0, tx_byte_cnt = 0, tx_win_drop = 0;
struct enetc_tx_swbd *tx_swbd;
int i, bds_to_clean;
bool do_tstamp;
......@@ -372,6 +373,10 @@ static bool enetc_clean_tx_ring(struct enetc_bdr *tx_ring, int napi_budget)
&tstamp);
do_tstamp = true;
}
if (tx_swbd->qbv_en &&
txbd->wb.status & ENETC_TXBD_STATS_WIN)
tx_win_drop++;
}
if (likely(tx_swbd->dma))
......@@ -415,6 +420,7 @@ static bool enetc_clean_tx_ring(struct enetc_bdr *tx_ring, int napi_budget)
tx_ring->next_to_clean = i;
tx_ring->stats.packets += tx_frm_cnt;
tx_ring->stats.bytes += tx_byte_cnt;
tx_ring->stats.win_drop += tx_win_drop;
if (unlikely(tx_frm_cnt && netif_carrier_ok(ndev) &&
__netif_subqueue_stopped(ndev, tx_ring->index) &&
......@@ -778,6 +784,9 @@ void enetc_get_si_caps(struct enetc_si *si)
if (val & ENETC_SIPCAPR0_QBV)
si->hw_features |= ENETC_SI_F_QBV;
if (val & ENETC_SIPCAPR0_QBU)
si->hw_features |= ENETC_SI_F_QBU;
}
static int enetc_dma_alloc_bdr(struct enetc_bdr *r, size_t bd_size)
......
......@@ -10,6 +10,7 @@
#include <linux/ethtool.h>
#include <linux/if_vlan.h>
#include <linux/phy.h>
#include <net/tsn.h>
#include "enetc_hw.h"
......@@ -24,6 +25,7 @@ struct enetc_tx_swbd {
u8 is_dma_page:1;
u8 check_wb:1;
u8 do_tstamp:1;
u8 qbv_en:1;
};
#define ENETC_RX_MAXFRM_SIZE ENETC_MAC_MAXFRM_SIZE
......@@ -42,6 +44,7 @@ struct enetc_ring_stats {
unsigned int packets;
unsigned int bytes;
unsigned int rx_alloc_errs;
unsigned int win_drop;
};
#define ENETC_BDR_DEFAULT_SIZE 1024
......@@ -111,6 +114,28 @@ struct enetc_msg_swbd {
int size;
};
#ifdef CONFIG_ENETC_TSN
/* Credit-Based Shaper parameters */
struct cbs {
u8 tc;
bool enable;
u8 bw;
u32 hi_credit;
u32 lo_credit;
u32 idle_slope;
u32 send_slope;
u32 tc_max_sized_frame;
u32 max_interfrence_size;
};
struct enetc_cbs {
u32 port_transmit_rate;
u32 port_max_size_frame;
u8 tc_nums;
struct cbs cbs[0];
};
#endif
#define ENETC_REV1 0x1
enum enetc_errata {
ENETC_ERR_TXCSUM = BIT(0),
......@@ -119,6 +144,7 @@ enum enetc_errata {
};
#define ENETC_SI_F_QBV BIT(0)
#define ENETC_SI_F_QBU BIT(1)
/* PCI IEP device data */
struct enetc_si {
......@@ -136,6 +162,10 @@ struct enetc_si {
int num_rss; /* number of RSS buckets */
unsigned short pad;
int hw_features;
#ifdef CONFIG_ENETC_TSN
struct enetc_cbs *ecbs;
#endif
};
#define ENETC_SI_ALIGN 32
......@@ -177,6 +207,7 @@ enum enetc_active_offloads {
ENETC_F_RX_TSTAMP = BIT(0),
ENETC_F_TX_TSTAMP = BIT(1),
ENETC_F_QBV = BIT(2),
ENETC_F_QBU = BIT(3),
};
struct enetc_ndev_priv {
......@@ -261,3 +292,10 @@ int enetc_setup_tc_cbs(struct net_device *ndev, void *type_data);
#define enetc_sched_speed_set(ndev) (void)0
#define enetc_setup_tc_cbs(ndev, type_data) -EOPNOTSUPP
#endif
#ifdef CONFIG_ENETC_TSN
void enetc_tsn_pf_init(struct net_device *netdev, struct pci_dev *pdev);
void enetc_tsn_pf_deinit(struct net_device *netdev);
#else
#define enetc_tsn_pf_init(netdev, pdev) (void)0
#define enetc_tsn_pf_deinit(netdev) (void)0
#endif
......@@ -183,6 +183,21 @@ static const struct {
{ ENETC_PICDR(3), "ICM DR3 discarded frames" },
};
static const struct {
int reg;
char name[ETH_GSTRING_LEN];
} enetc_pmac_counters[] = {
{ ENETC_PM1_RFRM, "PMAC rx frames" },
{ ENETC_PM1_RPKT, "PMAC rx packets" },
{ ENETC_PM1_RDRP, "PMAC rx dropped packets" },
{ ENETC_PM1_RFRG, "PMAC rx fragment packets" },
{ ENETC_PM1_TFRM, "PMAC tx frames" },
{ ENETC_PM1_TERR, "PMAC tx error frames" },
{ ENETC_PM1_TPKT, "PMAC tx packets" },
{ ENETC_MAC_MERGE_MMFCRXR, "MAC merge fragment rx counter" },
{ ENETC_MAC_MERGE_MMFCTXR, "MAC merge fragment tx counter"},
};
static const char rx_ring_stats[][ETH_GSTRING_LEN] = {
"Rx ring %2d frames",
"Rx ring %2d alloc errors",
......@@ -192,6 +207,10 @@ static const char tx_ring_stats[][ETH_GSTRING_LEN] = {
"Tx ring %2d frames",
};
static const char tx_windrop_stats[][ETH_GSTRING_LEN] = {
"Tx window drop %2d frames",
};
static int enetc_get_sset_count(struct net_device *ndev, int sset)
{
struct enetc_ndev_priv *priv = netdev_priv(ndev);
......@@ -209,6 +228,12 @@ static int enetc_get_sset_count(struct net_device *ndev, int sset)
len += ARRAY_SIZE(enetc_port_counters);
if (priv->active_offloads & ENETC_F_QBU)
len += ARRAY_SIZE(enetc_pmac_counters);
if (priv->active_offloads & ENETC_F_QBV)
len += ARRAY_SIZE(tx_windrop_stats) * priv->num_tx_rings;
return len;
}
......@@ -247,6 +272,28 @@ static void enetc_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
ETH_GSTRING_LEN);
p += ETH_GSTRING_LEN;
}
if (!(priv->active_offloads & ENETC_F_QBU))
break;
for (i = 0; i < ARRAY_SIZE(enetc_pmac_counters); i++) {
strlcpy(p, enetc_pmac_counters[i].name,
ETH_GSTRING_LEN);
p += ETH_GSTRING_LEN;
}
if (!((priv->active_offloads & ENETC_F_QBV)))
break;
for (i = 0; i < priv->num_tx_rings; i++) {
for (j = 0; j < ARRAY_SIZE(tx_windrop_stats); j++) {
snprintf(p, ETH_GSTRING_LEN,
tx_windrop_stats[j],
i);
p += ETH_GSTRING_LEN;
}
}
break;
}
}
......@@ -274,6 +321,18 @@ static void enetc_get_ethtool_stats(struct net_device *ndev,
for (i = 0; i < ARRAY_SIZE(enetc_port_counters); i++)
data[o++] = enetc_port_rd(hw, enetc_port_counters[i].reg);
if (!(priv->active_offloads & ENETC_F_QBU))
return;
for (i = 0; i < ARRAY_SIZE(enetc_pmac_counters); i++)
data[o++] = enetc_port_rd(hw, enetc_pmac_counters[i].reg);
if (!((priv->active_offloads & ENETC_F_QBV)))
return;
for (i = 0; i < priv->num_tx_rings; i++)
data[o++] = priv->tx_ring[i]->stats.win_drop;
}
#define ENETC_RSSHASH_L3 (RXH_L2DA | RXH_VLAN | RXH_L3_PROTO | RXH_IP_SRC | \
......
......@@ -19,6 +19,7 @@
#define ENETC_SICTR1 0x1c
#define ENETC_SIPCAPR0 0x20
#define ENETC_SIPCAPR0_QBV BIT(4)
#define ENETC_SIPCAPR0_QBU BIT(3)
#define ENETC_SIPCAPR0_RSS BIT(8)
#define ENETC_SIPCAPR1 0x24
#define ENETC_SITGTGR 0x30
......@@ -241,10 +242,20 @@ enum enetc_bdr_type {TX, RX};
#define ENETC_PCS_IF_MODE_SGMII_AN 0x0003
#define ENETC_PM0_IF_MODE 0x8300
#define ENETC_PM1_IF_MODE 0x9300
#define ENETC_PMO_IFM_RG BIT(2)
#define ENETC_PM0_IFM_RLP (BIT(5) | BIT(11))
#define ENETC_PM0_IFM_RGAUTO (BIT(15) | ENETC_PMO_IFM_RG | BIT(1))
#define ENETC_PM0_IFM_XGMII BIT(12)
#define ENETC_PSIDCAPR 0x1b08
#define ENETC_PSIDCAPR_MSK GENMASK(15, 0)
#define ENETC_PSFCAPR 0x1b18
#define ENETC_PSFCAPR_MSK GENMASK(15, 0)
#define ENETC_PSGCAPR 0x1b28
#define ENETC_PSGCAPR_GCL_MSK GENMASK(18, 16)
#define ENETC_PSGCAPR_SGIT_MSK GENMASK(15, 0)
#define ENETC_PFMCAPR 0x1b38
#define ENETC_PFMCAPR_MSK GENMASK(15, 0)
/* MAC counters */
#define ENETC_PM0_REOCT 0x8100
......@@ -294,6 +305,15 @@ enum enetc_bdr_type {TX, RX};
#define ENETC_PM0_TSCOL 0x82E0
#define ENETC_PM0_TLCOL 0x82E8
#define ENETC_PM0_TECOL 0x82F0
#define ENETC_PM1_RFRM 0x9120
#define ENETC_PM1_RDRP 0x9158
#define ENETC_PM1_RPKT 0x9160
#define ENETC_PM1_RFRG 0x91B8
#define ENETC_PM1_TFRM 0x9220
#define ENETC_PM1_TERR 0x9238
#define ENETC_PM1_TPKT 0x9260
#define ENETC_MAC_MERGE_MMFCRXR 0x1f14
#define ENETC_MAC_MERGE_MMFCTXR 0x1f18
/* Port counters */
#define ENETC_PICDR(n) (0x0700 + (n) * 8) /* n = [0..3] */
......@@ -452,6 +472,7 @@ union enetc_tx_bd {
#define ENETC_TXBD_FLAGS_CSUM BIT(3)
#define ENETC_TXBD_FLAGS_EX BIT(6)
#define ENETC_TXBD_FLAGS_F BIT(7)
#define ENETC_TXBD_STATS_WIN BIT(7)
static inline void enetc_clear_tx_bd(union enetc_tx_bd *txbd)
{
......@@ -479,6 +500,8 @@ static inline __le16 enetc_txbd_l3_csoff(int start, int hdr_sz, u16 l3_flags)
#define ENETC_TXBD_L4_UDP BIT(5)
#define ENETC_TXBD_L4_TCP BIT(6)
#define enetc_tsn_is_enabled() IS_ENABLED(CONFIG_ENETC_TSN)
union enetc_rx_bd {
struct {
__le64 addr;
......@@ -625,21 +648,307 @@ enum bdcr_cmd_class {
BDCR_CMD_RFS,
BDCR_CMD_PORT_GCL,
BDCR_CMD_RECV_CLASSIFIER,
BDCR_CMD_STREAM_IDENTIFY,
BDCR_CMD_STREAM_FILTER,
BDCR_CMD_STREAM_GCL,
BDCR_CMD_FLOW_METER,
__BDCR_CMD_MAX_LEN,
BDCR_CMD_MAX_LEN = __BDCR_CMD_MAX_LEN - 1,
};
/* class 7, command 0, Stream Identity Entry Configuration */
struct streamid_conf {
__le32 stream_handle; /* init gate value */
__le32 iports;
u8 id_type;
u8 oui[3];
u8 res[3];
u8 en;
};
#define ENETC_CBDR_SID_VID_MASK 0xfff
#define ENETC_CBDR_SID_VIDM BIT(12)
#define ENETC_CBDR_SID_TG_MASK 0xc000
/* streamid_conf address point to this data space */
struct null_streamid_data {
u8 dmac[6];
u16 vid_vidm_tg;
};
struct smac_streamid_data {
u8 smac[6];
u16 vid_vidm_tg;
};
/* class 7, command 1, query config , long format */
/* No need structure define */
#define ENETC_CDBR_SID_ENABLE BIT(7)
/* Stream ID Query Response Data Buffer */
struct streamid_query_resp {
u32 stream_handle;
u32 input_ports;
u8 id_type;
u8 oui[3];
u8 mac[6];
u16 vid_vidm_tg;
u8 res[3];
u8 en;
};
/* class 7, command 2, qeury status count, Stream ID query long format */
struct streamid_stat_query {
u8 res[12];
__le32 input_ports;
};
/* Stream Identity Statistics Query */
struct streamid_stat_query_resp {
u32 psinl;
u32 psinh;
u64 pspi[32];
};
#define ENETC_CBDR_SFI_PRI_MASK 0x7
#define ENETC_CBDR_SFI_PRIM BIT(3)
#define ENETC_CBDR_SFI_BLOV BIT(4)
#define ENETC_CBDR_SFI_BLEN BIT(5)
#define ENETC_CBDR_SFI_MSDUEN BIT(6)
#define ENETC_CBDR_SFI_FMITEN BIT(7)
#define ENETC_CBDR_SFI_ENABLE BIT(7)
/* class 8, command 0, Stream Filter Instance, Short Format */
struct sfi_conf {
__le32 stream_handle;
u8 multi;
u8 res[2];
u8 sthm;
/* Max Service Data Unit or Flow Meter Instance Table index.
* Depending on the value of FLT this represents either Max
* Service Data Unit (max frame size) allowed by the filter
* entry or is an index into the Flow Meter Instance table
* index identifying the policer which will be used to police
* it.
*/
__le16 fm_inst_table_index;
__le16 msdu;
__le16 sg_inst_table_index;
u8 res1[2];
__le32 input_ports;
u8 res2[3];
u8 en;
};
/* class 8, command 1, Stream Filter Instance, write back, short Format */
struct sfi_query {
u32 stream_handle;
u8 multi;
u8 res[2];
u8 sthm;
u16 fm_inst_table_index;
u16 msdu;
u16 sg_inst_table_index;
u8 res1[2];
u32 input_ports;
u8 res2[3];
u8 en;
};
/* class 8, command 2 stream Filter Instance status query short format
* command no need structure define
* Stream Filter Instance Query Statistics Response data
*/
struct sfi_counter_data {
u32 matchl;
u32 matchh;
u32 msdu_dropl;
u32 msdu_droph;
u32 stream_gate_dropl;
u32 stream_gate_droph;
u32 flow_meter_dropl;
u32 flow_meter_droph;
};
#define ENETC_CBDR_SGI_OIPV_MASK 0x7
#define ENETC_CBDR_SGI_OIPV_EN BIT(3)
#define ENETC_CBDR_SGI_CGTST BIT(6)
#define ENETC_CBDR_SGI_OGTST BIT(7)
#define ENETC_CBDR_SGI_CFG_CHG BIT(1)
#define ENETC_CBDR_SGI_CFG_PND BIT(2)
#define ENETC_CBDR_SGI_OEX BIT(4)
#define ENETC_CBDR_SGI_OEXEN BIT(5)
#define ENETC_CBDR_SGI_IRX BIT(6)
#define ENETC_CBDR_SGI_IRXEN BIT(7)
#define ENETC_CBDR_SGI_ACLLEN_MASK 0x3
#define ENETC_CBDR_SGI_OCLLEN_MASK 0xc
#define ENETC_CBDR_SGI_EN BIT(7)
/* class 9, command 0, Stream Gate Instance Table, Short Format
* class 9, command 2, Stream Gate Instance Table entry query write back
* Short Format
*/
struct sgi_table {
u8 res[8];
u8 oipv;
u8 res0[2];
u8 ocgtst;
u8 res1[7];
u8 gset;
u8 oacl_len;
u8 res2[2];
u8 en;
};
#define ENETC_CBDR_SGI_AIPV_MASK 0x7
#define ENETC_CBDR_SGI_AIPV_EN BIT(3)
#define ENETC_CBDR_SGI_AGTST BIT(7)
/* class 9, command 1, Stream Gate Control List, Long Format */
struct sgcl_conf {
u8 aipv;
u8 res[2];
u8 agtst;
u8 res1[4];
union {
struct {
u8 res2[4];
u8 acl_len;
u8 res3[3];
};
u8 cct[8]; /* Config change time */
};
};
/* stream control list class 9 , cmd 1 data buffer */
struct sgcl_data {
u32 btl;
u32 bth;
u32 ct;
u32 cte;
/*struct sgce *sgcl;*/
};
/* class 9, command 2, stream gate instant table enery query, short format
* write back see struct sgi_table. Do not need define.
* class 9, command 3 Stream Gate Control List Query Descriptor - Long Format
* ocl_len or acl_len to be 0, oper or admin would not show in the data space
* true len will be write back in the space.
*/
struct sgcl_query {
u8 res[12];
u8 oacl_len;
u8 res1[3];
};
/* define for 'stat' */
#define ENETC_CBDR_SGIQ_AIPV_MASK 0x7
#define ENETC_CBDR_SGIQ_AIPV_EN BIT(3)
#define ENETC_CBDR_SGIQ_AGTST BIT(4)
#define ENETC_CBDR_SGIQ_ACL_LEN_MASK 0x60
#define ENETC_CBDR_SGIQ_OIPV_MASK 0x380
#define ENETC_CBDR_SGIQ_OIPV_EN BIT(10)
#define ENETC_CBDR_SGIQ_OGTST BIT(11)
#define ENETC_CBDR_SGIQ_OCL_LEN_MASK 0x3000
/* class 9, command 3 data space */
struct sgcl_query_resp {
u16 stat;
u16 res;
u32 abtl;
u32 abth;
u32 act;
u32 acte;
u32 cctl;
u32 ccth;
u32 obtl;
u32 obth;
u32 oct;
u32 octe;
};
/* class 9, command 4 Stream Gate Instance Table Query Statistics Response
* short command, write back, no command define
*/
struct sgi_query_stat_resp {
u32 pgcl;
u32 pgch;
u32 dgcl;
u32 dgch;
u16 msdu_avail;
u8 res[6];
};
#define ENETC_CBDR_FMI_MR BIT(0)
#define ENETC_CBDR_FMI_MREN BIT(1)
#define ENETC_CBDR_FMI_DOY BIT(2)
#define ENETC_CBDR_FMI_CM BIT(3)
#define ENETC_CBDR_FMI_CF BIT(4)
#define ENETC_CBDR_FMI_NDOR BIT(5)
#define ENETC_CBDR_FMI_OALEN BIT(6)
#define ENETC_CBDR_FMI_IRFPP_MASK 0x1f
/* class 10: command 0/1, Flow Meter Instance Set, short Format */
struct fmi_conf {
__le32 cir;
__le32 cbs;
__le32 eir;
__le32 ebs;
u8 conf;
u8 res1;
u8 ir_fpp;
u8 res2[4];
u8 en;
};
/* class:10, command:2, Flow Meter Instance Statistics Query Response */
struct fmi_query_stat_resp {
u32 bcl;
u32 bch;
u32 dfl;
u32 dfh;
u32 d0gfl;
u32 d0gfh;
u32 d1gfl;
u32 d1gfh;
u32 dyfl;
u32 dyfh;
u32 ryfl;
u32 ryfh;
u32 drfl;
u32 drfh;
u32 rrfl;
u32 rrfh;
u32 lts;
u32 bci;
u32 bcf;
u32 bei;
u32 bef;
};
/* class 5, command 0 */
struct tgs_gcl_conf {
u8 atc; /* init gate value */
u8 res[7];
struct {
u8 res1[4];
__le16 acl_len;
u8 res2[2];
union {
struct {
u8 res1[4];
__le16 acl_len;
u8 res2[2];
};
struct {
u32 cctl;
u32 ccth;
};
};
};
#define ENETC_CBDR_SGL_IOMEN BIT(0)
#define ENETC_CBDR_SGL_IPVEN BIT(3)
#define ENETC_CBDR_SGL_GTST BIT(4)
#define ENETC_CBDR_SGL_IPV_MASK 0xe
/* Stream Gate Control List Entry */
struct sgce {
u32 interval;
u8 msdu[3];
u8 multi;
};
/* gate control list entry */
struct gce {