284 lines
7.9 KiB
C
284 lines
7.9 KiB
C
|
/*
|
||
|
* 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__ */
|