// SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2014-2019 Nuvoton Technology corporation. #ifdef CONFIG_NPCM7XX_EMC_ETH_DEBUG #define DEBUG #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef CONFIG_DEBUG_FS static struct dentry *npcm7xx_fs_dir; #endif #define MFSEL1_OFFSET 0x00C #define MFSEL3_OFFSET 0x064 #define INTCR_OFFSET 0x03C #define IPSRST1_OFFSET 0x020 #define DRV_MODULE_NAME "npcm7xx-emc" #define DRV_MODULE_VERSION "3.90" /* Ethernet MAC Registers */ #define REG_CAMCMR 0x00 #define REG_CAMEN 0x04 #define REG_CAMM_BASE 0x08 #define REG_CAML_BASE 0x0c #define REG_TXDLSA 0x88 #define REG_RXDLSA 0x8C #define REG_MCMDR 0x90 #define REG_MIID 0x94 #define REG_MIIDA 0x98 #define REG_FFTCR 0x9C #define REG_TSDR 0xa0 #define REG_RSDR 0xa4 #define REG_DMARFC 0xa8 #define REG_MIEN 0xac #define REG_MISTA 0xb0 #define REG_MGSTA 0xb4 #define REG_MPCNT 0xb8 #define REG_MRPC 0xbc #define REG_MRPCC 0xc0 #define REG_MREPC 0xc4 #define REG_DMARFS 0xc8 #define REG_CTXDSA 0xcc #define REG_CTXBSA 0xd0 #define REG_CRXDSA 0xd4 #define REG_CRXBSA 0xd8 /* EMC Diagnostic Registers */ #define REG_RXFSM 0x200 #define REG_TXFSM 0x204 #define REG_FSM0 0x208 #define REG_FSM1 0x20c #define REG_DCR 0x210 #define REG_DMMIR 0x214 #define REG_BISTR 0x300 /* mac controller bit */ #define MCMDR_RXON BIT(0) #define MCMDR_ALP BIT(1) #define MCMDR_ACP BIT(3) #define MCMDR_SPCRC BIT(5) #define MCMDR_TXON BIT(8) #define MCMDR_NDEF BIT(9) #define MCMDR_FDUP BIT(18) #define MCMDR_ENMDC BIT(19) #define MCMDR_OPMOD BIT(20) #define SWR BIT(24) /* cam command regiser */ #define CAMCMR_AUP BIT(0) #define CAMCMR_AMP BIT(1) #define CAMCMR_ABP BIT(2) #define CAMCMR_CCAM BIT(3) #define CAMCMR_ECMP BIT(4) /* cam enable regiser */ #define CAM0EN BIT(0) /* mac mii controller bit */ #define PHYAD BIT(8) #define PHYWR BIT(16) #define PHYBUSY BIT(17) #define PHYPRESP BIT(18) #define MDCON BIT(19) #define CAM_ENTRY_SIZE 0x08 /* rx and tx status */ #define TXDS_TXCP BIT(19) #define RXDS_CRCE BIT(17) #define RXDS_PTLE BIT(19) #define RXDS_RXGD BIT(20) #define RXDS_ALIE BIT(21) #define RXDS_RP BIT(22) /* mac interrupt status*/ #define MISTA_RXINTR BIT(0) #define MISTA_CRCE BIT(1) #define MISTA_RXOV BIT(2) #define MISTA_PTLE BIT(3) #define MISTA_RXGD BIT(4) #define MISTA_ALIE BIT(5) #define MISTA_RP BIT(6) #define MISTA_MMP BIT(7) #define MISTA_DFOI BIT(8) #define MISTA_DENI BIT(9) #define MISTA_RDU BIT(10) #define MISTA_RXBERR BIT(11) #define MISTA_CFR BIT(14) #define MISTA_TXINTR BIT(16) #define MISTA_TXEMP BIT(17) #define MISTA_TXCP BIT(18) #define MISTA_EXDEF BIT(19) #define MISTA_NCS BIT(20) #define MISTA_TXABT BIT(21) #define MISTA_LC BIT(22) #define MISTA_TDU BIT(23) #define MISTA_TXBERR BIT(24) /* Transmit/Receive Start Demand Register */ #define ENSTART BIT(0) #define ENRXINTR BIT(0) #define ENCRCE BIT(1) #define EMRXOV BIT(2) #define ENPTLE BIT(3) #define ENRXGD BIT(4) #define ENALIE BIT(5) #define ENRP BIT(6) #define ENMMP BIT(7) #define ENDFO BIT(8) #define ENDENI BIT(9) #define ENRDU BIT(10) #define ENRXBERR BIT(11) #define ENCFR BIT(14) #define ENTXINTR BIT(16) #define ENTXEMP BIT(17) #define ENTXCP BIT(18) #define ENTXDEF BIT(19) #define ENNCS BIT(20) #define ENTXABT BIT(21) #define ENLC BIT(22) #define ENTDU BIT(23) #define ENTXBERR BIT(24) /* rx and tx owner bit */ #define RX_OWN_DMA BIT(31) #define TX_OWN_DMA BIT(31) /* tx frame desc controller bit */ #define MACTXINTEN BIT(2) #define CRCMODE BIT(1) #define PADDINGMODE BIT(0) /* fftcr controller bit */ #define RXTHD (0x03 << 0) #define TXTHD (0x02 << 8) #define BLENGTH (0x02 << 20) /* global setting for driver */ #define RX_QUEUE_LEN 128 #define TX_QUEUE_LEN 64 #define MAX_RBUFF_SZ 0x600 #define MAX_TBUFF_SZ 0x600 #define TX_TIMEOUT 50 #define DELAY 1000 #define CAM0 0x0 #define RX_POLL_SIZE 16 #ifdef CONFIG_VLAN_8021Q #define IS_VLAN 1 #else #define IS_VLAN 0 #endif #define MAX_PACKET_SIZE (1514 + (IS_VLAN * 4)) #define MAX_PACKET_SIZE_W_CRC (MAX_PACKET_SIZE + 4) /* 1518 */ #define MHZ (1000 * 1000) #define MII_TIMEOUT 100 struct plat_npcm7xx_emc_data { char *phy_bus_name; int phy_addr; unsigned char mac_addr[ETH_ALEN]; }; struct npcm7xx_rxbd { __le32 sl; __le32 buffer; __le32 reserved; __le32 next; }; struct npcm7xx_txbd { __le32 mode; /* Ownership bit and some other bits */ __le32 buffer; /* Transmit Buffer Starting Address */ __le32 sl; /* Transmit Byte Count and status bits */ __le32 next; /* Next Tx Descriptor Starting Address */ }; struct npcm7xx_ether { struct sk_buff *rx_skb[RX_QUEUE_LEN]; struct sk_buff *tx_skb[TX_QUEUE_LEN]; spinlock_t lock; /* lock sk */ struct npcm7xx_rxbd *rdesc; struct npcm7xx_txbd *tdesc; dma_addr_t rdesc_phys; dma_addr_t tdesc_phys; struct net_device_stats stats; struct platform_device *pdev; struct net_device *ndev; struct resource *res; unsigned int msg_enable; struct mii_bus *mii_bus; struct phy_device *phy_dev; struct napi_struct napi; struct ncsi_dev *ncsidev; bool use_ncsi; void __iomem *reg; int rxirq; int txirq; unsigned int cur_tx; unsigned int cur_rx; unsigned int finish_tx; unsigned int pending_tx; __le32 start_tx_ptr; __le32 start_rx_ptr; unsigned int rx_berr; unsigned int rx_err; unsigned int rdu; unsigned int rxov; __le32 camcmr; unsigned int rx_stuck; int link; int speed; int duplex; int need_reset; char *dump_buf; struct regmap *rst_regmap; /* debug counters */ unsigned int max_waiting_rx; unsigned int rx_count_pool; unsigned int count_xmit; unsigned int rx_int_count; unsigned int rx_err_count; unsigned int tx_int_count; unsigned int tx_tdu; unsigned int tx_tdu_i; unsigned int tx_cp_i; unsigned int count_finish; #ifdef CONFIG_DEBUG_FS struct dentry *dbgfs_dir; struct dentry *dbgfs_status; struct dentry *dbgfs_dma_cap; #endif }; #if defined CONFIG_NPCM7XX_EMC_ETH_DEBUG || defined CONFIG_DEBUG_FS #define REG_PRINT(reg_name) {t = scnprintf(next, size, "%-10s = %08X\n", \ #reg_name, readl(ether->reg + reg_name)); size -= t; next += t; } #define DUMP_PRINT(f, x...) {t = scnprintf(next, size, f, ## x); size -= t; \ next += t; } static int npcm7xx_info_dump(char *buf, int count, struct net_device *dev) { struct npcm7xx_ether *ether = netdev_priv(dev); struct npcm7xx_txbd *txbd; struct npcm7xx_rxbd *rxbd; unsigned long flags; unsigned int i, cur, txd_offset, rxd_offset; char *next = buf; unsigned int size = count; int t; int is_locked = spin_is_locked(ðer->lock); if (!is_locked) spin_lock_irqsave(ðer->lock, flags); /* ------basic driver information ---- */ DUMP_PRINT("NPCM7XX EMC %s driver version: %s\n", dev->name, DRV_MODULE_VERSION); REG_PRINT(REG_CAMCMR); REG_PRINT(REG_CAMEN); REG_PRINT(REG_CAMM_BASE); REG_PRINT(REG_CAML_BASE); REG_PRINT(REG_TXDLSA); REG_PRINT(REG_RXDLSA); REG_PRINT(REG_MCMDR); REG_PRINT(REG_MIID); REG_PRINT(REG_MIIDA); REG_PRINT(REG_FFTCR); REG_PRINT(REG_TSDR); REG_PRINT(REG_RSDR); REG_PRINT(REG_DMARFC); REG_PRINT(REG_MIEN); REG_PRINT(REG_MISTA); REG_PRINT(REG_MGSTA); REG_PRINT(REG_MPCNT); writel(0x7FFF, (ether->reg + REG_MPCNT)); REG_PRINT(REG_MRPC); REG_PRINT(REG_MRPCC); REG_PRINT(REG_MREPC); REG_PRINT(REG_DMARFS); REG_PRINT(REG_CTXDSA); REG_PRINT(REG_CTXBSA); REG_PRINT(REG_CRXDSA); REG_PRINT(REG_CRXBSA); REG_PRINT(REG_RXFSM); REG_PRINT(REG_TXFSM); REG_PRINT(REG_FSM0); REG_PRINT(REG_FSM1); REG_PRINT(REG_DCR); REG_PRINT(REG_DMMIR); REG_PRINT(REG_BISTR); DUMP_PRINT("\n"); DUMP_PRINT("netif_queue %s\n\n", netif_queue_stopped(dev) ? "Stopped" : "Running"); if (ether->rdesc) DUMP_PRINT("napi is %s\n\n", test_bit(NAPI_STATE_SCHED, ðer->napi.state) ? "scheduled" : "not scheduled"); txd_offset = (readl((ether->reg + REG_CTXDSA)) - readl((ether->reg + REG_TXDLSA))) / sizeof(struct npcm7xx_txbd); DUMP_PRINT("TXD offset %6d\n", txd_offset); DUMP_PRINT("cur_tx %6d\n", ether->cur_tx); DUMP_PRINT("finish_tx %6d\n", ether->finish_tx); DUMP_PRINT("pending_tx %6d\n", ether->pending_tx); /* debug counters */ DUMP_PRINT("tx_tdu %6d\n", ether->tx_tdu); ether->tx_tdu = 0; DUMP_PRINT("tx_tdu_i %6d\n", ether->tx_tdu_i); ether->tx_tdu_i = 0; DUMP_PRINT("tx_cp_i %6d\n", ether->tx_cp_i); ether->tx_cp_i = 0; DUMP_PRINT("tx_int_count %6d\n", ether->tx_int_count); ether->tx_int_count = 0; DUMP_PRINT("count_xmit tx %6d\n", ether->count_xmit); ether->count_xmit = 0; DUMP_PRINT("count_finish %6d\n", ether->count_finish); ether->count_finish = 0; DUMP_PRINT("\n"); rxd_offset = (readl((ether->reg + REG_CRXDSA)) - readl((ether->reg + REG_RXDLSA))) / sizeof(struct npcm7xx_txbd); DUMP_PRINT("RXD offset %6d\n", rxd_offset); DUMP_PRINT("cur_rx %6d\n", ether->cur_rx); DUMP_PRINT("rx_err %6d\n", ether->rx_err); ether->rx_err = 0; DUMP_PRINT("rx_berr %6d\n", ether->rx_berr); ether->rx_berr = 0; DUMP_PRINT("rx_stuck %6d\n", ether->rx_stuck); ether->rx_stuck = 0; DUMP_PRINT("rdu %6d\n", ether->rdu); ether->rdu = 0; DUMP_PRINT("rxov rx %6d\n", ether->rxov); ether->rxov = 0; /* debug counters */ DUMP_PRINT("rx_int_count %6d\n", ether->rx_int_count); ether->rx_int_count = 0; DUMP_PRINT("rx_err_count %6d\n", ether->rx_err_count); ether->rx_err_count = 0; DUMP_PRINT("rx_count_pool %6d\n", ether->rx_count_pool); ether->rx_count_pool = 0; DUMP_PRINT("max_waiting_rx %5d\n", ether->max_waiting_rx); ether->max_waiting_rx = 0; DUMP_PRINT("\n"); DUMP_PRINT("need_reset %5d\n", ether->need_reset); if (ether->tdesc && ether->rdesc) { cur = ether->finish_tx - 2; for (i = 0; i < 3; i++) { cur = (cur + 1) % TX_QUEUE_LEN; txbd = (ether->tdesc + cur); DUMP_PRINT("finish %3d txbd mode %08X buffer %08X sl %08X next %08X tx_skb %p\n", cur, txbd->mode, txbd->buffer, txbd->sl, txbd->next, ether->tx_skb[cur]); } DUMP_PRINT("\n"); cur = txd_offset - 2; for (i = 0; i < 3; i++) { cur = (cur + 1) % TX_QUEUE_LEN; txbd = (ether->tdesc + cur); DUMP_PRINT("txd_of %3d txbd mode %08X buffer %08X sl %08X next %08X\n", cur, txbd->mode, txbd->buffer, txbd->sl, txbd->next); } DUMP_PRINT("\n"); cur = ether->cur_tx - 63; for (i = 0; i < 64; i++) { cur = (cur + 1) % TX_QUEUE_LEN; txbd = (ether->tdesc + cur); DUMP_PRINT("cur_tx %3d txbd mode %08X buffer %08X sl %08X next %08X\n", cur, txbd->mode, txbd->buffer, txbd->sl, txbd->next); } DUMP_PRINT("\n"); cur = ether->cur_rx - 63; for (i = 0; i < 64; i++) { cur = (cur + 1) % RX_QUEUE_LEN; rxbd = (ether->rdesc + cur); DUMP_PRINT("cur_rx %3d rxbd sl %08X buffer %08X sl %08X next %08X\n", cur, rxbd->sl, rxbd->buffer, rxbd->reserved, rxbd->next); } DUMP_PRINT("\n"); cur = rxd_offset - 2; for (i = 0; i < 3; i++) { cur = (cur + 1) % RX_QUEUE_LEN; rxbd = (ether->rdesc + cur); DUMP_PRINT("rxd_of %3d rxbd sl %08X buffer %08X sl %08X next %08X\n", cur, rxbd->sl, rxbd->buffer, rxbd->reserved, rxbd->next); } DUMP_PRINT("\n"); } if (!is_locked) spin_unlock_irqrestore(ðer->lock, flags); return count - size; } #endif #ifdef CONFIG_NPCM7XX_EMC_ETH_DEBUG static void npcm7xx_info_print(struct net_device *dev) { char *emc_dump_buf; int count; struct npcm7xx_ether *ether; struct platform_device *pdev; const size_t print_size = 5 * PAGE_SIZE; ether = netdev_priv(dev); pdev = ether->pdev; emc_dump_buf = kmalloc(print_size, GFP_KERNEL); if (!emc_dump_buf) { dev_err(&pdev->dev, "kmalloc failed\n"); } else { char c; char *tmp_buf = emc_dump_buf; count = npcm7xx_info_dump(emc_dump_buf, print_size, dev); while (count > 512) { c = tmp_buf[512]; tmp_buf[512] = 0; dev_info(&pdev->dev, "%s", tmp_buf); tmp_buf += 512; tmp_buf[0] = c; count -= 512; } dev_info(&pdev->dev, "%s", tmp_buf); kfree(emc_dump_buf); } } #endif #ifdef CONFIG_DEBUG_FS #include static int npcm7xx_debug_show(struct seq_file *sf, void *v) { struct net_device *dev = (struct net_device *)sf->private; struct npcm7xx_ether *ether = netdev_priv(dev); const size_t print_size = 5 * PAGE_SIZE; if (!ether->dump_buf) { ether->dump_buf = kmalloc(print_size, GFP_KERNEL); if (!ether->dump_buf) return -1; npcm7xx_info_dump(ether->dump_buf, print_size, dev); } seq_printf(sf, "%s", ether->dump_buf); if (sf->count < sf->size) { kfree(ether->dump_buf); ether->dump_buf = NULL; } return 0; } static int npcm7xx_debug_show_open(struct inode *inode, struct file *file) { return single_open(file, npcm7xx_debug_show, inode->i_private); } static const struct file_operations npcm7xx_debug_show_fops = { .open = npcm7xx_debug_show_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; static int npcm7xx_debug_reset(struct seq_file *sf, void *v) { struct net_device *dev = (struct net_device *)sf->private; struct npcm7xx_ether *ether = netdev_priv(dev); unsigned long flags; seq_puts(sf, "Ask to reset the module\n"); spin_lock_irqsave(ðer->lock, flags); writel(0, (ether->reg + REG_MIEN)); spin_unlock_irqrestore(ðer->lock, flags); ether->need_reset = 1; napi_schedule(ðer->napi); return 0; } static int npcm7xx_debug_reset_open(struct inode *inode, struct file *file) { return single_open(file, npcm7xx_debug_reset, inode->i_private); } static const struct file_operations npcm7xx_debug_reset_fops = { .owner = THIS_MODULE, .open = npcm7xx_debug_reset_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; static int npcm7xx_debug_fs(struct npcm7xx_ether *ether) { /* Create debugfs main directory if it doesn't exist yet */ if (!npcm7xx_fs_dir) { npcm7xx_fs_dir = debugfs_create_dir(DRV_MODULE_NAME, NULL); if (!npcm7xx_fs_dir || IS_ERR(npcm7xx_fs_dir)) { dev_err(ðer->pdev->dev, "ERROR %s, debugfs create directory failed\n", DRV_MODULE_NAME); return -ENOMEM; } } /* Create per netdev entries */ ether->dbgfs_dir = debugfs_create_dir(ether->ndev->name, npcm7xx_fs_dir); if (!ether->dbgfs_dir || IS_ERR(ether->dbgfs_dir)) { dev_err(ðer->pdev->dev, "ERROR failed to create %s directory\n", ether->ndev->name); return -ENOMEM; } /* Entry to report DMA RX/TX rings */ ether->dbgfs_status = debugfs_create_file("status", 0444, ether->dbgfs_dir, ether->ndev, &npcm7xx_debug_show_fops); if (!ether->dbgfs_status || IS_ERR(ether->dbgfs_status)) { dev_err(ðer->pdev->dev, "ERROR creating \'status\' debugfs file\n"); debugfs_remove_recursive(ether->dbgfs_dir); return -ENOMEM; } /* Entry to report the DMA HW features */ ether->dbgfs_dma_cap = debugfs_create_file("do_reset", 0444, ether->dbgfs_dir, ether->ndev, &npcm7xx_debug_reset_fops); if (!ether->dbgfs_dma_cap || IS_ERR(ether->dbgfs_dma_cap)) { dev_err(ðer->pdev->dev, "ERROR creating stmmac \'do_reset\' debugfs file\n"); debugfs_remove_recursive(ether->dbgfs_dir); return -ENOMEM; } return 0; } #endif static void npcm7xx_opmode(struct net_device *dev, int speed, int duplex) { __le32 val; struct npcm7xx_ether *ether = netdev_priv(dev); val = readl((ether->reg + REG_MCMDR)); if (speed == 100) val |= MCMDR_OPMOD; else val &= ~MCMDR_OPMOD; if (duplex == DUPLEX_FULL) val |= MCMDR_FDUP; else val &= ~MCMDR_FDUP; writel(val, (ether->reg + REG_MCMDR)); } static void adjust_link(struct net_device *dev) { struct npcm7xx_ether *ether = netdev_priv(dev); struct phy_device *phydev = ether->phy_dev; bool status_change = false; unsigned long flags; /* clear GPIO interrupt status whihc indicates PHY statu change? */ spin_lock_irqsave(ðer->lock, flags); if (phydev->link) { if (ether->speed != phydev->speed || ether->duplex != phydev->duplex) { ether->speed = phydev->speed; ether->duplex = phydev->duplex; status_change = true; } } else { ether->speed = 0; ether->duplex = -1; } if (phydev->link != ether->link) { ether->link = phydev->link; status_change = true; } spin_unlock_irqrestore(ðer->lock, flags); if (status_change) npcm7xx_opmode(dev, ether->speed, ether->duplex); } static void npcm7xx_write_cam(struct net_device *dev, unsigned int x, unsigned char *pval) { struct npcm7xx_ether *ether = netdev_priv(dev); __le32 msw, lsw; msw = (pval[0] << 24) | (pval[1] << 16) | (pval[2] << 8) | pval[3]; lsw = (pval[4] << 24) | (pval[5] << 16); writel(lsw, (ether->reg + REG_CAML_BASE) + x * CAM_ENTRY_SIZE); writel(msw, (ether->reg + REG_CAMM_BASE) + x * CAM_ENTRY_SIZE); dev_dbg(ðer->pdev->dev, "REG_CAML_BASE = 0x%08X REG_CAMM_BASE = 0x%08X", lsw, msw); } static struct sk_buff *get_new_skb(struct net_device *dev, u32 i) { struct npcm7xx_ether *ether = netdev_priv(dev); struct sk_buff *skb = dev_alloc_skb(roundup(MAX_PACKET_SIZE_W_CRC, 4)); if (!skb) return NULL; /* Do not unmark the following skb_reserve() Receive Buffer Starting * Address must be aligned to 4 bytes and the following line * if unmarked will make it align to 2 and this likely will * hult the RX and crash the linux skb_reserve(skb, NET_IP_ALIGN); */ skb->dev = dev; (ether->rdesc + i)->buffer = dma_map_single(&dev->dev, skb->data, roundup(MAX_PACKET_SIZE_W_CRC, 4), DMA_FROM_DEVICE); ether->rx_skb[i] = skb; return skb; } static int npcm7xx_init_desc(struct net_device *dev) { struct npcm7xx_ether *ether; struct npcm7xx_txbd *tdesc; struct npcm7xx_rxbd *rdesc; struct platform_device *pdev; unsigned int i; ether = netdev_priv(dev); pdev = ether->pdev; if (!ether->tdesc) { ether->tdesc = (struct npcm7xx_txbd *) dma_alloc_coherent(&pdev->dev, sizeof(struct npcm7xx_txbd) * TX_QUEUE_LEN, ðer->tdesc_phys, GFP_KERNEL); if (!ether->tdesc) { dev_err(&pdev->dev, "Failed to allocate memory for tx desc\n"); return -ENOMEM; } } if (!ether->rdesc) { ether->rdesc = (struct npcm7xx_rxbd *) dma_alloc_coherent(&pdev->dev, sizeof(struct npcm7xx_rxbd) * RX_QUEUE_LEN, ðer->rdesc_phys, GFP_KERNEL); if (!ether->rdesc) { dev_err(&pdev->dev, "Failed to allocate memory for rx desc\n"); dma_free_coherent(&pdev->dev, sizeof(struct npcm7xx_txbd) * TX_QUEUE_LEN, ether->tdesc, ether->tdesc_phys); ether->tdesc = NULL; return -ENOMEM; } } for (i = 0; i < TX_QUEUE_LEN; i++) { unsigned int offset; tdesc = (ether->tdesc + i); if (i == TX_QUEUE_LEN - 1) offset = 0; else offset = sizeof(struct npcm7xx_txbd) * (i + 1); tdesc->next = ether->tdesc_phys + offset; tdesc->buffer = (__le32)NULL; tdesc->sl = 0; tdesc->mode = 0; } ether->start_tx_ptr = ether->tdesc_phys; for (i = 0; i < RX_QUEUE_LEN; i++) { unsigned int offset; rdesc = (ether->rdesc + i); if (i == RX_QUEUE_LEN - 1) offset = 0; else offset = sizeof(struct npcm7xx_rxbd) * (i + 1); rdesc->next = ether->rdesc_phys + offset; rdesc->sl = RX_OWN_DMA; if (!get_new_skb(dev, i)) { dev_err(&pdev->dev, "get_new_skb() failed\n"); for (; i != 0; i--) { dma_unmap_single(&dev->dev, (dma_addr_t) ((ether->rdesc + i)->buffer), roundup(MAX_PACKET_SIZE_W_CRC, 4), DMA_FROM_DEVICE); dev_kfree_skb_any(ether->rx_skb[i]); ether->rx_skb[i] = NULL; } dma_free_coherent(&pdev->dev, sizeof(struct npcm7xx_txbd) * TX_QUEUE_LEN, ether->tdesc, ether->tdesc_phys); dma_free_coherent(&pdev->dev, sizeof(struct npcm7xx_rxbd) * RX_QUEUE_LEN, ether->rdesc, ether->rdesc_phys); return -ENOMEM; } } ether->start_rx_ptr = ether->rdesc_phys; wmb(); for (i = 0; i < TX_QUEUE_LEN; i++) ether->tx_skb[i] = NULL; return 0; } /* This API must call with Tx/Rx stopped */ static void npcm7xx_free_desc(struct net_device *dev, bool free_also_descriptors) { struct sk_buff *skb; u32 i; struct npcm7xx_ether *ether = netdev_priv(dev); struct platform_device *pdev = ether->pdev; for (i = 0; i < TX_QUEUE_LEN; i++) { skb = ether->tx_skb[i]; if (skb) { dma_unmap_single(&dev->dev, (dma_addr_t)((ether->tdesc + i)->buffer), skb->len, DMA_TO_DEVICE); dev_kfree_skb_any(skb); ether->tx_skb[i] = NULL; } } for (i = 0; i < RX_QUEUE_LEN; i++) { skb = ether->rx_skb[i]; if (skb) { dma_unmap_single(&dev->dev, (dma_addr_t)((ether->rdesc + i)->buffer), roundup(MAX_PACKET_SIZE_W_CRC, 4), DMA_FROM_DEVICE); dev_kfree_skb_any(skb); ether->rx_skb[i] = NULL; } } if (free_also_descriptors) { if (ether->tdesc) dma_free_coherent(&pdev->dev, sizeof(struct npcm7xx_txbd) * TX_QUEUE_LEN, ether->tdesc, ether->tdesc_phys); ether->tdesc = NULL; if (ether->rdesc) dma_free_coherent(&pdev->dev, sizeof(struct npcm7xx_rxbd) * RX_QUEUE_LEN, ether->rdesc, ether->rdesc_phys); ether->rdesc = NULL; } } static void npcm7xx_set_fifo_threshold(struct net_device *dev) { struct npcm7xx_ether *ether = netdev_priv(dev); __le32 val; val = RXTHD | TXTHD | BLENGTH; writel(val, (ether->reg + REG_FFTCR)); } static void npcm7xx_return_default_idle(struct net_device *dev) { struct npcm7xx_ether *ether = netdev_priv(dev); __le32 val; __le32 saved_bits; val = readl((ether->reg + REG_MCMDR)); saved_bits = val & (MCMDR_FDUP | MCMDR_OPMOD); val |= SWR; writel(val, (ether->reg + REG_MCMDR)); /* During the EMC reset the AHB will read 0 from all registers, * so in order to see if the reset finished we can't count on * (ether->reg + REG_MCMDR).SWR to become 0, instead we read another * register that its reset value is not 0, * we choose (ether->reg + REG_FFTCR). */ do { val = readl((ether->reg + REG_FFTCR)); } while (val == 0); /* * Now we can verify if (ether->reg + REG_MCMDR).SWR became * 0 (probably it will be 0 on the first read). */ do { val = readl((ether->reg + REG_MCMDR)); } while (val & SWR); /* restore values */ writel(saved_bits, (ether->reg + REG_MCMDR)); } static void npcm7xx_enable_mac_interrupt(struct net_device *dev) { struct npcm7xx_ether *ether = netdev_priv(dev); __le32 val; val = ENRXINTR | /* Start of RX interrupts */ ENCRCE | EMRXOV | (ENPTLE * (!IS_VLAN)) | /* If we don't support VLAN we want interrupt on long packets */ ENRXGD | ENALIE | ENRP | ENMMP | ENDFO | /* ENDENI | */ /* We don't need interrupt on DMA Early Notification */ ENRDU | /* We don't need interrupt on Receive Descriptor Unavailable Interrupt */ ENRXBERR | /* ENCFR | */ ENTXINTR | /* Start of TX interrupts */ ENTXEMP | ENTXCP | ENTXDEF | ENNCS | ENTXABT | ENLC | /* ENTDU | */ /* We don't need interrupt on Transmit Descriptor Unavailable at start of operation */ ENTXBERR; writel(val, (ether->reg + REG_MIEN)); } static void npcm7xx_get_and_clear_int(struct net_device *dev, __le32 *val, __le32 mask) { struct npcm7xx_ether *ether = netdev_priv(dev); *val = readl((ether->reg + REG_MISTA)) & mask; writel(*val, (ether->reg + REG_MISTA)); } static void npcm7xx_set_global_maccmd(struct net_device *dev) { struct npcm7xx_ether *ether = netdev_priv(dev); __le32 val; val = readl((ether->reg + REG_MCMDR)); val |= MCMDR_SPCRC | MCMDR_ENMDC | MCMDR_ACP | MCMDR_NDEF; if (IS_VLAN) { /* * we set ALP accept long packets since VLAN packets * are 4 bytes longer than 1518 */ val |= MCMDR_ALP; /* limit receive length to 1522 bytes due to VLAN */ writel(MAX_PACKET_SIZE_W_CRC, (ether->reg + REG_DMARFC)); } writel(val, (ether->reg + REG_MCMDR)); } static void npcm7xx_enable_cam(struct net_device *dev) { struct npcm7xx_ether *ether = netdev_priv(dev); __le32 val; npcm7xx_write_cam(dev, CAM0, dev->dev_addr); val = readl((ether->reg + REG_CAMEN)); val |= CAM0EN; writel(val, (ether->reg + REG_CAMEN)); } static void npcm7xx_set_curdest(struct net_device *dev) { struct npcm7xx_ether *ether = netdev_priv(dev); writel(ether->start_rx_ptr, (ether->reg + REG_RXDLSA)); writel(ether->start_tx_ptr, (ether->reg + REG_TXDLSA)); } static void npcm7xx_ether_set_rx_mode(struct net_device *dev) { struct npcm7xx_ether *ether; __le32 rx_mode; ether = netdev_priv(dev); dev_dbg(ðer->pdev->dev, "%s CAMCMR_AUP\n", (dev->flags & IFF_PROMISC) ? "Set" : "Clear"); if (dev->flags & IFF_PROMISC) rx_mode = CAMCMR_AUP | CAMCMR_AMP | CAMCMR_ABP | CAMCMR_ECMP; else if ((dev->flags & IFF_ALLMULTI) || !netdev_mc_empty(dev)) rx_mode = CAMCMR_AMP | CAMCMR_ABP | CAMCMR_ECMP; else rx_mode = CAMCMR_ECMP | CAMCMR_ABP; writel(rx_mode, (ether->reg + REG_CAMCMR)); ether->camcmr = rx_mode; } static void npcm7xx_reset_mac(struct net_device *dev, int need_free) { struct npcm7xx_ether *ether = netdev_priv(dev); netif_tx_lock(dev); /* disable RX and TX */ writel(readl((ether->reg + REG_MCMDR)) & ~(MCMDR_TXON | MCMDR_RXON), (ether->reg + REG_MCMDR)); npcm7xx_return_default_idle(dev); npcm7xx_set_fifo_threshold(dev); if (need_free) npcm7xx_free_desc(dev, false); npcm7xx_init_desc(dev); ether->cur_tx = 0x0; ether->finish_tx = 0x0; ether->pending_tx = 0x0; ether->cur_rx = 0x0; ether->tx_tdu = 0; ether->tx_tdu_i = 0; ether->tx_cp_i = 0; npcm7xx_set_curdest(dev); npcm7xx_enable_cam(dev); npcm7xx_ether_set_rx_mode(dev); npcm7xx_enable_mac_interrupt(dev); npcm7xx_set_global_maccmd(dev); /* enable RX and TX */ writel(readl((ether->reg + REG_MCMDR)) | MCMDR_TXON | MCMDR_RXON, (ether->reg + REG_MCMDR)); /* trigger RX */ writel(ENSTART, (ether->reg + REG_RSDR)); ether->need_reset = 0; netif_wake_queue(dev); netif_tx_unlock(dev); } static int npcm7xx_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value) { struct npcm7xx_ether *ether = bus->priv; unsigned long timeout = jiffies + msecs_to_jiffies(MII_TIMEOUT * 100); writel(value, (ether->reg + REG_MIID)); writel((phy_id << 0x08) | regnum | PHYBUSY | PHYWR, (ether->reg + REG_MIIDA)); /* Wait for completion */ while (readl((ether->reg + REG_MIIDA)) & PHYBUSY) { if (time_after(jiffies, timeout)) { dev_dbg(ðer->pdev->dev, "mdio read timed out\n ether->reg = 0x%x phy_id=0x%x REG_MIIDA=0x%x\n", (unsigned int)ether->reg, phy_id , readl((ether->reg + REG_MIIDA))); return -ETIMEDOUT; } cpu_relax(); } return 0; } static int npcm7xx_mdio_read(struct mii_bus *bus, int phy_id, int regnum) { struct npcm7xx_ether *ether = bus->priv; unsigned long timeout = jiffies + msecs_to_jiffies(MII_TIMEOUT * 100); writel((phy_id << 0x08) | regnum | PHYBUSY, (ether->reg + REG_MIIDA)); /* Wait for completion */ while (readl((ether->reg + REG_MIIDA)) & PHYBUSY) { if (time_after(jiffies, timeout)) { dev_dbg(ðer->pdev->dev, "mdio read timed out\n ether->reg = 0x%x phy_id=0x%x REG_MIIDA=0x%x\n", (unsigned int)ether->reg, phy_id , readl((ether->reg + REG_MIIDA))); return -ETIMEDOUT; } cpu_relax(); } return readl((ether->reg + REG_MIID)); } static int npcm7xx_mdio_reset(struct mii_bus *bus) { /* reset EMAC engine?? */ return 0; } static int npcm7xx_set_mac_address(struct net_device *dev, void *addr) { struct sockaddr *address = addr; if (!is_valid_ether_addr((u8 *)address->sa_data)) return -EADDRNOTAVAIL; memcpy(dev->dev_addr, address->sa_data, dev->addr_len); npcm7xx_write_cam(dev, CAM0, dev->dev_addr); return 0; } static int npcm7xx_ether_close(struct net_device *dev) { struct npcm7xx_ether *ether = netdev_priv(dev); npcm7xx_return_default_idle(dev); if (ether->phy_dev) phy_stop(ether->phy_dev); else if (ether->use_ncsi) ncsi_stop_dev(ether->ncsidev); msleep(20); free_irq(ether->txirq, dev); free_irq(ether->rxirq, dev); netif_stop_queue(dev); napi_disable(ðer->napi); npcm7xx_free_desc(dev, true); kfree(ether->dump_buf); ether->dump_buf = NULL; return 0; } static struct net_device_stats *npcm7xx_ether_stats(struct net_device *dev) { struct npcm7xx_ether *ether; ether = netdev_priv(dev); return ðer->stats; } static int npcm7xx_clean_tx(struct net_device *dev, bool from_xmit) { struct npcm7xx_ether *ether = netdev_priv(dev); struct npcm7xx_txbd *txbd; struct sk_buff *s; dma_addr_t cur_entry, entry; __le32 sl; if (ether->pending_tx == 0) return (0); cur_entry = readl((ether->reg + REG_CTXDSA)); /* Release old used buffers */ entry = ether->tdesc_phys + sizeof(struct npcm7xx_txbd) * (ether->finish_tx); while (entry != cur_entry) { txbd = (ether->tdesc + ether->finish_tx); s = ether->tx_skb[ether->finish_tx]; if (!s) break; ether->count_finish++; dma_unmap_single(&dev->dev, txbd->buffer, s->len, DMA_TO_DEVICE); consume_skb(s); ether->tx_skb[ether->finish_tx] = NULL; if (++ether->finish_tx >= TX_QUEUE_LEN) ether->finish_tx = 0; ether->pending_tx--; sl = txbd->sl; if (sl & TXDS_TXCP) { ether->stats.tx_packets++; ether->stats.tx_bytes += (sl & 0xFFFF); } else { ether->stats.tx_errors++; } entry = ether->tdesc_phys + sizeof(struct npcm7xx_txbd) * (ether->finish_tx); } if (!from_xmit && unlikely(netif_queue_stopped(dev) && (TX_QUEUE_LEN - ether->pending_tx) > 1)) { netif_tx_lock(dev); if (netif_queue_stopped(dev) && (TX_QUEUE_LEN - ether->pending_tx) > 1) { netif_wake_queue(dev); } netif_tx_unlock(dev); } return(0); } static int npcm7xx_ether_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct npcm7xx_ether *ether = netdev_priv(dev); struct npcm7xx_txbd *txbd; unsigned long flags; ether->count_xmit++; /* Insert new buffer */ txbd = (ether->tdesc + ether->cur_tx); txbd->buffer = dma_map_single(&dev->dev, skb->data, skb->len, DMA_TO_DEVICE); ether->tx_skb[ether->cur_tx] = skb; if (skb->len > MAX_PACKET_SIZE) dev_err(ðer->pdev->dev, "skb->len (= %d) > MAX_PACKET_SIZE (= %d)\n", skb->len, MAX_PACKET_SIZE); txbd->sl = skb->len > MAX_PACKET_SIZE ? MAX_PACKET_SIZE : skb->len; dma_wmb(); txbd->mode = TX_OWN_DMA | PADDINGMODE | CRCMODE; wmb(); /* trigger TX */ writel(ENSTART, (ether->reg + REG_TSDR)); if (++ether->cur_tx >= TX_QUEUE_LEN) ether->cur_tx = 0; spin_lock_irqsave(ðer->lock, flags); ether->pending_tx++; npcm7xx_clean_tx(dev, true); if (ether->pending_tx >= TX_QUEUE_LEN - 1) { __le32 reg_mien; unsigned int index_to_wake = ether->cur_tx + ((TX_QUEUE_LEN * 3) / 4); if (index_to_wake >= TX_QUEUE_LEN) index_to_wake -= TX_QUEUE_LEN; txbd = (ether->tdesc + index_to_wake); txbd->mode = TX_OWN_DMA | PADDINGMODE | CRCMODE | MACTXINTEN; wmb(); writel(MISTA_TDU, (ether->reg + REG_MISTA)); /* Clear TDU interrupt */ reg_mien = readl((ether->reg + REG_MIEN)); if (reg_mien != 0) /* Enable TDU interrupt */ writel(reg_mien | ENTDU, (ether->reg + REG_MIEN)); ether->tx_tdu++; netif_stop_queue(dev); } spin_unlock_irqrestore(ðer->lock, flags); return 0; } static irqreturn_t npcm7xx_tx_interrupt(int irq, void *dev_id) { struct npcm7xx_ether *ether; struct platform_device *pdev; struct net_device *dev; __le32 status; unsigned long flags; dev = dev_id; ether = netdev_priv(dev); pdev = ether->pdev; npcm7xx_get_and_clear_int(dev, &status, 0xFFFF0000); ether->tx_int_count++; if (status & MISTA_EXDEF) dev_err(&pdev->dev, "emc defer exceed interrupt status=0x%08X\n" , status); else if (status & MISTA_TXBERR) { dev_err(&pdev->dev, "emc bus error interrupt status=0x%08X\n", status); #ifdef CONFIG_NPCM7XX_EMC_ETH_DEBUG npcm7xx_info_print(dev); #endif spin_lock_irqsave(ðer->lock, flags); writel(0, (ether->reg + REG_MIEN)); /* disable any interrupt */ spin_unlock_irqrestore(ðer->lock, flags); ether->need_reset = 1; } else if (status & ~(MISTA_TXINTR | MISTA_TXCP | MISTA_TDU)) dev_err(&pdev->dev, "emc other error interrupt status=0x%08X\n", status); /* if we got MISTA_TXCP | MISTA_TDU remove those interrupt and call napi */ if (status & (MISTA_TXCP | MISTA_TDU) & readl((ether->reg + REG_MIEN))) { __le32 reg_mien; spin_lock_irqsave(ðer->lock, flags); reg_mien = readl((ether->reg + REG_MIEN)); if (reg_mien & ENTDU) /* Disable TDU interrupt */ writel(reg_mien & (~ENTDU), (ether->reg + REG_MIEN)); spin_unlock_irqrestore(ðer->lock, flags); if (status & MISTA_TXCP) ether->tx_cp_i++; if (status & MISTA_TDU) ether->tx_tdu_i++; } else { dev_dbg(&pdev->dev, "status=0x%08X\n", status); } napi_schedule(ðer->napi); return IRQ_HANDLED; } static irqreturn_t npcm7xx_rx_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *)dev_id; struct npcm7xx_ether *ether = netdev_priv(dev); struct platform_device *pdev = ether->pdev; __le32 status; unsigned long flags; unsigned int any_err = 0; __le32 rxfsm; npcm7xx_get_and_clear_int(dev, &status, 0xFFFF); ether->rx_int_count++; if (unlikely(status & MISTA_RXBERR)) { ether->rx_berr++; dev_err(&pdev->dev, "emc rx bus error status=0x%08X\n", status); #ifdef CONFIG_NPCM7XX_EMC_ETH_DEBUG npcm7xx_info_print(dev); #endif spin_lock_irqsave(ðer->lock, flags); writel(0, (ether->reg + REG_MIEN)); /* disable any interrupt */ spin_unlock_irqrestore(ðer->lock, flags); ether->need_reset = 1; napi_schedule(ðer->napi); return IRQ_HANDLED; } if (unlikely(status & (MISTA_RXOV | MISTA_RDU))) { /* * filter out all received packets until we have * enough available buffer descriptors */ writel(0, (ether->reg + REG_CAMCMR)); any_err = 1; if (status & (MISTA_RXOV)) ether->rxov++; if (status & (MISTA_RDU)) ether->rdu++; /* * workaround Errata 1.36: EMC Hangs on receiving 253-256 * byte packet */ rxfsm = readl((ether->reg + REG_RXFSM)); if ((rxfsm & 0xFFFFF000) == 0x08044000) { int i; for (i = 0; i < 32; i++) { rxfsm = readl((ether->reg + REG_RXFSM)); if ((rxfsm & 0xFFFFF000) != 0x08044000) break; } if (i == 32) { ether->rx_stuck++; spin_lock_irqsave(ðer->lock, flags); #ifdef CONFIG_NPCM7XX_EMC_ETH_DEBUG npcm7xx_info_print(dev); #endif writel(0, (ether->reg + REG_MIEN)); spin_unlock_irqrestore(ðer->lock, flags); ether->need_reset = 1; napi_schedule(ðer->napi); dev_err(&pdev->dev, "stuck on REG_RXFSM = 0x%08X status=%08X doing reset!\n", rxfsm, status); return IRQ_HANDLED; } } } /* echo MISTA status on unexpected flags although we don't do anithing with them */ if (unlikely(status & (/* MISTA_RXINTR | */ /* Receive - all RX interrupt set this */ MISTA_CRCE | /* CRC Error */ /* MISTA_RXOV | */ /* Receive FIFO Overflow - we alread handled it */ (MISTA_PTLE * !IS_VLAN) | /* Packet Too Long is needed if VLAN is not supported */ /* MISTA_RXGD | */ /* Receive Good - this is the common good case */ MISTA_ALIE | /* Alignment Error */ MISTA_RP | /* Runt Packet */ MISTA_MMP | /* More Missed Packet */ MISTA_DFOI | /* Maximum Frame Length */ /* MISTA_DENI | */ /* DMA Early Notification - every packet get this */ /* MISTA_RDU | */ /* Receive Descriptor Unavailable */ /* MISTA_RXBERR | */ /* Receive Bus Error Interrupt - we alread handled it */ /* MISTA_CFR | */ /* Control Frame Receive - not an error */ 0))) { dev_dbg(&pdev->dev, "emc rx MISTA status=0x%08X\n", status); any_err = 1; ether->rx_err++; } if (!any_err && ((status & MISTA_RXGD) == 0)) dev_err(&pdev->dev, "emc rx MISTA status=0x%08X\n", status); spin_lock_irqsave(ðer->lock, flags); writel(readl((ether->reg + REG_MIEN)) & ~ENRXGD, (ether->reg + REG_MIEN)); spin_unlock_irqrestore(ðer->lock, flags); napi_schedule(ðer->napi); return IRQ_HANDLED; } static int npcm7xx_poll(struct napi_struct *napi, int budget) { struct npcm7xx_ether *ether = container_of(napi, struct npcm7xx_ether, napi); struct npcm7xx_rxbd *rxbd; struct net_device *dev = ether->ndev; struct platform_device *pdev = ether->pdev; struct sk_buff *skb, *s; unsigned int length; __le32 status; unsigned long flags; int rx_cnt = 0; int complete = 0; unsigned int rx_offset = (readl((ether->reg + REG_CRXDSA)) - ether->start_rx_ptr) / sizeof(struct npcm7xx_txbd); unsigned int local_count = (rx_offset >= ether->cur_rx) ? rx_offset - ether->cur_rx : rx_offset + RX_QUEUE_LEN - ether->cur_rx; if (local_count > ether->max_waiting_rx) ether->max_waiting_rx = local_count; if (local_count > (4 * RX_POLL_SIZE)) /* * we are porbably in a storm of short packets and we don't * want to get into RDU since short packets in RDU cause * many RXOV which may cause EMC halt, so we filter out all * coming packets */ writel(0, (ether->reg + REG_CAMCMR)); if (local_count <= budget) /* we can restore accepting of packets */ writel(ether->camcmr, (ether->reg + REG_CAMCMR)); spin_lock_irqsave(ðer->lock, flags); npcm7xx_clean_tx(dev, false); spin_unlock_irqrestore(ðer->lock, flags); rxbd = (ether->rdesc + ether->cur_rx); while (rx_cnt < budget) { status = rxbd->sl; if ((status & RX_OWN_DMA) == RX_OWN_DMA) { complete = 1; break; } /* for debug puposes we save the previous value */ rxbd->reserved = status; s = ether->rx_skb[ether->cur_rx]; length = status & 0xFFFF; /* * If VLAN is not supporte RXDS_PTLE (packet too long) is also * an error */ if (likely((status & (RXDS_RXGD | RXDS_CRCE | RXDS_ALIE | RXDS_RP | (IS_VLAN ? 0 : RXDS_PTLE))) == RXDS_RXGD) && likely(length <= MAX_PACKET_SIZE)) { dma_unmap_single(&dev->dev, (dma_addr_t)rxbd->buffer, roundup(MAX_PACKET_SIZE_W_CRC, 4), DMA_FROM_DEVICE); skb_put(s, length); s->protocol = eth_type_trans(s, dev); netif_receive_skb(s); ether->stats.rx_packets++; ether->stats.rx_bytes += length; rx_cnt++; ether->rx_count_pool++; /* now we allocate new skb instead if the used one. */ skb = dev_alloc_skb(roundup(MAX_PACKET_SIZE_W_CRC, 4)); if (!skb) { dev_err(&pdev->dev, "get skb buffer error\n"); ether->stats.rx_dropped++; goto rx_out; } /* Do not unmark the following skb_reserve() Receive * Buffer Starting Address must be aligned * to 4 bytes and the following line if unmarked * will make it align to 2 and this likely * will hult the RX and crash the linux * skb_reserve(skb, NET_IP_ALIGN); */ skb->dev = dev; rxbd->buffer = dma_map_single(&dev->dev, skb->data, roundup(MAX_PACKET_SIZE_W_CRC, 4), DMA_FROM_DEVICE); ether->rx_skb[ether->cur_rx] = skb; } else { ether->rx_err_count++; ether->stats.rx_errors++; dev_dbg(&pdev->dev, "rx_errors = %lu status = 0x%08X\n", ether->stats.rx_errors, status); if (status & RXDS_RP) { ether->stats.rx_length_errors++; dev_dbg(&pdev->dev, "rx_length_errors = %lu\n", ether->stats.rx_length_errors); } else if (status & RXDS_CRCE) { ether->stats.rx_crc_errors++; dev_dbg(&pdev->dev, "rx_crc_errors = %lu\n", ether->stats.rx_crc_errors); } else if (status & RXDS_ALIE) { ether->stats.rx_frame_errors++; dev_dbg(&pdev->dev, "rx_frame_errors = %lu\n", ether->stats.rx_frame_errors); } else if (((!IS_VLAN) && (status & RXDS_PTLE)) || length > MAX_PACKET_SIZE) { ether->stats.rx_length_errors++; dev_dbg(&pdev->dev, "rx_length_errors = %lu\n", ether->stats.rx_length_errors); } } wmb(); rxbd->sl = RX_OWN_DMA; wmb(); if (++ether->cur_rx >= RX_QUEUE_LEN) ether->cur_rx = 0; rxbd = (ether->rdesc + ether->cur_rx); } if (complete) { napi_complete(napi); if (ether->need_reset) { dev_dbg(&pdev->dev, "Reset\n"); npcm7xx_reset_mac(dev, 1); } spin_lock_irqsave(ðer->lock, flags); writel(readl((ether->reg + REG_MIEN)) | ENRXGD, (ether->reg + REG_MIEN)); spin_unlock_irqrestore(ðer->lock, flags); } else { rx_offset = (readl((ether->reg + REG_CRXDSA)) - ether->start_rx_ptr) / sizeof(struct npcm7xx_txbd); local_count = (rx_offset >= ether->cur_rx) ? rx_offset - ether->cur_rx : rx_offset + RX_QUEUE_LEN - ether->cur_rx; if (local_count > ether->max_waiting_rx) ether->max_waiting_rx = local_count; if (local_count > (3 * RX_POLL_SIZE)) /* * we are porbably in a storm of short packets and * we don't want to get into RDU since short packets in * RDU cause many RXOV which may cause * EMC halt, so we filter out all coming packets */ writel(0, (ether->reg + REG_CAMCMR)); if (local_count <= RX_POLL_SIZE) /* we can restore accepting of packets */ writel(ether->camcmr, (ether->reg + REG_CAMCMR)); } rx_out: /* trigger RX */ writel(ENSTART, (ether->reg + REG_RSDR)); return rx_cnt; } static int npcm7xx_ether_open(struct net_device *dev) { struct npcm7xx_ether *ether; struct platform_device *pdev; ether = netdev_priv(dev); pdev = ether->pdev; if (ether->use_ncsi) { ether->speed = 100; ether->duplex = DUPLEX_FULL; npcm7xx_opmode(dev, 100, DUPLEX_FULL); } npcm7xx_reset_mac(dev, 0); if (request_irq(ether->txirq, npcm7xx_tx_interrupt, 0x0, pdev->name, dev)) { dev_err(&pdev->dev, "register irq tx failed\n"); npcm7xx_ether_close(dev); return -EAGAIN; } if (request_irq(ether->rxirq, npcm7xx_rx_interrupt, 0x0, pdev->name, dev)) { dev_err(&pdev->dev, "register irq rx failed\n"); npcm7xx_ether_close(dev); return -EAGAIN; } if (ether->phy_dev) phy_start(ether->phy_dev); else if (ether->use_ncsi) netif_carrier_on(dev); netif_start_queue(dev); napi_enable(ðer->napi); /* trigger RX */ writel(ENSTART, (ether->reg + REG_RSDR)); /* Start the NCSI device */ if (ether->use_ncsi) { int err = ncsi_start_dev(ether->ncsidev); if (err) { npcm7xx_ether_close(dev); return err; } } dev_info(&pdev->dev, "%s is OPENED\n", dev->name); return 0; } static int npcm7xx_ether_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct npcm7xx_ether *ether = netdev_priv(dev); struct phy_device *phydev = ether->phy_dev; if (!netif_running(dev)) return -EINVAL; if (!phydev) return -ENODEV; return phy_mii_ioctl(phydev, ifr, cmd); } static void npcm7xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver)); strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version)); strlcpy(info->fw_version, "N/A", sizeof(info->fw_version)); strlcpy(info->bus_info, "N/A", sizeof(info->bus_info)); } static int npcm7xx_get_settings(struct net_device *dev, struct ethtool_link_ksettings *cmd) { struct npcm7xx_ether *ether = netdev_priv(dev); struct phy_device *phydev = ether->phy_dev; if (!phydev) return -ENODEV; dev_info(ðer->pdev->dev, "\n\nnpcm7xx_get_settings\n"); phy_ethtool_ksettings_get(phydev, cmd); return 0; } static int npcm7xx_set_settings(struct net_device *dev, const struct ethtool_link_ksettings *cmd) { struct npcm7xx_ether *ether = netdev_priv(dev); struct phy_device *phydev = ether->phy_dev; int ret; if (!phydev) return -ENODEV; dev_info(ðer->pdev->dev, "\n\nnpcm7xx_set_settings\n"); ret = phy_ethtool_ksettings_set(phydev, cmd); return ret; } static u32 npcm7xx_get_msglevel(struct net_device *dev) { struct npcm7xx_ether *ether = netdev_priv(dev); return ether->msg_enable; } static void npcm7xx_set_msglevel(struct net_device *dev, u32 level) { struct npcm7xx_ether *ether = netdev_priv(dev); ether->msg_enable = level; } static const struct ethtool_ops npcm7xx_ether_ethtool_ops = { .get_link_ksettings = npcm7xx_get_settings, .set_link_ksettings = npcm7xx_set_settings, .get_drvinfo = npcm7xx_get_drvinfo, .get_msglevel = npcm7xx_get_msglevel, .set_msglevel = npcm7xx_set_msglevel, .get_link = ethtool_op_get_link, }; static const struct net_device_ops npcm7xx_ether_netdev_ops = { .ndo_open = npcm7xx_ether_open, .ndo_stop = npcm7xx_ether_close, .ndo_start_xmit = npcm7xx_ether_start_xmit, .ndo_get_stats = npcm7xx_ether_stats, .ndo_set_rx_mode = npcm7xx_ether_set_rx_mode, .ndo_set_mac_address = npcm7xx_set_mac_address, .ndo_do_ioctl = npcm7xx_ether_ioctl, .ndo_validate_addr = eth_validate_addr, .ndo_change_mtu = eth_change_mtu, }; static void get_mac_address(struct net_device *dev) { struct npcm7xx_ether *ether = netdev_priv(dev); struct platform_device *pdev = ether->pdev; struct device_node *np = ether->pdev->dev.of_node; const u8 *mac_address = NULL; mac_address = of_get_mac_address(np); if (mac_address != 0) ether_addr_copy(dev->dev_addr, mac_address); if (is_valid_ether_addr(dev->dev_addr)) { dev_info(&pdev->dev, "%s: device MAC address : %pM\n", pdev->name, dev->dev_addr); } else { eth_hw_addr_random(dev); dev_info(&pdev->dev, "%s: device MAC address (random generator) %pM\n", dev->name, dev->dev_addr); } } static int npcm7xx_mii_setup(struct net_device *dev) { struct npcm7xx_ether *ether = netdev_priv(dev); struct platform_device *pdev; struct phy_device *phydev = NULL; int i, err = 0; pdev = ether->pdev; ether->mii_bus = mdiobus_alloc(); if (!ether->mii_bus) { err = -ENOMEM; dev_err(&pdev->dev, "mdiobus_alloc() failed\n"); goto out0; } ether->mii_bus->name = "npcm7xx_rmii"; ether->mii_bus->read = &npcm7xx_mdio_read; ether->mii_bus->write = &npcm7xx_mdio_write; ether->mii_bus->reset = &npcm7xx_mdio_reset; snprintf(ether->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x", ether->pdev->name, ether->pdev->id); dev_dbg(&pdev->dev, "%s ether->mii_bus->id=%s\n", __func__, ether->mii_bus->id); ether->mii_bus->priv = ether; ether->mii_bus->parent = ðer->pdev->dev; for (i = 0; i < PHY_MAX_ADDR; i++) ether->mii_bus->irq[i] = PHY_POLL; platform_set_drvdata(ether->pdev, ether->mii_bus); /* Enable MDIO Clock */ writel(readl((ether->reg + REG_MCMDR)) | MCMDR_ENMDC, (ether->reg + REG_MCMDR)); if (mdiobus_register(ether->mii_bus)) { dev_err(&pdev->dev, "mdiobus_register() failed\n"); goto out2; } phydev = phy_find_first(ether->mii_bus); if (!phydev) { dev_err(&pdev->dev, "phy_find_first() failed\n"); goto out3; } dev_info(&pdev->dev, " name = %s ETH-Phy-Id = 0x%x\n", phydev_name(phydev), phydev->phy_id); phydev = phy_connect(dev, phydev_name(phydev), &adjust_link, PHY_INTERFACE_MODE_RMII); dev_info(&pdev->dev, " ETH-Phy-Id = 0x%x name = %s\n", phydev->phy_id, phydev->drv->name); if (IS_ERR(phydev)) { err = PTR_ERR(phydev); dev_err(&pdev->dev, "phy_connect() failed - %d\n", err); goto out3; } linkmode_and(phydev->supported, phydev->supported, PHY_BASIC_FEATURES); linkmode_copy(phydev->advertising, phydev->supported); ether->phy_dev = phydev; return 0; out3: mdiobus_unregister(ether->mii_bus); out2: kfree(ether->mii_bus->irq); mdiobus_free(ether->mii_bus); out0: return err; } static const struct of_device_id emc_dt_id[] = { { .compatible = "nuvoton,npcm750-emc", }, {}, }; MODULE_DEVICE_TABLE(of, emc_dt_id); static void npcm7xx_ncsi_handler(struct ncsi_dev *nd) { if (unlikely(nd->state != ncsi_dev_state_functional)) return; netdev_info(nd->dev, "NCSI interface %s\n", nd->link_up ? "up" : "down"); } static int npcm7xx_ether_probe(struct platform_device *pdev) { struct npcm7xx_ether *ether; struct net_device *dev; int error; struct clk *emc_clk = NULL; struct device_node *np = pdev->dev.of_node; pdev->id = of_alias_get_id(np, "ethernet"); if (pdev->id < 0) pdev->id = 0; emc_clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(emc_clk)) return PTR_ERR(emc_clk); /* Enable Clock */ clk_prepare_enable(emc_clk); error = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); if (error) return -ENODEV; dev = alloc_etherdev(sizeof(struct npcm7xx_ether)); if (!dev) return -ENOMEM; ether = netdev_priv(dev); ether->rst_regmap = syscon_regmap_lookup_by_compatible("nuvoton,npcm750-rst"); if (IS_ERR(ether->rst_regmap)) { dev_err(&pdev->dev, "%s: failed to find nuvoton,npcm750-rst\n", __func__); return IS_ERR(ether->rst_regmap); } /* Reset EMC module */ if (pdev->id == 0) { regmap_update_bits(ether->rst_regmap, IPSRST1_OFFSET, (0x1 << 6), (0x1 << 6)); regmap_update_bits(ether->rst_regmap, IPSRST1_OFFSET, (0x1 << 6), 0); } if (pdev->id == 1) { regmap_update_bits(ether->rst_regmap, IPSRST1_OFFSET, (0x1 << 21), (0x1 << 21)); regmap_update_bits(ether->rst_regmap, IPSRST1_OFFSET, (0x1 << 21), 0); } ether->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!ether->res) { dev_err(&pdev->dev, "failed to get I/O memory\n"); error = -ENXIO; goto failed_free; } if (!request_mem_region(ether->res->start, resource_size(ether->res), pdev->name)) { dev_err(&pdev->dev, "failed to request I/O memory\n"); error = -EBUSY; goto failed_free; } ether->reg = ioremap(ether->res->start, resource_size(ether->res)); dev_dbg(&pdev->dev, "%s ether->reg = 0x%x\n", __func__, (unsigned int)ether->reg); if (!ether->reg) { dev_err(&pdev->dev, "failed to remap I/O memory\n"); error = -ENXIO; goto failed_free_mem; } ether->txirq = platform_get_irq(pdev, 0); if (ether->txirq < 0) { dev_err(&pdev->dev, "failed to get ether tx irq\n"); error = -ENXIO; goto failed_free_io; } ether->rxirq = platform_get_irq(pdev, 1); if (ether->rxirq < 0) { dev_err(&pdev->dev, "failed to get ether rx irq\n"); error = -ENXIO; goto failed_free_io; } SET_NETDEV_DEV(dev, &pdev->dev); platform_set_drvdata(pdev, dev); ether->ndev = dev; ether->pdev = pdev; ether->msg_enable = NETIF_MSG_LINK; dev->netdev_ops = &npcm7xx_ether_netdev_ops; dev->ethtool_ops = &npcm7xx_ether_ethtool_ops; dev->tx_queue_len = TX_QUEUE_LEN; dev->dma = 0x0; dev->watchdog_timeo = TX_TIMEOUT; get_mac_address(dev); ether->cur_tx = 0x0; ether->cur_rx = 0x0; ether->finish_tx = 0x0; ether->pending_tx = 0x0; ether->link = 0; ether->speed = 100; ether->duplex = DUPLEX_FULL; ether->need_reset = 0; ether->dump_buf = NULL; ether->rx_berr = 0; ether->rx_err = 0; ether->rdu = 0; ether->rxov = 0; ether->rx_stuck = 0; /* debug counters */ ether->max_waiting_rx = 0; ether->rx_count_pool = 0; ether->count_xmit = 0; ether->rx_int_count = 0; ether->rx_err_count = 0; ether->tx_int_count = 0; ether->count_finish = 0; ether->tx_tdu = 0; ether->tx_tdu_i = 0; ether->tx_cp_i = 0; spin_lock_init(ðer->lock); netif_napi_add(dev, ðer->napi, npcm7xx_poll, RX_POLL_SIZE); if (pdev->dev.of_node && of_get_property(pdev->dev.of_node, "use-ncsi", NULL)) { if (!IS_ENABLED(CONFIG_NET_NCSI)) { dev_err(&pdev->dev, "CONFIG_NET_NCSI not enabled\n"); error = -ENODEV; goto failed_free_napi; } dev_info(&pdev->dev, "Using NCSI interface\n"); ether->use_ncsi = true; ether->ncsidev = ncsi_register_dev(dev, npcm7xx_ncsi_handler); if (!ether->ncsidev) { error = -ENODEV; goto failed_free_napi; } } else { ether->use_ncsi = false; error = npcm7xx_mii_setup(dev); if (error < 0) { dev_err(&pdev->dev, "npcm7xx_mii_setup err\n"); goto failed_free_napi; } } error = register_netdev(dev); if (error != 0) { dev_err(&pdev->dev, "register_netdev() failed\n"); error = -ENODEV; goto failed_free_napi; } #ifdef CONFIG_DEBUG_FS npcm7xx_debug_fs(ether); #endif return 0; failed_free_napi: netif_napi_del(ðer->napi); platform_set_drvdata(pdev, NULL); failed_free_io: iounmap(ether->reg); failed_free_mem: release_mem_region(ether->res->start, resource_size(ether->res)); failed_free: free_netdev(dev); return error; } static int npcm7xx_ether_remove(struct platform_device *pdev) { struct net_device *dev = platform_get_drvdata(pdev); struct npcm7xx_ether *ether = netdev_priv(dev); #ifdef CONFIG_DEBUG_FS debugfs_remove_recursive(ether->dbgfs_dir); #endif unregister_netdev(dev); free_irq(ether->txirq, dev); free_irq(ether->rxirq, dev); if (ether->phy_dev) phy_disconnect(ether->phy_dev); mdiobus_unregister(ether->mii_bus); kfree(ether->mii_bus->irq); mdiobus_free(ether->mii_bus); platform_set_drvdata(pdev, NULL); free_netdev(dev); return 0; } static struct platform_driver npcm7xx_ether_driver = { .probe = npcm7xx_ether_probe, .remove = npcm7xx_ether_remove, .driver = { .name = DRV_MODULE_NAME, .owner = THIS_MODULE, .of_match_table = of_match_ptr(emc_dt_id), }, }; module_platform_driver(npcm7xx_ether_driver); MODULE_AUTHOR("Nuvoton Technology Corp."); MODULE_DESCRIPTION("NPCM750 EMC driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:npcm750-emc"); MODULE_VERSION(DRV_MODULE_VERSION);