Netdev List
 help / color / mirror / Atom feed
* Re: [net-next 6/10] bnx2x: Update vlan_features
From: Or Gerlitz @ 2009-07-23 11:14 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: eilong, David Miller, netdev, Jay Vosburgh, Eric Dumazet
In-Reply-To: <4A683F83.1060701@trash.net>

Patrick McHardy wrote:
> vlan_features doesn't need to be updated, the resulting dev->features
> of the VLAN device is computed as the intersection of dev->features
> and dev->vlan_features.

I'm not sure to follow, do you claim that the patches to bnx2x and bonding aren't needed to make vlans set on top of such devices to support these features?

For example, on two 2.6.30 systems I have here, where one uses Intel/igb and the second uses Broadcom/tg3 I can see that vlan devices on top of igb have features while those on top of tg3 has none


2.6.30/igb/8021q
# cat /sys/class/net/eth1/features
0x114bb3
# cat /sys/class/net/eth1.4004/features
0x110803


2.6.30/tg3/8021q
# cat /sys/class/net/eth1/features
0x109a3
# cat /sys/class/net/eth1.4001/features
0x0



Or.

^ permalink raw reply

* Re: [PATCH net-next-2.6] bonding: propogate vlan_features to bonding master
From: Patrick McHardy @ 2009-07-23 11:03 UTC (permalink / raw)
  To: Jay Vosburgh; +Cc: Or Gerlitz, David Miller, netdev
In-Reply-To: <3463.1248298460@death.nxdomain.ibm.com>

Jay Vosburgh wrote:
> 	Propogate the vlan_features of the slave devices to the bonding
> master device, using the same logic as for regular features.
> 
> 	Tested by Or Gerlitz <ogerlitz@voltaire.com>, who also removed
> the debug logic from the original test patch.
> 
> diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
> index 3bf0cc6..5a8b882 100644
> --- a/drivers/net/bonding/bond_main.c
> +++ b/drivers/net/bonding/bond_main.c
> @@ -1354,6 +1359,7 @@ static int bond_compute_features(struct bonding *bond)
>  done:
>  	features |= (bond_dev->features & BOND_VLAN_FEATURES);
>  	bond_dev->features = netdev_fix_features(features, NULL);
> +	bond_dev->vlan_features = netdev_fix_features(vlan_features, NULL);


You need to call netdev_features_change() to make sure the VLAN
code notices the change.

^ permalink raw reply

* Re: [net-next 6/10] bnx2x: Update vlan_features
From: Patrick McHardy @ 2009-07-23 10:46 UTC (permalink / raw)
  To: eilong; +Cc: David Miller, netdev, Gerlitz
In-Reply-To: <1248191263.18195.49.camel@lb-tlvb-eilong>

Eilon Greenstein wrote:
> As noted by Or Gerlitz <ogerlitz@Voltaire.com>, the vlan_features was not
> updated
> 
> Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
> ---
>  drivers/net/bnx2x_main.c |   19 +++++++++++++++++--
>  1 files changed, 17 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c
> index 18c3803..b404a9b 100644
> --- a/drivers/net/bnx2x_main.c
> +++ b/drivers/net/bnx2x_main.c
> @@ -9310,9 +9310,17 @@ static int bnx2x_set_tso(struct net_device *dev, u32 data)
>  	if (data) {
>  		dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN);
>  		dev->features |= NETIF_F_TSO6;
> +#ifdef BCM_VLAN
> +		dev->vlan_features |= (NETIF_F_TSO | NETIF_F_TSO_ECN);
> +		dev->vlan_features |= NETIF_F_TSO6;
> +#endif
>  	} else {
>  		dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO_ECN);
>  		dev->features &= ~NETIF_F_TSO6;
> +#ifdef BCM_VLAN
> +		dev->vlan_features &= ~(NETIF_F_TSO | NETIF_F_TSO_ECN);
> +		dev->vlan_features &= ~NETIF_F_TSO6;
> +#endif

vlan_features doesn't need to be updated, the resulting dev->features
of the VLAN device is computed as the intersection of dev->features
and dev->vlan_features.


^ permalink raw reply

* Re: [PATCH] be2net: Adding support for 802.1ad (q-in-q mode)
From: Patrick McHardy @ 2009-07-23 10:12 UTC (permalink / raw)
  To: Sarveshwar Bandi; +Cc: davem, netdev
In-Reply-To: <20090723100533.GB3172@serverengines.com>

Sarveshwar Bandi wrote:
> On 23/07/09 11:48 +0200, Patrick McHardy wrote:
>> Sarveshwar Bandi wrote:
>>> On 23/07/09 11:25 +0200, Patrick McHardy wrote:
>>>> adapter->vlan_grp will always be the VLAN group associated directly with
>>>> the device, which is the group for the outer tag, not the inner one. So
>>>> this can't properly associate packets with the correct VLAN device.
>>>>
>>> In this case, vid is the inner vlan id in the packet. This is also the
>>> vlan id configured by vconfig. 
>>
>> So where does the outer tag come from then? Please provide an example
>> how to configure this using Q-in-Q.
>>
> The outer vlan is totally transparent to the host. It is used by the NIC 
> to demux packets across multiple pci network functions. Currently the 
> outer vlan tags are configured on the NIC by OEM provided utilities.

I see. A proper changelog entry would have explained that and avoided
all this confusion. Not that I think using another tool for this is a
good solution, but no objections from a functional POV.


^ permalink raw reply

* Re: [PATCH] be2net: Adding support for 802.1ad (q-in-q mode)
From: Sarveshwar Bandi @ 2009-07-23 10:05 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: davem, netdev
In-Reply-To: <4A6831E7.3020302@trash.net>

On 23/07/09 11:48 +0200, Patrick McHardy wrote:
> Sarveshwar Bandi wrote:
> > On 23/07/09 11:25 +0200, Patrick McHardy wrote:
> >> Sarveshwar Bandi wrote:
> >>> On 23/07/09 11:07 +0200, Patrick McHardy wrote:
> >>>>> Patch has code to check if the controller is in q-in-q mode. When the packet
> >>>>> has two vids, only the inner vid is passed onto the stack. The stack is never
> >>>>> made aware of the outer vid.
> >>>> But you're still using the outer VLAN group when passing the packet to
> >>>> the VLAN code, so the association to the correct VLAN device can't work.
> >>> In the case where packet comes with two vlan ids, the rx descriptor contains
> >>> the inner vlan id and qnq is set to 1, the driver indicates this vid to the
> >>> stack.
> >>> In the case where packet comes with single vlan id, the rx descriptor
> >>> contains the outer vlan id and qnq is set to 0, the driver indicates this
> >>> packet as a non-vlan packet to the stack by calling netif_receive_skb.
> >> I understand that. But the driver does:
> >>
> >> 	if (vtp) {
> >> 		if (!adapter->vlan_grp || adapter->num_vlans == 0) {
> >> 			kfree_skb(skb);
> >> 			return;
> >> 		}
> >> 		vid = AMAP_GET_BITS(struct amap_eth_rx_compl, vlan_tag, rxcp);
> >> 		vid = be16_to_cpu(vid);
> >> 		vlan_hwaccel_receive_skb(skb, adapter->vlan_grp, vid);
> >> 	}
> >>
> >> adapter->vlan_grp will always be the VLAN group associated directly with
> >> the device, which is the group for the outer tag, not the inner one. So
> >> this can't properly associate packets with the correct VLAN device.
> >>
> > In this case, vid is the inner vlan id in the packet. This is also the
> > vlan id configured by vconfig. 
> 
> So where does the outer tag come from then? Please provide an example
> how to configure this using Q-in-Q.
> 
The outer vlan is totally transparent to the host. It is used by the NIC 
to demux packets across multiple pci network functions. Currently the 
outer vlan tags are configured on the NIC by OEM provided utilities.
> > In the other case where packet had a single vlan tag, the following code
> > will set vlanf to 0 (vtp now renamed to vlanf in the patch) and will be
> > indicated as a non-vlan packet.
> >        if (adapter->qnq && !qnq)
> >                vlanf = 0;
> 
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH] be2net: Adding support for 802.1ad (q-in-q mode)
From: Patrick McHardy @ 2009-07-23  9:48 UTC (permalink / raw)
  To: Sarveshwar Bandi; +Cc: davem, netdev
In-Reply-To: <20090723094501.GA3172@serverengines.com>

Sarveshwar Bandi wrote:
> On 23/07/09 11:25 +0200, Patrick McHardy wrote:
>> Sarveshwar Bandi wrote:
>>> On 23/07/09 11:07 +0200, Patrick McHardy wrote:
>>>>> Patch has code to check if the controller is in q-in-q mode. When the packet
>>>>> has two vids, only the inner vid is passed onto the stack. The stack is never
>>>>> made aware of the outer vid.
>>>> But you're still using the outer VLAN group when passing the packet to
>>>> the VLAN code, so the association to the correct VLAN device can't work.
>>> In the case where packet comes with two vlan ids, the rx descriptor contains
>>> the inner vlan id and qnq is set to 1, the driver indicates this vid to the
>>> stack.
>>> In the case where packet comes with single vlan id, the rx descriptor
>>> contains the outer vlan id and qnq is set to 0, the driver indicates this
>>> packet as a non-vlan packet to the stack by calling netif_receive_skb.
>> I understand that. But the driver does:
>>
>> 	if (vtp) {
>> 		if (!adapter->vlan_grp || adapter->num_vlans == 0) {
>> 			kfree_skb(skb);
>> 			return;
>> 		}
>> 		vid = AMAP_GET_BITS(struct amap_eth_rx_compl, vlan_tag, rxcp);
>> 		vid = be16_to_cpu(vid);
>> 		vlan_hwaccel_receive_skb(skb, adapter->vlan_grp, vid);
>> 	}
>>
>> adapter->vlan_grp will always be the VLAN group associated directly with
>> the device, which is the group for the outer tag, not the inner one. So
>> this can't properly associate packets with the correct VLAN device.
>>
> In this case, vid is the inner vlan id in the packet. This is also the
> vlan id configured by vconfig. 

So where does the outer tag come from then? Please provide an example
how to configure this using Q-in-Q.

> In the other case where packet had a single vlan tag, the following code
> will set vlanf to 0 (vtp now renamed to vlanf in the patch) and will be
> indicated as a non-vlan packet.
>        if (adapter->qnq && !qnq)
>                vlanf = 0;


^ permalink raw reply

* Re: [PATCH] be2net: Adding support for 802.1ad (q-in-q mode)
From: Sarveshwar Bandi @ 2009-07-23  9:45 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: davem, netdev
In-Reply-To: <4A682CA1.8030706@trash.net>

On 23/07/09 11:25 +0200, Patrick McHardy wrote:
> Sarveshwar Bandi wrote:
> > On 23/07/09 11:07 +0200, Patrick McHardy wrote:
> >>> Patch has code to check if the controller is in q-in-q mode. When the packet
> >>> has two vids, only the inner vid is passed onto the stack. The stack is never
> >>> made aware of the outer vid.
> >>
> >> But you're still using the outer VLAN group when passing the packet to
> >> the VLAN code, so the association to the correct VLAN device can't work.
> >
> > In the case where packet comes with two vlan ids, the rx descriptor contains
> > the inner vlan id and qnq is set to 1, the driver indicates this vid to the
> > stack.
> > In the case where packet comes with single vlan id, the rx descriptor
> > contains the outer vlan id and qnq is set to 0, the driver indicates this
> > packet as a non-vlan packet to the stack by calling netif_receive_skb.
> 
> I understand that. But the driver does:
> 
> 	if (vtp) {
> 		if (!adapter->vlan_grp || adapter->num_vlans == 0) {
> 			kfree_skb(skb);
> 			return;
> 		}
> 		vid = AMAP_GET_BITS(struct amap_eth_rx_compl, vlan_tag, rxcp);
> 		vid = be16_to_cpu(vid);
> 		vlan_hwaccel_receive_skb(skb, adapter->vlan_grp, vid);
> 	}
> 
> adapter->vlan_grp will always be the VLAN group associated directly with
> the device, which is the group for the outer tag, not the inner one. So
> this can't properly associate packets with the correct VLAN device.
>
In this case, vid is the inner vlan id in the packet. This is also the
vlan id configured by vconfig. 
In the other case where packet had a single vlan tag, the following code
will set vlanf to 0 (vtp now renamed to vlanf in the patch) and will be
indicated as a non-vlan packet.
       if (adapter->qnq && !qnq)
               vlanf = 0;
 
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH] be2net: Adding support for 802.1ad (q-in-q mode)
From: Patrick McHardy @ 2009-07-23  9:25 UTC (permalink / raw)
  To: Sarveshwar Bandi; +Cc: davem, netdev
In-Reply-To: <20090723092036.GB1761@serverengines.com>

Sarveshwar Bandi wrote:
> On 23/07/09 11:07 +0200, Patrick McHardy wrote:
>>> Patch has code to check if the controller is in q-in-q mode. When the packet
>>> has two vids, only the inner vid is passed onto the stack. The stack is never
>>> made aware of the outer vid.
>>
>> But you're still using the outer VLAN group when passing the packet to
>> the VLAN code, so the association to the correct VLAN device can't work.
>
> In the case where packet comes with two vlan ids, the rx descriptor contains
> the inner vlan id and qnq is set to 1, the driver indicates this vid to the
> stack.
> In the case where packet comes with single vlan id, the rx descriptor
> contains the outer vlan id and qnq is set to 0, the driver indicates this
> packet as a non-vlan packet to the stack by calling netif_receive_skb.

I understand that. But the driver does:

	if (vtp) {
		if (!adapter->vlan_grp || adapter->num_vlans == 0) {
			kfree_skb(skb);
			return;
		}
		vid = AMAP_GET_BITS(struct amap_eth_rx_compl, vlan_tag, rxcp);
		vid = be16_to_cpu(vid);
		vlan_hwaccel_receive_skb(skb, adapter->vlan_grp, vid);
	}

adapter->vlan_grp will always be the VLAN group associated directly with
the device, which is the group for the outer tag, not the inner one. So
this can't properly associate packets with the correct VLAN device.


^ permalink raw reply

* Re: [PATCH] be2net: Adding support for 802.1ad (q-in-q mode)
From: Sarveshwar Bandi @ 2009-07-23  9:20 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: davem, netdev
In-Reply-To: <4A68284B.8020100@trash.net>

On 23/07/09 11:07 +0200, Patrick McHardy wrote:
> Sarveshwar Bandi wrote:
> > On 23/07/09 10:47 +0200, Patrick McHardy wrote:
> >> Sarveshwar Bandi wrote:
> >>> Please review and apply patch to net-next tree. Patch implements the 
> >>> support for q-in-q mode.
> >>
> >> Please describe your change more precisely. How does this interact with
> >> the stack and which VID is propagated to the VLAN code?
> >
> > Patch has code to check if the controller is in q-in-q mode. When the packet
> > has two vids, only the inner vid is passed onto the stack. The stack is never
> > made aware of the outer vid.
> 
> But you're still using the outer VLAN group when passing the packet to
> the VLAN code, so the association to the correct VLAN device can't work.
In the case where packet comes with two vlan ids, the rx descriptor contains
the inner vlan id and qnq is set to 1, the driver indicates this vid to the
stack.
In the case where packet comes with single vlan id, the rx descriptor
contains the outer vlan id and qnq is set to 0, the driver indicates this
packet as a non-vlan packet to the stack by calling netif_receive_skb.
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH] be2net: Adding support for 802.1ad (q-in-q mode)
From: Patrick McHardy @ 2009-07-23  9:07 UTC (permalink / raw)
  To: Sarveshwar Bandi; +Cc: davem, netdev
In-Reply-To: <20090723090216.GA1761@serverengines.com>

Sarveshwar Bandi wrote:
> On 23/07/09 10:47 +0200, Patrick McHardy wrote:
>> Sarveshwar Bandi wrote:
>>> Please review and apply patch to net-next tree. Patch implements the 
>>> support for q-in-q mode.
>>
>> Please describe your change more precisely. How does this interact with
>> the stack and which VID is propagated to the VLAN code?
>
> Patch has code to check if the controller is in q-in-q mode. When the packet
> has two vids, only the inner vid is passed onto the stack. The stack is never
> made aware of the outer vid.

But you're still using the outer VLAN group when passing the packet to
the VLAN code, so the association to the correct VLAN device can't work.

^ permalink raw reply

* Re: [PATCH] be2net: Adding support for 802.1ad (q-in-q mode)
From: Sarveshwar Bandi @ 2009-07-23  9:02 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: davem, netdev
In-Reply-To: <4A6823B5.7050608@trash.net>

On 23/07/09 10:47 +0200, Patrick McHardy wrote:
> Sarveshwar Bandi wrote:
> > Please review and apply patch to net-next tree. Patch implements the 
> > support for q-in-q mode.
> 
> Please describe your change more precisely. How does this interact with
> the stack and which VID is propagated to the VLAN code?
Patch has code to check if the controller is in q-in-q mode. When the packet
has two vids, only the inner vid is passed onto the stack. The stack is never
made aware of the outer vid.
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH] be2net: Adding support for 802.1ad (q-in-q mode)
From: Patrick McHardy @ 2009-07-23  8:47 UTC (permalink / raw)
  To: Sarveshwar Bandi; +Cc: davem, netdev
In-Reply-To: <20090723082552.GA602@serverengines.com>

Sarveshwar Bandi wrote:
> Please review and apply patch to net-next tree. Patch implements the 
> support for q-in-q mode.

Please describe your change more precisely. How does this interact with
the stack and which VID is propagated to the VLAN code?

^ permalink raw reply

* Re: ixgbe: panic in ixgbe_clean_rx_irq()
From: Jesper Dangaard Brouer @ 2009-07-23  8:46 UTC (permalink / raw)
  To: Waskiewicz Jr, Peter P; +Cc: netdev@vger.kernel.org
In-Reply-To: <Pine.WNT.4.64.0907221110550.9360@ppwaskie-MOBL2.amr.corp.intel.com>

On Wed, 2009-07-22 at 11:13 -0700, Waskiewicz Jr, Peter P wrote:
> On Wed, 22 Jul 2009, Jesper Dangaard Brouer wrote:
> 
> > Hi Peter,
> > 
> > Got a panic from the ixgbe driver on my 82599 based NICs, while running
> > two pktgen tests (1500 bytes packets) against the machine.
> > 
> > Kernel: 2.6.31-rc1-net-2.6-00122-ge594e96 with preemption

Got a new panic.  The strange thing its not happening in the same
place... and the anoying thing is that its hard to reproduce, as I have
to run pktgen a very long time before it dies.

I'm starting to suspect it could be related to CPU freq scaling, as the
last sysfs file is /sys/devices/system/cpu/cpu7/cpufreq/scaling_governor
and the call stack originates from mwait_idle().


