Netdev List
 help / color / mirror / Atom feed
* [net-next 4/10] bnx2x: Adding some mmiowb
From: Eilon Greenstein @ 2009-07-21 15:47 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, Vlad Zolotarov

Signed-off-by: Vlad Zolotarov <vladz@broadcom.com>
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
---
 drivers/net/bnx2x_main.c |   17 +++++++++++++++++
 1 files changed, 17 insertions(+), 0 deletions(-)

diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c
index d946c9e..f20df6d 100644
--- a/drivers/net/bnx2x_main.c
+++ b/drivers/net/bnx2x_main.c
@@ -652,6 +652,11 @@ static void bnx2x_int_enable(struct bnx2x *bp)
 	   val, port, addr, (msix ? "MSI-X" : (msi ? "MSI" : "INTx")));
 
 	REG_WR(bp, addr, val);
+	/*
+	 * Ensure that HC_CONFIG is written before leading/trailing edge config
+	 */
+	mmiowb();
+	barrier();
 
 	if (CHIP_IS_E1H(bp)) {
 		/* init leading/trailing edge */
@@ -666,6 +671,9 @@ static void bnx2x_int_enable(struct bnx2x *bp)
 		REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, val);
 		REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, val);
 	}
+
+	/* Make sure that interrupts are indeed enabled from here on */
+	mmiowb();
 }
 
 static void bnx2x_int_disable(struct bnx2x *bp)
@@ -739,6 +747,10 @@ static inline void bnx2x_ack_sb(struct bnx2x *bp, u8 sb_id,
 	DP(BNX2X_MSG_OFF, "write 0x%08x to HC addr 0x%x\n",
 	   (*(u32 *)&igu_ack), hc_addr);
 	REG_WR(bp, hc_addr, (*(u32 *)&igu_ack));
+
+	/* Make sure that ACK is written */
+	mmiowb();
+	barrier();
 }
 
 static inline u16 bnx2x_update_fpsb_idx(struct bnx2x_fastpath *fp)
@@ -2429,9 +2441,14 @@ static int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
 		bp->spq_prod_idx++;
 	}
 
+	/* Make sure that BD data is updated before writing the producer */
+	wmb();
+
 	REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_SPQ_PROD_OFFSET(func),
 	       bp->spq_prod_idx);
 
+	mmiowb();
+
 	spin_unlock_bh(&bp->spq_lock);
 	return 0;
 }
-- 
1.5.4.3





^ permalink raw reply related

* [net-next 3/10] bnx2x: Fan failure early detection
From: Eilon Greenstein @ 2009-07-21 15:47 UTC (permalink / raw)
  To: David Miller; +Cc: netdev

Check if fan failure happened before the driver was loaded and notify the user

Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
---
 drivers/net/bnx2x_main.c |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c
index ae8b7b5..d946c9e 100644
--- a/drivers/net/bnx2x_main.c
+++ b/drivers/net/bnx2x_main.c
@@ -5185,6 +5185,11 @@ static void bnx2x_nic_init(struct bnx2x *bp, u32 load_code)
 	mmiowb();
 
 	bnx2x_int_enable(bp);
+
+	/* Check for SPIO5 */
+	bnx2x_attn_int_deasserted0(bp,
+		REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_1_FUNC_0 + BP_PORT(bp)*4) &
+				   AEU_INPUTS_ATTN_BITS_SPIO5);
 }
 
 /* end of nic init */
-- 
1.5.4.3





^ permalink raw reply related

* [net-next 1/10] bnx2x: Stop management traffic in loopback test
From: Eilon Greenstein @ 2009-07-21 15:47 UTC (permalink / raw)
  To: David Miller; +Cc: netdev

Since management traffic cannot go on the wire while configured to loopback,
simply stop it to avoid race condition when the MAC is set to loopback in the
middle of a packet

Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
---
 drivers/net/bnx2x_main.c |   11 +++++++++++
 drivers/net/bnx2x_reg.h  |    2 ++
 2 files changed, 13 insertions(+), 0 deletions(-)

diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c
index 6c67be6..177cb46 100644
--- a/drivers/net/bnx2x_main.c
+++ b/drivers/net/bnx2x_main.c
@@ -9691,8 +9691,15 @@ static void bnx2x_self_test(struct net_device *dev,
 		etest->flags &= ~ETH_TEST_FL_OFFLINE;
 
 	if (etest->flags & ETH_TEST_FL_OFFLINE) {
+		int port = BP_PORT(bp);
+		u32 val;
 		u8 link_up;
 
+		/* save current value of input enable for TX port IF */
+		val = REG_RD(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4);
+		/* disable input for TX port IF */
+		REG_WR(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4, 0);
+
 		link_up = bp->link_vars.link_up;
 		bnx2x_nic_unload(bp, UNLOAD_NORMAL);
 		bnx2x_nic_load(bp, LOAD_DIAG);
@@ -9712,6 +9719,10 @@ static void bnx2x_self_test(struct net_device *dev,
 			etest->flags |= ETH_TEST_FL_FAILED;
 
 		bnx2x_nic_unload(bp, UNLOAD_NORMAL);
+
+		/* restore input for TX port IF */
+		REG_WR(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4, val);
+
 		bnx2x_nic_load(bp, LOAD_NORMAL);
 		/* wait until link state is restored */
 		bnx2x_wait_for_link(bp, link_up);
diff --git a/drivers/net/bnx2x_reg.h b/drivers/net/bnx2x_reg.h
index b8ce6fc..6d77730 100644
--- a/drivers/net/bnx2x_reg.h
+++ b/drivers/net/bnx2x_reg.h
@@ -1660,6 +1660,8 @@
 #define NIG_REG_EGRESS_PBF0_IN_EN				 0x100cc
 /* [RW 1] Input enable for TX PBF user packet port1 IF */
 #define NIG_REG_EGRESS_PBF1_IN_EN				 0x100d0
+/* [RW 1] Input enable for TX UMP management packet port0 IF */
+#define NIG_REG_EGRESS_UMP0_IN_EN				 0x100d4
 /* [RW 1] Input enable for RX_EMAC0 IF */
 #define NIG_REG_EMAC0_IN_EN					 0x100a4
 /* [RW 1] output enable for TX EMAC pause port 0 IF */
-- 
1.5.4.3





^ permalink raw reply related

* [net-next 2/10] bnx2x: Fan failure
From: Eilon Greenstein @ 2009-07-21 15:47 UTC (permalink / raw)
  To: David Miller; +Cc: netdev

Setup fan failure for different PHY types or according to nvram settings

Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
---
 drivers/net/bnx2x_hsi.h  |   15 ++++++
 drivers/net/bnx2x_main.c |  112 +++++++++++++++++++++++++++++++---------------
 2 files changed, 90 insertions(+), 37 deletions(-)

diff --git a/drivers/net/bnx2x_hsi.h b/drivers/net/bnx2x_hsi.h
index 03c6242..41c6dcb 100644
--- a/drivers/net/bnx2x_hsi.h
+++ b/drivers/net/bnx2x_hsi.h
@@ -91,6 +91,21 @@ struct shared_hw_cfg {					 /* NVRAM Offset */
 
 #define SHARED_HW_CFG_HIDE_PORT1		    0x00002000
 
+	/*  The fan failure mechanism is usually related to the PHY type
+	  since the power consumption of the board is determined by the PHY.
+	  Currently, fan is required for most designs with SFX7101, BCM8727
+	  and BCM8481. If a fan is not required for a board which uses one
+	  of those PHYs, this field should be set to "Disabled". If a fan is
+	  required for a different PHY type, this option should be set to
+	  "Enabled".
+	  The fan failure indication is expected on
+	  SPIO5 */
+#define SHARED_HW_CFG_FAN_FAILURE_MASK			      0x00180000
+#define SHARED_HW_CFG_FAN_FAILURE_SHIFT 		      19
+#define SHARED_HW_CFG_FAN_FAILURE_PHY_TYPE		      0x00000000
+#define SHARED_HW_CFG_FAN_FAILURE_DISABLED		      0x00080000
+#define SHARED_HW_CFG_FAN_FAILURE_ENABLED		      0x00100000
+
 	u32 power_dissipated;					/* 0x11c */
 #define SHARED_HW_CFG_POWER_DIS_CMN_MASK	    0xff000000
 #define SHARED_HW_CFG_POWER_DIS_CMN_SHIFT	    24
diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c
index 177cb46..ae8b7b5 100644
--- a/drivers/net/bnx2x_main.c
+++ b/drivers/net/bnx2x_main.c
@@ -2598,6 +2598,22 @@ static void bnx2x_attn_int_asserted(struct bnx2x *bp, u32 asserted)
 	}
 }
 
+static inline void bnx2x_fan_failure(struct bnx2x *bp)
+{
+	int port = BP_PORT(bp);
+
+	/* mark the failure */
+	bp->link_params.ext_phy_config &= ~PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK;
+	bp->link_params.ext_phy_config |= PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE;
+	SHMEM_WR(bp, dev_info.port_hw_config[port].external_phy_config,
+		 bp->link_params.ext_phy_config);
+
+	/* log the failure */
+	printk(KERN_ERR PFX "Fan Failure on Network Controller %s has caused"
+	       " the driver to shutdown the card to prevent permanent"
+	       " damage.  Please contact Dell Support for assistance\n",
+	       bp->dev->name);
+}
 static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn)
 {
 	int port = BP_PORT(bp);
@@ -2615,36 +2631,21 @@ static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn)
 
 		BNX2X_ERR("SPIO5 hw attention\n");
 
+		/* Fan failure attention */
 		switch (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config)) {
 		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
-			/* Fan failure attention */
-
-			/* The PHY reset is controlled by GPIO 1 */
-			bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
-				       MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
 			/* Low power mode is controlled by GPIO 2 */
 			bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
 				       MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
-			/* mark the failure */
-			bp->link_params.ext_phy_config &=
-					~PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK;
-			bp->link_params.ext_phy_config |=
-					PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE;
-			SHMEM_WR(bp,
-				 dev_info.port_hw_config[port].
-							external_phy_config,
-				 bp->link_params.ext_phy_config);
-			/* log the failure */
-			printk(KERN_ERR PFX "Fan Failure on Network"
-			       " Controller %s has caused the driver to"
-			       " shutdown the card to prevent permanent"
-			       " damage.  Please contact Dell Support for"
-			       " assistance\n", bp->dev->name);
+			/* The PHY reset is controlled by GPIO 1 */
+			bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
+				       MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
 			break;
 
 		default:
 			break;
 		}
+		bnx2x_fan_failure(bp);
 	}
 
 	if (attn & (AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0 |
@@ -5509,6 +5510,58 @@ static void bnx2x_reset_common(struct bnx2x *bp)
 	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, 0x1403);
 }
 
