Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH] sky2:  receive dma mapping error handling
From: Jarek Poplawski @ 2010-02-01 20:41 UTC (permalink / raw)
  To: Stephen Hemminger
  Cc: Michael Breuer, David Miller, akpm, flyboy, linux-kernel, netdev,
	Michael Chan, Don Fry, Francois Romieu, Matt Carlson
In-Reply-To: <20100201201323.GA3096@del.dom.local>

On Mon, Feb 01, 2010 at 09:13:23PM +0100, Jarek Poplawski wrote:
> On Mon, Feb 01, 2010 at 10:20:18AM -0800, Stephen Hemminger wrote:
> > This fixes the fact that re->flags is always zero without causing
> > other confusion.
> 
> Actually, there is a slight confusion: after tx_init() slots #0 are
> skipped and waiting for tx_complete. Of course, no big deal, but no
> problem with fixing it too, so there is the main difference between

Hmm... On the other hand it could be fixed simpler by moving
sky2->tx_cons. I'll send v3.

Thanks,
Jarek P.

^ permalink raw reply

* Re: [PATCH] irda: remove BKL from irnet open function
From: Thadeu Lima de Souza Cascardo @ 2010-02-01 20:36 UTC (permalink / raw)
  To: John Kacur
  Cc: Arnd Bergmann, Samuel Ortiz, David S. Miller, linux-kernel,
	netdev
In-Reply-To: <520f0cf11002011232u415146a9md3afe65af4d810a6@mail.gmail.com>

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

