diff options
Diffstat (limited to 'target/linux/layerscape/patches-5.4/701-net-0236-enetc-Replace-enetc_gregs-with-a-readers-writer-lock.patch')
-rw-r--r-- | target/linux/layerscape/patches-5.4/701-net-0236-enetc-Replace-enetc_gregs-with-a-readers-writer-lock.patch | 385 |
1 files changed, 0 insertions, 385 deletions
diff --git a/target/linux/layerscape/patches-5.4/701-net-0236-enetc-Replace-enetc_gregs-with-a-readers-writer-lock.patch b/target/linux/layerscape/patches-5.4/701-net-0236-enetc-Replace-enetc_gregs-with-a-readers-writer-lock.patch deleted file mode 100644 index cb164d4ffb..0000000000 --- a/target/linux/layerscape/patches-5.4/701-net-0236-enetc-Replace-enetc_gregs-with-a-readers-writer-lock.patch +++ /dev/null @@ -1,385 +0,0 @@ -From 659f899773f9f3fdc8325f61acc1017dd838126c Mon Sep 17 00:00:00 2001 -From: Vladimir Oltean <vladimir.oltean@nxp.com> -Date: Thu, 14 Nov 2019 17:30:50 +0200 -Subject: [PATCH] enetc: Replace enetc_gregs with a readers-writer lock - -The LS1028A MDIO errata tells us that any MDIO register access must not -be concurrent with any other ENETC register access. - -That has been handled so far by a number of per-CPU spinlocks over the -ENETC register map. This came as an optimization over a single spinlock, -because the regular register accesses can still be concurrent with one -another, as long as they aren't concurrent with MDIO. - -But this logic is broken in RT, because the enetc_rd_reg_wa and -enetc_wr_reg_wa functions can be preempted in any context, and when they -resume they may not run on the same CPU. - -This renders the logic to take the per-CPU spinlock pointless, since the -spinlock may not be the correct one (corresponding to this CPU) after -preemption has occurred. - -The following splat is telling us the same thing: - -[ 19.073928] BUG: using smp_processor_id() in preemptible [00000000] code: systemd-network/3423 -[ 19.073932] caller is debug_smp_processor_id+0x1c/0x30 -[ 19.073935] CPU: 1 PID: 3423 Comm: systemd-network Not tainted 4.19.68-rt26 #1 -[ 19.073936] Hardware name: LS1028A RDB Board (DT) -[ 19.073938] Call trace: -[ 19.073940] dump_backtrace+0x0/0x1a0 -[ 19.073942] show_stack+0x24/0x30 -[ 19.073945] dump_stack+0x9c/0xdc -[ 19.073948] check_preemption_disabled+0xe0/0x100 -[ 19.073951] debug_smp_processor_id+0x1c/0x30 -[ 19.073954] enetc_open+0x1b0/0xbc0 -[ 19.073957] __dev_open+0xdc/0x160 -[ 19.073960] __dev_change_flags+0x160/0x1d0 -[ 19.073963] dev_change_flags+0x34/0x70 -[ 19.073966] do_setlink+0x2a0/0xcd0 -[ 19.073969] rtnl_setlink+0xe4/0x140 -[ 19.073972] rtnetlink_rcv_msg+0x18c/0x500 -[ 19.073975] netlink_rcv_skb+0x60/0x120 -[ 19.073978] rtnetlink_rcv+0x28/0x40 -[ 19.073982] netlink_unicast+0x194/0x210 -[ 19.073985] netlink_sendmsg+0x194/0x330 -[ 19.073987] sock_sendmsg+0x34/0x50 -[ 19.073990] __sys_sendto+0xe4/0x150 -[ 19.073992] __arm64_sys_sendto+0x30/0x40 -[ 19.073996] el0_svc_common+0xa4/0x1a0 -[ 19.073999] el0_svc_handler+0x38/0x80 -[ 19.074002] el0_svc+0x8/0xc - -But there already exists a spinlock optimized for the single writer, -multiple readers case: the rwlock_t. The writer in this case is the MDIO -access code (irrelevant whether that MDIO access is a register read or -write), and the reader is everybody else. - -This patch also fixes two more existing bugs in the errata workaround: -- The MDIO access code was not unlocking the per-CPU spinlocks in the - reverse order of their locking order. -- The per-CPU spinlock array was not initialized. - -Fixes: 5ec0d668d62e ("enetc: WA for MDIO register access issue") -Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> -Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com> ---- - drivers/net/ethernet/freescale/enetc/enetc.c | 59 ++++++---------------- - drivers/net/ethernet/freescale/enetc/enetc_hw.h | 67 ++++--------------------- - drivers/net/ethernet/freescale/enetc/enetc_pf.c | 5 +- - 3 files changed, 30 insertions(+), 101 deletions(-) - ---- a/drivers/net/ethernet/freescale/enetc/enetc.c -+++ b/drivers/net/ethernet/freescale/enetc/enetc.c -@@ -20,13 +20,8 @@ netdev_tx_t enetc_xmit(struct sk_buff *s - { - struct enetc_ndev_priv *priv = netdev_priv(ndev); - struct enetc_bdr *tx_ring; -- unsigned long flags; -- /* pointer to per-cpu ENETC lock for register access issue WA */ -- spinlock_t *lock; - int count; - -- lock = this_cpu_ptr(&enetc_gregs); -- - tx_ring = priv->tx_ring[skb->queue_mapping]; - - if (unlikely(skb_shinfo(skb)->nr_frags > ENETC_MAX_SKB_FRAGS)) -@@ -39,11 +34,9 @@ netdev_tx_t enetc_xmit(struct sk_buff *s - return NETDEV_TX_BUSY; - } - -- spin_lock_irqsave(lock, flags); -- -+ read_lock(&enetc_mdio_lock); - count = enetc_map_tx_buffs(tx_ring, skb, priv->active_offloads); -- -- spin_unlock_irqrestore(lock, flags); -+ read_unlock(&enetc_mdio_lock); - - if (unlikely(!count)) - goto drop_packet_err; -@@ -259,13 +252,9 @@ dma_err: - static irqreturn_t enetc_msix(int irq, void *data) - { - struct enetc_int_vector *v = data; -- unsigned long flags; -- /* pointer to per-cpu ENETC lock for register access issue WA */ -- spinlock_t *lock; - int i; - -- lock = this_cpu_ptr(&enetc_gregs); -- spin_lock_irqsave(lock, flags); -+ read_lock(&enetc_mdio_lock); - - /* disable interrupts */ - enetc_wr_reg_hot(v->rbier, 0); -@@ -273,7 +262,7 @@ static irqreturn_t enetc_msix(int irq, v - for_each_set_bit(i, &v->tx_rings_map, ENETC_MAX_NUM_TXQS) - enetc_wr_reg_hot(v->tbier_base + ENETC_BDR_OFF(i), 0); - -- spin_unlock_irqrestore(lock, flags); -+ read_unlock(&enetc_mdio_lock); - - napi_schedule_irqoff(&v->napi); - -@@ -289,9 +278,6 @@ static int enetc_poll(struct napi_struct - struct enetc_int_vector - *v = container_of(napi, struct enetc_int_vector, napi); - bool complete = true; -- unsigned long flags; -- /* pointer to per-cpu ENETC lock for register access issue WA */ -- spinlock_t *lock; - int work_done; - int i; - -@@ -308,8 +294,7 @@ static int enetc_poll(struct napi_struct - - napi_complete_done(napi, work_done); - -- lock = this_cpu_ptr(&enetc_gregs); -- spin_lock_irqsave(lock, flags); -+ read_lock(&enetc_mdio_lock); - - /* enable interrupts */ - enetc_wr_reg_hot(v->rbier, ENETC_RBIER_RXTIE); -@@ -318,7 +303,7 @@ static int enetc_poll(struct napi_struct - enetc_wr_reg_hot(v->tbier_base + ENETC_BDR_OFF(i), - ENETC_TBIER_TXTIE); - -- spin_unlock_irqrestore(lock, flags); -+ read_unlock(&enetc_mdio_lock); - - return work_done; - } -@@ -363,18 +348,12 @@ static bool enetc_clean_tx_ring(struct e - bool do_tstamp; - u64 tstamp = 0; - -- unsigned long flags; -- /* pointer to per-cpu ENETC lock for register access issue WA */ -- spinlock_t *lock; -- -- lock = this_cpu_ptr(&enetc_gregs); -- - i = tx_ring->next_to_clean; - tx_swbd = &tx_ring->tx_swbd[i]; - -- spin_lock_irqsave(lock, flags); -+ read_lock(&enetc_mdio_lock); - bds_to_clean = enetc_bd_ready_count(tx_ring, i); -- spin_unlock_irqrestore(lock, flags); -+ read_unlock(&enetc_mdio_lock); - - do_tstamp = false; - -@@ -417,7 +396,7 @@ static bool enetc_clean_tx_ring(struct e - tx_swbd = tx_ring->tx_swbd; - } - -- spin_lock_irqsave(lock, flags); -+ read_lock(&enetc_mdio_lock); - - /* BD iteration loop end */ - if (is_eof) { -@@ -430,7 +409,7 @@ static bool enetc_clean_tx_ring(struct e - if (unlikely(!bds_to_clean)) - bds_to_clean = enetc_bd_ready_count(tx_ring, i); - -- spin_unlock_irqrestore(lock, flags); -+ read_unlock(&enetc_mdio_lock); - } - - tx_ring->next_to_clean = i; -@@ -516,7 +495,7 @@ static int enetc_refill_rx_ring(struct e - } - - #ifdef CONFIG_FSL_ENETC_HW_TIMESTAMPING --/* Must be called with &enetc_gregs spinlock held */ -+/* Must be called with the read-side enetc_mdio_lock held */ - static void enetc_get_rx_tstamp(struct net_device *ndev, - union enetc_rx_bd *rxbd, - struct sk_buff *skb) -@@ -667,12 +646,6 @@ static int enetc_clean_rx_ring(struct en - int rx_frm_cnt = 0, rx_byte_cnt = 0; - int cleaned_cnt, i; - -- unsigned long flags; -- /* pointer to per-cpu ENETC lock for register access issue WA */ -- spinlock_t *lock; -- -- lock = this_cpu_ptr(&enetc_gregs); -- - cleaned_cnt = enetc_bd_unused(rx_ring); - /* next descriptor to process */ - i = rx_ring->next_to_clean; -@@ -683,7 +656,7 @@ static int enetc_clean_rx_ring(struct en - u32 bd_status; - u16 size; - -- spin_lock_irqsave(lock, flags); -+ read_lock(&enetc_mdio_lock); - - if (cleaned_cnt >= ENETC_RXBD_BUNDLE) { - int count = enetc_refill_rx_ring(rx_ring, cleaned_cnt); -@@ -694,7 +667,7 @@ static int enetc_clean_rx_ring(struct en - rxbd = ENETC_RXBD(*rx_ring, i); - bd_status = le32_to_cpu(rxbd->r.lstatus); - if (!bd_status) { -- spin_unlock_irqrestore(lock, flags); -+ read_unlock(&enetc_mdio_lock); - break; - } - -@@ -703,7 +676,7 @@ static int enetc_clean_rx_ring(struct en - size = le16_to_cpu(rxbd->r.buf_len); - skb = enetc_map_rx_buff_to_skb(rx_ring, i, size); - if (!skb) { -- spin_unlock_irqrestore(lock, flags); -+ read_unlock(&enetc_mdio_lock); - break; - } - -@@ -719,7 +692,7 @@ static int enetc_clean_rx_ring(struct en - - if (unlikely(bd_status & - ENETC_RXBD_LSTATUS(ENETC_RXBD_ERR_MASK))) { -- spin_unlock_irqrestore(lock, flags); -+ read_unlock(&enetc_mdio_lock); - dev_kfree_skb(skb); - while (!(bd_status & ENETC_RXBD_LSTATUS_F)) { - dma_rmb(); -@@ -763,7 +736,7 @@ static int enetc_clean_rx_ring(struct en - - enetc_process_skb(rx_ring, skb); - -- spin_unlock_irqrestore(lock, flags); -+ read_unlock(&enetc_mdio_lock); - - napi_gro_receive(napi, skb); - ---- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h -+++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h -@@ -331,7 +331,7 @@ struct enetc_hw { - #define enetc_wr_reg(reg, val) enetc_wr_reg_wa((reg), (val)) - - /* accessors for data-path, due to MDIO issue on LS1028 these should be called -- * only under enetc_gregs per-cpu lock -+ * only under the rwlock_t enetc_mdio_lock - */ - #define enetc_rd_reg_hot(reg) ioread32((reg)) - #define enetc_wr_reg_hot(reg, val) iowrite32((val), (reg)) -@@ -354,90 +354,45 @@ static inline u64 enetc_rd_reg64(void __ - } - #endif - --extern DEFINE_PER_CPU(spinlock_t, enetc_gregs); -+extern rwlock_t enetc_mdio_lock; - - static inline u32 enetc_rd_reg_wa(void *reg) - { -- unsigned long flags; -- /* pointer to per-cpu ENETC lock for register access issue WA */ -- spinlock_t *lock; - u32 val; - -- lock = this_cpu_ptr(&enetc_gregs); -- spin_lock_irqsave(lock, flags); -+ read_lock(&enetc_mdio_lock); - val = ioread32(reg); -- spin_unlock_irqrestore(lock, flags); -+ read_unlock(&enetc_mdio_lock); - - return val; - } - - static inline void enetc_wr_reg_wa(void *reg, u32 val) - { -- unsigned long flags; -- /* pointer to per-cpu ENETC lock for register access issue WA */ -- spinlock_t *lock; -- -- lock = this_cpu_ptr(&enetc_gregs); -- spin_lock_irqsave(lock, flags); -+ read_lock(&enetc_mdio_lock); - iowrite32(val, reg); -- spin_unlock_irqrestore(lock, flags); -+ read_unlock(&enetc_mdio_lock); - } - --/* NR_CPUS=256 in ARM64 defconfig and using it as array size triggers stack -- * frame warnings for the functions below. Use a custom define of 2 for now, -- * LS1028 has just two cores. -- */ --#define ENETC_NR_CPU_LOCKS 2 -- - static inline u32 enetc_rd_reg_wa_single(void *reg) - { -- u32 val; -- int cpu; -- /* per-cpu ENETC lock array for register access issue WA */ -- spinlock_t *lock[ENETC_NR_CPU_LOCKS]; - unsigned long flags; -+ u32 val; - -- local_irq_save(flags); -- preempt_disable(); -- -- for_each_online_cpu(cpu) { -- lock[cpu] = per_cpu_ptr(&enetc_gregs, cpu); -- spin_lock(lock[cpu]); -- } -- -+ write_lock_irqsave(&enetc_mdio_lock, flags); - val = ioread32(reg); -- -- for_each_online_cpu(cpu) -- spin_unlock(lock[cpu]); -- local_irq_restore(flags); -- -- preempt_enable(); -+ write_unlock_irqrestore(&enetc_mdio_lock, flags); - - return val; - } - - static inline void enetc_wr_reg_wa_single(void *reg, u32 val) - { -- int cpu; -- /* per-cpu ENETC lock array for register access issue WA */ -- spinlock_t *lock[ENETC_NR_CPU_LOCKS]; - unsigned long flags; - -- local_irq_save(flags); -- preempt_disable(); -- -- for_each_online_cpu(cpu) { -- lock[cpu] = per_cpu_ptr(&enetc_gregs, cpu); -- spin_lock(lock[cpu]); -- } -- -+ write_lock_irqsave(&enetc_mdio_lock, flags); - iowrite32(val, reg); -- -- for_each_online_cpu(cpu) -- spin_unlock(lock[cpu]); -- local_irq_restore(flags); -- -- preempt_enable(); -+ write_unlock_irqrestore(&enetc_mdio_lock, flags); - } - - #define enetc_rd(hw, off) enetc_rd_reg((hw)->reg + (off)) ---- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c -+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c -@@ -1076,8 +1076,9 @@ static void enetc_pf_remove(struct pci_d - enetc_pci_remove(pdev); - } - --DEFINE_PER_CPU(spinlock_t, enetc_gregs); --EXPORT_PER_CPU_SYMBOL(enetc_gregs); -+/* Lock for MDIO access errata on LS1028A */ -+DEFINE_RWLOCK(enetc_mdio_lock); -+EXPORT_SYMBOL_GPL(enetc_mdio_lock); - - static const struct pci_device_id enetc_pf_id_table[] = { - { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, ENETC_DEV_ID_PF) }, |