From 61448f88078e813bbaaa58eb775d650c85e7d407 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Sat, 10 May 2008 13:43:33 +0200 Subject: [PATCH] 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 --- drivers/net/wireless/rt2x00/rt2400pci.c | 2 +- drivers/net/wireless/rt2x00/rt2400pci.h | 5 +++++ drivers/net/wireless/rt2x00/rt2500pci.c | 2 +- drivers/net/wireless/rt2x00/rt2500pci.h | 5 +++++ drivers/net/wireless/rt2x00/rt2500usb.c | 2 +- drivers/net/wireless/rt2x00/rt2500usb.h | 5 +++++ drivers/net/wireless/rt2x00/rt2x00.h | 1 + drivers/net/wireless/rt2x00/rt2x00dev.c | 5 +++++ drivers/net/wireless/rt2x00/rt2x00mac.c | 2 +- drivers/net/wireless/rt2x00/rt2x00queue.c | 8 ++++---- drivers/net/wireless/rt2x00/rt2x00queue.h | 2 +- drivers/net/wireless/rt2x00/rt61pci.c | 2 +- drivers/net/wireless/rt2x00/rt61pci.h | 5 +++++ drivers/net/wireless/rt2x00/rt73usb.c | 2 +- drivers/net/wireless/rt2x00/rt73usb.h | 5 +++++ 15 files changed, 42 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index fb02d118075..b4310d798f9 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 a5210f9a336..e9aa326be9f 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.h +++ b/drivers/net/wireless/rt2x00/rt2400pci.h @@ -51,6 +51,11 @@ #define BBP_SIZE 0x0020 #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 1724ce90f8b..54aaa8375a2 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 13899550465..ea93b8f423a 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.h +++ b/drivers/net/wireless/rt2x00/rt2500pci.h @@ -62,6 +62,11 @@ #define BBP_SIZE 0x0040 #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 7df06ece1b4..661cf3d7212 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 a37a068d0c7..7d50098f0cc 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.h +++ b/drivers/net/wireless/rt2x00/rt2500usb.h @@ -62,6 +62,11 @@ #define BBP_SIZE 0x0060 #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 65614841f74..6f7b34fac16 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 e1368f70985..46c377873f1 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -974,6 +974,11 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) if (status) return status; + /* + * Initialize HW fields. + */ + rt2x00dev->hw->queues = rt2x00dev->ops->tx_queues; + /* * Register HW. */ diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 767e0ffce04..c5cedb29b87 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 e5b861f8416..95f8dd3462f 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 3f7cfa9b7da..4bde98ba3c6 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 5d690ee1bef..68d2216131b 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 3511bba7ff6..c5a04b9329d 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.h +++ b/drivers/net/wireless/rt2x00/rt61pci.h @@ -53,6 +53,11 @@ #define BBP_SIZE 0x0080 #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 d98002cfe09..2191d8b94a8 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 06d687425fe..25cdcc9bf7c 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.h +++ b/drivers/net/wireless/rt2x00/rt73usb.h @@ -53,6 +53,11 @@ #define BBP_SIZE 0x0080 #define RF_SIZE 0x0014 +/* + * Number of TX queues. + */ +#define NUM_TX_QUEUES 4 + /* * USB registers. */ -- 2.41.1