On Mon, Feb 01, 2010 at 09:32:30PM +0100, John Kacur wrote:
> On Mon, Feb 1, 2010 at 7:18 PM, Thadeu Lima de Souza Cascardo
> <cascardo@holoscopio.com> wrote:
> > Commit cddf63d99d0d145f18b293c3d0de4af7dab2a922 has push down the BKL
> > into irnet open function. However, there's nothing that needs locking in
> > there.
> >
> > Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>
> > ---
> >  net/irda/irnet/irnet_ppp.c |    3 ---
> >  1 files changed, 0 insertions(+), 3 deletions(-)
> >
> > diff --git a/net/irda/irnet/irnet_ppp.c b/net/irda/irnet/irnet_ppp.c
> > index 156020d..d6b502c 100644
> > --- a/net/irda/irnet/irnet_ppp.c
> > +++ b/net/irda/irnet/irnet_ppp.c
> > @@ -479,7 +479,6 @@ dev_irnet_open(struct inode *       inode,
> >   ap = kzalloc(sizeof(*ap), GFP_KERNEL);
> >   DABORT(ap == NULL, -ENOMEM, FS_ERROR, "Can't allocate struct irnet...\n");
> >
> > -  lock_kernel();
> >   /* initialize the irnet structure */
> >   ap->file = file;
> >
> > @@ -501,7 +500,6 @@ dev_irnet_open(struct inode *       inode,
> >     {
> >       DERROR(FS_ERROR, "Can't setup IrDA link...\n");
> >       kfree(ap);
> > -      unlock_kernel();
> >       return err;
> >     }
> >
> > @@ -512,7 +510,6 @@ dev_irnet_open(struct inode *       inode,
> >   file->private_data = ap;
> >
> >   DEXIT(FS_TRACE, " - ap=0x%p\n", ap);
> > -  unlock_kernel();
> >   return 0;
> >  }
> >
> > --
> > 1.6.6.1
> 
> This is probably NOT safe to do, because the BKL is synchronizing the
> ioctl code.
> 
> Thanks

And is it possible that ioctl will be called before open returns? If it
is, then, yes, this is not safe. But I don't really believe the case. Or
is it?

Or is it only possible to happen with different struct file*? In that
case, open is only allocating and initializing the irnet_socket *ap.
Then, ioctl uses it. There is some race between the different ioctls,
but no race between open/ioctl for different opened devices. That is, a
process may open /dev/irnet while another process is issuing ioctls to
its own opened /dev/irnet.

Besides, dev_irnet_ioctl uses the file private_data to get to the
irnet_socket, which is the last thing the open call does. I assume doing
an attribution to a pointer is atomic in all architectures supported by
Linux currently, isn't it?

Regards,
Cascardo.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply

* Re: [PATCH] irda: remove BKL from irnet open function
From: John Kacur @ 2010-02-01 20:32 UTC (permalink / raw)
  To: Thadeu Lima de Souza Cascardo
  Cc: Arnd Bergmann, Samuel Ortiz, David S. Miller, linux-kernel,
	netdev
In-Reply-To: <1265048321-8097-1-git-send-email-cascardo@holoscopio.com>

On Mon, Feb 1, 2010 at 7:18 PM, Thadeu Lima de Souza Cascardo
<cascardo@holoscopio.com> wrote:
> Commit cddf63d99d0d145f18b293c3d0de4af7dab2a922 has push down the BKL
> into irnet open function. However, there's nothing that needs locking in
> there.
>
> Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>
> ---
>  net/irda/irnet/irnet_ppp.c |    3 ---
>  1 files changed, 0 insertions(+), 3 deletions(-)
>
> diff --git a/net/irda/irnet/irnet_ppp.c b/net/irda/irnet/irnet_ppp.c
> index 156020d..d6b502c 100644
> --- a/net/irda/irnet/irnet_ppp.c
> +++ b/net/irda/irnet/irnet_ppp.c
> @@ -479,7 +479,6 @@ dev_irnet_open(struct inode *       inode,
>   ap = kzalloc(sizeof(*ap), GFP_KERNEL);
>   DABORT(ap == NULL, -ENOMEM, FS_ERROR, "Can't allocate struct irnet...\n");
>
> -  lock_kernel();
>   /* initialize the irnet structure */
>   ap->file = file;
>
> @@ -501,7 +500,6 @@ dev_irnet_open(struct inode *       inode,
>     {
>       DERROR(FS_ERROR, "Can't setup IrDA link...\n");
>       kfree(ap);
> -      unlock_kernel();
>       return err;
>     }
>
> @@ -512,7 +510,6 @@ dev_irnet_open(struct inode *       inode,
>   file->private_data = ap;
>
>   DEXIT(FS_TRACE, " - ap=0x%p\n", ap);
> -  unlock_kernel();
>   return 0;
>  }
>
> --
> 1.6.6.1

This is probably NOT safe to do, because the BKL is synchronizing the
ioctl code.

Thanks

^ permalink raw reply

* Re: [net-next-2.6 v2] can: add support for CAN interface cards based on the PLX90xx PCI bridge
From: Wolfgang Grandegger @ 2010-02-01 20:31 UTC (permalink / raw)
  To: Ira W. Snyder
  Cc: Socketcan-core-0fE9KPoRgkgATYTw5x5z8w,
	netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20100201195611.GB32624-lulEs6mt1IksTUYHLfqkUA@public.gmane.org>

Ira W. Snyder wrote:
> On Tue, Feb 02, 2010 at 01:42:44AM +0600, Pavel B. Cheblakov wrote:
>> From: Pavel Cheblakov <P.B.Cheblakov-tHBF8D5G73F4OK5fxMSSsQ@public.gmane.org>
>>
>> This driver is for CAN interface cards based on the PLX90xx PCI bridge.
>> Driver supports now:
>>  - Adlink PCI-7841/cPCI-7841 card (http://www.adlinktech.com/)
>>  - Adlink PCI-7841/cPCI-7841 SE card
>>  - Marathon CAN-bus-PCI card (http://www.marathon.ru/)
>>  - TEWS TECHNOLOGIES TPMC810 card (http://www.tews.com/)
>>
>> Changes since v1:
>>  - Added some defines for static inline int plx_pci_check_sja1000(...)
>>  - static struct pci_device_id plx_pci_tbl[] replaced by
>>    static DEFINE_PCI_DEVICE_TABLE(plx_pci_tbl)
>>  - Typo fixed
>>
> 
> Hello,
> 
> Any ideas if this driver could support the Janz PCI CAN cards as well? I
> don't have any documentation for the cards, and I'd love to get away
> from their closed-source drivers.

Is it a passive or and intelligent CAN PCI card? What is the name of the
card? A intelligent card will run its own firmware and you do not have
direct access to the SJA1000. Pavel plx_pci driver is quite generic and
it should not be a big deal to support a PLX90xx based passive card.

Wolfgang.

Wolfgang.

^ permalink raw reply

* [PATCH net-next-2.6] cxgb3: add memory barriers
From: Divy Le Ray @ 2010-02-01 20:29 UTC (permalink / raw)
  To: davem; +Cc: netdev, linux-kernel, swise, wenxiong

From: Divy Le Ray <divy@chelsio.com>

Add memory barriers to fix crashes observed on newest PowerPC platforms.
The HW and driver state of the receive rings were getting out of sync.

Signed-off-by: Divy Le Ray <divy@chelsio.com>
---

 drivers/net/cxgb3/sge.c |   16 ++++++++++++----
 1 files changed, 12 insertions(+), 4 deletions(-)


diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c
index bdbd147..4cf9b79 100644
--- a/drivers/net/cxgb3/sge.c
+++ b/drivers/net/cxgb3/sge.c
@@ -480,6 +480,7 @@ static inline void ring_fl_db(struct adapter *adap, struct sge_fl *q)
 {
 	if (q->pend_cred >= q->credits / 4) {
 		q->pend_cred = 0;
+		wmb();
 		t3_write_reg(adap, A_SG_KDOORBELL, V_EGRCNTX(q->cntxt_id));
 	}
 }
@@ -2282,11 +2283,14 @@ static int process_responses(struct adapter *adap, struct sge_qset *qs,
 	while (likely(budget_left && is_new_response(r, q))) {
 		int packet_complete, eth, ethpad = 2, lro = qs->lro_enabled;
 		struct sk_buff *skb = NULL;
-		u32 len, flags = ntohl(r->flags);
-		__be32 rss_hi = *(const __be32 *)r,
-		       rss_lo = r->rss_hdr.rss_hash_val;
+		u32 len, flags;
+		__be32 rss_hi, rss_lo;
 
+		rmb();
 		eth = r->rss_hdr.opcode == CPL_RX_PKT;
+		rss_hi = *(const __be32 *)r;
+		rss_lo = r->rss_hdr.rss_hash_val;
+		flags = ntohl(r->flags);
 
 		if (unlikely(flags & F_RSPD_ASYNC_NOTIF)) {
 			skb = alloc_skb(AN_PKT_SIZE, GFP_ATOMIC);
@@ -2497,7 +2501,10 @@ static int process_pure_responses(struct adapter *adap, struct sge_qset *qs,
 			refill_rspq(adap, q, q->credits);
 			q->credits = 0;
 		}
-	} while (is_new_response(r, q) && is_pure_response(r));
+		if (!is_new_response(r, q))
+			break;
+		rmb();
+	} while (is_pure_response(r));
 
 	if (sleeping)
 		check_ring_db(adap, qs, sleeping);
@@ -2531,6 +2538,7 @@ static inline int handle_responses(struct adapter *adap, struct sge_rspq *q)
 
 	if (!is_new_response(r, q))
 		return -1;
+	rmb();
 	if (is_pure_response(r) && process_pure_responses(adap, qs, r) == 0) {
 		t3_write_reg(adap, A_SG_GTS, V_RSPQ(q->cntxt_id) |
 			     V_NEWTIMER(q->holdoff_tmr) | V_NEWINDEX(q->cidx));

^ permalink raw reply related

* Re: [PATCH] sky2:  receive dma mapping error handling
From: Jarek Poplawski @ 2010-02-01 20:13 UTC (permalink / raw)
  To: Stephen Hemminger
  Cc: Michael Breuer, David Miller, akpm, flyboy, linux-kernel, netdev,
	Michael Chan, Don Fry, Francois Romieu, Matt Carlson
In-Reply-To: <20100201102018.7b597992@nehalam>

On Mon, Feb 01, 2010 at 10:20:18AM -0800, Stephen Hemminger wrote:
> This fixes the fact that re->flags is always zero without causing
> other confusion.

Actually, there is a slight confusion: after tx_init() slots #0 are
skipped and waiting for tx_complete. Of course, no big deal, but no
problem with fixing it too, so there is the main difference between
these two patches. (Moving re->flags and re->skb initializations is
an optimization, but I tried to change only the buggy parts.)

Jarek P.

> 
> --- a/drivers/net/sky2.c	2010-02-01 10:07:42.676296236 -0800
> +++ b/drivers/net/sky2.c	2010-02-01 10:18:12.575044064 -0800
> @@ -1025,11 +1025,8 @@ static void sky2_prefetch_init(struct sk
>  static inline struct sky2_tx_le *get_tx_le(struct sky2_port *sky2, u16 *slot)
>  {
>  	struct sky2_tx_le *le = sky2->tx_le + *slot;
> -	struct tx_ring_info *re = sky2->tx_ring + *slot;
>  
>  	*slot = RING_NEXT(*slot, sky2->tx_ring_size);
> -	re->flags = 0;
> -	re->skb = NULL;
>  	le->ctrl = 0;
>  	return le;
>  }
> @@ -1622,8 +1619,7 @@ static unsigned tx_le_req(const struct s
>  	return count;
>  }
>  
> -static void sky2_tx_unmap(struct pci_dev *pdev,
> -			  const struct tx_ring_info *re)
> +static void sky2_tx_unmap(struct pci_dev *pdev, struct tx_ring_info *re)
>  {
>  	if (re->flags & TX_MAP_SINGLE)
>  		pci_unmap_single(pdev, pci_unmap_addr(re, mapaddr),
> @@ -1633,6 +1629,7 @@ static void sky2_tx_unmap(struct pci_dev
>  		pci_unmap_page(pdev, pci_unmap_addr(re, mapaddr),
>  			       pci_unmap_len(re, maplen),
>  			       PCI_DMA_TODEVICE);
> +	re->flags = 0;
>  }
>  
>  /*
> @@ -1839,6 +1836,7 @@ static void sky2_tx_complete(struct sky2
>  			dev->stats.tx_packets++;
>  			dev->stats.tx_bytes += skb->len;
>  
> +			re->skb = NULL;
>  			dev_kfree_skb_any(skb);
>  
>  			sky2->tx_next = RING_NEXT(idx, sky2->tx_ring_size);

^ permalink raw reply

* Re: [net-next-2.6 v2] can: add support for CAN interface cards based on the PLX90xx PCI bridge
From: Ira W. Snyder @ 2010-02-01 19:56 UTC (permalink / raw)
  To: Pavel B. Cheblakov; +Cc: netdev, Socketcan-core
In-Reply-To: <1265053364-24099-1-git-send-email-chebl@star.inp.nsk.su>

On Tue, Feb 02, 2010 at 01:42:44AM +0600, Pavel B. Cheblakov wrote:
> From: Pavel Cheblakov <P.B.Cheblakov@inp.nsk.su>
> 
> This driver is for CAN interface cards based on the PLX90xx PCI bridge.
> Driver supports now:
>  - Adlink PCI-7841/cPCI-7841 card (http://www.adlinktech.com/)
>  - Adlink PCI-7841/cPCI-7841 SE card
>  - Marathon CAN-bus-PCI card (http://www.marathon.ru/)
>  - TEWS TECHNOLOGIES TPMC810 card (http://www.tews.com/)
> 
> Changes since v1:
>  - Added some defines for static inline int plx_pci_check_sja1000(...)
>  - static struct pci_device_id plx_pci_tbl[] replaced by
>    static DEFINE_PCI_DEVICE_TABLE(plx_pci_tbl)
>  - Typo fixed
> 

Hello,

Any ideas if this driver could support the Janz PCI CAN cards as well? I
don't have any documentation for the cards, and I'd love to get away
from their closed-source drivers.

Here is the lspci output of two of these cards, if it helps:

iws@labcwdc ~ $ lspci -v -s 01:
01:0d.0 CANBUS: PLX Technology, Inc. PCI9030 32-bit 33MHz PCI <-> IOBus Bridge
	Subsystem: Janz Computer AG Device 0101
	Flags: medium devsel, IRQ 153
	Memory at febff800 (32-bit, non-prefetchable) [size=128]
	I/O ports at e880 [size=128]
	Memory at febfb000 (32-bit, non-prefetchable) [size=4K]
	Memory at febfa000 (32-bit, non-prefetchable) [size=4K]
	Memory at febf9000 (32-bit, non-prefetchable) [size=4K]
	Capabilities: <access denied>

01:0e.0 Bridge: PLX Technology, Inc. PCI <-> IOBus Bridge (rev 02)
	Subsystem: Janz Computer AG Device 0100
	Flags: medium devsel, IRQ 161
	Memory at febffc00 (32-bit, non-prefetchable) [size=128]
	I/O ports at ec00 [size=128]
	Memory at febfe000 (32-bit, non-prefetchable) [size=4K]
	Memory at febfd000 (32-bit, non-prefetchable) [size=4K]
	Memory at febfc000 (32-bit, non-prefetchable) [size=4K]
	Expansion ROM at 50000000 [disabled] [size=2K]

iws@labcwdc ~ $ lspci -v -s 01: -n
01:0d.0 0c09: 10b5:9030
	Subsystem: 13c3:0101
	Flags: medium devsel, IRQ 153
	Memory at febff800 (32-bit, non-prefetchable) [size=128]
	I/O ports at e880 [size=128]
	Memory at febfb000 (32-bit, non-prefetchable) [size=4K]
	Memory at febfa000 (32-bit, non-prefetchable) [size=4K]
	Memory at febf9000 (32-bit, non-prefetchable) [size=4K]
	Capabilities: <access denied>

01:0e.0 0680: 10b5:9050 (rev 02)
	Subsystem: 13c3:0100
	Flags: medium devsel, IRQ 161
	Memory at febffc00 (32-bit, non-prefetchable) [size=128]
	I/O ports at ec00 [size=128]
	Memory at febfe000 (32-bit, non-prefetchable) [size=4K]
	Memory at febfd000 (32-bit, non-prefetchable) [size=4K]
	Memory at febfc000 (32-bit, non-prefetchable) [size=4K]
	Expansion ROM at 50000000 [disabled] [size=2K]


Thanks,
Ira


> Signed-off-by: Pavel Cheblakov <P.B.Cheblakov@inp.nsk.su>
> Acked-by: Wolfgang Grandegger <wg@grandegger.com>
> ---
>  drivers/net/can/sja1000/Kconfig   |   12 +
>  drivers/net/can/sja1000/Makefile  |    1 +
>  drivers/net/can/sja1000/plx_pci.c |  472 +++++++++++++++++++++++++++++++++++++
>  3 files changed, 485 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/net/can/sja1000/plx_pci.c
> 
> diff --git a/drivers/net/can/sja1000/Kconfig b/drivers/net/can/sja1000/Kconfig
> index 4c67492..9e277d6 100644
> --- a/drivers/net/can/sja1000/Kconfig
> +++ b/drivers/net/can/sja1000/Kconfig
> @@ -44,4 +44,16 @@ config CAN_KVASER_PCI
>  	  This driver is for the the PCIcanx and PCIcan cards (1, 2 or
>  	  4 channel) from Kvaser (http://www.kvaser.com).
>  
> +config CAN_PLX_PCI
> +	tristate "PLX90xx PCI-bridge based Cards"
> +	depends on PCI
> +	---help---
> +	  This driver is for CAN interface cards based on
> +	  the PLX90xx PCI bridge.
> +	  Driver supports now:
> +	   - Adlink PCI-7841/cPCI-7841 card (http://www.adlinktech.com/)
> +	   - Adlink PCI-7841/cPCI-7841 SE card
> +	   - Marathon CAN-bus-PCI card (http://www.marathon.ru/)
> +	   - TEWS TECHNOLOGIES TPMC810 card (http://www.tews.com/)
> +
>  endif
> diff --git a/drivers/net/can/sja1000/Makefile b/drivers/net/can/sja1000/Makefile
> index 9d245ac..ce92455 100644
> --- a/drivers/net/can/sja1000/Makefile
> +++ b/drivers/net/can/sja1000/Makefile
> @@ -8,5 +8,6 @@ obj-$(CONFIG_CAN_SJA1000_PLATFORM) += sja1000_platform.o
>  obj-$(CONFIG_CAN_SJA1000_OF_PLATFORM) += sja1000_of_platform.o
>  obj-$(CONFIG_CAN_EMS_PCI) += ems_pci.o
>  obj-$(CONFIG_CAN_KVASER_PCI) += kvaser_pci.o
> +obj-$(CONFIG_CAN_PLX_PCI) += plx_pci.o
>  
>  ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
> diff --git a/drivers/net/can/sja1000/plx_pci.c b/drivers/net/can/sja1000/plx_pci.c
> new file mode 100644
> index 0000000..6b46a63
> --- /dev/null
> +++ b/drivers/net/can/sja1000/plx_pci.c
> @@ -0,0 +1,472 @@
> +/*
> + * Copyright (C) 2008-2010 Pavel Cheblakov <P.B.Cheblakov@inp.nsk.su>
> + *
> + * Derived from the ems_pci.c driver:
> + *	Copyright (C) 2007 Wolfgang Grandegger <wg@grandegger.com>
> + *	Copyright (C) 2008 Markus Plessing <plessing@ems-wuensche.com>
> + *	Copyright (C) 2008 Sebastian Haas <haas@ems-wuensche.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the version 2 of the GNU General Public License
> + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/interrupt.h>
> +#include <linux/netdevice.h>
> +#include <linux/delay.h>
> +#include <linux/pci.h>
> +#include <linux/can.h>
> +#include <linux/can/dev.h>
> +#include <linux/io.h>
> +
> +#include "sja1000.h"
> +
> +#define DRV_NAME  "sja1000_plx_pci"
> +
> +MODULE_AUTHOR("Pavel Cheblakov <P.B.Cheblakov@inp.nsk.su>");
> +MODULE_DESCRIPTION("Socket-CAN driver for PLX90xx PCI-bridge cards with "
> +		   "the SJA1000 chips");
> +MODULE_SUPPORTED_DEVICE("Adlink PCI-7841/cPCI-7841, "
> +			"Adlink PCI-7841/cPCI-7841 SE, "
> +			"Marathon CAN-bus-PCI, "
> +			"TEWS TECHNOLOGIES TPMC810");
> +MODULE_LICENSE("GPL v2");
> +
> +#define PLX_PCI_MAX_CHAN 2
> +
> +struct plx_pci_card {
> +	int channels;			/* detected channels count */
> +	struct net_device *net_dev[PLX_PCI_MAX_CHAN];
> +	void __iomem *conf_addr;
> +};
> +
> +#define PLX_PCI_CAN_CLOCK (16000000 / 2)
> +
> +/* PLX90xx registers */
> +#define PLX_INTCSR	0x4c		/* Interrupt Control/Status */
> +#define PLX_CNTRL	0x50		/* User I/O, Direct Slave Response,
> +					 * Serial EEPROM, and Initialization
> +					 * Control register
> +					 */
> +
> +#define PLX_LINT1_EN	0x1		/* Local interrupt 1 enable */
> +#define PLX_LINT2_EN	(1 << 3)	/* Local interrupt 2 enable */
> +#define PLX_PCI_INT_EN	(1 << 6)	/* PCI Interrupt Enable */
> +#define PLX_PCI_RESET	(1 << 30)	/* PCI Adapter Software Reset */
> +
> +/*
> + * The board configuration is probably following:
> + * RX1 is connected to ground.
> + * TX1 is not connected.
> + * CLKO is not connected.
> + * Setting the OCR register to 0xDA is a good idea.
> + * This means normal output mode, push-pull and the correct polarity.
> + */
> +#define PLX_PCI_OCR	(OCR_TX0_PUSHPULL | OCR_TX1_PUSHPULL)
> +
> +/*
> + * In the CDR register, you should set CBP to 1.
> + * You will probably also want to set the clock divider value to 7
> + * (meaning direct oscillator output) because the second SJA1000 chip
> + * is driven by the first one CLKOUT output.
> + */
> +#define PLX_PCI_CDR			(CDR_CBP | CDR_CLKOUT_MASK)
> +
> +/* SJA1000 Control Register in the BasicCAN Mode */
> +#define REG_CR				0x00
> +
> +/* States of some SJA1000 registers after hardware reset in the BasicCAN mode*/
> +#define REG_CR_BASICCAN_INITIAL		0x21
> +#define REG_CR_BASICCAN_INITIAL_MASK	0xa1
> +#define REG_SR_BASICCAN_INITIAL		0x0c
> +#define REG_IR_BASICCAN_INITIAL		0xe0
> +
> +/* States of some SJA1000 registers after hardware reset in the PeliCAN mode*/
> +#define REG_MOD_PELICAN_INITIAL		0x01
> +#define REG_SR_PELICAN_INITIAL		0x3c
> +#define REG_IR_PELICAN_INITIAL		0x00
> +
> +#define ADLINK_PCI_VENDOR_ID		0x144A
> +#define ADLINK_PCI_DEVICE_ID		0x7841
> +
> +#define MARATHON_PCI_DEVICE_ID		0x2715
> +
> +#define TEWS_PCI_VENDOR_ID		0x1498
> +#define TEWS_PCI_DEVICE_ID_TMPC810	0x032A
> +
> +static void plx_pci_reset_common(struct pci_dev *pdev);
> +static void plx_pci_reset_marathon(struct pci_dev *pdev);
> +
> +struct plx_pci_channel_map {
> +	u32 bar;
> +	u32 offset;
> +	u32 size;		/* 0x00 - auto, e.g. length of entire bar */
> +};
> +
> +struct plx_pci_card_info {
> +	const char *name;
> +	int channel_count;
> +	u32 can_clock;
> +	u8 ocr;			/* output control register */
> +	u8 cdr;			/* clock divider register */
> +
> +	/* Parameters for mapping local configuration space */
> +	struct plx_pci_channel_map conf_map;
> +
> +	/* Parameters for mapping the SJA1000 chips */
> +	struct plx_pci_channel_map chan_map_tbl[PLX_PCI_MAX_CHAN];
> +
> +	/* Pointer to device-dependent reset function */
> +	void (*reset_func)(struct pci_dev *pdev);
> +};
> +
> +static struct plx_pci_card_info plx_pci_card_info_adlink __devinitdata = {
> +	"Adlink PCI-7841/cPCI-7841", 2,
> +	PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
> +	{1, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x80, 0x80} },
> +	&plx_pci_reset_common
> +	/* based on PLX9052 */
> +};
> +
> +static struct plx_pci_card_info plx_pci_card_info_adlink_se __devinitdata = {
> +	"Adlink PCI-7841/cPCI-7841 SE", 2,
> +	PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
> +	{0, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x80, 0x80} },
> +	&plx_pci_reset_common
> +	/* based on PLX9052 */
> +};
> +
> +static struct plx_pci_card_info plx_pci_card_info_marathon __devinitdata = {
> +	"Marathon CAN-bus-PCI", 2,
> +	PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
> +	{0, 0x00, 0x00}, { {2, 0x00, 0x00}, {4, 0x00, 0x00} },
> +	&plx_pci_reset_marathon
> +	/* based on PLX9052 */
> +};
> +
> +static struct plx_pci_card_info plx_pci_card_info_tews __devinitdata = {
> +	"TEWS TECHNOLOGIES TPMC810", 2,
> +	PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
> +	{0, 0x00, 0x00}, { {2, 0x000, 0x80}, {2, 0x100, 0x80} },
> +	&plx_pci_reset_common
> +	/* based on PLX9030 */
> +};
> +
> +static DEFINE_PCI_DEVICE_TABLE(plx_pci_tbl) = {
> +	{
> +		/* Adlink PCI-7841/cPCI-7841 */
> +		ADLINK_PCI_VENDOR_ID, ADLINK_PCI_DEVICE_ID,
> +		PCI_ANY_ID, PCI_ANY_ID,
> +		PCI_CLASS_NETWORK_OTHER << 8, ~0,
> +		(kernel_ulong_t)&plx_pci_card_info_adlink
> +	},
> +	{
> +		/* Adlink PCI-7841/cPCI-7841 SE */
> +		ADLINK_PCI_VENDOR_ID, ADLINK_PCI_DEVICE_ID,
> +		PCI_ANY_ID, PCI_ANY_ID,
> +		PCI_CLASS_COMMUNICATION_OTHER << 8, ~0,
> +		(kernel_ulong_t)&plx_pci_card_info_adlink_se
> +	},
> +	{
> +		/* Marathon CAN-bus-PCI card */
> +		PCI_VENDOR_ID_PLX, MARATHON_PCI_DEVICE_ID,
> +		PCI_ANY_ID, PCI_ANY_ID,
> +		0, 0,
> +		(kernel_ulong_t)&plx_pci_card_info_marathon
> +	},
> +	{
> +		/* TEWS TECHNOLOGIES TPMC810 card */
> +		TEWS_PCI_VENDOR_ID, TEWS_PCI_DEVICE_ID_TMPC810,
> +		PCI_ANY_ID, PCI_ANY_ID,
> +		0, 0,
> +		(kernel_ulong_t)&plx_pci_card_info_tews
> +	},
> +	{ 0,}
> +};
> +MODULE_DEVICE_TABLE(pci, plx_pci_tbl);
> +
> +static u8 plx_pci_read_reg(const struct sja1000_priv *priv, int port)
> +{
> +	return ioread8(priv->reg_base + port);
> +}
> +
> +static void plx_pci_write_reg(const struct sja1000_priv *priv, int port, u8 val)
> +{
> +	iowrite8(val, priv->reg_base + port);
> +}
> +
> +/*
> + * Check if a CAN controller is present at the specified location
> + * by trying to switch 'em from the Basic mode into the PeliCAN mode.
> + * Also check states of some registers in reset mode.
> + */
> +static inline int plx_pci_check_sja1000(const struct sja1000_priv *priv)
> +{
> +	int flag = 0;
> +
> +	/*
> +	 * Check registers after hardware reset (the Basic mode)
> +	 * See states on p. 10 of the Datasheet.
> +	 */
> +	if ((priv->read_reg(priv, REG_CR) & REG_CR_BASICCAN_INITIAL_MASK) ==
> +	    REG_CR_BASICCAN_INITIAL &&
> +	    (priv->read_reg(priv, REG_SR) == REG_SR_BASICCAN_INITIAL) &&
> +	    (priv->read_reg(priv, REG_IR) == REG_IR_BASICCAN_INITIAL))
> +		flag = 1;
> +
> +	/* Bring the SJA1000 into the PeliCAN mode*/
> +	priv->write_reg(priv, REG_CDR, CDR_PELICAN);
> +
> +	/*
> +	 * Check registers after reset in the PeliCAN mode.
> +	 * See states on p. 23 of the Datasheet.
> +	 */
> +	if (priv->read_reg(priv, REG_MOD) == REG_MOD_PELICAN_INITIAL &&
> +	    priv->read_reg(priv, REG_SR) == REG_SR_PELICAN_INITIAL &&
> +	    priv->read_reg(priv, REG_IR) == REG_IR_PELICAN_INITIAL)
> +		return flag;
> +
> +	return 0;
> +}
> +
> +/*
> + * PLX90xx software reset
> + * Also LRESET# asserts and brings to reset device on the Local Bus (if wired).
> + * For most cards it's enough for reset the SJA1000 chips.
> + */
> +static void plx_pci_reset_common(struct pci_dev *pdev)
> +{
> +	struct plx_pci_card *card = pci_get_drvdata(pdev);
> +	u32 cntrl;
> +
> +	cntrl = ioread32(card->conf_addr + PLX_CNTRL);
> +	cntrl |= PLX_PCI_RESET;
> +	iowrite32(cntrl, card->conf_addr + PLX_CNTRL);
> +	udelay(100);
> +	cntrl ^= PLX_PCI_RESET;
> +	iowrite32(cntrl, card->conf_addr + PLX_CNTRL);
> +};
> +
> +/* Special reset function for Marathon card */
> +static void plx_pci_reset_marathon(struct pci_dev *pdev)
> +{
> +	void __iomem *reset_addr;
> +	int i;
> +	int reset_bar[2] = {3, 5};
> +
> +	plx_pci_reset_common(pdev);
> +
> +	for (i = 0; i < 2; i++) {
> +		reset_addr = pci_iomap(pdev, reset_bar[i], 0);
> +		if (!reset_addr) {
> +			dev_err(&pdev->dev, "Failed to remap reset "
> +				"space %d (BAR%d)\n", i, reset_bar[i]);
> +		} else {
> +			/* reset the SJA1000 chip */
> +			iowrite8(0x1, reset_addr);
> +			udelay(100);
> +			pci_iounmap(pdev, reset_addr);
> +		}
> +	}
> +}
> +
> +static void plx_pci_del_card(struct pci_dev *pdev)
> +{
> +	struct plx_pci_card *card = pci_get_drvdata(pdev);
> +	struct net_device *dev;
> +	struct sja1000_priv *priv;
> +	int i = 0;
> +
> +	for (i = 0; i < card->channels; i++) {
> +		dev = card->net_dev[i];
> +		if (!dev)
> +			continue;
> +
> +		dev_info(&pdev->dev, "Removing %s\n", dev->name);
> +		unregister_sja1000dev(dev);
> +		priv = netdev_priv(dev);
> +		if (priv->reg_base)
> +			pci_iounmap(pdev, priv->reg_base);
> +		free_sja1000dev(dev);
> +	}
> +
> +	plx_pci_reset_common(pdev);
> +
> +	/*
> +	 * Disable interrupts from PCI-card (PLX90xx) and disable Local_1,
> +	 * Local_2 interrupts
> +	 */
> +	iowrite32(0x0, card->conf_addr + PLX_INTCSR);
> +
> +	if (card->conf_addr)
> +		pci_iounmap(pdev, card->conf_addr);
> +
> +	kfree(card);
> +
> +	pci_disable_device(pdev);
> +	pci_set_drvdata(pdev, NULL);
> +}
> +
> +/*
> + * Probe PLX90xx based device for the SJA1000 chips and register each
> + * available CAN channel to SJA1000 Socket-CAN subsystem.
> + */
> +static int __devinit plx_pci_add_card(struct pci_dev *pdev,
> +				      const struct pci_device_id *ent)
> +{
> +	struct sja1000_priv *priv;
> +	struct net_device *dev;
> +	struct plx_pci_card *card;
> +	struct plx_pci_card_info *ci;
> +	int err, i;
> +	u32 val;
> +	void __iomem *addr;
> +
> +	ci = (struct plx_pci_card_info *)ent->driver_data;
> +
> +	if (pci_enable_device(pdev) < 0) {
> +		dev_err(&pdev->dev, "Failed to enable PCI device\n");
> +		return -ENODEV;
> +	}
> +
> +	dev_info(&pdev->dev, "Detected \"%s\" card at slot #%i\n",
> +		 ci->name, PCI_SLOT(pdev->devfn));
> +
> +	/* Allocate card structures to hold addresses, ... */
> +	card = kzalloc(sizeof(*card), GFP_KERNEL);
> +	if (!card) {
> +		dev_err(&pdev->dev, "Unable to allocate memory\n");
> +		pci_disable_device(pdev);
> +		return -ENOMEM;
> +	}
> +
> +	pci_set_drvdata(pdev, card);
> +
> +	card->channels = 0;
> +
> +	/* Remap PLX90xx configuration space */
> +	addr = pci_iomap(pdev, ci->conf_map.bar, ci->conf_map.size);
> +	if (!addr) {
> +		err = -ENOMEM;
> +		dev_err(&pdev->dev, "Failed to remap configuration space "
> +			"(BAR%d)\n", ci->conf_map.bar);
> +		goto failure_cleanup;
> +	}
> +	card->conf_addr = addr + ci->conf_map.offset;
> +
> +	ci->reset_func(pdev);
> +
> +	/* Detect available channels */
> +	for (i = 0; i < ci->channel_count; i++) {
> +		struct plx_pci_channel_map *cm = &ci->chan_map_tbl[i];
> +
> +		dev = alloc_sja1000dev(0);
> +		if (!dev) {
> +			err = -ENOMEM;
> +			goto failure_cleanup;
> +		}
> +
> +		card->net_dev[i] = dev;
> +		priv = netdev_priv(dev);
> +		priv->priv = card;
> +		priv->irq_flags = IRQF_SHARED;
> +
> +		dev->irq = pdev->irq;
> +
> +		/*
> +		 * Remap IO space of the SJA1000 chips
> +		 * This is device-dependent mapping
> +		 */
> +		addr = pci_iomap(pdev, cm->bar, cm->size);
> +		if (!addr) {
> +			err = -ENOMEM;
> +			dev_err(&pdev->dev, "Failed to remap BAR%d\n", cm->bar);
> +			goto failure_cleanup;
> +		}
> +
> +		priv->reg_base = addr + cm->offset;
> +		priv->read_reg = plx_pci_read_reg;
> +		priv->write_reg = plx_pci_write_reg;
> +
> +		/* Check if channel is present */
> +		if (plx_pci_check_sja1000(priv)) {
> +			priv->can.clock.freq = ci->can_clock;
> +			priv->ocr = ci->ocr;
> +			priv->cdr = ci->cdr;
> +
> +			SET_NETDEV_DEV(dev, &pdev->dev);
> +
> +			/* Register SJA1000 device */
> +			err = register_sja1000dev(dev);
> +			if (err) {
> +				dev_err(&pdev->dev, "Registering device failed "
> +					"(err=%d)\n", err);
> +				free_sja1000dev(dev);
> +				goto failure_cleanup;
> +			}
> +
> +			card->channels++;
> +
> +			dev_info(&pdev->dev, "Channel #%d at 0x%p, irq %d "
> +				 "registered as %s\n", i + 1, priv->reg_base,
> +				 dev->irq, dev->name);
> +		} else {
> +			dev_err(&pdev->dev, "Channel #%d not detected\n",
> +				i + 1);
> +			free_sja1000dev(dev);
> +		}
> +	}
> +
> +	if (!card->channels) {
> +		err = -ENODEV;
> +		goto failure_cleanup;
> +	}
> +
> +	/*
> +	 * Enable interrupts from PCI-card (PLX90xx) and enable Local_1,
> +	 * Local_2 interrupts from the SJA1000 chips
> +	 */
> +	val = ioread32(card->conf_addr + PLX_INTCSR);
> +	val |= PLX_LINT1_EN | PLX_LINT2_EN | PLX_PCI_INT_EN;
> +	iowrite32(val, card->conf_addr + PLX_INTCSR);
> +
> +	return 0;
> +
> +failure_cleanup:
> +	dev_err(&pdev->dev, "Error: %d. Cleaning Up.\n", err);
> +
> +	plx_pci_del_card(pdev);
> +
> +	return err;
> +}
> +
> +static struct pci_driver plx_pci_driver = {
> +	.name = DRV_NAME,
> +	.id_table = plx_pci_tbl,
> +	.probe = plx_pci_add_card,
> +	.remove = plx_pci_del_card,
> +};
> +
> +static int __init plx_pci_init(void)
> +{
> +	return pci_register_driver(&plx_pci_driver);
> +}
> +
> +static void __exit plx_pci_exit(void)
> +{
> +	pci_unregister_driver(&plx_pci_driver);
> +}
> +
> +module_init(plx_pci_init);
> +module_exit(plx_pci_exit);
> -- 
> 1.6.0.6
> 
> --
> 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

* [PATCH] net: CONFIG_COMPAT redux
From: Alexey Dobriyan @ 2010-02-01 19:44 UTC (permalink / raw)
  To: davem; +Cc: netdev

Ifdef out
	struct proto_ops::compat_ioctl
	struct proto_ops::compat_setsockopt
	struct proto_ops::compat_getsockopt
to make structures smaller on COMPAT=n kernels.

Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
---

 include/linux/net.h |    4 ++++
 1 file changed, 4 insertions(+)

--- a/include/linux/net.h
+++ b/include/linux/net.h
@@ -174,18 +174,22 @@ struct proto_ops {
 				      struct poll_table_struct *wait);
 	int		(*ioctl)     (struct socket *sock, unsigned int cmd,
 				      unsigned long arg);
+#ifdef CONFIG_COMPAT
 	int	 	(*compat_ioctl) (struct socket *sock, unsigned int cmd,
 				      unsigned long arg);
+#endif
 	int		(*listen)    (struct socket *sock, int len);
 	int		(*shutdown)  (struct socket *sock, int flags);
 	int		(*setsockopt)(struct socket *sock, int level,
 				      int optname, char __user *optval, unsigned int optlen);
 	int		(*getsockopt)(struct socket *sock, int level,
 				      int optname, char __user *optval, int __user *optlen);
+#ifdef CONFIG_COMPAT
 	int		(*compat_setsockopt)(struct socket *sock, int level,
 				      int optname, char __user *optval, unsigned int optlen);
 	int		(*compat_getsockopt)(struct socket *sock, int level,
 				      int optname, char __user *optval, int __user *optlen);
+#endif
 	int		(*sendmsg)   (struct kiocb *iocb, struct socket *sock,
 				      struct msghdr *m, size_t total_len);
 	int		(*recvmsg)   (struct kiocb *iocb, struct socket *sock,

^ permalink raw reply

* [net-next-2.6 v2] can: add support for CAN interface cards based on the PLX90xx PCI bridge
From: Pavel B. Cheblakov @ 2010-02-01 19:42 UTC (permalink / raw)
  To: netdev-u79uwXL29TY76Z2rM5mHXA; +Cc: Socketcan-core-0fE9KPoRgkgATYTw5x5z8w

From: Pavel Cheblakov <P.B.Cheblakov-tHBF8D5G73F4OK5fxMSSsQ@public.gmane.org>

This driver is for CAN interface cards based on the PLX90xx PCI bridge.
Driver supports now:
 - Adlink PCI-7841/cPCI-7841 card (http://www.adlinktech.com/)
 - Adlink PCI-7841/cPCI-7841 SE card
 - Marathon CAN-bus-PCI card (http://www.marathon.ru/)
 - TEWS TECHNOLOGIES TPMC810 card (http://www.tews.com/)

Changes since v1:
 - Added some defines for static inline int plx_pci_check_sja1000(...)
 - static struct pci_device_id plx_pci_tbl[] replaced by
   static DEFINE_PCI_DEVICE_TABLE(plx_pci_tbl)
 - Typo fixed

Signed-off-by: Pavel Cheblakov <P.B.Cheblakov-tHBF8D5G73F4OK5fxMSSsQ@public.gmane.org>
Acked-by: Wolfgang Grandegger <wg-5Yr1BZd7O62+XT7JhA+gdA@public.gmane.org>
---
 drivers/net/can/sja1000/Kconfig   |   12 +
 drivers/net/can/sja1000/Makefile  |    1 +
 drivers/net/can/sja1000/plx_pci.c |  472 +++++++++++++++++++++++++++++++++++++
 3 files changed, 485 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/can/sja1000/plx_pci.c

diff --git a/drivers/net/can/sja1000/Kconfig b/drivers/net/can/sja1000/Kconfig
index 4c67492..9e277d6 100644
--- a/drivers/net/can/sja1000/Kconfig
+++ b/drivers/net/can/sja1000/Kconfig
@@ -44,4 +44,16 @@ config CAN_KVASER_PCI
 	  This driver is for the the PCIcanx and PCIcan cards (1, 2 or
 	  4 channel) from Kvaser (http://www.kvaser.com).
 
+config CAN_PLX_PCI
+	tristate "PLX90xx PCI-bridge based Cards"
+	depends on PCI
+	---help---
+	  This driver is for CAN interface cards based on
+	  the PLX90xx PCI bridge.
+	  Driver supports now:
+	   - Adlink PCI-7841/cPCI-7841 card (http://www.adlinktech.com/)
+	   - Adlink PCI-7841/cPCI-7841 SE card
+	   - Marathon CAN-bus-PCI card (http://www.marathon.ru/)
+	   - TEWS TECHNOLOGIES TPMC810 card (http://www.tews.com/)
+
 endif
diff --git a/drivers/net/can/sja1000/Makefile b/drivers/net/can/sja1000/Makefile
index 9d245ac..ce92455 100644
--- a/drivers/net/can/sja1000/Makefile
+++ b/drivers/net/can/sja1000/Makefile
@@ -8,5 +8,6 @@ obj-$(CONFIG_CAN_SJA1000_PLATFORM) += sja1000_platform.o
 obj-$(CONFIG_CAN_SJA1000_OF_PLATFORM) += sja1000_of_platform.o
 obj-$(CONFIG_CAN_EMS_PCI) += ems_pci.o
 obj-$(CONFIG_CAN_KVASER_PCI) += kvaser_pci.o
+obj-$(CONFIG_CAN_PLX_PCI) += plx_pci.o
 
 ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
diff --git a/drivers/net/can/sja1000/plx_pci.c b/drivers/net/can/sja1000/plx_pci.c
new file mode 100644
index 0000000..6b46a63
--- /dev/null
+++ b/drivers/net/can/sja1000/plx_pci.c
@@ -0,0 +1,472 @@
+/*
+ * Copyright (C) 2008-2010 Pavel Cheblakov <P.B.Cheblakov-tHBF8D5G73F4OK5fxMSSsQ@public.gmane.org>
+ *
+ * Derived from the ems_pci.c driver:
+ *	Copyright (C) 2007 Wolfgang Grandegger <wg-5Yr1BZd7O62+XT7JhA+gdA@public.gmane.org>
+ *	Copyright (C) 2008 Markus Plessing <plessing-zsNKPWJ8Pib6hrUXjxyGrA@public.gmane.org>
+ *	Copyright (C) 2008 Sebastian Haas <haas-zsNKPWJ8Pib6hrUXjxyGrA@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include <linux/io.h>
+
+#include "sja1000.h"
+
+#define DRV_NAME  "sja1000_plx_pci"
+
+MODULE_AUTHOR("Pavel Cheblakov <P.B.Cheblakov-tHBF8D5G73F4OK5fxMSSsQ@public.gmane.org>");
+MODULE_DESCRIPTION("Socket-CAN driver for PLX90xx PCI-bridge cards with "
+		   "the SJA1000 chips");
+MODULE_SUPPORTED_DEVICE("Adlink PCI-7841/cPCI-7841, "
+			"Adlink PCI-7841/cPCI-7841 SE, "
+			"Marathon CAN-bus-PCI, "
+			"TEWS TECHNOLOGIES TPMC810");
+MODULE_LICENSE("GPL v2");
+
+#define PLX_PCI_MAX_CHAN 2
+
+struct plx_pci_card {
+	int channels;			/* detected channels count */
+	struct net_device *net_dev[PLX_PCI_MAX_CHAN];
+	void __iomem *conf_addr;
+};
+
+#define PLX_PCI_CAN_CLOCK (16000000 / 2)
+
+/* PLX90xx registers */
+#define PLX_INTCSR	0x4c		/* Interrupt Control/Status */
+#define PLX_CNTRL	0x50		/* User I/O, Direct Slave Response,
+					 * Serial EEPROM, and Initialization
+					 * Control register
+					 */
+
+#define PLX_LINT1_EN	0x1		/* Local interrupt 1 enable */
+#define PLX_LINT2_EN	(1 << 3)	/* Local interrupt 2 enable */
+#define PLX_PCI_INT_EN	(1 << 6)	/* PCI Interrupt Enable */
+#define PLX_PCI_RESET	(1 << 30)	/* PCI Adapter Software Reset */
+
+/*
+ * The board configuration is probably following:
+ * RX1 is connected to ground.
+ * TX1 is not connected.
+ * CLKO is not connected.
+ * Setting the OCR register to 0xDA is a good idea.
+ * This means normal output mode, push-pull and the correct polarity.
+ */
+#define PLX_PCI_OCR	(OCR_TX0_PUSHPULL | OCR_TX1_PUSHPULL)
+
+/*
+ * In the CDR register, you should set CBP to 1.
+ * You will probably also want to set the clock divider value to 7
+ * (meaning direct oscillator output) because the second SJA1000 chip
+ * is driven by the first one CLKOUT output.
+ */
+#define PLX_PCI_CDR			(CDR_CBP | CDR_CLKOUT_MASK)
+
+/* SJA1000 Control Register in the BasicCAN Mode */
+#define REG_CR				0x00
+
+/* States of some SJA1000 registers after hardware reset in the BasicCAN mode*/
+#define REG_CR_BASICCAN_INITIAL		0x21
+#define REG_CR_BASICCAN_INITIAL_MASK	0xa1
+#define REG_SR_BASICCAN_INITIAL		0x0c
+#define REG_IR_BASICCAN_INITIAL		0xe0
+
+/* States of some SJA1000 registers after hardware reset in the PeliCAN mode*/
+#define REG_MOD_PELICAN_INITIAL		0x01
+#define REG_SR_PELICAN_INITIAL		0x3c
+#define REG_IR_PELICAN_INITIAL		0x00
+
+#define ADLINK_PCI_VENDOR_ID		0x144A
+#define ADLINK_PCI_DEVICE_ID		0x7841
+
+#define MARATHON_PCI_DEVICE_ID		0x2715
+
+#define TEWS_PCI_VENDOR_ID		0x1498
+#define TEWS_PCI_DEVICE_ID_TMPC810	0x032A
+
+static void plx_pci_reset_common(struct pci_dev *pdev);
+static void plx_pci_reset_marathon(struct pci_dev *pdev);
+
+struct plx_pci_channel_map {
+	u32 bar;
+	u32 offset;
+	u32 size;		/* 0x00 - auto, e.g. length of entire bar */
+};
+
+struct plx_pci_card_info {
+	const char *name;
+	int channel_count;
+	u32 can_clock;
+	u8 ocr;			/* output control register */
+	u8 cdr;			/* clock divider register */
+
+	/* Parameters for mapping local configuration space */
+	struct plx_pci_channel_map conf_map;
+
+	/* Parameters for mapping the SJA1000 chips */
+	struct plx_pci_channel_map chan_map_tbl[PLX_PCI_MAX_CHAN];
+
+	/* Pointer to device-dependent reset function */
+	void (*reset_func)(struct pci_dev *pdev);
+};
+
+static struct plx_pci_card_info plx_pci_card_info_adlink __devinitdata = {
+	"Adlink PCI-7841/cPCI-7841", 2,
+	PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
+	{1, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x80, 0x80} },
+	&plx_pci_reset_common
+	/* based on PLX9052 */
+};
+
+static struct plx_pci_card_info plx_pci_card_info_adlink_se __devinitdata = {
+	"Adlink PCI-7841/cPCI-7841 SE", 2,
+	PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
+	{0, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x80, 0x80} },
+	&plx_pci_reset_common
+	/* based on PLX9052 */
+};
+
+static struct plx_pci_card_info plx_pci_card_info_marathon __devinitdata = {
+	"Marathon CAN-bus-PCI", 2,
+	PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
+	{0, 0x00, 0x00}, { {2, 0x00, 0x00}, {4, 0x00, 0x00} },
+	&plx_pci_reset_marathon
+	/* based on PLX9052 */
+};
+
+static struct plx_pci_card_info plx_pci_card_info_tews __devinitdata = {
+	"TEWS TECHNOLOGIES TPMC810", 2,
+	PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
+	{0, 0x00, 0x00}, { {2, 0x000, 0x80}, {2, 0x100, 0x80} },
+	&plx_pci_reset_common
+	/* based on PLX9030 */
+};
+
+static DEFINE_PCI_DEVICE_TABLE(plx_pci_tbl) = {
+	{
+		/* Adlink PCI-7841/cPCI-7841 */
+		ADLINK_PCI_VENDOR_ID, ADLINK_PCI_DEVICE_ID,
+		PCI_ANY_ID, PCI_ANY_ID,
+		PCI_CLASS_NETWORK_OTHER << 8, ~0,
+		(kernel_ulong_t)&plx_pci_card_info_adlink
+	},
+	{
+		/* Adlink PCI-7841/cPCI-7841 SE */
+		ADLINK_PCI_VENDOR_ID, ADLINK_PCI_DEVICE_ID,
+		PCI_ANY_ID, PCI_ANY_ID,
+		PCI_CLASS_COMMUNICATION_OTHER << 8, ~0,
+		(kernel_ulong_t)&plx_pci_card_info_adlink_se
+	},
+	{
+		/* Marathon CAN-bus-PCI card */
+		PCI_VENDOR_ID_PLX, MARATHON_PCI_DEVICE_ID,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0, 0,
+		(kernel_ulong_t)&plx_pci_card_info_marathon
+	},
+	{
+		/* TEWS TECHNOLOGIES TPMC810 card */
+		TEWS_PCI_VENDOR_ID, TEWS_PCI_DEVICE_ID_TMPC810,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0, 0,
+		(kernel_ulong_t)&plx_pci_card_info_tews
+	},
+	{ 0,}
+};
+MODULE_DEVICE_TABLE(pci, plx_pci_tbl);
+
+static u8 plx_pci_read_reg(const struct sja1000_priv *priv, int port)
+{
+	return ioread8(priv->reg_base + port);
+}
+
+static void plx_pci_write_reg(const struct sja1000_priv *priv, int port, u8 val)
+{
+	iowrite8(val, priv->reg_base + port);
+}
+
+/*
+ * Check if a CAN controller is present at the specified location
+ * by trying to switch 'em from the Basic mode into the PeliCAN mode.
+ * Also check states of some registers in reset mode.
+ */
+static inline int plx_pci_check_sja1000(const struct sja1000_priv *priv)
+{
+	int flag = 0;
+
+	/*
+	 * Check registers after hardware reset (the Basic mode)
+	 * See states on p. 10 of the Datasheet.
+	 */
+	if ((priv->read_reg(priv, REG_CR) & REG_CR_BASICCAN_INITIAL_MASK) ==
+	    REG_CR_BASICCAN_INITIAL &&
+	    (priv->read_reg(priv, REG_SR) == REG_SR_BASICCAN_INITIAL) &&
+	    (priv->read_reg(priv, REG_IR) == REG_IR_BASICCAN_INITIAL))
+		flag = 1;
+
+	/* Bring the SJA1000 into the PeliCAN mode*/
+	priv->write_reg(priv, REG_CDR, CDR_PELICAN);
+
+	/*
+	 * Check registers after reset in the PeliCAN mode.
+	 * See states on p. 23 of the Datasheet.
+	 */
+	if (priv->read_reg(priv, REG_MOD) == REG_MOD_PELICAN_INITIAL &&
+	    priv->read_reg(priv, REG_SR) == REG_SR_PELICAN_INITIAL &&
+	    priv->read_reg(priv, REG_IR) == REG_IR_PELICAN_INITIAL)
+		return flag;
+
+	return 0;
+}
+
+/*
+ * PLX90xx software reset
+ * Also LRESET# asserts and brings to reset device on the Local Bus (if wired).
+ * For most cards it's enough for reset the SJA1000 chips.
+ */
+static void plx_pci_reset_common(struct pci_dev *pdev)
+{
+	struct plx_pci_card *card = pci_get_drvdata(pdev);
+	u32 cntrl;
+
+	cntrl = ioread32(card->conf_addr + PLX_CNTRL);
+	cntrl |= PLX_PCI_RESET;
+	iowrite32(cntrl, card->conf_addr + PLX_CNTRL);
+	udelay(100);
+	cntrl ^= PLX_PCI_RESET;
+	iowrite32(cntrl, card->conf_addr + PLX_CNTRL);
+};
+
+/* Special reset function for Marathon card */
+static void plx_pci_reset_marathon(struct pci_dev *pdev)
+{
+	void __iomem *reset_addr;
+	int i;
+	int reset_bar[2] = {3, 5};
+
+	plx_pci_reset_common(pdev);
+
+	for (i = 0; i < 2; i++) {
+		reset_addr = pci_iomap(pdev, reset_bar[i], 0);
+		if (!reset_addr) {
+			dev_err(&pdev->dev, "Failed to remap reset "
+				"space %d (BAR%d)\n", i, reset_bar[i]);
+		} else {
+			/* reset the SJA1000 chip */
+			iowrite8(0x1, reset_addr);
+			udelay(100);
+			pci_iounmap(pdev, reset_addr);
+		}
+	}
+}
+
+static void plx_pci_del_card(struct pci_dev *pdev)
+{
+	struct plx_pci_card *card = pci_get_drvdata(pdev);
+	struct net_device *dev;
+	struct sja1000_priv *priv;
+	int i = 0;
+
+	for (i = 0; i < card->channels; i++) {
+		dev = card->net_dev[i];
+		if (!dev)
+			continue;
+
+		dev_info(&pdev->dev, "Removing %s\n", dev->name);
+		unregister_sja1000dev(dev);
+		priv = netdev_priv(dev);
+		if (priv->reg_base)
+			pci_iounmap(pdev, priv->reg_base);
+		free_sja1000dev(dev);
+	}
+
+	plx_pci_reset_common(pdev);
+
+	/*
+	 * Disable interrupts from PCI-card (PLX90xx) and disable Local_1,
+	 * Local_2 interrupts
+	 */
+	iowrite32(0x0, card->conf_addr + PLX_INTCSR);
+
+	if (card->conf_addr)
+		pci_iounmap(pdev, card->conf_addr);
+
+	kfree(card);
+
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+}
+
+/*
+ * Probe PLX90xx based device for the SJA1000 chips and register each
+ * available CAN channel to SJA1000 Socket-CAN subsystem.
+ */
+static int __devinit plx_pci_add_card(struct pci_dev *pdev,
+				      const struct pci_device_id *ent)
+{
+	struct sja1000_priv *priv;
+	struct net_device *dev;
+	struct plx_pci_card *card;
+	struct plx_pci_card_info *ci;
+	int err, i;
+	u32 val;
+	void __iomem *addr;
+
+	ci = (struct plx_pci_card_info *)ent->driver_data;
+
+	if (pci_enable_device(pdev) < 0) {
+		dev_err(&pdev->dev, "Failed to enable PCI device\n");
+		return -ENODEV;
+	}
+
+	dev_info(&pdev->dev, "Detected \"%s\" card at slot #%i\n",
+		 ci->name, PCI_SLOT(pdev->devfn));
+
+	/* Allocate card structures to hold addresses, ... */
+	card = kzalloc(sizeof(*card), GFP_KERNEL);
+	if (!card) {
+		dev_err(&pdev->dev, "Unable to allocate memory\n");
+		pci_disable_device(pdev);
+		return -ENOMEM;
+	}
+
+	pci_set_drvdata(pdev, card);
+
+	card->channels = 0;
+
+	/* Remap PLX90xx configuration space */
+	addr = pci_iomap(pdev, ci->conf_map.bar, ci->conf_map.size);
+	if (!addr) {
+		err = -ENOMEM;
+		dev_err(&pdev->dev, "Failed to remap configuration space "
+			"(BAR%d)\n", ci->conf_map.bar);
+		goto failure_cleanup;
+	}
+	card->conf_addr = addr + ci->conf_map.offset;
+
+	ci->reset_func(pdev);
+
+	/* Detect available channels */
+	for (i = 0; i < ci->channel_count; i++) {
+		struct plx_pci_channel_map *cm = &ci->chan_map_tbl[i];
+
+		dev = alloc_sja1000dev(0);
+		if (!dev) {
+			err = -ENOMEM;
+			goto failure_cleanup;
+		}
+
+		card->net_dev[i] = dev;
+		priv = netdev_priv(dev);
+		priv->priv = card;
+		priv->irq_flags = IRQF_SHARED;
+
+		dev->irq = pdev->irq;
+
+		/*
+		 * Remap IO space of the SJA1000 chips
+		 * This is device-dependent mapping
+		 */
+		addr = pci_iomap(pdev, cm->bar, cm->size);
+		if (!addr) {
+			err = -ENOMEM;
+			dev_err(&pdev->dev, "Failed to remap BAR%d\n", cm->bar);
+			goto failure_cleanup;
+		}
+
+		priv->reg_base = addr + cm->offset;
+		priv->read_reg = plx_pci_read_reg;
+		priv->write_reg = plx_pci_write_reg;
+
+		/* Check if channel is present */
+		if (plx_pci_check_sja1000(priv)) {
+			priv->can.clock.freq = ci->can_clock;
+			priv->ocr = ci->ocr;
+			priv->cdr = ci->cdr;
+
+			SET_NETDEV_DEV(dev, &pdev->dev);
+
+			/* Register SJA1000 device */
+			err = register_sja1000dev(dev);
+			if (err) {
+				dev_err(&pdev->dev, "Registering device failed "
+					"(err=%d)\n", err);
+				free_sja1000dev(dev);
+				goto failure_cleanup;
+			}
+
+			card->channels++;
+
+			dev_info(&pdev->dev, "Channel #%d at 0x%p, irq %d "
+				 "registered as %s\n", i + 1, priv->reg_base,
+				 dev->irq, dev->name);
+		} else {
+			dev_err(&pdev->dev, "Channel #%d not detected\n",
+				i + 1);
+			free_sja1000dev(dev);
+		}
+	}
+
+	if (!card->channels) {
+		err = -ENODEV;
+		goto failure_cleanup;
+	}
+
+	/*
+	 * Enable interrupts from PCI-card (PLX90xx) and enable Local_1,
+	 * Local_2 interrupts from the SJA1000 chips
+	 */
+	val = ioread32(card->conf_addr + PLX_INTCSR);
+	val |= PLX_LINT1_EN | PLX_LINT2_EN | PLX_PCI_INT_EN;
+	iowrite32(val, card->conf_addr + PLX_INTCSR);
+
+	return 0;
+
+failure_cleanup:
+	dev_err(&pdev->dev, "Error: %d. Cleaning Up.\n", err);
+
+	plx_pci_del_card(pdev);
+
+	return err;
+}
+
+static struct pci_driver plx_pci_driver = {
+	.name = DRV_NAME,
+	.id_table = plx_pci_tbl,
+	.probe = plx_pci_add_card,
+	.remove = plx_pci_del_card,
+};
+
+static int __init plx_pci_init(void)
+{
+	return pci_register_driver(&plx_pci_driver);
+}
+
+static void __exit plx_pci_exit(void)
+{
+	pci_unregister_driver(&plx_pci_driver);
+}
+
+module_init(plx_pci_init);
+module_exit(plx_pci_exit);
-- 
1.6.0.6

^ permalink raw reply related

* RE: [net-next-2.6 PATCH 2/5] if_link: Add SR-IOV configuration methods
From: Williams, Mitch A @ 2010-02-01 19:33 UTC (permalink / raw)
  To: Or Gerlitz, Kirsher, Jeffrey T
  Cc: davem@davemloft.net, netdev@vger.kernel.org, gospo@redhat.com,
	Or Gerlitz
In-Reply-To: <15ddcffd1001310625k3a1c1010w57e7cf62986c56ef@mail.gmail.com>

>From: Or Gerlitz [mailto:or.gerlitz@gmail.com]
>Sent: Sunday, January 31, 2010 6:26 AM


>In the same manner that vconfig does for 8021q devices, except for VID
>there's a need
>to let the user control on the egress qos mapping (vlan priority bits)
>per VF (I don't think it
>need to go per skb priority). Where for NIC HW which supports setting
>the VID only, the
>packets will be marked with a default priority.

To be honest, Or, this completely slipped my mind. I'll add it to my
to-do list.

If it's OK with you, I'd prefer to get this set of patches in as-is and
add the egress qos stuff later. A lot of people have been asking for
these patches, so I'd rather not delay for this feature.

-Mitch

^ permalink raw reply

* [net-next-2.6 v2] can: add support for CAN interface cards based on the PLX90xx PCI bridge
From: Pavel Cheblakov @ 2010-02-01 19:30 UTC (permalink / raw)
  To: netdev; +Cc: Pavel Cheblakov, Socketcan-core

This driver is for CAN interface cards based on the PLX90xx PCI bridge.
Driver supports now:
 - Adlink PCI-7841/cPCI-7841 card (http://www.adlinktech.com/)
 - Adlink PCI-7841/cPCI-7841 SE card
 - Marathon CAN-bus-PCI card (http://www.marathon.ru/)
 - TEWS TECHNOLOGIES TPMC810 card (http://www.tews.com/)

Changes since v1:
 - Added some defines for static inline int plx_pci_check_sja1000(...)
 - static struct pci_device_id plx_pci_tbl[] replaced by
   static DEFINE_PCI_DEVICE_TABLE(plx_pci_tbl)
 - Typo fixed

Signed-off-by: Pavel Cheblakov <P.B.Cheblakov@inp.nsk.su>
Acked-by: Wolfgang Grandegger <wg@grandegger.com>
---
 drivers/net/can/sja1000/Kconfig   |   12 +
 drivers/net/can/sja1000/Makefile  |    1 +
 drivers/net/can/sja1000/plx_pci.c |  472 +++++++++++++++++++++++++++++++++++++
 3 files changed, 485 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/can/sja1000/plx_pci.c

diff --git a/drivers/net/can/sja1000/Kconfig b/drivers/net/can/sja1000/Kconfig
index 4c67492..9e277d6 100644
--- a/drivers/net/can/sja1000/Kconfig
+++ b/drivers/net/can/sja1000/Kconfig
@@ -44,4 +44,16 @@ config CAN_KVASER_PCI
 	  This driver is for the the PCIcanx and PCIcan cards (1, 2 or
 	  4 channel) from Kvaser (http://www.kvaser.com).
 
+config CAN_PLX_PCI
+	tristate "PLX90xx PCI-bridge based Cards"
+	depends on PCI
+	---help---
+	  This driver is for CAN interface cards based on
+	  the PLX90xx PCI bridge.
+	  Driver supports now:
+	   - Adlink PCI-7841/cPCI-7841 card (http://www.adlinktech.com/)
+	   - Adlink PCI-7841/cPCI-7841 SE card
+	   - Marathon CAN-bus-PCI card (http://www.marathon.ru/)
+	   - TEWS TECHNOLOGIES TPMC810 card (http://www.tews.com/)
+
 endif
diff --git a/drivers/net/can/sja1000/Makefile b/drivers/net/can/sja1000/Makefile
index 9d245ac..ce92455 100644
--- a/drivers/net/can/sja1000/Makefile
+++ b/drivers/net/can/sja1000/Makefile
@@ -8,5 +8,6 @@ obj-$(CONFIG_CAN_SJA1000_PLATFORM) += sja1000_platform.o
 obj-$(CONFIG_CAN_SJA1000_OF_PLATFORM) += sja1000_of_platform.o
 obj-$(CONFIG_CAN_EMS_PCI) += ems_pci.o
 obj-$(CONFIG_CAN_KVASER_PCI) += kvaser_pci.o
+obj-$(CONFIG_CAN_PLX_PCI) += plx_pci.o
 
 ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
diff --git a/drivers/net/can/sja1000/plx_pci.c b/drivers/net/can/sja1000/plx_pci.c
new file mode 100644
index 0000000..6b46a63
--- /dev/null
+++ b/drivers/net/can/sja1000/plx_pci.c
@@ -0,0 +1,472 @@
+/*
+ * Copyright (C) 2008-2010 Pavel Cheblakov <P.B.Cheblakov@inp.nsk.su>
+ *
+ * Derived from the ems_pci.c driver:
+ *	Copyright (C) 2007 Wolfgang Grandegger <wg@grandegger.com>
+ *	Copyright (C) 2008 Markus Plessing <plessing@ems-wuensche.com>
+ *	Copyright (C) 2008 Sebastian Haas <haas@ems-wuensche.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include <linux/io.h>
+
+#include "sja1000.h"
+
+#define DRV_NAME  "sja1000_plx_pci"
+
+MODULE_AUTHOR("Pavel Cheblakov <P.B.Cheblakov@inp.nsk.su>");
+MODULE_DESCRIPTION("Socket-CAN driver for PLX90xx PCI-bridge cards with "
+		   "the SJA1000 chips");
+MODULE_SUPPORTED_DEVICE("Adlink PCI-7841/cPCI-7841, "
+			"Adlink PCI-7841/cPCI-7841 SE, "
+			"Marathon CAN-bus-PCI, "
+			"TEWS TECHNOLOGIES TPMC810");
+MODULE_LICENSE("GPL v2");
+
+#define PLX_PCI_MAX_CHAN 2
+
+struct plx_pci_card {
+	int channels;			/* detected channels count */
+	struct net_device *net_dev[PLX_PCI_MAX_CHAN];
+	void __iomem *conf_addr;
+};
+
+#define PLX_PCI_CAN_CLOCK (16000000 / 2)
+
+/* PLX90xx registers */
+#define PLX_INTCSR	0x4c		/* Interrupt Control/Status */
+#define PLX_CNTRL	0x50		/* User I/O, Direct Slave Response,
+					 * Serial EEPROM, and Initialization
+					 * Control register
+					 */
+
+#define PLX_LINT1_EN	0x1		/* Local interrupt 1 enable */
+#define PLX_LINT2_EN	(1 << 3)	/* Local interrupt 2 enable */
+#define PLX_PCI_INT_EN	(1 << 6)	/* PCI Interrupt Enable */
+#define PLX_PCI_RESET	(1 << 30)	/* PCI Adapter Software Reset */
+
+/*
+ * The board configuration is probably following:
+ * RX1 is connected to ground.
+ * TX1 is not connected.
+ * CLKO is not connected.
+ * Setting the OCR register to 0xDA is a good idea.
+ * This means normal output mode, push-pull and the correct polarity.
+ */
+#define PLX_PCI_OCR	(OCR_TX0_PUSHPULL | OCR_TX1_PUSHPULL)
+
+/*
+ * In the CDR register, you should set CBP to 1.
+ * You will probably also want to set the clock divider value to 7
+ * (meaning direct oscillator output) because the second SJA1000 chip
+ * is driven by the first one CLKOUT output.
+ */
+#define PLX_PCI_CDR			(CDR_CBP | CDR_CLKOUT_MASK)
+
+/* SJA1000 Control Register in the BasicCAN Mode */
+#define REG_CR				0x00
+
+/* States of some SJA1000 registers after hardware reset in the BasicCAN mode*/
+#define REG_CR_BASICCAN_INITIAL		0x21
+#define REG_CR_BASICCAN_INITIAL_MASK	0xa1
+#define REG_SR_BASICCAN_INITIAL		0x0c
+#define REG_IR_BASICCAN_INITIAL		0xe0
+
+/* States of some SJA1000 registers after hardware reset in the PeliCAN mode*/
+#define REG_MOD_PELICAN_INITIAL		0x01
+#define REG_SR_PELICAN_INITIAL		0x3c
+#define REG_IR_PELICAN_INITIAL		0x00
+
+#define ADLINK_PCI_VENDOR_ID		0x144A
+#define ADLINK_PCI_DEVICE_ID		0x7841
+
+#define MARATHON_PCI_DEVICE_ID		0x2715
+
+#define TEWS_PCI_VENDOR_ID		0x1498
+#define TEWS_PCI_DEVICE_ID_TMPC810	0x032A
+
+static void plx_pci_reset_common(struct pci_dev *pdev);
+static void plx_pci_reset_marathon(struct pci_dev *pdev);
+
+struct plx_pci_channel_map {
+	u32 bar;
+	u32 offset;
+	u32 size;		/* 0x00 - auto, e.g. length of entire bar */
+};
+
+struct plx_pci_card_info {
+	const char *name;
+	int channel_count;
+	u32 can_clock;
+	u8 ocr;			/* output control register */
+	u8 cdr;			/* clock divider register */
+
+	/* Parameters for mapping local configuration space */
+	struct plx_pci_channel_map conf_map;
+
+	/* Parameters for mapping the SJA1000 chips */
+	struct plx_pci_channel_map chan_map_tbl[PLX_PCI_MAX_CHAN];
+
+	/* Pointer to device-dependent reset function */
+	void (*reset_func)(struct pci_dev *pdev);
+};
+
+static struct plx_pci_card_info plx_pci_card_info_adlink __devinitdata = {
+	"Adlink PCI-7841/cPCI-7841", 2,
+	PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
+	{1, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x80, 0x80} },
+	&plx_pci_reset_common
+	/* based on PLX9052 */
+};
+
+static struct plx_pci_card_info plx_pci_card_info_adlink_se __devinitdata = {
+	"Adlink PCI-7841/cPCI-7841 SE", 2,
+	PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
+	{0, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x80, 0x80} },
+	&plx_pci_reset_common
+	/* based on PLX9052 */
+};
+
+static struct plx_pci_card_info plx_pci_card_info_marathon __devinitdata = {
+	"Marathon CAN-bus-PCI", 2,
+	PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
+	{0, 0x00, 0x00}, { {2, 0x00, 0x00}, {4, 0x00, 0x00} },
+	&plx_pci_reset_marathon
+	/* based on PLX9052 */
+};
+
+static struct plx_pci_card_info plx_pci_card_info_tews __devinitdata = {
+	"TEWS TECHNOLOGIES TPMC810", 2,
+	PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
+	{0, 0x00, 0x00}, { {2, 0x000, 0x80}, {2, 0x100, 0x80} },
+	&plx_pci_reset_common
+	/* based on PLX9030 */
+};
+
+static DEFINE_PCI_DEVICE_TABLE(plx_pci_tbl) = {
+	{
+		/* Adlink PCI-7841/cPCI-7841 */
+		ADLINK_PCI_VENDOR_ID, ADLINK_PCI_DEVICE_ID,
+		PCI_ANY_ID, PCI_ANY_ID,
+		PCI_CLASS_NETWORK_OTHER << 8, ~0,
+		(kernel_ulong_t)&plx_pci_card_info_adlink
+	},
+	{
+		/* Adlink PCI-7841/cPCI-7841 SE */
+		ADLINK_PCI_VENDOR_ID, ADLINK_PCI_DEVICE_ID,
+		PCI_ANY_ID, PCI_ANY_ID,
+		PCI_CLASS_COMMUNICATION_OTHER << 8, ~0,
+		(kernel_ulong_t)&plx_pci_card_info_adlink_se
+	},
+	{
+		/* Marathon CAN-bus-PCI card */
+		PCI_VENDOR_ID_PLX, MARATHON_PCI_DEVICE_ID,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0, 0,
+		(kernel_ulong_t)&plx_pci_card_info_marathon
+	},
+	{
+		/* TEWS TECHNOLOGIES TPMC810 card */
+		TEWS_PCI_VENDOR_ID, TEWS_PCI_DEVICE_ID_TMPC810,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0, 0,
+		(kernel_ulong_t)&plx_pci_card_info_tews
+	},
+	{ 0,}
+};
+MODULE_DEVICE_TABLE(pci, plx_pci_tbl);
+
+static u8 plx_pci_read_reg(const struct sja1000_priv *priv, int port)
+{
+	return ioread8(priv->reg_base + port);
+}
+
+static void plx_pci_write_reg(const struct sja1000_priv *priv, int port, u8 val)
+{
+	iowrite8(val, priv->reg_base + port);
+}
+
+/*
+ * Check if a CAN controller is present at the specified location
+ * by trying to switch 'em from the Basic mode into the PeliCAN mode.
+ * Also check states of some registers in reset mode.
+ */
+static inline int plx_pci_check_sja1000(const struct sja1000_priv *priv)
+{
+	int flag = 0;
+
+	/*
+	 * Check registers after hardware reset (the Basic mode)
+	 * See states on p. 10 of the Datasheet.
+	 */
+	if ((priv->read_reg(priv, REG_CR) & REG_CR_BASICCAN_INITIAL_MASK) ==
+	    REG_CR_BASICCAN_INITIAL &&
+	    (priv->read_reg(priv, REG_SR) == REG_SR_BASICCAN_INITIAL) &&
+	    (priv->read_reg(priv, REG_IR) == REG_IR_BASICCAN_INITIAL))
+		flag = 1;
+
+	/* Bring the SJA1000 into the PeliCAN mode*/
+	priv->write_reg(priv, REG_CDR, CDR_PELICAN);
+
+	/*
+	 * Check registers after reset in the PeliCAN mode.
+	 * See states on p. 23 of the Datasheet.
+	 */
+	if (priv->read_reg(priv, REG_MOD) == REG_MOD_PELICAN_INITIAL &&
+	    priv->read_reg(priv, REG_SR) == REG_SR_PELICAN_INITIAL &&
+	    priv->read_reg(priv, REG_IR) == REG_IR_PELICAN_INITIAL)
+		return flag;
+
+	return 0;
+}
+
+/*
+ * PLX90xx software reset
+ * Also LRESET# asserts and brings to reset device on the Local Bus (if wired).
+ * For most cards it's enough for reset the SJA1000 chips.
+ */
+static void plx_pci_reset_common(struct pci_dev *pdev)
+{
+	struct plx_pci_card *card = pci_get_drvdata(pdev);
+	u32 cntrl;
+
+	cntrl = ioread32(card->conf_addr + PLX_CNTRL);
+	cntrl |= PLX_PCI_RESET;
+	iowrite32(cntrl, card->conf_addr + PLX_CNTRL);
+	udelay(100);
+	cntrl ^= PLX_PCI_RESET;
+	iowrite32(cntrl, card->conf_addr + PLX_CNTRL);
+};
+
+/* Special reset function for Marathon card */
+static void plx_pci_reset_marathon(struct pci_dev *pdev)
+{
+	void __iomem *reset_addr;
+	int i;
+	int reset_bar[2] = {3, 5};
+
+	plx_pci_reset_common(pdev);
+
+	for (i = 0; i < 2; i++) {
+		reset_addr = pci_iomap(pdev, reset_bar[i], 0);
+		if (!reset_addr) {
+			dev_err(&pdev->dev, "Failed to remap reset "
+				"space %d (BAR%d)\n", i, reset_bar[i]);
+		} else {
+			/* reset the SJA1000 chip */
+			iowrite8(0x1, reset_addr);
+			udelay(100);
+			pci_iounmap(pdev, reset_addr);
+		}
+	}
+}
+
+static void plx_pci_del_card(struct pci_dev *pdev)
+{
+	struct plx_pci_card *card = pci_get_drvdata(pdev);
+	struct net_device *dev;
+	struct sja1000_priv *priv;
+	int i = 0;
+
+	for (i = 0; i < card->channels; i++) {
+		dev = card->net_dev[i];
+		if (!dev)
+			continue;
+
+		dev_info(&pdev->dev, "Removing %s\n", dev->name);
+		unregister_sja1000dev(dev);
+		priv = netdev_priv(dev);
+		if (priv->reg_base)
+			pci_iounmap(pdev, priv->reg_base);
+		free_sja1000dev(dev);
+	}
+
+	plx_pci_reset_common(pdev);
+
+	/*
+	 * Disable interrupts from PCI-card (PLX90xx) and disable Local_1,
+	 * Local_2 interrupts
+	 */
+	iowrite32(0x0, card->conf_addr + PLX_INTCSR);
+
+	if (card->conf_addr)
+		pci_iounmap(pdev, card->conf_addr);
+
+	kfree(card);
+
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+}
+
+/*
+ * Probe PLX90xx based device for the SJA1000 chips and register each
+ * available CAN channel to SJA1000 Socket-CAN subsystem.
+ */
+static int __devinit plx_pci_add_card(struct pci_dev *pdev,
+				      const struct pci_device_id *ent)
+{
+	struct sja1000_priv *priv;
+	struct net_device *dev;
+	struct plx_pci_card *card;
+	struct plx_pci_card_info *ci;
+	int err, i;
+	u32 val;
+	void __iomem *addr;
+
+	ci = (struct plx_pci_card_info *)ent->driver_data;
+
+	if (pci_enable_device(pdev) < 0) {
+		dev_err(&pdev->dev, "Failed to enable PCI device\n");
+		return -ENODEV;
+	}
+
+	dev_info(&pdev->dev, "Detected \"%s\" card at slot #%i\n",
+		 ci->name, PCI_SLOT(pdev->devfn));
+
+	/* Allocate card structures to hold addresses, ... */
+	card = kzalloc(sizeof(*card), GFP_KERNEL);
+	if (!card) {
+		dev_err(&pdev->dev, "Unable to allocate memory\n");
+		pci_disable_device(pdev);
+		return -ENOMEM;
+	}
+
+	pci_set_drvdata(pdev, card);
+
+	card->channels = 0;
+
+	/* Remap PLX90xx configuration space */
+	addr = pci_iomap(pdev, ci->conf_map.bar, ci->conf_map.size);
+	if (!addr) {
+		err = -ENOMEM;
+		dev_err(&pdev->dev, "Failed to remap configuration space "
+			"(BAR%d)\n", ci->conf_map.bar);
+		goto failure_cleanup;
+	}
+	card->conf_addr = addr + ci->conf_map.offset;
+
+	ci->reset_func(pdev);
+
+	/* Detect available channels */
+	for (i = 0; i < ci->channel_count; i++) {
+		struct plx_pci_channel_map *cm = &ci->chan_map_tbl[i];
+
+		dev = alloc_sja1000dev(0);
+		if (!dev) {
+			err = -ENOMEM;
+			goto failure_cleanup;
+		}
+
+		card->net_dev[i] = dev;
+		priv = netdev_priv(dev);
+		priv->priv = card;
+		priv->irq_flags = IRQF_SHARED;
+
+		dev->irq = pdev->irq;
+
+		/*
+		 * Remap IO space of the SJA1000 chips
+		 * This is device-dependent mapping
+		 */
+		addr = pci_iomap(pdev, cm->bar, cm->size);
+		if (!addr) {
+			err = -ENOMEM;
+			dev_err(&pdev->dev, "Failed to remap BAR%d\n", cm->bar);
+			goto failure_cleanup;
+		}
+
+		priv->reg_base = addr + cm->offset;
+		priv->read_reg = plx_pci_read_reg;
+		priv->write_reg = plx_pci_write_reg;
+
+		/* Check if channel is present */
+		if (plx_pci_check_sja1000(priv)) {
+			priv->can.clock.freq = ci->can_clock;
+			priv->ocr = ci->ocr;
+			priv->cdr = ci->cdr;
+
+			SET_NETDEV_DEV(dev, &pdev->dev);
+
+			/* Register SJA1000 device */
+			err = register_sja1000dev(dev);
+			if (err) {
+				dev_err(&pdev->dev, "Registering device failed "
+					"(err=%d)\n", err);
+				free_sja1000dev(dev);
+				goto failure_cleanup;
+			}
+
+			card->channels++;
+
+			dev_info(&pdev->dev, "Channel #%d at 0x%p, irq %d "
+				 "registered as %s\n", i + 1, priv->reg_base,
+				 dev->irq, dev->name);
+		} else {
+			dev_err(&pdev->dev, "Channel #%d not detected\n",
+				i + 1);
+			free_sja1000dev(dev);
+		}
+	}
+
+	if (!card->channels) {
+		err = -ENODEV;
+		goto failure_cleanup;
+	}
+
+	/*
+	 * Enable interrupts from PCI-card (PLX90xx) and enable Local_1,
+	 * Local_2 interrupts from the SJA1000 chips
+	 */
+	val = ioread32(card->conf_addr + PLX_INTCSR);
+	val |= PLX_LINT1_EN | PLX_LINT2_EN | PLX_PCI_INT_EN;
+	iowrite32(val, card->conf_addr + PLX_INTCSR);
+
+	return 0;
+
+failure_cleanup:
+	dev_err(&pdev->dev, "Error: %d. Cleaning Up.\n", err);
+
+	plx_pci_del_card(pdev);
+
+	return err;
+}
+
+static struct pci_driver plx_pci_driver = {
+	.name = DRV_NAME,
+	.id_table = plx_pci_tbl,
+	.probe = plx_pci_add_card,
+	.remove = plx_pci_del_card,
+};
+
+static int __init plx_pci_init(void)
+{
+	return pci_register_driver(&plx_pci_driver);
+}
+
+static void __exit plx_pci_exit(void)
+{
+	pci_unregister_driver(&plx_pci_driver);
+}
+
+module_init(plx_pci_init);
+module_exit(plx_pci_exit);
-- 
1.6.0.6


^ permalink raw reply related

* Re: [PATCH] sky2:  receive dma mapping error handling
From: Michael Breuer @ 2010-02-01 18:44 UTC (permalink / raw)
  To: Stephen Hemminger
  Cc: Jarek Poplawski, David Miller, akpm, flyboy, linux-kernel, netdev,
	Michael Chan, Don Fry, Francois Romieu, Matt Carlson
In-Reply-To: <20100201102018.7b597992@nehalam>

On 2/1/2010 1:20 PM, Stephen Hemminger wrote:
> This fixes the fact that re->flags is always zero without causing
> other confusion.
>
> --- a/drivers/net/sky2.c	2010-02-01 10:07:42.676296236 -0800
> +++ b/drivers/net/sky2.c	2010-02-01 10:18:12.575044064 -0800
> @@ -1025,11 +1025,8 @@ static void sky2_prefetch_init(struct sk
>   static inline struct sky2_tx_le *get_tx_le(struct sky2_port *sky2, u16 *slot)
>   {
>   	struct sky2_tx_le *le = sky2->tx_le + *slot;
> -	struct tx_ring_info *re = sky2->tx_ring + *slot;
>
>   	*slot = RING_NEXT(*slot, sky2->tx_ring_size);
> -	re->flags = 0;
> -	re->skb = NULL;
>   	le->ctrl = 0;
>   	return le;
>   }
> @@ -1622,8 +1619,7 @@ static unsigned tx_le_req(const struct s
>   	return count;
>   }
>
> -static void sky2_tx_unmap(struct pci_dev *pdev,
> -			  const struct tx_ring_info *re)
> +static void sky2_tx_unmap(struct pci_dev *pdev, struct tx_ring_info *re)
>   {
>   	if (re->flags&  TX_MAP_SINGLE)
>   		pci_unmap_single(pdev, pci_unmap_addr(re, mapaddr),
> @@ -1633,6 +1629,7 @@ static void sky2_tx_unmap(struct pci_dev
>   		pci_unmap_page(pdev, pci_unmap_addr(re, mapaddr),
>   			       pci_unmap_len(re, maplen),
>   			       PCI_DMA_TODEVICE);
> +	re->flags = 0;
>   }
>
>   /*
> @@ -1839,6 +1836,7 @@ static void sky2_tx_complete(struct sky2
>   			dev->stats.tx_packets++;
>   			dev->stats.tx_bytes += skb->len;
>
> +			re->skb = NULL;
>   			dev_kfree_skb_any(skb);
>
>   			sky2->tx_next = RING_NEXT(idx, sky2->tx_ring_size);
> --
> 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
>    
Running with this patch now - dma debug num_free_entries stable - so 
far, so good.

^ permalink raw reply

* Re: [PATCH 02/86] dccp: revert buggy auto-loading of dccp module
From: Neil Horman @ 2010-02-01 18:38 UTC (permalink / raw)
  To: Gerrit Renker; +Cc: davem, dccp, netdev
In-Reply-To: <20100201122119.GC25094@hmsreliant.think-freely.org>

On Mon, Feb 01, 2010 at 07:21:19AM -0500, Neil Horman wrote:
> On Mon, Feb 01, 2010 at 07:18:07AM +0100, Gerrit Renker wrote:
> > This reverts commit (38ff3e6bb987ec583268da8eb22628293095d43b) ("dccp_probe:
> > Fix module load dependencies between dccp and dccp_probe", from 15 Jan). Not
> > only does it not work:
> > 
> > % modprobe -v dccp_probe
> > kernel: [ 1431.442912] sys_init_module: 'dccp_probe'->init suspiciously \
> >  		      returned 1, it should follow 0/-E convention
> > kernel: [ 1431.442915] sys_init_module: loading module anyway...
> > 
> > 
> > ... but it also causes a crash:
> > 
> > % rmmod dccp_probe
> > kernel: [ 1777.305846] kernel BUG at /usr/src/davem-2.6/mm/slab.c:521!
> > kernel: [ 1777.305852] invalid opcode: 0000 [#1] SMP
> > kernel: [ 1777.305861] last sysfs file: /sys/class/power_supply/BAT0/energy_full
> > kernel: [ 1777.305867] Modules linked in: dccp_probe(-) iwl3945 iwlcore [last unloaded: dccp]
> > kernel: [ 1777.305883]
> > kernel: [ 1777.305891] Pid: 12912, comm: rmmod Tainted: G  R        2.6.33-rc5 #6 2008URG/2008URG
> > kernel: [ 1777.305899] EIP: 0060:[<c01d5e43>] EFLAGS: 00010046 CPU: 1
> > kernel: [ 1777.305910] EIP is at kfree+0x73/0x150
> > kernel: [ 1777.305916] EAX: c1678c00 EBX: 00000000 ECX: c01d5e15 EDX: 40080000
> > kernel: [ 1777.305922] ESI: c015cb9a EDI: 080488a0 EBP: f4ffbf34 ESP: f4ffbf10
> > kernel: [ 1777.305929]  DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068
> > kernel: [ 1777.305936] Process rmmod (pid: 12912, ti=f4ffb000 task=f61e8620 task.ti=f4ffb000)
> > 
> > ==> After reverting the commit:
> > 
> > % modprobe -v dccp_probe
> > insmod /lib/modules/2.6.33-rc5/kernel/net/dccp/dccp.ko
> > insmod /lib/modules/2.6.33-rc5/kernel/net/dccp/dccp_probe.ko
> > 
> > % lsmod
> > Module                  Size  Used by
> > dccp_probe              2345  0
> > dccp                  120233  1 dccp_probe
> > 
> > Previously (during about 4 years of this module's history) there had never
> > been a problem with the 'silent dependency' that the commit tried to fix:
> > this dependency is deliberate and required, since dccp_probe performs probing
> > of dccp connections and hence needs to know about dccp internals.
> > 
> > Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> 
> This doesn't make any sense.  Gerrit, you don't understand what the patch was
> trying to do.  There is a silent dependency, in that this module requires the
> dccp module to be loaded, but the reference to the dccp_send_probe symbol isn't
> one that depmod can see.  If you don't load dccp first, dccp_probe fails, why
> bother to allow that when try_then_request_module can avoid it?
> 
> The problem here is the construction of the first argument,
> try_then_request_module should only return valid return codes from the first
> argument, and my first argument is malformed.  register_jprobe returns zero on
> success, so I need to check its return in the call for 0, in case we need to
> trigger the request_module action, but in so doing ret gets the value of
> (register_jprobe(&dccp_send_probe) == 0), which will always be 0 or 1.  What we
> actually need to do is assign the result of register_jprobe to ret, without the
> side effect of the comparison.  I've not tested it, but this should do it,
> without re-breaking the silent dependency.
> 
> Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
> 
> 
>  
>  probe.c |    3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> 
> diff --git a/net/dccp/probe.c b/net/dccp/probe.c
> index bace1d8..a8f5fdf 100644
> --- a/net/dccp/probe.c
> +++ b/net/dccp/probe.c
> @@ -161,7 +161,8 @@ static __init int dccpprobe_init(void)
>  	if (!proc_net_fops_create(&init_net, procname, S_IRUSR, &dccpprobe_fops))
>  		goto err0;
>  
> -	ret = try_then_request_module((register_jprobe(&dccp_send_probe) == 0),
> +	try_then_request_module(
> +		((ret = register_jprobe(&dccp_send_probe)) == 0),
>  					"dccp");
>  	if (ret)
>  		goto err1;
> --
> 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
> 
Gerrit, any thoughts here?
Thanks & Regards
Neil


^ permalink raw reply

* Re: [PATCH v2] skbuff: align sk_buff::cb to 64 bit
From: Felix Fietkau @ 2010-02-01 18:37 UTC (permalink / raw)
  To: David Daney; +Cc: Eric Dumazet, netdev, Lennert Buytenhek
In-Reply-To: <4B671CEB.5080505@caviumnetworks.com>

On 2010-02-01 7:26 PM, David Daney wrote:
> Eric Dumazet wrote:
>> Le samedi 30 janvier 2010 à 01:38 +0100, Felix Fietkau a écrit :
>>> The alignment requirement for 64-bit load/store instructions on ARM is
>>> implementation defined. Some CPUs (such as Marvell Feroceon) do not
>>> generate an exception, if such an instruction is executed with an
>>> address that is not 64 bit aligned. In such a case, the Feroceon
>>> corrupts adjacent memory, which showed up
>>> in my tests as a crash in the rx path of ath9k that only occured with
>>> CONFIG_XFRM set. This crash happened, because the first field of the
>>> mac80211 rx status info in the cb is an u64, and changing it corrupted
>>> the skb->sp field.
>>>
>>> Signed-off-by: Felix Fietkau <nbd@openwrt.org>
>>> Cc: stable@kernel.org
>>> ---
>>> --- a/include/linux/skbuff.h
>>> +++ b/include/linux/skbuff.h
>>> @@ -329,7 +329,7 @@ struct sk_buff {
>>>  	 * want to keep them across layers you have to do a skb_clone()
>>>  	 * first. This is owned by whoever has the skb queued ATM.
>>>  	 */
>>> -	char			cb[48];
>>> +	char			cb[48] __aligned(8);
>>>   	unsigned int		len,
>>>  				data_len;
>>>
>>> --
>> 
>> Without a detailed analysis of holes added on x86_32 and/or x86_64, I
>> guess this patch is not acceptable as is.
>> 
>> You certainly can find a better way to do this, without adding holes in
>> sk_buff structure. Size matters a lot :)
>> 
> 
> Can't we just move cb[] up so that it comes after an even number of 
> pointers under all configs?
> 
> Then perhaps add __aligned(8) to the entire structure instead of just 
> this field.
Makes sense, I'll send a patch for that.

> Alternatively, could you fix the driver so that it adds the necessary 
> alignment to its use of the cb[] array?
> 
> How common it it to have sizeof(void *) == 4 *and* require 8-byte 
> alignment on other things?  cb[] is fairly large, can you afford to burn 
> 4 bytes for alignment purposes in your driver?
No, I can't afford to burn a single byte on this, in some places
mac80211 uses all of the cb[] area up to the last byte.

- Felix

^ permalink raw reply

* Re: [PATCH v2] skbuff: align sk_buff::cb to 64 bit
From: David Daney @ 2010-02-01 18:26 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: Felix Fietkau, netdev, Lennert Buytenhek
In-Reply-To: <1264835220.2919.10.camel@edumazet-laptop>

Eric Dumazet wrote:
> Le samedi 30 janvier 2010 à 01:38 +0100, Felix Fietkau a écrit :
>> The alignment requirement for 64-bit load/store instructions on ARM is
>> implementation defined. Some CPUs (such as Marvell Feroceon) do not
>> generate an exception, if such an instruction is executed with an
>> address that is not 64 bit aligned. In such a case, the Feroceon
>> corrupts adjacent memory, which showed up
>> in my tests as a crash in the rx path of ath9k that only occured with
>> CONFIG_XFRM set. This crash happened, because the first field of the
>> mac80211 rx status info in the cb is an u64, and changing it corrupted
>> the skb->sp field.
>>
>> Signed-off-by: Felix Fietkau <nbd@openwrt.org>
>> Cc: stable@kernel.org
>> ---
>> --- a/include/linux/skbuff.h
>> +++ b/include/linux/skbuff.h
>> @@ -329,7 +329,7 @@ struct sk_buff {
>>  	 * want to keep them across layers you have to do a skb_clone()
>>  	 * first. This is owned by whoever has the skb queued ATM.
>>  	 */
>> -	char			cb[48];
>> +	char			cb[48] __aligned(8);
>>   	unsigned int		len,
>>  				data_len;
>>
>> --
> 
> Without a detailed analysis of holes added on x86_32 and/or x86_64, I
> guess this patch is not acceptable as is.
> 
> You certainly can find a better way to do this, without adding holes in
> sk_buff structure. Size matters a lot :)
> 

Can't we just move cb[] up so that it comes after an even number of 
pointers under all configs?

Then perhaps add __aligned(8) to the entire structure instead of just 
this field.

Alternatively, could you fix the driver so that it adds the necessary 
alignment to its use of the cb[] array?

How common it it to have sizeof(void *) == 4 *and* require 8-byte 
alignment on other things?  cb[] is fairly large, can you afford to burn 
4 bytes for alignment purposes in your driver?


David Daney

^ permalink raw reply

* [PATCH] irda: remove BKL from irnet open function
From: Thadeu Lima de Souza Cascardo @ 2010-02-01 18:18 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Thadeu Lima de Souza Cascardo, Samuel Ortiz, David S. Miller,
	linux-kernel, netdev

Commit cddf63d99d0d145f18b293c3d0de4af7dab2a922 has push down the BKL
into irnet open function. However, there's nothing that needs locking in
there.

Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>
---
 net/irda/irnet/irnet_ppp.c |    3 ---
 1 files changed, 0 insertions(+), 3 deletions(-)

diff --git a/net/irda/irnet/irnet_ppp.c b/net/irda/irnet/irnet_ppp.c
index 156020d..d6b502c 100644
--- a/net/irda/irnet/irnet_ppp.c
+++ b/net/irda/irnet/irnet_ppp.c
@@ -479,7 +479,6 @@ dev_irnet_open(struct inode *	inode,
   ap = kzalloc(sizeof(*ap), GFP_KERNEL);
   DABORT(ap == NULL, -ENOMEM, FS_ERROR, "Can't allocate struct irnet...\n");
 
-  lock_kernel();
   /* initialize the irnet structure */
   ap->file = file;
 
@@ -501,7 +500,6 @@ dev_irnet_open(struct inode *	inode,
     {
       DERROR(FS_ERROR, "Can't setup IrDA link...\n");
       kfree(ap);
-      unlock_kernel();
       return err;
     }
 
@@ -512,7 +510,6 @@ dev_irnet_open(struct inode *	inode,
   file->private_data = ap;
 
   DEXIT(FS_TRACE, " - ap=0x%p\n", ap);
-  unlock_kernel();
   return 0;
 }
 
-- 
1.6.6.1


^ permalink raw reply related

* [PATCH 2/2] irda: add missing BKL in irnet_ppp ioctl
From: Thadeu Lima de Souza Cascardo @ 2010-02-01 18:21 UTC (permalink / raw)
  To: Alan Cox
  Cc: Thadeu Lima de Souza Cascardo, Samuel Ortiz, David S. Miller,
	linux-kernel, netdev
In-Reply-To: <1265048496-8149-1-git-send-email-cascardo@holoscopio.com>

One ioctl has been forgotten when the BKL was push down into irnet_ppp
ioctl function.

Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>
---
 net/irda/irnet/irnet_ppp.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/net/irda/irnet/irnet_ppp.c b/net/irda/irnet/irnet_ppp.c
index 8d38fdd..67aee5c 100644
--- a/net/irda/irnet/irnet_ppp.c
+++ b/net/irda/irnet/irnet_ppp.c
@@ -695,9 +695,11 @@ dev_irnet_ioctl(
 
       /* Query PPP channel and unit number */
     case PPPIOCGCHAN:
+      lock_kernel();
       if(ap->ppp_open && !put_user(ppp_channel_index(&ap->chan),
 						(int __user *)argp))
 	err = 0;
+      unlock_kernel();
       break;
     case PPPIOCGUNIT:
       lock_kernel();
-- 
1.6.6.1

^ permalink raw reply related

* [PATCH 1/2] irda: unbalanced lock_kernel in irnet_ppp
From: Thadeu Lima de Souza Cascardo @ 2010-02-01 18:21 UTC (permalink / raw)
  To: Alan Cox
  Cc: Thadeu Lima de Souza Cascardo, Samuel Ortiz, David S. Miller,
	linux-kernel, netdev

Add the missing unlock_kernel in one ioctl operation.

Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>
---
 net/irda/irnet/irnet_ppp.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/net/irda/irnet/irnet_ppp.c b/net/irda/irnet/irnet_ppp.c
index d6b502c..8d38fdd 100644
--- a/net/irda/irnet/irnet_ppp.c
+++ b/net/irda/irnet/irnet_ppp.c
@@ -703,7 +703,8 @@ dev_irnet_ioctl(
       lock_kernel();
       if(ap->ppp_open && !put_user(ppp_unit_number(&ap->chan),
 						(int __user *)argp))
-      err = 0;
+        err = 0;
+      unlock_kernel();
       break;
 
       /* All these ioctls can be passed both directly and from ppp_generic,
-- 
1.6.6.1

^ permalink raw reply related

* Re: [PATCH] sky2:  receive dma mapping error handling
From: Stephen Hemminger @ 2010-02-01 18:20 UTC (permalink / raw)
  To: Jarek Poplawski
  Cc: Michael Breuer, David Miller, akpm, flyboy, linux-kernel, netdev,
	Michael Chan, Don Fry, Francois Romieu, Matt Carlson
In-Reply-To: <20100131221835.GA3317@del.dom.local>

This fixes the fact that re->flags is always zero without causing
other confusion.

--- a/drivers/net/sky2.c	2010-02-01 10:07:42.676296236 -0800
+++ b/drivers/net/sky2.c	2010-02-01 10:18:12.575044064 -0800
@@ -1025,11 +1025,8 @@ static void sky2_prefetch_init(struct sk
 static inline struct sky2_tx_le *get_tx_le(struct sky2_port *sky2, u16 *slot)
 {
 	struct sky2_tx_le *le = sky2->tx_le + *slot;
-	struct tx_ring_info *re = sky2->tx_ring + *slot;
 
 	*slot = RING_NEXT(*slot, sky2->tx_ring_size);
-	re->flags = 0;
-	re->skb = NULL;
 	le->ctrl = 0;
 	return le;
 }
@@ -1622,8 +1619,7 @@ static unsigned tx_le_req(const struct s
 	return count;
 }
 
-static void sky2_tx_unmap(struct pci_dev *pdev,
-			  const struct tx_ring_info *re)
+static void sky2_tx_unmap(struct pci_dev *pdev, struct tx_ring_info *re)
 {
 	if (re->flags & TX_MAP_SINGLE)
 		pci_unmap_single(pdev, pci_unmap_addr(re, mapaddr),
@@ -1633,6 +1629,7 @@ static void sky2_tx_unmap(struct pci_dev
 		pci_unmap_page(pdev, pci_unmap_addr(re, mapaddr),
 			       pci_unmap_len(re, maplen),
 			       PCI_DMA_TODEVICE);
+	re->flags = 0;
 }
 
 /*
@@ -1839,6 +1836,7 @@ static void sky2_tx_complete(struct sky2
 			dev->stats.tx_packets++;
 			dev->stats.tx_bytes += skb->len;
 
+			re->skb = NULL;
 			dev_kfree_skb_any(skb);
 
 			sky2->tx_next = RING_NEXT(idx, sky2->tx_ring_size);

^ permalink raw reply

* Re: [PATCH] sky2:  receive dma mapping error handling
From: Stephen Hemminger @ 2010-02-01 18:08 UTC (permalink / raw)
  To: Jarek Poplawski
  Cc: Michael Breuer, David Miller, akpm, flyboy, linux-kernel, netdev,
	Michael Chan, Don Fry, Francois Romieu, Matt Carlson
In-Reply-To: <20100131221835.GA3317@del.dom.local>

On Sun, 31 Jan 2010 23:18:35 +0100
Jarek Poplawski <jarkao2@gmail.com> wrote:

> @@ -1025,9 +1025,10 @@ static void sky2_prefetch_init(struct sky2_hw *hw, u32 qaddr,
>  static inline struct sky2_tx_le *get_tx_le(struct sky2_port *sky2, u16 *slot)
>  {
>  	struct sky2_tx_le *le = sky2->tx_le + *slot;
> -	struct tx_ring_info *re = sky2->tx_ring + *slot;
> +	struct tx_ring_info *re;
>  
>  	*slot = RING_NEXT(*slot, sky2->tx_ring_size);
> +	re = sky2->tx_ring + *slot;
>  	re->flags = 0;

Bogus, le and re are 1-to-1, so hardware portion an software
portion should be at same index.

-- 

^ permalink raw reply

* [PATCH] can: ems_usb: removed duplicated code setting local echo support
From: Thadeu Lima de Souza Cascardo @ 2010-02-01 18:02 UTC (permalink / raw)
  To: trivial
  Cc: Thadeu Lima de Souza Cascardo, Urs Thuermann, Oliver Hartkopp,
	netdev, linux-kernel

Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>
---
 drivers/net/can/usb/ems_usb.c |    2 --
 1 files changed, 0 insertions(+), 2 deletions(-)

diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c
index efbb05c..ee849cf 100644
--- a/drivers/net/can/usb/ems_usb.c
+++ b/drivers/net/can/usb/ems_usb.c
@@ -1020,8 +1020,6 @@ static int ems_usb_probe(struct usb_interface *intf,
 	dev->can.do_set_bittiming = ems_usb_set_bittiming;
 	dev->can.do_set_mode = ems_usb_set_mode;
 
-	netdev->flags |= IFF_ECHO; /* we support local echo */
-
 	netdev->netdev_ops = &ems_usb_netdev_ops;
 
 	netdev->flags |= IFF_ECHO; /* we support local echo */
-- 
1.6.6.1


^ permalink raw reply related

* [PATCH] trivial: remove duplicated "from" in CAN USB EMS Kconfig help
From: Thadeu Lima de Souza Cascardo @ 2010-02-01 17:58 UTC (permalink / raw)
  To: trivial
  Cc: Thadeu Lima de Souza Cascardo, Urs Thuermann, Oliver Hartkopp,
	David S. Miller, Wolfgang Grandegger, netdev, linux-kernel

Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>
---
 drivers/net/can/usb/Kconfig |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig
index bbc78e0..97ff6fe 100644
--- a/drivers/net/can/usb/Kconfig
+++ b/drivers/net/can/usb/Kconfig
@@ -5,6 +5,6 @@ config CAN_EMS_USB
 	tristate "EMS CPC-USB/ARM7 CAN/USB interface"
 	---help---
 	  This driver is for the one channel CPC-USB/ARM7 CAN/USB interface
-	  from from EMS Dr. Thomas Wuensche (http://www.ems-wuensche.de).
+	  from EMS Dr. Thomas Wuensche (http://www.ems-wuensche.de).
 
 endmenu
-- 
1.6.6.1

^ permalink raw reply related

* Re: [PATCH v2] sky2: Fix transmit dma mapping handling
From: Michael Breuer @ 2010-02-01 17:52 UTC (permalink / raw)
  To: Jarek Poplawski
  Cc: David Miller, Stephen Hemminger, akpm, flyboy, linux-kernel,
	netdev, Michael Chan, Don Fry, Francois Romieu, Matt Carlson
In-Reply-To: <20100201091718.GA9849@ff.dom.local>

On 2/1/2010 4:17 AM, Jarek Poplawski wrote:
> On Sun, Jan 31, 2010 at 07:19:46PM -0500, Michael Breuer wrote:
>    
>> On 1/31/2010 5:18 PM, Jarek Poplawski wrote:
>>      
>>> On Sun, Jan 31, 2010 at 04:58:42PM -0500, Michael Breuer wrote:
>>>
>>>        
>>>> On 1/31/2010 1:50 PM, Michael Breuer wrote:
>>>>          
>>>>> I put a printk as a third else case in sky2_tx_unmap. Looks like
>>>>> the issue is that a large number (perhaps all) calls to
>>>>> sky2_tx_unmap have re->flags set to neither TX_MAP_SINGLE or
>>>>> TX_MAP_PAGE. Thus the elements are never being unmapped.
>>>>>
>>>>> I suspect that the system collapses when using DMAR sooner than if
>>>>> not using DMAR. Probably some hardware limitation on the number of
>>>>> mapped elements that is less than the software limitation. I don't
>>>>> see at present how a ring element can ever get to this code
>>>>> without re->flags being set to one or the other.
>>>>>
>>>>>
>>>>>
>>>>>            
>>>> Put some more debugging code in... re->flags is always NULL upon
>>>> entry to sky2_tx_unmap.
>>>>
>>>>
>>>>          
>>> Yes, good point! Could you try if this patch can fix it. (not compiled)
>>>        
> ...
>    
>> Ok- solves the dma-debug issue - i.e., elements are now being unmapped.
>>
>> Will leave up and hit with traffic unless a crash occurs. If I hit
>> something unrelated I'll backport to 2.6.32.7 and try that for a while.
>> I do think it's plausible that the dma errors after (during) load were
>> due to hardware limitations on the number of mapped entries (haven't
>> researched what that limit was). I would also assume that the sw map
>> would also have failed eventually.
>>
>> I'd suggest that regardless of whether this patch solves my crash that
>> it ought to be backported as it seems unlikely that any machine would be
>> able to survive for long without the tx entries being unmapped.
>>      
> Here is a bit improved version (re->flags = 0 in sky2_tx_unmap()) for
> merging, or additional testing if David wishes.
>
> Thanks,
> Jarek P.
> --------------->
> Michael Breuer reported that dma-debug entries added by sky2 driver
> weren't unmapped, and found out "re->flags is always NULL upon entry
> to sky2_tx_unmap". It is overwritten by get_tx_le() after changes
> introduced by commit 6b84dacadbdc3dab6a5b313d20d5a93b0d998641.
>
> This patch reorders initializations in get_tx_le() and tx_init(), and
> additionally does re->flags zeroing in sky2_tx_unmap() to prevent
> possible double unmapping.
>
> With debugging by: Michael Breuer<mbreuer@majjas.com>
>
> Reported-by: Michael Breuer<mbreuer@majjas.com>
> Tested-by: Michael Breuer<mbreuer@majjas.com>
> Signed-off-by: Jarek Poplawski<jarkao2@gmail.com>
> ---
>
>   drivers/net/sky2.c |   20 +++++++++++++-------
>   1 files changed, 13 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
> index d760650..21bb00a 100644
> --- a/drivers/net/sky2.c
> +++ b/drivers/net/sky2.c
> @@ -1025,9 +1025,10 @@ static void sky2_prefetch_init(struct sky2_hw *hw, u32 qaddr,
>   static inline struct sky2_tx_le *get_tx_le(struct sky2_port *sky2, u16 *slot)
>   {
>   	struct sky2_tx_le *le = sky2->tx_le + *slot;
> -	struct tx_ring_info *re = sky2->tx_ring + *slot;
> +	struct tx_ring_info *re;
>
>   	*slot = RING_NEXT(*slot, sky2->tx_ring_size);
> +	re = sky2->tx_ring + *slot;
>   	re->flags = 0;
>   	re->skb = NULL;
>   	le->ctrl = 0;
> @@ -1036,13 +1037,16 @@ static inline struct sky2_tx_le *get_tx_le(struct sky2_port *sky2, u16 *slot)
>
>   static void tx_init(struct sky2_port *sky2)
>   {
> -	struct sky2_tx_le *le;
> +	struct sky2_tx_le *le = sky2->tx_le;
> +	struct tx_ring_info *re = sky2->tx_ring;
>
>   	sky2->tx_prod = sky2->tx_cons = 0;
>   	sky2->tx_tcpsum = 0;
>   	sky2->tx_last_mss = 0;
>
> -	le = get_tx_le(sky2,&sky2->tx_prod);
> +	re->flags = 0;
> +	re->skb = NULL;
> +	le->ctrl = 0;
>   	le->addr = 0;
>   	le->opcode = OP_ADDR64 | HW_OWNER;
>   	sky2->tx_last_upper = 0;
> @@ -1622,17 +1626,19 @@ static unsigned tx_le_req(const struct sk_buff *skb)
>   	return count;
>   }
>
> -static void sky2_tx_unmap(struct pci_dev *pdev,
> -			  const struct tx_ring_info *re)
> +static void sky2_tx_unmap(struct pci_dev *pdev, struct tx_ring_info *re)
>   {
> -	if (re->flags&  TX_MAP_SINGLE)
> +	if (re->flags&  TX_MAP_SINGLE) {
>   		pci_unmap_single(pdev, pci_unmap_addr(re, mapaddr),
>   				 pci_unmap_len(re, maplen),
>   				 PCI_DMA_TODEVICE);
> -	else if (re->flags&  TX_MAP_PAGE)
> +		re->flags = 0;
> +	} else if (re->flags&  TX_MAP_PAGE) {
>   		pci_unmap_page(pdev, pci_unmap_addr(re, mapaddr),
>   			       pci_unmap_len(re, maplen),
>   			       PCI_DMA_TODEVICE);
> +		re->flags = 0;
> +	}
>   }
>
>   /*
>    
Running with v2 now. v1 patch significantly improved things. I cannot 
state for certain that the original issue is resolved (crash under 
load), however so far it appears so. Additionally, some performance 
issues (raid rebuild times, etc.) seem drastically improved. I'm 
guessing that this might have to do with the excess mapped sky2 tx buffers.

^ permalink raw reply

* [PATCH] vhost-net: switch to smp barriers
From: Michael S. Tsirkin @ 2010-02-01 17:21 UTC (permalink / raw)
  To: Michael S. Tsirkin, Rusty Russell, kvm, virtualization, netdev,
	linux-kernel

vhost-net only uses memory barriers to control SMP effects
(communication with userspace potentially running on a different CPU),
so it should use SMP barriers and not mandatory barriers for memory
access ordering, as suggested by Documentation/memory-barriers.txt

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
 drivers/vhost/vhost.c |   10 +++++-----
 1 files changed, 5 insertions(+), 5 deletions(-)

The above applies on top of net-next-2.6. Does not seem to give any
measureable performance gain, but seems to generate less code
and I think it's better to use correct APIs.

diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index c8c25db..6eb1525 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -685,7 +685,7 @@ int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log,
 	int i, r;
 
 	/* Make sure data written is seen before log. */
-	wmb();
+	smp_wmb();
 	for (i = 0; i < log_num; ++i) {
 		u64 l = min(log[i].len, len);
 		r = log_write(vq->log_base, log[i].addr, l);
@@ -884,7 +884,7 @@ unsigned vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq,
 		return vq->num;
 
 	/* Only get avail ring entries after they have been exposed by guest. */
-	rmb();
+	smp_rmb();
 
 	/* Grab the next descriptor number they're advertising, and increment
 	 * the index we've seen. */
@@ -996,14 +996,14 @@ int vhost_add_used(struct vhost_virtqueue *vq, unsigned int head, int len)
 		return -EFAULT;
 	}
 	/* Make sure buffer is written before we update index. */
-	wmb();
+	smp_wmb();
 	if (put_user(vq->last_used_idx + 1, &vq->used->idx)) {
 		vq_err(vq, "Failed to increment used idx");
 		return -EFAULT;
 	}
 	if (unlikely(vq->log_used)) {
 		/* Make sure data is seen before log. */
-		wmb();
+		smp_wmb();
 		log_write(vq->log_base, vq->log_addr + sizeof *vq->used->ring *
 			  (vq->last_used_idx % vq->num),
 			  sizeof *vq->used->ring);
@@ -1060,7 +1060,7 @@ bool vhost_enable_notify(struct vhost_virtqueue *vq)
 	}
 	/* They could have slipped one in as we were doing that: make
 	 * sure it's written, then check again. */
-	mb();
+	smp_mb();
 	r = get_user(avail_idx, &vq->avail->idx);
 	if (r) {
 		vq_err(vq, "Failed to check avail idx at %p: %d\n",
-- 
1.6.6.144.g5c3af

^ permalink raw reply related

* [PATCHv2 NEXT 7/7] qlcnic: add loppback diagnostic test
From: Amit Kumar Salecha @ 2010-02-01 15:25 UTC (permalink / raw)
  To: davem; +Cc: netdev, dhananjay.phadke, ameen.rahman
In-Reply-To: <1265037900-20403-1-git-send-email-amit.salecha@qlogic.com>

Loopback test (offline) added in ethtool self test.
o Set device in loopback mode
o Send packets
o Process receive packets in qlcnic_process_rcv_ring_diag()
o Compare packets
o Reset device in normal mode.

Signed-off-by: Amit Kumar Salecha <amit.salecha@qlogic.com>
---
 drivers/net/qlcnic/qlcnic.h         |    6 +++
 drivers/net/qlcnic/qlcnic_ethtool.c |   82 ++++++++++++++++++++++++++++++++++-
 drivers/net/qlcnic/qlcnic_hw.c      |   52 ++++++++++++++++++++++
 drivers/net/qlcnic/qlcnic_init.c    |   75 ++++++++++++++++++++++++++++++++
 drivers/net/qlcnic/qlcnic_main.c    |   20 +++++----
 5 files changed, 225 insertions(+), 10 deletions(-)

diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h
index a5a67e9..b40a851 100644
--- a/drivers/net/qlcnic/qlcnic.h
+++ b/drivers/net/qlcnic/qlcnic.h
@@ -897,6 +897,7 @@ struct qlcnic_mac_req {
 #define __QLCNIC_START_FW 		4
 
 #define QLCNIC_INTERRUPT_TEST		1
+#define QLCNIC_LOOPBACK_TEST		2
 
 struct qlcnic_adapter {
 	struct qlcnic_hardware_context ahw;
@@ -1066,6 +1067,8 @@ int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter);
 void qlcnic_update_cmd_producer(struct qlcnic_adapter *adapter,
 		struct qlcnic_host_tx_ring *tx_ring);
 int qlcnic_get_mac_addr(struct qlcnic_adapter *adapter, u64 *mac);
+void qlcnic_clear_ilb_mode(struct qlcnic_adapter *adapter);
+int qlcnic_set_ilb_mode(struct qlcnic_adapter *adapter);
 
 /* Functions from qlcnic_main.c */
 int qlcnic_reset_context(struct qlcnic_adapter *);
@@ -1073,6 +1076,9 @@ u32 qlcnic_issue_cmd(struct qlcnic_adapter *adapter,
 	u32 pci_fn, u32 version, u32 arg1, u32 arg2, u32 arg3, u32 cmd);
 void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings);
 int qlcnic_diag_alloc_res(struct net_device *netdev, int test);
+int qlcnic_check_loopback_buff(unsigned char *data);
+netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
+void qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring);
 
 /*
  * QLOGIC Board information
diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c
index 58c50ed..8da6ec8 100644
--- a/drivers/net/qlcnic/qlcnic_ethtool.c
+++ b/drivers/net/qlcnic/qlcnic_ethtool.c
@@ -66,7 +66,8 @@ static const struct qlcnic_stats qlcnic_gstrings_stats[] = {
 static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = {
 	"Register_Test_on_offline",
 	"Link_Test_on_offline",
-	"Interrupt_Test_offline"
+	"Interrupt_Test_offline",
+	"Loopback_Test_offline"
 };
 
 #define QLCNIC_TEST_LEN	ARRAY_SIZE(qlcnic_gstrings_test)
@@ -614,6 +615,80 @@ static int qlcnic_get_sset_count(struct net_device *dev, int sset)
 	}
 }
 
+#define QLC_ILB_PKT_SIZE 64
+
+static void qlcnic_create_loopback_buff(unsigned char *data)
+{
+	unsigned char random_data[] = {0xa8, 0x06, 0x45, 0x00};
+	memset(data, 0x4e, QLC_ILB_PKT_SIZE);
+	memset(data, 0xff, 12);
+	memcpy(data + 12, random_data, sizeof(random_data));
+}
+
+int qlcnic_check_loopback_buff(unsigned char *data)
+{
+	unsigned char buff[QLC_ILB_PKT_SIZE];
+	qlcnic_create_loopback_buff(buff);
+	return memcmp(data, buff, QLC_ILB_PKT_SIZE);
+}
+
+static int qlcnic_do_ilb_test(struct qlcnic_adapter *adapter)
+{
+	struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+	struct qlcnic_host_sds_ring *sds_ring = &recv_ctx->sds_rings[0];
+	struct sk_buff *skb;
+	int i;
+
+	for (i = 0; i < 16; i++) {
+		skb = dev_alloc_skb(QLC_ILB_PKT_SIZE);
+		qlcnic_create_loopback_buff(skb->data);
+		skb_put(skb, QLC_ILB_PKT_SIZE);
+
+		adapter->diag_cnt = 0;
+
+		qlcnic_xmit_frame(skb, adapter->netdev);
+
+		msleep(5);
+
+		qlcnic_process_rcv_ring_diag(sds_ring);
+
+		dev_kfree_skb_any(skb);
+		if (!adapter->diag_cnt)
+			return -1;
+	}
+	return 0;
+}
+
+static int qlcnic_loopback_test(struct net_device *netdev)
+{
+	struct qlcnic_adapter *adapter = netdev_priv(netdev);
+	int max_sds_rings = adapter->max_sds_rings;
+	int ret;
+
+	if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+		return -EIO;
+
+	ret = qlcnic_diag_alloc_res(netdev, QLCNIC_LOOPBACK_TEST);
+	if (ret)
+		goto clear_it;
+
+	ret = qlcnic_set_ilb_mode(adapter);
+	if (ret)
+		goto done;
+
+	ret = qlcnic_do_ilb_test(adapter);
+
+	qlcnic_clear_ilb_mode(adapter);
+
+done:
+	qlcnic_diag_free_res(netdev, max_sds_rings);
+
+clear_it:
+	adapter->max_sds_rings = max_sds_rings;
+	clear_bit(__QLCNIC_RESETTING, &adapter->state);
+	return ret;
+}
+
 static int qlcnic_irq_test(struct net_device *netdev)
 {
 	struct qlcnic_adapter *adapter = netdev_priv(netdev);
@@ -656,6 +731,11 @@ qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
 		data[2] = qlcnic_irq_test(dev);
 		if (data[2])
 			eth_test->flags |= ETH_TEST_FL_FAILED;
+
+		data[3] = qlcnic_loopback_test(dev);
+		if (data[3])
+			eth_test->flags |= ETH_TEST_FL_FAILED;
+
 	}
 
 	data[0] = qlcnic_reg_test(dev);
diff --git a/drivers/net/qlcnic/qlcnic_hw.c b/drivers/net/qlcnic/qlcnic_hw.c
index 8724e56..dc6cd69 100644
--- a/drivers/net/qlcnic/qlcnic_hw.c
+++ b/drivers/net/qlcnic/qlcnic_hw.c
@@ -1221,3 +1221,55 @@ int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate)
 
 	return rv;
 }
+
+static int qlcnic_set_fw_loopback(struct qlcnic_adapter *adapter, u32 flag)
+{
+	struct qlcnic_nic_req	req;
+	int			rv;
+	u64			word;
+
+	memset(&req, 0, sizeof(struct qlcnic_nic_req));
+	req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
+
+	word = QLCNIC_H2C_OPCODE_CONFIG_LOOPBACK |
+			((u64)adapter->portnum << 16);
+	req.req_hdr = cpu_to_le64(word);
+	req.words[0] = cpu_to_le64(flag);
+
+	rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
+	if (rv)
+		dev_err(&adapter->pdev->dev,
+			"%sting loopback mode failed.\n",
+					flag ? "Set" : "Reset");
+	return rv;
+}
+
+int qlcnic_set_ilb_mode(struct qlcnic_adapter *adapter)
+{
+	if (qlcnic_set_fw_loopback(adapter, 1))
+		return -EIO;
+
+	if (qlcnic_nic_set_promisc(adapter,
+				VPORT_MISS_MODE_ACCEPT_ALL)) {
+		qlcnic_set_fw_loopback(adapter, 0);
+		return -EIO;
+	}
+
+	msleep(1000);
+	return 0;
+}
+
+void qlcnic_clear_ilb_mode(struct qlcnic_adapter *adapter)
+{
+	int mode = VPORT_MISS_MODE_DROP;
+	struct net_device *netdev = adapter->netdev;
+
+	qlcnic_set_fw_loopback(adapter, 0);
+
+	if (netdev->flags & IFF_PROMISC)
+		mode = VPORT_MISS_MODE_ACCEPT_ALL;
+	else if (netdev->flags & IFF_ALLMULTI)
+		mode = VPORT_MISS_MODE_ACCEPT_MULTI;
+
+	qlcnic_nic_set_promisc(adapter, mode);
+}
diff --git a/drivers/net/qlcnic/qlcnic_init.c b/drivers/net/qlcnic/qlcnic_init.c
index 7ae8bcc..ea00ab4 100644
--- a/drivers/net/qlcnic/qlcnic_init.c
+++ b/drivers/net/qlcnic/qlcnic_init.c
@@ -1464,3 +1464,78 @@ qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter,
 	spin_unlock(&rds_ring->lock);
 }
 
+static struct qlcnic_rx_buffer *
+qlcnic_process_rcv_diag(struct qlcnic_adapter *adapter,
+		struct qlcnic_host_sds_ring *sds_ring,
+		int ring, u64 sts_data0)
+{
+	struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+	struct qlcnic_rx_buffer *buffer;
+	struct sk_buff *skb;
+	struct qlcnic_host_rds_ring *rds_ring;
+	int index, length, cksum, pkt_offset;
+
+	if (unlikely(ring >= adapter->max_rds_rings))
+		return NULL;
+
+	rds_ring = &recv_ctx->rds_rings[ring];
+
+	index = qlcnic_get_sts_refhandle(sts_data0);
+	if (unlikely(index >= rds_ring->num_desc))
+		return NULL;
+
+	buffer = &rds_ring->rx_buf_arr[index];
+
+	length = qlcnic_get_sts_totallength(sts_data0);
+	cksum  = qlcnic_get_sts_status(sts_data0);
+	pkt_offset = qlcnic_get_sts_pkt_offset(sts_data0);
+
+	skb = qlcnic_process_rxbuf(adapter, rds_ring, index, cksum);
+	if (!skb)
+		return buffer;
+
+	skb_put(skb, rds_ring->skb_size);
+
+	if (pkt_offset)
+		skb_pull(skb, pkt_offset);
+
+	skb->truesize = skb->len + sizeof(struct sk_buff);
+
+	if (!qlcnic_check_loopback_buff(skb->data))
+		adapter->diag_cnt++;
+
+	dev_kfree_skb_any(skb);
+
+	return buffer;
+}
+
+void
+qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring)
+{
+	struct qlcnic_adapter *adapter = sds_ring->adapter;
+	struct status_desc *desc;
+	struct qlcnic_rx_buffer *rxbuf;
+	u64 sts_data0;
+
+	int opcode, ring, desc_cnt;
+	u32 consumer = sds_ring->consumer;
+
+	desc = &sds_ring->desc_head[consumer];
+	sts_data0 = le64_to_cpu(desc->status_desc_data[0]);
+
+	if (!(sts_data0 & STATUS_OWNER_HOST))
+		return;
+
+	desc_cnt = qlcnic_get_sts_desc_cnt(sts_data0);
+	opcode = qlcnic_get_sts_opcode(sts_data0);
+
+	ring = qlcnic_get_sts_type(sts_data0);
+	rxbuf = qlcnic_process_rcv_diag(adapter, sds_ring,
+					ring, sts_data0);
+
+	desc->status_desc_data[0] = cpu_to_le64(STATUS_OWNER_PHANTOM);
+	consumer = get_next_index(consumer, sds_ring->num_desc);
+
+	sds_ring->consumer = consumer;
+	writel(consumer, sds_ring->crb_sts_consumer);
+}
diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c
index a8b0712..665e8e5 100644
--- a/drivers/net/qlcnic/qlcnic_main.c
+++ b/drivers/net/qlcnic/qlcnic_main.c
@@ -65,8 +65,6 @@ static int __devinit qlcnic_probe(struct pci_dev *pdev,
 static void __devexit qlcnic_remove(struct pci_dev *pdev);
 static int qlcnic_open(struct net_device *netdev);
 static int qlcnic_close(struct net_device *netdev);
-static netdev_tx_t qlcnic_xmit_frame(struct sk_buff *,
-					       struct net_device *);
 static void qlcnic_tx_timeout(struct net_device *netdev);
 static void qlcnic_tx_timeout_task(struct work_struct *work);
 static void qlcnic_attach_work(struct work_struct *work);
@@ -937,9 +935,11 @@ void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings)
 	struct qlcnic_host_sds_ring *sds_ring;
 	int ring;
 
-	for (ring = 0; ring < adapter->max_sds_rings; ring++) {
-		sds_ring = &adapter->recv_ctx.sds_rings[ring];
-		qlcnic_disable_int(sds_ring);
+	if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) {
+		for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+			sds_ring = &adapter->recv_ctx.sds_rings[ring];
+			qlcnic_disable_int(sds_ring);
+		}
 	}
 
 	qlcnic_detach(adapter);
@@ -977,9 +977,11 @@ int qlcnic_diag_alloc_res(struct net_device *netdev, int test)
 	if (ret)
 		return ret;
 
-	for (ring = 0; ring < adapter->max_sds_rings; ring++) {
-		sds_ring = &adapter->recv_ctx.sds_rings[ring];
-		qlcnic_enable_int(sds_ring);
+	if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) {
+		for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+			sds_ring = &adapter->recv_ctx.sds_rings[ring];
+			qlcnic_enable_int(sds_ring);
+		}
 	}
 
 	return 0;
@@ -1549,7 +1551,7 @@ qlcnic_clear_cmddesc(u64 *desc)
 	desc[2] = 0ULL;
 }
 
-static netdev_tx_t
+netdev_tx_t
 qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 {
 	struct qlcnic_adapter *adapter = netdev_priv(netdev);
-- 
1.6.0.2


^ 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