[27925.077996] general protection fault: 0000 [#1] PREEMPT SMP 
[27925.095080] last sysfs file: /sys/devices/system/cpu/cpu7/cpufreq/scaling_governor
[27925.118042] CPU 7 
[27925.124196] Modules linked in: asus_atk0110 ixgbe hwmon mdio r8169
[27925.142863] Pid: 0, comm: swapper Not tainted 2.6.31-rc1-net-2.6-00122-ge594e96 #8 System Product Name
[27925.171033] RIP: 0010:[<ffffffff81382b29>]  [<ffffffff81382b29>] skb_release_head_state+0x69/0xba
[27925.197904] RSP: 0018:ffff880001942d70  EFLAGS: 00010286
[27925.213938] RAX: 0000000000000000 RBX: ffff8800b0022100 RCX: 0000000000000400
[27925.235443] RDX: 00000000000003d6 RSI: 00000000b9c03000 RDI: d100000000000000
[27925.256958] RBP: ffff880001942d80 R08: 00000000000002a3 R09: ffffc90011e6a428
[27925.278474] R10: 0000000101a5abfb R11: ffffffff813828c5 R12: ffff8800bac7c580
[27925.299990] R13: 0000000000002a40 R14: 00000000000002a5 R15: 00000000000002a4
[27925.321504] FS:  0000000000000000(0000) GS:ffff88000193f000(0000) knlGS:0000000000000000
[27925.346030] CS:  0010 DS: 0018 ES: 0018 CR0: 000000008005003b
[27925.363373] CR2: 00007fecde5734a8 CR3: 00000000a5015000 CR4: 00000000000006a0
[27925.384878] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[27925.406380] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
[27925.427884] Process swapper (pid: 0, threadinfo ffff8800bef0c000, task ffff8800beef3480)
[27925.452409] Stack:
[27925.458553]  00000000000002a3 ffff8800b0022100 ffff880001942da0 ffffffff81382854
[27925.480328] <0> ffffc90011e6a428 ffffc900119ee480 ffff880001942db0 ffffffff813828f5
[27925.503588] <0> ffff880001942dc0 ffffffff8138b441 ffff880001942de0 ffffffffa001ab3e
[27925.527521] Call Trace:
[27925.534971]  <IRQ> 
[27925.541385]  [<ffffffff81382854>] __kfree_skb+0x11/0x87
[27925.557169]  [<ffffffff813828f5>] consume_skb+0x2b/0x2d
[27925.572943]  [<ffffffff8138b441>] dev_kfree_skb_any+0x2e/0x30
[27925.590287]  [<ffffffffa001ab3e>] ixgbe_unmap_and_free_tx_resource+0x39/0x4c [ixgbe]
[27925.613772]  [<ffffffffa001acb5>] ixgbe_clean_tx_irq+0xcf/0x366 [ixgbe]
[27925.633721]  [<ffffffffa001af88>] ixgbe_clean_txonly+0x3c/0xbd [ixgbe]
[27925.653410]  [<ffffffff8138a7b5>] net_rx_action+0xb2/0x234
[27925.669966]  [<ffffffff8103fb35>] __do_softirq+0x10c/0x211
[27925.686521]  [<ffffffff8100cc2c>] call_softirq+0x1c/0x28
[27925.702556]  [<ffffffff8100de84>] do_softirq+0x34/0x72
[27925.718070]  [<ffffffff8103f83f>] irq_exit+0x36/0x85
[27925.733065]  [<ffffffff8100d75f>] do_IRQ+0xa6/0xbd
[27925.747540]  [<ffffffff8100c493>] ret_from_intr+0x0/0xa
[27925.767191]  <EOI> 
[27925.773603]  [<ffffffff81012355>] ? mwait_idle+0x89/0x9f
[27925.789646]  [<ffffffff81012348>] ? mwait_idle+0x7c/0x9f
[27925.805682]  [<ffffffff8142c948>] ? atomic_notifier_call_chain+0xf/0x11
[27925.825624]  [<ffffffff8100aedb>] ? cpu_idle+0x4f/0xb3
[27925.841137]  [<ffffffff81424478>] ? start_secondary+0x17f/0x184
[27925.858994] Code: 00 ff 03 74 11 be 8e 01 00 00 48 c7 c7 fc d3 5f 81 e8 7f 79 cb ff 48 89 df ff 93 80 00 00 00 48 8b bb 88 00 00
 00 48 85 ff 74 0f <f0> ff 0f 0f 94 c0 84 c0 74 05 e8 68 1f 02 00 48 8b bb 90 00 00 
[27925.915956] RIP  [<ffffffff81382b29>] skb_release_head_state+0x69/0xba
[27925.935656]  RSP <ffff880001942d70>
[27925.946574] ---[ end trace acd86b5373a70766 ]---
[27925.960578] Kernel panic - not syncing: Fatal exception in interrupt
[27925.979798] Pid: 0, comm: swapper Tainted: G      D    2.6.31-rc1-net-2.6-00122-ge594e96 #8
[27926.005157] Call Trace:
[27926.012654]  <IRQ>  [<ffffffff81427c6b>] panic+0xaa/0x155
[27926.029070]  [<ffffffff8103f88c>] ? irq_exit+0x83/0x85
[27926.044644]  [<ffffffff8100c493>] ? ret_from_intr+0x0/0xa
[27926.061002]  [<ffffffff8142b039>] ? oops_end+0x6b/0xba
[27926.076571]  [<ffffffff8142b078>] oops_end+0xaa/0xba
[27926.091628]  [<ffffffff8100f0d1>] die+0x55/0x5e
[27926.105374]  [<ffffffff8142ac8e>] do_general_protection+0x123/0x12b
[27926.124324]  [<ffffffff8142a1af>] ? _spin_unlock+0x2a/0x35
[27926.140936]  [<ffffffff8142a5df>] general_protection+0x1f/0x30
[27926.158595]  [<ffffffff813828c5>] ? __kfree_skb+0x82/0x87
[27926.174946]  [<ffffffff81382b29>] ? skb_release_head_state+0x69/0xba
[27926.194169]  [<ffffffff81382854>] __kfree_skb+0x11/0x87
[27926.210008]  [<ffffffff813828f5>] consume_skb+0x2b/0x2d
[27926.225834]  [<ffffffff8138b441>] dev_kfree_skb_any+0x2e/0x30
[27926.243231]  [<ffffffffa001ab3e>] ixgbe_unmap_and_free_tx_resource+0x39/0x4c [ixgbe]
[27926.266772]  [<ffffffffa001acb5>] ixgbe_clean_tx_irq+0xcf/0x366 [ixgbe]
[27926.286785]  [<ffffffffa001af88>] ixgbe_clean_txonly+0x3c/0xbd [ixgbe]
[27926.306524]  [<ffffffff8138a7b5>] net_rx_action+0xb2/0x234
[27926.323147]  [<ffffffff8103fb35>] __do_softirq+0x10c/0x211
[27926.339765]  [<ffffffff8100cc2c>] call_softirq+0x1c/0x28
[27926.355853]  [<ffffffff8100de84>] do_softirq+0x34/0x72
[27926.371417]  [<ffffffff8103f83f>] irq_exit+0x36/0x85
[27926.386466]  [<ffffffff8100d75f>] do_IRQ+0xa6/0xbd
[27926.400990]  [<ffffffff8100c493>] ret_from_intr+0x0/0xa
[27926.416819]  <EOI>  [<ffffffff81012355>] ? mwait_idle+0x89/0x9f
[27926.434794]  [<ffffffff81012348>] ? mwait_idle+0x7c/0x9f
[27926.450881]  [<ffffffff8142c948>] ? atomic_notifier_call_chain+0xf/0x11
[27926.470877]  [<ffffffff8100aedb>] ? cpu_idle+0x4f/0xb3
[27926.486454]  [<ffffffff81424478>] ? start_secondary+0x17f/0x184

-- 
Med venlig hilsen / Best regards
  Jesper Brouer
  ComX Networks A/S
  Linux Network developer
  Cand. Scient Datalog / MSc.
  Author of http://adsl-optimizer.dk
  LinkedIn: http://www.linkedin.com/in/brouer


^ permalink raw reply

* [PATCH net-next-2.6] bnx2: Update vlan_features
From: Eric Dumazet @ 2009-07-23  8:29 UTC (permalink / raw)
  To: Or Gerlitz
  Cc: Jay Vosburgh, David Miller, netdev, Eilon Greenstein,
	Michael Chan
In-Reply-To: <4A681029.4070600@voltaire.com>

Or Gerlitz a écrit :
> Eric Dumazet wrote:
>> Jay Vosburgh a écrit :
>>> Propogate the vlan_features of the slave devices to the bonding
>>> master device, using the same logic as for regular features.
>> Seems pretty cool, but I could not test it on my dev machine, since
>> tg3 and bnx2 drivers dont advertize yet vlan_features
> The bnx2x maintainer posted yesterday a patch that does so, I assume a
> similar patch could work for at least one of tg3 or bnx2. I copied both
> maintainers on this email, in  the hope they can come up with a patch.
> 

Here is the bnx2 patch I cooked to test this vlan_features propagation on bonding.

Everything fine so far !

# cat /proc/net/bonding/bond0
Ethernet Channel Bonding Driver: v3.5.0 (November 4, 2008)

Bonding Mode: fault-tolerance (active-backup)
Primary Slave: None
Currently Active Slave: eth1
MII Status: up
MII Polling Interval (ms): 100
Up Delay (ms): 0
Down Delay (ms): 0

Slave Interface: eth1    (bnx2 driver)
MII Status: up
Link Failure Count: 2
Permanent HW addr: 00:1e:0b:ec:d3:d2

Slave Interface: eth2    (tg3 driver)
MII Status: up
Link Failure Count: 0
Permanent HW addr: 00:1e:0b:92:78:50


# ethtool -k bond0
Offload parameters for bond0:
Cannot get device rx csum settings: Operation not supported
rx-checksumming: off
tx-checksumming: on
scatter-gather: on
tcp-segmentation-offload: on
udp-fragmentation-offload: off
generic-segmentation-offload: off
generic-receive-offload: off
large-receive-offload: off

# ip link add link bond0 vlan.103 type vlan id 103
# ethtool -k vlan.103
Offload parameters for vlan.103:
rx-checksumming: off
tx-checksumming: on
scatter-gather: on
tcp-segmentation-offload: on
udp-fragmentation-offload: off
generic-segmentation-offload: on
generic-receive-offload: off
large-receive-offload: off


Thanks Or & Jay

[PATCH net-next-2.6] bnx2: Update vlan_features

In order to get full use of some advanced features of BNX2, we now need to
fill dev->vlan_features.

Patch successfully tested with vlan devices built on top of bonding.
(bond0 : one bnx2 slave, one tg3 slave (not yet vlan_features enabled)

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
 drivers/net/bnx2.c |   36 ++++++++++++++++++++++++++++++------
 1 files changed, 30 insertions(+), 6 deletions(-)

diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index b70cc99..0868673 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -3485,6 +3485,20 @@ static int bnx2_poll(struct napi_struct *napi, int budget)
 	return work_done;
 }
 
+static void inline vlan_features_add(struct net_device *dev, unsigned long flags)
+{
+#ifdef BCM_VLAN
+	dev->vlan_features |= flags;
+#endif
+}
+
+static void inline vlan_features_del(struct net_device *dev, unsigned long flags)
+{
+#ifdef BCM_VLAN
+	dev->vlan_features &= ~flags;
+#endif
+}
+
 /* Called with rtnl_lock from vlan functions and also netif_tx_lock
  * from set_multicast.
  */
@@ -7068,11 +7082,17 @@ bnx2_set_tso(struct net_device *dev, u32 data)
 
 	if (data) {
 		dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
-		if (CHIP_NUM(bp) == CHIP_NUM_5709)
+		vlan_features_add(dev, NETIF_F_TSO | NETIF_F_TSO_ECN);
+		if (CHIP_NUM(bp) == CHIP_NUM_5709) {
 			dev->features |= NETIF_F_TSO6;
-	} else
+			vlan_features_add(dev, NETIF_F_TSO6);
+		}
+	} else {
 		dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6 |
 				   NETIF_F_TSO_ECN);
+		vlan_features_del(dev, NETIF_F_TSO | NETIF_F_TSO6 |
+				  NETIF_F_TSO_ECN);
+	}
 	return 0;
 }
 
@@ -8064,16 +8084,20 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 	memcpy(dev->perm_addr, bp->mac_addr, 6);
 
 	dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
-	if (CHIP_NUM(bp) == CHIP_NUM_5709)
+	vlan_features_add(dev, NETIF_F_IP_CSUM | NETIF_F_SG);
+	if (CHIP_NUM(bp) == CHIP_NUM_5709) {
 		dev->features |= NETIF_F_IPV6_CSUM;
-
+		vlan_features_add(dev, NETIF_F_IPV6_CSUM);
+	}
 #ifdef BCM_VLAN
 	dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
 #endif
 	dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
