* Re: [PATCH 10/14] [rndis_host] Add rndis_early_init function pointer to 'struct rndis_data'.
From: David Brownell @ 2008-01-25 1:10 UTC (permalink / raw)
To: Jussi Kivilinna
Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA, bjd-a1rhEgazXTw,
netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20080120001438.25718.96722.stgit-q/85JClnwdg@public.gmane.org>
On Saturday 19 January 2008, Jussi Kivilinna wrote:
> Function pointer is for rndis minidrivers that need to do work on device right
> after RNDIS_INIT. For example setting device specific configuration parameters
> with OID_GEN_RNDIS_CONFIG_PARAMETER.
>
> Signed-off-by: Jussi Kivilinna <jussi.kivilinna-E01nCVcF24I@public.gmane.org>
Could this -- and #11/14 -- instead be generalized a bit,
so they're not RNDIS-specific? At least in name; the
only user for now would be the rndis_host code.
The generalization would presumably be "early_init" and
"link_change", paired with doc comments reflecting that
they're usable by any driver stack built over the usbnet
framework core.
There's no point IMO to having generalizable hooks be
restricted this way.
- Dave
> ---
>
> drivers/net/usb/rndis_host.c | 6 ++++++
> drivers/net/usb/usbnet.h | 3 +++
> 2 files changed, 9 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c
> index 1d6bf0a..22e5ca1 100644
> --- a/drivers/net/usb/rndis_host.c
> +++ b/drivers/net/usb/rndis_host.c
> @@ -336,6 +336,12 @@ int generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf)
> dev->hard_mtu, tmp, dev->rx_urb_size,
> 1 << le32_to_cpu(u.init_c->packet_alignment));
>
> + /* module has some device initialization code needs to be done right
> + * after RNDIS_INIT */
> + if (dev->driver_info->rndis_early_init &&
> + dev->driver_info->rndis_early_init(dev) != 0)
> + goto halt_fail_and_release;
> +
> /* Get designated host ethernet address */
> reply_len = ETH_ALEN;
> retval = rndis_query(dev, intf, u.buf, OID_802_3_PERMANENT_ADDRESS,
> diff --git a/drivers/net/usb/usbnet.h b/drivers/net/usb/usbnet.h
> index 0b4bf09..2bc5f76 100644
> --- a/drivers/net/usb/usbnet.h
> +++ b/drivers/net/usb/usbnet.h
> @@ -116,6 +116,9 @@ struct driver_info {
> struct sk_buff *(*tx_fixup)(struct usbnet *dev,
> struct sk_buff *skb, gfp_t flags);
>
> + /* rndis minidriver early initialization code, can sleep */
> + int (*rndis_early_init)(struct usbnet *dev);
> +
> /* for new devices, use the descriptor-reading code instead */
> int in; /* rx endpoint */
> int out; /* tx endpoint */
>
^ permalink raw reply
* Re: [PATCH 13/14] [rndis_host] blacklist known wireless RNDIS devices
From: David Brownell @ 2008-01-25 1:13 UTC (permalink / raw)
To: Jussi Kivilinna
Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA, bjd-a1rhEgazXTw,
netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20080120001455.25718.75424.stgit-q/85JClnwdg@public.gmane.org>
On Saturday 19 January 2008, Jussi Kivilinna wrote:
> Blacklist known wireless RNDIS devices that will be handled by
> rndis_wext module.
This seems destined to become a headache. Wouldn't it be better
to let the probe progress far enough to detect that it's actually
a WLAN device, and then back out so the next driver can try?
- Dave
> Signed-off-by: Jussi Kivilinna <jussi.kivilinna-E01nCVcF24I@public.gmane.org>
> ---
>
> drivers/net/usb/rndis_host.c | 104 ++++++++++++++++++++++++++++++++++++++++++
> 1 files changed, 104 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c
> index 1ffbbb3..cd1f953 100644
> --- a/drivers/net/usb/rndis_host.c
> +++ b/drivers/net/usb/rndis_host.c
> @@ -530,6 +530,110 @@ static const struct driver_info rndis_info = {
> /*-------------------------------------------------------------------------*/
>
> static const struct usb_device_id products [] = {
> +/*
> + * BLACKLIST !!
> + *
> + * Blacklist RNDIS devices that are handled in separate RNDIS modules.
> + */
> +
> +#define RNDIS_MASTER_INTERFACE \
> + .bInterfaceClass = USB_CLASS_COMM, \
> + .bInterfaceSubClass = 2 /* ACM */, \
> + .bInterfaceProtocol = 0x0ff
> +
> +/* Wireless RNDIS devices, rndis_wext module */
> +{
> + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
> + | USB_DEVICE_ID_MATCH_DEVICE,
> + .idVendor = 0x0411,
> + .idProduct = 0x00bc, /* Buffalo WLI-U2-KG125S */
> + RNDIS_MASTER_INTERFACE,
> + .driver_info = 0,
> +}, {
> + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
> + | USB_DEVICE_ID_MATCH_DEVICE,
> + .idVendor = 0x0baf,
> + .idProduct = 0x011b, /* U.S. Robotics USR5421 */
> + RNDIS_MASTER_INTERFACE,
> + .driver_info = 0,
> +}, {
> + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
> + | USB_DEVICE_ID_MATCH_DEVICE,
> + .idVendor = 0x050d,
> + .idProduct = 0x011b, /* Belkin F5D7051 */
> + RNDIS_MASTER_INTERFACE,
> + .driver_info = 0,
> +}, {
> + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
> + | USB_DEVICE_ID_MATCH_DEVICE,
> + .idVendor = 0x1799, /* Belkin has two vendor ids */
> + .idProduct = 0x011b, /* Belkin F5D7051 */
> + RNDIS_MASTER_INTERFACE,
> + .driver_info = 0,
> +}, {
> + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
> + | USB_DEVICE_ID_MATCH_DEVICE,
> + .idVendor = 0x13b1,
> + .idProduct = 0x0014, /* Linksys WUSB54GSv2 */
> + RNDIS_MASTER_INTERFACE,
> + .driver_info = 0,
> +}, {
> + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
> + | USB_DEVICE_ID_MATCH_DEVICE,
> + .idVendor = 0x13b1,
> + .idProduct = 0x0026, /* Linksys WUSB54GSC */
> + RNDIS_MASTER_INTERFACE,
> + .driver_info = 0,
> +}, {
> + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
> + | USB_DEVICE_ID_MATCH_DEVICE,
> + .idVendor = 0x0b05,
> + .idProduct = 0x1717, /* Asus WL169gE */
> + RNDIS_MASTER_INTERFACE,
> + .driver_info = 0,
> +}, {
> + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
> + | USB_DEVICE_ID_MATCH_DEVICE,
> + .idVendor = 0x0a5c,
> + .idProduct = 0xd11b, /* Eminent EM4045 */
> + RNDIS_MASTER_INTERFACE,
> + .driver_info = 0,
> +}, {
> + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
> + | USB_DEVICE_ID_MATCH_DEVICE,
> + .idVendor = 0x1690,
> + .idProduct = 0x0715, /* BT Voyager 1055 */
> + RNDIS_MASTER_INTERFACE,
> + .driver_info = 0,
> +}, {
> + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
> + | USB_DEVICE_ID_MATCH_DEVICE,
> + .idVendor = 0x13b1,
> + .idProduct = 0x000e, /* Linksys WUSB54GSv1 */
> + RNDIS_MASTER_INTERFACE,
> + .driver_info = 0,
> +}, {
> + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
> + | USB_DEVICE_ID_MATCH_DEVICE,
> + .idVendor = 0x0baf,
> + .idProduct = 0x0111, /* U.S. Robotics USR5420 */
> + RNDIS_MASTER_INTERFACE,
> + .driver_info = 0,
> +}, {
> + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
> + | USB_DEVICE_ID_MATCH_DEVICE,
> + .idVendor = 0x0411,
> + .idProduct = 0x004b, /* BUFFALO WLI-USB-G54 */
> + RNDIS_MASTER_INTERFACE,
> + .driver_info = 0,
> +},
> +
> +/*
> + * WHITELIST!!!
> + *
> + * All other RNDIS devices that do not need special OID handling in order
> + * to work.
> + */
> {
> /* RNDIS is MSFT's un-official variant of CDC ACM */
> USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff),
>
^ permalink raw reply
* Re: [PATCH 02/14] [cdc_ether] Hardwire CDC descriptors when missing
From: David Brownell @ 2008-01-25 0:55 UTC (permalink / raw)
To: Jussi Kivilinna; +Cc: linux-wireless, bjd, netdev
In-Reply-To: <20080120001353.25718.38880.stgit@fate.lan>
On Saturday 19 January 2008, Jussi Kivilinna wrote:
> From: Bjorge Dijkstra <bjd@jooz.net>
>
> Just as ActiveSync devices, some regular RNDIS devices also lack
> the CDC descriptors (e.g. devices based on BCM4320 WLAN chip).
> This patch hardwires the CDC descriptors for all RNDIS style devices
> when they are missing.
>
> Signed-off-by: Bjorge Dijkstra <bjd@jooz.net>
> Signed-off-by: Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
Acked-by: David Brownell <dbrownell@users.sourceforge.net>
> ---
>
> drivers/net/usb/cdc_ether.c | 10 +++++-----
> 1 files changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c
> index a42acc3..97c17bb 100644
> --- a/drivers/net/usb/cdc_ether.c
> +++ b/drivers/net/usb/cdc_ether.c
> @@ -228,15 +228,16 @@ next_desc:
> buf += buf [0];
> }
>
> - /* Microsoft ActiveSync based RNDIS devices lack the CDC descriptors,
> - * so we'll hard-wire the interfaces and not check for descriptors.
> + /* Microsoft ActiveSync based and some regular RNDIS devices lack the
> + * CDC descriptors, so we'll hard-wire the interfaces and not check
> + * for descriptors.
> */
> - if (is_activesync(&intf->cur_altsetting->desc) && !info->u) {
> + if (rndis && !info->u) {
> info->control = usb_ifnum_to_if(dev->udev, 0);
> info->data = usb_ifnum_to_if(dev->udev, 1);
> if (!info->control || !info->data) {
> dev_dbg(&intf->dev,
> - "activesync: master #0/%p slave #1/%p\n",
> + "rndis: master #0/%p slave #1/%p\n",
> info->control,
> info->data);
> goto bad_desc;
> @@ -316,7 +317,6 @@ void usbnet_cdc_unbind(struct usbnet *dev, struct usb_interface *intf)
> }
> EXPORT_SYMBOL_GPL(usbnet_cdc_unbind);
>
> -\f
> /*-------------------------------------------------------------------------
> *
> * Communications Device Class, Ethernet Control model
>
^ permalink raw reply
* Re: [PATCH 03/14] [rndis_host] Use 1KB buffer in rndis_unbind
From: David Brownell @ 2008-01-25 0:55 UTC (permalink / raw)
To: Jussi Kivilinna; +Cc: linux-wireless, bjd, netdev
In-Reply-To: <20080120001359.25718.20460.stgit@fate.lan>
On Saturday 19 January 2008, Jussi Kivilinna wrote:
> rndis_command requires the caller to pass in a buffer of at least 1KB.
>
> Signed-off-by: Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
> Signed-off-by: Bjorge Dijkstra <bjd@jooz.net>
Acked-by: David Brownell <dbrownell@users.sourceforge.net>
> ---
>
> drivers/net/usb/rndis_host.c | 2 +-
> 1 files changed, 1 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c
> index 96ef6a9..42b161c 100644
> --- a/drivers/net/usb/rndis_host.c
> +++ b/drivers/net/usb/rndis_host.c
> @@ -577,7 +577,7 @@ static void rndis_unbind(struct usbnet *dev, struct usb_interface *intf)
> struct rndis_halt *halt;
>
> /* try to clear any rndis state/activity (no i/o from stack!) */
> - halt = kzalloc(sizeof *halt, GFP_KERNEL);
> + halt = kzalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL);
> if (halt) {
> halt->msg_type = RNDIS_MSG_HALT;
> halt->msg_len = ccpu2(sizeof *halt);
>
^ permalink raw reply
* Re: [PATCH 05/14] [rndis_host] Fix rndis packet filter flags.
From: David Brownell @ 2008-01-25 0:55 UTC (permalink / raw)
To: Jussi Kivilinna; +Cc: linux-wireless, bjd, netdev
In-Reply-To: <20080120001410.25718.70147.stgit@fate.lan>
On Saturday 19 January 2008, Jussi Kivilinna wrote:
> RNDIS packet filter flags are not exactly the same as CDC flags
> so we cannot reuse them.
>
> Signed-off-by: Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
> Signed-off-by: Bjorge Dijkstra <bjd@jooz.net>
Acked-by: David Brownell <dbrownell@users.sourceforge.net>
> ---
>
> drivers/net/usb/rndis_host.c | 23 ++++++++++++++++++++++-
> 1 files changed, 22 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c
> index c686025..12daf9c 100644
> --- a/drivers/net/usb/rndis_host.c
> +++ b/drivers/net/usb/rndis_host.c
> @@ -256,6 +256,27 @@ struct rndis_keepalive_c { /* IN (optionally OUT) */
> #define OID_GEN_MAXIMUM_FRAME_SIZE ccpu2(0x00010106)
> #define OID_GEN_CURRENT_PACKET_FILTER ccpu2(0x0001010e)
>
> +/* packet filter bits used by OID_GEN_CURRENT_PACKET_FILTER */
> +#define RNDIS_PACKET_TYPE_DIRECTED ccpu2(0x00000001)
> +#define RNDIS_PACKET_TYPE_MULTICAST ccpu2(0x00000002)
> +#define RNDIS_PACKET_TYPE_ALL_MULTICAST ccpu2(0x00000004)
> +#define RNDIS_PACKET_TYPE_BROADCAST ccpu2(0x00000008)
> +#define RNDIS_PACKET_TYPE_SOURCE_ROUTING ccpu2(0x00000010)
> +#define RNDIS_PACKET_TYPE_PROMISCUOUS ccpu2(0x00000020)
> +#define RNDIS_PACKET_TYPE_SMT ccpu2(0x00000040)
> +#define RNDIS_PACKET_TYPE_ALL_LOCAL ccpu2(0x00000080)
> +#define RNDIS_PACKET_TYPE_GROUP ccpu2(0x00001000)
> +#define RNDIS_PACKET_TYPE_ALL_FUNCTIONAL ccpu2(0x00002000)
> +#define RNDIS_PACKET_TYPE_FUNCTIONAL ccpu2(0x00004000)
> +#define RNDIS_PACKET_TYPE_MAC_FRAME ccpu2(0x00008000)
> +
> +/* default filter used with RNDIS devices */
> +#define RNDIS_DEFAULT_FILTER ( \
> + RNDIS_PACKET_TYPE_DIRECTED | \
> + RNDIS_PACKET_TYPE_BROADCAST | \
> + RNDIS_PACKET_TYPE_ALL_MULTICAST | \
> + RNDIS_PACKET_TYPE_PROMISCUOUS)
> +
> /*
> * RNDIS notifications from device: command completion; "reverse"
> * keepalives; etc
> @@ -551,7 +572,7 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
> u.set->oid = OID_GEN_CURRENT_PACKET_FILTER;
> u.set->len = ccpu2(4);
> u.set->offset = ccpu2((sizeof *u.set) - 8);
> - *(__le32 *)(u.buf + sizeof *u.set) = ccpu2(DEFAULT_FILTER);
> + *(__le32 *)(u.buf + sizeof *u.set) = RNDIS_DEFAULT_FILTER;
>
> retval = rndis_command(dev, u.header);
> if (unlikely(retval < 0)) {
>
^ permalink raw reply
* Re: [PATCH 07/14] [rndis_host] Split up rndis_host.c
From: David Brownell @ 2008-01-25 0:58 UTC (permalink / raw)
To: Jussi Kivilinna; +Cc: linux-wireless, bjd, netdev
In-Reply-To: <20080120001421.25718.92634.stgit@fate.lan>
On Saturday 19 January 2008, Jussi Kivilinna wrote:
> Split up rndis_host.c into rndis_host.h and rndis_base.c. This is done so
> that rndis_wext can reuse common parts with rndis_host.
>
> Signed-off-by: Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
Acked-by: David Brownell <dbrownell@users.sourceforge.net>
> ---
>
> drivers/net/usb/rndis_host.c | 223 --------------------------------------
> drivers/net/usb/rndis_host.h | 248 ++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 249 insertions(+), 222 deletions(-)
>
> diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c
> index 12daf9c..29d7e3b 100644
> --- a/drivers/net/usb/rndis_host.c
> +++ b/drivers/net/usb/rndis_host.c
> @@ -31,6 +31,7 @@
> #include <linux/usb/cdc.h>
>
> #include "usbnet.h"
> +#include "rndis_host.h"
>
>
> /*
> @@ -56,228 +57,6 @@
> */
>
> /*
> - * CONTROL uses CDC "encapsulated commands" with funky notifications.
> - * - control-out: SEND_ENCAPSULATED
> - * - interrupt-in: RESPONSE_AVAILABLE
> - * - control-in: GET_ENCAPSULATED
> - *
> - * We'll try to ignore the RESPONSE_AVAILABLE notifications.
> - *
> - * REVISIT some RNDIS implementations seem to have curious issues still
> - * to be resolved.
> - */
> -struct rndis_msg_hdr {
> - __le32 msg_type; /* RNDIS_MSG_* */
> - __le32 msg_len;
> - // followed by data that varies between messages
> - __le32 request_id;
> - __le32 status;
> - // ... and more
> -} __attribute__ ((packed));
> -
> -/* MS-Windows uses this strange size, but RNDIS spec says 1024 minimum */
> -#define CONTROL_BUFFER_SIZE 1025
> -
> -/* RNDIS defines an (absurdly huge) 10 second control timeout,
> - * but ActiveSync seems to use a more usual 5 second timeout
> - * (which matches the USB 2.0 spec).
> - */
> -#define RNDIS_CONTROL_TIMEOUT_MS (5 * 1000)
> -
> -
> -#define ccpu2 __constant_cpu_to_le32
> -
> -#define RNDIS_MSG_COMPLETION ccpu2(0x80000000)
> -
> -/* codes for "msg_type" field of rndis messages;
> - * only the data channel uses packet messages (maybe batched);
> - * everything else goes on the control channel.
> - */
> -#define RNDIS_MSG_PACKET ccpu2(0x00000001) /* 1-N packets */
> -#define RNDIS_MSG_INIT ccpu2(0x00000002)
> -#define RNDIS_MSG_INIT_C (RNDIS_MSG_INIT|RNDIS_MSG_COMPLETION)
> -#define RNDIS_MSG_HALT ccpu2(0x00000003)
> -#define RNDIS_MSG_QUERY ccpu2(0x00000004)
> -#define RNDIS_MSG_QUERY_C (RNDIS_MSG_QUERY|RNDIS_MSG_COMPLETION)
> -#define RNDIS_MSG_SET ccpu2(0x00000005)
> -#define RNDIS_MSG_SET_C (RNDIS_MSG_SET|RNDIS_MSG_COMPLETION)
> -#define RNDIS_MSG_RESET ccpu2(0x00000006)
> -#define RNDIS_MSG_RESET_C (RNDIS_MSG_RESET|RNDIS_MSG_COMPLETION)
> -#define RNDIS_MSG_INDICATE ccpu2(0x00000007)
> -#define RNDIS_MSG_KEEPALIVE ccpu2(0x00000008)
> -#define RNDIS_MSG_KEEPALIVE_C (RNDIS_MSG_KEEPALIVE|RNDIS_MSG_COMPLETION)
> -
> -/* codes for "status" field of completion messages */
> -#define RNDIS_STATUS_SUCCESS ccpu2(0x00000000)
> -#define RNDIS_STATUS_FAILURE ccpu2(0xc0000001)
> -#define RNDIS_STATUS_INVALID_DATA ccpu2(0xc0010015)
> -#define RNDIS_STATUS_NOT_SUPPORTED ccpu2(0xc00000bb)
> -#define RNDIS_STATUS_MEDIA_CONNECT ccpu2(0x4001000b)
> -#define RNDIS_STATUS_MEDIA_DISCONNECT ccpu2(0x4001000c)
> -
> -
> -struct rndis_data_hdr {
> - __le32 msg_type; /* RNDIS_MSG_PACKET */
> - __le32 msg_len; // rndis_data_hdr + data_len + pad
> - __le32 data_offset; // 36 -- right after header
> - __le32 data_len; // ... real packet size
> -
> - __le32 oob_data_offset; // zero
> - __le32 oob_data_len; // zero
> - __le32 num_oob; // zero
> - __le32 packet_data_offset; // zero
> -
> - __le32 packet_data_len; // zero
> - __le32 vc_handle; // zero
> - __le32 reserved; // zero
> -} __attribute__ ((packed));
> -
> -struct rndis_init { /* OUT */
> - // header and:
> - __le32 msg_type; /* RNDIS_MSG_INIT */
> - __le32 msg_len; // 24
> - __le32 request_id;
> - __le32 major_version; // of rndis (1.0)
> - __le32 minor_version;
> - __le32 max_transfer_size;
> -} __attribute__ ((packed));
> -
> -struct rndis_init_c { /* IN */
> - // header and:
> - __le32 msg_type; /* RNDIS_MSG_INIT_C */
> - __le32 msg_len;
> - __le32 request_id;
> - __le32 status;
> - __le32 major_version; // of rndis (1.0)
> - __le32 minor_version;
> - __le32 device_flags;
> - __le32 medium; // zero == 802.3
> - __le32 max_packets_per_message;
> - __le32 max_transfer_size;
> - __le32 packet_alignment; // max 7; (1<<n) bytes
> - __le32 af_list_offset; // zero
> - __le32 af_list_size; // zero
> -} __attribute__ ((packed));
> -
> -struct rndis_halt { /* OUT (no reply) */
> - // header and:
> - __le32 msg_type; /* RNDIS_MSG_HALT */
> - __le32 msg_len;
> - __le32 request_id;
> -} __attribute__ ((packed));
> -
> -struct rndis_query { /* OUT */
> - // header and:
> - __le32 msg_type; /* RNDIS_MSG_QUERY */
> - __le32 msg_len;
> - __le32 request_id;
> - __le32 oid;
> - __le32 len;
> - __le32 offset;
> -/*?*/ __le32 handle; // zero
> -} __attribute__ ((packed));
> -
> -struct rndis_query_c { /* IN */
> - // header and:
> - __le32 msg_type; /* RNDIS_MSG_QUERY_C */
> - __le32 msg_len;
> - __le32 request_id;
> - __le32 status;
> - __le32 len;
> - __le32 offset;
> -} __attribute__ ((packed));
> -
> -struct rndis_set { /* OUT */
> - // header and:
> - __le32 msg_type; /* RNDIS_MSG_SET */
> - __le32 msg_len;
> - __le32 request_id;
> - __le32 oid;
> - __le32 len;
> - __le32 offset;
> -/*?*/ __le32 handle; // zero
> -} __attribute__ ((packed));
> -
> -struct rndis_set_c { /* IN */
> - // header and:
> - __le32 msg_type; /* RNDIS_MSG_SET_C */
> - __le32 msg_len;
> - __le32 request_id;
> - __le32 status;
> -} __attribute__ ((packed));
> -
> -struct rndis_reset { /* IN */
> - // header and:
> - __le32 msg_type; /* RNDIS_MSG_RESET */
> - __le32 msg_len;
> - __le32 reserved;
> -} __attribute__ ((packed));
> -
> -struct rndis_reset_c { /* OUT */
> - // header and:
> - __le32 msg_type; /* RNDIS_MSG_RESET_C */
> - __le32 msg_len;
> - __le32 status;
> - __le32 addressing_lost;
> -} __attribute__ ((packed));
> -
> -struct rndis_indicate { /* IN (unrequested) */
> - // header and:
> - __le32 msg_type; /* RNDIS_MSG_INDICATE */
> - __le32 msg_len;
> - __le32 status;
> - __le32 length;
> - __le32 offset;
> -/**/ __le32 diag_status;
> - __le32 error_offset;
> -/**/ __le32 message;
> -} __attribute__ ((packed));
> -
> -struct rndis_keepalive { /* OUT (optionally IN) */
> - // header and:
> - __le32 msg_type; /* RNDIS_MSG_KEEPALIVE */
> - __le32 msg_len;
> - __le32 request_id;
> -} __attribute__ ((packed));
> -
> -struct rndis_keepalive_c { /* IN (optionally OUT) */
> - // header and:
> - __le32 msg_type; /* RNDIS_MSG_KEEPALIVE_C */
> - __le32 msg_len;
> - __le32 request_id;
> - __le32 status;
> -} __attribute__ ((packed));
> -
> -/* NOTE: about 30 OIDs are "mandatory" for peripherals to support ... and
> - * there are gobs more that may optionally be supported. We'll avoid as much
> - * of that mess as possible.
> - */
> -#define OID_802_3_PERMANENT_ADDRESS ccpu2(0x01010101)
> -#define OID_GEN_MAXIMUM_FRAME_SIZE ccpu2(0x00010106)
> -#define OID_GEN_CURRENT_PACKET_FILTER ccpu2(0x0001010e)
> -
> -/* packet filter bits used by OID_GEN_CURRENT_PACKET_FILTER */
> -#define RNDIS_PACKET_TYPE_DIRECTED ccpu2(0x00000001)
> -#define RNDIS_PACKET_TYPE_MULTICAST ccpu2(0x00000002)
> -#define RNDIS_PACKET_TYPE_ALL_MULTICAST ccpu2(0x00000004)
> -#define RNDIS_PACKET_TYPE_BROADCAST ccpu2(0x00000008)
> -#define RNDIS_PACKET_TYPE_SOURCE_ROUTING ccpu2(0x00000010)
> -#define RNDIS_PACKET_TYPE_PROMISCUOUS ccpu2(0x00000020)
> -#define RNDIS_PACKET_TYPE_SMT ccpu2(0x00000040)
> -#define RNDIS_PACKET_TYPE_ALL_LOCAL ccpu2(0x00000080)
> -#define RNDIS_PACKET_TYPE_GROUP ccpu2(0x00001000)
> -#define RNDIS_PACKET_TYPE_ALL_FUNCTIONAL ccpu2(0x00002000)
> -#define RNDIS_PACKET_TYPE_FUNCTIONAL ccpu2(0x00004000)
> -#define RNDIS_PACKET_TYPE_MAC_FRAME ccpu2(0x00008000)
> -
> -/* default filter used with RNDIS devices */
> -#define RNDIS_DEFAULT_FILTER ( \
> - RNDIS_PACKET_TYPE_DIRECTED | \
> - RNDIS_PACKET_TYPE_BROADCAST | \
> - RNDIS_PACKET_TYPE_ALL_MULTICAST | \
> - RNDIS_PACKET_TYPE_PROMISCUOUS)
> -
> -/*
> * RNDIS notifications from device: command completion; "reverse"
> * keepalives; etc
> */
> diff --git a/drivers/net/usb/rndis_host.h b/drivers/net/usb/rndis_host.h
> new file mode 100644
> index 0000000..1386a17
> --- /dev/null
> +++ b/drivers/net/usb/rndis_host.h
> @@ -0,0 +1,248 @@
> +/*
> + * Host Side support for RNDIS Networking Links
> + * Copyright (C) 2005 by David Brownell
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> + */
> +
> +
> +#ifndef __RNDIS_HOST_H
> +#define __RNDIS_HOST_H
> +
> +
> +/*
> + * CONTROL uses CDC "encapsulated commands" with funky notifications.
> + * - control-out: SEND_ENCAPSULATED
> + * - interrupt-in: RESPONSE_AVAILABLE
> + * - control-in: GET_ENCAPSULATED
> + *
> + * We'll try to ignore the RESPONSE_AVAILABLE notifications.
> + *
> + * REVISIT some RNDIS implementations seem to have curious issues still
> + * to be resolved.
> + */
> +struct rndis_msg_hdr {
> + __le32 msg_type; /* RNDIS_MSG_* */
> + __le32 msg_len;
> + // followed by data that varies between messages
> + __le32 request_id;
> + __le32 status;
> + // ... and more
> +} __attribute__ ((packed));
> +
> +/* MS-Windows uses this strange size, but RNDIS spec says 1024 minimum */
> +#define CONTROL_BUFFER_SIZE 1025
> +
> +/* RNDIS defines an (absurdly huge) 10 second control timeout,
> + * but ActiveSync seems to use a more usual 5 second timeout
> + * (which matches the USB 2.0 spec).
> + */
> +#define RNDIS_CONTROL_TIMEOUT_MS (5 * 1000)
> +
> +
> +#define ccpu2 __constant_cpu_to_le32
> +
> +#define RNDIS_MSG_COMPLETION ccpu2(0x80000000)
> +
> +/* codes for "msg_type" field of rndis messages;
> + * only the data channel uses packet messages (maybe batched);
> + * everything else goes on the control channel.
> + */
> +#define RNDIS_MSG_PACKET ccpu2(0x00000001) /* 1-N packets */
> +#define RNDIS_MSG_INIT ccpu2(0x00000002)
> +#define RNDIS_MSG_INIT_C (RNDIS_MSG_INIT|RNDIS_MSG_COMPLETION)
> +#define RNDIS_MSG_HALT ccpu2(0x00000003)
> +#define RNDIS_MSG_QUERY ccpu2(0x00000004)
> +#define RNDIS_MSG_QUERY_C (RNDIS_MSG_QUERY|RNDIS_MSG_COMPLETION)
> +#define RNDIS_MSG_SET ccpu2(0x00000005)
> +#define RNDIS_MSG_SET_C (RNDIS_MSG_SET|RNDIS_MSG_COMPLETION)
> +#define RNDIS_MSG_RESET ccpu2(0x00000006)
> +#define RNDIS_MSG_RESET_C (RNDIS_MSG_RESET|RNDIS_MSG_COMPLETION)
> +#define RNDIS_MSG_INDICATE ccpu2(0x00000007)
> +#define RNDIS_MSG_KEEPALIVE ccpu2(0x00000008)
> +#define RNDIS_MSG_KEEPALIVE_C (RNDIS_MSG_KEEPALIVE|RNDIS_MSG_COMPLETION)
> +
> +/* codes for "status" field of completion messages */
> +#define RNDIS_STATUS_SUCCESS ccpu2(0x00000000)
> +#define RNDIS_STATUS_FAILURE ccpu2(0xc0000001)
> +#define RNDIS_STATUS_INVALID_DATA ccpu2(0xc0010015)
> +#define RNDIS_STATUS_NOT_SUPPORTED ccpu2(0xc00000bb)
> +#define RNDIS_STATUS_MEDIA_CONNECT ccpu2(0x4001000b)
> +#define RNDIS_STATUS_MEDIA_DISCONNECT ccpu2(0x4001000c)
> +
> +
> +struct rndis_data_hdr {
> + __le32 msg_type; /* RNDIS_MSG_PACKET */
> + __le32 msg_len; // rndis_data_hdr + data_len + pad
> + __le32 data_offset; // 36 -- right after header
> + __le32 data_len; // ... real packet size
> +
> + __le32 oob_data_offset; // zero
> + __le32 oob_data_len; // zero
> + __le32 num_oob; // zero
> + __le32 packet_data_offset; // zero
> +
> + __le32 packet_data_len; // zero
> + __le32 vc_handle; // zero
> + __le32 reserved; // zero
> +} __attribute__ ((packed));
> +
> +struct rndis_init { /* OUT */
> + // header and:
> + __le32 msg_type; /* RNDIS_MSG_INIT */
> + __le32 msg_len; // 24
> + __le32 request_id;
> + __le32 major_version; // of rndis (1.0)
> + __le32 minor_version;
> + __le32 max_transfer_size;
> +} __attribute__ ((packed));
> +
> +struct rndis_init_c { /* IN */
> + // header and:
> + __le32 msg_type; /* RNDIS_MSG_INIT_C */
> + __le32 msg_len;
> + __le32 request_id;
> + __le32 status;
> + __le32 major_version; // of rndis (1.0)
> + __le32 minor_version;
> + __le32 device_flags;
> + __le32 medium; // zero == 802.3
> + __le32 max_packets_per_message;
> + __le32 max_transfer_size;
> + __le32 packet_alignment; // max 7; (1<<n) bytes
> + __le32 af_list_offset; // zero
> + __le32 af_list_size; // zero
> +} __attribute__ ((packed));
> +
> +struct rndis_halt { /* OUT (no reply) */
> + // header and:
> + __le32 msg_type; /* RNDIS_MSG_HALT */
> + __le32 msg_len;
> + __le32 request_id;
> +} __attribute__ ((packed));
> +
> +struct rndis_query { /* OUT */
> + // header and:
> + __le32 msg_type; /* RNDIS_MSG_QUERY */
> + __le32 msg_len;
> + __le32 request_id;
> + __le32 oid;
> + __le32 len;
> + __le32 offset;
> +/*?*/ __le32 handle; // zero
> +} __attribute__ ((packed));
> +
> +struct rndis_query_c { /* IN */
> + // header and:
> + __le32 msg_type; /* RNDIS_MSG_QUERY_C */
> + __le32 msg_len;
> + __le32 request_id;
> + __le32 status;
> + __le32 len;
> + __le32 offset;
> +} __attribute__ ((packed));
> +
> +struct rndis_set { /* OUT */
> + // header and:
> + __le32 msg_type; /* RNDIS_MSG_SET */
> + __le32 msg_len;
> + __le32 request_id;
> + __le32 oid;
> + __le32 len;
> + __le32 offset;
> +/*?*/ __le32 handle; // zero
> +} __attribute__ ((packed));
> +
> +struct rndis_set_c { /* IN */
> + // header and:
> + __le32 msg_type; /* RNDIS_MSG_SET_C */
> + __le32 msg_len;
> + __le32 request_id;
> + __le32 status;
> +} __attribute__ ((packed));
> +
> +struct rndis_reset { /* IN */
> + // header and:
> + __le32 msg_type; /* RNDIS_MSG_RESET */
> + __le32 msg_len;
> + __le32 reserved;
> +} __attribute__ ((packed));
> +
> +struct rndis_reset_c { /* OUT */
> + // header and:
> + __le32 msg_type; /* RNDIS_MSG_RESET_C */
> + __le32 msg_len;
> + __le32 status;
> + __le32 addressing_lost;
> +} __attribute__ ((packed));
> +
> +struct rndis_indicate { /* IN (unrequested) */
> + // header and:
> + __le32 msg_type; /* RNDIS_MSG_INDICATE */
> + __le32 msg_len;
> + __le32 status;
> + __le32 length;
> + __le32 offset;
> +/**/ __le32 diag_status;
> + __le32 error_offset;
> +/**/ __le32 message;
> +} __attribute__ ((packed));
> +
> +struct rndis_keepalive { /* OUT (optionally IN) */
> + // header and:
> + __le32 msg_type; /* RNDIS_MSG_KEEPALIVE */
> + __le32 msg_len;
> + __le32 request_id;
> +} __attribute__ ((packed));
> +
> +struct rndis_keepalive_c { /* IN (optionally OUT) */
> + // header and:
> + __le32 msg_type; /* RNDIS_MSG_KEEPALIVE_C */
> + __le32 msg_len;
> + __le32 request_id;
> + __le32 status;
> +} __attribute__ ((packed));
> +
> +/* NOTE: about 30 OIDs are "mandatory" for peripherals to support ... and
> + * there are gobs more that may optionally be supported. We'll avoid as much
> + * of that mess as possible.
> + */
> +#define OID_802_3_PERMANENT_ADDRESS ccpu2(0x01010101)
> +#define OID_GEN_MAXIMUM_FRAME_SIZE ccpu2(0x00010106)
> +#define OID_GEN_CURRENT_PACKET_FILTER ccpu2(0x0001010e)
> +
> +/* packet filter bits used by OID_GEN_CURRENT_PACKET_FILTER */
> +#define RNDIS_PACKET_TYPE_DIRECTED ccpu2(0x00000001)
> +#define RNDIS_PACKET_TYPE_MULTICAST ccpu2(0x00000002)
> +#define RNDIS_PACKET_TYPE_ALL_MULTICAST ccpu2(0x00000004)
> +#define RNDIS_PACKET_TYPE_BROADCAST ccpu2(0x00000008)
> +#define RNDIS_PACKET_TYPE_SOURCE_ROUTING ccpu2(0x00000010)
> +#define RNDIS_PACKET_TYPE_PROMISCUOUS ccpu2(0x00000020)
> +#define RNDIS_PACKET_TYPE_SMT ccpu2(0x00000040)
> +#define RNDIS_PACKET_TYPE_ALL_LOCAL ccpu2(0x00000080)
> +#define RNDIS_PACKET_TYPE_GROUP ccpu2(0x00001000)
> +#define RNDIS_PACKET_TYPE_ALL_FUNCTIONAL ccpu2(0x00002000)
> +#define RNDIS_PACKET_TYPE_FUNCTIONAL ccpu2(0x00004000)
> +#define RNDIS_PACKET_TYPE_MAC_FRAME ccpu2(0x00008000)
> +
> +/* default filter used with RNDIS devices */
> +#define RNDIS_DEFAULT_FILTER ( \
> + RNDIS_PACKET_TYPE_DIRECTED | \
> + RNDIS_PACKET_TYPE_BROADCAST | \
> + RNDIS_PACKET_TYPE_ALL_MULTICAST | \
> + RNDIS_PACKET_TYPE_PROMISCUOUS)
> +
> +#endif /* __RNDIS_HOST_H */
> +
>
^ permalink raw reply
* Re: [PATCH 08/14] [rndis_host] export functions
From: David Brownell @ 2008-01-25 0:59 UTC (permalink / raw)
To: Jussi Kivilinna; +Cc: linux-wireless, bjd, netdev
In-Reply-To: <20080120001427.25718.45322.stgit@fate.lan>
On Saturday 19 January 2008, Jussi Kivilinna wrote:
> Export rndis_host functions and also rename rndis_bind() to
> generic_rndis_bind() for modules using rndis_host as base.
>
> Signed-off-by: Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
Acked-by: David Brownell <dbrownell@users.sourceforge.net>
> ---
>
> drivers/net/usb/rndis_host.c | 20 +++++++++++++-------
> drivers/net/usb/rndis_host.h | 9 +++++++++
> 2 files changed, 22 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c
> index 29d7e3b..1d6bf0a 100644
> --- a/drivers/net/usb/rndis_host.c
> +++ b/drivers/net/usb/rndis_host.c
> @@ -60,13 +60,14 @@
> * RNDIS notifications from device: command completion; "reverse"
> * keepalives; etc
> */
> -static void rndis_status(struct usbnet *dev, struct urb *urb)
> +void rndis_status(struct usbnet *dev, struct urb *urb)
> {
> devdbg(dev, "rndis status urb, len %d stat %d",
> urb->actual_length, urb->status);
> // FIXME for keepalives, respond immediately (asynchronously)
> // if not an RNDIS status, do like cdc_status(dev,urb) does
> }
> +EXPORT_SYMBOL_GPL(rndis_status);
>
> /*
> * RPC done RNDIS-style. Caller guarantees:
> @@ -78,7 +79,7 @@ static void rndis_status(struct usbnet *dev, struct urb *urb)
> * Call context is likely probe(), before interface name is known,
> * which is why we won't try to use it in the diagnostics.
> */
> -static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
> +int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
> {
> struct cdc_state *info = (void *) &dev->data;
> int master_ifnum;
> @@ -187,6 +188,7 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
> dev_dbg(&info->control->dev, "rndis response timeout\n");
> return -ETIMEDOUT;
> }
> +EXPORT_SYMBOL_GPL(rndis_command);
>
> /*
> * rndis_query:
> @@ -253,7 +255,7 @@ response_error:
> return -EDOM;
> }
>
> -static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
> +int generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf)
> {
> int retval;
> struct net_device *net = dev->net;
> @@ -377,8 +379,9 @@ fail:
> kfree(u.buf);
> return retval;
> }
> +EXPORT_SYMBOL_GPL(generic_rndis_bind);
>
> -static void rndis_unbind(struct usbnet *dev, struct usb_interface *intf)
> +void rndis_unbind(struct usbnet *dev, struct usb_interface *intf)
> {
> struct rndis_halt *halt;
>
> @@ -393,11 +396,12 @@ static void rndis_unbind(struct usbnet *dev, struct usb_interface *intf)
>
> usbnet_cdc_unbind(dev, intf);
> }
> +EXPORT_SYMBOL_GPL(rndis_unbind);
>
> /*
> * DATA -- host must not write zlps
> */
> -static int rndis_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
> +int rndis_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
> {
> /* peripheral may have batched packets to us... */
> while (likely(skb->len)) {
> @@ -439,8 +443,9 @@ static int rndis_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
> /* caller will usbnet_skb_return the remaining packet */
> return 1;
> }
> +EXPORT_SYMBOL_GPL(rndis_rx_fixup);
>
> -static struct sk_buff *
> +struct sk_buff *
> rndis_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
> {
> struct rndis_data_hdr *hdr;
> @@ -485,12 +490,13 @@ fill:
> /* FIXME make the last packet always be short ... */
> return skb;
> }
> +EXPORT_SYMBOL_GPL(rndis_tx_fixup);
>
>
> static const struct driver_info rndis_info = {
> .description = "RNDIS device",
> .flags = FLAG_ETHER | FLAG_FRAMING_RN | FLAG_NO_SETINT,
> - .bind = rndis_bind,
> + .bind = generic_rndis_bind,
> .unbind = rndis_unbind,
> .status = rndis_status,
> .rx_fixup = rndis_rx_fixup,
> diff --git a/drivers/net/usb/rndis_host.h b/drivers/net/usb/rndis_host.h
> index 1386a17..61f1fd8 100644
> --- a/drivers/net/usb/rndis_host.h
> +++ b/drivers/net/usb/rndis_host.h
> @@ -244,5 +244,14 @@ struct rndis_keepalive_c { /* IN (optionally OUT) */
> RNDIS_PACKET_TYPE_ALL_MULTICAST | \
> RNDIS_PACKET_TYPE_PROMISCUOUS)
>
> +
> +extern void rndis_status(struct usbnet *dev, struct urb *urb);
> +extern int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf);
> +extern int generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf);
> +extern void rndis_unbind(struct usbnet *dev, struct usb_interface *intf);
> +extern int rndis_rx_fixup(struct usbnet *dev, struct sk_buff *skb);
> +extern struct sk_buff *
> +rndis_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags);
> +
> #endif /* __RNDIS_HOST_H */
>
>
^ permalink raw reply
* Re: [PATCH 00/14] RFC: Driver for Wireless RNDIS USB devices.
From: David Brownell @ 2008-01-25 1:19 UTC (permalink / raw)
To: Jussi Kivilinna; +Cc: linux-wireless, bjd, netdev
In-Reply-To: <20080120001342.25718.83669.stgit@fate.lan>
On Saturday 19 January 2008, Jussi Kivilinna wrote:
> Hello,
>
> This is second try on wireless RNDIS patchset started by Bjorge Dijkstra. Since
> Bjorge has disappeared, I claim maintainership of rndis_wext and this patchset
> until he returns.
>
> This patchset adds support for various 802.11 USB devices based on Broadcom
> 4320 chip. Chip uses RNDIS to communicate with the host, so module depend
> heavily on rndis_host/cdc_ether/usbnet and needs some changes on these
> modules in order to work.
>
> Patches 1-6 are from first patchset:
> 1. Fix sparse warning: returning void valued expression
> 2. [cdc_ether] Hardwire CDC descriptors when missing
> 3. [rndis_host] Use 1KB buffer in rndis_unbind
> 4. [rndis_host] Halt device if rndis_bind fails
> 5. [rndis_host] Fix rndis packet filter flags
> 6. [usbnet] Use wlan device name for RNDIS wireless devices
>
> Of these 1, 3 and 4 are not required for this version of rndis_wext to work.
>
> Actual wireless part is changed from extension on rndis_host to separate
> driver. Different devices are detected by device specific USB vendor/product
> IDs as the way done with Windows drivers instead of detecting RNDIS media type
> like in first patchset.
>
> New patches 7-14:
> 7. [rndis_host] Split up rndis_host.c
> 8. [rndis_host] export functions
> 9. [usbnet] add driver_priv pointer to 'struct usbnet'
So far as I'm concerned patches 1-9 can go in any time.
The other patches I won't ack yet; see below.
> 10. [rndis_host] Add rndis_early_init function pointer to 'struct rndis_data'.
> 11. [rndis_host] Add rndis_link_change function pointer to 'struct rndis_data'.
Those aren't added to "struct rndis_data" ... they're added to
the struct at the core of the usbnet framework. So they should
not be RNDIS-specific ... even though the only current user will
be the RNDIS host code. Rename those methods and I'll be happy.
> 12. Move usbnet.h and rndis_host.h to include/linux/usb
No problem with that, except that fixing #10 and #11 will
break them.
> 13. [rndis_host] blacklist known wireless RNDIS devices
That will be a headache over time though ... can't you just
let the probe succeed enough to recogize it's wireless (using
the media flag) and then bail, so the next driver can try?
> 14. Add new driver 'rndis_wext' for wireless RNDIS devices.
The real goods! :)
> Patches should be applied in order, series apply cleanly to 2.6.24-rc8.
>
> - Jussi Kivilinna
>
^ permalink raw reply
* Re: 2.6.24-rc8-mm1 : net tcp_input.c warnings
From: Dave Young @ 2008-01-25 1:30 UTC (permalink / raw)
To: Ilpo Järvinen
Cc: Kamalesh Babulal, Krishna Kumar2, Denys Fedoryshchenko,
David Miller, LKML, Netdev, Andrew Morton
In-Reply-To: <Pine.LNX.4.64.0801241108400.31652@kivilampi-30.cs.helsinki.fi>
On Jan 24, 2008 5:54 PM, Ilpo Järvinen <ilpo.jarvinen@helsinki.fi> wrote:
> On Thu, 24 Jan 2008, Dave Young wrote:
>
> Hi Dave (& others),
>
> > Thanks.
>
> Thanks a lot, I was first to ignore all these because they occurred
> with newreno, but looked again... :-/
>
> > New warning trigged with your debug patch:
>
> This was probably with the earlier one I sent to you because there's still
> this case remaining which itself is valid:
>
> > P: 5 L: 0 vs 0 S: 0 vs 1 w: 2044790889-2044796616 (0)
>
> ...snip... this is still ok state (S+L <= P):
>
>
> > P: 5 L: 0 vs 0 S: 0 vs 3 w: 2044790889-2044796616 (0)
> > TCP wq(s) <
> > TCP wq(h) +++h+<
> > l0 s3 f0 p5 seq: su2044790889 hs2044795029 sn2044796616
> > ------------[ cut here ]------------
> > WARNING: at net/ipv4/tcp_input.c:2169 tcp_mark_head_lost+0x122/0x150()
> > Modules linked in: snd_seq_dummy snd_seq_oss snd_seq_midi_event
> > snd_seq snd_seq_device snd_pcm_oss snd_mixer_oss eeprom e100 psmouse
> > snd_hda_intel snd_pcm snd_timer btusb bluetooth serio_raw snd 3c59x sg
> > evdev thermal soundcore rtc_cmos snd_page_alloc rtc_core rtc_lib
> > i2c_i801 processor button intel_agp dcdbas pcspkr agpgart
> > Pid: 0, comm: swapper Not tainted 2.6.24-rc8-mm1 #8
> > [<c0132100>] ? have_callable_console+0x20/0x30
> > [<c0131844>] warn_on_slowpath+0x54/0x80
> > [<c03ffe54>] ? tcp_print_queue+0x1a4/0x230
> > [<c0132438>] ? vprintk+0x308/0x320
> > [<c0132438>] ? vprintk+0x308/0x320
> > [<c0132438>] ? vprintk+0x308/0x320
> > [<c03ffff6>] ? tcp_verify_wq+0x116/0x1c0
> > [<c03f6052>] tcp_mark_head_lost+0x122/0x150
> > [<c03f60ca>] tcp_update_scoreboard+0x4a/0x190
> > [<c03f6e7a>] tcp_fastretrans_alert+0x4da/0x700
> > [<c03f7e63>] tcp_ack+0x1b3/0x3a0
> > [<c03fa21b>] tcp_rcv_established+0x3eb/0x710
> > [<c0401c05>] tcp_v4_do_rcv+0xe5/0x100
> > [<c04021fb>] tcp_v4_rcv+0x5db/0x660
> > [<c0401fa7>] ? tcp_v4_rcv+0x387/0x660
> > [<c03e5eed>] ? ip_local_deliver_finish+0x2d/0x1d0
> > [<c03e5f44>] ip_local_deliver_finish+0x84/0x1d0
> > [<c03e5eed>] ? ip_local_deliver_finish+0x2d/0x1d0
> > [<c0156b97>] ? __lock_release+0x47/0x70
> > [<c03e6147>] ip_local_deliver+0xb7/0xc0
> > [<c03e6202>] ip_rcv_finish+0xb2/0x3c0
> > [<c03c01d8>] ? sock_def_readable+0x48/0xa0
> > [<c03be061>] ? sock_queue_rcv_skb+0xb1/0x1a0
> > [<c03be0a7>] ? sock_queue_rcv_skb+0xf7/0x1a0
> > [<c03e669f>] ip_rcv+0x18f/0x290
> > [<c042fb10>] ? packet_rcv_spkt+0xd0/0x130
> > [<c03c8da6>] netif_receive_skb+0x2b6/0x330
> > [<c03c8c17>] ? netif_receive_skb+0x127/0x330
> > [<c03c8ea3>] ? process_backlog+0x83/0x100
> > [<c03c8eae>] process_backlog+0x8e/0x100
> > [<c03c90bc>] net_rx_action+0x13c/0x230
> > [<c03c8fd9>] ? net_rx_action+0x59/0x230
> > [<c0136f63>] __do_softirq+0x93/0x120
> > [<c013706a>] do_softirq+0x7a/0x80
> > [<c0137135>] irq_exit+0x65/0x90
> > [<c01078b1>] do_IRQ+0x41/0x80
> > [<c0155659>] ? trace_hardirqs_on+0xb9/0x130
> > [<c01059ca>] common_interrupt+0x2e/0x34
> > [<c0103390>] ? mwait_idle_with_hints+0x40/0x50
> > [<c01033a0>] ? mwait_idle+0x0/0x20
> > [<c01033b2>] mwait_idle+0x12/0x20
> > [<c0103141>] cpu_idle+0x61/0x110
> > [<c04339fd>] rest_init+0x5d/0x60
> > [<c05a47fa>] start_kernel+0x1fa/0x260
> > [<c05a4190>] ? unknown_bootoption+0x0/0x130
> > =======================
> > ---[ end trace 14b601818e6903ac ]---
> > ------------[ cut here ]------------
> > WARNING: at net/ipv4/tcp_ipv4.c:197 tcp_verify_wq+0x1b6/0x1c0()
> > Modules linked in: snd_seq_dummy snd_seq_oss snd_seq_midi_event
> > snd_seq snd_seq_device snd_pcm_oss snd_mixer_oss eeprom e100 psmouse
> > snd_hda_intel snd_pcm snd_timer btusb bluetooth serio_raw snd 3c59x sg
> > evdev thermal soundcore rtc_cmos snd_page_alloc rtc_core rtc_lib
> > i2c_i801 processor button intel_agp dcdbas pcspkr agpgart
> > Pid: 0, comm: swapper Not tainted 2.6.24-rc8-mm1 #8
> > [<c0132100>] ? have_callable_console+0x20/0x30
> > [<c0131844>] warn_on_slowpath+0x54/0x80
> > [<c01317da>] ? print_oops_end_marker+0x2a/0x30
> > [<c0131849>] ? warn_on_slowpath+0x59/0x80
> > [<c03ffe54>] ? tcp_print_queue+0x1a4/0x230
> > [<c0132438>] ? vprintk+0x308/0x320
> > [<c0132438>] ? vprintk+0x308/0x320
> > [<c0400096>] tcp_verify_wq+0x1b6/0x1c0
> > [<c03ffff6>] ? tcp_verify_wq+0x116/0x1c0
> > [<c03f5ffc>] tcp_mark_head_lost+0xcc/0x150
> > [<c03f60ca>] tcp_update_scoreboard+0x4a/0x190
> > [<c03f6e7a>] tcp_fastretrans_alert+0x4da/0x700
> > [<c03f7e63>] tcp_ack+0x1b3/0x3a0
> > [<c03fa21b>] tcp_rcv_established+0x3eb/0x710
> > [<c0401c05>] tcp_v4_do_rcv+0xe5/0x100
> > [<c04021fb>] tcp_v4_rcv+0x5db/0x660
> > [<c0401fa7>] ? tcp_v4_rcv+0x387/0x660
> > [<c03e5eed>] ? ip_local_deliver_finish+0x2d/0x1d0
> > [<c03e5f44>] ip_local_deliver_finish+0x84/0x1d0
> > [<c03e5eed>] ? ip_local_deliver_finish+0x2d/0x1d0
> > [<c0156b97>] ? __lock_release+0x47/0x70
> > [<c03e6147>] ip_local_deliver+0xb7/0xc0
> > [<c03e6202>] ip_rcv_finish+0xb2/0x3c0
> > [<c03c01d8>] ? sock_def_readable+0x48/0xa0
> > [<c03be061>] ? sock_queue_rcv_skb+0xb1/0x1a0
> > [<c03be0a7>] ? sock_queue_rcv_skb+0xf7/0x1a0
> > [<c03e669f>] ip_rcv+0x18f/0x290
> > [<c042fb10>] ? packet_rcv_spkt+0xd0/0x130
> > [<c03c8da6>] netif_receive_skb+0x2b6/0x330
> > [<c03c8c17>] ? netif_receive_skb+0x127/0x330
> > [<c03c8ea3>] ? process_backlog+0x83/0x100
> > [<c03c8eae>] process_backlog+0x8e/0x100
> > [<c03c90bc>] net_rx_action+0x13c/0x230
> > [<c03c8fd9>] ? net_rx_action+0x59/0x230
> > [<c0136f63>] __do_softirq+0x93/0x120
> > [<c013706a>] do_softirq+0x7a/0x80
> > [<c0137135>] irq_exit+0x65/0x90
> > [<c01078b1>] do_IRQ+0x41/0x80
> > [<c0155659>] ? trace_hardirqs_on+0xb9/0x130
> > [<c01059ca>] common_interrupt+0x2e/0x34
> > [<c0103390>] ? mwait_idle_with_hints+0x40/0x50
> > [<c01033a0>] ? mwait_idle+0x0/0x20
> > [<c01033b2>] mwait_idle+0x12/0x20
> > [<c0103141>] cpu_idle+0x61/0x110
> > [<c04339fd>] rest_init+0x5d/0x60
> > [<c05a47fa>] start_kernel+0x1fa/0x260
> > [<c05a4190>] ? unknown_bootoption+0x0/0x130
> > =======================
> > ---[ end trace 14b601818e6903ac ]---
>
> ...But this no longer is, and even more, L: 5 is not valid state at this
> point all (should only happen if we went to RTO but it would reset S to
> zero with newreno):
>
> > P: 5 L: 5 vs 5 S: 0 vs 3 w: 2044790889-2044796616 (0)
> > TCP wq(s) LLLLl<
> > TCP wq(h) +++h+<
> > l5 s3 f0 p5 seq: su2044790889 hs2044795029 sn2044796616
>
> Surprisingly, it was the first time the WARN_ON for left_out returned
> correct location. This also explains why the patch I sent to Krishna
> didn't print anything (it didn't end up into printing because I forgot
> to add L+S>P check into to the state checking if).
>
> ...so please, could you (others than Denys) try this patch, it should
> solve the issue. And Denys, could you confirm (and if necessary double
> check) that the kernel you saw this similar problem with is the pure
> Linus' mainline, i.e., without any net-2.6.25 or mm bits please, if so,
> that problem persists. And anyway, there were some fackets_out related
> problems reported as well and this doesn't help for that but I think I've
> lost track of who was seeing it due to large number of reports :-), could
> somebody refresh my memory because I currently don't have time to dig it
> up from archives (at least on this week).
Thanks, applied on my test kernel, if there's no warnings I will just mute.
>
>
> --
> i.
>
> --
> [PATCH] [TCP]: NewReno must count every skb while marking losses
>
> NewReno should add cnt per skb (as with FACK) instead of depending
> on SACKED_ACKED bits which won't be set with it at all.
> Effectively, NewReno should always exists after the first
> iteration anyway (or immediately if there's already head in
> lost_out.
>
> This was fixed earlier in net-2.6.25 but got reverted among other
> stuff and I didn't notice that this is still necessary (actually
> wasn't even considering this case while trying to figure out the
> reports because I lived with different kind of code than it in
> reality was).
>
> This should solve the WARN_ONs in TCP code that as a result of
> this triggered multiple times in every place we check for this
> invariant.
>
> Special thanks to Dave Young <hidave.darkstar@gmail.com> and
> Krishna Kumar2 <krkumar2@in.ibm.com> for trying with my debug
> patches.
>
> Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi>
> ---
> net/ipv4/tcp_input.c | 2 +-
> 1 files changed, 1 insertions(+), 1 deletions(-)
>
> diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
> index 295490e..aa409a5 100644
> --- a/net/ipv4/tcp_input.c
> +++ b/net/ipv4/tcp_input.c
> @@ -2156,7 +2156,7 @@ static void tcp_mark_head_lost(struct sock *sk, int packets, int fast_rexmit)
> tp->lost_skb_hint = skb;
> tp->lost_cnt_hint = cnt;
>
> - if (tcp_is_fack(tp) ||
> + if (tcp_is_fack(tp) || tcp_is_reno(tp) ||
> (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED))
> cnt += tcp_skb_pcount(skb);
>
> --
> 1.5.2.2
>
^ permalink raw reply
* Re: [PATCH v2] PS3: gelic: Add wireless support for PS3
From: Dan Williams @ 2008-01-25 1:49 UTC (permalink / raw)
To: Masakazu Mokuno
Cc: linux-wireless, netdev, geoffrey.levand, Geert Uytterhoeven
In-Reply-To: <20080124144253.6176.40F06B3A@sm.sony.co.jp>
On Thu, 2008-01-24 at 14:51 +0900, Masakazu Mokuno wrote:
> Hi
>
> PS3: gelic: Add wireless support for PS3
>
> This is the version 2 of the re-worked (rewritten) version of the
> wireless support driver for PS3. The version 1 of the new driver was
> submitted on 13th Dec. 2007 (and the old one was submitted to net-dev ML
> in June 2007).
>
> Major differences with the old driver are:
> - The new driver has a separate ethX interface from ethernet.
> They share the same MAC address.
> - Thus we can use both ethernet and wireless simultaenously.
> - The new driver returns AP's cipher information by the common IE
> format in the scan information.
> - Cipher selection is done via the common wireless extension way
Looks like all my issues have been addressed. Thanks! Lets get this in
2.6.25 :)
Acked-by: Dan Williams <dcbw@redhat.com>
> V2 changes:
> - Emit more null IWAP events at appropriate timings, as Dan Williams
> pointed out at the V1 submission.
> - Fix sparse warnings
> o make some functions as static
> o use NULL for pointer instead of 0
> - Remove extra space
>
> Signed-off-by: Masakazu Mokuno <mokuno@sm.sony.co.jp>
> ---
>
> drivers/net/Kconfig | 10
> drivers/net/Makefile | 3
> drivers/net/ps3_gelic_net.c | 18
> drivers/net/ps3_gelic_net.h | 6
> drivers/net/ps3_gelic_wireless.c | 2753 +++++++++++++++++++++++++++++++++++++++
> drivers/net/ps3_gelic_wireless.h | 329 ++++
> 6 files changed, 3117 insertions(+), 2 deletions(-)
>
> --- a/drivers/net/Kconfig
> +++ b/drivers/net/Kconfig
> @@ -2302,6 +2302,16 @@ config GELIC_NET
> To compile this driver as a module, choose M here: the
> module will be called ps3_gelic.
>
> +config GELIC_WIRELESS
> + bool "PS3 Wireless support"
> + depends on GELIC_NET
> + help
> + This option adds the support for the wireless feature of PS3.
> + If you have the wireless-less model of PS3 or have no plan to
> + use wireless feature, disabling this option saves memory. As
> + the driver automatically distinguishes the models, you can
> + safely enable this option even if you have a wireless-less model.
> +
> config GIANFAR
> tristate "Gianfar Ethernet"
> depends on 85xx || 83xx || PPC_86xx
> --- a/drivers/net/Makefile
> +++ b/drivers/net/Makefile
> @@ -66,7 +66,8 @@ obj-$(CONFIG_BNX2) += bnx2.o
> spidernet-y += spider_net.o spider_net_ethtool.o
> obj-$(CONFIG_SPIDER_NET) += spidernet.o sungem_phy.o
> obj-$(CONFIG_GELIC_NET) += ps3_gelic.o
> -ps3_gelic-objs += ps3_gelic_net.o
> +gelic_wireless-$(CONFIG_GELIC_WIRELESS) += ps3_gelic_wireless.o
> +ps3_gelic-objs += ps3_gelic_net.o $(gelic_wireless-y)
> obj-$(CONFIG_TC35815) += tc35815.o
> obj-$(CONFIG_SKGE) += skge.o
> obj-$(CONFIG_SKY2) += sky2.o
> --- a/drivers/net/ps3_gelic_net.c
> +++ b/drivers/net/ps3_gelic_net.c
> @@ -46,9 +46,10 @@
> #include <asm/lv1call.h>
>
> #include "ps3_gelic_net.h"
> +#include "ps3_gelic_wireless.h"
>
> #define DRV_NAME "Gelic Network Driver"
> -#define DRV_VERSION "1.1"
> +#define DRV_VERSION "2.0"
>
> MODULE_AUTHOR("SCE Inc.");
> MODULE_DESCRIPTION("Gelic Network driver");
> @@ -1154,6 +1155,12 @@ static irqreturn_t gelic_card_interrupt(
> if (status & GELIC_CARD_PORT_STATUS_CHANGED)
> gelic_card_get_ether_port_status(card, 1);
>
> +#ifdef CONFIG_GELIC_WIRELESS
> + if (status & (GELIC_CARD_WLAN_EVENT_RECEIVED |
> + GELIC_CARD_WLAN_COMMAND_COMPLETED))
> + gelic_wl_interrupt(card->netdev[GELIC_PORT_WIRELESS], status);
> +#endif
> +
> return IRQ_HANDLED;
> }
>
> @@ -1635,6 +1642,12 @@ static int ps3_gelic_driver_probe(struct
> goto fail_setup_netdev;
> }
>
> +#ifdef CONFIG_GELIC_WIRELESS
> + if (gelic_wl_driver_probe(card)) {
> + dev_dbg(&dev->core, "%s: WL init failed\n", __func__);
> + goto fail_setup_netdev;
> + }
> +#endif
> pr_debug("%s: done\n", __func__);
> return 0;
>
> @@ -1674,6 +1687,9 @@ static int ps3_gelic_driver_remove(struc
> struct net_device *netdev0;
> pr_debug("%s: called\n", __func__);
>
> +#ifdef CONFIG_GELIC_WIRELESS
> + gelic_wl_driver_remove(card);
> +#endif
> /* stop interrupt */
> gelic_card_set_irq_mask(card, 0);
>
> --- a/drivers/net/ps3_gelic_net.h
> +++ b/drivers/net/ps3_gelic_net.h
> @@ -57,6 +57,8 @@
> #define GELIC_CARD_RX_PROTECTION_ERR 0x0000000004000000L
> #define GELIC_CARD_TX_TCP_UDP_CHECKSUM_ERR 0x0000000008000000L
> #define GELIC_CARD_PORT_STATUS_CHANGED 0x0000000020000000L
> +#define GELIC_CARD_WLAN_EVENT_RECEIVED 0x0000000040000000L
> +#define GELIC_CARD_WLAN_COMMAND_COMPLETED 0x0000000080000000L
> /* INT 0 */
> #define GELIC_CARD_TX_FLAGGED_DESCR 0x0004000000000000L
> #define GELIC_CARD_RX_FLAGGED_DESCR 0x0040000000000000L
> @@ -180,6 +182,10 @@ enum gelic_lv1_net_control_code {
> GELIC_LV1_GET_ETH_PORT_STATUS = 2,
> GELIC_LV1_SET_NEGOTIATION_MODE = 3,
> GELIC_LV1_GET_VLAN_ID = 4,
> + GELIC_LV1_GET_CHANNEL = 6,
> + GELIC_LV1_POST_WLAN_CMD = 9,
> + GELIC_LV1_GET_WLAN_CMD_RESULT = 10,
> + GELIC_LV1_GET_WLAN_EVENT = 11
> };
>
> /* status returened from GET_ETH_PORT_STATUS */
> --- /dev/null
> +++ b/drivers/net/ps3_gelic_wireless.c
> @@ -0,0 +1,2753 @@
> +/*
> + * PS3 gelic network driver.
> + *
> + * Copyright (C) 2007 Sony Computer Entertainment Inc.
> + * Copyright 2007 Sony Corporation
> + *
> + * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +#undef DEBUG
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +
> +#include <linux/etherdevice.h>
> +#include <linux/ethtool.h>
> +#include <linux/if_vlan.h>
> +
> +#include <linux/in.h>
> +#include <linux/ip.h>
> +#include <linux/tcp.h>
> +#include <linux/wireless.h>
> +#include <linux/ctype.h>
> +#include <linux/string.h>
> +#include <net/iw_handler.h>
> +#include <net/ieee80211.h>
> +
> +#include <linux/dma-mapping.h>
> +#include <net/checksum.h>
> +#include <asm/firmware.h>
> +#include <asm/ps3.h>
> +#include <asm/lv1call.h>
> +
> +#include "ps3_gelic_net.h"
> +#include "ps3_gelic_wireless.h"
> +
> +
> +static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan);
> +static int gelic_wl_try_associate(struct net_device *netdev);
> +
> +/*
> + * tables
> + */
> +
> +/* 802.11b/g channel to freq in MHz */
> +static const int channel_freq[] = {
> + 2412, 2417, 2422, 2427, 2432,
> + 2437, 2442, 2447, 2452, 2457,
> + 2462, 2467, 2472, 2484
> +};
> +#define NUM_CHANNELS ARRAY_SIZE(channel_freq)
> +
> +/* in bps */
> +static const int bitrate_list[] = {
> + 1000000,
> + 2000000,
> + 5500000,
> + 11000000,
> + 6000000,
> + 9000000,
> + 12000000,
> + 18000000,
> + 24000000,
> + 36000000,
> + 48000000,
> + 54000000
> +};
> +#define NUM_BITRATES ARRAY_SIZE(bitrate_list)
> +
> +/*
> + * wpa2 support requires the hypervisor version 2.0 or later
> + */
> +static inline int wpa2_capable(void)
> +{
> + return (0 <= ps3_compare_firmware_version(2, 0, 0));
> +}
> +
> +static inline int precise_ie(void)
> +{
> + return 0; /* FIXME */
> +}
> +/*
> + * post_eurus_cmd helpers
> + */
> +struct eurus_cmd_arg_info {
> + int pre_arg; /* command requres arg1, arg2 at POST COMMAND */
> + int post_arg; /* command requires arg1, arg2 at GET_RESULT */
> +};
> +
> +static const struct eurus_cmd_arg_info cmd_info[GELIC_EURUS_CMD_MAX_INDEX] = {
> + [GELIC_EURUS_CMD_SET_COMMON_CFG] = { .pre_arg = 1},
> + [GELIC_EURUS_CMD_SET_WEP_CFG] = { .pre_arg = 1},
> + [GELIC_EURUS_CMD_SET_WPA_CFG] = { .pre_arg = 1},
> + [GELIC_EURUS_CMD_GET_COMMON_CFG] = { .post_arg = 1},
> + [GELIC_EURUS_CMD_GET_WEP_CFG] = { .post_arg = 1},
> + [GELIC_EURUS_CMD_GET_WPA_CFG] = { .post_arg = 1},
> + [GELIC_EURUS_CMD_GET_RSSI_CFG] = { .post_arg = 1},
> + [GELIC_EURUS_CMD_GET_SCAN] = { .post_arg = 1},
> +};
> +
> +#ifdef DEBUG
> +static const char *cmdstr(enum gelic_eurus_command ix)
> +{
> + switch (ix) {
> + case GELIC_EURUS_CMD_ASSOC:
> + return "ASSOC";
> + case GELIC_EURUS_CMD_DISASSOC:
> + return "DISASSOC";
> + case GELIC_EURUS_CMD_START_SCAN:
> + return "SCAN";
> + case GELIC_EURUS_CMD_GET_SCAN:
> + return "GET SCAN";
> + case GELIC_EURUS_CMD_SET_COMMON_CFG:
> + return "SET_COMMON_CFG";
> + case GELIC_EURUS_CMD_GET_COMMON_CFG:
> + return "GET_COMMON_CFG";
> + case GELIC_EURUS_CMD_SET_WEP_CFG:
> + return "SET_WEP_CFG";
> + case GELIC_EURUS_CMD_GET_WEP_CFG:
> + return "GET_WEP_CFG";
> + case GELIC_EURUS_CMD_SET_WPA_CFG:
> + return "SET_WPA_CFG";
> + case GELIC_EURUS_CMD_GET_WPA_CFG:
> + return "GET_WPA_CFG";
> + case GELIC_EURUS_CMD_GET_RSSI_CFG:
> + return "GET_RSSI";
> + default:
> + break;
> + }
> + return "";
> +};
> +#else
> +static inline const char *cmdstr(enum gelic_eurus_command ix)
> +{
> + return "";
> +}
> +#endif
> +
> +/* synchronously do eurus commands */
> +static void gelic_eurus_sync_cmd_worker(struct work_struct *work)
> +{
> + struct gelic_eurus_cmd *cmd;
> + struct gelic_card *card;
> + struct gelic_wl_info *wl;
> +
> + u64 arg1, arg2;
> +
> + pr_debug("%s: <-\n", __func__);
> + cmd = container_of(work, struct gelic_eurus_cmd, work);
> + BUG_ON(cmd_info[cmd->cmd].pre_arg &&
> + cmd_info[cmd->cmd].post_arg);
> + wl = cmd->wl;
> + card = port_to_card(wl_port(wl));
> +
> + if (cmd_info[cmd->cmd].pre_arg) {
> + arg1 = ps3_mm_phys_to_lpar(__pa(cmd->buffer));
> + arg2 = cmd->buf_size;
> + } else {
> + arg1 = 0;
> + arg2 = 0;
> + }
> + init_completion(&wl->cmd_done_intr);
> + pr_debug("%s: cmd='%s' start\n", __func__, cmdstr(cmd->cmd));
> + cmd->status = lv1_net_control(bus_id(card), dev_id(card),
> + GELIC_LV1_POST_WLAN_CMD,
> + cmd->cmd, arg1, arg2,
> + &cmd->tag, &cmd->size);
> + if (cmd->status) {
> + complete(&cmd->done);
> + pr_info("%s: cmd issue failed\n", __func__);
> + return;
> + }
> +
> + wait_for_completion(&wl->cmd_done_intr);
> +
> + if (cmd_info[cmd->cmd].post_arg) {
> + arg1 = ps3_mm_phys_to_lpar(__pa(cmd->buffer));
> + arg2 = cmd->buf_size;
> + } else {
> + arg1 = 0;
> + arg2 = 0;
> + }
> +
> + cmd->status = lv1_net_control(bus_id(card), dev_id(card),
> + GELIC_LV1_GET_WLAN_CMD_RESULT,
> + cmd->tag, arg1, arg2,
> + &cmd->cmd_status, &cmd->size);
> +#ifdef DEBUG
> + if (cmd->status || cmd->cmd_status) {
> + pr_debug("%s: cmd done tag=%#lx arg1=%#lx, arg2=%#lx\n", __func__,
> + cmd->tag, arg1, arg2);
> + pr_debug("%s: cmd done status=%#x cmd_status=%#lx size=%#lx\n",
> + __func__, cmd->status, cmd->cmd_status, cmd->size);
> + }
> +#endif
> + complete(&cmd->done);
> + pr_debug("%s: cmd='%s' done\n", __func__, cmdstr(cmd->cmd));
> +}
> +
> +static struct gelic_eurus_cmd *gelic_eurus_sync_cmd(struct gelic_wl_info *wl,
> + unsigned int eurus_cmd,
> + void *buffer,
> + unsigned int buf_size)
> +{
> + struct gelic_eurus_cmd *cmd;
> +
> + /* allocate cmd */
> + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
> + if (!cmd)
> + return NULL;
> +
> + /* initialize members */
> + cmd->cmd = eurus_cmd;
> + cmd->buffer = buffer;
> + cmd->buf_size = buf_size;
> + cmd->wl = wl;
> + INIT_WORK(&cmd->work, gelic_eurus_sync_cmd_worker);
> + init_completion(&cmd->done);
> + queue_work(wl->eurus_cmd_queue, &cmd->work);
> +
> + /* wait for command completion */
> + wait_for_completion(&cmd->done);
> +
> + return cmd;
> +}
> +
> +static u32 gelic_wl_get_link(struct net_device *netdev)
> +{
> + struct gelic_wl_info *wl = port_wl(netdev_port(netdev));
> + u32 ret;
> +
> + pr_debug("%s: <-\n", __func__);
> + down(&wl->assoc_stat_lock);
> + if (wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED)
> + ret = 1;
> + else
> + ret = 0;
> + up(&wl->assoc_stat_lock);
> + pr_debug("%s: ->\n", __func__);
> + return ret;
> +}
> +
> +static void gelic_wl_send_iwap_event(struct gelic_wl_info *wl, u8 *bssid)
> +{
> + union iwreq_data data;
> +
> + memset(&data, 0, sizeof(data));
> + if (bssid)
> + memcpy(data.ap_addr.sa_data, bssid, ETH_ALEN);
> + data.ap_addr.sa_family = ARPHRD_ETHER;
> + wireless_send_event(port_to_netdev(wl_port(wl)), SIOCGIWAP,
> + &data, NULL);
> +}
> +
> +/*
> + * wireless extension handlers and helpers
> + */
> +
> +/* SIOGIWNAME */
> +static int gelic_wl_get_name(struct net_device *dev,
> + struct iw_request_info *info,
> + union iwreq_data *iwreq, char *extra)
> +{
> + strcpy(iwreq->name, "IEEE 802.11bg");
> + return 0;
> +}
> +
> +static void gelic_wl_get_ch_info(struct gelic_wl_info *wl)
> +{
> + struct gelic_card *card = port_to_card(wl_port(wl));
> + u64 ch_info_raw, tmp;
> + int status;
> +
> + if (!test_and_set_bit(GELIC_WL_STAT_CH_INFO, &wl->stat)) {
> + status = lv1_net_control(bus_id(card), dev_id(card),
> + GELIC_LV1_GET_CHANNEL, 0, 0, 0,
> + &ch_info_raw,
> + &tmp);
> + /* some fw versions may return error */
> + if (status) {
> + if (status != LV1_NO_ENTRY)
> + pr_info("%s: available ch unknown\n", __func__);
> + wl->ch_info = 0x07ff;/* 11 ch */
> + } else
> + /* 16 bits of MSB has available channels */
> + wl->ch_info = ch_info_raw >> 48;
> + }
> + return;
> +}
> +
> +/* SIOGIWRANGE */
> +static int gelic_wl_get_range(struct net_device *netdev,
> + struct iw_request_info *info,
> + union iwreq_data *iwreq, char *extra)
> +{
> + struct iw_point *point = &iwreq->data;
> + struct iw_range *range = (struct iw_range *)extra;
> + struct gelic_wl_info *wl = port_wl(netdev_port(netdev));
> + unsigned int i, chs;
> +
> + pr_debug("%s: <-\n", __func__);
> + point->length = sizeof(struct iw_range);
> + memset(range, 0, sizeof(struct iw_range));
> +
> + range->we_version_compiled = WIRELESS_EXT;
> + range->we_version_source = 22;
> +
> + /* available channels and frequencies */
> + gelic_wl_get_ch_info(wl);
> +
> + for (i = 0, chs = 0;
> + i < NUM_CHANNELS && chs < IW_MAX_FREQUENCIES; i++)
> + if (wl->ch_info & (1 << i)) {
> + range->freq[chs].i = i + 1;
> + range->freq[chs].m = channel_freq[i];
> + range->freq[chs].e = 6;
> + chs++;
> + }
> + range->num_frequency = chs;
> + range->old_num_frequency = chs;
> + range->num_channels = chs;
> + range->old_num_channels = chs;
> +
> + /* bitrates */
> + for (i = 0; i < NUM_BITRATES; i++)
> + range->bitrate[i] = bitrate_list[i];
> + range->num_bitrates = i;
> +
> + /* signal levels */
> + range->max_qual.qual = 100; /* relative value */
> + range->max_qual.level = 100;
> + range->avg_qual.qual = 50;
> + range->avg_qual.level = 50;
> + range->sensitivity = 0;
> +
> + /* Event capability */
> + IW_EVENT_CAPA_SET_KERNEL(range->event_capa);
> + IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
> + IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
> +
> + /* encryption capability */
> + range->enc_capa = IW_ENC_CAPA_WPA |
> + IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
> + if (wpa2_capable())
> + range->enc_capa |= IW_ENC_CAPA_WPA2;
> + range->encoding_size[0] = 5; /* 40bit WEP */
> + range->encoding_size[1] = 13; /* 104bit WEP */
> + range->encoding_size[2] = 32; /* WPA-PSK */
> + range->num_encoding_sizes = 3;
> + range->max_encoding_tokens = GELIC_WEP_KEYS;
> +
> + pr_debug("%s: ->\n", __func__);
> + return 0;
> +
> +}
> +
> +/* SIOC{G,S}IWSCAN */
> +static int gelic_wl_set_scan(struct net_device *netdev,
> + struct iw_request_info *info,
> + union iwreq_data *wrqu, char *extra)
> +{
> + struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
> +
> + return gelic_wl_start_scan(wl, 1);
> +}
> +
> +#define OUI_LEN 3
> +static const u8 rsn_oui[OUI_LEN] = { 0x00, 0x0f, 0xac };
> +static const u8 wpa_oui[OUI_LEN] = { 0x00, 0x50, 0xf2 };
> +
> +/*
> + * synthesize WPA/RSN IE data
> + * See WiFi WPA specification and IEEE 802.11-2007 7.3.2.25
> + * for the format
> + */
> +static size_t gelic_wl_synthesize_ie(u8 *buf,
> + struct gelic_eurus_scan_info *scan)
> +{
> +
> + const u8 *oui_header;
> + u8 *start = buf;
> + int rsn;
> + int ccmp;
> +
> + pr_debug("%s: <- sec=%16x\n", __func__, scan->security);
> + switch (be16_to_cpu(scan->security) & GELIC_EURUS_SCAN_SEC_MASK) {
> + case GELIC_EURUS_SCAN_SEC_WPA:
> + rsn = 0;
> + break;
> + case GELIC_EURUS_SCAN_SEC_WPA2:
> + rsn = 1;
> + break;
> + default:
> + /* WEP or none. No IE returned */
> + return 0;
> + }
> +
> + switch (be16_to_cpu(scan->security) & GELIC_EURUS_SCAN_SEC_WPA_MASK) {
> + case GELIC_EURUS_SCAN_SEC_WPA_TKIP:
> + ccmp = 0;
> + break;
> + case GELIC_EURUS_SCAN_SEC_WPA_AES:
> + ccmp = 1;
> + break;
> + default:
> + if (rsn) {
> + ccmp = 1;
> + pr_info("%s: no cipher info. defaulted to CCMP\n",
> + __func__);
> + } else {
> + ccmp = 0;
> + pr_info("%s: no cipher info. defaulted to TKIP\n",
> + __func__);
> + }
> + }
> +
> + if (rsn)
> + oui_header = rsn_oui;
> + else
> + oui_header = wpa_oui;
> +
> + /* element id */
> + if (rsn)
> + *buf++ = MFIE_TYPE_RSN;
> + else
> + *buf++ = MFIE_TYPE_GENERIC;
> +
> + /* length filed; set later */
> + buf++;
> +
> + /* wpa special header */
> + if (!rsn) {
> + memcpy(buf, wpa_oui, OUI_LEN);
> + buf += OUI_LEN;
> + *buf++ = 0x01;
> + }
> +
> + /* version */
> + *buf++ = 0x01; /* version 1.0 */
> + *buf++ = 0x00;
> +
> + /* group cipher */
> + memcpy(buf, oui_header, OUI_LEN);
> + buf += OUI_LEN;
> +
> + if (ccmp)
> + *buf++ = 0x04; /* CCMP */
> + else
> + *buf++ = 0x02; /* TKIP */
> +
> + /* pairwise key count always 1 */
> + *buf++ = 0x01;
> + *buf++ = 0x00;
> +
> + /* pairwise key suit */
> + memcpy(buf, oui_header, OUI_LEN);
> + buf += OUI_LEN;
> + if (ccmp)
> + *buf++ = 0x04; /* CCMP */
> + else
> + *buf++ = 0x02; /* TKIP */
> +
> + /* AKM count is 1 */
> + *buf++ = 0x01;
> + *buf++ = 0x00;
> +
> + /* AKM suite is assumed as PSK*/
> + memcpy(buf, oui_header, OUI_LEN);
> + buf += OUI_LEN;
> + *buf++ = 0x02; /* PSK */
> +
> + /* RSN capabilities is 0 */
> + *buf++ = 0x00;
> + *buf++ = 0x00;
> +
> + /* set length field */
> + start[1] = (buf - start - 2);
> +
> + pr_debug("%s: ->\n", __func__);
> + return (buf - start);
> +}
> +
> +struct ie_item {
> + u8 *data;
> + u8 len;
> +};
> +
> +struct ie_info {
> + struct ie_item wpa;
> + struct ie_item rsn;
> +};
> +
> +static void gelic_wl_parse_ie(u8 *data, size_t len,
> + struct ie_info *ie_info)
> +{
> + size_t data_left = len;
> + u8 *pos = data;
> + u8 item_len;
> + u8 item_id;
> +
> + pr_debug("%s: data=%p len=%ld \n", __func__,
> + data, len);
> + memset(ie_info, 0, sizeof(struct ie_info));
> +
> + while (0 < data_left) {
> + item_id = *pos++;
> + item_len = *pos++;
> +
> + switch (item_id) {
> + case MFIE_TYPE_GENERIC:
> + if (!memcmp(pos, wpa_oui, OUI_LEN) &&
> + pos[OUI_LEN] == 0x01) {
> + ie_info->wpa.data = pos - 2;
> + ie_info->wpa.len = item_len + 2;
> + }
> + break;
> + case MFIE_TYPE_RSN:
> + ie_info->rsn.data = pos - 2;
> + /* length includes the header */
> + ie_info->rsn.len = item_len + 2;
> + break;
> + default:
> + pr_debug("%s: ignore %#x,%d\n", __func__,
> + item_id, item_len);
> + break;
> + }
> + pos += item_len;
> + data_left -= item_len + 2;
> + }
> + pr_debug("%s: wpa=%p,%d wpa2=%p,%d\n", __func__,
> + ie_info->wpa.data, ie_info->wpa.len,
> + ie_info->rsn.data, ie_info->rsn.len);
> +}
> +
> +
> +/*
> + * translate the scan informations from hypervisor to a
> + * independent format
> + */
> +static char *gelic_wl_translate_scan(struct net_device *netdev,
> + char *ev,
> + char *stop,
> + struct gelic_wl_scan_info *network)
> +{
> + struct iw_event iwe;
> + struct gelic_eurus_scan_info *scan = network->hwinfo;
> + char *tmp;
> + u8 rate;
> + unsigned int i, j, len;
> + u8 buf[MAX_WPA_IE_LEN];
> +
> + pr_debug("%s: <-\n", __func__);
> +
> + /* first entry should be AP's mac address */
> + iwe.cmd = SIOCGIWAP;
> + iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
> + memcpy(iwe.u.ap_addr.sa_data, &scan->bssid[2], ETH_ALEN);
> + ev = iwe_stream_add_event(ev, stop, &iwe, IW_EV_ADDR_LEN);
> +
> + /* ESSID */
> + iwe.cmd = SIOCGIWESSID;
> + iwe.u.data.flags = 1;
> + iwe.u.data.length = strnlen(scan->essid, 32);
> + ev = iwe_stream_add_point(ev, stop, &iwe, scan->essid);
> +
> + /* FREQUENCY */
> + iwe.cmd = SIOCGIWFREQ;
> + iwe.u.freq.m = be16_to_cpu(scan->channel);
> + iwe.u.freq.e = 0; /* table value in MHz */
> + iwe.u.freq.i = 0;
> + ev = iwe_stream_add_event(ev, stop, &iwe, IW_EV_FREQ_LEN);
> +
> + /* RATES */
> + iwe.cmd = SIOCGIWRATE;
> + iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
> + /* to stuff multiple values in one event */
> + tmp = ev + IW_EV_LCP_LEN;
> + /* put them in ascendant order (older is first) */
> + i = 0;
> + j = 0;
> + pr_debug("%s: rates=%d rate=%d\n", __func__,
> + network->rate_len, network->rate_ext_len);
> + while (i < network->rate_len) {
> + if (j < network->rate_ext_len &&
> + ((scan->ext_rate[j] & 0x7f) < (scan->rate[i] & 0x7f)))
> + rate = scan->ext_rate[j++] & 0x7f;
> + else
> + rate = scan->rate[i++] & 0x7f;
> + iwe.u.bitrate.value = rate * 500000; /* 500kbps unit */
> + tmp = iwe_stream_add_value(ev, tmp, stop, &iwe,
> + IW_EV_PARAM_LEN);
> + }
> + while (j < network->rate_ext_len) {
> + iwe.u.bitrate.value = (scan->ext_rate[j++] & 0x7f) * 500000;
> + tmp = iwe_stream_add_value(ev, tmp, stop, &iwe,
> + IW_EV_PARAM_LEN);
> + }
> + /* Check if we added any rate */
> + if (IW_EV_LCP_LEN < (tmp - ev))
> + ev = tmp;
> +
> + /* ENCODE */
> + iwe.cmd = SIOCGIWENCODE;
> + if (be16_to_cpu(scan->capability) & WLAN_CAPABILITY_PRIVACY)
> + iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
> + else
> + iwe.u.data.flags = IW_ENCODE_DISABLED;
> + iwe.u.data.length = 0;
> + ev = iwe_stream_add_point(ev, stop, &iwe, scan->essid);
> +
> + /* MODE */
> + iwe.cmd = SIOCGIWMODE;
> + if (be16_to_cpu(scan->capability) &
> + (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
> + if (be16_to_cpu(scan->capability) & WLAN_CAPABILITY_ESS)
> + iwe.u.mode = IW_MODE_MASTER;
> + else
> + iwe.u.mode = IW_MODE_ADHOC;
> + ev = iwe_stream_add_event(ev, stop, &iwe, IW_EV_UINT_LEN);
> + }
> +
> + /* QUAL */
> + iwe.cmd = IWEVQUAL;
> + iwe.u.qual.updated = IW_QUAL_ALL_UPDATED |
> + IW_QUAL_QUAL_INVALID | IW_QUAL_NOISE_INVALID;
> + iwe.u.qual.level = be16_to_cpu(scan->rssi);
> + iwe.u.qual.qual = be16_to_cpu(scan->rssi);
> + iwe.u.qual.noise = 0;
> + ev = iwe_stream_add_event(ev, stop, &iwe, IW_EV_QUAL_LEN);
> +
> + /* RSN */
> + memset(&iwe, 0, sizeof(iwe));
> + if (be16_to_cpu(scan->size) <= sizeof(*scan)) {
> + /* If wpa[2] capable station, synthesize IE and put it */
> + len = gelic_wl_synthesize_ie(buf, scan);
> + if (len) {
> + iwe.cmd = IWEVGENIE;
> + iwe.u.data.length = len;
> + ev = iwe_stream_add_point(ev, stop, &iwe, buf);
> + }
> + } else {
> + /* this scan info has IE data */
> + struct ie_info ie_info;
> + size_t data_len;
> +
> + data_len = be16_to_cpu(scan->size) - sizeof(*scan);
> +
> + gelic_wl_parse_ie(scan->elements, data_len, &ie_info);
> +
> + if (ie_info.wpa.len && (ie_info.wpa.len <= sizeof(buf))) {
> + memcpy(buf, ie_info.wpa.data, ie_info.wpa.len);
> + iwe.cmd = IWEVGENIE;
> + iwe.u.data.length = ie_info.wpa.len;
> + ev = iwe_stream_add_point(ev, stop, &iwe, buf);
> + }
> +
> + if (ie_info.rsn.len && (ie_info.rsn.len <= sizeof(buf))) {
> + memset(&iwe, 0, sizeof(iwe));
> + memcpy(buf, ie_info.rsn.data, ie_info.rsn.len);
> + iwe.cmd = IWEVGENIE;
> + iwe.u.data.length = ie_info.rsn.len;
> + ev = iwe_stream_add_point(ev, stop, &iwe, buf);
> + }
> + }
> +
> + pr_debug("%s: ->\n", __func__);
> + return ev;
> +}
> +
> +
> +static int gelic_wl_get_scan(struct net_device *netdev,
> + struct iw_request_info *info,
> + union iwreq_data *wrqu, char *extra)
> +{
> + struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
> + struct gelic_wl_scan_info *scan_info;
> + char *ev = extra;
> + char *stop = ev + wrqu->data.length;
> + int ret = 0;
> + unsigned long this_time = jiffies;
> +
> + pr_debug("%s: <-\n", __func__);
> + if (down_interruptible(&wl->scan_lock))
> + return -EAGAIN;
> +
> + switch (wl->scan_stat) {
> + case GELIC_WL_SCAN_STAT_SCANNING:
> + /* If a scan in progress, caller should call me again */
> + ret = -EAGAIN;
> + goto out;
> + break;
> +
> + case GELIC_WL_SCAN_STAT_INIT:
> + /* last scan request failed or never issued */
> + ret = -ENODEV;
> + goto out;
> + break;
> + case GELIC_WL_SCAN_STAT_GOT_LIST:
> + /* ok, use current list */
> + break;
> + }
> +
> + list_for_each_entry(scan_info, &wl->network_list, list) {
> + if (wl->scan_age == 0 ||
> + time_after(scan_info->last_scanned + wl->scan_age,
> + this_time))
> + ev = gelic_wl_translate_scan(netdev, ev, stop,
> + scan_info);
> + else
> + pr_debug("%s:entry too old\n", __func__);
> +
> + if (stop - ev <= IW_EV_ADDR_LEN) {
> + ret = -E2BIG;
> + goto out;
> + }
> + }
> +
> + wrqu->data.length = ev - extra;
> + wrqu->data.flags = 0;
> +out:
> + up(&wl->scan_lock);
> + pr_debug("%s: -> %d %d\n", __func__, ret, wrqu->data.length);
> + return ret;
> +}
> +
> +#ifdef DEBUG
> +static void scan_list_dump(struct gelic_wl_info *wl)
> +{
> + struct gelic_wl_scan_info *scan_info;
> + int i;
> + DECLARE_MAC_BUF(mac);
> +
> + i = 0;
> + list_for_each_entry(scan_info, &wl->network_list, list) {
> + pr_debug("%s: item %d\n", __func__, i++);
> + pr_debug("valid=%d eurusindex=%d last=%lx\n",
> + scan_info->valid, scan_info->eurus_index,
> + scan_info->last_scanned);
> + pr_debug("r_len=%d r_ext_len=%d essid_len=%d\n",
> + scan_info->rate_len, scan_info->rate_ext_len,
> + scan_info->essid_len);
> + /* -- */
> + pr_debug("bssid=%s\n",
> + print_mac(mac, &scan_info->hwinfo->bssid[2]));
> + pr_debug("essid=%s\n", scan_info->hwinfo->essid);
> + }
> +}
> +#endif
> +
> +static int gelic_wl_set_auth(struct net_device *netdev,
> + struct iw_request_info *info,
> + union iwreq_data *data, char *extra)
> +{
> + struct iw_param *param = &data->param;
> + struct gelic_wl_info *wl = port_wl(netdev_port(netdev));
> + unsigned long irqflag;
> + int ret = 0;
> +
> + pr_debug("%s: <- %d\n", __func__, param->flags & IW_AUTH_INDEX);
> + spin_lock_irqsave(&wl->lock, irqflag);
> + switch (param->flags & IW_AUTH_INDEX) {
> + case IW_AUTH_WPA_VERSION:
> + if (param->value & IW_AUTH_WPA_VERSION_DISABLED) {
> + pr_debug("%s: NO WPA selected\n", __func__);
> + wl->wpa_level = GELIC_WL_WPA_LEVEL_NONE;
> + wl->group_cipher_method = GELIC_WL_CIPHER_WEP;
> + wl->pairwise_cipher_method = GELIC_WL_CIPHER_WEP;
> + }
> + if (param->value & IW_AUTH_WPA_VERSION_WPA) {
> + pr_debug("%s: WPA version 1 selected\n", __func__);
> + wl->wpa_level = GELIC_WL_WPA_LEVEL_WPA;
> + wl->group_cipher_method = GELIC_WL_CIPHER_TKIP;
> + wl->pairwise_cipher_method = GELIC_WL_CIPHER_TKIP;
> + wl->auth_method = GELIC_EURUS_AUTH_OPEN;
> + }
> + if (param->value & IW_AUTH_WPA_VERSION_WPA2) {
> + /*
> + * As the hypervisor may not tell the cipher
> + * information of the AP if it is WPA2,
> + * you will not decide suitable cipher from
> + * its beacon.
> + * You should have knowledge about the AP's
> + * cipher infomation in other method prior to
> + * the association.
> + */
> + if (!precise_ie())
> + pr_info("%s: WPA2 may not work\n", __func__);
> + if (wpa2_capable()) {
> + wl->wpa_level = GELIC_WL_WPA_LEVEL_WPA2;
> + wl->group_cipher_method = GELIC_WL_CIPHER_AES;
> + wl->pairwise_cipher_method =
> + GELIC_WL_CIPHER_AES;
> + wl->auth_method = GELIC_EURUS_AUTH_OPEN;
> + } else
> + ret = -EINVAL;
> + }
> + break;
> +
> + case IW_AUTH_CIPHER_PAIRWISE:
> + if (param->value &
> + (IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40)) {
> + pr_debug("%s: WEP selected\n", __func__);
> + wl->pairwise_cipher_method = GELIC_WL_CIPHER_WEP;
> + }
> + if (param->value & IW_AUTH_CIPHER_TKIP) {
> + pr_debug("%s: TKIP selected\n", __func__);
> + wl->pairwise_cipher_method = GELIC_WL_CIPHER_TKIP;
> + }
> + if (param->value & IW_AUTH_CIPHER_CCMP) {
> + pr_debug("%s: CCMP selected\n", __func__);
> + wl->pairwise_cipher_method = GELIC_WL_CIPHER_AES;
> + }
> + if (param->value & IW_AUTH_CIPHER_NONE) {
> + pr_debug("%s: no auth selected\n", __func__);
> + wl->pairwise_cipher_method = GELIC_WL_CIPHER_NONE;
> + }
> + break;
> + case IW_AUTH_CIPHER_GROUP:
> + if (param->value &
> + (IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40)) {
> + pr_debug("%s: WEP selected\n", __func__);
> + wl->group_cipher_method = GELIC_WL_CIPHER_WEP;
> + }
> + if (param->value & IW_AUTH_CIPHER_TKIP) {
> + pr_debug("%s: TKIP selected\n", __func__);
> + wl->group_cipher_method = GELIC_WL_CIPHER_TKIP;
> + }
> + if (param->value & IW_AUTH_CIPHER_CCMP) {
> + pr_debug("%s: CCMP selected\n", __func__);
> + wl->group_cipher_method = GELIC_WL_CIPHER_AES;
> + }
> + if (param->value & IW_AUTH_CIPHER_NONE) {
> + pr_debug("%s: no auth selected\n", __func__);
> + wl->group_cipher_method = GELIC_WL_CIPHER_NONE;
> + }
> + break;
> + case IW_AUTH_80211_AUTH_ALG:
> + if (param->value & IW_AUTH_ALG_SHARED_KEY) {
> + pr_debug("%s: shared key specified\n", __func__);
> + wl->auth_method = GELIC_EURUS_AUTH_SHARED;
> + } else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) {
> + pr_debug("%s: open system specified\n", __func__);
> + wl->auth_method = GELIC_EURUS_AUTH_OPEN;
> + } else
> + ret = -EINVAL;
> + break;
> +
> + case IW_AUTH_WPA_ENABLED:
> + if (param->value) {
> + pr_debug("%s: WPA enabled\n", __func__);
> + wl->wpa_level = GELIC_WL_WPA_LEVEL_WPA;
> + } else {
> + pr_debug("%s: WPA disabled\n", __func__);
> + wl->wpa_level = GELIC_WL_WPA_LEVEL_NONE;
> + }
> + break;
> +
> + case IW_AUTH_KEY_MGMT:
> + if (param->value & IW_AUTH_KEY_MGMT_PSK)
> + break;
> + /* intentionally fall through */
> + default:
> + ret = -EOPNOTSUPP;
> + break;
> + };
> +
> + if (!ret)
> + set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat);
> +
> + spin_unlock_irqrestore(&wl->lock, irqflag);
> + pr_debug("%s: -> %d\n", __func__, ret);
> + return ret;
> +}
> +
> +static int gelic_wl_get_auth(struct net_device *netdev,
> + struct iw_request_info *info,
> + union iwreq_data *iwreq, char *extra)
> +{
> + struct iw_param *param = &iwreq->param;
> + struct gelic_wl_info *wl = port_wl(netdev_port(netdev));
> + unsigned long irqflag;
> + int ret = 0;
> +
> + pr_debug("%s: <- %d\n", __func__, param->flags & IW_AUTH_INDEX);
> + spin_lock_irqsave(&wl->lock, irqflag);
> + switch (param->flags & IW_AUTH_INDEX) {
> + case IW_AUTH_WPA_VERSION:
> + switch (wl->wpa_level) {
> + case GELIC_WL_WPA_LEVEL_WPA:
> + param->value |= IW_AUTH_WPA_VERSION_WPA;
> + break;
> + case GELIC_WL_WPA_LEVEL_WPA2:
> + param->value |= IW_AUTH_WPA_VERSION_WPA2;
> + break;
> + default:
> + param->value |= IW_AUTH_WPA_VERSION_DISABLED;
> + }
> + break;
> +
> + case IW_AUTH_80211_AUTH_ALG:
> + if (wl->auth_method == GELIC_EURUS_AUTH_SHARED)
> + param->value = IW_AUTH_ALG_SHARED_KEY;
> + else if (wl->auth_method == GELIC_EURUS_AUTH_OPEN)
> + param->value = IW_AUTH_ALG_OPEN_SYSTEM;
> + break;
> +
> + case IW_AUTH_WPA_ENABLED:
> + switch (wl->wpa_level) {
> + case GELIC_WL_WPA_LEVEL_WPA:
> + case GELIC_WL_WPA_LEVEL_WPA2:
> + param->value = 1;
> + break;
> + default:
> + param->value = 0;
> + break;
> + }
> + break;
> + default:
> + ret = -EOPNOTSUPP;
> + }
> +
> + spin_unlock_irqrestore(&wl->lock, irqflag);
> + pr_debug("%s: -> %d\n", __func__, ret);
> + return ret;
> +}
> +
> +/* SIOC{S,G}IWESSID */
> +static int gelic_wl_set_essid(struct net_device *netdev,
> + struct iw_request_info *info,
> + union iwreq_data *data, char *extra)
> +{
> + struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
> + unsigned long irqflag;
> +
> + pr_debug("%s: <- l=%d f=%d\n", __func__,
> + data->essid.length, data->essid.flags);
> + if (IW_ESSID_MAX_SIZE < data->essid.length)
> + return -EINVAL;
> +
> + spin_lock_irqsave(&wl->lock, irqflag);
> + if (data->essid.flags) {
> + wl->essid_len = data->essid.length;
> + memcpy(wl->essid, extra, wl->essid_len);
> + pr_debug("%s: essid = '%s'\n", __func__, extra);
> + set_bit(GELIC_WL_STAT_ESSID_SET, &wl->stat);
> + } else {
> + pr_debug("%s: ESSID any \n", __func__);
> + clear_bit(GELIC_WL_STAT_ESSID_SET, &wl->stat);
> + }
> + set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat);
> + spin_unlock_irqrestore(&wl->lock, irqflag);
> +
> +
> + gelic_wl_try_associate(netdev); /* FIXME */
> + pr_debug("%s: -> \n", __func__);
> + return 0;
> +}
> +
> +static int gelic_wl_get_essid(struct net_device *netdev,
> + struct iw_request_info *info,
> + union iwreq_data *data, char *extra)
> +{
> + struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
> + unsigned long irqflag;
> +
> + pr_debug("%s: <- \n", __func__);
> + down(&wl->assoc_stat_lock);
> + spin_lock_irqsave(&wl->lock, irqflag);
> + if (test_bit(GELIC_WL_STAT_ESSID_SET, &wl->stat) ||
> + wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED) {
> + memcpy(extra, wl->essid, wl->essid_len);
> + data->essid.length = wl->essid_len;
> + data->essid.flags = 1;
> + } else
> + data->essid.flags = 0;
> +
> + up(&wl->assoc_stat_lock);
> + spin_unlock_irqrestore(&wl->lock, irqflag);
> + pr_debug("%s: -> len=%d \n", __func__, data->essid.length);
> +
> + return 0;
> +}
> +
> +/* SIO{S,G}IWENCODE */
> +static int gelic_wl_set_encode(struct net_device *netdev,
> + struct iw_request_info *info,
> + union iwreq_data *data, char *extra)
> +{
> + struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
> + struct iw_point *enc = &data->encoding;
> + __u16 flags;
> + unsigned int irqflag;
> + int key_index, index_specified;
> + int ret = 0;
> +
> + pr_debug("%s: <- \n", __func__);
> + flags = enc->flags & IW_ENCODE_FLAGS;
> + key_index = enc->flags & IW_ENCODE_INDEX;
> +
> + pr_debug("%s: key_index = %d\n", __func__, key_index);
> + pr_debug("%s: key_len = %d\n", __func__, enc->length);
> + pr_debug("%s: flag=%x\n", __func__, enc->flags & IW_ENCODE_FLAGS);
> +
> + if (GELIC_WEP_KEYS < key_index)
> + return -EINVAL;
> +
> + spin_lock_irqsave(&wl->lock, irqflag);
> + if (key_index) {
> + index_specified = 1;
> + key_index--;
> + } else {
> + index_specified = 0;
> + key_index = wl->current_key;
> + }
> +
> + if (flags & IW_ENCODE_NOKEY) {
> + /* if just IW_ENCODE_NOKEY, change current key index */
> + if (!flags && index_specified) {
> + wl->current_key = key_index;
> + goto done;
> + }
> +
> + if (flags & IW_ENCODE_DISABLED) {
> + if (!index_specified) {
> + /* disable encryption */
> + wl->group_cipher_method = GELIC_WL_CIPHER_NONE;
> + wl->pairwise_cipher_method =
> + GELIC_WL_CIPHER_NONE;
> + /* invalidate all key */
> + wl->key_enabled = 0;
> + } else
> + clear_bit(key_index, &wl->key_enabled);
> + }
> +
> + if (flags & IW_ENCODE_OPEN)
> + wl->auth_method = GELIC_EURUS_AUTH_OPEN;
> + if (flags & IW_ENCODE_RESTRICTED) {
> + pr_info("%s: shared key mode enabled\n", __func__);
> + wl->auth_method = GELIC_EURUS_AUTH_SHARED;
> + }
> + } else {
> + if (IW_ENCODING_TOKEN_MAX < enc->length) {
> + ret = -EINVAL;
> + goto done;
> + }
> + wl->key_len[key_index] = enc->length;
> + memcpy(wl->key[key_index], extra, enc->length);
> + set_bit(key_index, &wl->key_enabled);
> + wl->pairwise_cipher_method = GELIC_WL_CIPHER_WEP;
> + wl->group_cipher_method = GELIC_WL_CIPHER_WEP;
> + }
> + set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat);
> +done:
> + spin_unlock_irqrestore(&wl->lock, irqflag);
> + pr_debug("%s: -> \n", __func__);
> + return ret;
> +}
> +
> +static int gelic_wl_get_encode(struct net_device *netdev,
> + struct iw_request_info *info,
> + union iwreq_data *data, char *extra)
> +{
> + struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
> + struct iw_point *enc = &data->encoding;
> + unsigned int irqflag;
> + unsigned int key_index, index_specified;
> + int ret = 0;
> +
> + pr_debug("%s: <- \n", __func__);
> + key_index = enc->flags & IW_ENCODE_INDEX;
> + pr_debug("%s: flag=%#x point=%p len=%d extra=%p\n", __func__,
> + enc->flags, enc->pointer, enc->length, extra);
> + if (GELIC_WEP_KEYS < key_index)
> + return -EINVAL;
> +
> + spin_lock_irqsave(&wl->lock, irqflag);
> + if (key_index) {
> + index_specified = 1;
> + key_index--;
> + } else {
> + index_specified = 0;
> + key_index = wl->current_key;
> + }
> +
> + if (wl->group_cipher_method == GELIC_WL_CIPHER_WEP) {
> + switch (wl->auth_method) {
> + case GELIC_EURUS_AUTH_OPEN:
> + enc->flags = IW_ENCODE_OPEN;
> + break;
> + case GELIC_EURUS_AUTH_SHARED:
> + enc->flags = IW_ENCODE_RESTRICTED;
> + break;
> + }
> + } else
> + enc->flags = IW_ENCODE_DISABLED;
> +
> + if (test_bit(key_index, &wl->key_enabled)) {
> + if (enc->length < wl->key_len[key_index]) {
> + ret = -EINVAL;
> + goto done;
> + }
> + enc->length = wl->key_len[key_index];
> + memcpy(extra, wl->key[key_index], wl->key_len[key_index]);
> + } else {
> + enc->length = 0;
> + enc->flags |= IW_ENCODE_NOKEY;
> + }
> + enc->flags |= key_index + 1;
> + pr_debug("%s: -> flag=%x len=%d\n", __func__,
> + enc->flags, enc->length);
> +
> +done:
> + spin_unlock_irqrestore(&wl->lock, irqflag);
> + return ret;
> +}
> +
> +/* SIOC{S,G}IWAP */
> +static int gelic_wl_set_ap(struct net_device *netdev,
> + struct iw_request_info *info,
> + union iwreq_data *data, char *extra)
> +{
> + struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
> + unsigned long irqflag;
> +
> + pr_debug("%s: <-\n", __func__);
> + if (data->ap_addr.sa_family != ARPHRD_ETHER)
> + return -EINVAL;
> +
> + spin_lock_irqsave(&wl->lock, irqflag);
> + if (is_valid_ether_addr(data->ap_addr.sa_data)) {
> + memcpy(wl->bssid, data->ap_addr.sa_data,
> + ETH_ALEN);
> + set_bit(GELIC_WL_STAT_BSSID_SET, &wl->stat);
> + set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat);
> + pr_debug("%s: bss=%02x:%02x:%02x:%02x:%02x:%02x\n",
> + __func__,
> + wl->bssid[0], wl->bssid[1],
> + wl->bssid[2], wl->bssid[3],
> + wl->bssid[4], wl->bssid[5]);
> + } else {
> + pr_debug("%s: clear bssid\n", __func__);
> + clear_bit(GELIC_WL_STAT_BSSID_SET, &wl->stat);
> + memset(wl->bssid, 0, ETH_ALEN);
> + }
> + spin_unlock_irqrestore(&wl->lock, irqflag);
> + pr_debug("%s: ->\n", __func__);
> + return 0;
> +}
> +
> +static int gelic_wl_get_ap(struct net_device *netdev,
> + struct iw_request_info *info,
> + union iwreq_data *data, char *extra)
> +{
> + struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
> + unsigned long irqflag;
> +
> + pr_debug("%s: <-\n", __func__);
> + down(&wl->assoc_stat_lock);
> + spin_lock_irqsave(&wl->lock, irqflag);
> + if (wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED) {
> + data->ap_addr.sa_family = ARPHRD_ETHER;
> + memcpy(data->ap_addr.sa_data, wl->active_bssid,
> + ETH_ALEN);
> + } else
> + memset(data->ap_addr.sa_data, 0, ETH_ALEN);
> +
> + spin_unlock_irqrestore(&wl->lock, irqflag);
> + up(&wl->assoc_stat_lock);
> + pr_debug("%s: ->\n", __func__);
> + return 0;
> +}
> +
> +/* SIOC{S,G}IWENCODEEXT */
> +static int gelic_wl_set_encodeext(struct net_device *netdev,
> + struct iw_request_info *info,
> + union iwreq_data *data, char *extra)
> +{
> + struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
> + struct iw_point *enc = &data->encoding;
> + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
> + __u16 alg;
> + __u16 flags;
> + unsigned int irqflag;
> + int key_index;
> + int ret = 0;
> +
> + pr_debug("%s: <- \n", __func__);
> + flags = enc->flags & IW_ENCODE_FLAGS;
> + alg = ext->alg;
> + key_index = enc->flags & IW_ENCODE_INDEX;
> +
> + pr_debug("%s: key_index = %d\n", __func__, key_index);
> + pr_debug("%s: key_len = %d\n", __func__, enc->length);
> + pr_debug("%s: flag=%x\n", __func__, enc->flags & IW_ENCODE_FLAGS);
> + pr_debug("%s: ext_flag=%x\n", __func__, ext->ext_flags);
> + pr_debug("%s: ext_key_len=%x\n", __func__, ext->key_len);
> +
> + if (GELIC_WEP_KEYS < key_index)
> + return -EINVAL;
> +
> + spin_lock_irqsave(&wl->lock, irqflag);
> + if (key_index)
> + key_index--;
> + else
> + key_index = wl->current_key;
> +
> + if (!enc->length && (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)) {
> + /* reques to change default key index */
> + pr_debug("%s: request to change default key to %d\n",
> + __func__, key_index);
> + wl->current_key = key_index;
> + goto done;
> + }
> +
> + if (alg == IW_ENCODE_ALG_NONE || (flags & IW_ENCODE_DISABLED)) {
> + pr_debug("%s: alg disabled\n", __func__);
> + wl->wpa_level = GELIC_WL_WPA_LEVEL_NONE;
> + wl->group_cipher_method = GELIC_WL_CIPHER_NONE;
> + wl->pairwise_cipher_method = GELIC_WL_CIPHER_NONE;
> + wl->auth_method = GELIC_EURUS_AUTH_OPEN; /* should be open */
> + } else if (alg == IW_ENCODE_ALG_WEP) {
> + pr_debug("%s: WEP requested\n", __func__);
> + if (flags & IW_ENCODE_OPEN) {
> + pr_debug("%s: open key mode\n", __func__);
> + wl->auth_method = GELIC_EURUS_AUTH_OPEN;
> + }
> + if (flags & IW_ENCODE_RESTRICTED) {
> + pr_debug("%s: shared key mode\n", __func__);
> + wl->auth_method = GELIC_EURUS_AUTH_SHARED;
> + }
> + if (IW_ENCODING_TOKEN_MAX < ext->key_len) {
> + pr_info("%s: key is too long %d\n", __func__,
> + ext->key_len);
> + ret = -EINVAL;
> + goto done;
> + }
> + /* OK, update the key */
> + wl->key_len[key_index] = ext->key_len;
> + memset(wl->key[key_index], 0, IW_ENCODING_TOKEN_MAX);
> + memcpy(wl->key[key_index], ext->key, ext->key_len);
> + set_bit(key_index, &wl->key_enabled);
> + /* remember wep info changed */
> + set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat);
> + } else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) {
> + pr_debug("%s: TKIP/CCMP requested alg=%d\n", __func__, alg);
> + /* check key length */
> + if (IW_ENCODING_TOKEN_MAX < ext->key_len) {
> + pr_info("%s: key is too long %d\n", __func__,
> + ext->key_len);
> + ret = -EINVAL;
> + goto done;
> + }
> + if (alg == IW_ENCODE_ALG_CCMP) {
> + pr_debug("%s: AES selected\n", __func__);
> + wl->group_cipher_method = GELIC_WL_CIPHER_AES;
> + wl->pairwise_cipher_method = GELIC_WL_CIPHER_AES;
> + wl->wpa_level = GELIC_WL_WPA_LEVEL_WPA2;
> + } else {
> + pr_debug("%s: TKIP selected, WPA forced\n", __func__);
> + wl->group_cipher_method = GELIC_WL_CIPHER_TKIP;
> + wl->pairwise_cipher_method = GELIC_WL_CIPHER_TKIP;
> + /* FIXME: how do we do if WPA2 + TKIP? */
> + wl->wpa_level = GELIC_WL_WPA_LEVEL_WPA;
> + }
> + if (flags & IW_ENCODE_RESTRICTED)
> + BUG();
> + wl->auth_method = GELIC_EURUS_AUTH_OPEN;
> + /* We should use same key for both and unicast */
> + if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)
> + pr_debug("%s: group key \n", __func__);
> + else
> + pr_debug("%s: unicast key \n", __func__);
> + /* OK, update the key */
> + wl->key_len[key_index] = ext->key_len;
> + memset(wl->key[key_index], 0, IW_ENCODING_TOKEN_MAX);
> + memcpy(wl->key[key_index], ext->key, ext->key_len);
> + set_bit(key_index, &wl->key_enabled);
> + /* remember info changed */
> + set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat);
> + }
> +done:
> + spin_unlock_irqrestore(&wl->lock, irqflag);
> + pr_debug("%s: -> \n", __func__);
> + return ret;
> +}
> +
> +static int gelic_wl_get_encodeext(struct net_device *netdev,
> + struct iw_request_info *info,
> + union iwreq_data *data, char *extra)
> +{
> + struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
> + struct iw_point *enc = &data->encoding;
> + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
> + unsigned int irqflag;
> + int key_index;
> + int ret = 0;
> + int max_key_len;
> +
> + pr_debug("%s: <- \n", __func__);
> +
> + max_key_len = enc->length - sizeof(struct iw_encode_ext);
> + if (max_key_len < 0)
> + return -EINVAL;
> + key_index = enc->flags & IW_ENCODE_INDEX;
> +
> + pr_debug("%s: key_index = %d\n", __func__, key_index);
> + pr_debug("%s: key_len = %d\n", __func__, enc->length);
> + pr_debug("%s: flag=%x\n", __func__, enc->flags & IW_ENCODE_FLAGS);
> +
> + if (GELIC_WEP_KEYS < key_index)
> + return -EINVAL;
> +
> + spin_lock_irqsave(&wl->lock, irqflag);
> + if (key_index)
> + key_index--;
> + else
> + key_index = wl->current_key;
> +
> + memset(ext, 0, sizeof(struct iw_encode_ext));
> + switch (wl->group_cipher_method) {
> + case GELIC_WL_CIPHER_WEP:
> + ext->alg = IW_ENCODE_ALG_WEP;
> + enc->flags |= IW_ENCODE_ENABLED;
> + break;
> + case GELIC_WL_CIPHER_TKIP:
> + ext->alg = IW_ENCODE_ALG_TKIP;
> + enc->flags |= IW_ENCODE_ENABLED;
> + break;
> + case GELIC_WL_CIPHER_AES:
> + ext->alg = IW_ENCODE_ALG_CCMP;
> + enc->flags |= IW_ENCODE_ENABLED;
> + break;
> + case GELIC_WL_CIPHER_NONE:
> + default:
> + ext->alg = IW_ENCODE_ALG_NONE;
> + enc->flags |= IW_ENCODE_NOKEY;
> + break;
> + }
> +
> + if (!(enc->flags & IW_ENCODE_NOKEY)) {
> + if (max_key_len < wl->key_len[key_index]) {
> + ret = -E2BIG;
> + goto out;
> + }
> + if (test_bit(key_index, &wl->key_enabled))
> + memcpy(ext->key, wl->key[key_index],
> + wl->key_len[key_index]);
> + else
> + pr_debug("%s: disabled key requested ix=%d\n",
> + __func__, key_index);
> + }
> +out:
> + spin_unlock_irqrestore(&wl->lock, irqflag);
> + pr_debug("%s: -> \n", __func__);
> + return ret;
> +}
> +/* SIOC{S,G}IWMODE */
> +static int gelic_wl_set_mode(struct net_device *netdev,
> + struct iw_request_info *info,
> + union iwreq_data *data, char *extra)
> +{
> + __u32 mode = data->mode;
> + int ret;
> +
> + pr_debug("%s: <- \n", __func__);
> + if (mode == IW_MODE_INFRA)
> + ret = 0;
> + else
> + ret = -EOPNOTSUPP;
> + pr_debug("%s: -> %d\n", __func__, ret);
> + return ret;
> +}
> +
> +static int gelic_wl_get_mode(struct net_device *netdev,
> + struct iw_request_info *info,
> + union iwreq_data *data, char *extra)
> +{
> + __u32 *mode = &data->mode;
> + pr_debug("%s: <- \n", __func__);
> + *mode = IW_MODE_INFRA;
> + pr_debug("%s: ->\n", __func__);
> + return 0;
> +}
> +
> +/* SIOCIWFIRSTPRIV */
> +static int hex2bin(u8 *str, u8 *bin, unsigned int len)
> +{
> + unsigned int i;
> + static unsigned char *hex = "0123456789ABCDEF";
> + unsigned char *p, *q;
> + u8 tmp;
> +
> + if (len != WPA_PSK_LEN * 2)
> + return -EINVAL;
> +
> + for (i = 0; i < WPA_PSK_LEN * 2; i += 2) {
> + p = strchr(hex, toupper(str[i]));
> + q = strchr(hex, toupper(str[i + 1]));
> + if (!p || !q) {
> + pr_info("%s: unconvertible PSK digit=%d\n",
> + __func__, i);
> + return -EINVAL;
> + }
> + tmp = ((p - hex) << 4) + (q - hex);
> + *bin++ = tmp;
> + }
> + return 0;
> +};
> +
> +static int gelic_wl_priv_set_psk(struct net_device *net_dev,
> + struct iw_request_info *info,
> + union iwreq_data *data, char *extra)
> +{
> + struct gelic_wl_info *wl = port_wl(netdev_priv(net_dev));
> + unsigned int len;
> + unsigned int irqflag;
> + int ret = 0;
> +
> + pr_debug("%s:<- len=%d\n", __func__, data->data.length);
> + len = data->data.length - 1;
> + if (len <= 2)
> + return -EINVAL;
> +
> + spin_lock_irqsave(&wl->lock, irqflag);
> + if (extra[0] == '"' && extra[len - 1] == '"') {
> + pr_debug("%s: passphrase mode\n", __func__);
> + /* pass phrase */
> + if (GELIC_WL_EURUS_PSK_MAX_LEN < (len - 2)) {
> + pr_info("%s: passphrase too long\n", __func__);
> + ret = -E2BIG;
> + goto out;
> + }
> + memset(wl->psk, 0, sizeof(wl->psk));
> + wl->psk_len = len - 2;
> + memcpy(wl->psk, &(extra[1]), wl->psk_len);
> + wl->psk_type = GELIC_EURUS_WPA_PSK_PASSPHRASE;
> + } else {
> + ret = hex2bin(extra, wl->psk, len);
> + if (ret)
> + goto out;
> + wl->psk_len = WPA_PSK_LEN;
> + wl->psk_type = GELIC_EURUS_WPA_PSK_BIN;
> + }
> + set_bit(GELIC_WL_STAT_WPA_PSK_SET, &wl->stat);
> +out:
> + spin_unlock_irqrestore(&wl->lock, irqflag);
> + pr_debug("%s:->\n", __func__);
> + return ret;
> +}
> +
> +static int gelic_wl_priv_get_psk(struct net_device *net_dev,
> + struct iw_request_info *info,
> + union iwreq_data *data, char *extra)
> +{
> + struct gelic_wl_info *wl = port_wl(netdev_priv(net_dev));
> + char *p;
> + unsigned int irqflag;
> + unsigned int i;
> +
> + pr_debug("%s:<-\n", __func__);
> + if (!capable(CAP_NET_ADMIN))
> + return -EPERM;
> +
> + spin_lock_irqsave(&wl->lock, irqflag);
> + p = extra;
> + if (test_bit(GELIC_WL_STAT_WPA_PSK_SET, &wl->stat)) {
> + if (wl->psk_type == GELIC_EURUS_WPA_PSK_BIN) {
> + for (i = 0; i < wl->psk_len; i++) {
> + sprintf(p, "%02xu", wl->psk[i]);
> + p += 2;
> + }
> + *p = '\0';
> + data->data.length = wl->psk_len * 2;
> + } else {
> + *p++ = '"';
> + memcpy(p, wl->psk, wl->psk_len);
> + p += wl->psk_len;
> + *p++ = '"';
> + *p = '\0';
> + data->data.length = wl->psk_len + 2;
> + }
> + } else
> + /* no psk set */
> + data->data.length = 0;
> + spin_unlock_irqrestore(&wl->lock, irqflag);
> + pr_debug("%s:-> %d\n", __func__, data->data.length);
> + return 0;
> +}
> +
> +/* SIOCGIWNICKN */
> +static int gelic_wl_get_nick(struct net_device *net_dev,
> + struct iw_request_info *info,
> + union iwreq_data *data, char *extra)
> +{
> + strcpy(extra, "gelic_wl");
> + data->data.length = strlen(extra);
> + data->data.flags = 1;
> + return 0;
> +}
> +
> +
> +/* --- */
> +
> +static struct iw_statistics *gelic_wl_get_wireless_stats(
> + struct net_device *netdev)
> +{
> +
> + struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
> + struct gelic_eurus_cmd *cmd;
> + struct iw_statistics *is;
> + struct gelic_eurus_rssi_info *rssi;
> +
> + pr_debug("%s: <-\n", __func__);
> +
> + is = &wl->iwstat;
> + memset(is, 0, sizeof(*is));
> + cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_GET_RSSI_CFG,
> + wl->buf, sizeof(*rssi));
> + if (cmd && !cmd->status && !cmd->cmd_status) {
> + rssi = wl->buf;
> + is->qual.level = be16_to_cpu(rssi->rssi);
> + is->qual.updated = IW_QUAL_LEVEL_UPDATED |
> + IW_QUAL_QUAL_INVALID | IW_QUAL_NOISE_INVALID;
> + } else
> + /* not associated */
> + is->qual.updated = IW_QUAL_ALL_INVALID;
> +
> + kfree(cmd);
> + pr_debug("%s: ->\n", __func__);
> + return is;
> +}
> +
> +/*
> + * scanning helpers
> + */
> +static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan)
> +{
> + struct gelic_eurus_cmd *cmd;
> + int ret = 0;
> +
> + pr_debug("%s: <- always=%d\n", __func__, always_scan);
> + if (down_interruptible(&wl->scan_lock))
> + return -ERESTARTSYS;
> +
> + /*
> + * If already a scan in progress, do not trigger more
> + */
> + if (wl->scan_stat == GELIC_WL_SCAN_STAT_SCANNING) {
> + pr_debug("%s: scanning now\n", __func__);
> + goto out;
> + }
> +
> + init_completion(&wl->scan_done);
> + /*
> + * If we have already a bss list, don't try to get new
> + */
> + if (!always_scan && wl->scan_stat == GELIC_WL_SCAN_STAT_GOT_LIST) {
> + pr_debug("%s: already has the list\n", __func__);
> + complete(&wl->scan_done);
> + goto out;
> + }
> + /*
> + * issue start scan request
> + */
> + wl->scan_stat = GELIC_WL_SCAN_STAT_SCANNING;
> + cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_START_SCAN,
> + NULL, 0);
> + if (!cmd || cmd->status || cmd->cmd_status) {
> + wl->scan_stat = GELIC_WL_SCAN_STAT_INIT;
> + complete(&wl->scan_done);
> + ret = -ENOMEM;
> + goto out;
> + }
> + kfree(cmd);
> +out:
> + up(&wl->scan_lock);
> + pr_debug("%s: ->\n", __func__);
> + return ret;
> +}
> +
> +/*
> + * retrieve scan result from the chip (hypervisor)
> + * this function is invoked by schedule work.
> + */
> +static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl)
> +{
> + struct gelic_eurus_cmd *cmd = NULL;
> + struct gelic_wl_scan_info *target, *tmp;
> + struct gelic_wl_scan_info *oldest = NULL;
> + struct gelic_eurus_scan_info *scan_info;
> + unsigned int scan_info_size;
> + union iwreq_data data;
> + unsigned long this_time = jiffies;
> + unsigned int data_len, i, found, r;
> + DECLARE_MAC_BUF(mac);
> +
> + pr_debug("%s:start\n", __func__);
> + down(&wl->scan_lock);
> +
> + if (wl->scan_stat != GELIC_WL_SCAN_STAT_SCANNING) {
> + /*
> + * stop() may be called while scanning, ignore result
> + */
> + pr_debug("%s: scan complete when stat != scanning(%d)\n",
> + __func__, wl->scan_stat);
> + goto out;
> + }
> +
> + cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_GET_SCAN,
> + wl->buf, PAGE_SIZE);
> + if (!cmd || cmd->status || cmd->cmd_status) {
> + wl->scan_stat = GELIC_WL_SCAN_STAT_INIT;
> + pr_info("%s:cmd failed\n", __func__);
> + kfree(cmd);
> + goto out;
> + }
> + data_len = cmd->size;
> + pr_debug("%s: data_len = %d\n", __func__, data_len);
> + kfree(cmd);
> +
> + /* OK, bss list retrieved */
> + wl->scan_stat = GELIC_WL_SCAN_STAT_GOT_LIST;
> +
> + /* mark all entries are old */
> + list_for_each_entry_safe(target, tmp, &wl->network_list, list) {
> + target->valid = 0;
> + /* expire too old entries */
> + if (time_before(target->last_scanned + wl->scan_age,
> + this_time)) {
> + kfree(target->hwinfo);
> + target->hwinfo = NULL;
> + list_move_tail(&target->list, &wl->network_free_list);
> + }
> + }
> +
> + /* put them in the newtork_list */
> + scan_info = wl->buf;
> + scan_info_size = 0;
> + i = 0;
> + while (scan_info_size < data_len) {
> + pr_debug("%s:size=%d bssid=%s scan_info=%p\n", __func__,
> + be16_to_cpu(scan_info->size),
> + print_mac(mac, &scan_info->bssid[2]), scan_info);
> + found = 0;
> + oldest = NULL;
> + list_for_each_entry(target, &wl->network_list, list) {
> + if (!compare_ether_addr(&target->hwinfo->bssid[2],
> + &scan_info->bssid[2])) {
> + found = 1;
> + pr_debug("%s: same BBS found scanned list\n",
> + __func__);
> + break;
> + }
> + if (!oldest ||
> + (target->last_scanned < oldest->last_scanned))
> + oldest = target;
> + }
> +
> + if (!found) {
> + /* not found in the list */
> + if (list_empty(&wl->network_free_list)) {
> + /* expire oldest */
> + target = oldest;
> + } else {
> + target = list_entry(wl->network_free_list.next,
> + struct gelic_wl_scan_info,
> + list);
> + }
> + }
> +
> + /* update the item */
> + target->last_scanned = this_time;
> + target->valid = 1;
> + target->eurus_index = i;
> + kfree(target->hwinfo);
> + target->hwinfo = kzalloc(be16_to_cpu(scan_info->size),
> + GFP_KERNEL);
> + if (!target->hwinfo) {
> + pr_info("%s: kzalloc failed\n", __func__);
> + i++;
> + scan_info_size += be16_to_cpu(scan_info->size);
> + scan_info = (void *)scan_info +
> + be16_to_cpu(scan_info->size);
> + continue;
> + }
> + /* copy hw scan info */
> + memcpy(target->hwinfo, scan_info, scan_info->size);
> + target->essid_len = strnlen(scan_info->essid,
> + sizeof(scan_info->essid));
> + target->rate_len = 0;
> + for (r = 0; r < MAX_RATES_LENGTH; r++)
> + if (scan_info->rate[r])
> + target->rate_len++;
> + if (8 < target->rate_len)
> + pr_info("%s: AP returns %d rates\n", __func__,
> + target->rate_len);
> + target->rate_ext_len = 0;
> + for (r = 0; r < MAX_RATES_EX_LENGTH; r++)
> + if (scan_info->ext_rate[r])
> + target->rate_ext_len++;
> + list_move_tail(&target->list, &wl->network_list);
> + /* bump pointer */
> + i++;
> + scan_info_size += be16_to_cpu(scan_info->size);
> + scan_info = (void *)scan_info + be16_to_cpu(scan_info->size);
> + }
> + memset(&data, 0, sizeof(data));
> + wireless_send_event(port_to_netdev(wl_port(wl)), SIOCGIWSCAN, &data,
> + NULL);
> +out:
> + complete(&wl->scan_done);
> + up(&wl->scan_lock);
> + pr_debug("%s:end\n", __func__);
> +}
> +
> +/*
> + * Select an appropriate bss from current scan list regarding
> + * current settings from userspace.
> + * The caller must hold wl->scan_lock,
> + * and on the state of wl->scan_state == GELIC_WL_SCAN_GOT_LIST
> + */
> +static void update_best(struct gelic_wl_scan_info **best,
> + struct gelic_wl_scan_info *candid,
> + int *best_weight,
> + int *weight)
> +{
> + if (*best_weight < ++(*weight)) {
> + *best_weight = *weight;
> + *best = candid;
> + }
> +}
> +
> +static
> +struct gelic_wl_scan_info *gelic_wl_find_best_bss(struct gelic_wl_info *wl)
> +{
> + struct gelic_wl_scan_info *scan_info;
> + struct gelic_wl_scan_info *best_bss;
> + int weight, best_weight;
> + u16 security;
> + DECLARE_MAC_BUF(mac);
> +
> + pr_debug("%s: <-\n", __func__);
> +
> + best_bss = NULL;
> + best_weight = 0;
> +
> + list_for_each_entry(scan_info, &wl->network_list, list) {
> + pr_debug("%s: station %p\n", __func__, scan_info);
> +
> + if (!scan_info->valid) {
> + pr_debug("%s: station invalid\n", __func__);
> + continue;
> + }
> +
> + /* If bss specified, check it only */
> + if (test_bit(GELIC_WL_STAT_BSSID_SET, &wl->stat)) {
> + if (!compare_ether_addr(&scan_info->hwinfo->bssid[2],
> + wl->bssid)) {
> + best_bss = scan_info;
> + pr_debug("%s: bssid matched\n", __func__);
> + break;
> + } else {
> + pr_debug("%s: bssid unmached\n", __func__);
> + continue;
> + }
> + }
> +
> + weight = 0;
> +
> + /* security */
> + security = be16_to_cpu(scan_info->hwinfo->security) &
> + GELIC_EURUS_SCAN_SEC_MASK;
> + if (wl->wpa_level == GELIC_WL_WPA_LEVEL_WPA2) {
> + if (security == GELIC_EURUS_SCAN_SEC_WPA2)
> + update_best(&best_bss, scan_info,
> + &best_weight, &weight);
> + else
> + continue;
> + } else if (wl->wpa_level == GELIC_WL_WPA_LEVEL_WPA) {
> + if (security == GELIC_EURUS_SCAN_SEC_WPA)
> + update_best(&best_bss, scan_info,
> + &best_weight, &weight);
> + else
> + continue;
> + } else if (wl->wpa_level == GELIC_WL_WPA_LEVEL_NONE &&
> + wl->group_cipher_method == GELIC_WL_CIPHER_WEP) {
> + if (security == GELIC_EURUS_SCAN_SEC_WEP)
> + update_best(&best_bss, scan_info,
> + &best_weight, &weight);
> + else
> + continue;
> + }
> +
> + /* If ESSID is set, check it */
> + if (test_bit(GELIC_WL_STAT_ESSID_SET, &wl->stat)) {
> + if ((scan_info->essid_len == wl->essid_len) &&
> + !strncmp(wl->essid,
> + scan_info->hwinfo->essid,
> + scan_info->essid_len))
> + update_best(&best_bss, scan_info,
> + &best_weight, &weight);
> + else
> + continue;
> + }
> + }
> +
> +#ifdef DEBUG
> + pr_debug("%s: -> bss=%p\n", __func__, best_bss);
> + if (best_bss) {
> + pr_debug("%s:addr=%s\n", __func__,
> + print_mac(mac, &best_bss->hwinfo->bssid[2]));
> + }
> +#endif
> + return best_bss;
> +}
> +
> +/*
> + * Setup WEP configuration to the chip
> + * The caller must hold wl->scan_lock,
> + * and on the state of wl->scan_state == GELIC_WL_SCAN_GOT_LIST
> + */
> +static int gelic_wl_do_wep_setup(struct gelic_wl_info *wl)
> +{
> + unsigned int i;
> + struct gelic_eurus_wep_cfg *wep;
> + struct gelic_eurus_cmd *cmd;
> + int wep104 = 0;
> + int have_key = 0;
> + int ret = 0;
> +
> + pr_debug("%s: <-\n", __func__);
> + /* we can assume no one should uses the buffer */
> + wep = wl->buf;
> + memset(wep, 0, sizeof(*wep));
> +
> + if (wl->group_cipher_method == GELIC_WL_CIPHER_WEP) {
> + pr_debug("%s: WEP mode\n", __func__);
> + for (i = 0; i < GELIC_WEP_KEYS; i++) {
> + if (!test_bit(i, &wl->key_enabled))
> + continue;
> +
> + pr_debug("%s: key#%d enabled\n", __func__, i);
> + have_key = 1;
> + if (wl->key_len[i] == 13)
> + wep104 = 1;
> + else if (wl->key_len[i] != 5) {
> + pr_info("%s: wrong wep key[%d]=%d\n",
> + __func__, i, wl->key_len[i]);
> + ret = -EINVAL;
> + goto out;
> + }
> + memcpy(wep->key[i], wl->key[i], wl->key_len[i]);
> + }
> +
> + if (!have_key) {
> + pr_info("%s: all wep key disabled\n", __func__);
> + ret = -EINVAL;
> + goto out;
> + }
> +
> + if (wep104) {
> + pr_debug("%s: 104bit key\n", __func__);
> + wep->security = cpu_to_be16(GELIC_EURUS_WEP_SEC_104BIT);
> + } else {
> + pr_debug("%s: 40bit key\n", __func__);
> + wep->security = cpu_to_be16(GELIC_EURUS_WEP_SEC_40BIT);
> + }
> + } else {
> + pr_debug("%s: NO encryption\n", __func__);
> + wep->security = cpu_to_be16(GELIC_EURUS_WEP_SEC_NONE);
> + }
> +
> + /* issue wep setup */
> + cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_SET_WEP_CFG,
> + wep, sizeof(*wep));
> + if (!cmd)
> + ret = -ENOMEM;
> + else if (cmd->status || cmd->cmd_status)
> + ret = -ENXIO;
> +
> + kfree(cmd);
> +out:
> + pr_debug("%s: ->\n", __func__);
> + return ret;
> +}
> +
> +#ifdef DEBUG
> +static const char *wpasecstr(enum gelic_eurus_wpa_security sec)
> +{
> + switch (sec) {
> + case GELIC_EURUS_WPA_SEC_NONE:
> + return "NONE";
> + break;
> + case GELIC_EURUS_WPA_SEC_WPA_TKIP_TKIP:
> + return "WPA_TKIP_TKIP";
> + break;
> + case GELIC_EURUS_WPA_SEC_WPA_TKIP_AES:
> + return "WPA_TKIP_AES";
> + break;
> + case GELIC_EURUS_WPA_SEC_WPA_AES_AES:
> + return "WPA_AES_AES";
> + break;
> + case GELIC_EURUS_WPA_SEC_WPA2_TKIP_TKIP:
> + return "WPA2_TKIP_TKIP";
> + break;
> + case GELIC_EURUS_WPA_SEC_WPA2_TKIP_AES:
> + return "WPA2_TKIP_AES";
> + break;
> + case GELIC_EURUS_WPA_SEC_WPA2_AES_AES:
> + return "WPA2_AES_AES";
> + break;
> + }
> + return "";
> +};
> +#endif
> +
> +static int gelic_wl_do_wpa_setup(struct gelic_wl_info *wl)
> +{
> + struct gelic_eurus_wpa_cfg *wpa;
> + struct gelic_eurus_cmd *cmd;
> + u16 security;
> + int ret = 0;
> +
> + pr_debug("%s: <-\n", __func__);
> + /* we can assume no one should uses the buffer */
> + wpa = wl->buf;
> + memset(wpa, 0, sizeof(*wpa));
> +
> + if (!test_bit(GELIC_WL_STAT_WPA_PSK_SET, &wl->stat))
> + pr_info("%s: PSK not configured yet\n", __func__);
> +
> + /* copy key */
> + memcpy(wpa->psk, wl->psk, wl->psk_len);
> +
> + /* set security level */
> + if (wl->wpa_level == GELIC_WL_WPA_LEVEL_WPA2) {
> + if (wl->group_cipher_method == GELIC_WL_CIPHER_AES) {
> + security = GELIC_EURUS_WPA_SEC_WPA2_AES_AES;
> + } else {
> + if (wl->pairwise_cipher_method == GELIC_WL_CIPHER_AES &&
> + precise_ie())
> + security = GELIC_EURUS_WPA_SEC_WPA2_TKIP_AES;
> + else
> + security = GELIC_EURUS_WPA_SEC_WPA2_TKIP_TKIP;
> + }
> + } else {
> + if (wl->group_cipher_method == GELIC_WL_CIPHER_AES) {
> + security = GELIC_EURUS_WPA_SEC_WPA_AES_AES;
> + } else {
> + if (wl->pairwise_cipher_method == GELIC_WL_CIPHER_AES &&
> + precise_ie())
> + security = GELIC_EURUS_WPA_SEC_WPA_TKIP_AES;
> + else
> + security = GELIC_EURUS_WPA_SEC_WPA_TKIP_TKIP;
> + }
> + }
> + wpa->security = cpu_to_be16(security);
> +
> + /* PSK type */
> + wpa->psk_type = cpu_to_be16(wl->psk_type);
> +#ifdef DEBUG
> + pr_debug("%s: sec=%s psktype=%s\nn", __func__,
> + wpasecstr(wpa->security),
> + (wpa->psk_type == GELIC_EURUS_WPA_PSK_BIN) ?
> + "BIN" : "passphrase");
> +#if 0
> + /*
> + * don't enable here if you plan to submit
> + * the debug log because this dumps your precious
> + * passphrase/key.
> + */
> + pr_debug("%s: psk=%s\n",
> + (wpa->psk_type == GELIC_EURUS_WPA_PSK_BIN) ?
> + (char *)"N/A" : (char *)wpa->psk);
> +#endif
> +#endif
> + /* issue wpa setup */
> + cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_SET_WPA_CFG,
> + wpa, sizeof(*wpa));
> + if (!cmd)
> + ret = -ENOMEM;
> + else if (cmd->status || cmd->cmd_status)
> + ret = -ENXIO;
> + kfree(cmd);
> + pr_debug("%s: --> %d\n", __func__, ret);
> + return ret;
> +}
> +
> +/*
> + * Start association. caller must hold assoc_stat_lock
> + */
> +static int gelic_wl_associate_bss(struct gelic_wl_info *wl,
> + struct gelic_wl_scan_info *bss)
> +{
> + struct gelic_eurus_cmd *cmd;
> + struct gelic_eurus_common_cfg *common;
> + int ret = 0;
> + unsigned long rc;
> +
> + pr_debug("%s: <-\n", __func__);
> +
> + /* do common config */
> + common = wl->buf;
> + memset(common, 0, sizeof(*common));
> + common->bss_type = cpu_to_be16(GELIC_EURUS_BSS_INFRA);
> + common->op_mode = cpu_to_be16(GELIC_EURUS_OPMODE_11BG);
> +
> + common->scan_index = cpu_to_be16(bss->eurus_index);
> + switch (wl->auth_method) {
> + case GELIC_EURUS_AUTH_OPEN:
> + common->auth_method = cpu_to_be16(GELIC_EURUS_AUTH_OPEN);
> + break;
> + case GELIC_EURUS_AUTH_SHARED:
> + common->auth_method = cpu_to_be16(GELIC_EURUS_AUTH_SHARED);
> + break;
> + }
> +
> +#ifdef DEBUG
> + scan_list_dump(wl);
> +#endif
> + pr_debug("%s: common cfg index=%d bsstype=%d auth=%d\n", __func__,
> + be16_to_cpu(common->scan_index),
> + be16_to_cpu(common->bss_type),
> + be16_to_cpu(common->auth_method));
> +
> + cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_SET_COMMON_CFG,
> + common, sizeof(*common));
> + if (!cmd || cmd->status || cmd->cmd_status) {
> + ret = -ENOMEM;
> + kfree(cmd);
> + goto out;
> + }
> + kfree(cmd);
> +
> + /* WEP/WPA */
> + switch (wl->wpa_level) {
> + case GELIC_WL_WPA_LEVEL_NONE:
> + /* If WEP or no security, setup WEP config */
> + ret = gelic_wl_do_wep_setup(wl);
> + break;
> + case GELIC_WL_WPA_LEVEL_WPA:
> + case GELIC_WL_WPA_LEVEL_WPA2:
> + ret = gelic_wl_do_wpa_setup(wl);
> + break;
> + };
> +
> + if (ret) {
> + pr_debug("%s: WEP/WPA setup failed %d\n", __func__,
> + ret);
> + }
> +
> + /* start association */
> + init_completion(&wl->assoc_done);
> + wl->assoc_stat = GELIC_WL_ASSOC_STAT_ASSOCIATING;
> + cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_ASSOC,
> + NULL, 0);
> + if (!cmd || cmd->status || cmd->cmd_status) {
> + pr_debug("%s: assoc request failed\n", __func__);
> + wl->assoc_stat = GELIC_WL_ASSOC_STAT_DISCONN;
> + kfree(cmd);
> + ret = -ENOMEM;
> + gelic_wl_send_iwap_event(wl, NULL);
> + goto out;
> + }
> + kfree(cmd);
> +
> + /* wait for connected event */
> + rc = wait_for_completion_timeout(&wl->assoc_done, HZ * 4);/*FIXME*/
> +
> + if (!rc) {
> + /* timeouted. Maybe key or cyrpt mode is wrong */
> + pr_info("%s: connect timeout \n", __func__);
> + cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_DISASSOC,
> + NULL, 0);
> + kfree(cmd);
> + wl->assoc_stat = GELIC_WL_ASSOC_STAT_DISCONN;
> + gelic_wl_send_iwap_event(wl, NULL);
> + ret = -ENXIO;
> + } else {
> + wl->assoc_stat = GELIC_WL_ASSOC_STAT_ASSOCIATED;
> + /* copy bssid */
> + memcpy(wl->active_bssid, &bss->hwinfo->bssid[2], ETH_ALEN);
> +
> + /* send connect event */
> + gelic_wl_send_iwap_event(wl, wl->active_bssid);
> + pr_info("%s: connected\n", __func__);
> + }
> +out:
> + pr_debug("%s: ->\n", __func__);
> + return ret;
> +}
> +
> +/*
> + * connected event
> + */
> +static void gelic_wl_connected_event(struct gelic_wl_info *wl,
> + u64 event)
> +{
> + u64 desired_event = 0;
> +
> + switch (wl->wpa_level) {
> + case GELIC_WL_WPA_LEVEL_NONE:
> + desired_event = GELIC_LV1_WL_EVENT_CONNECTED;
> + break;
> + case GELIC_WL_WPA_LEVEL_WPA:
> + case GELIC_WL_WPA_LEVEL_WPA2:
> + desired_event = GELIC_LV1_WL_EVENT_WPA_CONNECTED;
> + break;
> + }
> +
> + if (desired_event == event) {
> + pr_debug("%s: completed \n", __func__);
> + complete(&wl->assoc_done);
> + netif_carrier_on(port_to_netdev(wl_port(wl)));
> + } else
> + pr_debug("%s: event %#lx under wpa\n",
> + __func__, event);
> +}
> +
> +/*
> + * disconnect event
> + */
> +static void gelic_wl_disconnect_event(struct gelic_wl_info *wl,
> + u64 event)
> +{
> + struct gelic_eurus_cmd *cmd;
> + int lock;
> +
> + /*
> + * If we fall here in the middle of association,
> + * associate_bss() should be waiting for complation of
> + * wl->assoc_done.
> + * As it waits with timeout, just leave assoc_done
> + * uncompleted, then it terminates with timeout
> + */
> + if (down_trylock(&wl->assoc_stat_lock)) {
> + pr_debug("%s: already locked\n", __func__);
> + lock = 0;
> + } else {
> + pr_debug("%s: obtain lock\n", __func__);
> + lock = 1;
> + }
> +
> + cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_DISASSOC, NULL, 0);
> + kfree(cmd);
> +
> + /* send disconnected event to the supplicant */
> + if (wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED)
> + gelic_wl_send_iwap_event(wl, NULL);
> +
> + wl->assoc_stat = GELIC_WL_ASSOC_STAT_DISCONN;
> + netif_carrier_off(port_to_netdev(wl_port(wl)));
> +
> + if (lock)
> + up(&wl->assoc_stat_lock);
> +}
> +/*
> + * event worker
> + */
> +#ifdef DEBUG
> +static const char *eventstr(enum gelic_lv1_wl_event event)
> +{
> + static char buf[32];
> + char *ret;
> + if (event & GELIC_LV1_WL_EVENT_DEVICE_READY)
> + ret = "EURUS_READY";
> + else if (event & GELIC_LV1_WL_EVENT_SCAN_COMPLETED)
> + ret = "SCAN_COMPLETED";
> + else if (event & GELIC_LV1_WL_EVENT_DEAUTH)
> + ret = "DEAUTH";
> + else if (event & GELIC_LV1_WL_EVENT_BEACON_LOST)
> + ret = "BEACON_LOST";
> + else if (event & GELIC_LV1_WL_EVENT_CONNECTED)
> + ret = "CONNECTED";
> + else if (event & GELIC_LV1_WL_EVENT_WPA_CONNECTED)
> + ret = "WPA_CONNECTED";
> + else if (event & GELIC_LV1_WL_EVENT_WPA_ERROR)
> + ret = "WPA_ERROR";
> + else {
> + sprintf(buf, "Unknown(%#x)", event);
> + ret = buf;
> + }
> + return ret;
> +}
> +#else
> +static const char *eventstr(enum gelic_lv1_wl_event event)
> +{
> + return NULL;
> +}
> +#endif
> +static void gelic_wl_event_worker(struct work_struct *work)
> +{
> + struct gelic_wl_info *wl;
> + struct gelic_port *port;
> + u64 event, tmp;
> + int status;
> +
> + pr_debug("%s:start\n", __func__);
> + wl = container_of(work, struct gelic_wl_info, event_work.work);
> + port = wl_port(wl);
> + while (1) {
> + status = lv1_net_control(bus_id(port->card), dev_id(port->card),
> + GELIC_LV1_GET_WLAN_EVENT, 0, 0, 0,
> + &event, &tmp);
> + if (status) {
> + if (status != LV1_NO_ENTRY)
> + pr_debug("%s:wlan event failed %d\n",
> + __func__, status);
> + /* got all events */
> + pr_debug("%s:end\n", __func__);
> + return;
> + }
> + pr_debug("%s: event=%s\n", __func__, eventstr(event));
> + switch (event) {
> + case GELIC_LV1_WL_EVENT_SCAN_COMPLETED:
> + gelic_wl_scan_complete_event(wl);
> + break;
> + case GELIC_LV1_WL_EVENT_BEACON_LOST:
> + case GELIC_LV1_WL_EVENT_DEAUTH:
> + gelic_wl_disconnect_event(wl, event);
> + break;
> + case GELIC_LV1_WL_EVENT_CONNECTED:
> + case GELIC_LV1_WL_EVENT_WPA_CONNECTED:
> + gelic_wl_connected_event(wl, event);
> + break;
> + default:
> + break;
> + }
> + } /* while */
> +}
> +/*
> + * association worker
> + */
> +static void gelic_wl_assoc_worker(struct work_struct *work)
> +{
> + struct gelic_wl_info *wl;
> +
> + struct gelic_wl_scan_info *best_bss;
> + int ret;
> +
> + wl = container_of(work, struct gelic_wl_info, assoc_work.work);
> +
> + down(&wl->assoc_stat_lock);
> +
> + if (wl->assoc_stat != GELIC_WL_ASSOC_STAT_DISCONN)
> + goto out;
> +
> + ret = gelic_wl_start_scan(wl, 0);
> + if (ret == -ERESTARTSYS) {
> + pr_debug("%s: scan start failed association\n", __func__);
> + schedule_delayed_work(&wl->assoc_work, HZ/10); /*FIXME*/
> + goto out;
> + } else if (ret) {
> + pr_info("%s: scan prerequisite failed\n", __func__);
> + goto out;
> + }
> +
> + /*
> + * Wait for bss scan completion
> + * If we have scan list already, gelic_wl_start_scan()
> + * returns OK and raises the complete. Thus,
> + * it's ok to wait unconditionally here
> + */
> + wait_for_completion(&wl->scan_done);
> +
> + pr_debug("%s: scan done\n", __func__);
> + down(&wl->scan_lock);
> + if (wl->scan_stat != GELIC_WL_SCAN_STAT_GOT_LIST) {
> + gelic_wl_send_iwap_event(wl, NULL);
> + pr_info("%s: no scan list. association failed\n", __func__);
> + goto scan_lock_out;
> + }
> +
> + /* find best matching bss */
> + best_bss = gelic_wl_find_best_bss(wl);
> + if (!best_bss) {
> + gelic_wl_send_iwap_event(wl, NULL);
> + pr_info("%s: no bss matched. association failed\n", __func__);
> + goto scan_lock_out;
> + }
> +
> + /* ok, do association */
> + ret = gelic_wl_associate_bss(wl, best_bss);
> + if (ret)
> + pr_info("%s: association failed %d\n", __func__, ret);
> +scan_lock_out:
> + up(&wl->scan_lock);
> +out:
> + up(&wl->assoc_stat_lock);
> +}
> +/*
> + * Interrupt handler
> + * Called from the ethernet interrupt handler
> + * Processes wireless specific virtual interrupts only
> + */
> +void gelic_wl_interrupt(struct net_device *netdev, u64 status)
> +{
> + struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
> +
> + if (status & GELIC_CARD_WLAN_COMMAND_COMPLETED) {
> + pr_debug("%s:cmd complete\n", __func__);
> + complete(&wl->cmd_done_intr);
> + }
> +
> + if (status & GELIC_CARD_WLAN_EVENT_RECEIVED) {
> + pr_debug("%s:event received\n", __func__);
> + queue_delayed_work(wl->event_queue, &wl->event_work, 0);
> + }
> +}
> +
> +/*
> + * driver helpers
> + */
> +#define IW_IOCTL(n) [(n) - SIOCSIWCOMMIT]
> +static const iw_handler gelic_wl_wext_handler[] =
> +{
> + IW_IOCTL(SIOCGIWNAME) = gelic_wl_get_name,
> + IW_IOCTL(SIOCGIWRANGE) = gelic_wl_get_range,
> + IW_IOCTL(SIOCSIWSCAN) = gelic_wl_set_scan,
> + IW_IOCTL(SIOCGIWSCAN) = gelic_wl_get_scan,
> + IW_IOCTL(SIOCSIWAUTH) = gelic_wl_set_auth,
> + IW_IOCTL(SIOCGIWAUTH) = gelic_wl_get_auth,
> + IW_IOCTL(SIOCSIWESSID) = gelic_wl_set_essid,
> + IW_IOCTL(SIOCGIWESSID) = gelic_wl_get_essid,
> + IW_IOCTL(SIOCSIWENCODE) = gelic_wl_set_encode,
> + IW_IOCTL(SIOCGIWENCODE) = gelic_wl_get_encode,
> + IW_IOCTL(SIOCSIWAP) = gelic_wl_set_ap,
> + IW_IOCTL(SIOCGIWAP) = gelic_wl_get_ap,
> + IW_IOCTL(SIOCSIWENCODEEXT) = gelic_wl_set_encodeext,
> + IW_IOCTL(SIOCGIWENCODEEXT) = gelic_wl_get_encodeext,
> + IW_IOCTL(SIOCSIWMODE) = gelic_wl_set_mode,
> + IW_IOCTL(SIOCGIWMODE) = gelic_wl_get_mode,
> + IW_IOCTL(SIOCGIWNICKN) = gelic_wl_get_nick,
> +};
> +
> +static struct iw_priv_args gelic_wl_private_args[] =
> +{
> + {
> + .cmd = GELIC_WL_PRIV_SET_PSK,
> + .set_args = IW_PRIV_TYPE_CHAR |
> + (GELIC_WL_EURUS_PSK_MAX_LEN + 2),
> + .name = "set_psk"
> + },
> + {
> + .cmd = GELIC_WL_PRIV_GET_PSK,
> + .get_args = IW_PRIV_TYPE_CHAR |
> + (GELIC_WL_EURUS_PSK_MAX_LEN + 2),
> + .name = "get_psk"
> + }
> +};
> +
> +static const iw_handler gelic_wl_private_handler[] =
> +{
> + gelic_wl_priv_set_psk,
> + gelic_wl_priv_get_psk,
> +};
> +
> +static const struct iw_handler_def gelic_wl_wext_handler_def = {
> + .num_standard = ARRAY_SIZE(gelic_wl_wext_handler),
> + .standard = gelic_wl_wext_handler,
> + .get_wireless_stats = gelic_wl_get_wireless_stats,
> + .num_private = ARRAY_SIZE(gelic_wl_private_handler),
> + .num_private_args = ARRAY_SIZE(gelic_wl_private_args),
> + .private = gelic_wl_private_handler,
> + .private_args = gelic_wl_private_args,
> +};
> +
> +static struct net_device *gelic_wl_alloc(struct gelic_card *card)
> +{
> + struct net_device *netdev;
> + struct gelic_port *port;
> + struct gelic_wl_info *wl;
> + unsigned int i;
> +
> + pr_debug("%s:start\n", __func__);
> + netdev = alloc_etherdev(sizeof(struct gelic_port) +
> + sizeof(struct gelic_wl_info));
> + pr_debug("%s: netdev =%p card=%p \np", __func__, netdev, card);
> + if (!netdev)
> + return NULL;
> +
> + port = netdev_priv(netdev);
> + port->netdev = netdev;
> + port->card = card;
> + port->type = GELIC_PORT_WIRELESS;
> +
> + wl = port_wl(port);
> + pr_debug("%s: wl=%p port=%p\n", __func__, wl, port);
> +
> + /* allocate scan list */
> + wl->networks = kzalloc(sizeof(struct gelic_wl_scan_info) *
> + GELIC_WL_BSS_MAX_ENT, GFP_KERNEL);
> +
> + if (!wl->networks)
> + goto fail_bss;
> +
> + wl->eurus_cmd_queue = create_singlethread_workqueue("gelic_cmd");
> + if (!wl->eurus_cmd_queue)
> + goto fail_cmd_workqueue;
> +
> + wl->event_queue = create_singlethread_workqueue("gelic_event");
> + if (!wl->event_queue)
> + goto fail_event_workqueue;
> +
> + INIT_LIST_HEAD(&wl->network_free_list);
> + INIT_LIST_HEAD(&wl->network_list);
> + for (i = 0; i < GELIC_WL_BSS_MAX_ENT; i++)
> + list_add_tail(&wl->networks[i].list,
> + &wl->network_free_list);
> + init_completion(&wl->cmd_done_intr);
> +
> + INIT_DELAYED_WORK(&wl->event_work, gelic_wl_event_worker);
> + INIT_DELAYED_WORK(&wl->assoc_work, gelic_wl_assoc_worker);
> + init_MUTEX(&wl->scan_lock);
> + init_MUTEX(&wl->assoc_stat_lock);
> +
> + init_completion(&wl->scan_done);
> + /* for the case that no scan request is issued and stop() is called */
> + complete(&wl->scan_done);
> +
> + spin_lock_init(&wl->lock);
> +
> + wl->scan_age = 5*HZ; /* FIXME */
> +
> + /* buffer for receiving scanned list etc */
> + BUILD_BUG_ON(PAGE_SIZE <
> + sizeof(struct gelic_eurus_scan_info) *
> + GELIC_EURUS_MAX_SCAN);
> + wl->buf = (void *)get_zeroed_page(GFP_KERNEL);
> + if (!wl->buf) {
> + pr_info("%s:buffer allocation failed\n", __func__);
> + goto fail_getpage;
> + }
> + pr_debug("%s:end\n", __func__);
> + return netdev;
> +
> +fail_getpage:
> + destroy_workqueue(wl->event_queue);
> +fail_event_workqueue:
> + destroy_workqueue(wl->eurus_cmd_queue);
> +fail_cmd_workqueue:
> + kfree(wl->networks);
> +fail_bss:
> + free_netdev(netdev);
> + pr_debug("%s:end error\n", __func__);
> + return NULL;
> +
> +}
> +
> +static void gelic_wl_free(struct gelic_wl_info *wl)
> +{
> + struct gelic_wl_scan_info *scan_info;
> + unsigned int i;
> +
> + pr_debug("%s: <-\n", __func__);
> +
> + pr_debug("%s: destroy queues\n", __func__);
> + destroy_workqueue(wl->eurus_cmd_queue);
> + destroy_workqueue(wl->event_queue);
> +
> + scan_info = wl->networks;
> + for (i = 0; i < GELIC_WL_BSS_MAX_ENT; i++, scan_info++)
> + kfree(scan_info->hwinfo);
> + kfree(wl->networks);
> +
> + free_netdev(port_to_netdev(wl_port(wl)));
> +
> + pr_debug("%s: ->\n", __func__);
> +}
> +
> +static int gelic_wl_try_associate(struct net_device *netdev)
> +{
> + struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
> + int ret = -1;
> + unsigned int i;
> +
> + pr_debug("%s: <-\n", __func__);
> +
> + /* check constraits for start association */
> + /* for no access restriction AP */
> + if (wl->group_cipher_method == GELIC_WL_CIPHER_NONE) {
> + if (test_bit(GELIC_WL_STAT_CONFIGURED,
> + &wl->stat))
> + goto do_associate;
> + else {
> + pr_debug("%s: no wep, not configured\n", __func__);
> + return ret;
> + }
> + }
> +
> + /* for WEP, one of four keys should be set */
> + if (wl->group_cipher_method == GELIC_WL_CIPHER_WEP) {
> + /* one of keys set */
> + for (i = 0; i < GELIC_WEP_KEYS; i++) {
> + if (test_bit(i, &wl->key_enabled))
> + goto do_associate;
> + }
> + pr_debug("%s: WEP, but no key specified\n", __func__);
> + return ret;
> + }
> +
> + /* for WPA[2], psk should be set */
> + if ((wl->group_cipher_method == GELIC_WL_CIPHER_TKIP) ||
> + (wl->group_cipher_method == GELIC_WL_CIPHER_AES)) {
> + if (test_bit(GELIC_WL_STAT_WPA_PSK_SET,
> + &wl->stat))
> + goto do_associate;
> + else {
> + pr_debug("%s: AES/TKIP, but PSK not configured\n",
> + __func__);
> + return ret;
> + }
> + }
> +
> +do_associate:
> + ret = schedule_delayed_work(&wl->assoc_work, 0);
> + pr_debug("%s: start association work %d\n", __func__, ret);
> + return ret;
> +}
> +
> +/*
> + * netdev handlers
> + */
> +static int gelic_wl_open(struct net_device *netdev)
> +{
> + struct gelic_card *card = netdev_card(netdev);
> +
> + pr_debug("%s:->%p\n", __func__, netdev);
> +
> + gelic_card_up(card);
> +
> + /* try to associate */
> + gelic_wl_try_associate(netdev);
> +
> + netif_start_queue(netdev);
> +
> + pr_debug("%s:<-\n", __func__);
> + return 0;
> +}
> +
> +/*
> + * reset state machine
> + */
> +static int gelic_wl_reset_state(struct gelic_wl_info *wl)
> +{
> + struct gelic_wl_scan_info *target;
> + struct gelic_wl_scan_info *tmp;
> +
> + /* empty scan list */
> + list_for_each_entry_safe(target, tmp, &wl->network_list, list) {
> + list_move_tail(&target->list, &wl->network_free_list);
> + }
> + wl->scan_stat = GELIC_WL_SCAN_STAT_INIT;
> +
> + /* clear configuration */
> + wl->auth_method = GELIC_EURUS_AUTH_OPEN;
> + wl->group_cipher_method = GELIC_WL_CIPHER_NONE;
> + wl->pairwise_cipher_method = GELIC_WL_CIPHER_NONE;
> + wl->wpa_level = GELIC_WL_WPA_LEVEL_NONE;
> +
> + wl->key_enabled = 0;
> + wl->current_key = 0;
> +
> + wl->psk_type = GELIC_EURUS_WPA_PSK_PASSPHRASE;
> + wl->psk_len = 0;
> +
> + wl->essid_len = 0;
> + memset(wl->essid, 0, sizeof(wl->essid));
> + memset(wl->bssid, 0, sizeof(wl->bssid));
> + memset(wl->active_bssid, 0, sizeof(wl->active_bssid));
> +
> + wl->assoc_stat = GELIC_WL_ASSOC_STAT_DISCONN;
> +
> + memset(&wl->iwstat, 0, sizeof(wl->iwstat));
> + /* all status bit clear */
> + wl->stat = 0;
> + return 0;
> +}
> +
> +/*
> + * Tell eurus to terminate association
> + */
> +static void gelic_wl_disconnect(struct net_device *netdev)
> +{
> + struct gelic_port *port = netdev_priv(netdev);
> + struct gelic_wl_info *wl = port_wl(port);
> + struct gelic_eurus_cmd *cmd;
> +
> + /*
> + * If scann process is running on chip,
> + * further requests will be rejected
> + */
> + if (wl->scan_stat == GELIC_WL_SCAN_STAT_SCANNING)
> + wait_for_completion_timeout(&wl->scan_done, HZ);
> +
> + cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_DISASSOC, NULL, 0);
> + kfree(cmd);
> + gelic_wl_send_iwap_event(wl, NULL);
> +};
> +
> +static int gelic_wl_stop(struct net_device *netdev)
> +{
> + struct gelic_port *port = netdev_priv(netdev);
> + struct gelic_wl_info *wl = port_wl(port);
> + struct gelic_card *card = netdev_card(netdev);
> +
> + pr_debug("%s:<-\n", __func__);
> +
> + /*
> + * Cancel pending association work.
> + * event work can run after netdev down
> + */
> + cancel_delayed_work(&wl->assoc_work);
> +
> + if (wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED)
> + gelic_wl_disconnect(netdev);
> +
> + /* reset our state machine */
> + gelic_wl_reset_state(wl);
> +
> + netif_stop_queue(netdev);
> +
> + gelic_card_down(card);
> +
> + pr_debug("%s:->\n", __func__);
> + return 0;
> +}
> +
> +/* -- */
> +
> +static struct ethtool_ops gelic_wl_ethtool_ops = {
> + .get_drvinfo = gelic_net_get_drvinfo,
> + .get_link = gelic_wl_get_link,
> + .get_tx_csum = ethtool_op_get_tx_csum,
> + .set_tx_csum = ethtool_op_set_tx_csum,
> + .get_rx_csum = gelic_net_get_rx_csum,
> + .set_rx_csum = gelic_net_set_rx_csum,
> +};
> +
> +static void gelic_wl_setup_netdev_ops(struct net_device *netdev)
> +{
> + struct gelic_wl_info *wl;
> + wl = port_wl(netdev_priv(netdev));
> + BUG_ON(!wl);
> + netdev->open = &gelic_wl_open;
> + netdev->stop = &gelic_wl_stop;
> + netdev->hard_start_xmit = &gelic_net_xmit;
> + netdev->set_multicast_list = &gelic_net_set_multi;
> + netdev->change_mtu = &gelic_net_change_mtu;
> + netdev->wireless_data = &wl->wireless_data;
> + netdev->wireless_handlers = &gelic_wl_wext_handler_def;
> + /* tx watchdog */
> + netdev->tx_timeout = &gelic_net_tx_timeout;
> + netdev->watchdog_timeo = GELIC_NET_WATCHDOG_TIMEOUT;
> +
> + netdev->ethtool_ops = &gelic_wl_ethtool_ops;
> +#ifdef CONFIG_NET_POLL_CONTROLLER
> + netdev->poll_controller = gelic_net_poll_controller;
> +#endif
> +}
> +
> +/*
> + * driver probe/remove
> + */
> +int gelic_wl_driver_probe(struct gelic_card *card)
> +{
> + int ret;
> + struct net_device *netdev;
> +
> + pr_debug("%s:start\n", __func__);
> +
> + if (ps3_compare_firmware_version(1, 6, 0) < 0)
> + return 0;
> + if (!card->vlan[GELIC_PORT_WIRELESS].tx)
> + return 0;
> +
> + /* alloc netdevice for wireless */
> + netdev = gelic_wl_alloc(card);
> + if (!netdev)
> + return -ENOMEM;
> +
> + /* setup net_device structure */
> + gelic_wl_setup_netdev_ops(netdev);
> +
> + /* setup some of net_device and register it */
> + ret = gelic_net_setup_netdev(netdev, card);
> + if (ret)
> + goto fail_setup;
> + card->netdev[GELIC_PORT_WIRELESS] = netdev;
> +
> + /* add enable wireless interrupt */
> + card->irq_mask |= GELIC_CARD_WLAN_EVENT_RECEIVED |
> + GELIC_CARD_WLAN_COMMAND_COMPLETED;
> + /* to allow wireless commands while both interfaces are down */
> + gelic_card_set_irq_mask(card, GELIC_CARD_WLAN_EVENT_RECEIVED |
> + GELIC_CARD_WLAN_COMMAND_COMPLETED);
> + pr_debug("%s:end\n", __func__);
> + return 0;
> +
> +fail_setup:
> + gelic_wl_free(port_wl(netdev_port(netdev)));
> +
> + return ret;
> +}
> +
> +int gelic_wl_driver_remove(struct gelic_card *card)
> +{
> + struct gelic_wl_info *wl;
> + struct net_device *netdev;
> +
> + pr_debug("%s:start\n", __func__);
> +
> + if (ps3_compare_firmware_version(1, 6, 0) < 0)
> + return 0;
> + if (!card->vlan[GELIC_PORT_WIRELESS].tx)
> + return 0;
> +
> + netdev = card->netdev[GELIC_PORT_WIRELESS];
> + wl = port_wl(netdev_priv(netdev));
> +
> + /* if the interface was not up, but associated */
> + if (wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED)
> + gelic_wl_disconnect(netdev);
> +
> + complete(&wl->cmd_done_intr);
> +
> + /* cancel all work queue */
> + cancel_delayed_work(&wl->assoc_work);
> + cancel_delayed_work(&wl->event_work);
> + flush_workqueue(wl->eurus_cmd_queue);
> + flush_workqueue(wl->event_queue);
> +
> + unregister_netdev(netdev);
> +
> + /* disable wireless interrupt */
> + pr_debug("%s: disable intr\n", __func__);
> + card->irq_mask &= ~(GELIC_CARD_WLAN_EVENT_RECEIVED |
> + GELIC_CARD_WLAN_COMMAND_COMPLETED);
> + /* free bss list, netdev*/
> + gelic_wl_free(wl);
> + pr_debug("%s:end\n", __func__);
> + return 0;
> +}
> --- /dev/null
> +++ b/drivers/net/ps3_gelic_wireless.h
> @@ -0,0 +1,329 @@
> +/*
> + * PS3 gelic network driver.
> + *
> + * Copyright (C) 2007 Sony Computer Entertainment Inc.
> + * Copyright 2007 Sony Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation version 2.
> + *
> + * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +#ifndef _GELIC_WIRELESS_H
> +#define _GELIC_WIRELESS_H
> +
> +#include <linux/wireless.h>
> +#include <net/iw_handler.h>
> +
> +
> +/* return value from GELIC_LV1_GET_WLAN_EVENT netcontrol */
> +enum gelic_lv1_wl_event {
> + GELIC_LV1_WL_EVENT_DEVICE_READY = 0x01, /* Eurus ready */
> + GELIC_LV1_WL_EVENT_SCAN_COMPLETED = 0x02, /* Scan has completed */
> + GELIC_LV1_WL_EVENT_DEAUTH = 0x04, /* Deauthed by the AP */
> + GELIC_LV1_WL_EVENT_BEACON_LOST = 0x08, /* Beacon lost detected */
> + GELIC_LV1_WL_EVENT_CONNECTED = 0x10, /* Connected to AP */
> + GELIC_LV1_WL_EVENT_WPA_CONNECTED = 0x20, /* WPA connection */
> + GELIC_LV1_WL_EVENT_WPA_ERROR = 0x40, /* MIC error */
> +};
> +
> +/* arguments for GELIC_LV1_POST_WLAN_COMMAND netcontrol */
> +enum gelic_eurus_command {
> + GELIC_EURUS_CMD_ASSOC = 1, /* association start */
> + GELIC_EURUS_CMD_DISASSOC = 2, /* disassociate */
> + GELIC_EURUS_CMD_START_SCAN = 3, /* scan start */
> + GELIC_EURUS_CMD_GET_SCAN = 4, /* get scan result */
> + GELIC_EURUS_CMD_SET_COMMON_CFG = 5, /* set common config */
> + GELIC_EURUS_CMD_GET_COMMON_CFG = 6, /* set common config */
> + GELIC_EURUS_CMD_SET_WEP_CFG = 7, /* set WEP config */
> + GELIC_EURUS_CMD_GET_WEP_CFG = 8, /* get WEP config */
> + GELIC_EURUS_CMD_SET_WPA_CFG = 9, /* set WPA config */
> + GELIC_EURUS_CMD_GET_WPA_CFG = 10, /* get WPA config */
> + GELIC_EURUS_CMD_GET_RSSI_CFG = 11, /* get RSSI info. */
> + GELIC_EURUS_CMD_MAX_INDEX
> +};
> +
> +/* for GELIC_EURUS_CMD_COMMON_CFG */
> +enum gelic_eurus_bss_type {
> + GELIC_EURUS_BSS_INFRA = 0,
> + GELIC_EURUS_BSS_ADHOC = 1, /* not supported */
> +};
> +
> +enum gelic_eurus_auth_method {
> + GELIC_EURUS_AUTH_OPEN = 0, /* FIXME: WLAN_AUTH_OPEN */
> + GELIC_EURUS_AUTH_SHARED = 1, /* not supported */
> +};
> +
> +enum gelic_eurus_opmode {
> + GELIC_EURUS_OPMODE_11BG = 0, /* 802.11b/g */
> + GELIC_EURUS_OPMODE_11B = 1, /* 802.11b only */
> + GELIC_EURUS_OPMODE_11G = 2, /* 802.11g only */
> +};
> +
> +struct gelic_eurus_common_cfg {
> + /* all fields are big endian */
> + u16 scan_index;
> + u16 bss_type; /* infra or adhoc */
> + u16 auth_method; /* shared key or open */
> + u16 op_mode; /* B/G */
> +} __attribute__((packed));
> +
> +
> +/* for GELIC_EURUS_CMD_WEP_CFG */
> +enum gelic_eurus_wep_security {
> + GELIC_EURUS_WEP_SEC_NONE = 0,
> + GELIC_EURUS_WEP_SEC_40BIT = 1,
> + GELIC_EURUS_WEP_SEC_104BIT = 2,
> +};
> +
> +struct gelic_eurus_wep_cfg {
> + /* all fields are big endian */
> + u16 security;
> + u8 key[4][16];
> +} __attribute__((packed));
> +
> +/* for GELIC_EURUS_CMD_WPA_CFG */
> +enum gelic_eurus_wpa_security {
> + GELIC_EURUS_WPA_SEC_NONE = 0x0000,
> + /* group=TKIP, pairwise=TKIP */
> + GELIC_EURUS_WPA_SEC_WPA_TKIP_TKIP = 0x0001,
> + /* group=AES, pairwise=AES */
> + GELIC_EURUS_WPA_SEC_WPA_AES_AES = 0x0002,
> + /* group=TKIP, pairwise=TKIP */
> + GELIC_EURUS_WPA_SEC_WPA2_TKIP_TKIP = 0x0004,
> + /* group=AES, pairwise=AES */
> + GELIC_EURUS_WPA_SEC_WPA2_AES_AES = 0x0008,
> + /* group=TKIP, pairwise=AES */
> + GELIC_EURUS_WPA_SEC_WPA_TKIP_AES = 0x0010,
> + /* group=TKIP, pairwise=AES */
> + GELIC_EURUS_WPA_SEC_WPA2_TKIP_AES = 0x0020,
> +};
> +
> +enum gelic_eurus_wpa_psk_type {
> + GELIC_EURUS_WPA_PSK_PASSPHRASE = 0, /* passphrase string */
> + GELIC_EURUS_WPA_PSK_BIN = 1, /* 32 bytes binary key */
> +};
> +
> +#define GELIC_WL_EURUS_PSK_MAX_LEN 64
> +#define WPA_PSK_LEN 32 /* WPA spec says 256bit */
> +
> +struct gelic_eurus_wpa_cfg {
> + /* all fields are big endian */
> + u16 security;
> + u16 psk_type; /* psk key encoding type */
> + u8 psk[GELIC_WL_EURUS_PSK_MAX_LEN]; /* psk key; hex or passphrase */
> +} __attribute__((packed));
> +
> +/* for GELIC_EURUS_CMD_{START,GET}_SCAN */
> +enum gelic_eurus_scan_capability {
> + GELIC_EURUS_SCAN_CAP_ADHOC = 0x0000,
> + GELIC_EURUS_SCAN_CAP_INFRA = 0x0001,
> + GELIC_EURUS_SCAN_CAP_MASK = 0x0001,
> +};
> +
> +enum gelic_eurus_scan_sec_type {
> + GELIC_EURUS_SCAN_SEC_NONE = 0x0000,
> + GELIC_EURUS_SCAN_SEC_WEP = 0x0100,
> + GELIC_EURUS_SCAN_SEC_WPA = 0x0200,
> + GELIC_EURUS_SCAN_SEC_WPA2 = 0x0400,
> + GELIC_EURUS_SCAN_SEC_MASK = 0x0f00,
> +};
> +
> +enum gelic_eurus_scan_sec_wep_type {
> + GELIC_EURUS_SCAN_SEC_WEP_UNKNOWN = 0x0000,
> + GELIC_EURUS_SCAN_SEC_WEP_40 = 0x0001,
> + GELIC_EURUS_SCAN_SEC_WEP_104 = 0x0002,
> + GELIC_EURUS_SCAN_SEC_WEP_MASK = 0x0003,
> +};
> +
> +enum gelic_eurus_scan_sec_wpa_type {
> + GELIC_EURUS_SCAN_SEC_WPA_UNKNOWN = 0x0000,
> + GELIC_EURUS_SCAN_SEC_WPA_TKIP = 0x0001,
> + GELIC_EURUS_SCAN_SEC_WPA_AES = 0x0002,
> + GELIC_EURUS_SCAN_SEC_WPA_MASK = 0x0003,
> +};
> +
> +/*
> + * hw BSS information structure returned from GELIC_EURUS_CMD_GET_SCAN
> + */
> +struct gelic_eurus_scan_info {
> + /* all fields are big endian */
> + __be16 size;
> + __be16 rssi; /* percentage */
> + __be16 channel; /* channel number */
> + __be16 beacon_period; /* FIXME: in msec unit */
> + __be16 capability;
> + __be16 security;
> + u8 bssid[8]; /* last ETH_ALEN are valid. bssid[0],[1] are unused */
> + u8 essid[32]; /* IW_ESSID_MAX_SIZE */
> + u8 rate[16]; /* first MAX_RATES_LENGTH(12) are valid */
> + u8 ext_rate[16]; /* first MAX_RATES_EX_LENGTH(16) are valid */
> + __be32 reserved1;
> + __be32 reserved2;
> + __be32 reserved3;
> + __be32 reserved4;
> + u8 elements[0]; /* ie */
> +} __attribute__ ((packed));
> +
> +/* the hypervisor returns bbs up to 16 */
> +#define GELIC_EURUS_MAX_SCAN (16)
> +struct gelic_wl_scan_info {
> + struct list_head list;
> + struct gelic_eurus_scan_info *hwinfo;
> +
> + int valid; /* set 1 if this entry was in latest scanned list
> + * from Eurus */
> + unsigned int eurus_index; /* index in the Eurus list */
> + unsigned long last_scanned; /* acquired time */
> +
> + unsigned int rate_len;
> + unsigned int rate_ext_len;
> + unsigned int essid_len;
> +};
> +
> +/* for GELIC_EURUS_CMD_GET_RSSI */
> +struct gelic_eurus_rssi_info {
> + /* big endian */
> + __be16 rssi;
> +} __attribute__ ((packed));
> +
> +
> +/* for 'stat' member of gelic_wl_info */
> +enum gelic_wl_info_status_bit {
> + GELIC_WL_STAT_CONFIGURED,
> + GELIC_WL_STAT_CH_INFO, /* ch info aquired */
> + GELIC_WL_STAT_ESSID_SET, /* ESSID specified by userspace */
> + GELIC_WL_STAT_BSSID_SET, /* BSSID specified by userspace */
> + GELIC_WL_STAT_WPA_PSK_SET, /* PMK specified by userspace */
> + GELIC_WL_STAT_WPA_LEVEL_SET, /* WEP or WPA[2] selected */
> +};
> +
> +/* for 'scan_stat' member of gelic_wl_info */
> +enum gelic_wl_scan_state {
> + /* just initialized or get last scan result failed */
> + GELIC_WL_SCAN_STAT_INIT,
> + /* scan request issued, accepted or chip is scanning */
> + GELIC_WL_SCAN_STAT_SCANNING,
> + /* scan results retrieved */
> + GELIC_WL_SCAN_STAT_GOT_LIST,
> +};
> +
> +/* for 'cipher_method' */
> +enum gelic_wl_cipher_method {
> + GELIC_WL_CIPHER_NONE,
> + GELIC_WL_CIPHER_WEP,
> + GELIC_WL_CIPHER_TKIP,
> + GELIC_WL_CIPHER_AES,
> +};
> +
> +/* for 'wpa_level' */
> +enum gelic_wl_wpa_level {
> + GELIC_WL_WPA_LEVEL_NONE,
> + GELIC_WL_WPA_LEVEL_WPA,
> + GELIC_WL_WPA_LEVEL_WPA2,
> +};
> +
> +/* for 'assoc_stat' */
> +enum gelic_wl_assoc_state {
> + GELIC_WL_ASSOC_STAT_DISCONN,
> + GELIC_WL_ASSOC_STAT_ASSOCIATING,
> + GELIC_WL_ASSOC_STAT_ASSOCIATED,
> +};
> +/* part of private data alloc_etherdev() allocated */
> +#define GELIC_WEP_KEYS 4
> +struct gelic_wl_info {
> + /* bss list */
> + struct semaphore scan_lock;
> + struct list_head network_list;
> + struct list_head network_free_list;
> + struct gelic_wl_scan_info *networks;
> +
> + unsigned long scan_age; /* last scanned time */
> + enum gelic_wl_scan_state scan_stat;
> + struct completion scan_done;
> +
> + /* eurus command queue */
> + struct workqueue_struct *eurus_cmd_queue;
> + struct completion cmd_done_intr;
> +
> + /* eurus event handling */
> + struct workqueue_struct *event_queue;
> + struct delayed_work event_work;
> +
> + /* wl status bits */
> + unsigned long stat;
> + enum gelic_eurus_auth_method auth_method; /* open/shared */
> + enum gelic_wl_cipher_method group_cipher_method;
> + enum gelic_wl_cipher_method pairwise_cipher_method;
> + enum gelic_wl_wpa_level wpa_level; /* wpa/wpa2 */
> +
> + /* association handling */
> + struct semaphore assoc_stat_lock;
> + struct delayed_work assoc_work;
> + enum gelic_wl_assoc_state assoc_stat;
> + struct completion assoc_done;
> +
> + spinlock_t lock;
> + u16 ch_info; /* available channels. bit0 = ch1 */
> + /* WEP keys */
> + u8 key[GELIC_WEP_KEYS][IW_ENCODING_TOKEN_MAX];
> + unsigned long key_enabled;
> + unsigned int key_len[GELIC_WEP_KEYS];
> + unsigned int current_key;
> + /* WWPA PSK */
> + u8 psk[GELIC_WL_EURUS_PSK_MAX_LEN];
> + enum gelic_eurus_wpa_psk_type psk_type;
> + unsigned int psk_len;
> +
> + u8 essid[IW_ESSID_MAX_SIZE];
> + u8 bssid[ETH_ALEN]; /* userland requested */
> + u8 active_bssid[ETH_ALEN]; /* associated bssid */
> + unsigned int essid_len;
> +
> + /* buffer for hypervisor IO */
> + void *buf;
> +
> + struct iw_public_data wireless_data;
> + struct iw_statistics iwstat;
> +};
> +
> +#define GELIC_WL_BSS_MAX_ENT 32
> +#define GELIC_WL_ASSOC_RETRY 50
> +static inline struct gelic_port *wl_port(struct gelic_wl_info *wl)
> +{
> + return container_of((void *)wl, struct gelic_port, priv);
> +}
> +static inline struct gelic_wl_info *port_wl(struct gelic_port *port)
> +{
> + return port_priv(port);
> +}
> +
> +struct gelic_eurus_cmd {
> + struct work_struct work;
> + struct gelic_wl_info *wl;
> + unsigned int cmd; /* command code */
> + u64 tag;
> + u64 size;
> + void *buffer;
> + unsigned int buf_size;
> + struct completion done;
> + int status;
> + u64 cmd_status;
> +};
> +
> +/* private ioctls to pass PSK */
> +#define GELIC_WL_PRIV_SET_PSK (SIOCIWFIRSTPRIV + 0)
> +#define GELIC_WL_PRIV_GET_PSK (SIOCIWFIRSTPRIV + 1)
> +
> +extern int gelic_wl_driver_probe(struct gelic_card *card);
> +extern int gelic_wl_driver_remove(struct gelic_card *card);
> +extern void gelic_wl_interrupt(struct net_device *netdev, u64 status);
> +#endif /* _GELIC_WIRELESS_H */
>
> -
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH] SMC91x: don't flag spurious interrupts when polling
From: Kevin Hilman @ 2008-01-25 2:15 UTC (permalink / raw)
To: netdev; +Cc: Nicolas Pitre, Kevin Hilman
When using polling, smc_poll_controller() can call smc_interrupt()
when there are likely to be no real interrups. This will trigger the
"spurious interrupt" printk whenever the driver is being polled.
This adds an 'is_polling' flags, and doesn't trigger the spurious
warning when in polling mode.
Signed-off-by: Kevin Hilman <khilman@mvista.com>
Signed-off-by: Nicolas Pitre <nico@cam.org>
---
drivers/net/smc91x.c | 6 +++++-
1 files changed, 5 insertions(+), 1 deletions(-)
diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c
index 7da7589..64ef6c1 100644
--- a/drivers/net/smc91x.c
+++ b/drivers/net/smc91x.c
@@ -1350,8 +1350,12 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id)
*/
static void smc_poll_controller(struct net_device *dev)
{
+ struct smc_local *lp = netdev_priv(dev);
+ void __iomem *ioaddr = lp->base;
+
disable_irq(dev->irq);
- smc_interrupt(dev->irq, dev);
+ if (SMC_GET_INT() & SMC_GET_INT_MASK())
+ smc_interrupt(dev->irq, dev);
enable_irq(dev->irq);
}
#endif
--
1.5.3.7
^ permalink raw reply related
* Re: [PATCH] SMC91x: don't flag spurious interrupts when polling
From: Nicolas Pitre @ 2008-01-25 2:23 UTC (permalink / raw)
To: Kevin Hilman; +Cc: netdev
In-Reply-To: <1201227343-10853-1-git-send-email-khilman@mvista.com>
On Thu, 24 Jan 2008, Kevin Hilman wrote:
> When using polling, smc_poll_controller() can call smc_interrupt()
> when there are likely to be no real interrups. This will trigger the
> "spurious interrupt" printk whenever the driver is being polled.
>
> This adds an 'is_polling' flags, and doesn't trigger the spurious
> warning when in polling mode.
>
> Signed-off-by: Kevin Hilman <khilman@mvista.com>
> Signed-off-by: Nicolas Pitre <nico@cam.org>
NAK
Kevin: you sent the wrong patch !
Nicolas
^ permalink raw reply
* [PATCH] phylib: Add Realtek 821x eth PHY support
From: Kim Phillips @ 2008-01-25 2:28 UTC (permalink / raw)
To: netdev, jgarzik; +Cc: Johnson Leung, Kevin Lam, Joe D'Abbraccio
this PHY present on the MPC8315E and MPC837xE RDB boards.
Signed-off-by: Johnson Leung <r58129@freescale.com>
Signed-off-by: Kevin Lam <r43770@freescale.com>
Signed-off-by: Joe D'Abbraccio <ljd015@freescale.com>
Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
---
drivers/net/phy/Kconfig | 5 +++
drivers/net/phy/Makefile | 1 +
drivers/net/phy/realtek.c | 80 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 86 insertions(+), 0 deletions(-)
create mode 100644 drivers/net/phy/realtek.c
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 7fe03ce..f4ca059 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -60,6 +60,11 @@ config ICPLUS_PHY
---help---
Currently supports the IP175C PHY.
+config REALTEK_PHY
+ tristate "Drivers for Realtek PHYs"
+ ---help---
+ Supports the Realtek 821x PHY.
+
config FIXED_PHY
bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
---help---
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 3d6cc7b..5997d6e 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -12,5 +12,6 @@ obj-$(CONFIG_SMSC_PHY) += smsc.o
obj-$(CONFIG_VITESSE_PHY) += vitesse.o
obj-$(CONFIG_BROADCOM_PHY) += broadcom.o
obj-$(CONFIG_ICPLUS_PHY) += icplus.o
+obj-$(CONFIG_REALTEK_PHY) += realtek.o
obj-$(CONFIG_FIXED_PHY) += fixed.o
obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o
diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
new file mode 100644
index 0000000..a052a67
--- /dev/null
+++ b/drivers/net/phy/realtek.c
@@ -0,0 +1,80 @@
+/*
+ * drivers/net/phy/realtek.c
+ *
+ * Driver for Realtek PHYs
+ *
+ * Author: Johnson Leung <r58129@freescale.com>
+ *
+ * Copyright (c) 2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/phy.h>
+
+#define RTL821x_PHYSR 0x11
+#define RTL821x_PHYSR_DUPLEX 0x2000
+#define RTL821x_PHYSR_SPEED 0xc000
+#define RTL821x_INER 0x12
+#define RTL821x_INER_INIT 0x6400
+#define RTL821x_INSR 0x13
+
+MODULE_DESCRIPTION("Realtek PHY driver");
+MODULE_AUTHOR("Johnson Leung");
+MODULE_LICENSE("GPL");
+
+static int rtl821x_ack_interrupt(struct phy_device *phydev)
+{
+ int err;
+
+ err = phy_read(phydev, RTL821x_INSR);
+
+ return (err < 0) ? err : 0;
+}
+
+static int rtl821x_config_intr(struct phy_device *phydev)
+{
+ int err;
+
+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+ err = phy_write(phydev, RTL821x_INER,
+ RTL821x_INER_INIT);
+ else
+ err = phy_write(phydev, RTL821x_INER, 0);
+
+ return err;
+}
+
+/* RTL8211B */
+static struct phy_driver rtl821x_driver = {
+ .phy_id = 0x001cc912,
+ .name = "RTL821x Gigabit Ethernet",
+ .phy_id_mask = 0x001fffff,
+ .features = PHY_GBIT_FEATURES,
+ .flags = PHY_HAS_INTERRUPT,
+ .config_aneg = &genphy_config_aneg,
+ .read_status = &genphy_read_status,
+ .ack_interrupt = &rtl821x_ack_interrupt,
+ .config_intr = &rtl821x_config_intr,
+ .driver = { .owner = THIS_MODULE,},
+};
+
+static int __init realtek_init(void)
+{
+ int ret;
+
+ ret = phy_driver_register(&rtl821x_driver);
+
+ return ret;
+}
+
+static void __exit realtek_exit(void)
+{
+ phy_driver_unregister(&rtl821x_driver);
+}
+
+module_init(realtek_init);
+module_exit(realtek_exit);
--
1.5.2.2
^ permalink raw reply related
* Re: [PATCH v2] PS3: gelic: Add wireless support for PS3
From: John W. Linville @ 2008-01-25 2:47 UTC (permalink / raw)
To: Dan Williams
Cc: Masakazu Mokuno, linux-wireless-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA,
geoffrey.levand-mEdOJwZ7QcZBDgjK7y7TUQ, Geert Uytterhoeven
In-Reply-To: <1201225785.15917.8.camel-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>
On Thu, Jan 24, 2008 at 08:49:45PM -0500, Dan Williams wrote:
> On Thu, 2008-01-24 at 14:51 +0900, Masakazu Mokuno wrote:
> > Hi
> >
> > PS3: gelic: Add wireless support for PS3
> >
> > This is the version 2 of the re-worked (rewritten) version of the
> > wireless support driver for PS3. The version 1 of the new driver was
> > submitted on 13th Dec. 2007 (and the old one was submitted to net-dev ML
> > in June 2007).
> >
> > Major differences with the old driver are:
> > - The new driver has a separate ethX interface from ethernet.
> > They share the same MAC address.
> > - Thus we can use both ethernet and wireless simultaenously.
> > - The new driver returns AP's cipher information by the common IE
> > format in the scan information.
> > - Cipher selection is done via the common wireless extension way
>
> Looks like all my issues have been addressed. Thanks! Lets get this in
> 2.6.25 :)
>
> Acked-by: Dan Williams <dcbw-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
ACK -- please merge it with the other patches through the powerpc tree.
Thanks,
John
--
John W. Linville
linville-2XuSBdqkA4R54TAoqtyWWQ@public.gmane.org
^ permalink raw reply
* Re: [PATCH 09/26] atl1: refactor tx processing
From: Jeff Garzik @ 2008-01-25 3:01 UTC (permalink / raw)
To: Jay Cliburn; +Cc: csnook, linux-kernel, atl1-devel, netdev
In-Reply-To: <20080124190024.1b81238e@osprey.hogchain.net>
Jay Cliburn wrote:
> On Tue, 22 Jan 2008 18:31:09 -0600
> Jay Cliburn <jacliburn@bellsouth.net> wrote:
>
>> On Tue, 22 Jan 2008 04:58:17 -0500
>> Jeff Garzik <jeff@garzik.org> wrote:
>>
> [...]
>>> for such a huge patch, this description is very tiny. [describe]
>>> what is refactored, and why.
>
> Is this one any better?
>
>
>
>>From df475e2eea401f9dc18ca23dab538b99fb9e710c Mon Sep 17 00:00:00 2001
> From: Jay Cliburn <jacliburn@bellsouth.net>
> Date: Wed, 23 Jan 2008 21:36:36 -0600
> Subject: [PATCH] atl1: simplify tx packet descriptor
>
> The transmit packet descriptor consists of four 32-bit words, with word 3
> upper bits overloaded depending upon the condition of its bits 3 and 4.
> The driver currently duplicates all word 2 and some word 3 register bit
> definitions unnecessarily and also uses a set of nested structures in its
> definition of the TPD without good cause. This patch adds a lengthy
> comment describing the TPD, eliminates duplicate TPD bit definitions,
> and simplifies the TPD structure itself. It also expands the TSO check
> to correctly handle custom checksum versus TSO processing using the revised
> TPD definitions. Finally, shorten some variable names in the transmit
> processing path to reduce line lengths, rename some variables to better
> describe their purpose (e.g., nseg versus m), and add a comment or two
> to better describe what the code is doing.
>
> Signed-off-by: Jay Cliburn <jacliburn@bellsouth.net>
> ---
> drivers/net/atlx/atl1.c | 265 +++++++++++++++++++++++++----------------------
> drivers/net/atlx/atl1.h | 201 +++++++++++++++++++-----------------
> 2 files changed, 246 insertions(+), 220 deletions(-)
Yep, better.
Jeff
^ permalink raw reply
* RE: [PATCH 2.6.25 1/1]S2io: Multiqueue network device support implementation
From: Ramkrishna Vepa @ 2008-01-25 3:19 UTC (permalink / raw)
To: Andi Kleen; +Cc: Sreenivasa Honnur, netdev, jeff, support
In-Reply-To: <20080124072549.GA6814@one.firstfloor.org>
> > [Ram] I am assuming that this is with regards to msi-x interrupts.
We
>
> Yes.
>
> And avoiding bouncing locks for device state between CPUs.
>
> > have done away with handling tx completion in the interrupt handler,
and
> > are instead handling them in the context of the transmit. The slow
path,
> > straggling transmit completions will be handled in the timer
context.
>
> Ok -- hopefully you don't have bad corner cases from this when the
pipe
> is not fully filled and then causing longer latencies on completion.
> Old NAPI sometimes suffered from such problems.
[Ram] We have hit the driver pretty hard during testing and have not
encountered any problems either on the network or host.
Ram
>
> -Andi
^ permalink raw reply
* RE: [PATCH 2.6.25 1/1]S2io: Multiqueue network device support implementation
From: Ramkrishna Vepa @ 2008-01-25 3:19 UTC (permalink / raw)
To: David Miller, andi; +Cc: Sreenivasa Honnur, netdev, jeff, support
In-Reply-To: <20080123.233006.124819204.davem@davemloft.net>
> From: netdev-owner@vger.kernel.org
[mailto:netdev-owner@vger.kernel.org]
> On Behalf Of David Miller
> Sent: Wednesday, January 23, 2008 11:30 PM
>
> From: Andi Kleen <andi@firstfloor.org>
> Date: Thu, 24 Jan 2008 08:25:49 +0100
>
> > > have done away with handling tx completion in the interrupt
handler,
> and
> > > are instead handling them in the context of the transmit. The slow
> path,
> > > straggling transmit completions will be handled in the timer
context.
> >
> > Ok -- hopefully you don't have bad corner cases from this when the
pipe
> > is not fully filled and then causing longer latencies on completion.
> > Old NAPI sometimes suffered from such problems.
>
> BTW, such a TX completion timer will stall TCP sockets when the TX
> queue of the device is partially filled and then sending stops.
>
> TX ring SKB liberation really must be done in a very small finite
> amount of time in order to avoid this problem properly.
>
> Deferring it to HZ granular timers doesn't give a quick enough
> response, especially at high packet rates.
[Ram] We could add a lower granular tx completion interrupt instead, to
handle all the transmit fifos. But this will be a fall back in the event
the completions do not happen in the context of the transmit.
Ram
^ permalink raw reply
* Re: [PATCH v2] PS3: gelic: Add wireless support for PS3
From: Masakazu Mokuno @ 2008-01-25 3:36 UTC (permalink / raw)
To: John W. Linville, Dan Williams
Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA,
geoffrey.levand-mEdOJwZ7QcZBDgjK7y7TUQ, Geert Uytterhoeven,
Paul Mackerras
In-Reply-To: <20080125024725.GB3411-2XuSBdqkA4R54TAoqtyWWQ@public.gmane.org>
On Thu, 24 Jan 2008 21:47:25 -0500
"John W. Linville" <linville-2XuSBdqkA4R54TAoqtyWWQ@public.gmane.org> wrote:
> On Thu, Jan 24, 2008 at 08:49:45PM -0500, Dan Williams wrote:
> > On Thu, 2008-01-24 at 14:51 +0900, Masakazu Mokuno wrote:
> > > Hi
> > >
> > > PS3: gelic: Add wireless support for PS3
> > >
> > > This is the version 2 of the re-worked (rewritten) version of the
> > > wireless support driver for PS3. The version 1 of the new driver was
> > > submitted on 13th Dec. 2007 (and the old one was submitted to net-dev ML
> > > in June 2007).
> > >
> > > Major differences with the old driver are:
> > > - The new driver has a separate ethX interface from ethernet.
> > > They share the same MAC address.
> > > - Thus we can use both ethernet and wireless simultaenously.
> > > - The new driver returns AP's cipher information by the common IE
> > > format in the scan information.
> > > - Cipher selection is done via the common wireless extension way
> >
> > Looks like all my issues have been addressed. Thanks! Lets get this in
> > 2.6.25 :)
> >
> > Acked-by: Dan Williams <dcbw-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
>
> ACK -- please merge it with the other patches through the powerpc tree.
>
> Thanks,
>
> John
Thank you, John, Dan.
I'll ask Paul to merge this if the wired part of dependent gelic patches
gets acked from network people.
--
Masakazu MOKUNO
^ permalink raw reply
* RE: [PATCH UCC TDM 3/3 ] Modified Documentation to explain dtsentries for TDM driver
From: Aggrwal Poonam @ 2008-01-25 3:58 UTC (permalink / raw)
To: Wood Scott
Cc: Barkowski Michael, netdev, Gala Kumar, linux-kernel, rubini,
linuxppc-dev, Kalra Ashish, Cutler Richard, akpm, Tabi Timur
In-Reply-To: <20080124201226.GA3926@loki.buserror.net>
Hi Scott
The device tree already has a brg-frequency property in qe node which
is the value of BRGCLK. The function get_brg_clk uses this property to
find the value of BRGCLK.
In case this value is 0(some older u-boots populate bus-frequency
property of qe and not the brg-frequency), get_brg_clk uses
bus-frequency/2 as BRGCLK.
With Regards
Poonam
-----Original Message-----
From: Wood Scott
Sent: Friday, January 25, 2008 1:42 AM
To: Aggrwal Poonam
Cc: Gala Kumar; akpm@linux-foundation.org; linux-kernel@vger.kernel.org;
netdev@vger.kernel.org; rubini@vision.unipv.it; linuxppc-dev@ozlabs.org;
Barkowski Michael; Cutler Richard; Tabi Timur; Kalra Ashish
Subject: Re: [PATCH UCC TDM 3/3 ] Modified Documentation to explain
dtsentries for TDM driver
On Thu, Jan 24, 2008 at 10:24:13AM +0530, Poonam_Aggrwal-b10812 wrote:
> + ix) Baud Rate Generator (BRG)
> +
> + Required properties:
> + - compatible : shpuld be "fsl,cpm-brg"
> + - fsl,brg-sources : define the input clock for all 16 BRGs. The
input
> + clock source could be 1 to 24 for CLK1 to CLK24. Zero means that
the
> + particular BRG will be driven by QE clock(BRGCLK).
Should also have a clock-frequency property to specify what BRGCLK is.
-Scott
^ permalink raw reply
* Re: pull request: wireless-2.6 'upstream' 2008-01-24
From: John W. Linville @ 2008-01-25 3:57 UTC (permalink / raw)
To: davem; +Cc: netdev, linux-wireless
In-Reply-To: <20080124195343.GC3200@tuxdriver.com>
On Thu, Jan 24, 2008 at 02:53:43PM -0500, John W. Linville wrote:
> The cfg80211 API change breaks ath5k, so I have listed it as "depends
> on BROKEN". I am assured that the ath5k team has agreed to fix
> this ASAP. Meanwhile we wanted to have it in place so that we can
> start shaking-out problems with other drivers.
Looks like this might have broken more than I expected, and there
may be some refactoring of the wireless rndis bits too. So, let's
hold off on this request. I'll post a new one in the next day or so.
Thanks,
John
--
John W. Linville
linville@tuxdriver.com
^ permalink raw reply
* RE: [PATCH UCC TDM 1/3 Updated] Platform changes for UCC TDM driver for MPC8323eRDB. Also includes related QE changes and dts entries.
From: Aggrwal Poonam @ 2008-01-25 4:09 UTC (permalink / raw)
To: avorontsov, Tabi Timur
Cc: Gala Kumar, akpm, linux-kernel, netdev, rubini, linuxppc-dev,
Barkowski Michael, Cutler Richard, Kalra Ashish
In-Reply-To: <20080124172327.GA6786@localhost.localdomain>
Hello Anton/Tabi
I am not sure which is the best place to configure the pins. Because
some drivers do it in one way and some in the other.
I actually tried to make the driver similar to ucc_geth because it is a
QE driver. The driver has no platform code in the platform files similar
to ucc_geth. It is probed along with all the QE devices thorugh
of_platform_bus_probe.
And the pins are configured for all the QE devices using par_io_init.
I thought this to be the most consistent way at that time.
How should we close this point?
Can we go ahead with the pio-map?
Infact the discussion in this thread was very good and I got to know a
lot of rationales behind this.
Please suggest.
Thanks and Regards
Poonam
From: Anton Vorontsov [mailto:avorontsov@ru.mvista.com]
Sent: Thursday, January 24, 2008 10:53 PM
To: Tabi Timur
Cc: Aggrwal Poonam; Gala Kumar; akpm@linux-foundation.org;
linux-kernel@vger.kernel.org; netdev@vger.kernel.org;
rubini@vision.unipv.it; linuxppc-dev@ozlabs.org; Barkowski Michael;
Cutler Richard; Kalra Ashish
Subject: Re: [PATCH UCC TDM 1/3 Updated] Platform changes for UCC TDM
driver for MPC8323eRDB. Also includes related QE changes and dts
entries.
On Thu, Jan 24, 2008 at 10:33:47AM -0600, Timur Tabi wrote:
> Anton Vorontsov wrote:
>
> >Are you saying that TDM is sharing same pins with the other QE
> >device, and we can choose to use/not use some device depending on
> >which driver is loaded?
>
> No. I'd have to closely examine the DTS, but I don't think that UCC
> devices share pins at all. But that isn't my point.
>
> >In that particular case UCC configuration is static, for every UCC.
> >So, we can set up all pins in the firmware/board file.
>
> Yes, but deciding what the UCC does might not be static. At what
> point do we declare, "UCC5 is for eth0 and eth0 only"?
>
> The advantage of putting the pin configurations in the device tree is
> that they now become configurable. I can envision a scenario where
> UCC5 could be either an Ethernet or a UART, depending on the setting
> of some jumpers on the board. That's what the QE was designed for: any
> UCC can do any task, and you can even have a UCC change its purpose
while the system is running.
> So I don't want the pin configurations hard-coded into the kernel.
> Having them in the device tree gives me some flexibility.
If hardware configuration is selected at the bootup time, by jumpers or
switches, it's even easier to do it right. Without pio-map.
> For instance, I have a plan (that I keep postponing) to introduce a
> new feature in U-Boot where U-Boot can determine the settings of some
> board jumpers and modify the device tree accordingly. The instructions
> on how to modify the device tree would be embedded in the tree itself.
Why you need to modify the device tree for that? Let the U-Boot simply
setup pins for the kernel. Regarding kernel overwriting pins
configuration...
> I can't
> support this feature if the kernel calls par_io_config_pin()
> regardless of what's in the device tree.
What I've understood from the previous debates, is that ideally kernel
should not touch pins' configuration. Today we're using pio-map solely
to fix up some old firmware misconfiguration. And we can do this in the
board file still. To determine if we need to fixup the firmware or not,
we can use some device tree property instead (firmware version?).
p.s.
I'm neither for pio-map nor against. I just want some consequence
regarding this. Last thread ended with consequence that pio-map is a bad
thing to use...
--
Anton Vorontsov
email: cbou@mail.ru
backup email: ya-cbou@yandex.ru
irc://irc.freenode.net/bd2
^ permalink raw reply
* Re: pull request: wireless-2.6 'upstream' 2008-01-24
From: David Miller @ 2008-01-25 5:26 UTC (permalink / raw)
To: linville; +Cc: netdev, linux-wireless
In-Reply-To: <20080125035751.GC3411@tuxdriver.com>
From: "John W. Linville" <linville@tuxdriver.com>
Date: Thu, 24 Jan 2008 22:57:51 -0500
> On Thu, Jan 24, 2008 at 02:53:43PM -0500, John W. Linville wrote:
>
> > The cfg80211 API change breaks ath5k, so I have listed it as "depends
> > on BROKEN". I am assured that the ath5k team has agreed to fix
> > this ASAP. Meanwhile we wanted to have it in place so that we can
> > start shaking-out problems with other drivers.
>
> Looks like this might have broken more than I expected, and there
> may be some refactoring of the wireless rndis bits too. So, let's
> hold off on this request. I'll post a new one in the next day or so.
Ok.
^ permalink raw reply
* Re: bluetooth : lockdep warning on rfcomm
From: Dave Young @ 2008-01-25 5:37 UTC (permalink / raw)
To: LKML; +Cc: Netdev, Marcel Holtmann, David Miller, bluez-devel
In-Reply-To: <a8e1da0801240125x6c65a4bfva24ff50cef890eba@mail.gmail.com>
On Jan 24, 2008 5:25 PM, Dave Young <hidave.darkstar@gmail.com> wrote:
>
> On Jan 24, 2008 11:02 AM, Dave Young <hidave.darkstar@gmail.com> wrote:
> > =============================================
> > [ INFO: possible recursive locking detected ]
> > 2.6.24-rc8-mm1 #8
> > ---------------------------------------------
> > bluepush/3213 is trying to acquire lock:
> > (sk_lock-AF_BLUETOOTH){--..}, at: [<f8978c80>]
> > l2cap_sock_bind+0x40/0x100 [l2cap]
> >
> > but task is already holding lock:
> > (sk_lock-AF_BLUETOOTH){--..}, at: [<f894a31e>]
> > rfcomm_sock_connect+0x3e/0xe0 [rfcomm]
> >
> > other info that might help us debug this:
> > 2 locks held by bluepush/3213:
> > #0: (sk_lock-AF_BLUETOOTH){--..}, at: [<f894a31e>]
> > rfcomm_sock_connect+0x3e/0xe0 [rfcomm]
> > #1: (rfcomm_mutex){--..}, at: [<f8947556>] rfcomm_dlc_open+0x26/0x60 [rfcomm]
> >
> > stack backtrace:
> > Pid: 3213, comm: bluepush Not tainted 2.6.24-rc8-mm1 #8
> > [<c0132128>] ? printk+0x18/0x20
> > [<c0154437>] print_deadlock_bug+0xc7/0xe0
> > [<c01544bc>] check_deadlock+0x6c/0x80
> > [<c01548fc>] validate_chain+0x14c/0x320
> > [<c0156221>] __lock_acquire+0x1c1/0x730
> > [<c0156d89>] lock_acquire+0x79/0xb0
> > [<f8978c80>] ? l2cap_sock_bind+0x40/0x100 [l2cap]
> > [<c03c05f5>] lock_sock_nested+0x55/0x70
> > [<f8978c80>] ? l2cap_sock_bind+0x40/0x100 [l2cap]
> > [<f8978c80>] l2cap_sock_bind+0x40/0x100 [l2cap]
> > [<c03bdb4a>] kernel_bind+0xa/0x10
> > [<f8947afc>] rfcomm_session_create+0x4c/0x110 [rfcomm]
> > [<f8947509>] __rfcomm_dlc_open+0x129/0x150 [rfcomm]
> > [<f8947568>] rfcomm_dlc_open+0x38/0x60 [rfcomm]
> > [<f894a396>] rfcomm_sock_connect+0xb6/0xe0 [rfcomm]
> > [<c03bcd39>] sys_connect+0x99/0xd0
> > [<c010f509>] ? cache_add_dev+0x39/0x1a0
> > [<c015323d>] ? put_lock_stats+0xd/0x30
> > [<c01532c0>] ? lock_release_holdtime+0x60/0x80
> > [<c018e86c>] ? fget+0x7c/0x100
> > [<c0156b97>] ? __lock_release+0x47/0x70
> > [<c018e86c>] ? fget+0x7c/0x100
> > [<c02611b7>] ? copy_from_user+0x37/0x70
> > [<c03bd855>] sys_socketcall+0xa5/0x230
> > [<c0155659>] ? trace_hardirqs_on+0xb9/0x130
> > [<c010501b>] ? restore_nocheck+0x12/0x15
> >
>
> While fixing this issue, another locking dependency confused me. Are
> rfcomm_dev_lock and &d->lock in same lock class?
>
> The warnings as following:
>
> =======================================================
> [ INFO: possible circular locking dependency detected ]
> 2.6.24-rc8-mm1 #8
> -------------------------------------------------------
> krfcommd/2912 is trying to acquire lock:
> (rfcomm_dev_lock){-.--}, at: [<f89d5bf2>]
> rfcomm_dev_state_change+0x92/0x160 [rfcomm]
>
> but task is already holding lock:
> (&d->lock){--..}, at: [<f89d15d3>] __rfcomm_dlc_close+0x43/0xd0 [rfcomm]
>
> which lock already depends on the new lock.
Answer to myself, the reason is that lockdep think this as a lock order problem.
in rfcomm_device_add the lock order is :
rfcomm_dev_lock --> dlc lock
but in __rfcomm_dlc_close is :
dlc lock --> rfcomm_dev_lock (-> state_change->rfcomm_dev_get)
>
>
> the existing dependency chain (in reverse order) is:
>
> -> #1 (&d->lock){--..}:
> [<c0153b13>] add_lock_to_list+0x33/0x70
> [<c01545a3>] check_prev_add+0xd3/0x200
> [<f89d5311>] rfcomm_dev_add+0x191/0x300 [rfcomm]
> [<c0154765>] check_prevs_add+0x95/0xe0
> [<c01549ef>] validate_chain+0x23f/0x320
> [<c0156221>] __lock_acquire+0x1c1/0x730
> [<c0155539>] mark_held_locks+0x39/0x80
> [<c0156d89>] lock_acquire+0x79/0xb0
> [<f89d5311>] rfcomm_dev_add+0x191/0x300 [rfcomm]
> [<c0436749>] _spin_lock+0x39/0x80
> [<f89d5311>] rfcomm_dev_add+0x191/0x300 [rfcomm]
> [<f89d5b10>] rfcomm_dev_data_ready+0x0/0x50 [rfcomm]
> [<f89d5311>] rfcomm_dev_add+0x191/0x300 [rfcomm]
> [<f89d565e>] rfcomm_create_dev+0x6e/0x100 [rfcomm]
> [<c03c05fa>] lock_sock_nested+0x5a/0x70
> [<f89d5ae3>] rfcomm_dev_ioctl+0x33/0x60 [rfcomm]
> [<f89d4c8c>] rfcomm_sock_ioctl+0x2c/0x50 [rfcomm]
> [<c03bc001>] sock_ioctl+0xc1/0x220
> [<c03bbf40>] sock_ioctl+0x0/0x220
> [<c019a366>] vfs_ioctl+0x76/0x90
> [<c019a616>] do_vfs_ioctl+0x56/0x140
> [<c019a762>] sys_ioctl+0x62/0x70
> [<c0104fba>] syscall_call+0x7/0xb
> [<ffffffff>] 0xffffffff
>
> -> #0 (rfcomm_dev_lock){-.--}:
> [<c0154504>] check_prev_add+0x34/0x200
> [<c012a9ab>] default_wake_function+0xb/0x10
> [<c0154765>] check_prevs_add+0x95/0xe0
> [<c01549ef>] validate_chain+0x23f/0x320
> [<c0156221>] __lock_acquire+0x1c1/0x730
> [<c0156d89>] lock_acquire+0x79/0xb0
> [<f89d5bf2>] rfcomm_dev_state_change+0x92/0x160 [rfcomm]
> [<c04361e9>] _read_lock+0x39/0x80
> [<f89d5bf2>] rfcomm_dev_state_change+0x92/0x160 [rfcomm]
> [<f89d5bf2>] rfcomm_dev_state_change+0x92/0x160 [rfcomm]
> [<f89d15e8>] __rfcomm_dlc_close+0x58/0xd0 [rfcomm]
> [<f89d2523>] rfcomm_recv_ua+0x73/0x140 [rfcomm]
> [<f89d3151>] rfcomm_recv_frame+0x171/0x1e0 [rfcomm]
> [<c0155659>] trace_hardirqs_on+0xb9/0x130
> [<c0436a39>] _spin_unlock_irqrestore+0x39/0x70
> [<f89d3447>] rfcomm_run+0xe7/0x590 [rfcomm]
> [<c0120000>] hpet_legacy_next_event+0x20/0x50
> [<f89d3360>] rfcomm_run+0x0/0x590 [rfcomm]
> [<c0146e0c>] kthread+0x5c/0xa0
> [<c0146db0>] kthread+0x0/0xa0
> [<c0105c17>] kernel_thread_helper+0x7/0x10
> [<ffffffff>] 0xffffffff
>
> other info that might help us debug this:
>
> 2 locks held by krfcommd/2912:
> #0: (rfcomm_mutex){--..}, at: [<f89d33db>] rfcomm_run+0x7b/0x590 [rfcomm]
> #1: (&d->lock){--..}, at: [<f89d15d3>] __rfcomm_dlc_close+0x43/0xd0 [rfcomm]
>
> stack backtrace:
> Pid: 2912, comm: krfcommd Not tainted 2.6.24-rc8-mm1 #8
> [<c0132128>] ? printk+0x18/0x20
> [<c0153cff>] print_circular_bug_tail+0x6f/0x80
> [<c0154504>] check_prev_add+0x34/0x200
> [<c012a9ab>] ? default_wake_function+0xb/0x10
> [<c0154765>] check_prevs_add+0x95/0xe0
> [<c01549ef>] validate_chain+0x23f/0x320
> [<c0156221>] __lock_acquire+0x1c1/0x730
> [<c0156d89>] lock_acquire+0x79/0xb0
> [<f89d5bf2>] ? rfcomm_dev_state_change+0x92/0x160 [rfcomm]
> [<c04361e9>] _read_lock+0x39/0x80
> [<f89d5bf2>] ? rfcomm_dev_state_change+0x92/0x160 [rfcomm]
> [<f89d5bf2>] rfcomm_dev_state_change+0x92/0x160 [rfcomm]
> [<f89d15e8>] __rfcomm_dlc_close+0x58/0xd0 [rfcomm]
> [<f89d2523>] rfcomm_recv_ua+0x73/0x140 [rfcomm]
> [<f89d3151>] rfcomm_recv_frame+0x171/0x1e0 [rfcomm]
> [<c0155659>] ? trace_hardirqs_on+0xb9/0x130
> [<c0436a39>] ? _spin_unlock_irqrestore+0x39/0x70
> [<f89d3447>] rfcomm_run+0xe7/0x590 [rfcomm]
> [<c0120000>] ? hpet_legacy_next_event+0x20/0x50
> [<f89d3360>] ? rfcomm_run+0x0/0x590 [rfcomm]
> [<c0146e0c>] kthread+0x5c/0xa0
> [<c0146db0>] ? kthread+0x0/0xa0
> [<c0105c17>] kernel_thread_helper+0x7/0x10
> =======================
>
-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
^ permalink raw reply
* [PATCH] SMC91x: poll_controller(): check for interrupts before calling handler
From: Kevin Hilman @ 2008-01-25 5:38 UTC (permalink / raw)
To: netdev; +Cc: Nicolas Pitre, Kevin Hilman
When using polling, smc_poll_controller() can call smc_interrupt()
when there are likely to be no real interrups. This will trigger the
"spurious interrupt" printk whenever the driver is being polled.
Instead, check for actual interrupts before calling smc_interrupt()
Signed-off-by: Kevin Hilman <khilman@mvista.com>
Signed-off-by: Nicolas Pitre <nico@cam.org>
---
drivers/net/smc91x.c | 6 +++++-
1 files changed, 5 insertions(+), 1 deletions(-)
diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c
index 7da7589..64ef6c1 100644
--- a/drivers/net/smc91x.c
+++ b/drivers/net/smc91x.c
@@ -1350,8 +1350,12 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id)
*/
static void smc_poll_controller(struct net_device *dev)
{
+ struct smc_local *lp = netdev_priv(dev);
+ void __iomem *ioaddr = lp->base;
+
disable_irq(dev->irq);
- smc_interrupt(dev->irq, dev);
+ if (SMC_GET_INT() & SMC_GET_INT_MASK())
+ smc_interrupt(dev->irq, dev);
enable_irq(dev->irq);
}
#endif
--
1.5.3.7
^ permalink raw reply related
* Re: [PATCH] fib_trie: rescan if key is lost during dump
From: Jarek Poplawski @ 2008-01-25 8:23 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: David Miller, kaber, netdev
In-Reply-To: <20080124135112.32b5c1c7@deepthought>
On 24-01-2008 22:51, Stephen Hemminger wrote:
> Normally during a dump the key of the last dumped entry is used for
> continuation, but since lock is dropped it might be lost. In that case
> fallback to the old counter based N^2 behaviour. This means the dump will end up
> skipping some routes which matches what FIB_HASH does.
>
> Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
...
> @@ -1918,35 +1931,37 @@ static int fn_trie_dump(struct fib_table
> struct leaf *l;
> struct trie *t = (struct trie *) tb->tb_data;
> t_key key = cb->args[2];
> + int count = cb->args[3];
>
> rcu_read_lock();
Sorry, but I lost the point: is rtnl held or not held here at the moment?
If held, how this rcu_read_lock can help? Maybe some additional comment
in the code?
Thanks,
Jarek P.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox