Netdev List
 help / color / mirror / Atom feed
* [PATCH net-2.6 3/3] jme: Advance driver version number
From: cooldavid @ 2010-03-15  5:15 UTC (permalink / raw)
  To: David Miller; +Cc: Guo-Fu Tseng, linux-netdev, Ethan Hsiao
In-Reply-To: <1268630108-10374-2-git-send-email-cooldavid@cooldavid.org>

From: Guo-Fu Tseng <cooldavid@cooldavid.org>

Advance driver version number after some bug fix.

Signed-off-by: Guo-Fu Tseng <cooldavid@cooldavid.org>
---
 drivers/net/jme.h |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/jme.h b/drivers/net/jme.h
index 0ed4924..727a3bf 100644
--- a/drivers/net/jme.h
+++ b/drivers/net/jme.h
@@ -25,7 +25,7 @@
 #define __JME_H_INCLUDED__
 
 #define DRV_NAME	"jme"
-#define DRV_VERSION	"1.0.5"
+#define DRV_VERSION	"1.0.6"
 #define PFX		DRV_NAME ": "
 
 #define PCI_DEVICE_ID_JMICRON_JMC250	0x0250
-- 
1.6.4.4


^ permalink raw reply related

* [PATCH net-2.6 2/3] jme: Adding lock to protect vlgrp structure.
From: cooldavid @ 2010-03-15  5:15 UTC (permalink / raw)
  To: David Miller; +Cc: Guo-Fu Tseng, linux-netdev, Ethan Hsiao
In-Reply-To: <1268630108-10374-1-git-send-email-cooldavid@cooldavid.org>

From: Guo-Fu Tseng <cooldavid@cooldavid.org>

Adding a lock to prevent modifying the vlgrp structure while receiving
VLAN packet.

Signed-off-by: Guo-Fu Tseng <cooldavid@cooldavid.org>
---
 drivers/net/jme.c |    6 ++++++
 drivers/net/jme.h |    1 +
 2 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/drivers/net/jme.c b/drivers/net/jme.c
