Netdev List
 help / color / mirror / Atom feed
* [RESEND patch 5/6] s390: remove tty support from ctc network device driver [1/2]
From: Frank Pavlic @ 2006-03-24  9:07 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: linux-kernel, netdev
In-Reply-To: <4421FA37.4050703@pobox.com>

[patch 5/6] s390: remove tty support from ctc network device driver [1/2]

From: Peter Tiedemann <ptiedem@de.ibm.com>
	[1/2]: 
        tty support code will be removed from the ctc network device driver.
        Today we have a couple of alternatives which are performing much
        better. The second thing is that ctc should be a network 
	device driver only. 
	We should not mix tty and networking here.
        This first patch will remove the tty code from ctcmain.c .
       	It also removes the build entry from the Makefile as well as TTY 
	definitions from ctcmain.h.
        The second patch will remove two files, ctctty.c and ctctty.h.

Signed-off-by: Frank Pavlic <fpavlic@de.ibm.com>

diffstat:

 Makefile  |    3 ++-
 ctcmain.c |   45 +++++++++------------------------------------
 ctcmain.h |   12 +++++-------
 3 files changed, 16 insertions(+), 44 deletions(-)

diff -Naupr git-linux/drivers/s390/net/ctcmain.c git-patched/drivers/s390/net/ctcmain.c
--- git-linux/drivers/s390/net/ctcmain.c	2006-03-24 09:21:59.000000000 +0100
+++ git-patched/drivers/s390/net/ctcmain.c	2006-03-24 09:41:17.000000000 +0100
@@ -6,7 +6,7 @@
  * Fixes by : Jochen Röhrig (roehrig@de.ibm.com)
  *            Arnaldo Carvalho de Melo <acme@conectiva.com.br>
 	      Peter Tiedemann (ptiedem@de.ibm.com)
