From 6b50d038e7c668eb60b18c2fba8982a22e36527e Mon Sep 17 00:00:00 2001 From: Andrew Ruder Date: Wed, 4 Jun 2014 17:28:44 -0500 Subject: [PATCH 1/6] dm9000: acquire irq flags from device tree The DM9000 supports both active high interrupts and active low interrupts. This is configured via the attached EEPROM. In the device-tree case, make sure that the DM9000 driver passes the correct flags to request_irq. Signed-off-by: Andrew Ruder Signed-off-by: David S. Miller --- drivers/net/ethernet/davicom/dm9000.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/davicom/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c index 8c4b93be333bc..1bdf69985c13f 100644 --- a/drivers/net/ethernet/davicom/dm9000.c +++ b/drivers/net/ethernet/davicom/dm9000.c @@ -1291,6 +1291,9 @@ dm9000_open(struct net_device *dev) /* If there is no IRQ type specified, default to something that * 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"); From 751bb6fd80b728d4820e0176837bc2c5e339e358 Mon Sep 17 00:00:00 2001 From: Andrew Ruder Date: Wed, 4 Jun 2014 17:28:45 -0500 Subject: [PATCH 2/6] dm9000: clean up reset code * Change a hard-coded 0x3 to NCR_RST | NCR_MAC_LBK in dm9000_reset * Every single place where dm9000_init_dm9000 was ran, a dm9000_reset was called immediately before-hand. Bring dm9000_reset into dm9000_init_dm9000. * The following commit updated the dm9000_probe reset routine to use NCR_RST | NCR_MAC_LBK: 6741f40 DM9000B: driver initialization upgrade and a later commit added a bug-fix to always reset the chip twice: 09ee9f8 dm9000: Implement full reset of DM9000 network device Unfortunately, since the changes in 6741f40 were made by replacing the dm9000_probe dm9000_reset with the adjusted iow(), the changes in 09ee9f8 were not incorporated into the dm9000_probe reset. Furthermore, it bypassed the requisite reset-delay causing some boards to get at least one "read wrong id ..." dev_err message during dm9000_probe. Signed-off-by: Andrew Ruder Signed-off-by: David S. Miller --- drivers/net/ethernet/davicom/dm9000.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/davicom/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c index 1bdf69985c13f..a10671ecbf815 100644 --- a/drivers/net/ethernet/davicom/dm9000.c +++ b/drivers/net/ethernet/davicom/dm9000.c @@ -187,13 +187,13 @@ dm9000_reset(board_info_t *db) * 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, 0x03); + 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, 0x03); + 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"); @@ -894,6 +894,8 @@ dm9000_init_dm9000(struct net_device *dev) dm9000_dbg(db, 1, "entering %s\n", __func__); + dm9000_reset(db); + /* I/O mode */ db->io_mode = ior(db, DM9000_ISR) >> 6; /* ISR bit7:6 keeps I/O mode */ @@ -962,7 +964,6 @@ static void dm9000_timeout(struct net_device *dev) reg_save = readb(db->io_addr); netif_stop_queue(dev); - dm9000_reset(db); dm9000_init_dm9000(dev); /* We can accept TX packets again */ dev->trans_start = jiffies; /* prevent tx timeout */ @@ -1304,7 +1305,6 @@ 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)) @@ -1550,12 +1550,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++) { @@ -1698,7 +1693,6 @@ 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); } From 17ad78de7f60bfc9711acb57c3c9561def6ee402 Mon Sep 17 00:00:00 2001 From: Andrew Ruder Date: Wed, 4 Jun 2014 17:28:46 -0500 Subject: [PATCH 3/6] dm9000: clean up edge-triggered irq compatibility DM9000 uses level-triggered interrupts. Some systems (PXA270) only support edge-triggered interrupts on GPIOs. Some changes are necessary to ensure that interrupts are not triggered while the GPIO interrupt is masked or we will miss the interrupt forever. * Make some helper functions called dm9000_mask_interrupts() and dm9000_unmask_interrupts() for readability. * dm9000_init_dm9000(): ensure that this function always leaves interrupts masked regardless of the state when it entered the function. This is primarily to support the situation in dm9000_open where the logic used to go: dm9000_open() dm9000_init_dm9000() unmask interrupts request_irq() If an interrupt occurred between unmasking the interrupt and requesting the irq, it would be missed forever as the edge event would never be seen by the GPIO hardware in the PXA270. This allows us to change the logic to: dm9000_open() dm9000_init_dm9000() dm9000_mask_interrupts() request_irq() dm9000_unmask_interrupts() * dm9000_timeout(), dm9000_drv_resume(): Add the missing dm9000_unmask_interrupts() now required by the change above. * dm9000_shutdown(): Use mask helper function * dm9000_interrupt(): Use mask/unmask helper functions Signed-off-by: Andrew Ruder Signed-off-by: David S. Miller --- drivers/net/ethernet/davicom/dm9000.c | 32 ++++++++++++++++++--------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/davicom/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c index a10671ecbf815..a34f9fcc39927 100644 --- a/drivers/net/ethernet/davicom/dm9000.c +++ b/drivers/net/ethernet/davicom/dm9000.c @@ -882,6 +882,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 */ @@ -895,6 +907,7 @@ 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 */ @@ -943,9 +956,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; @@ -965,6 +975,7 @@ static void dm9000_timeout(struct net_device *dev) netif_stop_queue(dev); 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); @@ -1194,9 +1205,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 */ @@ -1219,9 +1228,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); @@ -1309,6 +1316,10 @@ dm9000_open(struct net_device *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; @@ -1329,7 +1340,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 */ } @@ -1694,6 +1705,7 @@ dm9000_drv_resume(struct device *dev) * the device was powered off it is in a known state */ if (!db->wake_state) { dm9000_init_dm9000(ndev); + dm9000_unmask_interrupts(db); } netif_device_attach(ndev); From 36259012a4ba34d70d4fe0e8533980919e8b6024 Mon Sep 17 00:00:00 2001 From: Andrew Ruder Date: Wed, 4 Jun 2014 17:28:47 -0500 Subject: [PATCH 4/6] dm9000: remove redundant ISR status clear Since dm9000_interrupt() is already reading/clearing every set bit in DM9000_ISR, this additional clear in dm9000_rx() (which is only called by dm9000_interrupt()) is unnecessary and can be removed. Signed-off-by: Andrew Ruder Signed-off-by: David S. Miller --- drivers/net/ethernet/davicom/dm9000.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/davicom/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c index a34f9fcc39927..a86755f7824e6 100644 --- a/drivers/net/ethernet/davicom/dm9000.c +++ b/drivers/net/ethernet/davicom/dm9000.c @@ -1105,7 +1105,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; } From aac6d02280e61bc30302024ffd7541e0951a2cf6 Mon Sep 17 00:00:00 2001 From: Andrew Ruder Date: Wed, 4 Jun 2014 17:28:48 -0500 Subject: [PATCH 5/6] dm9000: handle initial link status On the DM9000A/DM9000B force the initial check of the link status. The DM9000A/B has a link status changed event and this interrupt bit isn't always set out of reset when a cable is plugged in. This results in the driver not seeing the cable attached link status until the cable is removed and plugged in again. Signed-off-by: Andrew Ruder Signed-off-by: David S. Miller --- drivers/net/ethernet/davicom/dm9000.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/davicom/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c index a86755f7824e6..48870a8b39a42 100644 --- a/drivers/net/ethernet/davicom/dm9000.c +++ b/drivers/net/ethernet/davicom/dm9000.c @@ -1326,7 +1326,8 @@ dm9000_open(struct net_device *dev) 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; } From 582379839bbdb76f2f0ad956a39f920cfd84fcea Mon Sep 17 00:00:00 2001 From: Andrew Ruder Date: Wed, 4 Jun 2014 17:28:49 -0500 Subject: [PATCH 6/6] dm9000: avoid sleeping in dm9000_timeout callback On the DM9000B, dm9000_msleep() is called during the dm9000_timeout() routine. Since dm9000_timeout() holds the main spinlock through the entire routine, mdelay() needs to be used rather than msleep(). Furthermore, the mutex_lock()/mutex_unlock() should be avoided so as to not sleep with spinlocks held. Signed-off-by: Andrew Ruder Signed-off-by: David S. Miller --- drivers/net/ethernet/davicom/dm9000.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/davicom/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c index 48870a8b39a42..13723c96d1a27 100644 --- a/drivers/net/ethernet/davicom/dm9000.c +++ b/drivers/net/ethernet/davicom/dm9000.c @@ -109,6 +109,7 @@ typedef struct board_info { u8 imr_all; unsigned int flags; + unsigned int in_timeout:1; unsigned int in_suspend:1; unsigned int wake_supported:1; @@ -273,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); @@ -334,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); @@ -365,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 @@ -971,6 +974,7 @@ 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); @@ -982,6 +986,7 @@ static void dm9000_timeout(struct net_device *dev) /* Restore previous register address */ writeb(reg_save, db->io_addr); + db->in_timeout = 0; spin_unlock_irqrestore(&db->lock, flags); }