index cfc7b98..9096bbd 100644
--- a/drivers/net/jme.c
+++ b/drivers/net/jme.c
@@ -942,11 +942,14 @@ jme_alloc_and_feed_skb(struct jme_adapter *jme, int idx)
 			skb->ip_summed = CHECKSUM_NONE;
 
 		if (rxdesc->descwb.flags & cpu_to_le16(RXWBFLAG_TAGON)) {
+			spin_lock(&jme->vlgrp_lock);
 			if (jme->vlgrp) {
 				jme->jme_vlan_rx(skb, jme->vlgrp,
 					le16_to_cpu(rxdesc->descwb.vlan));
+				spin_unlock(&jme->vlgrp_lock);
 				NET_STAT(jme).rx_bytes += 4;
 			} else {
+				spin_unlock(&jme->vlgrp_lock);
 				dev_kfree_skb(skb);
 			}
 		} else {
@@ -2088,7 +2091,9 @@ jme_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
 {
 	struct jme_adapter *jme = netdev_priv(netdev);
 
+	spin_lock_bh(&jme->vlgrp_lock);
 	jme->vlgrp = grp;
+	spin_unlock_bh(&jme->vlgrp_lock);
 }
 
 static void
@@ -2755,6 +2760,7 @@ jme_init_one(struct pci_dev *pdev,
 	spin_lock_init(&jme->phy_lock);
 	spin_lock_init(&jme->macaddr_lock);
 	spin_lock_init(&jme->rxmcs_lock);
+	spin_lock_init(&jme->vlgrp_lock);
 
 	atomic_set(&jme->link_changing, 1);
 	atomic_set(&jme->rx_cleaning, 1);
diff --git a/drivers/net/jme.h b/drivers/net/jme.h
index c19db91..0ed4924 100644
--- a/drivers/net/jme.h
+++ b/drivers/net/jme.h
@@ -393,6 +393,7 @@ struct jme_adapter {
 	spinlock_t		phy_lock;
 	spinlock_t		macaddr_lock;
 	spinlock_t		rxmcs_lock;
+	spinlock_t		vlgrp_lock;
 	struct tasklet_struct	rxempty_task;
 	struct tasklet_struct	rxclean_task;
 	struct tasklet_struct	txclean_task;
-- 
1.6.4.4


^ permalink raw reply related

* [PATCH v2.6.33 1/2] jme: Fix VLAN memory leak
From: cooldavid @ 2010-03-15  5:15 UTC (permalink / raw)
  To: David Miller; +Cc: Guo-Fu Tseng, linux-netdev, Ethan Hsiao

From: Guo-Fu Tseng <cooldavid@cooldavid.org>

Fix memory leak while receiving 8021q tagged packet which is not
registered by user.

Signed-off-by: Guo-Fu Tseng <cooldavid@cooldavid.org>
---
 drivers/net/jme.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/drivers/net/jme.c b/drivers/net/jme.c
index 792b88f..3da390a 100644
--- a/drivers/net/jme.c
+++ b/drivers/net/jme.c
@@ -946,6 +946,8 @@ jme_alloc_and_feed_skb(struct jme_adapter *jme, int idx)
 				jme->jme_vlan_rx(skb, jme->vlgrp,
 					le16_to_cpu(rxdesc->descwb.vlan));
 				NET_STAT(jme).rx_bytes += 4;
+			} else {
+				dev_kfree_skb(skb);
 			}
 		} else {
 			jme->jme_rx(skb);
-- 
1.6.4.4


^ permalink raw reply related

* [PATCH v2.6.33 2/2] jme: Adding lock to protect vlgrp structure.
From: cooldavid @ 2010-03-15  5:15 UTC (permalink / raw)
  To: David Miller; +Cc: Guo-Fu Tseng, linux-netdev, Ethan Hsiao
In-Reply-To: <1268630132-10410-1-git-send-email-cooldavid@cooldavid.org>

From: Guo-Fu Tseng <cooldavid@cooldavid.org>

Adding a lock to prevent modifying the vlgrp structure while receiving
VLAN packet.

Signed-off-by: Guo-Fu Tseng <cooldavid@cooldavid.org>
---
 drivers/net/jme.c |    6 ++++++
 drivers/net/jme.h |    1 +
 2 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/drivers/net/jme.c b/drivers/net/jme.c
index 3da390a..f10d9db 100644
--- a/drivers/net/jme.c
+++ b/drivers/net/jme.c
@@ -942,11 +942,14 @@ jme_alloc_and_feed_skb(struct jme_adapter *jme, int idx)
 			skb->ip_summed = CHECKSUM_NONE;
 
 		if (rxdesc->descwb.flags & cpu_to_le16(RXWBFLAG_TAGON)) {
+			spin_lock(&jme->vlgrp_lock);
 			if (jme->vlgrp) {
 				jme->jme_vlan_rx(skb, jme->vlgrp,
 					le16_to_cpu(rxdesc->descwb.vlan));
+				spin_unlock(&jme->vlgrp_lock);
 				NET_STAT(jme).rx_bytes += 4;
 			} else {
+				spin_unlock(&jme->vlgrp_lock);
 				dev_kfree_skb(skb);
 			}
 		} else {
@@ -2092,7 +2095,9 @@ jme_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
 {
 	struct jme_adapter *jme = netdev_priv(netdev);
 
+	spin_lock_bh(&jme->vlgrp_lock);
 	jme->vlgrp = grp;
+	spin_unlock_bh(&jme->vlgrp_lock);
 }
 
 static void
@@ -2759,6 +2764,7 @@ jme_init_one(struct pci_dev *pdev,
 	spin_lock_init(&jme->phy_lock);
 	spin_lock_init(&jme->macaddr_lock);
 	spin_lock_init(&jme->rxmcs_lock);
+	spin_lock_init(&jme->vlgrp_lock);
 
 	atomic_set(&jme->link_changing, 1);
 	atomic_set(&jme->rx_cleaning, 1);
diff --git a/drivers/net/jme.h b/drivers/net/jme.h
index 251abed..fbde5c5 100644
--- a/drivers/net/jme.h
+++ b/drivers/net/jme.h
@@ -420,6 +420,7 @@ struct jme_adapter {
 	spinlock_t		phy_lock;
 	spinlock_t		macaddr_lock;
 	spinlock_t		rxmcs_lock;
+	spinlock_t		vlgrp_lock;
 	struct tasklet_struct	rxempty_task;
 	struct tasklet_struct	rxclean_task;
 	struct tasklet_struct	txclean_task;
-- 
1.6.4.4


^ permalink raw reply related

* [PATCH net-2.6 1/3] jme: Fix VLAN memory leak
From: cooldavid @ 2010-03-15  5:15 UTC (permalink / raw)
  To: David Miller; +Cc: Guo-Fu Tseng, linux-netdev, Ethan Hsiao

From: Guo-Fu Tseng <cooldavid@cooldavid.org>

Fix memory leak while receiving 8021q tagged packet which is not
registered by user.

Signed-off-by: Guo-Fu Tseng <cooldavid@cooldavid.org>
---
 drivers/net/jme.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/drivers/net/jme.c b/drivers/net/jme.c
index 0f31497..cfc7b98 100644
--- a/drivers/net/jme.c
+++ b/drivers/net/jme.c
@@ -946,6 +946,8 @@ jme_alloc_and_feed_skb(struct jme_adapter *jme, int idx)
 				jme->jme_vlan_rx(skb, jme->vlgrp,
 					le16_to_cpu(rxdesc->descwb.vlan));
 				NET_STAT(jme).rx_bytes += 4;
+			} else {
+				dev_kfree_skb(skb);
 			}
 		} else {
 			jme->jme_rx(skb);
-- 
1.6.4.4


^ permalink raw reply related

* net-2.6 [Bug-Fix][dccp]: fix oops caused after failed initialisation
From: Gerrit Renker @ 2010-03-15  6:13 UTC (permalink / raw)
  To: David S. Miller, Arnaldo; +Cc: netdev, dccp

dccp: fix panic caused by failed initialisation

This fixes a kernel panic reported thanks to Andre Noll:

if DCCP is compiled into the kernel and any out of the initialisation
steps in net/dccp/proto.c:dccp_init() fail, a subsequent attempt to create
a SOCK_DCCP socket will panic, since inet{,6}_create() are not prevented
from creating DCCP sockets.

This patch fixes the problem by propagating a failure in dccp_init() to
dccp_v{4,6}_init_net(), and from there to dccp_v{4,6}_init(), so that the
DCCP protocol is not made available if its initialisation fails.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
---
 net/dccp/ipv4.c  |    8 ++++----
 net/dccp/ipv6.c  |    8 ++++----
 net/dccp/proto.c |   16 +++++++++-------
 3 files changed, 17 insertions(+), 15 deletions(-)

--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -998,11 +998,11 @@ static struct inet_protosw dccp_v4_proto
 
 static int __net_init dccp_v4_init_net(struct net *net)
 {
-	int err;
+	if (dccp_hashinfo.bhash == NULL)
+		return -ESOCKTNOSUPPORT;
 
-	err = inet_ctl_sock_create(&net->dccp.v4_ctl_sk, PF_INET,
-				   SOCK_DCCP, IPPROTO_DCCP, net);
-	return err;
+	return inet_ctl_sock_create(&net->dccp.v4_ctl_sk, PF_INET,
+				    SOCK_DCCP, IPPROTO_DCCP, net);
 }
 
 static void __net_exit dccp_v4_exit_net(struct net *net)
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -1191,11 +1191,11 @@ static struct inet_protosw dccp_v6_proto
 
 static int __net_init dccp_v6_init_net(struct net *net)
 {
-	int err;
+	if (dccp_hashinfo.bhash == NULL)
+		return -ESOCKTNOSUPPORT;
 
-	err = inet_ctl_sock_create(&net->dccp.v6_ctl_sk, PF_INET6,
-				   SOCK_DCCP, IPPROTO_DCCP, net);
-	return err;
+	return inet_ctl_sock_create(&net->dccp.v6_ctl_sk, PF_INET6,
+				    SOCK_DCCP, IPPROTO_DCCP, net);
 }
 
 static void __net_exit dccp_v6_exit_net(struct net *net)
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -1036,7 +1036,7 @@ static int __init dccp_init(void)
 		     FIELD_SIZEOF(struct sk_buff, cb));
 	rc = percpu_counter_init(&dccp_orphan_count, 0);
 	if (rc)
-		goto out;
+		goto out_fail;
 	rc = -ENOBUFS;
 	inet_hashinfo_init(&dccp_hashinfo);
 	dccp_hashinfo.bind_bucket_cachep =
@@ -1125,8 +1125,9 @@ static int __init dccp_init(void)
 		goto out_sysctl_exit;
 
 	dccp_timestamping_init();
-out:
-	return rc;
+
+	return 0;
+
 out_sysctl_exit:
 	dccp_sysctl_exit();
 out_ackvec_exit:
@@ -1135,18 +1136,19 @@ out_free_dccp_mib:
 	dccp_mib_exit();
 out_free_dccp_bhash:
 	free_pages((unsigned long)dccp_hashinfo.bhash, bhash_order);
-	dccp_hashinfo.bhash = NULL;
 out_free_dccp_locks:
 	inet_ehash_locks_free(&dccp_hashinfo);
 out_free_dccp_ehash:
 	free_pages((unsigned long)dccp_hashinfo.ehash, ehash_order);
-	dccp_hashinfo.ehash = NULL;
 out_free_bind_bucket_cachep:
 	kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep);
-	dccp_hashinfo.bind_bucket_cachep = NULL;
 out_free_percpu:
 	percpu_counter_destroy(&dccp_orphan_count);
-	goto out;
+out_fail:
+	dccp_hashinfo.bhash = NULL;
+	dccp_hashinfo.ehash = NULL;
+	dccp_hashinfo.bind_bucket_cachep = NULL;
+	return rc;
 }
 
 static void __exit dccp_fini(void)

^ permalink raw reply

* [patch] myri: remove dead code
From: Dan Carpenter @ 2010-03-15  8:24 UTC (permalink / raw)
  To: Andrew Gallatin
  Cc: Brice Goglin, David S. Miller, Patrick McHardy, netdev,
	kernel-janitors

We can never reach the return statement.

Signed-off-by: Dan Carpenter <error27@gmail.com>

diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index 676c513..e84dd3e 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -3687,7 +3687,6 @@ static void myri10ge_probe_slices(struct myri10ge_priv *mgp)
 	if (status != 0) {
 		dev_err(&mgp->pdev->dev, "failed reset\n");
 		goto abort_with_fw;
-		return;
 	}
 
 	mgp->max_intr_slots = cmd.data0 / sizeof(struct mcp_slot);

^ permalink raw reply related

* Re: [PATCH] [V2] Add non-Virtex5 support for LL TEMAC driver
From: Michal Simek @ 2010-03-15  8:39 UTC (permalink / raw)
  To: John Linn
  Cc: netdev, linuxppc-dev, grant.likely, jwboyer, john.williams,
	John Tyner
In-Reply-To: <bda26c8d-00b2-411d-b4b7-ad6954b9049e@SG2EHSMHS005.ehs.local>

John Linn wrote:
> This patch adds support for using the LL TEMAC Ethernet driver on
> non-Virtex 5 platforms by adding support for accessing the Soft DMA
> registers as if they were memory mapped instead of solely through the
> DCR's (available on the Virtex 5).
> 
> The patch also updates the driver so that it runs on the MicroBlaze.
> The changes were tested on the PowerPC 440, PowerPC 405, and the
> MicroBlaze platforms.

Which git-tree have you tested on? (Of course microblaze)

Michal

> 
> Signed-off-by: John Tyner <jtyner@cs.ucr.edu>
> Signed-off-by: John Linn <john.linn@xilinx.com>
> ---
> 
> V2 - Incorporated comments from Grant and added more logic to allow the driver
> to work on MicroBlaze.
> 
>  drivers/net/Kconfig         |    1 -
>  drivers/net/ll_temac.h      |   17 +++++-
>  drivers/net/ll_temac_main.c |  124 ++++++++++++++++++++++++++++++++++---------
>  3 files changed, 113 insertions(+), 29 deletions(-)
> 
> diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
> index 9b6efe1..5402105 100644
> --- a/drivers/net/Kconfig
> +++ b/drivers/net/Kconfig
> @@ -2443,7 +2443,6 @@ config MV643XX_ETH
>  config XILINX_LL_TEMAC
>  	tristate "Xilinx LL TEMAC (LocalLink Tri-mode Ethernet MAC) driver"
>  	select PHYLIB
> -	depends on PPC_DCR_NATIVE
>  	help
>  	  This driver supports the Xilinx 10/100/1000 LocalLink TEMAC
>  	  core used in Xilinx Spartan and Virtex FPGAs
> diff --git a/drivers/net/ll_temac.h b/drivers/net/ll_temac.h
> index 1af66a1..915aa34 100644
> --- a/drivers/net/ll_temac.h
> +++ b/drivers/net/ll_temac.h
> @@ -5,8 +5,11 @@
>  #include <linux/netdevice.h>
>  #include <linux/of.h>
>  #include <linux/spinlock.h>
> +
> +#ifdef CONFIG_PPC_DCR
>  #include <asm/dcr.h>
>  #include <asm/dcr-regs.h>
> +#endif
>  
>  /* packet size info */
>  #define XTE_HDR_SIZE			14      /* size of Ethernet header */
> @@ -290,8 +293,12 @@ This option defaults to enabled (set) */
>  
>  #define TX_CONTROL_CALC_CSUM_MASK   1
>  
> +/* Align the IP data in the packet on word boundaries as MicroBlaze
> + * needs it.
> + */
> +
>  #define XTE_ALIGN       32
> -#define BUFFER_ALIGN(adr) ((XTE_ALIGN - ((u32) adr)) % XTE_ALIGN)
> +#define BUFFER_ALIGN(adr) ((34 - ((u32) adr)) % XTE_ALIGN)
>  
>  #define MULTICAST_CAM_TABLE_NUM 4
>  
> @@ -335,9 +342,15 @@ struct temac_local {
>  	struct mii_bus *mii_bus;	/* MII bus reference */
>  	int mdio_irqs[PHY_MAX_ADDR];	/* IRQs table for MDIO bus */
>  
> -	/* IO registers and IRQs */
> +	/* IO registers, dma functions and IRQs */
>  	void __iomem *regs;
> +	void __iomem *sdma_regs;
> +#ifdef CONFIG_PPC_DCR
>  	dcr_host_t sdma_dcrs;
> +#endif
> +	u32 (*dma_in)(struct temac_local *, int);
> +	void (*dma_out)(struct temac_local *, int, u32);
> +
>  	int tx_irq;
>  	int rx_irq;
>  	int emac_num;
> diff --git a/drivers/net/ll_temac_main.c b/drivers/net/ll_temac_main.c
> index a18e348..9aedf9b 100644
> --- a/drivers/net/ll_temac_main.c
> +++ b/drivers/net/ll_temac_main.c
> @@ -20,9 +20,6 @@
>   *   or rx, so this should be okay.
>   *
>   * TODO:
> - * - Fix driver to work on more than just Virtex5.  Right now the driver
> - *   assumes that the locallink DMA registers are accessed via DCR
> - *   instructions.
>   * - Factor out locallink DMA code into separate driver
>   * - Fix multicast assignment.
>   * - Fix support for hardware checksumming.
> @@ -115,17 +112,86 @@ void temac_indirect_out32(struct temac_local *lp, int reg, u32 value)
>  	temac_iow(lp, XTE_CTL0_OFFSET, CNTLREG_WRITE_ENABLE_MASK | reg);
>  }
>  
> +/**
> + * temac_dma_in32 - Memory mapped DMA read, this function expects a
> + * register input that is based on DCR word addresses which
> + * are then converted to memory mapped byte addresses
> + */
>  static u32 temac_dma_in32(struct temac_local *lp, int reg)
>  {
> -	return dcr_read(lp->sdma_dcrs, reg);
> +	return in_be32((u32 *)(lp->sdma_regs + (reg << 2)));
>  }
>  
> +/**
> + * temac_dma_out32 - Memory mapped DMA read, this function expects a
> + * register input that is based on DCR word addresses which
> + * are then converted to memory mapped byte addresses
> + */
>  static void temac_dma_out32(struct temac_local *lp, int reg, u32 value)
>  {
> +	out_be32((u32 *)(lp->sdma_regs + (reg << 2)), value);
> +}
> +
> +/* DMA register access functions can be DCR based or memory mapped.
> + * The PowerPC 440 is DCR based, the PowerPC 405 and MicroBlaze are both
> + * memory mapped.
> + */
> +#ifdef CONFIG_PPC_DCR
> +
> +/**
> + * temac_dma_dcr_in32 - DCR based DMA read
> + */
> +static u32 temac_dma_dcr_in(struct temac_local *lp, int reg)
> +{
> +	return dcr_read(lp->sdma_dcrs, reg);
> +}
> +
> +/**
> + * temac_dma_dcr_out32 - DCR based DMA write
> + */
> +static void temac_dma_dcr_out(struct temac_local *lp, int reg, u32 value)
> +{
>  	dcr_write(lp->sdma_dcrs, reg, value);
>  }
>  
>  /**
> + * temac_dcr_setup - If the DMA is DCR based, then setup the address and
> + * I/O  functions
> + */
> +static int temac_dcr_setup(struct temac_local *lp, struct of_device *op,
> +				struct device_node *np)
> +{
> +	unsigned int dcrs;
> +
> +	/* setup the dcr address mapping if it's in the device tree */
> +
> +	dcrs = dcr_resource_start(np, 0);
> +	if (dcrs != 0) {
> +		lp->sdma_dcrs = dcr_map(np, dcrs, dcr_resource_len(np, 0));
> +		lp->dma_in = temac_dma_dcr_in;
> +		lp->dma_out = temac_dma_dcr_out;
> +		dev_dbg(&op->dev, "DCR base: %x\n", dcrs);
> +		return 0;
> +	}
> +	/* no DCR in the device tree, indicate a failure */
> +	return -1;
> +}
> +
> +#else
> +
> +/*
> + * temac_dcr_setup - This is a stub for when DCR is not supported,
> + * such as with MicroBlaze
> + */
> +static int temac_dcr_setup(struct temac_local *lp, struct of_device *op,
> +				struct device_node *np)
> +{
> +	return -1;
> +}
> +
> +#endif
> +
> +/**
>   * temac_dma_bd_init - Setup buffer descriptor rings
>   */
>  static int temac_dma_bd_init(struct net_device *ndev)
> @@ -172,23 +238,23 @@ static int temac_dma_bd_init(struct net_device *ndev)
>  		lp->rx_bd_v[i].app0 = STS_CTRL_APP0_IRQONEND;
>  	}
>  
> -	temac_dma_out32(lp, TX_CHNL_CTRL, 0x10220400 |
> +	lp->dma_out(lp, TX_CHNL_CTRL, 0x10220400 |
>  					  CHNL_CTRL_IRQ_EN |
>  					  CHNL_CTRL_IRQ_DLY_EN |
>  					  CHNL_CTRL_IRQ_COAL_EN);
>  	/* 0x10220483 */
>  	/* 0x00100483 */
> -	temac_dma_out32(lp, RX_CHNL_CTRL, 0xff010000 |
> +	lp->dma_out(lp, RX_CHNL_CTRL, 0xff010000 |
>  					  CHNL_CTRL_IRQ_EN |
>  					  CHNL_CTRL_IRQ_DLY_EN |
>  					  CHNL_CTRL_IRQ_COAL_EN |
>  					  CHNL_CTRL_IRQ_IOE);
>  	/* 0xff010283 */
>  
> -	temac_dma_out32(lp, RX_CURDESC_PTR,  lp->rx_bd_p);
> -	temac_dma_out32(lp, RX_TAILDESC_PTR,
> +	lp->dma_out(lp, RX_CURDESC_PTR,  lp->rx_bd_p);
> +	lp->dma_out(lp, RX_TAILDESC_PTR,
>  		       lp->rx_bd_p + (sizeof(*lp->rx_bd_v) * (RX_BD_NUM - 1)));
> -	temac_dma_out32(lp, TX_CURDESC_PTR, lp->tx_bd_p);
> +	lp->dma_out(lp, TX_CURDESC_PTR, lp->tx_bd_p);
>  
>  	return 0;
>  }
> @@ -426,9 +492,9 @@ static void temac_device_reset(struct net_device *ndev)
>  	temac_indirect_out32(lp, XTE_RXC1_OFFSET, val & ~XTE_RXC1_RXEN_MASK);
>  
>  	/* Reset Local Link (DMA) */
> -	temac_dma_out32(lp, DMA_CONTROL_REG, DMA_CONTROL_RST);
> +	lp->dma_out(lp, DMA_CONTROL_REG, DMA_CONTROL_RST);
>  	timeout = 1000;
> -	while (temac_dma_in32(lp, DMA_CONTROL_REG) & DMA_CONTROL_RST) {
> +	while (lp->dma_in(lp, DMA_CONTROL_REG) & DMA_CONTROL_RST) {
>  		udelay(1);
>  		if (--timeout == 0) {
>  			dev_err(&ndev->dev,
> @@ -436,7 +502,7 @@ static void temac_device_reset(struct net_device *ndev)
>  			break;
>  		}
>  	}
> -	temac_dma_out32(lp, DMA_CONTROL_REG, DMA_TAIL_ENABLE);
> +	lp->dma_out(lp, DMA_CONTROL_REG, DMA_TAIL_ENABLE);
>  
>  	temac_dma_bd_init(ndev);
>  
> @@ -597,7 +663,7 @@ static int temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
>  		lp->tx_bd_tail = 0;
>  
>  	/* Kick off the transfer */
> -	temac_dma_out32(lp, TX_TAILDESC_PTR, tail_p); /* DMA start */
> +	lp->dma_out(lp, TX_TAILDESC_PTR, tail_p); /* DMA start */
>  
>  	return NETDEV_TX_OK;
>  }
> @@ -663,7 +729,7 @@ static void ll_temac_recv(struct net_device *ndev)
>  		cur_p = &lp->rx_bd_v[lp->rx_bd_ci];
>  		bdstat = cur_p->app0;
>  	}
> -	temac_dma_out32(lp, RX_TAILDESC_PTR, tail_p);
> +	lp->dma_out(lp, RX_TAILDESC_PTR, tail_p);
>  
>  	spin_unlock_irqrestore(&lp->rx_lock, flags);
>  }
> @@ -674,8 +740,8 @@ static irqreturn_t ll_temac_tx_irq(int irq, void *_ndev)
>  	struct temac_local *lp = netdev_priv(ndev);
>  	unsigned int status;
>  
> -	status = temac_dma_in32(lp, TX_IRQ_REG);
> -	temac_dma_out32(lp, TX_IRQ_REG, status);
> +	status = lp->dma_in(lp, TX_IRQ_REG);
> +	lp->dma_out(lp, TX_IRQ_REG, status);
>  
>  	if (status & (IRQ_COAL | IRQ_DLY))
>  		temac_start_xmit_done(lp->ndev);
> @@ -692,8 +758,8 @@ static irqreturn_t ll_temac_rx_irq(int irq, void *_ndev)
>  	unsigned int status;
>  
>  	/* Read and clear the status registers */
> -	status = temac_dma_in32(lp, RX_IRQ_REG);
> -	temac_dma_out32(lp, RX_IRQ_REG, status);
> +	status = lp->dma_in(lp, RX_IRQ_REG);
> +	lp->dma_out(lp, RX_IRQ_REG, status);
>  
>  	if (status & (IRQ_COAL | IRQ_DLY))
>  		ll_temac_recv(lp->ndev);
> @@ -794,7 +860,7 @@ static ssize_t temac_show_llink_regs(struct device *dev,
>  	int i, len = 0;
>  
>  	for (i = 0; i < 0x11; i++)
> -		len += sprintf(buf + len, "%.8x%s", temac_dma_in32(lp, i),
> +		len += sprintf(buf + len, "%.8x%s", lp->dma_in(lp, i),
>  			       (i % 8) == 7 ? "\n" : " ");
>  	len += sprintf(buf + len, "\n");
>  
> @@ -820,7 +886,6 @@ temac_of_probe(struct of_device *op, const struct of_device_id *match)
>  	struct net_device *ndev;
>  	const void *addr;
>  	int size, rc = 0;
> -	unsigned int dcrs;
>  
>  	/* Init network device structure */
>  	ndev = alloc_etherdev(sizeof(*lp));
> @@ -870,13 +935,20 @@ temac_of_probe(struct of_device *op, const struct of_device_id *match)
>  		goto nodev;
>  	}
>  
> -	dcrs = dcr_resource_start(np, 0);
> -	if (dcrs == 0) {
> -		dev_err(&op->dev, "could not get DMA register address\n");
> -		goto nodev;
> +	/* Setup the DMA register accesses, could be DCR or memory mapped */
> +	if (temac_dcr_setup(lp, op, np)) {
> +
> +		/* no DCR in the device tree, try non-DCR */
> +		lp->sdma_regs = of_iomap(np, 0);
> +		if (lp->sdma_regs) {
> +			lp->dma_in = temac_dma_in32;
> +			lp->dma_out = temac_dma_out32;
> +			dev_dbg(&op->dev, "MEM base: %p\n", lp->sdma_regs);
> +		} else {
> +			dev_err(&op->dev, "unable to map DMA registers\n");
> +			goto nodev;
> +		}
>  	}
> -	lp->sdma_dcrs = dcr_map(np, dcrs, dcr_resource_len(np, 0));
> -	dev_dbg(&op->dev, "DCR base: %x\n", dcrs);
>  
>  	lp->rx_irq = irq_of_parse_and_map(np, 0);
>  	lp->tx_irq = irq_of_parse_and_map(np, 1);


-- 
Michal Simek, Ing. (M.Eng)
PetaLogix - Linux Solutions for a Reconfigurable World
w: www.petalogix.com p: +61-7-30090663,+42-0-721842854 f: +61-7-30090663

^ permalink raw reply

* RE: [PATCH v1 2/3] Provides multiple submits and asynchronous notifications.
From: Xin, Xiaohui @ 2010-03-15  8:46 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: netdev@vger.kernel.org, kvm@vger.kernel.org,
	linux-kernel@vger.kernel.org, mingo@elte.hu,
	jdike@c2.user-mode-linux.org
In-Reply-To: <20100307111816.GC20004@redhat.com>

>> +/* The structure to notify the virtqueue for async socket */
>> +struct vhost_notifier {
>> +	struct list_head list;
> >+	struct vhost_virtqueue *vq;
> >+	int head;
> >+	int size;
> >+	int log;
> >+	void *ctrl;
> >+	void (*dtor)(struct vhost_notifier *);
> >+};
> >+

>So IMO, this is not the best interface between vhost
>and your driver, exposing them to each other unnecessarily.
>
>If you think about it, your driver should not care about this structure.
>It could get e.g. a kiocb (sendmsg already gets one), and call ki_dtor
>on completion.  vhost could save it's state in ki_user_data.  If your
>driver needs to add more data to do more tracking, I think it can put
>skb pointer in the private pointer.

Then if I remove the struct vhost_notifier, and just use struct kiocb, but don't use the one got from sendmsg or recvmsg, but allocated within the page_info structure, and don't implement any aio logic related to it, is that ok?

Sorry, I made a patch, but don't know how to reply mail with a good formatted patch here....

Thanks
Xiaohui

^ permalink raw reply

* Re: KS8695: possible NAPI issue
From: Yegor Yefremov @ 2010-03-15  9:19 UTC (permalink / raw)
  To: figo zhang; +Cc: Dick Hollenbeck, netdev, zealcook
In-Reply-To: <c6ed1ac51003081750v19f9d5fuf07ad0cc2478005d@mail.gmail.com>

On Tue, Mar 9, 2010 at 2:50 AM, figo zhang <figo1802@gmail.com> wrote:
> 2010/3/8 Yegor Yefremov <yegorslists@googlemail.com>:
>> This is ping afterwards:
>>
>> debian:~# ping -c 1 192.168.1.38
>>
>> PING 192.168.1.38 (192.168.1.38) 56(84) bytes of data.
>>
>>
>>  tx   ram addr = c371c202 , data len = 62
>>
>>  dst:00:18:f3:fe:84:84 src:00:04:d9:80:94:cd type: 0x0800
>
> => the print info is not clear, it had better just keep "print_mem()",
> and remove other printk.
>
>>
>>  0xc371c20e : 45 00
>>
>>  0xc371c212 : 00 54 00 00 40 00 40 01 b6 f0 c0 a8 01 42 c0 a8
>>
>>  0xc371c222 : 01 26 08 00 65 51 1a 07 00 01 92 00 95 4b 5f 57
>>
>>  0xc371c232 : 07 00 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15
>>
>>  0xc371c242 : 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25
>>
>>  0xc371c252 : 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35
>>
>>  0xc371c262 : 36 37
>>
>>
>>
>>  tx   ram addr = c371c202 , data len = 2a
>>
>>  dst:00:18:f3:fe:84:84 src:00:04:d9:80:94:cd type: 0x0806
>>
>>  0xc371c20e : 00 01
>>
>>  0xc371c212 : 08 00 06 04 00 01 00 04 d9 80 94 cd c0 a8 01 42
> => it is a send arp packet, "c0 a8 01 42" is your curr ip addr
> 192.168.1.66, tell the other side it's ip addr.
>>
>>  0xc371c222 : 00 00 00 00 00 00 c0 a8 01 26
>>
>>
>>
>>  rx   ram addr = c35d2020 , data len = 3c
>>
>>  dst:00:04:d9:80:94:cd src:00:18:f3:fe:84:84 type: 0x0806
>>
>>  0xc35d202c : 00 01
>>
>>  0xc35d2030 : 08 00 06 04 00 02 00 18 f3 fe 84 84 c0 a8 01 26
>
> => it is a reply arp packet, "c0 a8 01 26" (192.168.1.38 ) is other
> side ip addr. so the arp
> request is finished.
>
>>
>>  0xc35d2040 : 00 04 d9 80 94 cd c0 a8 01 42 00 00 00 00 00 00
>>
>>  0xc35d2050 : 00 00 00 00 00 00 00 00 00 00 00 00
>>
> => so , it should still send  "IMCP" packet, you using "ping -c 1", it
> send one IMCP packet , and wait for reply.  at this point, it have not
> send packet?

I made some tests on Fr with a Netbook connected directly to our
ks8695 based device and not to the companies network. During the test
I couldn't encounter any problem. Than I connected ks8695 again to the
companies network and the issue was there right away. So I decided to
check how many broadcast I get and it turned out that I have one
device on the network that is sending broadcast almost every second if
not more frequent. It turned out that the network on ks8695 was not
completely down, but very slow and many packets got lost. As soon as I
removed the broadcast sending device I could ping ks8695. The
consequences:

1. as long as I make no netcat transfer, the network responses are as
usual regardless of many broadcasts
2. if during netcat a broadcast occurs, than the network is getting
slow, so that if during a constant ping you get a broadcast that ping
response gets lost

Any idea how broadcast during transfer could affect NAPI in that way?

Regards,
Yeor

^ permalink raw reply

* Re: [PATCH v1 2/3] Provides multiple submits and asynchronous notifications.
From: Michael S. Tsirkin @ 2010-03-15  9:23 UTC (permalink / raw)
  To: Xin, Xiaohui
  Cc: netdev@vger.kernel.org, kvm@vger.kernel.org,
	linux-kernel@vger.kernel.org, mingo@elte.hu,
	jdike@c2.user-mode-linux.org
In-Reply-To: <97F6D3BD476C464182C1B7BABF0B0AF5C164CEED@shzsmsx502.ccr.corp.intel.com>

On Mon, Mar 15, 2010 at 04:46:50PM +0800, Xin, Xiaohui wrote:
> >> +/* The structure to notify the virtqueue for async socket */
> >> +struct vhost_notifier {
> >> +	struct list_head list;
> > >+	struct vhost_virtqueue *vq;
> > >+	int head;
> > >+	int size;
> > >+	int log;
> > >+	void *ctrl;
> > >+	void (*dtor)(struct vhost_notifier *);
> > >+};
> > >+
> 
> >So IMO, this is not the best interface between vhost
> >and your driver, exposing them to each other unnecessarily.
> >
> >If you think about it, your driver should not care about this structure.
> >It could get e.g. a kiocb (sendmsg already gets one), and call ki_dtor
> >on completion.  vhost could save it's state in ki_user_data.  If your
> >driver needs to add more data to do more tracking, I think it can put
> >skb pointer in the private pointer.
> 
> Then if I remove the struct vhost_notifier, and just use struct kiocb, but don't use the one got from sendmsg or recvmsg, but allocated within the page_info structure, and don't implement any aio logic related to it, is that ok?

Hmm, not sure I understand.  It seems both cleaner and easier to use the
iocb passed to sendmsg/recvmsg. No? I am not saying you necessarily must
implement full aio directly.

> Sorry, I made a patch, but don't know how to reply mail with a good formatted patch here....
> 
> Thanks
> Xiaohui

Maybe Documentation/email-clients.txt will help?
Generally you do it like this (at start of mail):

Subject: one line patch summary (overrides mail subject)

multilie patch description

Signed-off-by: <...>

---

Free text comes after --- delimeter, before patch.

diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index a140dad..e830b30 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -106,22 +106,41 @@ static void handle_tx(struct vhost_net *net)




-- 
MST

^ permalink raw reply related

* Re: 2.6.34-rc1: rcu lockdep bug?
From: Américo Wang @ 2010-03-15  9:39 UTC (permalink / raw)
  To: Paul E. McKenney
  Cc: Américo Wang, Eric Dumazet, David Miller, peterz,
	linux-kernel, netdev
In-Reply-To: <2375c9f91003142010g61841666iad53c24f39036acf@mail.gmail.com>

2010/3/15 Américo Wang <xiyou.wangcong@gmail.com>:
> 2010/3/15 Américo Wang <xiyou.wangcong@gmail.com>:
>> On Sat, Mar 13, 2010 at 01:58:38PM -0800, Paul E. McKenney wrote:
>>>On Sat, Mar 13, 2010 at 01:33:56PM +0800, Américo Wang wrote:
>>>> On Fri, Mar 12, 2010 at 02:37:38PM +0100, Eric Dumazet wrote:
>>>> >Le vendredi 12 mars 2010 à 21:11 +0800, Américo Wang a écrit :
>>>> >
>>>> >> Oh, but lockdep complains about rcu_read_lock(), it said
>>>> >> rcu_read_lock() can't be used in softirq context.
>>>> >>
>>>> >> Am I missing something?
>>>> >
>>>> >Well, lockdep might be dumb, I dont know...
>>>> >
>>>> >I suggest you read rcu_read_lock_bh kernel doc :
>>>> >
>>>> >/**
>>>> > * rcu_read_lock_bh - mark the beginning of a softirq-only RCU critical
>>>> >section
>>>> > *
>>>> > * This is equivalent of rcu_read_lock(), but to be used when updates
>>>> > * are being done using call_rcu_bh(). Since call_rcu_bh() callbacks
>>>> > * consider completion of a softirq handler to be a quiescent state,
>>>> > * a process in RCU read-side critical section must be protected by
>>>> > * disabling softirqs. Read-side critical sections in interrupt context
>>>> > * can use just rcu_read_lock().
>>>> > *
>>>> > */
>>>> >
>>>> >
>>>> >Last sentence being perfect :
>>>> >
>>>> >Read-side critical sections in interrupt context
>>>> >can use just rcu_read_lock().
>>>> >
>>>>
>>>> Yeah, right, then it is more likely to be a bug of rcu lockdep.
>>>> Paul is looking at it.
>>>
>>>Except that it seems to be working correctly for me...
>>>
>>
>> Hmm, then I am confused. The only possibility here is that this is
>> a lockdep bug...
>>
>
> I believe so...
>
> Peter, this looks odd:
>
>  kernel:  (usbfs_mutex){+.?...}, at: [<ffffffff8146419f>]
> netif_receive_skb+0xe7/0x819
>
> netif_receive_skb() never has a chance to take usbfs_mutex. How can this
> comes out?
>

Ok, I think I found what lockdep really complains about, it is that we took
spin_lock in netpoll_poll_lock() which is in hardirq-enabled environment,
later, we took another spin_lock with spin_lock_irqsave() in netpoll_rx(),
so lockdep thought we broke the locking rule.

I don't know why netpoll_rx() needs irq disabled, it looks like that no one
takes rx_lock in hardirq context. So can we use spin_lock(&rx_lock)
instead? Or am I missing something here? Eric? David?

Thanks!

^ permalink raw reply

* Re: 2.6.34-rc1: rcu lockdep bug?
From: Eric Dumazet @ 2010-03-15 10:04 UTC (permalink / raw)
  To: Américo Wang
  Cc: Paul E. McKenney, David Miller, peterz, linux-kernel, netdev
In-Reply-To: <2375c9f91003150239m1abc765bh59eb51c948eed592@mail.gmail.com>

Le lundi 15 mars 2010 à 17:39 +0800, Américo Wang a écrit :

> 
> Ok, I think I found what lockdep really complains about, it is that we took
> spin_lock in netpoll_poll_lock() which is in hardirq-enabled environment,
> later, we took another spin_lock with spin_lock_irqsave() in netpoll_rx(),
> so lockdep thought we broke the locking rule.
> 
> I don't know why netpoll_rx() needs irq disabled, it looks like that no one
> takes rx_lock in hardirq context. So can we use spin_lock(&rx_lock)
> instead? Or am I missing something here? Eric? David?

I am a bit lost.

Could you give the complete picture, because I cannot find it in my
netdev archives.




^ permalink raw reply

* Re: 2.6.34-rc1: rcu lockdep bug?
From: Américo Wang @ 2010-03-15 10:12 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: Paul E. McKenney, David Miller, peterz, linux-kernel, netdev
In-Reply-To: <1268647460.3154.1.camel@edumazet-laptop>

On Mon, Mar 15, 2010 at 6:04 PM, Eric Dumazet <eric.dumazet@gmail.com> wrote:
> Le lundi 15 mars 2010 à 17:39 +0800, Américo Wang a écrit :
>
>>
>> Ok, I think I found what lockdep really complains about, it is that we took
>> spin_lock in netpoll_poll_lock() which is in hardirq-enabled environment,
>> later, we took another spin_lock with spin_lock_irqsave() in netpoll_rx(),
>> so lockdep thought we broke the locking rule.
>>
>> I don't know why netpoll_rx() needs irq disabled, it looks like that no one
>> takes rx_lock in hardirq context. So can we use spin_lock(&rx_lock)
>> instead? Or am I missing something here? Eric? David?
>
> I am a bit lost.
>
> Could you give the complete picture, because I cannot find it in my
> netdev archives.
>

Sure, sorry for this.

Here is the whole thread:

http://lkml.org/lkml/2010/3/11/100

^ permalink raw reply

* Re: 2.6.34-rc1: rcu lockdep bug?
From: Eric Dumazet @ 2010-03-15 10:41 UTC (permalink / raw)
  To: Américo Wang
  Cc: Paul E. McKenney, David Miller, peterz, linux-kernel, netdev
In-Reply-To: <2375c9f91003150312u37dfd70fk55a4b8820e13590e@mail.gmail.com>

Le lundi 15 mars 2010 à 18:12 +0800, Américo Wang a écrit :
> On Mon, Mar 15, 2010 at 6:04 PM, Eric Dumazet <eric.dumazet@gmail.com> wrote:
> > Le lundi 15 mars 2010 à 17:39 +0800, Américo Wang a écrit :
> >
> >>
> >> Ok, I think I found what lockdep really complains about, it is that we took
> >> spin_lock in netpoll_poll_lock() which is in hardirq-enabled environment,
> >> later, we took another spin_lock with spin_lock_irqsave() in netpoll_rx(),
> >> so lockdep thought we broke the locking rule.
> >>
> >> I don't know why netpoll_rx() needs irq disabled, it looks like that no one
> >> takes rx_lock in hardirq context. So can we use spin_lock(&rx_lock)
> >> instead? Or am I missing something here? Eric? David?
> >
> > I am a bit lost.
> >
> > Could you give the complete picture, because I cannot find it in my
> > netdev archives.
> >
> 
> Sure, sorry for this.
> 
> Here is the whole thread:
> 
> http://lkml.org/lkml/2010/3/11/100

OK thanks

netpoll_rx() can be called from hard irqs (netif_rx()), so rx_lock
definitly needs irq care.

netpoll_poll_lock() does take a spinlock with irq enabled, but its not
rx_lock, its napi->poll_lock.

I dont see what could be the problem, is it reproductible with vanilla
kernel ?

^ permalink raw reply

* Re: [PATCH 0/3] pci: fix/cleanup pcix get and set mmrbc functions
From: Dean Nelson @ 2010-03-15 10:59 UTC (permalink / raw)
  To: Jesse Barnes; +Cc: netdev, linux-pci
In-Reply-To: <20100312170000.55cc055a@jbarnes-piketon>

On 03/12/2010 07:00 PM, Jesse Barnes wrote:
> On Tue, 9 Mar 2010 22:26:33 -0500
> Dean Nelson<dnelson@redhat.com>  wrote:
>
>> A customer running RHEL4.8 encountered
>>
>>   "e1000: eth0: e1000_clean_tx_irq: Detected Tx Unit Hang"
>>
>> type errors, which were determined to be the result of a bad return value
>> from e1000_pcix_get_mmrbc() causing the call to e1000_pcix_set_mmrbc() to
>> be skipped in the following snippet of code from e1000_init_hw().
>>
>> 	switch (hw->mac_type) {
>> 	case e1000_82545_rev_3:
>> 	case e1000_82546_rev_3:
>> 		break;
>> 	default:
>> 		/* Workaround for PCI-X problem when BIOS sets MMRBC incorrectly. */
>> 		if (hw->bus_type == e1000_bus_type_pcix
>> 		&&  e1000_pcix_get_mmrbc(hw)>  2048)
>> 			e1000_pcix_set_mmrbc(hw, 2048);
>> 		break;
>> 	}
>>
>> e1000_pcix_get_mmrbc() is basically a wrapper for a call to pcix_get_mmrbc().
>> e1000_pcix_set_mmrbc() is the same for pcix_set_mmrbc().
>>
>> The following three patches are a response to the problems that were found to
>> exist with pcix_get_max_mmrbc(), pcix_get_mmrbc() and pcix_set_mmrbc().
>>
>> Versions of these patches applicable to RHEL4 were verified by the customer to
>> solve their problem.
>
> Thanks Dean, I'll pull these in and send them to Linus for 2.6.34.  I
> assume they should also be included in the stable kernel series?  If
> so, I'll add a cc: stable@kernel.org when I commit them.

Yes, they should also be included in the stable kernel series. Thanks so 
much Jesse.

Dean

^ permalink raw reply

* Re: [patch] myri: remove dead code
From: Andrew Gallatin @ 2010-03-15 11:19 UTC (permalink / raw)
  To: Dan Carpenter
  Cc: Brice Goglin, David S. Miller, Patrick McHardy, netdev,
	kernel-janitors
In-Reply-To: <20100315082408.GG18181@bicker>

Dan Carpenter wrote:
> We can never reach the return statement.

Agreed, thanks for pointing that out.

Drew

^ permalink raw reply

* [PATCH] xfrm: cache bundle lookup results in flow cache
From: Timo Teras @ 2010-03-15 12:20 UTC (permalink / raw)
  To: netdev; +Cc: Timo Teras, Herbert Xu

Instead of doing O(n) xfrm_find_bundle() call per-packet, cache
the previous lookup results in flow cache. The flow cache is
updated to be per-netns and more generic.

The flow cache no longer holds reference (which was not really
used in the first place, as it depended on garbage collection).
Now this is more explicit. The cache validity is maintained as follows:
- On policy insert, the whole cache is invalideted by incrementing
  generation id. No synchronization required as genid checks make
  sure no old objects are dereferenced.
- On policy removal from lists the object is marked deleted, and
  this invalidated the policy pointer.
- Policy object deletion requires explicit synchronization to remove
  stale pointers before can actually free the policy objects.
  xfrm_policy_gc_task() synchronizes the cache.
- Bundle creation and expiry is reflected in xfrm_bundle_ok() check
  before any bundle from cache is used.
- Bundle deletion is done by incrementing policy->bundles_genid and
  synchronizing with other cpu's so there is no stale bundle pointers
  left. After this the bundle objects can be safely deleted.

Basic testing done on 2.6.32 based kernel. This gives a boost of
several magnitudes on transmit path.

Signed-off-by: Timo Teras <timo.teras@iki.fi>
Cc: Herbert Xu <herbert@gondor.apana.org.au>
---
 include/net/flow.h               |   39 ++++-
 include/net/netns/xfrm.h         |    4 +
 include/net/xfrm.h               |    1 +
 net/core/flow.c                  |  342 ++++++++++++++++++--------------------
 net/ipv6/inet6_connection_sock.c |    6 +-
 net/xfrm/xfrm_policy.c           |  271 +++++++++++++++++++++---------
 6 files changed, 394 insertions(+), 269 deletions(-)

diff --git a/include/net/flow.h b/include/net/flow.h
index 809970b..814a9d2 100644
--- a/include/net/flow.h
+++ b/include/net/flow.h
@@ -8,6 +8,9 @@
 #define _NET_FLOW_H
 
 #include <linux/in6.h>
+#include <linux/notifier.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
 #include <asm/atomic.h>
 
 struct flowi {
@@ -86,13 +89,37 @@ struct flowi {
 
 struct net;
 struct sock;
-typedef int (*flow_resolve_t)(struct net *net, struct flowi *key, u16 family,
-			      u8 dir, void **objp, atomic_t **obj_refp);
 
-extern void *flow_cache_lookup(struct net *net, struct flowi *key, u16 family,
-			       u8 dir, flow_resolve_t resolver);
-extern void flow_cache_flush(void);
-extern atomic_t flow_cache_genid;
+struct flow_cache_percpu;
+struct flow_cache_entry;
+
+struct flow_cache {
+	u32				hash_shift;
+	u32				order;
+	struct flow_cache_percpu *	percpu;
+	struct notifier_block		hotcpu_notifier;
+	int				low_watermark;
+	int				high_watermark;
+	struct timer_list		rnd_timer;
+	struct kmem_cache *		flow_cachep;
+};
+
+struct flow_cache_entry {
+	struct flow_cache_entry	*next;
+	struct flowi		key;
+	u16			family;
+	u8			dir;
+};
+
+extern struct flow_cache_entry *flow_cache_lookup(
+	struct flow_cache *cache, struct flowi *key,
+	u16 family, u8 dir);
+extern void flow_cache_entry_put(struct flow_cache_entry *fce);
+
+void flow_cache_flush(struct flow_cache *fc,
+		      void (*flush)(struct flow_cache *fc, struct flow_cache_entry *fce));
+extern int flow_cache_init(struct flow_cache *cache, size_t entry_size);
+extern void flow_cache_fini(struct flow_cache *cache);
 
 static inline int flow_cache_uli_match(struct flowi *fl1, struct flowi *fl2)
 {
diff --git a/include/net/netns/xfrm.h b/include/net/netns/xfrm.h
index 74f119a..1b223c9 100644
--- a/include/net/netns/xfrm.h
+++ b/include/net/netns/xfrm.h
@@ -42,6 +42,10 @@ struct netns_xfrm {
 	struct xfrm_policy_hash	policy_bydst[XFRM_POLICY_MAX * 2];
 	unsigned int		policy_count[XFRM_POLICY_MAX * 2];
 	struct work_struct	policy_hash_work;
+	atomic_t		policy_genid;
+	struct hlist_head	policy_gc_list;
+	struct work_struct	policy_gc_work;
+	struct flow_cache	flow_cache;
 
 	struct dst_ops		xfrm4_dst_ops;
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index d74e080..f469b9b 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -488,6 +488,7 @@ struct xfrm_policy {
 	struct xfrm_lifetime_cfg lft;
 	struct xfrm_lifetime_cur curlft;
 	struct dst_entry       *bundles;
+	atomic_t		bundles_genid;
 	struct xfrm_policy_walk_entry walk;
 	u8			type;
 	u8			action;
diff --git a/net/core/flow.c b/net/core/flow.c
index 9601587..e3782c2 100644
--- a/net/core/flow.c
+++ b/net/core/flow.c
@@ -25,114 +25,85 @@
 #include <asm/atomic.h>
 #include <linux/security.h>
 
-struct flow_cache_entry {
-	struct flow_cache_entry	*next;
-	u16			family;
-	u8			dir;
-	u32			genid;
-	struct flowi		key;
-	void			*object;
-	atomic_t		*object_ref;
-};
-
-atomic_t flow_cache_genid = ATOMIC_INIT(0);
-
-static u32 flow_hash_shift;
-#define flow_hash_size	(1 << flow_hash_shift)
-static DEFINE_PER_CPU(struct flow_cache_entry **, flow_tables) = { NULL };
-
-#define flow_table(cpu) (per_cpu(flow_tables, cpu))
-
-static struct kmem_cache *flow_cachep __read_mostly;
 
-static int flow_lwm, flow_hwm;
-
-struct flow_percpu_info {
-	int hash_rnd_recalc;
-	u32 hash_rnd;
-	int count;
+struct flow_cache_percpu {
+	struct flow_cache_entry **	hash_table;
+	int				hash_count;
+	u32				hash_rnd;
+	int				hash_rnd_recalc;
+	struct tasklet_struct		flush_tasklet;
 };
-static DEFINE_PER_CPU(struct flow_percpu_info, flow_hash_info) = { 0 };
-
-#define flow_hash_rnd_recalc(cpu) \
-	(per_cpu(flow_hash_info, cpu).hash_rnd_recalc)
-#define flow_hash_rnd(cpu) \
-	(per_cpu(flow_hash_info, cpu).hash_rnd)
-#define flow_count(cpu) \
-	(per_cpu(flow_hash_info, cpu).count)
-
-static struct timer_list flow_hash_rnd_timer;
-
-#define FLOW_HASH_RND_PERIOD	(10 * 60 * HZ)
 
 struct flow_flush_info {
-	atomic_t cpuleft;
-	struct completion completion;
+	void (*flush)(struct flow_cache *fc, struct flow_cache_entry *fce);
+	struct flow_cache *		cache;
+	atomic_t			cpuleft;
+	struct completion		completion;
 };
-static DEFINE_PER_CPU(struct tasklet_struct, flow_flush_tasklets) = { NULL };
 
-#define flow_flush_tasklet(cpu) (&per_cpu(flow_flush_tasklets, cpu))
+#define flow_cache_hash_size(cache)	(1 << (cache)->hash_shift)
+#define FLOW_HASH_RND_PERIOD		(10 * 60 * HZ)
 
 static void flow_cache_new_hashrnd(unsigned long arg)
 {
+	struct flow_cache *fc = (struct flow_cache *) arg;
 	int i;
 
 	for_each_possible_cpu(i)
-		flow_hash_rnd_recalc(i) = 1;
+		per_cpu_ptr(fc->percpu, i)->hash_rnd_recalc = 1;
 
-	flow_hash_rnd_timer.expires = jiffies + FLOW_HASH_RND_PERIOD;
-	add_timer(&flow_hash_rnd_timer);
+	fc->rnd_timer.expires = jiffies + FLOW_HASH_RND_PERIOD;
+	add_timer(&fc->rnd_timer);
 }
 
-static void flow_entry_kill(int cpu, struct flow_cache_entry *fle)
-{
-	if (fle->object)
-		atomic_dec(fle->object_ref);
-	kmem_cache_free(flow_cachep, fle);
-	flow_count(cpu)--;
-}
-
-static void __flow_cache_shrink(int cpu, int shrink_to)
+static void __flow_cache_shrink(struct flow_cache *fc,
+				struct flow_cache_percpu *fcp,
+				int shrink_to)
 {
 	struct flow_cache_entry *fle, **flp;
 	int i;
 
-	for (i = 0; i < flow_hash_size; i++) {
+	for (i = 0; i < flow_cache_hash_size(fc); i++) {
 		int k = 0;
 
-		flp = &flow_table(cpu)[i];
+		flp = &fcp->hash_table[i];
 		while ((fle = *flp) != NULL && k < shrink_to) {
 			k++;
 			flp = &fle->next;
 		}
 		while ((fle = *flp) != NULL) {
 			*flp = fle->next;
-			flow_entry_kill(cpu, fle);
+
+			kmem_cache_free(fc->flow_cachep, fle);
+			fcp->hash_count--;
 		}
 	}
 }
 
-static void flow_cache_shrink(int cpu)
+static void flow_cache_shrink(struct flow_cache *fc,
+			      struct flow_cache_percpu *fcp)
 {
-	int shrink_to = flow_lwm / flow_hash_size;
+	int shrink_to = fc->low_watermark / flow_cache_hash_size(fc);
 
-	__flow_cache_shrink(cpu, shrink_to);
+	__flow_cache_shrink(fc, fcp, shrink_to);
 }
 
-static void flow_new_hash_rnd(int cpu)
+static void flow_new_hash_rnd(struct flow_cache *fc,
+			      struct flow_cache_percpu *fcp)
 {
-	get_random_bytes(&flow_hash_rnd(cpu), sizeof(u32));
-	flow_hash_rnd_recalc(cpu) = 0;
-
-	__flow_cache_shrink(cpu, 0);
+	get_random_bytes(&fcp->hash_rnd, sizeof(u32));
+	fcp->hash_rnd_recalc = 0;
+	__flow_cache_shrink(fc, fcp, 0);
 }
 
-static u32 flow_hash_code(struct flowi *key, int cpu)
+static u32 flow_hash_code(struct flow_cache *fc,
+			  struct flow_cache_percpu *fcp,
+			  struct flowi *key)
 {
 	u32 *k = (u32 *) key;
 
-	return (jhash2(k, (sizeof(*key) / sizeof(u32)), flow_hash_rnd(cpu)) &
-		(flow_hash_size - 1));
+	return (jhash2(k, (sizeof(*key) / sizeof(u32)), fcp->hash_rnd)
+		& (flow_cache_hash_size(fc) - 1));
 }
 
 #if (BITS_PER_LONG == 64)
@@ -165,128 +136,100 @@ static int flow_key_compare(struct flowi *key1, struct flowi *key2)
 	return 0;
 }
 
-void *flow_cache_lookup(struct net *net, struct flowi *key, u16 family, u8 dir,
-			flow_resolve_t resolver)
+struct flow_cache_entry *flow_cache_lookup(struct flow_cache *fc,
+					   struct flowi *key,
+					   u16 family, u8 dir)
 {
 	struct flow_cache_entry *fle, **head;
+	struct flow_cache_percpu *fcp;
 	unsigned int hash;
-	int cpu;
 
 	local_bh_disable();
-	cpu = smp_processor_id();
+	fcp = per_cpu_ptr(fc->percpu, smp_processor_id());
 
 	fle = NULL;
 	/* Packet really early in init?  Making flow_cache_init a
 	 * pre-smp initcall would solve this.  --RR */
-	if (!flow_table(cpu))
+	if (!fcp->hash_table)
 		goto nocache;
 
-	if (flow_hash_rnd_recalc(cpu))
-		flow_new_hash_rnd(cpu);
-	hash = flow_hash_code(key, cpu);
+	if (fcp->hash_rnd_recalc)
+		flow_new_hash_rnd(fc, fcp);
+
+	hash = flow_hash_code(fc, fcp, key);
 
-	head = &flow_table(cpu)[hash];
+	head = &fcp->hash_table[hash];
 	for (fle = *head; fle; fle = fle->next) {
 		if (fle->family == family &&
 		    fle->dir == dir &&
 		    flow_key_compare(key, &fle->key) == 0) {
-			if (fle->genid == atomic_read(&flow_cache_genid)) {
-				void *ret = fle->object;
-
-				if (ret)
-					atomic_inc(fle->object_ref);
-				local_bh_enable();
-
-				return ret;
-			}
-			break;
-		}
-	}
-
-	if (!fle) {
-		if (flow_count(cpu) > flow_hwm)
-			flow_cache_shrink(cpu);
-
-		fle = kmem_cache_alloc(flow_cachep, GFP_ATOMIC);
-		if (fle) {
-			fle->next = *head;
-			*head = fle;
-			fle->family = family;
-			fle->dir = dir;
-			memcpy(&fle->key, key, sizeof(*key));
-			fle->object = NULL;
-			flow_count(cpu)++;
+			return fle;
 		}
 	}
 
-nocache:
-	{
-		int err;
-		void *obj;
-		atomic_t *obj_ref;
-
-		err = resolver(net, key, family, dir, &obj, &obj_ref);
+	if (fcp->hash_count > fc->high_watermark)
+		flow_cache_shrink(fc, fcp);
 
-		if (fle && !err) {
-			fle->genid = atomic_read(&flow_cache_genid);
+	fle = kmem_cache_zalloc(fc->flow_cachep, GFP_ATOMIC);
+	if (!fle)
+		goto nocache;
 
-			if (fle->object)
-				atomic_dec(fle->object_ref);
+	fle->next = *head;
+	*head = fle;
+	fle->family = family;
+	fle->dir = dir;
+	memcpy(&fle->key, key, sizeof(*key));
+	fcp->hash_count++;
+	return fle;
 
-			fle->object = obj;
-			fle->object_ref = obj_ref;
-			if (obj)
-				atomic_inc(fle->object_ref);
-		}
-		local_bh_enable();
+nocache:
+	local_bh_enable();
+	return NULL;
+}
 
-		if (err)
-			obj = ERR_PTR(err);
-		return obj;
-	}
+void flow_cache_entry_put(struct flow_cache_entry *fce)
+{
+	local_bh_enable();
 }
 
 static void flow_cache_flush_tasklet(unsigned long data)
 {
-	struct flow_flush_info *info = (void *)data;
+	struct flow_flush_info *info = (void *) data;
+	struct flow_cache *fc = (void *) info->cache;
+	struct flow_cache_percpu *fcp;
 	int i;
-	int cpu;
 
-	cpu = smp_processor_id();
-	for (i = 0; i < flow_hash_size; i++) {
-		struct flow_cache_entry *fle;
+	if (info->flush == NULL)
+		goto done;
 
-		fle = flow_table(cpu)[i];
-		for (; fle; fle = fle->next) {
-			unsigned genid = atomic_read(&flow_cache_genid);
-
-			if (!fle->object || fle->genid == genid)
-				continue;
+	fcp = per_cpu_ptr(fc->percpu, smp_processor_id());
+	for (i = 0; i < flow_cache_hash_size(fc); i++) {
+		struct flow_cache_entry *fle;
 
-			fle->object = NULL;
-			atomic_dec(fle->object_ref);
-		}
+		fle = fcp->hash_table[i];
+		for (; fle; fle = fle->next)
+			info->flush(fc, fle);
 	}
 
+done:
 	if (atomic_dec_and_test(&info->cpuleft))
 		complete(&info->completion);
 }
 
-static void flow_cache_flush_per_cpu(void *) __attribute__((__unused__));
 static void flow_cache_flush_per_cpu(void *data)
 {
 	struct flow_flush_info *info = data;
-	int cpu;
 	struct tasklet_struct *tasklet;
+	int cpu;
 
 	cpu = smp_processor_id();
-
-	tasklet = flow_flush_tasklet(cpu);
-	tasklet->data = (unsigned long)info;
+	tasklet = &per_cpu_ptr(info->cache->percpu, cpu)->flush_tasklet;
+	tasklet->data = (unsigned long) data;
 	tasklet_schedule(tasklet);
 }
 
-void flow_cache_flush(void)
+void flow_cache_flush(struct flow_cache *fc,
+		      void (*flush)(struct flow_cache *fc, struct flow_cache_entry *fce))
 {
 	struct flow_flush_info info;
 	static DEFINE_MUTEX(flow_flush_sem);
@@ -294,6 +237,8 @@ void flow_cache_flush(void)
 	/* Don't want cpus going down or up during this. */
 	get_online_cpus();
 	mutex_lock(&flow_flush_sem);
+	info.cache = fc;
+	info.flush = flush;
 	atomic_set(&info.cpuleft, num_online_cpus());
 	init_completion(&info.completion);
 
@@ -307,62 +252,99 @@ void flow_cache_flush(void)
 	put_online_cpus();
 }
 
-static void __init flow_cache_cpu_prepare(int cpu)
+static void __init flow_cache_cpu_prepare(struct flow_cache *fc,
+					  struct flow_cache_percpu *fcp)
+{
+	fcp->hash_table = (struct flow_cache_entry **)
+		__get_free_pages(GFP_KERNEL|__GFP_ZERO, fc->order);
+	fcp->hash_rnd_recalc = 1;
+	fcp->hash_count = 0;
+
+	tasklet_init(&fcp->flush_tasklet, flow_cache_flush_tasklet, 0);
+}
+
+static int __cpuinit flow_cache_cpu(struct notifier_block *nfb,
+				    unsigned long action,
+				    void *hcpu)
+{
+	struct flow_cache *fc = container_of(nfb, struct flow_cache, hotcpu_notifier);
+	int cpu = (unsigned long) hcpu;
+	struct flow_cache_percpu *fcp = per_cpu_ptr(fc->percpu, cpu);
+
+	switch (action) {
+	case CPU_UP_PREPARE:
+	case CPU_UP_PREPARE_FROZEN:
+		flow_cache_cpu_prepare(fc, fcp);
+		if (!fcp->hash_table)
+			return NOTIFY_BAD;
+		break;
+	case CPU_UP_CANCELED:
+	case CPU_UP_CANCELED_FROZEN:
+	case CPU_DEAD:
+	case CPU_DEAD_FROZEN:
+		if (fcp->hash_table) {
+			__flow_cache_shrink(fc, fcp, 0);
+			free_pages((unsigned long) fcp->hash_table, fc->order);
+			fcp->hash_table = NULL;
+		}
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+int flow_cache_init(struct flow_cache *fc, size_t entry_size)
 {
-	struct tasklet_struct *tasklet;
 	unsigned long order;
+	int i, r;
+
+	BUG_ON(entry_size < sizeof(struct flow_cache_entry));
+	fc->flow_cachep = kmem_cache_create("flow_cache",
+					entry_size,
+					0, SLAB_PANIC,
+					NULL);
+	fc->hash_shift = 10;
+	fc->low_watermark = 2 * flow_cache_hash_size(fc);
+	fc->high_watermark = 4 * flow_cache_hash_size(fc);
+	fc->percpu = alloc_percpu(struct flow_cache_percpu);
 
 	for (order = 0;
 	     (PAGE_SIZE << order) <
-		     (sizeof(struct flow_cache_entry *)*flow_hash_size);
+		(sizeof(struct flow_cache_entry *) * flow_cache_hash_size(fc));
 	     order++)
 		/* NOTHING */;
+	fc->order = order;
 
-	flow_table(cpu) = (struct flow_cache_entry **)
-		__get_free_pages(GFP_KERNEL|__GFP_ZERO, order);
-	if (!flow_table(cpu))
-		panic("NET: failed to allocate flow cache order %lu\n", order);
+	setup_timer(&fc->rnd_timer, flow_cache_new_hashrnd, (unsigned long) fc);
+	fc->rnd_timer.expires = jiffies + FLOW_HASH_RND_PERIOD;
+	add_timer(&fc->rnd_timer);
 
-	flow_hash_rnd_recalc(cpu) = 1;
-	flow_count(cpu) = 0;
+	for_each_online_cpu(i) {
+		r = flow_cache_cpu(&fc->hotcpu_notifier,
+				   CPU_UP_PREPARE, (void*) i);
+		if (r != NOTIFY_OK)
+			panic("NET: failed to allocate flow cache order %lu\n", order);
+	}
 
-	tasklet = flow_flush_tasklet(cpu);
-	tasklet_init(tasklet, flow_cache_flush_tasklet, 0);
-}
+	fc->hotcpu_notifier = (struct notifier_block){
+		.notifier_call = flow_cache_cpu,
+	};
+	register_hotcpu_notifier(&fc->hotcpu_notifier);
 
-static int flow_cache_cpu(struct notifier_block *nfb,
-			  unsigned long action,
-			  void *hcpu)
-{
-	if (action == CPU_DEAD || action == CPU_DEAD_FROZEN)
-		__flow_cache_shrink((unsigned long)hcpu, 0);
-	return NOTIFY_OK;
+	return 0;
 }
 
-static int __init flow_cache_init(void)
+void flow_cache_fini(struct flow_cache *fc)
 {
 	int i;
 
-	flow_cachep = kmem_cache_create("flow_cache",
-					sizeof(struct flow_cache_entry),
-					0, SLAB_PANIC,
-					NULL);
-	flow_hash_shift = 10;
-	flow_lwm = 2 * flow_hash_size;
-	flow_hwm = 4 * flow_hash_size;
-
-	setup_timer(&flow_hash_rnd_timer, flow_cache_new_hashrnd, 0);
-	flow_hash_rnd_timer.expires = jiffies + FLOW_HASH_RND_PERIOD;
-	add_timer(&flow_hash_rnd_timer);
+	del_timer(&fc->rnd_timer);
+	unregister_hotcpu_notifier(&fc->hotcpu_notifier);
 
 	for_each_possible_cpu(i)
-		flow_cache_cpu_prepare(i);
+		flow_cache_cpu(&fc->hotcpu_notifier, CPU_DEAD, (void*) i);
 
-	hotcpu_notifier(flow_cache_cpu, 0);
-	return 0;
+	free_percpu(fc->percpu);
+	kmem_cache_destroy(fc->flow_cachep);
 }
 
-module_init(flow_cache_init);
-
-EXPORT_SYMBOL(flow_cache_genid);
 EXPORT_SYMBOL(flow_cache_lookup);
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c
index 3516e6f..588ba76 100644
--- a/net/ipv6/inet6_connection_sock.c
+++ b/net/ipv6/inet6_connection_sock.c
@@ -151,8 +151,9 @@ void __inet6_csk_dst_store(struct sock *sk, struct dst_entry *dst,
 
 #ifdef CONFIG_XFRM
 	{
+		struct net *net = sock_net(sk);
 		struct rt6_info *rt = (struct rt6_info  *)dst;
-		rt->rt6i_flow_cache_genid = atomic_read(&flow_cache_genid);
+		rt->rt6i_flow_cache_genid = atomic_read(&net->xfrm.policy_genid);
 	}
 #endif
 }
@@ -166,8 +167,9 @@ struct dst_entry *__inet6_csk_dst_check(struct sock *sk, u32 cookie)
 
 #ifdef CONFIG_XFRM
 	if (dst) {
+		struct net *net = sock_net(sk);
 		struct rt6_info *rt = (struct rt6_info *)dst;
-		if (rt->rt6i_flow_cache_genid != atomic_read(&flow_cache_genid)) {
+		if (rt->rt6i_flow_cache_genid != atomic_read(&net->xfrm.policy_genid)) {
 			__sk_dst_reset(sk);
 			dst = NULL;
 		}
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 843e066..228b813 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -44,7 +44,6 @@ static struct xfrm_policy_afinfo *xfrm_policy_afinfo[NPROTO];
 
 static struct kmem_cache *xfrm_dst_cache __read_mostly;
 
-static HLIST_HEAD(xfrm_policy_gc_list);
 static DEFINE_SPINLOCK(xfrm_policy_gc_lock);
 
 static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family);
@@ -53,6 +52,7 @@ static void xfrm_init_pmtu(struct dst_entry *dst);
 
 static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol,
 						int dir);
+static int stale_bundle(struct dst_entry *dst);
 
 static inline int
 __xfrm4_selector_match(struct xfrm_selector *sel, struct flowi *fl)
@@ -216,6 +216,35 @@ expired:
 	xfrm_pol_put(xp);
 }
 
+struct xfrm_flow_cache_entry {
+	struct flow_cache_entry fce;
+	struct xfrm_policy *policy;
+	struct xfrm_dst *dst;
+	u32 policy_genid, bundles_genid;
+};
+#define XFRM_CACHE_NO_POLICY ((struct xfrm_policy *) -1)
+
+void xfrm_flow_cache_entry_validate(struct flow_cache *fc,
+				    struct flow_cache_entry *fce)
+{
+	struct net *net = container_of(fc, struct net, xfrm.flow_cache);
+	struct xfrm_flow_cache_entry *xfc =
+		container_of(fce, struct xfrm_flow_cache_entry, fce);
+
+	if (xfc->policy_genid != atomic_read(&net->xfrm.policy_genid))
+		goto invalid;
+	if (xfc->policy == NULL || xfc->policy == XFRM_CACHE_NO_POLICY)
+		return;
+	if (xfc->policy->walk.dead)
+		goto invalid;
+	if (xfc->bundles_genid != atomic_read(&xfc->policy->bundles_genid))
+		goto invalid_dst;
+	return;
+invalid:
+	xfc->policy = NULL;
+invalid_dst:
+	xfc->dst = NULL;
+}
 
 /* Allocate xfrm_policy. Not used here, it is supposed to be used by pfkeyv2
  * SPD calls.
@@ -269,27 +298,26 @@ static void xfrm_policy_gc_kill(struct xfrm_policy *policy)
 	if (del_timer(&policy->timer))
 		atomic_dec(&policy->refcnt);
 
-	if (atomic_read(&policy->refcnt) > 1)
-		flow_cache_flush();
-
 	xfrm_pol_put(policy);
 }
 
 static void xfrm_policy_gc_task(struct work_struct *work)
 {
+	struct net *net = container_of(work, struct net, xfrm.policy_gc_work);
 	struct xfrm_policy *policy;
 	struct hlist_node *entry, *tmp;
 	struct hlist_head gc_list;
 
 	spin_lock_bh(&xfrm_policy_gc_lock);
-	gc_list.first = xfrm_policy_gc_list.first;
-	INIT_HLIST_HEAD(&xfrm_policy_gc_list);
+	gc_list.first = net->xfrm.policy_gc_list.first;
+	INIT_HLIST_HEAD(&net->xfrm.policy_gc_list);
 	spin_unlock_bh(&xfrm_policy_gc_lock);
 
+	flow_cache_flush(&net->xfrm.flow_cache, xfrm_flow_cache_entry_validate);
+
 	hlist_for_each_entry_safe(policy, entry, tmp, &gc_list, bydst)
 		xfrm_policy_gc_kill(policy);
 }
-static DECLARE_WORK(xfrm_policy_gc_work, xfrm_policy_gc_task);
 
 /* Rule must be locked. Release descentant resources, announce
  * entry dead. The rule must be unlinked from lists to the moment.
@@ -297,6 +325,7 @@ static DECLARE_WORK(xfrm_policy_gc_work, xfrm_policy_gc_task);
 
 static void xfrm_policy_kill(struct xfrm_policy *policy)
 {
+	struct net *net = xp_net(policy);
 	int dead;
 
 	write_lock_bh(&policy->lock);
@@ -310,10 +339,10 @@ static void xfrm_policy_kill(struct xfrm_policy *policy)
 	}
 
 	spin_lock_bh(&xfrm_policy_gc_lock);
-	hlist_add_head(&policy->bydst, &xfrm_policy_gc_list);
+	hlist_add_head(&policy->bydst, &net->xfrm.policy_gc_list);
 	spin_unlock_bh(&xfrm_policy_gc_lock);
 
-	schedule_work(&xfrm_policy_gc_work);
+	schedule_work(&net->xfrm.policy_gc_work);
 }
 
 static unsigned int xfrm_policy_hashmax __read_mostly = 1 * 1024 * 1024;
@@ -588,7 +617,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
 		hlist_add_head(&policy->bydst, chain);
 	xfrm_pol_hold(policy);
 	net->xfrm.policy_count[dir]++;
-	atomic_inc(&flow_cache_genid);
+	atomic_inc(&net->xfrm.policy_genid);
 	if (delpol)
 		__xfrm_policy_unlink(delpol, dir);
 	policy->index = delpol ? delpol->index : xfrm_gen_index(net, dir);
@@ -621,11 +650,13 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
 			gc_list = dst;
 
 			policy->bundles = NULL;
+			atomic_inc(&policy->bundles_genid);
 		}
 		write_unlock(&policy->lock);
 	}
 	read_unlock_bh(&xfrm_policy_lock);
 
+	flow_cache_flush(&net->xfrm.flow_cache, NULL);
 	while (gc_list) {
 		struct dst_entry *dst = gc_list;
 
@@ -672,7 +703,7 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type,
 	write_unlock_bh(&xfrm_policy_lock);
 
 	if (ret && delete) {
-		atomic_inc(&flow_cache_genid);
+		atomic_inc(&net->xfrm.policy_genid);
 		xfrm_policy_kill(ret);
 	}
 	return ret;
@@ -714,7 +745,7 @@ struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8 type,
 	write_unlock_bh(&xfrm_policy_lock);
 
 	if (ret && delete) {
-		atomic_inc(&flow_cache_genid);
+		atomic_inc(&net->xfrm.policy_genid);
 		xfrm_policy_kill(ret);
 	}
 	return ret;
@@ -835,7 +866,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info)
 	}
 	if (!cnt)
 		err = -ESRCH;
-	atomic_inc(&flow_cache_genid);
+	atomic_inc(&net->xfrm.policy_genid);
 out:
 	write_unlock_bh(&xfrm_policy_lock);
 	return err;
@@ -989,32 +1020,18 @@ fail:
 	return ret;
 }
 
-static int xfrm_policy_lookup(struct net *net, struct flowi *fl, u16 family,
-			      u8 dir, void **objp, atomic_t **obj_refp)
+static struct xfrm_policy *xfrm_policy_lookup(
+		struct net *net, struct flowi *fl,
+		u16 family, u8 dir)
 {
+#ifdef CONFIG_XFRM_SUB_POLICY
 	struct xfrm_policy *pol;
-	int err = 0;
 
-#ifdef CONFIG_XFRM_SUB_POLICY
 	pol = xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_SUB, fl, family, dir);
-	if (IS_ERR(pol)) {
-		err = PTR_ERR(pol);
-		pol = NULL;
-	}
-	if (pol || err)
-		goto end;
+	if (pol != NULL)
+		return pol;
 #endif
-	pol = xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_MAIN, fl, family, dir);
-	if (IS_ERR(pol)) {
-		err = PTR_ERR(pol);
-		pol = NULL;
-	}
-#ifdef CONFIG_XFRM_SUB_POLICY
-end:
-#endif
-	if ((*objp = (void *) pol) != NULL)
-		*obj_refp = &pol->refcnt;
-	return err;
+	return xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_MAIN, fl, family, dir);
 }
 
 static inline int policy_to_flow_dir(int dir)
@@ -1100,12 +1117,14 @@ static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol,
 
 int xfrm_policy_delete(struct xfrm_policy *pol, int dir)
 {
+	struct net *net = xp_net(pol);
+
 	write_lock_bh(&xfrm_policy_lock);
 	pol = __xfrm_policy_unlink(pol, dir);
 	write_unlock_bh(&xfrm_policy_lock);
 	if (pol) {
 		if (dir < XFRM_POLICY_MAX)
-			atomic_inc(&flow_cache_genid);
+			atomic_inc(&net->xfrm.policy_genid);
 		xfrm_policy_kill(pol);
 		return 0;
 	}
@@ -1545,13 +1564,34 @@ xfrm_dst_update_origin(struct dst_entry *dst, struct flowi *fl)
 #endif
 }
 
-static int stale_bundle(struct dst_entry *dst);
-
 /* Main function: finds/creates a bundle for given flow.
  *
  * At the moment we eat a raw IP route. Mostly to speed up lookups
  * on interfaces with disabled IPsec.
  */
+
+static void xfrm_flow_cache_update(struct net *net, struct flowi *key,
+				   u16 family, u8 dir,
+				   struct xfrm_policy *pol,
+				   struct xfrm_dst *dst)
+{
+	struct flow_cache_entry *fce;
+	struct xfrm_flow_cache_entry *xf;
+
+	fce = flow_cache_lookup(&net->xfrm.flow_cache,
+				key, family, dir);
+	if (fce == NULL)
+		return;
+
+	xf = container_of(fce, struct xfrm_flow_cache_entry, fce);
+	xf->policy_genid = atomic_read(&net->xfrm.policy_genid);
+	xf->policy = pol;
+	if (dst != NULL)
+		xf->bundles_genid = atomic_read(&pol->bundles_genid);
+	xf->dst = dst;
+	flow_cache_entry_put(fce);
+}
+
 int __xfrm_lookup(struct net *net, struct dst_entry **dst_p, struct flowi *fl,
 		  struct sock *sk, int flags)
 {
@@ -1570,8 +1610,10 @@ int __xfrm_lookup(struct net *net, struct dst_entry **dst_p, struct flowi *fl,
 	u8 dir = policy_to_flow_dir(XFRM_POLICY_OUT);
 
 restart:
-	genid = atomic_read(&flow_cache_genid);
+	family = dst_orig->ops->family;
+	genid = atomic_read(&net->xfrm.policy_genid);
 	policy = NULL;
+	dst = NULL;
 	for (pi = 0; pi < ARRAY_SIZE(pols); pi++)
 		pols[pi] = NULL;
 	npols = 0;
@@ -1588,24 +1630,51 @@ restart:
 	}
 
 	if (!policy) {
+		struct flow_cache_entry *fce;
+		struct xfrm_flow_cache_entry *xf;
+
 		/* To accelerate a bit...  */
 		if ((dst_orig->flags & DST_NOXFRM) ||
 		    !net->xfrm.policy_count[XFRM_POLICY_OUT])
 			goto nopol;
 
-		policy = flow_cache_lookup(net, fl, dst_orig->ops->family,
-					   dir, xfrm_policy_lookup);
-		err = PTR_ERR(policy);
-		if (IS_ERR(policy)) {
-			XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR);
-			goto dropdst;
+		fce = flow_cache_lookup(&net->xfrm.flow_cache,
+					fl, family, dir);
+		if (fce == NULL)
+			goto no_cache;
+
+		xf = container_of(fce, struct xfrm_flow_cache_entry, fce);
+		xfrm_flow_cache_entry_validate(&net->xfrm.flow_cache, fce);
+		if (xf->policy != NULL) {
+			policy = xf->policy;
+			if (policy != XFRM_CACHE_NO_POLICY)
+				xfrm_pol_hold(policy);
+			if (xf->dst != NULL)
+				dst = dst_clone((struct dst_entry *) xf->dst);
+		}
+		flow_cache_entry_put(fce);
+		if (policy == XFRM_CACHE_NO_POLICY)
+			goto nopol;
+		if (dst && !xfrm_bundle_ok(policy, (struct xfrm_dst *) dst, fl, family, 0)) {
+			dst_release(dst);
+			dst = NULL;
 		}
 	}
+no_cache:
+	if (!policy) {
+		policy = xfrm_policy_lookup(net, fl, family, dir);
+		if (!policy) {
+			xfrm_flow_cache_update(
+				net, fl, family, dir,
+				XFRM_CACHE_NO_POLICY, NULL);
+			goto nopol;
+		}
+	}
+	if (IS_ERR(policy)) {
+		XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR);
+		goto dropdst;
+	}
 
-	if (!policy)
-		goto nopol;
-
-	family = dst_orig->ops->family;
 	pols[0] = policy;
 	npols ++;
 	xfrm_nr += pols[0]->xfrm_nr;
@@ -1616,6 +1685,9 @@ restart:
 
 	policy->curlft.use_time = get_seconds();
 
+	if (dst)
+		goto dst_found;
+
 	switch (policy->action) {
 	default:
 	case XFRM_POLICY_BLOCK:
@@ -1626,18 +1698,11 @@ restart:
 
 	case XFRM_POLICY_ALLOW:
 #ifndef CONFIG_XFRM_SUB_POLICY
-		if (policy->xfrm_nr == 0) {
-			/* Flow passes not transformed. */
-			xfrm_pol_put(policy);
-			return 0;
-		}
+		if (policy->xfrm_nr == 0)
+			goto no_transform;
 #endif
 
-		/* Try to find matching bundle.
-		 *
-		 * LATER: help from flow cache. It is optional, this
-		 * is required only for output policy.
-		 */
+		/* Try to find matching bundle the hard way. */
 		dst = xfrm_find_bundle(fl, policy, family);
 		if (IS_ERR(dst)) {
 			XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTBUNDLECHECKERROR);
@@ -1677,12 +1742,8 @@ restart:
 		 * they are searched. See above not-transformed bypass
 		 * is surrounded by non-sub policy configuration, too.
 		 */
-		if (xfrm_nr == 0) {
-			/* Flow passes not transformed. */
-			xfrm_pols_put(pols, npols);
-			return 0;
-		}
-
+		if (xfrm_nr == 0)
+			goto no_transform;
 #endif
 		nx = xfrm_tmpl_resolve(pols, npols, fl, xfrm, family);
 
@@ -1713,7 +1774,7 @@ restart:
 					goto error;
 				}
 				if (nx == -EAGAIN ||
-				    genid != atomic_read(&flow_cache_genid)) {
+				    genid != atomic_read(&net->xfrm.policy_genid)) {
 					xfrm_pols_put(pols, npols);
 					goto restart;
 				}
@@ -1724,11 +1785,8 @@ restart:
 				goto error;
 			}
 		}
-		if (nx == 0) {
-			/* Flow passes not transformed. */
-			xfrm_pols_put(pols, npols);
-			return 0;
-		}
+		if (nx == 0)
+			goto no_transform;
 
 		dst = xfrm_bundle_create(policy, xfrm, nx, fl, dst_orig);
 		err = PTR_ERR(dst);
@@ -1777,6 +1835,9 @@ restart:
 		dst_hold(dst);
 		write_unlock_bh(&policy->lock);
 	}
+	xfrm_flow_cache_update(net, fl, family, dir,
+			       policy, (struct xfrm_dst *) dst);
+dst_found:
 	*dst_p = dst;
 	dst_release(dst_orig);
 	xfrm_pols_put(pols, npols);
@@ -1794,7 +1855,12 @@ nopol:
 	if (flags & XFRM_LOOKUP_ICMP)
 		goto dropdst;
 	return 0;
+no_transform:
+	/* Flow passes not transformed. */
+	xfrm_pols_put(pols, npols);
+	return 0;
 }
+
 EXPORT_SYMBOL(__xfrm_lookup);
 
 int xfrm_lookup(struct net *net, struct dst_entry **dst_p, struct flowi *fl,
@@ -1952,10 +2018,35 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
 		}
 	}
 
-	if (!pol)
-		pol = flow_cache_lookup(net, &fl, family, fl_dir,
-					xfrm_policy_lookup);
-
+	if (!pol) {
+		struct flow_cache_entry *fce;
+		struct xfrm_flow_cache_entry *xf;
+
+		fce = flow_cache_lookup(&net->xfrm.flow_cache,
+					&fl, family, dir);
+		if (fce != NULL) {
+			xf = container_of(fce, struct xfrm_flow_cache_entry, fce);
+			xfrm_flow_cache_entry_validate(&net->xfrm.flow_cache, fce);
+			if (xf->policy != NULL) {
+				pol = xf->policy;
+				if (pol != XFRM_CACHE_NO_POLICY)
+					xfrm_pol_hold(pol);
+				else
+					pol = NULL;
+			} else {
+				pol = xfrm_policy_lookup(net, &fl, family, dir);
+				if (!IS_ERR(pol)) {
+					if (pol)
+						xf->policy = pol;
+					else
+						xf->policy = XFRM_CACHE_NO_POLICY;
+				}
+				xf->dst = NULL;
+				xf->policy_genid = atomic_read(&net->xfrm.policy_genid);
+			}
+			flow_cache_entry_put(fce);
+		}
+	}
 	if (IS_ERR(pol)) {
 		XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLERROR);
 		return 0;
@@ -2153,6 +2244,7 @@ static void prune_one_bundle(struct xfrm_policy *pol, int (*func)(struct dst_ent
 			dstp = &dst->next;
 		}
 	}
+	atomic_inc(&pol->bundles_genid);
 	write_unlock(&pol->lock);
 }
 
@@ -2180,6 +2272,7 @@ static void xfrm_prune_bundles(struct net *net, int (*func)(struct dst_entry *))
 	}
 	read_unlock_bh(&xfrm_policy_lock);
 
+	flow_cache_flush(&net->xfrm.flow_cache, NULL);
 	while (gc_list) {
 		struct dst_entry *dst = gc_list;
 		gc_list = dst->next;
@@ -2498,6 +2591,9 @@ static int __net_init xfrm_policy_init(struct net *net)
 
 	INIT_LIST_HEAD(&net->xfrm.policy_all);
 	INIT_WORK(&net->xfrm.policy_hash_work, xfrm_hash_resize);
+	INIT_HLIST_HEAD(&net->xfrm.policy_gc_list);
+	INIT_WORK(&net->xfrm.policy_gc_work, xfrm_policy_gc_task);
+	flow_cache_init(&net->xfrm.flow_cache, sizeof(struct xfrm_flow_cache_entry));
 	if (net_eq(net, &init_net))
 		register_netdevice_notifier(&xfrm_dev_notifier);
 	return 0;
@@ -2531,7 +2627,7 @@ static void xfrm_policy_fini(struct net *net)
 	audit_info.sessionid = -1;
 	audit_info.secid = 0;
 	xfrm_policy_flush(net, XFRM_POLICY_TYPE_MAIN, &audit_info);
-	flush_work(&xfrm_policy_gc_work);
+	flush_work(&net->xfrm.policy_gc_work);
 
 	WARN_ON(!list_empty(&net->xfrm.policy_all));
 
@@ -2549,6 +2645,8 @@ static void xfrm_policy_fini(struct net *net)
 	sz = (net->xfrm.policy_idx_hmask + 1) * sizeof(struct hlist_head);
 	WARN_ON(!hlist_empty(net->xfrm.policy_byidx));
 	xfrm_hash_free(net->xfrm.policy_byidx, sz);
+
+	flow_cache_fini(&net->xfrm.flow_cache);
 }
 
 static int __net_init xfrm_net_init(struct net *net)
@@ -2756,8 +2854,9 @@ static int migrate_tmpl_match(struct xfrm_migrate *m, struct xfrm_tmpl *t)
 static int xfrm_policy_migrate(struct xfrm_policy *pol,
 			       struct xfrm_migrate *m, int num_migrate)
 {
+	struct net *net = xp_net(pol);
 	struct xfrm_migrate *mp;
-	struct dst_entry *dst;
+	struct dst_entry *gc_list = NULL, *tail;
 	int i, j, n = 0;
 
 	write_lock_bh(&pol->lock);
@@ -2782,15 +2881,25 @@ static int xfrm_policy_migrate(struct xfrm_policy *pol,
 			       sizeof(pol->xfrm_vec[i].saddr));
 			pol->xfrm_vec[i].encap_family = mp->new_family;
 			/* flush bundles */
-			while ((dst = pol->bundles) != NULL) {
-				pol->bundles = dst->next;
-				dst_free(dst);
-			}
+			tail = pol->bundles;
+			while (tail->next)
+				tail = tail->next;
+			tail->next = gc_list;
+			gc_list = pol->bundles;
+			pol->bundles = NULL;
+			atomic_inc(&pol->bundles_genid);
 		}
 	}
-
 	write_unlock_bh(&pol->lock);
 
+	flow_cache_flush(&net->xfrm.flow_cache, NULL);
+	while (gc_list) {
+		struct dst_entry *dst = gc_list;
+
+		gc_list = dst->next;
+		dst_free(dst);
+	}
+
 	if (!n)
 		return -ENODATA;
 
-- 
1.6.3.3


^ permalink raw reply related

* [PATCH] ISDN: Add PCI ID for HFC-2S/4S Beronet Card PCIe
From: Karsten Keil @ 2010-03-15 13:18 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Lars Ellenberg, netdev, Andreas Eversberg, Andrew Morton,
	linux-kernel

A few subdevice IDs seem to have been dropped when hfc_multi was
included upstream, just compare the list at
http://www.openvox.cn/viewvc/misdn/trunk/hfc_multi.c?revision=75&view=annotate#l175
with the IDs in drivers/isdn/hardware/mISDN/hfcmulti.c

Added PCIe 2 Port card and LED settings (same as PCI) /KKe

Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
Signed-off-by: Karsten Keil <keil@b1-systems.de>
---
 drivers/isdn/hardware/mISDN/hfcmulti.c |    6 ++++++
 include/linux/pci_ids.h                |    2 ++
 2 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c
index ad36df9..751b34c 100644
--- a/drivers/isdn/hardware/mISDN/hfcmulti.c
+++ b/drivers/isdn/hardware/mISDN/hfcmulti.c
@@ -5265,6 +5265,8 @@ static const struct hm_map hfcm_map[] = {
 /*31*/	{VENDOR_CCD, "XHFC-4S Speech Design", 5, 4, 0, 0, 0, 0,
 		HFC_IO_MODE_EMBSD, XHFC_IRQ},
 /*32*/	{VENDOR_JH, "HFC-8S (junghanns)", 8, 8, 1, 0, 0, 0, 0, 0},
+/*33*/	{VENDOR_BN, "HFC-2S Beronet Card PCIe", 4, 2, 1, 3, 0, DIP_4S, 0, 0},
+/*34*/	{VENDOR_BN, "HFC-4S Beronet Card PCIe", 4, 4, 1, 2, 0, DIP_4S, 0, 0},
 };
 
 #undef H
@@ -5300,6 +5302,10 @@ static struct pci_device_id hfmultipci_ids[] __devinitdata = {
 		PCI_SUBDEVICE_ID_CCD_OV4S, 0, 0, H(28)}, /* OpenVox 4 */
 	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD,
 		PCI_SUBDEVICE_ID_CCD_OV2S, 0, 0, H(29)}, /* OpenVox 2 */
+	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD,
+		PCI_SUBDEVICE_ID_CCD_BN2SE, 0, 0, H(33)}, /* BN2S PCIe */
+	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD,
+		PCI_SUBDEVICE_ID_CCD_BN4SE, 0, 0, H(34)}, /* BN4S PCIe */
 
 	/* Cards with HFC-8S Chip */
 	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD,
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 9f688d2..a5cc675 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -1923,6 +1923,8 @@
 #define PCI_SUBDEVICE_ID_CCD_HFC8S	0xB622
 #define PCI_DEVICE_ID_CCD_B700		0xb700
 #define PCI_DEVICE_ID_CCD_B701		0xb701