- * Driver Model stuff by : Cornelia Huck <huckc@de.ibm.com>
+ * Driver Model stuff by : Cornelia Huck <cornelia.huck@de.ibm.com>
  *
  * Documentation used:
  *  - Principles of Operation (IBM doc#: SA22-7201-06)
@@ -65,7 +65,6 @@
 
 #include <asm/idals.h>
 
-#include "ctctty.h"
 #include "fsm.h"
 #include "cu3088.h"
 
@@ -479,10 +478,7 @@ ctc_unpack_skb(struct channel *ch, struc
 		skb->dev = pskb->dev;
 		skb->protocol = pskb->protocol;
 		pskb->ip_summed = CHECKSUM_UNNECESSARY;
-		if (ch->protocol == CTC_PROTO_LINUX_TTY)
-			ctc_tty_netif_rx(skb);
-		else
-			netif_rx_ni(skb);
+		netif_rx_ni(skb);
 		/**
 		 * Successful rx; reset logflags
 		 */
@@ -557,8 +553,7 @@ ccw_unit_check(struct channel *ch, unsig
 	DBF_TEXT(trace, 5, __FUNCTION__);
 	if (sense & SNS0_INTERVENTION_REQ) {
 		if (sense & 0x01) {
-			if (ch->protocol != CTC_PROTO_LINUX_TTY)
-				ctc_pr_debug("%s: Interface disc. or Sel. reset "
+			ctc_pr_debug("%s: Interface disc. or Sel. reset "
 					"(remote)\n", ch->id);
 			fsm_event(ch->fsm, CH_EVENT_UC_RCRESET, ch);
 		} else {
@@ -2034,7 +2029,6 @@ static void
 dev_action_chup(fsm_instance * fi, int event, void *arg)
 {
 	struct net_device *dev = (struct net_device *) arg;
-	struct ctc_priv *privptr = dev->priv;
 
 	DBF_TEXT(trace, 3, __FUNCTION__);
 	switch (fsm_getstate(fi)) {
@@ -2049,8 +2043,6 @@ dev_action_chup(fsm_instance * fi, int e
 				fsm_newstate(fi, DEV_STATE_RUNNING);
 				ctc_pr_info("%s: connected with remote side\n",
 					    dev->name);
-				if (privptr->protocol == CTC_PROTO_LINUX_TTY)
-					ctc_tty_setcarrier(dev, 1);
 				ctc_clear_busy(dev);
 			}
 			break;
@@ -2059,8 +2051,6 @@ dev_action_chup(fsm_instance * fi, int e
 				fsm_newstate(fi, DEV_STATE_RUNNING);
 				ctc_pr_info("%s: connected with remote side\n",
 					    dev->name);
-				if (privptr->protocol == CTC_PROTO_LINUX_TTY)
-					ctc_tty_setcarrier(dev, 1);
 				ctc_clear_busy(dev);
 			}
 			break;
@@ -2086,14 +2076,10 @@ dev_action_chup(fsm_instance * fi, int e
 static void
 dev_action_chdown(fsm_instance * fi, int event, void *arg)
 {
-	struct net_device *dev = (struct net_device *) arg;
-	struct ctc_priv *privptr = dev->priv;
 
 	DBF_TEXT(trace, 3, __FUNCTION__);
 	switch (fsm_getstate(fi)) {
 		case DEV_STATE_RUNNING:
-			if (privptr->protocol == CTC_PROTO_LINUX_TTY)
-				ctc_tty_setcarrier(dev, 0);
 			if (event == DEV_EVENT_TXDOWN)
 				fsm_newstate(fi, DEV_STATE_STARTWAIT_TX);
 			else
@@ -2397,8 +2383,6 @@ ctc_tx(struct sk_buff *skb, struct net_d
 	 */
 	if (fsm_getstate(privptr->fsm) != DEV_STATE_RUNNING) {
 		fsm_event(privptr->fsm, DEV_EVENT_START, dev);
-		if (privptr->protocol == CTC_PROTO_LINUX_TTY)
-			return -EBUSY;
 		dev_kfree_skb(skb);
 		privptr->stats.tx_dropped++;
 		privptr->stats.tx_errors++;
@@ -2608,20 +2592,13 @@ ctc_netdev_unregister(struct net_device 
 	if (!dev)
 		return;
 	privptr = (struct ctc_priv *) dev->priv;
-	if (privptr->protocol != CTC_PROTO_LINUX_TTY)
-		unregister_netdev(dev);
-	else
-		ctc_tty_unregister_netdev(dev);
+	unregister_netdev(dev);
 }
 
 static int
 ctc_netdev_register(struct net_device * dev)
 {
-	struct ctc_priv *privptr = (struct ctc_priv *) dev->priv;
-	if (privptr->protocol != CTC_PROTO_LINUX_TTY)
-		return register_netdev(dev);
-	else
-		return ctc_tty_register_netdev(dev);
+	return register_netdev(dev);
 }
 
 static void
@@ -2667,7 +2644,9 @@ ctc_proto_store(struct device *dev, stru
 	if (!priv)
 		return -ENODEV;
 	sscanf(buf, "%u", &value);
-	if ((value < 0) || (value > CTC_PROTO_MAX))
+	if (!((value == CTC_PROTO_S390)  ||
+	      (value == CTC_PROTO_LINUX) ||
+	      (value == CTC_PROTO_OS390)))
 		return -EINVAL;
 	priv->protocol = value;
 
@@ -2897,10 +2876,7 @@ ctc_new_device(struct ccwgroup_device *c
 		goto out;
 	}
 
-	if (privptr->protocol == CTC_PROTO_LINUX_TTY)
-		strlcpy(dev->name, "ctctty%d", IFNAMSIZ);
-	else
-		strlcpy(dev->name, "ctc%d", IFNAMSIZ);
+	strlcpy(dev->name, "ctc%d", IFNAMSIZ);
 
 	for (direction = READ; direction <= WRITE; direction++) {
 		privptr->channel[direction] =
@@ -3046,7 +3022,6 @@ ctc_exit(void)
 {
 	DBF_TEXT(setup, 3, __FUNCTION__);
 	unregister_cu3088_discipline(&ctc_group_driver);
-	ctc_tty_cleanup();
 	ctc_unregister_dbf_views();
 	ctc_pr_info("CTC driver unloaded\n");
 }
@@ -3073,10 +3048,8 @@ ctc_init(void)
 		ctc_pr_crit("ctc_init failed with ctc_register_dbf_views rc = %d\n", ret);
 		return ret;
 	}
-	ctc_tty_init();
 	ret = register_cu3088_discipline(&ctc_group_driver);
 	if (ret) {
-		ctc_tty_cleanup();
 		ctc_unregister_dbf_views();
 	}
 	return ret;
diff -Naupr git-linux/drivers/s390/net/ctcmain.h git-patched/drivers/s390/net/ctcmain.h
--- git-linux/drivers/s390/net/ctcmain.h	2006-03-24 09:21:59.000000000 +0100
+++ git-patched/drivers/s390/net/ctcmain.h	2006-03-24 09:41:17.000000000 +0100
@@ -35,7 +35,9 @@
 #include <asm/ccwdev.h>
 #include <asm/ccwgroup.h>
 
-#include "ctctty.h"
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+
 #include "fsm.h"
 #include "cu3088.h"
 
@@ -50,9 +52,7 @@
 
 #define CTC_PROTO_S390          0
 #define CTC_PROTO_LINUX         1
-#define CTC_PROTO_LINUX_TTY     2
 #define CTC_PROTO_OS390         3
-#define CTC_PROTO_MAX           3
 
 #define CTC_BUFSIZE_LIMIT       65535
 #define CTC_BUFSIZE_DEFAULT     32768
@@ -257,15 +257,13 @@ static __inline__ void
 ctc_clear_busy(struct net_device * dev)
 {
 	clear_bit(0, &(((struct ctc_priv *) dev->priv)->tbusy));
-	if (((struct ctc_priv *)dev->priv)->protocol != CTC_PROTO_LINUX_TTY)
-		netif_wake_queue(dev);
+	netif_wake_queue(dev);
 }
 
 static __inline__ int
 ctc_test_and_set_busy(struct net_device * dev)
 {
-	if (((struct ctc_priv *)dev->priv)->protocol != CTC_PROTO_LINUX_TTY)
-		netif_stop_queue(dev);
+	netif_stop_queue(dev);
 	return test_and_set_bit(0, &((struct ctc_priv *) dev->priv)->tbusy);
 }
 
diff -Naupr git-linux/drivers/s390/net/Makefile git-patched/drivers/s390/net/Makefile
--- git-linux/drivers/s390/net/Makefile	2006-03-24 09:21:59.000000000 +0100
+++ git-patched/drivers/s390/net/Makefile	2006-03-24 09:41:17.000000000 +0100
@@ -2,7 +2,7 @@
 # S/390 network devices
 #
 
-ctc-objs := ctcmain.o ctctty.o ctcdbug.o
+ctc-objs := ctcmain.o ctcdbug.o
 
 obj-$(CONFIG_IUCV) += iucv.o
 obj-$(CONFIG_NETIUCV) += netiucv.o fsm.o
@@ -10,6 +10,7 @@ obj-$(CONFIG_SMSGIUCV) += smsgiucv.o
 obj-$(CONFIG_CTC) += ctc.o fsm.o cu3088.o
 obj-$(CONFIG_LCS) += lcs.o cu3088.o
 obj-$(CONFIG_CLAW) += claw.o cu3088.o
+obj-$(CONFIG_MPC) += ctcmpc.o fsm.o cu3088.o
 qeth-y := qeth_main.o qeth_mpc.o qeth_sys.o qeth_eddp.o 
 qeth-$(CONFIG_PROC_FS) += qeth_proc.o
 obj-$(CONFIG_QETH) += qeth.o

^ permalink raw reply

* [RESEND patch 6/6] s390: remove tty support from ctc network device driver [2/2]
From: Frank Pavlic @ 2006-03-24  9:08 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: linux-kernel, netdev
In-Reply-To: <4421FA37.4050703@pobox.com>

[patch 6/6] s390: remove tty support from ctc network device driver [2/2]

From: Peter Tiedemann <ptiedem@de.ibm.com>
	[2/2]: remove ctctty.c and ctctty.h files . 

Signed-off-by: Frank Pavlic <fpavlic@de.ibm.com>

diffstat:

 drivers/s390/net/ctctty.c | 1259 ---------------------------------------------
 drivers/s390/net/ctctty.h |   35 -
 2 files changed, 0 insertions(+), 1294 deletions(-)
 delete mode 100644 drivers/s390/net/ctctty.c
 delete mode 100644 drivers/s390/net/ctctty.h

5849a244ec8f32fe4dbbb8212cb48dc688e7a17d
diff --git a/drivers/s390/net/ctctty.c b/drivers/s390/net/ctctty.c
deleted file mode 100644
index 5cdcdbf..0000000
--- a/drivers/s390/net/ctctty.c
+++ /dev/null
@@ -1,1259 +0,0 @@
-/*
- * CTC / ESCON network driver, tty interface.
- *
- * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
- * Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com)
- *
- * 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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_reg.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <asm/uaccess.h>
-#include <linux/devfs_fs_kernel.h>
-#include "ctctty.h"
-#include "ctcdbug.h"
-
-#define CTC_TTY_MAJOR       43
-#define CTC_TTY_MAX_DEVICES 64
-
-#define CTC_ASYNC_MAGIC          0x49344C01 /* for paranoia-checking        */
-#define CTC_ASYNC_INITIALIZED    0x80000000 /* port was initialized         */
-#define CTC_ASYNC_NORMAL_ACTIVE  0x20000000 /* Normal device active         */
-#define CTC_ASYNC_CLOSING        0x08000000 /* Serial port is closing       */
-#define CTC_ASYNC_CTS_FLOW       0x04000000 /* Do CTS flow control          */
-#define CTC_ASYNC_CHECK_CD       0x02000000 /* i.e., CLOCAL                 */
-#define CTC_ASYNC_HUP_NOTIFY         0x0001 /* Notify tty on hangups/closes */
-#define CTC_ASYNC_NETDEV_OPEN        0x0002 /* Underlying netdev is open    */
-#define CTC_ASYNC_TX_LINESTAT        0x0004 /* Must send line status        */
-#define CTC_ASYNC_SPLIT_TERMIOS      0x0008 /* Sep. termios for dialin/out  */
-#define CTC_TTY_XMIT_SIZE              1024 /* Default bufsize for write    */
-#define CTC_SERIAL_XMIT_MAX            4000 /* Maximum bufsize for write    */
-
-/* Private data (similar to async_struct in <linux/serial.h>) */
-typedef struct {
-  int			magic;
-  int			flags;		 /* defined in tty.h               */
-  int			mcr;		 /* Modem control register         */
-  int                   msr;             /* Modem status register          */
-  int                   lsr;             /* Line status register           */
-  int			line;
-  int			count;		 /* # of fd on device              */
-  int			blocked_open;	 /* # of blocked opens             */
-  struct net_device     *netdev;
-  struct sk_buff_head   tx_queue;        /* transmit queue                 */
-  struct sk_buff_head   rx_queue;        /* receive queue                  */
-  struct tty_struct 	*tty;            /* Pointer to corresponding tty   */
-  wait_queue_head_t	open_wait;
-  wait_queue_head_t	close_wait;
-  struct semaphore      write_sem;
-  struct tasklet_struct tasklet;
-  struct timer_list     stoptimer;
-} ctc_tty_info;
-
-/* Description of one CTC-tty */
-typedef struct {
-  struct tty_driver  *ctc_tty_device;		   /* tty-device             */
-  ctc_tty_info       info[CTC_TTY_MAX_DEVICES];	   /* Private data           */
-} ctc_tty_driver;
-
-static ctc_tty_driver *driver;
-
-/* Leave this unchanged unless you know what you do! */
-#define MODEM_PARANOIA_CHECK
-#define MODEM_DO_RESTART
-
-#define CTC_TTY_NAME "ctctty"
-
-static __u32 ctc_tty_magic = CTC_ASYNC_MAGIC;
-static int ctc_tty_shuttingdown = 0;
-
-static spinlock_t ctc_tty_lock;
-
-/* ctc_tty_try_read() is called from within ctc_tty_rcv_skb()
- * to stuff incoming data directly into a tty's flip-buffer. If the
- * flip buffer is full, the packet gets queued up.
- *
- * Return:
- *  1 = Success
- *  0 = Failure, data has to be buffered and later processed by
- *      ctc_tty_readmodem().
- */
-static int
-ctc_tty_try_read(ctc_tty_info * info, struct sk_buff *skb)
-{
-	int len;
-	struct tty_struct *tty;
-
-	DBF_TEXT(trace, 5, __FUNCTION__);
-	if ((tty = info->tty)) {
-		if (info->mcr & UART_MCR_RTS) {
-			len = skb->len;
-			tty_insert_flip_string(tty, skb->data, len);
-			tty_flip_buffer_push(tty);
-			kfree_skb(skb);
-			return 1;
-		}
-	}
-	return 0;
-}
-
-/* ctc_tty_readmodem() is called periodically from within timer-interrupt.
- * It tries getting received data from the receive queue an stuff it into
- * the tty's flip-buffer.
- */
-static int
-ctc_tty_readmodem(ctc_tty_info *info)
-{
-	int ret = 1;
-	struct tty_struct *tty;
-
-	DBF_TEXT(trace, 5, __FUNCTION__);
-	if ((tty = info->tty)) {
-		if (info->mcr & UART_MCR_RTS) {
-			struct sk_buff *skb;
-			
-			if ((skb = skb_dequeue(&info->rx_queue))) {
-				int len = skb->len;
-				tty_insert_flip_string(tty, skb->data, len);
-				skb_pull(skb, len);
-				tty_flip_buffer_push(tty);
-				if (skb->len > 0)
-					skb_queue_head(&info->rx_queue, skb);
-				else {
-					kfree_skb(skb);
-					ret = !skb_queue_empty(&info->rx_queue);
-				}
-			}
-		}
-	}
-	return ret;
-}
-
-void
-ctc_tty_setcarrier(struct net_device *netdev, int on)
-{
-	int i;
-
-	DBF_TEXT(trace, 4, __FUNCTION__);
-	if ((!driver) || ctc_tty_shuttingdown)
-		return;
-	for (i = 0; i < CTC_TTY_MAX_DEVICES; i++)
-		if (driver->info[i].netdev == netdev) {
-			ctc_tty_info *info = &driver->info[i];
-			if (on)
-				info->msr |= UART_MSR_DCD;
-			else
-				info->msr &= ~UART_MSR_DCD;
-			if ((info->flags & CTC_ASYNC_CHECK_CD) && (!on))
-				tty_hangup(info->tty);
-		}
-}
-
-void
-ctc_tty_netif_rx(struct sk_buff *skb)
-{
-	int i;
-	ctc_tty_info *info = NULL;
-
-	DBF_TEXT(trace, 5, __FUNCTION__);
-	if (!skb)
-		return;
-	if ((!skb->dev) || (!driver) || ctc_tty_shuttingdown) {
-		dev_kfree_skb(skb);
-		return;
-	}
-	for (i = 0; i < CTC_TTY_MAX_DEVICES; i++)
-		if (driver->info[i].netdev == skb->dev) {
-			info = &driver->info[i];
-			break;
-		}
-	if (!info) {
-		dev_kfree_skb(skb);
-		return;
-	}
-	if (skb->len < 6) {
-		dev_kfree_skb(skb);
-		return;
-	}
-	if (memcmp(skb->data, &ctc_tty_magic, sizeof(__u32))) {
-		dev_kfree_skb(skb);
-		return;
-	}
-	skb_pull(skb, sizeof(__u32));
-
-	i = *((int *)skb->data);
-	skb_pull(skb, sizeof(info->mcr));
-	if (i & UART_MCR_RTS) {
-		info->msr |= UART_MSR_CTS;
-		if (info->flags & CTC_ASYNC_CTS_FLOW)
-			info->tty->hw_stopped = 0;
-	} else {
-		info->msr &= ~UART_MSR_CTS;
-		if (info->flags & CTC_ASYNC_CTS_FLOW)
-			info->tty->hw_stopped = 1;
-	}
-	if (i & UART_MCR_DTR)
-		info->msr |= UART_MSR_DSR;
-	else
-		info->msr &= ~UART_MSR_DSR;
-	if (skb->len <= 0) {
-		kfree_skb(skb);
-		return;
-	}
-	/* Try to deliver directly via tty-flip-buf if queue is empty */
-	if (skb_queue_empty(&info->rx_queue))
-		if (ctc_tty_try_read(info, skb))
-			return;
-	/* Direct deliver failed or queue wasn't empty.
-	 * Queue up for later dequeueing via timer-irq.
-	 */
-	skb_queue_tail(&info->rx_queue, skb);
-	/* Schedule dequeuing */
-	tasklet_schedule(&info->tasklet);
-}
-
-static int
-ctc_tty_tint(ctc_tty_info * info)
-{
-	struct sk_buff *skb = skb_dequeue(&info->tx_queue);
-	int stopped = (info->tty->hw_stopped || info->tty->stopped);
-	int wake = 1;
-	int rc;
-
-	DBF_TEXT(trace, 4, __FUNCTION__);
-	if (!info->netdev) {
-		if (skb)
-			kfree_skb(skb);
-		return 0;
-	}
-	if (info->flags & CTC_ASYNC_TX_LINESTAT) {
-		int skb_res = info->netdev->hard_header_len +
-			sizeof(info->mcr) + sizeof(__u32);
-		/* If we must update line status,
-		 * create an empty dummy skb and insert it.
-		 */
-		if (skb)
-			skb_queue_head(&info->tx_queue, skb);
-
-		skb = dev_alloc_skb(skb_res);
-		if (!skb) {
-			printk(KERN_WARNING
-			       "ctc_tty: Out of memory in %s%d tint\n",
-			       CTC_TTY_NAME, info->line);
-			return 1;
-		}
-		skb_reserve(skb, skb_res);
-		stopped = 0;
-		wake = 0;
-	}
-	if (!skb)
-		return 0;
-	if (stopped) {
-		skb_queue_head(&info->tx_queue, skb);
-		return 1;
-	}
-#if 0
-	if (skb->len > 0)
-		printk(KERN_DEBUG "tint: %d %02x\n", skb->len, *(skb->data));
-	else
-		printk(KERN_DEBUG "tint: %d STAT\n", skb->len);
-#endif
-	memcpy(skb_push(skb, sizeof(info->mcr)), &info->mcr, sizeof(info->mcr));
-	memcpy(skb_push(skb, sizeof(__u32)), &ctc_tty_magic, sizeof(__u32));
-	rc = info->netdev->hard_start_xmit(skb, info->netdev);
-	if (rc) {
-		skb_pull(skb, sizeof(info->mcr) + sizeof(__u32));
-		if (skb->len > 0)
-			skb_queue_head(&info->tx_queue, skb);
-		else
-			kfree_skb(skb);
-	} else {
-		struct tty_struct *tty = info->tty;
-
-		info->flags &= ~CTC_ASYNC_TX_LINESTAT;
-		if (tty) {
-			tty_wakeup(tty);
-		}
-	}
-	return (skb_queue_empty(&info->tx_queue) ? 0 : 1);
-}
-
-/************************************************************
- *
- * Modem-functions
- *
- * mostly "stolen" from original Linux-serial.c and friends.
- *
- ************************************************************/
-
-static inline int
-ctc_tty_paranoia_check(ctc_tty_info * info, char *name, const char *routine)
-{
-#ifdef MODEM_PARANOIA_CHECK
-	if (!info) {
-		printk(KERN_WARNING "ctc_tty: null info_struct for %s in %s\n",
-		       name, routine);
-		return 1;
-	}
-	if (info->magic != CTC_ASYNC_MAGIC) {
-		printk(KERN_WARNING "ctc_tty: bad magic for info struct %s in %s\n",
-		       name, routine);
-		return 1;
-	}
-#endif
-	return 0;
-}
-
-static void
-ctc_tty_inject(ctc_tty_info *info, char c)
-{
-	int skb_res;
-	struct sk_buff *skb;
-	
-	DBF_TEXT(trace, 4, __FUNCTION__);
-	if (ctc_tty_shuttingdown)
-		return;
-	skb_res = info->netdev->hard_header_len + sizeof(info->mcr) +
-		sizeof(__u32) + 1;
-	skb = dev_alloc_skb(skb_res);
-	if (!skb) {
-		printk(KERN_WARNING
-		       "ctc_tty: Out of memory in %s%d tx_inject\n",
-		       CTC_TTY_NAME, info->line);
-		return;
-	}
-	skb_reserve(skb, skb_res);
-	*(skb_put(skb, 1)) = c;
-	skb_queue_head(&info->tx_queue, skb);
-	tasklet_schedule(&info->tasklet);
-}
-
-static void
-ctc_tty_transmit_status(ctc_tty_info *info)
-{
-	DBF_TEXT(trace, 5, __FUNCTION__);
-	if (ctc_tty_shuttingdown)
-		return;
-	info->flags |= CTC_ASYNC_TX_LINESTAT;
-	tasklet_schedule(&info->tasklet);
-}
-
-static void
-ctc_tty_change_speed(ctc_tty_info * info)
-{
-	unsigned int cflag;
-	unsigned int quot;
-	int i;
-
-	DBF_TEXT(trace, 3, __FUNCTION__);
-	if (!info->tty || !info->tty->termios)
-		return;
-	cflag = info->tty->termios->c_cflag;
-
-	quot = i = cflag & CBAUD;
-	if (i & CBAUDEX) {
-		i &= ~CBAUDEX;
-		if (i < 1 || i > 2)
-			info->tty->termios->c_cflag &= ~CBAUDEX;
-		else
-			i += 15;
-	}
-	if (quot) {
-		info->mcr |= UART_MCR_DTR;
-		info->mcr |= UART_MCR_RTS;
-		ctc_tty_transmit_status(info);
-	} else {
-		info->mcr &= ~UART_MCR_DTR;
-		info->mcr &= ~UART_MCR_RTS;
-		ctc_tty_transmit_status(info);
-		return;
-	}
-
-	/* CTS flow control flag and modem status interrupts */
-	if (cflag & CRTSCTS) {
-		info->flags |= CTC_ASYNC_CTS_FLOW;
-	} else
-		info->flags &= ~CTC_ASYNC_CTS_FLOW;
-	if (cflag & CLOCAL)
-		info->flags &= ~CTC_ASYNC_CHECK_CD;
-	else {
-		info->flags |= CTC_ASYNC_CHECK_CD;
-	}
-}
-
-static int
-ctc_tty_startup(ctc_tty_info * info)
-{
-	DBF_TEXT(trace, 3, __FUNCTION__);
-	if (info->flags & CTC_ASYNC_INITIALIZED)
-		return 0;
-#ifdef CTC_DEBUG_MODEM_OPEN
-	printk(KERN_DEBUG "starting up %s%d ...\n", CTC_TTY_NAME, info->line);
-#endif
-	/*
-	 * Now, initialize the UART
-	 */
-	info->mcr = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
-	if (info->tty)
-		clear_bit(TTY_IO_ERROR, &info->tty->flags);
-	/*
-	 * and set the speed of the serial port
-	 */
-	ctc_tty_change_speed(info);
-
-	info->flags |= CTC_ASYNC_INITIALIZED;
-	if (!(info->flags & CTC_ASYNC_NETDEV_OPEN))
-		info->netdev->open(info->netdev);
-	info->flags |= CTC_ASYNC_NETDEV_OPEN;
-	return 0;
-}
-
-static void
-ctc_tty_stopdev(unsigned long data)
-{
-	ctc_tty_info *info = (ctc_tty_info *)data;
-
-	if ((!info) || (!info->netdev) ||
-	    (info->flags & CTC_ASYNC_INITIALIZED))
-		return;
-	info->netdev->stop(info->netdev);
-	info->flags &= ~CTC_ASYNC_NETDEV_OPEN;
-}
-
-/*
- * This routine will shutdown a serial port; interrupts are disabled, and
- * DTR is dropped if the hangup on close termio flag is on.
- */
-static void
-ctc_tty_shutdown(ctc_tty_info * info)
-{
-	DBF_TEXT(trace, 3, __FUNCTION__);
-	if (!(info->flags & CTC_ASYNC_INITIALIZED))
-		return;
-#ifdef CTC_DEBUG_MODEM_OPEN
-	printk(KERN_DEBUG "Shutting down %s%d ....\n", CTC_TTY_NAME, info->line);
-#endif
-	info->msr &= ~UART_MSR_RI;
-	if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
-		info->mcr &= ~(UART_MCR_DTR | UART_MCR_RTS);
-	if (info->tty)
-		set_bit(TTY_IO_ERROR, &info->tty->flags);
-	mod_timer(&info->stoptimer, jiffies + (10 * HZ));
-	skb_queue_purge(&info->tx_queue);
-	skb_queue_purge(&info->rx_queue);
-	info->flags &= ~CTC_ASYNC_INITIALIZED;
-}
-
-/* ctc_tty_write() is the main send-routine. It is called from the upper
- * levels within the kernel to perform sending data. Depending on the
- * online-flag it either directs output to the at-command-interpreter or
- * to the lower level. Additional tasks done here:
- *  - If online, check for escape-sequence (+++)
- *  - If sending audio-data, call ctc_tty_DLEdown() to parse DLE-codes.
- *  - If receiving audio-data, call ctc_tty_end_vrx() to abort if needed.
- *  - If dialing, abort dial.
- */
-static int
-ctc_tty_write(struct tty_struct *tty, const u_char * buf, int count)
-{
-	int c;
-	int total = 0;
-	ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
-
-	DBF_TEXT(trace, 5, __FUNCTION__);
-	if (ctc_tty_shuttingdown)
-		goto ex;
-	if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_write"))
-		goto ex;
-	if (!tty)
-		goto ex;
-	if (!info->netdev) {
-		total = -ENODEV;
-		goto ex;
-	}
-	while (1) {
-		struct sk_buff *skb;
-		int skb_res;
-
-		c = (count < CTC_TTY_XMIT_SIZE) ? count : CTC_TTY_XMIT_SIZE;
-		if (c <= 0)
-			break;
-		
-		skb_res = info->netdev->hard_header_len + sizeof(info->mcr) +
-			+ sizeof(__u32);
-		skb = dev_alloc_skb(skb_res + c);
-		if (!skb) {
-			printk(KERN_WARNING
-			       "ctc_tty: Out of memory in %s%d write\n",
-			       CTC_TTY_NAME, info->line);
-			break;
-		}
-		skb_reserve(skb, skb_res);
-		memcpy(skb_put(skb, c), buf, c);
-		skb_queue_tail(&info->tx_queue, skb);
-		buf += c;
-		total += c;
-		count -= c;
-	}
-	if (!skb_queue_empty(&info->tx_queue)) {
-		info->lsr &= ~UART_LSR_TEMT;
-		tasklet_schedule(&info->tasklet);
-	}
-ex:
-	DBF_TEXT(trace, 6, __FUNCTION__);
-	return total;
-}
-
-static int
-ctc_tty_write_room(struct tty_struct *tty)
-{
-	ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
-
-	if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_write_room"))
-		return 0;
-	return CTC_TTY_XMIT_SIZE;
-}
-
-static int
-ctc_tty_chars_in_buffer(struct tty_struct *tty)
-{
-	ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
-
-	if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_chars_in_buffer"))
-		return 0;
-	return 0;
-}
-
-static void
-ctc_tty_flush_buffer(struct tty_struct *tty)
-{
-	ctc_tty_info *info;
-	unsigned long flags;
-
-	DBF_TEXT(trace, 4, __FUNCTION__);
-	if (!tty)
-		goto ex;
-	spin_lock_irqsave(&ctc_tty_lock, flags);
-	info = (ctc_tty_info *) tty->driver_data;
-	if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_flush_buffer")) {
-		spin_unlock_irqrestore(&ctc_tty_lock, flags);
-		goto ex;
-	}
-	skb_queue_purge(&info->tx_queue);
-	info->lsr |= UART_LSR_TEMT;
-	spin_unlock_irqrestore(&ctc_tty_lock, flags);
-	wake_up_interruptible(&tty->write_wait);
-	tty_wakeup(tty);
-ex:
-	DBF_TEXT_(trace, 2, "ex: %s ", __FUNCTION__);
-	return;
-}
-
-static void
-ctc_tty_flush_chars(struct tty_struct *tty)
-{
-	ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
-
-	DBF_TEXT(trace, 4, __FUNCTION__);
-	if (ctc_tty_shuttingdown)
-		return;
-	if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_flush_chars"))
-		return;
-	if (tty->stopped || tty->hw_stopped || skb_queue_empty(&info->tx_queue))
-		return;
-	tasklet_schedule(&info->tasklet);
-}
-
-/*
- * ------------------------------------------------------------
- * ctc_tty_throttle()
- *
- * This routine is called by the upper-layer tty layer to signal that
- * incoming characters should be throttled.
- * ------------------------------------------------------------
- */
-static void
-ctc_tty_throttle(struct tty_struct *tty)
-{
-	ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
-
-	DBF_TEXT(trace, 4, __FUNCTION__);
-	if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_throttle"))
-		return;
-	info->mcr &= ~UART_MCR_RTS;
-	if (I_IXOFF(tty))
-		ctc_tty_inject(info, STOP_CHAR(tty));
-	ctc_tty_transmit_status(info);
-}
-
-static void
-ctc_tty_unthrottle(struct tty_struct *tty)
-{
-	ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
-
-	DBF_TEXT(trace, 4, __FUNCTION__);
-	if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_unthrottle"))
-		return;
-	info->mcr |= UART_MCR_RTS;
-	if (I_IXOFF(tty))
-		ctc_tty_inject(info, START_CHAR(tty));
-	ctc_tty_transmit_status(info);
-}
-
-/*
- * ------------------------------------------------------------
- * ctc_tty_ioctl() and friends
- * ------------------------------------------------------------
- */
-
-/*
- * ctc_tty_get_lsr_info - get line status register info
- *
- * Purpose: Let user call ioctl() to get info when the UART physically
- *          is emptied.  On bus types like RS485, the transmitter must
- *          release the bus after transmitting. This must be done when
- *          the transmit shift register is empty, not be done when the
- *          transmit holding register is empty.  This functionality
- *          allows RS485 driver to be written in user space.
- */
-static int
-ctc_tty_get_lsr_info(ctc_tty_info * info, uint __user *value)
-{
-	u_char status;
-	uint result;
-	ulong flags;
-
-	DBF_TEXT(trace, 4, __FUNCTION__);
-	spin_lock_irqsave(&ctc_tty_lock, flags);
-	status = info->lsr;
-	spin_unlock_irqrestore(&ctc_tty_lock, flags);
-	result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
-	put_user(result, value);
-	return 0;
-}
-
-
-static int ctc_tty_tiocmget(struct tty_struct *tty, struct file *file)
-{
-	ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
-	u_char control,
-	 status;
-	uint result;
-	ulong flags;
-
-	DBF_TEXT(trace, 4, __FUNCTION__);
-	if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_ioctl"))
-		return -ENODEV;
-	if (tty->flags & (1 << TTY_IO_ERROR))
-		return -EIO;
-
-	control = info->mcr;
-	spin_lock_irqsave(&ctc_tty_lock, flags);
-	status = info->msr;
-	spin_unlock_irqrestore(&ctc_tty_lock, flags);
-	result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
-	    | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
-	    | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0)
-	    | ((status & UART_MSR_RI) ? TIOCM_RNG : 0)
-	    | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0)
-	    | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
-	return result;
-}
-
-static int
-ctc_tty_tiocmset(struct tty_struct *tty, struct file *file,
-		 unsigned int set, unsigned int clear)
-{
-	ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
-
-	DBF_TEXT(trace, 4, __FUNCTION__);
-	if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_ioctl"))
-		return -ENODEV;
-	if (tty->flags & (1 << TTY_IO_ERROR))
-		return -EIO;
-
-	if (set & TIOCM_RTS)
-		info->mcr |= UART_MCR_RTS;
-	if (set & TIOCM_DTR)
-		info->mcr |= UART_MCR_DTR;
-
-	if (clear & TIOCM_RTS)
-		info->mcr &= ~UART_MCR_RTS;
-	if (clear & TIOCM_DTR)
-		info->mcr &= ~UART_MCR_DTR;
-
-	if ((set | clear) & (TIOCM_RTS|TIOCM_DTR))
-		ctc_tty_transmit_status(info);
-	return 0;
-}
-
-static int
-ctc_tty_ioctl(struct tty_struct *tty, struct file *file,
-	       uint cmd, ulong arg)
-{
-	ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
-	int error;
-	int retval;
-
-	DBF_TEXT(trace, 4, __FUNCTION__);
-	if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_ioctl"))
-		return -ENODEV;
-	if (tty->flags & (1 << TTY_IO_ERROR))
-		return -EIO;
-	switch (cmd) {
-		case TCSBRK:   /* SVID version: non-zero arg --> no break */
-#ifdef CTC_DEBUG_MODEM_IOCTL
-			printk(KERN_DEBUG "%s%d ioctl TCSBRK\n", CTC_TTY_NAME, info->line);
-#endif
-			retval = tty_check_change(tty);
-			if (retval)
-				return retval;
-			tty_wait_until_sent(tty, 0);
-			return 0;
-		case TCSBRKP:  /* support for POSIX tcsendbreak() */
-#ifdef CTC_DEBUG_MODEM_IOCTL
-			printk(KERN_DEBUG "%s%d ioctl TCSBRKP\n", CTC_TTY_NAME, info->line);
-#endif
-			retval = tty_check_change(tty);
-			if (retval)
-				return retval;
-			tty_wait_until_sent(tty, 0);
-			return 0;
-		case TIOCGSOFTCAR:
-#ifdef CTC_DEBUG_MODEM_IOCTL
-			printk(KERN_DEBUG "%s%d ioctl TIOCGSOFTCAR\n", CTC_TTY_NAME,
-			       info->line);
-#endif
-			error = put_user(C_CLOCAL(tty) ? 1 : 0, (ulong __user *) arg);
-			return error;
-		case TIOCSSOFTCAR:
-#ifdef CTC_DEBUG_MODEM_IOCTL
-			printk(KERN_DEBUG "%s%d ioctl TIOCSSOFTCAR\n", CTC_TTY_NAME,
-			       info->line);
-#endif
-			error = get_user(arg, (ulong __user *) arg);
-			if (error)
-				return error;
-			tty->termios->c_cflag =
-			    ((tty->termios->c_cflag & ~CLOCAL) |
-			     (arg ? CLOCAL : 0));
-			return 0;
-		case TIOCSERGETLSR:	/* Get line status register */
-#ifdef CTC_DEBUG_MODEM_IOCTL
-			printk(KERN_DEBUG "%s%d ioctl TIOCSERGETLSR\n", CTC_TTY_NAME,
-			       info->line);
-#endif
-			if (access_ok(VERIFY_WRITE, (void __user *) arg, sizeof(uint)))
-				return ctc_tty_get_lsr_info(info, (uint __user *) arg);
-			else
-				return -EFAULT;
-		default:
-#ifdef CTC_DEBUG_MODEM_IOCTL
-			printk(KERN_DEBUG "UNKNOWN ioctl 0x%08x on %s%d\n", cmd,
-			       CTC_TTY_NAME, info->line);
-#endif
-			return -ENOIOCTLCMD;
-	}
-	return 0;
-}
-
-static void
-ctc_tty_set_termios(struct tty_struct *tty, struct termios *old_termios)
-{
-	ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
-	unsigned int cflag = tty->termios->c_cflag;
-
-	DBF_TEXT(trace, 4, __FUNCTION__);
-	ctc_tty_change_speed(info);
-
-	/* Handle transition to B0 */
-	if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD)) {
-		info->mcr &= ~(UART_MCR_DTR|UART_MCR_RTS);
-		ctc_tty_transmit_status(info);
-	}
-
-	/* Handle transition from B0 to other */
-	if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
-		info->mcr |= UART_MCR_DTR;
-		if (!(tty->termios->c_cflag & CRTSCTS) ||
-                    !test_bit(TTY_THROTTLED, &tty->flags)) {
-                        info->mcr |= UART_MCR_RTS;
-                }
-		ctc_tty_transmit_status(info);
-	}
-
-	/* Handle turning off CRTSCTS */
-	if ((old_termios->c_cflag & CRTSCTS) &&
-            !(tty->termios->c_cflag & CRTSCTS))
-                tty->hw_stopped = 0;
-}
-
-/*
- * ------------------------------------------------------------
- * ctc_tty_open() and friends
- * ------------------------------------------------------------
- */
-static int
-ctc_tty_block_til_ready(struct tty_struct *tty, struct file *filp, ctc_tty_info *info)
-{
-	DECLARE_WAITQUEUE(wait, NULL);
-	int do_clocal = 0;
-	unsigned long flags;
-	int retval;
-
-	DBF_TEXT(trace, 4, __FUNCTION__);
-	/*
-	 * If the device is in the middle of being closed, then block
-	 * until it's done, and then try again.
-	 */
-	if (tty_hung_up_p(filp) ||
-	    (info->flags & CTC_ASYNC_CLOSING)) {
-		if (info->flags & CTC_ASYNC_CLOSING)
-			wait_event(info->close_wait, 
-				   !(info->flags & CTC_ASYNC_CLOSING));
-#ifdef MODEM_DO_RESTART
-		if (info->flags & CTC_ASYNC_HUP_NOTIFY)
-			return -EAGAIN;
-		else
-			return -ERESTARTSYS;
-#else
-		return -EAGAIN;
-#endif
-	}
-	/*
-	 * If non-blocking mode is set, then make the check up front
-	 * and then exit.
-	 */
-	if ((filp->f_flags & O_NONBLOCK) ||
-	    (tty->flags & (1 << TTY_IO_ERROR))) {
-		info->flags |= CTC_ASYNC_NORMAL_ACTIVE;
-		return 0;
-	}
-	if (tty->termios->c_cflag & CLOCAL)
-		do_clocal = 1;
-	/*
-	 * Block waiting for the carrier detect and the line to become
-	 * free (i.e., not in use by the callout).  While we are in
-	 * this loop, info->count is dropped by one, so that
-	 * ctc_tty_close() knows when to free things.  We restore it upon
-	 * exit, either normal or abnormal.
-	 */
-	retval = 0;
-	add_wait_queue(&info->open_wait, &wait);
-#ifdef CTC_DEBUG_MODEM_OPEN
-	printk(KERN_DEBUG "ctc_tty_block_til_ready before block: %s%d, count = %d\n",
-	       CTC_TTY_NAME, info->line, info->count);
-#endif
-	spin_lock_irqsave(&ctc_tty_lock, flags);
-	if (!(tty_hung_up_p(filp)))
-		info->count--;
-	spin_unlock_irqrestore(&ctc_tty_lock, flags);
-	info->blocked_open++;
-	while (1) {
-		set_current_state(TASK_INTERRUPTIBLE);
-		if (tty_hung_up_p(filp) ||
-		    !(info->flags & CTC_ASYNC_INITIALIZED)) {
-#ifdef MODEM_DO_RESTART
-			if (info->flags & CTC_ASYNC_HUP_NOTIFY)
-				retval = -EAGAIN;
-			else
-				retval = -ERESTARTSYS;
-#else
-			retval = -EAGAIN;
-#endif
-			break;
-		}
-		if (!(info->flags & CTC_ASYNC_CLOSING) &&
-		    (do_clocal || (info->msr & UART_MSR_DCD))) {
-			break;
-		}
-		if (signal_pending(current)) {
-			retval = -ERESTARTSYS;
-			break;
-		}
-#ifdef CTC_DEBUG_MODEM_OPEN
-		printk(KERN_DEBUG "ctc_tty_block_til_ready blocking: %s%d, count = %d\n",
-		       CTC_TTY_NAME, info->line, info->count);
-#endif
-		schedule();
-	}
-	current->state = TASK_RUNNING;
-	remove_wait_queue(&info->open_wait, &wait);
-	if (!tty_hung_up_p(filp))
-		info->count++;
-	info->blocked_open--;
-#ifdef CTC_DEBUG_MODEM_OPEN
-	printk(KERN_DEBUG "ctc_tty_block_til_ready after blocking: %s%d, count = %d\n",
-	       CTC_TTY_NAME, info->line, info->count);
-#endif
-	if (retval)
-		return retval;
-	info->flags |= CTC_ASYNC_NORMAL_ACTIVE;
-	return 0;
-}
-
-/*
- * This routine is called whenever a serial port is opened.  It
- * enables interrupts for a serial port, linking in its async structure into
- * the IRQ chain.   It also performs the serial-specific
- * initialization for the tty structure.
- */
-static int
-ctc_tty_open(struct tty_struct *tty, struct file *filp)
-{
-	ctc_tty_info *info;
-	unsigned long saveflags;
-	int retval,
-	 line;
-
-	DBF_TEXT(trace, 3, __FUNCTION__);
-	line = tty->index;
-	if (line < 0 || line > CTC_TTY_MAX_DEVICES)
-		return -ENODEV;
-	info = &driver->info[line];
-	if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_open"))
-		return -ENODEV;
-	if (!info->netdev)
-		return -ENODEV;
-#ifdef CTC_DEBUG_MODEM_OPEN
-	printk(KERN_DEBUG "ctc_tty_open %s, count = %d\n", tty->name,
-	       info->count);
-#endif
-	spin_lock_irqsave(&ctc_tty_lock, saveflags);
-	info->count++;
-	tty->driver_data = info;
-	info->tty = tty;
-	spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
-	/*
-	 * Start up serial port
-	 */
-	retval = ctc_tty_startup(info);
-	if (retval) {
-#ifdef CTC_DEBUG_MODEM_OPEN
-		printk(KERN_DEBUG "ctc_tty_open return after startup\n");
-#endif
-		return retval;
-	}
-	retval = ctc_tty_block_til_ready(tty, filp, info);
-	if (retval) {
-#ifdef CTC_DEBUG_MODEM_OPEN
-		printk(KERN_DEBUG "ctc_tty_open return after ctc_tty_block_til_ready \n");
-#endif
-		return retval;
-	}
-#ifdef CTC_DEBUG_MODEM_OPEN
-	printk(KERN_DEBUG "ctc_tty_open %s successful...\n", tty->name);
-#endif
-	return 0;
-}
-
-static void
-ctc_tty_close(struct tty_struct *tty, struct file *filp)
-{
-	ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
-	ulong flags;
-	ulong timeout;
-	DBF_TEXT(trace, 3, __FUNCTION__);
-	if (!info || ctc_tty_paranoia_check(info, tty->name, "ctc_tty_close"))
-		return;
-	spin_lock_irqsave(&ctc_tty_lock, flags);
-	if (tty_hung_up_p(filp)) {
-		spin_unlock_irqrestore(&ctc_tty_lock, flags);
-#ifdef CTC_DEBUG_MODEM_OPEN
-		printk(KERN_DEBUG "ctc_tty_close return after tty_hung_up_p\n");
-#endif
-		return;
-	}
-	if ((tty->count == 1) && (info->count != 1)) {
-		/*
-		 * Uh, oh.  tty->count is 1, which means that the tty
-		 * structure will be freed.  Info->count should always
-		 * be one in these conditions.  If it's greater than
-		 * one, we've got real problems, since it means the
-		 * serial port won't be shutdown.
-		 */
-		printk(KERN_ERR "ctc_tty_close: bad port count; tty->count is 1, "
-		       "info->count is %d\n", info->count);
-		info->count = 1;
-	}
-	if (--info->count < 0) {
-		printk(KERN_ERR "ctc_tty_close: bad port count for %s%d: %d\n",
-		       CTC_TTY_NAME, info->line, info->count);
-		info->count = 0;
-	}
-	if (info->count) {
-		local_irq_restore(flags);
-#ifdef CTC_DEBUG_MODEM_OPEN
-		printk(KERN_DEBUG "ctc_tty_close after info->count != 0\n");
-#endif
-		return;
-	}
-	info->flags |= CTC_ASYNC_CLOSING;
-	tty->closing = 1;
-	/*
-	 * At this point we stop accepting input.  To do this, we
-	 * disable the receive line status interrupts, and tell the
-	 * interrupt driver to stop checking the data ready bit in the
-	 * line status register.
-	 */
-	if (info->flags & CTC_ASYNC_INITIALIZED) {
-		tty_wait_until_sent(tty, 30*HZ); /* 30 seconds timeout */
-		/*
-		 * Before we drop DTR, make sure the UART transmitter
-		 * has completely drained; this is especially
-		 * important if there is a transmit FIFO!
-		 */
-		timeout = jiffies + HZ;
-		while (!(info->lsr & UART_LSR_TEMT)) {
-			spin_unlock_irqrestore(&ctc_tty_lock, flags);
-			msleep(500);
-			spin_lock_irqsave(&ctc_tty_lock, flags);
-			if (time_after(jiffies,timeout))
-				break;
-		}
-	}
-	ctc_tty_shutdown(info);
-	if (tty->driver->flush_buffer) {
-		skb_queue_purge(&info->tx_queue);
-		info->lsr |= UART_LSR_TEMT;
-	}
-	tty_ldisc_flush(tty);
-	info->tty = 0;
-	tty->closing = 0;
-	if (info->blocked_open) {
-		msleep_interruptible(500);
-		wake_up_interruptible(&info->open_wait);
-	}
-	info->flags &= ~(CTC_ASYNC_NORMAL_ACTIVE | CTC_ASYNC_CLOSING);
-	wake_up_interruptible(&info->close_wait);
-	spin_unlock_irqrestore(&ctc_tty_lock, flags);
-#ifdef CTC_DEBUG_MODEM_OPEN
-	printk(KERN_DEBUG "ctc_tty_close normal exit\n");
-#endif
-}
-
-/*
- * ctc_tty_hangup() --- called by tty_hangup() when a hangup is signaled.
- */
-static void
-ctc_tty_hangup(struct tty_struct *tty)
-{
-	ctc_tty_info *info = (ctc_tty_info *)tty->driver_data;
-	unsigned long saveflags;
-	DBF_TEXT(trace, 3, __FUNCTION__);
-	if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_hangup"))
-		return;
-	ctc_tty_shutdown(info);
-	info->count = 0;
-	info->flags &= ~CTC_ASYNC_NORMAL_ACTIVE;
-	spin_lock_irqsave(&ctc_tty_lock, saveflags);
-	info->tty = 0;
-	spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
-	wake_up_interruptible(&info->open_wait);
-}
-
-
-/*
- * For all online tty's, try sending data to
- * the lower levels.
- */
-static void
-ctc_tty_task(unsigned long arg)
-{
-	ctc_tty_info *info = (void *)arg;
-	unsigned long saveflags;
-	int again;
-
-	DBF_TEXT(trace, 3, __FUNCTION__);
-	spin_lock_irqsave(&ctc_tty_lock, saveflags);
-	if ((!ctc_tty_shuttingdown) && info) {
-		again = ctc_tty_tint(info);
-		if (!again)
-			info->lsr |= UART_LSR_TEMT;
-		again |= ctc_tty_readmodem(info);
-		if (again) {
-			tasklet_schedule(&info->tasklet);
-		}
-	}
-	spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
-}
-
-static struct tty_operations ctc_ops = {
-	.open = ctc_tty_open,
-	.close = ctc_tty_close,
-	.write = ctc_tty_write,
-	.flush_chars = ctc_tty_flush_chars,
-	.write_room = ctc_tty_write_room,
-	.chars_in_buffer = ctc_tty_chars_in_buffer,
-	.flush_buffer = ctc_tty_flush_buffer,
-	.ioctl = ctc_tty_ioctl,
-	.throttle = ctc_tty_throttle,
-	.unthrottle = ctc_tty_unthrottle,
-	.set_termios = ctc_tty_set_termios,
-	.hangup = ctc_tty_hangup,
-	.tiocmget = ctc_tty_tiocmget,
-	.tiocmset = ctc_tty_tiocmset,
-};
-
-int
-ctc_tty_init(void)
-{
-	int i;
-	ctc_tty_info *info;
-	struct tty_driver *device;
-
-	DBF_TEXT(trace, 2, __FUNCTION__);
-	driver = kmalloc(sizeof(ctc_tty_driver), GFP_KERNEL);
-	if (driver == NULL) {
-		printk(KERN_WARNING "Out of memory in ctc_tty_modem_init\n");
-		return -ENOMEM;
-	}
-	memset(driver, 0, sizeof(ctc_tty_driver));
-	device = alloc_tty_driver(CTC_TTY_MAX_DEVICES);
-	if (!device) {
-		kfree(driver);
-		printk(KERN_WARNING "Out of memory in ctc_tty_modem_init\n");
-		return -ENOMEM;
-	}
-
-	device->devfs_name = "ctc/" CTC_TTY_NAME;
-	device->name = CTC_TTY_NAME;
-	device->major = CTC_TTY_MAJOR;
-	device->minor_start = 0;
-	device->type = TTY_DRIVER_TYPE_SERIAL;
-	device->subtype = SERIAL_TYPE_NORMAL;
-	device->init_termios = tty_std_termios;
-	device->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-	device->flags = TTY_DRIVER_REAL_RAW;
-	device->driver_name = "ctc_tty",
-	tty_set_operations(device, &ctc_ops);
-	if (tty_register_driver(device)) {
-		printk(KERN_WARNING "ctc_tty: Couldn't register serial-device\n");
-		put_tty_driver(device);
-		kfree(driver);
-		return -1;
-	}
-	driver->ctc_tty_device = device;
-	for (i = 0; i < CTC_TTY_MAX_DEVICES; i++) {
-		info = &driver->info[i];
-		init_MUTEX(&info->write_sem);
-		tasklet_init(&info->tasklet, ctc_tty_task,
-				(unsigned long) info);
-		info->magic = CTC_ASYNC_MAGIC;
-		info->line = i;
-		info->tty = 0;
-		info->count = 0;
-		info->blocked_open = 0;
-		init_waitqueue_head(&info->open_wait);
-		init_waitqueue_head(&info->close_wait);
-		skb_queue_head_init(&info->tx_queue);
-		skb_queue_head_init(&info->rx_queue);
-		init_timer(&info->stoptimer);
-		info->stoptimer.function = ctc_tty_stopdev;
-		info->stoptimer.data = (unsigned long)info;
-		info->mcr = UART_MCR_RTS;
-	}
-	return 0;
-}
-
-int
-ctc_tty_register_netdev(struct net_device *dev) {
-	int ttynum;
-	char *err;
-	char *p;
-
-	DBF_TEXT(trace, 2, __FUNCTION__);
-	if ((!dev) || (!dev->name)) {
-		printk(KERN_WARNING
-		       "ctc_tty_register_netdev called "
-		       "with NULL dev or NULL dev-name\n");
-		return -1;
-	}
-
-	/*
-	 *	If the name is a format string the caller wants us to
-	 *	do a name allocation : format string must end with %d
-	 */
-	if (strchr(dev->name, '%'))
-	{
-		int err = dev_alloc_name(dev, dev->name);	// dev->name is changed by this
-		if (err < 0) {
-			printk(KERN_DEBUG "dev_alloc returned error %d\n", err);
-			return err;
-		}
-
-	}
-
-	for (p = dev->name; p && ((*p < '0') || (*p > '9')); p++);
-	ttynum = simple_strtoul(p, &err, 0);
-	if ((ttynum < 0) || (ttynum >= CTC_TTY_MAX_DEVICES) ||
-	    (err && *err)) {
-		printk(KERN_WARNING
-		       "ctc_tty_register_netdev called "
-		       "with number in name '%s'\n", dev->name);
-		return -1;
-	}
-	if (driver->info[ttynum].netdev) {
-		printk(KERN_WARNING
-		       "ctc_tty_register_netdev called "
-		       "for already registered device '%s'\n",
-		       dev->name);
-		return -1;
-	}
-	driver->info[ttynum].netdev = dev;
-	return 0;
-}
-
-void
-ctc_tty_unregister_netdev(struct net_device *dev) {
-	int i;
-	unsigned long saveflags;
-	ctc_tty_info *info = NULL;
-
-	DBF_TEXT(trace, 2, __FUNCTION__);
-	spin_lock_irqsave(&ctc_tty_lock, saveflags);
-	for (i = 0; i < CTC_TTY_MAX_DEVICES; i++)
-		if (driver->info[i].netdev == dev) {
-			info = &driver->info[i];
-			break;
-		}
-	if (info) {
-		info->netdev = NULL;
-		skb_queue_purge(&info->tx_queue);
-		skb_queue_purge(&info->rx_queue);
-	}
-	spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
-}
-
-void
-ctc_tty_cleanup(void) {
-	unsigned long saveflags;
-	
-	DBF_TEXT(trace, 2, __FUNCTION__);
-	spin_lock_irqsave(&ctc_tty_lock, saveflags);
-	ctc_tty_shuttingdown = 1;
-	spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
-	tty_unregister_driver(driver->ctc_tty_device);
-	put_tty_driver(driver->ctc_tty_device);
-	kfree(driver);
-	driver = NULL;
-}
diff --git a/drivers/s390/net/ctctty.h b/drivers/s390/net/ctctty.h
deleted file mode 100644
index 7254dc0..0000000
--- a/drivers/s390/net/ctctty.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * CTC / ESCON network driver, tty interface.
- *
- * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
- * Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com)
- *
- * 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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef _CTCTTY_H_
-#define _CTCTTY_H_
-
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-
-extern int  ctc_tty_register_netdev(struct net_device *);
-extern void ctc_tty_unregister_netdev(struct net_device *);
-extern void ctc_tty_netif_rx(struct sk_buff *);
-extern int  ctc_tty_init(void);
-extern void ctc_tty_cleanup(void);
-extern void ctc_tty_setcarrier(struct net_device *, int);
-
-#endif
-- 
1.2.4

^ permalink raw reply related

* Re: [2.6.16-gitX] heavy performance regression in ipw2200 wireless driver
From: Alessandro Suardi @ 2006-03-24  9:30 UTC (permalink / raw)
  To: Zhu Yi; +Cc: Andrew Morton, linux-kernel, James Ketrenos, netdev
In-Reply-To: <1143171674.17270.195.camel@debian.sh.intel.com>

On 3/24/06, Zhu Yi <yi.zhu@intel.com> wrote:
> On Thu, 2006-03-23 at 15:02 +0100, Alessandro Suardi wrote:
> > That scp test shows 50%ish - but that was a quickie. The VNC
> >  client even reported a 719Kbps throughput down from the more
> >  usual 11500Kbps it starts off with. The first scp I tried when the
> >  sluggishness was intolerable was going at 200KB/s - which
> >  shows the problem can easily get in the neighborhood of an
> >  order of magnitude.
>
> What kind of wireless encryption do you use? We turned off hardware
> encryption by default recently as a workaround for a firmware restart
> bug. You might want to load module with "modprobe ipw2200 hwcrypto=1"
> and retest.

I actually use no encryption yet, as I still have to find out time
 to call D-Link about the fact that my router hangs when I try
 to set up a whitelist of MAC addresses for the wireless AP;
 WPA would be up next...

Would loading the module with h/w encryption turned on
 make any difference in my case ?

Thanks,

PS don't tell my neighbors ;)

--alessandro

 "Dreamer ? Each one of us is a dreamer. We just push it down deep because
   we are repeatedly told that we are not allowed to dream in real life"
     (Reinhold Ziegler)

^ permalink raw reply

* Re: [RFC][UPDATED PATCH 2.6.16] [Patch 9/9] Generic netlink interface for delay accounting
From: jamal @ 2006-03-24 14:04 UTC (permalink / raw)
  To: balbir; +Cc: Matt Helsley, Shailabh Nagar, linux-kernel, netdev
In-Reply-To: <20060323154106.GA13159@in.ibm.com>

On Thu, 2006-23-03 at 21:11 +0530, Balbir Singh wrote:
> On Thu, Mar 23, 2006 at 09:04:46AM -0500, jamal wrote:

> > Should there be at least either a pid or tgid? If yes, you need to
> > validate here...
> >
> 
> Yes, you are correct. One of my test cases caught it too.. But I did
> not want to untidy the code with if-else's which will keep growing if
> the attributes change in the future. I just followed the controller
> example. I will change it and validate it. Currently if the attribute
> is not valid, a stat of all zero's is returned back.
>  

There are many ways to skin this cat.
As an example: you could make pid and tgid global to the function and
set them to 0. At the end of the if statements, you could check if at
least one of them is set - if not you know none was passed and bail out.

> > As a general comment double check your logic for errors; if you already
> > have stashed something in the skb, you need to remove it etc.
> > 
> 
> Wouldn't genlmsg_cancel() take care of cleaning all attributes?
> 

it would for attribute setting - but not for others. As a general
comment this is one of those areas where cutnpasting aka TheLinuxWay(tm)
could result in errors.


> > A single message with PID+TGID sounds reasonable. Why two messages with
> > two stats? all you will need to do is get rid of the prepare_reply()
> > above and NLA_PUT_U32() below (just like you do in a response to a GET.
> > 
> 
> The reason for two stats is that for TGID, we return accumulated values
> (of all threads in the group) and for PID we return the value just
> for that pid. The return value is
> 

Ok, I understand the dilemma now - but still not thrilled with having
two messages.
Perhaps you could have nesting of TLVs? This is widely used in the net
code for example
i.e:

TLV = TASKSTATS_TYPE_TGID/PID
    TLV = TASKSTATS_TYPE_STATS

Look at using nla_nest_start/end/cancel

cheers,
jamal

^ permalink raw reply

* Re: [RFC][UPDATED PATCH 2.6.16] [Patch 9/9] Generic netlink interface for delay accounting
From: jamal @ 2006-03-24 14:11 UTC (permalink / raw)
  To: balbir; +Cc: Matt Helsley, Shailabh Nagar, linux-kernel, netdev
In-Reply-To: <20060324013229.GD13159@in.ibm.com>

On Fri, 2006-24-03 at 07:02 +0530, Balbir Singh wrote:
> On Thu, Mar 23, 2006 at 09:04:46AM -0500, jamal wrote:

> 3. nlmsg_new() now allocates for 2*u32 + sizeof(taskstats)

Not the right size; the u32 covers the V part of TLV. The T = 16 bits
and L = 16 bits. And if you nest TLVs, then it gets more interesting.

Look at using proper macros instead of hard coding like you did.
grep for something like RTA_SPACE and perhaps send a patch to make it
generic for netlink.h

cheers,
jamal

^ permalink raw reply

* Re: [RFC][UPDATED PATCH 2.6.16] [Patch 9/9] Generic netlink interface for delay accounting
From: jamal @ 2006-03-24 14:19 UTC (permalink / raw)
  To: balbir; +Cc: Matt Helsley, Shailabh Nagar, linux-kernel, netdev
In-Reply-To: <1143209518.5076.21.camel@jzny2>

On Fri, 2006-24-03 at 09:11 -0500, jamal wrote:

> Look at using proper macros instead of hard coding like you did.
> grep for something like RTA_SPACE and perhaps send a patch to make it
> generic for netlink.h
> 

actually Thomas already has this in netlink.h
Look at using things like:
nla_attr_size()

make sure padding is taken care of etc (read: use the right macros).

cheers,
jamal

^ permalink raw reply

* Re: [RFC][UPDATED PATCH 2.6.16] [Patch 9/9] Generic netlink interface for delay accounting
From: Balbir Singh @ 2006-03-24 14:54 UTC (permalink / raw)
  To: jamal; +Cc: Matt Helsley, Shailabh Nagar, linux-kernel, netdev
In-Reply-To: <1143209061.5076.14.camel@jzny2>

On Fri, Mar 24, 2006 at 09:04:21AM -0500, jamal wrote:
> On Thu, 2006-23-03 at 21:11 +0530, Balbir Singh wrote:
> > On Thu, Mar 23, 2006 at 09:04:46AM -0500, jamal wrote:
> 
> > > Should there be at least either a pid or tgid? If yes, you need to
> > > validate here...
> > >
> > 
> > Yes, you are correct. One of my test cases caught it too.. But I did
> > not want to untidy the code with if-else's which will keep growing if
> > the attributes change in the future. I just followed the controller
> > example. I will change it and validate it. Currently if the attribute
> > is not valid, a stat of all zero's is returned back.
> >  
> 
> There are many ways to skin this cat.
> As an example: you could make pid and tgid global to the function and
> set them to 0. At the end of the if statements, you could check if at
> least one of them is set - if not you know none was passed and bail out.

The latest patch does fix it this issue. In the Changelog
6. taskstats_send_stats() now validates the command attributes and ensures
  that it either gets a PID or a TGID. If it gets both simultaneously
  the PID stats are sent.

Is this change ok with you?

> 
> > > As a general comment double check your logic for errors; if you already
> > > have stashed something in the skb, you need to remove it etc.
> > > 
> > 
> > Wouldn't genlmsg_cancel() take care of cleaning all attributes?
> > 
> 
> it would for attribute setting - but not for others. As a general
> comment this is one of those areas where cutnpasting aka TheLinuxWay(tm)
> could result in errors.

:-) I understand.
What I have done is moved all the NLA_PUT_U32 to after verifying the
return values of functions fill_*(). That way we do not stash anything into the
skb if there are pending errors.

> 
> 
> > > A single message with PID+TGID sounds reasonable. Why two messages with
> > > two stats? all you will need to do is get rid of the prepare_reply()
> > > above and NLA_PUT_U32() below (just like you do in a response to a GET.
> > > 
> > 
> > The reason for two stats is that for TGID, we return accumulated values
> > (of all threads in the group) and for PID we return the value just
> > for that pid. The return value is
> > 
> 
> Ok, I understand the dilemma now - but still not thrilled with having
> two messages.
> Perhaps you could have nesting of TLVs? This is widely used in the net
> code for example
> i.e:
> 
> TLV = TASKSTATS_TYPE_TGID/PID
>     TLV = TASKSTATS_TYPE_STATS
> 
> Look at using nla_nest_start/end/cancel

Hmm... Would it be ok to send one message with the following format

1. TLV=TASKSTATS_TYPE_PID
2. TLV=TASKSTATS_TYPE_STATS
3. TLV=TASKSTATS_TYPE_TGID
4. TLV=TASKSTATS_TYPE_STATS

It would still be one message, except that 3 and 4 would be optional.
What do you think?

> 
> cheers,
> jamal

Thanks for your comments,
Balbir

^ permalink raw reply

* Re: [RFC][UPDATED PATCH 2.6.16] [Patch 9/9] Generic netlink interface for delay accounting
From: Balbir Singh @ 2006-03-24 14:59 UTC (permalink / raw)
  To: jamal; +Cc: Matt Helsley, Shailabh Nagar, linux-kernel, netdev
In-Reply-To: <1143209518.5076.21.camel@jzny2>

On Fri, Mar 24, 2006 at 09:11:58AM -0500, jamal wrote:
> On Fri, 2006-24-03 at 07:02 +0530, Balbir Singh wrote:
> > On Thu, Mar 23, 2006 at 09:04:46AM -0500, jamal wrote:
> 
> > 3. nlmsg_new() now allocates for 2*u32 + sizeof(taskstats)
> 
> Not the right size; the u32 covers the V part of TLV. The T = 16 bits
> and L = 16 bits. And if you nest TLVs, then it gets more interesting.
> 
> Look at using proper macros instead of hard coding like you did.
> grep for something like RTA_SPACE and perhaps send a patch to make it
> generic for netlink.h
> 
> cheers,
> jamal
>

My bad,  but I was wondering why my test case did not segfault until
I saw the implementation of nlmsg_new :-)

I will fix this and use nla_total_size() to calculate the correct sizes
including padding and TLV.

Thanks again,
Balbir

 

^ permalink raw reply

* [2.6 patch] PCMCIA_SPECTRUM must select FW_LOADER
From: Adrian Bunk @ 2006-03-24 16:56 UTC (permalink / raw)
  To: Alexander E. Patrakov, linville; +Cc: LKML, netdev
In-Reply-To: <44241FF9.9070904@ums.usu.ru>

On Fri, Mar 24, 2006 at 09:36:09PM +0500, Alexander E. Patrakov wrote:
> In linux-2.6.16, it is possible to compile spectrum_cs.ko without enabling 
> firmware loader. Result:
> 
> WARNING: /lib/modules/2.6.16/kernel/drivers/net/wireless/spectrum_cs.ko 
> needs unknown symbol request_firmware

Thanks for your report, a fix is below.

> Alexander E. Patrakov

cu
Adrian


<--  snip  -->


PCMCIA_SPECTRUM must select FW_LOADER.

Reported by "Alexander E. Patrakov" <patrakov@ums.usu.ru>.

Signed-off-by: Adrian Bunk <bunk@stusta.de>

--- linux-2.6.16-mm1-full/drivers/net/wireless/Kconfig.old	2006-03-24 17:45:05.000000000 +0100
+++ linux-2.6.16-mm1-full/drivers/net/wireless/Kconfig	2006-03-24 17:45:38.000000000 +0100
@@ -397,6 +397,7 @@
 config PCMCIA_SPECTRUM
 	tristate "Symbol Spectrum24 Trilogy PCMCIA card support"
 	depends on NET_RADIO && PCMCIA && HERMES
+	select FW_LOADER
 	---help---
 
 	  This is a driver for 802.11b cards using RAM-loadable Symbol

^ permalink raw reply

* [git patches] net driver updates
From: Jeff Garzik @ 2006-03-24 17:19 UTC (permalink / raw)
  To: Andrew Morton, Linus Torvalds; +Cc: netdev, linux-kernel


Main thing is the ne2k-pci build fix.



Please pull from 'upstream-linus' branch of
master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6.git

to receive the following updates:

 drivers/net/arm/Kconfig                           |    8 
 drivers/net/arm/Makefile                          |    1 
 drivers/net/arm/at91_ether.c                      | 1110 ++++++++++++++++++++++
 drivers/net/arm/at91_ether.h                      |  101 ++
 drivers/net/ne2k-pci.c                            |    2 
 include/asm-arm/arch-at91rm9200/at91rm9200_emac.h |  138 ++
 6 files changed, 1359 insertions(+), 1 deletion(-)

Andrew Victor:
      AT91RM9200 Ethernet driver

Horms:
      net: ne2k.c won't compile if pci_clone_list is const

diff --git a/drivers/net/arm/Kconfig b/drivers/net/arm/Kconfig
index 625184b..77fe20d 100644
--- a/drivers/net/arm/Kconfig
+++ b/drivers/net/arm/Kconfig
@@ -31,3 +31,11 @@ config ARM_ETHERH
 	help
 	  If you have an Acorn system with one of these network cards, you
 	  should say Y to this option if you wish to use it with Linux.
+
+config ARM_AT91_ETHER
+	tristate "AT91RM9200 Ethernet support"
+	depends on NET_ETHERNET && ARM && ARCH_AT91RM9200
+	select MII
+	help
+	  If you wish to compile a kernel for the AT91RM9200 and enable
+	  ethernet support, then you should always answer Y to this.
diff --git a/drivers/net/arm/Makefile b/drivers/net/arm/Makefile
index bc263ed..42c95b7 100644
--- a/drivers/net/arm/Makefile
+++ b/drivers/net/arm/Makefile
@@ -7,3 +7,4 @@ obj-$(CONFIG_ARM_AM79C961A)	+= am79c961a
 obj-$(CONFIG_ARM_ETHERH)	+= etherh.o
 obj-$(CONFIG_ARM_ETHER3)	+= ether3.o
 obj-$(CONFIG_ARM_ETHER1)	+= ether1.o
+obj-$(CONFIG_ARM_AT91_ETHER)	+= at91_ether.o
diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c
new file mode 100644
index 0000000..5503dc8
--- /dev/null
+++ b/drivers/net/arm/at91_ether.c
@@ -0,0 +1,1110 @@
+/*
+ * Ethernet driver for the Atmel AT91RM9200 (Thunder)
+ *
+ *  Copyright (C) 2003 SAN People (Pty) Ltd
+ *
+ * Based on an earlier Atmel EMAC macrocell driver by Atmel and Lineo Inc.
+ * Initial version by Rick Bronson 01/11/2003
+ *
+ * Intel LXT971A PHY support by Christopher Bahns & David Knickerbocker
+ *   (Polaroid Corporation)
+ *
+ * Realtek RTL8201(B)L PHY support by Roman Avramenko <roman@imsystems.ru>
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/config.h>
+#include <linux/mii.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/dma-mapping.h>
+#include <linux/ethtool.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/at91rm9200_emac.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/board.h>
+
+#include "at91_ether.h"
+
+#define DRV_NAME	"at91_ether"
+#define DRV_VERSION	"1.0"
+
+static struct net_device *at91_dev;
+static struct clk *ether_clk;
+
+/* ..................................................................... */
+
+/*
+ * Read from a EMAC register.
+ */
+static inline unsigned long at91_emac_read(unsigned int reg)
+{
+	void __iomem *emac_base = (void __iomem *)AT91_VA_BASE_EMAC;
+
+	return __raw_readl(emac_base + reg);
+}
+
+/*
+ * Write to a EMAC register.
+ */
+static inline void at91_emac_write(unsigned int reg, unsigned long value)
+{
+	void __iomem *emac_base = (void __iomem *)AT91_VA_BASE_EMAC;
+
+	__raw_writel(value, emac_base + reg);
+}
+
+/* ........................... PHY INTERFACE ........................... */
+
+/*
+ * Enable the MDIO bit in MAC control register
+ * When not called from an interrupt-handler, access to the PHY must be
+ *  protected by a spinlock.
+ */
+static void enable_mdi(void)
+{
+	unsigned long ctl;
+
+	ctl = at91_emac_read(AT91_EMAC_CTL);
+	at91_emac_write(AT91_EMAC_CTL, ctl | AT91_EMAC_MPE);	/* enable management port */
+}
+
+/*
+ * Disable the MDIO bit in the MAC control register
+ */
+static void disable_mdi(void)
+{
+	unsigned long ctl;
+
+	ctl = at91_emac_read(AT91_EMAC_CTL);
+	at91_emac_write(AT91_EMAC_CTL, ctl & ~AT91_EMAC_MPE);	/* disable management port */
+}
+
+/*
+ * Wait until the PHY operation is complete.
+ */
+static inline void at91_phy_wait(void) {
+	unsigned long timeout = jiffies + 2;
+
+	while (!(at91_emac_read(AT91_EMAC_SR) & AT91_EMAC_SR_IDLE)) {
+		if (time_after(jiffies, timeout)) {
+			printk("at91_ether: MIO timeout\n");
+			break;
+		}
+		cpu_relax();
+	}
+}
+
+/*
+ * Write value to the a PHY register
+ * Note: MDI interface is assumed to already have been enabled.
+ */
+static void write_phy(unsigned char phy_addr, unsigned char address, unsigned int value)
+{
+	at91_emac_write(AT91_EMAC_MAN, AT91_EMAC_MAN_802_3 | AT91_EMAC_RW_W
+		| ((phy_addr & 0x1f) << 23) | (address << 18) | (value & AT91_EMAC_DATA));
+
+	/* Wait until IDLE bit in Network Status register is cleared */
+	at91_phy_wait();
+}
+
+/*
+ * Read value stored in a PHY register.
+ * Note: MDI interface is assumed to already have been enabled.
+ */
+static void read_phy(unsigned char phy_addr, unsigned char address, unsigned int *value)
+{
+	at91_emac_write(AT91_EMAC_MAN, AT91_EMAC_MAN_802_3 | AT91_EMAC_RW_R
+		| ((phy_addr & 0x1f) << 23) | (address << 18));
+
+	/* Wait until IDLE bit in Network Status register is cleared */
+	at91_phy_wait();
+
+	*value = at91_emac_read(AT91_EMAC_MAN) & AT91_EMAC_DATA;
+}
+
+/* ........................... PHY MANAGEMENT .......................... */
+
+/*
+ * Access the PHY to determine the current link speed and mode, and update the
+ * MAC accordingly.
+ * If no link or auto-negotiation is busy, then no changes are made.
+ */
+static void update_linkspeed(struct net_device *dev)
+{
+	struct at91_private *lp = (struct at91_private *) dev->priv;
+	unsigned int bmsr, bmcr, lpa, mac_cfg;
+	unsigned int speed, duplex;
+
+	if (!mii_link_ok(&lp->mii)) {		/* no link */
+		netif_carrier_off(dev);
+		printk(KERN_INFO "%s: Link down.\n", dev->name);
+		return;
+	}
+
+	/* Link up, or auto-negotiation still in progress */
+	read_phy(lp->phy_address, MII_BMSR, &bmsr);
+	read_phy(lp->phy_address, MII_BMCR, &bmcr);
+	if (bmcr & BMCR_ANENABLE) {				/* AutoNegotiation is enabled */
+		if (!(bmsr & BMSR_ANEGCOMPLETE))
+			return;			/* Do nothing - another interrupt generated when negotiation complete */
+
+		read_phy(lp->phy_address, MII_LPA, &lpa);
+		if ((lpa & LPA_100FULL) || (lpa & LPA_100HALF)) speed = SPEED_100;
+		else speed = SPEED_10;
+		if ((lpa & LPA_100FULL) || (lpa & LPA_10FULL)) duplex = DUPLEX_FULL;
+		else duplex = DUPLEX_HALF;
+	} else {
+		speed = (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10;
+		duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
+	}
+
+	/* Update the MAC */
+	mac_cfg = at91_emac_read(AT91_EMAC_CFG) & ~(AT91_EMAC_SPD | AT91_EMAC_FD);
+	if (speed == SPEED_100) {
+		if (duplex == DUPLEX_FULL)		/* 100 Full Duplex */
+			mac_cfg |= AT91_EMAC_SPD | AT91_EMAC_FD;
+		else					/* 100 Half Duplex */
+			mac_cfg |= AT91_EMAC_SPD;
+	} else {
+		if (duplex == DUPLEX_FULL)		/* 10 Full Duplex */
+			mac_cfg |= AT91_EMAC_FD;
+		else {}					/* 10 Half Duplex */
+	}
+	at91_emac_write(AT91_EMAC_CFG, mac_cfg);
+
+	printk(KERN_INFO "%s: Link now %i-%s\n", dev->name, speed, (duplex == DUPLEX_FULL) ? "FullDuplex" : "HalfDuplex");
+	netif_carrier_on(dev);
+}
+
+/*
+ * Handle interrupts from the PHY
+ */
+static irqreturn_t at91ether_phy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = (struct net_device *) dev_id;
+	struct at91_private *lp = (struct at91_private *) dev->priv;
+	unsigned int phy;
+
+	/*
+	 * This hander is triggered on both edges, but the PHY chips expect
+	 * level-triggering.  We therefore have to check if the PHY actually has
+	 * an IRQ pending.
+	 */
+	enable_mdi();
+	if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) {
+		read_phy(lp->phy_address, MII_DSINTR_REG, &phy);	/* ack interrupt in Davicom PHY */
+		if (!(phy & (1 << 0)))
+			goto done;
+	}
+	else if (lp->phy_type == MII_LXT971A_ID) {
+		read_phy(lp->phy_address, MII_ISINTS_REG, &phy);	/* ack interrupt in Intel PHY */
+		if (!(phy & (1 << 2)))
+			goto done;
+	}
+	else if (lp->phy_type == MII_BCM5221_ID) {
+		read_phy(lp->phy_address, MII_BCMINTR_REG, &phy);	/* ack interrupt in Broadcom PHY */
+		if (!(phy & (1 << 0)))
+			goto done;
+	}
+	else if (lp->phy_type == MII_KS8721_ID) {
+		read_phy(lp->phy_address, MII_TPISTATUS, &phy);		/* ack interrupt in Micrel PHY */
+		if (!(phy & ((1 << 2) | 1)))
+			goto done;
+	}
+
+	update_linkspeed(dev);
+
+done:
+	disable_mdi();
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * Initialize and enable the PHY interrupt for link-state changes
+ */
+static void enable_phyirq(struct net_device *dev)
+{
+	struct at91_private *lp = (struct at91_private *) dev->priv;
+	unsigned int dsintr, irq_number;
+	int status;
+
+	if (lp->phy_type == MII_RTL8201_ID)	/* RTL8201 does not have an interrupt */
+		return;
+	if (lp->phy_type == MII_DP83847_ID)	/* DP83847 does not have an interrupt */
+		return;
+	if (lp->phy_type == MII_AC101L_ID)	/* AC101L interrupt not supported yet */
+		return;
+
+	irq_number = lp->board_data.phy_irq_pin;
+	status = request_irq(irq_number, at91ether_phy_interrupt, 0, dev->name, dev);
+	if (status) {
+		printk(KERN_ERR "at91_ether: PHY IRQ %d request failed - status %d!\n", irq_number, status);
+		return;
+	}
+
+	spin_lock_irq(&lp->lock);
+	enable_mdi();
+
+	if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) {	/* for Davicom PHY */
+		read_phy(lp->phy_address, MII_DSINTR_REG, &dsintr);
+		dsintr = dsintr & ~0xf00;		/* clear bits 8..11 */
+		write_phy(lp->phy_address, MII_DSINTR_REG, dsintr);
+	}
+	else if (lp->phy_type == MII_LXT971A_ID) {	/* for Intel PHY */
+		read_phy(lp->phy_address, MII_ISINTE_REG, &dsintr);
+		dsintr = dsintr | 0xf2;			/* set bits 1, 4..7 */
+		write_phy(lp->phy_address, MII_ISINTE_REG, dsintr);
+	}
+	else if (lp->phy_type == MII_BCM5221_ID) {	/* for Broadcom PHY */
+		dsintr = (1 << 15) | ( 1 << 14);
+		write_phy(lp->phy_address, MII_BCMINTR_REG, dsintr);
+	}
+	else if (lp->phy_type == MII_KS8721_ID) {	/* for Micrel PHY */
+		dsintr = (1 << 10) | ( 1 << 8);
+		write_phy(lp->phy_address, MII_TPISTATUS, dsintr);
+	}
+
+	disable_mdi();
+	spin_unlock_irq(&lp->lock);
+}
+
+/*
+ * Disable the PHY interrupt
+ */
+static void disable_phyirq(struct net_device *dev)
+{
+	struct at91_private *lp = (struct at91_private *) dev->priv;
+	unsigned int dsintr;
+	unsigned int irq_number;
+
+	if (lp->phy_type == MII_RTL8201_ID) 	/* RTL8201 does not have an interrupt */
+		return;
+	if (lp->phy_type == MII_DP83847_ID)	/* DP83847 does not have an interrupt */
+		return;
+	if (lp->phy_type == MII_AC101L_ID)	/* AC101L interrupt not supported yet */
+		return;
+
+	spin_lock_irq(&lp->lock);
+	enable_mdi();
+
+	if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) {	/* for Davicom PHY */
+		read_phy(lp->phy_address, MII_DSINTR_REG, &dsintr);
+		dsintr = dsintr | 0xf00;			/* set bits 8..11 */
+		write_phy(lp->phy_address, MII_DSINTR_REG, dsintr);
+	}
+	else if (lp->phy_type == MII_LXT971A_ID) {	/* for Intel PHY */
+		read_phy(lp->phy_address, MII_ISINTE_REG, &dsintr);
+		dsintr = dsintr & ~0xf2;			/* clear bits 1, 4..7 */
+		write_phy(lp->phy_address, MII_ISINTE_REG, dsintr);
+	}
+	else if (lp->phy_type == MII_BCM5221_ID) {	/* for Broadcom PHY */
+		read_phy(lp->phy_address, MII_BCMINTR_REG, &dsintr);
+		dsintr = ~(1 << 14);
+		write_phy(lp->phy_address, MII_BCMINTR_REG, dsintr);
+	}
+	else if (lp->phy_type == MII_KS8721_ID) {	/* for Micrel PHY */
+		read_phy(lp->phy_address, MII_TPISTATUS, &dsintr);
+		dsintr = ~((1 << 10) | (1 << 8));
+		write_phy(lp->phy_address, MII_TPISTATUS, dsintr);
+	}
+
+	disable_mdi();
+	spin_unlock_irq(&lp->lock);
+
+	irq_number = lp->board_data.phy_irq_pin;
+	free_irq(irq_number, dev);			/* Free interrupt handler */
+}
+
+/*
+ * Perform a software reset of the PHY.
+ */
+#if 0
+static void reset_phy(struct net_device *dev)
+{
+	struct at91_private *lp = (struct at91_private *) dev->priv;
+	unsigned int bmcr;
+
+	spin_lock_irq(&lp->lock);
+	enable_mdi();
+
+	/* Perform PHY reset */
+	write_phy(lp->phy_address, MII_BMCR, BMCR_RESET);
+
+	/* Wait until PHY reset is complete */
+	do {
+		read_phy(lp->phy_address, MII_BMCR, &bmcr);
+	} while (!(bmcr && BMCR_RESET));
+
+	disable_mdi();
+	spin_unlock_irq(&lp->lock);
+}
+#endif
+
+/* ......................... ADDRESS MANAGEMENT ........................ */
+
+/*
+ * NOTE: Your bootloader must always set the MAC address correctly before
+ * booting into Linux.
+ *
+ * - It must always set the MAC address after reset, even if it doesn't
+ *   happen to access the Ethernet while it's booting.  Some versions of
+ *   U-Boot on the AT91RM9200-DK do not do this.
+ *
+ * - Likewise it must store the addresses in the correct byte order.
+ *   MicroMonitor (uMon) on the CSB337 does this incorrectly (and
+ *   continues to do so, for bug-compatibility).
+ */
+
+static short __init unpack_mac_address(struct net_device *dev, unsigned int hi, unsigned int lo)
+{
+	char addr[6];
+
+	if (machine_is_csb337()) {
+		addr[5] = (lo & 0xff);			/* The CSB337 bootloader stores the MAC the wrong-way around */
+		addr[4] = (lo & 0xff00) >> 8;
+		addr[3] = (lo & 0xff0000) >> 16;
+		addr[2] = (lo & 0xff000000) >> 24;
+		addr[1] = (hi & 0xff);
+		addr[0] = (hi & 0xff00) >> 8;
+	}
+	else {
+		addr[0] = (lo & 0xff);
+		addr[1] = (lo & 0xff00) >> 8;
+		addr[2] = (lo & 0xff0000) >> 16;
+		addr[3] = (lo & 0xff000000) >> 24;
+		addr[4] = (hi & 0xff);
+		addr[5] = (hi & 0xff00) >> 8;
+	}
+
+	if (is_valid_ether_addr(addr)) {
+		memcpy(dev->dev_addr, &addr, 6);
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * Set the ethernet MAC address in dev->dev_addr
+ */
+static void __init get_mac_address(struct net_device *dev)
+{
+	/* Check Specific-Address 1 */
+	if (unpack_mac_address(dev, at91_emac_read(AT91_EMAC_SA1H), at91_emac_read(AT91_EMAC_SA1L)))
+		return;
+	/* Check Specific-Address 2 */
+	if (unpack_mac_address(dev, at91_emac_read(AT91_EMAC_SA2H), at91_emac_read(AT91_EMAC_SA2L)))
+		return;
+	/* Check Specific-Address 3 */
+	if (unpack_mac_address(dev, at91_emac_read(AT91_EMAC_SA3H), at91_emac_read(AT91_EMAC_SA3L)))
+		return;
+	/* Check Specific-Address 4 */
+	if (unpack_mac_address(dev, at91_emac_read(AT91_EMAC_SA4H), at91_emac_read(AT91_EMAC_SA4L)))
+		return;
+
+	printk(KERN_ERR "at91_ether: Your bootloader did not configure a MAC address.\n");
+}
+
+/*
+ * Program the hardware MAC address from dev->dev_addr.
+ */
+static void update_mac_address(struct net_device *dev)
+{
+	at91_emac_write(AT91_EMAC_SA1L, (dev->dev_addr[3] << 24) | (dev->dev_addr[2] << 16) | (dev->dev_addr[1] << 8) | (dev->dev_addr[0]));
+	at91_emac_write(AT91_EMAC_SA1H, (dev->dev_addr[5] << 8) | (dev->dev_addr[4]));
+
+	at91_emac_write(AT91_EMAC_SA2L, 0);
+	at91_emac_write(AT91_EMAC_SA2H, 0);
+}
+
+/*
+ * Store the new hardware address in dev->dev_addr, and update the MAC.
+ */
+static int set_mac_address(struct net_device *dev, void* addr)
+{
+	struct sockaddr *address = addr;
+
+	if (!is_valid_ether_addr(address->sa_data))
+		return -EADDRNOTAVAIL;
+
+	memcpy(dev->dev_addr, address->sa_data, dev->addr_len);
+	update_mac_address(dev);
+
+	printk("%s: Setting MAC address to %02x:%02x:%02x:%02x:%02x:%02x\n", dev->name,
+		dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+		dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+
+	return 0;
+}
+
+static int inline hash_bit_value(int bitnr, __u8 *addr)
+{
+	if (addr[bitnr / 8] & (1 << (bitnr % 8)))
+		return 1;
+	return 0;
+}
+
+/*
+ * The hash address register is 64 bits long and takes up two locations in the memory map.
+ * The least significant bits are stored in EMAC_HSL and the most significant
+ * bits in EMAC_HSH.
+ *
+ * The unicast hash enable and the multicast hash enable bits in the network configuration
+ *  register enable the reception of hash matched frames. The destination address is
+ *  reduced to a 6 bit index into the 64 bit hash register using the following hash function.
+ * The hash function is an exclusive or of every sixth bit of the destination address.
+ *   hash_index[5] = da[5] ^ da[11] ^ da[17] ^ da[23] ^ da[29] ^ da[35] ^ da[41] ^ da[47]
+ *   hash_index[4] = da[4] ^ da[10] ^ da[16] ^ da[22] ^ da[28] ^ da[34] ^ da[40] ^ da[46]
+ *   hash_index[3] = da[3] ^ da[09] ^ da[15] ^ da[21] ^ da[27] ^ da[33] ^ da[39] ^ da[45]
+ *   hash_index[2] = da[2] ^ da[08] ^ da[14] ^ da[20] ^ da[26] ^ da[32] ^ da[38] ^ da[44]
+ *   hash_index[1] = da[1] ^ da[07] ^ da[13] ^ da[19] ^ da[25] ^ da[31] ^ da[37] ^ da[43]
+ *   hash_index[0] = da[0] ^ da[06] ^ da[12] ^ da[18] ^ da[24] ^ da[30] ^ da[36] ^ da[42]
+ * da[0] represents the least significant bit of the first byte received, that is, the multicast/
+ *  unicast indicator, and da[47] represents the most significant bit of the last byte
+ *  received.
+ * If the hash index points to a bit that is set in the hash register then the frame will be
+ *  matched according to whether the frame is multicast or unicast.
+ * A multicast match will be signalled if the multicast hash enable bit is set, da[0] is 1 and
+ *  the hash index points to a bit set in the hash register.
+ * A unicast match will be signalled if the unicast hash enable bit is set, da[0] is 0 and the
+ *  hash index points to a bit set in the hash register.
+ * To receive all multicast frames, the hash register should be set with all ones and the
+ *  multicast hash enable bit should be set in the network configuration register.
+ */
+
+/*
+ * Return the hash index value for the specified address.
+ */
+static int hash_get_index(__u8 *addr)
+{
+	int i, j, bitval;
+	int hash_index = 0;
+
+	for (j = 0; j < 6; j++) {
+		for (i = 0, bitval = 0; i < 8; i++)
+			bitval ^= hash_bit_value(i*6 + j, addr);
+
+		hash_index |= (bitval << j);
+	}
+
+        return hash_index;
+}
+
+/*
+ * Add multicast addresses to the internal multicast-hash table.
+ */
+static void at91ether_sethashtable(struct net_device *dev)
+{
+	struct dev_mc_list *curr;
+	unsigned long mc_filter[2];
+	unsigned int i, bitnr;
+
+	mc_filter[0] = mc_filter[1] = 0;
+
+	curr = dev->mc_list;
+	for (i = 0; i < dev->mc_count; i++, curr = curr->next) {
+		if (!curr) break;	/* unexpected end of list */
+
+		bitnr = hash_get_index(curr->dmi_addr);
+		mc_filter[bitnr >> 5] |= 1 << (bitnr & 31);
+	}
+
+	at91_emac_write(AT91_EMAC_HSH, mc_filter[0]);
+	at91_emac_write(AT91_EMAC_HSL, mc_filter[1]);
+}
+
+/*
+ * Enable/Disable promiscuous and multicast modes.
+ */
+static void at91ether_set_rx_mode(struct net_device *dev)
+{
+	unsigned long cfg;
+
+	cfg = at91_emac_read(AT91_EMAC_CFG);
+
+	if (dev->flags & IFF_PROMISC)			/* Enable promiscuous mode */
+		cfg |= AT91_EMAC_CAF;
+	else if (dev->flags & (~IFF_PROMISC))		/* Disable promiscuous mode */
+		cfg &= ~AT91_EMAC_CAF;
+
+	if (dev->flags & IFF_ALLMULTI) {		/* Enable all multicast mode */
+		at91_emac_write(AT91_EMAC_HSH, -1);
+		at91_emac_write(AT91_EMAC_HSL, -1);
+		cfg |= AT91_EMAC_MTI;
+	} else if (dev->mc_count > 0) {			/* Enable specific multicasts */
+		at91ether_sethashtable(dev);
+		cfg |= AT91_EMAC_MTI;
+	} else if (dev->flags & (~IFF_ALLMULTI)) {	/* Disable all multicast mode */
+		at91_emac_write(AT91_EMAC_HSH, 0);
+		at91_emac_write(AT91_EMAC_HSL, 0);
+		cfg &= ~AT91_EMAC_MTI;
+	}
+
+	at91_emac_write(AT91_EMAC_CFG, cfg);
+}
+
+
+/* ......................... ETHTOOL SUPPORT ........................... */
+
+
+static int mdio_read(struct net_device *dev, int phy_id, int location)
+{
+	unsigned int value;
+
+	read_phy(phy_id, location, &value);
+	return value;
+}
+
+static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
+{
+	write_phy(phy_id, location, value);
+}
+
+static int at91ether_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct at91_private *lp = (struct at91_private *) dev->priv;
+	int ret;
+
+	spin_lock_irq(&lp->lock);
+	enable_mdi();
+
+	ret = mii_ethtool_gset(&lp->mii, cmd);
+
+	disable_mdi();
+	spin_unlock_irq(&lp->lock);
+
+	if (lp->phy_media == PORT_FIBRE) {		/* override media type since mii.c doesn't know */
+		cmd->supported = SUPPORTED_FIBRE;
+		cmd->port = PORT_FIBRE;
+	}
+
+	return ret;
+}
+
+static int at91ether_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct at91_private *lp = (struct at91_private *) dev->priv;
+	int ret;
+
+	spin_lock_irq(&lp->lock);
+	enable_mdi();
+
+	ret = mii_ethtool_sset(&lp->mii, cmd);
+
+	disable_mdi();
+	spin_unlock_irq(&lp->lock);
+
+	return ret;
+}
+
+static int at91ether_nwayreset(struct net_device *dev)
+{
+	struct at91_private *lp = (struct at91_private *) dev->priv;
+	int ret;
+
+	spin_lock_irq(&lp->lock);
+	enable_mdi();
+
+	ret = mii_nway_restart(&lp->mii);
+
+	disable_mdi();
+	spin_unlock_irq(&lp->lock);
+
+	return ret;
+}
+
+static void at91ether_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+	strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+	strlcpy(info->bus_info, dev->class_dev.dev->bus_id, sizeof(info->bus_info));
+}
+
+static struct ethtool_ops at91ether_ethtool_ops = {
+	.get_settings	= at91ether_get_settings,
+	.set_settings	= at91ether_set_settings,
+	.get_drvinfo	= at91ether_get_drvinfo,
+	.nway_reset	= at91ether_nwayreset,
+	.get_link	= ethtool_op_get_link,
+};
+
+
+/* ................................ MAC ................................ */
+
+/*
+ * Initialize and start the Receiver and Transmit subsystems
+ */
+static void at91ether_start(struct net_device *dev)
+{
+	struct at91_private *lp = (struct at91_private *) dev->priv;
+	struct recv_desc_bufs *dlist, *dlist_phys;
+	int i;
+	unsigned long ctl;
+
+	dlist = lp->dlist;
+	dlist_phys = lp->dlist_phys;
+
+	for (i = 0; i < MAX_RX_DESCR; i++) {
+		dlist->descriptors[i].addr = (unsigned int) &dlist_phys->recv_buf[i][0];
+		dlist->descriptors[i].size = 0;
+	}
+
+	/* Set the Wrap bit on the last descriptor */
+	dlist->descriptors[i-1].addr |= EMAC_DESC_WRAP;
+
+	/* Reset buffer index */
+	lp->rxBuffIndex = 0;
+
+	/* Program address of descriptor list in Rx Buffer Queue register */
+	at91_emac_write(AT91_EMAC_RBQP, (unsigned long) dlist_phys);
+
+	/* Enable Receive and Transmit */
+	ctl = at91_emac_read(AT91_EMAC_CTL);
+	at91_emac_write(AT91_EMAC_CTL, ctl | AT91_EMAC_RE | AT91_EMAC_TE);
+}
+
+/*
+ * Open the ethernet interface
+ */
+static int at91ether_open(struct net_device *dev)
+{
+	struct at91_private *lp = (struct at91_private *) dev->priv;
+	unsigned long ctl;
+
+        if (!is_valid_ether_addr(dev->dev_addr))
+        	return -EADDRNOTAVAIL;
+
+	clk_enable(ether_clk);			/* Re-enable Peripheral clock */
+
+	/* Clear internal statistics */
+	ctl = at91_emac_read(AT91_EMAC_CTL);
+	at91_emac_write(AT91_EMAC_CTL, ctl | AT91_EMAC_CSR);
+
+	/* Update the MAC address (incase user has changed it) */
+	update_mac_address(dev);
+
+	/* Enable PHY interrupt */
+	enable_phyirq(dev);
+
+	/* Enable MAC interrupts */
+	at91_emac_write(AT91_EMAC_IER, AT91_EMAC_RCOM | AT91_EMAC_RBNA
+				| AT91_EMAC_TUND | AT91_EMAC_RTRY | AT91_EMAC_TCOM
+				| AT91_EMAC_ROVR | AT91_EMAC_ABT);
+
+	/* Determine current link speed */
+	spin_lock_irq(&lp->lock);
+	enable_mdi();
+	update_linkspeed(dev);
+	disable_mdi();
+	spin_unlock_irq(&lp->lock);
+
+	at91ether_start(dev);
+	netif_start_queue(dev);
+	return 0;
+}
+
+/*
+ * Close the interface
+ */
+static int at91ether_close(struct net_device *dev)
+{
+	unsigned long ctl;
+
+	/* Disable Receiver and Transmitter */
+	ctl = at91_emac_read(AT91_EMAC_CTL);
+	at91_emac_write(AT91_EMAC_CTL, ctl & ~(AT91_EMAC_TE | AT91_EMAC_RE));
+
+	/* Disable PHY interrupt */
+	disable_phyirq(dev);
+
+	/* Disable MAC interrupts */
+	at91_emac_write(AT91_EMAC_IDR, AT91_EMAC_RCOM | AT91_EMAC_RBNA
+				| AT91_EMAC_TUND | AT91_EMAC_RTRY | AT91_EMAC_TCOM
+				| AT91_EMAC_ROVR | AT91_EMAC_ABT);
+
+	netif_stop_queue(dev);
+
+	clk_disable(ether_clk);			/* Disable Peripheral clock */
+
+	return 0;
+}
+
+/*
+ * Transmit packet.
+ */
+static int at91ether_tx(struct sk_buff *skb, struct net_device *dev)
+{
+	struct at91_private *lp = (struct at91_private *) dev->priv;
+
+	if (at91_emac_read(AT91_EMAC_TSR) & AT91_EMAC_TSR_BNQ) {
+		netif_stop_queue(dev);
+
+		/* Store packet information (to free when Tx completed) */
+		lp->skb = skb;
+		lp->skb_length = skb->len;
+		lp->skb_physaddr = dma_map_single(NULL, skb->data, skb->len, DMA_TO_DEVICE);
+		lp->stats.tx_bytes += skb->len;
+
+		/* Set address of the data in the Transmit Address register */
+		at91_emac_write(AT91_EMAC_TAR, lp->skb_physaddr);
+		/* Set length of the packet in the Transmit Control register */
+		at91_emac_write(AT91_EMAC_TCR, skb->len);
+
+		dev->trans_start = jiffies;
+	} else {
+		printk(KERN_ERR "at91_ether.c: at91ether_tx() called, but device is busy!\n");
+		return 1;	/* if we return anything but zero, dev.c:1055 calls kfree_skb(skb)
+				on this skb, he also reports -ENETDOWN and printk's, so either
+				we free and return(0) or don't free and return 1 */
+	}
+
+	return 0;
+}
+
+/*
+ * Update the current statistics from the internal statistics registers.
+ */
+static struct net_device_stats *at91ether_stats(struct net_device *dev)
+{
+	struct at91_private *lp = (struct at91_private *) dev->priv;
+	int ale, lenerr, seqe, lcol, ecol;
+
+	if (netif_running(dev)) {
+		lp->stats.rx_packets += at91_emac_read(AT91_EMAC_OK);		/* Good frames received */
+		ale = at91_emac_read(AT91_EMAC_ALE);
+		lp->stats.rx_frame_errors += ale;				/* Alignment errors */
+		lenerr = at91_emac_read(AT91_EMAC_ELR) + at91_emac_read(AT91_EMAC_USF);
+		lp->stats.rx_length_errors += lenerr;				/* Excessive Length or Undersize Frame error */
+		seqe = at91_emac_read(AT91_EMAC_SEQE);
+		lp->stats.rx_crc_errors += seqe;				/* CRC error */
+		lp->stats.rx_fifo_errors += at91_emac_read(AT91_EMAC_DRFC);	/* Receive buffer not available */
+		lp->stats.rx_errors += (ale + lenerr + seqe
+			+ at91_emac_read(AT91_EMAC_CDE) + at91_emac_read(AT91_EMAC_RJB));
+
+		lp->stats.tx_packets += at91_emac_read(AT91_EMAC_FRA);		/* Frames successfully transmitted */
+		lp->stats.tx_fifo_errors += at91_emac_read(AT91_EMAC_TUE);	/* Transmit FIFO underruns */
+		lp->stats.tx_carrier_errors += at91_emac_read(AT91_EMAC_CSE);	/* Carrier Sense errors */
+		lp->stats.tx_heartbeat_errors += at91_emac_read(AT91_EMAC_SQEE);/* Heartbeat error */
+
+		lcol = at91_emac_read(AT91_EMAC_LCOL);
+		ecol = at91_emac_read(AT91_EMAC_ECOL);
+		lp->stats.tx_window_errors += lcol;			/* Late collisions */
+		lp->stats.tx_aborted_errors += ecol;			/* 16 collisions */
+
+		lp->stats.collisions += (at91_emac_read(AT91_EMAC_SCOL) + at91_emac_read(AT91_EMAC_MCOL) + lcol + ecol);
+	}
+	return &lp->stats;
+}
+
+/*
+ * Extract received frame from buffer descriptors and sent to upper layers.
+ * (Called from interrupt context)
+ */
+static void at91ether_rx(struct net_device *dev)
+{
+	struct at91_private *lp = (struct at91_private *) dev->priv;
+	struct recv_desc_bufs *dlist;
+	unsigned char *p_recv;
+	struct sk_buff *skb;
+	unsigned int pktlen;
+
+	dlist = lp->dlist;
+	while (dlist->descriptors[lp->rxBuffIndex].addr & EMAC_DESC_DONE) {
+		p_recv = dlist->recv_buf[lp->rxBuffIndex];
+		pktlen = dlist->descriptors[lp->rxBuffIndex].size & 0x7ff;	/* Length of frame including FCS */
+		skb = alloc_skb(pktlen + 2, GFP_ATOMIC);
+		if (skb != NULL) {
+			skb_reserve(skb, 2);
+			memcpy(skb_put(skb, pktlen), p_recv, pktlen);
+
+			skb->dev = dev;
+			skb->protocol = eth_type_trans(skb, dev);
+			skb->len = pktlen;
+			dev->last_rx = jiffies;
+			lp->stats.rx_bytes += pktlen;
+			netif_rx(skb);
+		}
+		else {
+			lp->stats.rx_dropped += 1;
+			printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
+		}
+
+		if (dlist->descriptors[lp->rxBuffIndex].size & EMAC_MULTICAST)
+			lp->stats.multicast++;
+
+		dlist->descriptors[lp->rxBuffIndex].addr &= ~EMAC_DESC_DONE;	/* reset ownership bit */
+		if (lp->rxBuffIndex == MAX_RX_DESCR-1)				/* wrap after last buffer */
+			lp->rxBuffIndex = 0;
+		else
+			lp->rxBuffIndex++;
+	}
+}
+
+/*
+ * MAC interrupt handler
+ */
+static irqreturn_t at91ether_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = (struct net_device *) dev_id;
+	struct at91_private *lp = (struct at91_private *) dev->priv;
+	unsigned long intstatus, ctl;
+
+	/* MAC Interrupt Status register indicates what interrupts are pending.
+	   It is automatically cleared once read. */
+	intstatus = at91_emac_read(AT91_EMAC_ISR);
+
+	if (intstatus & AT91_EMAC_RCOM)		/* Receive complete */
+		at91ether_rx(dev);
+
+	if (intstatus & AT91_EMAC_TCOM) {		/* Transmit complete */
+		/* The TCOM bit is set even if the transmission failed. */
+		if (intstatus & (AT91_EMAC_TUND | AT91_EMAC_RTRY))
+			lp->stats.tx_errors += 1;
+
+		if (lp->skb) {
+			dev_kfree_skb_irq(lp->skb);
+			lp->skb = NULL;
+			dma_unmap_single(NULL, lp->skb_physaddr, lp->skb_length, DMA_TO_DEVICE);
+		}
+		netif_wake_queue(dev);
+	}
+
+	/* Work-around for Errata #11 */
+	if (intstatus & AT91_EMAC_RBNA) {
+		ctl = at91_emac_read(AT91_EMAC_CTL);
+		at91_emac_write(AT91_EMAC_CTL, ctl & ~AT91_EMAC_RE);
+		at91_emac_write(AT91_EMAC_CTL, ctl | AT91_EMAC_RE);
+	}
+
+	if (intstatus & AT91_EMAC_ROVR)
+		printk("%s: ROVR error\n", dev->name);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * Initialize the ethernet interface
+ */
+static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_address, struct platform_device *pdev)
+{
+	struct at91_eth_data *board_data = pdev->dev.platform_data;
+	struct net_device *dev;
+	struct at91_private *lp;
+	unsigned int val;
+	int res;
+
+	if (at91_dev)			/* already initialized */
+		return 0;
+
+	dev = alloc_etherdev(sizeof(struct at91_private));
+	if (!dev)
+		return -ENOMEM;
+
+	dev->base_addr = AT91_VA_BASE_EMAC;
+	dev->irq = AT91_ID_EMAC;
+	SET_MODULE_OWNER(dev);
+
+	/* Install the interrupt handler */
+	if (request_irq(dev->irq, at91ether_interrupt, 0, dev->name, dev)) {
+		free_netdev(dev);
+		return -EBUSY;
+	}
+
+	/* Allocate memory for DMA Receive descriptors */
+	lp = (struct at91_private *)dev->priv;
+	lp->dlist = (struct recv_desc_bufs *) dma_alloc_coherent(NULL, sizeof(struct recv_desc_bufs), (dma_addr_t *) &lp->dlist_phys, GFP_KERNEL);
+	if (lp->dlist == NULL) {
+		free_irq(dev->irq, dev);
+		free_netdev(dev);
+		return -ENOMEM;
+	}
+	lp->board_data = *board_data;
+	platform_set_drvdata(pdev, dev);
+
+	spin_lock_init(&lp->lock);
+
+	ether_setup(dev);
+	dev->open = at91ether_open;
+	dev->stop = at91ether_close;
+	dev->hard_start_xmit = at91ether_tx;
+	dev->get_stats = at91ether_stats;
+	dev->set_multicast_list = at91ether_set_rx_mode;
+	dev->set_mac_address = set_mac_address;
+	dev->ethtool_ops = &at91ether_ethtool_ops;
+
+	SET_NETDEV_DEV(dev, &pdev->dev);
+
+	get_mac_address(dev);		/* Get ethernet address and store it in dev->dev_addr */
+	update_mac_address(dev);	/* Program ethernet address into MAC */
+
+	at91_emac_write(AT91_EMAC_CTL, 0);
+
+	if (lp->board_data.is_rmii)
+		at91_emac_write(AT91_EMAC_CFG, AT91_EMAC_CLK_DIV32 | AT91_EMAC_BIG | AT91_EMAC_RMII);
+	else
+		at91_emac_write(AT91_EMAC_CFG, AT91_EMAC_CLK_DIV32 | AT91_EMAC_BIG);
+
+	/* Perform PHY-specific initialization */
+	spin_lock_irq(&lp->lock);
+	enable_mdi();
+	if ((phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) {
+		read_phy(phy_address, MII_DSCR_REG, &val);
+		if ((val & (1 << 10)) == 0)			/* DSCR bit 10 is 0 -- fiber mode */
+			lp->phy_media = PORT_FIBRE;
+	} else if (machine_is_csb337()) {
+		/* mix link activity status into LED2 link state */
+		write_phy(phy_address, MII_LEDCTRL_REG, 0x0d22);
+	}
+	disable_mdi();
+	spin_unlock_irq(&lp->lock);
+
+	lp->mii.dev = dev;		/* Support for ethtool */
+	lp->mii.mdio_read = mdio_read;
+	lp->mii.mdio_write = mdio_write;
+
+	lp->phy_type = phy_type;	/* Type of PHY connected */
+	lp->phy_address = phy_address;	/* MDI address of PHY */
+
+	/* Register the network interface */
+	res = register_netdev(dev);
+	if (res) {
+		free_irq(dev->irq, dev);
+		free_netdev(dev);
+		dma_free_coherent(NULL, sizeof(struct recv_desc_bufs), lp->dlist, (dma_addr_t)lp->dlist_phys);
+		return res;
+	}
+	at91_dev = dev;
+
+	/* Determine current link speed */
+	spin_lock_irq(&lp->lock);
+	enable_mdi();
+	update_linkspeed(dev);
+	disable_mdi();
+	spin_unlock_irq(&lp->lock);
+	netif_carrier_off(dev);		/* will be enabled in open() */
+
+	/* Display ethernet banner */
+	printk(KERN_INFO "%s: AT91 ethernet at 0x%08x int=%d %s%s (%02x:%02x:%02x:%02x:%02x:%02x)\n",
+		dev->name, (uint) dev->base_addr, dev->irq,
+		at91_emac_read(AT91_EMAC_CFG) & AT91_EMAC_SPD ? "100-" : "10-",
+		at91_emac_read(AT91_EMAC_CFG) & AT91_EMAC_FD ? "FullDuplex" : "HalfDuplex",
+		dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+		dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+	if ((phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID))
+		printk(KERN_INFO "%s: Davicom 9196 PHY %s\n", dev->name, (lp->phy_media == PORT_FIBRE) ? "(Fiber)" : "(Copper)");
+	else if (phy_type == MII_LXT971A_ID)
+		printk(KERN_INFO "%s: Intel LXT971A PHY\n", dev->name);
+	else if (phy_type == MII_RTL8201_ID)
+		printk(KERN_INFO "%s: Realtek RTL8201(B)L PHY\n", dev->name);
+	else if (phy_type == MII_BCM5221_ID)
+		printk(KERN_INFO "%s: Broadcom BCM5221 PHY\n", dev->name);
+	else if (phy_type == MII_DP83847_ID)
+		printk(KERN_INFO "%s: National Semiconductor DP83847 PHY\n", dev->name);
+	else if (phy_type == MII_AC101L_ID)
+		printk(KERN_INFO "%s: Altima AC101L PHY\n", dev->name);
+	else if (phy_type == MII_KS8721_ID)
+		printk(KERN_INFO "%s: Micrel KS8721 PHY\n", dev->name);
+
+	return 0;
+}
+
+/*
+ * Detect MAC and PHY and perform initialization
+ */
+static int __init at91ether_probe(struct platform_device *pdev)
+{
+	unsigned int phyid1, phyid2;
+	int detected = -1;
+	unsigned long phy_id;
+	unsigned short phy_address = 0;
+
+	ether_clk = clk_get(&pdev->dev, "ether_clk");
+	if (!ether_clk) {
+		printk(KERN_ERR "at91_ether: no clock defined\n");
+		return -ENODEV;
+	}
+	clk_enable(ether_clk);					/* Enable Peripheral clock */
+
+	while ((detected != 0) && (phy_address < 32)) {
+		/* Read the PHY ID registers */
+		enable_mdi();
+		read_phy(phy_address, MII_PHYSID1, &phyid1);
+		read_phy(phy_address, MII_PHYSID2, &phyid2);
+		disable_mdi();
+
+		phy_id = (phyid1 << 16) | (phyid2 & 0xfff0);
+		switch (phy_id) {
+			case MII_DM9161_ID:		/* Davicom 9161: PHY_ID1 = 0x181, PHY_ID2 = B881 */
+			case MII_DM9161A_ID:		/* Davicom 9161A: PHY_ID1 = 0x181, PHY_ID2 = B8A0 */
+			case MII_LXT971A_ID:		/* Intel LXT971A: PHY_ID1 = 0x13, PHY_ID2 = 78E0 */
+			case MII_RTL8201_ID:		/* Realtek RTL8201: PHY_ID1 = 0, PHY_ID2 = 0x8201 */
+			case MII_BCM5221_ID:		/* Broadcom BCM5221: PHY_ID1 = 0x40, PHY_ID2 = 0x61e0 */
+			case MII_DP83847_ID:		/* National Semiconductor DP83847:  */
+			case MII_AC101L_ID:		/* Altima AC101L: PHY_ID1 = 0x22, PHY_ID2 = 0x5520 */
+			case MII_KS8721_ID:		/* Micrel KS8721: PHY_ID1 = 0x22, PHY_ID2 = 0x1610 */
+				detected = at91ether_setup(phy_id, phy_address, pdev);
+				break;
+		}
+
+		phy_address++;
+	}
+
+	clk_disable(ether_clk);					/* Disable Peripheral clock */
+
+	return detected;
+}
+
+static int __devexit at91ether_remove(struct platform_device *pdev)
+{
+	struct at91_private *lp = (struct at91_private *) at91_dev->priv;
+
+	unregister_netdev(at91_dev);
+	free_irq(at91_dev->irq, at91_dev);
+	dma_free_coherent(NULL, sizeof(struct recv_desc_bufs), lp->dlist, (dma_addr_t)lp->dlist_phys);
+	clk_put(ether_clk);
+
+	free_netdev(at91_dev);
+	at91_dev = NULL;
+	return 0;
+}
+
+static struct platform_driver at91ether_driver = {
+	.probe		= at91ether_probe,
+	.remove		= __devexit_p(at91ether_remove),
+	/* FIXME:  support suspend and resume */
+	.driver		= {
+		.name	= DRV_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init at91ether_init(void)
+{
+	return platform_driver_register(&at91ether_driver);
+}
+
+static void __exit at91ether_exit(void)
+{
+	platform_driver_unregister(&at91ether_driver);
+}
+
+module_init(at91ether_init)
+module_exit(at91ether_exit)
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("AT91RM9200 EMAC Ethernet driver");
+MODULE_AUTHOR("Andrew Victor");
diff --git a/drivers/net/arm/at91_ether.h b/drivers/net/arm/at91_ether.h
new file mode 100644
index 0000000..9885735
--- /dev/null
+++ b/drivers/net/arm/at91_ether.h
@@ -0,0 +1,101 @@
+/*
+ * Ethernet driver for the Atmel AT91RM9200 (Thunder)
+ *
+ *  Copyright (C) SAN People (Pty) Ltd
+ *
+ * Based on an earlier Atmel EMAC macrocell driver by Atmel and Lineo Inc.
+ * Initial version by Rick Bronson.
+ *
+ * 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.
+ */
+
+#ifndef AT91_ETHERNET
+#define AT91_ETHERNET
+
+
+/* Davicom 9161 PHY */
+#define MII_DM9161_ID	0x0181b880
+#define MII_DM9161A_ID	0x0181b8a0
+
+/* Davicom specific registers */
+#define MII_DSCR_REG	16
+#define MII_DSCSR_REG	17
+#define MII_DSINTR_REG	21
+
+/* Intel LXT971A PHY */
+#define MII_LXT971A_ID	0x001378E0
+
+/* Intel specific registers */
+#define MII_ISINTE_REG	18
+#define MII_ISINTS_REG	19
+#define MII_LEDCTRL_REG	20
+
+/* Realtek RTL8201 PHY */
+#define MII_RTL8201_ID	0x00008200
+
+/* Broadcom BCM5221 PHY */
+#define MII_BCM5221_ID	0x004061e0
+
+/* Broadcom specific registers */
+#define MII_BCMINTR_REG	26
+
+/* National Semiconductor DP83847 */
+#define MII_DP83847_ID	0x20005c30
+
+/* Altima AC101L PHY */
+#define MII_AC101L_ID	0x00225520
+
+/* Micrel KS8721 PHY */
+#define MII_KS8721_ID	0x00221610
+
+/* ........................................................................ */
+
+#define MAX_RBUFF_SZ	0x600		/* 1518 rounded up */
+#define MAX_RX_DESCR	9		/* max number of receive buffers */
+
+#define EMAC_DESC_DONE	0x00000001	/* bit for if DMA is done */
+#define EMAC_DESC_WRAP	0x00000002	/* bit for wrap */
+
+#define EMAC_BROADCAST	0x80000000	/* broadcast address */
+#define EMAC_MULTICAST	0x40000000	/* multicast address */
+#define EMAC_UNICAST	0x20000000	/* unicast address */
+
+struct rbf_t
+{
+	unsigned int addr;
+	unsigned long size;
+};
+
+struct recv_desc_bufs
+{
+	struct rbf_t descriptors[MAX_RX_DESCR];		/* must be on sizeof (rbf_t) boundary */
+	char recv_buf[MAX_RX_DESCR][MAX_RBUFF_SZ];	/* must be on long boundary */
+};
+
+struct at91_private
+{
+	struct net_device_stats stats;
+	struct mii_if_info mii;			/* ethtool support */
+	struct at91_eth_data board_data;	/* board-specific configuration */
+
+	/* PHY */
+	unsigned long phy_type;			/* type of PHY (PHY_ID) */
+	spinlock_t lock;			/* lock for MDI interface */
+	short phy_media;			/* media interface type */
+	unsigned short phy_address;		/* 5-bit MDI address of PHY (0..31) */
+
+	/* Transmit */
+	struct sk_buff *skb;			/* holds skb until xmit interrupt completes */
+	dma_addr_t skb_physaddr;		/* phys addr from pci_map_single */
+	int skb_length;				/* saved skb length for pci_unmap_single */
+
+	/* Receive */
+	int rxBuffIndex;			/* index into receive descriptor list */
+	struct recv_desc_bufs *dlist;		/* descriptor list address */
+	struct recv_desc_bufs *dlist_phys;	/* descriptor list physical address */
+};
+
+#endif
diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c
index e3ebb58..d11821d 100644
--- a/drivers/net/ne2k-pci.c
+++ b/drivers/net/ne2k-pci.c
@@ -117,7 +117,7 @@ enum ne2k_pci_chipsets {
 };
 
 
-static const struct {
+static struct {
 	char *name;
 	int flags;
 } pci_clone_list[] __devinitdata = {
diff --git a/include/asm-arm/arch-at91rm9200/at91rm9200_emac.h b/include/asm-arm/arch-at91rm9200/at91rm9200_emac.h
new file mode 100644
index 0000000..fbc091e
--- /dev/null
+++ b/include/asm-arm/arch-at91rm9200/at91rm9200_emac.h
@@ -0,0 +1,138 @@
+/*
+ * include/asm-arm/arch-at91rm9200/at91rm9200_emac.h
+ *
+ * Copyright (C) 2005 Ivan Kokshaysky
+ * Copyright (C) SAN People
+ *
+ * Ethernet MAC registers.
+ * Based on AT91RM9200 datasheet revision E.
+ *
+ * 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.
+ */
+
+#ifndef AT91RM9200_EMAC_H
+#define AT91RM9200_EMAC_H
+
+#define	AT91_EMAC_CTL		0x00	/* Control Register */
+#define		AT91_EMAC_LB		(1 <<  0)	/* Loopback */
+#define		AT91_EMAC_LBL		(1 <<  1)	/* Loopback Local */
+#define		AT91_EMAC_RE		(1 <<  2)	/* Receive Enable */
+#define		AT91_EMAC_TE		(1 <<  3)	/* Transmit Enable */
+#define		AT91_EMAC_MPE		(1 <<  4)	/* Management Port Enable */
+#define		AT91_EMAC_CSR		(1 <<  5)	/* Clear Statistics Registers */
+#define		AT91_EMAC_INCSTAT	(1 <<  6)	/* Increment Statistics Registers */
+#define		AT91_EMAC_WES		(1 <<  7)	/* Write Enable for Statistics Registers */
+#define		AT91_EMAC_BP		(1 <<  8)	/* Back Pressure */
+
+#define	AT91_EMAC_CFG		0x04	/* Configuration Register */
+#define		AT91_EMAC_SPD		(1 <<  0)	/* Speed */
+#define		AT91_EMAC_FD		(1 <<  1)	/* Full Duplex */
+#define		AT91_EMAC_BR		(1 <<  2)	/* Bit Rate */
+#define		AT91_EMAC_CAF		(1 <<  4)	/* Copy All Frames */
+#define		AT91_EMAC_NBC		(1 <<  5)	/* No Broadcast */
+#define		AT91_EMAC_MTI		(1 <<  6)	/* Multicast Hash Enable */
+#define		AT91_EMAC_UNI		(1 <<  7)	/* Unicast Hash Enable */
+#define		AT91_EMAC_BIG		(1 <<  8)	/* Receive 1522 Bytes */
+#define		AT91_EMAC_EAE		(1 <<  9)	/* External Address Match Enable */
+#define		AT91_EMAC_CLK		(3 << 10)	/* MDC Clock Divisor */
+#define		AT91_EMAC_CLK_DIV8		(0 << 10)
+#define		AT91_EMAC_CLK_DIV16		(1 << 10)
+#define		AT91_EMAC_CLK_DIV32		(2 << 10)
+#define		AT91_EMAC_CLK_DIV64		(3 << 10)
+#define		AT91_EMAC_RTY		(1 << 12)	/* Retry Test */
+#define		AT91_EMAC_RMII		(1 << 13)	/* Reduce MII (RMII) */
+
+#define	AT91_EMAC_SR		0x08	/* Status Register */
+#define		AT91_EMAC_SR_LINK	(1 <<  0)	/* Link */
+#define		AT91_EMAC_SR_MDIO	(1 <<  1)	/* MDIO pin */
+#define		AT91_EMAC_SR_IDLE	(1 <<  2)	/* PHY idle */
+
+#define	AT91_EMAC_TAR		0x0c	/* Transmit Address Register */
+
+#define	AT91_EMAC_TCR		0x10	/* Transmit Control Register */
+#define		AT91_EMAC_LEN		(0x7ff << 0)	/* Transmit Frame Length */
+#define		AT91_EMAC_NCRC		(1     << 15)	/* No CRC */
+
+#define	AT91_EMAC_TSR		0x14	/* Transmit Status Register */
+#define		AT91_EMAC_TSR_OVR	(1 <<  0)	/* Transmit Buffer Overrun */
+#define		AT91_EMAC_TSR_COL	(1 <<  1)	/* Collision Occurred */
+#define		AT91_EMAC_TSR_RLE	(1 <<  2)	/* Retry Limit Exceeded */
+#define		AT91_EMAC_TSR_IDLE	(1 <<  3)	/* Transmitter Idle */
+#define		AT91_EMAC_TSR_BNQ	(1 <<  4)	/* Transmit Buffer not Queued */
+#define		AT91_EMAC_TSR_COMP	(1 <<  5)	/* Transmit Complete */
+#define		AT91_EMAC_TSR_UND	(1 <<  6)	/* Transmit Underrun */
+
+#define	AT91_EMAC_RBQP		0x18	/* Receive Buffer Queue Pointer */
+
+#define	AT91_EMAC_RSR		0x20	/* Receive Status Register */
+#define		AT91_EMAC_RSR_BNA	(1 <<  0)	/* Buffer Not Available */
+#define		AT91_EMAC_RSR_REC	(1 <<  1)	/* Frame Received */
+#define		AT91_EMAC_RSR_OVR	(1 <<  2)	/* RX Overrun */
+
+#define	AT91_EMAC_ISR		0x24	/* Interrupt Status Register */
+#define		AT91_EMAC_DONE		(1 <<  0)	/* Management Done */
+#define		AT91_EMAC_RCOM		(1 <<  1)	/* Receive Complete */
+#define		AT91_EMAC_RBNA		(1 <<  2)	/* Receive Buffer Not Available */
+#define		AT91_EMAC_TOVR		(1 <<  3)	/* Transmit Buffer Overrun */
+#define		AT91_EMAC_TUND		(1 <<  4)	/* Transmit Buffer Underrun */
+#define		AT91_EMAC_RTRY		(1 <<  5)	/* Retry Limit */
+#define		AT91_EMAC_TBRE		(1 <<  6)	/* Transmit Buffer Register Empty */
+#define		AT91_EMAC_TCOM		(1 <<  7)	/* Transmit Complete */
+#define		AT91_EMAC_TIDLE		(1 <<  8)	/* Transmit Idle */
+#define		AT91_EMAC_LINK		(1 <<  9)	/* Link */
+#define		AT91_EMAC_ROVR		(1 << 10)	/* RX Overrun */
+#define		AT91_EMAC_ABT		(1 << 11)	/* Abort */
+
+#define	AT91_EMAC_IER		0x28	/* Interrupt Enable Register */
+#define	AT91_EMAC_IDR		0x2c	/* Interrupt Disable Register */
+#define	AT91_EMAC_IMR		0x30	/* Interrupt Mask Register */
+
+#define	AT91_EMAC_MAN		0x34	/* PHY Maintenance Register */
+#define		AT91_EMAC_DATA		(0xffff << 0)	/* MDIO Data */
+#define		AT91_EMAC_REGA		(0x1f	<< 18)	/* MDIO Register */
+#define		AT91_EMAC_PHYA		(0x1f	<< 23)	/* MDIO PHY Address */
+#define		AT91_EMAC_RW		(3	<< 28)	/* Read/Write operation */
+#define			AT91_EMAC_RW_W		(1 << 28)
+#define			AT91_EMAC_RW_R		(2 << 28)
+#define		AT91_EMAC_MAN_802_3	0x40020000	/* IEEE 802.3 value */
+
+/*
+ * Statistics Registers.
+ */
+#define AT91_EMAC_FRA		0x40	/* Frames Transmitted OK */
+#define AT91_EMAC_SCOL		0x44	/* Single Collision Frame */
+#define AT91_EMAC_MCOL		0x48	/* Multiple Collision Frame */
+#define AT91_EMAC_OK		0x4c	/* Frames Received OK */
+#define AT91_EMAC_SEQE		0x50	/* Frame Check Sequence Error */
+#define AT91_EMAC_ALE		0x54	/* Alignmemt Error */
+#define AT91_EMAC_DTE		0x58	/* Deffered Transmission Frame */
+#define AT91_EMAC_LCOL		0x5c	/* Late Collision */
+#define AT91_EMAC_ECOL		0x60	/* Excessive Collision */
+#define AT91_EMAC_TUE		0x64	/* Transmit Underrun Error */
+#define AT91_EMAC_CSE		0x68	/* Carrier Sense Error */
+#define AT91_EMAC_DRFC		0x6c	/* Discard RX Frame */
+#define AT91_EMAC_ROV		0x70	/* Receive Overrun */
+#define AT91_EMAC_CDE		0x74	/* Code Error */
+#define AT91_EMAC_ELR		0x78	/* Excessive Length Error */
+#define AT91_EMAC_RJB		0x7c	/* Receive Jabber */
+#define AT91_EMAC_USF		0x80	/* Undersize Frame */
+#define AT91_EMAC_SQEE		0x84	/* SQE Test Error */
+
+/*
+ * Address Registers.
+ */
+#define AT91_EMAC_HSL		0x90	/* Hash Address Low [31:0] */
+#define AT91_EMAC_HSH		0x94	/* Hash Address High [63:32] */
+#define AT91_EMAC_SA1L		0x98	/* Specific Address 1 Low, bytes 0-3 */
+#define AT91_EMAC_SA1H		0x9c	/* Specific Address 1 High, bytes 4-5 */
+#define AT91_EMAC_SA2L		0xa0	/* Specific Address 2 Low, bytes 0-3 */
+#define AT91_EMAC_SA2H		0xa4	/* Specific Address 2 High, bytes 4-5 */
+#define AT91_EMAC_SA3L		0xa8	/* Specific Address 3 Low, bytes 0-3 */
+#define AT91_EMAC_SA3H		0xac	/* Specific Address 3 High, bytes 4-5 */
+#define AT91_EMAC_SA4L		0xb0	/* Specific Address 4 Low, bytes 0-3 */
+#define AT91_EMAC_SA4H		0xb4	/* Specific Address 4 High, bytes 4-5 */
+
+#endif

^ permalink raw reply related

* Re: Two comments on the H.323 conntrack/NAT helper
From: Jing Min Zhao @ 2006-03-24 19:02 UTC (permalink / raw)
  To: Patrick McHardy, Adrian Bunk
  Cc: netdev, netfilter-devel, zhaojingmin, linux-kernel
In-Reply-To: <44235324.3080607@trash.net>


----- Original Message ----- 
From: "Patrick McHardy" <kaber@trash.net>
To: "Adrian Bunk" <bunk@stusta.de>
Cc: <netdev@vger.kernel.org>; <zhaojingmin@users.sourceforge.net>; <netfilter-devel@lists.netfilter.org>; "Jing Min Zhao" 
<zhaojignmin@hotmail.com>; <linux-kernel@vger.kernel.org>
Sent: Thursday, March 23, 2006 9:02 PM
Subject: Re: Two comments on the H.323 conntrack/NAT helper


> [The hotmail address of the author doesn't work, CCed sourceforge-address]
>
> Adrian Bunk wrote:
>> Two comments on the H.323 conntrack/NAT helper:
>> - the function prototypes in ip_nat_helper_h323.c are _ugly_,
>>   please move them to a header file
>
> Their ugliness is because of the current API, which cleaned up
> quite a lot of the surrounding code, but requires this ugliness
> from each helper. I would like to keep them visible as a reminder
> that a cleaner solution is wanted, but moving them to header
> files certainly sound like a good idea to eliminate the risk
> of prototype conflicts. But please do this for all helpers
> at once.
>
>> - is there a reason for not using EXPORT_SYMBOL_GPL?
>
> I would prefer that too.
>
>

I've moved those prototypes. But the move involves moving of two header files:
ip_conntrack_helper_h323_asn1.h and ip_conntrack_helper_h323_types.h.
This is because ip_conntrack_h323.h now has to include
ip_conntrack_helper_h323_asn1.h and thus ip_conntrack_helper_h323_types.h,
so they are moved from net/ipv4/netfilter/ to include/linux/netfilter_ipv4/ to
make sure other header files like ip_conntrack_h323.h and ip_conntrack.h
be able to find them.

Is this ok or you have a better idea?

Thanks a lot!

Jing Min Zhao

^ permalink raw reply

* [PATCH] PCI Error Recovery: e1000 network device driver
From: Linas Vepstas @ 2006-03-24 22:00 UTC (permalink / raw)
  To: Jeff Garzik, john.ronciak, jesse.brandeburg, jeffrey.t.kirsher
  Cc: linux-kernel, netdev, linux-pci, linuxppc-dev


Jeff, 
Can you please review and forward this patch upstream?  A previous
version of this patch has been ack'ed by Jesse Brandeburg, one
of the e1000 maintainers.

--linas


[PATCH] PCI Error Recovery: e1000 network device driver

Various PCI bus errors can be signaled by newer PCI controllers.  This
patch adds the PCI error recovery callbacks to the intel gigabit
ethernet e1000 device driver. The patch has been tested, and appears
to work well.

Signed-off-by: Linas Vepstas <linas@linas.org>
Acked-by: Jesse Brandeburg <jesse.brandeburg@intel.com>

----

 drivers/net/e1000/e1000_main.c |  114 ++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 113 insertions(+), 1 deletion(-)

Index: linux-2.6.16-git6/drivers/net/e1000/e1000_main.c
===================================================================
--- linux-2.6.16-git6.orig/drivers/net/e1000/e1000_main.c	2006-03-23 15:48:01.000000000 -0600
+++ linux-2.6.16-git6/drivers/net/e1000/e1000_main.c	2006-03-24 15:14:40.431371705 -0600
@@ -226,6 +226,16 @@ static int e1000_resume(struct pci_dev *
 static void e1000_netpoll (struct net_device *netdev);
 #endif
 
+static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev,
+                     pci_channel_state_t state);
+static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev);
+static void e1000_io_resume(struct pci_dev *pdev);
+
+static struct pci_error_handlers e1000_err_handler = {
+	.error_detected = e1000_io_error_detected,
+	.slot_reset = e1000_io_slot_reset,
+	.resume = e1000_io_resume,
+};
 
 static struct pci_driver e1000_driver = {
 	.name     = e1000_driver_name,
@@ -235,8 +245,9 @@ static struct pci_driver e1000_driver = 
 	/* Power Managment Hooks */
 #ifdef CONFIG_PM
 	.suspend  = e1000_suspend,
-	.resume   = e1000_resume
+	.resume   = e1000_resume,
 #endif
+	.err_handler = &e1000_err_handler,
 };
 
 MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
@@ -3063,6 +3074,10 @@ e1000_update_stats(struct e1000_adapter 
 
 #define PHY_IDLE_ERROR_COUNT_MASK 0x00FF
 
+	/* Prevent stats update while adapter is being reset */
+	if (adapter->link_speed == 0)
+		return;
+
 	spin_lock_irqsave(&adapter->stats_lock, flags);
 
 	/* these counters are modified from e1000_adjust_tbi_stats,
@@ -4631,4 +4646,101 @@ e1000_netpoll(struct net_device *netdev)
 }
 #endif
 
+/**
+ * e1000_io_error_detected - called when PCI error is detected
+ * @pdev: Pointer to PCI device
+ * @state: The current pci conneection state
+ *
+ * This function is called after a PCI bus error affecting
+ * this device has been detected.
+ */
+static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct e1000_adapter *adapter = netdev->priv;
+
+	netif_device_detach(netdev);
+
+	if (netif_running(netdev))
+		e1000_down(adapter);
+
+	/* Request a slot slot reset. */
+	return PCI_ERS_RESULT_NEED_RESET;
+}
+
+/**
+ * e1000_io_slot_reset - called after the pci bus has been reset.
+ * @pdev: Pointer to PCI device
+ *
+ * Restart the card from scratch, as if from a cold-boot. Implementation
+ * resembles the first-half of the e1000_resume routine.
+ */
+static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct e1000_adapter *adapter = netdev->priv;
+
+	if (pci_enable_device(pdev)) {
+		printk(KERN_ERR "e1000: Cannot re-enable PCI device after reset.\n");
+		return PCI_ERS_RESULT_DISCONNECT;
+	}
+	pci_set_master(pdev);
+
+	pci_enable_wake(pdev, 3, 0);
+	pci_enable_wake(pdev, 4, 0); /* 4 == D3 cold */
+
+	/* Perform card reset only on one instance of the card */
+	if(0 != PCI_FUNC (pdev->devfn))
+		return PCI_ERS_RESULT_RECOVERED;
+
+	e1000_reset(adapter);
+	E1000_WRITE_REG(&adapter->hw, WUS, ~0);
+
+	return PCI_ERS_RESULT_RECOVERED;
+}
+
+/**
+ * e1000_io_resume - called when traffic can start flowing again.
+ * @pdev: Pointer to PCI device
+ *
+ * This callback is called when the error recovery driver tells us that
+ * its OK to resume normal operation. Implementation resembles the
+ * second-half of the e1000_resume routine.
+ */
+static void e1000_io_resume(struct pci_dev *pdev)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct e1000_adapter *adapter = netdev->priv;
+	uint32_t manc, swsm;
+
+	if(netif_running(netdev)) {
+		if (e1000_up(adapter)) {
+			printk("e1000: can't bring device back up after reset\n");
+			return;
+		}
+	}
+
+	netif_device_attach(netdev);
+
+	if(adapter->hw.mac_type >= e1000_82540 &&
+	    adapter->hw.media_type == e1000_media_type_copper) {
+		manc = E1000_READ_REG(&adapter->hw, MANC);
+		manc &= ~(E1000_MANC_ARP_EN);
+		E1000_WRITE_REG(&adapter->hw, MANC, manc);
+	}
+
+	switch(adapter->hw.mac_type) {
+	case e1000_82573:
+		swsm = E1000_READ_REG(&adapter->hw, SWSM);
+		E1000_WRITE_REG(&adapter->hw, SWSM,
+				swsm | E1000_SWSM_DRV_LOAD);
+		break;
+	default:
+		break;
+	}
+
+	if(netif_running(netdev))
+		mod_timer(&adapter->watchdog_timer, jiffies);
+}
+
 /* e1000_main.c */

^ permalink raw reply

* Re: [RFC][UPDATED PATCH 2.6.16] [Patch 9/9] Generic netlink interface for delay accounting
From: jamal @ 2006-03-25  1:19 UTC (permalink / raw)
  To: balbir; +Cc: Matt Helsley, Shailabh Nagar, linux-kernel, netdev
In-Reply-To: <20060324145459.GA7495@in.ibm.com>

On Fri, 2006-24-03 at 20:24 +0530, Balbir Singh wrote:

> Hmm... Would it be ok to send one message with the following format
> 
> 1. TLV=TASKSTATS_TYPE_PID
> 2. TLV=TASKSTATS_TYPE_STATS
> 3. TLV=TASKSTATS_TYPE_TGID
> 4. TLV=TASKSTATS_TYPE_STATS
> 
> It would still be one message, except that 3 and 4 would be optional.
> What do you think?
> 

No, that wont work since #2 and #4 are basically the same TLV. [Recall
that "T" is used to index an array]. Your other alternative is to have
#4 perhaps called TASKSTATS_TGID_STATS and #2 TASKSTATS_PID_STATS
although that would smell a little.
Dont be afraid to do the nest, it will be a little painful initially but
i am sure once you figure it out you will appreciate it.

cheers,
jamal

^ permalink raw reply

* Re: [PATCH] PCI Error Recovery: e1000 network device driver
From: Greg KH @ 2006-03-25  2:22 UTC (permalink / raw)
  To: Linas Vepstas
  Cc: Jeff Garzik, john.ronciak, jesse.brandeburg, jeffrey.t.kirsher,
	linux-kernel, netdev, linux-pci, linuxppc-dev
In-Reply-To: <20060324220002.GC26137@austin.ibm.com>

On Fri, Mar 24, 2006 at 04:00:02PM -0600, Linas Vepstas wrote:
> +	/* Perform card reset only on one instance of the card */
> +	if(0 != PCI_FUNC (pdev->devfn))
> +		return PCI_ERS_RESULT_RECOVERED;

You seem to have forgotton to put a ' ' after the 'if' in a number of
different places in this patch.  Also the (0 != foo) form is a bit
different from the traditional kernel coding style.

> +	switch(adapter->hw.mac_type) {

And here too.

Remember, "if" and "switch" are not functions...

thanks,

greg k-h

^ permalink raw reply

* Re: [PATCH] PCI Error Recovery: e1000 network device driver
From: Linas Vepstas @ 2006-03-25  3:21 UTC (permalink / raw)
  To: Greg KH
  Cc: Jeff Garzik, john.ronciak, jesse.brandeburg, jeffrey.t.kirsher,
	linux-kernel, netdev, linux-pci, linuxppc-dev, linux.nics
In-Reply-To: <20060325022206.GA6361@kroah.com>

On Fri, Mar 24, 2006 at 06:22:06PM -0800, Greg KH wrote:
> ... a bit
> different from the traditional kernel coding style.

Sorry, this is due to inattention on my part; I get cross-eyed 
after staring at the same code for too long. The patch below should
fix things.  

--linas


[PATCH] PCI Error Recovery: e1000 network device driver

Various PCI bus errors can be signaled by newer PCI controllers.  This
patch adds the PCI error recovery callbacks to the intel gigabit
ethernet e1000 device driver. The patch has been tested, and appears
to work well.

Signed-off-by: Linas Vepstas <linas@linas.org>
Acked-by: Jesse Brandeburg <jesse.brandeburg@intel.com>

----

 drivers/net/e1000/e1000_main.c |  114 ++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 113 insertions(+), 1 deletion(-)

Index: linux-2.6.16-git6/drivers/net/e1000/e1000_main.c
===================================================================
--- linux-2.6.16-git6.orig/drivers/net/e1000/e1000_main.c	2006-03-23 15:48:01.000000000 -0600
+++ linux-2.6.16-git6/drivers/net/e1000/e1000_main.c	2006-03-24 15:14:40.431371705 -0600
@@ -226,6 +226,16 @@ static int e1000_resume(struct pci_dev *
 static void e1000_netpoll (struct net_device *netdev);
 #endif
 
+static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev,
+                     pci_channel_state_t state);
+static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev);
+static void e1000_io_resume(struct pci_dev *pdev);
+
+static struct pci_error_handlers e1000_err_handler = {
+	.error_detected = e1000_io_error_detected,
+	.slot_reset = e1000_io_slot_reset,
+	.resume = e1000_io_resume,
+};
 
 static struct pci_driver e1000_driver = {
 	.name     = e1000_driver_name,
@@ -235,8 +245,9 @@ static struct pci_driver e1000_driver = 
 	/* Power Managment Hooks */
 #ifdef CONFIG_PM
 	.suspend  = e1000_suspend,
-	.resume   = e1000_resume
+	.resume   = e1000_resume,
 #endif
+	.err_handler = &e1000_err_handler,
 };
 
 MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
@@ -3063,6 +3074,10 @@ e1000_update_stats(struct e1000_adapter 
 
 #define PHY_IDLE_ERROR_COUNT_MASK 0x00FF
 
+	/* Prevent stats update while adapter is being reset */
+	if (adapter->link_speed == 0)
+		return;
+
 	spin_lock_irqsave(&adapter->stats_lock, flags);
 
 	/* these counters are modified from e1000_adjust_tbi_stats,
@@ -4631,4 +4646,101 @@ e1000_netpoll(struct net_device *netdev)
 }
 #endif
 
+/**
+ * e1000_io_error_detected - called when PCI error is detected
+ * @pdev: Pointer to PCI device
+ * @state: The current pci conneection state
+ *
+ * This function is called after a PCI bus error affecting
+ * this device has been detected.
+ */
+static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct e1000_adapter *adapter = netdev->priv;
+
+	netif_device_detach(netdev);
+
+	if (netif_running(netdev))
+		e1000_down(adapter);
+
+	/* Request a slot slot reset. */
+	return PCI_ERS_RESULT_NEED_RESET;
+}
+
+/**
+ * e1000_io_slot_reset - called after the pci bus has been reset.
+ * @pdev: Pointer to PCI device
+ *
+ * Restart the card from scratch, as if from a cold-boot. Implementation
+ * resembles the first-half of the e1000_resume routine.
+ */
+static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct e1000_adapter *adapter = netdev->priv;
+
+	if (pci_enable_device(pdev)) {
+		printk(KERN_ERR "e1000: Cannot re-enable PCI device after reset.\n");
+		return PCI_ERS_RESULT_DISCONNECT;
+	}
+	pci_set_master(pdev);
+
+	pci_enable_wake(pdev, 3, 0);
+	pci_enable_wake(pdev, 4, 0); /* 4 == D3 cold */
+
+	/* Perform card reset only on one instance of the card */
+	if (PCI_FUNC (pdev->devfn) != 0)
+		return PCI_ERS_RESULT_RECOVERED;
+
+	e1000_reset(adapter);
+	E1000_WRITE_REG(&adapter->hw, WUS, ~0);
+
+	return PCI_ERS_RESULT_RECOVERED;
+}
+
+/**
+ * e1000_io_resume - called when traffic can start flowing again.
+ * @pdev: Pointer to PCI device
+ *
+ * This callback is called when the error recovery driver tells us that
+ * its OK to resume normal operation. Implementation resembles the
+ * second-half of the e1000_resume routine.
+ */
+static void e1000_io_resume(struct pci_dev *pdev)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct e1000_adapter *adapter = netdev->priv;
+	uint32_t manc, swsm;
+
+	if (netif_running(netdev)) {
+		if (e1000_up(adapter)) {
+			printk("e1000: can't bring device back up after reset\n");
+			return;
+		}
+	}
+
+	netif_device_attach(netdev);
+
+	if (adapter->hw.mac_type >= e1000_82540 &&
+	    adapter->hw.media_type == e1000_media_type_copper) {
+		manc = E1000_READ_REG(&adapter->hw, MANC);
+		manc &= ~(E1000_MANC_ARP_EN);
+		E1000_WRITE_REG(&adapter->hw, MANC, manc);
+	}
+
+	switch (adapter->hw.mac_type) {
+	case e1000_82573:
+		swsm = E1000_READ_REG(&adapter->hw, SWSM);
+		E1000_WRITE_REG(&adapter->hw, SWSM,
+				swsm | E1000_SWSM_DRV_LOAD);
+		break;
+	default:
+		break;
+	}
+
+	if (netif_running(netdev))
+		mod_timer(&adapter->watchdog_timer, jiffies);
+}
+
 /* e1000_main.c */

^ permalink raw reply

* Re: [RFC][UPDATED PATCH 2.6.16] [Patch 9/9] Generic netlink interface for delay accounting
From: Balbir Singh @ 2006-03-25  9:41 UTC (permalink / raw)
  To: jamal; +Cc: Matt Helsley, Shailabh Nagar, linux-kernel, netdev
In-Reply-To: <1143249565.5184.6.camel@jzny2>

On Fri, Mar 24, 2006 at 08:19:25PM -0500, jamal wrote:
> On Fri, 2006-24-03 at 20:24 +0530, Balbir Singh wrote:
> 
> > Hmm... Would it be ok to send one message with the following format
> > 
> > 1. TLV=TASKSTATS_TYPE_PID
> > 2. TLV=TASKSTATS_TYPE_STATS
> > 3. TLV=TASKSTATS_TYPE_TGID
> > 4. TLV=TASKSTATS_TYPE_STATS
> > 
> > It would still be one message, except that 3 and 4 would be optional.
> > What do you think?
> > 
> 
> No, that wont work since #2 and #4 are basically the same TLV. [Recall
> that "T" is used to index an array]. Your other alternative is to have
> #4 perhaps called TASKSTATS_TGID_STATS and #2 TASKSTATS_PID_STATS
> although that would smell a little.
> Dont be afraid to do the nest, it will be a little painful initially but
> i am sure once you figure it out you will appreciate it.
>

Thanks for the advice, I will dive into nesting. I could not find any 
in tree users who use nesting, so I have a few questions

nla_nest_start() accepts two parameters an skb and an attribute type.
Do I have to create a new attribute type like TASKSTATS_TYPE_AGGR to
contain the nested attributes 

TASKSTATS_TYPE_AGGR
   TASKSTATS_TYPE_PID/TGID
   TASKSTATS_TYPE_STATS

but this will lead to


TASKSTATS_TYPE_AGGR
   TASKSTATS_TYPE_PID
   TASKSTATS_TYPE_STATS
TASKSTATS_TYPE_AGGR
   TASKSTATS_TYPE_TGID
   TASKSTATS_TYPE_STATS

being returned from taskstats_exit_pid().

The other option is to nest

TASKSTATS_TYPE_PID/TGID
   TASKSTATS_TYPE_STATS

but the problem with this approach is, nla_len contains the length of
all attributes including the nested attribute. So it is hard to find
the offset of TASKSTATS_TYPE_STATS in the buffer.

Do I understand NLA nesting at all? May be I am missing something obvious.

Thanks,
Balbir

^ permalink raw reply

* Re: [RFC][UPDATED PATCH 2.6.16] [Patch 9/9] Generic netlink interface for delay accounting
From: jamal @ 2006-03-25 12:52 UTC (permalink / raw)
  To: balbir; +Cc: Matt Helsley, Shailabh Nagar, linux-kernel, netdev
In-Reply-To: <20060325094126.GA9376@in.ibm.com>

On Sat, 2006-25-03 at 15:11 +0530, Balbir Singh wrote:

> 
> Thanks for the advice, I will dive into nesting. I could not find any 
> in tree users who use nesting, so I have a few questions
> 

Hrm - I have to say i am suprised theres nothing; i could have sworn
Thomas had done some conversions already.

> nla_nest_start() accepts two parameters an skb and an attribute type.
> Do I have to create a new attribute type like TASKSTATS_TYPE_AGGR to
> contain the nested attributes 
> 
> TASKSTATS_TYPE_AGGR
>    TASKSTATS_TYPE_PID/TGID
>    TASKSTATS_TYPE_STATS
> 
>
> but this will lead to
> 
> TASKSTATS_TYPE_AGGR
>    TASKSTATS_TYPE_PID
>    TASKSTATS_TYPE_STATS
> TASKSTATS_TYPE_AGGR
>    TASKSTATS_TYPE_TGID
>    TASKSTATS_TYPE_STATS
> 
> being returned from taskstats_exit_pid().
> 

no this is wrong by virtue of having TASKSTATS_TYPE_AGGR twice.
Again invoke the rule i cited earlier.
What you could do instead is a second AGGR; and your nesting would be:

TASKSTATS_TYPE_AGGR1 <--- nest start with this type
   TASKSTATS_TYPE_PID <-- NLA_U32_PUT
   TASKSTATS_TYPE_STATS <-- NAL_PUT_TYPE
                     <-- nest end of TASKSTATS_TYPE_AGGR1
TASKSTATS_TYPE_AGGR2 <--- nest start with this type
   TASKSTATS_TYPE_TGID <-- NLA_U32_PUT
   TASKSTATS_TYPE_STATS <-- NAL_PUT_TYPE
                       <-- nest end of TASKSTATS_TYPE_AGGR2

> The other option is to nest
> 
> TASKSTATS_TYPE_PID/TGID
>    TASKSTATS_TYPE_STATS
> 

The advantage being you dont introduce another T.

> but the problem with this approach is, nla_len contains the length of
> all attributes including the nested attribute. So it is hard to find
> the offset of TASKSTATS_TYPE_STATS in the buffer.
> 

So you would distinguish the two as have something like:

TASKSTATS_TYPE_PID
   u32 pid
   TASKSTATS_TYPE_STATS
TASKSTATS_TYPE_TGID
   u32 tgid
   TASKSTATS_TYPE_STATS
or
TASKSTATS_TYPE_PID
   u32 pid
TASKSTATS_TYPE_TGID
   u32 tgid

both should be fine. The difference between the two is the length in the
second case will be 4 and in the other case will be larger. 

But come to think of it, this will introduce unneeded semantics; you
have very few items to do, so forget it. Go with scheme #1 but change
the names to TASKSTATS_TYPE_AGGR_PID and TASKSTATS_TYPE_AGGR_TGID.

cheers,
jamal

^ permalink raw reply

* Re: [RFC][UPDATED PATCH 2.6.16] [Patch 9/9] Generic netlink interface for delay accounting
From: Balbir Singh @ 2006-03-25 15:36 UTC (permalink / raw)
  To: jamal; +Cc: Matt Helsley, Shailabh Nagar, linux-kernel, netdev
In-Reply-To: <1143291133.5184.32.camel@jzny2>

On Sat, Mar 25, 2006 at 07:52:13AM -0500, jamal wrote:
> On Sat, 2006-25-03 at 15:11 +0530, Balbir Singh wrote:
> 
> > 
> > Thanks for the advice, I will dive into nesting. I could not find any 
> > in tree users who use nesting, so I have a few questions
> > 
> 
> Hrm - I have to say i am suprised theres nothing; i could have sworn
> Thomas had done some conversions already.

I used cscope to check for global references and callers of nla_nest_.*.
I could not find anything.

> 
> > nla_nest_start() accepts two parameters an skb and an attribute type.
> > Do I have to create a new attribute type like TASKSTATS_TYPE_AGGR to
> > contain the nested attributes 
> > 
> > TASKSTATS_TYPE_AGGR
> >    TASKSTATS_TYPE_PID/TGID
> >    TASKSTATS_TYPE_STATS
> > 
> >
> > but this will lead to
> > 
> > TASKSTATS_TYPE_AGGR
> >    TASKSTATS_TYPE_PID
> >    TASKSTATS_TYPE_STATS
> > TASKSTATS_TYPE_AGGR
> >    TASKSTATS_TYPE_TGID
> >    TASKSTATS_TYPE_STATS
> > 
> > being returned from taskstats_exit_pid().
> > 
> 
> no this is wrong by virtue of having TASKSTATS_TYPE_AGGR twice.
> Again invoke the rule i cited earlier.

Yes, thats why I wanted to point it out to you. Thanks for explaining the
rule.

> What you could do instead is a second AGGR; and your nesting would be:
> 
> TASKSTATS_TYPE_AGGR1 <--- nest start with this type
>    TASKSTATS_TYPE_PID <-- NLA_U32_PUT
>    TASKSTATS_TYPE_STATS <-- NAL_PUT_TYPE
>                      <-- nest end of TASKSTATS_TYPE_AGGR1
> TASKSTATS_TYPE_AGGR2 <--- nest start with this type
>    TASKSTATS_TYPE_TGID <-- NLA_U32_PUT
>    TASKSTATS_TYPE_STATS <-- NAL_PUT_TYPE
>                        <-- nest end of TASKSTATS_TYPE_AGGR2
> 
> > The other option is to nest
> > 
> > TASKSTATS_TYPE_PID/TGID
> >    TASKSTATS_TYPE_STATS
> > 
> 
> The advantage being you dont introduce another T.
> 
> > but the problem with this approach is, nla_len contains the length of
> > all attributes including the nested attribute. So it is hard to find
> > the offset of TASKSTATS_TYPE_STATS in the buffer.
> > 
> 
> So you would distinguish the two as have something like:
> 
> TASKSTATS_TYPE_PID
>    u32 pid
>    TASKSTATS_TYPE_STATS
> TASKSTATS_TYPE_TGID
>    u32 tgid
>    TASKSTATS_TYPE_STATS
> or
> TASKSTATS_TYPE_PID
>    u32 pid
> TASKSTATS_TYPE_TGID
>    u32 tgid
> 
> both should be fine. The difference between the two is the length in the
> second case will be 4 and in the other case will be larger. 
> 
> But come to think of it, this will introduce unneeded semantics; you
> have very few items to do, so forget it. Go with scheme #1 but change
> the names to TASKSTATS_TYPE_AGGR_PID and TASKSTATS_TYPE_AGGR_TGID.
>

I prefer #1 as well. The overloaded use of the same type with different lengths
can be confusing.
 
> cheers,
> jamal
> 

Here is another attempt (one more iteration) at trying to get it right.
Thank you for your patience and help in getting it right.

Changelog
---------

As discussed in our email.

Thanks,
Balbir

Signed-off-by: Shailabh Nagar <nagar@watson.ibm.com>
Signed-off-by: Balbir Singh <balbir@in.ibm.com>

---

 include/linux/delayacct.h |   11 +
 include/linux/taskstats.h |  113 +++++++++++++++++
 init/Kconfig              |   16 ++
 kernel/Makefile           |    1 
 kernel/delayacct.c        |   44 ++++++
 kernel/taskstats.c        |  291 ++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 473 insertions(+), 3 deletions(-)

diff -puN include/linux/delayacct.h~delayacct-genetlink include/linux/delayacct.h
--- linux-2.6.16/include/linux/delayacct.h~delayacct-genetlink	2006-03-22 11:56:03.000000000 +0530
+++ linux-2.6.16-balbir/include/linux/delayacct.h	2006-03-22 11:56:03.000000000 +0530
@@ -15,6 +15,7 @@
 #define _LINUX_TASKDELAYS_H
 
 #include <linux/sched.h>
+#include <linux/taskstats.h>
 
 #ifdef CONFIG_TASK_DELAY_ACCT
 extern int delayacct_on;	/* Delay accounting turned on/off */
@@ -25,6 +26,7 @@ extern void __delayacct_tsk_exit(struct 
 extern void __delayacct_blkio_start(void);
 extern void __delayacct_blkio_end(void);
 extern unsigned long long __delayacct_blkio_ticks(struct task_struct *);
+extern int __delayacct_add_tsk(struct taskstats *, struct task_struct *);
 
 static inline void delayacct_tsk_init(struct task_struct *tsk)
 {
@@ -72,4 +74,13 @@ static inline unsigned long long delayac
 	return 0;
 }
 #endif /* CONFIG_TASK_DELAY_ACCT */
+#ifdef CONFIG_TASKSTATS
+static inline int delayacct_add_tsk(struct taskstats *d,
+				    struct task_struct *tsk)
+{
+	if (!tsk->delays)
+		return -EINVAL;
+	return __delayacct_add_tsk(d, tsk);
+}
+#endif
 #endif /* _LINUX_TASKDELAYS_H */
diff -puN /dev/null include/linux/taskstats.h
--- /dev/null	2004-06-24 23:34:38.000000000 +0530
+++ linux-2.6.16-balbir/include/linux/taskstats.h	2006-03-25 20:56:55.000000000 +0530
@@ -0,0 +1,113 @@
+/* taskstats.h - exporting per-task statistics
+ *
+ * Copyright (C) Shailabh Nagar, IBM Corp. 2006
+ *           (C) Balbir Singh,   IBM Corp. 2006
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2.1 of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef _LINUX_TASKSTATS_H
+#define _LINUX_TASKSTATS_H
+
+/* Format for per-task data returned to userland when
+ *	- a task exits
+ *	- listener requests stats for a task
+ *
+ * The struct is versioned. Newer versions should only add fields to
+ * the bottom of the struct to maintain backward compatibility.
+ *
+ * To create the next version, bump up the taskstats_version variable
+ * and delineate the start of newly added fields with a comment indicating
+ * the version number.
+ */
+
+#define TASKSTATS_VERSION	1
+#define TASKSTATS_NOPID	-1
+
+struct taskstats {
+	/* Maintain 64-bit alignment while extending */
+	/* Version 1 */
+
+	/* XXX_count is number of delay values recorded.
+	 * XXX_total is corresponding cumulative delay in nanoseconds
+	 */
+
+#define TASKSTATS_NOCPUSTATS	1
+	__u64	cpu_count;
+	__u64	cpu_delay_total;	/* wait, while runnable, for cpu */
+	__u64	blkio_count;
+	__u64	blkio_delay_total;	/* sync,block io completion wait*/
+	__u64	swapin_count;
+	__u64	swapin_delay_total;	/* swapin page fault wait*/
+
+	__u64	cpu_run_total;		/* cpu running time
+					 * no count available/provided */
+};
+
+
+#define TASKSTATS_LISTEN_GROUP	0x1
+
+/*
+ * Commands sent from userspace
+ * Not versioned. New commands should only be inserted at the enum's end
+ */
+
+enum {
+	TASKSTATS_CMD_UNSPEC = 0,	/* Reserved */
+	TASKSTATS_CMD_GET,		/* user->kernel request */
+	TASKSTATS_CMD_NEW,		/* kernel->user event */
+	__TASKSTATS_CMD_MAX,
+};
+
+#define TASKSTATS_CMD_MAX (__TASKSTATS_CMD_MAX - 1)
+
+enum {
+	TASKSTATS_TYPE_UNSPEC = 0,	/* Reserved */
+	TASKSTATS_TYPE_PID,		/* Process id */
+	TASKSTATS_TYPE_TGID,		/* Thread group id */
+	TASKSTATS_TYPE_STATS,		/* taskstats structure */
+	TASKSTATS_TYPE_AGGR_PID,	/* contains pid + stats */
+	TASKSTATS_TYPE_AGGR_TGID,	/* contains tgid + stats */
+	__TASKSTATS_TYPE_MAX,
+};
+
+#define TASKSTATS_TYPE_MAX (__TASKSTATS_TYPE_MAX - 1)
+
+enum {
+	TASKSTATS_CMD_ATTR_UNSPEC = 0,
+	TASKSTATS_CMD_ATTR_PID,
+	TASKSTATS_CMD_ATTR_TGID,
+	__TASKSTATS_CMD_ATTR_MAX,
+};
+
+#define TASKSTATS_CMD_ATTR_MAX (__TASKSTATS_CMD_ATTR_MAX - 1)
+
+/* NETLINK_GENERIC related info */
+
+#define TASKSTATS_GENL_NAME	"TASKSTATS"
+#define TASKSTATS_GENL_VERSION	0x1
+
+#ifdef __KERNEL__
+
+#include <linux/sched.h>
+
+enum {
+	TASKSTATS_MSG_UNICAST,		/* send data only to requester */
+	TASKSTATS_MSG_MULTICAST,	/* send data to a group */
+};
+
+#ifdef CONFIG_TASKSTATS
+extern void taskstats_exit_pid(struct task_struct *);
+#else
+static inline void taskstats_exit_pid(struct task_struct *tsk)
+{}
+#endif
+
+#endif /* __KERNEL__ */
+#endif /* _LINUX_TASKSTATS_H */
diff -puN init/Kconfig~delayacct-genetlink init/Kconfig
--- linux-2.6.16/init/Kconfig~delayacct-genetlink	2006-03-22 11:56:03.000000000 +0530
+++ linux-2.6.16-balbir/init/Kconfig	2006-03-22 11:56:03.000000000 +0530
@@ -158,11 +158,21 @@ config TASK_DELAY_ACCT
 	  in pages. Such statistics can help in setting a task's priorities
 	  relative to other tasks for cpu, io, rss limits etc.
 
-	  Unlike BSD process accounting, this information is available
-	  continuously during the lifetime of a task.
-
 	  Say N if unsure.
 
+config TASKSTATS
+	bool "Export task/process statistics through netlink (EXPERIMENTAL)"
+	depends on TASK_DELAY_ACCT
+	default y
+	help
+	  Export selected statistics for tasks/processes through the
+	  generic netlink interface. Unlike BSD process accounting, the
+	  statistics are available during the lifetime of tasks/processes as
+	  responses to commands. Like BSD accounting, they are sent to user
+	  space on task exit.
+
+	  Say Y if unsure.
+
 config SYSCTL
 	bool "Sysctl support"
 	---help---
diff -puN kernel/delayacct.c~delayacct-genetlink kernel/delayacct.c
--- linux-2.6.16/kernel/delayacct.c~delayacct-genetlink	2006-03-22 11:56:03.000000000 +0530
+++ linux-2.6.16-balbir/kernel/delayacct.c	2006-03-25 20:56:55.000000000 +0530
@@ -1,6 +1,7 @@
 /* delayacct.c - per-task delay accounting
  *
  * Copyright (C) Shailabh Nagar, IBM Corp. 2006
+ * Copyright (C) Balbir Singh, IBM Corp. 2006
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2.1 of the GNU Lesser General Public License
@@ -16,9 +17,12 @@
 #include <linux/time.h>
 #include <linux/sysctl.h>
 #include <linux/delayacct.h>
+#include <linux/taskstats.h>
+#include <linux/mutex.h>
 
 int delayacct_on = 0;		/* Delay accounting turned on/off */
 kmem_cache_t *delayacct_cache;
+static DEFINE_MUTEX(delayacct_exit_mutex);
 
 static int __init delayacct_setup_enable(char *str)
 {
@@ -51,10 +55,16 @@ void __delayacct_tsk_init(struct task_st
 
 void __delayacct_tsk_exit(struct task_struct *tsk)
 {
+	/*
+	 * Protect against racing thread group exits
+	 */
+	mutex_lock(&delayacct_exit_mutex);
+	taskstats_exit_pid(tsk);
 	if (tsk->delays) {
 		kmem_cache_free(delayacct_cache, tsk->delays);
 		tsk->delays = NULL;
 	}
+	mutex_unlock(&delayacct_exit_mutex);
 }
 
 /*
@@ -124,3 +134,37 @@ unsigned long long __delayacct_blkio_tic
 	spin_unlock(&tsk->delays->lock);
 	return ret;
 }
+#ifdef CONFIG_TASKSTATS
+int __delayacct_add_tsk(struct taskstats *d, struct task_struct *tsk)
+{
+	nsec_t tmp;
+	struct timespec ts;
+	unsigned long t1,t2;
+
+	/* zero XXX_total,non-zero XXX_count implies XXX stat overflowed */
+
+	tmp = (nsec_t)d->cpu_run_total ;
+	tmp += (u64)(tsk->utime+tsk->stime)*TICK_NSEC;
+	d->cpu_run_total = (tmp < (nsec_t)d->cpu_run_total)? 0: tmp;
+
+	/* No locking available for sched_info. Take snapshot first. */
+	t1 = tsk->sched_info.pcnt;
+	t2 = tsk->sched_info.run_delay;
+
+	d->cpu_count += t1;
+
+	jiffies_to_timespec(t2, &ts);
+	tmp = (nsec_t)d->cpu_delay_total + timespec_to_ns(&ts);
+	d->cpu_delay_total = (tmp < (nsec_t)d->cpu_delay_total)? 0: tmp;
+
+	spin_lock(&tsk->delays->lock);
+	tmp = d->blkio_delay_total + tsk->delays->blkio_delay;
+	d->blkio_delay_total = (tmp < d->blkio_delay_total)? 0: tmp;
+	tmp = d->swapin_delay_total + tsk->delays->swapin_delay;
+	d->swapin_delay_total = (tmp < d->swapin_delay_total)? 0: tmp;
+	d->blkio_count += tsk->delays->blkio_count;
+	d->swapin_count += tsk->delays->swapin_count;
+	spin_unlock(&tsk->delays->lock);
+	return 0;
+}
+#endif /* CONFIG_TASKSTATS */
diff -puN kernel/Makefile~delayacct-genetlink kernel/Makefile
--- linux-2.6.16/kernel/Makefile~delayacct-genetlink	2006-03-22 11:56:03.000000000 +0530
+++ linux-2.6.16-balbir/kernel/Makefile	2006-03-22 11:56:03.000000000 +0530
@@ -35,6 +35,7 @@ obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
 obj-$(CONFIG_SECCOMP) += seccomp.o
 obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o
 obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o
+obj-$(CONFIG_TASKSTATS) += taskstats.o
 
 ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
diff -puN /dev/null kernel/taskstats.c
--- /dev/null	2004-06-24 23:34:38.000000000 +0530
+++ linux-2.6.16-balbir/kernel/taskstats.c	2006-03-25 20:57:19.000000000 +0530
@@ -0,0 +1,291 @@
+/*
+ * taskstats.c - Export per-task statistics to userland
+ *
+ * Copyright (C) Shailabh Nagar, IBM Corp. 2006
+ *           (C) Balbir Singh,   IBM Corp. 2006
+ *
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/taskstats.h>
+#include <linux/delayacct.h>
+#include <net/genetlink.h>
+#include <asm/atomic.h>
+
+const int taskstats_version = TASKSTATS_VERSION;
+static DEFINE_PER_CPU(__u32, taskstats_seqnum) = { 0 };
+static int family_registered = 0;
+
+static struct genl_family family = {
+	.id             = GENL_ID_GENERATE,
+	.name           = TASKSTATS_GENL_NAME,
+	.version        = TASKSTATS_GENL_VERSION,
+	.maxattr        = TASKSTATS_CMD_ATTR_MAX,
+};
+
+static struct nla_policy taskstats_cmd_get_policy[TASKSTATS_CMD_ATTR_MAX+1] __read_mostly = {
+	[TASKSTATS_CMD_ATTR_PID]  = { .type = NLA_U32 },
+	[TASKSTATS_CMD_ATTR_TGID] = { .type = NLA_U32 },
+};
+
+
+static int prepare_reply(struct genl_info *info, u8 cmd, struct sk_buff **skbp,
+			 void **replyp, size_t size)
+{
+	struct sk_buff *skb;
+	void *reply;
+
+	/*
+	 * If new attributes are added, please revisit this allocation
+	 */
+	skb = nlmsg_new(size);
+	if (!skb)
+		return -ENOMEM;
+
+	if (!info) {
+		int seq = get_cpu_var(taskstats_seqnum)++;
+		put_cpu_var(taskstats_seqnum);
+
+		reply = genlmsg_put(skb, 0, seq,
+				    family.id, 0, 0,
+				    cmd, family.version);
+	} else
+		reply = genlmsg_put(skb, info->snd_pid, info->snd_seq,
+				    family.id, 0, 0,
+				    cmd, family.version);
+	if (reply == NULL) {
+		nlmsg_free(skb);
+		return -EINVAL;
+	}
+
+	*skbp = skb;
+	*replyp = reply;
+	return 0;
+}
+
+static int send_reply(struct sk_buff *skb, pid_t pid, int event)
+{
+	struct genlmsghdr *genlhdr = nlmsg_data((struct nlmsghdr *)skb->data);
+	void *reply;
+	int rc;
+
+	reply = genlmsg_data(genlhdr);
+
+	rc = genlmsg_end(skb, reply);
+	if (rc < 0) {
+		nlmsg_free(skb);
+		return rc;
+	}
+
+	if (event == TASKSTATS_MSG_MULTICAST)
+		return genlmsg_multicast(skb, pid, TASKSTATS_LISTEN_GROUP);
+	return genlmsg_unicast(skb, pid);
+}
+
+static inline int fill_pid(pid_t pid, struct task_struct *pidtsk,
+			   struct taskstats *stats)
+{
+	int rc;
+	struct task_struct *tsk = pidtsk;
+
+	if (!pidtsk) {
+		read_lock(&tasklist_lock);
+		tsk = find_task_by_pid(pid);
+		if (!tsk) {
+			read_unlock(&tasklist_lock);
+			return -ESRCH;
+		}
+		get_task_struct(tsk);
+		read_unlock(&tasklist_lock);
+	} else
+		get_task_struct(tsk);
+
+	rc = delayacct_add_tsk(stats, tsk);
+	put_task_struct(tsk);
+
+	return rc;
+
+}
+
+static inline int fill_tgid(pid_t tgid, struct task_struct *tgidtsk,
+			    struct taskstats *stats)
+{
+	int rc;
+	struct task_struct *tsk, *first;
+
+	first = tgidtsk;
+	read_lock(&tasklist_lock);
+	if (!first) {
+		first = find_task_by_pid(tgid);
+		if (!first) {
+			read_unlock(&tasklist_lock);
+			return -ESRCH;
+		}
+	}
+	tsk = first;
+	do {
+		rc = delayacct_add_tsk(stats, tsk);
+		if (rc)
+			break;
+	} while_each_thread(first, tsk);
+	read_unlock(&tasklist_lock);
+
+	return rc;
+}
+
+static int taskstats_send_stats(struct sk_buff *skb, struct genl_info *info)
+{
+	int rc = 0;
+	struct sk_buff *rep_skb;
+	struct taskstats stats;
+	void *reply;
+	size_t size;
+	struct nlattr *na;
+
+	/*
+	 * Size includes space for nested attribute as well
+	 * The returned data is of the format
+	 * TASKSTATS_TYPE_AGGR_PID/TGID
+	 * --> TASKSTATS_TYPE_PID/TGID
+	 * --> TASKSTATS_TYPE_STATS
+	 */
+	size = nla_total_size(sizeof(u32)) +
+		nla_total_size(sizeof(struct taskstats)) + nla_total_size(0);
+
+	memset(&stats, 0, sizeof(stats));
+	rc = prepare_reply(info, TASKSTATS_CMD_NEW, &rep_skb, &reply, size);
+	if (rc < 0)
+		return rc;
+
+	if (info->attrs[TASKSTATS_CMD_ATTR_PID]) {
+		u32 pid = nla_get_u32(info->attrs[TASKSTATS_CMD_ATTR_PID]);
+		rc = fill_pid((pid_t)pid, NULL, &stats);
+		if (rc < 0)
+			goto err;
+
+		na = nla_nest_start(rep_skb, TASKSTATS_TYPE_AGGR_PID);
+		NLA_PUT_U32(rep_skb, TASKSTATS_TYPE_PID, pid);
+	} else if (info->attrs[TASKSTATS_CMD_ATTR_TGID]) {
+		u32 tgid = nla_get_u32(info->attrs[TASKSTATS_CMD_ATTR_TGID]);
+		rc = fill_tgid((pid_t)tgid, NULL, &stats);
+		if (rc < 0)
+			goto err;
+
+		na = nla_nest_start(rep_skb, TASKSTATS_TYPE_AGGR_TGID);
+		NLA_PUT_U32(rep_skb, TASKSTATS_TYPE_TGID, tgid);
+	} else {
+		rc = -EINVAL;
+		goto err;
+	}
+
+	NLA_PUT_TYPE(rep_skb, struct taskstats, TASKSTATS_TYPE_STATS, stats);
+	nla_nest_end(rep_skb, na);
+
+	return send_reply(rep_skb, info->snd_pid, TASKSTATS_MSG_UNICAST);
+
+nla_put_failure:
+	return  genlmsg_cancel(rep_skb, reply);
+err:
+	nlmsg_free(rep_skb);
+	return rc;
+}
+
+
+/* Send pid data out on exit */
+void taskstats_exit_pid(struct task_struct *tsk)
+{
+	int rc = 0;
+	struct sk_buff *rep_skb;
+	void *reply;
+	struct taskstats stats;
+	size_t size;
+	int is_thread_group = !thread_group_empty(tsk);
+	struct nlattr *na;
+
+	/*
+	 * tasks can start to exit very early. Ensure that the family
+	 * is registered before notifications are sent out
+	 */
+	if (!family_registered)
+		return;
+
+	/*
+	 * Size includes space for nested attributes
+	 */
+	size = nla_total_size(sizeof(u32)) +
+		nla_total_size(sizeof(struct taskstats)) + nla_total_size(0);
+
+	if (is_thread_group)
+		size = 2 * size;	// PID + STATS + TGID + STATS
+
+	memset(&stats, 0, sizeof(stats));
+	rc = prepare_reply(NULL, TASKSTATS_CMD_NEW, &rep_skb, &reply, size);
+	if (rc < 0)
+		return;
+
+	rc = fill_pid(tsk->pid, tsk, &stats);
+	if (rc < 0)
+		goto err;
+
+	na = nla_nest_start(rep_skb, TASKSTATS_TYPE_AGGR_PID);
+	NLA_PUT_U32(rep_skb, TASKSTATS_TYPE_PID, (u32)tsk->pid);
+	NLA_PUT_TYPE(rep_skb, struct taskstats, TASKSTATS_TYPE_STATS, stats);
+	nla_nest_end(rep_skb, na);
+
+	if (!is_thread_group) {
+		send_reply(rep_skb, 0, TASKSTATS_MSG_MULTICAST);
+		return;
+	}
+
+	memset(&stats, 0, sizeof(stats));
+	rc = fill_tgid(tsk->tgid, tsk, &stats);
+	if (rc < 0)
+		goto err;
+
+	na = nla_nest_start(rep_skb, TASKSTATS_TYPE_AGGR_TGID);
+	NLA_PUT_U32(rep_skb, TASKSTATS_TYPE_TGID, (u32)tsk->tgid);
+	NLA_PUT_TYPE(rep_skb, struct taskstats, TASKSTATS_TYPE_STATS, stats);
+	nla_nest_end(rep_skb, na);
+
+	send_reply(rep_skb, 0, TASKSTATS_MSG_MULTICAST);
+
+nla_put_failure:
+	genlmsg_cancel(rep_skb, reply);
+	return;
+err:
+	nlmsg_free(rep_skb);
+}
+
+static struct genl_ops taskstats_ops = {
+	.cmd            = TASKSTATS_CMD_GET,
+	.doit           = taskstats_send_stats,
+	.policy		= taskstats_cmd_get_policy,
+};
+
+static int __init taskstats_init(void)
+{
+	if (genl_register_family(&family))
+		return -EFAULT;
+        family_registered = 1;
+
+	if (genl_register_ops(&family, &taskstats_ops))
+		goto err;
+
+	return 0;
+err:
+	genl_unregister_family(&family);
+	family_registered = 0;
+	return -EFAULT;
+}
+
+late_initcall(taskstats_init);
_

^ permalink raw reply

* Re: [RFC][UPDATED PATCH 2.6.16] [Patch 9/9] Generic netlink interface for delay accounting
From: jamal @ 2006-03-25 17:48 UTC (permalink / raw)
  To: balbir; +Cc: Matt Helsley, Shailabh Nagar, linux-kernel, netdev
In-Reply-To: <20060325153632.GA25431@in.ibm.com>

On Sat, 2006-25-03 at 21:06 +0530, Balbir Singh wrote:
> On Sat, Mar 25, 2006 at 07:52:13AM -0500, jamal wrote:


I didnt pay attention to failure paths etc; i suppose your testing
should catch those. Getting there, a couple more comments:


> +enum {
> +	TASKSTATS_CMD_UNSPEC = 0,	/* Reserved */
> +	TASKSTATS_CMD_GET,		/* user->kernel request */
> +	TASKSTATS_CMD_NEW,		/* kernel->user event */

Should the comment read "kernel->user event/get-response"


> +
> +static int taskstats_send_stats(struct sk_buff *skb, struct genl_info *info)
> +{


> +
> +	if (info->attrs[TASKSTATS_CMD_ATTR_PID]) {
> +		u32 pid = nla_get_u32(info->attrs[TASKSTATS_CMD_ATTR_PID]);
> +		rc = fill_pid((pid_t)pid, NULL, &stats);
> +		if (rc < 0)
> +			goto err;
> +
> +		na = nla_nest_start(rep_skb, TASKSTATS_TYPE_AGGR_PID);
> +		NLA_PUT_U32(rep_skb, TASKSTATS_TYPE_PID, pid);
> +	} else if (info->attrs[TASKSTATS_CMD_ATTR_TGID]) {

in regards to the elseif above:
Could you not have both PID and TGID passed? From my earlier
understanding it seemed legit, no? if answer is yes, then you will have
to do your sizes + reply TLVs at the end.

Also in regards to the nesting, isnt there a need for nla_nest_cancel in
case of failures to add TLVs?

cheers,
jamal

^ permalink raw reply

* Re: [RFC][UPDATED PATCH 2.6.16] [Patch 9/9] Generic netlink interface for delay accounting
From: Balbir Singh @ 2006-03-25 18:22 UTC (permalink / raw)
  To: hadi; +Cc: Matt Helsley, Shailabh Nagar, linux-kernel, netdev
In-Reply-To: <1143308901.5184.48.camel@jzny2>

On 3/25/06, jamal <hadi@cyberus.ca> wrote:
> On Sat, 2006-25-03 at 21:06 +0530, Balbir Singh wrote:
> > On Sat, Mar 25, 2006 at 07:52:13AM -0500, jamal wrote:
>
>
> I didnt pay attention to failure paths etc; i suppose your testing
> should catch those. Getting there, a couple more comments:
>

Yes, I have tried several negative test cases.

>
> > +enum {
> > +     TASKSTATS_CMD_UNSPEC = 0,       /* Reserved */
> > +     TASKSTATS_CMD_GET,              /* user->kernel request */
> > +     TASKSTATS_CMD_NEW,              /* kernel->user event */
>
> Should the comment read "kernel->user event/get-response"
>

Yes, good catch. I will update the comment.

>
> > +
> > +static int taskstats_send_stats(struct sk_buff *skb, struct genl_info *info)
> > +{
>
>
> > +
> > +     if (info->attrs[TASKSTATS_CMD_ATTR_PID]) {
> > +             u32 pid = nla_get_u32(info->attrs[TASKSTATS_CMD_ATTR_PID]);
> > +             rc = fill_pid((pid_t)pid, NULL, &stats);
> > +             if (rc < 0)
> > +                     goto err;
> > +
> > +             na = nla_nest_start(rep_skb, TASKSTATS_TYPE_AGGR_PID);
> > +             NLA_PUT_U32(rep_skb, TASKSTATS_TYPE_PID, pid);
> > +     } else if (info->attrs[TASKSTATS_CMD_ATTR_TGID]) {
>
> in regards to the elseif above:
> Could you not have both PID and TGID passed? From my earlier
> understanding it seemed legit, no? if answer is yes, then you will have
> to do your sizes + reply TLVs at the end.

No, we cannot have both passed. If we pass both a PID and a TGID and
then the code returns just the stats for the PID.

>
> Also in regards to the nesting, isnt there a need for nla_nest_cancel in
> case of failures to add TLVs?
>

I thought about it, but when I looked at the code of genlmsg_cancel()
and nla_nest_cancel().  It seemed that genlmsg_cancel() should
suffice.

<snippet>
static inline int genlmsg_cancel(struct sk_buff *skb, void *hdr)
{
        return nlmsg_cancel(skb, hdr - GENL_HDRLEN - NLMSG_HDRLEN);
}

static inline int nlmsg_cancel(struct sk_buff *skb, struct nlmsghdr *nlh)
{
        skb_trim(skb, (unsigned char *) nlh - skb->data);

        return -1;
}

static inline int nla_nest_cancel(struct sk_buff *skb, struct nlattr *start)
{
        if (start)
                skb_trim(skb, (unsigned char *) start - skb->data);

        return -1;
}

</snippet>

genlmsg_cancel() seemed more generic, since it handles skb_trim from
the nlmsghdr down to skb->data, where as nla_test_cancel() does it
only from the start of the nested attributes to skb->data.

Is my understanding correct?


> cheers,
> jamal
>

Thanks,
Balbir

^ permalink raw reply

* [2.6 patch] make UNIX a bool
From: Adrian Bunk @ 2006-03-25 19:47 UTC (permalink / raw)
  To: Olaf Hering; +Cc: Andrew Morton, netdev, linux-kernel
In-Reply-To: <20060225224631.GA4085@suse.de>

On Sat, Feb 25, 2006 at 11:46:31PM +0100, Olaf Hering wrote:
>  On Sat, Feb 25, Adrian Bunk wrote:
> 
> > CONFIG_UNIX=m doesn't make much sense.
> 
> There is likely more code to support a modular unix.ko, this has to go
> as well.

Sounds resonable, updated patch below.

cu
Adrian


<--  snip  -->


CONFIG_UNIX=m doesn't make that much sense and requires us to export 
things we don't want to export to modules.

Signed-off-by: Adrian Bunk <bunk@stusta.de>

---

 fs/file_table.c            |    1 -
 include/net/af_unix.h      |    2 --
 net/unix/Kconfig           |    2 +-
 net/unix/af_unix.c         |   18 ------------------
 net/unix/sysctl_net_unix.c |    9 +--------
 5 files changed, 2 insertions(+), 30 deletions(-)

--- linux-2.6.16-mm1-full/net/unix/Kconfig.old	2006-03-25 20:10:47.000000000 +0100
+++ linux-2.6.16-mm1-full/net/unix/Kconfig	2006-03-25 20:10:54.000000000 +0100
@@ -3,7 +3,7 @@
 #
 
 config UNIX
-	tristate "Unix domain sockets"
+	bool "Unix domain sockets"
 	---help---
 	  If you say Y here, you will include support for Unix domain sockets;
 	  sockets are the standard Unix mechanism for establishing and
--- linux-2.6.16-mm1-full/include/net/af_unix.h.old	2006-03-25 20:13:33.000000000 +0100
+++ linux-2.6.16-mm1-full/include/net/af_unix.h	2006-03-25 20:13:40.000000000 +0100
@@ -85,10 +85,8 @@
 #ifdef CONFIG_SYSCTL
 extern int sysctl_unix_max_dgram_qlen;
 extern void unix_sysctl_register(void);
-extern void unix_sysctl_unregister(void);
 #else
 static inline void unix_sysctl_register(void) {}
-static inline void unix_sysctl_unregister(void) {}
 #endif
 #endif
 #endif
--- linux-2.6.16-mm1-full/net/unix/af_unix.c.old	2006-03-25 20:11:07.000000000 +0100
+++ linux-2.6.16-mm1-full/net/unix/af_unix.c	2006-03-25 20:14:05.000000000 +0100
@@ -475,7 +475,6 @@
 
 static const struct proto_ops unix_stream_ops = {
 	.family =	PF_UNIX,
-	.owner =	THIS_MODULE,
 	.release =	unix_release,
 	.bind =		unix_bind,
 	.connect =	unix_stream_connect,
@@ -496,7 +495,6 @@
 
 static const struct proto_ops unix_dgram_ops = {
 	.family =	PF_UNIX,
-	.owner =	THIS_MODULE,
 	.release =	unix_release,
 	.bind =		unix_bind,
 	.connect =	unix_dgram_connect,
@@ -517,7 +515,6 @@
 
 static const struct proto_ops unix_seqpacket_ops = {
 	.family =	PF_UNIX,
-	.owner =	THIS_MODULE,
 	.release =	unix_release,
 	.bind =		unix_bind,
 	.connect =	unix_stream_connect,
@@ -538,7 +535,6 @@
 
 static struct proto unix_proto = {
 	.name	  = "UNIX",
-	.owner	  = THIS_MODULE,
 	.obj_size = sizeof(struct unix_sock),
 };
 
@@ -2012,7 +2008,6 @@
 }
 
 static struct file_operations unix_seq_fops = {
-	.owner		= THIS_MODULE,
 	.open		= unix_seq_open,
 	.read		= seq_read,
 	.llseek		= seq_lseek,
@@ -2024,7 +2019,6 @@
 static struct net_proto_family unix_family_ops = {
 	.family = PF_UNIX,
 	.create = unix_create,
-	.owner	= THIS_MODULE,
 };
 
 static int __init af_unix_init(void)
@@ -2053,16 +2047,4 @@
 	return rc;
 }
 
-static void __exit af_unix_exit(void)
-{
-	sock_unregister(PF_UNIX);
-	unix_sysctl_unregister();
-	proc_net_remove("unix");
-	proto_unregister(&unix_proto);
-}
-
 module_init(af_unix_init);
-module_exit(af_unix_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_NETPROTO(PF_UNIX);
--- linux-2.6.16-mm1-full/net/unix/sysctl_net_unix.c.old	2006-03-25 20:14:10.000000000 +0100
+++ linux-2.6.16-mm1-full/net/unix/sysctl_net_unix.c	2006-03-25 20:15:21.000000000 +0100
@@ -46,15 +46,8 @@
 	{ .ctl_name = 0 }
 };
 
-static struct ctl_table_header * unix_sysctl_header;
-
 void unix_sysctl_register(void)
 {
-	unix_sysctl_header = register_sysctl_table(unix_root_table, 0);
-}
-
-void unix_sysctl_unregister(void)
-{
-	unregister_sysctl_table(unix_sysctl_header);
+	register_sysctl_table(unix_root_table, 0);
 }
 
--- linux-2.6.16-mm1-full/fs/file_table.c.old	2006-03-25 20:39:30.000000000 +0100
+++ linux-2.6.16-mm1-full/fs/file_table.c	2006-03-25 20:39:44.000000000 +0100
@@ -62,7 +62,6 @@
 {
 	return files_stat.max_files;
 }
-EXPORT_SYMBOL_GPL(get_max_files);
 
 /*
  * Handle nr_files sysctl

^ permalink raw reply

* [PATCH] acxsm: Reduce the number of ACX_PACKED instructions
From: Carlos Martin @ 2006-03-25 20:01 UTC (permalink / raw)
  To: netdev; +Cc: Denis Vlasenko, acx100-devel, Carlos Martin

Up to now, we were using ACX_PACKED after every field. I've finally
found out how to use only one at the end of each struct whilst
maintaining the typedef where it is now.

This should also apply to acx with a bit of fuzz, but I consider it to
be in maintenance mode, so this doesn't qualify for it.

Signed-off-by: Carlos Martin <carlos@cmartin.tk>

---

 acx_struct.h |  874 +++++++++++++++++++++++++++++-----------------------------
 common.c     |   26 +-
 ioctl.c      |   10 -
 usb.c        |    8 -
 4 files changed, 457 insertions(+), 461 deletions(-)

5fb2fdfd8c028a40921bbf9ef7ec4c53c03fcab4
diff --git a/acx_struct.h b/acx_struct.h
index 227b6e3..8c92302 100644
--- a/acx_struct.h
+++ b/acx_struct.h
@@ -522,9 +522,9 @@ DEF_IE(111_IE_DOT11_INVAL_1013,			0x1013
  * --vda
  */
 typedef struct phy_hdr {
-	u8	unknown[4] ACX_PACKED;
-	u8	acx111_unknown[4] ACX_PACKED;
-} phy_hdr_t;
+	u8	unknown[4];
+	u8	acx111_unknown[4];
+} ACX_PACKED phy_hdr_t;
 
 /* seems to be a bit similar to hfa384x_rx_frame.
  * These fields are still not quite obvious, though.
@@ -584,22 +584,22 @@ time: 4 bytes:
 */
 
 typedef struct rxbuffer {
-	u16	mac_cnt_rcvd ACX_PACKED;	/* only 12 bits are len! (0xfff) */
-	u8	mac_cnt_mblks ACX_PACKED;
-	u8	mac_status ACX_PACKED;
-	u8	phy_stat_baseband ACX_PACKED;	/* bit 0x80: used LNA (Low-Noise Amplifier) */
-	u8	phy_plcp_signal ACX_PACKED;
-	u8	phy_level ACX_PACKED;		/* PHY stat */
-	u8	phy_snr ACX_PACKED;		/* PHY stat */
-	u32	time ACX_PACKED;		/* timestamp upon MAC rcv first byte */
+	u16	mac_cnt_rcvd;	/* only 12 bits are len! (0xfff) */
+	u8	mac_cnt_mblks;
+	u8	mac_status;
+	u8	phy_stat_baseband;	/* bit 0x80: used LNA (Low-Noise Amplifier) */
+	u8	phy_plcp_signal;
+	u8	phy_level;		/* PHY stat */
+	u8	phy_snr;		/* PHY stat */
+	u32	time;		/* timestamp upon MAC rcv first byte */
 /* 4-byte (acx100) or 8-byte (acx111) phy header will be here
 ** if RX_CFG1_INCLUDE_PHY_HDR is in effect:
 **	phy_hdr_t phy			*/
-	wlan_hdr_a3_t hdr_a3 ACX_PACKED;
+	wlan_hdr_a3_t hdr_a3;
 	/* maximally sized data part of wlan packet */
-	u8	data_a3[WLAN_A4FR_MAXLEN_WEP_FCS - WLAN_HDR_A3_LEN] ACX_PACKED;
+	u8	data_a3[WLAN_A4FR_MAXLEN_WEP_FCS - WLAN_HDR_A3_LEN];
 	/* can add hdr/data_a4 if needed */
-} rxbuffer_t;
+} ACX_PACKED rxbuffer_t;
 
 
 /*--- Firmware statistics ----------------------------------------------------*/
@@ -609,93 +609,93 @@ typedef struct rxbuffer {
 #define FW_STATS_FUTURE_EXTENSION	100
 
 typedef struct fw_stats_tx {
-	u32	tx_desc_of ACX_PACKED;
-} fw_stats_tx_t;
+	u32	tx_desc_of;
+} ACX_PACKED fw_stats_tx_t;
 
 typedef struct fw_stats_rx {
-	u32	rx_oom ACX_PACKED;
-	u32	rx_hdr_of ACX_PACKED;
-	u32	rx_hw_stuck ACX_PACKED; /* old: u32	rx_hdr_use_next */
-	u32	rx_dropped_frame ACX_PACKED;
-	u32	rx_frame_ptr_err ACX_PACKED;
-	u32	rx_xfr_hint_trig ACX_PACKED;
-	u32	rx_aci_events ACX_PACKED; /* later versions only */
-	u32	rx_aci_resets ACX_PACKED; /* later versions only */
-} fw_stats_rx_t;
+	u32	rx_oom;
+	u32	rx_hdr_of;
+	u32	rx_hw_stuck; /* old: u32	rx_hdr_use_next */
+	u32	rx_dropped_frame;
+	u32	rx_frame_ptr_err;
+	u32	rx_xfr_hint_trig;
+	u32	rx_aci_events; /* later versions only */
+	u32	rx_aci_resets; /* later versions only */
+} ACX_PACKED fw_stats_rx_t;
 
 typedef struct fw_stats_dma {
-	u32	rx_dma_req ACX_PACKED;
-	u32	rx_dma_err ACX_PACKED;
-	u32	tx_dma_req ACX_PACKED;
-	u32	tx_dma_err ACX_PACKED;
-} fw_stats_dma_t;
+	u32	rx_dma_req;
+	u32	rx_dma_err;
+	u32	tx_dma_req;
+	u32	tx_dma_err;
+} ACX_PACKED fw_stats_dma_t;
 
 typedef struct fw_stats_irq {
-	u32	cmd_cplt ACX_PACKED;
-	u32	fiq ACX_PACKED;
-	u32	rx_hdrs ACX_PACKED;
-	u32	rx_cmplt ACX_PACKED;
-	u32	rx_mem_of ACX_PACKED;
-	u32	rx_rdys ACX_PACKED;
-	u32	irqs ACX_PACKED;
-	u32	tx_procs ACX_PACKED;
-	u32	decrypt_done ACX_PACKED;
-	u32	dma_0_done ACX_PACKED;
-	u32	dma_1_done ACX_PACKED;
-	u32	tx_exch_complet ACX_PACKED;
-	u32	commands ACX_PACKED;
-	u32	rx_procs ACX_PACKED;
-	u32	hw_pm_mode_changes ACX_PACKED;
-	u32	host_acks ACX_PACKED;
-	u32	pci_pm ACX_PACKED;
-	u32	acm_wakeups ACX_PACKED;
-} fw_stats_irq_t;
+	u32	cmd_cplt;
+	u32	fiq;
+	u32	rx_hdrs;
+	u32	rx_cmplt;
+	u32	rx_mem_of;
+	u32	rx_rdys;
+	u32	irqs;
+	u32	tx_procs;
+	u32	decrypt_done;
+	u32	dma_0_done;
+	u32	dma_1_done;
+	u32	tx_exch_complet;
+	u32	commands;
+	u32	rx_procs;
+	u32	hw_pm_mode_changes;
+	u32	host_acks;
+	u32	pci_pm;
+	u32	acm_wakeups;
+} ACX_PACKED fw_stats_irq_t;
 
 typedef struct fw_stats_wep {
-	u32	wep_key_count ACX_PACKED;
-	u32	wep_default_key_count ACX_PACKED;
-	u32	dot11_def_key_mib ACX_PACKED;
-	u32	wep_key_not_found ACX_PACKED;
-	u32	wep_decrypt_fail ACX_PACKED;
-	u32	wep_pkt_decrypt ACX_PACKED;
-	u32	wep_decrypt_irqs ACX_PACKED;
-} fw_stats_wep_t;
+	u32	wep_key_count;
+	u32	wep_default_key_count;
+	u32	dot11_def_key_mib;
+	u32	wep_key_not_found;
+	u32	wep_decrypt_fail;
+	u32	wep_pkt_decrypt;
+	u32	wep_decrypt_irqs;
+} ACX_PACKED fw_stats_wep_t;
 
 typedef struct fw_stats_pwr {
-	u32	tx_start_ctr ACX_PACKED;
-	u32	no_ps_tx_too_short ACX_PACKED;
-	u32	rx_start_ctr ACX_PACKED;
-	u32	no_ps_rx_too_short ACX_PACKED;
-	u32	lppd_started ACX_PACKED;
-	u32	no_lppd_too_noisy ACX_PACKED;
-	u32	no_lppd_too_short ACX_PACKED;
-	u32	no_lppd_matching_frame ACX_PACKED;
-} fw_stats_pwr_t;
+	u32	tx_start_ctr;
+	u32	no_ps_tx_too_short;
+	u32	rx_start_ctr;
+	u32	no_ps_rx_too_short;
+	u32	lppd_started;
+	u32	no_lppd_too_noisy;
+	u32	no_lppd_too_short;
+	u32	no_lppd_matching_frame;
+} ACX_PACKED fw_stats_pwr_t;
 
 typedef struct fw_stats_mic {
-	u32 mic_rx_pkts ACX_PACKED;
-	u32 mic_calc_fail ACX_PACKED;
-} fw_stats_mic_t;
+	u32 mic_rx_pkts;
+	u32 mic_calc_fail;
+} ACX_PACKED fw_stats_mic_t;
 
 typedef struct fw_stats_aes {
-	u32 aes_enc_fail ACX_PACKED;
-	u32 aes_dec_fail ACX_PACKED;
-	u32 aes_enc_pkts ACX_PACKED;
-	u32 aes_dec_pkts ACX_PACKED;
-	u32 aes_enc_irq ACX_PACKED;
-	u32 aes_dec_irq ACX_PACKED;
-} fw_stats_aes_t;
+	u32 aes_enc_fail;
+	u32 aes_dec_fail;
+	u32 aes_enc_pkts;
+	u32 aes_dec_pkts;
+	u32 aes_enc_irq;
+	u32 aes_dec_irq;
+} ACX_PACKED fw_stats_aes_t;
 
 typedef struct fw_stats_event {
-	u32 heartbeat ACX_PACKED;
-	u32 calibration ACX_PACKED;
-	u32 rx_mismatch ACX_PACKED;
-	u32 rx_mem_empty ACX_PACKED;
-	u32 rx_pool ACX_PACKED;
-	u32 oom_late ACX_PACKED;
-	u32 phy_tx_err ACX_PACKED;
-	u32 tx_stuck ACX_PACKED;
-} fw_stats_event_t;
+	u32 heartbeat;
+	u32 calibration;
+	u32 rx_mismatch;
+	u32 rx_mem_empty;
+	u32 rx_pool;
+	u32 oom_late;
+	u32 phy_tx_err;
+	u32 tx_stuck;
+} ACX_PACKED fw_stats_event_t;
 
 /* mainly for size calculation only */
 typedef struct fw_stats {
@@ -716,11 +716,11 @@ typedef struct fw_stats {
 /* Firmware version struct */
 
 typedef struct fw_ver {
-	u16	cmd ACX_PACKED;
-	u16	size ACX_PACKED;
-	char	fw_id[20] ACX_PACKED;
-	u32	hw_id ACX_PACKED;
-} fw_ver_t;
+	u16	cmd;
+	u16	size;
+	char	fw_id[20];
+	u32	hw_id;
+} ACX_PACKED fw_ver_t;
 
 #define FW_ID_SIZE 20
 
@@ -789,8 +789,8 @@ struct client {
  * Attempts to use acx_ptr without macros result in compile-time errors */
 
 typedef struct {
-	u32	v ACX_PACKED;
-} acx_ptr;
+	u32	v;
+} ACX_PACKED acx_ptr;
 
 #if ACX_DEBUG
 #define CHECK32(n) BUG_ON(sizeof(n)>4 && (long)(n)>0xffffff00)
@@ -892,59 +892,59 @@ typedef struct {
 /* Outside of "#ifdef PCI" because USB needs to know sizeof()
 ** of txdesc and rxdesc: */
 struct txdesc {
-	acx_ptr	pNextDesc ACX_PACKED;	/* pointer to next txdesc */
-	acx_ptr	HostMemPtr ACX_PACKED;			/* 0x04 */
-	acx_ptr	AcxMemPtr ACX_PACKED;			/* 0x08 */
-	u32	tx_time ACX_PACKED;			/* 0x0c */
-	u16	total_length ACX_PACKED;		/* 0x10 */
-	u16	Reserved ACX_PACKED;			/* 0x12 */
+	acx_ptr	pNextDesc;	/* pointer to next txdesc */
+	acx_ptr	HostMemPtr;			/* 0x04 */
+	acx_ptr	AcxMemPtr;			/* 0x08 */
+	u32	tx_time;			/* 0x0c */
+	u16	total_length;		/* 0x10 */
+	u16	Reserved;			/* 0x12 */
 
 /* The following 16 bytes do not change when acx100 owns the descriptor */
 /* BUG: fw clears last byte of this area which is supposedly reserved
 ** for driver use. amd64 blew up. We dare not use it now */
-	u32	dummy[4] ACX_PACKED;
+	u32	dummy[4];
 
-	u8	Ctl_8 ACX_PACKED;			/* 0x24, 8bit value */
-	u8	Ctl2_8 ACX_PACKED;			/* 0x25, 8bit value */
-	u8	error ACX_PACKED;			/* 0x26 */
-	u8	ack_failures ACX_PACKED;		/* 0x27 */
-	u8	rts_failures ACX_PACKED;		/* 0x28 */
-	u8	rts_ok ACX_PACKED;			/* 0x29 */
+	u8	Ctl_8;			/* 0x24, 8bit value */
+	u8	Ctl2_8;			/* 0x25, 8bit value */
+	u8	error;			/* 0x26 */
+	u8	ack_failures;		/* 0x27 */
+	u8	rts_failures;		/* 0x28 */
+	u8	rts_ok;			/* 0x29 */
 	union {
 		struct {
-			u8	rate ACX_PACKED;	/* 0x2a */
-			u8	queue_ctrl ACX_PACKED;	/* 0x2b */
-		} r1 ACX_PACKED;
+			u8	rate;	/* 0x2a */
+			u8	queue_ctrl;	/* 0x2b */
+		} ACX_PACKED r1;
 		struct {
-			u16	rate111 ACX_PACKED;	/* 0x2a */
-		} r2 ACX_PACKED;
-	} u ACX_PACKED;
-	u32	queue_info ACX_PACKED;			/* 0x2c (acx100, reserved on acx111) */
-};		/* size : 48 = 0x30 */
+			u16	rate111;	/* 0x2a */
+		} ACX_PACKED r2;
+	} u;
+	u32	queue_info;			/* 0x2c (acx100, reserved on acx111) */
+} ACX_PACKED;		/* size : 48 = 0x30 */
 /* NB: acx111 txdesc structure is 4 byte larger */
 /* All these 4 extra bytes are reserved. tx alloc code takes them into account */
 
 struct rxdesc {
-	acx_ptr	pNextDesc ACX_PACKED;			/* 0x00 */
-	acx_ptr	HostMemPtr ACX_PACKED;			/* 0x04 */
-	acx_ptr	ACXMemPtr ACX_PACKED;			/* 0x08 */
-	u32	rx_time ACX_PACKED;			/* 0x0c */
-	u16	total_length ACX_PACKED;		/* 0x10 */
-	u16	WEP_length ACX_PACKED;			/* 0x12 */
-	u32	WEP_ofs ACX_PACKED;			/* 0x14 */
+	acx_ptr	pNextDesc;			/* 0x00 */
+	acx_ptr	HostMemPtr;			/* 0x04 */
+	acx_ptr	ACXMemPtr;			/* 0x08 */
+	u32	rx_time;			/* 0x0c */
+	u16	total_length;		/* 0x10 */
+	u16	WEP_length;			/* 0x12 */
+	u32	WEP_ofs;			/* 0x14 */
 
 /* the following 16 bytes do not change when acx100 owns the descriptor */
-	u8	driverWorkspace[16] ACX_PACKED;		/* 0x18 */
+	u8	driverWorkspace[16];		/* 0x18 */
 
-	u8	Ctl_8 ACX_PACKED;
-	u8	rate ACX_PACKED;
-	u8	error ACX_PACKED;
-	u8	SNR ACX_PACKED;				/* Signal-to-Noise Ratio */
-	u8	RxLevel ACX_PACKED;
-	u8	queue_ctrl ACX_PACKED;
-	u16	unknown ACX_PACKED;
-	u32	unknown2 ACX_PACKED;
-};		/* size 52 = 0x34 */
+	u8	Ctl_8;
+	u8	rate;
+	u8	error;
+	u8	SNR;				/* Signal-to-Noise Ratio */
+	u8	RxLevel;
+	u8	queue_ctrl;
+	u16	unknown;
+	u32	unknown2;
+} ACX_PACKED;		/* size 52 = 0x34 */
 
 #ifdef ACX_PCI
 
