Netdev List
 help / color / mirror / Atom feed
* [RFC, PATCH 4/4] net: sh_eth: add support for SH7757's GETHER
From: Yoshihiro Shimoda @ 2011-02-15 11:47 UTC (permalink / raw)
  To: netdev; +Cc: SH-Linux

The SH7757 have GETHER and ETHER both. This patch supports them.

Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
---
 drivers/net/sh_eth.c |  136 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 135 insertions(+), 1 deletions(-)

diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c
index ca7ff4e..330f608 100644
--- a/drivers/net/sh_eth.c
+++ b/drivers/net/sh_eth.c
@@ -87,7 +87,8 @@ static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
 	.rpadir_value	= 0x00020000, /* NET_IP_ALIGN assumed to be 2 */
 };
 #elif defined(CONFIG_CPU_SUBTYPE_SH7757)
-#define SH_ETH_RESET_DEFAULT	1
+#define SH_ETH_HAS_BOTH_MODULES	1
+#define SH_ETH_HAS_TSU	1
 static void sh_eth_set_duplex(struct net_device *ndev)
 {
 	struct sh_eth_private *mdp = netdev_priv(ndev);
@@ -134,6 +135,135 @@ static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
 	.no_ade		= 1,
 };

+#define SH_GIGA_ETH_BASE	0xfee00000
+#define GIGA_MALR(port)		(SH_GIGA_ETH_BASE + 0x800 * (port) + 0x05c8)
+#define GIGA_MAHR(port)		(SH_GIGA_ETH_BASE + 0x800 * (port) + 0x05c0)
+static void sh_eth_chip_reset_giga(struct net_device *ndev)
+{
+	int i;
+	unsigned long mahr[2], malr[2];
+
+	/* save MAHR and MALR */
+	for (i = 0; i < 2; i++) {
+		malr[i] = readl(GIGA_MALR(i));
+		mahr[i] = readl(GIGA_MAHR(i));
+	}
+
+	/* reset device */
+	writel(ARSTR_ARSTR, SH_GIGA_ETH_BASE + 0x1800);
+	mdelay(1);
+
+	/* restore MAHR and MALR */
+	for (i = 0; i < 2; i++) {
+		writel(malr[i], GIGA_MALR(i));
+		writel(mahr[i], GIGA_MAHR(i));
+	}
+}
+
+static int sh_eth_is_gether(struct sh_eth_private *mdp);
+static void sh_eth_reset(struct net_device *ndev)
+{
+	struct sh_eth_private *mdp = netdev_priv(ndev);
+	int cnt = 100;
+
+	if (sh_eth_is_gether(mdp)) {
+		sh_eth_write(ndev, 0x03, EDSR);
+		sh_eth_write(ndev, sh_eth_read(ndev, EDMR) | EDMR_SRST_GETHER,
+				EDMR);
+		while (cnt > 0) {
+			if (!(sh_eth_read(ndev, EDMR) & 0x3))
+				break;
+			mdelay(1);
+			cnt--;
+		}
+		if (cnt < 0)
+			printk(KERN_ERR "Device reset fail\n");
+
+		/* Table Init */
+		sh_eth_write(ndev, 0x0, TDLAR);
+		sh_eth_write(ndev, 0x0, TDFAR);
+		sh_eth_write(ndev, 0x0, TDFXR);
+		sh_eth_write(ndev, 0x0, TDFFR);
+		sh_eth_write(ndev, 0x0, RDLAR);
+		sh_eth_write(ndev, 0x0, RDFAR);
+		sh_eth_write(ndev, 0x0, RDFXR);
+		sh_eth_write(ndev, 0x0, RDFFR);
+	} else {
+		sh_eth_write(ndev, sh_eth_read(ndev, EDMR) | EDMR_SRST_ETHER,
+				EDMR);
+		mdelay(3);
+		sh_eth_write(ndev, sh_eth_read(ndev, EDMR) & ~EDMR_SRST_ETHER,
+				EDMR);
+	}
+}
+
+static void sh_eth_set_duplex_giga(struct net_device *ndev)
+{
+	struct sh_eth_private *mdp = netdev_priv(ndev);
+
+	if (mdp->duplex) /* Full */
+		sh_eth_write(ndev, sh_eth_read(ndev, ECMR) | ECMR_DM, ECMR);
+	else		/* Half */
+		sh_eth_write(ndev, sh_eth_read(ndev, ECMR) & ~ECMR_DM, ECMR);
+}
+
+static void sh_eth_set_rate_giga(struct net_device *ndev)
+{
+	struct sh_eth_private *mdp = netdev_priv(ndev);
+
+	switch (mdp->speed) {
+	case 10: /* 10BASE */
+		sh_eth_write(ndev, 0x00000000, GECMR);
+		break;
+	case 100:/* 100BASE */
+		sh_eth_write(ndev, 0x00000010, GECMR);
+		break;
+	case 1000: /* 1000BASE */
+		sh_eth_write(ndev, 0x00000020, GECMR);
+		break;
+	default:
+		break;
+	}
+}
+
+/* SH7757(GETHERC) */
+static struct sh_eth_cpu_data sh_eth_my_cpu_data_giga = {
+	.chip_reset	= sh_eth_chip_reset_giga,
+	.set_duplex	= sh_eth_set_duplex_giga,
+	.set_rate	= sh_eth_set_rate_giga,
+
+	.ecsr_value	= ECSR_ICD | ECSR_MPD,
+	.ecsipr_value	= ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP,
+	.eesipr_value	= DMAC_M_RFRMER | DMAC_M_ECI | 0x003fffff,
+
+	.tx_check	= EESR_TC1 | EESR_FTC,
+	.eesr_err_check	= EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT | \
+			  EESR_RDE | EESR_RFRMER | EESR_TFE | EESR_TDE | \
+			  EESR_ECI,
+	.tx_error_check	= EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_TDE | \
+			  EESR_TFE,
+	.fdr_value	= 0x0000072f,
+	.rmcr_value	= 0x00000001,
+
+	.apr		= 1,
+	.mpr		= 1,
+	.tpauser	= 1,
+	.bculr		= 1,
+	.hw_swap	= 1,
+	.rpadir		= 1,
+	.rpadir_value   = 2 << 16,
+	.no_trimd	= 1,
+	.no_ade		= 1,
+};
+
+static struct sh_eth_cpu_data *sh_eth_get_cpu_data(struct sh_eth_private *mdp)
+{
+	if (sh_eth_is_gether(mdp))
+		return &sh_eth_my_cpu_data_giga;
+	else
+		return &sh_eth_my_cpu_data;
+}
+
 #elif defined(CONFIG_CPU_SUBTYPE_SH7763)
 #define SH_ETH_HAS_TSU	1
 static void sh_eth_chip_reset(struct net_device *ndev)
@@ -1515,7 +1645,11 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
 	mdp->reg_offset = sh_eth_get_register_offset(pd->register_type);

 	/* set cpu data */
+#if defined(SH_ETH_HAS_BOTH_MODULES)
+	mdp->cd = sh_eth_get_cpu_data(mdp);
+#else
 	mdp->cd = &sh_eth_my_cpu_data;
+#endif
 	sh_eth_set_default_cpu_data(mdp->cd);

 	/* set function */
-- 
1.7.1

^ permalink raw reply related

* [RFC, PATCH 3/4] net: sh_eth: remove almost #ifdef of SH7763
From: Yoshihiro Shimoda @ 2011-02-15 11:47 UTC (permalink / raw)
  To: netdev; +Cc: SH-Linux

The SH7763 has GETHER. So the specification of some registers differs than
other CPUs. This patch removes almost #ifdef of CONFIG_CPU_SUBTYPE_SH7763.
Then we are able to add other CPU's GETHER easily.

Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
---
 drivers/net/sh_eth.c |   72 +++++++++++++++++++++++++++++--------------------
 drivers/net/sh_eth.h |   14 +++-------
 2 files changed, 47 insertions(+), 39 deletions(-)

diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c
index 0593f29..ca7ff4e 100644
--- a/drivers/net/sh_eth.c
+++ b/drivers/net/sh_eth.c
@@ -148,7 +148,7 @@ static void sh_eth_reset(struct net_device *ndev)
 	int cnt = 100;

 	sh_eth_write(ndev, EDSR_ENALL, EDSR);
-	sh_eth_write(ndev, sh_eth_read(ndev, EDMR) | EDMR_SRST, EDMR);
+	sh_eth_write(ndev, sh_eth_read(ndev, EDMR) | EDMR_SRST_GETHER, EDMR);
 	while (cnt > 0) {
 		if (!(sh_eth_read(ndev, EDMR) & 0x3))
 			break;
@@ -274,9 +274,9 @@ static void sh_eth_set_default_cpu_data(struct sh_eth_cpu_data *cd)
 /* Chip Reset */
 static void sh_eth_reset(struct net_device *ndev)
 {
-	sh_eth_write(ndev, sh_eth_read(ndev, EDMR) | EDMR_SRST, EDMR);
+	sh_eth_write(ndev, sh_eth_read(ndev, EDMR) | EDMR_SRST_ETHER, EDMR);
 	mdelay(3);
-	sh_eth_write(ndev, sh_eth_read(ndev, EDMR) & ~EDMR_SRST, EDMR);
+	sh_eth_write(ndev, sh_eth_read(ndev, EDMR) & ~EDMR_SRST_ETHER, EDMR);
 }
 #endif

@@ -354,6 +354,22 @@ static void read_mac_address(struct net_device *ndev, unsigned char *mac)
 	}
 }

+static int sh_eth_is_gether(struct sh_eth_private *mdp)
+{
+	if (mdp->reg_offset == sh_eth_offset_gigabit)
+		return 1;
+	else
+		return 0;
+}
+
+static unsigned long sh_eth_get_edtrr_trns(struct sh_eth_private *mdp)
+{
+	if (sh_eth_is_gether(mdp))
+		return EDTRR_TRNS_GETHER;
+	else
+		return EDTRR_TRNS_ETHER;
+}
+
 struct bb_info {
 	struct mdiobb_ctrl ctrl;
 	u32 addr;
@@ -493,9 +509,8 @@ static void sh_eth_ring_format(struct net_device *ndev)
 		/* Rx descriptor address set */
 		if (i == 0) {
 			sh_eth_write(ndev, mdp->rx_desc_dma, RDLAR);
-#if defined(CONFIG_CPU_SUBTYPE_SH7763)
-			sh_eth_write(ndev, mdp->rx_desc_dma, RDFAR);
-#endif
+			if (sh_eth_is_gether(mdp))
+				sh_eth_write(ndev, mdp->rx_desc_dma, RDFAR);
 		}
 	}

@@ -515,9 +530,8 @@ static void sh_eth_ring_format(struct net_device *ndev)
 		if (i == 0) {
 			/* Tx descriptor address set */
 			sh_eth_write(ndev, mdp->tx_desc_dma, TDLAR);
-#if defined(CONFIG_CPU_SUBTYPE_SH7763)
-			sh_eth_write(ndev, mdp->tx_desc_dma, TDFAR);
-#endif
+			if (sh_eth_is_gether(mdp))
+				sh_eth_write(ndev, mdp->tx_desc_dma, TDFAR);
 		}
 	}

@@ -897,9 +911,9 @@ static void sh_eth_error(struct net_device *ndev, int intr_status)
 		sh_eth_txfree(ndev);

 		/* SH7712 BUG */
-		if (edtrr ^ EDTRR_TRNS) {
+		if (edtrr ^ sh_eth_get_edtrr_trns(mdp)) {
 			/* tx dma start */
-			sh_eth_write(ndev, EDTRR_TRNS, EDTRR);
+			sh_eth_write(ndev, sh_eth_get_edtrr_trns(mdp), EDTRR);
 		}
 		/* wakeup */
 		netif_wake_queue(ndev);
@@ -1177,8 +1191,8 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev)

 	mdp->cur_tx++;

-	if (!(sh_eth_read(ndev, EDTRR) & EDTRR_TRNS))
-		sh_eth_write(ndev, EDTRR_TRNS, EDTRR);
+	if (!(sh_eth_read(ndev, EDTRR) & sh_eth_get_edtrr_trns(mdp)))
+		sh_eth_write(ndev, sh_eth_get_edtrr_trns(mdp), EDTRR);

 	return NETDEV_TX_OK;
 }
@@ -1236,15 +1250,15 @@ static struct net_device_stats *sh_eth_get_stats(struct net_device *ndev)
 	sh_eth_write(ndev, 0, CDCR);	/* (write clear) */
 	mdp->stats.tx_carrier_errors += sh_eth_read(ndev, LCCR);
 	sh_eth_write(ndev, 0, LCCR);	/* (write clear) */
-#if defined(CONFIG_CPU_SUBTYPE_SH7763)
-	mdp->stats.tx_carrier_errors += sh_eth_read(ndev, CERCR);/* CERCR */
-	sh_eth_write(ndev, 0, CERCR);	/* (write clear) */
-	mdp->stats.tx_carrier_errors += sh_eth_read(ndev, CEECR);/* CEECR */
-	sh_eth_write(ndev, 0, CEECR);	/* (write clear) */
-#else
-	mdp->stats.tx_carrier_errors += sh_eth_read(ndev, CNDCR);
-	sh_eth_write(ndev, 0, CNDCR);	/* (write clear) */
-#endif
+	if (sh_eth_is_gether(mdp)) {
+		mdp->stats.tx_carrier_errors += sh_eth_read(ndev, CERCR);
+		sh_eth_write(ndev, 0, CERCR);	/* (write clear) */
+		mdp->stats.tx_carrier_errors += sh_eth_read(ndev, CEECR);
+		sh_eth_write(ndev, 0, CEECR);	/* (write clear) */
+	} else {
+		mdp->stats.tx_carrier_errors += sh_eth_read(ndev, CNDCR);
+		sh_eth_write(ndev, 0, CNDCR);	/* (write clear) */
+	}
 	pm_runtime_put_sync(&mdp->pdev->dev);

 	return &mdp->stats;
@@ -1294,13 +1308,13 @@ static void sh_eth_tsu_init(struct sh_eth_private *mdp)
 	sh_eth_tsu_write(mdp, 0, TSU_FWSL0);
 	sh_eth_tsu_write(mdp, 0, TSU_FWSL1);
 	sh_eth_tsu_write(mdp, TSU_FWSLC_POSTENU | TSU_FWSLC_POSTENL, TSU_FWSLC);
-#if defined(CONFIG_CPU_SUBTYPE_SH7763)
-	sh_eth_tsu_write(mdp, 0, TSU_QTAG0);	/* Disable QTAG(0->1) */
-	sh_eth_tsu_write(mdp, 0, TSU_QTAG1);	/* Disable QTAG(1->0) */
-#else
-	sh_eth_tsu_write(mdp, 0, TSU_QTAGM0);	/* Disable QTAG(0->1) */
-	sh_eth_tsu_write(mdp, 0, TSU_QTAGM1);	/* Disable QTAG(1->0) */
-#endif
+	if (sh_eth_is_gether(mdp)) {
+		sh_eth_tsu_write(mdp, 0, TSU_QTAG0);	/* Disable QTAG(0->1) */
+		sh_eth_tsu_write(mdp, 0, TSU_QTAG1);	/* Disable QTAG(1->0) */
+	} else {
+		sh_eth_tsu_write(mdp, 0, TSU_QTAGM0);	/* Disable QTAG(0->1) */
+		sh_eth_tsu_write(mdp, 0, TSU_QTAGM1);	/* Disable QTAG(1->0) */
+	}
 	sh_eth_tsu_write(mdp, 0, TSU_FWSR);	/* all interrupt status clear */
 	sh_eth_tsu_write(mdp, 0, TSU_FWINMK);	/* Disable all interrupt */
 	sh_eth_tsu_write(mdp, 0, TSU_TEN);	/* Disable all CAM entry */