+
+static void bnx2x_setup_fan_failure_detection(struct bnx2x *bp)
+{
+	u32 val;
+	u8 port;
+	u8 is_required = 0;
+
+	val = SHMEM_RD(bp, dev_info.shared_hw_config.config2) &
+	      SHARED_HW_CFG_FAN_FAILURE_MASK;
+
+	if (val == SHARED_HW_CFG_FAN_FAILURE_ENABLED)
+		is_required = 1;
+
+	/*
+	 * The fan failure mechanism is usually related to the PHY type since
+	 * the power consumption of the board is affected by the PHY. Currently,
+	 * fan is required for most designs with SFX7101, BCM8727 and BCM8481.
+	 */
+	else if (val == SHARED_HW_CFG_FAN_FAILURE_PHY_TYPE)
+		for (port = PORT_0; port < PORT_MAX; port++) {
+			u32 phy_type =
+				SHMEM_RD(bp, dev_info.port_hw_config[port].
+					 external_phy_config) &
+				PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK;
+			is_required |=
+				((phy_type ==
+				  PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101) ||
+				 (phy_type ==
+				  PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481));
+		}
+
+	DP(NETIF_MSG_HW, "fan detection setting: %d\n", is_required);
+
+	if (is_required == 0)
+		return;
+
+	/* Fan failure is indicated by SPIO 5 */
+	bnx2x_set_spio(bp, MISC_REGISTERS_SPIO_5,
+		       MISC_REGISTERS_SPIO_INPUT_HI_Z);
+
+	/* set to active low mode */
+	val = REG_RD(bp, MISC_REG_SPIO_INT);
+	val |= ((1 << MISC_REGISTERS_SPIO_5) <<
+				MISC_REGISTERS_SPIO_INT_OLD_SET_POS);
+	REG_WR(bp, MISC_REG_SPIO_INT, val);
+
+	/* enable interrupt to signal the IGU */
+	val = REG_RD(bp, MISC_REG_SPIO_EVENT_EN);
+	val |= (1 << MISC_REGISTERS_SPIO_5);
+	REG_WR(bp, MISC_REG_SPIO_EVENT_EN, val);
+}
+
 static int bnx2x_init_common(struct bnx2x *bp)
 {
 	u32 val, i;
@@ -5738,27 +5791,12 @@ static int bnx2x_init_common(struct bnx2x *bp)
 		bp->port.need_hw_lock = 1;
 		break;
 
-	case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
-		/* Fan failure is indicated by SPIO 5 */
-		bnx2x_set_spio(bp, MISC_REGISTERS_SPIO_5,
-			       MISC_REGISTERS_SPIO_INPUT_HI_Z);
-
-		/* set to active low mode */
-		val = REG_RD(bp, MISC_REG_SPIO_INT);
-		val |= ((1 << MISC_REGISTERS_SPIO_5) <<
-					MISC_REGISTERS_SPIO_INT_OLD_SET_POS);
-		REG_WR(bp, MISC_REG_SPIO_INT, val);
-
-		/* enable interrupt to signal the IGU */
-		val = REG_RD(bp, MISC_REG_SPIO_EVENT_EN);
-		val |= (1 << MISC_REGISTERS_SPIO_5);
-		REG_WR(bp, MISC_REG_SPIO_EVENT_EN, val);
-		break;
-
 	default:
 		break;
 	}
 
+	bnx2x_setup_fan_failure_detection(bp);
+
 	/* clear PXP2 attentions */
 	REG_RD(bp, PXP2_REG_PXP2_INT_STS_CLR_0);
 
-- 
1.5.4.3





^ permalink raw reply related

* Re: [PATCH] USB host CDC Phonet network interface driver
From: Marcel Holtmann @ 2009-07-21 15:34 UTC (permalink / raw)
  To: Dan Williams
  Cc: Rémi Denis-Courmont, netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-usb-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1248184373.6558.15.camel-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>

Hi Dan,

> > Many Nokia handsets support a Phonet interface to the cellular modem
> > via a vendor-specific USB interface. CDC Phonet follows the
> > Communications Device Class model, with one control interface, and
> > and a pair of inactive and active data alternative interface. The later
> > has two bulk endpoint, one per direction.
> > 
> > This was tested against Nokia E61, Nokia N95, and the existing Phonet
> > gadget function for the Linux composite USB gadget framework.
> 
> Is there an example somewhere of how to use Phonet to get a mobile
> broadband connection in place of usb-serial and PPP?  I've read the
> Phonet protocol description and other random docs I can find, but can't
> figure out how that would work.  Or does "PC Suite" mode not support
> that?

I talked with Remi about it and he told me that currently there is no
public example on how to do it. Also it involves a bit more event
handling and other details via ISI modem library. At some point we will
have an example inside oFono on how to do it, but not right now.

Regards

Marcel


--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH] dm9000: switch to dev_pm_ops
From: Ben Dooks @ 2009-07-21 15:04 UTC (permalink / raw)
  To: Mike Rapoport; +Cc: David S. Miller, netdev
In-Reply-To: <1248184837-22350-1-git-send-email-mike@compulab.co.il>