@@ -1013,30 +1013,30 @@ enum {
 #define INT_TRIG_CMD		0x01
 
 struct txhostdesc {
-	acx_ptr	data_phy ACX_PACKED;			/* 0x00 [u8 *] */
-	u16	data_offset ACX_PACKED;			/* 0x04 */
-	u16	reserved ACX_PACKED;			/* 0x06 */
-	u16	Ctl_16 ACX_PACKED;	/* 16bit value, endianness!! */
-	u16	length ACX_PACKED;			/* 0x0a */
-	acx_ptr	desc_phy_next ACX_PACKED;		/* 0x0c [txhostdesc *] */
-	acx_ptr	pNext ACX_PACKED;			/* 0x10 [txhostdesc *] */
-	u32	Status ACX_PACKED;			/* 0x14, unused on Tx */
+	acx_ptr	data_phy;			/* 0x00 [u8 *] */
+	u16	data_offset;			/* 0x04 */
+	u16	reserved;			/* 0x06 */
+	u16	Ctl_16;	/* 16bit value, endianness!! */
+	u16	length;			/* 0x0a */
+	acx_ptr	desc_phy_next;		/* 0x0c [txhostdesc *] */
+	acx_ptr	pNext;			/* 0x10 [txhostdesc *] */
+	u32	Status;			/* 0x14, unused on Tx */
 /* From here on you can use this area as you want (variable length, too!) */
-	u8	*data ACX_PACKED;
-};
+	u8	*data;
+} ACX_PACKED;
 
 struct rxhostdesc {
-	acx_ptr	data_phy ACX_PACKED;			/* 0x00 [rxbuffer_t *] */
-	u16	data_offset ACX_PACKED;			/* 0x04 */
-	u16	reserved ACX_PACKED;			/* 0x06 */
-	u16	Ctl_16 ACX_PACKED;			/* 0x08; 16bit value, endianness!! */
-	u16	length ACX_PACKED;			/* 0x0a */
-	acx_ptr	desc_phy_next ACX_PACKED;		/* 0x0c [rxhostdesc_t *] */
-	acx_ptr	pNext ACX_PACKED;			/* 0x10 [rxhostdesc_t *] */
-	u32	Status ACX_PACKED;			/* 0x14 */
+	acx_ptr	data_phy;			/* 0x00 [rxbuffer_t *] */
+	u16	data_offset;			/* 0x04 */
+	u16	reserved;			/* 0x06 */
+	u16	Ctl_16;			/* 0x08; 16bit value, endianness!! */
+	u16	length;			/* 0x0a */
+	acx_ptr	desc_phy_next;		/* 0x0c [rxhostdesc_t *] */
+	acx_ptr	pNext;			/* 0x10 [rxhostdesc_t *] */
+	u32	Status;			/* 0x14 */
 /* From here on you can use this area as you want (variable length, too!) */
-	rxbuffer_t *data ACX_PACKED;
-};
+	rxbuffer_t *data;
+} ACX_PACKED;
 
 #endif /* ACX_PCI */
 
