Merge branch 'lan966x-mqprio-taprio'
Horatiu Vultur says: ==================== net: lan966x: Add mqprio and taprio support Add support for offloading QoS features with tc command to lan966x. The offloaded QoS features are mqprio and taprio. v1->v2: - fix compilation warning - rename lan966x_taprio_enable/disable to lan966x_taprio_add/del ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
3aba35bb20
|
@ -8,4 +8,5 @@ obj-$(CONFIG_LAN966X_SWITCH) += lan966x-switch.o
|
|||
lan966x-switch-objs := lan966x_main.o lan966x_phylink.o lan966x_port.o \
|
||||
lan966x_mac.o lan966x_ethtool.o lan966x_switchdev.o \
|
||||
lan966x_vlan.o lan966x_fdb.o lan966x_mdb.o \
|
||||
lan966x_ptp.o lan966x_fdma.o lan966x_lag.o
|
||||
lan966x_ptp.o lan966x_fdma.o lan966x_lag.o \
|
||||
lan966x_tc.o lan966x_mqprio.o lan966x_taprio.o
|
||||
|
|
|
@ -466,6 +466,7 @@ static const struct net_device_ops lan966x_port_netdev_ops = {
|
|||
.ndo_set_mac_address = lan966x_port_set_mac_address,
|
||||
.ndo_get_port_parent_id = lan966x_port_get_parent_id,
|
||||
.ndo_eth_ioctl = lan966x_port_ioctl,
|
||||
.ndo_setup_tc = lan966x_tc_setup,
|
||||
};
|
||||
|
||||
bool lan966x_netdevice_check(const struct net_device *dev)
|
||||
|
@ -738,7 +739,8 @@ static int lan966x_probe_port(struct lan966x *lan966x, u32 p,
|
|||
return -EINVAL;
|
||||
|
||||
dev = devm_alloc_etherdev_mqs(lan966x->dev,
|
||||
sizeof(struct lan966x_port), 8, 1);
|
||||
sizeof(struct lan966x_port),
|
||||
NUM_PRIO_QUEUES, 1);
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -754,7 +756,9 @@ static int lan966x_probe_port(struct lan966x *lan966x, u32 p,
|
|||
dev->netdev_ops = &lan966x_port_netdev_ops;
|
||||
dev->ethtool_ops = &lan966x_ethtool_ops;
|
||||
dev->features |= NETIF_F_HW_VLAN_CTAG_TX |
|
||||
NETIF_F_HW_VLAN_STAG_TX;
|
||||
NETIF_F_HW_VLAN_STAG_TX |
|
||||
NETIF_F_HW_TC;
|
||||
dev->hw_features |= NETIF_F_HW_TC;
|
||||
dev->needed_headroom = IFH_LEN * sizeof(u32);
|
||||
|
||||
eth_hw_addr_gen(dev, lan966x->base_mac, p + 1);
|
||||
|
@ -959,6 +963,8 @@ static void lan966x_init(struct lan966x *lan966x)
|
|||
lan966x, ANA_ANAINTR);
|
||||
|
||||
spin_lock_init(&lan966x->tx_lock);
|
||||
|
||||
lan966x_taprio_init(lan966x);
|
||||
}
|
||||
|
||||
static int lan966x_ram_init(struct lan966x *lan966x)
|
||||
|
@ -1168,6 +1174,7 @@ static int lan966x_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct lan966x *lan966x = platform_get_drvdata(pdev);
|
||||
|
||||
lan966x_taprio_deinit(lan966x);
|
||||
lan966x_fdma_deinit(lan966x);
|
||||
lan966x_cleanup_ports(lan966x);
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <linux/phy.h>
|
||||
#include <linux/phylink.h>
|
||||
#include <linux/ptp_clock_kernel.h>
|
||||
#include <net/pkt_sched.h>
|
||||
#include <net/switchdev.h>
|
||||
|
||||
#include "lan966x_regs.h"
|
||||
|
@ -36,6 +37,7 @@
|
|||
|
||||
#define NUM_PHYS_PORTS 8
|
||||
#define CPU_PORT 8
|
||||
#define NUM_PRIO_QUEUES 8
|
||||
|
||||
/* Reserved PGIDs */
|
||||
#define PGID_CPU (PGID_AGGR - 6)
|
||||
|
@ -409,6 +411,8 @@ void lan966x_ptp_txtstamp_release(struct lan966x_port *port,
|
|||
struct sk_buff *skb);
|
||||
irqreturn_t lan966x_ptp_irq_handler(int irq, void *args);
|
||||
irqreturn_t lan966x_ptp_ext_irq_handler(int irq, void *args);
|
||||
u32 lan966x_ptp_get_period_ps(void);
|
||||
int lan966x_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts);
|
||||
|
||||
int lan966x_fdma_xmit(struct sk_buff *skb, __be32 *ifh, struct net_device *dev);
|
||||
int lan966x_fdma_change_mtu(struct lan966x *lan966x);
|
||||
|
@ -445,6 +449,19 @@ void lan966x_port_ageing_set(struct lan966x_port *port,
|
|||
unsigned long ageing_clock_t);
|
||||
void lan966x_update_fwd_mask(struct lan966x *lan966x);
|
||||
|
||||
int lan966x_tc_setup(struct net_device *dev, enum tc_setup_type type,
|
||||
void *type_data);
|
||||
|
||||
int lan966x_mqprio_add(struct lan966x_port *port, u8 num_tc);
|
||||
int lan966x_mqprio_del(struct lan966x_port *port);
|
||||
|
||||
void lan966x_taprio_init(struct lan966x *lan966x);
|
||||
void lan966x_taprio_deinit(struct lan966x *lan966x);
|
||||
int lan966x_taprio_add(struct lan966x_port *port,
|
||||
struct tc_taprio_qopt_offload *qopt);
|
||||
int lan966x_taprio_del(struct lan966x_port *port);
|
||||
int lan966x_taprio_speed_set(struct lan966x_port *port, int speed);
|
||||
|
||||
static inline void __iomem *lan_addr(void __iomem *base[],
|
||||
int id, int tinst, int tcnt,
|
||||
int gbase, int ginst,
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
#include "lan966x_main.h"
|
||||
|
||||
int lan966x_mqprio_add(struct lan966x_port *port, u8 num_tc)
|
||||
{
|
||||
u8 i;
|
||||
|
||||
if (num_tc != NUM_PRIO_QUEUES) {
|
||||
netdev_err(port->dev, "Only %d tarffic classes supported\n",
|
||||
NUM_PRIO_QUEUES);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
netdev_set_num_tc(port->dev, num_tc);
|
||||
|
||||
for (i = 0; i < num_tc; ++i)
|
||||
netdev_set_tc_queue(port->dev, i, 1, i);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lan966x_mqprio_del(struct lan966x_port *port)
|
||||
{
|
||||
netdev_reset_tc(port->dev);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -165,6 +165,8 @@ static void lan966x_port_link_up(struct lan966x_port *port)
|
|||
break;
|
||||
}
|
||||
|
||||
lan966x_taprio_speed_set(port, config->speed);
|
||||
|
||||
/* Also the GIGA_MODE_ENA(1) needs to be set regardless of the
|
||||
* port speed for QSGMII ports.
|
||||
*/
|
||||
|
|
|
@ -464,8 +464,7 @@ static int lan966x_ptp_settime64(struct ptp_clock_info *ptp,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int lan966x_ptp_gettime64(struct ptp_clock_info *ptp,
|
||||
struct timespec64 *ts)
|
||||
int lan966x_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts)
|
||||
{
|
||||
struct lan966x_phc *phc = container_of(ptp, struct lan966x_phc, info);
|
||||
struct lan966x *lan966x = phc->lan966x;
|
||||
|
@ -890,3 +889,9 @@ void lan966x_ptp_rxtstamp(struct lan966x *lan966x, struct sk_buff *skb,
|
|||
shhwtstamps = skb_hwtstamps(skb);
|
||||
shhwtstamps->hwtstamp = full_ts_in_ns;
|
||||
}
|
||||
|
||||
u32 lan966x_ptp_get_period_ps(void)
|
||||
{
|
||||
/* This represents the system clock period in picoseconds */
|
||||
return 15125;
|
||||
}
|
||||
|
|
|
@ -1018,6 +1018,165 @@ enum lan966x_target {
|
|||
/* QSYS:RES_CTRL:RES_CFG */
|
||||
#define QSYS_RES_CFG(g) __REG(TARGET_QSYS, 0, 1, 32768, g, 1024, 8, 0, 0, 1, 4)
|
||||
|
||||
/* QSYS:TAS_CONFIG:TAS_CFG_CTRL */
|
||||
#define QSYS_TAS_CFG_CTRL __REG(TARGET_QSYS, 0, 1, 57372, 0, 1, 12, 0, 0, 1, 4)
|
||||
|
||||
#define QSYS_TAS_CFG_CTRL_LIST_NUM_MAX GENMASK(27, 23)
|
||||
#define QSYS_TAS_CFG_CTRL_LIST_NUM_MAX_SET(x)\
|
||||
FIELD_PREP(QSYS_TAS_CFG_CTRL_LIST_NUM_MAX, x)
|
||||
#define QSYS_TAS_CFG_CTRL_LIST_NUM_MAX_GET(x)\
|
||||
FIELD_GET(QSYS_TAS_CFG_CTRL_LIST_NUM_MAX, x)
|
||||
|
||||
#define QSYS_TAS_CFG_CTRL_LIST_NUM GENMASK(22, 18)
|
||||
#define QSYS_TAS_CFG_CTRL_LIST_NUM_SET(x)\
|
||||
FIELD_PREP(QSYS_TAS_CFG_CTRL_LIST_NUM, x)
|
||||
#define QSYS_TAS_CFG_CTRL_LIST_NUM_GET(x)\
|
||||
FIELD_GET(QSYS_TAS_CFG_CTRL_LIST_NUM, x)
|
||||
|
||||
#define QSYS_TAS_CFG_CTRL_ALWAYS_GB_SCH_Q BIT(17)
|
||||
#define QSYS_TAS_CFG_CTRL_ALWAYS_GB_SCH_Q_SET(x)\
|
||||
FIELD_PREP(QSYS_TAS_CFG_CTRL_ALWAYS_GB_SCH_Q, x)
|
||||
#define QSYS_TAS_CFG_CTRL_ALWAYS_GB_SCH_Q_GET(x)\
|
||||
FIELD_GET(QSYS_TAS_CFG_CTRL_ALWAYS_GB_SCH_Q, x)
|
||||
|
||||
#define QSYS_TAS_CFG_CTRL_GCL_ENTRY_NUM GENMASK(16, 5)
|
||||
#define QSYS_TAS_CFG_CTRL_GCL_ENTRY_NUM_SET(x)\
|
||||
FIELD_PREP(QSYS_TAS_CFG_CTRL_GCL_ENTRY_NUM, x)
|
||||
#define QSYS_TAS_CFG_CTRL_GCL_ENTRY_NUM_GET(x)\
|
||||
FIELD_GET(QSYS_TAS_CFG_CTRL_GCL_ENTRY_NUM, x)
|
||||
|
||||
/* QSYS:TAS_CONFIG:TAS_GATE_STATE_CTRL */
|
||||
#define QSYS_TAS_GS_CTRL __REG(TARGET_QSYS, 0, 1, 57372, 0, 1, 12, 4, 0, 1, 4)
|
||||
|
||||
#define QSYS_TAS_GS_CTRL_HSCH_POS GENMASK(2, 0)
|
||||
#define QSYS_TAS_GS_CTRL_HSCH_POS_SET(x)\
|
||||
FIELD_PREP(QSYS_TAS_GS_CTRL_HSCH_POS, x)
|
||||
#define QSYS_TAS_GS_CTRL_HSCH_POS_GET(x)\
|
||||
FIELD_GET(QSYS_TAS_GS_CTRL_HSCH_POS, x)
|
||||
|
||||
/* QSYS:TAS_CONFIG:TAS_STATEMACHINE_CFG */
|
||||
#define QSYS_TAS_STM_CFG __REG(TARGET_QSYS, 0, 1, 57372, 0, 1, 12, 8, 0, 1, 4)
|
||||
|
||||
#define QSYS_TAS_STM_CFG_REVISIT_DLY GENMASK(7, 0)
|
||||
#define QSYS_TAS_STM_CFG_REVISIT_DLY_SET(x)\
|
||||
FIELD_PREP(QSYS_TAS_STM_CFG_REVISIT_DLY, x)
|
||||
#define QSYS_TAS_STM_CFG_REVISIT_DLY_GET(x)\
|
||||
FIELD_GET(QSYS_TAS_STM_CFG_REVISIT_DLY, x)
|
||||
|
||||
/* QSYS:TAS_PROFILE_CFG:TAS_PROFILE_CONFIG */
|
||||
#define QSYS_TAS_PROFILE_CFG(g) __REG(TARGET_QSYS, 0, 1, 30720, g, 16, 64, 32, 0, 1, 4)
|
||||
|
||||
#define QSYS_TAS_PROFILE_CFG_PORT_NUM GENMASK(21, 19)
|
||||
#define QSYS_TAS_PROFILE_CFG_PORT_NUM_SET(x)\
|
||||
FIELD_PREP(QSYS_TAS_PROFILE_CFG_PORT_NUM, x)
|
||||
#define QSYS_TAS_PROFILE_CFG_PORT_NUM_GET(x)\
|
||||
FIELD_GET(QSYS_TAS_PROFILE_CFG_PORT_NUM, x)
|
||||
|
||||
#define QSYS_TAS_PROFILE_CFG_LINK_SPEED GENMASK(18, 16)
|
||||
#define QSYS_TAS_PROFILE_CFG_LINK_SPEED_SET(x)\
|
||||
FIELD_PREP(QSYS_TAS_PROFILE_CFG_LINK_SPEED, x)
|
||||
#define QSYS_TAS_PROFILE_CFG_LINK_SPEED_GET(x)\
|
||||
FIELD_GET(QSYS_TAS_PROFILE_CFG_LINK_SPEED, x)
|
||||
|
||||
/* QSYS:TAS_LIST_CFG:TAS_BASE_TIME_NSEC */
|
||||
#define QSYS_TAS_BT_NSEC __REG(TARGET_QSYS, 0, 1, 27904, 0, 1, 64, 0, 0, 1, 4)
|
||||
|
||||
#define QSYS_TAS_BT_NSEC_NSEC GENMASK(29, 0)
|
||||
#define QSYS_TAS_BT_NSEC_NSEC_SET(x)\
|
||||
FIELD_PREP(QSYS_TAS_BT_NSEC_NSEC, x)
|
||||
#define QSYS_TAS_BT_NSEC_NSEC_GET(x)\
|
||||
FIELD_GET(QSYS_TAS_BT_NSEC_NSEC, x)
|
||||
|
||||
/* QSYS:TAS_LIST_CFG:TAS_BASE_TIME_SEC_LSB */
|
||||
#define QSYS_TAS_BT_SEC_LSB __REG(TARGET_QSYS, 0, 1, 27904, 0, 1, 64, 4, 0, 1, 4)
|
||||
|
||||
/* QSYS:TAS_LIST_CFG:TAS_BASE_TIME_SEC_MSB */
|
||||
#define QSYS_TAS_BT_SEC_MSB __REG(TARGET_QSYS, 0, 1, 27904, 0, 1, 64, 8, 0, 1, 4)
|
||||
|
||||
#define QSYS_TAS_BT_SEC_MSB_SEC_MSB GENMASK(15, 0)
|
||||
#define QSYS_TAS_BT_SEC_MSB_SEC_MSB_SET(x)\
|
||||
FIELD_PREP(QSYS_TAS_BT_SEC_MSB_SEC_MSB, x)
|
||||
#define QSYS_TAS_BT_SEC_MSB_SEC_MSB_GET(x)\
|
||||
FIELD_GET(QSYS_TAS_BT_SEC_MSB_SEC_MSB, x)
|
||||
|
||||
/* QSYS:TAS_LIST_CFG:TAS_CYCLE_TIME_CFG */
|
||||
#define QSYS_TAS_CT_CFG __REG(TARGET_QSYS, 0, 1, 27904, 0, 1, 64, 24, 0, 1, 4)
|
||||
|
||||
/* QSYS:TAS_LIST_CFG:TAS_STARTUP_CFG */
|
||||
#define QSYS_TAS_STARTUP_CFG __REG(TARGET_QSYS, 0, 1, 27904, 0, 1, 64, 28, 0, 1, 4)
|
||||
|
||||
#define QSYS_TAS_STARTUP_CFG_OBSOLETE_IDX GENMASK(27, 23)
|
||||
#define QSYS_TAS_STARTUP_CFG_OBSOLETE_IDX_SET(x)\
|
||||
FIELD_PREP(QSYS_TAS_STARTUP_CFG_OBSOLETE_IDX, x)
|
||||
#define QSYS_TAS_STARTUP_CFG_OBSOLETE_IDX_GET(x)\
|
||||
FIELD_GET(QSYS_TAS_STARTUP_CFG_OBSOLETE_IDX, x)
|
||||
|
||||
/* QSYS:TAS_LIST_CFG:TAS_LIST_CFG */
|
||||
#define QSYS_TAS_LIST_CFG __REG(TARGET_QSYS, 0, 1, 27904, 0, 1, 64, 32, 0, 1, 4)
|
||||
|
||||
#define QSYS_TAS_LIST_CFG_LIST_BASE_ADDR GENMASK(11, 0)
|
||||
#define QSYS_TAS_LIST_CFG_LIST_BASE_ADDR_SET(x)\
|
||||
FIELD_PREP(QSYS_TAS_LIST_CFG_LIST_BASE_ADDR, x)
|
||||
#define QSYS_TAS_LIST_CFG_LIST_BASE_ADDR_GET(x)\
|
||||
FIELD_GET(QSYS_TAS_LIST_CFG_LIST_BASE_ADDR, x)
|
||||
|
||||
/* QSYS:TAS_LIST_CFG:TAS_LIST_STATE */
|
||||
#define QSYS_TAS_LST __REG(TARGET_QSYS, 0, 1, 27904, 0, 1, 64, 36, 0, 1, 4)
|
||||
|
||||
#define QSYS_TAS_LST_LIST_STATE GENMASK(2, 0)
|
||||
#define QSYS_TAS_LST_LIST_STATE_SET(x)\
|
||||
FIELD_PREP(QSYS_TAS_LST_LIST_STATE, x)
|
||||
#define QSYS_TAS_LST_LIST_STATE_GET(x)\
|
||||
FIELD_GET(QSYS_TAS_LST_LIST_STATE, x)
|
||||
|
||||
/* QSYS:TAS_GCL_CFG:TAS_GCL_CTRL_CFG */
|
||||
#define QSYS_TAS_GCL_CT_CFG __REG(TARGET_QSYS, 0, 1, 27968, 0, 1, 16, 0, 0, 1, 4)
|
||||
|
||||
#define QSYS_TAS_GCL_CT_CFG_HSCH_POS GENMASK(12, 10)
|
||||
#define QSYS_TAS_GCL_CT_CFG_HSCH_POS_SET(x)\
|
||||
FIELD_PREP(QSYS_TAS_GCL_CT_CFG_HSCH_POS, x)
|
||||
#define QSYS_TAS_GCL_CT_CFG_HSCH_POS_GET(x)\
|
||||
FIELD_GET(QSYS_TAS_GCL_CT_CFG_HSCH_POS, x)
|
||||
|
||||
#define QSYS_TAS_GCL_CT_CFG_GATE_STATE GENMASK(9, 2)
|
||||
#define QSYS_TAS_GCL_CT_CFG_GATE_STATE_SET(x)\
|
||||
FIELD_PREP(QSYS_TAS_GCL_CT_CFG_GATE_STATE, x)
|
||||
#define QSYS_TAS_GCL_CT_CFG_GATE_STATE_GET(x)\
|
||||
FIELD_GET(QSYS_TAS_GCL_CT_CFG_GATE_STATE, x)
|
||||
|
||||
#define QSYS_TAS_GCL_CT_CFG_OP_TYPE GENMASK(1, 0)
|
||||
#define QSYS_TAS_GCL_CT_CFG_OP_TYPE_SET(x)\
|
||||
FIELD_PREP(QSYS_TAS_GCL_CT_CFG_OP_TYPE, x)
|
||||
#define QSYS_TAS_GCL_CT_CFG_OP_TYPE_GET(x)\
|
||||
FIELD_GET(QSYS_TAS_GCL_CT_CFG_OP_TYPE, x)
|
||||
|
||||
/* QSYS:TAS_GCL_CFG:TAS_GCL_CTRL_CFG2 */
|
||||
#define QSYS_TAS_GCL_CT_CFG2 __REG(TARGET_QSYS, 0, 1, 27968, 0, 1, 16, 4, 0, 1, 4)
|
||||
|
||||
#define QSYS_TAS_GCL_CT_CFG2_PORT_PROFILE GENMASK(15, 12)
|
||||
#define QSYS_TAS_GCL_CT_CFG2_PORT_PROFILE_SET(x)\
|
||||
FIELD_PREP(QSYS_TAS_GCL_CT_CFG2_PORT_PROFILE, x)
|
||||
#define QSYS_TAS_GCL_CT_CFG2_PORT_PROFILE_GET(x)\
|
||||
FIELD_GET(QSYS_TAS_GCL_CT_CFG2_PORT_PROFILE, x)
|
||||
|
||||
#define QSYS_TAS_GCL_CT_CFG2_NEXT_GCL GENMASK(11, 0)
|
||||
#define QSYS_TAS_GCL_CT_CFG2_NEXT_GCL_SET(x)\
|
||||
FIELD_PREP(QSYS_TAS_GCL_CT_CFG2_NEXT_GCL, x)
|
||||
#define QSYS_TAS_GCL_CT_CFG2_NEXT_GCL_GET(x)\
|
||||
FIELD_GET(QSYS_TAS_GCL_CT_CFG2_NEXT_GCL, x)
|
||||
|
||||
/* QSYS:TAS_GCL_CFG:TAS_GCL_TIME_CFG */
|
||||
#define QSYS_TAS_GCL_TM_CFG __REG(TARGET_QSYS, 0, 1, 27968, 0, 1, 16, 8, 0, 1, 4)
|
||||
|
||||
/* QSYS:HSCH_TAS_STATE:TAS_GATE_STATE */
|
||||
#define QSYS_TAS_GATE_STATE __REG(TARGET_QSYS, 0, 1, 28004, 0, 1, 4, 0, 0, 1, 4)
|
||||
|
||||
#define QSYS_TAS_GATE_STATE_TAS_GATE_STATE GENMASK(7, 0)
|
||||
#define QSYS_TAS_GATE_STATE_TAS_GATE_STATE_SET(x)\
|
||||
FIELD_PREP(QSYS_TAS_GATE_STATE_TAS_GATE_STATE, x)
|
||||
#define QSYS_TAS_GATE_STATE_TAS_GATE_STATE_GET(x)\
|
||||
FIELD_GET(QSYS_TAS_GATE_STATE_TAS_GATE_STATE, x)
|
||||
|
||||
/* REW:PORT:PORT_VLAN_CFG */
|
||||
#define REW_PORT_VLAN_CFG(g) __REG(TARGET_REW, 0, 1, 0, g, 10, 128, 0, 0, 1, 4)
|
||||
|
||||
|
|
|
@ -0,0 +1,528 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
#include "lan966x_main.h"
|
||||
|
||||
#define LAN966X_TAPRIO_TIMEOUT_MS 1000
|
||||
#define LAN966X_TAPRIO_ENTRIES_PER_PORT 2
|
||||
|
||||
/* Minimum supported cycle time in nanoseconds */
|
||||
#define LAN966X_TAPRIO_MIN_CYCLE_TIME_NS NSEC_PER_USEC
|
||||
|
||||
/* Maximum supported cycle time in nanoseconds */
|
||||
#define LAN966X_TAPRIO_MAX_CYCLE_TIME_NS (NSEC_PER_SEC - 1)
|
||||
|
||||
/* Total number of TAS GCL entries */
|
||||
#define LAN966X_TAPRIO_NUM_GCL 256
|
||||
|
||||
/* TAPRIO link speeds for calculation of guard band */
|
||||
enum lan966x_taprio_link_speed {
|
||||
LAN966X_TAPRIO_SPEED_NO_GB,
|
||||
LAN966X_TAPRIO_SPEED_10,
|
||||
LAN966X_TAPRIO_SPEED_100,
|
||||
LAN966X_TAPRIO_SPEED_1000,
|
||||
LAN966X_TAPRIO_SPEED_2500,
|
||||
};
|
||||
|
||||
/* TAPRIO list states */
|
||||
enum lan966x_taprio_state {
|
||||
LAN966X_TAPRIO_STATE_ADMIN,
|
||||
LAN966X_TAPRIO_STATE_ADVANCING,
|
||||
LAN966X_TAPRIO_STATE_PENDING,
|
||||
LAN966X_TAPRIO_STATE_OPERATING,
|
||||
LAN966X_TAPRIO_STATE_TERMINATING,
|
||||
LAN966X_TAPRIO_STATE_MAX,
|
||||
};
|
||||
|
||||
/* TAPRIO GCL command */
|
||||
enum lan966x_taprio_gcl_cmd {
|
||||
LAN966X_TAPRIO_GCL_CMD_SET_GATE_STATES = 0,
|
||||
};
|
||||
|
||||
static u32 lan966x_taprio_list_index(struct lan966x_port *port, u8 entry)
|
||||
{
|
||||
return port->chip_port * LAN966X_TAPRIO_ENTRIES_PER_PORT + entry;
|
||||
}
|
||||
|
||||
static u32 lan966x_taprio_list_state_get(struct lan966x_port *port)
|
||||
{
|
||||
struct lan966x *lan966x = port->lan966x;
|
||||
u32 val;
|
||||
|
||||
val = lan_rd(lan966x, QSYS_TAS_LST);
|
||||
return QSYS_TAS_LST_LIST_STATE_GET(val);
|
||||
}
|
||||
|
||||
static u32 lan966x_taprio_list_index_state_get(struct lan966x_port *port,
|
||||
u32 list)
|
||||
{
|
||||
struct lan966x *lan966x = port->lan966x;
|
||||
|
||||
lan_rmw(QSYS_TAS_CFG_CTRL_LIST_NUM_SET(list),
|
||||
QSYS_TAS_CFG_CTRL_LIST_NUM,
|
||||
lan966x, QSYS_TAS_CFG_CTRL);
|
||||
|
||||
return lan966x_taprio_list_state_get(port);
|
||||
}
|
||||
|
||||
static void lan966x_taprio_list_state_set(struct lan966x_port *port,
|
||||
u32 state)
|
||||
{
|
||||
struct lan966x *lan966x = port->lan966x;
|
||||
|
||||
lan_rmw(QSYS_TAS_LST_LIST_STATE_SET(state),
|
||||
QSYS_TAS_LST_LIST_STATE,
|
||||
lan966x, QSYS_TAS_LST);
|
||||
}
|
||||
|
||||
static int lan966x_taprio_list_shutdown(struct lan966x_port *port,
|
||||
u32 list)
|
||||
{
|
||||
struct lan966x *lan966x = port->lan966x;
|
||||
bool pending, operating;
|
||||
unsigned long end;
|
||||
u32 state;
|
||||
|
||||
end = jiffies + msecs_to_jiffies(LAN966X_TAPRIO_TIMEOUT_MS);
|
||||
/* It is required to try multiple times to set the state of list,
|
||||
* because the HW can overwrite this.
|
||||
*/
|
||||
do {
|
||||
state = lan966x_taprio_list_state_get(port);
|
||||
|
||||
pending = false;
|
||||
operating = false;
|
||||
|
||||
if (state == LAN966X_TAPRIO_STATE_ADVANCING ||
|
||||
state == LAN966X_TAPRIO_STATE_PENDING) {
|
||||
lan966x_taprio_list_state_set(port,
|
||||
LAN966X_TAPRIO_STATE_ADMIN);
|
||||
pending = true;
|
||||
}
|
||||
|
||||
if (state == LAN966X_TAPRIO_STATE_OPERATING) {
|
||||
lan966x_taprio_list_state_set(port,
|
||||
LAN966X_TAPRIO_STATE_TERMINATING);
|
||||
operating = true;
|
||||
}
|
||||
|
||||
/* If the entry was in pending and now gets in admin, then there
|
||||
* is nothing else to do, so just bail out
|
||||
*/
|
||||
state = lan966x_taprio_list_state_get(port);
|
||||
if (pending &&
|
||||
state == LAN966X_TAPRIO_STATE_ADMIN)
|
||||
return 0;
|
||||
|
||||
/* If the list was in operating and now is in terminating or
|
||||
* admin, then is OK to exit but it needs to wait until the list
|
||||
* will get in admin. It is not required to set the state
|
||||
* again.
|
||||
*/
|
||||
if (operating &&
|
||||
(state == LAN966X_TAPRIO_STATE_TERMINATING ||
|
||||
state == LAN966X_TAPRIO_STATE_ADMIN))
|
||||
break;
|
||||
|
||||
} while (!time_after(jiffies, end));
|
||||
|
||||
end = jiffies + msecs_to_jiffies(LAN966X_TAPRIO_TIMEOUT_MS);
|
||||
do {
|
||||
state = lan966x_taprio_list_state_get(port);
|
||||
if (state == LAN966X_TAPRIO_STATE_ADMIN)
|
||||
break;
|
||||
|
||||
} while (!time_after(jiffies, end));
|
||||
|
||||
/* If the list was in operating mode, it could be stopped while some
|
||||
* queues where closed, so make sure to restore "all-queues-open"
|
||||
*/
|
||||
if (operating) {
|
||||
lan_wr(QSYS_TAS_GS_CTRL_HSCH_POS_SET(port->chip_port),
|
||||
lan966x, QSYS_TAS_GS_CTRL);
|
||||
|
||||
lan_wr(QSYS_TAS_GATE_STATE_TAS_GATE_STATE_SET(0xff),
|
||||
lan966x, QSYS_TAS_GATE_STATE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lan966x_taprio_shutdown(struct lan966x_port *port)
|
||||
{
|
||||
u32 i, list, state;
|
||||
int err;
|
||||
|
||||
for (i = 0; i < LAN966X_TAPRIO_ENTRIES_PER_PORT; ++i) {
|
||||
list = lan966x_taprio_list_index(port, i);
|
||||
state = lan966x_taprio_list_index_state_get(port, list);
|
||||
if (state == LAN966X_TAPRIO_STATE_ADMIN)
|
||||
continue;
|
||||
|
||||
err = lan966x_taprio_list_shutdown(port, list);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Find a suitable list for a new schedule. First priority is a list in state
|
||||
* pending. Second priority is a list in state admin.
|
||||
*/
|
||||
static int lan966x_taprio_find_list(struct lan966x_port *port,
|
||||
struct tc_taprio_qopt_offload *qopt,
|
||||
int *new_list, int *obs_list)
|
||||
{
|
||||
int state[LAN966X_TAPRIO_ENTRIES_PER_PORT];
|
||||
int list[LAN966X_TAPRIO_ENTRIES_PER_PORT];
|
||||
int err, oper = -1;
|
||||
u32 i;
|
||||
|
||||
*new_list = -1;
|
||||
*obs_list = -1;
|
||||
|
||||
/* If there is already an entry in operating mode, return this list in
|
||||
* obs_list, such that when the new list will get activated the
|
||||
* operating list will be stopped. In this way is possible to have
|
||||
* smooth transitions between the lists
|
||||
*/
|
||||
for (i = 0; i < LAN966X_TAPRIO_ENTRIES_PER_PORT; ++i) {
|
||||
list[i] = lan966x_taprio_list_index(port, i);
|
||||
state[i] = lan966x_taprio_list_index_state_get(port, list[i]);
|
||||
if (state[i] == LAN966X_TAPRIO_STATE_OPERATING)
|
||||
oper = list[i];
|
||||
}
|
||||
|
||||
for (i = 0; i < LAN966X_TAPRIO_ENTRIES_PER_PORT; ++i) {
|
||||
if (state[i] == LAN966X_TAPRIO_STATE_PENDING) {
|
||||
err = lan966x_taprio_shutdown(port);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
*new_list = list[i];
|
||||
*obs_list = (oper == -1) ? *new_list : oper;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < LAN966X_TAPRIO_ENTRIES_PER_PORT; ++i) {
|
||||
if (state[i] == LAN966X_TAPRIO_STATE_ADMIN) {
|
||||
*new_list = list[i];
|
||||
*obs_list = (oper == -1) ? *new_list : oper;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
static int lan966x_taprio_check(struct tc_taprio_qopt_offload *qopt)
|
||||
{
|
||||
u64 total_time = 0;
|
||||
u32 i;
|
||||
|
||||
/* This is not supported by th HW */
|
||||
if (qopt->cycle_time_extension)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* There is a limited number of gcl entries that can be used, they are
|
||||
* shared by all ports
|
||||
*/
|
||||
if (qopt->num_entries > LAN966X_TAPRIO_NUM_GCL)
|
||||
return -EINVAL;
|
||||
|
||||
/* Don't allow cycle times bigger than 1 sec or smaller than 1 usec */
|
||||
if (qopt->cycle_time < LAN966X_TAPRIO_MIN_CYCLE_TIME_NS ||
|
||||
qopt->cycle_time > LAN966X_TAPRIO_MAX_CYCLE_TIME_NS)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < qopt->num_entries; ++i) {
|
||||
struct tc_taprio_sched_entry *entry = &qopt->entries[i];
|
||||
|
||||
/* Don't allow intervals bigger than 1 sec or smaller than 1
|
||||
* usec
|
||||
*/
|
||||
if (entry->interval < LAN966X_TAPRIO_MIN_CYCLE_TIME_NS ||
|
||||
entry->interval > LAN966X_TAPRIO_MAX_CYCLE_TIME_NS)
|
||||
return -EINVAL;
|
||||
|
||||
if (qopt->entries[i].command != TC_TAPRIO_CMD_SET_GATES)
|
||||
return -EINVAL;
|
||||
|
||||
total_time += qopt->entries[i].interval;
|
||||
}
|
||||
|
||||
/* Don't allow the total time of intervals be bigger than 1 sec */
|
||||
if (total_time > LAN966X_TAPRIO_MAX_CYCLE_TIME_NS)
|
||||
return -EINVAL;
|
||||
|
||||
/* The HW expects that the cycle time to be at least as big as sum of
|
||||
* each interval of gcl
|
||||
*/
|
||||
if (qopt->cycle_time < total_time)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lan966x_taprio_gcl_free_get(struct lan966x_port *port,
|
||||
unsigned long *free_list)
|
||||
{
|
||||
struct lan966x *lan966x = port->lan966x;
|
||||
u32 num_free, state, list;
|
||||
u32 base, next, max_list;
|
||||
|
||||
/* By default everything is free */
|
||||
bitmap_fill(free_list, LAN966X_TAPRIO_NUM_GCL);
|
||||
num_free = LAN966X_TAPRIO_NUM_GCL;
|
||||
|
||||
/* Iterate over all gcl entries and find out which are free. And mark
|
||||
* those that are not free.
|
||||
*/
|
||||
max_list = lan966x->num_phys_ports * LAN966X_TAPRIO_ENTRIES_PER_PORT;
|
||||
for (list = 0; list < max_list; ++list) {
|
||||
state = lan966x_taprio_list_index_state_get(port, list);
|
||||
if (state == LAN966X_TAPRIO_STATE_ADMIN)
|
||||
continue;
|
||||
|
||||
base = lan_rd(lan966x, QSYS_TAS_LIST_CFG);
|
||||
base = QSYS_TAS_LIST_CFG_LIST_BASE_ADDR_GET(base);
|
||||
next = base;
|
||||
|
||||
do {
|
||||
clear_bit(next, free_list);
|
||||
num_free--;
|
||||
|
||||
lan_rmw(QSYS_TAS_CFG_CTRL_GCL_ENTRY_NUM_SET(next),
|
||||
QSYS_TAS_CFG_CTRL_GCL_ENTRY_NUM,
|
||||
lan966x, QSYS_TAS_CFG_CTRL);
|
||||
|
||||
next = lan_rd(lan966x, QSYS_TAS_GCL_CT_CFG2);
|
||||
next = QSYS_TAS_GCL_CT_CFG2_NEXT_GCL_GET(next);
|
||||
} while (base != next);
|
||||
}
|
||||
|
||||
return num_free;
|
||||
}
|
||||
|
||||
static void lan966x_taprio_gcl_setup_entry(struct lan966x_port *port,
|
||||
struct tc_taprio_sched_entry *entry,
|
||||
u32 next_entry)
|
||||
{
|
||||
struct lan966x *lan966x = port->lan966x;
|
||||
|
||||
/* Setup a single gcl entry */
|
||||
lan_wr(QSYS_TAS_GCL_CT_CFG_GATE_STATE_SET(entry->gate_mask) |
|
||||
QSYS_TAS_GCL_CT_CFG_HSCH_POS_SET(port->chip_port) |
|
||||
QSYS_TAS_GCL_CT_CFG_OP_TYPE_SET(LAN966X_TAPRIO_GCL_CMD_SET_GATE_STATES),
|
||||
lan966x, QSYS_TAS_GCL_CT_CFG);
|
||||
|
||||
lan_wr(QSYS_TAS_GCL_CT_CFG2_PORT_PROFILE_SET(port->chip_port) |
|
||||
QSYS_TAS_GCL_CT_CFG2_NEXT_GCL_SET(next_entry),
|
||||
lan966x, QSYS_TAS_GCL_CT_CFG2);
|
||||
|
||||
lan_wr(entry->interval, lan966x, QSYS_TAS_GCL_TM_CFG);
|
||||
}
|
||||
|
||||
static int lan966x_taprio_gcl_setup(struct lan966x_port *port,
|
||||
struct tc_taprio_qopt_offload *qopt,
|
||||
int list)
|
||||
{
|
||||
DECLARE_BITMAP(free_list, LAN966X_TAPRIO_NUM_GCL);
|
||||
struct lan966x *lan966x = port->lan966x;
|
||||
u32 i, base, next;
|
||||
|
||||
if (lan966x_taprio_gcl_free_get(port, free_list) < qopt->num_entries)
|
||||
return -ENOSPC;
|
||||
|
||||
/* Select list */
|
||||
lan_rmw(QSYS_TAS_CFG_CTRL_LIST_NUM_SET(list),
|
||||
QSYS_TAS_CFG_CTRL_LIST_NUM,
|
||||
lan966x, QSYS_TAS_CFG_CTRL);
|
||||
|
||||
/* Setup the address of the first gcl entry */
|
||||
base = find_first_bit(free_list, LAN966X_TAPRIO_NUM_GCL);
|
||||
lan_rmw(QSYS_TAS_LIST_CFG_LIST_BASE_ADDR_SET(base),
|
||||
QSYS_TAS_LIST_CFG_LIST_BASE_ADDR,
|
||||
lan966x, QSYS_TAS_LIST_CFG);
|
||||
|
||||
/* Iterate over entries and add them to the gcl list */
|
||||
next = base;
|
||||
for (i = 0; i < qopt->num_entries; ++i) {
|
||||
lan_rmw(QSYS_TAS_CFG_CTRL_GCL_ENTRY_NUM_SET(next),
|
||||
QSYS_TAS_CFG_CTRL_GCL_ENTRY_NUM,
|
||||
lan966x, QSYS_TAS_CFG_CTRL);
|
||||
|
||||
/* If the entry is last, point back to the start of the list */
|
||||
if (i == qopt->num_entries - 1)
|
||||
next = base;
|
||||
else
|
||||
next = find_next_bit(free_list, LAN966X_TAPRIO_NUM_GCL,
|
||||
next + 1);
|
||||
|
||||
lan966x_taprio_gcl_setup_entry(port, &qopt->entries[i], next);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Calculate new base_time based on cycle_time. The HW recommends to have the
|
||||
* new base time at least 2 * cycle type + current time
|
||||
*/
|
||||
static void lan966x_taprio_new_base_time(struct lan966x *lan966x,
|
||||
const u32 cycle_time,
|
||||
const ktime_t org_base_time,
|
||||
ktime_t *new_base_time)
|
||||
{
|
||||
ktime_t current_time, threshold_time;
|
||||
struct timespec64 ts;
|
||||
|
||||
/* Get the current time and calculate the threshold_time */
|
||||
lan966x_ptp_gettime64(&lan966x->phc[LAN966X_PHC_PORT].info, &ts);
|
||||
current_time = timespec64_to_ktime(ts);
|
||||
threshold_time = current_time + (2 * cycle_time);
|
||||
|
||||
/* If the org_base_time is in enough in future just use it */
|
||||
if (org_base_time >= threshold_time) {
|
||||
*new_base_time = org_base_time;
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the org_base_time is smaller than current_time, calculate the new
|
||||
* base time as following.
|
||||
*/
|
||||
if (org_base_time <= current_time) {
|
||||
u64 tmp = current_time - org_base_time;
|
||||
u32 rem = 0;
|
||||
|
||||
if (tmp > cycle_time)
|
||||
div_u64_rem(tmp, cycle_time, &rem);
|
||||
rem = cycle_time - rem;
|
||||
*new_base_time = threshold_time + rem;
|
||||
return;
|
||||
}
|
||||
|
||||
/* The only left place for org_base_time is between current_time and
|
||||
* threshold_time. In this case the new_base_time is calculated like
|
||||
* org_base_time + 2 * cycletime
|
||||
*/
|
||||
*new_base_time = org_base_time + 2 * cycle_time;
|
||||
}
|
||||
|
||||
int lan966x_taprio_speed_set(struct lan966x_port *port, int speed)
|
||||
{
|
||||
struct lan966x *lan966x = port->lan966x;
|
||||
u8 taprio_speed;
|
||||
|
||||
switch (speed) {
|
||||
case SPEED_10:
|
||||
taprio_speed = LAN966X_TAPRIO_SPEED_10;
|
||||
break;
|
||||
case SPEED_100:
|
||||
taprio_speed = LAN966X_TAPRIO_SPEED_100;
|
||||
break;
|
||||
case SPEED_1000:
|
||||
taprio_speed = LAN966X_TAPRIO_SPEED_1000;
|
||||
break;
|
||||
case SPEED_2500:
|
||||
taprio_speed = LAN966X_TAPRIO_SPEED_2500;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
lan_rmw(QSYS_TAS_PROFILE_CFG_LINK_SPEED_SET(taprio_speed),
|
||||
QSYS_TAS_PROFILE_CFG_LINK_SPEED,
|
||||
lan966x, QSYS_TAS_PROFILE_CFG(port->chip_port));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lan966x_taprio_add(struct lan966x_port *port,
|
||||
struct tc_taprio_qopt_offload *qopt)
|
||||
{
|
||||
struct lan966x *lan966x = port->lan966x;
|
||||
int err, new_list, obs_list;
|
||||
struct timespec64 ts;
|
||||
ktime_t base_time;
|
||||
|
||||
err = lan966x_taprio_check(qopt);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = lan966x_taprio_find_list(port, qopt, &new_list, &obs_list);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = lan966x_taprio_gcl_setup(port, qopt, new_list);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
lan966x_taprio_new_base_time(lan966x, qopt->cycle_time,
|
||||
qopt->base_time, &base_time);
|
||||
|
||||
ts = ktime_to_timespec64(base_time);
|
||||
lan_wr(QSYS_TAS_BT_NSEC_NSEC_SET(ts.tv_nsec),
|
||||
lan966x, QSYS_TAS_BT_NSEC);
|
||||
|
||||
lan_wr(lower_32_bits(ts.tv_sec),
|
||||
lan966x, QSYS_TAS_BT_SEC_LSB);
|
||||
|
||||
lan_wr(QSYS_TAS_BT_SEC_MSB_SEC_MSB_SET(upper_32_bits(ts.tv_sec)),
|
||||
lan966x, QSYS_TAS_BT_SEC_MSB);
|
||||
|
||||
lan_wr(qopt->cycle_time, lan966x, QSYS_TAS_CT_CFG);
|
||||
|
||||
lan_rmw(QSYS_TAS_STARTUP_CFG_OBSOLETE_IDX_SET(obs_list),
|
||||
QSYS_TAS_STARTUP_CFG_OBSOLETE_IDX,
|
||||
lan966x, QSYS_TAS_STARTUP_CFG);
|
||||
|
||||
/* Start list processing */
|
||||
lan_rmw(QSYS_TAS_LST_LIST_STATE_SET(LAN966X_TAPRIO_STATE_ADVANCING),
|
||||
QSYS_TAS_LST_LIST_STATE,
|
||||
lan966x, QSYS_TAS_LST);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int lan966x_taprio_del(struct lan966x_port *port)
|
||||
{
|
||||
return lan966x_taprio_shutdown(port);
|
||||
}
|
||||
|
||||
void lan966x_taprio_init(struct lan966x *lan966x)
|
||||
{
|
||||
int num_taprio_lists;
|
||||
int p;
|
||||
|
||||
lan_wr(QSYS_TAS_STM_CFG_REVISIT_DLY_SET((256 * 1000) /
|
||||
lan966x_ptp_get_period_ps()),
|
||||
lan966x, QSYS_TAS_STM_CFG);
|
||||
|
||||
num_taprio_lists = lan966x->num_phys_ports *
|
||||
LAN966X_TAPRIO_ENTRIES_PER_PORT;
|
||||
|
||||
/* For now we always use guard band on all queues */
|
||||
lan_rmw(QSYS_TAS_CFG_CTRL_LIST_NUM_MAX_SET(num_taprio_lists) |
|
||||
QSYS_TAS_CFG_CTRL_ALWAYS_GB_SCH_Q_SET(1),
|
||||
QSYS_TAS_CFG_CTRL_LIST_NUM_MAX |
|
||||
QSYS_TAS_CFG_CTRL_ALWAYS_GB_SCH_Q,
|
||||
lan966x, QSYS_TAS_CFG_CTRL);
|
||||
|
||||
for (p = 0; p < lan966x->num_phys_ports; p++)
|
||||
lan_rmw(QSYS_TAS_PROFILE_CFG_PORT_NUM_SET(p),
|
||||
QSYS_TAS_PROFILE_CFG_PORT_NUM,
|
||||
lan966x, QSYS_TAS_PROFILE_CFG(p));
|
||||
}
|
||||
|
||||
void lan966x_taprio_deinit(struct lan966x *lan966x)
|
||||
{
|
||||
int p;
|
||||
|
||||
for (p = 0; p < lan966x->num_phys_ports; ++p) {
|
||||
if (!lan966x->ports[p])
|
||||
continue;
|
||||
|
||||
lan966x_taprio_del(lan966x->ports[p]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
#include <net/pkt_cls.h>
|
||||
|
||||
#include "lan966x_main.h"
|
||||
|
||||
static int lan966x_tc_setup_qdisc_mqprio(struct lan966x_port *port,
|
||||
struct tc_mqprio_qopt_offload *mqprio)
|
||||
{
|
||||
u8 num_tc = mqprio->qopt.num_tc;
|
||||
|
||||
mqprio->qopt.hw = TC_MQPRIO_HW_OFFLOAD_TCS;
|
||||
|
||||
return num_tc ? lan966x_mqprio_add(port, num_tc) :
|
||||
lan966x_mqprio_del(port);
|
||||
}
|
||||
|
||||
static int lan966x_tc_setup_qdisc_taprio(struct lan966x_port *port,
|
||||
struct tc_taprio_qopt_offload *taprio)
|
||||
{
|
||||
return taprio->enable ? lan966x_taprio_add(port, taprio) :
|
||||
lan966x_taprio_del(port);
|
||||
}
|
||||
|
||||
int lan966x_tc_setup(struct net_device *dev, enum tc_setup_type type,
|
||||
void *type_data)
|
||||
{
|
||||
struct lan966x_port *port = netdev_priv(dev);
|
||||
|
||||
switch (type) {
|
||||
case TC_SETUP_QDISC_MQPRIO:
|
||||
return lan966x_tc_setup_qdisc_mqprio(port, type_data);
|
||||
case TC_SETUP_QDISC_TAPRIO:
|
||||
return lan966x_tc_setup_qdisc_taprio(port, type_data);
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue