From 5a6e59991b82580c3ca00115603b85762ec76104 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 10 May 2008 13:41:32 +0200 Subject: rt2x00: trim skb_frame_desc to 32 bytes Remove frame_type from skb_frame_desc and pass it as argument to rt2x00debug_dump_frame(). Change data_len and desc_len to unsigned short to save another 4 bytes in skb_frame_desc. Note that this was the only location where the data_len and desc_len was not yet treated as unsigned short. This trim is required to help mac80211 with adding the TX control and TX status informtation into the skb->cb structure. When that happens, drivers will have approximately 40 bytes left to use freely. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c index bfab3b8..bd92cb8 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/rt2x00/rt2x00debug.c @@ -115,7 +115,7 @@ struct rt2x00debug_intf { }; void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, - struct sk_buff *skb) + enum rt2x00_dump_type type, struct sk_buff *skb) { struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf; struct skb_frame_desc *desc = get_skb_frame_desc(skb); @@ -148,7 +148,7 @@ void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, 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_le32(rt2x00dev->chip.rev); - dump_hdr->type = cpu_to_le16(desc->frame_type); + dump_hdr->type = cpu_to_le16(type); dump_hdr->queue_index = desc->entry->queue->qid; dump_hdr->entry_index = desc->entry->entry_idx; dump_hdr->timestamp_sec = cpu_to_le32(timestamp.tv_sec); diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 3a49c25..ea130f2 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -28,7 +28,6 @@ #include "rt2x00.h" #include "rt2x00lib.h" -#include "rt2x00dump.h" /* * Link tuning handlers @@ -540,11 +539,9 @@ void rt2x00lib_txdone(struct queue_entry *entry, * If send to mac80211, mac80211 will clean up the skb structure, * otherwise we have to do it ourself. */ - skbdesc = get_skb_frame_desc(entry->skb); - skbdesc->frame_type = DUMP_FRAME_TXDONE; - - rt2x00debug_dump_frame(rt2x00dev, entry->skb); + rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TXDONE, entry->skb); + skbdesc = get_skb_frame_desc(entry->skb); if (!(skbdesc->flags & FRAME_DESC_DRIVER_GENERATED)) ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb, &tx_status); @@ -610,8 +607,7 @@ void rt2x00lib_rxdone(struct queue_entry *entry, * Send frame to mac80211 & debugfs. * mac80211 will clean up the skb structure. */ - get_skb_frame_desc(entry->skb)->frame_type = DUMP_FRAME_RXDONE; - rt2x00debug_dump_frame(rt2x00dev, entry->skb); + rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb); ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb, rx_status); entry->skb = NULL; } @@ -752,8 +748,7 @@ void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev, * frame to the device, but we are going to push the * frame to debugfs here. */ - skbdesc->frame_type = DUMP_FRAME_TX; - rt2x00debug_dump_frame(rt2x00dev, skb); + rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TX, skb); } EXPORT_SYMBOL_GPL(rt2x00lib_write_tx_desc); diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 41ee02c..c4ce534 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -26,6 +26,8 @@ #ifndef RT2X00LIB_H #define RT2X00LIB_H +#include "rt2x00dump.h" + /* * Interval defines * Both the link tuner as the rfkill will be called once per second. @@ -128,7 +130,8 @@ 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, struct sk_buff *skb); +void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, + enum rt2x00_dump_type type, struct sk_buff *skb); #else static inline void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) { @@ -139,6 +142,7 @@ 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) { } diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index d1707a7..c3493ed 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -109,7 +109,6 @@ enum skb_frame_desc_flags { * this structure should not exceed the size of that array (48 bytes). * * @flags: Frame flags, see &enum skb_frame_desc_flags. - * @frame_type: Frame type, see &enum rt2x00_dump_type. * @data: Pointer to data part of frame (Start of ieee80211 header). * @desc: Pointer to descriptor part of the frame. * Note that this pointer could point to something outside @@ -121,14 +120,12 @@ enum skb_frame_desc_flags { struct skb_frame_desc { unsigned int flags; - unsigned int frame_type; + unsigned short data_len; + unsigned short desc_len; void *data; void *desc; - unsigned int data_len; - unsigned int desc_len; - struct queue_entry *entry; }; -- cgit v0.10.2 From fb55f4d1fa252ba1e479284b79da1049d658c371 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 10 May 2008 13:42:06 +0200 Subject: rt2x00: Fix TX status reporting The tx_status enumeration was broken since the introduction of rt61pci. That driver uses different values to report the status of the tx action. This would lead to frames that were reported as success but actually failed to be send out, or frames that were neither successfull or failure which were reported as failure. Fix this by change the TX status reporting and more explicitely check for failure or success. Note that a third possibility is added "unknown". Not all hardware (USB) can report the actual TX status, for rt61pci some frames will receive this status because the TXdone handler is never called for those frames. This unknown will now be handled as neither success or failure, so we no longer increment the failure counter while this conclusion could not be determined from the real status of the frame. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index afa565c..69b1dbd 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1137,7 +1137,18 @@ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, /* * Obtain the status about this packet. */ - txdesc.status = rt2x00_get_field32(word, TXD_W0_RESULT); + txdesc.flags = 0; + switch (rt2x00_get_field32(word, TXD_W0_RESULT)) { + case 0: /* Success */ + case 1: /* Success with retry */ + __set_bit(TXDONE_SUCCESS, &txdesc.flags); + break; + case 2: /* Failure, excessive retries */ + __set_bit(TXDONE_EXCESSIVE_RETRY, &txdesc.flags); + /* Don't break, this is a failed frame! */ + default: /* Failure */ + __set_bit(TXDONE_FAILURE, &txdesc.flags); + } txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT); rt2x00pci_txdone(rt2x00dev, entry, &txdesc); diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index c06f1b5..aa195da 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1292,7 +1292,18 @@ static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev, /* * Obtain the status about this packet. */ - txdesc.status = rt2x00_get_field32(word, TXD_W0_RESULT); + txdesc.flags = 0; + switch (rt2x00_get_field32(word, TXD_W0_RESULT)) { + case 0: /* Success */ + case 1: /* Success with retry */ + __set_bit(TXDONE_SUCCESS, &txdesc.flags); + break; + case 2: /* Failure, excessive retries */ + __set_bit(TXDONE_EXCESSIVE_RETRY, &txdesc.flags); + /* Don't break, this is a failed frame! */ + default: /* Failure */ + __set_bit(TXDONE_FAILURE, &txdesc.flags); + } txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT); rt2x00pci_txdone(rt2x00dev, entry, &txdesc); diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index ea130f2..69da22c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -496,38 +496,36 @@ void rt2x00lib_txdone(struct queue_entry *entry, struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct skb_frame_desc *skbdesc; struct ieee80211_tx_status tx_status; - int success = !!(txdesc->status == TX_SUCCESS || - txdesc->status == TX_SUCCESS_RETRY); - int fail = !!(txdesc->status == TX_FAIL_RETRY || - txdesc->status == TX_FAIL_INVALID || - txdesc->status == TX_FAIL_OTHER); /* * Update TX statistics. */ - rt2x00dev->link.qual.tx_success += success; - rt2x00dev->link.qual.tx_failed += txdesc->retry + fail; + rt2x00dev->link.qual.tx_success += + test_bit(TXDONE_SUCCESS, &txdesc->flags); + rt2x00dev->link.qual.tx_failed += + txdesc->retry + !!test_bit(TXDONE_FAILURE, &txdesc->flags); /* * Initialize TX status */ tx_status.flags = 0; tx_status.ack_signal = 0; - tx_status.excessive_retries = (txdesc->status == TX_FAIL_RETRY); + tx_status.excessive_retries = + test_bit(TXDONE_EXCESSIVE_RETRY, &txdesc->flags); tx_status.retry_count = txdesc->retry; memcpy(&tx_status.control, txdesc->control, sizeof(*txdesc->control)); if (!(tx_status.control.flags & IEEE80211_TXCTL_NO_ACK)) { - if (success) + if (test_bit(TXDONE_SUCCESS, &txdesc->flags)) tx_status.flags |= IEEE80211_TX_STATUS_ACK; - else + else if (test_bit(TXDONE_FAILURE, &txdesc->flags)) rt2x00dev->low_level_stats.dot11ACKFailureCount++; } if (tx_status.control.flags & IEEE80211_TXCTL_USE_RTS_CTS) { - if (success) + if (test_bit(TXDONE_SUCCESS, &txdesc->flags)) rt2x00dev->low_level_stats.dot11RTSSuccessCount++; - else + else if (test_bit(TXDONE_FAILURE, &txdesc->flags)) rt2x00dev->low_level_stats.dot11RTSFailureCount++; } @@ -546,7 +544,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb, &tx_status); else - dev_kfree_skb(entry->skb); + dev_kfree_skb_irq(entry->skb); entry->skb = NULL; } EXPORT_SYMBOL_GPL(rt2x00lib_txdone); diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index c3493ed..f361f78 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -168,18 +168,34 @@ struct rxdone_entry_desc { }; /** + * enum txdone_entry_desc_flags: Flags for &struct txdone_entry_desc + * + * @TXDONE_UNKNOWN: Hardware could not determine success of transmission. + * @TXDONE_SUCCESS: Frame was successfully send + * @TXDONE_FAILURE: Frame was not successfully send + * @TXDONE_EXCESSIVE_RETRY: In addition to &TXDONE_FAILURE, the + * frame transmission failed due to excessive retries. + */ +enum txdone_entry_desc_flags { + TXDONE_UNKNOWN = 1 << 0, + TXDONE_SUCCESS = 1 << 1, + TXDONE_FAILURE = 1 << 2, + TXDONE_EXCESSIVE_RETRY = 1 << 3, +}; + +/** * struct txdone_entry_desc: TX done entry descriptor * * Summary of information that has been read from the TX frame descriptor * after the device is done with transmission. * * @control: Control structure which was used to transmit the frame. - * @status: TX status (See &enum tx_status). + * @flags: TX done flags (See &enum txdone_entry_desc_flags). * @retry: Retry count. */ struct txdone_entry_desc { struct ieee80211_tx_control *control; - int status; + unsigned long flags; int retry; }; diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h index 0325bed..3f255df 100644 --- a/drivers/net/wireless/rt2x00/rt2x00reg.h +++ b/drivers/net/wireless/rt2x00/rt2x00reg.h @@ -27,17 +27,6 @@ #define RT2X00REG_H /* - * TX result flags. - */ -enum tx_status { - TX_SUCCESS = 0, - TX_SUCCESS_RETRY = 1, - TX_FAIL_RETRY = 2, - TX_FAIL_INVALID = 3, - TX_FAIL_OTHER = 4, -}; - -/* * Antenna values */ enum antenna { diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 98aafc2..caee65e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -147,8 +147,17 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) /* * 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 + * was succesfully pushed to the hardware, we have no + * way to determine the transmission status right now. + * (Only indirectly by looking at the failed TX counters + * in the register). */ - txdesc.status = !urb->status ? TX_SUCCESS : TX_FAIL_RETRY; + if (!urb->status) + __set_bit(TXDONE_UNKNOWN, &txdesc.flags); + else + __set_bit(TXDONE_FAILURE, &txdesc.flags); txdesc.retry = 0; txdesc.control = &priv_tx->control; diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index edddbf3..15191d6 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1764,7 +1764,8 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev) "TX status report missed for entry %d\n", entry_done->entry_idx); - txdesc.status = TX_FAIL_OTHER; + txdesc.flags = 0; + __set_bit(TXDONE_UNKNOWN, &txdesc.flags); txdesc.retry = 0; rt2x00pci_txdone(rt2x00dev, entry_done, &txdesc); @@ -1774,7 +1775,17 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev) /* * Obtain the status about this packet. */ - txdesc.status = rt2x00_get_field32(reg, STA_CSR4_TX_RESULT); + txdesc.flags = 0; + switch (rt2x00_get_field32(reg, STA_CSR4_TX_RESULT)) { + case 0: /* Success, maybe with retry */ + __set_bit(TXDONE_SUCCESS, &txdesc.flags); + break; + case 6: /* Failure, excessive retries */ + __set_bit(TXDONE_EXCESSIVE_RETRY, &txdesc.flags); + /* Don't break, this is a failed frame! */ + default: /* Failure */ + __set_bit(TXDONE_FAILURE, &txdesc.flags); + } txdesc.retry = rt2x00_get_field32(reg, STA_CSR4_RETRY_COUNT); rt2x00pci_txdone(rt2x00dev, entry, &txdesc); -- cgit v0.10.2 From 61486e0f68d1f8966c09b734566a187d42d65c54 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 10 May 2008 13:42:31 +0200 Subject: rt2x00: Remove ieee80211_tx_control argument from write_tx_desc() Move the last remaining information details read from ieee80211_tx_control in the drivers to the txentry_desc structure. After this we can remove ieee80211_tx_control from the argument list for the callback function, which makes it easier when the control information is moved into skb->cb Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 69b1dbd..fb02d11 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1001,8 +1001,7 @@ static int rt2400pci_set_device_state(struct rt2x00_dev *rt2x00dev, */ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb, - struct txentry_desc *txdesc, - struct ieee80211_tx_control *control) + struct txentry_desc *txdesc) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); __le32 *txd = skbdesc->desc; @@ -1046,8 +1045,7 @@ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, test_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs); rt2x00_set_field32(&word, TXD_W0_RETRY_MODE, - !!(control->flags & - IEEE80211_TXCTL_LONG_RETRY_LIMIT)); ++ test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags)); rt2x00_desc_write(txd, 0, word); } diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index aa195da..1724ce9 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1155,8 +1155,7 @@ static int rt2500pci_set_device_state(struct rt2x00_dev *rt2x00dev, */ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb, - struct txentry_desc *txdesc, - struct ieee80211_tx_control *control) + struct txentry_desc *txdesc) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); __le32 *txd = skbdesc->desc; @@ -1198,9 +1197,7 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W0_CIPHER_OWNER, 1); rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs); rt2x00_set_field32(&word, TXD_W0_RETRY_MODE, - !!(control->flags & - IEEE80211_TXCTL_LONG_RETRY_LIMIT)); - rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skbdesc->data_len); + test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE); rt2x00_desc_write(txd, 0, word); } diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 88bafdf..7df06ec 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1033,8 +1033,7 @@ static int rt2500usb_set_device_state(struct rt2x00_dev *rt2x00dev, */ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb, - struct txentry_desc *txdesc, - struct ieee80211_tx_control *control) + struct txentry_desc *txdesc) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); __le32 *txd = skbdesc->desc; @@ -1058,7 +1057,7 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_desc_write(txd, 2, word); rt2x00_desc_read(txd, 0, &word); - rt2x00_set_field32(&word, TXD_W0_RETRY_LIMIT, control->retry_limit); + 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, @@ -1068,7 +1067,7 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W0_OFDM, test_bit(ENTRY_TXD_OFDM_RATE, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_NEW_SEQ, - !!(control->flags & IEEE80211_TXCTL_FIRST_FRAGMENT)); + 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, skbdesc->data_len); rt2x00_set_field32(&word, TXD_W0_CIPHER, CIPHER_NONE); diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 79bd9c9..6561484 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -540,8 +540,7 @@ struct rt2x00lib_ops { */ void (*write_tx_desc) (struct rt2x00_dev *rt2x00dev, struct sk_buff *skb, - struct txentry_desc *txdesc, - struct ieee80211_tx_control *control); + struct txentry_desc *txdesc); int (*write_tx_data) (struct rt2x00_dev *rt2x00dev, struct data_queue *queue, struct sk_buff *skb, struct ieee80211_tx_control *control); diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 69da22c..e1368f7 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -664,7 +664,12 @@ void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev, tx_rate = control->rts_cts_rate->hw_value; } - rate = rt2x00_get_rate(tx_rate); + /* + * Determine retry information. + */ + txdesc.retry_limit = control->retry_limit; + if (control->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT) + __set_bit(ENTRY_TXD_RETRY_MODE, &txdesc.flags); /* * Check if more fragments are pending @@ -686,16 +691,20 @@ void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev, * Set ifs to IFS_SIFS when the this is not the first fragment, * or this fragment came after RTS/CTS. */ - if ((seq_ctrl & IEEE80211_SCTL_FRAG) > 0 || - test_bit(ENTRY_TXD_RTS_FRAME, &txdesc.flags)) + if (test_bit(ENTRY_TXD_RTS_FRAME, &txdesc.flags)) { txdesc.ifs = IFS_SIFS; - else + } else if (control->flags & IEEE80211_TXCTL_FIRST_FRAGMENT) { + __set_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc.flags); txdesc.ifs = IFS_BACKOFF; + } else { + txdesc.ifs = IFS_SIFS; + } /* * PLCP setup * Length calculation depends on OFDM/CCK rate. */ + rate = rt2x00_get_rate(tx_rate); txdesc.signal = rate->plcp; txdesc.service = 0x04; @@ -733,7 +742,7 @@ void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev, txdesc.signal |= 0x08; } - rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, skb, &txdesc, control); + rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, skb, &txdesc); /* * Update queue entry. diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index f361f78..3f7cfa9 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -204,18 +204,22 @@ struct txdone_entry_desc { * * @ENTRY_TXD_RTS_FRAME: This frame is a RTS frame. * @ENTRY_TXD_OFDM_RATE: This frame is send out with an OFDM rate. + * @ENTRY_TXD_FIRST_FRAGMENT: This is the first frame. * @ENTRY_TXD_MORE_FRAG: This frame is followed by another fragment. * @ENTRY_TXD_REQ_TIMESTAMP: Require timestamp to be inserted. * @ENTRY_TXD_BURST: This frame belongs to the same burst event. * @ENTRY_TXD_ACK: An ACK is required for this frame. + * @ENTRY_TXD_RETRY_MODE: When set, the long retry count is used. */ enum txentry_desc_flags { ENTRY_TXD_RTS_FRAME, ENTRY_TXD_OFDM_RATE, + ENTRY_TXD_FIRST_FRAGMENT, ENTRY_TXD_MORE_FRAG, ENTRY_TXD_REQ_TIMESTAMP, ENTRY_TXD_BURST, ENTRY_TXD_ACK, + ENTRY_TXD_RETRY_MODE, }; /** @@ -229,6 +233,7 @@ enum txentry_desc_flags { * @length_low: PLCP length low word. * @signal: PLCP signal. * @service: PLCP service. + * @retry_limit: Max number of retries. * @aifs: AIFS value. * @ifs: IFS value. * @cw_min: cwmin value. @@ -244,10 +249,11 @@ struct txentry_desc { u16 signal; u16 service; - int aifs; - int ifs; - int cw_min; - int cw_max; + short retry_limit; + short aifs; + short ifs; + short cw_min; + short cw_max; }; /** diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 15191d6..5d690ee 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1526,8 +1526,7 @@ static int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev, */ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb, - struct txentry_desc *txdesc, - struct ieee80211_tx_control *control) + struct txentry_desc *txdesc) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); __le32 *txd = skbdesc->desc; @@ -1577,8 +1576,7 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, test_bit(ENTRY_TXD_OFDM_RATE, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs); rt2x00_set_field32(&word, TXD_W0_RETRY_MODE, - !!(control->flags & - IEEE80211_TXCTL_LONG_RETRY_LIMIT)); + test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0); rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skbdesc->data_len); rt2x00_set_field32(&word, TXD_W0_BURST, diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 51c5575..d98002c 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1255,8 +1255,7 @@ static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev, */ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb, - struct txentry_desc *txdesc, - struct ieee80211_tx_control *control) + struct txentry_desc *txdesc) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); __le32 *txd = skbdesc->desc; @@ -1301,8 +1300,7 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, test_bit(ENTRY_TXD_OFDM_RATE, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs); rt2x00_set_field32(&word, TXD_W0_RETRY_MODE, - !!(control->flags & - IEEE80211_TXCTL_LONG_RETRY_LIMIT)); + test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0); rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skbdesc->data_len); rt2x00_set_field32(&word, TXD_W0_BURST2, -- cgit v0.10.2 From 61448f88078e813bbaaa58eb775d650c85e7d407 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Sat, 10 May 2008 13:43:33 +0200 Subject: rt2x00: Fix queue related oops in case of deselected mac80211 multi-queue feature. With the integration of the mac80211 multiqueue patches it has become possible that the mac80211 layer modifies the number of TX queues that is stored inside the ieee80211_hw structure, especially when multi-queue is not selected. The rt2x00 drivers are not well suited to handle that situation, as they allocate the queue structures before mac80211 has modified the number of queues it is going to use, and also expect the number of allocated queues to match the hardware implementation. Hence, ensure that rt2x00 maintains by itself the number of queues that the hardware supports, and, at the same time, making is not dependent on the preservation of contents inside a mac80211 structure. Signed-off-by: Gertjan van Wingerde Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index fb02d11..b4310d7 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1373,7 +1373,6 @@ static void rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | IEEE80211_HW_SIGNAL_DBM; rt2x00dev->hw->extra_tx_headroom = 0; - rt2x00dev->hw->queues = 2; SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev); SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, @@ -1620,6 +1619,7 @@ static const struct rt2x00_ops rt2400pci_ops = { .max_ap_intf = 1, .eeprom_size = EEPROM_SIZE, .rf_size = RF_SIZE, + .tx_queues = NUM_TX_QUEUES, .rx = &rt2400pci_queue_rx, .tx = &rt2400pci_queue_tx, .bcn = &rt2400pci_queue_bcn, diff --git a/drivers/net/wireless/rt2x00/rt2400pci.h b/drivers/net/wireless/rt2x00/rt2400pci.h index a5210f9..e9aa326 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.h +++ b/drivers/net/wireless/rt2x00/rt2400pci.h @@ -52,6 +52,11 @@ #define RF_SIZE 0x0010 /* + * Number of TX queues. + */ +#define NUM_TX_QUEUES 2 + +/* * Control/Status Registers(CSR). * Some values are set in TU, whereas 1 TU == 1024 us. */ diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 1724ce9..54aaa83 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1692,7 +1692,6 @@ static void rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) IEEE80211_HW_SIGNAL_DBM; rt2x00dev->hw->extra_tx_headroom = 0; - rt2x00dev->hw->queues = 2; SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev); SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, @@ -1933,6 +1932,7 @@ static const struct rt2x00_ops rt2500pci_ops = { .max_ap_intf = 1, .eeprom_size = EEPROM_SIZE, .rf_size = RF_SIZE, + .tx_queues = NUM_TX_QUEUES, .rx = &rt2500pci_queue_rx, .tx = &rt2500pci_queue_tx, .bcn = &rt2500pci_queue_bcn, diff --git a/drivers/net/wireless/rt2x00/rt2500pci.h b/drivers/net/wireless/rt2x00/rt2500pci.h index 1389955..ea93b8f4 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.h +++ b/drivers/net/wireless/rt2x00/rt2500pci.h @@ -63,6 +63,11 @@ #define RF_SIZE 0x0014 /* + * Number of TX queues. + */ +#define NUM_TX_QUEUES 2 + +/* * Control/Status Registers(CSR). * Some values are set in TU, whereas 1 TU == 1024 us. */ diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 7df06ec..661cf3d 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1590,7 +1590,6 @@ static void rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) IEEE80211_HW_SIGNAL_DBM; rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE; - rt2x00dev->hw->queues = 2; SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev); SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, @@ -1826,6 +1825,7 @@ static const struct rt2x00_ops rt2500usb_ops = { .max_ap_intf = 1, .eeprom_size = EEPROM_SIZE, .rf_size = RF_SIZE, + .tx_queues = NUM_TX_QUEUES, .rx = &rt2500usb_queue_rx, .tx = &rt2500usb_queue_tx, .bcn = &rt2500usb_queue_bcn, diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h index a37a068..7d50098 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.h +++ b/drivers/net/wireless/rt2x00/rt2500usb.h @@ -63,6 +63,11 @@ #define RF_SIZE 0x0014 /* + * Number of TX queues. + */ +#define NUM_TX_QUEUES 2 + +/* * Control/Status Registers(CSR). * Some values are set in TU, whereas 1 TU == 1024 us. */ diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 6561484..6f7b34f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -591,6 +591,7 @@ struct rt2x00_ops { const unsigned int max_ap_intf; const unsigned int eeprom_size; const unsigned int rf_size; + const unsigned int tx_queues; const struct data_queue_desc *rx; const struct data_queue_desc *tx; const struct data_queue_desc *bcn; diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index e1368f7..46c3778 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -975,6 +975,11 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) return status; /* + * Initialize HW fields. + */ + rt2x00dev->hw->queues = rt2x00dev->ops->tx_queues; + + /* * Register HW. */ status = ieee80211_register_hw(rt2x00dev->hw); diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 767e0ff..c5cedb2 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -456,7 +456,7 @@ int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw, struct rt2x00_dev *rt2x00dev = hw->priv; unsigned int i; - for (i = 0; i < hw->queues; i++) { + for (i = 0; i < rt2x00dev->ops->tx_queues; i++) { stats[i].len = rt2x00dev->tx[i].length; stats[i].limit = rt2x00dev->tx[i].limit; stats[i].count = rt2x00dev->tx[i].count; diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index e5b861f..95f8dd3 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -34,7 +34,7 @@ struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev, { int atim = test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags); - if (queue < rt2x00dev->hw->queues && rt2x00dev->tx) + if (queue < rt2x00dev->ops->tx_queues && rt2x00dev->tx) return &rt2x00dev->tx[queue]; if (!rt2x00dev->bcn) @@ -255,11 +255,11 @@ int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev) /* * We need the following queues: * RX: 1 - * TX: hw->queues + * TX: ops->tx_queues * Beacon: 1 * Atim: 1 (if required) */ - rt2x00dev->data_queues = 2 + rt2x00dev->hw->queues + req_atim; + rt2x00dev->data_queues = 2 + rt2x00dev->ops->tx_queues + req_atim; queue = kzalloc(rt2x00dev->data_queues * sizeof(*queue), GFP_KERNEL); if (!queue) { @@ -272,7 +272,7 @@ int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev) */ rt2x00dev->rx = queue; rt2x00dev->tx = &queue[1]; - rt2x00dev->bcn = &queue[1 + rt2x00dev->hw->queues]; + rt2x00dev->bcn = &queue[1 + rt2x00dev->ops->tx_queues]; /* * Initialize queue parameters. diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 3f7cfa9..4bde98b 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -397,7 +397,7 @@ struct data_queue_desc { * the end of the TX queue array. */ #define tx_queue_end(__dev) \ - &(__dev)->tx[(__dev)->hw->queues] + &(__dev)->tx[(__dev)->ops->tx_queues] /** * queue_loop - Loop through the queues within a specific range (HELPER MACRO). diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 5d690ee..68d2216 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2257,7 +2257,6 @@ static void rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | IEEE80211_HW_SIGNAL_DBM; rt2x00dev->hw->extra_tx_headroom = 0; - rt2x00dev->hw->queues = 4; SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev); SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, @@ -2489,6 +2488,7 @@ static const struct rt2x00_ops rt61pci_ops = { .max_ap_intf = 4, .eeprom_size = EEPROM_SIZE, .rf_size = RF_SIZE, + .tx_queues = NUM_TX_QUEUES, .rx = &rt61pci_queue_rx, .tx = &rt61pci_queue_tx, .bcn = &rt61pci_queue_bcn, diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h index 3511bba..c5a04b9 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.h +++ b/drivers/net/wireless/rt2x00/rt61pci.h @@ -54,6 +54,11 @@ #define RF_SIZE 0x0014 /* + * Number of TX queues. + */ +#define NUM_TX_QUEUES 4 + +/* * PCI registers. */ diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index d98002c..2191d8b 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1831,7 +1831,6 @@ static void rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | IEEE80211_HW_SIGNAL_DBM; rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE; - rt2x00dev->hw->queues = 4; SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev); SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, @@ -2079,6 +2078,7 @@ static const struct rt2x00_ops rt73usb_ops = { .max_ap_intf = 4, .eeprom_size = EEPROM_SIZE, .rf_size = RF_SIZE, + .tx_queues = NUM_TX_QUEUES, .rx = &rt73usb_queue_rx, .tx = &rt73usb_queue_tx, .bcn = &rt73usb_queue_bcn, diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h index 06d6874..25cdcc9 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.h +++ b/drivers/net/wireless/rt2x00/rt73usb.h @@ -54,6 +54,11 @@ #define RF_SIZE 0x0014 /* + * Number of TX queues. + */ +#define NUM_TX_QUEUES 4 + +/* * USB registers. */ -- cgit v0.10.2 From 70a96109439cba0af0780ee1dc25ec7ed15f0bae Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 10 May 2008 13:43:38 +0200 Subject: rt2x00: Preserve descriptor information after memmove() Due to usage of memmove() in rt2x00usb the descriptor can become corrupted because it is being overwritten by the data part. Overall having the descriptor in front of the frame is a bad idea, we can however use the skb->cb array for this task, since that contains more then enough room to hold the entire descriptor and preserve the information long enough. After this we can also cleanup the alignment code a bit to make it work a bit more flexible to allow for all kinds of odd header lengths. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 661cf3d..3be4c7e 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1129,20 +1129,22 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry, __le32 *rxd = (__le32 *)(entry->skb->data + (priv_rx->urb->actual_length - entry->queue->desc_size)); - unsigned int offset = entry->queue->desc_size + 2; u32 word0; u32 word1; /* - * Copy descriptor to the available headroom inside the skbuffer. + * Copy descriptor to the skb->cb array, this has 2 benefits: + * 1) Each descriptor word is 4 byte aligned. + * 2) Descriptor is safe from moving of frame data in rt2x00usb. */ - skb_push(entry->skb, offset); - memcpy(entry->skb->data, rxd, entry->queue->desc_size); - rxd = (__le32 *)entry->skb->data; + skbdesc->desc_len = + min_t(u16, entry->queue->desc_size, sizeof(entry->skb->cb)); + memcpy(entry->skb->cb, rxd, skbdesc->desc_len); + skbdesc->desc = entry->skb->cb; + rxd = (__le32 *)skbdesc->desc; /* - * The descriptor is now aligned to 4 bytes and thus it is - * now safe to read it on all architectures. + * It is now safe to read the descriptor on all architectures. */ rt2x00_desc_read(rxd, 0, &word0); rt2x00_desc_read(rxd, 1, &word1); @@ -1173,16 +1175,9 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry, /* * Adjust the skb memory window to the frame boundaries. */ - skb_pull(entry->skb, offset); skb_trim(entry->skb, rxdesc->size); - - /* - * Set descriptor and data pointer. - */ skbdesc->data = entry->skb->data; skbdesc->data_len = rxdesc->size; - skbdesc->desc = rxd; - skbdesc->desc_len = entry->queue->desc_size; } /* diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index caee65e..f72b3d0 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -246,22 +246,35 @@ static struct sk_buff* rt2x00usb_alloc_rxskb(struct data_queue *queue) { struct sk_buff *skb; unsigned int frame_size; + unsigned int reserved_size; /* - * As alignment we use 2 and not NET_IP_ALIGN because we need - * to be sure we have 2 bytes room in the head. (NET_IP_ALIGN - * can be 0 on some hardware). We use these 2 bytes for frame - * alignment later, we assume that the chance that - * header_size % 4 == 2 is bigger then header_size % 2 == 0 - * and thus optimize alignment by reserving the 2 bytes in - * advance. + * The frame size includes descriptor size, because the + * hardware directly receive the frame into the skbuffer. */ frame_size = queue->data_size + queue->desc_size; - skb = dev_alloc_skb(queue->desc_size + frame_size + 2); + + /* + * For the allocation we should keep a few things in mind: + * 1) 4byte alignment of 802.11 payload + * + * For (1) we need at most 4 bytes to guarentee the correct + * alignment. We are going to optimize the fact that the chance + * that the 802.11 header_size % 4 == 2 is much bigger then + * anything else. However since we need to move the frame up + * to 3 bytes to the front, which means we need to preallocate + * 6 bytes. + */ + reserved_size = 6; + + /* + * Allocate skbuffer. + */ + skb = dev_alloc_skb(frame_size + reserved_size); if (!skb) return NULL; - skb_reserve(skb, queue->desc_size + 2); + skb_reserve(skb, reserved_size); skb_put(skb, frame_size); return skb; @@ -274,7 +287,8 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) struct sk_buff *skb; struct skb_frame_desc *skbdesc; struct rxdone_entry_desc rxdesc; - int header_size; + unsigned int header_size; + unsigned int align; if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || !test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) @@ -298,19 +312,29 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) memset(&rxdesc, 0, sizeof(rxdesc)); rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc); + header_size = ieee80211_get_hdrlen_from_skb(entry->skb); + /* * The data behind the ieee80211 header must be - * aligned on a 4 byte boundary. + * aligned on a 4 byte boundary. We already reserved + * 2 bytes for header_size % 4 == 2 optimization. + * To determine the number of bytes which the data + * should be moved to the left, we must add these + * 2 bytes to the header_size. */ - header_size = ieee80211_get_hdrlen_from_skb(entry->skb); - if (header_size % 4 == 0) { - skb_push(entry->skb, 2); - memmove(entry->skb->data, entry->skb->data + 2, - entry->skb->len - 2); - skbdesc->data = entry->skb->data; - skb_trim(entry->skb,entry->skb->len - 2); + align = (header_size + 2) % 4; + + if (align) { + skb_push(entry->skb, align); + /* Move entire frame in 1 command */ + memmove(entry->skb->data, entry->skb->data + align, + rxdesc.size); } + /* Update data pointers, trim buffer to correct size */ + skbdesc->data = entry->skb->data; + skb_trim(entry->skb, rxdesc.size); + /* * Allocate a new sk buffer to replace the current one. * If allocation fails, we should drop the current frame diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 2191d8b..1bcf8c1 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1403,20 +1403,22 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry, { struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); __le32 *rxd = (__le32 *)entry->skb->data; - unsigned int offset = entry->queue->desc_size + 2; u32 word0; u32 word1; /* - * Copy descriptor to the available headroom inside the skbuffer. + * Copy descriptor to the skb->cb array, this has 2 benefits: + * 1) Each descriptor word is 4 byte aligned. + * 2) Descriptor is safe from moving of frame data in rt2x00usb. */ - skb_push(entry->skb, offset); - memcpy(entry->skb->data, rxd, entry->queue->desc_size); - rxd = (__le32 *)entry->skb->data; + skbdesc->desc_len = + min_t(u16, entry->queue->desc_size, sizeof(entry->skb->cb)); + memcpy(entry->skb->cb, rxd, skbdesc->desc_len); + skbdesc->desc = entry->skb->cb; + rxd = (__le32 *)skbdesc->desc; /* - * The descriptor is now aligned to 4 bytes and thus it is - * now safe to read it on all architectures. + * It is now safe to read the descriptor on all architectures. */ rt2x00_desc_read(rxd, 0, &word0); rt2x00_desc_read(rxd, 1, &word1); @@ -1442,18 +1444,12 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry, rxdesc->dev_flags |= RXDONE_MY_BSS; /* - * Adjust the skb memory window to the frame boundaries. + * Set skb pointers, and update frame information. */ - skb_pull(entry->skb, offset + entry->queue->desc_size); + skb_pull(entry->skb, entry->queue->desc_size); skb_trim(entry->skb, rxdesc->size); - - /* - * Set descriptor and data pointer. - */ skbdesc->data = entry->skb->data; skbdesc->data_len = rxdesc->size; - skbdesc->desc = rxd; - skbdesc->desc_len = entry->queue->desc_size; } /* -- cgit v0.10.2 From 4de36fe5abe077a4c65bf0b6a309865aa043e055 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Sat, 10 May 2008 13:44:14 +0200 Subject: rt2x00: Only initialize the minimum needed fields of PCI TX descriptors. In preparation of replacing the statically allocated data DMA buffers with DMA-mapped skb's we need to change the TXD handling of the PCI drivers, by moving the programming of the buffer address fields to the actual TXD writing at TX time, instead of at start-up time. Signed-off-by: Gertjan van Wingerde Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index b4310d7..2c0cf39 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -643,15 +643,6 @@ static void rt2400pci_init_txentry(struct rt2x00_dev *rt2x00dev, struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data; u32 word; - rt2x00_desc_read(priv_tx->desc, 1, &word); - rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, priv_tx->data_dma); - rt2x00_desc_write(priv_tx->desc, 1, word); - - rt2x00_desc_read(priv_tx->desc, 2, &word); - rt2x00_set_field32(&word, TXD_W2_BUFFER_LENGTH, - entry->queue->data_size); - rt2x00_desc_write(priv_tx->desc, 2, word); - rt2x00_desc_read(priv_tx->desc, 0, &word); rt2x00_set_field32(&word, TXD_W0_VALID, 0); rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); @@ -1004,13 +995,19 @@ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct txentry_desc *txdesc) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); + struct queue_entry_priv_pci_tx *entry_priv = skbdesc->entry->priv_data; __le32 *txd = skbdesc->desc; u32 word; /* * Start writing the descriptor words. */ + rt2x00_desc_read(entry_priv->desc, 1, &word); + rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, entry_priv->data_dma); + rt2x00_desc_write(entry_priv->desc, 1, word); + rt2x00_desc_read(txd, 2, &word); + rt2x00_set_field32(&word, TXD_W2_BUFFER_LENGTH, skbdesc->data_len); rt2x00_set_field32(&word, TXD_W2_DATABYTE_COUNT, skbdesc->data_len); rt2x00_desc_write(txd, 2, word); diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 54aaa83..6c31c5d 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -733,10 +733,6 @@ static void rt2500pci_init_txentry(struct rt2x00_dev *rt2x00dev, struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data; u32 word; - rt2x00_desc_read(priv_tx->desc, 1, &word); - rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, priv_tx->data_dma); - rt2x00_desc_write(priv_tx->desc, 1, word); - rt2x00_desc_read(priv_tx->desc, 0, &word); rt2x00_set_field32(&word, TXD_W0_VALID, 0); rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); @@ -1158,12 +1154,17 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct txentry_desc *txdesc) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); + struct queue_entry_priv_pci_tx *entry_priv = skbdesc->entry->priv_data; __le32 *txd = skbdesc->desc; u32 word; /* * Start writing the descriptor words. */ + rt2x00_desc_read(entry_priv->desc, 1, &word); + rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, entry_priv->data_dma); + rt2x00_desc_write(entry_priv->desc, 1, word); + rt2x00_desc_read(txd, 2, &word); rt2x00_set_field32(&word, TXD_W2_IV_OFFSET, IEEE80211_HEADER); rt2x00_set_field32(&word, TXD_W2_AIFS, txdesc->aifs); diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 68d2216..d8e681e 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1037,20 +1037,6 @@ static void rt61pci_init_txentry(struct rt2x00_dev *rt2x00dev, struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data; u32 word; - rt2x00_desc_read(priv_tx->desc, 1, &word); - rt2x00_set_field32(&word, TXD_W1_BUFFER_COUNT, 1); - rt2x00_desc_write(priv_tx->desc, 1, word); - - rt2x00_desc_read(priv_tx->desc, 5, &word); - rt2x00_set_field32(&word, TXD_W5_PID_TYPE, entry->queue->qid); - rt2x00_set_field32(&word, TXD_W5_PID_SUBTYPE, entry->entry_idx); - rt2x00_desc_write(priv_tx->desc, 5, word); - - rt2x00_desc_read(priv_tx->desc, 6, &word); - rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS, - priv_tx->data_dma); - rt2x00_desc_write(priv_tx->desc, 6, word); - rt2x00_desc_read(priv_tx->desc, 0, &word); rt2x00_set_field32(&word, TXD_W0_VALID, 0); rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); @@ -1529,6 +1515,7 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct txentry_desc *txdesc) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); + struct queue_entry_priv_pci_tx *entry_priv = skbdesc->entry->priv_data; __le32 *txd = skbdesc->desc; u32 word; @@ -1542,6 +1529,7 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max); rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER); rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, 1); + rt2x00_set_field32(&word, TXD_W1_BUFFER_COUNT, 1); rt2x00_desc_write(txd, 1, word); rt2x00_desc_read(txd, 2, &word); @@ -1552,11 +1540,19 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_desc_write(txd, 2, word); rt2x00_desc_read(txd, 5, &word); + rt2x00_set_field32(&word, TXD_W5_PID_TYPE, skbdesc->entry->queue->qid); + rt2x00_set_field32(&word, TXD_W5_PID_SUBTYPE, + skbdesc->entry->entry_idx); rt2x00_set_field32(&word, TXD_W5_TX_POWER, 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, 6, &word); + rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS, + entry_priv->data_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, skbdesc->data_len); -- cgit v0.10.2 From 7050ec821c52826b63835dde54ee3d71c7db4262 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 10 May 2008 13:46:13 +0200 Subject: rt2x00: Split rt2x00lib_write_tx_desc() Split rt2x00lib_write_tx_desc() up into a TX descriptor initializor and TX descriptor writer. This split is required to properly allow mac80211 to move its tx_control structure into the skb->cb array. The rt2x00queue_create_tx_descriptor() function will read all tx control information and convert it into a rt2x00 TX descriptor information structure. After that function is complete, we have all information we needed from the tx control structure and are free to start writing into the skb->cb array for our own purposes. rt2x00queue_write_tx_descriptor() will be in charge of really sending the TX descriptor to the hardware and kicking the TX queue. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 2c0cf39..d3d9b18 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1492,6 +1492,7 @@ static int rt2400pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, struct rt2x00_intf *intf = vif_to_intf(control->vif); struct queue_entry_priv_pci_tx *priv_tx; struct skb_frame_desc *skbdesc; + struct txentry_desc txdesc; u32 reg; if (unlikely(!intf->beacon)) @@ -1499,6 +1500,14 @@ static int rt2400pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, priv_tx = intf->beacon->priv_data; /* + * Copy all TX descriptor information into txdesc, + * after that we are free to use the skb->cb array + * for our information. + */ + intf->beacon->skb = skb; + rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc, control); + + /* * Fill in skb descriptor */ skbdesc = get_skb_frame_desc(skb); @@ -1525,8 +1534,8 @@ static int rt2400pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, * Write entire beacon with descriptor to register, * and kick the beacon generator. */ - rt2x00lib_write_tx_desc(rt2x00dev, skb, control); memcpy(priv_tx->data, skb->data, skb->len); + rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc); rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON); return 0; diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 6c31c5d..7de7980 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1808,6 +1808,7 @@ static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, struct rt2x00_intf *intf = vif_to_intf(control->vif); struct queue_entry_priv_pci_tx *priv_tx; struct skb_frame_desc *skbdesc; + struct txentry_desc txdesc; u32 reg; if (unlikely(!intf->beacon)) @@ -1816,6 +1817,14 @@ static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, priv_tx = intf->beacon->priv_data; /* + * Copy all TX descriptor information into txdesc, + * after that we are free to use the skb->cb array + * for our information. + */ + intf->beacon->skb = skb; + rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc, control); + + /* * Fill in skb descriptor */ skbdesc = get_skb_frame_desc(skb); @@ -1842,8 +1851,8 @@ static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, * Write entire beacon with descriptor to register, * and kick the beacon generator. */ - rt2x00lib_write_tx_desc(rt2x00dev, skb, control); memcpy(priv_tx->data, skb->data, skb->len); + rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc); rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON); return 0; diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 3be4c7e..6fe713a 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1676,6 +1676,7 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw, struct rt2x00_intf *intf = vif_to_intf(control->vif); struct queue_entry_priv_usb_bcn *priv_bcn; struct skb_frame_desc *skbdesc; + struct txentry_desc txdesc; int pipe = usb_sndbulkpipe(usb_dev, 1); int length; u16 reg; @@ -1686,6 +1687,14 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw, priv_bcn = intf->beacon->priv_data; /* + * Copy all TX descriptor information into txdesc, + * after that we are free to use the skb->cb array + * for our information. + */ + intf->beacon->skb = skb; + rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc, control); + + /* * Add the descriptor in front of the skb. */ skb_push(skb, intf->beacon->queue->desc_size); @@ -1713,7 +1722,7 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw, rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 0); rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); - rt2x00lib_write_tx_desc(rt2x00dev, skb, control); + rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc); /* * USB devices cannot blindly pass the skb->len as the diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 6f7b34f..9c186d7 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -927,6 +927,41 @@ static inline u16 get_duration_res(const unsigned int size, const u8 rate) } /** + * rt2x00queue_create_tx_descriptor - Create TX descriptor from mac80211 input + * @entry: The entry which will be used to transfer the TX frame. + * @txdesc: rt2x00 TX descriptor which will be initialized by this function. + * @control: mac80211 TX control structure from where we read the information. + * + * This function will initialize the &struct txentry_desc based on information + * from mac80211. This descriptor can then be used by rt2x00lib and the drivers + * to correctly initialize the hardware descriptor. + * Note that before calling this function the skb->cb array must be untouched + * by rt2x00lib. Only after this function completes will it be save to + * overwrite the skb->cb information. + * The reason for this is that mac80211 writes its own tx information into + * the skb->cb array, and this function will use that information to initialize + * the &struct txentry_desc structure. + */ +void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, + struct txentry_desc *txdesc, + struct ieee80211_tx_control *control); + +/** + * rt2x00queue_write_tx_descriptor - Write TX descriptor to hardware + * @entry: The entry which will be used to transfer the TX frame. + * @txdesc: TX descriptor which will be used to write hardware descriptor + * + * This function will write a TX descriptor initialized by + * &rt2x00queue_create_tx_descriptor to the hardware. After this call + * has completed the frame is now owned by the hardware, the hardware + * queue will have automatically be kicked unless this frame was generated + * by rt2x00lib, in which case the frame is "special" and must be kicked + * by the caller. + */ +void rt2x00queue_write_tx_descriptor(struct queue_entry *entry, + struct txentry_desc *txdesc); + +/** * rt2x00queue_get_queue - Convert queue index to queue pointer * @rt2x00dev: Pointer to &struct rt2x00_dev. * @queue: rt2x00 queue index (see &enum data_queue_qid). @@ -964,13 +999,6 @@ void rt2x00lib_rxdone(struct queue_entry *entry, struct rxdone_entry_desc *rxdesc); /* - * TX descriptor initializer - */ -void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev, - struct sk_buff *skb, - struct ieee80211_tx_control *control); - -/* * mac80211 handlers. */ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 46c3778..171f445 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -612,154 +612,6 @@ void rt2x00lib_rxdone(struct queue_entry *entry, EXPORT_SYMBOL_GPL(rt2x00lib_rxdone); /* - * TX descriptor initializer - */ -void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev, - struct sk_buff *skb, - struct ieee80211_tx_control *control) -{ - struct txentry_desc txdesc; - struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skbdesc->data; - const struct rt2x00_rate *rate; - int tx_rate; - int length; - int duration; - int residual; - u16 frame_control; - u16 seq_ctrl; - - memset(&txdesc, 0, sizeof(txdesc)); - - txdesc.queue = skbdesc->entry->queue->qid; - txdesc.cw_min = skbdesc->entry->queue->cw_min; - txdesc.cw_max = skbdesc->entry->queue->cw_max; - txdesc.aifs = skbdesc->entry->queue->aifs; - - /* - * Read required fields from ieee80211 header. - */ - frame_control = le16_to_cpu(hdr->frame_control); - seq_ctrl = le16_to_cpu(hdr->seq_ctrl); - - tx_rate = control->tx_rate->hw_value; - - /* - * Check whether this frame is to be acked - */ - if (!(control->flags & IEEE80211_TXCTL_NO_ACK)) - __set_bit(ENTRY_TXD_ACK, &txdesc.flags); - - /* - * Check if this is a RTS/CTS frame - */ - if (is_rts_frame(frame_control) || is_cts_frame(frame_control)) { - __set_bit(ENTRY_TXD_BURST, &txdesc.flags); - if (is_rts_frame(frame_control)) { - __set_bit(ENTRY_TXD_RTS_FRAME, &txdesc.flags); - __set_bit(ENTRY_TXD_ACK, &txdesc.flags); - } else - __clear_bit(ENTRY_TXD_ACK, &txdesc.flags); - if (control->rts_cts_rate) - tx_rate = control->rts_cts_rate->hw_value; - } - - /* - * Determine retry information. - */ - txdesc.retry_limit = control->retry_limit; - if (control->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT) - __set_bit(ENTRY_TXD_RETRY_MODE, &txdesc.flags); - - /* - * Check if more fragments are pending - */ - if (ieee80211_get_morefrag(hdr)) { - __set_bit(ENTRY_TXD_BURST, &txdesc.flags); - __set_bit(ENTRY_TXD_MORE_FRAG, &txdesc.flags); - } - - /* - * Beacons and probe responses require the tsf timestamp - * to be inserted into the frame. - */ - if (txdesc.queue == QID_BEACON || is_probe_resp(frame_control)) - __set_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc.flags); - - /* - * Determine with what IFS priority this frame should be send. - * Set ifs to IFS_SIFS when the this is not the first fragment, - * or this fragment came after RTS/CTS. - */ - if (test_bit(ENTRY_TXD_RTS_FRAME, &txdesc.flags)) { - txdesc.ifs = IFS_SIFS; - } else if (control->flags & IEEE80211_TXCTL_FIRST_FRAGMENT) { - __set_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc.flags); - txdesc.ifs = IFS_BACKOFF; - } else { - txdesc.ifs = IFS_SIFS; - } - - /* - * PLCP setup - * Length calculation depends on OFDM/CCK rate. - */ - rate = rt2x00_get_rate(tx_rate); - txdesc.signal = rate->plcp; - txdesc.service = 0x04; - - length = skbdesc->data_len + FCS_LEN; - if (rate->flags & DEV_RATE_OFDM) { - __set_bit(ENTRY_TXD_OFDM_RATE, &txdesc.flags); - - txdesc.length_high = (length >> 6) & 0x3f; - txdesc.length_low = length & 0x3f; - } else { - /* - * Convert length to microseconds. - */ - residual = get_duration_res(length, rate->bitrate); - duration = get_duration(length, rate->bitrate); - - if (residual != 0) { - duration++; - - /* - * Check if we need to set the Length Extension - */ - if (rate->bitrate == 110 && residual <= 30) - txdesc.service |= 0x80; - } - - txdesc.length_high = (duration >> 8) & 0xff; - txdesc.length_low = duration & 0xff; - - /* - * When preamble is enabled we should set the - * preamble bit for the signal. - */ - if (rt2x00_get_rate_preamble(tx_rate)) - txdesc.signal |= 0x08; - } - - rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, skb, &txdesc); - - /* - * Update queue entry. - */ - skbdesc->entry->skb = skb; - - /* - * The frame has been completely initialized and ready - * for sending to the device. The caller will push the - * frame to the device, but we are going to push the - * frame to debugfs here. - */ - rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TX, skb); -} -EXPORT_SYMBOL_GPL(rt2x00lib_write_tx_desc); - -/* * Driver initialization handlers. */ const struct rt2x00_rate rt2x00_supported_rates[12] = { diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index c17078e..a056b12 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -41,6 +41,7 @@ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data; struct skb_frame_desc *skbdesc; + struct txentry_desc txdesc; u32 word; if (rt2x00queue_full(queue)) @@ -58,6 +59,14 @@ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev, } /* + * Copy all TX descriptor information into txdesc, + * after that we are free to use the skb->cb array + * for our information. + */ + entry->skb = skb; + rt2x00queue_create_tx_descriptor(entry, &txdesc, control); + + /* * Fill in skb descriptor */ skbdesc = get_skb_frame_desc(skb); @@ -69,8 +78,8 @@ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev, memcpy(&priv_tx->control, control, sizeof(priv_tx->control)); memcpy(priv_tx->data, skb->data, skb->len); - rt2x00lib_write_tx_desc(rt2x00dev, skb, control); + rt2x00queue_write_tx_descriptor(entry, &txdesc); rt2x00queue_index_inc(queue, Q_INDEX); return 0; diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 95f8dd3..19c1062 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -29,6 +29,163 @@ #include "rt2x00.h" #include "rt2x00lib.h" +void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, + struct txentry_desc *txdesc, + struct ieee80211_tx_control *control) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data; + struct ieee80211_rate *rate = control->tx_rate; + const struct rt2x00_rate *hwrate; + unsigned int data_length; + unsigned int duration; + unsigned int residual; + u16 frame_control; + + memset(txdesc, 0, sizeof(*txdesc)); + + /* + * Initialize information from queue + */ + txdesc->queue = entry->queue->qid; + txdesc->cw_min = entry->queue->cw_min; + txdesc->cw_max = entry->queue->cw_max; + txdesc->aifs = entry->queue->aifs; + + /* Data length should be extended with 4 bytes for CRC */ + data_length = entry->skb->len + 4; + + /* + * Read required fields from ieee80211 header. + */ + frame_control = le16_to_cpu(hdr->frame_control); + + /* + * Check whether this frame is to be acked. + */ + if (!(control->flags & IEEE80211_TXCTL_NO_ACK)) + __set_bit(ENTRY_TXD_ACK, &txdesc->flags); + + /* + * Check if this is a RTS/CTS frame + */ + if (is_rts_frame(frame_control) || is_cts_frame(frame_control)) { + __set_bit(ENTRY_TXD_BURST, &txdesc->flags); + if (is_rts_frame(frame_control)) { + __set_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags); + __set_bit(ENTRY_TXD_ACK, &txdesc->flags); + } else { + __set_bit(ENTRY_TXD_CTS_FRAME, &txdesc->flags); + __clear_bit(ENTRY_TXD_ACK, &txdesc->flags); + } + if (control->rts_cts_rate) + rate = control->rts_cts_rate; + } + + /* + * Determine retry information. + */ + txdesc->retry_limit = control->retry_limit; + if (control->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT) + __set_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags); + + /* + * Check if more fragments are pending + */ + if (ieee80211_get_morefrag(hdr)) { + __set_bit(ENTRY_TXD_BURST, &txdesc->flags); + __set_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags); + } + + /* + * Beacons and probe responses require the tsf timestamp + * to be inserted into the frame. + */ + if (txdesc->queue == QID_BEACON || is_probe_resp(frame_control)) + __set_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags); + + /* + * Determine with what IFS priority this frame should be send. + * Set ifs to IFS_SIFS when the this is not the first fragment, + * or this fragment came after RTS/CTS. + */ + if (test_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags)) { + txdesc->ifs = IFS_SIFS; + } else if (control->flags & IEEE80211_TXCTL_FIRST_FRAGMENT) { + __set_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags); + txdesc->ifs = IFS_BACKOFF; + } else { + txdesc->ifs = IFS_SIFS; + } + + /* + * PLCP setup + * Length calculation depends on OFDM/CCK rate. + */ + hwrate = rt2x00_get_rate(rate->hw_value); + txdesc->signal = hwrate->plcp; + txdesc->service = 0x04; + + if (hwrate->flags & DEV_RATE_OFDM) { + __set_bit(ENTRY_TXD_OFDM_RATE, &txdesc->flags); + + txdesc->length_high = (data_length >> 6) & 0x3f; + txdesc->length_low = data_length & 0x3f; + } else { + /* + * Convert length to microseconds. + */ + residual = get_duration_res(data_length, hwrate->bitrate); + duration = get_duration(data_length, hwrate->bitrate); + + if (residual != 0) { + duration++; + + /* + * Check if we need to set the Length Extension + */ + if (hwrate->bitrate == 110 && residual <= 30) + txdesc->service |= 0x80; + } + + txdesc->length_high = (duration >> 8) & 0xff; + txdesc->length_low = duration & 0xff; + + /* + * When preamble is enabled we should set the + * preamble bit for the signal. + */ + if (rt2x00_get_rate_preamble(rate->hw_value)) + txdesc->signal |= 0x08; + } +} +EXPORT_SYMBOL_GPL(rt2x00queue_create_tx_descriptor); + +void rt2x00queue_write_tx_descriptor(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); + + rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, entry->skb, txdesc); + + /* + * 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); + + /* + * We are done writing the frame to the queue entry, + * if this entry is a RTS of CTS-to-self frame we are done, + * otherwise we need to kick the queue. + */ + if (rt2x00dev->ops->lib->kick_tx_queue && + !(skbdesc->flags & FRAME_DESC_DRIVER_GENERATED)) + rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, + entry->queue->qid); +} +EXPORT_SYMBOL_GPL(rt2x00queue_write_tx_descriptor); + struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev, const enum data_queue_qid queue) { diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 4bde98b..c6edc52 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -203,6 +203,7 @@ struct txdone_entry_desc { * enum txentry_desc_flags: Status flags for TX entry descriptor * * @ENTRY_TXD_RTS_FRAME: This frame is a RTS frame. + * @ENTRY_TXD_CTS_FRAME: This frame is a CTS-to-self frame. * @ENTRY_TXD_OFDM_RATE: This frame is send out with an OFDM rate. * @ENTRY_TXD_FIRST_FRAGMENT: This is the first frame. * @ENTRY_TXD_MORE_FRAG: This frame is followed by another fragment. @@ -213,6 +214,7 @@ struct txdone_entry_desc { */ enum txentry_desc_flags { ENTRY_TXD_RTS_FRAME, + ENTRY_TXD_CTS_FRAME, ENTRY_TXD_OFDM_RATE, ENTRY_TXD_FIRST_FRAGMENT, ENTRY_TXD_MORE_FRAG, diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index f72b3d0..df66210 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -186,6 +186,7 @@ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); struct queue_entry_priv_usb_tx *priv_tx = entry->priv_data; struct skb_frame_desc *skbdesc; + struct txentry_desc txdesc; u32 length; if (rt2x00queue_full(queue)) @@ -200,6 +201,14 @@ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, } /* + * Copy all TX descriptor information into txdesc, + * after that we are free to use the skb->cb array + * for our information. + */ + entry->skb = skb; + rt2x00queue_create_tx_descriptor(entry, &txdesc, control); + + /* * Add the descriptor in front of the skb. */ skb_push(skb, queue->desc_size); @@ -216,7 +225,7 @@ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, skbdesc->entry = entry; memcpy(&priv_tx->control, control, sizeof(priv_tx->control)); - rt2x00lib_write_tx_desc(rt2x00dev, skb, control); + rt2x00queue_write_tx_descriptor(entry, &txdesc); /* * USB devices cannot blindly pass the skb->len as the diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index d8e681e..d01d5f1 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2361,18 +2361,27 @@ static u64 rt61pci_get_tsf(struct ieee80211_hw *hw) } static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *control) + struct ieee80211_tx_control *control) { struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2x00_intf *intf = vif_to_intf(control->vif); struct queue_entry_priv_pci_tx *priv_tx; struct skb_frame_desc *skbdesc; + struct txentry_desc txdesc; unsigned int beacon_base; u32 reg; if (unlikely(!intf->beacon)) return -ENOBUFS; + /* + * Copy all TX descriptor information into txdesc, + * after that we are free to use the skb->cb array + * for our information. + */ + intf->beacon->skb = skb; + rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc, control); + priv_tx = intf->beacon->priv_data; memset(priv_tx->desc, 0, intf->beacon->queue->desc_size); @@ -2402,7 +2411,7 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, * Write entire beacon with descriptor to register, * and kick the beacon generator. */ - rt2x00lib_write_tx_desc(rt2x00dev, skb, control); + rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc); beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx); rt2x00pci_register_multiwrite(rt2x00dev, beacon_base, skbdesc->desc, skbdesc->desc_len); diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 1bcf8c1..bc44116 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1956,6 +1956,7 @@ static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2x00_intf *intf = vif_to_intf(control->vif); struct skb_frame_desc *skbdesc; + struct txentry_desc txdesc; unsigned int beacon_base; u32 reg; @@ -1963,6 +1964,14 @@ static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, return -ENOBUFS; /* + * Copy all TX descriptor information into txdesc, + * after that we are free to use the skb->cb array + * for our information. + */ + intf->beacon->skb = skb; + rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc, control); + + /* * Add the descriptor in front of the skb. */ skb_push(skb, intf->beacon->queue->desc_size); @@ -1994,7 +2003,7 @@ static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, * Write entire beacon with descriptor to register, * and kick the beacon generator. */ - rt2x00lib_write_tx_desc(rt2x00dev, skb, control); + rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc); beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx); rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE, USB_VENDOR_REQUEST_OUT, beacon_base, 0, -- cgit v0.10.2 From dec13b6bda600c7e7da993e634562873112af50b Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 10 May 2008 13:46:08 +0200 Subject: rt2x00: Remove redundant flags/dev_flags initializations the rxdesc structure is properly memsetted before passed to the driver. This means we don't have to reinitialize the flags and dev_flags fields in the drivers again. This will prevent problems when the rxdone handler is adding flags in a earlier status and will make the code look nicer when we are adding more read attributes in the rxdone handler in the driver. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index d3d9b18..a491ba5 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1087,7 +1087,6 @@ static void rt2400pci_fill_rxdone(struct queue_entry *entry, rt2x00_desc_read(priv_rx->desc, 2, &word2); rt2x00_desc_read(priv_rx->desc, 3, &word3); - rxdesc->flags = 0; if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR)) @@ -1103,7 +1102,7 @@ static void rt2400pci_fill_rxdone(struct queue_entry *entry, entry->queue->rt2x00dev->rssi_offset; rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); - rxdesc->dev_flags = RXDONE_SIGNAL_PLCP; + rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP; if (rt2x00_get_field32(word0, RXD_W0_MY_BSS)) rxdesc->dev_flags |= RXDONE_MY_BSS; } diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 7de7980..8057813 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1242,7 +1242,6 @@ static void rt2500pci_fill_rxdone(struct queue_entry *entry, rt2x00_desc_read(priv_rx->desc, 0, &word0); rt2x00_desc_read(priv_rx->desc, 2, &word2); - rxdesc->flags = 0; if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR)) @@ -1259,7 +1258,6 @@ static void rt2500pci_fill_rxdone(struct queue_entry *entry, entry->queue->rt2x00dev->rssi_offset; rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); - rxdesc->dev_flags = 0; if (rt2x00_get_field32(word0, RXD_W0_OFDM)) rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP; if (rt2x00_get_field32(word0, RXD_W0_MY_BSS)) diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 6fe713a..0bf9ab3 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1149,7 +1149,6 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry, rt2x00_desc_read(rxd, 0, &word0); rt2x00_desc_read(rxd, 1, &word1); - rxdesc->flags = 0; if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR)) @@ -1166,7 +1165,6 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry, entry->queue->rt2x00dev->rssi_offset; rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); - rxdesc->dev_flags = 0; if (rt2x00_get_field32(word0, RXD_W0_OFDM)) rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP; if (rt2x00_get_field32(word0, RXD_W0_MY_BSS)) diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index d01d5f1..2e5e45c 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1668,7 +1668,6 @@ static void rt61pci_fill_rxdone(struct queue_entry *entry, rt2x00_desc_read(priv_rx->desc, 0, &word0); rt2x00_desc_read(priv_rx->desc, 1, &word1); - rxdesc->flags = 0; if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; @@ -1682,7 +1681,6 @@ static void rt61pci_fill_rxdone(struct queue_entry *entry, rxdesc->rssi = rt61pci_agc_to_rssi(entry->queue->rt2x00dev, word1); rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); - rxdesc->dev_flags = 0; if (rt2x00_get_field32(word0, RXD_W0_OFDM)) rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP; if (rt2x00_get_field32(word0, RXD_W0_MY_BSS)) diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index bc44116..5d70dd8 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1423,7 +1423,6 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry, rt2x00_desc_read(rxd, 0, &word0); rt2x00_desc_read(rxd, 1, &word1); - rxdesc->flags = 0; if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; @@ -1437,7 +1436,6 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry, rxdesc->rssi = rt73usb_agc_to_rssi(entry->queue->rt2x00dev, word1); rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); - rxdesc->dev_flags = 0; if (rt2x00_get_field32(word0, RXD_W0_OFDM)) rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP; if (rt2x00_get_field32(word0, RXD_W0_MY_BSS)) -- cgit v0.10.2 From b8be63ffa5dc44324e7f507997870fa3e4b17619 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 10 May 2008 13:46:03 +0200 Subject: rt2x00: Merge RX and TX entry private data With the pending removal of the tx_control structure we can merge the RX and TX entry private data structure in advance. This will temporarily increase the required memory for the queue, but that overhead will only be limited. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index a491ba5..b11f445 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -620,39 +620,38 @@ static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev) static void rt2400pci_init_rxentry(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry) { - struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data; + struct queue_entry_priv_pci *entry_priv = entry->priv_data; u32 word; - rt2x00_desc_read(priv_rx->desc, 2, &word); + rt2x00_desc_read(entry_priv->desc, 2, &word); rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH, entry->queue->data_size); - rt2x00_desc_write(priv_rx->desc, 2, word); + rt2x00_desc_write(entry_priv->desc, 2, word); - rt2x00_desc_read(priv_rx->desc, 1, &word); - rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, priv_rx->data_dma); - rt2x00_desc_write(priv_rx->desc, 1, word); + rt2x00_desc_read(entry_priv->desc, 1, &word); + rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, entry_priv->data_dma); + rt2x00_desc_write(entry_priv->desc, 1, word); - rt2x00_desc_read(priv_rx->desc, 0, &word); + rt2x00_desc_read(entry_priv->desc, 0, &word); rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); - rt2x00_desc_write(priv_rx->desc, 0, word); + rt2x00_desc_write(entry_priv->desc, 0, word); } static void rt2400pci_init_txentry(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry) { - struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data; + struct queue_entry_priv_pci *entry_priv = entry->priv_data; u32 word; - rt2x00_desc_read(priv_tx->desc, 0, &word); + rt2x00_desc_read(entry_priv->desc, 0, &word); rt2x00_set_field32(&word, TXD_W0_VALID, 0); rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); - rt2x00_desc_write(priv_tx->desc, 0, word); + rt2x00_desc_write(entry_priv->desc, 0, word); } static int rt2400pci_init_queues(struct rt2x00_dev *rt2x00dev) { - struct queue_entry_priv_pci_rx *priv_rx; - struct queue_entry_priv_pci_tx *priv_tx; + struct queue_entry_priv_pci *entry_priv; u32 reg; /* @@ -665,28 +664,28 @@ static int rt2400pci_init_queues(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, TXCSR2_NUM_PRIO, rt2x00dev->tx[0].limit); rt2x00pci_register_write(rt2x00dev, TXCSR2, reg); - priv_tx = rt2x00dev->tx[1].entries[0].priv_data; + entry_priv = rt2x00dev->tx[1].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, TXCSR3, ®); rt2x00_set_field32(®, TXCSR3_TX_RING_REGISTER, - priv_tx->desc_dma); + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, TXCSR3, reg); - priv_tx = rt2x00dev->tx[0].entries[0].priv_data; + entry_priv = rt2x00dev->tx[0].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, TXCSR5, ®); rt2x00_set_field32(®, TXCSR5_PRIO_RING_REGISTER, - priv_tx->desc_dma); + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, TXCSR5, reg); - priv_tx = rt2x00dev->bcn[1].entries[0].priv_data; + entry_priv = rt2x00dev->bcn[1].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, TXCSR4, ®); rt2x00_set_field32(®, TXCSR4_ATIM_RING_REGISTER, - priv_tx->desc_dma); + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, TXCSR4, reg); - priv_tx = rt2x00dev->bcn[0].entries[0].priv_data; + entry_priv = rt2x00dev->bcn[0].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, TXCSR6, ®); rt2x00_set_field32(®, TXCSR6_BEACON_RING_REGISTER, - priv_tx->desc_dma); + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, TXCSR6, reg); rt2x00pci_register_read(rt2x00dev, RXCSR1, ®); @@ -694,9 +693,10 @@ static int rt2400pci_init_queues(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, RXCSR1_NUM_RXD, rt2x00dev->rx->limit); rt2x00pci_register_write(rt2x00dev, RXCSR1, reg); - priv_rx = rt2x00dev->rx->entries[0].priv_data; + entry_priv = rt2x00dev->rx->entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, RXCSR2, ®); - rt2x00_set_field32(®, RXCSR2_RX_RING_REGISTER, priv_rx->desc_dma); + rt2x00_set_field32(®, RXCSR2_RX_RING_REGISTER, + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, RXCSR2, reg); return 0; @@ -995,7 +995,7 @@ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct txentry_desc *txdesc) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); - struct queue_entry_priv_pci_tx *entry_priv = skbdesc->entry->priv_data; + struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data; __le32 *txd = skbdesc->desc; u32 word; @@ -1078,14 +1078,14 @@ static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, static void rt2400pci_fill_rxdone(struct queue_entry *entry, struct rxdone_entry_desc *rxdesc) { - struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data; + struct queue_entry_priv_pci *entry_priv = entry->priv_data; u32 word0; u32 word2; u32 word3; - rt2x00_desc_read(priv_rx->desc, 0, &word0); - rt2x00_desc_read(priv_rx->desc, 2, &word2); - rt2x00_desc_read(priv_rx->desc, 3, &word3); + rt2x00_desc_read(entry_priv->desc, 0, &word0); + rt2x00_desc_read(entry_priv->desc, 2, &word2); + rt2x00_desc_read(entry_priv->desc, 3, &word3); if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; @@ -1114,15 +1114,15 @@ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, const enum data_queue_qid queue_idx) { struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, queue_idx); - struct queue_entry_priv_pci_tx *priv_tx; + struct queue_entry_priv_pci *entry_priv; struct queue_entry *entry; struct txdone_entry_desc txdesc; u32 word; while (!rt2x00queue_empty(queue)) { entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); - priv_tx = entry->priv_data; - rt2x00_desc_read(priv_tx->desc, 0, &word); + entry_priv = entry->priv_data; + rt2x00_desc_read(entry_priv->desc, 0, &word); if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || !rt2x00_get_field32(word, TXD_W0_VALID)) @@ -1489,14 +1489,14 @@ static int rt2400pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, { struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2x00_intf *intf = vif_to_intf(control->vif); - struct queue_entry_priv_pci_tx *priv_tx; + struct queue_entry_priv_pci *entry_priv; struct skb_frame_desc *skbdesc; struct txentry_desc txdesc; u32 reg; if (unlikely(!intf->beacon)) return -ENOBUFS; - priv_tx = intf->beacon->priv_data; + entry_priv = intf->beacon->priv_data; /* * Copy all TX descriptor information into txdesc, @@ -1514,7 +1514,7 @@ static int rt2400pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED; skbdesc->data = skb->data; skbdesc->data_len = skb->len; - skbdesc->desc = priv_tx->desc; + skbdesc->desc = entry_priv->desc; skbdesc->desc_len = intf->beacon->queue->desc_size; skbdesc->entry = intf->beacon; @@ -1533,7 +1533,7 @@ static int rt2400pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, * Write entire beacon with descriptor to register, * and kick the beacon generator. */ - memcpy(priv_tx->data, skb->data, skb->len); + memcpy(entry_priv->data, skb->data, skb->len); rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc); rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON); @@ -1594,28 +1594,28 @@ static const struct data_queue_desc rt2400pci_queue_rx = { .entry_num = RX_ENTRIES, .data_size = DATA_FRAME_SIZE, .desc_size = RXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_pci_rx), + .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct data_queue_desc rt2400pci_queue_tx = { .entry_num = TX_ENTRIES, .data_size = DATA_FRAME_SIZE, .desc_size = TXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_pci_tx), + .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct data_queue_desc rt2400pci_queue_bcn = { .entry_num = BEACON_ENTRIES, .data_size = MGMT_FRAME_SIZE, .desc_size = TXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_pci_tx), + .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct data_queue_desc rt2400pci_queue_atim = { .entry_num = ATIM_ENTRIES, .data_size = DATA_FRAME_SIZE, .desc_size = TXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_pci_tx), + .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct rt2x00_ops rt2400pci_ops = { diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 8057813..06e87cd 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -715,34 +715,33 @@ dynamic_cca_tune: static void rt2500pci_init_rxentry(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry) { - struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data; + struct queue_entry_priv_pci *entry_priv = entry->priv_data; u32 word; - rt2x00_desc_read(priv_rx->desc, 1, &word); - rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, priv_rx->data_dma); - rt2x00_desc_write(priv_rx->desc, 1, word); + rt2x00_desc_read(entry_priv->desc, 1, &word); + rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, entry_priv->data_dma); + rt2x00_desc_write(entry_priv->desc, 1, word); - rt2x00_desc_read(priv_rx->desc, 0, &word); + rt2x00_desc_read(entry_priv->desc, 0, &word); rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); - rt2x00_desc_write(priv_rx->desc, 0, word); + rt2x00_desc_write(entry_priv->desc, 0, word); } static void rt2500pci_init_txentry(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry) { - struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data; + struct queue_entry_priv_pci *entry_priv = entry->priv_data; u32 word; - rt2x00_desc_read(priv_tx->desc, 0, &word); + rt2x00_desc_read(entry_priv->desc, 0, &word); rt2x00_set_field32(&word, TXD_W0_VALID, 0); rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); - rt2x00_desc_write(priv_tx->desc, 0, word); + rt2x00_desc_write(entry_priv->desc, 0, word); } static int rt2500pci_init_queues(struct rt2x00_dev *rt2x00dev) { - struct queue_entry_priv_pci_rx *priv_rx; - struct queue_entry_priv_pci_tx *priv_tx; + struct queue_entry_priv_pci *entry_priv; u32 reg; /* @@ -755,28 +754,28 @@ static int rt2500pci_init_queues(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, TXCSR2_NUM_PRIO, rt2x00dev->tx[0].limit); rt2x00pci_register_write(rt2x00dev, TXCSR2, reg); - priv_tx = rt2x00dev->tx[1].entries[0].priv_data; + entry_priv = rt2x00dev->tx[1].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, TXCSR3, ®); rt2x00_set_field32(®, TXCSR3_TX_RING_REGISTER, - priv_tx->desc_dma); + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, TXCSR3, reg); - priv_tx = rt2x00dev->tx[0].entries[0].priv_data; + entry_priv = rt2x00dev->tx[0].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, TXCSR5, ®); rt2x00_set_field32(®, TXCSR5_PRIO_RING_REGISTER, - priv_tx->desc_dma); + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, TXCSR5, reg); - priv_tx = rt2x00dev->bcn[1].entries[0].priv_data; + entry_priv = rt2x00dev->bcn[1].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, TXCSR4, ®); rt2x00_set_field32(®, TXCSR4_ATIM_RING_REGISTER, - priv_tx->desc_dma); + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, TXCSR4, reg); - priv_tx = rt2x00dev->bcn[0].entries[0].priv_data; + entry_priv = rt2x00dev->bcn[0].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, TXCSR6, ®); rt2x00_set_field32(®, TXCSR6_BEACON_RING_REGISTER, - priv_tx->desc_dma); + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, TXCSR6, reg); rt2x00pci_register_read(rt2x00dev, RXCSR1, ®); @@ -784,9 +783,10 @@ static int rt2500pci_init_queues(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, RXCSR1_NUM_RXD, rt2x00dev->rx->limit); rt2x00pci_register_write(rt2x00dev, RXCSR1, reg); - priv_rx = rt2x00dev->rx->entries[0].priv_data; + entry_priv = rt2x00dev->rx->entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, RXCSR2, ®); - rt2x00_set_field32(®, RXCSR2_RX_RING_REGISTER, priv_rx->desc_dma); + rt2x00_set_field32(®, RXCSR2_RX_RING_REGISTER, + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, RXCSR2, reg); return 0; @@ -1154,7 +1154,7 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct txentry_desc *txdesc) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); - struct queue_entry_priv_pci_tx *entry_priv = skbdesc->entry->priv_data; + struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data; __le32 *txd = skbdesc->desc; u32 word; @@ -1235,12 +1235,12 @@ static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, static void rt2500pci_fill_rxdone(struct queue_entry *entry, struct rxdone_entry_desc *rxdesc) { - struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data; + struct queue_entry_priv_pci *entry_priv = entry->priv_data; u32 word0; u32 word2; - rt2x00_desc_read(priv_rx->desc, 0, &word0); - rt2x00_desc_read(priv_rx->desc, 2, &word2); + rt2x00_desc_read(entry_priv->desc, 0, &word0); + rt2x00_desc_read(entry_priv->desc, 2, &word2); if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; @@ -1271,15 +1271,15 @@ static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev, const enum data_queue_qid queue_idx) { struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, queue_idx); - struct queue_entry_priv_pci_tx *priv_tx; + struct queue_entry_priv_pci *entry_priv; struct queue_entry *entry; struct txdone_entry_desc txdesc; u32 word; while (!rt2x00queue_empty(queue)) { entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); - priv_tx = entry->priv_data; - rt2x00_desc_read(priv_tx->desc, 0, &word); + entry_priv = entry->priv_data; + rt2x00_desc_read(entry_priv->desc, 0, &word); if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || !rt2x00_get_field32(word, TXD_W0_VALID)) @@ -1804,7 +1804,7 @@ static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, { struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2x00_intf *intf = vif_to_intf(control->vif); - struct queue_entry_priv_pci_tx *priv_tx; + struct queue_entry_priv_pci *entry_priv; struct skb_frame_desc *skbdesc; struct txentry_desc txdesc; u32 reg; @@ -1812,7 +1812,7 @@ static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, if (unlikely(!intf->beacon)) return -ENOBUFS; - priv_tx = intf->beacon->priv_data; + entry_priv = intf->beacon->priv_data; /* * Copy all TX descriptor information into txdesc, @@ -1830,7 +1830,7 @@ static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED; skbdesc->data = skb->data; skbdesc->data_len = skb->len; - skbdesc->desc = priv_tx->desc; + skbdesc->desc = entry_priv->desc; skbdesc->desc_len = intf->beacon->queue->desc_size; skbdesc->entry = intf->beacon; @@ -1849,7 +1849,7 @@ static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, * Write entire beacon with descriptor to register, * and kick the beacon generator. */ - memcpy(priv_tx->data, skb->data, skb->len); + memcpy(entry_priv->data, skb->data, skb->len); rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc); rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON); @@ -1910,28 +1910,28 @@ static const struct data_queue_desc rt2500pci_queue_rx = { .entry_num = RX_ENTRIES, .data_size = DATA_FRAME_SIZE, .desc_size = RXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_pci_rx), + .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct data_queue_desc rt2500pci_queue_tx = { .entry_num = TX_ENTRIES, .data_size = DATA_FRAME_SIZE, .desc_size = TXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_pci_tx), + .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct data_queue_desc rt2500pci_queue_bcn = { .entry_num = BEACON_ENTRIES, .data_size = MGMT_FRAME_SIZE, .desc_size = TXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_pci_tx), + .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct data_queue_desc rt2500pci_queue_atim = { .entry_num = ATIM_ENTRIES, .data_size = DATA_FRAME_SIZE, .desc_size = TXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_pci_tx), + .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct rt2x00_ops rt2500pci_ops = { diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 0bf9ab3..4122c5e 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1124,11 +1124,12 @@ static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, static void rt2500usb_fill_rxdone(struct queue_entry *entry, struct rxdone_entry_desc *rxdesc) { - struct queue_entry_priv_usb_rx *priv_rx = entry->priv_data; + struct queue_entry_priv_usb *entry_priv = entry->priv_data; struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); __le32 *rxd = (__le32 *)(entry->skb->data + - (priv_rx->urb->actual_length - entry->queue->desc_size)); + (entry_priv->urb->actual_length - + entry->queue->desc_size)); u32 word0; u32 word1; @@ -1184,7 +1185,7 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry, static void rt2500usb_beacondone(struct urb *urb) { struct queue_entry *entry = (struct queue_entry *)urb->context; - struct queue_entry_priv_usb_bcn *priv_bcn = entry->priv_data; + struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data; if (!test_bit(DEVICE_ENABLED_RADIO, &entry->queue->rt2x00dev->flags)) return; @@ -1195,9 +1196,9 @@ static void rt2500usb_beacondone(struct urb *urb) * Otherwise we should free the sk_buffer, the device * should be doing the rest of the work now. */ - if (priv_bcn->guardian_urb == urb) { - usb_submit_urb(priv_bcn->urb, GFP_ATOMIC); - } else if (priv_bcn->urb == urb) { + if (bcn_priv->guardian_urb == urb) { + usb_submit_urb(bcn_priv->urb, GFP_ATOMIC); + } else if (bcn_priv->urb == urb) { dev_kfree_skb(entry->skb); entry->skb = NULL; } @@ -1672,7 +1673,7 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw, struct rt2x00_dev *rt2x00dev = hw->priv; struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev); struct rt2x00_intf *intf = vif_to_intf(control->vif); - struct queue_entry_priv_usb_bcn *priv_bcn; + struct queue_entry_priv_usb_bcn *bcn_priv; struct skb_frame_desc *skbdesc; struct txentry_desc txdesc; int pipe = usb_sndbulkpipe(usb_dev, 1); @@ -1682,7 +1683,7 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw, if (unlikely(!intf->beacon)) return -ENOBUFS; - priv_bcn = intf->beacon->priv_data; + bcn_priv = intf->beacon->priv_data; /* * Copy all TX descriptor information into txdesc, @@ -1729,7 +1730,7 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw, */ length = rt2500usb_get_tx_data_len(rt2x00dev, skb); - usb_fill_bulk_urb(priv_bcn->urb, usb_dev, pipe, + usb_fill_bulk_urb(bcn_priv->urb, usb_dev, pipe, skb->data, length, rt2500usb_beacondone, intf->beacon); @@ -1738,15 +1739,15 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw, * We only need a single byte, so lets recycle * the 'flags' field we are not using for beacons. */ - priv_bcn->guardian_data = 0; - usb_fill_bulk_urb(priv_bcn->guardian_urb, usb_dev, pipe, - &priv_bcn->guardian_data, 1, rt2500usb_beacondone, + bcn_priv->guardian_data = 0; + usb_fill_bulk_urb(bcn_priv->guardian_urb, usb_dev, pipe, + &bcn_priv->guardian_data, 1, rt2500usb_beacondone, intf->beacon); /* * Send out the guardian byte. */ - usb_submit_urb(priv_bcn->guardian_urb, GFP_ATOMIC); + usb_submit_urb(bcn_priv->guardian_urb, GFP_ATOMIC); /* * Enable beacon generation. @@ -1797,14 +1798,14 @@ static const struct data_queue_desc rt2500usb_queue_rx = { .entry_num = RX_ENTRIES, .data_size = DATA_FRAME_SIZE, .desc_size = RXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_usb_rx), + .priv_size = sizeof(struct queue_entry_priv_usb), }; static const struct data_queue_desc rt2500usb_queue_tx = { .entry_num = TX_ENTRIES, .data_size = DATA_FRAME_SIZE, .desc_size = TXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_usb_tx), + .priv_size = sizeof(struct queue_entry_priv_usb), }; static const struct data_queue_desc rt2500usb_queue_bcn = { @@ -1818,7 +1819,7 @@ static const struct data_queue_desc rt2500usb_queue_atim = { .entry_num = ATIM_ENTRIES, .data_size = DATA_FRAME_SIZE, .desc_size = TXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_usb_tx), + .priv_size = sizeof(struct queue_entry_priv_usb), }; static const struct rt2x00_ops rt2500usb_ops = { diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index a056b12..fa7de41 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -39,7 +39,7 @@ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev, struct ieee80211_tx_control *control) { struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); - struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data; + struct queue_entry_priv_pci *entry_priv = entry->priv_data; struct skb_frame_desc *skbdesc; struct txentry_desc txdesc; u32 word; @@ -47,7 +47,7 @@ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev, if (rt2x00queue_full(queue)) return -EINVAL; - rt2x00_desc_read(priv_tx->desc, 0, &word); + rt2x00_desc_read(entry_priv->desc, 0, &word); if (rt2x00_get_field32(word, TXD_ENTRY_OWNER_NIC) || rt2x00_get_field32(word, TXD_ENTRY_VALID)) { @@ -72,12 +72,12 @@ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev, skbdesc = get_skb_frame_desc(skb); skbdesc->data = skb->data; skbdesc->data_len = skb->len; - skbdesc->desc = priv_tx->desc; + skbdesc->desc = entry_priv->desc; skbdesc->desc_len = queue->desc_size; skbdesc->entry = entry; - memcpy(&priv_tx->control, control, sizeof(priv_tx->control)); - memcpy(priv_tx->data, skb->data, skb->len); + memcpy(&entry_priv->control, control, sizeof(entry_priv->control)); + memcpy(entry_priv->data, skb->data, skb->len); rt2x00queue_write_tx_descriptor(entry, &txdesc); rt2x00queue_index_inc(queue, Q_INDEX); @@ -93,7 +93,7 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) { struct data_queue *queue = rt2x00dev->rx; struct queue_entry *entry; - struct queue_entry_priv_pci_rx *priv_rx; + struct queue_entry_priv_pci *entry_priv; struct ieee80211_hdr *hdr; struct skb_frame_desc *skbdesc; struct rxdone_entry_desc rxdesc; @@ -103,8 +103,8 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) while (1) { entry = rt2x00queue_get_entry(queue, Q_INDEX); - priv_rx = entry->priv_data; - rt2x00_desc_read(priv_rx->desc, 0, &word); + entry_priv = entry->priv_data; + rt2x00_desc_read(entry_priv->desc, 0, &word); if (rt2x00_get_field32(word, RXD_ENTRY_OWNER_NIC)) break; @@ -112,7 +112,7 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) memset(&rxdesc, 0, sizeof(rxdesc)); rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc); - hdr = (struct ieee80211_hdr *)priv_rx->data; + hdr = (struct ieee80211_hdr *)entry_priv->data; header_size = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)); @@ -132,7 +132,7 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) skb_reserve(entry->skb, align); memcpy(skb_put(entry->skb, rxdesc.size), - priv_rx->data, rxdesc.size); + entry_priv->data, rxdesc.size); /* * Fill in skb descriptor @@ -141,7 +141,7 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) memset(skbdesc, 0, sizeof(*skbdesc)); skbdesc->data = entry->skb->data; skbdesc->data_len = entry->skb->len; - skbdesc->desc = priv_rx->desc; + skbdesc->desc = entry_priv->desc; skbdesc->desc_len = queue->desc_size; skbdesc->entry = entry; @@ -152,7 +152,7 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) if (test_bit(DEVICE_ENABLED_RADIO, &queue->rt2x00dev->flags)) { rt2x00_set_field32(&word, RXD_ENTRY_OWNER_NIC, 1); - rt2x00_desc_write(priv_rx->desc, 0, word); + rt2x00_desc_write(entry_priv->desc, 0, word); } rt2x00queue_index_inc(queue, Q_INDEX); @@ -163,10 +163,10 @@ EXPORT_SYMBOL_GPL(rt2x00pci_rxdone); void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry, struct txdone_entry_desc *txdesc) { - struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data; + struct queue_entry_priv_pci *entry_priv = entry->priv_data; u32 word; - txdesc->control = &priv_tx->control; + txdesc->control = &entry_priv->control; rt2x00lib_txdone(entry, txdesc); /* @@ -174,10 +174,10 @@ void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry, */ entry->flags = 0; - rt2x00_desc_read(priv_tx->desc, 0, &word); + rt2x00_desc_read(entry_priv->desc, 0, &word); rt2x00_set_field32(&word, TXD_ENTRY_OWNER_NIC, 0); rt2x00_set_field32(&word, TXD_ENTRY_VALID, 0); - rt2x00_desc_write(priv_tx->desc, 0, word); + rt2x00_desc_write(entry_priv->desc, 0, word); rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE); @@ -187,7 +187,7 @@ void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry, * is reenabled when the txdone handler has finished. */ if (!rt2x00queue_full(entry->queue)) - ieee80211_wake_queue(rt2x00dev->hw, priv_tx->control.queue); + ieee80211_wake_queue(rt2x00dev->hw, entry_priv->control.queue); } EXPORT_SYMBOL_GPL(rt2x00pci_txdone); @@ -226,14 +226,9 @@ static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev, struct data_queue *queue) { struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev); - struct queue_entry_priv_pci_rx *priv_rx; - struct queue_entry_priv_pci_tx *priv_tx; + struct queue_entry_priv_pci *entry_priv; void *addr; dma_addr_t dma; - void *desc_addr; - dma_addr_t desc_dma; - void *data_addr; - dma_addr_t data_dma; unsigned int i; /* @@ -249,24 +244,11 @@ static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev, * Initialize all queue entries to contain valid addresses. */ for (i = 0; i < queue->limit; i++) { - desc_addr = desc_offset(queue, addr, i); - desc_dma = desc_offset(queue, dma, i); - data_addr = data_offset(queue, addr, i); - data_dma = data_offset(queue, dma, i); - - if (queue->qid == QID_RX) { - priv_rx = queue->entries[i].priv_data; - priv_rx->desc = desc_addr; - priv_rx->desc_dma = desc_dma; - priv_rx->data = data_addr; - priv_rx->data_dma = data_dma; - } else { - priv_tx = queue->entries[i].priv_data; - priv_tx->desc = desc_addr; - priv_tx->desc_dma = desc_dma; - priv_tx->data = data_addr; - priv_tx->data_dma = data_dma; - } + entry_priv = queue->entries[i].priv_data; + entry_priv->desc = desc_offset(queue, addr, i); + entry_priv->desc_dma = desc_offset(queue, dma, i); + entry_priv->data = data_offset(queue, addr, i); + entry_priv->data_dma = data_offset(queue, dma, i); } return 0; @@ -276,28 +258,13 @@ static void rt2x00pci_free_queue_dma(struct rt2x00_dev *rt2x00dev, struct data_queue *queue) { struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev); - struct queue_entry_priv_pci_rx *priv_rx; - struct queue_entry_priv_pci_tx *priv_tx; - void *data_addr; - dma_addr_t data_dma; - - if (queue->qid == QID_RX) { - priv_rx = queue->entries[0].priv_data; - data_addr = priv_rx->data; - data_dma = priv_rx->data_dma; - - priv_rx->data = NULL; - } else { - priv_tx = queue->entries[0].priv_data; - data_addr = priv_tx->data; - data_dma = priv_tx->data_dma; - - priv_tx->data = NULL; - } + struct queue_entry_priv_pci *entry_priv = + queue->entries[0].priv_data; - if (data_addr) + if (entry_priv->data) pci_free_consistent(pci_dev, dma_size(queue), - data_addr, data_dma); + entry_priv->data, entry_priv->data_dma); + entry_priv->data = NULL; } int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev) diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h index 2b0ef17..557d15a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.h +++ b/drivers/net/wireless/rt2x00/rt2x00pci.h @@ -95,31 +95,15 @@ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev, struct ieee80211_tx_control *control); /** - * struct queue_entry_priv_pci_rx: Per RX entry PCI specific information - * - * @desc: Pointer to device descriptor. - * @desc_dma: DMA pointer to @desc. - * @data: Pointer to device's entry memory. - * @data_dma: DMA pointer to &data. - */ -struct queue_entry_priv_pci_rx { - __le32 *desc; - dma_addr_t desc_dma; - - void *data; - dma_addr_t data_dma; -}; - -/** - * struct queue_entry_priv_pci_tx: Per TX entry PCI specific information + * struct queue_entry_priv_pci: Per entry PCI specific information * * @desc: Pointer to device descriptor - * @desc_dma: DMA pointer to @desc. + * @desc_dma: DMA pointer to &desc. * @data: Pointer to device's entry memory. * @data_dma: DMA pointer to &data. * @control: mac80211 control structure used to transmit data. */ -struct queue_entry_priv_pci_tx { +struct queue_entry_priv_pci { __le32 *desc; dma_addr_t desc_dma; diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index df66210..dcee1b4 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -129,7 +129,7 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) { struct queue_entry *entry = (struct queue_entry *)urb->context; struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; - struct queue_entry_priv_usb_tx *priv_tx = entry->priv_data; + struct queue_entry_priv_usb *entry_priv = entry->priv_data; struct txdone_entry_desc txdesc; __le32 *txd = (__le32 *)entry->skb->data; u32 word; @@ -159,7 +159,7 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) else __set_bit(TXDONE_FAILURE, &txdesc.flags); txdesc.retry = 0; - txdesc.control = &priv_tx->control; + txdesc.control = &entry_priv->control; rt2x00lib_txdone(entry, &txdesc); @@ -175,7 +175,7 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) * is reenabled when the txdone handler has finished. */ if (!rt2x00queue_full(entry->queue)) - ieee80211_wake_queue(rt2x00dev->hw, priv_tx->control.queue); + ieee80211_wake_queue(rt2x00dev->hw, entry_priv->control.queue); } int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, @@ -184,7 +184,7 @@ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, { struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev); struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); - struct queue_entry_priv_usb_tx *priv_tx = entry->priv_data; + struct queue_entry_priv_usb *entry_priv = entry->priv_data; struct skb_frame_desc *skbdesc; struct txentry_desc txdesc; u32 length; @@ -224,7 +224,7 @@ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, skbdesc->desc_len = queue->desc_size; skbdesc->entry = entry; - memcpy(&priv_tx->control, control, sizeof(priv_tx->control)); + memcpy(&entry_priv->control, control, sizeof(entry_priv->control)); rt2x00queue_write_tx_descriptor(entry, &txdesc); /* @@ -238,9 +238,9 @@ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, * Initialize URB and send the frame to the device. */ __set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); - usb_fill_bulk_urb(priv_tx->urb, usb_dev, usb_sndbulkpipe(usb_dev, 1), + usb_fill_bulk_urb(entry_priv->urb, usb_dev, usb_sndbulkpipe(usb_dev, 1), skb->data, length, rt2x00usb_interrupt_txdone, entry); - usb_submit_urb(priv_tx->urb, GFP_ATOMIC); + usb_submit_urb(entry_priv->urb, GFP_ATOMIC); rt2x00queue_index_inc(queue, Q_INDEX); @@ -380,10 +380,8 @@ skip_entry: */ void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev) { - struct queue_entry_priv_usb_rx *priv_rx; - struct queue_entry_priv_usb_tx *priv_tx; - struct queue_entry_priv_usb_bcn *priv_bcn; - struct data_queue *queue; + struct queue_entry_priv_usb *entry_priv; + struct queue_entry_priv_usb_bcn *bcn_priv; unsigned int i; rt2x00usb_vendor_request_sw(rt2x00dev, USB_RX_CONTROL, 0, 0, @@ -393,31 +391,17 @@ void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev) * Cancel all queues. */ for (i = 0; i < rt2x00dev->rx->limit; i++) { - priv_rx = rt2x00dev->rx->entries[i].priv_data; - usb_kill_urb(priv_rx->urb); - } - - tx_queue_for_each(rt2x00dev, queue) { - for (i = 0; i < queue->limit; i++) { - priv_tx = queue->entries[i].priv_data; - usb_kill_urb(priv_tx->urb); - } + entry_priv = rt2x00dev->rx->entries[i].priv_data; + usb_kill_urb(entry_priv->urb); } + /* + * Kill guardian urb. + */ for (i = 0; i < rt2x00dev->bcn->limit; i++) { - priv_bcn = rt2x00dev->bcn->entries[i].priv_data; - usb_kill_urb(priv_bcn->urb); - - if (priv_bcn->guardian_urb) - usb_kill_urb(priv_bcn->guardian_urb); - } - - if (!test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags)) - return; - - for (i = 0; i < rt2x00dev->bcn[1].limit; i++) { - priv_tx = rt2x00dev->bcn[1].entries[i].priv_data; - usb_kill_urb(priv_tx->urb); + bcn_priv = rt2x00dev->bcn->entries[i].priv_data; + if (bcn_priv->guardian_urb) + usb_kill_urb(bcn_priv->guardian_urb); } } EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio); @@ -429,15 +413,15 @@ void rt2x00usb_init_rxentry(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry) { struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev); - struct queue_entry_priv_usb_rx *priv_rx = entry->priv_data; + struct queue_entry_priv_usb *entry_priv = entry->priv_data; - usb_fill_bulk_urb(priv_rx->urb, usb_dev, + usb_fill_bulk_urb(entry_priv->urb, usb_dev, usb_rcvbulkpipe(usb_dev, 1), entry->skb->data, entry->skb->len, rt2x00usb_interrupt_rxdone, entry); __set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); - usb_submit_urb(priv_rx->urb, GFP_ATOMIC); + usb_submit_urb(entry_priv->urb, GFP_ATOMIC); } EXPORT_SYMBOL_GPL(rt2x00usb_init_rxentry); @@ -451,38 +435,31 @@ EXPORT_SYMBOL_GPL(rt2x00usb_init_txentry); static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev, struct data_queue *queue) { - struct queue_entry_priv_usb_rx *priv_rx; - struct queue_entry_priv_usb_tx *priv_tx; - struct queue_entry_priv_usb_bcn *priv_bcn; - struct urb *urb; - unsigned int guardian = - test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags); + struct queue_entry_priv_usb *entry_priv; + struct queue_entry_priv_usb_bcn *bcn_priv; unsigned int i; + for (i = 0; i < queue->limit; i++) { + entry_priv = queue->entries[i].priv_data; + entry_priv->urb = usb_alloc_urb(0, GFP_KERNEL); + if (!entry_priv->urb) + return -ENOMEM; + } + /* - * Allocate the URB's + * If this is not the beacon queue or + * no guardian byte was required for the beacon, + * then we are done. */ + if (rt2x00dev->bcn != queue || + !test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags)) + return 0; + for (i = 0; i < queue->limit; i++) { - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) + bcn_priv = queue->entries[i].priv_data; + bcn_priv->guardian_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!bcn_priv->guardian_urb) return -ENOMEM; - - if (queue->qid == QID_RX) { - priv_rx = queue->entries[i].priv_data; - priv_rx->urb = urb; - } else if (queue->qid == QID_MGMT && guardian) { - priv_bcn = queue->entries[i].priv_data; - priv_bcn->urb = urb; - - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) - return -ENOMEM; - - priv_bcn->guardian_urb = urb; - } else { - priv_tx = queue->entries[i].priv_data; - priv_tx->urb = urb; - } } return 0; @@ -491,38 +468,35 @@ static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev, static void rt2x00usb_free_urb(struct rt2x00_dev *rt2x00dev, struct data_queue *queue) { - struct queue_entry_priv_usb_rx *priv_rx; - struct queue_entry_priv_usb_tx *priv_tx; - struct queue_entry_priv_usb_bcn *priv_bcn; - struct urb *urb; - unsigned int guardian = - test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags); + struct queue_entry_priv_usb *entry_priv; + struct queue_entry_priv_usb_bcn *bcn_priv; unsigned int i; if (!queue->entries) return; for (i = 0; i < queue->limit; i++) { - if (queue->qid == QID_RX) { - priv_rx = queue->entries[i].priv_data; - urb = priv_rx->urb; - } else if (queue->qid == QID_MGMT && guardian) { - priv_bcn = queue->entries[i].priv_data; - - usb_kill_urb(priv_bcn->guardian_urb); - usb_free_urb(priv_bcn->guardian_urb); - - urb = priv_bcn->urb; - } else { - priv_tx = queue->entries[i].priv_data; - urb = priv_tx->urb; - } - - usb_kill_urb(urb); - usb_free_urb(urb); + entry_priv = queue->entries[i].priv_data; + usb_kill_urb(entry_priv->urb); + usb_free_urb(entry_priv->urb); if (queue->entries[i].skb) kfree_skb(queue->entries[i].skb); } + + /* + * If this is not the beacon queue or + * no guardian byte was required for the beacon, + * then we are done. + */ + if (rt2x00dev->bcn != queue || + !test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags)) + return; + + for (i = 0; i < queue->limit; i++) { + bcn_priv = queue->entries[i].priv_data; + usb_kill_urb(bcn_priv->guardian_urb); + usb_free_urb(bcn_priv->guardian_urb); + } } int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev) diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index 4da9eb3..15b404a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h @@ -220,30 +220,21 @@ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, struct ieee80211_tx_control *control); /** - * struct queue_entry_priv_usb_rx: Per RX entry USB specific information - * - * @urb: Urb structure used for device communication. - */ -struct queue_entry_priv_usb_rx { - struct urb *urb; -}; - -/** - * struct queue_entry_priv_usb_tx: Per TX entry USB specific information + * struct queue_entry_priv_usb: Per entry USB specific information * * @urb: Urb structure used for device communication. * @control: mac80211 control structure used to transmit data. */ -struct queue_entry_priv_usb_tx { +struct queue_entry_priv_usb { struct urb *urb; struct ieee80211_tx_control control; }; /** - * struct queue_entry_priv_usb_tx: Per TX entry USB specific information + * struct queue_entry_priv_usb_bcn: Per TX entry USB specific information * - * The first section should match &struct queue_entry_priv_usb_tx exactly. + * The first section should match &struct queue_entry_priv_usb exactly. * rt2500usb can use this structure to send a guardian byte when working * with beacons. * diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 2e5e45c..7598b6e 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1018,35 +1018,34 @@ static int rt61pci_load_firmware(struct rt2x00_dev *rt2x00dev, void *data, static void rt61pci_init_rxentry(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry) { - struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data; + struct queue_entry_priv_pci *entry_priv = entry->priv_data; u32 word; - rt2x00_desc_read(priv_rx->desc, 5, &word); + rt2x00_desc_read(entry_priv->desc, 5, &word); rt2x00_set_field32(&word, RXD_W5_BUFFER_PHYSICAL_ADDRESS, - priv_rx->data_dma); - rt2x00_desc_write(priv_rx->desc, 5, word); + entry_priv->data_dma); + rt2x00_desc_write(entry_priv->desc, 5, word); - rt2x00_desc_read(priv_rx->desc, 0, &word); + rt2x00_desc_read(entry_priv->desc, 0, &word); rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); - rt2x00_desc_write(priv_rx->desc, 0, word); + rt2x00_desc_write(entry_priv->desc, 0, word); } static void rt61pci_init_txentry(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry) { - struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data; + struct queue_entry_priv_pci *entry_priv = entry->priv_data; u32 word; - rt2x00_desc_read(priv_tx->desc, 0, &word); + rt2x00_desc_read(entry_priv->desc, 0, &word); rt2x00_set_field32(&word, TXD_W0_VALID, 0); rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); - rt2x00_desc_write(priv_tx->desc, 0, word); + rt2x00_desc_write(entry_priv->desc, 0, word); } static int rt61pci_init_queues(struct rt2x00_dev *rt2x00dev) { - struct queue_entry_priv_pci_rx *priv_rx; - struct queue_entry_priv_pci_tx *priv_tx; + struct queue_entry_priv_pci *entry_priv; u32 reg; /* @@ -1068,28 +1067,28 @@ static int rt61pci_init_queues(struct rt2x00_dev *rt2x00dev) rt2x00dev->tx[0].desc_size / 4); rt2x00pci_register_write(rt2x00dev, TX_RING_CSR1, reg); - priv_tx = rt2x00dev->tx[0].entries[0].priv_data; + entry_priv = rt2x00dev->tx[0].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, AC0_BASE_CSR, ®); rt2x00_set_field32(®, AC0_BASE_CSR_RING_REGISTER, - priv_tx->desc_dma); + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, AC0_BASE_CSR, reg); - priv_tx = rt2x00dev->tx[1].entries[0].priv_data; + entry_priv = rt2x00dev->tx[1].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, AC1_BASE_CSR, ®); rt2x00_set_field32(®, AC1_BASE_CSR_RING_REGISTER, - priv_tx->desc_dma); + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, AC1_BASE_CSR, reg); - priv_tx = rt2x00dev->tx[2].entries[0].priv_data; + entry_priv = rt2x00dev->tx[2].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, AC2_BASE_CSR, ®); rt2x00_set_field32(®, AC2_BASE_CSR_RING_REGISTER, - priv_tx->desc_dma); + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, AC2_BASE_CSR, reg); - priv_tx = rt2x00dev->tx[3].entries[0].priv_data; + entry_priv = rt2x00dev->tx[3].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, AC3_BASE_CSR, ®); rt2x00_set_field32(®, AC3_BASE_CSR_RING_REGISTER, - priv_tx->desc_dma); + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, AC3_BASE_CSR, reg); rt2x00pci_register_read(rt2x00dev, RX_RING_CSR, ®); @@ -1099,10 +1098,10 @@ static int rt61pci_init_queues(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, RX_RING_CSR_RXD_WRITEBACK_SIZE, 4); rt2x00pci_register_write(rt2x00dev, RX_RING_CSR, reg); - priv_rx = rt2x00dev->rx->entries[0].priv_data; + entry_priv = rt2x00dev->rx->entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, RX_BASE_CSR, ®); rt2x00_set_field32(®, RX_BASE_CSR_RING_REGISTER, - priv_rx->desc_dma); + entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, RX_BASE_CSR, reg); rt2x00pci_register_read(rt2x00dev, TX_DMA_DST_CSR, ®); @@ -1515,7 +1514,7 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct txentry_desc *txdesc) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); - struct queue_entry_priv_pci_tx *entry_priv = skbdesc->entry->priv_data; + struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data; __le32 *txd = skbdesc->desc; u32 word; @@ -1661,12 +1660,12 @@ static int rt61pci_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) static void rt61pci_fill_rxdone(struct queue_entry *entry, struct rxdone_entry_desc *rxdesc) { - struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data; + struct queue_entry_priv_pci *entry_priv = entry->priv_data; u32 word0; u32 word1; - rt2x00_desc_read(priv_rx->desc, 0, &word0); - rt2x00_desc_read(priv_rx->desc, 1, &word1); + rt2x00_desc_read(entry_priv->desc, 0, &word0); + rt2x00_desc_read(entry_priv->desc, 1, &word1); if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; @@ -1695,7 +1694,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev) struct data_queue *queue; struct queue_entry *entry; struct queue_entry *entry_done; - struct queue_entry_priv_pci_tx *priv_tx; + struct queue_entry_priv_pci *entry_priv; struct txdone_entry_desc txdesc; u32 word; u32 reg; @@ -1740,8 +1739,8 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev) continue; entry = &queue->entries[index]; - priv_tx = entry->priv_data; - rt2x00_desc_read(priv_tx->desc, 0, &word); + entry_priv = entry->priv_data; + rt2x00_desc_read(entry_priv->desc, 0, &word); if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || !rt2x00_get_field32(word, TXD_W0_VALID)) @@ -2363,7 +2362,7 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, { struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2x00_intf *intf = vif_to_intf(control->vif); - struct queue_entry_priv_pci_tx *priv_tx; + struct queue_entry_priv_pci *entry_priv; struct skb_frame_desc *skbdesc; struct txentry_desc txdesc; unsigned int beacon_base; @@ -2380,8 +2379,8 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, intf->beacon->skb = skb; rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc, control); - priv_tx = intf->beacon->priv_data; - memset(priv_tx->desc, 0, intf->beacon->queue->desc_size); + entry_priv = intf->beacon->priv_data; + memset(entry_priv->desc, 0, intf->beacon->queue->desc_size); /* * Fill in skb descriptor @@ -2391,7 +2390,7 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED; skbdesc->data = skb->data; skbdesc->data_len = skb->len; - skbdesc->desc = priv_tx->desc; + skbdesc->desc = entry_priv->desc; skbdesc->desc_len = intf->beacon->queue->desc_size; skbdesc->entry = intf->beacon; @@ -2468,21 +2467,21 @@ static const struct data_queue_desc rt61pci_queue_rx = { .entry_num = RX_ENTRIES, .data_size = DATA_FRAME_SIZE, .desc_size = RXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_pci_rx), + .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct data_queue_desc rt61pci_queue_tx = { .entry_num = TX_ENTRIES, .data_size = DATA_FRAME_SIZE, .desc_size = TXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_pci_tx), + .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct data_queue_desc rt61pci_queue_bcn = { .entry_num = 4 * BEACON_ENTRIES, .data_size = 0, /* No DMA required for beacons */ .desc_size = TXINFO_SIZE, - .priv_size = sizeof(struct queue_entry_priv_pci_tx), + .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct rt2x00_ops rt61pci_ops = { diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 5d70dd8..e55bcbd 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2058,21 +2058,21 @@ static const struct data_queue_desc rt73usb_queue_rx = { .entry_num = RX_ENTRIES, .data_size = DATA_FRAME_SIZE, .desc_size = RXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_usb_rx), + .priv_size = sizeof(struct queue_entry_priv_usb), }; static const struct data_queue_desc rt73usb_queue_tx = { .entry_num = TX_ENTRIES, .data_size = DATA_FRAME_SIZE, .desc_size = TXD_DESC_SIZE, - .priv_size = sizeof(struct queue_entry_priv_usb_tx), + .priv_size = sizeof(struct queue_entry_priv_usb), }; static const struct data_queue_desc rt73usb_queue_bcn = { .entry_num = 4 * BEACON_ENTRIES, .data_size = MGMT_FRAME_SIZE, .desc_size = TXINFO_SIZE, - .priv_size = sizeof(struct queue_entry_priv_usb_tx), + .priv_size = sizeof(struct queue_entry_priv_usb), }; static const struct rt2x00_ops rt73usb_ops = { -- cgit v0.10.2 From aade5102c5390280e7ae8a43e09b8995792f66d8 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 10 May 2008 13:45:58 +0200 Subject: rt2x00: Remove extra + Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index b11f445..4fcba9b 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1042,7 +1042,7 @@ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, test_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags)); 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)); + test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags)); rt2x00_desc_write(txd, 0, word); } -- cgit v0.10.2 From f9d1cf53cf9e934f15ce0371b5fd568407032ea2 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 10 May 2008 13:45:50 +0200 Subject: rt2x00: Release rt2x00 2.1.6 Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 9c186d7..1900d4c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -44,7 +44,7 @@ /* * Module information. */ -#define DRV_VERSION "2.1.5" +#define DRV_VERSION "2.1.6" #define DRV_PROJECT "http://rt2x00.serialmonkey.com" /* -- cgit v0.10.2 From e37fc6e11c79899451e394319cff18cc53d6448d Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 20 May 2008 11:47:16 +0100 Subject: libertas: Increase priority of 'unknown command' warnings Using the deprecated lbs_prepare_and_send_command() function for a command which it doesn't understand is an error; complain loudly about it even when we're not debugging. The mesh stats bug, where we converted MESH_ACCESS to a direct command but accidentally missed one user which was still trying to do it through lbs_prepare_and_send_command(), would have been caught a lot quicker if we'd done this sooner. Such bugs aren't entirely unlikely in future too, as we convert more code to stop using this function. Signed-off-by: David Woodhouse Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index c2dd43e..bed68e9 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -1452,7 +1452,7 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action); break; default: - lbs_deb_host("PREP_CMD: unknown command 0x%04x\n", cmd_no); + lbs_pr_err("PREP_CMD: unknown command 0x%04x\n", cmd_no); ret = -1; break; } diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 5abecb7..9e50fdd 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -376,8 +376,8 @@ static inline int handle_cmd_response(struct lbs_private *priv, break; default: - lbs_deb_host("CMD_RESP: unknown cmd response 0x%04x\n", - le16_to_cpu(resp->command)); + lbs_pr_err("CMD_RESP: unknown cmd response 0x%04x\n", + le16_to_cpu(resp->command)); break; } lbs_deb_leave(LBS_DEB_HOST); -- cgit v0.10.2 From 75bf45a7b4ab81cfa5c5eab68b57bbfee8b8ede2 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 20 May 2008 13:32:45 +0100 Subject: libertas: fix multicast filtering on eth and msh interfaces We weren't properly handling multicast on the mesh interface. Fix that, which involves setting up the hardware to use the union of dev->mc_list for both eth%d and msh%d devices. This means we can't do it directly from ->set_multicast_list() because we'd need to lock the other device to read its list, and we can't do that because it might deadlock. So punt the actual work to keventd. Also, invoke the same when taking an interface down; for some reason the core calls ->set_multicast_list while IFF_UP is still set in dev->flags when we're taking it down, so its addresses don't get removed then. We also convert MAC_MULTICAST_ADR to a direct command while we're at it, removing one more entry from the big switch statement in the deprecated lbs_prepare_and_send_command() function. Signed-off-by: David Woodhouse Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index bed68e9..b494aba 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -746,28 +746,6 @@ out: return ret; } -static int lbs_cmd_mac_multicast_adr(struct lbs_private *priv, - struct cmd_ds_command *cmd, - u16 cmd_action) -{ - struct cmd_ds_mac_multicast_adr *pMCastAdr = &cmd->params.madr; - - lbs_deb_enter(LBS_DEB_CMD); - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_multicast_adr) + - S_DS_GEN); - cmd->command = cpu_to_le16(CMD_MAC_MULTICAST_ADR); - - lbs_deb_cmd("MULTICAST_ADR: setting %d addresses\n", pMCastAdr->nr_of_adrs); - pMCastAdr->action = cpu_to_le16(cmd_action); - pMCastAdr->nr_of_adrs = - cpu_to_le16((u16) priv->nr_of_multicastmacaddr); - memcpy(pMCastAdr->maclist, priv->multicastlist, - priv->nr_of_multicastmacaddr * ETH_ALEN); - - lbs_deb_leave(LBS_DEB_CMD); - return 0; -} - /** * @brief Get the radio channel * @@ -1247,8 +1225,7 @@ void lbs_set_mac_control(struct lbs_private *priv) cmd.action = cpu_to_le16(priv->mac_control); cmd.reserved = 0; - lbs_cmd_async(priv, CMD_MAC_CONTROL, - &cmd.hdr, sizeof(cmd)); + lbs_cmd_async(priv, CMD_MAC_CONTROL, &cmd.hdr, sizeof(cmd)); lbs_deb_leave(LBS_DEB_CMD); } @@ -1360,10 +1337,6 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, cmdptr, cmd_action); break; - case CMD_MAC_MULTICAST_ADR: - ret = lbs_cmd_mac_multicast_adr(priv, cmdptr, cmd_action); - break; - case CMD_802_11_MONITOR_MODE: ret = lbs_cmd_802_11_monitor_mode(cmdptr, cmd_action, pdata_buf); diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 9e50fdd..4c3c5ec 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -316,7 +316,6 @@ static inline int handle_cmd_response(struct lbs_private *priv, break; - case CMD_RET(CMD_MAC_MULTICAST_ADR): case CMD_RET(CMD_802_11_RESET): case CMD_RET(CMD_802_11_AUTHENTICATE): case CMD_RET(CMD_802_11_BEACON_STOP): diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 0d9edb9..e12ce65 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -140,6 +140,8 @@ struct lbs_private { wait_queue_head_t waitq; struct workqueue_struct *work_thread; + struct work_struct mcast_work; + /** Scanning */ struct delayed_work scan_work; struct delayed_work assoc_work; diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index f29bc5b..c36ab31 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -219,6 +219,7 @@ struct cmd_ds_mac_control { }; struct cmd_ds_mac_multicast_adr { + struct cmd_header hdr; __le16 action; __le16 nr_of_adrs; u8 maclist[ETH_ALEN * MRVDRV_MAX_MULTICAST_LIST_SIZE]; @@ -703,7 +704,6 @@ struct cmd_ds_command { struct cmd_ds_802_11_rf_antenna rant; struct cmd_ds_802_11_monitor_mode monitor; struct cmd_ds_802_11_rate_adapt_rateset rateset; - struct cmd_ds_mac_multicast_adr madr; struct cmd_ds_802_11_ad_hoc_join adj; struct cmd_ds_802_11_rssi rssi; struct cmd_ds_802_11_rssi_rsp rssirsp; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index e333f14..a87feba 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -446,6 +447,8 @@ static int lbs_mesh_stop(struct net_device *dev) spin_unlock_irq(&priv->driver_lock); + schedule_work(&priv->mcast_work); + lbs_deb_leave(LBS_DEB_MESH); return 0; } @@ -467,6 +470,8 @@ static int lbs_eth_stop(struct net_device *dev) netif_stop_queue(dev); spin_unlock_irq(&priv->driver_lock); + schedule_work(&priv->mcast_work); + lbs_deb_leave(LBS_DEB_NET); return 0; } @@ -563,89 +568,116 @@ done: return ret; } -static int lbs_copy_multicast_address(struct lbs_private *priv, - struct net_device *dev) + +static inline int mac_in_list(unsigned char *list, int list_len, + unsigned char *mac) { - int i = 0; - struct dev_mc_list *mcptr = dev->mc_list; + while (list_len) { + if (!memcmp(list, mac, ETH_ALEN)) + return 1; + list += ETH_ALEN; + list_len--; + } + return 0; +} + - for (i = 0; i < dev->mc_count; i++) { - memcpy(&priv->multicastlist[i], mcptr->dmi_addr, ETH_ALEN); - mcptr = mcptr->next; +static int lbs_add_mcast_addrs(struct cmd_ds_mac_multicast_adr *cmd, + struct net_device *dev, int nr_addrs) +{ + int i = nr_addrs; + struct dev_mc_list *mc_list; + DECLARE_MAC_BUF(mac); + + if ((dev->flags & (IFF_UP|IFF_MULTICAST)) != (IFF_UP|IFF_MULTICAST)) + return nr_addrs; + + netif_tx_lock_bh(dev); + for (mc_list = dev->mc_list; mc_list; mc_list = mc_list->next) { + if (mac_in_list(cmd->maclist, nr_addrs, mc_list->dmi_addr)) { + lbs_deb_net("mcast address %s:%s skipped\n", dev->name, + print_mac(mac, mc_list->dmi_addr)); + continue; + } + + if (i == MRVDRV_MAX_MULTICAST_LIST_SIZE) + break; + memcpy(&cmd->maclist[6*i], mc_list->dmi_addr, ETH_ALEN); + lbs_deb_net("mcast address %s:%s added to filter\n", dev->name, + print_mac(mac, mc_list->dmi_addr)); + i++; } + netif_tx_unlock_bh(dev); + if (mc_list) + return -EOVERFLOW; + return i; } -static void lbs_set_multicast_list(struct net_device *dev) +static void lbs_set_mcast_worker(struct work_struct *work) { - struct lbs_private *priv = dev->priv; - int old_mac_control; - DECLARE_MAC_BUF(mac); + struct lbs_private *priv = container_of(work, struct lbs_private, mcast_work); + struct cmd_ds_mac_multicast_adr mcast_cmd; + int dev_flags; + int nr_addrs; + int old_mac_control = priv->mac_control; lbs_deb_enter(LBS_DEB_NET); - old_mac_control = priv->mac_control; - - if (dev->flags & IFF_PROMISC) { - lbs_deb_net("enable promiscuous mode\n"); - priv->mac_control |= - CMD_ACT_MAC_PROMISCUOUS_ENABLE; - priv->mac_control &= - ~(CMD_ACT_MAC_ALL_MULTICAST_ENABLE | - CMD_ACT_MAC_MULTICAST_ENABLE); - } else { - /* Multicast */ - priv->mac_control &= - ~CMD_ACT_MAC_PROMISCUOUS_ENABLE; - - if (dev->flags & IFF_ALLMULTI || dev->mc_count > - MRVDRV_MAX_MULTICAST_LIST_SIZE) { - lbs_deb_net( "enabling all multicast\n"); - priv->mac_control |= - CMD_ACT_MAC_ALL_MULTICAST_ENABLE; - priv->mac_control &= - ~CMD_ACT_MAC_MULTICAST_ENABLE; - } else { - priv->mac_control &= - ~CMD_ACT_MAC_ALL_MULTICAST_ENABLE; - - if (!dev->mc_count) { - lbs_deb_net("no multicast addresses, " - "disabling multicast\n"); - priv->mac_control &= - ~CMD_ACT_MAC_MULTICAST_ENABLE; - } else { - int i; - - priv->mac_control |= - CMD_ACT_MAC_MULTICAST_ENABLE; - - priv->nr_of_multicastmacaddr = - lbs_copy_multicast_address(priv, dev); - - lbs_deb_net("multicast addresses: %d\n", - dev->mc_count); - - for (i = 0; i < dev->mc_count; i++) { - lbs_deb_net("Multicast address %d: %s\n", - i, print_mac(mac, - priv->multicastlist[i])); - } - /* send multicast addresses to firmware */ - lbs_prepare_and_send_command(priv, - CMD_MAC_MULTICAST_ADR, - CMD_ACT_SET, 0, 0, - NULL); - } - } + dev_flags = priv->dev->flags; + if (priv->mesh_dev) + dev_flags |= priv->mesh_dev->flags; + + if (dev_flags & IFF_PROMISC) { + priv->mac_control |= CMD_ACT_MAC_PROMISCUOUS_ENABLE; + priv->mac_control &= ~(CMD_ACT_MAC_ALL_MULTICAST_ENABLE | + CMD_ACT_MAC_MULTICAST_ENABLE); + goto out_set_mac_control; + } else if (dev_flags & IFF_ALLMULTI) { + do_allmulti: + priv->mac_control |= CMD_ACT_MAC_ALL_MULTICAST_ENABLE; + priv->mac_control &= ~(CMD_ACT_MAC_PROMISCUOUS_ENABLE | + CMD_ACT_MAC_MULTICAST_ENABLE); + goto out_set_mac_control; } + /* Once for priv->dev, again for priv->mesh_dev if it exists */ + nr_addrs = lbs_add_mcast_addrs(&mcast_cmd, priv->dev, 0); + if (nr_addrs >= 0 && priv->mesh_dev) + nr_addrs = lbs_add_mcast_addrs(&mcast_cmd, priv->mesh_dev, nr_addrs); + if (nr_addrs < 0) + goto do_allmulti; + + if (nr_addrs) { + int size = offsetof(struct cmd_ds_mac_multicast_adr, + maclist[6*nr_addrs]); + + mcast_cmd.action = cpu_to_le16(CMD_ACT_SET); + mcast_cmd.hdr.size = cpu_to_le16(size); + mcast_cmd.nr_of_adrs = cpu_to_le16(nr_addrs); + + lbs_cmd_async(priv, CMD_MAC_MULTICAST_ADR, &mcast_cmd.hdr, size); + + priv->mac_control |= CMD_ACT_MAC_MULTICAST_ENABLE; + } else + priv->mac_control &= ~CMD_ACT_MAC_MULTICAST_ENABLE; + + priv->mac_control &= ~(CMD_ACT_MAC_PROMISCUOUS_ENABLE | + CMD_ACT_MAC_ALL_MULTICAST_ENABLE); + out_set_mac_control: if (priv->mac_control != old_mac_control) lbs_set_mac_control(priv); lbs_deb_leave(LBS_DEB_NET); } +static void lbs_set_multicast_list(struct net_device *dev) +{ + struct lbs_private *priv = dev->priv; + + schedule_work(&priv->mcast_work); +} + /** * @brief This function handles the major jobs in the LBS driver. * It handles all events generated by firmware, RX data received @@ -1122,6 +1154,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) priv->work_thread = create_singlethread_workqueue("lbs_worker"); INIT_DELAYED_WORK(&priv->assoc_work, lbs_association_worker); INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker); + INIT_WORK(&priv->mcast_work, lbs_set_mcast_worker); INIT_WORK(&priv->sync_channel, lbs_sync_channel_worker); sprintf(priv->mesh_ssid, "mesh"); @@ -1158,6 +1191,7 @@ void lbs_remove_card(struct lbs_private *priv) cancel_delayed_work_sync(&priv->scan_work); cancel_delayed_work_sync(&priv->assoc_work); + cancel_work_sync(&priv->mcast_work); destroy_workqueue(priv->work_thread); if (priv->psmode == LBS802_11POWERMODEMAX_PSP) { @@ -1322,6 +1356,8 @@ static int lbs_add_mesh(struct lbs_private *priv) #ifdef WIRELESS_EXT mesh_dev->wireless_handlers = (struct iw_handler_def *)&mesh_handler_def; #endif + mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST; + mesh_dev->set_multicast_list = lbs_set_multicast_list; /* Register virtual mesh interface */ ret = register_netdev(mesh_dev); if (ret) { @@ -1554,7 +1590,6 @@ static int lbs_add_rtap(struct lbs_private *priv) rtap_dev->stop = lbs_rtap_stop; rtap_dev->get_stats = lbs_rtap_get_stats; rtap_dev->hard_start_xmit = lbs_rtap_hard_start_xmit; - rtap_dev->set_multicast_list = lbs_set_multicast_list; rtap_dev->priv = priv; ret = register_netdev(rtap_dev); -- cgit v0.10.2 From edaea5ce05ca804cc55438c586ca2f947d49f56f Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Sat, 17 May 2008 00:55:10 -0700 Subject: libertas: Extend MESH_CONFIG command to access non-volatile configuration This patch is based on a patch from Shailendra Govardhan and Brian Cavagnolo. It extends the MESH_CONFIG command to configure non-volatile parameters on libertas devices that support them (e.g. OLPC Active Antenna). This patch only implements the driver/firmware interface. See http://dev.laptop.org/ticket/6823 for minimal testing results and known issues. Signed-off-by: Javier Cardona Signed-off-by: David Woodhouse Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index c9c3640..953a44f 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -603,7 +603,8 @@ static int assoc_helper_channel(struct lbs_private *priv, /* Change mesh channel first; 21.p21 firmware won't let you change channel otherwise (even though it'll return an error to this */ - lbs_mesh_config(priv, 0, assoc_req->channel); + lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, + assoc_req->channel); } lbs_deb_assoc("ASSOC: channel: %d -> %d\n", @@ -642,7 +643,8 @@ static int assoc_helper_channel(struct lbs_private *priv, restore_mesh: if (priv->mesh_dev) - lbs_mesh_config(priv, 1, priv->curbssparams.channel); + lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, + priv->curbssparams.channel); done: lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index b494aba..7ccec98 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -4,6 +4,7 @@ */ #include +#include #include #include "host.h" #include "hostcmd.h" @@ -998,24 +999,69 @@ int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action, return ret; } -int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan) +int lbs_mesh_config_send(struct lbs_private *priv, + struct cmd_ds_mesh_config *cmd, + uint16_t action, uint16_t type) +{ + int ret; + + lbs_deb_enter(LBS_DEB_CMD); + + cmd->hdr.command = cpu_to_le16(CMD_MESH_CONFIG); + cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_mesh_config)); + cmd->hdr.result = 0; + + cmd->type = cpu_to_le16(type); + cmd->action = cpu_to_le16(action); + + ret = lbs_cmd_with_response(priv, CMD_MESH_CONFIG, cmd); + + lbs_deb_leave(LBS_DEB_CMD); + return ret; +} + +/* This function is the CMD_MESH_CONFIG legacy function. It only handles the + * START and STOP actions. The extended actions supported by CMD_MESH_CONFIG + * are all handled by preparing a struct cmd_ds_mesh_config and passing it to + * lbs_mesh_config_send. + */ +int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan) { struct cmd_ds_mesh_config cmd; + struct mrvl_meshie *ie; memset(&cmd, 0, sizeof(cmd)); - cmd.action = cpu_to_le16(enable); cmd.channel = cpu_to_le16(chan); - cmd.type = cpu_to_le16(priv->mesh_tlv); - cmd.hdr.size = cpu_to_le16(sizeof(cmd)); - - if (enable) { - cmd.length = cpu_to_le16(priv->mesh_ssid_len); - memcpy(cmd.data, priv->mesh_ssid, priv->mesh_ssid_len); + ie = (struct mrvl_meshie *)cmd.data; + + switch (action) { + case CMD_ACT_MESH_CONFIG_START: + ie->hdr.id = MFIE_TYPE_GENERIC; + ie->val.oui[0] = 0x00; + ie->val.oui[1] = 0x50; + ie->val.oui[2] = 0x43; + ie->val.type = MARVELL_MESH_IE_TYPE; + ie->val.subtype = MARVELL_MESH_IE_SUBTYPE; + ie->val.version = MARVELL_MESH_IE_VERSION; + ie->val.active_protocol_id = MARVELL_MESH_PROTO_ID_HWMP; + ie->val.active_metric_id = MARVELL_MESH_METRIC_ID; + ie->val.mesh_capability = MARVELL_MESH_CAPABILITY; + ie->val.mesh_id_len = priv->mesh_ssid_len; + memcpy(ie->val.mesh_id, priv->mesh_ssid, priv->mesh_ssid_len); + ie->hdr.len = sizeof(struct mrvl_meshie_val) - + IW_ESSID_MAX_SIZE + priv->mesh_ssid_len; + cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val)); + break; + case CMD_ACT_MESH_CONFIG_STOP: + break; + default: + return -1; } - lbs_deb_cmd("mesh config enable %d TLV %x channel %d SSID %s\n", - enable, priv->mesh_tlv, chan, + lbs_deb_cmd("mesh config action %d type %x channel %d SSID %s\n", + action, priv->mesh_tlv, chan, escape_essid(priv->mesh_ssid, priv->mesh_ssid_len)); - return lbs_cmd_with_response(priv, CMD_MESH_CONFIG, &cmd); + + return lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv); } static int lbs_cmd_bcn_ctrl(struct lbs_private * priv, diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h index f4019c2..00d290e 100644 --- a/drivers/net/wireless/libertas/cmd.h +++ b/drivers/net/wireless/libertas/cmd.h @@ -39,6 +39,9 @@ int lbs_set_data_rate(struct lbs_private *priv, u8 rate); int lbs_get_channel(struct lbs_private *priv); int lbs_set_channel(struct lbs_private *priv, u8 channel); +int lbs_mesh_config_send(struct lbs_private *priv, + struct cmd_ds_mesh_config *cmd, + uint16_t action, uint16_t type); int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan); int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria); diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index d395201..3793cb9 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h @@ -170,6 +170,16 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in #define MARVELL_MESH_IE_LENGTH 9 +/* Values used to populate the struct mrvl_mesh_ie. The only time you need this + * is when enabling the mesh using CMD_MESH_CONFIG. + */ +#define MARVELL_MESH_IE_TYPE 4 +#define MARVELL_MESH_IE_SUBTYPE 0 +#define MARVELL_MESH_IE_VERSION 0 +#define MARVELL_MESH_PROTO_ID_HWMP 0 +#define MARVELL_MESH_METRIC_ID 0 +#define MARVELL_MESH_CAPABILITY 0 + /** INT status Bit Definition*/ #define MRVDRV_TX_DNLD_RDY 0x0001 #define MRVDRV_RX_UPLD_RDY 0x0002 diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index 3915c31..c92e41b 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -256,6 +256,23 @@ enum cmd_mesh_access_opts { CMD_ACT_MESH_GET_AUTOSTART_ENABLED, }; +/* Define actions and types for CMD_MESH_CONFIG */ +enum cmd_mesh_config_actions { + CMD_ACT_MESH_CONFIG_STOP = 0, + CMD_ACT_MESH_CONFIG_START, + CMD_ACT_MESH_CONFIG_SET, + CMD_ACT_MESH_CONFIG_GET, +}; + +enum cmd_mesh_config_types { + CMD_TYPE_MESH_SET_BOOTFLAG = 1, + CMD_TYPE_MESH_SET_BOOTTIME, + CMD_TYPE_MESH_SET_DEF_CHANNEL, + CMD_TYPE_MESH_SET_MESH_IE, + CMD_TYPE_MESH_GET_DEFAULTS, + CMD_TYPE_MESH_GET_MESH_IE, /* GET_DEFAULTS is superset of GET_MESHIE */ +}; + /** Card Event definition */ #define MACREG_INT_CODE_TX_PPA_FREE 0 #define MACREG_INT_CODE_TX_DMA_DONE 1 diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index a87feba..01299c8 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -344,14 +344,15 @@ static ssize_t lbs_mesh_set(struct device *dev, { struct lbs_private *priv = to_net_dev(dev)->priv; int enable; - int ret; + int ret, action = CMD_ACT_MESH_CONFIG_STOP; sscanf(buf, "%x", &enable); enable = !!enable; if (enable == !!priv->mesh_dev) return count; - - ret = lbs_mesh_config(priv, enable, priv->curbssparams.channel); + if (enable) + action = CMD_ACT_MESH_CONFIG_START; + ret = lbs_mesh_config(priv, action, priv->curbssparams.channel); if (ret) return ret; @@ -1257,9 +1258,11 @@ int lbs_start_card(struct lbs_private *priv) useful */ priv->mesh_tlv = 0x100 + 291; - if (lbs_mesh_config(priv, 1, priv->curbssparams.channel)) { + if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, + priv->curbssparams.channel)) { priv->mesh_tlv = 0x100 + 37; - if (lbs_mesh_config(priv, 1, priv->curbssparams.channel)) + if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, + priv->curbssparams.channel)) priv->mesh_tlv = 0; } if (priv->mesh_tlv) { diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h index 4031be4..e0c2599 100644 --- a/drivers/net/wireless/libertas/types.h +++ b/drivers/net/wireless/libertas/types.h @@ -6,6 +6,8 @@ #include #include +#include +#include struct ieeetypes_cfparamset { u8 elementid; @@ -252,4 +254,32 @@ struct mrvlietypes_ledbhv { struct led_bhv ledbhv[1]; } __attribute__ ((packed)); +/* Meant to be packed as the value member of a struct ieee80211_info_element. + * Note that the len member of the ieee80211_info_element varies depending on + * the mesh_id_len */ +struct mrvl_meshie_val { + uint8_t oui[P80211_OUI_LEN]; + uint8_t type; + uint8_t subtype; + uint8_t version; + uint8_t active_protocol_id; + uint8_t active_metric_id; + uint8_t mesh_capability; + uint8_t mesh_id_len; + uint8_t mesh_id[IW_ESSID_MAX_SIZE]; +} __attribute__ ((packed)); + +struct mrvl_meshie { + struct ieee80211_info_element hdr; + struct mrvl_meshie_val val; +} __attribute__ ((packed)); + +struct mrvl_mesh_defaults { + __le32 bootflag; + uint8_t boottime; + uint8_t reserved; + __le16 channel; + struct mrvl_meshie meshie; +} __attribute__ ((packed)); + #endif diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 0973d01..d4b19f1 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -1002,7 +1002,7 @@ static int lbs_mesh_set_freq(struct net_device *dev, else if (priv->mode == IW_MODE_ADHOC) lbs_stop_adhoc_network(priv); } - lbs_mesh_config(priv, 1, fwrq->m); + lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, fwrq->m); lbs_update_channel(priv); ret = 0; @@ -2011,7 +2011,8 @@ static int lbs_mesh_set_essid(struct net_device *dev, priv->mesh_ssid_len = dwrq->length; } - lbs_mesh_config(priv, 1, priv->curbssparams.channel); + lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, + priv->curbssparams.channel); out: lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); return ret; -- cgit v0.10.2 From 15dbaac03e862ee746310832c8d8d694dc0427ee Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Sat, 17 May 2008 21:01:24 -0700 Subject: libertas: sysfs interface for accessing non-volatile configuration This will create the following sysfs directories: /sys/class/net/mshX ... |-- boot_options | |-- bootflag | `-- boottime ... |-- mesh_ie | |-- capability | |-- mesh_id | |-- metric_id | `-- protocol_id Signed-off-by: Javier Cardona Signed-off-by: David Woodhouse Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile index f0724e3..02080a3 100644 --- a/drivers/net/wireless/libertas/Makefile +++ b/drivers/net/wireless/libertas/Makefile @@ -1,9 +1,5 @@ -libertas-objs := main.o wext.o \ - rx.o tx.o cmd.o \ - cmdresp.o scan.o \ - 11d.o \ - debugfs.o \ - ethtool.o assoc.o +libertas-objs := main.o wext.o rx.o tx.o cmd.o cmdresp.o scan.o 11d.o \ + debugfs.o persistcfg.o ethtool.o assoc.o usb8xxx-objs += if_usb.o libertas_cs-objs += if_cs.o diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h index 0632b09..a8ac974 100644 --- a/drivers/net/wireless/libertas/decl.h +++ b/drivers/net/wireless/libertas/decl.h @@ -60,6 +60,10 @@ void lbs_mac_event_disconnected(struct lbs_private *priv); void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str); +/* persistcfg.c */ +void lbs_persist_config_init(struct net_device *net); +void lbs_persist_config_remove(struct net_device *net); + /* main.c */ struct chan_freq_power *lbs_get_region_cfp_table(u8 region, int *cfp_no); diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index 3793cb9..12e6875 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h @@ -40,6 +40,7 @@ #define LBS_DEB_THREAD 0x00100000 #define LBS_DEB_HEX 0x00200000 #define LBS_DEB_SDIO 0x00400000 +#define LBS_DEB_SYSFS 0x00800000 extern unsigned int lbs_debug; @@ -81,7 +82,8 @@ do { if ((lbs_debug & (grp)) == (grp)) \ #define lbs_deb_usbd(dev, fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usbd", "%s:" fmt, (dev)->bus_id, ##args) #define lbs_deb_cs(fmt, args...) LBS_DEB_LL(LBS_DEB_CS, " cs", fmt, ##args) #define lbs_deb_thread(fmt, args...) LBS_DEB_LL(LBS_DEB_THREAD, " thread", fmt, ##args) -#define lbs_deb_sdio(fmt, args...) LBS_DEB_LL(LBS_DEB_SDIO, " thread", fmt, ##args) +#define lbs_deb_sdio(fmt, args...) LBS_DEB_LL(LBS_DEB_SDIO, " sdio", fmt, ##args) +#define lbs_deb_sysfs(fmt, args...) LBS_DEB_LL(LBS_DEB_SYSFS, " sysfs", fmt, ##args) #define lbs_pr_info(format, args...) \ printk(KERN_INFO DRV_NAME": " format, ## args) diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 01299c8..db246d0 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1302,8 +1302,9 @@ void lbs_stop_card(struct lbs_private *priv) lbs_debugfs_remove_one(priv); device_remove_file(&dev->dev, &dev_attr_lbs_rtap); - if (priv->mesh_tlv) + if (priv->mesh_tlv) { device_remove_file(&dev->dev, &dev_attr_lbs_mesh); + } /* Flush pending command nodes */ del_timer_sync(&priv->command_timer); @@ -1372,6 +1373,8 @@ static int lbs_add_mesh(struct lbs_private *priv) if (ret) goto err_unregister; + lbs_persist_config_init(mesh_dev); + /* Everything successful */ ret = 0; goto done; @@ -1398,8 +1401,9 @@ static void lbs_remove_mesh(struct lbs_private *priv) lbs_deb_enter(LBS_DEB_MESH); netif_stop_queue(mesh_dev); - netif_carrier_off(priv->mesh_dev); + netif_carrier_off(mesh_dev); sysfs_remove_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group); + lbs_persist_config_remove(mesh_dev); unregister_netdev(mesh_dev); priv->mesh_dev = NULL; free_netdev(mesh_dev); diff --git a/drivers/net/wireless/libertas/persistcfg.c b/drivers/net/wireless/libertas/persistcfg.c new file mode 100644 index 0000000..baa6627 --- /dev/null +++ b/drivers/net/wireless/libertas/persistcfg.c @@ -0,0 +1,408 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "host.h" +#include "decl.h" +#include "dev.h" +#include "wext.h" +#include "debugfs.h" +#include "scan.h" +#include "assoc.h" +#include "cmd.h" + +static int mesh_get_default_parameters(struct device *dev, + struct mrvl_mesh_defaults *defs) +{ + struct lbs_private *priv = to_net_dev(dev)->priv; + struct cmd_ds_mesh_config cmd; + int ret; + + memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config)); + ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_GET, + CMD_TYPE_MESH_GET_DEFAULTS); + + if (ret) + return -EOPNOTSUPP; + + memcpy(defs, &cmd.data[0], sizeof(struct mrvl_mesh_defaults)); + + return 0; +} + +/** + * @brief Get function for sysfs attribute bootflag + */ +static ssize_t bootflag_get(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mrvl_mesh_defaults defs; + int ret; + + ret = mesh_get_default_parameters(dev, &defs); + + if (ret) + return ret; + + return snprintf(buf, 12, "0x%x\n", le32_to_cpu(defs.bootflag)); +} + +/** + * @brief Set function for sysfs attribute bootflag + */ +static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct lbs_private *priv = to_net_dev(dev)->priv; + struct cmd_ds_mesh_config cmd; + uint32_t datum; + int ret; + + memset(&cmd, 0, sizeof(cmd)); + ret = sscanf(buf, "%x", &datum); + if (ret != 1) + return -EINVAL; + + *((__le32 *)&cmd.data[0]) = cpu_to_le32(!!datum); + cmd.length = cpu_to_le16(sizeof(uint32_t)); + ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, + CMD_TYPE_MESH_SET_BOOTFLAG); + if (ret) + return ret; + + return strlen(buf); +} + +/** + * @brief Get function for sysfs attribute boottime + */ +static ssize_t boottime_get(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mrvl_mesh_defaults defs; + int ret; + + ret = mesh_get_default_parameters(dev, &defs); + + if (ret) + return ret; + + return snprintf(buf, 12, "0x%x\n", defs.boottime); +} + +/** + * @brief Set function for sysfs attribute boottime + */ +static ssize_t boottime_set(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct lbs_private *priv = to_net_dev(dev)->priv; + struct cmd_ds_mesh_config cmd; + uint32_t datum; + int ret; + + memset(&cmd, 0, sizeof(cmd)); + ret = sscanf(buf, "%x", &datum); + if (ret != 1) + return -EINVAL; + + /* A too small boot time will result in the device booting into + * standalone (no-host) mode before the host can take control of it, + * so the change will be hard to revert. This may be a desired + * feature (e.g to configure a very fast boot time for devices that + * will not be attached to a host), but dangerous. So I'm enforcing a + * lower limit of 20 seconds: remove and recompile the driver if this + * does not work for you. + */ + datum = (datum < 20) ? 20 : datum; + cmd.data[0] = datum; + cmd.length = cpu_to_le16(sizeof(uint8_t)); + ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, + CMD_TYPE_MESH_SET_BOOTTIME); + if (ret) + return ret; + + return strlen(buf); +} + +/** + * @brief Get function for sysfs attribute mesh_id + */ +static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct mrvl_mesh_defaults defs; + int maxlen; + int ret; + + ret = mesh_get_default_parameters(dev, &defs); + + if (ret) + return ret; + + if (defs.meshie.val.mesh_id_len > IW_ESSID_MAX_SIZE) { + printk(KERN_ERR "Inconsistent mesh ID length"); + defs.meshie.val.mesh_id_len = IW_ESSID_MAX_SIZE; + } + + /* SSID not null terminated: reserve room for \0 + \n */ + maxlen = defs.meshie.val.mesh_id_len + 2; + maxlen = (PAGE_SIZE > maxlen) ? maxlen : PAGE_SIZE; + + defs.meshie.val.mesh_id[defs.meshie.val.mesh_id_len] = '\0'; + + return snprintf(buf, maxlen, "%s\n", defs.meshie.val.mesh_id); +} + +/** + * @brief Set function for sysfs attribute mesh_id + */ +static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct cmd_ds_mesh_config cmd; + struct mrvl_mesh_defaults defs; + struct mrvl_meshie *ie; + struct lbs_private *priv = to_net_dev(dev)->priv; + int len; + int ret; + + if (count < 2 || count > IW_ESSID_MAX_SIZE + 1) + return -EINVAL; + + memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config)); + ie = (struct mrvl_meshie *) &cmd.data[0]; + + /* fetch all other Information Element parameters */ + ret = mesh_get_default_parameters(dev, &defs); + + cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie)); + + /* transfer IE elements */ + memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie)); + + len = count - 1; + memcpy(ie->val.mesh_id, buf, len); + /* SSID len */ + ie->val.mesh_id_len = len; + /* IE len */ + ie->hdr.len = sizeof(struct mrvl_meshie_val) - IW_ESSID_MAX_SIZE + len; + + ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, + CMD_TYPE_MESH_SET_MESH_IE); + if (ret) + return ret; + + return strlen(buf); +} + +/** + * @brief Get function for sysfs attribute protocol_id + */ +static ssize_t protocol_id_get(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mrvl_mesh_defaults defs; + int ret; + + ret = mesh_get_default_parameters(dev, &defs); + + if (ret) + return ret; + + return snprintf(buf, 5, "%d\n", defs.meshie.val.active_protocol_id); +} + +/** + * @brief Set function for sysfs attribute protocol_id + */ +static ssize_t protocol_id_set(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct cmd_ds_mesh_config cmd; + struct mrvl_mesh_defaults defs; + struct mrvl_meshie *ie; + struct lbs_private *priv = to_net_dev(dev)->priv; + uint32_t datum; + int ret; + + memset(&cmd, 0, sizeof(cmd)); + ret = sscanf(buf, "%x", &datum); + if (ret != 1) + return -EINVAL; + + /* fetch all other Information Element parameters */ + ret = mesh_get_default_parameters(dev, &defs); + + cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie)); + + /* transfer IE elements */ + ie = (struct mrvl_meshie *) &cmd.data[0]; + memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie)); + /* update protocol id */ + ie->val.active_protocol_id = datum; + + ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, + CMD_TYPE_MESH_SET_MESH_IE); + if (ret) + return ret; + + return strlen(buf); +} + +/** + * @brief Get function for sysfs attribute metric_id + */ +static ssize_t metric_id_get(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mrvl_mesh_defaults defs; + int ret; + + ret = mesh_get_default_parameters(dev, &defs); + + if (ret) + return ret; + + return snprintf(buf, 5, "%d\n", defs.meshie.val.active_metric_id); +} + +/** + * @brief Set function for sysfs attribute metric_id + */ +static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct cmd_ds_mesh_config cmd; + struct mrvl_mesh_defaults defs; + struct mrvl_meshie *ie; + struct lbs_private *priv = to_net_dev(dev)->priv; + uint32_t datum; + int ret; + + memset(&cmd, 0, sizeof(cmd)); + ret = sscanf(buf, "%x", &datum); + if (ret != 1) + return -EINVAL; + + /* fetch all other Information Element parameters */ + ret = mesh_get_default_parameters(dev, &defs); + + cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie)); + + /* transfer IE elements */ + ie = (struct mrvl_meshie *) &cmd.data[0]; + memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie)); + /* update metric id */ + ie->val.active_metric_id = datum; + + ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, + CMD_TYPE_MESH_SET_MESH_IE); + if (ret) + return ret; + + return strlen(buf); +} + +/** + * @brief Get function for sysfs attribute capability + */ +static ssize_t capability_get(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mrvl_mesh_defaults defs; + int ret; + + ret = mesh_get_default_parameters(dev, &defs); + + if (ret) + return ret; + + return snprintf(buf, 5, "%d\n", defs.meshie.val.mesh_capability); +} + +/** + * @brief Set function for sysfs attribute capability + */ +static ssize_t capability_set(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct cmd_ds_mesh_config cmd; + struct mrvl_mesh_defaults defs; + struct mrvl_meshie *ie; + struct lbs_private *priv = to_net_dev(dev)->priv; + uint32_t datum; + int ret; + + memset(&cmd, 0, sizeof(cmd)); + ret = sscanf(buf, "%x", &datum); + if (ret != 1) + return -EINVAL; + + /* fetch all other Information Element parameters */ + ret = mesh_get_default_parameters(dev, &defs); + + cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie)); + + /* transfer IE elements */ + ie = (struct mrvl_meshie *) &cmd.data[0]; + memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie)); + /* update value */ + ie->val.mesh_capability = datum; + + ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, + CMD_TYPE_MESH_SET_MESH_IE); + if (ret) + return ret; + + return strlen(buf); +} + + +static DEVICE_ATTR(bootflag, 0644, bootflag_get, bootflag_set); +static DEVICE_ATTR(boottime, 0644, boottime_get, boottime_set); +static DEVICE_ATTR(mesh_id, 0644, mesh_id_get, mesh_id_set); +static DEVICE_ATTR(protocol_id, 0644, protocol_id_get, protocol_id_set); +static DEVICE_ATTR(metric_id, 0644, metric_id_get, metric_id_set); +static DEVICE_ATTR(capability, 0644, capability_get, capability_set); + +static struct attribute *boot_opts_attrs[] = { + &dev_attr_bootflag.attr, + &dev_attr_boottime.attr, + NULL +}; + +static struct attribute_group boot_opts_group = { + .name = "boot_options", + .attrs = boot_opts_attrs, +}; + +static struct attribute *mesh_ie_attrs[] = { + &dev_attr_mesh_id.attr, + &dev_attr_protocol_id.attr, + &dev_attr_metric_id.attr, + &dev_attr_capability.attr, + NULL +}; + +static struct attribute_group mesh_ie_group = { + .name = "mesh_ie", + .attrs = mesh_ie_attrs, +}; + +void lbs_persist_config_init(struct net_device *dev) +{ + int ret; + ret = sysfs_create_group(&(dev->dev.kobj), &boot_opts_group); + ret = sysfs_create_group(&(dev->dev.kobj), &mesh_ie_group); +} + +void lbs_persist_config_remove(struct net_device *dev) +{ + sysfs_remove_group(&(dev->dev.kobj), &boot_opts_group); + sysfs_remove_group(&(dev->dev.kobj), &mesh_ie_group); +} -- cgit v0.10.2 From edf5dabfa86163d589041cccf607b41a7033e9b0 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 20 May 2008 16:43:31 +0100 Subject: libertas: Add reset_card() callback to hardware driver Signed-off-by: David Woodhouse Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index e12ce65..0a9fc51 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -153,6 +153,7 @@ struct lbs_private { /** Hardware access */ int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb); + void (*reset_card) (struct lbs_private *priv); /* Wake On LAN */ uint32_t wol_criteria; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index db246d0..804da36 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -787,6 +787,11 @@ static int lbs_thread(void *data) le16_to_cpu(cmdnode->cmdbuf->command)); lbs_complete_command(priv, cmdnode, -ETIMEDOUT); priv->nr_retries = 0; + if (priv->reset_card) { + spin_unlock_irq(&priv->driver_lock); + priv->reset_card(priv); + spin_lock_irq(&priv->driver_lock); + } } else { priv->cur_cmd = NULL; lbs_pr_info("requeueing command %x due to timeout (#%d)\n", -- cgit v0.10.2 From b679aeb304e3070626750c15e043a40da0e942fc Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Tue, 20 May 2008 15:18:49 -0700 Subject: libertas: sysfs interface for accessing default mesh channel This will create the following entry: /sys/class/net/mshX -- boot_options | |-- ... | `-- channel ... ... which I overlooked on my previous patch. Signed-off-by: Javier Cardona Signed-off-by: David Woodhouse Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/persistcfg.c b/drivers/net/wireless/libertas/persistcfg.c index baa6627..6cf5e39 100644 --- a/drivers/net/wireless/libertas/persistcfg.c +++ b/drivers/net/wireless/libertas/persistcfg.c @@ -130,6 +130,49 @@ static ssize_t boottime_set(struct device *dev, } /** + * @brief Get function for sysfs attribute channel + */ +static ssize_t channel_get(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mrvl_mesh_defaults defs; + int ret; + + ret = mesh_get_default_parameters(dev, &defs); + + if (ret) + return ret; + + return snprintf(buf, 12, "0x%x\n", le16_to_cpu(defs.channel)); +} + +/** + * @brief Set function for sysfs attribute channel + */ +static ssize_t channel_set(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct lbs_private *priv = to_net_dev(dev)->priv; + struct cmd_ds_mesh_config cmd; + uint16_t datum; + int ret; + + memset(&cmd, 0, sizeof(cmd)); + ret = sscanf(buf, "%hx", &datum); + if (ret != 1 || datum < 1 || datum > 11) + return -EINVAL; + + *((__le16 *)&cmd.data[0]) = cpu_to_le16(datum); + cmd.length = cpu_to_le16(sizeof(uint16_t)); + ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, + CMD_TYPE_MESH_SET_DEF_CHANNEL); + if (ret) + return ret; + + return strlen(buf); +} + +/** * @brief Get function for sysfs attribute mesh_id */ static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr, @@ -365,6 +408,7 @@ static ssize_t capability_set(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR(bootflag, 0644, bootflag_get, bootflag_set); static DEVICE_ATTR(boottime, 0644, boottime_get, boottime_set); +static DEVICE_ATTR(channel, 0644, channel_get, channel_set); static DEVICE_ATTR(mesh_id, 0644, mesh_id_get, mesh_id_set); static DEVICE_ATTR(protocol_id, 0644, protocol_id_get, protocol_id_set); static DEVICE_ATTR(metric_id, 0644, metric_id_get, metric_id_set); @@ -373,6 +417,7 @@ static DEVICE_ATTR(capability, 0644, capability_get, capability_set); static struct attribute *boot_opts_attrs[] = { &dev_attr_bootflag.attr, &dev_attr_boottime.attr, + &dev_attr_channel.attr, NULL }; -- cgit v0.10.2 From 402d7752ed253369b7ab037e2d778e52d59c19ed Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Tue, 6 May 2008 18:53:43 +0400 Subject: mac80211: Brush up error paths in mesh_path_add. There are already tree paths, that do incremental rollbacks, so merge them together, rename labels and format the code to look a bit nicer. (I do not mind dropping/delaying this patch however). Signed-off-by: Pavel Emelyanov Signed-off-by: John W. Linville diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 99c2d36..7097ef9 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -158,19 +158,14 @@ int mesh_path_add(u8 *dst, struct net_device *dev) if (atomic_add_unless(&sdata->u.sta.mpaths, 1, MESH_MAX_MPATHS) == 0) return -ENOSPC; + err = -ENOMEM; new_mpath = kzalloc(sizeof(struct mesh_path), GFP_KERNEL); - if (!new_mpath) { - atomic_dec(&sdata->u.sta.mpaths); - err = -ENOMEM; - goto endadd2; - } + if (!new_mpath) + goto err_path_alloc; + new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL); - if (!new_node) { - kfree(new_mpath); - atomic_dec(&sdata->u.sta.mpaths); - err = -ENOMEM; - goto endadd2; - } + if (!new_node) + goto err_node_alloc; read_lock(&pathtbl_resize_lock); memcpy(new_mpath->dst, dst, ETH_ALEN); @@ -189,16 +184,11 @@ int mesh_path_add(u8 *dst, struct net_device *dev) spin_lock(&mesh_paths->hashwlock[hash_idx]); + err = -EEXIST; hlist_for_each_entry(node, n, bucket, list) { mpath = node->mpath; - if (mpath->dev == dev && memcmp(dst, mpath->dst, ETH_ALEN) - == 0) { - err = -EEXIST; - atomic_dec(&sdata->u.sta.mpaths); - kfree(new_node); - kfree(new_mpath); - goto endadd; - } + if (mpath->dev == dev && memcmp(dst, mpath->dst, ETH_ALEN) == 0) + goto err_exists; } hlist_add_head_rcu(&new_node->list, bucket); @@ -206,10 +196,9 @@ int mesh_path_add(u8 *dst, struct net_device *dev) mesh_paths->mean_chain_len * (mesh_paths->hash_mask + 1)) grow = 1; -endadd: spin_unlock(&mesh_paths->hashwlock[hash_idx]); read_unlock(&pathtbl_resize_lock); - if (!err && grow) { + if (grow) { struct mesh_table *oldtbl, *newtbl; write_lock(&pathtbl_resize_lock); @@ -225,7 +214,16 @@ endadd: synchronize_rcu(); mesh_table_free(oldtbl, false); } -endadd2: + return 0; + +err_exists: + spin_unlock(&mesh_paths->hashwlock[hash_idx]); + read_unlock(&pathtbl_resize_lock); + kfree(new_node); +err_node_alloc: + kfree(new_mpath); +err_path_alloc: + atomic_dec(&sdata->u.sta.mpaths); return err; } -- cgit v0.10.2 From 5194ee82b4aafc35b32c96db11bdacea9bf548be Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 7 May 2008 19:44:20 +0400 Subject: mac80211: Fix one more call to synchronize_rcu in atomic context. (This set applies OK without the previous one of 4 patches, but with some fuzz in the 7th one) The mesh_path_node_free() does so under hashwlock. But, this one is called 1. from mesh_path_add() after an old hash is hidden and synchronize_rcu() is calld 2. mesh_pathtbl_unregister(), when the module is being unloaded and no devices exist to mess with this hash. So, it seems to me, that simply removing the call is OK. Signed-off-by: Pavel Emelyanov Signed-off-by: John W. Linville diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 7097ef9..0b6c4bf 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -458,7 +458,6 @@ static void mesh_path_node_free(struct hlist_node *p, bool free_leafs) struct mpath_node *node = hlist_entry(p, struct mpath_node, list); mpath = node->mpath; hlist_del_rcu(p); - synchronize_rcu(); if (free_leafs) kfree(mpath); kfree(node); -- cgit v0.10.2 From 4caf86c6928cfaca270327bc944f901c2e2a8f50 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 7 May 2008 19:47:01 +0400 Subject: mac80211: Prepare mesh_table_grow to failing copy_node callback. The mesh_path_node_copy() performs kmalloc() and thus - may fail (well, it does not now, but I'm fixing this right now). Its caller - the mesh_table_grow() - isn't prepared for such a trick yet. This preparation is just flush the new hash and make copy_node() return an int value. Signed-off-by: Pavel Emelyanov Signed-off-by: John W. Linville diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 697ef67..ca81d00 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -349,7 +349,7 @@ struct mesh_table *mesh_table_grow(struct mesh_table *tbl) { struct mesh_table *newtbl; struct hlist_head *oldhash; - struct hlist_node *p; + struct hlist_node *p, *q; int err = 0; int i; @@ -373,13 +373,24 @@ struct mesh_table *mesh_table_grow(struct mesh_table *tbl) oldhash = tbl->hash_buckets; for (i = 0; i <= tbl->hash_mask; i++) hlist_for_each(p, &oldhash[i]) - tbl->copy_node(p, newtbl); + if (tbl->copy_node(p, newtbl) < 0) + goto errcopy; endgrow: if (err) return NULL; else return newtbl; + +errcopy: + for (i = 0; i <= newtbl->hash_mask; i++) { + hlist_for_each_safe(p, q, &newtbl->hash_buckets[i]) + tbl->free_node(p, 0); + } + kfree(newtbl->hash_buckets); + kfree(newtbl->hashwlock); + kfree(newtbl); + return NULL; } /** diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 2e161f6..669eafa 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -109,7 +109,7 @@ struct mesh_table { __u32 hash_rnd; /* Used for hash generation */ atomic_t entries; /* Up to MAX_MESH_NEIGHBOURS */ void (*free_node) (struct hlist_node *p, bool free_leafs); - void (*copy_node) (struct hlist_node *p, struct mesh_table *newtbl); + int (*copy_node) (struct hlist_node *p, struct mesh_table *newtbl); int size_order; int mean_chain_len; }; diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 0b6c4bf..512bfa1 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -463,7 +463,7 @@ static void mesh_path_node_free(struct hlist_node *p, bool free_leafs) kfree(node); } -static void mesh_path_node_copy(struct hlist_node *p, struct mesh_table *newtbl) +static int mesh_path_node_copy(struct hlist_node *p, struct mesh_table *newtbl) { struct mesh_path *mpath; struct mpath_node *node, *new_node; @@ -476,6 +476,7 @@ static void mesh_path_node_copy(struct hlist_node *p, struct mesh_table *newtbl) hash_idx = mesh_table_hash(mpath->dst, mpath->dev, newtbl); hlist_add_head(&new_node->list, &newtbl->hash_buckets[hash_idx]); + return 0; } int mesh_pathtbl_init(void) -- cgit v0.10.2 From 00242c40a167113688dd7ed46ec94e8a4c47f603 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 7 May 2008 19:48:14 +0400 Subject: mac80211: Report allocation failure from mesh_path_node_copy. Now - return the -ENOMEM in case kmalloc fails. Signed-off-by: Pavel Emelyanov Signed-off-by: John W. Linville diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 512bfa1..fe1ceee 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -469,9 +469,12 @@ static int mesh_path_node_copy(struct hlist_node *p, struct mesh_table *newtbl) struct mpath_node *node, *new_node; u32 hash_idx; + new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL); + if (new_node == NULL) + return -ENOMEM; + node = hlist_entry(p, struct mpath_node, list); mpath = node->mpath; - new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL); new_node->mpath = mpath; hash_idx = mesh_table_hash(mpath->dst, mpath->dev, newtbl); hlist_add_head(&new_node->list, -- cgit v0.10.2 From 8566dc3fca470454461b161677a5ae3bb3a8c1b8 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 7 May 2008 19:51:51 +0400 Subject: mac80211: Fix sleeping allocation under lock in mesh_path_node_copy. The mesh_path_node_copy() can be called like this: mesh_path_add `- write_lock(&pathtbl_resize_lock); /* ! */ `- mesh_table_grow `- ->copy_node `- mesh_path_node_copy thus, the GFP_KERNEL is not suitable here. The acceptable fix, I suppose, is make this allocation GPF_ATOMIC - the mpath_node being allocated is 4 pointers, i.e. this allocation is small enough to survive even under a moderate memory pressure. Signed-off-by: Pavel Emelyanov Signed-off-by: John W. Linville diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index fe1ceee..1154398 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -469,7 +469,7 @@ static int mesh_path_node_copy(struct hlist_node *p, struct mesh_table *newtbl) struct mpath_node *node, *new_node; u32 hash_idx; - new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL); + new_node = kmalloc(sizeof(struct mpath_node), GFP_ATOMIC); if (new_node == NULL) return -ENOMEM; -- cgit v0.10.2 From 3282aea9ea5644a5b0161ad0fbd70fbf1099a470 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 7 May 2008 19:54:04 +0400 Subject: mac80211: Do not report false error from mesh_path_add. In case the hash grow failed, it is not fair to return error - the new node _was_ _actually_ added in this case. Besides, after my previous patch, this grow is more likely to fail on large hashes. Signed-off-by: Pavel Emelyanov Signed-off-by: John W. Linville diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 1154398..947b13b4 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -206,7 +206,7 @@ int mesh_path_add(u8 *dst, struct net_device *dev) newtbl = mesh_table_grow(mesh_paths); if (!newtbl) { write_unlock(&pathtbl_resize_lock); - return -ENOMEM; + return 0; } rcu_assign_pointer(mesh_paths, newtbl); write_unlock(&pathtbl_resize_lock); -- cgit v0.10.2 From a3538b19a6d226f9d3d9b18865468370009dec55 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 7 May 2008 19:55:59 +0400 Subject: mac80211: Merge error paths in mesh_table_grow(). This is the first (of two) clean ups after the fixes above. The err variable is not even required after this cleaning. Signed-off-by: Pavel Emelyanov Signed-off-by: John W. Linville diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index ca81d00..cbce001 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -350,20 +350,15 @@ struct mesh_table *mesh_table_grow(struct mesh_table *tbl) struct mesh_table *newtbl; struct hlist_head *oldhash; struct hlist_node *p, *q; - int err = 0; int i; if (atomic_read(&tbl->entries) - < tbl->mean_chain_len * (tbl->hash_mask + 1)) { - err = -EPERM; + < tbl->mean_chain_len * (tbl->hash_mask + 1)) goto endgrow; - } newtbl = mesh_table_alloc(tbl->size_order + 1); - if (!newtbl) { - err = -ENOMEM; + if (!newtbl) goto endgrow; - } newtbl->free_node = tbl->free_node; newtbl->mean_chain_len = tbl->mean_chain_len; @@ -376,11 +371,7 @@ struct mesh_table *mesh_table_grow(struct mesh_table *tbl) if (tbl->copy_node(p, newtbl) < 0) goto errcopy; -endgrow: - if (err) - return NULL; - else - return newtbl; + return newtbl; errcopy: for (i = 0; i <= newtbl->hash_mask; i++) { @@ -390,6 +381,7 @@ errcopy: kfree(newtbl->hash_buckets); kfree(newtbl->hashwlock); kfree(newtbl); +endgrow: return NULL; } -- cgit v0.10.2 From bd9b448f4c0a514559bdae4ca18ca3e8cd999c6d Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 7 May 2008 19:57:11 +0400 Subject: mac80211: Consolidate hash kfree-ing in mesh.c. There are already two places, that kfree the mesh_table and its buckets. Signed-off-by: Pavel Emelyanov Signed-off-by: John W. Linville diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index cbce001..b5933b2 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -315,6 +315,13 @@ struct mesh_table *mesh_table_alloc(int size_order) return newtbl; } +static void __mesh_table_free(struct mesh_table *tbl) +{ + kfree(tbl->hash_buckets); + kfree(tbl->hashwlock); + kfree(tbl); +} + void mesh_table_free(struct mesh_table *tbl, bool free_leafs) { struct hlist_head *mesh_hash; @@ -330,9 +337,7 @@ void mesh_table_free(struct mesh_table *tbl, bool free_leafs) } spin_unlock(&tbl->hashwlock[i]); } - kfree(tbl->hash_buckets); - kfree(tbl->hashwlock); - kfree(tbl); + __mesh_table_free(tbl); } static void ieee80211_mesh_path_timer(unsigned long data) @@ -378,9 +383,7 @@ errcopy: hlist_for_each_safe(p, q, &newtbl->hash_buckets[i]) tbl->free_node(p, 0); } - kfree(newtbl->hash_buckets); - kfree(newtbl->hashwlock); - kfree(newtbl); + __mesh_table_free(tbl); endgrow: return NULL; } -- cgit v0.10.2 From 57962f0b9d76487a660619f97c0aa811924274a0 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Wed, 14 May 2008 16:30:28 +0200 Subject: libertas: reduce command retry time [PATCH, take 2] libertas: reduce command retry time In the normal case, an unsuccessful command would be retried for 10*5 seconds, or 10*10 seconds in the worst case. This patch reduces this to 3*3 seconds, or 3*10 seconds in the worst case. I also reduced the time it takes to start a new command downloaded. Signed-off-by: Holger Schurig Acked-by: Dan Williams Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 7ccec98..2d9bbcc 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -1136,7 +1136,7 @@ static void lbs_submit_command(struct lbs_private *priv, struct cmd_header *cmd; uint16_t cmdsize; uint16_t command; - int timeo = 5 * HZ; + int timeo = 3 * HZ; int ret; lbs_deb_enter(LBS_DEB_HOST); @@ -1154,7 +1154,7 @@ static void lbs_submit_command(struct lbs_private *priv, /* These commands take longer */ if (command == CMD_802_11_SCAN || command == CMD_802_11_ASSOCIATE || command == CMD_802_11_AUTHENTICATE) - timeo = 10 * HZ; + timeo = 5 * HZ; lbs_deb_cmd("DNLD_CMD: command 0x%04x, seq %d, size %d\n", command, le16_to_cpu(cmd->seqnum), cmdsize); @@ -1166,7 +1166,7 @@ static void lbs_submit_command(struct lbs_private *priv, lbs_pr_info("DNLD_CMD: hw_host_to_card failed: %d\n", ret); /* Let the timer kick in and retry, and potentially reset the whole thing if the condition persists */ - timeo = HZ; + timeo = HZ/4; } /* Setup the timer after transmit command */ diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 804da36..baafa44 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -782,9 +782,10 @@ static int lbs_thread(void *data) if (priv->cmd_timed_out && priv->cur_cmd) { struct cmd_ctrl_node *cmdnode = priv->cur_cmd; - if (++priv->nr_retries > 10) { - lbs_pr_info("Excessive timeouts submitting command %x\n", - le16_to_cpu(cmdnode->cmdbuf->command)); + if (++priv->nr_retries > 3) { + lbs_pr_info("Excessive timeouts submitting " + "command 0x%04x\n", + le16_to_cpu(cmdnode->cmdbuf->command)); lbs_complete_command(priv, cmdnode, -ETIMEDOUT); priv->nr_retries = 0; if (priv->reset_card) { @@ -794,8 +795,10 @@ static int lbs_thread(void *data) } } else { priv->cur_cmd = NULL; - lbs_pr_info("requeueing command %x due to timeout (#%d)\n", - le16_to_cpu(cmdnode->cmdbuf->command), priv->nr_retries); + lbs_pr_info("requeueing command 0x%04x due " + "to timeout (#%d)\n", + le16_to_cpu(cmdnode->cmdbuf->command), + priv->nr_retries); /* Stick it back at the _top_ of the pending queue for immediate resubmission */ @@ -986,12 +989,11 @@ static void command_timer_fn(unsigned long data) lbs_deb_enter(LBS_DEB_CMD); spin_lock_irqsave(&priv->driver_lock, flags); - if (!priv->cur_cmd) { - lbs_pr_info("Command timer expired; no pending command\n"); + if (!priv->cur_cmd) goto out; - } - lbs_pr_info("Command %x timed out\n", le16_to_cpu(priv->cur_cmd->cmdbuf->command)); + lbs_pr_info("command 0x%04x timed out\n", + le16_to_cpu(priv->cur_cmd->cmdbuf->command)); priv->cmd_timed_out = 1; wake_up_interruptible(&priv->waitq); -- cgit v0.10.2 From 1bd3dff549537d3d9b92d0b284f4cc2be264a56d Mon Sep 17 00:00:00 2001 From: Harvey Harrison Date: Wed, 14 May 2008 16:26:16 -0700 Subject: mac80211: michael.c use kernel-provided infrastructure Replace private implementation of bit rotation and unaligned access helpers with kernel-provided implementation. Fold xswap helper in its one usage in the michael_block macro. Signed-off-by: Harvey Harrison Cc: "John W. Linville" Signed-off-by: Andrew Morton Signed-off-by: John W. Linville diff --git a/net/mac80211/michael.c b/net/mac80211/michael.c index 0f844f7..c1e5897 100644 --- a/net/mac80211/michael.c +++ b/net/mac80211/michael.c @@ -8,71 +8,39 @@ */ #include +#include +#include #include "michael.h" -static inline u32 rotr(u32 val, int bits) -{ - return (val >> bits) | (val << (32 - bits)); -} - - -static inline u32 rotl(u32 val, int bits) -{ - return (val << bits) | (val >> (32 - bits)); -} - - -static inline u32 xswap(u32 val) -{ - return ((val & 0xff00ff00) >> 8) | ((val & 0x00ff00ff) << 8); -} - - #define michael_block(l, r) \ do { \ - r ^= rotl(l, 17); \ + r ^= rol32(l, 17); \ l += r; \ - r ^= xswap(l); \ + r ^= ((l & 0xff00ff00) >> 8) | ((l & 0x00ff00ff) << 8); \ l += r; \ - r ^= rotl(l, 3); \ + r ^= rol32(l, 3); \ l += r; \ - r ^= rotr(l, 2); \ + r ^= ror32(l, 2); \ l += r; \ } while (0) - -static inline u32 michael_get32(u8 *data) -{ - return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); -} - - -static inline void michael_put32(u32 val, u8 *data) -{ - data[0] = val & 0xff; - data[1] = (val >> 8) & 0xff; - data[2] = (val >> 16) & 0xff; - data[3] = (val >> 24) & 0xff; -} - - void michael_mic(u8 *key, u8 *da, u8 *sa, u8 priority, u8 *data, size_t data_len, u8 *mic) { u32 l, r, val; size_t block, blocks, left; - l = michael_get32(key); - r = michael_get32(key + 4); + l = get_unaligned_le32(key); + r = get_unaligned_le32(key + 4); /* A pseudo header (DA, SA, Priority, 0, 0, 0) is used in Michael MIC * calculation, but it is _not_ transmitted */ - l ^= michael_get32(da); + l ^= get_unaligned_le32(da); michael_block(l, r); - l ^= da[4] | (da[5] << 8) | (sa[0] << 16) | (sa[1] << 24); + l ^= get_unaligned_le16(&da[4]) | (get_unaligned_le16(sa) << 16); michael_block(l, r); - l ^= michael_get32(&sa[2]); + l ^= get_unaligned_le32(&sa[2]); michael_block(l, r); l ^= priority; michael_block(l, r); @@ -82,7 +50,7 @@ void michael_mic(u8 *key, u8 *da, u8 *sa, u8 priority, left = data_len % 4; for (block = 0; block < blocks; block++) { - l ^= michael_get32(&data[block * 4]); + l ^= get_unaligned_le32(&data[block * 4]); michael_block(l, r); } @@ -99,6 +67,6 @@ void michael_mic(u8 *key, u8 *da, u8 *sa, u8 priority, /* last block is zero, so l ^ 0 = l */ michael_block(l, r); - michael_put32(l, mic); - michael_put32(r, mic + 4); + put_unaligned_le32(l, mic); + put_unaligned_le32(r, mic + 4); } -- cgit v0.10.2 From 1b19ca396621dcba573b20d4625526f5a460c886 Mon Sep 17 00:00:00 2001 From: Harvey Harrison Date: Wed, 14 May 2008 16:26:17 -0700 Subject: mac80211: introduce struct michael_mic_ctx and static helpers Replace the existing macro with a static function, significantly shrinks the size of the produced object file. Signed-off-by: Harvey Harrison Cc: "John W. Linville" Signed-off-by: Andrew Morton Signed-off-by: John W. Linville diff --git a/net/mac80211/michael.c b/net/mac80211/michael.c index c1e5897..4e151e0 100644 --- a/net/mac80211/michael.c +++ b/net/mac80211/michael.c @@ -13,46 +13,52 @@ #include "michael.h" -#define michael_block(l, r) \ -do { \ - r ^= rol32(l, 17); \ - l += r; \ - r ^= ((l & 0xff00ff00) >> 8) | ((l & 0x00ff00ff) << 8); \ - l += r; \ - r ^= rol32(l, 3); \ - l += r; \ - r ^= ror32(l, 2); \ - l += r; \ -} while (0) +static void michael_block(struct michael_mic_ctx *mctx, u32 val) +{ + mctx->l ^= val; + mctx->r ^= rol32(mctx->l, 17); + mctx->l += mctx->r; + mctx->r ^= ((mctx->l & 0xff00ff00) >> 8) | + ((mctx->l & 0x00ff00ff) << 8); + mctx->l += mctx->r; + mctx->r ^= rol32(mctx->l, 3); + mctx->l += mctx->r; + mctx->r ^= ror32(mctx->l, 2); + mctx->l += mctx->r; +} + +static void michael_mic_hdr(struct michael_mic_ctx *mctx, + u8 *key, u8 *da, u8 *sa, u8 priority) +{ + mctx->l = get_unaligned_le32(key); + mctx->r = get_unaligned_le32(key + 4); + + /* + * A pseudo header (DA, SA, Priority, 0, 0, 0) is used in Michael MIC + * calculation, but it is _not_ transmitted + */ + michael_block(mctx, get_unaligned_le32(da)); + michael_block(mctx, get_unaligned_le16(&da[4]) | + (get_unaligned_le16(sa) << 16)); + michael_block(mctx, get_unaligned_le32(&sa[2])); + michael_block(mctx, priority); +} void michael_mic(u8 *key, u8 *da, u8 *sa, u8 priority, u8 *data, size_t data_len, u8 *mic) { - u32 l, r, val; + u32 val; size_t block, blocks, left; + struct michael_mic_ctx mctx; - l = get_unaligned_le32(key); - r = get_unaligned_le32(key + 4); - - /* A pseudo header (DA, SA, Priority, 0, 0, 0) is used in Michael MIC - * calculation, but it is _not_ transmitted */ - l ^= get_unaligned_le32(da); - michael_block(l, r); - l ^= get_unaligned_le16(&da[4]) | (get_unaligned_le16(sa) << 16); - michael_block(l, r); - l ^= get_unaligned_le32(&sa[2]); - michael_block(l, r); - l ^= priority; - michael_block(l, r); + michael_mic_hdr(&mctx, key, da, sa, priority); /* Real data */ blocks = data_len / 4; left = data_len % 4; - for (block = 0; block < blocks; block++) { - l ^= get_unaligned_le32(&data[block * 4]); - michael_block(l, r); - } + for (block = 0; block < blocks; block++) + michael_block(&mctx, get_unaligned_le32(&data[block * 4])); /* Partial block of 0..3 bytes and padding: 0x5a + 4..7 zeros to make * total length a multiple of 4. */ @@ -62,11 +68,10 @@ void michael_mic(u8 *key, u8 *da, u8 *sa, u8 priority, left--; val |= data[blocks * 4 + left]; } - l ^= val; - michael_block(l, r); - /* last block is zero, so l ^ 0 = l */ - michael_block(l, r); - put_unaligned_le32(l, mic); - put_unaligned_le32(r, mic + 4); + michael_block(&mctx, val); + michael_block(&mctx, 0); + + put_unaligned_le32(mctx.l, mic); + put_unaligned_le32(mctx.r, mic + 4); } diff --git a/net/mac80211/michael.h b/net/mac80211/michael.h index 2e6aeba..7d5707b 100644 --- a/net/mac80211/michael.h +++ b/net/mac80211/michael.h @@ -14,6 +14,10 @@ #define MICHAEL_MIC_LEN 8 +struct michael_mic_ctx { + u32 l, r; +}; + void michael_mic(u8 *key, u8 *da, u8 *sa, u8 priority, u8 *data, size_t data_len, u8 *mic); -- cgit v0.10.2 From a7b6f0c5558ad03281b8064d6a4ab2e124dea991 Mon Sep 17 00:00:00 2001 From: Harvey Harrison Date: Wed, 14 May 2008 16:26:18 -0700 Subject: mac80211: add const, remove unused function, make one function static Signed-off-by: Harvey Harrison Cc: "John W. Linville" Signed-off-by: Andrew Morton Signed-off-by: John W. Linville diff --git a/net/mac80211/michael.c b/net/mac80211/michael.c index 4e151e0..1fcdf38 100644 --- a/net/mac80211/michael.c +++ b/net/mac80211/michael.c @@ -6,7 +6,6 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ - #include #include #include @@ -28,7 +27,7 @@ static void michael_block(struct michael_mic_ctx *mctx, u32 val) } static void michael_mic_hdr(struct michael_mic_ctx *mctx, - u8 *key, u8 *da, u8 *sa, u8 priority) + const u8 *key, const u8 *da, const u8 *sa, u8 priority) { mctx->l = get_unaligned_le32(key); mctx->r = get_unaligned_le32(key + 4); @@ -44,8 +43,8 @@ static void michael_mic_hdr(struct michael_mic_ctx *mctx, michael_block(mctx, priority); } -void michael_mic(u8 *key, u8 *da, u8 *sa, u8 priority, - u8 *data, size_t data_len, u8 *mic) +void michael_mic(const u8 *key, const u8 *da, const u8 *sa, u8 priority, + const u8 *data, size_t data_len, u8 *mic) { u32 val; size_t block, blocks, left; diff --git a/net/mac80211/michael.h b/net/mac80211/michael.h index 7d5707b..69b4501 100644 --- a/net/mac80211/michael.h +++ b/net/mac80211/michael.h @@ -18,7 +18,7 @@ struct michael_mic_ctx { u32 l, r; }; -void michael_mic(u8 *key, u8 *da, u8 *sa, u8 priority, - u8 *data, size_t data_len, u8 *mic); +void michael_mic(const u8 *key, const u8 *da, const u8 *sa, u8 priority, + const u8 *data, size_t data_len, u8 *mic); #endif /* MICHAEL_H */ diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c index a7c3feb..8cdf053 100644 --- a/net/mac80211/tkip.c +++ b/net/mac80211/tkip.c @@ -6,7 +6,6 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ - #include #include #include @@ -132,7 +131,7 @@ static void tkip_mixing_phase2(const u16 *p1k, const u8 *tk, u16 tsc_IV16, /* Add TKIP IV and Ext. IV at @pos. @iv0, @iv1, and @iv2 are the first octets * of the IV. Returns pointer to the octet following IVs (i.e., beginning of * the packet payload). */ -u8 * ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key, +u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key, u8 iv0, u8 iv1, u8 iv2) { *pos++ = iv0; @@ -143,14 +142,7 @@ u8 * ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key, return pos + 4; } -void ieee80211_tkip_gen_phase1key(struct ieee80211_key *key, u8 *ta, - u16 *phase1key) -{ - tkip_mixing_phase1(ta, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY], - key->u.tkip.iv32, phase1key); -} - -void ieee80211_tkip_gen_rc4key(struct ieee80211_key *key, u8 *ta, +static void ieee80211_tkip_gen_rc4key(struct ieee80211_key *key, u8 *ta, u8 *rc4key) { /* Calculate per-packet key */ diff --git a/net/mac80211/tkip.h b/net/mac80211/tkip.h index 1fa0bb4..b890427 100644 --- a/net/mac80211/tkip.h +++ b/net/mac80211/tkip.h @@ -15,10 +15,6 @@ u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key, u8 iv0, u8 iv1, u8 iv2); -void ieee80211_tkip_gen_phase1key(struct ieee80211_key *key, u8 *ta, - u16 *phase1key); -void ieee80211_tkip_gen_rc4key(struct ieee80211_key *key, u8 *ta, - u8 *rc4key); void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm, struct ieee80211_key *key, u8 *pos, size_t payload_len, u8 *ta); -- cgit v0.10.2 From b0f76b335f8b1c324b4b2be06369d391b26a7cc9 Mon Sep 17 00:00:00 2001 From: Harvey Harrison Date: Wed, 14 May 2008 16:26:19 -0700 Subject: mac80211: add a struct to hold tkip context Signed-off-by: Harvey Harrison Cc: "John W. Linville" Signed-off-by: Andrew Morton Signed-off-by: John W. Linville diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 3cef80d..dbf0563 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -256,8 +256,8 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, case ALG_TKIP: params.cipher = WLAN_CIPHER_SUITE_TKIP; - iv32 = key->u.tkip.iv32; - iv16 = key->u.tkip.iv16; + iv32 = key->u.tkip.tx.iv32; + iv16 = key->u.tkip.tx.iv16; if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE && sdata->local->ops->get_tkip_seq) diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index 19efc3a..7439b63 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c @@ -97,8 +97,8 @@ static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf, break; case ALG_TKIP: len = scnprintf(buf, sizeof(buf), "%08x %04x\n", - key->u.tkip.iv32, - key->u.tkip.iv16); + key->u.tkip.tx.iv32, + key->u.tkip.tx.iv16); break; case ALG_CCMP: tpn = key->u.ccmp.tx_pn; @@ -128,8 +128,8 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf, for (i = 0; i < NUM_RX_DATA_QUEUES; i++) p += scnprintf(p, sizeof(buf)+buf-p, "%08x %04x\n", - key->u.tkip.iv32_rx[i], - key->u.tkip.iv16_rx[i]); + key->u.tkip.rx[i].iv32, + key->u.tkip.rx[i].iv16); len = p - buf; break; case ALG_CCMP: diff --git a/net/mac80211/key.h b/net/mac80211/key.h index f52c3df..a0f774a 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h @@ -69,6 +69,13 @@ enum ieee80211_internal_key_flags { KEY_FLAG_TODO_ADD_DEBUGFS = BIT(5), }; +struct tkip_ctx { + u32 iv32; + u16 iv16; + u16 p1k[5]; + int initialized; +}; + struct ieee80211_key { struct ieee80211_local *local; struct ieee80211_sub_if_data *sdata; @@ -85,16 +92,10 @@ struct ieee80211_key { union { struct { /* last used TSC */ - u32 iv32; - u16 iv16; - u16 p1k[5]; - int tx_initialized; + struct tkip_ctx tx; /* last received RSC */ - u32 iv32_rx[NUM_RX_DATA_QUEUES]; - u16 iv16_rx[NUM_RX_DATA_QUEUES]; - u16 p1k_rx[NUM_RX_DATA_QUEUES][5]; - int rx_initialized[NUM_RX_DATA_QUEUES]; + struct tkip_ctx rx[NUM_RX_DATA_QUEUES]; } tkip; struct { u8 tx_pn[6]; diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c index 8cdf053..d74c91e 100644 --- a/net/mac80211/tkip.c +++ b/net/mac80211/tkip.c @@ -138,7 +138,7 @@ u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key, *pos++ = iv1; *pos++ = iv2; *pos++ = (key->conf.keyidx << 6) | (1 << 5) /* Ext IV */; - put_unaligned_le32(key->u.tkip.iv32, pos); + put_unaligned_le32(key->u.tkip.tx.iv32, pos); return pos + 4; } @@ -146,16 +146,16 @@ static void ieee80211_tkip_gen_rc4key(struct ieee80211_key *key, u8 *ta, u8 *rc4key) { /* Calculate per-packet key */ - if (key->u.tkip.iv16 == 0 || !key->u.tkip.tx_initialized) { + if (key->u.tkip.tx.iv16 == 0 || !key->u.tkip.tx.initialized) { /* IV16 wrapped around - perform TKIP phase 1 */ tkip_mixing_phase1(ta, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY], - key->u.tkip.iv32, key->u.tkip.p1k); - key->u.tkip.tx_initialized = 1; + key->u.tkip.tx.iv32, key->u.tkip.tx.p1k); + key->u.tkip.tx.initialized = 1; } - tkip_mixing_phase2(key->u.tkip.p1k, + tkip_mixing_phase2(key->u.tkip.tx.p1k, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY], - key->u.tkip.iv16, rc4key); + key->u.tkip.tx.iv16, rc4key); } void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf, @@ -179,9 +179,9 @@ void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf, printk(KERN_DEBUG "TKIP encrypt: iv16 = 0x%04x, iv32 = 0x%08x\n", iv16, iv32); - if (iv32 != key->u.tkip.iv32) { + if (iv32 != key->u.tkip.tx.iv32) { printk(KERN_DEBUG "skb: iv32 = 0x%08x key: iv32 = 0x%08x\n", - iv32, key->u.tkip.iv32); + iv32, key->u.tkip.tx.iv32); printk(KERN_DEBUG "Wrap around of iv16 in the middle of a " "fragmented packet\n"); } @@ -190,19 +190,19 @@ void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf, /* Update the p1k only when the iv16 in the packet wraps around, this * might occur after the wrap around of iv16 in the key in case of * fragmented packets. */ - if (iv16 == 0 || !key->u.tkip.tx_initialized) { + if (iv16 == 0 || !key->u.tkip.tx.initialized) { /* IV16 wrapped around - perform TKIP phase 1 */ tkip_mixing_phase1(ta, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY], - iv32, key->u.tkip.p1k); - key->u.tkip.tx_initialized = 1; + iv32, key->u.tkip.tx.p1k); + key->u.tkip.tx.initialized = 1; } if (type == IEEE80211_TKIP_P1_KEY) { - memcpy(outkey, key->u.tkip.p1k, sizeof(u16) * 5); + memcpy(outkey, key->u.tkip.tx.p1k, sizeof(u16) * 5); return; } - tkip_mixing_phase2(key->u.tkip.p1k, + tkip_mixing_phase2(key->u.tkip.tx.p1k, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY], iv16, outkey); } EXPORT_SYMBOL(ieee80211_get_tkip_key); @@ -263,33 +263,33 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, if ((keyid >> 6) != key->conf.keyidx) return TKIP_DECRYPT_INVALID_KEYIDX; - if (key->u.tkip.rx_initialized[queue] && - (iv32 < key->u.tkip.iv32_rx[queue] || - (iv32 == key->u.tkip.iv32_rx[queue] && - iv16 <= key->u.tkip.iv16_rx[queue]))) { + if (key->u.tkip.rx[queue].initialized && + (iv32 < key->u.tkip.rx[queue].iv32 || + (iv32 == key->u.tkip.rx[queue].iv32 && + iv16 <= key->u.tkip.rx[queue].iv16))) { #ifdef CONFIG_TKIP_DEBUG DECLARE_MAC_BUF(mac); printk(KERN_DEBUG "TKIP replay detected for RX frame from " "%s (RX IV (%04x,%02x) <= prev. IV (%04x,%02x)\n", print_mac(mac, ta), - iv32, iv16, key->u.tkip.iv32_rx[queue], - key->u.tkip.iv16_rx[queue]); + iv32, iv16, key->u.tkip.rx[queue].iv32, + key->u.tkip.rx[queue].iv16); #endif /* CONFIG_TKIP_DEBUG */ return TKIP_DECRYPT_REPLAY; } if (only_iv) { res = TKIP_DECRYPT_OK; - key->u.tkip.rx_initialized[queue] = 1; + key->u.tkip.rx[queue].initialized = 1; goto done; } - if (!key->u.tkip.rx_initialized[queue] || - key->u.tkip.iv32_rx[queue] != iv32) { - key->u.tkip.rx_initialized[queue] = 1; + if (!key->u.tkip.rx[queue].initialized || + key->u.tkip.rx[queue].iv32 != iv32) { + key->u.tkip.rx[queue].initialized = 1; /* IV16 wrapped around - perform TKIP phase 1 */ tkip_mixing_phase1(ta, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY], - iv32, key->u.tkip.p1k_rx[queue]); + iv32, key->u.tkip.rx[queue].p1k); #ifdef CONFIG_TKIP_DEBUG { int i; @@ -303,7 +303,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, printk("\n"); printk(KERN_DEBUG "TKIP decrypt: P1K="); for (i = 0; i < 5; i++) - printk("%04x ", key->u.tkip.p1k_rx[queue][i]); + printk("%04x ", key->u.tkip.rx[queue].p1k[i]); printk("\n"); } #endif /* CONFIG_TKIP_DEBUG */ @@ -318,11 +318,11 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, key->local->ops->update_tkip_key( local_to_hw(key->local), &key->conf, - sta_addr, iv32, key->u.tkip.p1k_rx[queue]); + sta_addr, iv32, key->u.tkip.rx[queue].p1k); } } - tkip_mixing_phase2(key->u.tkip.p1k_rx[queue], + tkip_mixing_phase2(key->u.tkip.rx[queue].p1k, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY], iv16, rc4key); #ifdef CONFIG_TKIP_DEBUG diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 42f3654..d730449 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -176,8 +176,8 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) skb_trim(skb, skb->len - MICHAEL_MIC_LEN); /* update IV in key information to be able to detect replays */ - rx->key->u.tkip.iv32_rx[rx->queue] = rx->tkip_iv32; - rx->key->u.tkip.iv16_rx[rx->queue] = rx->tkip_iv16; + rx->key->u.tkip.rx[rx->queue].iv32 = rx->tkip_iv32; + rx->key->u.tkip.rx[rx->queue].iv16 = rx->tkip_iv16; return RX_CONTINUE; } @@ -214,19 +214,19 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, pos += hdrlen; /* Increase IV for the frame */ - key->u.tkip.iv16++; - if (key->u.tkip.iv16 == 0) - key->u.tkip.iv32++; + key->u.tkip.tx.iv16++; + if (key->u.tkip.tx.iv16 == 0) + key->u.tkip.tx.iv32++; if (tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { hdr = (struct ieee80211_hdr *)skb->data; /* hwaccel - with preallocated room for IV */ ieee80211_tkip_add_iv(pos, key, - (u8) (key->u.tkip.iv16 >> 8), - (u8) (((key->u.tkip.iv16 >> 8) | 0x20) & + (u8) (key->u.tkip.tx.iv16 >> 8), + (u8) (((key->u.tkip.tx.iv16 >> 8) | 0x20) & 0x7f), - (u8) key->u.tkip.iv16); + (u8) key->u.tkip.tx.iv16); tx->control->hw_key = &tx->key->conf; return 0; -- cgit v0.10.2 From 82a57447fa66bf138cd55206f33eea21ee257335 Mon Sep 17 00:00:00 2001 From: Harvey Harrison Date: Wed, 14 May 2008 16:26:19 -0700 Subject: mac80211: tkip.c use struct tkip_ctx in phase 1 key mixing Signed-off-by: Harvey Harrison Cc: "John W. Linville" Signed-off-by: Andrew Morton Signed-off-by: John W. Linville diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c index d74c91e..e9ee247 100644 --- a/net/mac80211/tkip.c +++ b/net/mac80211/tkip.c @@ -71,10 +71,12 @@ static u16 tkipS(u16 val) * TSC = TKIP sequence counter (48 bits, only 32 msb bits used) * P1K: 80 bits */ -static void tkip_mixing_phase1(const u8 *ta, const u8 *tk, u32 tsc_IV32, - u16 *p1k) +static void tkip_mixing_phase1(struct ieee80211_key *key, const u8 *ta, + struct tkip_ctx *ctx, u32 tsc_IV32) { int i, j; + const u8 *tk = &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY]; + u16 *p1k = ctx->p1k; p1k[0] = tsc_IV32 & 0xFFFF; p1k[1] = tsc_IV32 >> 16; @@ -90,6 +92,7 @@ static void tkip_mixing_phase1(const u8 *ta, const u8 *tk, u32 tsc_IV32, p1k[3] += tkipS(p1k[2] ^ get_unaligned_le16(tk + 12 + j)); p1k[4] += tkipS(p1k[3] ^ get_unaligned_le16(tk + 0 + j)) + i; } + ctx->initialized = 1; } static void tkip_mixing_phase2(const u16 *p1k, const u8 *tk, u16 tsc_IV16, @@ -146,12 +149,8 @@ static void ieee80211_tkip_gen_rc4key(struct ieee80211_key *key, u8 *ta, u8 *rc4key) { /* Calculate per-packet key */ - if (key->u.tkip.tx.iv16 == 0 || !key->u.tkip.tx.initialized) { - /* IV16 wrapped around - perform TKIP phase 1 */ - tkip_mixing_phase1(ta, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY], - key->u.tkip.tx.iv32, key->u.tkip.tx.p1k); - key->u.tkip.tx.initialized = 1; - } + if (key->u.tkip.tx.iv16 == 0 || !key->u.tkip.tx.initialized) + tkip_mixing_phase1(key, ta, &key->u.tkip.tx, key->u.tkip.tx.iv32); tkip_mixing_phase2(key->u.tkip.tx.p1k, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY], @@ -190,12 +189,8 @@ void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf, /* Update the p1k only when the iv16 in the packet wraps around, this * might occur after the wrap around of iv16 in the key in case of * fragmented packets. */ - if (iv16 == 0 || !key->u.tkip.tx.initialized) { - /* IV16 wrapped around - perform TKIP phase 1 */ - tkip_mixing_phase1(ta, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY], - iv32, key->u.tkip.tx.p1k); - key->u.tkip.tx.initialized = 1; - } + if (iv16 == 0 || !key->u.tkip.tx.initialized) + tkip_mixing_phase1(key, ta, &key->u.tkip.tx, iv32); if (type == IEEE80211_TKIP_P1_KEY) { memcpy(outkey, key->u.tkip.tx.p1k, sizeof(u16) * 5); @@ -286,10 +281,8 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, if (!key->u.tkip.rx[queue].initialized || key->u.tkip.rx[queue].iv32 != iv32) { - key->u.tkip.rx[queue].initialized = 1; /* IV16 wrapped around - perform TKIP phase 1 */ - tkip_mixing_phase1(ta, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY], - iv32, key->u.tkip.rx[queue].p1k); + tkip_mixing_phase1(key, ta, &key->u.tkip.rx[queue], iv32); #ifdef CONFIG_TKIP_DEBUG { int i; -- cgit v0.10.2 From 3c83809917dce9bbd880f6b08edc2d0ccac14a25 Mon Sep 17 00:00:00 2001 From: Harvey Harrison Date: Wed, 14 May 2008 16:26:20 -0700 Subject: mac80211: tkip.c use struct tkip_ctx in phase 2 key mixing Signed-off-by: Harvey Harrison Cc: "John W. Linville" Signed-off-by: Andrew Morton Signed-off-by: John W. Linville diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c index e9ee247..a00cf1ea 100644 --- a/net/mac80211/tkip.c +++ b/net/mac80211/tkip.c @@ -95,10 +95,12 @@ static void tkip_mixing_phase1(struct ieee80211_key *key, const u8 *ta, ctx->initialized = 1; } -static void tkip_mixing_phase2(const u16 *p1k, const u8 *tk, u16 tsc_IV16, - u8 *rc4key) +static void tkip_mixing_phase2(struct ieee80211_key *key, struct tkip_ctx *ctx, + u16 tsc_IV16, u8 *rc4key) { u16 ppk[6]; + const u16 *p1k = ctx->p1k; + const u8 *tk = &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY]; int i; ppk[0] = p1k[0]; @@ -152,9 +154,7 @@ static void ieee80211_tkip_gen_rc4key(struct ieee80211_key *key, u8 *ta, if (key->u.tkip.tx.iv16 == 0 || !key->u.tkip.tx.initialized) tkip_mixing_phase1(key, ta, &key->u.tkip.tx, key->u.tkip.tx.iv32); - tkip_mixing_phase2(key->u.tkip.tx.p1k, - &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY], - key->u.tkip.tx.iv16, rc4key); + tkip_mixing_phase2(key, &key->u.tkip.tx, key->u.tkip.tx.iv16, rc4key); } void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf, @@ -197,8 +197,7 @@ void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf, return; } - tkip_mixing_phase2(key->u.tkip.tx.p1k, - &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY], iv16, outkey); + tkip_mixing_phase2(key, &key->u.tkip.tx, iv16, outkey); } EXPORT_SYMBOL(ieee80211_get_tkip_key); @@ -315,9 +314,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, } } - tkip_mixing_phase2(key->u.tkip.rx[queue].p1k, - &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY], - iv16, rc4key); + tkip_mixing_phase2(key, &key->u.tkip.rx[queue], iv16, rc4key); #ifdef CONFIG_TKIP_DEBUG { int i; -- cgit v0.10.2 From 02883017607dfc60ff188980368adbe942823492 Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Thu, 15 May 2008 13:53:53 +0800 Subject: iwlwifi: changing irrelevant comment This patch changes an old eeprom comment in probe flow. Signed-off-by: Ron Rindjunsky Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 55ca752..d0f948d 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -6605,7 +6605,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e if (err) goto out_iounmap; - /* MAC Address location in EEPROM same for 3945/4965 */ + /* extract MAC Address */ iwl_eeprom_get_mac(priv, priv->mac_addr); IWL_DEBUG_INFO("MAC address: %s\n", print_mac(mac, priv->mac_addr)); SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr); -- cgit v0.10.2 From 0b794d63c5db8d010d1584c694eba97f0391fca6 Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Thu, 15 May 2008 13:53:54 +0800 Subject: iwlwifi: remove iwl4965_nic_start function This patch moves the contant of iwl4965_nic_start to the only place it is being used. Signed-off-by: Ron Rindjunsky Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index d0f948d..1a2d376 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -3958,13 +3958,6 @@ static void iwl4965_dealloc_ucode_pci(struct iwl_priv *priv) iwl_free_fw_desc(priv->pci_dev, &priv->ucode_boot); } -static void iwl4965_nic_start(struct iwl_priv *priv) -{ - /* Remove all resets to allow NIC to operate */ - iwl_write32(priv, CSR_RESET, 0); -} - - /** * iwl4965_read_ucode - Read uCode images from disk file. * @@ -4454,7 +4447,8 @@ static int __iwl4965_up(struct iwl_priv *priv) } /* start card; "initialize" will load runtime ucode */ - iwl4965_nic_start(priv); + /* Remove all resets to allow NIC to operate */ + iwl_write32(priv, CSR_RESET, 0); IWL_DEBUG_INFO(DRV_NAME " is coming up\n"); -- cgit v0.10.2 From edcdf8b21ac920e06b4180246123fe43b022e020 Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Thu, 15 May 2008 13:53:55 +0800 Subject: mac80211: separate Tx and Rx MCS when configuring HT This patch follows the 11n spec in separation between Tx and Rx MCS capabilities. Up until now, when configuring the HT possible set of Tx MCS only Rx MCS were considered, assuming they are the same as the Tx MCS. This patch fixed this by looking at low level driver Tx capabilities. Signed-off-by: Ron Rindjunsky Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 1a2d376..c713b27 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -3958,6 +3958,13 @@ static void iwl4965_dealloc_ucode_pci(struct iwl_priv *priv) iwl_free_fw_desc(priv->pci_dev, &priv->ucode_boot); } +static void iwl4965_nic_start(struct iwl_priv *priv) +{ + /* Remove all resets to allow NIC to operate */ + iwl_write32(priv, CSR_RESET, 0); +} + + /** * iwl4965_read_ucode - Read uCode images from disk file. * @@ -4447,8 +4454,7 @@ static int __iwl4965_up(struct iwl_priv *priv) } /* start card; "initialize" will load runtime ucode */ - /* Remove all resets to allow NIC to operate */ - iwl_write32(priv, CSR_RESET, 0); + iwl4965_nic_start(priv); IWL_DEBUG_INFO(DRV_NAME " is coming up\n"); @@ -6842,10 +6848,6 @@ static int __init iwl4965_init(void) return ret; - -#ifdef CONFIG_IWLWIFI_DEBUG - pci_unregister_driver(&iwl_driver); -#endif error_register: iwl4965_rate_control_unregister(); return ret; diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index a9102bc..3c2ac0c 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -306,8 +306,18 @@ struct ieee80211_ht_addt_info { #define IEEE80211_HT_CAP_SGI_40 0x0040 #define IEEE80211_HT_CAP_DELAY_BA 0x0400 #define IEEE80211_HT_CAP_MAX_AMSDU 0x0800 +/* 802.11n HT capability AMPDU settings */ #define IEEE80211_HT_CAP_AMPDU_FACTOR 0x03 #define IEEE80211_HT_CAP_AMPDU_DENSITY 0x1C +/* 802.11n HT capability MSC set */ +#define IEEE80211_SUPP_MCS_SET_UEQM 4 +#define IEEE80211_HT_CAP_MAX_STREAMS 4 +#define IEEE80211_SUPP_MCS_SET_LEN 10 +/* maximum streams the spec allows */ +#define IEEE80211_HT_CAP_MCS_TX_DEFINED 0x01 +#define IEEE80211_HT_CAP_MCS_TX_RX_DIFF 0x02 +#define IEEE80211_HT_CAP_MCS_TX_STREAMS 0x0C +#define IEEE80211_HT_CAP_MCS_TX_UEQM 0x10 /* 802.11n HT IE masks */ #define IEEE80211_HT_IE_CHA_SEC_OFFSET 0x03 #define IEEE80211_HT_IE_CHA_WIDTH 0x04 @@ -316,10 +326,10 @@ struct ieee80211_ht_addt_info { #define IEEE80211_HT_IE_NON_HT_STA_PRSNT 0x0010 /* MIMO Power Save Modes */ -#define WLAN_HT_CAP_MIMO_PS_STATIC 0 -#define WLAN_HT_CAP_MIMO_PS_DYNAMIC 1 -#define WLAN_HT_CAP_MIMO_PS_INVALID 2 -#define WLAN_HT_CAP_MIMO_PS_DISABLED 3 +#define WLAN_HT_CAP_MIMO_PS_STATIC 0 +#define WLAN_HT_CAP_MIMO_PS_DYNAMIC 1 +#define WLAN_HT_CAP_MIMO_PS_INVALID 2 +#define WLAN_HT_CAP_MIMO_PS_DISABLED 3 /* Authentication algorithms */ #define WLAN_AUTH_OPEN 0 diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 3601636..b0fddb7 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -35,8 +35,6 @@ #include "debugfs.h" #include "debugfs_netdev.h" -#define SUPP_MCS_SET_LEN 16 - /* * For seeing transmitted packets on monitor interfaces * we have a radiotap header too. @@ -1068,56 +1066,84 @@ u32 ieee80211_handle_ht(struct ieee80211_local *local, int enable_ht, struct ieee80211_supported_band *sband; struct ieee80211_ht_info ht_conf; struct ieee80211_ht_bss_info ht_bss_conf; - int i; u32 changed = 0; + int i; + u8 max_tx_streams = IEEE80211_HT_CAP_MAX_STREAMS; + u8 tx_mcs_set_cap; sband = local->hw.wiphy->bands[conf->channel->band]; + memset(&ht_conf, 0, sizeof(struct ieee80211_ht_info)); + memset(&ht_bss_conf, 0, sizeof(struct ieee80211_ht_bss_info)); + /* HT is not supported */ if (!sband->ht_info.ht_supported) { conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE; - return 0; + goto out; } - memset(&ht_conf, 0, sizeof(struct ieee80211_ht_info)); - memset(&ht_bss_conf, 0, sizeof(struct ieee80211_ht_bss_info)); - - if (enable_ht) { - if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)) + /* disable HT */ + if (!enable_ht) { + if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) changed |= BSS_CHANGED_HT; + conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE; + conf->ht_conf.ht_supported = 0; + goto out; + } - conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE; - ht_conf.ht_supported = 1; - ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap; - ht_conf.cap &= ~(IEEE80211_HT_CAP_MIMO_PS); - ht_conf.cap |= sband->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS; + if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)) + changed |= BSS_CHANGED_HT; - for (i = 0; i < SUPP_MCS_SET_LEN; i++) - ht_conf.supp_mcs_set[i] = - sband->ht_info.supp_mcs_set[i] & - req_ht_cap->supp_mcs_set[i]; + conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE; + ht_conf.ht_supported = 1; - ht_bss_conf.primary_channel = req_bss_cap->primary_channel; - ht_bss_conf.bss_cap = req_bss_cap->bss_cap; - ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode; + ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap; + ht_conf.cap &= ~(IEEE80211_HT_CAP_MIMO_PS); + ht_conf.cap |= sband->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS; + ht_bss_conf.primary_channel = req_bss_cap->primary_channel; + ht_bss_conf.bss_cap = req_bss_cap->bss_cap; + ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode; - ht_conf.ampdu_factor = req_ht_cap->ampdu_factor; - ht_conf.ampdu_density = req_ht_cap->ampdu_density; + ht_conf.ampdu_factor = req_ht_cap->ampdu_factor; + ht_conf.ampdu_density = req_ht_cap->ampdu_density; - /* if bss configuration changed store the new one */ - if (memcmp(&conf->ht_conf, &ht_conf, sizeof(ht_conf)) || - memcmp(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf))) { - changed |= BSS_CHANGED_HT; - memcpy(&conf->ht_conf, &ht_conf, sizeof(ht_conf)); - memcpy(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf)); - } - } else { - if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) - changed |= BSS_CHANGED_HT; - conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE; - } + /* Bits 96-100 */ + tx_mcs_set_cap = sband->ht_info.supp_mcs_set[12]; + /* configure suppoerted Tx MCS according to requested MCS + * (based in most cases on Rx capabilities of peer) and self + * Tx MCS capabilities (as defined by low level driver HW + * Tx capabilities) */ + if (!(tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_DEFINED)) + goto check_changed; + + /* Counting from 0 therfore + 1 */ + if (tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_RX_DIFF) + max_tx_streams = ((tx_mcs_set_cap & + IEEE80211_HT_CAP_MCS_TX_STREAMS) >> 2) + 1; + + for (i = 0; i < max_tx_streams; i++) + ht_conf.supp_mcs_set[i] = + sband->ht_info.supp_mcs_set[i] & + req_ht_cap->supp_mcs_set[i]; + + if (tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_UEQM) + for (i = IEEE80211_SUPP_MCS_SET_UEQM; + i < IEEE80211_SUPP_MCS_SET_LEN; i++) + ht_conf.supp_mcs_set[i] = + sband->ht_info.supp_mcs_set[i] & + req_ht_cap->supp_mcs_set[i]; + +check_changed: + /* if bss configuration changed store the new one */ + if (memcmp(&conf->ht_conf, &ht_conf, sizeof(ht_conf)) || + memcmp(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf))) { + changed |= BSS_CHANGED_HT; + memcpy(&conf->ht_conf, &ht_conf, sizeof(ht_conf)); + memcpy(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf)); + } +out: return changed; } -- cgit v0.10.2 From 39130df32adf8272373c03c8c2499cd2a1b4c5cf Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Thu, 15 May 2008 13:53:56 +0800 Subject: iwlwifi: filling Tx MCS set This patch fills the needed data about HW capabilities in matters of possible HT Tx MCS. Signed-off-by: Ron Rindjunsky Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index d3cbad2..a2f4f28 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -317,24 +317,33 @@ void iwl_reset_qos(struct iwl_priv *priv) EXPORT_SYMBOL(iwl_reset_qos); #ifdef CONFIG_IWL4965_HT +#define MAX_BIT_RATE_40_MHZ 0x96; /* 150 Mbps */ +#define MAX_BIT_RATE_20_MHZ 0x48; /* 72 Mbps */ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, struct ieee80211_ht_info *ht_info, enum ieee80211_band band) { + u16 max_bit_rate = 0; + u8 rx_chains_num = priv->hw_params.rx_chains_num; + u8 tx_chains_num = priv->hw_params.tx_chains_num; + ht_info->cap = 0; memset(ht_info->supp_mcs_set, 0, 16); ht_info->ht_supported = 1; + ht_info->cap |= (u16)IEEE80211_HT_CAP_GRN_FLD; + ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_20; + ht_info->cap |= (u16)(IEEE80211_HT_CAP_MIMO_PS & + (IWL_MIMO_PS_NONE << 2)); + + max_bit_rate = MAX_BIT_RATE_20_MHZ; if (priv->hw_params.fat_channel & BIT(band)) { ht_info->cap |= (u16)IEEE80211_HT_CAP_SUP_WIDTH; ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_40; ht_info->supp_mcs_set[4] = 0x01; + max_bit_rate = MAX_BIT_RATE_40_MHZ; } - ht_info->cap |= (u16)IEEE80211_HT_CAP_GRN_FLD; - ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_20; - ht_info->cap |= (u16)(IEEE80211_HT_CAP_MIMO_PS & - (IWL_MIMO_PS_NONE << 2)); if (priv->cfg->mod_params->amsdu_size_8K) ht_info->cap |= (u16)IEEE80211_HT_CAP_MAX_AMSDU; @@ -343,10 +352,22 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, ht_info->ampdu_density = CFG_HT_MPDU_DENSITY_DEF; ht_info->supp_mcs_set[0] = 0xFF; - if (priv->hw_params.tx_chains_num >= 2) + if (rx_chains_num >= 2) ht_info->supp_mcs_set[1] = 0xFF; - if (priv->hw_params.tx_chains_num >= 3) + if (rx_chains_num >= 3) ht_info->supp_mcs_set[2] = 0xFF; + + /* Highest supported Rx data rate */ + max_bit_rate *= rx_chains_num; + ht_info->supp_mcs_set[10] = (u8)(max_bit_rate & 0x00FF); + ht_info->supp_mcs_set[11] = (u8)((max_bit_rate & 0xFF00) >> 8); + + /* Tx MCS capabilities */ + ht_info->supp_mcs_set[12] = IEEE80211_HT_CAP_MCS_TX_DEFINED; + if (tx_chains_num != rx_chains_num) { + ht_info->supp_mcs_set[12] |= IEEE80211_HT_CAP_MCS_TX_RX_DIFF; + ht_info->supp_mcs_set[12] |= ((tx_chains_num - 1) << 2); + } } #else static inline void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, -- cgit v0.10.2 From 443cfd457f780e40ceab7e00fbb6a56882848834 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 15 May 2008 13:53:57 +0800 Subject: iwlwifi: rename iwl4965_queue to iwl_queue This patch renames iwl4965_queue to iwl_queue. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 17847f9..2bb0075 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -3231,7 +3231,7 @@ static int iwl4965_tx_queue_agg_disable(struct iwl_priv *priv, u16 txq_id, int iwl4965_check_empty_hw_queue(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id) { - struct iwl4965_queue *q = &priv->txq[txq_id].q; + struct iwl_queue *q = &priv->txq[txq_id].q; u8 *addr = priv->stations[sta_id].sta.sta.addr; struct iwl_tid_data *tid_data = &priv->stations[sta_id].tid[tid]; @@ -3263,16 +3263,6 @@ int iwl4965_check_empty_hw_queue(struct iwl_priv *priv, int sta_id, } /** - * iwl4965_queue_dec_wrap - Decrement queue index, wrap back to end if needed - * @index -- current index - * @n_bd -- total number of entries in queue (s/b power of 2) - */ -static inline int iwl4965_queue_dec_wrap(int index, int n_bd) -{ - return (index == 0) ? n_bd - 1 : index - 1; -} - -/** * iwl4965_rx_reply_compressed_ba - Handler for REPLY_COMPRESSED_BA * * Handles block-acknowledge notification from device, which reports success @@ -3304,7 +3294,7 @@ static void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv, agg = &priv->stations[ba_resp->sta_id].tid[ba_resp->tid].agg; /* Find index just before block-ack window */ - index = iwl4965_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd); + index = iwl_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd); /* TODO: Need to get this copy more safely - now good for debug */ @@ -3337,7 +3327,7 @@ static void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv, int freed = iwl4965_tx_queue_reclaim(priv, scd_flow, index); priv->stations[ba_resp->sta_id]. tid[ba_resp->tid].tfds_in_queue -= freed; - if (iwl4965_queue_space(&txq->q) > txq->q.low_mark && + if (iwl_queue_space(&txq->q) > txq->q.low_mark && priv->mac80211_registered && agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) ieee80211_wake_queue(priv->hw, ampdu_q); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 5dccc5a..cf99224 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -102,7 +102,7 @@ struct iwl_rx_mem_buffer { * * Contains common data for Rx and Tx queues */ -struct iwl4965_queue { +struct iwl_queue { int n_bd; /* number of BDs in this queue */ int write_ptr; /* 1-st empty entry (index) host_w*/ int read_ptr; /* last used entry (index) host_r*/ @@ -137,7 +137,7 @@ struct iwl4965_tx_info { * descriptors) and required locking structures. */ struct iwl_tx_queue { - struct iwl4965_queue q; + struct iwl_queue q; struct iwl_tfd_frame *bd; struct iwl_cmd *cmd; dma_addr_t dma_addr_cmd; @@ -721,7 +721,7 @@ extern u8 iwl_find_station(struct iwl_priv *priv, const u8 *bssid); extern int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel); extern int iwl4965_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index); -extern int iwl4965_queue_space(const struct iwl4965_queue *q); +extern int iwl_queue_space(const struct iwl_queue *q); struct iwl_priv; extern void iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio); diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index a1e03cc..870d257 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -105,7 +105,7 @@ EXPORT_SYMBOL(iwl_hw_txq_free_tfd); */ static void iwl_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq) { - struct iwl4965_queue *q = &txq->q; + struct iwl_queue *q = &txq->q; struct pci_dev *dev = priv->pci_dev; int len; @@ -158,7 +158,7 @@ EXPORT_SYMBOL(iwl_hw_txq_ctx_free); /** * iwl_queue_init - Initialize queue's high/low-water and read/write indexes */ -static int iwl_queue_init(struct iwl_priv *priv, struct iwl4965_queue *q, +static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q, int count, int slots_num, u32 id) { q->n_bd = count; diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index c713b27..2e7e616 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -173,7 +173,7 @@ static const char *iwl4965_escape_essid(const char *essid, u8 essid_len) * See more detailed info in iwl-4965-hw.h. ***************************************************/ -int iwl4965_queue_space(const struct iwl4965_queue *q) +int iwl_queue_space(const struct iwl_queue *q) { int s = q->read_ptr - q->write_ptr; @@ -190,14 +190,14 @@ int iwl4965_queue_space(const struct iwl4965_queue *q) } -static inline int x2_queue_used(const struct iwl4965_queue *q, int i) +static inline int iwl_queue_used(const struct iwl_queue *q, int i) { return q->write_ptr > q->read_ptr ? (i >= q->read_ptr && i < q->write_ptr) : !(i < q->read_ptr && i >= q->write_ptr); } -static inline u8 get_cmd_index(struct iwl4965_queue *q, u32 index, int is_huge) +static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge) { /* This is for scan command, the big buffer at end of command array */ if (is_huge) @@ -348,7 +348,7 @@ u8 iwl4965_add_station_flags(struct iwl_priv *priv, const u8 *addr, int iwl4965_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) { struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM]; - struct iwl4965_queue *q = &txq->q; + struct iwl_queue *q = &txq->q; struct iwl_tfd_frame *tfd; u32 *control_flags; struct iwl_cmd *out_cmd; @@ -369,7 +369,7 @@ int iwl4965_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) return -EIO; } - if (iwl4965_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) { + if (iwl_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) { IWL_ERROR("No space for Tx\n"); return -ENOSPC; } @@ -1768,7 +1768,7 @@ static int iwl4965_tx_skb(struct iwl_priv *priv, u32 *control_flags; int txq_id = ctl->queue; struct iwl_tx_queue *txq = NULL; - struct iwl4965_queue *q = NULL; + struct iwl_queue *q = NULL; dma_addr_t phys_addr; dma_addr_t txcmd_phys; dma_addr_t scratch_phys; @@ -1981,7 +1981,7 @@ static int iwl4965_tx_skb(struct iwl_priv *priv, if (rc) return rc; - if ((iwl4965_queue_space(q) < q->high_mark) + if ((iwl_queue_space(q) < q->high_mark) && priv->mac80211_registered) { if (wait_write_ptr) { spin_lock_irqsave(&priv->lock, flags); @@ -2332,10 +2332,10 @@ static void iwl4965_txstatus_to_ieee(struct iwl_priv *priv, int iwl4965_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) { struct iwl_tx_queue *txq = &priv->txq[txq_id]; - struct iwl4965_queue *q = &txq->q; + struct iwl_queue *q = &txq->q; int nfreed = 0; - if ((index >= q->n_bd) || (x2_queue_used(q, index) == 0)) { + if ((index >= q->n_bd) || (iwl_queue_used(q, index) == 0)) { IWL_ERROR("Read index for DMA queue txq id (%d), index %d, " "is out of range [0-%d] %d %d.\n", txq_id, index, q->n_bd, q->write_ptr, q->read_ptr); @@ -2541,7 +2541,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, __le16 *qc; #endif - if ((index >= txq->q.n_bd) || (x2_queue_used(&txq->q, index) == 0)) { + if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) { IWL_ERROR("Read index for DMA queue txq_id (%d) index %d " "is out of range [0-%d] %d %d\n", txq_id, index, txq->q.n_bd, txq->q.write_ptr, @@ -2587,7 +2587,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, freed = iwl4965_tx_queue_reclaim(priv, txq_id, index); priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; - if (iwl4965_queue_space(&txq->q) > txq->q.low_mark && + if (iwl_queue_space(&txq->q) > txq->q.low_mark && txq_id >= 0 && priv->mac80211_registered && agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) { /* calculate mac80211 ampdu sw queue to wake */ @@ -2621,7 +2621,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, int freed = iwl4965_tx_queue_reclaim(priv, txq_id, index); if (tid != MAX_TID_COUNT) priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; - if (iwl4965_queue_space(&txq->q) > txq->q.low_mark && + if (iwl_queue_space(&txq->q) > txq->q.low_mark && (txq_id >= 0) && priv->mac80211_registered) ieee80211_wake_queue(priv->hw, txq_id); if (tid != MAX_TID_COUNT) @@ -5783,7 +5783,7 @@ static int iwl4965_mac_get_tx_stats(struct ieee80211_hw *hw, struct iwl_priv *priv = hw->priv; int i, avail; struct iwl_tx_queue *txq; - struct iwl4965_queue *q; + struct iwl_queue *q; unsigned long flags; IWL_DEBUG_MAC80211("enter\n"); @@ -5798,7 +5798,7 @@ static int iwl4965_mac_get_tx_stats(struct ieee80211_hw *hw, for (i = 0; i < AC_NUM; i++) { txq = &priv->txq[i]; q = &txq->q; - avail = iwl4965_queue_space(q); + avail = iwl_queue_space(q); stats[i].len = q->n_window - avail; stats[i].limit = q->n_window - q->high_mark; -- cgit v0.10.2 From 8567c63e3385688b95658fe31b3ac8f4436b1b0f Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 15 May 2008 13:53:58 +0800 Subject: iwlwifi: rename iwl4965_tx_info to iwl_tx_info This patch renames iwl4965_tx_info to iwl_tx_info. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index cf99224..ae18a80 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -118,7 +118,7 @@ struct iwl_queue { #define MAX_NUM_OF_TBS (20) /* One for each TFD */ -struct iwl4965_tx_info { +struct iwl_tx_info { struct ieee80211_tx_status status; struct sk_buff *skb[MAX_NUM_OF_TBS]; }; @@ -141,7 +141,7 @@ struct iwl_tx_queue { struct iwl_tfd_frame *bd; struct iwl_cmd *cmd; dma_addr_t dma_addr_cmd; - struct iwl4965_tx_info *txb; + struct iwl_tx_info *txb; int need_update; int sched_retry; int active; diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 2e7e616..6e70405 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -1868,7 +1868,7 @@ static int iwl4965_tx_skb(struct iwl_priv *priv, idx = get_cmd_index(q, q->write_ptr, 0); /* Set up driver data for this TFD */ - memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl4965_tx_info)); + memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info)); txq->txb[q->write_ptr].skb[0] = skb; memcpy(&(txq->txb[q->write_ptr].status.control), ctl, sizeof(struct ieee80211_tx_control)); @@ -2306,7 +2306,7 @@ static int iwl4965_get_measurement(struct iwl_priv *priv, #endif static void iwl4965_txstatus_to_ieee(struct iwl_priv *priv, - struct iwl4965_tx_info *tx_sta) + struct iwl_tx_info *tx_sta) { tx_sta->status.ack_signal = 0; -- cgit v0.10.2 From c1adf9fb31e31ee753d613bd5bc6aef9b762b747 Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Thu, 15 May 2008 13:53:59 +0800 Subject: iwlwifi: get_hw_cmd_size This patch introduces a new handler get_hw_cmd_size in hcmd_utils, which should adjust the size of the command sent to the microcode according to the current nic. It also changes the RXON flow to make usage of this new handler. The patch also adds iwl_rxon_cmd structure which is supperset for 5000 HW and 4965. Signed-off-by: Gregory Greenman Signed-off-by: Zhu Yi Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 2bb0075..83876a0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -1857,8 +1857,8 @@ static int iwl4965_send_rxon_assoc(struct iwl_priv *priv) { int ret = 0; struct iwl4965_rxon_assoc_cmd rxon_assoc; - const struct iwl4965_rxon_cmd *rxon1 = &priv->staging_rxon; - const struct iwl4965_rxon_cmd *rxon2 = &priv->active_rxon; + const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon; + const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon; if ((rxon1->flags == rxon2->flags) && (rxon1->filter_flags == rxon2->filter_flags) && @@ -3743,6 +3743,16 @@ int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, #endif /* CONFIG_IWL4965_HT */ +static u16 iwl4965_get_hcmd_size(u8 cmd_id, u16 len) +{ + switch (cmd_id) { + case REPLY_RXON: + return (u16) sizeof(struct iwl4965_rxon_cmd); + default: + return len; + } +} + static u16 iwl4965_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data) { struct iwl4965_addsta_cmd *addsta = (struct iwl4965_addsta_cmd *)data; @@ -3802,6 +3812,7 @@ static struct iwl_hcmd_ops iwl4965_hcmd = { }; static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = { + .get_hcmd_size = iwl4965_get_hcmd_size, .enqueue_hcmd = iwl4965_enqueue_hcmd, .build_addsta_hcmd = iwl4965_build_addsta_hcmd, #ifdef CONFIG_IWL4965_RUN_TIME_CALIB diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index b5e28b8..72d655c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -459,10 +459,17 @@ static int iwl5000_disable_tx_fifo(struct iwl_priv *priv) return 0; } +/* Currently 5000 is the supperset of everything */ +static u16 iwl5000_get_hcmd_size(u8 cmd_id, u16 len) +{ + return len; +} + static struct iwl_hcmd_ops iwl5000_hcmd = { }; static struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = { + .get_hcmd_size = iwl5000_get_hcmd_size, .build_addsta_hcmd = iwl5000_build_addsta_hcmd, #ifdef CONFIG_IWL5000_RUN_TIME_CALIB .gain_computation = iwl5000_gain_computation, diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index d16a853..350af1b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -600,6 +600,32 @@ struct iwl4965_rxon_cmd { u8 ofdm_ht_dual_stream_basic_rates; } __attribute__ ((packed)); +/* 5000 HW just extend this cmmand */ +struct iwl_rxon_cmd { + u8 node_addr[6]; + __le16 reserved1; + u8 bssid_addr[6]; + __le16 reserved2; + u8 wlap_bssid_addr[6]; + __le16 reserved3; + u8 dev_type; + u8 air_propagation; + __le16 rx_chain; + u8 ofdm_basic_rates; + u8 cck_basic_rates; + __le16 assoc_id; + __le32 flags; + __le32 filter_flags; + __le16 channel; + u8 ofdm_ht_single_stream_basic_rates; + u8 ofdm_ht_dual_stream_basic_rates; + u8 ofdm_ht_triple_stream_basic_rates; + u8 reserved5; + __le16 acquisition_data; + __le16 reserved6; +} __attribute__ ((packed)); + + /* * REPLY_RXON_ASSOC = 0x11 (command, has simple generic response) */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index a2f4f28..b800031 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -588,7 +588,7 @@ EXPORT_SYMBOL(iwl_is_fat_tx_allowed); void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) { - struct iwl4965_rxon_cmd *rxon = &priv->staging_rxon; + struct iwl_rxon_cmd *rxon = &priv->staging_rxon; u32 val; if (!ht_info->is_ht) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index e139c8f..dcf1e56 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -86,6 +86,7 @@ struct iwl_hcmd_ops { int (*rxon_assoc)(struct iwl_priv *priv); }; struct iwl_hcmd_utils_ops { + u16 (*get_hcmd_size)(u8 cmd_id, u16 len); int (*enqueue_hcmd)(struct iwl_priv *priv, struct iwl_host_cmd *cmd); u16 (*build_addsta_hcmd)(const struct iwl_addsta_cmd *cmd, u8 *data); #ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB @@ -303,5 +304,4 @@ static inline int iwl_send_rxon_assoc(struct iwl_priv *priv) return priv->cfg->ops->hcmd->rxon_assoc(priv); } - #endif /* __iwl_core_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index ae18a80..9a842fd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1009,11 +1009,11 @@ struct iwl_priv { * changed via explicit cast within the * routines that actually update the physical * hardware */ - const struct iwl4965_rxon_cmd active_rxon; - struct iwl4965_rxon_cmd staging_rxon; + const struct iwl_rxon_cmd active_rxon; + struct iwl_rxon_cmd staging_rxon; int error_recovering; - struct iwl4965_rxon_cmd recovery_rxon; + struct iwl_rxon_cmd recovery_rxon; /* 1st responses from initialize and runtime uCode images. * 4965's initialize alive response contains some calibration data. */ diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 6e70405..45b6b52 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -353,11 +353,14 @@ int iwl4965_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) u32 *control_flags; struct iwl_cmd *out_cmd; u32 idx; - u16 fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr)); + u16 fix_size; dma_addr_t phys_addr; int ret; unsigned long flags; + cmd->len = priv->cfg->ops->utils->get_hcmd_size(cmd->id, cmd->len); + fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr)); + /* If any of the command structures end up being larger than * the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then * we will need to increase the size of the TFD entries */ @@ -422,7 +425,7 @@ int iwl4965_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) static void iwl4965_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt) { - struct iwl4965_rxon_cmd *rxon = &priv->staging_rxon; + struct iwl_rxon_cmd *rxon = &priv->staging_rxon; if (hw_decrypt) rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK; @@ -470,7 +473,7 @@ static int iwl4965_rxon_add_station(struct iwl_priv *priv, * be #ifdef'd out once the driver is stable and folks aren't actively * making changes */ -static int iwl4965_check_rxon_cmd(struct iwl4965_rxon_cmd *rxon) +static int iwl4965_check_rxon_cmd(struct iwl_rxon_cmd *rxon) { int error = 0; int counter = 1; @@ -595,7 +598,7 @@ static int iwl4965_full_rxon_required(struct iwl_priv *priv) static int iwl4965_commit_rxon(struct iwl_priv *priv) { /* cast away the const for active_rxon in this function */ - struct iwl4965_rxon_cmd *active_rxon = (void *)&priv->active_rxon; + struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon; DECLARE_MAC_BUF(mac); int rc = 0; @@ -640,7 +643,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; rc = iwl_send_cmd_pdu(priv, REPLY_RXON, - sizeof(struct iwl4965_rxon_cmd), + sizeof(struct iwl_rxon_cmd), &priv->active_rxon); /* If the mask clearing failed then we set @@ -665,7 +668,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) iwl4965_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto); /* Apply the new configuration */ rc = iwl_send_cmd_pdu(priv, REPLY_RXON, - sizeof(struct iwl4965_rxon_cmd), &priv->staging_rxon); + sizeof(struct iwl_rxon_cmd), &priv->staging_rxon); if (rc) { IWL_ERROR("Error setting new configuration (%d).\n", rc); return rc; @@ -2699,7 +2702,7 @@ static void iwl4965_rx_reply_error(struct iwl_priv *priv, static void iwl4965_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - struct iwl4965_rxon_cmd *rxon = (void *)&priv->active_rxon; + struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon; struct iwl4965_csa_notification *csa = &(pkt->u.csa_notif); IWL_DEBUG_11H("CSA notif: channel %d, status %d\n", le16_to_cpu(csa->channel), le32_to_cpu(csa->status)); @@ -3317,7 +3320,7 @@ static int iwl4965_tx_queue_update_write_ptr(struct iwl_priv *priv, #ifdef CONFIG_IWLWIFI_DEBUG static void iwl4965_print_rx_config_cmd(struct iwl_priv *priv) { - struct iwl4965_rxon_cmd *rxon = &priv->staging_rxon; + struct iwl_rxon_cmd *rxon = &priv->staging_rxon; DECLARE_MAC_BUF(mac); IWL_DEBUG_RADIO("RX CONFIG:\n"); @@ -4213,8 +4216,8 @@ static void iwl4965_alive_start(struct iwl_priv *priv) priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK; if (iwl_is_associated(priv)) { - struct iwl4965_rxon_cmd *active_rxon = - (struct iwl4965_rxon_cmd *)(&priv->active_rxon); + struct iwl_rxon_cmd *active_rxon = + (struct iwl_rxon_cmd *)&priv->active_rxon; memcpy(&priv->staging_rxon, &priv->active_rxon, sizeof(priv->staging_rxon)); @@ -5021,7 +5024,7 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw) /* we should be verifying the device is ready to be opened */ mutex_lock(&priv->mutex); - memset(&priv->staging_rxon, 0, sizeof(struct iwl4965_rxon_cmd)); + memset(&priv->staging_rxon, 0, sizeof(struct iwl_rxon_cmd)); /* fetch ucode file from disk, alloc and copy to bus-master buffers ... * ucode filename and max sizes are card-specific. */ -- cgit v0.10.2 From babcebfabbc3f52ba048495537baa9dffff080d4 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 15 May 2008 13:54:00 +0800 Subject: iwlwifi: remove 4965 from iwl4965_tx_queue_update_write_ptr This patch renames iwl4965_tx_queue_update_write_ptr to iwl_txq_update_write_ptr. This is a preparation for moving to iwl-tx.c. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 45b6b52..0ad9558 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -53,7 +53,7 @@ #include "iwl-sta.h" #include "iwl-calib.h" -static int iwl4965_tx_queue_update_write_ptr(struct iwl_priv *priv, +static int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq); /****************************************************************************** @@ -417,7 +417,7 @@ int iwl4965_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) /* Increment and update queue's write index */ q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); - ret = iwl4965_tx_queue_update_write_ptr(priv, txq); + ret = iwl_txq_update_write_ptr(priv, txq); spin_unlock_irqrestore(&priv->hcmd_lock, flags); return ret ? ret : idx; @@ -1978,7 +1978,7 @@ static int iwl4965_tx_skb(struct iwl_priv *priv, /* Tell device the write index *just past* this latest filled TFD */ q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); - rc = iwl4965_tx_queue_update_write_ptr(priv, txq); + rc = iwl_txq_update_write_ptr(priv, txq); spin_unlock_irqrestore(&priv->lock, flags); if (rc) @@ -1989,7 +1989,7 @@ static int iwl4965_tx_skb(struct iwl_priv *priv, if (wait_write_ptr) { spin_lock_irqsave(&priv->lock, flags); txq->need_update = 1; - iwl4965_tx_queue_update_write_ptr(priv, txq); + iwl_txq_update_write_ptr(priv, txq); spin_unlock_irqrestore(&priv->lock, flags); } @@ -3272,17 +3272,17 @@ int iwl4965_calc_sig_qual(int rssi_dbm, int noise_dbm) } /** - * iwl4965_tx_queue_update_write_ptr - Send new write index to hardware + * iwl_txq_update_write_ptr - Send new write index to hardware */ -static int iwl4965_tx_queue_update_write_ptr(struct iwl_priv *priv, +static int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq) { u32 reg = 0; - int rc = 0; + int ret = 0; int txq_id = txq->q.id; if (txq->need_update == 0) - return rc; + return ret; /* if we're trying to save power */ if (test_bit(STATUS_POWER_PMI, &priv->status)) { @@ -3295,13 +3295,13 @@ static int iwl4965_tx_queue_update_write_ptr(struct iwl_priv *priv, IWL_DEBUG_INFO("Requesting wakeup, GP1 = 0x%x\n", reg); iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - return rc; + return ret; } /* restore this queue's parameters in nic hardware. */ - rc = iwl_grab_nic_access(priv); - if (rc) - return rc; + ret = iwl_grab_nic_access(priv); + if (ret) + return ret; iwl_write_direct32(priv, HBUS_TARG_WRPTR, txq->q.write_ptr | (txq_id << 8)); iwl_release_nic_access(priv); @@ -3314,7 +3314,7 @@ static int iwl4965_tx_queue_update_write_ptr(struct iwl_priv *priv, txq->need_update = 0; - return rc; + return ret; } #ifdef CONFIG_IWLWIFI_DEBUG @@ -3706,12 +3706,12 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv) if (inta & CSR_INT_BIT_WAKEUP) { IWL_DEBUG_ISR("Wakeup interrupt\n"); iwl_rx_queue_update_write_ptr(priv, &priv->rxq); - iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[0]); - iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[1]); - iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[2]); - iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[3]); - iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[4]); - iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[5]); + iwl_txq_update_write_ptr(priv, &priv->txq[0]); + iwl_txq_update_write_ptr(priv, &priv->txq[1]); + iwl_txq_update_write_ptr(priv, &priv->txq[2]); + iwl_txq_update_write_ptr(priv, &priv->txq[3]); + iwl_txq_update_write_ptr(priv, &priv->txq[4]); + iwl_txq_update_write_ptr(priv, &priv->txq[5]); handled |= CSR_INT_BIT_WAKEUP; } -- cgit v0.10.2 From fcab423d716f923d6a7601ba33adf356bef83414 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 15 May 2008 13:54:01 +0800 Subject: iwlwifi: remove 4965 prefix from iwl4965_frame This patch removes 4965 from iwl4965_frame struct and handling functions. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 83876a0..922b0a1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2016,7 +2016,7 @@ int iwl4965_hw_get_temperature(struct iwl_priv *priv) } unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, - struct iwl4965_frame *frame, u8 rate) + struct iwl_frame *frame, u8 rate) { struct iwl4965_tx_beacon_cmd *tx_beacon_cmd; unsigned int frame_size; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 9a842fd..60a8f06 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -262,7 +262,7 @@ enum iwl_pwr_src { #define IEEE80211_HLEN (IEEE80211_4ADDR_LEN) #define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN) -struct iwl4965_frame { +struct iwl_frame { union { struct ieee80211_hdr frame; struct iwl4965_tx_beacon_cmd beacon; @@ -696,7 +696,7 @@ extern int iwl4965_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *tfd, dma_addr_t addr, u16 len); extern int iwl4965_hw_get_temperature(struct iwl_priv *priv); extern unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, - struct iwl4965_frame *frame, u8 rate); + struct iwl_frame *frame, u8 rate); extern void iwl4965_hw_build_tx_cmd_rate(struct iwl_priv *priv, struct iwl_cmd *cmd, struct ieee80211_tx_control *ctrl, diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 0ad9558..1c45b6f 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -800,7 +800,7 @@ static int iwl4965_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_fla return iwl_send_cmd(priv, &cmd); } -static void iwl4965_clear_free_frames(struct iwl_priv *priv) +static void iwl_clear_free_frames(struct iwl_priv *priv) { struct list_head *element; @@ -810,7 +810,7 @@ static void iwl4965_clear_free_frames(struct iwl_priv *priv) while (!list_empty(&priv->free_frames)) { element = priv->free_frames.next; list_del(element); - kfree(list_entry(element, struct iwl4965_frame, list)); + kfree(list_entry(element, struct iwl_frame, list)); priv->frames_count--; } @@ -821,9 +821,9 @@ static void iwl4965_clear_free_frames(struct iwl_priv *priv) } } -static struct iwl4965_frame *iwl4965_get_free_frame(struct iwl_priv *priv) +static struct iwl_frame *iwl_get_free_frame(struct iwl_priv *priv) { - struct iwl4965_frame *frame; + struct iwl_frame *frame; struct list_head *element; if (list_empty(&priv->free_frames)) { frame = kzalloc(sizeof(*frame), GFP_KERNEL); @@ -838,10 +838,10 @@ static struct iwl4965_frame *iwl4965_get_free_frame(struct iwl_priv *priv) element = priv->free_frames.next; list_del(element); - return list_entry(element, struct iwl4965_frame, list); + return list_entry(element, struct iwl_frame, list); } -static void iwl4965_free_frame(struct iwl_priv *priv, struct iwl4965_frame *frame) +static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame) { memset(frame, 0, sizeof(*frame)); list_add(&frame->list, &priv->free_frames); @@ -892,12 +892,12 @@ static u8 iwl4965_rate_get_lowest_plcp(struct iwl_priv *priv) static int iwl4965_send_beacon_cmd(struct iwl_priv *priv) { - struct iwl4965_frame *frame; + struct iwl_frame *frame; unsigned int frame_size; int rc; u8 rate; - frame = iwl4965_get_free_frame(priv); + frame = iwl_get_free_frame(priv); if (!frame) { IWL_ERROR("Could not obtain free frame buffer for beacon " @@ -912,7 +912,7 @@ static int iwl4965_send_beacon_cmd(struct iwl_priv *priv) rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size, &frame->u.cmd[0]); - iwl4965_free_frame(priv, frame); + iwl_free_frame(priv, frame); return rc; } @@ -4355,7 +4355,7 @@ static void __iwl4965_down(struct iwl_priv *priv) priv->ibss_beacon = NULL; /* clear out any free frames */ - iwl4965_clear_free_frames(priv); + iwl_clear_free_frames(priv); } static void iwl4965_down(struct iwl_priv *priv) -- cgit v0.10.2 From 1826dcc094466a39c82d4370ccfba694be0bc05b Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 15 May 2008 13:54:02 +0800 Subject: iwlwifi: remove 4965 from iwl4965_rate_info This patch removes 4965 from iwl4965_rate_info structure and associated variables. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index 8e3660e..e2123ab 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -481,7 +481,7 @@ static u32 rate_n_flags_from_tbl(struct iwl4965_scale_tbl_info *tbl, u32 rate_n_flags = 0; if (is_legacy(tbl->lq_type)) { - rate_n_flags = iwl4965_rates[index].plcp; + rate_n_flags = iwl_rates[index].plcp; if (index >= IWL_FIRST_CCK_RATE && index <= IWL_LAST_CCK_RATE) rate_n_flags |= RATE_MCS_CCK_MSK; @@ -493,11 +493,11 @@ static u32 rate_n_flags_from_tbl(struct iwl4965_scale_tbl_info *tbl, rate_n_flags = RATE_MCS_HT_MSK; if (is_siso(tbl->lq_type)) - rate_n_flags |= iwl4965_rates[index].plcp_siso; + rate_n_flags |= iwl_rates[index].plcp_siso; else if (is_mimo2(tbl->lq_type)) - rate_n_flags |= iwl4965_rates[index].plcp_mimo2; + rate_n_flags |= iwl_rates[index].plcp_mimo2; else - rate_n_flags |= iwl4965_rates[index].plcp_mimo3; + rate_n_flags |= iwl_rates[index].plcp_mimo3; } else { IWL_ERROR("Invalid tbl->lq_type %d\n", tbl->lq_type); } @@ -697,7 +697,7 @@ static u16 rs_get_adjacent_rate(struct iwl_priv *priv, u8 index, u16 rate_mask, low = index; while (low != IWL_RATE_INVALID) { - low = iwl4965_rates[low].prev_rs; + low = iwl_rates[low].prev_rs; if (low == IWL_RATE_INVALID) break; if (rate_mask & (1 << low)) @@ -707,7 +707,7 @@ static u16 rs_get_adjacent_rate(struct iwl_priv *priv, u8 index, u16 rate_mask, high = index; while (high != IWL_RATE_INVALID) { - high = iwl4965_rates[high].next_rs; + high = iwl_rates[high].next_rs; if (high == IWL_RATE_INVALID) break; if (rate_mask & (1 << high)) @@ -2088,7 +2088,7 @@ static void rs_initialize_lq(struct iwl_priv *priv, i = 0; /* FIXME:RS: This is also wrong in 4965 */ - rate = iwl4965_rates[i].plcp; + rate = iwl_rates[i].plcp; rate |= RATE_MCS_ANT_B_MSK; rate &= ~RATE_MCS_ANT_A_MSK; @@ -2691,7 +2691,7 @@ int iwl4965_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) int active = lq_sta->active_tbl; cnt += - sprintf(&buf[cnt], " %2dMbs: ", iwl4965_rates[i].ieee / 2); + sprintf(&buf[cnt], " %2dMbs: ", iwl_rates[i].ieee / 2); mask = (1ULL << (IWL_RATE_MAX_WINDOW - 1)); for (j = 0; j < IWL_RATE_MAX_WINDOW; j++, mask >>= 1) @@ -2702,7 +2702,7 @@ int iwl4965_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) samples += lq_sta->lq_info[active].win[i].counter; good += lq_sta->lq_info[active].win[i].success_counter; success += lq_sta->lq_info[active].win[i].success_counter * - iwl4965_rates[i].ieee; + iwl_rates[i].ieee; if (lq_sta->lq_info[active].win[i].stamp) { int delta = @@ -2722,10 +2722,11 @@ int iwl4965_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) i = j; } - /* Display the average rate of all samples taken. - * - * NOTE: We multiply # of samples by 2 since the IEEE measurement - * added from iwl4965_rates is actually 2X the rate */ + /* + * Display the average rate of all samples taken. + * NOTE: We multiply # of samples by 2 since the IEEE measurement + * added from iwl_rates is actually 2X the rate. + */ if (samples) cnt += sprintf(&buf[cnt], "\nAverage rate is %3d.%02dMbs over last %4dms\n" diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.h b/drivers/net/wireless/iwlwifi/iwl-4965-rs.h index 7ea2041..1dd4124 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.h @@ -29,7 +29,7 @@ #include "iwl-dev.h" -struct iwl4965_rate_info { +struct iwl_rate_info { u8 plcp; /* uCode API: IWL_RATE_6M_PLCP, etc. */ u8 plcp_siso; /* uCode API: IWL_RATE_SISO_6M_PLCP, etc. */ u8 plcp_mimo2; /* uCode API: IWL_RATE_MIMO2_6M_PLCP, etc. */ @@ -45,7 +45,7 @@ struct iwl4965_rate_info { /* * These serve as indexes into - * struct iwl4965_rate_info iwl4965_rates[IWL_RATE_COUNT]; + * struct iwl_rate_info iwl_rates[IWL_RATE_COUNT]; */ enum { IWL_RATE_1M_INDEX = 0, @@ -240,7 +240,7 @@ enum { #define TID_MAX_TIME_DIFF ((TID_QUEUE_MAX_SIZE - 1) * TID_QUEUE_CELL_SPACING) #define TIME_WRAP_AROUND(x, y) (((y) > (x)) ? (y) - (x) : (0-(x)) + (y)) -extern const struct iwl4965_rate_info iwl4965_rates[IWL_RATE_COUNT]; +extern const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT]; enum iwl_table_type { LQ_NONE, @@ -279,7 +279,7 @@ static inline u8 num_of_ant(u8 mask) static inline u8 iwl4965_get_prev_ieee_rate(u8 rate_index) { - u8 rate = iwl4965_rates[rate_index].prev_ieee; + u8 rate = iwl_rates[rate_index].prev_ieee; if (rate == IWL_RATE_INVALID) rate = rate_index; diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 922b0a1..1ec53a3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -345,8 +345,8 @@ int iwl4965_hwrate_to_plcp_idx(u32 rate_n_flags) /* 4965 legacy rate format, search for match in table */ } else { - for (idx = 0; idx < ARRAY_SIZE(iwl4965_rates); idx++) - if (iwl4965_rates[idx].plcp == (rate_n_flags & 0xFF)) + for (idx = 0; idx < ARRAY_SIZE(iwl_rates); idx++) + if (iwl_rates[idx].plcp == (rate_n_flags & 0xFF)) return idx; } @@ -1951,7 +1951,7 @@ void iwl4965_hw_build_tx_cmd_rate(struct iwl_priv *priv, u16 rate_flags = 0; int rate_idx = min(ctrl->tx_rate->hw_value & 0xffff, IWL_RATE_COUNT - 1); - rate_plcp = iwl4965_rates[rate_idx].plcp; + rate_plcp = iwl_rates[rate_idx].plcp; rts_retry_limit = (is_hcca) ? RTS_HCCA_RETRY_LIMIT : RTS_DFAULT_RETRY_LIMIT; @@ -2436,7 +2436,7 @@ static void iwl4965_add_radiotap(struct iwl_priv *priv, if (rate == -1) iwl4965_rt->rt_rate = 0; else - iwl4965_rt->rt_rate = iwl4965_rates[rate].ieee; + iwl4965_rt->rt_rate = iwl_rates[rate].ieee; /* * "antenna number" @@ -2848,7 +2848,7 @@ static void iwl4965_dbg_report_frame(struct iwl_priv *priv, if (unlikely(rate_idx == -1)) bitrate = 0; else - bitrate = iwl4965_rates[rate_idx].ieee / 2; + bitrate = iwl_rates[rate_idx].ieee / 2; /* print frame summary. * MAC addresses show just the last byte (for brevity), @@ -3473,7 +3473,7 @@ void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) rate_flags |= RATE_MCS_ANT_B_MSK; /*FIXME:RS*/ link_cmd.rs_table[i].rate_n_flags = - iwl4965_hw_set_rate_n_flags(iwl4965_rates[r].plcp, rate_flags); + iwl4965_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags); r = iwl4965_get_prev_ieee_rate(r); } diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index b800031..8e411de 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -67,7 +67,7 @@ MODULE_LICENSE("GPL"); * maps to IWL_RATE_INVALID * */ -const struct iwl4965_rate_info iwl4965_rates[IWL_RATE_COUNT] = { +const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = { IWL_DECLARE_RATE_INFO(1, INV, INV, 2, INV, 2, INV, 2), /* 1mbps */ IWL_DECLARE_RATE_INFO(2, INV, 1, 5, 1, 5, 1, 5), /* 2mbps */ IWL_DECLARE_RATE_INFO(5, INV, 2, 6, 2, 11, 2, 11), /*5.5mbps */ @@ -83,7 +83,7 @@ const struct iwl4965_rate_info iwl4965_rates[IWL_RATE_COUNT] = { IWL_DECLARE_RATE_INFO(60, 60, 48, INV, 48, INV, 48, INV),/* 60mbps */ /* FIXME:RS: ^^ should be INV (legacy) */ }; -EXPORT_SYMBOL(iwl4965_rates); +EXPORT_SYMBOL(iwl_rates); /* This function both allocates and initializes hw and priv. */ struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg, @@ -383,7 +383,7 @@ static void iwlcore_init_hw_rates(struct iwl_priv *priv, int i; for (i = 0; i < IWL_RATE_COUNT; i++) { - rates[i].bitrate = iwl4965_rates[i].ieee * 5; + rates[i].bitrate = iwl_rates[i].ieee * 5; rates[i].hw_value = i; /* Rate scaling will work on indexes */ rates[i].hw_value_short = i; rates[i].flags = 0; @@ -392,7 +392,7 @@ static void iwlcore_init_hw_rates(struct iwl_priv *priv, * If CCK != 1M then set short preamble rate flag. */ rates[i].flags |= - (iwl4965_rates[i].plcp == IWL_RATE_1M_PLCP) ? + (iwl_rates[i].plcp == IWL_RATE_1M_PLCP) ? 0 : IEEE80211_RATE_SHORT_PREAMBLE; } } diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 1c45b6f..edde814 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -878,9 +878,9 @@ static u8 iwl4965_rate_get_lowest_plcp(struct iwl_priv *priv) /* Find lowest valid rate */ for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID; - i = iwl4965_rates[i].next_ieee) { + i = iwl_rates[i].next_ieee) { if (rate_mask & (1 << i)) - return iwl4965_rates[i].plcp; + return iwl_rates[i].plcp; } /* No valid rate was found. Assign the lowest one */ @@ -939,7 +939,7 @@ static u16 iwl4965_supported_rate_to_ie(u8 *ie, u16 supported_rate, for (bit = 1, i = 0; i < IWL_RATE_COUNT; i++, bit <<= 1) { if (bit & supported_rate) { ret_rates |= bit; - rates[*cnt] = iwl4965_rates[i].ieee | + rates[*cnt] = iwl_rates[i].ieee | ((bit & basic_rate) ? 0x80 : 0x00); (*cnt)++; (*left)--; -- cgit v0.10.2 From 57bd1bea485bf6f37ff365dec2203ba6467b41a1 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 15 May 2008 13:54:03 +0800 Subject: iwlwifi: move iwl_bcast_addr to iwlcore This patch renames iwl4965_broadcast_addr to iwl_bcast_addr and moves it to iwlcore. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 1ec53a3..44215a7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2029,7 +2029,7 @@ unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, frame_size = iwl4965_fill_beacon_frame(priv, tx_beacon_cmd->frame, - iwl4965_broadcast_addr, + iwl_bcast_addr, sizeof(frame->u) - sizeof(*tx_beacon_cmd)); BUG_ON(frame_size > MAX_MPDU_SIZE); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 8e411de..79e46c5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -85,6 +85,11 @@ const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = { }; EXPORT_SYMBOL(iwl_rates); + +const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; +EXPORT_SYMBOL(iwl_bcast_addr); + + /* This function both allocates and initializes hw and priv. */ struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg, struct ieee80211_ops *hw_ops) diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 60a8f06..8809fe3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -659,7 +659,7 @@ int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src); int iwl4965_init_geos(struct iwl_priv *priv); void iwl4965_free_geos(struct iwl_priv *priv); -extern const u8 iwl4965_broadcast_addr[ETH_ALEN]; +extern const u8 iwl_bcast_addr[ETH_ALEN]; int iwl4965_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd); /* diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index edde814..bb820f3 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -207,7 +207,6 @@ static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge) return index & (q->n_window - 1); } -const u8 iwl4965_broadcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; /*************** STATION TABLE MANAGEMENT **** * mac80211 should be examined to determine if sta_info is duplicating @@ -692,7 +691,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) } /* Add the broadcast address so we can send broadcast frames */ - if (iwl4965_rxon_add_station(priv, iwl4965_broadcast_addr, 0) == + if (iwl4965_rxon_add_station(priv, iwl_bcast_addr, 0) == IWL_INVALID_STATION) { IWL_ERROR("Error adding BROADCAST address for transmit.\n"); return -EIO; @@ -1059,9 +1058,9 @@ static u16 iwl4965_fill_probe_req(struct iwl_priv *priv, len += 24; frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); - memcpy(frame->da, iwl4965_broadcast_addr, ETH_ALEN); + memcpy(frame->da, iwl_bcast_addr, ETH_ALEN); memcpy(frame->sa, priv->mac_addr, ETH_ALEN); - memcpy(frame->bssid, iwl4965_broadcast_addr, ETH_ALEN); + memcpy(frame->bssid, iwl_bcast_addr, ETH_ALEN); frame->seq_ctrl = 0; /* fill in our indirect SSID IE */ @@ -4912,7 +4911,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv) /* clear out the station table */ iwlcore_clear_stations_table(priv); - iwl4965_rxon_add_station(priv, iwl4965_broadcast_addr, 0); + iwl4965_rxon_add_station(priv, iwl_bcast_addr, 0); iwl4965_rxon_add_station(priv, priv->bssid, 0); iwl4965_rate_scale_init(priv->hw, IWL_STA_ID); iwl4965_send_beacon_cmd(priv); @@ -5324,7 +5323,7 @@ static void iwl4965_config_ap(struct iwl_priv *priv) priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; iwl4965_commit_rxon(priv); iwl4965_activate_qos(priv, 1); - iwl4965_rxon_add_station(priv, iwl4965_broadcast_addr, 0); + iwl4965_rxon_add_station(priv, iwl_bcast_addr, 0); } iwl4965_send_beacon_cmd(priv); -- cgit v0.10.2 From 4f40e4d9fb8fe028db9ba2a7b4d3ac7328f73bbc Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 15 May 2008 13:54:04 +0800 Subject: iwlwifi: move more station managment into iwl-sta.c This patch moves station management functions into iwl-sta.c (iwlcore). Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index e2123ab..ce70f2b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -2150,7 +2150,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_RATE("LQ: ADD station %s\n", print_mac(mac, hdr->addr1)); - sta_id = iwl4965_add_station_flags(priv, hdr->addr1, + sta_id = iwl_add_station_flags(priv, hdr->addr1, 0, CMD_ASYNC, NULL); } if ((sta_id != IWL_INVALID_STATION)) { @@ -2234,7 +2234,7 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_RATE("LQ: ADD station %s\n", print_mac(mac, sta->addr)); - sta_id = iwl4965_add_station_flags(priv, sta->addr, + sta_id = iwl_add_station_flags(priv, sta->addr, 0, CMD_ASYNC, NULL); } if ((sta_id != IWL_INVALID_STATION)) { diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 44215a7..aeaf5f7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -3433,109 +3433,8 @@ static int iwl4965_tx_queue_agg_enable(struct iwl_priv *priv, int txq_id, #endif /* CONFIG_IWL4965_HT */ -/** - * iwl4965_add_station - Initialize a station's hardware rate table - * - * The uCode's station table contains a table of fallback rates - * for automatic fallback during transmission. - * - * NOTE: This sets up a default set of values. These will be replaced later - * if the driver's iwl-4965-rs rate scaling algorithm is used, instead of - * rc80211_simple. - * - * NOTE: Run REPLY_ADD_STA command to set up station table entry, before - * calling this function (which runs REPLY_TX_LINK_QUALITY_CMD, - * which requires station table entry to exist). - */ -void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) -{ - int i, r; - struct iwl_link_quality_cmd link_cmd = { - .reserved1 = 0, - }; - u16 rate_flags; - - /* Set up the rate scaling to start at selected rate, fall back - * all the way down to 1M in IEEE order, and then spin on 1M */ - if (is_ap) - r = IWL_RATE_54M_INDEX; - else if (priv->band == IEEE80211_BAND_5GHZ) - r = IWL_RATE_6M_INDEX; - else - r = IWL_RATE_1M_INDEX; - - for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) { - rate_flags = 0; - if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE) - rate_flags |= RATE_MCS_CCK_MSK; - - /* Use Tx antenna B only */ - rate_flags |= RATE_MCS_ANT_B_MSK; /*FIXME:RS*/ - - link_cmd.rs_table[i].rate_n_flags = - iwl4965_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags); - r = iwl4965_get_prev_ieee_rate(r); - } - - link_cmd.general_params.single_stream_ant_msk = 2; - link_cmd.general_params.dual_stream_ant_msk = 3; - link_cmd.agg_params.agg_dis_start_th = 3; - link_cmd.agg_params.agg_time_limit = cpu_to_le16(4000); - - /* Update the rate scaling for control frame Tx to AP */ - link_cmd.sta_id = is_ap ? IWL_AP_ID : priv->hw_params.bcast_sta_id; - - iwl_send_cmd_pdu_async(priv, REPLY_TX_LINK_QUALITY_CMD, - sizeof(link_cmd), &link_cmd, NULL); -} #ifdef CONFIG_IWL4965_HT - -void iwl4965_set_ht_add_station(struct iwl_priv *priv, u8 index, - struct ieee80211_ht_info *sta_ht_inf) -{ - __le32 sta_flags; - u8 mimo_ps_mode; - - if (!sta_ht_inf || !sta_ht_inf->ht_supported) - goto done; - - mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2; - - sta_flags = priv->stations[index].sta.station_flags; - - sta_flags &= ~(STA_FLG_RTS_MIMO_PROT_MSK | STA_FLG_MIMO_DIS_MSK); - - switch (mimo_ps_mode) { - case WLAN_HT_CAP_MIMO_PS_STATIC: - sta_flags |= STA_FLG_MIMO_DIS_MSK; - break; - case WLAN_HT_CAP_MIMO_PS_DYNAMIC: - sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK; - break; - case WLAN_HT_CAP_MIMO_PS_DISABLED: - break; - default: - IWL_WARNING("Invalid MIMO PS mode %d", mimo_ps_mode); - break; - } - - sta_flags |= cpu_to_le32( - (u32)sta_ht_inf->ampdu_factor << STA_FLG_MAX_AGG_SIZE_POS); - - sta_flags |= cpu_to_le32( - (u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS); - - if (iwl_is_fat_tx_allowed(priv, sta_ht_inf)) - sta_flags |= STA_FLG_FAT_EN_MSK; - else - sta_flags &= ~STA_FLG_FAT_EN_MSK; - - priv->stations[index].sta.station_flags = sta_flags; - done: - return; -} - static int iwl4965_rx_agg_start(struct iwl_priv *priv, const u8 *addr, int tid, u16 ssn) { diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 8809fe3..565d7dc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -635,8 +635,8 @@ struct iwl_hw_params { struct iwl_addsta_cmd; extern int iwl_send_add_sta(struct iwl_priv *priv, struct iwl_addsta_cmd *sta, u8 flags); -extern u8 iwl4965_add_station_flags(struct iwl_priv *priv, const u8 *addr, - int is_ap, u8 flags, void *ht_data); +u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap, + u8 flags, struct ieee80211_ht_info *ht_info); extern int iwl4965_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header); extern int iwl4965_power_init_handle(struct iwl_priv *priv); @@ -731,8 +731,6 @@ extern void iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio); extern int iwl4965_tx_queue_update_wr_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq, u16 byte_cnt); -extern void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, - int is_ap); extern int iwl4965_alive_notify(struct iwl_priv *priv); extern void iwl4965_update_rate_scaling(struct iwl_priv *priv, u8 mode); extern void iwl4965_rf_kill_ct_config(struct iwl_priv *priv); @@ -746,8 +744,6 @@ extern void iwl4965_init_ht_hw_capab(const struct iwl_priv *priv, enum ieee80211_band band); void iwl4965_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info); -void iwl4965_set_ht_add_station(struct iwl_priv *priv, u8 index, - struct ieee80211_ht_info *sta_ht_inf); int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, enum ieee80211_ampdu_mlme_action action, const u8 *addr, u16 tid, u16 *ssn); diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index f226704..c8e468f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -117,6 +117,130 @@ int iwl_send_add_sta(struct iwl_priv *priv, } EXPORT_SYMBOL(iwl_send_add_sta); +#ifdef CONFIG_IWL4965_HT + +static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index, + struct ieee80211_ht_info *sta_ht_inf) +{ + __le32 sta_flags; + u8 mimo_ps_mode; + + if (!sta_ht_inf || !sta_ht_inf->ht_supported) + goto done; + + mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2; + + sta_flags = priv->stations[index].sta.station_flags; + + sta_flags &= ~(STA_FLG_RTS_MIMO_PROT_MSK | STA_FLG_MIMO_DIS_MSK); + + switch (mimo_ps_mode) { + case WLAN_HT_CAP_MIMO_PS_STATIC: + sta_flags |= STA_FLG_MIMO_DIS_MSK; + break; + case WLAN_HT_CAP_MIMO_PS_DYNAMIC: + sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK; + break; + case WLAN_HT_CAP_MIMO_PS_DISABLED: + break; + default: + IWL_WARNING("Invalid MIMO PS mode %d", mimo_ps_mode); + break; + } + + sta_flags |= cpu_to_le32( + (u32)sta_ht_inf->ampdu_factor << STA_FLG_MAX_AGG_SIZE_POS); + + sta_flags |= cpu_to_le32( + (u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS); + + if (iwl_is_fat_tx_allowed(priv, sta_ht_inf)) + sta_flags |= STA_FLG_FAT_EN_MSK; + else + sta_flags &= ~STA_FLG_FAT_EN_MSK; + + priv->stations[index].sta.station_flags = sta_flags; + done: + return; +} +#else +static inline void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index, + struct ieee80211_ht_info *sta_ht_info) +{ +} +#endif + +/** + * iwl_add_station_flags - Add station to tables in driver and device + */ +u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap, + u8 flags, struct ieee80211_ht_info *ht_info) +{ + int i; + int index = IWL_INVALID_STATION; + struct iwl_station_entry *station; + unsigned long flags_spin; + DECLARE_MAC_BUF(mac); + + spin_lock_irqsave(&priv->sta_lock, flags_spin); + if (is_ap) + index = IWL_AP_ID; + else if (is_broadcast_ether_addr(addr)) + index = priv->hw_params.bcast_sta_id; + else + for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) { + if (!compare_ether_addr(priv->stations[i].sta.sta.addr, + addr)) { + index = i; + break; + } + + if (!priv->stations[i].used && + index == IWL_INVALID_STATION) + index = i; + } + + + /* These two conditions have the same outcome, but keep them separate + since they have different meanings */ + if (unlikely(index == IWL_INVALID_STATION)) { + spin_unlock_irqrestore(&priv->sta_lock, flags_spin); + return index; + } + + if (priv->stations[index].used && + !compare_ether_addr(priv->stations[index].sta.sta.addr, addr)) { + spin_unlock_irqrestore(&priv->sta_lock, flags_spin); + return index; + } + + + IWL_DEBUG_ASSOC("Add STA ID %d: %s\n", index, print_mac(mac, addr)); + station = &priv->stations[index]; + station->used = 1; + priv->num_stations++; + + /* Set up the REPLY_ADD_STA command to send to device */ + memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd)); + memcpy(station->sta.sta.addr, addr, ETH_ALEN); + station->sta.mode = 0; + station->sta.sta.sta_id = index; + station->sta.station_flags = 0; + + /* BCAST station and IBSS stations do not work in HT mode */ + if (index != priv->hw_params.bcast_sta_id && + priv->iw_mode != IEEE80211_IF_TYPE_IBSS) + iwl_set_ht_add_station(priv, index, ht_info); + + spin_unlock_irqrestore(&priv->sta_lock, flags_spin); + + /* Add station to device's station table */ + iwl_send_add_sta(priv, &station->sta, flags); + return index; + +} +EXPORT_SYMBOL(iwl_add_station_flags); + int iwl_get_free_ucode_key_index(struct iwl_priv *priv) { int i; @@ -470,3 +594,148 @@ int iwl_send_lq_cmd(struct iwl_priv *priv, } EXPORT_SYMBOL(iwl_send_lq_cmd); +/** + * iwl_sta_init_lq - Initialize a station's hardware rate table + * + * The uCode's station table contains a table of fallback rates + * for automatic fallback during transmission. + * + * NOTE: This sets up a default set of values. These will be replaced later + * if the driver's iwl-4965-rs rate scaling algorithm is used, instead of + * rc80211_simple. + * + * NOTE: Run REPLY_ADD_STA command to set up station table entry, before + * calling this function (which runs REPLY_TX_LINK_QUALITY_CMD, + * which requires station table entry to exist). + */ +static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap) +{ + int i, r; + struct iwl_link_quality_cmd link_cmd = { + .reserved1 = 0, + }; + u16 rate_flags; + + /* Set up the rate scaling to start at selected rate, fall back + * all the way down to 1M in IEEE order, and then spin on 1M */ + if (is_ap) + r = IWL_RATE_54M_INDEX; + else if (priv->band == IEEE80211_BAND_5GHZ) + r = IWL_RATE_6M_INDEX; + else + r = IWL_RATE_1M_INDEX; + + for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) { + rate_flags = 0; + if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE) + rate_flags |= RATE_MCS_CCK_MSK; + + /* Use Tx antenna B only */ + rate_flags |= RATE_MCS_ANT_B_MSK; /*FIXME:RS*/ + + link_cmd.rs_table[i].rate_n_flags = + iwl4965_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags); + r = iwl4965_get_prev_ieee_rate(r); + } + + link_cmd.general_params.single_stream_ant_msk = 2; + link_cmd.general_params.dual_stream_ant_msk = 3; + link_cmd.agg_params.agg_dis_start_th = 3; + link_cmd.agg_params.agg_time_limit = cpu_to_le16(4000); + + /* Update the rate scaling for control frame Tx to AP */ + link_cmd.sta_id = is_ap ? IWL_AP_ID : priv->hw_params.bcast_sta_id; + + iwl_send_cmd_pdu_async(priv, REPLY_TX_LINK_QUALITY_CMD, + sizeof(link_cmd), &link_cmd, NULL); +} +/** + * iwl_rxon_add_station - add station into station table. + * + * there is only one AP station with id= IWL_AP_ID + * NOTE: mutex must be held before calling this fnction + */ +int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) +{ + u8 sta_id; + + /* Add station to device's station table */ +#ifdef CONFIG_IWL4965_HT + struct ieee80211_conf *conf = &priv->hw->conf; + struct ieee80211_ht_info *cur_ht_config = &conf->ht_conf; + + if ((is_ap) && + (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) && + (priv->iw_mode == IEEE80211_IF_TYPE_STA)) + sta_id = iwl_add_station_flags(priv, addr, is_ap, + 0, cur_ht_config); + else +#endif /* CONFIG_IWL4965_HT */ + sta_id = iwl_add_station_flags(priv, addr, is_ap, + 0, NULL); + + /* Set up default rate scaling table in device's station table */ + iwl_sta_init_lq(priv, addr, is_ap); + + return sta_id; +} +EXPORT_SYMBOL(iwl_rxon_add_station); + + +/** + * iwl_get_sta_id - Find station's index within station table + * + * If new IBSS station, create new entry in station table + */ +int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) +{ + int sta_id; + u16 fc = le16_to_cpu(hdr->frame_control); + DECLARE_MAC_BUF(mac); + + /* If this frame is broadcast or management, use broadcast station id */ + if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) || + is_multicast_ether_addr(hdr->addr1)) + return priv->hw_params.bcast_sta_id; + + switch (priv->iw_mode) { + + /* If we are a client station in a BSS network, use the special + * AP station entry (that's the only station we communicate with) */ + case IEEE80211_IF_TYPE_STA: + return IWL_AP_ID; + + /* If we are an AP, then find the station, or use BCAST */ + case IEEE80211_IF_TYPE_AP: + sta_id = iwl_find_station(priv, hdr->addr1); + if (sta_id != IWL_INVALID_STATION) + return sta_id; + return priv->hw_params.bcast_sta_id; + + /* If this frame is going out to an IBSS network, find the station, + * or create a new station table entry */ + case IEEE80211_IF_TYPE_IBSS: + sta_id = iwl_find_station(priv, hdr->addr1); + if (sta_id != IWL_INVALID_STATION) + return sta_id; + + /* Create new station table entry */ + sta_id = iwl_add_station_flags(priv, hdr->addr1, + 0, CMD_ASYNC, NULL); + + if (sta_id != IWL_INVALID_STATION) + return sta_id; + + IWL_DEBUG_DROP("Station %s not in station map. " + "Defaulting to broadcast...\n", + print_mac(mac, hdr->addr1)); + iwl_print_hex_dump(priv, IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); + return priv->hw_params.bcast_sta_id; + + default: + IWL_WARNING("Unknown mode of operation: %d", priv->iw_mode); + return priv->hw_params.bcast_sta_id; + } +} +EXPORT_SYMBOL(iwl_get_sta_id); + diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h index 38b1b0a..ee25643 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.h +++ b/drivers/net/wireless/iwlwifi/iwl-sta.h @@ -39,4 +39,6 @@ int iwl_set_dynamic_key(struct iwl_priv *priv, struct ieee80211_key_conf *key, u8 sta_id); int iwl_remove_dynamic_key(struct iwl_priv *priv, struct ieee80211_key_conf *key, u8 sta_id); +int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap); +int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr); #endif /* __iwl_sta_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index bb820f3..88032cc 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -258,79 +258,6 @@ out: } #endif -/** - * iwl4965_add_station_flags - Add station to tables in driver and device - */ -u8 iwl4965_add_station_flags(struct iwl_priv *priv, const u8 *addr, - int is_ap, u8 flags, void *ht_data) -{ - int i; - int index = IWL_INVALID_STATION; - struct iwl_station_entry *station; - unsigned long flags_spin; - DECLARE_MAC_BUF(mac); - - spin_lock_irqsave(&priv->sta_lock, flags_spin); - if (is_ap) - index = IWL_AP_ID; - else if (is_broadcast_ether_addr(addr)) - index = priv->hw_params.bcast_sta_id; - else - for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) { - if (!compare_ether_addr(priv->stations[i].sta.sta.addr, - addr)) { - index = i; - break; - } - - if (!priv->stations[i].used && - index == IWL_INVALID_STATION) - index = i; - } - - - /* These two conditions have the same outcome, but keep them separate - since they have different meanings */ - if (unlikely(index == IWL_INVALID_STATION)) { - spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - return index; - } - - if (priv->stations[index].used && - !compare_ether_addr(priv->stations[index].sta.sta.addr, addr)) { - spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - return index; - } - - - IWL_DEBUG_ASSOC("Add STA ID %d: %s\n", index, print_mac(mac, addr)); - station = &priv->stations[index]; - station->used = 1; - priv->num_stations++; - - /* Set up the REPLY_ADD_STA command to send to device */ - memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd)); - memcpy(station->sta.sta.addr, addr, ETH_ALEN); - station->sta.mode = 0; - station->sta.sta.sta_id = index; - station->sta.station_flags = 0; - -#ifdef CONFIG_IWL4965_HT - /* BCAST station and IBSS stations do not work in HT mode */ - if (index != priv->hw_params.bcast_sta_id && - priv->iw_mode != IEEE80211_IF_TYPE_IBSS) - iwl4965_set_ht_add_station(priv, index, - (struct ieee80211_ht_info *) ht_data); -#endif /*CONFIG_IWL4965_HT*/ - - spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - - /* Add station to device's station table */ - iwl_send_add_sta(priv, &station->sta, flags); - return index; - -} - /*************** HOST COMMAND QUEUE FUNCTIONS *****/ @@ -434,38 +361,6 @@ static void iwl4965_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt) } /** - * iwl4965_rxon_add_station - add station into station table. - * - * there is only one AP station with id= IWL_AP_ID - * NOTE: mutex must be held before calling this fnction - */ -static int iwl4965_rxon_add_station(struct iwl_priv *priv, - const u8 *addr, int is_ap) -{ - u8 sta_id; - - /* Add station to device's station table */ -#ifdef CONFIG_IWL4965_HT - struct ieee80211_conf *conf = &priv->hw->conf; - struct ieee80211_ht_info *cur_ht_config = &conf->ht_conf; - - if ((is_ap) && - (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) && - (priv->iw_mode == IEEE80211_IF_TYPE_STA)) - sta_id = iwl4965_add_station_flags(priv, addr, is_ap, - 0, cur_ht_config); - else -#endif /* CONFIG_IWL4965_HT */ - sta_id = iwl4965_add_station_flags(priv, addr, is_ap, - 0, NULL); - - /* Set up default rate scaling table in device's station table */ - iwl4965_add_station(priv, addr, is_ap); - - return sta_id; -} - -/** * iwl4965_check_rxon_cmd - validate RXON structure is valid * * NOTE: This is really only useful during development and can eventually @@ -691,7 +586,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) } /* Add the broadcast address so we can send broadcast frames */ - if (iwl4965_rxon_add_station(priv, iwl_bcast_addr, 0) == + if (iwl_rxon_add_station(priv, iwl_bcast_addr, 0) == IWL_INVALID_STATION) { IWL_ERROR("Error adding BROADCAST address for transmit.\n"); return -EIO; @@ -701,7 +596,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) * add the IWL_AP_ID to the station rate table */ if (iwl_is_associated(priv) && (priv->iw_mode == IEEE80211_IF_TYPE_STA)) { - if (iwl4965_rxon_add_station(priv, priv->active_rxon.bssid_addr, 1) + if (iwl_rxon_add_station(priv, priv->active_rxon.bssid_addr, 1) == IWL_INVALID_STATION) { IWL_ERROR("Error adding AP address for transmit.\n"); return -EIO; @@ -1702,63 +1597,6 @@ static void iwl_update_tx_stats(struct iwl_priv *priv, u16 fc, u16 len) priv->tx_stats[idx].cnt++; priv->tx_stats[idx].bytes += len; } -/** - * iwl4965_get_sta_id - Find station's index within station table - * - * If new IBSS station, create new entry in station table - */ -static int iwl4965_get_sta_id(struct iwl_priv *priv, - struct ieee80211_hdr *hdr) -{ - int sta_id; - u16 fc = le16_to_cpu(hdr->frame_control); - DECLARE_MAC_BUF(mac); - - /* If this frame is broadcast or management, use broadcast station id */ - if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) || - is_multicast_ether_addr(hdr->addr1)) - return priv->hw_params.bcast_sta_id; - - switch (priv->iw_mode) { - - /* If we are a client station in a BSS network, use the special - * AP station entry (that's the only station we communicate with) */ - case IEEE80211_IF_TYPE_STA: - return IWL_AP_ID; - - /* If we are an AP, then find the station, or use BCAST */ - case IEEE80211_IF_TYPE_AP: - sta_id = iwl_find_station(priv, hdr->addr1); - if (sta_id != IWL_INVALID_STATION) - return sta_id; - return priv->hw_params.bcast_sta_id; - - /* If this frame is going out to an IBSS network, find the station, - * or create a new station table entry */ - case IEEE80211_IF_TYPE_IBSS: - sta_id = iwl_find_station(priv, hdr->addr1); - if (sta_id != IWL_INVALID_STATION) - return sta_id; - - /* Create new station table entry */ - sta_id = iwl4965_add_station_flags(priv, hdr->addr1, - 0, CMD_ASYNC, NULL); - - if (sta_id != IWL_INVALID_STATION) - return sta_id; - - IWL_DEBUG_DROP("Station %s not in station map. " - "Defaulting to broadcast...\n", - print_mac(mac, hdr->addr1)); - iwl_print_hex_dump(priv, IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); - return priv->hw_params.bcast_sta_id; - - default: - IWL_WARNING("Unknown mode of operation: %d", priv->iw_mode); - return priv->hw_params.bcast_sta_id; - } -} - /* * start REPLY_TX command process */ @@ -1829,7 +1667,7 @@ static int iwl4965_tx_skb(struct iwl_priv *priv, hdr_len = ieee80211_get_hdrlen(fc); /* Find (or create) index into station table for destination station */ - sta_id = iwl4965_get_sta_id(priv, hdr); + sta_id = iwl_get_sta_id(priv, hdr); if (sta_id == IWL_INVALID_STATION) { DECLARE_MAC_BUF(mac); @@ -3585,7 +3423,7 @@ static void iwl4965_error_recovery(struct iwl_priv *priv) priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; iwl4965_commit_rxon(priv); - iwl4965_rxon_add_station(priv, priv->bssid, 1); + iwl_rxon_add_station(priv, priv->bssid, 1); spin_lock_irqsave(&priv->lock, flags); priv->assoc_id = le16_to_cpu(priv->staging_rxon.assoc_id); @@ -4911,8 +4749,8 @@ static void iwl4965_post_associate(struct iwl_priv *priv) /* clear out the station table */ iwlcore_clear_stations_table(priv); - iwl4965_rxon_add_station(priv, iwl_bcast_addr, 0); - iwl4965_rxon_add_station(priv, priv->bssid, 0); + iwl_rxon_add_station(priv, iwl_bcast_addr, 0); + iwl_rxon_add_station(priv, priv->bssid, 0); iwl4965_rate_scale_init(priv->hw, IWL_STA_ID); iwl4965_send_beacon_cmd(priv); @@ -5323,7 +5161,7 @@ static void iwl4965_config_ap(struct iwl_priv *priv) priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; iwl4965_commit_rxon(priv); iwl4965_activate_qos(priv, 1); - iwl4965_rxon_add_station(priv, iwl_bcast_addr, 0); + iwl_rxon_add_station(priv, iwl_bcast_addr, 0); } iwl4965_send_beacon_cmd(priv); @@ -5412,7 +5250,7 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, else { rc = iwl4965_commit_rxon(priv); if ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && rc) - iwl4965_rxon_add_station( + iwl_rxon_add_station( priv, priv->active_rxon.bssid_addr, 1); } -- cgit v0.10.2 From 83d527d9e8f9aff92cbd33f208f77c055dabb499 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 15 May 2008 13:54:05 +0800 Subject: iwlwifi: remove 4956 form iwl4965_tx_cmd This patch renames iwl4965_tx_cmd to iwl_tx_cmd and cleans collateral code. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index aeaf5f7..02bbe04 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -1053,7 +1053,6 @@ int iwl4965_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues; priv->hw_params.sw_crypto = priv->cfg->mod_params->sw_crypto; - priv->hw_params.tx_cmd_len = sizeof(struct iwl4965_tx_cmd); priv->hw_params.max_rxq_size = RX_QUEUE_SIZE; priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG; if (priv->cfg->mod_params->amsdu_size_8K) @@ -1943,7 +1942,7 @@ void iwl4965_hw_build_tx_cmd_rate(struct iwl_priv *priv, struct ieee80211_hdr *hdr, int sta_id, int is_hcca) { - struct iwl4965_tx_cmd *tx = &cmd->cmd.tx; + struct iwl_tx_cmd *tx = &cmd->cmd.tx; u8 rts_retry_limit = 0; u8 data_retry_limit = 0; u16 fc = le16_to_cpu(hdr->frame_control); diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 72d655c..d155247 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -298,7 +298,6 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues; priv->hw_params.sw_crypto = priv->cfg->mod_params->sw_crypto; - priv->hw_params.tx_cmd_len = sizeof(struct iwl4965_tx_cmd); priv->hw_params.max_rxq_size = RX_QUEUE_SIZE; priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG; if (priv->cfg->mod_params->amsdu_size_8K) diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 350af1b..dd84326 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -1196,7 +1196,7 @@ struct iwl4965_dram_scratch { /* * REPLY_TX = 0x1c (command) */ -struct iwl4965_tx_cmd { +struct iwl_tx_cmd { /* * MPDU byte count: * MAC header (24/26/30/32 bytes) + 2 bytes pad if 26/30 header size, @@ -2135,7 +2135,7 @@ struct iwl4965_scan_cmd { /* For active scans (set to all-0s for passive scans). * Does not include payload. Must specify Tx rate; no rate scaling. */ - struct iwl4965_tx_cmd tx_cmd; + struct iwl_tx_cmd tx_cmd; /* For directed active scans (set to all-0s otherwise) */ struct iwl4965_ssid_ie direct_scan[PROBE_OPTION_MAX]; @@ -2232,7 +2232,7 @@ struct iwl4965_beacon_notif { * REPLY_TX_BEACON = 0x91 (command, has simple generic response) */ struct iwl4965_tx_beacon_cmd { - struct iwl4965_tx_cmd tx; + struct iwl_tx_cmd tx; __le16 tim_idx; u8 tim_size; u8 reserved1; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 565d7dc..ddb950e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -329,7 +329,7 @@ struct iwl_cmd { struct iwl4965_rxon_time_cmd rxon_time; struct iwl4965_powertable_cmd powertable; struct iwl4965_qosparam_cmd qosparam; - struct iwl4965_tx_cmd tx; + struct iwl_tx_cmd tx; struct iwl4965_tx_beacon_cmd tx_beacon; struct iwl4965_rxon_assoc_cmd rxon_assoc; u8 *indirect; @@ -573,7 +573,6 @@ struct iwl_sensitivity_ranges { /** * struct iwl_hw_params * @max_txq_num: Max # Tx queues supported - * @tx_cmd_len: Size of Tx command (but not including frame itself) * @tx/rx_chains_num: Number of TX/RX chains * @valid_tx/rx_ant: usable antennas * @max_rxq_size: Max # Rx frames in Rx queue (must be power-of-2) @@ -590,7 +589,6 @@ struct iwl_sensitivity_ranges { */ struct iwl_hw_params { u16 max_txq_num; - u16 tx_cmd_len; u8 tx_chains_num; u8 rx_chains_num; u8 valid_tx_ant; diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 88032cc..6d5b58f 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -1740,7 +1740,7 @@ static int iwl4965_tx_skb(struct iwl_priv *priv, * of the MAC header (device reads on dword boundaries). * We'll tell device about this padding later. */ - len = priv->hw_params.tx_cmd_len + + len = sizeof(struct iwl_tx_cmd) + sizeof(struct iwl_cmd_header) + hdr_len; len_org = len; @@ -1789,7 +1789,7 @@ static int iwl4965_tx_skb(struct iwl_priv *priv, iwl_update_tx_stats(priv, fc, len); scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) + - offsetof(struct iwl4965_tx_cmd, scratch); + offsetof(struct iwl_tx_cmd, scratch); out_cmd->cmd.tx.dram_lsb_ptr = cpu_to_le32(scratch_phys); out_cmd->cmd.tx.dram_msb_ptr = iwl_get_dma_hi_address(scratch_phys); -- cgit v0.10.2 From 54dbb525e7b8580b86af352cf60b27cc889c2ae4 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 15 May 2008 13:54:06 +0800 Subject: iwlwifi: refactor ieee80211_get_qos_ctrl This patch refactors ieee80211_get_qos_ctrl function and its usage in iwlwifi drivers. Function is moved as inline into iwl-helpers.h. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index ce70f2b..071c7b6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -282,14 +282,20 @@ static void rs_tl_rm_old_stats(struct iwl4965_traffic_load *tl, u32 curr_time) * increment traffic load value for tid and also remove * any old values if passed the certain time period */ -static void rs_tl_add_packet(struct iwl4965_lq_sta *lq_data, u8 tid) +static void rs_tl_add_packet(struct iwl4965_lq_sta *lq_data, + struct ieee80211_hdr *hdr) { u32 curr_time = jiffies_to_msecs(jiffies); u32 time_diff; s32 index; struct iwl4965_traffic_load *tl = NULL; + u16 fc = le16_to_cpu(hdr->frame_control); + u8 tid; - if (tid >= TID_MAX_LOAD_COUNT) + if (ieee80211_is_qos_data(fc)) { + u8 *qc = ieee80211_get_qos_ctrl(hdr, ieee80211_get_hdrlen(fc)); + tid = qc[0] & 0xf; + } else return; tl = &lq_data->load[tid]; @@ -1670,7 +1676,6 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, u16 high_low; #ifdef CONFIG_IWL4965_HT u8 tid = MAX_TID_COUNT; - __le16 *qc; #endif IWL_DEBUG_RATE("rate scale calculate new rate for skb\n"); @@ -1693,11 +1698,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv; #ifdef CONFIG_IWL4965_HT - qc = ieee80211_get_qos_ctrl(hdr); - if (qc) { - tid = (u8)(le16_to_cpu(*qc) & 0xf); - rs_tl_add_packet(lq_sta, tid); - } + rs_tl_add_packet(lq_sta, hdr); #endif /* * Select rate-scale / modulation-mode table to work with in diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index ddb950e..7bd99f9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -650,7 +650,6 @@ extern int iwl4965_calc_sig_qual(int rssi_dbm, int noise_dbm); extern unsigned int iwl4965_fill_beacon_frame(struct iwl_priv *priv, struct ieee80211_hdr *hdr, const u8 *dest, int left); -extern __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr); extern void iwl4965_update_chain_flags(struct iwl_priv *priv); int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src); diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h index a443472..e4c3f84 100644 --- a/drivers/net/wireless/iwlwifi/iwl-helpers.h +++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h @@ -235,6 +235,25 @@ static inline int ieee80211_is_reassoc_response(u16 fc) ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_RESP); } +static inline int ieee80211_is_qos_data(u16 fc) +{ + return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && + ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_QOS_DATA); +} +/** + * ieee80211_get_qos_ctrl - get pointer to the QoS control field + * + * This function returns the pointer to 802.11 header QoS field (2 bytes) + * This function doesn't check whether hdr is a QoS hdr, use with care + * @hdr: struct ieee80211_hdr *hdr + * @hdr_len: header length + */ + +static inline u8 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr, int hdr_len) +{ + return ((u8 *) hdr + hdr_len - QOS_CONTROL_LEN); +} + static inline int iwl_check_bits(unsigned long field, unsigned long mask) { return ((field & mask) == mask) ? 1 : 0; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index c1234ff..b8fb8d8 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -102,16 +102,6 @@ MODULE_VERSION(DRV_VERSION); MODULE_AUTHOR(DRV_COPYRIGHT); MODULE_LICENSE("GPL"); -static __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr) -{ - u16 fc = le16_to_cpu(hdr->frame_control); - int hdr_len = ieee80211_get_hdrlen(fc); - - if ((fc & 0x00cc) == (IEEE80211_STYPE_QOS_DATA | IEEE80211_FTYPE_DATA)) - return (__le16 *) ((u8 *) hdr + hdr_len - QOS_CONTROL_LEN); - return NULL; -} - static const struct ieee80211_supported_band *iwl3945_get_band( struct iwl3945_priv *priv, enum ieee80211_band band) { @@ -2441,7 +2431,6 @@ static void iwl3945_build_tx_cmd_basic(struct iwl3945_priv *priv, struct ieee80211_hdr *hdr, int is_unicast, u8 std_id) { - __le16 *qc; u16 fc = le16_to_cpu(hdr->frame_control); __le32 tx_flags = cmd->cmd.tx.tx_flags; @@ -2462,12 +2451,13 @@ static void iwl3945_build_tx_cmd_basic(struct iwl3945_priv *priv, if (ieee80211_get_morefrag(hdr)) tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK; - qc = ieee80211_get_qos_ctrl(hdr); - if (qc) { - cmd->cmd.tx.tid_tspec = (u8) (le16_to_cpu(*qc) & 0xf); + if (ieee80211_is_qos_data(fc)) { + u8 *qc = ieee80211_get_qos_ctrl(hdr, ieee80211_get_hdrlen(fc)); + cmd->cmd.tx.tid_tspec = qc[0] & 0xf; tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK; - } else + } else { tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; + } if (ctrl->flags & IEEE80211_TXCTL_USE_RTS_CTS) { tx_flags |= TX_CMD_FLG_RTS_MSK; @@ -2568,13 +2558,15 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, dma_addr_t phys_addr; dma_addr_t txcmd_phys; struct iwl3945_cmd *out_cmd = NULL; - u16 len, idx, len_org; - u8 id, hdr_len, unicast; + u16 len, idx, len_org, hdr_len; + u8 id; + u8 unicast; u8 sta_id; + u8 tid = 0; u16 seq_number = 0; u16 fc; - __le16 *qc; u8 wait_write_ptr = 0; + u8 *qc = NULL; unsigned long flags; int rc; @@ -2632,9 +2624,9 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, IWL_DEBUG_RATE("station Id %d\n", sta_id); - qc = ieee80211_get_qos_ctrl(hdr); - if (qc) { - u8 tid = (u8)(le16_to_cpu(*qc) & 0xf); + if (ieee80211_is_qos_data(fc)) { + qc = ieee80211_get_qos_ctrl(hdr, hdr_len); + tid = qc[0] & 0xf; seq_number = priv->stations[sta_id].tid[tid].seq_number & IEEE80211_SCTL_SEQ; hdr->seq_ctrl = cpu_to_le16(seq_number) | @@ -2745,7 +2737,6 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, if (!ieee80211_get_morefrag(hdr)) { txq->need_update = 1; if (qc) { - u8 tid = (u8)(le16_to_cpu(*qc) & 0xf); priv->stations[sta_id].tid[tid].seq_number = seq_number; } } else { diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 6d5b58f..e3f872e 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -89,16 +89,6 @@ MODULE_VERSION(DRV_VERSION); MODULE_AUTHOR(DRV_COPYRIGHT); MODULE_LICENSE("GPL"); -__le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr) -{ - u16 fc = le16_to_cpu(hdr->frame_control); - int hdr_len = ieee80211_get_hdrlen(fc); - - if ((fc & 0x00cc) == (IEEE80211_STYPE_QOS_DATA | IEEE80211_FTYPE_DATA)) - return (__le16 *) ((u8 *) hdr + hdr_len - QOS_CONTROL_LEN); - return NULL; -} - static const struct ieee80211_supported_band *iwl_get_hw_mode( struct iwl_priv *priv, enum ieee80211_band band) { @@ -1532,7 +1522,6 @@ static void iwl4965_build_tx_cmd_basic(struct iwl_priv *priv, struct ieee80211_hdr *hdr, int is_unicast, u8 std_id) { - __le16 *qc; u16 fc = le16_to_cpu(hdr->frame_control); __le32 tx_flags = cmd->cmd.tx.tx_flags; @@ -1557,12 +1546,13 @@ static void iwl4965_build_tx_cmd_basic(struct iwl_priv *priv, if (ieee80211_get_morefrag(hdr)) tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK; - qc = ieee80211_get_qos_ctrl(hdr); - if (qc) { - cmd->cmd.tx.tid_tspec = (u8) (le16_to_cpu(*qc) & 0xf); + if (ieee80211_is_qos_data(fc)) { + u8 *qc = ieee80211_get_qos_ctrl(hdr, ieee80211_get_hdrlen(fc)); + cmd->cmd.tx.tid_tspec = qc[0] & 0xf; tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK; - } else + } else { tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; + } if (ctrl->flags & IEEE80211_TXCTL_USE_RTS_CTS) { tx_flags |= TX_CMD_FLG_RTS_MSK; @@ -1614,12 +1604,15 @@ static int iwl4965_tx_skb(struct iwl_priv *priv, dma_addr_t scratch_phys; struct iwl_cmd *out_cmd = NULL; u16 len, idx, len_org; - u8 id, hdr_len, unicast; + u8 hdr_len; + u8 id; + u8 unicast; u8 sta_id; + u8 tid = 0; + u8 wait_write_ptr = 0; u16 seq_number = 0; u16 fc; - __le16 *qc; - u8 wait_write_ptr = 0; + u8 *qc = NULL; unsigned long flags; int rc; @@ -1678,9 +1671,9 @@ static int iwl4965_tx_skb(struct iwl_priv *priv, IWL_DEBUG_TX("station Id %d\n", sta_id); - qc = ieee80211_get_qos_ctrl(hdr); - if (qc) { - u8 tid = (u8)(le16_to_cpu(*qc) & 0xf); + if (ieee80211_is_qos_data(fc)) { + qc = ieee80211_get_qos_ctrl(hdr, hdr_len); + tid = qc[0] & 0xf; seq_number = priv->stations[sta_id].tid[tid].seq_number & IEEE80211_SCTL_SEQ; hdr->seq_ctrl = cpu_to_le16(seq_number) | @@ -1795,10 +1788,8 @@ static int iwl4965_tx_skb(struct iwl_priv *priv, if (!ieee80211_get_morefrag(hdr)) { txq->need_update = 1; - if (qc) { - u8 tid = (u8)(le16_to_cpu(*qc) & 0xf); + if (qc) priv->stations[sta_id].tid[tid].seq_number = seq_number; - } } else { wait_write_ptr = 1; txq->need_update = 0; @@ -2377,8 +2368,9 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, u32 status = le32_to_cpu(tx_resp->status); #ifdef CONFIG_IWL4965_HT int tid = MAX_TID_COUNT, sta_id = IWL_INVALID_STATION; + u16 fc; struct ieee80211_hdr *hdr; - __le16 *qc; + u8 *qc = NULL; #endif if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) { @@ -2391,10 +2383,11 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, #ifdef CONFIG_IWL4965_HT hdr = iwl4965_tx_queue_get_hdr(priv, txq_id, index); - qc = ieee80211_get_qos_ctrl(hdr); - - if (qc) - tid = le16_to_cpu(*qc) & 0xf; + fc = le16_to_cpu(hdr->frame_control); + if (ieee80211_is_qos_data(fc)) { + qc = ieee80211_get_qos_ctrl(hdr, ieee80211_get_hdrlen(fc)); + tid = qc[0] & 0xf; + } sta_id = iwl4965_get_ra_sta_id(priv, hdr); if (txq->sched_retry && unlikely(sta_id == IWL_INVALID_STATION)) { -- cgit v0.10.2 From fd4abac54a7a7f1c0acad5ddc1fbf4af22f92569 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 15 May 2008 13:54:07 +0800 Subject: iwlwifi: move TX code into iwl-tx.c This patch moves the sending part of the TX code into iwl-tx.c including sending host commands. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 02bbe04..8f0852d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -1933,76 +1933,6 @@ int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) return rc; } -#define RTS_HCCA_RETRY_LIMIT 3 -#define RTS_DFAULT_RETRY_LIMIT 60 - -void iwl4965_hw_build_tx_cmd_rate(struct iwl_priv *priv, - struct iwl_cmd *cmd, - struct ieee80211_tx_control *ctrl, - struct ieee80211_hdr *hdr, int sta_id, - int is_hcca) -{ - struct iwl_tx_cmd *tx = &cmd->cmd.tx; - u8 rts_retry_limit = 0; - u8 data_retry_limit = 0; - u16 fc = le16_to_cpu(hdr->frame_control); - u8 rate_plcp; - u16 rate_flags = 0; - int rate_idx = min(ctrl->tx_rate->hw_value & 0xffff, IWL_RATE_COUNT - 1); - - rate_plcp = iwl_rates[rate_idx].plcp; - - rts_retry_limit = (is_hcca) ? - RTS_HCCA_RETRY_LIMIT : RTS_DFAULT_RETRY_LIMIT; - - if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE)) - rate_flags |= RATE_MCS_CCK_MSK; - - - if (ieee80211_is_probe_response(fc)) { - data_retry_limit = 3; - if (data_retry_limit < rts_retry_limit) - rts_retry_limit = data_retry_limit; - } else - data_retry_limit = IWL_DEFAULT_TX_RETRY; - - if (priv->data_retry_limit != -1) - data_retry_limit = priv->data_retry_limit; - - - if (ieee80211_is_data(fc)) { - tx->initial_rate_index = 0; - tx->tx_flags |= TX_CMD_FLG_STA_RATE_MSK; - } else { - switch (fc & IEEE80211_FCTL_STYPE) { - case IEEE80211_STYPE_AUTH: - case IEEE80211_STYPE_DEAUTH: - case IEEE80211_STYPE_ASSOC_REQ: - case IEEE80211_STYPE_REASSOC_REQ: - if (tx->tx_flags & TX_CMD_FLG_RTS_MSK) { - tx->tx_flags &= ~TX_CMD_FLG_RTS_MSK; - tx->tx_flags |= TX_CMD_FLG_CTS_MSK; - } - break; - default: - break; - } - - /* Alternate between antenna A and B for successive frames */ - if (priv->use_ant_b_for_management_frame) { - priv->use_ant_b_for_management_frame = 0; - rate_flags |= RATE_MCS_ANT_B_MSK; - } else { - priv->use_ant_b_for_management_frame = 1; - rate_flags |= RATE_MCS_ANT_A_MSK; - } - } - - tx->rts_retry_limit = rts_retry_limit; - tx->data_retry_limit = data_retry_limit; - tx->rate_n_flags = iwl4965_hw_set_rate_n_flags(rate_plcp, rate_flags); -} - static int iwl4965_shared_mem_rx_idx(struct iwl_priv *priv) { struct iwl4965_shared *s = priv->shared_virt; @@ -2046,40 +1976,6 @@ unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, return (sizeof(*tx_beacon_cmd) + frame_size); } -int iwl4965_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr, - dma_addr_t addr, u16 len) -{ - int index, is_odd; - struct iwl_tfd_frame *tfd = ptr; - u32 num_tbs = IWL_GET_BITS(*tfd, num_tbs); - - /* Each TFD can point to a maximum 20 Tx buffers */ - if ((num_tbs >= MAX_NUM_OF_TBS) || (num_tbs < 0)) { - IWL_ERROR("Error can not send more than %d chunks\n", - MAX_NUM_OF_TBS); - return -EINVAL; - } - - index = num_tbs / 2; - is_odd = num_tbs & 0x1; - - if (!is_odd) { - tfd->pa[index].tb1_addr = cpu_to_le32(addr); - IWL_SET_BITS(tfd->pa[index], tb1_addr_hi, - iwl_get_dma_hi_address(addr)); - IWL_SET_BITS(tfd->pa[index], tb1_len, len); - } else { - IWL_SET_BITS(tfd->pa[index], tb2_addr_lo16, - (u32) (addr & 0xffff)); - IWL_SET_BITS(tfd->pa[index], tb2_addr_hi20, addr >> 16); - IWL_SET_BITS(tfd->pa[index], tb2_len, len); - } - - IWL_SET_BITS(*tfd, num_tbs, num_tbs + 1); - - return 0; -} - static int iwl4965_alloc_shared_mem(struct iwl_priv *priv) { priv->shared_virt = pci_alloc_consistent(priv->pci_dev, @@ -3711,7 +3607,6 @@ static struct iwl_hcmd_ops iwl4965_hcmd = { static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = { .get_hcmd_size = iwl4965_get_hcmd_size, - .enqueue_hcmd = iwl4965_enqueue_hcmd, .build_addsta_hcmd = iwl4965_build_addsta_hcmd, #ifdef CONFIG_IWL4965_RUN_TIME_CALIB .chain_noise_reset = iwl4965_chain_noise_reset, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index dcf1e56..b159fd3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -87,7 +87,6 @@ struct iwl_hcmd_ops { }; struct iwl_hcmd_utils_ops { u16 (*get_hcmd_size)(u8 cmd_id, u16 len); - int (*enqueue_hcmd)(struct iwl_priv *priv, struct iwl_host_cmd *cmd); u16 (*build_addsta_hcmd)(const struct iwl_addsta_cmd *cmd, u8 *data); #ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB void (*gain_computation)(struct iwl_priv *priv, @@ -208,10 +207,14 @@ void iwl_rx_allocate(struct iwl_priv *priv); * TX ******************************************************/ int iwl_txq_ctx_reset(struct iwl_priv *priv); +int iwl_tx_skb(struct iwl_priv *priv, + struct sk_buff *skb, struct ieee80211_tx_control *ctl); /* FIXME: remove when free Tx is fully merged into iwlcore */ int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq); void iwl_hw_txq_ctx_free(struct iwl_priv *priv); - +int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *tfd, + dma_addr_t addr, u16 len); +int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq); /***************************************************** * S e n d i n g H o s t C o m m a n d s * *****************************************************/ @@ -227,6 +230,8 @@ int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len, int (*callback)(struct iwl_priv *priv, struct iwl_cmd *cmd, struct sk_buff *skb)); + +int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd); /*************** DRIVER STATUS FUNCTIONS *****/ #define STATUS_HCMD_ACTIVE 0 /* host command in progress */ diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 7bd99f9..4106efd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -689,8 +689,6 @@ extern int iwl4965_hw_set_hw_params(struct iwl_priv *priv); extern int iwl4965_hw_nic_stop_master(struct iwl_priv *priv); extern void iwl4965_hw_txq_ctx_stop(struct iwl_priv *priv); extern int iwl4965_hw_nic_reset(struct iwl_priv *priv); -extern int iwl4965_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *tfd, - dma_addr_t addr, u16 len); extern int iwl4965_hw_get_temperature(struct iwl_priv *priv); extern unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, struct iwl_frame *frame, u8 rate); @@ -719,6 +717,25 @@ extern u8 iwl_find_station(struct iwl_priv *priv, const u8 *bssid); extern int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel); extern int iwl4965_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index); extern int iwl_queue_space(const struct iwl_queue *q); +static inline int iwl_queue_used(const struct iwl_queue *q, int i) +{ + return q->write_ptr > q->read_ptr ? + (i >= q->read_ptr && i < q->write_ptr) : + !(i < q->read_ptr && i >= q->write_ptr); +} + + +static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge) +{ + /* This is for scan command, the big buffer at end of command array */ + if (is_huge) + return q->n_window; /* must be power of 2 */ + + /* Otherwise, use normal size buffers */ + return index & (q->n_window - 1); +} + + struct iwl_priv; extern void iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio); diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index 0412adf..dab4a0e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -139,7 +139,7 @@ static int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd) if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return -EBUSY; - ret = priv->cfg->ops->utils->enqueue_hcmd(priv, cmd); + ret = iwl_enqueue_hcmd(priv, cmd); if (ret < 0) { IWL_ERROR("Error sending %s: enqueue_hcmd failed: %d\n", get_cmd_string(cmd->id), ret); @@ -170,7 +170,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) if (cmd->meta.flags & CMD_WANT_SKB) cmd->meta.source = &cmd->meta; - cmd_idx = priv->cfg->ops->utils->enqueue_hcmd(priv, cmd); + cmd_idx = iwl_enqueue_hcmd(priv, cmd); if (cmd_idx < 0) { ret = cmd_idx; IWL_ERROR("Error sending %s: enqueue_hcmd failed: %d\n", diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 870d257..a37ced5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -27,6 +27,7 @@ * *****************************************************************************/ +#include #include #include "iwl-eeprom.h" #include "iwl-dev.h" @@ -95,6 +96,89 @@ int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) } EXPORT_SYMBOL(iwl_hw_txq_free_tfd); + +int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr, + dma_addr_t addr, u16 len) +{ + int index, is_odd; + struct iwl_tfd_frame *tfd = ptr; + u32 num_tbs = IWL_GET_BITS(*tfd, num_tbs); + + /* Each TFD can point to a maximum 20 Tx buffers */ + if ((num_tbs >= MAX_NUM_OF_TBS) || (num_tbs < 0)) { + IWL_ERROR("Error can not send more than %d chunks\n", + MAX_NUM_OF_TBS); + return -EINVAL; + } + + index = num_tbs / 2; + is_odd = num_tbs & 0x1; + + if (!is_odd) { + tfd->pa[index].tb1_addr = cpu_to_le32(addr); + IWL_SET_BITS(tfd->pa[index], tb1_addr_hi, + iwl_get_dma_hi_address(addr)); + IWL_SET_BITS(tfd->pa[index], tb1_len, len); + } else { + IWL_SET_BITS(tfd->pa[index], tb2_addr_lo16, + (u32) (addr & 0xffff)); + IWL_SET_BITS(tfd->pa[index], tb2_addr_hi20, addr >> 16); + IWL_SET_BITS(tfd->pa[index], tb2_len, len); + } + + IWL_SET_BITS(*tfd, num_tbs, num_tbs + 1); + + return 0; +} +EXPORT_SYMBOL(iwl_hw_txq_attach_buf_to_tfd); + +/** + * iwl_txq_update_write_ptr - Send new write index to hardware + */ +int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq) +{ + u32 reg = 0; + int ret = 0; + int txq_id = txq->q.id; + + if (txq->need_update == 0) + return ret; + + /* if we're trying to save power */ + if (test_bit(STATUS_POWER_PMI, &priv->status)) { + /* wake up nic if it's powered down ... + * uCode will wake up, and interrupt us again, so next + * time we'll skip this part. */ + reg = iwl_read32(priv, CSR_UCODE_DRV_GP1); + + if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { + IWL_DEBUG_INFO("Requesting wakeup, GP1 = 0x%x\n", reg); + iwl_set_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + return ret; + } + + /* restore this queue's parameters in nic hardware. */ + ret = iwl_grab_nic_access(priv); + if (ret) + return ret; + iwl_write_direct32(priv, HBUS_TARG_WRPTR, + txq->q.write_ptr | (txq_id << 8)); + iwl_release_nic_access(priv); + + /* else not in power-save mode, uCode will never sleep when we're + * trying to tx (during RFKILL, we're not trying to tx). */ + } else + iwl_write32(priv, HBUS_TARG_WRPTR, + txq->q.write_ptr | (txq_id << 8)); + + txq->need_update = 0; + + return ret; +} +EXPORT_SYMBOL(iwl_txq_update_write_ptr); + + /** * iwl_tx_queue_free - Deallocate DMA queue. * @txq: Transmit queue to deallocate. @@ -137,6 +221,47 @@ static void iwl_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq) memset(txq, 0, sizeof(*txq)); } +/*************** DMA-QUEUE-GENERAL-FUNCTIONS ***** + * DMA services + * + * Theory of operation + * + * A Tx or Rx queue resides in host DRAM, and is comprised of a circular buffer + * of buffer descriptors, each of which points to one or more data buffers for + * the device to read from or fill. Driver and device exchange status of each + * queue via "read" and "write" pointers. Driver keeps minimum of 2 empty + * entries in each circular buffer, to protect against confusing empty and full + * queue states. + * + * The device reads or writes the data in the queues via the device's several + * DMA/FIFO channels. Each queue is mapped to a single DMA channel. + * + * For Tx queue, there are low mark and high mark limits. If, after queuing + * the packet for Tx, free space become < low mark, Tx queue stopped. When + * reclaiming packets (on 'tx done IRQ), if free space become > high mark, + * Tx queue resumed. + * + * See more detailed info in iwl-4965-hw.h. + ***************************************************/ + +int iwl_queue_space(const struct iwl_queue *q) +{ + int s = q->read_ptr - q->write_ptr; + + if (q->read_ptr > q->write_ptr) + s -= q->n_bd; + + if (s <= 0) + s += q->n_window; + /* keep some reserve to not confuse empty and full situations */ + s -= 2; + if (s < 0) + s = 0; + return s; +} +EXPORT_SYMBOL(iwl_queue_space); + + /** * iwl_hw_txq_ctx_free - Free TXQ Context * @@ -371,3 +496,540 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv) error_kw: return ret; } + +/* + * handle build REPLY_TX command notification. + */ +static void iwl_tx_cmd_build_basic(struct iwl_priv *priv, + struct iwl_tx_cmd *tx_cmd, + struct ieee80211_tx_control *ctrl, + struct ieee80211_hdr *hdr, + int is_unicast, u8 std_id) +{ + u16 fc = le16_to_cpu(hdr->frame_control); + __le32 tx_flags = tx_cmd->tx_flags; + + tx_cmd->stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; + if (!(ctrl->flags & IEEE80211_TXCTL_NO_ACK)) { + tx_flags |= TX_CMD_FLG_ACK_MSK; + if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) + tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; + if (ieee80211_is_probe_response(fc) && + !(le16_to_cpu(hdr->seq_ctrl) & 0xf)) + tx_flags |= TX_CMD_FLG_TSF_MSK; + } else { + tx_flags &= (~TX_CMD_FLG_ACK_MSK); + tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; + } + + if (ieee80211_is_back_request(fc)) + tx_flags |= TX_CMD_FLG_ACK_MSK | TX_CMD_FLG_IMM_BA_RSP_MASK; + + + tx_cmd->sta_id = std_id; + if (ieee80211_get_morefrag(hdr)) + tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK; + + if (ieee80211_is_qos_data(fc)) { + u8 *qc = ieee80211_get_qos_ctrl(hdr, ieee80211_get_hdrlen(fc)); + tx_cmd->tid_tspec = qc[0] & 0xf; + tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK; + } else { + tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; + } + + if (ctrl->flags & IEEE80211_TXCTL_USE_RTS_CTS) { + tx_flags |= TX_CMD_FLG_RTS_MSK; + tx_flags &= ~TX_CMD_FLG_CTS_MSK; + } else if (ctrl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { + tx_flags &= ~TX_CMD_FLG_RTS_MSK; + tx_flags |= TX_CMD_FLG_CTS_MSK; + } + + if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK)) + tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK; + + tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK); + if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) { + if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ || + (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ) + tx_cmd->timeout.pm_frame_timeout = cpu_to_le16(3); + else + tx_cmd->timeout.pm_frame_timeout = cpu_to_le16(2); + } else { + tx_cmd->timeout.pm_frame_timeout = 0; + } + + tx_cmd->driver_txop = 0; + tx_cmd->tx_flags = tx_flags; + tx_cmd->next_frame_len = 0; +} + +#define RTS_HCCA_RETRY_LIMIT 3 +#define RTS_DFAULT_RETRY_LIMIT 60 + +static void iwl_tx_cmd_build_rate(struct iwl_priv *priv, + struct iwl_tx_cmd *tx_cmd, + struct ieee80211_tx_control *ctrl, + u16 fc, int sta_id, + int is_hcca) +{ + u8 rts_retry_limit = 0; + u8 data_retry_limit = 0; + u8 rate_plcp; + u16 rate_flags = 0; + int rate_idx = min(ctrl->tx_rate->hw_value & 0xffff, IWL_RATE_COUNT - 1); + + rate_plcp = iwl_rates[rate_idx].plcp; + + rts_retry_limit = (is_hcca) ? + RTS_HCCA_RETRY_LIMIT : RTS_DFAULT_RETRY_LIMIT; + + if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE)) + rate_flags |= RATE_MCS_CCK_MSK; + + + if (ieee80211_is_probe_response(fc)) { + data_retry_limit = 3; + if (data_retry_limit < rts_retry_limit) + rts_retry_limit = data_retry_limit; + } else + data_retry_limit = IWL_DEFAULT_TX_RETRY; + + if (priv->data_retry_limit != -1) + data_retry_limit = priv->data_retry_limit; + + + if (ieee80211_is_data(fc)) { + tx_cmd->initial_rate_index = 0; + tx_cmd->tx_flags |= TX_CMD_FLG_STA_RATE_MSK; + } else { + switch (fc & IEEE80211_FCTL_STYPE) { + case IEEE80211_STYPE_AUTH: + case IEEE80211_STYPE_DEAUTH: + case IEEE80211_STYPE_ASSOC_REQ: + case IEEE80211_STYPE_REASSOC_REQ: + if (tx_cmd->tx_flags & TX_CMD_FLG_RTS_MSK) { + tx_cmd->tx_flags &= ~TX_CMD_FLG_RTS_MSK; + tx_cmd->tx_flags |= TX_CMD_FLG_CTS_MSK; + } + break; + default: + break; + } + + /* Alternate between antenna A and B for successive frames */ + if (priv->use_ant_b_for_management_frame) { + priv->use_ant_b_for_management_frame = 0; + rate_flags |= RATE_MCS_ANT_B_MSK; + } else { + priv->use_ant_b_for_management_frame = 1; + rate_flags |= RATE_MCS_ANT_A_MSK; + } + } + + tx_cmd->rts_retry_limit = rts_retry_limit; + tx_cmd->data_retry_limit = data_retry_limit; + tx_cmd->rate_n_flags = iwl4965_hw_set_rate_n_flags(rate_plcp, rate_flags); +} + +static void iwl_tx_cmd_build_hwcrypto(struct iwl_priv *priv, + struct ieee80211_tx_control *ctl, + struct iwl_tx_cmd *tx_cmd, + struct sk_buff *skb_frag, + int sta_id) +{ + struct iwl_hw_key *keyinfo = &priv->stations[sta_id].keyinfo; + struct iwl_wep_key *wepkey; + int keyidx = 0; + + BUG_ON(ctl->hw_key->hw_key_idx > 3); + + switch (keyinfo->alg) { + case ALG_CCMP: + tx_cmd->sec_ctl = TX_CMD_SEC_CCM; + memcpy(tx_cmd->key, keyinfo->key, keyinfo->keylen); + if (ctl->flags & IEEE80211_TXCTL_AMPDU) + tx_cmd->tx_flags |= TX_CMD_FLG_AGG_CCMP_MSK; + IWL_DEBUG_TX("tx_cmd with aes hwcrypto\n"); + break; + + case ALG_TKIP: + tx_cmd->sec_ctl = TX_CMD_SEC_TKIP; + ieee80211_get_tkip_key(keyinfo->conf, skb_frag, + IEEE80211_TKIP_P2_KEY, tx_cmd->key); + IWL_DEBUG_TX("tx_cmd with tkip hwcrypto\n"); + break; + + case ALG_WEP: + wepkey = &priv->wep_keys[ctl->hw_key->hw_key_idx]; + tx_cmd->sec_ctl = 0; + if (priv->default_wep_key) { + /* the WEP key was sent as static */ + keyidx = ctl->hw_key->hw_key_idx; + memcpy(&tx_cmd->key[3], wepkey->key, + wepkey->key_size); + if (wepkey->key_size == WEP_KEY_LEN_128) + tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128; + } else { + /* the WEP key was sent as dynamic */ + keyidx = keyinfo->keyidx; + memcpy(&tx_cmd->key[3], keyinfo->key, + keyinfo->keylen); + if (keyinfo->keylen == WEP_KEY_LEN_128) + tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128; + } + + tx_cmd->sec_ctl |= (TX_CMD_SEC_WEP | + (keyidx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT); + + IWL_DEBUG_TX("Configuring packet for WEP encryption " + "with key %d\n", keyidx); + break; + + default: + printk(KERN_ERR "Unknown encode alg %d\n", keyinfo->alg); + break; + } +} + +static void iwl_update_tx_stats(struct iwl_priv *priv, u16 fc, u16 len) +{ + /* 0 - mgmt, 1 - cnt, 2 - data */ + int idx = (fc & IEEE80211_FCTL_FTYPE) >> 2; + priv->tx_stats[idx].cnt++; + priv->tx_stats[idx].bytes += len; +} + +/* + * start REPLY_TX command process + */ +int iwl_tx_skb(struct iwl_priv *priv, + struct sk_buff *skb, struct ieee80211_tx_control *ctl) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct iwl_tfd_frame *tfd; + u32 *control_flags; + int txq_id = ctl->queue; + struct iwl_tx_queue *txq = NULL; + struct iwl_queue *q = NULL; + dma_addr_t phys_addr; + dma_addr_t txcmd_phys; + dma_addr_t scratch_phys; + struct iwl_cmd *out_cmd = NULL; + struct iwl_tx_cmd *tx_cmd; + u16 len, idx, len_org; + u16 seq_number = 0; + u8 id, hdr_len, unicast; + u8 sta_id; + u16 fc; + u8 wait_write_ptr = 0; + u8 tid = 0; + u8 *qc = NULL; + unsigned long flags; + int ret; + + spin_lock_irqsave(&priv->lock, flags); + if (iwl_is_rfkill(priv)) { + IWL_DEBUG_DROP("Dropping - RF KILL\n"); + goto drop_unlock; + } + + if (!priv->vif) { + IWL_DEBUG_DROP("Dropping - !priv->vif\n"); + goto drop_unlock; + } + + if ((ctl->tx_rate->hw_value & 0xFF) == IWL_INVALID_RATE) { + IWL_ERROR("ERROR: No TX rate available.\n"); + goto drop_unlock; + } + + unicast = !is_multicast_ether_addr(hdr->addr1); + id = 0; + + fc = le16_to_cpu(hdr->frame_control); + +#ifdef CONFIG_IWLWIFI_DEBUG + if (ieee80211_is_auth(fc)) + IWL_DEBUG_TX("Sending AUTH frame\n"); + else if (ieee80211_is_assoc_request(fc)) + IWL_DEBUG_TX("Sending ASSOC frame\n"); + else if (ieee80211_is_reassoc_request(fc)) + IWL_DEBUG_TX("Sending REASSOC frame\n"); +#endif + + /* drop all data frame if we are not associated */ + if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && + (!iwl_is_associated(priv) || + ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && !priv->assoc_id) || + !priv->assoc_station_added)) { + IWL_DEBUG_DROP("Dropping - !iwl_is_associated\n"); + goto drop_unlock; + } + + spin_unlock_irqrestore(&priv->lock, flags); + + hdr_len = ieee80211_get_hdrlen(fc); + + /* Find (or create) index into station table for destination station */ + sta_id = iwl_get_sta_id(priv, hdr); + if (sta_id == IWL_INVALID_STATION) { + DECLARE_MAC_BUF(mac); + + IWL_DEBUG_DROP("Dropping - INVALID STATION: %s\n", + print_mac(mac, hdr->addr1)); + goto drop; + } + + IWL_DEBUG_TX("station Id %d\n", sta_id); + + if (ieee80211_is_qos_data(fc)) { + qc = ieee80211_get_qos_ctrl(hdr, hdr_len); + tid = qc[0] & 0xf; + seq_number = priv->stations[sta_id].tid[tid].seq_number & + IEEE80211_SCTL_SEQ; + hdr->seq_ctrl = cpu_to_le16(seq_number) | + (hdr->seq_ctrl & + __constant_cpu_to_le16(IEEE80211_SCTL_FRAG)); + seq_number += 0x10; +#ifdef CONFIG_IWL4965_HT + /* aggregation is on for this */ + if (ctl->flags & IEEE80211_TXCTL_AMPDU) + txq_id = priv->stations[sta_id].tid[tid].agg.txq_id; + priv->stations[sta_id].tid[tid].tfds_in_queue++; +#endif /* CONFIG_IWL4965_HT */ + } + + /* Descriptor for chosen Tx queue */ + txq = &priv->txq[txq_id]; + q = &txq->q; + + spin_lock_irqsave(&priv->lock, flags); + + /* Set up first empty TFD within this queue's circular TFD buffer */ + tfd = &txq->bd[q->write_ptr]; + memset(tfd, 0, sizeof(*tfd)); + control_flags = (u32 *) tfd; + idx = get_cmd_index(q, q->write_ptr, 0); + + /* Set up driver data for this TFD */ + memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info)); + txq->txb[q->write_ptr].skb[0] = skb; + memcpy(&(txq->txb[q->write_ptr].status.control), + ctl, sizeof(struct ieee80211_tx_control)); + + /* Set up first empty entry in queue's array of Tx/cmd buffers */ + out_cmd = &txq->cmd[idx]; + tx_cmd = &out_cmd->cmd.tx; + memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr)); + memset(tx_cmd, 0, sizeof(struct iwl_tx_cmd)); + + /* + * Set up the Tx-command (not MAC!) header. + * Store the chosen Tx queue and TFD index within the sequence field; + * after Tx, uCode's Tx response will return this value so driver can + * locate the frame within the tx queue and do post-tx processing. + */ + out_cmd->hdr.cmd = REPLY_TX; + out_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) | + INDEX_TO_SEQ(q->write_ptr))); + + /* Copy MAC header from skb into command buffer */ + memcpy(tx_cmd->hdr, hdr, hdr_len); + + /* + * Use the first empty entry in this queue's command buffer array + * to contain the Tx command and MAC header concatenated together + * (payload data will be in another buffer). + * Size of this varies, due to varying MAC header length. + * If end is not dword aligned, we'll have 2 extra bytes at the end + * of the MAC header (device reads on dword boundaries). + * We'll tell device about this padding later. + */ + len = sizeof(struct iwl_tx_cmd) + + sizeof(struct iwl_cmd_header) + hdr_len; + + len_org = len; + len = (len + 3) & ~3; + + if (len_org != len) + len_org = 1; + else + len_org = 0; + + /* Physical address of this Tx command's header (not MAC header!), + * within command buffer array. */ + txcmd_phys = txq->dma_addr_cmd + sizeof(struct iwl_cmd) * idx + + offsetof(struct iwl_cmd, hdr); + + /* Add buffer containing Tx command and MAC(!) header to TFD's + * first entry */ + iwl_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len); + + if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) + iwl_tx_cmd_build_hwcrypto(priv, ctl, tx_cmd, skb, sta_id); + + /* Set up TFD's 2nd entry to point directly to remainder of skb, + * if any (802.11 null frames have no payload). */ + len = skb->len - hdr_len; + if (len) { + phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len, + len, PCI_DMA_TODEVICE); + iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, len); + } + + /* Tell NIC about any 2-byte padding after MAC header */ + if (len_org) + tx_cmd->tx_flags |= TX_CMD_FLG_MH_PAD_MSK; + + /* Total # bytes to be transmitted */ + len = (u16)skb->len; + tx_cmd->len = cpu_to_le16(len); + /* TODO need this for burst mode later on */ + iwl_tx_cmd_build_basic(priv, tx_cmd, ctl, hdr, unicast, sta_id); + + /* set is_hcca to 0; it probably will never be implemented */ + iwl_tx_cmd_build_rate(priv, tx_cmd, ctl, fc, sta_id, 0); + + iwl_update_tx_stats(priv, fc, len); + + scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) + + offsetof(struct iwl_tx_cmd, scratch); + tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys); + tx_cmd->dram_msb_ptr = iwl_get_dma_hi_address(scratch_phys); + + if (!ieee80211_get_morefrag(hdr)) { + txq->need_update = 1; + if (qc) + priv->stations[sta_id].tid[tid].seq_number = seq_number; + } else { + wait_write_ptr = 1; + txq->need_update = 0; + } + + iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd)); + + iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len); + + /* Set up entry for this TFD in Tx byte-count array */ + priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq, len); + + /* Tell device the write index *just past* this latest filled TFD */ + q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); + ret = iwl_txq_update_write_ptr(priv, txq); + spin_unlock_irqrestore(&priv->lock, flags); + + if (ret) + return ret; + + if ((iwl_queue_space(q) < q->high_mark) + && priv->mac80211_registered) { + if (wait_write_ptr) { + spin_lock_irqsave(&priv->lock, flags); + txq->need_update = 1; + iwl_txq_update_write_ptr(priv, txq); + spin_unlock_irqrestore(&priv->lock, flags); + } + + ieee80211_stop_queue(priv->hw, ctl->queue); + } + + return 0; + +drop_unlock: + spin_unlock_irqrestore(&priv->lock, flags); +drop: + return -1; +} +EXPORT_SYMBOL(iwl_tx_skb); + +/*************** HOST COMMAND QUEUE FUNCTIONS *****/ + +/** + * iwl_enqueue_hcmd - enqueue a uCode command + * @priv: device private data point + * @cmd: a point to the ucode command structure + * + * The function returns < 0 values to indicate the operation is + * failed. On success, it turns the index (> 0) of command in the + * command queue. + */ +int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) +{ + struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM]; + struct iwl_queue *q = &txq->q; + struct iwl_tfd_frame *tfd; + u32 *control_flags; + struct iwl_cmd *out_cmd; + u32 idx; + u16 fix_size; + dma_addr_t phys_addr; + int ret; + unsigned long flags; + + cmd->len = priv->cfg->ops->utils->get_hcmd_size(cmd->id, cmd->len); + fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr)); + + /* If any of the command structures end up being larger than + * the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then + * we will need to increase the size of the TFD entries */ + BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) && + !(cmd->meta.flags & CMD_SIZE_HUGE)); + + if (iwl_is_rfkill(priv)) { + IWL_DEBUG_INFO("Not sending command - RF KILL"); + return -EIO; + } + + if (iwl_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) { + IWL_ERROR("No space for Tx\n"); + return -ENOSPC; + } + + spin_lock_irqsave(&priv->hcmd_lock, flags); + + tfd = &txq->bd[q->write_ptr]; + memset(tfd, 0, sizeof(*tfd)); + + control_flags = (u32 *) tfd; + + idx = get_cmd_index(q, q->write_ptr, cmd->meta.flags & CMD_SIZE_HUGE); + out_cmd = &txq->cmd[idx]; + + out_cmd->hdr.cmd = cmd->id; + memcpy(&out_cmd->meta, &cmd->meta, sizeof(cmd->meta)); + memcpy(&out_cmd->cmd.payload, cmd->data, cmd->len); + + /* At this point, the out_cmd now has all of the incoming cmd + * information */ + + out_cmd->hdr.flags = 0; + out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) | + INDEX_TO_SEQ(q->write_ptr)); + if (out_cmd->meta.flags & CMD_SIZE_HUGE) + out_cmd->hdr.sequence |= cpu_to_le16(SEQ_HUGE_FRAME); + + phys_addr = txq->dma_addr_cmd + sizeof(txq->cmd[0]) * idx + + offsetof(struct iwl_cmd, hdr); + iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size); + + IWL_DEBUG_HC("Sending command %s (#%x), seq: 0x%04X, " + "%d bytes at %d[%d]:%d\n", + get_cmd_string(out_cmd->hdr.cmd), + out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence), + fix_size, q->write_ptr, idx, IWL_CMD_QUEUE_NUM); + + txq->need_update = 1; + + /* Set up entry in queue's byte count circular buffer */ + priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq, 0); + + /* Increment and update queue's write index */ + q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); + ret = iwl_txq_update_write_ptr(priv, txq); + + spin_unlock_irqrestore(&priv->hcmd_lock, flags); + return ret ? ret : idx; +} + diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index e3f872e..dd2fd40 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -53,8 +53,6 @@ #include "iwl-sta.h" #include "iwl-calib.h" -static int iwl_txq_update_write_ptr(struct iwl_priv *priv, - struct iwl_tx_queue *txq); /****************************************************************************** * @@ -135,69 +133,6 @@ static const char *iwl4965_escape_essid(const char *essid, u8 essid_len) return escaped; } - -/*************** DMA-QUEUE-GENERAL-FUNCTIONS ***** - * DMA services - * - * Theory of operation - * - * A Tx or Rx queue resides in host DRAM, and is comprised of a circular buffer - * of buffer descriptors, each of which points to one or more data buffers for - * the device to read from or fill. Driver and device exchange status of each - * queue via "read" and "write" pointers. Driver keeps minimum of 2 empty - * entries in each circular buffer, to protect against confusing empty and full - * queue states. - * - * The device reads or writes the data in the queues via the device's several - * DMA/FIFO channels. Each queue is mapped to a single DMA channel. - * - * For Tx queue, there are low mark and high mark limits. If, after queuing - * the packet for Tx, free space become < low mark, Tx queue stopped. When - * reclaiming packets (on 'tx done IRQ), if free space become > high mark, - * Tx queue resumed. - * - * The 4965 operates with up to 17 queues: One receive queue, one transmit - * queue (#4) for sending commands to the device firmware, and 15 other - * Tx queues that may be mapped to prioritized Tx DMA/FIFO channels. - * - * See more detailed info in iwl-4965-hw.h. - ***************************************************/ - -int iwl_queue_space(const struct iwl_queue *q) -{ - int s = q->read_ptr - q->write_ptr; - - if (q->read_ptr > q->write_ptr) - s -= q->n_bd; - - if (s <= 0) - s += q->n_window; - /* keep some reserve to not confuse empty and full situations */ - s -= 2; - if (s < 0) - s = 0; - return s; -} - - -static inline int iwl_queue_used(const struct iwl_queue *q, int i) -{ - return q->write_ptr > q->read_ptr ? - (i >= q->read_ptr && i < q->write_ptr) : - !(i < q->read_ptr && i >= q->write_ptr); -} - -static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge) -{ - /* This is for scan command, the big buffer at end of command array */ - if (is_huge) - return q->n_window; /* must be power of 2 */ - - /* Otherwise, use normal size buffers */ - return index & (q->n_window - 1); -} - - /*************** STATION TABLE MANAGEMENT **** * mac80211 should be examined to determine if sta_info is duplicating * the functionality provided here @@ -250,95 +185,6 @@ out: -/*************** HOST COMMAND QUEUE FUNCTIONS *****/ - -/** - * iwl4965_enqueue_hcmd - enqueue a uCode command - * @priv: device private data point - * @cmd: a point to the ucode command structure - * - * The function returns < 0 values to indicate the operation is - * failed. On success, it turns the index (> 0) of command in the - * command queue. - */ -int iwl4965_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) -{ - struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM]; - struct iwl_queue *q = &txq->q; - struct iwl_tfd_frame *tfd; - u32 *control_flags; - struct iwl_cmd *out_cmd; - u32 idx; - u16 fix_size; - dma_addr_t phys_addr; - int ret; - unsigned long flags; - - cmd->len = priv->cfg->ops->utils->get_hcmd_size(cmd->id, cmd->len); - fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr)); - - /* If any of the command structures end up being larger than - * the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then - * we will need to increase the size of the TFD entries */ - BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) && - !(cmd->meta.flags & CMD_SIZE_HUGE)); - - if (iwl_is_rfkill(priv)) { - IWL_DEBUG_INFO("Not sending command - RF KILL"); - return -EIO; - } - - if (iwl_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) { - IWL_ERROR("No space for Tx\n"); - return -ENOSPC; - } - - spin_lock_irqsave(&priv->hcmd_lock, flags); - - tfd = &txq->bd[q->write_ptr]; - memset(tfd, 0, sizeof(*tfd)); - - control_flags = (u32 *) tfd; - - idx = get_cmd_index(q, q->write_ptr, cmd->meta.flags & CMD_SIZE_HUGE); - out_cmd = &txq->cmd[idx]; - - out_cmd->hdr.cmd = cmd->id; - memcpy(&out_cmd->meta, &cmd->meta, sizeof(cmd->meta)); - memcpy(&out_cmd->cmd.payload, cmd->data, cmd->len); - - /* At this point, the out_cmd now has all of the incoming cmd - * information */ - - out_cmd->hdr.flags = 0; - out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) | - INDEX_TO_SEQ(q->write_ptr)); - if (out_cmd->meta.flags & CMD_SIZE_HUGE) - out_cmd->hdr.sequence |= cpu_to_le16(SEQ_HUGE_FRAME); - - phys_addr = txq->dma_addr_cmd + sizeof(txq->cmd[0]) * idx + - offsetof(struct iwl_cmd, hdr); - iwl4965_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size); - - IWL_DEBUG_HC("Sending command %s (#%x), seq: 0x%04X, " - "%d bytes at %d[%d]:%d\n", - get_cmd_string(out_cmd->hdr.cmd), - out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence), - fix_size, q->write_ptr, idx, IWL_CMD_QUEUE_NUM); - - txq->need_update = 1; - - /* Set up entry in queue's byte count circular buffer */ - priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq, 0); - - /* Increment and update queue's write index */ - q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); - ret = iwl_txq_update_write_ptr(priv, txq); - - spin_unlock_irqrestore(&priv->hcmd_lock, flags); - return ret ? ret : idx; -} - static void iwl4965_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt) { struct iwl_rxon_cmd *rxon = &priv->staging_rxon; @@ -1453,385 +1299,6 @@ static int iwl4965_set_mode(struct iwl_priv *priv, int mode) return 0; } -static void iwl4965_build_tx_cmd_hwcrypto(struct iwl_priv *priv, - struct ieee80211_tx_control *ctl, - struct iwl_cmd *cmd, - struct sk_buff *skb_frag, - int sta_id) -{ - struct iwl_hw_key *keyinfo = &priv->stations[sta_id].keyinfo; - struct iwl_wep_key *wepkey; - int keyidx = 0; - - BUG_ON(ctl->hw_key->hw_key_idx > 3); - - switch (keyinfo->alg) { - case ALG_CCMP: - cmd->cmd.tx.sec_ctl = TX_CMD_SEC_CCM; - memcpy(cmd->cmd.tx.key, keyinfo->key, keyinfo->keylen); - if (ctl->flags & IEEE80211_TXCTL_AMPDU) - cmd->cmd.tx.tx_flags |= TX_CMD_FLG_AGG_CCMP_MSK; - IWL_DEBUG_TX("tx_cmd with aes hwcrypto\n"); - break; - - case ALG_TKIP: - cmd->cmd.tx.sec_ctl = TX_CMD_SEC_TKIP; - ieee80211_get_tkip_key(keyinfo->conf, skb_frag, - IEEE80211_TKIP_P2_KEY, cmd->cmd.tx.key); - IWL_DEBUG_TX("tx_cmd with tkip hwcrypto\n"); - break; - - case ALG_WEP: - wepkey = &priv->wep_keys[ctl->hw_key->hw_key_idx]; - cmd->cmd.tx.sec_ctl = 0; - if (priv->default_wep_key) { - /* the WEP key was sent as static */ - keyidx = ctl->hw_key->hw_key_idx; - memcpy(&cmd->cmd.tx.key[3], wepkey->key, - wepkey->key_size); - if (wepkey->key_size == WEP_KEY_LEN_128) - cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128; - } else { - /* the WEP key was sent as dynamic */ - keyidx = keyinfo->keyidx; - memcpy(&cmd->cmd.tx.key[3], keyinfo->key, - keyinfo->keylen); - if (keyinfo->keylen == WEP_KEY_LEN_128) - cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128; - } - - cmd->cmd.tx.sec_ctl |= (TX_CMD_SEC_WEP | - (keyidx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT); - - IWL_DEBUG_TX("Configuring packet for WEP encryption " - "with key %d\n", keyidx); - break; - - default: - printk(KERN_ERR "Unknown encode alg %d\n", keyinfo->alg); - break; - } -} - -/* - * handle build REPLY_TX command notification. - */ -static void iwl4965_build_tx_cmd_basic(struct iwl_priv *priv, - struct iwl_cmd *cmd, - struct ieee80211_tx_control *ctrl, - struct ieee80211_hdr *hdr, - int is_unicast, u8 std_id) -{ - u16 fc = le16_to_cpu(hdr->frame_control); - __le32 tx_flags = cmd->cmd.tx.tx_flags; - - cmd->cmd.tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; - if (!(ctrl->flags & IEEE80211_TXCTL_NO_ACK)) { - tx_flags |= TX_CMD_FLG_ACK_MSK; - if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) - tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; - if (ieee80211_is_probe_response(fc) && - !(le16_to_cpu(hdr->seq_ctrl) & 0xf)) - tx_flags |= TX_CMD_FLG_TSF_MSK; - } else { - tx_flags &= (~TX_CMD_FLG_ACK_MSK); - tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; - } - - if (ieee80211_is_back_request(fc)) - tx_flags |= TX_CMD_FLG_ACK_MSK | TX_CMD_FLG_IMM_BA_RSP_MASK; - - - cmd->cmd.tx.sta_id = std_id; - if (ieee80211_get_morefrag(hdr)) - tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK; - - if (ieee80211_is_qos_data(fc)) { - u8 *qc = ieee80211_get_qos_ctrl(hdr, ieee80211_get_hdrlen(fc)); - cmd->cmd.tx.tid_tspec = qc[0] & 0xf; - tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK; - } else { - tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; - } - - if (ctrl->flags & IEEE80211_TXCTL_USE_RTS_CTS) { - tx_flags |= TX_CMD_FLG_RTS_MSK; - tx_flags &= ~TX_CMD_FLG_CTS_MSK; - } else if (ctrl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { - tx_flags &= ~TX_CMD_FLG_RTS_MSK; - tx_flags |= TX_CMD_FLG_CTS_MSK; - } - - if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK)) - tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK; - - tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK); - if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) { - if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ || - (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ) - cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(3); - else - cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(2); - } else { - cmd->cmd.tx.timeout.pm_frame_timeout = 0; - } - - cmd->cmd.tx.driver_txop = 0; - cmd->cmd.tx.tx_flags = tx_flags; - cmd->cmd.tx.next_frame_len = 0; -} -static void iwl_update_tx_stats(struct iwl_priv *priv, u16 fc, u16 len) -{ - /* 0 - mgmt, 1 - cnt, 2 - data */ - int idx = (fc & IEEE80211_FCTL_FTYPE) >> 2; - priv->tx_stats[idx].cnt++; - priv->tx_stats[idx].bytes += len; -} -/* - * start REPLY_TX command process - */ -static int iwl4965_tx_skb(struct iwl_priv *priv, - struct sk_buff *skb, struct ieee80211_tx_control *ctl) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct iwl_tfd_frame *tfd; - u32 *control_flags; - int txq_id = ctl->queue; - struct iwl_tx_queue *txq = NULL; - struct iwl_queue *q = NULL; - dma_addr_t phys_addr; - dma_addr_t txcmd_phys; - dma_addr_t scratch_phys; - struct iwl_cmd *out_cmd = NULL; - u16 len, idx, len_org; - u8 hdr_len; - u8 id; - u8 unicast; - u8 sta_id; - u8 tid = 0; - u8 wait_write_ptr = 0; - u16 seq_number = 0; - u16 fc; - u8 *qc = NULL; - unsigned long flags; - int rc; - - spin_lock_irqsave(&priv->lock, flags); - if (iwl_is_rfkill(priv)) { - IWL_DEBUG_DROP("Dropping - RF KILL\n"); - goto drop_unlock; - } - - if (!priv->vif) { - IWL_DEBUG_DROP("Dropping - !priv->vif\n"); - goto drop_unlock; - } - - if ((ctl->tx_rate->hw_value & 0xFF) == IWL_INVALID_RATE) { - IWL_ERROR("ERROR: No TX rate available.\n"); - goto drop_unlock; - } - - unicast = !is_multicast_ether_addr(hdr->addr1); - id = 0; - - fc = le16_to_cpu(hdr->frame_control); - -#ifdef CONFIG_IWLWIFI_DEBUG - if (ieee80211_is_auth(fc)) - IWL_DEBUG_TX("Sending AUTH frame\n"); - else if (ieee80211_is_assoc_request(fc)) - IWL_DEBUG_TX("Sending ASSOC frame\n"); - else if (ieee80211_is_reassoc_request(fc)) - IWL_DEBUG_TX("Sending REASSOC frame\n"); -#endif - - /* drop all data frame if we are not associated */ - if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && - (!iwl_is_associated(priv) || - ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && !priv->assoc_id) || - !priv->assoc_station_added)) { - IWL_DEBUG_DROP("Dropping - !iwl_is_associated\n"); - goto drop_unlock; - } - - spin_unlock_irqrestore(&priv->lock, flags); - - hdr_len = ieee80211_get_hdrlen(fc); - - /* Find (or create) index into station table for destination station */ - sta_id = iwl_get_sta_id(priv, hdr); - if (sta_id == IWL_INVALID_STATION) { - DECLARE_MAC_BUF(mac); - - IWL_DEBUG_DROP("Dropping - INVALID STATION: %s\n", - print_mac(mac, hdr->addr1)); - goto drop; - } - - IWL_DEBUG_TX("station Id %d\n", sta_id); - - if (ieee80211_is_qos_data(fc)) { - qc = ieee80211_get_qos_ctrl(hdr, hdr_len); - tid = qc[0] & 0xf; - seq_number = priv->stations[sta_id].tid[tid].seq_number & - IEEE80211_SCTL_SEQ; - hdr->seq_ctrl = cpu_to_le16(seq_number) | - (hdr->seq_ctrl & - __constant_cpu_to_le16(IEEE80211_SCTL_FRAG)); - seq_number += 0x10; -#ifdef CONFIG_IWL4965_HT - /* aggregation is on for this */ - if (ctl->flags & IEEE80211_TXCTL_AMPDU) - txq_id = priv->stations[sta_id].tid[tid].agg.txq_id; - priv->stations[sta_id].tid[tid].tfds_in_queue++; -#endif /* CONFIG_IWL4965_HT */ - } - - /* Descriptor for chosen Tx queue */ - txq = &priv->txq[txq_id]; - q = &txq->q; - - spin_lock_irqsave(&priv->lock, flags); - - /* Set up first empty TFD within this queue's circular TFD buffer */ - tfd = &txq->bd[q->write_ptr]; - memset(tfd, 0, sizeof(*tfd)); - control_flags = (u32 *) tfd; - idx = get_cmd_index(q, q->write_ptr, 0); - - /* Set up driver data for this TFD */ - memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info)); - txq->txb[q->write_ptr].skb[0] = skb; - memcpy(&(txq->txb[q->write_ptr].status.control), - ctl, sizeof(struct ieee80211_tx_control)); - - /* Set up first empty entry in queue's array of Tx/cmd buffers */ - out_cmd = &txq->cmd[idx]; - memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr)); - memset(&out_cmd->cmd.tx, 0, sizeof(out_cmd->cmd.tx)); - - /* - * Set up the Tx-command (not MAC!) header. - * Store the chosen Tx queue and TFD index within the sequence field; - * after Tx, uCode's Tx response will return this value so driver can - * locate the frame within the tx queue and do post-tx processing. - */ - out_cmd->hdr.cmd = REPLY_TX; - out_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) | - INDEX_TO_SEQ(q->write_ptr))); - - /* Copy MAC header from skb into command buffer */ - memcpy(out_cmd->cmd.tx.hdr, hdr, hdr_len); - - /* - * Use the first empty entry in this queue's command buffer array - * to contain the Tx command and MAC header concatenated together - * (payload data will be in another buffer). - * Size of this varies, due to varying MAC header length. - * If end is not dword aligned, we'll have 2 extra bytes at the end - * of the MAC header (device reads on dword boundaries). - * We'll tell device about this padding later. - */ - len = sizeof(struct iwl_tx_cmd) + - sizeof(struct iwl_cmd_header) + hdr_len; - - len_org = len; - len = (len + 3) & ~3; - - if (len_org != len) - len_org = 1; - else - len_org = 0; - - /* Physical address of this Tx command's header (not MAC header!), - * within command buffer array. */ - txcmd_phys = txq->dma_addr_cmd + sizeof(struct iwl_cmd) * idx + - offsetof(struct iwl_cmd, hdr); - - /* Add buffer containing Tx command and MAC(!) header to TFD's - * first entry */ - iwl4965_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len); - - if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) - iwl4965_build_tx_cmd_hwcrypto(priv, ctl, out_cmd, skb, sta_id); - - /* Set up TFD's 2nd entry to point directly to remainder of skb, - * if any (802.11 null frames have no payload). */ - len = skb->len - hdr_len; - if (len) { - phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len, - len, PCI_DMA_TODEVICE); - iwl4965_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, len); - } - - /* Tell 4965 about any 2-byte padding after MAC header */ - if (len_org) - out_cmd->cmd.tx.tx_flags |= TX_CMD_FLG_MH_PAD_MSK; - - /* Total # bytes to be transmitted */ - len = (u16)skb->len; - out_cmd->cmd.tx.len = cpu_to_le16(len); - - /* TODO need this for burst mode later on */ - iwl4965_build_tx_cmd_basic(priv, out_cmd, ctl, hdr, unicast, sta_id); - - /* set is_hcca to 0; it probably will never be implemented */ - iwl4965_hw_build_tx_cmd_rate(priv, out_cmd, ctl, hdr, sta_id, 0); - - iwl_update_tx_stats(priv, fc, len); - - scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) + - offsetof(struct iwl_tx_cmd, scratch); - out_cmd->cmd.tx.dram_lsb_ptr = cpu_to_le32(scratch_phys); - out_cmd->cmd.tx.dram_msb_ptr = iwl_get_dma_hi_address(scratch_phys); - - if (!ieee80211_get_morefrag(hdr)) { - txq->need_update = 1; - if (qc) - priv->stations[sta_id].tid[tid].seq_number = seq_number; - } else { - wait_write_ptr = 1; - txq->need_update = 0; - } - - iwl_print_hex_dump(priv, IWL_DL_TX, out_cmd->cmd.payload, - sizeof(out_cmd->cmd.tx)); - - iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)out_cmd->cmd.tx.hdr, - ieee80211_get_hdrlen(fc)); - - /* Set up entry for this TFD in Tx byte-count array */ - priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq, len); - - /* Tell device the write index *just past* this latest filled TFD */ - q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); - rc = iwl_txq_update_write_ptr(priv, txq); - spin_unlock_irqrestore(&priv->lock, flags); - - if (rc) - return rc; - - if ((iwl_queue_space(q) < q->high_mark) - && priv->mac80211_registered) { - if (wait_write_ptr) { - spin_lock_irqsave(&priv->lock, flags); - txq->need_update = 1; - iwl_txq_update_write_ptr(priv, txq); - spin_unlock_irqrestore(&priv->lock, flags); - } - - ieee80211_stop_queue(priv->hw, ctl->queue); - } - - return 0; - -drop_unlock: - spin_unlock_irqrestore(&priv->lock, flags); -drop: - return -1; -} - static void iwl4965_set_rate(struct iwl_priv *priv) { const struct ieee80211_supported_band *hw = NULL; @@ -3101,52 +2568,6 @@ int iwl4965_calc_sig_qual(int rssi_dbm, int noise_dbm) return sig_qual; } -/** - * iwl_txq_update_write_ptr - Send new write index to hardware - */ -static int iwl_txq_update_write_ptr(struct iwl_priv *priv, - struct iwl_tx_queue *txq) -{ - u32 reg = 0; - int ret = 0; - int txq_id = txq->q.id; - - if (txq->need_update == 0) - return ret; - - /* if we're trying to save power */ - if (test_bit(STATUS_POWER_PMI, &priv->status)) { - /* wake up nic if it's powered down ... - * uCode will wake up, and interrupt us again, so next - * time we'll skip this part. */ - reg = iwl_read32(priv, CSR_UCODE_DRV_GP1); - - if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { - IWL_DEBUG_INFO("Requesting wakeup, GP1 = 0x%x\n", reg); - iwl_set_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - return ret; - } - - /* restore this queue's parameters in nic hardware. */ - ret = iwl_grab_nic_access(priv); - if (ret) - return ret; - iwl_write_direct32(priv, HBUS_TARG_WRPTR, - txq->q.write_ptr | (txq_id << 8)); - iwl_release_nic_access(priv); - - /* else not in power-save mode, uCode will never sleep when we're - * trying to tx (during RFKILL, we're not trying to tx). */ - } else - iwl_write32(priv, HBUS_TARG_WRPTR, - txq->q.write_ptr | (txq_id << 8)); - - txq->need_update = 0; - - return ret; -} - #ifdef CONFIG_IWLWIFI_DEBUG static void iwl4965_print_rx_config_cmd(struct iwl_priv *priv) { @@ -4956,7 +4377,7 @@ static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, ctl->tx_rate->bitrate); - if (iwl4965_tx_skb(priv, skb, ctl)) + if (iwl_tx_skb(priv, skb, ctl)) dev_kfree_skb_any(skb); IWL_DEBUG_MAC80211("leave\n"); -- cgit v0.10.2 From a98410139a2ef6553ae5d73bf12bb9a68d0b38b9 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 15 May 2008 13:54:08 +0800 Subject: iwlwifi: don't switch to SGI if not supported by AP This patch fixes SGI support. RS didn't look at the capabilities of the AP before switching to SGI, this should lead to a stall in the traffic with an AP that doesn't support SGI. Signed-off-by: Emmanuel Grumbach Signed-off-by: Guy Cohen Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index 071c7b6..2adc228 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -1439,6 +1439,15 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, } break; case IWL_SISO_SWITCH_GI: + if (!tbl->is_fat && + !(priv->current_ht_config.sgf & + HT_SHORT_GI_20MHZ)) + break; + if (tbl->is_fat && + !(priv->current_ht_config.sgf & + HT_SHORT_GI_40MHZ)) + break; + IWL_DEBUG_RATE("LQ: SISO toggle SGI/NGI\n"); memcpy(search_tbl, tbl, sz); @@ -1521,6 +1530,15 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv, break; case IWL_MIMO_SWITCH_GI: + if (!tbl->is_fat && + !(priv->current_ht_config.sgf & + HT_SHORT_GI_20MHZ)) + break; + if (tbl->is_fat && + !(priv->current_ht_config.sgf & + HT_SHORT_GI_40MHZ)) + break; + IWL_DEBUG_RATE("LQ: MIMO toggle SGI/NGI\n"); /* Set up new search table for MIMO */ diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 4106efd..7a54682 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -610,8 +610,8 @@ struct iwl_hw_params { #endif }; -#define HT_SHORT_GI_20MHZ_ONLY (1 << 0) -#define HT_SHORT_GI_40MHZ_ONLY (1 << 1) +#define HT_SHORT_GI_20MHZ (1 << 0) +#define HT_SHORT_GI_40MHZ (1 << 1) #define IWL_RX_HDR(x) ((struct iwl4965_rx_frame_hdr *)(\ diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index dd2fd40..a532a9e 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -700,9 +700,9 @@ static void iwl4965_ht_conf(struct iwl_priv *priv, priv->ps_mode = (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2); if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20) - iwl_conf->sgf |= 0x1; + iwl_conf->sgf |= HT_SHORT_GI_20MHZ; if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40) - iwl_conf->sgf |= 0x2; + iwl_conf->sgf |= HT_SHORT_GI_40MHZ; iwl_conf->is_green_field = !!(ht_conf->cap & IEEE80211_HT_CAP_GRN_FLD); iwl_conf->max_amsdu_size = -- cgit v0.10.2 From ccc038abe4cb00cf56aeae5b1df47fcc4ed4136c Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 15 May 2008 13:54:09 +0800 Subject: iwlwifi: clean up and bug fix for security This patch cleans up code in security. 1) uses the new pointer to ieee80211_key_conf passed with the tx_control. 2) resolves bug reported by Mirco Tischler (sends ADD_STA in ASYNC mode) 3) resolves bug reported by Volker Braun regarding dynamic WEP 4) drops a WEP packet which has been garbaged by firmware. This can happen upon rekeying. Signed-off-by: Emmanuel Grumbach Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 8f0852d..52c7eae 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2389,6 +2389,7 @@ static int iwl4965_set_decrypted_flag(struct iwl_priv *priv, RX_RES_STATUS_BAD_KEY_TTAK) break; + case RX_RES_STATUS_SEC_TYPE_WEP: if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == RX_RES_STATUS_BAD_ICV_MIC) { /* bad ICV, the packet is destroyed since the @@ -2396,7 +2397,6 @@ static int iwl4965_set_decrypted_flag(struct iwl_priv *priv, IWL_DEBUG_RX("Packet destroyed\n"); return -1; } - case RX_RES_STATUS_SEC_TYPE_WEP: case RX_RES_STATUS_SEC_TYPE_CCMP: if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == RX_RES_STATUS_DECRYPT_OK) { diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 7a54682..305491f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -442,7 +442,6 @@ struct iwl_hw_key { enum ieee80211_key_alg alg; int keylen; u8 keyidx; - struct ieee80211_key_conf *conf; u8 key[32]; }; diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index c8e468f..99ee1e1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -324,7 +324,7 @@ int iwl_set_default_wep_key(struct iwl_priv *priv, unsigned long flags; keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV; - keyconf->hw_key_idx = keyconf->keyidx; + keyconf->hw_key_idx = HW_KEY_DEFAULT; priv->stations[IWL_AP_ID].keyinfo.alg = ALG_WEP; spin_lock_irqsave(&priv->sta_lock, flags); @@ -354,7 +354,6 @@ static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv, int ret; keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV; - keyconf->hw_key_idx = keyconf->keyidx; key_flags |= (STA_KEY_FLG_WEP | STA_KEY_FLG_MAP_KEY_MSK); key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS); @@ -411,7 +410,6 @@ static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv, key_flags |= STA_KEY_MULTICAST_MSK; keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; - keyconf->hw_key_idx = keyconf->keyidx; spin_lock_irqsave(&priv->sta_lock, flags); priv->stations[sta_id].keyinfo.alg = keyconf->alg; @@ -449,12 +447,10 @@ static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv, keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; - keyconf->hw_key_idx = keyconf->keyidx; spin_lock_irqsave(&priv->sta_lock, flags); priv->stations[sta_id].keyinfo.alg = keyconf->alg; - priv->stations[sta_id].keyinfo.conf = keyconf; priv->stations[sta_id].keyinfo.keylen = 16; if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK) @@ -483,7 +479,7 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv, u16 key_flags; u8 keyidx; - priv->key_mapping_key = 0; + priv->key_mapping_key--; spin_lock_irqsave(&priv->sta_lock, flags); key_flags = le16_to_cpu(priv->stations[sta_id].sta.key.key_flags); @@ -514,31 +510,32 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv, priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; IWL_DEBUG_INFO("hwcrypto: clear ucode station key info\n"); - ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, 0); + ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); spin_unlock_irqrestore(&priv->sta_lock, flags); return ret; } EXPORT_SYMBOL(iwl_remove_dynamic_key); int iwl_set_dynamic_key(struct iwl_priv *priv, - struct ieee80211_key_conf *key, u8 sta_id) + struct ieee80211_key_conf *keyconf, u8 sta_id) { int ret; - priv->key_mapping_key = 1; + priv->key_mapping_key++; + keyconf->hw_key_idx = HW_KEY_DYNAMIC; - switch (key->alg) { + switch (keyconf->alg) { case ALG_CCMP: - ret = iwl_set_ccmp_dynamic_key_info(priv, key, sta_id); + ret = iwl_set_ccmp_dynamic_key_info(priv, keyconf, sta_id); break; case ALG_TKIP: - ret = iwl_set_tkip_dynamic_key_info(priv, key, sta_id); + ret = iwl_set_tkip_dynamic_key_info(priv, keyconf, sta_id); break; case ALG_WEP: - ret = iwl_set_wep_dynamic_key_info(priv, key, sta_id); + ret = iwl_set_wep_dynamic_key_info(priv, keyconf, sta_id); break; default: - IWL_ERROR("Unknown alg: %s alg = %d\n", __func__, key->alg); + IWL_ERROR("Unknown alg: %s alg = %d\n", __func__, keyconf->alg); ret = -EINVAL; } diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h index ee25643..b643546 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.h +++ b/drivers/net/wireless/iwlwifi/iwl-sta.h @@ -29,6 +29,9 @@ #ifndef __iwl_sta_h__ #define __iwl_sta_h__ +#define HW_KEY_DYNAMIC 0 +#define HW_KEY_DEFAULT 1 + int iwl_get_free_ucode_key_index(struct iwl_priv *priv); int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty); int iwl_remove_default_wep_key(struct iwl_priv *priv, diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index a37ced5..f32cdda 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -639,16 +639,12 @@ static void iwl_tx_cmd_build_hwcrypto(struct iwl_priv *priv, struct sk_buff *skb_frag, int sta_id) { - struct iwl_hw_key *keyinfo = &priv->stations[sta_id].keyinfo; - struct iwl_wep_key *wepkey; - int keyidx = 0; + struct ieee80211_key_conf *keyconf = ctl->hw_key; - BUG_ON(ctl->hw_key->hw_key_idx > 3); - - switch (keyinfo->alg) { + switch (keyconf->alg) { case ALG_CCMP: tx_cmd->sec_ctl = TX_CMD_SEC_CCM; - memcpy(tx_cmd->key, keyinfo->key, keyinfo->keylen); + memcpy(tx_cmd->key, keyconf->key, keyconf->keylen); if (ctl->flags & IEEE80211_TXCTL_AMPDU) tx_cmd->tx_flags |= TX_CMD_FLG_AGG_CCMP_MSK; IWL_DEBUG_TX("tx_cmd with aes hwcrypto\n"); @@ -656,39 +652,26 @@ static void iwl_tx_cmd_build_hwcrypto(struct iwl_priv *priv, case ALG_TKIP: tx_cmd->sec_ctl = TX_CMD_SEC_TKIP; - ieee80211_get_tkip_key(keyinfo->conf, skb_frag, + ieee80211_get_tkip_key(keyconf, skb_frag, IEEE80211_TKIP_P2_KEY, tx_cmd->key); IWL_DEBUG_TX("tx_cmd with tkip hwcrypto\n"); break; case ALG_WEP: - wepkey = &priv->wep_keys[ctl->hw_key->hw_key_idx]; - tx_cmd->sec_ctl = 0; - if (priv->default_wep_key) { - /* the WEP key was sent as static */ - keyidx = ctl->hw_key->hw_key_idx; - memcpy(&tx_cmd->key[3], wepkey->key, - wepkey->key_size); - if (wepkey->key_size == WEP_KEY_LEN_128) - tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128; - } else { - /* the WEP key was sent as dynamic */ - keyidx = keyinfo->keyidx; - memcpy(&tx_cmd->key[3], keyinfo->key, - keyinfo->keylen); - if (keyinfo->keylen == WEP_KEY_LEN_128) - tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128; - } - tx_cmd->sec_ctl |= (TX_CMD_SEC_WEP | - (keyidx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT); + (keyconf->keyidx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT); + + if (keyconf->keylen == WEP_KEY_LEN_128) + tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128; + + memcpy(&tx_cmd->key[3], keyconf->key, keyconf->keylen); IWL_DEBUG_TX("Configuring packet for WEP encryption " - "with key %d\n", keyidx); + "with key %d\n", keyconf->keyidx); break; default: - printk(KERN_ERR "Unknown encode alg %d\n", keyinfo->alg); + printk(KERN_ERR "Unknown encode alg %d\n", keyconf->alg); break; } } diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index a532a9e..40616db 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -4951,7 +4951,8 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, if (cmd == SET_KEY) is_default_wep_key = !priv->key_mapping_key; else - is_default_wep_key = priv->default_wep_key; + is_default_wep_key = + (key->hw_key_idx == HW_KEY_DEFAULT); } switch (cmd) { -- cgit v0.10.2 From 3647074973e70d0872b96ada27bbbb71fd1f628c Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Thu, 15 May 2008 13:54:10 +0800 Subject: iwlwifi: rename and move Tx queue activation/deactivation This patch moves iwl4965_txq_ctx_activate and iwl4965_txq_ctx_deactivate to iwl-dev.h and removes 4965 prefix from their names. Signed-off-by: Ron Rindjunsky Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 52c7eae..f848a5b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -911,16 +911,6 @@ static const u16 default_queue_to_tx_fifo[] = { IWL_TX_FIFO_HCCA_2 }; -static inline void iwl4965_txq_ctx_activate(struct iwl_priv *priv, int txq_id) -{ - set_bit(txq_id, &priv->txq_ctx_active_msk); -} - -static inline void iwl4965_txq_ctx_deactivate(struct iwl_priv *priv, int txq_id) -{ - clear_bit(txq_id, &priv->txq_ctx_active_msk); -} - int iwl4965_alive_notify(struct iwl_priv *priv) { u32 a; @@ -998,7 +988,7 @@ int iwl4965_alive_notify(struct iwl_priv *priv) /* Map each Tx/cmd queue to its corresponding fifo */ for (i = 0; i < ARRAY_SIZE(default_queue_to_tx_fifo); i++) { int ac = default_queue_to_tx_fifo[i]; - iwl4965_txq_ctx_activate(priv, i); + iwl_txq_ctx_activate(priv, i); iwl4965_tx_queue_set_status(priv, &priv->txq[i], ac, 0); } @@ -3115,7 +3105,7 @@ static int iwl4965_tx_queue_agg_disable(struct iwl_priv *priv, u16 txq_id, iwl4965_set_wr_ptrs(priv, txq_id, ssn_idx); iwl_clear_bits_prph(priv, IWL49_SCD_INTERRUPT_MASK, (1 << txq_id)); - iwl4965_txq_ctx_deactivate(priv, txq_id); + iwl_txq_ctx_deactivate(priv, txq_id); iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 0); iwl_release_nic_access(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 305491f..533479e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1210,6 +1210,16 @@ struct iwl_priv { struct timer_list statistics_periodic; }; /*iwl_priv */ +static inline void iwl_txq_ctx_activate(struct iwl_priv *priv, int txq_id) +{ + set_bit(txq_id, &priv->txq_ctx_active_msk); +} + +static inline void iwl_txq_ctx_deactivate(struct iwl_priv *priv, int txq_id) +{ + clear_bit(txq_id, &priv->txq_ctx_active_msk); +} + static inline int iwl_is_associated(struct iwl_priv *priv) { return (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0; -- cgit v0.10.2 From b600e4e1c5cd8928fef83bb983ab76c9a6f655bc Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Thu, 15 May 2008 13:54:11 +0800 Subject: iwlwifi: add rx_handlers stub for iwl5000 This patch adds rx_handler_setup stub to iwl5000. Signed-off-by: Ron Rindjunsky Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index d155247..00ad360 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -464,6 +464,10 @@ static u16 iwl5000_get_hcmd_size(u8 cmd_id, u16 len) return len; } +static void iwl5000_rx_handler_setup(struct iwl_priv *priv) +{ +} + static struct iwl_hcmd_ops iwl5000_hcmd = { }; @@ -483,6 +487,7 @@ static struct iwl_lib_ops iwl5000_lib = { .shared_mem_rx_idx = iwl5000_shared_mem_rx_idx, .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, .disable_tx_fifo = iwl5000_disable_tx_fifo, + .rx_handler_setup = iwl5000_rx_handler_setup, .apm_ops = { .init = iwl5000_apm_init, .config = iwl5000_nic_config, -- cgit v0.10.2 From dbb983b70a4696666112591572ed49c48c58da26 Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Thu, 15 May 2008 13:54:12 +0800 Subject: iwlwifi: add ucode loaders for iwl5000 This patch adds ucode initialization handler and functions to load ucode for iwl5000 NIC. Signed-off-by: Ron Rindjunsky Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 00ad360..b6bdffc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -287,6 +287,139 @@ static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv, return &priv->eeprom[address]; } +/* + * ucode + */ +static int iwl5000_load_section(struct iwl_priv *priv, + struct fw_desc *image, + u32 dst_addr) +{ + int ret = 0; + unsigned long flags; + + dma_addr_t phy_addr = image->p_addr; + u32 byte_cnt = image->len; + + spin_lock_irqsave(&priv->lock, flags); + ret = iwl_grab_nic_access(priv); + if (ret) { + spin_unlock_irqrestore(&priv->lock, flags); + return ret; + } + + iwl_write_direct32(priv, + FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL), + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE); + + iwl_write_direct32(priv, + FH_SRVC_CHNL_SRAM_ADDR_REG(FH_SRVC_CHNL), dst_addr); + + iwl_write_direct32(priv, + FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL), + phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK); + + /* FIME: write the MSB of the phy_addr in CTRL1 + * iwl_write_direct32(priv, + IWL_FH_TFDIB_CTRL1_REG(IWL_FH_SRVC_CHNL), + ((phy_addr & MSB_MSK) + << FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_count); + */ + iwl_write_direct32(priv, + FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL), byte_cnt); + iwl_write_direct32(priv, + FH_TCSR_CHNL_TX_BUF_STS_REG(FH_SRVC_CHNL), + 1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM | + 1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX | + FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID); + + iwl_write_direct32(priv, + FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL), + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL | + FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD); + + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + return 0; +} + +static int iwl5000_load_given_ucode(struct iwl_priv *priv, + struct fw_desc *inst_image, + struct fw_desc *data_image) +{ + int ret = 0; + + ret = iwl5000_load_section( + priv, inst_image, RTC_INST_LOWER_BOUND); + if (ret) + return ret; + + IWL_DEBUG_INFO("INST uCode section being loaded...\n"); + ret = wait_event_interruptible_timeout(priv->wait_command_queue, + priv->ucode_write_complete, 5 * HZ); + if (ret == -ERESTARTSYS) { + IWL_ERROR("Could not load the INST uCode section due " + "to interrupt\n"); + return ret; + } + if (!ret) { + IWL_ERROR("Could not load the INST uCode section\n"); + return -ETIMEDOUT; + } + + priv->ucode_write_complete = 0; + + ret = iwl5000_load_section( + priv, data_image, RTC_DATA_LOWER_BOUND); + if (ret) + return ret; + + IWL_DEBUG_INFO("DATA uCode section being loaded...\n"); + + ret = wait_event_interruptible_timeout(priv->wait_command_queue, + priv->ucode_write_complete, 5 * HZ); + if (ret == -ERESTARTSYS) { + IWL_ERROR("Could not load the INST uCode section due " + "to interrupt\n"); + return ret; + } else if (!ret) { + IWL_ERROR("Could not load the DATA uCode section\n"); + return -ETIMEDOUT; + } else + ret = 0; + + priv->ucode_write_complete = 0; + + return ret; +} + +static int iwl5000_load_ucode(struct iwl_priv *priv) +{ + int ret = 0; + + /* check whether init ucode should be loaded, or rather runtime ucode */ + if (priv->ucode_init.len && (priv->ucode_type == UCODE_NONE)) { + IWL_DEBUG_INFO("Init ucode found. Loading init ucode...\n"); + ret = iwl5000_load_given_ucode(priv, + &priv->ucode_init, &priv->ucode_init_data); + if (!ret) { + IWL_DEBUG_INFO("Init ucode load complete.\n"); + priv->ucode_type = UCODE_INIT; + } + } else { + IWL_DEBUG_INFO("Init ucode not found, or already loaded. " + "Loading runtime ucode...\n"); + ret = iwl5000_load_given_ucode(priv, + &priv->ucode_code, &priv->ucode_data); + if (!ret) { + IWL_DEBUG_INFO("Runtime ucode load complete.\n"); + priv->ucode_type = UCODE_RT; + } + } + + return ret; +} + static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) { if ((priv->cfg->mod_params->num_of_queues > IWL50_NUM_QUEUES) || @@ -488,6 +621,7 @@ static struct iwl_lib_ops iwl5000_lib = { .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, .disable_tx_fifo = iwl5000_disable_tx_fifo, .rx_handler_setup = iwl5000_rx_handler_setup, + .load_ucode = iwl5000_load_ucode, .apm_ops = { .init = iwl5000_apm_init, .config = iwl5000_nic_config, diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 533479e..b1ff0af 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -876,6 +876,12 @@ struct statistics_general_data { u32 beacon_energy_c; }; +enum ucode_type { + UCODE_NONE = 0, + UCODE_INIT, + UCODE_RT +}; + #ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB /* Sensitivity calib data */ struct iwl_sensitivity_data { @@ -1010,6 +1016,8 @@ struct iwl_priv { struct fw_desc ucode_init; /* initialization inst */ struct fw_desc ucode_init_data; /* initialization data */ struct fw_desc ucode_boot; /* bootstrap inst */ + enum ucode_type ucode_type; + u8 ucode_write_complete; /* the image write is complete */ struct iwl4965_rxon_time_cmd rxon_timing; diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 40616db..e06142d 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -2978,6 +2978,9 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv) if (inta & CSR_INT_BIT_FH_TX) { IWL_DEBUG_ISR("Tx interrupt\n"); handled |= CSR_INT_BIT_FH_TX; + /* FH finished to write, send event */ + priv->ucode_write_complete = 1; + wake_up_interruptible(&priv->wait_command_queue); } if (inta & ~handled) -- cgit v0.10.2 From 99da1b48fc77484aa8da85a45d9c3c1e00243659 Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Thu, 15 May 2008 13:54:13 +0800 Subject: iwlwifi: add ucode init flow handling for iwl5000 This patch adds all the handlers and functions needed for ucode initialization flow. Signed-off-by: Ron Rindjunsky Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index b6bdffc..5e818ee 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -46,6 +46,16 @@ #define IWL5000_UCODE_API "-1" +static const u16 iwl5000_default_queue_to_tx_fifo[] = { + IWL_TX_FIFO_AC3, + IWL_TX_FIFO_AC2, + IWL_TX_FIFO_AC1, + IWL_TX_FIFO_AC0, + IWL50_CMD_FIFO_NUM, + IWL_TX_FIFO_HCCA_1, + IWL_TX_FIFO_HCCA_2 +}; + static int iwl5000_apm_init(struct iwl_priv *priv) { int ret = 0; @@ -420,6 +430,151 @@ static int iwl5000_load_ucode(struct iwl_priv *priv) return ret; } +static void iwl5000_init_alive_start(struct iwl_priv *priv) +{ + int ret = 0; + + /* Check alive response for "valid" sign from uCode */ + if (priv->card_alive_init.is_valid != UCODE_VALID_OK) { + /* We had an error bringing up the hardware, so take it + * all the way back down so we can try again */ + IWL_DEBUG_INFO("Initialize Alive failed.\n"); + goto restart; + } + + /* initialize uCode was loaded... verify inst image. + * This is a paranoid check, because we would not have gotten the + * "initialize" alive if code weren't properly loaded. */ + if (iwl_verify_ucode(priv)) { + /* Runtime instruction load was bad; + * take it all the way back down so we can try again */ + IWL_DEBUG_INFO("Bad \"initialize\" uCode load.\n"); + goto restart; + } + + iwlcore_clear_stations_table(priv); + ret = priv->cfg->ops->lib->alive_notify(priv); + if (ret) { + IWL_WARNING("Could not complete ALIVE transition: %d\n", ret); + goto restart; + } + + return; + +restart: + /* real restart (first load init_ucode) */ + queue_work(priv->workqueue, &priv->restart); +} + +static void iwl5000_set_wr_ptrs(struct iwl_priv *priv, + int txq_id, u32 index) +{ + iwl_write_direct32(priv, HBUS_TARG_WRPTR, + (index & 0xff) | (txq_id << 8)); + iwl_write_prph(priv, IWL50_SCD_QUEUE_RDPTR(txq_id), index); +} + +static void iwl5000_tx_queue_set_status(struct iwl_priv *priv, + struct iwl_tx_queue *txq, + int tx_fifo_id, int scd_retry) +{ + int txq_id = txq->q.id; + int active = test_bit(txq_id, &priv->txq_ctx_active_msk)?1:0; + + iwl_write_prph(priv, IWL50_SCD_QUEUE_STATUS_BITS(txq_id), + (active << IWL50_SCD_QUEUE_STTS_REG_POS_ACTIVE) | + (tx_fifo_id << IWL50_SCD_QUEUE_STTS_REG_POS_TXF) | + (1 << IWL50_SCD_QUEUE_STTS_REG_POS_WSL) | + IWL50_SCD_QUEUE_STTS_REG_MSK); + + txq->sched_retry = scd_retry; + + IWL_DEBUG_INFO("%s %s Queue %d on AC %d\n", + active ? "Activate" : "Deactivate", + scd_retry ? "BA" : "AC", txq_id, tx_fifo_id); +} + +static int iwl5000_alive_notify(struct iwl_priv *priv) +{ + u32 a; + int i = 0; + unsigned long flags; + int ret; + + spin_lock_irqsave(&priv->lock, flags); + + ret = iwl_grab_nic_access(priv); + if (ret) { + spin_unlock_irqrestore(&priv->lock, flags); + return ret; + } + + priv->scd_base_addr = iwl_read_prph(priv, IWL50_SCD_SRAM_BASE_ADDR); + a = priv->scd_base_addr + IWL50_SCD_CONTEXT_DATA_OFFSET; + for (; a < priv->scd_base_addr + IWL50_SCD_TX_STTS_BITMAP_OFFSET; + a += 4) + iwl_write_targ_mem(priv, a, 0); + for (; a < priv->scd_base_addr + IWL50_SCD_TRANSLATE_TBL_OFFSET; + a += 4) + iwl_write_targ_mem(priv, a, 0); + for (; a < sizeof(u16) * priv->hw_params.max_txq_num; a += 4) + iwl_write_targ_mem(priv, a, 0); + + iwl_write_prph(priv, IWL50_SCD_DRAM_BASE_ADDR, + (priv->shared_phys + + offsetof(struct iwl5000_shared, queues_byte_cnt_tbls)) >> 10); + iwl_write_prph(priv, IWL50_SCD_QUEUECHAIN_SEL, + IWL50_SCD_QUEUECHAIN_SEL_ALL( + priv->hw_params.max_txq_num)); + iwl_write_prph(priv, IWL50_SCD_AGGR_SEL, 0); + + /* initiate the queues */ + for (i = 0; i < priv->hw_params.max_txq_num; i++) { + iwl_write_prph(priv, IWL50_SCD_QUEUE_RDPTR(i), 0); + iwl_write_direct32(priv, HBUS_TARG_WRPTR, 0 | (i << 8)); + iwl_write_targ_mem(priv, priv->scd_base_addr + + IWL50_SCD_CONTEXT_QUEUE_OFFSET(i), 0); + iwl_write_targ_mem(priv, priv->scd_base_addr + + IWL50_SCD_CONTEXT_QUEUE_OFFSET(i) + + sizeof(u32), + ((SCD_WIN_SIZE << + IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) & + IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) | + ((SCD_FRAME_LIMIT << + IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) & + IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK)); + } + + iwl_write_prph(priv, IWL50_SCD_INTERRUPT_MASK, + (1 << priv->hw_params.max_txq_num) - 1); + + iwl_write_prph(priv, IWL50_SCD_TXFACT, + SCD_TXFACT_REG_TXFIFO_MASK(0, 7)); + + iwl5000_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0); + /* map qos queues to fifos one-to-one */ + for (i = 0; i < ARRAY_SIZE(iwl5000_default_queue_to_tx_fifo); i++) { + int ac = iwl5000_default_queue_to_tx_fifo[i]; + iwl_txq_ctx_activate(priv, i); + iwl5000_tx_queue_set_status(priv, &priv->txq[i], ac, 0); + } + /* TODO - need to initialize those FIFOs inside the loop above, + * not only mark them as active */ + iwl_txq_ctx_activate(priv, 4); + iwl_txq_ctx_activate(priv, 7); + iwl_txq_ctx_activate(priv, 8); + iwl_txq_ctx_activate(priv, 9); + + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + /* Ask for statistics now, the uCode will send notification + * periodically after association */ + iwl_send_statistics_request(priv, CMD_ASYNC); + + return 0; +} + static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) { if ((priv->cfg->mod_params->num_of_queues > IWL50_NUM_QUEUES) || @@ -622,6 +777,8 @@ static struct iwl_lib_ops iwl5000_lib = { .disable_tx_fifo = iwl5000_disable_tx_fifo, .rx_handler_setup = iwl5000_rx_handler_setup, .load_ucode = iwl5000_load_ucode, + .init_alive_start = iwl5000_init_alive_start, + .alive_notify = iwl5000_alive_notify, .apm_ops = { .init = iwl5000_apm_init, .config = iwl5000_nic_config, diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index acac629..d6a04f6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -517,6 +517,34 @@ #define IWL49_SCD_QUEUE_RA_TID_MAP_RATID_MSK (0x01FF) /* 5000 SCD */ +#define IWL50_SCD_QUEUE_STTS_REG_POS_TXF (0) +#define IWL50_SCD_QUEUE_STTS_REG_POS_ACTIVE (3) +#define IWL50_SCD_QUEUE_STTS_REG_POS_WSL (4) +#define IWL50_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN (19) +#define IWL50_SCD_QUEUE_STTS_REG_MSK (0x00FF0000) + +#define IWL50_SCD_QUEUE_CTX_REG1_CREDIT_POS (8) +#define IWL50_SCD_QUEUE_CTX_REG1_CREDIT_MSK (0x00FFFF00) +#define IWL50_SCD_QUEUE_CTX_REG1_SUPER_CREDIT_POS (24) +#define IWL50_SCD_QUEUE_CTX_REG1_SUPER_CREDIT_MSK (0xFF000000) +#define IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS (0) +#define IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK (0x0000007F) +#define IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS (16) +#define IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK (0x007F0000) + +#define IWL50_SCD_CONTEXT_DATA_OFFSET (0x600) +#define IWL50_SCD_TX_STTS_BITMAP_OFFSET (0x7B1) +#define IWL50_SCD_TRANSLATE_TBL_OFFSET (0x7E0) + +#define IWL50_SCD_CONTEXT_QUEUE_OFFSET(x)\ + (IWL50_SCD_CONTEXT_DATA_OFFSET + ((x) * 8)) + +#define IWL50_SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \ + ((IWL50_SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffc) + +#define IWL50_SCD_QUEUECHAIN_SEL_ALL(x) (((1<<(x)) - 1) &\ + (~(1< Date: Thu, 15 May 2008 13:54:14 +0800 Subject: iwlwifi: iwl5000 WiFi/WiMax coexistence This patch adds WiFi/WiMax coexistence to iwl5000. Signed-off-by: Ron Rindjunsky Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 5e818ee..520c7ea 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -494,6 +494,16 @@ static void iwl5000_tx_queue_set_status(struct iwl_priv *priv, scd_retry ? "BA" : "AC", txq_id, tx_fifo_id); } +static int iwl5000_send_wimax_coex(struct iwl_priv *priv) +{ + struct iwl_wimax_coex_cmd coex_cmd; + + memset(&coex_cmd, 0, sizeof(coex_cmd)); + + return iwl_send_cmd_pdu(priv, COEX_PRIORITY_TABLE_CMD, + sizeof(coex_cmd), &coex_cmd); +} + static int iwl5000_alive_notify(struct iwl_priv *priv) { u32 a; @@ -568,6 +578,8 @@ static int iwl5000_alive_notify(struct iwl_priv *priv) iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); + iwl5000_send_wimax_coex(priv); + /* Ask for statistics now, the uCode will send notification * periodically after association */ iwl_send_statistics_request(priv, CMD_ASYNC); diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index dd84326..5b9e9bf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -93,6 +93,11 @@ enum { REPLY_LEDS_CMD = 0x48, REPLY_TX_LINK_QUALITY_CMD = 0x4e, /* 4965 only */ + /* WiMAX coexistence */ + COEX_PRIORITY_TABLE_CMD = 0x5a, /*5000 only */ + COEX_MEDIUM_NOTIFICATION = 0x5b, + COEX_EVENT_CMD = 0x5c, + /* 802.11h related */ RADAR_NOTIFICATION = 0x70, /* not used */ REPLY_QUIET_CMD = 0x71, /* not used */ @@ -2797,6 +2802,55 @@ struct iwl4965_led_cmd { u8 reserved; } __attribute__ ((packed)); +/* + * Coexistence WIFI/WIMAX Command + * COEX_PRIORITY_TABLE_CMD = 0x5a + * + */ +enum { + COEX_UNASSOC_IDLE = 0, + COEX_UNASSOC_MANUAL_SCAN = 1, + COEX_UNASSOC_AUTO_SCAN = 2, + COEX_CALIBRATION = 3, + COEX_PERIODIC_CALIBRATION = 4, + COEX_CONNECTION_ESTAB = 5, + COEX_ASSOCIATED_IDLE = 6, + COEX_ASSOC_MANUAL_SCAN = 7, + COEX_ASSOC_AUTO_SCAN = 8, + COEX_ASSOC_ACTIVE_LEVEL = 9, + COEX_RF_ON = 10, + COEX_RF_OFF = 11, + COEX_STAND_ALONE_DEBUG = 12, + COEX_IPAN_ASSOC_LEVEL = 13, + COEX_RSRVD1 = 14, + COEX_RSRVD2 = 15, + COEX_NUM_OF_EVENTS = 16 +}; + +struct iwl_wimax_coex_event_entry { + u8 request_prio; + u8 win_medium_prio; + u8 reserved; + u8 flags; +} __attribute__ ((packed)); + +/* COEX flag masks */ + +/* Staion table is valid */ +#define COEX_FLAGS_STA_TABLE_VALID_MSK (0x1) +/* UnMask wakeup src at unassociated sleep */ +#define COEX_FLAGS_UNASSOC_WA_UNMASK_MSK (0x4) +/* UnMask wakeup src at associated sleep */ +#define COEX_FLAGS_ASSOC_WA_UNMASK_MSK (0x8) +/* Enable CoEx feature. */ +#define COEX_FLAGS_COEX_ENABLE_MSK (0x80) + +struct iwl_wimax_coex_cmd { + u8 flags; + u8 reserved[3]; + struct iwl_wimax_coex_event_entry sta_prio[COEX_NUM_OF_EVENTS]; +} __attribute__ ((packed)); + /****************************************************************************** * (13) * Union of all expected notifications/responses: -- cgit v0.10.2 From da6833cb05cd76f4367fa7e4a783bf358c096faf Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 15 May 2008 13:54:15 +0800 Subject: iwlwifi: remove 4965 remainings in iwl-eeprom.c file The patch cleans up 4965 remaings from iwl-eeprom.c file. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index fa30660..300ef8e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -365,11 +365,11 @@ static void iwl_init_band_reference(const struct iwl_priv *priv, ? # x " " : "") /** - * iwl4965_set_fat_chan_info - Copy fat channel info into driver's priv. + * iwl_set_fat_chan_info - Copy fat channel info into driver's priv. * * Does not set up a command, or touch hardware. */ -static int iwl4965_set_fat_chan_info(struct iwl_priv *priv, +static int iwl_set_fat_chan_info(struct iwl_priv *priv, enum ieee80211_band band, u16 channel, const struct iwl_eeprom_channel *eeprom_ch, u8 fat_extension_channel) @@ -542,16 +542,16 @@ int iwl_init_channel_map(struct iwl_priv *priv) fat_extension_chan = HT_IE_EXT_CHANNEL_ABOVE; /* Set up driver's info for lower half */ - iwl4965_set_fat_chan_info(priv, ieeeband, - eeprom_ch_index[ch], - &(eeprom_ch_info[ch]), - fat_extension_chan); + iwl_set_fat_chan_info(priv, ieeeband, + eeprom_ch_index[ch], + &(eeprom_ch_info[ch]), + fat_extension_chan); /* Set up driver's info for upper half */ - iwl4965_set_fat_chan_info(priv, ieeeband, - (eeprom_ch_index[ch] + 4), - &(eeprom_ch_info[ch]), - HT_IE_EXT_CHANNEL_BELOW); + iwl_set_fat_chan_info(priv, ieeeband, + (eeprom_ch_index[ch] + 4), + &(eeprom_ch_info[ch]), + HT_IE_EXT_CHANNEL_BELOW); } } @@ -560,7 +560,7 @@ int iwl_init_channel_map(struct iwl_priv *priv) EXPORT_SYMBOL(iwl_init_channel_map); /* - * iwl_free_channel_map - undo allocations in iwl4965_init_channel_map + * iwl_free_channel_map - undo allocations in iwl_init_channel_map */ void iwl_free_channel_map(struct iwl_priv *priv) { -- cgit v0.10.2 From 445c2dff409ef9de5d2f964d20917ab238fd266f Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 15 May 2008 13:54:16 +0800 Subject: iwlwifi: add debugfs to disable/enable run time calibration This patch adds functionality to debugfs to enable or disable chain noise or sensitivity calibrations. Signed-off-by: Tomas Winkler Signed-off-by: Emmanuel Grumbach Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c index 1289d4c..beb9716 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c @@ -426,6 +426,9 @@ void iwl_init_sensitivity(struct iwl_priv *priv) struct iwl_sensitivity_data *data = NULL; const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens; + if (priv->disable_sens_cal) + return; + IWL_DEBUG_CALIB("Start iwl_init_sensitivity\n"); /* Clear driver's sensitivity algo data */ @@ -486,6 +489,9 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv, unsigned long flags; struct statistics_general_data statis; + if (priv->disable_sens_cal) + return; + data = &(priv->sensitivity_data); if (!iwl_is_associated(priv)) { @@ -608,6 +614,9 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, unsigned long flags; struct statistics_rx_non_phy *rx_info = &(stat_resp->rx.general); + if (priv->disable_chain_noise_cal) + return; + data = &(priv->chain_noise_data); /* Accumulate just the first 20 beacons after the first association, diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.h b/drivers/net/wireless/iwlwifi/iwl-calib.h index 933b0b0..e690668 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.h +++ b/drivers/net/wireless/iwlwifi/iwl-calib.h @@ -81,7 +81,9 @@ void iwl_init_sensitivity(struct iwl_priv *priv); static inline void iwl_chain_noise_reset(struct iwl_priv *priv) { - if (priv->cfg->ops->utils->chain_noise_reset) + + if (!priv->disable_chain_noise_cal && + priv->cfg->ops->utils->chain_noise_reset) priv->cfg->ops->utils->chain_noise_reset(priv); } #else diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 2f24594..c3f8e90 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -45,13 +45,20 @@ struct iwl_debugfs { const char *name; struct dentry *dir_drv; struct dentry *dir_data; - struct dir_data_files{ + struct dentry *dir_rf; + struct dir_data_files { struct dentry *file_sram; struct dentry *file_eeprom; struct dentry *file_stations; struct dentry *file_rx_statistics; struct dentry *file_tx_statistics; } dbgfs_data_files; + struct dir_rf_files { +#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB + struct dentry *file_disable_sensitivity; + struct dentry *file_disable_chain_noise; +#endif /* CONFIG_IWLWIFI_RUN_TIME_CALIB */ + } dbgfs_rf_files; u32 sram_offset; u32 sram_len; }; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index ad25806..f7ec200 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -55,6 +55,13 @@ goto err; \ } while (0) +#define DEBUGFS_ADD_BOOL(name, parent, ptr) do { \ + dbgfs->dbgfs_##parent##_files.file_##name = \ + debugfs_create_bool(#name, 0644, dbgfs->dir_##parent, ptr); \ + if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name)) \ + goto err; \ +} while (0) + #define DEBUGFS_REMOVE(name) do { \ debugfs_remove(name); \ name = NULL; \ @@ -344,12 +351,17 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) } DEBUGFS_ADD_DIR(data, dbgfs->dir_drv); + DEBUGFS_ADD_DIR(rf, dbgfs->dir_drv); DEBUGFS_ADD_FILE(eeprom, data); DEBUGFS_ADD_FILE(sram, data); DEBUGFS_ADD_FILE(stations, data); DEBUGFS_ADD_FILE(rx_statistics, data); DEBUGFS_ADD_FILE(tx_statistics, data); - +#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB + DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); + DEBUGFS_ADD_BOOL(disable_chain_noise, rf, + &priv->disable_chain_noise_cal); +#endif /* CONFIG_IWLWIFI_RUN_TIME_CALIB */ return 0; err: @@ -374,6 +386,11 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sram); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_stations); DEBUGFS_REMOVE(priv->dbgfs->dir_data); +#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise); +#endif /* CONFIG_IWLWIFI_RUN_TIME_CALIB */ + DEBUGFS_REMOVE(priv->dbgfs->dir_rf); DEBUGFS_REMOVE(priv->dbgfs->dir_drv); kfree(priv->dbgfs); priv->dbgfs = NULL; @@ -381,3 +398,4 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) EXPORT_SYMBOL(iwl_dbgfs_unregister); + diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index b1ff0af..820542b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1212,9 +1212,13 @@ struct iwl_priv { #endif /* CONFIG_IWLWIFI_DEBUG */ struct work_struct txpower_work; +#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB + u32 disable_sens_cal; + u32 disable_chain_noise_cal; +#endif /* CONFIG_IWLWIFI_RUN_TIME_CALIB */ #ifdef CONFIG_IWL4965_RUN_TIME_CALIB struct work_struct sensitivity_work; -#endif +#endif /* CONFIG_IWL4965_RUN_TIME_CALIB */ struct timer_list statistics_periodic; }; /*iwl_priv */ -- cgit v0.10.2 From 6ba879562289bcad537a2374754ef750307c7d32 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 15 May 2008 13:54:17 +0800 Subject: iwlwifi: refactor pci prob flow This patch refactores pci prob flow. It moves mac80211 registration to the end, otherwise there is a race between error path in pci_probe and mac_start. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 79e46c5..21f481e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -518,12 +518,6 @@ static int iwlcore_init_geos(struct iwl_priv *priv) priv->bands[IEEE80211_BAND_2GHZ].n_channels, priv->bands[IEEE80211_BAND_5GHZ].n_channels); - if (priv->bands[IEEE80211_BAND_2GHZ].n_channels) - priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = - &priv->bands[IEEE80211_BAND_2GHZ]; - if (priv->bands[IEEE80211_BAND_5GHZ].n_channels) - priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = - &priv->bands[IEEE80211_BAND_5GHZ]; set_bit(STATUS_GEO_CONFIGURED, &priv->status); @@ -533,13 +527,12 @@ static int iwlcore_init_geos(struct iwl_priv *priv) /* * iwlcore_free_geos - undo allocations in iwlcore_init_geos */ -void iwlcore_free_geos(struct iwl_priv *priv) +static void iwlcore_free_geos(struct iwl_priv *priv) { kfree(priv->ieee_channels); kfree(priv->ieee_rates); clear_bit(STATUS_GEO_CONFIGURED, &priv->status); } -EXPORT_SYMBOL(iwlcore_free_geos); #ifdef CONFIG_IWL4965_HT static u8 is_single_rx_stream(struct iwl_priv *priv) @@ -767,8 +760,9 @@ int iwl_set_rxon_channel(struct iwl_priv *priv, } EXPORT_SYMBOL(iwl_set_rxon_channel); -static void iwlcore_init_hw(struct iwl_priv *priv) +int iwl_setup_mac(struct iwl_priv *priv) { + int ret; struct ieee80211_hw *hw = priv->hw; hw->rate_control_algorithm = "iwl-4965-rs"; @@ -782,9 +776,29 @@ static void iwlcore_init_hw(struct iwl_priv *priv) /* Enhanced value; more queues, to support 11n aggregation */ hw->ampdu_queues = 12; #endif /* CONFIG_IWL4965_HT */ + + hw->conf.beacon_int = 100; + + if (priv->bands[IEEE80211_BAND_2GHZ].n_channels) + priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = + &priv->bands[IEEE80211_BAND_2GHZ]; + if (priv->bands[IEEE80211_BAND_5GHZ].n_channels) + priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = + &priv->bands[IEEE80211_BAND_5GHZ]; + + ret = ieee80211_register_hw(priv->hw); + if (ret) { + IWL_ERROR("Failed to register hw (error %d)\n", ret); + return ret; + } + priv->mac80211_registered = 1; + + return 0; } +EXPORT_SYMBOL(iwl_setup_mac); + -static int iwlcore_init_drv(struct iwl_priv *priv) +int iwl_init_drv(struct iwl_priv *priv) { int ret; int i; @@ -821,6 +835,9 @@ static int iwlcore_init_drv(struct iwl_priv *priv) /* Choose which receivers/antennas to use */ iwl_set_rxon_chain(priv); + if (priv->cfg->mod_params->enable_qos) + priv->qos_data.qos_enable = 1; + iwl_reset_qos(priv); priv->qos_data.qos_active = 0; @@ -845,34 +862,22 @@ static int iwlcore_init_drv(struct iwl_priv *priv) goto err_free_channel_map; } - ret = ieee80211_register_hw(priv->hw); - if (ret) { - IWL_ERROR("Failed to register network device (error %d)\n", - ret); - goto err_free_geos; - } - - priv->hw->conf.beacon_int = 100; - priv->mac80211_registered = 1; - return 0; -err_free_geos: - iwlcore_free_geos(priv); err_free_channel_map: iwl_free_channel_map(priv); err: return ret; } +EXPORT_SYMBOL(iwl_init_drv); + -int iwl_setup(struct iwl_priv *priv) +void iwl_uninit_drv(struct iwl_priv *priv) { - int ret = 0; - iwlcore_init_hw(priv); - ret = iwlcore_init_drv(priv); - return ret; + iwlcore_free_geos(priv); + iwl_free_channel_map(priv); } -EXPORT_SYMBOL(iwl_setup); +EXPORT_SYMBOL(iwl_uninit_drv); /* Low level driver call this function to update iwlcore with * driver status. diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index b159fd3..774aa7c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -175,13 +175,13 @@ void iwl_set_rxon_chain(struct iwl_priv *priv); int iwl_set_rxon_channel(struct iwl_priv *priv, enum ieee80211_band band, u16 channel); -void iwlcore_free_geos(struct iwl_priv *priv); -int iwl_setup(struct iwl_priv *priv); void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info); u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv, struct ieee80211_ht_info *sta_ht_inf); int iwl_hw_nic_init(struct iwl_priv *priv); - +int iwl_setup_mac(struct iwl_priv *priv); +int iwl_init_drv(struct iwl_priv *priv); +void iwl_uninit_drv(struct iwl_priv *priv); /* "keep warm" functions */ int iwl_kw_init(struct iwl_priv *priv); int iwl_kw_alloc(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 300ef8e..e559c19 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -567,7 +567,6 @@ void iwl_free_channel_map(struct iwl_priv *priv) kfree(priv->channel_info); priv->channel_count = 0; } -EXPORT_SYMBOL(iwl_free_channel_map); /** * iwl_get_channel_info - Find driver's private channel info diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index e06142d..05edde1 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -5878,10 +5878,10 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e } /******************* - * 6. Setup hw/priv + * 6. Setup priv *******************/ - err = iwl_setup(priv); + err = iwl_init_drv(priv); if (err) goto out_free_eeprom; /* At this point both hw and priv are initialized. */ @@ -5896,9 +5896,6 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e IWL_DEBUG_INFO("Radio disabled.\n"); } - if (priv->cfg->mod_params->enable_qos) - priv->qos_data.qos_enable = 1; - /******************** * 8. Setup services ********************/ @@ -5909,14 +5906,9 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e err = sysfs_create_group(&pdev->dev.kobj, &iwl4965_attribute_group); if (err) { IWL_ERROR("failed to create sysfs device attributes\n"); - goto out_free_eeprom; + goto out_uninit_drv; } - err = iwl_dbgfs_register(priv, DRV_NAME); - if (err) { - IWL_ERROR("failed to create debugfs files\n"); - goto out_remove_sysfs; - } iwl4965_setup_deferred_work(priv); iwl4965_setup_rx_handlers(priv); @@ -5927,12 +5919,26 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e pci_save_state(pdev); pci_disable_device(pdev); + /********************************** + * 10. Setup and register mac80211 + **********************************/ + + err = iwl_setup_mac(priv); + if (err) + goto out_remove_sysfs; + + err = iwl_dbgfs_register(priv, DRV_NAME); + if (err) + IWL_ERROR("failed to create debugfs files\n"); + /* notify iwlcore to init */ iwlcore_low_level_notify(priv, IWLCORE_INIT_EVT); return 0; out_remove_sysfs: sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group); + out_uninit_drv: + iwl_uninit_drv(priv); out_free_eeprom: iwl_eeprom_free(priv); out_iounmap: @@ -6014,8 +6020,7 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev) pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); - iwl_free_channel_map(priv); - iwlcore_free_geos(priv); + iwl_uninit_drv(priv); if (priv->ibss_beacon) dev_kfree_skb(priv->ibss_beacon); -- cgit v0.10.2 From 189a2b5942d62bd18e1e01772c4c784253f5dd16 Mon Sep 17 00:00:00 2001 From: Ester Kummer Date: Thu, 15 May 2008 13:54:18 +0800 Subject: iwlwifi: trigger event log from debugfs This patch adds a trigger for event log printing to debugfs. It removes the triger from sysfs. Signed-off-by: Ester Kummer Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 21f481e..7e25ca4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1055,3 +1055,104 @@ int iwl_verify_ucode(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_verify_ucode); + +#define EVENT_START_OFFSET (4 * sizeof(u32)) + +/** + * iwl_print_event_log - Dump error event log to syslog + * + * NOTE: Must be called with iwl4965_grab_nic_access() already obtained! + */ +void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, + u32 num_events, u32 mode) +{ + u32 i; + u32 base; /* SRAM byte address of event log header */ + u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */ + u32 ptr; /* SRAM byte address of log data */ + u32 ev, time, data; /* event log data */ + + if (num_events == 0) + return; + + base = le32_to_cpu(priv->card_alive.log_event_table_ptr); + + if (mode == 0) + event_size = 2 * sizeof(u32); + else + event_size = 3 * sizeof(u32); + + ptr = base + EVENT_START_OFFSET + (start_idx * event_size); + + /* "time" is actually "data" for mode 0 (no timestamp). + * place event id # at far right for easier visual parsing. */ + for (i = 0; i < num_events; i++) { + ev = iwl_read_targ_mem(priv, ptr); + ptr += sizeof(u32); + time = iwl_read_targ_mem(priv, ptr); + ptr += sizeof(u32); + if (mode == 0) + IWL_ERROR("0x%08x\t%04u\n", time, ev); /* data, ev */ + else { + data = iwl_read_targ_mem(priv, ptr); + ptr += sizeof(u32); + IWL_ERROR("%010u\t0x%08x\t%04u\n", time, data, ev); + } + } +} +EXPORT_SYMBOL(iwl_print_event_log); + + +void iwl_dump_nic_event_log(struct iwl_priv *priv) +{ + int rc; + u32 base; /* SRAM byte address of event log header */ + u32 capacity; /* event log capacity in # entries */ + u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */ + u32 num_wraps; /* # times uCode wrapped to top of log */ + u32 next_entry; /* index of next entry to be written by uCode */ + u32 size; /* # entries that we'll print */ + + base = le32_to_cpu(priv->card_alive.log_event_table_ptr); + if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { + IWL_ERROR("Invalid event log pointer 0x%08X\n", base); + return; + } + + rc = iwl_grab_nic_access(priv); + if (rc) { + IWL_WARNING("Can not read from adapter at this time.\n"); + return; + } + + /* event log header */ + capacity = iwl_read_targ_mem(priv, base); + mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32))); + num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32))); + next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32))); + + size = num_wraps ? capacity : next_entry; + + /* bail out if nothing in log */ + if (size == 0) { + IWL_ERROR("Start IWL Event Log Dump: nothing in log\n"); + iwl_release_nic_access(priv); + return; + } + + IWL_ERROR("Start IWL Event Log Dump: display count %d, wraps %d\n", + size, num_wraps); + + /* if uCode has wrapped back to top of log, start at the oldest entry, + * i.e the next one that uCode would fill. */ + if (num_wraps) + iwl_print_event_log(priv, next_entry, + capacity - next_entry, mode); + /* (then/else) start at top of log */ + iwl_print_event_log(priv, 0, next_entry, mode); + + iwl_release_nic_access(priv); +} +EXPORT_SYMBOL(iwl_dump_nic_event_log); + + diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 774aa7c..a8d062f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -232,6 +232,14 @@ int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len, struct sk_buff *skb)); int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd); + +/***************************************************** +* Error Handling Debugging +******************************************************/ +void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, + u32 num_events, u32 mode); +void iwl_dump_nic_event_log(struct iwl_priv *priv); + /*************** DRIVER STATUS FUNCTIONS *****/ #define STATUS_HCMD_ACTIVE 0 /* host command in progress */ diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index c3f8e90..11de561 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -52,6 +52,7 @@ struct iwl_debugfs { struct dentry *file_stations; struct dentry *file_rx_statistics; struct dentry *file_tx_statistics; + struct dentry *file_log_event; } dbgfs_data_files; struct dir_rf_files { #ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index f7ec200..c64e602 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -92,6 +92,14 @@ static const struct file_operations iwl_dbgfs_##name##_ops = { \ .open = iwl_dbgfs_open_file_generic, \ }; +#define DEBUGFS_WRITE_FILE_OPS(name) \ + DEBUGFS_WRITE_FUNC(name); \ +static const struct file_operations iwl_dbgfs_##name##_ops = { \ + .write = iwl_dbgfs_##name##_write, \ + .open = iwl_dbgfs_open_file_generic, \ +}; + + #define DEBUGFS_READ_WRITE_FILE_OPS(name) \ DEBUGFS_READ_FUNC(name); \ DEBUGFS_WRITE_FUNC(name); \ @@ -324,7 +332,29 @@ static ssize_t iwl_dbgfs_eeprom_read(struct file *file, return ret; } +static ssize_t iwl_dbgfs_log_event_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = file->private_data; + u32 event_log_flag; + char buf[8]; + int buf_size; + + memset(buf, 0, sizeof(buf)); + buf_size = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + if (sscanf(buf, "%d", &event_log_flag) != 1) + return -EFAULT; + if (event_log_flag == 1) + iwl_dump_nic_event_log(priv); + + return count; +} + DEBUGFS_READ_WRITE_FILE_OPS(sram); +DEBUGFS_WRITE_FILE_OPS(log_event); DEBUGFS_READ_FILE_OPS(eeprom); DEBUGFS_READ_FILE_OPS(stations); DEBUGFS_READ_FILE_OPS(rx_statistics); @@ -354,6 +384,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_DIR(rf, dbgfs->dir_drv); DEBUGFS_ADD_FILE(eeprom, data); DEBUGFS_ADD_FILE(sram, data); + DEBUGFS_ADD_FILE(log_event, data); DEBUGFS_ADD_FILE(stations, data); DEBUGFS_ADD_FILE(rx_statistics, data); DEBUGFS_ADD_FILE(tx_statistics, data); @@ -384,6 +415,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_rx_statistics); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_tx_statistics); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sram); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_log_event); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_stations); DEBUGFS_REMOVE(priv->dbgfs->dir_data); #ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 05edde1..48c59cb 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -2692,103 +2692,6 @@ static void iwl4965_dump_nic_error_log(struct iwl_priv *priv) iwl_release_nic_access(priv); } -#define EVENT_START_OFFSET (4 * sizeof(u32)) - -/** - * iwl4965_print_event_log - Dump error event log to syslog - * - * NOTE: Must be called with iwl_grab_nic_access() already obtained! - */ -static void iwl4965_print_event_log(struct iwl_priv *priv, u32 start_idx, - u32 num_events, u32 mode) -{ - u32 i; - u32 base; /* SRAM byte address of event log header */ - u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */ - u32 ptr; /* SRAM byte address of log data */ - u32 ev, time, data; /* event log data */ - - if (num_events == 0) - return; - - base = le32_to_cpu(priv->card_alive.log_event_table_ptr); - - if (mode == 0) - event_size = 2 * sizeof(u32); - else - event_size = 3 * sizeof(u32); - - ptr = base + EVENT_START_OFFSET + (start_idx * event_size); - - /* "time" is actually "data" for mode 0 (no timestamp). - * place event id # at far right for easier visual parsing. */ - for (i = 0; i < num_events; i++) { - ev = iwl_read_targ_mem(priv, ptr); - ptr += sizeof(u32); - time = iwl_read_targ_mem(priv, ptr); - ptr += sizeof(u32); - if (mode == 0) - IWL_ERROR("0x%08x\t%04u\n", time, ev); /* data, ev */ - else { - data = iwl_read_targ_mem(priv, ptr); - ptr += sizeof(u32); - IWL_ERROR("%010u\t0x%08x\t%04u\n", time, data, ev); - } - } -} - -static void iwl4965_dump_nic_event_log(struct iwl_priv *priv) -{ - int rc; - u32 base; /* SRAM byte address of event log header */ - u32 capacity; /* event log capacity in # entries */ - u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */ - u32 num_wraps; /* # times uCode wrapped to top of log */ - u32 next_entry; /* index of next entry to be written by uCode */ - u32 size; /* # entries that we'll print */ - - base = le32_to_cpu(priv->card_alive.log_event_table_ptr); - if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { - IWL_ERROR("Invalid event log pointer 0x%08X\n", base); - return; - } - - rc = iwl_grab_nic_access(priv); - if (rc) { - IWL_WARNING("Can not read from adapter at this time.\n"); - return; - } - - /* event log header */ - capacity = iwl_read_targ_mem(priv, base); - mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32))); - num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32))); - next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32))); - - size = num_wraps ? capacity : next_entry; - - /* bail out if nothing in log */ - if (size == 0) { - IWL_ERROR("Start IWL Event Log Dump: nothing in log\n"); - iwl_release_nic_access(priv); - return; - } - - IWL_ERROR("Start IWL Event Log Dump: display count %d, wraps %d\n", - size, num_wraps); - - /* if uCode has wrapped back to top of log, start at the oldest entry, - * i.e the next one that uCode would fill. */ - if (num_wraps) - iwl4965_print_event_log(priv, next_entry, - capacity - next_entry, mode); - - /* (then/else) start at top of log */ - iwl4965_print_event_log(priv, 0, next_entry, mode); - - iwl_release_nic_access(priv); -} - /** * iwl4965_irq_handle_error - called for HW or SW error interrupt from card */ @@ -2803,7 +2706,7 @@ static void iwl4965_irq_handle_error(struct iwl_priv *priv) #ifdef CONFIG_IWLWIFI_DEBUG if (priv->debug_level & IWL_DL_FW_ERRORS) { iwl4965_dump_nic_error_log(priv); - iwl4965_dump_nic_event_log(priv); + iwl_dump_nic_event_log(priv); iwl4965_print_rx_config_cmd(priv); } #endif @@ -5640,20 +5543,6 @@ static ssize_t dump_error_log(struct device *d, static DEVICE_ATTR(dump_errors, S_IWUSR, NULL, dump_error_log); -static ssize_t dump_event_log(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - char *p = (char *)buf; - - if (p[0] == '1') - iwl4965_dump_nic_event_log((struct iwl_priv *)d->driver_data); - - return strnlen(buf, count); -} - -static DEVICE_ATTR(dump_events, S_IWUSR, NULL, dump_event_log); - /***************************************************************************** * * driver setup and teardown @@ -5700,7 +5589,6 @@ static void iwl4965_cancel_deferred_work(struct iwl_priv *priv) static struct attribute *iwl4965_sysfs_entries[] = { &dev_attr_channels.attr, &dev_attr_dump_errors.attr, - &dev_attr_dump_events.attr, &dev_attr_flags.attr, &dev_attr_filter_flags.attr, #ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT -- cgit v0.10.2 From c4680470a34a4f39af3d0a5c40f70befd8701908 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 15 May 2008 12:55:25 +0200 Subject: mac80211: fix bugs in queue handling functions Commit 55c308c1315bc7267dbb88011c208fd743cdce31 ("mac80211: QoS related cleanups") introduced another bug, the queue handling functions that operate on all queues now only operated on the first queues, not the A-MPDU queues as expected. This patch fixes this. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 24a465c..9cd07e1 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -355,7 +355,7 @@ void ieee80211_start_queues(struct ieee80211_hw *hw) struct ieee80211_local *local = hw_to_local(hw); int i; - for (i = 0; i < local->hw.queues; i++) + for (i = 0; i < hw->queues + hw->ampdu_queues; i++) clear_bit(IEEE80211_LINK_STATE_XOFF, &local->state[i]); if (!ieee80211_qdisc_installed(local->mdev)) netif_start_queue(local->mdev); @@ -366,7 +366,7 @@ void ieee80211_stop_queues(struct ieee80211_hw *hw) { int i; - for (i = 0; i < hw->queues; i++) + for (i = 0; i < hw->queues + hw->ampdu_queues; i++) ieee80211_stop_queue(hw, i); } EXPORT_SYMBOL(ieee80211_stop_queues); @@ -375,7 +375,7 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw) { int i; - for (i = 0; i < hw->queues; i++) + for (i = 0; i < hw->queues + hw->ampdu_queues; i++) ieee80211_wake_queue(hw, i); } EXPORT_SYMBOL(ieee80211_wake_queues); -- cgit v0.10.2 From 36d6825b91bc492b65b6333c369cd96a2fc8c903 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 15 May 2008 12:55:26 +0200 Subject: mac80211: let drivers wake but not start queues Having drivers start queues is just confusing, their ->start() callback can block and do whatever is necessary, so let mac80211 start queues and have drivers wake queues when necessary (to get packets flowing again right away.) Signed-off-by: Johannes Berg Acked-by: David S. Miller Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index 7af5d88..79dfca5 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -2015,7 +2015,7 @@ static int adm8211_resume(struct pci_dev *pdev) if (priv->mode != IEEE80211_IF_TYPE_INVALID) { adm8211_start(dev); - ieee80211_start_queues(dev); + ieee80211_wake_queues(dev); } return 0; diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index c76ada1..3f16ad6 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -1599,7 +1599,7 @@ ath5k_txq_cleanup(struct ath5k_softc *sc) sc->txqs[i].link); } } - ieee80211_start_queues(sc->hw); /* XXX move to callers */ + ieee80211_wake_queues(sc->hw); /* XXX move to callers */ for (i = 0; i < ARRAY_SIZE(sc->txqs); i++) if (sc->txqs[i].setup) diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index fc23ba5..9445a60 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -3497,7 +3497,6 @@ static int b43_wireless_core_start(struct b43_wldev *dev) /* Start data flow (TX/RX). */ b43_mac_enable(dev); b43_interrupt_enable(dev, dev->irq_savedstate); - ieee80211_start_queues(dev->wl->hw); /* Start maintainance work */ b43_periodic_tasks_setup(dev); diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 7755c59..b05a507 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -2794,7 +2794,6 @@ static int b43legacy_wireless_core_start(struct b43legacy_wldev *dev) /* Start data flow (TX/RX) */ b43legacy_mac_enable(dev); b43legacy_interrupt_enable(dev, dev->irq_savedstate); - ieee80211_start_queues(dev->wl->hw); /* Start maintenance work */ b43legacy_periodic_tasks_setup(dev); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index b8fb8d8..54cde8a 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -5823,7 +5823,7 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv) if (iwl3945_is_rfkill(priv)) return; - ieee80211_start_queues(priv->hw); + ieee80211_wake_queues(priv->hw); priv->active_rate = priv->rates_mask; priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK; diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 48c59cb..db4f606 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -3367,7 +3367,7 @@ static void iwl4965_alive_start(struct iwl_priv *priv) if (iwl_is_rfkill(priv)) return; - ieee80211_start_queues(priv->hw); + ieee80211_wake_queues(priv->hw); priv->active_rate = priv->rates_mask; priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK; diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 9cbef5b..3d35fe6 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -375,9 +375,6 @@ static void inline p54_wake_free_queues(struct ieee80211_hw *dev) struct p54_common *priv = dev->priv; int i; - /* ieee80211_start_queues is great if all queues are really empty. - * But, what if some are full? */ - for (i = 0; i < dev->queues; i++) if (priv->tx_stats[i].len < priv->tx_stats[i].limit) ieee80211_wake_queue(dev, i); diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index fa52772..7dd4add 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -665,7 +665,7 @@ static int p54p_resume(struct pci_dev *pdev) if (priv->common.mode != IEEE80211_IF_TYPE_INVALID) { p54p_open(dev); - ieee80211_start_queues(dev); + ieee80211_wake_queues(dev); } return 0; diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 171f445..d341764 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -125,7 +125,7 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev) /* * Start the TX queues. */ - ieee80211_start_queues(rt2x00dev->hw); + ieee80211_wake_queues(rt2x00dev->hw); return 0; } @@ -1186,7 +1186,7 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) * In that case we have disabled the TX queue and should * now enable it again */ - ieee80211_start_queues(rt2x00dev->hw); + ieee80211_wake_queues(rt2x00dev->hw); /* * During interface iteration we might have changed the diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 909956c..f00fc76 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1567,14 +1567,6 @@ void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue); void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue); /** - * ieee80211_start_queues - start all queues - * @hw: pointer to as obtained from ieee80211_alloc_hw(). - * - * Drivers should use this function instead of netif_start_queue. - */ -void ieee80211_start_queues(struct ieee80211_hw *hw); - -/** * ieee80211_stop_queues - stop all queues * @hw: pointer as obtained from ieee80211_alloc_hw(). * diff --git a/net/mac80211/main.c b/net/mac80211/main.c index b0fddb7..9761d9b 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -110,7 +110,13 @@ static int ieee80211_master_open(struct net_device *dev) break; } } - return res; + + if (res) + return res; + + netif_start_queue(local->mdev); + + return 0; } static int ieee80211_master_stop(struct net_device *dev) diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 9cd07e1..800c15a 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -350,18 +350,6 @@ void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue) } EXPORT_SYMBOL(ieee80211_stop_queue); -void ieee80211_start_queues(struct ieee80211_hw *hw) -{ - struct ieee80211_local *local = hw_to_local(hw); - int i; - - for (i = 0; i < hw->queues + hw->ampdu_queues; i++) - clear_bit(IEEE80211_LINK_STATE_XOFF, &local->state[i]); - if (!ieee80211_qdisc_installed(local->mdev)) - netif_start_queue(local->mdev); -} -EXPORT_SYMBOL(ieee80211_start_queues); - void ieee80211_stop_queues(struct ieee80211_hw *hw) { int i; -- cgit v0.10.2 From 2e92e6f2c50b4baf85cca968f0e6f1b5c0df7d39 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 15 May 2008 12:55:27 +0200 Subject: mac80211: use rate index in TX control This patch modifies struct ieee80211_tx_control to give band info and the rate index (instead of rate pointers) to drivers. This mostly serves to reduce the TX control structure size to make it fit into skb->cb so that the fragmentation code can put it there and we can think about passing it to drivers that way in the future. The rt2x00 driver update was done by Ivo, thanks. Signed-off-by: Ivo van Doorn Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index 79dfca5..22db664 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -1693,10 +1693,10 @@ static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb, size_t payload_len, hdrlen; int plcp, dur, len, plcp_signal, short_preamble; struct ieee80211_hdr *hdr; + struct ieee80211_rate *txrate = ieee80211_get_tx_rate(dev, control); - short_preamble = !!(control->tx_rate->flags & - IEEE80211_TXCTL_SHORT_PREAMBLE); - plcp_signal = control->tx_rate->bitrate; + short_preamble = !!(txrate->flags & IEEE80211_TXCTL_SHORT_PREAMBLE); + plcp_signal = txrate->bitrate; hdr = (struct ieee80211_hdr *)skb->data; fc = le16_to_cpu(hdr->frame_control) & ~IEEE80211_FCTL_PROTECTED; diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 3f16ad6..32ee351 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -1323,7 +1323,8 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, ret = ah->ah_setup_tx_desc(ah, ds, pktlen, ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL, - (sc->power_level * 2), ctl->tx_rate->hw_value, + (sc->power_level * 2), + ieee80211_get_tx_rate(sc->hw, ctl)->hw_value, ctl->retry_limit, keyidx, 0, flags, 0, 0); if (ret) goto err_unmap; @@ -2046,7 +2047,8 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, ret = ah->ah_setup_tx_desc(ah, ds, skb->len, ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_BEACON, (sc->power_level * 2), - ctl->tx_rate->hw_value, 1, AR5K_TXKEYIX_INVALID, + ieee80211_get_tx_rate(sc->hw, ctl)->hw_value, + 1, AR5K_TXKEYIX_INVALID, antenna, flags, 0, 0); if (ret) goto err_unmap; @@ -2654,7 +2656,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb, memmove(skb->data, skb->data+pad, hdrlen); } - sc->led_txrate = ctl->tx_rate->hw_value; + sc->led_txrate = ieee80211_get_tx_rate(hw, ctl)->hw_value; spin_lock_irqsave(&sc->txbuflock, flags); if (list_empty(&sc->txbuf)) { diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 9445a60..e428645 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1372,7 +1372,7 @@ static void b43_write_beacon_template(struct b43_wldev *dev, bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data); len = min((size_t) dev->wl->current_beacon->len, 0x200 - sizeof(struct b43_plcp_hdr6)); - rate = dev->wl->beacon_txctl.tx_rate->hw_value; + rate = ieee80211_get_tx_rate(dev->wl->hw, &dev->wl->beacon_txctl)->hw_value; b43_write_template_common(dev, (const u8 *)bcn, len, ram_offset, shm_size_offset, rate); diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index afce933..9b682a3 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -201,13 +201,14 @@ int b43_generate_txhdr(struct b43_wldev *dev, u32 mac_ctl = 0; u16 phy_ctl = 0; u8 extra_ft = 0; + struct ieee80211_rate *txrate; memset(txhdr, 0, sizeof(*txhdr)); - WARN_ON(!txctl->tx_rate); - rate = txctl->tx_rate ? txctl->tx_rate->hw_value : B43_CCK_RATE_1MB; + txrate = ieee80211_get_tx_rate(dev->wl->hw, txctl); + rate = txrate ? txrate->hw_value : B43_CCK_RATE_1MB; rate_ofdm = b43_is_ofdm_rate(rate); - fbrate = txctl->alt_retry_rate ? : txctl->tx_rate; + fbrate = ieee80211_get_alt_retry_rate(dev->wl->hw, txctl) ? : txrate; rate_fb = fbrate->hw_value; rate_fb_ofdm = b43_is_ofdm_rate(rate_fb); @@ -336,9 +337,11 @@ int b43_generate_txhdr(struct b43_wldev *dev, int rts_rate, rts_rate_fb; int rts_rate_ofdm, rts_rate_fb_ofdm; struct b43_plcp_hdr6 *plcp; + struct ieee80211_rate *rts_cts_rate; - WARN_ON(!txctl->rts_cts_rate); - rts_rate = txctl->rts_cts_rate ? txctl->rts_cts_rate->hw_value : B43_CCK_RATE_1MB; + rts_cts_rate = ieee80211_get_rts_cts_rate(dev->wl->hw, txctl); + + rts_rate = rts_cts_rate ? rts_cts_rate->hw_value : B43_CCK_RATE_1MB; rts_rate_ofdm = b43_is_ofdm_rate(rts_rate); rts_rate_fb = b43_calc_fallback_rate(rts_rate); rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb); diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c index bed9e04..55dc251 100644 --- a/drivers/net/wireless/b43legacy/xmit.c +++ b/drivers/net/wireless/b43legacy/xmit.c @@ -201,15 +201,18 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, unsigned int plcp_fragment_len; u32 mac_ctl = 0; u16 phy_ctl = 0; + struct ieee80211_rate *tx_rate; wlhdr = (const struct ieee80211_hdr *)fragment_data; fctl = le16_to_cpu(wlhdr->frame_control); memset(txhdr, 0, sizeof(*txhdr)); - rate = txctl->tx_rate->hw_value; + tx_rate = ieee80211_get_tx_rate(dev->wl->hw, txctl); + + rate = tx_rate->hw_value; rate_ofdm = b43legacy_is_ofdm_rate(rate); - rate_fb = txctl->alt_retry_rate ? : txctl->tx_rate; + rate_fb = ieee80211_get_alt_retry_rate(dev->wl->hw, txctl) ? : tx_rate; rate_fb_ofdm = b43legacy_is_ofdm_rate(rate_fb->hw_value); txhdr->mac_frame_ctl = wlhdr->frame_control; @@ -312,7 +315,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, int rts_rate_ofdm; int rts_rate_fb_ofdm; - rts_rate = txctl->rts_cts_rate->hw_value; + rts_rate = ieee80211_get_rts_cts_rate(dev->wl->hw, txctl)->hw_value; rts_rate_ofdm = b43legacy_is_ofdm_rate(rts_rate); rts_rate_fb = b43legacy_calc_fallback_rate(rts_rate); rts_rate_fb_ofdm = b43legacy_is_ofdm_rate(rts_rate_fb); diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index e51eeef..f3ca02f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -464,7 +464,7 @@ static void rs_tx_status(void *priv_rate, retries = tx_resp->retry_count; - first_index = tx_resp->control.tx_rate->hw_value; + first_index = sband->bitrates[tx_resp->control.tx_rate_idx].hw_value; if ((first_index < 0) || (first_index >= IWL_RATE_COUNT)) { IWL_DEBUG_RATE("leave: Rate out of bounds: %d\n", first_index); return; @@ -669,7 +669,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, is_multicast_ether_addr(hdr->addr1) || !sta || !sta->rate_ctrl_priv) { IWL_DEBUG_RATE("leave: No STA priv data to update!\n"); - sel->rate = rate_lowest(local, sband, sta); + sel->rate_idx = rate_lowest_index(local, sband, sta); rcu_read_unlock(); return; } @@ -813,7 +813,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, IWL_DEBUG_RATE("leave: %d\n", index); - sel->rate = &sband->bitrates[sta->txrate_idx]; + sel->rate_idx = sta->txrate_idx; } static struct rate_control_ops rs_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index ad4e7b7..f8e691f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -331,7 +331,9 @@ static void iwl3945_rx_reply_tx(struct iwl3945_priv *priv, tx_resp->rate, tx_resp->failure_frame); rate_idx = iwl3945_hwrate_to_plcp_idx(tx_resp->rate); - tx_status->control.tx_rate = &priv->ieee_rates[rate_idx]; + if (tx_status->control.band == IEEE80211_BAND_5GHZ) + rate_idx -= IWL_FIRST_OFDM_RATE; + tx_status->control.tx_rate_idx = rate_idx; IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index); iwl3945_tx_queue_reclaim(priv, txq_id, index); @@ -962,7 +964,8 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl3945_priv *priv, struct ieee80211_hdr *hdr, int sta_id, int tx_id) { unsigned long flags; - u16 rate_index = min(ctrl->tx_rate->hw_value & 0xffff, IWL_RATE_COUNT - 1); + u16 hw_value = ieee80211_get_tx_rate(priv->hw, ctrl)->hw_value; + u16 rate_index = min(hw_value & 0xffff, IWL_RATE_COUNT - 1); u16 rate_mask; int rate; u8 rts_retry_limit; diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index 2adc228..7993a1d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -862,7 +862,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, if (priv->band == IEEE80211_BAND_5GHZ) rs_index -= IWL_FIRST_OFDM_RATE; - if ((tx_resp->control.tx_rate == NULL) || + if ((tx_resp->control.tx_rate_idx < 0) || (tbl_type.is_SGI ^ !!(tx_resp->control.flags & IEEE80211_TXCTL_SHORT_GI)) || (tbl_type.is_fat ^ @@ -875,7 +875,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, (!!(tx_rate & RATE_MCS_GF_MSK) ^ !!(tx_resp->control.flags & IEEE80211_TXCTL_GREEN_FIELD)) || (hw->wiphy->bands[priv->band]->bitrates[rs_index].bitrate != - tx_resp->control.tx_rate->bitrate)) { + hw->wiphy->bands[tx_resp->control.band]->bitrates[tx_resp->control.tx_rate_idx].bitrate)) { IWL_DEBUG_RATE("initial rate does not match 0x%x\n", tx_rate); goto out; } @@ -2154,7 +2154,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, fc = le16_to_cpu(hdr->frame_control); if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) || !sta || !sta->rate_ctrl_priv) { - sel->rate = rate_lowest(local, sband, sta); + sel->rate_idx = rate_lowest_index(local, sband, sta); goto out; } @@ -2184,11 +2184,13 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, done: if ((i < 0) || (i > IWL_RATE_COUNT)) { - sel->rate = rate_lowest(local, sband, sta); + sel->rate_idx = rate_lowest_index(local, sband, sta); goto out; } - sel->rate = &priv->ieee_rates[i]; + if (sband->band == IEEE80211_BAND_5GHZ) + i -= IWL_FIRST_OFDM_RATE; + sel->rate_idx = i; out: rcu_read_unlock(); } diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index f848a5b..fb670b5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -373,14 +373,10 @@ void iwl4965_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, control->flags |= IEEE80211_TXCTL_DUP_DATA; if (rate_n_flags & RATE_MCS_SGI_MSK) control->flags |= IEEE80211_TXCTL_SHORT_GI; - /* since iwl4965_hwrate_to_plcp_idx is band indifferent, we always use - * IEEE80211_BAND_2GHZ band as it contains all the rates */ rate_index = iwl4965_hwrate_to_plcp_idx(rate_n_flags); - if (rate_index == -1) - control->tx_rate = NULL; - else - control->tx_rate = - &priv->bands[IEEE80211_BAND_2GHZ].bitrates[rate_index]; + if (control->band == IEEE80211_BAND_5GHZ) + rate_index -= IWL_FIRST_OFDM_RATE; + control->tx_rate_idx = rate_index; } int iwl4965_hw_rxq_stop(struct iwl_priv *priv) diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index f32cdda..4b5149c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -578,7 +578,10 @@ static void iwl_tx_cmd_build_rate(struct iwl_priv *priv, u8 data_retry_limit = 0; u8 rate_plcp; u16 rate_flags = 0; - int rate_idx = min(ctrl->tx_rate->hw_value & 0xffff, IWL_RATE_COUNT - 1); + int rate_idx; + + rate_idx = min(ieee80211_get_tx_rate(priv->hw, ctrl)->hw_value & 0xffff, + IWL_RATE_COUNT - 1); rate_plcp = iwl_rates[rate_idx].plcp; @@ -723,7 +726,8 @@ int iwl_tx_skb(struct iwl_priv *priv, goto drop_unlock; } - if ((ctl->tx_rate->hw_value & 0xFF) == IWL_INVALID_RATE) { + if ((ieee80211_get_tx_rate(priv->hw, ctl)->hw_value & 0xFF) == + IWL_INVALID_RATE) { IWL_ERROR("ERROR: No TX rate available.\n"); goto drop_unlock; } diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 54cde8a..a28b4c9 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -2581,7 +2581,7 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, goto drop_unlock; } - if ((ctl->tx_rate->hw_value & 0xFF) == IWL_INVALID_RATE) { + if ((ieee80211_get_tx_rate(priv->hw, ctl)->hw_value & 0xFF) == IWL_INVALID_RATE) { IWL_ERROR("ERROR: No TX rate available.\n"); goto drop_unlock; } @@ -6694,7 +6694,7 @@ static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, } IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, - ctl->tx_rate->bitrate); + ieee80211_get_tx_rate(hw, ctl)->bitrate); if (iwl3945_tx_skb(priv, skb, ctl)) dev_kfree_skb_any(skb); diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index db4f606..1fad622 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -4281,7 +4281,7 @@ static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, } IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, - ctl->tx_rate->bitrate); + ieee80211_get_tx_rate(hw, ctl)->bitrate); if (iwl_tx_skb(priv, skb, ctl)) dev_kfree_skb_any(skb); diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 3d35fe6..3ca9386 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -592,7 +592,7 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb, txhdr->padding2 = 0; /* TODO: add support for alternate retry TX rates */ - rate = control->tx_rate->hw_value; + rate = ieee80211_get_tx_rate(dev, control)->hw_value; if (control->flags & IEEE80211_TXCTL_SHORT_PREAMBLE) rate |= 0x10; if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 19c1062..5cf4c2f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -33,8 +33,10 @@ void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, struct txentry_desc *txdesc, struct ieee80211_tx_control *control) { + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data; - struct ieee80211_rate *rate = control->tx_rate; + struct ieee80211_rate *rate = + ieee80211_get_tx_rate(rt2x00dev->hw, control); const struct rt2x00_rate *hwrate; unsigned int data_length; unsigned int duration; @@ -77,8 +79,9 @@ void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, __set_bit(ENTRY_TXD_CTS_FRAME, &txdesc->flags); __clear_bit(ENTRY_TXD_ACK, &txdesc->flags); } - if (control->rts_cts_rate) - rate = control->rts_cts_rate; + if (control->rts_cts_rate_idx >= 0) + rate = + ieee80211_get_rts_cts_rate(rt2x00dev->hw, control); } /* diff --git a/drivers/net/wireless/rtl8180_dev.c b/drivers/net/wireless/rtl8180_dev.c index c220998..6263209b 100644 --- a/drivers/net/wireless/rtl8180_dev.c +++ b/drivers/net/wireless/rtl8180_dev.c @@ -257,24 +257,21 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb, mapping = pci_map_single(priv->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); - BUG_ON(!control->tx_rate); - tx_flags = RTL8180_TX_DESC_FLAG_OWN | RTL8180_TX_DESC_FLAG_FS | RTL8180_TX_DESC_FLAG_LS | - (control->tx_rate->hw_value << 24) | skb->len; + (ieee80211_get_tx_rate(dev, control)->hw_value << 24) | + skb->len; if (priv->r8185) tx_flags |= RTL8180_TX_DESC_FLAG_DMA | RTL8180_TX_DESC_FLAG_NO_ENC; if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) { - BUG_ON(!control->rts_cts_rate); tx_flags |= RTL8180_TX_DESC_FLAG_RTS; - tx_flags |= control->rts_cts_rate->hw_value << 19; + tx_flags |= ieee80211_get_rts_cts_rate(dev, control)->hw_value << 19; } else if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { - BUG_ON(!control->rts_cts_rate); tx_flags |= RTL8180_TX_DESC_FLAG_CTS; - tx_flags |= control->rts_cts_rate->hw_value << 19; + tx_flags |= ieee80211_get_rts_cts_rate(dev, control)->hw_value << 19; } *((struct ieee80211_tx_control **) skb->cb) = @@ -288,9 +285,9 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb, unsigned int remainder; plcp_len = DIV_ROUND_UP(16 * (skb->len + 4), - (control->tx_rate->bitrate * 2) / 10); + (ieee80211_get_tx_rate(dev, control)->bitrate * 2) / 10); remainder = (16 * (skb->len + 4)) % - ((control->tx_rate->bitrate * 2) / 10); + ((ieee80211_get_tx_rate(dev, control)->bitrate * 2) / 10); if (remainder > 0 && remainder <= 6) plcp_len |= 1 << 15; } @@ -303,8 +300,8 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb, entry->plcp_len = cpu_to_le16(plcp_len); entry->tx_buf = cpu_to_le32(mapping); entry->frame_len = cpu_to_le32(skb->len); - entry->flags2 = control->alt_retry_rate != NULL ? - control->alt_retry_rate->bitrate << 4 : 0; + entry->flags2 = control->alt_retry_rate_idx >= 0 ? + ieee80211_get_alt_retry_rate(dev, control)->bitrate << 4 : 0; entry->retry_limit = control->retry_limit; entry->flags = cpu_to_le32(tx_flags); __skb_queue_tail(&ring->queue, skb); diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index e14c842..86a09b4 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -179,21 +179,17 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb, flags = skb->len; flags |= RTL8187_TX_FLAG_NO_ENCRYPT; - BUG_ON(!control->tx_rate); - - flags |= control->tx_rate->hw_value << 24; + flags |= ieee80211_get_tx_rate(dev, control)->hw_value << 24; if (ieee80211_get_morefrag((struct ieee80211_hdr *)skb->data)) flags |= RTL8187_TX_FLAG_MORE_FRAG; if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) { - BUG_ON(!control->rts_cts_rate); flags |= RTL8187_TX_FLAG_RTS; - flags |= control->rts_cts_rate->hw_value << 19; + flags |= ieee80211_get_rts_cts_rate(dev, control)->hw_value << 19; rts_dur = ieee80211_rts_duration(dev, priv->vif, skb->len, control); } else if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { - BUG_ON(!control->rts_cts_rate); flags |= RTL8187_TX_FLAG_CTS; - flags |= control->rts_cts_rate->hw_value << 19; + flags |= ieee80211_get_rts_cts_rate(dev, control)->hw_value << 19; } hdr = (struct rtl8187_tx_hdr *)skb_push(skb, sizeof(*hdr)); diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 0c73673..99c508c 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -523,14 +523,17 @@ static int fill_ctrlset(struct zd_mac *mac, struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; unsigned int frag_len = skb->len + FCS_LEN; unsigned int packet_length; + struct ieee80211_rate *txrate; struct zd_ctrlset *cs = (struct zd_ctrlset *) skb_push(skb, sizeof(struct zd_ctrlset)); ZD_ASSERT(frag_len <= 0xffff); - cs->modulation = control->tx_rate->hw_value; + txrate = ieee80211_get_tx_rate(mac->hw, control); + + cs->modulation = txrate->hw_value; if (control->flags & IEEE80211_TXCTL_SHORT_PREAMBLE) - cs->modulation = control->tx_rate->hw_value_short; + cs->modulation = txrate->hw_value_short; cs->tx_length = cpu_to_le16(frag_len); diff --git a/include/net/mac80211.h b/include/net/mac80211.h index f00fc76..0df91be 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -266,27 +266,26 @@ enum mac80211_tx_control_flags { * ieee80211_ops->remove_interface() callback funtion. * The hw_key pointer is valid until it has been removed with the * ieee80211_ops->set_key() callback function. - * The tx_rate and alt_retry_rate pointers are valid until the phy is - * deregistered. */ struct ieee80211_tx_control { - struct ieee80211_vif *vif; - struct ieee80211_rate *tx_rate; + u32 flags; /* tx control flags defined above */ + + s8 tx_rate_idx, /* Transmit rate (indexes registered rates) */ + rts_cts_rate_idx, /* Transmit rate for RTS/CTS frame */ + alt_retry_rate_idx; /* retry rate for the last retries */ - /* Transmit rate for RTS/CTS frame */ - struct ieee80211_rate *rts_cts_rate; + s8 retry_limit; /* 1 = only first attempt, 2 = one retry, .. + * This could be used when set_retry_limit + * is not implemented by the driver */ - /* retry rate for the last retries */ - struct ieee80211_rate *alt_retry_rate; + struct ieee80211_vif *vif; /* Key used for hardware encryption * NULL if IEEE80211_TXCTL_DO_NOT_ENCRYPT is set */ struct ieee80211_key_conf *hw_key; - u32 flags; /* tx control flags defined above */ - u8 retry_limit; /* 1 = only first attempt, 2 = one retry, .. - * This could be used when set_retry_limit - * is not implemented by the driver */ + enum ieee80211_band band; + u8 antenna_sel_tx; /* 0 = default/diversity, otherwise bit * position represents antenna number used */ u8 icv_len; /* length of the ICV/MIC field in octets */ @@ -298,6 +297,7 @@ struct ieee80211_tx_control { }; + /** * enum mac80211_rx_flags - receive flags * @@ -823,6 +823,33 @@ static inline void SET_IEEE80211_PERM_ADDR(struct ieee80211_hw *hw, u8 *addr) memcpy(hw->wiphy->perm_addr, addr, ETH_ALEN); } +static inline struct ieee80211_rate * +ieee80211_get_tx_rate(const struct ieee80211_hw *hw, + const struct ieee80211_tx_control *c) +{ + if (WARN_ON(c->tx_rate_idx < 0)) + return NULL; + return &hw->wiphy->bands[c->band]->bitrates[c->tx_rate_idx]; +} + +static inline struct ieee80211_rate * +ieee80211_get_rts_cts_rate(const struct ieee80211_hw *hw, + const struct ieee80211_tx_control *c) +{ + if (c->rts_cts_rate_idx < 0) + return NULL; + return &hw->wiphy->bands[c->band]->bitrates[c->rts_cts_rate_idx]; +} + +static inline struct ieee80211_rate * +ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw, + const struct ieee80211_tx_control *c) +{ + if (c->alt_retry_rate_idx < 0) + return NULL; + return &hw->wiphy->bands[c->band]->bitrates[c->alt_retry_rate_idx]; +} + /** * DOC: Hardware crypto acceleration * diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index ed0d9b3..a4cccd1 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -159,11 +159,11 @@ struct ieee80211_tx_data { struct ieee80211_tx_control *control; struct ieee80211_channel *channel; - struct ieee80211_rate *rate; + s8 rate_idx; /* use this rate (if set) for last fragment; rate can * be set to lower rate for the first fragments, e.g., * when using CTS protection with IEEE 802.11g. */ - struct ieee80211_rate *last_frag_rate; + s8 last_frag_rate_idx; /* Extra fragments (in addition to the first fragment * in skb) */ @@ -225,9 +225,9 @@ struct ieee80211_tx_stored_packet { struct ieee80211_tx_control control; struct sk_buff *skb; struct sk_buff **extra_frag; - struct ieee80211_rate *last_frag_rate; + s8 last_frag_rate_idx; int num_extra_frag; - unsigned int last_frag_rate_ctrl_probe; + bool last_frag_rate_ctrl_probe; }; struct beacon_data { diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 7877d3b..6041493 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2406,15 +2406,15 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, memset(&control, 0, sizeof(control)); rate_control_get_rate(dev, sband, skb, &ratesel); - if (!ratesel.rate) { + if (ratesel.rate_idx < 0) { printk(KERN_DEBUG "%s: Failed to determine TX rate " "for IBSS beacon\n", dev->name); break; } control.vif = &sdata->vif; - control.tx_rate = ratesel.rate; + control.tx_rate_idx = ratesel.rate_idx; if (sdata->bss_conf.use_short_preamble && - ratesel.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) + sband->bitrates[ratesel.rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE) control.flags |= IEEE80211_TXCTL_SHORT_PREAMBLE; control.antenna_sel_tx = local->hw.conf.antenna_sel_tx; control.flags |= IEEE80211_TXCTL_NO_ACK; diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 841df93..0388c09 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -176,20 +176,24 @@ void rate_control_get_rate(struct net_device *dev, rcu_read_lock(); sta = sta_info_get(local, hdr->addr1); - memset(sel, 0, sizeof(struct rate_selection)); + sel->rate_idx = -1; + sel->nonerp_idx = -1; + sel->probe_idx = -1; ref->ops->get_rate(ref->priv, dev, sband, skb, sel); + BUG_ON(sel->rate_idx < 0); + /* Select a non-ERP backup rate. */ - if (!sel->nonerp) { + if (sel->nonerp_idx < 0) { for (i = 0; i < sband->n_bitrates; i++) { struct ieee80211_rate *rate = &sband->bitrates[i]; - if (sel->rate->bitrate < rate->bitrate) + if (sband->bitrates[sel->rate_idx].bitrate < rate->bitrate) break; if (rate_supported(sta, sband->band, i) && !(rate->flags & IEEE80211_RATE_ERP_G)) - sel->nonerp = rate; + sel->nonerp_idx = i; } } diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index 5b45f33..a29148d 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h @@ -19,14 +19,15 @@ #include "ieee80211_i.h" #include "sta_info.h" -/* TODO: kdoc */ +/** + * struct rate_selection - rate selection for rate control algos + * @rate: selected transmission rate index + * @nonerp: Non-ERP rate to use instead if ERP cannot be used + * @probe: rate for probing (or -1) + * + */ struct rate_selection { - /* Selected transmission rate */ - struct ieee80211_rate *rate; - /* Non-ERP rate to use if mac80211 decides it cannot use an ERP rate */ - struct ieee80211_rate *nonerp; - /* probe with this rate, or NULL for no probing */ - struct ieee80211_rate *probe; + s8 rate_idx, nonerp_idx, probe_idx; }; struct rate_control_ops { @@ -138,7 +139,7 @@ static inline int rate_supported(struct sta_info *sta, return (sta == NULL || sta->supp_rates[band] & BIT(index)); } -static inline int +static inline s8 rate_lowest_index(struct ieee80211_local *local, struct ieee80211_supported_band *sband, struct sta_info *sta) @@ -155,14 +156,6 @@ rate_lowest_index(struct ieee80211_local *local, return 0; } -static inline struct ieee80211_rate * -rate_lowest(struct ieee80211_local *local, - struct ieee80211_supported_band *sband, - struct sta_info *sta) -{ - return &sband->bitrates[rate_lowest_index(local, sband, sta)]; -} - /* functions for rate control related to a device */ int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c index a849b74..14cde36 100644 --- a/net/mac80211/rc80211_pid_algo.c +++ b/net/mac80211/rc80211_pid_algo.c @@ -266,7 +266,7 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev, /* Ignore all frames that were sent with a different rate than the rate * we currently advise mac80211 to use. */ - if (status->control.tx_rate != &sband->bitrates[sta->txrate_idx]) + if (status->control.tx_rate_idx != sta->txrate_idx) goto unlock; spinfo = sta->rate_ctrl_priv; @@ -330,7 +330,7 @@ static void rate_control_pid_get_rate(void *priv, struct net_device *dev, fc = le16_to_cpu(hdr->frame_control); if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || is_multicast_ether_addr(hdr->addr1) || !sta) { - sel->rate = rate_lowest(local, sband, sta); + sel->rate_idx = rate_lowest_index(local, sband, sta); rcu_read_unlock(); return; } @@ -349,7 +349,7 @@ static void rate_control_pid_get_rate(void *priv, struct net_device *dev, rcu_read_unlock(); - sel->rate = &sband->bitrates[rateidx]; + sel->rate_idx = rateidx; #ifdef CONFIG_MAC80211_DEBUGFS rate_control_pid_event_tx_rate( diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index aecec2a..99c3860 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -91,11 +91,12 @@ static u16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr, int next_frag_len) { int rate, mrate, erp, dur, i; - struct ieee80211_rate *txrate = tx->rate; + struct ieee80211_rate *txrate; struct ieee80211_local *local = tx->local; struct ieee80211_supported_band *sband; - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + sband = local->hw.wiphy->bands[tx->channel->band]; + txrate = &sband->bitrates[tx->rate_idx]; erp = 0; if (tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) @@ -610,40 +611,40 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) struct rate_selection rsel; struct ieee80211_supported_band *sband; - sband = tx->local->hw.wiphy->bands[tx->local->hw.conf.channel->band]; + sband = tx->local->hw.wiphy->bands[tx->channel->band]; - if (likely(!tx->rate)) { + if (likely(tx->rate_idx < 0)) { rate_control_get_rate(tx->dev, sband, tx->skb, &rsel); - tx->rate = rsel.rate; - if (unlikely(rsel.probe)) { + tx->rate_idx = rsel.rate_idx; + if (unlikely(rsel.probe_idx >= 0)) { tx->control->flags |= IEEE80211_TXCTL_RATE_CTRL_PROBE; tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG; - tx->control->alt_retry_rate = tx->rate; - tx->rate = rsel.probe; + tx->control->alt_retry_rate_idx = tx->rate_idx; + tx->rate_idx = rsel.probe_idx; } else - tx->control->alt_retry_rate = NULL; + tx->control->alt_retry_rate_idx = -1; - if (!tx->rate) + if (unlikely(tx->rate_idx < 0)) return TX_DROP; } else - tx->control->alt_retry_rate = NULL; + tx->control->alt_retry_rate_idx = -1; if (tx->sdata->bss_conf.use_cts_prot && - (tx->flags & IEEE80211_TX_FRAGMENTED) && rsel.nonerp) { - tx->last_frag_rate = tx->rate; - if (rsel.probe) + (tx->flags & IEEE80211_TX_FRAGMENTED) && (rsel.nonerp_idx >= 0)) { + tx->last_frag_rate_idx = tx->rate_idx; + if (rsel.probe_idx >= 0) tx->flags &= ~IEEE80211_TX_PROBE_LAST_FRAG; else tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG; - tx->rate = rsel.nonerp; - tx->control->tx_rate = rsel.nonerp; + tx->rate_idx = rsel.nonerp_idx; + tx->control->tx_rate_idx = rsel.nonerp_idx; tx->control->flags &= ~IEEE80211_TXCTL_RATE_CTRL_PROBE; } else { - tx->last_frag_rate = tx->rate; - tx->control->tx_rate = tx->rate; + tx->last_frag_rate_idx = tx->rate_idx; + tx->control->tx_rate_idx = tx->rate_idx; } - tx->control->tx_rate = tx->rate; + tx->control->tx_rate_idx = tx->rate_idx; return TX_CONTINUE; } @@ -655,6 +656,9 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) u16 fc = le16_to_cpu(hdr->frame_control); u16 dur; struct ieee80211_tx_control *control = tx->control; + struct ieee80211_supported_band *sband; + + sband = tx->local->hw.wiphy->bands[tx->channel->band]; if (!control->retry_limit) { if (!is_multicast_ether_addr(hdr->addr1)) { @@ -681,14 +685,14 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) * frames. * TODO: The last fragment could still use multiple retry * rates. */ - control->alt_retry_rate = NULL; + control->alt_retry_rate_idx = -1; } /* Use CTS protection for unicast frames sent using extended rates if * there are associated non-ERP stations and RTS/CTS is not configured * for the frame. */ if ((tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) && - (tx->rate->flags & IEEE80211_RATE_ERP_G) && + (sband->bitrates[tx->rate_idx].flags & IEEE80211_RATE_ERP_G) && (tx->flags & IEEE80211_TX_UNICAST) && tx->sdata->bss_conf.use_cts_prot && !(control->flags & IEEE80211_TXCTL_USE_RTS_CTS)) @@ -698,7 +702,7 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) * short preambles at the selected rate and short preambles are * available on the network at the current point in time. */ if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && - (tx->rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) && + (sband->bitrates[tx->rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE) && tx->sdata->bss_conf.use_short_preamble && (!tx->sta || test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE))) { tx->control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE; @@ -715,32 +719,32 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) if ((control->flags & IEEE80211_TXCTL_USE_RTS_CTS) || (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) { struct ieee80211_supported_band *sband; - struct ieee80211_rate *rate, *baserate; + struct ieee80211_rate *rate; + s8 baserate = -1; int idx; - sband = tx->local->hw.wiphy->bands[ - tx->local->hw.conf.channel->band]; + sband = tx->local->hw.wiphy->bands[tx->channel->band]; /* Do not use multiple retry rates when using RTS/CTS */ - control->alt_retry_rate = NULL; + control->alt_retry_rate_idx = -1; /* Use min(data rate, max base rate) as CTS/RTS rate */ - rate = tx->rate; - baserate = NULL; + rate = &sband->bitrates[tx->rate_idx]; for (idx = 0; idx < sband->n_bitrates; idx++) { if (sband->bitrates[idx].bitrate > rate->bitrate) continue; if (tx->sdata->basic_rates & BIT(idx) && - (!baserate || - (baserate->bitrate < sband->bitrates[idx].bitrate))) - baserate = &sband->bitrates[idx]; + (baserate < 0 || + (sband->bitrates[baserate].bitrate + < sband->bitrates[idx].bitrate))) + baserate = idx; } - if (baserate) - control->rts_cts_rate = baserate; + if (baserate >= 0) + control->rts_cts_rate_idx = baserate; else - control->rts_cts_rate = &sband->bitrates[0]; + control->rts_cts_rate_idx = 0; } if (tx->sta) { @@ -768,7 +772,11 @@ ieee80211_tx_h_load_stats(struct ieee80211_tx_data *tx) struct sk_buff *skb = tx->skb; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; u32 load = 0, hdrtime; - struct ieee80211_rate *rate = tx->rate; + struct ieee80211_rate *rate; + struct ieee80211_supported_band *sband; + + sband = tx->local->hw.wiphy->bands[tx->channel->band]; + rate = &sband->bitrates[tx->rate_idx]; /* TODO: this could be part of tx_status handling, so that the number * of retries would be known; TX rate should in that case be stored @@ -803,7 +811,7 @@ ieee80211_tx_h_load_stats(struct ieee80211_tx_data *tx) for (i = 0; i < tx->num_extra_frag; i++) { load += 2 * hdrtime; load += tx->extra_frag[i]->len * - tx->rate->bitrate; + rate->bitrate; } } @@ -859,7 +867,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len); struct ieee80211_tx_control *control = tx->control; - sband = tx->local->hw.wiphy->bands[tx->local->hw.conf.channel->band]; + sband = tx->local->hw.wiphy->bands[tx->channel->band]; control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; tx->flags |= IEEE80211_TX_INJECTED; @@ -899,7 +907,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, r = &sband->bitrates[i]; if (r->bitrate == target_rate) { - tx->rate = r; + tx->rate_idx = i; break; } } @@ -1097,7 +1105,7 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, if (__ieee80211_queue_stopped(local, control->queue)) return IEEE80211_TX_FRAG_AGAIN; if (i == tx->num_extra_frag) { - control->tx_rate = tx->last_frag_rate; + control->tx_rate_idx = tx->last_frag_rate_idx; if (tx->flags & IEEE80211_TX_PROBE_LAST_FRAG) control->flags |= @@ -1155,6 +1163,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, sta = tx.sta; tx.channel = local->hw.conf.channel; + control->band = tx.channel->band; for (handler = ieee80211_tx_handlers; *handler != NULL; handler++) { @@ -1187,7 +1196,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, next_len = tx.extra_frag[i + 1]->len; } else { next_len = 0; - tx.rate = tx.last_frag_rate; + tx.rate_idx = tx.last_frag_rate_idx; } dur = ieee80211_duration(&tx, 0, next_len); hdr->duration_id = cpu_to_le16(dur); @@ -1224,7 +1233,7 @@ retry: store->skb = skb; store->extra_frag = tx.extra_frag; store->num_extra_frag = tx.num_extra_frag; - store->last_frag_rate = tx.last_frag_rate; + store->last_frag_rate_idx = tx.last_frag_rate_idx; store->last_frag_rate_ctrl_probe = !!(tx.flags & IEEE80211_TX_PROBE_LAST_FRAG); } @@ -1685,7 +1694,7 @@ void ieee80211_tx_pending(unsigned long data) tx.control = &store->control; tx.extra_frag = store->extra_frag; tx.num_extra_frag = store->num_extra_frag; - tx.last_frag_rate = store->last_frag_rate; + tx.last_frag_rate_idx = store->last_frag_rate_idx; tx.flags = 0; if (store->last_frag_rate_ctrl_probe) tx.flags |= IEEE80211_TX_PROBE_LAST_FRAG; @@ -1789,9 +1798,10 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, struct ieee80211_mgmt *mgmt; int *num_beacons; bool err = true; + enum ieee80211_band band = local->hw.conf.channel->band; u8 *pos; - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + sband = local->hw.wiphy->bands[band]; rcu_read_lock(); @@ -1885,8 +1895,9 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, } if (control) { + control->band = band; rate_control_get_rate(local->mdev, sband, skb, &rsel); - if (!rsel.rate) { + if (unlikely(rsel.rate_idx < 0)) { if (net_ratelimit()) { printk(KERN_DEBUG "%s: ieee80211_beacon_get: " "no rate found\n", @@ -1898,9 +1909,9 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, } control->vif = vif; - control->tx_rate = rsel.rate; + control->tx_rate_idx = rsel.rate_idx; if (sdata->bss_conf.use_short_preamble && - rsel.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) + sband->bitrates[rsel.rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE) control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE; control->antenna_sel_tx = local->hw.conf.antenna_sel_tx; control->flags |= IEEE80211_TXCTL_NO_ACK; @@ -2006,6 +2017,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, sta = tx.sta; tx.flags |= IEEE80211_TX_PS_BUFFERED; tx.channel = local->hw.conf.channel; + control->band = tx.channel->band; for (handler = ieee80211_tx_handlers; *handler != NULL; handler++) { res = (*handler)(&tx); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 800c15a..65a34fd 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -266,10 +266,13 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, bool short_preamble; int erp; u16 dur; + struct ieee80211_supported_band *sband; + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; short_preamble = sdata->bss_conf.use_short_preamble; - rate = frame_txctl->rts_cts_rate; + rate = &sband->bitrates[frame_txctl->rts_cts_rate_idx]; erp = 0; if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) @@ -300,10 +303,13 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, bool short_preamble; int erp; u16 dur; + struct ieee80211_supported_band *sband; + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; short_preamble = sdata->bss_conf.use_short_preamble; - rate = frame_txctl->rts_cts_rate; + rate = &sband->bitrates[frame_txctl->rts_cts_rate_idx]; erp = 0; if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) erp = rate->flags & IEEE80211_RATE_ERP_G; -- cgit v0.10.2 From e24549485f859be6518929bb1c9c0257d79f033d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 15 May 2008 12:55:28 +0200 Subject: mac80211: reorder some transmit handlers The next patch will require that transmit handlers that are after fragmentation are aware of the fact that the control info is also fragmented. To make that easier, this patch moves a number of transmit handlers before fragmentation. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 99c3860..666158f 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -506,106 +506,6 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) } static ieee80211_tx_result -ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; - size_t hdrlen, per_fragm, num_fragm, payload_len, left; - struct sk_buff **frags, *first, *frag; - int i; - u16 seq; - u8 *pos; - int frag_threshold = tx->local->fragmentation_threshold; - - if (!(tx->flags & IEEE80211_TX_FRAGMENTED)) - return TX_CONTINUE; - - first = tx->skb; - - hdrlen = ieee80211_get_hdrlen(tx->fc); - payload_len = first->len - hdrlen; - per_fragm = frag_threshold - hdrlen - FCS_LEN; - num_fragm = DIV_ROUND_UP(payload_len, per_fragm); - - frags = kzalloc(num_fragm * sizeof(struct sk_buff *), GFP_ATOMIC); - if (!frags) - goto fail; - - hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREFRAGS); - seq = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ; - pos = first->data + hdrlen + per_fragm; - left = payload_len - per_fragm; - for (i = 0; i < num_fragm - 1; i++) { - struct ieee80211_hdr *fhdr; - size_t copylen; - - if (left <= 0) - goto fail; - - /* reserve enough extra head and tail room for possible - * encryption */ - frag = frags[i] = - dev_alloc_skb(tx->local->tx_headroom + - frag_threshold + - IEEE80211_ENCRYPT_HEADROOM + - IEEE80211_ENCRYPT_TAILROOM); - if (!frag) - goto fail; - /* Make sure that all fragments use the same priority so - * that they end up using the same TX queue */ - frag->priority = first->priority; - skb_reserve(frag, tx->local->tx_headroom + - IEEE80211_ENCRYPT_HEADROOM); - fhdr = (struct ieee80211_hdr *) skb_put(frag, hdrlen); - memcpy(fhdr, first->data, hdrlen); - if (i == num_fragm - 2) - fhdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREFRAGS); - fhdr->seq_ctrl = cpu_to_le16(seq | ((i + 1) & IEEE80211_SCTL_FRAG)); - copylen = left > per_fragm ? per_fragm : left; - memcpy(skb_put(frag, copylen), pos, copylen); - - pos += copylen; - left -= copylen; - } - skb_trim(first, hdrlen + per_fragm); - - tx->num_extra_frag = num_fragm - 1; - tx->extra_frag = frags; - - return TX_CONTINUE; - - fail: - printk(KERN_DEBUG "%s: failed to fragment frame\n", tx->dev->name); - if (frags) { - for (i = 0; i < num_fragm - 1; i++) - if (frags[i]) - dev_kfree_skb(frags[i]); - kfree(frags); - } - I802_DEBUG_INC(tx->local->tx_handlers_drop_fragment); - return TX_DROP; -} - -static ieee80211_tx_result -ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx) -{ - if (!tx->key) - return TX_CONTINUE; - - switch (tx->key->conf.alg) { - case ALG_WEP: - return ieee80211_crypto_wep_encrypt(tx); - case ALG_TKIP: - return ieee80211_crypto_tkip_encrypt(tx); - case ALG_CCMP: - return ieee80211_crypto_ccmp_encrypt(tx); - } - - /* not reached */ - WARN_ON(1); - return TX_DROP; -} - -static ieee80211_tx_result ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) { struct rate_selection rsel; @@ -747,26 +647,114 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) control->rts_cts_rate_idx = 0; } - if (tx->sta) { + if (tx->sta) control->aid = tx->sta->aid; - tx->sta->tx_packets++; - tx->sta->tx_fragments++; - tx->sta->tx_bytes += tx->skb->len; - if (tx->extra_frag) { - int i; - tx->sta->tx_fragments += tx->num_extra_frag; - for (i = 0; i < tx->num_extra_frag; i++) { - tx->sta->tx_bytes += - tx->extra_frag[i]->len; - } - } + + return TX_CONTINUE; +} + +static ieee80211_tx_result +ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; + size_t hdrlen, per_fragm, num_fragm, payload_len, left; + struct sk_buff **frags, *first, *frag; + int i; + u16 seq; + u8 *pos; + int frag_threshold = tx->local->fragmentation_threshold; + + if (!(tx->flags & IEEE80211_TX_FRAGMENTED)) + return TX_CONTINUE; + + first = tx->skb; + + hdrlen = ieee80211_get_hdrlen(tx->fc); + payload_len = first->len - hdrlen; + per_fragm = frag_threshold - hdrlen - FCS_LEN; + num_fragm = DIV_ROUND_UP(payload_len, per_fragm); + + frags = kzalloc(num_fragm * sizeof(struct sk_buff *), GFP_ATOMIC); + if (!frags) + goto fail; + + hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREFRAGS); + seq = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ; + pos = first->data + hdrlen + per_fragm; + left = payload_len - per_fragm; + for (i = 0; i < num_fragm - 1; i++) { + struct ieee80211_hdr *fhdr; + size_t copylen; + + if (left <= 0) + goto fail; + + /* reserve enough extra head and tail room for possible + * encryption */ + frag = frags[i] = + dev_alloc_skb(tx->local->tx_headroom + + frag_threshold + + IEEE80211_ENCRYPT_HEADROOM + + IEEE80211_ENCRYPT_TAILROOM); + if (!frag) + goto fail; + /* Make sure that all fragments use the same priority so + * that they end up using the same TX queue */ + frag->priority = first->priority; + skb_reserve(frag, tx->local->tx_headroom + + IEEE80211_ENCRYPT_HEADROOM); + fhdr = (struct ieee80211_hdr *) skb_put(frag, hdrlen); + memcpy(fhdr, first->data, hdrlen); + if (i == num_fragm - 2) + fhdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREFRAGS); + fhdr->seq_ctrl = cpu_to_le16(seq | ((i + 1) & IEEE80211_SCTL_FRAG)); + copylen = left > per_fragm ? per_fragm : left; + memcpy(skb_put(frag, copylen), pos, copylen); + + pos += copylen; + left -= copylen; } + skb_trim(first, hdrlen + per_fragm); + + tx->num_extra_frag = num_fragm - 1; + tx->extra_frag = frags; return TX_CONTINUE; + + fail: + printk(KERN_DEBUG "%s: failed to fragment frame\n", tx->dev->name); + if (frags) { + for (i = 0; i < num_fragm - 1; i++) + if (frags[i]) + dev_kfree_skb(frags[i]); + kfree(frags); + } + I802_DEBUG_INC(tx->local->tx_handlers_drop_fragment); + return TX_DROP; } static ieee80211_tx_result -ieee80211_tx_h_load_stats(struct ieee80211_tx_data *tx) +ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx) +{ + if (!tx->key) + return TX_CONTINUE; + + switch (tx->key->conf.alg) { + case ALG_WEP: + return ieee80211_crypto_wep_encrypt(tx); + case ALG_TKIP: + return ieee80211_crypto_tkip_encrypt(tx); + case ALG_CCMP: + return ieee80211_crypto_ccmp_encrypt(tx); + } + + /* not reached */ + WARN_ON(1); + return TX_DROP; +} + +static ieee80211_tx_result +ieee80211_tx_h_stats(struct ieee80211_tx_data *tx) { struct ieee80211_local *local = tx->local; struct sk_buff *skb = tx->skb; @@ -822,6 +810,20 @@ ieee80211_tx_h_load_stats(struct ieee80211_tx_data *tx) tx->sta->channel_use_raw += load; tx->sdata->channel_use_raw += load; + if (tx->sta) { + tx->sta->tx_packets++; + tx->sta->tx_fragments++; + tx->sta->tx_bytes += tx->skb->len; + if (tx->extra_frag) { + int i; + tx->sta->tx_fragments += tx->num_extra_frag; + for (i = 0; i < tx->num_extra_frag; i++) { + tx->sta->tx_bytes += + tx->extra_frag[i]->len; + } + } + } + return TX_CONTINUE; } @@ -834,11 +836,11 @@ static ieee80211_tx_handler ieee80211_tx_handlers[] = ieee80211_tx_h_ps_buf, ieee80211_tx_h_select_key, ieee80211_tx_h_michael_mic_add, - ieee80211_tx_h_fragment, - ieee80211_tx_h_encrypt, ieee80211_tx_h_rate_ctrl, ieee80211_tx_h_misc, - ieee80211_tx_h_load_stats, + ieee80211_tx_h_fragment, + ieee80211_tx_h_encrypt, + ieee80211_tx_h_stats, NULL }; -- cgit v0.10.2 From e039fa4a4195ac4ee895e6f3d1334beed63256fe Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 15 May 2008 12:55:29 +0200 Subject: mac80211: move TX info into skb->cb This patch converts mac80211 and all drivers to have transmit information and status in skb->cb rather than allocating extra memory for it and copying all the data around. To make it fit, a union is used where only data that is necessary for all steps is kept outside of the union. A number of fixes were done by Ivo, as well as the rt2x00 part of this patch. Signed-off-by: Ivo van Doorn Signed-off-by: Johannes Berg Acked-by: David S. Miller Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index 22db664..0ba55ba 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -324,7 +324,7 @@ static void adm8211_interrupt_tci(struct ieee80211_hw *dev) for (dirty_tx = priv->dirty_tx; priv->cur_tx - dirty_tx; dirty_tx++) { unsigned int entry = dirty_tx % priv->tx_ring_size; u32 status = le32_to_cpu(priv->tx_ring[entry].status); - struct ieee80211_tx_status tx_status; + struct ieee80211_tx_info *txi; struct adm8211_tx_ring_info *info; struct sk_buff *skb; @@ -334,24 +334,23 @@ static void adm8211_interrupt_tci(struct ieee80211_hw *dev) info = &priv->tx_buffers[entry]; skb = info->skb; + txi = IEEE80211_SKB_CB(skb); /* TODO: check TDES0_STATUS_TUF and TDES0_STATUS_TRO */ pci_unmap_single(priv->pdev, info->mapping, info->skb->len, PCI_DMA_TODEVICE); - memset(&tx_status, 0, sizeof(tx_status)); + memset(&txi->status, 0, sizeof(txi->status)); skb_pull(skb, sizeof(struct adm8211_tx_hdr)); memcpy(skb_push(skb, info->hdrlen), skb->cb, info->hdrlen); - memcpy(&tx_status.control, &info->tx_control, - sizeof(tx_status.control)); - if (!(tx_status.control.flags & IEEE80211_TXCTL_NO_ACK)) { + if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK)) { if (status & TDES0_STATUS_ES) - tx_status.excessive_retries = 1; + txi->status.excessive_retries = 1; else - tx_status.flags |= IEEE80211_TX_STATUS_ACK; + txi->flags |= IEEE80211_TX_STAT_ACK; } - ieee80211_tx_status_irqsafe(dev, skb, &tx_status); + ieee80211_tx_status_irqsafe(dev, skb); info->skb = NULL; } @@ -1638,7 +1637,6 @@ static void adm8211_calc_durations(int *dur, int *plcp, size_t payload_len, int /* Transmit skb w/adm8211_tx_hdr (802.11 header created by hardware) */ static void adm8211_tx_raw(struct ieee80211_hw *dev, struct sk_buff *skb, u16 plcp_signal, - struct ieee80211_tx_control *control, size_t hdrlen) { struct adm8211_priv *priv = dev->priv; @@ -1664,7 +1662,6 @@ static void adm8211_tx_raw(struct ieee80211_hw *dev, struct sk_buff *skb, priv->tx_buffers[entry].skb = skb; priv->tx_buffers[entry].mapping = mapping; - memcpy(&priv->tx_buffers[entry].tx_control, control, sizeof(*control)); priv->tx_buffers[entry].hdrlen = hdrlen; priv->tx_ring[entry].buffer1 = cpu_to_le32(mapping); @@ -1685,17 +1682,17 @@ static void adm8211_tx_raw(struct ieee80211_hw *dev, struct sk_buff *skb, } /* Put adm8211_tx_hdr on skb and transmit */ -static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb, - struct ieee80211_tx_control *control) +static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb) { struct adm8211_tx_hdr *txhdr; u16 fc; size_t payload_len, hdrlen; int plcp, dur, len, plcp_signal, short_preamble; struct ieee80211_hdr *hdr; - struct ieee80211_rate *txrate = ieee80211_get_tx_rate(dev, control); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_rate *txrate = ieee80211_get_tx_rate(dev, info); - short_preamble = !!(txrate->flags & IEEE80211_TXCTL_SHORT_PREAMBLE); + short_preamble = !!(txrate->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE); plcp_signal = txrate->bitrate; hdr = (struct ieee80211_hdr *)skb->data; @@ -1730,15 +1727,15 @@ static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb, if (short_preamble) txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_SHORT_PREAMBLE); - if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) + if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_RTS); if (fc & IEEE80211_FCTL_PROTECTED) txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_WEP_ENGINE); - txhdr->retry_limit = control->retry_limit; + txhdr->retry_limit = info->control.retry_limit; - adm8211_tx_raw(dev, skb, plcp_signal, control, hdrlen); + adm8211_tx_raw(dev, skb, plcp_signal, hdrlen); return NETDEV_TX_OK; } diff --git a/drivers/net/wireless/adm8211.h b/drivers/net/wireless/adm8211.h index 8d7c564..9b190ee 100644 --- a/drivers/net/wireless/adm8211.h +++ b/drivers/net/wireless/adm8211.h @@ -443,7 +443,6 @@ struct adm8211_rx_ring_info { struct adm8211_tx_ring_info { struct sk_buff *skb; dma_addr_t mapping; - struct ieee80211_tx_control tx_control; size_t hdrlen; }; diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 32ee351..7d97934 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -167,8 +167,7 @@ static struct pci_driver ath5k_pci_driver = { /* * Prototypes - MAC 802.11 stack related functions */ -static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *ctl); +static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb); static int ath5k_reset(struct ieee80211_hw *hw); static int ath5k_start(struct ieee80211_hw *hw); static void ath5k_stop(struct ieee80211_hw *hw); @@ -196,8 +195,7 @@ static int ath5k_get_tx_stats(struct ieee80211_hw *hw, static u64 ath5k_get_tsf(struct ieee80211_hw *hw); static void ath5k_reset_tsf(struct ieee80211_hw *hw); static int ath5k_beacon_update(struct ieee80211_hw *hw, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl); + struct sk_buff *skb); static struct ieee80211_ops ath5k_hw_ops = { .tx = ath5k_tx, @@ -251,9 +249,7 @@ static void ath5k_desc_free(struct ath5k_softc *sc, static int ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf); static int ath5k_txbuf_setup(struct ath5k_softc *sc, - struct ath5k_buf *bf, - struct ieee80211_tx_control *ctl); - + struct ath5k_buf *bf); static inline void ath5k_txbuf_free(struct ath5k_softc *sc, struct ath5k_buf *bf) { @@ -289,8 +285,7 @@ static void ath5k_tx_processq(struct ath5k_softc *sc, static void ath5k_tasklet_tx(unsigned long data); /* Beacon handling */ static int ath5k_beacon_setup(struct ath5k_softc *sc, - struct ath5k_buf *bf, - struct ieee80211_tx_control *ctl); + struct ath5k_buf *bf); static void ath5k_beacon_send(struct ath5k_softc *sc); static void ath5k_beacon_config(struct ath5k_softc *sc); static void ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf); @@ -1295,37 +1290,36 @@ ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) } static int -ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, - struct ieee80211_tx_control *ctl) +ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) { struct ath5k_hw *ah = sc->ah; struct ath5k_txq *txq = sc->txq; struct ath5k_desc *ds = bf->desc; struct sk_buff *skb = bf->skb; + struct ieee80211_tx_info *info = (void*) skb->cb; unsigned int pktlen, flags, keyidx = AR5K_TXKEYIX_INVALID; int ret; flags = AR5K_TXDESC_INTREQ | AR5K_TXDESC_CLRDMASK; - bf->ctl = *ctl; + /* XXX endianness */ bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); - if (ctl->flags & IEEE80211_TXCTL_NO_ACK) + if (info->flags & IEEE80211_TX_CTL_NO_ACK) flags |= AR5K_TXDESC_NOACK; pktlen = skb->len; - if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) { - keyidx = ctl->hw_key->hw_key_idx; - pktlen += ctl->icv_len; + if (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT)) { + keyidx = info->control.hw_key->hw_key_idx; + pktlen += info->control.icv_len; } - ret = ah->ah_setup_tx_desc(ah, ds, pktlen, ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL, (sc->power_level * 2), - ieee80211_get_tx_rate(sc->hw, ctl)->hw_value, - ctl->retry_limit, keyidx, 0, flags, 0, 0); + ieee80211_get_tx_rate(sc->hw, info)->hw_value, + info->control.retry_limit, keyidx, 0, flags, 0, 0); if (ret) goto err_unmap; @@ -1927,11 +1921,11 @@ next: static void ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) { - struct ieee80211_tx_status txs = {}; struct ath5k_tx_status ts = {}; struct ath5k_buf *bf, *bf0; struct ath5k_desc *ds; struct sk_buff *skb; + struct ieee80211_tx_info *info; int ret; spin_lock(&txq->lock); @@ -1951,24 +1945,25 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) } skb = bf->skb; + info = (void*) skb->cb; bf->skb = NULL; + pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, PCI_DMA_TODEVICE); - txs.control = bf->ctl; - txs.retry_count = ts.ts_shortretry + ts.ts_longretry / 6; + info->status.retry_count = ts.ts_shortretry + ts.ts_longretry / 6; if (unlikely(ts.ts_status)) { sc->ll_stats.dot11ACKFailureCount++; if (ts.ts_status & AR5K_TXERR_XRETRY) - txs.excessive_retries = 1; + info->status.excessive_retries = 1; else if (ts.ts_status & AR5K_TXERR_FILT) - txs.flags |= IEEE80211_TX_STATUS_TX_FILTERED; + info->flags |= IEEE80211_TX_STAT_TX_FILTERED; } else { - txs.flags |= IEEE80211_TX_STATUS_ACK; - txs.ack_signal = ts.ts_rssi; + info->flags |= IEEE80211_TX_STAT_ACK; + info->status.ack_signal = ts.ts_rssi; } - ieee80211_tx_status(sc->hw, skb, &txs); + ieee80211_tx_status(sc->hw, skb); sc->tx_stats[txq->qnum].count++; spin_lock(&sc->txbuflock); @@ -2005,10 +2000,10 @@ ath5k_tasklet_tx(unsigned long data) * Setup the beacon frame for transmit. */ static int -ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, - struct ieee80211_tx_control *ctl) +ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) { struct sk_buff *skb = bf->skb; + struct ieee80211_tx_info *info = (void*) skb->cb; struct ath5k_hw *ah = sc->ah; struct ath5k_desc *ds; int ret, antenna = 0; @@ -2047,7 +2042,7 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, ret = ah->ah_setup_tx_desc(ah, ds, skb->len, ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_BEACON, (sc->power_level * 2), - ieee80211_get_tx_rate(sc->hw, ctl)->hw_value, + ieee80211_get_tx_rate(sc->hw, info)->hw_value, 1, AR5K_TXKEYIX_INVALID, antenna, flags, 0, 0); if (ret) @@ -2626,11 +2621,11 @@ ath5k_led_event(struct ath5k_softc *sc, int event) \********************/ static int -ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *ctl) +ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct ath5k_softc *sc = hw->priv; struct ath5k_buf *bf; + struct ieee80211_tx_info *info = (void*) skb->cb; unsigned long flags; int hdrlen; int pad; @@ -2656,13 +2651,13 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb, memmove(skb->data, skb->data+pad, hdrlen); } - sc->led_txrate = ieee80211_get_tx_rate(hw, ctl)->hw_value; + sc->led_txrate = ieee80211_get_tx_rate(hw, info)->hw_value; spin_lock_irqsave(&sc->txbuflock, flags); if (list_empty(&sc->txbuf)) { ATH5K_ERR(sc, "no further txbuf available, dropping packet\n"); spin_unlock_irqrestore(&sc->txbuflock, flags); - ieee80211_stop_queue(hw, ctl->queue); + ieee80211_stop_queue(hw, info->queue); return -1; } bf = list_first_entry(&sc->txbuf, struct ath5k_buf, list); @@ -2674,7 +2669,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb, bf->skb = skb; - if (ath5k_txbuf_setup(sc, bf, ctl)) { + if (ath5k_txbuf_setup(sc, bf)) { bf->skb = NULL; spin_lock_irqsave(&sc->txbuflock, flags); list_add_tail(&bf->list, &sc->txbuf); @@ -3052,8 +3047,7 @@ ath5k_reset_tsf(struct ieee80211_hw *hw) } static int -ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *ctl) +ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) { struct ath5k_softc *sc = hw->priv; int ret; @@ -3069,7 +3063,7 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, ath5k_txbuf_free(sc, sc->bbuf); sc->bbuf->skb = skb; - ret = ath5k_beacon_setup(sc, sc->bbuf, ctl); + ret = ath5k_beacon_setup(sc, sc->bbuf); if (ret) sc->bbuf->skb = NULL; else diff --git a/drivers/net/wireless/ath5k/base.h b/drivers/net/wireless/ath5k/base.h index ecb1749..bb4b26d 100644 --- a/drivers/net/wireless/ath5k/base.h +++ b/drivers/net/wireless/ath5k/base.h @@ -60,7 +60,6 @@ struct ath5k_buf { dma_addr_t daddr; /* physical addr of desc */ struct sk_buff *skb; /* skbuff for buf */ dma_addr_t skbaddr;/* physical addr of skb data */ - struct ieee80211_tx_control ctl; }; /* diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 0c2bc06..aa49383 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -733,7 +733,6 @@ struct b43_wl { /* The beacon we are currently using (AP or IBSS mode). * This beacon stuff is protected by the irq_lock. */ struct sk_buff *current_beacon; - struct ieee80211_tx_control beacon_txctl; bool beacon0_uploaded; bool beacon1_uploaded; struct work_struct beacon_update_trigger; diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index f50e201..aced986 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -1131,10 +1131,10 @@ struct b43_dmaring *parse_cookie(struct b43_wldev *dev, u16 cookie, int *slot) } static int dma_tx_fragment(struct b43_dmaring *ring, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl) + struct sk_buff *skb) { const struct b43_dma_ops *ops = ring->ops; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); u8 *header; int slot, old_top_slot, old_used_slots; int err; @@ -1158,7 +1158,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring, header = &(ring->txhdr_cache[slot * hdrsize]); cookie = generate_cookie(ring, slot); err = b43_generate_txhdr(ring->dev, header, - skb->data, skb->len, ctl, cookie); + skb->data, skb->len, info, cookie); if (unlikely(err)) { ring->current_slot = old_top_slot; ring->used_slots = old_used_slots; @@ -1180,7 +1180,6 @@ static int dma_tx_fragment(struct b43_dmaring *ring, desc = ops->idx2desc(ring, slot, &meta); memset(meta, 0, sizeof(*meta)); - memcpy(&meta->txstat.control, ctl, sizeof(*ctl)); meta->skb = skb; meta->is_last_fragment = 1; @@ -1210,7 +1209,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring, ops->fill_descriptor(ring, desc, meta->dmaaddr, skb->len, 0, 1, 1); - if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) { + if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { /* Tell the firmware about the cookie of the last * mcast frame, so it can clear the more-data bit in it. */ b43_shm_write16(ring->dev, B43_SHM_SHARED, @@ -1281,16 +1280,16 @@ static struct b43_dmaring * select_ring_by_priority(struct b43_wldev *dev, return ring; } -int b43_dma_tx(struct b43_wldev *dev, - struct sk_buff *skb, struct ieee80211_tx_control *ctl) +int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) { struct b43_dmaring *ring; struct ieee80211_hdr *hdr; int err = 0; unsigned long flags; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); hdr = (struct ieee80211_hdr *)skb->data; - if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) { + if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { /* The multicast ring will be sent after the DTIM */ ring = dev->dma.tx_ring_mcast; /* Set the more-data bit. Ucode will clear it on @@ -1298,7 +1297,7 @@ int b43_dma_tx(struct b43_wldev *dev, hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); } else { /* Decide by priority where to put this frame. */ - ring = select_ring_by_priority(dev, ctl->queue); + ring = select_ring_by_priority(dev, info->queue); } spin_lock_irqsave(&ring->lock, flags); @@ -1316,9 +1315,9 @@ int b43_dma_tx(struct b43_wldev *dev, /* Assign the queue number to the ring (if not already done before) * so TX status handling can use it. The queue to ring mapping is * static, so we don't need to store it per frame. */ - ring->queue_prio = ctl->queue; + ring->queue_prio = info->queue; - err = dma_tx_fragment(ring, skb, ctl); + err = dma_tx_fragment(ring, skb); if (unlikely(err == -ENOKEY)) { /* Drop this packet, as we don't have the encryption key * anymore and must not transmit it unencrypted. */ @@ -1334,7 +1333,7 @@ int b43_dma_tx(struct b43_wldev *dev, if ((free_slots(ring) < SLOTS_PER_PACKET) || should_inject_overflow(ring)) { /* This TX ring is full. */ - ieee80211_stop_queue(dev->wl->hw, ctl->queue); + ieee80211_stop_queue(dev->wl->hw, info->queue); ring->stopped = 1; if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index); @@ -1377,13 +1376,19 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, b43_txhdr_size(dev), 1); if (meta->is_last_fragment) { - B43_WARN_ON(!meta->skb); - /* Call back to inform the ieee80211 subsystem about the - * status of the transmission. - * Some fields of txstat are already filled in dma_tx(). + struct ieee80211_tx_info *info; + + BUG_ON(!meta->skb); + + info = IEEE80211_SKB_CB(meta->skb); + + memset(&info->status, 0, sizeof(info->status)); + + /* + * Call back to inform the ieee80211 subsystem about + * the status of the transmission. */ - frame_succeed = b43_fill_txstatus_report( - &(meta->txstat), status); + frame_succeed = b43_fill_txstatus_report(info, status); #ifdef CONFIG_B43_DEBUG if (frame_succeed) ring->nr_succeed_tx_packets++; @@ -1391,8 +1396,8 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, ring->nr_failed_tx_packets++; ring->nr_total_packet_tries += status->frame_count; #endif /* DEBUG */ - ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb, - &(meta->txstat)); + ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb); + /* skb is freed by ieee80211_tx_status_irqsafe() */ meta->skb = NULL; } else { diff --git a/drivers/net/wireless/b43/dma.h b/drivers/net/wireless/b43/dma.h index 20acf88..d1eb5c0 100644 --- a/drivers/net/wireless/b43/dma.h +++ b/drivers/net/wireless/b43/dma.h @@ -181,7 +181,6 @@ struct b43_dmadesc_meta { dma_addr_t dmaaddr; /* ieee80211 TX status. Only used once per 802.11 frag. */ bool is_last_fragment; - struct ieee80211_tx_status txstat; }; struct b43_dmaring; @@ -285,7 +284,7 @@ void b43_dma_get_tx_stats(struct b43_wldev *dev, struct ieee80211_tx_queue_stats *stats); int b43_dma_tx(struct b43_wldev *dev, - struct sk_buff *skb, struct ieee80211_tx_control *ctl); + struct sk_buff *skb); void b43_dma_handle_txstatus(struct b43_wldev *dev, const struct b43_txstatus *status); diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index e428645..3622d76 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1368,18 +1368,18 @@ static void b43_write_beacon_template(struct b43_wldev *dev, unsigned int rate; u16 ctl; int antenna; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(dev->wl->current_beacon); bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data); len = min((size_t) dev->wl->current_beacon->len, 0x200 - sizeof(struct b43_plcp_hdr6)); - rate = ieee80211_get_tx_rate(dev->wl->hw, &dev->wl->beacon_txctl)->hw_value; + rate = ieee80211_get_tx_rate(dev->wl->hw, info)->hw_value; b43_write_template_common(dev, (const u8 *)bcn, len, ram_offset, shm_size_offset, rate); /* Write the PHY TX control parameters. */ - antenna = b43_antenna_from_ieee80211(dev, - dev->wl->beacon_txctl.antenna_sel_tx); + antenna = b43_antenna_from_ieee80211(dev, info->antenna_sel_tx); antenna = b43_antenna_to_phyctl(antenna); ctl = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL); /* We can't send beacons with short preamble. Would get PHY errors. */ @@ -1613,8 +1613,7 @@ static void b43_beacon_update_trigger_work(struct work_struct *work) /* Asynchronously update the packet templates in template RAM. * Locking: Requires wl->irq_lock to be locked. */ -static void b43_update_templates(struct b43_wl *wl, struct sk_buff *beacon, - const struct ieee80211_tx_control *txctl) +static void b43_update_templates(struct b43_wl *wl, struct sk_buff *beacon) { /* This is the top half of the ansynchronous beacon update. * The bottom half is the beacon IRQ. @@ -1625,7 +1624,6 @@ static void b43_update_templates(struct b43_wl *wl, struct sk_buff *beacon, if (wl->current_beacon) dev_kfree_skb_any(wl->current_beacon); wl->current_beacon = beacon; - memcpy(&wl->beacon_txctl, txctl, sizeof(wl->beacon_txctl)); wl->beacon0_uploaded = 0; wl->beacon1_uploaded = 0; queue_work(wl->hw->workqueue, &wl->beacon_update_trigger); @@ -2813,8 +2811,7 @@ static int b43_rng_init(struct b43_wl *wl) } static int b43_op_tx(struct ieee80211_hw *hw, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl) + struct sk_buff *skb) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev = wl->current_dev; @@ -2836,9 +2833,9 @@ static int b43_op_tx(struct ieee80211_hw *hw, err = -ENODEV; if (likely(b43_status(dev) >= B43_STAT_STARTED)) { if (b43_using_pio_transfers(dev)) - err = b43_pio_tx(dev, skb, ctl); + err = b43_pio_tx(dev, skb); else - err = b43_dma_tx(dev, skb, ctl); + err = b43_dma_tx(dev, skb); } read_unlock_irqrestore(&wl->tx_lock, flags); @@ -3429,10 +3426,8 @@ static int b43_op_config_interface(struct ieee80211_hw *hw, if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) { B43_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP); b43_set_ssid(dev, conf->ssid, conf->ssid_len); - if (conf->beacon) { - b43_update_templates(wl, conf->beacon, - conf->beacon_control); - } + if (conf->beacon) + b43_update_templates(wl, conf->beacon); } b43_write_mac_bssid_templates(dev); } @@ -4118,31 +4113,29 @@ static int b43_op_beacon_set_tim(struct ieee80211_hw *hw, int aid, int set) struct b43_wl *wl = hw_to_b43_wl(hw); struct sk_buff *beacon; unsigned long flags; - struct ieee80211_tx_control txctl; /* We could modify the existing beacon and set the aid bit in * the TIM field, but that would probably require resizing and * moving of data within the beacon template. * Simply request a new beacon and let mac80211 do the hard work. */ - beacon = ieee80211_beacon_get(hw, wl->vif, &txctl); + beacon = ieee80211_beacon_get(hw, wl->vif); if (unlikely(!beacon)) return -ENOMEM; spin_lock_irqsave(&wl->irq_lock, flags); - b43_update_templates(wl, beacon, &txctl); + b43_update_templates(wl, beacon); spin_unlock_irqrestore(&wl->irq_lock, flags); return 0; } static int b43_op_ibss_beacon_update(struct ieee80211_hw *hw, - struct sk_buff *beacon, - struct ieee80211_tx_control *ctl) + struct sk_buff *beacon) { struct b43_wl *wl = hw_to_b43_wl(hw); unsigned long flags; spin_lock_irqsave(&wl->irq_lock, flags); - b43_update_templates(wl, beacon, ctl); + b43_update_templates(wl, beacon); spin_unlock_irqrestore(&wl->irq_lock, flags); return 0; diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index 08c8a08..284786a 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -446,29 +446,27 @@ static void pio_tx_frame_4byte_queue(struct b43_pio_txpacket *pack, } static int pio_tx_frame(struct b43_pio_txqueue *q, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl) + struct sk_buff *skb) { struct b43_pio_txpacket *pack; struct b43_txhdr txhdr; u16 cookie; int err; unsigned int hdrlen; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); B43_WARN_ON(list_empty(&q->packets_list)); pack = list_entry(q->packets_list.next, struct b43_pio_txpacket, list); - memset(&pack->txstat, 0, sizeof(pack->txstat)); - memcpy(&pack->txstat.control, ctl, sizeof(*ctl)); cookie = generate_cookie(q, pack); hdrlen = b43_txhdr_size(q->dev); err = b43_generate_txhdr(q->dev, (u8 *)&txhdr, skb->data, - skb->len, ctl, cookie); + skb->len, info, cookie); if (err) return err; - if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) { + if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { /* Tell the firmware about the cookie of the last * mcast frame, so it can clear the more-data bit in it. */ b43_shm_write16(q->dev, B43_SHM_SHARED, @@ -492,17 +490,18 @@ static int pio_tx_frame(struct b43_pio_txqueue *q, return 0; } -int b43_pio_tx(struct b43_wldev *dev, - struct sk_buff *skb, struct ieee80211_tx_control *ctl) +int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) { struct b43_pio_txqueue *q; struct ieee80211_hdr *hdr; unsigned long flags; unsigned int hdrlen, total_len; int err = 0; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); hdr = (struct ieee80211_hdr *)skb->data; - if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) { + + if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { /* The multicast queue will be sent after the DTIM. */ q = dev->pio.tx_queue_mcast; /* Set the frame More-Data bit. Ucode will clear it @@ -510,7 +509,7 @@ int b43_pio_tx(struct b43_wldev *dev, hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); } else { /* Decide by priority where to put this frame. */ - q = select_queue_by_priority(dev, ctl->queue); + q = select_queue_by_priority(dev, info->queue); } spin_lock_irqsave(&q->lock, flags); @@ -533,7 +532,7 @@ int b43_pio_tx(struct b43_wldev *dev, if (total_len > (q->buffer_size - q->buffer_used)) { /* Not enough memory on the queue. */ err = -EBUSY; - ieee80211_stop_queue(dev->wl->hw, ctl->queue); + ieee80211_stop_queue(dev->wl->hw, info->queue); q->stopped = 1; goto out_unlock; } @@ -541,9 +540,9 @@ int b43_pio_tx(struct b43_wldev *dev, /* Assign the queue number to the ring (if not already done before) * so TX status handling can use it. The mac80211-queue to b43-queue * mapping is static, so we don't need to store it per frame. */ - q->queue_prio = ctl->queue; + q->queue_prio = info->queue; - err = pio_tx_frame(q, skb, ctl); + err = pio_tx_frame(q, skb); if (unlikely(err == -ENOKEY)) { /* Drop this packet, as we don't have the encryption key * anymore and must not transmit it unencrypted. */ @@ -561,7 +560,7 @@ int b43_pio_tx(struct b43_wldev *dev, if (((q->buffer_size - q->buffer_used) < roundup(2 + 2 + 6, 4)) || (q->free_packet_slots == 0)) { /* The queue is full. */ - ieee80211_stop_queue(dev->wl->hw, ctl->queue); + ieee80211_stop_queue(dev->wl->hw, info->queue); q->stopped = 1; } @@ -578,6 +577,7 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev, struct b43_pio_txqueue *q; struct b43_pio_txpacket *pack = NULL; unsigned int total_len; + struct ieee80211_tx_info *info; q = parse_cookie(dev, status->cookie, &pack); if (unlikely(!q)) @@ -586,15 +586,17 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev, spin_lock(&q->lock); /* IRQs are already disabled. */ - b43_fill_txstatus_report(&(pack->txstat), status); + info = (void *)pack->skb; + memset(&info->status, 0, sizeof(info->status)); + + b43_fill_txstatus_report(info, status); total_len = pack->skb->len + b43_txhdr_size(dev); total_len = roundup(total_len, 4); q->buffer_used -= total_len; q->free_packet_slots += 1; - ieee80211_tx_status_irqsafe(dev->wl->hw, pack->skb, - &(pack->txstat)); + ieee80211_tx_status_irqsafe(dev->wl->hw, pack->skb); pack->skb = NULL; list_add(&pack->list, &q->packets_list); diff --git a/drivers/net/wireless/b43/pio.h b/drivers/net/wireless/b43/pio.h index e2ec676..6c174c9 100644 --- a/drivers/net/wireless/b43/pio.h +++ b/drivers/net/wireless/b43/pio.h @@ -62,8 +62,6 @@ struct b43_pio_txpacket { struct b43_pio_txqueue *queue; /* The TX data packet. */ struct sk_buff *skb; - /* The status meta data. */ - struct ieee80211_tx_status txstat; /* Index in the (struct b43_pio_txqueue)->packets array. */ u8 index; @@ -167,8 +165,7 @@ int b43_pio_init(struct b43_wldev *dev); void b43_pio_stop(struct b43_wldev *dev); void b43_pio_free(struct b43_wldev *dev); -int b43_pio_tx(struct b43_wldev *dev, - struct sk_buff *skb, struct ieee80211_tx_control *ctl); +int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb); void b43_pio_handle_txstatus(struct b43_wldev *dev, const struct b43_txstatus *status); void b43_pio_get_tx_stats(struct b43_wldev *dev, @@ -193,8 +190,7 @@ static inline void b43_pio_stop(struct b43_wldev *dev) { } static inline int b43_pio_tx(struct b43_wldev *dev, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl) + struct sk_buff *skb) { return 0; } diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index 9b682a3..f9e1cff 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -185,14 +185,14 @@ int b43_generate_txhdr(struct b43_wldev *dev, u8 *_txhdr, const unsigned char *fragment_data, unsigned int fragment_len, - const struct ieee80211_tx_control *txctl, + const struct ieee80211_tx_info *info, u16 cookie) { struct b43_txhdr *txhdr = (struct b43_txhdr *)_txhdr; const struct b43_phy *phy = &dev->phy; const struct ieee80211_hdr *wlhdr = (const struct ieee80211_hdr *)fragment_data; - int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)); + int use_encryption = (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT)); u16 fctl = le16_to_cpu(wlhdr->frame_control); struct ieee80211_rate *fbrate; u8 rate, rate_fb; @@ -205,10 +205,10 @@ int b43_generate_txhdr(struct b43_wldev *dev, memset(txhdr, 0, sizeof(*txhdr)); - txrate = ieee80211_get_tx_rate(dev->wl->hw, txctl); + txrate = ieee80211_get_tx_rate(dev->wl->hw, info); rate = txrate ? txrate->hw_value : B43_CCK_RATE_1MB; rate_ofdm = b43_is_ofdm_rate(rate); - fbrate = ieee80211_get_alt_retry_rate(dev->wl->hw, txctl) ? : txrate; + fbrate = ieee80211_get_alt_retry_rate(dev->wl->hw, info) ? : txrate; rate_fb = fbrate->hw_value; rate_fb_ofdm = b43_is_ofdm_rate(rate_fb); @@ -228,15 +228,13 @@ int b43_generate_txhdr(struct b43_wldev *dev, * use the original dur_id field. */ txhdr->dur_fb = wlhdr->duration_id; } else { - txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw, - txctl->vif, - fragment_len, - fbrate); + txhdr->dur_fb = ieee80211_generic_frame_duration( + dev->wl->hw, info->control.vif, fragment_len, fbrate); } plcp_fragment_len = fragment_len + FCS_LEN; if (use_encryption) { - u8 key_idx = txctl->hw_key->hw_key_idx; + u8 key_idx = info->control.hw_key->hw_key_idx; struct b43_key *key; int wlhdr_len; size_t iv_len; @@ -254,7 +252,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, } /* Hardware appends ICV. */ - plcp_fragment_len += txctl->icv_len; + plcp_fragment_len += info->control.icv_len; key_idx = b43_kidx_to_fw(dev, key_idx); mac_ctl |= (key_idx << B43_TXH_MAC_KEYIDX_SHIFT) & @@ -262,7 +260,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, mac_ctl |= (key->algorithm << B43_TXH_MAC_KEYALG_SHIFT) & B43_TXH_MAC_KEYALG; wlhdr_len = ieee80211_get_hdrlen(fctl); - iv_len = min((size_t) txctl->iv_len, + iv_len = min((size_t) info->control.iv_len, ARRAY_SIZE(txhdr->iv)); memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len); } @@ -293,10 +291,10 @@ int b43_generate_txhdr(struct b43_wldev *dev, phy_ctl |= B43_TXH_PHY_ENC_OFDM; else phy_ctl |= B43_TXH_PHY_ENC_CCK; - if (txctl->flags & IEEE80211_TXCTL_SHORT_PREAMBLE) + if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE) phy_ctl |= B43_TXH_PHY_SHORTPRMBL; - switch (b43_ieee80211_antenna_sanitize(dev, txctl->antenna_sel_tx)) { + switch (b43_ieee80211_antenna_sanitize(dev, info->antenna_sel_tx)) { case 0: /* Default */ phy_ctl |= B43_TXH_PHY_ANT01AUTO; break; @@ -317,21 +315,21 @@ int b43_generate_txhdr(struct b43_wldev *dev, } /* MAC control */ - if (!(txctl->flags & IEEE80211_TXCTL_NO_ACK)) + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) mac_ctl |= B43_TXH_MAC_ACK; if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) && ((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL))) mac_ctl |= B43_TXH_MAC_HWSEQ; - if (txctl->flags & IEEE80211_TXCTL_FIRST_FRAGMENT) + if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) mac_ctl |= B43_TXH_MAC_STMSDU; if (phy->type == B43_PHYTYPE_A) mac_ctl |= B43_TXH_MAC_5GHZ; - if (txctl->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT) + if (info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT) mac_ctl |= B43_TXH_MAC_LONGFRAME; /* Generate the RTS or CTS-to-self frame */ - if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) || - (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) { + if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) || + (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) { unsigned int len; struct ieee80211_hdr *hdr; int rts_rate, rts_rate_fb; @@ -339,14 +337,14 @@ int b43_generate_txhdr(struct b43_wldev *dev, struct b43_plcp_hdr6 *plcp; struct ieee80211_rate *rts_cts_rate; - rts_cts_rate = ieee80211_get_rts_cts_rate(dev->wl->hw, txctl); + rts_cts_rate = ieee80211_get_rts_cts_rate(dev->wl->hw, info); rts_rate = rts_cts_rate ? rts_cts_rate->hw_value : B43_CCK_RATE_1MB; rts_rate_ofdm = b43_is_ofdm_rate(rts_rate); rts_rate_fb = b43_calc_fallback_rate(rts_rate); rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb); - if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { + if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { struct ieee80211_cts *cts; if (b43_is_old_txhdr_format(dev)) { @@ -356,9 +354,9 @@ int b43_generate_txhdr(struct b43_wldev *dev, cts = (struct ieee80211_cts *) (txhdr->new_format.rts_frame); } - ieee80211_ctstoself_get(dev->wl->hw, txctl->vif, + ieee80211_ctstoself_get(dev->wl->hw, info->control.vif, fragment_data, fragment_len, - txctl, cts); + info, cts); mac_ctl |= B43_TXH_MAC_SENDCTS; len = sizeof(struct ieee80211_cts); } else { @@ -371,9 +369,9 @@ int b43_generate_txhdr(struct b43_wldev *dev, rts = (struct ieee80211_rts *) (txhdr->new_format.rts_frame); } - ieee80211_rts_get(dev->wl->hw, txctl->vif, + ieee80211_rts_get(dev->wl->hw, info->control.vif, fragment_data, fragment_len, - txctl, rts); + info, rts); mac_ctl |= B43_TXH_MAC_SENDRTS; len = sizeof(struct ieee80211_rts); } @@ -687,27 +685,27 @@ void b43_handle_txstatus(struct b43_wldev *dev, /* Fill out the mac80211 TXstatus report based on the b43-specific * txstatus report data. This returns a boolean whether the frame was * successfully transmitted. */ -bool b43_fill_txstatus_report(struct ieee80211_tx_status *report, +bool b43_fill_txstatus_report(struct ieee80211_tx_info *report, const struct b43_txstatus *status) { bool frame_success = 1; if (status->acked) { /* The frame was ACKed. */ - report->flags |= IEEE80211_TX_STATUS_ACK; + report->flags |= IEEE80211_TX_STAT_ACK; } else { /* The frame was not ACKed... */ - if (!(report->control.flags & IEEE80211_TXCTL_NO_ACK)) { + if (!(report->flags & IEEE80211_TX_CTL_NO_ACK)) { /* ...but we expected an ACK. */ frame_success = 0; - report->excessive_retries = 1; + report->status.excessive_retries = 1; } } if (status->frame_count == 0) { /* The frame was not transmitted at all. */ - report->retry_count = 0; + report->status.retry_count = 0; } else - report->retry_count = status->frame_count - 1; + report->status.retry_count = status->frame_count - 1; return frame_success; } diff --git a/drivers/net/wireless/b43/xmit.h b/drivers/net/wireless/b43/xmit.h index b05f44e..0215faf 100644 --- a/drivers/net/wireless/b43/xmit.h +++ b/drivers/net/wireless/b43/xmit.h @@ -178,7 +178,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, u8 * txhdr, const unsigned char *fragment_data, unsigned int fragment_len, - const struct ieee80211_tx_control *txctl, u16 cookie); + const struct ieee80211_tx_info *txctl, u16 cookie); /* Transmit Status */ struct b43_txstatus { @@ -294,7 +294,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr); void b43_handle_txstatus(struct b43_wldev *dev, const struct b43_txstatus *status); -bool b43_fill_txstatus_report(struct ieee80211_tx_status *report, +bool b43_fill_txstatus_report(struct ieee80211_tx_info *report, const struct b43_txstatus *status); void b43_tx_suspend(struct b43_wldev *dev); diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c index d6686f7..c1c501d 100644 --- a/drivers/net/wireless/b43legacy/dma.c +++ b/drivers/net/wireless/b43legacy/dma.c @@ -1205,10 +1205,10 @@ struct b43legacy_dmaring *parse_cookie(struct b43legacy_wldev *dev, } static int dma_tx_fragment(struct b43legacy_dmaring *ring, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl) + struct sk_buff *skb) { const struct b43legacy_dma_ops *ops = ring->ops; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); u8 *header; int slot, old_top_slot, old_used_slots; int err; @@ -1231,7 +1231,7 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring, header = &(ring->txhdr_cache[slot * sizeof( struct b43legacy_txhdr_fw3)]); err = b43legacy_generate_txhdr(ring->dev, header, - skb->data, skb->len, ctl, + skb->data, skb->len, info, generate_cookie(ring, slot)); if (unlikely(err)) { ring->current_slot = old_top_slot; @@ -1255,7 +1255,6 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring, desc = ops->idx2desc(ring, slot, &meta); memset(meta, 0, sizeof(*meta)); - memcpy(&meta->txstat.control, ctl, sizeof(*ctl)); meta->skb = skb; meta->is_last_fragment = 1; @@ -1323,14 +1322,14 @@ int should_inject_overflow(struct b43legacy_dmaring *ring) } int b43legacy_dma_tx(struct b43legacy_wldev *dev, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl) + struct sk_buff *skb) { struct b43legacy_dmaring *ring; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int err = 0; unsigned long flags; - ring = priority_to_txring(dev, ctl->queue); + ring = priority_to_txring(dev, info->queue); spin_lock_irqsave(&ring->lock, flags); B43legacy_WARN_ON(!ring->tx); if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) { @@ -1343,7 +1342,7 @@ int b43legacy_dma_tx(struct b43legacy_wldev *dev, * That would be a mac80211 bug. */ B43legacy_BUG_ON(ring->stopped); - err = dma_tx_fragment(ring, skb, ctl); + err = dma_tx_fragment(ring, skb); if (unlikely(err == -ENOKEY)) { /* Drop this packet, as we don't have the encryption key * anymore and must not transmit it unencrypted. */ @@ -1401,26 +1400,29 @@ void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev, 1); if (meta->is_last_fragment) { - B43legacy_WARN_ON(!meta->skb); + struct ieee80211_tx_info *info; + BUG_ON(!meta->skb); + info = IEEE80211_SKB_CB(meta->skb); /* Call back to inform the ieee80211 subsystem about the * status of the transmission. * Some fields of txstat are already filled in dma_tx(). */ + + memset(&info->status, 0, sizeof(info->status)); + if (status->acked) { - meta->txstat.flags |= IEEE80211_TX_STATUS_ACK; + info->flags |= IEEE80211_TX_STAT_ACK; } else { - if (!(meta->txstat.control.flags - & IEEE80211_TXCTL_NO_ACK)) - meta->txstat.excessive_retries = 1; + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) + info->status.excessive_retries = 1; } if (status->frame_count == 0) { /* The frame was not transmitted at all. */ - meta->txstat.retry_count = 0; + info->status.retry_count = 0; } else - meta->txstat.retry_count = status->frame_count + info->status.retry_count = status->frame_count - 1; - ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb, - &(meta->txstat)); + ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb); /* skb is freed by ieee80211_tx_status_irqsafe() */ meta->skb = NULL; } else { diff --git a/drivers/net/wireless/b43legacy/dma.h b/drivers/net/wireless/b43legacy/dma.h index 2dd488c..67537a7 100644 --- a/drivers/net/wireless/b43legacy/dma.h +++ b/drivers/net/wireless/b43legacy/dma.h @@ -195,7 +195,6 @@ struct b43legacy_dmadesc_meta { dma_addr_t dmaaddr; /* ieee80211 TX status. Only used once per 802.11 frag. */ bool is_last_fragment; - struct ieee80211_tx_status txstat; }; struct b43legacy_dmaring; @@ -297,8 +296,7 @@ void b43legacy_dma_get_tx_stats(struct b43legacy_wldev *dev, struct ieee80211_tx_queue_stats *stats); int b43legacy_dma_tx(struct b43legacy_wldev *dev, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl); + struct sk_buff *skb); void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev, const struct b43legacy_txstatus *status); diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index b05a507..f706ca6 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -2358,8 +2358,7 @@ static int b43legacy_rng_init(struct b43legacy_wl *wl) } static int b43legacy_op_tx(struct ieee80211_hw *hw, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl) + struct sk_buff *skb) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev = wl->current_dev; @@ -2373,10 +2372,10 @@ static int b43legacy_op_tx(struct ieee80211_hw *hw, /* DMA-TX is done without a global lock. */ if (b43legacy_using_pio(dev)) { spin_lock_irqsave(&wl->irq_lock, flags); - err = b43legacy_pio_tx(dev, skb, ctl); + err = b43legacy_pio_tx(dev, skb); spin_unlock_irqrestore(&wl->irq_lock, flags); } else - err = b43legacy_dma_tx(dev, skb, ctl); + err = b43legacy_dma_tx(dev, skb); out: if (unlikely(err)) return NETDEV_TX_BUSY; @@ -3409,7 +3408,7 @@ static int b43legacy_op_beacon_set_tim(struct ieee80211_hw *hw, * field, but that would probably require resizing and moving of data * within the beacon template. Simply request a new beacon and let * mac80211 do the hard work. */ - beacon = ieee80211_beacon_get(hw, wl->vif, NULL); + beacon = ieee80211_beacon_get(hw, wl->vif); if (unlikely(!beacon)) return -ENOMEM; spin_lock_irqsave(&wl->irq_lock, flags); @@ -3420,8 +3419,7 @@ static int b43legacy_op_beacon_set_tim(struct ieee80211_hw *hw, } static int b43legacy_op_ibss_beacon_update(struct ieee80211_hw *hw, - struct sk_buff *beacon, - struct ieee80211_tx_control *ctl) + struct sk_buff *beacon) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); unsigned long flags; diff --git a/drivers/net/wireless/b43legacy/pio.c b/drivers/net/wireless/b43legacy/pio.c index 8d3d27d..a86c764 100644 --- a/drivers/net/wireless/b43legacy/pio.c +++ b/drivers/net/wireless/b43legacy/pio.c @@ -196,7 +196,7 @@ static int pio_tx_write_fragment(struct b43legacy_pioqueue *queue, B43legacy_WARN_ON(skb_shinfo(skb)->nr_frags != 0); err = b43legacy_generate_txhdr(queue->dev, txhdr, skb->data, skb->len, - &packet->txstat.control, + IEEE80211_SKB_CB(skb), generate_cookie(queue, packet)); if (err) return err; @@ -463,8 +463,7 @@ err_destroy0: } int b43legacy_pio_tx(struct b43legacy_wldev *dev, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl) + struct sk_buff *skb) { struct b43legacy_pioqueue *queue = dev->pio.queue1; struct b43legacy_pio_txpacket *packet; @@ -476,9 +475,6 @@ int b43legacy_pio_tx(struct b43legacy_wldev *dev, list); packet->skb = skb; - memset(&packet->txstat, 0, sizeof(packet->txstat)); - memcpy(&packet->txstat.control, ctl, sizeof(*ctl)); - list_move_tail(&packet->list, &queue->txqueue); queue->nr_txfree--; queue->nr_tx_packets++; @@ -494,6 +490,7 @@ void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev, { struct b43legacy_pioqueue *queue; struct b43legacy_pio_txpacket *packet; + struct ieee80211_tx_info *info; queue = parse_cookie(dev, status->cookie, &packet); B43legacy_WARN_ON(!queue); @@ -505,11 +502,13 @@ void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev, queue->tx_devq_used -= (packet->skb->len + sizeof(struct b43legacy_txhdr_fw3)); + info = IEEE80211_SKB_CB(packet->skb); + memset(&info->status, 0, sizeof(info->status)); + if (status->acked) - packet->txstat.flags |= IEEE80211_TX_STATUS_ACK; - packet->txstat.retry_count = status->frame_count - 1; - ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb, - &(packet->txstat)); + info->flags |= IEEE80211_TX_STAT_ACK; + info->status.retry_count = status->frame_count - 1; + ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb); packet->skb = NULL; free_txpacket(packet, 1); diff --git a/drivers/net/wireless/b43legacy/pio.h b/drivers/net/wireless/b43legacy/pio.h index 5bfed0c..49310df 100644 --- a/drivers/net/wireless/b43legacy/pio.h +++ b/drivers/net/wireless/b43legacy/pio.h @@ -41,7 +41,6 @@ struct b43legacy_xmitstatus; struct b43legacy_pio_txpacket { struct b43legacy_pioqueue *queue; struct sk_buff *skb; - struct ieee80211_tx_status txstat; struct list_head list; }; @@ -104,8 +103,7 @@ int b43legacy_pio_init(struct b43legacy_wldev *dev); void b43legacy_pio_free(struct b43legacy_wldev *dev); int b43legacy_pio_tx(struct b43legacy_wldev *dev, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl); + struct sk_buff *skb); void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev, const struct b43legacy_txstatus *status); void b43legacy_pio_get_tx_stats(struct b43legacy_wldev *dev, diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c index 55dc251..82dc04d 100644 --- a/drivers/net/wireless/b43legacy/xmit.c +++ b/drivers/net/wireless/b43legacy/xmit.c @@ -188,11 +188,11 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, struct b43legacy_txhdr_fw3 *txhdr, const unsigned char *fragment_data, unsigned int fragment_len, - const struct ieee80211_tx_control *txctl, + const struct ieee80211_tx_info *info, u16 cookie) { const struct ieee80211_hdr *wlhdr; - int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)); + int use_encryption = (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT)); u16 fctl; u8 rate; struct ieee80211_rate *rate_fb; @@ -208,11 +208,11 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, memset(txhdr, 0, sizeof(*txhdr)); - tx_rate = ieee80211_get_tx_rate(dev->wl->hw, txctl); + tx_rate = ieee80211_get_tx_rate(dev->wl->hw, info); rate = tx_rate->hw_value; rate_ofdm = b43legacy_is_ofdm_rate(rate); - rate_fb = ieee80211_get_alt_retry_rate(dev->wl->hw, txctl) ? : tx_rate; + rate_fb = ieee80211_get_alt_retry_rate(dev->wl->hw, info) ? : tx_rate; rate_fb_ofdm = b43legacy_is_ofdm_rate(rate_fb->hw_value); txhdr->mac_frame_ctl = wlhdr->frame_control; @@ -228,14 +228,14 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, txhdr->dur_fb = wlhdr->duration_id; } else { txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw, - txctl->vif, + info->control.vif, fragment_len, rate_fb); } plcp_fragment_len = fragment_len + FCS_LEN; if (use_encryption) { - u8 key_idx = txctl->hw_key->hw_key_idx; + u8 key_idx = info->control.hw_key->hw_key_idx; struct b43legacy_key *key; int wlhdr_len; size_t iv_len; @@ -245,7 +245,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, if (key->enabled) { /* Hardware appends ICV. */ - plcp_fragment_len += txctl->icv_len; + plcp_fragment_len += info->control.icv_len; key_idx = b43legacy_kidx_to_fw(dev, key_idx); mac_ctl |= (key_idx << B43legacy_TX4_MAC_KEYIDX_SHIFT) & @@ -254,7 +254,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, B43legacy_TX4_MAC_KEYALG_SHIFT) & B43legacy_TX4_MAC_KEYALG; wlhdr_len = ieee80211_get_hdrlen(fctl); - iv_len = min((size_t)txctl->iv_len, + iv_len = min((size_t)info->control.iv_len, ARRAY_SIZE(txhdr->iv)); memcpy(txhdr->iv, ((u8 *)wlhdr) + wlhdr_len, iv_len); } else { @@ -278,7 +278,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, phy_ctl |= B43legacy_TX4_PHY_OFDM; if (dev->short_preamble) phy_ctl |= B43legacy_TX4_PHY_SHORTPRMBL; - switch (txctl->antenna_sel_tx) { + switch (info->antenna_sel_tx) { case 0: phy_ctl |= B43legacy_TX4_PHY_ANTLAST; break; @@ -293,21 +293,21 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, } /* MAC control */ - if (!(txctl->flags & IEEE80211_TXCTL_NO_ACK)) + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) mac_ctl |= B43legacy_TX4_MAC_ACK; if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) && ((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL))) mac_ctl |= B43legacy_TX4_MAC_HWSEQ; - if (txctl->flags & IEEE80211_TXCTL_FIRST_FRAGMENT) + if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) mac_ctl |= B43legacy_TX4_MAC_STMSDU; if (rate_fb_ofdm) mac_ctl |= B43legacy_TX4_MAC_FALLBACKOFDM; - if (txctl->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT) + if (info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT) mac_ctl |= B43legacy_TX4_MAC_LONGFRAME; /* Generate the RTS or CTS-to-self frame */ - if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) || - (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) { + if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) || + (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) { unsigned int len; struct ieee80211_hdr *hdr; int rts_rate; @@ -315,26 +315,26 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, int rts_rate_ofdm; int rts_rate_fb_ofdm; - rts_rate = ieee80211_get_rts_cts_rate(dev->wl->hw, txctl)->hw_value; + rts_rate = ieee80211_get_rts_cts_rate(dev->wl->hw, info)->hw_value; rts_rate_ofdm = b43legacy_is_ofdm_rate(rts_rate); rts_rate_fb = b43legacy_calc_fallback_rate(rts_rate); rts_rate_fb_ofdm = b43legacy_is_ofdm_rate(rts_rate_fb); if (rts_rate_fb_ofdm) mac_ctl |= B43legacy_TX4_MAC_CTSFALLBACKOFDM; - if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { + if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { ieee80211_ctstoself_get(dev->wl->hw, - txctl->vif, + info->control.vif, fragment_data, - fragment_len, txctl, + fragment_len, info, (struct ieee80211_cts *) (txhdr->rts_frame)); mac_ctl |= B43legacy_TX4_MAC_SENDCTS; len = sizeof(struct ieee80211_cts); } else { ieee80211_rts_get(dev->wl->hw, - txctl->vif, - fragment_data, fragment_len, txctl, + info->control.vif, + fragment_data, fragment_len, info, (struct ieee80211_rts *) (txhdr->rts_frame)); mac_ctl |= B43legacy_TX4_MAC_SENDRTS; @@ -365,12 +365,12 @@ int b43legacy_generate_txhdr(struct b43legacy_wldev *dev, u8 *txhdr, const unsigned char *fragment_data, unsigned int fragment_len, - const struct ieee80211_tx_control *txctl, + const struct ieee80211_tx_info *info, u16 cookie) { return generate_txhdr_fw3(dev, (struct b43legacy_txhdr_fw3 *)txhdr, fragment_data, fragment_len, - txctl, cookie); + info, cookie); } static s8 b43legacy_rssi_postprocess(struct b43legacy_wldev *dev, diff --git a/drivers/net/wireless/b43legacy/xmit.h b/drivers/net/wireless/b43legacy/xmit.h index bab4792..e56777e0f 100644 --- a/drivers/net/wireless/b43legacy/xmit.h +++ b/drivers/net/wireless/b43legacy/xmit.h @@ -80,7 +80,7 @@ int b43legacy_generate_txhdr(struct b43legacy_wldev *dev, u8 *txhdr, const unsigned char *fragment_data, unsigned int fragment_len, - const struct ieee80211_tx_control *txctl, + const struct ieee80211_tx_info *info, u16 cookie); diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index f3ca02f..10c64bd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -445,8 +445,7 @@ static int rs_adjust_next_rate(struct iwl3945_priv *priv, int rate) */ static void rs_tx_status(void *priv_rate, struct net_device *dev, - struct sk_buff *skb, - struct ieee80211_tx_status *tx_resp) + struct sk_buff *skb) { u8 retries, current_count; int scale_rate_index, first_index, last_index; @@ -457,14 +456,15 @@ static void rs_tx_status(void *priv_rate, struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct iwl3945_rs_sta *rs_sta; struct ieee80211_supported_band *sband; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); IWL_DEBUG_RATE("enter\n"); sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - retries = tx_resp->retry_count; - first_index = sband->bitrates[tx_resp->control.tx_rate_idx].hw_value; + retries = info->status.retry_count; + first_index = sband->bitrates[info->tx_rate_idx].hw_value; if ((first_index < 0) || (first_index >= IWL_RATE_COUNT)) { IWL_DEBUG_RATE("leave: Rate out of bounds: %d\n", first_index); return; @@ -525,11 +525,11 @@ static void rs_tx_status(void *priv_rate, /* Update the last index window with success/failure based on ACK */ IWL_DEBUG_RATE("Update rate %d with %s.\n", last_index, - (tx_resp->flags & IEEE80211_TX_STATUS_ACK) ? + (info->flags & IEEE80211_TX_STAT_ACK) ? "success" : "failure"); iwl3945_collect_tx_data(rs_sta, &rs_sta->win[last_index], - tx_resp->flags & IEEE80211_TX_STATUS_ACK, 1); + info->flags & IEEE80211_TX_STAT_ACK, 1); /* We updated the rate scale window -- if its been more than * flush_time since the last run, schedule the flush diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index f8e691f..0ba6889 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -283,8 +283,7 @@ static void iwl3945_tx_queue_reclaim(struct iwl3945_priv *priv, q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { tx_info = &txq->txb[txq->q.read_ptr]; - ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb[0], - &tx_info->status); + ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb[0]); tx_info->skb[0] = NULL; iwl3945_hw_txq_free_tfd(priv, txq); } @@ -306,7 +305,7 @@ static void iwl3945_rx_reply_tx(struct iwl3945_priv *priv, int txq_id = SEQ_TO_QUEUE(sequence); int index = SEQ_TO_INDEX(sequence); struct iwl3945_tx_queue *txq = &priv->txq[txq_id]; - struct ieee80211_tx_status *tx_status; + struct ieee80211_tx_info *info; struct iwl3945_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; u32 status = le32_to_cpu(tx_resp->status); int rate_idx; @@ -319,21 +318,22 @@ static void iwl3945_rx_reply_tx(struct iwl3945_priv *priv, return; } - tx_status = &(txq->txb[txq->q.read_ptr].status); + info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]); + memset(&info->status, 0, sizeof(info->status)); - tx_status->retry_count = tx_resp->failure_frame; + info->status.retry_count = tx_resp->failure_frame; /* tx_status->rts_retry_count = tx_resp->failure_rts; */ - tx_status->flags = ((status & TX_STATUS_MSK) == TX_STATUS_SUCCESS) ? - IEEE80211_TX_STATUS_ACK : 0; + info->flags |= ((status & TX_STATUS_MSK) == TX_STATUS_SUCCESS) ? + IEEE80211_TX_STAT_ACK : 0; IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) plcp rate %d retries %d\n", txq_id, iwl3945_get_tx_fail_reason(status), status, tx_resp->rate, tx_resp->failure_frame); rate_idx = iwl3945_hwrate_to_plcp_idx(tx_resp->rate); - if (tx_status->control.band == IEEE80211_BAND_5GHZ) + if (info->band == IEEE80211_BAND_5GHZ) rate_idx -= IWL_FIRST_OFDM_RATE; - tx_status->control.tx_rate_idx = rate_idx; + info->tx_rate_idx = rate_idx; IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index); iwl3945_tx_queue_reclaim(priv, txq_id, index); @@ -960,11 +960,11 @@ u8 iwl3945_hw_find_station(struct iwl3945_priv *priv, const u8 *addr) */ void iwl3945_hw_build_tx_cmd_rate(struct iwl3945_priv *priv, struct iwl3945_cmd *cmd, - struct ieee80211_tx_control *ctrl, + struct ieee80211_tx_info *info, struct ieee80211_hdr *hdr, int sta_id, int tx_id) { unsigned long flags; - u16 hw_value = ieee80211_get_tx_rate(priv->hw, ctrl)->hw_value; + u16 hw_value = ieee80211_get_tx_rate(priv->hw, info)->hw_value; u16 rate_index = min(hw_value & 0xffff, IWL_RATE_COUNT - 1); u16 rate_mask; int rate; @@ -977,7 +977,7 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl3945_priv *priv, tx_flags = cmd->cmd.tx.tx_flags; /* We need to figure out how to get the sta->supp_rates while - * in this running context; perhaps encoding into ctrl->tx_rate? */ + * in this running context */ rate_mask = IWL_RATES_MASK; spin_lock_irqsave(&priv->sta_lock, flags); diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index 9fdc140..835c5b4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -124,7 +124,6 @@ int iwl3945_x2_queue_used(const struct iwl3945_queue *q, int i); /* One for each TFD */ struct iwl3945_tx_info { - struct ieee80211_tx_status status; struct sk_buff *skb[MAX_NUM_OF_TBS]; }; @@ -645,7 +644,7 @@ extern unsigned int iwl3945_hw_get_beacon_cmd(struct iwl3945_priv *priv, extern int iwl3945_hw_get_rx_read(struct iwl3945_priv *priv); extern void iwl3945_hw_build_tx_cmd_rate(struct iwl3945_priv *priv, struct iwl3945_cmd *cmd, - struct ieee80211_tx_control *ctrl, + struct ieee80211_tx_info *info, struct ieee80211_hdr *hdr, int sta_id, int tx_id); extern int iwl3945_hw_reg_send_txpower(struct iwl3945_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index 7993a1d..f28b3cc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -785,8 +785,7 @@ out: * mac80211 sends us Tx status */ static void rs_tx_status(void *priv_rate, struct net_device *dev, - struct sk_buff *skb, - struct ieee80211_tx_status *tx_resp) + struct sk_buff *skb) { int status; u8 retries; @@ -798,6 +797,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, struct iwl_priv *priv = (struct iwl_priv *)priv_rate; struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_hw *hw = local_to_hw(local); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl4965_rate_scale_data *window = NULL; struct iwl4965_rate_scale_data *search_win = NULL; u32 tx_rate; @@ -813,11 +813,11 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, return; /* This packet was aggregated but doesn't carry rate scale info */ - if ((tx_resp->control.flags & IEEE80211_TXCTL_AMPDU) && - !(tx_resp->flags & IEEE80211_TX_STATUS_AMPDU)) + if ((info->flags & IEEE80211_TX_CTL_AMPDU) && + !(info->flags & IEEE80211_TX_STAT_AMPDU)) return; - retries = tx_resp->retry_count; + retries = info->status.retry_count; if (retries > 15) retries = 15; @@ -862,20 +862,20 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, if (priv->band == IEEE80211_BAND_5GHZ) rs_index -= IWL_FIRST_OFDM_RATE; - if ((tx_resp->control.tx_rate_idx < 0) || + if ((info->tx_rate_idx < 0) || (tbl_type.is_SGI ^ - !!(tx_resp->control.flags & IEEE80211_TXCTL_SHORT_GI)) || + !!(info->flags & IEEE80211_TX_CTL_SHORT_GI)) || (tbl_type.is_fat ^ - !!(tx_resp->control.flags & IEEE80211_TXCTL_40_MHZ_WIDTH)) || + !!(info->flags & IEEE80211_TX_CTL_40_MHZ_WIDTH)) || (tbl_type.is_dup ^ - !!(tx_resp->control.flags & IEEE80211_TXCTL_DUP_DATA)) || - (tbl_type.ant_type ^ tx_resp->control.antenna_sel_tx) || + !!(info->flags & IEEE80211_TX_CTL_DUP_DATA)) || + (tbl_type.ant_type ^ info->antenna_sel_tx) || (!!(tx_rate & RATE_MCS_HT_MSK) ^ - !!(tx_resp->control.flags & IEEE80211_TXCTL_OFDM_HT)) || + !!(info->flags & IEEE80211_TX_CTL_OFDM_HT)) || (!!(tx_rate & RATE_MCS_GF_MSK) ^ - !!(tx_resp->control.flags & IEEE80211_TXCTL_GREEN_FIELD)) || + !!(info->flags & IEEE80211_TX_CTL_GREEN_FIELD)) || (hw->wiphy->bands[priv->band]->bitrates[rs_index].bitrate != - hw->wiphy->bands[tx_resp->control.band]->bitrates[tx_resp->control.tx_rate_idx].bitrate)) { + hw->wiphy->bands[info->band]->bitrates[info->tx_rate_idx].bitrate)) { IWL_DEBUG_RATE("initial rate does not match 0x%x\n", tx_rate); goto out; } @@ -929,10 +929,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type, &rs_index); /* Update frame history window with "success" if Tx got ACKed ... */ - if (tx_resp->flags & IEEE80211_TX_STATUS_ACK) - status = 1; - else - status = 0; + status = !!(info->flags & IEEE80211_TX_STAT_ACK); /* If type matches "search" table, * add final tx status to "search" history */ @@ -943,10 +940,10 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, tpt = search_tbl->expected_tpt[rs_index]; else tpt = 0; - if (tx_resp->control.flags & IEEE80211_TXCTL_AMPDU) + if (info->flags & IEEE80211_TX_CTL_AMPDU) rs_collect_tx_data(search_win, rs_index, tpt, - tx_resp->ampdu_ack_len, - tx_resp->ampdu_ack_map); + info->status.ampdu_ack_len, + info->status.ampdu_ack_map); else rs_collect_tx_data(search_win, rs_index, tpt, 1, status); @@ -959,10 +956,10 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, tpt = curr_tbl->expected_tpt[rs_index]; else tpt = 0; - if (tx_resp->control.flags & IEEE80211_TXCTL_AMPDU) + if (info->flags & IEEE80211_TX_CTL_AMPDU) rs_collect_tx_data(window, rs_index, tpt, - tx_resp->ampdu_ack_len, - tx_resp->ampdu_ack_map); + info->status.ampdu_ack_len, + info->status.ampdu_ack_map); else rs_collect_tx_data(window, rs_index, tpt, 1, status); @@ -971,10 +968,10 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, /* If not searching for new mode, increment success/failed counter * ... these help determine when to start searching again */ if (lq_sta->stay_in_tbl) { - if (tx_resp->control.flags & IEEE80211_TXCTL_AMPDU) { - lq_sta->total_success += tx_resp->ampdu_ack_map; + if (info->flags & IEEE80211_TX_CTL_AMPDU) { + lq_sta->total_success += info->status.ampdu_ack_map; lq_sta->total_failed += - (tx_resp->ampdu_ack_len - tx_resp->ampdu_ack_map); + (info->status.ampdu_ack_len - info->status.ampdu_ack_map); } else { if (status) lq_sta->total_success++; diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index fb670b5..ca9ca92 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -357,22 +357,22 @@ int iwl4965_hwrate_to_plcp_idx(u32 rate_n_flags) * translate ucode response to mac80211 tx status control values */ void iwl4965_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, - struct ieee80211_tx_control *control) + struct ieee80211_tx_info *control) { int rate_index; control->antenna_sel_tx = ((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS); if (rate_n_flags & RATE_MCS_HT_MSK) - control->flags |= IEEE80211_TXCTL_OFDM_HT; + control->flags |= IEEE80211_TX_CTL_OFDM_HT; if (rate_n_flags & RATE_MCS_GF_MSK) - control->flags |= IEEE80211_TXCTL_GREEN_FIELD; + control->flags |= IEEE80211_TX_CTL_GREEN_FIELD; if (rate_n_flags & RATE_MCS_FAT_MSK) - control->flags |= IEEE80211_TXCTL_40_MHZ_WIDTH; + control->flags |= IEEE80211_TX_CTL_40_MHZ_WIDTH; if (rate_n_flags & RATE_MCS_DUP_MSK) - control->flags |= IEEE80211_TXCTL_DUP_DATA; + control->flags |= IEEE80211_TX_CTL_DUP_DATA; if (rate_n_flags & RATE_MCS_SGI_MSK) - control->flags |= IEEE80211_TXCTL_SHORT_GI; + control->flags |= IEEE80211_TX_CTL_SHORT_GI; rate_index = iwl4965_hwrate_to_plcp_idx(rate_n_flags); if (control->band == IEEE80211_BAND_5GHZ) rate_index -= IWL_FIRST_OFDM_RATE; @@ -3007,7 +3007,7 @@ static int iwl4965_tx_status_reply_compressed_ba(struct iwl_priv *priv, u16 scd_flow = le16_to_cpu(ba_resp->scd_flow); u64 bitmap; int successes = 0; - struct ieee80211_tx_status *tx_status; + struct ieee80211_tx_info *info; if (unlikely(!agg->wait_for_ba)) { IWL_ERROR("Received BA when not expected\n"); @@ -3045,13 +3045,13 @@ static int iwl4965_tx_status_reply_compressed_ba(struct iwl_priv *priv, agg->start_idx + i); } - tx_status = &priv->txq[scd_flow].txb[agg->start_idx].status; - tx_status->flags = IEEE80211_TX_STATUS_ACK; - tx_status->flags |= IEEE80211_TX_STATUS_AMPDU; - tx_status->ampdu_ack_map = successes; - tx_status->ampdu_ack_len = agg->frame_count; - iwl4965_hwrate_to_tx_control(priv, agg->rate_n_flags, - &tx_status->control); + info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb[0]); + memset(&info->status, 0, sizeof(info->status)); + info->flags = IEEE80211_TX_STAT_ACK; + info->flags |= IEEE80211_TX_STAT_AMPDU; + info->status.ampdu_ack_map = successes; + info->status.ampdu_ack_len = agg->frame_count; + iwl4965_hwrate_to_tx_control(priv, agg->rate_n_flags, info); IWL_DEBUG_TX_REPLY("Bitmap %llx\n", (unsigned long long)bitmap); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index a8d062f..ad7422e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -207,8 +207,7 @@ void iwl_rx_allocate(struct iwl_priv *priv); * TX ******************************************************/ int iwl_txq_ctx_reset(struct iwl_priv *priv); -int iwl_tx_skb(struct iwl_priv *priv, - struct sk_buff *skb, struct ieee80211_tx_control *ctl); +int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb); /* FIXME: remove when free Tx is fully merged into iwlcore */ int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq); void iwl_hw_txq_ctx_free(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 820542b..f7fd8ea 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -119,7 +119,6 @@ struct iwl_queue { /* One for each TFD */ struct iwl_tx_info { - struct ieee80211_tx_status status; struct sk_buff *skb[MAX_NUM_OF_TBS]; }; @@ -693,7 +692,7 @@ extern unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, struct iwl_frame *frame, u8 rate); extern void iwl4965_hw_build_tx_cmd_rate(struct iwl_priv *priv, struct iwl_cmd *cmd, - struct ieee80211_tx_control *ctrl, + struct ieee80211_tx_info *info, struct ieee80211_hdr *hdr, int sta_id, int tx_id); extern int iwl4965_hw_reg_send_txpower(struct iwl_priv *priv); @@ -749,7 +748,7 @@ extern void iwl4965_update_rate_scaling(struct iwl_priv *priv, u8 mode); extern void iwl4965_rf_kill_ct_config(struct iwl_priv *priv); extern void iwl4965_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, - struct ieee80211_tx_control *control); + struct ieee80211_tx_info *info); #ifdef CONFIG_IWL4965_HT extern void iwl4965_init_ht_hw_capab(const struct iwl_priv *priv, diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 4b5149c..a61293b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -502,7 +502,7 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv) */ static void iwl_tx_cmd_build_basic(struct iwl_priv *priv, struct iwl_tx_cmd *tx_cmd, - struct ieee80211_tx_control *ctrl, + struct ieee80211_tx_info *info, struct ieee80211_hdr *hdr, int is_unicast, u8 std_id) { @@ -510,7 +510,7 @@ static void iwl_tx_cmd_build_basic(struct iwl_priv *priv, __le32 tx_flags = tx_cmd->tx_flags; tx_cmd->stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; - if (!(ctrl->flags & IEEE80211_TXCTL_NO_ACK)) { + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { tx_flags |= TX_CMD_FLG_ACK_MSK; if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; @@ -538,10 +538,10 @@ static void iwl_tx_cmd_build_basic(struct iwl_priv *priv, tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; } - if (ctrl->flags & IEEE80211_TXCTL_USE_RTS_CTS) { + if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { tx_flags |= TX_CMD_FLG_RTS_MSK; tx_flags &= ~TX_CMD_FLG_CTS_MSK; - } else if (ctrl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { + } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { tx_flags &= ~TX_CMD_FLG_RTS_MSK; tx_flags |= TX_CMD_FLG_CTS_MSK; } @@ -570,7 +570,7 @@ static void iwl_tx_cmd_build_basic(struct iwl_priv *priv, static void iwl_tx_cmd_build_rate(struct iwl_priv *priv, struct iwl_tx_cmd *tx_cmd, - struct ieee80211_tx_control *ctrl, + struct ieee80211_tx_info *info, u16 fc, int sta_id, int is_hcca) { @@ -580,7 +580,7 @@ static void iwl_tx_cmd_build_rate(struct iwl_priv *priv, u16 rate_flags = 0; int rate_idx; - rate_idx = min(ieee80211_get_tx_rate(priv->hw, ctrl)->hw_value & 0xffff, + rate_idx = min(ieee80211_get_tx_rate(priv->hw, info)->hw_value & 0xffff, IWL_RATE_COUNT - 1); rate_plcp = iwl_rates[rate_idx].plcp; @@ -637,18 +637,18 @@ static void iwl_tx_cmd_build_rate(struct iwl_priv *priv, } static void iwl_tx_cmd_build_hwcrypto(struct iwl_priv *priv, - struct ieee80211_tx_control *ctl, + struct ieee80211_tx_info *info, struct iwl_tx_cmd *tx_cmd, struct sk_buff *skb_frag, int sta_id) { - struct ieee80211_key_conf *keyconf = ctl->hw_key; + struct ieee80211_key_conf *keyconf = info->control.hw_key; switch (keyconf->alg) { case ALG_CCMP: tx_cmd->sec_ctl = TX_CMD_SEC_CCM; memcpy(tx_cmd->key, keyconf->key, keyconf->keylen); - if (ctl->flags & IEEE80211_TXCTL_AMPDU) + if (info->flags & IEEE80211_TX_CTL_AMPDU) tx_cmd->tx_flags |= TX_CMD_FLG_AGG_CCMP_MSK; IWL_DEBUG_TX("tx_cmd with aes hwcrypto\n"); break; @@ -690,13 +690,13 @@ static void iwl_update_tx_stats(struct iwl_priv *priv, u16 fc, u16 len) /* * start REPLY_TX command process */ -int iwl_tx_skb(struct iwl_priv *priv, - struct sk_buff *skb, struct ieee80211_tx_control *ctl) +int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl_tfd_frame *tfd; u32 *control_flags; - int txq_id = ctl->queue; + int txq_id = info->queue; struct iwl_tx_queue *txq = NULL; struct iwl_queue *q = NULL; dma_addr_t phys_addr; @@ -726,7 +726,7 @@ int iwl_tx_skb(struct iwl_priv *priv, goto drop_unlock; } - if ((ieee80211_get_tx_rate(priv->hw, ctl)->hw_value & 0xFF) == + if ((ieee80211_get_tx_rate(priv->hw, info)->hw_value & 0xFF) == IWL_INVALID_RATE) { IWL_ERROR("ERROR: No TX rate available.\n"); goto drop_unlock; @@ -782,7 +782,7 @@ int iwl_tx_skb(struct iwl_priv *priv, seq_number += 0x10; #ifdef CONFIG_IWL4965_HT /* aggregation is on for this */ - if (ctl->flags & IEEE80211_TXCTL_AMPDU) + if (info->flags & IEEE80211_TX_CTL_AMPDU) txq_id = priv->stations[sta_id].tid[tid].agg.txq_id; priv->stations[sta_id].tid[tid].tfds_in_queue++; #endif /* CONFIG_IWL4965_HT */ @@ -803,8 +803,6 @@ int iwl_tx_skb(struct iwl_priv *priv, /* Set up driver data for this TFD */ memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info)); txq->txb[q->write_ptr].skb[0] = skb; - memcpy(&(txq->txb[q->write_ptr].status.control), - ctl, sizeof(struct ieee80211_tx_control)); /* Set up first empty entry in queue's array of Tx/cmd buffers */ out_cmd = &txq->cmd[idx]; @@ -854,8 +852,8 @@ int iwl_tx_skb(struct iwl_priv *priv, * first entry */ iwl_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len); - if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) - iwl_tx_cmd_build_hwcrypto(priv, ctl, tx_cmd, skb, sta_id); + if (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT)) + iwl_tx_cmd_build_hwcrypto(priv, info, tx_cmd, skb, sta_id); /* Set up TFD's 2nd entry to point directly to remainder of skb, * if any (802.11 null frames have no payload). */ @@ -874,10 +872,10 @@ int iwl_tx_skb(struct iwl_priv *priv, len = (u16)skb->len; tx_cmd->len = cpu_to_le16(len); /* TODO need this for burst mode later on */ - iwl_tx_cmd_build_basic(priv, tx_cmd, ctl, hdr, unicast, sta_id); + iwl_tx_cmd_build_basic(priv, tx_cmd, info, hdr, unicast, sta_id); /* set is_hcca to 0; it probably will never be implemented */ - iwl_tx_cmd_build_rate(priv, tx_cmd, ctl, fc, sta_id, 0); + iwl_tx_cmd_build_rate(priv, tx_cmd, info, fc, sta_id, 0); iwl_update_tx_stats(priv, fc, len); @@ -919,7 +917,7 @@ int iwl_tx_skb(struct iwl_priv *priv, spin_unlock_irqrestore(&priv->lock, flags); } - ieee80211_stop_queue(priv->hw, ctl->queue); + ieee80211_stop_queue(priv->hw, info->queue); } return 0; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index a28b4c9..a740a18 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -2376,13 +2376,13 @@ static int iwl3945_set_mode(struct iwl3945_priv *priv, int mode) } static void iwl3945_build_tx_cmd_hwcrypto(struct iwl3945_priv *priv, - struct ieee80211_tx_control *ctl, + struct ieee80211_tx_info *info, struct iwl3945_cmd *cmd, struct sk_buff *skb_frag, int last_frag) { struct iwl3945_hw_key *keyinfo = - &priv->stations[ctl->hw_key->hw_key_idx].keyinfo; + &priv->stations[info->control.hw_key->hw_key_idx].keyinfo; switch (keyinfo->alg) { case ALG_CCMP: @@ -2405,7 +2405,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl3945_priv *priv, case ALG_WEP: cmd->cmd.tx.sec_ctl = TX_CMD_SEC_WEP | - (ctl->hw_key->hw_key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT; + (info->control.hw_key->hw_key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT; if (keyinfo->keylen == 13) cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128; @@ -2413,7 +2413,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl3945_priv *priv, memcpy(&cmd->cmd.tx.key[3], keyinfo->key, keyinfo->keylen); IWL_DEBUG_TX("Configuring packet for WEP encryption " - "with key %d\n", ctl->hw_key->hw_key_idx); + "with key %d\n", info->control.hw_key->hw_key_idx); break; default: @@ -2427,7 +2427,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl3945_priv *priv, */ static void iwl3945_build_tx_cmd_basic(struct iwl3945_priv *priv, struct iwl3945_cmd *cmd, - struct ieee80211_tx_control *ctrl, + struct ieee80211_tx_info *info, struct ieee80211_hdr *hdr, int is_unicast, u8 std_id) { @@ -2435,7 +2435,7 @@ static void iwl3945_build_tx_cmd_basic(struct iwl3945_priv *priv, __le32 tx_flags = cmd->cmd.tx.tx_flags; cmd->cmd.tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; - if (!(ctrl->flags & IEEE80211_TXCTL_NO_ACK)) { + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { tx_flags |= TX_CMD_FLG_ACK_MSK; if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; @@ -2459,10 +2459,10 @@ static void iwl3945_build_tx_cmd_basic(struct iwl3945_priv *priv, tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; } - if (ctrl->flags & IEEE80211_TXCTL_USE_RTS_CTS) { + if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { tx_flags |= TX_CMD_FLG_RTS_MSK; tx_flags &= ~TX_CMD_FLG_CTS_MSK; - } else if (ctrl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { + } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { tx_flags &= ~TX_CMD_FLG_RTS_MSK; tx_flags |= TX_CMD_FLG_CTS_MSK; } @@ -2546,13 +2546,13 @@ static int iwl3945_get_sta_id(struct iwl3945_priv *priv, struct ieee80211_hdr *h /* * start REPLY_TX command process */ -static int iwl3945_tx_skb(struct iwl3945_priv *priv, - struct sk_buff *skb, struct ieee80211_tx_control *ctl) +static int iwl3945_tx_skb(struct iwl3945_priv *priv, struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl3945_tfd_frame *tfd; u32 *control_flags; - int txq_id = ctl->queue; + int txq_id = info->queue; struct iwl3945_tx_queue *txq = NULL; struct iwl3945_queue *q = NULL; dma_addr_t phys_addr; @@ -2581,7 +2581,7 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, goto drop_unlock; } - if ((ieee80211_get_tx_rate(priv->hw, ctl)->hw_value & 0xFF) == IWL_INVALID_RATE) { + if ((ieee80211_get_tx_rate(priv->hw, info)->hw_value & 0xFF) == IWL_INVALID_RATE) { IWL_ERROR("ERROR: No TX rate available.\n"); goto drop_unlock; } @@ -2650,8 +2650,6 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, /* Set up driver data for this TFD */ memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl3945_tx_info)); txq->txb[q->write_ptr].skb[0] = skb; - memcpy(&(txq->txb[q->write_ptr].status.control), - ctl, sizeof(struct ieee80211_tx_control)); /* Init first empty entry in queue's array of Tx/cmd buffers */ out_cmd = &txq->cmd[idx]; @@ -2700,8 +2698,8 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, * first entry */ iwl3945_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len); - if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) - iwl3945_build_tx_cmd_hwcrypto(priv, ctl, out_cmd, skb, 0); + if (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT)) + iwl3945_build_tx_cmd_hwcrypto(priv, info, out_cmd, skb, 0); /* Set up TFD's 2nd entry to point directly to remainder of skb, * if any (802.11 null frames have no payload). */ @@ -2726,10 +2724,10 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, out_cmd->cmd.tx.len = cpu_to_le16(len); /* TODO need this for burst mode later on */ - iwl3945_build_tx_cmd_basic(priv, out_cmd, ctl, hdr, unicast, sta_id); + iwl3945_build_tx_cmd_basic(priv, out_cmd, info, hdr, unicast, sta_id); /* set is_hcca to 0; it probably will never be implemented */ - iwl3945_hw_build_tx_cmd_rate(priv, out_cmd, ctl, hdr, sta_id, 0); + iwl3945_hw_build_tx_cmd_rate(priv, out_cmd, info, hdr, sta_id, 0); out_cmd->cmd.tx.tx_flags &= ~TX_CMD_FLG_ANT_A_MSK; out_cmd->cmd.tx.tx_flags &= ~TX_CMD_FLG_ANT_B_MSK; @@ -2767,7 +2765,7 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, spin_unlock_irqrestore(&priv->lock, flags); } - ieee80211_stop_queue(priv->hw, ctl->queue); + ieee80211_stop_queue(priv->hw, info->queue); } return 0; @@ -3230,7 +3228,7 @@ static void iwl3945_bg_beacon_update(struct work_struct *work) struct sk_buff *beacon; /* Pull updated AP beacon from mac80211. will fail if not in AP mode */ - beacon = ieee80211_beacon_get(priv->hw, priv->vif, NULL); + beacon = ieee80211_beacon_get(priv->hw, priv->vif); if (!beacon) { IWL_ERROR("update beacon failed\n"); @@ -6681,8 +6679,7 @@ static void iwl3945_mac_stop(struct ieee80211_hw *hw) IWL_DEBUG_MAC80211("leave\n"); } -static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *ctl) +static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct iwl3945_priv *priv = hw->priv; @@ -6694,9 +6691,9 @@ static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, } IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, - ieee80211_get_tx_rate(hw, ctl)->bitrate); + ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate); - if (iwl3945_tx_skb(priv, skb, ctl)) + if (iwl3945_tx_skb(priv, skb)) dev_kfree_skb_any(skb); IWL_DEBUG_MAC80211("leave\n"); @@ -7333,8 +7330,7 @@ static void iwl3945_mac_reset_tsf(struct ieee80211_hw *hw) } -static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *control) +static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) { struct iwl3945_priv *priv = hw->priv; unsigned long flags; diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 1fad622..07c52b6 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -1606,17 +1606,7 @@ static int iwl4965_get_measurement(struct iwl_priv *priv, static void iwl4965_txstatus_to_ieee(struct iwl_priv *priv, struct iwl_tx_info *tx_sta) { - - tx_sta->status.ack_signal = 0; - tx_sta->status.excessive_retries = 0; - - if (in_interrupt()) - ieee80211_tx_status_irqsafe(priv->hw, - tx_sta->skb[0], &(tx_sta->status)); - else - ieee80211_tx_status(priv->hw, - tx_sta->skb[0], &(tx_sta->status)); - + ieee80211_tx_status_irqsafe(priv->hw, tx_sta->skb[0]); tx_sta->skb[0] = NULL; } @@ -1710,7 +1700,7 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv, { u16 status; struct agg_tx_status *frame_status = &tx_resp->status; - struct ieee80211_tx_status *tx_status = NULL; + struct ieee80211_tx_info *info = NULL; struct ieee80211_hdr *hdr = NULL; int i, sh; int txq_id, idx; @@ -1736,14 +1726,14 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv, IWL_DEBUG_TX_REPLY("FrameCnt = %d, StartIdx=%d idx=%d\n", agg->frame_count, agg->start_idx, idx); - tx_status = &(priv->txq[txq_id].txb[idx].status); - tx_status->retry_count = tx_resp->failure_frame; - tx_status->control.flags &= ~IEEE80211_TXCTL_AMPDU; - tx_status->flags = iwl4965_is_tx_success(status)? - IEEE80211_TX_STATUS_ACK : 0; + info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]); + info->status.retry_count = tx_resp->failure_frame; + info->flags &= ~IEEE80211_TX_CTL_AMPDU; + info->flags |= iwl4965_is_tx_success(status)? + IEEE80211_TX_STAT_ACK : 0; iwl4965_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags), - &tx_status->control); + info); /* FIXME: code repetition end */ IWL_DEBUG_TX_REPLY("1 Frame 0x%x failure :%d\n", @@ -1830,7 +1820,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, int txq_id = SEQ_TO_QUEUE(sequence); int index = SEQ_TO_INDEX(sequence); struct iwl_tx_queue *txq = &priv->txq[txq_id]; - struct ieee80211_tx_status *tx_status; + struct ieee80211_tx_info *info; struct iwl4965_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; u32 status = le32_to_cpu(tx_resp->status); #ifdef CONFIG_IWL4965_HT @@ -1848,6 +1838,9 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, return; } + info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]); + memset(&info->status, 0, sizeof(info->status)); + #ifdef CONFIG_IWL4965_HT hdr = iwl4965_tx_queue_get_hdr(priv, txq_id, index); fc = le16_to_cpu(hdr->frame_control); @@ -1902,13 +1895,12 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, } } else { #endif /* CONFIG_IWL4965_HT */ - tx_status = &(txq->txb[txq->q.read_ptr].status); - tx_status->retry_count = tx_resp->failure_frame; - tx_status->flags = - iwl4965_is_tx_success(status) ? IEEE80211_TX_STATUS_ACK : 0; + info->status.retry_count = tx_resp->failure_frame; + info->flags |= + iwl4965_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0; iwl4965_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags), - &tx_status->control); + info); IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) rate_n_flags 0x%x " "retries %d\n", txq_id, iwl4965_get_tx_fail_reason(status), @@ -2053,7 +2045,7 @@ static void iwl4965_bg_beacon_update(struct work_struct *work) struct sk_buff *beacon; /* Pull updated AP beacon from mac80211. will fail if not in AP mode */ - beacon = ieee80211_beacon_get(priv->hw, priv->vif, NULL); + beacon = ieee80211_beacon_get(priv->hw, priv->vif); if (!beacon) { IWL_ERROR("update beacon failed\n"); @@ -4268,8 +4260,7 @@ static void iwl4965_mac_stop(struct ieee80211_hw *hw) IWL_DEBUG_MAC80211("leave\n"); } -static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *ctl) +static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct iwl_priv *priv = hw->priv; @@ -4281,9 +4272,9 @@ static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, } IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, - ieee80211_get_tx_rate(hw, ctl)->bitrate); + ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate); - if (iwl_tx_skb(priv, skb, ctl)) + if (iwl_tx_skb(priv, skb)) dev_kfree_skb_any(skb); IWL_DEBUG_MAC80211("leave\n"); @@ -5065,8 +5056,7 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw) IWL_DEBUG_MAC80211("leave\n"); } -static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *control) +static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) { struct iwl_priv *priv = hw->priv; unsigned long flags; diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 3ca9386..8508579 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -394,7 +394,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) while (entry != (struct sk_buff *)&priv->tx_queue) { range = (struct memrecord *)&entry->cb; if (range->start_addr == addr) { - struct ieee80211_tx_status status; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry); struct p54_control_hdr *entry_hdr; struct p54_tx_control_allocdata *entry_data; int pad = 0; @@ -406,30 +406,23 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) last_addr = range->end_addr; __skb_unlink(entry, &priv->tx_queue); - if (!range->control) { - kfree_skb(entry); - break; - } - memset(&status, 0, sizeof(status)); - memcpy(&status.control, range->control, - sizeof(status.control)); - kfree(range->control); - priv->tx_stats[status.control.queue].len--; + memset(&info->status, 0, sizeof(info->status)); + priv->tx_stats[info->queue].len--; entry_hdr = (struct p54_control_hdr *) entry->data; entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data; if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0) pad = entry_data->align[0]; - if (!(status.control.flags & IEEE80211_TXCTL_NO_ACK)) { + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { if (!(payload->status & 0x01)) - status.flags |= IEEE80211_TX_STATUS_ACK; + info->flags |= IEEE80211_TX_STAT_ACK; else - status.excessive_retries = 1; + info->status.excessive_retries = 1; } - status.retry_count = payload->retries - 1; - status.ack_signal = le16_to_cpu(payload->ack_rssi); + info->status.retry_count = payload->retries - 1; + info->status.ack_signal = le16_to_cpu(payload->ack_rssi); skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data)); - ieee80211_tx_status_irqsafe(dev, entry, &status); + ieee80211_tx_status_irqsafe(dev, entry); break; } else last_addr = range->end_addr; @@ -494,13 +487,11 @@ EXPORT_SYMBOL_GPL(p54_rx); * allocated areas. */ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, - struct p54_control_hdr *data, u32 len, - struct ieee80211_tx_control *control) + struct p54_control_hdr *data, u32 len) { struct p54_common *priv = dev->priv; struct sk_buff *entry = priv->tx_queue.next; struct sk_buff *target_skb = NULL; - struct memrecord *range; u32 last_addr = priv->rx_start; u32 largest_hole = 0; u32 target_addr = priv->rx_start; @@ -512,7 +503,8 @@ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, left = skb_queue_len(&priv->tx_queue); while (left--) { u32 hole_size; - range = (struct memrecord *)&entry->cb; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry); + struct memrecord *range = (void *)info->driver_data; hole_size = range->start_addr - last_addr; if (!target_skb && hole_size >= len) { target_skb = entry->prev; @@ -527,17 +519,18 @@ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, target_skb = priv->tx_queue.prev; largest_hole = max(largest_hole, priv->rx_end - last_addr - len); if (!skb_queue_empty(&priv->tx_queue)) { - range = (struct memrecord *)&target_skb->cb; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(target_skb); + struct memrecord *range = (void *)info->driver_data; target_addr = range->end_addr; } } else largest_hole = max(largest_hole, priv->rx_end - last_addr); if (skb) { - range = (struct memrecord *)&skb->cb; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct memrecord *range = (void *)info->driver_data; range->start_addr = target_addr; range->end_addr = target_addr + len; - range->control = control; __skb_queue_after(&priv->tx_queue, target_skb, skb); if (largest_hole < IEEE80211_MAX_RTS_THRESHOLD + 0x170 + sizeof(struct p54_control_hdr)) @@ -548,32 +541,27 @@ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, data->req_id = cpu_to_le32(target_addr + 0x70); } -static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb, - struct ieee80211_tx_control *control) +static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_queue_stats *current_queue; struct p54_common *priv = dev->priv; struct p54_control_hdr *hdr; struct p54_tx_control_allocdata *txhdr; - struct ieee80211_tx_control *control_copy; size_t padding, len; u8 rate; - current_queue = &priv->tx_stats[control->queue]; + current_queue = &priv->tx_stats[info->queue]; if (unlikely(current_queue->len > current_queue->limit)) return NETDEV_TX_BUSY; current_queue->len++; current_queue->count++; if (current_queue->len == current_queue->limit) - ieee80211_stop_queue(dev, control->queue); + ieee80211_stop_queue(dev, info->queue); padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3; len = skb->len; - control_copy = kmalloc(sizeof(*control), GFP_ATOMIC); - if (control_copy) - memcpy(control_copy, control, sizeof(*control)); - txhdr = (struct p54_tx_control_allocdata *) skb_push(skb, sizeof(*txhdr) + padding); hdr = (struct p54_control_hdr *) skb_push(skb, sizeof(*hdr)); @@ -583,35 +571,37 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb, else hdr->magic1 = cpu_to_le16(0x0010); hdr->len = cpu_to_le16(len); - hdr->type = (control->flags & IEEE80211_TXCTL_NO_ACK) ? 0 : cpu_to_le16(1); - hdr->retry1 = hdr->retry2 = control->retry_limit; - p54_assign_address(dev, skb, hdr, skb->len, control_copy); + hdr->type = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? 0 : cpu_to_le16(1); + hdr->retry1 = hdr->retry2 = info->control.retry_limit; memset(txhdr->wep_key, 0x0, 16); txhdr->padding = 0; txhdr->padding2 = 0; /* TODO: add support for alternate retry TX rates */ - rate = ieee80211_get_tx_rate(dev, control)->hw_value; - if (control->flags & IEEE80211_TXCTL_SHORT_PREAMBLE) + rate = ieee80211_get_tx_rate(dev, info)->hw_value; + if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE) rate |= 0x10; - if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) + if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) rate |= 0x40; - else if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) + else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) rate |= 0x20; memset(txhdr->rateset, rate, 8); txhdr->wep_key_present = 0; txhdr->wep_key_len = 0; - txhdr->frame_type = cpu_to_le32(control->queue + 4); + txhdr->frame_type = cpu_to_le32(info->queue + 4); txhdr->magic4 = 0; - txhdr->antenna = (control->antenna_sel_tx == 0) ? - 2 : control->antenna_sel_tx - 1; + txhdr->antenna = (info->antenna_sel_tx == 0) ? + 2 : info->antenna_sel_tx - 1; txhdr->output_power = 0x7f; // HW Maximum - txhdr->magic5 = (control->flags & IEEE80211_TXCTL_NO_ACK) ? + txhdr->magic5 = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? 0 : ((rate > 0x3) ? cpu_to_le32(0x33) : cpu_to_le32(0x23)); if (padding) txhdr->align[0] = padding; + /* modifies skb->cb and with it info, so must be last! */ + p54_assign_address(dev, skb, hdr, skb->len); + priv->tx(dev, hdr, skb->len, 0); return 0; } @@ -634,7 +624,7 @@ static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type, filter = (struct p54_tx_control_filter *) hdr->data; hdr->magic1 = cpu_to_le16(0x8001); hdr->len = cpu_to_le16(sizeof(*filter)); - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*filter), NULL); + p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*filter)); hdr->type = cpu_to_le16(P54_CONTROL_TYPE_FILTER_SET); filter->filter_type = cpu_to_le16(filter_type); @@ -678,7 +668,7 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq) hdr->magic1 = cpu_to_le16(0x8001); hdr->len = cpu_to_le16(sizeof(*chan)); hdr->type = cpu_to_le16(P54_CONTROL_TYPE_CHANNEL_CHANGE); - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + payload_len, NULL); + p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + payload_len); chan->magic1 = cpu_to_le16(0x1); chan->magic2 = cpu_to_le16(0x0); @@ -751,7 +741,7 @@ static int p54_set_leds(struct ieee80211_hw *dev, int mode, int link, int act) hdr->magic1 = cpu_to_le16(0x8001); hdr->len = cpu_to_le16(sizeof(*led)); hdr->type = cpu_to_le16(P54_CONTROL_TYPE_LED); - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*led), NULL); + p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*led)); led = (struct p54_tx_control_led *) hdr->data; led->mode = cpu_to_le16(mode); @@ -801,7 +791,7 @@ static void p54_set_vdcf(struct ieee80211_hw *dev) hdr = (void *)priv->cached_vdcf + priv->tx_hdr_len; - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*vdcf), NULL); + p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*vdcf)); vdcf = (struct p54_tx_control_vdcf *) hdr->data; @@ -837,12 +827,8 @@ static void p54_stop(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; struct sk_buff *skb; - while ((skb = skb_dequeue(&priv->tx_queue))) { - struct memrecord *range = (struct memrecord *)&skb->cb; - if (range->control) - kfree(range->control); + while ((skb = skb_dequeue(&priv->tx_queue))) kfree_skb(skb); - } priv->stop(dev); priv->mode = IEEE80211_IF_TYPE_INVALID; } diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index c15b56e..2245fcc 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h @@ -152,7 +152,6 @@ struct pda_pa_curve_data { struct memrecord { u32 start_addr; u32 end_addr; - struct ieee80211_tx_control *control; }; struct p54_eeprom_lm86 { diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 4fcba9b..900140d 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1484,11 +1484,11 @@ static u64 rt2400pci_get_tsf(struct ieee80211_hw *hw) return tsf; } -static int rt2400pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *control) +static int rt2400pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) { struct rt2x00_dev *rt2x00dev = hw->priv; - struct rt2x00_intf *intf = vif_to_intf(control->vif); + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif); struct queue_entry_priv_pci *entry_priv; struct skb_frame_desc *skbdesc; struct txentry_desc txdesc; @@ -1504,7 +1504,7 @@ static int rt2400pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, * for our information. */ intf->beacon->skb = skb; - rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc, control); + rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc); /* * Fill in skb descriptor diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 06e87cd..6733509 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1799,11 +1799,11 @@ static u64 rt2500pci_get_tsf(struct ieee80211_hw *hw) return tsf; } -static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *control) +static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) { struct rt2x00_dev *rt2x00dev = hw->priv; - struct rt2x00_intf *intf = vif_to_intf(control->vif); + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif); struct queue_entry_priv_pci *entry_priv; struct skb_frame_desc *skbdesc; struct txentry_desc txdesc; @@ -1820,7 +1820,7 @@ static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, * for our information. */ intf->beacon->skb = skb; - rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc, control); + rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc); /* * Fill in skb descriptor diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 4122c5e..cca1504 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1666,13 +1666,12 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ -static int rt2500usb_beacon_update(struct ieee80211_hw *hw, - struct sk_buff *skb, - struct ieee80211_tx_control *control) +static int rt2500usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) { struct rt2x00_dev *rt2x00dev = hw->priv; struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev); - struct rt2x00_intf *intf = vif_to_intf(control->vif); + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif); struct queue_entry_priv_usb_bcn *bcn_priv; struct skb_frame_desc *skbdesc; struct txentry_desc txdesc; @@ -1691,7 +1690,7 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw, * for our information. */ intf->beacon->skb = skb; - rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc, control); + rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc); /* * Add the descriptor in front of the skb. diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 1900d4c..5c7220e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -542,8 +542,7 @@ struct rt2x00lib_ops { struct sk_buff *skb, struct txentry_desc *txdesc); int (*write_tx_data) (struct rt2x00_dev *rt2x00dev, - struct data_queue *queue, struct sk_buff *skb, - struct ieee80211_tx_control *control); + struct data_queue *queue, struct sk_buff *skb); int (*get_tx_data_len) (struct rt2x00_dev *rt2x00dev, struct sk_buff *skb); void (*kick_tx_queue) (struct rt2x00_dev *rt2x00dev, @@ -930,7 +929,6 @@ static inline u16 get_duration_res(const unsigned int size, const u8 rate) * rt2x00queue_create_tx_descriptor - Create TX descriptor from mac80211 input * @entry: The entry which will be used to transfer the TX frame. * @txdesc: rt2x00 TX descriptor which will be initialized by this function. - * @control: mac80211 TX control structure from where we read the information. * * This function will initialize the &struct txentry_desc based on information * from mac80211. This descriptor can then be used by rt2x00lib and the drivers @@ -943,8 +941,7 @@ static inline u16 get_duration_res(const unsigned int size, const u8 rate) * the &struct txentry_desc structure. */ void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, - struct txentry_desc *txdesc, - struct ieee80211_tx_control *control); + struct txentry_desc *txdesc); /** * rt2x00queue_write_tx_descriptor - Write TX descriptor to hardware @@ -1001,8 +998,7 @@ void rt2x00lib_rxdone(struct queue_entry *entry, /* * mac80211 handlers. */ -int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *control); +int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb); int rt2x00mac_start(struct ieee80211_hw *hw); void rt2x00mac_stop(struct ieee80211_hw *hw); int rt2x00mac_add_interface(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index d341764..69e2336 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -415,7 +415,6 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac, struct rt2x00_dev *rt2x00dev = data; struct rt2x00_intf *intf = vif_to_intf(vif); struct sk_buff *skb; - struct ieee80211_tx_control control; struct ieee80211_bss_conf conf; int delayed_flags; @@ -433,9 +432,9 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac, spin_unlock(&intf->lock); if (delayed_flags & DELAYED_UPDATE_BEACON) { - skb = ieee80211_beacon_get(rt2x00dev->hw, vif, &control); - if (skb && rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, - skb, &control)) + skb = ieee80211_beacon_get(rt2x00dev->hw, vif); + if (skb && + rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, skb)) dev_kfree_skb(skb); } @@ -494,8 +493,13 @@ void rt2x00lib_txdone(struct queue_entry *entry, struct txdone_entry_desc *txdesc) { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; - struct skb_frame_desc *skbdesc; - struct ieee80211_tx_status tx_status; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); + + /* + * Send frame to debugfs immediately, after this call is completed + * we are going to overwrite the skb->cb array. + */ + rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TXDONE, entry->skb); /* * Update TX statistics. @@ -508,21 +512,20 @@ void rt2x00lib_txdone(struct queue_entry *entry, /* * Initialize TX status */ - tx_status.flags = 0; - tx_status.ack_signal = 0; - tx_status.excessive_retries = + memset(&tx_info->status, 0, sizeof(tx_info->status)); + tx_info->status.ack_signal = 0; + tx_info->status.excessive_retries = test_bit(TXDONE_EXCESSIVE_RETRY, &txdesc->flags); - tx_status.retry_count = txdesc->retry; - memcpy(&tx_status.control, txdesc->control, sizeof(*txdesc->control)); + tx_info->status.retry_count = txdesc->retry; - if (!(tx_status.control.flags & IEEE80211_TXCTL_NO_ACK)) { + if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) { if (test_bit(TXDONE_SUCCESS, &txdesc->flags)) - tx_status.flags |= IEEE80211_TX_STATUS_ACK; + tx_info->flags |= IEEE80211_TX_STAT_ACK; else if (test_bit(TXDONE_FAILURE, &txdesc->flags)) rt2x00dev->low_level_stats.dot11ACKFailureCount++; } - if (tx_status.control.flags & IEEE80211_TXCTL_USE_RTS_CTS) { + if (tx_info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { if (test_bit(TXDONE_SUCCESS, &txdesc->flags)) rt2x00dev->low_level_stats.dot11RTSSuccessCount++; else if (test_bit(TXDONE_FAILURE, &txdesc->flags)) @@ -530,19 +533,13 @@ void rt2x00lib_txdone(struct queue_entry *entry, } /* - * Send the tx_status to debugfs. Only send the status report - * to mac80211 when the frame originated from there. If this was - * a extra frame coming through a mac80211 library call (RTS/CTS) - * then we should not send the status report back. - * If send to mac80211, mac80211 will clean up the skb structure, - * otherwise we have to do it ourself. + * Only send the status report to mac80211 when TX status was + * requested by it. If this was a extra frame coming through + * a mac80211 library call (RTS/CTS) then we should not send the + * status report back. */ - rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TXDONE, entry->skb); - - skbdesc = get_skb_frame_desc(entry->skb); - if (!(skbdesc->flags & FRAME_DESC_DRIVER_GENERATED)) - ieee80211_tx_status_irqsafe(rt2x00dev->hw, - entry->skb, &tx_status); + if (tx_info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) + ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb); else dev_kfree_skb_irq(entry->skb); entry->skb = NULL; diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index c5cedb2..b5379b0 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -31,14 +31,15 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, struct data_queue *queue, - struct sk_buff *frag_skb, - struct ieee80211_tx_control *control) + struct sk_buff *frag_skb) { + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(frag_skb); struct skb_frame_desc *skbdesc; + struct ieee80211_tx_info *rts_info; struct sk_buff *skb; int size; - if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) + if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) size = sizeof(struct ieee80211_cts); else size = sizeof(struct ieee80211_rts); @@ -52,13 +53,33 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, skb_reserve(skb, rt2x00dev->hw->extra_tx_headroom); skb_put(skb, size); - if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) - ieee80211_ctstoself_get(rt2x00dev->hw, control->vif, - frag_skb->data, frag_skb->len, control, + /* + * Copy TX information over from original frame to + * RTS/CTS frame. Note that we set the no encryption flag + * since we don't want this frame to be encrypted. + * RTS frames should be acked, while CTS-to-self frames + * should not. The ready for TX flag is cleared to prevent + * it being automatically send when the descriptor is + * written to the hardware. + */ + memcpy(skb->cb, frag_skb->cb, sizeof(skb->cb)); + rts_info = IEEE80211_SKB_CB(skb); + rts_info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT; + rts_info->flags &= ~IEEE80211_TX_CTL_USE_CTS_PROTECT; + rts_info->flags &= ~IEEE80211_TX_CTL_REQ_TX_STATUS; + + if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) + rts_info->flags |= IEEE80211_TX_CTL_NO_ACK; + else + rts_info->flags &= ~IEEE80211_TX_CTL_NO_ACK; + + if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) + ieee80211_ctstoself_get(rt2x00dev->hw, tx_info->control.vif, + frag_skb->data, size, tx_info, (struct ieee80211_cts *)(skb->data)); else - ieee80211_rts_get(rt2x00dev->hw, control->vif, - frag_skb->data, frag_skb->len, control, + ieee80211_rts_get(rt2x00dev->hw, tx_info->control.vif, + frag_skb->data, size, tx_info, (struct ieee80211_rts *)(skb->data)); /* @@ -68,7 +89,7 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, memset(skbdesc, 0, sizeof(*skbdesc)); skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED; - if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, queue, skb, control)) { + if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, queue, skb)) { WARNING(rt2x00dev, "Failed to send RTS/CTS frame.\n"); return NETDEV_TX_BUSY; } @@ -76,14 +97,13 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, return NETDEV_TX_OK; } -int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *control) +int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct rt2x00_dev *rt2x00dev = hw->priv; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data; - enum data_queue_qid qid = mac80211_queue_to_qid(control->queue); + enum data_queue_qid qid = mac80211_queue_to_qid(tx_info->queue); struct data_queue *queue; - struct skb_frame_desc *skbdesc; u16 frame_control; /* @@ -100,7 +120,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, /* * Determine which queue to put packet on. */ - if (control->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM && + if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM && test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags)) queue = rt2x00queue_get_queue(rt2x00dev, QID_ATIM); else @@ -125,33 +145,27 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, */ frame_control = le16_to_cpu(ieee80211hdr->frame_control); if (!is_rts_frame(frame_control) && !is_cts_frame(frame_control) && - (control->flags & (IEEE80211_TXCTL_USE_RTS_CTS | - IEEE80211_TXCTL_USE_CTS_PROTECT)) && + (tx_info->flags & (IEEE80211_TX_CTL_USE_RTS_CTS | + IEEE80211_TX_CTL_USE_CTS_PROTECT)) && !rt2x00dev->ops->hw->set_rts_threshold) { if (rt2x00queue_available(queue) <= 1) { - ieee80211_stop_queue(rt2x00dev->hw, control->queue); + ieee80211_stop_queue(rt2x00dev->hw, tx_info->queue); return NETDEV_TX_BUSY; } - if (rt2x00mac_tx_rts_cts(rt2x00dev, queue, skb, control)) { - ieee80211_stop_queue(rt2x00dev->hw, control->queue); + if (rt2x00mac_tx_rts_cts(rt2x00dev, queue, skb)) { + ieee80211_stop_queue(rt2x00dev->hw, tx_info->queue); return NETDEV_TX_BUSY; } } - /* - * Initialize skb descriptor - */ - skbdesc = get_skb_frame_desc(skb); - memset(skbdesc, 0, sizeof(*skbdesc)); - - if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, queue, skb, control)) { - ieee80211_stop_queue(rt2x00dev->hw, control->queue); + if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, queue, skb)) { + ieee80211_stop_queue(rt2x00dev->hw, tx_info->queue); return NETDEV_TX_BUSY; } if (rt2x00queue_full(queue)) - ieee80211_stop_queue(rt2x00dev->hw, control->queue); + ieee80211_stop_queue(rt2x00dev->hw, tx_info->queue); if (rt2x00dev->ops->lib->kick_tx_queue) rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, qid); @@ -380,9 +394,7 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw, if (conf->type != IEEE80211_IF_TYPE_AP || !conf->beacon) return 0; - status = rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, - conf->beacon, - conf->beacon_control); + status = rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, conf->beacon); if (status) dev_kfree_skb(conf->beacon); diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index fa7de41..70a3d13 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -35,8 +35,7 @@ * TX data handlers. */ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev, - struct data_queue *queue, struct sk_buff *skb, - struct ieee80211_tx_control *control) + struct data_queue *queue, struct sk_buff *skb) { struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); struct queue_entry_priv_pci *entry_priv = entry->priv_data; @@ -64,19 +63,19 @@ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev, * for our information. */ entry->skb = skb; - rt2x00queue_create_tx_descriptor(entry, &txdesc, control); + rt2x00queue_create_tx_descriptor(entry, &txdesc); /* * Fill in skb descriptor */ skbdesc = get_skb_frame_desc(skb); + memset(skbdesc, 0, sizeof(*skbdesc)); skbdesc->data = skb->data; skbdesc->data_len = skb->len; skbdesc->desc = entry_priv->desc; skbdesc->desc_len = queue->desc_size; skbdesc->entry = entry; - memcpy(&entry_priv->control, control, sizeof(entry_priv->control)); memcpy(entry_priv->data, skb->data, skb->len); rt2x00queue_write_tx_descriptor(entry, &txdesc); @@ -164,9 +163,9 @@ void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry, struct txdone_entry_desc *txdesc) { struct queue_entry_priv_pci *entry_priv = entry->priv_data; + enum data_queue_qid qid = skb_get_queue_mapping(entry->skb); u32 word; - txdesc->control = &entry_priv->control; rt2x00lib_txdone(entry, txdesc); /* @@ -187,7 +186,7 @@ void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry, * is reenabled when the txdone handler has finished. */ if (!rt2x00queue_full(entry->queue)) - ieee80211_wake_queue(rt2x00dev->hw, entry_priv->control.queue); + ieee80211_wake_queue(rt2x00dev->hw, qid); } EXPORT_SYMBOL_GPL(rt2x00pci_txdone); diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h index 557d15a..37c851e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.h +++ b/drivers/net/wireless/rt2x00/rt2x00pci.h @@ -91,8 +91,7 @@ rt2x00pci_register_multiwrite(struct rt2x00_dev *rt2x00dev, * TX data handlers. */ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev, - struct data_queue *queue, struct sk_buff *skb, - struct ieee80211_tx_control *control); + struct data_queue *queue, struct sk_buff *skb); /** * struct queue_entry_priv_pci: Per entry PCI specific information @@ -101,7 +100,6 @@ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev, * @desc_dma: DMA pointer to &desc. * @data: Pointer to device's entry memory. * @data_dma: DMA pointer to &data. - * @control: mac80211 control structure used to transmit data. */ struct queue_entry_priv_pci { __le32 *desc; @@ -109,8 +107,6 @@ struct queue_entry_priv_pci { void *data; dma_addr_t data_dma; - - struct ieee80211_tx_control control; }; /** diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 5cf4c2f..e69ef4b 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -30,13 +30,13 @@ #include "rt2x00lib.h" void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, - struct txentry_desc *txdesc, - struct ieee80211_tx_control *control) + struct txentry_desc *txdesc) { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data; struct ieee80211_rate *rate = - ieee80211_get_tx_rate(rt2x00dev->hw, control); + ieee80211_get_tx_rate(rt2x00dev->hw, tx_info); const struct rt2x00_rate *hwrate; unsigned int data_length; unsigned int duration; @@ -64,7 +64,7 @@ void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, /* * Check whether this frame is to be acked. */ - if (!(control->flags & IEEE80211_TXCTL_NO_ACK)) + if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) __set_bit(ENTRY_TXD_ACK, &txdesc->flags); /* @@ -72,23 +72,20 @@ void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, */ if (is_rts_frame(frame_control) || is_cts_frame(frame_control)) { __set_bit(ENTRY_TXD_BURST, &txdesc->flags); - if (is_rts_frame(frame_control)) { + if (is_rts_frame(frame_control)) __set_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags); - __set_bit(ENTRY_TXD_ACK, &txdesc->flags); - } else { + else __set_bit(ENTRY_TXD_CTS_FRAME, &txdesc->flags); - __clear_bit(ENTRY_TXD_ACK, &txdesc->flags); - } - if (control->rts_cts_rate_idx >= 0) + if (tx_info->control.rts_cts_rate_idx >= 0) rate = - ieee80211_get_rts_cts_rate(rt2x00dev->hw, control); + ieee80211_get_rts_cts_rate(rt2x00dev->hw, tx_info); } /* * Determine retry information. */ - txdesc->retry_limit = control->retry_limit; - if (control->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT) + txdesc->retry_limit = tx_info->control.retry_limit; + if (tx_info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT) __set_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags); /* @@ -113,7 +110,7 @@ void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, */ if (test_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags)) { txdesc->ifs = IFS_SIFS; - } else if (control->flags & IEEE80211_TXCTL_FIRST_FRAGMENT) { + } else if (tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) { __set_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags); txdesc->ifs = IFS_BACKOFF; } else { @@ -179,8 +176,10 @@ void rt2x00queue_write_tx_descriptor(struct queue_entry *entry, /* * We are done writing the frame to the queue entry, - * if this entry is a RTS of CTS-to-self frame we are done, - * otherwise we need to kick the queue. + * also kick the queue in case the correct flags are set, + * note that this will automatically filter beacons and + * RTS/CTS frames since those frames don't have this flag + * set. */ if (rt2x00dev->ops->lib->kick_tx_queue && !(skbdesc->flags & FRAME_DESC_DRIVER_GENERATED)) diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index c6edc52..f263fe4 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -105,8 +105,8 @@ enum skb_frame_desc_flags { /** * struct skb_frame_desc: Descriptor information for the skb buffer * - * This structure is placed over the skb->cb array, this means that - * this structure should not exceed the size of that array (48 bytes). + * This structure is placed over the driver_data array, this means that + * this structure should not exceed the size of that array (40 bytes). * * @flags: Frame flags, see &enum skb_frame_desc_flags. * @data: Pointer to data part of frame (Start of ieee80211 header). @@ -129,10 +129,15 @@ struct skb_frame_desc { struct queue_entry *entry; }; +/** + * get_skb_frame_desc - Obtain the rt2x00 frame descriptor from a sk_buff. + * @skb: &struct sk_buff from where we obtain the &struct skb_frame_desc + */ static inline struct skb_frame_desc* get_skb_frame_desc(struct sk_buff *skb) { - BUILD_BUG_ON(sizeof(struct skb_frame_desc) > sizeof(skb->cb)); - return (struct skb_frame_desc *)&skb->cb[0]; + BUILD_BUG_ON(sizeof(struct skb_frame_desc) > + IEEE80211_TX_INFO_DRIVER_DATA_SIZE); + return (struct skb_frame_desc *)&IEEE80211_SKB_CB(skb)->driver_data; } /** @@ -189,12 +194,10 @@ enum txdone_entry_desc_flags { * Summary of information that has been read from the TX frame descriptor * after the device is done with transmission. * - * @control: Control structure which was used to transmit the frame. * @flags: TX done flags (See &enum txdone_entry_desc_flags). * @retry: Retry count. */ struct txdone_entry_desc { - struct ieee80211_tx_control *control; unsigned long flags; int retry; }; diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index dcee1b4..52d12fd 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -129,9 +129,9 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) { struct queue_entry *entry = (struct queue_entry *)urb->context; struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; - struct queue_entry_priv_usb *entry_priv = entry->priv_data; struct txdone_entry_desc txdesc; __le32 *txd = (__le32 *)entry->skb->data; + enum data_queue_qid qid = skb_get_queue_mapping(entry->skb); u32 word; if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || @@ -159,7 +159,6 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) else __set_bit(TXDONE_FAILURE, &txdesc.flags); txdesc.retry = 0; - txdesc.control = &entry_priv->control; rt2x00lib_txdone(entry, &txdesc); @@ -175,12 +174,11 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) * is reenabled when the txdone handler has finished. */ if (!rt2x00queue_full(entry->queue)) - ieee80211_wake_queue(rt2x00dev->hw, entry_priv->control.queue); + ieee80211_wake_queue(rt2x00dev->hw, qid); } int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, - struct data_queue *queue, struct sk_buff *skb, - struct ieee80211_tx_control *control) + struct data_queue *queue, struct sk_buff *skb) { struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev); struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); @@ -206,7 +204,7 @@ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, * for our information. */ entry->skb = skb; - rt2x00queue_create_tx_descriptor(entry, &txdesc, control); + rt2x00queue_create_tx_descriptor(entry, &txdesc); /* * Add the descriptor in front of the skb. @@ -218,13 +216,13 @@ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, * Fill in skb descriptor */ skbdesc = get_skb_frame_desc(skb); + memset(skbdesc, 0, sizeof(*skbdesc)); skbdesc->data = skb->data + queue->desc_size; skbdesc->data_len = skb->len - queue->desc_size; skbdesc->desc = skb->data; skbdesc->desc_len = queue->desc_size; skbdesc->entry = entry; - memcpy(&entry_priv->control, control, sizeof(entry_priv->control)); rt2x00queue_write_tx_descriptor(entry, &txdesc); /* diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index 15b404a..26f53f8 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h @@ -216,19 +216,15 @@ void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev); * TX data handlers. */ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, - struct data_queue *queue, struct sk_buff *skb, - struct ieee80211_tx_control *control); + struct data_queue *queue, struct sk_buff *skb); /** * struct queue_entry_priv_usb: Per entry USB specific information * * @urb: Urb structure used for device communication. - * @control: mac80211 control structure used to transmit data. */ struct queue_entry_priv_usb { struct urb *urb; - - struct ieee80211_tx_control control; }; /** @@ -239,15 +235,12 @@ struct queue_entry_priv_usb { * with beacons. * * @urb: Urb structure used for device communication. - * @control: mac80211 control structure used to transmit data. * @guardian_data: Set to 0, used for sending the guardian data. * @guardian_urb: Urb structure used to send the guardian data. */ struct queue_entry_priv_usb_bcn { struct urb *urb; - struct ieee80211_tx_control control; - unsigned int guardian_data; struct urb *guardian_urb; }; diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 7598b6e..e13ed5c 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2357,11 +2357,11 @@ static u64 rt61pci_get_tsf(struct ieee80211_hw *hw) return tsf; } -static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *control) +static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) { struct rt2x00_dev *rt2x00dev = hw->priv; - struct rt2x00_intf *intf = vif_to_intf(control->vif); + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif); struct queue_entry_priv_pci *entry_priv; struct skb_frame_desc *skbdesc; struct txentry_desc txdesc; @@ -2377,7 +2377,7 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, * for our information. */ intf->beacon->skb = skb; - rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc, control); + rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc); entry_priv = intf->beacon->priv_data; memset(entry_priv->desc, 0, intf->beacon->queue->desc_size); diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index e55bcbd..26c2e0a 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1948,11 +1948,11 @@ static u64 rt73usb_get_tsf(struct ieee80211_hw *hw) #define rt73usb_get_tsf NULL #endif -static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *control) +static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) { struct rt2x00_dev *rt2x00dev = hw->priv; - struct rt2x00_intf *intf = vif_to_intf(control->vif); + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif); struct skb_frame_desc *skbdesc; struct txentry_desc txdesc; unsigned int beacon_base; @@ -1967,7 +1967,7 @@ static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, * for our information. */ intf->beacon->skb = skb; - rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc, control); + rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc); /* * Add the descriptor in front of the skb. diff --git a/drivers/net/wireless/rtl8180_dev.c b/drivers/net/wireless/rtl8180_dev.c index 6263209b..4427bc9 100644 --- a/drivers/net/wireless/rtl8180_dev.c +++ b/drivers/net/wireless/rtl8180_dev.c @@ -170,34 +170,29 @@ static void rtl8180_handle_tx(struct ieee80211_hw *dev, unsigned int prio) while (skb_queue_len(&ring->queue)) { struct rtl8180_tx_desc *entry = &ring->desc[ring->idx]; struct sk_buff *skb; - struct ieee80211_tx_status status; - struct ieee80211_tx_control *control; + struct ieee80211_tx_info *info; u32 flags = le32_to_cpu(entry->flags); if (flags & RTL8180_TX_DESC_FLAG_OWN) return; - memset(&status, 0, sizeof(status)); - ring->idx = (ring->idx + 1) % ring->entries; skb = __skb_dequeue(&ring->queue); pci_unmap_single(priv->pdev, le32_to_cpu(entry->tx_buf), skb->len, PCI_DMA_TODEVICE); - control = *((struct ieee80211_tx_control **)skb->cb); - if (control) - memcpy(&status.control, control, sizeof(*control)); - kfree(control); + info = IEEE80211_SKB_CB(skb); + memset(&info->status, 0, sizeof(info->status)); - if (!(status.control.flags & IEEE80211_TXCTL_NO_ACK)) { + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { if (flags & RTL8180_TX_DESC_FLAG_TX_OK) - status.flags = IEEE80211_TX_STATUS_ACK; + info->flags |= IEEE80211_TX_STAT_ACK; else - status.excessive_retries = 1; + info->status.excessive_retries = 1; } - status.retry_count = flags & 0xFF; + info->status.retry_count = flags & 0xFF; - ieee80211_tx_status_irqsafe(dev, skb, &status); + ieee80211_tx_status_irqsafe(dev, skb); if (ring->entries - skb_queue_len(&ring->queue) == 2) ieee80211_wake_queue(dev, prio); } @@ -238,9 +233,9 @@ static irqreturn_t rtl8180_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb, - struct ieee80211_tx_control *control) +static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct rtl8180_priv *priv = dev->priv; struct rtl8180_tx_ring *ring; struct rtl8180_tx_desc *entry; @@ -251,7 +246,7 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb, u16 plcp_len = 0; __le16 rts_duration = 0; - prio = control->queue; + prio = info->queue; ring = &priv->tx_ring[prio]; mapping = pci_map_single(priv->pdev, skb->data, @@ -259,35 +254,32 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb, tx_flags = RTL8180_TX_DESC_FLAG_OWN | RTL8180_TX_DESC_FLAG_FS | RTL8180_TX_DESC_FLAG_LS | - (ieee80211_get_tx_rate(dev, control)->hw_value << 24) | + (ieee80211_get_tx_rate(dev, info)->hw_value << 24) | skb->len; if (priv->r8185) tx_flags |= RTL8180_TX_DESC_FLAG_DMA | RTL8180_TX_DESC_FLAG_NO_ENC; - if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) { + if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { tx_flags |= RTL8180_TX_DESC_FLAG_RTS; - tx_flags |= ieee80211_get_rts_cts_rate(dev, control)->hw_value << 19; - } else if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { + tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; + } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { tx_flags |= RTL8180_TX_DESC_FLAG_CTS; - tx_flags |= ieee80211_get_rts_cts_rate(dev, control)->hw_value << 19; + tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; } - *((struct ieee80211_tx_control **) skb->cb) = - kmemdup(control, sizeof(*control), GFP_ATOMIC); - - if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) + if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) rts_duration = ieee80211_rts_duration(dev, priv->vif, skb->len, - control); + info); if (!priv->r8185) { unsigned int remainder; plcp_len = DIV_ROUND_UP(16 * (skb->len + 4), - (ieee80211_get_tx_rate(dev, control)->bitrate * 2) / 10); + (ieee80211_get_tx_rate(dev, info)->bitrate * 2) / 10); remainder = (16 * (skb->len + 4)) % - ((ieee80211_get_tx_rate(dev, control)->bitrate * 2) / 10); + ((ieee80211_get_tx_rate(dev, info)->bitrate * 2) / 10); if (remainder > 0 && remainder <= 6) plcp_len |= 1 << 15; } @@ -300,13 +292,13 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb, entry->plcp_len = cpu_to_le16(plcp_len); entry->tx_buf = cpu_to_le32(mapping); entry->frame_len = cpu_to_le32(skb->len); - entry->flags2 = control->alt_retry_rate_idx >= 0 ? - ieee80211_get_alt_retry_rate(dev, control)->bitrate << 4 : 0; - entry->retry_limit = control->retry_limit; + entry->flags2 = info->control.alt_retry_rate_idx >= 0 ? + ieee80211_get_alt_retry_rate(dev, info)->bitrate << 4 : 0; + entry->retry_limit = info->control.retry_limit; entry->flags = cpu_to_le32(tx_flags); __skb_queue_tail(&ring->queue, skb); if (ring->entries - skb_queue_len(&ring->queue) < 2) - ieee80211_stop_queue(dev, control->queue); + ieee80211_stop_queue(dev, info->queue); spin_unlock_irqrestore(&priv->lock, flags); rtl818x_iowrite8(priv, &priv->map->TX_DMA_POLLING, (1 << (prio + 4))); @@ -522,7 +514,6 @@ static void rtl8180_free_tx_ring(struct ieee80211_hw *dev, unsigned int prio) pci_unmap_single(priv->pdev, le32_to_cpu(entry->tx_buf), skb->len, PCI_DMA_TODEVICE); - kfree(*((struct ieee80211_tx_control **) skb->cb)); kfree_skb(skb); ring->idx = (ring->idx + 1) % ring->entries; } diff --git a/drivers/net/wireless/rtl8187.h b/drivers/net/wireless/rtl8187.h index 076d88b..a0cfb666 100644 --- a/drivers/net/wireless/rtl8187.h +++ b/drivers/net/wireless/rtl8187.h @@ -44,12 +44,6 @@ struct rtl8187_rx_hdr { __le64 mac_time; } __attribute__((packed)); -struct rtl8187_tx_info { - struct ieee80211_tx_control *control; - struct urb *urb; - struct ieee80211_hw *dev; -}; - struct rtl8187_tx_hdr { __le32 flags; #define RTL8187_TX_FLAG_NO_ENCRYPT (1 << 15) diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index 86a09b4..b581ef8 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -145,27 +145,22 @@ void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data) static void rtl8187_tx_cb(struct urb *urb) { - struct ieee80211_tx_status status; struct sk_buff *skb = (struct sk_buff *)urb->context; - struct rtl8187_tx_info *info = (struct rtl8187_tx_info *)skb->cb; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_hw *hw = info->driver_data[0]; - memset(&status, 0, sizeof(status)); - - usb_free_urb(info->urb); - if (info->control) - memcpy(&status.control, info->control, sizeof(status.control)); - kfree(info->control); + usb_free_urb(info->driver_data[1]); skb_pull(skb, sizeof(struct rtl8187_tx_hdr)); - status.flags |= IEEE80211_TX_STATUS_ACK; - ieee80211_tx_status_irqsafe(info->dev, skb, &status); + memset(&info->status, 0, sizeof(info->status)); + info->flags |= IEEE80211_TX_STAT_ACK; + ieee80211_tx_status_irqsafe(hw, skb); } -static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb, - struct ieee80211_tx_control *control) +static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) { struct rtl8187_priv *priv = dev->priv; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct rtl8187_tx_hdr *hdr; - struct rtl8187_tx_info *info; struct urb *urb; __le16 rts_dur = 0; u32 flags; @@ -179,29 +174,27 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb, flags = skb->len; flags |= RTL8187_TX_FLAG_NO_ENCRYPT; - flags |= ieee80211_get_tx_rate(dev, control)->hw_value << 24; + flags |= ieee80211_get_tx_rate(dev, info)->hw_value << 24; if (ieee80211_get_morefrag((struct ieee80211_hdr *)skb->data)) flags |= RTL8187_TX_FLAG_MORE_FRAG; - if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) { + if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { flags |= RTL8187_TX_FLAG_RTS; - flags |= ieee80211_get_rts_cts_rate(dev, control)->hw_value << 19; + flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; rts_dur = ieee80211_rts_duration(dev, priv->vif, - skb->len, control); - } else if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { + skb->len, info); + } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { flags |= RTL8187_TX_FLAG_CTS; - flags |= ieee80211_get_rts_cts_rate(dev, control)->hw_value << 19; + flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; } hdr = (struct rtl8187_tx_hdr *)skb_push(skb, sizeof(*hdr)); hdr->flags = cpu_to_le32(flags); hdr->len = 0; hdr->rts_duration = rts_dur; - hdr->retry = cpu_to_le32(control->retry_limit << 8); + hdr->retry = cpu_to_le32(info->control.retry_limit << 8); - info = (struct rtl8187_tx_info *)skb->cb; - info->control = kmemdup(control, sizeof(*control), GFP_ATOMIC); - info->urb = urb; - info->dev = dev; + info->driver_data[0] = dev; + info->driver_data[1] = urb; usb_fill_bulk_urb(urb, priv->udev, usb_sndbulkpipe(priv->udev, 2), hdr, skb->len, rtl8187_tx_cb, skb); usb_submit_urb(urb, GFP_ATOMIC); diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 99c508c..edb1aef 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -224,36 +224,6 @@ out: return r; } -/** - * clear_tx_skb_control_block - clears the control block of tx skbuffs - * @skb: a &struct sk_buff pointer - * - * This clears the control block of skbuff buffers, which were transmitted to - * the device. Notify that the function is not thread-safe, so prevent - * multiple calls. - */ -static void clear_tx_skb_control_block(struct sk_buff *skb) -{ - struct zd_tx_skb_control_block *cb = - (struct zd_tx_skb_control_block *)skb->cb; - - kfree(cb->control); - cb->control = NULL; -} - -/** - * kfree_tx_skb - frees a tx skbuff - * @skb: a &struct sk_buff pointer - * - * Frees the tx skbuff. Frees also the allocated control structure in the - * control block if necessary. - */ -static void kfree_tx_skb(struct sk_buff *skb) -{ - clear_tx_skb_control_block(skb); - dev_kfree_skb_any(skb); -} - static void zd_op_stop(struct ieee80211_hw *hw) { struct zd_mac *mac = zd_hw_mac(hw); @@ -276,40 +246,15 @@ static void zd_op_stop(struct ieee80211_hw *hw) while ((skb = skb_dequeue(ack_wait_queue))) - kfree_tx_skb(skb); -} - -/** - * init_tx_skb_control_block - initializes skb control block - * @skb: a &sk_buff pointer - * @dev: pointer to the mac80221 device - * @control: mac80211 tx control applying for the frame in @skb - * - * Initializes the control block of the skbuff to be transmitted. - */ -static int init_tx_skb_control_block(struct sk_buff *skb, - struct ieee80211_hw *hw, - struct ieee80211_tx_control *control) -{ - struct zd_tx_skb_control_block *cb = - (struct zd_tx_skb_control_block *)skb->cb; - - ZD_ASSERT(sizeof(*cb) <= sizeof(skb->cb)); - memset(cb, 0, sizeof(*cb)); - cb->hw= hw; - cb->control = kmalloc(sizeof(*control), GFP_ATOMIC); - if (cb->control == NULL) - return -ENOMEM; - memcpy(cb->control, control, sizeof(*control)); - - return 0; + dev_kfree_skb_any(skb); } /** * tx_status - reports tx status of a packet if required * @hw - a &struct ieee80211_hw pointer * @skb - a sk-buffer - * @status - the tx status of the packet without control information + * @flags: extra flags to set in the TX status info + * @ackssi: ACK signal strength * @success - True for successfull transmission of the frame * * This information calls ieee80211_tx_status_irqsafe() if required by the @@ -319,18 +264,17 @@ static int init_tx_skb_control_block(struct sk_buff *skb, * If no status information has been requested, the skb is freed. */ static void tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_status *status, - bool success) + u32 flags, int ackssi, bool success) { - struct zd_tx_skb_control_block *cb = (struct zd_tx_skb_control_block *) - skb->cb; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + + memset(&info->status, 0, sizeof(info->status)); - ZD_ASSERT(cb->control != NULL); - memcpy(&status->control, cb->control, sizeof(status->control)); if (!success) - status->excessive_retries = 1; - clear_tx_skb_control_block(skb); - ieee80211_tx_status_irqsafe(hw, skb, status); + info->status.excessive_retries = 1; + info->flags |= flags; + info->status.ack_signal = ackssi; + ieee80211_tx_status_irqsafe(hw, skb); } /** @@ -345,15 +289,12 @@ void zd_mac_tx_failed(struct ieee80211_hw *hw) { struct sk_buff_head *q = &zd_hw_mac(hw)->ack_wait_queue; struct sk_buff *skb; - struct ieee80211_tx_status status; skb = skb_dequeue(q); if (skb == NULL) return; - memset(&status, 0, sizeof(status)); - - tx_status(hw, skb, &status, 0); + tx_status(hw, skb, 0, 0, 0); } /** @@ -368,28 +309,20 @@ void zd_mac_tx_failed(struct ieee80211_hw *hw) */ void zd_mac_tx_to_dev(struct sk_buff *skb, int error) { - struct zd_tx_skb_control_block *cb = - (struct zd_tx_skb_control_block *)skb->cb; - struct ieee80211_hw *hw = cb->hw; - - if (likely(cb->control)) { - skb_pull(skb, sizeof(struct zd_ctrlset)); - if (unlikely(error || - (cb->control->flags & IEEE80211_TXCTL_NO_ACK))) - { - struct ieee80211_tx_status status; - memset(&status, 0, sizeof(status)); - tx_status(hw, skb, &status, !error); - } else { - struct sk_buff_head *q = - &zd_hw_mac(hw)->ack_wait_queue; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_hw *hw = info->driver_data[0]; - skb_queue_tail(q, skb); - while (skb_queue_len(q) > ZD_MAC_MAX_ACK_WAITERS) - zd_mac_tx_failed(hw); - } + skb_pull(skb, sizeof(struct zd_ctrlset)); + if (unlikely(error || + (info->flags & IEEE80211_TX_CTL_NO_ACK))) { + tx_status(hw, skb, 0, 0, !error); } else { - kfree_tx_skb(skb); + struct sk_buff_head *q = + &zd_hw_mac(hw)->ack_wait_queue; + + skb_queue_tail(q, skb); + while (skb_queue_len(q) > ZD_MAC_MAX_ACK_WAITERS) + zd_mac_tx_failed(hw); } } @@ -454,7 +387,7 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs, cs->control = 0; /* First fragment */ - if (flags & IEEE80211_TXCTL_FIRST_FRAGMENT) + if (flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) cs->control |= ZD_CS_NEED_RANDOM_BACKOFF; /* Multicast */ @@ -466,10 +399,10 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs, (IEEE80211_FTYPE_CTL|IEEE80211_STYPE_PSPOLL)) cs->control |= ZD_CS_PS_POLL_FRAME; - if (flags & IEEE80211_TXCTL_USE_RTS_CTS) + if (flags & IEEE80211_TX_CTL_USE_RTS_CTS) cs->control |= ZD_CS_RTS; - if (flags & IEEE80211_TXCTL_USE_CTS_PROTECT) + if (flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) cs->control |= ZD_CS_SELF_CTS; /* FIXME: Management frame? */ @@ -516,8 +449,7 @@ void zd_mac_config_beacon(struct ieee80211_hw *hw, struct sk_buff *beacon) } static int fill_ctrlset(struct zd_mac *mac, - struct sk_buff *skb, - struct ieee80211_tx_control *control) + struct sk_buff *skb) { int r; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; @@ -526,18 +458,19 @@ static int fill_ctrlset(struct zd_mac *mac, struct ieee80211_rate *txrate; struct zd_ctrlset *cs = (struct zd_ctrlset *) skb_push(skb, sizeof(struct zd_ctrlset)); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); ZD_ASSERT(frag_len <= 0xffff); - txrate = ieee80211_get_tx_rate(mac->hw, control); + txrate = ieee80211_get_tx_rate(mac->hw, info); cs->modulation = txrate->hw_value; - if (control->flags & IEEE80211_TXCTL_SHORT_PREAMBLE) + if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE) cs->modulation = txrate->hw_value_short; cs->tx_length = cpu_to_le16(frag_len); - cs_set_control(mac, cs, hdr, control->flags); + cs_set_control(mac, cs, hdr, info->flags); packet_length = frag_len + sizeof(struct zd_ctrlset) + 10; ZD_ASSERT(packet_length <= 0xffff); @@ -582,24 +515,21 @@ static int fill_ctrlset(struct zd_mac *mac, * control block of the skbuff will be initialized. If necessary the incoming * mac80211 queues will be stopped. */ -static int zd_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *control) +static int zd_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct zd_mac *mac = zd_hw_mac(hw); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int r; - r = fill_ctrlset(mac, skb, control); + r = fill_ctrlset(mac, skb); if (r) return r; - r = init_tx_skb_control_block(skb, hw, control); - if (r) - return r; + info->driver_data[0] = hw; + r = zd_usb_tx(&mac->chip.usb, skb); - if (r) { - clear_tx_skb_control_block(skb); + if (r) return r; - } return 0; } @@ -637,13 +567,8 @@ static int filter_ack(struct ieee80211_hw *hw, struct ieee80211_hdr *rx_hdr, tx_hdr = (struct ieee80211_hdr *)skb->data; if (likely(!compare_ether_addr(tx_hdr->addr2, rx_hdr->addr1))) { - struct ieee80211_tx_status status; - - memset(&status, 0, sizeof(status)); - status.flags = IEEE80211_TX_STATUS_ACK; - status.ack_signal = stats->signal; __skb_unlink(skb, q); - tx_status(hw, skb, &status, 1); + tx_status(hw, skb, IEEE80211_TX_STAT_ACK, stats->signal, 1); goto out; } } @@ -947,8 +872,7 @@ static void zd_op_bss_info_changed(struct ieee80211_hw *hw, } static int zd_op_beacon_update(struct ieee80211_hw *hw, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl) + struct sk_buff *skb) { struct zd_mac *mac = zd_hw_mac(hw); zd_mac_config_beacon(hw, skb); diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h index 7117024..18c1d56 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.h +++ b/drivers/net/wireless/zd1211rw/zd_mac.h @@ -149,22 +149,6 @@ struct housekeeping { struct delayed_work link_led_work; }; -/** - * struct zd_tx_skb_control_block - control block for tx skbuffs - * @control: &struct ieee80211_tx_control pointer - * @context: context pointer - * - * This structure is used to fill the cb field in an &sk_buff to transmit. - * The control field is NULL, if there is no requirement from the mac80211 - * stack to report about the packet ACK. This is the case if the flag - * IEEE80211_TXCTL_NO_ACK is not set in &struct ieee80211_tx_control. - */ -struct zd_tx_skb_control_block { - struct ieee80211_tx_control *control; - struct ieee80211_hw *hw; - void *context; -}; - #define ZD_MAC_STATS_BUFFER_SIZE 16 #define ZD_MAC_MAX_ACK_WAITERS 10 diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 12e24f0..c8a0b34 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -869,7 +869,7 @@ static void tx_urb_complete(struct urb *urb) { int r; struct sk_buff *skb; - struct zd_tx_skb_control_block *cb; + struct ieee80211_tx_info *info; struct zd_usb *usb; switch (urb->status) { @@ -893,8 +893,8 @@ free_urb: * grab 'usb' pointer before handing off the skb (since * it might be freed by zd_mac_tx_to_dev or mac80211) */ - cb = (struct zd_tx_skb_control_block *)skb->cb; - usb = &zd_hw_mac(cb->hw)->chip.usb; + info = IEEE80211_SKB_CB(skb); + usb = &zd_hw_mac(info->driver_data[0])->chip.usb; zd_mac_tx_to_dev(skb, urb->status); free_tx_urb(usb, urb); tx_dec_submitted_urbs(usb); diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 0df91be..54960b8 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -201,101 +201,127 @@ struct ieee80211_bss_conf { }; /** - * enum mac80211_tx_control_flags - flags to describe Tx configuration for - * the Tx frame - * - * These flags are used with the @flags member of &ieee80211_tx_control - * - * @IEEE80211_TXCTL_REQ_TX_STATUS: request TX status callback for this frame. - * @IEEE80211_TXCTL_DO_NOT_ENCRYPT: send this frame without encryption; - * e.g., for EAPOL frame - * @IEEE80211_TXCTL_USE_RTS_CTS: use RTS-CTS before sending frame - * @IEEE80211_TXCTL_USE_CTS_PROTECT: use CTS protection for the frame (e.g., - * for combined 802.11g / 802.11b networks) - * @IEEE80211_TXCTL_NO_ACK: tell the low level not to wait for an ack - * @IEEE80211_TXCTL_RATE_CTRL_PROBE - * @EEE80211_TXCTL_CLEAR_PS_FILT: clear powersave filter - * for destination station - * @IEEE80211_TXCTL_REQUEUE: - * @IEEE80211_TXCTL_FIRST_FRAGMENT: this is a first fragment of the frame - * @IEEE80211_TXCTL_LONG_RETRY_LIMIT: this frame should be send using the - * through set_retry_limit configured long - * retry value - * @IEEE80211_TXCTL_EAPOL_FRAME: internal to mac80211 - * @IEEE80211_TXCTL_SEND_AFTER_DTIM: send this frame after DTIM beacon - * @IEEE80211_TXCTL_AMPDU: this frame should be sent as part of an A-MPDU - * @IEEE80211_TXCTL_OFDM_HT: this frame can be sent in HT OFDM rates. number - * of streams when this flag is on can be extracted - * from antenna_sel_tx, so if 1 antenna is marked - * use SISO, 2 antennas marked use MIMO, n antennas - * marked use MIMO_n. - * @IEEE80211_TXCTL_GREEN_FIELD: use green field protection for this frame - * @IEEE80211_TXCTL_40_MHZ_WIDTH: send this frame using 40 Mhz channel width - * @IEEE80211_TXCTL_DUP_DATA: duplicate data frame on both 20 Mhz channels - * @IEEE80211_TXCTL_SHORT_GI: send this frame using short guard interval + * enum mac80211_tx_flags - flags to transmission information/status + * + * These flags are used with the @flags member of &ieee80211_tx_info + * + * @IEEE80211_TX_CTL_REQ_TX_STATUS: request TX status callback for this frame. + * @IEEE80211_TX_CTL_DO_NOT_ENCRYPT: send this frame without encryption; + * e.g., for EAPOL frame + * @IEEE80211_TX_CTL_USE_RTS_CTS: use RTS-CTS before sending frame + * @IEEE80211_TX_CTL_USE_CTS_PROTECT: use CTS protection for the frame (e.g., + * for combined 802.11g / 802.11b networks) + * @IEEE80211_TX_CTL_NO_ACK: tell the low level not to wait for an ack + * @IEEE80211_TX_CTL_RATE_CTRL_PROBE + * @IEEE80211_TX_CTL_CLEAR_PS_FILT: clear powersave filter for destination + * station + * @IEEE80211_TX_CTL_REQUEUE: + * @IEEE80211_TX_CTL_FIRST_FRAGMENT: this is a first fragment of the frame + * @IEEE80211_TX_CTL_LONG_RETRY_LIMIT: this frame should be send using the + * through set_retry_limit configured long retry value + * @IEEE80211_TX_CTL_EAPOL_FRAME: internal to mac80211 + * @IEEE80211_TX_CTL_SEND_AFTER_DTIM: send this frame after DTIM beacon + * @IEEE80211_TX_CTL_AMPDU: this frame should be sent as part of an A-MPDU + * @IEEE80211_TX_CTL_OFDM_HT: this frame can be sent in HT OFDM rates. number + * of streams when this flag is on can be extracted from antenna_sel_tx, + * so if 1 antenna is marked use SISO, 2 antennas marked use MIMO, n + * antennas marked use MIMO_n. + * @IEEE80211_TX_CTL_GREEN_FIELD: use green field protection for this frame + * @IEEE80211_TX_CTL_40_MHZ_WIDTH: send this frame using 40 Mhz channel width + * @IEEE80211_TX_CTL_DUP_DATA: duplicate data frame on both 20 Mhz channels + * @IEEE80211_TX_CTL_SHORT_GI: send this frame using short guard interval + * @IEEE80211_TX_STAT_TX_FILTERED: The frame was not transmitted + * because the destination STA was in powersave mode. + * @IEEE80211_TX_STAT_ACK: Frame was acknowledged + * @IEEE80211_TX_STAT_AMPDU: The frame was aggregated, so status + * is for the whole aggregation. */ enum mac80211_tx_control_flags { - IEEE80211_TXCTL_REQ_TX_STATUS = (1<<0), - IEEE80211_TXCTL_DO_NOT_ENCRYPT = (1<<1), - IEEE80211_TXCTL_USE_RTS_CTS = (1<<2), - IEEE80211_TXCTL_USE_CTS_PROTECT = (1<<3), - IEEE80211_TXCTL_NO_ACK = (1<<4), - IEEE80211_TXCTL_RATE_CTRL_PROBE = (1<<5), - IEEE80211_TXCTL_CLEAR_PS_FILT = (1<<6), - IEEE80211_TXCTL_REQUEUE = (1<<7), - IEEE80211_TXCTL_FIRST_FRAGMENT = (1<<8), - IEEE80211_TXCTL_SHORT_PREAMBLE = (1<<9), - IEEE80211_TXCTL_LONG_RETRY_LIMIT = (1<<10), - IEEE80211_TXCTL_EAPOL_FRAME = (1<<11), - IEEE80211_TXCTL_SEND_AFTER_DTIM = (1<<12), - IEEE80211_TXCTL_AMPDU = (1<<13), - IEEE80211_TXCTL_OFDM_HT = (1<<14), - IEEE80211_TXCTL_GREEN_FIELD = (1<<15), - IEEE80211_TXCTL_40_MHZ_WIDTH = (1<<16), - IEEE80211_TXCTL_DUP_DATA = (1<<17), - IEEE80211_TXCTL_SHORT_GI = (1<<18), + IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0), + IEEE80211_TX_CTL_DO_NOT_ENCRYPT = BIT(1), + IEEE80211_TX_CTL_USE_RTS_CTS = BIT(2), + IEEE80211_TX_CTL_USE_CTS_PROTECT = BIT(3), + IEEE80211_TX_CTL_NO_ACK = BIT(4), + IEEE80211_TX_CTL_RATE_CTRL_PROBE = BIT(5), + IEEE80211_TX_CTL_CLEAR_PS_FILT = BIT(6), + IEEE80211_TX_CTL_REQUEUE = BIT(7), + IEEE80211_TX_CTL_FIRST_FRAGMENT = BIT(8), + IEEE80211_TX_CTL_SHORT_PREAMBLE = BIT(9), + IEEE80211_TX_CTL_LONG_RETRY_LIMIT = BIT(10), + IEEE80211_TX_CTL_EAPOL_FRAME = BIT(11), + IEEE80211_TX_CTL_SEND_AFTER_DTIM = BIT(12), + IEEE80211_TX_CTL_AMPDU = BIT(13), + IEEE80211_TX_CTL_OFDM_HT = BIT(14), + IEEE80211_TX_CTL_GREEN_FIELD = BIT(15), + IEEE80211_TX_CTL_40_MHZ_WIDTH = BIT(16), + IEEE80211_TX_CTL_DUP_DATA = BIT(17), + IEEE80211_TX_CTL_SHORT_GI = BIT(18), + IEEE80211_TX_CTL_INJECTED = BIT(19), + IEEE80211_TX_STAT_TX_FILTERED = BIT(20), + IEEE80211_TX_STAT_ACK = BIT(21), + IEEE80211_TX_STAT_AMPDU = BIT(22), }; -/* Transmit control fields. This data structure is passed to low-level driver - * with each TX frame. The low-level driver is responsible for configuring - * the hardware to use given values (depending on what is supported). - * - * NOTE: Be careful with using the pointers outside of the ieee80211_ops->tx() - * context (i.e. when defering the work to a workqueue). - * The vif pointer is valid until the it has been removed with the - * ieee80211_ops->remove_interface() callback funtion. - * The hw_key pointer is valid until it has been removed with the - * ieee80211_ops->set_key() callback function. - */ -struct ieee80211_tx_control { - u32 flags; /* tx control flags defined above */ - - s8 tx_rate_idx, /* Transmit rate (indexes registered rates) */ - rts_cts_rate_idx, /* Transmit rate for RTS/CTS frame */ - alt_retry_rate_idx; /* retry rate for the last retries */ - - s8 retry_limit; /* 1 = only first attempt, 2 = one retry, .. - * This could be used when set_retry_limit - * is not implemented by the driver */ - struct ieee80211_vif *vif; - - /* Key used for hardware encryption - * NULL if IEEE80211_TXCTL_DO_NOT_ENCRYPT is set */ - struct ieee80211_key_conf *hw_key; +#define IEEE80211_TX_INFO_DRIVER_DATA_SIZE \ + (sizeof(((struct sk_buff *)0)->cb) - 8) +#define IEEE80211_TX_INFO_DRIVER_DATA_PTRS \ + (IEEE80211_TX_INFO_DRIVER_DATA_SIZE / sizeof(void *)) - enum ieee80211_band band; +/** + * struct ieee80211_tx_info - skb transmit information + * + * This structure is placed in skb->cb for three uses: + * (1) mac80211 TX control - mac80211 tells the driver what to do + * (2) driver internal use (if applicable) + * (3) TX status information - driver tells mac80211 what happened + * + * @flags: transmit info flags, defined above + * @retry_count: number of retries + * @excessive_retries: set to 1 if the frame was retried many times + * but not acknowledged + * @ampdu_ack_len: number of aggregated frames. + * relevant only if IEEE80211_TX_STATUS_AMPDU was set. + * @ampdu_ack_map: block ack bit map for the aggregation. + * relevant only if IEEE80211_TX_STATUS_AMPDU was set. + * @ack_signal: signal strength of the ACK frame + */ +struct ieee80211_tx_info { + /* common information */ + u32 flags; + u8 band; + s8 tx_rate_idx; + u8 antenna_sel_tx; - u8 antenna_sel_tx; /* 0 = default/diversity, otherwise bit - * position represents antenna number used */ - u8 icv_len; /* length of the ICV/MIC field in octets */ - u8 iv_len; /* length of the IV field in octets */ - u16 queue; /* hardware queue to use for this frame; - * 0 = highest, hw->queues-1 = lowest */ - u16 aid; /* Station AID */ - int type; /* internal */ + u8 queue; /* use skb_queue_mapping soon */ + + union { + struct { + struct ieee80211_vif *vif; + struct ieee80211_key_conf *hw_key; + unsigned long jiffies; + int ifindex; + u16 aid; + s8 rts_cts_rate_idx, alt_retry_rate_idx; + u8 retry_limit; + u8 icv_len; + u8 iv_len; + } control; + struct { + u64 ampdu_ack_map; + int ack_signal; + u8 retry_count; + bool excessive_retries; + u8 ampdu_ack_len; + } status; + void *driver_data[IEEE80211_TX_INFO_DRIVER_DATA_PTRS]; + }; }; +static inline struct ieee80211_tx_info *IEEE80211_SKB_CB(struct sk_buff *skb) +{ + return (struct ieee80211_tx_info *)skb->cb; +} /** @@ -363,52 +389,6 @@ struct ieee80211_rx_status { }; /** - * enum ieee80211_tx_status_flags - transmit status flags - * - * Status flags to indicate various transmit conditions. - * - * @IEEE80211_TX_STATUS_TX_FILTERED: The frame was not transmitted - * because the destination STA was in powersave mode. - * @IEEE80211_TX_STATUS_ACK: Frame was acknowledged - * @IEEE80211_TX_STATUS_AMPDU: The frame was aggregated, so status - * is for the whole aggregation. - */ -enum ieee80211_tx_status_flags { - IEEE80211_TX_STATUS_TX_FILTERED = 1<<0, - IEEE80211_TX_STATUS_ACK = 1<<1, - IEEE80211_TX_STATUS_AMPDU = 1<<2, -}; - -/** - * struct ieee80211_tx_status - transmit status - * - * As much information as possible should be provided for each transmitted - * frame with ieee80211_tx_status(). - * - * @control: a copy of the &struct ieee80211_tx_control passed to the driver - * in the tx() callback. - * @flags: transmit status flags, defined above - * @retry_count: number of retries - * @excessive_retries: set to 1 if the frame was retried many times - * but not acknowledged - * @ampdu_ack_len: number of aggregated frames. - * relevant only if IEEE80211_TX_STATUS_AMPDU was set. - * @ampdu_ack_map: block ack bit map for the aggregation. - * relevant only if IEEE80211_TX_STATUS_AMPDU was set. - * @ack_signal: signal strength of the ACK frame either in dBm, dB or unspec - * depending on hardware capabilites flags @IEEE80211_HW_SIGNAL_* - */ -struct ieee80211_tx_status { - struct ieee80211_tx_control control; - u8 flags; - u8 retry_count; - bool excessive_retries; - u8 ampdu_ack_len; - u64 ampdu_ack_map; - int ack_signal; -}; - -/** * enum ieee80211_conf_flags - configuration flags * * Flags to define PHY configuration options @@ -563,7 +543,6 @@ struct ieee80211_if_conf { u8 *ssid; size_t ssid_len; struct sk_buff *beacon; - struct ieee80211_tx_control *beacon_control; }; /** @@ -825,7 +804,7 @@ static inline void SET_IEEE80211_PERM_ADDR(struct ieee80211_hw *hw, u8 *addr) static inline struct ieee80211_rate * ieee80211_get_tx_rate(const struct ieee80211_hw *hw, - const struct ieee80211_tx_control *c) + const struct ieee80211_tx_info *c) { if (WARN_ON(c->tx_rate_idx < 0)) return NULL; @@ -834,20 +813,20 @@ ieee80211_get_tx_rate(const struct ieee80211_hw *hw, static inline struct ieee80211_rate * ieee80211_get_rts_cts_rate(const struct ieee80211_hw *hw, - const struct ieee80211_tx_control *c) + const struct ieee80211_tx_info *c) { - if (c->rts_cts_rate_idx < 0) + if (c->control.rts_cts_rate_idx < 0) return NULL; - return &hw->wiphy->bands[c->band]->bitrates[c->rts_cts_rate_idx]; + return &hw->wiphy->bands[c->band]->bitrates[c->control.rts_cts_rate_idx]; } static inline struct ieee80211_rate * ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw, - const struct ieee80211_tx_control *c) + const struct ieee80211_tx_info *c) { - if (c->alt_retry_rate_idx < 0) + if (c->control.alt_retry_rate_idx < 0) return NULL; - return &hw->wiphy->bands[c->band]->bitrates[c->alt_retry_rate_idx]; + return &hw->wiphy->bands[c->band]->bitrates[c->control.alt_retry_rate_idx]; } /** @@ -1142,8 +1121,7 @@ enum ieee80211_ampdu_mlme_action { * that TX/RX_STOP can pass NULL for this parameter. */ struct ieee80211_ops { - int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *control); + int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb); int (*start)(struct ieee80211_hw *hw); void (*stop)(struct ieee80211_hw *hw); int (*add_interface)(struct ieee80211_hw *hw, @@ -1187,8 +1165,7 @@ struct ieee80211_ops { u64 (*get_tsf)(struct ieee80211_hw *hw); void (*reset_tsf)(struct ieee80211_hw *hw); int (*beacon_update)(struct ieee80211_hw *hw, - struct sk_buff *skb, - struct ieee80211_tx_control *control); + struct sk_buff *skb); int (*tx_last_beacon)(struct ieee80211_hw *hw); int (*ampdu_action)(struct ieee80211_hw *hw, enum ieee80211_ampdu_mlme_action action, @@ -1384,13 +1361,9 @@ void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, * * @hw: the hardware the frame was transmitted by * @skb: the frame that was transmitted, owned by mac80211 after this call - * @status: status information for this frame; the status pointer need not - * be valid after this function returns and is not freed by mac80211, - * it is recommended that it points to a stack area */ void ieee80211_tx_status(struct ieee80211_hw *hw, - struct sk_buff *skb, - struct ieee80211_tx_status *status); + struct sk_buff *skb); /** * ieee80211_tx_status_irqsafe - irq-safe transmit status callback @@ -1403,13 +1376,9 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, * * @hw: the hardware the frame was transmitted by * @skb: the frame that was transmitted, owned by mac80211 after this call - * @status: status information for this frame; the status pointer need not - * be valid after this function returns and is not freed by mac80211, - * it is recommended that it points to a stack area */ void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, - struct sk_buff *skb, - struct ieee80211_tx_status *status); + struct sk_buff *skb); /** * ieee80211_beacon_get - beacon generation function @@ -1425,8 +1394,7 @@ void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, * is responsible of freeing it. */ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_tx_control *control); + struct ieee80211_vif *vif); /** * ieee80211_rts_get - RTS frame generation function @@ -1434,7 +1402,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. * @frame: pointer to the frame that is going to be protected by the RTS. * @frame_len: the frame length (in octets). - * @frame_txctl: &struct ieee80211_tx_control of the frame. + * @frame_txctl: &struct ieee80211_tx_info of the frame. * @rts: The buffer where to store the RTS frame. * * If the RTS frames are generated by the host system (i.e., not in @@ -1444,7 +1412,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, */ void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const void *frame, size_t frame_len, - const struct ieee80211_tx_control *frame_txctl, + const struct ieee80211_tx_info *frame_txctl, struct ieee80211_rts *rts); /** @@ -1452,7 +1420,7 @@ void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, * @hw: pointer obtained from ieee80211_alloc_hw(). * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. * @frame_len: the length of the frame that is going to be protected by the RTS. - * @frame_txctl: &struct ieee80211_tx_control of the frame. + * @frame_txctl: &struct ieee80211_tx_info of the frame. * * If the RTS is generated in firmware, but the host system must provide * the duration field, the low-level driver uses this function to receive @@ -1460,7 +1428,7 @@ void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, */ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, struct ieee80211_vif *vif, size_t frame_len, - const struct ieee80211_tx_control *frame_txctl); + const struct ieee80211_tx_info *frame_txctl); /** * ieee80211_ctstoself_get - CTS-to-self frame generation function @@ -1468,7 +1436,7 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. * @frame: pointer to the frame that is going to be protected by the CTS-to-self. * @frame_len: the frame length (in octets). - * @frame_txctl: &struct ieee80211_tx_control of the frame. + * @frame_txctl: &struct ieee80211_tx_info of the frame. * @cts: The buffer where to store the CTS-to-self frame. * * If the CTS-to-self frames are generated by the host system (i.e., not in @@ -1479,7 +1447,7 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, void ieee80211_ctstoself_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const void *frame, size_t frame_len, - const struct ieee80211_tx_control *frame_txctl, + const struct ieee80211_tx_info *frame_txctl, struct ieee80211_cts *cts); /** @@ -1487,7 +1455,7 @@ void ieee80211_ctstoself_get(struct ieee80211_hw *hw, * @hw: pointer obtained from ieee80211_alloc_hw(). * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. * @frame_len: the length of the frame that is going to be protected by the CTS-to-self. - * @frame_txctl: &struct ieee80211_tx_control of the frame. + * @frame_txctl: &struct ieee80211_tx_info of the frame. * * If the CTS-to-self is generated in firmware, but the host system must provide * the duration field, the low-level driver uses this function to receive @@ -1496,7 +1464,7 @@ void ieee80211_ctstoself_get(struct ieee80211_hw *hw, __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, struct ieee80211_vif *vif, size_t frame_len, - const struct ieee80211_tx_control *frame_txctl); + const struct ieee80211_tx_info *frame_txctl); /** * ieee80211_generic_frame_duration - Calculate the duration field for a frame @@ -1535,8 +1503,7 @@ __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, * use common code for all beacons. */ struct sk_buff * -ieee80211_get_buffered_bc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_tx_control *control); +ieee80211_get_buffered_bc(struct ieee80211_hw *hw, struct ieee80211_vif *vif); /** * ieee80211_get_hdrlen_from_skb - get header length from data diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index a4cccd1..79a65b3 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2,6 +2,7 @@ * Copyright 2002-2005, Instant802 Networks, Inc. * Copyright 2005, Devicescape Software, Inc. * Copyright 2006-2007 Jiri Benc + * Copyright 2007-2008 Johannes Berg * * 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 @@ -147,7 +148,6 @@ typedef unsigned __bitwise__ ieee80211_tx_result; #define IEEE80211_TX_UNICAST BIT(1) #define IEEE80211_TX_PS_BUFFERED BIT(2) #define IEEE80211_TX_PROBE_LAST_FRAG BIT(3) -#define IEEE80211_TX_INJECTED BIT(4) struct ieee80211_tx_data { struct sk_buff *skb; @@ -157,7 +157,6 @@ struct ieee80211_tx_data { struct sta_info *sta; struct ieee80211_key *key; - struct ieee80211_tx_control *control; struct ieee80211_channel *channel; s8 rate_idx; /* use this rate (if set) for last fragment; rate can @@ -207,22 +206,7 @@ struct ieee80211_rx_data { u16 tkip_iv16; }; -/* flags used in struct ieee80211_tx_packet_data.flags */ -#define IEEE80211_TXPD_REQ_TX_STATUS BIT(0) -#define IEEE80211_TXPD_DO_NOT_ENCRYPT BIT(1) -#define IEEE80211_TXPD_REQUEUE BIT(2) -#define IEEE80211_TXPD_EAPOL_FRAME BIT(3) -#define IEEE80211_TXPD_AMPDU BIT(4) -/* Stored in sk_buff->cb */ -struct ieee80211_tx_packet_data { - int ifindex; - unsigned long jiffies; - unsigned int flags; - u8 queue; -}; - struct ieee80211_tx_stored_packet { - struct ieee80211_tx_control control; struct sk_buff *skb; struct sk_buff **extra_frag; s8 last_frag_rate_idx; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 9761d9b..8f1ff7e 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -971,8 +971,7 @@ void ieee80211_if_setup(struct net_device *dev) /* everything else */ static int __ieee80211_if_config(struct net_device *dev, - struct sk_buff *beacon, - struct ieee80211_tx_control *control) + struct sk_buff *beacon) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); @@ -990,13 +989,11 @@ static int __ieee80211_if_config(struct net_device *dev, conf.ssid_len = sdata->u.sta.ssid_len; } else if (ieee80211_vif_is_mesh(&sdata->vif)) { conf.beacon = beacon; - conf.beacon_control = control; ieee80211_start_mesh(dev); } else if (sdata->vif.type == IEEE80211_IF_TYPE_AP) { conf.ssid = sdata->u.ap.ssid; conf.ssid_len = sdata->u.ap.ssid_len; conf.beacon = beacon; - conf.beacon_control = control; } return local->ops->config_interface(local_to_hw(local), &sdata->vif, &conf); @@ -1009,23 +1006,21 @@ int ieee80211_if_config(struct net_device *dev) if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT && (local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE)) return ieee80211_if_config_beacon(dev); - return __ieee80211_if_config(dev, NULL, NULL); + return __ieee80211_if_config(dev, NULL); } int ieee80211_if_config_beacon(struct net_device *dev) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_tx_control control; struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct sk_buff *skb; if (!(local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE)) return 0; - skb = ieee80211_beacon_get(local_to_hw(local), &sdata->vif, - &control); + skb = ieee80211_beacon_get(local_to_hw(local), &sdata->vif); if (!skb) return -ENOMEM; - return __ieee80211_if_config(dev, skb, &control); + return __ieee80211_if_config(dev, skb); } int ieee80211_hw_config(struct ieee80211_local *local) @@ -1180,38 +1175,20 @@ void ieee80211_reset_erp_info(struct net_device *dev) } void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, - struct sk_buff *skb, - struct ieee80211_tx_status *status) + struct sk_buff *skb) { struct ieee80211_local *local = hw_to_local(hw); - struct ieee80211_tx_status *saved; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int tmp; skb->dev = local->mdev; - saved = kmalloc(sizeof(struct ieee80211_tx_status), GFP_ATOMIC); - if (unlikely(!saved)) { - if (net_ratelimit()) - printk(KERN_WARNING "%s: Not enough memory, " - "dropping tx status", skb->dev->name); - /* should be dev_kfree_skb_irq, but due to this function being - * named _irqsafe instead of just _irq we can't be sure that - * people won't call it from non-irq contexts */ - dev_kfree_skb_any(skb); - return; - } - memcpy(saved, status, sizeof(struct ieee80211_tx_status)); - /* copy pointer to saved status into skb->cb for use by tasklet */ - memcpy(skb->cb, &saved, sizeof(saved)); - skb->pkt_type = IEEE80211_TX_STATUS_MSG; - skb_queue_tail(status->control.flags & IEEE80211_TXCTL_REQ_TX_STATUS ? + skb_queue_tail(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS ? &local->skb_queue : &local->skb_queue_unreliable, skb); tmp = skb_queue_len(&local->skb_queue) + skb_queue_len(&local->skb_queue_unreliable); while (tmp > IEEE80211_IRQSAFE_QUEUE_LIMIT && (skb = skb_dequeue(&local->skb_queue_unreliable))) { - memcpy(&saved, skb->cb, sizeof(saved)); - kfree(saved); dev_kfree_skb_irq(skb); tmp--; I802_DEBUG_INC(local->tx_status_drop); @@ -1225,7 +1202,6 @@ static void ieee80211_tasklet_handler(unsigned long data) struct ieee80211_local *local = (struct ieee80211_local *) data; struct sk_buff *skb; struct ieee80211_rx_status rx_status; - struct ieee80211_tx_status *tx_status; struct ieee80211_ra_tid *ra_tid; while ((skb = skb_dequeue(&local->skb_queue)) || @@ -1240,12 +1216,8 @@ static void ieee80211_tasklet_handler(unsigned long data) __ieee80211_rx(local_to_hw(local), skb, &rx_status); break; case IEEE80211_TX_STATUS_MSG: - /* get pointer to saved status out of skb->cb */ - memcpy(&tx_status, skb->cb, sizeof(tx_status)); skb->pkt_type = 0; - ieee80211_tx_status(local_to_hw(local), - skb, tx_status); - kfree(tx_status); + ieee80211_tx_status(local_to_hw(local), skb); break; case IEEE80211_DELBA_MSG: ra_tid = (struct ieee80211_ra_tid *) &skb->cb; @@ -1274,24 +1246,15 @@ static void ieee80211_tasklet_handler(unsigned long data) * Also, tx_packet_data in cb is restored from tx_control. */ static void ieee80211_remove_tx_extra(struct ieee80211_local *local, struct ieee80211_key *key, - struct sk_buff *skb, - struct ieee80211_tx_control *control) + struct sk_buff *skb) { int hdrlen, iv_len, mic_len; - struct ieee80211_tx_packet_data *pkt_data; - - pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; - pkt_data->ifindex = vif_to_sdata(control->vif)->dev->ifindex; - pkt_data->flags = 0; - if (control->flags & IEEE80211_TXCTL_REQ_TX_STATUS) - pkt_data->flags |= IEEE80211_TXPD_REQ_TX_STATUS; - if (control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT) - pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT; - if (control->flags & IEEE80211_TXCTL_REQUEUE) - pkt_data->flags |= IEEE80211_TXPD_REQUEUE; - if (control->flags & IEEE80211_TXCTL_EAPOL_FRAME) - pkt_data->flags |= IEEE80211_TXPD_EAPOL_FRAME; - pkt_data->queue = control->queue; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + + info->flags &= IEEE80211_TX_CTL_REQ_TX_STATUS | + IEEE80211_TX_CTL_DO_NOT_ENCRYPT | + IEEE80211_TX_CTL_REQUEUE | + IEEE80211_TX_CTL_EAPOL_FRAME; hdrlen = ieee80211_get_hdrlen_from_skb(skb); @@ -1338,9 +1301,10 @@ no_key: static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, struct sta_info *sta, - struct sk_buff *skb, - struct ieee80211_tx_status *status) + struct sk_buff *skb) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + sta->tx_filtered_count++; /* @@ -1382,18 +1346,16 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, */ if (test_sta_flags(sta, WLAN_STA_PS) && skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) { - ieee80211_remove_tx_extra(local, sta->key, skb, - &status->control); + ieee80211_remove_tx_extra(local, sta->key, skb); skb_queue_tail(&sta->tx_filtered, skb); return; } if (!test_sta_flags(sta, WLAN_STA_PS) && - !(status->control.flags & IEEE80211_TXCTL_REQUEUE)) { + !(info->flags & IEEE80211_TX_CTL_REQUEUE)) { /* Software retry the packet once */ - status->control.flags |= IEEE80211_TXCTL_REQUEUE; - ieee80211_remove_tx_extra(local, sta->key, skb, - &status->control); + info->flags |= IEEE80211_TX_CTL_REQUEUE; + ieee80211_remove_tx_extra(local, sta->key, skb); dev_queue_xmit(skb); return; } @@ -1407,28 +1369,20 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, dev_kfree_skb(skb); } -void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_status *status) +void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) { struct sk_buff *skb2; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); u16 frag, type; struct ieee80211_tx_status_rtap_hdr *rthdr; struct ieee80211_sub_if_data *sdata; struct net_device *prev_dev = NULL; - if (!status) { - printk(KERN_ERR - "%s: ieee80211_tx_status called with NULL status\n", - wiphy_name(local->hw.wiphy)); - dev_kfree_skb(skb); - return; - } - rcu_read_lock(); - if (status->excessive_retries) { + if (info->status.excessive_retries) { struct sta_info *sta; sta = sta_info_get(local, hdr->addr1); if (sta) { @@ -1437,27 +1391,23 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, * The STA is in power save mode, so assume * that this TX packet failed because of that. */ - status->excessive_retries = 0; - status->flags |= IEEE80211_TX_STATUS_TX_FILTERED; - ieee80211_handle_filtered_frame(local, sta, - skb, status); + ieee80211_handle_filtered_frame(local, sta, skb); rcu_read_unlock(); return; } } } - if (status->flags & IEEE80211_TX_STATUS_TX_FILTERED) { + if (info->flags & IEEE80211_TX_STAT_TX_FILTERED) { struct sta_info *sta; sta = sta_info_get(local, hdr->addr1); if (sta) { - ieee80211_handle_filtered_frame(local, sta, skb, - status); + ieee80211_handle_filtered_frame(local, sta, skb); rcu_read_unlock(); return; } } else - rate_control_tx_status(local->mdev, skb, status); + rate_control_tx_status(local->mdev, skb); rcu_read_unlock(); @@ -1471,14 +1421,14 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, frag = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG; type = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_FTYPE; - if (status->flags & IEEE80211_TX_STATUS_ACK) { + if (info->flags & IEEE80211_TX_STAT_ACK) { if (frag == 0) { local->dot11TransmittedFrameCount++; if (is_multicast_ether_addr(hdr->addr1)) local->dot11MulticastTransmittedFrameCount++; - if (status->retry_count > 0) + if (info->status.retry_count > 0) local->dot11RetryCount++; - if (status->retry_count > 1) + if (info->status.retry_count > 1) local->dot11MultipleRetryCount++; } @@ -1524,17 +1474,17 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) | (1 << IEEE80211_RADIOTAP_DATA_RETRIES)); - if (!(status->flags & IEEE80211_TX_STATUS_ACK) && + if (!(info->flags & IEEE80211_TX_STAT_ACK) && !is_multicast_ether_addr(hdr->addr1)) rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL); - if ((status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS) && - (status->control.flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) + if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) && + (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS); - else if (status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS) + else if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS); - rthdr->data_retries = status->retry_count; + rthdr->data_retries = info->status.retry_count; /* XXX: is this sufficient for BPF? */ skb_set_mac_header(skb, 0); @@ -1895,7 +1845,9 @@ static int __init ieee80211_init(void) struct sk_buff *skb; int ret; - BUILD_BUG_ON(sizeof(struct ieee80211_tx_packet_data) > sizeof(skb->cb)); + BUILD_BUG_ON(sizeof(struct ieee80211_tx_info) > sizeof(skb->cb)); + BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, driver_data) + + IEEE80211_TX_INFO_DRIVER_DATA_SIZE > sizeof(skb->cb)); ret = rc80211_pid_init(); if (ret) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 6041493..9a26437 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -578,7 +578,7 @@ void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb, int encrypt) { struct ieee80211_sub_if_data *sdata; - struct ieee80211_tx_packet_data *pkt_data; + struct ieee80211_tx_info *info; sdata = IEEE80211_DEV_TO_SUB_IF(dev); skb->dev = sdata->local->mdev; @@ -586,11 +586,11 @@ void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb, skb_set_network_header(skb, 0); skb_set_transport_header(skb, 0); - pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; - memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data)); - pkt_data->ifindex = sdata->dev->ifindex; + info = IEEE80211_SKB_CB(skb); + memset(info, 0, sizeof(struct ieee80211_tx_info)); + info->control.ifindex = sdata->dev->ifindex; if (!encrypt) - pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT; + info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT; dev_queue_xmit(skb); } @@ -2314,7 +2314,7 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, int res, rates, i, j; struct sk_buff *skb; struct ieee80211_mgmt *mgmt; - struct ieee80211_tx_control control; + struct ieee80211_tx_info *control; struct rate_selection ratesel; u8 *pos; struct ieee80211_sub_if_data *sdata; @@ -2404,21 +2404,22 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, memcpy(pos, &bss->supp_rates[8], rates); } - memset(&control, 0, sizeof(control)); + control = IEEE80211_SKB_CB(skb); + rate_control_get_rate(dev, sband, skb, &ratesel); if (ratesel.rate_idx < 0) { printk(KERN_DEBUG "%s: Failed to determine TX rate " "for IBSS beacon\n", dev->name); break; } - control.vif = &sdata->vif; - control.tx_rate_idx = ratesel.rate_idx; + control->control.vif = &sdata->vif; + control->tx_rate_idx = ratesel.rate_idx; if (sdata->bss_conf.use_short_preamble && sband->bitrates[ratesel.rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE) - control.flags |= IEEE80211_TXCTL_SHORT_PREAMBLE; - control.antenna_sel_tx = local->hw.conf.antenna_sel_tx; - control.flags |= IEEE80211_TXCTL_NO_ACK; - control.retry_limit = 1; + control->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE; + control->antenna_sel_tx = local->hw.conf.antenna_sel_tx; + control->flags |= IEEE80211_TX_CTL_NO_ACK; + control->control.retry_limit = 1; ifsta->probe_resp = skb_copy(skb, GFP_ATOMIC); if (ifsta->probe_resp) { @@ -2433,8 +2434,7 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, } if (local->ops->beacon_update && - local->ops->beacon_update(local_to_hw(local), - skb, &control) == 0) { + local->ops->beacon_update(local_to_hw(local), skb) == 0) { printk(KERN_DEBUG "%s: Configured IBSS beacon " "template\n", dev->name); skb = NULL; diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index a29148d..0ed9c8a 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h @@ -34,8 +34,7 @@ struct rate_control_ops { struct module *module; const char *name; void (*tx_status)(void *priv, struct net_device *dev, - struct sk_buff *skb, - struct ieee80211_tx_status *status); + struct sk_buff *skb); void (*get_rate)(void *priv, struct net_device *dev, struct ieee80211_supported_band *band, struct sk_buff *skb, @@ -77,13 +76,12 @@ struct rate_control_ref *rate_control_get(struct rate_control_ref *ref); void rate_control_put(struct rate_control_ref *ref); static inline void rate_control_tx_status(struct net_device *dev, - struct sk_buff *skb, - struct ieee80211_tx_status *status) + struct sk_buff *skb) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct rate_control_ref *ref = local->rate_ctrl; - ref->ops->tx_status(ref->priv, dev, skb, status); + ref->ops->tx_status(ref->priv, dev, skb); } diff --git a/net/mac80211/rc80211_pid.h b/net/mac80211/rc80211_pid.h index 04afc13..2078803 100644 --- a/net/mac80211/rc80211_pid.h +++ b/net/mac80211/rc80211_pid.h @@ -61,7 +61,7 @@ enum rc_pid_event_type { union rc_pid_event_data { /* RC_PID_EVENT_TX_STATUS */ struct { - struct ieee80211_tx_status tx_status; + struct ieee80211_tx_info tx_status; }; /* RC_PID_EVENT_TYPE_RATE_CHANGE */ /* RC_PID_EVENT_TYPE_TX_RATE */ @@ -158,7 +158,7 @@ struct rc_pid_debugfs_entries { }; void rate_control_pid_event_tx_status(struct rc_pid_event_buffer *buf, - struct ieee80211_tx_status *stat); + struct ieee80211_tx_info *stat); void rate_control_pid_event_rate_change(struct rc_pid_event_buffer *buf, int index, int rate); diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c index 14cde36..e894541 100644 --- a/net/mac80211/rc80211_pid_algo.c +++ b/net/mac80211/rc80211_pid_algo.c @@ -237,8 +237,7 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo, } static void rate_control_pid_tx_status(void *priv, struct net_device *dev, - struct sk_buff *skb, - struct ieee80211_tx_status *status) + struct sk_buff *skb) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; @@ -248,6 +247,7 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev, struct rc_pid_sta_info *spinfo; unsigned long period; struct ieee80211_supported_band *sband; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); rcu_read_lock(); @@ -266,28 +266,28 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev, /* Ignore all frames that were sent with a different rate than the rate * we currently advise mac80211 to use. */ - if (status->control.tx_rate_idx != sta->txrate_idx) + if (info->tx_rate_idx != sta->txrate_idx) goto unlock; spinfo = sta->rate_ctrl_priv; spinfo->tx_num_xmit++; #ifdef CONFIG_MAC80211_DEBUGFS - rate_control_pid_event_tx_status(&spinfo->events, status); + rate_control_pid_event_tx_status(&spinfo->events, info); #endif /* We count frames that totally failed to be transmitted as two bad * frames, those that made it out but had some retries as one good and * one bad frame. */ - if (status->excessive_retries) { + if (info->status.excessive_retries) { spinfo->tx_num_failed += 2; spinfo->tx_num_xmit++; - } else if (status->retry_count) { + } else if (info->status.retry_count) { spinfo->tx_num_failed++; spinfo->tx_num_xmit++; } - if (status->excessive_retries) { + if (info->status.excessive_retries) { sta->tx_retry_failed++; sta->tx_num_consecutive_failures++; sta->tx_num_mpdu_fail++; @@ -295,8 +295,8 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev, sta->tx_num_consecutive_failures = 0; sta->tx_num_mpdu_ok++; } - sta->tx_retry_count += status->retry_count; - sta->tx_num_mpdu_fail += status->retry_count; + sta->tx_retry_count += info->status.retry_count; + sta->tx_num_mpdu_fail += info->status.retry_count; /* Update PID controller state. */ period = (HZ * pinfo->sampling_period + 500) / 1000; diff --git a/net/mac80211/rc80211_pid_debugfs.c b/net/mac80211/rc80211_pid_debugfs.c index ff5c380f..8121d3b 100644 --- a/net/mac80211/rc80211_pid_debugfs.c +++ b/net/mac80211/rc80211_pid_debugfs.c @@ -39,11 +39,11 @@ static void rate_control_pid_event(struct rc_pid_event_buffer *buf, } void rate_control_pid_event_tx_status(struct rc_pid_event_buffer *buf, - struct ieee80211_tx_status *stat) + struct ieee80211_tx_info *stat) { union rc_pid_event_data evd; - memcpy(&evd.tx_status, stat, sizeof(struct ieee80211_tx_status)); + memcpy(&evd.tx_status, stat, sizeof(struct ieee80211_tx_info)); rate_control_pid_event(buf, RC_PID_EVENT_TYPE_TX_STATUS, &evd); } @@ -167,8 +167,8 @@ static ssize_t rate_control_pid_events_read(struct file *file, char __user *buf, switch (ev->type) { case RC_PID_EVENT_TYPE_TX_STATUS: p += snprintf(pb + p, length - p, "tx_status %u %u", - ev->data.tx_status.excessive_retries, - ev->data.tx_status.retry_count); + ev->data.tx_status.status.excessive_retries, + ev->data.tx_status.status.retry_count); break; case RC_PID_EVENT_TYPE_RATE_CHANGE: p += snprintf(pb + p, length - p, "rate_change %d %d", diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index fa68305..cf0de3b 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -714,7 +714,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) struct sk_buff *skb; int sent = 0; struct ieee80211_sub_if_data *sdata; - struct ieee80211_tx_packet_data *pkt_data; + struct ieee80211_tx_info *info; DECLARE_MAC_BUF(mac); sdata = sta->sdata; @@ -734,13 +734,13 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) /* Send all buffered frames to the station */ while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) { - pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; + info = IEEE80211_SKB_CB(skb); sent++; - pkt_data->flags |= IEEE80211_TXPD_REQUEUE; + info->flags |= IEEE80211_TX_CTL_REQUEUE; dev_queue_xmit(skb); } while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { - pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; + info = IEEE80211_SKB_CB(skb); local->total_ps_buffered--; sent++; #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG @@ -748,7 +748,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) "since STA not sleeping anymore\n", dev->name, print_mac(mac, sta->addr), sta->aid); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ - pkt_data->flags |= IEEE80211_TXPD_REQUEUE; + info->flags |= IEEE80211_TX_CTL_REQUEUE; dev_queue_xmit(skb); } diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index baf5e47..ef31493 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -511,20 +511,20 @@ static inline int sta_info_buffer_expired(struct ieee80211_local *local, struct sta_info *sta, struct sk_buff *skb) { - struct ieee80211_tx_packet_data *pkt_data; + struct ieee80211_tx_info *info; int timeout; if (!skb) return 0; - pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; + info = IEEE80211_SKB_CB(skb); /* Timeout: (2 * listen_interval * beacon_int * 1024 / 1000000) sec */ timeout = (sta->listen_interval * local->hw.conf.beacon_int * 32 / 15625) * HZ; if (timeout < STA_TX_BUFFER_EXPIRE) timeout = STA_TX_BUFFER_EXPIRE; - return time_after(jiffies, pkt_data->jiffies + timeout); + return time_after(jiffies, info->control.jiffies + timeout); } diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index e89cc16..f592290 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -32,7 +32,7 @@ * @WLAN_STA_WDS: Station is one of our WDS peers. * @WLAN_STA_PSPOLL: Station has just PS-polled us. * @WLAN_STA_CLEAR_PS_FILT: Clear PS filter in hardware (using the - * IEEE80211_TXCTL_CLEAR_PS_FILT control flag) when the next + * IEEE80211_TX_CTL_CLEAR_PS_FILT control flag) when the next * frame to this station is transmitted. */ enum ieee80211_sta_info_flags { diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 666158f..ac9a4af 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -238,12 +238,12 @@ static ieee80211_tx_result ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG - struct sk_buff *skb = tx->skb; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); u32 sta_flags; - if (unlikely(tx->flags & IEEE80211_TX_INJECTED)) + if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED)) return TX_CONTINUE; if (unlikely(tx->local->sta_sw_scanning) && @@ -348,6 +348,8 @@ static void purge_old_ps_buffers(struct ieee80211_local *local) static ieee80211_tx_result ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); + /* * broadcast/multicast frame * @@ -383,7 +385,7 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx) } /* buffered in hardware */ - tx->control->flags |= IEEE80211_TXCTL_SEND_AFTER_DTIM; + info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM; return TX_CONTINUE; } @@ -392,6 +394,7 @@ static ieee80211_tx_result ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) { struct sta_info *sta = tx->sta; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); u32 staflags; DECLARE_MAC_BUF(mac); @@ -404,7 +407,6 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) if (unlikely((staflags & WLAN_STA_PS) && !(staflags & WLAN_STA_PSPOLL))) { - struct ieee80211_tx_packet_data *pkt_data; #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "STA %s aid %d: PS buffer (entries " "before %d)\n", @@ -428,8 +430,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) if (skb_queue_empty(&sta->ps_tx_buf)) sta_info_set_tim_bit(sta); - pkt_data = (struct ieee80211_tx_packet_data *)tx->skb->cb; - pkt_data->jiffies = jiffies; + info->control.jiffies = jiffies; skb_queue_tail(&sta->ps_tx_buf, tx->skb); return TX_QUEUED; } @@ -461,17 +462,18 @@ static ieee80211_tx_result ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) { struct ieee80211_key *key; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); u16 fc = tx->fc; - if (unlikely(tx->control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) + if (unlikely(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT)) tx->key = NULL; else if (tx->sta && (key = rcu_dereference(tx->sta->key))) tx->key = key; else if ((key = rcu_dereference(tx->sdata->default_key))) tx->key = key; else if (tx->sdata->drop_unencrypted && - !(tx->control->flags & IEEE80211_TXCTL_EAPOL_FRAME) && - !(tx->flags & IEEE80211_TX_INJECTED)) { + !(info->flags & IEEE80211_TX_CTL_EAPOL_FRAME) && + !(info->flags & IEEE80211_TX_CTL_INJECTED)) { I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted); return TX_DROP; } else @@ -500,7 +502,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) } if (!tx->key || !(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) - tx->control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; + info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT; return TX_CONTINUE; } @@ -510,6 +512,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) { struct rate_selection rsel; struct ieee80211_supported_band *sband; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); sband = tx->local->hw.wiphy->bands[tx->channel->band]; @@ -517,18 +520,17 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) rate_control_get_rate(tx->dev, sband, tx->skb, &rsel); tx->rate_idx = rsel.rate_idx; if (unlikely(rsel.probe_idx >= 0)) { - tx->control->flags |= - IEEE80211_TXCTL_RATE_CTRL_PROBE; + info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG; - tx->control->alt_retry_rate_idx = tx->rate_idx; + info->control.alt_retry_rate_idx = tx->rate_idx; tx->rate_idx = rsel.probe_idx; } else - tx->control->alt_retry_rate_idx = -1; + info->control.alt_retry_rate_idx = -1; if (unlikely(tx->rate_idx < 0)) return TX_DROP; } else - tx->control->alt_retry_rate_idx = -1; + info->control.alt_retry_rate_idx = -1; if (tx->sdata->bss_conf.use_cts_prot && (tx->flags & IEEE80211_TX_FRAGMENTED) && (rsel.nonerp_idx >= 0)) { @@ -538,13 +540,13 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) else tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG; tx->rate_idx = rsel.nonerp_idx; - tx->control->tx_rate_idx = rsel.nonerp_idx; - tx->control->flags &= ~IEEE80211_TXCTL_RATE_CTRL_PROBE; + info->tx_rate_idx = rsel.nonerp_idx; + info->flags &= ~IEEE80211_TX_CTL_RATE_CTRL_PROBE; } else { tx->last_frag_rate_idx = tx->rate_idx; - tx->control->tx_rate_idx = tx->rate_idx; + info->tx_rate_idx = tx->rate_idx; } - tx->control->tx_rate_idx = tx->rate_idx; + info->tx_rate_idx = tx->rate_idx; return TX_CONTINUE; } @@ -555,28 +557,32 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; u16 fc = le16_to_cpu(hdr->frame_control); u16 dur; - struct ieee80211_tx_control *control = tx->control; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); struct ieee80211_supported_band *sband; sband = tx->local->hw.wiphy->bands[tx->channel->band]; - if (!control->retry_limit) { + if (tx->sta) + info->control.aid = tx->sta->aid; + + if (!info->control.retry_limit) { if (!is_multicast_ether_addr(hdr->addr1)) { - if (tx->skb->len + FCS_LEN > tx->local->rts_threshold + int len = min_t(int, tx->skb->len + FCS_LEN, + tx->local->fragmentation_threshold); + if (len > tx->local->rts_threshold && tx->local->rts_threshold < - IEEE80211_MAX_RTS_THRESHOLD) { - control->flags |= - IEEE80211_TXCTL_USE_RTS_CTS; - control->flags |= - IEEE80211_TXCTL_LONG_RETRY_LIMIT; - control->retry_limit = + IEEE80211_MAX_RTS_THRESHOLD) { + info->flags |= IEEE80211_TX_CTL_USE_RTS_CTS; + info->flags |= + IEEE80211_TX_CTL_LONG_RETRY_LIMIT; + info->control.retry_limit = tx->local->long_retry_limit; } else { - control->retry_limit = + info->control.retry_limit = tx->local->short_retry_limit; } } else { - control->retry_limit = 1; + info->control.retry_limit = 1; } } @@ -585,7 +591,7 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) * frames. * TODO: The last fragment could still use multiple retry * rates. */ - control->alt_retry_rate_idx = -1; + info->control.alt_retry_rate_idx = -1; } /* Use CTS protection for unicast frames sent using extended rates if @@ -595,8 +601,8 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) (sband->bitrates[tx->rate_idx].flags & IEEE80211_RATE_ERP_G) && (tx->flags & IEEE80211_TX_UNICAST) && tx->sdata->bss_conf.use_cts_prot && - !(control->flags & IEEE80211_TXCTL_USE_RTS_CTS)) - control->flags |= IEEE80211_TXCTL_USE_CTS_PROTECT; + !(info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)) + info->flags |= IEEE80211_TX_CTL_USE_CTS_PROTECT; /* Transmit data frames using short preambles if the driver supports * short preambles at the selected rate and short preambles are @@ -605,7 +611,7 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) (sband->bitrates[tx->rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE) && tx->sdata->bss_conf.use_short_preamble && (!tx->sta || test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE))) { - tx->control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE; + info->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE; } /* Setup duration field for the first fragment of the frame. Duration @@ -616,8 +622,8 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) tx->extra_frag[0]->len : 0); hdr->duration_id = cpu_to_le16(dur); - if ((control->flags & IEEE80211_TXCTL_USE_RTS_CTS) || - (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) { + if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) || + (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) { struct ieee80211_supported_band *sband; struct ieee80211_rate *rate; s8 baserate = -1; @@ -626,7 +632,7 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) sband = tx->local->hw.wiphy->bands[tx->channel->band]; /* Do not use multiple retry rates when using RTS/CTS */ - control->alt_retry_rate_idx = -1; + info->control.alt_retry_rate_idx = -1; /* Use min(data rate, max base rate) as CTS/RTS rate */ rate = &sband->bitrates[tx->rate_idx]; @@ -642,13 +648,13 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) } if (baserate >= 0) - control->rts_cts_rate_idx = baserate; + info->control.rts_cts_rate_idx = baserate; else - control->rts_cts_rate_idx = 0; + info->control.rts_cts_rate_idx = 0; } if (tx->sta) - control->aid = tx->sta->aid; + info->control.aid = tx->sta->aid; return TX_CONTINUE; } @@ -762,6 +768,7 @@ ieee80211_tx_h_stats(struct ieee80211_tx_data *tx) u32 load = 0, hdrtime; struct ieee80211_rate *rate; struct ieee80211_supported_band *sband; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); sband = tx->local->hw.wiphy->bands[tx->channel->band]; rate = &sband->bitrates[tx->rate_idx]; @@ -786,9 +793,9 @@ ieee80211_tx_h_stats(struct ieee80211_tx_data *tx) if (!is_multicast_ether_addr(hdr->addr1)) load += hdrtime; - if (tx->control->flags & IEEE80211_TXCTL_USE_RTS_CTS) + if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) load += 2 * hdrtime; - else if (tx->control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) + else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) load += hdrtime; /* TODO: optimise again */ @@ -839,6 +846,7 @@ static ieee80211_tx_handler ieee80211_tx_handlers[] = ieee80211_tx_h_rate_ctrl, ieee80211_tx_h_misc, ieee80211_tx_h_fragment, + /* handlers after fragment must be aware of tx info fragmentation! */ ieee80211_tx_h_encrypt, ieee80211_tx_h_stats, NULL @@ -867,12 +875,12 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, (struct ieee80211_radiotap_header *) skb->data; struct ieee80211_supported_band *sband; int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len); - struct ieee80211_tx_control *control = tx->control; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); sband = tx->local->hw.wiphy->bands[tx->channel->band]; - control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; - tx->flags |= IEEE80211_TX_INJECTED; + info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT; + info->flags |= IEEE80211_TX_CTL_INJECTED; tx->flags &= ~IEEE80211_TX_FRAGMENTED; /* @@ -920,7 +928,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, * radiotap uses 0 for 1st ant, mac80211 is 1 for * 1st ant */ - control->antenna_sel_tx = (*iterator.this_arg) + 1; + info->antenna_sel_tx = (*iterator.this_arg) + 1; break; #if 0 @@ -944,8 +952,8 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, skb_trim(skb, skb->len - FCS_LEN); } if (*iterator.this_arg & IEEE80211_RADIOTAP_F_WEP) - control->flags &= - ~IEEE80211_TXCTL_DO_NOT_ENCRYPT; + info->flags &= + ~IEEE80211_TX_CTL_DO_NOT_ENCRYPT; if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG) tx->flags |= IEEE80211_TX_FRAGMENTED; break; @@ -980,12 +988,12 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, static ieee80211_tx_result __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, struct sk_buff *skb, - struct net_device *dev, - struct ieee80211_tx_control *control) + struct net_device *dev) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_hdr *hdr; struct ieee80211_sub_if_data *sdata; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int hdrlen; @@ -994,7 +1002,7 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, tx->dev = dev; /* use original interface */ tx->local = local; tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev); - tx->control = control; + tx->channel = local->hw.conf.channel; /* * Set this flag (used below to indicate "automatic fragmentation"), * it will be cleared/left by radiotap as desired. @@ -1021,10 +1029,10 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, if (is_multicast_ether_addr(hdr->addr1)) { tx->flags &= ~IEEE80211_TX_UNICAST; - control->flags |= IEEE80211_TXCTL_NO_ACK; + info->flags |= IEEE80211_TX_CTL_NO_ACK; } else { tx->flags |= IEEE80211_TX_UNICAST; - control->flags &= ~IEEE80211_TXCTL_NO_ACK; + info->flags &= ~IEEE80211_TX_CTL_NO_ACK; } if (tx->flags & IEEE80211_TX_FRAGMENTED) { @@ -1037,16 +1045,16 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, } if (!tx->sta) - control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT; + info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; else if (test_and_clear_sta_flags(tx->sta, WLAN_STA_CLEAR_PS_FILT)) - control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT; + info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; hdrlen = ieee80211_get_hdrlen(tx->fc); if (skb->len > hdrlen + sizeof(rfc1042_header) + 2) { u8 *pos = &skb->data[hdrlen + sizeof(rfc1042_header)]; tx->ethertype = (pos[0] << 8) | pos[1]; } - control->flags |= IEEE80211_TXCTL_FIRST_FRAGMENT; + info->flags |= IEEE80211_TX_CTL_FIRST_FRAGMENT; return TX_CONTINUE; } @@ -1056,14 +1064,12 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, */ static int ieee80211_tx_prepare(struct ieee80211_tx_data *tx, struct sk_buff *skb, - struct net_device *mdev, - struct ieee80211_tx_control *control) + struct net_device *mdev) { - struct ieee80211_tx_packet_data *pkt_data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct net_device *dev; - pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; - dev = dev_get_by_index(&init_net, pkt_data->ifindex); + dev = dev_get_by_index(&init_net, info->control.ifindex); if (unlikely(dev && !is_ieee80211_device(dev, mdev))) { dev_put(dev); dev = NULL; @@ -1071,7 +1077,7 @@ static int ieee80211_tx_prepare(struct ieee80211_tx_data *tx, if (unlikely(!dev)) return -ENODEV; /* initialises tx with control */ - __ieee80211_tx_prepare(tx, skb, dev, control); + __ieee80211_tx_prepare(tx, skb, dev); dev_put(dev); return 0; } @@ -1079,7 +1085,7 @@ static int ieee80211_tx_prepare(struct ieee80211_tx_data *tx, static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, struct ieee80211_tx_data *tx) { - struct ieee80211_tx_control *control = tx->control; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int ret, i; if (!ieee80211_qdisc_installed(local->mdev) && @@ -1090,39 +1096,39 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, if (skb) { ieee80211_dump_frame(wiphy_name(local->hw.wiphy), "TX to low-level driver", skb); - ret = local->ops->tx(local_to_hw(local), skb, control); + ret = local->ops->tx(local_to_hw(local), skb); if (ret) return IEEE80211_TX_AGAIN; local->mdev->trans_start = jiffies; ieee80211_led_tx(local, 1); } if (tx->extra_frag) { - control->flags &= ~(IEEE80211_TXCTL_USE_RTS_CTS | - IEEE80211_TXCTL_USE_CTS_PROTECT | - IEEE80211_TXCTL_CLEAR_PS_FILT | - IEEE80211_TXCTL_FIRST_FRAGMENT); for (i = 0; i < tx->num_extra_frag; i++) { if (!tx->extra_frag[i]) continue; - if (__ieee80211_queue_stopped(local, control->queue)) + info = IEEE80211_SKB_CB(tx->extra_frag[i]); + info->flags &= ~(IEEE80211_TX_CTL_USE_RTS_CTS | + IEEE80211_TX_CTL_USE_CTS_PROTECT | + IEEE80211_TX_CTL_CLEAR_PS_FILT | + IEEE80211_TX_CTL_FIRST_FRAGMENT); + if (__ieee80211_queue_stopped(local, info->queue)) return IEEE80211_TX_FRAG_AGAIN; if (i == tx->num_extra_frag) { - control->tx_rate_idx = tx->last_frag_rate_idx; + info->tx_rate_idx = tx->last_frag_rate_idx; if (tx->flags & IEEE80211_TX_PROBE_LAST_FRAG) - control->flags |= - IEEE80211_TXCTL_RATE_CTRL_PROBE; + info->flags |= + IEEE80211_TX_CTL_RATE_CTRL_PROBE; else - control->flags &= - ~IEEE80211_TXCTL_RATE_CTRL_PROBE; + info->flags &= + ~IEEE80211_TX_CTL_RATE_CTRL_PROBE; } ieee80211_dump_frame(wiphy_name(local->hw.wiphy), "TX to low-level driver", tx->extra_frag[i]); ret = local->ops->tx(local_to_hw(local), - tx->extra_frag[i], - control); + tx->extra_frag[i]); if (ret) return IEEE80211_TX_FRAG_AGAIN; local->mdev->trans_start = jiffies; @@ -1135,17 +1141,18 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, return IEEE80211_TX_OK; } -static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, - struct ieee80211_tx_control *control) +static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct sta_info *sta; ieee80211_tx_handler *handler; struct ieee80211_tx_data tx; ieee80211_tx_result res = TX_DROP, res_prepare; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int ret, i; + int queue = info->queue; - WARN_ON(__ieee80211_queue_pending(local, control->queue)); + WARN_ON(__ieee80211_queue_pending(local, queue)); if (unlikely(skb->len < 10)) { dev_kfree_skb(skb); @@ -1155,7 +1162,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, rcu_read_lock(); /* initialises tx */ - res_prepare = __ieee80211_tx_prepare(&tx, skb, dev, control); + res_prepare = __ieee80211_tx_prepare(&tx, skb, dev); if (res_prepare == TX_DROP) { dev_kfree_skb(skb); @@ -1165,7 +1172,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, sta = tx.sta; tx.channel = local->hw.conf.channel; - control->band = tx.channel->band; + info->band = tx.channel->band; for (handler = ieee80211_tx_handlers; *handler != NULL; handler++) { @@ -1174,7 +1181,8 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, break; } - skb = tx.skb; /* handlers are allowed to change skb */ + if (WARN_ON(tx.skb != skb)) + goto drop; if (unlikely(res == TX_DROP)) { I802_DEBUG_INC(local->tx_handlers_drop); @@ -1209,12 +1217,12 @@ retry: ret = __ieee80211_tx(local, skb, &tx); if (ret) { struct ieee80211_tx_stored_packet *store = - &local->pending_packet[control->queue]; + &local->pending_packet[info->queue]; if (ret == IEEE80211_TX_FRAG_AGAIN) skb = NULL; set_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[control->queue]); + &local->state[queue]); smp_mb(); /* When the driver gets out of buffers during sending of * fragments and calls ieee80211_stop_queue, there is @@ -1225,13 +1233,11 @@ retry: * called with IEEE80211_LINK_STATE_PENDING. Prevent this by * continuing transmitting here when that situation is * possible to have happened. */ - if (!__ieee80211_queue_stopped(local, control->queue)) { + if (!__ieee80211_queue_stopped(local, queue)) { clear_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[control->queue]); + &local->state[queue]); goto retry; } - memcpy(&store->control, control, - sizeof(struct ieee80211_tx_control)); store->skb = skb; store->extra_frag = tx.extra_frag; store->num_extra_frag = tx.num_extra_frag; @@ -1258,21 +1264,14 @@ retry: int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct ieee80211_tx_control control; - struct ieee80211_tx_packet_data *pkt_data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct net_device *odev = NULL; struct ieee80211_sub_if_data *osdata; int headroom; int ret; - /* - * copy control out of the skb so other people can use skb->cb - */ - pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; - memset(&control, 0, sizeof(struct ieee80211_tx_control)); - - if (pkt_data->ifindex) - odev = dev_get_by_index(&init_net, pkt_data->ifindex); + if (info->control.ifindex) + odev = dev_get_by_index(&init_net, info->control.ifindex); if (unlikely(odev && !is_ieee80211_device(odev, dev))) { dev_put(odev); odev = NULL; @@ -1285,6 +1284,7 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, dev_kfree_skb(skb); return 0; } + osdata = IEEE80211_DEV_TO_SUB_IF(odev); headroom = osdata->local->tx_headroom + IEEE80211_ENCRYPT_HEADROOM; @@ -1296,21 +1296,8 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, } } - control.vif = &osdata->vif; - control.type = osdata->vif.type; - if (pkt_data->flags & IEEE80211_TXPD_REQ_TX_STATUS) - control.flags |= IEEE80211_TXCTL_REQ_TX_STATUS; - if (pkt_data->flags & IEEE80211_TXPD_DO_NOT_ENCRYPT) - control.flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; - if (pkt_data->flags & IEEE80211_TXPD_REQUEUE) - control.flags |= IEEE80211_TXCTL_REQUEUE; - if (pkt_data->flags & IEEE80211_TXPD_EAPOL_FRAME) - control.flags |= IEEE80211_TXCTL_EAPOL_FRAME; - if (pkt_data->flags & IEEE80211_TXPD_AMPDU) - control.flags |= IEEE80211_TXCTL_AMPDU; - control.queue = pkt_data->queue; - - ret = ieee80211_tx(odev, skb, &control); + info->control.vif = &osdata->vif; + ret = ieee80211_tx(odev, skb); dev_put(odev); return ret; @@ -1320,7 +1307,7 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_tx_packet_data *pkt_data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_radiotap_header *prthdr = (struct ieee80211_radiotap_header *)skb->data; u16 len_rthdr; @@ -1342,14 +1329,12 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb, skb->dev = local->mdev; - pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; - memset(pkt_data, 0, sizeof(*pkt_data)); /* needed because we set skb device to master */ - pkt_data->ifindex = dev->ifindex; + info->control.ifindex = dev->ifindex; - pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT; + info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT; /* Interfaces should always request a status report */ - pkt_data->flags |= IEEE80211_TXPD_REQ_TX_STATUS; + info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; /* * fix up the pointers accounting for the radiotap @@ -1393,7 +1378,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_tx_packet_data *pkt_data; + struct ieee80211_tx_info *info; struct ieee80211_sub_if_data *sdata; int ret = 1, head_need; u16 ethertype, hdrlen, meshhdrlen = 0, fc; @@ -1625,14 +1610,14 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, nh_pos += hdrlen; h_pos += hdrlen; - pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; - memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data)); - pkt_data->ifindex = dev->ifindex; + info = IEEE80211_SKB_CB(skb); + memset(info, 0, sizeof(*info)); + info->control.ifindex = dev->ifindex; if (ethertype == ETH_P_PAE) - pkt_data->flags |= IEEE80211_TXPD_EAPOL_FRAME; + info->flags |= IEEE80211_TX_CTL_EAPOL_FRAME; /* Interfaces should always request a status report */ - pkt_data->flags |= IEEE80211_TXPD_REQ_TX_STATUS; + info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; skb->dev = local->mdev; dev->stats.tx_packets++; @@ -1693,7 +1678,6 @@ void ieee80211_tx_pending(unsigned long data) continue; } store = &local->pending_packet[i]; - tx.control = &store->control; tx.extra_frag = store->extra_frag; tx.num_extra_frag = store->num_extra_frag; tx.last_frag_rate_idx = store->last_frag_rate_idx; @@ -1786,11 +1770,11 @@ static void ieee80211_beacon_add_tim(struct ieee80211_local *local, } struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_tx_control *control) + struct ieee80211_vif *vif) { struct ieee80211_local *local = hw_to_local(hw); struct sk_buff *skb; + struct ieee80211_tx_info *info; struct net_device *bdev; struct ieee80211_sub_if_data *sdata = NULL; struct ieee80211_if_ap *ap = NULL; @@ -1896,31 +1880,32 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, goto out; } - if (control) { - control->band = band; - rate_control_get_rate(local->mdev, sband, skb, &rsel); - if (unlikely(rsel.rate_idx < 0)) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: ieee80211_beacon_get: " - "no rate found\n", - wiphy_name(local->hw.wiphy)); - } - dev_kfree_skb(skb); - skb = NULL; - goto out; - } + info = IEEE80211_SKB_CB(skb); + + info->band = band; + rate_control_get_rate(local->mdev, sband, skb, &rsel); - control->vif = vif; - control->tx_rate_idx = rsel.rate_idx; - if (sdata->bss_conf.use_short_preamble && - sband->bitrates[rsel.rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE) - control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE; - control->antenna_sel_tx = local->hw.conf.antenna_sel_tx; - control->flags |= IEEE80211_TXCTL_NO_ACK; - control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; - control->retry_limit = 1; - control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT; + if (unlikely(rsel.rate_idx < 0)) { + if (net_ratelimit()) { + printk(KERN_DEBUG "%s: ieee80211_beacon_get: " + "no rate found\n", + wiphy_name(local->hw.wiphy)); + } + dev_kfree_skb(skb); + skb = NULL; + goto out; } + + info->control.vif = vif; + info->tx_rate_idx = rsel.rate_idx; + if (sdata->bss_conf.use_short_preamble && + sband->bitrates[rsel.rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE) + info->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE; + info->antenna_sel_tx = local->hw.conf.antenna_sel_tx; + info->flags |= IEEE80211_TX_CTL_NO_ACK; + info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT; + info->control.retry_limit = 1; + info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; (*num_beacons)++; out: rcu_read_unlock(); @@ -1930,7 +1915,7 @@ EXPORT_SYMBOL(ieee80211_beacon_get); void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const void *frame, size_t frame_len, - const struct ieee80211_tx_control *frame_txctl, + const struct ieee80211_tx_info *frame_txctl, struct ieee80211_rts *rts) { const struct ieee80211_hdr *hdr = frame; @@ -1947,7 +1932,7 @@ EXPORT_SYMBOL(ieee80211_rts_get); void ieee80211_ctstoself_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const void *frame, size_t frame_len, - const struct ieee80211_tx_control *frame_txctl, + const struct ieee80211_tx_info *frame_txctl, struct ieee80211_cts *cts) { const struct ieee80211_hdr *hdr = frame; @@ -1963,8 +1948,7 @@ EXPORT_SYMBOL(ieee80211_ctstoself_get); struct sk_buff * ieee80211_get_buffered_bc(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_tx_control *control) + struct ieee80211_vif *vif) { struct ieee80211_local *local = hw_to_local(hw); struct sk_buff *skb; @@ -1976,6 +1960,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, struct ieee80211_sub_if_data *sdata; struct ieee80211_if_ap *bss = NULL; struct beacon_data *beacon; + struct ieee80211_tx_info *info; sdata = vif_to_sdata(vif); bdev = sdata->dev; @@ -1995,7 +1980,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, if (bss->dtim_count != 0) return NULL; /* send buffered bc/mc only after DTIM beacon */ - memset(control, 0, sizeof(*control)); + while (1) { skb = skb_dequeue(&bss->ps_bc_buf); if (!skb) @@ -2012,21 +1997,26 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, cpu_to_le16(IEEE80211_FCTL_MOREDATA); } - if (!ieee80211_tx_prepare(&tx, skb, local->mdev, control)) + if (!ieee80211_tx_prepare(&tx, skb, local->mdev)) break; dev_kfree_skb_any(skb); } + + info = IEEE80211_SKB_CB(skb); + sta = tx.sta; tx.flags |= IEEE80211_TX_PS_BUFFERED; tx.channel = local->hw.conf.channel; - control->band = tx.channel->band; + info->band = tx.channel->band; for (handler = ieee80211_tx_handlers; *handler != NULL; handler++) { res = (*handler)(&tx); if (res == TX_DROP || res == TX_QUEUED) break; } - skb = tx.skb; /* handlers are allowed to change skb */ + + if (WARN_ON(tx.skb != skb)) + return NULL; if (res == TX_DROP) { I802_DEBUG_INC(local->tx_handlers_drop); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 65a34fd..d9109de 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -258,7 +258,7 @@ EXPORT_SYMBOL(ieee80211_generic_frame_duration); __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, struct ieee80211_vif *vif, size_t frame_len, - const struct ieee80211_tx_control *frame_txctl) + const struct ieee80211_tx_info *frame_txctl) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_rate *rate; @@ -272,7 +272,7 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, short_preamble = sdata->bss_conf.use_short_preamble; - rate = &sband->bitrates[frame_txctl->rts_cts_rate_idx]; + rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx]; erp = 0; if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) @@ -295,7 +295,7 @@ EXPORT_SYMBOL(ieee80211_rts_duration); __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, struct ieee80211_vif *vif, size_t frame_len, - const struct ieee80211_tx_control *frame_txctl) + const struct ieee80211_tx_info *frame_txctl) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_rate *rate; @@ -309,7 +309,7 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, short_preamble = sdata->bss_conf.use_short_preamble; - rate = &sband->bitrates[frame_txctl->rts_cts_rate_idx]; + rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx]; erp = 0; if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) erp = rate->flags & IEEE80211_RATE_ERP_G; @@ -317,7 +317,7 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, /* Data frame duration */ dur = ieee80211_frame_duration(local, frame_len, rate->bitrate, erp, short_preamble); - if (!(frame_txctl->flags & IEEE80211_TXCTL_NO_ACK)) { + if (!(frame_txctl->flags & IEEE80211_TX_CTL_NO_ACK)) { /* ACK duration */ dur += ieee80211_frame_duration(local, 10, rate->bitrate, erp, short_preamble); diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index 3cbae42..1e7f03d 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c @@ -333,11 +333,16 @@ ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx) static int wep_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + + info->control.iv_len = WEP_IV_LEN; + info->control.icv_len = WEP_ICV_LEN; + if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { + info->control.hw_key = &tx->key->conf; if (ieee80211_wep_encrypt(tx->local, skb, tx->key)) return -1; } else { - tx->control->hw_key = &tx->key->conf; if (tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) { if (!ieee80211_wep_add_iv(tx->local, skb, tx->key)) return -1; @@ -349,8 +354,6 @@ static int wep_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) ieee80211_tx_result ieee80211_crypto_wep_encrypt(struct ieee80211_tx_data *tx) { - tx->control->iv_len = WEP_IV_LEN; - tx->control->icv_len = WEP_ICV_LEN; ieee80211_tx_set_protected(tx); if (wep_encrypt_skb(tx, tx->skb) < 0) { diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index c87baf4..477690f 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -149,8 +149,7 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr); struct ieee80211_hw *hw = &local->hw; struct ieee80211_sched_data *q = qdisc_priv(qd); - struct ieee80211_tx_packet_data *pkt_data = - (struct ieee80211_tx_packet_data *) skb->cb; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; unsigned short fc = le16_to_cpu(hdr->frame_control); struct Qdisc *qdisc; @@ -158,8 +157,8 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) int err, queue; u8 tid; - if (pkt_data->flags & IEEE80211_TXPD_REQUEUE) { - queue = pkt_data->queue; + if (info->flags & IEEE80211_TX_CTL_REQUEUE) { + queue = info->queue; rcu_read_lock(); sta = sta_info_get(local, hdr->addr1); tid = skb->priority & QOS_CONTROL_TAG1D_MASK; @@ -168,9 +167,9 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) if ((ampdu_queue < QD_NUM(hw)) && test_bit(ampdu_queue, q->qdisc_pool)) { queue = ampdu_queue; - pkt_data->flags |= IEEE80211_TXPD_AMPDU; + info->flags |= IEEE80211_TX_CTL_AMPDU; } else { - pkt_data->flags &= ~IEEE80211_TXPD_AMPDU; + info->flags &= ~IEEE80211_TX_CTL_AMPDU; } } rcu_read_unlock(); @@ -206,9 +205,9 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) if ((ampdu_queue < QD_NUM(hw)) && test_bit(ampdu_queue, q->qdisc_pool)) { queue = ampdu_queue; - pkt_data->flags |= IEEE80211_TXPD_AMPDU; + info->flags |= IEEE80211_TX_CTL_AMPDU; } else { - pkt_data->flags &= ~IEEE80211_TXPD_AMPDU; + info->flags &= ~IEEE80211_TX_CTL_AMPDU; } } @@ -220,7 +219,7 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) err = NET_XMIT_DROP; } else { tid = skb->priority & QOS_CONTROL_TAG1D_MASK; - pkt_data->queue = (unsigned int) queue; + info->queue = (unsigned int) queue; qdisc = q->queues[queue]; err = qdisc->enqueue(skb, qdisc); if (err == NET_XMIT_SUCCESS) { @@ -241,13 +240,12 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) static int wme_qdiscop_requeue(struct sk_buff *skb, struct Qdisc* qd) { struct ieee80211_sched_data *q = qdisc_priv(qd); - struct ieee80211_tx_packet_data *pkt_data = - (struct ieee80211_tx_packet_data *) skb->cb; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct Qdisc *qdisc; int err; /* we recorded which queue to use earlier! */ - qdisc = q->queues[pkt_data->queue]; + qdisc = q->queues[info->queue]; if ((err = qdisc->ops->requeue(skb, qdisc)) == 0) { qd->q.qlen++; diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index d730449..d6635f6 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -183,15 +183,25 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) } -static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, - struct sk_buff *skb, int test) +static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_key *key = tx->key; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int hdrlen, len, tailneed; u16 fc; u8 *pos; + info->control.icv_len = TKIP_ICV_LEN; + info->control.iv_len = TKIP_IV_LEN; + + if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && + !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { + /* hwaccel - with no need for preallocated room for IV/ICV */ + info->control.hw_key = &tx->key->conf; + return TX_CONTINUE; + } + fc = le16_to_cpu(hdr->frame_control); hdrlen = ieee80211_get_hdrlen(fc); len = skb->len - hdrlen; @@ -228,7 +238,7 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, 0x7f), (u8) key->u.tkip.tx.iv16); - tx->control->hw_key = &tx->key->conf; + info->control.hw_key = &tx->key->conf; return 0; } @@ -246,28 +256,16 @@ ieee80211_tx_result ieee80211_crypto_tkip_encrypt(struct ieee80211_tx_data *tx) { struct sk_buff *skb = tx->skb; - int wpa_test = 0, test = 0; - tx->control->icv_len = TKIP_ICV_LEN; - tx->control->iv_len = TKIP_IV_LEN; ieee80211_tx_set_protected(tx); - if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && - !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) && - !wpa_test) { - /* hwaccel - with no need for preallocated room for IV/ICV */ - tx->control->hw_key = &tx->key->conf; - return TX_CONTINUE; - } - - if (tkip_encrypt_skb(tx, skb, test) < 0) + if (tkip_encrypt_skb(tx, skb) < 0) return TX_DROP; if (tx->extra_frag) { int i; for (i = 0; i < tx->num_extra_frag; i++) { - if (tkip_encrypt_skb(tx, tx->extra_frag[i], test) - < 0) + if (tkip_encrypt_skb(tx, tx->extra_frag[i]) < 0) return TX_DROP; } } @@ -429,16 +427,27 @@ static inline int ccmp_hdr2pn(u8 *pn, u8 *hdr) } -static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, - struct sk_buff *skb, int test) +static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_key *key = tx->key; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int hdrlen, len, tailneed; u16 fc; u8 *pos, *pn, *b_0, *aad, *scratch; int i; + info->control.icv_len = CCMP_MIC_LEN; + info->control.iv_len = CCMP_HDR_LEN; + + if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && + !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { + /* hwaccel - with no need for preallocated room for CCMP " + * header or MIC fields */ + info->control.hw_key = &tx->key->conf; + return TX_CONTINUE; + } + scratch = key->u.ccmp.tx_crypto_buf; b_0 = scratch + 3 * AES_BLOCK_LEN; aad = scratch + 4 * AES_BLOCK_LEN; @@ -478,7 +487,7 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { /* hwaccel - with preallocated room for CCMP header */ - tx->control->hw_key = &tx->key->conf; + info->control.hw_key = &tx->key->conf; return 0; } @@ -495,28 +504,16 @@ ieee80211_tx_result ieee80211_crypto_ccmp_encrypt(struct ieee80211_tx_data *tx) { struct sk_buff *skb = tx->skb; - int test = 0; - tx->control->icv_len = CCMP_MIC_LEN; - tx->control->iv_len = CCMP_HDR_LEN; ieee80211_tx_set_protected(tx); - if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && - !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { - /* hwaccel - with no need for preallocated room for CCMP " - * header or MIC fields */ - tx->control->hw_key = &tx->key->conf; - return TX_CONTINUE; - } - - if (ccmp_encrypt_skb(tx, skb, test) < 0) + if (ccmp_encrypt_skb(tx, skb) < 0) return TX_DROP; if (tx->extra_frag) { int i; for (i = 0; i < tx->num_extra_frag; i++) { - if (ccmp_encrypt_skb(tx, tx->extra_frag[i], test) - < 0) + if (ccmp_encrypt_skb(tx, tx->extra_frag[i]) < 0) return TX_DROP; } } -- cgit v0.10.2 From a8c4ea7a10f3c45eee27efb3954c3e03c297f0a7 Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Fri, 16 May 2008 17:27:05 +0900 Subject: zd1211rw: Use DMA-aware buffer for usb transfer The zd1211rw driver uses unaligned stack buffer for USB control message. But it might cause stack corruption on non-coherent platform, such as MIPS. Use DMA-aware buffers for USB transfer. Signed-off-by: Atsushi Nemoto Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index c8a0b34..6a51ae4 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -169,10 +169,11 @@ static int upload_code(struct usb_device *udev, if (flags & REBOOT) { u8 ret; + /* Use "DMA-aware" buffer. */ r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), USB_REQ_FIRMWARE_CONFIRM, USB_DIR_IN | USB_TYPE_VENDOR, - 0, 0, &ret, sizeof(ret), 5000 /* ms */); + 0, 0, p, sizeof(ret), 5000 /* ms */); if (r != sizeof(ret)) { dev_err(&udev->dev, "control request firmeware confirmation failed." @@ -181,6 +182,7 @@ static int upload_code(struct usb_device *udev, r = -ENODEV; goto error; } + ret = p[0]; if (ret & 0x80) { dev_err(&udev->dev, "Internal error while downloading." @@ -312,22 +314,31 @@ int zd_usb_read_fw(struct zd_usb *usb, zd_addr_t addr, u8 *data, u16 len) { int r; struct usb_device *udev = zd_usb_to_usbdev(usb); + u8 *buf; + /* Use "DMA-aware" buffer. */ + buf = kmalloc(len, GFP_KERNEL); + if (!buf) + return -ENOMEM; r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), USB_REQ_FIRMWARE_READ_DATA, USB_DIR_IN | 0x40, addr, 0, - data, len, 5000); + buf, len, 5000); if (r < 0) { dev_err(&udev->dev, "read over firmware interface failed: %d\n", r); - return r; + goto exit; } else if (r != len) { dev_err(&udev->dev, "incomplete read over firmware interface: %d/%d\n", r, len); - return -EIO; + r = -EIO; + goto exit; } - - return 0; + r = 0; + memcpy(data, buf, len); +exit: + kfree(buf); + return r; } #define urb_dev(urb) (&(urb)->dev->dev) -- cgit v0.10.2 From e93048825face354ecb0cb3ac00190c764a44f45 Mon Sep 17 00:00:00 2001 From: "Larry.Finger@lwfinger.net" Date: Thu, 15 May 2008 14:07:36 -0500 Subject: b43: Fix typo in firmware file name for 802.11 cores with rev 13 When the patch for the BCM4311 rev 2 was prepared, I misread the specs and coded the wrong file name for the initvals firmware. Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 3622d76..ff5dce6 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1958,7 +1958,7 @@ static int b43_request_firmware(struct b43_wldev *dev) if ((rev >= 5) && (rev <= 10)) filename = "b0g0initvals5"; else if (rev >= 13) - filename = "lp0initvals13"; + filename = "b0g0initvals13"; else goto err_no_initvals; break; -- cgit v0.10.2 From eefce91a384a64c7bbf913eb08c4adfb911c3639 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 17 May 2008 00:57:13 +0200 Subject: mac80211: dont allow fragmentation and requeuing on A-MPDU queues There really is no reason for a driver to reject a frame on an A-MPDU queue when it can stop that queue for any period of time and is given frames one by one. Hence, disallow it with a big warning and reduce mac80211-internal state. Also add a warning when we try to fragment a frame destined for an A-MPDU queue and drop it, the actual bug needs to be fixed elsewhere but I'm not exactly sure how to yet. Signed-off-by: Johannes Berg Cc: Ron Rindjunsky Signed-off-by: John W. Linville diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 54960b8..4df39eb 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -986,8 +986,10 @@ enum ieee80211_ampdu_mlme_action { * @tx: Handler that 802.11 module calls for each transmitted frame. * skb contains the buffer starting from the IEEE 802.11 header. * The low-level driver should send the frame out based on - * configuration in the TX control data. Must be implemented and - * atomic. + * configuration in the TX control data. This handler should, + * preferably, never fail and stop queues appropriately, more + * importantly, however, it must never fail for A-MPDU-queues. + * Must be implemented and atomic. * * @start: Called before the first netdevice attached to the hardware * is enabled. This should turn on the hardware and must turn on diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 79a65b3..86a8612 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -595,7 +595,7 @@ struct ieee80211_local { struct timer_list sta_cleanup; unsigned long state[IEEE80211_MAX_QUEUES + IEEE80211_MAX_AMPDU_QUEUES]; - struct ieee80211_tx_stored_packet pending_packet[IEEE80211_MAX_QUEUES + IEEE80211_MAX_AMPDU_QUEUES]; + struct ieee80211_tx_stored_packet pending_packet[IEEE80211_MAX_QUEUES]; struct tasklet_struct tx_pending_tasklet; /* number of interfaces with corresponding IFF_ flags */ diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index ac9a4af..6268bbc 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -673,6 +673,16 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) if (!(tx->flags & IEEE80211_TX_FRAGMENTED)) return TX_CONTINUE; + /* + * Warn when submitting a fragmented A-MPDU frame and drop it. + * This is an error and needs to be fixed elsewhere, but when + * done needs to take care of monitor interfaces (injection) + * etc. + */ + if (WARN_ON(tx->flags & IEEE80211_TX_CTL_AMPDU || + IEEE80211_SKB_CB(tx->skb)->queue >= tx->local->hw.queues)) + return TX_DROP; + first = tx->skb; hdrlen = ieee80211_get_hdrlen(tx->fc); @@ -1216,8 +1226,17 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb) retry: ret = __ieee80211_tx(local, skb, &tx); if (ret) { - struct ieee80211_tx_stored_packet *store = - &local->pending_packet[info->queue]; + struct ieee80211_tx_stored_packet *store; + + /* + * Since there are no fragmented frames on A-MPDU + * queues, there's no reason for a driver to reject + * a frame there, warn and drop it. + */ + if (WARN_ON(queue >= local->hw.queues)) + goto drop; + + store = &local->pending_packet[queue]; if (ret == IEEE80211_TX_FRAG_AGAIN) skb = NULL; -- cgit v0.10.2 From e2530083609148a7835b54c431f6b8956407c1f6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 17 May 2008 00:57:14 +0200 Subject: mac80211: use multi-queue master netdevice This patch updates mac80211 and drivers to be multi-queue aware and use that instead of the internal queue mapping. Also does a number of cleanups in various pieces of the code that fall out and reduces internal mac80211 state size. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 7d97934..18e9422 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -2657,7 +2657,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) if (list_empty(&sc->txbuf)) { ATH5K_ERR(sc, "no further txbuf available, dropping packet\n"); spin_unlock_irqrestore(&sc->txbuflock, flags); - ieee80211_stop_queue(hw, info->queue); + ieee80211_stop_queue(hw, skb_get_queue_mapping(skb)); return -1; } bf = list_first_entry(&sc->txbuf, struct ath5k_buf, list); diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index aced986..b4eadd9 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -1297,7 +1297,8 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); } else { /* Decide by priority where to put this frame. */ - ring = select_ring_by_priority(dev, info->queue); + ring = select_ring_by_priority( + dev, skb_get_queue_mapping(skb)); } spin_lock_irqsave(&ring->lock, flags); @@ -1315,7 +1316,7 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) /* Assign the queue number to the ring (if not already done before) * so TX status handling can use it. The queue to ring mapping is * static, so we don't need to store it per frame. */ - ring->queue_prio = info->queue; + ring->queue_prio = skb_get_queue_mapping(skb); err = dma_tx_fragment(ring, skb); if (unlikely(err == -ENOKEY)) { @@ -1333,7 +1334,7 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) if ((free_slots(ring) < SLOTS_PER_PACKET) || should_inject_overflow(ring)) { /* This TX ring is full. */ - ieee80211_stop_queue(dev->wl->hw, info->queue); + ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); ring->stopped = 1; if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index); diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index 284786a..8b1555d 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -509,7 +509,7 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); } else { /* Decide by priority where to put this frame. */ - q = select_queue_by_priority(dev, info->queue); + q = select_queue_by_priority(dev, skb_get_queue_mapping(skb)); } spin_lock_irqsave(&q->lock, flags); @@ -532,7 +532,7 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) if (total_len > (q->buffer_size - q->buffer_used)) { /* Not enough memory on the queue. */ err = -EBUSY; - ieee80211_stop_queue(dev->wl->hw, info->queue); + ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); q->stopped = 1; goto out_unlock; } @@ -540,7 +540,7 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) /* Assign the queue number to the ring (if not already done before) * so TX status handling can use it. The mac80211-queue to b43-queue * mapping is static, so we don't need to store it per frame. */ - q->queue_prio = info->queue; + q->queue_prio = skb_get_queue_mapping(skb); err = pio_tx_frame(q, skb); if (unlikely(err == -ENOKEY)) { @@ -560,7 +560,7 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) if (((q->buffer_size - q->buffer_used) < roundup(2 + 2 + 6, 4)) || (q->free_packet_slots == 0)) { /* The queue is full. */ - ieee80211_stop_queue(dev->wl->hw, info->queue); + ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); q->stopped = 1; } diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c index c1c501d..33cc256 100644 --- a/drivers/net/wireless/b43legacy/dma.c +++ b/drivers/net/wireless/b43legacy/dma.c @@ -1325,11 +1325,10 @@ int b43legacy_dma_tx(struct b43legacy_wldev *dev, struct sk_buff *skb) { struct b43legacy_dmaring *ring; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int err = 0; unsigned long flags; - ring = priority_to_txring(dev, info->queue); + ring = priority_to_txring(dev, skb_get_queue_mapping(skb)); spin_lock_irqsave(&ring->lock, flags); B43legacy_WARN_ON(!ring->tx); if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) { diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index a61293b..0ebab96 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -696,7 +696,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl_tfd_frame *tfd; u32 *control_flags; - int txq_id = info->queue; + int txq_id = skb_get_queue_mapping(skb); struct iwl_tx_queue *txq = NULL; struct iwl_queue *q = NULL; dma_addr_t phys_addr; @@ -917,7 +917,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) spin_unlock_irqrestore(&priv->lock, flags); } - ieee80211_stop_queue(priv->hw, info->queue); + ieee80211_stop_queue(priv->hw, skb_get_queue_mapping(skb)); } return 0; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index a740a18..e0f52e2 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -2552,7 +2552,7 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, struct sk_buff *skb) struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl3945_tfd_frame *tfd; u32 *control_flags; - int txq_id = info->queue; + int txq_id = skb_get_queue_mapping(skb); struct iwl3945_tx_queue *txq = NULL; struct iwl3945_queue *q = NULL; dma_addr_t phys_addr; @@ -2765,7 +2765,7 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, struct sk_buff *skb) spin_unlock_irqrestore(&priv->lock, flags); } - ieee80211_stop_queue(priv->hw, info->queue); + ieee80211_stop_queue(priv->hw, skb_get_queue_mapping(skb)); } return 0; diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 8508579..91ac920 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -407,7 +407,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) last_addr = range->end_addr; __skb_unlink(entry, &priv->tx_queue); memset(&info->status, 0, sizeof(info->status)); - priv->tx_stats[info->queue].len--; + priv->tx_stats[skb_get_queue_mapping(skb)].len--; entry_hdr = (struct p54_control_hdr *) entry->data; entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data; if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0) @@ -551,13 +551,13 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) size_t padding, len; u8 rate; - current_queue = &priv->tx_stats[info->queue]; + current_queue = &priv->tx_stats[skb_get_queue_mapping(skb)]; if (unlikely(current_queue->len > current_queue->limit)) return NETDEV_TX_BUSY; current_queue->len++; current_queue->count++; if (current_queue->len == current_queue->limit) - ieee80211_stop_queue(dev, info->queue); + ieee80211_stop_queue(dev, skb_get_queue_mapping(skb)); padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3; len = skb->len; @@ -589,7 +589,7 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) memset(txhdr->rateset, rate, 8); txhdr->wep_key_present = 0; txhdr->wep_key_len = 0; - txhdr->frame_type = cpu_to_le32(info->queue + 4); + txhdr->frame_type = cpu_to_le32(skb_get_queue_mapping(skb) + 4); txhdr->magic4 = 0; txhdr->antenna = (info->antenna_sel_tx == 0) ? 2 : info->antenna_sel_tx - 1; diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index b5379b0..c05e05b 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -102,7 +102,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) struct rt2x00_dev *rt2x00dev = hw->priv; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data; - enum data_queue_qid qid = mac80211_queue_to_qid(tx_info->queue); + enum data_queue_qid qid = skb_get_queue_mapping(skb); struct data_queue *queue; u16 frame_control; @@ -149,23 +149,23 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) IEEE80211_TX_CTL_USE_CTS_PROTECT)) && !rt2x00dev->ops->hw->set_rts_threshold) { if (rt2x00queue_available(queue) <= 1) { - ieee80211_stop_queue(rt2x00dev->hw, tx_info->queue); + ieee80211_stop_queue(rt2x00dev->hw, qid); return NETDEV_TX_BUSY; } if (rt2x00mac_tx_rts_cts(rt2x00dev, queue, skb)) { - ieee80211_stop_queue(rt2x00dev->hw, tx_info->queue); + ieee80211_stop_queue(rt2x00dev->hw, qid); return NETDEV_TX_BUSY; } } if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, queue, skb)) { - ieee80211_stop_queue(rt2x00dev->hw, tx_info->queue); + ieee80211_stop_queue(rt2x00dev->hw, qid); return NETDEV_TX_BUSY; } if (rt2x00queue_full(queue)) - ieee80211_stop_queue(rt2x00dev->hw, tx_info->queue); + ieee80211_stop_queue(rt2x00dev->hw, qid); if (rt2x00dev->ops->lib->kick_tx_queue) rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, qid); diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index f263fe4..4d00ced 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -80,19 +80,6 @@ enum data_queue_qid { }; /** - * mac80211_queue_to_qid - Convert mac80211 queue to rt2x00 qid - * @queue: mac80211 queue. - */ -static inline enum data_queue_qid mac80211_queue_to_qid(unsigned int queue) -{ - /* Regular TX queues are mapped directly */ - if (queue < 4) - return queue; - WARN_ON(1); - return QID_OTHER; -} - -/** * enum skb_frame_desc_flags: Flags for &struct skb_frame_desc * * @FRAME_DESC_DRIVER_GENERATED: Frame was generated inside driver diff --git a/drivers/net/wireless/rtl8180_dev.c b/drivers/net/wireless/rtl8180_dev.c index 4427bc9..b7172a1 100644 --- a/drivers/net/wireless/rtl8180_dev.c +++ b/drivers/net/wireless/rtl8180_dev.c @@ -246,7 +246,7 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb) u16 plcp_len = 0; __le16 rts_duration = 0; - prio = info->queue; + prio = skb_get_queue_mapping(skb); ring = &priv->tx_ring[prio]; mapping = pci_map_single(priv->pdev, skb->data, @@ -298,7 +298,7 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb) entry->flags = cpu_to_le32(tx_flags); __skb_queue_tail(&ring->queue, skb); if (ring->entries - skb_queue_len(&ring->queue) < 2) - ieee80211_stop_queue(dev, info->queue); + ieee80211_stop_queue(dev, skb_get_queue_mapping(skb)); spin_unlock_irqrestore(&priv->lock, flags); rtl818x_iowrite8(priv, &priv->map->TX_DMA_POLLING, (1 << (prio + 4))); diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 4df39eb..c80e3be 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -293,7 +293,7 @@ struct ieee80211_tx_info { s8 tx_rate_idx; u8 antenna_sel_tx; - u8 queue; /* use skb_queue_mapping soon */ + /* 1 byte hole */ union { struct { @@ -802,6 +802,24 @@ static inline void SET_IEEE80211_PERM_ADDR(struct ieee80211_hw *hw, u8 *addr) memcpy(hw->wiphy->perm_addr, addr, ETH_ALEN); } +static inline int ieee80211_num_regular_queues(struct ieee80211_hw *hw) +{ +#ifdef CONFIG_MAC80211_QOS + return hw->queues; +#else + return 1; +#endif +} + +static inline int ieee80211_num_queues(struct ieee80211_hw *hw) +{ +#ifdef CONFIG_MAC80211_QOS + return hw->queues + hw->ampdu_queues; +#else + return 1; +#endif +} + static inline struct ieee80211_rate * ieee80211_get_tx_rate(const struct ieee80211_hw *hw, const struct ieee80211_tx_info *c) diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index a24b459..590e00b 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -7,11 +7,23 @@ config MAC80211 select CRC32 select WIRELESS_EXT select CFG80211 - select NET_SCH_FIFO ---help--- This option enables the hardware independent IEEE 802.11 networking stack. +config MAC80211_QOS + def_bool y + depends on MAC80211 + depends on NET_SCHED + depends on NETDEVICES_MULTIQUEUE + +comment "QoS/HT support disabled" + depends on MAC80211 && !MAC80211_QOS +comment "QoS/HT support needs CONFIG_NET_SCHED" + depends on MAC80211 && !NET_SCHED +comment "QoS/HT support needs CONFIG_NETDEVICES_MULTIQUEUE" + depends on MAC80211 && !NETDEVICES_MULTIQUEUE + menu "Rate control algorithm selection" depends on MAC80211 != n diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 4e5847f..1d2a4e0 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -29,7 +29,7 @@ mac80211-y := \ event.o mac80211-$(CONFIG_MAC80211_LEDS) += led.o -mac80211-$(CONFIG_NET_SCHED) += wme.o +mac80211-$(CONFIG_MAC80211_QOS) += wme.o mac80211-$(CONFIG_MAC80211_DEBUGFS) += \ debugfs.o \ debugfs_sta.o \ diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 86a8612..7d614cd 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -594,7 +594,7 @@ struct ieee80211_local { struct sta_info *sta_hash[STA_HASH_SIZE]; struct timer_list sta_cleanup; - unsigned long state[IEEE80211_MAX_QUEUES + IEEE80211_MAX_AMPDU_QUEUES]; + unsigned long queues_pending[BITS_TO_LONGS(IEEE80211_MAX_QUEUES)]; struct ieee80211_tx_stored_packet pending_packet[IEEE80211_MAX_QUEUES]; struct tasklet_struct tx_pending_tasklet; @@ -758,6 +758,15 @@ struct ieee80211_local { #endif }; +static inline int ieee80211_is_multiqueue(struct ieee80211_local *local) +{ +#ifdef CONFIG_MAC80211_QOS + return netif_is_multiqueue(local->mdev); +#else + return 0; +#endif +} + /* this struct represents 802.11n's RA/TID combination */ struct ieee80211_ra_tid { u8 ra[ETH_ALEN]; @@ -827,11 +836,6 @@ static inline struct ieee80211_hw *local_to_hw( return &local->hw; } -enum ieee80211_link_state_t { - IEEE80211_LINK_STATE_XOFF = 0, - IEEE80211_LINK_STATE_PENDING, -}; - struct sta_attribute { struct attribute attr; ssize_t (*show)(const struct sta_info *, char *buf); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 3c64e42..9844727 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -168,7 +168,7 @@ void ieee80211_if_set_type(struct net_device *dev, int type) ifsta->flags |= IEEE80211_STA_CREATE_IBSS | IEEE80211_STA_AUTO_BSSID_SEL | IEEE80211_STA_AUTO_CHANNEL_SEL; - if (sdata->local->hw.queues >= 4) + if (ieee80211_num_regular_queues(&sdata->local->hw) >= 4) ifsta->flags |= IEEE80211_STA_WMM_ENABLED; msdata = IEEE80211_DEV_TO_SUB_IF(sdata->local->mdev); diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 8f1ff7e..97d4a53 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -1634,12 +1634,32 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) if (result < 0) return result; + /* + * We use the number of queues for feature tests (QoS, HT) internally + * so restrict them appropriately. + */ +#ifdef CONFIG_MAC80211_QOS + if (hw->queues > IEEE80211_MAX_QUEUES) + hw->queues = IEEE80211_MAX_QUEUES; + if (hw->ampdu_queues > IEEE80211_MAX_AMPDU_QUEUES) + hw->ampdu_queues = IEEE80211_MAX_AMPDU_QUEUES; + if (hw->queues < 4) + hw->ampdu_queues = 0; +#else + hw->queues = 1; + hw->ampdu_queues = 0; +#endif + /* for now, mdev needs sub_if_data :/ */ - mdev = alloc_netdev(sizeof(struct ieee80211_sub_if_data), - "wmaster%d", ether_setup); + mdev = alloc_netdev_mq(sizeof(struct ieee80211_sub_if_data), + "wmaster%d", ether_setup, + ieee80211_num_queues(hw)); if (!mdev) goto fail_mdev_alloc; + if (ieee80211_num_queues(hw) > 1) + mdev->features |= NETIF_F_MULTI_QUEUE; + sdata = IEEE80211_DEV_TO_SUB_IF(mdev); mdev->ieee80211_ptr = &sdata->wdev; sdata->wdev.wiphy = local->hw.wiphy; @@ -1728,11 +1748,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) goto fail_wep; } - if (hw->queues > IEEE80211_MAX_QUEUES) - hw->queues = IEEE80211_MAX_QUEUES; - if (hw->ampdu_queues > IEEE80211_MAX_AMPDU_QUEUES) - hw->ampdu_queues = IEEE80211_MAX_AMPDU_QUEUES; - ieee80211_install_qdisc(local->mdev); /* add one default STA interface */ diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index ef31493..c24770c 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -255,7 +255,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, * sta_rx_agg_session_timer_expired for useage */ sta->timer_to_tid[i] = i; /* tid to tx queue: initialize according to HW (0 is valid) */ - sta->tid_to_tx_q[i] = local->hw.queues + local->hw.ampdu_queues; + sta->tid_to_tx_q[i] = ieee80211_num_queues(&local->hw); /* rx */ sta->ampdu_mlme.tid_state_rx[i] = HT_AGG_STATE_IDLE; sta->ampdu_mlme.tid_rx[i] = NULL; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 6268bbc..9273651 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -213,18 +213,6 @@ static u16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr, return dur; } -static inline int __ieee80211_queue_stopped(const struct ieee80211_local *local, - int queue) -{ - return test_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]); -} - -static inline int __ieee80211_queue_pending(const struct ieee80211_local *local, - int queue) -{ - return test_bit(IEEE80211_LINK_STATE_PENDING, &local->state[queue]); -} - static int inline is_ieee80211_device(struct net_device *dev, struct net_device *master) { @@ -680,7 +668,8 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) * etc. */ if (WARN_ON(tx->flags & IEEE80211_TX_CTL_AMPDU || - IEEE80211_SKB_CB(tx->skb)->queue >= tx->local->hw.queues)) + skb_get_queue_mapping(tx->skb) >= + ieee80211_num_regular_queues(&tx->local->hw))) return TX_DROP; first = tx->skb; @@ -1098,11 +1087,9 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int ret, i; - if (!ieee80211_qdisc_installed(local->mdev) && - __ieee80211_queue_stopped(local, 0)) { - netif_stop_queue(local->mdev); + if (netif_subqueue_stopped(local->mdev, skb)) return IEEE80211_TX_AGAIN; - } + if (skb) { ieee80211_dump_frame(wiphy_name(local->hw.wiphy), "TX to low-level driver", skb); @@ -1121,7 +1108,8 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, IEEE80211_TX_CTL_USE_CTS_PROTECT | IEEE80211_TX_CTL_CLEAR_PS_FILT | IEEE80211_TX_CTL_FIRST_FRAGMENT); - if (__ieee80211_queue_stopped(local, info->queue)) + if (netif_subqueue_stopped(local->mdev, + tx->extra_frag[i])) return IEEE80211_TX_FRAG_AGAIN; if (i == tx->num_extra_frag) { info->tx_rate_idx = tx->last_frag_rate_idx; @@ -1160,9 +1148,11 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb) ieee80211_tx_result res = TX_DROP, res_prepare; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int ret, i; - int queue = info->queue; + u16 queue; - WARN_ON(__ieee80211_queue_pending(local, queue)); + queue = skb_get_queue_mapping(skb); + + WARN_ON(test_bit(queue, local->queues_pending)); if (unlikely(skb->len < 10)) { dev_kfree_skb(skb); @@ -1233,28 +1223,28 @@ retry: * queues, there's no reason for a driver to reject * a frame there, warn and drop it. */ - if (WARN_ON(queue >= local->hw.queues)) + if (WARN_ON(queue >= ieee80211_num_regular_queues(&local->hw))) goto drop; store = &local->pending_packet[queue]; if (ret == IEEE80211_TX_FRAG_AGAIN) skb = NULL; - set_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[queue]); + set_bit(queue, local->queues_pending); smp_mb(); - /* When the driver gets out of buffers during sending of - * fragments and calls ieee80211_stop_queue, there is - * a small window between IEEE80211_LINK_STATE_XOFF and - * IEEE80211_LINK_STATE_PENDING flags are set. If a buffer + /* + * When the driver gets out of buffers during sending of + * fragments and calls ieee80211_stop_queue, the netif + * subqueue is stopped. There is, however, a small window + * in which the PENDING bit is not yet set. If a buffer * gets available in that window (i.e. driver calls * ieee80211_wake_queue), we would end up with ieee80211_tx - * called with IEEE80211_LINK_STATE_PENDING. Prevent this by + * called with the PENDING bit still set. Prevent this by * continuing transmitting here when that situation is - * possible to have happened. */ - if (!__ieee80211_queue_stopped(local, queue)) { - clear_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[queue]); + * possible to have happened. + */ + if (!__netif_subqueue_stopped(local->mdev, queue)) { + clear_bit(queue, local->queues_pending); goto retry; } store->skb = skb; @@ -1509,7 +1499,8 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, } /* receiver and we are QoS enabled, use a QoS type frame */ - if (sta_flags & WLAN_STA_WME && local->hw.queues >= 4) { + if (sta_flags & WLAN_STA_WME && + ieee80211_num_regular_queues(&local->hw) >= 4) { fc |= IEEE80211_STYPE_QOS_DATA; hdrlen += 2; } @@ -1661,41 +1652,51 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, return ret; } -/* helper functions for pending packets for when queues are stopped */ +/* + * ieee80211_clear_tx_pending may not be called in a context where + * it is possible that it packets could come in again. + */ void ieee80211_clear_tx_pending(struct ieee80211_local *local) { int i, j; struct ieee80211_tx_stored_packet *store; - for (i = 0; i < local->hw.queues; i++) { - if (!__ieee80211_queue_pending(local, i)) + for (i = 0; i < ieee80211_num_regular_queues(&local->hw); i++) { + if (!test_bit(i, local->queues_pending)) continue; store = &local->pending_packet[i]; kfree_skb(store->skb); for (j = 0; j < store->num_extra_frag; j++) kfree_skb(store->extra_frag[j]); kfree(store->extra_frag); - clear_bit(IEEE80211_LINK_STATE_PENDING, &local->state[i]); + clear_bit(i, local->queues_pending); } } +/* + * Transmit all pending packets. Called from tasklet, locks master device + * TX lock so that no new packets can come in. + */ void ieee80211_tx_pending(unsigned long data) { struct ieee80211_local *local = (struct ieee80211_local *)data; struct net_device *dev = local->mdev; struct ieee80211_tx_stored_packet *store; struct ieee80211_tx_data tx; - int i, ret, reschedule = 0; + int i, ret; netif_tx_lock_bh(dev); - for (i = 0; i < local->hw.queues; i++) { - if (__ieee80211_queue_stopped(local, i)) + for (i = 0; i < ieee80211_num_regular_queues(&local->hw); i++) { + /* Check that this queue is ok */ + if (__netif_subqueue_stopped(local->mdev, i)) continue; - if (!__ieee80211_queue_pending(local, i)) { - reschedule = 1; + + if (!test_bit(i, local->queues_pending)) { + ieee80211_wake_queue(&local->hw, i); continue; } + store = &local->pending_packet[i]; tx.extra_frag = store->extra_frag; tx.num_extra_frag = store->num_extra_frag; @@ -1708,19 +1709,11 @@ void ieee80211_tx_pending(unsigned long data) if (ret == IEEE80211_TX_FRAG_AGAIN) store->skb = NULL; } else { - clear_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[i]); - reschedule = 1; + clear_bit(i, local->queues_pending); + ieee80211_wake_queue(&local->hw, i); } } netif_tx_unlock_bh(dev); - if (reschedule) { - if (!ieee80211_qdisc_installed(dev)) { - if (!__ieee80211_queue_stopped(local, 0)) - netif_wake_queue(dev); - } else - netif_schedule(dev); - } } /* functions for drivers to get certain frames */ diff --git a/net/mac80211/util.c b/net/mac80211/util.c index d9109de..4f7180b 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -331,17 +331,15 @@ void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue) { struct ieee80211_local *local = hw_to_local(hw); - if (test_and_clear_bit(IEEE80211_LINK_STATE_XOFF, - &local->state[queue])) { - if (test_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[queue])) - tasklet_schedule(&local->tx_pending_tasklet); - else - if (!ieee80211_qdisc_installed(local->mdev)) { - if (queue == 0) - netif_wake_queue(local->mdev); - } else - __netif_schedule(local->mdev); + if (test_bit(queue, local->queues_pending)) { + tasklet_schedule(&local->tx_pending_tasklet); + } else { + if (ieee80211_is_multiqueue(local)) { + netif_wake_subqueue(local->mdev, queue); + } else { + WARN_ON(queue != 0); + netif_wake_queue(local->mdev); + } } } EXPORT_SYMBOL(ieee80211_wake_queue); @@ -350,9 +348,12 @@ void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue) { struct ieee80211_local *local = hw_to_local(hw); - if (!ieee80211_qdisc_installed(local->mdev) && queue == 0) + if (ieee80211_is_multiqueue(local)) { + netif_stop_subqueue(local->mdev, queue); + } else { + WARN_ON(queue != 0); netif_stop_queue(local->mdev); - set_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]); + } } EXPORT_SYMBOL(ieee80211_stop_queue); @@ -360,7 +361,7 @@ void ieee80211_stop_queues(struct ieee80211_hw *hw) { int i; - for (i = 0; i < hw->queues + hw->ampdu_queues; i++) + for (i = 0; i < ieee80211_num_queues(hw); i++) ieee80211_stop_queue(hw, i); } EXPORT_SYMBOL(ieee80211_stop_queues); diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 477690f..14a9ff1 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -158,7 +158,7 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) u8 tid; if (info->flags & IEEE80211_TX_CTL_REQUEUE) { - queue = info->queue; + queue = skb_get_queue_mapping(skb); rcu_read_lock(); sta = sta_info_get(local, hdr->addr1); tid = skb->priority & QOS_CONTROL_TAG1D_MASK; @@ -219,7 +219,7 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) err = NET_XMIT_DROP; } else { tid = skb->priority & QOS_CONTROL_TAG1D_MASK; - info->queue = (unsigned int) queue; + skb_set_queue_mapping(skb, queue); qdisc = q->queues[queue]; err = qdisc->enqueue(skb, qdisc); if (err == NET_XMIT_SUCCESS) { @@ -240,12 +240,11 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) static int wme_qdiscop_requeue(struct sk_buff *skb, struct Qdisc* qd) { struct ieee80211_sched_data *q = qdisc_priv(qd); - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct Qdisc *qdisc; int err; /* we recorded which queue to use earlier! */ - qdisc = q->queues[info->queue]; + qdisc = q->queues[skb_get_queue_mapping(skb)]; if ((err = qdisc->ops->requeue(skb, qdisc)) == 0) { qd->q.qlen++; @@ -269,11 +268,8 @@ static struct sk_buff *wme_qdiscop_dequeue(struct Qdisc* qd) /* check all the h/w queues in numeric/priority order */ for (queue = 0; queue < QD_NUM(hw); queue++) { /* see if there is room in this hardware queue */ - if ((test_bit(IEEE80211_LINK_STATE_XOFF, - &local->state[queue])) || - (test_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[queue])) || - (!test_bit(queue, q->qdisc_pool))) + if (__netif_subqueue_stopped(local->mdev, queue) || + !test_bit(queue, q->qdisc_pool)) continue; /* there is space - try and get a frame */ diff --git a/net/mac80211/wme.h b/net/mac80211/wme.h index fcc6b05..bbdb533 100644 --- a/net/mac80211/wme.h +++ b/net/mac80211/wme.h @@ -31,7 +31,7 @@ static inline int WLAN_FC_IS_QOS_DATA(u16 fc) return (fc & 0x8C) == 0x88; } -#ifdef CONFIG_NET_SCHED +#ifdef CONFIG_MAC80211_QOS void ieee80211_install_qdisc(struct net_device *dev); int ieee80211_qdisc_installed(struct net_device *dev); int ieee80211_ht_agg_queue_add(struct ieee80211_local *local, -- cgit v0.10.2 From e48b0eeb0ab508021b654a45f332b30cac2163b9 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sat, 17 May 2008 22:44:35 +0200 Subject: b43: Add hooks for firmware debugging This patch adds some hooks for firmware debugging. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index aa49383..0046859 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -422,6 +422,12 @@ enum { B43_IRQ_RFKILL | \ B43_IRQ_TX_OK) +/* Debug-IRQ reasons. */ +#define B43_DEBUGIRQ_PANIC 0 /* The firmware panic'ed */ +#define B43_DEBUGIRQ_DUMP_SHM 1 /* Dump shared SHM */ +#define B43_DEBUGIRQ_DUMP_REGS 2 /* Dump the microcode registers */ +#define B43_DEBUGIRQ_ACK 0xFFFF /* The host writes that to ACK the IRQ */ + /* Device specific rate values. * The actual values defined here are (rate_in_mbps * 2). * Some code depends on this. Don't change it. */ @@ -765,6 +771,9 @@ struct b43_firmware { u16 rev; /* Firmware patchlevel */ u16 patch; + + /* Set to true, if we are using an opensource firmware. */ + bool opensource; }; /* Device (802.11 core) initialization status. */ diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index ff5dce6..656a1f0 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1664,7 +1664,64 @@ static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int) static void handle_irq_ucode_debug(struct b43_wldev *dev) { - //TODO + unsigned int i, cnt; + u16 reason; + __le16 *buf; + + /* The proprietary firmware doesn't have this IRQ. */ + if (!dev->fw.opensource) + return; + + /* Microcode register 63 contains the debug-IRQ reason. */ + reason = b43_shm_read16(dev, B43_SHM_SCRATCH, 63); + switch (reason) { + case B43_DEBUGIRQ_PANIC: + /* The reason for the panic is in register 3. */ + reason = b43_shm_read16(dev, B43_SHM_SCRATCH, 3); + b43err(dev->wl, "Whoopsy, the microcode panic'ed! Reason: %u\n", + reason); + b43_controller_restart(dev, "Microcode panic"); + break; + case B43_DEBUGIRQ_DUMP_SHM: + if (!B43_DEBUG) + break; /* Only with driver debugging enabled. */ + buf = kmalloc(4096, GFP_ATOMIC); + if (!buf) { + b43dbg(dev->wl, "SHM-dump: Failed to allocate memory\n"); + goto out; + } + for (i = 0; i < 4096; i += 2) { + u16 tmp = b43_shm_read16(dev, B43_SHM_SHARED, i); + buf[i / 2] = cpu_to_le16(tmp); + } + b43info(dev->wl, "Shared memory dump:\n"); + print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, + 16, 2, buf, 4096, 1); + kfree(buf); + break; + case B43_DEBUGIRQ_DUMP_REGS: + if (!B43_DEBUG) + break; /* Only with driver debugging enabled. */ + b43info(dev->wl, "Microcode register dump:\n"); + for (i = 0, cnt = 0; i < 64; i++) { + u16 tmp = b43_shm_read16(dev, B43_SHM_SCRATCH, i); + if (cnt == 0) + printk(KERN_INFO); + printk("r%02u: 0x%04X ", i, tmp); + cnt++; + if (cnt == 6) { + printk("\n"); + cnt = 0; + } + } + printk("\n"); + break; + default: + b43dbg(dev->wl, "Debug-IRQ triggered for unknown reason: %u\n", + reason); + } +out: + b43_shm_write16(dev, B43_SHM_SCRATCH, 63, B43_DEBUGIRQ_ACK); } /* Interrupt handler bottom-half */ @@ -2122,14 +2179,22 @@ static int b43_upload_microcode(struct b43_wldev *dev) err = -EOPNOTSUPP; goto error; } - b43info(dev->wl, "Loading firmware version %u.%u " - "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", - fwrev, fwpatch, - (fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF, - (fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, fwtime & 0x1F); - dev->fw.rev = fwrev; dev->fw.patch = fwpatch; + dev->fw.opensource = (fwdate == 0xFFFF); + + if (dev->fw.opensource) { + /* Patchlevel info is encoded in the "time" field. */ + dev->fw.patch = fwtime; + b43info(dev->wl, "Loading OpenSource firmware version %u.%u\n", + dev->fw.rev, dev->fw.patch); + } else { + b43info(dev->wl, "Loading firmware version %u.%u " + "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", + fwrev, fwpatch, + (fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF, + (fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, fwtime & 0x1F); + } if (b43_is_old_txhdr_format(dev)) { b43warn(dev->wl, "You are using an old firmware image. " -- cgit v0.10.2 From 6821783271aaf541504ff8a138184fcc83fa282b Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sat, 17 May 2008 23:43:57 +0200 Subject: b43: Allow running without PCM firmware This patch adds code to allow running the device without PCM firmware loaded. Without PCM firmware we don't have hardware accelerated crypto on devices with a core rev <= 10. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 0046859..f588dfa 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -774,6 +774,10 @@ struct b43_firmware { /* Set to true, if we are using an opensource firmware. */ bool opensource; + /* Set to true, if the core needs a PCM firmware, but + * we failed to load one. This is always false for + * core rev > 10, as these don't need PCM firmware. */ + bool pcm_request_failed; }; /* Device (802.11 core) initialization status. */ diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 656a1f0..6011747 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1908,7 +1908,8 @@ static void b43_print_fw_helptext(struct b43_wl *wl, bool error) static int do_request_fw(struct b43_wldev *dev, const char *name, - struct b43_firmware_file *fw) + struct b43_firmware_file *fw, + bool silent) { char path[sizeof(modparam_fwpostfix) + 32]; const struct firmware *blob; @@ -1932,9 +1933,15 @@ static int do_request_fw(struct b43_wldev *dev, "b43%s/%s.fw", modparam_fwpostfix, name); err = request_firmware(&blob, path, dev->dev->dev); - if (err) { - b43err(dev->wl, "Firmware file \"%s\" not found " - "or load failed.\n", path); + if (err == -ENOENT) { + if (!silent) { + b43err(dev->wl, "Firmware file \"%s\" not found\n", + path); + } + return err; + } else if (err) { + b43err(dev->wl, "Firmware file \"%s\" request failed (err=%d)\n", + path, err); return err; } if (blob->size < sizeof(struct b43_fw_header)) @@ -1985,7 +1992,7 @@ static int b43_request_firmware(struct b43_wldev *dev) filename = "ucode13"; else goto err_no_ucode; - err = do_request_fw(dev, filename, &fw->ucode); + err = do_request_fw(dev, filename, &fw->ucode, 0); if (err) goto err_load; @@ -1996,8 +2003,13 @@ static int b43_request_firmware(struct b43_wldev *dev) filename = NULL; else goto err_no_pcm; - err = do_request_fw(dev, filename, &fw->pcm); - if (err) + fw->pcm_request_failed = 0; + err = do_request_fw(dev, filename, &fw->pcm, 1); + if (err == -ENOENT) { + /* We did not find a PCM file? Not fatal, but + * core rev <= 10 must do without hwcrypto then. */ + fw->pcm_request_failed = 1; + } else if (err) goto err_load; /* Get initvals */ @@ -2028,7 +2040,7 @@ static int b43_request_firmware(struct b43_wldev *dev) default: goto err_no_initvals; } - err = do_request_fw(dev, filename, &fw->initvals); + err = do_request_fw(dev, filename, &fw->initvals, 0); if (err) goto err_load; @@ -2062,7 +2074,7 @@ static int b43_request_firmware(struct b43_wldev *dev) default: goto err_no_initvals; } - err = do_request_fw(dev, filename, &fw->initvals_band); + err = do_request_fw(dev, filename, &fw->initvals_band, 0); if (err) goto err_load; @@ -2186,14 +2198,20 @@ static int b43_upload_microcode(struct b43_wldev *dev) if (dev->fw.opensource) { /* Patchlevel info is encoded in the "time" field. */ dev->fw.patch = fwtime; - b43info(dev->wl, "Loading OpenSource firmware version %u.%u\n", - dev->fw.rev, dev->fw.patch); + b43info(dev->wl, "Loading OpenSource firmware version %u.%u%s\n", + dev->fw.rev, dev->fw.patch, + dev->fw.pcm_request_failed ? " (Hardware crypto not supported)" : ""); } else { b43info(dev->wl, "Loading firmware version %u.%u " "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", fwrev, fwpatch, (fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF, (fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, fwtime & 0x1F); + if (dev->fw.pcm_request_failed) { + b43warn(dev->wl, "No \"pcm5.fw\" firmware file found. " + "Hardware accelerated cryptography is disabled.\n"); + b43_print_fw_helptext(dev->wl, 0); + } } if (b43_is_old_txhdr_format(dev)) { @@ -3358,6 +3376,13 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, if (!dev || b43_status(dev) < B43_STAT_INITIALIZED) goto out_unlock; + if (dev->fw.pcm_request_failed) { + /* We don't have firmware for the crypto engine. + * Must use software-crypto. */ + err = -EOPNOTSUPP; + goto out_unlock; + } + err = -EINVAL; switch (key->alg) { case ALG_WEP: -- cgit v0.10.2 From afa83e239af58a93eddd10a7a43ac5618884db15 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Mon, 19 May 2008 23:51:37 +0200 Subject: b43: Add panic reason code that doesn't trigger restart Add a firmware panic reason code that doesn't trigger a restart. This is useful for firmware debugging and avoiding endless restart loops. We can use FWPANIC_DIE to halt the firmware at a well defined point. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index f588dfa..f004175 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -422,12 +422,21 @@ enum { B43_IRQ_RFKILL | \ B43_IRQ_TX_OK) +/* The firmware register to fetch the debug-IRQ reason from. */ +#define B43_DEBUGIRQ_REASON_REG 63 /* Debug-IRQ reasons. */ #define B43_DEBUGIRQ_PANIC 0 /* The firmware panic'ed */ #define B43_DEBUGIRQ_DUMP_SHM 1 /* Dump shared SHM */ #define B43_DEBUGIRQ_DUMP_REGS 2 /* Dump the microcode registers */ #define B43_DEBUGIRQ_ACK 0xFFFF /* The host writes that to ACK the IRQ */ +/* The firmware register to fetch the panic reason from. */ +#define B43_FWPANIC_REASON_REG 3 +/* Firmware panic reason codes */ +#define B43_FWPANIC_DIE 0 /* Firmware died. Don't auto-restart it. */ +#define B43_FWPANIC_RESTART 1 /* Firmware died. Schedule a controller reset. */ + + /* Device specific rate values. * The actual values defined here are (rate_in_mbps * 2). * Some code depends on this. Don't change it. */ diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 6011747..e1dfb40 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1662,6 +1662,30 @@ static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int) b43dbg(dev->wl, "Set beacon interval to %u\n", beacon_int); } +static void b43_handle_firmware_panic(struct b43_wldev *dev) +{ + u16 reason; + + /* Read the register that contains the reason code for the panic. */ + reason = b43_shm_read16(dev, B43_SHM_SCRATCH, B43_FWPANIC_REASON_REG); + b43err(dev->wl, "Whoopsy, firmware panic! Reason: %u\n", reason); + + switch (reason) { + default: + b43dbg(dev->wl, "The panic reason is unknown.\n"); + /* fallthrough */ + case B43_FWPANIC_DIE: + /* Do not restart the controller or firmware. + * The device is nonfunctional from now on. + * Restarting would result in this panic to trigger again, + * so we avoid that recursion. */ + break; + case B43_FWPANIC_RESTART: + b43_controller_restart(dev, "Microcode panic"); + break; + } +} + static void handle_irq_ucode_debug(struct b43_wldev *dev) { unsigned int i, cnt; @@ -1672,15 +1696,12 @@ static void handle_irq_ucode_debug(struct b43_wldev *dev) if (!dev->fw.opensource) return; - /* Microcode register 63 contains the debug-IRQ reason. */ - reason = b43_shm_read16(dev, B43_SHM_SCRATCH, 63); + /* Read the register that contains the reason code for this IRQ. */ + reason = b43_shm_read16(dev, B43_SHM_SCRATCH, B43_DEBUGIRQ_REASON_REG); + switch (reason) { case B43_DEBUGIRQ_PANIC: - /* The reason for the panic is in register 3. */ - reason = b43_shm_read16(dev, B43_SHM_SCRATCH, 3); - b43err(dev->wl, "Whoopsy, the microcode panic'ed! Reason: %u\n", - reason); - b43_controller_restart(dev, "Microcode panic"); + b43_handle_firmware_panic(dev); break; case B43_DEBUGIRQ_DUMP_SHM: if (!B43_DEBUG) @@ -1721,7 +1742,9 @@ static void handle_irq_ucode_debug(struct b43_wldev *dev) reason); } out: - b43_shm_write16(dev, B43_SHM_SCRATCH, 63, B43_DEBUGIRQ_ACK); + /* Acknowledge the debug-IRQ, so the firmware can continue. */ + b43_shm_write16(dev, B43_SHM_SCRATCH, + B43_DEBUGIRQ_REASON_REG, B43_DEBUGIRQ_ACK); } /* Interrupt handler bottom-half */ -- cgit v0.10.2 From 53c068566dde708cb28a4dfc06ae3d7fd7434397 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Tue, 20 May 2008 00:24:36 +0200 Subject: b43: Add firmware markers support This adds support for firmware markers. With firmware markers it's easily possible to check whether the firmware runs some codepath or not. The driver will throw a message when the firmware executes a MARKER(x). Signed-off-by: Michael Buesch Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index f004175..e919189 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -428,8 +428,13 @@ enum { #define B43_DEBUGIRQ_PANIC 0 /* The firmware panic'ed */ #define B43_DEBUGIRQ_DUMP_SHM 1 /* Dump shared SHM */ #define B43_DEBUGIRQ_DUMP_REGS 2 /* Dump the microcode registers */ +#define B43_DEBUGIRQ_MARKER 3 /* A "marker" was thrown by the firmware. */ #define B43_DEBUGIRQ_ACK 0xFFFF /* The host writes that to ACK the IRQ */ +/* The firmware register that contains the "marker" line. */ +#define B43_MARKER_ID_REG 2 +#define B43_MARKER_LINE_REG 3 + /* The firmware register to fetch the panic reason from. */ #define B43_FWPANIC_REASON_REG 3 /* Firmware panic reason codes */ diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index e1dfb40..cbb317b 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1689,7 +1689,7 @@ static void b43_handle_firmware_panic(struct b43_wldev *dev) static void handle_irq_ucode_debug(struct b43_wldev *dev) { unsigned int i, cnt; - u16 reason; + u16 reason, marker_id, marker_line; __le16 *buf; /* The proprietary firmware doesn't have this IRQ. */ @@ -1737,6 +1737,17 @@ static void handle_irq_ucode_debug(struct b43_wldev *dev) } printk("\n"); break; + case B43_DEBUGIRQ_MARKER: + if (!B43_DEBUG) + break; /* Only with driver debugging enabled. */ + marker_id = b43_shm_read16(dev, B43_SHM_SCRATCH, + B43_MARKER_ID_REG); + marker_line = b43_shm_read16(dev, B43_SHM_SCRATCH, + B43_MARKER_LINE_REG); + b43info(dev->wl, "The firmware just executed the MARKER(%u) " + "at line number %u\n", + marker_id, marker_line); + break; default: b43dbg(dev->wl, "Debug-IRQ triggered for unknown reason: %u\n", reason); -- cgit v0.10.2 From 9e72ebd686a7f39facdfff639386055f1ad7dc88 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 21 May 2008 17:33:42 +0200 Subject: mac80211: remove channel use statistics The useless channel use statistics are quite a lot of code, currently use integer divisions in the packet fast path, are rather inaccurate since they do not account for retries and finally nobody even cares. Hence, remove them completely. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 3ae5493..b2089b2 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -155,7 +155,6 @@ static const struct file_operations name##_ops = { \ __IEEE80211_IF_WFILE(name) /* common attributes */ -IEEE80211_IF_FILE(channel_use, channel_use, DEC); IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC); /* STA/IBSS attributes */ @@ -248,7 +247,6 @@ IEEE80211_IF_WFILE(min_discovery_timeout, static void add_sta_files(struct ieee80211_sub_if_data *sdata) { - DEBUGFS_ADD(channel_use, sta); DEBUGFS_ADD(drop_unencrypted, sta); DEBUGFS_ADD(state, sta); DEBUGFS_ADD(bssid, sta); @@ -269,7 +267,6 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata) static void add_ap_files(struct ieee80211_sub_if_data *sdata) { - DEBUGFS_ADD(channel_use, ap); DEBUGFS_ADD(drop_unencrypted, ap); DEBUGFS_ADD(num_sta_ps, ap); DEBUGFS_ADD(dtim_count, ap); @@ -281,14 +278,12 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata) static void add_wds_files(struct ieee80211_sub_if_data *sdata) { - DEBUGFS_ADD(channel_use, wds); DEBUGFS_ADD(drop_unencrypted, wds); DEBUGFS_ADD(peer, wds); } static void add_vlan_files(struct ieee80211_sub_if_data *sdata) { - DEBUGFS_ADD(channel_use, vlan); DEBUGFS_ADD(drop_unencrypted, vlan); } @@ -376,7 +371,6 @@ static void add_files(struct ieee80211_sub_if_data *sdata) static void del_sta_files(struct ieee80211_sub_if_data *sdata) { - DEBUGFS_DEL(channel_use, sta); DEBUGFS_DEL(drop_unencrypted, sta); DEBUGFS_DEL(state, sta); DEBUGFS_DEL(bssid, sta); @@ -397,7 +391,6 @@ static void del_sta_files(struct ieee80211_sub_if_data *sdata) static void del_ap_files(struct ieee80211_sub_if_data *sdata) { - DEBUGFS_DEL(channel_use, ap); DEBUGFS_DEL(drop_unencrypted, ap); DEBUGFS_DEL(num_sta_ps, ap); DEBUGFS_DEL(dtim_count, ap); @@ -409,14 +402,12 @@ static void del_ap_files(struct ieee80211_sub_if_data *sdata) static void del_wds_files(struct ieee80211_sub_if_data *sdata) { - DEBUGFS_DEL(channel_use, wds); DEBUGFS_DEL(drop_unencrypted, wds); DEBUGFS_DEL(peer, wds); } static void del_vlan_files(struct ieee80211_sub_if_data *sdata) { - DEBUGFS_DEL(channel_use, vlan); DEBUGFS_DEL(drop_unencrypted, vlan); } diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index a2cc028..79a0627 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -66,7 +66,6 @@ STA_FILE(tx_retry_count, tx_retry_count, LU); STA_FILE(last_signal, last_signal, D); STA_FILE(last_qual, last_qual, D); STA_FILE(last_noise, last_noise, D); -STA_FILE(channel_use, channel_use, D); STA_FILE(wep_weak_iv_count, wep_weak_iv_count, LU); static ssize_t sta_flags_read(struct file *file, char __user *userbuf, diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 7d614cd..3f8601c 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -201,7 +201,6 @@ struct ieee80211_rx_data { unsigned int flags; int sent_ps_buffered; int queue; - int load; u32 tkip_iv32; u16 tkip_iv16; }; @@ -448,14 +447,11 @@ struct ieee80211_sub_if_data { struct ieee80211_if_sta sta; u32 mntr_flags; } u; - int channel_use; - int channel_use_raw; #ifdef CONFIG_MAC80211_DEBUGFS struct dentry *debugfsdir; union { struct { - struct dentry *channel_use; struct dentry *drop_unencrypted; struct dentry *state; struct dentry *bssid; @@ -474,7 +470,6 @@ struct ieee80211_sub_if_data { struct dentry *num_beacons_sta; } sta; struct { - struct dentry *channel_use; struct dentry *drop_unencrypted; struct dentry *num_sta_ps; struct dentry *dtim_count; @@ -484,12 +479,10 @@ struct ieee80211_sub_if_data { struct dentry *num_buffered_multicast; } ap; struct { - struct dentry *channel_use; struct dentry *drop_unencrypted; struct dentry *peer; } wds; struct { - struct dentry *channel_use; struct dentry *drop_unencrypted; } vlan; struct { @@ -661,9 +654,6 @@ struct ieee80211_local { assoc_led_name[32], radio_led_name[32]; #endif - u32 channel_use; - u32 channel_use_raw; - #ifdef CONFIG_MAC80211_DEBUGFS struct work_struct sta_debugfs_add; #endif @@ -861,28 +851,6 @@ u32 ieee80211_handle_ht(struct ieee80211_local *local, int enable_ht, /* ieee80211_ioctl.c */ extern const struct iw_handler_def ieee80211_iw_handler_def; - - -/* Least common multiple of the used rates (in 100 kbps). This is used to - * calculate rate_inv values for each rate so that only integers are needed. */ -#define CHAN_UTIL_RATE_LCM 95040 -/* 1 usec is 1/8 * (95040/10) = 1188 */ -#define CHAN_UTIL_PER_USEC 1188 -/* Amount of bits to shift the result right to scale the total utilization - * to values that will not wrap around 32-bit integers. */ -#define CHAN_UTIL_SHIFT 9 -/* Theoretical maximum of channel utilization counter in 10 ms (stat_time=1): - * (CHAN_UTIL_PER_USEC * 10000) >> CHAN_UTIL_SHIFT = 23203. So dividing the - * raw value with about 23 should give utilization in 10th of a percentage - * (1/1000). However, utilization is only estimated and not all intervals - * between frames etc. are calculated. 18 seems to give numbers that are closer - * to the real maximum. */ -#define CHAN_UTIL_PER_10MS 18 -#define CHAN_UTIL_HDR_LONG (202 * CHAN_UTIL_PER_USEC) -#define CHAN_UTIL_HDR_SHORT (40 * CHAN_UTIL_PER_USEC) - - -/* ieee80211_ioctl.c */ int ieee80211_set_freq(struct ieee80211_local *local, int freq); /* ieee80211_sta.c */ void ieee80211_sta_timer(unsigned long data); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index cf0de3b..9400a97 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -387,51 +387,9 @@ static void ieee80211_verify_ip_alignment(struct ieee80211_rx_data *rx) } -static u32 ieee80211_rx_load_stats(struct ieee80211_local *local, - struct sk_buff *skb, - struct ieee80211_rx_status *status, - struct ieee80211_rate *rate) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - u32 load = 0, hdrtime; - - /* Estimate total channel use caused by this frame */ - - /* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values, - * 1 usec = 1/8 * (1080 / 10) = 13.5 */ - - if (status->band == IEEE80211_BAND_5GHZ || - (status->band == IEEE80211_BAND_5GHZ && - rate->flags & IEEE80211_RATE_ERP_G)) - hdrtime = CHAN_UTIL_HDR_SHORT; - else - hdrtime = CHAN_UTIL_HDR_LONG; - - load = hdrtime; - if (!is_multicast_ether_addr(hdr->addr1)) - load += hdrtime; - - /* TODO: optimise again */ - load += skb->len * CHAN_UTIL_RATE_LCM / rate->bitrate; - - /* Divide channel_use by 8 to avoid wrapping around the counter */ - load >>= CHAN_UTIL_SHIFT; - - return load; -} - /* rx handlers */ static ieee80211_rx_result -ieee80211_rx_h_if_stats(struct ieee80211_rx_data *rx) -{ - if (rx->sta) - rx->sta->channel_use_raw += rx->load; - rx->sdata->channel_use_raw += rx->load; - return RX_CONTINUE; -} - -static ieee80211_rx_result ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx) { struct ieee80211_local *local = rx->local; @@ -1780,7 +1738,6 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx) typedef ieee80211_rx_result (*ieee80211_rx_handler)(struct ieee80211_rx_data *); static ieee80211_rx_handler ieee80211_rx_handlers[] = { - ieee80211_rx_h_if_stats, ieee80211_rx_h_passive_scan, ieee80211_rx_h_check, ieee80211_rx_h_decrypt, @@ -1939,7 +1896,6 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_rx_status *status, - u32 load, struct ieee80211_rate *rate) { struct ieee80211_local *local = hw_to_local(hw); @@ -1958,7 +1914,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, rx.local = local; rx.status = status; - rx.load = load; rx.rate = rate; rx.fc = le16_to_cpu(hdr->frame_control); type = rx.fc & IEEE80211_FCTL_FTYPE; @@ -2067,7 +2022,6 @@ u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, struct ieee80211_rx_status status; u16 head_seq_num, buf_size; int index; - u32 pkt_load; struct ieee80211_supported_band *sband; struct ieee80211_rate *rate; @@ -2102,12 +2056,9 @@ u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, sizeof(status)); sband = local->hw.wiphy->bands[status.band]; rate = &sband->bitrates[status.rate_idx]; - pkt_load = ieee80211_rx_load_stats(local, - tid_agg_rx->reorder_buf[index], - &status, rate); __ieee80211_rx_handle_packet(hw, tid_agg_rx->reorder_buf[index], - &status, pkt_load, rate); + &status, rate); tid_agg_rx->stored_mpdu_num--; tid_agg_rx->reorder_buf[index] = NULL; } @@ -2149,11 +2100,8 @@ u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, sizeof(status)); sband = local->hw.wiphy->bands[status.band]; rate = &sband->bitrates[status.rate_idx]; - pkt_load = ieee80211_rx_load_stats(local, - tid_agg_rx->reorder_buf[index], - &status, rate); __ieee80211_rx_handle_packet(hw, tid_agg_rx->reorder_buf[index], - &status, pkt_load, rate); + &status, rate); tid_agg_rx->stored_mpdu_num--; tid_agg_rx->reorder_buf[index] = NULL; tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num); @@ -2232,7 +2180,6 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_rx_status *status) { struct ieee80211_local *local = hw_to_local(hw); - u32 pkt_load; struct ieee80211_rate *rate = NULL; struct ieee80211_supported_band *sband; @@ -2272,11 +2219,8 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, return; } - pkt_load = ieee80211_rx_load_stats(local, skb, status, rate); - local->channel_use_raw += pkt_load; - if (!ieee80211_rx_reorder_ampdu(local, skb)) - __ieee80211_rx_handle_packet(hw, skb, status, pkt_load, rate); + __ieee80211_rx_handle_packet(hw, skb, status, rate); rcu_read_unlock(); } diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index f592290..95753f8 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -245,10 +245,6 @@ struct sta_info { unsigned int wme_tx_queue[NUM_RX_DATA_QUEUES]; #endif - /* Debug counters, no locking doesn't matter */ - int channel_use; - int channel_use_raw; - /* * Aggregation information, locked with lock. */ diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 9273651..baa1be0 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -761,73 +761,18 @@ ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx) static ieee80211_tx_result ieee80211_tx_h_stats(struct ieee80211_tx_data *tx) { - struct ieee80211_local *local = tx->local; - struct sk_buff *skb = tx->skb; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - u32 load = 0, hdrtime; - struct ieee80211_rate *rate; - struct ieee80211_supported_band *sband; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - - sband = tx->local->hw.wiphy->bands[tx->channel->band]; - rate = &sband->bitrates[tx->rate_idx]; - - /* TODO: this could be part of tx_status handling, so that the number - * of retries would be known; TX rate should in that case be stored - * somewhere with the packet */ - - /* Estimate total channel use caused by this frame */ - - /* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values, - * 1 usec = 1/8 * (1080 / 10) = 13.5 */ - - if (tx->channel->band == IEEE80211_BAND_5GHZ || - (tx->channel->band == IEEE80211_BAND_2GHZ && - rate->flags & IEEE80211_RATE_ERP_G)) - hdrtime = CHAN_UTIL_HDR_SHORT; - else - hdrtime = CHAN_UTIL_HDR_LONG; - - load = hdrtime; - if (!is_multicast_ether_addr(hdr->addr1)) - load += hdrtime; - - if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) - load += 2 * hdrtime; - else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) - load += hdrtime; + int i; - /* TODO: optimise again */ - load += skb->len * CHAN_UTIL_RATE_LCM / rate->bitrate; + if (!tx->sta) + return TX_CONTINUE; + tx->sta->tx_packets++; + tx->sta->tx_fragments++; + tx->sta->tx_bytes += tx->skb->len; if (tx->extra_frag) { - int i; - for (i = 0; i < tx->num_extra_frag; i++) { - load += 2 * hdrtime; - load += tx->extra_frag[i]->len * - rate->bitrate; - } - } - - /* Divide channel_use by 8 to avoid wrapping around the counter */ - load >>= CHAN_UTIL_SHIFT; - local->channel_use_raw += load; - if (tx->sta) - tx->sta->channel_use_raw += load; - tx->sdata->channel_use_raw += load; - - if (tx->sta) { - tx->sta->tx_packets++; - tx->sta->tx_fragments++; - tx->sta->tx_bytes += tx->skb->len; - if (tx->extra_frag) { - int i; - tx->sta->tx_fragments += tx->num_extra_frag; - for (i = 0; i < tx->num_extra_frag; i++) { - tx->sta->tx_bytes += - tx->extra_frag[i]->len; - } - } + tx->sta->tx_fragments += tx->num_extra_frag; + for (i = 0; i < tx->num_extra_frag; i++) + tx->sta->tx_bytes += tx->extra_frag[i]->len; } return TX_CONTINUE; -- cgit v0.10.2 From 04dea136b06ddd58879c9272b9f66ff060962317 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 20 May 2008 12:10:49 +0200 Subject: b43: enable mesh This patch enables b43 to do mesh networking, tested against my zd1211rw dongle. Signed-off-by: Johannes Berg Reviewed-by: Michael Buesch Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index cbb317b..f9c14c6 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1430,11 +1430,17 @@ static void b43_write_beacon_template(struct b43_wldev *dev, i += ie_len + 2; } if (!tim_found) { - b43warn(dev->wl, "Did not find a valid TIM IE in " - "the beacon template packet. AP or IBSS operation " - "may be broken.\n"); - } else - b43dbg(dev->wl, "Updated beacon template\n"); + /* + * If ucode wants to modify TIM do it behind the beacon, this + * will happen, for example, when doing mesh networking. + */ + b43_shm_write16(dev, B43_SHM_SHARED, + B43_SHM_SH_TIMBPOS, + len + sizeof(struct b43_plcp_hdr6)); + b43_shm_write16(dev, B43_SHM_SHARED, + B43_SHM_SH_DTIMPER, 0); + } + b43dbg(dev->wl, "Updated beacon template at 0x%x\n", ram_offset); } static void b43_write_probe_resp_plcp(struct b43_wldev *dev, @@ -1549,7 +1555,8 @@ static void handle_irq_beacon(struct b43_wldev *dev) struct b43_wl *wl = dev->wl; u32 cmd, beacon0_valid, beacon1_valid; - if (!b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) + if (!b43_is_mode(wl, IEEE80211_IF_TYPE_AP) && + !b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT)) return; /* This is the bottom half of the asynchronous beacon update. */ @@ -2491,7 +2498,8 @@ static void b43_adjust_opmode(struct b43_wldev *dev) ctl &= ~B43_MACCTL_BEACPROMISC; ctl |= B43_MACCTL_INFRA; - if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) + if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) || + b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT)) ctl |= B43_MACCTL_AP; else if (b43_is_mode(wl, IEEE80211_IF_TYPE_IBSS)) ctl &= ~B43_MACCTL_INFRA; @@ -3358,8 +3366,9 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_rx); b43_set_rx_antenna(dev, antenna); - /* Update templates for AP mode. */ - if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) + /* Update templates for AP/mesh mode. */ + if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) || + b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT)) b43_set_beacon_int(dev, conf->beacon_int); if (!!conf->radio_enabled != phy->radio_on) { @@ -3547,8 +3556,9 @@ static int b43_op_config_interface(struct ieee80211_hw *hw, else memset(wl->bssid, 0, ETH_ALEN); if (b43_status(dev) >= B43_STAT_INITIALIZED) { - if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) { - B43_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP); + if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) || + b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT)) { + B43_WARN_ON(conf->type != wl->if_type); b43_set_ssid(dev, conf->ssid, conf->ssid_len); if (conf->beacon) b43_update_templates(wl, conf->beacon); @@ -4088,6 +4098,7 @@ static int b43_op_add_interface(struct ieee80211_hw *hw, /* TODO: allow WDS/AP devices to coexist */ if (conf->type != IEEE80211_IF_TYPE_AP && + conf->type != IEEE80211_IF_TYPE_MESH_POINT && conf->type != IEEE80211_IF_TYPE_STA && conf->type != IEEE80211_IF_TYPE_WDS && conf->type != IEEE80211_IF_TYPE_IBSS) -- cgit v0.10.2 From b77ec4caefb280092a45d6798cbc2fd966ad01d8 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 20 May 2008 16:48:52 +0100 Subject: libertas: provide reset_card() callback on OLPC Signed-off-by: David Woodhouse Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index 8032df7..2478310 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -7,6 +7,10 @@ #include #include +#ifdef CONFIG_OLPC +#include +#endif + #define DRV_NAME "usb8xxx" #include "host.h" @@ -146,6 +150,14 @@ static void if_usb_fw_timeo(unsigned long priv) wake_up(&cardp->fw_wq); } +#ifdef CONFIG_OLPC +static void if_usb_reset_olpc_card(struct lbs_private *priv) +{ + printk(KERN_CRIT "Resetting OLPC wireless via EC...\n"); + olpc_ec_cmd(0x25, NULL, 0, NULL, 0); +} +#endif + /** * @brief sets the configuration values * @param ifnum interface number @@ -231,6 +243,11 @@ static int if_usb_probe(struct usb_interface *intf, cardp->priv->fw_ready = 1; priv->hw_host_to_card = if_usb_host_to_card; +#ifdef CONFIG_OLPC + if (machine_is_olpc()) + priv->reset_card = if_usb_reset_olpc_card; +#endif + cardp->boot2_version = udev->descriptor.bcdDevice; if_usb_submit_rx_urb(cardp); @@ -364,6 +381,11 @@ static int if_usb_reset_device(struct if_usb_card *cardp) ret = usb_reset_device(cardp->udev); msleep(100); +#ifdef CONFIG_OLPC + if (ret && machine_is_olpc()) + if_usb_reset_olpc_card(NULL); +#endif + lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret); return ret; -- cgit v0.10.2 From 706ddd600ca637720f87cef630179934add32b13 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Thu, 22 May 2008 00:00:01 -0700 Subject: ps3: gelic: scan_lock semaphore to mutex Signed-off-by: Daniel Walker Acked-by: Masakazu Mokuno Signed-off-by: John W. Linville diff --git a/drivers/net/ps3_gelic_wireless.c b/drivers/net/ps3_gelic_wireless.c index 1dae1f2..b338093 100644 --- a/drivers/net/ps3_gelic_wireless.c +++ b/drivers/net/ps3_gelic_wireless.c @@ -695,7 +695,7 @@ static int gelic_wl_get_scan(struct net_device *netdev, unsigned long this_time = jiffies; pr_debug("%s: <-\n", __func__); - if (down_interruptible(&wl->scan_lock)) + if (mutex_lock_interruptible(&wl->scan_lock)) return -EAGAIN; switch (wl->scan_stat) { @@ -733,7 +733,7 @@ static int gelic_wl_get_scan(struct net_device *netdev, wrqu->data.length = ev - extra; wrqu->data.flags = 0; out: - up(&wl->scan_lock); + mutex_unlock(&wl->scan_lock); pr_debug("%s: -> %d %d\n", __func__, ret, wrqu->data.length); return ret; } @@ -1554,7 +1554,7 @@ static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan) int ret = 0; pr_debug("%s: <- always=%d\n", __func__, always_scan); - if (down_interruptible(&wl->scan_lock)) + if (mutex_lock_interruptible(&wl->scan_lock)) return -ERESTARTSYS; /* @@ -1588,7 +1588,7 @@ static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan) } kfree(cmd); out: - up(&wl->scan_lock); + mutex_unlock(&wl->scan_lock); pr_debug("%s: ->\n", __func__); return ret; } @@ -1610,7 +1610,7 @@ static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl) DECLARE_MAC_BUF(mac); pr_debug("%s:start\n", __func__); - down(&wl->scan_lock); + mutex_lock(&wl->scan_lock); if (wl->scan_stat != GELIC_WL_SCAN_STAT_SCANNING) { /* @@ -1727,7 +1727,7 @@ static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl) NULL); out: complete(&wl->scan_done); - up(&wl->scan_lock); + mutex_unlock(&wl->scan_lock); pr_debug("%s:end\n", __func__); } @@ -2282,7 +2282,7 @@ static void gelic_wl_assoc_worker(struct work_struct *work) wait_for_completion(&wl->scan_done); pr_debug("%s: scan done\n", __func__); - down(&wl->scan_lock); + mutex_lock(&wl->scan_lock); if (wl->scan_stat != GELIC_WL_SCAN_STAT_GOT_LIST) { gelic_wl_send_iwap_event(wl, NULL); pr_info("%s: no scan list. association failed\n", __func__); @@ -2302,7 +2302,7 @@ static void gelic_wl_assoc_worker(struct work_struct *work) if (ret) pr_info("%s: association failed %d\n", __func__, ret); scan_lock_out: - up(&wl->scan_lock); + mutex_unlock(&wl->scan_lock); out: up(&wl->assoc_stat_lock); } @@ -2431,7 +2431,7 @@ static struct net_device *gelic_wl_alloc(struct gelic_card *card) INIT_DELAYED_WORK(&wl->event_work, gelic_wl_event_worker); INIT_DELAYED_WORK(&wl->assoc_work, gelic_wl_assoc_worker); - init_MUTEX(&wl->scan_lock); + mutex_init(&wl->scan_lock); init_MUTEX(&wl->assoc_stat_lock); init_completion(&wl->scan_done); diff --git a/drivers/net/ps3_gelic_wireless.h b/drivers/net/ps3_gelic_wireless.h index 1036971..fb3222e 100644 --- a/drivers/net/ps3_gelic_wireless.h +++ b/drivers/net/ps3_gelic_wireless.h @@ -241,7 +241,7 @@ enum gelic_wl_assoc_state { #define GELIC_WEP_KEYS 4 struct gelic_wl_info { /* bss list */ - struct semaphore scan_lock; + struct mutex scan_lock; struct list_head network_list; struct list_head network_free_list; struct gelic_wl_scan_info *networks; -- cgit v0.10.2 From bb2d67a34fe80c14d0a379695ab81362b3da1d53 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Thu, 22 May 2008 00:00:02 -0700 Subject: ps3: gelic: assoc_stat_lock semaphore to mutex Signed-off-by: Daniel Walker Acked-by: Masakazu Mokuno Signed-off-by: John W. Linville diff --git a/drivers/net/ps3_gelic_wireless.c b/drivers/net/ps3_gelic_wireless.c index b338093..e5e0233 100644 --- a/drivers/net/ps3_gelic_wireless.c +++ b/drivers/net/ps3_gelic_wireless.c @@ -240,12 +240,12 @@ static u32 gelic_wl_get_link(struct net_device *netdev) u32 ret; pr_debug("%s: <-\n", __func__); - down(&wl->assoc_stat_lock); + mutex_lock(&wl->assoc_stat_lock); if (wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED) ret = 1; else ret = 0; - up(&wl->assoc_stat_lock); + mutex_unlock(&wl->assoc_stat_lock); pr_debug("%s: ->\n", __func__); return ret; } @@ -979,7 +979,7 @@ static int gelic_wl_get_essid(struct net_device *netdev, unsigned long irqflag; pr_debug("%s: <- \n", __func__); - down(&wl->assoc_stat_lock); + mutex_lock(&wl->assoc_stat_lock); spin_lock_irqsave(&wl->lock, irqflag); if (test_bit(GELIC_WL_STAT_ESSID_SET, &wl->stat) || wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED) { @@ -989,7 +989,7 @@ static int gelic_wl_get_essid(struct net_device *netdev, } else data->essid.flags = 0; - up(&wl->assoc_stat_lock); + mutex_unlock(&wl->assoc_stat_lock); spin_unlock_irqrestore(&wl->lock, irqflag); pr_debug("%s: -> len=%d \n", __func__, data->essid.length); @@ -1170,7 +1170,7 @@ static int gelic_wl_get_ap(struct net_device *netdev, unsigned long irqflag; pr_debug("%s: <-\n", __func__); - down(&wl->assoc_stat_lock); + mutex_lock(&wl->assoc_stat_lock); spin_lock_irqsave(&wl->lock, irqflag); if (wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED) { data->ap_addr.sa_family = ARPHRD_ETHER; @@ -1180,7 +1180,7 @@ static int gelic_wl_get_ap(struct net_device *netdev, memset(data->ap_addr.sa_data, 0, ETH_ALEN); spin_unlock_irqrestore(&wl->lock, irqflag); - up(&wl->assoc_stat_lock); + mutex_unlock(&wl->assoc_stat_lock); pr_debug("%s: ->\n", __func__); return 0; } @@ -2151,7 +2151,7 @@ static void gelic_wl_disconnect_event(struct gelic_wl_info *wl, * As it waits with timeout, just leave assoc_done * uncompleted, then it terminates with timeout */ - if (down_trylock(&wl->assoc_stat_lock)) { + if (!mutex_trylock(&wl->assoc_stat_lock)) { pr_debug("%s: already locked\n", __func__); lock = 0; } else { @@ -2170,7 +2170,7 @@ static void gelic_wl_disconnect_event(struct gelic_wl_info *wl, netif_carrier_off(port_to_netdev(wl_port(wl))); if (lock) - up(&wl->assoc_stat_lock); + mutex_unlock(&wl->assoc_stat_lock); } /* * event worker @@ -2258,7 +2258,7 @@ static void gelic_wl_assoc_worker(struct work_struct *work) wl = container_of(work, struct gelic_wl_info, assoc_work.work); - down(&wl->assoc_stat_lock); + mutex_lock(&wl->assoc_stat_lock); if (wl->assoc_stat != GELIC_WL_ASSOC_STAT_DISCONN) goto out; @@ -2304,7 +2304,7 @@ static void gelic_wl_assoc_worker(struct work_struct *work) scan_lock_out: mutex_unlock(&wl->scan_lock); out: - up(&wl->assoc_stat_lock); + mutex_unlock(&wl->assoc_stat_lock); } /* * Interrupt handler @@ -2432,7 +2432,7 @@ static struct net_device *gelic_wl_alloc(struct gelic_card *card) INIT_DELAYED_WORK(&wl->event_work, gelic_wl_event_worker); INIT_DELAYED_WORK(&wl->assoc_work, gelic_wl_assoc_worker); mutex_init(&wl->scan_lock); - init_MUTEX(&wl->assoc_stat_lock); + mutex_init(&wl->assoc_stat_lock); init_completion(&wl->scan_done); /* for the case that no scan request is issued and stop() is called */ diff --git a/drivers/net/ps3_gelic_wireless.h b/drivers/net/ps3_gelic_wireless.h index fb3222e..bc73063 100644 --- a/drivers/net/ps3_gelic_wireless.h +++ b/drivers/net/ps3_gelic_wireless.h @@ -266,7 +266,7 @@ struct gelic_wl_info { enum gelic_wl_wpa_level wpa_level; /* wpa/wpa2 */ /* association handling */ - struct semaphore assoc_stat_lock; + struct mutex assoc_stat_lock; struct delayed_work assoc_work; enum gelic_wl_assoc_state assoc_stat; struct completion assoc_done; -- cgit v0.10.2 From f622360bce6facb05fdce4bce5ee4beb2432222d Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Thu, 22 May 2008 00:00:03 -0700 Subject: ps3: gelic: updown_lock semaphore to mutex Signed-off-by: Daniel Walker Acked-by: Masakazu Mokuno Signed-off-by: John W. Linville diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c index e365efb..2eb54fd 100644 --- a/drivers/net/ps3_gelic_net.c +++ b/drivers/net/ps3_gelic_net.c @@ -110,7 +110,7 @@ static void gelic_card_get_ether_port_status(struct gelic_card *card, void gelic_card_up(struct gelic_card *card) { pr_debug("%s: called\n", __func__); - down(&card->updown_lock); + mutex_lock(&card->updown_lock); if (atomic_inc_return(&card->users) == 1) { pr_debug("%s: real do\n", __func__); /* enable irq */ @@ -120,7 +120,7 @@ void gelic_card_up(struct gelic_card *card) napi_enable(&card->napi); } - up(&card->updown_lock); + mutex_unlock(&card->updown_lock); pr_debug("%s: done\n", __func__); } @@ -128,7 +128,7 @@ void gelic_card_down(struct gelic_card *card) { u64 mask; pr_debug("%s: called\n", __func__); - down(&card->updown_lock); + mutex_lock(&card->updown_lock); if (atomic_dec_if_positive(&card->users) == 0) { pr_debug("%s: real do\n", __func__); napi_disable(&card->napi); @@ -146,7 +146,7 @@ void gelic_card_down(struct gelic_card *card) /* stop tx */ gelic_card_disable_txdmac(card); } - up(&card->updown_lock); + mutex_unlock(&card->updown_lock); pr_debug("%s: done\n", __func__); } @@ -1534,7 +1534,7 @@ static struct gelic_card *gelic_alloc_card_net(struct net_device **netdev) INIT_WORK(&card->tx_timeout_task, gelic_net_tx_timeout_task); init_waitqueue_head(&card->waitq); atomic_set(&card->tx_timeout_task_counter, 0); - init_MUTEX(&card->updown_lock); + mutex_init(&card->updown_lock); atomic_set(&card->users, 0); return card; diff --git a/drivers/net/ps3_gelic_net.h b/drivers/net/ps3_gelic_net.h index 520f143..8b41386 100644 --- a/drivers/net/ps3_gelic_net.h +++ b/drivers/net/ps3_gelic_net.h @@ -298,7 +298,7 @@ struct gelic_card { wait_queue_head_t waitq; /* only first user should up the card */ - struct semaphore updown_lock; + struct mutex updown_lock; atomic_t users; u64 ether_port_status; -- cgit v0.10.2 From 23c0752a25d73ccc4547700e8a57d5ae2f2edf56 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 29 May 2008 10:38:53 +0200 Subject: mac80211: clean up skb reallocation code This cleans up the skb reallocation code to avoid problems with skb->truesize, not resize an skb twice for a single output path because we didn't expand it enough during the first copy and also removes the code to further expand it during crypto operations which will no longer be necessary. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index baa1be0..dac44cb 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1215,6 +1215,45 @@ retry: /* device xmit handlers */ +static int ieee80211_skb_resize(struct ieee80211_local *local, + struct sk_buff *skb, + int head_need, bool may_encrypt) +{ + int tail_need = 0; + + /* + * This could be optimised, devices that do full hardware + * crypto (including TKIP MMIC) need no tailroom... But we + * have no drivers for such devices currently. + */ + if (may_encrypt) { + tail_need = IEEE80211_ENCRYPT_TAILROOM; + tail_need -= skb_tailroom(skb); + tail_need = max_t(int, tail_need, 0); + } + + if (head_need || tail_need) { + /* Sorry. Can't account for this any more */ + skb_orphan(skb); + } + + if (skb_header_cloned(skb)) + I802_DEBUG_INC(local->tx_expand_skb_head_cloned); + else + I802_DEBUG_INC(local->tx_expand_skb_head); + + if (pskb_expand_head(skb, head_need, tail_need, GFP_ATOMIC)) { + printk(KERN_DEBUG "%s: failed to reallocate TX buffer\n", + wiphy_name(local->hw.wiphy)); + return -ENOMEM; + } + + /* update truesize too */ + skb->truesize += head_need + tail_need; + + return 0; +} + int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev) { @@ -1222,6 +1261,7 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *odev = NULL; struct ieee80211_sub_if_data *osdata; int headroom; + bool may_encrypt; int ret; if (info->control.ifindex) @@ -1241,13 +1281,18 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, osdata = IEEE80211_DEV_TO_SUB_IF(odev); - headroom = osdata->local->tx_headroom + IEEE80211_ENCRYPT_HEADROOM; - if (skb_headroom(skb) < headroom) { - if (pskb_expand_head(skb, headroom, 0, GFP_ATOMIC)) { - dev_kfree_skb(skb); - dev_put(odev); - return 0; - } + may_encrypt = !(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT); + + headroom = osdata->local->tx_headroom; + if (may_encrypt) + headroom += IEEE80211_ENCRYPT_HEADROOM; + headroom -= skb_headroom(skb); + headroom = max_t(int, 0, headroom); + + if (ieee80211_skb_resize(osdata->local, skb, headroom, may_encrypt)) { + dev_kfree_skb(skb); + dev_put(odev); + return 0; } info->control.vif = &osdata->vif; @@ -1509,32 +1554,26 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, * build in headroom in __dev_alloc_skb() (linux/skbuff.h) and * alloc_skb() (net/core/skbuff.c) */ - head_need = hdrlen + encaps_len + meshhdrlen + local->tx_headroom; - head_need -= skb_headroom(skb); + head_need = hdrlen + encaps_len + meshhdrlen - skb_headroom(skb); - /* We are going to modify skb data, so make a copy of it if happens to - * be cloned. This could happen, e.g., with Linux bridge code passing - * us broadcast frames. */ + /* + * So we need to modify the skb header and hence need a copy of + * that. The head_need variable above doesn't, so far, include + * the needed header space that we don't need right away. If we + * can, then we don't reallocate right now but only after the + * frame arrives at the master device (if it does...) + * + * If we cannot, however, then we will reallocate to include all + * the ever needed space. Also, if we need to reallocate it anyway, + * make it big enough for everything we may ever need. + */ if (head_need > 0 || skb_header_cloned(skb)) { -#if 0 - printk(KERN_DEBUG "%s: need to reallocate buffer for %d bytes " - "of headroom\n", dev->name, head_need); -#endif - - if (skb_header_cloned(skb)) - I802_DEBUG_INC(local->tx_expand_skb_head_cloned); - else - I802_DEBUG_INC(local->tx_expand_skb_head); - /* Since we have to reallocate the buffer, make sure that there - * is enough room for possible WEP IV/ICV and TKIP (8 bytes - * before payload and 12 after). */ - if (pskb_expand_head(skb, (head_need > 0 ? head_need + 8 : 8), - 12, GFP_ATOMIC)) { - printk(KERN_DEBUG "%s: failed to reallocate TX buffer" - "\n", dev->name); + head_need += IEEE80211_ENCRYPT_HEADROOM; + head_need += local->tx_headroom; + head_need = max_t(int, 0, head_need); + if (ieee80211_skb_resize(local, skb, head_need, true)) goto fail; - } } if (encaps_data) { diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index 1e7f03d..c9fd129 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c @@ -93,13 +93,9 @@ static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local, fc |= IEEE80211_FCTL_PROTECTED; hdr->frame_control = cpu_to_le16(fc); - if ((skb_headroom(skb) < WEP_IV_LEN || - skb_tailroom(skb) < WEP_ICV_LEN)) { - I802_DEBUG_INC(local->tx_expand_skb_head); - if (unlikely(pskb_expand_head(skb, WEP_IV_LEN, WEP_ICV_LEN, - GFP_ATOMIC))) - return NULL; - } + if (WARN_ON(skb_tailroom(skb) < WEP_ICV_LEN || + skb_headroom(skb) < WEP_IV_LEN)) + return NULL; hdrlen = ieee80211_get_hdrlen(fc); newhdr = skb_push(skb, WEP_IV_LEN); diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index d6635f6..9f6fd20 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -79,6 +79,7 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx) struct sk_buff *skb = tx->skb; int authenticator; int wpa_test = 0; + int tail; fc = tx->fc; @@ -98,16 +99,13 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx) return TX_CONTINUE; } - if (skb_tailroom(skb) < MICHAEL_MIC_LEN) { - I802_DEBUG_INC(tx->local->tx_expand_skb_head); - if (unlikely(pskb_expand_head(skb, TKIP_IV_LEN, - MICHAEL_MIC_LEN + TKIP_ICV_LEN, - GFP_ATOMIC))) { - printk(KERN_DEBUG "%s: failed to allocate more memory " - "for Michael MIC\n", tx->dev->name); - return TX_DROP; - } - } + tail = MICHAEL_MIC_LEN; + if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) + tail += TKIP_ICV_LEN; + + if (WARN_ON(skb_tailroom(skb) < tail || + skb_headroom(skb) < TKIP_IV_LEN)) + return TX_DROP; #if 0 authenticator = fc & IEEE80211_FCTL_FROMDS; /* FIX */ @@ -188,7 +186,7 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_key *key = tx->key; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - int hdrlen, len, tailneed; + int hdrlen, len, tail; u16 fc; u8 *pos; @@ -199,7 +197,7 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { /* hwaccel - with no need for preallocated room for IV/ICV */ info->control.hw_key = &tx->key->conf; - return TX_CONTINUE; + return 0; } fc = le16_to_cpu(hdr->frame_control); @@ -207,17 +205,13 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) len = skb->len - hdrlen; if (tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) - tailneed = 0; + tail = 0; else - tailneed = TKIP_ICV_LEN; - - if ((skb_headroom(skb) < TKIP_IV_LEN || - skb_tailroom(skb) < tailneed)) { - I802_DEBUG_INC(tx->local->tx_expand_skb_head); - if (unlikely(pskb_expand_head(skb, TKIP_IV_LEN, tailneed, - GFP_ATOMIC))) - return -1; - } + tail = TKIP_ICV_LEN; + + if (WARN_ON(skb_tailroom(skb) < tail || + skb_headroom(skb) < TKIP_IV_LEN)) + return -1; pos = skb_push(skb, TKIP_IV_LEN); memmove(pos, pos + TKIP_IV_LEN, hdrlen); @@ -432,7 +426,7 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_key *key = tx->key; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - int hdrlen, len, tailneed; + int hdrlen, len, tail; u16 fc; u8 *pos, *pn, *b_0, *aad, *scratch; int i; @@ -445,7 +439,7 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) /* hwaccel - with no need for preallocated room for CCMP " * header or MIC fields */ info->control.hw_key = &tx->key->conf; - return TX_CONTINUE; + return 0; } scratch = key->u.ccmp.tx_crypto_buf; @@ -457,17 +451,13 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) len = skb->len - hdrlen; if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) - tailneed = 0; + tail = 0; else - tailneed = CCMP_MIC_LEN; - - if ((skb_headroom(skb) < CCMP_HDR_LEN || - skb_tailroom(skb) < tailneed)) { - I802_DEBUG_INC(tx->local->tx_expand_skb_head); - if (unlikely(pskb_expand_head(skb, CCMP_HDR_LEN, tailneed, - GFP_ATOMIC))) - return -1; - } + tail = CCMP_MIC_LEN; + + if (WARN_ON(skb_tailroom(skb) < tail || + skb_headroom(skb) < CCMP_HDR_LEN)) + return -1; pos = skb_push(skb, CCMP_HDR_LEN); memmove(pos, pos + CCMP_HDR_LEN, hdrlen); -- cgit v0.10.2 From b43441a49d1c64769ff90f34e9543b2ba840b517 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Fri, 23 May 2008 10:07:56 +0200 Subject: libertas: don't spin_unlock_irq() twice priv->driver_lock has already been unlocked some lines above. This patch fixes the sparse warning: drivers/net/wireless/libertas/main.c:792:6: warning: context problem in 'lbs_thread': '_spin_unlock_irq' expected different context drivers/net/wireless/libertas/main.c:792:6: context 'lock': wanted >= 1, got 0 Signed-of-by: Holger Schurig Acked-by: Dan Williams Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index baafa44..0cd4702 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -788,11 +788,8 @@ static int lbs_thread(void *data) le16_to_cpu(cmdnode->cmdbuf->command)); lbs_complete_command(priv, cmdnode, -ETIMEDOUT); priv->nr_retries = 0; - if (priv->reset_card) { - spin_unlock_irq(&priv->driver_lock); + if (priv->reset_card) priv->reset_card(priv); - spin_lock_irq(&priv->driver_lock); - } } else { priv->cur_cmd = NULL; lbs_pr_info("requeueing command 0x%04x due " -- cgit v0.10.2 From 93416c871f8588446e80780f7d62fabc131c276b Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Fri, 23 May 2008 10:18:26 +0200 Subject: libertas: speeds up downloading of CF firmware Keep the timeout the same (1000*500 == 100000 * 5), but take shorter naps. Makes downloading the firmware slightly faster. Signed-off-by: Holger Schurig Acked-by: Dan Williams Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index 54280e2..86bb126 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -148,11 +148,11 @@ static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 r { int i; - for (i = 0; i < 1000; i++) { + for (i = 0; i < 100000; i++) { u8 val = if_cs_read8(card, addr); if (val == reg) return i; - udelay(500); + udelay(5); } return -ETIME; } -- cgit v0.10.2 From df349f9fe7500fcb98f560c74b5e99477ca1df1c Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Fri, 23 May 2008 12:16:51 +0200 Subject: libertas: use lbs_pr_XX instead of printk ... because lbs_pr_XXX prefixes all messages with "libertas: " Signed-off-by: Holger Schurig Acked-by: Dan Williams Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 2d9bbcc..e8d0144 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -110,7 +110,7 @@ int lbs_update_hw_spec(struct lbs_private *priv) * CF card firmware 5.0.16p0: cap 0x00000303 * USB dongle firmware 5.110.17p2: cap 0x00000303 */ - printk("libertas: %s, fw %u.%u.%up%u, cap 0x%08x\n", + lbs_pr_info("%s, fw %u.%u.%up%u, cap 0x%08x\n", print_mac(mac, cmd.permanentaddr), priv->fwrelease >> 24 & 0xff, priv->fwrelease >> 16 & 0xff, diff --git a/drivers/net/wireless/libertas/persistcfg.c b/drivers/net/wireless/libertas/persistcfg.c index 6cf5e39..6d0ff8d 100644 --- a/drivers/net/wireless/libertas/persistcfg.c +++ b/drivers/net/wireless/libertas/persistcfg.c @@ -188,7 +188,7 @@ static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr, return ret; if (defs.meshie.val.mesh_id_len > IW_ESSID_MAX_SIZE) { - printk(KERN_ERR "Inconsistent mesh ID length"); + lbs_pr_err("inconsistent mesh ID length"); defs.meshie.val.mesh_id_len = IW_ESSID_MAX_SIZE; } -- cgit v0.10.2 From ef707b8387c13b6aa3353b5519aa465cbe06034f Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Fri, 23 May 2008 16:04:13 +0200 Subject: libertas: before sleeping, check for a command result If we don't check for a command response early, but rather sleep, then we might sleep despite an already-received command response. This will lead to a command-timeout. Signed-off-by: Holger Schurig Acked-by: Dan Williams Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 0cd4702..faa4db1 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -722,14 +722,14 @@ static int lbs_thread(void *data) shouldsleep = 1; /* Something is en route to the device already */ else if (priv->tx_pending_len > 0) shouldsleep = 0; /* We've a packet to send */ + else if (priv->resp_len[priv->resp_idx]) + shouldsleep = 0; /* We have a command response */ else if (priv->cur_cmd) shouldsleep = 1; /* Can't send a command; one already running */ else if (!list_empty(&priv->cmdpendingq)) shouldsleep = 0; /* We have a command to send */ else if (__kfifo_len(priv->event_fifo)) shouldsleep = 0; /* We have an event to process */ - else if (priv->resp_len[priv->resp_idx]) - shouldsleep = 0; /* We have a command response */ else shouldsleep = 1; /* No command */ -- cgit v0.10.2 From a888d52d1eda77f08e09d38ac829353200240716 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 26 May 2008 16:43:39 +0200 Subject: ath5k: use IEEE80211_SKB_CB ath5k still uses the "(void*) skb->cb" direct cast, use IEEE80211_SKB_CB instead. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 18e9422..85045af 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -1296,7 +1296,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) struct ath5k_txq *txq = sc->txq; struct ath5k_desc *ds = bf->desc; struct sk_buff *skb = bf->skb; - struct ieee80211_tx_info *info = (void*) skb->cb; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); unsigned int pktlen, flags, keyidx = AR5K_TXKEYIX_INVALID; int ret; @@ -1945,7 +1945,7 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) } skb = bf->skb; - info = (void*) skb->cb; + info = IEEE80211_SKB_CB(skb); bf->skb = NULL; pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, @@ -2003,7 +2003,7 @@ static int ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) { struct sk_buff *skb = bf->skb; - struct ieee80211_tx_info *info = (void*) skb->cb; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ath5k_hw *ah = sc->ah; struct ath5k_desc *ds; int ret, antenna = 0; @@ -2625,7 +2625,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct ath5k_softc *sc = hw->priv; struct ath5k_buf *bf; - struct ieee80211_tx_info *info = (void*) skb->cb; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); unsigned long flags; int hdrlen; int pad; -- cgit v0.10.2 From 20ad4fd56255b455beb677dc097eb108d15f1d63 Mon Sep 17 00:00:00 2001 From: Scott Ashcroft Date: Tue, 27 May 2008 11:15:02 +0300 Subject: rndis_wlan: use ARRAY_SIZE instead of sizeof when adding 11g rates While figuring out the TKIP problem I found a bug in the code which adds the 11g rates. It's using sizeof instead of ARRAY_SIZE to terminate the for loop. This makes it fall off the end of the rates array start into the frequency array instead. Running "iwlist rate" should show the problem as there will always be 32 rates with the last few being bogus. The following patch will fix it. Signed-off-by: Scott Ashcroft Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index d0b1fb1..ed310f8 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -1108,7 +1108,7 @@ static int rndis_iw_get_range(struct net_device *dev, /* fill in 802.11g rates */ if (has_80211g_rates) { num = range->num_bitrates; - for (i = 0; i < sizeof(rates_80211g); i++) { + for (i = 0; i < ARRAY_SIZE(rates_80211g); i++) { for (j = 0; j < num; j++) { if (range->bitrate[j] == rates_80211g[i] * 1000000) -- cgit v0.10.2 From 747cf5e924a469a15a454b88a813236460b30975 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 27 May 2008 17:50:51 +0300 Subject: mac80211: fix ieee80211_get_buffered_bc fix bss not initialized in ieee80211_get_buffered_bc and unbalanced locking Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index dac44cb..16af308 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1947,7 +1947,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct ieee80211_local *local = hw_to_local(hw); - struct sk_buff *skb; + struct sk_buff *skb = NULL; struct sta_info *sta; ieee80211_tx_handler *handler; struct ieee80211_tx_data tx; @@ -1960,7 +1960,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, sdata = vif_to_sdata(vif); bdev = sdata->dev; - + bss = &sdata->u.ap; if (!bss) return NULL; @@ -1968,19 +1968,16 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, rcu_read_lock(); beacon = rcu_dereference(bss->beacon); - if (sdata->vif.type != IEEE80211_IF_TYPE_AP || !beacon || - !beacon->head) { - rcu_read_unlock(); - return NULL; - } + if (sdata->vif.type != IEEE80211_IF_TYPE_AP || !beacon || !beacon->head) + goto out; if (bss->dtim_count != 0) - return NULL; /* send buffered bc/mc only after DTIM beacon */ + goto out; /* send buffered bc/mc only after DTIM beacon */ while (1) { skb = skb_dequeue(&bss->ps_bc_buf); if (!skb) - return NULL; + goto out; local->total_ps_buffered--; if (!skb_queue_empty(&bss->ps_bc_buf) && skb->len >= 2) { @@ -2023,6 +2020,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, skb = NULL; } +out: rcu_read_unlock(); return skb; -- cgit v0.10.2 From b83f4e15e65d94f6f56924b0b06a77a7ca2b4d8a Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 27 May 2008 17:50:52 +0300 Subject: mac80211: fix deadlock in sta->lock This patch fixes a deadlock of sta->lock use, occurring while changing tx aggregation states, as dev_queue_xmit end up in new function test_and_clear_sta_flags that uses that lock thus leading to deadlock Signed-off-by: Tomas Winkler Signed-off-by: Ron Rindjunsky Signed-off-by: John W. Linville diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 97d4a53..f79f6b9 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -589,8 +589,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) sta = sta_info_get(local, ra); if (!sta) { printk(KERN_DEBUG "Could not find the station\n"); - rcu_read_unlock(); - return -ENOENT; + ret = -ENOENT; + goto exit; } spin_lock_bh(&sta->lock); @@ -598,7 +598,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) /* we have tried too many times, receiver does not want A-MPDU */ if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) { ret = -EBUSY; - goto start_ba_exit; + goto err_unlock_sta; } state = &sta->ampdu_mlme.tid_state_tx[tid]; @@ -609,7 +609,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) "idle on tid %u\n", tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ ret = -EAGAIN; - goto start_ba_exit; + goto err_unlock_sta; } /* prepare A-MPDU MLME for Tx aggregation */ @@ -620,7 +620,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) printk(KERN_ERR "allocate tx mlme to tid %d failed\n", tid); ret = -ENOMEM; - goto start_ba_exit; + goto err_unlock_sta; } /* Tx timer */ sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function = @@ -643,7 +643,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) printk(KERN_DEBUG "BA request denied - queue unavailable for" " tid %d\n", tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ - goto start_ba_err; + goto err_unlock_queue; } sdata = sta->sdata; @@ -665,12 +665,13 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) " tid %d\n", tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ *state = HT_AGG_STATE_IDLE; - goto start_ba_err; + goto err_unlock_queue; } /* Will put all the packets in the new SW queue */ ieee80211_requeue(local, ieee802_1d_to_ac[tid]); spin_unlock_bh(&local->mdev->queue_lock); + spin_unlock_bh(&sta->lock); /* send an addBA request */ sta->ampdu_mlme.dialog_token_allocator++; @@ -678,25 +679,26 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) sta->ampdu_mlme.dialog_token_allocator; sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num; + ieee80211_send_addba_request(sta->sdata->dev, ra, tid, sta->ampdu_mlme.tid_tx[tid]->dialog_token, sta->ampdu_mlme.tid_tx[tid]->ssn, 0x40, 5000); - /* activate the timer for the recipient's addBA response */ sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires = jiffies + ADDBA_RESP_INTERVAL; add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid); - goto start_ba_exit; + goto exit; -start_ba_err: +err_unlock_queue: kfree(sta->ampdu_mlme.tid_tx[tid]); sta->ampdu_mlme.tid_tx[tid] = NULL; spin_unlock_bh(&local->mdev->queue_lock); ret = -EBUSY; -start_ba_exit: +err_unlock_sta: spin_unlock_bh(&sta->lock); +exit: rcu_read_unlock(); return ret; } @@ -835,10 +837,11 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) } state = &sta->ampdu_mlme.tid_state_tx[tid]; - spin_lock_bh(&sta->lock); + /* NOTE: no need to use sta->lock in this state check, as + * ieee80211_stop_tx_ba_session will let only + * one stop call to pass through per sta/tid */ if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) { printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n"); - spin_unlock_bh(&sta->lock); rcu_read_unlock(); return; } @@ -861,6 +864,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) * ieee80211_wake_queue is not used here as this queue is not * necessarily stopped */ netif_schedule(local->mdev); + spin_lock_bh(&sta->lock); *state = HT_AGG_STATE_IDLE; sta->ampdu_mlme.addba_req_num[tid] = 0; kfree(sta->ampdu_mlme.tid_tx[tid]); -- cgit v0.10.2 From 553381c430f0e65e87ed1b5cee841a04c8a47b58 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 24 May 2008 20:07:55 +0200 Subject: b43legacy: fix build errors when DMA or PIO are not selected Currently, b43legacy is broken due to commit fbad4598ca826b994d0fd4ce3deebc9cd1960b31 Author: Johannes Berg Date: Thu May 15 12:55:29 2008 +0200 mac80211: move TX info into skb->cb when compiled with only PIO or only DMA because I forgot to update two stubs. This patch fixes it. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43legacy/dma.h b/drivers/net/wireless/b43legacy/dma.h index 67537a7..2f18600 100644 --- a/drivers/net/wireless/b43legacy/dma.h +++ b/drivers/net/wireless/b43legacy/dma.h @@ -321,8 +321,7 @@ void b43legacy_dma_get_tx_stats(struct b43legacy_wldev *dev, } static inline int b43legacy_dma_tx(struct b43legacy_wldev *dev, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl) + struct sk_buff *skb) { return 0; } diff --git a/drivers/net/wireless/b43legacy/pio.h b/drivers/net/wireless/b43legacy/pio.h index 49310df..464fec0 100644 --- a/drivers/net/wireless/b43legacy/pio.h +++ b/drivers/net/wireless/b43legacy/pio.h @@ -130,8 +130,7 @@ void b43legacy_pio_free(struct b43legacy_wldev *dev) } static inline int b43legacy_pio_tx(struct b43legacy_wldev *dev, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl) + struct sk_buff *skb) { return 0; } -- cgit v0.10.2 From 85319f933a703a92652a8f23339f1ec1694cd594 Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Sat, 24 May 2008 10:59:49 +0100 Subject: libertas: rate adaptation configuration via iwconfig. Implemented rate adaptation support via 'iwconfig rate' API. It is now possible to specify a bit-rate value and append 'auto'. That will configure rate adaptation to use all bit-rates equal or lower than than selected value. Made lbs_cmd_802_11_rate_adapt_rateset a direct command. Signed-off-by: Javier Cardona Signed-off-by: David Woodhouse Acked-by: Dan Williams Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index 953a44f..a267d6e 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -1250,7 +1250,7 @@ static int get_common_rates(struct lbs_private *priv, lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size); lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate); - if (!priv->auto_rate) { + if (!priv->enablehwauto) { for (i = 0; i < tmp_size; i++) { if (tmp[i] == priv->cur_rate) goto done; diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index e8d0144..cf261d3 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -676,26 +676,60 @@ static int lbs_cmd_802_11_monitor_mode(struct cmd_ds_command *cmd, return 0; } -static int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv, - struct cmd_ds_command *cmd, - u16 cmd_action) +static __le16 lbs_rate_to_fw_bitmap(int rate, int lower_rates_ok) { - struct cmd_ds_802_11_rate_adapt_rateset - *rateadapt = &cmd->params.rateset; +/* Bit Rate +* 15:13 Reserved +* 12 54 Mbps +* 11 48 Mbps +* 10 36 Mbps +* 9 24 Mbps +* 8 18 Mbps +* 7 12 Mbps +* 6 9 Mbps +* 5 6 Mbps +* 4 Reserved +* 3 11 Mbps +* 2 5.5 Mbps +* 1 2 Mbps +* 0 1 Mbps +**/ + + uint16_t ratemask; + int i = lbs_data_rate_to_fw_index(rate); + if (lower_rates_ok) + ratemask = (0x1fef >> (12 - i)); + else + ratemask = (1 << i); + return cpu_to_le16(ratemask); +} + +int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv, + uint16_t cmd_action) +{ + struct cmd_ds_802_11_rate_adapt_rateset cmd; + int ret; lbs_deb_enter(LBS_DEB_CMD); - cmd->size = - cpu_to_le16(sizeof(struct cmd_ds_802_11_rate_adapt_rateset) - + S_DS_GEN); - cmd->command = cpu_to_le16(CMD_802_11_RATE_ADAPT_RATESET); - rateadapt->action = cpu_to_le16(cmd_action); - rateadapt->enablehwauto = cpu_to_le16(priv->enablehwauto); - rateadapt->bitmap = cpu_to_le16(priv->ratebitmap); + if (!priv->cur_rate && !priv->enablehwauto) + return -EINVAL; - lbs_deb_leave(LBS_DEB_CMD); - return 0; + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + + cmd.action = cpu_to_le16(cmd_action); + cmd.enablehwauto = cpu_to_le16(priv->enablehwauto); + cmd.bitmap = lbs_rate_to_fw_bitmap(priv->cur_rate, priv->enablehwauto); + ret = lbs_cmd_with_response(priv, CMD_802_11_RATE_ADAPT_RATESET, &cmd); + if (!ret && cmd_action == CMD_ACT_GET) { + priv->ratebitmap = le16_to_cpu(cmd.bitmap); + priv->enablehwauto = le16_to_cpu(cmd.enablehwauto); + } + + lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); + return ret; } +EXPORT_SYMBOL_GPL(lbs_cmd_802_11_rate_adapt_rateset); /** * @brief Set the data rate @@ -1378,11 +1412,6 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, cmd_action, pdata_buf); break; - case CMD_802_11_RATE_ADAPT_RATESET: - ret = lbs_cmd_802_11_rate_adapt_rateset(priv, - cmdptr, cmd_action); - break; - case CMD_802_11_MONITOR_MODE: ret = lbs_cmd_802_11_monitor_mode(cmdptr, cmd_action, pdata_buf); diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h index 00d290e..a53b51f 100644 --- a/drivers/net/wireless/libertas/cmd.h +++ b/drivers/net/wireless/libertas/cmd.h @@ -48,6 +48,8 @@ int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria); int lbs_suspend(struct lbs_private *priv); void lbs_resume(struct lbs_private *priv); +int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv, + uint16_t cmd_action); int lbs_cmd_802_11_inactivity_timeout(struct lbs_private *priv, uint16_t cmd_action, uint16_t *timeout); int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action, diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 4c3c5ec..24de3c3 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -203,22 +203,6 @@ static int lbs_ret_802_11_rf_tx_power(struct lbs_private *priv, return 0; } -static int lbs_ret_802_11_rate_adapt_rateset(struct lbs_private *priv, - struct cmd_ds_command *resp) -{ - struct cmd_ds_802_11_rate_adapt_rateset *rates = &resp->params.rateset; - - lbs_deb_enter(LBS_DEB_CMD); - - if (rates->action == CMD_ACT_GET) { - priv->enablehwauto = le16_to_cpu(rates->enablehwauto); - priv->ratebitmap = le16_to_cpu(rates->bitmap); - } - - lbs_deb_leave(LBS_DEB_CMD); - return 0; -} - static int lbs_ret_802_11_rssi(struct lbs_private *priv, struct cmd_ds_command *resp) { @@ -321,10 +305,6 @@ static inline int handle_cmd_response(struct lbs_private *priv, case CMD_RET(CMD_802_11_BEACON_STOP): break; - case CMD_RET(CMD_802_11_RATE_ADAPT_RATESET): - ret = lbs_ret_802_11_rate_adapt_rateset(priv, resp); - break; - case CMD_RET(CMD_802_11_RSSI): ret = lbs_ret_802_11_rssi(priv, resp); break; diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 0a9fc51..f5bb40c 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -237,8 +237,8 @@ struct lbs_private { /** 802.11 statistics */ // struct cmd_DS_802_11_GET_STAT wlan802_11Stat; - u16 enablehwauto; - u16 ratebitmap; + uint16_t enablehwauto; + uint16_t ratebitmap; u32 fragthsd; u32 rtsthsd; @@ -296,7 +296,6 @@ struct lbs_private { /** data rate stuff */ u8 cur_rate; - u8 auto_rate; /** RF calibration data */ diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index c36ab31..913b480 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -500,6 +500,7 @@ struct cmd_ds_802_11_data_rate { }; struct cmd_ds_802_11_rate_adapt_rateset { + struct cmd_header hdr; __le16 action; __le16 enablehwauto; __le16 bitmap; @@ -703,7 +704,6 @@ struct cmd_ds_command { struct cmd_ds_802_11_rf_tx_power txp; struct cmd_ds_802_11_rf_antenna rant; struct cmd_ds_802_11_monitor_mode monitor; - struct cmd_ds_802_11_rate_adapt_rateset rateset; struct cmd_ds_802_11_ad_hoc_join adj; struct cmd_ds_802_11_rssi rssi; struct cmd_ds_802_11_rssi_rsp rssirsp; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index faa4db1..039e09a 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1044,7 +1044,7 @@ static int lbs_init_adapter(struct lbs_private *priv) priv->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL; priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; priv->radioon = RADIO_ON; - priv->auto_rate = 1; + priv->enablehwauto = 1; priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE; priv->psmode = LBS802_11POWERMODECAM; priv->psstate = PS_STATE_FULL_POWER; diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c index 05af731..5749f22 100644 --- a/drivers/net/wireless/libertas/rx.c +++ b/drivers/net/wireless/libertas/rx.c @@ -237,7 +237,7 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb) /* Take the data rate from the rxpd structure * only if the rate is auto */ - if (priv->auto_rate) + if (priv->enablehwauto) priv->cur_rate = lbs_fw_index_to_data_rate(p_rx_pd->rx_rate); lbs_compute_rssi(priv, p_rx_pd); @@ -383,7 +383,7 @@ static int process_rxed_802_11_packet(struct lbs_private *priv, /* Take the data rate from the rxpd structure * only if the rate is auto */ - if (priv->auto_rate) + if (priv->enablehwauto) priv->cur_rate = lbs_fw_index_to_data_rate(prxpd->rx_rate); lbs_compute_rssi(priv, prxpd); diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index d4b19f1..8b3ed77 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -1021,29 +1021,38 @@ static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); lbs_deb_wext("vwrq->value %d\n", vwrq->value); + lbs_deb_wext("vwrq->fixed %d\n", vwrq->fixed); + + if (vwrq->fixed && vwrq->value == -1) + goto out; /* Auto rate? */ - if (vwrq->value == -1) { - priv->auto_rate = 1; + priv->enablehwauto = !vwrq->fixed; + + if (vwrq->value == -1) priv->cur_rate = 0; - } else { + else { if (vwrq->value % 100000) goto out; + new_rate = vwrq->value / 500000; + priv->cur_rate = new_rate; + /* the rest is only needed for lbs_set_data_rate() */ memset(rates, 0, sizeof(rates)); copy_active_data_rates(priv, rates); - new_rate = vwrq->value / 500000; if (!memchr(rates, new_rate, sizeof(rates))) { lbs_pr_alert("fixed data rate 0x%X out of range\n", new_rate); goto out; } - - priv->cur_rate = new_rate; - priv->auto_rate = 0; } - ret = lbs_set_data_rate(priv, new_rate); + /* Try the newer command first (Firmware Spec 5.1 and above) */ + ret = lbs_cmd_802_11_rate_adapt_rateset(priv, CMD_ACT_SET); + + /* Fallback to older version */ + if (ret) + ret = lbs_set_data_rate(priv, new_rate); out: lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); @@ -1060,7 +1069,7 @@ static int lbs_get_rate(struct net_device *dev, struct iw_request_info *info, if (priv->connect_status == LBS_CONNECTED) { vwrq->value = priv->cur_rate * 500000; - if (priv->auto_rate) + if (priv->enablehwauto) vwrq->fixed = 0; else vwrq->fixed = 1; -- cgit v0.10.2 From 43d01c563d271260c1e4fe0a9383c47fae96887f Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Mon, 26 May 2008 12:50:23 +0200 Subject: libertas: fix compact flash interrupt handling The old code misbehaved because it polled card status and always called the "tx over" code-path. This also fixes a hard lockup by not allowing and card interrupts while transferring a TX frame or a command into the card. Signed-off-by: Holger Schurig Acked-by: Dan Williams Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index 86bb126..5963d92 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -215,9 +215,21 @@ static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 r /********************************************************************/ -/* I/O */ +/* I/O and interrupt handling */ /********************************************************************/ +static inline void if_cs_enable_ints(struct if_cs_card *card) +{ + lbs_deb_enter(LBS_DEB_CS); + if_cs_write16(card, IF_CS_H_INT_MASK, 0); +} + +static inline void if_cs_disable_ints(struct if_cs_card *card) +{ + lbs_deb_enter(LBS_DEB_CS); + if_cs_write16(card, IF_CS_H_INT_MASK, IF_CS_H_IM_MASK); +} + /* * Called from if_cs_host_to_card to send a command to the hardware */ @@ -228,6 +240,7 @@ static int if_cs_send_cmd(struct lbs_private *priv, u8 *buf, u16 nb) int loops = 0; lbs_deb_enter(LBS_DEB_CS); + if_cs_disable_ints(card); /* Is hardware ready? */ while (1) { @@ -258,19 +271,24 @@ static int if_cs_send_cmd(struct lbs_private *priv, u8 *buf, u16 nb) ret = 0; done: + if_cs_enable_ints(card); lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret); return ret; } - /* * Called from if_cs_host_to_card to send a data to the hardware */ static void if_cs_send_data(struct lbs_private *priv, u8 *buf, u16 nb) { struct if_cs_card *card = (struct if_cs_card *)priv->card; + u16 status; lbs_deb_enter(LBS_DEB_CS); + if_cs_disable_ints(card); + + status = if_cs_read16(card, IF_CS_C_STATUS); + BUG_ON((status & IF_CS_C_S_TX_DNLD_RDY) == 0); if_cs_write16(card, IF_CS_H_WRITE_LEN, nb); @@ -281,11 +299,11 @@ static void if_cs_send_data(struct lbs_private *priv, u8 *buf, u16 nb) if_cs_write16(card, IF_CS_H_STATUS, IF_CS_H_STATUS_TX_OVER); if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_STATUS_TX_OVER); + if_cs_enable_ints(card); lbs_deb_leave(LBS_DEB_CS); } - /* * Get the command result out of the card. */ @@ -330,7 +348,6 @@ out: return ret; } - static struct sk_buff *if_cs_receive_data(struct lbs_private *priv) { struct sk_buff *skb = NULL; @@ -367,25 +384,6 @@ out: return skb; } - - -/********************************************************************/ -/* Interrupts */ -/********************************************************************/ - -static inline void if_cs_enable_ints(struct if_cs_card *card) -{ - lbs_deb_enter(LBS_DEB_CS); - if_cs_write16(card, IF_CS_H_INT_MASK, 0); -} - -static inline void if_cs_disable_ints(struct if_cs_card *card) -{ - lbs_deb_enter(LBS_DEB_CS); - if_cs_write16(card, IF_CS_H_INT_MASK, IF_CS_H_IM_MASK); -} - - static irqreturn_t if_cs_interrupt(int irq, void *data) { struct if_cs_card *card = data; @@ -394,10 +392,8 @@ static irqreturn_t if_cs_interrupt(int irq, void *data) lbs_deb_enter(LBS_DEB_CS); + /* Ask card interrupt cause register if there is something for us */ cause = if_cs_read16(card, IF_CS_C_INT_CAUSE); - if_cs_write16(card, IF_CS_C_INT_CAUSE, cause & IF_CS_C_IC_MASK); - - lbs_deb_cs("cause 0x%04x\n", cause); if (cause == 0) { /* Not for us */ return IRQ_NONE; @@ -409,9 +405,9 @@ static irqreturn_t if_cs_interrupt(int irq, void *data) return IRQ_HANDLED; } - /* TODO: I'm not sure what the best ordering is */ - - cause = if_cs_read16(card, IF_CS_C_STATUS) & IF_CS_C_S_MASK; + /* Clear interrupt cause */ + if_cs_write16(card, IF_CS_C_INT_CAUSE, cause & IF_CS_C_IC_MASK); + lbs_deb_cs("cause 0x%04x\n", cause); if (cause & IF_CS_C_S_RX_UPLD_RDY) { struct sk_buff *skb; @@ -422,7 +418,7 @@ static irqreturn_t if_cs_interrupt(int irq, void *data) } if (cause & IF_CS_H_IC_TX_OVER) { - lbs_deb_cs("tx over\n"); + lbs_deb_cs("tx done\n"); lbs_host_to_card_done(priv); } @@ -430,7 +426,7 @@ static irqreturn_t if_cs_interrupt(int irq, void *data) unsigned long flags; u8 i; - lbs_deb_cs("cmd upload ready\n"); + lbs_deb_cs("cmd resp\n"); spin_lock_irqsave(&priv->driver_lock, flags); i = (priv->resp_idx == 0) ? 1 : 0; spin_unlock_irqrestore(&priv->driver_lock, flags); @@ -449,10 +445,11 @@ static irqreturn_t if_cs_interrupt(int irq, void *data) & IF_CS_C_S_STATUS_MASK; if_cs_write16(priv->card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_HOST_EVENT); - lbs_deb_cs("eventcause 0x%04x\n", event); + lbs_deb_cs("host event 0x%04x\n", event); lbs_queue_event(priv, event >> 8 & 0xff); } + lbs_deb_leave(LBS_DEB_CS); return IRQ_HANDLED; } -- cgit v0.10.2 From e623157b8d778a63736b0f41c04acc57c4f61ae0 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 27 May 2008 20:00:11 +0300 Subject: mac80211: sends HT IE to user level through wext This patch adds HT IE in the scan list that is returned to user level through wext. This is useful to let wpa_supplicant if a bss supports 11n or not: WEP and TKIP are not supported in 11n. Signed-off-by: Emmanuel Grumbach Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 9a26437..6faa700 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -4128,6 +4128,14 @@ ieee80211_sta_scan_result(struct net_device *dev, bss->rsn_ie); } + if (bss && bss->ht_ie) { + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVGENIE; + iwe.u.data.length = bss->ht_ie_len; + current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, + bss->ht_ie); + } + if (bss && bss->supp_rates_len > 0) { /* display all supported rates in readable format */ char *p = current_ev + IW_EV_LCP_LEN; -- cgit v0.10.2 From ede0cba45f2caf47715d105f6acc1086f4112a7a Mon Sep 17 00:00:00 2001 From: Ester Kummer Date: Thu, 29 May 2008 16:34:46 +0800 Subject: iwlwifi: move iwl_dump_nic_error_log to iwlcore module This patch moves the function iwl_dump_nic_error_log to iwlcore. Remove sysfs entry it cannot be really triggered. Signed-off-by: Ester Kummer Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 7e25ca4..785396f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1056,6 +1056,78 @@ int iwl_verify_ucode(struct iwl_priv *priv) EXPORT_SYMBOL(iwl_verify_ucode); +static const char *desc_lookup(int i) +{ + switch (i) { + case 1: + return "FAIL"; + case 2: + return "BAD_PARAM"; + case 3: + return "BAD_CHECKSUM"; + case 4: + return "NMI_INTERRUPT"; + case 5: + return "SYSASSERT"; + case 6: + return "FATAL_ERROR"; + } + + return "UNKNOWN"; +} + +#define ERROR_START_OFFSET (1 * sizeof(u32)) +#define ERROR_ELEM_SIZE (7 * sizeof(u32)) + +void iwl_dump_nic_error_log(struct iwl_priv *priv) +{ + u32 data2, line; + u32 desc, time, count, base, data1; + u32 blink1, blink2, ilink1, ilink2; + int rc; + + base = le32_to_cpu(priv->card_alive.error_event_table_ptr); + + if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { + IWL_ERROR("Not valid error log pointer 0x%08X\n", base); + return; + } + + rc = iwl_grab_nic_access(priv); + if (rc) { + IWL_WARNING("Can not read from adapter at this time.\n"); + return; + } + + count = iwl_read_targ_mem(priv, base); + + if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) { + IWL_ERROR("Start IWL Error Log Dump:\n"); + IWL_ERROR("Status: 0x%08lX, count: %d\n", priv->status, count); + } + + desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32)); + blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32)); + blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32)); + ilink1 = iwl_read_targ_mem(priv, base + 5 * sizeof(u32)); + ilink2 = iwl_read_targ_mem(priv, base + 6 * sizeof(u32)); + data1 = iwl_read_targ_mem(priv, base + 7 * sizeof(u32)); + data2 = iwl_read_targ_mem(priv, base + 8 * sizeof(u32)); + line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32)); + time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32)); + + IWL_ERROR("Desc Time " + "data1 data2 line\n"); + IWL_ERROR("%-13s (#%d) %010u 0x%08X 0x%08X %u\n", + desc_lookup(desc), desc, time, data1, data2, line); + IWL_ERROR("blink1 blink2 ilink1 ilink2\n"); + IWL_ERROR("0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2, + ilink1, ilink2); + + iwl_release_nic_access(priv); +} +EXPORT_SYMBOL(iwl_dump_nic_error_log); + #define EVENT_START_OFFSET (4 * sizeof(u32)) /** diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index ad7422e..9392fcf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -237,6 +237,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd); ******************************************************/ void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, u32 num_events, u32 mode); +void iwl_dump_nic_error_log(struct iwl_priv *priv); void iwl_dump_nic_event_log(struct iwl_priv *priv); /*************** DRIVER STATUS FUNCTIONS *****/ diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 07c52b6..e9dfb72 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -2613,76 +2613,6 @@ static inline void iwl4965_disable_interrupts(struct iwl_priv *priv) IWL_DEBUG_ISR("Disabled interrupts\n"); } -static const char *desc_lookup(int i) -{ - switch (i) { - case 1: - return "FAIL"; - case 2: - return "BAD_PARAM"; - case 3: - return "BAD_CHECKSUM"; - case 4: - return "NMI_INTERRUPT"; - case 5: - return "SYSASSERT"; - case 6: - return "FATAL_ERROR"; - } - - return "UNKNOWN"; -} - -#define ERROR_START_OFFSET (1 * sizeof(u32)) -#define ERROR_ELEM_SIZE (7 * sizeof(u32)) - -static void iwl4965_dump_nic_error_log(struct iwl_priv *priv) -{ - u32 data2, line; - u32 desc, time, count, base, data1; - u32 blink1, blink2, ilink1, ilink2; - int rc; - - base = le32_to_cpu(priv->card_alive.error_event_table_ptr); - - if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { - IWL_ERROR("Not valid error log pointer 0x%08X\n", base); - return; - } - - rc = iwl_grab_nic_access(priv); - if (rc) { - IWL_WARNING("Can not read from adapter at this time.\n"); - return; - } - - count = iwl_read_targ_mem(priv, base); - - if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) { - IWL_ERROR("Start IWL Error Log Dump:\n"); - IWL_ERROR("Status: 0x%08lX, count: %d\n", priv->status, count); - } - - desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32)); - blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32)); - blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32)); - ilink1 = iwl_read_targ_mem(priv, base + 5 * sizeof(u32)); - ilink2 = iwl_read_targ_mem(priv, base + 6 * sizeof(u32)); - data1 = iwl_read_targ_mem(priv, base + 7 * sizeof(u32)); - data2 = iwl_read_targ_mem(priv, base + 8 * sizeof(u32)); - line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32)); - time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32)); - - IWL_ERROR("Desc Time " - "data1 data2 line\n"); - IWL_ERROR("%-13s (#%d) %010u 0x%08X 0x%08X %u\n", - desc_lookup(desc), desc, time, data1, data2, line); - IWL_ERROR("blink1 blink2 ilink1 ilink2\n"); - IWL_ERROR("0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2, - ilink1, ilink2); - - iwl_release_nic_access(priv); -} /** * iwl4965_irq_handle_error - called for HW or SW error interrupt from card @@ -2697,7 +2627,7 @@ static void iwl4965_irq_handle_error(struct iwl_priv *priv) #ifdef CONFIG_IWLWIFI_DEBUG if (priv->debug_level & IWL_DL_FW_ERRORS) { - iwl4965_dump_nic_error_log(priv); + iwl_dump_nic_error_log(priv); iwl_dump_nic_event_log(priv); iwl4965_print_rx_config_cmd(priv); } @@ -5519,20 +5449,6 @@ static ssize_t show_status(struct device *d, static DEVICE_ATTR(status, S_IRUGO, show_status, NULL); -static ssize_t dump_error_log(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - char *p = (char *)buf; - - if (p[0] == '1') - iwl4965_dump_nic_error_log((struct iwl_priv *)d->driver_data); - - return strnlen(buf, count); -} - -static DEVICE_ATTR(dump_errors, S_IWUSR, NULL, dump_error_log); - /***************************************************************************** * * driver setup and teardown @@ -5578,7 +5494,6 @@ static void iwl4965_cancel_deferred_work(struct iwl_priv *priv) static struct attribute *iwl4965_sysfs_entries[] = { &dev_attr_channels.attr, - &dev_attr_dump_errors.attr, &dev_attr_flags.attr, &dev_attr_filter_flags.attr, #ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT -- cgit v0.10.2 From 87283cc1290f23458232cdf3b1893acb750a4ad3 Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Thu, 29 May 2008 16:34:47 +0800 Subject: iwlwifi: add RTC data address for iwl5000 This patch fills the valid_rtc_data_addr handler in iwl5000. Signed-off-by: Ron Rindjunsky Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 520c7ea..d6ffdee 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -768,6 +768,12 @@ static void iwl5000_rx_handler_setup(struct iwl_priv *priv) { } +static int iwl5000_hw_valid_rtc_data_addr(u32 addr) +{ + return (addr >= RTC_DATA_LOWER_BOUND) && + (addr < IWL50_RTC_DATA_UPPER_BOUND); +} + static struct iwl_hcmd_ops iwl5000_hcmd = { }; @@ -788,6 +794,7 @@ static struct iwl_lib_ops iwl5000_lib = { .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, .disable_tx_fifo = iwl5000_disable_tx_fifo, .rx_handler_setup = iwl5000_rx_handler_setup, + .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr, .load_ucode = iwl5000_load_ucode, .init_alive_start = iwl5000_init_alive_start, .alive_notify = iwl5000_alive_notify, -- cgit v0.10.2 From e1dfc0851ae0fb280a5eb827dd08853ed46cb241 Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Thu, 29 May 2008 16:34:48 +0800 Subject: iwlwifi: use uCode error and event tables pointer w.r.t loaded image This patch updates the usage of the pointers to error and log tables received in alive response w.r.t. the current uCode image. Signed-off-by: Gregory Greenman Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 785396f..373e984 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1084,17 +1084,20 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) u32 data2, line; u32 desc, time, count, base, data1; u32 blink1, blink2, ilink1, ilink2; - int rc; + int ret; - base = le32_to_cpu(priv->card_alive.error_event_table_ptr); + if (priv->ucode_type == UCODE_INIT) + base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr); + else + base = le32_to_cpu(priv->card_alive.error_event_table_ptr); if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { IWL_ERROR("Not valid error log pointer 0x%08X\n", base); return; } - rc = iwl_grab_nic_access(priv); - if (rc) { + ret = iwl_grab_nic_access(priv); + if (ret) { IWL_WARNING("Can not read from adapter at this time.\n"); return; } @@ -1146,8 +1149,10 @@ void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, if (num_events == 0) return; - - base = le32_to_cpu(priv->card_alive.log_event_table_ptr); + if (priv->ucode_type == UCODE_INIT) + base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); + else + base = le32_to_cpu(priv->card_alive.log_event_table_ptr); if (mode == 0) event_size = 2 * sizeof(u32); @@ -1177,7 +1182,7 @@ EXPORT_SYMBOL(iwl_print_event_log); void iwl_dump_nic_event_log(struct iwl_priv *priv) { - int rc; + int ret; u32 base; /* SRAM byte address of event log header */ u32 capacity; /* event log capacity in # entries */ u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */ @@ -1185,14 +1190,18 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv) u32 next_entry; /* index of next entry to be written by uCode */ u32 size; /* # entries that we'll print */ - base = le32_to_cpu(priv->card_alive.log_event_table_ptr); + if (priv->ucode_type == UCODE_INIT) + base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); + else + base = le32_to_cpu(priv->card_alive.log_event_table_ptr); + if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { IWL_ERROR("Invalid event log pointer 0x%08X\n", base); return; } - rc = iwl_grab_nic_access(priv); - if (rc) { + ret = iwl_grab_nic_access(priv); + if (ret) { IWL_WARNING("Can not read from adapter at this time.\n"); return; } -- cgit v0.10.2 From bd68fb6f010eb312ba20349311aceb89848ad5ff Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Thu, 29 May 2008 16:34:49 +0800 Subject: iwlwifi: increase max payload of iwl_cmd This patch increases iwl_cmd payload maximum size from 360 to 640 to fit some of iwl5000 commands as well. Signed-off-by: Ron Rindjunsky Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index f7fd8ea..1ee8121 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -307,6 +307,8 @@ struct iwl_cmd_meta { } __attribute__ ((packed)); +#define IWL_CMD_MAX_PAYLOAD 640 + /** * struct iwl_cmd * @@ -332,7 +334,7 @@ struct iwl_cmd { struct iwl4965_tx_beacon_cmd tx_beacon; struct iwl4965_rxon_assoc_cmd rxon_assoc; u8 *indirect; - u8 payload[360]; + u8 payload[IWL_CMD_MAX_PAYLOAD]; } __attribute__ ((packed)) cmd; } __attribute__ ((packed)); -- cgit v0.10.2 From 95b1a8224abf6230899856753c5506a3f737a65b Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 29 May 2008 16:34:50 +0800 Subject: iwlwifi: create drivers debugfs dir under wiphy->debugfsdir This patch creates driver's debugfs tree under wiphy->debugfsdir. This patch fixes collision in debugfs if two or more NICs are plugged. Signed-off-by: Zhu Yi Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index c64e602..29e16ba 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -367,6 +367,7 @@ DEBUGFS_READ_FILE_OPS(tx_statistics); int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) { struct iwl_debugfs *dbgfs; + struct dentry *phyd = priv->hw->wiphy->debugfsdir; dbgfs = kzalloc(sizeof(struct iwl_debugfs), GFP_KERNEL); if (!dbgfs) { @@ -375,7 +376,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) priv->dbgfs = dbgfs; dbgfs->name = name; - dbgfs->dir_drv = debugfs_create_dir(name, NULL); + dbgfs->dir_drv = debugfs_create_dir(name, phyd); if (!dbgfs->dir_drv || IS_ERR(dbgfs->dir_drv)){ goto err; } -- cgit v0.10.2 From 2d87889f61e97194891f7e7ff3a0e5f11e4392db Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 29 May 2008 16:34:51 +0800 Subject: iwlwifi: mark 4965 ucode types This patch marks 4965 ucode types. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index ca9ca92..063ba2e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -162,9 +162,10 @@ static int iwl4965_load_bsm(struct iwl_priv *priv) /* Tell bootstrap uCode where to find the "Initialize" uCode * in host DRAM ... host DRAM physical address bits 35:4 for 4965. - * NOTE: iwl4965_initialize_alive_start() will replace these values, + * NOTE: iwl_init_alive_start() will replace these values, * after the "initialize" uCode has run, to point to - * runtime/protocol instructions and backup data cache. */ + * runtime/protocol instructions and backup data cache. + */ pinst = priv->ucode_init.p_addr >> 4; pdata = priv->ucode_init_data.p_addr >> 4; inst_len = priv->ucode_init.len; @@ -220,6 +221,8 @@ static int iwl4965_load_bsm(struct iwl_priv *priv) iwl_release_nic_access(priv); + priv->ucode_type = UCODE_INIT; + return 0; } @@ -266,6 +269,8 @@ static int iwl4965_set_ucode_ptrs(struct iwl_priv *priv) IWL_DEBUG_INFO("Runtime uCode pointers are set.\n"); + priv->ucode_type = UCODE_RT; + return ret; } -- cgit v0.10.2 From c317fee3c1a01a0dbf505ed46236e93c55e279fa Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 29 May 2008 16:34:52 +0800 Subject: iwlwifi: remove unused variable form __iwl4965_down This patch removes unused variable from __iwl4965_down. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index e9dfb72..d7f9321 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -3341,12 +3341,9 @@ static void __iwl4965_down(struct iwl_priv *priv) { unsigned long flags; int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status); - struct ieee80211_conf *conf = NULL; IWL_DEBUG_INFO(DRV_NAME " is going down\n"); - conf = ieee80211_get_hw_conf(priv->hw); - if (!exit_pending) set_bit(STATUS_EXIT_PENDING, &priv->status); -- cgit v0.10.2 From 84df9d3130118146c9aedf5146040f9f6495f471 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 29 May 2008 16:34:53 +0800 Subject: iwlwifi: remove notif_missed_beacons variable This patch removes notif_missed_beacons from priv since it was never used. Missed beacons notification will have only meaning if roaming will be implemented in mac80211. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index 835c5b4..a9b3eda 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -835,8 +835,6 @@ struct iwl3945_priv { u8 mac80211_registered; - u32 notif_missed_beacons; - /* Rx'd packet timing information */ u32 last_beacon_time; u64 last_tsf; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 1ee8121..342c6a5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1125,8 +1125,6 @@ struct iwl_priv { u8 mac80211_registered; - u32 notif_missed_beacons; - /* Rx'd packet timing information */ u32 last_beacon_time; u64 last_tsf; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index e0f52e2..244bfe5 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -5847,9 +5847,6 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv) /* Configure the adapter for unassociated operation */ iwl3945_commit_rxon(priv); - /* At this point, the NIC is initialized and operational */ - priv->notif_missed_beacons = 0; - iwl3945_reg_txpower_periodic(priv); iwl3945_led_register(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index d7f9321..6785200 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -3314,8 +3314,6 @@ static void iwl4965_alive_start(struct iwl_priv *priv) iwl4965_commit_rxon(priv); /* At this point, the NIC is initialized and operational */ - priv->notif_missed_beacons = 0; - iwl4965_rf_kill_ct_config(priv); iwl_leds_register(priv); -- cgit v0.10.2 From 4a4a9e81aed702421ef3e782f82d4e929fb81796 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 29 May 2008 16:34:54 +0800 Subject: iwlwifi: clean up alive_start routine This patch cleans up alive_start routine. It removes 4965 from the common code and moves the run time calibration reset into a common code. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 063ba2e..d548bda 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -921,15 +921,6 @@ int iwl4965_alive_notify(struct iwl_priv *priv) spin_lock_irqsave(&priv->lock, flags); -#ifdef CONFIG_IWL4965_RUN_TIME_CALIB - memset(&(priv->sensitivity_data), 0, - sizeof(struct iwl_sensitivity_data)); - memset(&(priv->chain_noise_data), 0, - sizeof(struct iwl_chain_noise_data)); - for (i = 0; i < NUM_RX_CHAINS; i++) - priv->chain_noise_data.delta_gain_code[i] = - CHAIN_NOISE_DELTA_GAIN_INIT_VAL; -#endif /* CONFIG_IWL4965_RUN_TIME_CALIB*/ ret = iwl_grab_nic_access(priv); if (ret) { spin_unlock_irqrestore(&priv->lock, flags); @@ -996,9 +987,6 @@ int iwl4965_alive_notify(struct iwl_priv *priv) iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); - /* Ask for statistics now, the uCode will send statistics notification - * periodically after association */ - iwl_send_statistics_request(priv, CMD_ASYNC); return ret; } diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index d6ffdee..0355ccd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -580,10 +580,6 @@ static int iwl5000_alive_notify(struct iwl_priv *priv) iwl5000_send_wimax_coex(priv); - /* Ask for statistics now, the uCode will send notification - * periodically after association */ - iwl_send_statistics_request(priv, CMD_ASYNC); - return 0; } diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c index beb9716..a6c7f0d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c @@ -786,3 +786,21 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, } EXPORT_SYMBOL(iwl_chain_noise_calibration); + +void iwl_reset_run_time_calib(struct iwl_priv *priv) +{ + int i; + memset(&(priv->sensitivity_data), 0, + sizeof(struct iwl_sensitivity_data)); + memset(&(priv->chain_noise_data), 0, + sizeof(struct iwl_chain_noise_data)); + for (i = 0; i < NUM_RX_CHAINS; i++) + priv->chain_noise_data.delta_gain_code[i] = + CHAIN_NOISE_DELTA_GAIN_INIT_VAL; + + /* Ask for statistics now, the uCode will send notification + * periodically after association */ + iwl_send_statistics_request(priv, CMD_ASYNC); +} +EXPORT_SYMBOL(iwl_reset_run_time_calib); + diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.h b/drivers/net/wireless/iwlwifi/iwl-calib.h index e690668..b8e57c5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.h +++ b/drivers/net/wireless/iwlwifi/iwl-calib.h @@ -78,7 +78,7 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv, struct iwl4965_notif_statistics *resp); void iwl_init_sensitivity(struct iwl_priv *priv); - +void iwl_reset_run_time_calib(struct iwl_priv *priv); static inline void iwl_chain_noise_reset(struct iwl_priv *priv) { @@ -101,6 +101,9 @@ static inline void iwl_init_sensitivity(struct iwl_priv *priv) static inline void iwl_chain_noise_reset(struct iwl_priv *priv) { } +static inline void iwl_reset_run_time_calib(struct iwl_priv *priv) +{ +} #endif #endif /* __iwl_calib_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 6785200..5a5306d 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -3244,11 +3244,11 @@ static int iwl4965_read_ucode(struct iwl_priv *priv) } /** - * iwl4965_alive_start - called after REPLY_ALIVE notification received + * iwl_alive_start - called after REPLY_ALIVE notification received * from protocol/runtime uCode (initialization uCode's - * Alive gets handled by iwl4965_init_alive_start()). + * Alive gets handled by iwl_init_alive_start()). */ -static void iwl4965_alive_start(struct iwl_priv *priv) +static void iwl_alive_start(struct iwl_priv *priv) { int ret = 0; @@ -3272,7 +3272,6 @@ static void iwl4965_alive_start(struct iwl_priv *priv) } iwlcore_clear_stations_table(priv); - ret = priv->cfg->ops->lib->alive_notify(priv); if (ret) { IWL_WARNING("Could not complete ALIVE transition [ntf]: %d\n", @@ -3310,6 +3309,8 @@ static void iwl4965_alive_start(struct iwl_priv *priv) /* Configure Bluetooth device coexistence support */ iwl4965_send_bt_config(priv); + iwl_reset_run_time_calib(priv); + /* Configure the adapter for unassociated operation */ iwl4965_commit_rxon(priv); @@ -3554,7 +3555,7 @@ static int __iwl4965_up(struct iwl_priv *priv) * *****************************************************************************/ -static void iwl4965_bg_init_alive_start(struct work_struct *data) +static void iwl_bg_init_alive_start(struct work_struct *data) { struct iwl_priv *priv = container_of(data, struct iwl_priv, init_alive_start.work); @@ -3567,7 +3568,7 @@ static void iwl4965_bg_init_alive_start(struct work_struct *data) mutex_unlock(&priv->mutex); } -static void iwl4965_bg_alive_start(struct work_struct *data) +static void iwl_bg_alive_start(struct work_struct *data) { struct iwl_priv *priv = container_of(data, struct iwl_priv, alive_start.work); @@ -3576,7 +3577,7 @@ static void iwl4965_bg_alive_start(struct work_struct *data) return; mutex_lock(&priv->mutex); - iwl4965_alive_start(priv); + iwl_alive_start(priv); mutex_unlock(&priv->mutex); } @@ -5466,8 +5467,8 @@ static void iwl4965_setup_deferred_work(struct iwl_priv *priv) INIT_WORK(&priv->beacon_update, iwl4965_bg_beacon_update); INIT_WORK(&priv->set_monitor, iwl4965_bg_set_monitor); INIT_DELAYED_WORK(&priv->post_associate, iwl4965_bg_post_associate); - INIT_DELAYED_WORK(&priv->init_alive_start, iwl4965_bg_init_alive_start); - INIT_DELAYED_WORK(&priv->alive_start, iwl4965_bg_alive_start); + INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start); + INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start); INIT_DELAYED_WORK(&priv->scan_check, iwl4965_bg_scan_check); iwl4965_hw_setup_deferred_work(priv); -- cgit v0.10.2 From 885ba202cabd90b8ade1fe59185dc96ed4d69e02 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 29 May 2008 16:34:55 +0800 Subject: iwlwifi: remove 4965 from alive_resp structures This patch removes 4965 from alive_resp and init_alivie_resp. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 5b9e9bf..afd0f7d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -373,7 +373,7 @@ struct iwl4965_tx_power_db { * 3) Tx gain compensation to balance 4965's 2 Tx chains for MIMO operation, * for each of 5 frequency ranges. */ -struct iwl4965_init_alive_resp { +struct iwl_init_alive_resp { u8 ucode_minor; u8 ucode_major; __le16 reserved1; @@ -449,7 +449,7 @@ struct iwl4965_init_alive_resp { * The Linux driver can print both logs to the system log when a uCode error * occurs. */ -struct iwl4965_alive_resp { +struct iwl_alive_resp { u8 ucode_minor; u8 ucode_major; __le16 reserved1; @@ -473,7 +473,7 @@ union tsf { /* * REPLY_ERROR = 0x2 (response only, not a command) */ -struct iwl4965_error_resp { +struct iwl_error_resp { __le32 error_type; u8 cmd_id; u8 reserved1; @@ -2861,12 +2861,12 @@ struct iwl_rx_packet { __le32 len; struct iwl_cmd_header hdr; union { - struct iwl4965_alive_resp alive_frame; + struct iwl_alive_resp alive_frame; struct iwl4965_rx_frame rx_frame; struct iwl4965_tx_resp tx_resp; struct iwl4965_spectrum_notification spectrum_notif; struct iwl4965_csa_notification csa_notif; - struct iwl4965_error_resp err_resp; + struct iwl_error_resp err_resp; struct iwl4965_card_state_notif card_state_notif; struct iwl4965_beacon_notif beacon_status; struct iwl4965_add_sta_resp add_sta; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 342c6a5..da4d606 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1035,8 +1035,8 @@ struct iwl_priv { /* 1st responses from initialize and runtime uCode images. * 4965's initialize alive response contains some calibration data. */ - struct iwl4965_init_alive_resp card_alive_init; - struct iwl4965_alive_resp card_alive; + struct iwl_init_alive_resp card_alive_init; + struct iwl_alive_resp card_alive; #ifdef CONFIG_IWLWIFI_RFKILL struct iwl_rfkill_mngr rfkill_mngr; #endif diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 5a5306d..ee9fe56 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -1927,11 +1927,11 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, } -static void iwl4965_rx_reply_alive(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static void iwl_rx_reply_alive(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) { struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - struct iwl4965_alive_resp *palive; + struct iwl_alive_resp *palive; struct delayed_work *pwork; palive = &pkt->u.alive_frame; @@ -1945,12 +1945,12 @@ static void iwl4965_rx_reply_alive(struct iwl_priv *priv, IWL_DEBUG_INFO("Initialization Alive received.\n"); memcpy(&priv->card_alive_init, &pkt->u.alive_frame, - sizeof(struct iwl4965_init_alive_resp)); + sizeof(struct iwl_init_alive_resp)); pwork = &priv->init_alive_start; } else { IWL_DEBUG_INFO("Runtime Alive received.\n"); memcpy(&priv->card_alive, &pkt->u.alive_frame, - sizeof(struct iwl4965_alive_resp)); + sizeof(struct iwl_alive_resp)); pwork = &priv->alive_start; } @@ -2279,7 +2279,7 @@ static void iwl4965_rx_card_state_notif(struct iwl_priv *priv, */ static void iwl4965_setup_rx_handlers(struct iwl_priv *priv) { - priv->rx_handlers[REPLY_ALIVE] = iwl4965_rx_reply_alive; + priv->rx_handlers[REPLY_ALIVE] = iwl_rx_reply_alive; priv->rx_handlers[REPLY_ADD_STA] = iwl4965_rx_reply_add_sta; priv->rx_handlers[REPLY_ERROR] = iwl4965_rx_reply_error; priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl4965_rx_csa; @@ -3423,7 +3423,7 @@ static void __iwl4965_down(struct iwl_priv *priv) priv->cfg->ops->lib->free_shared_mem(priv); exit: - memset(&priv->card_alive, 0, sizeof(struct iwl4965_alive_resp)); + memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp)); if (priv->ibss_beacon) dev_kfree_skb(priv->ibss_beacon); @@ -5075,7 +5075,7 @@ static ssize_t show_version(struct device *d, struct device_attribute *attr, char *buf) { struct iwl_priv *priv = d->driver_data; - struct iwl4965_alive_resp *palive = &priv->card_alive; + struct iwl_alive_resp *palive = &priv->card_alive; if (palive->is_valid) return sprintf(buf, "fw version: 0x%01X.0x%01X.0x%01X.0x%01X\n" -- cgit v0.10.2 From 8f0618914e02c62c5cf2482f8acc7eb8e9afb816 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 29 May 2008 16:34:56 +0800 Subject: iwlwifi: setup correctly L1 L0S pi link values This patch setups L1 L0S pci link values. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h index ee55b28..fc11833 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h @@ -100,9 +100,14 @@ #include "iwl-commands.h" -#define PCI_LINK_CTRL 0x0F0 +/* PCI registers */ +#define PCI_LINK_CTRL 0x0F0 /* 1 byte */ #define PCI_POWER_SOURCE 0x0C8 #define PCI_REG_WUM8 0x0E8 + +/* PCI register values */ +#define PCI_LINK_VAL_L0S_EN 0x01 +#define PCI_LINK_VAL_L1_EN 0x02 #define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT (0x80000000) #define TFD_QUEUE_SIZE_MAX (256) diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index d548bda..bf0bd4a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -496,6 +496,10 @@ static int iwl4965_apm_init(struct iwl_priv *priv) iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); + /* disable L0s without affecting L1 :don't wait for ICH L0s bug W/A) */ + iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, + CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX); + /* set "initialization complete" bit to move adapter * D0U* --> D0A* state */ iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); @@ -514,11 +518,12 @@ static int iwl4965_apm_init(struct iwl_priv *priv) goto out; /* enable DMA */ - iwl_write_prph(priv, APMG_CLK_CTRL_REG, - APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT); + iwl_write_prph(priv, APMG_CLK_CTRL_REG, APMG_CLK_VAL_DMA_CLK_RQT | + APMG_CLK_VAL_BSM_CLK_RQT); udelay(20); + /* disable L1-Active */ iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, APMG_PCIDEV_STT_VAL_L1_ACT_DIS); @@ -546,8 +551,13 @@ static void iwl4965_nic_config(struct iwl_priv *priv) pci_read_config_byte(priv->pci_dev, PCI_LINK_CTRL, &val_link); - /* disable L1 entry -- workaround for pre-B1 */ - pci_write_config_byte(priv->pci_dev, PCI_LINK_CTRL, val_link & ~0x02); + /* L1 is enabled by BIOS */ + if ((val_link & PCI_LINK_VAL_L1_EN) == PCI_LINK_VAL_L1_EN) + /* diable L0S disabled L1A enabled */ + iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED); + else + /* L0S enabled L1A disabled */ + iwl_clear_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED); radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG); diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 0355ccd..b1c5045 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -63,6 +63,10 @@ static int iwl5000_apm_init(struct iwl_priv *priv) iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); + /* disable L0s without affecting L1 :don't wait for ICH L0s bug W/A) */ + iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, + CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX); + iwl_set_bit(priv, CSR_ANA_PLL_CFG, CSR50_ANA_PLL_CFG_VAL); /* set "initialization complete" bit to move adapter @@ -83,13 +87,13 @@ static int iwl5000_apm_init(struct iwl_priv *priv) return ret; /* enable DMA */ - iwl_write_prph(priv, APMG_CLK_EN_REG, - APMG_CLK_VAL_DMA_CLK_RQT); + iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT); udelay(20); + /* disable L1-Active */ iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, - APMG_PCIDEV_STT_VAL_L1_ACT_DIS); + APMG_PCIDEV_STT_VAL_L1_ACT_DIS); iwl_release_nic_access(priv); @@ -106,8 +110,13 @@ static void iwl5000_nic_config(struct iwl_priv *priv) pci_read_config_byte(priv->pci_dev, PCI_LINK_CTRL, &val_link); - /* disable L1 entry -- workaround for pre-B1 */ - pci_write_config_byte(priv->pci_dev, PCI_LINK_CTRL, val_link & ~0x02); + /* L1 is enabled by BIOS */ + if ((val_link & PCI_LINK_VAL_L1_EN) == PCI_LINK_VAL_L1_EN) + /* diable L0S disabled L1A enabled */ + iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED); + else + /* L0S enabled L1A disabled */ + iwl_clear_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED); radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG); diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index 9d6e5d2..545ed69 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -87,13 +87,14 @@ /* EEPROM reads */ #define CSR_EEPROM_REG (CSR_BASE+0x02c) #define CSR_EEPROM_GP (CSR_BASE+0x030) +#define CSR_GIO_REG (CSR_BASE+0x03C) #define CSR_GP_UCODE (CSR_BASE+0x044) #define CSR_UCODE_DRV_GP1 (CSR_BASE+0x054) #define CSR_UCODE_DRV_GP1_SET (CSR_BASE+0x058) #define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c) #define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060) -#define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100) #define CSR_LED_REG (CSR_BASE+0x094) +#define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100) /* Analog phase-lock-loop configuration */ #define CSR_ANA_PLL_CFG (CSR_BASE+0x20c) @@ -213,6 +214,9 @@ #define CSR_EEPROM_GP_BAD_SIGNATURE (0x00000000) #define CSR_EEPROM_GP_IF_OWNER_MSK (0x00000180) +/* CSR GIO */ +#define CSR_GIO_REG_VAL_L0S_ENABLED (0x00000002) + /* UCODE DRV GP */ #define CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP (0x00000001) #define CSR_UCODE_SW_BIT_RFKILL (0x00000002) -- cgit v0.10.2 From 7f066108d15d06ec3534434333f0274c868fe798 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 29 May 2008 16:34:57 +0800 Subject: iwlwifi: implement apm reset flow This patch implements apm reset flow for 4965 and 5000. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index bf0bd4a..646c589 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -642,9 +642,9 @@ void iwl4965_hw_txq_ctx_stop(struct iwl_priv *priv) iwl_hw_txq_ctx_free(priv); } -int iwl4965_hw_nic_reset(struct iwl_priv *priv) +static int iwl4965_apm_reset(struct iwl_priv *priv) { - int rc = 0; + int ret = 0; unsigned long flags; iwl4965_hw_nic_stop_master(priv); @@ -655,33 +655,40 @@ int iwl4965_hw_nic_reset(struct iwl_priv *priv) udelay(10); + /* FIXME: put here L1A -L0S w/a */ + iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - rc = iwl_poll_bit(priv, CSR_RESET, + ret = iwl_poll_bit(priv, CSR_RESET, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25); + if (ret) + goto out; + udelay(10); - rc = iwl_grab_nic_access(priv); - if (!rc) { - iwl_write_prph(priv, APMG_CLK_EN_REG, - APMG_CLK_VAL_DMA_CLK_RQT | - APMG_CLK_VAL_BSM_CLK_RQT); + ret = iwl_grab_nic_access(priv); + if (ret) + goto out; + /* Enable DMA and BSM Clock */ + iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT | + APMG_CLK_VAL_BSM_CLK_RQT); - udelay(10); + udelay(10); - iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, - APMG_PCIDEV_STT_VAL_L1_ACT_DIS); + /* disable L1A */ + iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, + APMG_PCIDEV_STT_VAL_L1_ACT_DIS); - iwl_release_nic_access(priv); - } + iwl_release_nic_access(priv); clear_bit(STATUS_HCMD_ACTIVE, &priv->status); wake_up_interruptible(&priv->wait_command_queue); +out: spin_unlock_irqrestore(&priv->lock, flags); - return rc; + return ret; } @@ -3617,6 +3624,7 @@ static struct iwl_lib_ops iwl4965_lib = { .load_ucode = iwl4965_load_bsm, .apm_ops = { .init = iwl4965_apm_init, + .reset = iwl4965_apm_reset, .config = iwl4965_nic_config, .set_pwr_src = iwl4965_set_pwr_src, }, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index b1c5045..10054bd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -100,6 +100,59 @@ static int iwl5000_apm_init(struct iwl_priv *priv) return ret; } +static int iwl5000_apm_reset(struct iwl_priv *priv) +{ + int ret = 0; + unsigned long flags; + + iwl4965_hw_nic_stop_master(priv); + + spin_lock_irqsave(&priv->lock, flags); + + iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); + + udelay(10); + + + /* FIXME: put here L1A -L0S w/a */ + + iwl_set_bit(priv, CSR_ANA_PLL_CFG, CSR50_ANA_PLL_CFG_VAL); + + /* set "initialization complete" bit to move adapter + * D0U* --> D0A* state */ + iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + + /* wait for clock stabilization */ + ret = iwl_poll_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + if (ret < 0) { + IWL_DEBUG_INFO("Failed to init the card\n"); + goto out; + } + + ret = iwl_grab_nic_access(priv); + if (ret) + goto out; + + /* enable DMA */ + iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT); + + udelay(20); + + /* disable L1-Active */ + iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, + APMG_PCIDEV_STT_VAL_L1_ACT_DIS); + + iwl_release_nic_access(priv); + +out: + spin_unlock_irqrestore(&priv->lock, flags); + + return ret; +} + + static void iwl5000_nic_config(struct iwl_priv *priv) { unsigned long flags; @@ -805,6 +858,7 @@ static struct iwl_lib_ops iwl5000_lib = { .alive_notify = iwl5000_alive_notify, .apm_ops = { .init = iwl5000_apm_init, + .reset = iwl5000_apm_reset, .config = iwl5000_nic_config, .set_pwr_src = iwl4965_set_pwr_src, }, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 9392fcf..d82660c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -124,6 +124,7 @@ struct iwl_lib_ops { /* power management */ struct { int (*init)(struct iwl_priv *priv); + int (*reset)(struct iwl_priv *priv); void (*config)(struct iwl_priv *priv); int (*set_pwr_src)(struct iwl_priv *priv, enum iwl_pwr_src src); } apm_ops; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index da4d606..d193da3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -688,7 +688,6 @@ extern int iwl4965_hw_rxq_stop(struct iwl_priv *priv); extern int iwl4965_hw_set_hw_params(struct iwl_priv *priv); extern int iwl4965_hw_nic_stop_master(struct iwl_priv *priv); extern void iwl4965_hw_txq_ctx_stop(struct iwl_priv *priv); -extern int iwl4965_hw_nic_reset(struct iwl_priv *priv); extern int iwl4965_hw_get_temperature(struct iwl_priv *priv); extern unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, struct iwl_frame *frame, u8 rate); diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index ee9fe56..af0ffd3 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -3417,9 +3417,8 @@ static void __iwl4965_down(struct iwl_priv *priv) udelay(5); - iwl4965_hw_nic_stop_master(priv); - iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); - iwl4965_hw_nic_reset(priv); + /* FIXME: apm_ops.suspend(priv) */ + priv->cfg->ops->lib->apm_ops.reset(priv); priv->cfg->ops->lib->free_shared_mem(priv); exit: -- cgit v0.10.2 From f118a91d16127e461cc8c17c529306910f13a8b1 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 29 May 2008 16:34:58 +0800 Subject: iwlwifi: implement apm stop function This patch adds apm stop function for 4965 and 5000. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 646c589..080fc54 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -642,6 +642,22 @@ void iwl4965_hw_txq_ctx_stop(struct iwl_priv *priv) iwl_hw_txq_ctx_free(priv); } +static void iwl4965_apm_stop(struct iwl_priv *priv) +{ + unsigned long flags; + + iwl4965_hw_nic_stop_master(priv); + + spin_lock_irqsave(&priv->lock, flags); + + iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); + + udelay(10); + + iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + spin_unlock_irqrestore(&priv->lock, flags); +} + static int iwl4965_apm_reset(struct iwl_priv *priv) { int ret = 0; @@ -658,6 +674,7 @@ static int iwl4965_apm_reset(struct iwl_priv *priv) /* FIXME: put here L1A -L0S w/a */ iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + ret = iwl_poll_bit(priv, CSR_RESET, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25); @@ -689,7 +706,6 @@ out: spin_unlock_irqrestore(&priv->lock, flags); return ret; - } #define REG_RECALIB_PERIOD (60) @@ -3625,6 +3641,7 @@ static struct iwl_lib_ops iwl4965_lib = { .apm_ops = { .init = iwl4965_apm_init, .reset = iwl4965_apm_reset, + .stop = iwl4965_apm_stop, .config = iwl4965_nic_config, .set_pwr_src = iwl4965_set_pwr_src, }, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 10054bd..27cfe3c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -100,6 +100,25 @@ static int iwl5000_apm_init(struct iwl_priv *priv) return ret; } +/* FIXME: this is indentical to 4965 */ +static void iwl5000_apm_stop(struct iwl_priv *priv) +{ + unsigned long flags; + + iwl4965_hw_nic_stop_master(priv); + + spin_lock_irqsave(&priv->lock, flags); + + iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); + + udelay(10); + + iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + + spin_unlock_irqrestore(&priv->lock, flags); +} + + static int iwl5000_apm_reset(struct iwl_priv *priv) { int ret = 0; @@ -859,6 +878,7 @@ static struct iwl_lib_ops iwl5000_lib = { .apm_ops = { .init = iwl5000_apm_init, .reset = iwl5000_apm_reset, + .stop = iwl5000_apm_stop, .config = iwl5000_nic_config, .set_pwr_src = iwl4965_set_pwr_src, }, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index d82660c..d6e6985 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -125,6 +125,7 @@ struct iwl_lib_ops { struct { int (*init)(struct iwl_priv *priv); int (*reset)(struct iwl_priv *priv); + void (*stop)(struct iwl_priv *priv); void (*config)(struct iwl_priv *priv); int (*set_pwr_src)(struct iwl_priv *priv, enum iwl_pwr_src src); } apm_ops; -- cgit v0.10.2 From 46315e012236af887cf442fd494a91b1d36858b9 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 29 May 2008 16:34:59 +0800 Subject: iwlwifi: refactor stop master function This patch refactors stop master function for 4965 and 5000. Currently it duplicates the function. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 080fc54..c586490 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -579,39 +579,6 @@ static void iwl4965_nic_config(struct iwl_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } -int iwl4965_hw_nic_stop_master(struct iwl_priv *priv) -{ - int rc = 0; - u32 reg_val; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - - /* set stop master bit */ - iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); - - reg_val = iwl_read32(priv, CSR_GP_CNTRL); - - if (CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE == - (reg_val & CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE)) - IWL_DEBUG_INFO("Card in power save, master is already " - "stopped\n"); - else { - rc = iwl_poll_bit(priv, CSR_RESET, - CSR_RESET_REG_FLAG_MASTER_DISABLED, - CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); - if (rc < 0) { - spin_unlock_irqrestore(&priv->lock, flags); - return rc; - } - } - - spin_unlock_irqrestore(&priv->lock, flags); - IWL_DEBUG_INFO("stop master\n"); - - return rc; -} - /** * iwl4965_hw_txq_ctx_stop - Stop all Tx DMA channels, free Tx queue memory */ @@ -642,11 +609,34 @@ void iwl4965_hw_txq_ctx_stop(struct iwl_priv *priv) iwl_hw_txq_ctx_free(priv); } +static int iwl4965_apm_stop_master(struct iwl_priv *priv) +{ + int ret = 0; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + + /* set stop master bit */ + iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); + + ret = iwl_poll_bit(priv, CSR_RESET, + CSR_RESET_REG_FLAG_MASTER_DISABLED, + CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); + if (ret < 0) + goto out; + +out: + spin_unlock_irqrestore(&priv->lock, flags); + IWL_DEBUG_INFO("stop master\n"); + + return ret; +} + static void iwl4965_apm_stop(struct iwl_priv *priv) { unsigned long flags; - iwl4965_hw_nic_stop_master(priv); + iwl4965_apm_stop_master(priv); spin_lock_irqsave(&priv->lock, flags); @@ -663,7 +653,7 @@ static int iwl4965_apm_reset(struct iwl_priv *priv) int ret = 0; unsigned long flags; - iwl4965_hw_nic_stop_master(priv); + iwl4965_apm_stop_master(priv); spin_lock_irqsave(&priv->lock, flags); diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 27cfe3c..d607452 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -56,6 +56,31 @@ static const u16 iwl5000_default_queue_to_tx_fifo[] = { IWL_TX_FIFO_HCCA_2 }; +/* FIXME: same implementation as 4965 */ +static int iwl5000_apm_stop_master(struct iwl_priv *priv) +{ + int ret = 0; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + + /* set stop master bit */ + iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); + + ret = iwl_poll_bit(priv, CSR_RESET, + CSR_RESET_REG_FLAG_MASTER_DISABLED, + CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); + if (ret < 0) + goto out; + +out: + spin_unlock_irqrestore(&priv->lock, flags); + IWL_DEBUG_INFO("stop master\n"); + + return ret; +} + + static int iwl5000_apm_init(struct iwl_priv *priv) { int ret = 0; @@ -105,7 +130,7 @@ static void iwl5000_apm_stop(struct iwl_priv *priv) { unsigned long flags; - iwl4965_hw_nic_stop_master(priv); + iwl5000_apm_stop_master(priv); spin_lock_irqsave(&priv->lock, flags); @@ -124,7 +149,7 @@ static int iwl5000_apm_reset(struct iwl_priv *priv) int ret = 0; unsigned long flags; - iwl4965_hw_nic_stop_master(priv); + iwl5000_apm_stop_master(priv); spin_lock_irqsave(&priv->lock, flags); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index d193da3..44bd827 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -686,7 +686,6 @@ extern void iwl4965_hw_setup_deferred_work(struct iwl_priv *priv); extern void iwl4965_hw_cancel_deferred_work(struct iwl_priv *priv); extern int iwl4965_hw_rxq_stop(struct iwl_priv *priv); extern int iwl4965_hw_set_hw_params(struct iwl_priv *priv); -extern int iwl4965_hw_nic_stop_master(struct iwl_priv *priv); extern void iwl4965_hw_txq_ctx_stop(struct iwl_priv *priv); extern int iwl4965_hw_get_temperature(struct iwl_priv *priv); extern unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, -- cgit v0.10.2 From da1bc4539f9b10dc30ac1750fbaaf5afae4b3446 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 29 May 2008 16:35:00 +0800 Subject: iwlwifi: move txq_ctx_stop into iwl-tx.c This patch moves txq_ctx_stop into iwl-tx.c iwlcore module. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index c586490..fe73191 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -468,25 +468,13 @@ int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src) return ret; } -static int iwl4965_disable_tx_fifo(struct iwl_priv *priv) +/* + * Activate/Deactivat Tx DMA/FIFO channels according tx fifos mask + * must be called under priv->lock and mac access + */ +static void iwl4965_txq_set_sched(struct iwl_priv *priv, u32 mask) { - unsigned long flags; - int ret; - - spin_lock_irqsave(&priv->lock, flags); - - ret = iwl_grab_nic_access(priv); - if (unlikely(ret)) { - IWL_ERROR("Tx fifo reset failed"); - spin_unlock_irqrestore(&priv->lock, flags); - return ret; - } - - iwl_write_prph(priv, IWL49_SCD_TXFACT, 0); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->lock, flags); - - return 0; + iwl_write_prph(priv, IWL49_SCD_TXFACT, mask); } static int iwl4965_apm_init(struct iwl_priv *priv) @@ -579,36 +567,6 @@ static void iwl4965_nic_config(struct iwl_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } -/** - * iwl4965_hw_txq_ctx_stop - Stop all Tx DMA channels, free Tx queue memory - */ -void iwl4965_hw_txq_ctx_stop(struct iwl_priv *priv) -{ - - int txq_id; - unsigned long flags; - - /* Stop each Tx DMA channel, and wait for it to be idle */ - for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) { - spin_lock_irqsave(&priv->lock, flags); - if (iwl_grab_nic_access(priv)) { - spin_unlock_irqrestore(&priv->lock, flags); - continue; - } - - iwl_write_direct32(priv, - FH_TCSR_CHNL_TX_CONFIG_REG(txq_id), 0x0); - iwl_poll_direct_bit(priv, FH_TSSR_TX_STATUS_REG, - FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE - (txq_id), 200); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->lock, flags); - } - - /* Deallocate memory for all Tx queues */ - iwl_hw_txq_ctx_free(priv); -} - static int iwl4965_apm_stop_master(struct iwl_priv *priv) { int ret = 0; @@ -995,8 +953,7 @@ int iwl4965_alive_notify(struct iwl_priv *priv) (1 << priv->hw_params.max_txq_num) - 1); /* Activate all Tx DMA/FIFO channels */ - iwl_write_prph(priv, IWL49_SCD_TXFACT, - SCD_TXFACT_REG_TXFIFO_MASK(0, 7)); + priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 7)); iwl4965_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0); @@ -3622,7 +3579,7 @@ static struct iwl_lib_ops iwl4965_lib = { .free_shared_mem = iwl4965_free_shared_mem, .shared_mem_rx_idx = iwl4965_shared_mem_rx_idx, .txq_update_byte_cnt_tbl = iwl4965_txq_update_byte_cnt_tbl, - .disable_tx_fifo = iwl4965_disable_tx_fifo, + .txq_set_sched = iwl4965_txq_set_sched, .rx_handler_setup = iwl4965_rx_handler_setup, .is_valid_rtc_data_addr = iwl4965_hw_valid_rtc_data_addr, .alive_notify = iwl4965_alive_notify, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index d607452..a94cd36 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -662,10 +662,10 @@ static int iwl5000_alive_notify(struct iwl_priv *priv) } iwl_write_prph(priv, IWL50_SCD_INTERRUPT_MASK, - (1 << priv->hw_params.max_txq_num) - 1); + IWL_MASK(0, priv->hw_params.max_txq_num)); - iwl_write_prph(priv, IWL50_SCD_TXFACT, - SCD_TXFACT_REG_TXFIFO_MASK(0, 7)); + /* Activate all Tx DMA/FIFO channels */ + priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 7)); iwl5000_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0); /* map qos queues to fifos one-to-one */ @@ -839,25 +839,13 @@ static u16 iwl5000_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data) } -static int iwl5000_disable_tx_fifo(struct iwl_priv *priv) +/* + * Activate/Deactivat Tx DMA/FIFO channels according tx fifos mask + * must be called under priv->lock and mac access + */ +static void iwl5000_txq_set_sched(struct iwl_priv *priv, u32 mask) { - unsigned long flags; - int ret; - - spin_lock_irqsave(&priv->lock, flags); - - ret = iwl_grab_nic_access(priv); - if (unlikely(ret)) { - IWL_ERROR("Tx fifo reset failed"); - spin_unlock_irqrestore(&priv->lock, flags); - return ret; - } - - iwl_write_prph(priv, IWL50_SCD_TXFACT, 0); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->lock, flags); - - return 0; + iwl_write_prph(priv, IWL50_SCD_TXFACT, mask); } /* Currently 5000 is the supperset of everything */ @@ -894,7 +882,7 @@ static struct iwl_lib_ops iwl5000_lib = { .free_shared_mem = iwl5000_free_shared_mem, .shared_mem_rx_idx = iwl5000_shared_mem_rx_idx, .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, - .disable_tx_fifo = iwl5000_disable_tx_fifo, + .txq_set_sched = iwl5000_txq_set_sched, .rx_handler_setup = iwl5000_rx_handler_setup, .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr, .load_ucode = iwl5000_load_ucode, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index d6e6985..d67b53c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -110,7 +110,7 @@ struct iwl_lib_ops { /* setup Rx handler */ void (*rx_handler_setup)(struct iwl_priv *priv); /* nic Tx fifo handling */ - int (*disable_tx_fifo)(struct iwl_priv *priv); + void (*txq_set_sched)(struct iwl_priv *priv, u32 mask); /* alive notification after init uCode load */ void (*init_alive_start)(struct iwl_priv *priv); /* alive notification */ diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 44bd827..3cefaaf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -686,7 +686,7 @@ extern void iwl4965_hw_setup_deferred_work(struct iwl_priv *priv); extern void iwl4965_hw_cancel_deferred_work(struct iwl_priv *priv); extern int iwl4965_hw_rxq_stop(struct iwl_priv *priv); extern int iwl4965_hw_set_hw_params(struct iwl_priv *priv); -extern void iwl4965_hw_txq_ctx_stop(struct iwl_priv *priv); +extern void iwl_txq_ctx_stop(struct iwl_priv *priv); extern int iwl4965_hw_get_temperature(struct iwl_priv *priv); extern unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, struct iwl_frame *frame, u8 rate); diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h index e4c3f84..dedefa0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-helpers.h +++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h @@ -136,6 +136,8 @@ static inline void iwl_set_bits16(__le16 *dst, u8 pos, u8 len, int val) #define KELVIN_TO_CELSIUS(x) ((x)-273) #define CELSIUS_TO_KELVIN(x) ((x)+273) +#define IWL_MASK(lo, hi) ((1 << (hi)) | ((1 << (hi)) - (1 << (lo)))) + #define IEEE80211_CHAN_W_RADAR_DETECT 0x00000010 diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index d6a04f6..15cb7ff 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -358,11 +358,6 @@ * 7- 0: Enable (1), disable (0), one bit for each channel 0-7 */ #define IWL49_SCD_TXFACT (IWL49_SCD_START_OFFSET + 0x1c) - -/* Mask to enable contiguous Tx DMA/FIFO channels between "lo" and "hi". */ -#define SCD_TXFACT_REG_TXFIFO_MASK(lo, hi) \ - ((1 << (hi)) | ((1 << (hi)) - (1 << (lo)))) - /* * Queue (x) Write Pointers (indexes, really!), one for each Tx queue. * Initialized and updated by driver as new TFDs are added to queue. diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 0ebab96..0b822b5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -263,24 +263,6 @@ EXPORT_SYMBOL(iwl_queue_space); /** - * iwl_hw_txq_ctx_free - Free TXQ Context - * - * Destroy all TX DMA queues and structures - */ -void iwl_hw_txq_ctx_free(struct iwl_priv *priv) -{ - int txq_id; - - /* Tx queues */ - for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) - iwl_tx_queue_free(priv, &priv->txq[txq_id]); - - /* Keep-warm buffer */ - iwl_kw_free(priv); -} -EXPORT_SYMBOL(iwl_hw_txq_ctx_free); - -/** * iwl_queue_init - Initialize queue's high/low-water and read/write indexes */ static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q, @@ -437,6 +419,24 @@ static int iwl_tx_queue_init(struct iwl_priv *priv, return 0; } +/** + * iwl_hw_txq_ctx_free - Free TXQ Context + * + * Destroy all TX DMA queues and structures + */ +void iwl_hw_txq_ctx_free(struct iwl_priv *priv) +{ + int txq_id; + + /* Tx queues */ + for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) + iwl_tx_queue_free(priv, &priv->txq[txq_id]); + + /* Keep-warm buffer */ + iwl_kw_free(priv); +} +EXPORT_SYMBOL(iwl_hw_txq_ctx_free); + /** * iwl_txq_ctx_reset - Reset TX queue context @@ -449,6 +449,7 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv) { int ret = 0; int txq_id, slots_num; + unsigned long flags; iwl_kw_free(priv); @@ -461,11 +462,19 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv) IWL_ERROR("Keep Warm allocation failed"); goto error_kw; } + spin_lock_irqsave(&priv->lock, flags); + ret = iwl_grab_nic_access(priv); + if (unlikely(ret)) { + spin_unlock_irqrestore(&priv->lock, flags); + goto error_reset; + } /* Turn off all Tx DMA fifos */ - ret = priv->cfg->ops->lib->disable_tx_fifo(priv); - if (unlikely(ret)) - goto error_reset; + priv->cfg->ops->lib->txq_set_sched(priv, 0); + + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + /* Tell nic where to find the keep-warm buffer */ ret = iwl_kw_init(priv); @@ -474,8 +483,7 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv) goto error_reset; } - /* Alloc and init all (default 16) Tx queues, - * including the command queue (#4) */ + /* Alloc and init all Tx queues, including the command queue (#4) */ for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) { slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ? TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; @@ -496,6 +504,40 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv) error_kw: return ret; } +/** + * iwl_txq_ctx_stop - Stop all Tx DMA channels, free Tx queue memory + */ +void iwl_txq_ctx_stop(struct iwl_priv *priv) +{ + + int txq_id; + unsigned long flags; + + + /* Turn off all Tx DMA fifos */ + spin_lock_irqsave(&priv->lock, flags); + if (iwl_grab_nic_access(priv)) { + spin_unlock_irqrestore(&priv->lock, flags); + return; + } + + priv->cfg->ops->lib->txq_set_sched(priv, 0); + + /* Stop each Tx DMA channel, and wait for it to be idle */ + for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) { + iwl_write_direct32(priv, + FH_TCSR_CHNL_TX_CONFIG_REG(txq_id), 0x0); + iwl_poll_direct_bit(priv, FH_TSSR_TX_STATUS_REG, + FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE + (txq_id), 200); + } + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + /* Deallocate memory for all Tx queues */ + iwl_hw_txq_ctx_free(priv); +} +EXPORT_SYMBOL(iwl_txq_ctx_stop); /* * handle build REPLY_TX command notification. diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index af0ffd3..2652f5f 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -3404,7 +3404,7 @@ static void __iwl4965_down(struct iwl_priv *priv) CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); spin_unlock_irqrestore(&priv->lock, flags); - iwl4965_hw_txq_ctx_stop(priv); + iwl_txq_ctx_stop(priv); iwl4965_hw_rxq_stop(priv); spin_lock_irqsave(&priv->lock, flags); -- cgit v0.10.2 From b3bbacb78bc688707ac312158c5bbc6bbbb55b23 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 29 May 2008 16:35:01 +0800 Subject: iwlwifi: move iwl_rxq_stop into iwl-rx.c This patch moves iwl_rxq_stop into iwl-rx.c. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index fe73191..2f254c4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -384,31 +384,6 @@ void iwl4965_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, control->tx_rate_idx = rate_index; } -int iwl4965_hw_rxq_stop(struct iwl_priv *priv) -{ - int rc; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - rc = iwl_grab_nic_access(priv); - if (rc) { - spin_unlock_irqrestore(&priv->lock, flags); - return rc; - } - - /* stop Rx DMA */ - iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); - rc = iwl_poll_direct_bit(priv, FH_MEM_RSSR_RX_STATUS_REG, - (1 << 24), 1000); - if (rc < 0) - IWL_ERROR("Can't stop Rx DMA.\n"); - - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->lock, flags); - - return 0; -} - /* * EEPROM handlers */ diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 3cefaaf..5291f1a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -684,8 +684,8 @@ extern u8 iwl4965_sync_station(struct iwl_priv *priv, int sta_id, ****************************************************************************/ extern void iwl4965_hw_setup_deferred_work(struct iwl_priv *priv); extern void iwl4965_hw_cancel_deferred_work(struct iwl_priv *priv); -extern int iwl4965_hw_rxq_stop(struct iwl_priv *priv); extern int iwl4965_hw_set_hw_params(struct iwl_priv *priv); +extern int iwl_rxq_stop(struct iwl_priv *priv); extern void iwl_txq_ctx_stop(struct iwl_priv *priv); extern int iwl4965_hw_get_temperature(struct iwl_priv *priv); extern unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index a2eb90d..ed63e5c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -420,3 +420,29 @@ int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) return 0; } +int iwl_rxq_stop(struct iwl_priv *priv) +{ + int ret; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + ret = iwl_grab_nic_access(priv); + if (unlikely(ret)) { + spin_unlock_irqrestore(&priv->lock, flags); + return ret; + } + + /* stop Rx DMA */ + iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); + ret = iwl_poll_direct_bit(priv, FH_MEM_RSSR_RX_STATUS_REG, + (1 << 24), 1000); + if (ret < 0) + IWL_ERROR("Can't stop Rx DMA.\n"); + + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} +EXPORT_SYMBOL(iwl_rxq_stop); + diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 2652f5f..985876b 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -3405,7 +3405,7 @@ static void __iwl4965_down(struct iwl_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); iwl_txq_ctx_stop(priv); - iwl4965_hw_rxq_stop(priv); + iwl_rxq_stop(priv); spin_lock_irqsave(&priv->lock, flags); if (!iwl_grab_nic_access(priv)) { -- cgit v0.10.2 From 7a999bf0c5eb19b20ac6ab0f21f6e5013400fa51 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 29 May 2008 16:35:02 +0800 Subject: iwlwifi: add remove station functionality This patch adds remove station functionality, which is required for 5000 and AP mode. There are still some gaps in managment that need to be closed but it provides sufficient functionality for 5000 HW. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index afd0f7d..a637abe 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -928,10 +928,28 @@ struct iwl_addsta_cmd { /* * REPLY_ADD_STA = 0x18 (response) */ -struct iwl4965_add_sta_resp { +struct iwl_add_sta_resp { u8 status; /* ADD_STA_* */ } __attribute__ ((packed)); +#define REM_STA_SUCCESS_MSK 0x1 +/* + * REPLY_REM_STA = 0x19 (response) + */ +struct iwl_rem_sta_resp { + u8 status; +} __attribute__ ((packed)); + +/* + * REPLY_REM_STA = 0x19 (command) + */ +struct iwl_rem_sta_cmd { + u8 num_sta; /* number of removed stations */ + u8 reserved[3]; + u8 addr[ETH_ALEN]; /* MAC addr of the first station */ + u8 reserved2[2]; +} __attribute__ ((packed)); + /* * REPLY_WEP_KEY = 0x20 */ @@ -2869,7 +2887,8 @@ struct iwl_rx_packet { struct iwl_error_resp err_resp; struct iwl4965_card_state_notif card_state_notif; struct iwl4965_beacon_notif beacon_status; - struct iwl4965_add_sta_resp add_sta; + struct iwl_add_sta_resp add_sta; + struct iwl_rem_sta_resp rem_sta; struct iwl4965_sleep_notification sleep_notif; struct iwl4965_spectrum_resp spectrum; struct iwl4965_notif_statistics stats; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 5291f1a..2c92e55 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -333,6 +333,7 @@ struct iwl_cmd { struct iwl_tx_cmd tx; struct iwl4965_tx_beacon_cmd tx_beacon; struct iwl4965_rxon_assoc_cmd rxon_assoc; + struct iwl_rem_sta_cmd rm_sta; u8 *indirect; u8 payload[IWL_CMD_MAX_PAYLOAD]; } __attribute__ ((packed)) cmd; diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 99ee1e1..11ec408 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -37,6 +37,10 @@ #include "iwl-io.h" #include "iwl-helpers.h" + +#define IWL_STA_DRIVER_ACTIVE 0x1 /* ucode entry is active */ +#define IWL_STA_UCODE_ACTIVE 0x2 /* ucode entry is active */ + u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr) { int i; @@ -241,6 +245,152 @@ u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap, } EXPORT_SYMBOL(iwl_add_station_flags); + +static int iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr) +{ + unsigned long flags; + u8 sta_id; + DECLARE_MAC_BUF(mac); + + sta_id = iwl_find_station(priv, addr); + if (sta_id != IWL_INVALID_STATION) { + IWL_DEBUG_ASSOC("Removed STA from Ucode: %s\n", + print_mac(mac, addr)); + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].used &= ~IWL_STA_UCODE_ACTIVE; + memset(&priv->stations[sta_id], 0, + sizeof(struct iwl_station_entry)); + spin_unlock_irqrestore(&priv->sta_lock, flags); + return 0; + } + return -EINVAL; +} + +static int iwl_remove_sta_callback(struct iwl_priv *priv, + struct iwl_cmd *cmd, struct sk_buff *skb) +{ + struct iwl_rx_packet *res = NULL; + const char *addr = cmd->cmd.rm_sta.addr; + + if (!skb) { + IWL_ERROR("Error: Response NULL in REPLY_REMOVE_STA.\n"); + return 1; + } + + res = (struct iwl_rx_packet *)skb->data; + if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + IWL_ERROR("Bad return from REPLY_REMOVE_STA (0x%08X)\n", + res->hdr.flags); + return 1; + } + + switch (res->u.rem_sta.status) { + case REM_STA_SUCCESS_MSK: + iwl_sta_ucode_deactivate(priv, addr); + break; + default: + break; + } + + /* We didn't cache the SKB; let the caller free it */ + return 1; +} + +static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr, + u8 flags) +{ + struct iwl_rx_packet *res = NULL; + int ret; + + struct iwl_rem_sta_cmd rm_sta_cmd; + + struct iwl_host_cmd cmd = { + .id = REPLY_REMOVE_STA, + .len = sizeof(struct iwl_rem_sta_cmd), + .meta.flags = flags, + .data = &rm_sta_cmd, + }; + + memset(&rm_sta_cmd, 0, sizeof(rm_sta_cmd)); + rm_sta_cmd.num_sta = 1; + memcpy(&rm_sta_cmd.addr, addr , ETH_ALEN); + + if (flags & CMD_ASYNC) + cmd.meta.u.callback = iwl_remove_sta_callback; + else + cmd.meta.flags |= CMD_WANT_SKB; + ret = iwl_send_cmd(priv, &cmd); + + if (ret || (flags & CMD_ASYNC)) + return ret; + + res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + IWL_ERROR("Bad return from REPLY_REMOVE_STA (0x%08X)\n", + res->hdr.flags); + ret = -EIO; + } + + if (!ret) { + switch (res->u.rem_sta.status) { + case REM_STA_SUCCESS_MSK: + iwl_sta_ucode_deactivate(priv, addr); + IWL_DEBUG_ASSOC("REPLY_REMOVE_STA PASSED\n"); + break; + default: + ret = -EIO; + IWL_ERROR("REPLY_REMOVE_STA failed\n"); + break; + } + } + + priv->alloc_rxb_skb--; + dev_kfree_skb_any(cmd.meta.u.skb); + + return ret; +} +/** + * iwl_remove_station - Remove driver's knowledge of station. + * + */ +u8 iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap) +{ + int index = IWL_INVALID_STATION; + int i; + unsigned long flags; + + spin_lock_irqsave(&priv->sta_lock, flags); + + if (is_ap) + index = IWL_AP_ID; + else if (is_broadcast_ether_addr(addr)) + index = priv->hw_params.bcast_sta_id; + else + for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) + if (priv->stations[i].used && + !compare_ether_addr(priv->stations[i].sta.sta.addr, + addr)) { + index = i; + break; + } + + if (unlikely(index == IWL_INVALID_STATION)) + goto out; + + if (priv->stations[index].used) { + priv->stations[index].used = 0; + priv->num_stations--; + } + + BUG_ON(priv->num_stations < 0); + spin_unlock_irqrestore(&priv->sta_lock, flags); + iwl_send_remove_station(priv, addr, CMD_ASYNC); + return index; +out: + spin_unlock_irqrestore(&priv->sta_lock, flags); + return 0; +} +EXPORT_SYMBOL(iwl_remove_station); int iwl_get_free_ucode_key_index(struct iwl_priv *priv) { int i; diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h index b643546..500e1df 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.h +++ b/drivers/net/wireless/iwlwifi/iwl-sta.h @@ -43,5 +43,6 @@ int iwl_set_dynamic_key(struct iwl_priv *priv, int iwl_remove_dynamic_key(struct iwl_priv *priv, struct ieee80211_key_conf *key, u8 sta_id); int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap); +u8 iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap); int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr); #endif /* __iwl_sta_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 985876b..185d667 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -140,49 +140,6 @@ static const char *iwl4965_escape_essid(const char *essid, u8 essid_len) /**************************************************************/ -#if 0 /* temporary disable till we add real remove station */ -/** - * iwl4965_remove_station - Remove driver's knowledge of station. - * - * NOTE: This does not remove station from device's station table. - */ -static u8 iwl4965_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap) -{ - int index = IWL_INVALID_STATION; - int i; - unsigned long flags; - - spin_lock_irqsave(&priv->sta_lock, flags); - - if (is_ap) - index = IWL_AP_ID; - else if (is_broadcast_ether_addr(addr)) - index = priv->hw_params.bcast_sta_id; - else - for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) - if (priv->stations[i].used && - !compare_ether_addr(priv->stations[i].sta.sta.addr, - addr)) { - index = i; - break; - } - - if (unlikely(index == IWL_INVALID_STATION)) - goto out; - - if (priv->stations[index].used) { - priv->stations[index].used = 0; - priv->num_stations--; - } - - BUG_ON(priv->num_stations < 0); - -out: - spin_unlock_irqrestore(&priv->sta_lock, flags); - return 0; -} -#endif - static void iwl4965_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt) @@ -404,6 +361,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) return rc; } + iwl_remove_station(priv, iwl_bcast_addr, 0); iwlcore_clear_stations_table(priv); if (!priv->error_recovering) -- cgit v0.10.2 From 42132bce8011bf9507cfbb920ced2235d8dd5fce Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 29 May 2008 16:35:03 +0800 Subject: iwlwifi: move add sta handler to iwl-sta.c This patch moves add_sta hander to iwl-sta.c. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 11ec408..ed07566 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -74,6 +74,39 @@ u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr) } EXPORT_SYMBOL(iwl_find_station); +static int iwl_add_sta_callback(struct iwl_priv *priv, + struct iwl_cmd *cmd, struct sk_buff *skb) +{ + struct iwl_rx_packet *res = NULL; + + if (!skb) { + IWL_ERROR("Error: Response NULL in REPLY_ADD_STA.\n"); + return 1; + } + + res = (struct iwl_rx_packet *)skb->data; + if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n", + res->hdr.flags); + return 1; + } + + switch (res->u.add_sta.status) { + case ADD_STA_SUCCESS_MSK: + /* FIXME: implement iwl_sta_ucode_activate(priv, addr); */ + /* fail through */ + default: + IWL_DEBUG_HC("Received REPLY_ADD_STA:(0x%08X)\n", + res->u.add_sta.status); + break; + } + + /* We didn't cache the SKB; let the caller free it */ + return 1; +} + + + int iwl_send_add_sta(struct iwl_priv *priv, struct iwl_addsta_cmd *sta, u8 flags) { @@ -86,7 +119,9 @@ int iwl_send_add_sta(struct iwl_priv *priv, .data = data, }; - if (!(flags & CMD_ASYNC)) + if (flags & CMD_ASYNC) + cmd.meta.u.callback = iwl_add_sta_callback; + else cmd.meta.flags |= CMD_WANT_SKB; cmd.len = priv->cfg->ops->utils->build_addsta_hcmd(sta, data); diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 185d667..f3815b7 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -1921,15 +1921,6 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv, IWL_WARNING("uCode did not respond OK.\n"); } -static void iwl4965_rx_reply_add_sta(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - - IWL_DEBUG_RX("Received REPLY_ADD_STA: 0x%02X\n", pkt->u.status); - return; -} - static void iwl4965_rx_reply_error(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { @@ -2238,7 +2229,6 @@ static void iwl4965_rx_card_state_notif(struct iwl_priv *priv, static void iwl4965_setup_rx_handlers(struct iwl_priv *priv) { priv->rx_handlers[REPLY_ALIVE] = iwl_rx_reply_alive; - priv->rx_handlers[REPLY_ADD_STA] = iwl4965_rx_reply_add_sta; priv->rx_handlers[REPLY_ERROR] = iwl4965_rx_reply_error; priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl4965_rx_csa; priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] = -- cgit v0.10.2 From c135475439f75e6eb29e7586d33f3e22a61c1bb4 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 29 May 2008 16:35:04 +0800 Subject: iwlwifi: move iwl_rx_missed_beacon_notif to iwl-rx.c This patch moves iwl_rx_missed_beacon_notif rx handler to iwl-rx.c. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 2f254c4..1b3e82f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2898,26 +2898,7 @@ static void iwl4965_rx_reply_rx_phy(struct iwl_priv *priv, memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]), sizeof(struct iwl4965_rx_phy_res)); } -static void iwl4965_rx_missed_beacon_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ -#ifdef CONFIG_IWL4965_RUN_TIME_CALIB - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - struct iwl4965_missed_beacon_notif *missed_beacon; - - missed_beacon = &pkt->u.missed_beacon; - if (le32_to_cpu(missed_beacon->consequtive_missed_beacons) > 5) { - IWL_DEBUG_CALIB("missed bcn cnsq %d totl %d rcd %d expctd %d\n", - le32_to_cpu(missed_beacon->consequtive_missed_beacons), - le32_to_cpu(missed_beacon->total_missed_becons), - le32_to_cpu(missed_beacon->num_recvd_beacons), - le32_to_cpu(missed_beacon->num_expected_beacons)); - if (!test_bit(STATUS_SCANNING, &priv->status)) - iwl_init_sensitivity(priv); - } -#endif /*CONFIG_IWL4965_RUN_TIME_CALIB*/ -} #ifdef CONFIG_IWL4965_HT /** @@ -3508,9 +3489,6 @@ static void iwl4965_rx_handler_setup(struct iwl_priv *priv) priv->rx_handlers[REPLY_RX_PHY_CMD] = iwl4965_rx_reply_rx_phy; priv->rx_handlers[REPLY_RX_MPDU_CMD] = iwl4965_rx_reply_rx; - priv->rx_handlers[MISSED_BEACONS_NOTIFICATION] = - iwl4965_rx_missed_beacon_notif; - #ifdef CONFIG_IWL4965_HT priv->rx_handlers[REPLY_COMPRESSED_BA] = iwl4965_rx_reply_compressed_ba; #endif /* CONFIG_IWL4965_HT */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index d67b53c..0505491 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -204,6 +204,9 @@ int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq); int iwl_rx_queue_restock(struct iwl_priv *priv); int iwl_rx_queue_space(const struct iwl_rx_queue *q); void iwl_rx_allocate(struct iwl_priv *priv); +/* Handlers */ +void iwl_rx_missed_beacon_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb); /***************************************************** * TX diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index ed63e5c..cc61c93 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -33,6 +33,7 @@ #include "iwl-core.h" #include "iwl-sta.h" #include "iwl-io.h" +#include "iwl-calib.h" #include "iwl-helpers.h" /************************** RX-FUNCTIONS ****************************/ /* @@ -446,3 +447,24 @@ int iwl_rxq_stop(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_rxq_stop); +void iwl_rx_missed_beacon_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) + +{ +#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl4965_missed_beacon_notif *missed_beacon; + + missed_beacon = &pkt->u.missed_beacon; + if (le32_to_cpu(missed_beacon->consequtive_missed_beacons) > 5) { + IWL_DEBUG_CALIB("missed bcn cnsq %d totl %d rcd %d expctd %d\n", + le32_to_cpu(missed_beacon->consequtive_missed_beacons), + le32_to_cpu(missed_beacon->total_missed_becons), + le32_to_cpu(missed_beacon->num_recvd_beacons), + le32_to_cpu(missed_beacon->num_expected_beacons)); + if (!test_bit(STATUS_SCANNING, &priv->status)) + iwl_init_sensitivity(priv); + } +#endif /* CONFIG_IWLWIFI_RUN_TIME_CALIB */ +} +EXPORT_SYMBOL(iwl_rx_missed_beacon_notif); diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index f3815b7..b3c1807 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -2255,6 +2255,9 @@ static void iwl4965_setup_rx_handlers(struct iwl_priv *priv) priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl4965_rx_card_state_notif; priv->rx_handlers[REPLY_TX] = iwl4965_rx_reply_tx; + priv->rx_handlers[MISSED_BEACONS_NOTIFICATION] = + iwl_rx_missed_beacon_notif; + /* Set up hardware specific Rx handlers */ priv->cfg->ops->lib->rx_handler_setup(priv); } -- cgit v0.10.2 From 7c616cba240cd0d579c996be3f3603456acfb0ad Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 29 May 2008 16:35:05 +0800 Subject: iwlwifi-5000: implement initial calibration for 5000 This patch adds initial calibration framework for 5000 HW faimily. Signed-off-by: Tomas Winkler Signed-off-by: Gregory Greenman Signed-off-by: Ron Rindjunsky Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index a94cd36..eb6141e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -395,6 +395,8 @@ static struct iwl_sensitivity_ranges iwl5000_sensitivity = { #endif /* CONFIG_IWL5000_RUN_TIME_CALIB */ + + static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv, size_t offset) { @@ -404,6 +406,118 @@ static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv, } /* + * Calibration + */ +static int iwl5000_send_Xtal_calib(struct iwl_priv *priv) +{ + u16 *xtal_calib = (u16 *)iwl_eeprom_query_addr(priv, EEPROM_5000_XTAL); + + struct iwl5000_calibration cal_cmd = { + .op_code = IWL5000_PHY_CALIBRATE_CRYSTAL_FRQ_CMD, + .data = { + (u8)xtal_calib[0], + (u8)xtal_calib[1], + } + }; + + return iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, + sizeof(cal_cmd), &cal_cmd); +} + +static int iwl5000_send_calib_results(struct iwl_priv *priv) +{ + int ret = 0; + + if (priv->calib_results.lo_res) + ret = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, + priv->calib_results.lo_res_len, + priv->calib_results.lo_res); + if (ret) + goto err; + + + if (priv->calib_results.tx_iq_res) + ret = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, + priv->calib_results.tx_iq_res_len, + priv->calib_results.tx_iq_res); + + if (ret) + goto err; + + if (priv->calib_results.tx_iq_perd_res) + ret = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, + priv->calib_results.tx_iq_perd_res_len, + priv->calib_results.tx_iq_perd_res); + if (ret) + goto err; + + return 0; +err: + IWL_ERROR("Error %d\n", ret); + return ret; +} + +static int iwl5000_send_calib_cfg(struct iwl_priv *priv) +{ + struct iwl5000_calib_cfg_cmd calib_cfg_cmd; + struct iwl_host_cmd cmd = { + .id = CALIBRATION_CFG_CMD, + .len = sizeof(struct iwl5000_calib_cfg_cmd), + .data = &calib_cfg_cmd, + }; + + memset(&calib_cfg_cmd, 0, sizeof(calib_cfg_cmd)); + calib_cfg_cmd.ucd_calib_cfg.once.is_enable = IWL_CALIB_INIT_CFG_ALL; + calib_cfg_cmd.ucd_calib_cfg.once.start = IWL_CALIB_INIT_CFG_ALL; + calib_cfg_cmd.ucd_calib_cfg.once.send_res = IWL_CALIB_INIT_CFG_ALL; + calib_cfg_cmd.ucd_calib_cfg.flags = IWL_CALIB_INIT_CFG_ALL; + + return iwl_send_cmd(priv, &cmd); +} + +static void iwl5000_rx_calib_result(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl5000_calib_hdr *hdr = (struct iwl5000_calib_hdr *)pkt->u.raw; + int len = le32_to_cpu(pkt->len) & FH_RSCSR_FRAME_SIZE_MSK; + + iwl_free_calib_results(priv); + + /* reduce the size of the length field itself */ + len -= 4; + + switch (hdr->op_code) { + case IWL5000_PHY_CALIBRATE_LO_CMD: + priv->calib_results.lo_res = kzalloc(len, GFP_ATOMIC); + priv->calib_results.lo_res_len = len; + memcpy(priv->calib_results.lo_res, pkt->u.raw, len); + break; + case IWL5000_PHY_CALIBRATE_TX_IQ_CMD: + priv->calib_results.tx_iq_res = kzalloc(len, GFP_ATOMIC); + priv->calib_results.tx_iq_res_len = len; + memcpy(priv->calib_results.tx_iq_res, pkt->u.raw, len); + break; + case IWL5000_PHY_CALIBRATE_TX_IQ_PERD_CMD: + priv->calib_results.tx_iq_perd_res = kzalloc(len, GFP_ATOMIC); + priv->calib_results.tx_iq_perd_res_len = len; + memcpy(priv->calib_results.tx_iq_perd_res, pkt->u.raw, len); + break; + default: + IWL_ERROR("Unknown calibration notification %d\n", + hdr->op_code); + return; + } +} + +static void iwl5000_rx_calib_complete(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + IWL_DEBUG_INFO("Init. calibration is completed, restarting fw.\n"); + queue_work(priv->workqueue, &priv->restart); +} + +/* * ucode */ static int iwl5000_load_section(struct iwl_priv *priv, @@ -565,6 +679,7 @@ static void iwl5000_init_alive_start(struct iwl_priv *priv) goto restart; } + iwl5000_send_calib_cfg(priv); return; restart: @@ -684,8 +799,14 @@ static int iwl5000_alive_notify(struct iwl_priv *priv) iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); + iwl5000_send_wimax_coex(priv); + iwl5000_send_Xtal_calib(priv); + + if (priv->ucode_type == UCODE_RT) + iwl5000_send_calib_results(priv); + return 0; } @@ -856,8 +977,14 @@ static u16 iwl5000_get_hcmd_size(u8 cmd_id, u16 len) static void iwl5000_rx_handler_setup(struct iwl_priv *priv) { + /* init calibration handlers */ + priv->rx_handlers[CALIBRATION_RES_NOTIFICATION] = + iwl5000_rx_calib_result; + priv->rx_handlers[CALIBRATION_COMPLETE_NOTIFICATION] = + iwl5000_rx_calib_complete; } + static int iwl5000_hw_valid_rtc_data_addr(u32 addr) { return (addr >= RTC_DATA_LOWER_BOUND) && diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index a637abe..6f62beb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -2778,10 +2778,59 @@ enum { IWL5000_PHY_CALIBRATE_AGC_TABLE_CMD = 14, IWL5000_PHY_CALIBRATE_CRYSTAL_FRQ_CMD = 15, IWL5000_PHY_CALIBRATE_BASE_BAND_CMD = 16, + IWL5000_PHY_CALIBRATE_TX_IQ_PERD_CMD = 17, IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD = 18, IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD = 19, }; +enum { + CALIBRATION_CFG_CMD = 0x65, + CALIBRATION_RES_NOTIFICATION = 0x66, + CALIBRATION_COMPLETE_NOTIFICATION = 0x67 +}; + +struct iwl_cal_crystal_freq_cmd { + u8 cap_pin1; + u8 cap_pin2; +} __attribute__ ((packed)); + +struct iwl5000_calibration { + u8 op_code; + u8 first_group; + u8 num_groups; + u8 all_data_valid; + struct iwl_cal_crystal_freq_cmd data; +} __attribute__ ((packed)); + +#define IWL_CALIB_INIT_CFG_ALL __constant_cpu_to_le32(0xffffffff) + +struct iwl_calib_cfg_elmnt_s { + __le32 is_enable; + __le32 start; + __le32 send_res; + __le32 apply_res; + __le32 reserved; +} __attribute__ ((packed)); + +struct iwl_calib_cfg_status_s { + struct iwl_calib_cfg_elmnt_s once; + struct iwl_calib_cfg_elmnt_s perd; + __le32 flags; +} __attribute__ ((packed)); + +struct iwl5000_calib_cfg_cmd { + struct iwl_calib_cfg_status_s ucd_calib_cfg; + struct iwl_calib_cfg_status_s drv_calib_cfg; + __le32 reserved1; +} __attribute__ ((packed)); + +struct iwl5000_calib_hdr { + u8 op_code; + u8 first_group; + u8 groups_num; + u8 data_valid; +} __attribute__ ((packed)); + struct iwl5000_calibration_chain_noise_reset_cmd { u8 op_code; /* IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD */ u8 flags; /* not used */ @@ -2894,6 +2943,7 @@ struct iwl_rx_packet { struct iwl4965_notif_statistics stats; struct iwl4965_compressed_ba_resp compressed_ba; struct iwl4965_missed_beacon_notif missed_beacon; + struct iwl5000_calibration calib; __le32 status; u8 raw[0]; } u; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 373e984..010085a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -871,9 +871,25 @@ err: } EXPORT_SYMBOL(iwl_init_drv); +void iwl_free_calib_results(struct iwl_priv *priv) +{ + kfree(priv->calib_results.lo_res); + priv->calib_results.lo_res = NULL; + priv->calib_results.lo_res_len = 0; + + kfree(priv->calib_results.tx_iq_res); + priv->calib_results.tx_iq_res = NULL; + priv->calib_results.tx_iq_res_len = 0; + + kfree(priv->calib_results.tx_iq_perd_res); + priv->calib_results.tx_iq_perd_res = NULL; + priv->calib_results.tx_iq_perd_res_len = 0; +} +EXPORT_SYMBOL(iwl_free_calib_results); void iwl_uninit_drv(struct iwl_priv *priv) { + iwl_free_calib_results(priv); iwlcore_free_geos(priv); iwl_free_channel_map(priv); } diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 0505491..9d43085 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -172,6 +172,7 @@ struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg, void iwl_hw_detect(struct iwl_priv *priv); void iwlcore_clear_stations_table(struct iwl_priv *priv); +void iwl_free_calib_results(struct iwl_priv *priv); void iwl_reset_qos(struct iwl_priv *priv); void iwl_set_rxon_chain(struct iwl_priv *priv); int iwl_set_rxon_channel(struct iwl_priv *priv, diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 2c92e55..291c1ec 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -876,6 +876,15 @@ struct statistics_general_data { u32 beacon_energy_c; }; +struct iwl_calib_results { + void *tx_iq_res; + void *tx_iq_perd_res; + void *lo_res; + u32 tx_iq_res_len; + u32 tx_iq_perd_res_len; + u32 lo_res_len; +}; + enum ucode_type { UCODE_NONE = 0, UCODE_INIT, @@ -983,6 +992,9 @@ struct iwl_priv { s32 temperature; /* degrees Kelvin */ s32 last_temperature; + /* init calibration results */ + struct iwl_calib_results calib_results; + /* Scan related variables */ unsigned long last_scan_jiffies; unsigned long next_scan_jiffies; diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index dc1f027..d3a2a5b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -146,6 +146,7 @@ struct iwl_eeprom_channel { /*5000 calibrations */ #define EEPROM_5000_CALIB_ALL (INDIRECT_ADDRESS | INDIRECT_CALIBRATION) +#define EEPROM_5000_XTAL ((2*0x128) | EEPROM_5000_CALIB_ALL) /* 5000 links */ #define EEPROM_5000_LINK_HOST (2*0x64) diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index dab4a0e..6c53736 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -56,6 +56,7 @@ const char *get_cmd_string(u8 cmd) IWL_CMD(REPLY_RATE_SCALE); IWL_CMD(REPLY_LEDS_CMD); IWL_CMD(REPLY_TX_LINK_QUALITY_CMD); + IWL_CMD(COEX_PRIORITY_TABLE_CMD); IWL_CMD(RADAR_NOTIFICATION); IWL_CMD(REPLY_QUIET_CMD); IWL_CMD(REPLY_CHANNEL_SWITCH); @@ -89,6 +90,9 @@ const char *get_cmd_string(u8 cmd) IWL_CMD(REPLY_RX_MPDU_CMD); IWL_CMD(REPLY_RX); IWL_CMD(REPLY_COMPRESSED_BA); + IWL_CMD(CALIBRATION_CFG_CMD); + IWL_CMD(CALIBRATION_RES_NOTIFICATION); + IWL_CMD(CALIBRATION_COMPLETE_NOTIFICATION); default: return "UNKNOWN"; -- cgit v0.10.2 From fe9b6b720bd11c598417529755ac850a85070560 Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Thu, 29 May 2008 16:35:06 +0800 Subject: iwlwifi: activate status ready timeout only for run time ucode This patch makes driver state timeout checks on ucode alive response only if run time ucode have been loaded. Signed-off-by: Ron Rindjunsky Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 1b3e82f..3bb6ac5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -156,6 +156,8 @@ static int iwl4965_load_bsm(struct iwl_priv *priv) IWL_DEBUG_INFO("Begin load bsm\n"); + priv->ucode_type = UCODE_RT; + /* make sure bootstrap program is no larger than BSM's SRAM size */ if (len > IWL_MAX_BSM_SIZE) return -EINVAL; @@ -221,8 +223,6 @@ static int iwl4965_load_bsm(struct iwl_priv *priv) iwl_release_nic_access(priv); - priv->ucode_type = UCODE_INIT; - return 0; } @@ -269,8 +269,6 @@ static int iwl4965_set_ucode_ptrs(struct iwl_priv *priv) IWL_DEBUG_INFO("Runtime uCode pointers are set.\n"); - priv->ucode_type = UCODE_RT; - return ret; } diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index eb6141e..685a84e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -804,8 +804,11 @@ static int iwl5000_alive_notify(struct iwl_priv *priv) iwl5000_send_Xtal_calib(priv); - if (priv->ucode_type == UCODE_RT) + if (priv->ucode_type == UCODE_RT) { iwl5000_send_calib_results(priv); + set_bit(STATUS_READY, &priv->status); + priv->is_open = 1; + } return 0; } diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index b3c1807..af8394c 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -4074,21 +4074,23 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw) if (test_bit(STATUS_IN_SUSPEND, &priv->status)) return 0; - /* Wait for START_ALIVE from ucode. Otherwise callbacks from + /* Wait for START_ALIVE from Run Time ucode. Otherwise callbacks from * mac80211 will not be run successfully. */ - ret = wait_event_interruptible_timeout(priv->wait_command_queue, - test_bit(STATUS_READY, &priv->status), - UCODE_READY_TIMEOUT); - if (!ret) { - if (!test_bit(STATUS_READY, &priv->status)) { - IWL_ERROR("Wait for START_ALIVE timeout after %dms.\n", - jiffies_to_msecs(UCODE_READY_TIMEOUT)); - ret = -ETIMEDOUT; - goto out_release_irq; + if (priv->ucode_type == UCODE_RT) { + ret = wait_event_interruptible_timeout(priv->wait_command_queue, + test_bit(STATUS_READY, &priv->status), + UCODE_READY_TIMEOUT); + if (!ret) { + if (!test_bit(STATUS_READY, &priv->status)) { + IWL_ERROR("START_ALIVE timeout after %dms.\n", + jiffies_to_msecs(UCODE_READY_TIMEOUT)); + ret = -ETIMEDOUT; + goto out_release_irq; + } } - } - priv->is_open = 1; + priv->is_open = 1; + } IWL_DEBUG_MAC80211("leave\n"); return 0; -- cgit v0.10.2 From 001caff0da8784989ef208af0f39d55ea07dfef5 Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Thu, 29 May 2008 16:35:07 +0800 Subject: iwlwifi: add iwl5000_tx_response structure This patch adds iwl5000_tx_repsons structure. Signed-off-by: Ron Rindjunsky Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 6f62beb..bad0e94 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -1419,6 +1419,11 @@ enum { * within the sending station (this 4965), rather than whether it was * received successfully by the destination station. */ +struct agg_tx_status { + __le16 status; + __le16 sequence; +} __attribute__ ((packed)); + struct iwl4965_tx_resp { u8 frame_count; /* 1 no aggregation, >1 aggregation */ u8 bt_kill_count; /* # blocked by bluetooth (unused for agg) */ @@ -1453,11 +1458,6 @@ struct iwl4965_tx_resp { __le32 status; /* TX status (for aggregation status of 1st frame) */ } __attribute__ ((packed)); -struct agg_tx_status { - __le16 status; - __le16 sequence; -} __attribute__ ((packed)); - struct iwl4965_tx_resp_agg { u8 frame_count; /* 1 no aggregation, >1 aggregation */ u8 reserved1; @@ -1472,6 +1472,44 @@ struct iwl4965_tx_resp_agg { /* of 1st frame) */ } __attribute__ ((packed)); +struct iwl5000_tx_resp { + u8 frame_count; /* 1 no aggregation, >1 aggregation */ + u8 bt_kill_count; /* # blocked by bluetooth (unused for agg) */ + u8 failure_rts; /* # failures due to unsuccessful RTS */ + u8 failure_frame; /* # failures due to no ACK (unused for agg) */ + + /* For non-agg: Rate at which frame was successful. + * For agg: Rate at which all frames were transmitted. */ + __le32 rate_n_flags; /* RATE_MCS_* */ + + /* For non-agg: RTS + CTS + frame tx attempts time + ACK. + * For agg: RTS + CTS + aggregation tx time + block-ack time. */ + __le16 wireless_media_time; /* uSecs */ + + __le16 reserved; + __le32 pa_power1; /* RF power amplifier measurement (not used) */ + __le32 pa_power2; + + __le32 tfd_info; + __le16 seq_ctl; + __le16 byte_cnt; + __le32 tlc_info; + /* + * For non-agg: frame status TX_STATUS_* + * For agg: status of 1st frame, AGG_TX_STATE_*; other frame status + * fields follow this one, up to frame_count. + * Bit fields: + * 11- 0: AGG_TX_STATE_* status code + * 15-12: Retry count for 1st frame in aggregation (retries + * occur if tx failed for this frame when it was a + * member of a previous aggregation block). If rate + * scaling is used, retry count indicates the rate + * table entry used for all frames in the new agg. + * 31-16: Sequence # for this frame's Tx cmd (not SSN!) + */ + struct agg_tx_status status; /* TX status (in aggregation - + * status of 1st frame) */ +} __attribute__ ((packed)); /* * REPLY_COMPRESSED_BA = 0xc5 (response only, not a command) * -- cgit v0.10.2 From a332f8d618a7bdb0096c7b21555120a1822cedec Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 29 May 2008 16:35:08 +0800 Subject: iwlwifi: move tx response common handlers to iwlcore This pach moves common tx response handlers to the header files and iwl-tx.c. Signed-off-by: Tomas Winkler Signed-off-by: Ron Rindjunsky Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index bad0e94..2652e37 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -1365,6 +1365,15 @@ enum { TX_ABORT_REQUIRED_MSK = 0x80000000, /* bits 31:31 */ }; +static inline int iwl_is_tx_success(u32 status) +{ + status &= TX_STATUS_MSK; + return (status == TX_STATUS_SUCCESS) + || (status == TX_STATUS_DIRECT_DONE); +} + + + /* ******************************* * TX aggregation status ******************************* */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 9d43085..9449b61 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -209,6 +209,8 @@ void iwl_rx_allocate(struct iwl_priv *priv); void iwl_rx_missed_beacon_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); +/* TX helpers */ + /***************************************************** * TX ******************************************************/ @@ -220,6 +222,7 @@ void iwl_hw_txq_ctx_free(struct iwl_priv *priv); int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *tfd, dma_addr_t addr, u16 len); int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq); + /***************************************************** * S e n d i n g H o s t C o m m a n d s * *****************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 291c1ec..93433130 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1242,6 +1242,36 @@ static inline void iwl_txq_ctx_deactivate(struct iwl_priv *priv, int txq_id) clear_bit(txq_id, &priv->txq_ctx_active_msk); } +#ifdef CONFIG_IWLWIF_DEBUG +const char *iwl_get_tx_fail_reason(u32 status); +#else +static inline const char *iwl_get_tx_fail_reason(u32 status) { return ""; } +#endif + + +#ifdef CONFIG_IWL4965_HT +static inline int iwl_get_ra_sta_id(struct iwl_priv *priv, + struct ieee80211_hdr *hdr) +{ + if (priv->iw_mode == IEEE80211_IF_TYPE_STA) { + return IWL_AP_ID; + } else { + u8 *da = ieee80211_get_DA(hdr); + return iwl_find_station(priv, da); + } +} + +static inline struct ieee80211_hdr *iwl_tx_queue_get_hdr(struct iwl_priv *priv, + int txq_id, int idx) +{ + if (priv->txq[txq_id].txb[idx].skb[0]) + return (struct ieee80211_hdr *)priv->txq[txq_id]. + txb[idx].skb[0]->data; + return NULL; +} +#endif + + static inline int iwl_is_associated(struct iwl_priv *priv) { return (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 0b822b5..885a4c1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -1060,3 +1060,33 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) return ret ? ret : idx; } +#ifdef CONFIG_IWLWIF_DEBUG +#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x + +const char *iwl_get_tx_fail_reason(u32 status) +{ + switch (status & TX_STATUS_MSK) { + case TX_STATUS_SUCCESS: + return "SUCCESS"; + TX_STATUS_ENTRY(SHORT_LIMIT); + TX_STATUS_ENTRY(LONG_LIMIT); + TX_STATUS_ENTRY(FIFO_UNDERRUN); + TX_STATUS_ENTRY(MGMNT_ABORT); + TX_STATUS_ENTRY(NEXT_FRAG); + TX_STATUS_ENTRY(LIFE_EXPIRE); + TX_STATUS_ENTRY(DEST_PS); + TX_STATUS_ENTRY(ABORTED); + TX_STATUS_ENTRY(BT_RETRY); + TX_STATUS_ENTRY(STA_INVALID); + TX_STATUS_ENTRY(FRAG_DROPPED); + TX_STATUS_ENTRY(TID_DISABLE); + TX_STATUS_ENTRY(FRAME_FLUSHED); + TX_STATUS_ENTRY(INSUFFICIENT_CF_POLL); + TX_STATUS_ENTRY(TX_LOCKED); + TX_STATUS_ENTRY(NO_BEACON_ON_RADAR); + } + + return "UNKNOWN"; +} +EXPORT_SYMBOL(iwl_get_tx_fail_reason); +#endif /* CONFIG_IWLWIFI_DEBUG */ diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index af8394c..411fad3 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -915,33 +915,7 @@ int iwl4965_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *heade return 1; } -#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x -static const char *iwl4965_get_tx_fail_reason(u32 status) -{ - switch (status & TX_STATUS_MSK) { - case TX_STATUS_SUCCESS: - return "SUCCESS"; - TX_STATUS_ENTRY(SHORT_LIMIT); - TX_STATUS_ENTRY(LONG_LIMIT); - TX_STATUS_ENTRY(FIFO_UNDERRUN); - TX_STATUS_ENTRY(MGMNT_ABORT); - TX_STATUS_ENTRY(NEXT_FRAG); - TX_STATUS_ENTRY(LIFE_EXPIRE); - TX_STATUS_ENTRY(DEST_PS); - TX_STATUS_ENTRY(ABORTED); - TX_STATUS_ENTRY(BT_RETRY); - TX_STATUS_ENTRY(STA_INVALID); - TX_STATUS_ENTRY(FRAG_DROPPED); - TX_STATUS_ENTRY(TID_DISABLE); - TX_STATUS_ENTRY(FRAME_FLUSHED); - TX_STATUS_ENTRY(INSUFFICIENT_CF_POLL); - TX_STATUS_ENTRY(TX_LOCKED); - TX_STATUS_ENTRY(NO_BEACON_ON_RADAR); - } - - return "UNKNOWN"; -} /** * iwl4965_scan_cancel - Cancel any currently executing HW scan @@ -1606,40 +1580,12 @@ int iwl4965_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) return nfreed; } -static int iwl4965_is_tx_success(u32 status) -{ - status &= TX_STATUS_MSK; - return (status == TX_STATUS_SUCCESS) - || (status == TX_STATUS_DIRECT_DONE); -} - /****************************************************************************** * * Generic RX handler implementations * ******************************************************************************/ #ifdef CONFIG_IWL4965_HT - -static inline int iwl4965_get_ra_sta_id(struct iwl_priv *priv, - struct ieee80211_hdr *hdr) -{ - if (priv->iw_mode == IEEE80211_IF_TYPE_STA) - return IWL_AP_ID; - else { - u8 *da = ieee80211_get_DA(hdr); - return iwl_find_station(priv, da); - } -} - -static struct ieee80211_hdr *iwl4965_tx_queue_get_hdr( - struct iwl_priv *priv, int txq_id, int idx) -{ - if (priv->txq[txq_id].txb[idx].skb[0]) - return (struct ieee80211_hdr *)priv->txq[txq_id]. - txb[idx].skb[0]->data; - return NULL; -} - static inline u32 iwl4965_get_scd_ssn(struct iwl4965_tx_resp *tx_resp) { __le32 *scd_ssn = (__le32 *)((u32 *)&tx_resp->status + @@ -1687,7 +1633,7 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv, info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]); info->status.retry_count = tx_resp->failure_frame; info->flags &= ~IEEE80211_TX_CTL_AMPDU; - info->flags |= iwl4965_is_tx_success(status)? + info->flags |= iwl_is_tx_success(status)? IEEE80211_TX_STAT_ACK : 0; iwl4965_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags), @@ -1720,7 +1666,7 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv, IWL_DEBUG_TX_REPLY("FrameCnt = %d, txq_id=%d idx=%d\n", agg->frame_count, txq_id, idx); - hdr = iwl4965_tx_queue_get_hdr(priv, txq_id, idx); + hdr = iwl_tx_queue_get_hdr(priv, txq_id, idx); sc = le16_to_cpu(hdr->seq_ctrl); if (idx != (SEQ_TO_SN(sc) & 0xff)) { @@ -1800,14 +1746,14 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, memset(&info->status, 0, sizeof(info->status)); #ifdef CONFIG_IWL4965_HT - hdr = iwl4965_tx_queue_get_hdr(priv, txq_id, index); + hdr = iwl_tx_queue_get_hdr(priv, txq_id, index); fc = le16_to_cpu(hdr->frame_control); if (ieee80211_is_qos_data(fc)) { qc = ieee80211_get_qos_ctrl(hdr, ieee80211_get_hdrlen(fc)); tid = qc[0] & 0xf; } - sta_id = iwl4965_get_ra_sta_id(priv, hdr); + sta_id = iwl_get_ra_sta_id(priv, hdr); if (txq->sched_retry && unlikely(sta_id == IWL_INVALID_STATION)) { IWL_ERROR("Station not known\n"); return; @@ -1825,8 +1771,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, iwl4965_tx_status_reply_tx(priv, agg, (struct iwl4965_tx_resp_agg *)tx_resp, index); - if ((tx_resp->frame_count == 1) && - !iwl4965_is_tx_success(status)) { + if ((tx_resp->frame_count == 1) && !iwl_is_tx_success(status)) { /* TODO: send BAR */ } @@ -1856,12 +1801,12 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, info->status.retry_count = tx_resp->failure_frame; info->flags |= - iwl4965_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0; + iwl_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0; iwl4965_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags), info); IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) rate_n_flags 0x%x " - "retries %d\n", txq_id, iwl4965_get_tx_fail_reason(status), + "retries %d\n", txq_id, iwl_get_tx_fail_reason(status), status, le32_to_cpu(tx_resp->rate_n_flags), tx_resp->failure_frame); -- cgit v0.10.2 From e532fa0e3ce3feda1f1eb14aa31caae503cd9bda Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Thu, 29 May 2008 16:35:09 +0800 Subject: iwlwlifi: impelemnt 5000 tx response path This patch implements 5000 HW tx response path. Signed-off-by: Ron Rindjunsky Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 685a84e..cfabcb0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -972,6 +972,241 @@ static void iwl5000_txq_set_sched(struct iwl_priv *priv, u32 mask) iwl_write_prph(priv, IWL50_SCD_TXFACT, mask); } + +static inline u32 iwl5000_get_scd_ssn(struct iwl5000_tx_resp *tx_resp) +{ + __le32 *scd_ssn = (__le32 *)((u32 *)&tx_resp->status + + tx_resp->frame_count); + return le32_to_cpu(*scd_ssn) & MAX_SN; + +} + +static int iwl5000_tx_status_reply_tx(struct iwl_priv *priv, + struct iwl_ht_agg *agg, + struct iwl5000_tx_resp *tx_resp, + u16 start_idx) +{ + u16 status; + struct agg_tx_status *frame_status = &tx_resp->status; + struct ieee80211_tx_info *info = NULL; + struct ieee80211_hdr *hdr = NULL; + int i, sh; + int txq_id, idx; + u16 seq; + + if (agg->wait_for_ba) + IWL_DEBUG_TX_REPLY("got tx response w/o block-ack\n"); + + agg->frame_count = tx_resp->frame_count; + agg->start_idx = start_idx; + agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags); + agg->bitmap = 0; + + /* # frames attempted by Tx command */ + if (agg->frame_count == 1) { + /* Only one frame was attempted; no block-ack will arrive */ + status = le16_to_cpu(frame_status[0].status); + seq = le16_to_cpu(frame_status[0].sequence); + idx = SEQ_TO_INDEX(seq); + txq_id = SEQ_TO_QUEUE(seq); + + /* FIXME: code repetition */ + IWL_DEBUG_TX_REPLY("FrameCnt = %d, StartIdx=%d idx=%d\n", + agg->frame_count, agg->start_idx, idx); + + info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]); + info->status.retry_count = tx_resp->failure_frame; + info->flags &= ~IEEE80211_TX_CTL_AMPDU; + info->flags |= iwl_is_tx_success(status)? + IEEE80211_TX_STAT_ACK : 0; + iwl4965_hwrate_to_tx_control(priv, + le32_to_cpu(tx_resp->rate_n_flags), + info); + /* FIXME: code repetition end */ + + IWL_DEBUG_TX_REPLY("1 Frame 0x%x failure :%d\n", + status & 0xff, tx_resp->failure_frame); + IWL_DEBUG_TX_REPLY("Rate Info rate_n_flags=%x\n", + iwl4965_hw_get_rate_n_flags(tx_resp->rate_n_flags)); + + agg->wait_for_ba = 0; + } else { + /* Two or more frames were attempted; expect block-ack */ + u64 bitmap = 0; + int start = agg->start_idx; + + /* Construct bit-map of pending frames within Tx window */ + for (i = 0; i < agg->frame_count; i++) { + u16 sc; + status = le16_to_cpu(frame_status[i].status); + seq = le16_to_cpu(frame_status[i].sequence); + idx = SEQ_TO_INDEX(seq); + txq_id = SEQ_TO_QUEUE(seq); + + if (status & (AGG_TX_STATE_FEW_BYTES_MSK | + AGG_TX_STATE_ABORT_MSK)) + continue; + + IWL_DEBUG_TX_REPLY("FrameCnt = %d, txq_id=%d idx=%d\n", + agg->frame_count, txq_id, idx); + + hdr = iwl_tx_queue_get_hdr(priv, txq_id, idx); + + sc = le16_to_cpu(hdr->seq_ctrl); + if (idx != (SEQ_TO_SN(sc) & 0xff)) { + IWL_ERROR("BUG_ON idx doesn't match seq control" + " idx=%d, seq_idx=%d, seq=%d\n", + idx, SEQ_TO_SN(sc), + hdr->seq_ctrl); + return -1; + } + + IWL_DEBUG_TX_REPLY("AGG Frame i=%d idx %d seq=%d\n", + i, idx, SEQ_TO_SN(sc)); + + sh = idx - start; + if (sh > 64) { + sh = (start - idx) + 0xff; + bitmap = bitmap << sh; + sh = 0; + start = idx; + } else if (sh < -64) + sh = 0xff - (start - idx); + else if (sh < 0) { + sh = start - idx; + start = idx; + bitmap = bitmap << sh; + sh = 0; + } + bitmap |= (1 << sh); + IWL_DEBUG_TX_REPLY("start=%d bitmap=0x%x\n", + start, (u32)(bitmap & 0xFFFFFFFF)); + } + + agg->bitmap = bitmap; + agg->start_idx = start; + agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags); + IWL_DEBUG_TX_REPLY("Frames %d start_idx=%d bitmap=0x%llx\n", + agg->frame_count, agg->start_idx, + (unsigned long long)agg->bitmap); + + if (bitmap) + agg->wait_for_ba = 1; + } + return 0; +} + +static void iwl5000_rx_reply_tx(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + u16 sequence = le16_to_cpu(pkt->hdr.sequence); + int txq_id = SEQ_TO_QUEUE(sequence); + int index = SEQ_TO_INDEX(sequence); + struct iwl_tx_queue *txq = &priv->txq[txq_id]; + struct ieee80211_tx_info *info; + struct iwl5000_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; + u32 status = le16_to_cpu(tx_resp->status.status); +#ifdef CONFIG_IWL4965_HT + int tid = MAX_TID_COUNT, sta_id = IWL_INVALID_STATION; + u16 fc; + struct ieee80211_hdr *hdr; + u8 *qc = NULL; +#endif + + if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) { + IWL_ERROR("Read index for DMA queue txq_id (%d) index %d " + "is out of range [0-%d] %d %d\n", txq_id, + index, txq->q.n_bd, txq->q.write_ptr, + txq->q.read_ptr); + return; + } + + info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]); + memset(&info->status, 0, sizeof(info->status)); + +#ifdef CONFIG_IWL4965_HT + hdr = iwl_tx_queue_get_hdr(priv, txq_id, index); + fc = le16_to_cpu(hdr->frame_control); + if (ieee80211_is_qos_data(fc)) { + qc = ieee80211_get_qos_ctrl(hdr, ieee80211_get_hdrlen(fc)); + tid = qc[0] & 0xf; + } + + sta_id = iwl_get_ra_sta_id(priv, hdr); + if (txq->sched_retry && unlikely(sta_id == IWL_INVALID_STATION)) { + IWL_ERROR("Station not known\n"); + return; + } + + if (txq->sched_retry) { + const u32 scd_ssn = iwl5000_get_scd_ssn(tx_resp); + struct iwl_ht_agg *agg = NULL; + + if (!qc) + return; + + agg = &priv->stations[sta_id].tid[tid].agg; + + iwl5000_tx_status_reply_tx(priv, agg, tx_resp, index); + + if ((tx_resp->frame_count == 1) && !iwl_is_tx_success(status)) { + /* TODO: send BAR */ + } + + if (txq->q.read_ptr != (scd_ssn & 0xff)) { + int freed, ampdu_q; + index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd); + IWL_DEBUG_TX_REPLY("Retry scheduler reclaim scd_ssn " + "%d index %d\n", scd_ssn , index); + freed = iwl4965_tx_queue_reclaim(priv, txq_id, index); + priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; + + if (iwl_queue_space(&txq->q) > txq->q.low_mark && + txq_id >= 0 && priv->mac80211_registered && + agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) { + /* calculate mac80211 ampdu sw queue to wake */ + ampdu_q = txq_id - IWL_BACK_QUEUE_FIRST_ID + + priv->hw->queues; + if (agg->state == IWL_AGG_OFF) + ieee80211_wake_queue(priv->hw, txq_id); + else + ieee80211_wake_queue(priv->hw, ampdu_q); + } + iwl4965_check_empty_hw_queue(priv, sta_id, tid, txq_id); + } + } else { +#endif /* CONFIG_IWL4965_HT */ + + info->status.retry_count = tx_resp->failure_frame; + info->flags = iwl_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0; + iwl4965_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags), + info); + + IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) rate_n_flags 0x%x " + "retries %d\n", txq_id, iwl_get_tx_fail_reason(status), + status, le32_to_cpu(tx_resp->rate_n_flags), + tx_resp->failure_frame); + + IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index); +#ifdef CONFIG_IWL4965_HT + if (index != -1) { + int freed = iwl4965_tx_queue_reclaim(priv, txq_id, index); + if (tid != MAX_TID_COUNT) + priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; + if (iwl_queue_space(&txq->q) > txq->q.low_mark && + (txq_id >= 0) && priv->mac80211_registered) + ieee80211_wake_queue(priv->hw, txq_id); + if (tid != MAX_TID_COUNT) + iwl4965_check_empty_hw_queue(priv, sta_id, tid, txq_id); + } + } +#endif /* CONFIG_IWL4965_HT */ + + if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK)) + IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n"); +} + /* Currently 5000 is the supperset of everything */ static u16 iwl5000_get_hcmd_size(u8 cmd_id, u16 len) { @@ -985,6 +1220,7 @@ static void iwl5000_rx_handler_setup(struct iwl_priv *priv) iwl5000_rx_calib_result; priv->rx_handlers[CALIBRATION_COMPLETE_NOTIFICATION] = iwl5000_rx_calib_complete; + priv->rx_handlers[REPLY_TX] = iwl5000_rx_reply_tx; } -- cgit v0.10.2 From f20217d9d57584b6c7fcfef8c4183f10ee45fddd Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 29 May 2008 16:35:10 +0800 Subject: iwlwifi: move 4965 tx response into iwl-4965.c This patch moves 4965 tx repsone into iwl-4965.c. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 3bb6ac5..98f3df0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -3477,6 +3477,251 @@ static u16 iwl4965_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data) return (u16)sizeof(struct iwl4965_addsta_cmd); } + +#ifdef CONFIG_IWL4965_HT +static inline u32 iwl4965_get_scd_ssn(struct iwl4965_tx_resp *tx_resp) +{ + __le32 *scd_ssn = (__le32 *)((u32 *)&tx_resp->status + + tx_resp->frame_count); + return le32_to_cpu(*scd_ssn) & MAX_SN; + +} + +/** + * iwl4965_tx_status_reply_tx - Handle Tx rspnse for frames in aggregation queue + */ +static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv, + struct iwl_ht_agg *agg, + struct iwl4965_tx_resp_agg *tx_resp, + u16 start_idx) +{ + u16 status; + struct agg_tx_status *frame_status = &tx_resp->status; + struct ieee80211_tx_info *info = NULL; + struct ieee80211_hdr *hdr = NULL; + int i, sh; + int txq_id, idx; + u16 seq; + + if (agg->wait_for_ba) + IWL_DEBUG_TX_REPLY("got tx response w/o block-ack\n"); + + agg->frame_count = tx_resp->frame_count; + agg->start_idx = start_idx; + agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags); + agg->bitmap = 0; + + /* # frames attempted by Tx command */ + if (agg->frame_count == 1) { + /* Only one frame was attempted; no block-ack will arrive */ + status = le16_to_cpu(frame_status[0].status); + seq = le16_to_cpu(frame_status[0].sequence); + idx = SEQ_TO_INDEX(seq); + txq_id = SEQ_TO_QUEUE(seq); + + /* FIXME: code repetition */ + IWL_DEBUG_TX_REPLY("FrameCnt = %d, StartIdx=%d idx=%d\n", + agg->frame_count, agg->start_idx, idx); + + info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]); + info->status.retry_count = tx_resp->failure_frame; + info->flags &= ~IEEE80211_TX_CTL_AMPDU; + info->flags |= iwl_is_tx_success(status)? + IEEE80211_TX_STAT_ACK : 0; + iwl4965_hwrate_to_tx_control(priv, + le32_to_cpu(tx_resp->rate_n_flags), + info); + /* FIXME: code repetition end */ + + IWL_DEBUG_TX_REPLY("1 Frame 0x%x failure :%d\n", + status & 0xff, tx_resp->failure_frame); + IWL_DEBUG_TX_REPLY("Rate Info rate_n_flags=%x\n", + iwl4965_hw_get_rate_n_flags(tx_resp->rate_n_flags)); + + agg->wait_for_ba = 0; + } else { + /* Two or more frames were attempted; expect block-ack */ + u64 bitmap = 0; + int start = agg->start_idx; + + /* Construct bit-map of pending frames within Tx window */ + for (i = 0; i < agg->frame_count; i++) { + u16 sc; + status = le16_to_cpu(frame_status[i].status); + seq = le16_to_cpu(frame_status[i].sequence); + idx = SEQ_TO_INDEX(seq); + txq_id = SEQ_TO_QUEUE(seq); + + if (status & (AGG_TX_STATE_FEW_BYTES_MSK | + AGG_TX_STATE_ABORT_MSK)) + continue; + + IWL_DEBUG_TX_REPLY("FrameCnt = %d, txq_id=%d idx=%d\n", + agg->frame_count, txq_id, idx); + + hdr = iwl_tx_queue_get_hdr(priv, txq_id, idx); + + sc = le16_to_cpu(hdr->seq_ctrl); + if (idx != (SEQ_TO_SN(sc) & 0xff)) { + IWL_ERROR("BUG_ON idx doesn't match seq control" + " idx=%d, seq_idx=%d, seq=%d\n", + idx, SEQ_TO_SN(sc), + hdr->seq_ctrl); + return -1; + } + + IWL_DEBUG_TX_REPLY("AGG Frame i=%d idx %d seq=%d\n", + i, idx, SEQ_TO_SN(sc)); + + sh = idx - start; + if (sh > 64) { + sh = (start - idx) + 0xff; + bitmap = bitmap << sh; + sh = 0; + start = idx; + } else if (sh < -64) + sh = 0xff - (start - idx); + else if (sh < 0) { + sh = start - idx; + start = idx; + bitmap = bitmap << sh; + sh = 0; + } + bitmap |= (1 << sh); + IWL_DEBUG_TX_REPLY("start=%d bitmap=0x%x\n", + start, (u32)(bitmap & 0xFFFFFFFF)); + } + + agg->bitmap = bitmap; + agg->start_idx = start; + agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags); + IWL_DEBUG_TX_REPLY("Frames %d start_idx=%d bitmap=0x%llx\n", + agg->frame_count, agg->start_idx, + (unsigned long long)agg->bitmap); + + if (bitmap) + agg->wait_for_ba = 1; + } + return 0; +} +#endif + +/** + * iwl4965_rx_reply_tx - Handle standard (non-aggregation) Tx response + */ +static void iwl4965_rx_reply_tx(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + u16 sequence = le16_to_cpu(pkt->hdr.sequence); + int txq_id = SEQ_TO_QUEUE(sequence); + int index = SEQ_TO_INDEX(sequence); + struct iwl_tx_queue *txq = &priv->txq[txq_id]; + struct ieee80211_tx_info *info; + struct iwl4965_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; + u32 status = le32_to_cpu(tx_resp->status); +#ifdef CONFIG_IWL4965_HT + int tid = MAX_TID_COUNT, sta_id = IWL_INVALID_STATION; + u16 fc; + struct ieee80211_hdr *hdr; + u8 *qc = NULL; +#endif + + if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) { + IWL_ERROR("Read index for DMA queue txq_id (%d) index %d " + "is out of range [0-%d] %d %d\n", txq_id, + index, txq->q.n_bd, txq->q.write_ptr, + txq->q.read_ptr); + return; + } + + info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]); + memset(&info->status, 0, sizeof(info->status)); + +#ifdef CONFIG_IWL4965_HT + hdr = iwl_tx_queue_get_hdr(priv, txq_id, index); + fc = le16_to_cpu(hdr->frame_control); + if (ieee80211_is_qos_data(fc)) { + qc = ieee80211_get_qos_ctrl(hdr, ieee80211_get_hdrlen(fc)); + tid = qc[0] & 0xf; + } + + sta_id = iwl_get_ra_sta_id(priv, hdr); + if (txq->sched_retry && unlikely(sta_id == IWL_INVALID_STATION)) { + IWL_ERROR("Station not known\n"); + return; + } + + if (txq->sched_retry) { + const u32 scd_ssn = iwl4965_get_scd_ssn(tx_resp); + struct iwl_ht_agg *agg = NULL; + + if (!qc) + return; + + agg = &priv->stations[sta_id].tid[tid].agg; + + iwl4965_tx_status_reply_tx(priv, agg, + (struct iwl4965_tx_resp_agg *)tx_resp, index); + + if ((tx_resp->frame_count == 1) && !iwl_is_tx_success(status)) { + /* TODO: send BAR */ + } + + if (txq->q.read_ptr != (scd_ssn & 0xff)) { + int freed, ampdu_q; + index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd); + IWL_DEBUG_TX_REPLY("Retry scheduler reclaim scd_ssn " + "%d index %d\n", scd_ssn , index); + freed = iwl4965_tx_queue_reclaim(priv, txq_id, index); + priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; + + if (iwl_queue_space(&txq->q) > txq->q.low_mark && + txq_id >= 0 && priv->mac80211_registered && + agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) { + /* calculate mac80211 ampdu sw queue to wake */ + ampdu_q = txq_id - IWL_BACK_QUEUE_FIRST_ID + + priv->hw->queues; + if (agg->state == IWL_AGG_OFF) + ieee80211_wake_queue(priv->hw, txq_id); + else + ieee80211_wake_queue(priv->hw, ampdu_q); + } + iwl4965_check_empty_hw_queue(priv, sta_id, tid, txq_id); + } + } else { +#endif /* CONFIG_IWL4965_HT */ + + info->status.retry_count = tx_resp->failure_frame; + info->flags |= iwl_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0; + iwl4965_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags), + info); + + IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) rate_n_flags 0x%x " + "retries %d\n", txq_id, iwl_get_tx_fail_reason(status), + status, le32_to_cpu(tx_resp->rate_n_flags), + tx_resp->failure_frame); + + IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index); +#ifdef CONFIG_IWL4965_HT + if (index != -1) { + int freed = iwl4965_tx_queue_reclaim(priv, txq_id, index); + if (tid != MAX_TID_COUNT) + priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; + if (iwl_queue_space(&txq->q) > txq->q.low_mark && + (txq_id >= 0) && priv->mac80211_registered) + ieee80211_wake_queue(priv->hw, txq_id); + if (tid != MAX_TID_COUNT) + iwl4965_check_empty_hw_queue(priv, sta_id, tid, txq_id); + } + } +#endif /* CONFIG_IWL4965_HT */ + + if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK)) + IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n"); +} + + /* Set up 4965-specific Rx frame reply handlers */ static void iwl4965_rx_handler_setup(struct iwl_priv *priv) { @@ -3487,6 +3732,8 @@ static void iwl4965_rx_handler_setup(struct iwl_priv *priv) priv->rx_handlers[REPLY_RX_PHY_CMD] = iwl4965_rx_reply_rx_phy; priv->rx_handlers[REPLY_RX_MPDU_CMD] = iwl4965_rx_reply_rx; + priv->rx_handlers[REPLY_TX] = iwl4965_rx_reply_tx; + #ifdef CONFIG_IWL4965_HT priv->rx_handlers[REPLY_COMPRESSED_BA] = iwl4965_rx_reply_compressed_ba; #endif /* CONFIG_IWL4965_HT */ diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 411fad3..10d7734 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -1585,251 +1585,6 @@ int iwl4965_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) * Generic RX handler implementations * ******************************************************************************/ -#ifdef CONFIG_IWL4965_HT -static inline u32 iwl4965_get_scd_ssn(struct iwl4965_tx_resp *tx_resp) -{ - __le32 *scd_ssn = (__le32 *)((u32 *)&tx_resp->status + - tx_resp->frame_count); - return le32_to_cpu(*scd_ssn) & MAX_SN; - -} - -/** - * iwl4965_tx_status_reply_tx - Handle Tx rspnse for frames in aggregation queue - */ -static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv, - struct iwl_ht_agg *agg, - struct iwl4965_tx_resp_agg *tx_resp, - u16 start_idx) -{ - u16 status; - struct agg_tx_status *frame_status = &tx_resp->status; - struct ieee80211_tx_info *info = NULL; - struct ieee80211_hdr *hdr = NULL; - int i, sh; - int txq_id, idx; - u16 seq; - - if (agg->wait_for_ba) - IWL_DEBUG_TX_REPLY("got tx response w/o block-ack\n"); - - agg->frame_count = tx_resp->frame_count; - agg->start_idx = start_idx; - agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags); - agg->bitmap = 0; - - /* # frames attempted by Tx command */ - if (agg->frame_count == 1) { - /* Only one frame was attempted; no block-ack will arrive */ - status = le16_to_cpu(frame_status[0].status); - seq = le16_to_cpu(frame_status[0].sequence); - idx = SEQ_TO_INDEX(seq); - txq_id = SEQ_TO_QUEUE(seq); - - /* FIXME: code repetition */ - IWL_DEBUG_TX_REPLY("FrameCnt = %d, StartIdx=%d idx=%d\n", - agg->frame_count, agg->start_idx, idx); - - info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]); - info->status.retry_count = tx_resp->failure_frame; - info->flags &= ~IEEE80211_TX_CTL_AMPDU; - info->flags |= iwl_is_tx_success(status)? - IEEE80211_TX_STAT_ACK : 0; - iwl4965_hwrate_to_tx_control(priv, - le32_to_cpu(tx_resp->rate_n_flags), - info); - /* FIXME: code repetition end */ - - IWL_DEBUG_TX_REPLY("1 Frame 0x%x failure :%d\n", - status & 0xff, tx_resp->failure_frame); - IWL_DEBUG_TX_REPLY("Rate Info rate_n_flags=%x\n", - iwl4965_hw_get_rate_n_flags(tx_resp->rate_n_flags)); - - agg->wait_for_ba = 0; - } else { - /* Two or more frames were attempted; expect block-ack */ - u64 bitmap = 0; - int start = agg->start_idx; - - /* Construct bit-map of pending frames within Tx window */ - for (i = 0; i < agg->frame_count; i++) { - u16 sc; - status = le16_to_cpu(frame_status[i].status); - seq = le16_to_cpu(frame_status[i].sequence); - idx = SEQ_TO_INDEX(seq); - txq_id = SEQ_TO_QUEUE(seq); - - if (status & (AGG_TX_STATE_FEW_BYTES_MSK | - AGG_TX_STATE_ABORT_MSK)) - continue; - - IWL_DEBUG_TX_REPLY("FrameCnt = %d, txq_id=%d idx=%d\n", - agg->frame_count, txq_id, idx); - - hdr = iwl_tx_queue_get_hdr(priv, txq_id, idx); - - sc = le16_to_cpu(hdr->seq_ctrl); - if (idx != (SEQ_TO_SN(sc) & 0xff)) { - IWL_ERROR("BUG_ON idx doesn't match seq control" - " idx=%d, seq_idx=%d, seq=%d\n", - idx, SEQ_TO_SN(sc), - hdr->seq_ctrl); - return -1; - } - - IWL_DEBUG_TX_REPLY("AGG Frame i=%d idx %d seq=%d\n", - i, idx, SEQ_TO_SN(sc)); - - sh = idx - start; - if (sh > 64) { - sh = (start - idx) + 0xff; - bitmap = bitmap << sh; - sh = 0; - start = idx; - } else if (sh < -64) - sh = 0xff - (start - idx); - else if (sh < 0) { - sh = start - idx; - start = idx; - bitmap = bitmap << sh; - sh = 0; - } - bitmap |= (1 << sh); - IWL_DEBUG_TX_REPLY("start=%d bitmap=0x%x\n", - start, (u32)(bitmap & 0xFFFFFFFF)); - } - - agg->bitmap = bitmap; - agg->start_idx = start; - agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags); - IWL_DEBUG_TX_REPLY("Frames %d start_idx=%d bitmap=0x%llx\n", - agg->frame_count, agg->start_idx, - (unsigned long long)agg->bitmap); - - if (bitmap) - agg->wait_for_ba = 1; - } - return 0; -} -#endif - -/** - * iwl4965_rx_reply_tx - Handle standard (non-aggregation) Tx response - */ -static void iwl4965_rx_reply_tx(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - u16 sequence = le16_to_cpu(pkt->hdr.sequence); - int txq_id = SEQ_TO_QUEUE(sequence); - int index = SEQ_TO_INDEX(sequence); - struct iwl_tx_queue *txq = &priv->txq[txq_id]; - struct ieee80211_tx_info *info; - struct iwl4965_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; - u32 status = le32_to_cpu(tx_resp->status); -#ifdef CONFIG_IWL4965_HT - int tid = MAX_TID_COUNT, sta_id = IWL_INVALID_STATION; - u16 fc; - struct ieee80211_hdr *hdr; - u8 *qc = NULL; -#endif - - if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) { - IWL_ERROR("Read index for DMA queue txq_id (%d) index %d " - "is out of range [0-%d] %d %d\n", txq_id, - index, txq->q.n_bd, txq->q.write_ptr, - txq->q.read_ptr); - return; - } - - info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]); - memset(&info->status, 0, sizeof(info->status)); - -#ifdef CONFIG_IWL4965_HT - hdr = iwl_tx_queue_get_hdr(priv, txq_id, index); - fc = le16_to_cpu(hdr->frame_control); - if (ieee80211_is_qos_data(fc)) { - qc = ieee80211_get_qos_ctrl(hdr, ieee80211_get_hdrlen(fc)); - tid = qc[0] & 0xf; - } - - sta_id = iwl_get_ra_sta_id(priv, hdr); - if (txq->sched_retry && unlikely(sta_id == IWL_INVALID_STATION)) { - IWL_ERROR("Station not known\n"); - return; - } - - if (txq->sched_retry) { - const u32 scd_ssn = iwl4965_get_scd_ssn(tx_resp); - struct iwl_ht_agg *agg = NULL; - - if (!qc) - return; - - agg = &priv->stations[sta_id].tid[tid].agg; - - iwl4965_tx_status_reply_tx(priv, agg, - (struct iwl4965_tx_resp_agg *)tx_resp, index); - - if ((tx_resp->frame_count == 1) && !iwl_is_tx_success(status)) { - /* TODO: send BAR */ - } - - if (txq->q.read_ptr != (scd_ssn & 0xff)) { - int freed, ampdu_q; - index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd); - IWL_DEBUG_TX_REPLY("Retry scheduler reclaim scd_ssn " - "%d index %d\n", scd_ssn , index); - freed = iwl4965_tx_queue_reclaim(priv, txq_id, index); - priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; - - if (iwl_queue_space(&txq->q) > txq->q.low_mark && - txq_id >= 0 && priv->mac80211_registered && - agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) { - /* calculate mac80211 ampdu sw queue to wake */ - ampdu_q = txq_id - IWL_BACK_QUEUE_FIRST_ID + - priv->hw->queues; - if (agg->state == IWL_AGG_OFF) - ieee80211_wake_queue(priv->hw, txq_id); - else - ieee80211_wake_queue(priv->hw, ampdu_q); - } - iwl4965_check_empty_hw_queue(priv, sta_id, tid, txq_id); - } - } else { -#endif /* CONFIG_IWL4965_HT */ - - info->status.retry_count = tx_resp->failure_frame; - info->flags |= - iwl_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0; - iwl4965_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags), - info); - - IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) rate_n_flags 0x%x " - "retries %d\n", txq_id, iwl_get_tx_fail_reason(status), - status, le32_to_cpu(tx_resp->rate_n_flags), - tx_resp->failure_frame); - - IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index); -#ifdef CONFIG_IWL4965_HT - if (index != -1) { - int freed = iwl4965_tx_queue_reclaim(priv, txq_id, index); - if (tid != MAX_TID_COUNT) - priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; - if (iwl_queue_space(&txq->q) > txq->q.low_mark && - (txq_id >= 0) && priv->mac80211_registered) - ieee80211_wake_queue(priv->hw, txq_id); - if (tid != MAX_TID_COUNT) - iwl4965_check_empty_hw_queue(priv, sta_id, tid, txq_id); - } - } -#endif /* CONFIG_IWL4965_HT */ - - if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK)) - IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n"); -} - - static void iwl_rx_reply_alive(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { @@ -2198,7 +1953,6 @@ static void iwl4965_setup_rx_handlers(struct iwl_priv *priv) priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] = iwl4965_rx_scan_complete_notif; priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl4965_rx_card_state_notif; - priv->rx_handlers[REPLY_TX] = iwl4965_rx_reply_tx; priv->rx_handlers[MISSED_BEACONS_NOTIFICATION] = iwl_rx_missed_beacon_notif; -- cgit v0.10.2 From a5e8b5056ea8762e67c9fa980c8db48009ed2a67 Mon Sep 17 00:00:00 2001 From: Guy Cohen Date: Thu, 29 May 2008 16:35:11 +0800 Subject: iwlwifi: fix in-column rate scaling This patch fixes cases that the code raised or didn't decrease the rate although the success ratio was not good. Signed-off-by: Guy Cohen Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index f28b3cc..a89639f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -1336,7 +1336,7 @@ static int rs_move_legacy_other(struct iwl_priv *priv, lq_sta->search_better_tbl = 1; goto out; } - + break; case IWL_LEGACY_SWITCH_SISO: IWL_DEBUG_RATE("LQ: Legacy switch to SISO\n"); @@ -1422,9 +1422,9 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, lq_sta->search_better_tbl = 1; goto out; } - + break; case IWL_SISO_SWITCH_MIMO2: - IWL_DEBUG_RATE("LQ: SISO switch to MIMO\n"); + IWL_DEBUG_RATE("LQ: SISO switch to MIMO2\n"); memcpy(search_tbl, tbl, sz); search_tbl->is_SGI = 0; search_tbl->ant_type = ANT_AB; /*FIXME:RS*/ @@ -1689,6 +1689,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, u8 active_tbl = 0; u8 done_search = 0; u16 high_low; + s32 sr; #ifdef CONFIG_IWL4965_HT u8 tid = MAX_TID_COUNT; #endif @@ -1864,6 +1865,8 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, low = high_low & 0xff; high = (high_low >> 8) & 0xff; + sr = window->success_ratio; + /* Collect measured throughputs for current and adjacent rates */ current_tpt = window->average_tpt; if (low != IWL_RATE_INVALID) @@ -1871,19 +1874,22 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, if (high != IWL_RATE_INVALID) high_tpt = tbl->win[high].average_tpt; - /* Assume rate increase */ - scale_action = 1; + scale_action = 0; /* Too many failures, decrease rate */ - if ((window->success_ratio <= IWL_RATE_DECREASE_TH) || - (current_tpt == 0)) { + if ((sr <= IWL_RATE_DECREASE_TH) || (current_tpt == 0)) { IWL_DEBUG_RATE("decrease rate because of low success_ratio\n"); scale_action = -1; /* No throughput measured yet for adjacent rates; try increase. */ } else if ((low_tpt == IWL_INVALID_VALUE) && - (high_tpt == IWL_INVALID_VALUE)) - scale_action = 1; + (high_tpt == IWL_INVALID_VALUE)) { + + if (high != IWL_RATE_INVALID && sr >= IWL_RATE_INCREASE_TH) + scale_action = 1; + else if (low != IWL_RATE_INVALID) + scale_action = -1; + } /* Both adjacent throughputs are measured, but neither one has better * throughput; we're using the best rate, don't change it! */ @@ -1899,9 +1905,10 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, /* Higher adjacent rate's throughput is measured */ if (high_tpt != IWL_INVALID_VALUE) { /* Higher rate has better throughput */ - if (high_tpt > current_tpt) + if (high_tpt > current_tpt && + sr >= IWL_RATE_INCREASE_TH) { scale_action = 1; - else { + } else { IWL_DEBUG_RATE ("decrease rate because of high tpt\n"); scale_action = -1; @@ -1914,23 +1921,17 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, IWL_DEBUG_RATE ("decrease rate because of low tpt\n"); scale_action = -1; - } else + } else if (sr >= IWL_RATE_INCREASE_TH) { scale_action = 1; + } } } /* Sanity check; asked for decrease, but success rate or throughput * has been good at old rate. Don't change it. */ - if (scale_action == -1) { - if ((low != IWL_RATE_INVALID) && - ((window->success_ratio > IWL_RATE_HIGH_TH) || + if ((scale_action == -1) && (low != IWL_RATE_INVALID) && + ((sr > IWL_RATE_HIGH_TH) || (current_tpt > (100 * tbl->expected_tpt[low])))) - scale_action = 0; - - /* Sanity check; asked for increase, but success rate has not been great - * even at old rate, higher rate will be worse. Don't change it. */ - } else if ((scale_action == 1) && - (window->success_ratio < IWL_RATE_INCREASE_TH)) scale_action = 0; switch (scale_action) { @@ -1959,7 +1960,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, "high %d type %d\n", index, scale_action, low, high, tbl->lq_type); - lq_update: +lq_update: /* Replace uCode's rate table for the destination station. */ if (update_lq) { rate = rate_n_flags_from_tbl(tbl, index, is_green); -- cgit v0.10.2 From 17b889290a184b52ee394c31dd5a52b8c1b3456d Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 29 May 2008 16:35:12 +0800 Subject: iwlwifi: move tx reclaim flow into iwl-tx This patch 1. moves TX reclaim flow into iwl-tx 2. separates command queue and tx queue reclaim flow Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 98f3df0..1d95e8c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -3132,7 +3132,7 @@ static void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv, /* calculate mac80211 ampdu sw queue to wake */ int ampdu_q = scd_flow - IWL_BACK_QUEUE_FIRST_ID + priv->hw->queues; - int freed = iwl4965_tx_queue_reclaim(priv, scd_flow, index); + int freed = iwl_tx_queue_reclaim(priv, scd_flow, index); priv->stations[ba_resp->sta_id]. tid[ba_resp->tid].tfds_in_queue -= freed; if (iwl_queue_space(&txq->q) > txq->q.low_mark && @@ -3673,7 +3673,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd); IWL_DEBUG_TX_REPLY("Retry scheduler reclaim scd_ssn " "%d index %d\n", scd_ssn , index); - freed = iwl4965_tx_queue_reclaim(priv, txq_id, index); + freed = iwl_tx_queue_reclaim(priv, txq_id, index); priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; if (iwl_queue_space(&txq->q) > txq->q.low_mark && @@ -3705,7 +3705,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index); #ifdef CONFIG_IWL4965_HT if (index != -1) { - int freed = iwl4965_tx_queue_reclaim(priv, txq_id, index); + int freed = iwl_tx_queue_reclaim(priv, txq_id, index); if (tid != MAX_TID_COUNT) priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; if (iwl_queue_space(&txq->q) > txq->q.low_mark && diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index cfabcb0..dc9f3b6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1159,7 +1159,7 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv, index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd); IWL_DEBUG_TX_REPLY("Retry scheduler reclaim scd_ssn " "%d index %d\n", scd_ssn , index); - freed = iwl4965_tx_queue_reclaim(priv, txq_id, index); + freed = iwl_tx_queue_reclaim(priv, txq_id, index); priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; if (iwl_queue_space(&txq->q) > txq->q.low_mark && @@ -1191,7 +1191,7 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv, IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index); #ifdef CONFIG_IWL4965_HT if (index != -1) { - int freed = iwl4965_tx_queue_reclaim(priv, txq_id, index); + int freed = iwl_tx_queue_reclaim(priv, txq_id, index); if (tid != MAX_TID_COUNT) priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; if (iwl_queue_space(&txq->q) > txq->q.low_mark && diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 9449b61..8264b4e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -205,6 +205,8 @@ int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq); int iwl_rx_queue_restock(struct iwl_priv *priv); int iwl_rx_queue_space(const struct iwl_rx_queue *q); void iwl_rx_allocate(struct iwl_priv *priv); +void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); +int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index); /* Handlers */ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 93433130..8c258d6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -714,7 +714,6 @@ extern int iwl4965_get_temperature(const struct iwl_priv *priv); extern u8 iwl_find_station(struct iwl_priv *priv, const u8 *bssid); extern int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel); -extern int iwl4965_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index); extern int iwl_queue_space(const struct iwl_queue *q); static inline int iwl_queue_used(const struct iwl_queue *q, int i) { diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 885a4c1..b2b2ed2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -1060,6 +1060,114 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) return ret ? ret : idx; } +int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) +{ + struct iwl_tx_queue *txq = &priv->txq[txq_id]; + struct iwl_queue *q = &txq->q; + struct iwl_tx_info *tx_info; + int nfreed = 0; + + if ((index >= q->n_bd) || (iwl_queue_used(q, index) == 0)) { + IWL_ERROR("Read index for DMA queue txq id (%d), index %d, " + "is out of range [0-%d] %d %d.\n", txq_id, + index, q->n_bd, q->write_ptr, q->read_ptr); + return 0; + } + + for (index = iwl_queue_inc_wrap(index, q->n_bd); q->read_ptr != index; + q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { + + tx_info = &txq->txb[txq->q.read_ptr]; + ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb[0]); + tx_info->skb[0] = NULL; + iwl_hw_txq_free_tfd(priv, txq); + + nfreed++; + } + return nfreed; +} +EXPORT_SYMBOL(iwl_tx_queue_reclaim); + + +/** + * iwl_hcmd_queue_reclaim - Reclaim TX command queue entries already Tx'd + * + * When FW advances 'R' index, all entries between old and new 'R' index + * need to be reclaimed. As result, some free space forms. If there is + * enough free space (> low mark), wake the stack that feeds us. + */ +static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) +{ + struct iwl_tx_queue *txq = &priv->txq[txq_id]; + struct iwl_queue *q = &txq->q; + int nfreed = 0; + + if ((index >= q->n_bd) || (iwl_queue_used(q, index) == 0)) { + IWL_ERROR("Read index for DMA queue txq id (%d), index %d, " + "is out of range [0-%d] %d %d.\n", txq_id, + index, q->n_bd, q->write_ptr, q->read_ptr); + return; + } + + for (index = iwl_queue_inc_wrap(index, q->n_bd); q->read_ptr != index; + q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { + + if (nfreed > 1) { + IWL_ERROR("HCMD skipped: index (%d) %d %d\n", index, + q->write_ptr, q->read_ptr); + queue_work(priv->workqueue, &priv->restart); + } + nfreed++; + } +} + +/** + * iwl_tx_cmd_complete - Pull unused buffers off the queue and reclaim them + * @rxb: Rx buffer to reclaim + * + * If an Rx buffer has an async callback associated with it the callback + * will be executed. The attached skb (if present) will only be freed + * if the callback returns 1 + */ +void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + u16 sequence = le16_to_cpu(pkt->hdr.sequence); + int txq_id = SEQ_TO_QUEUE(sequence); + int index = SEQ_TO_INDEX(sequence); + int huge = sequence & SEQ_HUGE_FRAME; + int cmd_index; + struct iwl_cmd *cmd; + + /* If a Tx command is being handled and it isn't in the actual + * command queue then there a command routing bug has been introduced + * in the queue management code. */ + if (txq_id != IWL_CMD_QUEUE_NUM) + IWL_ERROR("Error wrong command queue %d command id 0x%X\n", + txq_id, pkt->hdr.cmd); + BUG_ON(txq_id != IWL_CMD_QUEUE_NUM); + + cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge); + cmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index]; + + /* Input error checking is done when commands are added to queue. */ + if (cmd->meta.flags & CMD_WANT_SKB) { + cmd->meta.source->u.skb = rxb->skb; + rxb->skb = NULL; + } else if (cmd->meta.u.callback && + !cmd->meta.u.callback(priv, cmd, rxb->skb)) + rxb->skb = NULL; + + iwl_hcmd_queue_reclaim(priv, txq_id, index); + + if (!(cmd->meta.flags & CMD_ASYNC)) { + clear_bit(STATUS_HCMD_ACTIVE, &priv->status); + wake_up_interruptible(&priv->wait_command_queue); + } +} +EXPORT_SYMBOL(iwl_tx_cmd_complete); + + #ifdef CONFIG_IWLWIF_DEBUG #define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 10d7734..4322cd6 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -1535,51 +1535,6 @@ static int iwl4965_get_measurement(struct iwl_priv *priv, } #endif -static void iwl4965_txstatus_to_ieee(struct iwl_priv *priv, - struct iwl_tx_info *tx_sta) -{ - ieee80211_tx_status_irqsafe(priv->hw, tx_sta->skb[0]); - tx_sta->skb[0] = NULL; -} - -/** - * iwl4965_tx_queue_reclaim - Reclaim Tx queue entries already Tx'd - * - * When FW advances 'R' index, all entries between old and new 'R' index - * need to be reclaimed. As result, some free space forms. If there is - * enough free space (> low mark), wake the stack that feeds us. - */ -int iwl4965_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) -{ - struct iwl_tx_queue *txq = &priv->txq[txq_id]; - struct iwl_queue *q = &txq->q; - int nfreed = 0; - - if ((index >= q->n_bd) || (iwl_queue_used(q, index) == 0)) { - IWL_ERROR("Read index for DMA queue txq id (%d), index %d, " - "is out of range [0-%d] %d %d.\n", txq_id, - index, q->n_bd, q->write_ptr, q->read_ptr); - return 0; - } - - for (index = iwl_queue_inc_wrap(index, q->n_bd); - q->read_ptr != index; - q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { - if (txq_id != IWL_CMD_QUEUE_NUM) { - iwl4965_txstatus_to_ieee(priv, - &(txq->txb[txq->q.read_ptr])); - iwl_hw_txq_free_tfd(priv, txq); - } else if (nfreed > 1) { - IWL_ERROR("HCMD skipped: index (%d) %d %d\n", index, - q->write_ptr, q->read_ptr); - queue_work(priv->workqueue, &priv->restart); - } - nfreed++; - } - - return nfreed; -} - /****************************************************************************** * * Generic RX handler implementations @@ -1961,52 +1916,6 @@ static void iwl4965_setup_rx_handlers(struct iwl_priv *priv) priv->cfg->ops->lib->rx_handler_setup(priv); } -/** - * iwl4965_tx_cmd_complete - Pull unused buffers off the queue and reclaim them - * @rxb: Rx buffer to reclaim - * - * If an Rx buffer has an async callback associated with it the callback - * will be executed. The attached skb (if present) will only be freed - * if the callback returns 1 - */ -static void iwl4965_tx_cmd_complete(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - u16 sequence = le16_to_cpu(pkt->hdr.sequence); - int txq_id = SEQ_TO_QUEUE(sequence); - int index = SEQ_TO_INDEX(sequence); - int huge = sequence & SEQ_HUGE_FRAME; - int cmd_index; - struct iwl_cmd *cmd; - - /* If a Tx command is being handled and it isn't in the actual - * command queue then there a command routing bug has been introduced - * in the queue management code. */ - if (txq_id != IWL_CMD_QUEUE_NUM) - IWL_ERROR("Error wrong command queue %d command id 0x%X\n", - txq_id, pkt->hdr.cmd); - BUG_ON(txq_id != IWL_CMD_QUEUE_NUM); - - cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge); - cmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index]; - - /* Input error checking is done when commands are added to queue. */ - if (cmd->meta.flags & CMD_WANT_SKB) { - cmd->meta.source->u.skb = rxb->skb; - rxb->skb = NULL; - } else if (cmd->meta.u.callback && - !cmd->meta.u.callback(priv, cmd, rxb->skb)) - rxb->skb = NULL; - - iwl4965_tx_queue_reclaim(priv, txq_id, index); - - if (!(cmd->meta.flags & CMD_ASYNC)) { - clear_bit(STATUS_HCMD_ACTIVE, &priv->status); - wake_up_interruptible(&priv->wait_command_queue); - } -} - /* * this should be called while priv->lock is locked */ @@ -2095,7 +2004,7 @@ void iwl_rx_handle(struct iwl_priv *priv) * fire off the (possibly) blocking iwl_send_cmd() * as we reclaim the driver command queue */ if (rxb && rxb->skb) - iwl4965_tx_cmd_complete(priv, rxb); + iwl_tx_cmd_complete(priv, rxb); else IWL_WARNING("Claim null rxb?\n"); } -- cgit v0.10.2 From 972cf447d20df30dbd74edfc00ae179c4b822c68 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 29 May 2008 16:35:13 +0800 Subject: iwlwifi: implement txq invalidate byte count table This is required to overcome a bug in 5000 HW byte count table. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index dc9f3b6..6a10526 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -955,6 +955,26 @@ static void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv, } } +static void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv, + struct iwl_tx_queue *txq) +{ + int txq_id = txq->q.id; + struct iwl5000_shared *shared_data = priv->shared_virt; + u8 sta = 0; + + if (txq_id != IWL_CMD_QUEUE_NUM) + sta = txq->cmd[txq->q.read_ptr].cmd.tx.sta_id; + + shared_data->queues_byte_cnt_tbls[txq_id].tfd_offset[txq->q.read_ptr]. + val = cpu_to_le16(1 | (sta << 12)); + + if (txq->q.write_ptr < IWL50_MAX_WIN_SIZE) { + shared_data->queues_byte_cnt_tbls[txq_id]. + tfd_offset[IWL50_QUEUE_SIZE + txq->q.read_ptr]. + val = cpu_to_le16(1 | (sta << 12)); + } +} + static u16 iwl5000_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data) { u16 size = (u16)sizeof(struct iwl_addsta_cmd); @@ -1248,6 +1268,7 @@ static struct iwl_lib_ops iwl5000_lib = { .free_shared_mem = iwl5000_free_shared_mem, .shared_mem_rx_idx = iwl5000_shared_mem_rx_idx, .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, + .txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl, .txq_set_sched = iwl5000_txq_set_sched, .rx_handler_setup = iwl5000_rx_handler_setup, .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 8264b4e..1941a91 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -107,10 +107,12 @@ struct iwl_lib_ops { void (*txq_update_byte_cnt_tbl)(struct iwl_priv *priv, struct iwl_tx_queue *txq, u16 byte_cnt); + void (*txq_inval_byte_cnt_tbl)(struct iwl_priv *priv, + struct iwl_tx_queue *txq); + void (*txq_set_sched)(struct iwl_priv *priv, u32 mask); /* setup Rx handler */ void (*rx_handler_setup)(struct iwl_priv *priv); /* nic Tx fifo handling */ - void (*txq_set_sched)(struct iwl_priv *priv, u32 mask); /* alive notification after init uCode load */ void (*init_alive_start)(struct iwl_priv *priv); /* alive notification */ diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index b2b2ed2..224bcec 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -1080,8 +1080,11 @@ int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) tx_info = &txq->txb[txq->q.read_ptr]; ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb[0]); tx_info->skb[0] = NULL; - iwl_hw_txq_free_tfd(priv, txq); + if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl) + priv->cfg->ops->lib->txq_inval_byte_cnt_tbl(priv, txq); + + iwl_hw_txq_free_tfd(priv, txq); nfreed++; } return nfreed; -- cgit v0.10.2 From fe7a90c2b73f0c1da0882861cd015c835ed28781 Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Thu, 29 May 2008 16:35:14 +0800 Subject: iwlwifi: iwl-5000 add rxon_assoc This patch adds rxon assoc command for 5000 HW. Signed-off-by: Ron Rindjunsky Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 6a10526..217c6a9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1250,7 +1250,55 @@ static int iwl5000_hw_valid_rtc_data_addr(u32 addr) (addr < IWL50_RTC_DATA_UPPER_BOUND); } +static int iwl5000_send_rxon_assoc(struct iwl_priv *priv) +{ + int ret = 0; + struct iwl5000_rxon_assoc_cmd rxon_assoc; + const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon; + const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon; + + if ((rxon1->flags == rxon2->flags) && + (rxon1->filter_flags == rxon2->filter_flags) && + (rxon1->cck_basic_rates == rxon2->cck_basic_rates) && + (rxon1->ofdm_ht_single_stream_basic_rates == + rxon2->ofdm_ht_single_stream_basic_rates) && + (rxon1->ofdm_ht_dual_stream_basic_rates == + rxon2->ofdm_ht_dual_stream_basic_rates) && + (rxon1->ofdm_ht_triple_stream_basic_rates == + rxon2->ofdm_ht_triple_stream_basic_rates) && + (rxon1->acquisition_data == rxon2->acquisition_data) && + (rxon1->rx_chain == rxon2->rx_chain) && + (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) { + IWL_DEBUG_INFO("Using current RXON_ASSOC. Not resending.\n"); + return 0; + } + + rxon_assoc.flags = priv->staging_rxon.flags; + rxon_assoc.filter_flags = priv->staging_rxon.filter_flags; + rxon_assoc.ofdm_basic_rates = priv->staging_rxon.ofdm_basic_rates; + rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates; + rxon_assoc.reserved1 = 0; + rxon_assoc.reserved2 = 0; + rxon_assoc.reserved3 = 0; + rxon_assoc.ofdm_ht_single_stream_basic_rates = + priv->staging_rxon.ofdm_ht_single_stream_basic_rates; + rxon_assoc.ofdm_ht_dual_stream_basic_rates = + priv->staging_rxon.ofdm_ht_dual_stream_basic_rates; + rxon_assoc.rx_chain_select_flags = priv->staging_rxon.rx_chain; + rxon_assoc.ofdm_ht_triple_stream_basic_rates = + priv->staging_rxon.ofdm_ht_triple_stream_basic_rates; + rxon_assoc.acquisition_data = priv->staging_rxon.acquisition_data; + + ret = iwl_send_cmd_pdu_async(priv, REPLY_RXON_ASSOC, + sizeof(rxon_assoc), &rxon_assoc, NULL); + if (ret) + return ret; + + return ret; +} + static struct iwl_hcmd_ops iwl5000_hcmd = { + .rxon_assoc = iwl5000_send_rxon_assoc, }; static struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = { diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 2652e37..fb6f5ff 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -630,6 +630,20 @@ struct iwl_rxon_cmd { __le16 reserved6; } __attribute__ ((packed)); +struct iwl5000_rxon_assoc_cmd { + __le32 flags; + __le32 filter_flags; + u8 ofdm_basic_rates; + u8 cck_basic_rates; + __le16 reserved1; + u8 ofdm_ht_single_stream_basic_rates; + u8 ofdm_ht_dual_stream_basic_rates; + u8 ofdm_ht_triple_stream_basic_rates; + u8 reserved2; + __le16 rx_chain_select_flags; + __le16 acquisition_data; + __le32 reserved3; +} __attribute__ ((packed)); /* * REPLY_RXON_ASSOC = 0x11 (command, has simple generic response) @@ -645,6 +659,9 @@ struct iwl4965_rxon_assoc_cmd { __le16 reserved; } __attribute__ ((packed)); + + + /* * REPLY_RXON_TIMING = 0x14 (command, has simple generic response) */ -- cgit v0.10.2 From 5083e56326208f9a1d4e597529912004968c77d7 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 29 May 2008 16:35:15 +0800 Subject: iwlwifi: move iwl_sta_modify_enable_tid_tx to iwl-sta.c This patch moves iwl_sta_modify_enable_tid_tx into iwl-sta.c. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 1d95e8c..b719d19 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -44,6 +44,7 @@ #include "iwl-io.h" #include "iwl-helpers.h" #include "iwl-calib.h" +#include "iwl-sta.h" /* module parameters */ static struct iwl_mod_params iwl4965_mod_params = { @@ -2900,24 +2901,6 @@ static void iwl4965_rx_reply_rx_phy(struct iwl_priv *priv, #ifdef CONFIG_IWL4965_HT /** - * iwl4965_sta_modify_enable_tid_tx - Enable Tx for this TID in station table - */ -static void iwl4965_sta_modify_enable_tid_tx(struct iwl_priv *priv, - int sta_id, int tid) -{ - unsigned long flags; - - /* Remove "disable" flag, to enable Tx for this TID */ - spin_lock_irqsave(&priv->sta_lock, flags); - priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_TID_DISABLE_TX; - priv->stations[sta_id].sta.tid_disable_tx &= cpu_to_le16(~(1 << tid)); - priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; - spin_unlock_irqrestore(&priv->sta_lock, flags); - - iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); -} - -/** * iwl4965_tx_status_reply_compressed_ba - Update tx status from block-ack * * Go through block-ack's bitmap of ACK'd frames, update driver's record of @@ -3193,7 +3176,7 @@ static int iwl4965_tx_queue_agg_enable(struct iwl_priv *priv, int txq_id, ra_tid = BUILD_RAxTID(sta_id, tid); /* Modify device's station table to Tx this TID */ - iwl4965_sta_modify_enable_tid_tx(priv, sta_id, tid); + iwl_sta_modify_enable_tid_tx(priv, sta_id, tid); spin_lock_irqsave(&priv->lock, flags); rc = iwl_grab_nic_access(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index ed07566..983f107 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -921,3 +921,23 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) } EXPORT_SYMBOL(iwl_get_sta_id); + +/** + * iwl_sta_modify_enable_tid_tx - Enable Tx for this TID in station table + */ +void iwl_sta_modify_enable_tid_tx(struct iwl_priv *priv, int sta_id, int tid) +{ + unsigned long flags; + + /* Remove "disable" flag, to enable Tx for this TID */ + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_TID_DISABLE_TX; + priv->stations[sta_id].sta.tid_disable_tx &= cpu_to_le16(~(1 << tid)); + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); +} +EXPORT_SYMBOL(iwl_sta_modify_enable_tid_tx); + + diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h index 500e1df..3d55716 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.h +++ b/drivers/net/wireless/iwlwifi/iwl-sta.h @@ -45,4 +45,5 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv, int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap); u8 iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap); int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr); +void iwl_sta_modify_enable_tid_tx(struct iwl_priv *priv, int sta_id, int tid); #endif /* __iwl_sta_h__ */ -- cgit v0.10.2 From 30e553e3ea3572bee3118fcde36e043c0cb2174c Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 29 May 2008 16:35:16 +0800 Subject: iwlwifi: move aggregation code to iwl-tx.c This patch moves aggregation action code to iwl-tx.c in iwlcore. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index b719d19..556e59e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -55,30 +55,6 @@ static struct iwl_mod_params iwl4965_mod_params = { /* the rest are 0 by default */ }; -#ifdef CONFIG_IWL4965_HT - -static const u16 default_tid_to_tx_fifo[] = { - IWL_TX_FIFO_AC1, - IWL_TX_FIFO_AC0, - IWL_TX_FIFO_AC0, - IWL_TX_FIFO_AC1, - IWL_TX_FIFO_AC2, - IWL_TX_FIFO_AC2, - IWL_TX_FIFO_AC3, - IWL_TX_FIFO_AC3, - IWL_TX_FIFO_NONE, - IWL_TX_FIFO_NONE, - IWL_TX_FIFO_NONE, - IWL_TX_FIFO_NONE, - IWL_TX_FIFO_NONE, - IWL_TX_FIFO_NONE, - IWL_TX_FIFO_NONE, - IWL_TX_FIFO_NONE, - IWL_TX_FIFO_AC3 -}; - -#endif /*CONFIG_IWL4965_HT */ - /* check contents of special bootstrap uCode SRAM */ static int iwl4965_verify_bsm(struct iwl_priv *priv) { @@ -2986,8 +2962,8 @@ static void iwl4965_tx_queue_stop_scheduler(struct iwl_priv *priv, * txq_id must be greater than IWL_BACK_QUEUE_FIRST_ID * priv->lock must be held by the caller */ -static int iwl4965_tx_queue_agg_disable(struct iwl_priv *priv, u16 txq_id, - u16 ssn_idx, u8 tx_fifo) +static int iwl4965_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, + u16 ssn_idx, u8 tx_fifo) { int ret = 0; @@ -3019,39 +2995,6 @@ static int iwl4965_tx_queue_agg_disable(struct iwl_priv *priv, u16 txq_id, return 0; } -int iwl4965_check_empty_hw_queue(struct iwl_priv *priv, int sta_id, - u8 tid, int txq_id) -{ - struct iwl_queue *q = &priv->txq[txq_id].q; - u8 *addr = priv->stations[sta_id].sta.sta.addr; - struct iwl_tid_data *tid_data = &priv->stations[sta_id].tid[tid]; - - switch (priv->stations[sta_id].tid[tid].agg.state) { - case IWL_EMPTYING_HW_QUEUE_DELBA: - /* We are reclaiming the last packet of the */ - /* aggregated HW queue */ - if (txq_id == tid_data->agg.txq_id && - q->read_ptr == q->write_ptr) { - u16 ssn = SEQ_TO_SN(tid_data->seq_number); - int tx_fifo = default_tid_to_tx_fifo[tid]; - IWL_DEBUG_HT("HW queue empty: continue DELBA flow\n"); - iwl4965_tx_queue_agg_disable(priv, txq_id, - ssn, tx_fifo); - tid_data->agg.state = IWL_AGG_OFF; - ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, addr, tid); - } - break; - case IWL_EMPTYING_HW_QUEUE_ADDBA: - /* We are reclaiming the last packet of the queue */ - if (tid_data->tfds_in_queue == 0) { - IWL_DEBUG_HT("HW queue empty: continue ADDBA flow\n"); - tid_data->agg.state = IWL_AGG_ON; - ieee80211_start_tx_ba_cb_irqsafe(priv->hw, addr, tid); - } - break; - } - return 0; -} /** * iwl4965_rx_reply_compressed_ba - Handler for REPLY_COMPRESSED_BA @@ -3122,8 +3065,9 @@ static void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv, priv->mac80211_registered && agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) ieee80211_wake_queue(priv->hw, ampdu_q); - iwl4965_check_empty_hw_queue(priv, ba_resp->sta_id, - ba_resp->tid, scd_flow); + + iwl_txq_check_empty(priv, ba_resp->sta_id, + ba_resp->tid, scd_flow); } } @@ -3137,7 +3081,7 @@ static int iwl4965_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid, u32 tbl_dw; u16 scd_q2ratid; - scd_q2ratid = ra_tid & IWL49_SCD_QUEUE_RA_TID_MAP_RATID_MSK; + scd_q2ratid = ra_tid & IWL_SCD_QUEUE_RA_TID_MAP_RATID_MSK; tbl_dw_addr = priv->scd_base_addr + IWL49_SCD_TRANSLATE_TBL_OFFSET_QUEUE(txq_id); @@ -3161,12 +3105,11 @@ static int iwl4965_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid, * NOTE: txq_id must be greater than IWL_BACK_QUEUE_FIRST_ID, * i.e. it must be one of the higher queues used for aggregation */ -static int iwl4965_tx_queue_agg_enable(struct iwl_priv *priv, int txq_id, - int tx_fifo, int sta_id, int tid, - u16 ssn_idx) +static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id, + int tx_fifo, int sta_id, int tid, u16 ssn_idx) { unsigned long flags; - int rc; + int ret; u16 ra_tid; if (IWL_BACK_QUEUE_FIRST_ID > txq_id) @@ -3179,10 +3122,10 @@ static int iwl4965_tx_queue_agg_enable(struct iwl_priv *priv, int txq_id, iwl_sta_modify_enable_tid_tx(priv, sta_id, tid); spin_lock_irqsave(&priv->lock, flags); - rc = iwl_grab_nic_access(priv); - if (rc) { + ret = iwl_grab_nic_access(priv); + if (ret) { spin_unlock_irqrestore(&priv->lock, flags); - return rc; + return ret; } /* Stop this Tx queue before configuring it */ @@ -3269,137 +3212,6 @@ static int iwl4965_rx_agg_stop(struct iwl_priv *priv, CMD_ASYNC); } -/* - * Find first available (lowest unused) Tx Queue, mark it "active". - * Called only when finding queue for aggregation. - * Should never return anything < 7, because they should already - * be in use as EDCA AC (0-3), Command (4), HCCA (5, 6). - */ -static int iwl4965_txq_ctx_activate_free(struct iwl_priv *priv) -{ - int txq_id; - - for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) - if (!test_and_set_bit(txq_id, &priv->txq_ctx_active_msk)) - return txq_id; - return -1; -} - -static int iwl4965_tx_agg_start(struct ieee80211_hw *hw, const u8 *ra, - u16 tid, u16 *start_seq_num) -{ - struct iwl_priv *priv = hw->priv; - int sta_id; - int tx_fifo; - int txq_id; - int ssn = -1; - int ret = 0; - unsigned long flags; - struct iwl_tid_data *tid_data; - DECLARE_MAC_BUF(mac); - - if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo))) - tx_fifo = default_tid_to_tx_fifo[tid]; - else - return -EINVAL; - - IWL_WARNING("%s on ra = %s tid = %d\n", - __func__, print_mac(mac, ra), tid); - - sta_id = iwl_find_station(priv, ra); - if (sta_id == IWL_INVALID_STATION) - return -ENXIO; - - if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_OFF) { - IWL_ERROR("Start AGG when state is not IWL_AGG_OFF !\n"); - return -ENXIO; - } - - txq_id = iwl4965_txq_ctx_activate_free(priv); - if (txq_id == -1) - return -ENXIO; - - spin_lock_irqsave(&priv->sta_lock, flags); - tid_data = &priv->stations[sta_id].tid[tid]; - ssn = SEQ_TO_SN(tid_data->seq_number); - tid_data->agg.txq_id = txq_id; - spin_unlock_irqrestore(&priv->sta_lock, flags); - - *start_seq_num = ssn; - ret = iwl4965_tx_queue_agg_enable(priv, txq_id, tx_fifo, - sta_id, tid, ssn); - if (ret) - return ret; - - ret = 0; - if (tid_data->tfds_in_queue == 0) { - printk(KERN_ERR "HW queue is empty\n"); - tid_data->agg.state = IWL_AGG_ON; - ieee80211_start_tx_ba_cb_irqsafe(hw, ra, tid); - } else { - IWL_DEBUG_HT("HW queue is NOT empty: %d packets in HW queue\n", - tid_data->tfds_in_queue); - tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA; - } - return ret; -} - -static int iwl4965_tx_agg_stop(struct ieee80211_hw *hw, const u8 *ra, u16 tid) -{ - struct iwl_priv *priv = hw->priv; - int tx_fifo_id, txq_id, sta_id, ssn = -1; - struct iwl_tid_data *tid_data; - int ret, write_ptr, read_ptr; - unsigned long flags; - DECLARE_MAC_BUF(mac); - - if (!ra) { - IWL_ERROR("ra = NULL\n"); - return -EINVAL; - } - - if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo))) - tx_fifo_id = default_tid_to_tx_fifo[tid]; - else - return -EINVAL; - - sta_id = iwl_find_station(priv, ra); - - if (sta_id == IWL_INVALID_STATION) - return -ENXIO; - - if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_ON) - IWL_WARNING("Stopping AGG while state not IWL_AGG_ON\n"); - - tid_data = &priv->stations[sta_id].tid[tid]; - ssn = (tid_data->seq_number & IEEE80211_SCTL_SEQ) >> 4; - txq_id = tid_data->agg.txq_id; - write_ptr = priv->txq[txq_id].q.write_ptr; - read_ptr = priv->txq[txq_id].q.read_ptr; - - /* The queue is not empty */ - if (write_ptr != read_ptr) { - IWL_DEBUG_HT("Stopping a non empty AGG HW QUEUE\n"); - priv->stations[sta_id].tid[tid].agg.state = - IWL_EMPTYING_HW_QUEUE_DELBA; - return 0; - } - - IWL_DEBUG_HT("HW queue is empty\n"); - priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF; - - spin_lock_irqsave(&priv->lock, flags); - ret = iwl4965_tx_queue_agg_disable(priv, txq_id, ssn, tx_fifo_id); - spin_unlock_irqrestore(&priv->lock, flags); - - if (ret) - return ret; - - ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, ra, tid); - - return 0; -} - int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, enum ieee80211_ampdu_mlme_action action, const u8 *addr, u16 tid, u16 *ssn) @@ -3419,10 +3231,10 @@ int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, return iwl4965_rx_agg_stop(priv, addr, tid); case IEEE80211_AMPDU_TX_START: IWL_DEBUG_HT("start Tx\n"); - return iwl4965_tx_agg_start(hw, addr, tid, ssn); + return iwl_tx_agg_start(priv, addr, tid, ssn); case IEEE80211_AMPDU_TX_STOP: IWL_DEBUG_HT("stop Tx\n"); - return iwl4965_tx_agg_stop(hw, addr, tid); + return iwl_tx_agg_stop(priv, addr, tid); default: IWL_DEBUG_HT("unknown\n"); return -EINVAL; @@ -3670,7 +3482,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, else ieee80211_wake_queue(priv->hw, ampdu_q); } - iwl4965_check_empty_hw_queue(priv, sta_id, tid, txq_id); + iwl_txq_check_empty(priv, sta_id, tid, txq_id); } } else { #endif /* CONFIG_IWL4965_HT */ @@ -3695,7 +3507,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, (txq_id >= 0) && priv->mac80211_registered) ieee80211_wake_queue(priv->hw, txq_id); if (tid != MAX_TID_COUNT) - iwl4965_check_empty_hw_queue(priv, sta_id, tid, txq_id); + iwl_txq_check_empty(priv, sta_id, tid, txq_id); } } #endif /* CONFIG_IWL4965_HT */ @@ -3761,6 +3573,10 @@ static struct iwl_lib_ops iwl4965_lib = { .shared_mem_rx_idx = iwl4965_shared_mem_rx_idx, .txq_update_byte_cnt_tbl = iwl4965_txq_update_byte_cnt_tbl, .txq_set_sched = iwl4965_txq_set_sched, +#ifdef CONFIG_IWL4965_HT + .txq_agg_enable = iwl4965_txq_agg_enable, + .txq_agg_disable = iwl4965_txq_agg_disable, +#endif .rx_handler_setup = iwl4965_rx_handler_setup, .is_valid_rtc_data_addr = iwl4965_hw_valid_rtc_data_addr, .alive_notify = iwl4965_alive_notify, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 217c6a9..9ef4468 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1193,7 +1193,7 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv, else ieee80211_wake_queue(priv->hw, ampdu_q); } - iwl4965_check_empty_hw_queue(priv, sta_id, tid, txq_id); + iwl_txq_check_empty(priv, sta_id, tid, txq_id); } } else { #endif /* CONFIG_IWL4965_HT */ @@ -1218,7 +1218,7 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv, (txq_id >= 0) && priv->mac80211_registered) ieee80211_wake_queue(priv->hw, txq_id); if (tid != MAX_TID_COUNT) - iwl4965_check_empty_hw_queue(priv, sta_id, tid, txq_id); + iwl_txq_check_empty(priv, sta_id, tid, txq_id); } } #endif /* CONFIG_IWL4965_HT */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 1941a91..004c684 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -104,15 +104,22 @@ struct iwl_lib_ops { int (*alloc_shared_mem)(struct iwl_priv *priv); void (*free_shared_mem)(struct iwl_priv *priv); int (*shared_mem_rx_idx)(struct iwl_priv *priv); + /* Handling TX */ void (*txq_update_byte_cnt_tbl)(struct iwl_priv *priv, struct iwl_tx_queue *txq, u16 byte_cnt); void (*txq_inval_byte_cnt_tbl)(struct iwl_priv *priv, struct iwl_tx_queue *txq); void (*txq_set_sched)(struct iwl_priv *priv, u32 mask); +#ifdef CONFIG_IWL4965_HT + /* aggregations */ + int (*txq_agg_enable)(struct iwl_priv *priv, int txq_id, int tx_fifo, + int sta_id, int tid, u16 ssn_idx); + int (*txq_agg_disable)(struct iwl_priv *priv, u16 txq_id, u16 ssn_idx, + u8 tx_fifo); +#endif /* CONFIG_IWL4965_HT */ /* setup Rx handler */ void (*rx_handler_setup)(struct iwl_priv *priv); - /* nic Tx fifo handling */ /* alive notification after init uCode load */ void (*init_alive_start)(struct iwl_priv *priv); /* alive notification */ @@ -226,6 +233,11 @@ void iwl_hw_txq_ctx_free(struct iwl_priv *priv); int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *tfd, dma_addr_t addr, u16 len); int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq); +#ifdef CONFIG_IWL4965_HT +int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn); +int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid); +int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id); +#endif /***************************************************** * S e n d i n g H o s t C o m m a n d s * diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index 15cb7ff..70d9c75 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -507,9 +507,9 @@ #define IWL49_SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \ ((IWL49_SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffffffc) -#define IWL49_SCD_TXFIFO_POS_TID (0) -#define IWL49_SCD_TXFIFO_POS_RA (4) -#define IWL49_SCD_QUEUE_RA_TID_MAP_RATID_MSK (0x01FF) +#define IWL_SCD_TXFIFO_POS_TID (0) +#define IWL_SCD_TXFIFO_POS_RA (4) +#define IWL_SCD_QUEUE_RA_TID_MAP_RATID_MSK (0x01FF) /* 5000 SCD */ #define IWL50_SCD_QUEUE_STTS_REG_POS_TXF (0) diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 224bcec..cfe6f4b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -36,6 +36,32 @@ #include "iwl-io.h" #include "iwl-helpers.h" +#ifdef CONFIG_IWL4965_HT + +static const u16 default_tid_to_tx_fifo[] = { + IWL_TX_FIFO_AC1, + IWL_TX_FIFO_AC0, + IWL_TX_FIFO_AC0, + IWL_TX_FIFO_AC1, + IWL_TX_FIFO_AC2, + IWL_TX_FIFO_AC2, + IWL_TX_FIFO_AC3, + IWL_TX_FIFO_AC3, + IWL_TX_FIFO_NONE, + IWL_TX_FIFO_NONE, + IWL_TX_FIFO_NONE, + IWL_TX_FIFO_NONE, + IWL_TX_FIFO_NONE, + IWL_TX_FIFO_NONE, + IWL_TX_FIFO_NONE, + IWL_TX_FIFO_NONE, + IWL_TX_FIFO_AC3 +}; + +#endif /*CONFIG_IWL4965_HT */ + + + /** * iwl_hw_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr] * @@ -1171,6 +1197,170 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) EXPORT_SYMBOL(iwl_tx_cmd_complete); +#ifdef CONFIG_IWL4965_HT +/* + * Find first available (lowest unused) Tx Queue, mark it "active". + * Called only when finding queue for aggregation. + * Should never return anything < 7, because they should already + * be in use as EDCA AC (0-3), Command (4), HCCA (5, 6). + */ +static int iwl_txq_ctx_activate_free(struct iwl_priv *priv) +{ + int txq_id; + + for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) + if (!test_and_set_bit(txq_id, &priv->txq_ctx_active_msk)) + return txq_id; + return -1; +} + +int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn) +{ + int sta_id; + int tx_fifo; + int txq_id; + int ret; + unsigned long flags; + struct iwl_tid_data *tid_data; + DECLARE_MAC_BUF(mac); + + if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo))) + tx_fifo = default_tid_to_tx_fifo[tid]; + else + return -EINVAL; + + IWL_WARNING("%s on ra = %s tid = %d\n", + __func__, print_mac(mac, ra), tid); + + sta_id = iwl_find_station(priv, ra); + if (sta_id == IWL_INVALID_STATION) + return -ENXIO; + + if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_OFF) { + IWL_ERROR("Start AGG when state is not IWL_AGG_OFF !\n"); + return -ENXIO; + } + + txq_id = iwl_txq_ctx_activate_free(priv); + if (txq_id == -1) + return -ENXIO; + + spin_lock_irqsave(&priv->sta_lock, flags); + tid_data = &priv->stations[sta_id].tid[tid]; + *ssn = SEQ_TO_SN(tid_data->seq_number); + tid_data->agg.txq_id = txq_id; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + ret = priv->cfg->ops->lib->txq_agg_enable(priv, txq_id, tx_fifo, + sta_id, tid, *ssn); + if (ret) + return ret; + + if (tid_data->tfds_in_queue == 0) { + printk(KERN_ERR "HW queue is empty\n"); + tid_data->agg.state = IWL_AGG_ON; + ieee80211_start_tx_ba_cb_irqsafe(priv->hw, ra, tid); + } else { + IWL_DEBUG_HT("HW queue is NOT empty: %d packets in HW queue\n", + tid_data->tfds_in_queue); + tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA; + } + return ret; +} +EXPORT_SYMBOL(iwl_tx_agg_start); + +int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid) +{ + int tx_fifo_id, txq_id, sta_id, ssn = -1; + struct iwl_tid_data *tid_data; + int ret, write_ptr, read_ptr; + unsigned long flags; + DECLARE_MAC_BUF(mac); + + if (!ra) { + IWL_ERROR("ra = NULL\n"); + return -EINVAL; + } + + if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo))) + tx_fifo_id = default_tid_to_tx_fifo[tid]; + else + return -EINVAL; + + sta_id = iwl_find_station(priv, ra); + + if (sta_id == IWL_INVALID_STATION) + return -ENXIO; + + if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_ON) + IWL_WARNING("Stopping AGG while state not IWL_AGG_ON\n"); + + tid_data = &priv->stations[sta_id].tid[tid]; + ssn = (tid_data->seq_number & IEEE80211_SCTL_SEQ) >> 4; + txq_id = tid_data->agg.txq_id; + write_ptr = priv->txq[txq_id].q.write_ptr; + read_ptr = priv->txq[txq_id].q.read_ptr; + + /* The queue is not empty */ + if (write_ptr != read_ptr) { + IWL_DEBUG_HT("Stopping a non empty AGG HW QUEUE\n"); + priv->stations[sta_id].tid[tid].agg.state = + IWL_EMPTYING_HW_QUEUE_DELBA; + return 0; + } + + IWL_DEBUG_HT("HW queue is empty\n"); + priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF; + + spin_lock_irqsave(&priv->lock, flags); + ret = priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, ssn, + tx_fifo_id); + spin_unlock_irqrestore(&priv->lock, flags); + + if (ret) + return ret; + + ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, ra, tid); + + return 0; +} +EXPORT_SYMBOL(iwl_tx_agg_stop); + +int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id) +{ + struct iwl_queue *q = &priv->txq[txq_id].q; + u8 *addr = priv->stations[sta_id].sta.sta.addr; + struct iwl_tid_data *tid_data = &priv->stations[sta_id].tid[tid]; + + switch (priv->stations[sta_id].tid[tid].agg.state) { + case IWL_EMPTYING_HW_QUEUE_DELBA: + /* We are reclaiming the last packet of the */ + /* aggregated HW queue */ + if (txq_id == tid_data->agg.txq_id && + q->read_ptr == q->write_ptr) { + u16 ssn = SEQ_TO_SN(tid_data->seq_number); + int tx_fifo = default_tid_to_tx_fifo[tid]; + IWL_DEBUG_HT("HW queue empty: continue DELBA flow\n"); + priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, + ssn, tx_fifo); + tid_data->agg.state = IWL_AGG_OFF; + ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, addr, tid); + } + break; + case IWL_EMPTYING_HW_QUEUE_ADDBA: + /* We are reclaiming the last packet of the queue */ + if (tid_data->tfds_in_queue == 0) { + IWL_DEBUG_HT("HW queue empty: continue ADDBA flow\n"); + tid_data->agg.state = IWL_AGG_ON; + ieee80211_start_tx_ba_cb_irqsafe(priv->hw, addr, tid); + } + break; + } + return 0; +} +EXPORT_SYMBOL(iwl_txq_check_empty); +#endif /* CONFIG_IWL4965_HT */ + #ifdef CONFIG_IWLWIF_DEBUG #define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x -- cgit v0.10.2 From 5e1dd8dc19dc2c1bacadda04a5c2478aa9516a1b Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 29 May 2008 16:35:17 +0800 Subject: iwlwifi: add frame count limit to link quality command This patch adds frame count limit to link quality host command. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index a89639f..a955f9c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -2444,6 +2444,7 @@ static void rs_fill_link_cmd(const struct iwl_priv *priv, repeat_rate--; } + lq_cmd->agg_params.agg_frame_cnt_limit = 64; lq_cmd->agg_params.agg_dis_start_th = 3; lq_cmd->agg_params.agg_time_limit = cpu_to_le16(4000); } -- cgit v0.10.2 From 37a44211cbe27795dbb79b2ea7036ff784f18d73 Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Thu, 29 May 2008 16:35:18 +0800 Subject: iwlwifi: Rx handlers common use for 4965 and 5000 This patch moves Rx handlers from iwl 4965 only use to common use along with iwl 5000, thus enables Rx path to iwl 5000. Signed-off-by: Ron Rindjunsky Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 556e59e..aee7014 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2689,7 +2689,7 @@ static inline void iwl4965_dbg_report_frame(struct iwl_priv *priv, /* Called for REPLY_RX (legacy ABG frames), or * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */ -static void iwl4965_rx_reply_rx(struct iwl_priv *priv, +void iwl4965_rx_reply_rx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { struct ieee80211_hdr *header; @@ -2863,17 +2863,6 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv, } } -/* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD). - * This will be used later in iwl4965_rx_reply_rx() for REPLY_RX_MPDU_CMD. */ -static void iwl4965_rx_reply_rx_phy(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - priv->last_phy_res[0] = 1; - memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]), - sizeof(struct iwl4965_rx_phy_res)); -} - #ifdef CONFIG_IWL4965_HT /** @@ -3522,11 +3511,7 @@ static void iwl4965_rx_handler_setup(struct iwl_priv *priv) { /* Legacy Rx frames */ priv->rx_handlers[REPLY_RX] = iwl4965_rx_reply_rx; - - /* High-throughput (HT) Rx frames */ - priv->rx_handlers[REPLY_RX_PHY_CMD] = iwl4965_rx_reply_rx_phy; - priv->rx_handlers[REPLY_RX_MPDU_CMD] = iwl4965_rx_reply_rx; - + /* Tx response */ priv->rx_handlers[REPLY_TX] = iwl4965_rx_reply_tx; #ifdef CONFIG_IWL4965_HT diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 8c258d6..a2b9817 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -702,6 +702,8 @@ extern void iwl4965_hw_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); extern void iwl4965_disable_events(struct iwl_priv *priv); extern int iwl4965_get_temperature(const struct iwl_priv *priv); +extern void iwl4965_rx_reply_rx(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb); /** * iwl_find_station - Find station id for a given BSSID diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 4322cd6..49e72d4 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -1872,6 +1872,17 @@ static void iwl4965_rx_card_state_notif(struct iwl_priv *priv, wake_up_interruptible(&priv->wait_command_queue); } +/* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD). + * This will be used later in iwl4965_rx_reply_rx() for REPLY_RX_MPDU_CMD. */ +static void iwl4965_rx_reply_rx_phy(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + priv->last_phy_res[0] = 1; + memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]), + sizeof(struct iwl4965_rx_phy_res)); +} + /** * iwl4965_setup_rx_handlers - Initialize Rx handler callbacks * @@ -1900,18 +1911,21 @@ static void iwl4965_setup_rx_handlers(struct iwl_priv *priv) */ priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl4965_hw_rx_statistics; priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl4965_hw_rx_statistics; - + /* scan handlers */ priv->rx_handlers[REPLY_SCAN_CMD] = iwl4965_rx_reply_scan; priv->rx_handlers[SCAN_START_NOTIFICATION] = iwl4965_rx_scan_start_notif; priv->rx_handlers[SCAN_RESULTS_NOTIFICATION] = iwl4965_rx_scan_results_notif; priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] = iwl4965_rx_scan_complete_notif; + /* status change handler */ priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl4965_rx_card_state_notif; priv->rx_handlers[MISSED_BEACONS_NOTIFICATION] = iwl_rx_missed_beacon_notif; - + /* Rx handlers */ + priv->rx_handlers[REPLY_RX_PHY_CMD] = iwl4965_rx_reply_rx_phy; + priv->rx_handlers[REPLY_RX_MPDU_CMD] = iwl4965_rx_reply_rx; /* Set up hardware specific Rx handlers */ priv->cfg->ops->lib->rx_handler_setup(priv); } -- cgit v0.10.2 From 3c57601d0a1993cfc12a27cc6652b750bb44c523 Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Thu, 29 May 2008 16:35:19 +0800 Subject: iwlwifi: move iwl_get_hw_mode to iwl-core.h This patch moves iwl_get_hw_mode to iwl-core.h. Signed-off-by: Ron Rindjunsky Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 004c684..6b5af7a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -342,4 +342,10 @@ static inline int iwl_send_rxon_assoc(struct iwl_priv *priv) return priv->cfg->ops->hcmd->rxon_assoc(priv); } +static inline const struct ieee80211_supported_band *iwl_get_hw_mode( + struct iwl_priv *priv, enum ieee80211_band band) +{ + return priv->hw->wiphy->bands[band]; +} + #endif /* __iwl_core_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 49e72d4..676d043 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -87,12 +87,6 @@ MODULE_VERSION(DRV_VERSION); MODULE_AUTHOR(DRV_COPYRIGHT); MODULE_LICENSE("GPL"); -static const struct ieee80211_supported_band *iwl_get_hw_mode( - struct iwl_priv *priv, enum ieee80211_band band) -{ - return priv->hw->wiphy->bands[band]; -} - static int iwl4965_is_empty_essid(const char *essid, int essid_len) { /* Single white space is for Linksys APs */ -- cgit v0.10.2 From 9306102ea5696a3815f8d24ac0c0fbd1e19be7d3 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 29 May 2008 16:35:23 +0800 Subject: mac80211: allow disable FAT in specific configurations This patch allows to disable FAT channel in specific configurations. For example the configuration (8, +1), (primary channel 8, extension channel 12) isn't permitted in U.S., but (8, -1), (primary channel 8, extension channel 4) is. When FAT channel configuration is not permitted, FAT channel should be reported as not supported in the capabilities of the HT IE in association request. And sssociation is performed on 20Mhz channel. Signed-off-by: Emmanuel Grumbach Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 3c2ac0c..9300f37 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -320,6 +320,8 @@ struct ieee80211_ht_addt_info { #define IEEE80211_HT_CAP_MCS_TX_UEQM 0x10 /* 802.11n HT IE masks */ #define IEEE80211_HT_IE_CHA_SEC_OFFSET 0x03 +#define IEEE80211_HT_IE_CHA_SEC_ABOVE 0x01 +#define IEEE80211_HT_IE_CHA_SEC_BELOW 0x03 #define IEEE80211_HT_IE_CHA_WIDTH 0x04 #define IEEE80211_HT_IE_HT_PROTECTION 0x0003 #define IEEE80211_HT_IE_NON_GF_STA_PRSNT 0x0004 diff --git a/include/net/wireless.h b/include/net/wireless.h index 667b408..9324f8d 100644 --- a/include/net/wireless.h +++ b/include/net/wireless.h @@ -39,12 +39,18 @@ enum ieee80211_band { * on this channel. * @IEEE80211_CHAN_NO_IBSS: IBSS is not allowed on this channel. * @IEEE80211_CHAN_RADAR: Radar detection is required on this channel. + * @IEEE80211_CHAN_NO_FAT_ABOVE: extension channel above this channel + * is not permitted. + * @IEEE80211_CHAN_NO_FAT_BELOW: extension channel below this channel + * is not permitted. */ enum ieee80211_channel_flags { IEEE80211_CHAN_DISABLED = 1<<0, IEEE80211_CHAN_PASSIVE_SCAN = 1<<1, IEEE80211_CHAN_NO_IBSS = 1<<2, IEEE80211_CHAN_RADAR = 1<<3, + IEEE80211_CHAN_NO_FAT_ABOVE = 1<<4, + IEEE80211_CHAN_NO_FAT_BELOW = 1<<5, }; /** diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 3f8601c..432011c 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -92,6 +92,8 @@ struct ieee80211_sta_bss { size_t wmm_ie_len; u8 *ht_ie; size_t ht_ie_len; + u8 *ht_add_ie; + size_t ht_add_ie_len; #ifdef CONFIG_MAC80211_MESH u8 *mesh_id; size_t mesh_id_len; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 6faa700..d30c113 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -808,8 +808,29 @@ static void ieee80211_send_assoc(struct net_device *dev, /* wmm support is a must to HT */ if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED) && - sband->ht_info.ht_supported) { - __le16 tmp = cpu_to_le16(sband->ht_info.cap); + sband->ht_info.ht_supported && bss->ht_add_ie) { + struct ieee80211_ht_addt_info *ht_add_info = + (struct ieee80211_ht_addt_info *)bss->ht_add_ie; + u16 cap = sband->ht_info.cap; + __le16 tmp; + u32 flags = local->hw.conf.channel->flags; + + switch (ht_add_info->ht_param & IEEE80211_HT_IE_CHA_SEC_OFFSET) { + case IEEE80211_HT_IE_CHA_SEC_ABOVE: + if (flags & IEEE80211_CHAN_NO_FAT_ABOVE) { + cap &= ~IEEE80211_HT_CAP_SUP_WIDTH; + cap &= ~IEEE80211_HT_CAP_SGI_40; + } + break; + case IEEE80211_HT_IE_CHA_SEC_BELOW: + if (flags & IEEE80211_CHAN_NO_FAT_BELOW) { + cap &= ~IEEE80211_HT_CAP_SUP_WIDTH; + cap &= ~IEEE80211_HT_CAP_SGI_40; + } + break; + } + + tmp = cpu_to_le16(cap); pos = skb_put(skb, sizeof(struct ieee80211_ht_cap)+2); *pos++ = WLAN_EID_HT_CAPABILITY; *pos++ = sizeof(struct ieee80211_ht_cap); @@ -2264,6 +2285,7 @@ static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss) kfree(bss->rsn_ie); kfree(bss->wmm_ie); kfree(bss->ht_ie); + kfree(bss->ht_add_ie); kfree(bss_mesh_id(bss)); kfree(bss_mesh_cfg(bss)); kfree(bss); @@ -2640,6 +2662,26 @@ static void ieee80211_rx_bss_info(struct net_device *dev, bss->ht_ie_len = 0; } + if (elems.ht_info_elem && + (!bss->ht_add_ie || + bss->ht_add_ie_len != elems.ht_info_elem_len || + memcmp(bss->ht_add_ie, elems.ht_info_elem, + elems.ht_info_elem_len))) { + kfree(bss->ht_add_ie); + bss->ht_add_ie = + kmalloc(elems.ht_info_elem_len + 2, GFP_ATOMIC); + if (bss->ht_add_ie) { + memcpy(bss->ht_add_ie, elems.ht_info_elem - 2, + elems.ht_info_elem_len + 2); + bss->ht_add_ie_len = elems.ht_info_elem_len + 2; + } else + bss->ht_add_ie_len = 0; + } else if (!elems.ht_info_elem && bss->ht_add_ie) { + kfree(bss->ht_add_ie); + bss->ht_add_ie = NULL; + bss->ht_add_ie_len = 0; + } + bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int); bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info); -- cgit v0.10.2 From 4d38c2e8ea7589f546244a1673b8171455283fcb Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 29 May 2008 16:35:24 +0800 Subject: iwlwifi: disable FAT channel when not permitted This patch disables FAT channel when it is not permitted according to the EEPROM. Signed-off-by: Emmanuel Grumbach Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 010085a..c9bbfbb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -486,6 +486,25 @@ static int iwlcore_init_geos(struct iwl_priv *priv) if (ch->flags & EEPROM_CHANNEL_RADAR) geo_ch->flags |= IEEE80211_CHAN_RADAR; + switch (ch->fat_extension_channel) { + case HT_IE_EXT_CHANNEL_ABOVE: + /* only above is allowed, disable below */ + geo_ch->flags |= IEEE80211_CHAN_NO_FAT_BELOW; + break; + case HT_IE_EXT_CHANNEL_BELOW: + /* only below is allowed, disable above */ + geo_ch->flags |= IEEE80211_CHAN_NO_FAT_ABOVE; + break; + case HT_IE_EXT_CHANNEL_NONE: + /* fat not allowed: disable both*/ + geo_ch->flags |= (IEEE80211_CHAN_NO_FAT_ABOVE | + IEEE80211_CHAN_NO_FAT_BELOW); + break; + case HT_IE_EXT_CHANNEL_MAX: + /* both above and below are permitted */ + break; + } + if (ch->max_power_avg > priv->max_channel_txpower_limit) priv->max_channel_txpower_limit = ch->max_power_avg; -- cgit v0.10.2 From 261415f77a947a452dbd32a35186b2dc3ce14020 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 29 May 2008 16:35:25 +0800 Subject: iwlwifi: fix a memory leak in scan This patch fixes a memory leak that the scan buffer isn't released on exit. Signed-off-by: Emmanuel Grumbach Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index c9bbfbb..61716ba 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -911,6 +911,7 @@ void iwl_uninit_drv(struct iwl_priv *priv) iwl_free_calib_results(priv); iwlcore_free_geos(priv); iwl_free_channel_map(priv); + kfree(priv->scan); } EXPORT_SYMBOL(iwl_uninit_drv); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 244bfe5..72279e0 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -8257,7 +8257,7 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev) iwl3945_free_channel_map(priv); iwl3945_free_geos(priv); - + kfree(priv->scan); if (priv->ibss_beacon) dev_kfree_skb(priv->ibss_beacon); -- cgit v0.10.2 From 67249625089c21ec299b337a26448312b7eb91b3 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 29 May 2008 16:35:26 +0800 Subject: iwlwifi: remove debugfs entries before cfg80211 This patch solves a bug in debugfs unregistration. iwlwifi registers its debugfs files under cfg80211's dir, but removed its files only after having unregistered mac80211 that removes cfg80211 debugfs dir. This garbaged debugfs and didn't allow to rmmod and insmod iwlwifi several times in a row. Signed-off-by: Emmanuel Grumbach Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 676d043..e5e8ad8 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -5323,6 +5323,9 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev) IWL_DEBUG_INFO("*** UNLOAD DRIVER ***\n"); + iwl_dbgfs_unregister(priv); + sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group); + if (priv->mac80211_registered) { ieee80211_unregister_hw(priv->hw); priv->mac80211_registered = 0; @@ -5350,8 +5353,6 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev) } iwlcore_low_level_notify(priv, IWLCORE_REMOVE_EVT); - iwl_dbgfs_unregister(priv); - sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group); iwl4965_dealloc_ucode_pci(priv); -- cgit v0.10.2 From d2f18bfd9bc6b51c8bb72b272ecca902a88387d4 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 29 May 2008 16:35:27 +0800 Subject: iwlwifi: send calibration results as HUGE commands This patch saves memory by reducing the size of the entry in the txq. It was 640 because of the calibration commands. Calibration commands are now sent as HUGE commands (using the extra 1024 bytes at the end of the command txq), hence, there is no need for 640 in every entry any more. Signed-off-by: Emmanuel Grumbach Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 9ef4468..7e525ad 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -428,28 +428,37 @@ static int iwl5000_send_calib_results(struct iwl_priv *priv) { int ret = 0; - if (priv->calib_results.lo_res) - ret = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, - priv->calib_results.lo_res_len, - priv->calib_results.lo_res); - if (ret) - goto err; + struct iwl_host_cmd hcmd = { + .id = REPLY_PHY_CALIBRATION_CMD, + .meta.flags = CMD_SIZE_HUGE, + }; + if (priv->calib_results.lo_res) { + hcmd.len = priv->calib_results.lo_res_len; + hcmd.data = priv->calib_results.lo_res; + ret = iwl_send_cmd_sync(priv, &hcmd); - if (priv->calib_results.tx_iq_res) - ret = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, - priv->calib_results.tx_iq_res_len, - priv->calib_results.tx_iq_res); + if (ret) + goto err; + } - if (ret) - goto err; + if (priv->calib_results.tx_iq_res) { + hcmd.len = priv->calib_results.tx_iq_res_len; + hcmd.data = priv->calib_results.tx_iq_res; + ret = iwl_send_cmd_sync(priv, &hcmd); - if (priv->calib_results.tx_iq_perd_res) - ret = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, - priv->calib_results.tx_iq_perd_res_len, - priv->calib_results.tx_iq_perd_res); - if (ret) - goto err; + if (ret) + goto err; + } + + if (priv->calib_results.tx_iq_perd_res) { + hcmd.len = priv->calib_results.tx_iq_perd_res_len; + hcmd.data = priv->calib_results.tx_iq_perd_res; + ret = iwl_send_cmd_sync(priv, &hcmd); + + if (ret) + goto err; + } return 0; err: diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index a2b9817..802f1a1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -307,7 +307,7 @@ struct iwl_cmd_meta { } __attribute__ ((packed)); -#define IWL_CMD_MAX_PAYLOAD 640 +#define IWL_CMD_MAX_PAYLOAD 320 /** * struct iwl_cmd -- cgit v0.10.2 From 82a66bbbe96126ca1bc6bc5ded8e67f529bcdfa4 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 29 May 2008 16:35:28 +0800 Subject: iwlwifi: clean iwl4965_mac_config This patch cleans up iwl4965_mac_config. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index e559c19..11f9d95 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -573,9 +573,8 @@ void iwl_free_channel_map(struct iwl_priv *priv) * * Based on band and channel number. */ -const struct iwl_channel_info *iwl_get_channel_info( - const struct iwl_priv *priv, - enum ieee80211_band band, u16 channel) +const struct iwl_channel_info *iwl_get_channel_info(const struct iwl_priv *priv, + enum ieee80211_band band, u16 channel) { int i; diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index e5e8ad8..c71daec 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -1084,8 +1084,8 @@ static int iwl4965_scan_initiate(struct iwl_priv *priv) } -static void iwl4965_set_flags_for_phymode(struct iwl_priv *priv, - enum ieee80211_band band) +static void iwl_set_flags_for_band(struct iwl_priv *priv, + enum ieee80211_band band) { if (band == IEEE80211_BAND_5GHZ) { priv->staging_rxon.flags &= @@ -1170,7 +1170,7 @@ static void iwl4965_connection_init_rx_config(struct iwl_priv *priv) priv->staging_rxon.channel = cpu_to_le16(ch_info->channel); priv->band = ch_info->band; - iwl4965_set_flags_for_phymode(priv, priv->band); + iwl_set_flags_for_band(priv, priv->band); priv->staging_rxon.ofdm_basic_rates = (IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; @@ -3823,6 +3823,7 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co const struct iwl_channel_info *ch_info; unsigned long flags; int ret = 0; + u16 channel; mutex_lock(&priv->mutex); IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel->hw_value); @@ -3843,22 +3844,21 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co return 0; } - spin_lock_irqsave(&priv->lock, flags); - - ch_info = iwl_get_channel_info(priv, conf->channel->band, - ieee80211_frequency_to_channel(conf->channel->center_freq)); + channel = ieee80211_frequency_to_channel(conf->channel->center_freq); + ch_info = iwl_get_channel_info(priv, conf->channel->band, channel); if (!is_channel_valid(ch_info)) { IWL_DEBUG_MAC80211("leave - invalid channel\n"); - spin_unlock_irqrestore(&priv->lock, flags); ret = -EINVAL; goto out; } + spin_lock_irqsave(&priv->lock, flags); + #ifdef CONFIG_IWL4965_HT /* if we are switching from ht to 2.4 clear flags * from any ht related info since 2.4 does not * support ht */ - if ((le16_to_cpu(priv->staging_rxon.channel) != conf->channel->hw_value) + if ((le16_to_cpu(priv->staging_rxon.channel) != channel) #ifdef IEEE80211_CONF_CHANNEL_SWITCH && !(conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) #endif @@ -3866,10 +3866,9 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co priv->staging_rxon.flags = 0; #endif /* CONFIG_IWL4965_HT */ - iwl_set_rxon_channel(priv, conf->channel->band, - ieee80211_frequency_to_channel(conf->channel->center_freq)); + iwl_set_rxon_channel(priv, conf->channel->band, channel); - iwl4965_set_flags_for_phymode(priv, conf->channel->band); + iwl_set_flags_for_band(priv, conf->channel->band); /* The list of supported rates and rate mask can be different * for each band; since the band may have changed, reset -- cgit v0.10.2 From 13de15e71db7a38f02c4d9f642f06541f5acc2b0 Mon Sep 17 00:00:00 2001 From: Masakazu Mokuno Date: Fri, 30 May 2008 16:27:24 +0900 Subject: PS3: gelic: Allocate the bounce buffer dynamically Allocate the bouce buffer for the wireless command dynamically. Signed-off-by: Masakazu Mokuno Signed-off-by: John W. Linville diff --git a/drivers/net/ps3_gelic_wireless.c b/drivers/net/ps3_gelic_wireless.c index e5e0233..c16a30b 100644 --- a/drivers/net/ps3_gelic_wireless.c +++ b/drivers/net/ps3_gelic_wireless.c @@ -1524,15 +1524,20 @@ static struct iw_statistics *gelic_wl_get_wireless_stats( struct gelic_eurus_cmd *cmd; struct iw_statistics *is; struct gelic_eurus_rssi_info *rssi; + void *buf; pr_debug("%s: <-\n", __func__); + buf = (void *)__get_free_page(GFP_KERNEL); + if (!buf) + return NULL; + is = &wl->iwstat; memset(is, 0, sizeof(*is)); cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_GET_RSSI_CFG, - wl->buf, sizeof(*rssi)); + buf, sizeof(*rssi)); if (cmd && !cmd->status && !cmd->cmd_status) { - rssi = wl->buf; + rssi = buf; is->qual.level = be16_to_cpu(rssi->rssi); is->qual.updated = IW_QUAL_LEVEL_UPDATED | IW_QUAL_QUAL_INVALID | IW_QUAL_NOISE_INVALID; @@ -1541,6 +1546,7 @@ static struct iw_statistics *gelic_wl_get_wireless_stats( is->qual.updated = IW_QUAL_ALL_INVALID; kfree(cmd); + free_page((unsigned long)buf); pr_debug("%s: ->\n", __func__); return is; } @@ -1607,11 +1613,18 @@ static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl) union iwreq_data data; unsigned long this_time = jiffies; unsigned int data_len, i, found, r; + void *buf; DECLARE_MAC_BUF(mac); pr_debug("%s:start\n", __func__); mutex_lock(&wl->scan_lock); + buf = (void *)__get_free_page(GFP_KERNEL); + if (!buf) { + pr_info("%s: scan buffer alloc failed\n", __func__); + goto out; + } + if (wl->scan_stat != GELIC_WL_SCAN_STAT_SCANNING) { /* * stop() may be called while scanning, ignore result @@ -1622,7 +1635,7 @@ static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl) } cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_GET_SCAN, - wl->buf, PAGE_SIZE); + buf, PAGE_SIZE); if (!cmd || cmd->status || cmd->cmd_status) { wl->scan_stat = GELIC_WL_SCAN_STAT_INIT; pr_info("%s:cmd failed\n", __func__); @@ -1649,7 +1662,7 @@ static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl) } /* put them in the newtork_list */ - for (i = 0, scan_info_size = 0, scan_info = wl->buf; + for (i = 0, scan_info_size = 0, scan_info = buf; scan_info_size < data_len; i++, scan_info_size += be16_to_cpu(scan_info->size), scan_info = (void *)scan_info + be16_to_cpu(scan_info->size)) { @@ -1726,6 +1739,7 @@ static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl) wireless_send_event(port_to_netdev(wl_port(wl)), SIOCGIWSCAN, &data, NULL); out: + free_page((unsigned long)buf); complete(&wl->scan_done); mutex_unlock(&wl->scan_lock); pr_debug("%s:end\n", __func__); @@ -1848,7 +1862,10 @@ static int gelic_wl_do_wep_setup(struct gelic_wl_info *wl) pr_debug("%s: <-\n", __func__); /* we can assume no one should uses the buffer */ - wep = wl->buf; + wep = (struct gelic_eurus_wep_cfg *)__get_free_page(GFP_KERNEL); + if (!wep) + return -ENOMEM; + memset(wep, 0, sizeof(*wep)); if (wl->group_cipher_method == GELIC_WL_CIPHER_WEP) { @@ -1898,6 +1915,7 @@ static int gelic_wl_do_wep_setup(struct gelic_wl_info *wl) kfree(cmd); out: + free_page((unsigned long)wep); pr_debug("%s: ->\n", __func__); return ret; } @@ -1941,7 +1959,10 @@ static int gelic_wl_do_wpa_setup(struct gelic_wl_info *wl) pr_debug("%s: <-\n", __func__); /* we can assume no one should uses the buffer */ - wpa = wl->buf; + wpa = (struct gelic_eurus_wpa_cfg *)__get_free_page(GFP_KERNEL); + if (!wpa) + return -ENOMEM; + memset(wpa, 0, sizeof(*wpa)); if (!test_bit(GELIC_WL_STAT_WPA_PSK_SET, &wl->stat)) @@ -2000,6 +2021,7 @@ static int gelic_wl_do_wpa_setup(struct gelic_wl_info *wl) else if (cmd->status || cmd->cmd_status) ret = -ENXIO; kfree(cmd); + free_page((unsigned long)wpa); pr_debug("%s: --> %d\n", __func__, ret); return ret; } @@ -2018,7 +2040,10 @@ static int gelic_wl_associate_bss(struct gelic_wl_info *wl, pr_debug("%s: <-\n", __func__); /* do common config */ - common = wl->buf; + common = (struct gelic_eurus_common_cfg *)__get_free_page(GFP_KERNEL); + if (!common) + return -ENOMEM; + memset(common, 0, sizeof(*common)); common->bss_type = cpu_to_be16(GELIC_EURUS_BSS_INFRA); common->op_mode = cpu_to_be16(GELIC_EURUS_OPMODE_11BG); @@ -2104,6 +2129,7 @@ static int gelic_wl_associate_bss(struct gelic_wl_info *wl, pr_info("%s: connected\n", __func__); } out: + free_page((unsigned long)common); pr_debug("%s: ->\n", __func__); return ret; } -- cgit v0.10.2 From 3df4e2486a58826f16574ead1818daab0edb59df Mon Sep 17 00:00:00 2001 From: Masakazu Mokuno Date: Fri, 30 May 2008 16:27:42 +0900 Subject: PS3: gelic: Kill the static bounce buffer As the bounce buffer is allocaetd dynamically, kill the static bounce buffer. Signed-off-by: Masakazu Mokuno Signed-off-by: John W. Linville diff --git a/drivers/net/ps3_gelic_wireless.c b/drivers/net/ps3_gelic_wireless.c index c16a30b..4bc6eaa 100644 --- a/drivers/net/ps3_gelic_wireless.c +++ b/drivers/net/ps3_gelic_wireless.c @@ -2472,16 +2472,9 @@ static struct net_device *gelic_wl_alloc(struct gelic_card *card) BUILD_BUG_ON(PAGE_SIZE < sizeof(struct gelic_eurus_scan_info) * GELIC_EURUS_MAX_SCAN); - wl->buf = (void *)get_zeroed_page(GFP_KERNEL); - if (!wl->buf) { - pr_info("%s:buffer allocation failed\n", __func__); - goto fail_getpage; - } pr_debug("%s:end\n", __func__); return netdev; -fail_getpage: - destroy_workqueue(wl->event_queue); fail_event_workqueue: destroy_workqueue(wl->eurus_cmd_queue); fail_cmd_workqueue: @@ -2500,8 +2493,6 @@ static void gelic_wl_free(struct gelic_wl_info *wl) pr_debug("%s: <-\n", __func__); - free_page((unsigned long)wl->buf); - pr_debug("%s: destroy queues\n", __func__); destroy_workqueue(wl->eurus_cmd_queue); destroy_workqueue(wl->event_queue); diff --git a/drivers/net/ps3_gelic_wireless.h b/drivers/net/ps3_gelic_wireless.h index bc73063..5339e00 100644 --- a/drivers/net/ps3_gelic_wireless.h +++ b/drivers/net/ps3_gelic_wireless.h @@ -288,9 +288,6 @@ struct gelic_wl_info { u8 active_bssid[ETH_ALEN]; /* associated bssid */ unsigned int essid_len; - /* buffer for hypervisor IO */ - void *buf; - struct iw_public_data wireless_data; struct iw_statistics iwstat; }; -- cgit v0.10.2 From ba569b4c68f11906da2996ee252bcff0df61cb90 Mon Sep 17 00:00:00 2001 From: Masakazu Mokuno Date: Fri, 30 May 2008 16:52:23 +0900 Subject: WEXT: Add support for passing PMK and capability flags to WEXT This defines the flags for setting the PMK to the driver and the capability flag for this so that the user space program can figure out whether the target driver wants to do 4-way hand shake by itself and pass the PMK which is needed before 4-way handshake to the driver. Signed-off-by: Masakazu Mokuno Signed-off-by: John W. Linville diff --git a/include/linux/wireless.h b/include/linux/wireless.h index 0a9b5b4..4a95a0e 100644 --- a/include/linux/wireless.h +++ b/include/linux/wireless.h @@ -611,6 +611,7 @@ #define IW_ENCODE_ALG_WEP 1 #define IW_ENCODE_ALG_TKIP 2 #define IW_ENCODE_ALG_CCMP 3 +#define IW_ENCODE_ALG_PMK 4 /* struct iw_encode_ext ->ext_flags */ #define IW_ENCODE_EXT_TX_SEQ_VALID 0x00000001 #define IW_ENCODE_EXT_RX_SEQ_VALID 0x00000002 @@ -630,6 +631,7 @@ #define IW_ENC_CAPA_WPA2 0x00000002 #define IW_ENC_CAPA_CIPHER_TKIP 0x00000004 #define IW_ENC_CAPA_CIPHER_CCMP 0x00000008 +#define IW_ENC_CAPA_4WAY_HANDSHAKE 0x00000010 /* Event capability macros - in (struct iw_range *)->event_capa * Because we have more than 32 possible events, we use an array of -- cgit v0.10.2 From 04b2046c856e36c3c9cf382adb2c0bc8ba780cf7 Mon Sep 17 00:00:00 2001 From: Masakazu Mokuno Date: Fri, 30 May 2008 16:52:44 +0900 Subject: PS3: gelic: Use the new PMK interface in the gelic driver With the new WEXT flags, the PS3 wireless driver can tell the user space that it would do handle 4-way handshake by itself and needs the PSK without private ioctls. Signed-off-by: Masakazu Mokuno Signed-off-by: John W. Linville diff --git a/drivers/net/ps3_gelic_wireless.c b/drivers/net/ps3_gelic_wireless.c index 4bc6eaa..5f69809 100644 --- a/drivers/net/ps3_gelic_wireless.c +++ b/drivers/net/ps3_gelic_wireless.c @@ -350,7 +350,8 @@ static int gelic_wl_get_range(struct net_device *netdev, /* encryption capability */ range->enc_capa = IW_ENC_CAPA_WPA | - IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; + IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP | + IW_ENC_CAPA_4WAY_HANDSHAKE; if (wpa2_capable()) range->enc_capa |= IW_ENC_CAPA_WPA2; range->encoding_size[0] = 5; /* 40bit WEP */ @@ -1256,42 +1257,19 @@ static int gelic_wl_set_encodeext(struct net_device *netdev, set_bit(key_index, &wl->key_enabled); /* remember wep info changed */ set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat); - } else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) { - pr_debug("%s: TKIP/CCMP requested alg=%d\n", __func__, alg); - /* check key length */ - if (IW_ENCODING_TOKEN_MAX < ext->key_len) { - pr_info("%s: key is too long %d\n", __func__, - ext->key_len); + } else if (alg == IW_ENCODE_ALG_PMK) { + if (ext->key_len != WPA_PSK_LEN) { + pr_err("%s: PSK length wrong %d\n", __func__, + ext->key_len); ret = -EINVAL; goto done; } - if (alg == IW_ENCODE_ALG_CCMP) { - pr_debug("%s: AES selected\n", __func__); - wl->group_cipher_method = GELIC_WL_CIPHER_AES; - wl->pairwise_cipher_method = GELIC_WL_CIPHER_AES; - wl->wpa_level = GELIC_WL_WPA_LEVEL_WPA2; - } else { - pr_debug("%s: TKIP selected, WPA forced\n", __func__); - wl->group_cipher_method = GELIC_WL_CIPHER_TKIP; - wl->pairwise_cipher_method = GELIC_WL_CIPHER_TKIP; - /* FIXME: how do we do if WPA2 + TKIP? */ - wl->wpa_level = GELIC_WL_WPA_LEVEL_WPA; - } - if (flags & IW_ENCODE_RESTRICTED) - BUG(); - wl->auth_method = GELIC_EURUS_AUTH_OPEN; - /* We should use same key for both and unicast */ - if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) - pr_debug("%s: group key \n", __func__); - else - pr_debug("%s: unicast key \n", __func__); - /* OK, update the key */ - wl->key_len[key_index] = ext->key_len; - memset(wl->key[key_index], 0, IW_ENCODING_TOKEN_MAX); - memcpy(wl->key[key_index], ext->key, ext->key_len); - set_bit(key_index, &wl->key_enabled); - /* remember info changed */ - set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat); + memset(wl->psk, 0, sizeof(wl->psk)); + memcpy(wl->psk, ext->key, ext->key_len); + wl->psk_len = ext->key_len; + wl->psk_type = GELIC_EURUS_WPA_PSK_BIN; + /* remember PSK configured */ + set_bit(GELIC_WL_STAT_WPA_PSK_SET, &wl->stat); } done: spin_unlock_irqrestore(&wl->lock, irqflag); -- cgit v0.10.2 From f409e348005693016281bf29535c9d0a91b21f77 Mon Sep 17 00:00:00 2001 From: Masakazu Mokuno Date: Fri, 30 May 2008 16:52:55 +0900 Subject: PS3: gelic: Deprecate the private ioctls in the gelic driver As the driver has the standard way to handle PSK, deprecate the old interface. Signed-off-by: Masakazu Mokuno Signed-off-by: John W. Linville diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 9f6cc8a..e52533d 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2283,6 +2283,19 @@ config GELIC_WIRELESS the driver automatically distinguishes the models, you can safely enable this option even if you have a wireless-less model. +config GELIC_WIRELESS_OLD_PSK_INTERFACE + bool "PS3 Wireless private PSK interface (OBSOLETE)" + depends on GELIC_WIRELESS + help + This option retains the obsolete private interface to pass + the PSK from user space programs to the driver. The PSK + stands for 'Pre Shared Key' and is used for WPA[2]-PSK + (WPA-Personal) environment. + If WPA[2]-PSK is used and you need to use old programs that + support only this old interface, say Y. Otherwise N. + + If unsure, say N. + config GIANFAR tristate "Gianfar Ethernet" depends on FSL_SOC diff --git a/drivers/net/ps3_gelic_wireless.c b/drivers/net/ps3_gelic_wireless.c index 5f69809..f5e5f13 100644 --- a/drivers/net/ps3_gelic_wireless.c +++ b/drivers/net/ps3_gelic_wireless.c @@ -1375,6 +1375,7 @@ static int gelic_wl_get_mode(struct net_device *netdev, return 0; } +#ifdef CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE /* SIOCIWFIRSTPRIV */ static int hex2bin(u8 *str, u8 *bin, unsigned int len) { @@ -1479,6 +1480,7 @@ static int gelic_wl_priv_get_psk(struct net_device *net_dev, pr_debug("%s:-> %d\n", __func__, data->data.length); return 0; } +#endif /* SIOCGIWNICKN */ static int gelic_wl_get_nick(struct net_device *net_dev, @@ -2355,6 +2357,7 @@ static const iw_handler gelic_wl_wext_handler[] = IW_IOCTL(SIOCGIWNICKN) = gelic_wl_get_nick, }; +#ifdef CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE static struct iw_priv_args gelic_wl_private_args[] = { { @@ -2376,15 +2379,18 @@ static const iw_handler gelic_wl_private_handler[] = gelic_wl_priv_set_psk, gelic_wl_priv_get_psk, }; +#endif static const struct iw_handler_def gelic_wl_wext_handler_def = { .num_standard = ARRAY_SIZE(gelic_wl_wext_handler), .standard = gelic_wl_wext_handler, .get_wireless_stats = gelic_wl_get_wireless_stats, +#ifdef CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE .num_private = ARRAY_SIZE(gelic_wl_private_handler), .num_private_args = ARRAY_SIZE(gelic_wl_private_args), .private = gelic_wl_private_handler, .private_args = gelic_wl_private_args, +#endif }; static struct net_device *gelic_wl_alloc(struct gelic_card *card) -- cgit v0.10.2 From 552fe53f48ef2fd54b031b37d304211cee893ba0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 30 May 2008 21:07:15 +0200 Subject: p54: fix skb->cb tx info conversion When I moved the TX info into skb->cb apparently I forgot to change a few places to put the p54-internal data into info->driver_data rather than skb->cb. This should fix it. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 91ac920..9f7224d 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -392,16 +392,21 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) u32 last_addr = priv->rx_start; while (entry != (struct sk_buff *)&priv->tx_queue) { - range = (struct memrecord *)&entry->cb; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry); + range = (void *)info->driver_data; if (range->start_addr == addr) { - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry); struct p54_control_hdr *entry_hdr; struct p54_tx_control_allocdata *entry_data; int pad = 0; - if (entry->next != (struct sk_buff *)&priv->tx_queue) - freed = ((struct memrecord *)&entry->next->cb)->start_addr - last_addr; - else + if (entry->next != (struct sk_buff *)&priv->tx_queue) { + struct ieee80211_tx_info *ni; + struct memrecord *mr; + + ni = IEEE80211_SKB_CB(entry->next); + mr = (struct memrecord *)ni->driver_data; + freed = mr->start_addr - last_addr; + } else freed = priv->rx_end - last_addr; last_addr = range->end_addr; -- cgit v0.10.2 From 7fd871edf437362b62ddd807542638cbda8d8a39 Mon Sep 17 00:00:00 2001 From: Masakazu Mokuno Date: Mon, 2 Jun 2008 12:49:16 +0900 Subject: PS3: gelic: Add support for ESSID scan This adds the support for ESSID scanning Signed-off-by: Masakazu Mokuno Signed-off-by: John W. Linville diff --git a/drivers/net/ps3_gelic_wireless.c b/drivers/net/ps3_gelic_wireless.c index f5e5f13..aa963ac 100644 --- a/drivers/net/ps3_gelic_wireless.c +++ b/drivers/net/ps3_gelic_wireless.c @@ -45,7 +45,8 @@ #include "ps3_gelic_wireless.h" -static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan); +static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan, + u8 *essid, size_t essid_len); static int gelic_wl_try_associate(struct net_device *netdev); /* @@ -105,6 +106,7 @@ static const struct eurus_cmd_arg_info cmd_info[GELIC_EURUS_CMD_MAX_INDEX] = { [GELIC_EURUS_CMD_GET_WEP_CFG] = { .post_arg = 1}, [GELIC_EURUS_CMD_GET_WPA_CFG] = { .post_arg = 1}, [GELIC_EURUS_CMD_GET_RSSI_CFG] = { .post_arg = 1}, + [GELIC_EURUS_CMD_START_SCAN] = { .pre_arg = 1}, [GELIC_EURUS_CMD_GET_SCAN] = { .post_arg = 1}, }; @@ -163,7 +165,9 @@ static void gelic_eurus_sync_cmd_worker(struct work_struct *work) card = port_to_card(wl_port(wl)); if (cmd_info[cmd->cmd].pre_arg) { - arg1 = ps3_mm_phys_to_lpar(__pa(cmd->buffer)); + arg1 = (cmd->buffer) ? + ps3_mm_phys_to_lpar(__pa(cmd->buffer)) : + 0; arg2 = cmd->buf_size; } else { arg1 = 0; @@ -360,6 +364,9 @@ static int gelic_wl_get_range(struct net_device *netdev, range->num_encoding_sizes = 3; range->max_encoding_tokens = GELIC_WEP_KEYS; + /* scan capability */ + range->scan_capa = IW_SCAN_CAPA_ESSID; + pr_debug("%s: ->\n", __func__); return 0; @@ -371,8 +378,18 @@ static int gelic_wl_set_scan(struct net_device *netdev, union iwreq_data *wrqu, char *extra) { struct gelic_wl_info *wl = port_wl(netdev_priv(netdev)); - - return gelic_wl_start_scan(wl, 1); + struct iw_scan_req *req; + u8 *essid = NULL; + size_t essid_len = 0; + + if (wrqu->data.length == sizeof(struct iw_scan_req) && + wrqu->data.flags & IW_SCAN_THIS_ESSID) { + req = (struct iw_scan_req*)extra; + essid = req->essid; + essid_len = req->essid_len; + pr_debug("%s: ESSID scan =%s\n", __func__, essid); + } + return gelic_wl_start_scan(wl, 1, essid, essid_len); } #define OUI_LEN 3 @@ -1534,10 +1551,13 @@ static struct iw_statistics *gelic_wl_get_wireless_stats( /* * scanning helpers */ -static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan) +static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan, + u8 *essid, size_t essid_len) { struct gelic_eurus_cmd *cmd; int ret = 0; + void *buf = NULL; + size_t len; pr_debug("%s: <- always=%d\n", __func__, always_scan); if (mutex_lock_interruptible(&wl->scan_lock)) @@ -1560,12 +1580,27 @@ static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan) complete(&wl->scan_done); goto out; } + + /* ESSID scan ? */ + if (essid_len && essid) { + buf = (void *)__get_free_page(GFP_KERNEL); + if (!buf) { + ret = -ENOMEM; + goto out; + } + len = IW_ESSID_MAX_SIZE; /* hypervisor always requires 32 */ + memset(buf, 0, len); + memcpy(buf, essid, essid_len); + pr_debug("%s: essid scan='%s'\n", __func__, (char *)buf); + } else + len = 0; + /* * issue start scan request */ wl->scan_stat = GELIC_WL_SCAN_STAT_SCANNING; cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_START_SCAN, - NULL, 0); + buf, len); if (!cmd || cmd->status || cmd->cmd_status) { wl->scan_stat = GELIC_WL_SCAN_STAT_INIT; complete(&wl->scan_done); @@ -1574,6 +1609,7 @@ static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan) } kfree(cmd); out: + free_page((unsigned long)buf); mutex_unlock(&wl->scan_lock); pr_debug("%s: ->\n", __func__); return ret; @@ -2261,6 +2297,9 @@ static void gelic_wl_assoc_worker(struct work_struct *work) struct gelic_wl_scan_info *best_bss; int ret; + unsigned long irqflag; + u8 *essid; + size_t essid_len; wl = container_of(work, struct gelic_wl_info, assoc_work.work); @@ -2269,7 +2308,19 @@ static void gelic_wl_assoc_worker(struct work_struct *work) if (wl->assoc_stat != GELIC_WL_ASSOC_STAT_DISCONN) goto out; - ret = gelic_wl_start_scan(wl, 0); + spin_lock_irqsave(&wl->lock, irqflag); + if (test_bit(GELIC_WL_STAT_ESSID_SET, &wl->stat)) { + pr_debug("%s: assoc ESSID configured %s\n", __func__, + wl->essid); + essid = wl->essid; + essid_len = wl->essid_len; + } else { + essid = NULL; + essid_len = 0; + } + spin_unlock_irqrestore(&wl->lock, irqflag); + + ret = gelic_wl_start_scan(wl, 0, essid, essid_len); if (ret == -ERESTARTSYS) { pr_debug("%s: scan start failed association\n", __func__); schedule_delayed_work(&wl->assoc_work, HZ/10); /*FIXME*/ -- cgit v0.10.2 From 5854a32e6cb672d182ce378c69f0f7470137a062 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 2 Jun 2008 09:38:04 +0200 Subject: mac80211: fix rate control initialisation In commit 2e92e6f2c50b4baf85cca968f0e6f1b5c0df7d39 ("mac80211: use rate index in TX control") I forgot to initialise a few new variables to -1 which means that the rate control algorithm is never triggered and 0 is used as the only rate index, effectively fixing the transmit bitrate at the lowest supported. This patch adds the missing initialisation. Signed-off-by: Johannes Berg Bisected-by: Sitsofe Wheeler Signed-off-by: John W. Linville diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 16af308..332ddcb 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -947,6 +947,8 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, tx->local = local; tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev); tx->channel = local->hw.conf.channel; + tx->rate_idx = -1; + tx->last_frag_rate_idx = -1; /* * Set this flag (used below to indicate "automatic fragmentation"), * it will be cleared/left by radiotap as desired. -- cgit v0.10.2 From 2b2121417eff64125bdb7f322d3b533e06d73dae Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Mon, 2 Jun 2008 07:54:50 -0400 Subject: mac80211: fix panic when using hardware WEP e039fa4a4195ac4ee895e6f3d1334beed63256fe ("mac80211: move TX info into skb->cb") misplaced code for setting hardware WEP keys. Move it back. This fixes kernel panic in b43 if WEP is used and hardware encryption is enabled. Signed-off-by: Pavel Roskin Acked-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index c9fd129..e7b6344 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c @@ -335,10 +335,10 @@ static int wep_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) info->control.icv_len = WEP_ICV_LEN; if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { - info->control.hw_key = &tx->key->conf; if (ieee80211_wep_encrypt(tx->local, skb, tx->key)) return -1; } else { + info->control.hw_key = &tx->key->conf; if (tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) { if (!ieee80211_wep_add_iv(tx->local, skb, tx->key)) return -1; -- cgit v0.10.2 From b97e77e0446f0702de7fa0f5d2c52acf42d0289f Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Mon, 2 Jun 2008 20:31:56 +0300 Subject: mac80211: fix unbalanced locking in ieee80211_get_buffered_bc This patch fixes unbalanced locking in ieee80211_get_buffered_bc Signed-off-by: Tomas Winkler Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 332ddcb..4214d03 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -2011,7 +2011,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, } if (WARN_ON(tx.skb != skb)) - return NULL; + res = TX_DROP; if (res == TX_DROP) { I802_DEBUG_INC(local->tx_handlers_drop); -- cgit v0.10.2 From 2d892986e82306b8ad96285fb54b9999523331e0 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Mon, 2 Jun 2008 20:31:57 +0300 Subject: mac80211: removing shadowed sband This patch removes doubly defined sband variable Signed-off-by: Tomas Winkler Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 4214d03..1ad9e66 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -612,13 +612,10 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) || (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) { - struct ieee80211_supported_band *sband; struct ieee80211_rate *rate; s8 baserate = -1; int idx; - sband = tx->local->hw.wiphy->bands[tx->channel->band]; - /* Do not use multiple retry rates when using RTS/CTS */ info->control.alt_retry_rate_idx = -1; -- cgit v0.10.2 From 78cf07472f0ede8394bacc4bc02354505080cfe1 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Mon, 2 Jun 2008 09:25:05 +0200 Subject: libertas: unify various CF-related defines Signed-off-by: Holger Schurig Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index 5963d92..873ab10 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -159,56 +159,40 @@ static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 r -/* Host control registers and their bit definitions */ +/* First the bitmasks for the host/card interrupt/status registers: */ +#define IF_CS_BIT_TX 0x0001 +#define IF_CS_BIT_RX 0x0002 +#define IF_CS_BIT_COMMAND 0x0004 +#define IF_CS_BIT_RESP 0x0008 +#define IF_CS_BIT_EVENT 0x0010 +#define IF_CS_BIT_MASK 0x001f -#define IF_CS_H_STATUS 0x00000000 -#define IF_CS_H_STATUS_TX_OVER 0x0001 -#define IF_CS_H_STATUS_RX_OVER 0x0002 -#define IF_CS_H_STATUS_DNLD_OVER 0x0004 +/* And now the individual registers and assorted masks */ +#define IF_CS_HOST_STATUS 0x00000000 -#define IF_CS_H_INT_CAUSE 0x00000002 -#define IF_CS_H_IC_TX_OVER 0x0001 -#define IF_CS_H_IC_RX_OVER 0x0002 -#define IF_CS_H_IC_DNLD_OVER 0x0004 -#define IF_CS_H_IC_POWER_DOWN 0x0008 -#define IF_CS_H_IC_HOST_EVENT 0x0010 -#define IF_CS_H_IC_MASK 0x001f +#define IF_CS_HOST_INT_CAUSE 0x00000002 -#define IF_CS_H_INT_MASK 0x00000004 -#define IF_CS_H_IM_MASK 0x001f +#define IF_CS_HOST_INT_MASK 0x00000004 -#define IF_CS_H_WRITE_LEN 0x00000014 +#define IF_CS_HOST_WRITE 0x00000016 +#define IF_CS_HOST_WRITE_LEN 0x00000014 -#define IF_CS_H_WRITE 0x00000016 +#define IF_CS_HOST_CMD 0x0000001A +#define IF_CS_HOST_CMD_LEN 0x00000018 -#define IF_CS_H_CMD_LEN 0x00000018 +#define IF_CS_READ 0x00000010 +#define IF_CS_READ_LEN 0x00000024 -#define IF_CS_H_CMD 0x0000001A +#define IF_CS_CARD_CMD 0x00000012 +#define IF_CS_CARD_CMD_LEN 0x00000030 -#define IF_CS_C_READ_LEN 0x00000024 +#define IF_CS_CARD_STATUS 0x00000020 +#define IF_CS_CARD_STATUS_MASK 0x7f00 -#define IF_CS_H_READ 0x00000010 +#define IF_CS_CARD_INT_CAUSE 0x00000022 -/* Card control registers and their bit definitions */ - -#define IF_CS_C_STATUS 0x00000020 -#define IF_CS_C_S_TX_DNLD_RDY 0x0001 -#define IF_CS_C_S_RX_UPLD_RDY 0x0002 -#define IF_CS_C_S_CMD_DNLD_RDY 0x0004 -#define IF_CS_C_S_CMD_UPLD_RDY 0x0008 -#define IF_CS_C_S_CARDEVENT 0x0010 -#define IF_CS_C_S_MASK 0x001f -#define IF_CS_C_S_STATUS_MASK 0x7f00 - -#define IF_CS_C_INT_CAUSE 0x00000022 -#define IF_CS_C_IC_MASK 0x001f - -#define IF_CS_C_SQ_READ_LOW 0x00000028 -#define IF_CS_C_SQ_HELPER_OK 0x10 - -#define IF_CS_C_CMD_LEN 0x00000030 - -#define IF_CS_C_CMD 0x00000012 +#define IF_CS_CARD_SQ_READ_LOW 0x00000028 +#define IF_CS_CARD_SQ_HELPER_OK 0x10 #define IF_CS_SCRATCH 0x0000003F @@ -221,13 +205,13 @@ static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 r static inline void if_cs_enable_ints(struct if_cs_card *card) { lbs_deb_enter(LBS_DEB_CS); - if_cs_write16(card, IF_CS_H_INT_MASK, 0); + if_cs_write16(card, IF_CS_HOST_INT_MASK, 0); } static inline void if_cs_disable_ints(struct if_cs_card *card) { lbs_deb_enter(LBS_DEB_CS); - if_cs_write16(card, IF_CS_H_INT_MASK, IF_CS_H_IM_MASK); + if_cs_write16(card, IF_CS_HOST_INT_MASK, IF_CS_BIT_MASK); } /* @@ -244,8 +228,8 @@ static int if_cs_send_cmd(struct lbs_private *priv, u8 *buf, u16 nb) /* Is hardware ready? */ while (1) { - u16 val = if_cs_read16(card, IF_CS_C_STATUS); - if (val & IF_CS_C_S_CMD_DNLD_RDY) + u16 val = if_cs_read16(card, IF_CS_CARD_STATUS); + if (val & IF_CS_BIT_COMMAND) break; if (++loops > 100) { lbs_pr_err("card not ready for commands\n"); @@ -254,20 +238,20 @@ static int if_cs_send_cmd(struct lbs_private *priv, u8 *buf, u16 nb) mdelay(1); } - if_cs_write16(card, IF_CS_H_CMD_LEN, nb); + if_cs_write16(card, IF_CS_HOST_CMD_LEN, nb); - if_cs_write16_rep(card, IF_CS_H_CMD, buf, nb / 2); + if_cs_write16_rep(card, IF_CS_HOST_CMD, buf, nb / 2); /* Are we supposed to transfer an odd amount of bytes? */ if (nb & 1) - if_cs_write8(card, IF_CS_H_CMD, buf[nb-1]); + if_cs_write8(card, IF_CS_HOST_CMD, buf[nb-1]); /* "Assert the download over interrupt command in the Host * status register" */ - if_cs_write16(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER); + if_cs_write16(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND); /* "Assert the download over interrupt command in the Card * interrupt case register" */ - if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER); + if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND); ret = 0; done: @@ -287,18 +271,18 @@ static void if_cs_send_data(struct lbs_private *priv, u8 *buf, u16 nb) lbs_deb_enter(LBS_DEB_CS); if_cs_disable_ints(card); - status = if_cs_read16(card, IF_CS_C_STATUS); - BUG_ON((status & IF_CS_C_S_TX_DNLD_RDY) == 0); + status = if_cs_read16(card, IF_CS_CARD_STATUS); + BUG_ON((status & IF_CS_BIT_TX) == 0); - if_cs_write16(card, IF_CS_H_WRITE_LEN, nb); + if_cs_write16(card, IF_CS_HOST_WRITE_LEN, nb); /* write even number of bytes, then odd byte if necessary */ - if_cs_write16_rep(card, IF_CS_H_WRITE, buf, nb / 2); + if_cs_write16_rep(card, IF_CS_HOST_WRITE, buf, nb / 2); if (nb & 1) - if_cs_write8(card, IF_CS_H_WRITE, buf[nb-1]); + if_cs_write8(card, IF_CS_HOST_WRITE, buf[nb-1]); - if_cs_write16(card, IF_CS_H_STATUS, IF_CS_H_STATUS_TX_OVER); - if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_STATUS_TX_OVER); + if_cs_write16(card, IF_CS_HOST_STATUS, IF_CS_BIT_TX); + if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_TX); if_cs_enable_ints(card); lbs_deb_leave(LBS_DEB_CS); @@ -311,27 +295,28 @@ static int if_cs_receive_cmdres(struct lbs_private *priv, u8 *data, u32 *len) { unsigned long flags; int ret = -1; - u16 val; + u16 status; lbs_deb_enter(LBS_DEB_CS); /* is hardware ready? */ - val = if_cs_read16(priv->card, IF_CS_C_STATUS); - if ((val & IF_CS_C_S_CMD_UPLD_RDY) == 0) { - lbs_pr_err("card not ready for CMD\n"); + status = if_cs_read16(priv->card, IF_CS_CARD_STATUS); + if ((status & IF_CS_BIT_RESP) == 0) { + lbs_pr_err("no cmd response in card\n"); + *len = 0; goto out; } - *len = if_cs_read16(priv->card, IF_CS_C_CMD_LEN); + *len = if_cs_read16(priv->card, IF_CS_CARD_CMD_LEN); if ((*len == 0) || (*len > LBS_CMD_BUFFER_SIZE)) { lbs_pr_err("card cmd buffer has invalid # of bytes (%d)\n", *len); goto out; } /* read even number of bytes, then odd byte if necessary */ - if_cs_read16_rep(priv->card, IF_CS_C_CMD, data, *len/sizeof(u16)); + if_cs_read16_rep(priv->card, IF_CS_CARD_CMD, data, *len/sizeof(u16)); if (*len & 1) - data[*len-1] = if_cs_read8(priv->card, IF_CS_C_CMD); + data[*len-1] = if_cs_read8(priv->card, IF_CS_CARD_CMD); /* This is a workaround for a firmware that reports too much * bytes */ @@ -356,7 +341,7 @@ static struct sk_buff *if_cs_receive_data(struct lbs_private *priv) lbs_deb_enter(LBS_DEB_CS); - len = if_cs_read16(priv->card, IF_CS_C_READ_LEN); + len = if_cs_read16(priv->card, IF_CS_READ_LEN); if (len == 0 || len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) { lbs_pr_err("card data buffer has invalid # of bytes (%d)\n", len); priv->stats.rx_dropped++; @@ -371,13 +356,13 @@ static struct sk_buff *if_cs_receive_data(struct lbs_private *priv) data = skb->data; /* read even number of bytes, then odd byte if necessary */ - if_cs_read16_rep(priv->card, IF_CS_H_READ, data, len/sizeof(u16)); + if_cs_read16_rep(priv->card, IF_CS_READ, data, len/sizeof(u16)); if (len & 1) - data[len-1] = if_cs_read8(priv->card, IF_CS_H_READ); + data[len-1] = if_cs_read8(priv->card, IF_CS_READ); dat_err: - if_cs_write16(priv->card, IF_CS_H_STATUS, IF_CS_H_STATUS_RX_OVER); - if_cs_write16(priv->card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_RX_OVER); + if_cs_write16(priv->card, IF_CS_HOST_STATUS, IF_CS_BIT_RX); + if_cs_write16(priv->card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_RX); out: lbs_deb_leave_args(LBS_DEB_CS, "ret %p", skb); @@ -393,7 +378,7 @@ static irqreturn_t if_cs_interrupt(int irq, void *data) lbs_deb_enter(LBS_DEB_CS); /* Ask card interrupt cause register if there is something for us */ - cause = if_cs_read16(card, IF_CS_C_INT_CAUSE); + cause = if_cs_read16(card, IF_CS_CARD_INT_CAUSE); if (cause == 0) { /* Not for us */ return IRQ_NONE; @@ -406,10 +391,10 @@ static irqreturn_t if_cs_interrupt(int irq, void *data) } /* Clear interrupt cause */ - if_cs_write16(card, IF_CS_C_INT_CAUSE, cause & IF_CS_C_IC_MASK); + if_cs_write16(card, IF_CS_CARD_INT_CAUSE, cause & IF_CS_BIT_MASK); lbs_deb_cs("cause 0x%04x\n", cause); - if (cause & IF_CS_C_S_RX_UPLD_RDY) { + if (cause & IF_CS_BIT_RX) { struct sk_buff *skb; lbs_deb_cs("rx packet\n"); skb = if_cs_receive_data(priv); @@ -417,12 +402,12 @@ static irqreturn_t if_cs_interrupt(int irq, void *data) lbs_process_rxed_packet(priv, skb); } - if (cause & IF_CS_H_IC_TX_OVER) { + if (cause & IF_CS_BIT_TX) { lbs_deb_cs("tx done\n"); lbs_host_to_card_done(priv); } - if (cause & IF_CS_C_S_CMD_UPLD_RDY) { + if (cause & IF_CS_BIT_RESP) { unsigned long flags; u8 i; @@ -440,11 +425,11 @@ static irqreturn_t if_cs_interrupt(int irq, void *data) spin_unlock_irqrestore(&priv->driver_lock, flags); } - if (cause & IF_CS_H_IC_HOST_EVENT) { - u16 event = if_cs_read16(priv->card, IF_CS_C_STATUS) - & IF_CS_C_S_STATUS_MASK; - if_cs_write16(priv->card, IF_CS_H_INT_CAUSE, - IF_CS_H_IC_HOST_EVENT); + if (cause & IF_CS_BIT_EVENT) { + u16 event = if_cs_read16(priv->card, IF_CS_CARD_STATUS) + & IF_CS_CARD_STATUS_MASK; + if_cs_write16(priv->card, IF_CS_HOST_INT_CAUSE, + IF_CS_BIT_EVENT); lbs_deb_cs("host event 0x%04x\n", event); lbs_queue_event(priv, event >> 8 & 0xff); } @@ -511,26 +496,26 @@ static int if_cs_prog_helper(struct if_cs_card *card) /* "write the number of bytes to be sent to the I/O Command * write length register" */ - if_cs_write16(card, IF_CS_H_CMD_LEN, count); + if_cs_write16(card, IF_CS_HOST_CMD_LEN, count); /* "write this to I/O Command port register as 16 bit writes */ if (count) - if_cs_write16_rep(card, IF_CS_H_CMD, + if_cs_write16_rep(card, IF_CS_HOST_CMD, &fw->data[sent], count >> 1); /* "Assert the download over interrupt command in the Host * status register" */ - if_cs_write8(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER); + if_cs_write8(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND); /* "Assert the download over interrupt command in the Card * interrupt case register" */ - if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER); + if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND); /* "The host polls the Card Status register ... for 50 ms before declaring a failure */ - ret = if_cs_poll_while_fw_download(card, IF_CS_C_STATUS, - IF_CS_C_S_CMD_DNLD_RDY); + ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS, + IF_CS_BIT_COMMAND); if (ret < 0) { lbs_pr_err("can't download helper at 0x%x, ret %d\n", sent, ret); @@ -572,14 +557,15 @@ static int if_cs_prog_real(struct if_cs_card *card) } lbs_deb_cs("fw size %td\n", fw->size); - ret = if_cs_poll_while_fw_download(card, IF_CS_C_SQ_READ_LOW, IF_CS_C_SQ_HELPER_OK); + ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_SQ_READ_LOW, + IF_CS_CARD_SQ_HELPER_OK); if (ret < 0) { lbs_pr_err("helper firmware doesn't answer\n"); goto err_release; } for (sent = 0; sent < fw->size; sent += len) { - len = if_cs_read16(card, IF_CS_C_SQ_READ_LOW); + len = if_cs_read16(card, IF_CS_CARD_SQ_READ_LOW); if (len & 1) { retry++; lbs_pr_info("odd, need to retry this firmware block\n"); @@ -597,16 +583,16 @@ static int if_cs_prog_real(struct if_cs_card *card) } - if_cs_write16(card, IF_CS_H_CMD_LEN, len); + if_cs_write16(card, IF_CS_HOST_CMD_LEN, len); - if_cs_write16_rep(card, IF_CS_H_CMD, + if_cs_write16_rep(card, IF_CS_HOST_CMD, &fw->data[sent], (len+1) >> 1); - if_cs_write8(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER); - if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER); + if_cs_write8(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND); + if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND); - ret = if_cs_poll_while_fw_download(card, IF_CS_C_STATUS, - IF_CS_C_S_CMD_DNLD_RDY); + ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS, + IF_CS_BIT_COMMAND); if (ret < 0) { lbs_pr_err("can't download firmware at 0x%x\n", sent); goto err_release; @@ -834,7 +820,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev) /* Clear any interrupt cause that happend while sending * firmware/initializing card */ - if_cs_write16(card, IF_CS_C_INT_CAUSE, IF_CS_C_IC_MASK); + if_cs_write16(card, IF_CS_CARD_INT_CAUSE, IF_CS_BIT_MASK); if_cs_enable_ints(card); /* And finally bring the card up */ -- cgit v0.10.2