@@ -1050,30 +1050,30 @@ struct rxhostdesc {
 /* Size of header (everything up to data[]) */
 #define USB_TXBUF_HDRSIZE	14
 typedef struct usb_txbuffer {
-	u16	desc ACX_PACKED;
-	u16	mpdu_len ACX_PACKED;
-	u8	queue_index ACX_PACKED;
-	u8	rate ACX_PACKED;
-	u32	hostdata ACX_PACKED;
-	u8	ctrl1 ACX_PACKED;
-	u8	ctrl2 ACX_PACKED;
-	u16	data_len ACX_PACKED;
+	u16	desc;
+	u16	mpdu_len;
+	u8	queue_index;
+	u8	rate;
+	u32	hostdata;
+	u8	ctrl1;
+	u8	ctrl2;
+	u16	data_len;
 	/* wlan packet content is placed here: */
-	u8	data[WLAN_A4FR_MAXLEN_WEP_FCS] ACX_PACKED;
-} usb_txbuffer_t;
+	u8	data[WLAN_A4FR_MAXLEN_WEP_FCS];
+} ACX_PACKED usb_txbuffer_t;
 
 /* USB returns either rx packets (see rxbuffer) or
 ** these "tx status" structs: */
 typedef struct usb_txstatus {
-	u16	mac_cnt_rcvd ACX_PACKED;	/* only 12 bits are len! (0xfff) */
-	u8	queue_index ACX_PACKED;
-	u8	mac_status ACX_PACKED;		/* seen 0x20 on tx failure */
-	u32	hostdata ACX_PACKED;
-	u8	rate ACX_PACKED;
-	u8	ack_failures ACX_PACKED;
-	u8	rts_failures ACX_PACKED;
-	u8	rts_ok ACX_PACKED;
-} usb_txstatus_t;
+	u16	mac_cnt_rcvd;	/* only 12 bits are len! (0xfff) */
+	u8	queue_index;
+	u8	mac_status;		/* seen 0x20 on tx failure */
+	u32	hostdata;
+	u8	rate;
+	u8	ack_failures;
+	u8	rts_failures;
+	u8	rts_ok;
+} ACX_PACKED usb_txstatus_t;
 
 typedef struct usb_tx {
 	unsigned	busy:1;
@@ -1104,72 +1104,71 @@ typedef struct usb_rx {
 /* Config Option structs */
 
 typedef struct co_antennas {
-	u8	type ACX_PACKED;
-	u8	len ACX_PACKED;
-	u8	list[2] ACX_PACKED;
-} co_antennas_t;
+	u8	type;
+	u8	len;
+	u8	list[2];
+} ACX_PACKED co_antennas_t;
 
 typedef struct co_powerlevels {
-	u8	type ACX_PACKED;
-	u8	len ACX_PACKED;
-	u16	list[8] ACX_PACKED;
-} co_powerlevels_t;
+	u8	type;
+	u8	len;
+	u16	list[8];
+} ACX_PACKED co_powerlevels_t;
 
 typedef struct co_datarates {
-	u8	type ACX_PACKED;
-	u8	len ACX_PACKED;
-	u8	list[8] ACX_PACKED;
-} co_datarates_t;
+	u8	type;
+	u8	len;
+	u8	list[8];
+} ACX_PACKED co_datarates_t;
 
 typedef struct co_domains {
-	u8	type ACX_PACKED;
-	u8	len ACX_PACKED;
-	u8	list[6] ACX_PACKED;
-} co_domains_t;
+	u8	type;
+	u8	len;
+	u8	list[6];
+} ACX_PACKED co_domains_t;
 
 typedef struct co_product_id {
-	u8	type ACX_PACKED;
-	u8	len ACX_PACKED;
-	u8	list[128] ACX_PACKED;
-} co_product_id_t;
+	u8	type;
+	u8	len;
+	u8	list[128];
+} ACX_PACKED co_product_id_t;
 
 typedef struct co_manuf_id {
-	u8	type ACX_PACKED;
-	u8	len ACX_PACKED;
-	u8	list[128] ACX_PACKED;
-} co_manuf_t;
+	u8	type;
+	u8	len;
+	u8	list[128];
+} ACX_PACKED co_manuf_t;
 
 typedef struct co_fixed {
-	char	NVSv[8] ACX_PACKED;
+	char	NVSv[8];
 /*	u16	NVS_vendor_offs;	ACX111-only */
 /*	u16	unknown;		ACX111-only */
-	u8	MAC[6] ACX_PACKED;	/* ACX100-only */
-	u16	probe_delay ACX_PACKED;	/* ACX100-only */
-	u32	eof_memory ACX_PACKED;
-	u8	dot11CCAModes ACX_PACKED;
-	u8	dot11Diversity ACX_PACKED;
-	u8	dot11ShortPreambleOption ACX_PACKED;
-	u8	dot11PBCCOption ACX_PACKED;
-	u8	dot11ChannelAgility ACX_PACKED;
-	u8	dot11PhyType ACX_PACKED; /* FIXME: does 802.11 call it "dot11PHYType"? */
-	u8	dot11TempType ACX_PACKED;
-	u8	table_count ACX_PACKED;
-} co_fixed_t;
+	u8	MAC[6];	/* ACX100-only */
+	u16	probe_delay;	/* ACX100-only */
+	u32	eof_memory;
+	u8	dot11CCAModes;
+	u8	dot11Diversity;
+	u8	dot11ShortPreambleOption;
+	u8	dot11PBCCOption;
+	u8	dot11ChannelAgility;
+	u8	dot11PhyType; /* FIXME: does 802.11 call it "dot11PHYType"? */
+	u8	dot11TempType;
+	u8	table_count;
+} ACX_PACKED co_fixed_t;
 
 typedef struct acx111_ie_configoption {
-	u16			type ACX_PACKED;
-	u16			len ACX_PACKED;
+	u16			type;
+	u16			len;
 /* Do not access below members directly, they are in fact variable length */
-	co_fixed_t		fixed ACX_PACKED;
-	co_antennas_t		antennas ACX_PACKED;
-	co_powerlevels_t	power_levels ACX_PACKED;
-	co_datarates_t		data_rates ACX_PACKED;
-	co_domains_t		domains ACX_PACKED;
-	co_product_id_t		product_id ACX_PACKED;
-	co_manuf_t		manufacturer ACX_PACKED;
+	co_fixed_t		fixed;
+	co_antennas_t		antennas;
+	co_powerlevels_t	power_levels;
+	co_datarates_t		data_rates;
+	co_domains_t		domains;
+	co_product_id_t		product_id;
+	co_manuf_t		manufacturer;
 	u8			_padding[4];
-} acx111_ie_configoption_t;
-
+} ACX_PACKED acx111_ie_configoption_t;
 
 /***********************************************************************
 ** Main acx per-device data structure
@@ -1601,108 +1600,108 @@ ndev2adev(struct net_device *ndev)
 /***********************************************************************
 */
 typedef struct acx100_ie_memblocksize {
-	u16	type ACX_PACKED;
-	u16	len ACX_PACKED;
-	u16	size ACX_PACKED;
-} acx100_ie_memblocksize_t;
+	u16	type;
+	u16	len;
+	u16	size;
+} ACX_PACKED acx100_ie_memblocksize_t;
 
 typedef struct acx100_ie_queueconfig {
-	u16	type ACX_PACKED;
-	u16	len ACX_PACKED;
-	u32	AreaSize ACX_PACKED;
-	u32	RxQueueStart ACX_PACKED;
-	u8	QueueOptions ACX_PACKED;
-	u8	NumTxQueues ACX_PACKED;
-	u8	NumRxDesc ACX_PACKED;	 /* for USB only */
-	u8	pad1 ACX_PACKED;
-	u32	QueueEnd ACX_PACKED;
-	u32	HostQueueEnd ACX_PACKED; /* QueueEnd2 */
-	u32	TxQueueStart ACX_PACKED;
-	u8	TxQueuePri ACX_PACKED;
-	u8	NumTxDesc ACX_PACKED;
-	u16	pad2 ACX_PACKED;
-} acx100_ie_queueconfig_t;
+	u16	type;
+	u16	len;
+	u32	AreaSize;
+	u32	RxQueueStart;
+	u8	QueueOptions;
+	u8	NumTxQueues;
+	u8	NumRxDesc;	 /* for USB only */
+	u8	pad1;
+	u32	QueueEnd;
+	u32	HostQueueEnd; /* QueueEnd2 */
+	u32	TxQueueStart;
+	u8	TxQueuePri;
+	u8	NumTxDesc;
+	u16	pad2;
+} ACX_PACKED acx100_ie_queueconfig_t;
 
 typedef struct acx111_ie_queueconfig {
-	u16	type ACX_PACKED;
-	u16	len ACX_PACKED;
-	u32	tx_memory_block_address ACX_PACKED;
-	u32	rx_memory_block_address ACX_PACKED;
-	u32	rx1_queue_address ACX_PACKED;
-	u32	reserved1 ACX_PACKED;
-	u32	tx1_queue_address ACX_PACKED;
-	u8	tx1_attributes ACX_PACKED;
-	u16	reserved2 ACX_PACKED;
-	u8	reserved3 ACX_PACKED;
-} acx111_ie_queueconfig_t;
+	u16	type;
+	u16	len;
+	u32	tx_memory_block_address;
+	u32	rx_memory_block_address;
+	u32	rx1_queue_address;
+	u32	reserved1;
+	u32	tx1_queue_address;
+	u8	tx1_attributes;
+	u16	reserved2;
+	u8	reserved3;
+} ACX_PACKED acx111_ie_queueconfig_t;
 
 typedef struct acx100_ie_memconfigoption {
-	u16	type ACX_PACKED;
-	u16	len ACX_PACKED;
-	u32	DMA_config ACX_PACKED;
-	acx_ptr	pRxHostDesc ACX_PACKED;
-	u32	rx_mem ACX_PACKED;
-	u32	tx_mem ACX_PACKED;
-	u16	RxBlockNum ACX_PACKED;
-	u16	TxBlockNum ACX_PACKED;
-} acx100_ie_memconfigoption_t;
+	u16	type;
+	u16	len;
+	u32	DMA_config;
+	acx_ptr	pRxHostDesc;
+	u32	rx_mem;
+	u32	tx_mem;
+	u16	RxBlockNum;
+	u16	TxBlockNum;
+} ACX_PACKED acx100_ie_memconfigoption_t;
 
 typedef struct acx111_ie_memoryconfig {
-	u16	type ACX_PACKED;
-	u16	len ACX_PACKED;
-	u16	no_of_stations ACX_PACKED;
-	u16	memory_block_size ACX_PACKED;
-	u8	tx_rx_memory_block_allocation ACX_PACKED;
-	u8	count_rx_queues ACX_PACKED;
-	u8	count_tx_queues ACX_PACKED;
-	u8	options ACX_PACKED;
-	u8	fragmentation ACX_PACKED;
-	u16	reserved1 ACX_PACKED;
-	u8	reserved2 ACX_PACKED;
+	u16	type;
+	u16	len;
+	u16	no_of_stations;
+	u16	memory_block_size;
+	u8	tx_rx_memory_block_allocation;
+	u8	count_rx_queues;
+	u8	count_tx_queues;
+	u8	options;
+	u8	fragmentation;
+	u16	reserved1;
+	u8	reserved2;
 
 	/* start of rx1 block */
-	u8	rx_queue1_count_descs ACX_PACKED;
-	u8	rx_queue1_reserved1 ACX_PACKED;
-	u8	rx_queue1_type ACX_PACKED; /* must be set to 7 */
-	u8	rx_queue1_prio ACX_PACKED; /* must be set to 0 */
-	acx_ptr	rx_queue1_host_rx_start ACX_PACKED;
+	u8	rx_queue1_count_descs;
+	u8	rx_queue1_reserved1;
+	u8	rx_queue1_type; /* must be set to 7 */
+	u8	rx_queue1_prio; /* must be set to 0 */
+	acx_ptr	rx_queue1_host_rx_start;
 	/* end of rx1 block */
 
 	/* start of tx1 block */
-	u8	tx_queue1_count_descs ACX_PACKED;
-	u8	tx_queue1_reserved1 ACX_PACKED;
-	u8	tx_queue1_reserved2 ACX_PACKED;
-	u8	tx_queue1_attributes ACX_PACKED;
+	u8	tx_queue1_count_descs;
+	u8	tx_queue1_reserved1;
+	u8	tx_queue1_reserved2;
+	u8	tx_queue1_attributes;
 	/* end of tx1 block */
-} acx111_ie_memoryconfig_t;
+} ACX_PACKED acx111_ie_memoryconfig_t;
 
 typedef struct acx_ie_memmap {
-	u16	type ACX_PACKED;
-	u16	len ACX_PACKED;
-	u32	CodeStart ACX_PACKED;
-	u32	CodeEnd ACX_PACKED;
-	u32	WEPCacheStart ACX_PACKED;
-	u32	WEPCacheEnd ACX_PACKED;
-	u32	PacketTemplateStart ACX_PACKED;
-	u32	PacketTemplateEnd ACX_PACKED;
-	u32	QueueStart ACX_PACKED;
-	u32	QueueEnd ACX_PACKED;
-	u32	PoolStart ACX_PACKED;
-	u32	PoolEnd ACX_PACKED;
-} acx_ie_memmap_t;
+	u16	type;
+	u16	len;
+	u32	CodeStart;
+	u32	CodeEnd;
+	u32	WEPCacheStart;
+	u32	WEPCacheEnd;
+	u32	PacketTemplateStart;
+	u32	PacketTemplateEnd;
+	u32	QueueStart;
+	u32	QueueEnd;
+	u32	PoolStart;
+	u32	PoolEnd;
+} ACX_PACKED acx_ie_memmap_t;
 
 typedef struct acx111_ie_feature_config {
-	u16	type ACX_PACKED;
-	u16	len ACX_PACKED;
-	u32	feature_options ACX_PACKED;
-	u32	data_flow_options ACX_PACKED;
-} acx111_ie_feature_config_t;
+	u16	type;
+	u16	len;
+	u32	feature_options;
+	u32	data_flow_options;
+} ACX_PACKED acx111_ie_feature_config_t;
 
 typedef struct acx111_ie_tx_level {
-	u16	type ACX_PACKED;
-	u16	len ACX_PACKED;
-	u8	level ACX_PACKED;
-} acx111_ie_tx_level_t;
+	u16	type;
+	u16	len;
+	u8	level;
+} ACX_PACKED acx111_ie_tx_level_t;
 
 #define PS_CFG_ENABLE		0x80
 #define PS_CFG_PENDING		0x40 /* status flag when entering PS */