-	if (CHIP_NUM(bp) == CHIP_NUM_5709)
+	vlan_features_add(dev, NETIF_F_TSO | NETIF_F_TSO_ECN);
+	if (CHIP_NUM(bp) == CHIP_NUM_5709) {
 		dev->features |= NETIF_F_TSO6;
-
+		vlan_features_add(dev, NETIF_F_TSO6);
+	}
 	if ((rc = register_netdev(dev))) {
 		dev_err(&pdev->dev, "Cannot register net device\n");
 		goto error;

^ permalink raw reply related

* [PATCH] be2net: Adding support for 802.1ad (q-in-q mode)
From: Sarveshwar Bandi @ 2009-07-23  8:26 UTC (permalink / raw)
  To: davem; +Cc: netdev

Please review and apply patch to net-next tree. Patch implements the 
support for q-in-q mode.

- Sarvesh

Signed-off-by: Sarveshwar Bandi <sarveshwarb@serverengines.com>
---
 drivers/net/benet/be.h      |    1 +
 drivers/net/benet/be_cmds.c |    8 +++++++-
 drivers/net/benet/be_cmds.h |    4 +++-
 drivers/net/benet/be_main.c |   22 ++++++++++++++++++----
 4 files changed, 29 insertions(+), 6 deletions(-)

diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h
index 41cddbe..317b77d 100644
--- a/drivers/net/benet/be.h
+++ b/drivers/net/benet/be.h
@@ -270,6 +270,7 @@ struct be_adapter {
 	bool link_up;
 	u32 port_num;
 	bool promiscuous;
+	bool qnq;
 };
 
 extern struct ethtool_ops be_ethtool_ops;
diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c
index 583517e..848a75b 100644
--- a/drivers/net/benet/be_cmds.c
+++ b/drivers/net/benet/be_cmds.c
@@ -1037,11 +1037,12 @@ int be_cmd_get_flow_control(struct be_ct
 	return status;
 }
 
-int be_cmd_query_fw_cfg(struct be_ctrl_info *ctrl, u32 *port_num)
+int be_cmd_query_fw_cfg(struct be_ctrl_info *ctrl, u32 *port_num, bool *qnq)
 {
 	struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
 	struct be_cmd_req_query_fw_cfg *req = embedded_payload(wrb);
 	int status;
+	int mode;
 
 	spin_lock(&ctrl->mbox_lock);
 
@@ -1056,6 +1057,11 @@ int be_cmd_query_fw_cfg(struct be_ctrl_i
 	if (!status) {
 		struct be_cmd_resp_query_fw_cfg *resp = embedded_payload(wrb);
 		*port_num = le32_to_cpu(resp->phys_port);
+		mode = le32_to_cpu(resp->function_mode);
+		if (mode & QNQ_MODE)
+			*qnq = true;
+		else
+			*qnq = false;
 	}
 
 	spin_unlock(&ctrl->mbox_lock);
diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h
index 747626d..4cfe995 100644
--- a/drivers/net/benet/be_cmds.h
+++ b/drivers/net/benet/be_cmds.h
@@ -683,6 +683,7 @@ struct be_cmd_resp_modify_eq_delay {
 } __packed;
 
 /******************** Get FW Config *******************/
+#define QNQ_MODE 0x400
 struct be_cmd_req_query_fw_cfg {
 	struct be_cmd_req_hdr hdr;
 	u32 rsvd[30];
@@ -744,5 +745,6 @@ extern int be_cmd_set_flow_control(struc
 			u32 tx_fc, u32 rx_fc);
 extern int be_cmd_get_flow_control(struct be_ctrl_info *ctrl,
 			u32 *tx_fc, u32 *rx_fc);
-extern int be_cmd_query_fw_cfg(struct be_ctrl_info *ctrl, u32 *port_num);
+extern int be_cmd_query_fw_cfg(struct be_ctrl_info *ctrl, u32 *port_num,
+			bool *qnq);
 extern void be_process_mcc(struct be_ctrl_info *ctrl);
diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c
index 45df8e2..59c2a86 100644
--- a/drivers/net/benet/be_main.c
+++ b/drivers/net/benet/be_main.c
@@ -747,9 +747,16 @@ static void be_rx_compl_process(struct b
 			struct be_eth_rx_compl *rxcp)
 {
 	struct sk_buff *skb;
-	u32 vtp, vid;
+	u32 vlanf, vid;
+	u8 qnq;
 
-	vtp = AMAP_GET_BITS(struct amap_eth_rx_compl, vtp, rxcp);
+	vlanf = AMAP_GET_BITS(struct amap_eth_rx_compl, vtp, rxcp);
+	qnq = AMAP_GET_BITS(struct amap_eth_rx_compl, qnq, rxcp);
+
+	/* In QnQ mode, if qnq is 0 it is a non-vlan packet
+	   irrespective of vlanf */
+	if (adapter->qnq && !qnq)
+		vlanf = 0;
 
 	skb = netdev_alloc_skb(adapter->netdev, BE_HDR_LEN + NET_IP_ALIGN);
 	if (!skb) {
@@ -772,7 +779,7 @@ static void be_rx_compl_process(struct b
 	skb->protocol = eth_type_trans(skb, adapter->netdev);
 	skb->dev = adapter->netdev;
 
-	if (vtp) {
+	if (vlanf) {
 		if (!adapter->vlan_grp || adapter->num_vlans == 0) {
 			kfree_skb(skb);
 			return;
@@ -799,11 +806,18 @@ static void be_rx_compl_process_gro(stru
 	struct be_eq_obj *eq_obj =  &adapter->rx_eq;
 	u32 num_rcvd, pkt_size, remaining, vlanf, curr_frag_len;
 	u16 i, rxq_idx = 0, vid, j;
+	u8 qnq;
 
 	num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl, numfrags, rxcp);
 	pkt_size = AMAP_GET_BITS(struct amap_eth_rx_compl, pktsize, rxcp);
 	vlanf = AMAP_GET_BITS(struct amap_eth_rx_compl, vtp, rxcp);
 	rxq_idx = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx, rxcp);
+	qnq = AMAP_GET_BITS(struct amap_eth_rx_compl, qnq, rxcp);
+
+	/* In QnQ mode, if qnq is 0 it is a non-vlan packet
+	   irrespective of vlanf */
+	if (adapter->qnq && !qnq)
+		vlanf = 0;
 
 	skb = napi_get_frags(&eq_obj->napi);
 	if (!skb) {
@@ -1851,7 +1865,7 @@ static int be_hw_up(struct be_adapter *a
 	if (status)
 		return status;
 
-	status = be_cmd_query_fw_cfg(ctrl, &adapter->port_num);
+	status = be_cmd_query_fw_cfg(ctrl, &adapter->port_num, &adapter->qnq);
 	return status;
 }
 
-- 
1.4.0


^ permalink raw reply related

* [PATCH 10/13] mISDN: Add support for Traverse Technologies NETJet PCI cards
From: Karsten Keil @ 2009-07-23  8:03 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA, David Miller,
	i4ldeveloper-JX7+OpRa80SjiSfgN6Y1Ib39b6g2fGNp
In-Reply-To: <cover.1248546896.git.keil-shG/GajIFYqbacvFa/9K2g@public.gmane.org>

Add support for cards based on the Tiger 300 and Tiger 320
ISDN PCI chip.
Currently only the ISAC ISDN line interface is supported.

Signed-off-by: Karsten Keil <keil-shG/GajIFYqbacvFa/9K2g@public.gmane.org>
---
 drivers/isdn/hardware/mISDN/Kconfig  |    9 +
 drivers/isdn/hardware/mISDN/Makefile |    1 +
 drivers/isdn/hardware/mISDN/netjet.c | 1156 ++++++++++++++++++++++++++++++++++
 drivers/isdn/hardware/mISDN/netjet.h |   58 ++
 4 files changed, 1224 insertions(+), 0 deletions(-)
 create mode 100644 drivers/isdn/hardware/mISDN/netjet.c
 create mode 100644 drivers/isdn/hardware/mISDN/netjet.h

diff --git a/drivers/isdn/hardware/mISDN/Kconfig b/drivers/isdn/hardware/mISDN/Kconfig
index d72586e..bde55d7 100644
--- a/drivers/isdn/hardware/mISDN/Kconfig
+++ b/drivers/isdn/hardware/mISDN/Kconfig
@@ -72,6 +72,15 @@ config MISDN_W6692
 	help
 	  Enable support for Winbond 6692 PCI chip based cards.
 
+config MISDN_NETJET
+	tristate "Support for NETJet cards"
+	depends on MISDN
+	depends on PCI
+	select MISDN_IPAC
+	select ISDN_HDLC
+	help
+	  Enable support for Traverse Technologies NETJet PCI cards.
+
 
 config MISDN_IPAC
 	tristate
diff --git a/drivers/isdn/hardware/mISDN/Makefile b/drivers/isdn/hardware/mISDN/Makefile
index 61dd5a5..2987d99 100644
--- a/drivers/isdn/hardware/mISDN/Makefile
+++ b/drivers/isdn/hardware/mISDN/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_MISDN_AVMFRITZ) += avmfritz.o
 obj-$(CONFIG_MISDN_SPEEDFAX) += speedfax.o
 obj-$(CONFIG_MISDN_INFINEON) += mISDNinfineon.o
 obj-$(CONFIG_MISDN_W6692) += w6692.o
+obj-$(CONFIG_MISDN_NETJET) += netjet.o
 # chip modules
 obj-$(CONFIG_MISDN_IPAC) += mISDNipac.o
 obj-$(CONFIG_MISDN_ISAR) += mISDNisar.o
diff --git a/drivers/isdn/hardware/mISDN/netjet.c b/drivers/isdn/hardware/mISDN/netjet.c
new file mode 100644
index 0000000..6c1b164
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/netjet.c
@@ -0,0 +1,1156 @@
+/*
+ * NETJet mISDN driver
+ *
+ * Author       Karsten Keil <keil-4YnUg6GLQKNUnpShzZ3juw@public.gmane.org>
+ *
+ * Copyright 2009  by Karsten Keil <keil-4YnUg6GLQKNUnpShzZ3juw@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/mISDNhw.h>
+#include "ipac.h"
+#include "iohelper.h"
+#include "netjet.h"
+#include <linux/isdn/hdlc.h>
+
+#define NETJET_REV	"2.0"
+
+enum nj_types {
+	NETJET_S_TJ300,
+	NETJET_S_TJ320,
+	ENTERNOW__TJ320,
+};
+
+struct tiger_dma {
+	size_t		size;
+	u32		*start;
+	int		idx;
+	u32		dmastart;
+	u32		dmairq;
+	u32		dmaend;
+	u32		dmacur;
+};
+
+struct tiger_hw;
+
+struct tiger_ch {
+	struct bchannel		bch;
+	struct tiger_hw		*nj;
+	int			idx;
+	int			free;
+	int			lastrx;
+	u16			rxstate;
+	u16			txstate;
+	struct isdnhdlc_vars	hsend;
+	struct isdnhdlc_vars	hrecv;
+	u8			*hsbuf;
+	u8			*hrbuf;
+};
+
+#define TX_INIT		0x0001
+#define TX_IDLE		0x0002
+#define TX_RUN		0x0004
+#define TX_UNDERRUN	0x0100
+#define RX_OVERRUN	0x0100
+
+#define LOG_SIZE	64
+
+struct tiger_hw {
+	struct list_head	list;
+	struct pci_dev		*pdev;
+	char			name[MISDN_MAX_IDLEN];
+	enum nj_types		typ;
+	int			irq;
+	u32			irqcnt;
+	u32			base;
+	size_t			base_s;
+	dma_addr_t		dma;
+	void			*dma_p;
+	spinlock_t		lock;	/* lock HW */
+	struct isac_hw		isac;
+	struct tiger_dma	send;
+	struct tiger_dma	recv;
+	struct tiger_ch		bc[2];
+	u8			ctrlreg;
+	u8			dmactrl;
+	u8			auxd;
+	u8			last_is0;
+	u8			irqmask0;
+	char			log[LOG_SIZE];
+};
+
+static LIST_HEAD(Cards);
+static DEFINE_RWLOCK(card_lock); /* protect Cards */
+static u32 debug;
+static int nj_cnt;
+
+static void
+_set_debug(struct tiger_hw *card)
+{
+	card->isac.dch.debug = debug;
+	card->bc[0].bch.debug = debug;
+	card->bc[1].bch.debug = debug;
+}
+
+static int
+set_debug(const char *val, struct kernel_param *kp)
+{
+	int ret;
+	struct tiger_hw *card;
+
+	ret = param_set_uint(val, kp);
+	if (!ret) {
+		read_lock(&card_lock);
+		list_for_each_entry(card, &Cards, list)
+			_set_debug(card);
+		read_unlock(&card_lock);
+	}
+	return ret;
+}
+
+MODULE_AUTHOR("Karsten Keil");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(NETJET_REV);
+module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Netjet debug mask");
+
+static void
+nj_disable_hwirq(struct tiger_hw *card)
+{
+	outb(0, card->base + NJ_IRQMASK0);
+	outb(0, card->base + NJ_IRQMASK1);
+}
+
+
+static u8
+ReadISAC_nj(void *p, u8 offset)
+{
+	struct tiger_hw *card = p;
+	u8 ret;
+
+	card->auxd &= 0xfc;
+	card->auxd |= (offset >> 4) & 3;
+	outb(card->auxd, card->base + NJ_AUXDATA);
+	ret = inb(card->base + NJ_ISAC_OFF + ((offset & 0x0f) << 2));
+	return ret;
+}
+
+static void
+WriteISAC_nj(void *p, u8 offset, u8 value)
+{
+	struct tiger_hw *card = p;
+
+	card->auxd &= 0xfc;
+	card->auxd |= (offset >> 4) & 3;
+	outb(card->auxd, card->base + NJ_AUXDATA);
+	outb(value, card->base + NJ_ISAC_OFF + ((offset & 0x0f) << 2));
+}
+
+static void
+ReadFiFoISAC_nj(void *p, u8 offset, u8 *data, int size)
+{
+	struct tiger_hw *card = p;
+
+	card->auxd &= 0xfc;
+	outb(card->auxd, card->base + NJ_AUXDATA);
+	insb(card->base + NJ_ISAC_OFF, data, size);
+}
+
+static void
+WriteFiFoISAC_nj(void *p, u8 offset, u8 *data, int size)
+{
+	struct tiger_hw *card = p;
+
+	card->auxd &= 0xfc;
+	outb(card->auxd, card->base + NJ_AUXDATA);
+	outsb(card->base + NJ_ISAC_OFF, data, size);
+}
+
+static void
+fill_mem(struct tiger_ch *bc, u32 idx, u32 cnt, u32 fill)
+{
+	struct tiger_hw *card = bc->bch.hw;
+	u32 mask = 0xff, val;
+
+	pr_debug("%s: B%1d fill %02x len %d idx %d/%d\n", card->name,
+		bc->bch.nr, fill, cnt, idx, card->send.idx);
+	if (bc->bch.nr & 2) {
+		fill  <<= 8;
+		mask <<= 8;
+	}
+	mask ^= 0xffffffff;
+	while (cnt--) {
+		val = card->send.start[idx];
+		val &= mask;
+		val |= fill;
+		card->send.start[idx++] = val;
+		if (idx >= card->send.size)
+			idx = 0;
+	}
+}
+
+static int
+mode_tiger(struct tiger_ch *bc, u32 protocol)
+{
+	struct tiger_hw *card = bc->bch.hw;
+
+	pr_debug("%s: B%1d protocol %x-->%x\n", card->name,
+		bc->bch.nr, bc->bch.state, protocol);
+	switch (protocol) {
+	case ISDN_P_NONE:
+		if (bc->bch.state == ISDN_P_NONE)
+			break;
+		fill_mem(bc, 0, card->send.size, 0xff);
+		bc->bch.state = protocol;
+		/* only stop dma and interrupts if both channels NULL */
+		if ((card->bc[0].bch.state == ISDN_P_NONE) &&
+		    (card->bc[1].bch.state == ISDN_P_NONE)) {
+			card->dmactrl = 0;
+			outb(card->dmactrl, card->base + NJ_DMACTRL);
+			outb(0, card->base + NJ_IRQMASK0);
+		}
+		test_and_clear_bit(FLG_HDLC, &bc->bch.Flags);
+		test_and_clear_bit(FLG_TRANSPARENT, &bc->bch.Flags);
+		bc->txstate = 0;
+		bc->rxstate = 0;
+		bc->lastrx = -1;
+		break;
+	case ISDN_P_B_RAW:
+		test_and_set_bit(FLG_TRANSPARENT, &bc->bch.Flags);
+		bc->bch.state = protocol;
+		bc->idx = 0;
+		bc->free = card->send.size/2;
+		bc->rxstate = 0;
+		bc->txstate = TX_INIT | TX_IDLE;
+		bc->lastrx = -1;
+		if (!card->dmactrl) {
+			card->dmactrl = 1;
+			outb(card->dmactrl, card->base + NJ_DMACTRL);
+			outb(0x0f, card->base + NJ_IRQMASK0);
+		}
+		break;
+	case ISDN_P_B_HDLC:
+		test_and_set_bit(FLG_HDLC, &bc->bch.Flags);
+		bc->bch.state = protocol;
+		bc->idx = 0;
+		bc->free = card->send.size/2;
+		bc->rxstate = 0;
+		bc->txstate = TX_INIT | TX_IDLE;
+		isdnhdlc_rcv_init(&bc->hrecv, 0);
+		isdnhdlc_out_init(&bc->hsend, 0);
+		bc->lastrx = -1;
+		if (!card->dmactrl) {
+			card->dmactrl = 1;
+			outb(card->dmactrl, card->base + NJ_DMACTRL);
+			outb(0x0f, card->base + NJ_IRQMASK0);
+		}
+		break;
+	default:
+		pr_info("%s: %s protocol %x not handled\n", card->name,
+			__func__, protocol);
+		return -ENOPROTOOPT;
+	}
+	card->send.dmacur = inl(card->base + NJ_DMA_READ_ADR);
+	card->recv.dmacur = inl(card->base + NJ_DMA_WRITE_ADR);
+	card->send.idx = (card->send.dmacur - card->send.dmastart) >> 2;
+	card->recv.idx = (card->recv.dmacur - card->recv.dmastart) >> 2;
+	pr_debug("%s: %s ctrl %x irq  %02x/%02x idx %d/%d\n",
+		card->name, __func__,
+		inb(card->base + NJ_DMACTRL),
+		inb(card->base + NJ_IRQMASK0),
+		inb(card->base + NJ_IRQSTAT0),
+		card->send.idx,
+		card->recv.idx);
+	return 0;
+}
+
+static void
+nj_reset(struct tiger_hw *card)
+{
+	outb(0xff, card->base + NJ_CTRL); /* Reset On */
+	mdelay(1);
+
+	/* now edge triggered for TJ320 GE 13/07/00 */
+	/* see comment in IRQ function */
+	if (card->typ == NETJET_S_TJ320) /* TJ320 */
+		card->ctrlreg = 0x40;  /* Reset Off and status read clear */
+	else
+		card->ctrlreg = 0x00;  /* Reset Off and status read clear */
+	outb(card->ctrlreg, card->base + NJ_CTRL);
+	mdelay(10);
+
+	/* configure AUX pins (all output except ISAC IRQ pin) */
+	card->auxd = 0;
+	card->dmactrl = 0;
+	outb(~NJ_ISACIRQ, card->base + NJ_AUXCTRL);
+	outb(NJ_ISACIRQ,  card->base + NJ_IRQMASK1);
+	outb(card->auxd, card->base + NJ_AUXDATA);
+}
+
+static int
+inittiger(struct tiger_hw *card)
+{
+	int i;
+
+	card->dma_p = pci_alloc_consistent(card->pdev, NJ_DMA_SIZE,
+			&card->dma);
+	if (!card->dma_p) {
+		pr_info("%s: No DMA memory\n", card->name);
+		return -ENOMEM;
+	}
+	if ((u64)card->dma > 0xffffffff) {
+		pr_info("%s: DMA outside 32 bit\n", card->name);
+		return -ENOMEM;
+	}
+	for (i = 0; i < 2; i++) {
+		card->bc[i].hsbuf = kmalloc(NJ_DMA_TXSIZE, GFP_KERNEL);
+		if (!card->bc[i].hsbuf) {
+			pr_info("%s: no B%d send buffer\n", card->name, i + 1);
+			return -ENOMEM;
+		}
+		card->bc[i].hrbuf = kmalloc(NJ_DMA_RXSIZE, GFP_KERNEL);
+		if (!card->bc[i].hrbuf) {
+			pr_info("%s: no B%d recv buffer\n", card->name, i + 1);
+			return -ENOMEM;
+		}
+	}
+	memset(card->dma_p, 0xff, NJ_DMA_SIZE);
+
+	card->send.start = card->dma_p;
+	card->send.dmastart = (u32)card->dma;
+	card->send.dmaend = card->send.dmastart +
+		(4 * (NJ_DMA_TXSIZE - 1));
+	card->send.dmairq = card->send.dmastart +
+		(4 * ((NJ_DMA_TXSIZE / 2) - 1));
+	card->send.size = NJ_DMA_TXSIZE;
+
+	if (debug & DEBUG_HW)
+		pr_notice("%s: send buffer phy %#x - %#x - %#x  virt %p"
+			" size %zu u32\n", card->name,
+			card->send.dmastart, card->send.dmairq,
+			card->send.dmaend, card->send.start, card->send.size);
+
+	outl(card->send.dmastart, card->base + NJ_DMA_READ_START);
+	outl(card->send.dmairq, card->base + NJ_DMA_READ_IRQ);
+	outl(card->send.dmaend, card->base + NJ_DMA_READ_END);
+
+	card->recv.start = card->dma_p + (NJ_DMA_SIZE / 2);
+	card->recv.dmastart = (u32)card->dma  + (NJ_DMA_SIZE / 2);
+	card->recv.dmaend = card->recv.dmastart +
+		(4 * (NJ_DMA_RXSIZE - 1));
+	card->recv.dmairq = card->recv.dmastart +
+		(4 * ((NJ_DMA_RXSIZE / 2) - 1));
+	card->recv.size = NJ_DMA_RXSIZE;
+
+	if (debug & DEBUG_HW)
+		pr_notice("%s: recv buffer phy %#x - %#x - %#x  virt %p"
+			" size %zu u32\n", card->name,
+			card->recv.dmastart, card->recv.dmairq,
+			card->recv.dmaend, card->recv.start, card->recv.size);
+
+	outl(card->recv.dmastart, card->base + NJ_DMA_WRITE_START);
+	outl(card->recv.dmairq, card->base + NJ_DMA_WRITE_IRQ);
+	outl(card->recv.dmaend, card->base + NJ_DMA_WRITE_END);
+	return 0;
+}
+
+static void
+read_dma(struct tiger_ch *bc, u32 idx, int cnt)
+{
+	struct tiger_hw *card = bc->bch.hw;
+	int i, stat;
+	u32 val;
+	u8 *p, *pn;
+
+	if (bc->lastrx == idx) {
+		bc->rxstate |= RX_OVERRUN;
+		pr_info("%s: B%1d overrun at idx %d\n", card->name,
+			bc->bch.nr, idx);
+	}
+	bc->lastrx = idx;
+	if (!bc->bch.rx_skb) {
+		bc->bch.rx_skb = mI_alloc_skb(bc->bch.maxlen, GFP_ATOMIC);
+		if (!bc->bch.rx_skb) {
+			pr_info("%s: B%1d receive out of memory\n",
+				card->name, bc->bch.nr);
+			return;
+		}
+	}
+
+	if (test_bit(FLG_TRANSPARENT, &bc->bch.Flags)) {
+		if ((bc->bch.rx_skb->len + cnt) > bc->bch.maxlen) {
+			pr_debug("%s: B%1d overrun %d\n", card->name,
+				bc->bch.nr, bc->bch.rx_skb->len + cnt);
+			skb_trim(bc->bch.rx_skb, 0);
+			return;
+		}
+		p = skb_put(bc->bch.rx_skb, cnt);
+	} else
+		p = bc->hrbuf;
+
+	for (i = 0; i < cnt; i++) {
+		val = card->recv.start[idx++];
+		if (bc->bch.nr & 2)
+			val >>= 8;
+		if (idx >= card->recv.size)
+			idx = 0;
+		p[i] = val & 0xff;
+	}
+	pn = bc->hrbuf;
+next_frame:
+	if (test_bit(FLG_HDLC, &bc->bch.Flags)) {
+		stat = isdnhdlc_decode(&bc->hrecv, pn, cnt, &i,
+			bc->bch.rx_skb->data, bc->bch.maxlen);
+		if (stat > 0) /* valid frame received */ 
+			p = skb_put(bc->bch.rx_skb, stat);
+		else if (stat == -HDLC_CRC_ERROR)
+			pr_info("%s: B%1d receive frame CRC error\n",
+				card->name, bc->bch.nr);
+		else if (stat == -HDLC_FRAMING_ERROR)
+			pr_info("%s: B%1d receive framing error\n",
+				card->name, bc->bch.nr);
+		else if (stat == -HDLC_LENGTH_ERROR)
+			pr_info("%s: B%1d receive frame too long (> %d)\n",
+				card->name, bc->bch.nr, bc->bch.maxlen);
+	} else
+		stat = cnt;	
+
+	if (stat > 0) {
+		if (debug & DEBUG_HW_BFIFO) {
+			snprintf(card->log, LOG_SIZE, "B%1d-recv %s %d ",
+				bc->bch.nr, card->name, stat);
+			print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET,
+				p, stat);
+		}
+		recv_Bchannel(&bc->bch, 0);
+	}
+	if (test_bit(FLG_HDLC, &bc->bch.Flags)) {
+		pn += i;
+		cnt -= i;
+		if (!bc->bch.rx_skb) {
+			bc->bch.rx_skb = mI_alloc_skb(bc->bch.maxlen,
+				GFP_ATOMIC);
+			if (!bc->bch.rx_skb) {
+				pr_info("%s: B%1d receive out of memory\n",
+					card->name, bc->bch.nr);
+				return;
+			}
+		}
+		if (cnt > 0)
+			goto next_frame;
+	}
+}
+
+static void
+recv_tiger(struct tiger_hw *card, u8 irq_stat)
+{
+	u32 idx;
+	int cnt = card->recv.size / 2;
+
+	/* Note receive is via the WRITE DMA channel */
+	card->last_is0 &= ~NJ_IRQM0_WR_MASK;
+	card->last_is0 |= (irq_stat & NJ_IRQM0_WR_MASK);
+
+	if (irq_stat & NJ_IRQM0_WR_END)
+		idx = cnt - 1;
+	else
+		idx = card->recv.size - 1;
+
+	if (test_bit(FLG_ACTIVE, &card->bc[0].bch.Flags))
+		read_dma(&card->bc[0], idx, cnt);
+	if (test_bit(FLG_ACTIVE, &card->bc[1].bch.Flags))
+		read_dma(&card->bc[1], idx, cnt);
+}
+
+/* sync with current DMA address at start or after exception */
+static void
+resync(struct tiger_ch *bc, struct tiger_hw *card)
+{
+	card->send.dmacur = inl(card->base | NJ_DMA_READ_ADR);
+	card->send.idx = (card->send.dmacur - card->send.dmastart) >> 2;
+	if (bc->free > card->send.size / 2)
+		bc->free = card->send.size / 2;
+	/* currently we simple sync to the next complete free area
+	 * this hast the advantage that we have always maximum time to
+	 * handle TX irq
+	 */
+	if (card->send.idx < ((card->send.size / 2) - 1))
+		bc->idx = (card->recv.size / 2) - 1;
+	else
+		bc->idx = card->recv.size - 1;
+	bc->txstate = TX_RUN;
+	pr_debug("%s: %s B%1d free %d idx %d/%d\n", card->name,
+		__func__, bc->bch.nr, bc->free, bc->idx, card->send.idx);
+}
+
+static int bc_next_frame(struct tiger_ch *);
+
+static void
+fill_hdlc_flag(struct tiger_ch *bc)
+{
+	struct tiger_hw *card = bc->bch.hw;
+	int count, i;
+	u32 m, v;
+	u8  *p;
+
+	if (bc->free == 0)
+		return;
+	pr_debug("%s: %s B%1d %d state %x idx %d/%d\n", card->name,
+		__func__, bc->bch.nr, bc->free, bc->txstate,
+		bc->idx, card->send.idx);
+	if (bc->txstate & (TX_IDLE | TX_INIT | TX_UNDERRUN))
+		resync(bc, card);
+	count = isdnhdlc_encode(&bc->hsend, NULL, 0, &i,
+			bc->hsbuf, bc->free);
+	pr_debug("%s: B%1d hdlc encoded %d flags\n", card->name,
+			bc->bch.nr, count);
+	bc->free -= count;
+	p = bc->hsbuf;
+	m = (bc->bch.nr & 1) ? 0xffffff00 : 0xffff00ff;
+	for (i = 0; i < count; i++) {
+		if (bc->idx >= card->send.size)
+			bc->idx = 0;
+		v = card->send.start[bc->idx];
+		v &= m;
+		v |= (bc->bch.nr & 1) ? (u32)(p[i]) : ((u32)(p[i])) << 8;
+		card->send.start[bc->idx++] = v;
+	}
+	if (debug & DEBUG_HW_BFIFO) {
+		snprintf(card->log, LOG_SIZE, "B%1d-send %s %d ",
+			bc->bch.nr, card->name, count);
+		print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, p, count);
+	}
+}
+
+static void
+fill_dma(struct tiger_ch *bc)
+{
+	struct tiger_hw *card = bc->bch.hw;
+	int count, i;
+	u32 m, v;
+	u8  *p;
+
+	if (bc->free == 0)
+		return;
+	count = bc->bch.tx_skb->len - bc->bch.tx_idx;
+	if (count <= 0)
+		return;
+	pr_debug("%s: %s B%1d %d/%d/%d/%d state %x idx %d/%d\n", card->name,
+		__func__, bc->bch.nr, count, bc->free, bc->bch.tx_idx,
+		bc->bch.tx_skb->len, bc->txstate, bc->idx, card->send.idx);
+	if (bc->txstate & (TX_IDLE | TX_INIT | TX_UNDERRUN))
+		resync(bc, card);
+	p = bc->bch.tx_skb->data + bc->bch.tx_idx;
+	if (test_bit(FLG_HDLC, &bc->bch.Flags)) {
+		count = isdnhdlc_encode(&bc->hsend, p, count, &i,
+			bc->hsbuf, bc->free);
+		pr_debug("%s: B%1d hdlc encoded %d in %d\n", card->name,
+			bc->bch.nr, i, count);
+		bc->bch.tx_idx += i;
+		bc->free -= count;
+		p = bc->hsbuf;
+	} else {
+		if (count > bc->free)
+			count = bc->free;
+		bc->bch.tx_idx += count;
+		bc->free -= count;
+	}
+	m = (bc->bch.nr & 1) ? 0xffffff00 : 0xffff00ff;
+	for (i = 0; i < count; i++) {
+		if (bc->idx >= card->send.size)
+			bc->idx = 0;
+		v = card->send.start[bc->idx];
+		v &= m;
+		v |= (bc->bch.nr & 1) ? (u32)(p[i]) : ((u32)(p[i])) << 8;
+		card->send.start[bc->idx++] = v;
+	}
+	if (debug & DEBUG_HW_BFIFO) {
+		snprintf(card->log, LOG_SIZE, "B%1d-send %s %d ",
+			bc->bch.nr, card->name, count);
+		print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, p, count);
+	}
+	if (bc->free)
+		bc_next_frame(bc);
+}
+
+
+static int
+bc_next_frame(struct tiger_ch *bc)
+{
+	if (bc->bch.tx_skb && bc->bch.tx_idx < bc->bch.tx_skb->len)
+		fill_dma(bc);
+	else {
+		if (bc->bch.tx_skb) {
+			/* send confirm, on trans, free on hdlc. */
+			if (test_bit(FLG_TRANSPARENT, &bc->bch.Flags))
+				confirm_Bsend(&bc->bch);
+			dev_kfree_skb(bc->bch.tx_skb);
+		}
+		if (get_next_bframe(&bc->bch))
+			fill_dma(bc);
+		else
+			return 0;
+	}
+	return 1;
+}
+
+static void
+send_tiger_bc(struct tiger_hw *card, struct tiger_ch *bc)
+{
+	int ret;
+
+	bc->free += card->send.size / 2;
+	if (bc->free >= card->send.size) {
+		if (!(bc->txstate & (TX_UNDERRUN | TX_INIT))) {
+			pr_info("%s: B%1d TX underrun state %x\n", card->name,
+				bc->bch.nr, bc->txstate);
+			bc->txstate |= TX_UNDERRUN;
+		}
+		bc->free = card->send.size;
+	}
+	ret = bc_next_frame(bc);
+	if (!ret) {
+		if (test_bit(FLG_HDLC, &bc->bch.Flags)) {
+			fill_hdlc_flag(bc);
+			return;
+		}
+		pr_debug("%s: B%1d TX no data free %d idx %d/%d\n", card->name,
+			bc->bch.nr, bc->free, bc->idx, card->send.idx);
+		if (!(bc->txstate & (TX_IDLE | TX_INIT))) {
+			fill_mem(bc, bc->idx, bc->free, 0xff);
+			if (bc->free == card->send.size)
+				bc->txstate |= TX_IDLE;
+		}
+	}
+}
+
+static void
+send_tiger(struct tiger_hw *card, u8 irq_stat)
+{
+	int i;
+
+	/* Note send is via the READ DMA channel */
+	if ((irq_stat & card->last_is0) & NJ_IRQM0_RD_MASK) {
+		pr_info("%s: tiger warn write double dma %x/%x\n",
+			card->name, irq_stat, card->last_is0);
+		return;
+	} else {
+		card->last_is0 &= ~NJ_IRQM0_RD_MASK;
+		card->last_is0 |= (irq_stat & NJ_IRQM0_RD_MASK);
+	}
+	for (i = 0; i < 2; i++) {
+		if (test_bit(FLG_ACTIVE, &card->bc[i].bch.Flags))
+			send_tiger_bc(card, &card->bc[i]);
+	}
+}
+
+static irqreturn_t
+nj_irq(int intno, void *dev_id)
+{
+	struct tiger_hw *card = dev_id;
+	u8 val, s1val, s0val;
+
+	spin_lock(&card->lock);
+	s0val = inb(card->base | NJ_IRQSTAT0);
+	s1val = inb(card->base | NJ_IRQSTAT1);
+	if ((s1val & NJ_ISACIRQ) && (s0val == 0)) {
+		/* shared IRQ */
+		spin_unlock(&card->lock);
+		return IRQ_NONE;
+	}
+	pr_debug("%s: IRQSTAT0 %02x IRQSTAT1 %02x\n", card->name, s0val, s1val);
+	card->irqcnt++;
+	if (!(s1val & NJ_ISACIRQ)) {
+		val = ReadISAC_nj(card, ISAC_ISTA);
+		if (val)
+			mISDNisac_irq(&card->isac, val);
+	}
+
+	if (s0val)
+		/* write to clear */
+		outb(s0val, card->base | NJ_IRQSTAT0);
+	else
+		goto end;
+	s1val = s0val;
+	/* set bits in sval to indicate which page is free */
+	card->recv.dmacur = inl(card->base | NJ_DMA_WRITE_ADR);
+	card->recv.idx = (card->recv.dmacur - card->recv.dmastart) >> 2;
+	if (card->recv.dmacur < card->recv.dmairq)
+		s0val = 0x08;	/* the 2nd write area is free */
+	else
+		s0val = 0x04;	/* the 1st write area is free */
+
+	card->send.dmacur = inl(card->base | NJ_DMA_READ_ADR);
+	card->send.idx = (card->send.dmacur - card->send.dmastart) >> 2;
+	if (card->send.dmacur < card->send.dmairq)
+		s0val |= 0x02;	/* the 2nd read area is free */
+	else
+		s0val |= 0x01;	/* the 1st read area is free */
+
+	pr_debug("%s: DMA Status %02x/%02x/%02x %d/%d\n", card->name,
+		s1val, s0val, card->last_is0,
+		card->recv.idx, card->send.idx);
+	/* test if we have a DMA interrupt */
+	if (s0val != card->last_is0) {
+		if ((s0val & NJ_IRQM0_RD_MASK) !=
+		    (card->last_is0 & NJ_IRQM0_RD_MASK))
+			/* got a write dma int */
+			send_tiger(card, s0val);
+		if ((s0val & NJ_IRQM0_WR_MASK) !=
+		    (card->last_is0 & NJ_IRQM0_WR_MASK))
+			/* got a read dma int */
+			recv_tiger(card, s0val);
+	}
+end:
+	spin_unlock(&card->lock);
+	return IRQ_HANDLED;
+}
+
+static int
+nj_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb)
+{
+	int ret = -EINVAL;
+	struct bchannel *bch = container_of(ch, struct bchannel, ch);
+	struct tiger_ch *bc = container_of(bch, struct tiger_ch, bch);
+	struct tiger_hw *card = bch->hw;
+	struct mISDNhead *hh = mISDN_HEAD_P(skb);
+	u32 id;
+	u_long flags;
+
+	switch (hh->prim) {
+	case PH_DATA_REQ:
+		spin_lock_irqsave(&card->lock, flags);
+		ret = bchannel_senddata(bch, skb);
+		if (ret > 0) { /* direct TX */
+			id = hh->id; /* skb can be freed */
+			fill_dma(bc);
+			ret = 0;
+			spin_unlock_irqrestore(&card->lock, flags);
+			if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
+				queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
+		} else
+			spin_unlock_irqrestore(&card->lock, flags);
+		return ret;
+	case PH_ACTIVATE_REQ:
+		spin_lock_irqsave(&card->lock, flags);
+		if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags))
+			ret = mode_tiger(bc, ch->protocol);
+		else
+			ret = 0;
+		spin_unlock_irqrestore(&card->lock, flags);
+		if (!ret)
+			_queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0,
+				NULL, GFP_KERNEL);
+		break;
+	case PH_DEACTIVATE_REQ:
+		spin_lock_irqsave(&card->lock, flags);
+		mISDN_clear_bchannel(bch);
+		mode_tiger(bc, ISDN_P_NONE);
+		spin_unlock_irqrestore(&card->lock, flags);
+		_queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0,
+			NULL, GFP_KERNEL);
+		ret = 0;
+		break;
+	}
+	if (!ret)
+		dev_kfree_skb(skb);
+	return ret;
+}
+
+static int
+channel_bctrl(struct tiger_ch *bc, struct mISDN_ctrl_req *cq)
+{
+	int ret = 0;
+	struct tiger_hw *card  = bc->bch.hw;
+
+	switch (cq->op) {
+	case MISDN_CTRL_GETOP:
+		cq->op = 0;
+		break;
+	/* Nothing implemented yet */
+	case MISDN_CTRL_FILL_EMPTY:
+	default:
+		pr_info("%s: %s unknown Op %x\n", card->name, __func__, cq->op);
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static int
+nj_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
+{
+	struct bchannel *bch = container_of(ch, struct bchannel, ch);
+	struct tiger_ch *bc = container_of(bch, struct tiger_ch, bch);
+	struct tiger_hw *card  = bch->hw;
+	int ret = -EINVAL;
+	u_long flags;
+
+	pr_debug("%s: %s cmd:%x %p\n", card->name, __func__, cmd, arg);
+	switch (cmd) {
+	case CLOSE_CHANNEL:
+		test_and_clear_bit(FLG_OPEN, &bch->Flags);
+		if (test_bit(FLG_ACTIVE, &bch->Flags)) {
+			spin_lock_irqsave(&card->lock, flags);
+			mISDN_freebchannel(bch);
+			test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
+			test_and_clear_bit(FLG_ACTIVE, &bch->Flags);
+			mode_tiger(bc, ISDN_P_NONE);
+			spin_unlock_irqrestore(&card->lock, flags);
+		}
+		ch->protocol = ISDN_P_NONE;
+		ch->peer = NULL;
+		module_put(THIS_MODULE);
+		ret = 0;
+		break;
+	case CONTROL_CHANNEL:
+		ret = channel_bctrl(bc, arg);
+		break;
+	default:
+		pr_info("%s: %s unknown prim(%x)\n", card->name, __func__, cmd);
+	}
+	return ret;
+}
+
+static int
+channel_ctrl(struct tiger_hw *card, struct mISDN_ctrl_req *cq)
+{
+	int	ret = 0;
+
+	switch (cq->op) {
+	case MISDN_CTRL_GETOP:
+		cq->op = MISDN_CTRL_LOOP;
+		break;
+	case MISDN_CTRL_LOOP:
+		/* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */
+		if (cq->channel < 0 || cq->channel > 3) {
+			ret = -EINVAL;
+			break;
+		}
+		ret = card->isac.ctrl(&card->isac, HW_TESTLOOP, cq->channel);
+		break;
+	default:
+		pr_info("%s: %s unknown Op %x\n", card->name, __func__, cq->op);
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static int
+open_bchannel(struct tiger_hw *card, struct channel_req *rq)
+{
+	struct bchannel *bch;
+
+	if (rq->adr.channel > 2)
+		return -EINVAL;
+	if (rq->protocol == ISDN_P_NONE)
+		return -EINVAL;
+	bch = &card->bc[rq->adr.channel - 1].bch;
+	if (test_and_set_bit(FLG_OPEN, &bch->Flags))
+		return -EBUSY; /* b-channel can be only open once */
+	test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags);
+	bch->ch.protocol = rq->protocol;
+	rq->ch = &bch->ch;
+	return 0;
+}
+
+/*
+ * device control function
+ */
+static int
+nj_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
+{
+	struct mISDNdevice	*dev = container_of(ch, struct mISDNdevice, D);
+	struct dchannel		*dch = container_of(dev, struct dchannel, dev);
+	struct tiger_hw	*card = dch->hw;
+	struct channel_req	*rq;
+	int			err = 0;
+
+	pr_debug("%s: %s cmd:%x %p\n", card->name, __func__, cmd, arg);
+	switch (cmd) {
+	case OPEN_CHANNEL:
+		rq = arg;
+		if (rq->protocol == ISDN_P_TE_S0)
+			err = card->isac.open(&card->isac, rq);
+		else
+			err = open_bchannel(card, rq);
+		if (err)
+			break;
+		if (!try_module_get(THIS_MODULE))
+			pr_info("%s: cannot get module\n", card->name);
+		break;
+	case CLOSE_CHANNEL:
+		pr_debug("%s: dev(%d) close from %p\n", card->name, dch->dev.id,
+			__builtin_return_address(0));
+		module_put(THIS_MODULE);
+		break;
+	case CONTROL_CHANNEL:
+		err = channel_ctrl(card, arg);
+		break;
+	default:
+		pr_debug("%s: %s unknown command %x\n",
+			card->name, __func__, cmd);
+		return -EINVAL;
+	}
+	return err;
+}
+
+static int
+nj_init_card(struct tiger_hw *card)
+{
+	u_long flags;
+	int ret;
+
+	spin_lock_irqsave(&card->lock, flags);
+	nj_disable_hwirq(card);
+	spin_unlock_irqrestore(&card->lock, flags);
+
+	card->irq = card->pdev->irq;
+	if (request_irq(card->irq, nj_irq, IRQF_SHARED, card->name, card)) {
+		pr_info("%s: couldn't get interrupt %d\n",
+			card->name, card->irq);
+		card->irq = -1;
+		return -EIO;
+	}
+
+	spin_lock_irqsave(&card->lock, flags);
+	nj_reset(card);
+	ret = card->isac.init(&card->isac);
+	if (ret)
+		goto error;
+	ret = inittiger(card);
+	if (ret)
+		goto error;
+	mode_tiger(&card->bc[0], ISDN_P_NONE);
+	mode_tiger(&card->bc[1], ISDN_P_NONE);
+error:
+	spin_unlock_irqrestore(&card->lock, flags);
+	return ret;
+}
+
+
+static void
+nj_release(struct tiger_hw *card)
+{
+	u_long flags;
+	int i;
+
+	if (card->base_s) {
+		spin_lock_irqsave(&card->lock, flags);
+		nj_disable_hwirq(card);
+		mode_tiger(&card->bc[0], ISDN_P_NONE);
+		mode_tiger(&card->bc[1], ISDN_P_NONE);
+		card->isac.release(&card->isac);
+		spin_unlock_irqrestore(&card->lock, flags);
+		release_region(card->base, card->base_s);
+		card->base_s = 0;
+	}
+	if (card->irq > 0)
+		free_irq(card->irq, card);
+	if (card->isac.dch.dev.dev.class)
+		mISDN_unregister_device(&card->isac.dch.dev);
+	
+	for (i = 0; i < 2; i++) {
+		mISDN_freebchannel(&card->bc[i].bch);
+		kfree(card->bc[i].hsbuf);
+		kfree(card->bc[i].hrbuf);
+	}
+	if (card->dma_p)
+		pci_free_consistent(card->pdev, NJ_DMA_SIZE,
+			card->dma_p, card->dma);
+	write_lock_irqsave(&card_lock, flags);
+	list_del(&card->list);
+	write_unlock_irqrestore(&card_lock, flags);
+	pci_clear_master(card->pdev);
+	pci_disable_device(card->pdev);
+	pci_set_drvdata(card->pdev, NULL);
+	kfree(card);
+}
+
+
+static int
+nj_setup(struct tiger_hw *card)
+{
+	card->base = pci_resource_start(card->pdev, 0);
+	card->base_s = pci_resource_len(card->pdev, 0);
+	if (!request_region(card->base, card->base_s, card->name)) {
+		pr_info("%s: NETjet config port %#x-%#x already in use\n",
+			card->name, card->base,
+			(u32)(card->base + card->base_s - 1));
+		card->base_s = 0;
+		return -EIO;
+	}
+	ASSIGN_FUNC(nj, ISAC, card->isac);
+	return 0;
+}
+
+
+static int __devinit
+setup_instance(struct tiger_hw *card)
+{
+	int i, err;
+	u_long flags;
+
+	snprintf(card->name, MISDN_MAX_IDLEN - 1, "netjet.%d", nj_cnt + 1);
+	write_lock_irqsave(&card_lock, flags);
+	list_add_tail(&card->list, &Cards);
+	write_unlock_irqrestore(&card_lock, flags);
+
+	_set_debug(card);
+	card->isac.name = card->name;
+	spin_lock_init(&card->lock);
+	card->isac.hwlock = &card->lock;
+	mISDNisac_init(&card->isac, card);
+
+	card->isac.dch.dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) |
+		(1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK));
+	card->isac.dch.dev.D.ctrl = nj_dctrl;
+	for (i = 0; i < 2; i++) {
+		card->bc[i].bch.nr = i + 1;
+		set_channelmap(i + 1, card->isac.dch.dev.channelmap);
+		mISDN_initbchannel(&card->bc[i].bch, MAX_DATA_MEM);
+		card->bc[i].bch.hw = card;
+		card->bc[i].bch.ch.send = nj_l2l1B;
+		card->bc[i].bch.ch.ctrl = nj_bctrl;
+		card->bc[i].bch.ch.nr = i + 1;
+		list_add(&card->bc[i].bch.ch.list,
+			&card->isac.dch.dev.bchannels);
+		card->bc[i].bch.hw = card;
+	}
+	err = nj_setup(card);
+	if (err)
+		goto error;
+	err = mISDN_register_device(&card->isac.dch.dev, &card->pdev->dev,
+		card->name);
+	if (err)
+		goto error;
+	err = nj_init_card(card);
+	if (!err)  {
+		nj_cnt++;
+		pr_notice("Netjet %d cards installed\n", nj_cnt);
+		return 0;
+	}
+error:
+	nj_release(card);
+	return err;
+}
+
+static int __devinit
+nj_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	int err = -ENOMEM;
+	int cfg;
+	struct tiger_hw *card;
+
+	if (pdev->subsystem_vendor == 0x8086 &&
+	    pdev->subsystem_device == 0x0003) {
+		pr_notice("Netjet: Digium X100P/X101P not handled\n");
+		return -ENODEV;
+	}
+
+	if (pdev->subsystem_vendor == 0x55 &&
+	    pdev->subsystem_device == 0x02) {
+		pr_notice("Netjet: Enter!Now not handled yet\n");
+		return -ENODEV;
+	}
+
+	card = kzalloc(sizeof(struct tiger_hw), GFP_ATOMIC);
+	if (!card) {
+		pr_info("No kmem for Netjet\n");
+		return err;
+	}
+
+	card->pdev = pdev;
+
+	err = pci_enable_device(pdev);
+	if (err) {
+		kfree(card);
+		return err;
+	}
+
+	printk(KERN_INFO "nj_probe(mISDN): found adapter at %s\n",
+		pci_name(pdev));
+
+	pci_set_master(pdev);
+
+	/* the TJ300 and TJ320 must be detected, the IRQ handling is different
+	 * unfortunately the chips use the same device ID, but the TJ320 has
+	 * the bit20 in status PCI cfg register set
+	 */
+	pci_read_config_dword(pdev, 0x04, &cfg);
+	if (cfg & 0x00100000)
+		card->typ = NETJET_S_TJ320;
+	else
+		card->typ = NETJET_S_TJ300;
+
+	card->base = pci_resource_start(pdev, 0);
+	card->irq = pdev->irq;
+	pci_set_drvdata(pdev, card);
+	err = setup_instance(card);
+	if (err)
+		pci_set_drvdata(pdev, NULL);
+
+	return err;
+}
+
+
+static void __devexit nj_remove(struct pci_dev *pdev)
+{
+	struct tiger_hw *card = pci_get_drvdata(pdev);
+
+	if (card)
+		nj_release(card);
+	else
+		pr_info("%s drvdata already removed\n", __func__);
+}
+
+/* We cannot select cards with PCI_SUB... IDs, since here are cards with
+ * SUB IDs set to PCI_ANY_ID, so we need to match all and reject
+ * known other cards which not work with this driver - see probe function */
+static struct pci_device_id nj_pci_ids[] __devinitdata = {
+	{ PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_300,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ }
+};
+MODULE_DEVICE_TABLE(pci, nj_pci_ids);
+
+static struct pci_driver nj_driver = {
+	.name = "netjet",
+	.probe = nj_probe,
+	.remove = __devexit_p(nj_remove),
+	.id_table = nj_pci_ids,
+};
+
+static int __init nj_init(void)
+{
+	int err;
+
+	pr_notice("Netjet PCI driver Rev. %s\n", NETJET_REV);
+	err = pci_register_driver(&nj_driver);
+	return err;
+}
+
+static void __exit nj_cleanup(void)
+{
+	pci_unregister_driver(&nj_driver);
+}
+
+module_init(nj_init);
+module_exit(nj_cleanup);
diff --git a/drivers/isdn/hardware/mISDN/netjet.h b/drivers/isdn/hardware/mISDN/netjet.h
new file mode 100644
index 0000000..d061ff9
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/netjet.h
@@ -0,0 +1,58 @@
+/*
+ * NETjet common header file
+ *
+ * Author	Karsten Keil
+ *              based on work of Matt Henderson and Daniel Potts,
+ *              Traverse Technologies P/L www.traverse.com.au
+ *
+ * Copyright 2009  by Karsten Keil <keil-4YnUg6GLQKNUnpShzZ3juw@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#define NJ_CTRL			0x00
+#define NJ_DMACTRL		0x01
+#define NJ_AUXCTRL		0x02
+#define NJ_AUXDATA		0x03
+#define NJ_IRQMASK0		0x04
+#define NJ_IRQMASK1		0x05
+#define NJ_IRQSTAT0		0x06
+#define NJ_IRQSTAT1		0x07
+#define NJ_DMA_READ_START	0x08
+#define NJ_DMA_READ_IRQ		0x0c
+#define NJ_DMA_READ_END		0x10
+#define NJ_DMA_READ_ADR		0x14
+#define NJ_DMA_WRITE_START	0x18
+#define NJ_DMA_WRITE_IRQ	0x1c
+#define NJ_DMA_WRITE_END	0x20
+#define NJ_DMA_WRITE_ADR	0x24
+#define NJ_PULSE_CNT		0x28
+
+#define NJ_ISAC_OFF		0xc0
+#define NJ_ISACIRQ		0x10
+
+#define NJ_IRQM0_RD_MASK	0x03
+#define NJ_IRQM0_RD_IRQ		0x01
+#define NJ_IRQM0_RD_END		0x02
+#define NJ_IRQM0_WR_MASK	0x0c
+#define NJ_IRQM0_WR_IRQ		0x04
+#define NJ_IRQM0_WR_END		0x08
+
+/* one page here is no need to be smaller */
+#define NJ_DMA_SIZE		4096
+/* 2 * 64 byte is a compromise between IRQ count and latency */
+#define NJ_DMA_RXSIZE		128  /* 2 * 64 */
+#define NJ_DMA_TXSIZE		128  /* 2 * 64 */
+
-- 
1.6.0.2

