mirror of
https://github.com/openwrt/openwrt.git
synced 2026-10-12 06:57:57 +04:00
realtek: eth: drop the RTL839x L2 notification code
On RTL839x the ethernet driver turns on the L2 notification engine and passes its learn and age events to the bridge. It reports them against the conduit, which is not a bridge port, so br_switchdev_event() drops every one of them. Nothing else reads them. RTL838x, RTL930x and RTL931x run without this code. Drop the notification setup, its interrupt handling and ring, and the NIC reset code that preserved them. The vendor SDK defines no interrupt in the mask bits this code also set on the other families: bits 20-22 of DMA_IF_INTR_MSK on RTL838x, bits 4-6 of DMA_IF_INTR_TX_DONE_MSK on RTL930x and RTL931x. Tested on an HPE 1920-48G (RTL8393): - after boot, L2_NOTIFICATION_CTRL reads 0x00001002 (engine off) and DMA_IF_INTR_MSK has none of bits 20-22 set; - the switch still learns the hosts behind its ports; - a route offloaded with IPv4 forwarding off still delivers 8 of 8 echoes. This does not stop the resets on a full bridge fdb show on that switch: they happen with or without this code. Assisted-by: Claude:claude-opus-5-5 Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net> Link: https://github.com/openwrt/openwrt/pull/25776 Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
This commit is contained in:
1 parent
884ab21a3a
commit
5d9fa15647
2 files changed
+4
-166
No files matched your search
@@ -25,7 +25,6 @@
|
||||
#include <net/dsa.h>
|
||||
#include <net/dst_metadata.h>
|
||||
#include <net/page_pool/helpers.h>
|
||||
#include <net/switchdev.h>
|
||||
|
||||
#include "rtl838x_eth.h"
|
||||
|
||||
@@ -110,7 +109,7 @@ static void rteth_93xx_enable_rx_irq(struct rteth_ctrl *ctrl, int ring)
|
||||
}
|
||||
|
||||
static void rteth_83xx_confirm_disable_irqs(struct rteth_ctrl *ctrl,
|
||||
unsigned long *rings, bool *l2)
|
||||
unsigned long *rings)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 disable, state;
|
||||
@@ -119,7 +118,6 @@ static void rteth_83xx_confirm_disable_irqs(struct rteth_ctrl *ctrl,
|
||||
|
||||
regmap_read(ctrl->map, ctrl->cfg->dma_if_intr_sts, &state);
|
||||
*rings = FIELD_GET(GENMASK(7, 0), state) | FIELD_GET(GENMASK(15, 8), state);
|
||||
*l2 = !!(state & RTETH_839X_DMA_IF_INTR_NOTIFY_MASK);
|
||||
disable = FIELD_PREP(GENMASK(7, 0), *rings) | FIELD_PREP(GENMASK(15, 8), *rings);
|
||||
|
||||
regmap_clear_bits(ctrl->map, ctrl->cfg->dma_if_intr_msk, disable);
|
||||
@@ -129,7 +127,7 @@ static void rteth_83xx_confirm_disable_irqs(struct rteth_ctrl *ctrl,
|
||||
}
|
||||
|
||||
static void rteth_93xx_confirm_disable_irqs(struct rteth_ctrl *ctrl,
|
||||
unsigned long *rings, bool *l2)
|
||||
unsigned long *rings)
|
||||
{
|
||||
u32 state_done, state_runout;
|
||||
unsigned long flags;
|
||||
@@ -139,7 +137,6 @@ static void rteth_93xx_confirm_disable_irqs(struct rteth_ctrl *ctrl,
|
||||
regmap_read(ctrl->map, ctrl->cfg->dma_if_intr_sts, &state_runout);
|
||||
regmap_read(ctrl->map, ctrl->cfg->dma_if_intr_sts + 4, &state_done);
|
||||
*rings = state_runout | state_done;
|
||||
*l2 = false;
|
||||
|
||||
regmap_clear_bits(ctrl->map, ctrl->cfg->dma_if_intr_msk, *rings);
|
||||
regmap_clear_bits(ctrl->map, ctrl->cfg->dma_if_intr_msk + 4, *rings);
|
||||
@@ -161,18 +158,8 @@ static void rteth_disable_all_irqs(struct rteth_ctrl *ctrl)
|
||||
|
||||
static void rteth_enable_all_rx_irqs(struct rteth_ctrl *ctrl)
|
||||
{
|
||||
int mask, reg;
|
||||
|
||||
for (int ring = 0; ring < RTETH_RX_RINGS; ring++)
|
||||
ctrl->cfg->enable_rx_irq(ctrl, ring);
|
||||
|
||||
/*
|
||||
* RTL839x has additional L2 notification interrupts. Simply activate them. All other
|
||||
* devices that do not have the feature have adequate reserved bit space and ignore it.
|
||||
*/
|
||||
mask = GENMASK(2, 0) << ((ctrl->cfg->rx_rings * 2 + 4) % 32);
|
||||
reg = (ctrl->cfg->rx_rings * 2 + 4) / 32;
|
||||
regmap_update_bits(ctrl->map, ctrl->cfg->dma_if_intr_msk + reg * 4, mask, mask);
|
||||
}
|
||||
|
||||
static void rteth_83xx_update_counter(struct rteth_ctrl *ctrl, int ring, int released)
|
||||
@@ -239,88 +226,18 @@ static bool rteth_93xx_decode_tag(struct rteth_frag *frag, struct rteth_dsa_tag
|
||||
return t->l2_offloaded;
|
||||
}
|
||||
|
||||
struct fdb_update_work {
|
||||
struct work_struct work;
|
||||
struct net_device *dev;
|
||||
u64 macs[RTETH_NOTIFY_EVENTS + 1];
|
||||
};
|
||||
|
||||
static void rtl838x_fdb_sync(struct work_struct *work)
|
||||
{
|
||||
const struct fdb_update_work *uw = container_of(work, struct fdb_update_work, work);
|
||||
|
||||
for (int i = 0; uw->macs[i]; i++) {
|
||||
struct switchdev_notifier_fdb_info info;
|
||||
u8 addr[ETH_ALEN];
|
||||
int action;
|
||||
|
||||
action = (uw->macs[i] & (1ULL << 63)) ?
|
||||
SWITCHDEV_FDB_ADD_TO_BRIDGE :
|
||||
SWITCHDEV_FDB_DEL_TO_BRIDGE;
|
||||
u64_to_ether_addr(uw->macs[i] & 0xffffffffffffULL, addr);
|
||||
info.addr = &addr[0];
|
||||
info.vid = 0;
|
||||
info.offloaded = 1;
|
||||
pr_debug("FDB entry %d: %llx, action %d\n", i, uw->macs[0], action);
|
||||
call_switchdev_notifiers(action, uw->dev, &info.info, NULL);
|
||||
}
|
||||
kfree(work);
|
||||
}
|
||||
|
||||
static void rtl839x_l2_notification_handler(struct rteth_ctrl *ctrl)
|
||||
{
|
||||
struct notify_b *nb = ctrl->membase;
|
||||
u32 e = ctrl->lastEvent;
|
||||
|
||||
while (!(nb->ring[e] & 1)) {
|
||||
struct fdb_update_work *w;
|
||||
struct n_event *event;
|
||||
u64 mac;
|
||||
int i;
|
||||
|
||||
w = kzalloc(sizeof(*w), GFP_ATOMIC);
|
||||
if (!w)
|
||||
return;
|
||||
|
||||
INIT_WORK(&w->work, rtl838x_fdb_sync);
|
||||
|
||||
for (i = 0; i < RTETH_NOTIFY_EVENTS; i++) {
|
||||
event = &nb->blocks[e].events[i];
|
||||
if (!event->valid)
|
||||
continue;
|
||||
mac = event->mac;
|
||||
if (event->type)
|
||||
mac |= 1ULL << 63;
|
||||
w->dev = ctrl->dev;
|
||||
w->macs[i] = mac;
|
||||
}
|
||||
|
||||
/* Hand the ring entry back to the switch */
|
||||
nb->ring[e] = nb->ring[e] | 1;
|
||||
e = (e + 1) % RTETH_NOTIFY_BLOCKS;
|
||||
|
||||
w->macs[i] = 0ULL;
|
||||
schedule_work(&w->work);
|
||||
}
|
||||
ctrl->lastEvent = e;
|
||||
}
|
||||
|
||||
static irqreturn_t rteth_net_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct net_device *dev = dev_id;
|
||||
struct rteth_ctrl *ctrl = netdev_priv(dev);
|
||||
unsigned long ring, rings;
|
||||
bool l2;
|
||||
|
||||
ctrl->cfg->confirm_disable_irqs(ctrl, &rings, &l2);
|
||||
ctrl->cfg->confirm_disable_irqs(ctrl, &rings);
|
||||
for_each_set_bit(ring, &rings, RTETH_RX_RINGS) {
|
||||
netdev_dbg(dev, "schedule rx ring %lu\n", ring);
|
||||
napi_schedule(&ctrl->rx_info[ring].napi);
|
||||
}
|
||||
|
||||
if (unlikely(l2))
|
||||
rtl839x_l2_notification_handler(ctrl);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@@ -353,12 +270,6 @@ static void rteth_838x_hw_reset(struct rteth_ctrl *ctrl)
|
||||
|
||||
static void rteth_839x_hw_reset(struct rteth_ctrl *ctrl)
|
||||
{
|
||||
u32 int_saved, nbuf;
|
||||
|
||||
/* Preserve L2 notification and NBUF settings */
|
||||
regmap_read(ctrl->map, ctrl->cfg->dma_if_intr_msk, &int_saved);
|
||||
regmap_read(ctrl->map, RTETH_839X_DMA_IF_NBUF_BASE_CTRL, &nbuf);
|
||||
|
||||
/* Disable link change interrupt on RTL839x */
|
||||
regmap_write(ctrl->map, RTETH_839X_IMR_PORT_LINK_STS_CHG, 0);
|
||||
regmap_write(ctrl->map, RTETH_839X_IMR_PORT_LINK_STS_CHG + 4, 0);
|
||||
@@ -370,10 +281,6 @@ static void rteth_839x_hw_reset(struct rteth_ctrl *ctrl)
|
||||
regmap_write(ctrl->map, RTETH_839X_ISR_PORT_LINK_STS_CHG + 4, 0xffffffff);
|
||||
regmap_write(ctrl->map, RTETH_839X_IMR_PORT_LINK_STS_CHG, 0xffffffff);
|
||||
regmap_write(ctrl->map, RTETH_839X_IMR_PORT_LINK_STS_CHG + 4, 0xffffffff);
|
||||
|
||||
/* Restore notification settings: on RTL838x these bits are null */
|
||||
regmap_update_bits(ctrl->map, ctrl->cfg->dma_if_intr_msk, 7 << 20, int_saved & (7 << 20));
|
||||
regmap_write(ctrl->map, RTETH_839X_DMA_IF_NBUF_BASE_CTRL, nbuf);
|
||||
}
|
||||
|
||||
static void rteth_93xx_set_hol(struct rteth_ctrl *ctrl)
|
||||
@@ -733,33 +640,6 @@ static int rteth_setup_ring_buffer(struct rteth_ctrl *ctrl)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rteth_839x_setup_notify_buffer(struct rteth_ctrl *ctrl)
|
||||
{
|
||||
struct notify_b *b = ctrl->membase;
|
||||
|
||||
for (int i = 0; i < RTETH_NOTIFY_BLOCKS; i++)
|
||||
b->ring[i] = KSEG1ADDR(&b->blocks[i]) | RTETH_RING_OWN_HW;
|
||||
b->ring[RTETH_NOTIFY_BLOCKS - 1] |= RTETH_RING_WRAP;
|
||||
|
||||
regmap_write(ctrl->map, RTETH_839X_DMA_IF_NBUF_BASE_CTRL, (u32)b->ring);
|
||||
regmap_update_bits(ctrl->map, RTETH_839X_L2_NOTIFICATION_CTRL, 0x3ff << 2, 100 << 2);
|
||||
|
||||
/* Setup notification events */
|
||||
|
||||
/* RTL8390_L2_CTRL_0_FLUSH_NOTIFY_EN */
|
||||
regmap_set_bits(ctrl->map, RTETH_839X_L2_CTRL_0, BIT(14));
|
||||
/* SUSPEND_NOTIFICATION_EN */
|
||||
regmap_set_bits(ctrl->map, RTETH_839X_L2_NOTIFICATION_CTRL, BIT(12));
|
||||
|
||||
/* Enable Notification */
|
||||
regmap_set_bits(ctrl->map, RTETH_839X_L2_NOTIFICATION_CTRL, BIT(0));
|
||||
ctrl->lastEvent = 0;
|
||||
|
||||
/* Make sure the ring structure is visible to the ASIC */
|
||||
mb();
|
||||
flush_cache_all();
|
||||
}
|
||||
|
||||
static void rteth_838x_hw_init(struct rteth_ctrl *ctrl)
|
||||
{
|
||||
/* Trap IGMP/MLD traffic to CPU-Port */
|
||||
@@ -825,9 +705,6 @@ static int rteth_open(struct net_device *dev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (ctrl->cfg->setup_notify_buffer)
|
||||
ctrl->cfg->setup_notify_buffer(ctrl);
|
||||
|
||||
rteth_hw_ring_setup(ctrl);
|
||||
phylink_start(ctrl->phylink);
|
||||
rteth_enable_napi(ctrl);
|
||||
@@ -1638,7 +1515,6 @@ static const struct rteth_cfg rteth_839x_cfg = {
|
||||
.init_mac = rteth_839x_init_mac,
|
||||
.set_hol = rteth_83xx_set_hol,
|
||||
.set_max_packet_length = rteth_839x_set_max_packet_length,
|
||||
.setup_notify_buffer = rteth_839x_setup_notify_buffer,
|
||||
.set_rx_mode = rteth_839x_set_rx_mode,
|
||||
.rx_csum_mask = BIT(3),
|
||||
};
|
||||
@@ -1806,14 +1682,6 @@ static int rteth_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(ctrl->map))
|
||||
return PTR_ERR(ctrl->map);
|
||||
|
||||
/* Allocate buffer memory */
|
||||
ctrl->membase = dmam_alloc_coherent(&pdev->dev, sizeof(struct notify_b),
|
||||
(void *)&dev->mem_start, GFP_KERNEL);
|
||||
if (!ctrl->membase) {
|
||||
dev_err(&pdev->dev, "cannot allocate DMA buffer\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ctrl->rx_data = dmam_alloc_coherent(&pdev->dev, sizeof(struct rteth_rx_data) * RTETH_RX_RINGS,
|
||||
&ctrl->rx_dma, GFP_KERNEL);
|
||||
if (!ctrl->rx_data)
|
||||
|
||||
@@ -116,8 +116,6 @@
|
||||
#define RTETH_931X_L2_NTFY_IF_INTR_MSK (0x09E4)
|
||||
#define RTETH_931X_L2_NTFY_IF_INTR_STS (0x09E8)
|
||||
|
||||
#define RTETH_839X_DMA_IF_INTR_NOTIFY_MASK GENMASK(22, 20)
|
||||
|
||||
#define RTETH_838X_DMA_IF_TX_CUR_DESC_ADDR_CTRL (0x9F48)
|
||||
#define RTETH_930X_DMA_IF_TX_CUR_DESC_ADDR_CTRL (0xE008)
|
||||
|
||||
@@ -147,8 +145,6 @@
|
||||
#define RTETH_RX_PAUSE_EN BIT(7)
|
||||
|
||||
/* L2 Notification DMA interface */
|
||||
#define RTETH_839X_DMA_IF_NBUF_BASE_CTRL (0x785C)
|
||||
#define RTETH_839X_L2_NOTIFICATION_CTRL (0x7808)
|
||||
#define RTETH_931X_L2_NTFY_RING_BASE_ADDR (0x09DC)
|
||||
#define RTETH_931X_L2_NTFY_RING_CUR_ADDR (0x09E0)
|
||||
#define RTETH_931X_L2_NTFY_CTRL (0xCDC8)
|
||||
@@ -199,9 +195,6 @@
|
||||
#define RTETH_TX_RINGS 2
|
||||
#define RTETH_TX_TRIGGER(ctrl, ring) ((0x16 >> ring) & ctrl->cfg->tx_trigger_mask)
|
||||
|
||||
#define RTETH_NOTIFY_EVENTS 10
|
||||
#define RTETH_NOTIFY_BLOCKS 10
|
||||
|
||||
#define RTETH_RX_TRUNCATE_EN_93XX BIT(6)
|
||||
#define RTETH_RX_TRUNCATE_EN_83XX BIT(4)
|
||||
#define RTETH_TX_PAD_EN_838X BIT(5)
|
||||
@@ -272,37 +265,15 @@ struct rteth_tx_info {
|
||||
struct sk_buff *skb[RTETH_TX_RING_SIZE];
|
||||
};
|
||||
|
||||
struct n_event {
|
||||
u32 type:2;
|
||||
u32 fidVid:12;
|
||||
u64 mac:48;
|
||||
u32 slp:6;
|
||||
u32 valid:1;
|
||||
u32 reserved:27;
|
||||
} __packed __aligned(1);
|
||||
|
||||
struct notify_block {
|
||||
struct n_event events[RTETH_NOTIFY_EVENTS];
|
||||
};
|
||||
|
||||
struct notify_b {
|
||||
struct notify_block blocks[RTETH_NOTIFY_BLOCKS];
|
||||
u32 reserved1[8];
|
||||
u32 ring[RTETH_NOTIFY_BLOCKS];
|
||||
u32 reserved2[8];
|
||||
};
|
||||
|
||||
struct rteth_ctrl {
|
||||
const struct rteth_cfg *cfg;
|
||||
struct regmap *map;
|
||||
struct net_device *dev;
|
||||
struct platform_device *pdev;
|
||||
void *membase;
|
||||
spinlock_t lock;
|
||||
struct mii_bus *mii_bus;
|
||||
struct phylink *phylink;
|
||||
struct phylink_config phylink_config;
|
||||
u32 lastEvent;
|
||||
struct metadata_dst *dsa_meta[RTETH_931X_CPU_PORT];
|
||||
struct metadata_dst *dsa_meta_trapped[RTETH_931X_CPU_PORT];
|
||||
/* receive handling */
|
||||
@@ -343,7 +314,7 @@ struct rteth_cfg {
|
||||
int skb_headroom;
|
||||
u32 mac_reg[RTETH_MAX_MAC_REGS];
|
||||
int l2_tbl_flush_ctrl;
|
||||
void (*confirm_disable_irqs)(struct rteth_ctrl *ctrl, unsigned long *rings, bool *l2);
|
||||
void (*confirm_disable_irqs)(struct rteth_ctrl *ctrl, unsigned long *rings);
|
||||
void (*enable_rx_irq)(struct rteth_ctrl *ctrl, int ring);
|
||||
void (*create_tx_header)(struct rteth_frag *frag, unsigned int dest_port, int prio);
|
||||
bool (*decode_tag)(struct rteth_frag *frag, struct rteth_dsa_tag *tag);
|
||||
@@ -354,7 +325,6 @@ struct rteth_cfg {
|
||||
int (*init_mac)(struct rteth_ctrl *ctrl);
|
||||
void (*set_hol)(struct rteth_ctrl *ctrl);
|
||||
void (*set_max_packet_length)(struct rteth_ctrl *ctrl, int len);
|
||||
void (*setup_notify_buffer)(struct rteth_ctrl *ctrl);
|
||||
void (*update_counter)(struct rteth_ctrl *ctrl, int ring, int released);
|
||||
void (*set_rx_mode)(struct net_device *dev);
|
||||
u32 rx_csum_mask;
|
||||
|
||||
Reference in new issue
Block a user