diff options
author | Camelia Groza <camelia.groza@nxp.com> | 2019-05-27 18:21:31 +0300 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2019-05-28 17:11:02 -0700 |
commit | cbe9e835946fc792b061d51527c6f006a10419e6 (patch) | |
tree | 8571f17a637ffc5594f9ae01eba618f9566e46ef /drivers | |
parent | 7f3343234c0b9c2f3e64b4a82f666034f6c5b479 (diff) |
enetc: Enable TC offloading with mqprio
Add support to configure multiple prioritized TX traffic
classes with mqprio.
Configure one BD ring per TC for the moment, one netdev
queue per TC.
Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/ethernet/freescale/enetc/enetc.c | 56 | ||||
-rw-r--r-- | drivers/net/ethernet/freescale/enetc/enetc.h | 3 | ||||
-rw-r--r-- | drivers/net/ethernet/freescale/enetc/enetc_hw.h | 12 | ||||
-rw-r--r-- | drivers/net/ethernet/freescale/enetc/enetc_pf.c | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/freescale/enetc/enetc_vf.c | 1 |
5 files changed, 72 insertions, 1 deletions
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c index 79bbc86abe77..223709443ea4 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc.c +++ b/drivers/net/ethernet/freescale/enetc/enetc.c @@ -1427,6 +1427,62 @@ int enetc_close(struct net_device *ndev) return 0; } +int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type, + void *type_data) +{ + struct enetc_ndev_priv *priv = netdev_priv(ndev); + struct tc_mqprio_qopt *mqprio = type_data; + struct enetc_bdr *tx_ring; + u8 num_tc; + int i; + + if (type != TC_SETUP_QDISC_MQPRIO) + return -EOPNOTSUPP; + + mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS; + num_tc = mqprio->num_tc; + + if (!num_tc) { + netdev_reset_tc(ndev); + netif_set_real_num_tx_queues(ndev, priv->num_tx_rings); + + /* Reset all ring priorities to 0 */ + for (i = 0; i < priv->num_tx_rings; i++) { + tx_ring = priv->tx_ring[i]; + enetc_set_bdr_prio(&priv->si->hw, tx_ring->index, 0); + } + + return 0; + } + + /* Check if we have enough BD rings available to accommodate all TCs */ + if (num_tc > priv->num_tx_rings) { + netdev_err(ndev, "Max %d traffic classes supported\n", + priv->num_tx_rings); + return -EINVAL; + } + + /* For the moment, we use only one BD ring per TC. + * + * Configure num_tc BD rings with increasing priorities. + */ + for (i = 0; i < num_tc; i++) { + tx_ring = priv->tx_ring[i]; + enetc_set_bdr_prio(&priv->si->hw, tx_ring->index, i); + } + + /* Reset the number of netdev queues based on the TC count */ + netif_set_real_num_tx_queues(ndev, num_tc); + + netdev_set_num_tc(ndev, num_tc); + + /* Each TC is associated with one netdev queue */ + for (i = 0; i < num_tc; i++) + netdev_set_tc_queue(ndev, i, 1, i); + + return 0; +} + struct net_device_stats *enetc_get_stats(struct net_device *ndev) { struct enetc_ndev_priv *priv = netdev_priv(ndev); diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h index ea443268bf70..541b4e2073fe 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc.h +++ b/drivers/net/ethernet/freescale/enetc/enetc.h @@ -229,6 +229,9 @@ struct net_device_stats *enetc_get_stats(struct net_device *ndev); int enetc_set_features(struct net_device *ndev, netdev_features_t features); int enetc_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd); +int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type, + void *type_data); + /* ethtool */ void enetc_set_ethtool_ops(struct net_device *ndev); diff --git a/drivers/net/ethernet/freescale/enetc/enetc_hw.h b/drivers/net/ethernet/freescale/enetc/enetc_hw.h index 6559cef4b07d..88276299f447 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h +++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h @@ -127,7 +127,7 @@ enum enetc_bdr_type {TX, RX}; #define ENETC_TBSR_BUSY BIT(0) #define ENETC_TBMR_VIH BIT(9) #define ENETC_TBMR_PRIO_MASK GENMASK(2, 0) -#define ENETC_TBMR_PRIO_SET(val) val +#define ENETC_TBMR_SET_PRIO(val) ((val) & ENETC_TBMR_PRIO_MASK) #define ENETC_TBMR_EN BIT(31) #define ENETC_TBSR 0x4 #define ENETC_TBBAR0 0x10 @@ -544,3 +544,13 @@ static inline void enetc_enable_txvlan(struct enetc_hw *hw, int si_idx, val = (val & ~ENETC_TBMR_VIH) | (en ? ENETC_TBMR_VIH : 0); enetc_txbdr_wr(hw, si_idx, ENETC_TBMR, val); } + +static inline void enetc_set_bdr_prio(struct enetc_hw *hw, int bdr_idx, + int prio) +{ + u32 val = enetc_txbdr_rd(hw, bdr_idx, ENETC_TBMR); + + val &= ~ENETC_TBMR_PRIO_MASK; + val |= ENETC_TBMR_SET_PRIO(prio); + enetc_txbdr_wr(hw, bdr_idx, ENETC_TBMR, val); +} diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c index d78ec8d43c39..258b3cb38a6f 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c @@ -703,6 +703,7 @@ static const struct net_device_ops enetc_ndev_ops = { .ndo_set_vf_spoofchk = enetc_pf_set_vf_spoofchk, .ndo_set_features = enetc_pf_set_features, .ndo_do_ioctl = enetc_ioctl, + .ndo_setup_tc = enetc_setup_tc, }; static void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev, diff --git a/drivers/net/ethernet/freescale/enetc/enetc_vf.c b/drivers/net/ethernet/freescale/enetc/enetc_vf.c index 17f72644c5a1..ebd21bf4cfa1 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_vf.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_vf.c @@ -112,6 +112,7 @@ static const struct net_device_ops enetc_ndev_ops = { .ndo_set_mac_address = enetc_vf_set_mac_addr, .ndo_set_features = enetc_vf_set_features, .ndo_do_ioctl = enetc_ioctl, + .ndo_setup_tc = enetc_setup_tc, }; static void enetc_vf_netdev_setup(struct enetc_si *si, struct net_device *ndev, |