mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2025-01-16 02:46:55 +07:00
1cf3299b03
Compared to other DSA switches, in the Ocelot cores, the RX filtering is a much more important concern. Firstly, the primary use case for Ocelot is non-DSA, so there isn't any secondary Ethernet MAC [the DSA master's one] to implicitly drop frames having a DMAC we are not interested in. So the switch driver itself needs to install FDB entries towards the CPU port module (PGID_CPU) for the MAC address of each switch port, in each VLAN installed on the port. Every address that is not whitelisted is implicitly dropped. This is in order to achieve a behavior similar to N standalone net devices. Secondly, even in the secondary use case of DSA, such as illustrated by Felix with the NPI port mode, that secondary Ethernet MAC is present, but its RX filter is bypassed. This is because the DSA tags themselves are placed before Ethernet, so the DMAC that the switch ports see is not seen by the DSA master too (since it's shifter to the right). So RX filtering is pretty important. A good RX filter won't bother the CPU in case the switch port receives a frame that it's not interested in, and there exists no other line of defense. Ocelot is pretty strict when it comes to RX filtering: non-IP multicast and broadcast traffic is allowed to go to the CPU port module, but unknown unicast isn't. This means that traffic reception for any other MAC addresses than the ones configured on each switch port net device won't work. This includes use cases such as macvlan or bridging with a non-Ocelot (so-called "foreign") interface. But this seems to be fine for the scenarios that the Linux system embedded inside an Ocelot switch is intended for - it is simply not interested in unknown unicast traffic, as explained in Allan Nielsen's presentation [0]. On the other hand, the Felix DSA switch is integrated in more general-purpose Linux systems, so it can't afford to drop that sort of traffic in hardware, even if it will end up doing so later, in software. Actually, unknown unicast means more for Felix than it does for Ocelot. Felix doesn't attempt to perform the whitelisting of switch port MAC addresses towards PGID_CPU at all, mainly because it is too complicated to be feasible: while the MAC addresses are unique in Ocelot, by default in DSA all ports are equal and inherited from the DSA master. This adds into account the question of reference counting MAC addresses (delayed ocelot_mact_forget), not to mention reference counting for the VLAN IDs that those MAC addresses are installed in. This reference counting should be done in the DSA core, and the fact that it wasn't needed so far is due to the fact that the other DSA switches don't have the DSA tag placed before Ethernet, so the DSA master is able to whitelist the MAC addresses in hardware. So this means that even regular traffic termination on a Felix switch port happens through flooding (because neither Felix nor Ocelot learn source MAC addresses from CPU-injected frames). So far we've explained that whitelisting towards PGID_CPU: - helps to reduce the likelihood of spamming the CPU with frames it won't process very far anyway - is implemented in the ocelot driver - is sufficient for the ocelot use cases - is not feasible in DSA - breaks use cases in DSA, in the current status (whitelisting enabled but no MAC address whitelisted) So the proposed patch allows unknown unicast frames to be sent to the CPU port module. This is done for the Felix DSA driver only, as Ocelot seems to be happy without it. [0]: https://www.youtube.com/watch?v=B1HhxEcU7Jg Suggested-by: Allan W. Nielsen <allan.nielsen@microchip.com> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Reviewed-by: Allan W. Nielsen <allan.nielsen@microchip.com> Signed-off-by: David S. Miller <davem@davemloft.net>
89 lines
2.2 KiB
C
89 lines
2.2 KiB
C
/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
|
|
/*
|
|
* Microsemi Ocelot Switch driver
|
|
*
|
|
* Copyright (c) 2017 Microsemi Corporation
|
|
*/
|
|
|
|
#ifndef _MSCC_OCELOT_H_
|
|
#define _MSCC_OCELOT_H_
|
|
|
|
#include <linux/bitops.h>
|
|
#include <linux/etherdevice.h>
|
|
#include <linux/if_vlan.h>
|
|
#include <linux/net_tstamp.h>
|
|
#include <linux/phy.h>
|
|
#include <linux/phy/phy.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/ptp_clock_kernel.h>
|
|
#include <linux/regmap.h>
|
|
|
|
#include <soc/mscc/ocelot_qsys.h>
|
|
#include <soc/mscc/ocelot_sys.h>
|
|
#include <soc/mscc/ocelot_dev.h>
|
|
#include <soc/mscc/ocelot_ana.h>
|
|
#include <soc/mscc/ocelot.h>
|
|
#include "ocelot_rew.h"
|
|
#include "ocelot_qs.h"
|
|
#include "ocelot_tc.h"
|
|
#include "ocelot_ptp.h"
|
|
|
|
#define OCELOT_BUFFER_CELL_SZ 60
|
|
|
|
#define OCELOT_STATS_CHECK_DELAY (2 * HZ)
|
|
|
|
#define OCELOT_PTP_QUEUE_SZ 128
|
|
|
|
struct frame_info {
|
|
u32 len;
|
|
u16 port;
|
|
u16 vid;
|
|
u8 tag_type;
|
|
u16 rew_op;
|
|
u32 timestamp; /* rew_val */
|
|
};
|
|
|
|
struct ocelot_multicast {
|
|
struct list_head list;
|
|
unsigned char addr[ETH_ALEN];
|
|
u16 vid;
|
|
u16 ports;
|
|
};
|
|
|
|
struct ocelot_port_private {
|
|
struct ocelot_port port;
|
|
struct net_device *dev;
|
|
struct phy_device *phy;
|
|
u8 chip_port;
|
|
|
|
u8 vlan_aware;
|
|
|
|
struct phy *serdes;
|
|
|
|
struct ocelot_port_tc tc;
|
|
};
|
|
|
|
u32 ocelot_port_readl(struct ocelot_port *port, u32 reg);
|
|
void ocelot_port_writel(struct ocelot_port *port, u32 val, u32 reg);
|
|
|
|
#define ocelot_field_write(ocelot, reg, val) regmap_field_write((ocelot)->regfields[(reg)], (val))
|
|
#define ocelot_field_read(ocelot, reg, val) regmap_field_read((ocelot)->regfields[(reg)], (val))
|
|
|
|
int ocelot_chip_init(struct ocelot *ocelot, const struct ocelot_ops *ops);
|
|
int ocelot_probe_port(struct ocelot *ocelot, u8 port,
|
|
void __iomem *regs,
|
|
struct phy_device *phy);
|
|
|
|
void ocelot_set_cpu_port(struct ocelot *ocelot, int cpu,
|
|
enum ocelot_tag_prefix injection,
|
|
enum ocelot_tag_prefix extraction);
|
|
|
|
extern struct notifier_block ocelot_netdevice_nb;
|
|
extern struct notifier_block ocelot_switchdev_nb;
|
|
extern struct notifier_block ocelot_switchdev_blocking_nb;
|
|
|
|
#define ocelot_field_write(ocelot, reg, val) regmap_field_write((ocelot)->regfields[(reg)], (val))
|
|
#define ocelot_field_read(ocelot, reg, val) regmap_field_read((ocelot)->regfields[(reg)], (val))
|
|
|
|
#endif
|