[rt2x00-users] [PATCH] rt2x00 : Fix tx and rx for rt2800pci take 2.
Alban Browaeys
prahal at yahoo.com
Thu Jul 16 05:59:52 EST 2009
Second attempt that fix the heavy load or long use queue filled or even segfault when race happens
(using WCID instead of trying to keep it with the key_idx).
The current version has been tested with wpa 2 personal network and the previous one which was close
enough with open network.
Everything is fully working (suspend and resume too even though MCU status is failing on first call after
resume).
I knew about the gpio register bit which ought to be the right one in 'origin'. Though I checked the rt2860 code
which was not obvious so I cannot tell from it (there is hardware radio state and software radio state and it seems
this value is the opposite in main and in mlme. It is tested around 250 runs (two weeks of constent use of this hack) while
developping. I do not tell it is right though that it shoudl be considered by tester to switch it one side or the other
and report (as I tell afterwards on eeepc the gpio state is meaningless as the platform driver shut of the power from the wireless
card via acpu before it could be switched by the device).
Last time I did not investigate any further after our discussion and I did not this time (yet). Because I wanted to focuse on the TX/RX
cause last time focusing too narrowingly onto few register and being pedantic about each warning left me with interesting informations
though not even RX working.
Probably this should be left out of a commit to trunk.
With kind regards and thanks for the notice on the previous patch.
Alban
-----------------------------------------------------------------------
Move the register wpdma reset around to fix rx
(and reverse the gpio value sent to rfkill, to be checked again though
with the opposite value I get an ieee80211 stop. And I always get 1 on eeepc
as of the device is turned of before gpio value could be read by the platform driver
on suspend so only one value can be grabbed. Though my understanding of rfkill switch
is pretty bare).
For TX : make SD_LEN0 the length of the TXWI plus the full frame (header
+data).
Make WirelessCliID (WCID) the entry_idx instead of the key_idx ... I need
two registry entries (one for the queue index, one for the entry_idx and the code
in txdone was already attempting to read entry_idx from WCID.
Various small ghost glitches (desc_size behing TXWI_DESC_SIZE instead
of TXD_DESC_SIZE for beacon ... harmless as they are the same length
but for consistency lets fix thoses.
There are hacks in tx processing:
- in my old tests I had to add 1 to queue->index send via the TXWI to
the interrupt handler otherwise it was not passed (I remove the 1 from
the value in the interrupt handler). This has to be tested again adn removed
if not needed.
- same thing for entry_idx set in WirelessCliID (I blindly added 1 to avoid the previous
issue and did not tested otherwise to gain time getting tx fully working).
- This WCID may not be the wrong answer (key_idx may be of use there. Though I did
not found another way to avoid races in txdone. On heavy load at random time
next txdone happened between the rt2x00queue_write_tx_frame
set of the ENTRY_DATA_PENDING and rt2800pci_write_tx_desc (thus with the Q_INDEX -1
approach the current instead of the previous entry was grabbed processed and freed
before tx_write_desc ... which lead to fatal NULL - skbdesc or skb in tx_write_desc -
in interrupt context.
Signed-off-by: Alban Browaeys <prahal at yahoo.com>
---
drivers/net/wireless/rt2x00/rt2800pci.c | 93 ++++++++++++++++++++-----------
1 files changed, 61 insertions(+), 32 deletions(-)
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index 372c632..7c2ccd7 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -380,7 +380,7 @@ static int rt2800pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
u32 reg;
rt2x00pci_register_read(rt2x00dev, GPIO_CTRL_CFG, ®);
- return rt2x00_get_field32(reg, GPIO_CTRL_CFG_BIT2);
+ return !rt2x00_get_field32(reg, GPIO_CTRL_CFG_BIT2);
}
#ifdef CONFIG_RT2X00_LIB_LEDS
@@ -1389,19 +1389,6 @@ static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev)
u32 reg;
unsigned int i;
- rt2x00pci_register_read(rt2x00dev, WPDMA_RST_IDX, ®);
- rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX0, 1);
- rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX1, 1);
- rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX2, 1);
- rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX3, 1);
- rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX4, 1);
- rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX5, 1);
- rt2x00_set_field32(®, WPDMA_RST_IDX_DRX_IDX0, 1);
- rt2x00pci_register_write(rt2x00dev, WPDMA_RST_IDX, reg);
-
- rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f);
- rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00);
-
rt2x00pci_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003);
rt2x00pci_register_read(rt2x00dev, MAC_SYS_CTRL, ®);
@@ -1647,6 +1634,9 @@ static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00pci_register_read(rt2x00dev, TX_STA_CNT1, ®);
rt2x00pci_register_read(rt2x00dev, TX_STA_CNT2, ®);
+ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0);
+ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
+
return 0;
}
@@ -1957,6 +1947,20 @@ static int rt2800pci_enable_radio(struct rt2x00_dev *rt2x00dev)
u32 reg;
u16 word;
+ // pbf hardware reset : force write of wpdma updated value
+ rt2x00pci_register_read(rt2x00dev, WPDMA_RST_IDX, ®);
+ rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX0, 1);
+ rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX1, 1);
+ rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX2, 1);
+ rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX3, 1);
+ rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX4, 1);
+ rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX5, 1);
+ rt2x00_set_field32(®, WPDMA_RST_IDX_DRX_IDX0, 1);
+ rt2x00pci_register_write(rt2x00dev, WPDMA_RST_IDX, reg);
+
+ rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f);
+ rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00);
+
/*
* Initialize all registers.
*/
@@ -2030,6 +2034,17 @@ static void rt2800pci_disable_radio(struct rt2x00_dev *rt2x00dev)
rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00001280);
/* Wait for DMA, ignore error */
+ rt2x00pci_register_read(rt2x00dev, WPDMA_RST_IDX, ®);
+ rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX0, 1);
+ rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX1, 1);
+ rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX2, 1);
+ rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX3, 1);
+ rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX4, 1);
+ rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX5, 1);
+ rt2x00_set_field32(®, WPDMA_RST_IDX_DRX_IDX0, 1);
+ rt2x00pci_register_write(rt2x00dev, WPDMA_RST_IDX, reg);
+ rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f);
+ rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00);
rt2800pci_wait_wpdma_ready(rt2x00dev);
}
@@ -2145,12 +2160,14 @@ static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags));
rt2x00_set_field32(&word, TXWI_W1_BW_WIN_SIZE, txdesc->ba_size);
rt2x00_set_field32(&word, TXWI_W1_WIRELESS_CLI_ID,
- test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags) ?
- txdesc->key_idx : 0xff);
+ skbdesc->entry->entry_idx + 1);
+ //test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags) ?
+ // txdesc->key_idx : 0xff);
rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT,
skb->len - txdesc->l2pad);
rt2x00_set_field32(&word, TXWI_W1_PACKETID,
- skbdesc->entry->queue->qid);
+ //skbdesc->entry->entry_idx);
+ skbdesc->entry->queue->qid+1);
rt2x00_desc_write(txwi, 1, word);
/*
@@ -2176,7 +2193,7 @@ static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&word, TXD_W1_BURST,
test_bit(ENTRY_TXD_BURST, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W1_SD_LEN0,
- rt2x00dev->hw->extra_tx_headroom);
+ rt2x00dev->hw->extra_tx_headroom + skb->len);
rt2x00_set_field32(&word, TXD_W1_LAST_SEC0,
!test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W1_DMA_DONE, 0);
@@ -2236,7 +2253,8 @@ static void rt2800pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
const enum data_queue_qid queue_idx)
{
struct data_queue *queue;
- unsigned int idx, qidx = 0;
+ unsigned int index, index_back, qidx = 0;
+ struct queue_entry *entry;
u32 reg;
if (queue_idx == QID_BEACON) {
@@ -2254,14 +2272,21 @@ static void rt2800pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
return;
queue = rt2x00queue_get_queue(rt2x00dev, queue_idx);
- idx = queue->index[Q_INDEX];
if (queue_idx == QID_MGMT)
qidx = 5;
else
qidx = queue_idx;
- rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX(qidx), idx);
+
+ index = queue->index[Q_INDEX];
+ index_back = index;
+ if(index_back == 0) index_back = queue->limit;
+ index_back -= 1;
+ entry = &queue->entries[index_back];
+
+ if (test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags))
+ rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX(qidx), index);
}
static void rt2800pci_kill_tx_queue(struct rt2x00_dev *rt2x00dev,
@@ -2289,8 +2314,8 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry,
struct rxdone_entry_desc *rxdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
- struct queue_entry_priv_pci *entry_priv = entry->priv_data;
- __le32 *rxd = entry_priv->desc;
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+ __le32 *rxd = (__le32 *)skbdesc;
__le32 *rxwi = (__le32 *)entry->skb->data;
u32 rxd3;
u32 rxwi0;
@@ -2375,15 +2400,12 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry,
rt2x00pci_register_write(rt2x00dev, RX_CRX_IDX, entry->entry_idx);
/*
- * Remove TXWI descriptor from start of buffer.
+ * Remove RX descriptor from start of buffer.
*/
- skb_pull(entry->skb, RXWI_DESC_SIZE);
+ skb_pull(entry->skb, skbdesc->desc_len);
skb_trim(entry->skb, rxdesc->size);
}
-/*
- * Interrupt functions.
- */
static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue;
@@ -2420,7 +2442,7 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
* Skip this entry when it contains an invalid
* queue identication number.
*/
- type = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE);
+ type = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE) - 1;
queue = rt2x00queue_get_queue(rt2x00dev, type);
if (unlikely(!queue))
continue;
@@ -2433,8 +2455,15 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
if (unlikely(index >= queue->limit))
continue;
- entry = &queue->entries[index];
- entry_priv = entry->priv_data;
+ if(index == 0) index = queue->limit;
+ entry = &queue->entries[index - 1];
+
+ if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) ||
+ !test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+ break;
+
+ entry_priv = entry->priv_data;
+
rt2x00_desc_read((__le32 *)entry->skb->data, 0, &word);
entry_done = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
@@ -3111,7 +3140,7 @@ static const struct data_queue_desc rt2800pci_queue_tx = {
static const struct data_queue_desc rt2800pci_queue_bcn = {
.entry_num = 8 * BEACON_ENTRIES,
.data_size = 0, /* No DMA required for beacons */
- .desc_size = TXWI_DESC_SIZE,
+ .desc_size = TXD_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_pci),
};
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-rt2x00-Fix-tx-and-rx-take-2.patch
Type: text/x-patch
Size: 8060 bytes
Desc: not available
URL: <http://rt2x00.serialmonkey.com/pipermail/users_rt2x00.serialmonkey.com/attachments/20090715/09f2ea75/attachment.bin>
More information about the users
mailing list