* [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
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox