developer | c2cfe0f | 2023-09-22 04:11:09 +0800 | [diff] [blame] | 1 | From 843b9adeef21e5e3e574baea8391a929bf48412a Mon Sep 17 00:00:00 2001 |
| 2 | From: Shayne Chen <shayne.chen@mediatek.com> |
| 3 | Date: Mon, 3 Jul 2023 22:38:43 +0800 |
| 4 | Subject: [PATCH 13/22] wifi: mt76: mt7996: add lock for indirect register |
| 5 | access |
| 6 | |
| 7 | Some races were observed during indirect register access, fix this |
| 8 | by adding reg_lock and reworking l1/l2 remap flow. |
| 9 | |
| 10 | Signed-off-by: Shayne Chen <shayne.chen@mediatek.com> |
| 11 | Change-Id: I0de2cd27df9ccb7f9a7d9ce265e869175b1ca7f1 |
| 12 | --- |
| 13 | mt7996/mmio.c | 68 +++++++++++++++++++++++++++++++++---------------- |
| 14 | mt7996/mt7996.h | 3 +-- |
| 15 | 2 files changed, 47 insertions(+), 24 deletions(-) |
| 16 | |
| 17 | diff --git a/mt7996/mmio.c b/mt7996/mmio.c |
| 18 | index 3a591a7b4..d5eaa1bcf 100644 |
| 19 | --- a/mt7996/mmio.c |
| 20 | +++ b/mt7996/mmio.c |
| 21 | @@ -82,7 +82,6 @@ static u32 mt7996_reg_map_l1(struct mt7996_dev *dev, u32 addr) |
| 22 | u32 offset = FIELD_GET(MT_HIF_REMAP_L1_OFFSET, addr); |
| 23 | u32 base = FIELD_GET(MT_HIF_REMAP_L1_BASE, addr); |
| 24 | |
| 25 | - dev->reg_l1_backup = dev->bus_ops->rr(&dev->mt76, MT_HIF_REMAP_L1); |
| 26 | dev->bus_ops->rmw(&dev->mt76, MT_HIF_REMAP_L1, |
| 27 | MT_HIF_REMAP_L1_MASK, |
| 28 | FIELD_PREP(MT_HIF_REMAP_L1_MASK, base)); |
| 29 | @@ -97,7 +96,6 @@ static u32 mt7996_reg_map_l2(struct mt7996_dev *dev, u32 addr) |
| 30 | u32 offset = FIELD_GET(MT_HIF_REMAP_L2_OFFSET, addr); |
| 31 | u32 base = FIELD_GET(MT_HIF_REMAP_L2_BASE, addr); |
| 32 | |
| 33 | - dev->reg_l2_backup = dev->bus_ops->rr(&dev->mt76, MT_HIF_REMAP_L2); |
| 34 | dev->bus_ops->rmw(&dev->mt76, MT_HIF_REMAP_L2, |
| 35 | MT_HIF_REMAP_L2_MASK, |
| 36 | FIELD_PREP(MT_HIF_REMAP_L2_MASK, base)); |
| 37 | @@ -107,26 +105,10 @@ static u32 mt7996_reg_map_l2(struct mt7996_dev *dev, u32 addr) |
| 38 | return MT_HIF_REMAP_BASE_L2 + offset; |
| 39 | } |
| 40 | |
| 41 | -static void mt7996_reg_remap_restore(struct mt7996_dev *dev) |
| 42 | -{ |
| 43 | - /* remap to ori status */ |
| 44 | - if (unlikely(dev->reg_l1_backup)) { |
| 45 | - dev->bus_ops->wr(&dev->mt76, MT_HIF_REMAP_L1, dev->reg_l1_backup); |
| 46 | - dev->reg_l1_backup = 0; |
| 47 | - } |
| 48 | - |
| 49 | - if (dev->reg_l2_backup) { |
| 50 | - dev->bus_ops->wr(&dev->mt76, MT_HIF_REMAP_L2, dev->reg_l2_backup); |
| 51 | - dev->reg_l2_backup = 0; |
| 52 | - } |
| 53 | -} |
| 54 | - |
| 55 | static u32 __mt7996_reg_addr(struct mt7996_dev *dev, u32 addr) |
| 56 | { |
| 57 | int i; |
| 58 | |
| 59 | - mt7996_reg_remap_restore(dev); |
| 60 | - |
| 61 | if (addr < 0x100000) |
| 62 | return addr; |
| 63 | |
| 64 | @@ -143,6 +125,11 @@ static u32 __mt7996_reg_addr(struct mt7996_dev *dev, u32 addr) |
| 65 | return dev->reg.map[i].mapped + ofs; |
| 66 | } |
| 67 | |
| 68 | + return 0; |
| 69 | +} |
| 70 | + |
| 71 | +static u32 __mt7996_reg_remap_addr(struct mt7996_dev *dev, u32 addr) |
| 72 | +{ |
| 73 | if ((addr >= MT_INFRA_BASE && addr < MT_WFSYS0_PHY_START) || |
| 74 | (addr >= MT_WFSYS0_PHY_START && addr < MT_WFSYS1_PHY_START) || |
| 75 | (addr >= MT_WFSYS1_PHY_START && addr <= MT_WFSYS1_PHY_END)) |
| 76 | @@ -166,29 +153,65 @@ void mt7996_memcpy_fromio(struct mt7996_dev *dev, void *buf, u32 offset, |
| 77 | size_t len) |
| 78 | { |
| 79 | u32 addr = __mt7996_reg_addr(dev, offset); |
| 80 | + unsigned long flags; |
| 81 | |
| 82 | - memcpy_fromio(buf, dev->mt76.mmio.regs + addr, len); |
| 83 | + if (addr) { |
| 84 | + memcpy_fromio(buf, dev->mt76.mmio.regs + addr, len); |
| 85 | + return; |
| 86 | + } |
| 87 | + |
| 88 | + spin_lock_irqsave(&dev->reg_lock, flags); |
| 89 | + memcpy_fromio(buf, dev->mt76.mmio.regs + |
| 90 | + __mt7996_reg_remap_addr(dev, offset), len); |
| 91 | + spin_unlock_irqrestore(&dev->reg_lock, flags); |
| 92 | } |
| 93 | |
| 94 | static u32 mt7996_rr(struct mt76_dev *mdev, u32 offset) |
| 95 | { |
| 96 | struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); |
| 97 | + u32 addr = __mt7996_reg_addr(dev, offset), val; |
| 98 | + unsigned long flags; |
| 99 | + |
| 100 | + if (addr) |
| 101 | + return dev->bus_ops->rr(mdev, addr); |
| 102 | |
| 103 | - return dev->bus_ops->rr(mdev, __mt7996_reg_addr(dev, offset)); |
| 104 | + spin_lock_irqsave(&dev->reg_lock, flags); |
| 105 | + val = dev->bus_ops->rr(mdev, __mt7996_reg_remap_addr(dev, offset)); |
| 106 | + spin_unlock_irqrestore(&dev->reg_lock, flags); |
| 107 | + |
| 108 | + return val; |
| 109 | } |
| 110 | |
| 111 | static void mt7996_wr(struct mt76_dev *mdev, u32 offset, u32 val) |
| 112 | { |
| 113 | struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); |
| 114 | + u32 addr = __mt7996_reg_addr(dev, offset); |
| 115 | + unsigned long flags; |
| 116 | |
| 117 | - dev->bus_ops->wr(mdev, __mt7996_reg_addr(dev, offset), val); |
| 118 | + if (addr) { |
| 119 | + dev->bus_ops->wr(mdev, addr, val); |
| 120 | + return; |
| 121 | + } |
| 122 | + |
| 123 | + spin_lock_irqsave(&dev->reg_lock, flags); |
| 124 | + dev->bus_ops->wr(mdev, __mt7996_reg_remap_addr(dev, offset), val); |
| 125 | + spin_unlock_irqrestore(&dev->reg_lock, flags); |
| 126 | } |
| 127 | |
| 128 | static u32 mt7996_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val) |
| 129 | { |
| 130 | struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); |
| 131 | + u32 addr = __mt7996_reg_addr(dev, offset); |
| 132 | + unsigned long flags; |
| 133 | + |
| 134 | + if (addr) |
| 135 | + return dev->bus_ops->rmw(mdev, addr, mask, val); |
| 136 | + |
| 137 | + spin_lock_irqsave(&dev->reg_lock, flags); |
| 138 | + val = dev->bus_ops->rmw(mdev, __mt7996_reg_remap_addr(dev, offset), mask, val); |
| 139 | + spin_unlock_irqrestore(&dev->reg_lock, flags); |
| 140 | |
| 141 | - return dev->bus_ops->rmw(mdev, __mt7996_reg_addr(dev, offset), mask, val); |
| 142 | + return val; |
| 143 | } |
| 144 | |
| 145 | static int mt7996_mmio_init(struct mt76_dev *mdev, |
| 146 | @@ -200,6 +223,7 @@ static int mt7996_mmio_init(struct mt76_dev *mdev, |
| 147 | |
| 148 | dev = container_of(mdev, struct mt7996_dev, mt76); |
| 149 | mt76_mmio_init(&dev->mt76, mem_base); |
| 150 | + spin_lock_init(&dev->reg_lock); |
| 151 | |
| 152 | switch (device_id) { |
| 153 | case 0x7990: |
| 154 | diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h |
| 155 | index 890f522d9..ea1104845 100644 |
| 156 | --- a/mt7996/mt7996.h |
| 157 | +++ b/mt7996/mt7996.h |
| 158 | @@ -257,8 +257,7 @@ struct mt7996_dev { |
| 159 | u8 n_agrt; |
| 160 | } twt; |
| 161 | |
| 162 | - u32 reg_l1_backup; |
| 163 | - u32 reg_l2_backup; |
| 164 | + spinlock_t reg_lock; |
| 165 | |
| 166 | u8 wtbl_size_group; |
| 167 | }; |
| 168 | -- |
| 169 | 2.39.2 |
| 170 | |