* [PATCH 2/2]: e1000 disable device on PCI error
From: Linas Vepstas @ 2006-06-29 20:11 UTC (permalink / raw)
To: Jesse Brandeburg, Rajesh Shah, Ronciak, John, Grant Grundler,
bibo,mao
Cc: linux-kernel, linux-pci, netdev, akpm
In-Reply-To: <20060629200644.GA29526@austin.ibm.com>
Same as last patch, but for the e1000 gigabit card.
A recent patch in -mm3 titled
"gregkh-pci-pci-don-t-enable-device-if-already-enabled.patch"
causes pci_enable_device() to be a no-op if the kernel thinks
that the device is already enabled. This change breaks the
PCI error recovery mechanism in the e1000 device driver, since,
after PCI slot reset, the card is no longer enabled. This is
a trivial fix for this problem. Tested.
Please submit uptream.
Signed-off-by: Linas Vepstas <linas@austin.ibm.com>
----
drivers/net/e1000/e1000_main.c | 1 +
1 file changed, 1 insertion(+)
Index: linux-2.6.17-mm3/drivers/net/e1000/e1000_main.c
===================================================================
--- linux-2.6.17-mm3.orig/drivers/net/e1000/e1000_main.c 2006-06-27 12:30:02.000000000 -0500
+++ linux-2.6.17-mm3/drivers/net/e1000/e1000_main.c 2006-06-29 14:52:29.000000000 -0500
@@ -4640,6 +4640,7 @@ static pci_ers_result_t e1000_io_error_d
if (netif_running(netdev))
e1000_down(adapter);
+ pci_disable_device(pdev);
/* Request a slot slot reset. */
return PCI_ERS_RESULT_NEED_RESET;
^ permalink raw reply
* Re: RDMA will be reverted
From: Tom Tucker @ 2006-06-29 20:16 UTC (permalink / raw)
To: David Miller; +Cc: rdreier, netdev, akpm
In-Reply-To: <1151611866.11739.57.camel@trinity.ogc.int>
[...snip...]
> community at large, Linux and Andrew, you? I'm not trying to be
Linus sorry... spell checker...
^ permalink raw reply
* Re: RDMA will be reverted
From: David Miller @ 2006-06-29 20:19 UTC (permalink / raw)
To: tom; +Cc: rdreier, netdev, akpm
In-Reply-To: <1151611866.11739.57.camel@trinity.ogc.int>
From: Tom Tucker <tom@opengridcomputing.com>
Date: Thu, 29 Jun 2006 15:11:06 -0500
> Doesn't this position force vendors to build deeper adapters, not
> shallower adapters? Isn't this exactly the opposite of what is intended?
Nope.
Look at what the networking developers give a lot of attention and
effort to, things like TCP Large Receive Offload, and Van Jacobson net
channels, both of which are fully stack integrated receive performance
enhancements. They do not bypass netfilter, they do not bypass
packet scheduling, and yet they provide a hardware assist performance
improvement for receive.
This has been stated over and over again.
If companies keep designing undesirable hardware that unnecessarily
takes features away from the user, that really is not our problem.
^ permalink raw reply
* Re: Subject: [PATCH 1/2]: e100 disable device on PCI error
From: Auke Kok @ 2006-06-29 20:19 UTC (permalink / raw)
To: Linas Vepstas
Cc: Jesse Brandeburg, Rajesh Shah, Ronciak, John, Grant Grundler,
bibo,mao, linux-kernel, linux-pci, netdev, akpm
In-Reply-To: <20060629200644.GA29526@austin.ibm.com>
Linas Vepstas wrote:
> A recent patch in -mm3 titled
> "gregkh-pci-pci-don-t-enable-device-if-already-enabled.patch"
> causes pci_enable_device() to be a no-op if the kernel thinks
> that the device is already enabled. This change breaks the
> PCI error recovery mechanism in the e100 device driver, since,
> after PCI slot reset, the card is no longer enabled. This is
> a trivial fix for this problem. Tested.
>
> Please submit uptream.
Ack!
I'm preparing a set of e100 patches at the moment, and will include this one
with them.
Cheers,
Auke
>
> Signed-off-by: Linas Vepstas <linas@austin.ibm.com>
>
> ----
> drivers/net/e100.c | 1 +
> 1 file changed, 1 insertion(+)
>
> Index: linux-2.6.17-mm3/drivers/net/e100.c
> ===================================================================
> --- linux-2.6.17-mm3.orig/drivers/net/e100.c 2006-06-27 11:39:08.000000000 -0500
> +++ linux-2.6.17-mm3/drivers/net/e100.c 2006-06-29 14:18:40.000000000 -0500
> @@ -2742,6 +2742,7 @@ static pci_ers_result_t e100_io_error_de
> /* Detach; put netif into state similar to hotplug unplug. */
> netif_poll_enable(netdev);
> netif_device_detach(netdev);
> + pci_disable_device(pdev);
>
> /* Request a slot reset. */
> return PCI_ERS_RESULT_NEED_RESET;
> -
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: 2.6.17-mm4
From: Michal Piotrowski @ 2006-06-29 20:39 UTC (permalink / raw)
To: Andrew Morton; +Cc: linux-kernel, netdev
In-Reply-To: <20060629013643.4b47e8bd.akpm@osdl.org>
Hi,
On 29/06/06, Andrew Morton <akpm@osdl.org> wrote:
>
> ftp://ftp.kernel.org/pub/linux/kernel/people/akpm/patches/2.6/2.6.17/2.6.17-mm4/
>
>
This looks very strange.
BUG: unable to handle kernel paging request at virtual address 6b6b6c07
printing eip:
c0138594
*pde=00000000
Oops: 0002 [#1]
4K_STACK PREEMPT SMP
last sysfs file /class/net/eth0/address
Modules linked in: ipv6 af_packet ipt_REJECT xt_tcpudp x_tables
p4_clockmod speedstep_lib binfmt_misc
(gdb) list *0xc0138594
0xc0138594 is in __lock_acquire (include2/asm/atomic.h:96).
warning: Source file is more recent than executable.
91 *
92 * Atomically increments @v by 1.
93 */
94 static __inline__ void atomic_inc(atomic_t *v)
95 {
96 __asm__ __volatile__(
97 LOCK_PREFIX "incl %0"
98 :"=m" (v->counter)
99 :"m" (v->counter));
100 }
Here is a config file
http://www.stardust.webpages.pl/files/mm/2.6.17-mm4/mm-config
Regards,
Michal
--
Michal K. K. Piotrowski
LTG - Linux Testers Group
(http://www.stardust.webpages.pl/ltg/wiki/)
^ permalink raw reply
* Re: RDMA will be reverted
From: James Morris @ 2006-06-29 20:42 UTC (permalink / raw)
To: Tom Tucker; +Cc: David Miller, rdreier, netdev, akpm
In-Reply-To: <1151611866.11739.57.camel@trinity.ogc.int>
On Thu, 29 Jun 2006, Tom Tucker wrote:
> On Thu, 2006-06-29 at 12:46 -0700, David Miller wrote:
> > From: Roland Dreier <rdreier@cisco.com>
> > Date: Thu, 29 Jun 2006 09:54:37 -0700
> >
> > > In any case I think we need to find a way for Linux to support iWARP
> > > hardware, since there are users that want this, and (some of) the
> > > vendors are working hard to do things the right way (including cc'ing
> > > netdev on the conversation). I don't think it's good for Linux for
> > > the answer to just be, "sorry, you're wrong to want to use that hardware."
> >
> > We give the same response for TOE stuff.
>
> What does the word "we" represent in this context? Is it the Linux
> community at large, Linux and Andrew, you? I'm not trying to be
> argumentative, I just want to understand how carefully and by whom iWARP
> technology has been considered.
$ grep -ri davem /usr/src/linux
- James
--
James Morris
<jmorris@namei.org>
^ permalink raw reply
* Re: 2.6.17-mm4
From: Dave Jones @ 2006-06-29 20:43 UTC (permalink / raw)
To: Michal Piotrowski; +Cc: Andrew Morton, linux-kernel, netdev
In-Reply-To: <6bffcb0e0606291339s69a16bc5ie108c0b8d4e29ed6@mail.gmail.com>
On Thu, Jun 29, 2006 at 10:39:33PM +0200, Michal Piotrowski wrote:
> This looks very strange.
>
> BUG: unable to handle kernel paging request at virtual address 6b6b6c07
Looks like a use after free.
> printing eip:
> c0138594
> *pde=00000000
> Oops: 0002 [#1]
> 4K_STACK PREEMPT SMP
> last sysfs file /class/net/eth0/address
> Modules linked in: ipv6 af_packet ipt_REJECT xt_tcpudp x_tables
> p4_clockmod speedstep_lib binfmt_misc
>
> (gdb) list *0xc0138594
> 0xc0138594 is in __lock_acquire (include2/asm/atomic.h:96).
> warning: Source file is more recent than executable.
got a backtrace ?
Dave
--
http://www.codemonkey.org.uk
^ permalink raw reply
* Re: 2.6.17-mm4
From: Michal Piotrowski @ 2006-06-29 20:46 UTC (permalink / raw)
To: Dave Jones, Michal Piotrowski, Andrew Morton, linux-kernel,
netdev
In-Reply-To: <20060629204330.GC13619@redhat.com>
On 29/06/06, Dave Jones <davej@redhat.com> wrote:
> On Thu, Jun 29, 2006 at 10:39:33PM +0200, Michal Piotrowski wrote:
>
> > This looks very strange.
> >
> > BUG: unable to handle kernel paging request at virtual address 6b6b6c07
>
> Looks like a use after free.
>
> > printing eip:
> > c0138594
> > *pde=00000000
> > Oops: 0002 [#1]
> > 4K_STACK PREEMPT SMP
> > last sysfs file /class/net/eth0/address
> > Modules linked in: ipv6 af_packet ipt_REJECT xt_tcpudp x_tables
> > p4_clockmod speedstep_lib binfmt_misc
> >
> > (gdb) list *0xc0138594
> > 0xc0138594 is in __lock_acquire (include2/asm/atomic.h:96).
> > warning: Source file is more recent than executable.
>
> got a backtrace ?
Unfortunately no.
>
> Dave
>
> --
> http://www.codemonkey.org.uk
>
Regards,
Michal
--
Michal K. K. Piotrowski
LTG - Linux Testers Group
(http://www.stardust.webpages.pl/ltg/wiki/)
^ permalink raw reply
* Re: RDMA will be reverted
From: Tom Tucker @ 2006-06-29 20:47 UTC (permalink / raw)
To: David Miller; +Cc: rdreier, netdev, akpm
In-Reply-To: <20060629.131938.55726619.davem@davemloft.net>
On Thu, 2006-06-29 at 13:19 -0700, David Miller wrote:
> From: Tom Tucker <tom@opengridcomputing.com>
> Date: Thu, 29 Jun 2006 15:11:06 -0500
>
> > Doesn't this position force vendors to build deeper adapters, not
> > shallower adapters? Isn't this exactly the opposite of what is intended?
>
> Nope.
>
> Look at what the networking developers give a lot of attention and
> effort to, things like TCP Large Receive Offload, and Van Jacobson net
> channels, both of which are fully stack integrated receive performance
> enhancements. They do not bypass netfilter, they do not bypass
> packet scheduling, and yet they provide a hardware assist performance
> improvement for receive.
These technologies are integrated because someone chose to and was
allowed to integrate them. I contend that iWARP could be equally well
integrated if the decision was made to do so. It would, however, require
cooperation from both the hardware vendors and the netdev maintainers.
>
> This has been stated over and over again.
For TOE, you are correct, however, for iWARP, you can't do RDMA (direct
placement into application buffers) without state in the adapter. I
personally tried very hard to build an adapter without doing so, but
alas, I failed ;-)
>
> If companies keep designing undesirable hardware that unnecessarily
> takes features away from the user, that really is not our problem.
I concede that features have been lost, but some applications benefit
greatly from RDMA. For these applications and these customers, the
hardware is not undesirable and the fact that netfilter won't work on
their sub 5us latency adapter is not perceived to be a big issue. The
mention of packet scheduling would cause an apoplectic seizure...unless
it were in the hardware...
All that verbiage aside, I believe that it is not a matter of whether it
is possible to integrate iWARP it is question of whether it is
permissible.
^ permalink raw reply
* Re: 2.6.17-mm4
From: Dave Jones @ 2006-06-29 20:49 UTC (permalink / raw)
To: Michal Piotrowski; +Cc: Andrew Morton, linux-kernel, netdev
In-Reply-To: <6bffcb0e0606291346s64530db4g1c9c33da9cf34e73@mail.gmail.com>
On Thu, Jun 29, 2006 at 10:46:24PM +0200, Michal Piotrowski wrote:
> On 29/06/06, Dave Jones <davej@redhat.com> wrote:
> >On Thu, Jun 29, 2006 at 10:39:33PM +0200, Michal Piotrowski wrote:
> >
> > > This looks very strange.
> > >
> > > BUG: unable to handle kernel paging request at virtual address 6b6b6c07
> >
> >Looks like a use after free.
> >
> > > printing eip:
> > > c0138594
> > > *pde=00000000
> > > Oops: 0002 [#1]
> > > 4K_STACK PREEMPT SMP
> > > last sysfs file /class/net/eth0/address
> > > Modules linked in: ipv6 af_packet ipt_REJECT xt_tcpudp x_tables
> > > p4_clockmod speedstep_lib binfmt_misc
> > >
> > > (gdb) list *0xc0138594
> > > 0xc0138594 is in __lock_acquire (include2/asm/atomic.h:96).
> > > warning: Source file is more recent than executable.
> >
> >got a backtrace ?
>
> Unfortunately no.
nothing useful from 'bt' from that gdb prompt ?
Dave
--
http://www.codemonkey.org.uk
^ permalink raw reply
* [PATCH 0/9] pcnet32: NAPI support
From: Don Fry @ 2006-06-29 20:51 UTC (permalink / raw)
To: tsbogend, jgarzik, netdev
These patches to the pcnet32 driver implement NAPI and fix some other
errors found during NAPI development and testing. Please apply to
2.6.18.
1/9 Fix Section mismatch error
2/9 Use PCI_DEVICE macro
3/9 Fix off-by-one in get_ringparam
4/9 Use kcalloc instead of kmalloc and memset
5/9 Handle memory allocation failures cleanly when resizing tx/rx rings
6/9 Suspend the chip rather than restart when changing multicast/promisc
7/9 Cleanup rx buffers after loopback test.
8/9 NAPI implementation.
9/9 Magic number cleanup.
--
Don Fry
brazilnut@us.ibm.com
^ permalink raw reply
* [PATCH 1/9] pcnet32: Fix Section mismatch error
From: Don Fry @ 2006-06-29 20:52 UTC (permalink / raw)
To: tsbogend, jgarzik, netdev
Fix Section mismatch error. Tested ia32 and ppc64.
Signed-off-by: Don Fry <brazilnut@us.ibm.com>
--- linux-2.6.17-git13/drivers/net/orig.pcnet32.c Wed Jun 28 10:38:46 2006
+++ linux-2.6.17-git13/drivers/net/pcnet32.c Wed Jun 28 11:03:38 2006
@@ -277,7 +277,6 @@ struct pcnet32_private {
u32 phymask;
};
-static void pcnet32_probe_vlbus(void);
static int pcnet32_probe_pci(struct pci_dev *, const struct pci_device_id *);
static int pcnet32_probe1(unsigned long, int, struct pci_dev *);
static int pcnet32_open(struct net_device *);
@@ -952,7 +951,7 @@ static struct ethtool_ops pcnet32_ethtoo
/* only probes for non-PCI devices, the rest are handled by
* pci_register_driver via pcnet32_probe_pci */
-static void __devinit pcnet32_probe_vlbus(void)
+static void __devinit pcnet32_probe_vlbus(unsigned int *pcnet32_portlist)
{
unsigned int *port, ioaddr;
@@ -2730,7 +2729,7 @@ static int __init pcnet32_init_module(vo
/* should we find any remaining VLbus devices ? */
if (pcnet32vlb)
- pcnet32_probe_vlbus();
+ pcnet32_probe_vlbus(pcnet32_portlist);
if (cards_found && (pcnet32_debug & NETIF_MSG_PROBE))
printk(KERN_INFO PFX "%d cards_found.\n", cards_found);
--
Don Fry
brazilnut@us.ibm.com
^ permalink raw reply
* [PATCH 2/9] pcnet32: Use PCI_DEVICE macro
From: Don Fry @ 2006-06-29 20:52 UTC (permalink / raw)
To: tsbogend, jgarzik, netdev
Jon Mason wrote on Thu, 12 Jan 2006 17:07:49 -0600:
This patch adds the PCI_DEVICE macro to the pcnet32 driver.
This has been tested on my opteron with my "trident" adapter.
Don Fry modified it slightly and tested on ia32 and ppc64.
Signed-off-by: Jon Mason <jdmason@us.ibm.com>
Signed-off-by: Don Fry <brazilnut@us.ibm.com>
--- linux-2.6.17-git13/drivers/net/mismatch.pcnet32.c Wed Jun 28 11:03:38 2006
+++ linux-2.6.17-git13/drivers/net/pcnet32.c Wed Jun 28 11:11:37 2006
@@ -58,18 +58,15 @@ static const char *const version =
* PCI device identifiers for "new style" Linux PCI Device Drivers
*/
static struct pci_device_id pcnet32_pci_tbl[] = {
- { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE_HOME,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE_HOME), },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE), },
/*
* Adapters that were sold with IBM's RS/6000 or pSeries hardware have
* the incorrect vendor id.
*/
- { PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_AMD_LANCE,
- PCI_ANY_ID, PCI_ANY_ID,
- PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, 0},
+ { PCI_DEVICE(PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_AMD_LANCE),
+ .class = (PCI_CLASS_NETWORK_ETHERNET << 8), .class_mask = 0xffff00, },
{ } /* terminate list */
};
--
Don Fry
brazilnut@us.ibm.com
^ permalink raw reply
* [PATCH 3/9] pcnet32: Fix off-by-one in get_ringparam
From: Don Fry @ 2006-06-29 20:53 UTC (permalink / raw)
To: tsbogend, jgarzik, netdev
Fix off-by-one in pcnet32_get_ringparam
Signed-off-by: Don Fry <brazilnut@us.ibm.com>
--- linux-2.6.17-git13/drivers/net/device.pcnet32.c Wed Jun 28 11:12:22 2006
+++ linux-2.6.17-git13/drivers/net/pcnet32.c Wed Jun 28 11:16:15 2006
@@ -515,10 +515,10 @@ static void pcnet32_get_ringparam(struct
{
struct pcnet32_private *lp = dev->priv;
- ering->tx_max_pending = TX_MAX_RING_SIZE - 1;
- ering->tx_pending = lp->tx_ring_size - 1;
- ering->rx_max_pending = RX_MAX_RING_SIZE - 1;
- ering->rx_pending = lp->rx_ring_size - 1;
+ ering->tx_max_pending = TX_MAX_RING_SIZE;
+ ering->tx_pending = lp->tx_ring_size;
+ ering->rx_max_pending = RX_MAX_RING_SIZE;
+ ering->rx_pending = lp->rx_ring_size;
}
static int pcnet32_set_ringparam(struct net_device *dev,
--
Don Fry
brazilnut@us.ibm.com
^ permalink raw reply
* [PATCH 4/9] pcnet32: Use kcalloc instead of kmalloc and memset
From: Don Fry @ 2006-06-29 20:53 UTC (permalink / raw)
To: tsbogend, jgarzik, netdev
On 2006-03-08 Eric Sesterhenn wrote:
converts drivers/net to kzalloc usage.
Don Fry modified it to use netif_msg_drv. Tested ia32 and ppc64.
Signed-off-by: Eric Sesterhenn <snakebyte@gmx.de>
Signed-off-by: Don Fry <brazilnut@us.ibm.com>
--- linux-2.6.17-git13/drivers/net/get.pcnet32.c Wed Jun 28 11:17:09 2006
+++ linux-2.6.17-git13/drivers/net/pcnet32.c Wed Jun 28 11:55:52 2006
@@ -1432,7 +1432,7 @@ static int pcnet32_alloc_ring(struct net
lp->tx_ring_size,
&lp->tx_ring_dma_addr);
if (lp->tx_ring == NULL) {
- if (pcnet32_debug & NETIF_MSG_DRV)
+ if (netif_msg_drv(lp))
printk("\n" KERN_ERR PFX
"%s: Consistent memory allocation failed.\n",
name);
@@ -1444,52 +1444,48 @@ static int pcnet32_alloc_ring(struct net
lp->rx_ring_size,
&lp->rx_ring_dma_addr);
if (lp->rx_ring == NULL) {
- if (pcnet32_debug & NETIF_MSG_DRV)
+ if (netif_msg_drv(lp))
printk("\n" KERN_ERR PFX
"%s: Consistent memory allocation failed.\n",
name);
return -ENOMEM;
}
- lp->tx_dma_addr = kmalloc(sizeof(dma_addr_t) * lp->tx_ring_size,
+ lp->tx_dma_addr = kcalloc(lp->tx_ring_size, sizeof(dma_addr_t),
GFP_ATOMIC);
if (!lp->tx_dma_addr) {
- if (pcnet32_debug & NETIF_MSG_DRV)
+ if (netif_msg_drv(lp))
printk("\n" KERN_ERR PFX
"%s: Memory allocation failed.\n", name);
return -ENOMEM;
}
- memset(lp->tx_dma_addr, 0, sizeof(dma_addr_t) * lp->tx_ring_size);
- lp->rx_dma_addr = kmalloc(sizeof(dma_addr_t) * lp->rx_ring_size,
+ lp->rx_dma_addr = kcalloc(lp->rx_ring_size, sizeof(dma_addr_t),
GFP_ATOMIC);
if (!lp->rx_dma_addr) {
- if (pcnet32_debug & NETIF_MSG_DRV)
+ if (netif_msg_drv(lp))
printk("\n" KERN_ERR PFX
"%s: Memory allocation failed.\n", name);
return -ENOMEM;
}
- memset(lp->rx_dma_addr, 0, sizeof(dma_addr_t) * lp->rx_ring_size);
- lp->tx_skbuff = kmalloc(sizeof(struct sk_buff *) * lp->tx_ring_size,
+ lp->tx_skbuff = kcalloc(lp->tx_ring_size, sizeof(struct sk_buff *),
GFP_ATOMIC);
if (!lp->tx_skbuff) {
- if (pcnet32_debug & NETIF_MSG_DRV)
+ if (netif_msg_drv(lp))
printk("\n" KERN_ERR PFX
"%s: Memory allocation failed.\n", name);
return -ENOMEM;
}
- memset(lp->tx_skbuff, 0, sizeof(struct sk_buff *) * lp->tx_ring_size);
- lp->rx_skbuff = kmalloc(sizeof(struct sk_buff *) * lp->rx_ring_size,
+ lp->rx_skbuff = kcalloc(lp->rx_ring_size, sizeof(struct sk_buff *),
GFP_ATOMIC);
if (!lp->rx_skbuff) {
- if (pcnet32_debug & NETIF_MSG_DRV)
+ if (netif_msg_drv(lp))
printk("\n" KERN_ERR PFX
"%s: Memory allocation failed.\n", name);
return -ENOMEM;
}
- memset(lp->rx_skbuff, 0, sizeof(struct sk_buff *) * lp->rx_ring_size);
return 0;
}
--
Don Fry
brazilnut@us.ibm.com
^ permalink raw reply
* Re: RDMA will be reverted
From: David Miller @ 2006-06-29 20:53 UTC (permalink / raw)
To: tom; +Cc: rdreier, netdev, akpm
In-Reply-To: <1151614033.11739.82.camel@trinity.ogc.int>
From: Tom Tucker <tom@opengridcomputing.com>
Date: Thu, 29 Jun 2006 15:47:13 -0500
> I concede that features have been lost, but some applications benefit
> greatly from RDMA. For these applications and these customers,
TOE folks give the same story... it's a broken record, really.
Let us know when you can say something new about the situation.
Under Linux we get to make better long term architectually sane
decisions, even if it is to the dismay of the backers of certain
short-sighted pieces of technology.
^ permalink raw reply
* [PATCH 5/9] pcnet32: Handle memory allocation failures cleanly when resizing tx/rx rings
From: Don Fry @ 2006-06-29 20:54 UTC (permalink / raw)
To: tsbogend, jgarzik, netdev
Fix pcnet32_set_ringparam to handle memory allocation errors without
leaving the adapter in an inoperative state and null pointers waiting to
be dereferenced.
Tested ia32 and ppc64.
Signed-off-by: Don Fry <brazilnut@us.ibm.com>
--- linux-2.6.17-git13/drivers/net/calloc.pcnet32.c Wed Jun 28 11:55:52 2006
+++ linux-2.6.17-git13/drivers/net/pcnet32.c Wed Jun 28 13:13:52 2006
@@ -185,6 +185,23 @@ static int homepna[MAX_UNITS];
#define PCNET32_TOTAL_SIZE 0x20
+#define CSR0 0
+#define CSR0_INIT 0x1
+#define CSR0_START 0x2
+#define CSR0_STOP 0x4
+#define CSR0_TXPOLL 0x8
+#define CSR0_INTEN 0x40
+#define CSR0_IDON 0x0100
+#define CSR0_NORMAL (CSR0_START | CSR0_INTEN)
+#define PCNET32_INIT_LOW 1
+#define PCNET32_INIT_HIGH 2
+#define CSR3 3
+#define CSR4 4
+#define CSR5 5
+#define CSR5_SUSPEND 0x0001
+#define CSR15 15
+#define PCNET32_MC_FILTER 8
+
/* The PCNET32 Rx and Tx ring descriptors. */
struct pcnet32_rx_head {
u32 base;
@@ -415,6 +432,219 @@ static struct pcnet32_access pcnet32_dwi
.reset = pcnet32_dwio_reset
};
+static void pcnet32_netif_stop(struct net_device *dev)
+{
+ dev->trans_start = jiffies;
+ netif_poll_disable(dev);
+ netif_tx_disable(dev);
+}
+
+static void pcnet32_netif_start(struct net_device *dev)
+{
+ netif_wake_queue(dev);
+ netif_poll_enable(dev);
+}
+
+/*
+ * Allocate space for the new sized tx ring.
+ * Free old resources
+ * Save new resources.
+ * Any failure keeps old resources.
+ * Must be called with lp->lock held.
+ */
+static void pcnet32_realloc_tx_ring(struct net_device *dev,
+ struct pcnet32_private *lp,
+ unsigned int size)
+{
+ dma_addr_t new_ring_dma_addr;
+ dma_addr_t *new_dma_addr_list;
+ struct pcnet32_tx_head *new_tx_ring;
+ struct sk_buff **new_skb_list;
+
+ pcnet32_purge_tx_ring(dev);
+
+ new_tx_ring = pci_alloc_consistent(lp->pci_dev,
+ sizeof(struct pcnet32_tx_head) *
+ (1 << size),
+ &new_ring_dma_addr);
+ if (new_tx_ring == NULL) {
+ if (netif_msg_drv(lp))
+ printk("\n" KERN_ERR
+ "%s: Consistent memory allocation failed.\n",
+ dev->name);
+ return;
+ }
+ memset(new_tx_ring, 0, sizeof(struct pcnet32_tx_head) * (1 << size));
+
+ new_dma_addr_list = kcalloc((1 << size), sizeof(dma_addr_t),
+ GFP_ATOMIC);
+ if (!new_dma_addr_list) {
+ if (netif_msg_drv(lp))
+ printk("\n" KERN_ERR
+ "%s: Memory allocation failed.\n", dev->name);
+ goto free_new_tx_ring;
+ }
+
+ new_skb_list = kcalloc((1 << size), sizeof(struct sk_buff *),
+ GFP_ATOMIC);
+ if (!new_skb_list) {
+ if (netif_msg_drv(lp))
+ printk("\n" KERN_ERR
+ "%s: Memory allocation failed.\n", dev->name);
+ goto free_new_lists;
+ }
+
+ kfree(lp->tx_skbuff);
+ kfree(lp->tx_dma_addr);
+ pci_free_consistent(lp->pci_dev,
+ sizeof(struct pcnet32_tx_head) *
+ lp->tx_ring_size, lp->tx_ring,
+ lp->tx_ring_dma_addr);
+
+ lp->tx_ring_size = (1 << size);
+ lp->tx_mod_mask = lp->tx_ring_size - 1;
+ lp->tx_len_bits = (size << 12);
+ lp->tx_ring = new_tx_ring;
+ lp->tx_ring_dma_addr = new_ring_dma_addr;
+ lp->tx_dma_addr = new_dma_addr_list;
+ lp->tx_skbuff = new_skb_list;
+ return;
+
+ free_new_lists:
+ kfree(new_dma_addr_list);
+ free_new_tx_ring:
+ pci_free_consistent(lp->pci_dev,
+ sizeof(struct pcnet32_tx_head) *
+ (1 << size),
+ new_tx_ring,
+ new_ring_dma_addr);
+ return;
+}
+
+/*
+ * Allocate space for the new sized rx ring.
+ * Re-use old receive buffers.
+ * alloc extra buffers
+ * free unneeded buffers
+ * free unneeded buffers
+ * Save new resources.
+ * Any failure keeps old resources.
+ * Must be called with lp->lock held.
+ */
+static void pcnet32_realloc_rx_ring(struct net_device *dev,
+ struct pcnet32_private *lp,
+ unsigned int size)
+{
+ dma_addr_t new_ring_dma_addr;
+ dma_addr_t *new_dma_addr_list;
+ struct pcnet32_rx_head *new_rx_ring;
+ struct sk_buff **new_skb_list;
+ int new, overlap;
+
+ new_rx_ring = pci_alloc_consistent(lp->pci_dev,
+ sizeof(struct pcnet32_rx_head) *
+ (1 << size),
+ &new_ring_dma_addr);
+ if (new_rx_ring == NULL) {
+ if (netif_msg_drv(lp))
+ printk("\n" KERN_ERR
+ "%s: Consistent memory allocation failed.\n",
+ dev->name);
+ return;
+ }
+ memset(new_rx_ring, 0, sizeof(struct pcnet32_rx_head) * (1 << size));
+
+ new_dma_addr_list = kcalloc((1 << size), sizeof(dma_addr_t),
+ GFP_ATOMIC);
+ if (!new_dma_addr_list) {
+ if (netif_msg_drv(lp))
+ printk("\n" KERN_ERR
+ "%s: Memory allocation failed.\n", dev->name);
+ goto free_new_rx_ring;
+ }
+
+ new_skb_list = kcalloc((1 << size), sizeof(struct sk_buff *),
+ GFP_ATOMIC);
+ if (!new_skb_list) {
+ if (netif_msg_drv(lp))
+ printk("\n" KERN_ERR
+ "%s: Memory allocation failed.\n", dev->name);
+ goto free_new_lists;
+ }
+
+ /* first copy the current receive buffers */
+ overlap = min(size, lp->rx_ring_size);
+ for (new = 0; new < overlap; new++) {
+ new_rx_ring[new] = lp->rx_ring[new];
+ new_dma_addr_list[new] = lp->rx_dma_addr[new];
+ new_skb_list[new] = lp->rx_skbuff[new];
+ }
+ /* now allocate any new buffers needed */
+ for (; new < size; new++ ) {
+ struct sk_buff *rx_skbuff;
+ new_skb_list[new] = dev_alloc_skb(PKT_BUF_SZ);
+ if (!(rx_skbuff = new_skb_list[new])) {
+ /* keep the original lists and buffers */
+ if (netif_msg_drv(lp))
+ printk(KERN_ERR
+ "%s: pcnet32_realloc_rx_ring dev_alloc_skb failed.\n",
+ dev->name);
+ goto free_all_new;
+ }
+ skb_reserve(rx_skbuff, 2);
+
+ new_dma_addr_list[new] =
+ pci_map_single(lp->pci_dev, rx_skbuff->data,
+ PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
+ new_rx_ring[new].base = (u32) le32_to_cpu(new_dma_addr_list[new]);
+ new_rx_ring[new].buf_length = le16_to_cpu(2 - PKT_BUF_SZ);
+ new_rx_ring[new].status = le16_to_cpu(0x8000);
+ }
+ /* and free any unneeded buffers */
+ for (; new < lp->rx_ring_size; new++) {
+ if (lp->rx_skbuff[new]) {
+ pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[new],
+ PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(lp->rx_skbuff[new]);
+ }
+ }
+
+ kfree(lp->rx_skbuff);
+ kfree(lp->rx_dma_addr);
+ pci_free_consistent(lp->pci_dev,
+ sizeof(struct pcnet32_rx_head) *
+ lp->rx_ring_size, lp->rx_ring,
+ lp->rx_ring_dma_addr);
+
+ lp->rx_ring_size = (1 << size);
+ lp->rx_mod_mask = lp->rx_ring_size - 1;
+ lp->rx_len_bits = (size << 4);
+ lp->rx_ring = new_rx_ring;
+ lp->rx_ring_dma_addr = new_ring_dma_addr;
+ lp->rx_dma_addr = new_dma_addr_list;
+ lp->rx_skbuff = new_skb_list;
+ return;
+
+ free_all_new:
+ for (; --new >= lp->rx_ring_size; ) {
+ if (new_skb_list[new]) {
+ pci_unmap_single(lp->pci_dev, new_dma_addr_list[new],
+ PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(new_skb_list[new]);
+ }
+ }
+ kfree(new_skb_list);
+ free_new_lists:
+ kfree(new_dma_addr_list);
+ free_new_rx_ring:
+ pci_free_consistent(lp->pci_dev,
+ sizeof(struct pcnet32_rx_head) *
+ (1 << size),
+ new_rx_ring,
+ new_ring_dma_addr);
+ return;
+}
+
#ifdef CONFIG_NET_POLL_CONTROLLER
static void pcnet32_poll_controller(struct net_device *dev)
{
@@ -526,56 +756,53 @@ static int pcnet32_set_ringparam(struct
{
struct pcnet32_private *lp = dev->priv;
unsigned long flags;
+ unsigned int size;
+ ulong ioaddr = dev->base_addr;
int i;
if (ering->rx_mini_pending || ering->rx_jumbo_pending)
return -EINVAL;
if (netif_running(dev))
- pcnet32_close(dev);
+ pcnet32_netif_stop(dev);
spin_lock_irqsave(&lp->lock, flags);
- pcnet32_free_ring(dev);
- lp->tx_ring_size =
- min(ering->tx_pending, (unsigned int)TX_MAX_RING_SIZE);
- lp->rx_ring_size =
- min(ering->rx_pending, (unsigned int)RX_MAX_RING_SIZE);
+ lp->a.write_csr(ioaddr, CSR0, CSR0_STOP); /* stop the chip */
+
+ size = min(ering->tx_pending, (unsigned int)TX_MAX_RING_SIZE);
/* set the minimum ring size to 4, to allow the loopback test to work
* unchanged.
*/
for (i = 2; i <= PCNET32_LOG_MAX_TX_BUFFERS; i++) {
- if (lp->tx_ring_size <= (1 << i))
+ if (size <= (1 << i))
break;
}
- lp->tx_ring_size = (1 << i);
- lp->tx_mod_mask = lp->tx_ring_size - 1;
- lp->tx_len_bits = (i << 12);
-
+ if ((1 << i) != lp->tx_ring_size)
+ pcnet32_realloc_tx_ring(dev, lp, i);
+
+ size = min(ering->rx_pending, (unsigned int)RX_MAX_RING_SIZE);
for (i = 2; i <= PCNET32_LOG_MAX_RX_BUFFERS; i++) {
- if (lp->rx_ring_size <= (1 << i))
+ if (size <= (1 << i))
break;
}
- lp->rx_ring_size = (1 << i);
- lp->rx_mod_mask = lp->rx_ring_size - 1;
- lp->rx_len_bits = (i << 4);
-
- if (pcnet32_alloc_ring(dev, dev->name)) {
- pcnet32_free_ring(dev);
- spin_unlock_irqrestore(&lp->lock, flags);
- return -ENOMEM;
+ if ((1 << i) != lp->rx_ring_size)
+ pcnet32_realloc_rx_ring(dev, lp, i);
+
+ dev->weight = lp->rx_ring_size / 2;
+
+ if (netif_running(dev)) {
+ pcnet32_netif_start(dev);
+ pcnet32_restart(dev, CSR0_NORMAL);
}
spin_unlock_irqrestore(&lp->lock, flags);
- if (pcnet32_debug & NETIF_MSG_DRV)
- printk(KERN_INFO PFX
+ if (netif_msg_drv(lp))
+ printk(KERN_INFO
"%s: Ring Param Settings: RX: %d, TX: %d\n", dev->name,
lp->rx_ring_size, lp->tx_ring_size);
- if (netif_running(dev))
- pcnet32_open(dev);
-
return 0;
}
--
Don Fry
brazilnut@us.ibm.com
^ permalink raw reply
* [PATCH 6/9] pcnet32: Suspend the chip rather than restart when changing multicast/promisc
From: Don Fry @ 2006-06-29 20:55 UTC (permalink / raw)
To: tsbogend, jgarzik, netdev
Suspend the chip if possible rather than stop and discard all tx and rx
frames, when changing the mcast list or entering/leaving promiscuous
mode. Created common pcnet32_suspend routine.
Tested ia32 and ppc64
Signed-off-by: Don Fry <brazilnut@us.ibm.com>
--- linux-2.6.17-git13/drivers/net/set.pcnet32.c Wed Jun 28 13:13:52 2006
+++ linux-2.6.17-git13/drivers/net/pcnet32.c Wed Jun 28 15:16:58 2006
@@ -1062,6 +1062,43 @@ static int pcnet32_phys_id(struct net_de
return 0;
}
+/*
+ * lp->lock must be held.
+ */
+static int pcnet32_suspend(struct net_device *dev, unsigned long *flags,
+ int can_sleep)
+{
+ int csr5;
+ struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_access *a = &lp->a;
+ ulong ioaddr = dev->base_addr;
+ int ticks;
+
+ /* set SUSPEND (SPND) - CSR5 bit 0 */
+ csr5 = a->read_csr(ioaddr, CSR5);
+ a->write_csr(ioaddr, CSR5, csr5 | CSR5_SUSPEND);
+
+ /* poll waiting for bit to be set */
+ ticks = 0;
+ while (!(a->read_csr(ioaddr, CSR5) & CSR5_SUSPEND)) {
+ spin_unlock_irqrestore(&lp->lock, *flags);
+ if (can_sleep)
+ msleep(1);
+ else
+ mdelay(1);
+ spin_lock_irqsave(&lp->lock, *flags);
+ ticks++;
+ if (ticks > 200) {
+ if (netif_msg_hw(lp))
+ printk(KERN_DEBUG
+ "%s: Error getting into suspend!\n",
+ dev->name);
+ return 0;
+ }
+ }
+ return 1;
+}
+
#define PCNET32_REGS_PER_PHY 32
#define PCNET32_MAX_PHYS 32
static int pcnet32_get_regs_len(struct net_device *dev)
@@ -1080,32 +1117,13 @@ static void pcnet32_get_regs(struct net_
struct pcnet32_private *lp = dev->priv;
struct pcnet32_access *a = &lp->a;
ulong ioaddr = dev->base_addr;
- int ticks;
unsigned long flags;
spin_lock_irqsave(&lp->lock, flags);
- csr0 = a->read_csr(ioaddr, 0);
- if (!(csr0 & 0x0004)) { /* If not stopped */
- /* set SUSPEND (SPND) - CSR5 bit 0 */
- a->write_csr(ioaddr, 5, 0x0001);
-
- /* poll waiting for bit to be set */
- ticks = 0;
- while (!(a->read_csr(ioaddr, 5) & 0x0001)) {
- spin_unlock_irqrestore(&lp->lock, flags);
- mdelay(1);
- spin_lock_irqsave(&lp->lock, flags);
- ticks++;
- if (ticks > 200) {
- if (netif_msg_hw(lp))
- printk(KERN_DEBUG
- "%s: Error getting into suspend!\n",
- dev->name);
- break;
- }
- }
- }
+ csr0 = a->read_csr(ioaddr, CSR0);
+ if (!(csr0 & CSR0_STOP)) /* If not stopped */
+ pcnet32_suspend(dev, &flags, 1);
/* read address PROM */
for (i = 0; i < 16; i += 2)
@@ -1142,9 +1160,12 @@ static void pcnet32_get_regs(struct net_
}
}
- if (!(csr0 & 0x0004)) { /* If not stopped */
+ if (!(csr0 & CSR0_STOP)) { /* If not stopped */
+ int csr5;
+
/* clear SUSPEND (SPND) - CSR5 bit 0 */
- a->write_csr(ioaddr, 5, 0x0000);
+ csr5 = a->read_csr(ioaddr, CSR5);
+ a->write_csr(ioaddr, CSR5, csr5 & (~CSR5_SUSPEND));
}
spin_unlock_irqrestore(&lp->lock, flags);
@@ -2652,6 +2673,7 @@ static void pcnet32_load_multicast(struc
volatile struct pcnet32_init_block *ib = &lp->init_block;
volatile u16 *mcast_table = (u16 *) & ib->filter;
struct dev_mc_list *dmi = dev->mc_list;
+ unsigned long ioaddr = dev->base_addr;
char *addrs;
int i;
u32 crc;
@@ -2660,6 +2682,10 @@ static void pcnet32_load_multicast(struc
if (dev->flags & IFF_ALLMULTI) {
ib->filter[0] = 0xffffffff;
ib->filter[1] = 0xffffffff;
+ lp->a.write_csr(ioaddr, PCNET32_MC_FILTER, 0xffff);
+ lp->a.write_csr(ioaddr, PCNET32_MC_FILTER+1, 0xffff);
+ lp->a.write_csr(ioaddr, PCNET32_MC_FILTER+2, 0xffff);
+ lp->a.write_csr(ioaddr, PCNET32_MC_FILTER+3, 0xffff);
return;
}
/* clear the multicast filter */
@@ -2681,6 +2707,9 @@ static void pcnet32_load_multicast(struc
le16_to_cpu(le16_to_cpu(mcast_table[crc >> 4]) |
(1 << (crc & 0xf)));
}
+ for (i = 0; i < 4; i++)
+ lp->a.write_csr(ioaddr, PCNET32_MC_FILTER + i,
+ le16_to_cpu(mcast_table[i]));
return;
}
@@ -2691,8 +2720,11 @@ static void pcnet32_set_multicast_list(s
{
unsigned long ioaddr = dev->base_addr, flags;
struct pcnet32_private *lp = dev->priv;
+ int csr15, suspended;
spin_lock_irqsave(&lp->lock, flags);
+ suspended = pcnet32_suspend(dev, &flags, 0);
+ csr15 = lp->a.read_csr(ioaddr, CSR15);
if (dev->flags & IFF_PROMISC) {
/* Log any net taps. */
if (netif_msg_hw(lp))
@@ -2701,15 +2733,24 @@ static void pcnet32_set_multicast_list(s
lp->init_block.mode =
le16_to_cpu(0x8000 | (lp->options & PCNET32_PORT_PORTSEL) <<
7);
+ lp->a.write_csr(ioaddr, CSR15, csr15 | 0x8000);
} else {
lp->init_block.mode =
le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7);
+ lp->a.write_csr(ioaddr, CSR15, csr15 & 0x7fff);
pcnet32_load_multicast(dev);
}
- lp->a.write_csr(ioaddr, 0, 0x0004); /* Temporarily stop the lance. */
- pcnet32_restart(dev, 0x0042); /* Resume normal operation */
- netif_wake_queue(dev);
+ if (suspended) {
+ int csr5;
+ /* clear SUSPEND (SPND) - CSR5 bit 0 */
+ csr5 = lp->a.read_csr(ioaddr, CSR5);
+ lp->a.write_csr(ioaddr, CSR5, csr5 & (~CSR5_SUSPEND));
+ } else {
+ lp->a.write_csr(ioaddr, CSR0, CSR0_STOP);
+ pcnet32_restart(dev, CSR0_NORMAL);
+ netif_wake_queue(dev);
+ }
spin_unlock_irqrestore(&lp->lock, flags);
}
--
Don Fry
brazilnut@us.ibm.com
^ permalink raw reply
* Re: 2.6.17-mm4
From: Andrew Morton @ 2006-06-29 20:58 UTC (permalink / raw)
To: Michal Piotrowski; +Cc: davej, michal.k.k.piotrowski, linux-kernel, netdev
In-Reply-To: <6bffcb0e0606291346s64530db4g1c9c33da9cf34e73@mail.gmail.com>
"Michal Piotrowski" <michal.k.k.piotrowski@gmail.com> wrote:
>
> On 29/06/06, Dave Jones <davej@redhat.com> wrote:
> > On Thu, Jun 29, 2006 at 10:39:33PM +0200, Michal Piotrowski wrote:
> >
> > > This looks very strange.
> > >
> > > BUG: unable to handle kernel paging request at virtual address 6b6b6c07
> >
> > Looks like a use after free.
> >
> > > printing eip:
> > > c0138594
> > > *pde=00000000
> > > Oops: 0002 [#1]
> > > 4K_STACK PREEMPT SMP
> > > last sysfs file /class/net/eth0/address
> > > Modules linked in: ipv6 af_packet ipt_REJECT xt_tcpudp x_tables
> > > p4_clockmod speedstep_lib binfmt_misc
> > >
> > > (gdb) list *0xc0138594
> > > 0xc0138594 is in __lock_acquire (include2/asm/atomic.h:96).
> > > warning: Source file is more recent than executable.
> >
> > got a backtrace ?
>
> Unfortunately no.
>
How irritating.
CONFIG_FRAME_POINTER=y
# CONFIG_UNWIND_INFO is not set
OK. Perhaps try setting 8k stacks?
Disable lockdep?
^ permalink raw reply
* [PATCH 7/9] pcnet32: Cleanup rx buffers after loopback test.
From: Don Fry @ 2006-06-29 20:55 UTC (permalink / raw)
To: tsbogend, jgarzik, netdev
More cleanup to pcnet32_loopback_test to release receive buffers if
device is not up. Created common routine to free rx buffers.
Tested ia32 and ppc64
Signed-off-by: Don Fry <brazilnut@us.ibm.com>
--- linux-2.6.17-git13/drivers/net/mcast.pcnet32.c Wed Jun 28 15:16:58 2006
+++ linux-2.6.17-git13/drivers/net/pcnet32.c Thu Jun 29 13:09:40 2006
@@ -645,6 +645,25 @@ static void pcnet32_realloc_rx_ring(stru
return;
}
+static void pcnet32_purge_rx_ring(struct net_device *dev)
+{
+ struct pcnet32_private *lp = dev->priv;
+ int i;
+
+ /* free all allocated skbuffs */
+ for (i = 0; i < lp->rx_ring_size; i++) {
+ lp->rx_ring[i].status = 0; /* CPU owns buffer */
+ wmb(); /* Make sure adapter sees owner change */
+ if (lp->rx_skbuff[i]) {
+ pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i],
+ PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
+ dev_kfree_skb_any(lp->rx_skbuff[i]);
+ }
+ lp->rx_skbuff[i] = NULL;
+ lp->rx_dma_addr[i] = 0;
+ }
+}
+
#ifdef CONFIG_NET_POLL_CONTROLLER
static void pcnet32_poll_controller(struct net_device *dev)
{
@@ -856,29 +875,27 @@ static int pcnet32_loopback_test(struct
unsigned long flags;
unsigned long ticks;
- *data1 = 1; /* status of test, default to fail */
rc = 1; /* default to fail */
if (netif_running(dev))
pcnet32_close(dev);
spin_lock_irqsave(&lp->lock, flags);
+ lp->a.write_csr(ioaddr, CSR0, CSR0_STOP); /* stop the chip */
+
+ numbuffs = min(numbuffs, (int)min(lp->rx_ring_size, lp->tx_ring_size));
/* Reset the PCNET32 */
lp->a.reset(ioaddr);
+ lp->a.write_csr(ioaddr, CSR4, 0x0915);
/* switch pcnet32 to 32bit mode */
lp->a.write_bcr(ioaddr, 20, 2);
- lp->init_block.mode =
- le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7);
- lp->init_block.filter[0] = 0;
- lp->init_block.filter[1] = 0;
-
/* purge & init rings but don't actually restart */
pcnet32_restart(dev, 0x0000);
- lp->a.write_csr(ioaddr, 0, 0x0004); /* Set STOP bit */
+ lp->a.write_csr(ioaddr, CSR0, CSR0_STOP); /* Set STOP bit */
/* Initialize Transmit buffers. */
size = data_len + 15;
@@ -920,14 +937,15 @@ static int pcnet32_loopback_test(struct
}
}
- x = a->read_bcr(ioaddr, 32); /* set internal loopback in BSR32 */
- x = x | 0x0002;
- a->write_bcr(ioaddr, 32, x);
+ x = a->read_bcr(ioaddr, 32); /* set internal loopback in BCR32 */
+ a->write_bcr(ioaddr, 32, x | 0x0002);
- lp->a.write_csr(ioaddr, 15, 0x0044); /* set int loopback in CSR15 */
+ /* set int loopback in CSR15 */
+ x = a->read_csr(ioaddr, CSR15) & 0xfffc;
+ lp->a.write_csr(ioaddr, CSR15, x | 0x0044);
teststatus = le16_to_cpu(0x8000);
- lp->a.write_csr(ioaddr, 0, 0x0002); /* Set STRT bit */
+ lp->a.write_csr(ioaddr, CSR0, CSR0_START); /* Set STRT bit */
/* Check status of descriptors */
for (x = 0; x < numbuffs; x++) {
@@ -935,7 +953,7 @@ static int pcnet32_loopback_test(struct
rmb();
while ((lp->rx_ring[x].status & teststatus) && (ticks < 200)) {
spin_unlock_irqrestore(&lp->lock, flags);
- mdelay(1);
+ msleep(1);
spin_lock_irqsave(&lp->lock, flags);
rmb();
ticks++;
@@ -948,7 +966,7 @@ static int pcnet32_loopback_test(struct
}
}
- lp->a.write_csr(ioaddr, 0, 0x0004); /* Set STOP bit */
+ lp->a.write_csr(ioaddr, CSR0, CSR0_STOP); /* Set STOP bit */
wmb();
if (netif_msg_hw(lp) && netif_msg_pktdata(lp)) {
printk(KERN_DEBUG "%s: RX loopback packets:\n", dev->name);
@@ -981,25 +999,24 @@ static int pcnet32_loopback_test(struct
}
x++;
}
- if (!rc) {
- *data1 = 0;
- }
clean_up:
+ *data1 = rc;
pcnet32_purge_tx_ring(dev);
- x = a->read_csr(ioaddr, 15) & 0xFFFF;
- a->write_csr(ioaddr, 15, (x & ~0x0044)); /* reset bits 6 and 2 */
- x = a->read_bcr(ioaddr, 32); /* reset internal loopback */
- x = x & ~0x0002;
- a->write_bcr(ioaddr, 32, x);
+ x = a->read_csr(ioaddr, CSR15);
+ a->write_csr(ioaddr, CSR15, (x & ~0x0044)); /* reset bits 6 and 2 */
- spin_unlock_irqrestore(&lp->lock, flags);
+ x = a->read_bcr(ioaddr, 32); /* reset internal loopback */
+ a->write_bcr(ioaddr, 32, (x & ~0x0002));
if (netif_running(dev)) {
+ spin_unlock_irqrestore(&lp->lock, flags);
pcnet32_open(dev);
} else {
+ pcnet32_purge_rx_ring(dev);
lp->a.write_bcr(ioaddr, 20, 4); /* return to 16bit mode */
+ spin_unlock_irqrestore(&lp->lock, flags);
}
return (rc);
@@ -1997,16 +2014,7 @@ static int pcnet32_open(struct net_devic
err_free_ring:
/* free any allocated skbuffs */
- for (i = 0; i < lp->rx_ring_size; i++) {
- lp->rx_ring[i].status = 0;
- if (lp->rx_skbuff[i]) {
- pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i],
- PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
- dev_kfree_skb(lp->rx_skbuff[i]);
- }
- lp->rx_skbuff[i] = NULL;
- lp->rx_dma_addr[i] = 0;
- }
+ pcnet32_purge_rx_ring(dev);
/*
* Switch back to 16bit mode to avoid problems with dumb
@@ -2588,7 +2596,6 @@ static int pcnet32_close(struct net_devi
{
unsigned long ioaddr = dev->base_addr;
struct pcnet32_private *lp = dev->priv;
- int i;
unsigned long flags;
del_timer_sync(&lp->watchdog_timer);
@@ -2619,31 +2626,8 @@ static int pcnet32_close(struct net_devi
spin_lock_irqsave(&lp->lock, flags);
- /* free all allocated skbuffs */
- for (i = 0; i < lp->rx_ring_size; i++) {
- lp->rx_ring[i].status = 0;
- wmb(); /* Make sure adapter sees owner change */
- if (lp->rx_skbuff[i]) {
- pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i],
- PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
- dev_kfree_skb(lp->rx_skbuff[i]);
- }
- lp->rx_skbuff[i] = NULL;
- lp->rx_dma_addr[i] = 0;
- }
-
- for (i = 0; i < lp->tx_ring_size; i++) {
- lp->tx_ring[i].status = 0; /* CPU owns buffer */
- wmb(); /* Make sure adapter sees owner change */
- if (lp->tx_skbuff[i]) {
- pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[i],
- lp->tx_skbuff[i]->len,
- PCI_DMA_TODEVICE);
- dev_kfree_skb(lp->tx_skbuff[i]);
- }
- lp->tx_skbuff[i] = NULL;
- lp->tx_dma_addr[i] = 0;
- }
+ pcnet32_purge_rx_ring(dev);
+ pcnet32_purge_tx_ring(dev);
spin_unlock_irqrestore(&lp->lock, flags);
--
Don Fry
brazilnut@us.ibm.com
^ permalink raw reply
* Re: [PATCH 2/3] [VLAN]: Update iif when receiving via VLAN device
From: Thomas Graf @ 2006-06-29 20:55 UTC (permalink / raw)
To: jamal; +Cc: Patrick McHardy, David Miller, netdev
In-Reply-To: <20060629085111.GY1376@postel.suug.ch>
* Thomas Graf <tgraf@suug.ch> 2006-06-29 10:51
> If a packet is to be redirected, the mirred action
> shall take care of providing this information to the next netdevice.
> My additional request is to provide a flag to disable this for special
> purposes not hurting anyone.
[NET]: Use interface index to keep input device information
Using the interface index instead of a direct reference
allows a safe usage beyond the scope where an interface
could disappear.
The old input_dev field was incorrectly made dependant
on CONFIG_NET_CLS_ACT in skb_copy().
The ifb device is changed to not update iif since the only
feeder is mirred which already takes care of this.
Signed-off-by: Thomas Graf <tgraf@suug.ch>
Index: net-2.6.git/include/linux/skbuff.h
===================================================================
--- net-2.6.git.orig/include/linux/skbuff.h
+++ net-2.6.git/include/linux/skbuff.h
@@ -181,7 +181,6 @@ enum {
* @sk: Socket we are owned by
* @tstamp: Time we arrived
* @dev: Device we arrived on/are leaving by
- * @input_dev: Device we arrived on
* @h: Transport layer header
* @nh: Network layer header
* @mac: Link layer header
@@ -192,6 +191,7 @@ enum {
* @data_len: Data length
* @mac_len: Length of link layer header
* @csum: Checksum
+ * @iif: Device we arrived on
* @local_df: allow local fragmentation
* @cloned: Head may be cloned (check refcnt to be sure)
* @nohdr: Payload reference only, must not modify header
@@ -228,7 +228,6 @@ struct sk_buff {
struct sock *sk;
struct skb_timeval tstamp;
struct net_device *dev;
- struct net_device *input_dev;
union {
struct tcphdr *th;
@@ -266,6 +265,7 @@ struct sk_buff {
data_len,
mac_len,
csum;
+ int iif;
__u32 priority;
__u8 local_df:1,
cloned:1,
Index: net-2.6.git/include/net/pkt_cls.h
===================================================================
--- net-2.6.git.orig/include/net/pkt_cls.h
+++ net-2.6.git/include/net/pkt_cls.h
@@ -352,14 +352,19 @@ tcf_change_indev(struct tcf_proto *tp, c
static inline int
tcf_match_indev(struct sk_buff *skb, char *indev)
{
+ int ret = 1;
+
if (indev[0]) {
- if (!skb->input_dev)
- return 0;
- if (strcmp(indev, skb->input_dev->name))
+ struct net_device *dev;
+
+ dev = dev_get_by_index(skb->iif);
+ if (!dev)
return 0;
+ ret = !strcmp(indev, dev->name);
+ dev_put(dev);
}
- return 1;
+ return ret;
}
#endif /* CONFIG_NET_CLS_IND */
Index: net-2.6.git/net/core/dev.c
===================================================================
--- net-2.6.git.orig/net/core/dev.c
+++ net-2.6.git/net/core/dev.c
@@ -1715,8 +1715,8 @@ static int ing_filter(struct sk_buff *sk
if (dev->qdisc_ingress) {
__u32 ttl = (__u32) G_TC_RTTL(skb->tc_verd);
if (MAX_RED_LOOP < ttl++) {
- printk("Redir loop detected Dropping packet (%s->%s)\n",
- skb->input_dev->name, skb->dev->name);
+ printk("Redir loop detected Dropping packet (%d->%s)\n",
+ skb->iif, skb->dev->name);
return TC_ACT_SHOT;
}
@@ -1749,8 +1749,8 @@ int netif_receive_skb(struct sk_buff *sk
if (!skb->tstamp.off_sec)
net_timestamp(skb);
- if (!skb->input_dev)
- skb->input_dev = skb->dev;
+ if (!skb->iif)
+ skb->iif = skb->dev->ifindex;
orig_dev = skb_bond(skb);
Index: net-2.6.git/net/core/skbuff.c
===================================================================
--- net-2.6.git.orig/net/core/skbuff.c
+++ net-2.6.git/net/core/skbuff.c
@@ -463,10 +463,10 @@ struct sk_buff *skb_clone(struct sk_buff
n->tc_verd = SET_TC_VERD(skb->tc_verd,0);
n->tc_verd = CLR_TC_OK2MUNGE(n->tc_verd);
n->tc_verd = CLR_TC_MUNGED(n->tc_verd);
- C(input_dev);
#endif
skb_copy_secmark(n, skb);
#endif
+ C(iif);
C(truesize);
atomic_set(&n->users, 1);
C(head);
Index: net-2.6.git/net/sched/act_api.c
===================================================================
--- net-2.6.git.orig/net/sched/act_api.c
+++ net-2.6.git/net/sched/act_api.c
@@ -156,9 +156,8 @@ int tcf_action_exec(struct sk_buff *skb,
if (skb->tc_verd & TC_NCLS) {
skb->tc_verd = CLR_TC_NCLS(skb->tc_verd);
- D2PRINTK("(%p)tcf_action_exec: cleared TC_NCLS in %s out %s\n",
- skb, skb->input_dev ? skb->input_dev->name : "xxx",
- skb->dev->name);
+ D2PRINTK("(%p)tcf_action_exec: cleared TC_NCLS in %d out %s\n",
+ skb, skb->iif, skb->dev->name);
ret = TC_ACT_OK;
goto exec_done;
}
Index: net-2.6.git/net/sched/act_mirred.c
===================================================================
--- net-2.6.git.orig/net/sched/act_mirred.c
+++ net-2.6.git/net/sched/act_mirred.c
@@ -207,7 +207,7 @@ bad_mirred:
skb2->tc_verd = SET_TC_FROM(skb2->tc_verd, at);
skb2->dev = dev;
- skb2->input_dev = skb->dev;
+ skb2->iif = skb->dev->ifindex;
dev_queue_xmit(skb2);
spin_unlock(&p->lock);
return p->action;
Index: net-2.6.git/drivers/net/ifb.c
===================================================================
--- net-2.6.git.orig/drivers/net/ifb.c
+++ net-2.6.git/drivers/net/ifb.c
@@ -158,7 +158,7 @@ static int ifb_xmit(struct sk_buff *skb,
stats->tx_packets++;
stats->tx_bytes+=skb->len;
- if (!from || !skb->input_dev) {
+ if (!from || !skb->iif) {
dropped:
dev_kfree_skb(skb);
stats->rx_dropped++;
@@ -169,8 +169,7 @@ dropped:
* ingress -> egress or
* egress -> ingress
*/
- skb->dev = skb->input_dev;
- skb->input_dev = dev;
+ skb->dev = dev;
if (from & AT_INGRESS) {
skb_pull(skb, skb->dev->hard_header_len);
} else {
^ permalink raw reply
* [PATCH 8/9] pcnet32: NAPI implementation.
From: Don Fry @ 2006-06-29 20:55 UTC (permalink / raw)
To: tsbogend, jgarzik, netdev
Implement NAPI changes to pcnet32 driver. Compile default is off.
Listed as experimental.
Len and Don both worked on a NAPI implementation and have both tested
these changes.
An e1000 blasting short packets to the pcnet32 will lockup Don's system
until the receive storm stops. Without NAPI Len's system watchdog would
expire causing the system to reboot. With NAPI the system will stay
operational.
Tested ia32 and ppc64. Tested '970A, '971, '972, '973, '975, '976, and
'978.
The Kconfig changes came from Len. Don is to blame for all the others.
Signed-off-by: Len Sorensen <lsorense@csclub.uwaterloo.ca>
Signed-off-by: Don Fry <brazilnut@us.ibm.com>
--- linux-2.6.17-git13/drivers/net/orig.Kconfig Wed Jun 28 10:38:45 2006
+++ linux-2.6.17-git13/drivers/net/Kconfig Wed Jun 28 15:36:25 2006
@@ -1300,6 +1300,23 @@ config PCNET32
<file:Documentation/networking/net-modules.txt>. The module
will be called pcnet32.
+config PCNET32_NAPI
+ bool "Use RX polling (NAPI) (EXPERIMENTAL)"
+ depends on PCNET32 && EXPERIMENTAL
+ help
+ NAPI is a new driver API designed to reduce CPU and interrupt load
+ when the driver is receiving lots of packets from the card. It is
+ still somewhat experimental and thus not yet enabled by default.
+
+ If your estimated Rx load is 10kpps or more, or if the card will be
+ deployed on potentially unfriendly networks (e.g. in a firewall),
+ then say Y here.
+
+ See <file:Documentation/networking/NAPI_HOWTO.txt> for more
+ information.
+
+ If in doubt, say N.
+
config AMD8111_ETH
tristate "AMD 8111 (new PCI lance) support"
depends on NET_PCI && PCI
--- linux-2.6.17-git13/drivers/net/purge.pcnet32.c Thu Jun 29 13:28:24 2006
+++ linux-2.6.17-git13/drivers/net/pcnet32.c Thu Jun 29 13:28:31 2006
@@ -21,9 +21,15 @@
*
*************************************************************************/
+#include <linux/config.h>
+
#define DRV_NAME "pcnet32"
-#define DRV_VERSION "1.32"
-#define DRV_RELDATE "18.Mar.2006"
+#ifdef CONFIG_PCNET32_NAPI
+#define DRV_VERSION "1.33-NAPI"
+#else
+#define DRV_VERSION "1.33"
+#endif
+#define DRV_RELDATE "27.Jun.2006"
#define PFX DRV_NAME ": "
static const char *const version =
@@ -296,7 +302,6 @@ static int pcnet32_probe1(unsigned long,
static int pcnet32_open(struct net_device *);
static int pcnet32_init_ring(struct net_device *);
static int pcnet32_start_xmit(struct sk_buff *, struct net_device *);
-static int pcnet32_rx(struct net_device *);
static void pcnet32_tx_timeout(struct net_device *dev);
static irqreturn_t pcnet32_interrupt(int, void *, struct pt_regs *);
static int pcnet32_close(struct net_device *);
@@ -878,7 +883,11 @@ static int pcnet32_loopback_test(struct
rc = 1; /* default to fail */
if (netif_running(dev))
+#ifdef CONFIG_PCNET32_NAPI
+ pcnet32_netif_stop(dev);
+#else
pcnet32_close(dev);
+#endif
spin_lock_irqsave(&lp->lock, flags);
lp->a.write_csr(ioaddr, CSR0, CSR0_STOP); /* stop the chip */
@@ -1010,6 +1019,16 @@ static int pcnet32_loopback_test(struct
x = a->read_bcr(ioaddr, 32); /* reset internal loopback */
a->write_bcr(ioaddr, 32, (x & ~0x0002));
+#ifdef CONFIG_PCNET32_NAPI
+ if (netif_running(dev)) {
+ pcnet32_netif_start(dev);
+ pcnet32_restart(dev, CSR0_NORMAL);
+ } else {
+ pcnet32_purge_rx_ring(dev);
+ lp->a.write_bcr(ioaddr, 20, 4); /* return to 16bit mode */
+ }
+ spin_unlock_irqrestore(&lp->lock, flags);
+#else
if (netif_running(dev)) {
spin_unlock_irqrestore(&lp->lock, flags);
pcnet32_open(dev);
@@ -1018,6 +1037,7 @@ static int pcnet32_loopback_test(struct
lp->a.write_bcr(ioaddr, 20, 4); /* return to 16bit mode */
spin_unlock_irqrestore(&lp->lock, flags);
}
+#endif
return (rc);
} /* end pcnet32_loopback_test */
@@ -1116,6 +1136,285 @@ static int pcnet32_suspend(struct net_de
return 1;
}
+static int pcnet32_rx_entry(struct net_device *dev,
+ struct pcnet32_private *lp,
+ struct pcnet32_rx_head *rxp,
+ int entry)
+{
+ int status = (short)le16_to_cpu(rxp->status) >> 8;
+ int rx_in_place = 0;
+ struct sk_buff *skb;
+ short pkt_len;
+
+ if (status != 0x03) { /* There was an error. */
+ /*
+ * There is a tricky error noted by John Murphy,
+ * <murf@perftech.com> to Russ Nelson: Even with full-sized
+ * buffers it's possible for a jabber packet to use two
+ * buffers, with only the last correctly noting the error.
+ */
+ if (status & 0x01) /* Only count a general error at the */
+ lp->stats.rx_errors++; /* end of a packet. */
+ if (status & 0x20)
+ lp->stats.rx_frame_errors++;
+ if (status & 0x10)
+ lp->stats.rx_over_errors++;
+ if (status & 0x08)
+ lp->stats.rx_crc_errors++;
+ if (status & 0x04)
+ lp->stats.rx_fifo_errors++;
+ return 1;
+ }
+
+ pkt_len = (le32_to_cpu(rxp->msg_length) & 0xfff) - 4;
+
+ /* Discard oversize frames. */
+ if (unlikely(pkt_len > PKT_BUF_SZ - 2)) {
+ if (netif_msg_drv(lp))
+ printk(KERN_ERR "%s: Impossible packet size %d!\n",
+ dev->name, pkt_len);
+ lp->stats.rx_errors++;
+ return 1;
+ }
+ if (pkt_len < 60) {
+ if (netif_msg_rx_err(lp))
+ printk(KERN_ERR "%s: Runt packet!\n", dev->name);
+ lp->stats.rx_errors++;
+ return 1;
+ }
+
+ if (pkt_len > rx_copybreak) {
+ struct sk_buff *newskb;
+
+ if ((newskb = dev_alloc_skb(PKT_BUF_SZ))) {
+ skb_reserve(newskb, 2);
+ skb = lp->rx_skbuff[entry];
+ pci_unmap_single(lp->pci_dev,
+ lp->rx_dma_addr[entry],
+ PKT_BUF_SZ - 2,
+ PCI_DMA_FROMDEVICE);
+ skb_put(skb, pkt_len);
+ lp->rx_skbuff[entry] = newskb;
+ newskb->dev = dev;
+ lp->rx_dma_addr[entry] =
+ pci_map_single(lp->pci_dev,
+ newskb->data,
+ PKT_BUF_SZ - 2,
+ PCI_DMA_FROMDEVICE);
+ rxp->base = le32_to_cpu(lp->rx_dma_addr[entry]);
+ rx_in_place = 1;
+ } else
+ skb = NULL;
+ } else {
+ skb = dev_alloc_skb(pkt_len + 2);
+ }
+
+ if (skb == NULL) {
+ if (netif_msg_drv(lp))
+ printk(KERN_ERR
+ "%s: Memory squeeze, dropping packet.\n",
+ dev->name);
+ lp->stats.rx_dropped++;
+ return 1;
+ }
+ skb->dev = dev;
+ if (!rx_in_place) {
+ skb_reserve(skb, 2); /* 16 byte align */
+ skb_put(skb, pkt_len); /* Make room */
+ pci_dma_sync_single_for_cpu(lp->pci_dev,
+ lp->rx_dma_addr[entry],
+ PKT_BUF_SZ - 2,
+ PCI_DMA_FROMDEVICE);
+ eth_copy_and_sum(skb,
+ (unsigned char *)(lp->rx_skbuff[entry]->data),
+ pkt_len, 0);
+ pci_dma_sync_single_for_device(lp->pci_dev,
+ lp->rx_dma_addr[entry],
+ PKT_BUF_SZ - 2,
+ PCI_DMA_FROMDEVICE);
+ }
+ lp->stats.rx_bytes += skb->len;
+ lp->stats.rx_packets++;
+ skb->protocol = eth_type_trans(skb, dev);
+#ifdef CONFIG_PCNET32_NAPI
+ netif_receive_skb(skb);
+#else
+ netif_rx(skb);
+#endif
+ dev->last_rx = jiffies;
+ return 1;
+}
+
+static int pcnet32_rx(struct net_device *dev, int quota)
+{
+ struct pcnet32_private *lp = dev->priv;
+ int entry = lp->cur_rx & lp->rx_mod_mask;
+ struct pcnet32_rx_head *rxp = &lp->rx_ring[entry];
+ int npackets = 0;
+
+ /* If we own the next entry, it's a new packet. Send it up. */
+ while (quota > npackets && (short)le16_to_cpu(rxp->status) >= 0) {
+ npackets += pcnet32_rx_entry(dev, lp, rxp, entry);
+ /*
+ * The docs say that the buffer length isn't touched, but Andrew
+ * Boyd of QNX reports that some revs of the 79C965 clear it.
+ */
+ rxp->buf_length = le16_to_cpu(2 - PKT_BUF_SZ);
+ wmb(); /* Make sure owner changes after others are visible */
+ rxp->status = le16_to_cpu(0x8000);
+ entry = (++lp->cur_rx) & lp->rx_mod_mask;
+ rxp = &lp->rx_ring[entry];
+ }
+
+ return npackets;
+}
+
+static int pcnet32_tx(struct net_device *dev)
+{
+ struct pcnet32_private *lp = dev->priv;
+ unsigned int dirty_tx = lp->dirty_tx;
+ int delta;
+ int must_restart = 0;
+
+ while (dirty_tx != lp->cur_tx) {
+ int entry = dirty_tx & lp->tx_mod_mask;
+ int status = (short)le16_to_cpu(lp->tx_ring[entry].status);
+
+ if (status < 0)
+ break; /* It still hasn't been Txed */
+
+ lp->tx_ring[entry].base = 0;
+
+ if (status & 0x4000) {
+ /* There was an major error, log it. */
+ int err_status =
+ le32_to_cpu(lp->tx_ring[entry].
+ misc);
+ lp->stats.tx_errors++;
+ if (netif_msg_tx_err(lp))
+ printk(KERN_ERR
+ "%s: Tx error status=%04x err_status=%08x\n",
+ dev->name, status,
+ err_status);
+ if (err_status & 0x04000000)
+ lp->stats.tx_aborted_errors++;
+ if (err_status & 0x08000000)
+ lp->stats.tx_carrier_errors++;
+ if (err_status & 0x10000000)
+ lp->stats.tx_window_errors++;
+#ifndef DO_DXSUFLO
+ if (err_status & 0x40000000) {
+ lp->stats.tx_fifo_errors++;
+ /* Ackk! On FIFO errors the Tx unit is turned off! */
+ /* Remove this verbosity later! */
+ if (netif_msg_tx_err(lp))
+ printk(KERN_ERR
+ "%s: Tx FIFO error!\n",
+ dev->name);
+ must_restart = 1;
+ }
+#else
+ if (err_status & 0x40000000) {
+ lp->stats.tx_fifo_errors++;
+ if (!lp->dxsuflo) { /* If controller doesn't recover ... */
+ /* Ackk! On FIFO errors the Tx unit is turned off! */
+ /* Remove this verbosity later! */
+ if (netif_msg_tx_err(lp))
+ printk(KERN_ERR
+ "%s: Tx FIFO error!\n",
+ dev->name);
+ must_restart = 1;
+ }
+ }
+#endif
+ } else {
+ if (status & 0x1800)
+ lp->stats.collisions++;
+ lp->stats.tx_packets++;
+ }
+
+ /* We must free the original skb */
+ if (lp->tx_skbuff[entry]) {
+ pci_unmap_single(lp->pci_dev,
+ lp->tx_dma_addr[entry],
+ lp->tx_skbuff[entry]->
+ len, PCI_DMA_TODEVICE);
+ dev_kfree_skb_any(lp->tx_skbuff[entry]);
+ lp->tx_skbuff[entry] = NULL;
+ lp->tx_dma_addr[entry] = 0;
+ }
+ dirty_tx++;
+ }
+
+ delta = (lp->cur_tx - dirty_tx) & (lp->tx_mod_mask + lp->tx_ring_size);
+ if (delta > lp->tx_ring_size) {
+ if (netif_msg_drv(lp))
+ printk(KERN_ERR
+ "%s: out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
+ dev->name, dirty_tx, lp->cur_tx,
+ lp->tx_full);
+ dirty_tx += lp->tx_ring_size;
+ delta -= lp->tx_ring_size;
+ }
+
+ if (lp->tx_full &&
+ netif_queue_stopped(dev) &&
+ delta < lp->tx_ring_size - 2) {
+ /* The ring is no longer full, clear tbusy. */
+ lp->tx_full = 0;
+ netif_wake_queue(dev);
+ }
+ lp->dirty_tx = dirty_tx;
+
+ return must_restart;
+}
+
+#ifdef CONFIG_PCNET32_NAPI
+static int pcnet32_poll(struct net_device *dev, int *budget)
+{
+ struct pcnet32_private *lp = dev->priv;
+ int quota = min(dev->quota, *budget);
+ unsigned long ioaddr = dev->base_addr;
+ u16 val;
+ unsigned long flags;
+
+ quota = pcnet32_rx(dev, quota);
+
+ spin_lock_irqsave(&lp->lock, flags);
+ if (pcnet32_tx(dev)) {
+ /* reset the chip to clear the error condition, then restart */
+ lp->a.reset(ioaddr);
+ lp->a.write_csr(ioaddr, CSR4, 0x0915);
+ pcnet32_restart(dev, CSR0_START);
+ netif_wake_queue(dev);
+ }
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ *budget -= quota;
+ dev->quota -= quota;
+
+ if (dev->quota == 0) {
+ return 1;
+ }
+
+ netif_rx_complete(dev);
+
+ spin_lock_irqsave(&lp->lock, flags);
+
+ /* clear interrupt masks */
+ val = lp->a.read_csr(ioaddr, CSR3);
+ val &= 0x00ff;
+ lp->a.write_csr(ioaddr, CSR3, val);
+
+ /* Set interrupt enable. */
+ lp->a.write_csr(ioaddr, CSR0, CSR0_INTEN);
+
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ return 0;
+}
+#endif
+
#define PCNET32_REGS_PER_PHY 32
#define PCNET32_MAX_PHYS 32
static int pcnet32_get_regs_len(struct net_device *dev)
@@ -1651,6 +1950,10 @@ pcnet32_probe1(unsigned long ioaddr, int
dev->ethtool_ops = &pcnet32_ethtool_ops;
dev->tx_timeout = pcnet32_tx_timeout;
dev->watchdog_timeo = (5 * HZ);
+ dev->weight = lp->rx_ring_size / 2;
+#ifdef CONFIG_PCNET32_NAPI
+ dev->poll = pcnet32_poll;
+#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = pcnet32_poll_controller;
@@ -2253,9 +2556,9 @@ pcnet32_interrupt(int irq, void *dev_id,
struct net_device *dev = dev_id;
struct pcnet32_private *lp;
unsigned long ioaddr;
- u16 csr0, rap;
int boguscnt = max_interrupt_work;
- int must_restart;
+ u16 csr0;
+ irqreturn_t rc = IRQ_HANDLED;
if (!dev) {
if (pcnet32_debug & NETIF_MSG_INTR)
@@ -2269,141 +2572,33 @@ pcnet32_interrupt(int irq, void *dev_id,
spin_lock(&lp->lock);
- rap = lp->a.read_rap(ioaddr);
- while ((csr0 = lp->a.read_csr(ioaddr, 0)) & 0x8f00 && --boguscnt >= 0) {
- if (csr0 == 0xffff) {
- break; /* PCMCIA remove happened */
- }
+ csr0 = lp->a.read_csr(ioaddr, CSR0);
+ if (csr0 == 0xffff) {
+ rc = IRQ_NONE;
+ } else while (csr0 & 0x8f00 && --boguscnt >= 0) {
/* Acknowledge all of the current interrupt sources ASAP. */
- lp->a.write_csr(ioaddr, 0, csr0 & ~0x004f);
-
- must_restart = 0;
+ lp->a.write_csr(ioaddr, CSR0, csr0 & ~0x004f);
if (netif_msg_intr(lp))
printk(KERN_DEBUG
"%s: interrupt csr0=%#2.2x new csr=%#2.2x.\n",
- dev->name, csr0, lp->a.read_csr(ioaddr, 0));
-
- if (csr0 & 0x0400) /* Rx interrupt */
- pcnet32_rx(dev);
-
- if (csr0 & 0x0200) { /* Tx-done interrupt */
- unsigned int dirty_tx = lp->dirty_tx;
- int delta;
-
- while (dirty_tx != lp->cur_tx) {
- int entry = dirty_tx & lp->tx_mod_mask;
- int status =
- (short)le16_to_cpu(lp->tx_ring[entry].
- status);
-
- if (status < 0)
- break; /* It still hasn't been Txed */
-
- lp->tx_ring[entry].base = 0;
-
- if (status & 0x4000) {
- /* There was an major error, log it. */
- int err_status =
- le32_to_cpu(lp->tx_ring[entry].
- misc);
- lp->stats.tx_errors++;
- if (netif_msg_tx_err(lp))
- printk(KERN_ERR
- "%s: Tx error status=%04x err_status=%08x\n",
- dev->name, status,
- err_status);
- if (err_status & 0x04000000)
- lp->stats.tx_aborted_errors++;
- if (err_status & 0x08000000)
- lp->stats.tx_carrier_errors++;
- if (err_status & 0x10000000)
- lp->stats.tx_window_errors++;
-#ifndef DO_DXSUFLO
- if (err_status & 0x40000000) {
- lp->stats.tx_fifo_errors++;
- /* Ackk! On FIFO errors the Tx unit is turned off! */
- /* Remove this verbosity later! */
- if (netif_msg_tx_err(lp))
- printk(KERN_ERR
- "%s: Tx FIFO error! CSR0=%4.4x\n",
- dev->name, csr0);
- must_restart = 1;
- }
-#else
- if (err_status & 0x40000000) {
- lp->stats.tx_fifo_errors++;
- if (!lp->dxsuflo) { /* If controller doesn't recover ... */
- /* Ackk! On FIFO errors the Tx unit is turned off! */
- /* Remove this verbosity later! */
- if (netif_msg_tx_err
- (lp))
- printk(KERN_ERR
- "%s: Tx FIFO error! CSR0=%4.4x\n",
- dev->
- name,
- csr0);
- must_restart = 1;
- }
- }
-#endif
- } else {
- if (status & 0x1800)
- lp->stats.collisions++;
- lp->stats.tx_packets++;
- }
-
- /* We must free the original skb */
- if (lp->tx_skbuff[entry]) {
- pci_unmap_single(lp->pci_dev,
- lp->tx_dma_addr[entry],
- lp->tx_skbuff[entry]->
- len, PCI_DMA_TODEVICE);
- dev_kfree_skb_irq(lp->tx_skbuff[entry]);
- lp->tx_skbuff[entry] = NULL;
- lp->tx_dma_addr[entry] = 0;
- }
- dirty_tx++;
- }
-
- delta =
- (lp->cur_tx - dirty_tx) & (lp->tx_mod_mask +
- lp->tx_ring_size);
- if (delta > lp->tx_ring_size) {
- if (netif_msg_drv(lp))
- printk(KERN_ERR
- "%s: out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
- dev->name, dirty_tx, lp->cur_tx,
- lp->tx_full);
- dirty_tx += lp->tx_ring_size;
- delta -= lp->tx_ring_size;
- }
-
- if (lp->tx_full &&
- netif_queue_stopped(dev) &&
- delta < lp->tx_ring_size - 2) {
- /* The ring is no longer full, clear tbusy. */
- lp->tx_full = 0;
- netif_wake_queue(dev);
- }
- lp->dirty_tx = dirty_tx;
- }
+ dev->name, csr0, lp->a.read_csr(ioaddr, CSR0));
/* Log misc errors. */
if (csr0 & 0x4000)
lp->stats.tx_errors++; /* Tx babble. */
if (csr0 & 0x1000) {
/*
- * this happens when our receive ring is full. This shouldn't
- * be a problem as we will see normal rx interrupts for the frames
- * in the receive ring. But there are some PCI chipsets (I can
- * reproduce this on SP3G with Intel saturn chipset) which have
- * sometimes problems and will fill up the receive ring with
- * error descriptors. In this situation we don't get a rx
- * interrupt, but a missed frame interrupt sooner or later.
- * So we try to clean up our receive ring here.
+ * This happens when our receive ring is full. This
+ * shouldn't be a problem as we will see normal rx
+ * interrupts for the frames in the receive ring. But
+ * there are some PCI chipsets (I can reproduce this
+ * on SP3G with Intel saturn chipset) which have
+ * sometimes problems and will fill up the receive
+ * ring with error descriptors. In this situation we
+ * don't get a rx interrupt, but a missed frame
+ * interrupt sooner or later.
*/
- pcnet32_rx(dev);
lp->stats.rx_errors++; /* Missed a Rx frame. */
}
if (csr0 & 0x0800) {
@@ -2413,183 +2608,41 @@ pcnet32_interrupt(int irq, void *dev_id,
dev->name, csr0);
/* unlike for the lance, there is no restart needed */
}
-
- if (must_restart) {
+#ifdef CONFIG_PCNET32_NAPI
+ if (netif_rx_schedule_prep(dev)) {
+ u16 val;
+ /* set interrupt masks */
+ val = lp->a.read_csr(ioaddr, CSR3);
+ val |= 0x5f00;
+ lp->a.write_csr(ioaddr, CSR3, val);
+ __netif_rx_schedule(dev);
+ break;
+ }
+#else
+ pcnet32_rx(dev, dev->weight);
+ if (pcnet32_tx(dev)) {
/* reset the chip to clear the error condition, then restart */
lp->a.reset(ioaddr);
- lp->a.write_csr(ioaddr, 4, 0x0915);
- pcnet32_restart(dev, 0x0002);
+ lp->a.write_csr(ioaddr, CSR4, 0x0915);
+ pcnet32_restart(dev, CSR0_START);
netif_wake_queue(dev);
}
+#endif
+ csr0 = lp->a.read_csr(ioaddr, CSR0);
}
- /* Set interrupt enable. */
- lp->a.write_csr(ioaddr, 0, 0x0040);
- lp->a.write_rap(ioaddr, rap);
+#ifndef CONFIG_PCNET32_NAPI
+ /*Set interrupt enable. */
+ lp->a.write_csr(ioaddr, CSR0, CSR0_INTEN);
+#endif
if (netif_msg_intr(lp))
printk(KERN_DEBUG "%s: exiting interrupt, csr0=%#4.4x.\n",
- dev->name, lp->a.read_csr(ioaddr, 0));
+ dev->name, lp->a.read_csr(ioaddr, CSR0));
spin_unlock(&lp->lock);
- return IRQ_HANDLED;
-}
-
-static int pcnet32_rx(struct net_device *dev)
-{
- struct pcnet32_private *lp = dev->priv;
- int entry = lp->cur_rx & lp->rx_mod_mask;
- int boguscnt = lp->rx_ring_size / 2;
-
- /* If we own the next entry, it's a new packet. Send it up. */
- while ((short)le16_to_cpu(lp->rx_ring[entry].status) >= 0) {
- int status = (short)le16_to_cpu(lp->rx_ring[entry].status) >> 8;
-
- if (status != 0x03) { /* There was an error. */
- /*
- * There is a tricky error noted by John Murphy,
- * <murf@perftech.com> to Russ Nelson: Even with full-sized
- * buffers it's possible for a jabber packet to use two
- * buffers, with only the last correctly noting the error.
- */
- if (status & 0x01) /* Only count a general error at the */
- lp->stats.rx_errors++; /* end of a packet. */
- if (status & 0x20)
- lp->stats.rx_frame_errors++;
- if (status & 0x10)
- lp->stats.rx_over_errors++;
- if (status & 0x08)
- lp->stats.rx_crc_errors++;
- if (status & 0x04)
- lp->stats.rx_fifo_errors++;
- lp->rx_ring[entry].status &= le16_to_cpu(0x03ff);
- } else {
- /* Malloc up new buffer, compatible with net-2e. */
- short pkt_len =
- (le32_to_cpu(lp->rx_ring[entry].msg_length) & 0xfff)
- - 4;
- struct sk_buff *skb;
-
- /* Discard oversize frames. */
- if (unlikely(pkt_len > PKT_BUF_SZ - 2)) {
- if (netif_msg_drv(lp))
- printk(KERN_ERR
- "%s: Impossible packet size %d!\n",
- dev->name, pkt_len);
- lp->stats.rx_errors++;
- } else if (pkt_len < 60) {
- if (netif_msg_rx_err(lp))
- printk(KERN_ERR "%s: Runt packet!\n",
- dev->name);
- lp->stats.rx_errors++;
- } else {
- int rx_in_place = 0;
-
- if (pkt_len > rx_copybreak) {
- struct sk_buff *newskb;
-
- if ((newskb =
- dev_alloc_skb(PKT_BUF_SZ))) {
- skb_reserve(newskb, 2);
- skb = lp->rx_skbuff[entry];
- pci_unmap_single(lp->pci_dev,
- lp->
- rx_dma_addr
- [entry],
- PKT_BUF_SZ - 2,
- PCI_DMA_FROMDEVICE);
- skb_put(skb, pkt_len);
- lp->rx_skbuff[entry] = newskb;
- newskb->dev = dev;
- lp->rx_dma_addr[entry] =
- pci_map_single(lp->pci_dev,
- newskb->data,
- PKT_BUF_SZ -
- 2,
- PCI_DMA_FROMDEVICE);
- lp->rx_ring[entry].base =
- le32_to_cpu(lp->
- rx_dma_addr
- [entry]);
- rx_in_place = 1;
- } else
- skb = NULL;
- } else {
- skb = dev_alloc_skb(pkt_len + 2);
- }
-
- if (skb == NULL) {
- int i;
- if (netif_msg_drv(lp))
- printk(KERN_ERR
- "%s: Memory squeeze, deferring packet.\n",
- dev->name);
- for (i = 0; i < lp->rx_ring_size; i++)
- if ((short)
- le16_to_cpu(lp->
- rx_ring[(entry +
- i)
- & lp->
- rx_mod_mask].
- status) < 0)
- break;
-
- if (i > lp->rx_ring_size - 2) {
- lp->stats.rx_dropped++;
- lp->rx_ring[entry].status |=
- le16_to_cpu(0x8000);
- wmb(); /* Make sure adapter sees owner change */
- lp->cur_rx++;
- }
- break;
- }
- skb->dev = dev;
- if (!rx_in_place) {
- skb_reserve(skb, 2); /* 16 byte align */
- skb_put(skb, pkt_len); /* Make room */
- pci_dma_sync_single_for_cpu(lp->pci_dev,
- lp->
- rx_dma_addr
- [entry],
- PKT_BUF_SZ -
- 2,
- PCI_DMA_FROMDEVICE);
- eth_copy_and_sum(skb,
- (unsigned char *)(lp->
- rx_skbuff
- [entry]->
- data),
- pkt_len, 0);
- pci_dma_sync_single_for_device(lp->
- pci_dev,
- lp->
- rx_dma_addr
- [entry],
- PKT_BUF_SZ
- - 2,
- PCI_DMA_FROMDEVICE);
- }
- lp->stats.rx_bytes += skb->len;
- skb->protocol = eth_type_trans(skb, dev);
- netif_rx(skb);
- dev->last_rx = jiffies;
- lp->stats.rx_packets++;
- }
- }
- /*
- * The docs say that the buffer length isn't touched, but Andrew Boyd
- * of QNX reports that some revs of the 79C965 clear it.
- */
- lp->rx_ring[entry].buf_length = le16_to_cpu(2 - PKT_BUF_SZ);
- wmb(); /* Make sure owner changes after all others are visible */
- lp->rx_ring[entry].status |= le16_to_cpu(0x8000);
- entry = (++lp->cur_rx) & lp->rx_mod_mask;
- if (--boguscnt <= 0)
- break; /* don't stay in loop forever */
- }
-
- return 0;
+ return rc;
}
static int pcnet32_close(struct net_device *dev)
--
Don Fry
brazilnut@us.ibm.com
^ permalink raw reply
* [PATCH 9/9] pcnet32: Magic number cleanup.
From: Don Fry @ 2006-06-29 20:56 UTC (permalink / raw)
To: tsbogend, jgarzik, netdev
Initial magic number cleanup. Delete one unnecessary read and write.
Tested ia32 and ppc64.
Signed-off-by: Don Fry <brazilnut@us.ibm.com>
--- linux-2.6.17-git13/drivers/net/napi.pcnet32.c Thu Jun 29 13:25:50 2006
+++ linux-2.6.17-git13/drivers/net/pcnet32.c Thu Jun 29 13:30:46 2006
@@ -211,7 +211,7 @@ static int homepna[MAX_UNITS];
/* The PCNET32 Rx and Tx ring descriptors. */
struct pcnet32_rx_head {
u32 base;
- s16 buf_length;
+ s16 buf_length; /* two`s complement of length */
s16 status;
u32 msg_length;
u32 reserved;
@@ -219,7 +219,7 @@ struct pcnet32_rx_head {
struct pcnet32_tx_head {
u32 base;
- s16 length;
+ s16 length; /* two`s complement of length */
s16 status;
u32 misc;
u32 reserved;
@@ -896,7 +896,7 @@ static int pcnet32_loopback_test(struct
/* Reset the PCNET32 */
lp->a.reset(ioaddr);
- lp->a.write_csr(ioaddr, CSR4, 0x0915);
+ lp->a.write_csr(ioaddr, CSR4, 0x0915); /* auto tx pad */
/* switch pcnet32 to 32bit mode */
lp->a.write_bcr(ioaddr, 20, 2);
@@ -1384,7 +1384,7 @@ static int pcnet32_poll(struct net_devic
if (pcnet32_tx(dev)) {
/* reset the chip to clear the error condition, then restart */
lp->a.reset(ioaddr);
- lp->a.write_csr(ioaddr, CSR4, 0x0915);
+ lp->a.write_csr(ioaddr, CSR4, 0x0915); /* auto tx pad */
pcnet32_restart(dev, CSR0_START);
netif_wake_queue(dev);
}
@@ -1891,7 +1891,7 @@ pcnet32_probe1(unsigned long ioaddr, int
* boards will work.
*/
/* Trigger an initialization just for the interrupt. */
- a->write_csr(ioaddr, 0, 0x41);
+ a->write_csr(ioaddr, CSR0, CSR0_INTEN | CSR0_INIT);
mdelay(1);
dev->irq = probe_irq_off(irq_mask);
@@ -2261,9 +2261,9 @@ static int pcnet32_open(struct net_devic
#ifdef DO_DXSUFLO
if (lp->dxsuflo) { /* Disable transmit stop on underflow */
- val = lp->a.read_csr(ioaddr, 3);
+ val = lp->a.read_csr(ioaddr, CSR3);
val |= 0x40;
- lp->a.write_csr(ioaddr, 3, val);
+ lp->a.write_csr(ioaddr, CSR3, val);
}
#endif
@@ -2284,8 +2284,8 @@ static int pcnet32_open(struct net_devic
(lp->dma_addr +
offsetof(struct pcnet32_private, init_block)) >> 16);
- lp->a.write_csr(ioaddr, 4, 0x0915);
- lp->a.write_csr(ioaddr, 0, 0x0001);
+ lp->a.write_csr(ioaddr, CSR4, 0x0915); /* auto tx pad */
+ lp->a.write_csr(ioaddr, CSR0, CSR0_INIT);
netif_start_queue(dev);
@@ -2295,13 +2295,13 @@ static int pcnet32_open(struct net_devic
i = 0;
while (i++ < 100)
- if (lp->a.read_csr(ioaddr, 0) & 0x0100)
+ if (lp->a.read_csr(ioaddr, CSR0) & CSR0_IDON)
break;
/*
* We used to clear the InitDone bit, 0x0100, here but Mark Stockton
* reports that doing so triggers a bug in the '974.
*/
- lp->a.write_csr(ioaddr, 0, 0x0042);
+ lp->a.write_csr(ioaddr, CSR0, CSR0_NORMAL);
if (netif_msg_ifup(lp))
printk(KERN_DEBUG
@@ -2309,7 +2309,7 @@ static int pcnet32_open(struct net_devic
dev->name, i,
(u32) (lp->dma_addr +
offsetof(struct pcnet32_private, init_block)),
- lp->a.read_csr(ioaddr, 0));
+ lp->a.read_csr(ioaddr, CSR0));
spin_unlock_irqrestore(&lp->lock, flags);
@@ -2380,7 +2380,7 @@ static int pcnet32_init_ring(struct net_
(rx_skbuff = lp->rx_skbuff[i] =
dev_alloc_skb(PKT_BUF_SZ))) {
/* there is not much, we can do at this point */
- if (pcnet32_debug & NETIF_MSG_DRV)
+ if (netif_msg_drv(lp))
printk(KERN_ERR
"%s: pcnet32_init_ring dev_alloc_skb failed.\n",
dev->name);
@@ -2430,7 +2430,7 @@ static void pcnet32_restart(struct net_d
/* wait for stop */
for (i = 0; i < 100; i++)
- if (lp->a.read_csr(ioaddr, 0) & 0x0004)
+ if (lp->a.read_csr(ioaddr, CSR0) & CSR0_STOP)
break;
if (i >= 100 && netif_msg_drv(lp))
@@ -2443,13 +2443,13 @@ static void pcnet32_restart(struct net_d
return;
/* ReInit Ring */
- lp->a.write_csr(ioaddr, 0, 1);
+ lp->a.write_csr(ioaddr, CSR0, CSR0_INIT);
i = 0;
while (i++ < 1000)
- if (lp->a.read_csr(ioaddr, 0) & 0x0100)
+ if (lp->a.read_csr(ioaddr, CSR0) & CSR0_IDON)
break;
- lp->a.write_csr(ioaddr, 0, csr0_bits);
+ lp->a.write_csr(ioaddr, CSR0, csr0_bits);
}
static void pcnet32_tx_timeout(struct net_device *dev)
@@ -2462,8 +2462,8 @@ static void pcnet32_tx_timeout(struct ne
if (pcnet32_debug & NETIF_MSG_DRV)
printk(KERN_ERR
"%s: transmit timed out, status %4.4x, resetting.\n",
- dev->name, lp->a.read_csr(ioaddr, 0));
- lp->a.write_csr(ioaddr, 0, 0x0004);
+ dev->name, lp->a.read_csr(ioaddr, CSR0));
+ lp->a.write_csr(ioaddr, CSR0, CSR0_STOP);
lp->stats.tx_errors++;
if (netif_msg_tx_err(lp)) {
int i;
@@ -2485,7 +2485,7 @@ static void pcnet32_tx_timeout(struct ne
le16_to_cpu(lp->tx_ring[i].status));
printk("\n");
}
- pcnet32_restart(dev, 0x0042);
+ pcnet32_restart(dev, CSR0_NORMAL);
dev->trans_start = jiffies;
netif_wake_queue(dev);
@@ -2506,7 +2506,7 @@ static int pcnet32_start_xmit(struct sk_
if (netif_msg_tx_queued(lp)) {
printk(KERN_DEBUG
"%s: pcnet32_start_xmit() called, csr0 %4.4x.\n",
- dev->name, lp->a.read_csr(ioaddr, 0));
+ dev->name, lp->a.read_csr(ioaddr, CSR0));
}
/* Default status -- will not enable Successful-TxDone
@@ -2537,7 +2537,7 @@ static int pcnet32_start_xmit(struct sk_
lp->stats.tx_bytes += skb->len;
/* Trigger an immediate send poll. */
- lp->a.write_csr(ioaddr, 0, 0x0048);
+ lp->a.write_csr(ioaddr, CSR0, CSR0_INTEN | CSR0_TXPOLL);
dev->trans_start = jiffies;
@@ -2623,7 +2623,7 @@ pcnet32_interrupt(int irq, void *dev_id,
if (pcnet32_tx(dev)) {
/* reset the chip to clear the error condition, then restart */
lp->a.reset(ioaddr);
- lp->a.write_csr(ioaddr, CSR4, 0x0915);
+ lp->a.write_csr(ioaddr, CSR4, 0x0915); /* auto tx pad */
pcnet32_restart(dev, CSR0_START);
netif_wake_queue(dev);
}
@@ -2662,10 +2662,10 @@ static int pcnet32_close(struct net_devi
if (netif_msg_ifdown(lp))
printk(KERN_DEBUG
"%s: Shutting down ethercard, status was %2.2x.\n",
- dev->name, lp->a.read_csr(ioaddr, 0));
+ dev->name, lp->a.read_csr(ioaddr, CSR0));
/* We stop the PCNET32 here -- it occasionally polls memory if we don't. */
- lp->a.write_csr(ioaddr, 0, 0x0004);
+ lp->a.write_csr(ioaddr, CSR0, CSR0_STOP);
/*
* Switch back to 16bit mode to avoid problems with dumb
@@ -2691,13 +2691,10 @@ static struct net_device_stats *pcnet32_
{
struct pcnet32_private *lp = dev->priv;
unsigned long ioaddr = dev->base_addr;
- u16 saved_addr;
unsigned long flags;
spin_lock_irqsave(&lp->lock, flags);
- saved_addr = lp->a.read_rap(ioaddr);
lp->stats.rx_missed_errors = lp->a.read_csr(ioaddr, 112);
- lp->a.write_rap(ioaddr, saved_addr);
spin_unlock_irqrestore(&lp->lock, flags);
return &lp->stats;
--
Don Fry
brazilnut@us.ibm.com
^ permalink raw reply
* Re: [PATCH] improved statistics for bcm43xx-softmac
From: Dan Williams @ 2006-06-29 20:56 UTC (permalink / raw)
To: Larry Finger; +Cc: John Linville, netdev
In-Reply-To: <44A3524C.40704@lwfinger.net>
On Wed, 2006-06-28 at 23:08 -0500, Larry Finger wrote:
> This patch improves the statistics returned from bcm43xx_get_wireless_stats. The signal level comes
> from smoothing the rssi value returned by the firmware. The quality value is a hack derived from the
> smoothed rssi value and an assumed rssi_max of -25. If anyone has a better value, please let me
> know. The noise value is still the one calculated from the clean-room formula. On my system, this is
> roughly -65 dBm, which seems too high. I would appreciate getting any ideas on what other
> interface/driver combinations get for the noise value.
Tentative NAK, this looks somewhat wrong... are you _really_ getting
quality values as RSSI, or as dBm?
RSSI is usually a positive integer from 0 to some larger number. It's
an arbitrary value and the maximum will be specific to the
chipset/radio/firmware.
dBm is usually bounded by (noise floor, 0), where noise floor is a
negative number around -100.
To me, it looks like you're trying to use dBm rather than RSSI here. In
that case, you have to set range->max_qual.level to 0, because the upper
bound of dBm is indeed 0. If you are using negative values _anywhere_
in your code for quality, you're almost certainly using dBm, not RSSI,
or something is very wrong.
Print out the value of 'average' from handle_irq_noise() both when close
and far away from the AP. It looks to me like the final calculations
there come out in dBm given the fact that (a) average is negative, and
(b) that average is in the range of acceptable dBm numbers. So:
1. set your stats->max_qual.level = 0
2. set bcm->stats.link_quality = average
3. Do link quality calculation on signal and noise; you can't just be
linear here though, since a noise floor of -100 with a signal of -90 is
in reality better than 10% signal; it's actually pretty OK. Each -1 dBm
step near the noise floor counts for more % than a -1 dBm increase near
the best signal level. You have to weight the bottom of the scale WRT
percentage to get values that make sense.
ipw2200 for example reports -53 dBm near the AP, with noise floor of -83
dBm in a fairly spectrum-crowded area. That translates into what
ipw2200 reports as a 75% signal, which seems a bit off, but gives you an
idea. You'll never get near 0 dBm, since there's already 10s of dBm
loss when the signal has to cross any air at all.
Dan
> Signed-Off-By: Larry Finger <Larry.Finger@lwfinger.net>
>
> ==========================================================
>
> diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
> index af97755..c80fdcd 100644
> --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
> +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
> @@ -1581,17 +1581,8 @@ static void handle_irq_noise(struct bcm4
> else
> average -= 48;
>
> -/* FIXME: This is wrong, but people want fancy stats. well... */
> -bcm->stats.noise = average;
> - if (average > -65)
> - bcm->stats.link_quality = 0;
> - else if (average > -75)
> - bcm->stats.link_quality = 1;
> - else if (average > -85)
> - bcm->stats.link_quality = 2;
> - else
> - bcm->stats.link_quality = 3;
> -// dprintk(KERN_INFO PFX "Link Quality: %u (avg was %d)\n", bcm->stats.link_quality, average);
> +/* FIXME: This matches the formula from the clean-room, but yields a value that is probably too
> large. */
> + bcm->stats.noise = average;
> drop_calculation:
> bcm->noisecalc.calculation_running = 0;
> return;
> diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
> index 5c36e29..8224da1 100644
> --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
> +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
> @@ -47,6 +47,8 @@ #include "bcm43xx_phy.h"
> #define BCM43xx_WX_VERSION 18
>
> #define MAX_WX_STRING 80
> +/* FIXME: the next line is a guess as to what the maximum value of rssi might be */
> +#define RSSI_MAX -25
>
>
> static int bcm43xx_wx_get_name(struct net_device *net_dev,
> @@ -227,15 +229,15 @@ static int bcm43xx_wx_get_rangeparams(st
>
> range->max_qual.qual = 100;
> /* TODO: Real max RSSI */
> - range->max_qual.level = 3;
> - range->max_qual.noise = 100;
> - range->max_qual.updated = 7;
> -
> - range->avg_qual.qual = 70;
> - range->avg_qual.level = 2;
> - range->avg_qual.noise = 40;
> - range->avg_qual.updated = 7;
> -
> + range->max_qual.level = -100;
> + range->max_qual.noise = -100;
> + range->max_qual.updated = IW_QUAL_ALL_UPDATED;
> +
> + range->avg_qual.qual = 50;
> + range->avg_qual.level = -40;
> + range->avg_qual.noise = -65;
> + range->avg_qual.updated = IW_QUAL_ALL_UPDATED;
> +
> range->min_rts = BCM43xx_MIN_RTS_THRESHOLD;
> range->max_rts = BCM43xx_MAX_RTS_THRESHOLD;
> range->min_frag = MIN_FRAG_THRESHOLD;
> @@ -827,6 +829,8 @@ static struct iw_statistics *bcm43xx_get
> struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
> struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
> struct iw_statistics *wstats;
> + struct ieee80211_network *network = NULL;
> + static int tmp_level = 0;
>
> wstats = &bcm->stats.wstats;
> if (!mac->associated) {
> @@ -849,11 +853,19 @@ static struct iw_statistics *bcm43xx_get
> return wstats;
> }
> /* fill in the real statistics when iface associated */
> - wstats->qual.qual = 100; // TODO: get the real signal quality
> - wstats->qual.level = 3 - bcm->stats.link_quality;
> + list_for_each_entry(network, &mac->ieee->network_list, list) {
> + if (!memcmp(mac->associnfo.bssid, network->bssid, ETH_ALEN)) {
> + if (!tmp_level) /* get initial value */
> + tmp_level = network->stats.rssi;
> + else /* smooth results */
> + tmp_level = (7 * tmp_level + network->stats.rssi)/8;
> + break;
> + }
> + }
> + wstats->qual.level = tmp_level;
> + wstats->qual.qual = 100 + tmp_level - RSSI_MAX; // TODO: get the real signal quality
> wstats->qual.noise = bcm->stats.noise;
> - wstats->qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED |
> - IW_QUAL_NOISE_UPDATED;
> + wstats->qual.updated = IW_QUAL_ALL_UPDATED;
> wstats->discard.code = bcm->ieee->ieee_stats.rx_discards_undecryptable;
> wstats->discard.retries = bcm->ieee->ieee_stats.tx_retry_limit_exceeded;
> wstats->discard.nwid = bcm->ieee->ieee_stats.tx_discards_wrong_sa;
>
> ==================
>
> -
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: 2.6.17-mm4
From: Michal Piotrowski @ 2006-06-29 20:57 UTC (permalink / raw)
To: Dave Jones, Michal Piotrowski, Andrew Morton, linux-kernel,
netdev
In-Reply-To: <20060629204905.GF13619@redhat.com>
On 29/06/06, Dave Jones <davej@redhat.com> wrote:
> On Thu, Jun 29, 2006 at 10:46:24PM +0200, Michal Piotrowski wrote:
> > On 29/06/06, Dave Jones <davej@redhat.com> wrote:
> > >On Thu, Jun 29, 2006 at 10:39:33PM +0200, Michal Piotrowski wrote:
> > >
> > > > This looks very strange.
> > > >
> > > > BUG: unable to handle kernel paging request at virtual address 6b6b6c07
> > >
> > >Looks like a use after free.
> > >
> > > > printing eip:
> > > > c0138594
> > > > *pde=00000000
> > > > Oops: 0002 [#1]
> > > > 4K_STACK PREEMPT SMP
> > > > last sysfs file /class/net/eth0/address
> > > > Modules linked in: ipv6 af_packet ipt_REJECT xt_tcpudp x_tables
> > > > p4_clockmod speedstep_lib binfmt_misc
> > > >
> > > > (gdb) list *0xc0138594
> > > > 0xc0138594 is in __lock_acquire (include2/asm/atomic.h:96).
> > > > warning: Source file is more recent than executable.
> > >
> > >got a backtrace ?
> >
> > Unfortunately no.
>
> nothing useful from 'bt' from that gdb prompt ?
(gdb) bt
No stack.
>
> Dave
>
> --
> http://www.codemonkey.org.uk
>
Regards,
Michal
--
Michal K. K. Piotrowski
LTG - Linux Testers Group
(http://www.stardust.webpages.pl/ltg/wiki/)
^ 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