* [PATCH v2 02/10] rt2x00: In debugfs frame dumping allow the TX descriptor to be part of the skb.
From: Gertjan van Wingerde @ 2010-05-13 9:36 UTC (permalink / raw)
To: John W. Linville
Cc: Ivo van Doorn, linux-wireless, users, Gertjan van Wingerde
In-Reply-To: <1273743418-28383-1-git-send-email-gwingerde@gmail.com>
Preparation for futher cleanups in the area of properly maintaining the skb
data without fiddling with the skb->data pointer.
Signed-off-by: Gertjan van Wingerde <gwingerde@gmail.com>
Acked-by: Ivo van Doorn <IvDoorn@gmail.com>
---
drivers/net/wireless/rt2x00/rt2x00debug.c | 14 ++++++++++----
drivers/net/wireless/rt2x00/rt2x00queue.h | 3 +++
2 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c
index 9e2eed5..1e81eef 100644
--- a/drivers/net/wireless/rt2x00/rt2x00debug.c
+++ b/drivers/net/wireless/rt2x00/rt2x00debug.c
@@ -159,6 +159,7 @@ void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skbcopy;
struct rt2x00dump_hdr *dump_hdr;
struct timeval timestamp;
+ u32 data_len;
do_gettimeofday(×tamp);
@@ -170,7 +171,11 @@ void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
return;
}
- skbcopy = alloc_skb(sizeof(*dump_hdr) + skbdesc->desc_len + skb->len,
+ data_len = skb->len;
+ if (skbdesc->flags & SKBDESC_DESC_IN_SKB)
+ data_len -= skbdesc->desc_len;
+
+ skbcopy = alloc_skb(sizeof(*dump_hdr) + skbdesc->desc_len + data_len,
GFP_ATOMIC);
if (!skbcopy) {
DEBUG(rt2x00dev, "Failed to copy skb for dump.\n");
@@ -181,7 +186,7 @@ void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
dump_hdr->version = cpu_to_le32(DUMP_HEADER_VERSION);
dump_hdr->header_length = cpu_to_le32(sizeof(*dump_hdr));
dump_hdr->desc_length = cpu_to_le32(skbdesc->desc_len);
- dump_hdr->data_length = cpu_to_le32(skb->len);
+ dump_hdr->data_length = cpu_to_le32(data_len);
dump_hdr->chip_rt = cpu_to_le16(rt2x00dev->chip.rt);
dump_hdr->chip_rf = cpu_to_le16(rt2x00dev->chip.rf);
dump_hdr->chip_rev = cpu_to_le16(rt2x00dev->chip.rev);
@@ -191,8 +196,9 @@ void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
dump_hdr->timestamp_sec = cpu_to_le32(timestamp.tv_sec);
dump_hdr->timestamp_usec = cpu_to_le32(timestamp.tv_usec);
- memcpy(skb_put(skbcopy, skbdesc->desc_len), skbdesc->desc,
- skbdesc->desc_len);
+ if (!(skbdesc->flags & SKBDESC_DESC_IN_SKB))
+ memcpy(skb_put(skbcopy, skbdesc->desc_len), skbdesc->desc,
+ skbdesc->desc_len);
memcpy(skb_put(skbcopy, skb->len), skb->data, skb->len);
skb_queue_tail(&intf->frame_dump_skbqueue, skbcopy);
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h
index 36a957a..f791708 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.h
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.h
@@ -94,12 +94,15 @@ enum data_queue_qid {
* mac80211 but was stripped for processing by the driver.
* @SKBDESC_NOT_MAC80211: Frame didn't originate from mac80211,
* don't try to pass it back.
+ * @SKBDESC_DESC_IN_SKB: The descriptor is at the start of the
+ * skb, instead of in the desc field.
*/
enum skb_frame_desc_flags {
SKBDESC_DMA_MAPPED_RX = 1 << 0,
SKBDESC_DMA_MAPPED_TX = 1 << 1,
SKBDESC_IV_STRIPPED = 1 << 2,
SKBDESC_NOT_MAC80211 = 1 << 3,
+ SKBDESC_DESC_IN_SKB = 1 << 4,
};
/**
--
1.7.1
^ permalink raw reply related
* [PATCH v2 06/10] rt2x00: Re-order tx descriptor writing code in drivers.
From: Gertjan van Wingerde @ 2010-05-13 9:36 UTC (permalink / raw)
To: John W. Linville
Cc: Ivo van Doorn, linux-wireless, users, Gertjan van Wingerde
In-Reply-To: <1273743418-28383-1-git-send-email-gwingerde@gmail.com>
Where possible, write the tx descriptor words from start to end, to
follow a logical ordering of words.
Where this is not possible (in rt2400pci, rt2500pci and rt61pci) add
a comment as to why word 0 needs to be written last.
Signed-off-by: Gertjan van Wingerde <gwingerde@gmail.com>
Acked-by: Ivo van Doorn <IvDoorn@gmail.com>
---
drivers/net/wireless/rt2x00/rt2400pci.c | 5 +++
drivers/net/wireless/rt2x00/rt2500pci.c | 5 +++
drivers/net/wireless/rt2x00/rt2500usb.c | 36 +++++++++++-----------
drivers/net/wireless/rt2x00/rt61pci.c | 5 +++
drivers/net/wireless/rt2x00/rt73usb.c | 52 +++++++++++++++---------------
5 files changed, 59 insertions(+), 44 deletions(-)
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index 4b38451..1eff6ec 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -1039,6 +1039,11 @@ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_HIGH_BUSY, 1);
rt2x00_desc_write(txd, 4, word);
+ /*
+ * Writing TXD word 0 must the last to prevent a race condition with
+ * the device, whereby the device may take hold of the TXD before we
+ * finished updating it.
+ */
rt2x00_desc_read(txd, 0, &word);
rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 1);
rt2x00_set_field32(&word, TXD_W0_VALID, 1);
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index d876c6d..8d3e95e 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -1193,6 +1193,11 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
test_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags));
rt2x00_desc_write(txd, 10, word);
+ /*
+ * Writing TXD word 0 must the last to prevent a race condition with
+ * the device, whereby the device may take hold of the TXD before we
+ * finished updating it.
+ */
rt2x00_desc_read(txd, 0, &word);
rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 1);
rt2x00_set_field32(&word, TXD_W0_VALID, 1);
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index 30c0544..9a915be 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -1039,6 +1039,24 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
/*
* Start writing the descriptor words.
*/
+ rt2x00_desc_read(txd, 0, &word);
+ rt2x00_set_field32(&word, TXD_W0_RETRY_LIMIT, txdesc->retry_limit);
+ rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
+ test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
+ rt2x00_set_field32(&word, TXD_W0_ACK,
+ test_bit(ENTRY_TXD_ACK, &txdesc->flags));
+ rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
+ test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags));
+ rt2x00_set_field32(&word, TXD_W0_OFDM,
+ (txdesc->rate_mode == RATE_MODE_OFDM));
+ rt2x00_set_field32(&word, TXD_W0_NEW_SEQ,
+ test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags));
+ rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
+ rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, txdesc->length);
+ rt2x00_set_field32(&word, TXD_W0_CIPHER, !!txdesc->cipher);
+ rt2x00_set_field32(&word, TXD_W0_KEY_ID, txdesc->key_idx);
+ rt2x00_desc_write(txd, 0, word);
+
rt2x00_desc_read(txd, 1, &word);
rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, txdesc->iv_offset);
rt2x00_set_field32(&word, TXD_W1_AIFS, txdesc->aifs);
@@ -1057,24 +1075,6 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
_rt2x00_desc_write(txd, 3, skbdesc->iv[0]);
_rt2x00_desc_write(txd, 4, skbdesc->iv[1]);
}
-
- rt2x00_desc_read(txd, 0, &word);
- rt2x00_set_field32(&word, TXD_W0_RETRY_LIMIT, txdesc->retry_limit);
- rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
- test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
- rt2x00_set_field32(&word, TXD_W0_ACK,
- test_bit(ENTRY_TXD_ACK, &txdesc->flags));
- rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
- test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags));
- rt2x00_set_field32(&word, TXD_W0_OFDM,
- (txdesc->rate_mode == RATE_MODE_OFDM));
- rt2x00_set_field32(&word, TXD_W0_NEW_SEQ,
- test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags));
- rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
- rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, txdesc->length);
- rt2x00_set_field32(&word, TXD_W0_CIPHER, !!txdesc->cipher);
- rt2x00_set_field32(&word, TXD_W0_KEY_ID, txdesc->key_idx);
- rt2x00_desc_write(txd, 0, word);
}
/*
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 99c2981..55aa010 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -1813,6 +1813,11 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
rt2x00_desc_write(txd, 11, word);
}
+ /*
+ * Writing TXD word 0 must the last to prevent a race condition with
+ * the device, whereby the device may take hold of the TXD before we
+ * finished updating it.
+ */
rt2x00_desc_read(txd, 0, &word);
rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 1);
rt2x00_set_field32(&word, TXD_W0_VALID, 1);
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index 81f6db1..fa40d43 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -1446,6 +1446,32 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
/*
* Start writing the descriptor words.
*/
+ rt2x00_desc_read(txd, 0, &word);
+ rt2x00_set_field32(&word, TXD_W0_BURST,
+ test_bit(ENTRY_TXD_BURST, &txdesc->flags));
+ rt2x00_set_field32(&word, TXD_W0_VALID, 1);
+ rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
+ test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
+ rt2x00_set_field32(&word, TXD_W0_ACK,
+ test_bit(ENTRY_TXD_ACK, &txdesc->flags));
+ rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
+ test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags));
+ rt2x00_set_field32(&word, TXD_W0_OFDM,
+ (txdesc->rate_mode == RATE_MODE_OFDM));
+ rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
+ rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
+ test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags));
+ rt2x00_set_field32(&word, TXD_W0_TKIP_MIC,
+ test_bit(ENTRY_TXD_ENCRYPT_MMIC, &txdesc->flags));
+ rt2x00_set_field32(&word, TXD_W0_KEY_TABLE,
+ test_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags));
+ rt2x00_set_field32(&word, TXD_W0_KEY_INDEX, txdesc->key_idx);
+ rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, txdesc->length);
+ rt2x00_set_field32(&word, TXD_W0_BURST2,
+ test_bit(ENTRY_TXD_BURST, &txdesc->flags));
+ rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, txdesc->cipher);
+ rt2x00_desc_write(txd, 0, word);
+
rt2x00_desc_read(txd, 1, &word);
rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, txdesc->queue);
rt2x00_set_field32(&word, TXD_W1_AIFSN, txdesc->aifs);
@@ -1473,32 +1499,6 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
TXPOWER_TO_DEV(rt2x00dev->tx_power));
rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1);
rt2x00_desc_write(txd, 5, word);
-
- rt2x00_desc_read(txd, 0, &word);
- rt2x00_set_field32(&word, TXD_W0_BURST,
- test_bit(ENTRY_TXD_BURST, &txdesc->flags));
- rt2x00_set_field32(&word, TXD_W0_VALID, 1);
- rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
- test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
- rt2x00_set_field32(&word, TXD_W0_ACK,
- test_bit(ENTRY_TXD_ACK, &txdesc->flags));
- rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
- test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags));
- rt2x00_set_field32(&word, TXD_W0_OFDM,
- (txdesc->rate_mode == RATE_MODE_OFDM));
- rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
- rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
- test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags));
- rt2x00_set_field32(&word, TXD_W0_TKIP_MIC,
- test_bit(ENTRY_TXD_ENCRYPT_MMIC, &txdesc->flags));
- rt2x00_set_field32(&word, TXD_W0_KEY_TABLE,
- test_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags));
- rt2x00_set_field32(&word, TXD_W0_KEY_INDEX, txdesc->key_idx);
- rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, txdesc->length);
- rt2x00_set_field32(&word, TXD_W0_BURST2,
- test_bit(ENTRY_TXD_BURST, &txdesc->flags));
- rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, txdesc->cipher);
- rt2x00_desc_write(txd, 0, word);
}
/*
--
1.7.1
^ permalink raw reply related
* [PATCH v2 04/10] rt2x00: Move rt2x00debug_dump_frame declaration to rt2x00.h.
From: Gertjan van Wingerde @ 2010-05-13 9:36 UTC (permalink / raw)
To: John W. Linville
Cc: Ivo van Doorn, linux-wireless, users, Gertjan van Wingerde
In-Reply-To: <1273743418-28383-1-git-send-email-gwingerde@gmail.com>
This allows rt2x00debug_dump_frame to be used from everywhere.
This is preparation for beacon writing clean ups.
Signed-off-by: Gertjan van Wingerde <gwingerde@gmail.com>
---
drivers/net/wireless/rt2x00/rt2x00.h | 35 +++++++++++++++++++++++++++++
drivers/net/wireless/rt2x00/rt2x00debug.c | 1 +
drivers/net/wireless/rt2x00/rt2x00dump.h | 20 ----------------
drivers/net/wireless/rt2x00/rt2x00lib.h | 10 --------
4 files changed, 36 insertions(+), 30 deletions(-)
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 6c1ff4c..1329f6c 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -1015,6 +1015,41 @@ struct queue_entry *rt2x00queue_get_entry(struct data_queue *queue,
enum queue_index index);
/*
+ * Debugfs handlers.
+ */
+/**
+ * enum rt2x00_dump_type - Frame type
+ *
+ * These values are used for the indicate the type of frame that is being
+ * dumped:
+ * @DUMP_FRAME_RXDONE: This frame has been received by the hardware.
+ * @DUMP_FRAME_TX: This frame is queued for transmission to the hardware.
+ * @DUMP_FRAME_TXDONE: This frame indicates the device has handled
+ * the tx event which has either succeeded or failed. A frame
+ * with this type should also have been reported with as a
+ * %DUMP_FRAME_TX frame.
+ * @DUMP_FRAME_BEACON: This beacon frame is queued for transmission to the
+ * hardware.
+ */
+enum rt2x00_dump_type {
+ DUMP_FRAME_RXDONE = 1,
+ DUMP_FRAME_TX = 2,
+ DUMP_FRAME_TXDONE = 3,
+ DUMP_FRAME_BEACON = 4,
+};
+
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
+ enum rt2x00_dump_type type, struct sk_buff *skb);
+#else
+static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
+ enum rt2x00_dump_type type,
+ struct sk_buff *skb)
+{
+}
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+
+/*
* Interrupt context handlers.
*/
void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev);
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c
index 1e81eef..9dd8b7c 100644
--- a/drivers/net/wireless/rt2x00/rt2x00debug.c
+++ b/drivers/net/wireless/rt2x00/rt2x00debug.c
@@ -210,6 +210,7 @@ void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
if (!test_bit(FRAME_DUMP_FILE_OPEN, &intf->frame_dump_flags))
skb_queue_purge(&intf->frame_dump_skbqueue);
}
+EXPORT_SYMBOL_GPL(rt2x00debug_dump_frame);
static int rt2x00debug_file_open(struct inode *inode, struct file *file)
{
diff --git a/drivers/net/wireless/rt2x00/rt2x00dump.h b/drivers/net/wireless/rt2x00/rt2x00dump.h
index ed303b4..e803342 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dump.h
+++ b/drivers/net/wireless/rt2x00/rt2x00dump.h
@@ -53,26 +53,6 @@
*/
/**
- * enum rt2x00_dump_type - Frame type
- *
- * These values are used for the @type member of &rt2x00dump_hdr.
- * @DUMP_FRAME_RXDONE: This frame has been received by the hardware.
- * @DUMP_FRAME_TX: This frame is queued for transmission to the hardware.
- * @DUMP_FRAME_TXDONE: This frame indicates the device has handled
- * the tx event which has either succeeded or failed. A frame
- * with this type should also have been reported with as a
- * %DUMP_FRAME_TX frame.
- * @DUMP_FRAME_BEACON: This beacon frame is queued for transmission to the
- * hardware.
- */
-enum rt2x00_dump_type {
- DUMP_FRAME_RXDONE = 1,
- DUMP_FRAME_TX = 2,
- DUMP_FRAME_TXDONE = 3,
- DUMP_FRAME_BEACON = 4,
-};
-
-/**
* struct rt2x00dump_hdr - Dump frame header
*
* Each frame dumped to the debugfs file starts with this header
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h
index be2e37f..0ca40e1 100644
--- a/drivers/net/wireless/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -27,8 +27,6 @@
#ifndef RT2X00LIB_H
#define RT2X00LIB_H
-#include "rt2x00dump.h"
-
/*
* Interval defines
*/
@@ -296,8 +294,6 @@ static inline void rt2x00lib_free_firmware(struct rt2x00_dev *rt2x00dev)
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
void rt2x00debug_register(struct rt2x00_dev *rt2x00dev);
void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev);
-void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
- enum rt2x00_dump_type type, struct sk_buff *skb);
void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev,
struct rxdone_entry_desc *rxdesc);
#else
@@ -309,12 +305,6 @@ static inline void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev)
{
}
-static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
- enum rt2x00_dump_type type,
- struct sk_buff *skb)
-{
-}
-
static inline void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev,
struct rxdone_entry_desc *rxdesc)
{
--
1.7.1
^ permalink raw reply related
* [PATCH v2 03/10] rt2x00: Dump beacons under a different identifier than TX frames.
From: Gertjan van Wingerde @ 2010-05-13 9:36 UTC (permalink / raw)
To: John W. Linville
Cc: Ivo van Doorn, linux-wireless, users, Gertjan van Wingerde
In-Reply-To: <1273743418-28383-1-git-send-email-gwingerde@gmail.com>
This allows for specific identification of beacons in the debugfs
frame stream.
Preparation for later differences between dumped TX frames and dumped
beacons.
Signed-off-by: Gertjan van Wingerde <gwingerde@gmail.com>
Acked-by: Ivo van Doorn <IvDoorn@gmail.com>
---
drivers/net/wireless/rt2x00/rt2x00dump.h | 3 +++
drivers/net/wireless/rt2x00/rt2x00queue.c | 5 ++++-
2 files changed, 7 insertions(+), 1 deletions(-)
diff --git a/drivers/net/wireless/rt2x00/rt2x00dump.h b/drivers/net/wireless/rt2x00/rt2x00dump.h
index 727019a..ed303b4 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dump.h
+++ b/drivers/net/wireless/rt2x00/rt2x00dump.h
@@ -62,11 +62,14 @@
* the tx event which has either succeeded or failed. A frame
* with this type should also have been reported with as a
* %DUMP_FRAME_TX frame.
+ * @DUMP_FRAME_BEACON: This beacon frame is queued for transmission to the
+ * hardware.
*/
enum rt2x00_dump_type {
DUMP_FRAME_RXDONE = 1,
DUMP_FRAME_TX = 2,
DUMP_FRAME_TXDONE = 3,
+ DUMP_FRAME_BEACON = 4,
};
/**
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index 97b2c76..4a067db 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -420,6 +420,7 @@ static void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
{
struct data_queue *queue = entry->queue;
struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ enum rt2x00_dump_type dump_type;
rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, entry->skb, txdesc);
@@ -427,7 +428,9 @@ static void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
* All processing on the frame has been completed, this means
* it is now ready to be dumped to userspace through debugfs.
*/
- rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TX, entry->skb);
+ dump_type = (txdesc->queue == QID_BEACON) ?
+ DUMP_FRAME_BEACON : DUMP_FRAME_TX;
+ rt2x00debug_dump_frame(rt2x00dev, dump_type, entry->skb);
}
static void rt2x00queue_kick_tx_queue(struct queue_entry *entry,
--
1.7.1
^ permalink raw reply related
* [PATCH v2 09/10] rt2x00: Reverse calling order of bus write_tx_desc and driver write_tx_desc.
From: Gertjan van Wingerde @ 2010-05-13 9:36 UTC (permalink / raw)
To: John W. Linville
Cc: Ivo van Doorn, linux-wireless, users, Gertjan van Wingerde
In-Reply-To: <1273743418-28383-1-git-send-email-gwingerde@gmail.com>
For rt2800 reverse the calling order of rt2x00pci_write_data and
rt2800pci_write_data. Currently rt2800pci_write_data calls rt2x00pci_write_data
as there can be only 1 driver callback function specified by the driver.
Reverse this calling order by introducing a new driver callback function,
called write_tx_datadesc, which is called from the bus-specific write_tx_data
functions.
Preparation for futher cleanups in the skb data handling of rt2x00.
Signed-off-by: Gertjan van Wingerde <gwingerde@gmail.com>
---
drivers/net/wireless/rt2x00/rt2800pci.c | 15 ++++-----------
drivers/net/wireless/rt2x00/rt2x00.h | 2 ++
drivers/net/wireless/rt2x00/rt2x00pci.c | 6 ++++++
drivers/net/wireless/rt2x00/rt2x00usb.c | 6 ++++++
4 files changed, 18 insertions(+), 11 deletions(-)
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index 88dba7f..72e4f29 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -613,18 +613,10 @@ static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev,
/*
* TX descriptor initialization
*/
-static int rt2800pci_write_tx_data(struct queue_entry* entry,
- struct txentry_desc *txdesc)
+static void rt2800pci_write_tx_datadesc(struct queue_entry* entry,
+ struct txentry_desc *txdesc)
{
- int ret;
-
- ret = rt2x00pci_write_tx_data(entry, txdesc);
- if (ret)
- return ret;
-
rt2800_write_txwi(entry->skb, txdesc);
-
- return 0;
}
@@ -1079,7 +1071,8 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
.reset_tuner = rt2800_reset_tuner,
.link_tuner = rt2800_link_tuner,
.write_tx_desc = rt2800pci_write_tx_desc,
- .write_tx_data = rt2800pci_write_tx_data,
+ .write_tx_data = rt2x00pci_write_tx_data,
+ .write_tx_datadesc = rt2800pci_write_tx_datadesc,
.write_beacon = rt2800pci_write_beacon,
.kick_tx_queue = rt2800pci_kick_tx_queue,
.kill_tx_queue = rt2800pci_kill_tx_queue,
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 1329f6c..d27127a 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -551,6 +551,8 @@ struct rt2x00lib_ops {
struct txentry_desc *txdesc);
int (*write_tx_data) (struct queue_entry *entry,
struct txentry_desc *txdesc);
+ void (*write_tx_datadesc) (struct queue_entry *entry,
+ struct txentry_desc *txdesc);
void (*write_beacon) (struct queue_entry *entry,
struct txentry_desc *txdesc);
int (*get_tx_data_len) (struct queue_entry *entry);
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c
index ff80ef7..714c982 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.c
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
@@ -80,6 +80,12 @@ int rt2x00pci_write_tx_data(struct queue_entry *entry,
return -EINVAL;
}
+ /*
+ * Call the driver's write_tx_datadesc function, if it exists.
+ */
+ if (rt2x00dev->ops->lib->write_tx_datadesc)
+ rt2x00dev->ops->lib->write_tx_datadesc(entry, txdesc);
+
return 0;
}
EXPORT_SYMBOL_GPL(rt2x00pci_write_tx_data);
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index a4f0551..bcc9483 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -247,6 +247,12 @@ int rt2x00usb_write_tx_data(struct queue_entry *entry,
*/
skb_pull(entry->skb, entry->queue->desc_size);
+ /*
+ * Call the driver's write_tx_datadesc function, if it exists.
+ */
+ if (rt2x00dev->ops->lib->write_tx_datadesc)
+ rt2x00dev->ops->lib->write_tx_datadesc(entry, txdesc);
+
return 0;
}
EXPORT_SYMBOL_GPL(rt2x00usb_write_tx_data);
--
1.7.1
^ permalink raw reply related
* [PATCH v2 05/10] rt2x00: Fix beacon descriptor writing for rt61pci.
From: Gertjan van Wingerde @ 2010-05-13 9:36 UTC (permalink / raw)
To: John W. Linville
Cc: Ivo van Doorn, linux-wireless, users, Gertjan van Wingerde
In-Reply-To: <1273743418-28383-1-git-send-email-gwingerde@gmail.com>
The buffer address descriptor word is not part of the TXINFO structure
needed for beacons. The current writing of that word for beacons is
therefore an out-of-bounds write.
Fix this by only writing the buffer address descriptor word for TX
queues.
Signed-off-by: Gertjan van Wingerde <gwingerde@gmail.com>
Acked-by: Ivo van Doorn <IvDoorn@gmail.com>
---
drivers/net/wireless/rt2x00/rt61pci.c | 10 +++++-----
1 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 2436363..99c2981 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -1801,12 +1801,12 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1);
rt2x00_desc_write(txd, 5, word);
- rt2x00_desc_read(txd, 6, &word);
- rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS,
- skbdesc->skb_dma);
- rt2x00_desc_write(txd, 6, word);
+ if (txdesc->queue != QID_BEACON) {
+ rt2x00_desc_read(txd, 6, &word);
+ rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS,
+ skbdesc->skb_dma);
+ rt2x00_desc_write(txd, 6, word);
- if (skbdesc->desc_len > TXINFO_SIZE) {
rt2x00_desc_read(txd, 11, &word);
rt2x00_set_field32(&word, TXD_W11_BUFFER_LENGTH0,
txdesc->length);
--
1.7.1
^ permalink raw reply related
* [PATCH v2 08/10] rt2x00: Push beacon TX descriptor writing to drivers.
From: Gertjan van Wingerde @ 2010-05-13 9:36 UTC (permalink / raw)
To: John W. Linville
Cc: Ivo van Doorn, linux-wireless, users, Gertjan van Wingerde
In-Reply-To: <1273743418-28383-1-git-send-email-gwingerde@gmail.com>
Not all the devices require a TX descriptor to be written (i.e. rt2800
device don't require them). Push down the creation of the TX descriptor
to the device drivers so that they can decide for themselves whether
a TX descriptor is to be created.
Signed-off-by: Gertjan van Wingerde <gwingerde@gmail.com>
---
drivers/net/wireless/rt2x00/rt2400pci.c | 15 +++++++++------
drivers/net/wireless/rt2x00/rt2500pci.c | 15 +++++++++------
drivers/net/wireless/rt2x00/rt2500usb.c | 10 ++++++++++
drivers/net/wireless/rt2x00/rt2800pci.c | 16 ++++++++++++++++
drivers/net/wireless/rt2x00/rt2800usb.c | 16 ++++++++++++++++
drivers/net/wireless/rt2x00/rt2x00queue.c | 10 +---------
drivers/net/wireless/rt2x00/rt61pci.c | 10 ++++++++++
drivers/net/wireless/rt2x00/rt73usb.c | 10 ++++++++++
8 files changed, 81 insertions(+), 21 deletions(-)
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index def3fa4..66cff04 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -1074,9 +1074,6 @@ static void rt2400pci_write_beacon(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
- struct queue_entry_priv_pci *entry_priv = entry->priv_data;
- struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
- u32 word;
u32 reg;
/*
@@ -1089,9 +1086,15 @@ static void rt2400pci_write_beacon(struct queue_entry *entry,
rt2x00queue_map_txskb(rt2x00dev, entry->skb);
- rt2x00_desc_read(entry_priv->desc, 1, &word);
- rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
- rt2x00_desc_write(entry_priv->desc, 1, word);
+ /*
+ * Write the TX descriptor for the beacon.
+ */
+ rt2400pci_write_tx_desc(rt2x00dev, entry->skb, txdesc);
+
+ /*
+ * Dump beacon to userspace through debugfs.
+ */
+ rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
/*
* Enable beaconing again.
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index 070c23e..d30811c 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -1231,9 +1231,6 @@ static void rt2500pci_write_beacon(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
- struct queue_entry_priv_pci *entry_priv = entry->priv_data;
- struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
- u32 word;
u32 reg;
/*
@@ -1246,9 +1243,15 @@ static void rt2500pci_write_beacon(struct queue_entry *entry,
rt2x00queue_map_txskb(rt2x00dev, entry->skb);
- rt2x00_desc_read(entry_priv->desc, 1, &word);
- rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
- rt2x00_desc_write(entry_priv->desc, 1, word);
+ /*
+ * Write the TX descriptor for the beacon.
+ */
+ rt2500pci_write_tx_desc(rt2x00dev, entry->skb, txdesc);
+
+ /*
+ * Dump beacon to userspace through debugfs.
+ */
+ rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
/*
* Enable beaconing again.
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index b985d8f..dfaa948 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -1107,6 +1107,16 @@ static void rt2500usb_write_beacon(struct queue_entry *entry,
rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
/*
+ * Write the TX descriptor for the beacon.
+ */
+ rt2500usb_write_tx_desc(rt2x00dev, entry->skb, txdesc);
+
+ /*
+ * Dump beacon to userspace through debugfs.
+ */
+ rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
+
+ /*
* Take the descriptor in front of the skb into account.
*/
skb_push(entry->skb, TXD_DESC_SIZE);
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index b2f2327..88dba7f 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -688,6 +688,7 @@ static void rt2800pci_write_beacon(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
unsigned int beacon_base;
u32 reg;
@@ -700,9 +701,24 @@ static void rt2800pci_write_beacon(struct queue_entry *entry,
rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
/*
+ * Register descriptor details in skb frame descriptor.
+ */
+ skbdesc->desc = entry->skb->data - TXWI_DESC_SIZE;
+ skbdesc->desc_len = TXWI_DESC_SIZE;
+
+ /*
* Add the TXWI for the beacon to the skb.
*/
rt2800_write_txwi(entry->skb, txdesc);
+
+ /*
+ * Dump beacon to userspace through debugfs.
+ */
+ rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
+
+ /*
+ * Adjust skb to take TXWI into account.
+ */
skb_push(entry->skb, TXWI_DESC_SIZE);
/*
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 1b87daa..2ac1386 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -437,6 +437,7 @@ static void rt2800usb_write_beacon(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
unsigned int beacon_base;
u32 reg;
@@ -449,9 +450,24 @@ static void rt2800usb_write_beacon(struct queue_entry *entry,
rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
/*
+ * Register descriptor details in skb frame descriptor.
+ */
+ skbdesc->desc = entry->skb->data - TXWI_DESC_SIZE;
+ skbdesc->desc_len = TXWI_DESC_SIZE;
+
+ /*
* Add the TXWI for the beacon to the skb.
*/
rt2800_write_txwi(entry->skb, txdesc);
+
+ /*
+ * Dump beacon to userspace through debugfs.
+ */
+ rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
+
+ /*
+ * Adjust skb to take TXWI into account.
+ */
skb_push(entry->skb, TXWI_DESC_SIZE);
/*
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index c68bf32..9e48bbc 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -420,7 +420,6 @@ static void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
{
struct data_queue *queue = entry->queue;
struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
- enum rt2x00_dump_type dump_type;
rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, entry->skb, txdesc);
@@ -428,9 +427,7 @@ static void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
* All processing on the frame has been completed, this means
* it is now ready to be dumped to userspace through debugfs.
*/
- dump_type = (txdesc->queue == QID_BEACON) ?
- DUMP_FRAME_BEACON : DUMP_FRAME_TX;
- rt2x00debug_dump_frame(rt2x00dev, dump_type, entry->skb);
+ rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TX, entry->skb);
}
static void rt2x00queue_kick_tx_queue(struct queue_entry *entry,
@@ -594,11 +591,6 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
skbdesc->entry = intf->beacon;
/*
- * Write TX descriptor into reserved room in front of the beacon.
- */
- rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
-
- /*
* Send beacon to hardware and enable beacon genaration..
*/
rt2x00dev->ops->lib->write_beacon(intf->beacon, &txdesc);
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 1be1d7d..643202f 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -1872,6 +1872,16 @@ static void rt61pci_write_beacon(struct queue_entry *entry,
rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
/*
+ * Write the TX descriptor for the beacon.
+ */
+ rt61pci_write_tx_desc(rt2x00dev, entry->skb, txdesc);
+
+ /*
+ * Dump beacon to userspace through debugfs.
+ */
+ rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
+
+ /*
* Write entire beacon with descriptor to register.
*/
beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index fca661c..dcc46a2 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -1526,6 +1526,16 @@ static void rt73usb_write_beacon(struct queue_entry *entry,
rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
/*
+ * Write the TX descriptor for the beacon.
+ */
+ rt73usb_write_tx_desc(rt2x00dev, entry->skb, txdesc);
+
+ /*
+ * Dump beacon to userspace through debugfs.
+ */
+ rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
+
+ /*
* Take the descriptor in front of the skb into account.
*/
skb_push(entry->skb, TXD_DESC_SIZE);
--
1.7.1
^ permalink raw reply related
* [PATCH v2 10/10] rt2x00: Properly reserve room for descriptors in skbs.
From: Gertjan van Wingerde @ 2010-05-13 9:36 UTC (permalink / raw)
To: John W. Linville
Cc: Ivo van Doorn, linux-wireless, users, Gertjan van Wingerde
In-Reply-To: <1273743418-28383-1-git-send-email-gwingerde@gmail.com>
Instead of fiddling with the skb->data pointer and thereby risking
out of bounds accesses, properly reserve the space needed in an
skb for descriptors.
Signed-off-by: Gertjan van Wingerde <gwingerde@gmail.com>
Acked-by: Ivo van Doorn <IvDoorn@gmail.com>
---
drivers/net/wireless/rt2x00/rt2400pci.c | 2 +-
drivers/net/wireless/rt2x00/rt2500pci.c | 2 +-
drivers/net/wireless/rt2x00/rt2500usb.c | 14 ++++++----
drivers/net/wireless/rt2x00/rt2800lib.c | 3 +-
drivers/net/wireless/rt2x00/rt2800lib.h | 2 +-
drivers/net/wireless/rt2x00/rt2800pci.c | 23 ++++++++--------
drivers/net/wireless/rt2x00/rt2800usb.c | 22 +++++++++------
drivers/net/wireless/rt2x00/rt2x00.h | 7 +++++
drivers/net/wireless/rt2x00/rt2x00dev.c | 5 ---
drivers/net/wireless/rt2x00/rt2x00lib.h | 7 -----
drivers/net/wireless/rt2x00/rt2x00pci.c | 40 +++++++++++++++++++++++++++++
drivers/net/wireless/rt2x00/rt2x00pci.h | 8 ++++++
drivers/net/wireless/rt2x00/rt2x00queue.c | 24 +----------------
drivers/net/wireless/rt2x00/rt2x00usb.c | 11 +++----
drivers/net/wireless/rt2x00/rt61pci.c | 4 +-
drivers/net/wireless/rt2x00/rt73usb.c | 14 ++++++----
16 files changed, 109 insertions(+), 79 deletions(-)
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index 66cff04..641459b 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -1227,7 +1227,7 @@ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev,
}
txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT);
- rt2x00lib_txdone(entry, &txdesc);
+ rt2x00pci_txdone(entry, &txdesc);
}
}
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index d30811c..c8363bc 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -1363,7 +1363,7 @@ static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev,
}
txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT);
- rt2x00lib_txdone(entry, &txdesc);
+ rt2x00pci_txdone(entry, &txdesc);
}
}
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index dfaa948..eb99934 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -1033,7 +1033,7 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
struct txentry_desc *txdesc)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
- __le32 *txd = (__le32 *)(skb->data - TXD_DESC_SIZE);
+ __le32 *txd = (__le32 *) skb->data;
u32 word;
/*
@@ -1079,6 +1079,7 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
/*
* Register descriptor details in skb frame descriptor.
*/
+ skbdesc->flags |= SKBDESC_DESC_IN_SKB;
skbdesc->desc = txd;
skbdesc->desc_len = TXD_DESC_SIZE;
}
@@ -1107,6 +1108,12 @@ static void rt2500usb_write_beacon(struct queue_entry *entry,
rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
/*
+ * Add space for the descriptor in front of the skb.
+ */
+ skb_push(entry->skb, TXD_DESC_SIZE);
+ memset(entry->skb->data, 0, TXD_DESC_SIZE);
+
+ /*
* Write the TX descriptor for the beacon.
*/
rt2500usb_write_tx_desc(rt2x00dev, entry->skb, txdesc);
@@ -1117,11 +1124,6 @@ static void rt2500usb_write_beacon(struct queue_entry *entry,
rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
/*
- * Take the descriptor in front of the skb into account.
- */
- skb_push(entry->skb, TXD_DESC_SIZE);
-
- /*
* USB devices cannot blindly pass the skb->len as the
* length of the data to usb_fill_bulk_urb. Pass the skb
* to the driver to determine what the length should be.
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index 7410ac1..53a3257 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -281,9 +281,8 @@ int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev)
}
EXPORT_SYMBOL_GPL(rt2800_wait_wpdma_ready);
-void rt2800_write_txwi(struct sk_buff *skb, struct txentry_desc *txdesc)
+void rt2800_write_txwi(__le32 *txwi, struct txentry_desc *txdesc)
{
- __le32 *txwi = (__le32 *)(skb->data - TXWI_DESC_SIZE);
u32 word;
/*
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h
index 94de999..0f0a13c 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/rt2x00/rt2800lib.h
@@ -111,7 +111,7 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev,
const u8 command, const u8 token,
const u8 arg0, const u8 arg1);
-void rt2800_write_txwi(struct sk_buff *skb, struct txentry_desc *txdesc);
+void rt2800_write_txwi(__le32 *txwi, struct txentry_desc *txdesc);
void rt2800_process_rxwi(struct sk_buff *skb, struct rxdone_entry_desc *txdesc);
extern const struct rt2x00debug rt2800_rt2x00debug;
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index 72e4f29..db61a78 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -616,7 +616,7 @@ static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev,
static void rt2800pci_write_tx_datadesc(struct queue_entry* entry,
struct txentry_desc *txdesc)
{
- rt2800_write_txwi(entry->skb, txdesc);
+ rt2800_write_txwi((__le32 *) entry->skb->data, txdesc);
}
@@ -693,15 +693,22 @@ static void rt2800pci_write_beacon(struct queue_entry *entry,
rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
/*
+ * Add space for the TXWI in front of the skb.
+ */
+ skb_push(entry->skb, TXWI_DESC_SIZE);
+ memset(entry->skb, 0, TXWI_DESC_SIZE);
+
+ /*
* Register descriptor details in skb frame descriptor.
*/
- skbdesc->desc = entry->skb->data - TXWI_DESC_SIZE;
+ skbdesc->flags |= SKBDESC_DESC_IN_SKB;
+ skbdesc->desc = entry->skb->data;
skbdesc->desc_len = TXWI_DESC_SIZE;
/*
* Add the TXWI for the beacon to the skb.
*/
- rt2800_write_txwi(entry->skb, txdesc);
+ rt2800_write_txwi((__le32 *)entry->skb->data, txdesc);
/*
* Dump beacon to userspace through debugfs.
@@ -709,11 +716,6 @@ static void rt2800pci_write_beacon(struct queue_entry *entry,
rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
/*
- * Adjust skb to take TXWI into account.
- */
- skb_push(entry->skb, TXWI_DESC_SIZE);
-
- /*
* Write entire beacon with TXWI to register.
*/
beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
@@ -888,8 +890,7 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
/* Check if we got a match by looking at WCID/ACK/PID
* fields */
- txwi = (__le32 *)(entry->skb->data -
- rt2x00dev->ops->extra_tx_headroom);
+ txwi = (__le32 *) entry->skb->data;
rt2x00_desc_read(txwi, 1, &word);
tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID);
@@ -934,7 +935,7 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
__set_bit(TXDONE_FALLBACK, &txdesc.flags);
- rt2x00lib_txdone(entry, &txdesc);
+ rt2x00pci_txdone(entry, &txdesc);
}
}
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 2ac1386..33d7ac9 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -400,13 +400,14 @@ static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
struct txentry_desc *txdesc)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
- __le32 *txi = (__le32 *)(skb->data - TXWI_DESC_SIZE - TXINFO_DESC_SIZE);
+ __le32 *txi = (__le32 *) skb->data;
+ __le32 *txwi = (__le32 *) (skb->data + TXINFO_DESC_SIZE);
u32 word;
/*
* Initialize TXWI descriptor
*/
- rt2800_write_txwi(skb, txdesc);
+ rt2800_write_txwi(txwi, txdesc);
/*
* Initialize TXINFO descriptor
@@ -426,6 +427,7 @@ static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
/*
* Register descriptor details in skb frame descriptor.
*/
+ skbdesc->flags |= SKBDESC_DESC_IN_SKB;
skbdesc->desc = txi;
skbdesc->desc_len = TXINFO_DESC_SIZE + TXWI_DESC_SIZE;
}
@@ -450,15 +452,22 @@ static void rt2800usb_write_beacon(struct queue_entry *entry,
rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
/*
+ * Add space for the TXWI in front of the skb.
+ */
+ skb_push(entry->skb, TXWI_DESC_SIZE);
+ memset(entry->skb, 0, TXWI_DESC_SIZE);
+
+ /*
* Register descriptor details in skb frame descriptor.
*/
- skbdesc->desc = entry->skb->data - TXWI_DESC_SIZE;
+ skbdesc->flags |= SKBDESC_DESC_IN_SKB;
+ skbdesc->desc = entry->skb->data;
skbdesc->desc_len = TXWI_DESC_SIZE;
/*
* Add the TXWI for the beacon to the skb.
*/
- rt2800_write_txwi(entry->skb, txdesc);
+ rt2800_write_txwi((__le32 *) entry->skb->data, txdesc);
/*
* Dump beacon to userspace through debugfs.
@@ -466,11 +475,6 @@ static void rt2800usb_write_beacon(struct queue_entry *entry,
rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
/*
- * Adjust skb to take TXWI into account.
- */
- skb_push(entry->skb, TXWI_DESC_SIZE);
-
- /*
* Write entire beacon with descriptor to register.
*/
beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index d27127a..ae0aa07 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -1001,6 +1001,13 @@ static inline bool rt2x00_is_soc(struct rt2x00_dev *rt2x00dev)
void rt2x00queue_map_txskb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
/**
+ * rt2x00queue_unmap_skb - Unmap a skb from DMA.
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ * @skb: The skb to unmap.
+ */
+void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
+
+/**
* rt2x00queue_get_queue - Convert queue index to queue pointer
* @rt2x00dev: Pointer to &struct rt2x00_dev.
* @queue: rt2x00 queue index (see &enum data_queue_qid).
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 33c2f5f..6790441 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -210,11 +210,6 @@ void rt2x00lib_txdone(struct queue_entry *entry,
bool success;
/*
- * Unmap the skb.
- */
- rt2x00queue_unmap_skb(rt2x00dev, entry->skb);
-
- /*
* Remove L2 padding which was added during
*/
if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags))
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h
index 0ca40e1..822affc 100644
--- a/drivers/net/wireless/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -105,13 +105,6 @@ struct sk_buff *rt2x00queue_alloc_rxskb(struct rt2x00_dev *rt2x00dev,
struct queue_entry *entry);
/**
- * rt2x00queue_unmap_skb - Unmap a skb from DMA.
- * @rt2x00dev: Pointer to &struct rt2x00_dev.
- * @skb: The skb to unmap.
- */
-void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
-
-/**
* rt2x00queue_free_skb - free a skb
* @rt2x00dev: Pointer to &struct rt2x00_dev.
* @skb: The skb to free.
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c
index 714c982..19b8683 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.c
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
@@ -81,11 +81,23 @@ int rt2x00pci_write_tx_data(struct queue_entry *entry,
}
/*
+ * Add the requested extra tx headroom in front of the skb.
+ */
+ skb_push(entry->skb, rt2x00dev->ops->extra_tx_headroom);
+ memset(entry->skb->data, 0, rt2x00dev->ops->extra_tx_headroom);
+
+ /*
* Call the driver's write_tx_datadesc function, if it exists.
*/
if (rt2x00dev->ops->lib->write_tx_datadesc)
rt2x00dev->ops->lib->write_tx_datadesc(entry, txdesc);
+ /*
+ * Map the skb to DMA.
+ */
+ if (test_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags))
+ rt2x00queue_map_txskb(rt2x00dev, entry->skb);
+
return 0;
}
EXPORT_SYMBOL_GPL(rt2x00pci_write_tx_data);
@@ -93,6 +105,34 @@ EXPORT_SYMBOL_GPL(rt2x00pci_write_tx_data);
/*
* TX/RX data handlers.
*/
+void rt2x00pci_txdone(struct queue_entry *entry,
+ struct txdone_entry_desc *txdesc)
+{
+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+
+ /*
+ * Unmap the skb.
+ */
+ rt2x00queue_unmap_skb(rt2x00dev, entry->skb);
+
+ /*
+ * Remove the extra tx headroom from the skb.
+ */
+ skb_pull(entry->skb, rt2x00dev->ops->extra_tx_headroom);
+
+ /*
+ * Signal that the TX descriptor is no longer in the skb.
+ */
+ skbdesc->flags &= ~SKBDESC_DESC_IN_SKB;
+
+ /*
+ * Pass on to rt2x00lib.
+ */
+ rt2x00lib_txdone(entry, txdesc);
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_txdone);
+
void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue = rt2x00dev->rx;
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h
index 51bcef3..00528b8 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.h
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.h
@@ -109,6 +109,14 @@ struct queue_entry_priv_pci {
};
/**
+ * rt2x00pci_txdone - Handle TX done events.
+ * @entry: The queue entry for which a TX done event was received.
+ * @txdesc: The TX done descriptor for the entry.
+ */
+void rt2x00pci_txdone(struct queue_entry *entry,
+ struct txdone_entry_desc *txdesc);
+
+/**
* rt2x00pci_rxdone - Handle RX done events
* @rt2x00dev: Device pointer, see &struct rt2x00_dev.
*/
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index 9e48bbc..bcdbf95 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -99,21 +99,8 @@ void rt2x00queue_map_txskb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
- /*
- * If device has requested headroom, we should make sure that
- * is also mapped to the DMA so it can be used for transfering
- * additional descriptor information to the hardware.
- */
- skb_push(skb, rt2x00dev->ops->extra_tx_headroom);
-
skbdesc->skb_dma =
dma_map_single(rt2x00dev->dev, skb->data, skb->len, DMA_TO_DEVICE);
-
- /*
- * Restore data pointer to original location again.
- */
- skb_pull(skb, rt2x00dev->ops->extra_tx_headroom);
-
skbdesc->flags |= SKBDESC_DMA_MAPPED_TX;
}
EXPORT_SYMBOL_GPL(rt2x00queue_map_txskb);
@@ -129,16 +116,12 @@ void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
}
if (skbdesc->flags & SKBDESC_DMA_MAPPED_TX) {
- /*
- * Add headroom to the skb length, it has been removed
- * by the driver, but it was actually mapped to DMA.
- */
- dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma,
- skb->len + rt2x00dev->ops->extra_tx_headroom,
+ dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma, skb->len,
DMA_TO_DEVICE);
skbdesc->flags &= ~SKBDESC_DMA_MAPPED_TX;
}
}
+EXPORT_SYMBOL_GPL(rt2x00queue_unmap_skb);
void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
{
@@ -533,9 +516,6 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
return -EIO;
}
- if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags))
- rt2x00queue_map_txskb(queue->rt2x00dev, skb);
-
set_bit(ENTRY_DATA_PENDING, &entry->flags);
rt2x00queue_index_inc(queue, Q_INDEX);
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index bcc9483..1f72c59 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -197,6 +197,11 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
return;
/*
+ * Remove the descriptor from the front of the skb.
+ */
+ skb_pull(entry->skb, entry->queue->desc_size);
+
+ /*
* Obtain the status about this packet.
* Note that when the status is 0 it does not mean the
* frame was send out correctly. It only means the frame
@@ -242,12 +247,6 @@ int rt2x00usb_write_tx_data(struct queue_entry *entry,
rt2x00usb_interrupt_txdone, entry);
/*
- * Make sure the skb->data pointer points to the frame, not the
- * descriptor.
- */
- skb_pull(entry->skb, entry->queue->desc_size);
-
- /*
* Call the driver's write_tx_datadesc function, if it exists.
*/
if (rt2x00dev->ops->lib->write_tx_datadesc)
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 643202f..9ac2f5c 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -2108,7 +2108,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
__set_bit(TXDONE_UNKNOWN, &txdesc.flags);
txdesc.retry = 0;
- rt2x00lib_txdone(entry_done, &txdesc);
+ rt2x00pci_txdone(entry_done, &txdesc);
entry_done = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
}
@@ -2128,7 +2128,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
}
txdesc.retry = rt2x00_get_field32(reg, STA_CSR4_RETRY_COUNT);
- rt2x00lib_txdone(entry, &txdesc);
+ rt2x00pci_txdone(entry, &txdesc);
}
}
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index dcc46a2..a9738ee 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -1440,7 +1440,7 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
struct txentry_desc *txdesc)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
- __le32 *txd = (__le32 *)(skb->data - TXD_DESC_SIZE);
+ __le32 *txd = (__le32 *) skb->data;
u32 word;
/*
@@ -1503,6 +1503,7 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
/*
* Register descriptor details in skb frame descriptor.
*/
+ skbdesc->flags |= SKBDESC_DESC_IN_SKB;
skbdesc->desc = txd;
skbdesc->desc_len = TXD_DESC_SIZE;
}
@@ -1526,6 +1527,12 @@ static void rt73usb_write_beacon(struct queue_entry *entry,
rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
/*
+ * Add space for the descriptor in front of the skb.
+ */
+ skb_push(entry->skb, TXD_DESC_SIZE);
+ memset(entry->skb->data, 0, TXD_DESC_SIZE);
+
+ /*
* Write the TX descriptor for the beacon.
*/
rt73usb_write_tx_desc(rt2x00dev, entry->skb, txdesc);
@@ -1536,11 +1543,6 @@ static void rt73usb_write_beacon(struct queue_entry *entry,
rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
/*
- * Take the descriptor in front of the skb into account.
- */
- skb_push(entry->skb, TXD_DESC_SIZE);
-
- /*
* Write entire beacon with descriptor to register.
*/
beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
--
1.7.1
^ permalink raw reply related
* [PATCH v2 07/10] rt2x00: Simplify TXD handling of beacons.
From: Gertjan van Wingerde @ 2010-05-13 9:36 UTC (permalink / raw)
To: John W. Linville
Cc: Ivo van Doorn, linux-wireless, users, Gertjan van Wingerde
In-Reply-To: <1273743418-28383-1-git-send-email-gwingerde@gmail.com>
The handling of tx descriptors for beacons can be simplified by updating
write_tx_desc implementations of each driver to write directly to the
queue entry descriptor instead of to a provided memory area.
This is also a preparation for further clean ups where descriptors are
properly reserved in the skb instead of fiddling with the skb data
pointer.
Signed-off-by: Gertjan van Wingerde <gwingerde@gmail.com>
Acked-by: Ivo van Doorn <IvDoorn@gmail.com>
---
drivers/net/wireless/rt2x00/rt2400pci.c | 21 +++++++++------------
drivers/net/wireless/rt2x00/rt2500pci.c | 21 +++++++++------------
drivers/net/wireless/rt2x00/rt2500usb.c | 21 ++++++++++++---------
drivers/net/wireless/rt2x00/rt2800pci.c | 14 ++++++++++----
drivers/net/wireless/rt2x00/rt2800usb.c | 8 +++++++-
drivers/net/wireless/rt2x00/rt2x00pci.c | 9 ---------
drivers/net/wireless/rt2x00/rt2x00queue.c | 10 ----------
drivers/net/wireless/rt2x00/rt2x00usb.c | 8 --------
drivers/net/wireless/rt2x00/rt61pci.c | 20 +++++++++++++-------
drivers/net/wireless/rt2x00/rt73usb.c | 21 ++++++++++++---------
10 files changed, 72 insertions(+), 81 deletions(-)
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index 1eff6ec..def3fa4 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -1006,15 +1006,15 @@ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data;
- __le32 *txd = skbdesc->desc;
+ __le32 *txd = entry_priv->desc;
u32 word;
/*
* Start writing the descriptor words.
*/
- rt2x00_desc_read(entry_priv->desc, 1, &word);
+ rt2x00_desc_read(txd, 1, &word);
rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
- rt2x00_desc_write(entry_priv->desc, 1, word);
+ rt2x00_desc_write(txd, 1, word);
rt2x00_desc_read(txd, 2, &word);
rt2x00_set_field32(&word, TXD_W2_BUFFER_LENGTH, txdesc->length);
@@ -1059,6 +1059,12 @@ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags));
rt2x00_desc_write(txd, 0, word);
+
+ /*
+ * Register descriptor details in skb frame descriptor.
+ */
+ skbdesc->desc = txd;
+ skbdesc->desc_len = TXD_DESC_SIZE;
}
/*
@@ -1081,15 +1087,6 @@ static void rt2400pci_write_beacon(struct queue_entry *entry,
rt2x00_set_field32(®, CSR14_BEACON_GEN, 0);
rt2x00pci_register_write(rt2x00dev, CSR14, reg);
- /*
- * Replace rt2x00lib allocated descriptor with the
- * pointer to the _real_ hardware descriptor.
- * After that, map the beacon to DMA and update the
- * descriptor.
- */
- memcpy(entry_priv->desc, skbdesc->desc, skbdesc->desc_len);
- skbdesc->desc = entry_priv->desc;
-
rt2x00queue_map_txskb(rt2x00dev, entry->skb);
rt2x00_desc_read(entry_priv->desc, 1, &word);
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index 8d3e95e..070c23e 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -1164,15 +1164,15 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data;
- __le32 *txd = skbdesc->desc;
+ __le32 *txd = entry_priv->desc;
u32 word;
/*
* Start writing the descriptor words.
*/
- rt2x00_desc_read(entry_priv->desc, 1, &word);
+ rt2x00_desc_read(txd, 1, &word);
rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
- rt2x00_desc_write(entry_priv->desc, 1, word);
+ rt2x00_desc_write(txd, 1, word);
rt2x00_desc_read(txd, 2, &word);
rt2x00_set_field32(&word, TXD_W2_IV_OFFSET, IEEE80211_HEADER);
@@ -1216,6 +1216,12 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, txdesc->length);
rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE);
rt2x00_desc_write(txd, 0, word);
+
+ /*
+ * Register descriptor details in skb frame descriptor.
+ */
+ skbdesc->desc = txd;
+ skbdesc->desc_len = TXD_DESC_SIZE;
}
/*
@@ -1238,15 +1244,6 @@ static void rt2500pci_write_beacon(struct queue_entry *entry,
rt2x00_set_field32(®, CSR14_BEACON_GEN, 0);
rt2x00pci_register_write(rt2x00dev, CSR14, reg);
- /*
- * Replace rt2x00lib allocated descriptor with the
- * pointer to the _real_ hardware descriptor.
- * After that, map the beacon to DMA and update the
- * descriptor.
- */
- memcpy(entry_priv->desc, skbdesc->desc, skbdesc->desc_len);
- skbdesc->desc = entry_priv->desc;
-
rt2x00queue_map_txskb(rt2x00dev, entry->skb);
rt2x00_desc_read(entry_priv->desc, 1, &word);
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index 9a915be..b985d8f 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -1033,7 +1033,7 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
struct txentry_desc *txdesc)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
- __le32 *txd = skbdesc->desc;
+ __le32 *txd = (__le32 *)(skb->data - TXD_DESC_SIZE);
u32 word;
/*
@@ -1075,6 +1075,12 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
_rt2x00_desc_write(txd, 3, skbdesc->iv[0]);
_rt2x00_desc_write(txd, 4, skbdesc->iv[1]);
}
+
+ /*
+ * Register descriptor details in skb frame descriptor.
+ */
+ skbdesc->desc = txd;
+ skbdesc->desc_len = TXD_DESC_SIZE;
}
/*
@@ -1088,19 +1094,11 @@ static void rt2500usb_write_beacon(struct queue_entry *entry,
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data;
- struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
int pipe = usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint);
int length;
u16 reg, reg0;
/*
- * Add the descriptor in front of the skb.
- */
- skb_push(entry->skb, entry->queue->desc_size);
- memcpy(entry->skb->data, skbdesc->desc, skbdesc->desc_len);
- skbdesc->desc = entry->skb->data;
-
- /*
* Disable beaconing while we are reloading the beacon data,
* otherwise we might be sending out invalid data.
*/
@@ -1109,6 +1107,11 @@ static void rt2500usb_write_beacon(struct queue_entry *entry,
rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
/*
+ * Take the descriptor in front of the skb into account.
+ */
+ skb_push(entry->skb, TXD_DESC_SIZE);
+
+ /*
* USB devices cannot blindly pass the skb->len as the
* length of the data to usb_fill_bulk_urb. Pass the skb
* to the driver to determine what the length should be.
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index 7d4778d..b2f2327 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -633,7 +633,8 @@ static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
struct txentry_desc *txdesc)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
- __le32 *txd = skbdesc->desc;
+ struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data;
+ __le32 *txd = entry_priv->desc;
u32 word;
/*
@@ -657,15 +658,14 @@ static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
!test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W1_BURST,
test_bit(ENTRY_TXD_BURST, &txdesc->flags));
- rt2x00_set_field32(&word, TXD_W1_SD_LEN0,
- rt2x00dev->ops->extra_tx_headroom);
+ rt2x00_set_field32(&word, TXD_W1_SD_LEN0, TXWI_DESC_SIZE);
rt2x00_set_field32(&word, TXD_W1_LAST_SEC0, 0);
rt2x00_set_field32(&word, TXD_W1_DMA_DONE, 0);
rt2x00_desc_write(txd, 1, word);
rt2x00_desc_read(txd, 2, &word);
rt2x00_set_field32(&word, TXD_W2_SD_PTR1,
- skbdesc->skb_dma + rt2x00dev->ops->extra_tx_headroom);
+ skbdesc->skb_dma + TXWI_DESC_SIZE);
rt2x00_desc_write(txd, 2, word);
rt2x00_desc_read(txd, 3, &word);
@@ -673,6 +673,12 @@ static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
!test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W3_QSEL, 2);
rt2x00_desc_write(txd, 3, word);
+
+ /*
+ * Register descriptor details in skb frame descriptor.
+ */
+ skbdesc->desc = txd;
+ skbdesc->desc_len = TXD_DESC_SIZE;
}
/*
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index d48d705..1b87daa 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -400,7 +400,7 @@ static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
struct txentry_desc *txdesc)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
- __le32 *txi = skbdesc->desc;
+ __le32 *txi = (__le32 *)(skb->data - TXWI_DESC_SIZE - TXINFO_DESC_SIZE);
u32 word;
/*
@@ -422,6 +422,12 @@ static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&word, TXINFO_W0_USB_DMA_TX_BURST,
test_bit(ENTRY_TXD_BURST, &txdesc->flags));
rt2x00_desc_write(txi, 0, word);
+
+ /*
+ * Register descriptor details in skb frame descriptor.
+ */
+ skbdesc->desc = txi;
+ skbdesc->desc_len = TXINFO_DESC_SIZE + TXWI_DESC_SIZE;
}
/*
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c
index 2fe9f29..ff80ef7 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.c
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
@@ -66,8 +66,6 @@ int rt2x00pci_write_tx_data(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
- struct queue_entry_priv_pci *entry_priv = entry->priv_data;
- struct skb_frame_desc *skbdesc;
/*
* This should not happen, we already checked the entry
@@ -82,13 +80,6 @@ int rt2x00pci_write_tx_data(struct queue_entry *entry,
return -EINVAL;
}
- /*
- * Fill in skb descriptor
- */
- skbdesc = get_skb_frame_desc(entry->skb);
- skbdesc->desc = entry_priv->desc;
- skbdesc->desc_len = entry->queue->desc_size;
-
return 0;
}
EXPORT_SYMBOL_GPL(rt2x00pci_write_tx_data);
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index 4a067db..c68bf32 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -555,7 +555,6 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
struct rt2x00_intf *intf = vif_to_intf(vif);
struct skb_frame_desc *skbdesc;
struct txentry_desc txdesc;
- __le32 desc[16];
if (unlikely(!intf->beacon))
return -ENOBUFS;
@@ -588,19 +587,10 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc);
/*
- * For the descriptor we use a local array from where the
- * driver can move it to the correct location required for
- * the hardware.
- */
- memset(desc, 0, sizeof(desc));
-
- /*
* Fill in skb descriptor
*/
skbdesc = get_skb_frame_desc(intf->beacon->skb);
memset(skbdesc, 0, sizeof(*skbdesc));
- skbdesc->desc = desc;
- skbdesc->desc_len = intf->beacon->queue->desc_size;
skbdesc->entry = intf->beacon;
/*
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index acf3282..a4f0551 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -221,7 +221,6 @@ int rt2x00usb_write_tx_data(struct queue_entry *entry,
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
struct queue_entry_priv_usb *entry_priv = entry->priv_data;
- struct skb_frame_desc *skbdesc;
u32 length;
/*
@@ -231,13 +230,6 @@ int rt2x00usb_write_tx_data(struct queue_entry *entry,
memset(entry->skb->data, 0, entry->queue->desc_size);
/*
- * Fill in skb descriptor
- */
- skbdesc = get_skb_frame_desc(entry->skb);
- skbdesc->desc = entry->skb->data;
- skbdesc->desc_len = entry->queue->desc_size;
-
- /*
* USB devices cannot blindly pass the skb->len as the
* length of the data to usb_fill_bulk_urb. Pass the skb
* to the driver to determine what the length should be.
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 55aa010..1be1d7d 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -1763,7 +1763,8 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
struct txentry_desc *txdesc)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
- __le32 *txd = skbdesc->desc;
+ struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data;
+ __le32 *txd = entry_priv->desc;
u32 word;
/*
@@ -1842,6 +1843,13 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
test_bit(ENTRY_TXD_BURST, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, txdesc->cipher);
rt2x00_desc_write(txd, 0, word);
+
+ /*
+ * Register descriptor details in skb frame descriptor.
+ */
+ skbdesc->desc = txd;
+ skbdesc->desc_len =
+ (txdesc->queue == QID_BEACON) ? TXINFO_SIZE : TXD_DESC_SIZE;
}
/*
@@ -1851,7 +1859,7 @@ static void rt61pci_write_beacon(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
- struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+ struct queue_entry_priv_pci *entry_priv = entry->priv_data;
unsigned int beacon_base;
u32 reg;
@@ -1867,11 +1875,9 @@ static void rt61pci_write_beacon(struct queue_entry *entry,
* Write entire beacon with descriptor to register.
*/
beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
- rt2x00pci_register_multiwrite(rt2x00dev,
- beacon_base,
- skbdesc->desc, skbdesc->desc_len);
- rt2x00pci_register_multiwrite(rt2x00dev,
- beacon_base + skbdesc->desc_len,
+ rt2x00pci_register_multiwrite(rt2x00dev, beacon_base,
+ entry_priv->desc, TXINFO_SIZE);
+ rt2x00pci_register_multiwrite(rt2x00dev, beacon_base + TXINFO_SIZE,
entry->skb->data, entry->skb->len);
/*
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index fa40d43..fca661c 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -1440,7 +1440,7 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
struct txentry_desc *txdesc)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
- __le32 *txd = skbdesc->desc;
+ __le32 *txd = (__le32 *)(skb->data - TXD_DESC_SIZE);
u32 word;
/*
@@ -1499,6 +1499,12 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
TXPOWER_TO_DEV(rt2x00dev->tx_power));
rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1);
rt2x00_desc_write(txd, 5, word);
+
+ /*
+ * Register descriptor details in skb frame descriptor.
+ */
+ skbdesc->desc = txd;
+ skbdesc->desc_len = TXD_DESC_SIZE;
}
/*
@@ -1508,18 +1514,10 @@ static void rt73usb_write_beacon(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
- struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
unsigned int beacon_base;
u32 reg;
/*
- * Add the descriptor in front of the skb.
- */
- skb_push(entry->skb, entry->queue->desc_size);
- memcpy(entry->skb->data, skbdesc->desc, skbdesc->desc_len);
- skbdesc->desc = entry->skb->data;
-
- /*
* Disable beaconing while we are reloading the beacon data,
* otherwise we might be sending out invalid data.
*/
@@ -1528,6 +1526,11 @@ static void rt73usb_write_beacon(struct queue_entry *entry,
rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
/*
+ * Take the descriptor in front of the skb into account.
+ */
+ skb_push(entry->skb, TXD_DESC_SIZE);
+
+ /*
* Write entire beacon with descriptor to register.
*/
beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
--
1.7.1
^ permalink raw reply related
* Re: [PATCH v2 04/10] rt2x00: Move rt2x00debug_dump_frame declaration to rt2x00.h.
From: Ivo Van Doorn @ 2010-05-13 9:45 UTC (permalink / raw)
To: Gertjan van Wingerde; +Cc: John W. Linville, linux-wireless, users
In-Reply-To: <1273743418-28383-5-git-send-email-gwingerde@gmail.com>
On Thu, May 13, 2010 at 11:36 AM, Gertjan van Wingerde
<gwingerde@gmail.com> wrote:
> This allows rt2x00debug_dump_frame to be used from everywhere.
>
> This is preparation for beacon writing clean ups.
>
> Signed-off-by: Gertjan van Wingerde <gwingerde@gmail.com>
> ---
> drivers/net/wireless/rt2x00/rt2x00.h | 35 +++++++++++++++++++++++++++++
> drivers/net/wireless/rt2x00/rt2x00debug.c | 1 +
> drivers/net/wireless/rt2x00/rt2x00dump.h | 20 ----------------
> drivers/net/wireless/rt2x00/rt2x00lib.h | 10 --------
> 4 files changed, 36 insertions(+), 30 deletions(-)
>
> diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
> index 6c1ff4c..1329f6c 100644
> --- a/drivers/net/wireless/rt2x00/rt2x00.h
> +++ b/drivers/net/wireless/rt2x00/rt2x00.h
> @@ -1015,6 +1015,41 @@ struct queue_entry *rt2x00queue_get_entry(struct data_queue *queue,
> enum queue_index index);
>
> /*
> + * Debugfs handlers.
> + */
> +/**
> + * enum rt2x00_dump_type - Frame type
> + *
> + * These values are used for the indicate the type of frame that is being
> + * dumped:
> + * @DUMP_FRAME_RXDONE: This frame has been received by the hardware.
> + * @DUMP_FRAME_TX: This frame is queued for transmission to the hardware.
> + * @DUMP_FRAME_TXDONE: This frame indicates the device has handled
> + * the tx event which has either succeeded or failed. A frame
> + * with this type should also have been reported with as a
> + * %DUMP_FRAME_TX frame.
> + * @DUMP_FRAME_BEACON: This beacon frame is queued for transmission to the
> + * hardware.
> + */
> +enum rt2x00_dump_type {
> + DUMP_FRAME_RXDONE = 1,
> + DUMP_FRAME_TX = 2,
> + DUMP_FRAME_TXDONE = 3,
> + DUMP_FRAME_BEACON = 4,
> +};
Can't this stay in rt2x00dump.h? The rt2x00dump.h is part of the
public interface towards
userspace which can use these defined to determine the frame type.
We can safely include this header in rt2x00.h since it contains the
public interface anyway.
> +#ifdef CONFIG_RT2X00_LIB_DEBUGFS
> +void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
> + enum rt2x00_dump_type type, struct sk_buff *skb);
> +#else
> +static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
> + enum rt2x00_dump_type type,
> + struct sk_buff *skb)
> +{
> +}
> +#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
Could you add some documentation to this function?
Thanks,
Ivo
^ permalink raw reply
* Re: [PATCH v2 08/10] rt2x00: Push beacon TX descriptor writing to drivers.
From: Ivo Van Doorn @ 2010-05-13 9:46 UTC (permalink / raw)
To: Gertjan van Wingerde; +Cc: John W. Linville, linux-wireless, users
In-Reply-To: <1273743418-28383-9-git-send-email-gwingerde@gmail.com>
On Thu, May 13, 2010 at 11:36 AM, Gertjan van Wingerde
<gwingerde@gmail.com> wrote:
> Not all the devices require a TX descriptor to be written (i.e. rt2800
> device don't require them). Push down the creation of the TX descriptor
> to the device drivers so that they can decide for themselves whether
> a TX descriptor is to be created.
>
> Signed-off-by: Gertjan van Wingerde <gwingerde@gmail.com>
Acked-by: Ivo van Doorn <IvDoorn@gmail.com>
^ permalink raw reply
* [PATCH] wl1271: remove sdio ARM dependency
From: Ohad Ben-Cohen @ 2010-05-13 9:43 UTC (permalink / raw)
To: linux-wireless; +Cc: Luciano Coelho, Ohad Ben-Cohen
Make it possible to use wl1271's SDIO interface on non-ARM platforms.
Fully tested on a x86 platform, compile-tested on ARM.
Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
---
drivers/net/wireless/wl12xx/Kconfig | 2 +-
drivers/net/wireless/wl12xx/wl1271_sdio.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig
index 337fc7b..1516341 100644
--- a/drivers/net/wireless/wl12xx/Kconfig
+++ b/drivers/net/wireless/wl12xx/Kconfig
@@ -65,7 +65,7 @@ config WL1271_SPI
config WL1271_SDIO
tristate "TI wl1271 SDIO support"
- depends on WL1271 && MMC && ARM
+ depends on WL1271 && MMC
---help---
This module adds support for the SDIO interface of adapters using
TI wl1271 chipset. Select this if your platform is using
diff --git a/drivers/net/wireless/wl12xx/wl1271_sdio.c b/drivers/net/wireless/wl12xx/wl1271_sdio.c
index d3d6f30..7059b5c 100644
--- a/drivers/net/wireless/wl12xx/wl1271_sdio.c
+++ b/drivers/net/wireless/wl12xx/wl1271_sdio.c
@@ -28,7 +28,7 @@
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/card.h>
-#include <plat/gpio.h>
+#include <linux/gpio.h>
#include "wl1271.h"
#include "wl12xx_80211.h"
--
1.7.0.4
^ permalink raw reply related
* Re: [PATCH v2 09/10] rt2x00: Reverse calling order of bus write_tx_desc and driver write_tx_desc.
From: Ivo Van Doorn @ 2010-05-13 9:47 UTC (permalink / raw)
To: Gertjan van Wingerde; +Cc: John W. Linville, linux-wireless, users
In-Reply-To: <1273743418-28383-10-git-send-email-gwingerde@gmail.com>
On Thu, May 13, 2010 at 11:36 AM, Gertjan van Wingerde
<gwingerde@gmail.com> wrote:
> For rt2800 reverse the calling order of rt2x00pci_write_data and
> rt2800pci_write_data. Currently rt2800pci_write_data calls rt2x00pci_write_data
> as there can be only 1 driver callback function specified by the driver.
> Reverse this calling order by introducing a new driver callback function,
> called write_tx_datadesc, which is called from the bus-specific write_tx_data
> functions.
> Preparation for futher cleanups in the skb data handling of rt2x00.
>
> Signed-off-by: Gertjan van Wingerde <gwingerde@gmail.com>
Acked-by: Ivo van Doorn <IvDoorn@gmail.com>
^ permalink raw reply
* [RFC] Libertas: Added 11d support using cfg80211
From: Kiran Divekar @ 2010-05-13 11:00 UTC (permalink / raw)
To: linux-wireless@vger.kernel.org; +Cc: libertas-dev@lists.infradead.org
Added 11d support for libertas driver using cfg80211. This is based on Holger Shurig's initial work to add cfg80211 support libertas.
(https://patchwork.kernel.org/patch/64286/)
Please let us know, if there are any improvements comments.
Code is added to send 11d enable command to firmware while
initialisation and pass 11d specific information to firmware
when notifier handler is called by cfg80211.
Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
Signed-off-by: Kiran Divekar <dkiran@marvell.com>
---
drivers/net/wireless/libertas/cfg.c | 110 +++++++++++++++++++++++++++++++
drivers/net/wireless/libertas/cfg.h | 5 ++
drivers/net/wireless/libertas/cmd.c | 65 ++++++++++++++++++
drivers/net/wireless/libertas/cmdresp.c | 50 ++++++++++++++
drivers/net/wireless/libertas/decl.h | 5 ++
drivers/net/wireless/libertas/dev.h | 3 +
drivers/net/wireless/libertas/host.h | 28 ++++++++-
drivers/net/wireless/libertas/main.c | 3 +
8 files changed, 268 insertions(+), 1 deletions(-)
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
index 9b23728..7a44384 100644
--- a/drivers/net/wireless/libertas/cfg.c
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -8,6 +8,7 @@
#include <linux/slab.h>
#include <linux/if_arp.h>
+#include <linux/ieee80211.h>
#include <net/cfg80211.h>
#include <asm/unaligned.h>
@@ -2044,6 +2045,7 @@ int lbs_cfg_register(struct lbs_private *priv)
*/
wdev->wiphy->cipher_suites = cipher_suites;
wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
+ wdev->wiphy->reg_notifier = lbs_reg_notifier;
ret = wiphy_register(wdev->wiphy);
if (ret < 0)
@@ -2063,6 +2065,114 @@ int lbs_cfg_register(struct lbs_private *priv)
return ret;
}
+/**
+ * @brief This function sets DOMAIN INFO to FW
+ * @param priv pointer to struct lbs_private
+ * @return 0; -1
+*/
+static int lbs_11d_set_domain_info(struct lbs_private *priv)
+{
+ int ret;
+
+ ret = lbs_prepare_and_send_command(priv, CMD_802_11D_DOMAIN_INFO,
+ CMD_ACT_SET,
+ CMD_OPTION_WAITFORRSP, 0, NULL);
+ if (ret)
+ lbs_deb_11d("fail to dnld domain info\n");
+
+ return ret;
+}
+
+static void lbs_send_domain_info_cmd_fw(struct wiphy *wiphy,
+ struct regulatory_request *request)
+{
+ u8 no_of_triplet = 0;
+ u8 no_of_parsed_chan = 0;
+ u8 first_channel = 0, next_chan = 0, max_pwr = 0;
+ u8 i, flag = 0;
+ enum ieee80211_band band;
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_channel *ch;
+ struct lbs_private *priv = wiphy_priv(wiphy);
+ struct lbs_802_11d_domain_reg *domain_info = &priv->domain_reg;
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_CFG80211);
+
+ /* Set country code */
+ domain_info->country_code[0] = request->alpha2[0];
+ domain_info->country_code[1] = request->alpha2[1];
+ domain_info->country_code[2] = ' ';
+
+ for (band = 0; band < IEEE80211_NUM_BANDS ; band++) {
+
+ if (!wiphy->bands[band])
+ continue;
+
+ sband = wiphy->bands[band];
+
+ for (i = 0; i < sband->n_channels ; i++) {
+ ch = &sband->channels[i];
+ if (ch->flags & IEEE80211_CHAN_DISABLED)
+ continue;
+
+ if (!flag) {
+ flag = 1;
+ next_chan = first_channel = (u32) ch->hw_value;
+ max_pwr = ch->max_power;
+ no_of_parsed_chan = 1;
+ continue;
+ }
+
+ if (ch->hw_value == next_chan + 1 &&
+ ch->max_power == max_pwr) {
+ next_chan++;
+ no_of_parsed_chan++;
+ } else {
+ domain_info->triplet[no_of_triplet]
+ .chans.first_channel = first_channel;
+ domain_info->triplet[no_of_triplet]
+ .chans.num_channels = no_of_parsed_chan;
+ domain_info->triplet[no_of_triplet]
+ .chans.max_power = max_pwr;
+ no_of_triplet++;
+ flag = 0;
+ }
+ }
+ if (flag) {
+ domain_info->triplet[no_of_triplet]
+ .chans.first_channel = first_channel;
+ domain_info->triplet[no_of_triplet]
+ .chans.num_channels = no_of_parsed_chan;
+ domain_info->triplet[no_of_triplet]
+ .chans.max_power = max_pwr;
+ no_of_triplet++;
+ }
+ }
+
+ domain_info->no_triplet = no_of_triplet;
+
+ /* Set domain info */
+ ret = lbs_11d_set_domain_info(priv);
+ if (ret)
+ lbs_pr_err("11D: error setting domain info in FW\n");
+
+ lbs_deb_leave(LBS_DEB_CFG80211);
+}
+
+int lbs_reg_notifier(struct wiphy *wiphy,
+ struct regulatory_request *request)
+{
+ lbs_deb_enter_args(LBS_DEB_CFG80211, "cfg80211 regulatory domain "
+ "callback for domain %c%c\n", request->alpha2[0],
+ request->alpha2[1]);
+
+ lbs_send_domain_info_cmd_fw(wiphy, request);
+
+ lbs_deb_leave(LBS_DEB_CFG80211);
+
+ return 0;
+}
void lbs_scan_deinit(struct lbs_private *priv)
{
diff --git a/drivers/net/wireless/libertas/cfg.h b/drivers/net/wireless/libertas/cfg.h
index eae3fd9..756fb98 100644
--- a/drivers/net/wireless/libertas/cfg.h
+++ b/drivers/net/wireless/libertas/cfg.h
@@ -3,11 +3,16 @@
struct device;
struct lbs_private;
+struct regulatory_request;
+struct wiphy;
struct wireless_dev *lbs_cfg_alloc(struct device *dev);
int lbs_cfg_register(struct lbs_private *priv);
void lbs_cfg_free(struct lbs_private *priv);
+int lbs_reg_notifier(struct wiphy *wiphy,
+ struct regulatory_request *request);
+
/* All of those are TODOs: */
#define lbs_cmd_802_11_rssi(priv, cmdptr) (0)
#define lbs_ret_802_11_rssi(priv, resp) (0)
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index 10067ca..cb93de9 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -877,6 +877,66 @@ void lbs_set_mac_control(struct lbs_private *priv)
}
/**
+ * @brief This function implements command CMD_802_11D_DOMAIN_INFO
+ * @param priv pointer to struct lbs_private
+ * @param cmd pointer to cmd buffer
+ * @param cmdno cmd ID
+ * @param cmdOption cmd action
+ * @return 0
+*/
+int lbs_cmd_802_11d_domain_info(struct lbs_private *priv,
+ struct cmd_ds_command *cmd,
+ u16 cmdoption)
+{
+ struct cmd_ds_802_11d_domain_info *pdomaininfo =
+ &cmd->params.domaininfo;
+ struct mrvl_ie_domain_param_set *domain = &pdomaininfo->domain;
+ u8 nr_triplet = priv->domain_reg.no_triplet;
+
+ lbs_deb_enter(LBS_DEB_11D);
+
+ lbs_deb_11d("nr_triplet=%x\n", nr_triplet);
+
+ pdomaininfo->action = cpu_to_le16(cmdoption);
+ if (cmdoption == CMD_ACT_GET) {
+ cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
+ sizeof(struct cmd_header));
+ lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd,
+ le16_to_cpu(cmd->size));
+ goto done;
+ }
+
+ domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN);
+ memcpy(domain->countrycode, priv->domain_reg.country_code,
+ sizeof(domain->countrycode));
+
+ domain->header.len = cpu_to_le16(nr_triplet
+ * sizeof(struct ieee80211_country_ie_triplet)
+ + sizeof(domain->countrycode));
+
+ if (nr_triplet) {
+ memcpy(domain->triplet, priv->domain_reg.triplet,
+ nr_triplet *
+ sizeof(struct ieee80211_country_ie_triplet));
+
+ cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
+ le16_to_cpu(domain->header.len) +
+ sizeof(struct mrvl_ie_header) +
+ sizeof(struct cmd_header));
+ } else {
+ cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
+ sizeof(struct cmd_header));
+ }
+
+ lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd,
+ le16_to_cpu(cmd->size));
+
+done:
+ lbs_deb_enter(LBS_DEB_11D);
+ return 0;
+}
+
+/**
* @brief This function prepare the command before send to firmware.
*
* @param priv A pointer to struct lbs_private structure
@@ -974,6 +1034,11 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
ret = 0;
goto done;
+ case CMD_802_11D_DOMAIN_INFO:
+ cmdptr->command = cpu_to_le16(cmd_no);
+ ret = lbs_cmd_802_11d_domain_info(priv, cmdptr, cmd_action);
+ break;
+
case CMD_802_11_TPC_CFG:
cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG);
cmdptr->size =
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
index d6c61bd..c31b32d 100644
--- a/drivers/net/wireless/libertas/cmdresp.c
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -97,6 +97,52 @@ static int lbs_ret_reg_access(struct lbs_private *priv,
return ret;
}
+/**
+ * @brief This function parses countryinfo from AP and download country info to FW
+ * @param priv pointer to struct lbs_private
+ * @param resp pointer to command response buffer
+ * @return 0; -1
+ */
+int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp)
+{
+ struct cmd_ds_802_11d_domain_info *domaininfo =
+ &resp->params.domaininforesp;
+ struct mrvl_ie_domain_param_set *domain = &domaininfo->domain;
+ u16 action = le16_to_cpu(domaininfo->action);
+ s16 ret = 0;
+ u8 nr_triplet = 0;
+
+ lbs_deb_enter(LBS_DEB_11D);
+
+ lbs_deb_hex(LBS_DEB_11D, "domain info resp", (u8 *) resp,
+ (int)le16_to_cpu(resp->size));
+
+ nr_triplet = (le16_to_cpu(domain->header.len) - COUNTRY_CODE_LEN) /
+ sizeof(struct ieee80211_country_ie_triplet);
+
+ lbs_deb_11d("domain info resp: nr_triplet %d\n", nr_triplet);
+
+ if (nr_triplet > MRVDRV_MAX_TRIPLET_802_11D) {
+ lbs_deb_11d("invalid number of triplets returned!!\n");
+ return -1;
+ }
+
+ switch (action) {
+ case CMD_ACT_SET: /*Proc set action */
+ break;
+
+ case CMD_ACT_GET:
+ break;
+ default:
+ lbs_deb_11d("invalid action:%d\n", domaininfo->action);
+ ret = -1;
+ break;
+ }
+
+ lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
+ return ret;
+}
+
static inline int handle_cmd_response(struct lbs_private *priv,
struct cmd_header *cmd_response)
{
@@ -130,6 +176,10 @@ static inline int handle_cmd_response(struct lbs_private *priv,
ret = lbs_ret_802_11_rssi(priv, resp);
break;
+ case CMD_RET(CMD_802_11D_DOMAIN_INFO):
+ ret = lbs_ret_802_11d_domain_info(resp);
+ break;
+
case CMD_RET(CMD_802_11_TPC_CFG):
spin_lock_irqsave(&priv->driver_lock, flags);
memmove((void *)priv->cur_cmd->callback_arg, &resp->params.tpccfg,
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
index 2bccad3..9d2566e 100644
--- a/drivers/net/wireless/libertas/decl.h
+++ b/drivers/net/wireless/libertas/decl.h
@@ -13,6 +13,7 @@
struct lbs_private;
struct sk_buff;
struct net_device;
+struct cmd_ds_command;
/* ethtool.c */
@@ -52,5 +53,9 @@ int lbs_exit_auto_deep_sleep(struct lbs_private *priv);
u32 lbs_fw_index_to_data_rate(u8 index);
u8 lbs_data_rate_to_fw_index(u32 rate);
+int lbs_cmd_802_11d_domain_info(struct lbs_private *priv,
+ struct cmd_ds_command *cmd, u16 cmdoption);
+
+int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp);
#endif
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index afbd891..d9dad5d 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -60,6 +60,9 @@ struct lbs_private {
struct dentry *regs_dir;
struct dentry *debugfs_regs_files[6];
+ /** 11D and domain regulatory data */
+ struct lbs_802_11d_domain_reg domain_reg;
+
/* Hardware debugging */
u32 mac_offset;
u32 bbp_offset;
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h
index 3809c0b..112fbf1 100644
--- a/drivers/net/wireless/libertas/host.h
+++ b/drivers/net/wireless/libertas/host.h
@@ -389,6 +389,30 @@ struct lbs_offset_value {
u32 value;
} __attribute__ ((packed));
+#define MRVDRV_MAX_TRIPLET_802_11D 83
+
+#define COUNTRY_CODE_LEN 3
+
+struct mrvl_ie_domain_param_set {
+ struct mrvl_ie_header header;
+
+ u8 countrycode[COUNTRY_CODE_LEN];
+ struct ieee80211_country_ie_triplet triplet[1];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11d_domain_info {
+ __le16 action;
+ struct mrvl_ie_domain_param_set domain;
+} __attribute__ ((packed));
+
+struct lbs_802_11d_domain_reg {
+ /** Country code*/
+ u8 country_code[COUNTRY_CODE_LEN];
+ /** No. of triplet*/
+ u8 no_triplet;
+ struct ieee80211_country_ie_triplet triplet[MRVDRV_MAX_TRIPLET_802_11D];
+} __attribute__ ((packed));
+
/*
* Define data structure for CMD_GET_HW_SPEC
* This structure defines the response for the GET_HW_SPEC command
@@ -949,6 +973,9 @@ struct cmd_ds_command {
struct cmd_ds_bbp_reg_access bbpreg;
struct cmd_ds_rf_reg_access rfreg;
+ struct cmd_ds_802_11d_domain_info domaininfo;
+ struct cmd_ds_802_11d_domain_info domaininforesp;
+
struct cmd_ds_802_11_tpc_cfg tpccfg;
struct cmd_ds_802_11_afc afc;
struct cmd_ds_802_11_led_ctrl ledgpio;
@@ -958,5 +985,4 @@ struct cmd_ds_command {
struct cmd_ds_802_11_beacon_control bcn_ctrl;
} params;
} __attribute__ ((packed));
-
#endif
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index 2fd5042..ff4380e 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -629,6 +629,9 @@ static int lbs_setup_firmware(struct lbs_private *priv)
priv->txpower_max = maxlevel;
}
+ /* Send cmd to FW to enable 11D function */
+ ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_11D_ENABLE, 1);
+
lbs_set_mac_control(priv);
done:
lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
--
1.5.3.4
^ permalink raw reply related
* Re: [PATCH v2 04/10] rt2x00: Move rt2x00debug_dump_frame declaration to rt2x00.h.
From: Gertjan van Wingerde @ 2010-05-13 11:04 UTC (permalink / raw)
To: Ivo Van Doorn; +Cc: John W. Linville, linux-wireless, users
In-Reply-To: <AANLkTilbzQ1_16u2hjkh6pFSnUmjg8bNRHiJf_g1hPPb@mail.gmail.com>
On 05/13/10 11:45, Ivo Van Doorn wrote:
> On Thu, May 13, 2010 at 11:36 AM, Gertjan van Wingerde
> <gwingerde@gmail.com> wrote:
>> This allows rt2x00debug_dump_frame to be used from everywhere.
>>
>> This is preparation for beacon writing clean ups.
>>
>> Signed-off-by: Gertjan van Wingerde <gwingerde@gmail.com>
>> ---
>> drivers/net/wireless/rt2x00/rt2x00.h | 35 +++++++++++++++++++++++++++++
>> drivers/net/wireless/rt2x00/rt2x00debug.c | 1 +
>> drivers/net/wireless/rt2x00/rt2x00dump.h | 20 ----------------
>> drivers/net/wireless/rt2x00/rt2x00lib.h | 10 --------
>> 4 files changed, 36 insertions(+), 30 deletions(-)
>>
>> diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
>> index 6c1ff4c..1329f6c 100644
>> --- a/drivers/net/wireless/rt2x00/rt2x00.h
>> +++ b/drivers/net/wireless/rt2x00/rt2x00.h
>> @@ -1015,6 +1015,41 @@ struct queue_entry *rt2x00queue_get_entry(struct data_queue *queue,
>> enum queue_index index);
>>
>> /*
>> + * Debugfs handlers.
>> + */
>> +/**
>> + * enum rt2x00_dump_type - Frame type
>> + *
>> + * These values are used for the indicate the type of frame that is being
>> + * dumped:
>> + * @DUMP_FRAME_RXDONE: This frame has been received by the hardware.
>> + * @DUMP_FRAME_TX: This frame is queued for transmission to the hardware.
>> + * @DUMP_FRAME_TXDONE: This frame indicates the device has handled
>> + * the tx event which has either succeeded or failed. A frame
>> + * with this type should also have been reported with as a
>> + * %DUMP_FRAME_TX frame.
>> + * @DUMP_FRAME_BEACON: This beacon frame is queued for transmission to the
>> + * hardware.
>> + */
>> +enum rt2x00_dump_type {
>> + DUMP_FRAME_RXDONE = 1,
>> + DUMP_FRAME_TX = 2,
>> + DUMP_FRAME_TXDONE = 3,
>> + DUMP_FRAME_BEACON = 4,
>> +};
>
> Can't this stay in rt2x00dump.h? The rt2x00dump.h is part of the
> public interface towards
> userspace which can use these defined to determine the frame type.
> We can safely include this header in rt2x00.h since it contains the
> public interface anyway.
Hmpf, it looks like there is a lot of unspecified assumptions about the placement
of information in files and for some functionality. We must get better in documenting
this.
Although it is a bit strange to have a public interface to userspace defined this deep
in the kernel source tree, I'll move it back and put a big fat comment is there that this
actually is the public interface towards userspace and that all this information is to
be kept together.
>
>> +#ifdef CONFIG_RT2X00_LIB_DEBUGFS
>> +void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
>> + enum rt2x00_dump_type type, struct sk_buff *skb);
>> +#else
>> +static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
>> + enum rt2x00_dump_type type,
>> + struct sk_buff *skb)
>> +{
>> +}
>> +#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
>
> Could you add some documentation to this function?
>
Off course I can; although that is a bit more than just moving declarations ;-)
---
Gertjan.
^ permalink raw reply
* [PATCH v3 04/10] rt2x00: Move rt2x00debug_dump_frame declaration to rt2x00.h.
From: Gertjan van Wingerde @ 2010-05-13 11:16 UTC (permalink / raw)
To: John W. Linville
Cc: Ivo van Doorn, linux-wireless, users, Gertjan van Wingerde
This allows rt2x00debug_dump_frame to be used from everywhere.
This is preparation for beacon writing clean ups.
Signed-off-by: Gertjan van Wingerde <gwingerde@gmail.com>
---
v3: Handled Ivo's further comments.
---
drivers/net/wireless/rt2x00/rt2x00.h | 21 +++++++++++++++++++++
drivers/net/wireless/rt2x00/rt2x00debug.c | 1 +
drivers/net/wireless/rt2x00/rt2x00dump.h | 7 ++++++-
drivers/net/wireless/rt2x00/rt2x00lib.h | 10 ----------
4 files changed, 28 insertions(+), 11 deletions(-)
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 6c1ff4c..c8e5fed 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -39,6 +39,7 @@
#include <net/mac80211.h>
#include "rt2x00debug.h"
+#include "rt2x00dump.h"
#include "rt2x00leds.h"
#include "rt2x00reg.h"
#include "rt2x00queue.h"
@@ -1015,6 +1016,26 @@ struct queue_entry *rt2x00queue_get_entry(struct data_queue *queue,
enum queue_index index);
/*
+ * Debugfs handlers.
+ */
+/**
+ * rt2x00debug_dump_frame - Dump a frame to userspace through debugfs.
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ * @type: The type of frame that is being dumped.
+ * @skb: The skb containing the frame to be dumped.
+ */
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
+ enum rt2x00_dump_type type, struct sk_buff *skb);
+#else
+static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
+ enum rt2x00_dump_type type,
+ struct sk_buff *skb)
+{
+}
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+
+/*
* Interrupt context handlers.
*/
void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev);
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c
index 1e81eef..9dd8b7c 100644
--- a/drivers/net/wireless/rt2x00/rt2x00debug.c
+++ b/drivers/net/wireless/rt2x00/rt2x00debug.c
@@ -210,6 +210,7 @@ void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
if (!test_bit(FRAME_DUMP_FILE_OPEN, &intf->frame_dump_flags))
skb_queue_purge(&intf->frame_dump_skbqueue);
}
+EXPORT_SYMBOL_GPL(rt2x00debug_dump_frame);
static int rt2x00debug_file_open(struct inode *inode, struct file *file)
{
diff --git a/drivers/net/wireless/rt2x00/rt2x00dump.h b/drivers/net/wireless/rt2x00/rt2x00dump.h
index ed303b4..8fd342c 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dump.h
+++ b/drivers/net/wireless/rt2x00/rt2x00dump.h
@@ -20,7 +20,12 @@
/*
Module: rt2x00dump
- Abstract: Data structures for the rt2x00debug & userspace.
+ Abstract:
+ Data structures for the rt2x00debug & userspace.
+
+ The declarations in this file can be used by both rt2x00
+ and userspace and therefore should be kept together in
+ this file.
*/
#ifndef RT2X00DUMP_H
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h
index be2e37f..0ca40e1 100644
--- a/drivers/net/wireless/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -27,8 +27,6 @@
#ifndef RT2X00LIB_H
#define RT2X00LIB_H
-#include "rt2x00dump.h"
-
/*
* Interval defines
*/
@@ -296,8 +294,6 @@ static inline void rt2x00lib_free_firmware(struct rt2x00_dev *rt2x00dev)
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
void rt2x00debug_register(struct rt2x00_dev *rt2x00dev);
void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev);
-void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
- enum rt2x00_dump_type type, struct sk_buff *skb);
void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev,
struct rxdone_entry_desc *rxdesc);
#else
@@ -309,12 +305,6 @@ static inline void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev)
{
}
-static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
- enum rt2x00_dump_type type,
- struct sk_buff *skb)
-{
-}
-
static inline void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev,
struct rxdone_entry_desc *rxdesc)
{
--
1.7.1
^ permalink raw reply related
* Re: [PATCH v3 04/10] rt2x00: Move rt2x00debug_dump_frame declaration to rt2x00.h.
From: Ivo Van Doorn @ 2010-05-13 11:38 UTC (permalink / raw)
To: Gertjan van Wingerde; +Cc: John W. Linville, linux-wireless, users
In-Reply-To: <1273749396-3199-1-git-send-email-gwingerde@gmail.com>
On Thu, May 13, 2010 at 1:16 PM, Gertjan van Wingerde
<gwingerde@gmail.com> wrote:
> This allows rt2x00debug_dump_frame to be used from everywhere.
>
> This is preparation for beacon writing clean ups.
>
> Signed-off-by: Gertjan van Wingerde <gwingerde@gmail.com>
Thanks!
Acked-by: Ivo van Doorn <IvDoorn@gmail.com>
^ permalink raw reply
* Re: [PATCH] compat-wireless: fix 07-change-default-rate-alg.patch
From: Hauke Mehrtens @ 2010-05-13 11:48 UTC (permalink / raw)
To: Bruno Randolf; +Cc: lrodriguez, linux-wireless
In-Reply-To: <20100513011711.13007.45318.stgit@tt-desk>
Am 13.05.2010 03:17, schrieb Bruno Randolf:
> i need this change to make it apply again
>
> Signed-off-by: Bruno Randolf <br1@einfach.org>
> ---
> patches/07-change-default-rate-alg.patch | 10 +++++-----
> 1 files changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/patches/07-change-default-rate-alg.patch b/patches/07-change-default-rate-alg.patch
> index f0ccbce..f73a4c5 100644
> --- a/patches/07-change-default-rate-alg.patch
> +++ b/patches/07-change-default-rate-alg.patch
> @@ -10,9 +10,9 @@ and define CONFIG_COMPAT_MAC80211_RC_DEFAULT on config.mk.
> Through the compat autoconf we then get it also defined there
> at compilation time.
>
> ---- a/net/mac80211/rate.c
> -+++ b/net/mac80211/rate.c
> -@@ -23,7 +23,7 @@ struct rate_control_alg {
> +--- a/net/mac80211/rate.c 2010-05-12 16:27:02.245747971 +0900
> ++++ b/net/mac80211/rate.c 2010-05-12 17:00:45.855748158 +0900
> +@@ -23,7 +23,7 @@
> static LIST_HEAD(rate_ctrl_algs);
> static DEFINE_MUTEX(rate_ctrl_mutex);
>
> @@ -21,7 +21,7 @@ at compilation time.
> module_param(ieee80211_default_rc_algo, charp, 0644);
> MODULE_PARM_DESC(ieee80211_default_rc_algo,
> "Default rate control algorithm for mac80211 to use");
> -@@ -119,8 +119,8 @@ ieee80211_rate_control_ops_get(const cha
> +@@ -118,8 +118,8 @@
> ops = ieee80211_try_rate_control_ops_get(ieee80211_default_rc_algo);
>
> /* try built-in one if specific alg requested but not found */
> @@ -29,6 +29,6 @@ at compilation time.
> - ops = ieee80211_try_rate_control_ops_get(CONFIG_MAC80211_RC_DEFAULT);
> + if (!ops && strlen(CONFIG_COMPAT_MAC80211_RC_DEFAULT))
> + ops = ieee80211_try_rate_control_ops_get(CONFIG_COMPAT_MAC80211_RC_DEFAULT);
> - kparam_unblock_sysfs_write(ieee80211_default_rc_algo);
>
> return ops;
> + }
>
Hi Bruno,
For me it does not apply any more against linux-next with your patch,
without your patch it still applies.
In the linux-next tree there is this line
kparam_unblock_sysfs_write(ieee80211_default_rc_algo);
it was introduced 2 days ago. In wireless-text this does not exist for now.
Could it be that you tried to generate compat-wireless out of
wireless-testing and not linux-next?
Please run "./scripts/admin-refresh.sh refresh" after changing a patch
to format it automatically in a common way.
Hauke
^ permalink raw reply
* Possible issue with mac80211 and certain access points
From: Chad Koehler @ 2010-05-13 14:41 UTC (permalink / raw)
To: linux-wireless
Recently purchased a Palm Pre and immediately found some issues with
connecting to the Wifi Hotspot. Connecting to other access points
would work flawlessly.
Using the Palm Pre hotspot, I can get connected, but the connection
will drop after a very short period of time. There are messages in
the system log whenever the connection drops:
No probe response from AP <address> after 500ms, disconnecting.
An internet search turned up several results for people with the same
issue, different wireless drivers and different access point types.
I traced this message down to mac80211/mlme.c, to the
ieee80211_sta_work() function, and was able to determine that for some
reason this particular AP was not responding to probe requests. This
let me further on to the function ieee80211_mgd_probe_ap_send(), which
sends a direct probe request to the AP -- this probe request was being
sent and never responded to.
If I change this function to send a probe request to the broadcast
address, in a similar manner to what is done in
ieee80211_direct_probe(), then the access point responds and works
without issue.
Due to the volume of issues on the internet that I see with the same
underlying symptoms, I wonder if there are some small amount of access
points that will not respond to a direct packet probe request even
when associated.
I admittedly know very little about wireless networking internals, so
I am hesitant to state that this fix is necessary or appropriate, but
it does solve the issue for me and I am able to remain connected to
the Palm Pre hotspot, as well as other access points that I have
tried.
Please let me know if I can provide further information in this space.
Thank You,
Chad
^ permalink raw reply
* [PATCH] mac80211: add the minstrel_ht rate control algorithm
From: Felix Fietkau @ 2010-05-13 14:48 UTC (permalink / raw)
To: linux-wireless
Cc: Derek Smithies, Benoit PAPILLAULT, Luis R. Rodriguez,
Christian Lamparter, Björn Smedman, Bob Copeland,
Johannes Berg
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
changes since rfc v3:
- various fixes by christian lamparter
- tune sampling for better aggregation length
- added kconfig option
- enables 3 streams (ath9k supports it now)
--- a/net/mac80211/Makefile
+++ b/net/mac80211/Makefile
@@ -50,7 +50,11 @@ rc80211_pid-$(CONFIG_MAC80211_DEBUGFS) +
rc80211_minstrel-y := rc80211_minstrel.o
rc80211_minstrel-$(CONFIG_MAC80211_DEBUGFS) += rc80211_minstrel_debugfs.o
+rc80211_minstrel_ht-y := rc80211_minstrel_ht.o
+rc80211_minstrel_ht-$(CONFIG_MAC80211_DEBUGFS) += rc80211_minstrel_ht_debugfs.o
+
mac80211-$(CONFIG_MAC80211_RC_PID) += $(rc80211_pid-y)
mac80211-$(CONFIG_MAC80211_RC_MINSTREL) += $(rc80211_minstrel-y)
+mac80211-$(CONFIG_MAC80211_RC_MINSTREL_HT) += $(rc80211_minstrel_ht-y)
ccflags-y += -D__CHECK_ENDIAN__
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -716,6 +716,10 @@ static int __init ieee80211_init(void)
if (ret)
return ret;
+ ret = rc80211_minstrel_ht_init();
+ if (ret)
+ goto err_minstrel;
+
ret = rc80211_pid_init();
if (ret)
goto err_pid;
@@ -728,6 +732,8 @@ static int __init ieee80211_init(void)
err_netdev:
rc80211_pid_exit();
err_pid:
+ rc80211_minstrel_ht_exit();
+ err_minstrel:
rc80211_minstrel_exit();
return ret;
@@ -736,6 +742,7 @@ static int __init ieee80211_init(void)
static void __exit ieee80211_exit(void)
{
rc80211_pid_exit();
+ rc80211_minstrel_ht_exit();
rc80211_minstrel_exit();
/*
--- a/net/mac80211/rate.h
+++ b/net/mac80211/rate.h
@@ -147,5 +147,18 @@ static inline void rc80211_minstrel_exit
}
#endif
+#ifdef CONFIG_MAC80211_RC_MINSTREL_HT
+extern int rc80211_minstrel_ht_init(void);
+extern void rc80211_minstrel_ht_exit(void);
+#else
+static inline int rc80211_minstrel_ht_init(void)
+{
+ return 0;
+}
+static inline void rc80211_minstrel_ht_exit(void)
+{
+}
+#endif
+
#endif /* IEEE80211_RATE_H */
--- /dev/null
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -0,0 +1,824 @@
+/*
+ * Copyright (C) 2010 Felix Fietkau <nbd@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/netdevice.h>
+#include <linux/types.h>
+#include <linux/skbuff.h>
+#include <linux/debugfs.h>
+#include <linux/random.h>
+#include <linux/ieee80211.h>
+#include <net/mac80211.h>
+#include "rate.h"
+#include "rc80211_minstrel.h"
+#include "rc80211_minstrel_ht.h"
+
+#define AVG_PKT_SIZE 1200
+#define SAMPLE_COLUMNS 10
+#define EWMA_LEVEL 75
+
+/* Number of bits for an average sized packet */
+#define MCS_NBITS (AVG_PKT_SIZE << 3)
+
+/* Number of symbols for a packet with (bps) bits per symbol */
+#define MCS_NSYMS(bps) ((MCS_NBITS + (bps) - 1) / (bps))
+
+/* Transmission time for a packet containing (syms) symbols */
+#define MCS_SYMBOL_TIME(sgi, syms) \
+ (sgi ? \
+ ((syms) * 18 + 4) / 5 : /* syms * 3.6 us */ \
+ (syms) << 2 /* syms * 4 us */ \
+ )
+
+/* Transmit duration for the raw data part of an average sized packet */
+#define MCS_DURATION(streams, sgi, bps) MCS_SYMBOL_TIME(sgi, MCS_NSYMS((streams) * (bps)))
+
+/* MCS rate information for an MCS group */
+#define MCS_GROUP(_streams, _sgi, _ht40) { \
+ .streams = _streams, \
+ .flags = \
+ (_sgi ? IEEE80211_TX_RC_SHORT_GI : 0) | \
+ (_ht40 ? IEEE80211_TX_RC_40_MHZ_WIDTH : 0), \
+ .duration = { \
+ MCS_DURATION(_streams, _sgi, _ht40 ? 54 : 26), \
+ MCS_DURATION(_streams, _sgi, _ht40 ? 108 : 52), \
+ MCS_DURATION(_streams, _sgi, _ht40 ? 162 : 78), \
+ MCS_DURATION(_streams, _sgi, _ht40 ? 216 : 104), \
+ MCS_DURATION(_streams, _sgi, _ht40 ? 324 : 156), \
+ MCS_DURATION(_streams, _sgi, _ht40 ? 432 : 208), \
+ MCS_DURATION(_streams, _sgi, _ht40 ? 486 : 234), \
+ MCS_DURATION(_streams, _sgi, _ht40 ? 540 : 260) \
+ } \
+}
+
+/*
+ * To enable sufficiently targeted rate sampling, MCS rates are divided into
+ * groups, based on the number of streams and flags (HT40, SGI) that they
+ * use.
+ */
+const struct mcs_group minstrel_mcs_groups[] = {
+ MCS_GROUP(1, 0, 0),
+ MCS_GROUP(2, 0, 0),
+#if MINSTREL_MAX_STREAMS >= 3
+ MCS_GROUP(3, 0, 0),
+#endif
+
+ MCS_GROUP(1, 1, 0),
+ MCS_GROUP(2, 1, 0),
+#if MINSTREL_MAX_STREAMS >= 3
+ MCS_GROUP(3, 1, 0),
+#endif
+
+ MCS_GROUP(1, 0, 1),
+ MCS_GROUP(2, 0, 1),
+#if MINSTREL_MAX_STREAMS >= 3
+ MCS_GROUP(3, 0, 1),
+#endif
+
+ MCS_GROUP(1, 1, 1),
+ MCS_GROUP(2, 1, 1),
+#if MINSTREL_MAX_STREAMS >= 3
+ MCS_GROUP(3, 1, 1),
+#endif
+};
+
+static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES];
+
+/*
+ * Perform EWMA (Exponentially Weighted Moving Average) calculation
+ */
+static int
+minstrel_ewma(int old, int new, int weight)
+{
+ return (new * (100 - weight) + old * weight) / 100;
+}
+
+/*
+ * Look up an MCS group index based on mac80211 rate information
+ */
+static int
+minstrel_ht_get_group_idx(struct ieee80211_tx_rate *rate)
+{
+ int streams = (rate->idx / MCS_GROUP_RATES) + 1;
+ u32 flags = IEEE80211_TX_RC_SHORT_GI | IEEE80211_TX_RC_40_MHZ_WIDTH;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(minstrel_mcs_groups); i++) {
+ if (minstrel_mcs_groups[i].streams != streams)
+ continue;
+ if (minstrel_mcs_groups[i].flags != (rate->flags & flags))
+ continue;
+
+ return i;
+ }
+
+ WARN_ON(1);
+ return 0;
+}
+
+static inline struct minstrel_rate_stats *
+minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index)
+{
+ return &mi->groups[index / MCS_GROUP_RATES].rates[index % MCS_GROUP_RATES];
+}
+
+
+/*
+ * Recalculate success probabilities and counters for a rate using EWMA
+ */
+static void
+minstrel_calc_rate_ewma(struct minstrel_priv *mp, struct minstrel_rate_stats *mr)
+{
+ if (unlikely(mr->attempts > 0)) {
+ mr->sample_skipped = 0;
+ mr->cur_prob = MINSTREL_FRAC(mr->success, mr->attempts);
+ if (!mr->att_hist)
+ mr->probability = mr->cur_prob;
+ else
+ mr->probability = minstrel_ewma(mr->probability,
+ mr->cur_prob, EWMA_LEVEL);
+ mr->att_hist += mr->attempts;
+ mr->succ_hist += mr->success;
+ } else {
+ mr->sample_skipped++;
+ }
+ mr->last_success = mr->success;
+ mr->last_attempts = mr->attempts;
+ mr->success = 0;
+ mr->attempts = 0;
+}
+
+/*
+ * Calculate throughput based on the average A-MPDU length, taking into account
+ * the expected number of retransmissions and their expected length
+ */
+static void
+minstrel_ht_calc_tp(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
+ int group, int rate)
+{
+ struct minstrel_rate_stats *mr;
+ unsigned int usecs;
+
+ mr = &mi->groups[group].rates[rate];
+
+ if (mr->probability < MINSTREL_FRAC(1, 10)) {
+ mr->cur_tp = 0;
+ return;
+ }
+
+ usecs = mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len);
+ usecs += minstrel_mcs_groups[group].duration[rate];
+ mr->cur_tp = MINSTREL_TRUNC((1000000 / usecs) * mr->probability);
+}
+
+/*
+ * Update rate statistics and select new primary rates
+ *
+ * Rules for rate selection:
+ * - max_prob_rate must use only one stream, as a tradeoff between delivery
+ * probability and throughput during strong fluctuations
+ * - as long as the max prob rate has a probability of more than 3/4, pick
+ * higher throughput rates, even if the probablity is a bit lower
+ */
+static void
+minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
+{
+ struct minstrel_mcs_group_data *mg;
+ struct minstrel_rate_stats *mr;
+ int cur_prob, cur_prob_tp, cur_tp, cur_tp2;
+ int group, i, index;
+
+ if (mi->ampdu_packets > 0) {
+ mi->avg_ampdu_len = minstrel_ewma(mi->avg_ampdu_len,
+ MINSTREL_FRAC(mi->ampdu_len, mi->ampdu_packets), EWMA_LEVEL);
+ mi->ampdu_len = 0;
+ mi->ampdu_packets = 0;
+ }
+
+ mi->sample_slow = 0;
+ mi->sample_count = 0;
+ mi->max_tp_rate = 0;
+ mi->max_tp_rate2 = 0;
+ mi->max_prob_rate = 0;
+
+ for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) {
+ cur_prob = 0;
+ cur_prob_tp = 0;
+ cur_tp = 0;
+ cur_tp2 = 0;
+
+ mg = &mi->groups[group];
+ if (!mg->supported)
+ continue;
+
+ mg->max_tp_rate = 0;
+ mg->max_tp_rate2 = 0;
+ mg->max_prob_rate = 0;
+ mi->sample_count++;
+
+ for (i = 0; i < MCS_GROUP_RATES; i++) {
+ if (!(mg->supported & BIT(i)))
+ continue;
+
+ mr = &mg->rates[i];
+ mr->retry_updated = false;
+ index = MCS_GROUP_RATES * group + i;
+ minstrel_calc_rate_ewma(mp, mr);
+ minstrel_ht_calc_tp(mp, mi, group, i);
+
+ if (!mr->cur_tp)
+ continue;
+
+ /* ignore the lowest rate of each single-stream group */
+ if (!i && minstrel_mcs_groups[group].streams == 1)
+ continue;
+
+ if ((mr->cur_tp > cur_prob_tp && mr->probability >
+ MINSTREL_FRAC(3, 4)) || mr->probability > cur_prob) {
+ mg->max_prob_rate = index;
+ cur_prob = mr->probability;
+ }
+
+ if (mr->cur_tp > cur_tp) {
+ swap(index, mg->max_tp_rate);
+ cur_tp = mr->cur_tp;
+ mr = minstrel_get_ratestats(mi, index);
+ }
+
+ if (index >= mg->max_tp_rate)
+ continue;
+
+ if (mr->cur_tp > cur_tp2) {
+ mg->max_tp_rate2 = index;
+ cur_tp2 = mr->cur_tp;
+ }
+ }
+ }
+
+ /* try to sample up to half of the availble rates during each interval */
+ mi->sample_count *= 4;
+
+ cur_prob = 0;
+ cur_prob_tp = 0;
+ cur_tp = 0;
+ cur_tp2 = 0;
+ for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) {
+ mg = &mi->groups[group];
+ if (!mg->supported)
+ continue;
+
+ mr = minstrel_get_ratestats(mi, mg->max_prob_rate);
+ if (cur_prob_tp < mr->cur_tp &&
+ minstrel_mcs_groups[group].streams == 1) {
+ mi->max_prob_rate = mg->max_prob_rate;
+ cur_prob = mr->cur_prob;
+ }
+
+ mr = minstrel_get_ratestats(mi, mg->max_tp_rate);
+ if (cur_tp < mr->cur_tp) {
+ mi->max_tp_rate = mg->max_tp_rate;
+ cur_tp = mr->cur_tp;
+ }
+
+ mr = minstrel_get_ratestats(mi, mg->max_tp_rate2);
+ if (cur_tp2 < mr->cur_tp) {
+ mi->max_tp_rate2 = mg->max_tp_rate2;
+ cur_tp2 = mr->cur_tp;
+ }
+ }
+
+ mi->stats_update = jiffies;
+}
+
+static bool
+minstrel_ht_txstat_valid(struct ieee80211_tx_rate *rate)
+{
+ if (!rate->count)
+ return false;
+
+ if (rate->idx < 0)
+ return false;
+
+ return !!(rate->flags & IEEE80211_TX_RC_MCS);
+}
+
+static void
+minstrel_next_sample_idx(struct minstrel_ht_sta *mi)
+{
+ struct minstrel_mcs_group_data *mg;
+
+ for (;;) {
+ mi->sample_group++;
+ mi->sample_group %= ARRAY_SIZE(minstrel_mcs_groups);
+ mg = &mi->groups[mi->sample_group];
+
+ if (!mg->supported)
+ continue;
+
+ if (++mg->index >= MCS_GROUP_RATES) {
+ mg->index = 0;
+ if (++mg->column >= ARRAY_SIZE(sample_table))
+ mg->column = 0;
+ }
+ break;
+ }
+}
+
+static void
+minstrel_downgrade_rate(struct minstrel_ht_sta *mi, int *idx, bool primary)
+{
+ int group, orig_group;
+
+ orig_group = group = *idx / MCS_GROUP_RATES;
+ while (group > 0) {
+ group--;
+
+ if (!mi->groups[group].supported)
+ continue;
+
+ if (minstrel_mcs_groups[group].streams >
+ minstrel_mcs_groups[orig_group].streams)
+ continue;
+
+ if (primary)
+ *idx = mi->groups[group].max_tp_rate;
+ else
+ *idx = mi->groups[group].max_tp_rate2;
+ break;
+ }
+}
+
+static void
+minstrel_aggr_check(struct minstrel_priv *mp, struct ieee80211_sta *pubsta, struct sk_buff *skb)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
+ u16 tid;
+
+ if (unlikely(!ieee80211_is_data_qos(hdr->frame_control)))
+ return;
+
+ if (unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE)))
+ return;
+
+ tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
+ if (likely(sta->ampdu_mlme.tid_state_tx[tid] != HT_AGG_STATE_IDLE))
+ return;
+
+ ieee80211_start_tx_ba_session(pubsta, tid);
+}
+
+static void
+minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
+ struct ieee80211_sta *sta, void *priv_sta,
+ struct sk_buff *skb)
+{
+ struct minstrel_ht_sta_priv *msp = priv_sta;
+ struct minstrel_ht_sta *mi = &msp->ht;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_tx_rate *ar = info->status.rates;
+ struct minstrel_rate_stats *rate, *rate2;
+ struct minstrel_priv *mp = priv;
+ bool last = false;
+ int group;
+ int i = 0;
+
+ if (!msp->is_ht)
+ return mac80211_minstrel.tx_status(priv, sband, sta, &msp->legacy, skb);
+
+ /* This packet was aggregated but doesn't carry status info */
+ if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
+ !(info->flags & IEEE80211_TX_STAT_AMPDU))
+ return;
+
+ if (!info->status.ampdu_len) {
+ info->status.ampdu_ack_len = 1;
+ info->status.ampdu_len = 1;
+ }
+
+ mi->ampdu_packets++;
+ mi->ampdu_len += info->status.ampdu_len;
+
+ if (!mi->sample_wait && !mi->sample_tries && mi->sample_count > 0) {
+ mi->sample_wait = 4 + 2 * MINSTREL_TRUNC(mi->avg_ampdu_len);
+ mi->sample_tries = 3;
+ mi->sample_count--;
+ }
+
+ if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) {
+ mi->sample_packets += info->status.ampdu_len;
+ minstrel_next_sample_idx(mi);
+ }
+
+ for (i = 0; !last; i++) {
+ last = (i == IEEE80211_TX_MAX_RATES - 1) ||
+ !minstrel_ht_txstat_valid(&ar[i + 1]);
+
+ if (!minstrel_ht_txstat_valid(&ar[i]))
+ break;
+
+ group = minstrel_ht_get_group_idx(&ar[i]);
+ rate = &mi->groups[group].rates[ar[i].idx % 8];
+
+ if (last && (info->flags & IEEE80211_TX_STAT_ACK))
+ rate->success += info->status.ampdu_ack_len;
+
+ rate->attempts += ar[i].count * info->status.ampdu_len;
+ }
+
+ /*
+ * check for sudden death of spatial multiplexing,
+ * downgrade to a lower number of streams if necessary.
+ */
+ rate = minstrel_get_ratestats(mi, mi->max_tp_rate);
+ if (rate->attempts > 30 &&
+ MINSTREL_FRAC(rate->success, rate->attempts) <
+ MINSTREL_FRAC(20, 100))
+ minstrel_downgrade_rate(mi, &mi->max_tp_rate, true);
+
+ rate2 = minstrel_get_ratestats(mi, mi->max_tp_rate2);
+ if (rate->attempts > 30 &&
+ MINSTREL_FRAC(rate->success, rate->attempts) <
+ MINSTREL_FRAC(20, 100))
+ minstrel_downgrade_rate(mi, &mi->max_tp_rate2, false);
+
+ if (time_after(jiffies, mi->stats_update + (mp->update_interval / 2 * HZ) / 1000)) {
+ minstrel_ht_update_stats(mp, mi);
+ minstrel_aggr_check(mp, sta, skb);
+ }
+}
+
+static void
+minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
+ int index)
+{
+ struct minstrel_rate_stats *mr;
+ const struct mcs_group *group;
+ unsigned int tx_time, tx_time_rtscts, tx_time_data;
+ unsigned int cw = mp->cw_min;
+ unsigned int t_slot = 9; /* FIXME */
+ unsigned int ampdu_len = MINSTREL_TRUNC(mi->avg_ampdu_len);
+
+ mr = minstrel_get_ratestats(mi, index);
+ if (mr->probability < MINSTREL_FRAC(1, 10)) {
+ mr->retry_count = 1;
+ mr->retry_count_rtscts = 1;
+ return;
+ }
+
+ mr->retry_count = 2;
+ mr->retry_count_rtscts = 2;
+ mr->retry_updated = true;
+
+ group = &minstrel_mcs_groups[index / MCS_GROUP_RATES];
+ tx_time_data = group->duration[index % MCS_GROUP_RATES] * ampdu_len;
+ tx_time = 2 * (t_slot + mi->overhead + tx_time_data);
+ tx_time_rtscts = 2 * (t_slot + mi->overhead_rtscts + tx_time_data);
+ do {
+ cw = (cw << 1) | 1;
+ cw = min(cw, mp->cw_max);
+ tx_time += cw + t_slot + mi->overhead;
+ tx_time_rtscts += cw + t_slot + mi->overhead_rtscts;
+ if (tx_time_rtscts < mp->segment_size)
+ mr->retry_count_rtscts++;
+ } while ((tx_time < mp->segment_size) &&
+ (++mr->retry_count < mp->max_retry));
+}
+
+
+static void
+minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
+ struct ieee80211_tx_rate *rate, int index,
+ struct ieee80211_tx_rate_control *txrc,
+ bool sample, bool rtscts)
+{
+ const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES];
+ struct minstrel_rate_stats *mr;
+
+ mr = minstrel_get_ratestats(mi, index);
+ if (!mr->retry_updated)
+ minstrel_calc_retransmit(mp, mi, index);
+
+ if (mr->probability < MINSTREL_FRAC(20, 100))
+ rate->count = 2;
+ else if (rtscts)
+ rate->count = mr->retry_count_rtscts;
+ else
+ rate->count = mr->retry_count;
+
+ rate->flags = IEEE80211_TX_RC_MCS | group->flags;
+ if (txrc->short_preamble)
+ rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE;
+ if (txrc->rts || rtscts)
+ rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS;
+ rate->idx = index % MCS_GROUP_RATES + (group->streams - 1) * MCS_GROUP_RATES;
+}
+
+static inline int
+minstrel_get_duration(int index)
+{
+ const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES];
+ return group->duration[index % MCS_GROUP_RATES];
+}
+
+static int
+minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
+{
+ struct minstrel_rate_stats *mr;
+ struct minstrel_mcs_group_data *mg;
+ int sample_idx = 0;
+
+ if (mi->sample_wait > 0) {
+ mi->sample_wait--;
+ return -1;
+ }
+
+ if (!mi->sample_tries)
+ return -1;
+
+ mi->sample_tries--;
+ mg = &mi->groups[mi->sample_group];
+ sample_idx = sample_table[mg->column][mg->index];
+ mr = &mg->rates[sample_idx];
+ sample_idx += mi->sample_group * MCS_GROUP_RATES;
+
+ /*
+ * When not using MRR, do not sample if the probability is already
+ * higher than 95% to avoid wasting airtime
+ */
+ if (!mp->has_mrr && (mr->probability > MINSTREL_FRAC(95, 100)))
+ goto next;
+
+ /*
+ * Make sure that lower rates get sampled only occasionally,
+ * if the link is working perfectly.
+ */
+ if (minstrel_get_duration(sample_idx) >
+ minstrel_get_duration(mi->max_tp_rate)) {
+ if (mr->sample_skipped < 10)
+ goto next;
+
+ if (mi->sample_slow++ > 2)
+ goto next;
+ }
+
+ return sample_idx;
+
+next:
+ minstrel_next_sample_idx(mi);
+ return -1;
+}
+
+static void
+minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
+ struct ieee80211_tx_rate_control *txrc)
+{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb);
+ struct ieee80211_tx_rate *ar = info->status.rates;
+ struct minstrel_ht_sta_priv *msp = priv_sta;
+ struct minstrel_ht_sta *mi = &msp->ht;
+ struct minstrel_priv *mp = priv;
+ int sample_idx;
+
+ if (rate_control_send_low(sta, priv_sta, txrc))
+ return;
+
+ if (!msp->is_ht)
+ return mac80211_minstrel.get_rate(priv, sta, &msp->legacy, txrc);
+
+ info->flags |= mi->tx_flags;
+ sample_idx = minstrel_get_sample_rate(mp, mi);
+ if (sample_idx >= 0) {
+ minstrel_ht_set_rate(mp, mi, &ar[0], sample_idx,
+ txrc, true, false);
+ minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_tp_rate,
+ txrc, false, true);
+ info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
+ } else {
+ minstrel_ht_set_rate(mp, mi, &ar[0], mi->max_tp_rate,
+ txrc, false, false);
+ minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_tp_rate2,
+ txrc, false, true);
+ }
+ minstrel_ht_set_rate(mp, mi, &ar[2], mi->max_prob_rate, txrc, false, true);
+
+ ar[3].count = 0;
+ ar[3].idx = -1;
+
+ mi->total_packets++;
+
+ /* wraparound */
+ if (mi->total_packets == ~0) {
+ mi->total_packets = 0;
+ mi->sample_packets = 0;
+ }
+}
+
+static void
+minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband,
+ struct ieee80211_sta *sta, void *priv_sta,
+ enum nl80211_channel_type oper_chan_type)
+{
+ struct minstrel_priv *mp = priv;
+ struct minstrel_ht_sta_priv *msp = priv_sta;
+ struct minstrel_ht_sta *mi = &msp->ht;
+ struct ieee80211_mcs_info *mcs = &sta->ht_cap.mcs;
+ struct ieee80211_local *local = hw_to_local(mp->hw);
+ u16 sta_cap = sta->ht_cap.cap;
+ int ack_dur;
+ int stbc;
+ int i;
+
+ /* fall back to the old minstrel for legacy stations */
+ if (sta && !sta->ht_cap.ht_supported) {
+ msp->is_ht = false;
+ memset(&msp->legacy, 0, sizeof(msp->legacy));
+ msp->legacy.r = msp->ratelist;
+ msp->legacy.sample_table = msp->sample_table;
+ return mac80211_minstrel.rate_init(priv, sband, sta, &msp->legacy);
+ }
+
+ BUILD_BUG_ON(ARRAY_SIZE(minstrel_mcs_groups) !=
+ MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS);
+
+ msp->is_ht = true;
+ memset(mi, 0, sizeof(*mi));
+ mi->stats_update = jiffies;
+
+ ack_dur = ieee80211_frame_duration(local, 10, 60, 1, 1);
+ mi->overhead = ieee80211_frame_duration(local, 0, 60, 1, 1) + ack_dur;
+ mi->overhead_rtscts = mi->overhead + 2 * ack_dur;
+
+ mi->avg_ampdu_len = MINSTREL_FRAC(1, 1);
+
+ /* When using MRR, sample more on the first attempt, without delay */
+ if (mp->has_mrr) {
+ mi->sample_count = 16;
+ mi->sample_wait = 0;
+ } else {
+ mi->sample_count = 8;
+ mi->sample_wait = 8;
+ }
+ mi->sample_tries = 4;
+
+ stbc = (sta_cap & IEEE80211_HT_CAP_RX_STBC) >>
+ IEEE80211_HT_CAP_RX_STBC_SHIFT;
+ mi->tx_flags |= stbc << IEEE80211_TX_CTL_STBC_SHIFT;
+
+ if (sta_cap & IEEE80211_HT_CAP_LDPC_CODING)
+ mi->tx_flags |= IEEE80211_TX_CTL_LDPC;
+
+ if (oper_chan_type != NL80211_CHAN_HT40MINUS &&
+ oper_chan_type != NL80211_CHAN_HT40PLUS)
+ sta_cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+
+ for (i = 0; i < ARRAY_SIZE(mi->groups); i++) {
+ u16 req = 0;
+
+ mi->groups[i].supported = 0;
+ if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_SHORT_GI) {
+ if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+ req |= IEEE80211_HT_CAP_SGI_40;
+ else
+ req |= IEEE80211_HT_CAP_SGI_20;
+ }
+
+ if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+ req |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+
+ if ((sta_cap & req) != req)
+ continue;
+
+ mi->groups[i].supported =
+ mcs->rx_mask[minstrel_mcs_groups[i].streams - 1];
+ }
+}
+
+static void
+minstrel_ht_rate_init(void *priv, struct ieee80211_supported_band *sband,
+ struct ieee80211_sta *sta, void *priv_sta)
+{
+ struct minstrel_priv *mp = priv;
+
+ minstrel_ht_update_caps(priv, sband, sta, priv_sta, mp->hw->conf.channel_type);
+}
+
+static void
+minstrel_ht_rate_update(void *priv, struct ieee80211_supported_band *sband,
+ struct ieee80211_sta *sta, void *priv_sta,
+ u32 changed, enum nl80211_channel_type oper_chan_type)
+{
+ minstrel_ht_update_caps(priv, sband, sta, priv_sta, oper_chan_type);
+}
+
+static void *
+minstrel_ht_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp)
+{
+ struct ieee80211_supported_band *sband;
+ struct minstrel_ht_sta_priv *msp;
+ struct minstrel_priv *mp = priv;
+ struct ieee80211_hw *hw = mp->hw;
+ int max_rates = 0;
+ int i;
+
+ for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
+ sband = hw->wiphy->bands[i];
+ if (sband && sband->n_bitrates > max_rates)
+ max_rates = sband->n_bitrates;
+ }
+
+ msp = kzalloc(sizeof(struct minstrel_ht_sta), gfp);
+ if (!msp)
+ return NULL;
+
+ msp->ratelist = kzalloc(sizeof(struct minstrel_rate) * max_rates, gfp);
+ if (!msp->ratelist)
+ goto error;
+
+ msp->sample_table = kmalloc(SAMPLE_COLUMNS * max_rates, gfp);
+ if (!msp->sample_table)
+ goto error1;
+
+ return msp;
+
+error1:
+ kfree(msp->sample_table);
+error:
+ kfree(msp);
+ return NULL;
+}
+
+static void
+minstrel_ht_free_sta(void *priv, struct ieee80211_sta *sta, void *priv_sta)
+{
+ struct minstrel_ht_sta_priv *msp = priv_sta;
+
+ kfree(msp->sample_table);
+ kfree(msp->ratelist);
+ kfree(msp);
+}
+
+static void *
+minstrel_ht_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
+{
+ return mac80211_minstrel.alloc(hw, debugfsdir);
+}
+
+static void
+minstrel_ht_free(void *priv)
+{
+ mac80211_minstrel.free(priv);
+}
+
+static struct rate_control_ops mac80211_minstrel_ht = {
+ .name = "minstrel_ht",
+ .tx_status = minstrel_ht_tx_status,
+ .get_rate = minstrel_ht_get_rate,
+ .rate_init = minstrel_ht_rate_init,
+ .rate_update = minstrel_ht_rate_update,
+ .alloc_sta = minstrel_ht_alloc_sta,
+ .free_sta = minstrel_ht_free_sta,
+ .alloc = minstrel_ht_alloc,
+ .free = minstrel_ht_free,
+#ifdef CONFIG_MAC80211_DEBUGFS
+ .add_sta_debugfs = minstrel_ht_add_sta_debugfs,
+ .remove_sta_debugfs = minstrel_ht_remove_sta_debugfs,
+#endif
+};
+
+
+static void
+init_sample_table(void)
+{
+ int col, i, new_idx;
+ u8 rnd[MCS_GROUP_RATES];
+
+ memset(sample_table, 0xff, sizeof(sample_table));
+ for (col = 0; col < SAMPLE_COLUMNS; col++) {
+ for (i = 0; i < MCS_GROUP_RATES; i++) {
+ get_random_bytes(rnd, sizeof(rnd));
+ new_idx = (i + rnd[i]) % MCS_GROUP_RATES;
+
+ while (sample_table[col][new_idx] != 0xff)
+ new_idx = (new_idx + 1) % MCS_GROUP_RATES;
+
+ sample_table[col][new_idx] = i;
+ }
+ }
+}
+
+int __init
+rc80211_minstrel_ht_init(void)
+{
+ init_sample_table();
+ return ieee80211_rate_control_register(&mac80211_minstrel_ht);
+}
+
+void
+rc80211_minstrel_ht_exit(void)
+{
+ ieee80211_rate_control_unregister(&mac80211_minstrel_ht);
+}
--- /dev/null
+++ b/net/mac80211/rc80211_minstrel_ht.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2010 Felix Fietkau <nbd@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __RC_MINSTREL_HT_H
+#define __RC_MINSTREL_HT_H
+
+/*
+ * The number of streams can be changed to 2 to reduce code
+ * size and memory footprint.
+ */
+#define MINSTREL_MAX_STREAMS 3
+#define MINSTREL_STREAM_GROUPS 4
+
+/* scaled fraction values */
+#define MINSTREL_SCALE 16
+#define MINSTREL_FRAC(val, div) (((val) << MINSTREL_SCALE) / div)
+#define MINSTREL_TRUNC(val) ((val) >> MINSTREL_SCALE)
+
+#define MCS_GROUP_RATES 8
+
+struct mcs_group {
+ u32 flags;
+ unsigned int streams;
+ unsigned int duration[MCS_GROUP_RATES];
+};
+
+struct minstrel_rate_stats {
+ /* current / last sampling period attempts/success counters */
+ unsigned int attempts, last_attempts;
+ unsigned int success, last_success;
+
+ /* total attempts/success counters */
+ u64 att_hist, succ_hist;
+
+ /* current throughput */
+ unsigned int cur_tp;
+
+ /* packet delivery probabilities */
+ unsigned int cur_prob, probability;
+
+ /* maximum retry counts */
+ unsigned int retry_count;
+ unsigned int retry_count_rtscts;
+
+ bool retry_updated;
+ u8 sample_skipped;
+};
+
+struct minstrel_mcs_group_data {
+ u8 index;
+ u8 column;
+
+ /* bitfield of supported MCS rates of this group */
+ u8 supported;
+
+ /* selected primary rates */
+ unsigned int max_tp_rate;
+ unsigned int max_tp_rate2;
+ unsigned int max_prob_rate;
+
+ /* MCS rate statistics */
+ struct minstrel_rate_stats rates[MCS_GROUP_RATES];
+};
+
+struct minstrel_ht_sta {
+ /* ampdu length (average, per sampling interval) */
+ unsigned int ampdu_len;
+ unsigned int ampdu_packets;
+
+ /* ampdu length (EWMA) */
+ unsigned int avg_ampdu_len;
+
+ /* best throughput rate */
+ unsigned int max_tp_rate;
+
+ /* second best throughput rate */
+ unsigned int max_tp_rate2;
+
+ /* best probability rate */
+ unsigned int max_prob_rate;
+
+ /* time of last status update */
+ unsigned long stats_update;
+
+ /* overhead time in usec for each frame */
+ unsigned int overhead;
+ unsigned int overhead_rtscts;
+
+ unsigned int total_packets;
+ unsigned int sample_packets;
+
+ /* tx flags to add for frames for this sta */
+ u32 tx_flags;
+
+ u8 sample_wait;
+ u8 sample_tries;
+ u8 sample_count;
+ u8 sample_slow;
+
+ /* current MCS group to be sampled */
+ u8 sample_group;
+
+ /* MCS rate group info and statistics */
+ struct minstrel_mcs_group_data groups[MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS];
+};
+
+struct minstrel_ht_sta_priv {
+ union {
+ struct minstrel_ht_sta ht;
+ struct minstrel_sta_info legacy;
+ };
+#ifdef CONFIG_MAC80211_DEBUGFS
+ struct dentry *dbg_stats;
+#endif
+ void *ratelist;
+ void *sample_table;
+ bool is_ht;
+};
+
+void minstrel_ht_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir);
+void minstrel_ht_remove_sta_debugfs(void *priv, void *priv_sta);
+
+#endif
--- /dev/null
+++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2010 Felix Fietkau <nbd@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/netdevice.h>
+#include <linux/types.h>
+#include <linux/skbuff.h>
+#include <linux/debugfs.h>
+#include <linux/ieee80211.h>
+#include <net/mac80211.h>
+#include "rc80211_minstrel.h"
+#include "rc80211_minstrel_ht.h"
+
+extern const struct mcs_group minstrel_mcs_groups[];
+
+static int
+minstrel_ht_stats_open(struct inode *inode, struct file *file)
+{
+ struct minstrel_ht_sta_priv *msp = inode->i_private;
+ struct minstrel_ht_sta *mi = &msp->ht;
+ struct minstrel_debugfs_info *ms;
+ unsigned int i, j, tp, prob, eprob;
+ char *p;
+ int ret;
+
+ if (!msp->is_ht) {
+ inode->i_private = &msp->legacy;
+ ret = minstrel_stats_open(inode, file);
+ inode->i_private = msp;
+ return ret;
+ }
+
+ ms = kmalloc(sizeof(*ms) + 8192, GFP_KERNEL);
+ if (!ms)
+ return -ENOMEM;
+
+ file->private_data = ms;
+ p = ms->buf;
+ p += sprintf(p, "type rate throughput ewma prob this prob "
+ "this succ/attempt success attempts\n");
+ for (i = 0; i < MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS; i++) {
+ char htmode = '2';
+ char gimode = 'L';
+
+ if (!mi->groups[i].supported)
+ continue;
+
+ if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+ htmode = '4';
+ if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_SHORT_GI)
+ gimode = 'S';
+
+ for (j = 0; j < MCS_GROUP_RATES; j++) {
+ struct minstrel_rate_stats *mr = &mi->groups[i].rates[j];
+ int idx = i * MCS_GROUP_RATES + j;
+
+ if (!(mi->groups[i].supported & BIT(j)))
+ continue;
+
+ p += sprintf(p, "HT%c0/%cGI ", htmode, gimode);
+
+ *(p++) = (idx == mi->max_tp_rate) ? 'T' : ' ';
+ *(p++) = (idx == mi->max_tp_rate2) ? 't' : ' ';
+ *(p++) = (idx == mi->max_prob_rate) ? 'P' : ' ';
+ p += sprintf(p, "MCS%-2u", (minstrel_mcs_groups[i].streams - 1) *
+ MCS_GROUP_RATES + j);
+
+ tp = mr->cur_tp / 10;
+ prob = MINSTREL_TRUNC(mr->cur_prob * 1000);
+ eprob = MINSTREL_TRUNC(mr->probability * 1000);
+
+ p += sprintf(p, " %6u.%1u %6u.%1u %6u.%1u "
+ "%3u(%3u) %8llu %8llu\n",
+ tp / 10, tp % 10,
+ eprob / 10, eprob % 10,
+ prob / 10, prob % 10,
+ mr->last_success,
+ mr->last_attempts,
+ (unsigned long long)mr->succ_hist,
+ (unsigned long long)mr->att_hist);
+ }
+ }
+ p += sprintf(p, "\nTotal packet count:: ideal %d "
+ "lookaround %d\n",
+ max(0, (int) mi->total_packets - (int) mi->sample_packets),
+ mi->sample_packets);
+ p += sprintf(p, "Average A-MPDU length: %d.%d\n",
+ MINSTREL_TRUNC(mi->avg_ampdu_len),
+ MINSTREL_TRUNC(mi->avg_ampdu_len * 10) % 10);
+ ms->len = p - ms->buf;
+
+ return 0;
+}
+
+static const struct file_operations minstrel_ht_stat_fops = {
+ .owner = THIS_MODULE,
+ .open = minstrel_ht_stats_open,
+ .read = minstrel_stats_read,
+ .release = minstrel_stats_release,
+};
+
+void
+minstrel_ht_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir)
+{
+ struct minstrel_ht_sta_priv *msp = priv_sta;
+
+ msp->dbg_stats = debugfs_create_file("rc_stats", S_IRUGO, dir, msp,
+ &minstrel_ht_stat_fops);
+}
+
+void
+minstrel_ht_remove_sta_debugfs(void *priv, void *priv_sta)
+{
+ struct minstrel_ht_sta_priv *msp = priv_sta;
+
+ debugfs_remove(msp->dbg_stats);
+}
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -33,6 +33,13 @@ config MAC80211_RC_MINSTREL
---help---
This option enables the 'minstrel' TX rate control algorithm
+config MAC80211_RC_MINSTREL_HT
+ bool "Minstrel 802.11n support" if EMBEDDED
+ depends on MAC80211_RC_MINSTREL
+ default y
+ ---help---
+ This option enables the 'minstrel_ht' TX rate control algorithm
+
choice
prompt "Default rate control algorithm"
depends on MAC80211_HAS_RC
^ permalink raw reply
* compat-wireless 2010-05-12 is crashing
From: Joshua Smith @ 2010-05-13 15:43 UTC (permalink / raw)
To: linux-wireless
When I connect any rt2x00 device, I'm getting this crash:
usb 1-1.6: new high speed USB device using ehci_hcd and address 5
usb 1-1.6: configuration #1 chosen from 1 choice
Generic kernel compatibility enabled based on linux-next next-20100113
cfg80211: Calling CRDA to update world regulatory domain
cfg80211: World regulatory domain updated:
(start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp)
(2402000 KHz - 2472000 KHz @ 40000 KHz), (300 mBi, 2000 mBm)
(2457000 KHz - 2482000 KHz @ 20000 KHz), (300 mBi, 2000 mBm)
(2474000 KHz - 2494000 KHz @ 20000 KHz), (300 mBi, 2000 mBm)
(5170000 KHz - 5250000 KHz @ 40000 KHz), (300 mBi, 2000 mBm)
(5735000 KHz - 5835000 KHz @ 40000 KHz), (300 mBi, 2000 mBm)
phy0: Selected rate control algorithm 'minstrel'
BUG: unable to handle kernel NULL pointer dereference at 00000000
IP: [<00000000>]
*pde = 00000000
Oops: 0000 [#1] SMP
Modules linked in: arc4 ecb rt2800usb(+) rt2800lib rt2x00usb rt2x00lib led_class compat_firmware_class mac80211 cfg80211 rfkill_backport compat crc_ccitt snd_seq_dummy snd_seq_oss snd_seq_midi_event snd_seq snd_seq_device snd_pcm_oss snd_mixer_oss pcmcia pcmcia_core agpgart ppdev lp parport_pc parport pcspkr psmouse sg snd_hda_intel snd_pcm snd_timer snd_page_alloc snd_hwdep snd soundcore e1000e evdev fuse aufs squashfs sqlzma unlzma [last unloaded: pcmcia_core]
Pid: 5340, comm: modprobe Not tainted (2.6.27.8 #1)
EIP: 0060:[<00000000>] EFLAGS: 00010286 CPU: 2
EIP is at 0x0
EAX: f5012000 EBX: f7146890 ECX: 00000000 EDX: 00000000
ESI: f7146800 EDI: f5084300 EBP: f5012000 ESP: f519bc54
DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068
Process modprobe (pid: 5340, ti=f519a000 task=f6abb100 task.ti=f519a000)
Stack: c067340f f5012160 00000282 00000292 f794ff60 00000000 00000000 00000000
00000000 00000000 00000000 00000000 000005dc f5012000 f5084300 ffffffff
00000010 c06738c9 00000000 00000000 ffffffff 00000000 c08eaa5c ffffffff
Call Trace:
[<c067340f>] rtnl_fill_ifinfo+0x2af/0x4a0
[<c06738c9>] rtmsg_ifinfo+0x69/0x100
[<c06739a4>] rtnetlink_event+0x44/0x60
[<c013ba50>] notifier_call_chain+0x30/0x60
[<c013baf7>] raw_notifier_call_chain+0x17/0x20
[<c066ad60>] register_netdevice+0x200/0x340
[<fa1a0030>] ieee80211_rx_mgmt_probe_resp+0xe0/0x170 [mac80211]
[<fa1a3aec>] ieee80211_setup_sdata+0x2c/0xf0 [mac80211]
[<fa1a424e>] ieee80211_if_add+0x47e/0x860 [mac80211]
[<c03ab109>] crypto_spawn_tfm+0x59/0xb0
[<fa1161aa>] crypto_ecb_init_tfm+0x1a/0x30 [ecb]
[<c01263db>] printk+0x1b/0x20
[<fa1a5a24>] ieee80211_init_rate_ctrl_alg+0xd4/0x1e0 [mac80211]
[<fa197b32>] ieee80211_register_hw+0x322/0x3b0 [mac80211]
[<fa11dc19>] rt2x00lib_probe_dev+0x2d9/0x390 [rt2x00lib]
[<fa067c83>] rt2x00usb_probe+0xb3/0x150 [rt2x00usb]
[<c05e8e67>] usb_match_one_id+0x27/0xb0
[<c05e9e1a>] usb_probe_interface+0x8a/0x130
[<c01b984f>] sysfs_create_link+0xf/0x20
[<c0435592>] driver_probe_device+0x82/0x180
[<c04356fc>] __driver_attach+0x6c/0x70
[<c0434d3b>] bus_for_each_dev+0x3b/0x60
[<c0435416>] driver_attach+0x16/0x20
[<c0435690>] __driver_attach+0x0/0x70
[<c0435271>] bus_add_driver+0x1a1/0x220
[<c04358fd>] driver_register+0x4d/0x120
[<c05e9451>] usb_register_driver+0x81/0x100
[<fa1283a0>] rt2800_config_erp+0x0/0x160 [rt2800lib]
[<f8d1c000>] rt2800usb_init+0x0/0x14 [rt2800usb]
[<c0101123>] _stext+0x33/0x160
[<c0146bb7>] sys_init_module+0x87/0x1b0
[<c01764d1>] sys_read+0x41/0x70
[<c0103262>] syscall_call+0x7/0xb
=======================
Code: Bad EIP value.
EIP: [<00000000>] 0x0 SS:ESP 0068:f519bc54
---[ end trace fbe1874eb5bb9481 ]---
Is this a known problem?
What other info would you like to help diagnose this?
-Joshua
^ permalink raw reply
* Strange ACK Behaviour with ath9k
From: Roberto Riggio @ 2010-05-13 16:04 UTC (permalink / raw)
To: linux-wireless
Hi,
I'm having a very strange behaviour between two sr71a (ath9k) cards
operating in monitor mode. I'm using the following patch to specify
the transmission rate frame by frame:
http://thread.gmane.org/gmane.linux.kernel.wireless.general/47441
However if I try to send some traffic between the two nodes with both
interfaces operating in monitor mode I can see from a third machine
using wireshark that albeit the frame is sent and the corresponding
ack generated, the originator seems to ignore the ACK and keepts
retransmitting the frame. This is happening on both ends of the
communication (i'm ping one node from the other).
As a matter of fact i thought that ACK are handled directly by the
firmware. Any hints?
R.
^ permalink raw reply
* [PATCH 0/2] ath9k: bb watchdog events for AR9003
From: Luis R. Rodriguez @ 2010-05-13 17:33 UTC (permalink / raw)
To: linville; +Cc: linux-wireless, Luis R. Rodriguez
These two patches enable the baseband watchdog events for the
AR9003 family. One touches the hardware code, the other patch
enables this on the driver core.
Luis R. Rodriguez (2):
ath9k_hw: add support for the AR9003 baseband watchdog
ath9k: enable the baseband watchdog events for AR9003
drivers/net/wireless/ath/ath9k/ar9003_mac.c | 5 +
drivers/net/wireless/ath/ath9k/ar9003_mac.h | 1 +
drivers/net/wireless/ath/ath9k/ar9003_phy.c | 119 +++++++++++++++++++++++++++
drivers/net/wireless/ath/ath9k/ar9003_phy.h | 66 ++++++++--------
drivers/net/wireless/ath/ath9k/debug.c | 5 +
drivers/net/wireless/ath/ath9k/debug.h | 2 +
drivers/net/wireless/ath/ath9k/hw.c | 2 +
drivers/net/wireless/ath/ath9k/hw.h | 9 ++-
drivers/net/wireless/ath/ath9k/main.c | 10 ++-
drivers/net/wireless/ath/ath9k/reg.h | 1 +
10 files changed, 185 insertions(+), 35 deletions(-)
^ permalink raw reply
* Re: [PATCH] Fix AR9285 always turn off LED on HP mini 210 [1/1]
From: Luis R. Rodriguez @ 2010-05-13 17:52 UTC (permalink / raw)
To: Matt Chen
Cc: Luis Rodriguez, Joey Lee, Gary Lin, Greg Kroah-Hartman,
linux-net@vger.kernel.org, linux-wireless
In-Reply-To: <AANLkTikDcu0vDdThckqunFEa1bPzkfxhpwyql-wKdU8Z@mail.gmail.com>
On Thu, May 13, 2010 at 04:13:18AM -0700, Matt Chen wrote:
> Hi Luis,
> Tried the driver,compat-wireless-2.6.33.
> 2.tar.bz2, from http://wireless.kernel.org/en/users/Download/stable, it doesn't fix this issue. The LED is still keeping off whatever you enable/disable it.
2.6.33 is ancient now, try the compat-wireles 2.6.34-rc stuff and if
that doesn't help try bleeding edge. The fixes need to be addressed
on bleedinge edge *first* but if bleedinge edge already has a fix
then its a matter of cherry picking that and sending it to the stable
gods.
Luis
^ permalink raw reply
* [PATCH 1/2] ath9k: change beacon allocation to prefer the first beacon slot
From: Felix Fietkau @ 2010-05-13 18:37 UTC (permalink / raw)
To: linux-wireless; +Cc: lrodriguez, linville
This fixes IBSS beacon transmissions without VEOL enabled
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
drivers/net/wireless/ath/ath9k/beacon.c | 12 +++---------
1 files changed, 3 insertions(+), 9 deletions(-)
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index c8a4558..77face7 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -274,17 +274,11 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif)
avp->av_bslot = 0;
for (slot = 0; slot < ATH_BCBUF; slot++)
if (sc->beacon.bslot[slot] == NULL) {
- /*
- * XXX hack, space out slots to better
- * deal with misses
- */
- if (slot+1 < ATH_BCBUF &&
- sc->beacon.bslot[slot+1] == NULL) {
- avp->av_bslot = slot+1;
- break;
- }
avp->av_bslot = slot;
+
/* NB: keep looking for a double slot */
+ if (slot == 0 || !sc->beacon.bslot[slot-1])
+ break;
}
BUG_ON(sc->beacon.bslot[avp->av_bslot] != NULL);
sc->beacon.bslot[avp->av_bslot] = vif;
--
1.6.4.2
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox