2013-08-19 13:11:25

by Gabor Juhos

[permalink] [raw]
Subject: [PATCH v2 0/6] rt2x00: fix beaconing on RT3593

Gabor Juhos (6):
rt2x00: rt2800lib: move rt2800_drv_data declaration into rt2800lib.h
rt2x00: rt2800lib: introduce RT2800_HAS_HIGH_SHARED_MEM flag
rt2x00: rt2800: serialize shared memory access
rt2x00: rt2800lib: add rt2800_hw_beacon_base helper
rt2x00: rt2800lib: don't hardcode beacon offsets
rt2x00: rt2800lib: fix beacon generation on RT3593

drivers/net/wireless/rt2x00/rt2800.h | 18 ++--
drivers/net/wireless/rt2x00/rt2800lib.c | 141 ++++++++++++++++++++++++++++---
drivers/net/wireless/rt2x00/rt2800lib.h | 42 +++++++++
drivers/net/wireless/rt2x00/rt2800pci.c | 10 +++
drivers/net/wireless/rt2x00/rt2800usb.c | 5 ++
5 files changed, 193 insertions(+), 23 deletions(-)

--
1.7.10


2013-08-19 13:11:27

by Gabor Juhos

[permalink] [raw]
Subject: [PATCH v2 5/6] rt2x00: rt2800lib: don't hardcode beacon offsets

The values written into the BCN_OFFSET[01] registers are
hardcoded in the rt2800_init_register function.

Add a macro and a helper function to derive these values
directly from the base address of a given beacon, and use
the new function instead of the hardcoded numbers.

The patch contains no functional changes. The programmed
register values are the same before and after the patch.

Signed-off-by: Gabor Juhos <[email protected]>
---
Changes since v1: ---
---
drivers/net/wireless/rt2x00/rt2800.h | 2 ++
drivers/net/wireless/rt2x00/rt2800lib.c | 30 ++++++++++++++++++++++--------
2 files changed, 24 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h
index 426129a..48018a5 100644
--- a/drivers/net/wireless/rt2x00/rt2800.h
+++ b/drivers/net/wireless/rt2x00/rt2800.h
@@ -2024,6 +2024,8 @@ struct mac_iveiv_entry {
(((__index) < 6) ? (HW_BEACON_BASE4 + ((__index - 4) * 0x0200)) : \
(HW_BEACON_BASE6 - ((__index - 6) * 0x0200))))

+#define BEACON_BASE_TO_OFFSET(_base) (((_base) - 0x4000) / 64)
+
/*
* BBP registers.
* The wordsize of the BBP is 8 bits.
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index 18a95e3..3bd0fae 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -954,6 +954,12 @@ static unsigned int rt2800_hw_beacon_base(struct rt2x00_dev *rt2x00dev,
return HW_BEACON_BASE(index);
}

+static inline u8 rt2800_get_beacon_offset(struct rt2x00_dev *rt2x00dev,
+ unsigned int index)
+{
+ return BEACON_BASE_TO_OFFSET(rt2800_hw_beacon_base(rt2x00dev, index));
+}
+
void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
@@ -4505,17 +4511,25 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
return ret;

rt2800_register_read(rt2x00dev, BCN_OFFSET0, &reg);
- rt2x00_set_field32(&reg, BCN_OFFSET0_BCN0, 0xe0); /* 0x3800 */
- rt2x00_set_field32(&reg, BCN_OFFSET0_BCN1, 0xe8); /* 0x3a00 */
- rt2x00_set_field32(&reg, BCN_OFFSET0_BCN2, 0xf0); /* 0x3c00 */
- rt2x00_set_field32(&reg, BCN_OFFSET0_BCN3, 0xf8); /* 0x3e00 */
+ rt2x00_set_field32(&reg, BCN_OFFSET0_BCN0,
+ rt2800_get_beacon_offset(rt2x00dev, 0));
+ rt2x00_set_field32(&reg, BCN_OFFSET0_BCN1,
+ rt2800_get_beacon_offset(rt2x00dev, 1));
+ rt2x00_set_field32(&reg, BCN_OFFSET0_BCN2,
+ rt2800_get_beacon_offset(rt2x00dev, 2));
+ rt2x00_set_field32(&reg, BCN_OFFSET0_BCN3,
+ rt2800_get_beacon_offset(rt2x00dev, 3));
rt2800_register_write(rt2x00dev, BCN_OFFSET0, reg);

rt2800_register_read(rt2x00dev, BCN_OFFSET1, &reg);
- rt2x00_set_field32(&reg, BCN_OFFSET1_BCN4, 0xc8); /* 0x3200 */
- rt2x00_set_field32(&reg, BCN_OFFSET1_BCN5, 0xd0); /* 0x3400 */
- rt2x00_set_field32(&reg, BCN_OFFSET1_BCN6, 0x77); /* 0x1dc0 */
- rt2x00_set_field32(&reg, BCN_OFFSET1_BCN7, 0x6f); /* 0x1bc0 */
+ rt2x00_set_field32(&reg, BCN_OFFSET1_BCN4,
+ rt2800_get_beacon_offset(rt2x00dev, 4));
+ rt2x00_set_field32(&reg, BCN_OFFSET1_BCN5,
+ rt2800_get_beacon_offset(rt2x00dev, 5));
+ rt2x00_set_field32(&reg, BCN_OFFSET1_BCN6,
+ rt2800_get_beacon_offset(rt2x00dev, 6));
+ rt2x00_set_field32(&reg, BCN_OFFSET1_BCN7,
+ rt2800_get_beacon_offset(rt2x00dev, 7));
rt2800_register_write(rt2x00dev, BCN_OFFSET1, reg);

rt2800_register_write(rt2x00dev, LEGACY_BASIC_RATE, 0x0000013f);
--
1.7.10

2013-08-21 16:42:38

by Gabor Juhos

[permalink] [raw]
Subject: Re: [PATCH v2 3/6] rt2x00: rt2800: serialize shared memory access

Hi Helmut,

> On Mon, Aug 19, 2013 at 3:11 PM, Gabor Juhos <[email protected]> wrote:
>> The shared memory of the rt2800 devices is accessible
>> through the register offset range between 0x4000 and
>> 0x8000. The size of this range is 16KB only and on
>> devices which have more than 16KB of shared memory either
>> the low or the high part of the memory is accessible at a
>> time.
>>
>
>> Serialize all accesses to the shared memory by a mutex,
>> in order to avoid concurrent use of that.
>>
>> Signed-off-by: Gabor Juhos <[email protected]>
>> ---
>
> [...]
>
>
>> @@ -993,8 +1001,11 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
>> }
>>
>> beacon_base = HW_BEACON_BASE(entry->entry_idx);
>> +
>> + rt2800_shared_mem_lock(rt2x00dev);
>> rt2800_register_multiwrite(rt2x00dev, beacon_base, entry->skb->data,
>> entry->skb->len + padding_len);
>> + rt2800_shared_mem_unlock(rt2x00dev);
>>
>> /*
>> * Enable beaconing again.
>
> Beacons on PCI devices are updated from pre_tbtt or beacon_done tasklet.
> Looks like this will fail for pci then ...

Hm, you are right:

BUG: sleeping function called from invalid context at kernel/mutex.c:619
in_atomic(): 1, irqs_disabled(): 0, pid: 0, name: swapper
INFO: lockdep is turned off.
CPU: 0 PID: 0 Comm: swapper Tainted: G O 3.11.0-rc6-wl #627
Stack : 00000000 00000000 80745dbe 00000045 00000000 80439ca0 803f097c 80723a50
8043da78 8043d7c7 001f0640 80439ca0 83dfee20 803f0000 00000006 8035c3dc
00000000 80031558 80745dbc 00000000 803f42b8 80439b9c 80439b9c 803f097c
c01ba400 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 80439b30
...
Call Trace:
[<8000d328>] show_stack+0x64/0x7c
[<80361ca0>] mutex_lock_nested+0x4c/0x484
[<c01ba458>] rt2800_write_beacon+0x300/0x460 [rt2800lib]
[<c016dc24>] rt2x00queue_update_beacon_locked+0xc0/0xe4 [rt2x00lib]
[<8033fa30>] ieee80211_iterate_active_interfaces_atomic+0x180/0x188
[<c01cbb18>] 0xc01cbb18


In an early version of the patch, I have used a spinlock but that was not
suitable for USB devices. I have to rethink that how can I resolve this.

Thank you for the review!

-Gabor

2013-08-19 13:20:40

by Helmut Schaa

[permalink] [raw]
Subject: Re: [PATCH v2 3/6] rt2x00: rt2800: serialize shared memory access

Hi Gabor,

On Mon, Aug 19, 2013 at 3:11 PM, Gabor Juhos <[email protected]> wrote:
> The shared memory of the rt2800 devices is accessible
> through the register offset range between 0x4000 and
> 0x8000. The size of this range is 16KB only and on
> devices which have more than 16KB of shared memory either
> the low or the high part of the memory is accessible at a
> time.
>

> Serialize all accesses to the shared memory by a mutex,
> in order to avoid concurrent use of that.
>
> Signed-off-by: Gabor Juhos <[email protected]>
> ---

[...]


> @@ -993,8 +1001,11 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
> }
>
> beacon_base = HW_BEACON_BASE(entry->entry_idx);
> +
> + rt2800_shared_mem_lock(rt2x00dev);
> rt2800_register_multiwrite(rt2x00dev, beacon_base, entry->skb->data,
> entry->skb->len + padding_len);
> + rt2800_shared_mem_unlock(rt2x00dev);
>
> /*
> * Enable beaconing again.

Beacons on PCI devices are updated from pre_tbtt or beacon_done tasklet.
Looks like this will fail for pci then ...

Helmut

2013-08-19 13:11:25

by Gabor Juhos

[permalink] [raw]
Subject: [PATCH v2 1/6] rt2x00: rt2800lib: move rt2800_drv_data declaration into rt2800lib.h

The rt2800_drv_data structure contains driver specific
information. Move the declaration into the rt2800lib.h
header which is a more logical place for it. Also fix
the comment style to avoid checkpatch warning.

The patch contains no functional changes, it is in
preparation for the next patch.

Signed-off-by: Gabor Juhos <[email protected]>
---
Changes since v1: ---
---
drivers/net/wireless/rt2x00/rt2800.h | 13 -------------
drivers/net/wireless/rt2x00/rt2800lib.h | 11 +++++++++++
2 files changed, 11 insertions(+), 13 deletions(-)

diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h
index e25e5bf..426129a 100644
--- a/drivers/net/wireless/rt2x00/rt2800.h
+++ b/drivers/net/wireless/rt2x00/rt2800.h
@@ -2956,17 +2956,4 @@ enum rt2800_eeprom_word {
*/
#define BCN_TBTT_OFFSET 64

