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>
This commit is contained in:
Jakub Kicinski 2015-07-31 15:04:46 +02:00 committed by Kalle Valo
parent 7845af35e0
commit bed429e1ae
3 changed files with 34 additions and 35 deletions

View File

@ -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;

View File

@ -92,8 +92,7 @@ void mt7601u_complete_urb(struct urb *urb)
complete(cmpl);
}
static int
__mt7601u_vendor_request(struct mt7601u_dev *dev, const u8 req,
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)
{
@ -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, &reg, 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,
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;

View File

@ -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,