aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/layerscape/patches-5.4/701-net-0236-enetc-Replace-enetc_gregs-with-a-readers-writer-lock.patch
diff options
context:
space:
mode:
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.patch385
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) },