-/*
- * RT2800 driver data structure
- */
-struct rt2800_drv_data {
- u8 calibration_bw20;
- u8 calibration_bw40;
- u8 bbp25;
- u8 bbp26;
- u8 txmixer_gain_24g;
- u8 txmixer_gain_5g;
- unsigned int tbtt_tick;
-};
-
#endif /* RT2800_H */
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h
index a94ba44..9b3e8ef 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/rt2x00/rt2800lib.h
@@ -22,6 +22,17 @@
#ifndef RT2800LIB_H
#define RT2800LIB_H

+/* RT2800 driver data structure */
+struct rt2800_drv_data {
+ u8 calibration_bw20;
+ u8 calibration_bw40;
+ u8 bbp25;
+ u8 bbp26;
+ u8 txmixer_gain_24g;
+ u8 txmixer_gain_5g;
+ unsigned int tbtt_tick;
+};
+
struct rt2800_ops {
void (*register_read)(struct rt2x00_dev *rt2x00dev,
const unsigned int offset, u32 *value);
--
1.7.10

2013-08-19 13:11:25

by Gabor Juhos

[permalink] [raw]
Subject: [PATCH v2 3/6] rt2x00: rt2800: serialize shared memory access

The shared memory of the rt2800 devices is accessible
through the register offset range between 0x4000 and
0x8000. The size of this range is 16KB only and on
devices which have more than 16KB of shared memory either
the low or the high part of the memory is accessible at a
time.

Serialize all accesses to the shared memory by a mutex,
in order to avoid concurrent use of that.

Signed-off-by: Gabor Juhos <[email protected]>
---
Changes since v1: ---
---
drivers/net/wireless/rt2x00/rt2800lib.c | 50 +++++++++++++++++++++++++++++++
drivers/net/wireless/rt2x00/rt2800lib.h | 18 +++++++++++
drivers/net/wireless/rt2x00/rt2800pci.c | 10 +++++++
drivers/net/wireless/rt2x00/rt2800usb.c | 5 ++++
4 files changed, 83 insertions(+)

diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index 94da67c..cb37b32 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -445,6 +445,7 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev,
if (rt2x00_is_soc(rt2x00dev))
return;

+ rt2800_shared_mem_lock(rt2x00dev);
mutex_lock(&rt2x00dev->csr_mutex);

/*
@@ -464,6 +465,7 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev,
}

mutex_unlock(&rt2x00dev->csr_mutex);
+ rt2800_shared_mem_unlock(rt2x00dev);
}
EXPORT_SYMBOL_GPL(rt2800_mcu_request);

@@ -699,10 +701,16 @@ int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev,
/*
* Initialize firmware.
*/
+ rt2800_shared_mem_lock(rt2x00dev);
rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0);
rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
+ rt2800_shared_mem_unlock(rt2x00dev);
+
if (rt2x00_is_usb(rt2x00dev)) {
+ rt2800_shared_mem_lock(rt2x00dev);
rt2800_register_write(rt2x00dev, H2M_INT_SRC, 0);
+ rt2800_shared_mem_unlock(rt2x00dev);
+
rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0);
}
msleep(1);
@@ -993,8 +1001,11 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
}