@@ -1719,25 +1718,25 @@ typedef struct acx111_ie_tx_level {
 #define PS_OPT_STILL_RCV_BCASTS	0x01
 
 typedef struct acx100_ie_powersave {
-	u16	type ACX_PACKED;
-	u16	len ACX_PACKED;
-	u8	wakeup_cfg ACX_PACKED;
-	u8	listen_interval ACX_PACKED; /* for EACH_ITVL: wake up every "beacon units" interval */
-	u8	options ACX_PACKED;
-	u8	hangover_period ACX_PACKED; /* remaining wake time after Tx MPDU w/ PS bit, in values of 1/1024 seconds */
-	u16	enhanced_ps_transition_time ACX_PACKED; /* rem. wake time for Enh. PS */
-} acx100_ie_powersave_t;
+	u16	type;
+	u16	len;
+	u8	wakeup_cfg;
+	u8	listen_interval; /* for EACH_ITVL: wake up every "beacon units" interval */
+	u8	options;
+	u8	hangover_period; /* remaining wake time after Tx MPDU w/ PS bit, in values of 1/1024 seconds */
+	u16	enhanced_ps_transition_time; /* rem. wake time for Enh. PS */
+} ACX_PACKED acx100_ie_powersave_t;
 
 typedef struct acx111_ie_powersave {
-	u16	type ACX_PACKED;
-	u16	len ACX_PACKED;
-	u8	wakeup_cfg ACX_PACKED;
-	u8	listen_interval ACX_PACKED; /* for EACH_ITVL: wake up every "beacon units" interval */
-	u8	options ACX_PACKED;
-	u8	hangover_period ACX_PACKED; /* remaining wake time after Tx MPDU w/ PS bit, in values of 1/1024 seconds */
-	u32	beacon_rx_time ACX_PACKED;
-	u32	enhanced_ps_transition_time ACX_PACKED; /* rem. wake time for Enh. PS */
-} acx111_ie_powersave_t;
+	u16	type;
+	u16	len;
+	u8	wakeup_cfg;
+	u8	listen_interval; /* for EACH_ITVL: wake up every "beacon units" interval */
+	u8	options;
+	u8	hangover_period; /* remaining wake time after Tx MPDU w/ PS bit, in values of 1/1024 seconds */
+	u32	beacon_rx_time;
+	u32	enhanced_ps_transition_time; /* rem. wake time for Enh. PS */
+} ACX_PACKED acx111_ie_powersave_t;
 
 
 /***********************************************************************
@@ -1764,14 +1763,14 @@ typedef struct acx111_ie_powersave {
 ** Background scan can be active or passive, just like normal one */
 #define ACX_SCAN_OPT_BACKGROUND	0x02
 typedef struct acx100_scan {
-	u16	count ACX_PACKED;	/* number of scans to do, 0xffff == continuous */
-	u16	start_chan ACX_PACKED;
-	u16	flags ACX_PACKED;	/* channel list mask; 0x8000 == all channels? */
-	u8	max_rate ACX_PACKED;	/* max. probe rate */
-	u8	options ACX_PACKED;	/* bit mask, see defines above */
-	u16	chan_duration ACX_PACKED;
-	u16	max_probe_delay ACX_PACKED;
-} acx100_scan_t;			/* length 0xc */
+	u16	count;	/* number of scans to do, 0xffff == continuous */
+	u16	start_chan;
+	u16	flags;	/* channel list mask; 0x8000 == all channels? */
+	u8	max_rate;	/* max. probe rate */
+	u8	options;	/* bit mask, see defines above */
+	u16	chan_duration;
+	u16	max_probe_delay;
+} ACX_PACKED acx100_scan_t; 			/* length 0xc */
 
 #define ACX111_SCAN_RATE_6	0x0B
 #define ACX111_SCAN_RATE_9	0x0F
