* Power management for au1000_eth.c
@ 2006-04-05 15:47 Rodolfo Giometti
2006-04-05 22:23 ` Rodolfo Giometti
0 siblings, 1 reply; 11+ messages in thread
From: Rodolfo Giometti @ 2006-04-05 15:47 UTC (permalink / raw)
To: Linux MIPS; +Cc: ppopov
Hello,
I'm trying to add power management support to au1000_eth.c driver.
In order to to it I 've added these two functions:
static int au1000_eth_suspend(struct device *dev, pm_message_t state, u32 level)
{
struct net_device *ndev = dev_get_drvdata(dev);
struct au1000_private *aup = (struct au1000_private *) ndev->priv;
if (!ndev)
return 0;
switch (level) {
case SUSPEND_DISABLE :
if (netif_running(ndev))
netif_device_detach(ndev);
break;
case SUSPEND_SAVE_STATE :
/* bring the device out of reset, otherwise accessing to mii
* will hang */
*aup->enable = MAC_EN_CLOCK_ENABLE;
au_sync_delay(2);
*aup->enable = MAC_EN_RESET0 | MAC_EN_RESET1 |
MAC_EN_RESET2 | MAC_EN_CLOCK_ENABLE;
au_sync_delay(2);
if (aup->phy_ops->phy_suspend)
aup->phy_ops->phy_suspend(ndev, aup->phy_addr, level);
del_timer_sync(&aup->timer); /* FIXME: REMOVED??? */
reset_mac(ndev);
netif_stop_queue(ndev);
free_irq(ndev->irq, dev);
break;
case SUSPEND_POWER_DOWN :
break;
}
return 0;
}
static int au1000_eth_resume(struct device *dev, u32 level)
{
struct net_device *ndev = dev_get_drvdata(dev);
struct au1000_private *aup = (struct au1000_private *) ndev->priv;
u32 flags;
int ret;
if (!ndev)
return 0;
switch (level) {
case RESUME_RESTORE_STATE :
/* bring the device out of reset, otherwise accessing to mii
* will hang */
*aup->enable = MAC_EN_CLOCK_ENABLE;
au_sync_delay(2);
*aup->enable = MAC_EN_RESET0 | MAC_EN_RESET1 |
MAC_EN_RESET2 | MAC_EN_CLOCK_ENABLE;
au_sync_delay(2);
if (aup->phy_ops->phy_resume)
aup->phy_ops->phy_resume(ndev, aup->phy_addr, level);
aup->phy_ops->phy_init(ndev, aup->phy_addr);
/* au1000_init() expects that the device is in reset state.
*/
reset_mac(ndev); /* au1000_init() expects the device in reset */
au1000_init(ndev);
ret = request_irq(ndev->irq, &au1000_interrupt, 0, ndev->name, ndev);
if (ret) {
printk(KERN_ERR "%s: unable to get IRQ %d\n",
ndev->name, ndev->irq);
return ret; //FIXME
}
init_timer(&aup->timer); /* used in ioctl() */
aup->timer.expires = RUN_AT((3*HZ));
aup->timer.data = (unsigned long) ndev;
aup->timer.function = &au1000_timer; /* timer handler */
add_timer(&aup->timer);
break;
case RESUME_ENABLE :
if (netif_running(ndev))
netif_device_attach(ndev);
break;
}
return 0;
}
The problem is that after wakeup the system hangs or returns lots of
errors like:
Reserved instruction in kernel code in arch/mips/kernel/traps.c::do_ri, line 706[#169]:
Note that if I compile the driver as a module and removing it before
sleeping and reinstalling it after wake up the system (and the
ethernet) works correctly...
Suggestions? :)
Thanks in advance,
Rodolfo
--
GNU/Linux Solutions e-mail: giometti@enneenne.com
Linux Device Driver giometti@gnudd.com
Embedded Systems giometti@linux.it
UNIX programming phone: +39 349 2432127
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Power management for au1000_eth.c
2006-04-05 15:47 Power management for au1000_eth.c Rodolfo Giometti
@ 2006-04-05 22:23 ` Rodolfo Giometti
2006-04-05 22:26 ` [PATCH] Oops! - " Rodolfo Giometti
0 siblings, 1 reply; 11+ messages in thread
From: Rodolfo Giometti @ 2006-04-05 22:23 UTC (permalink / raw)
To: Linux MIPS; +Cc: ppopov
On Wed, Apr 05, 2006 at 05:47:11PM +0200, Rodolfo Giometti wrote:
> Hello,
>
> I'm trying to add power management support to au1000_eth.c driver.
Solved! :)
Here a patch to implement power management functions for au1000_eth.
Note that this patch needs my previous one who implements new power
management's sysfs interface.
Ciao,
Rodolfo
--
GNU/Linux Solutions e-mail: giometti@enneenne.com
Linux Device Driver giometti@gnudd.com
Embedded Systems giometti@linux.it
UNIX programming phone: +39 349 2432127
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH] Oops! - Re: Power management for au1000_eth.c
2006-04-05 22:23 ` Rodolfo Giometti
@ 2006-04-05 22:26 ` Rodolfo Giometti
2006-04-06 14:43 ` Sergei Shtylyov
0 siblings, 1 reply; 11+ messages in thread
From: Rodolfo Giometti @ 2006-04-05 22:26 UTC (permalink / raw)
To: Linux MIPS; +Cc: ppopov
[-- Attachment #1.1: Type: text/plain, Size: 751 bytes --]
On Thu, Apr 06, 2006 at 12:23:32AM +0200, Rodolfo Giometti wrote:
> On Wed, Apr 05, 2006 at 05:47:11PM +0200, Rodolfo Giometti wrote:
> > Hello,
> >
> > I'm trying to add power management support to au1000_eth.c driver.
>
> Solved! :)
>
> Here a patch to implement power management functions for au1000_eth.
>
> Note that this patch needs my previous one who implements new power
> management's sysfs interface.
The forgotten attachment. :)
Ciao,
Rodolfo
--
GNU/Linux Solutions e-mail: giometti@enneenne.com
Linux Device Driver giometti@gnudd.com
Embedded Systems giometti@linux.it
UNIX programming phone: +39 349 2432127
[-- Attachment #1.2: patch-au1000_eth-pm --]
[-- Type: text/plain, Size: 22531 bytes --]
--- /home/develop/embedded/mipsel/linux/linux-mips.git/arch/mips/au1000/common/au1xxx_irqmap.c 2006-03-31 16:57:26.000000000 +0200
+++ arch/mips/au1000/common/au1xxx_irqmap.c 2006-04-03 17:50:49.000000000 +0200
@@ -118,7 +118,7 @@
{ AU1000_USB_DEV_SUS_INT, INTC_INT_RISE_EDGE, 0 },
{ AU1000_USB_HOST_INT, INTC_INT_LOW_LEVEL, 0 },
{ AU1000_ACSYNC_INT, INTC_INT_RISE_EDGE, 0 },
- { AU1500_MAC0_DMA_INT, INTC_INT_HIGH_LEVEL, 0},
+ { AU1000_MAC0_DMA_INT, INTC_INT_HIGH_LEVEL, 0},
{ AU1500_MAC1_DMA_INT, INTC_INT_HIGH_LEVEL, 0},
{ AU1000_AC97C_INT, INTC_INT_RISE_EDGE, 0 },
@@ -152,7 +152,7 @@
{ AU1000_USB_DEV_SUS_INT, INTC_INT_RISE_EDGE, 0 },
{ AU1000_USB_HOST_INT, INTC_INT_LOW_LEVEL, 0 },
{ AU1000_ACSYNC_INT, INTC_INT_RISE_EDGE, 0 },
- { AU1100_MAC0_DMA_INT, INTC_INT_HIGH_LEVEL, 0},
+ { AU1000_MAC0_DMA_INT, INTC_INT_HIGH_LEVEL, 0},
/*{ AU1000_GPIO215_208_INT, INTC_INT_HIGH_LEVEL, 0},*/
{ AU1100_LCD_INT, INTC_INT_HIGH_LEVEL, 0},
{ AU1000_AC97C_INT, INTC_INT_RISE_EDGE, 0 },
--- /home/develop/embedded/mipsel/linux/linux-mips.git/arch/mips/au1000/common/platform.c 2006-04-03 18:22:05.000000000 +0200
+++ arch/mips/au1000/common/platform.c 2006-04-05 23:08:55.000000000 +0200
@@ -16,6 +16,78 @@
#include <asm/mach-au1x00/au1xxx.h>
+#if defined(CONFIG_MIPS_AU1X00_ENET) || defined(CONFIG_MIPS_AU1X00_ENET_MODULE)
+/* Ethernet controllers */
+static struct resource au1xxx_eth0_resources[] = {
+ [0] = {
+ .name = "eth-base",
+ .start = ETH0_BASE,
+ .end = ETH0_BASE + 0x0ffff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .name = "eth-mac",
+ .start = MAC0_ENABLE,
+ .end = MAC0_ENABLE + 0x0ffff,
+ .flags = IORESOURCE_MEM,
+ },
+ [2] = {
+ .name = "eth-irq",
+#if defined(CONFIG_SOC_AU1550)
+ .start = AU1550_MAC0_DMA_INT,
+ .end = AU1550_MAC0_DMA_INT,
+#else
+ .start = AU1000_MAC0_DMA_INT,
+ .end = AU1000_MAC0_DMA_INT,
+#endif
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device au1xxx_eth0_device = {
+ .name = "au1xxx-eth",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(au1xxx_eth0_resources),
+ .resource = au1xxx_eth0_resources,
+};
+
+#if defined(CONFIG_SOC_AU1000) || \
+ defined(CONFIG_SOC_AU1500) || defined(CONFIG_SOC_AU1550)
+static struct resource au1xxx_eth1_resources[] = {
+ [0] = {
+ .name = "eth-base",
+ .start = ETH1_BASE,
+ .end = ETH1_BASE + 0x0ffff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .name = "eth-mac",
+ .start = MAC1_ENABLE,
+ .end = MAC1_ENABLE + 0x0ffff,
+ .flags = IORESOURCE_MEM,
+ },
+ [2] = {
+ .name = "eth-irq",
+#if defined(CONFIG_SOC_AU1550)
+ .start = AU1550_MAC1_DMA_INT,
+ .end = AU1550_MAC1_DMA_INT,
+#else
+ .start = AU1000_MAC1_DMA_INT,
+ .end = AU1000_MAC1_DMA_INT,
+#endif
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device au1xxx_eth1_device = {
+ .name = "au1xxx-eth",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(au1xxx_eth1_resources),
+ .resource = au1xxx_eth1_resources,
+};
+#endif
+#endif
+
/* OHCI (USB full speed host controller) */
static struct resource au1xxx_usb_ohci_resources[] = {
[0] = {
@@ -272,6 +344,13 @@
#endif
static struct platform_device *au1xxx_platform_devices[] __initdata = {
+#if defined(CONFIG_MIPS_AU1X00_ENET) || defined(CONFIG_MIPS_AU1X00_ENET_MODULE)
+ &au1xxx_eth0_device,
+#if defined(CONFIG_SOC_AU1000) || \
+ defined(CONFIG_SOC_AU1500) || defined(CONFIG_SOC_AU1550)
+ &au1xxx_eth1_device,
+#endif
+#endif
&au1xxx_usb_ohci_device,
&au1x00_pcmcia_device,
#ifdef CONFIG_FB_AU1100
--- a/drivers/net/Kconfig 2 Jul 2005 06:46:30 -0000 1.1.1.1
+++ b/drivers/net/Kconfig 5 Apr 2006 21:20:30 -0000
@@ -440,12 +440,12 @@
Say Y here to support the Ethernet subsystem on your GT96100 card.
config MIPS_AU1X00_ENET
- bool "MIPS AU1000 Ethernet support"
+ tristate "MIPS AU1000 Ethernet support"
depends on NET_ETHERNET && SOC_AU1X00
select CRC32
help
If you have an Alchemy Semi AU1X00 based system
- say Y. Otherwise, say N.
+ say Y or M. Otherwise, say N.
config SGI_IOC3_ETH
bool "SGI IOC3 Ethernet"
--- /home/develop/embedded/mipsel/linux/linux-mips.git/drivers/net/au1000_eth.c 2006-04-03 18:23:17.000000000 +0200
+++ drivers/net/au1000_eth.c 2006-04-05 23:43:18.000000000 +0200
@@ -9,6 +9,9 @@
* Update: 2004 Bjoern Riemer, riemer@fokus.fraunhofer.de
* or riemer@riemer-nt.de: fixed the link beat detection with
* ioctls (SIOCGMIIPHY)
+ * Update: 2006 Rodolfo Giometti: PM support, module support.
+ * Copyright 2006 Rodolfo Giometti <giometti@linux.it>
+ *
* Author: MontaVista Software, Inc.
* ppopov@mvista.com or source@mvista.com
*
@@ -57,6 +60,7 @@
#include <asm/io.h>
#include <asm/processor.h>
+#include <linux/platform_device.h>
#include <asm/mach-au1x00/au1000.h>
#include <asm/cpu.h>
#include "au1000_eth.h"
@@ -67,8 +71,8 @@
static int au1000_debug = 3;
#endif
-#define DRV_NAME "au1000eth"
-#define DRV_VERSION "1.5"
+#define DRV_NAME "au1xxx-eth"
+#define DRV_VERSION "1.6"
#define DRV_AUTHOR "Pete Popov <ppopov@embeddedalley.com>"
#define DRV_DESC "Au1xxx on-chip Ethernet driver"
@@ -79,7 +83,8 @@
// prototypes
static void hard_stop(struct net_device *);
static void enable_rx_tx(struct net_device *dev);
-static struct net_device * au1000_probe(u32 ioaddr, int irq, int port_num);
+static int au1000_lowlevel_probe(struct net_device *ndev, u32 ioaddr, u32 macen_addr, int port_num);
+static void au1000_lowlevel_remove(struct net_device *ndev);
static int au1000_init(struct net_device *);
static int au1000_open(struct net_device *);
static int au1000_close(struct net_device *);
@@ -432,6 +437,34 @@
return 0;
}
+#ifdef CONFIG_PM
+int am79c874_suspend(struct net_device *dev, int phy_addr, int level)
+{
+ s16 mii_control;
+
+ if (au1000_debug > 4)
+ printk("am79c874_suspend\n");
+
+ mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
+ mdio_write(dev, phy_addr, MII_CONTROL, mii_control | MII_CNTL_PWRDWN);
+ mdelay(1);
+ return 0;
+}
+
+int am79c874_resume(struct net_device *dev, int phy_addr, int level)
+{
+ s16 mii_control;
+
+ if (au1000_debug > 4)
+ printk("am79c874_resume\n");
+
+ mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
+ mdio_write(dev, phy_addr, MII_CONTROL, mii_control & ~MII_CNTL_PWRDWN);
+ mdelay(1);
+ return 0;
+}
+#endif
+
int lxt971a_init(struct net_device *dev, int phy_addr)
{
if (au1000_debug > 4)
@@ -727,6 +760,10 @@
am79c874_init,
am79c874_reset,
am79c874_status,
+#ifdef CONFIG_PM
+ am79c874_suspend,
+ am79c874_resume,
+#endif
};
struct phy_ops am79c901_ops = {
@@ -1108,9 +1145,6 @@
dev->name, (unsigned)aup);
spin_lock_irqsave(&aup->lock, flags);
- if (aup->timer.function == &au1000_timer) {/* check if timer initted */
- del_timer(&aup->timer);
- }
hard_stop(dev);
#ifdef CONFIG_BCM5222_DUAL_PHY
@@ -1158,84 +1192,6 @@
}
}
-static struct {
- int port;
- u32 base_addr;
- u32 macen_addr;
- int irq;
- struct net_device *dev;
-} iflist[2];
-
-static int num_ifs;
-
-/*
- * Setup the base address and interupt of the Au1xxx ethernet macs
- * based on cpu type and whether the interface is enabled in sys_pinfunc
- * register. The last interface is enabled if SYS_PF_NI2 (bit 4) is 0.
- */
-static int __init au1000_init_module(void)
-{
- struct cpuinfo_mips *c = ¤t_cpu_data;
- int ni = (int)((au_readl(SYS_PINFUNC) & (u32)(SYS_PF_NI2)) >> 4);
- struct net_device *dev;
- int i, found_one = 0;
-
- switch (c->cputype) {
-#ifdef CONFIG_SOC_AU1000
- case CPU_AU1000:
- num_ifs = 2 - ni;
- iflist[0].base_addr = AU1000_ETH0_BASE;
- iflist[1].base_addr = AU1000_ETH1_BASE;
- iflist[0].macen_addr = AU1000_MAC0_ENABLE;
- iflist[1].macen_addr = AU1000_MAC1_ENABLE;
- iflist[0].irq = AU1000_MAC0_DMA_INT;
- iflist[1].irq = AU1000_MAC1_DMA_INT;
- break;
-#endif
-#ifdef CONFIG_SOC_AU1100
- case CPU_AU1100:
- num_ifs = 1 - ni;
- iflist[0].base_addr = AU1100_ETH0_BASE;
- iflist[0].macen_addr = AU1100_MAC0_ENABLE;
- iflist[0].irq = AU1100_MAC0_DMA_INT;
- break;
-#endif
-#ifdef CONFIG_SOC_AU1500
- case CPU_AU1500:
- num_ifs = 2 - ni;
- iflist[0].base_addr = AU1500_ETH0_BASE;
- iflist[1].base_addr = AU1500_ETH1_BASE;
- iflist[0].macen_addr = AU1500_MAC0_ENABLE;
- iflist[1].macen_addr = AU1500_MAC1_ENABLE;
- iflist[0].irq = AU1500_MAC0_DMA_INT;
- iflist[1].irq = AU1500_MAC1_DMA_INT;
- break;
-#endif
-#ifdef CONFIG_SOC_AU1550
- case CPU_AU1550:
- num_ifs = 2 - ni;
- iflist[0].base_addr = AU1550_ETH0_BASE;
- iflist[1].base_addr = AU1550_ETH1_BASE;
- iflist[0].macen_addr = AU1550_MAC0_ENABLE;
- iflist[1].macen_addr = AU1550_MAC1_ENABLE;
- iflist[0].irq = AU1550_MAC0_DMA_INT;
- iflist[1].irq = AU1550_MAC1_DMA_INT;
- break;
-#endif
- default:
- num_ifs = 0;
- }
- for(i = 0; i < num_ifs; i++) {
- dev = au1000_probe(iflist[i].base_addr, iflist[i].irq, i);
- iflist[i].dev = dev;
- if (dev)
- found_one++;
- }
- if (!found_one)
- return -ENODEV;
- return 0;
-}
-
static int au1000_setup_aneg(struct net_device *dev, u32 advertise)
{
struct au1000_private *aup = (struct au1000_private *)dev->priv;
@@ -1435,40 +1391,14 @@
.get_link = au1000_get_link
};
-static struct net_device *
-au1000_probe(u32 ioaddr, int irq, int port_num)
+static int
+au1000_lowlevel_probe(struct net_device *ndev, u32 ioaddr, u32 macen_addr, int port_num)
{
- static unsigned version_printed = 0;
- struct au1000_private *aup = NULL;
- struct net_device *dev = NULL;
+ struct au1000_private *aup = ndev->priv;
db_dest_t *pDB, *pDBfree;
char *pmac, *argptr;
char ethaddr[6];
- int i, err;
-
- if (!request_mem_region(CPHYSADDR(ioaddr), MAC_IOSIZE, "Au1x00 ENET"))
- return NULL;
-
- if (version_printed++ == 0)
- printk("%s version %s %s\n", DRV_NAME, DRV_VERSION, DRV_AUTHOR);
-
- dev = alloc_etherdev(sizeof(struct au1000_private));
- if (!dev) {
- printk (KERN_ERR "au1000 eth: alloc_etherdev failed\n");
- return NULL;
- }
-
- if ((err = register_netdev(dev))) {
- printk(KERN_ERR "Au1x_eth Cannot register net device err %d\n",
- err);
- free_netdev(dev);
- return NULL;
- }
-
- printk("%s: Au1x Ethernet found at 0x%x, irq %d\n",
- dev->name, ioaddr, irq);
-
- aup = dev->priv;
+ int i, ret;
/* Allocate the data buffers */
/* Snooping works fine with eth on all au1xxx */
@@ -1477,15 +1407,16 @@
&aup->dma_addr,
0);
if (!aup->vaddr) {
- free_netdev(dev);
- release_mem_region(CPHYSADDR(ioaddr), MAC_IOSIZE);
- return NULL;
+ printk(KERN_ERR "%s: cannot dma_alloc_noncoherent\n",
+ ndev->name);
+ ret = -ENOMEM;
+ goto out;
}
/* aup->mac is the base address of the MAC's registers */
aup->mac = (volatile mac_reg_t *)((unsigned long)ioaddr);
/* Setup some variables for quick register address access */
- if (ioaddr == iflist[0].base_addr)
+ if (port_num == 0)
{
/* check env variables first */
if (!get_ethernet_addr(ethaddr)) {
@@ -1495,7 +1426,7 @@
argptr = prom_getcmdline();
if ((pmac = strstr(argptr, "ethaddr=")) == NULL) {
printk(KERN_INFO "%s: No mac address found\n",
- dev->name);
+ ndev->name);
/* use the hard coded mac addresses */
} else {
str2eaddr(ethaddr, pmac + strlen("ethaddr="));
@@ -1504,26 +1435,26 @@
}
}
aup->enable = (volatile u32 *)
- ((unsigned long)iflist[0].macen_addr);
- memcpy(dev->dev_addr, au1000_mac_addr, sizeof(au1000_mac_addr));
+ ((unsigned long) macen_addr);
+ memcpy(ndev->dev_addr, au1000_mac_addr, sizeof(au1000_mac_addr));
setup_hw_rings(aup, MAC0_RX_DMA_ADDR, MAC0_TX_DMA_ADDR);
aup->mac_id = 0;
au_macs[0] = aup;
}
else
- if (ioaddr == iflist[1].base_addr)
+ if (port_num == 1)
{
aup->enable = (volatile u32 *)
- ((unsigned long)iflist[1].macen_addr);
- memcpy(dev->dev_addr, au1000_mac_addr, sizeof(au1000_mac_addr));
- dev->dev_addr[4] += 0x10;
+ ((unsigned long) macen_addr);
+ memcpy(ndev->dev_addr, au1000_mac_addr, sizeof(au1000_mac_addr));
+ ndev->dev_addr[4] += 0x10;
setup_hw_rings(aup, MAC1_RX_DMA_ADDR, MAC1_TX_DMA_ADDR);
aup->mac_id = 1;
au_macs[1] = aup;
}
else
{
- printk(KERN_ERR "%s: bad ioaddr\n", dev->name);
+ printk(KERN_ERR "%s: bad ioaddr\n", ndev->name);
}
/* bring the device out of reset, otherwise probing the mii
@@ -1536,7 +1467,8 @@
aup->mii = kmalloc(sizeof(struct mii_phy), GFP_KERNEL);
if (!aup->mii) {
- printk(KERN_ERR "%s: out of memory\n", dev->name);
+ printk(KERN_ERR "%s: out of memory\n", ndev->name);
+ ret = -ENOMEM;
goto err_out;
}
aup->mii->next = NULL;
@@ -1545,7 +1477,8 @@
aup->mii->mii_control_reg = 0;
aup->mii->mii_data_reg = 0;
- if (mii_probe(dev) != 0) {
+ if (mii_probe(ndev) != 0) {
+ ret = -EBUSY;
goto err_out;
}
@@ -1564,6 +1497,7 @@
for (i = 0; i < NUM_RX_DMA; i++) {
pDB = GetFreeDB(aup);
if (!pDB) {
+ ret = -ENOMEM;
goto err_out;
}
aup->rx_dma_ring[i]->buff_stat = (unsigned)pDB->dma_addr;
@@ -1572,6 +1506,7 @@
for (i = 0; i < NUM_TX_DMA; i++) {
pDB = GetFreeDB(aup);
if (!pDB) {
+ ret = -ENOMEM;
goto err_out;
}
aup->tx_dma_ring[i]->buff_stat = (unsigned)pDB->dma_addr;
@@ -1579,32 +1514,24 @@
aup->tx_db_inuse[i] = pDB;
}
- spin_lock_init(&aup->lock);
- dev->base_addr = ioaddr;
- dev->irq = irq;
- dev->open = au1000_open;
- dev->hard_start_xmit = au1000_tx;
- dev->stop = au1000_close;
- dev->get_stats = au1000_get_stats;
- dev->set_multicast_list = &set_rx_mode;
- dev->do_ioctl = &au1000_ioctl;
- SET_ETHTOOL_OPS(dev, &au1000_ethtool_ops);
- dev->set_config = &au1000_set_config;
- dev->tx_timeout = au1000_tx_timeout;
- dev->watchdog_timeo = ETH_TX_TIMEOUT;
- /*
- * The boot code uses the ethernet controller, so reset it to start
- * fresh. au1000_init() expects that the device is in reset state.
- */
- reset_mac(dev);
+ return 0;
- return dev;
+err_out :
+ au1000_lowlevel_remove(ndev);
+out :
+ return ret;
+}
+
+static void
+au1000_lowlevel_remove(struct net_device *ndev)
+{
+ struct au1000_private *aup = ndev->priv;
+ int i;
-err_out:
/* here we should have a valid dev plus aup-> register addresses
* so we can reset the mac properly.*/
- reset_mac(dev);
+ reset_mac(ndev);
kfree(aup->mii);
for (i = 0; i < NUM_RX_DMA; i++) {
if (aup->rx_db_inuse[i])
@@ -1618,10 +1545,6 @@
MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS),
(void *)aup->vaddr,
aup->dma_addr);
- unregister_netdev(dev);
- free_netdev(dev);
- release_mem_region(CPHYSADDR(ioaddr), MAC_IOSIZE);
- return NULL;
}
/*
@@ -1779,6 +1712,7 @@
if (au1000_debug > 4)
printk("%s: close: dev=%p\n", dev->name, dev);
+ del_timer_sync(&aup->timer);
reset_mac(dev);
spin_lock_irqsave(&aup->lock, flags);
@@ -1793,36 +1727,6 @@
return 0;
}
-static void __exit au1000_cleanup_module(void)
-{
- int i, j;
- struct net_device *dev;
- struct au1000_private *aup;
-
- for (i = 0; i < num_ifs; i++) {
- dev = iflist[i].dev;
- if (dev) {
- aup = (struct au1000_private *) dev->priv;
- unregister_netdev(dev);
- kfree(aup->mii);
- for (j = 0; j < NUM_RX_DMA; j++) {
- if (aup->rx_db_inuse[j])
- ReleaseDB(aup, aup->rx_db_inuse[j]);
- }
- for (j = 0; j < NUM_TX_DMA; j++) {
- if (aup->tx_db_inuse[j])
- ReleaseDB(aup, aup->tx_db_inuse[j]);
- }
- dma_free_noncoherent(NULL,
- MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS),
- (void *)aup->vaddr,
- aup->dma_addr);
- free_netdev(dev);
- release_mem_region(CPHYSADDR(iflist[i].base_addr), MAC_IOSIZE);
- }
- }
-}
-
static void update_tx_stats(struct net_device *dev, u32 status)
{
struct au1000_private *aup = (struct au1000_private *) dev->priv;
@@ -2255,5 +2162,232 @@
return 0;
}
-module_init(au1000_init_module);
-module_exit(au1000_cleanup_module);
+/*
+ * Setup the base address and interupt of the Au1xxx ethernet macs
+ * based on cpu type and whether the interface is enabled in sys_pinfunc
+ * register. The last interface is enabled if SYS_PF_NI2 (bit 4) is 0.
+ */
+static int au1000_drv_probe(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct net_device *ndev;
+ struct au1000_private *aup;
+ struct resource *res;
+ static unsigned version_printed = 0;
+ u32 base_addr, macen_addr;
+ int irq, ret;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "eth-base");
+ if (!res) {
+ ret = -ENODEV;
+ goto out;
+ }
+ base_addr = res->start;
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "eth-mac");
+ if (!res) {
+ ret = -ENODEV;
+ goto out;
+ }
+ macen_addr = res->start;
+ res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "eth-irq");
+ if (!res) {
+ ret = -ENODEV;
+ goto out;
+ }
+ irq = res->start;
+
+ if (!request_mem_region(CPHYSADDR(base_addr), MAC_IOSIZE, "Au1x00 ENET")) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ if (version_printed++ == 0)
+ printk("%s version %s %s\n", DRV_NAME, DRV_VERSION, DRV_AUTHOR);
+
+ ndev = alloc_etherdev(sizeof(struct au1000_private));
+ if (!ndev) {
+ printk (KERN_ERR "%s: alloc etherdev failed\n", DRV_NAME);
+ ret = -ENOMEM;
+ goto out_release_io;
+ }
+ SET_MODULE_OWNER(ndev);
+ SET_NETDEV_DEV(ndev, dev);
+
+ ret = au1000_lowlevel_probe(ndev, base_addr, macen_addr, pdev->id);
+ if (ret < 0) {
+ printk (KERN_ERR "%s: low level probe failed\n", DRV_NAME);
+ goto out_free_netdev;
+ }
+
+ aup = ndev->priv;
+
+ spin_lock_init(&aup->lock);
+ ndev->base_addr = base_addr;
+ ndev->irq = irq;
+ ndev->open = au1000_open;
+ ndev->hard_start_xmit = au1000_tx;
+ ndev->stop = au1000_close;
+ ndev->get_stats = au1000_get_stats;
+ ndev->set_multicast_list = &set_rx_mode;
+ ndev->do_ioctl = &au1000_ioctl;
+ SET_ETHTOOL_OPS(ndev, &au1000_ethtool_ops);
+ ndev->set_config = &au1000_set_config;
+ ndev->tx_timeout = au1000_tx_timeout;
+ ndev->watchdog_timeo = ETH_TX_TIMEOUT;
+
+ /*
+ * The boot code uses the ethernet controller, so reset it to start
+ * fresh. au1000_init() expects that the device is in reset state.
+ */
+ reset_mac(ndev);
+
+ ret = register_netdev(ndev);
+ if (ret) {
+ printk(KERN_ERR "%s: cannot register net device err %d\n",
+ DRV_NAME, ret);
+ goto out_lowlevel_remove;
+ }
+
+ printk("%s: Au1x Ethernet found at 0x%x, irq %d\n",
+ ndev->name, base_addr, irq);
+
+ dev_set_drvdata(dev, ndev);
+
+ return 0;
+
+out_lowlevel_remove :
+ au1000_lowlevel_remove(ndev);
+out_free_netdev :
+ free_netdev(ndev);
+out_release_io :
+ release_mem_region(CPHYSADDR(base_addr), MAC_IOSIZE);
+out :
+ printk("%s: not found (%d).\n", DRV_NAME, ret);
+
+ return ret;
+}
+
+static int au1000_drv_remove(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct net_device *ndev = dev_get_drvdata(dev);
+ struct resource *res;
+
+ dev_set_drvdata(dev, NULL);
+
+ unregister_netdev(ndev);
+ au1000_lowlevel_remove(ndev);
+ free_netdev(ndev);
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "eth-base");
+ if (!res) {
+ printk(DRV_NAME ": warning! Invalid data!");
+ return -EINVAL;
+ }
+ release_mem_region(CPHYSADDR(res->start), MAC_IOSIZE);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int au1000_drv_suspend(struct device *dev, pm_message_t state, u32 level)
+{
+ struct net_device *ndev = dev_get_drvdata(dev);
+ struct au1000_private *aup = (struct au1000_private *) ndev->priv;
+
+ if (!ndev)
+ return 0;
+
+ switch (level) {
+ case SUSPEND_DISABLE :
+ if (netif_running(ndev))
+ netif_device_detach(ndev);
+
+ break;
+
+ case SUSPEND_SAVE_STATE :
+ /* bring the device out of reset, otherwise accessing to mii
+ * will hang */
+ *aup->enable = MAC_EN_CLOCK_ENABLE;
+ au_sync_delay(2);
+ *aup->enable = MAC_EN_RESET0 | MAC_EN_RESET1 |
+ MAC_EN_RESET2 | MAC_EN_CLOCK_ENABLE;
+ au_sync_delay(2);
+
+ if (aup->phy_ops->phy_suspend)
+ aup->phy_ops->phy_suspend(ndev, aup->phy_addr, level);
+
+ au1000_lowlevel_remove(ndev);
+
+ break;
+
+ case SUSPEND_POWER_DOWN :
+
+ break;
+ }
+
+ return 0;
+}
+
+static int au1000_drv_resume(struct device *dev, u32 level)
+{
+ struct net_device *ndev = dev_get_drvdata(dev);
+ struct au1000_private *aup = (struct au1000_private *) ndev->priv;
+ int ret;
+
+ if (!ndev)
+ return 0;
+
+ switch (level) {
+ case RESUME_RESTORE_STATE :
+ ret = au1000_lowlevel_probe(ndev, aup->mac, aup->enable, aup->mac_id);
+ if (ret < 0) {
+ printk (KERN_ERR "%s: low level probe failed\n", DRV_NAME);
+ return ret;
+ }
+
+ if (aup->phy_ops->phy_resume)
+ aup->phy_ops->phy_resume(ndev, aup->phy_addr, level);
+ aup->phy_ops->phy_init(ndev, aup->phy_addr);
+
+ /* au1000_init() expects that the device is in reset state.
+ */
+ reset_mac(ndev); /* au1000_init() expects the device in reset */
+ au1000_init(ndev);
+
+ break;
+
+ case RESUME_ENABLE :
+ if (netif_running(ndev))
+ netif_device_attach(ndev);
+
+ break;
+ }
+
+ return 0;
+}
+#endif
+
+static struct device_driver au1000_driver = {
+ .name = DRV_NAME,
+ .bus = &platform_bus_type,
+ .probe = au1000_drv_probe,
+ .remove = au1000_drv_remove,
+#ifdef CONFIG_PM
+ .suspend = au1000_drv_suspend,
+ .resume = au1000_drv_resume,
+#endif
+};
+
+static int __init au1000_eth_init(void)
+{
+ return driver_register(&au1000_driver);
+}
+
+static void __exit au1000_eth_cleanup(void)
+{
+ driver_unregister(&au1000_driver);
+}
+
+module_init(au1000_eth_init);
+module_exit(au1000_eth_cleanup);
--- /home/develop/embedded/mipsel/linux/linux-mips.git/drivers/net/au1000_eth.h 2006-03-31 16:58:55.000000000 +0200
+++ drivers/net/au1000_eth.h 2006-04-05 12:55:56.000000000 +0200
@@ -152,6 +152,8 @@
int (*phy_init) (struct net_device *, int);
int (*phy_reset) (struct net_device *, int);
int (*phy_status) (struct net_device *, int, u16 *, u16 *);
+ int (*phy_suspend) (struct net_device *, int, int);
+ int (*phy_resume) (struct net_device *, int, int);
};
/*
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] Oops! - Re: Power management for au1000_eth.c
2006-04-05 22:26 ` [PATCH] Oops! - " Rodolfo Giometti
@ 2006-04-06 14:43 ` Sergei Shtylyov
2006-04-06 15:50 ` Rodolfo Giometti
2006-04-06 17:10 ` Oops! - Re: Power management for au1000_eth.c Jordan Crouse
0 siblings, 2 replies; 11+ messages in thread
From: Sergei Shtylyov @ 2006-04-06 14:43 UTC (permalink / raw)
To: Linux MIPS; +Cc: Rodolfo Giometti, Jordan Crouse, Pete Popov
Hello.
Rodolfo Giometti wrote:
>>>I'm trying to add power management support to au1000_eth.c driver.
>>Solved! :)
>>Here a patch to implement power management functions for au1000_eth.
Actually, the network driver patches should be sent to Jeff Garzik and
Andrew Morton.
>>Note that this patch needs my previous one who implements new power
>>management's sysfs interface.
> The forgotten attachment. :)
Funny, I've also been cooking a patch to straighten Alchemy Ethernet
probing code a bit...
> ------------------------------------------------------------------------
>
> --- /home/develop/embedded/mipsel/linux/linux-mips.git/arch/mips/au1000/common/au1xxx_irqmap.c 2006-03-31 16:57:26.000000000 +0200
> +++ arch/mips/au1000/common/au1xxx_irqmap.c 2006-04-03 17:50:49.000000000 +0200
> @@ -118,7 +118,7 @@
> { AU1000_USB_DEV_SUS_INT, INTC_INT_RISE_EDGE, 0 },
> { AU1000_USB_HOST_INT, INTC_INT_LOW_LEVEL, 0 },
> { AU1000_ACSYNC_INT, INTC_INT_RISE_EDGE, 0 },
> - { AU1500_MAC0_DMA_INT, INTC_INT_HIGH_LEVEL, 0},
> + { AU1000_MAC0_DMA_INT, INTC_INT_HIGH_LEVEL, 0},
> { AU1500_MAC1_DMA_INT, INTC_INT_HIGH_LEVEL, 0},
> { AU1000_AC97C_INT, INTC_INT_RISE_EDGE, 0 },
>
> @@ -152,7 +152,7 @@
> { AU1000_USB_DEV_SUS_INT, INTC_INT_RISE_EDGE, 0 },
> { AU1000_USB_HOST_INT, INTC_INT_LOW_LEVEL, 0 },
> { AU1000_ACSYNC_INT, INTC_INT_RISE_EDGE, 0 },
> - { AU1100_MAC0_DMA_INT, INTC_INT_HIGH_LEVEL, 0},
> + { AU1000_MAC0_DMA_INT, INTC_INT_HIGH_LEVEL, 0},
> /*{ AU1000_GPIO215_208_INT, INTC_INT_HIGH_LEVEL, 0},*/
> { AU1100_LCD_INT, INTC_INT_HIGH_LEVEL, 0},
> { AU1000_AC97C_INT, INTC_INT_RISE_EDGE, 0 },
Don't think these changes are necessary.
> --- /home/develop/embedded/mipsel/linux/linux-mips.git/arch/mips/au1000/common/platform.c 2006-04-03 18:22:05.000000000 +0200
> +++ arch/mips/au1000/common/platform.c 2006-04-05 23:08:55.000000000 +0200
> @@ -16,6 +16,78 @@
>
> #include <asm/mach-au1x00/au1xxx.h>
>
> +#if defined(CONFIG_MIPS_AU1X00_ENET) || defined(CONFIG_MIPS_AU1X00_ENET_MODULE)
> +/* Ethernet controllers */
> +static struct resource au1xxx_eth0_resources[] = {
> + [0] = {
> + .name = "eth-base",
> + .start = ETH0_BASE,
> + .end = ETH0_BASE + 0x0ffff,
> + .flags = IORESOURCE_MEM,
> + },
NAK, ETH0_BASE not defined anywhere, and that address differs between SOCs.
Note that this must be a *physical* address, not KSEG1-base.
> + [1] = {
> + .name = "eth-mac",
> + .start = MAC0_ENABLE,
> + .end = MAC0_ENABLE + 0x0ffff,
> + .flags = IORESOURCE_MEM,
> + },
NAK, because:
1) MAC0_ENABLE not defined anywhere, and that address differs between SOCs;
2) MAC enable register occupies 4 bytes, not 65536.
[...]
> +#if defined(CONFIG_SOC_AU1000) || \
> + defined(CONFIG_SOC_AU1500) || defined(CONFIG_SOC_AU1550)
> +static struct resource au1xxx_eth1_resources[] = {
> + [0] = {
> + .name = "eth-base",
> + .start = ETH1_BASE,
> + .end = ETH1_BASE + 0x0ffff,
> + .flags = IORESOURCE_MEM,
> + },
> + [1] = {
> + .name = "eth-mac",
> + .start = MAC1_ENABLE,
> + .end = MAC1_ENABLE + 0x0ffff,
> + .flags = IORESOURCE_MEM,
> + },
Same here.
> --- /home/develop/embedded/mipsel/linux/linux-mips.git/drivers/net/au1000_eth.c 2006-04-03 18:23:17.000000000 +0200
> +++ drivers/net/au1000_eth.c 2006-04-05 23:43:18.000000000 +0200
[...]
> @@ -67,8 +71,8 @@
> static int au1000_debug = 3;
> #endif
>
> -#define DRV_NAME "au1000eth"
> -#define DRV_VERSION "1.5"
> +#define DRV_NAME "au1xxx-eth"
au1000_eth, according to the driver name.
> +#define DRV_VERSION "1.6"
Heh, nobody keeps track of the versions. :-)
> @@ -1435,40 +1391,14 @@
> .get_link = au1000_get_link
> };
>
> -static struct net_device *
> -au1000_probe(u32 ioaddr, int irq, int port_num)
> +static int
> +au1000_lowlevel_probe(struct net_device *ndev, u32 ioaddr, u32 macen_addr, int port_num)
[...]
> @@ -1477,15 +1407,16 @@
> &aup->dma_addr,
> 0);
> if (!aup->vaddr) {
> - free_netdev(dev);
> - release_mem_region(CPHYSADDR(ioaddr), MAC_IOSIZE);
> - return NULL;
> + printk(KERN_ERR "%s: cannot dma_alloc_noncoherent\n",
> + ndev->name);
> + ret = -ENOMEM;
> + goto out;
> }
>
> /* aup->mac is the base address of the MAC's registers */
> aup->mac = (volatile mac_reg_t *)((unsigned long)ioaddr);
NAK, ioaddr should be physical address.
> /* Setup some variables for quick register address access */
> - if (ioaddr == iflist[0].base_addr)
> + if (port_num == 0)
Yep, I disliked this code too. :-)
> {
> /* check env variables first */
> if (!get_ethernet_addr(ethaddr)) {
> @@ -1495,7 +1426,7 @@
> argptr = prom_getcmdline();
> if ((pmac = strstr(argptr, "ethaddr=")) == NULL) {
> printk(KERN_INFO "%s: No mac address found\n",
> - dev->name);
> + ndev->name);
> /* use the hard coded mac addresses */
> } else {
> str2eaddr(ethaddr, pmac + strlen("ethaddr="));
> @@ -1504,26 +1435,26 @@
> }
> }
> aup->enable = (volatile u32 *)
> - ((unsigned long)iflist[0].macen_addr);
> - memcpy(dev->dev_addr, au1000_mac_addr, sizeof(au1000_mac_addr));
> + ((unsigned long) macen_addr);
NAK, macen_addr should have been a physical address at that point too
(if the plarform definitions were correct :-). Also, this could have been done
outside of "if".
> + memcpy(ndev->dev_addr, au1000_mac_addr, sizeof(au1000_mac_addr));
That too.
> setup_hw_rings(aup, MAC0_RX_DMA_ADDR, MAC0_TX_DMA_ADDR);
> aup->mac_id = 0;
> au_macs[0] = aup;
> }
> else
> - if (ioaddr == iflist[1].base_addr)
> + if (port_num == 1)
> {
> aup->enable = (volatile u32 *)
> - ((unsigned long)iflist[1].macen_addr);
> - memcpy(dev->dev_addr, au1000_mac_addr, sizeof(au1000_mac_addr));
> - dev->dev_addr[4] += 0x10;
> + ((unsigned long) macen_addr);
> + memcpy(ndev->dev_addr, au1000_mac_addr, sizeof(au1000_mac_addr));
> + ndev->dev_addr[4] += 0x10;
Actually, the DBAu15x0 boards have their Ethernet addresess differ by 1 in
the last byte, not by 0x10 in the next to last one. This code assigns to the
port an address different to what's printed on a port's sticker. This should
be fixed I guess...
> setup_hw_rings(aup, MAC1_RX_DMA_ADDR, MAC1_TX_DMA_ADDR);
> aup->mac_id = 1;
> au_macs[1] = aup;
> }
> else
> {
> - printk(KERN_ERR "%s: bad ioaddr\n", dev->name);
> + printk(KERN_ERR "%s: bad ioaddr\n", ndev->name);
> }
Doubt we need this "else" at all...
> @@ -2255,5 +2162,232 @@
> return 0;
> }
>
> -module_init(au1000_init_module);
> -module_exit(au1000_cleanup_module);
> +/*
> + * Setup the base address and interupt of the Au1xxx ethernet macs
> + * based on cpu type and whether the interface is enabled in sys_pinfunc
> + * register. The last interface is enabled if SYS_PF_NI2 (bit 4) is 0.
> + */
> +static int au1000_drv_probe(struct device *dev)
> +{
> + struct platform_device *pdev = to_platform_device(dev);
> + struct net_device *ndev;
> + struct au1000_private *aup;
> + struct resource *res;
> + static unsigned version_printed = 0;
> + u32 base_addr, macen_addr;
> + int irq, ret;
> +
> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "eth-base");
> + if (!res) {
> + ret = -ENODEV;
> + goto out;
> + }
> + base_addr = res->start;
> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "eth-mac");
> + if (!res) {
> + ret = -ENODEV;
> + goto out;
> + }
> + macen_addr = res->start;
> + res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "eth-irq");
> + if (!res) {
> + ret = -ENODEV;
> + goto out;
> + }
> + irq = res->start;
> +
> + if (!request_mem_region(CPHYSADDR(base_addr), MAC_IOSIZE, "Au1x00 ENET")) {
NAK, base_addr should adready be a physical address. Also, why no
request_mem_region()
for the MAC enable register?
> + ret = au1000_lowlevel_probe(ndev, base_addr, macen_addr, pdev->id);
Remember, The passed addresses are physical at that point.
[...]
WBR, Sergei
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] Oops! - Re: Power management for au1000_eth.c
2006-04-06 14:43 ` Sergei Shtylyov
@ 2006-04-06 15:50 ` Rodolfo Giometti
2006-04-19 18:46 ` [PATCH] au1000_eth.c probe code straightened up Sergei Shtylyov
2006-04-06 17:10 ` Oops! - Re: Power management for au1000_eth.c Jordan Crouse
1 sibling, 1 reply; 11+ messages in thread
From: Rodolfo Giometti @ 2006-04-06 15:50 UTC (permalink / raw)
To: Linux MIPS; +Cc: Sergei Shtylyov, Jordan Crouse, Pete Popov
[-- Attachment #1.1: Type: text/plain, Size: 6811 bytes --]
On Thu, Apr 06, 2006 at 06:43:24PM +0400, Sergei Shtylyov wrote:
>
> Actually, the network driver patches should be sent to Jeff Garzik and
> Andrew Morton.
Ok. Sorry. Hope they can get the patch from this list.
> Funny, I've also been cooking a patch to straighten Alchemy Ethernet
> probing code a bit...
:)
> >------------------------------------------------------------------------
> >
> >---
> >/home/develop/embedded/mipsel/linux/linux-mips.git/arch/mips/au1000/common/au1xxx_irqmap.c 2006-03-31 16:57:26.000000000 +0200
> >+++ arch/mips/au1000/common/au1xxx_irqmap.c 2006-04-03
> >17:50:49.000000000 +0200
> >@@ -118,7 +118,7 @@
> > { AU1000_USB_DEV_SUS_INT, INTC_INT_RISE_EDGE, 0 },
> > { AU1000_USB_HOST_INT, INTC_INT_LOW_LEVEL, 0 },
> > { AU1000_ACSYNC_INT, INTC_INT_RISE_EDGE, 0 },
> >- { AU1500_MAC0_DMA_INT, INTC_INT_HIGH_LEVEL, 0},
> >+ { AU1000_MAC0_DMA_INT, INTC_INT_HIGH_LEVEL, 0},
> > { AU1500_MAC1_DMA_INT, INTC_INT_HIGH_LEVEL, 0},
> > { AU1000_AC97C_INT, INTC_INT_RISE_EDGE, 0 },
> >
> >@@ -152,7 +152,7 @@
> > { AU1000_USB_DEV_SUS_INT, INTC_INT_RISE_EDGE, 0 },
> > { AU1000_USB_HOST_INT, INTC_INT_LOW_LEVEL, 0 },
> > { AU1000_ACSYNC_INT, INTC_INT_RISE_EDGE, 0 },
> >- { AU1100_MAC0_DMA_INT, INTC_INT_HIGH_LEVEL, 0},
> >+ { AU1000_MAC0_DMA_INT, INTC_INT_HIGH_LEVEL, 0},
> > /*{ AU1000_GPIO215_208_INT, INTC_INT_HIGH_LEVEL, 0},*/
> > { AU1100_LCD_INT, INTC_INT_HIGH_LEVEL, 0},
> > { AU1000_AC97C_INT, INTC_INT_RISE_EDGE, 0 },
>
> Don't think these changes are necessary.
These are necessary to group togheter CPUs that have the same
parameters.
> >---
> >/home/develop/embedded/mipsel/linux/linux-mips.git/arch/mips/au1000/common/platform.c 2006-04-03 18:22:05.000000000 +0200
> >+++ arch/mips/au1000/common/platform.c 2006-04-05
> >23:08:55.000000000 +0200
> >@@ -16,6 +16,78 @@
> >
> > #include <asm/mach-au1x00/au1xxx.h>
> >
> >+#if defined(CONFIG_MIPS_AU1X00_ENET) ||
> >defined(CONFIG_MIPS_AU1X00_ENET_MODULE)
> >+/* Ethernet controllers */
> >+static struct resource au1xxx_eth0_resources[] = {
> >+ [0] = {
> >+ .name = "eth-base",
> >+ .start = ETH0_BASE,
> >+ .end = ETH0_BASE + 0x0ffff,
> > + .flags = IORESOURCE_MEM,
> > + },
>
> NAK, ETH0_BASE not defined anywhere, and that address differs between
> SOCs.
> Note that this must be a *physical* address, not KSEG1-base.
You are right! I forgot to add the attached file... I'm very sorry but
I must work on an older Linux version which still use CVS. I can't
switch to GIT right now and I have to build my patches by hands.
In the attached file you can see that I grouped togheter CPUs that
have the same configuration parameters.
> > /* Setup some variables for quick register address access */
> >- if (ioaddr == iflist[0].base_addr)
> >+ if (port_num == 0)
>
> Yep, I disliked this code too. :-)
I just use the "id" filed instaed of using the base address. It seems
to me more readable...
> > {
> > /* check env variables first */
> > if (!get_ethernet_addr(ethaddr)) {
> >@@ -1495,7 +1426,7 @@
> > argptr = prom_getcmdline();
> > if ((pmac = strstr(argptr, "ethaddr=")) == NULL) {
> > printk(KERN_INFO "%s: No mac address
> > found\n", - dev->name);
> >+ ndev->name);
> > /* use the hard coded mac addresses */
> > } else {
> > str2eaddr(ethaddr, pmac +
> > strlen("ethaddr="));
> >@@ -1504,26 +1435,26 @@
> > }
> > }
> > aup->enable = (volatile u32 *)
> >- ((unsigned long)iflist[0].macen_addr);
> >- memcpy(dev->dev_addr, au1000_mac_addr,
> >sizeof(au1000_mac_addr));
> >+ ((unsigned long) macen_addr);
>
> NAK, macen_addr should have been a physical address at that point too
> (if the plarform definitions were correct :-). Also, this could have been
> done
> outside of "if".
I just keeped the original structure...
> > setup_hw_rings(aup, MAC0_RX_DMA_ADDR, MAC0_TX_DMA_ADDR);
> > aup->mac_id = 0;
> > au_macs[0] = aup;
> > }
> > else
> >- if (ioaddr == iflist[1].base_addr)
> >+ if (port_num == 1)
> > {
> > aup->enable = (volatile u32 *)
> >- ((unsigned long)iflist[1].macen_addr);
> >- memcpy(dev->dev_addr, au1000_mac_addr,
> >sizeof(au1000_mac_addr));
> >- dev->dev_addr[4] += 0x10;
> >+ ((unsigned long) macen_addr);
> >+ memcpy(ndev->dev_addr, au1000_mac_addr,
> >sizeof(au1000_mac_addr));
> >+ ndev->dev_addr[4] += 0x10;
>
> Actually, the DBAu15x0 boards have their Ethernet addresess differ by 1
> in the last byte, not by 0x10 in the next to last one. This code assigns to
> the port an address different to what's printed on a port's sticker. This
> should be fixed I guess...
Yes. However this comes from the previous driver version and I'm
working on an Au1100 based board. :)
> >@@ -2255,5 +2162,232 @@
> > return 0;
> > }
> >
> >-module_init(au1000_init_module);
> >-module_exit(au1000_cleanup_module);
> >+/*
> >+ * Setup the base address and interupt of the Au1xxx ethernet macs
> >+ * based on cpu type and whether the interface is enabled in sys_pinfunc
> >+ * register. The last interface is enabled if SYS_PF_NI2 (bit 4) is 0.
> >+ */
> >+static int au1000_drv_probe(struct device *dev)
> >+{
> >+ struct platform_device *pdev = to_platform_device(dev);
> >+ struct net_device *ndev;
> >+ struct au1000_private *aup;
> >+ struct resource *res;
> >+ static unsigned version_printed = 0;
> >+ u32 base_addr, macen_addr;
> >+ int irq, ret;
> >+
> >+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "eth-base");
> >+ if (!res) {
> >+ ret = -ENODEV;
> >+ goto out;
> >+ }
> >+ base_addr = res->start;
> >+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "eth-mac");
> >+ if (!res) {
> >+ ret = -ENODEV;
> >+ goto out;
> >+ }
> >+ macen_addr = res->start;
> >+ res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "eth-irq");
> >+ if (!res) {
> >+ ret = -ENODEV;
> >+ goto out;
> >+ }
> >+ irq = res->start;
> >+
> >+ if (!request_mem_region(CPHYSADDR(base_addr), MAC_IOSIZE, "Au1x00
> >ENET")) {
>
> NAK, base_addr should adready be a physical address. Also, why no
> request_mem_region()
> for the MAC enable register?
Yes. I forgot to add it.
Thanks for your suggestions! But I'd like to know if I have to change
something and resubmit the patch or these suggestions can be resolved
during the merging of the code...
Ciao,
Rodolfo
--
GNU/Linux Solutions e-mail: giometti@enneenne.com
Linux Device Driver giometti@gnudd.com
Embedded Systems giometti@linux.it
UNIX programming phone: +39 349 2432127
[-- Attachment #1.2: patch-au1000_eth-pm-2 --]
[-- Type: text/plain, Size: 2999 bytes --]
--- /home/develop/embedded/mipsel/linux/linux-mips.git/include/asm-mips/mach-au1x00/au1000.h 2006-04-03 18:24:38.000000000 +0200
+++ include/asm-mips/mach-au1x00/au1000.h 2006-04-06 17:31:04.000000000 +0200
@@ -606,11 +690,10 @@
#define USB_OHCI_BASE 0x10100000 // phys addr for ioremap
#define USB_HOST_CONFIG 0xB017fffc
-#define AU1000_ETH0_BASE 0xB0500000
-#define AU1000_ETH1_BASE 0xB0510000
-#define AU1000_MAC0_ENABLE 0xB0520000
-#define AU1000_MAC1_ENABLE 0xB0520004
-#define NUM_ETH_INTERFACES 2
+#define ETH0_BASE 0xB0500000
+#define ETH1_BASE 0xB0510000
+#define MAC0_ENABLE 0xB0520000
+#define MAC1_ENABLE 0xB0520004
#endif /* CONFIG_SOC_AU1000 */
/* Au1500 */
@@ -635,8 +718,8 @@
#define AU1000_USB_DEV_SUS_INT 25
#define AU1000_USB_HOST_INT 26
#define AU1000_ACSYNC_INT 27
-#define AU1500_MAC0_DMA_INT 28
-#define AU1500_MAC1_DMA_INT 29
+#define AU1000_MAC0_DMA_INT 28
+#define AU1000_MAC1_DMA_INT 29
#define AU1000_AC97C_INT 31
#define AU1000_GPIO_0 32
#define AU1000_GPIO_1 33
@@ -683,11 +766,10 @@
#define USB_OHCI_BASE 0x10100000 // phys addr for ioremap
#define USB_HOST_CONFIG 0xB017fffc
-#define AU1500_ETH0_BASE 0xB1500000
-#define AU1500_ETH1_BASE 0xB1510000
-#define AU1500_MAC0_ENABLE 0xB1520000
-#define AU1500_MAC1_ENABLE 0xB1520004
-#define NUM_ETH_INTERFACES 2
+#define ETH0_BASE 0xB1500000
+#define ETH1_BASE 0xB1510000
+#define MAC0_ENABLE 0xB1520000
+#define MAC1_ENABLE 0xB1520004
#endif /* CONFIG_SOC_AU1500 */
/* Au1100 */
@@ -713,8 +795,8 @@
#define AU1000_USB_DEV_SUS_INT 25
#define AU1000_USB_HOST_INT 26
#define AU1000_ACSYNC_INT 27
-#define AU1100_MAC0_DMA_INT 28
-#define AU1100_GPIO_208_215 29
+#define AU1000_MAC0_DMA_INT 28
+#define AU1100_GPIO_208_215 29
#define AU1100_LCD_INT 30
#define AU1000_AC97C_INT 31
#define AU1000_GPIO_0 32
@@ -757,8 +839,8 @@
#define USB_OHCI_BASE 0x10100000 // phys addr for ioremap
#define USB_HOST_CONFIG 0xB017fffc
-#define AU1100_ETH0_BASE 0xB0500000
-#define AU1100_MAC0_ENABLE 0xB0520000
+#define ETH0_BASE 0xB0500000
+#define MAC0_ENABLE 0xB0520000
#define NUM_ETH_INTERFACES 1
#endif /* CONFIG_SOC_AU1100 */
@@ -841,11 +923,10 @@
#define USB_OHCI_LEN 0x00060000
#define USB_HOST_CONFIG 0xB4027ffc
-#define AU1550_ETH0_BASE 0xB0500000
-#define AU1550_ETH1_BASE 0xB0510000
-#define AU1550_MAC0_ENABLE 0xB0520000
-#define AU1550_MAC1_ENABLE 0xB0520004
-#define NUM_ETH_INTERFACES 2
+#define ETH0_BASE 0xB0500000
+#define ETH1_BASE 0xB0510000
+#define MAC0_ENABLE 0xB0520000
+#define MAC1_ENABLE 0xB0520004
#endif /* CONFIG_SOC_AU1550 */
#ifdef CONFIG_SOC_AU1200
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Oops! - Re: Power management for au1000_eth.c
2006-04-06 14:43 ` Sergei Shtylyov
2006-04-06 15:50 ` Rodolfo Giometti
@ 2006-04-06 17:10 ` Jordan Crouse
1 sibling, 0 replies; 11+ messages in thread
From: Jordan Crouse @ 2006-04-06 17:10 UTC (permalink / raw)
To: Sergei Shtylyov; +Cc: Linux MIPS, Rodolfo Giometti, Pete Popov
On 06/04/06 18:43 +0400, Sergei Shtylyov wrote:
> Hello.
>
> Rodolfo Giometti wrote:
>
> >>>I'm trying to add power management support to au1000_eth.c driver.
>
> >>Solved! :)
>
> >>Here a patch to implement power management functions for au1000_eth.
>
> Actually, the network driver patches should be sent to Jeff Garzik and
> Andrew Morton.
And the description is wrong - this isn't exactly just power management,
there are lots of changes here. You should separate them out into multiple
patches.
> >>Note that this patch needs my previous one who implements new power
> >>management's sysfs interface.
Thats OK, as long as this patch can be applied on its own, without requiring
the previous patch. It is one thing to write a new PM interface for the
whole system, but the driver suspend and resume functions should never be
system specific. That makes life easier for future developers.
> Funny, I've also been cooking a patch to straighten Alchemy Ethernet
> probing code a bit...
I think we can all get along here. The PM stuff looks decent to me, and
Sergei had some good comments about the rest of the patch. I don't see
any reason why the two of you can't get together and bang out a few patches
to fix all of our ills.
Jordan
--
Jordan Crouse
Senior Linux Engineer
AMD - Personal Connectivity Solutions Group
<www.amd.com/embeddedprocessors>
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH] au1000_eth.c probe code straightened up
2006-04-06 15:50 ` Rodolfo Giometti
@ 2006-04-19 18:46 ` Sergei Shtylyov
2006-05-02 15:09 ` [PATCH] au1000_eth.c Power Management, driver registration and module support Rodolfo Giometti
0 siblings, 1 reply; 11+ messages in thread
From: Sergei Shtylyov @ 2006-04-19 18:46 UTC (permalink / raw)
To: jgarzik; +Cc: Rodolfo Giometti, netdev, Linux-MIPS
[-- Attachment #1: Type: text/plain, Size: 429 bytes --]
Straighten up the AMD Au1xx0 Ethernet probing code, make it print out (and
store in the 'net_device' structure) the physical address of the controller,
not the KSEG1-based virtual. Make the driver also claim/release the 4-byte MAC
enable registers and assign to the Ethernet ports two consecutive MAC
addresses to match those that are printed on their stickers.
Signed-off-by: Sergei Shtylyov <sshtylyov@ru.mvista.com>
[-- Attachment #2: au1000_eth-probe-rewrite.patch --]
[-- Type: text/plain, Size: 10374 bytes --]
diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c
index 1363083..d5dfc78 100644
--- a/drivers/net/au1000_eth.c
+++ b/drivers/net/au1000_eth.c
@@ -2,7 +2,7 @@
*
* Alchemy Au1x00 ethernet driver
*
- * Copyright 2001,2002,2003 MontaVista Software Inc.
+ * Copyright 2001-2003, 2006 MontaVista Software Inc.
* Copyright 2002 TimeSys Corp.
* Added ethtool/mii-tool support,
* Copyright 2004 Matt Porter <mporter@kernel.crashing.org>
@@ -67,7 +67,7 @@ static int au1000_debug = 5;
static int au1000_debug = 3;
#endif
-#define DRV_NAME "au1000eth"
+#define DRV_NAME "au1000_eth"
#define DRV_VERSION "1.5"
#define DRV_AUTHOR "Pete Popov <ppopov@embeddedalley.com>"
#define DRV_DESC "Au1xxx on-chip Ethernet driver"
@@ -79,7 +79,7 @@ MODULE_LICENSE("GPL");
// prototypes
static void hard_stop(struct net_device *);
static void enable_rx_tx(struct net_device *dev);
-static struct net_device * au1000_probe(u32 ioaddr, int irq, int port_num);
+static struct net_device * au1000_probe(int port_num);
static int au1000_init(struct net_device *);
static int au1000_open(struct net_device *);
static int au1000_close(struct net_device *);
@@ -1159,12 +1159,27 @@ setup_hw_rings(struct au1000_private *au
}
static struct {
- int port;
u32 base_addr;
u32 macen_addr;
int irq;
struct net_device *dev;
-} iflist[2];
+} iflist[2] = {
+#ifdef CONFIG_SOC_AU1000
+ {AU1000_ETH0_BASE, AU1000_MAC0_ENABLE, AU1000_MAC0_DMA_INT},
+ {AU1000_ETH1_BASE, AU1000_MAC1_ENABLE, AU1000_MAC1_DMA_INT}
+#endif
+#ifdef CONFIG_SOC_AU1100
+ {AU1100_ETH0_BASE, AU1100_MAC0_ENABLE, AU1100_MAC0_DMA_INT}
+#endif
+#ifdef CONFIG_SOC_AU1500
+ {AU1500_ETH0_BASE, AU1500_MAC0_ENABLE, AU1500_MAC0_DMA_INT},
+ {AU1500_ETH1_BASE, AU1500_MAC1_ENABLE, AU1500_MAC1_DMA_INT}
+#endif
+#ifdef CONFIG_SOC_AU1550
+ {AU1550_ETH0_BASE, AU1550_MAC0_ENABLE, AU1550_MAC0_DMA_INT},
+ {AU1550_ETH1_BASE, AU1550_MAC1_ENABLE, AU1550_MAC1_DMA_INT}
+#endif
+};
static int num_ifs;
@@ -1175,58 +1190,14 @@ static int num_ifs;
*/
static int __init au1000_init_module(void)
{
- struct cpuinfo_mips *c = ¤t_cpu_data;
int ni = (int)((au_readl(SYS_PINFUNC) & (u32)(SYS_PF_NI2)) >> 4);
struct net_device *dev;
int i, found_one = 0;
- switch (c->cputype) {
-#ifdef CONFIG_SOC_AU1000
- case CPU_AU1000:
- num_ifs = 2 - ni;
- iflist[0].base_addr = AU1000_ETH0_BASE;
- iflist[1].base_addr = AU1000_ETH1_BASE;
- iflist[0].macen_addr = AU1000_MAC0_ENABLE;
- iflist[1].macen_addr = AU1000_MAC1_ENABLE;
- iflist[0].irq = AU1000_MAC0_DMA_INT;
- iflist[1].irq = AU1000_MAC1_DMA_INT;
- break;
-#endif
-#ifdef CONFIG_SOC_AU1100
- case CPU_AU1100:
- num_ifs = 1 - ni;
- iflist[0].base_addr = AU1100_ETH0_BASE;
- iflist[0].macen_addr = AU1100_MAC0_ENABLE;
- iflist[0].irq = AU1100_MAC0_DMA_INT;
- break;
-#endif
-#ifdef CONFIG_SOC_AU1500
- case CPU_AU1500:
- num_ifs = 2 - ni;
- iflist[0].base_addr = AU1500_ETH0_BASE;
- iflist[1].base_addr = AU1500_ETH1_BASE;
- iflist[0].macen_addr = AU1500_MAC0_ENABLE;
- iflist[1].macen_addr = AU1500_MAC1_ENABLE;
- iflist[0].irq = AU1500_MAC0_DMA_INT;
- iflist[1].irq = AU1500_MAC1_DMA_INT;
- break;
-#endif
-#ifdef CONFIG_SOC_AU1550
- case CPU_AU1550:
- num_ifs = 2 - ni;
- iflist[0].base_addr = AU1550_ETH0_BASE;
- iflist[1].base_addr = AU1550_ETH1_BASE;
- iflist[0].macen_addr = AU1550_MAC0_ENABLE;
- iflist[1].macen_addr = AU1550_MAC1_ENABLE;
- iflist[0].irq = AU1550_MAC0_DMA_INT;
- iflist[1].irq = AU1550_MAC1_DMA_INT;
- break;
-#endif
- default:
- num_ifs = 0;
- }
+ num_ifs = NUM_ETH_INTERFACES - ni;
+
for(i = 0; i < num_ifs; i++) {
- dev = au1000_probe(iflist[i].base_addr, iflist[i].irq, i);
+ dev = au1000_probe(i);
iflist[i].dev = dev;
if (dev)
found_one++;
@@ -1435,8 +1406,7 @@ static struct ethtool_ops au1000_ethtool
.get_link = au1000_get_link
};
-static struct net_device *
-au1000_probe(u32 ioaddr, int irq, int port_num)
+static struct net_device * au1000_probe(int port_num)
{
static unsigned version_printed = 0;
struct au1000_private *aup = NULL;
@@ -1444,94 +1414,95 @@ au1000_probe(u32 ioaddr, int irq, int po
db_dest_t *pDB, *pDBfree;
char *pmac, *argptr;
char ethaddr[6];
- int i, err;
+ int irq, i, err;
+ u32 base, macen;
+
+ if (port_num >= NUM_ETH_INTERFACES)
+ return NULL;
- if (!request_mem_region(CPHYSADDR(ioaddr), MAC_IOSIZE, "Au1x00 ENET"))
+ base = CPHYSADDR(iflist[port_num].base_addr );
+ macen = CPHYSADDR(iflist[port_num].macen_addr);
+ irq = iflist[port_num].irq;
+
+ if (!request_mem_region( base, MAC_IOSIZE, "Au1x00 ENET") ||
+ !request_mem_region(macen, 4, "Au1x00 ENET"))
return NULL;
- if (version_printed++ == 0)
+ if (version_printed++ == 0)
printk("%s version %s %s\n", DRV_NAME, DRV_VERSION, DRV_AUTHOR);
dev = alloc_etherdev(sizeof(struct au1000_private));
if (!dev) {
- printk (KERN_ERR "au1000 eth: alloc_etherdev failed\n");
+ printk(KERN_ERR "%s: alloc_etherdev failed\n", DRV_NAME);
return NULL;
}
- if ((err = register_netdev(dev))) {
- printk(KERN_ERR "Au1x_eth Cannot register net device err %d\n",
- err);
+ if ((err = register_netdev(dev)) != 0) {
+ printk(KERN_ERR "%s: Cannot register net device, error %d\n",
+ DRV_NAME, err);
free_netdev(dev);
return NULL;
}
- printk("%s: Au1x Ethernet found at 0x%x, irq %d\n",
- dev->name, ioaddr, irq);
+ printk("%s: Au1xx0 Ethernet found at 0x%x, irq %d\n",
+ dev->name, base, irq);
aup = dev->priv;
/* Allocate the data buffers */
/* Snooping works fine with eth on all au1xxx */
- aup->vaddr = (u32)dma_alloc_noncoherent(NULL,
- MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS),
- &aup->dma_addr,
- 0);
+ aup->vaddr = (u32)dma_alloc_noncoherent(NULL, MAX_BUF_SIZE *
+ (NUM_TX_BUFFS + NUM_RX_BUFFS),
+ &aup->dma_addr, 0);
if (!aup->vaddr) {
free_netdev(dev);
- release_mem_region(CPHYSADDR(ioaddr), MAC_IOSIZE);
+ release_mem_region( base, MAC_IOSIZE);
+ release_mem_region(macen, 4);
return NULL;
}
/* aup->mac is the base address of the MAC's registers */
- aup->mac = (volatile mac_reg_t *)((unsigned long)ioaddr);
+ aup->mac = (volatile mac_reg_t *)iflist[port_num].base_addr;
+
/* Setup some variables for quick register address access */
- if (ioaddr == iflist[0].base_addr)
- {
- /* check env variables first */
- if (!get_ethernet_addr(ethaddr)) {
+ aup->enable = (volatile u32 *)iflist[port_num].macen_addr;
+ aup->mac_id = port_num;
+ au_macs[port_num] = aup;
+
+ if (port_num == 0) {
+ /* Check the environment variables first */
+ if (get_ethernet_addr(ethaddr) == 0)
memcpy(au1000_mac_addr, ethaddr, sizeof(au1000_mac_addr));
- } else {
+ else {
/* Check command line */
argptr = prom_getcmdline();
- if ((pmac = strstr(argptr, "ethaddr=")) == NULL) {
- printk(KERN_INFO "%s: No mac address found\n",
- dev->name);
- /* use the hard coded mac addresses */
- } else {
+ if ((pmac = strstr(argptr, "ethaddr=")) == NULL)
+ printk(KERN_INFO "%s: No MAC address found\n",
+ dev->name);
+ /* Use the hard coded MAC addresses */
+ else {
str2eaddr(ethaddr, pmac + strlen("ethaddr="));
memcpy(au1000_mac_addr, ethaddr,
- sizeof(au1000_mac_addr));
+ sizeof(au1000_mac_addr));
}
}
- aup->enable = (volatile u32 *)
- ((unsigned long)iflist[0].macen_addr);
- memcpy(dev->dev_addr, au1000_mac_addr, sizeof(au1000_mac_addr));
+
setup_hw_rings(aup, MAC0_RX_DMA_ADDR, MAC0_TX_DMA_ADDR);
- aup->mac_id = 0;
- au_macs[0] = aup;
- }
- else
- if (ioaddr == iflist[1].base_addr)
- {
- aup->enable = (volatile u32 *)
- ((unsigned long)iflist[1].macen_addr);
- memcpy(dev->dev_addr, au1000_mac_addr, sizeof(au1000_mac_addr));
- dev->dev_addr[4] += 0x10;
+ } else if (port_num == 1)
setup_hw_rings(aup, MAC1_RX_DMA_ADDR, MAC1_TX_DMA_ADDR);
- aup->mac_id = 1;
- au_macs[1] = aup;
- }
- else
- {
- printk(KERN_ERR "%s: bad ioaddr\n", dev->name);
- }
- /* bring the device out of reset, otherwise probing the mii
- * will hang */
+ /*
+ * Assign to the Ethernet ports two consecutive MAC addresses
+ * to match those that are printed on their stickers
+ */
+ memcpy(dev->dev_addr, au1000_mac_addr, sizeof(au1000_mac_addr));
+ dev->dev_addr[5] += port_num;
+
+ /* Bring the device out of reset, otherwise probing the MII will hang */
*aup->enable = MAC_EN_CLOCK_ENABLE;
au_sync_delay(2);
- *aup->enable = MAC_EN_RESET0 | MAC_EN_RESET1 |
- MAC_EN_RESET2 | MAC_EN_CLOCK_ENABLE;
+ *aup->enable = MAC_EN_RESET0 | MAC_EN_RESET1 | MAC_EN_RESET2 |
+ MAC_EN_CLOCK_ENABLE;
au_sync_delay(2);
aup->mii = kmalloc(sizeof(struct mii_phy), GFP_KERNEL);
@@ -1580,7 +1551,7 @@ au1000_probe(u32 ioaddr, int irq, int po
}
spin_lock_init(&aup->lock);
- dev->base_addr = ioaddr;
+ dev->base_addr = base;
dev->irq = irq;
dev->open = au1000_open;
dev->hard_start_xmit = au1000_tx;
@@ -1614,13 +1585,12 @@ err_out:
if (aup->tx_db_inuse[i])
ReleaseDB(aup, aup->tx_db_inuse[i]);
}
- dma_free_noncoherent(NULL,
- MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS),
- (void *)aup->vaddr,
- aup->dma_addr);
+ dma_free_noncoherent(NULL, MAX_BUF_SIZE * (NUM_TX_BUFFS + NUM_RX_BUFFS),
+ (void *)aup->vaddr, aup->dma_addr);
unregister_netdev(dev);
free_netdev(dev);
- release_mem_region(CPHYSADDR(ioaddr), MAC_IOSIZE);
+ release_mem_region( base, MAC_IOSIZE);
+ release_mem_region(macen, 4);
return NULL;
}
@@ -1805,20 +1775,18 @@ static void __exit au1000_cleanup_module
aup = (struct au1000_private *) dev->priv;
unregister_netdev(dev);
kfree(aup->mii);
- for (j = 0; j < NUM_RX_DMA; j++) {
+ for (j = 0; j < NUM_RX_DMA; j++)
if (aup->rx_db_inuse[j])
ReleaseDB(aup, aup->rx_db_inuse[j]);
- }
- for (j = 0; j < NUM_TX_DMA; j++) {
+ for (j = 0; j < NUM_TX_DMA; j++)
if (aup->tx_db_inuse[j])
ReleaseDB(aup, aup->tx_db_inuse[j]);
- }
- dma_free_noncoherent(NULL,
- MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS),
- (void *)aup->vaddr,
- aup->dma_addr);
+ dma_free_noncoherent(NULL, MAX_BUF_SIZE *
+ (NUM_TX_BUFFS + NUM_RX_BUFFS),
+ (void *)aup->vaddr, aup->dma_addr);
+ release_mem_region(dev->base_addr, MAC_IOSIZE);
+ release_mem_region(CPHYSADDR(iflist[i].macen_addr), 4);
free_netdev(dev);
- release_mem_region(CPHYSADDR(iflist[i].base_addr), MAC_IOSIZE);
}
}
}
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH] au1000_eth.c Power Management, driver registration and module support
2006-04-19 18:46 ` [PATCH] au1000_eth.c probe code straightened up Sergei Shtylyov
@ 2006-05-02 15:09 ` Rodolfo Giometti
2006-05-03 7:47 ` Rodolfo Giometti
2006-05-31 15:01 ` Sergei Shtylyov
0 siblings, 2 replies; 11+ messages in thread
From: Rodolfo Giometti @ 2006-05-02 15:09 UTC (permalink / raw)
To: Sergei Shtylyov; +Cc: jgarzik, netdev, Linux-MIPS
[-- Attachment #1: Type: text/plain, Size: 1492 bytes --]
Hello,
here:
http://ftp.enneenne.com/pub/misc/au1100-patches/linux/patch-au1000_eth-pm-and-registration
the new version of my patch for au1000_eth.c who should implement:
* Module support.
- bool "MIPS AU1000 Ethernet support"
+ tristate "MIPS AU1000 Ethernet support"
* Driver registration.
+static int __init au1000_eth_init(void)
+{
+ return driver_register(&au1000_driver);
+}
+
+static void __exit au1000_eth_cleanup(void)
+{
+ driver_unregister(&au1000_driver);
+}
* Power Management.
+#ifdef CONFIG_PM
+ .suspend = au1000_drv_suspend,
+ .resume = au1000_drv_resume,
+#endif
Also, as suggested by Sergei it:
* uses physical addresses and not KSEG1-based virtual anymore and
claims/releases the 4-byte MAC enable registers:
wwpc:~# cat /proc/iomem
10500000-1050ffff : eth-base
10520000-10520003 : eth-mac
* assigns to the Ethernet ports two consecutive MAC addresses:
- dev->dev_addr[4] += 0x10;
+ ((unsigned long) macen_addr);
+ memcpy(ndev->dev_addr, au1000_mac_addr, sizeof(au1000_mac_addr));
+ ndev->dev_addr[5] += 0x01;
Ciao,
Rodolfo
--
GNU/Linux Solutions e-mail: giometti@enneenne.com
Linux Device Driver giometti@gnudd.com
Embedded Systems giometti@linux.it
UNIX programming phone: +39 349 2432127
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] au1000_eth.c Power Management, driver registration and module support
2006-05-02 15:09 ` [PATCH] au1000_eth.c Power Management, driver registration and module support Rodolfo Giometti
@ 2006-05-03 7:47 ` Rodolfo Giometti
2006-05-31 15:01 ` Sergei Shtylyov
1 sibling, 0 replies; 11+ messages in thread
From: Rodolfo Giometti @ 2006-05-03 7:47 UTC (permalink / raw)
To: Sergei Shtylyov; +Cc: jgarzik, netdev, Linux-MIPS
[-- Attachment #1: Type: text/plain, Size: 467 bytes --]
Hello,
yesterday I did a little mess with GIT... now the patch is
complete. Sorry. :)
I forgot also to say that it has been done against
«linux-2.6.16-stable» branch.
Ciao,
Rodolfo
--
GNU/Linux Solutions e-mail: giometti@enneenne.com
Linux Device Driver giometti@gnudd.com
Embedded Systems giometti@linux.it
UNIX programming phone: +39 349 2432127
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] au1000_eth.c Power Management, driver registration and module support
2006-05-02 15:09 ` [PATCH] au1000_eth.c Power Management, driver registration and module support Rodolfo Giometti
2006-05-03 7:47 ` Rodolfo Giometti
@ 2006-05-31 15:01 ` Sergei Shtylyov
2006-05-31 15:21 ` Rodolfo Giometti
1 sibling, 1 reply; 11+ messages in thread
From: Sergei Shtylyov @ 2006-05-31 15:01 UTC (permalink / raw)
To: Rodolfo Giometti; +Cc: jgarzik, netdev, Linux-MIPS, Jordan Crouse
Hello.
Rodolfo Giometti wrote:
> here:
> http://ftp.enneenne.com/pub/misc/au1100-patches/linux/patch-au1000_eth-pm-and-registration
> the new version of my patch for au1000_eth.c who should implement:
> Also, as suggested by Sergei it:
>
> * uses physical addresses and not KSEG1-based virtual anymore and
> claims/releases the 4-byte MAC enable registers:
>
> wwpc:~# cat /proc/iomem
> 10500000-1050ffff : eth-base
> 10520000-10520003 : eth-mac
>
> * assigns to the Ethernet ports two consecutive MAC addresses:
>
> - dev->dev_addr[4] += 0x10;
> + ((unsigned long) macen_addr);
> + memcpy(ndev->dev_addr, au1000_mac_addr, sizeof(au1000_mac_addr));
> + ndev->dev_addr[5] += 0x01;
>
> Ciao,
Now that this is merged, Rodolfo's patch should probably preempt mine...
but it looks like something was lost during the transition: I failed to see
where SYS_PINFUNC register is actually read (the comment mentioning this was
retained :-) to check whether Ethernet port 1 is enabled (its pins are shared
w/GPIO)...
> Rodolfo
WBR, Sergei
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] au1000_eth.c Power Management, driver registration and module support
2006-05-31 15:01 ` Sergei Shtylyov
@ 2006-05-31 15:21 ` Rodolfo Giometti
0 siblings, 0 replies; 11+ messages in thread
From: Rodolfo Giometti @ 2006-05-31 15:21 UTC (permalink / raw)
To: Sergei Shtylyov; +Cc: jgarzik, netdev, Linux-MIPS, Jordan Crouse
[-- Attachment #1: Type: text/plain, Size: 1337 bytes --]
On Wed, May 31, 2006 at 07:01:02PM +0400, Sergei Shtylyov wrote:
>
> Now that this is merged, Rodolfo's patch should probably preempt mine...
> but it looks like something was lost during the transition: I failed to see
> where SYS_PINFUNC register is actually read (the comment mentioning this
> was retained :-) to check whether Ethernet port 1 is enabled (its pins are
> shared w/GPIO)...
You are right! Maybe something like this may fix the problem:
diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c
index 341fdc4..8a6427e 100644
--- a/drivers/net/au1000_eth.c
+++ b/drivers/net/au1000_eth.c
@@ -2149,6 +2149,9 @@ static int au1000_drv_probe(struct devic
void *base_addr, *macen_addr;
int irq, ret;
+ if (pdev->id == 1 && (au_readl(SYS_PINFUNC) & SYS_PF_NI2) != 0)
+ return -ENODEV;
+
/* Get the resource info */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "eth-base");
if (!res) {
Ciao,
Rodolfo
--
GNU/Linux Solutions e-mail: giometti@enneenne.com
Linux Device Driver giometti@gnudd.com
Embedded Systems giometti@linux.it
UNIX programming phone: +39 349 2432127
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2006-05-31 15:21 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-04-05 15:47 Power management for au1000_eth.c Rodolfo Giometti
2006-04-05 22:23 ` Rodolfo Giometti
2006-04-05 22:26 ` [PATCH] Oops! - " Rodolfo Giometti
2006-04-06 14:43 ` Sergei Shtylyov
2006-04-06 15:50 ` Rodolfo Giometti
2006-04-19 18:46 ` [PATCH] au1000_eth.c probe code straightened up Sergei Shtylyov
2006-05-02 15:09 ` [PATCH] au1000_eth.c Power Management, driver registration and module support Rodolfo Giometti
2006-05-03 7:47 ` Rodolfo Giometti
2006-05-31 15:01 ` Sergei Shtylyov
2006-05-31 15:21 ` Rodolfo Giometti
2006-04-06 17:10 ` Oops! - Re: Power management for au1000_eth.c Jordan Crouse
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.