beacon_base = HW_BEACON_BASE(entry->entry_idx);
+
+ rt2800_shared_mem_lock(rt2x00dev);
rt2800_register_multiwrite(rt2x00dev, beacon_base, entry->skb->data,
entry->skb->len + padding_len);
+ rt2800_shared_mem_unlock(rt2x00dev);

/*
* Enable beaconing again.
@@ -1019,6 +1030,8 @@ static inline void rt2800_clear_beacon_register(struct rt2x00_dev *rt2x00dev,

beacon_base = HW_BEACON_BASE(index);

+ rt2800_shared_mem_lock(rt2x00dev);
+
/*
* For the Beacon base registers we only need to clear
* the whole TXWI which (when set to 0) will invalidate
@@ -1026,6 +1039,8 @@ static inline void rt2800_clear_beacon_register(struct rt2x00_dev *rt2x00dev,
*/
for (i = 0; i < txwi_desc_size; i += sizeof(__le32))
rt2800_register_write(rt2x00dev, beacon_base + i, 0);
+
+ rt2800_shared_mem_unlock(rt2x00dev);
}

void rt2800_clear_beacon(struct queue_entry *entry)
@@ -1209,7 +1224,9 @@ static void rt2800_delete_wcid_attr(struct rt2x00_dev *rt2x00dev, int wcid)
{
u32 offset;
offset = MAC_WCID_ATTR_ENTRY(wcid);
+ rt2800_shared_mem_lock(rt2x00dev);
rt2800_register_write(rt2x00dev, offset, 0);
+ rt2800_shared_mem_unlock(rt2x00dev);
}

static void rt2800_config_wcid_attr_bssidx(struct rt2x00_dev *rt2x00dev,
@@ -1222,11 +1239,13 @@ static void rt2800_config_wcid_attr_bssidx(struct rt2x00_dev *rt2x00dev,
* The BSS Idx numbers is split in a main value of 3 bits,
* and a extended field for adding one additional bit to the value.
*/
+ rt2800_shared_mem_lock(rt2x00dev);
rt2800_register_read(rt2x00dev, offset, &reg);
rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_BSS_IDX, (bssidx & 0x7));
rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_BSS_IDX_EXT,
(bssidx & 0x8) >> 3);
rt2800_register_write(rt2x00dev, offset, reg);
+ rt2800_shared_mem_unlock(rt2x00dev);
}

static void rt2800_config_wcid_attr_cipher(struct rt2x00_dev *rt2x00dev,
@@ -1239,6 +1258,7 @@ static void rt2800_config_wcid_attr_cipher(struct rt2x00_dev *rt2x00dev,

offset = MAC_WCID_ATTR_ENTRY(key->hw_key_idx);

+ rt2800_shared_mem_lock(rt2x00dev);
if (crypto->cmd == SET_KEY) {
rt2800_register_read(rt2x00dev, offset, &reg);
rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_KEYTAB,
@@ -1263,6 +1283,7 @@ static void rt2800_config_wcid_attr_cipher(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_RX_WIUDF, 0);
rt2800_register_write(rt2x00dev, offset, reg);
}
+ rt2800_shared_mem_unlock(rt2x00dev);

offset = MAC_IVEIV_ENTRY(key->hw_key_idx);

@@ -1272,8 +1293,11 @@ static void rt2800_config_wcid_attr_cipher(struct rt2x00_dev *rt2x00dev,
(crypto->cipher == CIPHER_AES))
iveiv_entry.iv[3] |= 0x20;
iveiv_entry.iv[3] |= key->keyidx << 6;
+
+ rt2800_shared_mem_lock(rt2x00dev);
rt2800_register_multiwrite(rt2x00dev, offset,
&iveiv_entry, sizeof(iveiv_entry));
+ rt2800_shared_mem_unlock(rt2x00dev);
}

int rt2800_config_shared_key(struct rt2x00_dev *rt2x00dev,
@@ -1296,8 +1320,11 @@ int rt2800_config_shared_key(struct rt2x00_dev *rt2x00dev,
sizeof(key_entry.rx_mic));

offset = SHARED_KEY_ENTRY(key->hw_key_idx);
+
+ rt2800_shared_mem_lock(rt2x00dev);
rt2800_register_multiwrite(rt2x00dev, offset,
&key_entry, sizeof(key_entry));
+ rt2800_shared_mem_unlock(rt2x00dev);
}

/*
@@ -1312,10 +1339,12 @@ int rt2800_config_shared_key(struct rt2x00_dev *rt2x00dev,

offset = SHARED_KEY_MODE_ENTRY(key->hw_key_idx / 8);

+ rt2800_shared_mem_lock(rt2x00dev);
rt2800_register_read(rt2x00dev, offset, &reg);
rt2x00_set_field32(&reg, field,
(crypto->cmd == SET_KEY) * crypto->cipher);
rt2800_register_write(rt2x00dev, offset, reg);
+ rt2800_shared_mem_unlock(rt2x00dev);

/*
* Update WCID information
@@ -1385,8 +1414,11 @@ int rt2800_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
sizeof(key_entry.rx_mic));

offset = PAIRWISE_KEY_ENTRY(key->hw_key_idx);
+
+ rt2800_shared_mem_lock(rt2x00dev);
rt2800_register_multiwrite(rt2x00dev, offset,
&key_entry, sizeof(key_entry));
+ rt2800_shared_mem_unlock(rt2x00dev);
}

/*
@@ -4816,14 +4848,19 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
/*
* ASIC will keep garbage value after boot, clear encryption keys.
*/
+ rt2800_shared_mem_lock(rt2x00dev);
for (i = 0; i < 4; i++)
rt2800_register_write(rt2x00dev,
SHARED_KEY_MODE_ENTRY(i), 0);
+ rt2800_shared_mem_unlock(rt2x00dev);

for (i = 0; i < 256; i++) {
rt2800_config_wcid(rt2x00dev, NULL, i);
rt2800_delete_wcid_attr(rt2x00dev, i);
+
+ rt2800_shared_mem_lock(rt2x00dev);
rt2800_register_write(rt2x00dev, MAC_IVEIV_ENTRY(i), 0);
+ rt2800_shared_mem_unlock(rt2x00dev);
}

/*
@@ -4949,8 +4986,10 @@ static int rt2800_wait_bbp_ready(struct rt2x00_dev *rt2x00dev)
* BBP was enabled after firmware was loaded,
* but we need to reactivate it now.
*/
+ rt2800_shared_mem_lock(rt2x00dev);
rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0);
rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
+ rt2800_shared_mem_unlock(rt2x00dev);
msleep(1);

for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
@@ -6634,10 +6673,16 @@ int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev)
/*
* Send signal to firmware during boot time.
*/
+ rt2800_shared_mem_lock(rt2x00dev);
rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0);
rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
+ rt2800_shared_mem_unlock(rt2x00dev);
+
if (rt2x00_is_usb(rt2x00dev)) {
+ rt2800_shared_mem_lock(rt2x00dev);
rt2800_register_write(rt2x00dev, H2M_INT_SRC, 0);
+ rt2800_shared_mem_unlock(rt2x00dev);
+
rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0);
}
msleep(1);
@@ -7701,6 +7746,8 @@ int rt2800_probe_hw(struct rt2x00_dev *rt2x00dev)
int retval;
u32 reg;

+ mutex_init(&drv_data->shared_mem_mutex);
+
retval = rt2800_probe_rt(rt2x00dev);
if (retval)
return retval;
@@ -7780,8 +7827,11 @@ void rt2800_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx, u32 *iv32,
u32 offset;

offset = MAC_IVEIV_ENTRY(hw_key_idx);
+
+ rt2800_shared_mem_lock(rt2x00dev);
rt2800_register_multiread(rt2x00dev, offset,
&iveiv_entry, sizeof(iveiv_entry));
+ rt2800_shared_mem_unlock(rt2x00dev);

memcpy(iv16, &iveiv_entry.iv[0], sizeof(*iv16));
memcpy(iv32, &iveiv_entry.iv[4], sizeof(*iv32));
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h
index f89d413..f3f4404 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/rt2x00/rt2800lib.h
@@ -37,6 +37,8 @@ struct rt2800_drv_data {
unsigned int tbtt_tick;

unsigned long rt2800_flags;
+
+ struct mutex shared_mem_mutex;
};

struct rt2800_ops {
@@ -76,6 +78,22 @@ static inline bool rt2800_has_high_shared_mem(struct rt2x00_dev *rt2x00dev)
return test_bit(RT2800_HAS_HIGH_SHARED_MEM, &drv_data->rt2800_flags);
}

