wifi: mt76: mt7996: add locking for accessing mapped registers

[ Upstream commit 3687854d3e ]

A race condition was observed when accessing mapped registers, so add
locking to protect against concurrent access.

Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
Shayne Chen 2024-01-26 17:09:21 +08:00 committed by Greg Kroah-Hartman
parent 1152c2cd38
commit 1feb6fcfba
2 changed files with 43 additions and 24 deletions

View file

@ -82,7 +82,6 @@ static u32 mt7996_reg_map_l1(struct mt7996_dev *dev, u32 addr)
u32 offset = FIELD_GET(MT_HIF_REMAP_L1_OFFSET, addr);
u32 base = FIELD_GET(MT_HIF_REMAP_L1_BASE, addr);
dev->reg_l1_backup = dev->bus_ops->rr(&dev->mt76, MT_HIF_REMAP_L1);
dev->bus_ops->rmw(&dev->mt76, MT_HIF_REMAP_L1,
MT_HIF_REMAP_L1_MASK,
FIELD_PREP(MT_HIF_REMAP_L1_MASK, base));
@ -97,7 +96,6 @@ static u32 mt7996_reg_map_l2(struct mt7996_dev *dev, u32 addr)
u32 offset = FIELD_GET(MT_HIF_REMAP_L2_OFFSET, addr);
u32 base = FIELD_GET(MT_HIF_REMAP_L2_BASE, addr);
dev->reg_l2_backup = dev->bus_ops->rr(&dev->mt76, MT_HIF_REMAP_L2);
dev->bus_ops->rmw(&dev->mt76, MT_HIF_REMAP_L2,
MT_HIF_REMAP_L2_MASK,
FIELD_PREP(MT_HIF_REMAP_L2_MASK, base));
@ -107,26 +105,10 @@ static u32 mt7996_reg_map_l2(struct mt7996_dev *dev, u32 addr)
return MT_HIF_REMAP_BASE_L2 + offset;
}
static void mt7996_reg_remap_restore(struct mt7996_dev *dev)
{
/* remap to ori status */
if (unlikely(dev->reg_l1_backup)) {
dev->bus_ops->wr(&dev->mt76, MT_HIF_REMAP_L1, dev->reg_l1_backup);
dev->reg_l1_backup = 0;
}
if (dev->reg_l2_backup) {
dev->bus_ops->wr(&dev->mt76, MT_HIF_REMAP_L2, dev->reg_l2_backup);
dev->reg_l2_backup = 0;
}
}
static u32 __mt7996_reg_addr(struct mt7996_dev *dev, u32 addr)
{
int i;
mt7996_reg_remap_restore(dev);
if (addr < 0x100000)
return addr;
@ -143,6 +125,11 @@ static u32 __mt7996_reg_addr(struct mt7996_dev *dev, u32 addr)
return dev->reg.map[i].mapped + ofs;
}
return 0;
}
static u32 __mt7996_reg_remap_addr(struct mt7996_dev *dev, u32 addr)
{
if ((addr >= MT_INFRA_BASE && addr < MT_WFSYS0_PHY_START) ||
(addr >= MT_WFSYS0_PHY_START && addr < MT_WFSYS1_PHY_START) ||
(addr >= MT_WFSYS1_PHY_START && addr <= MT_WFSYS1_PHY_END))
@ -167,28 +154,60 @@ void mt7996_memcpy_fromio(struct mt7996_dev *dev, void *buf, u32 offset,
{
u32 addr = __mt7996_reg_addr(dev, offset);
memcpy_fromio(buf, dev->mt76.mmio.regs + addr, len);
if (addr) {
memcpy_fromio(buf, dev->mt76.mmio.regs + addr, len);
return;
}
spin_lock_bh(&dev->reg_lock);
memcpy_fromio(buf, dev->mt76.mmio.regs +
__mt7996_reg_remap_addr(dev, offset), len);
spin_unlock_bh(&dev->reg_lock);
}
static u32 mt7996_rr(struct mt76_dev *mdev, u32 offset)
{
struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
u32 addr = __mt7996_reg_addr(dev, offset), val;
return dev->bus_ops->rr(mdev, __mt7996_reg_addr(dev, offset));
if (addr)
return dev->bus_ops->rr(mdev, addr);
spin_lock_bh(&dev->reg_lock);
val = dev->bus_ops->rr(mdev, __mt7996_reg_remap_addr(dev, offset));
spin_unlock_bh(&dev->reg_lock);
return val;
}
static void mt7996_wr(struct mt76_dev *mdev, u32 offset, u32 val)
{
struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
u32 addr = __mt7996_reg_addr(dev, offset);
dev->bus_ops->wr(mdev, __mt7996_reg_addr(dev, offset), val);
if (addr) {
dev->bus_ops->wr(mdev, addr, val);
return;
}
spin_lock_bh(&dev->reg_lock);
dev->bus_ops->wr(mdev, __mt7996_reg_remap_addr(dev, offset), val);
spin_unlock_bh(&dev->reg_lock);
}
static u32 mt7996_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val)
{
struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
u32 addr = __mt7996_reg_addr(dev, offset);
return dev->bus_ops->rmw(mdev, __mt7996_reg_addr(dev, offset), mask, val);
if (addr)
return dev->bus_ops->rmw(mdev, addr, mask, val);
spin_lock_bh(&dev->reg_lock);
val = dev->bus_ops->rmw(mdev, __mt7996_reg_remap_addr(dev, offset), mask, val);
spin_unlock_bh(&dev->reg_lock);
return val;
}
static int mt7996_mmio_init(struct mt76_dev *mdev,
@ -200,6 +219,7 @@ static int mt7996_mmio_init(struct mt76_dev *mdev,
dev = container_of(mdev, struct mt7996_dev, mt76);
mt76_mmio_init(&dev->mt76, mem_base);
spin_lock_init(&dev->reg_lock);
switch (device_id) {
case 0x7990:

View file

@ -242,8 +242,7 @@ struct mt7996_dev {
u8 n_agrt;
} twt;
u32 reg_l1_backup;
u32 reg_l2_backup;
spinlock_t reg_lock;
u8 wtbl_size_group;
};