+#define PCI_SUBDEVICE_ID_CCD_BN2SE	0xb761
+#define PCI_SUBDEVICE_ID_CCD_BN4SE	0xb762
 #define PCI_SUBDEVICE_ID_CCD_HFCE1	0xC523
 #define PCI_SUBDEVICE_ID_CCD_OV2S	0xE884
 #define PCI_SUBDEVICE_ID_CCD_OV4S	0xE888
-- 
1.6.0.2

^ permalink raw reply related

* [PATCH V2] ISDN: Add PCI ID for HFC-2S/4S Beronet Card PCIe
From: Karsten Keil @ 2010-03-15 13:18 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Lars Ellenberg, netdev, Andreas Eversberg, Andrew Morton,
	linux-kernel
In-Reply-To: <1268668176.12629@pingi>

From: Lars Ellenberg <lars.ellenberg@linbit.com>

A few subdevice IDs seem to have been dropped when hfc_multi was
included upstream, just compare the list at
http://www.openvox.cn/viewvc/misdn/trunk/hfc_multi.c?revision=75&view=annotate#l175
with the IDs in drivers/isdn/hardware/mISDN/hfcmulti.c

Added PCIe 2 Port card and LED settings (same as PCI)
Do not use <linux/pci_ids.h> /KKe

Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
Signed-off-by: Karsten Keil <keil@b1-systems.de>
---
 drivers/isdn/hardware/mISDN/hfcmulti.c |    6 ++++++
 include/linux/pci_ids.h                |    2 ++
 2 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c
