Commit f7522949 authored by Lorenzo Bianconi's avatar Lorenzo Bianconi Committed by Felix Fietkau

mt76: usb: use a linear buffer for tx/rx datapath if sg is not supported

Use linear fragment and not a single usb scatter-gather buffer in mt76u
{tx,rx} datapath if the usb controller has sg data length constraints
Signed-off-by: default avatarLorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: default avatarFelix Fietkau <nbd@nbd.name>
parent d704d16f
...@@ -432,10 +432,11 @@ static int mt76u_get_rx_entry_len(u8 *data, u32 data_len) ...@@ -432,10 +432,11 @@ static int mt76u_get_rx_entry_len(u8 *data, u32 data_len)
} }
static int static int
mt76u_process_rx_entry(struct mt76_dev *dev, struct urb *urb) mt76u_process_rx_entry(struct mt76_dev *dev, struct mt76u_buf *buf)
{ {
struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN]; struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN];
u8 *data = sg_virt(&urb->sg[0]); struct urb *urb = buf->urb;
u8 *data = urb->num_sgs ? sg_virt(&urb->sg[0]) : buf->buf;
int data_len, len, nsgs = 1; int data_len, len, nsgs = 1;
struct sk_buff *skb; struct sk_buff *skb;
...@@ -446,7 +447,8 @@ mt76u_process_rx_entry(struct mt76_dev *dev, struct urb *urb) ...@@ -446,7 +447,8 @@ mt76u_process_rx_entry(struct mt76_dev *dev, struct urb *urb)
if (len < 0) if (len < 0)
return 0; return 0;
data_len = min_t(int, len, urb->sg[0].length - MT_DMA_HDR_LEN); data_len = urb->num_sgs ? urb->sg[0].length : buf->len;
data_len = min_t(int, len, data_len - MT_DMA_HDR_LEN);
if (MT_DMA_HDR_LEN + data_len > SKB_WITH_OVERHEAD(q->buf_size)) if (MT_DMA_HDR_LEN + data_len > SKB_WITH_OVERHEAD(q->buf_size))
return 0; return 0;
...@@ -458,7 +460,7 @@ mt76u_process_rx_entry(struct mt76_dev *dev, struct urb *urb) ...@@ -458,7 +460,7 @@ mt76u_process_rx_entry(struct mt76_dev *dev, struct urb *urb)
__skb_put(skb, data_len); __skb_put(skb, data_len);
len -= data_len; len -= data_len;
while (len > 0) { while (len > 0 && urb->num_sgs) {
data_len = min_t(int, len, urb->sg[nsgs].length); data_len = min_t(int, len, urb->sg[nsgs].length);
skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
sg_page(&urb->sg[nsgs]), sg_page(&urb->sg[nsgs]),
...@@ -503,12 +505,26 @@ static void mt76u_complete_rx(struct urb *urb) ...@@ -503,12 +505,26 @@ static void mt76u_complete_rx(struct urb *urb)
spin_unlock_irqrestore(&q->lock, flags); spin_unlock_irqrestore(&q->lock, flags);
} }
static int
mt76u_refill_rx(struct mt76_dev *dev, struct mt76_queue *q,
struct mt76u_buf *buf, int nsgs)
{
if (dev->usb.sg_en) {
return mt76u_fill_rx_sg(dev, buf, nsgs, q->buf_size,
SKB_WITH_OVERHEAD(q->buf_size));
} else {
buf->buf = page_frag_alloc(&q->rx_page, q->buf_size,
GFP_ATOMIC);
return buf->buf ? 0 : -ENOMEM;
}
}
static void mt76u_rx_tasklet(unsigned long data) static void mt76u_rx_tasklet(unsigned long data)
{ {
struct mt76_dev *dev = (struct mt76_dev *)data; struct mt76_dev *dev = (struct mt76_dev *)data;
struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN]; struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN];
int err, nsgs, buf_len = q->buf_size;
struct mt76u_buf *buf; struct mt76u_buf *buf;
int err, count;
rcu_read_lock(); rcu_read_lock();
...@@ -517,11 +533,9 @@ static void mt76u_rx_tasklet(unsigned long data) ...@@ -517,11 +533,9 @@ static void mt76u_rx_tasklet(unsigned long data)
if (!buf) if (!buf)
break; break;
nsgs = mt76u_process_rx_entry(dev, buf->urb); count = mt76u_process_rx_entry(dev, buf);
if (nsgs > 0) { if (count > 0) {
err = mt76u_fill_rx_sg(dev, buf, nsgs, err = mt76u_refill_rx(dev, q, buf, count);
buf_len,
SKB_WITH_OVERHEAD(buf_len));
if (err < 0) if (err < 0)
break; break;
} }
...@@ -559,7 +573,7 @@ EXPORT_SYMBOL_GPL(mt76u_submit_rx_buffers); ...@@ -559,7 +573,7 @@ EXPORT_SYMBOL_GPL(mt76u_submit_rx_buffers);
static int mt76u_alloc_rx(struct mt76_dev *dev) static int mt76u_alloc_rx(struct mt76_dev *dev)
{ {
struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN]; struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN];
int i, err, nsgs; int i, err;
spin_lock_init(&q->rx_page_lock); spin_lock_init(&q->rx_page_lock);
spin_lock_init(&q->lock); spin_lock_init(&q->lock);
...@@ -569,18 +583,17 @@ static int mt76u_alloc_rx(struct mt76_dev *dev) ...@@ -569,18 +583,17 @@ static int mt76u_alloc_rx(struct mt76_dev *dev)
if (!q->entry) if (!q->entry)
return -ENOMEM; return -ENOMEM;
if (dev->usb.sg_en) { q->buf_size = dev->usb.sg_en ? MT_RX_BUF_SIZE : PAGE_SIZE;
q->buf_size = MT_RX_BUF_SIZE;
nsgs = MT_SG_MAX_SIZE;
} else {
q->buf_size = PAGE_SIZE;
nsgs = 1;
}
q->ndesc = MT_NUM_RX_ENTRIES; q->ndesc = MT_NUM_RX_ENTRIES;
for (i = 0; i < q->ndesc; i++) { for (i = 0; i < q->ndesc; i++) {
if (dev->usb.sg_en)
err = mt76u_buf_alloc_sg(dev, &q->entry[i].ubuf, err = mt76u_buf_alloc_sg(dev, &q->entry[i].ubuf,
nsgs, q->buf_size, MT_SG_MAX_SIZE, q->buf_size,
SKB_WITH_OVERHEAD(q->buf_size),
GFP_KERNEL);
else
err = mt76u_buf_alloc(dev, &q->entry[i].ubuf,
q->buf_size,
SKB_WITH_OVERHEAD(q->buf_size), SKB_WITH_OVERHEAD(q->buf_size),
GFP_KERNEL); GFP_KERNEL);
if (err < 0) if (err < 0)
...@@ -730,7 +743,7 @@ mt76u_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q, ...@@ -730,7 +743,7 @@ mt76u_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q,
{ {
struct usb_interface *intf = to_usb_interface(dev->dev); struct usb_interface *intf = to_usb_interface(dev->dev);
struct usb_device *udev = interface_to_usbdev(intf); struct usb_device *udev = interface_to_usbdev(intf);
u8 ep = q2ep(q->hw_idx); u8 *data = NULL, ep = q2ep(q->hw_idx);
struct mt76u_buf *buf; struct mt76u_buf *buf;
u16 idx = q->tail; u16 idx = q->tail;
unsigned int pipe; unsigned int pipe;
...@@ -747,12 +760,16 @@ mt76u_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q, ...@@ -747,12 +760,16 @@ mt76u_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q,
buf = &q->entry[idx].ubuf; buf = &q->entry[idx].ubuf;
buf->done = false; buf->done = false;
if (dev->usb.sg_en) {
err = mt76u_tx_build_sg(skb, buf->urb); err = mt76u_tx_build_sg(skb, buf->urb);
if (err < 0) if (err < 0)
return err; return err;
} else {
data = skb->data;
}
pipe = usb_sndbulkpipe(udev, dev->usb.out_ep[ep]); pipe = usb_sndbulkpipe(udev, dev->usb.out_ep[ep]);
usb_fill_bulk_urb(buf->urb, udev, pipe, NULL, skb->len, usb_fill_bulk_urb(buf->urb, udev, pipe, data, skb->len,
mt76u_complete_tx, buf); mt76u_complete_tx, buf);
q->tail = (q->tail + 1) % q->ndesc; q->tail = (q->tail + 1) % q->ndesc;
...@@ -788,10 +805,8 @@ static int mt76u_alloc_tx(struct mt76_dev *dev) ...@@ -788,10 +805,8 @@ static int mt76u_alloc_tx(struct mt76_dev *dev)
{ {
struct mt76u_buf *buf; struct mt76u_buf *buf;
struct mt76_queue *q; struct mt76_queue *q;
size_t size;
int i, j; int i, j;
size = MT_SG_MAX_SIZE * sizeof(struct scatterlist);
for (i = 0; i < IEEE80211_NUM_ACS; i++) { for (i = 0; i < IEEE80211_NUM_ACS; i++) {
q = &dev->q_tx[i]; q = &dev->q_tx[i];
spin_lock_init(&q->lock); spin_lock_init(&q->lock);
...@@ -813,11 +828,17 @@ static int mt76u_alloc_tx(struct mt76_dev *dev) ...@@ -813,11 +828,17 @@ static int mt76u_alloc_tx(struct mt76_dev *dev)
if (!buf->urb) if (!buf->urb)
return -ENOMEM; return -ENOMEM;
buf->urb->sg = devm_kzalloc(dev->dev, size, GFP_KERNEL); if (dev->usb.sg_en) {
size_t size = MT_SG_MAX_SIZE *
sizeof(struct scatterlist);
buf->urb->sg = devm_kzalloc(dev->dev, size,
GFP_KERNEL);
if (!buf->urb->sg) if (!buf->urb->sg)
return -ENOMEM; return -ENOMEM;
} }
} }
}
return 0; return 0;
} }
......
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