mirror of
https://github.com/nxp-imx/linux-imx.git
synced 2026-01-27 12:35:36 +01:00
net: dsa: felix: add tsn support for felix switch based on net/tsn
VSC9959 has hardware TSN features. Allow the following to be configured through the tsntool netlink interface: - IEEE 802.1Qbv - IEEE 802.1Qbu/802.3br - IEEE 802.1Qci - IEEE 802.1Qav - IEEE 802.1CB This patch is based on netlink adaptation layer in net/tsn/*. The functionality is automatically enabled if CONFIG_TSN=y or m. Signed-off-by: Xiaoliang Yang <xiaoliang.yang_1@nxp.com> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
This commit is contained in:
parent
aac0120422
commit
4d63133f7d
|
|
@ -37,6 +37,7 @@ config NET_DSA_MSCC_FELIX
|
|||
depends on HAS_IOMEM
|
||||
depends on PTP_1588_CLOCK_OPTIONAL
|
||||
depends on NET_SCH_TAPRIO || NET_SCH_TAPRIO=n
|
||||
depends on TSN || TSN=n
|
||||
select MSCC_OCELOT_SWITCH_LIB
|
||||
select NET_DSA_MSCC_FELIX_DSA_LIB
|
||||
select NET_DSA_TAG_OCELOT_8021Q
|
||||
|
|
|
|||
|
|
@ -8,3 +8,7 @@ mscc_felix_dsa_lib-objs := felix.o
|
|||
mscc_felix-objs := felix_vsc9959.o
|
||||
mscc_ocelot_ext-objs := ocelot_ext.o
|
||||
mscc_seville-objs := seville_vsc9953.o
|
||||
|
||||
ifdef CONFIG_TSN
|
||||
mscc_felix-objs += felix_tsn.o
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -1454,6 +1454,10 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports)
|
|||
ocelot_port->ocelot = ocelot;
|
||||
ocelot_port->target = target;
|
||||
ocelot_port->index = port;
|
||||
/* Enable cut-through forwarding on all traffic classes by
|
||||
* default, to be compatible with the upstream kernel.
|
||||
*/
|
||||
ocelot_port->cut_thru = GENMASK(7, 0);
|
||||
ocelot->ports[port] = ocelot_port;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -102,5 +102,7 @@ struct felix {
|
|||
|
||||
struct net_device *felix_port_to_netdev(struct ocelot *ocelot, int port);
|
||||
int felix_netdev_to_port(struct net_device *dev);
|
||||
void vsc9959_new_base_time(struct ocelot *ocelot, ktime_t base_time,
|
||||
u64 cycle_time, struct timespec64 *new_base_ts);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
1516
drivers/net/dsa/ocelot/felix_tsn.c
Normal file
1516
drivers/net/dsa/ocelot/felix_tsn.c
Normal file
File diff suppressed because it is too large
Load Diff
32
drivers/net/dsa/ocelot/felix_tsn.h
Normal file
32
drivers/net/dsa/ocelot/felix_tsn.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/* SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
||||
*
|
||||
* TSN support for Felix VSC9959 through tsntool
|
||||
*
|
||||
* Copyright 2020-2023 NXP
|
||||
*/
|
||||
|
||||
#ifndef _MSCC_FELIX_SWITCH_TSN_H_
|
||||
#define _MSCC_FELIX_SWITCH_TSN_H_
|
||||
|
||||
#include <soc/mscc/ocelot.h>
|
||||
#include <net/dsa.h>
|
||||
|
||||
#if IS_ENABLED(CONFIG_TSN)
|
||||
|
||||
void felix_cbs_reset(struct ocelot *ocelot, int port, u32 speed);
|
||||
void felix_tsn_enable(struct dsa_switch *ds);
|
||||
|
||||
#else
|
||||
|
||||
static inline void felix_cbs_reset(struct ocelot *ocelot, int port,
|
||||
u32 speed)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void felix_tsn_enable(struct dsa_switch *ds)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/of.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/time.h>
|
||||
#include "felix_tsn.h"
|
||||
#include "felix.h"
|
||||
|
||||
#define VSC9959_NUM_PORTS 6
|
||||
|
|
@ -1379,11 +1380,12 @@ static void vsc9959_sched_speed_set(struct ocelot *ocelot, int port,
|
|||
vsc9959_tas_guard_bands_update(ocelot, port);
|
||||
|
||||
mutex_unlock(&ocelot->fwd_domain_lock);
|
||||
|
||||
felix_cbs_reset(ocelot, port, speed);
|
||||
}
|
||||
|
||||
static void vsc9959_new_base_time(struct ocelot *ocelot, ktime_t base_time,
|
||||
u64 cycle_time,
|
||||
struct timespec64 *new_base_ts)
|
||||
void vsc9959_new_base_time(struct ocelot *ocelot, ktime_t base_time,
|
||||
u64 cycle_time, struct timespec64 *new_base_ts)
|
||||
{
|
||||
struct timespec64 ts;
|
||||
ktime_t new_base_time;
|
||||
|
|
@ -2585,7 +2587,7 @@ static void vsc9959_cut_through_fwd(struct ocelot *ocelot)
|
|||
* reason, if sent as cut-through.
|
||||
*/
|
||||
if (ocelot_port->speed == min_speed) {
|
||||
val = GENMASK(7, 0) & ~mm->active_preemptible_tcs;
|
||||
val = ocelot_port->cut_thru & ~mm->active_preemptible_tcs;
|
||||
|
||||
for (tc = 0; tc < OCELOT_NUM_TC; tc++)
|
||||
if (vsc9959_port_qmaxsdu_get(ocelot, port, tc))
|
||||
|
|
@ -2728,6 +2730,8 @@ static int felix_pci_probe(struct pci_dev *pdev,
|
|||
goto err_register_ds;
|
||||
}
|
||||
|
||||
felix_tsn_enable(ds);
|
||||
|
||||
return 0;
|
||||
|
||||
err_register_ds:
|
||||
|
|
|
|||
|
|
@ -21,12 +21,6 @@
|
|||
|
||||
#define OCELOT_RSV_VLAN_RANGE_START 4000
|
||||
|
||||
struct ocelot_mact_entry {
|
||||
u8 mac[ETH_ALEN];
|
||||
u16 vid;
|
||||
enum macaccess_entry_type type;
|
||||
};
|
||||
|
||||
/* Caller must hold &ocelot->mact_lock */
|
||||
static inline u32 ocelot_mact_read_macaccess(struct ocelot *ocelot)
|
||||
{
|
||||
|
|
@ -1259,10 +1253,10 @@ int ocelot_fdb_del(struct ocelot *ocelot, int port, const unsigned char *addr,
|
|||
EXPORT_SYMBOL(ocelot_fdb_del);
|
||||
|
||||
/* Caller must hold &ocelot->mact_lock */
|
||||
static int ocelot_mact_read(struct ocelot *ocelot, int port, int row, int col,
|
||||
struct ocelot_mact_entry *entry)
|
||||
int ocelot_mact_read(struct ocelot *ocelot, int row, int col, int *dst,
|
||||
struct ocelot_mact_entry *entry)
|
||||
{
|
||||
u32 val, dst, macl, mach;
|
||||
u32 val, macl, mach;
|
||||
char mac[ETH_ALEN];
|
||||
|
||||
/* Set row and column to read from */
|
||||
|
|
@ -1282,12 +1276,9 @@ static int ocelot_mact_read(struct ocelot *ocelot, int port, int row, int col,
|
|||
if (!(val & ANA_TABLES_MACACCESS_VALID))
|
||||
return -EINVAL;
|
||||
|
||||
/* If the entry read has another port configured as its destination,
|
||||
* do not report it.
|
||||
*/
|
||||
dst = (val & ANA_TABLES_MACACCESS_DEST_IDX_M) >> 3;
|
||||
if (dst != port)
|
||||
return -EINVAL;
|
||||
*dst = (val & ANA_TABLES_MACACCESS_DEST_IDX_M) >> 3;
|
||||
|
||||
entry->type = ANA_TABLES_MACACCESS_ENTRYTYPE_X(val);
|
||||
|
||||
/* Get the entry's MAC address and VLAN id */
|
||||
macl = ocelot_read(ocelot, ANA_TABLES_MACLDATA);
|
||||
|
|
@ -1305,6 +1296,7 @@ static int ocelot_mact_read(struct ocelot *ocelot, int port, int row, int col,
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ocelot_mact_read);
|
||||
|
||||
int ocelot_mact_flush(struct ocelot *ocelot, int port)
|
||||
{
|
||||
|
|
@ -1359,16 +1351,18 @@ int ocelot_fdb_dump(struct ocelot *ocelot, int port,
|
|||
for (j = 0; j < 4; j++) {
|
||||
struct ocelot_mact_entry entry;
|
||||
bool is_static;
|
||||
int dst;
|
||||
|
||||
err = ocelot_mact_read(ocelot, port, i, j, &entry);
|
||||
/* If the entry is invalid (wrong port, invalid...),
|
||||
* skip it.
|
||||
*/
|
||||
err = ocelot_mact_read(ocelot, i, j, &dst, &entry);
|
||||
/* If the entry is invalid, skip it. */
|
||||
if (err == -EINVAL)
|
||||
continue;
|
||||
else if (err)
|
||||
break;
|
||||
|
||||
if (dst != port)
|
||||
continue;
|
||||
|
||||
is_static = (entry.type == ENTRYTYPE_LOCKED);
|
||||
|
||||
/* Hide the reserved VLANs used for
|
||||
|
|
@ -1721,6 +1715,42 @@ void ocelot_port_unassign_dsa_8021q_cpu(struct ocelot *ocelot, int port)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(ocelot_port_unassign_dsa_8021q_cpu);
|
||||
|
||||
void ocelot_bridge_force_forward_port(struct ocelot *ocelot, int port, bool en)
|
||||
{
|
||||
struct ocelot_port *ocelot_port = ocelot->ports[port];
|
||||
u32 mask;
|
||||
int i;
|
||||
|
||||
mutex_lock(&ocelot->fwd_domain_lock);
|
||||
|
||||
if (!en) {
|
||||
if (ocelot_port->force_forward) {
|
||||
ocelot_apply_bridge_fwd_mask(ocelot, false);
|
||||
ocelot_port->force_forward = 0;
|
||||
}
|
||||
mutex_unlock(&ocelot->fwd_domain_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ocelot_port->force_forward) {
|
||||
mutex_unlock(&ocelot->fwd_domain_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
ocelot_port->force_forward = 1;
|
||||
for (i = 0; i < ocelot->num_phys_ports; i++) {
|
||||
if (i == port)
|
||||
continue;
|
||||
|
||||
mask = ocelot_read_rix(ocelot, ANA_PGID_PGID, PGID_SRC + i);
|
||||
mask |= BIT(port);
|
||||
ocelot_write_rix(ocelot, mask, ANA_PGID_PGID, PGID_SRC + i);
|
||||
}
|
||||
|
||||
mutex_unlock(&ocelot->fwd_domain_lock);
|
||||
}
|
||||
EXPORT_SYMBOL(ocelot_bridge_force_forward_port);
|
||||
|
||||
void ocelot_bridge_stp_state_set(struct ocelot *ocelot, int port, u8 state)
|
||||
{
|
||||
struct ocelot_port *ocelot_port = ocelot->ports[port];
|
||||
|
|
@ -2733,7 +2763,9 @@ int ocelot_port_mqprio(struct ocelot *ocelot, int port,
|
|||
if (err)
|
||||
goto err_reset_tc;
|
||||
|
||||
ocelot_port_change_fp(ocelot, port, mqprio->preemptible_tcs);
|
||||
err = ocelot_port_change_fp(ocelot, port, mqprio->preemptible_tcs);
|
||||
if (err)
|
||||
goto err_reset_tc;
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -114,8 +114,6 @@ int ocelot_stats_init(struct ocelot *ocelot);
|
|||
void ocelot_stats_deinit(struct ocelot *ocelot);
|
||||
|
||||
int ocelot_mm_init(struct ocelot *ocelot);
|
||||
void ocelot_port_change_fp(struct ocelot *ocelot, int port,
|
||||
unsigned long preemptible_tcs);
|
||||
void ocelot_port_update_active_preemptible_tcs(struct ocelot *ocelot, int port);
|
||||
|
||||
extern struct notifier_block ocelot_netdevice_nb;
|
||||
|
|
|
|||
|
|
@ -87,20 +87,30 @@ void ocelot_port_update_active_preemptible_tcs(struct ocelot *ocelot, int port)
|
|||
QSYS_PREEMPTION_CFG, port);
|
||||
}
|
||||
|
||||
void ocelot_port_change_fp(struct ocelot *ocelot, int port,
|
||||
unsigned long preemptible_tcs)
|
||||
int ocelot_port_change_fp(struct ocelot *ocelot, int port,
|
||||
unsigned long preemptible_tcs)
|
||||
{
|
||||
struct ocelot_port *ocelot_port = ocelot->ports[port];
|
||||
struct ocelot_mm_state *mm = &ocelot->mm[port];
|
||||
|
||||
lockdep_assert_held(&ocelot->fwd_domain_lock);
|
||||
|
||||
if (ocelot_port->cut_thru_selected_by_user & preemptible_tcs) {
|
||||
dev_err(ocelot->dev,
|
||||
"A traffic class cannot be preemptible and cut-through at the same time.\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (mm->preemptible_tcs == preemptible_tcs)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
mm->preemptible_tcs = preemptible_tcs;
|
||||
|
||||
ocelot_port_update_active_preemptible_tcs(ocelot, port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ocelot_port_change_fp);
|
||||
|
||||
static void ocelot_mm_update_port_status(struct ocelot *ocelot, int port)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ struct tc_mqprio_qopt_offload;
|
|||
*/
|
||||
|
||||
/* Reserve some destination PGIDs at the end of the range:
|
||||
* PGID_FRER: Destinations for multicast traffic in 802.1CB redundant network.
|
||||
* PGID_BLACKHOLE: used for not forwarding the frames
|
||||
* PGID_CPU: used for whitelisting certain MAC addresses, such as the addresses
|
||||
* of the switch port net devices, towards the CPU port module.
|
||||
|
|
@ -63,6 +64,7 @@ struct tc_mqprio_qopt_offload;
|
|||
* PGID_MCIPV6: the flooding destinations for IPv6 multicast traffic.
|
||||
* PGID_BC: the flooding destinations for broadcast traffic.
|
||||
*/
|
||||
#define PGID_FRER 56
|
||||
#define PGID_BLACKHOLE 57
|
||||
#define PGID_CPU 58
|
||||
#define PGID_UC 59
|
||||
|
|
@ -78,7 +80,7 @@ struct tc_mqprio_qopt_offload;
|
|||
|
||||
#define for_each_nonreserved_multicast_dest_pgid(ocelot, pgid) \
|
||||
for ((pgid) = (ocelot)->num_phys_ports + 1; \
|
||||
(pgid) < PGID_BLACKHOLE; \
|
||||
(pgid) < PGID_FRER; \
|
||||
(pgid)++)
|
||||
|
||||
#define for_each_aggr_pgid(ocelot, pgid) \
|
||||
|
|
@ -732,6 +734,12 @@ enum macaccess_entry_type {
|
|||
ENTRYTYPE_MACv6,
|
||||
};
|
||||
|
||||
struct ocelot_mact_entry {
|
||||
u8 mac[ETH_ALEN];
|
||||
u16 vid;
|
||||
enum macaccess_entry_type type;
|
||||
};
|
||||
|
||||
enum ocelot_proto {
|
||||
OCELOT_PROTO_PTP_L2 = BIT(0),
|
||||
OCELOT_PROTO_PTP_L4 = BIT(1),
|
||||
|
|
@ -801,6 +809,10 @@ struct ocelot_port {
|
|||
|
||||
int bridge_num;
|
||||
|
||||
bool force_forward;
|
||||
u8 cut_thru;
|
||||
u8 cut_thru_selected_by_user;
|
||||
|
||||
int speed;
|
||||
};
|
||||
|
||||
|
|
@ -895,6 +907,22 @@ struct ocelot_policer {
|
|||
u32 burst; /* bytes */
|
||||
};
|
||||
|
||||
int ocelot_mact_read(struct ocelot *ocelot, int row, int col, int *dst,
|
||||
struct ocelot_mact_entry *entry);
|
||||
int ocelot_mact_learn(struct ocelot *ocelot, int port,
|
||||
const unsigned char mac[ETH_ALEN],
|
||||
unsigned int vid, enum macaccess_entry_type type);
|
||||
int ocelot_mact_forget(struct ocelot *ocelot, const unsigned char mac[ETH_ALEN],
|
||||
unsigned int vid);
|
||||
int ocelot_mact_lookup(struct ocelot *ocelot, int *dst_idx,
|
||||
const unsigned char mac[ETH_ALEN],
|
||||
unsigned int vid, enum macaccess_entry_type *type);
|
||||
int ocelot_mact_learn_streamdata(struct ocelot *ocelot, int dst_idx,
|
||||
const unsigned char mac[ETH_ALEN],
|
||||
unsigned int vid,
|
||||
enum macaccess_entry_type type,
|
||||
int sfid, int ssid);
|
||||
|
||||
#define ocelot_bulk_read(ocelot, reg, buf, count) \
|
||||
__ocelot_bulk_read_ix(ocelot, reg, 0, buf, count)
|
||||
|
||||
|
|
@ -1022,6 +1050,7 @@ int ocelot_get_ts_info(struct ocelot *ocelot, int port,
|
|||
void ocelot_set_ageing_time(struct ocelot *ocelot, unsigned int msecs);
|
||||
int ocelot_port_vlan_filtering(struct ocelot *ocelot, int port, bool enabled,
|
||||
struct netlink_ext_ack *extack);
|
||||
void ocelot_bridge_force_forward_port(struct ocelot *ocelot, int port, bool en);
|
||||
void ocelot_bridge_stp_state_set(struct ocelot *ocelot, int port, u8 state);
|
||||
u32 ocelot_get_bridge_fwd_mask(struct ocelot *ocelot, int src_port);
|
||||
int ocelot_port_pre_bridge_flags(struct ocelot *ocelot, int port,
|
||||
|
|
@ -1164,6 +1193,8 @@ int ocelot_port_get_mm(struct ocelot *ocelot, int port,
|
|||
struct ethtool_mm_state *state);
|
||||
int ocelot_port_mqprio(struct ocelot *ocelot, int port,
|
||||
struct tc_mqprio_qopt_offload *mqprio);
|
||||
int ocelot_port_change_fp(struct ocelot *ocelot, int port,
|
||||
unsigned long preemptible_tcs);
|
||||
|
||||
#if IS_ENABLED(CONFIG_BRIDGE_MRP)
|
||||
int ocelot_mrp_add(struct ocelot *ocelot, int port,
|
||||
|
|
|
|||
|
|
@ -138,6 +138,9 @@
|
|||
#define MACACCESS_CMD_READ 6
|
||||
#define MACACCESS_CMD_WRITE 7
|
||||
|
||||
#define MACACCESS_ENTRY_TYPE_NORMAL 0
|
||||
#define MACACCESS_ENTRY_TYPE_LOCKED 1
|
||||
|
||||
#define ANA_TABLES_VLANACCESS_VLAN_PORT_MASK(x) (((x) << 2) & GENMASK(13, 2))
|
||||
#define ANA_TABLES_VLANACCESS_VLAN_PORT_MASK_M GENMASK(13, 2)
|
||||
#define ANA_TABLES_VLANACCESS_VLAN_PORT_MASK_X(x) (((x) & GENMASK(13, 2)) >> 2)
|
||||
|
|
@ -271,6 +274,9 @@
|
|||
|
||||
#define ANA_SG_GCL_GS_CONFIG_IPS(x) ((x) & GENMASK(3, 0))
|
||||
#define ANA_SG_GCL_GS_CONFIG_IPS_M GENMASK(3, 0)
|
||||
#define ANA_SG_GCL_GS_CONFIG_IPV_VALID BIT(3)
|
||||
#define ANA_SG_GCL_GS_CONFIG_IPV(x) ((x) & GENMASK(2, 0))
|
||||
#define ANA_SG_GCL_GS_CONFIG_IPV_M GENMASK(2, 0)
|
||||
#define ANA_SG_GCL_GS_CONFIG_GATE_STATE BIT(4)
|
||||
|
||||
#define ANA_SG_GCL_TI_CONFIG_RSZ 0x4
|
||||
|
|
@ -281,6 +287,10 @@
|
|||
#define ANA_SG_STATUS_REG_3_IPS(x) (((x) << 20) & GENMASK(23, 20))
|
||||
#define ANA_SG_STATUS_REG_3_IPS_M GENMASK(23, 20)
|
||||
#define ANA_SG_STATUS_REG_3_IPS_X(x) (((x) & GENMASK(23, 20)) >> 20)
|
||||
#define ANA_SG_STATUS_REG_3_IPV_VALID BIT(23)
|
||||
#define ANA_SG_STATUS_REG_3_IPV(x) (((x) << 20) & GENMASK(22, 20))
|
||||
#define ANA_SG_STATUS_REG_3_IPV_M GENMASK(22, 20)
|
||||
#define ANA_SG_STATUS_REG_3_IPV_X(x) (((x) & GENMASK(22, 20)) >> 20)
|
||||
#define ANA_SG_STATUS_REG_3_CONFIG_PENDING BIT(24)
|
||||
|
||||
#define ANA_PORT_VLAN_CFG_GSZ 0x100
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user