Skip to content

Commit

Permalink
mt76: fix wcid allocation issues
Browse files Browse the repository at this point in the history
mt76 core uses ffs() to find the next free bit. This works well for 32 bit
architectures where BITS_PER_LONG is 32. ffs only checks 32 bit values, so
allocation fails on 64 bit architectures.
Additionally, the wcid mask array was too small in cases where the array
was not a multiple of BITS_PER_LONG.
Fix this by making the wcid mask array u32 instead and use DIV_ROUND_UP
for the size, just in case we ever bump it to a value that's not a multiple
of 32.

Signed-off-by: Felix Fietkau <[email protected]>
  • Loading branch information
nbd168 committed May 23, 2020
1 parent 466a5b4 commit 984a172
Show file tree
Hide file tree
Showing 3 changed files with 15 additions and 15 deletions.
4 changes: 2 additions & 2 deletions mt76.h
Original file line number Diff line number Diff line change
Expand Up @@ -537,8 +537,8 @@ struct mt76_dev {
wait_queue_head_t tx_wait;
struct sk_buff_head status_list;

unsigned long wcid_mask[MT76_N_WCIDS / BITS_PER_LONG];
unsigned long wcid_phy_mask[MT76_N_WCIDS / BITS_PER_LONG];
u32 wcid_mask[DIV_ROUND_UP(MT76_N_WCIDS, 32)];
u32 wcid_phy_mask[DIV_ROUND_UP(MT76_N_WCIDS, 32)];

struct mt76_wcid global_wcid;
struct mt76_wcid __rcu *wcid[MT76_N_WCIDS];
Expand Down
12 changes: 6 additions & 6 deletions util.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,17 @@ bool __mt76_poll_msec(struct mt76_dev *dev, u32 offset, u32 mask, u32 val,
}
EXPORT_SYMBOL_GPL(__mt76_poll_msec);

int mt76_wcid_alloc(unsigned long *mask, int size)
int mt76_wcid_alloc(u32 *mask, int size)
{
int i, idx = 0, cur;

for (i = 0; i < DIV_ROUND_UP(size, BITS_PER_LONG); i++) {
for (i = 0; i < DIV_ROUND_UP(size, 32); i++) {
idx = ffs(~mask[i]);
if (!idx)
continue;

idx--;
cur = i * BITS_PER_LONG + idx;
cur = i * 32 + idx;
if (cur >= size)
break;

Expand All @@ -74,13 +74,13 @@ int mt76_get_min_avg_rssi(struct mt76_dev *dev, bool ext_phy)
rcu_read_lock();

for (i = 0; i < ARRAY_SIZE(dev->wcid_mask); i++) {
unsigned long mask = dev->wcid_mask[i];
unsigned long phy_mask = dev->wcid_phy_mask[i];
u32 mask = dev->wcid_mask[i];
u32 phy_mask = dev->wcid_phy_mask[i];

if (!mask)
continue;

for (j = i * BITS_PER_LONG; mask; j++, mask >>= 1, phy_mask >>= 1) {
for (j = i * 32; mask; j++, mask >>= 1, phy_mask >>= 1) {
if (!(mask & 1))
continue;

Expand Down
14 changes: 7 additions & 7 deletions util.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,24 @@
#define MT76_INCR(_var, _size) \
(_var = (((_var) + 1) % (_size)))

int mt76_wcid_alloc(unsigned long *mask, int size);
int mt76_wcid_alloc(u32 *mask, int size);

static inline bool
mt76_wcid_mask_test(unsigned long *mask, int idx)
mt76_wcid_mask_test(u32 *mask, int idx)
{
return mask[idx / BITS_PER_LONG] & BIT(idx % BITS_PER_LONG);
return mask[idx / 32] & BIT(idx % 32);
}

static inline void
mt76_wcid_mask_set(unsigned long *mask, int idx)
mt76_wcid_mask_set(u32 *mask, int idx)
{
mask[idx / BITS_PER_LONG] |= BIT(idx % BITS_PER_LONG);
mask[idx / 32] |= BIT(idx % 32);
}

static inline void
mt76_wcid_mask_clear(unsigned long *mask, int idx)
mt76_wcid_mask_clear(u32 *mask, int idx)
{
mask[idx / BITS_PER_LONG] &= ~BIT(idx % BITS_PER_LONG);
mask[idx / 32] &= ~BIT(idx % 32);
}

static inline void
Expand Down

0 comments on commit 984a172

Please sign in to comment.