Skip to content
Snippets Groups Projects
au1000_eth.c 32.7 KiB
Newer Older
		return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed

	if (!aup->phy_dev)
		return -EINVAL; /* PHY not controllable */
Linus Torvalds's avatar
Linus Torvalds committed

	return phy_mii_ioctl(aup->phy_dev, rq, cmd);
static const struct net_device_ops au1000_netdev_ops = {
	.ndo_open		= au1000_open,
	.ndo_stop		= au1000_close,
	.ndo_start_xmit		= au1000_tx,
	.ndo_set_multicast_list	= au1000_multicast_list,
	.ndo_do_ioctl		= au1000_ioctl,
	.ndo_tx_timeout		= au1000_tx_timeout,
	.ndo_set_mac_address	= eth_mac_addr,
	.ndo_validate_addr	= eth_validate_addr,
	.ndo_change_mtu		= eth_change_mtu,
};

static int __devinit au1000_probe(struct platform_device *pdev)
	static unsigned version_printed;
	struct au1000_private *aup = NULL;
	struct au1000_eth_platform_data *pd;
	struct net_device *dev = NULL;
	struct db_dest *pDB, *pDBfree;
	int irq, i, err = 0;
	struct resource *base, *macen;
	base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!base) {
		dev_err(&pdev->dev, "failed to retrieve base register\n");
	macen = platform_get_resource(pdev, IORESOURCE_MEM, 1);
	if (!macen) {
		dev_err(&pdev->dev, "failed to retrieve MAC Enable register\n");
	irq = platform_get_irq(pdev, 0);
	if (irq < 0) {
		dev_err(&pdev->dev, "failed to retrieve IRQ\n");
	if (!request_mem_region(base->start, resource_size(base),
							pdev->name)) {
		dev_err(&pdev->dev, "failed to request memory region for base registers\n");
	if (!request_mem_region(macen->start, resource_size(macen),
							pdev->name)) {
		dev_err(&pdev->dev, "failed to request memory region for MAC enable register\n");
		err = -ENXIO;
		goto err_request;
	}

	dev = alloc_etherdev(sizeof(struct au1000_private));
	if (!dev) {
		dev_err(&pdev->dev, "alloc_etherdev failed\n");
		err = -ENOMEM;
		goto err_alloc;
	SET_NETDEV_DEV(dev, &pdev->dev);
	platform_set_drvdata(pdev, dev);
	aup = netdev_priv(dev);

	spin_lock_init(&aup->lock);
	aup->msg_enable = (au1000_debug < 4 ?
				AU1000_DEF_MSG_ENABLE : au1000_debug);
	/* 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);
	if (!aup->vaddr) {
		dev_err(&pdev->dev, "failed to allocate data buffers\n");
		err = -ENOMEM;
		goto err_vaddr;
	}

	/* aup->mac is the base address of the MAC's registers */
	aup->mac = (struct mac_reg *)
			ioremap_nocache(base->start, resource_size(base));
		dev_err(&pdev->dev, "failed to ioremap MAC registers\n");
		err = -ENXIO;
		goto err_remap1;
	}
	/* Setup some variables for quick register address access */
	aup->enable = (u32 *)ioremap_nocache(macen->start,
		dev_err(&pdev->dev, "failed to ioremap MAC enable register\n");
		err = -ENXIO;
		goto err_remap2;
	}
	aup->mac_id = pdev->id;
		au1000_setup_hw_rings(aup, MAC0_RX_DMA_ADDR, MAC0_TX_DMA_ADDR);
		au1000_setup_hw_rings(aup, MAC1_RX_DMA_ADDR, MAC1_TX_DMA_ADDR);
	/* set a random MAC now in case platform_data doesn't provide one */
	random_ether_addr(dev->dev_addr);
	aup->mac_enabled = 0;

	pd = pdev->dev.platform_data;
	if (!pd) {
		dev_info(&pdev->dev, "no platform_data passed,"
					" PHY search on MAC0\n");
		aup->phy1_search_mac0 = 1;
	} else {
		if (is_valid_ether_addr(pd->mac))
			memcpy(dev->dev_addr, pd->mac, 6);

		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) {
		dev_err(&pdev->dev, "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) {
		dev_err(&pdev->dev, "failed to allocate mdiobus structure\n");
		err = -ENOMEM;
		goto err_mdiobus_alloc;
	}

	aup->mii_bus->priv = dev;
	aup->mii_bus->read = au1000_mdiobus_read;
	aup->mii_bus->write = au1000_mdiobus_write;
	aup->mii_bus->reset = au1000_mdiobus_reset;
	aup->mii_bus->name = "au1000_eth_mii";
	snprintf(aup->mii_bus->id, MII_BUS_ID_SIZE, "%x", aup->mac_id);
	aup->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
	for (i = 0; i < PHY_MAX_ADDR; ++i)
		aup->mii_bus->irq[i] = PHY_POLL;
	/* if known, set corresponding PHY IRQs */
	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;

	err = mdiobus_register(aup->mii_bus);
	if (err) {
		dev_err(&pdev->dev, "failed to register MDIO bus\n");
	if (au1000_mii_probe(dev) != 0)
		goto err_out;

	pDBfree = NULL;
	/* setup the data buffer descriptors and attach a buffer to each one */
	pDB = aup->db;
	for (i = 0; i < (NUM_TX_BUFFS+NUM_RX_BUFFS); i++) {
		pDB->pnext = pDBfree;
		pDBfree = pDB;
		pDB->vaddr = (u32 *)((unsigned)aup->vaddr + MAX_BUF_SIZE*i);
		pDB->dma_addr = (dma_addr_t)virt_to_bus(pDB->vaddr);
		pDB++;
	}
	aup->pDBfree = pDBfree;

	for (i = 0; i < NUM_RX_DMA; i++) {
		pDB = au1000_GetFreeDB(aup);
		if (!pDB)
			goto err_out;
		aup->rx_dma_ring[i]->buff_stat = (unsigned)pDB->dma_addr;
		aup->rx_db_inuse[i] = pDB;
	}
	for (i = 0; i < NUM_TX_DMA; i++) {
		pDB = au1000_GetFreeDB(aup);
		if (!pDB)
			goto err_out;
		aup->tx_dma_ring[i]->buff_stat = (unsigned)pDB->dma_addr;
		aup->tx_dma_ring[i]->len = 0;
		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.
	 */
	au1000_reset_mac(dev);
	err = register_netdev(dev);
	if (err) {
		netdev_err(dev, "Cannot register net device, aborting.\n");
	netdev_info(dev, "Au1xx0 Ethernet found at 0x%lx, irq %d\n",
			(unsigned long)base->start, irq);
	if (version_printed++ == 0)
		pr_info("%s version %s %s\n",
					DRV_NAME, DRV_VERSION, DRV_AUTHOR);
	if (aup->mii_bus != NULL)
		mdiobus_unregister(aup->mii_bus);

	/* here we should have a valid dev plus aup-> register addresses
	 * so we can reset the mac properly.
	 */
	au1000_reset_mac(dev);

	for (i = 0; i < NUM_RX_DMA; i++) {
		if (aup->rx_db_inuse[i])
			au1000_ReleaseDB(aup, aup->rx_db_inuse[i]);
	}
	for (i = 0; i < NUM_TX_DMA; i++) {
		if (aup->tx_db_inuse[i])
			au1000_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);
	free_netdev(dev);
err_alloc:
	release_mem_region(macen->start, resource_size(macen));
err_request:
	release_mem_region(base->start, resource_size(base));
out:
	return err;
static int __devexit au1000_remove(struct platform_device *pdev)
	struct net_device *dev = platform_get_drvdata(pdev);
	struct au1000_private *aup = netdev_priv(dev);
	int i;
	struct resource *base, *macen;
	platform_set_drvdata(pdev, NULL);

	unregister_netdev(dev);
	mdiobus_unregister(aup->mii_bus);
	mdiobus_free(aup->mii_bus);

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

	for (i = 0; i < NUM_TX_DMA; i++)
		if (aup->tx_db_inuse[i])
			au1000_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);

	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);
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);
Linus Torvalds's avatar
Linus Torvalds committed
module_init(au1000_init_module);
module_exit(au1000_exit_module);