Netdev List
 help / color / mirror / Atom feed
* Re: [net-next-2.6 PATCH 1/7] xfrm: introduce basic mark infrastructure
From: jamal @ 2010-02-22 14:09 UTC (permalink / raw)
  To: David Miller; +Cc: timo.teras, kaber, herbert, netdev
In-Reply-To: <20100221.222612.112587589.davem@davemloft.net>


I will fix both and resubmit. Thanks for taking the time Dave.

cheers,
jamal


^ permalink raw reply

* Re: [PATCH 1/2] can:ti_hecc: Add pm hook-up
From: Wolfgang Grandegger @ 2010-02-22 14:01 UTC (permalink / raw)
  To: Sriramakrishnan; +Cc: socketcan-core, netdev, K R Baalaaji
In-Reply-To: <1266845736-7161-1-git-send-email-srk@ti.com>

Sriramakrishnan wrote:
> Added the suspend and resume implementation in the HECC (CAN)
> driver.
> 
> Signed-off-by: K R Baalaaji <krbaalaaji@ti.com>
> Signed-off-by: Sriramakrishnan <srk@ti.com>
> Acked-by: Anant Gole <anantgole@ti.com>
> ---
>  drivers/net/can/ti_hecc.c |   51 ++++++++++++++++++++++++++++++++++++++++++--
>  1 files changed, 48 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c
> index 5c993c2..df27d82 100644
> --- a/drivers/net/can/ti_hecc.c
> +++ b/drivers/net/can/ti_hecc.c
> @@ -824,7 +824,6 @@ static int ti_hecc_open(struct net_device *ndev)
>  		return err;
>  	}
>  
> -	clk_enable(priv->clk);
>  	ti_hecc_start(ndev);
>  	napi_enable(&priv->napi);
>  	netif_start_queue(ndev);
> @@ -840,7 +839,6 @@ static int ti_hecc_close(struct net_device *ndev)
>  	napi_disable(&priv->napi);
>  	ti_hecc_stop(ndev);
>  	free_irq(ndev->irq, ndev);
> -	clk_disable(priv->clk);
>  	close_candev(ndev);
>  
>  	return 0;
> @@ -925,6 +923,7 @@ static int ti_hecc_probe(struct platform_device *pdev)
>  	netif_napi_add(ndev, &priv->napi, ti_hecc_rx_poll,
>  		HECC_DEF_NAPI_WEIGHT);
>  
> +	clk_enable(priv->clk);
>  	err = register_candev(ndev);
>  	if (err) {
>  		dev_err(&pdev->dev, "register_candev() failed\n");
> @@ -953,6 +952,7 @@ static int __devexit ti_hecc_remove(struct platform_device *pdev)
>  	struct net_device *ndev = platform_get_drvdata(pdev);
>  	struct ti_hecc_priv *priv = netdev_priv(ndev);
>  
> +	clk_disable(priv->clk);
>  	clk_put(priv->clk);
>  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>  	iounmap(priv->base);
> @@ -964,6 +964,48 @@ static int __devexit ti_hecc_remove(struct platform_device *pdev)
>  	return 0;
>  }
>  
> +
> +#ifdef CONFIG_PM
> +static int ti_hecc_suspend(struct platform_device *pdev, pm_message_t state)
> +{
> +	struct net_device *dev = platform_get_drvdata(pdev);
> +	struct ti_hecc_priv *priv = netdev_priv(dev);
> +
> +	if (netif_running(dev)) {
> +		netif_stop_queue(dev);
> +		netif_device_detach(dev);
> +	}
> +
> +	hecc_set_bit(priv, HECC_CANMC, HECC_CANMC_PDR);
> +	priv->can.state = CAN_STATE_SLEEPING;
> +
> +	clk_disable(priv->clk);
> +
> +	return 0;
> +}
> +
> +static int ti_hecc_resume(struct platform_device *pdev)
> +{
> +	struct net_device *dev = platform_get_drvdata(pdev);
> +	struct ti_hecc_priv *priv = netdev_priv(dev);
> +
> +	clk_enable(priv->clk);
> +
> +	hecc_clear_bit(priv, HECC_CANMC, HECC_CANMC_PDR);
> +	priv->can.state = CAN_STATE_ERROR_ACTIVE;
> +
> +	if (netif_running(dev)) {
> +		netif_device_attach(dev);
> +		netif_start_queue(dev);
> +	}
> +
> +	return 0;
> +}
> +#else
> +#define ti_hecc_suspend NULL
> +#define ti_hecc_resume NULL
> +#endif
> +
>  /* TI HECC netdevice driver: platform driver structure */
>  static struct platform_driver ti_hecc_driver = {
>  	.driver = {
> @@ -972,6 +1014,8 @@ static struct platform_driver ti_hecc_driver = {
>  	},
>  	.probe = ti_hecc_probe,
>  	.remove = __devexit_p(ti_hecc_remove),
> +	.suspend = ti_hecc_suspend,
> +	.resume = ti_hecc_resume,
>  };
>  
>  static int __init ti_hecc_init_driver(void)
> @@ -979,14 +1023,15 @@ static int __init ti_hecc_init_driver(void)
>  	printk(KERN_INFO DRV_DESC "\n");
>  	return platform_driver_register(&ti_hecc_driver);
>  }
> -module_init(ti_hecc_init_driver);
>  
>  static void __exit ti_hecc_exit_driver(void)
>  {
>  	printk(KERN_INFO DRV_DESC " unloaded\n");
>  	platform_driver_unregister(&ti_hecc_driver);
>  }
> +
>  module_exit(ti_hecc_exit_driver);
> +module_init(ti_hecc_init_driver);

What is the reason for moving around module_init? Please revert. Then
you can add my "Acked-by: Wolfgang Grandegger <wg@grandegger.com>".

Thanks,

Wolfgang.

^ permalink raw reply

* [PATCH 2/2] can: ti hecc module : add platform specific initialization callback.
From: Sriramakrishnan @ 2010-02-22 13:36 UTC (permalink / raw)
  To: socketcan-core, netdev; +Cc: anantgole, Sriramakrishnan

CAN module on AM3517 requires programming of IO expander as part
of init sequence - to enable CAN PHY. Added platform specific
init callback to handle this.

Signed-off-by: Sriramakrishnan <srk@ti.com>
Acked-by: Anant Gole <anantgole@ti.com>
---
 drivers/net/can/ti_hecc.c            |    3 +++
 include/linux/can/platform/ti_hecc.h |    1 +
 2 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c
index df27d82..604147e 100644
--- a/drivers/net/can/ti_hecc.c
+++ b/drivers/net/can/ti_hecc.c
@@ -865,6 +865,9 @@ static int ti_hecc_probe(struct platform_device *pdev)
 		goto probe_exit;
 	}
 
+	if (pdata->platform_init)
+		pdata->platform_init();
+
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!mem) {
 		dev_err(&pdev->dev, "No mem resources\n");
diff --git a/include/linux/can/platform/ti_hecc.h b/include/linux/can/platform/ti_hecc.h
index 4688c7b..7036612 100644
--- a/include/linux/can/platform/ti_hecc.h
+++ b/include/linux/can/platform/ti_hecc.h
@@ -35,6 +35,7 @@ struct ti_hecc_platform_data {
 	u32 mbx_offset;
 	u32 int_line;
 	u32 version;
+	void (*platform_init) (void);
 };
 
 
-- 
1.6.2.4


^ permalink raw reply related

* [PATCH 1/2] can:ti_hecc: Add pm hook-up
From: Sriramakrishnan @ 2010-02-22 13:35 UTC (permalink / raw)
  To: socketcan-core, netdev; +Cc: anantgole, Sriramakrishnan, K R Baalaaji

Added the suspend and resume implementation in the HECC (CAN)
driver.

Signed-off-by: K R Baalaaji <krbaalaaji@ti.com>
Signed-off-by: Sriramakrishnan <srk@ti.com>
Acked-by: Anant Gole <anantgole@ti.com>
---
 drivers/net/can/ti_hecc.c |   51 ++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 48 insertions(+), 3 deletions(-)

diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c
index 5c993c2..df27d82 100644
--- a/drivers/net/can/ti_hecc.c
+++ b/drivers/net/can/ti_hecc.c
@@ -824,7 +824,6 @@ static int ti_hecc_open(struct net_device *ndev)
 		return err;
 	}
 
-	clk_enable(priv->clk);
 	ti_hecc_start(ndev);
 	napi_enable(&priv->napi);
 	netif_start_queue(ndev);
@@ -840,7 +839,6 @@ static int ti_hecc_close(struct net_device *ndev)
 	napi_disable(&priv->napi);
 	ti_hecc_stop(ndev);
 	free_irq(ndev->irq, ndev);
-	clk_disable(priv->clk);
 	close_candev(ndev);
 
 	return 0;
@@ -925,6 +923,7 @@ static int ti_hecc_probe(struct platform_device *pdev)
 	netif_napi_add(ndev, &priv->napi, ti_hecc_rx_poll,
 		HECC_DEF_NAPI_WEIGHT);
 
+	clk_enable(priv->clk);
 	err = register_candev(ndev);
 	if (err) {
 		dev_err(&pdev->dev, "register_candev() failed\n");
@@ -953,6 +952,7 @@ static int __devexit ti_hecc_remove(struct platform_device *pdev)
 	struct net_device *ndev = platform_get_drvdata(pdev);
 	struct ti_hecc_priv *priv = netdev_priv(ndev);
 
+	clk_disable(priv->clk);
 	clk_put(priv->clk);
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	iounmap(priv->base);
@@ -964,6 +964,48 @@ static int __devexit ti_hecc_remove(struct platform_device *pdev)
 	return 0;
 }
 
+
+#ifdef CONFIG_PM
+static int ti_hecc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct net_device *dev = platform_get_drvdata(pdev);
+	struct ti_hecc_priv *priv = netdev_priv(dev);
+
+	if (netif_running(dev)) {
+		netif_stop_queue(dev);
+		netif_device_detach(dev);
+	}
+
+	hecc_set_bit(priv, HECC_CANMC, HECC_CANMC_PDR);
+	priv->can.state = CAN_STATE_SLEEPING;
+
+	clk_disable(priv->clk);
+
+	return 0;
+}
+
+static int ti_hecc_resume(struct platform_device *pdev)
+{
+	struct net_device *dev = platform_get_drvdata(pdev);
+	struct ti_hecc_priv *priv = netdev_priv(dev);
+
+	clk_enable(priv->clk);
+
+	hecc_clear_bit(priv, HECC_CANMC, HECC_CANMC_PDR);
+	priv->can.state = CAN_STATE_ERROR_ACTIVE;
+
+	if (netif_running(dev)) {
+		netif_device_attach(dev);
+		netif_start_queue(dev);
+	}
+
+	return 0;
+}
+#else
+#define ti_hecc_suspend NULL
+#define ti_hecc_resume NULL
+#endif
+
 /* TI HECC netdevice driver: platform driver structure */
 static struct platform_driver ti_hecc_driver = {
 	.driver = {
@@ -972,6 +1014,8 @@ static struct platform_driver ti_hecc_driver = {
 	},
 	.probe = ti_hecc_probe,
 	.remove = __devexit_p(ti_hecc_remove),
+	.suspend = ti_hecc_suspend,
+	.resume = ti_hecc_resume,
 };
 
 static int __init ti_hecc_init_driver(void)
@@ -979,14 +1023,15 @@ static int __init ti_hecc_init_driver(void)
 	printk(KERN_INFO DRV_DESC "\n");
 	return platform_driver_register(&ti_hecc_driver);
 }
-module_init(ti_hecc_init_driver);
 
 static void __exit ti_hecc_exit_driver(void)
 {
 	printk(KERN_INFO DRV_DESC " unloaded\n");
 	platform_driver_unregister(&ti_hecc_driver);
 }
+
 module_exit(ti_hecc_exit_driver);
+module_init(ti_hecc_init_driver);
 
 MODULE_AUTHOR("Anant Gole <anantgole@ti.com>");
 MODULE_LICENSE("GPL v2");
-- 
1.6.2.4


^ permalink raw reply related

* Re: Subject: [PATCH 4/6] bna: Brocade 10Gb Ethernet device driver
From: Stanislaw Gruszka @ 2010-02-22 12:42 UTC (permalink / raw)
  To: Rasesh Mody; +Cc: netdev, adapter_linux_open_src_team
In-Reply-To: <201002192152.o1JLqcTh031965@blc-10-1.brocade.com>

On Fri, Feb 19, 2010 at 01:52:38PM -0800, Rasesh Mody wrote:
> From: Rasesh Mody <rmody@brocade.com>
> 
> This is patch 4/6 which contains linux driver source for
> Brocade's BR1010/BR1020 10Gb CEE capable ethernet adapter.
> Source is based against net-next-2.6.
> 
> We wish this patch to be considered for inclusion in net-next-2.6
> 
> Signed-off-by: Rasesh Mody <rmody@brocade.com>
> ---
>  bfa_ioc.h   |  320 ++++++++
>  bna.h       | 2195 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  bna_hwreg.h |  910 ++++++++++++++++++++++++
>  bna_intr.h  |   96 ++
>  4 files changed, 3521 insertions(+)
[snip]

> +/**
> + * Ethernet / Ethernet & VLAN header used by diag loopback
> + */
> +struct bna_ether_hdr {
> +	struct mac dst;		/* destination mac address      */
> +	struct mac src;		/* source mac address		*/
> +	u16 proto;		/* ethernet protocol		*/
> +};
Not used ?

> +
> +struct bna_ether_vlan_hdr {
> +	struct mac dst;		/* destination mac address      */
> +	struct mac src;		/* source mac address		*/
> +	u16 vlan_proto;	/* vlan ethernet protocol	*/
> +	u16 vlan_tci;	/* vlan tag/priority		*/
> +	u16 proto;		/* ethernet protocol		*/
> +};

Not used ?


^ permalink raw reply

* Re: Subject: [PATCH 1/6] bna: Brocade 10Gb Ethernet device driver
From: Stanislaw Gruszka @ 2010-02-22 12:40 UTC (permalink / raw)
  To: Rasesh Mody; +Cc: netdev, adapter_linux_open_src_team
In-Reply-To: <201002192152.o1JLqc8G031956@blc-10-1.brocade.com>

On Fri, Feb 19, 2010 at 01:52:38PM -0800, Rasesh Mody wrote:
> From: Rasesh Mody <rmody@brocade.com>
> 
> This is patch 1/6 which contains linux driver source for
> Brocade's BR1010/BR1020 10Gb CEE capable ethernet adapter.
> Source is based against net-next-2.6.
> 
> We wish this patch to be considered for inclusion in net-next-2.6
> 
> Signed-off-by: Rasesh Mody <rmody@brocade.com>
> ---
>  bnad.c | 3481 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  bnad.h |  341 ++++++
>  2 files changed, 3822 insertions(+)
[snip]
> void bnad_ioc_timeout(unsigned long ioc_arg)
> +{
> +	struct bnad *bnad = (struct bnad *)(((struct bfa_ioc*)ioc_arg)->bfa);
> +	spin_lock_irq(&bnad->priv_lock);
> +	spin_unlock_irq(&bnad->priv_lock);

Quite strange spin lock usage :)
  
> +u32
> +bnad_get_msglevel(struct net_device *netdev)
> +{
> +	return bnad_log_level;
> +}
> +
> +void
> +bnad_set_msglevel(struct net_device *netdev, u32 msglevel)
> +{
> +	struct bnad *bnad = netdev_priv(netdev);
> +	mutex_lock(&bnad->conf_mutex);
> +	bnad_log_level = msglevel;
> +	mutex_unlock(&bnad->conf_mutex);
> +}

bnad_log_level is not used anywhere.


^ permalink raw reply

* Re: Subject: [PATCH 2/6] bna: Brocade 10Gb Ethernet device driver
From: Stanislaw Gruszka @ 2010-02-22 12:36 UTC (permalink / raw)
  To: Rasesh Mody; +Cc: netdev, adapter_linux_open_src_team
In-Reply-To: <201002192152.o1JLqcI5031959@blc-10-1.brocade.com>

On Fri, Feb 19, 2010 at 01:52:38PM -0800, Rasesh Mody wrote:
> From: Rasesh Mody <rmody@brocade.com>
> 
> This is patch 2/6 which contains linux driver source for
> Brocade's BR1010/BR1020 10Gb CEE capable ethernet adapter.
> Source is based against net-next-2.6.
> 
> We wish this patch to be considered for inclusion in net-next-2.6
> 
> Signed-off-by: Rasesh Mody <rmody@brocade.com>
> ---
>  bfad_fwimg.c   |   94 ++
>  bna_fn.c       | 1795 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  bna_queue.c    |  394 ++++++++++++
>  bnad_ethtool.c | 1100 ++++++++++++++++++++++++++++++++++
>  4 files changed, 3383 insertions(+)
[snip]

