X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=drivers%2Fnet%2Fdm9000.c;h=909822a6fd39ccf3bac6de4df80f0a31893de8db;hb=5d8d8603d606063c40c605e5c8dc30b0fd7afb12;hp=31b8bef49d2e1a15323634f29b72b8453815b0e8;hpb=9eead2a8115d2a6aecf267c292f751f7761fa5f8;p=firefly-linux-kernel-4.4.55.git diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index 31b8bef49d2e..909822a6fd39 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -37,6 +37,8 @@ #include #include #include +#include +#include #include "dm9000.h" @@ -103,6 +105,12 @@ typedef struct board_info { int debug_level; enum dm9000_type type; + +#ifdef CONFIG_DM9000_USE_NAND_CONTROL + void *dev_id; + struct work_struct dm9k_work; + struct workqueue_struct *dm9000_wq; +#endif void (*inblk)(void __iomem *port, void *data, int length); void (*outblk)(void __iomem *port, void *data, int length); @@ -132,7 +140,6 @@ typedef struct board_info { } board_info_t; /* debug code */ - #define dm9000_dbg(db, lev, msg...) do { \ if ((lev) < CONFIG_DM9000_DEBUGLEVEL && \ (lev) < db->debug_level) { \ @@ -140,6 +147,16 @@ typedef struct board_info { } \ } while (0) +#if defined(CONFIG_DM9000_USE_NAND_CONTROL) && defined(CONFIG_MTD_NAND_RK2818) +extern void rk2818_nand_status_mutex_lock(void); +extern int rk2818_nand_status_mutex_trylock(void); +extern void rk2818_nand_status_mutex_unlock(void); +#else +static void rk2818_nand_status_mutex_lock(void){return;} +static int rk2818_nand_status_mutex_trylock(void) {return 1;} +static void rk2818_nand_status_mutex_unlock(void) {return;} +#endif + static inline board_info_t *to_dm9000_board(struct net_device *dev) { return netdev_priv(dev); @@ -306,11 +323,15 @@ dm9000_read_locked(board_info_t *db, int reg) { unsigned long flags; unsigned int ret; + + rk2818_nand_status_mutex_lock(); - spin_lock_irqsave(&db->lock, flags); + spin_lock_irqsave(&db->lock, flags); ret = ior(db, reg); spin_unlock_irqrestore(&db->lock, flags); + rk2818_nand_status_mutex_unlock(); + return ret; } @@ -362,21 +383,27 @@ dm9000_read_eeprom(board_info_t *db, int offset, u8 *to) } mutex_lock(&db->addr_lock); + + rk2818_nand_status_mutex_lock(); spin_lock_irqsave(&db->lock, flags); - + iow(db, DM9000_EPAR, offset); iow(db, DM9000_EPCR, EPCR_ERPRR); spin_unlock_irqrestore(&db->lock, flags); + rk2818_nand_status_mutex_unlock(); + dm9000_wait_eeprom(db); /* delay for at-least 150uS */ msleep(1); + + rk2818_nand_status_mutex_lock(); spin_lock_irqsave(&db->lock, flags); - + iow(db, DM9000_EPCR, 0x0); to[0] = ior(db, DM9000_EPDRL); @@ -384,6 +411,8 @@ dm9000_read_eeprom(board_info_t *db, int offset, u8 *to) spin_unlock_irqrestore(&db->lock, flags); + rk2818_nand_status_mutex_unlock(); + mutex_unlock(&db->addr_lock); } @@ -399,22 +428,30 @@ dm9000_write_eeprom(board_info_t *db, int offset, u8 *data) return; mutex_lock(&db->addr_lock); + + rk2818_nand_status_mutex_lock(); - spin_lock_irqsave(&db->lock, flags); + spin_lock_irqsave(&db->lock, flags); iow(db, DM9000_EPAR, offset); iow(db, DM9000_EPDRH, data[1]); iow(db, DM9000_EPDRL, data[0]); iow(db, DM9000_EPCR, EPCR_WEP | EPCR_ERPRW); spin_unlock_irqrestore(&db->lock, flags); + rk2818_nand_status_mutex_unlock(); + dm9000_wait_eeprom(db); mdelay(1); /* wait at least 150uS to clear */ + + rk2818_nand_status_mutex_lock(); spin_lock_irqsave(&db->lock, flags); iow(db, DM9000_EPCR, 0); spin_unlock_irqrestore(&db->lock, flags); + rk2818_nand_status_mutex_unlock(); + mutex_unlock(&db->addr_lock); } @@ -479,9 +516,12 @@ static int dm9000_set_rx_csum(struct net_device *dev, uint32_t data) if (dm->can_csum) { dm->rx_csum = data; + rk2818_nand_status_mutex_lock(); + spin_lock_irqsave(&dm->lock, flags); iow(dm, DM9000_RCSR, dm->rx_csum ? RCSR_CSUM : 0); spin_unlock_irqrestore(&dm->lock, flags); + rk2818_nand_status_mutex_unlock(); return 0; } @@ -679,9 +719,11 @@ dm9000_hash_table(struct net_device *dev) unsigned long flags; dm9000_dbg(db, 1, "entering %s\n", __func__); + + rk2818_nand_status_mutex_lock(); spin_lock_irqsave(&db->lock, flags); - + for (i = 0, oft = DM9000_PAR; i < 6; i++, oft++) iow(db, oft, dev->dev_addr[i]); @@ -712,6 +754,8 @@ dm9000_hash_table(struct net_device *dev) iow(db, DM9000_RCR, rcr); spin_unlock_irqrestore(&db->lock, flags); + + rk2818_nand_status_mutex_unlock(); } /* @@ -775,6 +819,9 @@ static void dm9000_timeout(struct net_device *dev) /* Save previous register address */ reg_save = readb(db->io_addr); + + rk2818_nand_status_mutex_lock(); + spin_lock_irqsave(&db->lock, flags); netif_stop_queue(dev); @@ -787,6 +834,8 @@ static void dm9000_timeout(struct net_device *dev) /* Restore previous register address */ writeb(reg_save, db->io_addr); spin_unlock_irqrestore(&db->lock, flags); + + rk2818_nand_status_mutex_unlock(); } static void dm9000_send_packet(struct net_device *dev, @@ -824,11 +873,17 @@ dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev) dm9000_dbg(db, 3, "%s:\n", __func__); - if (db->tx_pkt_cnt > 1) + if (db->tx_pkt_cnt > 1) { + dev_dbg(db->dev, "netdev tx busy\n"); return NETDEV_TX_BUSY; + } + if (!rk2818_nand_status_mutex_trylock()) { + dev_dbg(db->dev, "fun:%s, nand busy\n", __func__); + return NETDEV_TX_BUSY; + } spin_lock_irqsave(&db->lock, flags); - + /* Move data to DM9000 TX RAM */ writeb(DM9000_MWCMD, db->io_addr); @@ -847,6 +902,8 @@ dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev) } spin_unlock_irqrestore(&db->lock, flags); + + rk2818_nand_status_mutex_unlock(); /* free this SKB */ dev_kfree_skb(skb); @@ -902,14 +959,20 @@ dm9000_rx(struct net_device *dev) do { ior(db, DM9000_MRCMDX); /* Dummy read */ + udelay(1);//add by lyx@20100713,or dm9000_rx will be error in high frequence + /* Get most updated data */ rxbyte = readb(db->io_data); /* Status check: this byte must be 0 or 1 */ if (rxbyte & DM9000_PKT_ERR) { dev_warn(db->dev, "status check fail: %d\n", rxbyte); + #if 0 iow(db, DM9000_RCR, 0x00); /* Stop Device */ - iow(db, DM9000_ISR, IMR_PAR); /* Stop INT request */ + iow(db, DM9000_IMR, IMR_PAR); /* Stop INT request */ + #else + dm9000_reset(db); + #endif return; } @@ -991,6 +1054,81 @@ dm9000_rx(struct net_device *dev) } while (rxbyte & DM9000_PKT_RDY); } +#ifdef CONFIG_DM9000_USE_NAND_CONTROL +static void dm9000_interrupt_work(struct work_struct *work) +{ + board_info_t *db = container_of(work, board_info_t, dm9k_work); + struct net_device *dev = db->dev_id; + int int_status; + unsigned long flags; + u8 reg_save; + + //printk("entering %s\n", __FUNCTION__); + + /* A real interrupt coming */ + + /* holders of db->lock must always block IRQs */ + + rk2818_nand_status_mutex_lock(); + + spin_lock_irqsave(&db->lock, flags); + + /* Save previous register address */ + reg_save = readb(db->io_addr); + + /* Disable all interrupts */ + iow(db, DM9000_IMR, IMR_PAR); + + /* Got DM9000 interrupt status */ + int_status = ior(db, DM9000_ISR); /* Got ISR */ + iow(db, DM9000_ISR, int_status); /* Clear ISR status */ + + if (netif_msg_intr(db)) + dev_dbg(db->dev, "interrupt status %02x\n", int_status); + + /* Received the coming packet */ + if (int_status & ISR_PRS) + dm9000_rx(dev); + + /* Trnasmit Interrupt check */ + if (int_status & ISR_PTS) + dm9000_tx_done(dev, db); + + if (db->type != TYPE_DM9000E) { + if (int_status & ISR_LNKCHNG) { + /* fire a link-change request */ + schedule_delayed_work(&db->phy_poll, 1); + } + } + + /* Re-enable interrupt mask */ + iow(db, DM9000_IMR, db->imr_all); + + /* Restore previous register address */ + writeb(reg_save, db->io_addr); + + spin_unlock_irqrestore(&db->lock, flags); + + rk2818_nand_status_mutex_unlock(); + + enable_irq(dev->irq); + +} + +static irqreturn_t dm9000_interrupt(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + board_info_t *db = netdev_priv(dev); + + //printk("enter : %s\n", __FUNCTION__); + + db->dev_id = dev_id; + disable_irq_nosync(irq); + queue_work(db->dm9000_wq, &(db->dm9k_work)); + + return IRQ_HANDLED; +} +#else static irqreturn_t dm9000_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; @@ -1003,7 +1141,7 @@ static irqreturn_t dm9000_interrupt(int irq, void *dev_id) /* A real interrupt coming */ - /* holders of db->lock must always block IRQs */ + /* holders of db->lock must always block IRQs */ spin_lock_irqsave(&db->lock, flags); /* Save previous register address */ @@ -1041,9 +1179,10 @@ static irqreturn_t dm9000_interrupt(int irq, void *dev_id) writeb(reg_save, db->io_addr); spin_unlock_irqrestore(&db->lock, flags); - + return IRQ_HANDLED; } +#endif #ifdef CONFIG_NET_POLL_CONTROLLER /* @@ -1067,6 +1206,11 @@ dm9000_open(struct net_device *dev) board_info_t *db = netdev_priv(dev); unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK; + #ifdef CONFIG_DM9000_USE_NAND_CONTROL + db->dm9000_wq = create_workqueue("dm9000 wq"); + INIT_WORK(&(db->dm9k_work), dm9000_interrupt_work); + #endif + if (netif_msg_ifup(db)) dev_dbg(db->dev, "enabling %s\n", dev->name); @@ -1121,8 +1265,10 @@ dm9000_phy_read(struct net_device *dev, int phy_reg_unused, int reg) mutex_lock(&db->addr_lock); - spin_lock_irqsave(&db->lock,flags); + rk2818_nand_status_mutex_lock(); + spin_lock_irqsave(&db->lock,flags); + /* Save previous register address */ reg_save = readb(db->io_addr); @@ -1133,10 +1279,15 @@ dm9000_phy_read(struct net_device *dev, int phy_reg_unused, int reg) writeb(reg_save, db->io_addr); spin_unlock_irqrestore(&db->lock,flags); + + rk2818_nand_status_mutex_unlock(); dm9000_msleep(db, 1); /* Wait read complete */ + rk2818_nand_status_mutex_lock(); + spin_lock_irqsave(&db->lock,flags); + reg_save = readb(db->io_addr); iow(db, DM9000_EPCR, 0x0); /* Clear phyxcer read command */ @@ -1147,6 +1298,8 @@ dm9000_phy_read(struct net_device *dev, int phy_reg_unused, int reg) /* restore the previous address */ writeb(reg_save, db->io_addr); spin_unlock_irqrestore(&db->lock,flags); + + rk2818_nand_status_mutex_unlock(); mutex_unlock(&db->addr_lock); @@ -1168,8 +1321,10 @@ dm9000_phy_write(struct net_device *dev, dm9000_dbg(db, 5, "phy_write[%02x] = %04x\n", reg, value); mutex_lock(&db->addr_lock); - spin_lock_irqsave(&db->lock,flags); + rk2818_nand_status_mutex_lock(); + spin_lock_irqsave(&db->lock,flags); + /* Save previous register address */ reg_save = readb(db->io_addr); @@ -1184,10 +1339,15 @@ dm9000_phy_write(struct net_device *dev, writeb(reg_save, db->io_addr); spin_unlock_irqrestore(&db->lock, flags); + + rk2818_nand_status_mutex_unlock(); dm9000_msleep(db, 1); /* Wait write complete */ + rk2818_nand_status_mutex_lock(); + spin_lock_irqsave(&db->lock,flags); + reg_save = readb(db->io_addr); iow(db, DM9000_EPCR, 0x0); /* Clear phyxcer write command */ @@ -1196,6 +1356,8 @@ dm9000_phy_write(struct net_device *dev, writeb(reg_save, db->io_addr); spin_unlock_irqrestore(&db->lock, flags); + + rk2818_nand_status_mutex_unlock(); mutex_unlock(&db->addr_lock); } @@ -1233,6 +1395,10 @@ dm9000_stop(struct net_device *ndev) dm9000_shutdown(ndev); + #ifdef CONFIG_DM9000_USE_NAND_CONTROL + destroy_workqueue(db->dm9000_wq); + #endif + return 0; } @@ -1337,8 +1503,14 @@ dm9000_probe(struct platform_device *pdev) /* fill in parameters for net-dev structure */ ndev->base_addr = (unsigned long)db->io_addr; - ndev->irq = db->irq_res->start; + #if 0 + ndev->irq = db->irq_res->start; + #else//modify by liuyx@20100510 + rk2818_mux_api_set(GPIOE_SPI1_FLASH_SEL1_NAME, IOMUXA_GPIO1_A12); + ndev->irq = gpio_to_irq(db->irq_res->start); + #endif + /* ensure at least we have a default set of IO routines */ dm9000_set_io(db, iosize); @@ -1468,6 +1640,9 @@ dm9000_probe(struct platform_device *pdev) ndev->name, dm9000_type_to_char(db->type), db->io_addr, db->io_data, ndev->irq, ndev->dev_addr, mac_src); + + dm9000_shutdown(ndev);//add by lyx@20100713, reduce power consume + return 0; out: