* Re: [PATCH] net/, drivers/net/ , missing EXPERIMENTAL in menus
From: Jan Engelhardt @ 2007-08-31 19:29 UTC (permalink / raw)
To: Jeff Garzik
Cc: Robert P. J. Day, Randy Dunlap, Simon Arlott, sam,
Linux Kernel Mailing List, Stefan Richter, Adrian Bunk, Gabriel C,
netdev
In-Reply-To: <46D858A9.4080506@garzik.org>
On Aug 31 2007 14:06, Jeff Garzik wrote:
>> something like BROKEN, though, has *nothing* to do with maturity. a
>> feature can be any of those maturity levels, and simultaneously be
>> BROKEN. i consider BROKEN to be what i call a "status", and different
>> status levels might be the default of normal, or KIND_OF_FLAKY or
>> TOTALLY_BORKED -- that's where BROKEN would fit in.
>
> BROKEN is definitely a maturity level. A more accurate description would be
> BITROTTING perhaps. The code in question has passed through bleeding ->
> experimental -> stable, and come out the other side.
Software is quite unlike the art of medicine. There, you would go from
'stable' to 'broken', then someone 'experiments' with you, and if
it's a bad day, you bleed out. :)
Jan
--
^ permalink raw reply
* Re: [PATCH] net/, drivers/net/ , missing EXPERIMENTAL in menus
From: Randy Dunlap @ 2007-08-31 20:16 UTC (permalink / raw)
To: Jeff Garzik
Cc: Robert P. J. Day, Randy Dunlap, Simon Arlott, sam,
Linux Kernel Mailing List, Stefan Richter, Adrian Bunk, Gabriel C,
netdev
In-Reply-To: <46D858A9.4080506@garzik.org>
On Fri, 31 Aug 2007 14:06:33 -0400 Jeff Garzik wrote:
> Robert P. J. Day wrote:
> > On Fri, 31 Aug 2007, Randy Dunlap wrote:
> >
> >> On Thu, 19 Jul 2007 23:05:57 +0100 Simon Arlott wrote:
> >>
> >>> On 19/07/07 17:19, Robert P. J. Day wrote:
> >>>> On Thu, 19 Jul 2007, Randy Dunlap wrote:
> >>>>> I think that Stefan means a patch to the kconfig source code,
> >>>>> not the the Kconfig files. Good luck. I'd still like to see it.
> >>>> yes, i understand what he wanted now. as a first step (that
> >>>> theoretically shouldn't change any behaviour), i'd patch the Kconfig
> >>>> structure to add a new attribute ("maturity") which would be allowed
> >>>> to be set to *exactly one* of a pre-defined set of values (say,
> >>>> OBSOLETE, DEPRECATED, EXPERIMENTAL, and STILLBLEEDING). and that's
> >>>> it, nothing more.
> >>>>
> >>>> don't try to do anything with any of that just yet, just add the
> >>>> infrastructure to support the (optional) association of a maturity
> >>>> level with a config option. that's step one.
> >>> What about something like this? I'm not sure if the addition to sym_init
> >>> is desirable... I also had to prefix _ to the name for now otherwise it
> >>> conflicts badly with the current symbols. It probably should stop
> >>> "depends on _BROKEN" etc. too.
> >
> > i'm sure i'm going to get shouted down here, but i really disagree
> > with "BROKEN" being considered a "maturity level". IMHO, things like
> > EXPERIMENTAL, DEPRECATED and OBSOLETE represent maturity levels, for
> > what i think are obvious reasons.
> >
> > something like BROKEN, though, has *nothing* to do with maturity. a
> > feature can be any of those maturity levels, and simultaneously be
> > BROKEN. i consider BROKEN to be what i call a "status", and different
> > status levels might be the default of normal, or KIND_OF_FLAKY or
> > TOTALLY_BORKED -- that's where BROKEN would fit in.
>
> BROKEN is definitely a maturity level. A more accurate description
> would be BITROTTING perhaps. The code in question has passed through
> bleeding -> experimental -> stable, and come out the other side.
>
> In contrast, OBSOLETE and DEPRECATED reflect high-level status not code
> quality/maturity.
What I like about the patch is that it associates some kconfig symbol
with prompt strings, so that we don't have to edit "(EXPERIMENTAL)"
all the darn time (e.g.).
I'd be quite happy with calling it "status" rather than "maturity",
and with being able to use multiple of the status tags at one time,
such as
config FOO
depends on BAR
status OBSOLETE BROKEN
---
~Randy
*** Remember to use Documentation/SubmitChecklist when testing your code ***
^ permalink raw reply
* [PATCH] Fix e100 on systems that have cache incoherent DMA
From: David Acker @ 2007-08-31 20:54 UTC (permalink / raw)
To: Auke Kok
Cc: John Ronciak, Jesse Brandeburg, Jeff Kirsher, Milton Miller,
Jeff Garzik, netdev, e1000-devel, Scott Feldman
On the systems that have cache incoherent DMA, including ARM, there is a
race condition between software allocating a new receive buffer and hardware
writing into a buffer. The two race on touching the last Receive Frame
Descriptor (RFD). It has its el-bit set and its next link equal to 0.
When hardware encounters this buffer it attempts to write data to it and
then update Status Word bits and Actual Count in the RFD. At the same time
software may try to clear the el-bit and set the link address to a new buffer.
Since the entire RFD is once cache-line, the two write operations can collide.
This can lead to the receive unit stalling or interpreting random memory as
its receive area.
The fix is to set the el-bit on and the size to 0 on the next to last buffer
in the chain. When the hardware encounters this buffer it stops and does not
write to it at all. The hardware issues an RNR interrupt with the receive
unit in the No Resources state. Software can write to the tail of the list
because it knows hardware will stop on the previous descriptor that was
marked as the end of list.
Once it has a new next to last buffer prepared, it can clear the el-bit and
set the size on the previous one. The race on this buffer is safe since
the link already points to a valid next buffer and the software can handle
the race setting the size (assuming aligned 16 bit writes are atomic with
respect to the DMA read). If the hardware sees the el-bit cleared without
the size set, it will move on to the next buffer and skip this one. If it
sees the size set but the el-bit still set, it will complete that buffer
and then RNR interrupt and wait.
Flags are kept in the software descriptor to note if the el bit is set and if
the size was 0. When software clears the RFD's el bit and set its size, it
also clears the el flag but leaves the size was 0 bit set. This way software
can identify them when the race may have occurred when cleaning the ring.
On these descriptors, it looks ahead and if the next one is complete then
hardware must have skipped the current one. Logic is added to prevent two
packets in a row being marked while the receiver is running to avoid running
in lockstep with the hardware and thereby limiting the required lookahead.
This is a patch for 2.6.23-rc4.
Signed-off-by: David Acker <dacker@roinet.com>
---
--- linux-2.6.23-rc4/drivers/net/e100.c.orig 2007-08-30 13:32:10.000000000 -0400
+++ linux-2.6.23-rc4/drivers/net/e100.c 2007-08-30 15:42:07.000000000 -0400
@@ -106,6 +106,13 @@
* the RFD, the RFD must be dma_sync'ed to maintain a consistent
* view from software and hardware.
*
+ * In order to keep updates to the RFD link field from colliding with
+ * hardware writes to mark packets complete, we use the feature that
+ * hardware will not write to a size 0 descriptor and mark the previous
+ * packet as end-of-list (EL). After updating the link, we remove EL
+ * and only then restore the size such that hardware may use the
+ * previous-to-end RFD.
+ *
* Under typical operation, the receive unit (RU) is start once,
* and the controller happily fills RFDs as frames arrive. If
* replacement RFDs cannot be allocated, or the RU goes non-active,
@@ -281,14 +288,14 @@ struct csr {
};
enum scb_status {
+ rus_no_res = 0x08,
rus_ready = 0x10,
rus_mask = 0x3C,
};
enum ru_state {
- RU_SUSPENDED = 0,
- RU_RUNNING = 1,
- RU_UNINITIALIZED = -1,
+ ru_stopped = 0,
+ ru_running = 1,
};
enum scb_stat_ack {
@@ -401,10 +408,16 @@ struct rfd {
u16 size;
};
+enum rx_flags {
+ rx_el = 0x01,
+ rx_s0 = 0x02,
+};
+
struct rx {
struct rx *next, *prev;
struct sk_buff *skb;
dma_addr_t dma_addr;
+ u8 flags;
};
#if defined(__BIG_ENDIAN_BITFIELD)
@@ -952,7 +965,7 @@ static void e100_get_defaults(struct nic
((nic->mac >= mac_82558_D101_A4) ? cb_cid : cb_i));
/* Template for a freshly allocated RFD */
- nic->blank_rfd.command = cpu_to_le16(cb_el);
+ nic->blank_rfd.command = 0;
nic->blank_rfd.rbd = 0xFFFFFFFF;
nic->blank_rfd.size = cpu_to_le16(VLAN_ETH_FRAME_LEN);
@@ -1753,18 +1766,48 @@ static int e100_alloc_cbs(struct nic *ni
return 0;
}
-static inline void e100_start_receiver(struct nic *nic, struct rx *rx)
+static void e100_find_mark_el(struct nic *nic, struct rx *marked_rx, int is_running)
{
- if(!nic->rxs) return;
- if(RU_SUSPENDED != nic->ru_running) return;
+ struct rx *rx = nic->rx_to_use->prev->prev;
+ struct rfd *rfd;
+
+ if (marked_rx == rx)
+ return;
+
+ rfd = (struct rfd *) rx->skb->data;
+ rfd->command |= cpu_to_le16(cb_el);
+ rfd->size = 0;
+ pci_dma_sync_single_for_device(nic->pdev, rx->dma_addr,
+ sizeof(struct rfd), PCI_DMA_BIDIRECTIONAL);
+ rx->flags |= (rx_el | rx_s0);
+
+ if (!marked_rx)
+ return;
+
+ rfd = (struct rfd *) marked_rx->skb->data;
+ rfd->command &= ~cpu_to_le16(cb_el);
+ pci_dma_sync_single_for_device(nic->pdev, marked_rx->dma_addr,
+ sizeof(struct rfd), PCI_DMA_BIDIRECTIONAL);
+
+ rfd->size = cpu_to_le16(VLAN_ETH_FRAME_LEN);
+ pci_dma_sync_single_for_device(nic->pdev, marked_rx->dma_addr,
+ sizeof(struct rfd), PCI_DMA_BIDIRECTIONAL);
- /* handle init time starts */
- if(!rx) rx = nic->rxs;
+ if (is_running)
+ marked_rx->flags &= ~rx_el;
+ else
+ marked_rx->flags &= ~(rx_el | rx_s0);
+}
+
+static inline void e100_start_receiver(struct nic *nic)
+{
+ if(!nic->rxs) return;
+ if (ru_stopped != nic->ru_running) return;
/* (Re)start RU if suspended or idle and RFA is non-NULL */
- if(rx->skb) {
- e100_exec_cmd(nic, ruc_start, rx->dma_addr);
- nic->ru_running = RU_RUNNING;
+ if (nic->rx_to_clean->skb) {
+ e100_exec_cmd(nic, ruc_start, nic->rx_to_clean->dma_addr);
+ nic->ru_running = ru_running;
}
}
@@ -1793,8 +1836,6 @@ static int e100_rx_alloc_skb(struct nic
struct rfd *prev_rfd = (struct rfd *)rx->prev->skb->data;
put_unaligned(cpu_to_le32(rx->dma_addr),
(u32 *)&prev_rfd->link);
- wmb();
- prev_rfd->command &= ~cpu_to_le16(cb_el);
pci_dma_sync_single_for_device(nic->pdev, rx->prev->dma_addr,
sizeof(struct rfd), PCI_DMA_TODEVICE);
}
@@ -1808,6 +1849,7 @@ static int e100_rx_indicate(struct nic *
struct sk_buff *skb = rx->skb;
struct rfd *rfd = (struct rfd *)skb->data;
u16 rfd_status, actual_size;
+ u8 status;
if(unlikely(work_done && *work_done >= work_to_do))
return -EAGAIN;
@@ -1819,9 +1861,47 @@ static int e100_rx_indicate(struct nic *
DPRINTK(RX_STATUS, DEBUG, "status=0x%04X\n", rfd_status);
- /* If data isn't ready, nothing to indicate */
- if(unlikely(!(rfd_status & cb_complete)))
+ /*
+ * If data isn't ready, nothing to indicate
+ * If both the el and s0 rx flags are set, we have hit the marked
+ * buffer but we don't know if hardware has seen it so we check
+ * the status.
+ * If only the s0 flag is set, we check the next buffer.
+ * If it is complete, we know that hardware saw the rfd el bit
+ * get cleared but did not see the rfd size get set so it
+ * skipped this buffer. We just return 0 and look at the
+ * next buffer.
+ * If only the s0 flag is set but the next buffer is
+ * not complete, we cleared the el flag as hardware
+ * hit this buffer.
+ */
+ if (unlikely(!(rfd_status & cb_complete))) {
+ u8 maskedFlags = rx->flags & (rx_el | rx_s0);
+ if (maskedFlags == (rx_el | rx_s0)) {
+ status = readb(&nic->csr->scb.status);
+ if (status & rus_no_res)
+ nic->ru_running = ru_stopped;
+ } else if (maskedFlags == rx_s0) {
+ struct rx *next_rx = rx->next;
+ struct rfd *next_rfd = (struct rfd *)next_rx->skb->data;
+ pci_dma_sync_single_for_cpu(nic->pdev,
+ next_rx->dma_addr, sizeof(struct rfd),
+ PCI_DMA_FROMDEVICE);
+ if (next_rfd->status & cpu_to_le16(cb_complete)) {
+ pci_unmap_single(nic->pdev, rx->dma_addr,
+ RFD_BUF_LEN, PCI_DMA_FROMDEVICE);
+ dev_kfree_skb_any(skb);
+ rx->skb = NULL;
+ rx->flags &= ~rx_s0;
+ return 0;
+ } else {
+ status = readb(&nic->csr->scb.status);
+ if (status & rus_no_res)
+ nic->ru_running = ru_stopped;
+ }
+ }
return -ENODATA;
+ }
/* Get actual data size */
actual_size = le16_to_cpu(rfd->actual_size) & 0x3FFF;
@@ -1832,9 +1912,15 @@ static int e100_rx_indicate(struct nic *
pci_unmap_single(nic->pdev, rx->dma_addr,
RFD_BUF_LEN, PCI_DMA_FROMDEVICE);
- /* this allows for a fast restart without re-enabling interrupts */
- if(le16_to_cpu(rfd->command) & cb_el)
- nic->ru_running = RU_SUSPENDED;
+ /*
+ * This happens when hardward sees the rfd el flag set
+ * but then sees the rfd size set as well
+ */
+ if (le16_to_cpu(rfd->command) & cb_el) {
+ status = readb(&nic->csr->scb.status);
+ if (status & rus_no_res)
+ nic->ru_running = ru_stopped;
+ }
/* Pull off the RFD and put the actual data (minus eth hdr) */
skb_reserve(skb, sizeof(struct rfd));
@@ -1865,32 +1951,34 @@ static int e100_rx_indicate(struct nic *
static void e100_rx_clean(struct nic *nic, unsigned int *work_done,
unsigned int work_to_do)
{
- struct rx *rx;
+ struct rx *rx, *marked_rx;
int restart_required = 0;
- struct rx *rx_to_start = NULL;
-
- /* are we already rnr? then pay attention!!! this ensures that
- * the state machine progression never allows a start with a
- * partially cleaned list, avoiding a race between hardware
- * and rx_to_clean when in NAPI mode */
- if(RU_SUSPENDED == nic->ru_running)
- restart_required = 1;
+ int err = 0;
/* Indicate newly arrived packets */
for(rx = nic->rx_to_clean; rx->skb; rx = nic->rx_to_clean = rx->next) {
- int err = e100_rx_indicate(nic, rx, work_done, work_to_do);
- if(-EAGAIN == err) {
- /* hit quota so have more work to do, restart once
- * cleanup is complete */
- restart_required = 0;
+ err = e100_rx_indicate(nic, rx, work_done, work_to_do);
+ /* Hit quota or no more to clean */
+ if(-EAGAIN == err || -ENODATA == err)
break;
- } else if(-ENODATA == err)
- break; /* No more to clean */
}
- /* save our starting point as the place we'll restart the receiver */
- if(restart_required)
- rx_to_start = nic->rx_to_clean;
+ /*
+ * On EAGAIN, hit quota so have more work to do, restart once
+ * cleanup is complete.
+ * Else, are we already rnr? then pay attention!!! this ensures that
+ * the state machine progression never allows a start with a
+ * partially cleaned list, avoiding a race between hardware
+ * and rx_to_clean when in NAPI mode
+ */
+ if(-EAGAIN != err && ru_stopped == nic->ru_running)
+ restart_required = 1;
+
+ marked_rx = nic->rx_to_use->prev->prev;
+ if (!(marked_rx->flags & rx_el)) {
+ marked_rx = marked_rx->prev;
+ BUG_ON(!marked_rx->flags & rx_el);
+ }
/* Alloc new skbs to refill list */
for(rx = nic->rx_to_use; !rx->skb; rx = nic->rx_to_use = rx->next) {
@@ -1898,10 +1986,12 @@ static void e100_rx_clean(struct nic *ni
break; /* Better luck next time (see watchdog) */
}
+ e100_find_mark_el(nic, marked_rx, !restart_required);
+
if(restart_required) {
// ack the rnr?
writeb(stat_ack_rnr, &nic->csr->scb.stat_ack);
- e100_start_receiver(nic, rx_to_start);
+ e100_start_receiver(nic);
if(work_done)
(*work_done)++;
}
@@ -1912,8 +2002,6 @@ static void e100_rx_clean_list(struct ni
struct rx *rx;
unsigned int i, count = nic->params.rfds.count;
- nic->ru_running = RU_UNINITIALIZED;
-
if(nic->rxs) {
for(rx = nic->rxs, i = 0; i < count; rx++, i++) {
if(rx->skb) {
@@ -1935,7 +2023,6 @@ static int e100_rx_alloc_list(struct nic
unsigned int i, count = nic->params.rfds.count;
nic->rx_to_use = nic->rx_to_clean = NULL;
- nic->ru_running = RU_UNINITIALIZED;
if(!(nic->rxs = kcalloc(count, sizeof(struct rx), GFP_ATOMIC)))
return -ENOMEM;
@@ -1950,7 +2037,9 @@ static int e100_rx_alloc_list(struct nic
}
nic->rx_to_use = nic->rx_to_clean = nic->rxs;
- nic->ru_running = RU_SUSPENDED;
+ nic->ru_running = ru_stopped;
+
+ e100_find_mark_el(nic, NULL, 0);
return 0;
}
@@ -1971,8 +2060,8 @@ static irqreturn_t e100_intr(int irq, vo
iowrite8(stat_ack, &nic->csr->scb.stat_ack);
/* We hit Receive No Resource (RNR); restart RU after cleaning */
- if(stat_ack & stat_ack_rnr)
- nic->ru_running = RU_SUSPENDED;
+ if (stat_ack & stat_ack_rnr)
+ nic->ru_running = ru_stopped;
if(likely(netif_rx_schedule_prep(netdev))) {
e100_disable_irq(nic);
@@ -2065,7 +2154,7 @@ static int e100_up(struct nic *nic)
if((err = e100_hw_init(nic)))
goto err_clean_cbs;
e100_set_multicast_list(nic->netdev);
- e100_start_receiver(nic, NULL);
+ e100_start_receiver(nic);
mod_timer(&nic->watchdog, jiffies);
if((err = request_irq(nic->pdev->irq, e100_intr, IRQF_SHARED,
nic->netdev->name, nic->netdev)))
@@ -2146,7 +2235,7 @@ static int e100_loopback_test(struct nic
mdio_write(nic->netdev, nic->mii.phy_id, MII_BMCR,
BMCR_LOOPBACK);
- e100_start_receiver(nic, NULL);
+ e100_start_receiver(nic);
if(!(skb = netdev_alloc_skb(nic->netdev, ETH_DATA_LEN))) {
err = -ENOMEM;
^ permalink raw reply
* Re: [PATCH] make _minimum_ TCP retransmission timeout configurable take 2
From: Rick Jones @ 2007-08-31 20:59 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <20070831.115706.97292718.davem@davemloft.net>
I managed to find iproute2 sources (they were debian lenny/testing
2.6.20-1) and applied the patch, and figured-out how to add a host route
back to one of my systems. I then did a change to set rto_min to 300.
I started a tcpdump and then a netperf, and then forces some
retransmissions the old fashioned way - by pulling a cable :) I then
Ctrl-C'd netperf and at that point got this:
Unable to handle kernel NULL pointer dereference (address 0000000000000038)
swapper[0]: Oops 8813272891392 [1]
Modules linked in: ipv6 sg sr_mod cdrom dm_snapshot dm_mirror dm_mod
loop button shpchp pci_hotplug joydev evdev ext3 jbd mbcache usb_storage
usbhid hid ide_core mptspi mptscsih ehci_hcd cciss ohci_hcd mptbase
scsi_transport_spi scsi_mod usbcore e1000 thermal processor fan
Pid: 0, CPU 3, comm: swapper
psr : 0000101008026038 ifs : 8000000000000001 ip : [<a000000100477600>]
Not tainted
ip is at tcp_rto_min+0x20/0x40
unat: 0000000000000000 pfs : 0000000000000307 rsc : 0000000000000003
rnat: e0000100f32917e0 bsps: e0000100f32917e8 pr : 00000000000166a5
ldrs: 0000000000000000 ccv : 0000000000010001 fpsr: 0009804c0270033f
csd : 0000000000000000 ssd : 0000000000000000
b0 : a0000001004777f0 b6 : a000000100230700 b7 : a000000100452e40
f6 : 000000000000000000000 f7 : 1003e000000000002813f
f8 : 1003e00000000001c06e2 f9 : 1003e000000000000043f
f10 : 1003e00000000000fd24b f11 : 1003e0044b82fa09b5a53
r1 : a0000001009b2710 r2 : 0000000000000000 r3 : e0000100fd317b40
r8 : 0000000000000032 r9 : 000000000000012c r10 : 0000000000000003
r11 : e000000ff07b63a0 r12 : e0000100fd317b40 r13 : e0000100fd310000
r14 : 0000000000000000 r15 : 0000000000000038 r16 : 0000000000000068
r17 : e000000ff07b6380 r18 : fffffffffffffa58 r19 : 000000008d769671
r20 : 000000008d769c19 r21 : e000000ff07b62f0 r22 : 000000008d7712e1
r23 : e000000ff07b62ec r24 : e000000ff07b637c r25 : 000000000000012c
r26 : 0000000000000032 r27 : e000000ff07b6438 r28 : e000000ff07b5fc8
r29 : e000000ff215bd80 r30 : e000000ff07b60d0 r31 : e000000ff07b6250
Call Trace:
[<a000000100013700>] show_stack+0x40/0xa0
sp=e0000100fd317710 bsp=e0000100fd311310
[<a000000100014000>] show_regs+0x840/0x880
sp=e0000100fd3178e0 bsp=e0000100fd3112b8
[<a0000001000351a0>] die+0x1a0/0x2a0
sp=e0000100fd3178e0 bsp=e0000100fd311270
[<a0000001000579d0>] ia64_do_page_fault+0x8d0/0xa00
sp=e0000100fd3178e0 bsp=e0000100fd311220
[<a00000010000b0c0>] ia64_leave_kernel+0x0/0x270
sp=e0000100fd317970 bsp=e0000100fd311220
[<a000000100477600>] tcp_rto_min+0x20/0x40
sp=e0000100fd317b40 bsp=e0000100fd311218
[<a0000001004777f0>] tcp_rtt_estimator+0x1d0/0x280
sp=e0000100fd317b40 bsp=e0000100fd3111e0
[<a000000100479110>] tcp_ack_saw_tstamp+0x50/0xc0
sp=e0000100fd317b40 bsp=e0000100fd3111c0
[<a00000010047d7a0>] tcp_ack+0x13c0/0x4380
sp=e0000100fd317b40 bsp=e0000100fd311120
[<a000000100486fa0>] tcp_rcv_state_process+0x1420/0x2100
sp=e0000100fd317b60 bsp=e0000100fd3110d8
[<a000000100498760>] tcp_v4_do_rcv+0x960/0xa80
sp=e0000100fd317b60 bsp=e0000100fd311078
[<a00000010049e830>] tcp_v4_rcv+0x19d0/0x1b20
sp=e0000100fd317b70 bsp=e0000100fd311008
[<a0000001004542f0>] ip_local_deliver+0x530/0x7c0
sp=e0000100fd317b70 bsp=e0000100fd310fd0
[<a000000100453cb0>] ip_rcv+0xe70/0xf80
sp=e0000100fd317b80 bsp=e0000100fd310f98
[<a0000001003fcb40>] netif_receive_skb+0xa20/0xb80
sp=e0000100fd317ba0 bsp=e0000100fd310f50
[<a000000213211c20>] e1000_clean_rx_irq+0x9e0/0xc00 [e1000]
sp=e0000100fd317ba0 bsp=e0000100fd310e90
[<a00000021320ce50>] e1000_clean+0x130/0x6e0 [e1000]
sp=e0000100fd317ba0 bsp=e0000100fd310e38
[<a0000001004034c0>] net_rx_action+0x1c0/0x540
sp=e0000100fd317bb0 bsp=e0000100fd310df0
[<a0000001000908f0>] __do_softirq+0xf0/0x240
sp=e0000100fd317bc0 bsp=e0000100fd310d78
[<a000000100090ab0>] do_softirq+0x70/0xc0
sp=e0000100fd317bc0 bsp=e0000100fd310d18
[<a000000100090ca0>] irq_exit+0x80/0xa0
sp=e0000100fd317bc0 bsp=e0000100fd310d00
[<a000000100010cc0>] ia64_handle_irq+0x2a0/0x2e0
sp=e0000100fd317bc0 bsp=e0000100fd310cd0
[<a00000010000b0c0>] ia64_leave_kernel+0x0/0x270
sp=e0000100fd317bc0 bsp=e0000100fd310cd0
[<a0000001000142d0>] default_idle+0x110/0x180
sp=e0000100fd317d90 bsp=e0000100fd310c90
[<a0000001000131b0>] cpu_idle+0x210/0x2e0
sp=e0000100fd317e30 bsp=e0000100fd310c60
[<a00000010063cf50>] start_secondary+0x4b0/0x4e0
sp=e0000100fd317e30 bsp=e0000100fd310c20
[<a00000010050ae00>] __kprobes_text_end+0x340/0x370
sp=e0000100fd317e30 bsp=e0000100fd310c20
Kernel panic - not syncing: Aiee, killing interrupt handler!
Of course there isn't all that much code to tcp_rto_min:
+static u32 tcp_rto_min(struct sock *sk)
+{
+ struct dst_entry *dst = __sk_dst_get(sk);
+ u32 rto_min = TCP_RTO_MIN;
+
+ if (dst_metric_locked(dst, RTAX_RTO_MIN))
+ rto_min = dst->metrics[RTAX_RTO_MIN-1];
+ return rto_min;
+}
+
So, I went ahead and rebooted and started again:
hpcpc103:~# ./ip route add dev eth0 15.244.56.217
hpcpc103:~# ./ip route show
15.244.56.217 dev eth0 scope link
16.89.84.0/25 dev eth0 proto kernel scope link src 16.89.84.103
default via 16.89.84.1 dev eth0
hpcpc103:~# netperf -H tardy -l 30
TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to
tardy.cup.hp.com (15.244.56.217) port 0 AF_INET
hpcpc103:~# ./ip route change dev eth0 15.244.56.217 min_rto 300
Error: either "to" is duplicate, or "min_rto" is a garbage.
hpcpc103:~# ./ip route change dev eth0 15.244.56.217 rto_min 300
hpcpc103:~# ./ip route show
15.244.56.217 dev eth0 scope link rto_min lock 1200ms
16.89.84.0/25 dev eth0 proto kernel scope link src 16.89.84.103
default via 16.89.84.1 dev eth0
300 became 1200
hpcpc103:~# ./ip route change dev eth0 15.244.56.217 rto_min 600
hpcpc103:~# ./ip route show
15.244.56.217 dev eth0 scope link rto_min lock 2400ms
16.89.84.0/25 dev eth0 proto kernel scope link src 16.89.84.103
default via 16.89.84.1 dev eth0
600 became 2400 ms but that is window dressing at the moment. Go ahead
and run netperf and let it finish on its own:
hpcpc103:~# netperf -H tardy
TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to
tardy.cup.hp.com (15.244.56.217) port 0 AF_INET
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
32768 16384 16384 10.02 72.81
hpcpc103:~#
now try it and abort netperf in the middle:
hpcpc103:~# netperf -H tardy -l 30
TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to
tardy.cup.hp.com (15.244.56.217) port 0 AF_INET
hpcpc103:~#
hmm, didn't happen again. Now try with some RTO's forced:
hpcpc103:~# netperf -H tardy -l 30
TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to
tardy.cup.hp.com (15.244.56.217) port 0 AF_INET
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
32768 16384 16384 30.02 32.69
still happy. forced RTO's and abort:
hpcpc103:~# netperf -H tardy -l 30
TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to
tardy.cup.hp.com (15.244.56.217) port 0 AF_INET
hpcpc103:~#
ok still happy. So the failure is at best intermittant. One final
thing - try adding the tcpudmp again:
hpcpc103:~# device eth0 entered promiscuous mode
audit(1188593799.036:2): dev=eth0 prom=256 old_prom=0 auid=4294967295
netperf -H tardy -l 30
TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to
tardy.cup.hp.com (15.244.56.217) port 0 AF_INET
hpcpc103:~#
still happy. Sigh, so much for easily reproducing the panic :(
rick
that second tcpdump does show the rto_min being honored:
16:56:46.543603 IP tardy.cup.hp.com.52620 > hpcpc103.cup.hp.com.51691: .
ack 29438433 win 32768 <nop,nop,timestamp 7997540 54018>
16:56:46.543608 IP hpcpc103.cup.hp.com.51691 > tardy.cup.hp.com.52620: .
29438433:29454361(15928) ack 1 win 46 <nop,nop,timestamp 54018 7997540>
16:56:46.543613 IP hpcpc103.cup.hp.com.51691 > tardy.cup.hp.com.52620: P
29454361:29470289(15928) ack 1 win 46 <nop,nop,timestamp 54018 7997540>
16:56:48.956342 IP hpcpc103.cup.hp.com.51691 > tardy.cup.hp.com.52620: .
29438433:29439881(1448) ack 1 win 46 <nop,nop,timestamp 54622 7997540>
16:56:53.788276 IP hpcpc103.cup.hp.com.51691 > tardy.cup.hp.com.52620: .
29438433:29439881(1448) ack 1 win 46 <nop,nop,timestamp 55830 7997540>
16:56:53.855520 IP tardy.cup.hp.com.52620 > hpcpc103.cup.hp.com.51691: .
ack 29439881 win 32768 <nop,nop,timestamp 7998272 55830>
16:56:53.855526 IP hpcpc103.cup.hp.com.51691 > tardy.cup.hp.com.52620: .
29439881:29441329(1448) ack 1 win 46 <nop,nop,timestamp 55846 7998272>
16:56:53.855530 IP hpcpc103.cup.hp.com.51691 > tardy.cup.hp.com.52620: .
29441329:29442777(1448) ack 1 win 46 <nop,nop,timestamp 55846 7998272>
16:56:53.925505 IP tardy.cup.hp.com.52620 > hpcpc103.cup.hp.com.51691: .
ack 29442777 win 32768 <nop,nop,timestamp 7998279 55846>
16:56:53.925511 IP hpcpc103.cup.hp.com.51691 > tardy.cup.hp.com.52620: .
29442777:29444225(1448) ack 1 win 46 <nop,nop,timestamp 55864 7998279>
^ permalink raw reply
* Re: [PATCH] net/, drivers/net/ , missing EXPERIMENTAL in menus
From: Robert P. J. Day @ 2007-08-31 20:49 UTC (permalink / raw)
To: Jeff Garzik
Cc: Randy Dunlap, Simon Arlott, sam, Linux Kernel Mailing List,
Stefan Richter, Adrian Bunk, Gabriel C, netdev
In-Reply-To: <46D858A9.4080506@garzik.org>
On Fri, 31 Aug 2007, Jeff Garzik wrote:
> Robert P. J. Day wrote:
> > i'm sure i'm going to get shouted down here, but i really disagree
> > with "BROKEN" being considered a "maturity level". IMHO, things
> > like EXPERIMENTAL, DEPRECATED and OBSOLETE represent maturity
> > levels, for what i think are obvious reasons.
> >
> > something like BROKEN, though, has *nothing* to do with maturity.
> > a feature can be any of those maturity levels, and simultaneously
> > be BROKEN. i consider BROKEN to be what i call a "status", and
> > different status levels might be the default of normal, or
> > KIND_OF_FLAKY or TOTALLY_BORKED -- that's where BROKEN would fit
> > in.
>
> BROKEN is definitely a maturity level.
no. it's not. end of discussion. you're wrong.
the concept of "maturity level" reflects where in the life cycle some
feature is. it will typically start as "bleeding edge" or
"experimental" or something like that, eventually stabilize to be
normal (which would be the obvious default), after which, when its
value starts to run out and it begins showing its age, it becomes
"deprecated" and eventually "obsolete" it's a natural and obvious
progression.
on the other hand, a feature can be "broken" at *any* point in that
life cycle -- that's why it is absolutely *not* a maturity level.
please don't fight with me on this, jeff. you're simply wrong.
> In contrast, OBSOLETE and DEPRECATED reflect high-level status not
> code quality/maturity.
you have this so backwards, i can't begin to think how to explain it
to you.
rday
--
========================================================================
Robert P. J. Day
Linux Consulting, Training and Annoying Kernel Pedantry
Waterloo, Ontario, CANADA
http://crashcourse.ca
========================================================================
^ permalink raw reply
* Re: [PATCH] net/, drivers/net/ , missing EXPERIMENTAL in menus
From: Robert P. J. Day @ 2007-08-31 21:00 UTC (permalink / raw)
To: Randy Dunlap
Cc: Jeff Garzik, Simon Arlott, sam, Linux Kernel Mailing List,
Stefan Richter, Adrian Bunk, Gabriel C, netdev
In-Reply-To: <20070831131612.312664ef.rdunlap@xenotime.net>
On Fri, 31 Aug 2007, Randy Dunlap wrote:
> What I like about the patch is that it associates some kconfig
> symbol with prompt strings, so that we don't have to edit
> "(EXPERIMENTAL)" all the darn time (e.g.).
>
> I'd be quite happy with calling it "status" rather than "maturity",
> and with being able to use multiple of the status tags at one time,
> such as
>
> config FOO
> depends on BAR
> status OBSOLETE BROKEN
grrrrrrrr ... i already made my point in my earlier post. i'd
really, really like it if *this* attribute remained as "maturity". an
entirely *separate* attribute could be defined as a feature "status",
which would be entirely orthogonal to maturity level, so that the
above would be written as
maturity OBSOLETE
status BROKEN
there's a reason for this -- any feature should have exactly *one*
value for any attribute. that is, in terms of maturity, a feature
could be EXPERIMENTAL *or* DEPRECATED *or* OBSOLETE. it ***can't***
be more than one, as in both DEPRECATED *and* OBSOLETE. to allow that
flexibility is to descend into absurdity.
rday
--
========================================================================
Robert P. J. Day
Linux Consulting, Training and Annoying Kernel Pedantry
Waterloo, Ontario, CANADA
http://crashcourse.ca
========================================================================
^ permalink raw reply
* Re: [PATCH] net/, drivers/net/ , missing EXPERIMENTAL in menus
From: Randy Dunlap @ 2007-08-31 21:25 UTC (permalink / raw)
To: Robert P. J. Day
Cc: Jeff Garzik, Simon Arlott, sam, Linux Kernel Mailing List,
Stefan Richter, Adrian Bunk, Gabriel C, netdev
In-Reply-To: <Pine.LNX.4.64.0708311656360.27345@localhost.localdomain>
On Fri, 31 Aug 2007 17:00:57 -0400 (EDT) Robert P. J. Day wrote:
> On Fri, 31 Aug 2007, Randy Dunlap wrote:
>
> > What I like about the patch is that it associates some kconfig
> > symbol with prompt strings, so that we don't have to edit
> > "(EXPERIMENTAL)" all the darn time (e.g.).
> >
> > I'd be quite happy with calling it "status" rather than "maturity",
> > and with being able to use multiple of the status tags at one time,
> > such as
> >
> > config FOO
> > depends on BAR
> > status OBSOLETE BROKEN
>
> grrrrrrrr ... i already made my point in my earlier post. i'd
> really, really like it if *this* attribute remained as "maturity". an
> entirely *separate* attribute could be defined as a feature "status",
> which would be entirely orthogonal to maturity level, so that the
> above would be written as
>
> maturity OBSOLETE
> status BROKEN
>
> there's a reason for this -- any feature should have exactly *one*
> value for any attribute. that is, in terms of maturity, a feature
> could be EXPERIMENTAL *or* DEPRECATED *or* OBSOLETE. it ***can't***
> be more than one, as in both DEPRECATED *and* OBSOLETE. to allow that
> flexibility is to descend into absurdity.
If Simon (or anyone else) continues to work on it, I'll leave this
decision up to them...
---
~Randy
*** Remember to use Documentation/SubmitChecklist when testing your code ***
^ permalink raw reply
* Re: [PATCH] make _minimum_ TCP retransmission timeout configurable take 2
From: David Miller @ 2007-08-31 21:38 UTC (permalink / raw)
To: rick.jones2; +Cc: netdev
In-Reply-To: <46D88146.9090401@hp.com>
From: Rick Jones <rick.jones2@hp.com>
Date: Fri, 31 Aug 2007 13:59:50 -0700
> ip is at tcp_rto_min+0x20/0x40
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 1ee7212..bbad2cd 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -560,7 +560,7 @@ static u32 tcp_rto_min(struct sock *sk)
struct dst_entry *dst = __sk_dst_get(sk);
u32 rto_min = TCP_RTO_MIN;
- if (dst_metric_locked(dst, RTAX_RTO_MIN))
+ if (dst && dst_metric_locked(dst, RTAX_RTO_MIN))
rto_min = dst->metrics[RTAX_RTO_MIN-1];
return rto_min;
}
^ permalink raw reply related
* [PATCH v3 0/2][BNX2]: Add iSCSI support to BNX2 devices.
From: Michael Chan @ 2007-08-31 22:35 UTC (permalink / raw)
To: davem, mchristi, netdev, open-iscsi; +Cc: anilgv, talm, lusinsky, uri
Third version of the iSCSI patch for BNX2 which has addressed the
comments we have received. I know there is general dislike about this
stuff on netdev, as shown by the RDMA discussions. iSCSI is at least a
bit more mainstream. David, please consider merging this for 2.6.24.
Thanks.
Full patch available from ftp:
ftp://Net_sys_anon@ftp1.broadcom.com/0003-BNX2-Add-iSCSI-support-to-BNX2-devices.patch
Firmware blob omitted in the next 2 emails for review.
--
[BNX2]: Add iSCSI support to BNX2 devices.
Modify bnx2 and add a cnic driver to support some offload functions
needed by iSCSI.
Add a new open-iscsi driver to support iSCSI offload on bnx2 devices.
Signed-off-by: Anil Veerabhadrappa <anilgv@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
---
drivers/net/Kconfig | 10 +
drivers/net/Makefile | 1 +
drivers/net/bnx2.c | 117 +-
drivers/net/bnx2.h | 21 +-
drivers/net/bnx2_fw.h | 7039 ++++++++++++++++++-----------
drivers/net/cnic.c | 1881 ++++++++
drivers/net/cnic.h | 163 +
drivers/net/cnic_cm.h | 555 +++
drivers/net/cnic_if.h | 152 +
drivers/scsi/Kconfig | 2 +
drivers/scsi/Makefile | 1 +
drivers/scsi/bnx2i/57xx_iscsi_constants.h | 212 +
drivers/scsi/bnx2i/57xx_iscsi_hsi.h | 1501 ++++++
drivers/scsi/bnx2i/Kconfig | 7 +
drivers/scsi/bnx2i/Makefile | 4 +
drivers/scsi/bnx2i/bnx2i.h | 841 ++++
drivers/scsi/bnx2i/bnx2i_hwi.c | 1977 ++++++++
drivers/scsi/bnx2i/bnx2i_init.c | 400 ++
drivers/scsi/bnx2i/bnx2i_iscsi.c | 3578 +++++++++++++++
drivers/scsi/bnx2i/bnx2i_sysfs.c | 615 +++
20 files changed, 16440 insertions(+), 2637 deletions(-)
create mode 100644 drivers/net/cnic.c
create mode 100644 drivers/net/cnic.h
create mode 100644 drivers/net/cnic_cm.h
create mode 100644 drivers/net/cnic_if.h
create mode 100644 drivers/scsi/bnx2i/57xx_iscsi_constants.h
create mode 100644 drivers/scsi/bnx2i/57xx_iscsi_hsi.h
create mode 100644 drivers/scsi/bnx2i/Kconfig
create mode 100644 drivers/scsi/bnx2i/Makefile
create mode 100644 drivers/scsi/bnx2i/bnx2i.h
create mode 100644 drivers/scsi/bnx2i/bnx2i_hwi.c
create mode 100644 drivers/scsi/bnx2i/bnx2i_init.c
create mode 100644 drivers/scsi/bnx2i/bnx2i_iscsi.c
create mode 100644 drivers/scsi/bnx2i/bnx2i_sysfs.c
^ permalink raw reply
* [PATCH v3 1/2][BNX2]: Add iSCSI support to BNX2 devices.
From: Michael Chan @ 2007-08-31 22:36 UTC (permalink / raw)
To: davem, mchristi, netdev, open-iscsi; +Cc: anilgv, talm, lusinsky, uri
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index b92b7dc..bde67a2 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -2253,6 +2253,16 @@ config BNX2
To compile this driver as a module, choose M here: the module
will be called bnx2. This is recommended.
+config CNIC
+ tristate "Broadcom CNIC support"
+ depends on BNX2
+ help
+ This driver supports offload features of Broadcom NetXtremeII
+ gigabit Ethernet cards.
+
+ To compile this driver as a module, choose M here: the module
+ will be called cnic. This is recommended.
+
config SPIDER_NET
tristate "Spider Gigabit Ethernet driver"
depends on PCI && (PPC_IBM_CELL_BLADE || PPC_CELLEB)
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index c964c7b..b5d8d00 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -59,6 +59,7 @@ obj-$(CONFIG_STNIC) += stnic.o 8390.o
obj-$(CONFIG_FEALNX) += fealnx.o
obj-$(CONFIG_TIGON3) += tg3.o
obj-$(CONFIG_BNX2) += bnx2.o
+obj-$(CONFIG_CNIC) += cnic.o
spidernet-y += spider_net.o spider_net_ethtool.o
obj-$(CONFIG_SPIDER_NET) += spidernet.o sungem_phy.o
obj-$(CONFIG_GELIC_NET) += ps3_gelic.o
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index e4aede6..706def2 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -242,7 +242,7 @@ static inline u32 bnx2_tx_avail(struct bnx2 *bp)
return (bp->tx_ring_size - diff);
}
-static u32
+u32
bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset)
{
u32 val;
@@ -254,7 +254,7 @@ bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset)
return val;
}
-static void
+void
bnx2_reg_wr_ind(struct bnx2 *bp, u32 offset, u32 val)
{
spin_lock_bh(&bp->indirect_lock);
@@ -263,7 +263,7 @@ bnx2_reg_wr_ind(struct bnx2 *bp, u32 offset, u32 val)
spin_unlock_bh(&bp->indirect_lock);
}
-static void
+void
bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val)
{
offset += cid_addr;
@@ -447,6 +447,26 @@ bnx2_netif_start(struct bnx2 *bp)
}
static void
+bnx2_cnic_stop(struct bnx2 *bp)
+{
+ struct cnic_ops *c_ops;
+
+ c_ops = rcu_dereference(bp->cnic_ops);
+ if (c_ops)
+ c_ops->cnic_stop(bp->cnic_data);
+}
+
+static void
+bnx2_cnic_start(struct bnx2 *bp)
+{
+ struct cnic_ops *c_ops;
+
+ c_ops = rcu_dereference(bp->cnic_ops);
+ if (c_ops)
+ c_ops->cnic_start(bp->cnic_data);
+}
+
+static void
bnx2_free_mem(struct bnx2 *bp)
{
int i;
@@ -2628,6 +2648,9 @@ bnx2_has_work(struct bnx2 *bp)
(sblk->status_attn_bits_ack & STATUS_ATTN_EVENTS))
return 1;
+ if (rcu_dereference(bp->cnic_ops) && (bp->cnic_tag != sblk->status_idx))
+ return 1;
+
return 0;
}
@@ -2640,6 +2663,7 @@ bnx2_poll(struct napi_struct *napi, int budget)
u32 status_attn_bits = sblk->status_attn_bits;
u32 status_attn_bits_ack = sblk->status_attn_bits_ack;
int work_done = 0;
+ struct cnic_ops *c_ops;
if ((status_attn_bits & STATUS_ATTN_EVENTS) !=
(status_attn_bits_ack & STATUS_ATTN_EVENTS)) {
@@ -2660,6 +2684,13 @@ bnx2_poll(struct napi_struct *napi, int budget)
if (bp->status_blk->status_rx_quick_consumer_index0 != bp->hw_rx_cons)
work_done = bnx2_rx_int(bp, budget);
+ rcu_read_lock();
+ c_ops = rcu_dereference(bp->cnic_ops);
+ if (c_ops)
+ bp->cnic_tag = c_ops->cnic_handler(bp->cnic_data,
+ bp->status_blk);
+ rcu_read_unlock();
+
bp->last_status_idx = bp->status_blk->status_idx;
rmb();
@@ -2684,6 +2715,52 @@ bnx2_poll(struct napi_struct *napi, int budget)
return work_done;
}
+int bnx2_register_cnic(struct net_device *dev, struct cnic_ops *ops, void *data)
+{
+ struct bnx2 *bp = netdev_priv(dev);
+
+ if (ops == NULL)
+ return -EINVAL;
+
+ if (netif_running(bp->dev)) {
+ struct status_block *status_blk = bp->status_blk;
+ int i = 0;
+
+ while (status_blk->status_completion_producer_index && i < 10) {
+ REG_WR(bp, BNX2_HC_COMMAND,
+ bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
+ udelay(10);
+ i++;
+ barrier();
+ }
+ if (status_blk->status_completion_producer_index) {
+ printk(KERN_ERR PFX "%s: "
+ "KCQ index not resetting to 0.\n",
+ bp->dev->name);
+ return -EBUSY;
+ }
+ }
+
+ if (!try_module_get(ops->cnic_owner))
+ return -EBUSY;
+
+ bp->cnic_tag = bp->last_status_idx;
+ bp->cnic_data = data;
+ rcu_assign_pointer(bp->cnic_ops, ops);
+
+ return 0;
+}
+
+int bnx2_unregister_cnic(struct net_device *dev)
+{
+ struct bnx2 *bp = netdev_priv(dev);
+
+ module_put(bp->cnic_ops->cnic_owner);
+ rcu_assign_pointer(bp->cnic_ops, NULL);
+ synchronize_rcu();
+ return 0;
+}
+
/* Called with rtnl_lock from vlan functions and also netif_tx_lock
* from set_multicast.
*/
@@ -2759,7 +2836,7 @@ bnx2_set_rx_mode(struct net_device *dev)
spin_unlock_bh(&bp->phy_lock);
}
-#define FW_BUF_SIZE 0x8000
+#define FW_BUF_SIZE 0x10000
static int
bnx2_gunzip_init(struct bnx2 *bp)
@@ -3099,13 +3176,15 @@ bnx2_init_cpus(struct bnx2 *bp)
cpu_reg.spad_base = BNX2_CP_SCRATCH;
cpu_reg.mips_view_base = 0x8000000;
- if (CHIP_NUM(bp) == CHIP_NUM_5709) {
+ if (CHIP_NUM(bp) == CHIP_NUM_5709)
fw = &bnx2_cp_fw_09;
+ else
+ fw = &bnx2_cp_fw_06;
+
+ rc = load_cpu_fw(bp, &cpu_reg, fw);
+ if (rc)
+ goto init_cpu_err;
- rc = load_cpu_fw(bp, &cpu_reg, fw);
- if (rc)
- goto init_cpu_err;
- }
init_cpu_err:
bnx2_gunzip_end(bp);
return rc;
@@ -5109,12 +5188,14 @@ bnx2_reset_task(struct work_struct *work)
return;
bp->in_reset_task = 1;
+ bnx2_cnic_stop(bp);
bnx2_netif_stop(bp);
bnx2_init_nic(bp);
atomic_set(&bp->intr_sem, 1);
bnx2_netif_start(bp);
+ bnx2_cnic_start(bp);
bp->in_reset_task = 0;
}
@@ -5801,9 +5882,11 @@ bnx2_set_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
bp->stats_ticks &= BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
if (netif_running(bp->dev)) {
+ bnx2_cnic_stop(bp);
bnx2_netif_stop(bp);
bnx2_init_nic(bp);
bnx2_netif_start(bp);
+ bnx2_cnic_start(bp);
}
return 0;
@@ -5837,7 +5920,9 @@ bnx2_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
return -EINVAL;
}
+
if (netif_running(bp->dev)) {
+ bnx2_cnic_stop(bp);
bnx2_netif_stop(bp);
bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);
bnx2_free_skbs(bp);
@@ -5855,6 +5940,7 @@ bnx2_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
return rc;
bnx2_init_nic(bp);
bnx2_netif_start(bp);
+ bnx2_cnic_start(bp);
}
return 0;
@@ -6080,6 +6166,7 @@ bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf)
if (etest->flags & ETH_TEST_FL_OFFLINE) {
int i;
+ bnx2_cnic_stop(bp);
bnx2_netif_stop(bp);
bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_DIAG);
bnx2_free_skbs(bp);
@@ -6101,6 +6188,7 @@ bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf)
else {
bnx2_init_nic(bp);
bnx2_netif_start(bp);
+ bnx2_cnic_start(bp);
}
/* wait for link up */
@@ -6352,11 +6440,13 @@ bnx2_change_mtu(struct net_device *dev, int new_mtu)
dev->mtu = new_mtu;
if (netif_running(dev)) {
+ bnx2_cnic_stop(bp);
bnx2_netif_stop(bp);
bnx2_init_nic(bp);
bnx2_netif_start(bp);
+ bnx2_cnic_start(bp);
}
return 0;
}
@@ -6943,6 +7033,7 @@ bnx2_suspend(struct pci_dev *pdev, pm_message_t state)
return 0;
flush_scheduled_work();
+ bnx2_cnic_stop(bp);
bnx2_netif_stop(bp);
netif_device_detach(dev);
del_timer_sync(&bp->timer);
@@ -6972,6 +7063,7 @@ bnx2_resume(struct pci_dev *pdev)
netif_device_attach(dev);
bnx2_init_nic(bp);
bnx2_netif_start(bp);
+ bnx2_cnic_start(bp);
return 0;
}
@@ -6997,5 +7089,8 @@ static void __exit bnx2_cleanup(void)
module_init(bnx2_init);
module_exit(bnx2_cleanup);
-
-
+EXPORT_SYMBOL(bnx2_register_cnic);
+EXPORT_SYMBOL(bnx2_unregister_cnic);
+EXPORT_SYMBOL(bnx2_reg_rd_ind);
+EXPORT_SYMBOL(bnx2_reg_wr_ind);
+EXPORT_SYMBOL(bnx2_ctx_wr);
diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h
index fbae439..4230b4b 100644
--- a/drivers/net/bnx2.h
+++ b/drivers/net/bnx2.h
@@ -6465,6 +6465,16 @@ struct flash_spec {
u8 *name;
};
+struct cnic_ops {
+ struct module *cnic_owner;
+ void (*cnic_stop)(void *);
+ void (*cnic_start)(void *);
+ int (*cnic_handler)(void *, struct status_block *);
+};
+
+extern int bnx2_register_cnic(struct net_device *, struct cnic_ops *, void *) __attribute__((weak));
+extern int bnx2_unregister_cnic(struct net_device *) __attribute__((weak));
+
struct bnx2 {
/* Fields used in the tx and intr/napi performance paths are grouped */
/* together in the beginning of the structure. */
@@ -6526,6 +6536,10 @@ struct bnx2 {
int tx_ring_size;
u32 tx_wake_thresh;
+ struct cnic_ops *cnic_ops;
+ void *cnic_data;
+ int cnic_tag;
+
/* End of fields used in the performance code paths. */
char *name;
@@ -6637,6 +6651,7 @@ struct bnx2 {
u16 req_line_speed;
u8 req_duplex;
+ u8 req_port;
u8 phy_port;
u8 link_up;
@@ -6686,8 +6701,8 @@ struct bnx2 {
void *gunzip_buf;
};
-static u32 bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset);
-static void bnx2_reg_wr_ind(struct bnx2 *bp, u32 offset, u32 val);
+extern u32 bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset) __attribute__((weak));
+extern void bnx2_reg_wr_ind(struct bnx2 *bp, u32 offset, u32 val) __attribute__((weak));
#define REG_RD(bp, offset) \
readl(bp->regview + offset)
@@ -6706,7 +6721,7 @@ static void bnx2_reg_wr_ind(struct bnx2 *bp, u32 offset, u32 val);
/* Indirect context access. Unlike the MBQ_WR, these macros will not
* trigger a chip event. */
-static void bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val);
+extern void bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val) __attribute__((weak));
#define CTX_WR(bp, cid_addr, offset, val) \
bnx2_ctx_wr(bp, cid_addr, offset, val)
diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c
new file mode 100644
index 0000000..b8817c3
--- /dev/null
+++ b/drivers/net/cnic.c
@@ -0,0 +1,1881 @@
+/* cnic.c: Broadcom CNIC core network driver.
+ *
+ * Copyright (c) 2006-2007 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * Written by: John(Zongxi) Chen (zongxi@broadcom.com)
+ * Modified and maintained by: Michael Chan <mchan@broadcom.com>
+ */
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/in.h>
+#include <linux/dma-mapping.h>
+#include <asm/byteorder.h>
+#include <linux/delay.h>
+#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
+#define BCM_VLAN 1
+#include <net/ip.h>
+#include <net/tcp.h>
+#include <linux/workqueue.h>
+#include <net/arp.h>
+#include <net/neighbour.h>
+#include <net/route.h>
+#include <net/netevent.h>
+
+#include "bnx2.h"
+#include "cnic_if.h"
+#include "cnic.h"
+#include "cnic_cm.h"
+
+#define DRV_MODULE_NAME "cnic"
+#define PFX DRV_MODULE_NAME ": "
+
+static char version[] __devinitdata =
+ "Broadcom NetXtreme II CNIC Driver " DRV_MODULE_NAME " v" CNIC_MODULE_VERSION " (" CNIC_MODULE_RELDATE ")\n";
+
+MODULE_AUTHOR("John(Zongxi) Chen <zongxic@broadcom.com>");
+MODULE_DESCRIPTION("Broadcom NetXtreme II CNIC Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(CNIC_MODULE_VERSION);
+
+static LIST_HEAD(cnic_dev_list);
+static DEFINE_RWLOCK(cnic_dev_lock);
+static DEFINE_MUTEX(cnic_lock);
+
+struct cnic_ulp_ops *cnic_ulp_tbl[MAX_CNIC_ULP_TYPE];
+
+static int cnic_service_kq(void *, struct status_block *);
+static void cnic_service_stop(void *);
+static void cnic_service_start(void *);
+
+static struct cnic_ops my_cnic_ops = {
+ .cnic_owner = THIS_MODULE,
+ .cnic_handler = cnic_service_kq,
+ .cnic_stop = cnic_service_stop,
+ .cnic_start = cnic_service_start,
+};
+
+static inline void cnic_hold(struct cnic_dev *dev)
+{
+ atomic_inc(&dev->ref_count);
+}
+
+static inline void cnic_put(struct cnic_dev *dev)
+{
+ atomic_dec(&dev->ref_count);
+}
+
+int cnic_register_driver(int ulp_type, struct cnic_ulp_ops *ulp_ops)
+{
+ struct cnic_dev *dev;
+
+ if (ulp_type >= MAX_CNIC_ULP_TYPE) {
+ printk(KERN_ERR PFX "cnic_register_driver: Bad type %d\n",
+ ulp_type);
+ return -EINVAL;
+ }
+ mutex_lock(&cnic_lock);
+ if (cnic_ulp_tbl[ulp_type]) {
+ printk(KERN_ERR PFX "cnic_register_driver: Type %d has already "
+ "been registered\n", ulp_type);
+ mutex_unlock(&cnic_lock);
+ return -EBUSY;
+ }
+
+ read_lock(&cnic_dev_lock);
+ list_for_each_entry(dev, &cnic_dev_list, list) {
+ struct cnic_local *cp = dev->cnic_priv;
+
+ clear_bit(ULP_F_INIT, &cp->ulp_flags[ulp_type]);
+ }
+ read_unlock(&cnic_dev_lock);
+
+ rcu_assign_pointer(cnic_ulp_tbl[ulp_type], ulp_ops);
+ mutex_unlock(&cnic_lock);
+
+ read_lock(&cnic_dev_lock);
+ list_for_each_entry(dev, &cnic_dev_list, list) {
+ struct cnic_local *cp = dev->cnic_priv;
+
+ /* Prevent race conditions with netdev_event */
+ rtnl_lock();
+ if (!test_and_set_bit(ULP_F_INIT, &cp->ulp_flags[ulp_type]))
+ ulp_ops->cnic_init(dev);
+ rtnl_unlock();
+ }
+ read_unlock(&cnic_dev_lock);
+
+ return 0;
+}
+
+int cnic_unregister_driver(int ulp_type)
+{
+ struct cnic_dev *dev;
+
+ if (ulp_type >= MAX_CNIC_ULP_TYPE) {
+ printk(KERN_ERR PFX "cnic_unregister_driver: Bad type %d\n",
+ ulp_type);
+ return -EINVAL;
+ }
+ mutex_lock(&cnic_lock);
+ if (!cnic_ulp_tbl[ulp_type]) {
+ printk(KERN_ERR PFX "cnic_unregister_driver: Type %d has not "
+ "been registered\n", ulp_type);
+ goto out_unlock;
+ }
+ read_lock(&cnic_dev_lock);
+ list_for_each_entry(dev, &cnic_dev_list, list) {
+ struct cnic_local *cp = dev->cnic_priv;
+
+ if (rcu_dereference(cp->ulp_ops[ulp_type])) {
+ printk(KERN_ERR PFX "cnic_unregister_driver: Type %d "
+ "still has devices registered\n", ulp_type);
+ read_unlock(&cnic_dev_lock);
+ goto out_unlock;
+ }
+ }
+ read_unlock(&cnic_dev_lock);
+
+ rcu_assign_pointer(cnic_ulp_tbl[ulp_type], NULL);
+
+ mutex_unlock(&cnic_lock);
+ synchronize_rcu();
+ return 0;
+
+out_unlock:
+ mutex_unlock(&cnic_lock);
+ return -EINVAL;
+}
+
+EXPORT_SYMBOL(cnic_register_driver);
+EXPORT_SYMBOL(cnic_unregister_driver);
+
+static int cnic_start_hw(struct cnic_dev *);
+static void cnic_stop_hw(struct cnic_dev *);
+
+static int cnic_register_device(struct cnic_dev *dev, int ulp_type,
+ void *ulp_ctx)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ struct cnic_ulp_ops *ulp_ops;
+
+ if (ulp_type >= MAX_CNIC_ULP_TYPE) {
+ printk(KERN_ERR PFX "cnic_register_device: Bad type %d\n",
+ ulp_type);
+ return -EINVAL;
+ }
+ mutex_lock(&cnic_lock);
+ if (cnic_ulp_tbl[ulp_type] == NULL) {
+ printk(KERN_ERR PFX "cnic_register_device: Driver with type %d "
+ "has not been registered\n", ulp_type);
+ mutex_unlock(&cnic_lock);
+ return -EAGAIN;
+ }
+ if (rcu_dereference(cp->ulp_ops[ulp_type])) {
+ printk(KERN_ERR PFX "cnic_register_device: Type %d has already "
+ "been registered to this device\n", ulp_type);
+ mutex_unlock(&cnic_lock);
+ return -EBUSY;
+ }
+ if (!try_module_get(cnic_ulp_tbl[ulp_type]->owner)) {
+ mutex_unlock(&cnic_lock);
+ return -EBUSY;
+ }
+
+ clear_bit(ULP_F_START, &cp->ulp_flags[ulp_type]);
+ cp->ulp_handle[ulp_type] = ulp_ctx;
+ ulp_ops = cnic_ulp_tbl[ulp_type];
+ rcu_assign_pointer(cp->ulp_ops[ulp_type], ulp_ops);
+ cnic_hold(dev);
+ dev->use_count++;
+
+ if (dev->use_count == 1) {
+ if (test_bit(CNIC_F_IF_UP, &dev->flags))
+ cnic_start_hw(dev);
+ }
+
+ if (test_bit(CNIC_F_CNIC_UP, &dev->flags))
+ if (!test_and_set_bit(ULP_F_START, &cp->ulp_flags[ulp_type]))
+ ulp_ops->cnic_start(cp->ulp_handle[ulp_type]);
+
+ mutex_unlock(&cnic_lock);
+
+ return 0;
+
+}
+
+static int cnic_unregister_device(struct cnic_dev *dev, int ulp_type)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+
+ if (ulp_type >= MAX_CNIC_ULP_TYPE) {
+ printk(KERN_ERR PFX "cnic_unregister_device: Bad type %d\n",
+ ulp_type);
+ return -EINVAL;
+ }
+ mutex_lock(&cnic_lock);
+ if (rcu_dereference(cp->ulp_ops[ulp_type])) {
+ dev->use_count--;
+ module_put(cp->ulp_ops[ulp_type]->owner);
+ rcu_assign_pointer(cp->ulp_ops[ulp_type], NULL);
+ if (dev->use_count == 0)
+ cnic_stop_hw(dev);
+ cnic_put(dev);
+ } else {
+ printk(KERN_ERR PFX "cnic_unregister_device: device not "
+ "registered to this ulp type %d\n", ulp_type);
+ mutex_unlock(&cnic_lock);
+ return -EINVAL;
+ }
+ mutex_unlock(&cnic_lock);
+
+ synchronize_rcu();
+
+ return 0;
+}
+
+static ssize_t show_pci_bar(struct class_device *cdev, char *buf)
+{
+ struct cnic_dev *dev = container_of(cdev, struct cnic_dev, class_dev);
+
+ return sprintf(buf, "0x%.8x\n", (u32)pci_resource_start(dev->pcidev, 0));
+}
+
+static ssize_t show_kq_intr_coal(struct class_device *cdev, char *buf)
+{
+ struct cnic_dev *dev = container_of(cdev, struct cnic_dev, class_dev);
+
+ return sprintf(buf, "0x%.8x\n", REG_RD(dev, BNX2_HC_COMP_PROD_TRIP));
+}
+
+static ssize_t set_kq_intr_coal(struct class_device *cdev, const char *buf,
+ size_t count)
+{
+ struct cnic_dev *dev = container_of(cdev, struct cnic_dev, class_dev);
+ u32 val;
+
+ if (sscanf(buf, " 0x%x ", &val) > 0)
+ REG_WR(dev, BNX2_HC_COMP_PROD_TRIP, val);
+ return count;
+}
+
+static ssize_t show_kq_com_ticks(struct class_device *cdev, char *buf)
+{
+ struct cnic_dev *dev = container_of(cdev, struct cnic_dev, class_dev);
+
+ return sprintf(buf, "0x%.8x\n", REG_RD(dev, BNX2_HC_COM_TICKS));
+}
+
+static ssize_t set_kq_com_ticks(struct class_device *cdev, const char *buf,
+ size_t count)
+{
+ struct cnic_dev *dev = container_of(cdev, struct cnic_dev, class_dev);
+ u32 val;
+
+ if (sscanf(buf, " 0x%x ", &val) > 0)
+ REG_WR(dev, BNX2_HC_COM_TICKS, val);
+ return count;
+}
+
+static ssize_t show_kq_cmd_ticks(struct class_device *cdev, char *buf)
+{
+ struct cnic_dev *dev = container_of(cdev, struct cnic_dev, class_dev);
+
+ return sprintf(buf, "0x%.8x\n", REG_RD(dev, BNX2_HC_CMD_TICKS));
+}
+
+static ssize_t set_kq_cmd_ticks(struct class_device *cdev, const char *buf,
+ size_t count)
+{
+ struct cnic_dev *dev = container_of(cdev, struct cnic_dev, class_dev);
+ u32 val;
+
+ if (sscanf(buf, " 0x%x ", &val) > 0)
+ REG_WR(dev, BNX2_HC_CMD_TICKS, val);
+ return count;
+}
+
+static CLASS_DEVICE_ATTR(pci_bar, S_IRUGO, show_pci_bar, NULL);
+static CLASS_DEVICE_ATTR(kq_intr_coal, S_IRUGO | S_IWUSR, show_kq_intr_coal,
+ set_kq_intr_coal);
+static CLASS_DEVICE_ATTR(kq_com_ticks, S_IRUGO | S_IWUSR, show_kq_com_ticks,
+ set_kq_com_ticks);
+static CLASS_DEVICE_ATTR(kq_cmd_ticks, S_IRUGO | S_IWUSR, show_kq_cmd_ticks,
+ set_kq_cmd_ticks);
+
+static struct class_device_attribute *cnic_class_attributes[] = {
+ &class_device_attr_pci_bar,
+ &class_device_attr_kq_intr_coal,
+ &class_device_attr_kq_com_ticks,
+ &class_device_attr_kq_cmd_ticks
+};
+
+static void cnic_sysfs_release(struct class_device *class_dev)
+{
+}
+
+static struct class cnic_class = {
+ .name = "cnic",
+ .release = cnic_sysfs_release,
+};
+
+static int cnic_register_sysfs(struct cnic_dev *device)
+{
+ struct class_device *class_dev = &device->class_dev;
+ char dev_name[BUS_ID_SIZE];
+ int ret;
+ int i;
+
+ class_dev->class = &cnic_class;
+ class_dev->class_data = device;
+ snprintf(dev_name, BUS_ID_SIZE, "%.2x:%.2x.%.1x",
+ device->pcidev->bus->number, PCI_SLOT(device->pcidev->devfn),
+ PCI_FUNC(device->pcidev->devfn));
+ strlcpy(class_dev->class_id, dev_name, BUS_ID_SIZE);
+
+ ret = class_device_register(class_dev);
+ if (ret)
+ goto err;
+
+ for (i = 0; i < ARRAY_SIZE(cnic_class_attributes); ++i) {
+ ret = class_device_create_file(class_dev,
+ cnic_class_attributes[i]);
+ if (ret)
+ goto err_unregister;
+ }
+
+ return 0;
+
+err_unregister:
+ class_device_unregister(class_dev);
+err:
+ return ret;
+}
+
+static void cnic_unregister_sysfs(struct cnic_dev *device)
+{
+ class_device_unregister(&device->class_dev);
+}
+
+static int cnic_sysfs_setup(void)
+{
+ return class_register(&cnic_class);
+}
+
+static void cnic_sysfs_cleanup(void)
+{
+ class_unregister(&cnic_class);
+}
+
+static void cnic_free_resc(struct cnic_dev *dev)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ int i;
+
+ if (cp->kwq_pgtbl) {
+ pci_free_consistent(dev->pcidev, cp->kwq_pgtbl_size,
+ cp->kwq_pgtbl, cp->kwq_pgtbl_mapping);
+ cp->kwq_pgtbl = NULL;
+ }
+ for (i = 0; i < KWQ_PAGE_CNT; i++) {
+ if (cp->kwq[i]) {
+ pci_free_consistent(dev->pcidev, BCM_PAGE_SIZE,
+ cp->kwq[i], cp->kwq_mapping[i]);
+ cp->kwq[i] = NULL;
+ }
+ }
+ if (cp->kcq_pgtbl) {
+ pci_free_consistent(dev->pcidev, cp->kcq_pgtbl_size,
+ cp->kcq_pgtbl, cp->kcq_pgtbl_mapping);
+ cp->kcq_pgtbl = NULL;
+ }
+ for (i = 0; i < KCQ_PAGE_CNT; i++) {
+ if (cp->kcq[i]) {
+ pci_free_consistent(dev->pcidev, BCM_PAGE_SIZE,
+ cp->kcq[i], cp->kcq_mapping[i]);
+ cp->kcq[i] = NULL;
+ }
+ }
+
+ return;
+}
+
+static int cnic_alloc_resc(struct cnic_dev *dev)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ int i;
+
+ cp->kwq_pgtbl_size = ((KWQ_PAGE_CNT * 8) + BCM_PAGE_SIZE - 1) &
+ (BCM_PAGE_SIZE - 1);
+ cp->kwq_pgtbl = pci_alloc_consistent(dev->pcidev, cp->kwq_pgtbl_size,
+ &cp->kwq_pgtbl_mapping);
+ if (cp->kwq_pgtbl == NULL)
+ goto error;
+
+ for (i = 0; i < KWQ_PAGE_CNT; i++) {
+ cp->kwq[i] = pci_alloc_consistent(dev->pcidev, BCM_PAGE_SIZE,
+ &cp->kwq_mapping[i]);
+ if (cp->kwq[i] == NULL)
+ goto error;
+ }
+
+ cp->kcq_pgtbl_size = ((KCQ_PAGE_CNT * 8) + BCM_PAGE_SIZE - 1) &
+ (BCM_PAGE_SIZE - 1);
+ cp->kcq_pgtbl = pci_alloc_consistent(dev->pcidev, cp->kcq_pgtbl_size,
+ &cp->kcq_pgtbl_mapping);
+ if (cp->kcq_pgtbl == NULL)
+ goto error;
+
+ for (i = 0; i < KCQ_PAGE_CNT; i++) {
+ cp->kcq[i] = pci_alloc_consistent(dev->pcidev, BCM_PAGE_SIZE,
+ &cp->kcq_mapping[i]);
+ if (cp->kcq[i] == NULL)
+ goto error;
+ }
+
+ return 0;
+
+error:
+ cnic_free_resc(dev);
+ return -ENOMEM;
+}
+
+static void cnic_setup_page_tbl(u32 *page_table, u32 page_cnt,
+ dma_addr_t base_mapping[])
+{
+ int i;
+
+ for (i = 0; i < page_cnt; i++) {
+ /* Each entry needs to be in big endian format. */
+ *page_table = (u32) ((u64) base_mapping[i] >> 32);
+ page_table++;
+ *page_table = (u32) base_mapping[i];
+ page_table++;
+ }
+}
+
+static inline u32 cnic_kwq_avail(struct cnic_local *cp)
+{
+ return (MAX_KWQ_IDX -
+ ((cp->kwq_prod_idx - cp->kwq_con_idx) & MAX_KWQ_IDX));
+}
+
+static int cnic_submit_kernel_wqes(struct cnic_dev *dev, struct kwqe *wqes[],
+ u32 num_wqes)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ struct kwqe *prod_qe;
+ u16 prod, sw_prod, i;
+
+ if (!test_bit(CNIC_F_CNIC_UP, &dev->flags))
+ return -EAGAIN; /* bnx2 is down */
+
+ spin_lock_bh(&cp->cnic_ulp_lock);
+ if (num_wqes > cnic_kwq_avail(cp)) {
+ spin_unlock_bh(&cp->cnic_ulp_lock);
+ return -EAGAIN;
+ }
+
+ prod = cp->kwq_prod_idx;
+ sw_prod = prod & MAX_KWQ_IDX;
+ for (i = 0; i < num_wqes; i++) {
+ prod_qe = &cp->kwq[KWQ_PG(sw_prod)][KWQ_IDX(sw_prod)];
+ memcpy(prod_qe, wqes[i], sizeof(struct kwqe));
+ prod++;
+ sw_prod = prod & MAX_KWQ_IDX;
+ }
+ cp->kwq_prod_idx = prod;
+
+ REG_WR16(dev, cp->kwq_io_addr, cp->kwq_prod_idx);
+
+ spin_unlock_bh(&cp->cnic_ulp_lock);
+ return 0;
+}
+
+static void service_kcqes(struct cnic_dev *dev, int num_cqes)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ int i, j;
+
+ i = 0;
+ j = 1;
+ while (num_cqes) {
+ struct cnic_ulp_ops *ulp_ops;
+ int ulp_type;
+ u32 kcqe_op_flag = cp->completed_kcq[i]->kcqe_op_flag &
+ KCQE_FLAGS_LAYER_MASK;
+
+ while (j < num_cqes) {
+ if ((cp->completed_kcq[i + j]->kcqe_op_flag &
+ KCQE_FLAGS_LAYER_MASK) != kcqe_op_flag) {
+ break;
+ }
+ j++;
+ }
+
+ if (kcqe_op_flag == KCQE_FLAGS_LAYER_MASK_L5_RDMA)
+ ulp_type = CNIC_ULP_RDMA;
+ else if (kcqe_op_flag == KCQE_FLAGS_LAYER_MASK_L5_ISCSI)
+ ulp_type = CNIC_ULP_ISCSI;
+ else if (kcqe_op_flag == KCQE_FLAGS_LAYER_MASK_L4)
+ ulp_type = CNIC_ULP_L4;
+ else {
+ printk(KERN_ERR PFX "%s: Unknown type of KCQE(0x%x)\n",
+ dev->netdev->name, kcqe_op_flag);
+ goto end;
+ }
+
+ rcu_read_lock();
+ ulp_ops = rcu_dereference(cp->ulp_ops[ulp_type]);
+ if (likely(ulp_ops)) {
+ ulp_ops->indicate_kcqes(cp->ulp_handle[ulp_type],
+ cp->completed_kcq + i, j);
+ }
+ rcu_read_unlock();
+end:
+ num_cqes -= j;
+ i += j;
+ j = 1;
+ }
+ return;
+}
+
+static int cnic_service_kq(void *data, struct status_block *status_blk)
+{
+ struct cnic_dev *dev = data;
+ struct cnic_local *cp = dev->cnic_priv;
+ u32 status_idx = status_blk->status_idx;
+ u16 hw_prod, sw_prod;
+
+ cp->kwq_con_idx = status_blk->status_rx_quick_consumer_index15;
+
+ hw_prod = status_blk->status_completion_producer_index;
+ sw_prod = cp->kcq_prod_idx;
+ while (sw_prod != hw_prod) {
+ u16 i, max;
+ struct kcqe *kcqe;
+ int kcqe_cnt = 0;
+
+ i = sw_prod & MAX_KCQ_IDX;
+ max = hw_prod & MAX_KCQ_IDX;
+ while ((i != max) && (kcqe_cnt < MAX_COMPLETED_KCQE)) {
+ cp->completed_kcq[kcqe_cnt++] =
+ &cp->kcq[KCQ_PG(i)][KCQ_IDX(i)];
+ i = (i + 1) & MAX_KCQ_IDX;
+ }
+
+ kcqe = cp->completed_kcq[kcqe_cnt - 1];
+ while (kcqe->kcqe_op_flag & KCQE_FLAGS_NEXT) {
+ kcqe_cnt--;
+ if (kcqe_cnt == 0)
+ goto done;
+ kcqe = cp->completed_kcq[kcqe_cnt - 1];
+ }
+ sw_prod += kcqe_cnt;
+
+ service_kcqes(dev, kcqe_cnt);
+
+ /* Tell compiler that status_blk fields can change. */
+ barrier();
+ if (status_idx != status_blk->status_idx) {
+ status_idx = status_blk->status_idx;
+ cp->kwq_con_idx =
+ status_blk->status_rx_quick_consumer_index15;
+ hw_prod = status_blk->status_completion_producer_index;
+ } else
+ break;
+ }
+
+done:
+ REG_WR16(dev, cp->kcq_io_addr, sw_prod);
+
+ cp->kcq_prod_idx = sw_prod;
+ return status_idx;
+}
+
+static void cnic_ulp_stop(struct cnic_dev *dev)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ int if_type;
+
+ rcu_read_lock();
+ for (if_type = 0; if_type < MAX_CNIC_ULP_TYPE; if_type++) {
+ struct cnic_ulp_ops *ulp_ops;
+
+ ulp_ops = rcu_dereference(cp->ulp_ops[if_type]);
+ if (!ulp_ops)
+ continue;
+
+ if (test_and_clear_bit(ULP_F_START, &cp->ulp_flags[if_type]))
+ ulp_ops->cnic_stop(cp->ulp_handle[if_type]);
+ }
+ rcu_read_unlock();
+}
+
+static void cnic_ulp_start(struct cnic_dev *dev)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ int if_type;
+
+ rcu_read_lock();
+ for (if_type = 0; if_type < MAX_CNIC_ULP_TYPE; if_type++) {
+ struct cnic_ulp_ops *ulp_ops;
+
+ ulp_ops = rcu_dereference(cp->ulp_ops[if_type]);
+ if (!ulp_ops)
+ continue;
+
+ if (!test_and_set_bit(ULP_F_START, &cp->ulp_flags[if_type]))
+ ulp_ops->cnic_start(cp->ulp_handle[if_type]);
+ }
+ rcu_read_unlock();
+}
+
+static void cnic_service_start(void *data)
+{
+ struct cnic_dev *dev = data;
+
+ cnic_hold(dev);
+ mutex_lock(&cnic_lock);
+ set_bit(CNIC_F_IF_UP, &dev->flags);
+ if (dev->use_count) {
+ if (!cnic_start_hw(dev))
+ cnic_ulp_start(dev);
+ }
+ mutex_unlock(&cnic_lock);
+ cnic_put(dev);
+}
+
+static void cnic_service_stop(void *data)
+{
+ struct cnic_dev *dev = data;
+
+ cnic_hold(dev);
+ mutex_lock(&cnic_lock);
+ clear_bit(CNIC_F_IF_UP, &dev->flags);
+ cnic_ulp_stop(dev);
+ cnic_stop_hw(dev);
+ mutex_unlock(&cnic_lock);
+ cnic_put(dev);
+}
+
+static void cnic_ulp_init(struct cnic_dev *dev)
+{
+ int i;
+ struct cnic_local *cp = dev->cnic_priv;
+
+ rcu_read_lock();
+ for (i = 0; i < MAX_CNIC_ULP_TYPE_EXT; i++) {
+ struct cnic_ulp_ops *ulp_ops;
+
+ ulp_ops = rcu_dereference(cnic_ulp_tbl[i]);
+ if (!ulp_ops || !try_module_get(ulp_ops->owner))
+ continue;
+
+ if (!test_and_set_bit(ULP_F_INIT, &cp->ulp_flags[i]))
+ ulp_ops->cnic_init(dev);
+
+ module_put(ulp_ops->owner);
+ }
+ rcu_read_unlock();
+}
+
+static void cnic_ulp_exit(struct cnic_dev *dev)
+{
+ int i;
+ struct cnic_local *cp = dev->cnic_priv;
+
+ rcu_read_lock();
+ for (i = 0; i < MAX_CNIC_ULP_TYPE_EXT; i++) {
+ struct cnic_ulp_ops *ulp_ops;
+
+ ulp_ops = rcu_dereference(cnic_ulp_tbl[i]);
+ if (!ulp_ops || !try_module_get(ulp_ops->owner))
+ continue;
+
+ if (test_and_clear_bit(ULP_F_INIT, &cp->ulp_flags[i]))
+ ulp_ops->cnic_exit(dev);
+
+ module_put(ulp_ops->owner);
+ }
+ rcu_read_unlock();
+}
+
+static int cnic_queue_work(struct cnic_local *cp, u32 work_type, void *data)
+{
+ struct cnic_work_node *node;
+ int bytes = sizeof(u32 *);
+
+ spin_lock_bh(&cp->cm_lock);
+
+ node = &cp->cnic_work_ring[cp->cnic_wr_prod];
+ node->work_type = work_type;
+ if (work_type == WORK_TYPE_KCQE)
+ bytes = sizeof(struct kcqe);
+ if (work_type == WORK_TYPE_REDIRECT)
+ bytes = sizeof(struct cnic_redirect_entry);
+ memcpy(&node->work_data, data, bytes);
+ cp->cnic_wr_prod++;
+ cp->cnic_wr_prod &= WORK_RING_SIZE_MASK;
+
+ spin_unlock_bh(&cp->cm_lock);
+ return 0;
+}
+
+static int cnic_cm_offload_pg(struct cnic_sock *csk)
+{
+ struct cnic_dev *dev = csk->dev;
+ struct l4_kwq_offload_pg *l4kwqe;
+ struct kwqe *wqes[1];
+ struct neighbour *neigh = csk->dst->neighbour;
+ struct net_device *netdev = neigh->dev;
+
+ l4kwqe = (struct l4_kwq_offload_pg *) &csk->kwqe1;
+ memset(l4kwqe, 0, sizeof(*l4kwqe));
+ wqes[0] = (struct kwqe *) l4kwqe;
+
+ l4kwqe->op_code = L4_KWQE_OPCODE_VALUE_OFFLOAD_PG;
+ l4kwqe->flags =
+ L4_LAYER_CODE << L4_KWQ_OFFLOAD_PG_LAYER_CODE_SHIFT;
+ l4kwqe->l2hdr_nbytes = ETH_HLEN;
+ l4kwqe->da0 = neigh->ha[0];
+ l4kwqe->da1 = neigh->ha[1];
+ l4kwqe->da2 = neigh->ha[2];
+ l4kwqe->da3 = neigh->ha[3];
+ l4kwqe->da4 = neigh->ha[4];
+ l4kwqe->da5 = neigh->ha[5];
+
+ l4kwqe->sa0 = netdev->dev_addr[0];
+ l4kwqe->sa1 = netdev->dev_addr[1];
+ l4kwqe->sa2 = netdev->dev_addr[2];
+ l4kwqe->sa3 = netdev->dev_addr[3];
+ l4kwqe->sa4 = netdev->dev_addr[4];
+ l4kwqe->sa5 = netdev->dev_addr[5];
+
+ l4kwqe->etype = ETH_P_IP;
+ l4kwqe->ipid_count = DEF_IPID_COUNT;
+ l4kwqe->host_opaque = csk->l5_cid;
+
+ if (csk->vlan_id) {
+ l4kwqe->pg_flags |= L4_KWQ_OFFLOAD_PG_VLAN_TAGGING;
+ l4kwqe->vlan_tag = csk->vlan_id;
+ l4kwqe->l2hdr_nbytes += 4;
+ }
+
+ return (dev->submit_kwqes(dev, wqes, 1));
+}
+
+static int cnic_cm_update_pg(struct cnic_sock *csk)
+{
+ struct cnic_dev *dev = csk->dev;
+ struct l4_kwq_update_pg *l4kwqe;
+ struct kwqe *wqes[1];
+ struct neighbour *neigh = csk->dst->neighbour;
+
+ l4kwqe = (struct l4_kwq_update_pg *) &csk->kwqe1;
+ memset(l4kwqe, 0, sizeof(*l4kwqe));
+ wqes[0] = (struct kwqe *) l4kwqe;
+
+ l4kwqe->opcode = L4_KWQE_OPCODE_VALUE_UPDATE_PG;
+ l4kwqe->flags =
+ L4_LAYER_CODE << L4_KWQ_UPDATE_PG_LAYER_CODE_SHIFT;
+ l4kwqe->pg_cid = csk->pg_cid;
+ l4kwqe->da0 = neigh->ha[0];
+ l4kwqe->da1 = neigh->ha[1];
+ l4kwqe->da2 = neigh->ha[2];
+ l4kwqe->da3 = neigh->ha[3];
+ l4kwqe->da4 = neigh->ha[4];
+ l4kwqe->da5 = neigh->ha[5];
+
+ l4kwqe->pg_host_opaque = 0;
+ l4kwqe->pg_valids = L4_KWQ_UPDATE_PG_VALIDS_DA;
+
+ return (dev->submit_kwqes(dev, wqes, 1));
+}
+
+static int cnic_cm_upload_pg(struct cnic_sock *csk)
+{
+ struct cnic_dev *dev = csk->dev;
+ struct l4_kwq_upload *l4kwqe;
+ struct kwqe *wqes[1];
+
+ l4kwqe = (struct l4_kwq_upload *) &csk->kwqe1;
+ memset(l4kwqe, 0, sizeof(*l4kwqe));
+ wqes[0] = (struct kwqe *) l4kwqe;
+
+ l4kwqe->opcode = L4_KWQE_OPCODE_VALUE_UPLOAD_PG;
+ l4kwqe->flags =
+ L4_LAYER_CODE << L4_KWQ_UPLOAD_LAYER_CODE_SHIFT;
+ l4kwqe->cid = csk->pg_cid;
+
+ return (dev->submit_kwqes(dev, wqes, 1));
+}
+
+static void cnic_redirect(struct cnic_local *cp, struct dst_entry *new,
+ struct dst_entry *old)
+{
+ int i, found = 0;
+
+ spin_lock_bh(&cp->cm_lock);
+ for (i = 0; i < MAX_CM_SK_TBL_SZ; i++) {
+ struct cnic_sock *csk;
+
+ csk = &cp->csk_tbl[i];
+ if (test_bit(SK_F_INUSE, &csk->flags) && csk->dst == old)
+ found = 1;
+ }
+ spin_unlock_bh(&cp->cm_lock);
+
+ if (found) {
+ struct cnic_redirect_entry cnic_redir;
+
+ dst_hold(new);
+ cnic_redir.old_dst = old;
+ cnic_redir.new_dst = new;
+ cnic_queue_work(cp, WORK_TYPE_REDIRECT, &cnic_redir);
+ schedule_work(&cp->cnic_task);
+ }
+}
+
+static void cnic_update_neigh(struct cnic_local *cp, struct neighbour *neigh)
+{
+ int i, found = 0;
+
+ spin_lock_bh(&cp->cm_lock);
+ for (i = 0; i < MAX_CM_SK_TBL_SZ; i++) {
+ struct cnic_sock *csk;
+
+ csk = &cp->csk_tbl[i];
+ if (test_bit(SK_F_INUSE, &csk->flags) && csk->dst) {
+ if (csk->dst->neighbour == neigh)
+ found = 1;
+ }
+ }
+ spin_unlock_bh(&cp->cm_lock);
+
+ if (!found)
+ return;
+
+ neigh_hold(neigh);
+
+ cnic_queue_work(cp, WORK_TYPE_NEIGH_UPDATE, &neigh);
+ schedule_work(&cp->cnic_task);
+}
+
+static int cnic_net_callback(struct notifier_block *this, unsigned long event,
+ void *ptr)
+{
+ struct cnic_local *cp = container_of(this, struct cnic_local, cm_nb);
+
+ if (event == NETEVENT_NEIGH_UPDATE) {
+ struct neighbour *neigh = ptr;
+
+ cnic_update_neigh(cp, neigh);
+
+ } else if (event == NETEVENT_REDIRECT) {
+ struct netevent_redirect *netevent = ptr;
+ struct dst_entry *old_dst = netevent->old;
+ struct dst_entry *new_dst = netevent->new;
+
+ cnic_redirect(cp, new_dst, old_dst);
+ }
+ return 0;
+}
+
+static int cnic_ok_to_connect(struct cnic_sock *csk)
+{
+ if (test_bit(SK_F_INUSE, &csk->flags) &&
+ !test_bit(SK_F_OFFLD_PENDING, &csk->flags) &&
+ !test_bit(SK_F_OFFLD_COMPLETE, &csk->flags) &&
+ test_bit(SK_F_PG_OFFLD_COMPLETE, &csk->flags))
+ return 1;
+ return 0;
+}
+
+static int cnic_cm_conn_req(struct cnic_sock *csk)
+{
+ struct cnic_dev *dev = csk->dev;
+ struct l4_kwq_connect_req1 *l4kwqe1;
+ struct l4_kwq_connect_req3 *l4kwqe3;
+ struct kwqe *wqes[2];
+ u8 tcp_flags = 0;
+
+ l4kwqe1 = (struct l4_kwq_connect_req1 *) &csk->kwqe2;
+ l4kwqe3 = (struct l4_kwq_connect_req3 *) &csk->kwqe3;
+ memset(l4kwqe1, 0, sizeof(*l4kwqe1));
+ memset(l4kwqe3, 0, sizeof(*l4kwqe3));
+ wqes[0] = (struct kwqe *) l4kwqe1;
+ wqes[1] = (struct kwqe *) l4kwqe3;
+
+ l4kwqe1->op_code = L4_KWQE_OPCODE_VALUE_CONNECT1;
+ l4kwqe1->flags =
+ (L4_LAYER_CODE << L4_KWQ_CONNECT_REQ1_LAYER_CODE_SHIFT) |
+ L4_KWQ_CONNECT_REQ3_LINKED_WITH_NEXT;
+ l4kwqe1->cid = csk->cid;
+ l4kwqe1->pg_cid = csk->pg_cid;
+ l4kwqe1->src_ip = be32_to_cpu(csk->src_ip);
+ l4kwqe1->dst_ip = be32_to_cpu(csk->dst_ip);
+ l4kwqe1->src_port = be16_to_cpu(csk->src_port);
+ l4kwqe1->dst_port = be16_to_cpu(csk->dst_port);
+ if (test_bit(SK_TCP_NO_DELAY_ACK, &csk->tcp_flags))
+ tcp_flags |= L4_KWQ_CONNECT_REQ1_NO_DELAY_ACK;
+ if (test_bit(SK_TCP_KEEP_ALIVE, &csk->tcp_flags))
+ tcp_flags |= L4_KWQ_CONNECT_REQ1_KEEP_ALIVE;
+ if (test_bit(SK_TCP_NAGLE, &csk->tcp_flags))
+ tcp_flags |= L4_KWQ_CONNECT_REQ1_NAGLE_ENABLE;
+ if (test_bit(SK_TCP_TIMESTAMP, &csk->tcp_flags))
+ tcp_flags |= L4_KWQ_CONNECT_REQ1_TIME_STAMP;
+ if (test_bit(SK_TCP_SACK, &csk->tcp_flags))
+ tcp_flags |= L4_KWQ_CONNECT_REQ1_SACK;
+ if (test_bit(SK_TCP_SEG_SCALING, &csk->tcp_flags))
+ tcp_flags |= L4_KWQ_CONNECT_REQ1_SEG_SCALING;
+
+ l4kwqe1->tcp_flags = tcp_flags;
+
+ l4kwqe3->op_code = L4_KWQE_OPCODE_VALUE_CONNECT3;
+ l4kwqe3->flags =
+ L4_LAYER_CODE << L4_KWQ_CONNECT_REQ3_LAYER_CODE_SHIFT;
+ l4kwqe3->ka_timeout = csk->ka_timeout;
+ l4kwqe3->ka_interval = csk->ka_interval;
+ l4kwqe3->ka_max_probe_count = csk->ka_max_probe_count;
+ l4kwqe3->tos = csk->tos;
+ l4kwqe3->ttl = csk->ttl;
+ l4kwqe3->snd_seq_scale = csk->snd_seq_scale;
+ l4kwqe3->pmtu = dst_mtu(csk->dst);
+ l4kwqe3->mss = l4kwqe3->pmtu - 40;
+ l4kwqe3->rcv_buf = csk->rcv_buf;
+ l4kwqe3->snd_buf = csk->snd_buf;
+ l4kwqe3->seed = csk->seed;
+
+ return (dev->submit_kwqes(dev, wqes, 2));
+}
+
+static int cnic_cm_close_req(struct cnic_sock *csk)
+{
+ struct cnic_dev *dev = csk->dev;
+ struct l4_kwq_close_req *l4kwqe;
+ struct kwqe *wqes[1];
+
+ l4kwqe = (struct l4_kwq_close_req *) &csk->kwqe2;
+ memset(l4kwqe, 0, sizeof(*l4kwqe));
+ wqes[0] = (struct kwqe *) l4kwqe;
+
+ l4kwqe->op_code = L4_KWQE_OPCODE_VALUE_CLOSE;
+ l4kwqe->flags = L4_LAYER_CODE << L4_KWQ_CLOSE_REQ_LAYER_CODE_SHIFT;
+ l4kwqe->cid = csk->cid;
+
+ return (dev->submit_kwqes(dev, wqes, 1));
+}
+
+static int cnic_cm_abort_req(struct cnic_sock *csk)
+{
+ struct cnic_dev *dev = csk->dev;
+ struct l4_kwq_reset_req *l4kwqe;
+ struct kwqe *wqes[1];
+
+ l4kwqe = (struct l4_kwq_reset_req *) &csk->kwqe2;
+ memset(l4kwqe, 0, sizeof(*l4kwqe));
+ wqes[0] = (struct kwqe *) l4kwqe;
+
+ l4kwqe->op_code = L4_KWQE_OPCODE_VALUE_RESET;
+ l4kwqe->flags = L4_LAYER_CODE << L4_KWQ_RESET_REQ_LAYER_CODE_SHIFT;
+ l4kwqe->cid = csk->cid;
+
+ return (dev->submit_kwqes(dev, wqes, 1));
+}
+
+static int cnic_cm_create(struct cnic_dev *dev, int ulp_type, u32 cid,
+ u32 l5_cid, struct cnic_sock **csk, void *context)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ struct cnic_sock *csk1;
+
+ if (l5_cid >= MAX_CM_SK_TBL_SZ)
+ return -EINVAL;
+
+ csk1 = &cp->csk_tbl[l5_cid];
+ if (test_and_set_bit(SK_F_INUSE, &csk1->flags))
+ return -EINVAL;
+
+ csk1->dev = dev;
+ csk1->cid = cid;
+ csk1->l5_cid = l5_cid;
+ csk1->ulp_type = ulp_type;
+ csk1->context = context;
+
+ csk1->ka_timeout = DEF_KA_TIMEOUT;
+ csk1->ka_interval = DEF_KA_INTERVAL;
+ csk1->ka_max_probe_count = DEF_KA_MAX_PROBE_COUNT;
+ csk1->tos = DEF_TOS;
+ csk1->ttl = DEF_TTL;
+ csk1->snd_seq_scale = DEF_SND_SEQ_SCALE;
+ csk1->rcv_buf = DEF_RCV_BUF;
+ csk1->snd_buf = DEF_SND_BUF;
+ csk1->seed = DEF_SEED;
+
+ *csk = csk1;
+
+ return 0;
+}
+
+static int cnic_cm_destroy(struct cnic_sock *csk)
+{
+ struct cnic_local *cp = csk->dev->cnic_priv;
+
+ if (!test_bit(SK_F_INUSE, &csk->flags))
+ return -EINVAL;
+
+ spin_lock_bh(&cp->cm_lock);
+ if (csk->dst) {
+ if (csk->dst->neighbour)
+ neigh_release(csk->dst->neighbour);
+ dst_release(csk->dst);
+ csk->dst = NULL;
+ }
+ csk->flags = 0;
+ spin_unlock_bh(&cp->cm_lock);
+ return 0;
+}
+
+static inline struct net_device *get_real_netdev(struct net_device *netdev)
+{
+ return netdev->priv_flags & IFF_802_1Q_VLAN ?
+ VLAN_DEV_INFO(netdev)->real_dev : netdev;
+}
+
+static struct cnic_dev *cnic_cm_select_dev(struct sockaddr_in *dst_addr,
+ int ulp_type)
+{
+ u32 dst_ip = dst_addr->sin_addr.s_addr;
+ struct flowi fl;
+ struct rtable *rt;
+ struct net_device *netdev;
+ struct cnic_dev *dev;
+ int err, found;
+
+ memset(&fl, 0, sizeof(fl));
+ fl.nl_u.ip4_u.daddr = dst_ip;
+
+ err = ip_route_output_key(&rt, &fl);
+ if (err)
+ return NULL;
+
+ netdev = get_real_netdev(rt->idev->dev);
+
+ found = 0;
+ read_lock(&cnic_dev_lock);
+ list_for_each_entry(dev, &cnic_dev_list, list) {
+ if (netdev == dev->netdev) {
+ found = 1;
+ cnic_hold(dev);
+ break;
+ }
+ }
+ read_unlock(&cnic_dev_lock);
+
+ ip_rt_put(rt);
+
+ if (found) {
+ struct cnic_local *cp = dev->cnic_priv;
+
+ if (rcu_dereference(cp->ulp_ops[ulp_type])) {
+ cnic_put(dev);
+ return dev;
+ }
+ cnic_put(dev);
+ }
+
+ return NULL;
+}
+
+static int cnic_cm_connect(struct cnic_sock *csk, struct cnic_sockaddr *saddr)
+{
+ struct cnic_dev *dev = csk->dev;
+ struct net_device *realdev;
+ u32 dst_ip = saddr->remote_addr.sin_addr.s_addr;
+ u32 src_ip = saddr->local_addr.sin_addr.s_addr;
+ struct flowi fl;
+ struct rtable *rt;
+ struct neighbour *neigh;
+ int err = 0, retry = 0;
+
+ if (!test_bit(SK_F_INUSE, &csk->flags))
+ return -EINVAL;
+
+ memset(&fl, 0, sizeof(fl));
+ fl.nl_u.ip4_u.daddr = dst_ip;
+ fl.nl_u.ip4_u.saddr = src_ip;
+ err = ip_route_output_key(&rt, &fl);
+ if (err)
+ return err;
+
+ realdev = get_real_netdev(rt->idev->dev);
+ if (realdev != dev->netdev)
+ goto err;
+
+ if (src_ip == 0)
+ src_ip = inet_select_addr(rt->idev->dev, dst_ip, RT_SCOPE_LINK);
+
+ csk->dst = &rt->u.dst;
+ csk->src_ip = src_ip;
+ csk->dst_ip = dst_ip;
+ csk->src_port = saddr->local_addr.sin_port;
+ csk->dst_port = saddr->remote_addr.sin_port;
+
+ neigh = csk->dst->neighbour;
+ if (!csk->dst->neighbour)
+ goto err;
+
+ neigh_hold(neigh);
+
+ if (realdev != rt->idev->dev)
+ csk->vlan_id = VLAN_DEV_INFO(rt->idev->dev)->vlan_id;
+ else
+ csk->vlan_id = 0;
+
+
+ if (neigh->nud_state & NUD_VALID)
+ err = cnic_cm_offload_pg(csk);
+
+ while (!(neigh->nud_state & NUD_VALID) && (retry < 3)) {
+ arp_send(ARPOP_REQUEST, ETH_P_ARP, rt->rt_gateway,
+ rt->idev->dev, rt->rt_src, NULL,
+ rt->idev->dev->dev_addr, NULL);
+ msleep(1000);
+ retry++;
+ }
+ if (!(neigh->nud_state & NUD_VALID))
+ err = -ENODATA;
+
+ if (!err)
+ return 0;
+
+ neigh_release(neigh);
+
+err:
+ csk->dst = NULL;
+
+ ip_rt_put(rt);
+ return err;
+}
+
+static int cnic_cm_abort(struct cnic_sock *csk)
+{
+ if (!test_bit(SK_F_INUSE, &csk->flags))
+ return -EINVAL;
+
+ return (cnic_cm_abort_req(csk));
+}
+
+static int cnic_cm_close(struct cnic_sock *csk)
+{
+ if (!test_bit(SK_F_INUSE, &csk->flags))
+ return -EINVAL;
+
+ return (cnic_cm_close_req(csk));
+}
+
+static void cnic_cm_process_neigh(struct cnic_dev *dev, struct neighbour *neigh)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ int i;
+
+ for (i = 0; i < MAX_CM_SK_TBL_SZ; i++) {
+ struct cnic_sock *csk;
+
+ csk = &cp->csk_tbl[i];
+ spin_lock_bh(&cp->cm_lock);
+ if (test_bit(SK_F_INUSE, &csk->flags) && csk->dst &&
+ csk->dst->neighbour == neigh) {
+ if (test_bit(SK_F_PG_OFFLD_COMPLETE, &csk->flags))
+ cnic_cm_update_pg(csk);
+ else
+ cnic_cm_offload_pg(csk);
+ }
+ spin_unlock_bh(&cp->cm_lock);
+ }
+ neigh_release(neigh);
+}
+
+static void cnic_cm_process_redirect(struct cnic_dev *dev,
+ struct cnic_redirect_entry *redir)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ int i;
+
+ for (i = 0; i < MAX_CM_SK_TBL_SZ; i++) {
+ struct cnic_sock *csk;
+
+ spin_lock_bh(&cp->cm_lock);
+ csk = &cp->csk_tbl[i];
+ if (test_bit(SK_F_INUSE, &csk->flags) &&
+ csk->dst == redir->old_dst) {
+ csk->dst = redir->new_dst;
+ dst_hold(csk->dst);
+ neigh_hold(csk->dst->neighbour);
+ if (redir->old_dst->neighbour);
+ neigh_release(redir->old_dst->neighbour);
+ dst_release(redir->old_dst);
+ if (test_bit(SK_F_PG_OFFLD_COMPLETE, &csk->flags))
+ cnic_cm_update_pg(csk);
+ else
+ cnic_cm_offload_pg(csk);
+ }
+ spin_unlock_bh(&cp->cm_lock);
+ }
+
+ dst_release(redir->new_dst);
+}
+
+static void cnic_cm_upcall(struct cnic_local *cp, struct cnic_sock *csk,
+ u8 opcode)
+{
+ struct cnic_ulp_ops *ulp_ops;
+ int ulp_type = csk->ulp_type;
+
+ rcu_read_lock();
+ ulp_ops = rcu_dereference(cp->ulp_ops[ulp_type]);
+ if (ulp_ops) {
+ if (opcode == L4_KCQE_OPCODE_VALUE_CONNECT_COMPLETE)
+ ulp_ops->cm_connect_complete(csk);
+ else if (opcode == L4_KCQE_OPCODE_VALUE_CONNECT_CLOSE)
+ ulp_ops->cm_close_complete(csk);
+ else if (opcode == L4_KCQE_OPCODE_VALUE_RESET_RECEIVED)
+ ulp_ops->cm_remote_abort(csk);
+ else if (opcode == L4_KCQE_OPCODE_VALUE_RESET_COMP)
+ ulp_ops->cm_abort_complete(csk);
+ else if (opcode == L4_KCQE_OPCODE_VALUE_CLOSE_RECEIVED)
+ ulp_ops->cm_remote_close(csk);
+ }
+ rcu_read_unlock();
+}
+
+static void cnic_cm_process_kcqe(struct cnic_dev *dev, struct kcqe *kcqe)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ struct l4_kcq *l4kcqe = (struct l4_kcq *) kcqe;
+ u8 opcode = l4kcqe->op_code;
+
+ if (opcode == L4_KCQE_OPCODE_VALUE_OFFLOAD_PG) {
+ u32 l5_cid = l4kcqe->pg_host_opaque;
+ struct cnic_sock *csk = &cp->csk_tbl[l5_cid];
+
+ if (!test_bit(SK_F_INUSE, &csk->flags))
+ return;
+
+ csk->pg_cid = l4kcqe->pg_cid;
+ set_bit(SK_F_PG_OFFLD_COMPLETE, &csk->flags);
+ if (cnic_ok_to_connect(csk)) {
+ set_bit(SK_F_OFFLD_PENDING, &csk->flags);
+ cnic_cm_conn_req(csk);
+ }
+
+ } else if (opcode == L4_KCQE_OPCODE_VALUE_CONNECT_RESP) {
+
+ } else if (opcode == L4_KCQE_OPCODE_VALUE_CONNECT_COMPLETE) {
+ u32 l5_cid = l4kcqe->conn_id;
+ struct cnic_sock *csk = &cp->csk_tbl[l5_cid];
+
+ if (test_bit(SK_F_INUSE, &csk->flags)) {
+ if (l4kcqe->status == 0)
+ set_bit(SK_F_OFFLD_COMPLETE, &csk->flags);
+ clear_bit(SK_F_OFFLD_PENDING, &csk->flags);
+ cnic_cm_upcall(cp, csk, opcode);
+ }
+
+ } else if (opcode == L4_KCQE_OPCODE_VALUE_CONNECT_CLOSE ||
+ opcode == L4_KCQE_OPCODE_VALUE_RESET_RECEIVED ||
+ opcode == L4_KCQE_OPCODE_VALUE_RESET_COMP) {
+ u32 l5_cid = l4kcqe->conn_id;
+ struct cnic_sock *csk = &cp->csk_tbl[l5_cid];
+
+ if (test_bit(SK_F_INUSE, &csk->flags)) {
+ clear_bit(SK_F_OFFLD_COMPLETE, &csk->flags);
+ clear_bit(SK_F_OFFLD_PENDING, &csk->flags);
+ cnic_cm_upload_pg(csk);
+ clear_bit(SK_F_PG_OFFLD_COMPLETE, &csk->flags);
+ cnic_cm_upcall(cp, csk, opcode);
+ }
+ } else if (opcode == L4_KCQE_OPCODE_VALUE_CLOSE_RECEIVED) {
+ u32 l5_cid = l4kcqe->conn_id;
+ struct cnic_sock *csk = &cp->csk_tbl[l5_cid];
+
+ if (test_bit(SK_F_INUSE, &csk->flags))
+ cnic_cm_upcall(cp, csk, opcode);
+ }
+}
+
+static void cnic_cm_indicate_kcqe(void *data, struct kcqe *kcqe[], u32 num_cqe)
+{
+ struct cnic_dev *dev = data;
+ int i;
+ struct cnic_local *cp = dev->cnic_priv;
+
+ for (i = 0; i < num_cqe; i++)
+ cnic_queue_work(cp, WORK_TYPE_KCQE, kcqe[i]);
+
+ schedule_work(&cp->cnic_task);
+}
+
+static void cnic_cm_indicate_event(void *data, unsigned long event)
+{
+}
+
+static void cnic_cm_dummy(void *data)
+{
+}
+
+static struct cnic_ulp_ops cm_ulp_ops = {
+ .cnic_start = cnic_cm_dummy,
+ .cnic_stop = cnic_cm_dummy,
+ .indicate_kcqes = cnic_cm_indicate_kcqe,
+ .indicate_netevent = cnic_cm_indicate_event,
+ .indicate_inetevent = cnic_cm_indicate_event,
+};
+
+static void cnic_task(struct work_struct *work)
+{
+ struct cnic_local *cp =
+ container_of(work, struct cnic_local, cnic_task);
+ struct cnic_dev *dev = cp->dev;
+ u32 cons = cp->cnic_wr_cons;
+ u32 prod = cp->cnic_wr_prod;
+
+ while (cons != prod) {
+ struct cnic_work_node *node;
+
+ node = &cp->cnic_work_ring[cons];
+ if (node->work_type == WORK_TYPE_KCQE)
+ cnic_cm_process_kcqe(dev, &node->work_data.kcqe);
+ else if (node->work_type == WORK_TYPE_NEIGH_UPDATE)
+ cnic_cm_process_neigh(dev, node->work_data.neigh);
+ else if (node->work_type == WORK_TYPE_REDIRECT)
+ cnic_cm_process_redirect(dev,
+ &node->work_data.cnic_redir);
+ cons++;
+ cons &= WORK_RING_SIZE_MASK;
+ }
+ cp->cnic_wr_cons = cons;
+}
+
+static void cnic_free_dev(struct cnic_dev *dev)
+{
+ printk(KERN_INFO PFX "Removed CNIC device: %s\n", dev->netdev->name);
+ cnic_free_resc(dev);
+ cnic_unregister_sysfs(dev);
+ pci_dev_put(dev->pcidev);
+ dev_put(dev->netdev);
+ kfree(dev);
+}
+
+static void cnic_cm_free_mem(struct cnic_dev *dev)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+
+ kfree(cp->csk_tbl);
+ cp->csk_tbl = NULL;
+}
+
+static int cnic_cm_alloc_mem(struct cnic_dev *dev)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+
+ cp->csk_tbl = kmalloc(sizeof(struct cnic_sock) * MAX_CM_SK_TBL_SZ,
+ GFP_KERNEL);
+ if (!cp->csk_tbl)
+ return -ENOMEM;
+ memset(cp->csk_tbl, 0, sizeof(struct cnic_sock) * MAX_CM_SK_TBL_SZ);
+ return 0;
+}
+
+static int cnic_cm_open(struct cnic_dev *dev)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ u32 seed;
+ int err;
+
+ get_random_bytes(&seed, 4);
+ bnx2_ctx_wr(dev->bp, 45, 0, seed);
+
+ err = cnic_cm_alloc_mem(dev);
+ if (err) {
+ cnic_cm_free_mem(dev);
+ return err;
+ }
+
+ spin_lock_init(&cp->cm_lock);
+
+ INIT_WORK(&cp->cnic_task, cnic_task);
+
+ cp->cm_nb.notifier_call = cnic_net_callback;
+ register_netevent_notifier(&cp->cm_nb);
+
+ dev->cm_create = cnic_cm_create;
+ dev->cm_destroy = cnic_cm_destroy;
+ dev->cm_connect = cnic_cm_connect;
+ dev->cm_abort = cnic_cm_abort;
+ dev->cm_close = cnic_cm_close;
+ dev->cm_select_dev = cnic_cm_select_dev;
+
+ cp->ulp_handle[CNIC_ULP_L4] = dev;
+ rcu_assign_pointer(cp->ulp_ops[CNIC_ULP_L4], &cm_ulp_ops);
+ return 0;
+}
+
+static void cnic_cm_cleanup(struct cnic_sock *csk)
+{
+ clear_bit(SK_F_INUSE, &csk->flags);
+ if (csk->dst) {
+ if (csk->dst->neighbour)
+ neigh_release(csk->dst->neighbour);
+ dst_release(csk->dst);
+ csk->dst = NULL;
+ }
+}
+
+static int cnic_cm_shutdown(struct cnic_dev *dev)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ int i;
+
+ unregister_netevent_notifier(&cp->cm_nb);
+
+ cancel_work_sync(&cp->cnic_task);
+
+ if (!cp->csk_tbl)
+ return 0;
+
+ for (i = 0; i < MAX_CM_SK_TBL_SZ; i++) {
+ struct cnic_sock *csk = &cp->csk_tbl[i];
+
+ cnic_cm_cleanup(csk);
+ }
+ cnic_cm_free_mem(dev);
+
+ return 0;
+}
+
+static void cnic_init_context(struct cnic_dev *dev, u32 cid)
+{
+ u32 cid_addr;
+ int i;
+
+ cid_addr = GET_CID_ADDR(cid);
+
+ for (i = 0; i < CTX_SIZE; i += 4)
+ bnx2_ctx_wr(dev->bp, cid_addr, i, 0);
+}
+
+static int cnic_start_hw(struct cnic_dev *dev)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ u32 val;
+ int err;
+
+ if (test_bit(CNIC_F_CNIC_UP, &dev->flags))
+ return -EALREADY;
+
+ val = REG_RD(dev, BNX2_MQ_CONFIG);
+ val &= ~BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE;
+ if (BCM_PAGE_BITS > 12)
+ val |= (12 - 8) << 4;
+ else
+ val |= (BCM_PAGE_BITS - 8) << 4;
+
+ REG_WR(dev, BNX2_MQ_CONFIG, val);
+
+ REG_WR(dev, BNX2_HC_COMP_PROD_TRIP, (2 << 16) | 8);
+ REG_WR(dev, BNX2_HC_COM_TICKS, (64 << 16) | 220);
+ REG_WR(dev, BNX2_HC_CMD_TICKS, (64 << 16) | 220);
+
+ cnic_init_context(dev, KWQ_CID);
+ cnic_init_context(dev, KCQ_CID);
+
+ cp->kwq_cid_addr = GET_CID_ADDR(KWQ_CID);
+ cp->kwq_io_addr = MB_GET_CID_ADDR(KWQ_CID) + L5_KRNLQ_HOST_QIDX;
+
+ cnic_setup_page_tbl(cp->kwq_pgtbl, KWQ_PAGE_CNT, cp->kwq_mapping);
+
+ cp->kwq_prod_idx = 0;
+ cp->kwq_con_idx = 0;
+
+ /* Initialize the kernel work queue context. */
+ val = KRNLQ_TYPE_TYPE_KRNLQ | KRNLQ_SIZE_TYPE_SIZE |
+ (BCM_PAGE_BITS - 8) | KRNLQ_FLAGS_QE_SELF_SEQ;
+ bnx2_ctx_wr(dev->bp, cp->kwq_cid_addr, L5_KRNLQ_TYPE, val);
+
+ val = (PAGE_SIZE / sizeof(struct kwqe) - 1) << 16;
+ bnx2_ctx_wr(dev->bp, cp->kwq_cid_addr, L5_KRNLQ_QE_SELF_SEQ_MAX, val);
+
+ val = ((PAGE_SIZE / sizeof(struct kwqe)) << 16) | KWQ_PAGE_CNT;
+ bnx2_ctx_wr(dev->bp, cp->kwq_cid_addr, L5_KRNLQ_PGTBL_NPAGES, val);
+
+ val = (u32) ((u64) cp->kwq_pgtbl_mapping >> 32);
+ bnx2_ctx_wr(dev->bp, cp->kwq_cid_addr, L5_KRNLQ_PGTBL_HADDR_HI, val);
+
+ val = (u32) cp->kwq_pgtbl_mapping;
+ bnx2_ctx_wr(dev->bp, cp->kwq_cid_addr, L5_KRNLQ_PGTBL_HADDR_LO, val);
+
+ cp->kcq_cid_addr = GET_CID_ADDR(KCQ_CID);
+ cp->kcq_io_addr = MB_GET_CID_ADDR(KCQ_CID) + L5_KRNLQ_HOST_QIDX;
+
+ cnic_setup_page_tbl(cp->kcq_pgtbl, KCQ_PAGE_CNT, cp->kcq_mapping);
+
+ cp->kcq_prod_idx = 0;
+
+ /* Initialize the kernel complete queue context. */
+ val = KRNLQ_TYPE_TYPE_KRNLQ | KRNLQ_SIZE_TYPE_SIZE |
+ (BCM_PAGE_BITS - 8) | KRNLQ_FLAGS_QE_SELF_SEQ;
+ bnx2_ctx_wr(dev->bp, cp->kcq_cid_addr, L5_KRNLQ_TYPE, val);
+
+ val = (BCM_PAGE_SIZE / sizeof(struct kcqe) - 1) << 16;
+ bnx2_ctx_wr(dev->bp, cp->kcq_cid_addr, L5_KRNLQ_QE_SELF_SEQ_MAX, val);
+
+ val = ((BCM_PAGE_SIZE / sizeof(struct kcqe)) << 16) | KCQ_PAGE_CNT;
+ bnx2_ctx_wr(dev->bp, cp->kcq_cid_addr, L5_KRNLQ_PGTBL_NPAGES, val);
+
+ val = (u32) ((u64) cp->kcq_pgtbl_mapping >> 32);
+ bnx2_ctx_wr(dev->bp, cp->kcq_cid_addr, L5_KRNLQ_PGTBL_HADDR_HI, val);
+
+ val = (u32) cp->kcq_pgtbl_mapping;
+ bnx2_ctx_wr(dev->bp, cp->kcq_cid_addr, L5_KRNLQ_PGTBL_HADDR_LO, val);
+
+ /* Enable Commnad Scheduler notification when we write to the
+ * host producer index of the kernel contexts. */
+ REG_WR(dev, BNX2_MQ_KNL_CMD_MASK1, 2);
+
+ /* Enable Command Scheduler notification when we write to either
+ * the Send Queue or Receive Queue producer indexes of the kernel
+ * bypass contexts. */
+ REG_WR(dev, BNX2_MQ_KNL_BYP_CMD_MASK1, 7);
+ REG_WR(dev, BNX2_MQ_KNL_BYP_WRITE_MASK1, 7);
+
+ /* Notify COM when the driver post an application buffer. */
+ REG_WR(dev, BNX2_MQ_KNL_RX_V2P_MASK2, 0x2000);
+
+ /* Set the CP and COM doorbells. These two processors polls the
+ * doorbell for a non zero value before running. This must be done
+ * after setting up the kernel queue contexts. */
+ bnx2_reg_wr_ind(dev->bp, BNX2_CP_SCRATCH + 0x20, 1);
+ bnx2_reg_wr_ind(dev->bp, BNX2_COM_SCRATCH + 0x20, 1);
+
+ err = bnx2_register_cnic(dev->netdev, &my_cnic_ops, dev);
+ if (err) {
+ printk(KERN_ERR PFX "%s: bnx2_register_cnic failed\n",
+ dev->netdev->name);
+ return -EBUSY;
+ }
+
+ set_bit(CNIC_F_CNIC_UP, &dev->flags);
+ cnic_cm_open(dev);
+
+ return 0;
+}
+
+static void cnic_stop_hw(struct cnic_dev *dev)
+{
+ if (test_bit(CNIC_F_CNIC_UP, &dev->flags)) {
+ struct cnic_local *cp = dev->cnic_priv;
+
+ cnic_cm_shutdown(dev);
+ bnx2_unregister_cnic(dev->netdev);
+ rcu_assign_pointer(cp->ulp_ops[CNIC_ULP_L4], NULL);
+ clear_bit(CNIC_F_CNIC_UP, &dev->flags);
+ synchronize_rcu();
+
+ bnx2_reg_wr_ind(dev->bp, BNX2_CP_SCRATCH + 0x20, 0);
+ bnx2_reg_wr_ind(dev->bp, BNX2_COM_SCRATCH + 0x20, 0);
+
+ cnic_init_context(dev, KWQ_CID);
+ cnic_init_context(dev, KCQ_CID);
+ }
+}
+
+static struct cnic_dev *init_cnic(struct net_device *dev)
+{
+ struct cnic_dev *cdev;
+ struct cnic_local *bp;
+ struct bnx2 *bnx2_bp = netdev_priv(dev);
+ struct pci_dev *pdev = bnx2_bp->pdev;
+ int alloc_size;
+
+ if (!pdev)
+ return NULL;
+
+ pci_dev_get(pdev);
+ if (pdev->device == PCI_DEVICE_ID_NX2_5709 ||
+ pdev->device == PCI_DEVICE_ID_NX2_5709S) {
+ pci_dev_put(pdev);
+ return NULL;
+ }
+
+ alloc_size = sizeof(struct cnic_dev) + sizeof(struct cnic_local);
+
+ cdev = kmalloc(alloc_size , GFP_KERNEL);
+ if (cdev == NULL) {
+ printk(KERN_ERR PFX "%s: allocate dev struct failure\n",
+ dev->name);
+ pci_dev_put(pdev);
+ return cdev;
+ }
+ memset(cdev, 0, alloc_size);
+
+ cdev->netdev = dev;
+ cdev->bp = bnx2_bp;
+ cdev->pcidev = pdev;
+ cdev->regview = bnx2_bp->regview;
+ cdev->cnic_priv = (char *)cdev + sizeof(struct cnic_dev);
+ cdev->submit_kwqes = cnic_submit_kernel_wqes;
+ cdev->register_device = cnic_register_device;
+ cdev->unregister_device = cnic_unregister_device;
+
+ if (cnic_alloc_resc(cdev)) {
+ printk(KERN_ERR PFX "%s: allocate resource failure\n",
+ dev->name);
+ kfree(cdev);
+ pci_dev_put(pdev);
+ return NULL;
+ }
+ bp = cdev->cnic_priv;
+ bp->dev = cdev;
+ spin_lock_init(&bp->cnic_ulp_lock);
+ dev_hold(cdev->netdev);
+ printk(KERN_INFO PFX "Added CNIC device: %s\n", dev->name);
+
+ return cdev;
+}
+
+static struct cnic_dev *is_cnic_dev(struct net_device *dev)
+{
+ struct ethtool_drvinfo drvinfo;
+ struct cnic_dev *cdev = NULL;
+
+ if (dev->ethtool_ops && dev->ethtool_ops->get_drvinfo) {
+ memset(&drvinfo, 0, sizeof(drvinfo));
+ dev->ethtool_ops->get_drvinfo(dev, &drvinfo);
+
+ if (!strcmp(drvinfo.driver, "bnx2")) {
+ cdev = init_cnic(dev);
+ if (cdev) {
+ cnic_register_sysfs(cdev);
+ write_lock(&cnic_dev_lock);
+ list_add(&cdev->list, &cnic_dev_list);
+ write_unlock(&cnic_dev_lock);
+ }
+ }
+ }
+ return cdev;
+}
+
+/**
+ * IP event handler
+ */
+static int cnic_ip_event(struct notifier_block *this, unsigned long event,
+ void *ptr)
+{
+ struct in_ifaddr *ifa = (struct in_ifaddr *) ptr;
+ struct net_device *netdev = (struct net_device *) ifa->ifa_dev->dev;
+ struct cnic_dev *dev;
+ int if_type;
+ u32 my_dev = 0;
+
+ read_lock(&cnic_dev_lock);
+ list_for_each_entry(dev, &cnic_dev_list, list) {
+ if (netdev == dev->netdev) {
+ my_dev = 1;
+ cnic_hold(dev);
+ break;
+ }
+ }
+ read_unlock(&cnic_dev_lock);
+
+ if (my_dev) {
+ struct cnic_local *cp = dev->cnic_priv;
+
+ rcu_read_lock();
+ for (if_type = 0; if_type < MAX_CNIC_ULP_TYPE; if_type++) {
+ struct cnic_ulp_ops *ulp_ops;
+
+ ulp_ops = rcu_dereference(cp->ulp_ops[if_type]);
+ if (ulp_ops) {
+ void *ctx = cp->ulp_handle[if_type];
+
+ ulp_ops->indicate_inetevent(ctx, event);
+ }
+ }
+ rcu_read_unlock();
+
+ cnic_put(dev);
+ }
+
+ return NOTIFY_DONE;
+}
+
+/**
+ * netdev event handler
+ */
+static int cnic_netdev_event(struct notifier_block *this, unsigned long event,
+ void *ptr)
+{
+ struct net_device *netdev = ptr;
+ struct cnic_dev *dev;
+ int if_type;
+ u32 my_dev = 0;
+
+ read_lock(&cnic_dev_lock);
+ list_for_each_entry(dev, &cnic_dev_list, list) {
+ if (netdev == dev->netdev) {
+ my_dev = 1;
+ cnic_hold(dev);
+ break;
+ }
+ }
+ read_unlock(&cnic_dev_lock);
+
+ if (!my_dev && event == NETDEV_REGISTER) {
+ /* Check for the hot-plug device */
+ dev = is_cnic_dev(netdev);
+ if (dev) {
+ my_dev = 1;
+ cnic_hold(dev);
+ }
+ }
+ if (my_dev) {
+ struct cnic_local *cp = dev->cnic_priv;
+
+ if (event == NETDEV_REGISTER)
+ cnic_ulp_init(dev);
+ else if (event == NETDEV_UNREGISTER)
+ cnic_ulp_exit(dev);
+ else if (event == NETDEV_UP) {
+ mutex_lock(&cnic_lock);
+ set_bit(CNIC_F_IF_UP, &dev->flags);
+ if (dev->use_count) {
+ if (!cnic_start_hw(dev))
+ cnic_ulp_start(dev);
+ }
+ mutex_unlock(&cnic_lock);
+ }
+
+ rcu_read_lock();
+ for (if_type = 0; if_type < MAX_CNIC_ULP_TYPE; if_type++) {
+ struct cnic_ulp_ops *ulp_ops;
+ void *ctx;
+
+ ulp_ops = rcu_dereference(cp->ulp_ops[if_type]);
+ if (!ulp_ops)
+ continue;
+
+ ctx = cp->ulp_handle[if_type];
+
+ ulp_ops->indicate_netevent(ctx, event);
+ }
+ rcu_read_unlock();
+
+ if (event == NETDEV_GOING_DOWN) {
+ mutex_lock(&cnic_lock);
+ clear_bit(CNIC_F_IF_UP, &dev->flags);
+ cnic_ulp_stop(dev);
+ cnic_stop_hw(dev);
+ mutex_unlock(&cnic_lock);
+ } else if (event == NETDEV_UNREGISTER) {
+ int i = 0;
+
+ write_lock(&cnic_dev_lock);
+ list_del_init(&dev->list);
+ write_unlock(&cnic_dev_lock);
+ while ((atomic_read(&dev->ref_count) != 1) &&
+ i < 10) {
+ msleep(100);
+ i++;
+ }
+ if (atomic_read(&dev->ref_count) != 1)
+ printk(KERN_ERR PFX "%s: Failed waiting"
+ " for ref count to go zero\n",
+ dev->netdev->name);
+
+ cnic_free_dev(dev);
+ goto done;
+ }
+ cnic_put(dev);
+ }
+done:
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block cnic_ip_notifier = {
+ cnic_ip_event,
+ 0
+};
+
+static struct notifier_block cnic_netdev_notifier = {
+ cnic_netdev_event,
+ 0
+};
+
+static void cnic_release(void)
+{
+ struct cnic_dev *dev;
+
+ while (!list_empty(&cnic_dev_list)) {
+ dev = list_entry(cnic_dev_list.next, struct cnic_dev, list);
+ if (test_bit(CNIC_F_CNIC_UP, &dev->flags))
+ cnic_stop_hw(dev);
+
+ list_del_init(&dev->list);
+ cnic_free_dev(dev);
+ }
+}
+
+static int __init cnic_init(void)
+{
+ int rc = 0;
+ struct net_device *dev;
+
+ printk(KERN_INFO "%s", version);
+
+ cnic_sysfs_setup();
+
+ read_lock(&dev_base_lock);
+ /* Find Teton devices */
+ for_each_netdev(dev)
+ is_cnic_dev(dev);
+
+ read_unlock(&dev_base_lock);
+
+ rc = register_inetaddr_notifier(&cnic_ip_notifier);
+ if (rc)
+ cnic_release();
+ rc = register_netdevice_notifier(&cnic_netdev_notifier);
+ if (rc) {
+ unregister_inetaddr_notifier(&cnic_ip_notifier);
+ cnic_release();
+ }
+ return rc;
+}
+
+static void __exit cnic_exit(void)
+{
+ unregister_inetaddr_notifier(&cnic_ip_notifier);
+ unregister_netdevice_notifier(&cnic_netdev_notifier);
+ cnic_release();
+ cnic_sysfs_cleanup();
+
+ return;
+}
+
+module_init(cnic_init);
+module_exit(cnic_exit);
diff --git a/drivers/net/cnic.h b/drivers/net/cnic.h
new file mode 100644
index 0000000..6ba1f4e
--- /dev/null
+++ b/drivers/net/cnic.h
@@ -0,0 +1,163 @@
+/* cnic.h: Broadcom CNIC core network driver.
+ *
+ * Copyright (c) 2006 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * Written by: John(Zongxi) Chen (zongxic@broadcom.com)
+ */
+
+
+#ifndef CNIC_H
+#define CNIC_H
+
+#if !defined(__LITTLE_ENDIAN) && !defined(__BIG_ENDIAN)
+ #error "Missing either LITTLE_ENDIAN or BIG_ENDIAN definition."
+#endif
+
+#define KWQ_PAGE_CNT 4
+#define KCQ_PAGE_CNT 16
+
+#define KWQ_CID 24
+#define KCQ_CID 25
+
+/*
+ * krnlq_context definition
+ */
+#define L5_KRNLQ_FLAGS 0x00000000
+#define L5_KRNLQ_SIZE 0x00000000
+#define L5_KRNLQ_TYPE 0x00000000
+#define KRNLQ_FLAGS_PG_SZ (0xf<<0)
+#define KRNLQ_FLAGS_PG_SZ_256 (0<<0)
+#define KRNLQ_FLAGS_PG_SZ_512 (1<<0)
+#define KRNLQ_FLAGS_PG_SZ_1K (2<<0)
+#define KRNLQ_FLAGS_PG_SZ_2K (3<<0)
+#define KRNLQ_FLAGS_PG_SZ_4K (4<<0)
+#define KRNLQ_FLAGS_PG_SZ_8K (5<<0)
+#define KRNLQ_FLAGS_PG_SZ_16K (6<<0)
+#define KRNLQ_FLAGS_PG_SZ_32K (7<<0)
+#define KRNLQ_FLAGS_PG_SZ_64K (8<<0)
+#define KRNLQ_FLAGS_PG_SZ_128K (9<<0)
+#define KRNLQ_FLAGS_PG_SZ_256K (10<<0)
+#define KRNLQ_FLAGS_PG_SZ_512K (11<<0)
+#define KRNLQ_FLAGS_PG_SZ_1M (12<<0)
+#define KRNLQ_FLAGS_PG_SZ_2M (13<<0)
+#define KRNLQ_FLAGS_QE_SELF_SEQ (1<<15)
+#define KRNLQ_SIZE_TYPE_SIZE ((((0x28 + 0x1f) & ~0x1f) / 0x20) << 16)
+#define KRNLQ_TYPE_TYPE (0xf<<28)
+#define KRNLQ_TYPE_TYPE_EMPTY (0<<28)
+#define KRNLQ_TYPE_TYPE_KRNLQ (6<<28)
+
+#define L5_KRNLQ_HOST_QIDX 0x00000004
+#define L5_KRNLQ_HOST_FW_QIDX 0x00000008
+#define L5_KRNLQ_NX_QE_SELF_SEQ 0x0000000c
+#define L5_KRNLQ_QE_SELF_SEQ_MAX 0x0000000c
+#define L5_KRNLQ_NX_QE_HADDR_HI 0x00000010
+#define L5_KRNLQ_NX_QE_HADDR_LO 0x00000014
+#define L5_KRNLQ_PGTBL_PGIDX 0x00000018
+#define L5_KRNLQ_NX_PG_QIDX 0x00000018
+#define L5_KRNLQ_PGTBL_NPAGES 0x0000001c
+#define L5_KRNLQ_QIDX_INCR 0x0000001c
+#define L5_KRNLQ_PGTBL_HADDR_HI 0x00000020
+#define L5_KRNLQ_PGTBL_HADDR_LO 0x00000024
+
+struct cnic_redirect_entry {
+ struct dst_entry *old_dst;
+ struct dst_entry *new_dst;
+};
+
+struct cnic_work_node {
+ u32 work_type;
+#define WORK_TYPE_KCQE 1
+#define WORK_TYPE_NEIGH_UPDATE 2
+#define WORK_TYPE_REDIRECT 3
+ union {
+ struct kcqe kcqe;
+ struct neighbour *neigh;
+ struct cnic_redirect_entry cnic_redir;
+ } work_data;
+};
+
+#define WORK_RING_SIZE 128
+#define WORK_RING_SIZE_MASK 127
+#define MAX_CM_SK_TBL_SZ 128
+#define MAX_COMPLETED_KCQE 64
+
+#define KWQE_CNT (BCM_PAGE_SIZE / sizeof(struct kwqe))
+#define KCQE_CNT (BCM_PAGE_SIZE / sizeof(struct kcqe))
+#define MAX_KWQE_CNT (KWQE_CNT - 1)
+#define MAX_KCQE_CNT (KCQE_CNT - 1)
+
+#define MAX_KWQ_IDX ((KWQ_PAGE_CNT * KWQE_CNT) - 1)
+#define MAX_KCQ_IDX ((KCQ_PAGE_CNT * KCQE_CNT) - 1)
+
+#define KWQ_PG(x) (((x) & ~MAX_KWQE_CNT) >> (BCM_PAGE_BITS - 5))
+#define KWQ_IDX(x) ((x) & MAX_KWQE_CNT)
+
+#define KCQ_PG(x) (((x) & ~MAX_KCQE_CNT) >> (BCM_PAGE_BITS - 5))
+#define KCQ_IDX(x) ((x) & MAX_KCQE_CNT)
+
+#define DEF_IPID_COUNT 0xc001
+
+#define DEF_KA_TIMEOUT 10000
+#define DEF_KA_INTERVAL 300000
+#define DEF_KA_MAX_PROBE_COUNT 3
+#define DEF_TOS 0
+#define DEF_TTL 0xfe
+#define DEF_SND_SEQ_SCALE 0
+#define DEF_RCV_BUF 0xffff
+#define DEF_SND_BUF 0xffff
+#define DEF_SEED 0
+
+struct cnic_local {
+
+ spinlock_t cnic_ulp_lock;
+ void *ulp_handle[MAX_CNIC_ULP_TYPE];
+ unsigned long ulp_flags[MAX_CNIC_ULP_TYPE];
+#define ULP_F_INIT 0
+#define ULP_F_START 1
+ struct cnic_ulp_ops *ulp_ops[MAX_CNIC_ULP_TYPE];
+
+ struct cnic_dev *dev;
+
+ u32 kwq_cid_addr;
+ u32 kcq_cid_addr;
+
+ struct kwqe *kwq[KWQ_PAGE_CNT];
+ dma_addr_t kwq_mapping[KWQ_PAGE_CNT];
+ u16 kwq_prod_idx;
+ u32 kwq_io_addr;
+
+ u16 kwq_con_idx;
+
+ void *kwq_pgtbl;
+ dma_addr_t kwq_pgtbl_mapping;
+ int kwq_pgtbl_size;
+
+ struct kcqe *kcq[KCQ_PAGE_CNT];
+ dma_addr_t kcq_mapping[KCQ_PAGE_CNT];
+ u16 kcq_prod_idx;
+ u32 kcq_io_addr;
+
+ void *kcq_pgtbl;
+ dma_addr_t kcq_pgtbl_mapping;
+ int kcq_pgtbl_size;
+
+ struct kcqe *completed_kcq[MAX_COMPLETED_KCQE];
+
+ struct cnic_sock *csk_tbl;
+ spinlock_t cm_lock;
+
+ struct notifier_block cm_nb;
+
+ struct cnic_work_node cnic_work_ring[WORK_RING_SIZE];
+ int cnic_wr_cons;
+ int cnic_wr_prod;
+
+ struct work_struct cnic_task;
+
+};
+
+#endif
diff --git a/drivers/net/cnic_cm.h b/drivers/net/cnic_cm.h
new file mode 100644
index 0000000..d6ea01d
--- /dev/null
+++ b/drivers/net/cnic_cm.h
@@ -0,0 +1,555 @@
+#ifndef __57XX_L5CM_HSI_LINUX_LE__
+#define __57XX_L5CM_HSI_LINUX_LE__
+
+/* KWQ (kernel work queue) request op codes */
+#define L4_KWQE_OPCODE_VALUE_CONNECT1 (50)
+#define L4_KWQE_OPCODE_VALUE_CONNECT2 (51)
+#define L4_KWQE_OPCODE_VALUE_CONNECT3 (52)
+#define L4_KWQE_OPCODE_VALUE_RESET (53)
+#define L4_KWQE_OPCODE_VALUE_CLOSE (54)
+#define L4_KWQE_OPCODE_VALUE_UPDATE_SECRET (60)
+#define L4_KWQE_OPCODE_VALUE_INIT_ULP (61)
+
+#define L4_KWQE_OPCODE_VALUE_OFFLOAD_PG (1)
+#define L4_KWQE_OPCODE_VALUE_UPDATE_PG (9)
+#define L4_KWQE_OPCODE_VALUE_UPLOAD_PG (14)
+
+/* KCQ (kernel completion queue) response op codes */
+#define L4_KCQE_OPCODE_VALUE_CONNECT_RESP (52)
+#define L4_KCQE_OPCODE_VALUE_CLOSE_COMP (53)
+#define L4_KCQE_OPCODE_VALUE_RESET_COMP (54)
+#define L4_KCQE_OPCODE_VALUE_FW_TCP_UPDATE (55)
+#define L4_KCQE_OPCODE_VALUE_CONNECT_COMPLETE (56)
+#define L4_KCQE_OPCODE_VALUE_RESET_RECEIVED (57)
+#define L4_KCQE_OPCODE_VALUE_CLOSE_RECEIVED (58)
+#define L4_KCQE_OPCODE_VALUE_CONNECT_CLOSE (59)
+#define L4_KCQE_OPCODE_VALUE_CONNECT_RESET (60)
+#define L4_KCQE_OPCODE_VALUE_INIT_ULP (61)
+
+#define L4_KCQE_OPCODE_VALUE_OFFLOAD_PG (1)
+#define L4_KCQE_OPCODE_VALUE_UPLOAD_PG (14)
+
+/* KCQ (kernel completion queue) completion status */
+#define L4_KCQE_COMPLETION_STATUS_SUCCESS (0)
+#define L4_KCQE_COMPLETION_STATUS_TIMEOUT (0x93)
+
+#define L4_LAYER_CODE (4)
+
+/*
+ * L4 KCQ CQE
+ */
+struct l4_kcq {
+ u32 cid;
+ u32 pg_cid;
+ u32 conn_id;
+ u32 pg_host_opaque;
+#if defined(__BIG_ENDIAN)
+ u16 status;
+ u16 reserved1;
+#elif defined(__LITTLE_ENDIAN)
+ u16 reserved1;
+ u16 status;
+#endif
+ u32 reserved2[2];
+#if defined(__BIG_ENDIAN)
+ u8 flags;
+#define L4_KCQ_RESERVED3 (0xF<<0)
+#define L4_KCQ_RESERVED3_SHIFT 0
+#define L4_KCQ_LAYER_CODE (0x7<<4)
+#define L4_KCQ_LAYER_CODE_SHIFT 4
+#define L4_KCQ_RESERVED4 (0x1<<7)
+#define L4_KCQ_RESERVED4_SHIFT 7
+ u8 op_code;
+ u16 qe_self_seq;
+#elif defined(__LITTLE_ENDIAN)
+ u16 qe_self_seq;
+ u8 op_code;
+ u8 flags;
+#define L4_KCQ_RESERVED3 (0xF<<0)
+#define L4_KCQ_RESERVED3_SHIFT 0
+#define L4_KCQ_LAYER_CODE (0x7<<4)
+#define L4_KCQ_LAYER_CODE_SHIFT 4
+#define L4_KCQ_RESERVED4 (0x1<<7)
+#define L4_KCQ_RESERVED4_SHIFT 7
+#endif
+};
+
+
+/*
+ * L4 KCQ CQE PG upload
+ */
+struct l4_kcq_upload_pg {
+ u32 pg_cid;
+#if defined(__BIG_ENDIAN)
+ u16 pg_status;
+ u16 pg_ipid_count;
+#elif defined(__LITTLE_ENDIAN)
+ u16 pg_ipid_count;
+ u16 pg_status;
+#endif
+ u32 reserved1[5];
+#if defined(__BIG_ENDIAN)
+ u8 flags;
+#define L4_KCQ_UPLOAD_PG_RESERVED3 (0xF<<0)
+#define L4_KCQ_UPLOAD_PG_RESERVED3_SHIFT 0
+#define L4_KCQ_UPLOAD_PG_LAYER_CODE (0x7<<4)
+#define L4_KCQ_UPLOAD_PG_LAYER_CODE_SHIFT 4
+#define L4_KCQ_UPLOAD_PG_RESERVED4 (0x1<<7)
+#define L4_KCQ_UPLOAD_PG_RESERVED4_SHIFT 7
+ u8 op_code;
+ u16 qe_self_seq;
+#elif defined(__LITTLE_ENDIAN)
+ u16 qe_self_seq;
+ u8 op_code;
+ u8 flags;
+#define L4_KCQ_UPLOAD_PG_RESERVED3 (0xF<<0)
+#define L4_KCQ_UPLOAD_PG_RESERVED3_SHIFT 0
+#define L4_KCQ_UPLOAD_PG_LAYER_CODE (0x7<<4)
+#define L4_KCQ_UPLOAD_PG_LAYER_CODE_SHIFT 4
+#define L4_KCQ_UPLOAD_PG_RESERVED4 (0x1<<7)
+#define L4_KCQ_UPLOAD_PG_RESERVED4_SHIFT 7
+#endif
+};
+
+
+/*
+ * Gracefully close the connection request
+ */
+struct l4_kwq_close_req {
+#if defined(__BIG_ENDIAN)
+ u8 flags;
+#define L4_KWQ_CLOSE_REQ_RESERVED1 (0xF<<0)
+#define L4_KWQ_CLOSE_REQ_RESERVED1_SHIFT 0
+#define L4_KWQ_CLOSE_REQ_LAYER_CODE (0x7<<4)
+#define L4_KWQ_CLOSE_REQ_LAYER_CODE_SHIFT 4
+#define L4_KWQ_CLOSE_REQ_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_CLOSE_REQ_LINKED_WITH_NEXT_SHIFT 7
+ u8 op_code;
+ u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+ u16 reserved0;
+ u8 op_code;
+ u8 flags;
+#define L4_KWQ_CLOSE_REQ_RESERVED1 (0xF<<0)
+#define L4_KWQ_CLOSE_REQ_RESERVED1_SHIFT 0
+#define L4_KWQ_CLOSE_REQ_LAYER_CODE (0x7<<4)
+#define L4_KWQ_CLOSE_REQ_LAYER_CODE_SHIFT 4
+#define L4_KWQ_CLOSE_REQ_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_CLOSE_REQ_LINKED_WITH_NEXT_SHIFT 7
+#endif
+ u32 cid;
+ u32 reserved2[6];
+};
+
+
+/*
+ * The first request to be passed in order to establish connection in option2
+ */
+struct l4_kwq_connect_req1 {
+#if defined(__BIG_ENDIAN)
+ u8 flags;
+#define L4_KWQ_CONNECT_REQ1_RESERVED1 (0xF<<0)
+#define L4_KWQ_CONNECT_REQ1_RESERVED1_SHIFT 0
+#define L4_KWQ_CONNECT_REQ1_LAYER_CODE (0x7<<4)
+#define L4_KWQ_CONNECT_REQ1_LAYER_CODE_SHIFT 4
+#define L4_KWQ_CONNECT_REQ1_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_CONNECT_REQ1_LINKED_WITH_NEXT_SHIFT 7
+ u8 op_code;
+ u8 reserved0;
+ u8 conn_flags;
+#define L4_KWQ_CONNECT_REQ1_IS_PG_HOST_OPAQUE (0x1<<0)
+#define L4_KWQ_CONNECT_REQ1_IS_PG_HOST_OPAQUE_SHIFT 0
+#define L4_KWQ_CONNECT_REQ1_IP_V6 (0x1<<1)
+#define L4_KWQ_CONNECT_REQ1_IP_V6_SHIFT 1
+#define L4_KWQ_CONNECT_REQ1_PASSIVE_FLAG (0x1<<2)
+#define L4_KWQ_CONNECT_REQ1_PASSIVE_FLAG_SHIFT 2
+#define L4_KWQ_CONNECT_REQ1_RSRV (0x1F<<3)
+#define L4_KWQ_CONNECT_REQ1_RSRV_SHIFT 3
+#elif defined(__LITTLE_ENDIAN)
+ u8 conn_flags;
+#define L4_KWQ_CONNECT_REQ1_IS_PG_HOST_OPAQUE (0x1<<0)
+#define L4_KWQ_CONNECT_REQ1_IS_PG_HOST_OPAQUE_SHIFT 0
+#define L4_KWQ_CONNECT_REQ1_IP_V6 (0x1<<1)
+#define L4_KWQ_CONNECT_REQ1_IP_V6_SHIFT 1
+#define L4_KWQ_CONNECT_REQ1_PASSIVE_FLAG (0x1<<2)
+#define L4_KWQ_CONNECT_REQ1_PASSIVE_FLAG_SHIFT 2
+#define L4_KWQ_CONNECT_REQ1_RSRV (0x1F<<3)
+#define L4_KWQ_CONNECT_REQ1_RSRV_SHIFT 3
+ u8 reserved0;
+ u8 op_code;
+ u8 flags;
+#define L4_KWQ_CONNECT_REQ1_RESERVED1 (0xF<<0)
+#define L4_KWQ_CONNECT_REQ1_RESERVED1_SHIFT 0
+#define L4_KWQ_CONNECT_REQ1_LAYER_CODE (0x7<<4)
+#define L4_KWQ_CONNECT_REQ1_LAYER_CODE_SHIFT 4
+#define L4_KWQ_CONNECT_REQ1_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_CONNECT_REQ1_LINKED_WITH_NEXT_SHIFT 7
+#endif
+ u32 cid;
+ u32 pg_cid;
+ u32 src_ip;
+ u32 dst_ip;
+#if defined(__BIG_ENDIAN)
+ u16 dst_port;
+ u16 src_port;
+#elif defined(__LITTLE_ENDIAN)
+ u16 src_port;
+ u16 dst_port;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 rsrv1[3];
+ u8 tcp_flags;
+#define L4_KWQ_CONNECT_REQ1_NO_DELAY_ACK (0x1<<0)
+#define L4_KWQ_CONNECT_REQ1_NO_DELAY_ACK_SHIFT 0
+#define L4_KWQ_CONNECT_REQ1_KEEP_ALIVE (0x1<<1)
+#define L4_KWQ_CONNECT_REQ1_KEEP_ALIVE_SHIFT 1
+#define L4_KWQ_CONNECT_REQ1_NAGLE_ENABLE (0x1<<2)
+#define L4_KWQ_CONNECT_REQ1_NAGLE_ENABLE_SHIFT 2
+#define L4_KWQ_CONNECT_REQ1_TIME_STAMP (0x1<<3)
+#define L4_KWQ_CONNECT_REQ1_TIME_STAMP_SHIFT 3
+#define L4_KWQ_CONNECT_REQ1_SACK (0x1<<4)
+#define L4_KWQ_CONNECT_REQ1_SACK_SHIFT 4
+#define L4_KWQ_CONNECT_REQ1_SEG_SCALING (0x1<<5)
+#define L4_KWQ_CONNECT_REQ1_SEG_SCALING_SHIFT 5
+#define L4_KWQ_CONNECT_REQ1_RESERVED2 (0x3<<6)
+#define L4_KWQ_CONNECT_REQ1_RESERVED2_SHIFT 6
+#elif defined(__LITTLE_ENDIAN)
+ u8 tcp_flags;
+#define L4_KWQ_CONNECT_REQ1_NO_DELAY_ACK (0x1<<0)
+#define L4_KWQ_CONNECT_REQ1_NO_DELAY_ACK_SHIFT 0
+#define L4_KWQ_CONNECT_REQ1_KEEP_ALIVE (0x1<<1)
+#define L4_KWQ_CONNECT_REQ1_KEEP_ALIVE_SHIFT 1
+#define L4_KWQ_CONNECT_REQ1_NAGLE_ENABLE (0x1<<2)
+#define L4_KWQ_CONNECT_REQ1_NAGLE_ENABLE_SHIFT 2
+#define L4_KWQ_CONNECT_REQ1_TIME_STAMP (0x1<<3)
+#define L4_KWQ_CONNECT_REQ1_TIME_STAMP_SHIFT 3
+#define L4_KWQ_CONNECT_REQ1_SACK (0x1<<4)
+#define L4_KWQ_CONNECT_REQ1_SACK_SHIFT 4
+#define L4_KWQ_CONNECT_REQ1_SEG_SCALING (0x1<<5)
+#define L4_KWQ_CONNECT_REQ1_SEG_SCALING_SHIFT 5
+#define L4_KWQ_CONNECT_REQ1_RESERVED2 (0x3<<6)
+#define L4_KWQ_CONNECT_REQ1_RESERVED2_SHIFT 6
+ u8 rsrv1[3];
+#endif
+ u32 rsrv2;
+};
+
+
+/*
+ * The second ( optional )request to be passed in order to establish connection in option2 - for IPv6 only
+ */
+struct l4_kwq_connect_req2 {
+#if defined(__BIG_ENDIAN)
+ u8 flags;
+#define L4_KWQ_CONNECT_REQ2_RESERVED1 (0xF<<0)
+#define L4_KWQ_CONNECT_REQ2_RESERVED1_SHIFT 0
+#define L4_KWQ_CONNECT_REQ2_LAYER_CODE (0x7<<4)
+#define L4_KWQ_CONNECT_REQ2_LAYER_CODE_SHIFT 4
+#define L4_KWQ_CONNECT_REQ2_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_CONNECT_REQ2_LINKED_WITH_NEXT_SHIFT 7
+ u8 op_code;
+ u8 reserved0;
+ u8 rsrv;
+#elif defined(__LITTLE_ENDIAN)
+ u8 rsrv;
+ u8 reserved0;
+ u8 op_code;
+ u8 flags;
+#define L4_KWQ_CONNECT_REQ2_RESERVED1 (0xF<<0)
+#define L4_KWQ_CONNECT_REQ2_RESERVED1_SHIFT 0
+#define L4_KWQ_CONNECT_REQ2_LAYER_CODE (0x7<<4)
+#define L4_KWQ_CONNECT_REQ2_LAYER_CODE_SHIFT 4
+#define L4_KWQ_CONNECT_REQ2_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_CONNECT_REQ2_LINKED_WITH_NEXT_SHIFT 7
+#endif
+ u32 reserved2;
+ u32 src_ip_v6_2;
+ u32 src_ip_v6_3;
+ u32 src_ip_v6_4;
+ u32 dst_ip_v6_2;
+ u32 dst_ip_v6_3;
+ u32 dst_ip_v6_4;
+};
+
+
+/*
+ * The third ( and last )request to be passed in order to establish connection in option2
+ */
+struct l4_kwq_connect_req3 {
+#if defined(__BIG_ENDIAN)
+ u8 flags;
+#define L4_KWQ_CONNECT_REQ3_RESERVED1 (0xF<<0)
+#define L4_KWQ_CONNECT_REQ3_RESERVED1_SHIFT 0
+#define L4_KWQ_CONNECT_REQ3_LAYER_CODE (0x7<<4)
+#define L4_KWQ_CONNECT_REQ3_LAYER_CODE_SHIFT 4
+#define L4_KWQ_CONNECT_REQ3_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_CONNECT_REQ3_LINKED_WITH_NEXT_SHIFT 7
+ u8 op_code;
+ u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+ u16 reserved0;
+ u8 op_code;
+ u8 flags;
+#define L4_KWQ_CONNECT_REQ3_RESERVED1 (0xF<<0)
+#define L4_KWQ_CONNECT_REQ3_RESERVED1_SHIFT 0
+#define L4_KWQ_CONNECT_REQ3_LAYER_CODE (0x7<<4)
+#define L4_KWQ_CONNECT_REQ3_LAYER_CODE_SHIFT 4
+#define L4_KWQ_CONNECT_REQ3_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_CONNECT_REQ3_LINKED_WITH_NEXT_SHIFT 7
+#endif
+ u32 ka_timeout;
+ u32 ka_interval ;
+#if defined(__BIG_ENDIAN)
+ u8 snd_seq_scale;
+ u8 ttl;
+ u8 tos;
+ u8 ka_max_probe_count;
+#elif defined(__LITTLE_ENDIAN)
+ u8 ka_max_probe_count;
+ u8 tos;
+ u8 ttl;
+ u8 snd_seq_scale;
+#endif
+#if defined(__BIG_ENDIAN)
+ u16 pmtu;
+ u16 mss;
+#elif defined(__LITTLE_ENDIAN)
+ u16 mss;
+ u16 pmtu;
+#endif
+ u32 rcv_buf;
+ u32 snd_buf;
+ u32 seed;
+};
+
+
+/*
+ * a KWQE request to offload a PG connection
+ */
+struct l4_kwq_offload_pg {
+#if defined(__BIG_ENDIAN)
+ u8 flags;
+#define L4_KWQ_OFFLOAD_PG_RESERVED1 (0xF<<0)
+#define L4_KWQ_OFFLOAD_PG_RESERVED1_SHIFT 0
+#define L4_KWQ_OFFLOAD_PG_LAYER_CODE (0x7<<4)
+#define L4_KWQ_OFFLOAD_PG_LAYER_CODE_SHIFT 4
+#define L4_KWQ_OFFLOAD_PG_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_OFFLOAD_PG_LINKED_WITH_NEXT_SHIFT 7
+ u8 op_code;
+ u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+ u16 reserved0;
+ u8 op_code;
+ u8 flags;
+#define L4_KWQ_OFFLOAD_PG_RESERVED1 (0xF<<0)
+#define L4_KWQ_OFFLOAD_PG_RESERVED1_SHIFT 0
+#define L4_KWQ_OFFLOAD_PG_LAYER_CODE (0x7<<4)
+#define L4_KWQ_OFFLOAD_PG_LAYER_CODE_SHIFT 4
+#define L4_KWQ_OFFLOAD_PG_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_OFFLOAD_PG_LINKED_WITH_NEXT_SHIFT 7
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 l2hdr_nbytes;
+ u8 pg_flags;
+#define L4_KWQ_OFFLOAD_PG_SNAP_ENCAP (0x1<<0)
+#define L4_KWQ_OFFLOAD_PG_SNAP_ENCAP_SHIFT 0
+#define L4_KWQ_OFFLOAD_PG_VLAN_TAGGING (0x1<<1)
+#define L4_KWQ_OFFLOAD_PG_VLAN_TAGGING_SHIFT 1
+#define L4_KWQ_OFFLOAD_PG_RESERVED2 (0x3F<<2)
+#define L4_KWQ_OFFLOAD_PG_RESERVED2_SHIFT 2
+ u8 da0;
+ u8 da1;
+#elif defined(__LITTLE_ENDIAN)
+ u8 da1;
+ u8 da0;
+ u8 pg_flags;
+#define L4_KWQ_OFFLOAD_PG_SNAP_ENCAP (0x1<<0)
+#define L4_KWQ_OFFLOAD_PG_SNAP_ENCAP_SHIFT 0
+#define L4_KWQ_OFFLOAD_PG_VLAN_TAGGING (0x1<<1)
+#define L4_KWQ_OFFLOAD_PG_VLAN_TAGGING_SHIFT 1
+#define L4_KWQ_OFFLOAD_PG_RESERVED2 (0x3F<<2)
+#define L4_KWQ_OFFLOAD_PG_RESERVED2_SHIFT 2
+ u8 l2hdr_nbytes;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 da2;
+ u8 da3;
+ u8 da4;
+ u8 da5;
+#elif defined(__LITTLE_ENDIAN)
+ u8 da5;
+ u8 da4;
+ u8 da3;
+ u8 da2;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 sa0;
+ u8 sa1;
+ u8 sa2;
+ u8 sa3;
+#elif defined(__LITTLE_ENDIAN)
+ u8 sa3;
+ u8 sa2;
+ u8 sa1;
+ u8 sa0;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 sa4;
+ u8 sa5;
+ u16 etype;
+#elif defined(__LITTLE_ENDIAN)
+ u16 etype;
+ u8 sa5;
+ u8 sa4;
+#endif
+#if defined(__BIG_ENDIAN)
+ u16 vlan_tag;
+ u16 ipid_start;
+#elif defined(__LITTLE_ENDIAN)
+ u16 ipid_start;
+ u16 vlan_tag;
+#endif
+#if defined(__BIG_ENDIAN)
+ u16 ipid_count;
+ u16 reserved3;
+#elif defined(__LITTLE_ENDIAN)
+ u16 reserved3;
+ u16 ipid_count;
+#endif
+ u32 host_opaque;
+};
+
+
+/*
+ * Abortively close the connection request
+ */
+struct l4_kwq_reset_req {
+#if defined(__BIG_ENDIAN)
+ u8 flags;
+#define L4_KWQ_RESET_REQ_RESERVED1 (0xF<<0)
+#define L4_KWQ_RESET_REQ_RESERVED1_SHIFT 0
+#define L4_KWQ_RESET_REQ_LAYER_CODE (0x7<<4)
+#define L4_KWQ_RESET_REQ_LAYER_CODE_SHIFT 4
+#define L4_KWQ_RESET_REQ_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_RESET_REQ_LINKED_WITH_NEXT_SHIFT 7
+ u8 op_code;
+ u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+ u16 reserved0;
+ u8 op_code;
+ u8 flags;
+#define L4_KWQ_RESET_REQ_RESERVED1 (0xF<<0)
+#define L4_KWQ_RESET_REQ_RESERVED1_SHIFT 0
+#define L4_KWQ_RESET_REQ_LAYER_CODE (0x7<<4)
+#define L4_KWQ_RESET_REQ_LAYER_CODE_SHIFT 4
+#define L4_KWQ_RESET_REQ_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_RESET_REQ_LINKED_WITH_NEXT_SHIFT 7
+#endif
+ u32 cid;
+ u32 reserved2[6];
+};
+
+
+/*
+ * a KWQE request to update a PG connection
+ */
+struct l4_kwq_update_pg {
+#if defined(__BIG_ENDIAN)
+ u8 flags;
+#define L4_KWQ_UPDATE_PG_RESERVED1 (0xF<<0)
+#define L4_KWQ_UPDATE_PG_RESERVED1_SHIFT 0
+#define L4_KWQ_UPDATE_PG_LAYER_CODE (0x7<<4)
+#define L4_KWQ_UPDATE_PG_LAYER_CODE_SHIFT 4
+#define L4_KWQ_UPDATE_PG_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_UPDATE_PG_LINKED_WITH_NEXT_SHIFT 7
+ u8 opcode;
+ u16 oper16;
+#elif defined(__LITTLE_ENDIAN)
+ u16 oper16;
+ u8 opcode;
+ u8 flags;
+#define L4_KWQ_UPDATE_PG_RESERVED1 (0xF<<0)
+#define L4_KWQ_UPDATE_PG_RESERVED1_SHIFT 0
+#define L4_KWQ_UPDATE_PG_LAYER_CODE (0x7<<4)
+#define L4_KWQ_UPDATE_PG_LAYER_CODE_SHIFT 4
+#define L4_KWQ_UPDATE_PG_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_UPDATE_PG_LINKED_WITH_NEXT_SHIFT 7
+#endif
+ u32 pg_cid;
+ u32 pg_host_opaque;
+#if defined(__BIG_ENDIAN)
+ u8 pg_valids;
+#define L4_KWQ_UPDATE_PG_VALIDS_IPID_COUNT (0x1<<0)
+#define L4_KWQ_UPDATE_PG_VALIDS_IPID_COUNT_SHIFT 0
+#define L4_KWQ_UPDATE_PG_VALIDS_DA (0x1<<1)
+#define L4_KWQ_UPDATE_PG_VALIDS_DA_SHIFT 1
+#define L4_KWQ_UPDATE_PG_RESERVERD2 (0x3F<<2)
+#define L4_KWQ_UPDATE_PG_RESERVERD2_SHIFT 2
+ u8 pg_unused_a;
+ u16 pg_ipid_count;
+#elif defined(__LITTLE_ENDIAN)
+ u16 pg_ipid_count;
+ u8 pg_unused_a;
+ u8 pg_valids;
+#define L4_KWQ_UPDATE_PG_VALIDS_IPID_COUNT (0x1<<0)
+#define L4_KWQ_UPDATE_PG_VALIDS_IPID_COUNT_SHIFT 0
+#define L4_KWQ_UPDATE_PG_VALIDS_DA (0x1<<1)
+#define L4_KWQ_UPDATE_PG_VALIDS_DA_SHIFT 1
+#define L4_KWQ_UPDATE_PG_RESERVERD2 (0x3F<<2)
+#define L4_KWQ_UPDATE_PG_RESERVERD2_SHIFT 2
+#endif
+#if defined(__BIG_ENDIAN)
+ u16 reserverd3;
+ u8 da0;
+ u8 da1;
+#elif defined(__LITTLE_ENDIAN)
+ u8 da1;
+ u8 da0;
+ u16 reserverd3;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 da2;
+ u8 da3;
+ u8 da4;
+ u8 da5;
+#elif defined(__LITTLE_ENDIAN)
+ u8 da5;
+ u8 da4;
+ u8 da3;
+ u8 da2;
+#endif
+ u32 reserved4;
+ u32 reserved5;
+};
+
+
+/*
+ * a KWQE request to upload a PG or L4 context
+ */
+struct l4_kwq_upload {
+#if defined(__BIG_ENDIAN)
+ u8 flags;
+#define L4_KWQ_UPLOAD_RESERVED1 (0xF<<0)
+#define L4_KWQ_UPLOAD_RESERVED1_SHIFT 0
+#define L4_KWQ_UPLOAD_LAYER_CODE (0x7<<4)
+#define L4_KWQ_UPLOAD_LAYER_CODE_SHIFT 4
+#define L4_KWQ_UPLOAD_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_UPLOAD_LINKED_WITH_NEXT_SHIFT 7
+ u8 opcode;
+ u16 oper16;
+#elif defined(__LITTLE_ENDIAN)
+ u16 oper16;
+ u8 opcode;
+ u8 flags;
+#define L4_KWQ_UPLOAD_RESERVED1 (0xF<<0)
+#define L4_KWQ_UPLOAD_RESERVED1_SHIFT 0
+#define L4_KWQ_UPLOAD_LAYER_CODE (0x7<<4)
+#define L4_KWQ_UPLOAD_LAYER_CODE_SHIFT 4
+#define L4_KWQ_UPLOAD_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_UPLOAD_LINKED_WITH_NEXT_SHIFT 7
+#endif
+ u32 cid;
+ u32 reserved2[6];
+};
+
+#endif /* __57XX_L5CM_HSI_LINUX_LE__ */
diff --git a/drivers/net/cnic_if.h b/drivers/net/cnic_if.h
new file mode 100644
index 0000000..6ec8f1a
--- /dev/null
+++ b/drivers/net/cnic_if.h
@@ -0,0 +1,152 @@
+/* cnic_if.h: Broadcom CNIC core network driver.
+ *
+ * Copyright (c) 2006 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * Written by: John(Zongxi) Chen (zongxic@broadcom.com)
+ */
+
+
+#ifndef CNIC_IF_H
+#define CNIC_IF_H
+
+#define CNIC_MODULE_VERSION "1.1.12"
+#define CNIC_MODULE_RELDATE "Aug 24, 2007"
+
+#define CNIC_ULP_RDMA 0
+#define CNIC_ULP_ISCSI 1
+#define CNIC_ULP_L4 2
+#define MAX_CNIC_ULP_TYPE_EXT 2
+#define MAX_CNIC_ULP_TYPE 3
+
+struct kwqe {
+ u32 kwqe_op_flag;
+
+ u32 kwqe_info0;
+ u32 kwqe_info1;
+ u32 kwqe_info2;
+ u32 kwqe_info3;
+ u32 kwqe_info4;
+ u32 kwqe_info5;
+ u32 kwqe_info6;
+};
+
+struct kcqe {
+ u32 kcqe_info0;
+ u32 kcqe_info1;
+ u32 kcqe_info2;
+ u32 kcqe_info3;
+ u32 kcqe_info4;
+ u32 kcqe_info5;
+ u32 kcqe_info6;
+ u32 kcqe_op_flag;
+ #define KCQE_FLAGS_LAYER_MASK (0x7<<28)
+ #define KCQE_FLAGS_LAYER_MASK_MISC (0<<28)
+ #define KCQE_FLAGS_LAYER_MASK_L2 (2<<28)
+ #define KCQE_FLAGS_LAYER_MASK_L3 (3<<28)
+ #define KCQE_FLAGS_LAYER_MASK_L4 (4<<28)
+ #define KCQE_FLAGS_LAYER_MASK_L5_RDMA (5<<28)
+ #define KCQE_FLAGS_LAYER_MASK_L5_ISCSI (6<<28)
+ #define KCQE_FLAGS_NEXT (1<<31)
+};
+
+struct cnic_sockaddr {
+ struct sockaddr_in local_addr;
+ struct sockaddr_in remote_addr;
+};
+
+struct cnic_sock {
+ struct cnic_dev *dev;
+ void *context;
+ u32 src_ip;
+ u32 dst_ip;
+ u16 src_port;
+ u16 dst_port;
+ u16 vlan_id;
+ struct dst_entry *dst;
+ u32 cid;
+ u32 l5_cid;
+ u32 pg_cid;
+ int ulp_type;
+
+ u32 ka_timeout;
+ u32 ka_interval;
+ u8 ka_max_probe_count;
+ u8 tos;
+ u8 ttl;
+ u8 snd_seq_scale;
+ u32 rcv_buf;
+ u32 snd_buf;
+ u32 seed;
+
+ unsigned long tcp_flags;
+#define SK_TCP_NO_DELAY_ACK 0
+#define SK_TCP_KEEP_ALIVE 1
+#define SK_TCP_NAGLE 2
+#define SK_TCP_TIMESTAMP 3
+#define SK_TCP_SACK 4
+#define SK_TCP_SEG_SCALING 5
+ unsigned long flags;
+#define SK_F_INUSE 0
+#define SK_F_OFFLD_COMPLETE 1
+#define SK_F_OFFLD_PENDING 2
+#define SK_F_PG_OFFLD_COMPLETE 3
+ struct kwqe kwqe1;
+ struct kwqe kwqe2;
+ struct kwqe kwqe3;
+};
+
+struct cnic_dev {
+ struct net_device *netdev;
+ struct bnx2 *bp;
+ struct pci_dev *pcidev;
+ void __iomem *regview;
+ struct list_head list;
+ struct class_device class_dev;
+
+ int (*register_device)(struct cnic_dev *dev, int ulp_type,
+ void *ulp_ctx);
+ int (*unregister_device)(struct cnic_dev *dev, int ulp_type);
+ int (*submit_kwqes)(struct cnic_dev *dev, struct kwqe *wqes[],
+ u32 num_wqes);
+
+ int (*cm_create)(struct cnic_dev *, int, u32, u32, struct cnic_sock **,
+ void *);
+ int (*cm_destroy)(struct cnic_sock *);
+ int (*cm_connect)(struct cnic_sock *, struct cnic_sockaddr *);
+ int (*cm_abort)(struct cnic_sock *);
+ int (*cm_close)(struct cnic_sock *);
+ struct cnic_dev *(*cm_select_dev)(struct sockaddr_in *, int ulp_type);
+ unsigned long flags;
+#define CNIC_F_IF_UP 0
+#define CNIC_F_CNIC_UP 1
+ atomic_t ref_count;
+ int use_count;
+ void *cnic_priv;
+};
+
+struct cnic_ulp_ops {
+ void (*cnic_init)(struct cnic_dev *dev);
+ void (*cnic_exit)(struct cnic_dev *dev);
+ void (*cnic_start)(void *ulp_ctx);
+ void (*cnic_stop)(void *ulp_ctx);
+ void (*indicate_kcqes)(void *ulp_ctx, struct kcqe *cqes[],
+ u32 num_cqes);
+ void (*indicate_netevent)(void *ulp_ctx, unsigned long event);
+ void (*indicate_inetevent)(void *ulp_ctx, unsigned long event);
+ void (*cm_connect_complete)(struct cnic_sock *);
+ void (*cm_close_complete)(struct cnic_sock *);
+ void (*cm_abort_complete)(struct cnic_sock *);
+ void (*cm_remote_close)(struct cnic_sock *);
+ void (*cm_remote_abort)(struct cnic_sock *);
+ struct module *owner;
+};
+
+extern int cnic_register_driver(int ulp_type, struct cnic_ulp_ops *ulp_ops);
+
+extern int cnic_unregister_driver(int ulp_type);
+
+#endif
^ permalink raw reply related
* Ethernet weirdness on 82xx
From: Rune Torgersen @ 2007-08-31 21:35 UTC (permalink / raw)
To: linuxppc-embedded, netdev
I'm not sure if this is by design or an actual bug.
We have a system witb an 8280 with two active ethernets (fcc2 and fcc3)
We are running kernel 2.6.18.1 (and won't be upgrading in a while) out
of arch/ppc
Eth0 and eth1 are in totally different subnets.
We happened to have both ehternets connected to the same network, and I
ran a arping agains the IP on eth0.
Both ports (eth0 and eth1) responded with the same address, but
different macs....
sudo /sbin/arping -c1 172.23.12.114
ARPING 172.23.12.114 from 172.23.15.21 eth0
Unicast reply from 172.23.12.114 [00:30:D7:00:14:55] 0.838ms
Unicast reply from 172.23.12.114 [00:30:D7:00:14:54] 0.890ms
Sent 1 probes (1 broadcast(s))
Received 2 response(s)
It only gets both responses on the first (broadcast) query from arping
All responses afterward is then from the wrong port....
The ethernet setup on the target box:
eth0 Link encap:Ethernet HWaddr 00:30:D7:00:14:54
inet addr:172.23.12.114 Bcast:172.23.15.255
Mask:255.255.248.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:473244 errors:0 dropped:2 overruns:0 frame:0
TX packets:186655 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:162928671 (155.3 Mb) TX bytes:42222862 (40.2 Mb)
Base address:0x8500
eth1 Link encap:Ethernet HWaddr 00:30:D7:00:14:55
inet addr:192.168.0.100 Bcast:192.168.0.255
Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:1553 errors:0 dropped:0 overruns:0 frame:0
TX packets:4 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:203182 (198.4 Kb) TX bytes:168 (168.0 b)
Base address:0x8600
^ permalink raw reply
* Re: [1/1] Block device throttling [Re: Distributed storage.]
From: Alasdair G Kergon @ 2007-08-31 21:41 UTC (permalink / raw)
To: Daniel Phillips
Cc: Evgeniy Polyakov, Jens Axboe, netdev, linux-kernel, linux-fsdevel,
Peter Zijlstra, Neil Brown
In-Reply-To: <200708301620.37965.phillips@phunq.net>
On Thu, Aug 30, 2007 at 04:20:35PM -0700, Daniel Phillips wrote:
> Resubmitting a bio or submitting a dependent bio from
> inside a block driver does not need to be throttled because all
> resources required to guarantee completion must have been obtained
> _before_ the bio was allowed to proceed into the block layer.
I'm toying with the idea of keeping track of the maximum device stack
depth for each stacked device, and only permitting it to increase in
controlled circumstances.
Alasdair
--
agk@redhat.com
^ permalink raw reply
* Re: [PATCH] net/, drivers/net/ , missing EXPERIMENTAL in menus
From: Jeff Garzik @ 2007-08-31 22:01 UTC (permalink / raw)
To: Robert P. J. Day
Cc: Randy Dunlap, Simon Arlott, sam, Linux Kernel Mailing List,
Stefan Richter, Adrian Bunk, Gabriel C, netdev
In-Reply-To: <Pine.LNX.4.64.0708311643080.27345@localhost.localdomain>
Robert P. J. Day wrote:
> On Fri, 31 Aug 2007, Jeff Garzik wrote:
>
>> Robert P. J. Day wrote:
>
>>> i'm sure i'm going to get shouted down here, but i really disagree
>>> with "BROKEN" being considered a "maturity level". IMHO, things
>>> like EXPERIMENTAL, DEPRECATED and OBSOLETE represent maturity
>>> levels, for what i think are obvious reasons.
>>>
>>> something like BROKEN, though, has *nothing* to do with maturity.
>>> a feature can be any of those maturity levels, and simultaneously
>>> be BROKEN. i consider BROKEN to be what i call a "status", and
>>> different status levels might be the default of normal, or
>>> KIND_OF_FLAKY or TOTALLY_BORKED -- that's where BROKEN would fit
>>> in.
>> BROKEN is definitely a maturity level.
>
> no. it's not. end of discussion. you're wrong.
>
> the concept of "maturity level" reflects where in the life cycle some
> feature is. it will typically start as "bleeding edge" or
> "experimental" or something like that, eventually stabilize to be
> normal (which would be the obvious default), after which, when its
> value starts to run out and it begins showing its age, it becomes
> "deprecated" and eventually "obsolete" it's a natural and obvious
> progression.
>
> on the other hand, a feature can be "broken" at *any* point in that
> life cycle -- that's why it is absolutely *not* a maturity level.
> please don't fight with me on this, jeff. you're simply wrong.
Get off your high horse and actually look at the patches that mark
things BROKEN.
'deprecrated' and 'obsolete' are matters of discussed opinion,
describing the utility of the code in question. 'broken' describes the
state of the code itself.
Clear difference.
Jeff, one who actually marks this stuff as such
^ permalink raw reply
* Re: [PATCH net-2.6.24] introduce MAC_FMT/MAC_ARG
From: Joe Perches @ 2007-08-31 22:16 UTC (permalink / raw)
To: David Miller; +Cc: johannes, netdev
In-Reply-To: <20070828.142216.99461544.davem@davemloft.net>
On Tue, 2007-08-28 at 14:22 -0700, David Miller wrote:
> From: Joe Perches <joe@perches.com>
> > Option 2:
> > DECLARE_MAC_BUF(mac);
> > printk("%s", print_mac(mac, dev->dev_addr));
> I'm slightly leaning towards 2.
Here are the patches for this conversion.
Compiled successfully x86, defconfig and allyesconfig
against net-2.6.24 but the patch is largely untested.
I've inlined the include changes, but the entire patch
is quite large. (300KB)
MAC address format changes:
UPPER->lower case changes in MAC addresses in printks.
presentation from "%x %x..." to "%02x:%02x...".
seq_printf uses of mac addresses
Perhaps the seq_printf changes might cause problems
with usermode programs.
please pull from:
git pull git://repo.or.cz/linux-2.6/trivial-mods.git net-2.6.24-print_mac
Signed-off-by: Joe Perches <joe@perches.com>
--
include/linux/if_ether.h | 7 +++++++
include/net/ieee80211.h | 5 -----
include/net/mac80211.h | 4 ----
3 files changed, 7 insertions(+), 9 deletions(-)
diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h
index 3213f6f..bb3eb51 100644
--- a/include/linux/if_ether.h
+++ b/include/linux/if_ether.h
@@ -122,4 +122,11 @@ extern struct ctl_table ether_table[];
#endif
#endif
+/*
+ * Display a 6 byte device address (MAC) in a readable format.
+ */
+#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
+extern char *print_mac(char* buf, const u8 *addr);
+#define DECLARE_MAC_BUF(var) char var[18] __maybe_unused
+
#endif /* _LINUX_IF_ETHER_H */
diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h
index bbd85cd..164d132 100644
--- a/include/net/ieee80211.h
+++ b/include/net/ieee80211.h
@@ -119,11 +119,6 @@ do { if (ieee80211_debug_level & (level)) \
#define IEEE80211_DEBUG(level, fmt, args...) do {} while (0)
#endif /* CONFIG_IEEE80211_DEBUG */
-/* debug macros not dependent on CONFIG_IEEE80211_DEBUG */
-
-#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
-#define MAC_ARG(x) ((u8*)(x))[0],((u8*)(x))[1],((u8*)(x))[2],((u8*)(x))[3],((u8*)(x))[4],((u8*)(x))[5]
-
/* escape_essid() is intended to be used in debug (and possibly error)
* messages. It should never be used for passing essid to user space. */
const char *escape_essid(const char *essid, u8 essid_len);
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index ec8c739..6de3ceb 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1089,8 +1089,4 @@ static inline int ieee80211_get_morefrag(struct ieee80211_hdr *hdr)
IEEE80211_FCTL_MOREFRAGS) != 0;
}
-#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
-#define MAC_ARG(x) ((u8*)(x))[0], ((u8*)(x))[1], ((u8*)(x))[2], \
- ((u8*)(x))[3], ((u8*)(x))[4], ((u8*)(x))[5]
-
#endif /* MAC80211_H */
--
drivers/net/3c503.c | 4 +-
drivers/net/3c505.c | 10 +-
drivers/net/3c507.c | 6 +-
drivers/net/3c509.c | 6 +-
drivers/net/3c515.c | 4 +-
drivers/net/3c523.c | 20 +--
drivers/net/3c527.c | 7 +-
drivers/net/3c59x.c | 7 +-
drivers/net/8139cp.c | 8 +-
drivers/net/8139too.c | 8 +-
drivers/net/82596.c | 18 +--
drivers/net/a2065.c | 6 +-
drivers/net/ac3200.c | 8 +-
drivers/net/acenic.c | 7 +-
drivers/net/amd8111e.c | 12 +-
drivers/net/apne.c | 9 +-
drivers/net/ariadne.c | 44 +++---
drivers/net/arm/am79c961a.c | 8 +-
drivers/net/arm/at91_ether.c | 18 +-
drivers/net/arm/ether1.c | 8 +-
drivers/net/arm/ether3.c | 8 +-
drivers/net/arm/etherh.c | 8 +-
drivers/net/at1700.c | 4 +-
drivers/net/atarilance.c | 40 +++---
drivers/net/atp.c | 8 +-
drivers/net/b44.c | 9 +-
drivers/net/bmac.c | 6 +-
drivers/net/bnx2.c | 12 +-
drivers/net/bonding/bond_main.c | 34 ++---
drivers/net/bonding/bond_sysfs.c | 11 +-
drivers/net/cassini.c | 11 +-
drivers/net/cris/eth_v10.c | 8 +-
drivers/net/cs89x0.c | 15 +--
drivers/net/de600.c | 6 +-
drivers/net/de620.c | 8 +-
drivers/net/declance.c | 14 +-
drivers/net/depca.c | 13 +-
drivers/net/dgrs.c | 18 +--
drivers/net/dl2k.c | 7 +-
drivers/net/dm9000.c | 9 +-
drivers/net/e100.c | 9 +-
drivers/net/e1000/e1000_main.c | 5 +-
drivers/net/eepro.c | 5 +-
drivers/net/eepro100.c | 9 +-
drivers/net/epic100.c | 9 +-
drivers/net/es3210.c | 22 ++--
drivers/net/ewrk3.c | 16 +--
drivers/net/fealnx.c | 9 +-
drivers/net/fec.c | 7 +-
drivers/net/forcedeth.c | 12 +-
drivers/net/gianfar.c | 7 +-
drivers/net/hamachi.c | 8 +-
drivers/net/hamradio/bpqether.c | 23 +--
drivers/net/hp-plus.c | 6 +-
drivers/net/hp.c | 5 +-
drivers/net/hp100.c | 6 +-
drivers/net/hydra.c | 7 +-
drivers/net/ibm_emac/ibm_emac_core.c | 14 +-
drivers/net/ibmlana.c | 6 +-
drivers/net/ibmveth.c | 9 +-
drivers/net/ioc3-eth.c | 12 +-
drivers/net/isa-skeleton.c | 5 +-
drivers/net/jazzsonic.c | 10 +-
drivers/net/lance.c | 6 +-
drivers/net/lguest_net.c | 4 +-
drivers/net/lib82596.c | 18 +--
drivers/net/lne390.c | 9 +-
drivers/net/mac89x0.c | 11 +-
drivers/net/macb.c | 6 +-
drivers/net/mace.c | 9 +-
drivers/net/macmace.c | 6 +-
drivers/net/macsonic.c | 21 +--
drivers/net/meth.c | 6 +-
drivers/net/mv643xx_eth.c | 5 +-
drivers/net/mvme147.c | 11 +-
drivers/net/myri10ge/myri10ge.c | 11 +-
drivers/net/myri_sbus.c | 29 ++---
drivers/net/natsemi.c | 11 +-
drivers/net/ne-h8300.c | 8 +-
drivers/net/ne.c | 5 +-
drivers/net/ne2.c | 17 +--
drivers/net/ne2k-pci.c | 11 +-
drivers/net/ne3210.c | 11 +-
drivers/net/netconsole.c | 14 +-
drivers/net/netxen/netxen_nic_main.c | 13 +-
drivers/net/netxen/netxen_nic_niu.c | 14 +-
drivers/net/ni5010.c | 4 +-
drivers/net/ns83820.c | 7 +-
drivers/net/pasemi_mac.c | 6 +-
drivers/net/pci-skeleton.c | 9 +-
drivers/net/pcmcia/3c574_cs.c | 9 +-
drivers/net/pcmcia/3c589_cs.c | 10 +-
drivers/net/pcmcia/axnet_cs.c | 9 +-
drivers/net/pcmcia/fmvj18x_cs.c | 8 +-
drivers/net/pcmcia/nmclan_cs.c | 9 +-
drivers/net/pcmcia/pcnet_cs.c | 7 +-
drivers/net/pcmcia/smc91c92_cs.c | 8 +-
drivers/net/pcmcia/xirc2ps_cs.c | 9 +-
drivers/net/pppoe.c | 8 +-
drivers/net/ps3_gelic_net.c | 7 +-
drivers/net/qla3xxx.c | 7 +-
drivers/net/rionet.c | 6 +-
drivers/net/rrunner.c | 8 +-
drivers/net/s2io.c | 11 +-
drivers/net/sb1250-mac.c | 7 +-
drivers/net/seeq8005.c | 4 +-
drivers/net/sgiseeq.c | 6 +-
drivers/net/sis190.c | 10 +-
drivers/net/sis900.c | 9 +-
drivers/net/skge.c | 7 +-
drivers/net/sky2.c | 7 +-
drivers/net/smc-mca.c | 8 +-
drivers/net/smc-ultra.c | 8 +-
drivers/net/smc-ultra32.c | 8 +-
drivers/net/smc9194.c | 7 +-
drivers/net/smc91x.c | 9 +-
drivers/net/starfire.c | 26 ++--
drivers/net/sun3lance.c | 36 ++---
drivers/net/sunbmac.c | 8 +-
drivers/net/sundance.c | 10 +-
drivers/net/sungem.c | 12 +-
drivers/net/sunhme.c | 12 +-
drivers/net/sunlance.c | 9 +-
drivers/net/tokenring/abyss.c | 12 +-
drivers/net/tokenring/ibmtr.c | 26 ++--
drivers/net/tokenring/lanstreamer.c | 64 ++++-----
drivers/net/tokenring/madgemc.c | 19 +--
drivers/net/tokenring/olympic.c | 138 +++++++---------
drivers/net/tokenring/proteon.c | 8 +-
drivers/net/tokenring/skisa.c | 8 +-
drivers/net/tokenring/tmspci.c | 10 +-
drivers/net/tsi108_eth.c | 7 +-
drivers/net/tulip/de2104x.c | 9 +-
drivers/net/tulip/de4x5.c | 33 +---
drivers/net/tulip/dmfe.c | 15 +-
drivers/net/tulip/tulip_core.c | 15 +-
drivers/net/tulip/uli526x.c | 9 +-
drivers/net/tulip/winbond-840.c | 29 ++--
drivers/net/tulip/xircom_cb.c | 7 +-
drivers/net/tun.c | 33 ++---
drivers/net/typhoon.c | 10 +-
drivers/net/usb/pegasus.c | 11 +-
drivers/net/usb/usbnet.c | 8 +-
drivers/net/via-rhine.c | 13 +-
drivers/net/wd.c | 7 +-
drivers/net/wireless/airo.c | 32 ++---
drivers/net/wireless/arlan-main.c | 23 ++--
drivers/net/wireless/atmel.c | 7 +-
drivers/net/wireless/bcm43xx/bcm43xx.h | 6 -
drivers/net/wireless/hostap/hostap_80211_rx.c | 49 ++++---
drivers/net/wireless/hostap/hostap_80211_tx.c | 13 +-
drivers/net/wireless/hostap/hostap_ap.c | 198 ++++++++++++++----------
drivers/net/wireless/hostap/hostap_common.h | 3 -
drivers/net/wireless/hostap/hostap_hw.c | 11 +-
drivers/net/wireless/hostap/hostap_info.c | 17 ++-
drivers/net/wireless/hostap/hostap_ioctl.c | 15 +-
drivers/net/wireless/hostap/hostap_main.c | 30 ++--
drivers/net/wireless/hostap/hostap_proc.c | 15 +-
drivers/net/wireless/ipw2100.c | 48 +++---
drivers/net/wireless/ipw2200.c | 207 ++++++++++++++-----------
drivers/net/wireless/libertas/assoc.c | 19 ++-
drivers/net/wireless/libertas/cmdresp.c | 7 +-
drivers/net/wireless/libertas/debugfs.c | 5 +-
drivers/net/wireless/libertas/join.c | 15 +-
drivers/net/wireless/libertas/main.c | 12 +-
drivers/net/wireless/libertas/scan.c | 14 +-
drivers/net/wireless/libertas/wext.c | 5 +-
drivers/net/wireless/netwave_cs.c | 14 +-
drivers/net/wireless/orinoco.c | 7 +-
drivers/net/wireless/prism54/isl_ioctl.c | 50 ++----
drivers/net/wireless/ray_cs.c | 15 +-
drivers/net/wireless/rtl8187_dev.c | 7 +-
drivers/net/wireless/wavelan.c | 53 +++----
drivers/net/wireless/wavelan_cs.c | 54 +++----
drivers/net/wireless/wl3501_cs.c | 22 ++--
drivers/net/wireless/zd1211rw/zd_chip.c | 3 +-
drivers/net/wireless/zd1211rw/zd_mac.c | 8 +-
drivers/net/yellowfin.c | 19 +--
drivers/net/znet.c | 11 +-
drivers/net/zorro8390.c | 15 +-
180 files changed, 1305 insertions(+), 1504 deletions(-)
--
net/802/tr.c | 28 ++--
net/appletalk/aarp.c | 9 +-
net/atm/br2684.c | 16 +--
net/atm/lec.c | 33 ++---
net/core/dev.c | 13 ++
net/core/netpoll.c | 12 +--
net/core/pktgen.c | 17 +--
net/ethernet/eth.c | 8 +
net/ieee80211/ieee80211_crypt_ccmp.c | 30 +++--
net/ieee80211/ieee80211_crypt_tkip.c | 31 +++--
net/ieee80211/ieee80211_rx.c | 59 +++++----
net/ieee80211/ieee80211_wx.c | 5 +-
net/ieee80211/softmac/ieee80211softmac_assoc.c | 4 +-
net/ieee80211/softmac/ieee80211softmac_auth.c | 35 +++--
net/ieee80211/softmac/ieee80211softmac_wx.c | 5 +-
net/irda/irlan/irlan_client.c | 6 +-
net/llc/llc_proc.c | 12 +-
net/mac80211/debugfs_key.c | 3 +-
net/mac80211/debugfs_netdev.c | 3 +-
net/mac80211/debugfs_sta.c | 6 +-
net/mac80211/event.c | 5 +-
net/mac80211/ieee80211.c | 5 +-
net/mac80211/ieee80211_ioctl.c | 5 +-
net/mac80211/ieee80211_sta.c | 180 +++++++++++++-----------
net/mac80211/key.c | 10 +-
net/mac80211/rc80211_simple.c | 5 +-
net/mac80211/rx.c | 118 +++++++++------
net/mac80211/sta_info.c | 13 +-
net/mac80211/tkip.c | 10 +-
net/mac80211/tx.c | 32 +++--
net/mac80211/wpa.c | 19 ++-
net/tipc/eth_media.c | 4 +-
32 files changed, 414 insertions(+), 327 deletions(-)
^ permalink raw reply related
* Re: [PATCH net-2.6.24] introduce MAC_FMT/MAC_ARG
From: Johannes Berg @ 2007-08-31 22:21 UTC (permalink / raw)
To: Joe Perches; +Cc: David Miller, netdev
In-Reply-To: <1188598563.6062.191.camel@localhost>
[-- Attachment #1: Type: text/plain, Size: 203 bytes --]
On Fri, 2007-08-31 at 15:16 -0700, Joe Perches wrote:
> please pull from:
> git pull git://repo.or.cz/linux-2.6/trivial-mods.git net-2.6.24-print_mac
got a gitweb for that somewhere?
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 190 bytes --]
^ permalink raw reply
* Re: [PATCH] make _minimum_ TCP retransmission timeout configurable take 2
From: Rick Jones @ 2007-08-31 22:20 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <20070831.143855.88699905.davem@davemloft.net>
David Miller wrote:
> From: Rick Jones <rick.jones2@hp.com>
> Date: Fri, 31 Aug 2007 13:59:50 -0700
>
>
>>ip is at tcp_rto_min+0x20/0x40
>
>
> diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
> index 1ee7212..bbad2cd 100644
> --- a/net/ipv4/tcp_input.c
> +++ b/net/ipv4/tcp_input.c
> @@ -560,7 +560,7 @@ static u32 tcp_rto_min(struct sock *sk)
> struct dst_entry *dst = __sk_dst_get(sk);
> u32 rto_min = TCP_RTO_MIN;
>
> - if (dst_metric_locked(dst, RTAX_RTO_MIN))
> + if (dst && dst_metric_locked(dst, RTAX_RTO_MIN))
> rto_min = dst->metrics[RTAX_RTO_MIN-1];
> return rto_min;
> }
Applied and beating on it with a while loop doing a bunch of ip route
del add change stuff while netperf TCP_CRR tests are running. Thusfar
things seem OK wrt the system staying alive, but since I only saw the
failure once I'm not sure how much that is really saying.
I'm going to go ahead and take a look at input vs output units and
differences between those with rto_min vs rtt.
rick jones
^ permalink raw reply
* Re: [PATCH] net/, drivers/net/ , missing EXPERIMENTAL in menus
From: Robert P. J. Day @ 2007-08-31 22:10 UTC (permalink / raw)
To: Jeff Garzik
Cc: Randy Dunlap, Simon Arlott, sam, Linux Kernel Mailing List,
Stefan Richter, Adrian Bunk, Gabriel C, netdev
In-Reply-To: <46D88FB8.5000503@garzik.org>
On Fri, 31 Aug 2007, Jeff Garzik wrote:
> 'deprecrated' and 'obsolete' are matters of discussed opinion,
> describing the utility of the code in question. 'broken' describes
> the state of the code itself.
>
> Clear difference.
precisely. thank you for making my point for me.
rday
--
========================================================================
Robert P. J. Day
Linux Consulting, Training and Annoying Kernel Pedantry
Waterloo, Ontario, CANADA
http://crashcourse.ca
========================================================================
^ permalink raw reply
* Re: [PATCH net-2.6.24] introduce MAC_FMT/MAC_ARG
From: Joe Perches @ 2007-08-31 22:24 UTC (permalink / raw)
To: Johannes Berg; +Cc: David Miller, netdev
In-Reply-To: <1188598880.7585.52.camel@johannes.berg>
On Sat, 2007-09-01 at 00:21 +0200, Johannes Berg wrote:
> On Fri, 2007-08-31 at 15:16 -0700, Joe Perches wrote:
> > please pull from:
> > git pull git://repo.or.cz/linux-2.6/trivial-mods.git net-2.6.24-print_mac
> got a gitweb for that somewhere?
Does this work for you?
http://repo.or.cz/w/linux-2.6/trivial-mods.git
^ permalink raw reply
* Re: [PATCH] make _minimum_ TCP retransmission timeout configurable take 2
From: David Miller @ 2007-08-31 22:24 UTC (permalink / raw)
To: rick.jones2; +Cc: netdev
In-Reply-To: <46D89444.3080508@hp.com>
From: Rick Jones <rick.jones2@hp.com>
Date: Fri, 31 Aug 2007 15:20:52 -0700
> I'm going to go ahead and take a look at input vs output units and
> differences between those with rto_min vs rtt.
You better because that's one of the last non-trivial emails you'll
get for me over the next few days while I'm travelling to kernel
summit :-)
^ permalink raw reply
* Re: [PATCH net-2.6.24] introduce MAC_FMT/MAC_ARG
From: Johannes Berg @ 2007-08-31 22:27 UTC (permalink / raw)
To: Joe Perches; +Cc: David Miller, netdev
In-Reply-To: <1188599040.6062.192.camel@localhost>
[-- Attachment #1: Type: text/plain, Size: 434 bytes --]
On Fri, 2007-08-31 at 15:24 -0700, Joe Perches wrote:
> On Sat, 2007-09-01 at 00:21 +0200, Johannes Berg wrote:
> > On Fri, 2007-08-31 at 15:16 -0700, Joe Perches wrote:
> > > please pull from:
> > > git pull git://repo.or.cz/linux-2.6/trivial-mods.git net-2.6.24-print_mac
> > got a gitweb for that somewhere?
>
> Does this work for you?
>
> http://repo.or.cz/w/linux-2.6/trivial-mods.git
Perfect, thanks.
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 190 bytes --]
^ permalink raw reply
* Re: [PATCH net-2.6.24] introduce MAC_FMT/MAC_ARG
From: Johannes Berg @ 2007-08-31 22:32 UTC (permalink / raw)
To: Joe Perches; +Cc: David Miller, netdev
In-Reply-To: <1188599040.6062.192.camel@localhost>
[-- Attachment #1: Type: text/plain, Size: 1284 bytes --]
On Fri, 2007-08-31 at 15:24 -0700, Joe Perches wrote:
> On Sat, 2007-09-01 at 00:21 +0200, Johannes Berg wrote:
> > On Fri, 2007-08-31 at 15:16 -0700, Joe Perches wrote:
> > > please pull from:
> > > git pull git://repo.or.cz/linux-2.6/trivial-mods.git net-2.6.24-print_mac
> > got a gitweb for that somewhere?
>
> Does this work for you?
>
> http://repo.or.cz/w/linux-2.6/trivial-mods.git
I think you got a bit too trigger-happy:
p += sprintf(p, "key[%d] alg=CCMP key_set=%d "
- "tx_pn=%02x%02x%02x%02x%02x%02x "
- "rx_pn=%02x%02x%02x%02x%02x%02x "
+ "tx_pn=%s "
+ "rx_pn=%s "
"format_errors=%d replays=%d decrypt_errors=%d\n",
ccmp->key_idx, ccmp->key_set,
- MAC_ARG(ccmp->tx_pn), MAC_ARG(ccmp->rx_pn),
+ print_mac(mac, ccmp->tx_pn), print_mac(mac2, ccmp->rx_pn),
the PN is a number, not a MAC address :) The fact that it used MAC_ARG,
was, I guess, just laziness of the original author since the PN is also
6 bytes long. That said, I can live with it being printed this way too,
it's just a bit weird.
Going to be fun to merge with my 70 outstanding patches though :)
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 190 bytes --]
^ permalink raw reply
* Re: [PATCH net-2.6.24] introduce MAC_FMT/MAC_ARG
From: Joe Perches @ 2007-08-31 22:39 UTC (permalink / raw)
To: Johannes Berg; +Cc: David Miller, netdev
In-Reply-To: <1188599575.7585.62.camel@johannes.berg>
On Sat, 2007-09-01 at 00:32 +0200, Johannes Berg wrote:
> I think you got a bit too trigger-happy:
> p += sprintf(p, "key[%d] alg=CCMP key_set=%d "
> - "tx_pn=%02x%02x%02x%02x%02x%02x "
> - "rx_pn=%02x%02x%02x%02x%02x%02x "
> + "tx_pn=%s "
> + "rx_pn=%s "
> "format_errors=%d replays=%d decrypt_errors=%d\n",
> ccmp->key_idx, ccmp->key_set,
> - MAC_ARG(ccmp->tx_pn), MAC_ARG(ccmp->rx_pn),
> + print_mac(mac, ccmp->tx_pn), print_mac(mac2, ccmp->rx_pn),
>
> the PN is a number, not a MAC address :) The fact that it used MAC_ARG,
> was, I guess, just laziness of the original author since the PN is also
> 6 bytes long. That said, I can live with it being printed this way too,
> it's just a bit weird.
Yes, that was one of the dodgy ones.
I didn't actually realize it wasn't a MAC address though.
I think all of the sprintf/seq_foo changes should be inspected.
I broke ipv6 once doing something similar to v6 addresses.
> Going to be fun to merge with my 70 outstanding patches though :)
That's a cheery definition of fun.
^ permalink raw reply
* [SKBUFF]: Fix up csum_start when head room changes
From: Herbert Xu @ 2007-09-01 1:13 UTC (permalink / raw)
To: David S. Miller, netdev
Hi Dave:
[SKBUFF]: Fix up csum_start when head room changes
Thanks for noticing the bug where csum_start is not updated
when the head room changes.
This patch fixes that. It also moves the csum/ip_summed
copying into copy_skb_header so that skb_copy_expand gets
it too. I've checked its callers and no one should be upset
by this.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Cheers,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
--
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 35021eb..944189d 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -472,6 +472,9 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
#ifdef CONFIG_INET
new->sp = secpath_get(old->sp);
#endif
+ new->csum_start = old->csum_start;
+ new->csum_offset = old->csum_offset;
+ new->ip_summed = old->ip_summed;
new->transport_header = old->transport_header;
new->network_header = old->network_header;
new->mac_header = old->mac_header;
@@ -545,8 +548,6 @@ struct sk_buff *skb_copy(const struct sk_buff *skb, gfp_t gfp_mask)
skb_reserve(n, headerlen);
/* Set the tail pointer and length */
skb_put(n, skb->len);
- n->csum = skb->csum;
- n->ip_summed = skb->ip_summed;
if (skb_copy_bits(skb, -headerlen, n->head, headerlen + skb->len))
BUG();
@@ -589,8 +590,6 @@ struct sk_buff *pskb_copy(struct sk_buff *skb, gfp_t gfp_mask)
skb_put(n, skb_headlen(skb));
/* Copy the bytes */
skb_copy_from_linear_data(skb, n->data, n->len);
- n->csum = skb->csum;
- n->ip_summed = skb->ip_summed;
n->truesize += skb->data_len;
n->data_len = skb->data_len;
@@ -686,6 +685,7 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
skb->transport_header += off;
skb->network_header += off;
skb->mac_header += off;
+ skb->csum_start += off;
skb->cloned = 0;
skb->hdr_len = 0;
skb->nohdr = 0;
@@ -734,9 +734,6 @@ struct sk_buff *skb_realloc_headroom(struct sk_buff *skb, unsigned int headroom)
*
* You must pass %GFP_ATOMIC as the allocation priority if this function
* is called from an interrupt.
- *
- * BUG ALERT: ip_summed is not copied. Why does this work? Is it used
- * only by netfilter in the cases when checksum is recalculated? --ANK
*/
struct sk_buff *skb_copy_expand(const struct sk_buff *skb,
int newheadroom, int newtailroom,
@@ -749,7 +746,7 @@ struct sk_buff *skb_copy_expand(const struct sk_buff *skb,
gfp_mask);
int oldheadroom = skb_headroom(skb);
int head_copy_len, head_copy_off;
- int off = 0;
+ int off;
if (!n)
return NULL;
@@ -773,12 +770,13 @@ struct sk_buff *skb_copy_expand(const struct sk_buff *skb,
copy_skb_header(n, skb);
-#ifdef NET_SKBUFF_DATA_USES_OFFSET
off = newheadroom - oldheadroom;
-#endif
+ n->csum_start += off;
+#ifdef NET_SKBUFF_DATA_USES_OFFSET
n->transport_header += off;
n->network_header += off;
n->mac_header += off;
+#endif
return n;
}
^ permalink raw reply related
* RE: [PATCH 2.6.24 4/5]S2io: Check for CARD_DOWN before handling traffic
From: Ramkrishna Vepa @ 2007-09-01 1:43 UTC (permalink / raw)
To: Jeff Garzik; +Cc: netdev, support
In-Reply-To: <46D811BB.5060007@garzik.org>
Jeff,
> > - Added check to return from the traffic handling function, if the
card
> status
> > is DOWN.
> >
> > Signed-off-by: Sivakumar Subramani
<sivakumar.subramani@neterion.com>
> > Signed-off-by: Santosh Rastapur <santosh.rastapur@neterion.com>
> > Signed-off-by: Ramkrishna Vepa <ram.vepa@neterion.com>
> > ---
> > diff -Nurp patch3/drivers/net/s2io.c patch4/drivers/net/s2io.c
> > --- patch3/drivers/net/s2io.c 2007-08-15 08:57:32.000000000
-0700
> > +++ patch4/drivers/net/s2io.c 2007-08-15 08:42:14.000000000
-0700
> > @@ -2927,6 +2927,11 @@ static int s2io_poll(struct net_device *
> > int i;
> >
> > atomic_inc(&nic->isr_cnt);
> > + if (unlikely(atomic_read(&nic->card_state) == CARD_DOWN)) {
> > + atomic_dec(&nic->isr_cnt);
> > + return IRQ_NONE;
> > + }
> > +
> > mac_control = &nic->mac_control;
> > config = &nic->config;
> >
>
> invalid return value, for this function
>
> Overall, this looks quite racy -- why does the card state differ from
> net_device state in the first place?
[Ram] Agreed, it is racy. Will use test_and_set_bit(), set_bit() and
clear_bit().
The card reset could be initiated due to an internal error detected in
one of the blocks in the chip, while interrupts are still occurring.
There is a net_device state (LINK_STATE_START) set at open and reset at
close but none for temporary disabled/enabled states. Did you want us to
use this enum along with the CARRIER states?
Ram
^ permalink raw reply
* Re: [PATCH 1/5] Net: ath5k, split hw into hw, phy and initvals
From: Nick Kossifidis @ 2007-09-01 3:12 UTC (permalink / raw)
To: John W. Linville
Cc: Christoph Hellwig, Jiri Slaby,
linux-wireless-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20070830123849.GB5140-2XuSBdqkA4R54TAoqtyWWQ@public.gmane.org>
2007/8/30, John W. Linville <linville-2XuSBdqkA4R54TAoqtyWWQ@public.gmane.org>:
> On Thu, Aug 30, 2007 at 04:50:01AM +0300, Nick Kossifidis wrote:
> > 2007/8/28, Christoph Hellwig <hch-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org>:
>
> > > ath5k_hw_phy.o should probably be ath5k_phy.o by conventions used by
> > > most drivers and ath5k_hw_inivals.o mights aswell be something like
> > > ath5k_init.o
>
> > If you check out the code you'll see i'm using the same convention
> > inside them, ath5k_hw* files contain hw related functions
> > (ath5k_hw_<name>) while driver code has ath5k_<name>. Also ath5k_init
> > is misleading, file acually includes initial register settings for
>
> I have to agree w/ Christoph -- the extra "_hw" in the names is just
> a bit unwieldy.
>
> John
>
> P.S. "ath5k_initvals.c" seems acceptable to me.
ACK, i'll remove _hw ;-)
--
GPG ID: 0xD21DB2DB
As you read this post global entropy rises. Have Fun ;-)
Nick
^ 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