> +u32 *
> +bfad_read_firmware(struct pci_dev *pdev, u32 **bfi_image,
> +			u32 *bfi_image_size, char *fw_name)
> +{
> +	const struct firmware *fw;
> +
> +	if (request_firmware(&fw, fw_name, &pdev->dev)) {
> +		printk(KERN_ALERT "Can't locate firmware %s\n", fw_name);
> +		goto error;
> +	}
> +
> +	*bfi_image = vmalloc(fw->size);
> +	if (NULL == *bfi_image) {
> +		printk(KERN_ALERT "Fail to allocate buffer for fw image "
> +			"size=%x!\n", (u32) fw->size);
> +		goto error;
> +	}
> +
> +	memcpy(*bfi_image, fw->data, fw->size);

Why do you alloc and copy image, why not just use fw->data?

> +	 struct bfa_log_mod *logmod)
> +{
> +	u32 pcifn;
> +
> +	memset(dev, 0, sizeof(struct bna_dev));
> +
> +	dev->trcmod = trcmod;
> +	dev->logmod = logmod;
> +
> +	dev->bar0 = (u8 *) bar0;
> +	dev->hw_stats = (struct bfi_ll_stats *)stats;
> +	dev->hw_stats_dma.msb = stats_dma.msb;
> +	dev->hw_stats_dma.lsb = stats_dma.lsb;
> +
> +	dev->rxf_promiscuous_id = BNA_RXF_ID_NONE;
> +	dev->rxf_default_id = BNA_RXF_ID_NONE;
> +
> +	pcifn = readl(dev->bar0 + FNC_ID_REG);
> +	pcifn = readl(dev->bar0 + FNC_ID_REG);
What for you read this twice?

> +	/* we always use RSS table 0 */
> +	writel(cfg_ptr->flags & BNA_RXF_CF_RSS_ENABLE,
> +		&rx_fndb_ram[rxf_id].rss_prop);
> +
> +	/* small large buffer enable/disable */
> +	writel((cfg_ptr->flags & BNA_RXF_CF_SM_LG_RXQ) | 0x80,
> +		&rx_fndb_ram[rxf_id].size_routing_props);
> +
> +	/* RIT offset, HDS forced offset, multicast RxQ Id */
> +	writel(
> +		       (cfg_ptr->rit_offset << 16) | (cfg_ptr->hds.
> +						      forced_offset << 8) |
> +		       (cfg_ptr->hds.type & BNA_HDS_FORCED) | cfg_ptr->
> +		       mcast_rxq_id, &rx_fndb_ram[rxf_id].rit_hds_mcastq);
Please use normal indentions.


^ permalink raw reply

* Re: Subject: [PATCH 3/6] bna: Brocade 10Gb Ethernet device driver
From: Stanislaw Gruszka @ 2010-02-22 12:26 UTC (permalink / raw)
  To: Rasesh Mody; +Cc: netdev, adapter_linux_open_src_team
In-Reply-To: <201002192152.o1JLqcNL031962@blc-10-1.brocade.com>

On Fri, Feb 19, 2010 at 01:52:38PM -0800, Rasesh Mody wrote:
> From: Rasesh Mody <rmody@brocade.com>
> 
> This is patch 3/6 which contains linux driver source for
> Brocade's BR1010/BR1020 10Gb CEE capable ethernet adapter.
> Source is based against net-next-2.6.
> 
> We wish this patch to be considered for inclusion in net-next-2.6
> 
> Signed-off-by: Rasesh Mody <rmody@brocade.com>
> ---
>  bfa_cee.c     |  459 +++++++++++++
>  bfa_csdebug.c |   55 +
>  bfa_ioc.c     | 1930 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  bfa_ioc_ct.c  |  416 ++++++++++++
>  bfa_sm.c      |   38 +
>  bna_if.c      |  524 +++++++++++++++
>  bna_iocll.h   |   60 +
>  bna_priv.h    |  472 ++++++++++++++
>  bnad_defs.h   |   37 +
>  cna.h         |   42 +
>  10 files changed, 4033 insertions(+)
[snip]
> +/**
> + * bfa_cee_attach()
> + *
> + *
> + * @param[in] cee - Pointer to the CEE module data structure
> + *            ioc - Pointer to the ioc module data structure
> + *            dev - Pointer to the device driver module data structure
> + *                  The device driver specific mbox ISR functions have
> + *                  this pointer as one of the parameters.
> + *            trcmod -
> + *            logmod -
> + *
> + * @return void
> + */
> +void
> +bfa_cee_attach(struct bfa_cee *cee, struct bfa_ioc *ioc,
> +		void *dev,
> +		struct bfa_trc_mod *trcmod,
> +		struct bfa_log_mod *logmod)
> +{
> +	cee->dev = dev;
> +	cee->trcmod = trcmod;
> +	cee->logmod = logmod;

We do not have trcmod, logmod in this driver anymore, please remove all
references to them.

> +#include "cs/bfa_debug.h"
> +#include "cna.h"
> +#include "cs/bfa_q.h"
> +
> +/**
> + *  cs_debug_api
> + */
> +
> +void
> +bfa_panic(int line, char *file, char *panicstr)
> +{
> +	pr_err("Assertion failure: %s:%d: %s", file, line, panicstr);
> +}
> +
> +void
> +bfa_sm_panic(struct bfa_log_mod *logm, int line, char *file, int event)
> +{
> +	pr_err("SM Assertion failure: %s:%d: event = %d",
> +			file, line, event);
> +}

If this is panic do panic not just print the message. I think you should
use BUG() instead of bfa_{sm_} panic.

> +static void
> +bfa_ioc_sm_hwinit_entry(struct bfa_ioc *ioc)
> +{
> +	mod_timer(&ioc->ioc_timer, jiffies +
> +	msecs_to_jiffies(BFA_IOC_TOV));

Do not break lines or use proper indention.

> +	bfa_ioc_reset(ioc, false);
> +}
> +
> +/**
> + * Hardware is being initialized. Interrupts are enabled.
> + * Holding hardware semaphore lock.
> + */
> +static void
> +bfa_ioc_sm_hwinit(struct bfa_ioc *ioc, enum ioc_event event)
> +{
> +
> +	switch (event) {
> +	case IOC_E_FWREADY:
> +		del_timer(&ioc->ioc_timer);
> +		bfa_fsm_set_state(ioc, bfa_ioc_sm_enabling);
> +		break;
> +
> +	case IOC_E_HWERROR:
> +		del_timer(&ioc->ioc_timer);
> +		/* fall through */
> +
> +	case IOC_E_TIMEOUT:
> +		ioc->retry_count++;
> +		if (ioc->retry_count < BFA_IOC_HWINIT_MAX) {
> +			mod_timer(&ioc->ioc_timer, jiffies +
> +	msecs_to_jiffies(BFA_IOC_TOV));

Here too, and in a few more places.

> +
> +enum bfa_ioc_type
> +bfa_ioc_get_type(struct bfa_ioc *ioc)
> +{
> +	if (!ioc->ctdev || ioc->fcmode)
> +		return BFA_IOC_TYPE_FC;
> +	else if (ioc->ioc_mc == BFI_MC_IOCFC)
> +		return BFA_IOC_TYPE_FCoE;
> +	else if (ioc->ioc_mc == BFI_MC_LL)
> +		return BFA_IOC_TYPE_LL;
> +	else {
> +		BUG_ON(!(ioc->ioc_mc == BFI_MC_LL));

Use BUG().

> +		return BFA_IOC_TYPE_LL;
> +	}
> +}
> +
> +void
> +bfa_ioc_get_adapter_serial_num(struct bfa_ioc *ioc, char *serial_num)
> +{
> +	memset((void *)serial_num, 0, BFA_ADAPTER_SERIAL_NUM_LEN);
> +	memcpy((void *)serial_num,

What for are (void *) casts in memcpy/memset?

> +enum bna_status bna_cleanup(void *bna_dev)

That exactly you should do :-) We are seeing and very appreciate your
current efforts, however more work need to be done regarding cleaning
up this driver (and BTW even more work with bfa).

> +#ifndef PCI_VENDOR_ID_BROCADE
> +#define PCI_VENDOR_ID_BROCADE	0x1657
> +#endif
> +
> +#ifndef PCI_DEVICE_ID_BROCADE_CATAPULT
> +#define PCI_DEVICE_ID_BROCADE_CATAPULT	0x0014
> +#endif

In linux we have include/linux/pci_ids.h files for that.

> +
> +#define PFX "BNA: "
> +#define DPRINTK(klevel, fmt, args...) do {  \
> +	printk(KERN_##klevel PFX fmt, ## args);      \
> +} while (0)

Is this used ?



^ permalink raw reply

* Re: [net-next-2.6 PATCH v2 0/3] Support for MPC512x FEC
From: David Miller @ 2010-02-22 11:44 UTC (permalink / raw)
  To: agust; +Cc: wd, dzu, netdev, linuxppc-dev
In-Reply-To: <20100222123724.67a7b862@wker>

From: Anatolij Gustschin <agust@denx.de>
Date: Mon, 22 Feb 2010 12:37:24 +0100

> Could you please comment on this patch series.

It's in the net-next-2.6 tree.

If you need to make any more changes, they need to be relative
to what went into my tree.

^ permalink raw reply

* Re: [net-next-2.6 PATCH v2 0/3] Support for MPC512x FEC
From: Anatolij Gustschin @ 2010-02-22 11:37 UTC (permalink / raw)
  To: David S. Miller; +Cc: Wolfgang Denk, Detlev Zundel, netdev, linuxppc-dev
In-Reply-To: <1266418530-2727-1-git-send-email-agust@denx.de>

Hi David,

On Wed, 17 Feb 2010 15:55:27 +0100
Anatolij Gustschin <agust@denx.de> wrote:

> These patches attempt to provide support for the Freescale MPC512x
> FEC in the fs_enet driver. The first cleanup patch replaces printk
> by dev_xxx. The second and third attemt to support MPC5121 FEC
> in the FEC driver.

Could you please comment on this patch series. The patches
have been acked by Grant and I slightly reworked third patch
to address Eric's comments, so there is v3 for this patch now.

Thanks,

Anatolij

^ permalink raw reply

* Re: [PATCH] module param_call: fix potential NULL pointer dereference
From: DDD @ 2010-02-22 10:11 UTC (permalink / raw)
  To: Rusty Russell
  Cc: Américo Wang, davem, linux-kernel, netdev, jason.wessel,
	lenb, dwmw2, mdharm-usb, bfields, robert.richter
In-Reply-To: <201002221941.21662.rusty@rustcorp.com.au>

Rusty Russell wrote:
> On Sun, 21 Feb 2010 07:11:36 pm Américo Wang wrote:
>> On Sun, Feb 21, 2010 at 3:24 PM, Dongdong Deng
>> <dongdong.deng@windriver.com> wrote:
>>> The param_set_fn() function will get a parameter which is a NULL
>>> pointer when insmod module with params via following method:
>>>
>>> $insmod module.ko module_params
>>>
>>> BTW: the normal method usually as following format:
>>> $insmod module.ko module_params=example
>>>
>>> If the param_set_fn() function didn't check that parameter and used
>>> it directly, it could caused an OOPS due to NULL pointer dereference.
>>>
>>> The solution is simple:
>>> Just checking the parameter before using in param_set_fn().
>>>
>>> Example:
>>> int set_module_params(const char *val, struct kernel_param *kp)
>>> {
>>>        /*Checking the val parameter before using */
>>>        if (!val)
>>>                return -EINVAL;
>>>        ...
>>> }
>>> module_param_call(module_params, set_module_params, NULL, NULL, 0644);
>>>
>> Why not just checking all of them in the generic code?
> 
> It seemed useful to allow 'foo' as well as 'foo='. 

Ah, this is a good method to deal with this issue.

I will redo this patch shortly.

Thanks,
Dongdong

  But given these examples,
> obviously that was too easy to misuse.
> 
> So I like your patch; please annotate it properly and put a comment
> like:
> 	/* We used to hand NULL for bare params, but most code didn't handle it :( */
> 
> I assume none of those non-standard param parsers *want* to handle NULL?
> 
> Thanks,
> Rusty.

^ permalink raw reply

* Re: [PATCH] module param_call: fix potential NULL pointer dereference
From: Rusty Russell @ 2010-02-22  9:11 UTC (permalink / raw)
  To: Américo Wang
  Cc: Dongdong Deng, davem, linux-kernel, netdev, jason.wessel, lenb,
	dwmw2, mdharm-usb, bfields, robert.richter
In-Reply-To: <2375c9f91002210041l1bf30871vdf3881589a654d5a@mail.gmail.com>

On Sun, 21 Feb 2010 07:11:36 pm Américo Wang wrote:
> On Sun, Feb 21, 2010 at 3:24 PM, Dongdong Deng
> <dongdong.deng@windriver.com> wrote:
> > The param_set_fn() function will get a parameter which is a NULL
> > pointer when insmod module with params via following method:
> >
> > $insmod module.ko module_params
> >
> > BTW: the normal method usually as following format:
> > $insmod module.ko module_params=example
> >
> > If the param_set_fn() function didn't check that parameter and used
> > it directly, it could caused an OOPS due to NULL pointer dereference.
> >
> > The solution is simple:
> > Just checking the parameter before using in param_set_fn().
> >
> > Example:
> > int set_module_params(const char *val, struct kernel_param *kp)
> > {
> >        /*Checking the val parameter before using */
> >        if (!val)
> >                return -EINVAL;
> >        ...
> > }
> > module_param_call(module_params, set_module_params, NULL, NULL, 0644);
> >
> 
> Why not just checking all of them in the generic code?

It seemed useful to allow 'foo' as well as 'foo='.  But given these examples,
obviously that was too easy to misuse.

So I like your patch; please annotate it properly and put a comment
like:
	/* We used to hand NULL for bare params, but most code didn't handle it :( */

I assume none of those non-standard param parsers *want* to handle NULL?

Thanks,
Rusty.
-- 
Away travelling 25Feb-26Mar (6 .de + 1 .pl + 17 .lt + 2 .sg)

^ permalink raw reply

* Re: [PATCH] module param_call: fix potential NULL pointer dereference
From: Américo Wang @ 2010-02-22  7:37 UTC (permalink / raw)
  To: DDD
  Cc: rusty, davem, linux-kernel, netdev, jason.wessel, lenb, dwmw2,
	mdharm-usb, bfields, robert.richter
In-Reply-To: <4B80FA08.8080304@windriver.com>

On Sun, Feb 21, 2010 at 5:16 PM, DDD <dongdong.deng@windriver.com> wrote:
> Américo Wang wrote:
>>
>> On Sun, Feb 21, 2010 at 3:24 PM, Dongdong Deng
>> <dongdong.deng@windriver.com> wrote:
>>>
>>> The param_set_fn() function will get a parameter which is a NULL
>>> pointer when insmod module with params via following method:
>>>
>>> $insmod module.ko module_params
>>>
>>> BTW: the normal method usually as following format:
>>> $insmod module.ko module_params=example
>>>
>>> If the param_set_fn() function didn't check that parameter and used
>>> it directly, it could caused an OOPS due to NULL pointer dereference.
>>>
>>> The solution is simple:
>>> Just checking the parameter before using in param_set_fn().
>>>
>>> Example:
>>> int set_module_params(const char *val, struct kernel_param *kp)
>>> {
>>>       /*Checking the val parameter before using */
>>>       if (!val)
>>>               return -EINVAL;
>>>       ...
>>> }
>>> module_param_call(module_params, set_module_params, NULL, NULL, 0644);
>>>
>>
>> Why not just checking all of them in the generic code?
>
> It is no problem that we check the params before invoking param_set_fn().
>
> But I trend to do the checking in param_set_*fn(), because we can offer some
> special prompt infos to user if we want and handle some special cases like
> param_set_bool().
>

Yeah, I knew standard bool parameters can accept that,
the problem is that KPARAM_ISBOOL is not enough to
check if a parameter is bool or not. Probably we need
a new flag...

Thanks.

^ permalink raw reply

* Re: dccp-test-tree [Patch 1/1] "UDP-like" CCID sample kernel module
From: Ivo Calado @ 2010-02-22  7:00 UTC (permalink / raw)
  To: Gerrit Renker, dccp, netdev
In-Reply-To: <20100215060928.GA5350@gerrit.erg.abdn.ac.uk>

On Mon, Feb 15, 2010 at 03:09, Gerrit Renker <gerrit@erg.abdn.ac.uk> wrote:
> This patch is for the dccp test tree at
>  git://eden-feed.erg.abdn.ac.uk/dccp_exp [subtree 'dccp']
>
> The actual 'module' is only 5 lines long.
>>>>>>>>>>>>>>>>>>>>>> Patch <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
> dccp: sample kernel module, NULL-CCID ("UDP-like")
>
> This implements an experimental CCID which does not do any congestion control,
> i.e. "UDP-like".
>
> This is an experimental CCID. It is not meant for actual deployment, but
> rather as sample kernel code, providing a worked example of how to add a
> new CCID module.
>
> Since CCID-0 is reserved (RFC 4340, table 5), this experimental NULL CCID uses
> the first available experimental CCID, CCID-248 (RFC 4340, 19.5).
>
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> ---
>  include/linux/dccp.h   |    7 +++++++
>  net/dccp/Makefile      |    1 +
>  net/dccp/ccid.c        |    3 +++
>  net/dccp/ccid.h        |    3 +++
>  net/dccp/ccids/Kconfig |   12 ++++++++++++
>  net/dccp/ccids/ccid0.c |   27 +++++++++++++++++++++++++++
>  net/dccp/feat.c        |   17 ++++++++++++++++-
>  7 files changed, 69 insertions(+), 1 deletion(-)
>
> --- a/include/linux/dccp.h
> +++ b/include/linux/dccp.h
> @@ -177,6 +177,13 @@ enum {
>  enum {
>        DCCPC_CCID2 = 2,
>        DCCPC_CCID3 = 3,
> +       /*
> +        * CCIDs 248-255 below are permanently reserved for
> +        * experimental and testing use (RFC 4340, 19.5).
> +        */
> +#define DCCPC_TESTING_MIN      248
> +#define DCCPC_TESTING_MAX      255
> +       DCCPC_CCID_ZERO = DCCPC_TESTING_MIN,
>  };
>
>  /* DCCP features (RFC 4340 section 6.4) */
> --- /dev/null
> +++ b/net/dccp/ccids/ccid0.c
> @@ -0,0 +1,27 @@
> +/*
> + *  CCID-ZERO - UDP-like congestion control
> + *
> + *  This is a sample kernel module, used for testing and development, but not
> + *  for actual deployment. The CCID number is taken from the range of CCIDs
> + *  set apart for testing and experimenting.
> + *
> + *  This program is free software; you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation; either version 2 of the License, or
> + *  (at your option) any later version.
> + *
> + *  This program is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *  GNU General Public License for more details.
> + *
> + *  You should have received a copy of the GNU General Public License
> + *  along with this program; if not, write to the Free Software
> + *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +#include "../ccid.h"
> +
> +struct ccid_operations ccid0_ops = {
> +       .ccid_id        = DCCPC_CCID_ZERO,
> +       .ccid_name      = "UDP-like transport"
> +};
> --- a/net/dccp/ccid.c
> +++ b/net/dccp/ccid.c
> @@ -19,6 +19,9 @@ static struct ccid_operations *ccids[] =
>  #ifdef CONFIG_IP_DCCP_CCID3
>        &ccid3_ops,
>  #endif
> +#ifdef CONFIG_IP_DCCP_CCID0
> +       &ccid0_ops,
> +#endif
>  };
>
>  static struct ccid_operations *ccid_by_number(const u8 id)
> --- a/net/dccp/ccid.h
> +++ b/net/dccp/ccid.h
> @@ -91,6 +91,9 @@ struct ccid_operations {
>                                                 int __user *optlen);
>  };
>
> +#ifdef CONFIG_IP_DCCP_CCID0
> +extern struct ccid_operations ccid0_ops;
> +#endif
>  extern struct ccid_operations ccid2_ops;
>  #ifdef CONFIG_IP_DCCP_CCID3
>  extern struct ccid_operations ccid3_ops;
> --- a/net/dccp/feat.c
> +++ b/net/dccp/feat.c
> @@ -620,7 +620,8 @@ static u8 dccp_feat_is_valid_sp_val(u8 f
>  {
>        switch (feat_num) {
>        case DCCPF_CCID:
> -               return val == DCCPC_CCID2 || val == DCCPC_CCID3;
> +               return  val == DCCPC_CCID2 || val == DCCPC_CCID3 ||
> +                       (val >= DCCPC_TESTING_MIN && val <= DCCPC_TESTING_MAX);
>        /* Type-check Boolean feature values: */
>        case DCCPF_SHORT_SEQNOS:
>        case DCCPF_ECN_INCAPABLE:
> @@ -831,6 +832,18 @@ EXPORT_SYMBOL_GPL(dccp_feat_signal_nn_ch
>  */
>  static const struct ccid_dependency *dccp_feat_ccid_deps(u8 ccid, bool is_local)
>  {
> +       static const struct ccid_dependency ccid0_dependencies[2][2] = {
> +               /*
> +                * The UDP-like CCID does not have special dependencies, but for
> +                * testing dependencies (e.g. Ack Vectors) can be defined below.
> +                */
> +               {
> +                       { 0, 0, 0, 0 }
> +               },
> +               {
> +                       { 0, 0, 0, 0 }
> +               }
> +       };
>        static const struct ccid_dependency ccid2_dependencies[2][2] = {
>                /*
>                 * CCID2 mandates Ack Vectors (RFC 4341, 4.): as CCID is a TX
> @@ -916,6 +929,8 @@ static const struct ccid_dependency *dcc
>                }
>        };
>        switch (ccid) {
> +       case DCCPC_CCID_ZERO:
> +               return ccid0_dependencies[is_local];
>        case DCCPC_CCID2:
>                return ccid2_dependencies[is_local];
>        case DCCPC_CCID3:
> --- a/net/dccp/ccids/Kconfig
> +++ b/net/dccp/ccids/Kconfig
> @@ -103,4 +103,16 @@ config IP_DCCP_TFRC_LIB
>
>  config IP_DCCP_TFRC_DEBUG
>        def_bool y if IP_DCCP_CCID3_DEBUG
> +
> +config IP_DCCP_CCID0
> +       bool "CCID-ZERO (UDP-Like) sample kernel module"
> +       def_bool n
> +       ---help---
> +         This is a sample kernel module to illustrate the integration of new
> +         CCID kernel modules into CCID. It can also be used for performance
> +         testing, but is not meant for deployment since it operates without
> +         any congestion control. It is a NULL CCID, its identifier is 248.
> +
> +         Say N.
> +
>  endmenu
> --- a/net/dccp/Makefile
> +++ b/net/dccp/Makefile
> @@ -7,6 +7,7 @@ dccp-y := ccid.o feat.o input.o minisock
>  #
>  # CCID-2 is default (RFC 4340, p. 77) and has Ack Vectors as dependency
>  dccp-y += ccids/ccid2.o ackvec.o
> +dccp-$(CONFIG_IP_DCCP_CCID0)   += ccids/ccid0.o
>  dccp-$(CONFIG_IP_DCCP_CCID3)   += ccids/ccid3.o
>  dccp-$(CONFIG_IP_DCCP_TFRC_LIB) += ccids/lib/tfrc.o            \
>                                   ccids/lib/tfrc_equation.o    \
> --
> To unsubscribe from this list: send the line "unsubscribe dccp" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>


Acked-by: Ivo Calado <ivocalado@embedded.ufcg.edu.br>  for ccid4 subtree

^ permalink raw reply

* Re: [net-next PATCH v4 1/3] net: TCP thin-stream detection
From: Lars Eggert @ 2010-02-22  6:41 UTC (permalink / raw)
  To: David Miller
  Cc: zimmermann@nets.rwth-aachen.de, pavel@ucw.cz, apetlund@simula.no,
	netdev@vger.kernel.org, ilpo.jarvinen@helsinki.fi,
	eric.dumazet@gmail.com, Arnd.Hannemann@nets.rwth-aachen.de,
	linux-kernel@vger.kernel.org, shemminger@vyatta.com,
	william.allen.simpson@gmail.com, damian@tvk.rwth-aachen.de,
	ebiederm@xmission.com
In-Reply-To: <20100221.150311.193707249.davem@davemloft.net>

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

If it's off by default there is no issue.

On 2010-2-22, at 1:03, David Miller wrote:

> From: Lars Eggert <lars.eggert@nokia.com>
> Date: Sun, 21 Feb 2010 22:04:46 +0200
> 
>> Agree with Alexander. It is not at all clear to me that these
>> changes are safe for non-exerimental use in the wider Internet.
> 
> It's off by default and we provide all sorts of experimental
> congestion control algorithms which can cause just as much
> if not more trouble than these thin-stream bits.
> 
> There is no problem integrating these changes.


[-- Attachment #2: smime.p7s --]
[-- Type: application/pkcs7-signature, Size: 2490 bytes --]

^ permalink raw reply

* Re: Subject: [PATCH 0/6] bna: Brocade 10Gb Ethernet device driver
From: David Miller @ 2010-02-22  6:39 UTC (permalink / raw)
  To: rmody; +Cc: netdev, adapter_linux_open_src_team
In-Reply-To: <201002192152.o1JLqcB6031953@blc-10-1.brocade.com>


This driver still needs a lot of work.

The number of headers files is rediculious and I see pieces of
information duplicated up to 4 or 5 times (!?!??!)

First, reduce the header files to say two or three.

Next, remove all of the duplicated information.  You have at least two
copies of the PCI device ID in these header files.  There are three or
four definitions of the same statistics data structures.

It's pure bloat, you have to consolidate the content and the number of
header files holding this information.

^ permalink raw reply

* Re: [PATCH net-next 0/7] cxgb4 patches V2
From: David Miller @ 2010-02-22  6:30 UTC (permalink / raw)
  To: dm; +Cc: netdev
In-Reply-To: <1266528256-20873-1-git-send-email-dm@chelsio.com>

From: Dimitris Michailidis <dm@chelsio.com>
Date: Thu, 18 Feb 2010 13:24:09 -0800

> 
> This is V2 of the cxgb4 patches.
> 
> Changes since V1:
> - Whitespace fixed as well as some additional checkpatch issues.
> - I removed the CH_* logging wrappers.  I used the new netdev_* in a handful of
>   places but mostly stayed with the dev_* functions.
> - I added some comments to describe the register macro scheme.  As a macro
>   change would involve a rather large number of LOCs I'd really like to avoid
>   changing them.

I also told you to not use the non-standard S_*, V_*, etc. register
naming convention.

If you repost your driver without addressing all of the review
feedback you've received thus far, you are wasting people's time
because they will take time out to review your patches again
only to find that you've haven't fixed everything you've already
been made aware of.

^ permalink raw reply

* Re: [net-next-2.6 PATCH 1/7] xfrm: introduce basic mark infrastructure
From: David Miller @ 2010-02-22  6:26 UTC (permalink / raw)
  To: hadi; +Cc: timo.teras, kaber, herbert, netdev
In-Reply-To: <1266699340-5590-2-git-send-email-hadi@cyberus.ca>

From: jamal <hadi@cyberus.ca>
Date: Sat, 20 Feb 2010 15:55:34 -0500

>  	XFRMA_ALG_AUTH_TRUNC,	/* struct xfrm_algo_auth */
> +	XFRMA_MARK,		/* u32 */
>  	__XFRMA_MAX
>  

XFRM_MARK is "struct xfrm_*mask" not "u32".

> +struct xfrm_kmark {
> +	u32           v; /* value */
> +	u32           m; /* mask */
> +};
> +

You absolutely don't need this song and dance.

If the userspace attribute type equals the kernel one, you can just
define one "struct xfrm_mark" in linux/xfrm.h and use it universally.

This is how we handle this with other XFRM userspace visible
datastructures.

We only make seperate internal ones when they have to be different for
some reason, which is not true here.

Please respin your entire patch set once you've fixed this.

Thanks.

^ permalink raw reply

* Re: [PATCH V2 net-next 14/15] drivers/net/typhoon.c: Use (pr|netdev)_<level> macro helpers
From: David Dillow @ 2010-02-22  3:23 UTC (permalink / raw)
  To: Joe Perches; +Cc: David Miller, netdev
In-Reply-To: <1266808127.10646.77.camel@Joe-Laptop.home>

On Sun, 2010-02-21 at 19:08 -0800, Joe Perches wrote: 
> David Dillow took my suggestions and improved on them.
> Here is this latest version.
> 
> Add #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> Remove #define PFX
> Remove #define ERR_PFX
> Remove now unused member name from struct typhoon
> Use pr_<level>
> Use netdev_<level>
> Coalesce long formats
> Remove version information
> 
> Signed-off-by: Joe Perches <joe@perches.com>
> Signed-off-by: David Dillow <dave@thedillows.org>

Perhaps commit text as follows? I can sign-off on it, but I don't think
my effort rises to that level. I certainly ack the patch, though.

typhoon: clean up message output
    
Use the new netdev_* helpers to clean up and make the logging output
more consistent with other network drivers. This also removes the
constantly-stale version info in favor of using the kernel version from
which the module was built.

Signed-off-by: Joe Perches <joe@perches.com>
Acked-by: David Dillow <dave@thedillows.org>


^ permalink raw reply

* [PATCH V2 net-next 14/15] drivers/net/typhoon.c: Use (pr|netdev)_<level> macro helpers
From: Joe Perches @ 2010-02-22  3:08 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, David Dillow
In-Reply-To: <1266804176.10646.65.camel@Joe-Laptop.home>

David Dillow took my suggestions and improved on them.
Here is this latest version.

Add #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
Remove #define PFX
Remove #define ERR_PFX
Remove now unused member name from struct typhoon
Use pr_<level>
Use netdev_<level>
Coalesce long formats
Remove version information

Signed-off-by: Joe Perches <joe@perches.com>
Signed-off-by: David Dillow <dave@thedillows.org>
---
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
index edabc49..38c2161 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -98,14 +98,10 @@ static const int multicast_filter_limit = 32;
 #define TX_TIMEOUT  (2*HZ)
 
 #define PKT_BUF_SZ		1536
-
-#define DRV_MODULE_NAME		"typhoon"
-#define DRV_MODULE_VERSION 	"1.5.9"
-#define DRV_MODULE_RELDATE	"Mar 2, 2009"
-#define PFX			DRV_MODULE_NAME ": "
-#define ERR_PFX			KERN_ERR PFX
 #define FIRMWARE_NAME		"3com/typhoon.bin"
 
+#define pr_fmt(fmt)		KBUILD_MODNAME " " fmt
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -132,14 +128,12 @@ static const int multicast_filter_limit = 32;
 #include <linux/in6.h>
 #include <linux/dma-mapping.h>
 #include <linux/firmware.h>
+#include <generated/utsrelease.h>
 
 #include "typhoon.h"
 
-static char version[] __devinitdata =
-    "typhoon.c: version " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
-
 MODULE_AUTHOR("David Dillow <dave@thedillows.org>");
-MODULE_VERSION(DRV_MODULE_VERSION);
+MODULE_VERSION(UTS_RELEASE);
 MODULE_LICENSE("GPL");
 MODULE_FIRMWARE(FIRMWARE_NAME);
 MODULE_DESCRIPTION("3Com Typhoon Family (3C990, 3CR990, and variants)");
@@ -161,8 +155,8 @@ module_param(use_mmio, int, 0);
 #endif
 
 struct typhoon_card_info {
-	char *name;
-	int capabilities;
+	const char *name;
+	const int capabilities;
 };
 
 #define TYPHOON_CRYPTO_NONE		0x00
@@ -299,7 +293,6 @@ struct typhoon {
 	struct basic_ring	respRing;
 	struct net_device_stats	stats;
 	struct net_device_stats	stats_saved;
-	const char *		name;
 	struct typhoon_shared *	shared;
 	dma_addr_t		shared_dma;
 	__le16			xcvr_select;
@@ -534,13 +527,13 @@ typhoon_process_response(struct typhoon *tp, int resp_size,
 		} else if(resp->cmd == TYPHOON_CMD_HELLO_RESP) {
 			typhoon_hello(tp);
 		} else {
-			printk(KERN_ERR "%s: dumping unexpected response "
-			       "0x%04x:%d:0x%02x:0x%04x:%08x:%08x\n",
-			       tp->name, le16_to_cpu(resp->cmd),
-			       resp->numDesc, resp->flags,
-			       le16_to_cpu(resp->parm1),
-			       le32_to_cpu(resp->parm2),
-			       le32_to_cpu(resp->parm3));
+			netdev_err(tp->dev,
+				   "dumping unexpected response 0x%04x:%d:0x%02x:0x%04x:%08x:%08x\n",
+				   le16_to_cpu(resp->cmd),
+				   resp->numDesc, resp->flags,
+				   le16_to_cpu(resp->parm1),
+				   le32_to_cpu(resp->parm2),
+				   le32_to_cpu(resp->parm3));
 		}
 
 cleanup:
@@ -606,9 +599,8 @@ typhoon_issue_command(struct typhoon *tp, int num_cmd, struct cmd_desc *cmd,
 	freeResp = typhoon_num_free_resp(tp);
 
 	if(freeCmd < num_cmd || freeResp < num_resp) {
-		printk("%s: no descs for cmd, had (needed) %d (%d) cmd, "
-			"%d (%d) resp\n", tp->name, freeCmd, num_cmd,
-			freeResp, num_resp);
+		netdev_err(tp->dev, "no descs for cmd, had (needed) %d (%d) cmd, %d (%d) resp\n",
+			   freeCmd, num_cmd, freeResp, num_resp);
 		err = -ENOMEM;
 		goto out;
 	}
@@ -733,7 +725,7 @@ typhoon_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
 		spin_unlock_bh(&tp->state_lock);
 		err = typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
 		if(err < 0)
-			printk("%s: vlan offload error %d\n", tp->name, -err);
+			netdev_err(tp->dev, "vlan offload error %d\n", -err);
 		spin_lock_bh(&tp->state_lock);
 	}
 
@@ -1021,7 +1013,7 @@ typhoon_get_stats(struct net_device *dev)
 		return saved;
 
 	if(typhoon_do_get_stats(tp) < 0) {
-		printk(KERN_ERR "%s: error getting stats\n", dev->name);
+		netdev_err(dev, "error getting stats\n");
 		return saved;
 	}
 
@@ -1063,8 +1055,8 @@ typhoon_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 		}
 	}
 
-	strcpy(info->driver, DRV_MODULE_NAME);
-	strcpy(info->version, DRV_MODULE_VERSION);
+	strcpy(info->driver, KBUILD_MODNAME);
+	strcpy(info->version, UTS_RELEASE);
 	strcpy(info->bus_info, pci_name(pci_dev));
 }
 
@@ -1366,8 +1358,8 @@ typhoon_request_firmware(struct typhoon *tp)
 
 	err = request_firmware(&typhoon_fw, FIRMWARE_NAME, &tp->pdev->dev);
 	if (err) {
-		printk(KERN_ERR "%s: Failed to load firmware \"%s\"\n",
-				tp->name, FIRMWARE_NAME);
+		netdev_err(tp->dev, "Failed to load firmware \"%s\"\n",
+			   FIRMWARE_NAME);
 		return err;
 	}
 
@@ -1402,7 +1394,7 @@ typhoon_request_firmware(struct typhoon *tp)
 	return 0;
 
 invalid_fw:
-	printk(KERN_ERR "%s: Invalid firmware image\n", tp->name);
+	netdev_err(tp->dev, "Invalid firmware image\n");
 	release_firmware(typhoon_fw);
 	typhoon_fw = NULL;
 	return -EINVAL;
@@ -1439,7 +1431,7 @@ typhoon_download_firmware(struct typhoon *tp)
 	err = -ENOMEM;
 	dpage = pci_alloc_consistent(pdev, PAGE_SIZE, &dpage_dma);
 	if(!dpage) {
-		printk(KERN_ERR "%s: no DMA mem for firmware\n", tp->name);
+		netdev_err(tp->dev, "no DMA mem for firmware\n");
 		goto err_out;
 	}
 
@@ -1452,7 +1444,7 @@ typhoon_download_firmware(struct typhoon *tp)
 
 	err = -ETIMEDOUT;
 	if(typhoon_wait_status(ioaddr, TYPHOON_STATUS_WAITING_FOR_HOST) < 0) {
-		printk(KERN_ERR "%s: card ready timeout\n", tp->name);
+		netdev_err(tp->dev, "card ready timeout\n");
 		goto err_out_irq;
 	}
 
@@ -1492,8 +1484,7 @@ typhoon_download_firmware(struct typhoon *tp)
 			if(typhoon_wait_interrupt(ioaddr) < 0 ||
 			   ioread32(ioaddr + TYPHOON_REG_STATUS) !=
 			   TYPHOON_STATUS_WAITING_FOR_SEGMENT) {
-				printk(KERN_ERR "%s: segment ready timeout\n",
-				       tp->name);
+				netdev_err(tp->dev, "segment ready timeout\n");
 				goto err_out_irq;
 			}
 
@@ -1503,8 +1494,8 @@ typhoon_download_firmware(struct typhoon *tp)
 			 * the checksum, we can do this once, at the end.
 			 */
 			csum = csum_fold(csum_partial_copy_nocheck(image_data,
-								  dpage, len,
-								  0));
+								   dpage, len,
+								   0));
 
 			iowrite32(len, ioaddr + TYPHOON_REG_BOOT_LENGTH);
 			iowrite32(le16_to_cpu((__force __le16)csum),
@@ -1515,7 +1506,7 @@ typhoon_download_firmware(struct typhoon *tp)
 			iowrite32(dpage_dma, ioaddr + TYPHOON_REG_BOOT_DATA_LO);
 			typhoon_post_pci_writes(ioaddr);
 			iowrite32(TYPHOON_BOOTCMD_SEG_AVAILABLE,
-			       ioaddr + TYPHOON_REG_COMMAND);
+					ioaddr + TYPHOON_REG_COMMAND);
 
 			image_data += len;
 			load_addr += len;
@@ -1526,15 +1517,15 @@ typhoon_download_firmware(struct typhoon *tp)
 	if(typhoon_wait_interrupt(ioaddr) < 0 ||
 	   ioread32(ioaddr + TYPHOON_REG_STATUS) !=
 	   TYPHOON_STATUS_WAITING_FOR_SEGMENT) {
-		printk(KERN_ERR "%s: final segment ready timeout\n", tp->name);
+		netdev_err(tp->dev, "final segment ready timeout\n");
 		goto err_out_irq;
 	}
 
 	iowrite32(TYPHOON_BOOTCMD_DNLD_COMPLETE, ioaddr + TYPHOON_REG_COMMAND);
 
 	if(typhoon_wait_status(ioaddr, TYPHOON_STATUS_WAITING_FOR_BOOT) < 0) {
-		printk(KERN_ERR "%s: boot ready timeout, status 0x%0x\n",
-		       tp->name, ioread32(ioaddr + TYPHOON_REG_STATUS));
+		netdev_err(tp->dev, "boot ready timeout, status 0x%0x\n",
+			   ioread32(ioaddr + TYPHOON_REG_STATUS));
 		goto err_out_irq;
 	}
 
@@ -1556,7 +1547,7 @@ typhoon_boot_3XP(struct typhoon *tp, u32 initial_status)
 	void __iomem *ioaddr = tp->ioaddr;
 
 	if(typhoon_wait_status(ioaddr, initial_status) < 0) {
-		printk(KERN_ERR "%s: boot ready timeout\n", tp->name);
+		netdev_err(tp->dev, "boot ready timeout\n");
 		goto out_timeout;
 	}
 
@@ -1567,8 +1558,8 @@ typhoon_boot_3XP(struct typhoon *tp, u32 initial_status)
 				ioaddr + TYPHOON_REG_COMMAND);
 
 	if(typhoon_wait_status(ioaddr, TYPHOON_STATUS_RUNNING) < 0) {
-		printk(KERN_ERR "%s: boot finish timeout (status 0x%x)\n",
-		       tp->name, ioread32(ioaddr + TYPHOON_REG_STATUS));
+		netdev_err(tp->dev, "boot finish timeout (status 0x%x)\n",
+			   ioread32(ioaddr + TYPHOON_REG_STATUS));
 		goto out_timeout;
 	}
 
@@ -1867,8 +1858,7 @@ typhoon_interrupt(int irq, void *dev_instance)
 		typhoon_post_pci_writes(ioaddr);
 		__napi_schedule(&tp->napi);
 	} else {
-		printk(KERN_ERR "%s: Error, poll already scheduled\n",
-                       dev->name);
+		netdev_err(dev, "Error, poll already scheduled\n");
 	}
 	return IRQ_HANDLED;
 }
@@ -1901,16 +1891,15 @@ typhoon_sleep(struct typhoon *tp, pci_power_t state, __le16 events)
 	xp_cmd.parm1 = events;
 	err = typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
 	if(err < 0) {
-		printk(KERN_ERR "%s: typhoon_sleep(): wake events cmd err %d\n",
-				tp->name, err);
+		netdev_err(tp->dev, "typhoon_sleep(): wake events cmd err %d\n",
+			   err);
 		return err;
 	}
 
 	INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_GOTO_SLEEP);
 	err = typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
 	if(err < 0) {
-		printk(KERN_ERR "%s: typhoon_sleep(): sleep cmd err %d\n",
-				tp->name, err);
+		netdev_err(tp->dev, "typhoon_sleep(): sleep cmd err %d\n", err);
 		return err;
 	}
 
@@ -1961,12 +1950,12 @@ typhoon_start_runtime(struct typhoon *tp)
 
 	err = typhoon_download_firmware(tp);
 	if(err < 0) {
-		printk("%s: cannot load runtime on 3XP\n", tp->name);
+		netdev_err(tp->dev, "cannot load runtime on 3XP\n");
 		goto error_out;
 	}
 
 	if(typhoon_boot_3XP(tp, TYPHOON_STATUS_WAITING_FOR_BOOT) < 0) {
-		printk("%s: cannot boot 3XP\n", tp->name);
+		netdev_err(tp->dev, "cannot boot 3XP\n");
 		err = -EIO;
 		goto error_out;
 	}
@@ -2070,9 +2059,7 @@ typhoon_stop_runtime(struct typhoon *tp, int wait_type)
 	}
 
 	if(i == TYPHOON_WAIT_TIMEOUT)
-		printk(KERN_ERR
-		       "%s: halt timed out waiting for Tx to complete\n",
-		       tp->name);
+		netdev_err(tp->dev, "halt timed out waiting for Tx to complete\n");
 
 	INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_TX_DISABLE);
 	typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
