aboutsummaryrefslogtreecommitdiff
path: root/drivers/uwb/i1480/i1480u-wlp/rx.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/uwb/i1480/i1480u-wlp/rx.c')
-rw-r--r--drivers/uwb/i1480/i1480u-wlp/rx.c474
1 files changed, 0 insertions, 474 deletions
diff --git a/drivers/uwb/i1480/i1480u-wlp/rx.c b/drivers/uwb/i1480/i1480u-wlp/rx.c
deleted file mode 100644
index d4e51e108aa..00000000000
--- a/drivers/uwb/i1480/i1480u-wlp/rx.c
+++ /dev/null
@@ -1,474 +0,0 @@
-/*
- * WUSB Wire Adapter: WLP interface
- * Driver for the Linux Network stack.
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- *
- * i1480u's RX handling is simple. i1480u will send the received
- * network packets broken up in fragments; 1 to N fragments make a
- * packet, we assemble them together and deliver the packet with netif_rx().
- *
- * Beacuse each USB transfer is a *single* fragment (except when the
- * transfer contains a first fragment), each URB called thus
- * back contains one or two fragments. So we queue N URBs, each with its own
- * fragment buffer. When a URB is done, we process it (adding to the
- * current skb from the fragment buffer until complete). Once
- * processed, we requeue the URB. There is always a bunch of URBs
- * ready to take data, so the intergap should be minimal.
- *
- * An URB's transfer buffer is the data field of a socket buffer. This
- * reduces copying as data can be passed directly to network layer. If a
- * complete packet or 1st fragment is received the URB's transfer buffer is
- * taken away from it and used to send data to the network layer. In this
- * case a new transfer buffer is allocated to the URB before being requeued.
- * If a "NEXT" or "LAST" fragment is received, the fragment contents is
- * appended to the RX packet under construction and the transfer buffer
- * is reused. To be able to use this buffer to assemble complete packets
- * we set each buffer's size to that of the MAX ethernet packet that can
- * be received. There is thus room for improvement in memory usage.
- *
- * When the max tx fragment size increases, we should be able to read
- * data into the skbs directly with very simple code.
- *
- * ROADMAP:
- *
- * ENTRY POINTS:
- *
- * i1480u_rx_setup(): setup RX context [from i1480u_open()]
- *
- * i1480u_rx_release(): release RX context [from i1480u_stop()]
- *
- * i1480u_rx_cb(): called when the RX USB URB receives a
- * packet. It removes the header and pushes it up
- * the Linux netdev stack with netif_rx().
- *
- * i1480u_rx_buffer()
- * i1480u_drop() and i1480u_fix()
- * i1480u_skb_deliver
- *
- */
-
-#include <linux/gfp.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include "i1480u-wlp.h"
-
-/*
- * Setup the RX context
- *
- * Each URB is provided with a transfer_buffer that is the data field
- * of a new socket buffer.
- */
-int i1480u_rx_setup(struct i1480u *i1480u)
-{
- int result, cnt;
- struct device *dev = &i1480u->usb_iface->dev;
- struct net_device *net_dev = i1480u->net_dev;
- struct usb_endpoint_descriptor *epd;
- struct sk_buff *skb;
-
- /* Alloc RX stuff */
- i1480u->rx_skb = NULL; /* not in process of receiving packet */
- result = -ENOMEM;
- epd = &i1480u->usb_iface->cur_altsetting->endpoint[1].desc;
- for (cnt = 0; cnt < i1480u_RX_BUFS; cnt++) {
- struct i1480u_rx_buf *rx_buf = &i1480u->rx_buf[cnt];
- rx_buf->i1480u = i1480u;
- skb = dev_alloc_skb(i1480u_MAX_RX_PKT_SIZE);
- if (!skb) {
- dev_err(dev,
- "RX: cannot allocate RX buffer %d\n", cnt);
- result = -ENOMEM;
- goto error;
- }
- skb->dev = net_dev;
- skb->ip_summed = CHECKSUM_NONE;
- skb_reserve(skb, 2);
- rx_buf->data = skb;
- rx_buf->urb = usb_alloc_urb(0, GFP_KERNEL);
- if (unlikely(rx_buf->urb == NULL)) {
- dev_err(dev, "RX: cannot allocate URB %d\n", cnt);
- result = -ENOMEM;
- goto error;
- }
- usb_fill_bulk_urb(rx_buf->urb, i1480u->usb_dev,
- usb_rcvbulkpipe(i1480u->usb_dev, epd->bEndpointAddress),
- rx_buf->data->data, i1480u_MAX_RX_PKT_SIZE - 2,
- i1480u_rx_cb, rx_buf);
- result = usb_submit_urb(rx_buf->urb, GFP_NOIO);
- if (unlikely(result < 0)) {
- dev_err(dev, "RX: cannot submit URB %d: %d\n",
- cnt, result);
- goto error;
- }
- }
- return 0;
-
-error:
- i1480u_rx_release(i1480u);
- return result;
-}
-
-
-/* Release resources associated to the rx context */
-void i1480u_rx_release(struct i1480u *i1480u)
-{
- int cnt;
- for (cnt = 0; cnt < i1480u_RX_BUFS; cnt++) {
- if (i1480u->rx_buf[cnt].data)
- dev_kfree_skb(i1480u->rx_buf[cnt].data);
- if (i1480u->rx_buf[cnt].urb) {
- usb_kill_urb(i1480u->rx_buf[cnt].urb);
- usb_free_urb(i1480u->rx_buf[cnt].urb);
- }
- }
- if (i1480u->rx_skb != NULL)
- dev_kfree_skb(i1480u->rx_skb);
-}
-
-static
-void i1480u_rx_unlink_urbs(struct i1480u *i1480u)
-{
- int cnt;
- for (cnt = 0; cnt < i1480u_RX_BUFS; cnt++) {
- if (i1480u->rx_buf[cnt].urb)
- usb_unlink_urb(i1480u->rx_buf[cnt].urb);
- }
-}
-
-/* Fix an out-of-sequence packet */
-#define i1480u_fix(i1480u, msg...) \
-do { \
- if (printk_ratelimit()) \
- dev_err(&i1480u->usb_iface->dev, msg); \
- dev_kfree_skb_irq(i1480u->rx_skb); \
- i1480u->rx_skb = NULL; \
- i1480u->rx_untd_pkt_size = 0; \
-} while (0)
-
-
-/* Drop an out-of-sequence packet */
-#define i1480u_drop(i1480u, msg...) \
-do { \
- if (printk_ratelimit()) \
- dev_err(&i1480u->usb_iface->dev, msg); \
- i1480u->net_dev->stats.rx_dropped++; \
-} while (0)
-
-
-
-
-/* Finalizes setting up the SKB and delivers it
- *
- * We first pass the incoming frame to WLP substack for verification. It
- * may also be a WLP association frame in which case WLP will take over the
- * processing. If WLP does not take it over it will still verify it, if the
- * frame is invalid the skb will be freed by WLP and we will not continue
- * parsing.
- * */
-static
-void i1480u_skb_deliver(struct i1480u *i1480u)
-{
- int should_parse;
- struct net_device *net_dev = i1480u->net_dev;
- struct device *dev = &i1480u->usb_iface->dev;
-
- should_parse = wlp_receive_frame(dev, &i1480u->wlp, i1480u->rx_skb,
- &i1480u->rx_srcaddr);
- if (!should_parse)
- goto out;
- i1480u->rx_skb->protocol = eth_type_trans(i1480u->rx_skb, net_dev);
- net_dev->stats.rx_packets++;
- net_dev->stats.rx_bytes += i1480u->rx_untd_pkt_size;
-
- netif_rx(i1480u->rx_skb); /* deliver */
-out:
- i1480u->rx_skb = NULL;
- i1480u->rx_untd_pkt_size = 0;
-}
-
-
-/*
- * Process a buffer of data received from the USB RX endpoint
- *
- * First fragment arrives with next or last fragment. All other fragments
- * arrive alone.
- *
- * /me hates long functions.
- */
-static
-void i1480u_rx_buffer(struct i1480u_rx_buf *rx_buf)
-{
- unsigned pkt_completed = 0; /* !0 when we got all pkt fragments */
- size_t untd_hdr_size, untd_frg_size;
- size_t i1480u_hdr_size;
- struct wlp_rx_hdr *i1480u_hdr = NULL;
-
- struct i1480u *i1480u = rx_buf->i1480u;
- struct sk_buff *skb = rx_buf->data;
- int size_left = rx_buf->urb->actual_length;
- void *ptr = rx_buf->urb->transfer_buffer; /* also rx_buf->data->data */
- struct untd_hdr *untd_hdr;
-
- struct net_device *net_dev = i1480u->net_dev;
- struct device *dev = &i1480u->usb_iface->dev;
- struct sk_buff *new_skb;
-
-#if 0
- dev_fnstart(dev,
- "(i1480u %p ptr %p size_left %zu)\n", i1480u, ptr, size_left);
- dev_err(dev, "RX packet, %zu bytes\n", size_left);
- dump_bytes(dev, ptr, size_left);
-#endif
- i1480u_hdr_size = sizeof(struct wlp_rx_hdr);
-
- while (size_left > 0) {
- if (pkt_completed) {
- i1480u_drop(i1480u, "RX: fragment follows completed"
- "packet in same buffer. Dropping\n");
- break;
- }
- untd_hdr = ptr;
- if (size_left < sizeof(*untd_hdr)) { /* Check the UNTD header */
- i1480u_drop(i1480u, "RX: short UNTD header! Dropping\n");
- goto out;
- }
- if (unlikely(untd_hdr_rx_tx(untd_hdr) == 0)) { /* Paranoia: TX set? */
- i1480u_drop(i1480u, "RX: TX bit set! Dropping\n");
- goto out;
- }
- switch (untd_hdr_type(untd_hdr)) { /* Check the UNTD header type */
- case i1480u_PKT_FRAG_1ST: {
- struct untd_hdr_1st *untd_hdr_1st = (void *) untd_hdr;
- dev_dbg(dev, "1st fragment\n");
- untd_hdr_size = sizeof(struct untd_hdr_1st);
- if (i1480u->rx_skb != NULL)
- i1480u_fix(i1480u, "RX: 1st fragment out of "
- "sequence! Fixing\n");
- if (size_left < untd_hdr_size + i1480u_hdr_size) {
- i1480u_drop(i1480u, "RX: short 1st fragment! "
- "Dropping\n");
- goto out;
- }
- i1480u->rx_untd_pkt_size = le16_to_cpu(untd_hdr->len)
- - i1480u_hdr_size;
- untd_frg_size = le16_to_cpu(untd_hdr_1st->fragment_len);
- if (size_left < untd_hdr_size + untd_frg_size) {
- i1480u_drop(i1480u,
- "RX: short payload! Dropping\n");
- goto out;
- }
- i1480u->rx_skb = skb;
- i1480u_hdr = (void *) untd_hdr_1st + untd_hdr_size;
- i1480u->rx_srcaddr = i1480u_hdr->srcaddr;
- skb_put(i1480u->rx_skb, untd_hdr_size + untd_frg_size);
- skb_pull(i1480u->rx_skb, untd_hdr_size + i1480u_hdr_size);
- stats_add_sample(&i1480u->lqe_stats, (s8) i1480u_hdr->LQI - 7);
- stats_add_sample(&i1480u->rssi_stats, i1480u_hdr->RSSI + 18);
- rx_buf->data = NULL; /* need to create new buffer */
- break;
- }
- case i1480u_PKT_FRAG_NXT: {
- dev_dbg(dev, "nxt fragment\n");
- untd_hdr_size = sizeof(struct untd_hdr_rst);
- if (i1480u->rx_skb == NULL) {
- i1480u_drop(i1480u, "RX: next fragment out of "
- "sequence! Dropping\n");
- goto out;
- }
- if (size_left < untd_hdr_size) {
- i1480u_drop(i1480u, "RX: short NXT fragment! "
- "Dropping\n");
- goto out;
- }
- untd_frg_size = le16_to_cpu(untd_hdr->len);
- if (size_left < untd_hdr_size + untd_frg_size) {
- i1480u_drop(i1480u,
- "RX: short payload! Dropping\n");
- goto out;
- }
- memmove(skb_put(i1480u->rx_skb, untd_frg_size),
- ptr + untd_hdr_size, untd_frg_size);
- break;
- }
- case i1480u_PKT_FRAG_LST: {
- dev_dbg(dev, "Lst fragment\n");
- untd_hdr_size = sizeof(struct untd_hdr_rst);
- if (i1480u->rx_skb == NULL) {
- i1480u_drop(i1480u, "RX: last fragment out of "
- "sequence! Dropping\n");
- goto out;
- }
- if (size_left < untd_hdr_size) {
- i1480u_drop(i1480u, "RX: short LST fragment! "
- "Dropping\n");
- goto out;
- }
- untd_frg_size = le16_to_cpu(untd_hdr->len);
- if (size_left < untd_frg_size + untd_hdr_size) {
- i1480u_drop(i1480u,
- "RX: short payload! Dropping\n");
- goto out;
- }
- memmove(skb_put(i1480u->rx_skb, untd_frg_size),
- ptr + untd_hdr_size, untd_frg_size);
- pkt_completed = 1;
- break;
- }
- case i1480u_PKT_FRAG_CMP: {
- dev_dbg(dev, "cmp fragment\n");
- untd_hdr_size = sizeof(struct untd_hdr_cmp);
- if (i1480u->rx_skb != NULL)
- i1480u_fix(i1480u, "RX: fix out-of-sequence CMP"
- " fragment!\n");
- if (size_left < untd_hdr_size + i1480u_hdr_size) {
- i1480u_drop(i1480u, "RX: short CMP fragment! "
- "Dropping\n");
- goto out;
- }
- i1480u->rx_untd_pkt_size = le16_to_cpu(untd_hdr->len);
- untd_frg_size = i1480u->rx_untd_pkt_size;
- if (size_left < i1480u->rx_untd_pkt_size + untd_hdr_size) {
- i1480u_drop(i1480u,
- "RX: short payload! Dropping\n");
- goto out;
- }
- i1480u->rx_skb = skb;
- i1480u_hdr = (void *) untd_hdr + untd_hdr_size;
- i1480u->rx_srcaddr = i1480u_hdr->srcaddr;
- stats_add_sample(&i1480u->lqe_stats, (s8) i1480u_hdr->LQI - 7);
- stats_add_sample(&i1480u->rssi_stats, i1480u_hdr->RSSI + 18);
- skb_put(i1480u->rx_skb, untd_hdr_size + i1480u->rx_untd_pkt_size);
- skb_pull(i1480u->rx_skb, untd_hdr_size + i1480u_hdr_size);
- rx_buf->data = NULL; /* for hand off skb to network stack */
- pkt_completed = 1;
- i1480u->rx_untd_pkt_size -= i1480u_hdr_size; /* accurate stat */
- break;
- }
- default:
- i1480u_drop(i1480u, "RX: unknown packet type %u! "
- "Dropping\n", untd_hdr_type(untd_hdr));
- goto out;
- }
- size_left -= untd_hdr_size + untd_frg_size;
- if (size_left > 0)
- ptr += untd_hdr_size + untd_frg_size;
- }
- if (pkt_completed)
- i1480u_skb_deliver(i1480u);
-out:
- /* recreate needed RX buffers*/
- if (rx_buf->data == NULL) {
- /* buffer is being used to receive packet, create new */
- new_skb = dev_alloc_skb(i1480u_MAX_RX_PKT_SIZE);
- if (!new_skb) {
- if (printk_ratelimit())
- dev_err(dev,
- "RX: cannot allocate RX buffer\n");
- } else {
- new_skb->dev = net_dev;
- new_skb->ip_summed = CHECKSUM_NONE;
- skb_reserve(new_skb, 2);
- rx_buf->data = new_skb;
- }
- }
- return;
-}
-
-
-/*
- * Called when an RX URB has finished receiving or has found some kind
- * of error condition.
- *
- * LIMITATIONS:
- *
- * - We read USB-transfers, each transfer contains a SINGLE fragment
- * (can contain a complete packet, or a 1st, next, or last fragment
- * of a packet).
- * Looks like a transfer can contain more than one fragment (07/18/06)
- *
- * - Each transfer buffer is the size of the maximum packet size (minus
- * headroom), i1480u_MAX_PKT_SIZE - 2
- *
- * - We always read the full USB-transfer, no partials.
- *
- * - Each transfer is read directly into a skb. This skb will be used to
- * send data to the upper layers if it is the first fragment or a complete
- * packet. In the other cases the data will be copied from the skb to
- * another skb that is being prepared for the upper layers from a prev
- * first fragment.
- *
- * It is simply too much of a pain. Gosh, there should be a unified
- * SG infrastructure for *everything* [so that I could declare a SG
- * buffer, pass it to USB for receiving, append some space to it if
- * I wish, receive more until I have the whole chunk, adapt
- * pointers on each fragment to remove hardware headers and then
- * attach that to an skbuff and netif_rx()].
- */
-void i1480u_rx_cb(struct urb *urb)
-{
- int result;
- int do_parse_buffer = 1;
- struct i1480u_rx_buf *rx_buf = urb->context;
- struct i1480u *i1480u = rx_buf->i1480u;
- struct device *dev = &i1480u->usb_iface->dev;
- unsigned long flags;
- u8 rx_buf_idx = rx_buf - i1480u->rx_buf;
-
- switch (urb->status) {
- case 0:
- break;
- case -ECONNRESET: /* Not an error, but a controlled situation; */
- case -ENOENT: /* (we killed the URB)...so, no broadcast */
- case -ESHUTDOWN: /* going away! */
- dev_err(dev, "RX URB[%u]: goind down %d\n",
- rx_buf_idx, urb->status);
- goto error;
- default:
- dev_err(dev, "RX URB[%u]: unknown status %d\n",
- rx_buf_idx, urb->status);
- if (edc_inc(&i1480u->rx_errors, EDC_MAX_ERRORS,
- EDC_ERROR_TIMEFRAME)) {
- dev_err(dev, "RX: max acceptable errors exceeded,"
- " resetting device.\n");
- i1480u_rx_unlink_urbs(i1480u);
- wlp_reset_all(&i1480u->wlp);
- goto error;
- }
- do_parse_buffer = 0;
- break;
- }
- spin_lock_irqsave(&i1480u->lock, flags);
- /* chew the data fragments, extract network packets */
- if (do_parse_buffer) {
- i1480u_rx_buffer(rx_buf);
- if (rx_buf->data) {
- rx_buf->urb->transfer_buffer = rx_buf->data->data;
- result = usb_submit_urb(rx_buf->urb, GFP_ATOMIC);
- if (result < 0) {
- dev_err(dev, "RX URB[%u]: cannot submit %d\n",
- rx_buf_idx, result);
- }
- }
- }
- spin_unlock_irqrestore(&i1480u->lock, flags);
-error:
- return;
-}
-