^ permalink raw reply related

* Your Webmail Quota Has Exceeded The Set Quota/Limit
From: MR PATRICK CHAN @ 2009-07-22 22:29 UTC (permalink / raw)


Your Webmail Quota Has Exceeded The Set Quota/Limit Which Is 20GB.
You  Are Currently Running On 23GB Due To Hidden Files And Folder On Your Mailbox.
Please Click the Link Below To Validate Your Mailbox And Increase Your Quota.

www.jotform.com/form/92023703919
Failure To Click This Link And Validate Your Quota May Result In Loss Of Important Information In Your Mailbox/Or Cause Limited Access To It.

^ permalink raw reply

* Re: [PATCH net-next-2.6] bonding: propogate vlan_features to bonding master
From: Or Gerlitz @ 2009-07-23  7:24 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: Jay Vosburgh, David Miller, netdev, Eilon Greenstein,
	Michael Chan
In-Reply-To: <4A67FD4C.4080407@cosmosbay.com>

Eric Dumazet wrote:
> Jay Vosburgh a écrit :
>> Propogate the vlan_features of the slave devices to the bonding master device, using the same logic as for regular features.
> Seems pretty cool, but I could not test it on my dev machine, since tg3 and bnx2 drivers dont advertize yet vlan_features
The bnx2x maintainer posted yesterday a patch that does so, I assume a 
similar patch could work for at least one of tg3 or bnx2. I copied both 
maintainers on this email, in  the hope they can come up with a patch.