@@ -2089,11 +2076,10 @@ typhoon_stop_runtime(struct typhoon *tp, int wait_type)
 	typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
 
 	if(typhoon_wait_status(ioaddr, TYPHOON_STATUS_HALTED) < 0)
-		printk(KERN_ERR "%s: timed out waiting for 3XP to halt\n",
-		       tp->name);
+		netdev_err(tp->dev, "timed out waiting for 3XP to halt\n");
 
 	if(typhoon_reset(ioaddr, wait_type) < 0) {
-		printk(KERN_ERR "%s: unable to reset 3XP\n", tp->name);
+		netdev_err(tp->dev, "unable to reset 3XP\n");
 		return -ETIMEDOUT;
 	}
 
@@ -2112,8 +2098,7 @@ typhoon_tx_timeout(struct net_device *dev)
 	struct typhoon *tp = netdev_priv(dev);
 
 	if(typhoon_reset(tp->ioaddr, WaitNoSleep) < 0) {
-		printk(KERN_WARNING "%s: could not reset in tx timeout\n",
-					dev->name);
+		netdev_warn(dev, "could not reset in tx timeout\n");
 		goto truely_dead;
 	}
 
@@ -2122,8 +2107,7 @@ typhoon_tx_timeout(struct net_device *dev)
 	typhoon_free_rx_rings(tp);
 
 	if(typhoon_start_runtime(tp) < 0) {
-		printk(KERN_ERR "%s: could not start runtime in tx timeout\n",
-					dev->name);
+		netdev_err(dev, "could not start runtime in tx timeout\n");
 		goto truely_dead;
         }
 
@@ -2148,7 +2132,7 @@ typhoon_open(struct net_device *dev)
 
 	err = typhoon_wakeup(tp, WaitSleep);
 	if(err < 0) {
-		printk(KERN_ERR "%s: unable to wakeup device\n", dev->name);
+		netdev_err(dev, "unable to wakeup device\n");
 		goto out_sleep;
 	}
 
@@ -2173,14 +2157,13 @@ out_irq:
 
 out_sleep:
 	if(typhoon_boot_3XP(tp, TYPHOON_STATUS_WAITING_FOR_HOST) < 0) {
-		printk(KERN_ERR "%s: unable to reboot into sleep img\n",
-				dev->name);
+		netdev_err(dev, "unable to reboot into sleep img\n");
 		typhoon_reset(tp->ioaddr, NoWait);
 		goto out;
 	}
 
 	if(typhoon_sleep(tp, PCI_D3hot, 0) < 0)
-		printk(KERN_ERR "%s: unable to go back to sleep\n", dev->name);
+		netdev_err(dev, "unable to go back to sleep\n");
 
 out:
 	return err;
@@ -2195,7 +2178,7 @@ typhoon_close(struct net_device *dev)
 	napi_disable(&tp->napi);
 
 	if(typhoon_stop_runtime(tp, WaitSleep) < 0)
-		printk(KERN_ERR "%s: unable to stop runtime\n", dev->name);
+		netdev_err(dev, "unable to stop runtime\n");
 
 	/* Make sure there is no irq handler running on a different CPU. */
 	free_irq(dev->irq, dev);
@@ -2204,10 +2187,10 @@ typhoon_close(struct net_device *dev)
 	typhoon_init_rings(tp);
 
 	if(typhoon_boot_3XP(tp, TYPHOON_STATUS_WAITING_FOR_HOST) < 0)
-		printk(KERN_ERR "%s: unable to boot sleep image\n", dev->name);
+		netdev_err(dev, "unable to boot sleep image\n");
 
 	if(typhoon_sleep(tp, PCI_D3hot, 0) < 0)
-		printk(KERN_ERR "%s: unable to put card to sleep\n", dev->name);
+		netdev_err(dev, "unable to put card to sleep\n");
 
 	return 0;
 }
@@ -2225,14 +2208,12 @@ typhoon_resume(struct pci_dev *pdev)
 		return 0;
 
 	if(typhoon_wakeup(tp, WaitNoSleep) < 0) {
-		printk(KERN_ERR "%s: critical: could not wake up in resume\n",
-				dev->name);
+		netdev_err(dev, "critical: could not wake up in resume\n");
 		goto reset;
 	}
 
 	if(typhoon_start_runtime(tp) < 0) {
-		printk(KERN_ERR "%s: critical: could not start runtime in "
-				"resume\n", dev->name);
+		netdev_err(dev, "critical: could not start runtime in resume\n");
 		goto reset;
 	}
 
@@ -2259,8 +2240,7 @@ typhoon_suspend(struct pci_dev *pdev, pm_message_t state)
 	spin_lock_bh(&tp->state_lock);
 	if(tp->vlgrp && tp->wol_events & TYPHOON_WAKE_MAGIC_PKT) {
 		spin_unlock_bh(&tp->state_lock);
-		printk(KERN_ERR "%s: cannot do WAKE_MAGIC with VLANS\n",
-				dev->name);
+		netdev_err(dev, "cannot do WAKE_MAGIC with VLANS\n");
 		return -EBUSY;
 	}
 	spin_unlock_bh(&tp->state_lock);
@@ -2268,7 +2248,7 @@ typhoon_suspend(struct pci_dev *pdev, pm_message_t state)
 	netif_device_detach(dev);
 
 	if(typhoon_stop_runtime(tp, WaitNoSleep) < 0) {
-		printk(KERN_ERR "%s: unable to stop runtime\n", dev->name);
+		netdev_err(dev, "unable to stop runtime\n");
 		goto need_resume;
 	}
 
@@ -2276,7 +2256,7 @@ typhoon_suspend(struct pci_dev *pdev, pm_message_t state)
 	typhoon_init_rings(tp);
 
 	if(typhoon_boot_3XP(tp, TYPHOON_STATUS_WAITING_FOR_HOST) < 0) {
-		printk(KERN_ERR "%s: unable to boot sleep image\n", dev->name);
+		netdev_err(dev, "unable to boot sleep image\n");
 		goto need_resume;
 	}
 
@@ -2284,21 +2264,19 @@ typhoon_suspend(struct pci_dev *pdev, pm_message_t state)
 	xp_cmd.parm1 = cpu_to_le16(ntohs(*(__be16 *)&dev->dev_addr[0]));
 	xp_cmd.parm2 = cpu_to_le32(ntohl(*(__be32 *)&dev->dev_addr[2]));
 	if(typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL) < 0) {
-		printk(KERN_ERR "%s: unable to set mac address in suspend\n",
-				dev->name);
+		netdev_err(dev, "unable to set mac address in suspend\n");
 		goto need_resume;
 	}
 
 	INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_SET_RX_FILTER);
 	xp_cmd.parm1 = TYPHOON_RX_FILTER_DIRECTED | TYPHOON_RX_FILTER_BROADCAST;
 	if(typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL) < 0) {
-		printk(KERN_ERR "%s: unable to set rx filter in suspend\n",
-				dev->name);
+		netdev_err(dev, "unable to set rx filter in suspend\n");
 		goto need_resume;
 	}
 
 	if(typhoon_sleep(tp, pci_choose_state(pdev, state), tp->wol_events) < 0) {
-		printk(KERN_ERR "%s: unable to put card to sleep\n", dev->name);
+		netdev_err(dev, "unable to put card to sleep\n");
 		goto need_resume;
 	}
 
@@ -2352,7 +2330,7 @@ out_unmap:
 
 out:
 	if(!mode)
-		printk(KERN_INFO PFX "falling back to port IO\n");
+		pr_info("%s: falling back to port IO\n", pci_name(pdev));
 	return mode;
 }
 