@@ -1786,22 +1785,21 @@ typedef struct acx100_scan {
 #define ACX111_SCAN_MOD_PBCC	0x80
 #define ACX111_SCAN_MOD_OFDM	0x40
 typedef struct acx111_scan {
-	u16	count ACX_PACKED;		/* number of scans to do */
-	u8	channel_list_select ACX_PACKED; /* 0: scan all channels, 1: from chan_list only */
-	u16	reserved1 ACX_PACKED;
-	u8	reserved2 ACX_PACKED;
-	u8	rate ACX_PACKED;		/* rate for probe requests (if active scan) */
-	u8	options ACX_PACKED;		/* bit mask, see defines above */
-	u16	chan_duration ACX_PACKED;	/* min time to wait for reply on one channel (in TU) */
+	u16	count;		/* number of scans to do */
+	u8	channel_list_select; /* 0: scan all channels, 1: from chan_list only */
+	u16	reserved1;
+	u8	reserved2;
+	u8	rate;		/* rate for probe requests (if active scan) */
+	u8	options;		/* bit mask, see defines above */
+	u16	chan_duration;	/* min time to wait for reply on one channel (in TU) */
 						/* (active scan only) (802.11 section 11.1.3.2.2) */
-	u16	max_probe_delay ACX_PACKED;	/* max time to wait for reply on one channel (active scan) */
+	u16	max_probe_delay;	/* max time to wait for reply on one channel (active scan) */
 						/* time to listen on a channel (passive scan) */
-	u8	modulation ACX_PACKED;
-	u8	channel_list[26] ACX_PACKED;	/* bits 7:0 first byte: channels 8:1 */
+	u8	modulation;
+	u8	channel_list[26];	/* bits 7:0 first byte: channels 8:1 */
 						/* bits 7:0 second byte: channels 16:9 */
 						/* 26 bytes is enough to cover 802.11a */
-} acx111_scan_t;
-
+} ACX_PACKED acx111_scan_t;
 
 /*
 ** Radio calibration command structure
@@ -1810,10 +1808,9 @@ typedef struct acx111_cmd_radiocalib {
 /* 0x80000000 == automatic calibration by firmware, according to interval;
  * bits 0..3: select calibration methods to go through:
  * calib based on DC, AfeDC, Tx mismatch, Tx equilization */