index ad36df9..751b34c 100644
--- a/drivers/isdn/hardware/mISDN/hfcmulti.c
+++ b/drivers/isdn/hardware/mISDN/hfcmulti.c
@@ -5265,6 +5265,8 @@ static const struct hm_map hfcm_map[] = {
 /*31*/	{VENDOR_CCD, "XHFC-4S Speech Design", 5, 4, 0, 0, 0, 0,
 		HFC_IO_MODE_EMBSD, XHFC_IRQ},
 /*32*/	{VENDOR_JH, "HFC-8S (junghanns)", 8, 8, 1, 0, 0, 0, 0, 0},
+/*33*/	{VENDOR_BN, "HFC-2S Beronet Card PCIe", 4, 2, 1, 3, 0, DIP_4S, 0, 0},
+/*34*/	{VENDOR_BN, "HFC-4S Beronet Card PCIe", 4, 4, 1, 2, 0, DIP_4S, 0, 0},
 };
 
 #undef H
@@ -5300,6 +5302,10 @@ static struct pci_device_id hfmultipci_ids[] __devinitdata = {
 		PCI_SUBDEVICE_ID_CCD_OV4S, 0, 0, H(28)}, /* OpenVox 4 */
 	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD,
 		PCI_SUBDEVICE_ID_CCD_OV2S, 0, 0, H(29)}, /* OpenVox 2 */