Or.


^ permalink raw reply

* Re: [Bugme-new] [Bug 13760] New: 2.6.30 kernel locks up with pppoe in  back trace (regression)
From: Andrew Morton @ 2009-07-23  7:01 UTC (permalink / raw)
  To: Igor M Podlesny; +Cc: bugzilla-daemon, bugme-daemon, netdev
In-Reply-To: <43d009740907222339n50ebe411ya6453dc5a294b9a0@mail.gmail.com>

On Thu, 23 Jul 2009 14:39:29 +0800 Igor M Podlesny <for.poige+bugzilla.kernel.org@gmail.com> wrote:

> 2009/7/23 Andrew Morton <akpm@linux-foundation.org>:
> >
> > (switched to email. __Please respond via emailed reply-to-all, not via the
> > bugzilla web interface).
> >
> > On Sat, 11 Jul 2009 06:10:00 GMT
> > bugzilla-daemon@bugzilla.kernel.org wrote:
> >
> >> http://bugzilla.kernel.org/show_bug.cgi?id=13760
> >>
> >> __ __ __ __ __ __Summary: 2.6.30 kernel locks up with pppoe in back trace
> >> __ __ __ __ __ __ __ __ __ __ (regression)
> >> __ __ __ __ __ __Product: Networking
> >> __ __ __ __ __ __Version: 2.5
> >> __ __ Kernel Version: 2.6.30
> >> __ __ __ __ __ Platform: All
> >> __ __ __ __ OS/Version: Linux
> >> __ __ __ __ __ __ __ Tree: Mainline
> >> __ __ __ __ __ __ Status: NEW
> >> __ __ __ __ __ Severity: normal
> >> __ __ __ __ __ Priority: P1
> >> __ __ __ __ __Component: Other
> >> __ __ __ __ AssignedTo: acme@ghostprotocols.net
> >> __ __ __ __ ReportedBy: for.poige+bugzilla.kernel.org@gmail.com
> >> __ __ __ __ Regression: Yes
> >>
> >>
> >> Having updated kernel to 2.6.30 (and 2.6.30.1) I've faced several lock-ups
> >> during boot sequence (and even during shutdown), when pppoe connection had been
> >> initiated (and interrupted on shutdown). The lock-ups aren't Alt_SysRq_B
> >> breakable.
> >>
> >> I still not have backtraces saved but as soon as pppoe connection initiation
> >> runs before running X-server (and after its shutdown), I have seen parts of
> >> dmesg's output and to my surprise it was regarding pppoe's functions.
> >>
> >
> > This regression report is nearly two weeks old and I think there has
> > been a bit of ppp-related fixing going on in that time.
> >
> > Can you please tell us whether the regression is still present in
> > 2.6.30.2? __If so, I expect we'll be wanting to see those traces,
> > please.
> >
> 	Just repeating the same thing I had written in the Bugzilla: I
> haven't noticed any changes to pppoe during last commits to 2.6.30.
> Why do you think there's a chance that bug(s) would have been fixed?

Could have been a problem in net core, perhaps.

Below is a ppp fix from 2.6.31, but it seems unlikely to fix your problem.

It would help if we could see that trace, please.  A digital photo
would suit.


commit adeab1afb7de89555c69aab5ca21300c14af6369
Author:     Ralf Baechle <ralf@linux-mips.org>
AuthorDate: Sun Jul 12 21:09:20 2009 -0700
Commit:     David S. Miller <davem@davemloft.net>
CommitDate: Sun Jul 12 21:09:20 2009 -0700

    NET: Fix locking issues in PPP, 6pack, mkiss and strip line disciplines.
    
    Guido Trentalancia reports:
    
    I am trying to use the kiss driver in the Linux kernel that is being
    shipped with Fedora 10 but unfortunately I get the following oops:
    
    mkiss: AX.25 Multikiss, Hans Albas PE1AYX
    mkiss: ax0: crc mode is auto.
    ADDRCONF(NETDEV_CHANGE): ax0: link becomes ready
    ------------[ cut here ]------------
    WARNING: at kernel/softirq.c:77 __local_bh_disable+0x2f/0x83() (Not
    tainted)
    [...]
    unloaded: microcode]
    Pid: 0, comm: swapper Not tainted 2.6.27.25-170.2.72.fc10.i686 #1
     [<c042ddfb>] warn_on_slowpath+0x65/0x8b
     [<c06ab62b>] ? _spin_unlock_irqrestore+0x22/0x38
     [<c04228b4>] ? __enqueue_entity+0xe3/0xeb
     [<c042431e>] ? enqueue_entity+0x203/0x20b
     [<c0424361>] ? enqueue_task_fair+0x3b/0x3f
     [<c041f88c>] ? resched_task+0x3a/0x6e
     [<c06ab62b>] ? _spin_unlock_irqrestore+0x22/0x38
     [<c06ab4e2>] ? _spin_lock_bh+0xb/0x16
     [<c043255b>] __local_bh_disable+0x2f/0x83
     [<c04325ba>] local_bh_disable+0xb/0xd
     [<c06ab4e2>] _spin_lock_bh+0xb/0x16
     [<f8b6f600>] mkiss_receive_buf+0x2fb/0x3a6 [mkiss]
     [<c0572a30>] flush_to_ldisc+0xf7/0x198
     [<c0572b12>] tty_flip_buffer_push+0x41/0x51
     [<f89477f2>] ftdi_process_read+0x375/0x4ad [ftdi_sio]
     [<f8947a5a>] ftdi_read_bulk_callback+0x130/0x138 [ftdi_sio]
     [<c05d4bec>] usb_hcd_giveback_urb+0x63/0x93
     [<c05ea290>] uhci_giveback_urb+0xe5/0x15f
     [<c05eaabf>] uhci_scan_schedule+0x52e/0x767
     [<c05f6288>] ? psmouse_handle_byte+0xc/0xe5
     [<c054df78>] ? acpi_ev_gpe_detect+0xd6/0xe1
     [<c05ec5b0>] uhci_irq+0x110/0x125
     [<c05d4834>] usb_hcd_irq+0x40/0xa3
     [<c0465313>] handle_IRQ_event+0x2f/0x64
     [<c046642b>] handle_level_irq+0x74/0xbe
     [<c04663b7>] ? handle_level_irq+0x0/0xbe
     [<c0406e6e>] do_IRQ+0xc7/0xfe
     [<c0405668>] common_interrupt+0x28/0x30
     [<c056821a>] ? acpi_idle_enter_simple+0x162/0x19d
     [<c0617f52>] cpuidle_idle_call+0x60/0x92
     [<c0403c61>] cpu_idle+0x101/0x134
     [<c069b1ba>] rest_init+0x4e/0x50
     =======================
    ---[ end trace b7cc8076093467ad ]---
    ------------[ cut here ]------------
    WARNING: at kernel/softirq.c:136 _local_bh_enable_ip+0x3d/0xc4()
    [...]
    Pid: 0, comm: swapper Tainted: G        W 2.6.27.25-170.2.72.fc10.i686
     [<c042ddfb>] warn_on_slowpath+0x65/0x8b
     [<c06ab62b>] ? _spin_unlock_irqrestore+0x22/0x38
     [<c04228b4>] ? __enqueue_entity+0xe3/0xeb
     [<c042431e>] ? enqueue_entity+0x203/0x20b
     [<c0424361>] ? enqueue_task_fair+0x3b/0x3f
     [<c041f88c>] ? resched_task+0x3a/0x6e
     [<c06ab62b>] ? _spin_unlock_irqrestore+0x22/0x38
     [<c06ab4e2>] ? _spin_lock_bh+0xb/0x16
     [<f8b6f642>] ? mkiss_receive_buf+0x33d/0x3a6 [mkiss]
     [<c04325f9>] _local_bh_enable_ip+0x3d/0xc4
     [<c0432688>] local_bh_enable_ip+0x8/0xa
     [<c06ab54d>] _spin_unlock_bh+0x11/0x13
     [<f8b6f642>] mkiss_receive_buf+0x33d/0x3a6 [mkiss]
     [<c0572a30>] flush_to_ldisc+0xf7/0x198
     [<c0572b12>] tty_flip_buffer_push+0x41/0x51
     [<f89477f2>] ftdi_process_read+0x375/0x4ad [ftdi_sio]
     [<f8947a5a>] ftdi_read_bulk_callback+0x130/0x138 [ftdi_sio]
     [<c05d4bec>] usb_hcd_giveback_urb+0x63/0x93
     [<c05ea290>] uhci_giveback_urb+0xe5/0x15f
     [<c05eaabf>] uhci_scan_schedule+0x52e/0x767
     [<c05f6288>] ? psmouse_handle_byte+0xc/0xe5
     [<c054df78>] ? acpi_ev_gpe_detect+0xd6/0xe1
     [<c05ec5b0>] uhci_irq+0x110/0x125
     [<c05d4834>] usb_hcd_irq+0x40/0xa3
     [<c0465313>] handle_IRQ_event+0x2f/0x64
     [<c046642b>] handle_level_irq+0x74/0xbe
     [<c04663b7>] ? handle_level_irq+0x0/0xbe
     [<c0406e6e>] do_IRQ+0xc7/0xfe
     [<c0405668>] common_interrupt+0x28/0x30
     [<c056821a>] ? acpi_idle_enter_simple+0x162/0x19d
     [<c0617f52>] cpuidle_idle_call+0x60/0x92
     [<c0403c61>] cpu_idle+0x101/0x134
     [<c069b1ba>] rest_init+0x4e/0x50
     =======================
    ---[ end trace b7cc8076093467ad ]---
    mkiss: ax0: Trying crc-smack
    mkiss: ax0: Trying crc-flexnet
    
    The issue was, that the locking code in mkiss was assuming it was only
    ever being called in process or bh context.  Fixed by converting the
    involved locking code to use irq-safe locks.
    
    Review of other networking line disciplines shows that 6pack, both sync
    and async PPP and STRIP have similar issues.  The ppp_async one is the
    most interesting one as it sorts out half of the issue as far back as
    2004 in commit http://git.kernel.org/?p=linux/kernel/git/tglx/history.git;a=commitdiff;h=2996d8deaeddd01820691a872550dc0cfba0c37d
    
    Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
    Reported-by: Guido Trentalancia <guido@trentalancia.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
index 1551600..913a564 100644
--- a/drivers/net/hamradio/6pack.c
+++ b/drivers/net/hamradio/6pack.c
@@ -398,13 +398,14 @@ static DEFINE_RWLOCK(disc_data_lock);
                                                                                 
 static struct sixpack *sp_get(struct tty_struct *tty)
 {
+	unsigned long flags;
 	struct sixpack *sp;
 
-	read_lock(&disc_data_lock);
+	read_lock_irqsave(&disc_data_lock, flags);
 	sp = tty->disc_data;
 	if (sp)
 		atomic_inc(&sp->refcnt);
-	read_unlock(&disc_data_lock);
+	read_unlock_irqrestore(&disc_data_lock, flags);
 
 	return sp;
 }