+static inline void rt2800_shared_mem_lock(struct rt2x00_dev *rt2x00dev)
+{
+ struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;
+
+ if (rt2800_has_high_shared_mem(rt2x00dev))
+ mutex_lock(&drv_data->shared_mem_mutex);
+}
+
+static inline void rt2800_shared_mem_unlock(struct rt2x00_dev *rt2x00dev)
+{
+ struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;
+
+ if (rt2800_has_high_shared_mem(rt2x00dev))
+ mutex_unlock(&drv_data->shared_mem_mutex);
+}
+
static inline void rt2800_register_read(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
u32 *value)
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index f8f2abb..b14ddf6 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -71,6 +71,8 @@ static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token)
if (rt2x00_is_soc(rt2x00dev))
return;

+ rt2800_shared_mem_lock(rt2x00dev);
+
for (i = 0; i < 200; i++) {
rt2x00mmio_register_read(rt2x00dev, H2M_MAILBOX_CID, &reg);

@@ -88,6 +90,8 @@ static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token)

rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0);
rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
+
+ rt2800_shared_mem_unlock(rt2x00dev);
}

#if defined(CONFIG_SOC_RT288X) || defined(CONFIG_SOC_RT305X)
@@ -325,8 +329,10 @@ static int rt2800pci_write_firmware(struct rt2x00_dev *rt2x00dev,
rt2x00mmio_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000);
rt2x00mmio_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00001);

+ rt2800_shared_mem_lock(rt2x00dev);
rt2x00mmio_register_write(rt2x00dev, H2M_BBP_AGENT, 0);
rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
+ rt2800_shared_mem_unlock(rt2x00dev);

return 0;
}
@@ -547,8 +553,10 @@ static int rt2800pci_enable_radio(struct rt2x00_dev *rt2x00dev)
return retval;

/* After resume MCU_BOOT_SIGNAL will trash these. */
+ rt2800_shared_mem_lock(rt2x00dev);
rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0);
rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
+ rt2800_shared_mem_unlock(rt2x00dev);

rt2800_mcu_request(rt2x00dev, MCU_SLEEP, TOKEN_RADIO_OFF, 0xff, 0x02);
rt2800pci_mcu_status(rt2x00dev, TOKEN_RADIO_OFF);
@@ -576,10 +584,12 @@ static int rt2800pci_set_state(struct rt2x00_dev *rt2x00dev,
0, 0x02);
rt2800pci_mcu_status(rt2x00dev, TOKEN_WAKEUP);
} else if (state == STATE_SLEEP) {
+ rt2800_shared_mem_lock(rt2x00dev);
rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_STATUS,
0xffffffff);
rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_CID,
0xffffffff);
+ rt2800_shared_mem_unlock(rt2x00dev);
rt2800_mcu_request(rt2x00dev, MCU_SLEEP, TOKEN_SLEEP,
0xff, 0x01);
}
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 338034e..4ff38b8 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -259,8 +259,10 @@ static int rt2800usb_write_firmware(struct rt2x00_dev *rt2x00dev,
rt2x00usb_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE,
data + offset, length);

+ rt2800_shared_mem_lock(rt2x00dev);
rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0);
+ rt2800_shared_mem_unlock(rt2x00dev);

