diff options
Diffstat (limited to 'drivers/uwb/i1480/i1480u-wlp')
-rw-r--r-- | drivers/uwb/i1480/i1480u-wlp/Makefile | 8 | ||||
-rw-r--r-- | drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h | 283 | ||||
-rw-r--r-- | drivers/uwb/i1480/i1480u-wlp/lc.c | 424 | ||||
-rw-r--r-- | drivers/uwb/i1480/i1480u-wlp/netdev.c | 331 | ||||
-rw-r--r-- | drivers/uwb/i1480/i1480u-wlp/rx.c | 474 | ||||
-rw-r--r-- | drivers/uwb/i1480/i1480u-wlp/sysfs.c | 407 | ||||
-rw-r--r-- | drivers/uwb/i1480/i1480u-wlp/tx.c | 584 |
7 files changed, 0 insertions, 2511 deletions
diff --git a/drivers/uwb/i1480/i1480u-wlp/Makefile b/drivers/uwb/i1480/i1480u-wlp/Makefile deleted file mode 100644 index fe6709b8e68..00000000000 --- a/drivers/uwb/i1480/i1480u-wlp/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -obj-$(CONFIG_UWB_I1480U_WLP) += i1480u-wlp.o - -i1480u-wlp-objs := \ - lc.o \ - netdev.o \ - rx.o \ - sysfs.o \ - tx.o diff --git a/drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h b/drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h deleted file mode 100644 index 2e31f536a34..00000000000 --- a/drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Intel 1480 Wireless UWB Link USB - * Header formats, constants, general internal interfaces - * - * - * 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. - * - * - * This is not an standard interface. - * - * FIXME: docs - * - * i1480u-wlp is pretty simple: two endpoints, one for tx, one for - * rx. rx is polled. Network packets (ethernet, whatever) are wrapped - * in i1480 TX or RX headers (for sending over the air), and these - * packets are wrapped in UNTD headers (for sending to the WLP UWB - * controller). - * - * UNTD packets (UNTD hdr + i1480 hdr + network packet) packets - * cannot be bigger than i1480u_MAX_FRG_SIZE. When this happens, the - * i1480 packet is broken in chunks/packets: - * - * UNTD-1st.hdr + i1480.hdr + payload - * UNTD-next.hdr + payload - * ... - * UNTD-last.hdr + payload - * - * so that each packet is smaller or equal than i1480u_MAX_FRG_SIZE. - * - * All HW structures and bitmaps are little endian, so we need to play - * ugly tricks when defining bitfields. Hoping for the day GCC - * implements __attribute__((endian(1234))). - * - * FIXME: ROADMAP to the whole implementation - */ - -#ifndef __i1480u_wlp_h__ -#define __i1480u_wlp_h__ - -#include <linux/usb.h> -#include <linux/netdevice.h> -#include <linux/uwb.h> /* struct uwb_rc, struct uwb_notifs_handler */ -#include <linux/wlp.h> -#include "../i1480-wlp.h" - -#undef i1480u_FLOW_CONTROL /* Enable flow control code */ - -/** - * Basic flow control - */ -enum { - i1480u_TX_INFLIGHT_MAX = 1000, - i1480u_TX_INFLIGHT_THRESHOLD = 100, -}; - -/** Maximum size of a transaction that we can tx/rx */ -enum { - /* Maximum packet size computed as follows: max UNTD header (8) + - * i1480 RX header (8) + max Ethernet header and payload (4096) + - * Padding added by skb_reserve (2) to make post Ethernet payload - * start on 16 byte boundary*/ - i1480u_MAX_RX_PKT_SIZE = 4114, - i1480u_MAX_FRG_SIZE = 512, - i1480u_RX_BUFS = 9, -}; - - -/** - * UNTD packet type - * - * We need to fragment any payload whose UNTD packet is going to be - * bigger than i1480u_MAX_FRG_SIZE. - */ -enum i1480u_pkt_type { - i1480u_PKT_FRAG_1ST = 0x1, - i1480u_PKT_FRAG_NXT = 0x0, - i1480u_PKT_FRAG_LST = 0x2, - i1480u_PKT_FRAG_CMP = 0x3 -}; -enum { - i1480u_PKT_NONE = 0x4, -}; - -/** USB Network Transfer Descriptor - common */ -struct untd_hdr { - u8 type; - __le16 len; -} __attribute__((packed)); - -static inline enum i1480u_pkt_type untd_hdr_type(const struct untd_hdr *hdr) -{ - return hdr->type & 0x03; -} - -static inline int untd_hdr_rx_tx(const struct untd_hdr *hdr) -{ - return (hdr->type >> 2) & 0x01; -} - -static inline void untd_hdr_set_type(struct untd_hdr *hdr, enum i1480u_pkt_type type) -{ - hdr->type = (hdr->type & ~0x03) | type; -} - -static inline void untd_hdr_set_rx_tx(struct untd_hdr *hdr, int rx_tx) -{ - hdr->type = (hdr->type & ~0x04) | (rx_tx << 2); -} - - -/** - * USB Network Transfer Descriptor - Complete Packet - * - * This is for a packet that is smaller (header + payload) than - * i1480u_MAX_FRG_SIZE. - * - * @hdr.total_len is the size of the payload; the payload doesn't - * count this header nor the padding, but includes the size of i1480 - * header. - */ -struct untd_hdr_cmp { - struct untd_hdr hdr; - u8 padding; -} __attribute__((packed)); - - -/** - * USB Network Transfer Descriptor - First fragment - * - * @hdr.len is the size of the *whole packet* (excluding UNTD - * headers); @fragment_len is the size of the payload (excluding UNTD - * headers, but including i1480 headers). - */ -struct untd_hdr_1st { - struct untd_hdr hdr; - __le16 fragment_len; - u8 padding[3]; -} __attribute__((packed)); - - -/** - * USB Network Transfer Descriptor - Next / Last [Rest] - * - * @hdr.len is the size of the payload, not including headrs. - */ -struct untd_hdr_rst { - struct untd_hdr hdr; - u8 padding; -} __attribute__((packed)); - - -/** - * Transmission context - * - * Wraps all the stuff needed to track a pending/active tx - * operation. - */ -struct i1480u_tx { - struct list_head list_node; - struct i1480u *i1480u; - struct urb *urb; - - struct sk_buff *skb; - struct wlp_tx_hdr *wlp_tx_hdr; - - void *buf; /* if NULL, no new buf was used */ - size_t buf_size; -}; - -/** - * Basic flow control - * - * We maintain a basic flow control counter. "count" how many TX URBs are - * outstanding. Only allow "max" - * TX URBs to be outstanding. If this value is reached the queue will be - * stopped. The queue will be restarted when there are - * "threshold" URBs outstanding. - * Maintain a counter of how many time the TX queue needed to be restarted - * due to the "max" being exceeded and the "threshold" reached again. The - * timestamp "restart_ts" is to keep track from when the counter was last - * queried (see sysfs handling of file wlp_tx_inflight). - */ -struct i1480u_tx_inflight { - atomic_t count; - unsigned long max; - unsigned long threshold; - unsigned long restart_ts; - atomic_t restart_count; -}; - -/** - * Instance of a i1480u WLP interface - * - * Keeps references to the USB device that wraps it, as well as it's - * interface and associated UWB host controller. As well, it also - * keeps a link to the netdevice for integration into the networking - * stack. - * We maintian separate error history for the tx and rx endpoints because - * the implementation does not rely on locking - having one shared - * structure between endpoints may cause problems. Adding locking to the - * implementation will have higher cost than adding a separate structure. - */ -struct i1480u { - struct usb_device *usb_dev; - struct usb_interface *usb_iface; - struct net_device *net_dev; - - spinlock_t lock; - - /* RX context handling */ - struct sk_buff *rx_skb; - struct uwb_dev_addr rx_srcaddr; - size_t rx_untd_pkt_size; - struct i1480u_rx_buf { - struct i1480u *i1480u; /* back pointer */ - struct urb *urb; - struct sk_buff *data; /* i1480u_MAX_RX_PKT_SIZE each */ - } rx_buf[i1480u_RX_BUFS]; /* N bufs */ - - spinlock_t tx_list_lock; /* TX context */ - struct list_head tx_list; - u8 tx_stream; - - struct stats lqe_stats, rssi_stats; /* radio statistics */ - - /* Options we can set from sysfs */ - struct wlp_options options; - struct uwb_notifs_handler uwb_notifs_handler; - struct edc tx_errors; - struct edc rx_errors; - struct wlp wlp; -#ifdef i1480u_FLOW_CONTROL - struct urb *notif_urb; - struct edc notif_edc; /* error density counter */ - u8 notif_buffer[1]; -#endif - struct i1480u_tx_inflight tx_inflight; -}; - -/* Internal interfaces */ -extern void i1480u_rx_cb(struct urb *urb); -extern int i1480u_rx_setup(struct i1480u *); -extern void i1480u_rx_release(struct i1480u *); -extern void i1480u_tx_release(struct i1480u *); -extern int i1480u_xmit_frame(struct wlp *, struct sk_buff *, - struct uwb_dev_addr *); -extern void i1480u_stop_queue(struct wlp *); -extern void i1480u_start_queue(struct wlp *); -extern int i1480u_sysfs_setup(struct i1480u *); -extern void i1480u_sysfs_release(struct i1480u *); - -/* netdev interface */ -extern int i1480u_open(struct net_device *); -extern int i1480u_stop(struct net_device *); -extern netdev_tx_t i1480u_hard_start_xmit(struct sk_buff *, - struct net_device *); -extern void i1480u_tx_timeout(struct net_device *); -extern int i1480u_set_config(struct net_device *, struct ifmap *); -extern int i1480u_change_mtu(struct net_device *, int); -extern void i1480u_uwb_notifs_cb(void *, struct uwb_dev *, enum uwb_notifs); - -/* bandwidth allocation callback */ -extern void i1480u_bw_alloc_cb(struct uwb_rsv *); - -/* Sys FS */ -extern struct attribute_group i1480u_wlp_attr_group; - -#endif /* #ifndef __i1480u_wlp_h__ */ diff --git a/drivers/uwb/i1480/i1480u-wlp/lc.c b/drivers/uwb/i1480/i1480u-wlp/lc.c deleted file mode 100644 index def778cf221..00000000000 --- a/drivers/uwb/i1480/i1480u-wlp/lc.c +++ /dev/null @@ -1,424 +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. - * - * - * FIXME: docs - * - * This implements a very simple network driver for the WLP USB - * device that is associated to a UWB (Ultra Wide Band) host. - * - * This is seen as an interface of a composite device. Once the UWB - * host has an association to another WLP capable device, the - * networking interface (aka WLP) can start to send packets back and - * forth. - * - * Limitations: - * - * - Hand cranked; can't ifup the interface until there is an association - * - * - BW allocation very simplistic [see i1480u_mas_set() and callees]. - * - * - * ROADMAP: - * - * ENTRY POINTS (driver model): - * - * i1480u_driver_{exit,init}(): initialization of the driver. - * - * i1480u_probe(): called by the driver code when a device - * matching 'i1480u_id_table' is connected. - * - * This allocs a netdev instance, inits with - * i1480u_add(), then registers_netdev(). - * i1480u_init() - * i1480u_add() - * - * i1480u_disconnect(): device has been disconnected/module - * is being removed. - * i1480u_rm() - */ -#include <linux/gfp.h> -#include <linux/if_arp.h> -#include <linux/etherdevice.h> - -#include "i1480u-wlp.h" - - - -static inline -void i1480u_init(struct i1480u *i1480u) -{ - /* nothing so far... doesn't it suck? */ - spin_lock_init(&i1480u->lock); - INIT_LIST_HEAD(&i1480u->tx_list); - spin_lock_init(&i1480u->tx_list_lock); - wlp_options_init(&i1480u->options); - edc_init(&i1480u->tx_errors); - edc_init(&i1480u->rx_errors); -#ifdef i1480u_FLOW_CONTROL - edc_init(&i1480u->notif_edc); -#endif - stats_init(&i1480u->lqe_stats); - stats_init(&i1480u->rssi_stats); - wlp_init(&i1480u->wlp); -} - -/** - * Fill WLP device information structure - * - * The structure will contain a few character arrays, each ending with a - * null terminated string. Each string has to fit (excluding terminating - * character) into a specified range obtained from the WLP substack. - * - * It is still not clear exactly how this device information should be - * obtained. Until we find out we use the USB device descriptor as backup, some - * information elements have intuitive mappings, other not. - */ -static -void i1480u_fill_device_info(struct wlp *wlp, struct wlp_device_info *dev_info) -{ - struct i1480u *i1480u = container_of(wlp, struct i1480u, wlp); - struct usb_device *usb_dev = i1480u->usb_dev; - /* Treat device name and model name the same */ - if (usb_dev->descriptor.iProduct) { - usb_string(usb_dev, usb_dev->descriptor.iProduct, - dev_info->name, sizeof(dev_info->name)); - usb_string(usb_dev, usb_dev->descriptor.iProduct, - dev_info->model_name, sizeof(dev_info->model_name)); - } - if (usb_dev->descriptor.iManufacturer) - usb_string(usb_dev, usb_dev->descriptor.iManufacturer, - dev_info->manufacturer, - sizeof(dev_info->manufacturer)); - scnprintf(dev_info->model_nr, sizeof(dev_info->model_nr), "%04x", - __le16_to_cpu(usb_dev->descriptor.bcdDevice)); - if (usb_dev->descriptor.iSerialNumber) - usb_string(usb_dev, usb_dev->descriptor.iSerialNumber, - dev_info->serial, sizeof(dev_info->serial)); - /* FIXME: where should we obtain category? */ - dev_info->prim_dev_type.category = cpu_to_le16(WLP_DEV_CAT_OTHER); - /* FIXME: Complete OUI and OUIsubdiv attributes */ -} - -#ifdef i1480u_FLOW_CONTROL -/** - * Callback for the notification endpoint - * - * This mostly controls the xon/xoff protocol. In case of hard error, - * we stop the queue. If not, we always retry. - */ -static -void i1480u_notif_cb(struct urb *urb, struct pt_regs *regs) -{ - struct i1480u *i1480u = urb->context; - struct usb_interface *usb_iface = i1480u->usb_iface; - struct device *dev = &usb_iface->dev; - int result; - - switch (urb->status) { - case 0: /* Got valid data, do xon/xoff */ - switch (i1480u->notif_buffer[0]) { - case 'N': - dev_err(dev, "XOFF STOPPING queue at %lu\n", jiffies); - netif_stop_queue(i1480u->net_dev); - break; - case 'A': - dev_err(dev, "XON STARTING queue at %lu\n", jiffies); - netif_start_queue(i1480u->net_dev); - break; - default: - dev_err(dev, "NEP: unknown data 0x%02hhx\n", - i1480u->notif_buffer[0]); - } - break; - case -ECONNRESET: /* Controlled situation ... */ - case -ENOENT: /* we killed the URB... */ - dev_err(dev, "NEP: URB reset/noent %d\n", urb->status); - goto error; - case -ESHUTDOWN: /* going away! */ - dev_err(dev, "NEP: URB down %d\n", urb->status); - goto error; - default: /* Retry unless it gets ugly */ - if (edc_inc(&i1480u->notif_edc, EDC_MAX_ERRORS, - EDC_ERROR_TIMEFRAME)) { - dev_err(dev, "NEP: URB max acceptable errors " - "exceeded; resetting device\n"); - goto error_reset; - } - dev_err(dev, "NEP: URB error %d\n", urb->status); - break; - } - result = usb_submit_urb(urb, GFP_ATOMIC); - if (result < 0) { - dev_err(dev, "NEP: Can't resubmit URB: %d; resetting device\n", - result); - goto error_reset; - } - return; - -error_reset: - wlp_reset_all(&i1480-wlp); -error: - netif_stop_queue(i1480u->net_dev); - return; -} -#endif - -static const struct net_device_ops i1480u_netdev_ops = { - .ndo_open = i1480u_open, - .ndo_stop = i1480u_stop, - .ndo_start_xmit = i1480u_hard_start_xmit, - .ndo_tx_timeout = i1480u_tx_timeout, - .ndo_set_config = i1480u_set_config, - .ndo_change_mtu = i1480u_change_mtu, -}; - -static -int i1480u_add(struct i1480u *i1480u, struct usb_interface *iface) -{ - int result = -ENODEV; - struct wlp *wlp = &i1480u->wlp; - struct usb_device *usb_dev = interface_to_usbdev(iface); - struct net_device *net_dev = i1480u->net_dev; - struct uwb_rc *rc; - struct uwb_dev *uwb_dev; -#ifdef i1480u_FLOW_CONTROL - struct usb_endpoint_descriptor *epd; -#endif - - i1480u->usb_dev = usb_get_dev(usb_dev); - i1480u->usb_iface = iface; - rc = uwb_rc_get_by_grandpa(&i1480u->usb_dev->dev); - if (rc == NULL) { - dev_err(&iface->dev, "Cannot get associated UWB Radio " - "Controller\n"); - goto out; - } - wlp->xmit_frame = i1480u_xmit_frame; - wlp->fill_device_info = i1480u_fill_device_info; - wlp->stop_queue = i1480u_stop_queue; - wlp->start_queue = i1480u_start_queue; - result = wlp_setup(wlp, rc, net_dev); - if (result < 0) { - dev_err(&iface->dev, "Cannot setup WLP\n"); - goto error_wlp_setup; - } - result = 0; - ether_setup(net_dev); /* make it an etherdevice */ - uwb_dev = &rc->uwb_dev; - /* FIXME: hookup address change notifications? */ - - memcpy(net_dev->dev_addr, uwb_dev->mac_addr.data, - sizeof(net_dev->dev_addr)); - - net_dev->hard_header_len = sizeof(struct untd_hdr_cmp) - + sizeof(struct wlp_tx_hdr) - + WLP_DATA_HLEN - + ETH_HLEN; - net_dev->mtu = 3500; - net_dev->tx_queue_len = 20; /* FIXME: maybe use 1000? */ - -/* net_dev->flags &= ~IFF_BROADCAST; FIXME: BUG in firmware */ - /* FIXME: multicast disabled */ - net_dev->flags &= ~IFF_MULTICAST; - net_dev->features &= ~NETIF_F_SG; - net_dev->features &= ~NETIF_F_FRAGLIST; - /* All NETIF_F_*_CSUM disabled */ - net_dev->features |= NETIF_F_HIGHDMA; - net_dev->watchdog_timeo = 5*HZ; /* FIXME: a better default? */ - - net_dev->netdev_ops = &i1480u_netdev_ops; - -#ifdef i1480u_FLOW_CONTROL - /* Notification endpoint setup (submitted when we open the device) */ - i1480u->notif_urb = usb_alloc_urb(0, GFP_KERNEL); - if (i1480u->notif_urb == NULL) { - dev_err(&iface->dev, "Unable to allocate notification URB\n"); - result = -ENOMEM; - goto error_urb_alloc; - } - epd = &iface->cur_altsetting->endpoint[0].desc; - usb_fill_int_urb(i1480u->notif_urb, usb_dev, - usb_rcvintpipe(usb_dev, epd->bEndpointAddress), - i1480u->notif_buffer, sizeof(i1480u->notif_buffer), - i1480u_notif_cb, i1480u, epd->bInterval); - -#endif - - i1480u->tx_inflight.max = i1480u_TX_INFLIGHT_MAX; - i1480u->tx_inflight.threshold = i1480u_TX_INFLIGHT_THRESHOLD; - i1480u->tx_inflight.restart_ts = jiffies; - usb_set_intfdata(iface, i1480u); - return result; - -#ifdef i1480u_FLOW_CONTROL -error_urb_alloc: -#endif - wlp_remove(wlp); -error_wlp_setup: - uwb_rc_put(rc); -out: - usb_put_dev(i1480u->usb_dev); - return result; -} - -static void i1480u_rm(struct i1480u *i1480u) -{ - struct uwb_rc *rc = i1480u->wlp.rc; - usb_set_intfdata(i1480u->usb_iface, NULL); -#ifdef i1480u_FLOW_CONTROL - usb_kill_urb(i1480u->notif_urb); - usb_free_urb(i1480u->notif_urb); -#endif - wlp_remove(&i1480u->wlp); - uwb_rc_put(rc); - usb_put_dev(i1480u->usb_dev); -} - -/** Just setup @net_dev's i1480u private data */ -static void i1480u_netdev_setup(struct net_device *net_dev) -{ - struct i1480u *i1480u = netdev_priv(net_dev); - /* Initialize @i1480u */ - memset(i1480u, 0, sizeof(*i1480u)); - i1480u_init(i1480u); -} - -/** - * Probe a i1480u interface and register it - * - * @iface: USB interface to link to - * @id: USB class/subclass/protocol id - * @returns: 0 if ok, < 0 errno code on error. - * - * Does basic housekeeping stuff and then allocs a netdev with space - * for the i1480u data. Initializes, registers in i1480u, registers in - * netdev, ready to go. - */ -static int i1480u_probe(struct usb_interface *iface, - const struct usb_device_id *id) -{ - int result; - struct net_device *net_dev; - struct device *dev = &iface->dev; - struct i1480u *i1480u; - - /* Allocate instance [calls i1480u_netdev_setup() on it] */ - result = -ENOMEM; - net_dev = alloc_netdev(sizeof(*i1480u), "wlp%d", i1480u_netdev_setup); - if (net_dev == NULL) { - dev_err(dev, "no memory for network device instance\n"); - goto error_alloc_netdev; - } - SET_NETDEV_DEV(net_dev, dev); - i1480u = netdev_priv(net_dev); - i1480u->net_dev = net_dev; - result = i1480u_add(i1480u, iface); /* Now setup all the wlp stuff */ - if (result < 0) { - dev_err(dev, "cannot add i1480u device: %d\n", result); - goto error_i1480u_add; - } - result = register_netdev(net_dev); /* Okey dokey, bring it up */ - if (result < 0) { - dev_err(dev, "cannot register network device: %d\n", result); - goto error_register_netdev; - } - i1480u_sysfs_setup(i1480u); - if (result < 0) - goto error_sysfs_init; - return 0; - -error_sysfs_init: - unregister_netdev(net_dev); -error_register_netdev: - i1480u_rm(i1480u); -error_i1480u_add: - free_netdev(net_dev); -error_alloc_netdev: - return result; -} - - -/** - * Disconect a i1480u from the system. - * - * i1480u_stop() has been called before, so al the rx and tx contexts - * have been taken down already. Make sure the queue is stopped, - * unregister netdev and i1480u, free and kill. - */ -static void i1480u_disconnect(struct usb_interface *iface) -{ - struct i1480u *i1480u; - struct net_device *net_dev; - - i1480u = usb_get_intfdata(iface); - net_dev = i1480u->net_dev; - netif_stop_queue(net_dev); -#ifdef i1480u_FLOW_CONTROL - usb_kill_urb(i1480u->notif_urb); -#endif - i1480u_sysfs_release(i1480u); - unregister_netdev(net_dev); - i1480u_rm(i1480u); - free_netdev(net_dev); -} - -static struct usb_device_id i1480u_id_table[] = { - { - .match_flags = USB_DEVICE_ID_MATCH_DEVICE \ - | USB_DEVICE_ID_MATCH_DEV_INFO \ - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x8086, - .idProduct = 0x0c3b, - .bDeviceClass = 0xef, - .bDeviceSubClass = 0x02, - .bDeviceProtocol = 0x02, - .bInterfaceClass = 0xff, - .bInterfaceSubClass = 0xff, - .bInterfaceProtocol = 0xff, - }, - {}, -}; -MODULE_DEVICE_TABLE(usb, i1480u_id_table); - -static struct usb_driver i1480u_driver = { - .name = KBUILD_MODNAME, - .probe = i1480u_probe, - .disconnect = i1480u_disconnect, - .id_table = i1480u_id_table, -}; - -static int __init i1480u_driver_init(void) -{ - return usb_register(&i1480u_driver); -} -module_init(i1480u_driver_init); - - -static void __exit i1480u_driver_exit(void) -{ - usb_deregister(&i1480u_driver); -} -module_exit(i1480u_driver_exit); - -MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>"); -MODULE_DESCRIPTION("i1480 Wireless UWB Link WLP networking for USB"); -MODULE_LICENSE("GPL"); diff --git a/drivers/uwb/i1480/i1480u-wlp/netdev.c b/drivers/uwb/i1480/i1480u-wlp/netdev.c deleted file mode 100644 index f98f6ce8b9e..00000000000 --- a/drivers/uwb/i1480/i1480u-wlp/netdev.c +++ /dev/null @@ -1,331 +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. - * - * - * FIXME: docs - * - * Implementation of the netdevice linkage (except tx and rx related stuff). - * - * ROADMAP: - * - * ENTRY POINTS (Net device): - * - * i1480u_open(): Called when we ifconfig up the interface; - * associates to a UWB host controller, reserves - * bandwidth (MAS), sets up RX USB URB and starts - * the queue. - * - * i1480u_stop(): Called when we ifconfig down a interface; - * reverses _open(). - * - * i1480u_set_config(): - */ - -#include <linux/slab.h> -#include <linux/if_arp.h> -#include <linux/etherdevice.h> - -#include "i1480u-wlp.h" - -struct i1480u_cmd_set_ip_mas { - struct uwb_rccb rccb; - struct uwb_dev_addr addr; - u8 stream; - u8 owner; - u8 type; /* enum uwb_drp_type */ - u8 baMAS[32]; -} __attribute__((packed)); - - -static -int i1480u_set_ip_mas( - struct uwb_rc *rc, - const struct uwb_dev_addr *dstaddr, - u8 stream, u8 owner, u8 type, unsigned long *mas) -{ - - int result; - struct i1480u_cmd_set_ip_mas *cmd; - struct uwb_rc_evt_confirm reply; - - result = -ENOMEM; - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (cmd == NULL) - goto error_kzalloc; - cmd->rccb.bCommandType = 0xfd; - cmd->rccb.wCommand = cpu_to_le16(0x000e); - cmd->addr = *dstaddr; - cmd->stream = stream; - cmd->owner = owner; - cmd->type = type; - if (mas == NULL) - memset(cmd->baMAS, 0x00, sizeof(cmd->baMAS)); - else - memcpy(cmd->baMAS, mas, sizeof(cmd->baMAS)); - reply.rceb.bEventType = 0xfd; - reply.rceb.wEvent = cpu_to_le16(0x000e); - result = uwb_rc_cmd(rc, "SET-IP-MAS", &cmd->rccb, sizeof(*cmd), - &reply.rceb, sizeof(reply)); - if (result < 0) - goto error_cmd; - if (reply.bResultCode != UWB_RC_RES_FAIL) { - dev_err(&rc->uwb_dev.dev, - "SET-IP-MAS: command execution failed: %d\n", - reply.bResultCode); - result = -EIO; - } -error_cmd: - kfree(cmd); -error_kzalloc: - return result; -} - -/* - * Inform a WLP interface of a MAS reservation - * - * @rc is assumed refcnted. - */ -/* FIXME: detect if remote device is WLP capable? */ -static int i1480u_mas_set_dev(struct uwb_dev *uwb_dev, struct uwb_rc *rc, - u8 stream, u8 owner, u8 type, unsigned long *mas) -{ - int result = 0; - struct device *dev = &rc->uwb_dev.dev; - - result = i1480u_set_ip_mas(rc, &uwb_dev->dev_addr, stream, owner, - type, mas); - if (result < 0) { - char rcaddrbuf[UWB_ADDR_STRSIZE], devaddrbuf[UWB_ADDR_STRSIZE]; - uwb_dev_addr_print(rcaddrbuf, sizeof(rcaddrbuf), - &rc->uwb_dev.dev_addr); - uwb_dev_addr_print(devaddrbuf, sizeof(devaddrbuf), - &uwb_dev->dev_addr); - dev_err(dev, "Set IP MAS (%s to %s) failed: %d\n", - rcaddrbuf, devaddrbuf, result); - } - return result; -} - -/** - * Called by bandwidth allocator when change occurs in reservation. - * - * @rsv: The reservation that is being established, modified, or - * terminated. - * - * When a reservation is established, modified, or terminated the upper layer - * (WLP here) needs set/update the currently available Media Access Slots - * that can be use for IP traffic. - * - * Our action taken during failure depends on how the reservation is being - * changed: - * - if reservation is being established we do nothing if we cannot set the - * new MAS to be used - * - if reservation is being terminated we revert back to PCA whether the - * SET IP MAS command succeeds or not. - */ -void i1480u_bw_alloc_cb(struct uwb_rsv *rsv) -{ - int result = 0; - struct i1480u *i1480u = rsv->pal_priv; - struct device *dev = &i1480u->usb_iface->dev; - struct uwb_dev *target_dev = rsv->target.dev; - struct uwb_rc *rc = i1480u->wlp.rc; - u8 stream = rsv->stream; - int type = rsv->type; - int is_owner = rsv->owner == &rc->uwb_dev; - unsigned long *bmp = rsv->mas.bm; - - dev_err(dev, "WLP callback called - sending set ip mas\n"); - /*user cannot change options while setting configuration*/ - mutex_lock(&i1480u->options.mutex); - switch (rsv->state) { - case UWB_RSV_STATE_T_ACCEPTED: - case UWB_RSV_STATE_O_ESTABLISHED: - result = i1480u_mas_set_dev(target_dev, rc, stream, is_owner, - type, bmp); - if (result < 0) { - dev_err(dev, "MAS reservation failed: %d\n", result); - goto out; - } - if (is_owner) { - wlp_tx_hdr_set_delivery_id_type(&i1480u->options.def_tx_hdr, - WLP_DRP | stream); - wlp_tx_hdr_set_rts_cts(&i1480u->options.def_tx_hdr, 0); - } - break; - case UWB_RSV_STATE_NONE: - /* revert back to PCA */ - result = i1480u_mas_set_dev(target_dev, rc, stream, is_owner, - type, bmp); - if (result < 0) - dev_err(dev, "MAS reservation failed: %d\n", result); - /* Revert to PCA even though SET IP MAS failed. */ - wlp_tx_hdr_set_delivery_id_type(&i1480u->options.def_tx_hdr, - i1480u->options.pca_base_priority); - wlp_tx_hdr_set_rts_cts(&i1480u->options.def_tx_hdr, 1); - break; - default: - dev_err(dev, "unexpected WLP reservation state: %s (%d).\n", - uwb_rsv_state_str(rsv->state), rsv->state); - break; - } -out: - mutex_unlock(&i1480u->options.mutex); - return; -} - -/** - * - * Called on 'ifconfig up' - */ -int i1480u_open(struct net_device *net_dev) -{ - int result; - struct i1480u *i1480u = netdev_priv(net_dev); - struct wlp *wlp = &i1480u->wlp; - struct uwb_rc *rc; - struct device *dev = &i1480u->usb_iface->dev; - - rc = wlp->rc; - result = i1480u_rx_setup(i1480u); /* Alloc RX stuff */ - if (result < 0) - goto error_rx_setup; - - result = uwb_radio_start(&wlp->pal); - if (result < 0) - goto error_radio_start; - - netif_wake_queue(net_dev); -#ifdef i1480u_FLOW_CONTROL - result = usb_submit_urb(i1480u->notif_urb, GFP_KERNEL); - if (result < 0) { - dev_err(dev, "Can't submit notification URB: %d\n", result); - goto error_notif_urb_submit; - } -#endif - /* Interface is up with an address, now we can create WSS */ - result = wlp_wss_setup(net_dev, &wlp->wss); - if (result < 0) { - dev_err(dev, "Can't create WSS: %d. \n", result); - goto error_wss_setup; - } - return 0; -error_wss_setup: -#ifdef i1480u_FLOW_CONTROL - usb_kill_urb(i1480u->notif_urb); -error_notif_urb_submit: -#endif - uwb_radio_stop(&wlp->pal); -error_radio_start: - netif_stop_queue(net_dev); - i1480u_rx_release(i1480u); -error_rx_setup: - return result; -} - - -/** - * Called on 'ifconfig down' - */ -int i1480u_stop(struct net_device *net_dev) -{ - struct i1480u *i1480u = netdev_priv(net_dev); - struct wlp *wlp = &i1480u->wlp; - - BUG_ON(wlp->rc == NULL); - wlp_wss_remove(&wlp->wss); - netif_carrier_off(net_dev); -#ifdef i1480u_FLOW_CONTROL - usb_kill_urb(i1480u->notif_urb); -#endif - netif_stop_queue(net_dev); - uwb_radio_stop(&wlp->pal); - i1480u_rx_release(i1480u); - i1480u_tx_release(i1480u); - return 0; -} - -/** - * - * Change the interface config--we probably don't have to do anything. - */ -int i1480u_set_config(struct net_device *net_dev, struct ifmap *map) -{ - int result; - struct i1480u *i1480u = netdev_priv(net_dev); - BUG_ON(i1480u->wlp.rc == NULL); - result = 0; - return result; -} - -/** - * Change the MTU of the interface - */ -int i1480u_change_mtu(struct net_device *net_dev, int mtu) -{ - static union { - struct wlp_tx_hdr tx; - struct wlp_rx_hdr rx; - } i1480u_all_hdrs; - - if (mtu < ETH_HLEN) /* We encap eth frames */ - return -ERANGE; - if (mtu > 4000 - sizeof(i1480u_all_hdrs)) - return -ERANGE; - net_dev->mtu = mtu; - return 0; -} - -/** - * Stop the network queue - * - * Enable WLP substack to stop network queue. We also set the flow control - * threshold at this time to prevent the flow control from restarting the - * queue. - * - * we are loosing the current threshold value here ... FIXME? - */ -void i1480u_stop_queue(struct wlp *wlp) -{ - struct i1480u *i1480u = container_of(wlp, struct i1480u, wlp); - struct net_device *net_dev = i1480u->net_dev; - i1480u->tx_inflight.threshold = 0; - netif_stop_queue(net_dev); -} - -/** - * Start the network queue - * - * Enable WLP substack to start network queue. Also re-enable the flow - * control to manage the queue again. - * - * We re-enable the flow control by storing the default threshold in the - * flow control threshold. This means that if the user modified the - * threshold before the queue was stopped and restarted that information - * will be lost. FIXME? - */ -void i1480u_start_queue(struct wlp *wlp) -{ - struct i1480u *i1480u = container_of(wlp, struct i1480u, wlp); - struct net_device *net_dev = i1480u->net_dev; - i1480u->tx_inflight.threshold = i1480u_TX_INFLIGHT_THRESHOLD; - netif_start_queue(net_dev); -} 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; -} - diff --git a/drivers/uwb/i1480/i1480u-wlp/sysfs.c b/drivers/uwb/i1480/i1480u-wlp/sysfs.c deleted file mode 100644 index 4ffaf546cc6..00000000000 --- a/drivers/uwb/i1480/i1480u-wlp/sysfs.c +++ /dev/null @@ -1,407 +0,0 @@ -/* - * WUSB Wire Adapter: WLP interface - * Sysfs interfaces - * - * 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. - * - * - * FIXME: docs - */ - -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/device.h> - -#include "i1480u-wlp.h" - - -/** - * - * @dev: Class device from the net_device; assumed refcnted. - * - * Yes, I don't lock--we assume it is refcounted and I am getting a - * single byte value that is kind of atomic to read. - */ -ssize_t uwb_phy_rate_show(const struct wlp_options *options, char *buf) -{ - return sprintf(buf, "%u\n", - wlp_tx_hdr_phy_rate(&options->def_tx_hdr)); -} -EXPORT_SYMBOL_GPL(uwb_phy_rate_show); - - -ssize_t uwb_phy_rate_store(struct wlp_options *options, - const char *buf, size_t size) -{ - ssize_t result; - unsigned rate; - - result = sscanf(buf, "%u\n", &rate); - if (result != 1) { - result = -EINVAL; - goto out; - } - result = -EINVAL; - if (rate >= UWB_PHY_RATE_INVALID) - goto out; - wlp_tx_hdr_set_phy_rate(&options->def_tx_hdr, rate); - result = 0; -out: - return result < 0 ? result : size; -} -EXPORT_SYMBOL_GPL(uwb_phy_rate_store); - - -ssize_t uwb_rts_cts_show(const struct wlp_options *options, char *buf) -{ - return sprintf(buf, "%u\n", - wlp_tx_hdr_rts_cts(&options->def_tx_hdr)); -} -EXPORT_SYMBOL_GPL(uwb_rts_cts_show); - - -ssize_t uwb_rts_cts_store(struct wlp_options *options, - const char *buf, size_t size) -{ - ssize_t result; - unsigned value; - - result = sscanf(buf, "%u\n", &value); - if (result != 1) { - result = -EINVAL; - goto out; - } - result = -EINVAL; - wlp_tx_hdr_set_rts_cts(&options->def_tx_hdr, !!value); - result = 0; -out: - return result < 0 ? result : size; -} -EXPORT_SYMBOL_GPL(uwb_rts_cts_store); - - -ssize_t uwb_ack_policy_show(const struct wlp_options *options, char *buf) -{ - return sprintf(buf, "%u\n", - wlp_tx_hdr_ack_policy(&options->def_tx_hdr)); -} -EXPORT_SYMBOL_GPL(uwb_ack_policy_show); - - -ssize_t uwb_ack_policy_store(struct wlp_options *options, - const char *buf, size_t size) -{ - ssize_t result; - unsigned value; - - result = sscanf(buf, "%u\n", &value); - if (result != 1 || value > UWB_ACK_B_REQ) { - result = -EINVAL; - goto out; - } - wlp_tx_hdr_set_ack_policy(&options->def_tx_hdr, value); - result = 0; -out: - return result < 0 ? result : size; -} -EXPORT_SYMBOL_GPL(uwb_ack_policy_store); - - -/** - * Show the PCA base priority. - * - * We can access without locking, as the value is (for now) orthogonal - * to other values. - */ -ssize_t uwb_pca_base_priority_show(const struct wlp_options *options, - char *buf) -{ - return sprintf(buf, "%u\n", - options->pca_base_priority); -} -EXPORT_SYMBOL_GPL(uwb_pca_base_priority_show); - - -/** - * Set the PCA base priority. - * - * We can access without locking, as the value is (for now) orthogonal - * to other values. - */ -ssize_t uwb_pca_base_priority_store(struct wlp_options *options, - const char *buf, size_t size) -{ - ssize_t result = -EINVAL; - u8 pca_base_priority; - - result = sscanf(buf, "%hhu\n", &pca_base_priority); - if (result != 1) { - result = -EINVAL; - goto out; - } - result = -EINVAL; - if (pca_base_priority >= 8) - goto out; - options->pca_base_priority = pca_base_priority; - /* Update TX header if we are currently using PCA. */ - if (result >= 0 && (wlp_tx_hdr_delivery_id_type(&options->def_tx_hdr) & WLP_DRP) == 0) - wlp_tx_hdr_set_delivery_id_type(&options->def_tx_hdr, options->pca_base_priority); - result = 0; -out: - return result < 0 ? result : size; -} -EXPORT_SYMBOL_GPL(uwb_pca_base_priority_store); - -/** - * Show current inflight values - * - * Will print the current MAX and THRESHOLD values for the basic flow - * control. In addition it will report how many times the TX queue needed - * to be restarted since the last time this query was made. - */ -static ssize_t wlp_tx_inflight_show(struct i1480u_tx_inflight *inflight, - char *buf) -{ - ssize_t result; - unsigned long sec_elapsed = (jiffies - inflight->restart_ts)/HZ; - unsigned long restart_count = atomic_read(&inflight->restart_count); - - result = scnprintf(buf, PAGE_SIZE, "%lu %lu %d %lu %lu %lu\n" - "#read: threshold max inflight_count restarts " - "seconds restarts/sec\n" - "#write: threshold max\n", - inflight->threshold, inflight->max, - atomic_read(&inflight->count), - restart_count, sec_elapsed, - sec_elapsed == 0 ? 0 : restart_count/sec_elapsed); - inflight->restart_ts = jiffies; - atomic_set(&inflight->restart_count, 0); - return result; -} - -static -ssize_t wlp_tx_inflight_store(struct i1480u_tx_inflight *inflight, - const char *buf, size_t size) -{ - unsigned long in_threshold, in_max; - ssize_t result; - result = sscanf(buf, "%lu %lu", &in_threshold, &in_max); - if (result != 2) - return -EINVAL; - if (in_max <= in_threshold) - return -EINVAL; - inflight->max = in_max; - inflight->threshold = in_threshold; - return size; -} -/* - * Glue (or function adaptors) for accesing info on sysfs - * - * [we need this indirection because the PCI driver does almost the - * same] - * - * Linux 2.6.21 changed how 'struct netdevice' does attributes (from - * having a 'struct class_dev' to having a 'struct device'). That is - * quite of a pain. - * - * So we try to abstract that here. i1480u_SHOW() and i1480u_STORE() - * create adaptors for extracting the 'struct i1480u' from a 'struct - * dev' and calling a function for doing a sysfs operation (as we have - * them factorized already). i1480u_ATTR creates the attribute file - * (CLASS_DEVICE_ATTR or DEVICE_ATTR) and i1480u_ATTR_NAME produces a - * class_device_attr_NAME or device_attr_NAME (for group registration). - */ - -#define i1480u_SHOW(name, fn, param) \ -static ssize_t i1480u_show_##name(struct device *dev, \ - struct device_attribute *attr,\ - char *buf) \ -{ \ - struct i1480u *i1480u = netdev_priv(to_net_dev(dev)); \ - return fn(&i1480u->param, buf); \ -} - -#define i1480u_STORE(name, fn, param) \ -static ssize_t i1480u_store_##name(struct device *dev, \ - struct device_attribute *attr,\ - const char *buf, size_t size)\ -{ \ - struct i1480u *i1480u = netdev_priv(to_net_dev(dev)); \ - return fn(&i1480u->param, buf, size); \ -} - -#define i1480u_ATTR(name, perm) static DEVICE_ATTR(name, perm, \ - i1480u_show_##name,\ - i1480u_store_##name) - -#define i1480u_ATTR_SHOW(name) static DEVICE_ATTR(name, \ - S_IRUGO, \ - i1480u_show_##name, NULL) - -#define i1480u_ATTR_NAME(a) (dev_attr_##a) - - -/* - * Sysfs adaptors - */ -i1480u_SHOW(uwb_phy_rate, uwb_phy_rate_show, options); -i1480u_STORE(uwb_phy_rate, uwb_phy_rate_store, options); -i1480u_ATTR(uwb_phy_rate, S_IRUGO | S_IWUSR); - -i1480u_SHOW(uwb_rts_cts, uwb_rts_cts_show, options); -i1480u_STORE(uwb_rts_cts, uwb_rts_cts_store, options); -i1480u_ATTR(uwb_rts_cts, S_IRUGO | S_IWUSR); - -i1480u_SHOW(uwb_ack_policy, uwb_ack_policy_show, options); -i1480u_STORE(uwb_ack_policy, uwb_ack_policy_store, options); -i1480u_ATTR(uwb_ack_policy, S_IRUGO | S_IWUSR); - -i1480u_SHOW(uwb_pca_base_priority, uwb_pca_base_priority_show, options); -i1480u_STORE(uwb_pca_base_priority, uwb_pca_base_priority_store, options); -i1480u_ATTR(uwb_pca_base_priority, S_IRUGO | S_IWUSR); - -i1480u_SHOW(wlp_eda, wlp_eda_show, wlp); -i1480u_STORE(wlp_eda, wlp_eda_store, wlp); -i1480u_ATTR(wlp_eda, S_IRUGO | S_IWUSR); - -i1480u_SHOW(wlp_uuid, wlp_uuid_show, wlp); -i1480u_STORE(wlp_uuid, wlp_uuid_store, wlp); -i1480u_ATTR(wlp_uuid, S_IRUGO | S_IWUSR); - -i1480u_SHOW(wlp_dev_name, wlp_dev_name_show, wlp); -i1480u_STORE(wlp_dev_name, wlp_dev_name_store, wlp); -i1480u_ATTR(wlp_dev_name, S_IRUGO | S_IWUSR); - -i1480u_SHOW(wlp_dev_manufacturer, wlp_dev_manufacturer_show, wlp); -i1480u_STORE(wlp_dev_manufacturer, wlp_dev_manufacturer_store, wlp); -i1480u_ATTR(wlp_dev_manufacturer, S_IRUGO | S_IWUSR); - -i1480u_SHOW(wlp_dev_model_name, wlp_dev_model_name_show, wlp); -i1480u_STORE(wlp_dev_model_name, wlp_dev_model_name_store, wlp); -i1480u_ATTR(wlp_dev_model_name, S_IRUGO | S_IWUSR); - -i1480u_SHOW(wlp_dev_model_nr, wlp_dev_model_nr_show, wlp); -i1480u_STORE(wlp_dev_model_nr, wlp_dev_model_nr_store, wlp); -i1480u_ATTR(wlp_dev_model_nr, S_IRUGO | S_IWUSR); - -i1480u_SHOW(wlp_dev_serial, wlp_dev_serial_show, wlp); -i1480u_STORE(wlp_dev_serial, wlp_dev_serial_store, wlp); -i1480u_ATTR(wlp_dev_serial, S_IRUGO | S_IWUSR); - -i1480u_SHOW(wlp_dev_prim_category, wlp_dev_prim_category_show, wlp); -i1480u_STORE(wlp_dev_prim_category, wlp_dev_prim_category_store, wlp); -i1480u_ATTR(wlp_dev_prim_category, S_IRUGO | S_IWUSR); - -i1480u_SHOW(wlp_dev_prim_OUI, wlp_dev_prim_OUI_show, wlp); -i1480u_STORE(wlp_dev_prim_OUI, wlp_dev_prim_OUI_store, wlp); -i1480u_ATTR(wlp_dev_prim_OUI, S_IRUGO | S_IWUSR); - -i1480u_SHOW(wlp_dev_prim_OUI_sub, wlp_dev_prim_OUI_sub_show, wlp); -i1480u_STORE(wlp_dev_prim_OUI_sub, wlp_dev_prim_OUI_sub_store, wlp); -i1480u_ATTR(wlp_dev_prim_OUI_sub, S_IRUGO | S_IWUSR); - -i1480u_SHOW(wlp_dev_prim_subcat, wlp_dev_prim_subcat_show, wlp); -i1480u_STORE(wlp_dev_prim_subcat, wlp_dev_prim_subcat_store, wlp); -i1480u_ATTR(wlp_dev_prim_subcat, S_IRUGO | S_IWUSR); - -i1480u_SHOW(wlp_neighborhood, wlp_neighborhood_show, wlp); -i1480u_ATTR_SHOW(wlp_neighborhood); - -i1480u_SHOW(wss_activate, wlp_wss_activate_show, wlp.wss); -i1480u_STORE(wss_activate, wlp_wss_activate_store, wlp.wss); -i1480u_ATTR(wss_activate, S_IRUGO | S_IWUSR); - -/* - * Show the (min, max, avg) Line Quality Estimate (LQE, in dB) as over - * the last 256 received WLP frames (ECMA-368 13.3). - * - * [the -7dB that have to be substracted from the LQI to make the LQE - * are already taken into account]. - */ -i1480u_SHOW(wlp_lqe, stats_show, lqe_stats); -i1480u_STORE(wlp_lqe, stats_store, lqe_stats); -i1480u_ATTR(wlp_lqe, S_IRUGO | S_IWUSR); - -/* - * Show the Receive Signal Strength Indicator averaged over all the - * received WLP frames (ECMA-368 13.3). Still is not clear what - * this value is, but is kind of a percentage of the signal strength - * at the antenna. - */ -i1480u_SHOW(wlp_rssi, stats_show, rssi_stats); -i1480u_STORE(wlp_rssi, stats_store, rssi_stats); -i1480u_ATTR(wlp_rssi, S_IRUGO | S_IWUSR); - -/** - * We maintain a basic flow control counter. "count" how many TX URBs are - * outstanding. Only allow "max" - * TX URBs to be outstanding. If this value is reached the queue will be - * stopped. The queue will be restarted when there are - * "threshold" URBs outstanding. - */ -i1480u_SHOW(wlp_tx_inflight, wlp_tx_inflight_show, tx_inflight); -i1480u_STORE(wlp_tx_inflight, wlp_tx_inflight_store, tx_inflight); -i1480u_ATTR(wlp_tx_inflight, S_IRUGO | S_IWUSR); - -static struct attribute *i1480u_attrs[] = { - &i1480u_ATTR_NAME(uwb_phy_rate).attr, - &i1480u_ATTR_NAME(uwb_rts_cts).attr, - &i1480u_ATTR_NAME(uwb_ack_policy).attr, - &i1480u_ATTR_NAME(uwb_pca_base_priority).attr, - &i1480u_ATTR_NAME(wlp_lqe).attr, - &i1480u_ATTR_NAME(wlp_rssi).attr, - &i1480u_ATTR_NAME(wlp_eda).attr, - &i1480u_ATTR_NAME(wlp_uuid).attr, - &i1480u_ATTR_NAME(wlp_dev_name).attr, - &i1480u_ATTR_NAME(wlp_dev_manufacturer).attr, - &i1480u_ATTR_NAME(wlp_dev_model_name).attr, - &i1480u_ATTR_NAME(wlp_dev_model_nr).attr, - &i1480u_ATTR_NAME(wlp_dev_serial).attr, - &i1480u_ATTR_NAME(wlp_dev_prim_category).attr, - &i1480u_ATTR_NAME(wlp_dev_prim_OUI).attr, - &i1480u_ATTR_NAME(wlp_dev_prim_OUI_sub).attr, - &i1480u_ATTR_NAME(wlp_dev_prim_subcat).attr, - &i1480u_ATTR_NAME(wlp_neighborhood).attr, - &i1480u_ATTR_NAME(wss_activate).attr, - &i1480u_ATTR_NAME(wlp_tx_inflight).attr, - NULL, -}; - -static struct attribute_group i1480u_attr_group = { - .name = NULL, /* we want them in the same directory */ - .attrs = i1480u_attrs, -}; - -int i1480u_sysfs_setup(struct i1480u *i1480u) -{ - int result; - struct device *dev = &i1480u->usb_iface->dev; - result = sysfs_create_group(&i1480u->net_dev->dev.kobj, - &i1480u_attr_group); - if (result < 0) - dev_err(dev, "cannot initialize sysfs attributes: %d\n", - result); - return result; -} - - -void i1480u_sysfs_release(struct i1480u *i1480u) -{ - sysfs_remove_group(&i1480u->net_dev->dev.kobj, - &i1480u_attr_group); -} diff --git a/drivers/uwb/i1480/i1480u-wlp/tx.c b/drivers/uwb/i1480/i1480u-wlp/tx.c deleted file mode 100644 index 3c117a36456..00000000000 --- a/drivers/uwb/i1480/i1480u-wlp/tx.c +++ /dev/null @@ -1,584 +0,0 @@ -/* - * WUSB Wire Adapter: WLP interface - * Deal with TX (massaging data to transmit, handling it) - * - * 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. - * - * - * Transmission engine. Get an skb, create from that a WLP transmit - * context, add a WLP TX header (which we keep prefilled in the - * device's instance), fill out the target-specific fields and - * fire it. - * - * ROADMAP: - * - * Entry points: - * - * i1480u_tx_release(): called by i1480u_disconnect() to release - * pending tx contexts. - * - * i1480u_tx_cb(): callback for TX contexts (USB URBs) - * i1480u_tx_destroy(): - * - * i1480u_tx_timeout(): called for timeout handling from the - * network stack. - * - * i1480u_hard_start_xmit(): called for transmitting an skb from - * the network stack. Will interact with WLP - * substack to verify and prepare frame. - * i1480u_xmit_frame(): actual transmission on hardware - * - * i1480u_tx_create() Creates TX context - * i1480u_tx_create_1() For packets in 1 fragment - * i1480u_tx_create_n() For packets in >1 fragments - * - * TODO: - * - * - FIXME: rewrite using usb_sg_*(), add asynch support to - * usb_sg_*(). It might not make too much sense as most of - * the times the MTU will be smaller than one page... - */ - -#include <linux/slab.h> -#include "i1480u-wlp.h" - -enum { - /* This is only for Next and Last TX packets */ - i1480u_MAX_PL_SIZE = i1480u_MAX_FRG_SIZE - - sizeof(struct untd_hdr_rst), -}; - -/* Free resources allocated to a i1480u tx context. */ -static -void i1480u_tx_free(struct i1480u_tx *wtx) -{ - kfree(wtx->buf); - if (wtx->skb) - dev_kfree_skb_irq(wtx->skb); - usb_free_urb(wtx->urb); - kfree(wtx); -} - -static -void i1480u_tx_destroy(struct i1480u *i1480u, struct i1480u_tx *wtx) -{ - unsigned long flags; - spin_lock_irqsave(&i1480u->tx_list_lock, flags); /* not active any more */ - list_del(&wtx->list_node); - i1480u_tx_free(wtx); - spin_unlock_irqrestore(&i1480u->tx_list_lock, flags); -} - -static -void i1480u_tx_unlink_urbs(struct i1480u *i1480u) -{ - unsigned long flags; - struct i1480u_tx *wtx, *next; - - spin_lock_irqsave(&i1480u->tx_list_lock, flags); - list_for_each_entry_safe(wtx, next, &i1480u->tx_list, list_node) { - usb_unlink_urb(wtx->urb); - } - spin_unlock_irqrestore(&i1480u->tx_list_lock, flags); -} - - -/* - * Callback for a completed tx USB URB. - * - * TODO: - * - * - FIXME: recover errors more gracefully - * - FIXME: handle NAKs (I dont think they come here) for flow ctl - */ -static -void i1480u_tx_cb(struct urb *urb) -{ - struct i1480u_tx *wtx = urb->context; - struct i1480u *i1480u = wtx->i1480u; - struct net_device *net_dev = i1480u->net_dev; - struct device *dev = &i1480u->usb_iface->dev; - unsigned long flags; - - switch (urb->status) { - case 0: - spin_lock_irqsave(&i1480u->lock, flags); - net_dev->stats.tx_packets++; - net_dev->stats.tx_bytes += urb->actual_length; - spin_unlock_irqrestore(&i1480u->lock, flags); - break; - case -ECONNRESET: /* Not an error, but a controlled situation; */ - case -ENOENT: /* (we killed the URB)...so, no broadcast */ - dev_dbg(dev, "notif endp: reset/noent %d\n", urb->status); - netif_stop_queue(net_dev); - break; - case -ESHUTDOWN: /* going away! */ - dev_dbg(dev, "notif endp: down %d\n", urb->status); - netif_stop_queue(net_dev); - break; - default: - dev_err(dev, "TX: unknown URB status %d\n", urb->status); - if (edc_inc(&i1480u->tx_errors, EDC_MAX_ERRORS, - EDC_ERROR_TIMEFRAME)) { - dev_err(dev, "TX: max acceptable errors exceeded." - "Reset device.\n"); - netif_stop_queue(net_dev); - i1480u_tx_unlink_urbs(i1480u); - wlp_reset_all(&i1480u->wlp); - } - break; - } - i1480u_tx_destroy(i1480u, wtx); - if (atomic_dec_return(&i1480u->tx_inflight.count) - <= i1480u->tx_inflight.threshold - && netif_queue_stopped(net_dev) - && i1480u->tx_inflight.threshold != 0) { - netif_start_queue(net_dev); - atomic_inc(&i1480u->tx_inflight.restart_count); - } - return; -} - - -/* - * Given a buffer that doesn't fit in a single fragment, create an - * scatter/gather structure for delivery to the USB pipe. - * - * Implements functionality of i1480u_tx_create(). - * - * @wtx: tx descriptor - * @skb: skb to send - * @gfp_mask: gfp allocation mask - * @returns: Pointer to @wtx if ok, NULL on error. - * - * Sorry, TOO LONG a function, but breaking it up is kind of hard - * - * This will break the buffer in chunks smaller than - * i1480u_MAX_FRG_SIZE (including the header) and add proper headers - * to each: - * - * 1st header \ - * i1480 tx header | fragment 1 - * fragment data / - * nxt header \ fragment 2 - * fragment data / - * .. - * .. - * last header \ fragment 3 - * last fragment data / - * - * This does not fill the i1480 TX header, it is left up to the - * caller to do that; you can get it from @wtx->wlp_tx_hdr. - * - * This function consumes the skb unless there is an error. - */ -static -int i1480u_tx_create_n(struct i1480u_tx *wtx, struct sk_buff *skb, - gfp_t gfp_mask) -{ - int result; - void *pl; - size_t pl_size; - - void *pl_itr, *buf_itr; - size_t pl_size_left, frgs, pl_size_1st, frg_pl_size = 0; - struct untd_hdr_1st *untd_hdr_1st; - struct wlp_tx_hdr *wlp_tx_hdr; - struct untd_hdr_rst *untd_hdr_rst; - - wtx->skb = NULL; - pl = skb->data; - pl_itr = pl; - pl_size = skb->len; - pl_size_left = pl_size; /* payload size */ - /* First fragment; fits as much as i1480u_MAX_FRG_SIZE minus - * the headers */ - pl_size_1st = i1480u_MAX_FRG_SIZE - - sizeof(struct untd_hdr_1st) - sizeof(struct wlp_tx_hdr); - BUG_ON(pl_size_1st > pl_size); - pl_size_left -= pl_size_1st; - /* The rest have an smaller header (no i1480 TX header). We - * need to break up the payload in blocks smaller than - * i1480u_MAX_PL_SIZE (payload excluding header). */ - frgs = (pl_size_left + i1480u_MAX_PL_SIZE - 1) / i1480u_MAX_PL_SIZE; - /* Allocate space for the new buffer. In this new buffer we'll - * place the headers followed by the data fragment, headers, - * data fragments, etc.. - */ - result = -ENOMEM; - wtx->buf_size = sizeof(*untd_hdr_1st) - + sizeof(*wlp_tx_hdr) - + frgs * sizeof(*untd_hdr_rst) - + pl_size; - wtx->buf = kmalloc(wtx->buf_size, gfp_mask); - if (wtx->buf == NULL) - goto error_buf_alloc; - - buf_itr = wtx->buf; /* We got the space, let's fill it up */ - /* Fill 1st fragment */ - untd_hdr_1st = buf_itr; - buf_itr += sizeof(*untd_hdr_1st); - untd_hdr_set_type(&untd_hdr_1st->hdr, i1480u_PKT_FRAG_1ST); - untd_hdr_set_rx_tx(&untd_hdr_1st->hdr, 0); - untd_hdr_1st->hdr.len = cpu_to_le16(pl_size + sizeof(*wlp_tx_hdr)); - untd_hdr_1st->fragment_len = - cpu_to_le16(pl_size_1st + sizeof(*wlp_tx_hdr)); - memset(untd_hdr_1st->padding, 0, sizeof(untd_hdr_1st->padding)); - /* Set up i1480 header info */ - wlp_tx_hdr = wtx->wlp_tx_hdr = buf_itr; - buf_itr += sizeof(*wlp_tx_hdr); - /* Copy the first fragment */ - memcpy(buf_itr, pl_itr, pl_size_1st); - pl_itr += pl_size_1st; - buf_itr += pl_size_1st; - - /* Now do each remaining fragment */ - result = -EINVAL; - while (pl_size_left > 0) { - if (buf_itr + sizeof(*untd_hdr_rst) - wtx->buf - > wtx->buf_size) { - printk(KERN_ERR "BUG: no space for header\n"); - goto error_bug; - } - untd_hdr_rst = buf_itr; - buf_itr += sizeof(*untd_hdr_rst); - if (pl_size_left > i1480u_MAX_PL_SIZE) { - frg_pl_size = i1480u_MAX_PL_SIZE; - untd_hdr_set_type(&untd_hdr_rst->hdr, i1480u_PKT_FRAG_NXT); - } else { - frg_pl_size = pl_size_left; - untd_hdr_set_type(&untd_hdr_rst->hdr, i1480u_PKT_FRAG_LST); - } - untd_hdr_set_rx_tx(&untd_hdr_rst->hdr, 0); - untd_hdr_rst->hdr.len = cpu_to_le16(frg_pl_size); - untd_hdr_rst->padding = 0; - if (buf_itr + frg_pl_size - wtx->buf - > wtx->buf_size) { - printk(KERN_ERR "BUG: no space for payload\n"); - goto error_bug; - } - memcpy(buf_itr, pl_itr, frg_pl_size); - buf_itr += frg_pl_size; - pl_itr += frg_pl_size; - pl_size_left -= frg_pl_size; - } - dev_kfree_skb_irq(skb); - return 0; - -error_bug: - printk(KERN_ERR - "BUG: skb %u bytes\n" - "BUG: frg_pl_size %zd i1480u_MAX_FRG_SIZE %u\n" - "BUG: buf_itr %zu buf_size %zu pl_size_left %zu\n", - skb->len, - frg_pl_size, i1480u_MAX_FRG_SIZE, - buf_itr - wtx->buf, wtx->buf_size, pl_size_left); - - kfree(wtx->buf); -error_buf_alloc: - return result; -} - - -/* - * Given a buffer that fits in a single fragment, fill out a @wtx - * struct for transmitting it down the USB pipe. - * - * Uses the fact that we have space reserved in front of the skbuff - * for hardware headers :] - * - * This does not fill the i1480 TX header, it is left up to the - * caller to do that; you can get it from @wtx->wlp_tx_hdr. - * - * @pl: pointer to payload data - * @pl_size: size of the payuload - * - * This function does not consume the @skb. - */ -static -int i1480u_tx_create_1(struct i1480u_tx *wtx, struct sk_buff *skb, - gfp_t gfp_mask) -{ - struct untd_hdr_cmp *untd_hdr_cmp; - struct wlp_tx_hdr *wlp_tx_hdr; - - wtx->buf = NULL; - wtx->skb = skb; - BUG_ON(skb_headroom(skb) < sizeof(*wlp_tx_hdr)); - wlp_tx_hdr = (void *) __skb_push(skb, sizeof(*wlp_tx_hdr)); - wtx->wlp_tx_hdr = wlp_tx_hdr; - BUG_ON(skb_headroom(skb) < sizeof(*untd_hdr_cmp)); - untd_hdr_cmp = (void *) __skb_push(skb, sizeof(*untd_hdr_cmp)); - - untd_hdr_set_type(&untd_hdr_cmp->hdr, i1480u_PKT_FRAG_CMP); - untd_hdr_set_rx_tx(&untd_hdr_cmp->hdr, 0); - untd_hdr_cmp->hdr.len = cpu_to_le16(skb->len - sizeof(*untd_hdr_cmp)); - untd_hdr_cmp->padding = 0; - return 0; -} - - -/* - * Given a skb to transmit, massage it to become palatable for the TX pipe - * - * This will break the buffer in chunks smaller than - * i1480u_MAX_FRG_SIZE and add proper headers to each. - * - * 1st header \ - * i1480 tx header | fragment 1 - * fragment data / - * nxt header \ fragment 2 - * fragment data / - * .. - * .. - * last header \ fragment 3 - * last fragment data / - * - * Each fragment will be always smaller or equal to i1480u_MAX_FRG_SIZE. - * - * If the first fragment is smaller than i1480u_MAX_FRG_SIZE, then the - * following is composed: - * - * complete header \ - * i1480 tx header | single fragment - * packet data / - * - * We were going to use s/g support, but because the interface is - * synch and at the end there is plenty of overhead to do it, it - * didn't seem that worth for data that is going to be smaller than - * one page. - */ -static -struct i1480u_tx *i1480u_tx_create(struct i1480u *i1480u, - struct sk_buff *skb, gfp_t gfp_mask) -{ - int result; - struct usb_endpoint_descriptor *epd; - int usb_pipe; - unsigned long flags; - - struct i1480u_tx *wtx; - const size_t pl_max_size = - i1480u_MAX_FRG_SIZE - sizeof(struct untd_hdr_cmp) - - sizeof(struct wlp_tx_hdr); - - wtx = kmalloc(sizeof(*wtx), gfp_mask); - if (wtx == NULL) - goto error_wtx_alloc; - wtx->urb = usb_alloc_urb(0, gfp_mask); - if (wtx->urb == NULL) - goto error_urb_alloc; - epd = &i1480u->usb_iface->cur_altsetting->endpoint[2].desc; - usb_pipe = usb_sndbulkpipe(i1480u->usb_dev, epd->bEndpointAddress); - /* Fits in a single complete packet or need to split? */ - if (skb->len > pl_max_size) { - result = i1480u_tx_create_n(wtx, skb, gfp_mask); - if (result < 0) - goto error_create; - usb_fill_bulk_urb(wtx->urb, i1480u->usb_dev, usb_pipe, - wtx->buf, wtx->buf_size, i1480u_tx_cb, wtx); - } else { - result = i1480u_tx_create_1(wtx, skb, gfp_mask); - if (result < 0) - goto error_create; - usb_fill_bulk_urb(wtx->urb, i1480u->usb_dev, usb_pipe, - skb->data, skb->len, i1480u_tx_cb, wtx); - } - spin_lock_irqsave(&i1480u->tx_list_lock, flags); - list_add(&wtx->list_node, &i1480u->tx_list); - spin_unlock_irqrestore(&i1480u->tx_list_lock, flags); - return wtx; - -error_create: - kfree(wtx->urb); -error_urb_alloc: - kfree(wtx); -error_wtx_alloc: - return NULL; -} - -/* - * Actual fragmentation and transmission of frame - * - * @wlp: WLP substack data structure - * @skb: To be transmitted - * @dst: Device address of destination - * @returns: 0 on success, <0 on failure - * - * This function can also be called directly (not just from - * hard_start_xmit), so we also check here if the interface is up before - * taking sending anything. - */ -int i1480u_xmit_frame(struct wlp *wlp, struct sk_buff *skb, - struct uwb_dev_addr *dst) -{ - int result = -ENXIO; - struct i1480u *i1480u = container_of(wlp, struct i1480u, wlp); - struct device *dev = &i1480u->usb_iface->dev; - struct net_device *net_dev = i1480u->net_dev; - struct i1480u_tx *wtx; - struct wlp_tx_hdr *wlp_tx_hdr; - static unsigned char dev_bcast[2] = { 0xff, 0xff }; - - BUG_ON(i1480u->wlp.rc == NULL); - if ((net_dev->flags & IFF_UP) == 0) - goto out; - result = -EBUSY; - if (atomic_read(&i1480u->tx_inflight.count) >= i1480u->tx_inflight.max) { - netif_stop_queue(net_dev); - goto error_max_inflight; - } - result = -ENOMEM; - wtx = i1480u_tx_create(i1480u, skb, GFP_ATOMIC); - if (unlikely(wtx == NULL)) { - if (printk_ratelimit()) - dev_err(dev, "TX: no memory for WLP TX URB," - "dropping packet (in flight %d)\n", - atomic_read(&i1480u->tx_inflight.count)); - netif_stop_queue(net_dev); - goto error_wtx_alloc; - } - wtx->i1480u = i1480u; - /* Fill out the i1480 header; @i1480u->def_tx_hdr read without - * locking. We do so because they are kind of orthogonal to - * each other (and thus not changed in an atomic batch). - * The ETH header is right after the WLP TX header. */ - wlp_tx_hdr = wtx->wlp_tx_hdr; - *wlp_tx_hdr = i1480u->options.def_tx_hdr; - wlp_tx_hdr->dstaddr = *dst; - if (!memcmp(&wlp_tx_hdr->dstaddr, dev_bcast, sizeof(dev_bcast)) - && (wlp_tx_hdr_delivery_id_type(wlp_tx_hdr) & WLP_DRP)) { - /*Broadcast message directed to DRP host. Send as best effort - * on PCA. */ - wlp_tx_hdr_set_delivery_id_type(wlp_tx_hdr, i1480u->options.pca_base_priority); - } - - result = usb_submit_urb(wtx->urb, GFP_ATOMIC); /* Go baby */ - if (result < 0) { - dev_err(dev, "TX: cannot submit URB: %d\n", result); - /* We leave the freeing of skb to calling function */ - wtx->skb = NULL; - goto error_tx_urb_submit; - } - atomic_inc(&i1480u->tx_inflight.count); - net_dev->trans_start = jiffies; - return result; - -error_tx_urb_submit: - i1480u_tx_destroy(i1480u, wtx); -error_wtx_alloc: -error_max_inflight: -out: - return result; -} - - -/* - * Transmit an skb Called when an skbuf has to be transmitted - * - * The skb is first passed to WLP substack to ensure this is a valid - * frame. If valid the device address of destination will be filled and - * the WLP header prepended to the skb. If this step fails we fake sending - * the frame, if we return an error the network stack will just keep trying. - * - * Broadcast frames inside a WSS needs to be treated special as multicast is - * not supported. A broadcast frame is sent as unicast to each member of the - * WSS - this is done by the WLP substack when it finds a broadcast frame. - * So, we test if the WLP substack took over the skb and only transmit it - * if it has not (been taken over). - * - * @net_dev->xmit_lock is held - */ -netdev_tx_t i1480u_hard_start_xmit(struct sk_buff *skb, - struct net_device *net_dev) -{ - int result; - struct i1480u *i1480u = netdev_priv(net_dev); - struct device *dev = &i1480u->usb_iface->dev; - struct uwb_dev_addr dst; - - if ((net_dev->flags & IFF_UP) == 0) - goto error; - result = wlp_prepare_tx_frame(dev, &i1480u->wlp, skb, &dst); - if (result < 0) { - dev_err(dev, "WLP verification of TX frame failed (%d). " - "Dropping packet.\n", result); - goto error; - } else if (result == 1) { - /* trans_start time will be set when WLP actually transmits - * the frame */ - goto out; - } - result = i1480u_xmit_frame(&i1480u->wlp, skb, &dst); - if (result < 0) { - dev_err(dev, "Frame TX failed (%d).\n", result); - goto error; - } - return NETDEV_TX_OK; -error: - dev_kfree_skb_any(skb); - net_dev->stats.tx_dropped++; -out: - return NETDEV_TX_OK; -} - - -/* - * Called when a pkt transmission doesn't complete in a reasonable period - * Device reset may sleep - do it outside of interrupt context (delayed) - */ -void i1480u_tx_timeout(struct net_device *net_dev) -{ - struct i1480u *i1480u = netdev_priv(net_dev); - - wlp_reset_all(&i1480u->wlp); -} - - -void i1480u_tx_release(struct i1480u *i1480u) -{ - unsigned long flags; - struct i1480u_tx *wtx, *next; - int count = 0, empty; - - spin_lock_irqsave(&i1480u->tx_list_lock, flags); - list_for_each_entry_safe(wtx, next, &i1480u->tx_list, list_node) { - count++; - usb_unlink_urb(wtx->urb); - } - spin_unlock_irqrestore(&i1480u->tx_list_lock, flags); - count = count*10; /* i1480ut 200ms per unlinked urb (intervals of 20ms) */ - /* - * We don't like this sollution too much (dirty as it is), but - * it is cheaper than putting a refcount on each i1480u_tx and - * i1480uting for all of them to go away... - * - * Called when no more packets can be added to tx_list - * so can i1480ut for it to be empty. - */ - while (1) { - spin_lock_irqsave(&i1480u->tx_list_lock, flags); - empty = list_empty(&i1480u->tx_list); - spin_unlock_irqrestore(&i1480u->tx_list_lock, flags); - if (empty) - break; - count--; - BUG_ON(count == 0); - msleep(20); - } -} |