Commit 61448f88 authored by Gertjan van Wingerde's avatar Gertjan van Wingerde Committed by John W. Linville

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: default avatarGertjan van Wingerde <gwingerde@kpnplanet.nl>
Signed-off-by: default avatarIvo van Doorn <IvDoorn@gmail.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 61486e0f
...@@ -1373,7 +1373,6 @@ static void rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) ...@@ -1373,7 +1373,6 @@ static void rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
IEEE80211_HW_SIGNAL_DBM; IEEE80211_HW_SIGNAL_DBM;
rt2x00dev->hw->extra_tx_headroom = 0; rt2x00dev->hw->extra_tx_headroom = 0;
rt2x00dev->hw->queues = 2;
SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev); SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev);
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
...@@ -1620,6 +1619,7 @@ static const struct rt2x00_ops rt2400pci_ops = { ...@@ -1620,6 +1619,7 @@ static const struct rt2x00_ops rt2400pci_ops = {
.max_ap_intf = 1, .max_ap_intf = 1,
.eeprom_size = EEPROM_SIZE, .eeprom_size = EEPROM_SIZE,
.rf_size = RF_SIZE, .rf_size = RF_SIZE,
.tx_queues = NUM_TX_QUEUES,
.rx = &rt2400pci_queue_rx, .rx = &rt2400pci_queue_rx,
.tx = &rt2400pci_queue_tx, .tx = &rt2400pci_queue_tx,
.bcn = &rt2400pci_queue_bcn, .bcn = &rt2400pci_queue_bcn,
......
...@@ -51,6 +51,11 @@ ...@@ -51,6 +51,11 @@
#define BBP_SIZE 0x0020 #define BBP_SIZE 0x0020
#define RF_SIZE 0x0010 #define RF_SIZE 0x0010
/*
* Number of TX queues.
*/
#define NUM_TX_QUEUES 2
/* /*
* Control/Status Registers(CSR). * Control/Status Registers(CSR).
* Some values are set in TU, whereas 1 TU == 1024 us. * Some values are set in TU, whereas 1 TU == 1024 us.
......
...@@ -1692,7 +1692,6 @@ static void rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) ...@@ -1692,7 +1692,6 @@ static void rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
IEEE80211_HW_SIGNAL_DBM; IEEE80211_HW_SIGNAL_DBM;
rt2x00dev->hw->extra_tx_headroom = 0; rt2x00dev->hw->extra_tx_headroom = 0;
rt2x00dev->hw->queues = 2;
SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev); SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev);
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
...@@ -1933,6 +1932,7 @@ static const struct rt2x00_ops rt2500pci_ops = { ...@@ -1933,6 +1932,7 @@ static const struct rt2x00_ops rt2500pci_ops = {
.max_ap_intf = 1, .max_ap_intf = 1,
.eeprom_size = EEPROM_SIZE, .eeprom_size = EEPROM_SIZE,
.rf_size = RF_SIZE, .rf_size = RF_SIZE,
.tx_queues = NUM_TX_QUEUES,
.rx = &rt2500pci_queue_rx, .rx = &rt2500pci_queue_rx,
.tx = &rt2500pci_queue_tx, .tx = &rt2500pci_queue_tx,
.bcn = &rt2500pci_queue_bcn, .bcn = &rt2500pci_queue_bcn,
......
...@@ -62,6 +62,11 @@ ...@@ -62,6 +62,11 @@
#define BBP_SIZE 0x0040 #define BBP_SIZE 0x0040
#define RF_SIZE 0x0014 #define RF_SIZE 0x0014
/*
* Number of TX queues.
*/
#define NUM_TX_QUEUES 2
/* /*
* Control/Status Registers(CSR). * Control/Status Registers(CSR).
* Some values are set in TU, whereas 1 TU == 1024 us. * Some values are set in TU, whereas 1 TU == 1024 us.
......
...@@ -1590,7 +1590,6 @@ static void rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) ...@@ -1590,7 +1590,6 @@ static void rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
IEEE80211_HW_SIGNAL_DBM; IEEE80211_HW_SIGNAL_DBM;
rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE; rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE;
rt2x00dev->hw->queues = 2;
SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev); SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev);
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
...@@ -1826,6 +1825,7 @@ static const struct rt2x00_ops rt2500usb_ops = { ...@@ -1826,6 +1825,7 @@ static const struct rt2x00_ops rt2500usb_ops = {
.max_ap_intf = 1, .max_ap_intf = 1,
.eeprom_size = EEPROM_SIZE, .eeprom_size = EEPROM_SIZE,
.rf_size = RF_SIZE, .rf_size = RF_SIZE,
.tx_queues = NUM_TX_QUEUES,
.rx = &rt2500usb_queue_rx, .rx = &rt2500usb_queue_rx,
.tx = &rt2500usb_queue_tx, .tx = &rt2500usb_queue_tx,
.bcn = &rt2500usb_queue_bcn, .bcn = &rt2500usb_queue_bcn,
......
...@@ -62,6 +62,11 @@ ...@@ -62,6 +62,11 @@
#define BBP_SIZE 0x0060 #define BBP_SIZE 0x0060
#define RF_SIZE 0x0014 #define RF_SIZE 0x0014
/*
* Number of TX queues.
*/
#define NUM_TX_QUEUES 2
/* /*
* Control/Status Registers(CSR). * Control/Status Registers(CSR).
* Some values are set in TU, whereas 1 TU == 1024 us. * Some values are set in TU, whereas 1 TU == 1024 us.
......
...@@ -591,6 +591,7 @@ struct rt2x00_ops { ...@@ -591,6 +591,7 @@ struct rt2x00_ops {
const unsigned int max_ap_intf; const unsigned int max_ap_intf;
const unsigned int eeprom_size; const unsigned int eeprom_size;
const unsigned int rf_size; const unsigned int rf_size;
const unsigned int tx_queues;
const struct data_queue_desc *rx; const struct data_queue_desc *rx;
const struct data_queue_desc *tx; const struct data_queue_desc *tx;
const struct data_queue_desc *bcn; const struct data_queue_desc *bcn;
......
...@@ -974,6 +974,11 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) ...@@ -974,6 +974,11 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev)
if (status) if (status)
return status; return status;
/*
* Initialize HW fields.
*/
rt2x00dev->hw->queues = rt2x00dev->ops->tx_queues;
/* /*
* Register HW. * Register HW.
*/ */
......
...@@ -456,7 +456,7 @@ int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw, ...@@ -456,7 +456,7 @@ int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw,
struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2x00_dev *rt2x00dev = hw->priv;
unsigned int i; 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].len = rt2x00dev->tx[i].length;
stats[i].limit = rt2x00dev->tx[i].limit; stats[i].limit = rt2x00dev->tx[i].limit;
stats[i].count = rt2x00dev->tx[i].count; stats[i].count = rt2x00dev->tx[i].count;
......
...@@ -34,7 +34,7 @@ struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev, ...@@ -34,7 +34,7 @@ struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev,
{ {
int atim = test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags); 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]; return &rt2x00dev->tx[queue];
if (!rt2x00dev->bcn) if (!rt2x00dev->bcn)
...@@ -255,11 +255,11 @@ int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev) ...@@ -255,11 +255,11 @@ int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev)
/* /*
* We need the following queues: * We need the following queues:
* RX: 1 * RX: 1
* TX: hw->queues * TX: ops->tx_queues
* Beacon: 1 * Beacon: 1
* Atim: 1 (if required) * 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); queue = kzalloc(rt2x00dev->data_queues * sizeof(*queue), GFP_KERNEL);
if (!queue) { if (!queue) {
...@@ -272,7 +272,7 @@ int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev) ...@@ -272,7 +272,7 @@ int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev)
*/ */
rt2x00dev->rx = queue; rt2x00dev->rx = queue;
rt2x00dev->tx = &queue[1]; rt2x00dev->tx = &queue[1];
rt2x00dev->bcn = &queue[1 + rt2x00dev->hw->queues]; rt2x00dev->bcn = &queue[1 + rt2x00dev->ops->tx_queues];
/* /*
* Initialize queue parameters. * Initialize queue parameters.
......
...@@ -397,7 +397,7 @@ struct data_queue_desc { ...@@ -397,7 +397,7 @@ struct data_queue_desc {
* the end of the TX queue array. * the end of the TX queue array.
*/ */
#define tx_queue_end(__dev) \ #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). * queue_loop - Loop through the queues within a specific range (HELPER MACRO).
......
...@@ -2257,7 +2257,6 @@ static void rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) ...@@ -2257,7 +2257,6 @@ static void rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
IEEE80211_HW_SIGNAL_DBM; IEEE80211_HW_SIGNAL_DBM;
rt2x00dev->hw->extra_tx_headroom = 0; rt2x00dev->hw->extra_tx_headroom = 0;
rt2x00dev->hw->queues = 4;
SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev); SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev);
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
...@@ -2489,6 +2488,7 @@ static const struct rt2x00_ops rt61pci_ops = { ...@@ -2489,6 +2488,7 @@ static const struct rt2x00_ops rt61pci_ops = {
.max_ap_intf = 4, .max_ap_intf = 4,
.eeprom_size = EEPROM_SIZE, .eeprom_size = EEPROM_SIZE,
.rf_size = RF_SIZE, .rf_size = RF_SIZE,
.tx_queues = NUM_TX_QUEUES,
.rx = &rt61pci_queue_rx, .rx = &rt61pci_queue_rx,
.tx = &rt61pci_queue_tx, .tx = &rt61pci_queue_tx,
.bcn = &rt61pci_queue_bcn, .bcn = &rt61pci_queue_bcn,
......
...@@ -53,6 +53,11 @@ ...@@ -53,6 +53,11 @@
#define BBP_SIZE 0x0080 #define BBP_SIZE 0x0080
#define RF_SIZE 0x0014 #define RF_SIZE 0x0014
/*
* Number of TX queues.
*/
#define NUM_TX_QUEUES 4
/* /*
* PCI registers. * PCI registers.
*/ */
......
...@@ -1831,7 +1831,6 @@ static void rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) ...@@ -1831,7 +1831,6 @@ static void rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
IEEE80211_HW_SIGNAL_DBM; IEEE80211_HW_SIGNAL_DBM;
rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE; rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE;
rt2x00dev->hw->queues = 4;
SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev); SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev);
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
...@@ -2079,6 +2078,7 @@ static const struct rt2x00_ops rt73usb_ops = { ...@@ -2079,6 +2078,7 @@ static const struct rt2x00_ops rt73usb_ops = {
.max_ap_intf = 4, .max_ap_intf = 4,
.eeprom_size = EEPROM_SIZE, .eeprom_size = EEPROM_SIZE,
.rf_size = RF_SIZE, .rf_size = RF_SIZE,
.tx_queues = NUM_TX_QUEUES,
.rx = &rt73usb_queue_rx, .rx = &rt73usb_queue_rx,
.tx = &rt73usb_queue_tx, .tx = &rt73usb_queue_tx,
.bcn = &rt73usb_queue_bcn, .bcn = &rt73usb_queue_bcn,
......
...@@ -53,6 +53,11 @@ ...@@ -53,6 +53,11 @@
#define BBP_SIZE 0x0080 #define BBP_SIZE 0x0080
#define RF_SIZE 0x0014 #define RF_SIZE 0x0014
/*
* Number of TX queues.
*/
#define NUM_TX_QUEUES 4
/* /*
* USB registers. * USB registers.
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment