Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bd2302c2 authored by Florian Fainelli's avatar Florian Fainelli Committed by Ralf Baechle
Browse files

NET: au1000-eth: Convert to platform_driver model



This patch converts the au1000-eth driver to become a full platform-driver
as it ought to be. We now pass PHY-speficic configurations through
platform_data but for compatibility the driver still assumes the default
settings (search for PHY1 on MAC0) when no platform_data is passed. Tested
on my MTX-1 board.

Signed-off-by: default avatarFlorian Fainelli <florian@openwrt.org>
Cc: linux-mips@linux-mips.org
Cc: netdev@vger.kernel.org
Acked-by: default avatarDavid S. Miller <davem@davemloft.net>
Patchwork: http://patchwork.linux-mips.org/patch/619/
Patchwork: http://patchwork.linux-mips.org/patch/963/


Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
parent 66f75ccb
Loading
Loading
Loading
Loading
+223 −218
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@
#include <linux/delay.h>
#include <linux/crc32.h>
#include <linux/phy.h>
#include <linux/platform_device.h>

#include <asm/cpu.h>
#include <asm/mipsregs.h>
@@ -63,6 +64,7 @@
#include <asm/processor.h>

#include <au1000.h>
#include <au1xxx_eth.h>
#include <prom.h>

#include "au1000_eth.h"
@@ -112,15 +114,15 @@ struct au1000_private *au_macs[NUM_ETH_INTERFACES];
 *
 * PHY detection algorithm
 *
 * If AU1XXX_PHY_STATIC_CONFIG is undefined, the PHY setup is
 * If phy_static_config is undefined, the PHY setup is
 * autodetected:
 *
 * mii_probe() first searches the current MAC's MII bus for a PHY,
 * selecting the first (or last, if AU1XXX_PHY_SEARCH_HIGHEST_ADDR is
 * selecting the first (or last, if phy_search_highest_addr is
 * defined) PHY address not already claimed by another netdev.
 *
 * If nothing was found that way when searching for the 2nd ethernet
 * controller's PHY and AU1XXX_PHY1_SEARCH_ON_MAC0 is defined, then
 * controller's PHY and phy1_search_mac0 is defined, then
 * the first MII bus is searched as well for an unclaimed PHY; this is
 * needed in case of a dual-PHY accessible only through the MAC0's MII
 * bus.
@@ -129,9 +131,7 @@ struct au1000_private *au_macs[NUM_ETH_INTERFACES];
 * controller is not registered to the network subsystem.
 */

/* autodetection defaults */
#undef  AU1XXX_PHY_SEARCH_HIGHEST_ADDR
#define AU1XXX_PHY1_SEARCH_ON_MAC0
/* autodetection defaults: phy1_search_mac0 */

/* static PHY setup
 *
@@ -148,29 +148,6 @@ struct au1000_private *au_macs[NUM_ETH_INTERFACES];
 * specific irq-map
 */

#if defined(CONFIG_MIPS_BOSPORUS)
/*
 * Micrel/Kendin 5 port switch attached to MAC0,
 * MAC0 is associated with PHY address 5 (== WAN port)
 * MAC1 is not associated with any PHY, since it's connected directly
 * to the switch.
 * no interrupts are used
 */
# define AU1XXX_PHY_STATIC_CONFIG

# define AU1XXX_PHY0_ADDR  5
# define AU1XXX_PHY0_BUSID 0
#  undef AU1XXX_PHY0_IRQ

#  undef AU1XXX_PHY1_ADDR
#  undef AU1XXX_PHY1_BUSID
#  undef AU1XXX_PHY1_IRQ
#endif

#if defined(AU1XXX_PHY0_BUSID) && (AU1XXX_PHY0_BUSID > 0)
# error MAC0-associated PHY attached 2nd MACs MII bus not supported yet
#endif

static void enable_mac(struct net_device *dev, int force_reset)
{
	unsigned long flags;
@@ -390,53 +367,41 @@ static int mii_probe (struct net_device *dev)
	struct au1000_private *const aup = netdev_priv(dev);
	struct phy_device *phydev = NULL;

#if defined(AU1XXX_PHY_STATIC_CONFIG)
	if (aup->phy_static_config) {
		BUG_ON(aup->mac_id < 0 || aup->mac_id > 1);

	if(aup->mac_id == 0) { /* get PHY0 */
# if defined(AU1XXX_PHY0_ADDR)
		phydev = au_macs[AU1XXX_PHY0_BUSID]->mii_bus->phy_map[AU1XXX_PHY0_ADDR];
# else
		printk (KERN_INFO DRV_NAME ":%s: using PHY-less setup\n",
			dev->name);
		return 0;
# endif /* defined(AU1XXX_PHY0_ADDR) */
	} else if (aup->mac_id == 1) { /* get PHY1 */
# if defined(AU1XXX_PHY1_ADDR)
		phydev = au_macs[AU1XXX_PHY1_BUSID]->mii_bus->phy_map[AU1XXX_PHY1_ADDR];
# else
		if (aup->phy_addr)
			phydev = aup->mii_bus->phy_map[aup->phy_addr];
		else
			printk (KERN_INFO DRV_NAME ":%s: using PHY-less setup\n",
				dev->name);
		return 0;
# endif /* defined(AU1XXX_PHY1_ADDR) */
	}

#else /* defined(AU1XXX_PHY_STATIC_CONFIG) */
	} else {
		int phy_addr;

		/* find the first (lowest address) PHY on the current MAC's MII bus */
		for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++)
			if (aup->mii_bus->phy_map[phy_addr]) {
				phydev = aup->mii_bus->phy_map[phy_addr];
# if !defined(AU1XXX_PHY_SEARCH_HIGHEST_ADDR)
				if (!aup->phy_search_highest_addr)
					break; /* break out with first one found */
# endif
			}

# if defined(AU1XXX_PHY1_SEARCH_ON_MAC0)
		if (aup->phy1_search_mac0) {
			/* try harder to find a PHY */
			if (!phydev && (aup->mac_id == 1)) {
				/* no PHY found, maybe we have a dual PHY? */
				printk (KERN_INFO DRV_NAME ": no PHY found on MAC1, "
					"let's see if it's attached to MAC0...\n");

		BUG_ON(!au_macs[0]);

				/* find the first (lowest address) non-attached PHY on
				 * the MAC0 MII bus */
				for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
					struct phy_device *const tmp_phydev =
				au_macs[0]->mii_bus->phy_map[phy_addr];
							aup->mii_bus->phy_map[phy_addr];

					if (aup->mac_id == 1)
						break;

					if (!tmp_phydev)
						continue; /* no PHY here... */
@@ -448,9 +413,9 @@ static int mii_probe (struct net_device *dev)
					break; /* found it */
				}
			}
# endif /* defined(AU1XXX_PHY1_SEARCH_OTHER_BUS) */
		}
	}

#endif /* defined(AU1XXX_PHY_STATIC_CONFIG) */
	if (!phydev) {
		printk (KERN_ERR DRV_NAME ":%s: no PHY found\n", dev->name);
		return -1;
@@ -578,31 +543,6 @@ setup_hw_rings(struct au1000_private *aup, u32 rx_base, u32 tx_base)
	}
}

static struct {
	u32 base_addr;
	u32 macen_addr;
	int irq;
	struct net_device *dev;
} 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;

/*
 * ethtool operations
 */
@@ -711,7 +651,6 @@ static int au1000_init(struct net_device *dev)

static inline void update_rx_stats(struct net_device *dev, u32 status)
{
	struct au1000_private *aup = netdev_priv(dev);
	struct net_device_stats *ps = &dev->stats;

	ps->rx_packets++;
@@ -969,7 +908,7 @@ static netdev_tx_t au1000_tx(struct sk_buff *skb, struct net_device *dev)
	}

	pDB = aup->tx_db_inuse[aup->tx_head];
	skb_copy_from_linear_data(skb, pDB->vaddr, skb->len);
	skb_copy_from_linear_data(skb, (void *)pDB->vaddr, skb->len);
	if (skb->len < ETH_ZLEN) {
		for (i=skb->len; i<ETH_ZLEN; i++) {
			((char *)pDB->vaddr)[i] = 0;
@@ -1058,53 +997,59 @@ static const struct net_device_ops au1000_netdev_ops = {
	.ndo_change_mtu		= eth_change_mtu,
};

static struct net_device * au1000_probe(int port_num)
static int __devinit au1000_probe(struct platform_device *pdev)
{
	static unsigned version_printed = 0;
	struct au1000_private *aup = NULL;
	struct au1000_eth_platform_data *pd;
	struct net_device *dev = NULL;
	db_dest_t *pDB, *pDBfree;
	int irq, i, err = 0;
	struct resource *base, *macen;
	char ethaddr[6];
	int irq, i, err;
	u32 base, macen;

	if (port_num >= NUM_ETH_INTERFACES)
		return NULL;
	base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!base) {
		printk(KERN_ERR DRV_NAME ": failed to retrieve base register\n");
		err = -ENODEV;
		goto out;
	}

	base  = CPHYSADDR(iflist[port_num].base_addr );
	macen = CPHYSADDR(iflist[port_num].macen_addr);
	irq = iflist[port_num].irq;
	macen = platform_get_resource(pdev, IORESOURCE_MEM, 1);
	if (!macen) {
		printk(KERN_ERR DRV_NAME ": failed to retrieve MAC Enable register\n");
		err = -ENODEV;
		goto out;
	}

	if (!request_mem_region( base, MAC_IOSIZE, "Au1x00 ENET") ||
	    !request_mem_region(macen, 4, "Au1x00 ENET"))
		return NULL;
	irq = platform_get_irq(pdev, 0);
	if (irq < 0) {
		printk(KERN_ERR DRV_NAME ": failed to retrieve IRQ\n");
		err = -ENODEV;
		goto out;
	}

	if (version_printed++ == 0)
		printk("%s version %s %s\n", DRV_NAME, DRV_VERSION, DRV_AUTHOR);
	if (!request_mem_region(base->start, resource_size(base), pdev->name)) {
		printk(KERN_ERR DRV_NAME ": failed to request memory region for base registers\n");
		err = -ENXIO;
		goto out;
	}

	if (!request_mem_region(macen->start, resource_size(macen), pdev->name)) {
		printk(KERN_ERR DRV_NAME ": failed to request memory region for MAC enable register\n");
		err = -ENXIO;
		goto err_request;
	}

	dev = alloc_etherdev(sizeof(struct au1000_private));
	if (!dev) {
		printk(KERN_ERR "%s: alloc_etherdev failed\n", DRV_NAME);
		return NULL;
		err = -ENOMEM;
		goto err_alloc;
	}

	dev->base_addr = base;
	dev->irq = irq;
	dev->netdev_ops = &au1000_netdev_ops;
	SET_ETHTOOL_OPS(dev, &au1000_ethtool_ops);
	dev->watchdog_timeo = ETH_TX_TIMEOUT;

	err = register_netdev(dev);
	if (err != 0) {
		printk(KERN_ERR "%s: Cannot register net device, error %d\n",
				DRV_NAME, err);
		free_netdev(dev);
		return NULL;
	}

	printk("%s: Au1xx0 Ethernet found at 0x%x, irq %d\n",
		dev->name, base, irq);

	SET_NETDEV_DEV(dev, &pdev->dev);
	platform_set_drvdata(pdev, dev);
	aup = netdev_priv(dev);

	spin_lock_init(&aup->lock);
@@ -1115,21 +1060,29 @@ static struct net_device * au1000_probe(int port_num)
						(NUM_TX_BUFFS + NUM_RX_BUFFS),
						&aup->dma_addr,	0);
	if (!aup->vaddr) {
		free_netdev(dev);
		release_mem_region( base, MAC_IOSIZE);
		release_mem_region(macen, 4);
		return NULL;
		printk(KERN_ERR DRV_NAME ": failed to allocate data buffers\n");
		err = -ENOMEM;
		goto err_vaddr;
	}

	/* aup->mac is the base address of the MAC's registers */
	aup->mac = (volatile mac_reg_t *)iflist[port_num].base_addr;
	aup->mac = (volatile mac_reg_t *)ioremap_nocache(base->start, resource_size(base));
	if (!aup->mac) {
		printk(KERN_ERR DRV_NAME ": failed to ioremap MAC registers\n");
		err = -ENXIO;
		goto err_remap1;
	}

        /* Setup some variables for quick register address access */
	aup->enable = (volatile u32 *)iflist[port_num].macen_addr;
	aup->mac_id = port_num;
	au_macs[port_num] = aup;
	aup->enable = (volatile u32 *)ioremap_nocache(macen->start, resource_size(macen));
	if (!aup->enable) {
		printk(KERN_ERR DRV_NAME ": failed to ioremap MAC enable register\n");
		err = -ENXIO;
		goto err_remap2;
	}
	aup->mac_id = pdev->id;

	if (port_num == 0) {
	if (pdev->id == 0) {
		if (prom_get_ethernet_addr(ethaddr) == 0)
			memcpy(au1000_mac_addr, ethaddr, sizeof(au1000_mac_addr));
		else {
@@ -1139,7 +1092,7 @@ static struct net_device * au1000_probe(int port_num)
		}

		setup_hw_rings(aup, MAC0_RX_DMA_ADDR, MAC0_TX_DMA_ADDR);
	} else if (port_num == 1)
	} else if (pdev->id == 1)
		setup_hw_rings(aup, MAC1_RX_DMA_ADDR, MAC1_TX_DMA_ADDR);

	/*
@@ -1147,14 +1100,37 @@ static struct net_device * au1000_probe(int port_num)
	 * 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;
	dev->dev_addr[5] += pdev->id;

	*aup->enable = 0;
	aup->mac_enabled = 0;

	pd = pdev->dev.platform_data;
	if (!pd) {
		printk(KERN_INFO DRV_NAME ": no platform_data passed, PHY search on MAC0\n");
		aup->phy1_search_mac0 = 1;
	} else {
		aup->phy_static_config = pd->phy_static_config;
		aup->phy_search_highest_addr = pd->phy_search_highest_addr;
		aup->phy1_search_mac0 = pd->phy1_search_mac0;
		aup->phy_addr = pd->phy_addr;
		aup->phy_busid = pd->phy_busid;
		aup->phy_irq = pd->phy_irq;
	}

	if (aup->phy_busid && aup->phy_busid > 0) {
		printk(KERN_ERR DRV_NAME ": MAC0-associated PHY attached 2nd MACs MII"
				"bus not supported yet\n");
		err = -ENODEV;
		goto err_mdiobus_alloc;
	}

	aup->mii_bus = mdiobus_alloc();
	if (aup->mii_bus == NULL)
		goto err_out;
	if (aup->mii_bus == NULL) {
		printk(KERN_ERR DRV_NAME ": failed to allocate mdiobus structure\n");
		err = -ENOMEM;
		goto err_mdiobus_alloc;
	}

	aup->mii_bus->priv = dev;
	aup->mii_bus->read = au1000_mdiobus_read;
@@ -1168,24 +1144,20 @@ static struct net_device * au1000_probe(int port_num)

	for(i = 0; i < PHY_MAX_ADDR; ++i)
		aup->mii_bus->irq[i] = PHY_POLL;

	/* if known, set corresponding PHY IRQs */
#if defined(AU1XXX_PHY_STATIC_CONFIG)
# if defined(AU1XXX_PHY0_IRQ)
	if (AU1XXX_PHY0_BUSID == aup->mac_id)
		aup->mii_bus->irq[AU1XXX_PHY0_ADDR] = AU1XXX_PHY0_IRQ;
# endif
# if defined(AU1XXX_PHY1_IRQ)
	if (AU1XXX_PHY1_BUSID == aup->mac_id)
		aup->mii_bus->irq[AU1XXX_PHY1_ADDR] = AU1XXX_PHY1_IRQ;
# endif
#endif
	mdiobus_register(aup->mii_bus);
	if (aup->phy_static_config)
		if (aup->phy_irq && aup->phy_busid == aup->mac_id)
			aup->mii_bus->irq[aup->phy_addr] = aup->phy_irq;

	if (mii_probe(dev) != 0) {
		goto err_out;
	err = mdiobus_register(aup->mii_bus);
	if (err) {
		printk(KERN_ERR DRV_NAME " failed to register MDIO bus\n");
		goto err_mdiobus_reg;
	}

	if (mii_probe(dev) != 0)
		goto err_out;

	pDBfree = NULL;
	/* setup the data buffer descriptors and attach a buffer to each one */
	pDB = aup->db;
@@ -1216,19 +1188,35 @@ static struct net_device * au1000_probe(int port_num)
		aup->tx_db_inuse[i] = pDB;
	}

	dev->base_addr = base->start;
	dev->irq = irq;
	dev->netdev_ops = &au1000_netdev_ops;
	SET_ETHTOOL_OPS(dev, &au1000_ethtool_ops);
	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 dev;
	err = register_netdev(dev);
	if (err) {
		printk(KERN_ERR DRV_NAME "%s: Cannot register net device, aborting.\n",
					dev->name);
		goto err_out;
	}

	printk("%s: Au1xx0 Ethernet found at 0x%lx, irq %d\n",
			dev->name, (unsigned long)base->start, irq);
	if (version_printed++ == 0)
		printk("%s version %s %s\n", DRV_NAME, DRV_VERSION, DRV_AUTHOR);

	return 0;

err_out:
	if (aup->mii_bus != NULL) {
	if (aup->mii_bus != NULL)
		mdiobus_unregister(aup->mii_bus);
		mdiobus_free(aup->mii_bus);
	}

	/* here we should have a valid dev plus aup-> register addresses
	 * so we can reset the mac properly.*/
@@ -1242,67 +1230,84 @@ static struct net_device * au1000_probe(int port_num)
		if (aup->tx_db_inuse[i])
			ReleaseDB(aup, aup->tx_db_inuse[i]);
	}
err_mdiobus_reg:
	mdiobus_free(aup->mii_bus);
err_mdiobus_alloc:
	iounmap(aup->enable);
err_remap2:
	iounmap(aup->mac);
err_remap1:
	dma_free_noncoherent(NULL, MAX_BUF_SIZE * (NUM_TX_BUFFS + NUM_RX_BUFFS),
			     (void *)aup->vaddr, aup->dma_addr);
	unregister_netdev(dev);
err_vaddr:
	free_netdev(dev);
	release_mem_region( base, MAC_IOSIZE);
	release_mem_region(macen, 4);
	return NULL;
err_alloc:
	release_mem_region(macen->start, resource_size(macen));
err_request:
	release_mem_region(base->start, resource_size(base));
out:
	return err;
}

/*
 * Setup the base address and interrupt 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)
static int __devexit au1000_remove(struct platform_device *pdev)
{
	int ni = (int)((au_readl(SYS_PINFUNC) & (u32)(SYS_PF_NI2)) >> 4);
	struct net_device *dev;
	int i, found_one = 0;

	num_ifs = NUM_ETH_INTERFACES - ni;

	for(i = 0; i < num_ifs; i++) {
		dev = au1000_probe(i);
		iflist[i].dev = dev;
		if (dev)
			found_one++;
	}
	if (!found_one)
		return -ENODEV;
	return 0;
}
	struct net_device *dev = platform_get_drvdata(pdev);
	struct au1000_private *aup = netdev_priv(dev);
	int i;
	struct resource *base, *macen;

static void __exit au1000_cleanup_module(void)
{
	int i, j;
	struct net_device *dev;
	struct au1000_private *aup;
	platform_set_drvdata(pdev, NULL);

	for (i = 0; i < num_ifs; i++) {
		dev = iflist[i].dev;
		if (dev) {
			aup = netdev_priv(dev);
	unregister_netdev(dev);
	mdiobus_unregister(aup->mii_bus);
	mdiobus_free(aup->mii_bus);
			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]);

	for (i = 0; i < NUM_RX_DMA; i++)
		if (aup->rx_db_inuse[i])
			ReleaseDB(aup, aup->rx_db_inuse[i]);

	for (i = 0; i < NUM_TX_DMA; i++)
		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);
			release_mem_region(dev->base_addr, MAC_IOSIZE);
			release_mem_region(CPHYSADDR(iflist[i].macen_addr), 4);

	iounmap(aup->mac);
	iounmap(aup->enable);

	base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	release_mem_region(base->start, resource_size(base));

	macen = platform_get_resource(pdev, IORESOURCE_MEM, 1);
	release_mem_region(macen->start, resource_size(macen));

	free_netdev(dev);

	return 0;
}

static struct platform_driver au1000_eth_driver = {
	.probe  = au1000_probe,
	.remove = __devexit_p(au1000_remove),
	.driver = {
		.name   = "au1000-eth",
		.owner  = THIS_MODULE,
	},
};
MODULE_ALIAS("platform:au1000-eth");


static int __init au1000_init_module(void)
{
	return platform_driver_register(&au1000_eth_driver);
}

static void __exit au1000_exit_module(void)
{
	platform_driver_unregister(&au1000_eth_driver);
}

module_init(au1000_init_module);
module_exit(au1000_cleanup_module);
module_exit(au1000_exit_module);
+9 −0
Original line number Diff line number Diff line
@@ -108,6 +108,15 @@ struct au1000_private {
	struct phy_device *phy_dev;
	struct mii_bus *mii_bus;

	/* PHY configuration */
	int phy_static_config;
	int phy_search_highest_addr;
	int phy1_search_mac0;

	int phy_addr;
	int phy_busid;
	int phy_irq;

	/* These variables are just for quick access to certain regs addresses. */
	volatile mac_reg_t *mac;  /* mac registers                      */
	volatile u32 *enable;     /* address of MAC Enable Register     */