@@ -2372,7 +2350,6 @@ static const struct net_device_ops typhoon_netdev_ops = {
 static int __devinit
 typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
-	static int did_version = 0;
 	struct net_device *dev;
 	struct typhoon *tp;
 	int card_id = (int) ent->driver_data;
@@ -2382,14 +2359,11 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 	struct cmd_desc xp_cmd;
 	struct resp_desc xp_resp[3];
 	int err = 0;
-
-	if(!did_version++)
-		printk(KERN_INFO "%s", version);
+	const char *err_msg;
 
 	dev = alloc_etherdev(sizeof(*tp));
 	if(dev == NULL) {
-		printk(ERR_PFX "%s: unable to alloc new net device\n",
-		       pci_name(pdev));
+		err_msg = "unable to alloc new net device";
 		err = -ENOMEM;
 		goto error_out;
 	}
@@ -2397,57 +2371,48 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 	err = pci_enable_device(pdev);
 	if(err < 0) {
-		printk(ERR_PFX "%s: unable to enable device\n",
-		       pci_name(pdev));
+		err_msg = "unable to enable device";
 		goto error_out_dev;
 	}
 
 	err = pci_set_mwi(pdev);
 	if(err < 0) {
-		printk(ERR_PFX "%s: unable to set MWI\n", pci_name(pdev));
+		err_msg = "unable to set MWI";
 		goto error_out_disable;
 	}
 
 	err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
 	if(err < 0) {
-		printk(ERR_PFX "%s: No usable DMA configuration\n",
-		       pci_name(pdev));
+		err_msg = "No usable DMA configuration";
 		goto error_out_mwi;
 	}
 
 	/* sanity checks on IO and MMIO BARs
 	 */
 	if(!(pci_resource_flags(pdev, 0) & IORESOURCE_IO)) {
-		printk(ERR_PFX
-		       "%s: region #1 not a PCI IO resource, aborting\n",
-		       pci_name(pdev));
+		err_msg = "region #1 not a PCI IO resource, aborting";
 		err = -ENODEV;
 		goto error_out_mwi;
 	}
 	if(pci_resource_len(pdev, 0) < 128) {
-		printk(ERR_PFX "%s: Invalid PCI IO region size, aborting\n",
-		       pci_name(pdev));
+		err_msg = "Invalid PCI IO region size, aborting";
 		err = -ENODEV;
 		goto error_out_mwi;
 	}
 	if(!(pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) {
-		printk(ERR_PFX
-		       "%s: region #1 not a PCI MMIO resource, aborting\n",
-		       pci_name(pdev));
+		err_msg = "region #1 not a PCI MMIO resource, aborting";
 		err = -ENODEV;
 		goto error_out_mwi;
 	}
 	if(pci_resource_len(pdev, 1) < 128) {
-		printk(ERR_PFX "%s: Invalid PCI MMIO region size, aborting\n",
-		       pci_name(pdev));
+		err_msg = "Invalid PCI MMIO region size, aborting";
 		err = -ENODEV;
 		goto error_out_mwi;
 	}
 
-	err = pci_request_regions(pdev, "typhoon");
+	err = pci_request_regions(pdev, KBUILD_MODNAME);
 	if(err < 0) {
-		printk(ERR_PFX "%s: could not request regions\n",
-		       pci_name(pdev));
+		err_msg = "could not request regions";
 		goto error_out_mwi;
 	}
 
@@ -2458,8 +2423,7 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 	ioaddr = pci_iomap(pdev, use_mmio, 128);
 	if (!ioaddr) {
-		printk(ERR_PFX "%s: cannot remap registers, aborting\n",
-		       pci_name(pdev));
+		err_msg = "cannot remap registers, aborting";
 		err = -EIO;
 		goto error_out_regions;
 	}
@@ -2469,8 +2433,7 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 	shared = pci_alloc_consistent(pdev, sizeof(struct typhoon_shared),
 				      &shared_dma);
 	if(!shared) {
-		printk(ERR_PFX "%s: could not allocate DMA memory\n",
-		       pci_name(pdev));
+		err_msg = "could not allocate DMA memory";
 		err = -ENOMEM;
 		goto error_out_remap;
 	}
@@ -2493,7 +2456,7 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 	 * 5) Put the card to sleep.
 	 */
 	if (typhoon_reset(ioaddr, WaitSleep) < 0) {
-		printk(ERR_PFX "%s: could not reset 3XP\n", pci_name(pdev));
+		err_msg = "could not reset 3XP";
 		err = -EIO;
 		goto error_out_dma;
 	}
@@ -2505,26 +2468,18 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 	pci_set_master(pdev);
 	pci_save_state(pdev);
 
-	/* dev->name is not valid until we register, but we need to
-	 * use some common routines to initialize the card. So that those
-	 * routines print the right name, we keep our oun pointer to the name
-	 */
-	tp->name = pci_name(pdev);
-
 	typhoon_init_interface(tp);
 	typhoon_init_rings(tp);
 
 	if(typhoon_boot_3XP(tp, TYPHOON_STATUS_WAITING_FOR_HOST) < 0) {
-		printk(ERR_PFX "%s: cannot boot 3XP sleep image\n",
-		       pci_name(pdev));
+		err_msg = "cannot boot 3XP sleep image";
 		err = -EIO;
 		goto error_out_reset;
 	}
 
 	INIT_COMMAND_WITH_RESPONSE(&xp_cmd, TYPHOON_CMD_READ_MAC_ADDRESS);
 	if(typhoon_issue_command(tp, 1, &xp_cmd, 1, xp_resp) < 0) {
-		printk(ERR_PFX "%s: cannot read MAC address\n",
-		       pci_name(pdev));
+		err_msg = "cannot read MAC address";
 		err = -EIO;
 		goto error_out_reset;
 	}
@@ -2533,8 +2488,7 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 	*(__be32 *)&dev->dev_addr[2] = htonl(le32_to_cpu(xp_resp[0].parm2));
 
 	if(!is_valid_ether_addr(dev->dev_addr)) {
-		printk(ERR_PFX "%s: Could not obtain valid ethernet address, "
-		       "aborting\n", pci_name(pdev));
+		err_msg = "Could not obtain valid ethernet address, aborting";
 		goto error_out_reset;
 	}
 
@@ -2543,8 +2497,7 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 	 */
 	INIT_COMMAND_WITH_RESPONSE(&xp_cmd, TYPHOON_CMD_READ_VERSIONS);
 	if(typhoon_issue_command(tp, 1, &xp_cmd, 3, xp_resp) < 0) {
-		printk(ERR_PFX "%s: Could not get Sleep Image version\n",
-			pci_name(pdev));
+		err_msg = "Could not get Sleep Image version";
 		goto error_out_reset;
 	}
 
@@ -2561,8 +2514,7 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 		tp->capabilities |= TYPHOON_WAKEUP_NEEDS_RESET;
 
 	if(typhoon_sleep(tp, PCI_D3hot, 0) < 0) {
-		printk(ERR_PFX "%s: cannot put adapter to sleep\n",
-		       pci_name(pdev));
+		err_msg = "cannot put adapter to sleep";
 		err = -EIO;
 		goto error_out_reset;
 	}
@@ -2581,19 +2533,18 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 	dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
 	dev->features |= NETIF_F_TSO;
 
-	if(register_netdev(dev) < 0)
+	if(register_netdev(dev) < 0) {
+		err_msg = "unable to register netdev";
 		goto error_out_reset;
-
-	/* fixup our local name */
-	tp->name = dev->name;
+	}
 
 	pci_set_drvdata(pdev, dev);
 
-	printk(KERN_INFO "%s: %s at %s 0x%llx, %pM\n",
-	       dev->name, typhoon_card_info[card_id].name,
-	       use_mmio ? "MMIO" : "IO",
-	       (unsigned long long)pci_resource_start(pdev, use_mmio),
-	       dev->dev_addr);
+	netdev_info(dev, "%s at %s 0x%llx, %pM\n",
+		    typhoon_card_info[card_id].name,
+		    use_mmio ? "MMIO" : "IO",
+		    (unsigned long long)pci_resource_start(pdev, use_mmio),
+		    dev->dev_addr);
 
 	/* xp_resp still contains the response to the READ_VERSIONS command.
 	 * For debugging, let the user know what version he has.
@@ -2603,23 +2554,20 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 		 * of version is Month/Day of build.
 		 */
 		u16 monthday = le32_to_cpu(xp_resp[0].parm2) & 0xffff;
-		printk(KERN_INFO "%s: Typhoon 1.0 Sleep Image built "
-			"%02u/%02u/2000\n", dev->name, monthday >> 8,
-			monthday & 0xff);
+		netdev_info(dev, "Typhoon 1.0 Sleep Image built %02u/%02u/2000\n",
+			    monthday >> 8, monthday & 0xff);
 	} else if(xp_resp[0].numDesc == 2) {
 		/* This is the Typhoon 1.1+ type Sleep Image
 		 */
 		u32 sleep_ver = le32_to_cpu(xp_resp[0].parm2);
 		u8 *ver_string = (u8 *) &xp_resp[1];
 		ver_string[25] = 0;
-		printk(KERN_INFO "%s: Typhoon 1.1+ Sleep Image version "
-			"%02x.%03x.%03x %s\n", dev->name, sleep_ver >> 24,
-			(sleep_ver >> 12) & 0xfff, sleep_ver & 0xfff,
-			ver_string);
+		netdev_info(dev, "Typhoon 1.1+ Sleep Image version %02x.%03x.%03x %s\n",
+			    sleep_ver >> 24, (sleep_ver >> 12) & 0xfff,
+			    sleep_ver & 0xfff, ver_string);
 	} else {
-		printk(KERN_WARNING "%s: Unknown Sleep Image version "
-			"(%u:%04x)\n", dev->name, xp_resp[0].numDesc,
-			le32_to_cpu(xp_resp[0].parm2));
+		netdev_warn(dev, "Unknown Sleep Image version (%u:%04x)\n",
+			    xp_resp[0].numDesc, le32_to_cpu(xp_resp[0].parm2));
 	}
 
 	return 0;
@@ -2641,6 +2589,7 @@ error_out_disable:
 error_out_dev:
 	free_netdev(dev);
 error_out:
+	pr_err("%s: %s\n", pci_name(pdev), err_msg);
 	return err;
 }
 
