diff options
Diffstat (limited to 'drivers/net/ethernet/davicom')
| -rw-r--r-- | drivers/net/ethernet/davicom/Kconfig | 3 | ||||
| -rw-r--r-- | drivers/net/ethernet/davicom/dm9000.c | 256 |
2 files changed, 154 insertions, 105 deletions
diff --git a/drivers/net/ethernet/davicom/Kconfig b/drivers/net/ethernet/davicom/Kconfig index 972b62b3183..316c5e5a92a 100644 --- a/drivers/net/ethernet/davicom/Kconfig +++ b/drivers/net/ethernet/davicom/Kconfig @@ -4,9 +4,8 @@ config DM9000 tristate "DM9000 support" - depends on ARM || BLACKFIN || MIPS + depends on ARM || BLACKFIN || MIPS || COLDFIRE select CRC32 - select NET_CORE select MII ---help--- Support for DM9000 chipset. diff --git a/drivers/net/ethernet/davicom/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c index 2f2e98baeca..13723c96d1a 100644 --- a/drivers/net/ethernet/davicom/dm9000.c +++ b/drivers/net/ethernet/davicom/dm9000.c @@ -23,12 +23,13 @@ #include <linux/ioport.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> -#include <linux/init.h> #include <linux/interrupt.h> #include <linux/skbuff.h> #include <linux/spinlock.h> #include <linux/crc32.h> #include <linux/mii.h> +#include <linux/of.h> +#include <linux/of_net.h> #include <linux/ethtool.h> #include <linux/dm9000.h> #include <linux/delay.h> @@ -108,8 +109,9 @@ typedef struct board_info { u8 imr_all; unsigned int flags; - unsigned int in_suspend :1; - unsigned int wake_supported :1; + unsigned int in_timeout:1; + unsigned int in_suspend:1; + unsigned int wake_supported:1; enum dm9000_type type; @@ -156,23 +158,11 @@ static inline board_info_t *to_dm9000_board(struct net_device *dev) /* DM9000 network board routine ---------------------------- */ -static void -dm9000_reset(board_info_t * db) -{ - dev_dbg(db->dev, "resetting device\n"); - - /* RESET device */ - writeb(DM9000_NCR, db->io_addr); - udelay(200); - writeb(NCR_RST, db->io_data); - udelay(200); -} - /* * Read a byte from I/O port */ static u8 -ior(board_info_t * db, int reg) +ior(board_info_t *db, int reg) { writeb(reg, db->io_addr); return readb(db->io_data); @@ -183,45 +173,66 @@ ior(board_info_t * db, int reg) */ static void -iow(board_info_t * db, int reg, int value) +iow(board_info_t *db, int reg, int value) { writeb(reg, db->io_addr); writeb(value, db->io_data); } +static void +dm9000_reset(board_info_t *db) +{ + dev_dbg(db->dev, "resetting device\n"); + + /* Reset DM9000, see DM9000 Application Notes V1.22 Jun 11, 2004 page 29 + * The essential point is that we have to do a double reset, and the + * instruction is to set LBK into MAC internal loopback mode. + */ + iow(db, DM9000_NCR, NCR_RST | NCR_MAC_LBK); + udelay(100); /* Application note says at least 20 us */ + if (ior(db, DM9000_NCR) & 1) + dev_err(db->dev, "dm9000 did not respond to first reset\n"); + + iow(db, DM9000_NCR, 0); + iow(db, DM9000_NCR, NCR_RST | NCR_MAC_LBK); + udelay(100); + if (ior(db, DM9000_NCR) & 1) + dev_err(db->dev, "dm9000 did not respond to second reset\n"); +} + /* routines for sending block to chip */ static void dm9000_outblk_8bit(void __iomem *reg, void *data, int count) { - writesb(reg, data, count); + iowrite8_rep(reg, data, count); } static void dm9000_outblk_16bit(void __iomem *reg, void *data, int count) { - writesw(reg, data, (count+1) >> 1); + iowrite16_rep(reg, data, (count+1) >> 1); } static void dm9000_outblk_32bit(void __iomem *reg, void *data, int count) { - writesl(reg, data, (count+3) >> 2); + iowrite32_rep(reg, data, (count+3) >> 2); } /* input block from chip to memory */ static void dm9000_inblk_8bit(void __iomem *reg, void *data, int count) { - readsb(reg, data, count); + ioread8_rep(reg, data, count); } static void dm9000_inblk_16bit(void __iomem *reg, void *data, int count) { - readsw(reg, data, (count+1) >> 1); + ioread16_rep(reg, data, (count+1) >> 1); } static void dm9000_inblk_32bit(void __iomem *reg, void *data, int count) { - readsl(reg, data, (count+3) >> 2); + ioread32_rep(reg, data, (count+3) >> 2); } /* dump block from chip to null */ @@ -263,7 +274,7 @@ static void dm9000_dumpblk_32bit(void __iomem *reg, int count) */ static void dm9000_msleep(board_info_t *db, unsigned int ms) { - if (db->in_suspend) + if (db->in_suspend || db->in_timeout) mdelay(ms); else msleep(ms); @@ -324,7 +335,8 @@ dm9000_phy_write(struct net_device *dev, unsigned long reg_save; dm9000_dbg(db, 5, "phy_write[%02x] = %04x\n", reg, value); - mutex_lock(&db->addr_lock); + if (!db->in_timeout) + mutex_lock(&db->addr_lock); spin_lock_irqsave(&db->lock, flags); @@ -355,7 +367,8 @@ dm9000_phy_write(struct net_device *dev, writeb(reg_save, db->io_addr); spin_unlock_irqrestore(&db->lock, flags); - mutex_unlock(&db->addr_lock); + if (!db->in_timeout) + mutex_unlock(&db->addr_lock); } /* dm9000_set_io @@ -535,9 +548,10 @@ static void dm9000_get_drvinfo(struct net_device *dev, { board_info_t *dm = to_dm9000_board(dev); - strcpy(info->driver, CARDNAME); - strcpy(info->version, DRV_VERSION); - strcpy(info->bus_info, to_platform_device(dm->dev)->name); + strlcpy(info->driver, CARDNAME, sizeof(info->driver)); + strlcpy(info->version, DRV_VERSION, sizeof(info->version)); + strlcpy(info->bus_info, to_platform_device(dm->dev)->name, + sizeof(info->bus_info)); } static u32 dm9000_get_msglevel(struct net_device *dev) @@ -575,10 +589,11 @@ static int dm9000_nway_reset(struct net_device *dev) return mii_nway_restart(&dm->mii); } -static int dm9000_set_features(struct net_device *dev, u32 features) +static int dm9000_set_features(struct net_device *dev, + netdev_features_t features) { board_info_t *dm = to_dm9000_board(dev); - u32 changed = dev->features ^ features; + netdev_features_t changed = dev->features ^ features; unsigned long flags; if (!(changed & NETIF_F_RXCSUM)) @@ -732,23 +747,28 @@ static const struct ethtool_ops dm9000_ethtool_ops = { .get_link = dm9000_get_link, .get_wol = dm9000_get_wol, .set_wol = dm9000_set_wol, - .get_eeprom_len = dm9000_get_eeprom_len, - .get_eeprom = dm9000_get_eeprom, - .set_eeprom = dm9000_set_eeprom, + .get_eeprom_len = dm9000_get_eeprom_len, + .get_eeprom = dm9000_get_eeprom, + .set_eeprom = dm9000_set_eeprom, }; static void dm9000_show_carrier(board_info_t *db, unsigned carrier, unsigned nsr) { + int lpa; struct net_device *ndev = db->ndev; + struct mii_if_info *mii = &db->mii; unsigned ncr = dm9000_read_locked(db, DM9000_NCR); - if (carrier) - dev_info(db->dev, "%s: link up, %dMbps, %s-duplex, no LPA\n", + if (carrier) { + lpa = mii->mdio_read(mii->dev, mii->phy_id, MII_LPA); + dev_info(db->dev, + "%s: link up, %dMbps, %s-duplex, lpa 0x%04X\n", ndev->name, (nsr & NSR_SPEED) ? 10 : 100, - (ncr & NCR_FDX) ? "full" : "half"); - else + (ncr & NCR_FDX) ? "full" : "half", lpa); + } else { dev_info(db->dev, "%s: link down\n", ndev->name); + } } static void @@ -777,7 +797,7 @@ dm9000_poll_work(struct work_struct *w) } } else mii_check_media(&db->mii, netif_msg_link(db), 0); - + if (netif_running(ndev)) dm9000_schedule_poll(db); } @@ -825,7 +845,7 @@ dm9000_hash_table_unlocked(struct net_device *dev) struct netdev_hw_addr *ha; int i, oft; u32 hash_val; - u16 hash_table[4]; + u16 hash_table[4] = { 0, 0, 0, 0x8000 }; /* broadcast address */ u8 rcr = RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN; dm9000_dbg(db, 1, "entering %s\n", __func__); @@ -833,13 +853,6 @@ dm9000_hash_table_unlocked(struct net_device *dev) for (i = 0, oft = DM9000_PAR; i < 6; i++, oft++) iow(db, oft, dev->dev_addr[i]); - /* Clear Hash Table */ - for (i = 0; i < 4; i++) - hash_table[i] = 0x0; - - /* broadcast address */ - hash_table[3] = 0x8000; - if (dev->flags & IFF_PROMISC) rcr |= RCR_PRMSC; @@ -872,6 +885,18 @@ dm9000_hash_table(struct net_device *dev) spin_unlock_irqrestore(&db->lock, flags); } +static void +dm9000_mask_interrupts(board_info_t *db) +{ + iow(db, DM9000_IMR, IMR_PAR); +} + +static void +dm9000_unmask_interrupts(board_info_t *db) +{ + iow(db, DM9000_IMR, db->imr_all); +} + /* * Initialize dm9000 board */ @@ -884,6 +909,9 @@ dm9000_init_dm9000(struct net_device *dev) dm9000_dbg(db, 1, "entering %s\n", __func__); + dm9000_reset(db); + dm9000_mask_interrupts(db); + /* I/O mode */ db->io_mode = ior(db, DM9000_ISR) >> 6; /* ISR bit7:6 keeps I/O mode */ @@ -893,9 +921,15 @@ dm9000_init_dm9000(struct net_device *dev) (dev->features & NETIF_F_RXCSUM) ? RCSR_CSUM : 0); iow(db, DM9000_GPCR, GPCR_GEP_CNTL); /* Let GPIO0 output */ + iow(db, DM9000_GPR, 0); - dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET); /* PHY RESET */ - dm9000_phy_write(dev, 0, MII_DM_DSPCR, DSPCR_INIT_PARAM); /* Init */ + /* If we are dealing with DM9000B, some extra steps are required: a + * manual phy reset, and setting init params. + */ + if (db->type == TYPE_DM9000B) { + dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET); + dm9000_phy_write(dev, 0, MII_DM_DSPCR, DSPCR_INIT_PARAM); + } ncr = (db->flags & DM9000_PLATF_EXT_PHY) ? NCR_EXT_PHY : 0; @@ -925,9 +959,6 @@ dm9000_init_dm9000(struct net_device *dev) db->imr_all = imr; - /* Enable TX/RX interrupt mask */ - iow(db, DM9000_IMR, imr); - /* Init Driver variable */ db->tx_pkt_cnt = 0; db->queue_pkt_len = 0; @@ -943,17 +974,19 @@ static void dm9000_timeout(struct net_device *dev) /* Save previous register address */ spin_lock_irqsave(&db->lock, flags); + db->in_timeout = 1; reg_save = readb(db->io_addr); netif_stop_queue(dev); - dm9000_reset(db); dm9000_init_dm9000(dev); + dm9000_unmask_interrupts(db); /* We can accept TX packets again */ dev->trans_start = jiffies; /* prevent tx timeout */ netif_wake_queue(dev); /* Restore previous register address */ writeb(reg_save, db->io_addr); + db->in_timeout = 0; spin_unlock_irqrestore(&db->lock, flags); } @@ -1017,7 +1050,7 @@ dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&db->lock, flags); /* free this SKB */ - dev_kfree_skb(skb); + dev_consume_skb_any(skb); return NETDEV_TX_OK; } @@ -1077,7 +1110,6 @@ dm9000_rx(struct net_device *dev) if (rxbyte & DM9000_PKT_ERR) { dev_warn(db->dev, "status check fail: %d\n", rxbyte); iow(db, DM9000_RCR, 0x00); /* Stop Device */ - iow(db, DM9000_ISR, IMR_PAR); /* Stop INT request */ return; } @@ -1131,7 +1163,7 @@ dm9000_rx(struct net_device *dev) /* Move data from DM9000 */ if (GoodPacket && - ((skb = dev_alloc_skb(RxLen + 4)) != NULL)) { + ((skb = netdev_alloc_skb(dev, RxLen + 4)) != NULL)) { skb_reserve(skb, 2); rdptr = (u8 *) skb_put(skb, RxLen - 4); @@ -1177,9 +1209,7 @@ static irqreturn_t dm9000_interrupt(int irq, void *dev_id) /* Save previous register address */ reg_save = readb(db->io_addr); - /* Disable all interrupts */ - iow(db, DM9000_IMR, IMR_PAR); - + dm9000_mask_interrupts(db); /* Got DM9000 interrupt status */ int_status = ior(db, DM9000_ISR); /* Got ISR */ iow(db, DM9000_ISR, int_status); /* Clear ISR status */ @@ -1202,9 +1232,7 @@ static irqreturn_t dm9000_interrupt(int irq, void *dev_id) } } - /* Re-enable interrupt mask */ - iow(db, DM9000_IMR, db->imr_all); - + dm9000_unmask_interrupts(db); /* Restore previous register address */ writeb(reg_save, db->io_addr); @@ -1235,12 +1263,11 @@ static irqreturn_t dm9000_wol_interrupt(int irq, void *dev_id) dev_info(db->dev, "wake by link status change\n"); if (wcr & WCR_SAMPLEST) dev_info(db->dev, "wake by sample packet\n"); - if (wcr & WCR_MAGICST ) + if (wcr & WCR_MAGICST) dev_info(db->dev, "wake by magic packet\n"); if (!(wcr & (WCR_LINKST | WCR_SAMPLEST | WCR_MAGICST))) dev_err(db->dev, "wake signalled with no reason? " "NSR=0x%02x, WSR=0x%02x\n", nsr, wcr); - } spin_unlock_irqrestore(&db->lock, flags); @@ -1277,6 +1304,9 @@ dm9000_open(struct net_device *dev) * may work, and tell the user that this is a problem */ if (irqflags == IRQF_TRIGGER_NONE) + irqflags = irq_get_trigger_type(dev->irq); + + if (irqflags == IRQF_TRIGGER_NONE) dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n"); irqflags |= IRQF_SHARED; @@ -1286,19 +1316,23 @@ dm9000_open(struct net_device *dev) mdelay(1); /* delay needs by DM9000B */ /* Initialize DM9000 board */ - dm9000_reset(db); dm9000_init_dm9000(dev); if (request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev)) return -EAGAIN; + /* Now that we have an interrupt handler hooked up we can unmask + * our interrupts + */ + dm9000_unmask_interrupts(db); /* Init driver variable */ db->dbug_cnt = 0; mii_check_media(&db->mii, netif_msg_link(db), 1); netif_start_queue(dev); - - dm9000_schedule_poll(db); + + /* Poll initial link status */ + schedule_delayed_work(&db->phy_poll, 1); return 0; } @@ -1311,7 +1345,7 @@ dm9000_shutdown(struct net_device *dev) /* RESET device */ dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET); /* PHY RESET */ iow(db, DM9000_GPR, 0x01); /* Power-Down PHY */ - iow(db, DM9000_IMR, IMR_PAR); /* Disable all interrupt */ + dm9000_mask_interrupts(db); iow(db, DM9000_RCR, 0x00); /* Disable RX */ } @@ -1356,13 +1390,38 @@ static const struct net_device_ops dm9000_netdev_ops = { #endif }; +static struct dm9000_plat_data *dm9000_parse_dt(struct device *dev) +{ + struct dm9000_plat_data *pdata; + struct device_node *np = dev->of_node; + const void *mac_addr; + + if (!IS_ENABLED(CONFIG_OF) || !np) + return NULL; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return ERR_PTR(-ENOMEM); + + if (of_find_property(np, "davicom,ext-phy", NULL)) + pdata->flags |= DM9000_PLATF_EXT_PHY; + if (of_find_property(np, "davicom,no-eeprom", NULL)) + pdata->flags |= DM9000_PLATF_NO_EEPROM; + + mac_addr = of_get_mac_address(np); + if (mac_addr) + memcpy(pdata->dev_addr, mac_addr, sizeof(pdata->dev_addr)); + + return pdata; +} + /* * Search DM9000 board, allocate space and register it */ -static int __devinit +static int dm9000_probe(struct platform_device *pdev) { - struct dm9000_plat_data *pdata = pdev->dev.platform_data; + struct dm9000_plat_data *pdata = dev_get_platdata(&pdev->dev); struct board_info *db; /* Point a board information structure */ struct net_device *ndev; const unsigned char *mac_src; @@ -1371,12 +1430,16 @@ dm9000_probe(struct platform_device *pdev) int i; u32 id_val; + if (!pdata) { + pdata = dm9000_parse_dt(&pdev->dev); + if (IS_ERR(pdata)) + return PTR_ERR(pdata); + } + /* Init network device */ ndev = alloc_etherdev(sizeof(struct board_info)); - if (!ndev) { - dev_err(&pdev->dev, "could not allocate device.\n"); + if (!ndev) return -ENOMEM; - } SET_NETDEV_DEV(ndev, &pdev->dev); @@ -1503,12 +1566,7 @@ dm9000_probe(struct platform_device *pdev) db->flags |= DM9000_PLATF_SIMPLE_PHY; #endif - /* Fixing bug on dm9000_probe, takeover dm9000_reset(db), - * Need 'NCR_MAC_LBK' bit to indeed stable our DM9000 fifo - * while probe stage. - */ - - iow(db, DM9000_NCR, NCR_MAC_LBK | NCR_RST); + dm9000_reset(db); /* try multiple times, DM9000 sometimes gets the read wrong */ for (i = 0; i < 8; i++) { @@ -1577,12 +1635,12 @@ dm9000_probe(struct platform_device *pdev) if (!is_valid_ether_addr(ndev->dev_addr) && pdata != NULL) { mac_src = "platform data"; - memcpy(ndev->dev_addr, pdata->dev_addr, 6); + memcpy(ndev->dev_addr, pdata->dev_addr, ETH_ALEN); } if (!is_valid_ether_addr(ndev->dev_addr)) { /* try reading from mac */ - + mac_src = "chip"; for (i = 0; i < 6; i++) ndev->dev_addr[i] = ior(db, i+DM9000_PAR); @@ -1592,7 +1650,7 @@ dm9000_probe(struct platform_device *pdev) dev_warn(db->dev, "%s: Invalid ethernet MAC address. Please " "set using ifconfig\n", ndev->name); - random_ether_addr(ndev->dev_addr); + eth_hw_addr_random(ndev); mac_src = "random"; } @@ -1651,8 +1709,8 @@ dm9000_drv_resume(struct device *dev) /* reset if we were not in wake mode to ensure if * the device was powered off it is in a known state */ if (!db->wake_state) { - dm9000_reset(db); dm9000_init_dm9000(ndev); + dm9000_unmask_interrupts(db); } netif_device_attach(ndev); @@ -1668,13 +1726,11 @@ static const struct dev_pm_ops dm9000_drv_pm_ops = { .resume = dm9000_drv_resume, }; -static int __devexit +static int dm9000_drv_remove(struct platform_device *pdev) { struct net_device *ndev = platform_get_drvdata(pdev); - platform_set_drvdata(pdev, NULL); - unregister_netdev(ndev); dm9000_release_board(pdev, netdev_priv(ndev)); free_netdev(ndev); /* free device structure */ @@ -1683,32 +1739,26 @@ dm9000_drv_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_OF +static const struct of_device_id dm9000_of_matches[] = { + { .compatible = "davicom,dm9000", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, dm9000_of_matches); +#endif + static struct platform_driver dm9000_driver = { .driver = { .name = "dm9000", .owner = THIS_MODULE, .pm = &dm9000_drv_pm_ops, + .of_match_table = of_match_ptr(dm9000_of_matches), }, .probe = dm9000_probe, - .remove = __devexit_p(dm9000_drv_remove), + .remove = dm9000_drv_remove, }; -static int __init -dm9000_init(void) -{ - printk(KERN_INFO "%s Ethernet Driver, V%s\n", CARDNAME, DRV_VERSION); - - return platform_driver_register(&dm9000_driver); -} - -static void __exit -dm9000_cleanup(void) -{ - platform_driver_unregister(&dm9000_driver); -} - -module_init(dm9000_init); -module_exit(dm9000_cleanup); +module_platform_driver(dm9000_driver); MODULE_AUTHOR("Sascha Hauer, Ben Dooks"); MODULE_DESCRIPTION("Davicom DM9000 network driver"); |