/*
* Send firmware request to device to load firmware,
@@ -275,7 +277,10 @@ static int rt2800usb_write_firmware(struct rt2x00_dev *rt2x00dev,
}

msleep(10);
+
+ rt2800_shared_mem_lock(rt2x00dev);
rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
+ rt2800_shared_mem_unlock(rt2x00dev);

return 0;
}
--
1.7.10

2013-08-19 13:11:27

by Gabor Juhos

[permalink] [raw]
Subject: [PATCH v2 4/6] rt2x00: rt2800lib: add rt2800_hw_beacon_base helper

The HW_BEACON_BASE() macro returns the base address
of a given beacon, however the returned values are
not usable on all chipsets. On devices which have
selectable shared memory parts, some beacon may be
located in the high part of the shared memory.

Instead of extending the already complicated macro,
add a new helper function and use that to get the
base address of a given beacon.

Te helper function will be extended in a subsequent
patch to handle different chipsets' requirements,
the actual patch contains no functional changes.

Signed-off-by: Gabor Juhos <[email protected]>
---
Changes since v1: ---
---
drivers/net/wireless/rt2x00/rt2800lib.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index cb37b32..18a95e3 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -948,6 +948,12 @@ void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32 *txwi)
}
EXPORT_SYMBOL_GPL(rt2800_txdone_entry);

+static unsigned int rt2800_hw_beacon_base(struct rt2x00_dev *rt2x00dev,
+ unsigned int index)
+{
+ return HW_BEACON_BASE(index);
+}
+
void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
@@ -1000,7 +1006,7 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
return;
}

- beacon_base = HW_BEACON_BASE(entry->entry_idx);
+ beacon_base = rt2800_hw_beacon_base(rt2x00dev, entry->entry_idx);

rt2800_shared_mem_lock(rt2x00dev);
rt2800_register_multiwrite(rt2x00dev, beacon_base, entry->skb->data,
@@ -1028,7 +1034,7 @@ static inline void rt2800_clear_beacon_register(struct rt2x00_dev *rt2x00dev,
const int txwi_desc_size = rt2x00dev->bcn->winfo_size;
unsigned int beacon_base;

- beacon_base = HW_BEACON_BASE(index);
+ beacon_base = rt2800_hw_beacon_base(rt2x00dev, index);

rt2800_shared_mem_lock(rt2x00dev);

--
1.7.10

2013-08-19 13:11:25

by Gabor Juhos

[permalink] [raw]
Subject: [PATCH v2 2/6] rt2x00: rt2800lib: introduce RT2800_HAS_HIGH_SHARED_MEM flag

Some chipsets have more than 16KB of shared memory.
Introduce a new rt2800 specific flag to indicate that
and add a helper function which helps to check the
presence of the new flag.

Also enable the new flag for the RT3593 chipset which
has 24KB of shared memory. The flag can also be used
for other chipsets, but none of those has been tested
yet.

Signed-off-by: Gabor Juhos <[email protected]>
---
Changes since v1:
- don't enable the new flag for RT3071 and RT5592
---
drivers/net/wireless/rt2x00/rt2800lib.c | 4 ++++
drivers/net/wireless/rt2x00/rt2800lib.h | 13 +++++++++++++
2 files changed, 17 insertions(+)

diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index aa6b6b0..94da67c 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -7697,6 +7697,7 @@ static int rt2800_probe_rt(struct rt2x00_dev *rt2x00dev)

int rt2800_probe_hw(struct rt2x00_dev *rt2x00dev)
{
+ struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;
int retval;
u32 reg;

@@ -7704,6 +7705,9 @@ int rt2800_probe_hw(struct rt2x00_dev *rt2x00dev)
if (retval)
return retval;

+ if (rt2x00_rt(rt2x00dev, RT3593))
+ __set_bit(RT2800_HAS_HIGH_SHARED_MEM, &drv_data->rt2800_flags);
+
/*
* Allocate eeprom data.
*/
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h
index 9b3e8ef..f89d413 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/rt2x00/rt2800lib.h
@@ -22,6 +22,10 @@
#ifndef RT2800LIB_H
#define RT2800LIB_H

+enum rt2800_flag {
+ RT2800_HAS_HIGH_SHARED_MEM,
+};
+
/* RT2800 driver data structure */
struct rt2800_drv_data {
u8 calibration_bw20;
@@ -31,6 +35,8 @@ struct rt2800_drv_data {
u8 txmixer_gain_24g;
u8 txmixer_gain_5g;
unsigned int tbtt_tick;
+
+ unsigned long rt2800_flags;
};

struct rt2800_ops {
@@ -63,6 +69,13 @@ struct rt2800_ops {
__le32 *(*drv_get_txwi)(struct queue_entry *entry);
};

+static inline bool rt2800_has_high_shared_mem(struct rt2x00_dev *rt2x00dev)
+{
+ struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;
+
+ return test_bit(RT2800_HAS_HIGH_SHARED_MEM, &drv_data->rt2800_flags);
+}
+
static inline void rt2800_register_read(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
u32 *value)
--
1.7.10

2013-08-19 13:11:28

by Gabor Juhos

[permalink] [raw]
Subject: [PATCH v2 6/6] rt2x00: rt2800lib: fix beacon generation on RT3593

On the RT3593 chipset, the beacon registers are located
in the high 8KB part of the shared memory.

The high part of the shared memory is only accessible
if it is explicitly selected. Add a helper function
in order to be able to control the SHR_MSEL bit in
the PBF_SYS_CTRL register. Also add a few more helper
functions and use those to select the correct part of
the shared memory before and after accessing the beacon
registers.

The base addresses of the beacon registers are also
different from the actually used values, so fix the
'rt2800_hw_beacon_base' function to return the correct
values.

Signed-off-by: Gabor Juhos <[email protected]>
---
Changes since v1: ---
---
drivers/net/wireless/rt2x00/rt2800.h | 3 ++
drivers/net/wireless/rt2x00/rt2800lib.c | 47 +++++++++++++++++++++++++++++++
2 files changed, 50 insertions(+)

diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h
index 48018a5..67498b0 100644
--- a/drivers/net/wireless/rt2x00/rt2800.h
+++ b/drivers/net/wireless/rt2x00/rt2800.h
@@ -572,6 +572,7 @@
#define PBF_SYS_CTRL 0x0400
#define PBF_SYS_CTRL_READY FIELD32(0x00000080)
#define PBF_SYS_CTRL_HOST_RAM_WRITE FIELD32(0x00010000)
+#define PBF_SYS_CTRL_SHR_MSEL FIELD32(0x00080000)

/*
* HOST-MCU shared memory
@@ -2024,6 +2025,8 @@ struct mac_iveiv_entry {
(((__index) < 6) ? (HW_BEACON_BASE4 + ((__index - 4) * 0x0200)) : \
(HW_BEACON_BASE6 - ((__index - 6) * 0x0200))))

+#define HW_BEACON_BASE_HIGH(__index) (0x4000 + (__index) * 512)
+
#define BEACON_BASE_TO_OFFSET(_base) (((_base) - 0x4000) / 64)

/*
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index 3bd0fae..13df86c 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -84,6 +84,42 @@ static inline bool rt2800_is_305x_soc(struct rt2x00_dev *rt2x00dev)
return false;
}

+static inline void rt2800_shared_mem_select(struct rt2x00_dev *rt2x00dev,
+ bool high)
+{
+ struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;
+ u32 reg;
+
+ lockdep_assert_held(&drv_data->shared_mem_mutex);
+
+ if (WARN_ON_ONCE(!rt2800_has_high_shared_mem(rt2x00dev)))
+ return;
+
+ rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, &reg);
+ rt2x00_set_field32(&reg, PBF_SYS_CTRL_SHR_MSEL, high);
+ rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, reg);
+}
+
+static inline bool rt2800_beacon_uses_high_mem(struct rt2x00_dev *rt2x00dev)
+{
+ if (rt2x00_rt(rt2x00dev, RT3593))
+ return true;
+
+ return false;
+}
+
+static inline void rt2800_select_beacon_mem(struct rt2x00_dev *rt2x00dev)
+{
+ if (rt2800_beacon_uses_high_mem(rt2x00dev))
+ rt2800_shared_mem_select(rt2x00dev, true);
+}
+
+static inline void rt2800_deselect_beacon_mem(struct rt2x00_dev *rt2x00dev)
+{
+ if (rt2800_beacon_uses_high_mem(rt2x00dev))
+ rt2800_shared_mem_select(rt2x00dev, false);
+}
+
static void rt2800_bbp_write(struct rt2x00_dev *rt2x00dev,
const unsigned int word, const u8 value)
{
@@ -951,6 +987,9 @@ EXPORT_SYMBOL_GPL(rt2800_txdone_entry);
static unsigned int rt2800_hw_beacon_base(struct rt2x00_dev *rt2x00dev,
unsigned int index)
{
+ if (rt2x00_rt(rt2x00dev, RT3593))
+ return HW_BEACON_BASE_HIGH(index);
+
return HW_BEACON_BASE(index);
}

@@ -1015,8 +1054,12 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
beacon_base = rt2800_hw_beacon_base(rt2x00dev, entry->entry_idx);

rt2800_shared_mem_lock(rt2x00dev);
+
+ rt2800_select_beacon_mem(rt2x00dev);
rt2800_register_multiwrite(rt2x00dev, beacon_base, entry->skb->data,
entry->skb->len + padding_len);
+ rt2800_deselect_beacon_mem(rt2x00dev);
+
rt2800_shared_mem_unlock(rt2x00dev);

/*
@@ -1044,6 +1087,8 @@ static inline void rt2800_clear_beacon_register(struct rt2x00_dev *rt2x00dev,

rt2800_shared_mem_lock(rt2x00dev);

+ rt2800_select_beacon_mem(rt2x00dev);
+
/*
* For the Beacon base registers we only need to clear
* the whole TXWI which (when set to 0) will invalidate
@@ -1052,6 +1097,8 @@ static inline void rt2800_clear_beacon_register(struct rt2x00_dev *rt2x00dev,
for (i = 0; i < txwi_desc_size; i += sizeof(__le32))
rt2800_register_write(rt2x00dev, beacon_base + i, 0);

+ rt2800_deselect_beacon_mem(rt2x00dev);
+
rt2800_shared_mem_unlock(rt2x00dev);
}

--
1.7.10