]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - queue-6.8/wifi-mt76-mt7996-add-locking-for-accessing-mapped-re.patch
Fixes for 6.8
[thirdparty/kernel/stable-queue.git] / queue-6.8 / wifi-mt76-mt7996-add-locking-for-accessing-mapped-re.patch
1 From dfc0f43c69ba4ecc8c37179309bdb3f0c1ae41e8 Mon Sep 17 00:00:00 2001
2 From: Sasha Levin <sashal@kernel.org>
3 Date: Fri, 26 Jan 2024 17:09:21 +0800
4 Subject: wifi: mt76: mt7996: add locking for accessing mapped registers
5
6 From: Shayne Chen <shayne.chen@mediatek.com>
7
8 [ Upstream commit 3687854d3e7e7fd760d939dd9e5a3520d5ab60fe ]
9
10 A race condition was observed when accessing mapped registers, so add
11 locking to protect against concurrent access.
12
13 Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
14 Signed-off-by: Felix Fietkau <nbd@nbd.name>
15 Signed-off-by: Sasha Levin <sashal@kernel.org>
16 ---
17 .../net/wireless/mediatek/mt76/mt7996/mmio.c | 64 ++++++++++++-------
18 .../wireless/mediatek/mt76/mt7996/mt7996.h | 3 +-
19 2 files changed, 43 insertions(+), 24 deletions(-)
20
21 diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c
22 index 9f2abfa273c9b..efd4a767eb37d 100644
23 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c
24 +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c
25 @@ -140,7 +140,6 @@ static u32 mt7996_reg_map_l1(struct mt7996_dev *dev, u32 addr)
26 u32 offset = FIELD_GET(MT_HIF_REMAP_L1_OFFSET, addr);
27 u32 base = FIELD_GET(MT_HIF_REMAP_L1_BASE, addr);
28
29 - dev->reg_l1_backup = dev->bus_ops->rr(&dev->mt76, MT_HIF_REMAP_L1);
30 dev->bus_ops->rmw(&dev->mt76, MT_HIF_REMAP_L1,
31 MT_HIF_REMAP_L1_MASK,
32 FIELD_PREP(MT_HIF_REMAP_L1_MASK, base));
33 @@ -155,7 +154,6 @@ static u32 mt7996_reg_map_l2(struct mt7996_dev *dev, u32 addr)
34 u32 offset = FIELD_GET(MT_HIF_REMAP_L2_OFFSET, addr);
35 u32 base = FIELD_GET(MT_HIF_REMAP_L2_BASE, addr);
36
37 - dev->reg_l2_backup = dev->bus_ops->rr(&dev->mt76, MT_HIF_REMAP_L2);
38 dev->bus_ops->rmw(&dev->mt76, MT_HIF_REMAP_L2,
39 MT_HIF_REMAP_L2_MASK,
40 FIELD_PREP(MT_HIF_REMAP_L2_MASK, base));
41 @@ -165,26 +163,10 @@ static u32 mt7996_reg_map_l2(struct mt7996_dev *dev, u32 addr)
42 return MT_HIF_REMAP_BASE_L2 + offset;
43 }
44
45 -static void mt7996_reg_remap_restore(struct mt7996_dev *dev)
46 -{
47 - /* remap to ori status */
48 - if (unlikely(dev->reg_l1_backup)) {
49 - dev->bus_ops->wr(&dev->mt76, MT_HIF_REMAP_L1, dev->reg_l1_backup);
50 - dev->reg_l1_backup = 0;
51 - }
52 -
53 - if (dev->reg_l2_backup) {
54 - dev->bus_ops->wr(&dev->mt76, MT_HIF_REMAP_L2, dev->reg_l2_backup);
55 - dev->reg_l2_backup = 0;
56 - }
57 -}
58 -
59 static u32 __mt7996_reg_addr(struct mt7996_dev *dev, u32 addr)
60 {
61 int i;
62
63 - mt7996_reg_remap_restore(dev);
64 -
65 if (addr < 0x100000)
66 return addr;
67
68 @@ -201,6 +183,11 @@ static u32 __mt7996_reg_addr(struct mt7996_dev *dev, u32 addr)
69 return dev->reg.map[i].mapped + ofs;
70 }
71
72 + return 0;
73 +}
74 +
75 +static u32 __mt7996_reg_remap_addr(struct mt7996_dev *dev, u32 addr)
76 +{
77 if ((addr >= MT_INFRA_BASE && addr < MT_WFSYS0_PHY_START) ||
78 (addr >= MT_WFSYS0_PHY_START && addr < MT_WFSYS1_PHY_START) ||
79 (addr >= MT_WFSYS1_PHY_START && addr <= MT_WFSYS1_PHY_END))
80 @@ -225,28 +212,60 @@ void mt7996_memcpy_fromio(struct mt7996_dev *dev, void *buf, u32 offset,
81 {
82 u32 addr = __mt7996_reg_addr(dev, offset);
83
84 - memcpy_fromio(buf, dev->mt76.mmio.regs + addr, len);
85 + if (addr) {
86 + memcpy_fromio(buf, dev->mt76.mmio.regs + addr, len);
87 + return;
88 + }
89 +
90 + spin_lock_bh(&dev->reg_lock);
91 + memcpy_fromio(buf, dev->mt76.mmio.regs +
92 + __mt7996_reg_remap_addr(dev, offset), len);
93 + spin_unlock_bh(&dev->reg_lock);
94 }
95
96 static u32 mt7996_rr(struct mt76_dev *mdev, u32 offset)
97 {
98 struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
99 + u32 addr = __mt7996_reg_addr(dev, offset), val;
100 +
101 + if (addr)
102 + return dev->bus_ops->rr(mdev, addr);
103
104 - return dev->bus_ops->rr(mdev, __mt7996_reg_addr(dev, offset));
105 + spin_lock_bh(&dev->reg_lock);
106 + val = dev->bus_ops->rr(mdev, __mt7996_reg_remap_addr(dev, offset));
107 + spin_unlock_bh(&dev->reg_lock);
108 +
109 + return val;
110 }
111
112 static void mt7996_wr(struct mt76_dev *mdev, u32 offset, u32 val)
113 {
114 struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
115 + u32 addr = __mt7996_reg_addr(dev, offset);
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_bh(&dev->reg_lock);
124 + dev->bus_ops->wr(mdev, __mt7996_reg_remap_addr(dev, offset), val);
125 + spin_unlock_bh(&dev->reg_lock);
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 +
133 + if (addr)
134 + return dev->bus_ops->rmw(mdev, addr, mask, val);
135 +
136 + spin_lock_bh(&dev->reg_lock);
137 + val = dev->bus_ops->rmw(mdev, __mt7996_reg_remap_addr(dev, offset), mask, val);
138 + spin_unlock_bh(&dev->reg_lock);
139
140 - return dev->bus_ops->rmw(mdev, __mt7996_reg_addr(dev, offset), mask, val);
141 + return val;
142 }
143
144 #ifdef CONFIG_NET_MEDIATEK_SOC_WED
145 @@ -421,6 +440,7 @@ static int mt7996_mmio_init(struct mt76_dev *mdev,
146
147 dev = container_of(mdev, struct mt7996_dev, mt76);
148 mt76_mmio_init(&dev->mt76, mem_base);
149 + spin_lock_init(&dev->reg_lock);
150
151 switch (device_id) {
152 case 0x7990:
153 diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
154 index 8154ad37827f0..36d1f247d55aa 100644
155 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
156 +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
157 @@ -325,8 +325,7 @@ struct mt7996_dev {
158 u8 n_agrt;
159 } twt;
160
161 - u32 reg_l1_backup;
162 - u32 reg_l2_backup;
163 + spinlock_t reg_lock;
164
165 u8 wtbl_size_group;
166 };
167 --
168 2.43.0
169