diff --git a/drivers/net/sh_eth.h b/drivers/net/sh_eth.h
index 1a32dc0..1e7d90a 100644
--- a/drivers/net/sh_eth.h
+++ b/drivers/net/sh_eth.h
@@ -398,20 +398,14 @@ enum GECMR_BIT {
 enum DMAC_M_BIT {
 	EDMR_EL = 0x40, /* Litte endian */
 	EDMR_DL1 = 0x20, EDMR_DL0 = 0x10,
-#ifdef CONFIG_CPU_SUBTYPE_SH7763
-	EDMR_SRST = 0x03,
-#else /* CONFIG_CPU_SUBTYPE_SH7763 */
-	EDMR_SRST = 0x01,
-#endif
+	EDMR_SRST_GETHER = 0x03,
+	EDMR_SRST_ETHER = 0x01,
 };

 /* EDTRR */
 enum DMAC_T_BIT {
-#ifdef CONFIG_CPU_SUBTYPE_SH7763
-	EDTRR_TRNS = 0x03,
-#else
-	EDTRR_TRNS = 0x01,
-#endif
+	EDTRR_TRNS_GETHER = 0x03,
+	EDTRR_TRNS_ETHER = 0x01,
 };

 /* EDRRR*/
-- 
1.7.1

^ permalink raw reply related

* [RFC, PATCH 2/4] net: sh_eth: remove the SH_TSU_ADDR
From: Yoshihiro Shimoda @ 2011-02-15 11:47 UTC (permalink / raw)
  To: netdev; +Cc: SH-Linux

The defination is hardcoded in this driver for some CPUs. This patch
modifies to get resource of TSU address from platform_device.

Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
---
 drivers/net/sh_eth.c |   16 ++++++++++++----
 drivers/net/sh_eth.h |   15 ---------------
 2 files changed, 12 insertions(+), 19 deletions(-)

diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c
index 3b6d545..0593f29 100644
--- a/drivers/net/sh_eth.c
+++ b/drivers/net/sh_eth.c
@@ -1446,7 +1446,7 @@ static const struct net_device_ops sh_eth_netdev_ops = {
 static int sh_eth_drv_probe(struct platform_device *pdev)
 {
 	int ret, devno = 0;
-	struct resource *res;
+	struct resource *res, *res_tsu;
 	struct net_device *ndev = NULL;
 	struct sh_eth_private *mdp;
 	struct sh_eth_plat_data *pd;
@@ -1520,9 +1520,13 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
 			mdp->cd->chip_reset(ndev);

 #if defined(SH_ETH_HAS_TSU)
-		/* TSU init (Init only)*/
-		mdp->tsu_addr = SH_TSU_ADDR;
-		sh_eth_tsu_init(mdp);
+		res_tsu = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+		if (res_tsu) {
+			mdp->tsu_addr = ioremap(res_tsu->start,
+						resource_size(res_tsu));
+			/* TSU init (Init only)*/
+			sh_eth_tsu_init(mdp);
+		}
 #endif
 	}

@@ -1549,6 +1553,8 @@ out_unregister:

 out_release:
 	/* net_dev free */
+	if (mdp->tsu_addr)
+		iounmap(mdp->tsu_addr);
 	if (ndev)
 		free_netdev(ndev);

@@ -1559,7 +1565,9 @@ out:
 static int sh_eth_drv_remove(struct platform_device *pdev)
 {
 	struct net_device *ndev = platform_get_drvdata(pdev);
+	struct sh_eth_private *mdp = netdev_priv(ndev);

+	iounmap(mdp->tsu_addr);
 	sh_mdio_release(ndev);
 	unregister_netdev(ndev);
 	pm_runtime_disable(&pdev->dev);
diff --git a/drivers/net/sh_eth.h b/drivers/net/sh_eth.h
index 1510a7c..1a32dc0 100644
--- a/drivers/net/sh_eth.h
+++ b/drivers/net/sh_eth.h
@@ -371,21 +371,6 @@ static const u16 sh_eth_offset_fast_sh3_sh2[SH_ETH_MAX_REGISTER_OFFSET] = {

 };

-#if defined(CONFIG_CPU_SUBTYPE_SH7763)
-/* This CPU register maps is very difference by other SH4 CPU */
-/* Chip Base Address */
-# define SH_TSU_ADDR	0xFEE01800
-# define ARSTR		SH_TSU_ADDR
-#elif defined(CONFIG_CPU_SH4)	/* #if defined(CONFIG_CPU_SUBTYPE_SH7763) */
-#else /* #elif defined(CONFIG_CPU_SH4) */
-/* This section is SH3 or SH2 */
-#ifndef CONFIG_CPU_SUBTYPE_SH7619
-/* Chip base address */
-# define SH_TSU_ADDR  0xA7000804
-# define ARSTR		  0xA7000800
-#endif
-#endif /* CONFIG_CPU_SUBTYPE_SH7763 */
-
 /* Driver's parameters */
 #if defined(CONFIG_CPU_SH4)
 #define SH4_SKB_RX_ALIGN	32
-- 
1.7.1

^ permalink raw reply related

* [RFC, PATCH 0/4] net: sh_eth: modify for both modules
From: Yoshihiro Shimoda @ 2011-02-15 11:47 UTC (permalink / raw)
  To: netdev; +Cc: SH-Linux

This current driver supports ETHER and GETHER. But we cannot
use them at same time because the defination of registers is
hardcoded by #ifdef in sh_eth.h.
The patches modify the defination to arrays of const. Then
we can choose the array by platform_device's data.
The patches also modify for GETHER. The current driver used
the "#ifdef CONFIG_CPU_SUBTYPE_SH7763". The patches remove it
and check by other method for GETHER.

^ permalink raw reply

* [RFC, PATCH 1/4] net: sh_eth: modify the definitions of register
From: Yoshihiro Shimoda @ 2011-02-15 11:47 UTC (permalink / raw)
  To: netdev; +Cc: SH-Linux

The previous code cannot handle the ETHER and GETHER both as same time
because the definitions of register was hardcoded.

Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
---
 arch/sh/include/asm/sh_eth.h |    7 +
 drivers/net/sh_eth.c         |  322 +++++++++++-----------
 drivers/net/sh_eth.h         |  623 ++++++++++++++++++++++++------------------
 3 files changed, 537 insertions(+), 415 deletions(-)

diff --git a/arch/sh/include/asm/sh_eth.h b/arch/sh/include/asm/sh_eth.h
index f739061..44d64c0 100644
--- a/arch/sh/include/asm/sh_eth.h
+++ b/arch/sh/include/asm/sh_eth.h
@@ -2,10 +2,17 @@
 #define __ASM_SH_ETH_H__

 enum {EDMAC_LITTLE_ENDIAN, EDMAC_BIG_ENDIAN};
+enum {
+	SH_ETH_REG_DEFAULT = 0,
+	SH_ETH_REG_GIGABIT,
+	SH_ETH_REG_FAST_SH4,
+	SH_ETH_REG_FAST_SH3_SH2
+};

 struct sh_eth_plat_data {
 	int phy;
 	int edmac_endian;
+	int register_type;

 	unsigned char mac_addr[6];
 	unsigned no_ether_link:1;
diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c
index 819c175..3b6d545 100644
--- a/drivers/net/sh_eth.c
+++ b/drivers/net/sh_eth.c
@@ -42,25 +42,23 @@
 static void sh_eth_set_duplex(struct net_device *ndev)
 {
 	struct sh_eth_private *mdp = netdev_priv(ndev);
-	u32 ioaddr = ndev->base_addr;

 	if (mdp->duplex) /* Full */
-		writel(readl(ioaddr + ECMR) | ECMR_DM, ioaddr + ECMR);
+		sh_eth_write(ndev, sh_eth_read(ndev, ECMR) | ECMR_DM, ECMR);
 	else		/* Half */
-		writel(readl(ioaddr + ECMR) & ~ECMR_DM, ioaddr + ECMR);
+		sh_eth_write(ndev, sh_eth_read(ndev, ECMR) & ~ECMR_DM, ECMR);
 }

 static void sh_eth_set_rate(struct net_device *ndev)
 {
 	struct sh_eth_private *mdp = netdev_priv(ndev);
-	u32 ioaddr = ndev->base_addr;

 	switch (mdp->speed) {
 	case 10: /* 10BASE */
-		writel(readl(ioaddr + ECMR) & ~ECMR_RTM, ioaddr + ECMR);
+		sh_eth_write(ndev, sh_eth_read(ndev, ECMR) & ~ECMR_RTM, ECMR);
 		break;
 	case 100:/* 100BASE */
-		writel(readl(ioaddr + ECMR) | ECMR_RTM, ioaddr + ECMR);
+		sh_eth_write(ndev, sh_eth_read(ndev, ECMR) | ECMR_RTM, ECMR);
 		break;
 	default:
 		break;
@@ -93,25 +91,23 @@ static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
 static void sh_eth_set_duplex(struct net_device *ndev)
 {
 	struct sh_eth_private *mdp = netdev_priv(ndev);
-	u32 ioaddr = ndev->base_addr;

 	if (mdp->duplex) /* Full */
-		writel(readl(ioaddr + ECMR) | ECMR_DM, ioaddr + ECMR);
+		sh_eth_write(ndev, sh_eth_read(ndev, ECMR) | ECMR_DM, ECMR);
 	else		/* Half */
-		writel(readl(ioaddr + ECMR) & ~ECMR_DM, ioaddr + ECMR);
+		sh_eth_write(ndev, sh_eth_read(ndev, ECMR) & ~ECMR_DM, ECMR);
 }

 static void sh_eth_set_rate(struct net_device *ndev)
 {
 	struct sh_eth_private *mdp = netdev_priv(ndev);
-	u32 ioaddr = ndev->base_addr;

 	switch (mdp->speed) {
 	case 10: /* 10BASE */
-		writel(0, ioaddr + RTRATE);
+		sh_eth_write(ndev, 0, RTRATE);
 		break;
 	case 100:/* 100BASE */
-		writel(1, ioaddr + RTRATE);
+		sh_eth_write(ndev, 1, RTRATE);
 		break;
 	default:
 		break;
@@ -149,13 +145,12 @@ static void sh_eth_chip_reset(struct net_device *ndev)

 static void sh_eth_reset(struct net_device *ndev)
 {
-	u32 ioaddr = ndev->base_addr;
 	int cnt = 100;

-	writel(EDSR_ENALL, ioaddr + EDSR);
-	writel(readl(ioaddr + EDMR) | EDMR_SRST, ioaddr + EDMR);
+	sh_eth_write(ndev, EDSR_ENALL, EDSR);
+	sh_eth_write(ndev, sh_eth_read(ndev, EDMR) | EDMR_SRST, EDMR);
 	while (cnt > 0) {
-		if (!(readl(ioaddr + EDMR) & 0x3))
+		if (!(sh_eth_read(ndev, EDMR) & 0x3))
 			break;
 		mdelay(1);
 		cnt--;
@@ -164,41 +159,39 @@ static void sh_eth_reset(struct net_device *ndev)
 		printk(KERN_ERR "Device reset fail\n");

 	/* Table Init */
-	writel(0x0, ioaddr + TDLAR);
-	writel(0x0, ioaddr + TDFAR);
-	writel(0x0, ioaddr + TDFXR);
-	writel(0x0, ioaddr + TDFFR);
-	writel(0x0, ioaddr + RDLAR);
-	writel(0x0, ioaddr + RDFAR);
-	writel(0x0, ioaddr + RDFXR);
-	writel(0x0, ioaddr + RDFFR);
+	sh_eth_write(ndev, 0x0, TDLAR);
+	sh_eth_write(ndev, 0x0, TDFAR);
+	sh_eth_write(ndev, 0x0, TDFXR);
+	sh_eth_write(ndev, 0x0, TDFFR);
+	sh_eth_write(ndev, 0x0, RDLAR);
+	sh_eth_write(ndev, 0x0, RDFAR);
+	sh_eth_write(ndev, 0x0, RDFXR);
+	sh_eth_write(ndev, 0x0, RDFFR);
 }

 static void sh_eth_set_duplex(struct net_device *ndev)
 {
 	struct sh_eth_private *mdp = netdev_priv(ndev);
-	u32 ioaddr = ndev->base_addr;

 	if (mdp->duplex) /* Full */
-		writel(readl(ioaddr + ECMR) | ECMR_DM, ioaddr + ECMR);
+		sh_eth_write(ndev, sh_eth_read(ndev, ECMR) | ECMR_DM, ECMR);
 	else		/* Half */
-		writel(readl(ioaddr + ECMR) & ~ECMR_DM, ioaddr + ECMR);
+		sh_eth_write(ndev, sh_eth_read(ndev, ECMR) & ~ECMR_DM, ECMR);
 }

 static void sh_eth_set_rate(struct net_device *ndev)
 {
 	struct sh_eth_private *mdp = netdev_priv(ndev);
-	u32 ioaddr = ndev->base_addr;

 	switch (mdp->speed) {
 	case 10: /* 10BASE */
-		writel(GECMR_10, ioaddr + GECMR);
+		sh_eth_write(ndev, GECMR_10, GECMR);
 		break;
 	case 100:/* 100BASE */
-		writel(GECMR_100, ioaddr + GECMR);
+		sh_eth_write(ndev, GECMR_100, GECMR);
 		break;
 	case 1000: /* 1000BASE */
-		writel(GECMR_1000, ioaddr + GECMR);
+		sh_eth_write(ndev, GECMR_1000, GECMR);
 		break;
 	default:
 		break;
@@ -281,11 +274,9 @@ static void sh_eth_set_default_cpu_data(struct sh_eth_cpu_data *cd)
 /* Chip Reset */
 static void sh_eth_reset(struct net_device *ndev)
 {
-	u32 ioaddr = ndev->base_addr;
-
-	writel(readl(ioaddr + EDMR) | EDMR_SRST, ioaddr + EDMR);
+	sh_eth_write(ndev, sh_eth_read(ndev, EDMR) | EDMR_SRST, EDMR);
 	mdelay(3);
-	writel(readl(ioaddr + EDMR) & ~EDMR_SRST, ioaddr + EDMR);
+	sh_eth_write(ndev, sh_eth_read(ndev, EDMR) & ~EDMR_SRST, EDMR);
 }
 #endif

@@ -334,13 +325,11 @@ static inline __u32 edmac_to_cpu(struct sh_eth_private *mdp, u32 x)
  */
 static void update_mac_address(struct net_device *ndev)
 {
-	u32 ioaddr = ndev->base_addr;
-
-	writel((ndev->dev_addr[0] << 24) | (ndev->dev_addr[1] << 16) |
-		  (ndev->dev_addr[2] << 8) | (ndev->dev_addr[3]),
-		  ioaddr + MAHR);
-	writel((ndev->dev_addr[4] << 8) | (ndev->dev_addr[5]),
-		  ioaddr + MALR);
+	sh_eth_write(ndev,
+		(ndev->dev_addr[0] << 24) | (ndev->dev_addr[1] << 16) |
+		(ndev->dev_addr[2] << 8) | (ndev->dev_addr[3]), MAHR);
+	sh_eth_write(ndev,
+		(ndev->dev_addr[4] << 8) | (ndev->dev_addr[5]), MALR);
 }

 /*
@@ -353,17 +342,15 @@ static void update_mac_address(struct net_device *ndev)
  */
 static void read_mac_address(struct net_device *ndev, unsigned char *mac)
 {
-	u32 ioaddr = ndev->base_addr;
-
 	if (mac[0] || mac[1] || mac[2] || mac[3] || mac[4] || mac[5]) {
 		memcpy(ndev->dev_addr, mac, 6);
 	} else {
-		ndev->dev_addr[0] = (readl(ioaddr + MAHR) >> 24);
-		ndev->dev_addr[1] = (readl(ioaddr + MAHR) >> 16) & 0xFF;
-		ndev->dev_addr[2] = (readl(ioaddr + MAHR) >> 8) & 0xFF;
-		ndev->dev_addr[3] = (readl(ioaddr + MAHR) & 0xFF);
-		ndev->dev_addr[4] = (readl(ioaddr + MALR) >> 8) & 0xFF;
-		ndev->dev_addr[5] = (readl(ioaddr + MALR) & 0xFF);
+		ndev->dev_addr[0] = (sh_eth_read(ndev, MAHR) >> 24);
+		ndev->dev_addr[1] = (sh_eth_read(ndev, MAHR) >> 16) & 0xFF;
+		ndev->dev_addr[2] = (sh_eth_read(ndev, MAHR) >> 8) & 0xFF;
+		ndev->dev_addr[3] = (sh_eth_read(ndev, MAHR) & 0xFF);
+		ndev->dev_addr[4] = (sh_eth_read(ndev, MALR) >> 8) & 0xFF;
+		ndev->dev_addr[5] = (sh_eth_read(ndev, MALR) & 0xFF);
 	}
 }

@@ -470,7 +457,6 @@ static void sh_eth_ring_free(struct net_device *ndev)
 /* format skb and descriptor buffer */
 static void sh_eth_ring_format(struct net_device *ndev)
 {
-	u32 ioaddr = ndev->base_addr;
 	struct sh_eth_private *mdp = netdev_priv(ndev);
 	int i;
 	struct sk_buff *skb;
@@ -506,9 +492,9 @@ static void sh_eth_ring_format(struct net_device *ndev)
 		rxdesc->buffer_length = ALIGN(mdp->rx_buf_sz, 16);
 		/* Rx descriptor address set */
 		if (i == 0) {
-			writel(mdp->rx_desc_dma, ioaddr + RDLAR);
+			sh_eth_write(ndev, mdp->rx_desc_dma, RDLAR);
 #if defined(CONFIG_CPU_SUBTYPE_SH7763)
-			writel(mdp->rx_desc_dma, ioaddr + RDFAR);
+			sh_eth_write(ndev, mdp->rx_desc_dma, RDFAR);
 #endif
 		}
 	}
@@ -528,9 +514,9 @@ static void sh_eth_ring_format(struct net_device *ndev)
 		txdesc->buffer_length = 0;
 		if (i == 0) {
 			/* Tx descriptor address set */
-			writel(mdp->tx_desc_dma, ioaddr + TDLAR);
+			sh_eth_write(ndev, mdp->tx_desc_dma, TDLAR);
 #if defined(CONFIG_CPU_SUBTYPE_SH7763)
-			writel(mdp->tx_desc_dma, ioaddr + TDFAR);
+			sh_eth_write(ndev, mdp->tx_desc_dma, TDFAR);
 #endif
 		}
 	}
@@ -613,7 +599,6 @@ static int sh_eth_dev_init(struct net_device *ndev)
 {
 	int ret = 0;
 	struct sh_eth_private *mdp = netdev_priv(ndev);
-	u32 ioaddr = ndev->base_addr;
 	u_int32_t rx_int_var, tx_int_var;
 	u32 val;

@@ -623,71 +608,71 @@ static int sh_eth_dev_init(struct net_device *ndev)
 	/* Descriptor format */
 	sh_eth_ring_format(ndev);
 	if (mdp->cd->rpadir)
-		writel(mdp->cd->rpadir_value, ioaddr + RPADIR);
+		sh_eth_write(ndev, mdp->cd->rpadir_value, RPADIR);

 	/* all sh_eth int mask */
-	writel(0, ioaddr + EESIPR);
+	sh_eth_write(ndev, 0, EESIPR);

 #if defined(__LITTLE_ENDIAN__)
 	if (mdp->cd->hw_swap)
-		writel(EDMR_EL, ioaddr + EDMR);
+		sh_eth_write(ndev, EDMR_EL, EDMR);
 	else
 #endif
-		writel(0, ioaddr + EDMR);
+		sh_eth_write(ndev, 0, EDMR);

 	/* FIFO size set */
-	writel(mdp->cd->fdr_value, ioaddr + FDR);
-	writel(0, ioaddr + TFTR);
+	sh_eth_write(ndev, mdp->cd->fdr_value, FDR);
+	sh_eth_write(ndev, 0, TFTR);

 	/* Frame recv control */
-	writel(mdp->cd->rmcr_value, ioaddr + RMCR);
+	sh_eth_write(ndev, mdp->cd->rmcr_value, RMCR);

 	rx_int_var = mdp->rx_int_var = DESC_I_RINT8 | DESC_I_RINT5;
 	tx_int_var = mdp->tx_int_var = DESC_I_TINT2;
-	writel(rx_int_var | tx_int_var, ioaddr + TRSCER);
+	sh_eth_write(ndev, rx_int_var | tx_int_var, TRSCER);

 	if (mdp->cd->bculr)
-		writel(0x800, ioaddr + BCULR);	/* Burst sycle set */
+		sh_eth_write(ndev, 0x800, BCULR);	/* Burst sycle set */

-	writel(mdp->cd->fcftr_value, ioaddr + FCFTR);
+	sh_eth_write(ndev, mdp->cd->fcftr_value, FCFTR);

 	if (!mdp->cd->no_trimd)
-		writel(0, ioaddr + TRIMD);
+		sh_eth_write(ndev, 0, TRIMD);

 	/* Recv frame limit set register */
-	writel(RFLR_VALUE, ioaddr + RFLR);
+	sh_eth_write(ndev, RFLR_VALUE, RFLR);

-	writel(readl(ioaddr + EESR), ioaddr + EESR);
-	writel(mdp->cd->eesipr_value, ioaddr + EESIPR);
+	sh_eth_write(ndev, sh_eth_read(ndev, EESR), EESR);
+	sh_eth_write(ndev, mdp->cd->eesipr_value, EESIPR);

 	/* PAUSE Prohibition */
-	val = (readl(ioaddr + ECMR) & ECMR_DM) |
+	val = (sh_eth_read(ndev, ECMR) & ECMR_DM) |
 		ECMR_ZPF | (mdp->duplex ? ECMR_DM : 0) | ECMR_TE | ECMR_RE;

-	writel(val, ioaddr + ECMR);
+	sh_eth_write(ndev, val, ECMR);

 	if (mdp->cd->set_rate)
 		mdp->cd->set_rate(ndev);

 	/* E-MAC Status Register clear */
-	writel(mdp->cd->ecsr_value, ioaddr + ECSR);
+	sh_eth_write(ndev, mdp->cd->ecsr_value, ECSR);

 	/* E-MAC Interrupt Enable register */
-	writel(mdp->cd->ecsipr_value, ioaddr + ECSIPR);
+	sh_eth_write(ndev, mdp->cd->ecsipr_value, ECSIPR);

 	/* Set MAC address */
 	update_mac_address(ndev);

 	/* mask reset */
 	if (mdp->cd->apr)
-		writel(APR_AP, ioaddr + APR);
+		sh_eth_write(ndev, APR_AP, APR);
 	if (mdp->cd->mpr)
-		writel(MPR_MP, ioaddr + MPR);
+		sh_eth_write(ndev, MPR_MP, MPR);
 	if (mdp->cd->tpauser)
-		writel(TPAUSER_UNLIMITED, ioaddr + TPAUSER);
+		sh_eth_write(ndev, TPAUSER_UNLIMITED, TPAUSER);

 	/* Setting the Rx mode will start the Rx process. */
-	writel(EDRRR_R, ioaddr + EDRRR);
+	sh_eth_write(ndev, EDRRR_R, EDRRR);

 	netif_start_queue(ndev);

@@ -811,8 +796,8 @@ static int sh_eth_rx(struct net_device *ndev)

 	/* Restart Rx engine if stopped. */
 	/* If we don't need to check status, don't. -KDU */
-	if (!(readl(ndev->base_addr + EDRRR) & EDRRR_R))
-		writel(EDRRR_R, ndev->base_addr + EDRRR);
+	if (!(sh_eth_read(ndev, EDRRR) & EDRRR_R))
+		sh_eth_write(ndev, EDRRR_R, EDRRR);

 	return 0;
 }
@@ -821,14 +806,13 @@ static int sh_eth_rx(struct net_device *ndev)
 static void sh_eth_error(struct net_device *ndev, int intr_status)
 {
 	struct sh_eth_private *mdp = netdev_priv(ndev);
-	u32 ioaddr = ndev->base_addr;
 	u32 felic_stat;
 	u32 link_stat;
 	u32 mask;

 	if (intr_status & EESR_ECI) {
-		felic_stat = readl(ioaddr + ECSR);
-		writel(felic_stat, ioaddr + ECSR);	/* clear int */
+		felic_stat = sh_eth_read(ndev, ECSR);
+		sh_eth_write(ndev, felic_stat, ECSR);	/* clear int */
 		if (felic_stat & ECSR_ICD)
 			mdp->stats.tx_carrier_errors++;
 		if (felic_stat & ECSR_LCHNG) {
@@ -839,26 +823,26 @@ static void sh_eth_error(struct net_device *ndev, int intr_status)
 				else
 					link_stat = PHY_ST_LINK;
 			} else {
-				link_stat = (readl(ioaddr + PSR));
+				link_stat = (sh_eth_read(ndev, PSR));
 				if (mdp->ether_link_active_low)
 					link_stat = ~link_stat;
 			}
 			if (!(link_stat & PHY_ST_LINK)) {
 				/* Link Down : disable tx and rx */
-				writel(readl(ioaddr + ECMR) &
-					  ~(ECMR_RE | ECMR_TE), ioaddr + ECMR);
+				sh_eth_write(ndev, sh_eth_read(ndev, ECMR) &
+					  ~(ECMR_RE | ECMR_TE), ECMR);
 			} else {
 				/* Link Up */
-				writel(readl(ioaddr + EESIPR) &
-					  ~DMAC_M_ECI, ioaddr + EESIPR);
+				sh_eth_write(ndev, sh_eth_read(ndev, EESIPR) &
+					  ~DMAC_M_ECI, EESIPR);
 				/*clear int */
-				writel(readl(ioaddr + ECSR),
-					  ioaddr + ECSR);
-				writel(readl(ioaddr + EESIPR) |
-					  DMAC_M_ECI, ioaddr + EESIPR);
+				sh_eth_write(ndev, sh_eth_read(ndev, ECSR),
+					  ECSR);
+				sh_eth_write(ndev, sh_eth_read(ndev, EESIPR) |
+					  DMAC_M_ECI, EESIPR);
 				/* enable tx and rx */
-				writel(readl(ioaddr + ECMR) |
-					  (ECMR_RE | ECMR_TE), ioaddr + ECMR);
+				sh_eth_write(ndev, sh_eth_read(ndev, ECMR) |
+					  (ECMR_RE | ECMR_TE), ECMR);
 			}
 		}
 	}
@@ -888,8 +872,8 @@ static void sh_eth_error(struct net_device *ndev, int intr_status)
 		/* Receive Descriptor Empty int */
 		mdp->stats.rx_over_errors++;

-		if (readl(ioaddr + EDRRR) ^ EDRRR_R)
-			writel(EDRRR_R, ioaddr + EDRRR);
+		if (sh_eth_read(ndev, EDRRR) ^ EDRRR_R)
+			sh_eth_write(ndev, EDRRR_R, EDRRR);
 		dev_err(&ndev->dev, "Receive Descriptor Empty\n");
 	}
 	if (intr_status & EESR_RFE) {
@@ -903,7 +887,7 @@ static void sh_eth_error(struct net_device *ndev, int intr_status)
 		mask &= ~EESR_ADE;
 	if (intr_status & mask) {
 		/* Tx error */
-		u32 edtrr = readl(ndev->base_addr + EDTRR);
+		u32 edtrr = sh_eth_read(ndev, EDTRR);
 		/* dmesg */
 		dev_err(&ndev->dev, "TX error. status=%8.8x cur_tx=%8.8x ",
 				intr_status, mdp->cur_tx);
@@ -915,7 +899,7 @@ static void sh_eth_error(struct net_device *ndev, int intr_status)
 		/* SH7712 BUG */
 		if (edtrr ^ EDTRR_TRNS) {
 			/* tx dma start */
-			writel(EDTRR_TRNS, ndev->base_addr + EDTRR);
+			sh_eth_write(ndev, EDTRR_TRNS, EDTRR);
 		}
 		/* wakeup */
 		netif_wake_queue(ndev);
@@ -928,18 +912,17 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev)
 	struct sh_eth_private *mdp = netdev_priv(ndev);
 	struct sh_eth_cpu_data *cd = mdp->cd;
 	irqreturn_t ret = IRQ_NONE;
-	u32 ioaddr, intr_status = 0;
+	u32 intr_status = 0;

-	ioaddr = ndev->base_addr;
 	spin_lock(&mdp->lock);

 	/* Get interrpt stat */
-	intr_status = readl(ioaddr + EESR);
+	intr_status = sh_eth_read(ndev, EESR);
 	/* Clear interrupt */
 	if (intr_status & (EESR_FRC | EESR_RMAF | EESR_RRF |
 			EESR_RTLF | EESR_RTSF | EESR_PRE | EESR_CERF |
 			cd->tx_check | cd->eesr_err_check)) {
-		writel(intr_status, ioaddr + EESR);
+		sh_eth_write(ndev, intr_status, EESR);
 		ret = IRQ_HANDLED;
 	} else
 		goto other_irq;
@@ -982,7 +965,6 @@ static void sh_eth_adjust_link(struct net_device *ndev)
 {
 	struct sh_eth_private *mdp = netdev_priv(ndev);
 	struct phy_device *phydev = mdp->phydev;
-	u32 ioaddr = ndev->base_addr;
 	int new_state = 0;

 	if (phydev->link != PHY_DOWN) {
@@ -1000,8 +982,8 @@ static void sh_eth_adjust_link(struct net_device *ndev)
 				mdp->cd->set_rate(ndev);
 		}
 		if (mdp->link == PHY_DOWN) {
-			writel((readl(ioaddr + ECMR) & ~ECMR_TXF)
-					| ECMR_DM, ioaddr + ECMR);
+			sh_eth_write(ndev, (sh_eth_read(ndev, ECMR) & ~ECMR_TXF)
+					| ECMR_DM, ECMR);
 			new_state = 1;
 			mdp->link = phydev->link;
 		}
@@ -1117,7 +1099,6 @@ out_free_irq:
 static void sh_eth_tx_timeout(struct net_device *ndev)
 {
 	struct sh_eth_private *mdp = netdev_priv(ndev);
-	u32 ioaddr = ndev->base_addr;
 	struct sh_eth_rxdesc *rxdesc;
 	int i;

@@ -1125,7 +1106,7 @@ static void sh_eth_tx_timeout(struct net_device *ndev)

 	/* worning message out. */
 	printk(KERN_WARNING "%s: transmit timed out, status %8.8x,"
-	       " resetting...\n", ndev->name, (int)readl(ioaddr + EESR));
+	       " resetting...\n", ndev->name, (int)sh_eth_read(ndev, EESR));

 	/* tx_errors count up */
 	mdp->stats.tx_errors++;
@@ -1196,8 +1177,8 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev)

 	mdp->cur_tx++;

-	if (!(readl(ndev->base_addr + EDTRR) & EDTRR_TRNS))
-		writel(EDTRR_TRNS, ndev->base_addr + EDTRR);
+	if (!(sh_eth_read(ndev, EDTRR) & EDTRR_TRNS))
+		sh_eth_write(ndev, EDTRR_TRNS, EDTRR);

 	return NETDEV_TX_OK;
 }
@@ -1206,17 +1187,16 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 static int sh_eth_close(struct net_device *ndev)
 {
 	struct sh_eth_private *mdp = netdev_priv(ndev);
-	u32 ioaddr = ndev->base_addr;
 	int ringsize;

 	netif_stop_queue(ndev);

 	/* Disable interrupts by clearing the interrupt mask. */
-	writel(0x0000, ioaddr + EESIPR);
+	sh_eth_write(ndev, 0x0000, EESIPR);

 	/* Stop the chip's Tx and Rx processes. */
-	writel(0, ioaddr + EDTRR);
-	writel(0, ioaddr + EDRRR);
+	sh_eth_write(ndev, 0, EDTRR);
+	sh_eth_write(ndev, 0, EDRRR);

 	/* PHY Disconnect */
 	if (mdp->phydev) {
@@ -1247,24 +1227,23 @@ static int sh_eth_close(struct net_device *ndev)
 static struct net_device_stats *sh_eth_get_stats(struct net_device *ndev)
 {
 	struct sh_eth_private *mdp = netdev_priv(ndev);
-	u32 ioaddr = ndev->base_addr;

 	pm_runtime_get_sync(&mdp->pdev->dev);

-	mdp->stats.tx_dropped += readl(ioaddr + TROCR);
-	writel(0, ioaddr + TROCR);	/* (write clear) */
-	mdp->stats.collisions += readl(ioaddr + CDCR);
-	writel(0, ioaddr + CDCR);	/* (write clear) */
-	mdp->stats.tx_carrier_errors += readl(ioaddr + LCCR);
-	writel(0, ioaddr + LCCR);	/* (write clear) */
+	mdp->stats.tx_dropped += sh_eth_read(ndev, TROCR);
+	sh_eth_write(ndev, 0, TROCR);	/* (write clear) */
+	mdp->stats.collisions += sh_eth_read(ndev, CDCR);
+	sh_eth_write(ndev, 0, CDCR);	/* (write clear) */
+	mdp->stats.tx_carrier_errors += sh_eth_read(ndev, LCCR);
+	sh_eth_write(ndev, 0, LCCR);	/* (write clear) */
 #if defined(CONFIG_CPU_SUBTYPE_SH7763)
-	mdp->stats.tx_carrier_errors += readl(ioaddr + CERCR);/* CERCR */
-	writel(0, ioaddr + CERCR);	/* (write clear) */
-	mdp->stats.tx_carrier_errors += readl(ioaddr + CEECR);/* CEECR */
-	writel(0, ioaddr + CEECR);	/* (write clear) */
+	mdp->stats.tx_carrier_errors += sh_eth_read(ndev, CERCR);/* CERCR */
+	sh_eth_write(ndev, 0, CERCR);	/* (write clear) */
+	mdp->stats.tx_carrier_errors += sh_eth_read(ndev, CEECR);/* CEECR */
+	sh_eth_write(ndev, 0, CEECR);	/* (write clear) */
 #else
-	mdp->stats.tx_carrier_errors += readl(ioaddr + CNDCR);
-	writel(0, ioaddr + CNDCR);	/* (write clear) */
+	mdp->stats.tx_carrier_errors += sh_eth_read(ndev, CNDCR);
+	sh_eth_write(ndev, 0, CNDCR);	/* (write clear) */
 #endif
 	pm_runtime_put_sync(&mdp->pdev->dev);

@@ -1291,46 +1270,44 @@ static int sh_eth_do_ioctl(struct net_device *ndev, struct ifreq *rq,
 /* Multicast reception directions set */
 static void sh_eth_set_multicast_list(struct net_device *ndev)
 {
-	u32 ioaddr = ndev->base_addr;
-
 	if (ndev->flags & IFF_PROMISC) {
 		/* Set promiscuous. */
-		writel((readl(ioaddr + ECMR) & ~ECMR_MCT) | ECMR_PRM,
-			  ioaddr + ECMR);
+		sh_eth_write(ndev, (sh_eth_read(ndev, ECMR) & ~ECMR_MCT) |
+				ECMR_PRM, ECMR);
 	} else {
 		/* Normal, unicast/broadcast-only mode. */
-		writel((readl(ioaddr + ECMR) & ~ECMR_PRM) | ECMR_MCT,
-			  ioaddr + ECMR);
+		sh_eth_write(ndev, (sh_eth_read(ndev, ECMR) & ~ECMR_PRM) |
+				ECMR_MCT, ECMR);
 	}
 }

 /* SuperH's TSU register init function */
-static void sh_eth_tsu_init(u32 ioaddr)
+static void sh_eth_tsu_init(struct sh_eth_private *mdp)
 {
-	writel(0, ioaddr + TSU_FWEN0);	/* Disable forward(0->1) */
-	writel(0, ioaddr + TSU_FWEN1);	/* Disable forward(1->0) */
-	writel(0, ioaddr + TSU_FCM);	/* forward fifo 3k-3k */
-	writel(0xc, ioaddr + TSU_BSYSL0);
-	writel(0xc, ioaddr + TSU_BSYSL1);
-	writel(0, ioaddr + TSU_PRISL0);
-	writel(0, ioaddr + TSU_PRISL1);
-	writel(0, ioaddr + TSU_FWSL0);
-	writel(0, ioaddr + TSU_FWSL1);
-	writel(TSU_FWSLC_POSTENU | TSU_FWSLC_POSTENL, ioaddr + TSU_FWSLC);
+	sh_eth_tsu_write(mdp, 0, TSU_FWEN0);	/* Disable forward(0->1) */
+	sh_eth_tsu_write(mdp, 0, TSU_FWEN1);	/* Disable forward(1->0) */
+	sh_eth_tsu_write(mdp, 0, TSU_FCM);	/* forward fifo 3k-3k */
+	sh_eth_tsu_write(mdp, 0xc, TSU_BSYSL0);
+	sh_eth_tsu_write(mdp, 0xc, TSU_BSYSL1);
+	sh_eth_tsu_write(mdp, 0, TSU_PRISL0);
+	sh_eth_tsu_write(mdp, 0, TSU_PRISL1);
+	sh_eth_tsu_write(mdp, 0, TSU_FWSL0);
+	sh_eth_tsu_write(mdp, 0, TSU_FWSL1);
+	sh_eth_tsu_write(mdp, TSU_FWSLC_POSTENU | TSU_FWSLC_POSTENL, TSU_FWSLC);
 #if defined(CONFIG_CPU_SUBTYPE_SH7763)
-	writel(0, ioaddr + TSU_QTAG0);	/* Disable QTAG(0->1) */
-	writel(0, ioaddr + TSU_QTAG1);	/* Disable QTAG(1->0) */
+	sh_eth_tsu_write(mdp, 0, TSU_QTAG0);	/* Disable QTAG(0->1) */
+	sh_eth_tsu_write(mdp, 0, TSU_QTAG1);	/* Disable QTAG(1->0) */
 #else
-	writel(0, ioaddr + TSU_QTAGM0);	/* Disable QTAG(0->1) */
-	writel(0, ioaddr + TSU_QTAGM1);	/* Disable QTAG(1->0) */
+	sh_eth_tsu_write(mdp, 0, TSU_QTAGM0);	/* Disable QTAG(0->1) */
+	sh_eth_tsu_write(mdp, 0, TSU_QTAGM1);	/* Disable QTAG(1->0) */
 #endif
-	writel(0, ioaddr + TSU_FWSR);	/* all interrupt status clear */
-	writel(0, ioaddr + TSU_FWINMK);	/* Disable all interrupt */
-	writel(0, ioaddr + TSU_TEN);	/* Disable all CAM entry */
-	writel(0, ioaddr + TSU_POST1);	/* Disable CAM entry [ 0- 7] */
-	writel(0, ioaddr + TSU_POST2);	/* Disable CAM entry [ 8-15] */
-	writel(0, ioaddr + TSU_POST3);	/* Disable CAM entry [16-23] */
-	writel(0, ioaddr + TSU_POST4);	/* Disable CAM entry [24-31] */
+	sh_eth_tsu_write(mdp, 0, TSU_FWSR);	/* all interrupt status clear */
+	sh_eth_tsu_write(mdp, 0, TSU_FWINMK);	/* Disable all interrupt */
+	sh_eth_tsu_write(mdp, 0, TSU_TEN);	/* Disable all CAM entry */
+	sh_eth_tsu_write(mdp, 0, TSU_POST1);	/* Disable CAM entry [ 0- 7] */
+	sh_eth_tsu_write(mdp, 0, TSU_POST2);	/* Disable CAM entry [ 8-15] */
+	sh_eth_tsu_write(mdp, 0, TSU_POST3);	/* Disable CAM entry [16-23] */
+	sh_eth_tsu_write(mdp, 0, TSU_POST4);	/* Disable CAM entry [24-31] */
 }
 #endif /* SH_ETH_HAS_TSU */

@@ -1369,7 +1346,7 @@ static int sh_mdio_init(struct net_device *ndev, int id)
 	}

 	/* bitbang init */
-	bitbang->addr = ndev->base_addr + PIR;
+	bitbang->addr = ndev->base_addr + mdp->reg_offset[PIR];
 	bitbang->mdi_msk = 0x08;
 	bitbang->mdo_msk = 0x04;
 	bitbang->mmd_msk = 0x02;/* MMD */
@@ -1420,6 +1397,37 @@ out:
 	return ret;
 }

+static const u16 *sh_eth_get_register_offset(int register_type)
+{
+	const u16 *reg_offset = NULL;
+
+	switch (register_type) {
+	case SH_ETH_REG_GIGABIT:
+		reg_offset = sh_eth_offset_gigabit;
+		break;
+	case SH_ETH_REG_FAST_SH4:
+		reg_offset = sh_eth_offset_fast_sh4;
+		break;
+	case SH_ETH_REG_FAST_SH3_SH2:
+		reg_offset = sh_eth_offset_fast_sh3_sh2;
+		break;
+	case SH_ETH_REG_DEFAULT:
+#if defined(CONFIG_CPU_SUBTYPE_SH7763)
+		reg_offset = sh_eth_offset_gigabit;
+#elif defined(CONFIG_CPU_SH4)
+		reg_offset = sh_eth_offset_fast_sh4;
+#else
+		reg_offset = sh_eth_offset_fast_sh3_sh2;
+#endif
+		break;
+	default:
+		printk(KERN_ERR "Unknown register type (%d)\n", register_type);
+		break;
+	}
+
+	return reg_offset;
+}
+
 static const struct net_device_ops sh_eth_netdev_ops = {
 	.ndo_open		= sh_eth_open,
 	.ndo_stop		= sh_eth_close,
@@ -1490,6 +1498,7 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
 	mdp->edmac_endian = pd->edmac_endian;
 	mdp->no_ether_link = pd->no_ether_link;
 	mdp->ether_link_active_low = pd->ether_link_active_low;
+	mdp->reg_offset = sh_eth_get_register_offset(pd->register_type);

 	/* set cpu data */
 	mdp->cd = &sh_eth_my_cpu_data;
@@ -1512,7 +1521,8 @@ static int sh_eth_drv_probe(struct platform_device *pdev)

 #if defined(SH_ETH_HAS_TSU)
 		/* TSU init (Init only)*/
-		sh_eth_tsu_init(SH_TSU_ADDR);
+		mdp->tsu_addr = SH_TSU_ADDR;
+		sh_eth_tsu_init(mdp);
 #endif
 	}

diff --git a/drivers/net/sh_eth.h b/drivers/net/sh_eth.h
index efa6422..1510a7c 100644
--- a/drivers/net/sh_eth.h
+++ b/drivers/net/sh_eth.h
@@ -2,7 +2,7 @@
  *  SuperH Ethernet device driver
  *
  *  Copyright (C) 2006-2008 Nobuhiro Iwamatsu
- *  Copyright (C) 2008-2009 Renesas Solutions Corp.
+ *  Copyright (C) 2008-2011 Renesas Solutions Corp.
  *
  *  This program is free software; you can redistribute it and/or modify it
  *  under the terms and conditions of the GNU General Public License,
@@ -38,162 +38,345 @@
 #define ETHERSMALL		60
 #define PKT_BUF_SZ		1538

+enum {
+	/* E-DMAC registers */
+	EDSR = 0,
+	EDMR,
+	EDTRR,
+	EDRRR,
+	EESR,
+	EESIPR,
+	TDLAR,
+	TDFAR,
+	TDFXR,
+	TDFFR,
+	RDLAR,
+	RDFAR,
+	RDFXR,
+	RDFFR,
+	TRSCER,
+	RMFCR,
+	TFTR,
+	FDR,
+	RMCR,
+	EDOCR,
+	TFUCR,
+	RFOCR,
+	FCFTR,
+	RPADIR,
+	TRIMD,
+	RBWAR,
+	TBRAR,
+
+	/* Ether registers */
+	ECMR,
+	ECSR,
+	ECSIPR,
+	PIR,
+	PSR,
+	RDMLR,
+	PIPR,
+	RFLR,
+	IPGR,
+	APR,
+	MPR,
+	PFTCR,
+	PFRCR,
+	RFCR,
+	RFCF,
+	TPAUSER,
+	TPAUSECR,
+	BCFR,
+	BCFRR,
+	GECMR,
+	BCULR,
+	MAHR,
+	MALR,
+	TROCR,
+	CDCR,
+	LCCR,
+	CNDCR,
+	CEFCR,
+	FRECR,
+	TSFRCR,
+	TLFRCR,
+	CERCR,
+	CEECR,
+	MAFCR,
+	RTRATE,
+
+	/* TSU Absolute address */
+	ARSTR,
+	TSU_CTRST,
+	TSU_FWEN0,
+	TSU_FWEN1,
+	TSU_FCM,
+	TSU_BSYSL0,
+	TSU_BSYSL1,
+	TSU_PRISL0,
+	TSU_PRISL1,
+	TSU_FWSL0,
+	TSU_FWSL1,
+	TSU_FWSLC,
+	TSU_QTAG0,
+	TSU_QTAG1,
+	TSU_QTAGM0,
+	TSU_QTAGM1,
+	TSU_FWSR,
+	TSU_FWINMK,
+	TSU_ADQT0,
+	TSU_ADQT1,
+	TSU_VTAG0,
+	TSU_VTAG1,
+	TSU_ADSBSY,
+	TSU_TEN,
+	TSU_POST1,
+	TSU_POST2,
+	TSU_POST3,
+	TSU_POST4,
+	TSU_ADRH0,
+	TSU_ADRL0,
+	TSU_ADRH31,
+	TSU_ADRL31,
+
+	TXNLCR0,
+	TXALCR0,
+	RXNLCR0,
+	RXALCR0,
+	FWNLCR0,
+	FWALCR0,
+	TXNLCR1,
+	TXALCR1,
+	RXNLCR1,
+	RXALCR1,
+	FWNLCR1,
+	FWALCR1,
+
+	/* This value must be written at last. */
+	SH_ETH_MAX_REGISTER_OFFSET,
+};
+
+static const u16 sh_eth_offset_gigabit[SH_ETH_MAX_REGISTER_OFFSET] = {
+	[EDSR]	= 0x0000,
+	[EDMR]	= 0x0400,
+	[EDTRR]	= 0x0408,
+	[EDRRR]	= 0x0410,
+	[EESR]	= 0x0428,
+	[EESIPR]	= 0x0430,
+	[TDLAR]	= 0x0010,
+	[TDFAR]	= 0x0014,
+	[TDFXR]	= 0x0018,
+	[TDFFR]	= 0x001c,
+	[RDLAR]	= 0x0030,
+	[RDFAR]	= 0x0034,
+	[RDFXR]	= 0x0038,
+	[RDFFR]	= 0x003c,
+	[TRSCER]	= 0x0438,
+	[RMFCR]	= 0x0440,
+	[TFTR]	= 0x0448,
+	[FDR]	= 0x0450,
+	[RMCR]	= 0x0458,
+	[RPADIR]	= 0x0460,
+	[FCFTR]	= 0x0468,
+
+	[ECMR]	= 0x0500,
+	[ECSR]	= 0x0510,
+	[ECSIPR]	= 0x0518,
+	[PIR]	= 0x0520,
+	[PSR]	= 0x0528,
+	[PIPR]	= 0x052c,
+	[RFLR]	= 0x0508,
+	[APR]	= 0x0554,
+	[MPR]	= 0x0558,
+	[PFTCR]	= 0x055c,
+	[PFRCR]	= 0x0560,
+	[TPAUSER]	= 0x0564,
+	[GECMR]	= 0x05b0,
+	[BCULR]	= 0x05b4,
+	[MAHR]	= 0x05c0,
+	[MALR]	= 0x05c8,
+	[TROCR]	= 0x0700,
+	[CDCR]	= 0x0708,
+	[LCCR]	= 0x0710,
+	[CEFCR]	= 0x0740,
+	[FRECR]	= 0x0748,
+	[TSFRCR]	= 0x0750,
+	[TLFRCR]	= 0x0758,
+	[RFCR]	= 0x0760,
+	[CERCR]	= 0x0768,
+	[CEECR]	= 0x0770,
+	[MAFCR]	= 0x0778,
+
+	[TSU_CTRST]	= 0x0004,
+	[TSU_FWEN0]	= 0x0010,
+	[TSU_FWEN1]	= 0x0014,
+	[TSU_FCM]	= 0x0018,
+	[TSU_BSYSL0]	= 0x0020,
+	[TSU_BSYSL1]	= 0x0024,
+	[TSU_PRISL0]	= 0x0028,
+	[TSU_PRISL1]	= 0x002c,
+	[TSU_FWSL0]	= 0x0030,
+	[TSU_FWSL1]	= 0x0034,
+	[TSU_FWSLC]	= 0x0038,
+	[TSU_QTAG0]	= 0x0040,
+	[TSU_QTAG1]	= 0x0044,
+	[TSU_FWSR]	= 0x0050,
+	[TSU_FWINMK]	= 0x0054,
+	[TSU_ADQT0]	= 0x0048,
+	[TSU_ADQT1]	= 0x004c,
+	[TSU_VTAG0]	= 0x0058,
+	[TSU_VTAG1]	= 0x005c,
+	[TSU_ADSBSY]	= 0x0060,
+	[TSU_TEN]	= 0x0064,
+	[TSU_POST1]	= 0x0070,
+	[TSU_POST2]	= 0x0074,
+	[TSU_POST3]	= 0x0078,
+	[TSU_POST4]	= 0x007c,
+	[TSU_ADRH0]	= 0x0100,
+	[TSU_ADRL0]	= 0x0104,
+	[TSU_ADRH31]	= 0x01f8,
+	[TSU_ADRL31]	= 0x01fc,
+
+	[TXNLCR0]	= 0x0080,
+	[TXALCR0]	= 0x0084,
+	[RXNLCR0]	= 0x0088,
+	[RXALCR0]	= 0x008c,
+	[FWNLCR0]	= 0x0090,
+	[FWALCR0]	= 0x0094,
+	[TXNLCR1]	= 0x00a0,
+	[TXALCR1]	= 0x00a0,
+	[RXNLCR1]	= 0x00a8,
+	[RXALCR1]	= 0x00ac,
+	[FWNLCR1]	= 0x00b0,
+	[FWALCR1]	= 0x00b4,
+};
+
+static const u16 sh_eth_offset_fast_sh4[SH_ETH_MAX_REGISTER_OFFSET] = {
+	[ECMR]	= 0x0100,
+	[RFLR]	= 0x0108,
+	[ECSR]	= 0x0110,
+	[ECSIPR]	= 0x0118,
+	[PIR]	= 0x0120,
+	[PSR]	= 0x0128,
+	[RDMLR]	= 0x0140,
+	[IPGR]	= 0x0150,
+	[APR]	= 0x0154,
+	[MPR]	= 0x0158,
+	[TPAUSER]	= 0x0164,
+	[RFCF]	= 0x0160,
+	[TPAUSECR]	= 0x0168,
+	[BCFRR]	= 0x016c,
+	[MAHR]	= 0x01c0,
+	[MALR]	= 0x01c8,
+	[TROCR]	= 0x01d0,
+	[CDCR]	= 0x01d4,
+	[LCCR]	= 0x01d8,
+	[CNDCR]	= 0x01dc,
+	[CEFCR]	= 0x01e4,
+	[FRECR]	= 0x01e8,
+	[TSFRCR]	= 0x01ec,
+	[TLFRCR]	= 0x01f0,
+	[RFCR]	= 0x01f4,
+	[MAFCR]	= 0x01f8,
+	[RTRATE]	= 0x01fc,
+
+	[EDMR]	= 0x0000,
+	[EDTRR]	= 0x0008,
+	[EDRRR]	= 0x0010,
+	[TDLAR]	= 0x0018,
+	[RDLAR]	= 0x0020,
+	[EESR]	= 0x0028,
+	[EESIPR]	= 0x0030,
+	[TRSCER]	= 0x0038,
+	[RMFCR]	= 0x0040,
+	[TFTR]	= 0x0048,
+	[FDR]	= 0x0050,
+	[RMCR]	= 0x0058,
+	[TFUCR]	= 0x0064,
+	[RFOCR]	= 0x0068,
+	[FCFTR]	= 0x0070,
+	[RPADIR]	= 0x0078,
+	[TRIMD]	= 0x007c,
+	[RBWAR]	= 0x00c8,
+	[RDFAR]	= 0x00cc,
+	[TBRAR]	= 0x00d4,
+	[TDFAR]	= 0x00d8,
+};
+
+static const u16 sh_eth_offset_fast_sh3_sh2[SH_ETH_MAX_REGISTER_OFFSET] = {
+	[ECMR]	= 0x0160,
+	[ECSR]	= 0x0164,
+	[ECSIPR]	= 0x0168,
+	[PIR]	= 0x016c,
+	[MAHR]	= 0x0170,
+	[MALR]	= 0x0174,
+	[RFLR]	= 0x0178,
+	[PSR]	= 0x017c,
+	[TROCR]	= 0x0180,
+	[CDCR]	= 0x0184,
+	[LCCR]	= 0x0188,
+	[CNDCR]	= 0x018c,
+	[CEFCR]	= 0x0194,
+	[FRECR]	= 0x0198,
+	[TSFRCR]	= 0x019c,
+	[TLFRCR]	= 0x01a0,
+	[RFCR]	= 0x01a4,
+	[MAFCR]	= 0x01a8,
+	[IPGR]	= 0x01b4,
+	[APR]	= 0x01b8,
+	[MPR]	= 0x01bc,
+	[TPAUSER]	= 0x01c4,
+	[BCFR]	= 0x01cc,
+
+	[TSU_CTRST]	= 0x0004,
+	[TSU_FWEN0]	= 0x0010,
+	[TSU_FWEN1]	= 0x0014,
+	[TSU_FCM]	= 0x0018,
+	[TSU_BSYSL0]	= 0x0020,
+	[TSU_BSYSL1]	= 0x0024,
+	[TSU_PRISL0]	= 0x0028,
+	[TSU_PRISL1]	= 0x002c,
+	[TSU_FWSL0]	= 0x0030,
+	[TSU_FWSL1]	= 0x0034,
+	[TSU_FWSLC]	= 0x0038,
+	[TSU_QTAGM0]	= 0x0040,
+	[TSU_QTAGM1]	= 0x0044,
+	[TSU_ADQT0]	= 0x0048,
+	[TSU_ADQT1]	= 0x004c,
+	[TSU_FWSR]	= 0x0050,
+	[TSU_FWINMK]	= 0x0054,
+	[TSU_ADSBSY]	= 0x0060,
+	[TSU_TEN]	= 0x0064,
+	[TSU_POST1]	= 0x0070,
+	[TSU_POST2]	= 0x0074,
+	[TSU_POST3]	= 0x0078,
+	[TSU_POST4]	= 0x007c,
+
+	[TXNLCR0]	= 0x0080,
+	[TXALCR0]	= 0x0084,
+	[RXNLCR0]	= 0x0088,
+	[RXALCR0]	= 0x008c,
+	[FWNLCR0]	= 0x0090,
+	[FWALCR0]	= 0x0094,
+	[TXNLCR1]	= 0x00a0,
+	[TXALCR1]	= 0x00a0,
+	[RXNLCR1]	= 0x00a8,
+	[RXALCR1]	= 0x00ac,
+	[FWNLCR1]	= 0x00b0,
+	[FWALCR1]	= 0x00b4,
+
+	[TSU_ADRH0]	= 0x0100,
+	[TSU_ADRL0]	= 0x0104,
+	[TSU_ADRL31]	= 0x01fc,
+
+};
+
 #if defined(CONFIG_CPU_SUBTYPE_SH7763)
 /* This CPU register maps is very difference by other SH4 CPU */
-
 /* Chip Base Address */
 # define SH_TSU_ADDR	0xFEE01800
 # define ARSTR		SH_TSU_ADDR
-
-/* Chip Registers */
-/* E-DMAC */
-# define EDSR    0x000
-# define EDMR    0x400
-# define EDTRR   0x408
-# define EDRRR   0x410
-# define EESR    0x428
-# define EESIPR  0x430
-# define TDLAR   0x010
-# define TDFAR   0x014
-# define TDFXR   0x018
-# define TDFFR   0x01C
-# define RDLAR   0x030
-# define RDFAR   0x034
-# define RDFXR   0x038
-# define RDFFR   0x03C
-# define TRSCER  0x438
-# define RMFCR   0x440
-# define TFTR    0x448
-# define FDR     0x450
-# define RMCR    0x458
-# define RPADIR  0x460
-# define FCFTR   0x468
-
-/* Ether Register */
-# define ECMR    0x500
-# define ECSR    0x510
-# define ECSIPR  0x518
-# define PIR     0x520
-# define PSR     0x528
-# define PIPR    0x52C
-# define RFLR    0x508
-# define APR     0x554
-# define MPR     0x558
-# define PFTCR	 0x55C
-# define PFRCR	 0x560
-# define TPAUSER 0x564
-# define GECMR   0x5B0
-# define BCULR   0x5B4
-# define MAHR    0x5C0
-# define MALR    0x5C8
-# define TROCR   0x700
-# define CDCR    0x708
-# define LCCR    0x710
-# define CEFCR   0x740
-# define FRECR   0x748
-# define TSFRCR  0x750
-# define TLFRCR  0x758
-# define RFCR    0x760
-# define CERCR   0x768
-# define CEECR   0x770
-# define MAFCR   0x778
-
-/* TSU Absolute Address */
-# define TSU_CTRST       0x004
-# define TSU_FWEN0       0x010
-# define TSU_FWEN1       0x014
-# define TSU_FCM         0x18
-# define TSU_BSYSL0      0x20
-# define TSU_BSYSL1      0x24
-# define TSU_PRISL0      0x28
-# define TSU_PRISL1      0x2C
-# define TSU_FWSL0       0x30
-# define TSU_FWSL1       0x34
-# define TSU_FWSLC       0x38
-# define TSU_QTAG0       0x40
-# define TSU_QTAG1       0x44
-# define TSU_FWSR        0x50
-# define TSU_FWINMK      0x54
-# define TSU_ADQT0       0x48
-# define TSU_ADQT1       0x4C
-# define TSU_VTAG0       0x58
-# define TSU_VTAG1       0x5C
-# define TSU_ADSBSY      0x60
-# define TSU_TEN         0x64
-# define TSU_POST1       0x70
-# define TSU_POST2       0x74
-# define TSU_POST3       0x78
-# define TSU_POST4       0x7C
-# define TSU_ADRH0       0x100
-# define TSU_ADRL0       0x104
-# define TSU_ADRH31      0x1F8
-# define TSU_ADRL31      0x1FC
-
-# define TXNLCR0         0x80
-# define TXALCR0         0x84
-# define RXNLCR0         0x88
-# define RXALCR0         0x8C
-# define FWNLCR0         0x90
-# define FWALCR0         0x94
-# define TXNLCR1         0xA0
-# define TXALCR1         0xA4
-# define RXNLCR1         0xA8
-# define RXALCR1         0xAC
-# define FWNLCR1         0xB0
-# define FWALCR1         0x40
-
 #elif defined(CONFIG_CPU_SH4)	/* #if defined(CONFIG_CPU_SUBTYPE_SH7763) */
-/* EtherC */
-#define ECMR		0x100
-#define RFLR		0x108
-#define ECSR		0x110
-#define ECSIPR		0x118
-#define PIR		0x120
-#define PSR		0x128
-#define RDMLR		0x140
-#define IPGR		0x150
-#define APR		0x154
-#define MPR		0x158
-#define TPAUSER		0x164
-#define RFCF		0x160
-#define TPAUSECR	0x168
-#define BCFRR		0x16c
-#define MAHR		0x1c0
-#define MALR		0x1c8
-#define TROCR		0x1d0
-#define CDCR		0x1d4
-#define LCCR		0x1d8
-#define CNDCR		0x1dc
-#define CEFCR		0x1e4
-#define FRECR		0x1e8
-#define TSFRCR		0x1ec
-#define TLFRCR		0x1f0
-#define RFCR		0x1f4
-#define MAFCR		0x1f8
-#define RTRATE		0x1fc
-
-/* E-DMAC */
-#define EDMR		0x000
-#define EDTRR		0x008
-#define EDRRR		0x010
-#define TDLAR		0x018
-#define RDLAR		0x020
-#define EESR		0x028
-#define EESIPR		0x030
-#define TRSCER		0x038
-#define RMFCR		0x040
-#define TFTR		0x048
-#define FDR		0x050
-#define RMCR		0x058
-#define TFUCR		0x064
-#define RFOCR		0x068
-#define FCFTR		0x070
-#define RPADIR		0x078
-#define TRIMD		0x07c
-#define RBWAR		0x0c8
-#define RDFAR		0x0cc
-#define TBRAR		0x0d4
-#define TDFAR		0x0d8
 #else /* #elif defined(CONFIG_CPU_SH4) */
 /* This section is SH3 or SH2 */
 #ifndef CONFIG_CPU_SUBTYPE_SH7619
@@ -201,116 +384,8 @@
 # define SH_TSU_ADDR  0xA7000804
 # define ARSTR		  0xA7000800
 #endif
-/* Chip Registers */
-/* E-DMAC */
-# define EDMR	0x0000
-# define EDTRR	0x0004
-# define EDRRR	0x0008
-# define TDLAR	0x000C
-# define RDLAR	0x0010
-# define EESR	0x0014
-# define EESIPR	0x0018
-# define TRSCER	0x001C
-# define RMFCR	0x0020
-# define TFTR	0x0024
-# define FDR	0x0028
-# define RMCR	0x002C
-# define EDOCR	0x0030
-# define FCFTR	0x0034
-# define RPADIR	0x0038
-# define TRIMD	0x003C
-# define RBWAR	0x0040
-# define RDFAR	0x0044
-# define TBRAR	0x004C
-# define TDFAR	0x0050
-
-/* Ether Register */
-# define ECMR	0x0160
-# define ECSR	0x0164
-# define ECSIPR	0x0168
-# define PIR	0x016C
-# define MAHR	0x0170
-# define MALR	0x0174
-# define RFLR	0x0178
-# define PSR	0x017C
-# define TROCR	0x0180
-# define CDCR	0x0184
-# define LCCR	0x0188
-# define CNDCR	0x018C
-# define CEFCR	0x0194
-# define FRECR	0x0198
-# define TSFRCR	0x019C
-# define TLFRCR	0x01A0
-# define RFCR	0x01A4
-# define MAFCR	0x01A8
-# define IPGR	0x01B4
-# if defined(CONFIG_CPU_SUBTYPE_SH7710)
-# define APR	0x01B8
-# define MPR 	0x01BC
-# define TPAUSER 0x1C4
-# define BCFR	0x1CC
-# endif /* CONFIG_CPU_SH7710 */
-
-/* TSU */
-# define TSU_CTRST	0x004
-# define TSU_FWEN0	0x010
-# define TSU_FWEN1	0x014
-# define TSU_FCM	0x018
-# define TSU_BSYSL0	0x020
-# define TSU_BSYSL1	0x024
-# define TSU_PRISL0	0x028
-# define TSU_PRISL1	0x02C
-# define TSU_FWSL0	0x030
-# define TSU_FWSL1	0x034
-# define TSU_FWSLC	0x038
-# define TSU_QTAGM0	0x040
-# define TSU_QTAGM1	0x044
-# define TSU_ADQT0 	0x048
-# define TSU_ADQT1	0x04C
-# define TSU_FWSR	0x050
-# define TSU_FWINMK	0x054
-# define TSU_ADSBSY	0x060
-# define TSU_TEN	0x064
-# define TSU_POST1	0x070
-# define TSU_POST2	0x074
-# define TSU_POST3	0x078
-# define TSU_POST4	0x07C
-# define TXNLCR0	0x080
-# define TXALCR0	0x084
-# define RXNLCR0	0x088
-# define RXALCR0	0x08C
-# define FWNLCR0	0x090
-# define FWALCR0	0x094
-# define TXNLCR1	0x0A0
-# define TXALCR1	0x0A4
-# define RXNLCR1	0x0A8
-# define RXALCR1	0x0AC
-# define FWNLCR1	0x0B0
-# define FWALCR1	0x0B4
-
-#define TSU_ADRH0	0x0100
-#define TSU_ADRL0	0x0104
-#define TSU_ADRL31	0x01FC
-
 #endif /* CONFIG_CPU_SUBTYPE_SH7763 */

-/* There are avoid compile error... */
-#if !defined(BCULR)
-#define BCULR	0x0fc
-#endif
-#if !defined(TRIMD)
-#define TRIMD	0x0fc
-#endif
-#if !defined(APR)
-#define APR	0x0fc
-#endif
-#if !defined(MPR)
-#define MPR	0x0fc
-#endif
-#if !defined(TPAUSER)
-#define TPAUSER	0x0fc
-#endif
-
 /* Driver's parameters */
 #if defined(CONFIG_CPU_SH4)
 #define SH4_SKB_RX_ALIGN	32
@@ -704,6 +779,8 @@ struct sh_eth_cpu_data {
 struct sh_eth_private {
 	struct platform_device *pdev;
 	struct sh_eth_cpu_data *cd;
+	const u16 *reg_offset;
+	void __iomem *tsu_addr;
 	dma_addr_t rx_desc_dma;
 	dma_addr_t tx_desc_dma;
 	struct sh_eth_rxdesc *rx_ring;
@@ -746,4 +823,32 @@ static inline void sh_eth_soft_swap(char *src, int len)
 #endif
 }

+static inline void sh_eth_write(struct net_device *ndev, unsigned long data,
+				int enum_index)
+{
+	struct sh_eth_private *mdp = netdev_priv(ndev);
+
+	writel(data, ndev->base_addr + mdp->reg_offset[enum_index]);
+}
+
+static inline unsigned long sh_eth_read(struct net_device *ndev,
+					int enum_index)
+{
+	struct sh_eth_private *mdp = netdev_priv(ndev);
+
+	return readl(ndev->base_addr + mdp->reg_offset[enum_index]);
+}
+
+static inline void sh_eth_tsu_write(struct sh_eth_private *mdp,
+				unsigned long data, int enum_index)
+{
+	writel(data, mdp->tsu_addr + mdp->reg_offset[enum_index]);
+}
+
+static inline unsigned long sh_eth_tsu_read(struct sh_eth_private *mdp,
+					int enum_index)
+{
+	return readl(mdp->tsu_addr + mdp->reg_offset[enum_index]);
+}
+
 #endif	/* #ifndef __SH_ETH_H__ */
-- 
1.7.1


^ permalink raw reply related

* Re: [PATCH] virtio: use __GFP_NOWARN for try_fill_recv in virtnet_poll
From: Rusty Russell @ 2011-02-15 11:09 UTC (permalink / raw)
  To: Michal Hocko; +Cc: Michael S. Tsirkin, virtualization, netdev, linux-kernel
In-Reply-To: <20110215102549.GD8341@tiehlicka.suse.cz>

On Tue, 15 Feb 2011 08:55:50 pm Michal Hocko wrote:
> On Tue 15-02-11 20:41:29, Rusty Russell wrote:
> > On Tue, 15 Feb 2011 08:05:27 pm Michal Hocko wrote:
> > > Hi,
> > > we have started seeing a lot of allocator messages complaining about
> > > failed allocations from virtnet_poll in soft IRQ. Could you consider the
> > > following patch, please?
> > 
> > Do we really want to silence this?  Isn't warning about it kind of the
> > point?  Your network is probably sucking if this happens...
> 
> What can user do about it? Is the low level memory allocator message
> very much usefull for him?  Maybe we can add a printk_once in the fail
> path with some more useful and virtio specific message.

That's an argument against ever printing any message.

What we need to know is why does this happen with virtio_net and not other
cards?  If it happens to them too, and they silently fall back, all good.

I want to make sure we're not papering over a real problem...

Thanks,
Rusty.

^ permalink raw reply

* Re: Process for subsystem maintainers to get Hyper-V code out of staging.
From: Alan Cox @ 2011-02-15 10:33 UTC (permalink / raw)
  To: Hank Janssen
  Cc: shemminger@linux-foundation.org, netdev@vger.kernel.org,
	davem@davemloft.net, linux-ide@vger.kernel.org,
	Jame.Bottomley@HansenPartnership.com, linux-scsi@vger.kernel.org,
	KY Srinivasan, Hashir Abdi, Mike Sterling, Haiyang Zhang,
	gregkh@suse.de
In-Reply-To: <8AFC7968D54FB448A30D8F38F259C56233F95737@TK5EX14MBXC114.redmond.corp.microsoft.com>

> 	1. Most important thing of course, did we contact the correct subsystem 
> 	    maintainers?
> 		i. IDE/Blkvsc		David Miller

Libata - Jeff Garzik & linux-ide@vger.kernel.org

drivers/ide is obsolete and on its way out.

drivers/ata replaced it as the old code couldn't really cope with things
like SATA NCQ or hotplug. The new stuff can which is probably handy in a
hypervisor.

> 		ii. SCSI/Storvsc		James Bottomley

Yes & linux-scsi@vger.kernel.org

> 		iii. Network/Netvsc	Stephen Hemminger
> 	2. What is the process to submit the code for review?

See: Documentation/SubmittingPatches in your kernel tree

That should answer the rest. If not then keep a tag on things that should
have been in there but weren't and that can also get updated.

^ permalink raw reply

* Re: [PATCH] virtio: use __GFP_NOWARN for try_fill_recv in virtnet_poll
From: Michal Hocko @ 2011-02-15 10:25 UTC (permalink / raw)
  To: Rusty Russell; +Cc: Michael S. Tsirkin, virtualization, netdev, linux-kernel
In-Reply-To: <201102152041.29179.rusty@rustcorp.com.au>

On Tue 15-02-11 20:41:29, Rusty Russell wrote:
> On Tue, 15 Feb 2011 08:05:27 pm Michal Hocko wrote:
> > Hi,
> > we have started seeing a lot of allocator messages complaining about
> > failed allocations from virtnet_poll in soft IRQ. Could you consider the
> > following patch, please?
> 
> Do we really want to silence this?  Isn't warning about it kind of the
> point?  Your network is probably sucking if this happens...

What can user do about it? Is the low level memory allocator message
very much usefull for him?  Maybe we can add a printk_once in the fail
path with some more useful and virtio specific message.

Thanks
-- 
Michal Hocko
SUSE Labs
SUSE LINUX s.r.o.
Lihovarska 1060/12
190 00 Praha 9    
Czech Republic

^ permalink raw reply

* Re: Process for subsystem maintainers to get Hyper-V code out of staging.
From: Christoph Hellwig @ 2011-02-15 10:21 UTC (permalink / raw)
  To: Hank Janssen
  Cc: shemminger@linux-foundation.org, netdev@vger.kernel.org,
	davem@davemloft.net, linux-ide@vger.kernel.org,
	Jame.Bottomley@HansenPartnership.com, linux-scsi@vger.kernel.org,
	KY Srinivasan, Hashir Abdi, Mike Sterling, Haiyang Zhang,
	gregkh@suse.de
In-Reply-To: <8AFC7968D54FB448A30D8F38F259C56233F95737@TK5EX14MBXC114.redmond.corp.microsoft.com>

Please give all the driver a unique prefix, hv_ is a bit to generic.
mshv might be better.

What's the point of the blksvc driver?  It is implemented as a block
driver, steals the major number of the IDE driver, which is a big no-no
and speaks a SCSI-like protocol to the host.  In what way does this
protocol differ from the full SCSI protocol in the storvsc driver?

As far as the storsvc driver is converned: please merge the storvsc.c
and storvsc_drv.c, as they are only used together.  Also please try to
clean up the way you use function pointers.  E.g. the
OnDeviceAdd/OnDeviceRemove/OnCleanup methods should be part of a
mshv_driver structure, and not store into individual objects.

Please get rid of the *_context structure that only have a single
intance anyway.  In generaly a Linux driver should not have any global
state except for maybe module paramters or a list of devices in cases
where the device model can't handle that.

Please clean up the calling convention for the init code, there is
absolutely no reason to pass stor_vsc_initialize as a function pointer
to storvsc_drv_init instead of calling it directly, and in fact there
is no reason to not just inline both of those into storvsc_init.  One
all the function pointers are moved into a driver struct and the global
context is gone there will be almost no code left in there anyway.

Similarly the exit routine is implemented entirely wrong.  The core
bus layer should iterate over all devices for the driver beeing
unregister and call back into the ->remove callback just for that
device.  Try to follow common real hardware busses like pci, usb or for
a really simple one eisa in your design.

There is no reason to have a per-device slab cache, a global one is
enough.  But for per-I/O allocations you'll need a mempool to make it
deadlock-free.

Do you really need scsi_scan_host for a virtualized scsi transport?  Is
there no way for the host to tell you which LUNs actually are present?

Why do you bother to linearize S/G lists?  If your host can't handle it
just tell the scsi layer that you have a sg_tablesize of 1, which means
you'll never get multiple S/G elements.  (Not doing SG is really, really
sad for new virtual hardware btw, please take the crack away from the
person who designed it).

Also can you please avoid forward declaration of functions as much as
possible?  They really make the code hard to read if used as much as in
these drivers.

That's it for the first round, I'm pretty sure there will be more
comments once the code is better structured and more readabke.

^ permalink raw reply

* Re: [PATCH] virtio: use __GFP_NOWARN for try_fill_recv in virtnet_poll
From: Rusty Russell @ 2011-02-15 10:11 UTC (permalink / raw)
  To: Michal Hocko; +Cc: Michael S. Tsirkin, virtualization, netdev, linux-kernel
In-Reply-To: <20110215093527.GB8341@tiehlicka.suse.cz>

On Tue, 15 Feb 2011 08:05:27 pm Michal Hocko wrote:
> Hi,
> we have started seeing a lot of allocator messages complaining about
> failed allocations from virtnet_poll in soft IRQ. Could you consider the
> following patch, please?

Do we really want to silence this?  Isn't warning about it kind of the
point?  Your network is probably sucking if this happens...

Cheers,
Rusty.

^ permalink raw reply

* Re: [PATCH 1/1] ARC VMAC ethernet driver.
From: Eric Dumazet @ 2011-02-15 10:02 UTC (permalink / raw)
  To: Andreas Fenkart; +Cc: davem, netdev
In-Reply-To: <1297762288-9263-1-git-send-email-afenkart@gmail.com>

Le mardi 15 février 2011 à 10:31 +0100, Andreas Fenkart a écrit :
> Signed-off-by: Andreas Fenkart <afenkart@gmail.com>


> +		processed++;
> +		skb->dev = dev;
	eth_type_trans() already sets "skb->dev = dev;"

> +		skb->protocol = eth_type_trans(skb, dev);
> +		ap->stats.rx_packets++;
Hmm, why dont you use dev->stats internal structure ? No need to
maintain a shadow in ap->stats.

> +		ap->stats.rx_bytes += skb->len;
> +		dev->last_rx = jiffies;
	/* last_rx = jiffies; not needed anymore  */


> +		netif_rx(skb);

A NAPI driver should use netif_receive_skb(), not netif_rx()




^ permalink raw reply

* [PATCH] virtio: use __GFP_NOWARN for try_fill_recv in virtnet_poll
From: Michal Hocko @ 2011-02-15  9:35 UTC (permalink / raw)
  To: Rusty Russell; +Cc: Michael S. Tsirkin, virtualization, netdev, linux-kernel

Hi,
we have started seeing a lot of allocator messages complaining about
failed allocations from virtnet_poll in soft IRQ. Could you consider the
following patch, please?

The patch is based on 2.6.38-rc4.
--- 
>From aabc19f22915dafeac0f1f6aa7cb7e49a8021ba1 Mon Sep 17 00:00:00 2001
From: Michal Hocko <mhocko@suse.cz>
Date: Tue, 15 Feb 2011 10:20:59 +0100
Subject: [PATCH] virtio: use __GFP_NOWARN for try_fill_recv in virtnet_poll

virtnet_poll is called from soft IRQ and it tries to allocate GFP_ATOMIC
memory (through try_fill_recv). This allocation can fail and we are
falling back to schedule_delayed_work in that case.

Let's add __GFP_NOWARN to the allocation flags to get rid of the
allocator complains for failed allocations:

[22798.508903] The following is only an harmless informational message.
[22798.508909] Unless you get a _continuous_flood_ of these messages it means
[22798.508911] everything is working fine. Allocations from irqs cannot be
[22798.508913] perfectly reliable and the kernel is designed to handle that.
[22798.508917] loop3: page allocation failure. order:0, mode:0x20, alloc_flags:0x30 pflags:0x80208040

Signed-off-by: Michal Hocko <mhocko@suse.cz>
---
 drivers/net/virtio_net.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 90a23e4..aea1e51 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -477,7 +477,7 @@ again:
 	}
 
 	if (vi->num < vi->max / 2) {
-		if (!try_fill_recv(vi, GFP_ATOMIC))
+		if (!try_fill_recv(vi, GFP_ATOMIC|__GFP_NOWARN))
 			schedule_delayed_work(&vi->refill, 0);
 	}
 
-- 
1.7.2.3


-- 
Michal Hocko
SUSE Labs
SUSE LINUX s.r.o.
Lihovarska 1060/12
190 00 Praha 9    
Czech Republic

^ permalink raw reply related

* [PATCH 1/1] ARC VMAC ethernet driver.
From: Andreas Fenkart @ 2011-02-15  9:31 UTC (permalink / raw)
  To: davem; +Cc: netdev, Andreas Fenkart
In-Reply-To: <20101208.090040.39174008.davem@davemloft.net>

Signed-off-by: Andreas Fenkart <afenkart@gmail.com>
---
 drivers/net/Kconfig   |   10 +
 drivers/net/Makefile  |    1 +
 drivers/net/arcvmac.c | 1495 +++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/arcvmac.h |  266 +++++++++
 4 files changed, 1772 insertions(+), 0 deletions(-)

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 0382332..ab239da 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -251,6 +251,16 @@ config AX88796_93CX6
 	help
 	  Select this if your platform comes with an external 93CX6 eeprom.
 
+config ARCVMAC
+	tristate "ARC VMAC ethernet support"
+	depends on HAS_DMA
+	select MII
+	select PHYLIB
+	select CRC32
+
+	help
+	  MAC present on Zoran Quatro43XX
+
 config MACE
 	tristate "MACE (Power Mac ethernet) support"
 	depends on PPC_PMAC && PPC32
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index b90738d..059e253 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -140,6 +140,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..099f4c8
--- /dev/null
+++ b/drivers/net/arcvmac.c
@@ -0,0 +1,1495 @@
+/*
+ * 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-2011 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
+ */
+
+#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/sched.h>
+#include <linux/types.h>
+
+#include "arcvmac.h"
+
+/* Register access macros */
+#define vmac_writel(port, value, reg)	\
+	writel(cpu_to_le32(value), (port)->regs + VMAC_##reg)
+#define vmac_readl(port, reg)	le32_to_cpu(readl((port)->regs + VMAC_##reg))
+
+static int get_register_map(struct vmac_priv *ap);
+static int put_register_map(struct vmac_priv *ap);
+
+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;
+
+	WARN_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 */
+	WARN_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 */
+	WARN_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 *vmac_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(&ap->pdev->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(&ap->pdev->dev, "could not attach to PHY %d\n", err);
+		goto err_out;
+	}
+
+	phydev->supported &= PHY_BASIC_FEATURES;
+	phydev->supported |= SUPPORTED_Asym_Pause | SUPPORTED_Pause;
+
+	vmac_clk = clk_get(&ap->pdev->dev, "arcvmac");
+	if (IS_ERR(vmac_clk)) {
+		err = PTR_ERR(vmac_clk);
+		goto err_disconnect;
+	}
+
+	clock_rate = clk_get_rate(vmac_clk);
+	clk_put(vmac_clk);
+
+	dev_dbg(&ap->pdev->dev, "vmac_clk: %lu Hz\n", 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)
+{
+	unsigned long flags;
+	int err, i;
+
+	spin_lock_irqsave(&ap->lock, flags);
+
+	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;
+
+	spin_unlock_irqrestore(&ap->lock, flags);
+
+	/* locking: mdio concurrency */
+
+	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_unlocked(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, 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%pP", &ap->mem->start);
+}
+
+static int update_error_counters_unlocked(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 */
+	WARN_ON(status & TXCH_MASK);
+	WARN_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_unlocked(struct net_device *dev, int status)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+
+	if (status & BD_UFLO)
+		ap->stats.tx_fifo_errors++;
+
+	if (ap->duplex)
+		return;
+
+	/* half duplex flags */
+	if (status & BD_LTCL)
+		ap->stats.tx_window_errors++;
+	if (status & BD_RETRY_CT)
+		ap->stats.collisions += (status & BD_RETRY_CT) >> 24;
+	if (status & BD_DROP)  /* too many retries */
+		ap->stats.tx_aborted_errors++;
+	if (status & BD_DEFER)
+		dev_vdbg(&ap->pdev->dev, "\"defer to traffic\"\n");
+	if (status & BD_CARLOSS)
+		ap->stats.tx_carrier_errors++;
+}
+
+static int vmac_rx_reclaim_force_unlocked(struct net_device *dev)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	int ct;
+
+	/* locking: no conurrency, runs only during shutdown */
+	WARN_ON(!ap->shutdown);
+
+	dev_dbg(&ap->pdev->dev, "need to release %d rx sk_buff\n",
+			fifo_used(&ap->rx_ring));
+
+	ct = 0;
+	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;
+}
+
+/* Function refills empty buffer descriptors and passes ownership to DMA */
+static int vmac_rx_refill_unlocked(struct net_device *dev)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+
+	/* locking: protect from refill_timer */
+	/* locking: fct owns area outside rx_ring, head exclusive tail,
+	 *	modifies head */
+
+	spin_lock(&ap->refill_lock);
+
+	WARN_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 = cpu_to_le32(BD_DMA_OWN | ap->rx_skb_size);
+			continue;
+		}
+
+		skb = netdev_alloc_skb_ip_align(dev, ap->rx_skb_size);
+		if (!skb) {
+			dev_info(&ap->pdev->dev, "failed to allocate rx_skb, skb's left %d\n",
+					fifo_used(&ap->rx_ring));
+			break;
+		}
+
+		ap->rx_skbuff[desc_idx] = skb;
+
+		p = dma_map_single(&ap->pdev->dev, skb->data, ap->rx_skb_size,
+				DMA_FROM_DEVICE);
+
+		desc->data = p;
+
+		wmb();
+		desc->info = cpu_to_le32(BD_DMA_OWN | ap->rx_skb_size);
+
+		fifo_inc_head(&ap->rx_ring);
+	}
+
+	spin_unlock(&ap->refill_lock);
+
+	/* 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->refill_timer.expires = jiffies + HZ;
+		add_timer(&ap->refill_timer);
+	}
+
+	return 0;
+}
+
+/*
+ * timer callback to defer refill rx queue in case we're OOM
+ */
+static void vmac_refill_rx_timer(unsigned long data)
+{
+	vmac_rx_refill_unlocked((struct net_device *)data);
+}
+
+/* merge buffer chaining  */
+struct sk_buff *vmac_merge_rx_buffers_unlocked(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;
+
+	/* locking: same as vmac_rx_receive */
+
+	rx_ring = &ap->rx_ring;
+	desc = &ap->rxbd[rx_ring->tail];
+
+	WARN_ON(desc == after);
+
+	/* strip FCS */
+	pkt_len -= 4;
+
+	merge_skb = netdev_alloc_skb_ip_align(dev, pkt_len + NET_IP_ALIGN);
+	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;
+	}
+
+	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];
+		WARN_ON(!cur_skb);
+
+		dma_unmap_single(&ap->pdev->dev, desc->data, ap->rx_skb_size,
+				DMA_FROM_DEVICE);
+
+		/* do not copy FCS */
+		buf_len = le32_to_cpu(desc->info) & BD_LEN;
+		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++ */
+
+	if (unlikely(pkt_len != 0))
+		dev_err(&ap->pdev->dev, "buffer chaining bytes missing %d\n",
+				pkt_len);
+
+	WARN_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;
+
+	/* true concurrency -> DMA engine running in parallel */
+	/* locking: fct owns rx_ring tail to current DMA read position, alias
+	 * 'received packets'. rx_refill owns area outside rx_ring, doesn't
+	 * modify tail */
+
+	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 & cpu_to_le32(BD_DMA_OWN)) {
+			/* safe the dma position */
+			ap->dma_rx_head = vmac_readl(ap, MAC_RXRING_HEAD);
+			break;
+		}
+
+		if (desc->info & cpu_to_le32(BD_FRST)) {
+			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 & cpu_to_le32(BD_LEN);
+		pkt_err |= desc->info & cpu_to_le32(BD_BUFF);
+
+		if (!(desc->info & cpu_to_le32(BD_LAST)))
+			continue;
+
+		/* received complete packet */
+
+		if (unlikely(pkt_err || !first)) {
+			/* recycle buffers */
+			ap->rx_ring.tail = lookahead.tail;
+			continue;
+		}
+
+#ifdef DEBUG
+		WARN_ON(!(first->info & cpu_to_le32(BD_FRST)) ||
+				!(desc->info & cpu_to_le32(BD_LAST)));
+		WARN_ON(pkt_err);
+#endif
+
+		/* -- valid packet -- */
+
+		if (first != desc) {
+			skb = vmac_merge_rx_buffers_unlocked(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 - ETH_FCS_LEN);
+		}
+
+		/* free buffers */
+		ap->rx_ring.tail = lookahead.tail;
+
+#ifdef DEBUG
+		WARN_ON(skb->len != pkt_len - ETH_FCS_LEN);
+#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_unlocked(dev);
+
+	return processed;
+}
+
+static void vmac_toggle_irqmask_unlocked(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_unlocked(dev, enable, TXINT_MASK);
+	spin_unlock_irqrestore(&ap->lock, flags);
+}
+
+static void vmac_toggle_rxint_unlocked(struct net_device *dev, int enable)
+{
+	vmac_toggle_irqmask_unlocked(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 */
+	spin_lock_irqsave(&ap->lock, flags);
+	vmac_writel(ap, RXINT_MASK, STAT);
+	spin_unlock_irqrestore(&ap->lock, flags);
+
+	rx_work_done = vmac_rx_receive(dev, budget);
+
+	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_unlocked(dev, 1);
+	spin_unlock_irqrestore(&ap->lock, flags);
+
+	return rx_work_done;
+}
+
+static int vmac_tx_reclaim_unlocked(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->dma_rx_head !=
+			 vmac_readl(ap, MAC_RXRING_HEAD))) {
+		vmac_toggle_rxint_unlocked(dev, 0);
+		napi_schedule(&ap->napi);
+	}
+
+	if (unlikely(netif_queue_stopped(dev) && (status & TXINT_MASK)))
+		vmac_tx_reclaim_unlocked(dev, 0);
+
+	if (status & MDIO_MASK)
+		complete(&ap->mdio_complete);
+
+	if (unlikely(status & ERR_MASK))
+		update_error_counters_unlocked(dev, status);
+
+	spin_unlock(&ap->lock);
+
+	return IRQ_HANDLED;
+}
+
+static int vmac_tx_reclaim_unlocked(struct net_device *dev, int force)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	int released = 0;
+
+	/* locking: modifies tx_ring tail, head only during shutdown */
+	/* locking: call with ap->lock held */
+	WARN_ON(force && !ap->shutdown);
+
+	/* 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 & cpu_to_le32(BD_DMA_OWN)) && !force)
+			break;
+
+		if (desc->info & cpu_to_le32(BD_TX_ERR)) {
+			update_tx_errors_unlocked(dev,
+					le32_to_cpu(desc->info));
+			/* recycle packet, let upper level deal with it */
+		}
+
+		skb = ap->tx_skbuff[desc_idx];
+		ap->tx_skbuff[desc_idx] = NULL;
+		WARN_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 long flags;
+	unsigned int tmp;
+
+	/* running under xmit lock */
+	/* locking: modifies tx_ring head, tx_reclaim only tail */
+
+	/* no scatter/gatter see features below */
+	WARN_ON(skb_shinfo(skb)->nr_frags != 0);
+	WARN_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_ip_align(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];
+	WARN_ON(desc->info & cpu_to_le32(BD_DMA_OWN));
+
+	desc->data = dma_map_single(&ap->pdev->dev, skb->data, skb->len,
+			DMA_TO_DEVICE);
+
+	/* dma might already be polling */
+	wmb();
+	desc->info = cpu_to_le32(BD_DMA_OWN | BD_FRST | BD_LAST | skb->len);
+	wmb();
+
+	/* lock device data */
+	spin_lock_irqsave(&ap->lock, flags);
+
+	/* 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 outside of vmac_tx_timeout */
+	if (fifo_used(&ap->tx_ring) > 8)
+		vmac_tx_reclaim_unlocked(dev, 0);
+
+	/* unlock device data */
+	spin_unlock_irqrestore(&ap->lock, flags);
+
+	/* 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_unlocked(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 */
+	WARN_ON(((uintptr_t)ap->txbd & 0x7) || ((uintptr_t)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_unlocked(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_unlocked(struct net_device *dev)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+
+	/* free skbuff */
+	vmac_tx_reclaim_unlocked(dev, 1);
+	vmac_rx_reclaim_force_unlocked(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 long flags;
+	unsigned int temp, ctrl;
+	int err = 0;
+
+	/* locking: no concurrency yet */
+
+	if (ap == NULL)
+		return -ENODEV;
+
+	spin_lock_irqsave(&ap->lock, flags);
+	ap->shutdown = 0;
+
+	err = get_register_map(ap);
+	if (err)
+		return err;
+
+	vmac_hw_init(dev);
+
+	/* mac address changed? */
+	write_mac_reg(dev, dev->dev_addr);
+
+	err = alloc_buffers_unlocked(dev);
+	if (err)
+		return err;
+
+	/* 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);
+
+	/* Set control */
+	ctrl = (RX_BDT_LEN << 24) | (TX_BDT_LEN << 16) | TXRN_MASK | RXRN_MASK;
+	vmac_writel(ap, ctrl, CONTROL);
+
+	/* make sure we enable napi before rx interrupt  */
+	napi_enable(&ap->napi);
+
+	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;
+	}
+
+	/* IRQ mask */
+	temp = RXINT_MASK | ERR_MASK | TXCH_MASK | MDIO_MASK;
+	vmac_writel(ap, temp, ENABLE);
+
+	/* enable, after all other bits are set */
+	vmac_writel(ap, ctrl | EN_MASK, CONTROL);
+	spin_unlock_irqrestore(&ap->lock, flags);
+
+	/* locking: concurrency */
+
+	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:
+	napi_disable(&ap->napi);
+	free_buffers_unlocked(dev);
+	return err;
+}
+
+int vmac_close(struct net_device *dev)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	unsigned long flags;
+	unsigned int temp;
+
+	/* locking: protect everything, DMA / IRQ / timer */
+	spin_lock_irqsave(&ap->lock, flags);
+
+	/* complete running transfer, then stop */
+	temp = vmac_readl(ap, CONTROL);
+	temp &= ~(TXRN_MASK | RXRN_MASK);
+	vmac_writel(ap, temp, CONTROL);
+
+	/* reenable IRQ, process pending */
+	spin_unlock_irqrestore(&ap->lock, flags);
+
+	set_current_state(TASK_INTERRUPTIBLE);
+	schedule_timeout(msecs_to_jiffies(20));
+
+	/* shut it down now */
+	spin_lock_irqsave(&ap->lock, flags);
+	ap->shutdown = 1;
+
+	netif_stop_queue(dev);
+	napi_disable(&ap->napi);
+
+	/* disable phy */
+	phy_stop(ap->phy_dev);
+	vmac_mii_exit_unlocked(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) */
+
+	/* locking: concurrency off */
+	spin_unlock_irqrestore(&ap->lock, flags);
+
+	del_timer_sync(&ap->refill_timer);
+	free_buffers_unlocked(dev);
+
+	put_register_map(ap);
+
+	return 0;
+}
+
+void update_vmac_stats_unlocked(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);
+	update_vmac_stats_unlocked(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 */
+	WARN_ON(!netif_queue_stopped(dev));
+	WARN_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_unlocked(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)
+{
+	unsigned long crc;
+	char *addrs;
+
+	/* locking: done by net_device */
+
+	WARN_ON(netdev_mc_count(dev) == 0);
+	WARN_ON(dev->flags & IFF_ALLMULTI);
+
+	bitmask[0] = bitmask[1] = 0;
+
+	{
+		struct netdev_hw_addr *ha;
+		netdev_for_each_mc_addr(ha, dev) {
+			addrs = ha->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 (netdev_mc_count(dev) == 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 get_register_map(struct vmac_priv *ap)
+{
+	int err;
+
+	err = -EBUSY;
+	if (!request_mem_region(ap->mem->start, resource_size(ap->mem),
+				DRV_NAME)) {
+		dev_err(&ap->pdev->dev, "no memory region available\n");
+		return err;
+	}
+
+	err = -ENOMEM;
+	ap->regs = ioremap(ap->mem->start, resource_size(ap->mem));
+	if (!ap->regs) {
+		dev_err(&ap->pdev->dev, "failed to map registers, aborting.\n");
+		goto err_out_release_mem;
+	}
+
+	return 0;
+
+err_out_release_mem:
+	release_mem_region(ap->mem->start, resource_size(ap->mem));
+	return err;
+}
+
+static int put_register_map(struct vmac_priv *ap)
+{
+	iounmap(ap->regs);
+	release_mem_region(ap->mem->start, resource_size(ap->mem));
+	return 0;
+}
+
+static int __devinit vmac_probe(struct platform_device *pdev)
+{
+	struct net_device *dev;
+	struct vmac_priv *ap;
+	struct resource *mem;
+	int err;
+
+	/* locking: no concurrency */
+
+	if (dma_get_mask(&pdev->dev) > DMA_BIT_MASK(32) ||
+			pdev->dev.coherent_dma_mask > DMA_BIT_MASK(32)) {
+		dev_err(&pdev->dev, "arcvmac supports only 32-bit DMA addresses\n");
+		return -ENODEV;
+	}
+
+	dev = alloc_etherdev(sizeof(*ap));
+	if (!dev) {
+		dev_err(&pdev->dev, "etherdev alloc failed, aborting.\n");
+		return -ENOMEM;
+	}
+
+	ap = netdev_priv(dev);
+
+	err = -ENODEV;
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem) {
+		dev_err(&pdev->dev, "no mmio resource defined\n");
+		goto err_out;
+	}
+	ap->mem = mem;
+
+	err = platform_get_irq(pdev, 0);
+	if (err < 0) {
+		dev_err(&pdev->dev, "no irq found\n");
+		goto err_out;
+	}
+	dev->irq = err;
+
+	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->refill_timer);
+	ap->refill_timer.function = vmac_refill_rx_timer;
+	ap->refill_timer.data = (unsigned long)dev;
+	spin_lock_init(&ap->refill_lock);
+
+	netif_napi_add(dev, &ap->napi, vmac_poll, 2);
+	dev->netdev_ops = &vmac_netdev_ops;
+	dev->ethtool_ops = &vmac_ethtool_ops;
+
+	dev->flags |= IFF_MULTICAST;
+
+	dev->base_addr = (unsigned long)ap->regs; /* TODO */
+
+	/* prevent buffer chaining, favor speed over space */
+	ap->rx_skb_size = ETH_FRAME_LEN + VMAC_BUFFER_PAD;
+
+	/* private struct functional */
+
+	/* temporarily map registers to fetch mac addr */
+	err = get_register_map(ap);
+	if (err)
+		goto err_out;
+
+	/* mac address intialize, set vmac_open  */
+	read_mac_reg(dev, dev->dev_addr); /* TODO */
+
+	if (!is_valid_ether_addr(dev->dev_addr))
+		random_ether_addr(dev->dev_addr);
+
+	err = register_netdev(dev);
+	if (err) {
+		dev_err(&pdev->dev, "Cannot register net device, aborting.\n");
+		goto err_out;
+	}
+
+	/* release the memory region, till open is called */
+	put_register_map(ap);
+
+	dev_info(&pdev->dev, "ARC VMAC at 0x%pP irq %d %pM\n", &mem->start,
+	    dev->irq, dev->dev_addr);
+	platform_set_drvdata(pdev, ap);
+
+	return 0;
+
+err_out:
+	free_netdev(dev);
+	return err;
+}
+
+static int __devexit vmac_remove(struct platform_device *pdev)
+{
+	struct vmac_priv *ap;
+
+	/* locking: no concurrency */
+
+	ap = platform_get_drvdata(pdev);
+	if (!ap) {
+		dev_err(&pdev->dev, "vmac_remove no valid dev found\n");
+		return 0;
+	}
+
+	/* MAC */
+	unregister_netdev(ap->dev);
+	netif_napi_del(&ap->napi);
+
+	platform_set_drvdata(pdev, NULL);
+	free_netdev(ap->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("afenkart@gmail.com");
diff --git a/drivers/net/arcvmac.h b/drivers/net/arcvmac.h
new file mode 100644
index 0000000..e638b9b
--- /dev/null
+++ b/drivers/net/arcvmac.h
@@ -0,0 +1,266 @@
+/*
+ * 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
+ *
+ */
+
+#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 bytes */
+#define VMAC_ID			0x00
+
+/* stat/enable use same bit mask */
+#define VMAC_STAT		0x04
+#define VMAC_ENABLE		0x08
+#  define TXINT_MASK		0x00000001 /* Transmit interrupt */
+#  define RXINT_MASK		0x00000002 /* Receive interrupt */
+#  define ERR_MASK		0x00000004 /* Error interrupt */
+#  define TXCH_MASK		0x00000008 /* Transmit chaining error */
+#  define MSER_MASK		0x00000010 /* Missed packet counter error */
+#  define RXCR_MASK		0x00000100 /* RXCRCERR counter rolled over	 */
+#  define RXFR_MASK		0x00000200 /* RXFRAMEERR counter rolled over */
+#  define RXFL_MASK		0x00000400 /* RXOFLOWERR counter rolled over */
+#  define MDIO_MASK		0x00001000 /* MDIO complete */
+#  define TXPL_MASK		0x80000000 /* TXPOLL */
+
+#define VMAC_CONTROL		0x0c
+#  define EN_MASK		0x00000001 /* VMAC enable */
+#  define TXRN_MASK		0x00000008 /* TX enable */
+#  define RXRN_MASK		0x00000010 /* RX enable */
+#  define DSBC_MASK		0x00000100 /* Disable receive broadcast */
+#  define ENFL_MASK		0x00000400 /* Enable Full Duplex */
+#  define PROM_MASK		0x00000800 /* Promiscuous mode */
+
+#define VMAC_POLLRATE		0x10
+
+#define VMAC_RXERR		0x14
+#  define RXERR_CRC		0x000000ff
+#  define RXERR_FRM		0x0000ff00
+#  define RXERR_OFLO		0x00ff0000 /* fifo overflow */
+
+#define VMAC_MISS		0x18
+#define VMAC_TXRINGPTR		0x1c
+#define VMAC_RXRINGPTR		0x20
+#define VMAC_ADDRL		0x24
+#define VMAC_ADDRH		0x28
+#define VMAC_LAFL		0x2c
+#define VMAC_LAFH		0x30
+#define VMAC_MAC_TXRING_HEAD	0x38
+#define VMAC_MAC_RXRING_HEAD	0x3C
+
+#define VMAC_MDIO_DATA		0x34
+#  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
+/* common combinations */
+#  define MDIO_BASE		0x40020000
+#  define MDIO_OP_READ		0x20000000
+#  define MDIO_OP_WRITE		0x10000000
+
+/* Buffer descriptor INFO bit masks */
+#define BD_DMA_OWN		0x80000000 /* buffer ownership, 0 CPU, 1 DMA */
+#define BD_BUFF			0x40000000 /* buffer invalid, rx */
+#define BD_UFLO			0x20000000 /* underflow, tx */
+#define BD_LTCL			0x10000000 /* late collision, tx  */
+#define BD_RETRY_CT		0x0f000000 /* tx */
+#define BD_DROP			0x00800000 /* drop, more than 16 retries, tx */
+#define BD_DEFER		0x00400000 /* traffic on the wire, tx */
+#define BD_CARLOSS		0x00200000 /* carrier loss while transmission, tx, rx? */
+/* 20:19 reserved */
+#define BD_ADCR			0x00040000 /* add crc, ignored if not disaddcrc */
+#define BD_LAST			0x00020000 /* Last buffer in chain */
+#define BD_FRST			0x00010000 /* First buffer in chain */
+/* 15:11 reserved */
+#define BD_LEN			0x000007FF
+
+/* common combinations */
+#define BD_TX_ERR		(BD_UFLO | BD_LTCL | BD_RETRY_CT | BD_DROP | \
+		BD_DEFER | BD_CARLOSS)
+
+
+/* arcvmac private data structures */
+struct vmac_buffer_desc {
+	__le32 info;
+	__le32 data;
+};
+
+struct dma_fifo {
+	int head; /* head */
+	int tail; /* tail */
+	int size;
+};
+
+struct	vmac_priv {
+	struct net_device *dev;
+	struct platform_device *pdev;
+	struct net_device_stats stats;
+
+	struct completion mdio_complete;
+	spinlock_t lock; /* protects structure plus hw regs of device */
+
+	/* base address of register set */
+	char *regs;
+	struct resource *mem;
+
+	/* 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; /* valid rx buffers */
+	struct dma_fifo tx_ring;
+
+	/* descriptor last polled/processed by the VMAC */
+	unsigned long dma_rx_head;
+
+	/* timer to retry rx skb allocation, if failed during receive */
+	struct timer_list refill_timer;
+	spinlock_t refill_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;
+};
+
+/* DMA ring management */
+
+/* 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 */
+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	  /* _ARCVMAC_H */
-- 
1.7.2.3


^ permalink raw reply related

* Re: [PATCH] arp_notify: unconditionally send gratuitous ARP for NETDEV_NOTIFY_PEERS.
From: Ian Campbell @ 2011-02-15  9:13 UTC (permalink / raw)
  To: David Miller; +Cc: netdev@vger.kernel.org
In-Reply-To: <20110214.174654.115944453.davem@davemloft.net>

On Tue, 2011-02-15 at 01:46 +0000, David Miller wrote:
> From: Ian Campbell <ian.campbell@citrix.com>
> Date: Fri, 11 Feb 2011 17:44:16 +0000
> 
> > NETDEV_NOTIFY_PEER is an explicit request by the driver to send a link
> > notification while NETDEV_UP/NETDEV_CHANGEADDR generate link
> > notifications as a sort of side effect.
> > 
> > In the later cases the sysctl option is present because link
> > notification events can have undesired effects e.g. if the link is
> > flapping. I don't think this applies in the case of an explicit
> > request from a driver.
> > 
> > This patch makes NETDEV_NOTIFY_PEER unconditional, if preferred we
> > could add a new sysctl for this case which defaults to on.
> > 
> > This change causes Xen post-migration ARP notifications (which cause
> > switches to relearn their MAC tables etc) to be sent by default.
> > 
> > Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
> 
> Ok, applied, thanks.

Thanks.

I nearly forgot -- the NETDEV_NOTIFY_PEER stuff was tagged for
stable/longterm backport (it appeared in 2.6.32.19 or so). I think this
change should likewise go back, what do you think?

Ian.



^ permalink raw reply

* (unknown), 
From: Western Union Transfer @ 2011-02-15  1:24 UTC (permalink / raw)





We have been trying to reach you since the past few days,
as my associate has helped me to send your first payment
of $7,500 USD to you as instructed by Mr. David Cameron
the United Kingdom prime minister after the last G20
meeting that was held in United Kingdom, making you one
of the beneficiaries. Here is the information below.

MONEY TRANSFER CONTROL NUMBER: 3928738492
SENDER NAME:Solomon Daniel
AMOUNT: $7,500 USD

I told him to keep sending you $7,500 USD twice a week
until the FULL payment of ($360.000 United State Dollars)
is completed.

Note a certificate will be made to change the Receiver Name as
stated by the British prime minister, send your Full Names
and your direct phone contact via Email to: Mr Gary Moore

The money will not reflect until the clearance certificate is
issue to you by the G20 committee.

contact Mr. Gary Moore for your clearance certificate.

Mr Gary Moore
E-mail:western_uniontransfer09@zbavitu.net
D/L:+44 7024018331




^ permalink raw reply

* (unknown), 
From: Western Union Transfer @ 2011-02-15  1:23 UTC (permalink / raw)





We have been trying to reach you since the past few days,
as my associate has helped me to send your first payment
of $7,500 USD to you as instructed by Mr. David Cameron
the United Kingdom prime minister after the last G20
meeting that was held in United Kingdom, making you one
of the beneficiaries. Here is the information below.

MONEY TRANSFER CONTROL NUMBER: 3928738492
SENDER NAME:Solomon Daniel
AMOUNT: $7,500 USD

I told him to keep sending you $7,500 USD twice a week
until the FULL payment of ($360.000 United State Dollars)
is completed.

Note a certificate will be made to change the Receiver Name as
stated by the British prime minister, send your Full Names
and your direct phone contact via Email to: Mr Gary Moore

The money will not reflect until the clearance certificate is
issue to you by the G20 committee.

contact Mr. Gary Moore for your clearance certificate.

Mr Gary Moore
E-mail:western_uniontransfer09@zbavitu.net
D/L:+44 7024018331




^ permalink raw reply

* Re: [PATCH 02/14] net/fec: release mem_region requested in probe in error path and remove
From: Uwe Kleine-König @ 2011-02-15  8:53 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, shawn.guo, kernel
In-Reply-To: <20110214.110549.193710827.davem@davemloft.net>

Hi David,

On Mon, Feb 14, 2011 at 11:05:49AM -0800, David Miller wrote:
> From: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
> Date: Mon, 14 Feb 2011 09:25:25 +0100
> > On Sun, Feb 13, 2011 at 01:15:31PM -0800, David Miller wrote:
> >> From: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
> >> Date: Sun, 13 Feb 2011 22:07:09 +0100
> >> > On Fri, Feb 11, 2011 at 09:25:32PM -0800, David Miller wrote:
> >> >> I can't pull from that tree because it is _NOT_ based upon net-next-2.6
> >> >> and therefore brings in all kinds of commits not related to your work.
> >> > Sorry, I'm not used to the customs on netdev.  I can rebase, but still I
> >> > wonder about the reason you cannot pull for.  The only reason I can
> >> > imagine is that you fear unrelated breakage when taking these patches
> >> > that are already in Linus' tree.  But if it's that, wouldn't it be great
> >> > the realize this breakage already now and not only during the next merge
> >> > window?
> >> 
> >> My trees only merge in Linus's tree when absolutely necessary,
> >> to resolve conflicts or similar.
> > You don't merge Linus' tree, you merge mine that just happen to be based
> > on a newer version of Linus' tree. I'm sure Linus won't yell on you for
> > that. He only objects to merge directly from his tree, because the
> > result for him is an "empty" merge.
> 
> You don't get it.
> 
> These merge commits look ugly and Linus wants them minimized.
Hmm, right, I don't get why this looks uglier for Linus than a merge of
a tree that bases on something you already have.  I guess you're too
annoyed by now to explain why you think it does.
 
> Either you follow the rules and my expectations, which is that when you
> give me a GIT tree to pull from it's based upon one of my trees, or
> I don't pull from you.
So I rebased my tree on something older.  It now starts at

	c69b909 (pch_can: fix module reload issue with MSI)

which is already in net-next/master.

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

^ permalink raw reply

* [PATCH v2 5/5] OMAP: hsmmc: Enable MMC4 and MMC5 on OMAP4 platforms
From: Panduranga Mallireddy @ 2011-02-15  8:40 UTC (permalink / raw)
  To: coelho, netdev, linux-omap, linux-mmc
  Cc: ohad, benzyg, pradeepgurumath, vishalm, x-boudet, naveen_jain,
	pavan_savoy, manjunatha_halli, tony, cjb, Kishore Kadiyala,
	Panduranga Mallireddy
In-Reply-To: <1297759236-25323-5-git-send-email-panduranga_mallireddy@ti.com>

From: Kishore Kadiyala <kishore.kadiyala@ti.com>

OMAP4 supports up to 5 MMC controllers, but only 3 of these were
initialized. MMC5 is used by wl12xx chip. So initialize MMC4 and MMC5.

Signed-off-by: Kishore Kadiyala <kishore.kadiyala@ti.com>
Signed-off-by: Panduranga Mallireddy <panduranga_mallireddy@ti.com>
---
 arch/arm/mach-omap2/hsmmc.c   |    5 +++++
 drivers/mmc/host/omap_hsmmc.c |   24 ++++++++++++++++++++----
 2 files changed, 25 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c
index 8f1a484..3c0809f 100644
--- a/arch/arm/mach-omap2/hsmmc.c
+++ b/arch/arm/mach-omap2/hsmmc.c
@@ -348,6 +348,11 @@ void __init omap2_hsmmc_init(struct omap2_hsmmc_info *controllers)
 				mmc->slots[0].after_set_reg = NULL;
 			}
 			break;
+		case 4:
+		case 5:
+			mmc->slots[0].before_set_reg = NULL;
+			mmc->slots[0].after_set_reg = NULL;
+			break;
 		default:
 			pr_err("MMC%d configuration not supported!\n", c->mmc);
 			kfree(mmc);
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index f59f8da..2525071 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -260,7 +260,7 @@ static int omap_hsmmc_1_set_power(struct device *dev, int slot, int power_on,
 	return ret;
 }
 
-static int omap_hsmmc_23_set_power(struct device *dev, int slot, int power_on,
+static int omap_hsmmc_235_set_power(struct device *dev, int slot, int power_on,
 				   int vdd)
 {
 	struct omap_hsmmc_host *host =
@@ -316,6 +316,12 @@ static int omap_hsmmc_23_set_power(struct device *dev, int slot, int power_on,
 	return ret;
 }
 
+static int omap_hsmmc_4_set_power(struct device *dev, int slot, int power_on,
+					int vdd)
+{
+	return 0;
+}
+
 static int omap_hsmmc_1_set_sleep(struct device *dev, int slot, int sleep,
 				  int vdd, int cardsleep)
 {
@@ -326,7 +332,7 @@ static int omap_hsmmc_1_set_sleep(struct device *dev, int slot, int sleep,
 	return regulator_set_mode(host->vcc, mode);
 }
 
-static int omap_hsmmc_23_set_sleep(struct device *dev, int slot, int sleep,
+static int omap_hsmmc_235_set_sleep(struct device *dev, int slot, int sleep,
 				   int vdd, int cardsleep)
 {
 	struct omap_hsmmc_host *host =
@@ -365,6 +371,12 @@ static int omap_hsmmc_23_set_sleep(struct device *dev, int slot, int sleep,
 		return regulator_enable(host->vcc_aux);
 }
 
+static int omap_hsmmc_4_set_sleep(struct device *dev, int slot, int sleep,
+					int vdd, int cardsleep)
+{
+	return 0;
+}
+
 static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
 {
 	struct regulator *reg;
@@ -379,10 +391,14 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
 		break;
 	case OMAP_MMC2_DEVID:
 	case OMAP_MMC3_DEVID:
+	case OMAP_MMC5_DEVID:
 		/* Off-chip level shifting, or none */
-		mmc_slot(host).set_power = omap_hsmmc_23_set_power;
-		mmc_slot(host).set_sleep = omap_hsmmc_23_set_sleep;
+		mmc_slot(host).set_power = omap_hsmmc_235_set_power;
+		mmc_slot(host).set_sleep = omap_hsmmc_235_set_sleep;
 		break;
+	case OMAP_MMC4_DEVID:
+		mmc_slot(host).set_power = omap_hsmmc_4_set_power;
+		mmc_slot(host).set_sleep = omap_hsmmc_4_set_sleep;
 	default:
 		pr_err("MMC%d configuration not supported!\n", host->id);
 		return -EINVAL;
-- 
1.5.6.3


^ permalink raw reply related

* [PATCH v2 4/5] omap: panda: add mmc5/wl1271 device support
From: Panduranga Mallireddy @ 2011-02-15  8:40 UTC (permalink / raw)
  To: coelho, netdev, linux-omap, linux-mmc
  Cc: ohad, benzyg, pradeepgurumath, vishalm, x-boudet, naveen_jain,
	pavan_savoy, manjunatha_halli, tony, cjb, Panduranga Mallireddy
In-Reply-To: <1297759236-25323-4-git-send-email-panduranga_mallireddy@ti.com>

Add MMC5 support on PANDA, which has the wl1271 device hardwired to.

The wl1271 is a 4-wire, 1.8V, embedded SDIO WLAN device with an
external IRQ line, and power-controlled by a GPIO-based fixed regulator.

Based on the patch for mmc3/wl1271 device support for zoom by Ohad
Ben-Cohen <ohad@wizery.com>
Signed-off-by: Panduranga Mallireddy <panduranga_mallireddy@ti.com>
---
 arch/arm/mach-omap2/board-omap4panda.c |   20 ++++++++++++++++++++
 1 files changed, 20 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c
index cd25255..ef43010 100644
--- a/arch/arm/mach-omap2/board-omap4panda.c
+++ b/arch/arm/mach-omap2/board-omap4panda.c
@@ -27,6 +27,7 @@
 #include <linux/i2c/twl.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/fixed.h>
+#include <linux/wl12xx.h>
 
 #include <mach/hardware.h>
 #include <mach/omap4-common.h>
@@ -47,6 +48,7 @@
 #define GPIO_HUB_POWER		1
 #define GPIO_HUB_NRESET		62
 #define GPIO_WIFI_PMENA		43
+#define GPIO_WIFI_IRQ		53
 
 static struct gpio_led gpio_leds[] = {
 	{
@@ -164,6 +166,15 @@ static struct omap2_hsmmc_info mmc[] = {
 		.gpio_wp	= -EINVAL,
 		.gpio_cd	= -EINVAL,
 	},
+	{
+		.name		= "wl1271",
+		.mmc		= 5,
+		.caps		= MMC_CAP_4_BIT_DATA | MMC_CAP_POWER_OFF_CARD,
+		.gpio_wp	= -EINVAL,
+		.gpio_cd	= -EINVAL,
+		.ocr_mask	= MMC_VDD_165_195,
+		.nonremovable	= true,
+	},
 	{}	/* Terminator */
 };
 
@@ -205,6 +216,12 @@ static struct platform_device omap_vwlan_device = {
 	},
 };
 
+struct wl12xx_platform_data omap_panda_wlan_data  __initdata = {
+	.irq = OMAP_GPIO_IRQ(GPIO_WIFI_IRQ),
+	/* PANDA ref clock is 38.4 MHz */
+	.board_ref_clock = 2,
+};
+
 static int omap4_twl6030_hsmmc_late_init(struct device *dev)
 {
 	int ret = 0;
@@ -461,6 +478,9 @@ static void __init omap4_panda_init(void)
 		package = OMAP_PACKAGE_CBL;
 	omap4_mux_init(board_mux, package);
 
+	if (wl12xx_set_platform_data(&omap_panda_wlan_data))
+		pr_err("error setting wl12xx data\n");
+
 	omap4_panda_i2c_init();
 	platform_add_devices(panda_devices, ARRAY_SIZE(panda_devices));
 	platform_device_register(&omap_vwlan_device);
-- 
1.5.6.3


^ permalink raw reply related

* [PATCH v2 2/5] omap: select REGULATOR_FIXED_VOLTAGE by default for panda and sdp4430
From: Panduranga Mallireddy @ 2011-02-15  8:40 UTC (permalink / raw)
  To: coelho, netdev, linux-omap, linux-mmc
  Cc: ohad, benzyg, pradeepgurumath, vishalm, x-boudet, naveen_jain,
	pavan_savoy, manjunatha_halli, tony, cjb, Panduranga Mallireddy
In-Reply-To: <1297759236-25323-2-git-send-email-panduranga_mallireddy@ti.com>

Power to the wl12xx wlan device is controlled by a fixed regulator.
Boards that have the wl12xx should select REGULATOR_FIXED_VOLTAGE.
Signed-off-by: Panduranga Mallireddy <panduranga_mallireddy@ti.com>
---
 arch/arm/mach-omap2/Kconfig |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index 1a2cf62..eeaeb3b 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -300,6 +300,7 @@ config MACH_OMAP_4430SDP
 	depends on ARCH_OMAP4
 	select OMAP_PACKAGE_CBL
 	select OMAP_PACKAGE_CBS
+	select REGULATOR_FIXED_VOLTAGE
 
 config MACH_OMAP4_PANDA
 	bool "OMAP4 Panda Board"
@@ -307,6 +308,7 @@ config MACH_OMAP4_PANDA
 	depends on ARCH_OMAP4
 	select OMAP_PACKAGE_CBL
 	select OMAP_PACKAGE_CBS
+	select REGULATOR_FIXED_VOLTAGE
 
 config OMAP3_EMU
 	bool "OMAP3 debugging peripherals"
-- 
1.5.6.3


^ permalink raw reply related

* [PATCH v2 1/5] omap: panda: wlan board muxing
From: Panduranga Mallireddy @ 2011-02-15  8:40 UTC (permalink / raw)
  To: coelho, netdev, linux-omap, linux-mmc
  Cc: ohad, benzyg, pradeepgurumath, vishalm, x-boudet, naveen_jain,
	pavan_savoy, manjunatha_halli, tony, cjb, Panduranga Mallireddy
In-Reply-To: <1297759236-25323-1-git-send-email-panduranga_mallireddy@ti.com>

Add board muxing to support the wlan wl1271 chip that is
hardwired to mmc5 (fifth mmc controller) on the PANDA.

Based on the wlan board muxing for zoom3 by Ohad Ben-Cohen
<ohadb@ti.com>
Signed-off-by: Panduranga Mallireddy <panduranga_mallireddy@ti.com>
---
 arch/arm/mach-omap2/board-omap4panda.c |   13 +++++++++++++
 1 files changed, 13 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c
index 9218862..cc9df6c 100644
--- a/arch/arm/mach-omap2/board-omap4panda.c
+++ b/arch/arm/mach-omap2/board-omap4panda.c
@@ -401,6 +401,19 @@ static int __init omap4_panda_i2c_init(void)
 
 #ifdef CONFIG_OMAP_MUX
 static struct omap_board_mux board_mux[] __initdata = {
+	/* WLAN IRQ - GPIO 53 */
+	OMAP4_MUX(GPMC_NCS3, OMAP_MUX_MODE3 | OMAP_PIN_INPUT),
+	/* WLAN POWER ENABLE - GPIO 43 */
+	OMAP4_MUX(GPMC_A19, OMAP_MUX_MODE3 | OMAP_PIN_OUTPUT),
+	/* WLAN SDIO: MMC5 CMD */
+	OMAP4_MUX(SDMMC5_CMD, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+	/* WLAN SDIO: MMC5 CLK */
+	OMAP4_MUX(SDMMC5_CLK, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+	/* WLAN SDIO: MMC5 DAT[0-3] */
+	OMAP4_MUX(SDMMC5_DAT0, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+	OMAP4_MUX(SDMMC5_DAT1, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+	OMAP4_MUX(SDMMC5_DAT2, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+	OMAP4_MUX(SDMMC5_DAT3, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
 	{ .reg_offset = OMAP_MUX_TERMINATOR },
 };
 #else
-- 
1.5.6.3


^ permalink raw reply related

* [PATCH v2 0/5] Panda: Support for WLAN on WL127x
From: Panduranga Mallireddy @ 2011-02-15  8:40 UTC (permalink / raw)
  To: coelho, netdev, linux-omap, linux-mmc
  Cc: ohad, benzyg, pradeepgurumath, vishalm, x-boudet, naveen_jain,
	pavan_savoy, manjunatha_halli, tony, cjb, Panduranga Mallireddy

Fixes from V1:
1. Removing the pull up of WLAN IRQ line, since it is always held up by wl127x device.

Adding support for WLAN on Panda board using wl12xx and mac80211 drivers

Patches were tested on Panda board.

These patches add software control for emulating card detect events,
add board configurations to support the wl127x device.

These patches are dependent on the patches that enable clock for WLAN on panda.
Please refer the following links for these patches:
https://patchwork.kernel.org/patch/546381/
https://patchwork.kernel.org/patch/546401/

[PATCH 5/5] OMAP: hsmmc: Enable MMC4 and MMC5 on OMAP4 platforms
 is dependent on hwmod adpotation for HSMMC patches series.
For original patches of adpotation for HSMMC refer:
http://www.mail-archive.com/linux-omap@vger.kernel.org/msg43464.html

Patches are based on mainline 2.6.38-rc3

Kishore Kadiyala (1):
  OMAP: hsmmc: Enable MMC4 and MMC5 on OMAP4 platforms

Panduranga Mallireddy (4):
  omap: panda: wlan board muxing
  omap: select REGULATOR_FIXED_VOLTAGE by default for panda and sdp4430
  omap: panda: add fixed regulator device for wlan
  omap: panda: add mmc5/wl1271 device support

 arch/arm/mach-omap2/Kconfig            |    2 +
 arch/arm/mach-omap2/board-omap4panda.c |   67 ++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/hsmmc.c            |    5 ++
 drivers/mmc/host/omap_hsmmc.c          |   24 +++++++++--
 4 files changed, 94 insertions(+), 4 deletions(-)


^ permalink raw reply

* [PATCH v2 3/5] omap: panda: add fixed regulator device for wlan
From: Panduranga Mallireddy @ 2011-02-15  8:40 UTC (permalink / raw)
  To: coelho, netdev, linux-omap, linux-mmc
  Cc: ohad, benzyg, pradeepgurumath, vishalm, x-boudet, naveen_jain,
	pavan_savoy, manjunatha_halli, tony, cjb, Panduranga Mallireddy
In-Reply-To: <1297759236-25323-3-git-send-email-panduranga_mallireddy@ti.com>

Add a fixed regulator vmmc device to enable power control
of the wl1271 wlan device.

Based on the patch for zoom by Ohad Ben-Cohen <ohad@wizery.com>
Signed-off-by: Panduranga Mallireddy <panduranga_mallireddy@ti.com>
---
 arch/arm/mach-omap2/board-omap4panda.c |   34 ++++++++++++++++++++++++++++++++
 1 files changed, 34 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c
index cc9df6c..cd25255 100644
--- a/arch/arm/mach-omap2/board-omap4panda.c
+++ b/arch/arm/mach-omap2/board-omap4panda.c
@@ -26,6 +26,7 @@
 #include <linux/usb/otg.h>
 #include <linux/i2c/twl.h>
 #include <linux/regulator/machine.h>
+#include <linux/regulator/fixed.h>
 
 #include <mach/hardware.h>
 #include <mach/omap4-common.h>
@@ -45,6 +46,7 @@
 
 #define GPIO_HUB_POWER		1
 #define GPIO_HUB_NRESET		62
+#define GPIO_WIFI_PMENA		43
 
 static struct gpio_led gpio_leds[] = {
 	{
@@ -172,6 +174,37 @@ static struct regulator_consumer_supply omap4_panda_vmmc_supply[] = {
 	},
 };
 
+static struct regulator_consumer_supply omap4_panda_vmmc5_supply = {
+	.supply = "vmmc",
+	.dev_name = "mmci-omap-hs.4",
+};
+
+static struct regulator_init_data panda_vmmc5 = {
+	.constraints = {
+		.valid_ops_mask = REGULATOR_CHANGE_STATUS,
+	},
+	.num_consumer_supplies = 1,
+	.consumer_supplies = &omap4_panda_vmmc5_supply,
+};
+
+static struct fixed_voltage_config panda_vwlan = {
+	.supply_name = "vwl1271",
+	.microvolts = 1800000, /* 1.8V */
+	.gpio = GPIO_WIFI_PMENA,
+	.startup_delay = 70000, /* 70msec */
+	.enable_high = 1,
+	.enabled_at_boot = 0,
+	.init_data = &panda_vmmc5,
+};
+
+static struct platform_device omap_vwlan_device = {
+	.name		= "reg-fixed-voltage",
+	.id		= 1,
+	.dev = {
+		.platform_data = &panda_vwlan,
+	},
+};
+
 static int omap4_twl6030_hsmmc_late_init(struct device *dev)
 {
 	int ret = 0;
@@ -430,6 +463,7 @@ static void __init omap4_panda_init(void)
 
 	omap4_panda_i2c_init();
 	platform_add_devices(panda_devices, ARRAY_SIZE(panda_devices));
+	platform_device_register(&omap_vwlan_device);
 	omap_serial_init();
 	omap4_twl6030_hsmmc_init(mmc);
 	/* OMAP4 Panda uses internal transceiver so register nop transceiver */
-- 
1.5.6.3


^ permalink raw reply related

* FINANCIAL LENDER
From: ZENITH HOME LENDER INC. @ 2011-02-15  6:40 UTC (permalink / raw)
  To: zenithhlinc

apply for a financial lending amount to start your business our interest is very affordable 

our lending process is very fast as well as percentage rate of 2.5% yearly from $5 000.00 

min To $100 000 000.00 max
get back to us on this information below

amount, duration time,address and phone number

regards,
zenith home lender inc
zenithhlinc@gmail.com
mr ronald.c. foster


^ permalink raw reply

* Re: [Bugme-new] [Bug 27212] New: Warning kmemcheck: Caught 64-bit read from uninitialized memory in netlink_broadcast_filtered
From: Pekka Enberg @ 2011-02-15  5:48 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: Andrew Morton, netdev, bugzilla-daemon, bugme-daemon,
	casteyde.christian, Changli Gao, Vegard Nossum, David Miller,
	linux-kernel, Christoph Lameter, David Rientjes
In-Reply-To: <1297704922.2996.60.camel@edumazet-laptop>

On Mon, Feb 14, 2011 at 7:35 PM, Eric Dumazet <eric.dumazet@gmail.com> wrote:
> Le vendredi 21 janvier 2011 à 09:49 +0200, Pekka Enberg a écrit :
>
>> It actually looks like a bug in SLUB+kmemcheck. The
>> kmemcheck_slab_alloc() call in slab_post_alloc_hook() should use ksize()
>> instead of s->objsize. SLAB seems to do the right thing already. Anyone
>> care to send a patch my way?
>>
>
> Hmm, what do you think of following patch ?
>
> Thanks, and sorry for the delay.

Looks good to me. Christoph, David, any objections to the patch?

> [PATCH] slub: fix kmemcheck calls to match ksize() hints
>
> Recent use of ksize() in network stack (commit ca44ac38 : net: don't
> reallocate skb->head unless the current one hasn't the needed extra size
> or is shared) triggers kmemcheck warnings, because ksize() can return
> more space than kmemcheck is aware of.
>
> Pekka Enberg noticed SLAB+kmemcheck is doing the right thing, while SLUB
> +kmemcheck doesnt.
>
> Bugzilla reference #27212
>
> Reported-by: Christian Casteyde <casteyde.christian@free.fr>
> Suggested-by: Pekka Enberg <penberg@kernel.org>
> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
> CC: David Miller <davem@davemloft.net>
> CC: Changli Gao <xiaosuo@gmail.com>
> CC: Andrew Morton <akpm@linux-foundation.org>
> ---
>  mm/slub.c |   49 ++++++++++++++++++++++++++-----------------------
>  1 file changed, 26 insertions(+), 23 deletions(-)
>
> diff --git a/mm/slub.c b/mm/slub.c
> index e15aa7f..ee0aeb8 100644
> --- a/mm/slub.c
> +++ b/mm/slub.c
> @@ -797,10 +797,34 @@ static inline int slab_pre_alloc_hook(struct kmem_cache *s, gfp_t flags)
>        return should_failslab(s->objsize, flags, s->flags);
>  }
>
> +static inline size_t slab_ksize(const struct kmem_cache *s)
> +{
> +#ifdef CONFIG_SLUB_DEBUG
> +       /*
> +        * Debugging requires use of the padding between object
> +        * and whatever may come after it.
> +        */
> +       if (s->flags & (SLAB_RED_ZONE | SLAB_POISON))
> +               return s->objsize;
> +
> +#endif
> +       /*
> +        * If we have the need to store the freelist pointer
> +        * back there or track user information then we can
> +        * only use the space before that information.
> +        */
> +       if (s->flags & (SLAB_DESTROY_BY_RCU | SLAB_STORE_USER))
> +               return s->inuse;
> +       /*
> +        * Else we can use all the padding etc for the allocation
> +        */
> +       return s->size;
> +}
> +
>  static inline void slab_post_alloc_hook(struct kmem_cache *s, gfp_t flags, void *object)
>  {
>        flags &= gfp_allowed_mask;
> -       kmemcheck_slab_alloc(s, flags, object, s->objsize);
> +       kmemcheck_slab_alloc(s, flags, object, slab_ksize(s));
>        kmemleak_alloc_recursive(object, s->objsize, 1, s->flags, flags);
>  }
>
> @@ -2696,7 +2720,6 @@ EXPORT_SYMBOL(__kmalloc_node);
>  size_t ksize(const void *object)
>  {
>        struct page *page;
> -       struct kmem_cache *s;
>
>        if (unlikely(object == ZERO_SIZE_PTR))
>                return 0;
> @@ -2707,28 +2730,8 @@ size_t ksize(const void *object)
>                WARN_ON(!PageCompound(page));
>                return PAGE_SIZE << compound_order(page);
>        }
> -       s = page->slab;
>
> -#ifdef CONFIG_SLUB_DEBUG
> -       /*
> -        * Debugging requires use of the padding between object
> -        * and whatever may come after it.
> -        */
> -       if (s->flags & (SLAB_RED_ZONE | SLAB_POISON))
> -               return s->objsize;
> -
> -#endif
> -       /*
> -        * If we have the need to store the freelist pointer
> -        * back there or track user information then we can
> -        * only use the space before that information.
> -        */
> -       if (s->flags & (SLAB_DESTROY_BY_RCU | SLAB_STORE_USER))
> -               return s->inuse;
> -       /*
> -        * Else we can use all the padding etc for the allocation
> -        */
> -       return s->size;
> +       return slab_ksize(page->slab);
>  }
>  EXPORT_SYMBOL(ksize);
>
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
>

^ 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