wifi: mt76: mt7996: add locking for accessing mapped registers
[ Upstream commit 3687854d3e7e7fd760d939dd9e5a3520d5ab60fe ] 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:
parent
1152c2cd38
commit
1feb6fcfba
@ -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:
|
||||
|
@ -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;
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user