-	u32	methods ACX_PACKED;
-	u32	interval ACX_PACKED;
-} acx111_cmd_radiocalib_t;
-
+	u32	methods;
+	u32	interval;
+} ACX_PACKED acx111_cmd_radiocalib_t;
 
 /*
 ** Packet template structures
@@ -1836,53 +1833,52 @@ typedef struct acx111_cmd_radiocalib {
 **   rest must be zero filled.
 ** - variable length fields shown only in comments */
 typedef struct acx_template_tim {
-	u16	size ACX_PACKED;
-	u8	tim_eid ACX_PACKED;	/* 00 1 TIM IE ID * */
-	u8	len ACX_PACKED;		/* 01 1 Length * */
-	u8	dtim_cnt ACX_PACKED;	/* 02 1 DTIM Count */
-	u8	dtim_period ACX_PACKED;	/* 03 1 DTIM Period */
-	u8	bitmap_ctrl ACX_PACKED;	/* 04 1 Bitmap Control * (except bit0) */
+	u16	size;
+	u8	tim_eid;	/* 00 1 TIM IE ID * */
+	u8	len;		/* 01 1 Length * */
+	u8	dtim_cnt;	/* 02 1 DTIM Count */
+	u8	dtim_period;	/* 03 1 DTIM Period */
+	u8	bitmap_ctrl;	/* 04 1 Bitmap Control * (except bit0) */
 					/* 05 n Partial Virtual Bitmap * */
-	u8	variable[0x100 - 1-1-1-1-1] ACX_PACKED;
-} acx_template_tim_t;
+	u8	variable[0x100 - 1-1-1-1-1];
+} ACX_PACKED acx_template_tim_t;
 
 typedef struct acx_template_probereq {
-	u16	size ACX_PACKED;
-	u16	fc ACX_PACKED;		/* 00 2 fc * */
-	u16	dur ACX_PACKED;		/* 02 2 Duration */
-	u8	da[6] ACX_PACKED;	/* 04 6 Destination Address * */
-	u8	sa[6] ACX_PACKED;	/* 0A 6 Source Address * */
-	u8	bssid[6] ACX_PACKED;	/* 10 6 BSSID * */
-	u16	seq ACX_PACKED;		/* 16 2 Sequence Control */
+	u16	size;
+	u16	fc;		/* 00 2 fc * */
+	u16	dur;		/* 02 2 Duration */
+	u8	da[6];	/* 04 6 Destination Address * */
+	u8	sa[6];	/* 0A 6 Source Address * */
+	u8	bssid[6];	/* 10 6 BSSID * */
+	u16	seq;		/* 16 2 Sequence Control */
 					/* 18 n SSID * */
 					/* nn n Supported Rates * */
-	u8	variable[0x44 - 2-2-6-6-6-2] ACX_PACKED;
-} acx_template_probereq_t;
+	u8	variable[0x44 - 2-2-6-6-6-2];
+} ACX_PACKED acx_template_probereq_t;
 
 typedef struct acx_template_proberesp {
-	u16	size ACX_PACKED;
-	u16	fc ACX_PACKED;		/* 00 2 fc * (bits [15:12] and [10:8] per 802.11 section 7.1.3.1) */
-	u16	dur ACX_PACKED;		/* 02 2 Duration */
-	u8	da[6] ACX_PACKED;	/* 04 6 Destination Address */
-	u8	sa[6] ACX_PACKED;	/* 0A 6 Source Address */
-	u8	bssid[6] ACX_PACKED;	/* 10 6 BSSID */
-	u16	seq ACX_PACKED;		/* 16 2 Sequence Control */
-	u8	timestamp[8] ACX_PACKED;/* 18 8 Timestamp */
-	u16	beacon_interval ACX_PACKED; /* 20 2 Beacon Interval * */
-	u16	cap ACX_PACKED;		/* 22 2 Capability Information * */
+	u16	size;
+	u16	fc;		/* 00 2 fc * (bits [15:12] and [10:8] per 802.11 section 7.1.3.1) */
+	u16	dur;		/* 02 2 Duration */
+	u8	da[6];	/* 04 6 Destination Address */
+	u8	sa[6];	/* 0A 6 Source Address */
+	u8	bssid[6];	/* 10 6 BSSID */
+	u16	seq;		/* 16 2 Sequence Control */
+	u8	timestamp[8];/* 18 8 Timestamp */
+	u16	beacon_interval; /* 20 2 Beacon Interval * */
+	u16	cap;		/* 22 2 Capability Information * */
 					/* 24 n SSID * */
 					/* nn n Supported Rates * */
 					/* nn 1 DS Parameter Set * */
-	u8	variable[0x54 - 2-2-6-6-6-2-8-2-2] ACX_PACKED;
-} acx_template_proberesp_t;
+	u8	variable[0x54 - 2-2-6-6-6-2-8-2-2];
+} ACX_PACKED acx_template_proberesp_t;
 #define acx_template_beacon_t acx_template_proberesp_t
 #define acx_template_beacon acx_template_proberesp
 
 typedef struct acx_template_nullframe {
-	u16	size ACX_PACKED;
-	struct wlan_hdr_a3 hdr ACX_PACKED;
-} acx_template_nullframe_t;
-
+	u16	size;
+	struct wlan_hdr_a3 hdr;
+} ACX_PACKED acx_template_nullframe_t;
 
 /*
 ** JOIN command structure
@@ -1890,28 +1886,28 @@ typedef struct acx_template_nullframe {
 ** as opposed to acx100, acx111 dtim interval is AFTER rates_basic111.
 ** NOTE: took me about an hour to get !@#$%^& packing right --> struct packing is eeeeevil... */
 typedef struct acx_joinbss {
-	u8	bssid[ETH_ALEN] ACX_PACKED;
-	u16	beacon_interval ACX_PACKED;
+	u8	bssid[ETH_ALEN];
+	u16	beacon_interval;
 	union {
 		struct {
-			u8	dtim_interval ACX_PACKED;
-			u8	rates_basic ACX_PACKED;
-			u8	rates_supported ACX_PACKED;
-		} acx100 ACX_PACKED;
+			u8	dtim_interval;
+			u8	rates_basic;
+			u8	rates_supported;
+		} ACX_PACKED acx100;
 		struct {
-			u16	rates_basic ACX_PACKED;
-			u8	dtim_interval ACX_PACKED;
-		} acx111 ACX_PACKED;
-	} u ACX_PACKED;
-	u8	genfrm_txrate ACX_PACKED;	/* generated frame (bcn, proberesp, RTS, PSpoll) tx rate */
-	u8	genfrm_mod_pre ACX_PACKED;	/* generated frame modulation/preamble:
+			u16	rates_basic;
+			u8	dtim_interval;
+		} ACX_PACKED acx111;
+	} u;
+	u8	genfrm_txrate;	/* generated frame (bcn, proberesp, RTS, PSpoll) tx rate */
+	u8	genfrm_mod_pre;	/* generated frame modulation/preamble:
 						** bit7: PBCC, bit6: OFDM (else CCK/DQPSK/DBPSK)
 						** bit5: short pre */
