summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/mediatek/mt7601u
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2015-06-23 11:03:18 +0300
committerDavid S. Miller <davem@davemloft.net>2015-06-23 11:03:18 +0300
commitfa433354f042105fc7a299253f904bb48dae0950 (patch)
tree7dc747d4f994713699a37080b0774f8315a1e1ef /drivers/net/wireless/mediatek/mt7601u
parent10ea5165e44ec8467e393a84ecfbf5732605d504 (diff)
parent40b503c76481aecf811a29a14a80c13b429b5e14 (diff)
downloadlinux-fa433354f042105fc7a299253f904bb48dae0950.tar.xz
Merge tag 'wireless-drivers-next-for-davem-2015-06-18' of git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers-next
Kalle Valo says: ==================== Major changes: mwifiex: * enhancements for AP mode: support verbose information in station dump command and also information about AP link. * enable power save by default brcmfmac: * fix module reload issue for PCIe * improving msgbuf protocol for PCIe devices * rework .get_station() cfg80211 callback operation * determine interface combinations upon device feature support ath9k: * ath9k_htc: add support of channel switch wil6210: * add modparam for bcast ring size * support hidden SSID * add per-MCS Rx stats ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/wireless/mediatek/mt7601u')
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/dma.c74
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/eeprom.c4
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/init.c3
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/mac.c8
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/main.c1
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/usb.c9
6 files changed, 45 insertions, 54 deletions
diff --git a/drivers/net/wireless/mediatek/mt7601u/dma.c b/drivers/net/wireless/mediatek/mt7601u/dma.c
index 9c9e1288644b..7217da4f1543 100644
--- a/drivers/net/wireless/mediatek/mt7601u/dma.c
+++ b/drivers/net/wireless/mediatek/mt7601u/dma.c
@@ -34,56 +34,32 @@ static unsigned int ieee80211_get_hdrlen_from_buf(const u8 *data, unsigned len)
static struct sk_buff *
mt7601u_rx_skb_from_seg(struct mt7601u_dev *dev, struct mt7601u_rxwi *rxwi,
- u8 *data, u32 seg_len)
+ void *data, u32 seg_len, u32 truesize, struct page *p)
{
struct sk_buff *skb;
- u32 true_len;
+ u32 true_len, hdr_len = 0, copy, frag;
- if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_L2PAD))
- seg_len -= 2;
-
- skb = alloc_skb(seg_len, GFP_ATOMIC);
- if (!skb)
- return NULL;
-
- if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_L2PAD)) {
- int hdr_len = ieee80211_get_hdrlen_from_buf(data, seg_len);
-
- memcpy(skb_put(skb, hdr_len), data, hdr_len);
- data += hdr_len + 2;
- seg_len -= hdr_len;
- }
-
- memcpy(skb_put(skb, seg_len), data, seg_len);
-
- true_len = mt76_mac_process_rx(dev, skb, skb->data, rxwi);
- skb_trim(skb, true_len);
-
- return skb;
-}
-
-static struct sk_buff *
-mt7601u_rx_skb_from_seg_paged(struct mt7601u_dev *dev,
- struct mt7601u_rxwi *rxwi, void *data,
- u32 seg_len, u32 truesize, struct page *p)
-{
- unsigned int hdr_len = ieee80211_get_hdrlen_from_buf(data, seg_len);
- unsigned int true_len, copy, frag;
- struct sk_buff *skb;
-
- skb = alloc_skb(128, GFP_ATOMIC);
+ skb = alloc_skb(p ? 128 : seg_len, GFP_ATOMIC);
if (!skb)
return NULL;
true_len = mt76_mac_process_rx(dev, skb, data, rxwi);
+ if (!true_len || true_len > seg_len)
+ goto bad_frame;
+
+ hdr_len = ieee80211_get_hdrlen_from_buf(data, true_len);
+ if (!hdr_len)
+ goto bad_frame;
if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_L2PAD)) {
memcpy(skb_put(skb, hdr_len), data, hdr_len);
+
data += hdr_len + 2;
true_len -= hdr_len;
hdr_len = 0;
}
+ /* If not doing paged RX allocated skb will always have enough space */
copy = (true_len <= skb_tailroom(skb)) ? true_len : hdr_len + 8;
frag = true_len - copy;
@@ -97,10 +73,16 @@ mt7601u_rx_skb_from_seg_paged(struct mt7601u_dev *dev,
}
return skb;
+
+bad_frame:
+ dev_err_ratelimited(dev->dev, "Error: incorrect frame len:%u hdr:%u\n",
+ true_len, hdr_len);
+ dev_kfree_skb(skb);
+ return NULL;
}
static void mt7601u_rx_process_seg(struct mt7601u_dev *dev, u8 *data,
- u32 seg_len, struct page *p, bool paged)
+ u32 seg_len, struct page *p)
{
struct sk_buff *skb;
struct mt7601u_rxwi *rxwi;
@@ -126,11 +108,7 @@ static void mt7601u_rx_process_seg(struct mt7601u_dev *dev, u8 *data,
trace_mt_rx(dev, rxwi, fce_info);
- if (paged)
- skb = mt7601u_rx_skb_from_seg_paged(dev, rxwi, data, seg_len,
- truesize, p);
- else
- skb = mt7601u_rx_skb_from_seg(dev, rxwi, data, seg_len);
+ skb = mt7601u_rx_skb_from_seg(dev, rxwi, data, seg_len, truesize, p);
if (!skb)
return;
@@ -158,23 +136,17 @@ mt7601u_rx_process_entry(struct mt7601u_dev *dev, struct mt7601u_dma_buf_rx *e)
u32 seg_len, data_len = e->urb->actual_length;
u8 *data = page_address(e->p);
struct page *new_p = NULL;
- bool paged = true;
int cnt = 0;
if (!test_bit(MT7601U_STATE_INITIALIZED, &dev->state))
return;
/* Copy if there is very little data in the buffer. */
- if (data_len < 512) {
- paged = false;
- } else {
+ if (data_len > 512)
new_p = dev_alloc_pages(MT_RX_ORDER);
- if (!new_p)
- paged = false;
- }
while ((seg_len = mt7601u_rx_next_seg_len(data, data_len))) {
- mt7601u_rx_process_seg(dev, data, seg_len, e->p, paged);
+ mt7601u_rx_process_seg(dev, data, seg_len, new_p ? e->p : NULL);
data_len -= seg_len;
data += seg_len;
@@ -182,9 +154,9 @@ mt7601u_rx_process_entry(struct mt7601u_dev *dev, struct mt7601u_dma_buf_rx *e)
}
if (cnt > 1)
- trace_mt_rx_dma_aggr(dev, cnt, paged);
+ trace_mt_rx_dma_aggr(dev, cnt, !!new_p);
- if (paged) {
+ if (new_p) {
/* we have one extra ref from the allocator */
__free_pages(e->p, MT_RX_ORDER);
diff --git a/drivers/net/wireless/mediatek/mt7601u/eeprom.c b/drivers/net/wireless/mediatek/mt7601u/eeprom.c
index ce3837f270f0..8d8ee0344f7b 100644
--- a/drivers/net/wireless/mediatek/mt7601u/eeprom.c
+++ b/drivers/net/wireless/mediatek/mt7601u/eeprom.c
@@ -277,6 +277,10 @@ mt7601u_extra_power_over_mac(struct mt7601u_dev *dev)
static void
mt7601u_set_power_rate(struct power_per_rate *rate, s8 delta, u8 value)
{
+ /* Invalid? Note: vendor driver does not handle this */
+ if (value == 0xff)
+ return;
+
rate->raw = s6_validate(value);
rate->bw20 = s6_to_int(value);
/* Note: vendor driver does cap the value to s6 right away */
diff --git a/drivers/net/wireless/mediatek/mt7601u/init.c b/drivers/net/wireless/mediatek/mt7601u/init.c
index ca1ea2e55ff4..df3dd56199a7 100644
--- a/drivers/net/wireless/mediatek/mt7601u/init.c
+++ b/drivers/net/wireless/mediatek/mt7601u/init.c
@@ -427,6 +427,9 @@ err:
void mt7601u_cleanup(struct mt7601u_dev *dev)
{
+ if (!test_and_clear_bit(MT7601U_STATE_INITIALIZED, &dev->state))
+ return;
+
mt7601u_stop_hardware(dev);
mt7601u_dma_cleanup(dev);
mt7601u_mcu_cmd_deinit(dev);
diff --git a/drivers/net/wireless/mediatek/mt7601u/mac.c b/drivers/net/wireless/mediatek/mt7601u/mac.c
index c161bcc6a7fa..7514bce1ac91 100644
--- a/drivers/net/wireless/mediatek/mt7601u/mac.c
+++ b/drivers/net/wireless/mediatek/mt7601u/mac.c
@@ -450,10 +450,14 @@ u32 mt76_mac_process_rx(struct mt7601u_dev *dev, struct sk_buff *skb,
{
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
struct mt7601u_rxwi *rxwi = rxi;
- u32 ctl = le32_to_cpu(rxwi->ctl);
+ u32 len, ctl = le32_to_cpu(rxwi->ctl);
u16 rate = le16_to_cpu(rxwi->rate);
int rssi;
+ len = MT76_GET(MT_RXWI_CTL_MPDU_LEN, ctl);
+ if (len < 10)
+ return 0;
+
if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_DECRYPT)) {
status->flag |= RX_FLAG_DECRYPTED;
status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED;
@@ -474,7 +478,7 @@ u32 mt76_mac_process_rx(struct mt7601u_dev *dev, struct sk_buff *skb,
dev->avg_rssi = (dev->avg_rssi * 15) / 16 + (rssi << 8);
spin_unlock_bh(&dev->con_mon_lock);
- return MT76_GET(MT_RXWI_CTL_MPDU_LEN, ctl);
+ return len;
}
static enum mt76_cipher_type
diff --git a/drivers/net/wireless/mediatek/mt7601u/main.c b/drivers/net/wireless/mediatek/mt7601u/main.c
index ced82abb414f..169384b48b27 100644
--- a/drivers/net/wireless/mediatek/mt7601u/main.c
+++ b/drivers/net/wireless/mediatek/mt7601u/main.c
@@ -119,6 +119,7 @@ mt76_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
dev->rxfilter &= ~MT_RX_FILTR_CFG_OTHER_BSS;
+ MT76_FILTER(OTHER_BSS, MT_RX_FILTR_CFG_PROMISC);
MT76_FILTER(FCSFAIL, MT_RX_FILTR_CFG_CRC_ERR);
MT76_FILTER(PLCPFAIL, MT_RX_FILTR_CFG_PHY_ERR);
MT76_FILTER(CONTROL, MT_RX_FILTR_CFG_ACK |
diff --git a/drivers/net/wireless/mediatek/mt7601u/usb.c b/drivers/net/wireless/mediatek/mt7601u/usb.c
index 99e2b3997bfa..54dba4001865 100644
--- a/drivers/net/wireless/mediatek/mt7601u/usb.c
+++ b/drivers/net/wireless/mediatek/mt7601u/usb.c
@@ -338,8 +338,15 @@ static int mt7601u_suspend(struct usb_interface *usb_intf, pm_message_t state)
static int mt7601u_resume(struct usb_interface *usb_intf)
{
struct mt7601u_dev *dev = usb_get_intfdata(usb_intf);
+ int ret;
+
+ ret = mt7601u_init_hardware(dev);
+ if (ret)
+ return ret;
+
+ set_bit(MT7601U_STATE_INITIALIZED, &dev->state);
- return mt7601u_init_hardware(dev);
+ return 0;
}
MODULE_DEVICE_TABLE(usb, mt7601u_device_table);