Mike Rapoport wrote:
> Signed-off-by: Mike Rapoport <mike@compulab.co.il>
Acked-by: Ben Dooks <ben-linux@fluff.org>
> ---
>  drivers/net/dm9000.c |   18 ++++++++++++------
>  1 files changed, 12 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
> index dd771de..7b639cd 100644
> --- a/drivers/net/dm9000.c
> +++ b/drivers/net/dm9000.c
> @@ -1410,9 +1410,10 @@ out:
>  }
>  
>  static int
> -dm9000_drv_suspend(struct platform_device *dev, pm_message_t state)
> +dm9000_drv_suspend(struct device *dev)
>  {
> -	struct net_device *ndev = platform_get_drvdata(dev);
> +	struct platform_device *pdev = to_platform_device(dev);
> +	struct net_device *ndev = platform_get_drvdata(pdev);
>  	board_info_t *db;
>  
>  	if (ndev) {
> @@ -1428,9 +1429,10 @@ dm9000_drv_suspend(struct platform_device *dev, pm_message_t state)
>  }
>  
>  static int
> -dm9000_drv_resume(struct platform_device *dev)
> +dm9000_drv_resume(struct device *dev)
>  {
> -	struct net_device *ndev = platform_get_drvdata(dev);
> +	struct platform_device *pdev = to_platform_device(dev);
> +	struct net_device *ndev = platform_get_drvdata(pdev);
>  	board_info_t *db = netdev_priv(ndev);
>  
>  	if (ndev) {
> @@ -1447,6 +1449,11 @@ dm9000_drv_resume(struct platform_device *dev)
>  	return 0;
>  }
>  
> +static struct dev_pm_ops dm9000_drv_pm_ops = {
> +	.suspend	= dm9000_drv_suspend,
> +	.resume		= dm9000_drv_resume,
> +};
> +
>  static int __devexit
>  dm9000_drv_remove(struct platform_device *pdev)
>  {
> @@ -1466,11 +1473,10 @@ static struct platform_driver dm9000_driver = {
>  	.driver	= {
>  		.name    = "dm9000",
>  		.owner	 = THIS_MODULE,
> +		.pm	 = &dm9000_drv_pm_ops,
>  	},
>  	.probe   = dm9000_probe,
>  	.remove  = __devexit_p(dm9000_drv_remove),
> -	.suspend = dm9000_drv_suspend,
> -	.resume  = dm9000_drv_resume,
>  };
>  
>  static int __init


-- 
Ben Dooks, Software Engineer, Simtec Electronics

http://www.simtec.co.uk/

^ permalink raw reply

* [PATCH] dm9000: switch to dev_pm_ops
From: Mike Rapoport @ 2009-07-21 14:00 UTC (permalink / raw)
  To: David S. Miller; +Cc: Ben Dooks, netdev, Mike Rapoport

Signed-off-by: Mike Rapoport <mike@compulab.co.il>
---
 drivers/net/dm9000.c |   18 ++++++++++++------
 1 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
index dd771de..7b639cd 100644
--- a/drivers/net/dm9000.c
+++ b/drivers/net/dm9000.c
@@ -1410,9 +1410,10 @@ out:
 }
 
 static int
-dm9000_drv_suspend(struct platform_device *dev, pm_message_t state)
+dm9000_drv_suspend(struct device *dev)
 {
-	struct net_device *ndev = platform_get_drvdata(dev);
+	struct platform_device *pdev = to_platform_device(dev);
+	struct net_device *ndev = platform_get_drvdata(pdev);
 	board_info_t *db;
 
 	if (ndev) {
@@ -1428,9 +1429,10 @@ dm9000_drv_suspend(struct platform_device *dev, pm_message_t state)
 }
 
 static int
-dm9000_drv_resume(struct platform_device *dev)
+dm9000_drv_resume(struct device *dev)
 {
-	struct net_device *ndev = platform_get_drvdata(dev);
+	struct platform_device *pdev = to_platform_device(dev);
+	struct net_device *ndev = platform_get_drvdata(pdev);
 	board_info_t *db = netdev_priv(ndev);
 
 	if (ndev) {
@@ -1447,6 +1449,11 @@ dm9000_drv_resume(struct platform_device *dev)
 	return 0;
 }
 
+static struct dev_pm_ops dm9000_drv_pm_ops = {
+	.suspend	= dm9000_drv_suspend,
+	.resume		= dm9000_drv_resume,
+};
+
 static int __devexit
 dm9000_drv_remove(struct platform_device *pdev)
 {
@@ -1466,11 +1473,10 @@ static struct platform_driver dm9000_driver = {
 	.driver	= {
 		.name    = "dm9000",
 		.owner	 = THIS_MODULE,
+		.pm	 = &dm9000_drv_pm_ops,
 	},
 	.probe   = dm9000_probe,
 	.remove  = __devexit_p(dm9000_drv_remove),
-	.suspend = dm9000_drv_suspend,
-	.resume  = dm9000_drv_resume,
 };
 
 static int __init
-- 
1.6.0.6


^ permalink raw reply related

* Re: [PATCH] USB host CDC Phonet network interface driver
From: Dan Williams @ 2009-07-21 13:52 UTC (permalink / raw)
  To: Rémi Denis-Courmont; +Cc: netdev, linux-usb
In-Reply-To: <1248177515-12712-1-git-send-email-remi.denis-courmont@nokia.com>

On Tue, 2009-07-21 at 14:58 +0300, Rémi Denis-Courmont wrote:
> From: Rémi Denis-Courmont <remi.denis-courmont@nokia.com>
> 
> Many Nokia handsets support a Phonet interface to the cellular modem
> via a vendor-specific USB interface. CDC Phonet follows the
> Communications Device Class model, with one control interface, and
> and a pair of inactive and active data alternative interface. The later
> has two bulk endpoint, one per direction.
> 
> This was tested against Nokia E61, Nokia N95, and the existing Phonet
> gadget function for the Linux composite USB gadget framework.

Is there an example somewhere of how to use Phonet to get a mobile
broadband connection in place of usb-serial and PPP?  I've read the
Phonet protocol description and other random docs I can find, but can't
figure out how that would work.  Or does "PC Suite" mode not support
that?

Thanks!
Dan


> Signed-off-by: Rémi Denis-Courmont <remi.denis-courmont@nokia.com>
> ---
>  drivers/net/usb/Kconfig      |    8 +
>  drivers/net/usb/Makefile     |    1 +
>  drivers/net/usb/cdc-phonet.c |  461 ++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 470 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/net/usb/cdc-phonet.c
> 
> diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
> index a906d39..c47237c 100644
> --- a/drivers/net/usb/Kconfig
> +++ b/drivers/net/usb/Kconfig
> @@ -369,4 +369,12 @@ config USB_NET_INT51X1
>  	  (Powerline Communications) solution with an Intellon
>  	  INT51x1/INT5200 chip, like the "devolo dLan duo".
>  
> +config USB_CDC_PHONET
> +	tristate "CDC Phonet support"
> +	depends on PHONET
> +	help
> +	  Choose this option to support the Phonet interface to a Nokia
> +	  cellular modem, as found on most Nokia handsets with the
> +	  "PC suite" USB profile.
> +
>  endmenu
> diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile
> index b870b0b..e17afb7 100644
> --- a/drivers/net/usb/Makefile
> +++ b/drivers/net/usb/Makefile
> @@ -21,4 +21,5 @@ obj-$(CONFIG_USB_NET_ZAURUS)	+= zaurus.o
>  obj-$(CONFIG_USB_NET_MCS7830)	+= mcs7830.o
>  obj-$(CONFIG_USB_USBNET)	+= usbnet.o
>  obj-$(CONFIG_USB_NET_INT51X1)	+= int51x1.o
> +obj-$(CONFIG_USB_CDC_PHONET)	+= cdc-phonet.o
>  
> diff --git a/drivers/net/usb/cdc-phonet.c b/drivers/net/usb/cdc-phonet.c
> new file mode 100644
> index 0000000..792af72
> --- /dev/null
> +++ b/drivers/net/usb/cdc-phonet.c
> @@ -0,0 +1,461 @@
> +/*
> + * phonet.c -- USB CDC Phonet host driver
> + *
> + * Copyright (C) 2008-2009 Nokia Corporation. All rights reserved.
> + *
> + * Author: Rémi Denis-Courmont
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * version 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
> + * 02110-1301 USA
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/usb.h>
> +#include <linux/usb/cdc.h>
> +#include <linux/netdevice.h>
> +#include <linux/if_arp.h>
> +#include <linux/if_phonet.h>
> +
> +#define PN_MEDIA_USB	0x1B
> +
> +static const unsigned rxq_size = 17;
> +
> +struct usbpn_dev {
> +	struct net_device	*dev;
> +
> +	struct usb_interface	*intf, *data_intf;
> +	struct usb_device	*usb;
> +	unsigned int		tx_pipe, rx_pipe;
> +	u8 active_setting;
> +	u8 disconnected;
> +
> +	unsigned		tx_queue;
> +	spinlock_t		tx_lock;
> +
> +	spinlock_t		rx_lock;
> +	struct sk_buff		*rx_skb;
> +	struct urb		*urbs[0];
> +};
> +
> +static void tx_complete(struct urb *req);
> +static void rx_complete(struct urb *req);
> +
> +/*
> + * Network device callbacks
> + */
> +static int usbpn_xmit(struct sk_buff *skb, struct net_device *dev)
> +{
> +	struct usbpn_dev *pnd = netdev_priv(dev);
> +	struct urb *req = NULL;
> +	unsigned long flags;
> +	int err;
> +
> +	if (skb->protocol != htons(ETH_P_PHONET))
> +		goto drop;
> +
> +	req = usb_alloc_urb(0, GFP_ATOMIC);
> +	if (!req)
> +		goto drop;
> +	usb_fill_bulk_urb(req, pnd->usb, pnd->tx_pipe, skb->data, skb->len,
> +				tx_complete, skb);
> +	req->transfer_flags = URB_ZERO_PACKET;
> +	err = usb_submit_urb(req, GFP_ATOMIC);
> +	if (err) {
> +		usb_free_urb(req);
> +		goto drop;
> +	}
> +
> +	spin_lock_irqsave(&pnd->tx_lock, flags);
> +	pnd->tx_queue++;
> +	if (pnd->tx_queue >= dev->tx_queue_len)
> +		netif_stop_queue(dev);
> +	spin_unlock_irqrestore(&pnd->tx_lock, flags);
> +	return 0;
> +
> +drop:
> +	dev_kfree_skb(skb);
> +	dev->stats.tx_dropped++;
> +	return 0;
> +}
> +
> +static void tx_complete(struct urb *req)
> +{
> +	struct sk_buff *skb = req->context;
> +	struct net_device *dev = skb->dev;
> +	struct usbpn_dev *pnd = netdev_priv(dev);
> +
> +	switch (req->status) {
> +	case 0:
> +		dev->stats.tx_bytes += skb->len;
> +		break;
> +
> +	case -ENOENT:
> +	case -ECONNRESET:
> +	case -ESHUTDOWN:
> +		dev->stats.tx_aborted_errors++;
> +	default:
> +		dev->stats.tx_errors++;
> +		dev_dbg(&dev->dev, "TX error (%d)\n", req->status);
> +	}
> +	dev->stats.tx_packets++;
> +
> +	spin_lock(&pnd->tx_lock);
> +	pnd->tx_queue--;
> +	netif_wake_queue(dev);
> +	spin_unlock(&pnd->tx_lock);
> +
> +	dev_kfree_skb_any(skb);
> +	usb_free_urb(req);
> +}
> +
> +static int rx_submit(struct usbpn_dev *pnd, struct urb *req, gfp_t gfp_flags)
> +{
> +	struct net_device *dev = pnd->dev;
> +	struct page *page;
> +	int err;
> +
> +	page = __netdev_alloc_page(dev, gfp_flags);
> +	if (!page)
> +		return -ENOMEM;
> +
> +	usb_fill_bulk_urb(req, pnd->usb, pnd->rx_pipe, page_address(page),
> +				PAGE_SIZE, rx_complete, dev);
> +	req->transfer_flags = 0;
> +	err = usb_submit_urb(req, gfp_flags);
> +	if (unlikely(err)) {
> +		dev_dbg(&dev->dev, "RX submit error (%d)\n", err);
> +		netdev_free_page(dev, page);
> +	}
> +	return err;
> +}
> +
> +static void rx_complete(struct urb *req)
> +{
> +	struct net_device *dev = req->context;
> +	struct usbpn_dev *pnd = netdev_priv(dev);
> +	struct page *page = virt_to_page(req->transfer_buffer);
> +	struct sk_buff *skb;
> +	unsigned long flags;
> +
> +	switch (req->status) {
> +	case 0:
> +		spin_lock_irqsave(&pnd->rx_lock, flags);
> +		skb = pnd->rx_skb;
> +		if (!skb) {
> +			skb = pnd->rx_skb = netdev_alloc_skb(dev, 12);
> +			if (likely(skb)) {
> +				/* Can't use pskb_pull() on page in IRQ */
> +				memcpy(skb_put(skb, 1), page_address(page), 1);
> +				skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
> +						page, 1, req->actual_length);
> +				page = NULL;
> +			}
> +		} else {
> +			skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
> +					page, 0, req->actual_length);
> +			page = NULL;
> +		}
> +		if (req->actual_length < PAGE_SIZE)
> +			pnd->rx_skb = NULL; /* Last fragment */
> +		else
> +			skb = NULL;
> +		spin_unlock_irqrestore(&pnd->rx_lock, flags);
> +		if (skb) {
> +			skb->protocol = htons(ETH_P_PHONET);
> +			skb_reset_mac_header(skb);
> +			__skb_pull(skb, 1);
> +			skb->dev = dev;
> +			dev->stats.rx_packets++;
> +			dev->stats.rx_bytes += skb->len;
> +
> +			netif_rx(skb);
> +		}
> +		goto resubmit;
> +
> +	case -ENOENT:
> +	case -ECONNRESET:
> +	case -ESHUTDOWN:
> +		req = NULL;
> +		break;
> +
> +	case -EOVERFLOW:
> +		dev->stats.rx_over_errors++;
> +		dev_dbg(&dev->dev, "RX overflow\n");
> +		break;
> +
> +	case -EILSEQ:
> +		dev->stats.rx_crc_errors++;
> +		break;
> +	}
> +
> +	dev->stats.rx_errors++;
> +resubmit:
> +	if (page)
> +		netdev_free_page(dev, page);
> +	if (req)
> +		rx_submit(pnd, req, GFP_ATOMIC);
> +}
> +
> +static int usbpn_close(struct net_device *dev);
> +
> +static int usbpn_open(struct net_device *dev)
> +{
> +	struct usbpn_dev *pnd = netdev_priv(dev);
> +	int err;
> +	unsigned i;
> +	unsigned num = pnd->data_intf->cur_altsetting->desc.bInterfaceNumber;
> +
> +	err = usb_set_interface(pnd->usb, num, pnd->active_setting);
> +	if (err)
> +		return err;
> +
> +	for (i = 0; i < rxq_size; i++) {
> +		struct urb *req = usb_alloc_urb(0, GFP_KERNEL);
> +
> +		if (!req || rx_submit(pnd, req, GFP_KERNEL)) {
> +			usbpn_close(dev);
> +			return -ENOMEM;
> +		}
> +		pnd->urbs[i] = req;
> +	}
> +
> +	netif_wake_queue(dev);
> +	return 0;
> +}
> +
> +static int usbpn_close(struct net_device *dev)
> +{
> +	struct usbpn_dev *pnd = netdev_priv(dev);
> +	unsigned i;
> +	unsigned num = pnd->data_intf->cur_altsetting->desc.bInterfaceNumber;
> +
> +	netif_stop_queue(dev);
> +
> +	for (i = 0; i < rxq_size; i++) {
> +		struct urb *req = pnd->urbs[i];
> +
> +		if (!req)
> +			continue;
> +		usb_kill_urb(req);
> +		usb_free_urb(req);
> +		pnd->urbs[i] = NULL;
> +	}
> +
> +	return usb_set_interface(pnd->usb, num, !pnd->active_setting);
> +}
> +
> +static int usbpn_set_mtu(struct net_device *dev, int new_mtu)
> +{
> +	if ((new_mtu < PHONET_MIN_MTU) || (new_mtu > PHONET_MAX_MTU))
> +		return -EINVAL;
> +
> +	dev->mtu = new_mtu;
> +	return 0;
> +}
> +
> +static const struct net_device_ops usbpn_ops = {
> +	.ndo_open	= usbpn_open,
> +	.ndo_stop	= usbpn_close,
> +	.ndo_start_xmit = usbpn_xmit,
> +	.ndo_change_mtu = usbpn_set_mtu,
> +};
> +
> +static void usbpn_setup(struct net_device *dev)
> +{
> +	dev->features		= 0;
> +	dev->netdev_ops		= &usbpn_ops,
> +	dev->header_ops		= &phonet_header_ops;
> +	dev->type		= ARPHRD_PHONET;
> +	dev->flags		= IFF_POINTOPOINT | IFF_NOARP;
> +	dev->mtu		= PHONET_MAX_MTU;
> +	dev->hard_header_len	= 1;
> +	dev->dev_addr[0]	= PN_MEDIA_USB;
> +	dev->addr_len		= 1;
> +	dev->tx_queue_len	= 3;
> +
> +	dev->destructor		= free_netdev;
> +}
> +
> +/*
> + * USB driver callbacks
> + */
> +static struct usb_device_id usbpn_ids[] = {
> +	{
> +		.match_flags = USB_DEVICE_ID_MATCH_VENDOR
> +			| USB_DEVICE_ID_MATCH_INT_CLASS
> +			| USB_DEVICE_ID_MATCH_INT_SUBCLASS,
> +		.idVendor = 0x0421, /* Nokia */
> +		.bInterfaceClass = USB_CLASS_COMM,
> +		.bInterfaceSubClass = 0xFE,
> +	},
> +	{ },
> +};
> +
> +MODULE_DEVICE_TABLE(usb, usbpn_ids);
> +
> +static struct usb_driver usbpn_driver;
> +
> +int usbpn_probe(struct usb_interface *intf, const struct usb_device_id *id)
> +{
> +	static const char ifname[] = "usbpn%d";
> +	const struct usb_cdc_union_desc *union_header = NULL;
> +	const struct usb_cdc_header_desc *phonet_header = NULL;
> +	const struct usb_host_interface *data_desc;
> +	struct usb_interface *data_intf;
> +	struct usb_device *usbdev = interface_to_usbdev(intf);
> +	struct net_device *dev;
> +	struct usbpn_dev *pnd;
> +	u8 *data;
> +	int len, err;
> +
> +	data = intf->altsetting->extra;
> +	len = intf->altsetting->extralen;
> +	while (len >= 3) {
> +		u8 dlen = data[0];
> +		if (dlen < 3)
> +			return -EINVAL;
> +
> +		/* bDescriptorType */
> +		if (data[1] == USB_DT_CS_INTERFACE) {
> +			/* bDescriptorSubType */
> +			switch (data[2]) {
> +			case USB_CDC_UNION_TYPE:
> +				if (union_header || dlen < 5)
> +					break;
> +				union_header =
> +					(struct usb_cdc_union_desc *)data;
> +				break;
> +			case 0xAB:
> +				if (phonet_header || dlen < 5)
> +					break;
> +				phonet_header =
> +					(struct usb_cdc_header_desc *)data;
> +				break;
> +			}
> +		}
> +		data += dlen;
> +		len -= dlen;
> +	}
> +
> +	if (!union_header || !phonet_header)
> +		return -EINVAL;
> +
> +	data_intf = usb_ifnum_to_if(usbdev, union_header->bSlaveInterface0);
> +	if (data_intf == NULL)
> +		return -ENODEV;
> +	/* Data interface has one inactive and one active setting */
> +	if (data_intf->num_altsetting != 2)
> +		return -EINVAL;
> +	if (data_intf->altsetting[0].desc.bNumEndpoints == 0
> +	 && data_intf->altsetting[1].desc.bNumEndpoints == 2)
> +		data_desc = data_intf->altsetting + 1;
> +	else
> +	if (data_intf->altsetting[0].desc.bNumEndpoints == 2
> +	 && data_intf->altsetting[1].desc.bNumEndpoints == 0)
> +		data_desc = data_intf->altsetting;
> +	else
> +		return -EINVAL;
> +
> +	dev = alloc_netdev(sizeof(*pnd) + sizeof(pnd->urbs[0]) * rxq_size,
> +				ifname, usbpn_setup);
> +	if (!dev)
> +		return -ENOMEM;
> +
> +	pnd = netdev_priv(dev);
> +	SET_NETDEV_DEV(dev, &intf->dev);
> +	netif_stop_queue(dev);
> +
> +	pnd->dev = dev;
> +	pnd->usb = usb_get_dev(usbdev);
> +	pnd->intf = intf;
> +	pnd->data_intf = data_intf;
> +	spin_lock_init(&pnd->tx_lock);
> +	spin_lock_init(&pnd->rx_lock);
> +	/* Endpoints */
> +	if (usb_pipein(data_desc->endpoint[0].desc.bEndpointAddress)) {
> +		pnd->rx_pipe = usb_rcvbulkpipe(usbdev,
> +			data_desc->endpoint[0].desc.bEndpointAddress);
> +		pnd->tx_pipe = usb_sndbulkpipe(usbdev,
> +			data_desc->endpoint[1].desc.bEndpointAddress);
> +	} else {
> +		pnd->rx_pipe = usb_rcvbulkpipe(usbdev,
> +			data_desc->endpoint[1].desc.bEndpointAddress);
> +		pnd->tx_pipe = usb_sndbulkpipe(usbdev,
> +			data_desc->endpoint[0].desc.bEndpointAddress);
> +	}
> +	pnd->active_setting = data_desc - data_intf->altsetting;
> +
> +	err = usb_driver_claim_interface(&usbpn_driver, data_intf, pnd);
> +	if (err)
> +		goto out;
> +
> +	/* Force inactive mode until the network device is brought UP */
> +	usb_set_interface(usbdev, union_header->bSlaveInterface0,
> +				!pnd->active_setting);
> +	usb_set_intfdata(intf, pnd);
> +
> +	err = register_netdev(dev);
> +	if (err) {
> +		usb_driver_release_interface(&usbpn_driver, data_intf);
> +		goto out;
> +	}
> +
> +	dev_dbg(&dev->dev, "USB CDC Phonet device found\n");
> +	return 0;
> +
> +out:
> +	usb_set_intfdata(intf, NULL);
> +	free_netdev(dev);
> +	return err;
> +}
> +
> +static void usbpn_disconnect(struct usb_interface *intf)
> +{
> +	struct usbpn_dev *pnd = usb_get_intfdata(intf);
> +	struct usb_device *usb = pnd->usb;
> +
> +	if (pnd->disconnected)
> +		return;
> +
> +	pnd->disconnected = 1;
> +	usb_driver_release_interface(&usbpn_driver,
> +			(pnd->intf == intf) ? pnd->data_intf : pnd->intf);
> +	unregister_netdev(pnd->dev);
> +	usb_put_dev(usb);
> +}
> +
> +static struct usb_driver usbpn_driver = {
> +	.name =		"cdc_phonet",
> +	.probe =	usbpn_probe,
> +	.disconnect =	usbpn_disconnect,
> +	.id_table =	usbpn_ids,
> +};
> +
> +static int __init usbpn_init(void)
> +{
> +	return usb_register(&usbpn_driver);
> +}
> +
> +static void __exit usbpn_exit(void)
> +{
> +	usb_deregister(&usbpn_driver);
> +}
> +
> +module_init(usbpn_init);
> +module_exit(usbpn_exit);
> +
> +MODULE_AUTHOR("Remi Denis-Courmont");
> +MODULE_DESCRIPTION("USB CDC Phonet host interface");
> +MODULE_LICENSE("GPL");


^ permalink raw reply

* Re: [Qemu-devel] [PATCH] net: add raw backend  - some performance measurements
From: Or Gerlitz @ 2009-07-21 13:41 UTC (permalink / raw)
  To: Herbert Xu
  Cc: Michael S. Tsirkin, Jamie Lokier, Anthony Liguori, qemu-devel,
	Jan Kiszka, Mark McLoughlin, Dor Laor, netdev
In-Reply-To: <20090721121420.GA19236@gondor.apana.org.au>

Herbert Xu wrote:
> On Tue, Jul 21, 2009 at 03:01:42PM +0300, Michael S. Tsirkin wrote:

>> the thing to check then would be that some kind of misconfiguration
>> does not cause the bridge to flood your packets to multiple interfaces.

> Right, we should make sure that the interfaces are not in promiscous mode

Michael, Herbert, 

First, I don't see how flooding can happen in my setup, I have only two interfaces on 
the bridge (see below), a tap and a NIC (vlan) and the bridge will never attempt to forward
a packet through the port it was received. Second, the bridge always set all interfaces
attached to it to be in promiscous mode, see the call to dev_set_promiscuity() from br_add_if()
but this doesn't mean it applied flooding, it does mac learning...

Or.

# brctl show
bridge name     bridge id               STP enabled     interfaces
br0             8000.0030485f9977       no              eth1.4009
                                                        tap0

The VM mac is de:ab:be:01:01:09 and the remote node mac is 00:30:48:65:a6:2b, you 
can see that these two macs were learned by the bridge and hence no flooding is expected.

# brctl showmacs br0
port no mac addr                is local?       ageing timer
  1     00:30:48:5f:99:77       yes                0.00
  1     00:30:48:65:a6:2b       no                12.50
  2     06:f5:76:64:a0:d4       yes                0.00
  2     de:ab:be:01:01:09       no                 0.00

^ permalink raw reply

* Re: [Qemu-devel] [PATCH] net: add raw backend  - some performance measurements
From: Herbert Xu @ 2009-07-21 12:14 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: Or Gerlitz, Jamie Lokier, Anthony Liguori, qemu-devel, Jan Kiszka,
	Mark McLoughlin, Dor Laor, netdev
In-Reply-To: <20090721120142.GA23439@redhat.com>

On Tue, Jul 21, 2009 at 03:01:42PM +0300, Michael S. Tsirkin wrote:
>
> the thing to check then would be that some kind of misconfiguration
> does not cause the bridge to flood your packets to multiple interfaces.

Right, we should make sure that the interfaces are not in promiscous
mode.

Cheers,
-- 
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply

* [net-next-2.6 PATCH][be2net] Add GRO support to the be2net driver. LRO is not supported anymore.
From: Ajit Khaparde @ 2009-07-21 12:07 UTC (permalink / raw)
  To: David Miller; +Cc: netdev


This patch removes support for INET_LRO and switches over to GRO.
Please accept.

-Ajit

Signed-off-by: Ajit Khaparde <ajitk@serverengines.com>
---
 drivers/net/benet/Kconfig      |    1 -
 drivers/net/benet/be.h         |   11 +----
 drivers/net/benet/be_ethtool.c |    9 +---
 drivers/net/benet/be_main.c    |  104 +++++++++++-----------------------------
 4 files changed, 31 insertions(+), 94 deletions(-)

diff --git a/drivers/net/benet/Kconfig b/drivers/net/benet/Kconfig
index c6934f1..fdb6e81 100644
--- a/drivers/net/benet/Kconfig
+++ b/drivers/net/benet/Kconfig
@@ -1,7 +1,6 @@
 config BE2NET
 	tristate "ServerEngines' 10Gbps NIC - BladeEngine 2"
 	depends on PCI && INET
-	select INET_LRO
 	help
 	This driver implements the NIC functionality for ServerEngines'
 	10Gbps network adapter - BladeEngine 2.
diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h
index 5b4bf3d..41cddbe 100644
--- a/drivers/net/benet/be.h
+++ b/drivers/net/benet/be.h
@@ -28,11 +28,10 @@
 #include <linux/if_vlan.h>
 #include <linux/workqueue.h>
 #include <linux/interrupt.h>
-#include <linux/inet_lro.h>
 
 #include "be_hw.h"
 
-#define DRV_VER			"2.0.348"
+#define DRV_VER			"2.0.400"
 #define DRV_NAME		"be2net"
 #define BE_NAME			"ServerEngines BladeEngine2 10Gbps NIC"
 #define OC_NAME			"Emulex OneConnect 10Gbps NIC"
@@ -72,9 +71,6 @@ static inline char *nic_name(struct pci_dev *pdev)
 #define MAX_RX_POST 		BE_NAPI_WEIGHT /* Frags posted at a time */
 #define RX_FRAGS_REFILL_WM	(RX_Q_LEN - MAX_RX_POST)
 
-#define BE_MAX_LRO_DESCRIPTORS  16
-#define BE_MAX_FRAGS_PER_FRAME  (min((u32) 16, (u32) MAX_SKB_FRAGS))
-
 struct be_dma_mem {
 	void *va;
 	dma_addr_t dma;
@@ -189,8 +185,6 @@ struct be_drvr_stats {
 	u32 be_polls;		/* number of times NAPI called poll function */
 	u32 be_rx_events;	/* number of ucast rx completion events  */
 	u32 be_rx_compl;	/* number of rx completion entries processed */
-	u32 be_lro_hgram_data[8];	/* histogram of LRO data packets */
-	u32 be_lro_hgram_ack[8];	/* histogram of LRO ACKs */
 	ulong be_rx_jiffies;
 	u64 be_rx_bytes;
 	u64 be_rx_bytes_prev;
@@ -233,8 +227,6 @@ struct be_rx_obj {
 	struct be_queue_info q;
 	struct be_queue_info cq;
 	struct be_rx_page_info page_info_tbl[RX_Q_LEN];
-	struct net_lro_mgr lro_mgr;
-	struct net_lro_desc lro_desc[BE_MAX_LRO_DESCRIPTORS];
 };
 
 #define BE_NUM_MSIX_VECTORS		2	/* 1 each for Tx and Rx */
@@ -271,7 +263,6 @@ struct be_adapter {
 
 	/* Ethtool knobs and info */
 	bool rx_csum; 		/* BE card must perform rx-checksumming */
-	u32 max_rx_coal;
 	char fw_ver[FW_VER_LEN];
 	u32 if_handle;		/* Used to configure filtering */
 	u32 pmac_id;		/* MAC addr handle used by BE card */
diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c
index cccc541..f3f0f91 100644
--- a/drivers/net/benet/be_ethtool.c
+++ b/drivers/net/benet/be_ethtool.c
@@ -127,8 +127,6 @@ be_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
 	struct be_eq_obj *rx_eq = &adapter->rx_eq;
 	struct be_eq_obj *tx_eq = &adapter->tx_eq;
 
-	coalesce->rx_max_coalesced_frames = adapter->max_rx_coal;
-
 	coalesce->rx_coalesce_usecs = rx_eq->cur_eqd;
 	coalesce->rx_coalesce_usecs_high = rx_eq->max_eqd;
 	coalesce->rx_coalesce_usecs_low = rx_eq->min_eqd;
@@ -144,8 +142,7 @@ be_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
 }
 
 /*
- * This routine is used to set interrup coalescing delay *as well as*
- * the number of pkts to coalesce for LRO.
+ * This routine is used to set interrup coalescing delay
  */
 static int
 be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
@@ -161,10 +158,6 @@ be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
 	if (coalesce->use_adaptive_tx_coalesce == 1)
 		return -EINVAL;
 
-	adapter->max_rx_coal = coalesce->rx_max_coalesced_frames;
-	if (adapter->max_rx_coal > BE_MAX_FRAGS_PER_FRAME)
-		adapter->max_rx_coal = BE_MAX_FRAGS_PER_FRAME;
-
 	/* if AIC is being turned on now, start with an EQD of 0 */
 	if (rx_eq->enable_aic == 0 &&
 		coalesce->use_adaptive_rx_coalesce == 1) {
diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c
index c43f6a1..45df8e2 100644
--- a/drivers/net/benet/be_main.c
+++ b/drivers/net/benet/be_main.c
@@ -742,7 +742,7 @@ done:
 	return;
 }
 
-/* Process the RX completion indicated by rxcp when LRO is disabled */
+/* Process the RX completion indicated by rxcp when GRO is disabled */
 static void be_rx_compl_process(struct be_adapter *adapter,
 			struct be_eth_rx_compl *rxcp)
 {
@@ -789,13 +789,14 @@ static void be_rx_compl_process(struct be_adapter *adapter,
 	return;
 }
 
-/* Process the RX completion indicated by rxcp when LRO is enabled */
-static void be_rx_compl_process_lro(struct be_adapter *adapter,
+/* Process the RX completion indicated by rxcp when GRO is enabled */
+static void be_rx_compl_process_gro(struct be_adapter *adapter,
 			struct be_eth_rx_compl *rxcp)
 {
 	struct be_rx_page_info *page_info;
-	struct skb_frag_struct rx_frags[BE_MAX_FRAGS_PER_FRAME];
+	struct sk_buff *skb = NULL;
 	struct be_queue_info *rxq = &adapter->rx_obj.q;
+	struct be_eq_obj *eq_obj =  &adapter->rx_eq;
 	u32 num_rcvd, pkt_size, remaining, vlanf, curr_frag_len;
 	u16 i, rxq_idx = 0, vid, j;
 
@@ -804,6 +805,12 @@ static void be_rx_compl_process_lro(struct be_adapter *adapter,
 	vlanf = AMAP_GET_BITS(struct amap_eth_rx_compl, vtp, rxcp);
 	rxq_idx = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx, rxcp);
 
+	skb = napi_get_frags(&eq_obj->napi);
+	if (!skb) {
+		be_rx_compl_discard(adapter, rxcp);
+		return;
+	}
+
 	remaining = pkt_size;
 	for (i = 0, j = -1; i < num_rcvd; i++) {
 		page_info = get_rx_page_info(adapter, rxq_idx);
@@ -814,13 +821,14 @@ static void be_rx_compl_process_lro(struct be_adapter *adapter,
 		if (i == 0 || page_info->page_offset == 0) {
 			/* First frag or Fresh page */
 			j++;
-			rx_frags[j].page = page_info->page;
-			rx_frags[j].page_offset = page_info->page_offset;
-			rx_frags[j].size = 0;
+			skb_shinfo(skb)->frags[j].page = page_info->page;
+			skb_shinfo(skb)->frags[j].page_offset =
+							page_info->page_offset;
+			skb_shinfo(skb)->frags[j].size = 0;
 		} else {
 			put_page(page_info->page);
 		}
-		rx_frags[j].size += curr_frag_len;
+		skb_shinfo(skb)->frags[j].size += curr_frag_len;
 
 		remaining -= curr_frag_len;
 		index_inc(&rxq_idx, rxq->len);
@@ -828,9 +836,14 @@ static void be_rx_compl_process_lro(struct be_adapter *adapter,
 	}
 	BUG_ON(j > MAX_SKB_FRAGS);
 
+	skb_shinfo(skb)->nr_frags = j + 1;
+	skb->len = pkt_size;
+	skb->data_len = pkt_size;
+	skb->truesize += pkt_size;
+	skb->ip_summed = CHECKSUM_UNNECESSARY;
+
 	if (likely(!vlanf)) {
-		lro_receive_frags(&adapter->rx_obj.lro_mgr, rx_frags, pkt_size,
-				pkt_size, NULL, 0);
+		napi_gro_frags(&eq_obj->napi);
 	} else {
 		vid = AMAP_GET_BITS(struct amap_eth_rx_compl, vlan_tag, rxcp);
 		vid = be16_to_cpu(vid);
@@ -838,9 +851,7 @@ static void be_rx_compl_process_lro(struct be_adapter *adapter,
 		if (!adapter->vlan_grp || adapter->num_vlans == 0)
 			return;
 
-		lro_vlan_hwaccel_receive_frags(&adapter->rx_obj.lro_mgr,
-			rx_frags, pkt_size, pkt_size, adapter->vlan_grp,
-			vid, NULL, 0);
+		vlan_gro_frags(&eq_obj->napi, adapter->vlan_grp, vid);
 	}
 
 	be_rx_stats_update(adapter, pkt_size, num_rcvd);
@@ -1183,7 +1194,6 @@ static int be_rx_queues_create(struct be_adapter *adapter)
 	struct be_queue_info *eq, *q, *cq;
 	int rc;
 
-	adapter->max_rx_coal = BE_MAX_FRAGS_PER_FRAME;
 	adapter->big_page_size = (1 << get_order(rx_frag_size)) * PAGE_SIZE;
 	adapter->rx_eq.max_eqd = BE_MAX_EQD;
 	adapter->rx_eq.min_eqd = 0;
@@ -1305,7 +1315,7 @@ static irqreturn_t be_msix_tx_mcc(int irq, void *dev)
 	return IRQ_HANDLED;
 }
 
-static inline bool do_lro(struct be_adapter *adapter,
+static inline bool do_gro(struct be_adapter *adapter,
 			struct be_eth_rx_compl *rxcp)
 {
 	int err = AMAP_GET_BITS(struct amap_eth_rx_compl, err, rxcp);
@@ -1314,8 +1324,7 @@ static inline bool do_lro(struct be_adapter *adapter,
 	if (err)
 		drvr_stats(adapter)->be_rxcp_err++;
 
-	return (!tcp_frame || err || (adapter->max_rx_coal <= 1)) ?
-		false : true;
+	return (tcp_frame && !err) ? true : false;
 }
 
 int be_poll_rx(struct napi_struct *napi, int budget)
@@ -1332,16 +1341,14 @@ int be_poll_rx(struct napi_struct *napi, int budget)
 		if (!rxcp)
 			break;
 
-		if (do_lro(adapter, rxcp))
-			be_rx_compl_process_lro(adapter, rxcp);
+		if (do_gro(adapter, rxcp))
+			be_rx_compl_process_gro(adapter, rxcp);
 		else
 			be_rx_compl_process(adapter, rxcp);
 
 		be_rx_compl_reset(rxcp);
 	}
 
-	lro_flush_all(&adapter->rx_obj.lro_mgr);
-
 	/* Refill the queue */
 	if (atomic_read(&adapter->rx_obj.q.used) < RX_FRAGS_REFILL_WM)
 		be_post_rx_frags(adapter);
@@ -1656,57 +1663,6 @@ static int be_close(struct net_device *netdev)
 	return 0;
 }
 
-static int be_get_frag_header(struct skb_frag_struct *frag, void **mac_hdr,
-				void **ip_hdr, void **tcpudp_hdr,
-				u64 *hdr_flags, void *priv)
-{
-	struct ethhdr *eh;
-	struct vlan_ethhdr *veh;
-	struct iphdr *iph;
-	u8 *va = page_address(frag->page) + frag->page_offset;
-	unsigned long ll_hlen;
-
-	prefetch(va);
-	eh = (struct ethhdr *)va;
-	*mac_hdr = eh;
-	ll_hlen = ETH_HLEN;
-	if (eh->h_proto != htons(ETH_P_IP)) {
-		if (eh->h_proto == htons(ETH_P_8021Q)) {
-			veh = (struct vlan_ethhdr *)va;
-			if (veh->h_vlan_encapsulated_proto != htons(ETH_P_IP))
-				return -1;
-
-			ll_hlen += VLAN_HLEN;
-		} else {
-			return -1;
-		}
-	}
-	*hdr_flags = LRO_IPV4;
-	iph = (struct iphdr *)(va + ll_hlen);
-	*ip_hdr = iph;
-	if (iph->protocol != IPPROTO_TCP)
-		return -1;
-	*hdr_flags |= LRO_TCP;
-	*tcpudp_hdr = (u8 *) (*ip_hdr) + (iph->ihl << 2);
-
-	return 0;
-}
-
-static void be_lro_init(struct be_adapter *adapter, struct net_device *netdev)
-{
-	struct net_lro_mgr *lro_mgr;
-
-	lro_mgr = &adapter->rx_obj.lro_mgr;
-	lro_mgr->dev = netdev;
-	lro_mgr->features = LRO_F_NAPI;
-	lro_mgr->ip_summed = CHECKSUM_UNNECESSARY;
-	lro_mgr->ip_summed_aggr = CHECKSUM_UNNECESSARY;
-	lro_mgr->max_desc = BE_MAX_LRO_DESCRIPTORS;
-	lro_mgr->lro_arr = adapter->rx_obj.lro_desc;
-	lro_mgr->get_frag_header = be_get_frag_header;
-	lro_mgr->max_aggr = BE_MAX_FRAGS_PER_FRAME;
-}
-
 static struct net_device_ops be_netdev_ops = {
 	.ndo_open		= be_open,
 	.ndo_stop		= be_close,
@@ -1727,7 +1683,7 @@ static void be_netdev_init(struct net_device *netdev)
 
 	netdev->features |= NETIF_F_SG | NETIF_F_HW_VLAN_RX | NETIF_F_TSO |
 		NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER | NETIF_F_IP_CSUM |
-		NETIF_F_IPV6_CSUM;
+		NETIF_F_IPV6_CSUM | NETIF_F_GRO;
 
 	netdev->flags |= IFF_MULTICAST;
 
@@ -1737,8 +1693,6 @@ static void be_netdev_init(struct net_device *netdev)
 
 	SET_ETHTOOL_OPS(netdev, &be_ethtool_ops);
 
-	be_lro_init(adapter, netdev);
-
 	netif_napi_add(netdev, &adapter->rx_eq.napi, be_poll_rx,
 		BE_NAPI_WEIGHT);
 	netif_napi_add(netdev, &adapter->tx_eq.napi, be_poll_tx_mcc,
-- 
1.6.0.4


^ permalink raw reply related

* Bonanza
From: Werley David @ 2009-07-21 12:04 UTC (permalink / raw)
  To: info

950.000.00 GBP has been award to you in LG Eletronics promo. Send your details.
Name:.....
Address:...
Country:......


^ permalink raw reply

* Bonanza
From: Werley David @ 2009-07-21 12:04 UTC (permalink / raw)
  To: info

950.000.00 GBP has been award to you in LG Eletronics promo. Send your details.
Name:.....
Address:...
Country:......


^ permalink raw reply

* Bonanza
From: Werley David @ 2009-07-21 12:04 UTC (permalink / raw)
  To: info

950.000.00 GBP has been award to you in LG Eletronics promo. Send your details.
Name:.....
Address:...
Country:......


^ permalink raw reply

* Bonanza
From: Werley David @ 2009-07-21 12:04 UTC (permalink / raw)
  To: info

950.000.00 GBP has been award to you in LG Eletronics promo. Send your details.
Name:.....
Address:...
Country:......


^ permalink raw reply

* Bonanza
From: Werley David @ 2009-07-21 12:04 UTC (permalink / raw)
  To: info

950.000.00 GBP has been award to you in LG Eletronics promo. Send your details.
Name:.....
Address:...
Country:......


^ permalink raw reply

* Bonanza
From: Werley David @ 2009-07-21 12:04 UTC (permalink / raw)
  To: info

950.000.00 GBP has been award to you in LG Eletronics promo. Send your details.
Name:.....
Address:...
Country:......


^ permalink raw reply

* Re: [Qemu-devel] [PATCH] net: add raw backend  - some performance measurements
From: Michael S. Tsirkin @ 2009-07-21 12:01 UTC (permalink / raw)
  To: Or Gerlitz
  Cc: Herbert Xu, Jamie Lokier, Anthony Liguori, qemu-devel, Jan Kiszka,
	Mark McLoughlin, Dor Laor, netdev
In-Reply-To: <4A65A0FC.6090204@Voltaire.com>

On Tue, Jul 21, 2009 at 02:05:32PM +0300, Or Gerlitz wrote:
> Michael S. Tsirkin wrote:
> > With raw sockets, send will block or fail if the TX queue for device is
> > full. With tap+bridge, the buffer in tap has to fill up instead, which
> > is not the same. I'm not sure this is the issue here, but could be: the
> > benchmark is UDP, isn't it?
> 
> Michael, 
> 
> What/where is this tap buffer?
> we're talking on VM TX, so looking on tun_get_user I see a call to 
> skb_copy_datagram_from_iovec() to copy from the user buffer to an skb, then a call to netif_rx_ni() and that's it... As for your question, indeed udp, the VM runs netperf/UDP_STREAM
> 
> Or.

Queue is not the right word, sorry.

I was referring to the fact that, when bridge floods a packet to
multiple interfaces, it clones the skb and frees the original, which
breaks the send buffer accounting in tun and might let you overrun the
tx queue in one of the devices.  This does not usually happen with raw
sockets.  This is the code in question:

                        if (prev != NULL) {
                                struct sk_buff *skb2;

                                if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) {
                                        br->dev->stats.tx_dropped++;
                                        kfree_skb(skb);
                                        return;
                                }

                                __packet_hook(prev, skb2);
                        }

the thing to check then would be that some kind of misconfiguration
does not cause the bridge to flood your packets to multiple interfaces.

-- 
MST

^ permalink raw reply

* [PATCH] USB host CDC Phonet network interface driver
From: Rémi Denis-Courmont @ 2009-07-21 11:58 UTC (permalink / raw)
  To: netdev; +Cc: linux-usb

From: Rémi Denis-Courmont <remi.denis-courmont@nokia.com>

Many Nokia handsets support a Phonet interface to the cellular modem
via a vendor-specific USB interface. CDC Phonet follows the
Communications Device Class model, with one control interface, and
and a pair of inactive and active data alternative interface. The later
has two bulk endpoint, one per direction.

This was tested against Nokia E61, Nokia N95, and the existing Phonet
gadget function for the Linux composite USB gadget framework.

Signed-off-by: Rémi Denis-Courmont <remi.denis-courmont@nokia.com>
---
 drivers/net/usb/Kconfig      |    8 +
 drivers/net/usb/Makefile     |    1 +
 drivers/net/usb/cdc-phonet.c |  461 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 470 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/usb/cdc-phonet.c

diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index a906d39..c47237c 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -369,4 +369,12 @@ config USB_NET_INT51X1
 	  (Powerline Communications) solution with an Intellon
 	  INT51x1/INT5200 chip, like the "devolo dLan duo".
 
+config USB_CDC_PHONET
+	tristate "CDC Phonet support"
+	depends on PHONET
+	help
+	  Choose this option to support the Phonet interface to a Nokia
+	  cellular modem, as found on most Nokia handsets with the
+	  "PC suite" USB profile.
+
 endmenu
diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile
index b870b0b..e17afb7 100644
--- a/drivers/net/usb/Makefile
+++ b/drivers/net/usb/Makefile
@@ -21,4 +21,5 @@ obj-$(CONFIG_USB_NET_ZAURUS)	+= zaurus.o
 obj-$(CONFIG_USB_NET_MCS7830)	+= mcs7830.o
 obj-$(CONFIG_USB_USBNET)	+= usbnet.o
 obj-$(CONFIG_USB_NET_INT51X1)	+= int51x1.o
+obj-$(CONFIG_USB_CDC_PHONET)	+= cdc-phonet.o
 
diff --git a/drivers/net/usb/cdc-phonet.c b/drivers/net/usb/cdc-phonet.c
new file mode 100644
index 0000000..792af72
--- /dev/null
+++ b/drivers/net/usb/cdc-phonet.c
@@ -0,0 +1,461 @@
+/*
+ * phonet.c -- USB CDC Phonet host driver
+ *
+ * Copyright (C) 2008-2009 Nokia Corporation. All rights reserved.
+ *
+ * Author: Rémi Denis-Courmont
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/cdc.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/if_phonet.h>
+
+#define PN_MEDIA_USB	0x1B
+
+static const unsigned rxq_size = 17;
+
+struct usbpn_dev {
+	struct net_device	*dev;
+
+	struct usb_interface	*intf, *data_intf;
+	struct usb_device	*usb;
+	unsigned int		tx_pipe, rx_pipe;
+	u8 active_setting;
+	u8 disconnected;
+
+	unsigned		tx_queue;
+	spinlock_t		tx_lock;
+
+	spinlock_t		rx_lock;
+	struct sk_buff		*rx_skb;
+	struct urb		*urbs[0];
+};
+
+static void tx_complete(struct urb *req);
+static void rx_complete(struct urb *req);
+
+/*
+ * Network device callbacks
+ */
+static int usbpn_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct usbpn_dev *pnd = netdev_priv(dev);
+	struct urb *req = NULL;
+	unsigned long flags;
+	int err;
+
+	if (skb->protocol != htons(ETH_P_PHONET))
+		goto drop;
+
+	req = usb_alloc_urb(0, GFP_ATOMIC);
+	if (!req)
+		goto drop;
+	usb_fill_bulk_urb(req, pnd->usb, pnd->tx_pipe, skb->data, skb->len,
+				tx_complete, skb);
+	req->transfer_flags = URB_ZERO_PACKET;
+	err = usb_submit_urb(req, GFP_ATOMIC);
+	if (err) {
+		usb_free_urb(req);
+		goto drop;
+	}
+
+	spin_lock_irqsave(&pnd->tx_lock, flags);
+	pnd->tx_queue++;
+	if (pnd->tx_queue >= dev->tx_queue_len)
+		netif_stop_queue(dev);
+	spin_unlock_irqrestore(&pnd->tx_lock, flags);
+	return 0;
+
+drop:
+	dev_kfree_skb(skb);
+	dev->stats.tx_dropped++;
+	return 0;
+}
+
+static void tx_complete(struct urb *req)
+{
+	struct sk_buff *skb = req->context;
+	struct net_device *dev = skb->dev;
+	struct usbpn_dev *pnd = netdev_priv(dev);
+
+	switch (req->status) {
+	case 0:
+		dev->stats.tx_bytes += skb->len;
+		break;
+
+	case -ENOENT:
+	case -ECONNRESET:
+	case -ESHUTDOWN:
+		dev->stats.tx_aborted_errors++;
+	default:
+		dev->stats.tx_errors++;
+		dev_dbg(&dev->dev, "TX error (%d)\n", req->status);
+	}
+	dev->stats.tx_packets++;
+
+	spin_lock(&pnd->tx_lock);
+	pnd->tx_queue--;
+	netif_wake_queue(dev);
+	spin_unlock(&pnd->tx_lock);
+
+	dev_kfree_skb_any(skb);
+	usb_free_urb(req);
+}
+
+static int rx_submit(struct usbpn_dev *pnd, struct urb *req, gfp_t gfp_flags)
+{
+	struct net_device *dev = pnd->dev;
+	struct page *page;
+	int err;
+
+	page = __netdev_alloc_page(dev, gfp_flags);
+	if (!page)
+		return -ENOMEM;
+
+	usb_fill_bulk_urb(req, pnd->usb, pnd->rx_pipe, page_address(page),
+				PAGE_SIZE, rx_complete, dev);
+	req->transfer_flags = 0;
+	err = usb_submit_urb(req, gfp_flags);
+	if (unlikely(err)) {
+		dev_dbg(&dev->dev, "RX submit error (%d)\n", err);
+		netdev_free_page(dev, page);
+	}
+	return err;
+}
+
+static void rx_complete(struct urb *req)
+{
+	struct net_device *dev = req->context;
+	struct usbpn_dev *pnd = netdev_priv(dev);
+	struct page *page = virt_to_page(req->transfer_buffer);
+	struct sk_buff *skb;
+	unsigned long flags;
+
+	switch (req->status) {
+	case 0:
+		spin_lock_irqsave(&pnd->rx_lock, flags);
+		skb = pnd->rx_skb;
+		if (!skb) {
+			skb = pnd->rx_skb = netdev_alloc_skb(dev, 12);
+			if (likely(skb)) {
+				/* Can't use pskb_pull() on page in IRQ */
+				memcpy(skb_put(skb, 1), page_address(page), 1);
+				skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
+						page, 1, req->actual_length);
+				page = NULL;
+			}
+		} else {
+			skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
+					page, 0, req->actual_length);
+			page = NULL;
+		}
+		if (req->actual_length < PAGE_SIZE)
+			pnd->rx_skb = NULL; /* Last fragment */
+		else
+			skb = NULL;
+		spin_unlock_irqrestore(&pnd->rx_lock, flags);
+		if (skb) {
+			skb->protocol = htons(ETH_P_PHONET);
+			skb_reset_mac_header(skb);
+			__skb_pull(skb, 1);
+			skb->dev = dev;
+			dev->stats.rx_packets++;
+			dev->stats.rx_bytes += skb->len;
+
+			netif_rx(skb);
+		}
+		goto resubmit;
+
+	case -ENOENT:
+	case -ECONNRESET:
+	case -ESHUTDOWN:
+		req = NULL;
+		break;
+
+	case -EOVERFLOW:
+		dev->stats.rx_over_errors++;
+		dev_dbg(&dev->dev, "RX overflow\n");
+		break;
+
+	case -EILSEQ:
+		dev->stats.rx_crc_errors++;
+		break;
+	}
+
+	dev->stats.rx_errors++;
+resubmit:
+	if (page)
+		netdev_free_page(dev, page);
+	if (req)
+		rx_submit(pnd, req, GFP_ATOMIC);
+}
+
+static int usbpn_close(struct net_device *dev);
+
+static int usbpn_open(struct net_device *dev)
+{
+	struct usbpn_dev *pnd = netdev_priv(dev);
+	int err;
+	unsigned i;
+	unsigned num = pnd->data_intf->cur_altsetting->desc.bInterfaceNumber;
+
+	err = usb_set_interface(pnd->usb, num, pnd->active_setting);
+	if (err)
+		return err;
+
+	for (i = 0; i < rxq_size; i++) {
+		struct urb *req = usb_alloc_urb(0, GFP_KERNEL);
+
+		if (!req || rx_submit(pnd, req, GFP_KERNEL)) {
+			usbpn_close(dev);
+			return -ENOMEM;
+		}
+		pnd->urbs[i] = req;
+	}
+
+	netif_wake_queue(dev);
+	return 0;
+}
+
+static int usbpn_close(struct net_device *dev)
+{
+	struct usbpn_dev *pnd = netdev_priv(dev);
+	unsigned i;
+	unsigned num = pnd->data_intf->cur_altsetting->desc.bInterfaceNumber;
+
+	netif_stop_queue(dev);
+
+	for (i = 0; i < rxq_size; i++) {
+		struct urb *req = pnd->urbs[i];
+
+		if (!req)
+			continue;
+		usb_kill_urb(req);
+		usb_free_urb(req);
+		pnd->urbs[i] = NULL;
+	}
+
+	return usb_set_interface(pnd->usb, num, !pnd->active_setting);
+}
+
+static int usbpn_set_mtu(struct net_device *dev, int new_mtu)
+{
+	if ((new_mtu < PHONET_MIN_MTU) || (new_mtu > PHONET_MAX_MTU))
+		return -EINVAL;
+
+	dev->mtu = new_mtu;
+	return 0;
+}
+
+static const struct net_device_ops usbpn_ops = {
+	.ndo_open	= usbpn_open,
+	.ndo_stop	= usbpn_close,
+	.ndo_start_xmit = usbpn_xmit,
+	.ndo_change_mtu = usbpn_set_mtu,
+};
+
+static void usbpn_setup(struct net_device *dev)
+{
+	dev->features		= 0;
+	dev->netdev_ops		= &usbpn_ops,
+	dev->header_ops		= &phonet_header_ops;
+	dev->type		= ARPHRD_PHONET;
+	dev->flags		= IFF_POINTOPOINT | IFF_NOARP;
+	dev->mtu		= PHONET_MAX_MTU;
+	dev->hard_header_len	= 1;
+	dev->dev_addr[0]	= PN_MEDIA_USB;
+	dev->addr_len		= 1;
+	dev->tx_queue_len	= 3;
+
+	dev->destructor		= free_netdev;
+}
+
+/*
+ * USB driver callbacks
+ */
+static struct usb_device_id usbpn_ids[] = {
+	{
+		.match_flags = USB_DEVICE_ID_MATCH_VENDOR
+			| USB_DEVICE_ID_MATCH_INT_CLASS
+			| USB_DEVICE_ID_MATCH_INT_SUBCLASS,
+		.idVendor = 0x0421, /* Nokia */
+		.bInterfaceClass = USB_CLASS_COMM,
+		.bInterfaceSubClass = 0xFE,
+	},
+	{ },
+};
+
+MODULE_DEVICE_TABLE(usb, usbpn_ids);
+
+static struct usb_driver usbpn_driver;
+
+int usbpn_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+	static const char ifname[] = "usbpn%d";
+	const struct usb_cdc_union_desc *union_header = NULL;
+	const struct usb_cdc_header_desc *phonet_header = NULL;
+	const struct usb_host_interface *data_desc;
+	struct usb_interface *data_intf;
+	struct usb_device *usbdev = interface_to_usbdev(intf);
+	struct net_device *dev;
+	struct usbpn_dev *pnd;
+	u8 *data;
+	int len, err;
+
+	data = intf->altsetting->extra;
+	len = intf->altsetting->extralen;
+	while (len >= 3) {
+		u8 dlen = data[0];
+		if (dlen < 3)
+			return -EINVAL;
+
+		/* bDescriptorType */
+		if (data[1] == USB_DT_CS_INTERFACE) {
+			/* bDescriptorSubType */
+			switch (data[2]) {
+			case USB_CDC_UNION_TYPE:
+				if (union_header || dlen < 5)
+					break;
+				union_header =
+					(struct usb_cdc_union_desc *)data;
+				break;
+			case 0xAB:
+				if (phonet_header || dlen < 5)
+					break;
+				phonet_header =
+					(struct usb_cdc_header_desc *)data;
+				break;
+			}
+		}
+		data += dlen;
+		len -= dlen;
+	}
+
+	if (!union_header || !phonet_header)
+		return -EINVAL;
+
+	data_intf = usb_ifnum_to_if(usbdev, union_header->bSlaveInterface0);
+	if (data_intf == NULL)
+		return -ENODEV;
+	/* Data interface has one inactive and one active setting */
+	if (data_intf->num_altsetting != 2)
+		return -EINVAL;
+	if (data_intf->altsetting[0].desc.bNumEndpoints == 0
+	 && data_intf->altsetting[1].desc.bNumEndpoints == 2)
+		data_desc = data_intf->altsetting + 1;
+	else
+	if (data_intf->altsetting[0].desc.bNumEndpoints == 2
+	 && data_intf->altsetting[1].desc.bNumEndpoints == 0)
+		data_desc = data_intf->altsetting;
+	else
+		return -EINVAL;
+
+	dev = alloc_netdev(sizeof(*pnd) + sizeof(pnd->urbs[0]) * rxq_size,
+				ifname, usbpn_setup);
+	if (!dev)
+		return -ENOMEM;
+
+	pnd = netdev_priv(dev);
+	SET_NETDEV_DEV(dev, &intf->dev);
+	netif_stop_queue(dev);
+
+	pnd->dev = dev;
+	pnd->usb = usb_get_dev(usbdev);
+	pnd->intf = intf;
+	pnd->data_intf = data_intf;
+	spin_lock_init(&pnd->tx_lock);
+	spin_lock_init(&pnd->rx_lock);
+	/* Endpoints */
+	if (usb_pipein(data_desc->endpoint[0].desc.bEndpointAddress)) {
+		pnd->rx_pipe = usb_rcvbulkpipe(usbdev,
+			data_desc->endpoint[0].desc.bEndpointAddress);
+		pnd->tx_pipe = usb_sndbulkpipe(usbdev,
+			data_desc->endpoint[1].desc.bEndpointAddress);
+	} else {
+		pnd->rx_pipe = usb_rcvbulkpipe(usbdev,
+			data_desc->endpoint[1].desc.bEndpointAddress);
+		pnd->tx_pipe = usb_sndbulkpipe(usbdev,
+			data_desc->endpoint[0].desc.bEndpointAddress);
+	}
+	pnd->active_setting = data_desc - data_intf->altsetting;
+
+	err = usb_driver_claim_interface(&usbpn_driver, data_intf, pnd);
+	if (err)
+		goto out;
+
+	/* Force inactive mode until the network device is brought UP */
+	usb_set_interface(usbdev, union_header->bSlaveInterface0,
+				!pnd->active_setting);
+	usb_set_intfdata(intf, pnd);
+
+	err = register_netdev(dev);
+	if (err) {
+		usb_driver_release_interface(&usbpn_driver, data_intf);
+		goto out;
+	}
+
+	dev_dbg(&dev->dev, "USB CDC Phonet device found\n");
+	return 0;
+
+out:
+	usb_set_intfdata(intf, NULL);
+	free_netdev(dev);
+	return err;
+}
+
+static void usbpn_disconnect(struct usb_interface *intf)
+{
+	struct usbpn_dev *pnd = usb_get_intfdata(intf);
+	struct usb_device *usb = pnd->usb;
+
+	if (pnd->disconnected)
+		return;
+
+	pnd->disconnected = 1;
+	usb_driver_release_interface(&usbpn_driver,
+			(pnd->intf == intf) ? pnd->data_intf : pnd->intf);
+	unregister_netdev(pnd->dev);
+	usb_put_dev(usb);
+}
+
+static struct usb_driver usbpn_driver = {
+	.name =		"cdc_phonet",
+	.probe =	usbpn_probe,
+	.disconnect =	usbpn_disconnect,
+	.id_table =	usbpn_ids,
+};
+
+static int __init usbpn_init(void)
+{
+	return usb_register(&usbpn_driver);
+}
+
+static void __exit usbpn_exit(void)
+{
+	usb_deregister(&usbpn_driver);
+}
+
+module_init(usbpn_init);
+module_exit(usbpn_exit);
+
+MODULE_AUTHOR("Remi Denis-Courmont");
+MODULE_DESCRIPTION("USB CDC Phonet host interface");
+MODULE_LICENSE("GPL");
-- 
1.6.0.4


^ permalink raw reply related

* [PATCH] Phonet: account for dropped RX packets
From: Rémi Denis-Courmont @ 2009-07-21 11:57 UTC (permalink / raw)
  To: netdev
In-Reply-To: <1248177479-12669-2-git-send-email-remi.denis-courmont@nokia.com>

From: Rémi Denis-Courmont <remi.denis-courmont@nokia.com>

Signed-off-by: Rémi Denis-Courmont <remi.denis-courmont@nokia.com>
---
 net/phonet/pep.c |    7 ++++++-
 1 files changed, 6 insertions(+), 1 deletions(-)

diff --git a/net/phonet/pep.c b/net/phonet/pep.c
index eef833e..b8252d2 100644
--- a/net/phonet/pep.c
+++ b/net/phonet/pep.c
@@ -346,8 +346,10 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
 		break;
 
 	case PNS_PEP_CTRL_REQ:
-		if (skb_queue_len(&pn->ctrlreq_queue) >= PNPIPE_CTRLREQ_MAX)
+		if (skb_queue_len(&pn->ctrlreq_queue) >= PNPIPE_CTRLREQ_MAX) {
+			atomic_inc(&sk->sk_drops);
 			break;
+		}
 		__skb_pull(skb, 4);
 		queue = &pn->ctrlreq_queue;
 		goto queue;
@@ -358,10 +360,13 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
 			err = sock_queue_rcv_skb(sk, skb);
 			if (!err)
 				return 0;
+			if (err == -ENOMEM)
+				atomic_inc(&sk->sk_drops);
 			break;
 		}
 
 		if (pn->rx_credits == 0) {
+			atomic_inc(&sk->sk_drops);
 			err = -ENOBUFS;
 			break;
 		}
-- 
1.6.0.4


^ permalink raw reply related

* [PATCH] Phonet: sockets list through proc_fs
From: Rémi Denis-Courmont @ 2009-07-21 11:57 UTC (permalink / raw)
  To: netdev

From: Rémi Denis-Courmont <remi.denis-courmont@nokia.com>

This provides a list of sockets with their Phonet bind addresses and
some socket debug informations through /proc/net/phonet.

Signed-off-by: Rémi Denis-Courmont <remi.denis-courmont@nokia.com>
---
 include/net/phonet/pn_dev.h |    2 +
 net/phonet/pn_dev.c         |    7 +++
 net/phonet/socket.c         |   96 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 105 insertions(+), 0 deletions(-)

diff --git a/include/net/phonet/pn_dev.h b/include/net/phonet/pn_dev.h
index 29d1267..44c923c 100644
--- a/include/net/phonet/pn_dev.h
+++ b/include/net/phonet/pn_dev.h
@@ -49,4 +49,6 @@ void phonet_address_notify(int event, struct net_device *dev, u8 addr);
 
 #define PN_NO_ADDR	0xff
 
+extern const struct file_operations pn_sock_seq_fops;
+
 #endif
diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c
index b0d6ddd..5107b79 100644
--- a/net/phonet/pn_dev.c
+++ b/net/phonet/pn_dev.c
@@ -218,6 +218,11 @@ static int phonet_init_net(struct net *net)
 	if (!pnn)
 		return -ENOMEM;
 
+	if (!proc_net_fops_create(net, "phonet", 0, &pn_sock_seq_fops)) {
+		kfree(pnn);
+		return -ENOMEM;
+	}
+
 	INIT_LIST_HEAD(&pnn->pndevs.list);
 	spin_lock_init(&pnn->pndevs.lock);
 	net_assign_generic(net, phonet_net_id, pnn);
@@ -233,6 +238,8 @@ static void phonet_exit_net(struct net *net)
 	for_each_netdev(net, dev)
 		phonet_device_destroy(dev);
 	rtnl_unlock();
+
+	proc_net_remove(net, "phonet");
 	kfree(pnn);
 }
 
diff --git a/net/phonet/socket.c b/net/phonet/socket.c
index ada2a35..aa1617a 100644
--- a/net/phonet/socket.c
+++ b/net/phonet/socket.c
@@ -412,3 +412,99 @@ found:
 	return 0;
 }
 EXPORT_SYMBOL(pn_sock_get_port);
+
+static struct sock *pn_sock_get_idx(struct seq_file *seq, loff_t pos)
+{
+	struct net *net = seq_file_net(seq);
+	struct hlist_node *node;
+	struct sock *sknode;
+
+	sk_for_each(sknode, node, &pnsocks.hlist) {
+		if (!net_eq(net, sock_net(sknode)))
+			continue;
+		if (!pos)
+			return sknode;
+		pos--;
+	}
+	return NULL;
+}
+
+static struct sock *pn_sock_get_next(struct seq_file *seq, struct sock *sk)
+{
+	struct net *net = seq_file_net(seq);
+
+	do
+		sk = sk_next(sk);
+	while (sk && !net_eq(net, sock_net(sk)));
+
+	return sk;
+}
+
+static void *pn_sock_seq_start(struct seq_file *seq, loff_t *pos)
+	__acquires(pnsocks.lock)
+{
+	spin_lock_bh(&pnsocks.lock);
+	return *pos ? pn_sock_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
+}
+
+static void *pn_sock_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	struct sock *sk;
+
+	if (v == SEQ_START_TOKEN)
+		sk = pn_sock_get_idx(seq, 0);
+	else
+		sk = pn_sock_get_next(seq, v);
+	(*pos)++;
+	return sk;
+}
+
+static void pn_sock_seq_stop(struct seq_file *seq, void *v)
+	__releases(pnsocks.lock)
+{
+	spin_unlock_bh(&pnsocks.lock);
+}
+
+static int pn_sock_seq_show(struct seq_file *seq, void *v)
+{
+	int len;
+
+	if (v == SEQ_START_TOKEN)
+		seq_printf(seq, "%s%n", "pt  loc  rem rs st tx_queue rx_queue "
+			"  uid inode ref pointer drops", &len);
+	else {
+		struct sock *sk = v;
+		struct pn_sock *pn = pn_sk(sk);
+
+		seq_printf(seq, "%2d %04X:%04X:%02X %02X %08X:%08X %5d %lu "
+			"%d %p %d%n",
+			sk->sk_protocol, pn->sobject, 0, pn->resource,
+			sk->sk_state,
+			sk_wmem_alloc_get(sk), sk_rmem_alloc_get(sk),
+			sock_i_uid(sk), sock_i_ino(sk),
+			atomic_read(&sk->sk_refcnt), sk,
+			atomic_read(&sk->sk_drops), &len);
+	}
+	seq_printf(seq, "%*s\n", 127 - len, "");
+	return 0;
+}
+
+static const struct seq_operations pn_sock_seq_ops = {
+	.start = pn_sock_seq_start,
+	.next = pn_sock_seq_next,
+	.stop = pn_sock_seq_stop,
+	.show = pn_sock_seq_show,
+};
+
+static int pn_sock_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &pn_sock_seq_ops);
+}
+
+const struct file_operations pn_sock_seq_fops = {
+	.owner = THIS_MODULE,
+	.open = pn_sock_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release,
+};
-- 
1.6.0.4


^ permalink raw reply related

* [PATCH] Phonet: dropped datagrams accounting
From: Rémi Denis-Courmont @ 2009-07-21 11:57 UTC (permalink / raw)
  To: netdev
In-Reply-To: <1248177479-12669-1-git-send-email-remi.denis-courmont@nokia.com>

From: Rémi Denis-Courmont <remi.denis-courmont@nokia.com>

The per-socket drop count is visible via /proc/net/phonet.

Signed-off-by: Rémi Denis-Courmont <remi.denis-courmont@nokia.com>
---
 net/phonet/datagram.c |    5 ++++-
 1 files changed, 4 insertions(+), 1 deletions(-)

diff --git a/net/phonet/datagram.c b/net/phonet/datagram.c
index e087862..ef5c75c 100644
--- a/net/phonet/datagram.c
+++ b/net/phonet/datagram.c
@@ -159,8 +159,11 @@ out_nofree:
 static int pn_backlog_rcv(struct sock *sk, struct sk_buff *skb)
 {
 	int err = sock_queue_rcv_skb(sk, skb);
-	if (err < 0)
+	if (err < 0) {
 		kfree_skb(skb);
+		if (err == -ENOMEM)
+			atomic_inc(&sk->sk_drops);
+	}
 	return err ? NET_RX_DROP : NET_RX_SUCCESS;
 }
 
-- 
1.6.0.4


^ permalink raw reply related

* Re: [Qemu-devel] [PATCH] net: add raw backend  - some performance measurements
From: Or Gerlitz @ 2009-07-21 11:05 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: Herbert Xu, Jamie Lokier, Anthony Liguori, qemu-devel, Jan Kiszka,
	Mark McLoughlin, Dor Laor, netdev
In-Reply-To: <20090721102733.GB22155@redhat.com>

Michael S. Tsirkin wrote:
> With raw sockets, send will block or fail if the TX queue for device is
> full. With tap+bridge, the buffer in tap has to fill up instead, which
> is not the same. I'm not sure this is the issue here, but could be: the
> benchmark is UDP, isn't it?

Michael, 

What/where is this tap buffer? we're talking on VM TX, so looking on tun_get_user I see a call to 
skb_copy_datagram_from_iovec() to copy from the user buffer to an skb, then a call to netif_rx_ni() and that's it... As for your question, indeed udp, the VM runs netperf/UDP_STREAM

Or.


^ permalink raw reply

* Re: Wireless fails to associate at boot (regression) due to commit 77fdaa12c
From: Johannes Berg @ 2009-07-21 10:49 UTC (permalink / raw)
  To: Mike McCormack; +Cc: netdev
In-Reply-To: <392fb48f0907202254t120ff3cmec885d164dc3344d@mail.gmail.com>

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

On Tue, 2009-07-21 at 14:54 +0900, Mike McCormack wrote:
> Hi Johannes,
> 
> The following commit causes my wireless network not to associate after
> bootup.

Hard to believe, but you're using wireless-testing which is known to be
broken anyway at this point, because John has been on the road and
hasn't merged fixes...

Also wrong mailing list. If you follow wireless-testing, really do use
(and read maybe) the wireless list.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply

* Bonanza
From: Werley David @ 2009-07-21 10:45 UTC (permalink / raw)
  To: info

950.000.00 GBP has been award to you in LG Eletronics promo. Send your details.
Name:.....
Address:...
Country:......


^ permalink raw reply


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