-	u8	macmode ACX_PACKED;	/* BSS Type, must be one of ACX_MODE_xxx */
-	u8	channel ACX_PACKED;
-	u8	essid_len ACX_PACKED;
-	char	essid[IW_ESSID_MAX_SIZE] ACX_PACKED;
-} acx_joinbss_t;
+	u8	macmode;	/* BSS Type, must be one of ACX_MODE_xxx */
+	u8	channel;
+	u8	essid_len;
+	char	essid[IW_ESSID_MAX_SIZE];
+} ACX_PACKED acx_joinbss_t;
 
 #define JOINBSS_RATES_1		0x01
 #define JOINBSS_RATES_2		0x02
@@ -1942,64 +1938,64 @@ typedef struct acx_joinbss {
 /***********************************************************************
 */
 typedef struct mem_read_write {
-	u16	addr ACX_PACKED;
-	u16	type ACX_PACKED; /* 0x0 int. RAM / 0xffff MAC reg. / 0x81 PHY RAM / 0x82 PHY reg.; or maybe it's actually 0x30 for MAC? Better verify it by writing and reading back and checking whether the value holds! */
-	u32	len ACX_PACKED;
-	u32	data ACX_PACKED;
-} mem_read_write_t;
+	u16	addr;
+	u16	type; /* 0x0 int. RAM / 0xffff MAC reg. / 0x81 PHY RAM / 0x82 PHY reg.; or maybe it's actually 0x30 for MAC? Better verify it by writing and reading back and checking whether the value holds! */
+	u32	len;
+	u32	data;
+} ACX_PACKED mem_read_write_t;
 
 typedef struct firmware_image {
-	u32	chksum ACX_PACKED;
-	u32	size ACX_PACKED;
-	u8	data[1] ACX_PACKED; /* the byte array of the actual firmware... */
-} firmware_image_t;
+	u32	chksum;
+	u32	size;
+	u8	data[1]; /* the byte array of the actual firmware... */
+} ACX_PACKED firmware_image_t;
 
 typedef struct acx_cmd_radioinit {
-	u32	offset ACX_PACKED;
-	u32	len ACX_PACKED;
-} acx_cmd_radioinit_t;
+	u32	offset;
+	u32	len;
+} ACX_PACKED acx_cmd_radioinit_t;
 
 typedef struct acx100_ie_wep_options {
-	u16	type ACX_PACKED;
-	u16	len ACX_PACKED;
-	u16	NumKeys ACX_PACKED;	/* max # of keys */
-	u8	WEPOption ACX_PACKED;	/* 0 == decrypt default key only, 1 == override decrypt */
-	u8	Pad ACX_PACKED;		/* used only for acx111 */
-} acx100_ie_wep_options_t;
+	u16	type;
+	u16	len;
+	u16	NumKeys;	/* max # of keys */
+	u8	WEPOption;	/* 0 == decrypt default key only, 1 == override decrypt */
+	u8	Pad;		/* used only for acx111 */
+} ACX_PACKED acx100_ie_wep_options_t;
 
 typedef struct ie_dot11WEPDefaultKey {
-	u16	type ACX_PACKED;
-	u16	len ACX_PACKED;
-	u8	action ACX_PACKED;
-	u8	keySize ACX_PACKED;
-	u8	defaultKeyNum ACX_PACKED;
-	u8	key[29] ACX_PACKED;	/* check this! was Key[19] */
-} ie_dot11WEPDefaultKey_t;
+	u16	type;
+	u16	len;
+	u8	action;
+	u8	keySize;
+	u8	defaultKeyNum;
+	u8	key[29];	/* check this! was Key[19] */
+} ACX_PACKED ie_dot11WEPDefaultKey_t;
 
 typedef struct acx111WEPDefaultKey {
-	u8	MacAddr[ETH_ALEN] ACX_PACKED;
-	u16	action ACX_PACKED;	/* NOTE: this is a u16, NOT a u8!! */
-	u16	reserved ACX_PACKED;
-	u8	keySize ACX_PACKED;
-	u8	type ACX_PACKED;
-	u8	index ACX_PACKED;
-	u8	defaultKeyNum ACX_PACKED;
-	u8	counter[6] ACX_PACKED;
-	u8	key[32] ACX_PACKED;	/* up to 32 bytes (for TKIP!) */
-} acx111WEPDefaultKey_t;
+	u8	MacAddr[ETH_ALEN];
+	u16	action;	/* NOTE: this is a u16, NOT a u8!! */
+	u16	reserved;
+	u8	keySize;
+	u8	type;
+	u8	index;
+	u8	defaultKeyNum;
+	u8	counter[6];
+	u8	key[32];	/* up to 32 bytes (for TKIP!) */
+} ACX_PACKED acx111WEPDefaultKey_t;
 
 typedef struct ie_dot11WEPDefaultKeyID {
-	u16	type ACX_PACKED;
-	u16	len ACX_PACKED;
-	u8	KeyID ACX_PACKED;
-} ie_dot11WEPDefaultKeyID_t;
+	u16	type;
+	u16	len;
+	u8	KeyID;
+} ACX_PACKED ie_dot11WEPDefaultKeyID_t;
 
 typedef struct acx100_cmd_wep_mgmt {
-	u8	MacAddr[ETH_ALEN] ACX_PACKED;
-	u16	Action ACX_PACKED;
-	u16	KeySize ACX_PACKED;
-	u8	Key[29] ACX_PACKED; /* 29*8 == 232bits == WEP256 */
-} acx100_cmd_wep_mgmt_t;
+	u8	MacAddr[ETH_ALEN];
+	u16	Action;
+	u16	KeySize;
+	u8	Key[29]; /* 29*8 == 232bits == WEP256 */
+} ACX_PACKED acx100_cmd_wep_mgmt_t;
 
 /* UNUSED?
 typedef struct defaultkey {
@@ -2008,17 +2004,17 @@ typedef struct defaultkey {
 */
 
 typedef struct acx_ie_generic {
-	u16	type ACX_PACKED;
-	u16	len ACX_PACKED;
+	u16	type;
+	u16	len;
 	union {
 		/* struct wep wp ACX_PACKED; */
 		/* Association ID IE: just a 16bit value: */
 		u16	aid;
 		/* UNUSED? struct defaultkey dkey ACX_PACKED; */
 		/* generic member for quick implementation of commands */
-		u8	bytes[32] ACX_PACKED;
-	} m ACX_PACKED;
-} acx_ie_generic_t;
+		u8	bytes[32];
+	} m;
+} ACX_PACKED acx_ie_generic_t;
 
 /***********************************************************************
 */
diff --git a/common.c b/common.c
index 623e70d..ff6152d 100644
--- a/common.c
+++ b/common.c
@@ -1097,11 +1097,11 @@ void
 great_inquisitor(acx_device_t *adev)
 {
 	static struct {
-		u16	type ACX_PACKED;
-		u16	len ACX_PACKED;
+		u16	type;
+		u16	len;
 		/* 0x200 was too large here: */
-		u8	data[0x100 - 4] ACX_PACKED;
-	} ie;
+		u8	data[0x100 - 4];
+	} ACX_PACKED ie;
 	u16 type;
 
 	FN_ENTER;
@@ -2341,11 +2341,11 @@ static void
 acx_s_initialize_rx_config(acx_device_t *adev)
 {
 	struct {
-		u16	id ACX_PACKED;
-		u16	len ACX_PACKED;
-		u16	rx_cfg1 ACX_PACKED;
-		u16	rx_cfg2 ACX_PACKED;
-	} cfg;
+		u16	id;
+		u16	len;
+		u16	rx_cfg1;
+		u16	rx_cfg2;
+	} ACX_PACKED cfg;
 
 	switch (adev->mode) {
 	case ACX_MODE_OFF:
@@ -6941,10 +6941,10 @@ acx_s_update_card_settings(acx_device_t 
 		ie_dot11WEPDefaultKeyID_t dkey;
 #ifdef DEBUG_WEP
 		struct {
-			u16 type ACX_PACKED;
-			u16 len ACX_PACKED;
-			u8  val ACX_PACKED;
-		} keyindic;
+			u16 type;
+			u16 len;
+			u8  val;
+		} ACX_PACKED keyindic;
 #endif
 		log(L_INIT, "updating WEP key settings\n");
 
diff --git a/ioctl.c b/ioctl.c
index 6c548ca..ca3c42e 100644
--- a/ioctl.c
+++ b/ioctl.c
@@ -2168,11 +2168,11 @@ acx_ioctl_get_phy_chan_busy_percentage(
 {
 	acx_device_t *adev = ndev2adev(ndev);
 	struct { /* added ACX_PACKED, not tested --vda */
-		u16 type ACX_PACKED;
-		u16 len ACX_PACKED;
-		u32 busytime ACX_PACKED;
-		u32 totaltime ACX_PACKED;
-	} usage;
+		u16 type;
+		u16 len;
+		u32 busytime;
+		u32 totaltime;
+	} ACX_PACKED usage;
 	int result;
 
 	acx_sem_lock(adev);
diff --git a/usb.c b/usb.c
index 5833d04..51290ed 100644
--- a/usb.c
+++ b/usb.c
@@ -305,10 +305,10 @@ acxusb_s_issue_cmd_timeo_debug(
 
 	struct usb_device *usbdev;
 	struct {
-		u16	cmd ACX_PACKED;
-		u16	status ACX_PACKED;
-		u8	data[1] ACX_PACKED;
-	} *loc;
+		u16	cmd;
+		u16	status;
+		u8	data[1];
+	} ACX_PACKED *loc;
 	const char *devname;
 	int acklen, blocklen, inpipe, outpipe;
 	int cmd_status;
-- 
1.2.4.g3103




-------------------------------------------------------
This SF.Net email is sponsored by xPML, a groundbreaking scripting language
that extends applications into web and mobile media. Attend the live webcast
and join the prime developer group breaking into this new coding territory!
http://sel.as-us.falkag.net/sel?cmd=lnk&kid\x110944&bid$1720&dat\x121642

^ permalink raw reply related

* Re: [2.6.16-gitX] heavy performance regression in ipw2200 wireless driver
From: Alessandro Suardi @ 2006-03-25 22:48 UTC (permalink / raw)
  To: Zhu Yi; +Cc: Andrew Morton, linux-kernel, James Ketrenos, netdev
In-Reply-To: <1143171674.17270.195.camel@debian.sh.intel.com>

On 3/24/06, Zhu Yi <yi.zhu@intel.com> wrote:
> On Thu, 2006-03-23 at 15:02 +0100, Alessandro Suardi wrote:
> > That scp test shows 50%ish - but that was a quickie. The VNC
> >  client even reported a 719Kbps throughput down from the more
> >  usual 11500Kbps it starts off with. The first scp I tried when the
> >  sluggishness was intolerable was going at 200KB/s - which
> >  shows the problem can easily get in the neighborhood of an
> >  order of magnitude.
>
> What kind of wireless encryption do you use? We turned off hardware
> encryption by default recently as a workaround for a firmware restart
> bug. You might want to load module with "modprobe ipw2200 hwcrypto=1"
> and retest.

The issue seems to have vanished in more recent kernel snapshots
 (namely, 2.6.16-git3 and -git5 exhibited the problem; -git8 and -git9
 did not).

I will holler if the problem pops up again... thanks,

--alessandro

 "Dreamer ? Each one of us is a dreamer. We just push it down deep because
   we are repeatedly told that we are not allowed to dream in real life"
     (Reinhold Ziegler)

^ permalink raw reply

* [KJ][Patch] fix array overflows in de4x5.c
From: Darren Jenkins\ @ 2006-03-26  6:45 UTC (permalink / raw)
  To: kernel Janitors; +Cc: NetDev

[-- Attachment #1: Type: text/plain, Size: 1872 bytes --]

G'day list

Coverity found 3 'OVERRUN_STATIC' in de4x5.c, @ lines 4814, 5115 and
5125.

Looking at the code these look like very minor problems, but as they are
easy to fix I though I would do a patch.

The patch below just adds an explicit check for the array index in
type3_infoblock() and corrects a loop exit check, to eliminate an 
(array+1) error in mii_get_phy().

Note: A better solution in type3_infoblock() may be to change 
- #define MOTO_SROM_BUG    ((lp->active == 8) && (((le32_to_cpu(get_unaligned(((s32 *)dev->dev_addr))))&0x00ffffff)==0x3e0008))
+ #define MOTO_SROM_BUG    ((lp->active >= DE4X5_MAX_PHY) || (((le32_to_cpu(get_unaligned(((s32 *)dev->dev_addr))))&0x00ffffff)==0x3e0008

as this seems to make sense, but as i am not sure that this bug happens
when (lp->active < 8) I am reluctant to change this.



Signed-off-by: Darren Jenkins <darrenrjenkins@gmail.com>

--- linux-2.6.16-git8/drivers/net/tulip/de4x5.c.orig	2006-03-26 14:36:17.000000000 +1100
+++ linux-2.6.16-git8/drivers/net/tulip/de4x5.c	2006-03-26 17:06:06.000000000 +1100
@@ -4810,7 +4810,8 @@ type3_infoblock(struct net_device *dev, 
     if (lp->state == INITIALISED) {
         lp->ibn = 3;
         lp->active = *p++;
-	if (MOTO_SROM_BUG) lp->active = 0;
+	if (MOTO_SROM_BUG || lp->active >= DE4X5_MAX_PHY)
+		lp->active = 0;
 	lp->phy[lp->active].gep = (*p ? p : NULL); p += (2 * (*p) + 1);
 	lp->phy[lp->active].rst = (*p ? p : NULL); p += (2 * (*p) + 1);
 	lp->phy[lp->active].mc  = TWIDDLE(p); p += 2;
@@ -5111,7 +5112,7 @@ mii_get_phy(struct net_device *dev)
 	    break;
 	}
 	if ((j == limit) && (i < DE4X5_MAX_MII)) {
-	    for (k=0; lp->phy[k].id && (k < DE4X5_MAX_PHY); k++);
+	    for (k=0; lp->phy[k].id && (k < DE4X5_MAX_PHY - 1); k++);
 	    lp->phy[k].addr = i;
 	    lp->phy[k].id = id;
 	    lp->phy[k].spd.reg = GENERIC_REG;      /* ANLPA register         */



[-- Attachment #2: Type: text/plain, Size: 168 bytes --]

_______________________________________________
Kernel-janitors mailing list
Kernel-janitors@lists.osdl.org
https://lists.osdl.org/mailman/listinfo/kernel-janitors

^ permalink raw reply

* [2.6 patch] net: drop duplicate assignment in request_sock
From: Adrian Bunk @ 2006-03-26 12:24 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Norbert Kiesel, acme, linux-kernel, netdev

From: Norbert Kiesel <nkiesel@tbdnetworks.com>

Just noticed that request_sock.[ch] contain a useless assignment of
rskq_accept_head to itself.  I assume this is a typo and the 2nd one
was supposed to be _tail.  However, setting _tail to NULL is not
needed, so the patch below just drops the 2nd assignment.

Signed-Off-By: Norbert Kiesel <nkiesel@tbdnetworks.com>
Signed-off-by: Adrian Bunk <bunk@stusta.de>

---

This patch was sent by Norbert Kiesel on:
-  5 Mar 2006

diff -ru a/include/net/request_sock.h b/include/net/request_sock.h
--- a/include/net/request_sock.h	2005-10-28 15:44:45.000000000 -0700
+++ b/include/net/request_sock.h	2006-03-05 15:22:33.000000000 -0800
@@ -145,7 +145,7 @@
 {
 	struct request_sock *req = queue->rskq_accept_head;
 
-	queue->rskq_accept_head = queue->rskq_accept_head = NULL;
+	queue->rskq_accept_head = NULL;
 	return req;
 }
 
diff -ru a/net/core/request_sock.c b/net/core/request_sock.c
--- a/net/core/request_sock.c	2006-03-05 14:40:50.000000000 -0800
+++ b/net/core/request_sock.c	2006-03-05 15:23:11.000000000 -0800
@@ -51,7 +51,7 @@
 
 	get_random_bytes(&lopt->hash_rnd, sizeof(lopt->hash_rnd));
 	rwlock_init(&queue->syn_wait_lock);
-	queue->rskq_accept_head = queue->rskq_accept_head = NULL;
+	queue->rskq_accept_head = NULL;
 	lopt->nr_table_entries = nr_table_entries;
 
 	write_lock_bh(&queue->syn_wait_lock);

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox