summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/rt2x00/rt73usb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt73usb.c')
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c181
1 files changed, 116 insertions, 65 deletions
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index 9be8089317e4..02f1148c577e 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -40,7 +40,7 @@
/*
* Allow hardware encryption to be disabled.
*/
-static int modparam_nohwcrypt = 0;
+static int modparam_nohwcrypt;
module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
@@ -502,26 +502,14 @@ static void rt73usb_config_intf(struct rt2x00_dev *rt2x00dev,
struct rt2x00intf_conf *conf,
const unsigned int flags)
{
- unsigned int beacon_base;
u32 reg;
if (flags & CONFIG_UPDATE_TYPE) {
/*
- * Clear current synchronisation setup.
- * For the Beacon base registers we only need to clear
- * the first byte since that byte contains the VALID and OWNER
- * bits which (when set to 0) will invalidate the entire beacon.
- */
- beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx);
- rt2x00usb_register_write(rt2x00dev, beacon_base, 0);
-
- /*
* Enable synchronisation.
*/
rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
- rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
rt2x00_set_field32(&reg, TXRX_CSR9_TSF_SYNC, conf->sync);
- rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
}
@@ -1031,6 +1019,55 @@ dynamic_cca_tune:
}
/*
+ * Queue handlers.
+ */
+static void rt73usb_start_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_RX:
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX, 0);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+ break;
+ case QID_BEACON:
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 1);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+static void rt73usb_stop_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_RX:
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX, 1);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+ break;
+ case QID_BEACON:
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+/*
* Firmware functions
*/
static char *rt73usb_get_firmware_name(struct rt2x00_dev *rt2x00dev)
@@ -1324,18 +1361,6 @@ static int rt73usb_init_bbp(struct rt2x00_dev *rt2x00dev)
/*
* Device state switch handlers.
*/
-static void rt73usb_toggle_rx(struct rt2x00_dev *rt2x00dev,
- enum dev_state state)
-{
- u32 reg;
-
- rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
- rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX,
- (state == STATE_RADIO_RX_OFF) ||
- (state == STATE_RADIO_RX_OFF_LINK));
- rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg);
-}
-
static int rt73usb_enable_radio(struct rt2x00_dev *rt2x00dev)
{
/*
@@ -1402,16 +1427,8 @@ static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev,
case STATE_RADIO_OFF:
rt73usb_disable_radio(rt2x00dev);
break;
- case STATE_RADIO_RX_ON:
- case STATE_RADIO_RX_ON_LINK:
- case STATE_RADIO_RX_OFF:
- case STATE_RADIO_RX_OFF_LINK:
- rt73usb_toggle_rx(rt2x00dev, state);
- break;
case STATE_RADIO_IRQ_ON:
- case STATE_RADIO_IRQ_ON_ISR:
case STATE_RADIO_IRQ_OFF:
- case STATE_RADIO_IRQ_OFF_ISR:
/* No support, but no error either */
break;
case STATE_DEEP_SLEEP:
@@ -1457,7 +1474,7 @@ static void rt73usb_write_tx_desc(struct queue_entry *entry,
test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_OFDM,
(txdesc->rate_mode == RATE_MODE_OFDM));
- rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
+ rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->u.plcp.ifs);
rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_TKIP_MIC,
@@ -1472,20 +1489,22 @@ static void rt73usb_write_tx_desc(struct queue_entry *entry,
rt2x00_desc_write(txd, 0, word);
rt2x00_desc_read(txd, 1, &word);
- rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, txdesc->qid);
- rt2x00_set_field32(&word, TXD_W1_AIFSN, txdesc->aifs);
- rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min);
- rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max);
+ rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, entry->queue->qid);
+ rt2x00_set_field32(&word, TXD_W1_AIFSN, entry->queue->aifs);
+ rt2x00_set_field32(&word, TXD_W1_CWMIN, entry->queue->cw_min);
+ rt2x00_set_field32(&word, TXD_W1_CWMAX, entry->queue->cw_max);
rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, txdesc->iv_offset);
rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE,
test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags));
rt2x00_desc_write(txd, 1, word);
rt2x00_desc_read(txd, 2, &word);
- rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, txdesc->signal);
- rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, txdesc->service);
- rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, txdesc->length_low);
- rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, txdesc->length_high);
+ rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, txdesc->u.plcp.signal);
+ rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, txdesc->u.plcp.service);
+ rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW,
+ txdesc->u.plcp.length_low);
+ rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH,
+ txdesc->u.plcp.length_high);
rt2x00_desc_write(txd, 2, word);
if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags)) {
@@ -1515,13 +1534,15 @@ static void rt73usb_write_beacon(struct queue_entry *entry,
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
unsigned int beacon_base;
- u32 reg;
+ unsigned int padding_len;
+ u32 orig_reg, reg;
/*
* Disable beaconing while we are reloading the beacon data,
* otherwise we might be sending out invalid data.
*/
rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ orig_reg = reg;
rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
@@ -1542,11 +1563,20 @@ static void rt73usb_write_beacon(struct queue_entry *entry,
rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
/*
- * Write entire beacon with descriptor to register.
+ * Write entire beacon with descriptor and padding to register.
*/
+ padding_len = roundup(entry->skb->len, 4) - entry->skb->len;
+ if (padding_len && skb_pad(entry->skb, padding_len)) {
+ ERROR(rt2x00dev, "Failure padding beacon, aborting\n");
+ /* skb freed by skb_pad() on failure */
+ entry->skb = NULL;
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, orig_reg);
+ return;
+ }
+
beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
- rt2x00usb_register_multiwrite(rt2x00dev, beacon_base,
- entry->skb->data, entry->skb->len);
+ rt2x00usb_register_multiwrite(rt2x00dev, beacon_base, entry->skb->data,
+ entry->skb->len + padding_len);
/*
* Enable beaconing again.
@@ -1556,8 +1586,6 @@ static void rt73usb_write_beacon(struct queue_entry *entry,
*/
rt2x00usb_register_write(rt2x00dev, TXRX_CSR10, 0x00001008);
- rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
- rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 1);
rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
@@ -1568,6 +1596,33 @@ static void rt73usb_write_beacon(struct queue_entry *entry,
entry->skb = NULL;
}
+static void rt73usb_clear_beacon(struct queue_entry *entry)
+{
+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+ unsigned int beacon_base;
+ u32 reg;
+
+ /*
+ * Disable beaconing while we are reloading the beacon data,
+ * otherwise we might be sending out invalid data.
+ */
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+
+ /*
+ * Clear beacon.
+ */
+ beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
+ rt2x00usb_register_write(rt2x00dev, beacon_base, 0);
+
+ /*
+ * Enable beaconing again.
+ */
+ rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 1);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+}
+
static int rt73usb_get_tx_data_len(struct queue_entry *entry)
{
int length;
@@ -1582,14 +1637,6 @@ static int rt73usb_get_tx_data_len(struct queue_entry *entry)
return length;
}
-static void rt73usb_kill_tx_queue(struct data_queue *queue)
-{
- if (queue->qid == QID_BEACON)
- rt2x00usb_register_write(queue->rt2x00dev, TXRX_CSR9, 0);
-
- rt2x00usb_kill_tx_queue(queue);
-}
-
/*
* RX control handlers
*/
@@ -1672,9 +1719,8 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry,
rxdesc->flags |= RX_FLAG_IV_STRIPPED;
/*
- * FIXME: Legacy driver indicates that the frame does
- * contain the Michael Mic. Unfortunately, in rt2x00
- * the MIC seems to be missing completely...
+ * The hardware has already checked the Michael Mic and has
+ * stripped it from the frame. Signal this to mac80211.
*/
rxdesc->flags |= RX_FLAG_MMIC_STRIPPED;
@@ -2203,7 +2249,7 @@ static int rt73usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
if (queue_idx >= 4)
return 0;
- queue = rt2x00queue_get_queue(rt2x00dev, queue_idx);
+ queue = rt2x00queue_get_tx_queue(rt2x00dev, queue_idx);
/* Update WMM TXOP register */
offset = AC_TXOP_CSR0 + (sizeof(u32) * (!!(queue_idx & 2)));
@@ -2264,6 +2310,7 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = {
.conf_tx = rt73usb_conf_tx,
.get_tsf = rt73usb_get_tsf,
.rfkill_poll = rt2x00mac_rfkill_poll,
+ .flush = rt2x00mac_flush,
};
static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
@@ -2280,11 +2327,14 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
.reset_tuner = rt73usb_reset_tuner,
.link_tuner = rt73usb_link_tuner,
.watchdog = rt2x00usb_watchdog,
+ .start_queue = rt73usb_start_queue,
+ .kick_queue = rt2x00usb_kick_queue,
+ .stop_queue = rt73usb_stop_queue,
+ .flush_queue = rt2x00usb_flush_queue,
.write_tx_desc = rt73usb_write_tx_desc,
.write_beacon = rt73usb_write_beacon,
+ .clear_beacon = rt73usb_clear_beacon,
.get_tx_data_len = rt73usb_get_tx_data_len,
- .kick_tx_queue = rt2x00usb_kick_tx_queue,
- .kill_tx_queue = rt73usb_kill_tx_queue,
.fill_rxdone = rt73usb_fill_rxdone,
.config_shared_key = rt73usb_config_shared_key,
.config_pairwise_key = rt73usb_config_pairwise_key,
@@ -2296,21 +2346,21 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
};
static const struct data_queue_desc rt73usb_queue_rx = {
- .entry_num = RX_ENTRIES,
+ .entry_num = 32,
.data_size = DATA_FRAME_SIZE,
.desc_size = RXD_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_usb),
};
static const struct data_queue_desc rt73usb_queue_tx = {
- .entry_num = TX_ENTRIES,
+ .entry_num = 32,
.data_size = DATA_FRAME_SIZE,
.desc_size = TXD_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_usb),
};
static const struct data_queue_desc rt73usb_queue_bcn = {
- .entry_num = 4 * BEACON_ENTRIES,
+ .entry_num = 4,
.data_size = MGMT_FRAME_SIZE,
.desc_size = TXINFO_SIZE,
.priv_size = sizeof(struct queue_entry_priv_usb),
@@ -2417,6 +2467,7 @@ static struct usb_device_id rt73usb_device_table[] = {
{ USB_DEVICE(0x04bb, 0x093d), USB_DEVICE_DATA(&rt73usb_ops) },
{ USB_DEVICE(0x148f, 0x2573), USB_DEVICE_DATA(&rt73usb_ops) },
{ USB_DEVICE(0x148f, 0x2671), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x0812, 0x3101), USB_DEVICE_DATA(&rt73usb_ops) },
/* Qcom */
{ USB_DEVICE(0x18e8, 0x6196), USB_DEVICE_DATA(&rt73usb_ops) },
{ USB_DEVICE(0x18e8, 0x6229), USB_DEVICE_DATA(&rt73usb_ops) },