+	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD,
+		0xb761, 0, 0, H(33)}, /* BN2S PCIe */
+	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD,
+		0xb762, 0, 0, H(34)}, /* BN4S PCIe */
 
 	/* Cards with HFC-8S Chip */
 	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD,

-- 
1.6.0.2

^ permalink raw reply related

* RE: [PATCH] [V2] Add non-Virtex5 support for LL TEMAC driver
From: John Linn @ 2010-03-15 13:40 UTC (permalink / raw)
  To: michal.simek
  Cc: netdev, linuxppc-dev, grant.likely, jwboyer, john.williams,
	John Tyner
In-Reply-To: <4B9DF254.2030402@petalogix.com>

> -----Original Message-----
> From: Michal Simek [mailto:michal.simek@petalogix.com]
> Sent: Monday, March 15, 2010 2:40 AM
> To: John Linn
> Cc: netdev@vger.kernel.org; linuxppc-dev@ozlabs.org;
grant.likely@secretlab.ca;
> jwboyer@linux.vnet.ibm.com; john.williams@petalogix.com; John Tyner
> Subject: Re: [PATCH] [V2] Add non-Virtex5 support for LL TEMAC driver
> 
> John Linn wrote:
> > This patch adds support for using the LL TEMAC Ethernet driver on
> > non-Virtex 5 platforms by adding support for accessing the Soft DMA
> > registers as if they were memory mapped instead of solely through
the
> > DCR's (available on the Virtex 5).
> >
> > The patch also updates the driver so that it runs on the MicroBlaze.
> > The changes were tested on the PowerPC 440, PowerPC 405, and the
> > MicroBlaze platforms.
> 
> Which git-tree have you tested on? (Of course microblaze)

It was tested on the Xilinx tree for MicroBlaze which is based on the
mainline and the Petalogix tree as DMA was needed. I tried to build
against the mainline head but got errors with the DMA routines. I guess
it's possible that it was a configuration issue there as I didn't dig
real deep.

I tested the PowerPC against the head of mainline.

Thanks,
John

> 
> Michal
> 
> >
> > Signed-off-by: John Tyner <jtyner@cs.ucr.edu>
> > Signed-off-by: John Linn <john.linn@xilinx.com>
> > ---
> >
> > V2 - Incorporated comments from Grant and added more logic to allow
the driver
> > to work on MicroBlaze.
> >
> >  drivers/net/Kconfig         |    1 -
> >  drivers/net/ll_temac.h      |   17 +++++-
> >  drivers/net/ll_temac_main.c |  124
++++++++++++++++++++++++++++++++++---------
> >  3 files changed, 113 insertions(+), 29 deletions(-)
> >
> > diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
> > index 9b6efe1..5402105 100644
> > --- a/drivers/net/Kconfig
> > +++ b/drivers/net/Kconfig
> > @@ -2443,7 +2443,6 @@ config MV643XX_ETH
> >  config XILINX_LL_TEMAC
> >  	tristate "Xilinx LL TEMAC (LocalLink Tri-mode Ethernet MAC)
driver"
> >  	select PHYLIB
> > -	depends on PPC_DCR_NATIVE
> >  	help
> >  	  This driver supports the Xilinx 10/100/1000 LocalLink TEMAC
> >  	  core used in Xilinx Spartan and Virtex FPGAs
> > diff --git a/drivers/net/ll_temac.h b/drivers/net/ll_temac.h
> > index 1af66a1..915aa34 100644
> > --- a/drivers/net/ll_temac.h
> > +++ b/drivers/net/ll_temac.h
> > @@ -5,8 +5,11 @@
> >  #include <linux/netdevice.h>
> >  #include <linux/of.h>
> >  #include <linux/spinlock.h>
> > +
> > +#ifdef CONFIG_PPC_DCR
> >  #include <asm/dcr.h>
> >  #include <asm/dcr-regs.h>
> > +#endif
> >
> >  /* packet size info */
> >  #define XTE_HDR_SIZE			14      /* size of
Ethernet header */
> > @@ -290,8 +293,12 @@ This option defaults to enabled (set) */
> >
> >  #define TX_CONTROL_CALC_CSUM_MASK   1
> >
> > +/* Align the IP data in the packet on word boundaries as MicroBlaze
> > + * needs it.
> > + */
> > +
> >  #define XTE_ALIGN       32
> > -#define BUFFER_ALIGN(adr) ((XTE_ALIGN - ((u32) adr)) % XTE_ALIGN)
> > +#define BUFFER_ALIGN(adr) ((34 - ((u32) adr)) % XTE_ALIGN)
> >
> >  #define MULTICAST_CAM_TABLE_NUM 4
> >
> > @@ -335,9 +342,15 @@ struct temac_local {
> >  	struct mii_bus *mii_bus;	/* MII bus reference */
> >  	int mdio_irqs[PHY_MAX_ADDR];	/* IRQs table for MDIO bus */
> >
> > -	/* IO registers and IRQs */
> > +	/* IO registers, dma functions and IRQs */
> >  	void __iomem *regs;
> > +	void __iomem *sdma_regs;
> > +#ifdef CONFIG_PPC_DCR
> >  	dcr_host_t sdma_dcrs;
> > +#endif
> > +	u32 (*dma_in)(struct temac_local *, int);
> > +	void (*dma_out)(struct temac_local *, int, u32);
> > +
> >  	int tx_irq;
> >  	int rx_irq;
> >  	int emac_num;
> > diff --git a/drivers/net/ll_temac_main.c
b/drivers/net/ll_temac_main.c
> > index a18e348..9aedf9b 100644
> > --- a/drivers/net/ll_temac_main.c
> > +++ b/drivers/net/ll_temac_main.c
> > @@ -20,9 +20,6 @@
> >   *   or rx, so this should be okay.
> >   *
> >   * TODO:
> > - * - Fix driver to work on more than just Virtex5.  Right now the
driver
> > - *   assumes that the locallink DMA registers are accessed via DCR
> > - *   instructions.
> >   * - Factor out locallink DMA code into separate driver
> >   * - Fix multicast assignment.
> >   * - Fix support for hardware checksumming.
> > @@ -115,17 +112,86 @@ void temac_indirect_out32(struct temac_local
*lp, int reg, u32 value)
> >  	temac_iow(lp, XTE_CTL0_OFFSET, CNTLREG_WRITE_ENABLE_MASK | reg);
> >  }
> >
> > +/**
> > + * temac_dma_in32 - Memory mapped DMA read, this function expects a
> > + * register input that is based on DCR word addresses which
> > + * are then converted to memory mapped byte addresses
> > + */
> >  static u32 temac_dma_in32(struct temac_local *lp, int reg)
> >  {
> > -	return dcr_read(lp->sdma_dcrs, reg);
> > +	return in_be32((u32 *)(lp->sdma_regs + (reg << 2)));
> >  }
> >
> > +/**
> > + * temac_dma_out32 - Memory mapped DMA read, this function expects
a
> > + * register input that is based on DCR word addresses which
> > + * are then converted to memory mapped byte addresses
> > + */
> >  static void temac_dma_out32(struct temac_local *lp, int reg, u32
value)
> >  {
> > +	out_be32((u32 *)(lp->sdma_regs + (reg << 2)), value);
> > +}
> > +
> > +/* DMA register access functions can be DCR based or memory mapped.
> > + * The PowerPC 440 is DCR based, the PowerPC 405 and MicroBlaze are
both
> > + * memory mapped.
> > + */
> > +#ifdef CONFIG_PPC_DCR
> > +
> > +/**
> > + * temac_dma_dcr_in32 - DCR based DMA read
> > + */
> > +static u32 temac_dma_dcr_in(struct temac_local *lp, int reg)
> > +{
> > +	return dcr_read(lp->sdma_dcrs, reg);
> > +}
> > +
> > +/**
> > + * temac_dma_dcr_out32 - DCR based DMA write
> > + */
> > +static void temac_dma_dcr_out(struct temac_local *lp, int reg, u32
value)
> > +{
> >  	dcr_write(lp->sdma_dcrs, reg, value);
> >  }
> >
> >  /**
> > + * temac_dcr_setup - If the DMA is DCR based, then setup the
address and
> > + * I/O  functions
> > + */
> > +static int temac_dcr_setup(struct temac_local *lp, struct of_device
*op,
> > +				struct device_node *np)
> > +{
> > +	unsigned int dcrs;
> > +
> > +	/* setup the dcr address mapping if it's in the device tree */
> > +
> > +	dcrs = dcr_resource_start(np, 0);
> > +	if (dcrs != 0) {
> > +		lp->sdma_dcrs = dcr_map(np, dcrs, dcr_resource_len(np,
0));
> > +		lp->dma_in = temac_dma_dcr_in;
> > +		lp->dma_out = temac_dma_dcr_out;
> > +		dev_dbg(&op->dev, "DCR base: %x\n", dcrs);
> > +		return 0;
> > +	}
> > +	/* no DCR in the device tree, indicate a failure */
> > +	return -1;
> > +}
> > +
> > +#else
> > +
> > +/*
> > + * temac_dcr_setup - This is a stub for when DCR is not supported,
> > + * such as with MicroBlaze
> > + */
> > +static int temac_dcr_setup(struct temac_local *lp, struct of_device
*op,
> > +				struct device_node *np)
> > +{
> > +	return -1;
> > +}
> > +
> > +#endif
> > +
> > +/**
> >   * temac_dma_bd_init - Setup buffer descriptor rings
> >   */
> >  static int temac_dma_bd_init(struct net_device *ndev)
> > @@ -172,23 +238,23 @@ static int temac_dma_bd_init(struct net_device
*ndev)
> >  		lp->rx_bd_v[i].app0 = STS_CTRL_APP0_IRQONEND;
> >  	}
> >
> > -	temac_dma_out32(lp, TX_CHNL_CTRL, 0x10220400 |
> > +	lp->dma_out(lp, TX_CHNL_CTRL, 0x10220400 |
> >  					  CHNL_CTRL_IRQ_EN |
> >  					  CHNL_CTRL_IRQ_DLY_EN |
> >  					  CHNL_CTRL_IRQ_COAL_EN);
> >  	/* 0x10220483 */
> >  	/* 0x00100483 */
> > -	temac_dma_out32(lp, RX_CHNL_CTRL, 0xff010000 |
> > +	lp->dma_out(lp, RX_CHNL_CTRL, 0xff010000 |
> >  					  CHNL_CTRL_IRQ_EN |
> >  					  CHNL_CTRL_IRQ_DLY_EN |
> >  					  CHNL_CTRL_IRQ_COAL_EN |
> >  					  CHNL_CTRL_IRQ_IOE);
> >  	/* 0xff010283 */
> >
> > -	temac_dma_out32(lp, RX_CURDESC_PTR,  lp->rx_bd_p);
> > -	temac_dma_out32(lp, RX_TAILDESC_PTR,
> > +	lp->dma_out(lp, RX_CURDESC_PTR,  lp->rx_bd_p);
> > +	lp->dma_out(lp, RX_TAILDESC_PTR,
> >  		       lp->rx_bd_p + (sizeof(*lp->rx_bd_v) * (RX_BD_NUM
- 1)));
> > -	temac_dma_out32(lp, TX_CURDESC_PTR, lp->tx_bd_p);
> > +	lp->dma_out(lp, TX_CURDESC_PTR, lp->tx_bd_p);
> >
> >  	return 0;
> >  }
> > @@ -426,9 +492,9 @@ static void temac_device_reset(struct net_device
*ndev)
> >  	temac_indirect_out32(lp, XTE_RXC1_OFFSET, val &
~XTE_RXC1_RXEN_MASK);
> >
> >  	/* Reset Local Link (DMA) */
> > -	temac_dma_out32(lp, DMA_CONTROL_REG, DMA_CONTROL_RST);
> > +	lp->dma_out(lp, DMA_CONTROL_REG, DMA_CONTROL_RST);
> >  	timeout = 1000;
> > -	while (temac_dma_in32(lp, DMA_CONTROL_REG) & DMA_CONTROL_RST) {
> > +	while (lp->dma_in(lp, DMA_CONTROL_REG) & DMA_CONTROL_RST) {
> >  		udelay(1);
> >  		if (--timeout == 0) {
> >  			dev_err(&ndev->dev,
> > @@ -436,7 +502,7 @@ static void temac_device_reset(struct net_device
*ndev)
> >  			break;
> >  		}
> >  	}
> > -	temac_dma_out32(lp, DMA_CONTROL_REG, DMA_TAIL_ENABLE);
> > +	lp->dma_out(lp, DMA_CONTROL_REG, DMA_TAIL_ENABLE);
> >
> >  	temac_dma_bd_init(ndev);
> >
> > @@ -597,7 +663,7 @@ static int temac_start_xmit(struct sk_buff *skb,
struct net_device *ndev)
> >  		lp->tx_bd_tail = 0;
> >
> >  	/* Kick off the transfer */
> > -	temac_dma_out32(lp, TX_TAILDESC_PTR, tail_p); /* DMA start */
> > +	lp->dma_out(lp, TX_TAILDESC_PTR, tail_p); /* DMA start */
> >
> >  	return NETDEV_TX_OK;
> >  }
> > @@ -663,7 +729,7 @@ static void ll_temac_recv(struct net_device
*ndev)
> >  		cur_p = &lp->rx_bd_v[lp->rx_bd_ci];
> >  		bdstat = cur_p->app0;
> >  	}
> > -	temac_dma_out32(lp, RX_TAILDESC_PTR, tail_p);
> > +	lp->dma_out(lp, RX_TAILDESC_PTR, tail_p);
> >
> >  	spin_unlock_irqrestore(&lp->rx_lock, flags);
> >  }
> > @@ -674,8 +740,8 @@ static irqreturn_t ll_temac_tx_irq(int irq, void
*_ndev)
> >  	struct temac_local *lp = netdev_priv(ndev);
> >  	unsigned int status;
> >
> > -	status = temac_dma_in32(lp, TX_IRQ_REG);
> > -	temac_dma_out32(lp, TX_IRQ_REG, status);
> > +	status = lp->dma_in(lp, TX_IRQ_REG);
> > +	lp->dma_out(lp, TX_IRQ_REG, status);
> >
> >  	if (status & (IRQ_COAL | IRQ_DLY))
> >  		temac_start_xmit_done(lp->ndev);
> > @@ -692,8 +758,8 @@ static irqreturn_t ll_temac_rx_irq(int irq, void
*_ndev)
> >  	unsigned int status;
> >
> >  	/* Read and clear the status registers */
> > -	status = temac_dma_in32(lp, RX_IRQ_REG);
> > -	temac_dma_out32(lp, RX_IRQ_REG, status);
> > +	status = lp->dma_in(lp, RX_IRQ_REG);
> > +	lp->dma_out(lp, RX_IRQ_REG, status);
> >
> >  	if (status & (IRQ_COAL | IRQ_DLY))
> >  		ll_temac_recv(lp->ndev);
> > @@ -794,7 +860,7 @@ static ssize_t temac_show_llink_regs(struct
device *dev,
> >  	int i, len = 0;
> >
> >  	for (i = 0; i < 0x11; i++)
> > -		len += sprintf(buf + len, "%.8x%s", temac_dma_in32(lp,
i),
> > +		len += sprintf(buf + len, "%.8x%s", lp->dma_in(lp, i),
> >  			       (i % 8) == 7 ? "\n" : " ");
> >  	len += sprintf(buf + len, "\n");
> >
> > @@ -820,7 +886,6 @@ temac_of_probe(struct of_device *op, const
struct of_device_id *match)
> >  	struct net_device *ndev;
> >  	const void *addr;
> >  	int size, rc = 0;
> > -	unsigned int dcrs;
> >
> >  	/* Init network device structure */
> >  	ndev = alloc_etherdev(sizeof(*lp));
> > @@ -870,13 +935,20 @@ temac_of_probe(struct of_device *op, const
struct of_device_id *match)
> >  		goto nodev;
> >  	}
> >
> > -	dcrs = dcr_resource_start(np, 0);
> > -	if (dcrs == 0) {
> > -		dev_err(&op->dev, "could not get DMA register
address\n");
> > -		goto nodev;
> > +	/* Setup the DMA register accesses, could be DCR or memory
mapped */
> > +	if (temac_dcr_setup(lp, op, np)) {
> > +
> > +		/* no DCR in the device tree, try non-DCR */
> > +		lp->sdma_regs = of_iomap(np, 0);
> > +		if (lp->sdma_regs) {
> > +			lp->dma_in = temac_dma_in32;
> > +			lp->dma_out = temac_dma_out32;
> > +			dev_dbg(&op->dev, "MEM base: %p\n",
lp->sdma_regs);
> > +		} else {
> > +			dev_err(&op->dev, "unable to map DMA
registers\n");
> > +			goto nodev;
> > +		}
> >  	}
> > -	lp->sdma_dcrs = dcr_map(np, dcrs, dcr_resource_len(np, 0));
> > -	dev_dbg(&op->dev, "DCR base: %x\n", dcrs);
> >
> >  	lp->rx_irq = irq_of_parse_and_map(np, 0);
> >  	lp->tx_irq = irq_of_parse_and_map(np, 1);
> 
> 
> --
> Michal Simek, Ing. (M.Eng)
> PetaLogix - Linux Solutions for a Reconfigurable World
> w: www.petalogix.com p: +61-7-30090663,+42-0-721842854 f:
+61-7-30090663


This email and any attachments are intended for the sole use of the named recipient(s) and contain(s) confidential information that may be proprietary, privileged or copyrighted under applicable law. If you are not the intended recipient, do not read, copy, or forward this email message or any attachments. Delete this email message and any attachments immediately.



^ permalink raw reply

* tcp_reordering as 0 possible?
From: raj ravi @ 2010-03-15 14:25 UTC (permalink / raw)
  To: netdev

Hi,
what is the behaviour in TCP stack if I set tcp_reordering as 0.
So , sender will  start retransmission without waiting for any duplicate ACK ?
/proc/sys/net/ipv4/tcp_reordering   - Please clarify.
The default value is 3 which means it waits until 3 duplicate ack's
arrive and then start retransmission.

"The TCP sender should use the fast retransmit algorithm to detect and
repair loss based on incoming duplicate ACKs. After the arrival of 3
duplicate ACKs (4 identical ACKs without the arrival of any other
intervening packet), TCP performs a retransmission of what appears to
be the missing segment, without waiting for the retransmission timer
to expire."

Thanks!
Kavi

^ permalink raw reply

* Re: [PATCH] [V2] Add non-Virtex5 support for LL TEMAC driver
From: Michal Simek @ 2010-03-15 14:39 UTC (permalink / raw)
  To: John Linn
  Cc: netdev, linuxppc-dev, grant.likely, jwboyer, john.williams,
	John Tyner
In-Reply-To: <2d2cb4b6-627a-4e42-bc59-7845bbb6b680@SG2EHSMHS004.ehs.local>

John Linn wrote:
>> -----Original Message-----
>> From: Michal Simek [mailto:michal.simek@petalogix.com]
>> Sent: Monday, March 15, 2010 2:40 AM
>> To: John Linn
>> Cc: netdev@vger.kernel.org; linuxppc-dev@ozlabs.org;
> grant.likely@secretlab.ca;
>> jwboyer@linux.vnet.ibm.com; john.williams@petalogix.com; John Tyner
>> Subject: Re: [PATCH] [V2] Add non-Virtex5 support for LL TEMAC driver
>>
>> John Linn wrote:
>>> This patch adds support for using the LL TEMAC Ethernet driver on
>>> non-Virtex 5 platforms by adding support for accessing the Soft DMA
>>> registers as if they were memory mapped instead of solely through
> the
>>> DCR's (available on the Virtex 5).
>>>
>>> The patch also updates the driver so that it runs on the MicroBlaze.
>>> The changes were tested on the PowerPC 440, PowerPC 405, and the
>>> MicroBlaze platforms.
>> Which git-tree have you tested on? (Of course microblaze)
> 
> It was tested on the Xilinx tree for MicroBlaze which is based on the
> mainline and the Petalogix tree as DMA was needed. I tried to build
> against the mainline head but got errors with the DMA routines. I guess
> it's possible that it was a configuration issue there as I didn't dig
> real deep.

New dma api is in for-linus branch.
I tested it on that version and I am seeing some weird things. :-(
Access to bad area. I will try your tree.

The second thing which I see is in ll_temac_recv function.
On the following line is read a packet length which could be 0-16k.
		length = cur_p->app4 & 0x3FFF;

But allocated skb has max size XTE_MAX_JUMBO_FRAME_SIZE + XTE_ALIGN.

What happen if driver get packet greater than 9kB?
I got it (I don't know how) but skb_put has one checking mechanism which 
will cal skb_over_panic which caused panic.
That's why I think that will be good always to check that length is less 
than XTE_MAX_JUMBO_FRAME_SIZE + XTE_ALIGN.

What do you think?

Thanks,
Michal

> 
> I tested the PowerPC against the head of mainline.
> 
> Thanks,
> John
> 
>> Michal
>>
>>> Signed-off-by: John Tyner <jtyner@cs.ucr.edu>
>>> Signed-off-by: John Linn <john.linn@xilinx.com>
>>> ---
>>>
>>> V2 - Incorporated comments from Grant and added more logic to allow
> the driver
>>> to work on MicroBlaze.
>>>
>>>  drivers/net/Kconfig         |    1 -
>>>  drivers/net/ll_temac.h      |   17 +++++-
>>>  drivers/net/ll_temac_main.c |  124
> ++++++++++++++++++++++++++++++++++---------
>>>  3 files changed, 113 insertions(+), 29 deletions(-)
>>>
>>> diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
>>> index 9b6efe1..5402105 100644
>>> --- a/drivers/net/Kconfig
>>> +++ b/drivers/net/Kconfig
>>> @@ -2443,7 +2443,6 @@ config MV643XX_ETH
>>>  config XILINX_LL_TEMAC
>>>  	tristate "Xilinx LL TEMAC (LocalLink Tri-mode Ethernet MAC)
> driver"
>>>  	select PHYLIB
>>> -	depends on PPC_DCR_NATIVE
>>>  	help
>>>  	  This driver supports the Xilinx 10/100/1000 LocalLink TEMAC
>>>  	  core used in Xilinx Spartan and Virtex FPGAs
>>> diff --git a/drivers/net/ll_temac.h b/drivers/net/ll_temac.h
>>> index 1af66a1..915aa34 100644
>>> --- a/drivers/net/ll_temac.h
>>> +++ b/drivers/net/ll_temac.h
>>> @@ -5,8 +5,11 @@
>>>  #include <linux/netdevice.h>
>>>  #include <linux/of.h>
>>>  #include <linux/spinlock.h>
>>> +
>>> +#ifdef CONFIG_PPC_DCR
>>>  #include <asm/dcr.h>
>>>  #include <asm/dcr-regs.h>
>>> +#endif
>>>
>>>  /* packet size info */
>>>  #define XTE_HDR_SIZE			14      /* size of
> Ethernet header */
>>> @@ -290,8 +293,12 @@ This option defaults to enabled (set) */
>>>
>>>  #define TX_CONTROL_CALC_CSUM_MASK   1
>>>
>>> +/* Align the IP data in the packet on word boundaries as MicroBlaze
>>> + * needs it.
>>> + */
>>> +
>>>  #define XTE_ALIGN       32
>>> -#define BUFFER_ALIGN(adr) ((XTE_ALIGN - ((u32) adr)) % XTE_ALIGN)
>>> +#define BUFFER_ALIGN(adr) ((34 - ((u32) adr)) % XTE_ALIGN)
>>>
>>>  #define MULTICAST_CAM_TABLE_NUM 4
>>>
>>> @@ -335,9 +342,15 @@ struct temac_local {
>>>  	struct mii_bus *mii_bus;	/* MII bus reference */
>>>  	int mdio_irqs[PHY_MAX_ADDR];	/* IRQs table for MDIO bus */
>>>
>>> -	/* IO registers and IRQs */
>>> +	/* IO registers, dma functions and IRQs */
>>>  	void __iomem *regs;
>>> +	void __iomem *sdma_regs;
>>> +#ifdef CONFIG_PPC_DCR
>>>  	dcr_host_t sdma_dcrs;
>>> +#endif
>>> +	u32 (*dma_in)(struct temac_local *, int);
>>> +	void (*dma_out)(struct temac_local *, int, u32);
>>> +
>>>  	int tx_irq;
>>>  	int rx_irq;
>>>  	int emac_num;
>>> diff --git a/drivers/net/ll_temac_main.c
> b/drivers/net/ll_temac_main.c
>>> index a18e348..9aedf9b 100644
>>> --- a/drivers/net/ll_temac_main.c
>>> +++ b/drivers/net/ll_temac_main.c
>>> @@ -20,9 +20,6 @@
>>>   *   or rx, so this should be okay.
>>>   *
>>>   * TODO:
>>> - * - Fix driver to work on more than just Virtex5.  Right now the
> driver
>>> - *   assumes that the locallink DMA registers are accessed via DCR
>>> - *   instructions.
>>>   * - Factor out locallink DMA code into separate driver
>>>   * - Fix multicast assignment.
>>>   * - Fix support for hardware checksumming.
>>> @@ -115,17 +112,86 @@ void temac_indirect_out32(struct temac_local
> *lp, int reg, u32 value)
>>>  	temac_iow(lp, XTE_CTL0_OFFSET, CNTLREG_WRITE_ENABLE_MASK | reg);
>>>  }
>>>
>>> +/**
>>> + * temac_dma_in32 - Memory mapped DMA read, this function expects a
>>> + * register input that is based on DCR word addresses which
>>> + * are then converted to memory mapped byte addresses
>>> + */
>>>  static u32 temac_dma_in32(struct temac_local *lp, int reg)
>>>  {
>>> -	return dcr_read(lp->sdma_dcrs, reg);
>>> +	return in_be32((u32 *)(lp->sdma_regs + (reg << 2)));
>>>  }
>>>
>>> +/**
>>> + * temac_dma_out32 - Memory mapped DMA read, this function expects
> a
>>> + * register input that is based on DCR word addresses which
>>> + * are then converted to memory mapped byte addresses
>>> + */
>>>  static void temac_dma_out32(struct temac_local *lp, int reg, u32
> value)
>>>  {
>>> +	out_be32((u32 *)(lp->sdma_regs + (reg << 2)), value);
>>> +}
>>> +
>>> +/* DMA register access functions can be DCR based or memory mapped.
>>> + * The PowerPC 440 is DCR based, the PowerPC 405 and MicroBlaze are
> both
>>> + * memory mapped.
>>> + */
>>> +#ifdef CONFIG_PPC_DCR
>>> +
>>> +/**
>>> + * temac_dma_dcr_in32 - DCR based DMA read
>>> + */
>>> +static u32 temac_dma_dcr_in(struct temac_local *lp, int reg)
>>> +{
>>> +	return dcr_read(lp->sdma_dcrs, reg);
>>> +}
>>> +
>>> +/**
>>> + * temac_dma_dcr_out32 - DCR based DMA write
>>> + */
>>> +static void temac_dma_dcr_out(struct temac_local *lp, int reg, u32
> value)
>>> +{
>>>  	dcr_write(lp->sdma_dcrs, reg, value);
>>>  }
>>>
>>>  /**
>>> + * temac_dcr_setup - If the DMA is DCR based, then setup the
> address and
>>> + * I/O  functions
>>> + */
>>> +static int temac_dcr_setup(struct temac_local *lp, struct of_device
> *op,
>>> +				struct device_node *np)
>>> +{
>>> +	unsigned int dcrs;
>>> +
>>> +	/* setup the dcr address mapping if it's in the device tree */
>>> +
>>> +	dcrs = dcr_resource_start(np, 0);
>>> +	if (dcrs != 0) {
>>> +		lp->sdma_dcrs = dcr_map(np, dcrs, dcr_resource_len(np,
> 0));
>>> +		lp->dma_in = temac_dma_dcr_in;
>>> +		lp->dma_out = temac_dma_dcr_out;
>>> +		dev_dbg(&op->dev, "DCR base: %x\n", dcrs);
>>> +		return 0;
>>> +	}
>>> +	/* no DCR in the device tree, indicate a failure */
>>> +	return -1;
>>> +}
>>> +
>>> +#else
>>> +
>>> +/*
>>> + * temac_dcr_setup - This is a stub for when DCR is not supported,
>>> + * such as with MicroBlaze
>>> + */
>>> +static int temac_dcr_setup(struct temac_local *lp, struct of_device
> *op,
>>> +				struct device_node *np)
>>> +{
>>> +	return -1;
>>> +}
>>> +
>>> +#endif
>>> +
>>> +/**
>>>   * temac_dma_bd_init - Setup buffer descriptor rings
>>>   */
>>>  static int temac_dma_bd_init(struct net_device *ndev)
>>> @@ -172,23 +238,23 @@ static int temac_dma_bd_init(struct net_device
> *ndev)
>>>  		lp->rx_bd_v[i].app0 = STS_CTRL_APP0_IRQONEND;
>>>  	}
>>>
>>> -	temac_dma_out32(lp, TX_CHNL_CTRL, 0x10220400 |
>>> +	lp->dma_out(lp, TX_CHNL_CTRL, 0x10220400 |
>>>  					  CHNL_CTRL_IRQ_EN |
>>>  					  CHNL_CTRL_IRQ_DLY_EN |
>>>  					  CHNL_CTRL_IRQ_COAL_EN);
>>>  	/* 0x10220483 */
>>>  	/* 0x00100483 */
>>> -	temac_dma_out32(lp, RX_CHNL_CTRL, 0xff010000 |
>>> +	lp->dma_out(lp, RX_CHNL_CTRL, 0xff010000 |
>>>  					  CHNL_CTRL_IRQ_EN |
>>>  					  CHNL_CTRL_IRQ_DLY_EN |
>>>  					  CHNL_CTRL_IRQ_COAL_EN |
>>>  					  CHNL_CTRL_IRQ_IOE);
>>>  	/* 0xff010283 */
>>>
>>> -	temac_dma_out32(lp, RX_CURDESC_PTR,  lp->rx_bd_p);
>>> -	temac_dma_out32(lp, RX_TAILDESC_PTR,
>>> +	lp->dma_out(lp, RX_CURDESC_PTR,  lp->rx_bd_p);
>>> +	lp->dma_out(lp, RX_TAILDESC_PTR,
>>>  		       lp->rx_bd_p + (sizeof(*lp->rx_bd_v) * (RX_BD_NUM
> - 1)));
>>> -	temac_dma_out32(lp, TX_CURDESC_PTR, lp->tx_bd_p);
>>> +	lp->dma_out(lp, TX_CURDESC_PTR, lp->tx_bd_p);
>>>
>>>  	return 0;
>>>  }
>>> @@ -426,9 +492,9 @@ static void temac_device_reset(struct net_device
> *ndev)
>>>  	temac_indirect_out32(lp, XTE_RXC1_OFFSET, val &
> ~XTE_RXC1_RXEN_MASK);
>>>  	/* Reset Local Link (DMA) */
>>> -	temac_dma_out32(lp, DMA_CONTROL_REG, DMA_CONTROL_RST);
>>> +	lp->dma_out(lp, DMA_CONTROL_REG, DMA_CONTROL_RST);
>>>  	timeout = 1000;
>>> -	while (temac_dma_in32(lp, DMA_CONTROL_REG) & DMA_CONTROL_RST) {
>>> +	while (lp->dma_in(lp, DMA_CONTROL_REG) & DMA_CONTROL_RST) {
>>>  		udelay(1);
>>>  		if (--timeout == 0) {
>>>  			dev_err(&ndev->dev,
>>> @@ -436,7 +502,7 @@ static void temac_device_reset(struct net_device
> *ndev)
>>>  			break;
>>>  		}
>>>  	}
>>> -	temac_dma_out32(lp, DMA_CONTROL_REG, DMA_TAIL_ENABLE);
>>> +	lp->dma_out(lp, DMA_CONTROL_REG, DMA_TAIL_ENABLE);
>>>
>>>  	temac_dma_bd_init(ndev);
>>>
>>> @@ -597,7 +663,7 @@ static int temac_start_xmit(struct sk_buff *skb,
> struct net_device *ndev)
>>>  		lp->tx_bd_tail = 0;
>>>
>>>  	/* Kick off the transfer */
>>> -	temac_dma_out32(lp, TX_TAILDESC_PTR, tail_p); /* DMA start */
>>> +	lp->dma_out(lp, TX_TAILDESC_PTR, tail_p); /* DMA start */
>>>
>>>  	return NETDEV_TX_OK;
>>>  }
>>> @@ -663,7 +729,7 @@ static void ll_temac_recv(struct net_device
> *ndev)
>>>  		cur_p = &lp->rx_bd_v[lp->rx_bd_ci];
>>>  		bdstat = cur_p->app0;
>>>  	}
>>> -	temac_dma_out32(lp, RX_TAILDESC_PTR, tail_p);
>>> +	lp->dma_out(lp, RX_TAILDESC_PTR, tail_p);
>>>
>>>  	spin_unlock_irqrestore(&lp->rx_lock, flags);
>>>  }
>>> @@ -674,8 +740,8 @@ static irqreturn_t ll_temac_tx_irq(int irq, void
> *_ndev)
>>>  	struct temac_local *lp = netdev_priv(ndev);
>>>  	unsigned int status;
>>>
>>> -	status = temac_dma_in32(lp, TX_IRQ_REG);
>>> -	temac_dma_out32(lp, TX_IRQ_REG, status);
>>> +	status = lp->dma_in(lp, TX_IRQ_REG);
>>> +	lp->dma_out(lp, TX_IRQ_REG, status);
>>>
>>>  	if (status & (IRQ_COAL | IRQ_DLY))
>>>  		temac_start_xmit_done(lp->ndev);
>>> @@ -692,8 +758,8 @@ static irqreturn_t ll_temac_rx_irq(int irq, void
> *_ndev)
>>>  	unsigned int status;
>>>
>>>  	/* Read and clear the status registers */
>>> -	status = temac_dma_in32(lp, RX_IRQ_REG);
>>> -	temac_dma_out32(lp, RX_IRQ_REG, status);
>>> +	status = lp->dma_in(lp, RX_IRQ_REG);
>>> +	lp->dma_out(lp, RX_IRQ_REG, status);
>>>
>>>  	if (status & (IRQ_COAL | IRQ_DLY))
>>>  		ll_temac_recv(lp->ndev);
>>> @@ -794,7 +860,7 @@ static ssize_t temac_show_llink_regs(struct
> device *dev,
>>>  	int i, len = 0;
>>>
>>>  	for (i = 0; i < 0x11; i++)
>>> -		len += sprintf(buf + len, "%.8x%s", temac_dma_in32(lp,
> i),
>>> +		len += sprintf(buf + len, "%.8x%s", lp->dma_in(lp, i),
>>>  			       (i % 8) == 7 ? "\n" : " ");
>>>  	len += sprintf(buf + len, "\n");
>>>
>>> @@ -820,7 +886,6 @@ temac_of_probe(struct of_device *op, const
> struct of_device_id *match)
>>>  	struct net_device *ndev;
>>>  	const void *addr;
>>>  	int size, rc = 0;
>>> -	unsigned int dcrs;
>>>
>>>  	/* Init network device structure */
>>>  	ndev = alloc_etherdev(sizeof(*lp));
>>> @@ -870,13 +935,20 @@ temac_of_probe(struct of_device *op, const
> struct of_device_id *match)
>>>  		goto nodev;
>>>  	}
>>>
>>> -	dcrs = dcr_resource_start(np, 0);
>>> -	if (dcrs == 0) {
>>> -		dev_err(&op->dev, "could not get DMA register
> address\n");
>>> -		goto nodev;
>>> +	/* Setup the DMA register accesses, could be DCR or memory
> mapped */
>>> +	if (temac_dcr_setup(lp, op, np)) {
>>> +
>>> +		/* no DCR in the device tree, try non-DCR */
>>> +		lp->sdma_regs = of_iomap(np, 0);
>>> +		if (lp->sdma_regs) {
>>> +			lp->dma_in = temac_dma_in32;
>>> +			lp->dma_out = temac_dma_out32;
>>> +			dev_dbg(&op->dev, "MEM base: %p\n",
> lp->sdma_regs);
>>> +		} else {
>>> +			dev_err(&op->dev, "unable to map DMA
> registers\n");
>>> +			goto nodev;
>>> +		}
>>>  	}
>>> -	lp->sdma_dcrs = dcr_map(np, dcrs, dcr_resource_len(np, 0));
>>> -	dev_dbg(&op->dev, "DCR base: %x\n", dcrs);
>>>
>>>  	lp->rx_irq = irq_of_parse_and_map(np, 0);
>>>  	lp->tx_irq = irq_of_parse_and_map(np, 1);
>>
>> --
>> Michal Simek, Ing. (M.Eng)
>> PetaLogix - Linux Solutions for a Reconfigurable World
>> w: www.petalogix.com p: +61-7-30090663,+42-0-721842854 f:
> +61-7-30090663
> 
> 
> This email and any attachments are intended for the sole use of the named recipient(s) and contain(s) confidential information that may be proprietary, privileged or copyrighted under applicable law. If you are not the intended recipient, do not read, copy, or forward this email message or any attachments. Delete this email message and any attachments immediately.
> 
> 


-- 
Michal Simek, Ing. (M.Eng)
PetaLogix - Linux Solutions for a Reconfigurable World
w: www.petalogix.com p: +61-7-30090663,+42-0-721842854 f: +61-7-30090663

^ permalink raw reply

* Re: [1/3] gigaset: avoid registering CAPI driver more than once
From: Karsten Keil @ 2010-03-15 14:48 UTC (permalink / raw)
  To: Tilman Schmidt
  Cc: David Miller, netdev, linux-kernel, stable, isdn4linux,
	Hansjoerg Lipp, i4ldeveloper

Registering/unregistering the Gigaset CAPI driver when a device is
connected/disconnected causes an Oops when disconnecting two Gigaset
devices in a row, because the same capi_driver structure gets
unregistered twice. Fix by making driver registration/unregistration
a separate operation (empty in the ISDN4Linux case) called when the
main module is loaded/unloaded.

Impact: bugfix
Signed-off-by: Tilman Schmidt <tilman@imap.cc>
Acked-by: Karsten Keil <keil@b1-systems.de>

---
Note to -stable: applies correctly to 2.6.33 with fuzz 2 in capi.c.

 drivers/isdn/gigaset/capi.c    |   44 ++++++++++++++++++++++-----------------
 drivers/isdn/gigaset/common.c  |    6 +++-
 drivers/isdn/gigaset/gigaset.h |    6 +++-
 drivers/isdn/gigaset/i4l.c     |   28 ++++++++++++++++++-------
 4 files changed, 53 insertions(+), 31 deletions(-)

diff --git a/drivers/isdn/gigaset/capi.c b/drivers/isdn/gigaset/capi.c
index 6643d65..4a31962 100644
--- a/drivers/isdn/gigaset/capi.c
+++ b/drivers/isdn/gigaset/capi.c
@@ -2191,36 +2191,24 @@ static const struct file_operations gigaset_proc_fops = {
 	.release	= single_release,
 };
 
-static struct capi_driver capi_driver_gigaset = {
-	.name		= "gigaset",
-	.revision	= "1.0",
-};
-
 /**
- * gigaset_isdn_register() - register to LL
+ * gigaset_isdn_regdev() - register device to LL
  * @cs:		device descriptor structure.
  * @isdnid:	device name.
  *
- * Called by main module to register the device with the LL.
- *
  * Return value: 1 for success, 0 for failure
  */
-int gigaset_isdn_register(struct cardstate *cs, const char *isdnid)
+int gigaset_isdn_regdev(struct cardstate *cs, const char *isdnid)
 {
 	struct gigaset_capi_ctr *iif;
 	int rc;
 
-	pr_info("Kernel CAPI interface\n");
-
 	iif = kmalloc(sizeof(*iif), GFP_KERNEL);
 	if (!iif) {
 		pr_err("%s: out of memory\n", __func__);
 		return 0;
 	}
 
-	/* register driver with CAPI (ToDo: what for?) */
-	register_capi_driver(&capi_driver_gigaset);
-
 	/* prepare controller structure */
 	iif->ctr.owner         = THIS_MODULE;
 	iif->ctr.driverdata    = cs;
@@ -2241,7 +2229,6 @@ int gigaset_isdn_register(struct cardstate *cs, const char *isdnid)
 	rc = attach_capi_ctr(&iif->ctr);
 	if (rc) {
 		pr_err("attach_capi_ctr failed (%d)\n", rc);
-		unregister_capi_driver(&capi_driver_gigaset);
 		kfree(iif);
 		return 0;
 	}
@@ -2252,17 +2239,36 @@ int gigaset_isdn_register(struct cardstate *cs, const char *isdnid)
 }
 
 /**
- * gigaset_isdn_unregister() - unregister from LL
+ * gigaset_isdn_unregdev() - unregister device from LL
  * @cs:		device descriptor structure.
- *
- * Called by main module to unregister the device from the LL.
  */
-void gigaset_isdn_unregister(struct cardstate *cs)
+void gigaset_isdn_unregdev(struct cardstate *cs)
 {
 	struct gigaset_capi_ctr *iif = cs->iif;
 
 	detach_capi_ctr(&iif->ctr);
 	kfree(iif);
 	cs->iif = NULL;
+}
+
+static struct capi_driver capi_driver_gigaset = {
+	.name		= "gigaset",
+	.revision	= "1.0",
+};
+
+/**
+ * gigaset_isdn_regdrv() - register driver to LL
+ */
+void gigaset_isdn_regdrv(void)
+{
+	pr_info("Kernel CAPI interface\n");
+	register_capi_driver(&capi_driver_gigaset);
+}
+
+/**
+ * gigaset_isdn_unregdrv() - unregister driver from LL
+ */
+void gigaset_isdn_unregdrv(void)
+{
 	unregister_capi_driver(&capi_driver_gigaset);
 }
diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c
index 85de339..bdc01cb 100644
--- a/drivers/isdn/gigaset/common.c
+++ b/drivers/isdn/gigaset/common.c
@@ -507,7 +507,7 @@ void gigaset_freecs(struct cardstate *cs)
 	case 2: /* error in initcshw */
 		/* Deregister from LL */
 		make_invalid(cs, VALID_ID);
-		gigaset_isdn_unregister(cs);
+		gigaset_isdn_unregdev(cs);
 
 		/* fall through */
 	case 1: /* error when registering to LL */
@@ -769,7 +769,7 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
 	cs->cmdbytes = 0;
 
 	gig_dbg(DEBUG_INIT, "setting up iif");
-	if (!gigaset_isdn_register(cs, modulename)) {
+	if (!gigaset_isdn_regdev(cs, modulename)) {
 		pr_err("error registering ISDN device\n");
 		goto error;
 	}
@@ -1205,11 +1205,13 @@ static int __init gigaset_init_module(void)
 		gigaset_debuglevel = DEBUG_DEFAULT;
 
 	pr_info(DRIVER_DESC DRIVER_DESC_DEBUG "\n");
+	gigaset_isdn_regdrv();
 	return 0;
 }
 
 static void __exit gigaset_exit_module(void)
 {
+	gigaset_isdn_unregdrv();
 }
 
 module_init(gigaset_init_module);
diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h
index 1875ab8..cdd144e 100644
--- a/drivers/isdn/gigaset/gigaset.h
+++ b/drivers/isdn/gigaset/gigaset.h
@@ -675,8 +675,10 @@ int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size);
  */
 
 /* Called from common.c for setting up/shutting down with the ISDN subsystem */
-int gigaset_isdn_register(struct cardstate *cs, const char *isdnid);
-void gigaset_isdn_unregister(struct cardstate *cs);
+void gigaset_isdn_regdrv(void);
+void gigaset_isdn_unregdrv(void);
+int gigaset_isdn_regdev(struct cardstate *cs, const char *isdnid);
+void gigaset_isdn_unregdev(struct cardstate *cs);
 
 /* Called from hardware module to indicate completion of an skb */
 void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb);
diff --git a/drivers/isdn/gigaset/i4l.c b/drivers/isdn/gigaset/i4l.c
index f0acb9d..c22e5ac 100644
--- a/drivers/isdn/gigaset/i4l.c
+++ b/drivers/isdn/gigaset/i4l.c
@@ -592,15 +592,13 @@ void gigaset_isdn_stop(struct cardstate *cs)
 }
 
 /**
- * gigaset_isdn_register() - register to LL
+ * gigaset_isdn_regdev() - register to LL
  * @cs:		device descriptor structure.
  * @isdnid:	device name.
  *
- * Called by main module to register the device with the LL.
- *
  * Return value: 1 for success, 0 for failure
  */
-int gigaset_isdn_register(struct cardstate *cs, const char *isdnid)
+int gigaset_isdn_regdev(struct cardstate *cs, const char *isdnid)
 {
 	isdn_if *iif;
 
@@ -650,15 +648,29 @@ int gigaset_isdn_register(struct cardstate *cs, const char *isdnid)
 }
 
 /**
- * gigaset_isdn_unregister() - unregister from LL
+ * gigaset_isdn_unregdev() - unregister device from LL
  * @cs:		device descriptor structure.
- *
- * Called by main module to unregister the device from the LL.
  */
-void gigaset_isdn_unregister(struct cardstate *cs)
+void gigaset_isdn_unregdev(struct cardstate *cs)
 {
 	gig_dbg(DEBUG_CMD, "sending UNLOAD");
 	gigaset_i4l_cmd(cs, ISDN_STAT_UNLOAD);
 	kfree(cs->iif);
 	cs->iif = NULL;
 }
+
+/**
+ * gigaset_isdn_regdrv() - register driver to LL
+ */
+void gigaset_isdn_regdrv(void)
+{
+	/* nothing to do */
+}
+
+/**
+ * gigaset_isdn_unregdrv() - unregister driver from LL
+ */
+void gigaset_isdn_unregdrv(void)
+{
+	/* nothing to do */
+}

^ permalink raw reply related

* Re: [2/3] gigaset: correct clearing of at_state strings on RING
From: Karsten Keil @ 2010-03-15 14:48 UTC (permalink / raw)
  To: Tilman Schmidt
  Cc: David Miller, netdev, linux-kernel, stable, isdn4linux,
	Hansjoerg Lipp, i4ldeveloper

In RING handling, clear the table of received parameter strings in
a loop like everywhere else, instead of by enumeration which had
already gotten out of sync.

Impact: minor bugfix
Signed-off-by: Tilman Schmidt <tilman@imap.cc>
Acked-by: Karsten Keil <keil@b1-systems.de>

---
Note to -stable: applies correctly to 2.6.33.

 drivers/isdn/gigaset/ev-layer.c |   12 ++++--------
 1 files changed, 4 insertions(+), 8 deletions(-)

diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c
index c8f89b7..206c380 100644
--- a/drivers/isdn/gigaset/ev-layer.c
+++ b/drivers/isdn/gigaset/ev-layer.c
@@ -1258,14 +1258,10 @@ static void do_action(int action, struct cardstate *cs,
 		 * note that bcs may be NULL if no B channel is free
 		 */
 		at_state2->ConState = 700;
-		kfree(at_state2->str_var[STR_NMBR]);
-		at_state2->str_var[STR_NMBR] = NULL;
-		kfree(at_state2->str_var[STR_ZCPN]);
-		at_state2->str_var[STR_ZCPN] = NULL;
-		kfree(at_state2->str_var[STR_ZBC]);
-		at_state2->str_var[STR_ZBC] = NULL;
-		kfree(at_state2->str_var[STR_ZHLC]);
-		at_state2->str_var[STR_ZHLC] = NULL;
+		for (i = 0; i < STR_NUM; ++i) {
+			kfree(at_state2->str_var[i]);
+			at_state2->str_var[i] = NULL;
+		}
 		at_state2->int_var[VAR_ZCTP] = -1;
 
 		spin_lock_irqsave(&cs->lock, flags);

^ 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