@@ -2665,7 +2614,7 @@ typhoon_remove_one(struct pci_dev *pdev)
 }
 
 static struct pci_driver typhoon_driver = {
-	.name		= DRV_MODULE_NAME,
+	.name		= KBUILD_MODNAME,
 	.id_table	= typhoon_pci_tbl,
 	.probe		= typhoon_init_one,
 	.remove		= __devexit_p(typhoon_remove_one),





^ permalink raw reply related

* Re: [net-next PATCH v5 2/3] sysctl: add proc_do_large_bitmap
From: Cong Wang @ 2010-02-22  2:45 UTC (permalink / raw)
  To: opurdila
  Cc: David Miller, Linux Kernel Network Developers,
	Linux Kernel Developers, Eric W. Biederman
In-Reply-To: <1266752533.3428.28.camel@Nokia-N900-42-11>

Octavian Purdila wrote:
> 
> But I think its worth to keep the whitespaces in beetween, e.g. allow
> 
> $ echo '1, 2 ,3 ' >   ip_local_reserved_ports.


Sure.

> 
>> Also, if I write an invalid value, it does reject this, but the previous
>> value in that file is cleared, shouldn't we keep the previous one?
>>
>>
> 
> The only way I see to fix this is to return EINVAL if we detect a write with offset.


Yeah, we shouldn't continue once we find any invalid value.

> 
> IMO we should do that for the other proc write routines as well, as otherwise ther result is confusing, e.g.
> 
> write("1 2"); write(" 3");
> 
> will set first value in the vector to 1, than second value to 2 then *first* value to 3.
> 
> I am all for it, but again, this changes userspace ABI. 

Sorry, is this related with the problem I mentioned above? Both "1 2"
and " 3" are valid values.

Thanks.

^ permalink raw reply

* Re: [PATCH][v4] tcp: fix ICMP-RTO war
From: David Miller @ 2010-02-22  2:10 UTC (permalink / raw)
  To: ilpo.jarvinen; +Cc: damian, netdev
In-Reply-To: <alpine.DEB.2.00.1002151535030.7063@wel-95.cs.helsinki.fi>

From: "Ilpo Järvinen" <ilpo.jarvinen@helsinki.fi>
Date: Tue, 16 Feb 2010 14:45:25 +0200 (EET)

> On Wed, 10 Feb 2010, Damian Lukowski wrote:
> 
>> @@ -5783,12 +5783,10 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
>>  
>>  				/* tcp_ack considers this ACK as duplicate
>>  				 * and does not calculate rtt.
>> -				 * Fix it at least with timestamps.
>> +				 * Force it here.
>>  				 */
>> -				if (tp->rx_opt.saw_tstamp &&
>> -				    tp->rx_opt.rcv_tsecr && !tp->srtt)
>> -					tcp_ack_saw_tstamp(sk, 0);
>> -
>> +				tcp_ack_update_rtt(sk, 0, 0);
>> +
> 
> ...Here a zero seq_rtt is given to RTT estimator (it will be effective 
> only in the case w/o timestamps, TS case recalculates it from the stored 
> timestamps). Maybe we could use some field (timestamp related one comes to 
> my mind) in request sock to get a real RTT estimate for non-timestamp case 
> too. ...It seems possible to me, though tricky because the request_sock is 
> no longer that easily available here so some parameter passing would be 
> needed.

Agreed.

But even more simply I think we should make even the current
tcp_ack_update_rtt() call here conditional on at least
tp->srtt being zero.

Damian do you at least agree with that?

^ permalink raw reply

* [PATCH 1/1] ARC vmac ethernet driver.
From: Andreas Fenkart @ 2010-02-22  0:21 UTC (permalink / raw)
  To: netdev; +Cc: Andreas Fenkart


Signed-off-by: Andreas Fenkart <andreas.fenkart@streamunlimited.com>
---
 drivers/net/Makefile       |    1 +
 drivers/net/arcvmac.c      | 1499 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/arcvmac.h      |  122 ++++
 drivers/net/arcvmac_fifo.h |  109 ++++
 4 files changed, 1731 insertions(+), 0 deletions(-)

diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 2aff98c..0095022 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -134,6 +134,7 @@ obj-$(CONFIG_ULTRA32) += smc-ultra32.o 8390.o
 obj-$(CONFIG_E2100) += e2100.o 8390.o
 obj-$(CONFIG_ES3210) += es3210.o 8390.o
 obj-$(CONFIG_LNE390) += lne390.o 8390.o
+obj-$(CONFIG_ARCVMAC) += arcvmac.o
 obj-$(CONFIG_NE3210) += ne3210.o 8390.o
 obj-$(CONFIG_SB1250_MAC) += sb1250-mac.o
 obj-$(CONFIG_B44) += b44.o
diff --git a/drivers/net/arcvmac.c b/drivers/net/arcvmac.c
new file mode 100644
index 0000000..82fa3e6
--- /dev/null
+++ b/drivers/net/arcvmac.c
@@ -0,0 +1,1499 @@
+/*
+ * linux/arch/arc/drivers/arcvmac.c
+ *
+ * Copyright (C) 2003-2006 Codito Technologies, for linux-2.4 port
+ * Copyright (C) 2006-2007 Celunite Inc, for linux-2.6 port
+ * Copyright (C) 2007-2008 Sagem Communications, Fehmi HAFSI
+ * Copyright (C) 2009 Sagem Communications, Andreas Fenkart
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * external PHY support based on dnet.c
+ * ring management based on bcm63xx_enet.c
+ *
+ * Authors: amit.bhor@celunite.com, sameer.dhavale@celunite.com
+ */
+
+#undef DEBUG
+
+#include <linux/clk.h>
+#include <linux/crc32.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/etherdevice.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include "arcvmac.h"
+#include "arcvmac_fifo.h"
+
+static char *mac_addr;
+module_param(mac_addr, charp, 0644);
+MODULE_PARM_DESC(mac_addr, "MAC address as colon separated hexadecimals");
+
+struct vmac_buffer_desc {
+	unsigned int info;
+	dma_addr_t data;
+};
+
+struct	vmac_priv {
+	struct net_device *dev;
+	struct platform_device *pdev;
+	struct net_device_stats stats;
+
+	spinlock_t lock; /* TODO revisit */
+	struct completion mdio_complete;
+
+	/* base address of register set */
+	int *regs;
+	unsigned int mem_base;
+
+	/* DMA ring buffers */
+	struct vmac_buffer_desc *rxbd;
+	dma_addr_t rxbd_dma;
+
+	struct vmac_buffer_desc *txbd;
+	dma_addr_t txbd_dma;
+
+	/* socket buffers */
+	struct sk_buff *rx_skbuff[RX_BDT_LEN];
+	struct sk_buff *tx_skbuff[TX_BDT_LEN];
+	int rx_skb_size;
+
+	/* skb / dma desc managing */
+	struct dma_fifo rx_ring;
+	struct dma_fifo tx_ring;
+
+	/* descriptor last polled/processed by the VMAC */
+	unsigned long mac_rxring_head;
+	/* used when rx skb allocation failed, so we defer rx queue
+	 * refill */
+	struct timer_list rx_timeout;
+
+	/* lock rx_timeout against rx normal operation */
+	spinlock_t rx_lock;
+
+	struct napi_struct napi;
+
+	/* rx buffer chaining */
+	int rx_merge_error;
+	int tx_timeout_error;
+
+	/* PHY stuff */
+	struct mii_bus *mii_bus;
+	struct phy_device *phy_dev;
+
+	int link;
+	int speed;
+	int duplex;
+
+	/* debug */
+	int shutdown;
+};
+
+static void parse_mac_addr_param(struct net_device *dev,
+		char *module_param)
+{
+	struct sockaddr saddr;
+	unsigned char *hwaddr = saddr.sa_data;
+
+	sscanf(module_param, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
+			&hwaddr[0],
+			&hwaddr[1],
+			&hwaddr[2],
+			&hwaddr[3],
+			&hwaddr[4],
+			&hwaddr[5]);
+
+	eth_mac_addr(dev, &saddr);
+}
+
+/* Register access macros */
+#define vmac_writel(port, value, reg)	\
+	writel((value), (port)->regs + reg##_OFFSET)
+#define vmac_readl(port, reg)	readl((port)->regs + reg##_OFFSET)
+
+static unsigned char *read_mac_reg(struct net_device *dev,
+		unsigned char hwaddr[ETH_ALEN])
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	unsigned mac_lo, mac_hi;
+
+	BUG_ON(!hwaddr);
+	mac_lo = vmac_readl(ap, ADDRL);
+	mac_hi = vmac_readl(ap, ADDRH);
+
+	hwaddr[0] = (mac_lo >> 0) & 0xff;
+	hwaddr[1] = (mac_lo >> 8) & 0xff;
+	hwaddr[2] = (mac_lo >> 16) & 0xff;
+	hwaddr[3] = (mac_lo >> 24) & 0xff;
+	hwaddr[4] = (mac_hi >> 0) & 0xff;
+	hwaddr[5] = (mac_hi >> 8) & 0xff;
+	return hwaddr;
+}
+
+static void write_mac_reg(struct net_device *dev, unsigned char* hwaddr)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	unsigned mac_lo, mac_hi;
+
+	mac_lo = hwaddr[3] << 24 | hwaddr[2] << 16 | hwaddr[1] << 8 | hwaddr[0];
+	mac_hi = hwaddr[5] << 8 | hwaddr[4];
+
+	vmac_writel(ap, mac_lo, ADDRL);
+	vmac_writel(ap, mac_hi, ADDRH);
+}
+
+static void vmac_mdio_xmit(struct vmac_priv *ap, unsigned val)
+{
+	init_completion(&ap->mdio_complete);
+	vmac_writel(ap, val, MDIO_DATA);
+	wait_for_completion(&ap->mdio_complete);
+}
+
+static int vmac_mdio_read(struct mii_bus *bus, int phy_id, int phy_reg)
+{
+	struct vmac_priv *vmac = bus->priv;
+	unsigned int val;
+	/* only 5 bits allowed for phy-addr and reg_offset */
+	BUG_ON(phy_id & ~0x1f || phy_reg & ~0x1f);
+
+	val = MDIO_BASE | MDIO_OP_READ;
+	val |= phy_id << 23 | phy_reg << 18;
+	vmac_mdio_xmit(vmac, val);
+
+	val = vmac_readl(vmac, MDIO_DATA);
+	return val & MDIO_DATA_MASK;
+}
+
+static int vmac_mdio_write(struct mii_bus *bus, int phy_id, int phy_reg,
+			 u16 value)
+{
+	struct vmac_priv *vmac = bus->priv;
+	unsigned int val;
+	/* only 5 bits allowed for phy-addr and reg_offset */
+	BUG_ON(phy_id & ~0x1f || phy_reg & ~0x1f);
+
+	val = MDIO_BASE | MDIO_OP_WRITE;
+	val |= phy_id << 23 | phy_reg << 18;
+	val |= (value & MDIO_DATA_MASK);
+	vmac_mdio_xmit(vmac, val);
+	return 0;
+}
+
+static void vmac_handle_link_change(struct net_device *dev)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	struct phy_device *phydev = ap->phy_dev;
+	unsigned long flags;
+	int report_change = 0;
+
+	spin_lock_irqsave(&ap->lock, flags);
+
+	if (phydev->duplex != ap->duplex) {
+		unsigned tmp;
+
+		tmp = vmac_readl(ap, ENABLE);
+
+		if (phydev->duplex)
+			tmp |= ENFL_MASK;
+		else
+			tmp &= ~ENFL_MASK;
+
+		vmac_writel(ap, tmp, ENABLE);
+
+		ap->duplex = phydev->duplex;
+		report_change = 1;
+	}
+
+	if (phydev->speed != ap->speed) {
+		ap->speed = phydev->speed;
+		report_change = 1;
+	}
+
+	if (phydev->link != ap->link) {
+		ap->link = phydev->link;
+		report_change = 1;
+	}
+
+	spin_unlock_irqrestore(&ap->lock, flags);
+
+	if (report_change)
+		phy_print_status(ap->phy_dev);
+}
+
+static int __devinit vmac_mii_probe(struct net_device *dev)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	struct phy_device *phydev = NULL;
+	struct clk *sys_clk;
+	unsigned long clock_rate;
+	int phy_addr, err;
+
+	/* find the first phy */
+	for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
+		if (ap->mii_bus->phy_map[phy_addr]) {
+			phydev = ap->mii_bus->phy_map[phy_addr];
+			break;
+		}
+	}
+
+	if (!phydev) {
+		dev_err(&dev->dev, "no PHY found\n");
+		return -ENODEV;
+	}
+
+	/* FIXME: add pin_irq, if avail */
+
+	phydev = phy_connect(dev, dev_name(&phydev->dev),
+			&vmac_handle_link_change, 0,
+			PHY_INTERFACE_MODE_MII);
+
+	if (IS_ERR(phydev)) {
+		err = PTR_ERR(phydev);
+		dev_err(&dev->dev, "could not attach to PHY %d\n", err);
+		goto err_out;
+	}
+
+	phydev->supported &= PHY_BASIC_FEATURES;
+	phydev->supported |= SUPPORTED_Asym_Pause | SUPPORTED_Pause;
+
+	sys_clk = clk_get(&ap->pdev->dev, "arcvmac");
+	if (IS_ERR(sys_clk)) {
+		err = PTR_ERR(sys_clk);
+		goto err_disconnect;
+	}
+
+	clock_rate = clk_get_rate(sys_clk);
+	clk_put(sys_clk);
+
+	dev_dbg(&ap->pdev->dev, "clk_get: dev_name : %s %lu\n",
+			dev_name(&ap->pdev->dev),
+			clock_rate);
+
+	if (clock_rate < 25000000)
+		phydev->supported &= ~(SUPPORTED_100baseT_Half |
+				SUPPORTED_100baseT_Full);
+
+	phydev->advertising = phydev->supported;
+
+	ap->link = 0;
+	ap->speed = 0;
+	ap->duplex = -1;
+	ap->phy_dev = phydev;
+
+	return 0;
+
+err_disconnect:
+	phy_disconnect(phydev);
+err_out:
+	return err;
+}
+
+static int __devinit vmac_mii_init(struct vmac_priv *ap)
+{
+	int err, i;
+
+	ap->mii_bus = mdiobus_alloc();
+	if (ap->mii_bus == NULL)
+		return -ENOMEM;
+
+	ap->mii_bus->name = "vmac_mii_bus";
+	ap->mii_bus->read = &vmac_mdio_read;
+	ap->mii_bus->write = &vmac_mdio_write;
+
+	snprintf(ap->mii_bus->id, MII_BUS_ID_SIZE, "%x", 0);
+
+	ap->mii_bus->priv = ap;
+
+	err = -ENOMEM;
+	ap->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
+	if (!ap->mii_bus->irq)
+		goto err_out;
+
+	for (i = 0; i < PHY_MAX_ADDR; i++)
+		ap->mii_bus->irq[i] = PHY_POLL;
+
+#if 0
+	/* FIXME: what is it used for? */
+	platform_set_drvdata(ap->dev, ap->mii_bus);
+#endif
+
+	err = mdiobus_register(ap->mii_bus);
+	if (err)
+		goto err_out_free_mdio_irq;
+
+	err = vmac_mii_probe(ap->dev);
+	if (err)
+		goto err_out_unregister_bus;
+
+	return 0;
+
+err_out_unregister_bus:
+	mdiobus_unregister(ap->mii_bus);
+err_out_free_mdio_irq:
+	kfree(ap->mii_bus->irq);
+err_out:
+	mdiobus_free(ap->mii_bus);
+	return err;
+}
+
+static void vmac_mii_exit(struct net_device *dev)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+
+	if (ap->phy_dev)
+		phy_disconnect(ap->phy_dev);
+
+	mdiobus_unregister(ap->mii_bus);
+	kfree(ap->mii_bus->irq);
+	mdiobus_free(ap->mii_bus);
+}
+
+static int vmacether_get_settings(struct net_device *dev,
+    struct ethtool_cmd *cmd)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	struct phy_device *phydev = ap->phy_dev;
+
+	if (!phydev)
+		return -ENODEV;
+
+	return phy_ethtool_gset(phydev, cmd);
+}
+
+static int vmacether_set_settings(struct net_device *dev,
+    struct ethtool_cmd *cmd)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	struct phy_device *phydev = ap->phy_dev;
+
+	if (!phydev)
+		return -ENODEV;
+
+	return phy_ethtool_sset(phydev, cmd);
+}
+
+static int vmac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	struct phy_device *phydev = ap->phy_dev;
+
+	if (!netif_running(dev))
+		return -EINVAL;
+
+	if (!phydev)
+		return -ENODEV;
+
+	return phy_mii_ioctl(phydev, if_mii(rq), cmd);
+}
+
+static void vmacether_get_drvinfo(struct net_device *dev,
+    struct ethtool_drvinfo *info)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+
+	strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+	snprintf(info->bus_info, sizeof(info->bus_info),
+			"platform 0x%x", ap->mem_base);
+}
+
+static int update_error_counters(struct net_device *dev, int status)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	dev_dbg(&ap->pdev->dev, "rx error counter overrun. status = 0x%x\n",
+			status);
+
+	/* programming error */
+	BUG_ON(status & TXCH_MASK);
+	BUG_ON(!(status & (MSER_MASK | RXCR_MASK | RXFR_MASK | RXFL_MASK)));
+
+	if (status & MSER_MASK)
+		ap->stats.rx_over_errors += 256; /* ran out of BD */
+	if (status & RXCR_MASK)
+		ap->stats.rx_crc_errors += 256;
+	if (status & RXFR_MASK)
+		ap->stats.rx_frame_errors += 256;
+	if (status & RXFL_MASK)
+		ap->stats.rx_fifo_errors += 256;
+
+	return 0;
+}
+
+static void update_tx_errors(struct net_device *dev, int status)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+
+	if (status & UFLO)
+		ap->stats.tx_fifo_errors++;
+
+	if (ap->duplex)
+		return;
+
+	/* half duplex flags */
+	if (status & LTCL)
+		ap->stats.tx_window_errors++;
+	if (status & RETRY_CT)
+		ap->stats.collisions += (status & RETRY_CT) >> 24;
+	if (status & DROP)  /* too many retries */
+		ap->stats.tx_aborted_errors++;
+	if (status & DEFER)
+		dev_vdbg(&ap->pdev->dev, "\"defer to traffic\"\n");
+	if (status & CARLOSS)
+		ap->stats.tx_carrier_errors++;
+}
+
+static int vmac_rx_reclaim_force(struct net_device *dev)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	int ct;
+
+	ct = 0;
+
+	dev_dbg(&ap->pdev->dev, "%s need to release %d rx sk_buff\n",
+	    __func__, fifo_used(&ap->rx_ring));
+
+	while (!fifo_empty(&ap->rx_ring) && ct++ < ap->rx_ring.size) {
+		struct vmac_buffer_desc *desc;
+		struct sk_buff *skb;
+		int desc_idx;
+
+		desc_idx = ap->rx_ring.tail;
+		desc = &ap->rxbd[desc_idx];
+		fifo_inc_tail(&ap->rx_ring);
+
+		if (!ap->rx_skbuff[desc_idx]) {
+			dev_err(&ap->pdev->dev, "non-populated rx_skbuff found %d\n",
+					desc_idx);
+			continue;
+		}
+
+		skb = ap->rx_skbuff[desc_idx];
+		ap->rx_skbuff[desc_idx] = NULL;
+
+		dma_unmap_single(&ap->pdev->dev, desc->data, skb->len,
+		    DMA_TO_DEVICE);
+
+		dev_kfree_skb(skb);
+	}
+
+	if (!fifo_empty(&ap->rx_ring)) {
+		dev_err(&ap->pdev->dev, "failed to reclaim %d rx sk_buff\n",
+				fifo_used(&ap->rx_ring));
+	}
+
+	return 0;
+}
+
+static int vmac_rx_refill(struct net_device *dev)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+
+	BUG_ON(fifo_full(&ap->rx_ring));
+
+	while (!fifo_full(&ap->rx_ring)) {
+		struct vmac_buffer_desc *desc;
+		struct sk_buff *skb;
+		dma_addr_t p;
+		int desc_idx;
+
+		desc_idx = ap->rx_ring.head;
+		desc = &ap->rxbd[desc_idx];
+
+		/* make sure we read the actual descriptor status */
+		rmb();
+
+		if (ap->rx_skbuff[desc_idx]) {
+			/* dropped packet / buffer chaining */
+			fifo_inc_head(&ap->rx_ring);
+
+			/* return to DMA */
+			wmb();
+			desc->info = OWN_MASK | ap->rx_skb_size;
+			continue;
+		}
+
+		skb = netdev_alloc_skb(dev, ap->rx_skb_size + 2);
+		if (!skb) {
+			dev_info(&ap->pdev->dev, "failed to allocate rx_skb, skb's left %d\n",
+					fifo_used(&ap->rx_ring));
+			break;
+		}
+
+		/* IP header Alignment (14 byte Ethernet header) */
+		skb_reserve(skb, 2);
+		BUG_ON(skb->len != 0); /* nothing received yet */
+
+		ap->rx_skbuff[desc_idx] = skb;
+
+		/* TODO +2 okay with alignment? */
+		p = dma_map_single(&ap->pdev->dev, skb->data, ap->rx_skb_size,
+				DMA_FROM_DEVICE);
+
+		desc->data = p;
+
+		wmb();
+		desc->info = OWN_MASK | ap->rx_skb_size;
+
+		fifo_inc_head(&ap->rx_ring);
+	}
+
+	/* If rx ring is still empty, set a timer to try allocating
+	 * again at a later time. */
+	if (fifo_empty(&ap->rx_ring) && netif_running(dev)) {
+		dev_warn(&ap->pdev->dev, "unable to refill rx ring\n");
+		ap->rx_timeout.expires = jiffies + HZ;
+		add_timer(&ap->rx_timeout);
+	}
+
+	return 0;
+}
+
+/*
+ * timer callback to defer refill rx queue in case we're OOM
+ */
+static void vmac_refill_rx_timer(unsigned long data)
+{
+	struct net_device *dev;
+	struct vmac_priv *ap;
+
+	dev = (struct net_device *)data;
+	ap = netdev_priv(dev);
+
+	spin_lock(&ap->rx_lock);
+	vmac_rx_refill(dev);
+	spin_unlock(&ap->rx_lock);
+}
+
+/* merge buffer chaining  */
+struct sk_buff *vmac_merge_rx_buffers(struct net_device *dev,
+		struct vmac_buffer_desc *after,
+		int pkt_len) /* data */
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	struct sk_buff *merge_skb, *cur_skb;
+	struct dma_fifo *rx_ring;
+	struct vmac_buffer_desc *desc;
+
+	rx_ring = &ap->rx_ring;
+	desc = &ap->rxbd[rx_ring->tail];
+
+	BUG_ON(desc == after);
+
+	/* strip FCS */
+	pkt_len -= 4;
+
+	/* IP header Alignment (14 byte Ethernet header) */
+	merge_skb = netdev_alloc_skb(dev, pkt_len + 2);
+	if (!merge_skb) {
+		dev_err(&ap->pdev->dev, "failed to allocate merged rx_skb, rx skb's left %d\n",
+				fifo_used(rx_ring));
+
+		return NULL;
+	}
+
+	skb_reserve(merge_skb, 2);
+
+	while (desc != after && pkt_len) {
+		struct vmac_buffer_desc *desc;
+		int buf_len, valid;
+
+		/* desc needs wrapping */
+		desc = &ap->rxbd[rx_ring->tail];
+		cur_skb = ap->rx_skbuff[rx_ring->tail];
+		BUG_ON(!cur_skb);
+
+		dma_unmap_single(&ap->pdev->dev, desc->data, ap->rx_skb_size,
+				DMA_FROM_DEVICE);
+
+		/* do not copy FCS */
+		buf_len = desc->info & LEN_MASK;
+		valid = min(pkt_len, buf_len);
+		pkt_len -= valid;
+
+		memcpy(skb_put(merge_skb, valid), cur_skb->data, valid);
+
+		fifo_inc_tail(rx_ring);
+	}
+
+	/* merging_pressure++ */
+
+#ifdef DEBUG
+	if (pkt_len != 0)
+		dev_err(&ap->pdev->dev, "buffer chaining bytes missing %d\n", pkt_len);
+#endif
+
+	BUG_ON(desc != after);
+
+	return merge_skb;
+}
+
+int vmac_rx_receive(struct net_device *dev, int budget)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	struct vmac_buffer_desc *first;
+	int processed, pkt_len, pkt_err;
+	struct dma_fifo lookahead;
+
+	processed = 0;
+
+	first = NULL;
+	pkt_err = pkt_len = 0;
+
+	/* look ahead, till packet complete */
+	lookahead = ap->rx_ring;
+
+	do {
+		struct vmac_buffer_desc *desc; /* cur_ */
+		int desc_idx; /* cur_ */
+		struct sk_buff *skb; /* pkt_ */
+
+		desc_idx = lookahead.tail;
+		desc = &ap->rxbd[desc_idx];
+
+		/* make sure we read the actual descriptor status */
+		rmb();
+
+		/* break if dma ownership belongs to hw */
+		if (desc->info & OWN_MASK) {
+			ap->mac_rxring_head = vmac_readl(ap, MAC_RXRING_HEAD);
+			break;
+		}
+
+		if (desc->info & FRST_MASK) {
+			pkt_len = 0;
+			pkt_err = 0;
+
+			/* don't free current */
+			ap->rx_ring.tail = lookahead.tail;
+			first = desc;
+		}
+
+		fifo_inc_tail(&lookahead);
+
+		/* check bd */
+
+		pkt_len += desc->info & LEN_MASK;
+		pkt_err |= (desc->info & BUFF);
+
+		if (!(desc->info & LAST_MASK))
+			continue;
+
+		/* received complete packet */
+
+		if (unlikely(pkt_err || !first)) {
+			/* recycle buffers */
+			ap->rx_ring.tail = lookahead.tail;
+			continue;
+		}
+
+#ifdef DEBUG
+		BUG_ON(!(first->info & FRST_MASK) || !(desc->info & LAST_MASK));
+		BUG_ON(pkt_err);
+#endif
+
+		/* -- valid packet -- */
+
+		if (first != desc) {
+			skb = vmac_merge_rx_buffers(dev, desc, pkt_len);
+
+			if (!skb) {
+				/* kill packet */
+				ap->rx_ring.tail = lookahead.tail;
+				ap->rx_merge_error++;
+				continue;
+			}
+		} else {
+			dma_unmap_single(&ap->pdev->dev, desc->data,
+					ap->rx_skb_size, DMA_FROM_DEVICE);
+
+			skb = ap->rx_skbuff[desc_idx];
+			ap->rx_skbuff[desc_idx] = NULL;
+			/* desc->data != skb->data => desc->data is DMA mapped */
+
+			/* strip FCS */
+			skb_put(skb, pkt_len - 4);
+		}
+
+		/* free buffers */
+		ap->rx_ring.tail = lookahead.tail;
+
+#ifdef DEBUG
+		BUG_ON(skb->len != pkt_len - 4);
+#endif
+		processed++;
+		skb->dev = dev;
+		skb->protocol = eth_type_trans(skb, dev);
+		ap->stats.rx_packets++;
+		ap->stats.rx_bytes += skb->len;
+		dev->last_rx = jiffies;
+		netif_rx(skb);
+
+	} while (!fifo_empty(&lookahead) && (processed < budget));
+
+	dev_vdbg(&ap->pdev->dev, "processed pkt %d, remaining rx buff %d\n",
+			processed,
+			fifo_used(&ap->rx_ring));
+
+	if (processed || fifo_empty(&ap->rx_ring))
+		vmac_rx_refill(dev);
+
+	return processed;
+}
+
+static void vmac_toggle_irqmask(struct net_device *dev, int enable, int mask)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	unsigned long tmp;
+
+	tmp = vmac_readl(ap, ENABLE);
+	if (enable)
+		tmp |= mask;
+	else
+		tmp &= ~mask;
+	vmac_writel(ap, tmp, ENABLE);
+}
+
+static void vmac_toggle_txint(struct net_device *dev, int enable)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	unsigned long flags;
+
+	spin_lock_irqsave(&ap->lock, flags);
+	vmac_toggle_irqmask(dev, enable, TXINT_MASK);
+	spin_unlock_irqrestore(&ap->lock, flags);
+}
+
+static void vmac_toggle_rxint(struct net_device *dev, int enable)
+{
+	vmac_toggle_irqmask(dev, enable, RXINT_MASK);
+}
+
+static int vmac_poll(struct napi_struct *napi, int budget)
+{
+	struct vmac_priv *ap;
+	struct net_device *dev;
+	int rx_work_done;
+	unsigned long flags;
+
+	ap = container_of(napi, struct vmac_priv, napi);
+	dev = ap->dev;
+
+	/* ack interrupt */
+	vmac_writel(ap, RXINT_MASK, STAT);
+
+	spin_lock(&ap->rx_lock);
+	rx_work_done = vmac_rx_receive(dev, budget);
+	spin_unlock(&ap->rx_lock);
+
+	if (0 && printk_ratelimit()) {
+		dev_dbg(&ap->pdev->dev, "poll budget %d receive rx_work_done %d\n",
+				budget,
+				rx_work_done);
+	}
+
+	if (rx_work_done >= budget) {
+		/* rx queue is not yet empty/clean */
+		return rx_work_done;
+	}
+
+	/* no more packet in rx/tx queue, remove device from poll
+	 * queue */
+	spin_lock_irqsave(&ap->lock, flags);
+	napi_complete(napi);
+	vmac_toggle_rxint(dev, 1);
+	spin_unlock_irqrestore(&ap->lock, flags);
+
+	return rx_work_done;
+}
+
+static int vmac_tx_reclaim(struct net_device *dev, int force);
+
+static irqreturn_t vmac_intr(int irq, void *dev_instance)
+{
+	struct net_device *dev = dev_instance;
+	struct vmac_priv *ap = netdev_priv(dev);
+	unsigned int status;
+
+	spin_lock(&ap->lock);
+
+	status = vmac_readl(ap, STAT);
+	vmac_writel(ap, status, STAT);
+
+#ifdef DEBUG
+	if (unlikely(ap->shutdown))
+		dev_err(&ap->pdev->dev, "ISR during close\n");
+
+	if (unlikely(!status & (RXINT_MASK|MDIO_MASK|ERR_MASK)))
+		dev_err(&ap->pdev->dev, "No source of IRQ found\n");
+#endif
+
+	if ((status & RXINT_MASK) &&
+			(ap->mac_rxring_head !=
+			 vmac_readl(ap, MAC_RXRING_HEAD))) {
+		vmac_toggle_rxint(dev, 0);
+		napi_schedule(&ap->napi);
+	}
+
+	if (unlikely(netif_queue_stopped(dev) && (status & TXINT_MASK)))
+		vmac_tx_reclaim(dev, 0);
+
+	if (status & MDIO_MASK)
+		complete(&ap->mdio_complete);
+
+	if (unlikely(status & ERR_MASK))
+		update_error_counters(dev, status);
+
+	spin_unlock(&ap->lock);
+
+	return IRQ_HANDLED;
+}
+
+static int vmac_tx_reclaim(struct net_device *dev, int force)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	int released = 0;
+
+	/* buffer chaining not used, see vmac_start_xmit */
+
+	while (!fifo_empty(&ap->tx_ring)) {
+		struct vmac_buffer_desc *desc;
+		struct sk_buff *skb;
+		int desc_idx;
+
+		desc_idx = ap->tx_ring.tail;
+		desc = &ap->txbd[desc_idx];
+
+		/* ensure other field of the descriptor were not read
+		 * before we checked ownership */
+		rmb();
+
+		if ((desc->info & OWN_MASK) && !force)
+			break;
+
+		if (desc->info & ERR_MSK_TX) {
+			update_tx_errors(dev, desc->info);
+			/* recycle packet, let upper level deal with it */
+		}
+
+		skb = ap->tx_skbuff[desc_idx];
+		ap->tx_skbuff[desc_idx] = NULL;
+		BUG_ON(!skb);
+
+		dma_unmap_single(&ap->pdev->dev, desc->data, skb->len,
+				DMA_TO_DEVICE);
+
+		dev_kfree_skb_any(skb);
+
+		released++;
+		fifo_inc_tail(&ap->tx_ring);
+	}
+
+	if (netif_queue_stopped(dev) && released) {
+		netif_wake_queue(dev);
+		vmac_toggle_txint(dev, 0);
+	}
+
+	if (unlikely(force && !fifo_empty(&ap->tx_ring))) {
+		dev_err(&ap->pdev->dev, "failed to reclaim %d tx sk_buff\n",
+				fifo_used(&ap->tx_ring));
+	}
+
+	return released;
+}
+
+int vmac_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	struct vmac_buffer_desc *desc;
+	unsigned int tmp;
+
+	/* running under xmit lock */
+
+	/* no scatter/gatter see features below */
+	BUG_ON(skb_shinfo(skb)->nr_frags != 0);
+	BUG_ON(skb->len > MAX_TX_BUFFER_LEN);
+
+	if (unlikely(fifo_full(&ap->tx_ring))) {
+		netif_stop_queue(dev);
+		vmac_toggle_txint(dev, 1);
+		dev_err(&ap->pdev->dev, "xmit called with no tx desc available\n");
+		return NETDEV_TX_BUSY;
+	}
+
+	if (unlikely(skb->len < ETH_ZLEN)) {
+		struct sk_buff *short_skb;
+		short_skb = netdev_alloc_skb(dev, ETH_ZLEN);
+		if (!short_skb)
+			return NETDEV_TX_LOCKED;
+
+		memset(short_skb->data, 0, ETH_ZLEN);
+		memcpy(skb_put(short_skb, ETH_ZLEN), skb->data, skb->len);
+		dev_kfree_skb(skb);
+		skb = short_skb;
+	}
+
+	/* fill descriptor */
+	ap->tx_skbuff[ap->tx_ring.head] = skb;
+
+	desc = &ap->txbd[ap->tx_ring.head];
+	desc->data = dma_map_single(&ap->pdev->dev, skb->data, skb->len,
+			DMA_TO_DEVICE);
+
+	/* dma might already be polling */
+	wmb();
+	desc->info = OWN_MASK | FRST_MASK | LAST_MASK | skb->len;
+	wmb();
+
+	/* kick tx dma */
+	tmp = vmac_readl(ap, STAT);
+	vmac_writel(ap, tmp | TXPL_MASK, STAT);
+
+	ap->stats.tx_packets++;
+	ap->stats.tx_bytes += skb->len;
+	dev->trans_start = jiffies;
+	fifo_inc_head(&ap->tx_ring);
+
+	/* vmac_tx_reclaim independent of vmac_tx_timeout */
+	if (fifo_used(&ap->tx_ring) > 8)
+		vmac_tx_reclaim(dev, 0);
+
+	/* stop queue if no more desc available */
+	if (fifo_full(&ap->tx_ring)) {
+		netif_stop_queue(dev);
+		vmac_toggle_txint(dev, 1);
+	}
+
+	return NETDEV_TX_OK;
+}
+
+static int alloc_buffers(struct net_device *dev)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	int err = -ENOMEM;
+	int size;
+
+	fifo_init(&ap->rx_ring, RX_BDT_LEN);
+	fifo_init(&ap->tx_ring, TX_BDT_LEN);
+
+	/* initialize skb list */
+	memset(ap->rx_skbuff, 0, sizeof(ap->rx_skbuff));
+	memset(ap->tx_skbuff, 0, sizeof(ap->tx_skbuff));
+
+	/* allocate DMA received descriptors */
+	size = sizeof(*ap->rxbd) * ap->rx_ring.size;
+	ap->rxbd = dma_alloc_coherent(&ap->pdev->dev, size,
+			&ap->rxbd_dma,
+			GFP_KERNEL);
+	if (ap->rxbd == NULL)
+		goto err_out;
+
+	/* allocate DMA transmit descriptors */
+	size = sizeof(*ap->txbd) * ap->tx_ring.size;
+	ap->txbd = dma_alloc_coherent(&ap->pdev->dev, size,
+			&ap->txbd_dma,
+			GFP_KERNEL);
+	if (ap->txbd == NULL)
+		goto err_free_rxbd;
+
+	/* ensure 8-byte aligned */
+	BUG_ON(((int)ap->txbd & 0x7) || ((int)ap->rxbd & 0x7));
+
+	memset(ap->txbd, 0, sizeof(*ap->txbd) * ap->tx_ring.size);
+	memset(ap->rxbd, 0, sizeof(*ap->rxbd) * ap->rx_ring.size);
+
+	/* allocate rx skb */
+	err = vmac_rx_refill(dev);
+	if (err)
+		goto err_free_txbd;
+
+	return 0;
+
+err_free_txbd:
+	dma_free_coherent(&ap->pdev->dev, sizeof(*ap->txbd) * ap->tx_ring.size,
+			ap->txbd, ap->txbd_dma);
+err_free_rxbd:
+	dma_free_coherent(&ap->pdev->dev, sizeof(*ap->rxbd) * ap->rx_ring.size,
+			ap->rxbd, ap->rxbd_dma);
+err_out:
+	return err;
+}
+
+static int free_buffers(struct net_device *dev)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+
+	/* free skbuff */
+	vmac_tx_reclaim(dev, 1);
+	vmac_rx_reclaim_force(dev);
+
+	/* free DMA ring */
+	dma_free_coherent(&ap->pdev->dev, sizeof(ap->txbd) * ap->tx_ring.size,
+			ap->txbd, ap->txbd_dma);
+	dma_free_coherent(&ap->pdev->dev, sizeof(ap->rxbd) * ap->rx_ring.size,
+			ap->rxbd, ap->rxbd_dma);
+
+	return 0;
+}
+
+static int vmac_hw_init(struct net_device *dev)
+{
+	struct vmac_priv *priv = netdev_priv(dev);
+
+	/* clear IRQ mask */
+	vmac_writel(priv, 0, ENABLE);
+
+	/* clear pending IRQ */
+	vmac_writel(priv, 0xffffffff, STAT);
+
+	/* Initialize logical address filter */
+	vmac_writel(priv, 0x0, LAFL);
+	vmac_writel(priv, 0x0, LAFH);
+
+	return 0;
+}
+
+int vmac_open(struct net_device *dev)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	struct phy_device *phydev;
+	unsigned int temp;
+	int err = 0;
+
+	if (ap == NULL)
+		return -ENODEV;
+
+	ap->shutdown = 0;
+
+	vmac_hw_init(dev);
+
+	/* mac address changed? */
+	write_mac_reg(dev, dev->dev_addr);
+
+	err = alloc_buffers(dev);
+	if (err)
+		goto err_out;
+
+	err = request_irq(dev->irq, &vmac_intr, 0, dev->name, dev);
+	if (err) {
+		dev_err(&ap->pdev->dev, "Unable to request IRQ %d (error %d)\n",
+				dev->irq, err);
+		goto err_free_buffers;
+	}
+
+	/* install DMA ring pointers */
+	vmac_writel(ap, ap->rxbd_dma, RXRINGPTR);
+	vmac_writel(ap, ap->txbd_dma, TXRINGPTR);
+
+	/* set poll rate to 1 ms */
+	vmac_writel(ap, POLLRATE_TIME, POLLRATE);
+
+	/* make sure we enable napi before rx interrupt  */
+	napi_enable(&ap->napi);
+
+	/* IRQ mask */
+	temp = RXINT_MASK | ERR_MASK | TXCH_MASK | MDIO_MASK;
+	vmac_writel(ap, temp, ENABLE);
+
+	/* Set control */
+	temp = (RX_BDT_LEN << 24) | (TX_BDT_LEN << 16) | TXRN_MASK | RXRN_MASK;
+	vmac_writel(ap, temp, CONTROL);
+
+	/* enable, after all other bits are set */
+	vmac_writel(ap, temp | EN_MASK, CONTROL);
+
+	netif_start_queue(dev);
+	netif_carrier_off(dev);
+
+	/* register the PHY board fixup, if needed */
+	err = vmac_mii_init(ap);
+	if (err)
+		goto err_free_irq;
+
+	/* schedule a link state check */
+	phy_start(ap->phy_dev);
+
+	phydev = ap->phy_dev;
+	dev_info(&ap->pdev->dev, "PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n",
+	       phydev->drv->name, dev_name(&phydev->dev), phydev->irq);
+
+	return 0;
+
+err_free_irq:
+	free_irq(dev->irq, dev);
+err_free_buffers:
+	free_buffers(dev);
+err_out:
+	return err;
+}
+
+int vmac_close(struct net_device *dev)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	unsigned int temp;
+
+	netif_stop_queue(dev);
+	napi_disable(&ap->napi);
+
+	/* stop running transfers */
+	temp = vmac_readl(ap, CONTROL);
+	temp &= ~(TXRN_MASK | RXRN_MASK);
+	vmac_writel(ap, temp, CONTROL);
+
+	del_timer_sync(&ap->rx_timeout);
+
+	/* disable phy */
+	phy_stop(ap->phy_dev);
+	vmac_mii_exit(dev);
+	netif_carrier_off(dev);
+
+	/* disable interrupts */
+	vmac_writel(ap, 0, ENABLE);
+	free_irq(dev->irq, dev);
+
+	/* turn off vmac */
+	vmac_writel(ap, 0, CONTROL);
+	/* vmac_reset_hw(vmac) */
+
+	ap->shutdown = 1;
+	wmb();
+
+	free_buffers(dev);
+	return 0;
+}
+
+void vmac_update_stats(struct vmac_priv *ap)
+{
+	struct net_device_stats *_stats = &ap->stats;
+	unsigned long miss, rxerr;
+	unsigned long rxfram, rxcrc, rxoflow;
+
+	/* compare with /proc/net/dev,
+	 * see net/core/dev.c:dev_seq_printf_stats */
+
+	/* rx stats */
+	rxerr = vmac_readl(ap, RXERR);
+	miss = vmac_readl(ap, MISS);
+
+	rxcrc = (rxerr & RXERR_CRC);
+	rxfram = (rxerr & RXERR_FRM) >> 8;
+	rxoflow = (rxerr & RXERR_OFLO) >> 16;
+
+	_stats->rx_length_errors = 0;
+	_stats->rx_over_errors += miss;
+	_stats->rx_crc_errors += rxcrc;
+	_stats->rx_frame_errors += rxfram;
+	_stats->rx_fifo_errors += rxoflow;
+	_stats->rx_missed_errors = 0;
+
+	/* TODO check rx_dropped/rx_errors/tx_dropped/tx_errors have not
+	 * been updated elsewhere */
+	_stats->rx_dropped = _stats->rx_over_errors +
+		_stats->rx_fifo_errors +
+		ap->rx_merge_error;
+
+	_stats->rx_errors = _stats->rx_length_errors + _stats->rx_crc_errors +
+		_stats->rx_frame_errors +
+		_stats->rx_missed_errors +
+		_stats->rx_dropped;
+
+	/* tx stats */
+	_stats->tx_dropped = 0; /* otherwise queue stopped */
+
+	_stats->tx_errors = _stats->tx_aborted_errors +
+		_stats->tx_carrier_errors +
+		_stats->tx_fifo_errors +
+		_stats->tx_heartbeat_errors +
+		_stats->tx_window_errors +
+		_stats->tx_dropped +
+		ap->tx_timeout_error;
+}
+
+struct net_device_stats *vmac_stats(struct net_device *dev)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	unsigned long flags;
+
+	spin_lock_irqsave(&ap->lock, flags);
+	vmac_update_stats(ap);
+	spin_unlock_irqrestore(&ap->lock, flags);
+
+	return &ap->stats;
+}
+
+void vmac_tx_timeout(struct net_device *dev)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	unsigned int status;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ap->lock, flags);
+
+	/* queue did not progress for timeo jiffies */
+	BUG_ON(!netif_queue_stopped(dev));
+	BUG_ON(!fifo_full(&ap->tx_ring));
+
+	/* TX IRQ lost? */
+	status = vmac_readl(ap, STAT);
+	if (status & TXINT_MASK) {
+		dev_err(&ap->pdev->dev, "lost tx interrupt, IRQ mask %x\n",
+				vmac_readl(ap, ENABLE));
+		vmac_writel(ap, TXINT_MASK, STAT);
+	}
+
+	/* TODO RX/MDIO/ERR as well? */
+
+	vmac_tx_reclaim(dev, 0);
+	if (fifo_full(&ap->tx_ring))
+		dev_err(&ap->pdev->dev, "DMA state machine not active\n");
+
+	/* We can accept TX packets again */
+	ap->tx_timeout_error++;
+	dev->trans_start = jiffies;
+	netif_wake_queue(dev);
+
+	spin_unlock_irqrestore(&ap->lock, flags);
+}
+
+static void create_multicast_filter(struct net_device *dev,
+	unsigned long *bitmask)
+{
+	struct dev_mc_list *mc_ptr;
+	unsigned long crc;
+	char *addrs;
+
+	BUG_ON(dev->mc_count == 0);
+	BUG_ON(dev->flags & IFF_ALLMULTI);
+
+	bitmask[0] = bitmask[1] = 0;
+	for (mc_ptr = dev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) {
+		addrs = mc_ptr->dmi_addr;
+
+		/* skip non-multicast addresses */
+		if (!(*addrs & 1))
+			continue;
+
+		crc = ether_crc_le(ETH_ALEN, addrs);
+		set_bit(crc >> 26, bitmask);
+	}
+}
+
+static void vmac_set_multicast_list(struct net_device *dev)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	unsigned long flags, bitmask[2];
+	int promisc, reg;
+
+	spin_lock_irqsave(&ap->lock, flags);
+
+	promisc = !!(dev->flags & IFF_PROMISC);
+	reg = vmac_readl(ap, ENABLE);
+	if (promisc != !!(reg & PROM_MASK)) {
+		reg ^= PROM_MASK;
+		vmac_writel(ap, reg, ENABLE);
+	}
+
+	if (dev->flags & IFF_ALLMULTI)
+		memset(bitmask, 1, sizeof(bitmask));
+	else if (dev->mc_count == 0)
+		memset(bitmask, 0, sizeof(bitmask));
+	else
+		create_multicast_filter(dev, bitmask);
+
+	vmac_writel(ap, bitmask[0], LAFL);
+	vmac_writel(ap, bitmask[1], LAFH);
+
+	spin_unlock_irqrestore(&ap->lock, flags);
+}
+
+static struct ethtool_ops vmac_ethtool_ops = {
+	.get_settings		= vmacether_get_settings,
+	.set_settings		= vmacether_set_settings,
+	.get_drvinfo		= vmacether_get_drvinfo,
+	.get_link		= ethtool_op_get_link,
+};
+
+static const struct net_device_ops vmac_netdev_ops = {
+	.ndo_open		= vmac_open,
+	.ndo_stop		= vmac_close,
+	.ndo_get_stats		= vmac_stats,
+	.ndo_start_xmit		= vmac_start_xmit,
+	.ndo_do_ioctl		= vmac_ioctl,
+	.ndo_set_mac_address	= eth_mac_addr,
+	.ndo_tx_timeout		= vmac_tx_timeout,
+	.ndo_set_multicast_list = vmac_set_multicast_list,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_change_mtu		= eth_change_mtu,
+};
+
+static int __devinit vmac_probe(struct platform_device *pdev)
+{
+	struct net_device *dev;
+	struct vmac_priv *ap;
+	struct resource *res;
+	unsigned int mem_base, mem_size, irq;
+	int err;
+
+	dev = alloc_etherdev(sizeof(*ap));
+	if (!dev) {
+		dev_err(&pdev->dev, "etherdev alloc failed, aborting.\n");
+		return -ENOMEM;
+	}
+
+	ap = netdev_priv(dev);
+
+	err = -ENODEV;
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "no mmio resource defined\n");
+		goto err_out;
+	}
+	mem_base = res->start;
+	mem_size = resource_size(res);
+	irq = platform_get_irq(pdev, 0);
+
+	err = -EBUSY;
+	if (!request_mem_region(mem_base, mem_size, DRV_NAME)) {
+		dev_err(&pdev->dev, "no memory region available\n");
+		goto err_out;
+	}
+
+	err = -ENOMEM;
+	ap->regs = ioremap(mem_base, mem_size);
+	if (!ap->regs) {
+		dev_err(&pdev->dev, "failed to map registers, aborting.\n");
+		goto err_out_release_mem;
+	}
+
+	/* no checksum support, hence no scatter/gather */
+	dev->features |= NETIF_F_HIGHDMA;
+
+	spin_lock_init(&ap->lock);
+
+	SET_NETDEV_DEV(dev, &pdev->dev);
+	ap->dev = dev;
+	ap->pdev = pdev;
+
+	/* init rx timeout (used for oom) */
+	init_timer(&ap->rx_timeout);
+	ap->rx_timeout.function = vmac_refill_rx_timer;
+	ap->rx_timeout.data = (unsigned long)dev;
+
+	netif_napi_add(dev, &ap->napi, vmac_poll, 2);
+	dev->netdev_ops = &vmac_netdev_ops;
+	dev->ethtool_ops = &vmac_ethtool_ops;
+	dev->irq = irq;
+
+	dev->flags |= IFF_MULTICAST;
+
+	dev->base_addr = (unsigned long)ap->regs;
+	ap->mem_base = mem_base;
+
+	/* prevent buffer chaining, favor speed over space */
+	ap->rx_skb_size = ETH_FRAME_LEN + VMAC_BUFFER_PAD;
+
+	/* private struct functional */
+
+	/* mac address intialize, set vmac_open  */
+	read_mac_reg(dev, dev->dev_addr);
+
+	if (!is_valid_ether_addr(dev->dev_addr))
+		random_ether_addr(dev->dev_addr);
+	if (mac_addr != NULL) {
+		/* overridde mac address by module parameter */
+		parse_mac_addr_param(dev, mac_addr);
+	}
+
+	err = register_netdev(dev);
+	if (err) {
+		dev_err(&pdev->dev, "Cannot register net device, aborting.\n");
+		goto err_out_iounmap;
+	}
+
+	dev_info(&pdev->dev, "ARC VMAC at 0x%08x irq %d %pM\n", mem_base,
+	    dev->irq, dev->dev_addr);
+	platform_set_drvdata(pdev, dev);
+
+	return 0;
+
+err_out_iounmap:
+	iounmap(ap->regs);
+err_out_release_mem:
+	release_mem_region(mem_base, mem_size);
+err_out:
+	free_netdev(dev);
+	return err;
+}
+
+static int __devexit vmac_remove(struct platform_device *pdev)
+{
+	struct net_device *dev;
+	struct vmac_priv *ap;
+	struct resource *res;
+
+	dev = platform_get_drvdata(pdev);
+	if (!dev) {
+		dev_err(&pdev->dev, "%s no valid dev found\n", __func__);
+		return 0;
+	}
+
+	ap = netdev_priv(dev);
+
+	/* MAC */
+	unregister_netdev(dev);
+	iounmap(ap->regs);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	release_mem_region(res->start, resource_size(res));
+
+	platform_set_drvdata(pdev, NULL);
+	free_netdev(dev);
+	return 0;
+}
+
+static struct platform_driver arcvmac_driver = {
+	.probe		= vmac_probe,
+	.remove		= __devexit_p(vmac_remove),
+	.driver		= {
+		.name		= "arcvmac",
+	},
+};
+
+static int __init vmac_init(void)
+{
+	return platform_driver_register(&arcvmac_driver);
+}
+
+static void __exit vmac_exit(void)
+{
+	platform_driver_unregister(&arcvmac_driver);
+}
+
+module_init(vmac_init);
+module_exit(vmac_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ARC VMAC Ethernet driver");
+MODULE_AUTHOR("amit.bhor@celunite.com, sameer.dhavale@celunite.com");
diff --git a/drivers/net/arcvmac.h b/drivers/net/arcvmac.h
new file mode 100644
index 0000000..279742a
--- /dev/null
+++ b/drivers/net/arcvmac.h
@@ -0,0 +1,122 @@
+/*
+ * linux/arch/arc/drivers/arcvmac.h
+ *
+ * Copyright (C) 2003-2006 Codito Technologies, for linux-2.4 port
+ * Copyright (C) 2006-2007 Celunite Inc, for linux-2.6 port
+ * Copyright (C) 2007-2008 Sagem Communications, Fehmi HAFSI
+ * Copyright (C) 2009 Sagem Communications, Andreas Fenkart
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors: amit.bhor@celunite.com, sameer.dhavale@celunite.com
+ */
+
+#ifndef _ARCVMAC_H
+#define _ARCVMAC_H
+
+#define DRV_NAME		"arcvmac"
+#define DRV_VERSION		"1.0"
+
+/* Buffer descriptors */
+#define TX_BDT_LEN		16    /* Number of receive BD's */
+#define RX_BDT_LEN		256   /* Number of transmit BD's */
+
+/* BD poll rate, in 1024 cycles. @100Mhz: x * 1024 cy * 10ns = 1ms */
+#define POLLRATE_TIME		200
+
+/* next power of two, bigger than ETH_FRAME_LEN + VLAN  */
+#define MAX_RX_BUFFER_LEN	0x800	/* 2^11 = 2048 = 0x800 */
+#define MAX_TX_BUFFER_LEN	0x800	/* 2^11 = 2048 = 0x800 */
+
+/* 14 bytes of ethernet header, 4 bytes VLAN, FCS,
+ * plus extra pad to prevent buffer chaining of
+ * maximum sized ethernet packets (1514 bytes) */
+#define	VMAC_BUFFER_PAD		(ETH_HLEN + 4 + ETH_FCS_LEN + 4)
+
+/* VMAC register definitions, offsets in the ref manual are in bytes */
+#define ID_OFFSET		(0x00/0x4)
+#define STAT_OFFSET		(0x04/0x4)
+#define ENABLE_OFFSET		(0x08/0x4)
+#define CONTROL_OFFSET		(0x0c/0x4)
+#define POLLRATE_OFFSET		(0x10/0x4)
+#define RXERR_OFFSET		(0x14/0x4)
+#define MISS_OFFSET		(0x18/0x4)
+#define TXRINGPTR_OFFSET	(0x1c/0x4)
+#define RXRINGPTR_OFFSET	(0x20/0x4)
+#define ADDRL_OFFSET		(0x24/0x4)
+#define ADDRH_OFFSET		(0x28/0x4)
+#define LAFL_OFFSET		(0x2c/0x4)
+#define LAFH_OFFSET		(0x30/0x4)
+#define MDIO_DATA_OFFSET	(0x34/0x4)
+#define MAC_TXRING_HEAD_OFFSET	(0x38/0x4)
+#define MAC_RXRING_HEAD_OFFSET	(0x3C/0x4)
+
+/* STATUS and ENABLE register bit masks */
+#define TXINT_MASK		(1<<0)	/* Transmit interrupt */
+#define RXINT_MASK		(1<<1)	/* Receive interrupt */
+#define ERR_MASK		(1<<2)	/* Error interrupt */
+#define TXCH_MASK		(1<<3)	/* Transmit chaining error interrupt */
+#define MSER_MASK		(1<<4)	/* Missed packet counter error */
+#define RXCR_MASK		(1<<8)	/* RXCRCERR counter rolled over	 */
+#define RXFR_MASK		(1<<9)	/* RXFRAMEERR counter rolled over */
+#define RXFL_MASK		(1<<10)	/* RXOFLOWERR counter rolled over */
+#define MDIO_MASK		(1<<12)	/* MDIO complete */
+#define TXPL_MASK		(1<<31)	/* TXPOLL */
+
+/* CONTROL register bitmasks */
+#define EN_MASK			(1<<0)	/* VMAC enable */
+#define TXRN_MASK		(1<<3)	/* TX enable */
+#define RXRN_MASK		(1<<4)	/* RX enable */
+#define DSBC_MASK		(1<<8)	/* Disable receive broadcast */
+#define ENFL_MASK		(1<<10)	/* Enable Full Duplex */
+#define PROM_MASK		(1<<11)	/* Promiscuous mode */
+
+/* RXERR register bitmasks */
+#define RXERR_CRC		0x000000ff
+#define RXERR_FRM		0x0000ff00
+#define RXERR_OFLO		0x00ff0000 /* fifo overflow */
+
+/* MDIO data register bit masks */
+#define MDIO_SFD		0xC0000000
+#define MDIO_OP			0x30000000
+#define MDIO_ID_MASK		0x0F800000
+#define MDIO_REG_MASK		0x007C0000
+#define MDIO_TA			0x00030000
+#define MDIO_DATA_MASK		0x0000FFFF
+
+#define MDIO_BASE		0x40020000
+#define MDIO_OP_READ		0x20000000
+#define MDIO_OP_WRITE		0x10000000
+
+/* Buffer descriptor INFO bit masks */
+#define OWN_MASK		(1<<31)	/* ownership of buffer, 0 CPU, 1 DMA */
+#define BUFF			(1<<30) /* buffer invalid, rx */
+#define UFLO			(1<<29) /* underflow, tx */
+#define LTCL			(1<<28) /* late collision, tx  */
+#define RETRY_CT		(0xf<<24)  /* tx */
+#define DROP			(1<<23) /* drop, more than 16 retries, tx */
+#define DEFER			(1<<22) /* traffic on the wire, tx */
+#define CARLOSS			(1<<21) /* carrier loss while transmission, tx, rx? */
+/* 20:19 reserved */
+#define ADCR			(1<<18) /* add crc, ignored if not disaddcrc */
+#define LAST_MASK		(1<<17)	/* Last buffer in chain */
+#define FRST_MASK		(1<<16)	/* First buffer in chain */
+/* 15:11 reserved */
+#define LEN_MASK		0x000007FF
+
+#define ERR_MSK_TX		0x3fe00000 /* UFLO | LTCL | RTRY | DROP | DEFER | CRLS */
+
+#endif	  /* _ARCVMAC_H */
diff --git a/drivers/net/arcvmac_fifo.h b/drivers/net/arcvmac_fifo.h
new file mode 100644
index 0000000..39252c9
--- /dev/null
+++ b/drivers/net/arcvmac_fifo.h
@@ -0,0 +1,109 @@
+/*
+ * linux/arch/arc/drivers/arcvmac.c
+ *
+ * Copyright (C) 2009 Sagem Communications
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors: andreas.fenkart@streamunlimited.com
+ */
+
+#ifndef _GEN_DMA_FIFO_H_
+#define _GEN_DMA_FIFO_H_
+
+/* for a fifo with size n,
+ * - [0..n] fill levels are n + 1 states
+ * - there are only n different deltas (head - tail) values
+ * => not all fill levels can be represented with head, tail
+ *    pointers only
+ * we give up the n fill level, aka fifo full */
+
+/* sacrifice one elt as a sentinel */
+struct dma_fifo {
+	int head; /* head */
+	int tail; /* tail */
+	int size;
+};
+
+static inline int fifo_used(struct dma_fifo *f);
+static inline int fifo_inc_ct(int ct, int size);
+static inline void fifo_dump(struct dma_fifo *fifo);
+
+static inline int fifo_empty(struct dma_fifo *f)
+{
+	return (f->head == f->tail);
+}
+
+static inline int fifo_free(struct dma_fifo *f)
+{
+	int free;
+
+	free = f->tail - f->head;
+	if (free <= 0)
+		free += f->size;
+
+	return free;
+}
+
+static inline int fifo_used(struct dma_fifo *f)
+{
+	int used;
+
+	used = f->head - f->tail;
+	if (used < 0)
+		used += f->size;
+
+	return used;
+}
+
+static inline int fifo_full(struct dma_fifo *f)
+{
+	return (fifo_used(f) + 1) == f->size;
+}
+
+/* manipulate */
+static inline void fifo_init(struct dma_fifo *fifo, int size)
+{
+	fifo->size = size;
+	fifo->head = fifo->tail = 0; /* empty */
+}
+
+static inline void fifo_inc_head(struct dma_fifo *fifo)
+{
+	BUG_ON(fifo_full(fifo));
+	fifo->head = fifo_inc_ct(fifo->head, fifo->size);
+}
+
+static inline void fifo_inc_tail(struct dma_fifo *fifo)
+{
+	BUG_ON(fifo_empty(fifo));
+	fifo->tail = fifo_inc_ct(fifo->tail, fifo->size);
+}
+
+/* internal funcs */
+static inline void fifo_dump(struct dma_fifo *fifo)
+{
+	printk(KERN_INFO "fifo: head %d, tail %d, size %d\n", fifo->head,
+			fifo->tail,
+			fifo->size);
+}
+
+static inline int fifo_inc_ct(int ct, int size)
+{
+	return (++ct == size) ? 0 : ct;
+}
+
+#endif
-- 
1.6.6.1


^ permalink raw reply related

* Re: [net-next PATCH v5 2/3] sysctl: add proc_do_large_bitmap
From: Octavian Purdila @ 2010-02-21 11:42 UTC (permalink / raw)
  To: Cong Wang
  Cc: David Miller, Linux Kernel Network Developers,
	Linux Kernel Developers, Eric W. Biederman

>
> My test shows it still accepts spaces, e.g.
>
> echo '50000 50003 50005' > ip_local_reserved_ports
>
> works same as
>
> echo '50000,50003,50005' > ip_local_reserved_ports
>
> Is this expected? We will only accept commas, right?
>

Thanks for testing, I didn't saw that comming! I wanted to allow whitespaces in between the commas but it looks like I got overzealous. I can easily fix that. 

But I think its worth to keep the whitespaces in beetween, e.g. allow

$ echo '1, 2 ,3 ' >   ip_local_reserved_ports.

>
> Also, if I write an invalid value, it does reject this, but the previous
> value in that file is cleared, shouldn't we keep the previous one?
>
>

The only way I see to fix this is to return EINVAL if we detect a write with offset.

IMO we should do that for the other proc write routines as well, as otherwise ther result is confusing, e.g.

write("1 2"); write(" 3");

will set first value in the vector to 1, than second value to 2 then *first* value to 3.

I am all for it, but again, this changes userspace ABI. 

^ permalink raw reply

* Re: [net-next PATCH v4 1/3] net: TCP thin-stream detection
From: Alexander Zimmermann @ 2010-02-21 11:23 UTC (permalink / raw)
  To: Pavel Machek, Andreas Petlund, lars.eggert
  Cc: netdev, Ilpo J?rvinen, Eric Dumazet, Arnd Hannemann, LKML,
	shemminger, David Miller, william.allen.simpson, Lukowski Damian,
	Eric W. Biederman
In-Reply-To: <20100221102102.GB1311@ucw.cz>


Am 21.02.2010 um 11:21 schrieb Pavel Machek:

> Hi!
> 
>> +After analysing a large number of time-dependent interactive
>> +applications, we have seen that they often produce thin streams
>> +and also stay with this traffic pattern throughout its entire
>> +lifespan. The combination of time-dependency and the fact that the
>> +streams provoke high latencies when using TCP is unfortunate.
>> +
>> +In order to reduce application-layer latency when packets are lost,
>> +a set of mechanisms has been made, which address these latency issues
>> +for thin streams. In short, if the kernel detects a thin stream,
>> +the retransmission mechanisms are modified in the following manner:
>> +
>> +1) If the stream is thin, fast retransmit on the first dupACK.
>> +2) If the stream is thin, do not apply exponential backoff.
> 
> 2) seems very dangerous/unfair. If network  congestion is caused just
> by thin streams, will the network just fall apart?

and 1) can also be dangerous if we have reordering on the path.

I strongly suggest that we discuss Andreas' idea on IETF TCPM *before*
we integrate it in the kernel and enable it for everyone

Alex,

as an netdev reader and TCPM member

> 
> 
> -- 
> (english) http://www.livejournal.com/~pavelmachek
> (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

//
// Dipl.-Inform. Alexander Zimmermann
// Department of Computer Science, Informatik 4
// RWTH Aachen University
// Ahornstr. 55, 52056 Aachen, Germany
// phone: (49-241) 80-21422, fax: (49-241) 80-22220
// email: zimmermann@cs.rwth-aachen.de
// web: http://www.umic-mesh.net
//


^ 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