* [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
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox