mirror of
https://github.com/vincentmli/bpfire.git
synced 2026-04-27 11:13:24 +02:00
backports: update to 4.2.6
Signed-off-by: Arne Fitzenreiter <arne_f@ipfire.org>
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
441
src/patches/backports-4.2.6-1-mt7601_upstream_fixes.patch
Normal file
441
src/patches/backports-4.2.6-1-mt7601_upstream_fixes.patch
Normal file
@@ -0,0 +1,441 @@
|
||||
From bed429e1ae8b7ee207e01f3aa60dcc0d06a8ed4d Mon Sep 17 00:00:00 2001
|
||||
From: Jakub Kicinski <kubakici@wp.pl>
|
||||
Date: Fri, 31 Jul 2015 15:04:46 +0200
|
||||
Subject: mt7601u: fix dma from stack address
|
||||
|
||||
DMA to variables located on the stack is a bad idea.
|
||||
For simplicity and to avoid frequent allocations create
|
||||
a buffer inside the device structure. Protect this
|
||||
buffer with vendor_req_mutex. Don't protect vendor
|
||||
requests which don't use this buffer.
|
||||
|
||||
Signed-off-by: Jakub Kicinski <kubakici@wp.pl>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
drivers/net/wireless/mediatek/mt7601u/mt7601u.h | 4 +-
|
||||
drivers/net/wireless/mediatek/mt7601u/usb.c | 63 ++++++++++++-------------
|
||||
drivers/net/wireless/mediatek/mt7601u/usb.h | 2 +
|
||||
3 files changed, 34 insertions(+), 35 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h
|
||||
index 9102be6b..6bdfc11 100644
|
||||
--- a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h
|
||||
+++ b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h
|
||||
@@ -146,7 +146,7 @@ enum {
|
||||
* @rx_lock: protects @rx_q.
|
||||
* @con_mon_lock: protects @ap_bssid, @bcn_*, @avg_rssi.
|
||||
* @mutex: ensures exclusive access from mac80211 callbacks.
|
||||
- * @vendor_req_mutex: ensures atomicity of vendor requests.
|
||||
+ * @vendor_req_mutex: protects @vend_buf, ensures atomicity of split writes.
|
||||
* @reg_atomic_mutex: ensures atomicity of indirect register accesses
|
||||
* (accesses to RF and BBP).
|
||||
* @hw_atomic_mutex: ensures exclusive access to HW during critical
|
||||
@@ -184,6 +184,8 @@ struct mt7601u_dev {
|
||||
struct mt7601u_eeprom_params *ee;
|
||||
|
||||
struct mutex vendor_req_mutex;
|
||||
+ void *vend_buf;
|
||||
+
|
||||
struct mutex reg_atomic_mutex;
|
||||
struct mutex hw_atomic_mutex;
|
||||
|
||||
diff --git a/drivers/net/wireless/mediatek/mt7601u/usb.c b/drivers/net/wireless/mediatek/mt7601u/usb.c
|
||||
index 54dba40..416c604 100644
|
||||
--- a/drivers/net/wireless/mediatek/mt7601u/usb.c
|
||||
+++ b/drivers/net/wireless/mediatek/mt7601u/usb.c
|
||||
@@ -92,10 +92,9 @@ void mt7601u_complete_urb(struct urb *urb)
|
||||
complete(cmpl);
|
||||
}
|
||||
|
||||
-static int
|
||||
-__mt7601u_vendor_request(struct mt7601u_dev *dev, const u8 req,
|
||||
- const u8 direction, const u16 val, const u16 offset,
|
||||
- void *buf, const size_t buflen)
|
||||
+int mt7601u_vendor_request(struct mt7601u_dev *dev, const u8 req,
|
||||
+ const u8 direction, const u16 val, const u16 offset,
|
||||
+ void *buf, const size_t buflen)
|
||||
{
|
||||
int i, ret;
|
||||
struct usb_device *usb_dev = mt7601u_to_usb_dev(dev);
|
||||
@@ -110,6 +109,8 @@ __mt7601u_vendor_request(struct mt7601u_dev *dev, const u8 req,
|
||||
trace_mt_vend_req(dev, pipe, req, req_type, val, offset,
|
||||
buf, buflen, ret);
|
||||
|
||||
+ if (ret == -ENODEV)
|
||||
+ set_bit(MT7601U_STATE_REMOVED, &dev->state);
|
||||
if (ret >= 0 || ret == -ENODEV)
|
||||
return ret;
|
||||
|
||||
@@ -122,25 +123,6 @@ __mt7601u_vendor_request(struct mt7601u_dev *dev, const u8 req,
|
||||
return ret;
|
||||
}
|
||||
|
||||
-int
|
||||
-mt7601u_vendor_request(struct mt7601u_dev *dev, const u8 req,
|
||||
- const u8 direction, const u16 val, const u16 offset,
|
||||
- void *buf, const size_t buflen)
|
||||
-{
|
||||
- int ret;
|
||||
-
|
||||
- mutex_lock(&dev->vendor_req_mutex);
|
||||
-
|
||||
- ret = __mt7601u_vendor_request(dev, req, direction, val, offset,
|
||||
- buf, buflen);
|
||||
- if (ret == -ENODEV)
|
||||
- set_bit(MT7601U_STATE_REMOVED, &dev->state);
|
||||
-
|
||||
- mutex_unlock(&dev->vendor_req_mutex);
|
||||
-
|
||||
- return ret;
|
||||
-}
|
||||
-
|
||||
void mt7601u_vendor_reset(struct mt7601u_dev *dev)
|
||||
{
|
||||
mt7601u_vendor_request(dev, MT_VEND_DEV_MODE, USB_DIR_OUT,
|
||||
@@ -150,19 +132,21 @@ void mt7601u_vendor_reset(struct mt7601u_dev *dev)
|
||||
u32 mt7601u_rr(struct mt7601u_dev *dev, u32 offset)
|
||||
{
|
||||
int ret;
|
||||
- __le32 reg;
|
||||
- u32 val;
|
||||
+ u32 val = ~0;
|
||||
|
||||
WARN_ONCE(offset > USHRT_MAX, "read high off:%08x", offset);
|
||||
|
||||
+ mutex_lock(&dev->vendor_req_mutex);
|
||||
+
|
||||
ret = mt7601u_vendor_request(dev, MT_VEND_MULTI_READ, USB_DIR_IN,
|
||||
- 0, offset, ®, sizeof(reg));
|
||||
- val = le32_to_cpu(reg);
|
||||
- if (ret > 0 && ret != sizeof(reg)) {
|
||||
+ 0, offset, dev->vend_buf, MT_VEND_BUF);
|
||||
+ if (ret == MT_VEND_BUF)
|
||||
+ val = get_unaligned_le32(dev->vend_buf);
|
||||
+ else if (ret > 0)
|
||||
dev_err(dev->dev, "Error: wrong size read:%d off:%08x\n",
|
||||
ret, offset);
|
||||
- val = ~0;
|
||||
- }
|
||||
+
|
||||
+ mutex_unlock(&dev->vendor_req_mutex);
|
||||
|
||||
trace_reg_read(dev, offset, val);
|
||||
return val;
|
||||
@@ -173,12 +157,17 @@ int mt7601u_vendor_single_wr(struct mt7601u_dev *dev, const u8 req,
|
||||
{
|
||||
int ret;
|
||||
|
||||
+ mutex_lock(&dev->vendor_req_mutex);
|
||||
+
|
||||
ret = mt7601u_vendor_request(dev, req, USB_DIR_OUT,
|
||||
val & 0xffff, offset, NULL, 0);
|
||||
- if (ret)
|
||||
- return ret;
|
||||
- return mt7601u_vendor_request(dev, req, USB_DIR_OUT,
|
||||
- val >> 16, offset + 2, NULL, 0);
|
||||
+ if (!ret)
|
||||
+ ret = mt7601u_vendor_request(dev, req, USB_DIR_OUT,
|
||||
+ val >> 16, offset + 2, NULL, 0);
|
||||
+
|
||||
+ mutex_unlock(&dev->vendor_req_mutex);
|
||||
+
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
void mt7601u_wr(struct mt7601u_dev *dev, u32 offset, u32 val)
|
||||
@@ -275,6 +264,12 @@ static int mt7601u_probe(struct usb_interface *usb_intf,
|
||||
|
||||
usb_set_intfdata(usb_intf, dev);
|
||||
|
||||
+ dev->vend_buf = devm_kmalloc(dev->dev, MT_VEND_BUF, GFP_KERNEL);
|
||||
+ if (!dev->vend_buf) {
|
||||
+ ret = -ENOMEM;
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
ret = mt7601u_assign_pipes(usb_intf, dev);
|
||||
if (ret)
|
||||
goto err;
|
||||
diff --git a/drivers/net/wireless/mediatek/mt7601u/usb.h b/drivers/net/wireless/mediatek/mt7601u/usb.h
|
||||
index 49e188f..bc18202 100644
|
||||
--- a/drivers/net/wireless/mediatek/mt7601u/usb.h
|
||||
+++ b/drivers/net/wireless/mediatek/mt7601u/usb.h
|
||||
@@ -23,6 +23,8 @@
|
||||
|
||||
#define MT_VEND_DEV_MODE_RESET 1
|
||||
|
||||
+#define MT_VEND_BUF sizeof(__le32)
|
||||
+
|
||||
enum mt_vendor_req {
|
||||
MT_VEND_DEV_MODE = 1,
|
||||
MT_VEND_WRITE = 2,
|
||||
--
|
||||
cgit v0.12
|
||||
|
||||
From d9517c0a5d7468a7ea63086057604fcb0fff480e Mon Sep 17 00:00:00 2001
|
||||
From: Jakub Kicinski <kubakici@wp.pl>
|
||||
Date: Fri, 31 Jul 2015 15:04:47 +0200
|
||||
Subject: mt7601u: use correct ieee80211_rx variant
|
||||
|
||||
Rx is run inside a tasklet so ieee80211_rx() should be used
|
||||
instead of ieee80211_rx_ni().
|
||||
|
||||
Signed-off-by: Jakub Kicinski <kubakici@wp.pl>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
drivers/net/wireless/mediatek/mt7601u/dma.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/net/wireless/mediatek/mt7601u/dma.c b/drivers/net/wireless/mediatek/mt7601u/dma.c
|
||||
index 7217da4..fb183e3 100644
|
||||
--- a/drivers/net/wireless/mediatek/mt7601u/dma.c
|
||||
+++ b/drivers/net/wireless/mediatek/mt7601u/dma.c
|
||||
@@ -112,7 +112,7 @@ static void mt7601u_rx_process_seg(struct mt7601u_dev *dev, u8 *data,
|
||||
if (!skb)
|
||||
return;
|
||||
|
||||
- ieee80211_rx_ni(dev->hw, skb);
|
||||
+ ieee80211_rx(dev->hw, skb);
|
||||
}
|
||||
|
||||
static u16 mt7601u_rx_next_seg_len(u8 *data, u32 data_len)
|
||||
--
|
||||
cgit v0.12
|
||||
|
||||
From 4513493d188d5e3052aee68eda85eaaa1a4e41c2 Mon Sep 17 00:00:00 2001
|
||||
From: Jakub Kicinski <kubakici@wp.pl>
|
||||
Date: Fri, 31 Jul 2015 15:04:48 +0200
|
||||
Subject: mt7601u: fix tx status reporting contexts
|
||||
|
||||
mac80211 requires that rx path does not run concurrently with
|
||||
tx status reporting. Since rx path is run in driver tasklet,
|
||||
tx status cannot be reported directly from interrupt context
|
||||
(there would be no way to lock it out).
|
||||
|
||||
Add tasklet for tx and move all possible code from irq handler
|
||||
there.
|
||||
|
||||
Note: tx tasklet is needed because workqueue is queued very
|
||||
rarely and that kills TCP performance.
|
||||
|
||||
Signed-off-by: Jakub Kicinski <kubakici@wp.pl>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
drivers/net/wireless/mediatek/mt7601u/dma.c | 30 +++++++++++++++++++++----
|
||||
drivers/net/wireless/mediatek/mt7601u/init.c | 1 +
|
||||
drivers/net/wireless/mediatek/mt7601u/mac.c | 4 ++++
|
||||
drivers/net/wireless/mediatek/mt7601u/mt7601u.h | 2 ++
|
||||
4 files changed, 33 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/wireless/mediatek/mt7601u/dma.c b/drivers/net/wireless/mediatek/mt7601u/dma.c
|
||||
index fb183e3..63c4854 100644
|
||||
--- a/drivers/net/wireless/mediatek/mt7601u/dma.c
|
||||
+++ b/drivers/net/wireless/mediatek/mt7601u/dma.c
|
||||
@@ -236,23 +236,42 @@ static void mt7601u_complete_tx(struct urb *urb)
|
||||
skb = q->e[q->start].skb;
|
||||
trace_mt_tx_dma_done(dev, skb);
|
||||
|
||||
- mt7601u_tx_status(dev, skb);
|
||||
+ __skb_queue_tail(&dev->tx_skb_done, skb);
|
||||
+ tasklet_schedule(&dev->tx_tasklet);
|
||||
|
||||
if (q->used == q->entries - q->entries / 8)
|
||||
ieee80211_wake_queue(dev->hw, skb_get_queue_mapping(skb));
|
||||
|
||||
q->start = (q->start + 1) % q->entries;
|
||||
q->used--;
|
||||
+out:
|
||||
+ spin_unlock_irqrestore(&dev->tx_lock, flags);
|
||||
+}
|
||||
|
||||
- if (urb->status)
|
||||
- goto out;
|
||||
+static void mt7601u_tx_tasklet(unsigned long data)
|
||||
+{
|
||||
+ struct mt7601u_dev *dev = (struct mt7601u_dev *) data;
|
||||
+ struct sk_buff_head skbs;
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ __skb_queue_head_init(&skbs);
|
||||
+
|
||||
+ spin_lock_irqsave(&dev->tx_lock, flags);
|
||||
|
||||
set_bit(MT7601U_STATE_MORE_STATS, &dev->state);
|
||||
if (!test_and_set_bit(MT7601U_STATE_READING_STATS, &dev->state))
|
||||
queue_delayed_work(dev->stat_wq, &dev->stat_work,
|
||||
msecs_to_jiffies(10));
|
||||
-out:
|
||||
+
|
||||
+ skb_queue_splice_init(&dev->tx_skb_done, &skbs);
|
||||
+
|
||||
spin_unlock_irqrestore(&dev->tx_lock, flags);
|
||||
+
|
||||
+ while (!skb_queue_empty(&skbs)) {
|
||||
+ struct sk_buff *skb = __skb_dequeue(&skbs);
|
||||
+
|
||||
+ mt7601u_tx_status(dev, skb);
|
||||
+ }
|
||||
}
|
||||
|
||||
static int mt7601u_dma_submit_tx(struct mt7601u_dev *dev,
|
||||
@@ -475,6 +494,7 @@ int mt7601u_dma_init(struct mt7601u_dev *dev)
|
||||
{
|
||||
int ret = -ENOMEM;
|
||||
|
||||
+ tasklet_init(&dev->tx_tasklet, mt7601u_tx_tasklet, (unsigned long) dev);
|
||||
tasklet_init(&dev->rx_tasklet, mt7601u_rx_tasklet, (unsigned long) dev);
|
||||
|
||||
ret = mt7601u_alloc_tx(dev);
|
||||
@@ -502,4 +522,6 @@ void mt7601u_dma_cleanup(struct mt7601u_dev *dev)
|
||||
|
||||
mt7601u_free_rx(dev);
|
||||
mt7601u_free_tx(dev);
|
||||
+
|
||||
+ tasklet_kill(&dev->tx_tasklet);
|
||||
}
|
||||
diff --git a/drivers/net/wireless/mediatek/mt7601u/init.c b/drivers/net/wireless/mediatek/mt7601u/init.c
|
||||
index df3dd56..38eb20b 100644
|
||||
--- a/drivers/net/wireless/mediatek/mt7601u/init.c
|
||||
+++ b/drivers/net/wireless/mediatek/mt7601u/init.c
|
||||
@@ -456,6 +456,7 @@ struct mt7601u_dev *mt7601u_alloc_device(struct device *pdev)
|
||||
spin_lock_init(&dev->lock);
|
||||
spin_lock_init(&dev->con_mon_lock);
|
||||
atomic_set(&dev->avg_ampdu_len, 1);
|
||||
+ skb_queue_head_init(&dev->tx_skb_done);
|
||||
|
||||
dev->stat_wq = alloc_workqueue("mt7601u", WQ_UNBOUND, 0);
|
||||
if (!dev->stat_wq) {
|
||||
diff --git a/drivers/net/wireless/mediatek/mt7601u/mac.c b/drivers/net/wireless/mediatek/mt7601u/mac.c
|
||||
index 7514bce..e3928cf 100644
|
||||
--- a/drivers/net/wireless/mediatek/mt7601u/mac.c
|
||||
+++ b/drivers/net/wireless/mediatek/mt7601u/mac.c
|
||||
@@ -181,7 +181,11 @@ void mt76_send_tx_status(struct mt7601u_dev *dev, struct mt76_tx_status *stat)
|
||||
}
|
||||
|
||||
mt76_mac_fill_tx_status(dev, &info, stat);
|
||||
+
|
||||
+ local_bh_disable();
|
||||
ieee80211_tx_status_noskb(dev->hw, sta, &info);
|
||||
+ local_bh_enable();
|
||||
+
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
diff --git a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h
|
||||
index 6bdfc11..bc5e294 100644
|
||||
--- a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h
|
||||
+++ b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h
|
||||
@@ -199,7 +199,9 @@ struct mt7601u_dev {
|
||||
|
||||
/* TX */
|
||||
spinlock_t tx_lock;
|
||||
+ struct tasklet_struct tx_tasklet;
|
||||
struct mt7601u_tx_queue *tx_q;
|
||||
+ struct sk_buff_head tx_skb_done;
|
||||
|
||||
atomic_t avg_ampdu_len;
|
||||
|
||||
--
|
||||
cgit v0.12
|
||||
|
||||
From 78623bfb6f4cbdba3183621e8e0e781611217022 Mon Sep 17 00:00:00 2001
|
||||
From: Jakub Kicinski <kubakici@wp.pl>
|
||||
Date: Fri, 31 Jul 2015 15:04:49 +0200
|
||||
Subject: mt7601u: lock out rx path and tx status reporting
|
||||
|
||||
mac80211 requires that rx path does not run concurrently with
|
||||
tx status reporting. Add a spinlock which will ensure that.
|
||||
|
||||
Signed-off-by: Jakub Kicinski <kubakici@wp.pl>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
drivers/net/wireless/mediatek/mt7601u/dma.c | 2 ++
|
||||
drivers/net/wireless/mediatek/mt7601u/init.c | 1 +
|
||||
drivers/net/wireless/mediatek/mt7601u/mac.c | 4 ++--
|
||||
drivers/net/wireless/mediatek/mt7601u/mt7601u.h | 4 +++-
|
||||
drivers/net/wireless/mediatek/mt7601u/tx.c | 3 +++
|
||||
5 files changed, 11 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/wireless/mediatek/mt7601u/dma.c b/drivers/net/wireless/mediatek/mt7601u/dma.c
|
||||
index 63c4854..57a80cf 100644
|
||||
--- a/drivers/net/wireless/mediatek/mt7601u/dma.c
|
||||
+++ b/drivers/net/wireless/mediatek/mt7601u/dma.c
|
||||
@@ -112,7 +112,9 @@ static void mt7601u_rx_process_seg(struct mt7601u_dev *dev, u8 *data,
|
||||
if (!skb)
|
||||
return;
|
||||
|
||||
+ spin_lock(&dev->mac_lock);
|
||||
ieee80211_rx(dev->hw, skb);
|
||||
+ spin_unlock(&dev->mac_lock);
|
||||
}
|
||||
|
||||
static u16 mt7601u_rx_next_seg_len(u8 *data, u32 data_len)
|
||||
diff --git a/drivers/net/wireless/mediatek/mt7601u/init.c b/drivers/net/wireless/mediatek/mt7601u/init.c
|
||||
index 38eb20b..26190fd 100644
|
||||
--- a/drivers/net/wireless/mediatek/mt7601u/init.c
|
||||
+++ b/drivers/net/wireless/mediatek/mt7601u/init.c
|
||||
@@ -454,6 +454,7 @@ struct mt7601u_dev *mt7601u_alloc_device(struct device *pdev)
|
||||
spin_lock_init(&dev->tx_lock);
|
||||
spin_lock_init(&dev->rx_lock);
|
||||
spin_lock_init(&dev->lock);
|
||||
+ spin_lock_init(&dev->mac_lock);
|
||||
spin_lock_init(&dev->con_mon_lock);
|
||||
atomic_set(&dev->avg_ampdu_len, 1);
|
||||
skb_queue_head_init(&dev->tx_skb_done);
|
||||
diff --git a/drivers/net/wireless/mediatek/mt7601u/mac.c b/drivers/net/wireless/mediatek/mt7601u/mac.c
|
||||
index e3928cf..e21c53e 100644
|
||||
--- a/drivers/net/wireless/mediatek/mt7601u/mac.c
|
||||
+++ b/drivers/net/wireless/mediatek/mt7601u/mac.c
|
||||
@@ -182,9 +182,9 @@ void mt76_send_tx_status(struct mt7601u_dev *dev, struct mt76_tx_status *stat)
|
||||
|
||||
mt76_mac_fill_tx_status(dev, &info, stat);
|
||||
|
||||
- local_bh_disable();
|
||||
+ spin_lock_bh(&dev->mac_lock);
|
||||
ieee80211_tx_status_noskb(dev->hw, sta, &info);
|
||||
- local_bh_enable();
|
||||
+ spin_unlock_bh(&dev->mac_lock);
|
||||
|
||||
rcu_read_unlock();
|
||||
}
|
||||
diff --git a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h
|
||||
index bc5e294..428bd2f 100644
|
||||
--- a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h
|
||||
+++ b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h
|
||||
@@ -141,8 +141,9 @@ enum {
|
||||
/**
|
||||
* struct mt7601u_dev - adapter structure
|
||||
* @lock: protects @wcid->tx_rate.
|
||||
+ * @mac_lock: locks out mac80211's tx status and rx paths.
|
||||
* @tx_lock: protects @tx_q and changes of MT7601U_STATE_*_STATS
|
||||
- flags in @state.
|
||||
+ * flags in @state.
|
||||
* @rx_lock: protects @rx_q.
|
||||
* @con_mon_lock: protects @ap_bssid, @bcn_*, @avg_rssi.
|
||||
* @mutex: ensures exclusive access from mac80211 callbacks.
|
||||
@@ -177,6 +178,7 @@ struct mt7601u_dev {
|
||||
struct mt76_wcid __rcu *wcid[N_WCIDS];
|
||||
|
||||
spinlock_t lock;
|
||||
+ spinlock_t mac_lock;
|
||||
|
||||
const u16 *beacon_offsets;
|
||||
|
||||
diff --git a/drivers/net/wireless/mediatek/mt7601u/tx.c b/drivers/net/wireless/mediatek/mt7601u/tx.c
|
||||
index 0be2080..a0a33dc 100644
|
||||
--- a/drivers/net/wireless/mediatek/mt7601u/tx.c
|
||||
+++ b/drivers/net/wireless/mediatek/mt7601u/tx.c
|
||||
@@ -116,7 +116,10 @@ void mt7601u_tx_status(struct mt7601u_dev *dev, struct sk_buff *skb)
|
||||
ieee80211_tx_info_clear_status(info);
|
||||
info->status.rates[0].idx = -1;
|
||||
info->flags |= IEEE80211_TX_STAT_ACK;
|
||||
+
|
||||
+ spin_lock(&dev->mac_lock);
|
||||
ieee80211_tx_status(dev->hw, skb);
|
||||
+ spin_unlock(&dev->mac_lock);
|
||||
}
|
||||
|
||||
static int mt7601u_skb_rooms(struct mt7601u_dev *dev, struct sk_buff *skb)
|
||||
--
|
||||
cgit v0.12
|
||||
|
||||
@@ -1,240 +0,0 @@
|
||||
diff --git a/drivers/media/usb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c
|
||||
index 1a3df10..82d35c6 100644
|
||||
--- a/drivers/media/usb/dvb-usb/dw2102.c
|
||||
+++ b/drivers/media/usb/dvb-usb/dw2102.c
|
||||
@@ -31,6 +31,9 @@
|
||||
#include "m88rs2000.h"
|
||||
#include "tda18271.h"
|
||||
#include "cxd2820r.h"
|
||||
+#include "m88ds3103.h"
|
||||
+#include "m88ts2022.h"
|
||||
+
|
||||
|
||||
/* Max transfer size done by I2C transfer functions */
|
||||
#define MAX_XFER_SIZE 64
|
||||
@@ -71,6 +74,14 @@
|
||||
#define USB_PID_TEVII_S480_2 0xd482
|
||||
#endif
|
||||
|
||||
+#ifndef USB_PID_TEVII_S482_1
|
||||
+#define USB_PID_TEVII_S482_1 0xd483
|
||||
+#endif
|
||||
+
|
||||
+#ifndef USB_PID_TEVII_S482_2
|
||||
+#define USB_PID_TEVII_S482_2 0xd484
|
||||
+#endif
|
||||
+
|
||||
#ifndef USB_PID_PROF_1100
|
||||
#define USB_PID_PROF_1100 0xb012
|
||||
#endif
|
||||
@@ -1117,6 +1128,19 @@ static struct tda18271_config tda18271_config = {
|
||||
.gate = TDA18271_GATE_DIGITAL,
|
||||
};
|
||||
|
||||
+static const struct m88ds3103_config s482_m88ds3103_config = {
|
||||
+ .i2c_addr = 0x68,
|
||||
+ .clock = 27000000,
|
||||
+ .i2c_wr_max = 33,
|
||||
+ .clock_out = 0,
|
||||
+ .ts_mode = M88DS3103_TS_CI,
|
||||
+ .ts_clk = 16000,
|
||||
+ .ts_clk_pol = 0,
|
||||
+ .agc = 0x99,
|
||||
+ .lnb_hv_pol = 1,
|
||||
+ .lnb_en_pol = 1,
|
||||
+ };
|
||||
+
|
||||
static u8 m88rs2000_inittab[] = {
|
||||
DEMOD_WRITE, 0x9a, 0x30,
|
||||
DEMOD_WRITE, 0x00, 0x01,
|
||||
@@ -1386,6 +1410,83 @@ static int su3000_frontend_attach(struct dvb_usb_adapter *d)
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
+static int m88ds3103_frontend_attach(struct dvb_usb_adapter *d)
|
||||
+{
|
||||
+ u8 obuf[3] = { 0xe, 0x80, 0 };
|
||||
+ u8 ibuf[] = { 0 };
|
||||
+
|
||||
+ /* demod I2C adapter */
|
||||
+ struct i2c_adapter *i2c_adapter;
|
||||
+ struct i2c_client *client;
|
||||
+ struct i2c_board_info info;
|
||||
+ struct m88ts2022_config m88ts2022_config = {
|
||||
+ .clock = 27000000,
|
||||
+ };
|
||||
+ memset(&info, 0, sizeof(struct i2c_board_info));
|
||||
+ if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
|
||||
+ err("command 0x0e transfer failed.");
|
||||
+
|
||||
+ obuf[0] = 0xe;
|
||||
+ obuf[1] = 0x02;
|
||||
+ obuf[2] = 1;
|
||||
+
|
||||
+ if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
|
||||
+ err("command 0x0e transfer failed.");
|
||||
+ msleep(300);
|
||||
+
|
||||
+ obuf[0] = 0xe;
|
||||
+ obuf[1] = 0x83;
|
||||
+ obuf[2] = 0;
|
||||
+
|
||||
+ if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
|
||||
+ err("command 0x0e transfer failed.");
|
||||
+
|
||||
+ obuf[0] = 0xe;
|
||||
+ obuf[1] = 0x83;
|
||||
+ obuf[2] = 1;
|
||||
+
|
||||
+ if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
|
||||
+ err("command 0x0e transfer failed.");
|
||||
+
|
||||
+ obuf[0] = 0x51;
|
||||
+
|
||||
+ if (dvb_usb_generic_rw(d->dev, obuf, 1, ibuf, 1, 0) < 0)
|
||||
+ err("command 0x51 transfer failed.");
|
||||
+ d->fe_adap[0].fe = dvb_attach(m88ds3103_attach,
|
||||
+ &s482_m88ds3103_config,
|
||||
+ &d->dev->i2c_adap,
|
||||
+ &i2c_adapter);
|
||||
+ if (d->fe_adap[0].fe == NULL)
|
||||
+ return -EIO;
|
||||
+ /* attach tuner */
|
||||
+ m88ts2022_config.fe = d->fe_adap[0].fe;
|
||||
+ strlcpy(info.type, "m88ts2022", I2C_NAME_SIZE);
|
||||
+ info.addr = 0x60;
|
||||
+ info.platform_data = &m88ts2022_config;
|
||||
+ request_module("m88ts2022");
|
||||
+ client = i2c_new_device(i2c_adapter, &info);
|
||||
+ if (client == NULL || client->dev.driver == NULL) {
|
||||
+ dvb_frontend_detach(d->fe_adap[0].fe);
|
||||
+ goto fail_attach;
|
||||
+ }
|
||||
+ if (!try_module_get(client->dev.driver->owner)) {
|
||||
+ i2c_unregister_device(client);
|
||||
+ dvb_frontend_detach(d->fe_adap[0].fe);
|
||||
+ goto fail_attach;
|
||||
+ }
|
||||
+ info("attached m88ds3103/m88ts2022!\n");
|
||||
+
|
||||
+ /* delegate signal strength measurement to tuner */
|
||||
+
|
||||
+ d->fe_adap[0].fe->ops.read_signal_strength =
|
||||
+ d->fe_adap[0].fe->ops.tuner_ops.get_rf_strength;
|
||||
+
|
||||
+ return 0;
|
||||
+fail_attach:
|
||||
+ info("Failed to attach m88ds3103/m88ts2022!\n");
|
||||
+ return -EIO;
|
||||
+}
|
||||
+
|
||||
static int t220_frontend_attach(struct dvb_usb_adapter *d)
|
||||
{
|
||||
u8 obuf[3] = { 0xe, 0x87, 0 };
|
||||
@@ -1557,6 +1658,8 @@ enum dw2102_table_entry {
|
||||
TEVII_S480_2,
|
||||
X3M_SPC1400HD,
|
||||
TEVII_S421,
|
||||
+ TEVII_S482_1,
|
||||
+ TEVII_S482_2,
|
||||
TEVII_S632,
|
||||
TERRATEC_CINERGY_S2_R2,
|
||||
GOTVIEW_SAT_HD,
|
||||
@@ -1580,7 +1683,9 @@ static struct usb_device_id dw2102_table[] = {
|
||||
[TEVII_S480_2] = {USB_DEVICE(0x9022, USB_PID_TEVII_S480_2)},
|
||||
[X3M_SPC1400HD] = {USB_DEVICE(0x1f4d, 0x3100)},
|
||||
[TEVII_S421] = {USB_DEVICE(0x9022, USB_PID_TEVII_S421)},
|
||||
- [TEVII_S632] = {USB_DEVICE(0x9022, USB_PID_TEVII_S632)},
|
||||
+ [TEVII_S482_1] = { USB_DEVICE(0x9022, USB_PID_TEVII_S482_1) },
|
||||
+ [TEVII_S482_2] = { USB_DEVICE(0x9022, USB_PID_TEVII_S482_2) },
|
||||
+ [TEVII_S632] = { USB_DEVICE(0x9022, USB_PID_TEVII_S632) },
|
||||
[TERRATEC_CINERGY_S2_R2] = {USB_DEVICE(USB_VID_TERRATEC, 0x00b0)},
|
||||
[GOTVIEW_SAT_HD] = {USB_DEVICE(0x1FE1, USB_PID_GOTVIEW_SAT_HD)},
|
||||
[GENIATECH_T220] = {USB_DEVICE(0x1f4d, 0xD220)},
|
||||
@@ -2012,6 +2117,59 @@ static struct dvb_usb_device_properties su3000_properties = {
|
||||
}
|
||||
};
|
||||
|
||||
+static struct dvb_usb_device_properties m88ds3103_properties = {
|
||||
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
+ .usb_ctrl = DEVICE_SPECIFIC,
|
||||
+ .size_of_priv = sizeof(struct su3000_state),
|
||||
+ .power_ctrl = su3000_power_ctrl,
|
||||
+ .num_adapters = 1,
|
||||
+ .identify_state = su3000_identify_state,
|
||||
+ .i2c_algo = &su3000_i2c_algo,
|
||||
+
|
||||
+ .rc.core = {
|
||||
+ .rc_interval = 150,
|
||||
+ .rc_codes = RC_MAP_TEVII_NEC,
|
||||
+ .module_name = "dw2102",
|
||||
+ .allowed_protos = RC_BIT_NEC,
|
||||
+ .rc_query = dw2102_rc_query,
|
||||
+ },
|
||||
+
|
||||
+ .read_mac_address = su3000_read_mac_address,
|
||||
+
|
||||
+ .generic_bulk_ctrl_endpoint = 0x01,
|
||||
+
|
||||
+ .adapter = {
|
||||
+ {
|
||||
+ .num_frontends = 1,
|
||||
+ .fe = { {
|
||||
+ .streaming_ctrl = su3000_streaming_ctrl,
|
||||
+ .frontend_attach = m88ds3103_frontend_attach,
|
||||
+ .stream = {
|
||||
+ .type = USB_BULK,
|
||||
+ .count = 8,
|
||||
+ .endpoint = 0x82,
|
||||
+ .u = {
|
||||
+ .bulk = {
|
||||
+ .buffersize = 4096,
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ } },
|
||||
+ }
|
||||
+ },
|
||||
+ .num_device_descs = 2,
|
||||
+ .devices = {
|
||||
+ { "TeVii S482.1 USB",
|
||||
+ { &dw2102_table[TEVII_S482_1], NULL },
|
||||
+ { NULL },
|
||||
+ },
|
||||
+ { "TeVii S482.2 USB",
|
||||
+ { &dw2102_table[TEVII_S482_2], NULL },
|
||||
+ { NULL },
|
||||
+ },
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
static struct dvb_usb_device_properties t220_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
.usb_ctrl = DEVICE_SPECIFIC,
|
||||
@@ -2131,11 +2289,13 @@ static int dw2102_probe(struct usb_interface *intf,
|
||||
0 == dvb_usb_device_init(intf, p7500,
|
||||
THIS_MODULE, NULL, adapter_nr) ||
|
||||
0 == dvb_usb_device_init(intf, s421,
|
||||
- THIS_MODULE, NULL, adapter_nr) ||
|
||||
- 0 == dvb_usb_device_init(intf, &su3000_properties,
|
||||
- THIS_MODULE, NULL, adapter_nr) ||
|
||||
+ THIS_MODULE, NULL, adapter_nr) ||
|
||||
0 == dvb_usb_device_init(intf, &t220_properties,
|
||||
- THIS_MODULE, NULL, adapter_nr))
|
||||
+ THIS_MODULE, NULL, adapter_nr) ||
|
||||
+ 0 == dvb_usb_device_init(intf, &m88ds3103_properties,
|
||||
+ THIS_MODULE, NULL, adapter_nr) ||
|
||||
+ 0 == dvb_usb_device_init(intf, &su3000_properties,
|
||||
+ THIS_MODULE, NULL, adapter_nr))
|
||||
return 0;
|
||||
|
||||
return -ENODEV;
|
||||
@@ -2153,7 +2313,7 @@ module_usb_driver(dw2102_driver);
|
||||
MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by");
|
||||
MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104,"
|
||||
" DVB-C 3101 USB2.0,"
|
||||
- " TeVii S600, S630, S650, S660, S480, S421, S632"
|
||||
+ " TeVii S600, S630, S650, S660, S480, S482, S421, S632"
|
||||
" Prof 1100, 7500 USB2.0,"
|
||||
" Geniatech SU3000, T220 devices");
|
||||
MODULE_VERSION("0.1");
|
||||
Reference in New Issue
Block a user