@@ -688,12 +689,13 @@ out:
  */
 static void sixpack_close(struct tty_struct *tty)
 {
+	unsigned long flags;
 	struct sixpack *sp;
 
-	write_lock(&disc_data_lock);
+	write_lock_irqsave(&disc_data_lock, flags);
 	sp = tty->disc_data;
 	tty->disc_data = NULL;
-	write_unlock(&disc_data_lock);
+	write_unlock_irqrestore(&disc_data_lock, flags);
 	if (!sp)
 		return;
 
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index fda2fc8..a728650 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -244,15 +244,16 @@ static int kiss_esc_crc(unsigned char *s, unsigned char *d, unsigned short crc,
 /* Send one completely decapsulated AX.25 packet to the AX.25 layer. */
 static void ax_bump(struct mkiss *ax)
 {
+	unsigned long flags;
 	struct sk_buff *skb;
 	int count;
 
-	spin_lock_bh(&ax->buflock);
+	spin_lock_irqsave(&ax->buflock, flags);
 	if (ax->rbuff[0] > 0x0f) {
 		if (ax->rbuff[0] & 0x80) {
 			if (check_crc_16(ax->rbuff, ax->rcount) < 0) {
 				ax->dev->stats.rx_errors++;
-				spin_unlock_bh(&ax->buflock);
+				spin_unlock_irqrestore(&ax->buflock, flags);
 
 				return;
 			}
@@ -267,7 +268,7 @@ static void ax_bump(struct mkiss *ax)
 		} else if (ax->rbuff[0] & 0x20)  {
 			if (check_crc_flex(ax->rbuff, ax->rcount) < 0) {
 				ax->dev->stats.rx_errors++;
-				spin_unlock_bh(&ax->buflock);
+				spin_unlock_irqrestore(&ax->buflock, flags);
 				return;
 			}
 			if (ax->crcmode != CRC_MODE_FLEX && ax->crcauto) {
@@ -294,7 +295,7 @@ static void ax_bump(struct mkiss *ax)
 		printk(KERN_ERR "mkiss: %s: memory squeeze, dropping packet.\n",
 		       ax->dev->name);
 		ax->dev->stats.rx_dropped++;
-		spin_unlock_bh(&ax->buflock);
+		spin_unlock_irqrestore(&ax->buflock, flags);
 		return;
 	}
 
@@ -303,11 +304,13 @@ static void ax_bump(struct mkiss *ax)
 	netif_rx(skb);
 	ax->dev->stats.rx_packets++;
 	ax->dev->stats.rx_bytes += count;
-	spin_unlock_bh(&ax->buflock);
+	spin_unlock_irqrestore(&ax->buflock, flags);
 }
 
 static void kiss_unesc(struct mkiss *ax, unsigned char s)
 {
+	unsigned long flags;
+
 	switch (s) {
 	case END:
 		/* drop keeptest bit = VSV */
@@ -334,18 +337,18 @@ static void kiss_unesc(struct mkiss *ax, unsigned char s)
 		break;
 	}
 
-	spin_lock_bh(&ax->buflock);
+	spin_lock_irqsave(&ax->buflock, flags);
 	if (!test_bit(AXF_ERROR, &ax->flags)) {
 		if (ax->rcount < ax->buffsize) {
 			ax->rbuff[ax->rcount++] = s;
-			spin_unlock_bh(&ax->buflock);
+			spin_unlock_irqrestore(&ax->buflock, flags);
 			return;
 		}
 
 		ax->dev->stats.rx_over_errors++;
 		set_bit(AXF_ERROR, &ax->flags);
 	}
-	spin_unlock_bh(&ax->buflock);
+	spin_unlock_irqrestore(&ax->buflock, flags);
 }
 
 static int ax_set_mac_address(struct net_device *dev, void *addr)
@@ -367,6 +370,7 @@ static void ax_changedmtu(struct mkiss *ax)
 {
 	struct net_device *dev = ax->dev;
 	unsigned char *xbuff, *rbuff, *oxbuff, *orbuff;
+	unsigned long flags;
 	int len;
 
 	len = dev->mtu * 2;
@@ -392,7 +396,7 @@ static void ax_changedmtu(struct mkiss *ax)
 		return;
 	}
 
-	spin_lock_bh(&ax->buflock);
+	spin_lock_irqsave(&ax->buflock, flags);
 
 	oxbuff    = ax->xbuff;
 	ax->xbuff = xbuff;
@@ -423,7 +427,7 @@ static void ax_changedmtu(struct mkiss *ax)
 	ax->mtu      = dev->mtu + 73;
 	ax->buffsize = len;
 
-	spin_unlock_bh(&ax->buflock);
+	spin_unlock_irqrestore(&ax->buflock, flags);
 
 	kfree(oxbuff);
 	kfree(orbuff);
@@ -433,6 +437,7 @@ static void ax_changedmtu(struct mkiss *ax)
 static void ax_encaps(struct net_device *dev, unsigned char *icp, int len)
 {
 	struct mkiss *ax = netdev_priv(dev);
+	unsigned long flags;
 	unsigned char *p;
 	int actual, count;
 
@@ -449,7 +454,7 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len)
 
 	p = icp;
 
-	spin_lock_bh(&ax->buflock);
+	spin_lock_irqsave(&ax->buflock, flags);
 	if ((*p & 0x0f) != 0) {
 		/* Configuration Command (kissparms(1).
 		 * Protocol spec says: never append CRC.
@@ -479,7 +484,7 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len)
 				ax->crcauto = (cmd ? 0 : 1);
 				printk(KERN_INFO "mkiss: %s: crc mode %s %d\n", ax->dev->name, (len) ? "set to" : "is", cmd);
 			}
-			spin_unlock_bh(&ax->buflock);
+			spin_unlock_irqrestore(&ax->buflock, flags);
 			netif_start_queue(dev);
 
 			return;
@@ -512,7 +517,7 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len)
 			count = kiss_esc(p, (unsigned char *)ax->xbuff, len);
 		}
   	}
-	spin_unlock_bh(&ax->buflock);
+	spin_unlock_irqrestore(&ax->buflock, flags);
 
 	set_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags);
 	actual = ax->tty->ops->write(ax->tty, ax->xbuff, count);
@@ -704,13 +709,14 @@ static DEFINE_RWLOCK(disc_data_lock);
 
 static struct mkiss *mkiss_get(struct tty_struct *tty)
 {
+	unsigned long flags;
 	struct mkiss *ax;
 
-	read_lock(&disc_data_lock);
+	read_lock_irqsave(&disc_data_lock, flags);
 	ax = tty->disc_data;
 	if (ax)
 		atomic_inc(&ax->refcnt);
-	read_unlock(&disc_data_lock);
+	read_unlock_irqrestore(&disc_data_lock, flags);
 
 	return ax;
 }
@@ -809,12 +815,13 @@ out:
 
 static void mkiss_close(struct tty_struct *tty)
 {
+	unsigned long flags;
 	struct mkiss *ax;
 
-	write_lock(&disc_data_lock);
+	write_lock_irqsave(&disc_data_lock, flags);
 	ax = tty->disc_data;
 	tty->disc_data = NULL;
-	write_unlock(&disc_data_lock);
+	write_unlock_irqrestore(&disc_data_lock, flags);
 
 	if (!ax)
 		return;
diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c
index 17c116b..1fd319b 100644
--- a/drivers/net/ppp_async.c
+++ b/drivers/net/ppp_async.c
@@ -132,13 +132,15 @@ static DEFINE_RWLOCK(disc_data_lock);
 
 static struct asyncppp *ap_get(struct tty_struct *tty)
 {
+	unsigned long flags;
 	struct asyncppp *ap;
 
-	read_lock(&disc_data_lock);
+	read_lock_irqsave(&disc_data_lock, flags);
 	ap = tty->disc_data;
 	if (ap != NULL)
 		atomic_inc(&ap->refcnt);
-	read_unlock(&disc_data_lock);
+	read_unlock_irqrestore(&disc_data_lock, flags);
+
 	return ap;
 }
 
@@ -215,12 +217,13 @@ ppp_asynctty_open(struct tty_struct *tty)
 static void
 ppp_asynctty_close(struct tty_struct *tty)
 {
+	unsigned long flags;
 	struct asyncppp *ap;
 
-	write_lock_irq(&disc_data_lock);
+	write_lock_irqsave(&disc_data_lock, flags);
 	ap = tty->disc_data;
 	tty->disc_data = NULL;
-	write_unlock_irq(&disc_data_lock);
+	write_unlock_irqrestore(&disc_data_lock, flags);
 	if (!ap)
 		return;
 
diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c
index aa3d39f..1b3f75f 100644
--- a/drivers/net/ppp_synctty.c
+++ b/drivers/net/ppp_synctty.c
@@ -182,13 +182,15 @@ static DEFINE_RWLOCK(disc_data_lock);
 
 static struct syncppp *sp_get(struct tty_struct *tty)
 {
+	unsigned long flags;
 	struct syncppp *ap;
 
-	read_lock(&disc_data_lock);
+	read_lock_irqsave(&disc_data_lock, flags);
 	ap = tty->disc_data;
 	if (ap != NULL)
 		atomic_inc(&ap->refcnt);
-	read_unlock(&disc_data_lock);
+	read_unlock_irqrestore(&disc_data_lock, flags);
+
 	return ap;
 }
 
@@ -262,12 +264,13 @@ ppp_sync_open(struct tty_struct *tty)
 static void
 ppp_sync_close(struct tty_struct *tty)
 {
+	unsigned long flags;
 	struct syncppp *ap;
 
-	write_lock_irq(&disc_data_lock);
+	write_lock_irqsave(&disc_data_lock, flags);
 	ap = tty->disc_data;
 	tty->disc_data = NULL;
-	write_unlock_irq(&disc_data_lock);
+	write_unlock_irqrestore(&disc_data_lock, flags);
 	if (!ap)
 		return;
 
diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c
index 38366a5..3d39f65 100644
--- a/drivers/net/wireless/strip.c
+++ b/drivers/net/wireless/strip.c
@@ -856,6 +856,7 @@ static int strip_change_mtu(struct net_device *dev, int new_mtu)
 	unsigned char *orbuff = strip_info->rx_buff;
 	unsigned char *osbuff = strip_info->sx_buff;
 	unsigned char *otbuff = strip_info->tx_buff;
+	unsigned long flags;
 
 	if (new_mtu > MAX_SEND_MTU) {
 		printk(KERN_ERR
@@ -864,11 +865,11 @@ static int strip_change_mtu(struct net_device *dev, int new_mtu)
 		return -EINVAL;
 	}
 
-	spin_lock_bh(&strip_lock);
+	spin_lock_irqsave(&strip_lock, flags);
 	if (!allocate_buffers(strip_info, new_mtu)) {
 		printk(KERN_ERR "%s: unable to grow strip buffers, MTU change cancelled.\n",
 		       strip_info->dev->name);
-		spin_unlock_bh(&strip_lock);
+		spin_unlock_irqrestore(&strip_lock, flags);
 		return -ENOMEM;
 	}
 
@@ -892,7 +893,7 @@ static int strip_change_mtu(struct net_device *dev, int new_mtu)
 		}
 	}
 	strip_info->tx_head = strip_info->tx_buff;
-	spin_unlock_bh(&strip_lock);
+	spin_unlock_irqrestore(&strip_lock, flags);
 
 	printk(KERN_NOTICE "%s: strip MTU changed fom %d to %d.\n",
 	       strip_info->dev->name, old_mtu, strip_info->mtu);
@@ -983,10 +984,13 @@ static void strip_seq_neighbours(struct seq_file *seq,
 			   const MetricomNodeTable * table,
 			   const char *title)
 {
-	/* We wrap this in a do/while loop, so if the table changes */
-	/* while we're reading it, we just go around and try again. */
+	unsigned long flags;
 	struct timeval t;
 
+	/*
+	 * We wrap this in a do/while loop, so if the table changes
+	 * while we're reading it, we just go around and try again.
+	 */
 	do {
 		int i;
 		t = table->timestamp;
@@ -995,9 +999,9 @@ static void strip_seq_neighbours(struct seq_file *seq,
 		for (i = 0; i < table->num_nodes; i++) {
 			MetricomNode node;
 
-			spin_lock_bh(&strip_lock);
+			spin_lock_irqsave(&strip_lock, flags);
 			node = table->node[i];
-			spin_unlock_bh(&strip_lock);
+			spin_unlock_irqrestore(&strip_lock, flags);
 			seq_printf(seq, "  %s\n", node.c);
 		}
 	} while (table->timestamp.tv_sec != t.tv_sec
@@ -1536,6 +1540,7 @@ static void strip_send(struct strip *strip_info, struct sk_buff *skb)
 static int strip_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct strip *strip_info = netdev_priv(dev);
+	unsigned long flags;
 
 	if (!netif_running(dev)) {
 		printk(KERN_ERR "%s: xmit call when iface is down\n",
@@ -1574,11 +1579,11 @@ static int strip_xmit(struct sk_buff *skb, struct net_device *dev)
 			       strip_info->dev->name, sx_pps_count / 8);
 	}
 
-	spin_lock_bh(&strip_lock);
+	spin_lock_irqsave(&strip_lock, flags);
 
 	strip_send(strip_info, skb);
 
-	spin_unlock_bh(&strip_lock);
+	spin_unlock_irqrestore(&strip_lock, flags);
 
 	if (skb)
 		dev_kfree_skb(skb);
@@ -2263,12 +2268,13 @@ static void strip_receive_buf(struct tty_struct *tty, const unsigned char *cp,
 {
 	struct strip *strip_info = tty->disc_data;
 	const unsigned char *end = cp + count;
+	unsigned long flags;
 
 	if (!strip_info || strip_info->magic != STRIP_MAGIC
 	    || !netif_running(strip_info->dev))
 		return;
 
-	spin_lock_bh(&strip_lock);
+	spin_lock_irqsave(&strip_lock, flags);
 #if 0
 	{
 		struct timeval tv;
@@ -2335,7 +2341,7 @@ static void strip_receive_buf(struct tty_struct *tty, const unsigned char *cp,
 		}
 		cp++;
 	}
-	spin_unlock_bh(&strip_lock);
+	spin_unlock_irqrestore(&strip_lock, flags);
 }
 
 
@@ -2523,9 +2529,11 @@ static void strip_dev_setup(struct net_device *dev)
 
 static void strip_free(struct strip *strip_info)
 {
-	spin_lock_bh(&strip_lock);
+	unsigned long flags;
+
+	spin_lock_irqsave(&strip_lock, flags);
 	list_del_rcu(&strip_info->list);
-	spin_unlock_bh(&strip_lock);
+	spin_unlock_irqrestore(&strip_lock, flags);
 
 	strip_info->magic = 0;
 
@@ -2539,6 +2547,7 @@ static void strip_free(struct strip *strip_info)
 static struct strip *strip_alloc(void)
 {
 	struct list_head *n;
+	unsigned long flags;
 	struct net_device *dev;
 	struct strip *strip_info;
 
@@ -2562,7 +2571,7 @@ static struct strip *strip_alloc(void)
 	strip_info->idle_timer.function = strip_IdleTask;
 
 
-	spin_lock_bh(&strip_lock);
+	spin_lock_irqsave(&strip_lock, flags);
  rescan:
 	/*
 	 * Search the list to find where to put our new entry
@@ -2581,7 +2590,7 @@ static struct strip *strip_alloc(void)
 	sprintf(dev->name, "st%ld", dev->base_addr);
 
 	list_add_tail_rcu(&strip_info->list, &strip_list);
-	spin_unlock_bh(&strip_lock);
+	spin_unlock_irqrestore(&strip_lock, flags);
 
 	return strip_info;
 }


^ permalink raw reply related

* Re: [Bugme-new] [Bug 13760] New: 2.6.30 kernel locks up with pppoe in back trace (regression)
From: Igor M Podlesny @ 2009-07-23  6:39 UTC (permalink / raw)
  To: Andrew Morton
  Cc: for.poige+bugzilla.kernel.org, bugzilla-daemon, bugme-daemon,
	netdev
In-Reply-To: <20090722134557.2457c5f5.akpm@linux-foundation.org>

2009/7/23 Andrew Morton <akpm@linux-foundation.org>:
>
> (switched to email.  Please respond via emailed reply-to-all, not via the
> bugzilla web interface).
>
> On Sat, 11 Jul 2009 06:10:00 GMT
> bugzilla-daemon@bugzilla.kernel.org wrote:
>
>> http://bugzilla.kernel.org/show_bug.cgi?id=13760
>>
>>            Summary: 2.6.30 kernel locks up with pppoe in back trace
>>                     (regression)
>>            Product: Networking
>>            Version: 2.5
>>     Kernel Version: 2.6.30
>>           Platform: All
>>         OS/Version: Linux
>>               Tree: Mainline
>>             Status: NEW
>>           Severity: normal
>>           Priority: P1
>>          Component: Other
>>         AssignedTo: acme@ghostprotocols.net
>>         ReportedBy: for.poige+bugzilla.kernel.org@gmail.com
>>         Regression: Yes
>>
>>
>> Having updated kernel to 2.6.30 (and 2.6.30.1) I've faced several lock-ups
>> during boot sequence (and even during shutdown), when pppoe connection had been
>> initiated (and interrupted on shutdown). The lock-ups aren't Alt_SysRq_B
>> breakable.
>>
>> I still not have backtraces saved but as soon as pppoe connection initiation
>> runs before running X-server (and after its shutdown), I have seen parts of
>> dmesg's output and to my surprise it was regarding pppoe's functions.
>>
>
> This regression report is nearly two weeks old and I think there has
> been a bit of ppp-related fixing going on in that time.
>
> Can you please tell us whether the regression is still present in
> 2.6.30.2?  If so, I expect we'll be wanting to see those traces,
> please.
>
	Just repeating the same thing I had written in the Bugzilla: I
haven't noticed any changes to pppoe during last commits to 2.6.30.
Why do you think there's a chance that bug(s) would have been fixed?

-- 
End of message. Next message?

^ permalink raw reply

* Re: [net-next-2.6 PATCH][be2net] Add GRO support to the be2net driver. LRO is not supported anymore.
From: Ajit Khaparde @ 2009-07-23  6:18 UTC (permalink / raw)
  To: David Miller; +Cc: netdev
In-Reply-To: <20090721.123635.76413778.davem@davemloft.net>

On 21/07/09 12:36 -0700, David Miller wrote:
> From: Ajit Khaparde <ajitk@serverengines.com>
> Date: Tue, 21 Jul 2009 17:37:11 +0530
> 
> > 
> > This patch removes support for INET_LRO and switches over to GRO.
> >
> > Signed-off-by: Ajit Khaparde <ajitk@serverengines.com>
> 
> Applied, thanks a lot for doing this work.

Dave, I just finished a git pull, but don't see the changes. 
What could be the reason?

-Ajit

^ permalink raw reply

* Re: [PATCH net-next-2.6] bonding: propogate vlan_features to bonding master
From: Eric Dumazet @ 2009-07-23  6:03 UTC (permalink / raw)
  To: Jay Vosburgh; +Cc: Or Gerlitz, David Miller, netdev
In-Reply-To: <3463.1248298460@death.nxdomain.ibm.com>

Jay Vosburgh a écrit :
> 	Propogate the vlan_features of the slave devices to the bonding
> master device, using the same logic as for regular features.
> 
> 	Tested by Or Gerlitz <ogerlitz@voltaire.com>, who also removed
> the debug logic from the original test patch.
> 
> Signed-off-by: Or Gerlitz <ogerlitz@voltaire.com>
> Signed-off-by: Jay Vosburgh <fubar@us.ibm.com>

Seems pretty cool, but I could not test it on my dev machine,
since tg3 and bnx2 drivers dont advertize yet vlan_features

> 
> diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
> index 3bf0cc6..5a8b882 100644
> --- a/drivers/net/bonding/bond_main.c
> +++ b/drivers/net/bonding/bond_main.c
> @@ -1331,6 +1331,7 @@ static int bond_compute_features(struct bonding *bond)
>  	struct slave *slave;
>  	struct net_device *bond_dev = bond->dev;
>  	unsigned long features = bond_dev->features;
> +	unsigned long vlan_features;
>  	unsigned short max_hard_header_len = max((u16)ETH_HLEN,
>  						bond_dev->hard_header_len);
>  	int i;
> @@ -1343,10 +1344,14 @@ static int bond_compute_features(struct bonding *bond)
>  
>  	features &= ~NETIF_F_ONE_FOR_ALL;
>  
> +	vlan_features = bond->first_slave->dev->vlan_features;
>  	bond_for_each_slave(bond, slave, i) {
>  		features = netdev_increment_features(features,
>  						     slave->dev->features,
>  						     NETIF_F_ONE_FOR_ALL);
> +		vlan_features = netdev_increment_features(vlan_features,
> +							slave->dev->vlan_features,
> +							NETIF_F_ONE_FOR_ALL);
>  		if (slave->dev->hard_header_len > max_hard_header_len)
>  			max_hard_header_len = slave->dev->hard_header_len;
>  	}
> @@ -1354,6 +1359,7 @@ static int bond_compute_features(struct bonding *bond)
>  done:
>  	features |= (bond_dev->features & BOND_VLAN_FEATURES);
>  	bond_dev->features = netdev_fix_features(features, NULL);
> +	bond_dev->vlan_features = netdev_fix_features(vlan_features, NULL);
>  	bond_dev->hard_header_len = max_hard_header_len;
>  
>  	return 0;


^ permalink raw reply

* Re: [PATCH] Add mac driver for w90p910
From: Wan ZongShun @ 2009-07-23  4:52 UTC (permalink / raw)
  To: David Miller, Russell King
  Cc: soni.trilok, netdev, linux-arm-kernel, eric.y.miao
In-Reply-To: <20090720.105217.236487133.davem@davemloft.net>

Dear sirs,

I have to sent this patch third times and really didn't know why previous two mails
were held by arm-linux-kernel. but it look like sending linux-netdev is successful,
For any inconvenience caused, please forgive.

I fixed up previous mac driver and make a patch relative to it.

thanks for your help.

According to Russell's advice, I fixed up mac driver,
which relatives to previous mac driver patch, and the
evaluation board based on w90p910.

Signed-off-by: Wan ZongShun <mcuos.com@gmail.com>

diff --git a/drivers/net/arm/w90p910_ether.c b/drivers/net/arm/w90p910_ether.c
index 7b5f315..890716f 100644
--- a/drivers/net/arm/w90p910_ether.c
+++ b/drivers/net/arm/w90p910_ether.c
@@ -143,16 +143,17 @@ struct recv_pdesc {
 
 struct tran_pdesc {
 	struct w90p910_txbd desclist[TX_DESC_SIZE];
-	char tran_buf[RX_DESC_SIZE][MAX_TBUFF_SZ];
+	char tran_buf[TX_DESC_SIZE][MAX_TBUFF_SZ];
 };
 
 struct  w90p910_ether {
 	struct recv_pdesc *rdesc;
-	struct recv_pdesc *rdesc_phys;
 	struct tran_pdesc *tdesc;
-	struct tran_pdesc *tdesc_phys;
+	dma_addr_t rdesc_phys;
+	dma_addr_t tdesc_phys;
 	struct net_device_stats stats;
 	struct platform_device *pdev;
+	struct resource *res;
 	struct sk_buff *skb;
 	struct clk *clk;
 	struct clk *rmiiclk;
@@ -274,59 +275,75 @@ static void w90p910_write_cam(struct net_device *dev,
 	__raw_writel(msw, ether->reg + REG_CAMM_BASE + x * CAM_ENTRY_SIZE);
 }
 
-static void w90p910_init_desc(struct net_device *dev)
+static int w90p910_init_desc(struct net_device *dev)
 {
 	struct w90p910_ether *ether;
-	struct w90p910_txbd  *tdesc, *tdesc_phys;
-	struct w90p910_rxbd  *rdesc, *rdesc_phys;
-	unsigned int i, j;
+	struct w90p910_txbd  *tdesc;
+	struct w90p910_rxbd  *rdesc;
+	struct platform_device *pdev;
+	unsigned int i;
 
 	ether = netdev_priv(dev);
+	pdev = ether->pdev;
 
 	ether->tdesc = (struct tran_pdesc *)
-			dma_alloc_coherent(NULL, sizeof(struct tran_pdesc),
-				(dma_addr_t *)&ether->tdesc_phys, GFP_KERNEL);
+		dma_alloc_coherent(&pdev->dev, sizeof(struct tran_pdesc),
+					&ether->tdesc_phys, GFP_KERNEL);
+
+	if (!ether->tdesc) {
+		dev_err(&pdev->dev, "Failed to allocate memory for tx desc\n");
+		return -ENOMEM;
+	}
 
 	ether->rdesc = (struct recv_pdesc *)
-			dma_alloc_coherent(NULL, sizeof(struct recv_pdesc),
-				(dma_addr_t *)&ether->rdesc_phys, GFP_KERNEL);
+		dma_alloc_coherent(&pdev->dev, sizeof(struct recv_pdesc),
+					&ether->rdesc_phys, GFP_KERNEL);
+
+	if (!ether->rdesc) {
+		dev_err(&pdev->dev, "Failed to allocate memory for rx desc\n");
+		dma_free_coherent(&pdev->dev, sizeof(struct tran_pdesc),
+					ether->tdesc, ether->tdesc_phys);
+		return -ENOMEM;
+	}
 
 	for (i = 0; i < TX_DESC_SIZE; i++) {
-		tdesc = &(ether->tdesc->desclist[i]);
+		unsigned int offset;
 
-		j = ((i + 1) / TX_DESC_SIZE);
+		tdesc = &(ether->tdesc->desclist[i]);
 
-		if (j != 0) {
-			tdesc_phys = &(ether->tdesc_phys->desclist[0]);
-			ether->start_tx_ptr = (unsigned int)tdesc_phys;
-			tdesc->next = (unsigned int)ether->start_tx_ptr;
-		} else {
-			tdesc_phys = &(ether->tdesc_phys->desclist[i+1]);
-			tdesc->next = (unsigned int)tdesc_phys;
-		}
+		if (i == TX_DESC_SIZE - 1)
+			offset = offsetof(struct tran_pdesc, desclist[0]);
+		else
+			offset = offsetof(struct tran_pdesc, desclist[i + 1]);
 
-		tdesc->buffer = (unsigned int)ether->tdesc_phys->tran_buf[i];
+		tdesc->next = ether->tdesc_phys + offset;
+		tdesc->buffer = ether->tdesc_phys +
+			offsetof(struct tran_pdesc, tran_buf[i]);
 		tdesc->sl = 0;
 		tdesc->mode = 0;
 	}
 
+	ether->start_tx_ptr = ether->tdesc_phys;
+
 	for (i = 0; i < RX_DESC_SIZE; i++) {
-		rdesc = &(ether->rdesc->desclist[i]);
+		unsigned int offset;
 
-		j = ((i + 1) / RX_DESC_SIZE);
+		rdesc = &(ether->rdesc->desclist[i]);
 
-		if (j != 0) {
-			rdesc_phys = &(ether->rdesc_phys->desclist[0]);
-			ether->start_rx_ptr = (unsigned int)rdesc_phys;
-			rdesc->next = (unsigned int)ether->start_rx_ptr;
-		} else {
-			rdesc_phys = &(ether->rdesc_phys->desclist[i+1]);
-			rdesc->next = (unsigned int)rdesc_phys;
-		}
+		if (i == RX_DESC_SIZE - 1)
+			offset = offsetof(struct recv_pdesc, desclist[0]);
+		else
+			offset = offsetof(struct recv_pdesc, desclist[i + 1]);
 
+		rdesc->next = ether->rdesc_phys + offset;
 		rdesc->sl = RX_OWEN_DMA;
-		rdesc->buffer = (unsigned int)ether->rdesc_phys->recv_buf[i];
+		rdesc->buffer = ether->rdesc_phys +
+			offsetof(struct recv_pdesc, recv_buf[i]);
 	  }
+
+	ether->start_rx_ptr = ether->rdesc_phys;
+
+	return 0;
 }
 
 static void w90p910_set_fifo_threshold(struct net_device *dev)
@@ -552,11 +569,14 @@ static int w90p910_set_mac_address(struct net_device *dev, void *addr)
 static int w90p910_ether_close(struct net_device *dev)
 {
 	struct w90p910_ether *ether = netdev_priv(dev);
+	struct platform_device *pdev;
+
+	pdev = ether->pdev;
 
-	dma_free_writecombine(NULL, sizeof(struct w90p910_rxbd),
-				ether->rdesc, (dma_addr_t)ether->rdesc_phys);
-	dma_free_writecombine(NULL, sizeof(struct w90p910_txbd),
-				ether->tdesc, (dma_addr_t)ether->tdesc_phys);
+	dma_free_coherent(&pdev->dev, sizeof(struct recv_pdesc),
+					ether->rdesc, ether->rdesc_phys);
+	dma_free_coherent(&pdev->dev, sizeof(struct tran_pdesc),
+					ether->tdesc, ether->tdesc_phys);
 
 	netif_stop_queue(dev);
 
@@ -592,6 +612,7 @@ static int w90p910_send_frame(struct net_device *dev,
 
 	txbd = &ether->tdesc->desclist[ether->cur_tx];
 	buffer = ether->tdesc->tran_buf[ether->cur_tx];
+
 	if (length > 1514) {
 		dev_err(&pdev->dev, "send data %d bytes, check it\n", length);
 		length = 1514;
@@ -607,7 +628,9 @@ static int w90p910_send_frame(struct net_device *dev,
 
 	w90p910_trigger_tx(dev);
 
-	ether->cur_tx = (ether->cur_tx+1) % TX_DESC_SIZE;
+	if (++ether->cur_tx >= TX_DESC_SIZE)
+		ether->cur_tx = 0;
+
 	txbd = &ether->tdesc->desclist[ether->cur_tx];
 
 	dev->trans_start = jiffies;
@@ -635,7 +658,6 @@ static irqreturn_t w90p910_tx_interrupt(int irq, void *dev_id)
 	struct w90p910_ether *ether;
 	struct w90p910_txbd  *txbd;
 	struct platform_device *pdev;
-	struct tran_pdesc *tran_pdesc;
 	struct net_device *dev;
 	unsigned int cur_entry, entry, status;
 
@@ -647,13 +669,14 @@ static irqreturn_t w90p910_tx_interrupt(int irq, void *dev_id)
 
 	cur_entry = __raw_readl(ether->reg + REG_CTXDSA);
 
-	tran_pdesc = ether->tdesc_phys;
-	entry = (unsigned int)(&tran_pdesc->desclist[ether->finish_tx]);
+	entry = ether->tdesc_phys +
+		offsetof(struct tran_pdesc, desclist[ether->finish_tx]);
 
 	while (entry != cur_entry) {
 		txbd = &ether->tdesc->desclist[ether->finish_tx];
 
-		ether->finish_tx = (ether->finish_tx + 1) % TX_DESC_SIZE;
+		if (++ether->finish_tx >= TX_DESC_SIZE)
+			ether->finish_tx = 0;
 
 		if (txbd->sl & TXDS_TXCP) {
 			ether->stats.tx_packets++;
@@ -668,7 +691,8 @@ static irqreturn_t w90p910_tx_interrupt(int irq, void *dev_id)
 		if (netif_queue_stopped(dev))
 			netif_wake_queue(dev);
 
-		entry = (unsigned int)(&tran_pdesc->desclist[ether->finish_tx]);
+		entry = ether->tdesc_phys +
+			offsetof(struct tran_pdesc, desclist[ether->finish_tx]);
 	}
 
 	if (status & MISTA_EXDEF) {
@@ -689,20 +713,20 @@ static void netdev_rx(struct net_device *dev)
 	struct w90p910_ether *ether;
 	struct w90p910_rxbd *rxbd;
 	struct platform_device *pdev;
-	struct recv_pdesc *rdesc_phys;
 	struct sk_buff *skb;
 	unsigned char *data;
 	unsigned int length, status, val, entry;
 
 	ether = netdev_priv(dev);
 	pdev = ether->pdev;
-	rdesc_phys = ether->rdesc_phys;
 
 	rxbd = &ether->rdesc->desclist[ether->cur_rx];
 
 	do {
 		val = __raw_readl(ether->reg + REG_CRXDSA);
-		entry = (unsigned int)&rdesc_phys->desclist[ether->cur_rx];
+
+		entry = ether->rdesc_phys +
+			offsetof(struct recv_pdesc, desclist[ether->cur_rx]);
 
 		if (val == entry)
 			break;
@@ -747,7 +771,10 @@ static void netdev_rx(struct net_device *dev)
 
 		rxbd->sl = RX_OWEN_DMA;
 		rxbd->reserved = 0x0;
-		ether->cur_rx = (ether->cur_rx+1) % RX_DESC_SIZE;
+
+		if (++ether->cur_rx >= RX_DESC_SIZE)
+			ether->cur_rx = 0;
+
 		rxbd = &ether->rdesc->desclist[ether->cur_rx];
 
 		dev->last_rx = jiffies;
@@ -955,30 +982,29 @@ static int __devinit w90p910_ether_probe(struct platform_device *pdev)
 {
 	struct w90p910_ether *ether;
 	struct net_device *dev;
-	struct resource *res;
 	int error;
 
 	dev = alloc_etherdev(sizeof(struct w90p910_ether));
 	if (!dev)
 		return -ENOMEM;
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (res == NULL) {
+	ether = netdev_priv(dev);
+
+	ether->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (ether->res == NULL) {
 		dev_err(&pdev->dev, "failed to get I/O memory\n");
 		error = -ENXIO;
 		goto failed_free;
 	}
 
-	res = request_mem_region(res->start, resource_size(res), pdev->name);
-	if (res == NULL) {
+	if (!request_mem_region(ether->res->start,
+				resource_size(ether->res), pdev->name)) {
 		dev_err(&pdev->dev, "failed to request I/O memory\n");
 		error = -EBUSY;
 		goto failed_free;
 	}
 
-	ether = netdev_priv(dev);
-
-	ether->reg = ioremap(res->start, resource_size(res));
+	ether->reg = ioremap(ether->res->start, resource_size(ether->res));
 	if (ether->reg == NULL) {
 		dev_err(&pdev->dev, "failed to remap I/O memory\n");
 		error = -ENXIO;
@@ -1039,7 +1065,7 @@ failed_free_txirq:
 failed_free_io:
 	iounmap(ether->reg);
 failed_free_mem:
-	release_mem_region(res->start, resource_size(res));
+	release_mem_region(ether->res->start, resource_size(ether->res));
 failed_free:
 	free_netdev(dev);
 	return error;
@@ -1051,12 +1077,19 @@ static int __devexit w90p910_ether_remove(struct platform_device *pdev)
 	struct w90p910_ether *ether = netdev_priv(dev);
 
 	unregister_netdev(dev);
+
 	clk_put(ether->rmiiclk);
 	clk_put(ether->clk);
-	del_timer_sync(&ether->check_timer);
-	platform_set_drvdata(pdev, NULL);
+
+	iounmap(ether->reg);
+	release_mem_region(ether->res->start, resource_size(ether->res));
+
 	free_irq(ether->txirq, dev);
 	free_irq(ether->rxirq, dev);
+
+	del_timer_sync(&ether->check_timer);
+	platform_set_drvdata(pdev, NULL);
+
 	free_netdev(dev);
 	return 0;
 }
-- 
1.5.6.3
 


^ permalink raw reply related

* [PATCH] Add mac driver patch fixed for w90p910
From: Wan ZongShun @ 2009-07-23  4:33 UTC (permalink / raw)
  To: Wan ZongShun
  Cc: David Miller, Russell King, soni.trilok, netdev, linux-arm-kernel
In-Reply-To: <4A67E49A.5090806@gmail.com>

Dear Russell&David,

"[PATCH] fixed up the previous mac driver for w90p910"

Just now sent above patch failed, so resent it.

Due to having a bit busy, when David has applied this mac patch,
however,I did not fix it based on comments as pointed by Russell.

So, I have to resubmit a new patch relative to previous patch.

patch text:

According to Russell's advice, I fixed up mac driver,
which relatives to previous mac driver patch, and the
evaluation board based on w90p910.

Signed-off-by: Wan ZongShun <mcuos.com@gmail.com>

diff --git a/drivers/net/arm/w90p910_ether.c b/drivers/net/arm/w90p910_ether.c
index 7b5f315..890716f 100644
--- a/drivers/net/arm/w90p910_ether.c
+++ b/drivers/net/arm/w90p910_ether.c
@@ -143,16 +143,17 @@ struct recv_pdesc {
 
 struct tran_pdesc {
 	struct w90p910_txbd desclist[TX_DESC_SIZE];
-	char tran_buf[RX_DESC_SIZE][MAX_TBUFF_SZ];
+	char tran_buf[TX_DESC_SIZE][MAX_TBUFF_SZ];
 };
 
 struct  w90p910_ether {
 	struct recv_pdesc *rdesc;
-	struct recv_pdesc *rdesc_phys;
 	struct tran_pdesc *tdesc;
-	struct tran_pdesc *tdesc_phys;
+	dma_addr_t rdesc_phys;
+	dma_addr_t tdesc_phys;
 	struct net_device_stats stats;
 	struct platform_device *pdev;
+	struct resource *res;
 	struct sk_buff *skb;
 	struct clk *clk;
 	struct clk *rmiiclk;
@@ -274,59 +275,75 @@ static void w90p910_write_cam(struct net_device *dev,
 	__raw_writel(msw, ether->reg + REG_CAMM_BASE + x * CAM_ENTRY_SIZE);
 }
 
-static void w90p910_init_desc(struct net_device *dev)
+static int w90p910_init_desc(struct net_device *dev)
 {
 	struct w90p910_ether *ether;
-	struct w90p910_txbd  *tdesc, *tdesc_phys;
-	struct w90p910_rxbd  *rdesc, *rdesc_phys;
-	unsigned int i, j;
+	struct w90p910_txbd  *tdesc;
+	struct w90p910_rxbd  *rdesc;
+	struct platform_device *pdev;
+	unsigned int i;
 
 	ether = netdev_priv(dev);
+	pdev = ether->pdev;
 
 	ether->tdesc = (struct tran_pdesc *)
-			dma_alloc_coherent(NULL, sizeof(struct tran_pdesc),
-				(dma_addr_t *)&ether->tdesc_phys, GFP_KERNEL);
+		dma_alloc_coherent(&pdev->dev, sizeof(struct tran_pdesc),
+					&ether->tdesc_phys, GFP_KERNEL);
+
+	if (!ether->tdesc) {
+		dev_err(&pdev->dev, "Failed to allocate memory for tx desc\n");
+		return -ENOMEM;
+	}
 
 	ether->rdesc = (struct recv_pdesc *)
-			dma_alloc_coherent(NULL, sizeof(struct recv_pdesc),
-				(dma_addr_t *)&ether->rdesc_phys, GFP_KERNEL);
+		dma_alloc_coherent(&pdev->dev, sizeof(struct recv_pdesc),
+					&ether->rdesc_phys, GFP_KERNEL);
+
+	if (!ether->rdesc) {
+		dev_err(&pdev->dev, "Failed to allocate memory for rx desc\n");
+		dma_free_coherent(&pdev->dev, sizeof(struct tran_pdesc),
+					ether->tdesc, ether->tdesc_phys);
+		return -ENOMEM;
+	}
 
 	for (i = 0; i < TX_DESC_SIZE; i++) {
-		tdesc = &(ether->tdesc->desclist[i]);
+		unsigned int offset;
 
-		j = ((i + 1) / TX_DESC_SIZE);
+		tdesc = &(ether->tdesc->desclist[i]);
 
-		if (j != 0) {
-			tdesc_phys = &(ether->tdesc_phys->desclist[0]);
-			ether->start_tx_ptr = (unsigned int)tdesc_phys;
-			tdesc->next = (unsigned int)ether->start_tx_ptr;
-		} else {
-			tdesc_phys = &(ether->tdesc_phys->desclist[i+1]);
-			tdesc->next = (unsigned int)tdesc_phys;
-		}
+		if (i == TX_DESC_SIZE - 1)
+			offset = offsetof(struct tran_pdesc, desclist[0]);
+		else
+			offset = offsetof(struct tran_pdesc, desclist[i + 1]);
 
-		tdesc->buffer = (unsigned int)ether->tdesc_phys->tran_buf[i];
+		tdesc->next = ether->tdesc_phys + offset;
+		tdesc->buffer = ether->tdesc_phys +
+			offsetof(struct tran_pdesc, tran_buf[i]);
 		tdesc->sl = 0;
 		tdesc->mode = 0;
 	}
 
+	ether->start_tx_ptr = ether->tdesc_phys;
+
 	for (i = 0; i < RX_DESC_SIZE; i++) {
-		rdesc = &(ether->rdesc->desclist[i]);
+		unsigned int offset;
 
-		j = ((i + 1) / RX_DESC_SIZE);
+		rdesc = &(ether->rdesc->desclist[i]);
 
-		if (j != 0) {
-			rdesc_phys = &(ether->rdesc_phys->desclist[0]);
-			ether->start_rx_ptr = (unsigned int)rdesc_phys;
-			rdesc->next = (unsigned int)ether->start_rx_ptr;
-		} else {
-			rdesc_phys = &(ether->rdesc_phys->desclist[i+1]);
-			rdesc->next = (unsigned int)rdesc_phys;
-		}
+		if (i == RX_DESC_SIZE - 1)
+			offset = offsetof(struct recv_pdesc, desclist[0]);
+		else
+			offset = offsetof(struct recv_pdesc, desclist[i + 1]);
 
+		rdesc->next = ether->rdesc_phys + offset;
 		rdesc->sl = RX_OWEN_DMA;
-		rdesc->buffer = (unsigned int)ether->rdesc_phys->recv_buf[i];
+		rdesc->buffer = ether->rdesc_phys +
+			offsetof(struct recv_pdesc, recv_buf[i]);
 	  }
+
+	ether->start_rx_ptr = ether->rdesc_phys;
+
+	return 0;
 }
 
 static void w90p910_set_fifo_threshold(struct net_device *dev)
@@ -552,11 +569,14 @@ static int w90p910_set_mac_address(struct net_device *dev, void *addr)
 static int w90p910_ether_close(struct net_device *dev)
 {
 	struct w90p910_ether *ether = netdev_priv(dev);
+	struct platform_device *pdev;
+
+	pdev = ether->pdev;
 
-	dma_free_writecombine(NULL, sizeof(struct w90p910_rxbd),
-				ether->rdesc, (dma_addr_t)ether->rdesc_phys);
-	dma_free_writecombine(NULL, sizeof(struct w90p910_txbd),
-				ether->tdesc, (dma_addr_t)ether->tdesc_phys);
+	dma_free_coherent(&pdev->dev, sizeof(struct recv_pdesc),
+					ether->rdesc, ether->rdesc_phys);
+	dma_free_coherent(&pdev->dev, sizeof(struct tran_pdesc),
+					ether->tdesc, ether->tdesc_phys);
 
 	netif_stop_queue(dev);
 
@@ -592,6 +612,7 @@ static int w90p910_send_frame(struct net_device *dev,
 
 	txbd = &ether->tdesc->desclist[ether->cur_tx];
 	buffer = ether->tdesc->tran_buf[ether->cur_tx];
+
 	if (length > 1514) {
 		dev_err(&pdev->dev, "send data %d bytes, check it\n", length);
 		length = 1514;
@@ -607,7 +628,9 @@ static int w90p910_send_frame(struct net_device *dev,
 
 	w90p910_trigger_tx(dev);
 
-	ether->cur_tx = (ether->cur_tx+1) % TX_DESC_SIZE;
+	if (++ether->cur_tx >= TX_DESC_SIZE)
+		ether->cur_tx = 0;
+
 	txbd = &ether->tdesc->desclist[ether->cur_tx];
 
 	dev->trans_start = jiffies;
@@ -635,7 +658,6 @@ static irqreturn_t w90p910_tx_interrupt(int irq, void *dev_id)
 	struct w90p910_ether *ether;
 	struct w90p910_txbd  *txbd;
 	struct platform_device *pdev;
-	struct tran_pdesc *tran_pdesc;
 	struct net_device *dev;
 	unsigned int cur_entry, entry, status;
 
@@ -647,13 +669,14 @@ static irqreturn_t w90p910_tx_interrupt(int irq, void *dev_id)
 
 	cur_entry = __raw_readl(ether->reg + REG_CTXDSA);
 
-	tran_pdesc = ether->tdesc_phys;
-	entry = (unsigned int)(&tran_pdesc->desclist[ether->finish_tx]);
+	entry = ether->tdesc_phys +
+		offsetof(struct tran_pdesc, desclist[ether->finish_tx]);
 
 	while (entry != cur_entry) {
 		txbd = &ether->tdesc->desclist[ether->finish_tx];
 
-		ether->finish_tx = (ether->finish_tx + 1) % TX_DESC_SIZE;
+		if (++ether->finish_tx >= TX_DESC_SIZE)
+			ether->finish_tx = 0;
 
 		if (txbd->sl & TXDS_TXCP) {
 			ether->stats.tx_packets++;
@@ -668,7 +691,8 @@ static irqreturn_t w90p910_tx_interrupt(int irq, void *dev_id)
 		if (netif_queue_stopped(dev))
 			netif_wake_queue(dev);
 
-		entry = (unsigned int)(&tran_pdesc->desclist[ether->finish_tx]);
+		entry = ether->tdesc_phys +
+			offsetof(struct tran_pdesc, desclist[ether->finish_tx]);
 	}
 
 	if (status & MISTA_EXDEF) {
@@ -689,20 +713,20 @@ static void netdev_rx(struct net_device *dev)
 	struct w90p910_ether *ether;
 	struct w90p910_rxbd *rxbd;
 	struct platform_device *pdev;
-	struct recv_pdesc *rdesc_phys;
 	struct sk_buff *skb;
 	unsigned char *data;
 	unsigned int length, status, val, entry;
 
 	ether = netdev_priv(dev);
 	pdev = ether->pdev;
-	rdesc_phys = ether->rdesc_phys;
 
 	rxbd = &ether->rdesc->desclist[ether->cur_rx];
 
 	do {
 		val = __raw_readl(ether->reg + REG_CRXDSA);
-		entry = (unsigned int)&rdesc_phys->desclist[ether->cur_rx];
+
+		entry = ether->rdesc_phys +
+			offsetof(struct recv_pdesc, desclist[ether->cur_rx]);
 
 		if (val == entry)
 			break;
@@ -747,7 +771,10 @@ static void netdev_rx(struct net_device *dev)
 
 		rxbd->sl = RX_OWEN_DMA;
 		rxbd->reserved = 0x0;
-		ether->cur_rx = (ether->cur_rx+1) % RX_DESC_SIZE;
+
+		if (++ether->cur_rx >= RX_DESC_SIZE)
+			ether->cur_rx = 0;
+
 		rxbd = &ether->rdesc->desclist[ether->cur_rx];
 
 		dev->last_rx = jiffies;
@@ -955,30 +982,29 @@ static int __devinit w90p910_ether_probe(struct platform_device *pdev)
 {
 	struct w90p910_ether *ether;
 	struct net_device *dev;
-	struct resource *res;
 	int error;
 
 	dev = alloc_etherdev(sizeof(struct w90p910_ether));
 	if (!dev)
 		return -ENOMEM;
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (res == NULL) {
+	ether = netdev_priv(dev);
+
+	ether->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (ether->res == NULL) {
 		dev_err(&pdev->dev, "failed to get I/O memory\n");
 		error = -ENXIO;
 		goto failed_free;
 	}
 
-	res = request_mem_region(res->start, resource_size(res), pdev->name);
-	if (res == NULL) {
+	if (!request_mem_region(ether->res->start,
+				resource_size(ether->res), pdev->name)) {
 		dev_err(&pdev->dev, "failed to request I/O memory\n");
 		error = -EBUSY;
 		goto failed_free;
 	}
 
-	ether = netdev_priv(dev);
-
-	ether->reg = ioremap(res->start, resource_size(res));
+	ether->reg = ioremap(ether->res->start, resource_size(ether->res));
 	if (ether->reg == NULL) {
 		dev_err(&pdev->dev, "failed to remap I/O memory\n");
 		error = -ENXIO;
@@ -1039,7 +1065,7 @@ failed_free_txirq:
 failed_free_io:
 	iounmap(ether->reg);
 failed_free_mem:
-	release_mem_region(res->start, resource_size(res));
+	release_mem_region(ether->res->start, resource_size(ether->res));
 failed_free:
 	free_netdev(dev);
 	return error;
@@ -1051,12 +1077,19 @@ static int __devexit w90p910_ether_remove(struct platform_device *pdev)
 	struct w90p910_ether *ether = netdev_priv(dev);
 
 	unregister_netdev(dev);
+
 	clk_put(ether->rmiiclk);
 	clk_put(ether->clk);
-	del_timer_sync(&ether->check_timer);
-	platform_set_drvdata(pdev, NULL);
+
+	iounmap(ether->reg);
+	release_mem_region(ether->res->start, resource_size(ether->res));
+
 	free_irq(ether->txirq, dev);
 	free_irq(ether->rxirq, dev);
+
+	del_timer_sync(&ether->check_timer);
+	platform_set_drvdata(pdev, NULL);
+
 	free_netdev(dev);
 	return 0;
 }
-- 
1.5.6.3

^ permalink raw reply related

* [PATCH] fixed up the previous mac driver for w90p910
From: Wan ZongShun @ 2009-07-23  4:18 UTC (permalink / raw)
  To: David Miller, Russell King; +Cc: soni.trilok, netdev, linux-arm-kernel
In-Reply-To: <20090720.105217.236487133.davem@davemloft.net>

Dear Russell&David,

Due to having a bit busy, when David has applied this mac patch,
however,I did not fix it based on comments as pointed by Russell.

So, I have to resubmit a new patch relative to previous patch.

patch text:

According to Russell's advice, I fixed up mac driver,
which relatives to previous mac driver patch, and the
evaluation board based on w90p910.

Signed-off-by: Wan ZongShun <mcuos.com@gmail.com>

diff --git a/drivers/net/arm/w90p910_ether.c b/drivers/net/arm/w90p910_ether.c
index 7b5f315..890716f 100644
--- a/drivers/net/arm/w90p910_ether.c
+++ b/drivers/net/arm/w90p910_ether.c
@@ -143,16 +143,17 @@ struct recv_pdesc {
 
 struct tran_pdesc {
 	struct w90p910_txbd desclist[TX_DESC_SIZE];
-	char tran_buf[RX_DESC_SIZE][MAX_TBUFF_SZ];
+	char tran_buf[TX_DESC_SIZE][MAX_TBUFF_SZ];
 };
 
 struct  w90p910_ether {
 	struct recv_pdesc *rdesc;
-	struct recv_pdesc *rdesc_phys;
 	struct tran_pdesc *tdesc;
-	struct tran_pdesc *tdesc_phys;
+	dma_addr_t rdesc_phys;
+	dma_addr_t tdesc_phys;
 	struct net_device_stats stats;
 	struct platform_device *pdev;
+	struct resource *res;
 	struct sk_buff *skb;
 	struct clk *clk;
 	struct clk *rmiiclk;
@@ -274,59 +275,75 @@ static void w90p910_write_cam(struct net_device *dev,
 	__raw_writel(msw, ether->reg + REG_CAMM_BASE + x * CAM_ENTRY_SIZE);
 }
 
-static void w90p910_init_desc(struct net_device *dev)
+static int w90p910_init_desc(struct net_device *dev)
 {
 	struct w90p910_ether *ether;
-	struct w90p910_txbd  *tdesc, *tdesc_phys;
-	struct w90p910_rxbd  *rdesc, *rdesc_phys;
-	unsigned int i, j;
+	struct w90p910_txbd  *tdesc;
+	struct w90p910_rxbd  *rdesc;
+	struct platform_device *pdev;
+	unsigned int i;
 
 	ether = netdev_priv(dev);
+	pdev = ether->pdev;
 
 	ether->tdesc = (struct tran_pdesc *)
-			dma_alloc_coherent(NULL, sizeof(struct tran_pdesc),
-				(dma_addr_t *)&ether->tdesc_phys, GFP_KERNEL);
+		dma_alloc_coherent(&pdev->dev, sizeof(struct tran_pdesc),
+					&ether->tdesc_phys, GFP_KERNEL);
+
+	if (!ether->tdesc) {
+		dev_err(&pdev->dev, "Failed to allocate memory for tx desc\n");
+		return -ENOMEM;
+	}
 
 	ether->rdesc = (struct recv_pdesc *)
-			dma_alloc_coherent(NULL, sizeof(struct recv_pdesc),
-				(dma_addr_t *)&ether->rdesc_phys, GFP_KERNEL);
+		dma_alloc_coherent(&pdev->dev, sizeof(struct recv_pdesc),
+					&ether->rdesc_phys, GFP_KERNEL);
+
+	if (!ether->rdesc) {
+		dev_err(&pdev->dev, "Failed to allocate memory for rx desc\n");
+		dma_free_coherent(&pdev->dev, sizeof(struct tran_pdesc),
+					ether->tdesc, ether->tdesc_phys);
+		return -ENOMEM;
+	}
 
 	for (i = 0; i < TX_DESC_SIZE; i++) {
-		tdesc = &(ether->tdesc->desclist[i]);
+		unsigned int offset;
 
-		j = ((i + 1) / TX_DESC_SIZE);
+		tdesc = &(ether->tdesc->desclist[i]);
 
-		if (j != 0) {
-			tdesc_phys = &(ether->tdesc_phys->desclist[0]);
-			ether->start_tx_ptr = (unsigned int)tdesc_phys;
-			tdesc->next = (unsigned int)ether->start_tx_ptr;
-		} else {
-			tdesc_phys = &(ether->tdesc_phys->desclist[i+1]);
-			tdesc->next = (unsigned int)tdesc_phys;
-		}
+		if (i == TX_DESC_SIZE - 1)
+			offset = offsetof(struct tran_pdesc, desclist[0]);
+		else
+			offset = offsetof(struct tran_pdesc, desclist[i + 1]);
 
-		tdesc->buffer = (unsigned int)ether->tdesc_phys->tran_buf[i];
+		tdesc->next = ether->tdesc_phys + offset;
+		tdesc->buffer = ether->tdesc_phys +
+			offsetof(struct tran_pdesc, tran_buf[i]);
 		tdesc->sl = 0;
 		tdesc->mode = 0;
 	}
 
+	ether->start_tx_ptr = ether->tdesc_phys;
+
 	for (i = 0; i < RX_DESC_SIZE; i++) {
-		rdesc = &(ether->rdesc->desclist[i]);
+		unsigned int offset;
 
-		j = ((i + 1) / RX_DESC_SIZE);
+		rdesc = &(ether->rdesc->desclist[i]);
 
-		if (j != 0) {
-			rdesc_phys = &(ether->rdesc_phys->desclist[0]);
-			ether->start_rx_ptr = (unsigned int)rdesc_phys;
-			rdesc->next = (unsigned int)ether->start_rx_ptr;
-		} else {
-			rdesc_phys = &(ether->rdesc_phys->desclist[i+1]);
-			rdesc->next = (unsigned int)rdesc_phys;
-		}
+		if (i == RX_DESC_SIZE - 1)
+			offset = offsetof(struct recv_pdesc, desclist[0]);
+		else
+			offset = offsetof(struct recv_pdesc, desclist[i + 1]);
 
+		rdesc->next = ether->rdesc_phys + offset;
 		rdesc->sl = RX_OWEN_DMA;
-		rdesc->buffer = (unsigned int)ether->rdesc_phys->recv_buf[i];
+		rdesc->buffer = ether->rdesc_phys +
+			offsetof(struct recv_pdesc, recv_buf[i]);
 	  }
+
+	ether->start_rx_ptr = ether->rdesc_phys;
+
+	return 0;
 }
 
 static void w90p910_set_fifo_threshold(struct net_device *dev)
@@ -552,11 +569,14 @@ static int w90p910_set_mac_address(struct net_device *dev, void *addr)
 static int w90p910_ether_close(struct net_device *dev)
 {
 	struct w90p910_ether *ether = netdev_priv(dev);
+	struct platform_device *pdev;
+
+	pdev = ether->pdev;
 
-	dma_free_writecombine(NULL, sizeof(struct w90p910_rxbd),
-				ether->rdesc, (dma_addr_t)ether->rdesc_phys);
-	dma_free_writecombine(NULL, sizeof(struct w90p910_txbd),
-				ether->tdesc, (dma_addr_t)ether->tdesc_phys);
+	dma_free_coherent(&pdev->dev, sizeof(struct recv_pdesc),
+					ether->rdesc, ether->rdesc_phys);
+	dma_free_coherent(&pdev->dev, sizeof(struct tran_pdesc),
+					ether->tdesc, ether->tdesc_phys);
 
 	netif_stop_queue(dev);
 
@@ -592,6 +612,7 @@ static int w90p910_send_frame(struct net_device *dev,
 
 	txbd = &ether->tdesc->desclist[ether->cur_tx];
 	buffer = ether->tdesc->tran_buf[ether->cur_tx];
+
 	if (length > 1514) {
 		dev_err(&pdev->dev, "send data %d bytes, check it\n", length);
 		length = 1514;
@@ -607,7 +628,9 @@ static int w90p910_send_frame(struct net_device *dev,
 
 	w90p910_trigger_tx(dev);
 
-	ether->cur_tx = (ether->cur_tx+1) % TX_DESC_SIZE;
+	if (++ether->cur_tx >= TX_DESC_SIZE)
+		ether->cur_tx = 0;
+
 	txbd = &ether->tdesc->desclist[ether->cur_tx];
 
 	dev->trans_start = jiffies;
@@ -635,7 +658,6 @@ static irqreturn_t w90p910_tx_interrupt(int irq, void *dev_id)
 	struct w90p910_ether *ether;
 	struct w90p910_txbd  *txbd;
 	struct platform_device *pdev;
-	struct tran_pdesc *tran_pdesc;
 	struct net_device *dev;
 	unsigned int cur_entry, entry, status;
 
@@ -647,13 +669,14 @@ static irqreturn_t w90p910_tx_interrupt(int irq, void *dev_id)
 
 	cur_entry = __raw_readl(ether->reg + REG_CTXDSA);
 
-	tran_pdesc = ether->tdesc_phys;
-	entry = (unsigned int)(&tran_pdesc->desclist[ether->finish_tx]);
+	entry = ether->tdesc_phys +
+		offsetof(struct tran_pdesc, desclist[ether->finish_tx]);
 
 	while (entry != cur_entry) {
 		txbd = &ether->tdesc->desclist[ether->finish_tx];
 
-		ether->finish_tx = (ether->finish_tx + 1) % TX_DESC_SIZE;
+		if (++ether->finish_tx >= TX_DESC_SIZE)
+			ether->finish_tx = 0;
 
 		if (txbd->sl & TXDS_TXCP) {
 			ether->stats.tx_packets++;
@@ -668,7 +691,8 @@ static irqreturn_t w90p910_tx_interrupt(int irq, void *dev_id)
 		if (netif_queue_stopped(dev))
 			netif_wake_queue(dev);
 
-		entry = (unsigned int)(&tran_pdesc->desclist[ether->finish_tx]);
+		entry = ether->tdesc_phys +
+			offsetof(struct tran_pdesc, desclist[ether->finish_tx]);
 	}
 
 	if (status & MISTA_EXDEF) {
@@ -689,20 +713,20 @@ static void netdev_rx(struct net_device *dev)
 	struct w90p910_ether *ether;
 	struct w90p910_rxbd *rxbd;
 	struct platform_device *pdev;
-	struct recv_pdesc *rdesc_phys;
 	struct sk_buff *skb;
 	unsigned char *data;
 	unsigned int length, status, val, entry;
 
 	ether = netdev_priv(dev);
 	pdev = ether->pdev;
-	rdesc_phys = ether->rdesc_phys;
 
 	rxbd = &ether->rdesc->desclist[ether->cur_rx];
 
 	do {
 		val = __raw_readl(ether->reg + REG_CRXDSA);
-		entry = (unsigned int)&rdesc_phys->desclist[ether->cur_rx];
+
+		entry = ether->rdesc_phys +
+			offsetof(struct recv_pdesc, desclist[ether->cur_rx]);
 
 		if (val == entry)
 			break;
@@ -747,7 +771,10 @@ static void netdev_rx(struct net_device *dev)
 
 		rxbd->sl = RX_OWEN_DMA;
 		rxbd->reserved = 0x0;
-		ether->cur_rx = (ether->cur_rx+1) % RX_DESC_SIZE;
+
+		if (++ether->cur_rx >= RX_DESC_SIZE)
+			ether->cur_rx = 0;
+
 		rxbd = &ether->rdesc->desclist[ether->cur_rx];
 
 		dev->last_rx = jiffies;
@@ -955,30 +982,29 @@ static int __devinit w90p910_ether_probe(struct platform_device *pdev)
 {
 	struct w90p910_ether *ether;
 	struct net_device *dev;
-	struct resource *res;
 	int error;
 
 	dev = alloc_etherdev(sizeof(struct w90p910_ether));
 	if (!dev)
 		return -ENOMEM;
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (res == NULL) {
+	ether = netdev_priv(dev);
+
+	ether->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (ether->res == NULL) {
 		dev_err(&pdev->dev, "failed to get I/O memory\n");
 		error = -ENXIO;
 		goto failed_free;
 	}
 
-	res = request_mem_region(res->start, resource_size(res), pdev->name);
-	if (res == NULL) {
+	if (!request_mem_region(ether->res->start,
+				resource_size(ether->res), pdev->name)) {
 		dev_err(&pdev->dev, "failed to request I/O memory\n");
 		error = -EBUSY;
 		goto failed_free;
 	}
 
-	ether = netdev_priv(dev);
-
-	ether->reg = ioremap(res->start, resource_size(res));
+	ether->reg = ioremap(ether->res->start, resource_size(ether->res));
 	if (ether->reg == NULL) {
 		dev_err(&pdev->dev, "failed to remap I/O memory\n");
 		error = -ENXIO;
@@ -1039,7 +1065,7 @@ failed_free_txirq:
 failed_free_io:
 	iounmap(ether->reg);
 failed_free_mem:
-	release_mem_region(res->start, resource_size(res));
+	release_mem_region(ether->res->start, resource_size(ether->res));
 failed_free:
 	free_netdev(dev);
 	return error;
@@ -1051,12 +1077,19 @@ static int __devexit w90p910_ether_remove(struct platform_device *pdev)
 	struct w90p910_ether *ether = netdev_priv(dev);
 
 	unregister_netdev(dev);
+
 	clk_put(ether->rmiiclk);
 	clk_put(ether->clk);
-	del_timer_sync(&ether->check_timer);
-	platform_set_drvdata(pdev, NULL);
+
+	iounmap(ether->reg);
+	release_mem_region(ether->res->start, resource_size(ether->res));
+
 	free_irq(ether->txirq, dev);
 	free_irq(ether->rxirq, dev);
+
+	del_timer_sync(&ether->check_timer);
+	platform_set_drvdata(pdev, NULL);
+
 	free_netdev(dev);
 	return 0;
 }
-- 
1.5.6.3


> From: Trilok Soni <soni.trilok@gmail.com>
> Date: Mon, 20 Jul 2009 23:19:38 +0530
> 
>> Hi David,
>>
>> On Mon, Jul 20, 2009 at 8:15 PM, David Miller<davem@davemloft.net> wrote:
>>> From: Wan ZongShun <mcuos.com@gmail.com>
>>> Date: Thu, 16 Jul 2009 20:55:05 +0800
>>>
>>>> Add mac driver support for evaluation board based on w90p910.
>>>>
>>>> Signed-off-by: Wan ZongShun <mcuos.com@gmail.com>
>>> Applied, thanks.
>> I thought Wan will send us the updated patch with fixing comments as
>> pointed by Russell.
>>
>> Wan, could you please send updated patch.
> 
> Send me a relative patch as I've already pushed this driver commit
> publicly and that cannot be undone without a lot of pain.
> 


^ permalink raw reply related


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