All new accounts created on Gitlab now require administrator approval. If you invite any collaborators, please let Flux staff know so they can approve the accounts.

Commit a21b963a authored by Inaky Perez-Gonzalez's avatar Inaky Perez-Gonzalez Committed by David Vrabel

uwb: add the i1480 WLP driver

Add the driver for the WLP capability of the Intel i1480 device.
Signed-off-by: default avatarDavid Vrabel <david.vrabel@csr.com>
parent 1ba47da5
......@@ -76,4 +76,14 @@ config UWB_I1480U
To compile this driver select Y (built in) or M (module). It
is safe to select any even if you do not have the hardware.
config UWB_I1480U_WLP
tristate "Support for Intel Wireless UWB Link 1480 HWA's WLP interface"
depends on UWB_I1480U && UWB_WLP && NET
help
This driver enables WLP support for the i1480 when connected via
USB. WLP is the WiMedia Link Protocol, or IP over UWB.
To compile this driver select Y (built in) or M (module). It
is safe to select any even if you don't have the hardware.
endif # UWB
obj-$(CONFIG_UWB_I1480U) += dfu/ i1480-est.o
obj-$(CONFIG_UWB_I1480U_WLP) += i1480u-wlp/
/*
* Intel 1480 Wireless UWB Link
* WLP specific definitions
*
*
* 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
*/
#ifndef __i1480_wlp_h__
#define __i1480_wlp_h__
#include <linux/spinlock.h>
#include <linux/list.h>
#include <linux/uwb.h>
#include <linux/if_ether.h>
#include <asm/byteorder.h>
/* New simplified header format? */
#undef WLP_HDR_FMT_2 /* FIXME: rename */
/**
* Values of the Delivery ID & Type field when PCA or DRP
*
* The Delivery ID & Type field in the WLP TX header indicates whether
* the frame is PCA or DRP. This is done based on the high level bit of
* this field.
* We use this constant to test if the traffic is PCA or DRP as follows:
* if (wlp_tx_hdr_delivery_id_type(wlp_tx_hdr) & WLP_DRP)
* this is DRP traffic
* else
* this is PCA traffic
*/
enum deliver_id_type_bit {
WLP_DRP = 8,
};
/**
* WLP TX header
*
* Indicates UWB/WLP-specific transmission parameters for a network
* packet.
*/
struct wlp_tx_hdr {
/* dword 0 */
struct uwb_dev_addr dstaddr;
u8 key_index;
u8 mac_params;
/* dword 1 */
u8 phy_params;
#ifndef WLP_HDR_FMT_2
u8 reserved;
__le16 oui01; /* FIXME: not so sure if __le16 or u8[2] */
/* dword 2 */
u8 oui2; /* if all LE, it could be merged */
__le16 prid;
#endif
} __attribute__((packed));
static inline int wlp_tx_hdr_delivery_id_type(const struct wlp_tx_hdr *hdr)
{
return hdr->mac_params & 0x0f;
}
static inline int wlp_tx_hdr_ack_policy(const struct wlp_tx_hdr *hdr)
{
return (hdr->mac_params >> 4) & 0x07;
}
static inline int wlp_tx_hdr_rts_cts(const struct wlp_tx_hdr *hdr)
{
return (hdr->mac_params >> 7) & 0x01;
}
static inline void wlp_tx_hdr_set_delivery_id_type(struct wlp_tx_hdr *hdr, int id)
{
hdr->mac_params = (hdr->mac_params & ~0x0f) | id;
}
static inline void wlp_tx_hdr_set_ack_policy(struct wlp_tx_hdr *hdr,
enum uwb_ack_pol policy)
{
hdr->mac_params = (hdr->mac_params & ~0x70) | (policy << 4);
}
static inline void wlp_tx_hdr_set_rts_cts(struct wlp_tx_hdr *hdr, int rts_cts)
{
hdr->mac_params = (hdr->mac_params & ~0x80) | (rts_cts << 7);
}
static inline enum uwb_phy_rate wlp_tx_hdr_phy_rate(const struct wlp_tx_hdr *hdr)
{
return hdr->phy_params & 0x0f;
}
static inline int wlp_tx_hdr_tx_power(const struct wlp_tx_hdr *hdr)
{
return (hdr->phy_params >> 4) & 0x0f;
}
static inline void wlp_tx_hdr_set_phy_rate(struct wlp_tx_hdr *hdr, enum uwb_phy_rate rate)
{
hdr->phy_params = (hdr->phy_params & ~0x0f) | rate;
}
static inline void wlp_tx_hdr_set_tx_power(struct wlp_tx_hdr *hdr, int pwr)
{
hdr->phy_params = (hdr->phy_params & ~0xf0) | (pwr << 4);
}
/**
* WLP RX header
*
* Provides UWB/WLP-specific transmission data for a received
* network packet.
*/
struct wlp_rx_hdr {
/* dword 0 */
struct uwb_dev_addr dstaddr;
struct uwb_dev_addr srcaddr;
/* dword 1 */
u8 LQI;
s8 RSSI;
u8 reserved3;
#ifndef WLP_HDR_FMT_2
u8 oui0;
/* dword 2 */
__le16 oui12;
__le16 prid;
#endif
} __attribute__((packed));
/** User configurable options for WLP */
struct wlp_options {
struct mutex mutex; /* access to user configurable options*/
struct wlp_tx_hdr def_tx_hdr; /* default tx hdr */
u8 pca_base_priority;
u8 bw_alloc; /*index into bw_allocs[] for PCA/DRP reservations*/
};
static inline
void wlp_options_init(struct wlp_options *options)
{
mutex_init(&options->mutex);
wlp_tx_hdr_set_ack_policy(&options->def_tx_hdr, UWB_ACK_INM);
wlp_tx_hdr_set_rts_cts(&options->def_tx_hdr, 1);
/* FIXME: default to phy caps */
wlp_tx_hdr_set_phy_rate(&options->def_tx_hdr, UWB_PHY_RATE_480);
#ifndef WLP_HDR_FMT_2
options->def_tx_hdr.prid = cpu_to_le16(0x0000);
#endif
}
/* sysfs helpers */
extern ssize_t uwb_pca_base_priority_store(struct wlp_options *,
const char *, size_t);
extern ssize_t uwb_pca_base_priority_show(const struct wlp_options *, char *);
extern ssize_t uwb_bw_alloc_store(struct wlp_options *, const char *, size_t);
extern ssize_t uwb_bw_alloc_show(const struct wlp_options *, char *);
extern ssize_t uwb_ack_policy_store(struct wlp_options *,
const char *, size_t);
extern ssize_t uwb_ack_policy_show(const struct wlp_options *, char *);
extern ssize_t uwb_rts_cts_store(struct wlp_options *, const char *, size_t);
extern ssize_t uwb_rts_cts_show(const struct wlp_options *, char *);
extern ssize_t uwb_phy_rate_store(struct wlp_options *, const char *, size_t);
extern ssize_t uwb_phy_rate_show(const struct wlp_options *, char *);
/** Simple bandwidth allocation (temporary and too simple) */
struct wlp_bw_allocs {
const char *name;
struct {
u8 mask, stream;
} tx, rx;
};
#endif /* #ifndef __i1480_wlp_h__ */
obj-$(CONFIG_UWB_I1480U_WLP) += i1480u-wlp.o
i1480u-wlp-objs := \
lc.o \
netdev.o \
rx.o \
sysfs.o \
tx.o
/*
* 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;
struct net_device_stats stats;
/* 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 int 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 struct net_device_stats *i1480u_get_stats(struct net_device *);
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__ */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment