cassini.c
来自「linux 内核源代码」· C语言 代码 · 共 2,335 行 · 第 1/5 页
C
2,335 行
CAS_BASE(RX_INDEX_RING, 0)); } cp->rx_old[0] = RX_DESC_RINGN_SIZE(0) - 4; cp->rx_last[0] = 0; cp->cas_flags &= ~CAS_FLAG_RXD_POST(0);}static void cas_clean_rxcs(struct cas *cp){ int i, j; /* take ownership of rx comp descriptors */ memset(cp->rx_cur, 0, sizeof(*cp->rx_cur)*N_RX_COMP_RINGS); memset(cp->rx_new, 0, sizeof(*cp->rx_new)*N_RX_COMP_RINGS); for (i = 0; i < N_RX_COMP_RINGS; i++) { struct cas_rx_comp *rxc = cp->init_rxcs[i]; for (j = 0; j < RX_COMP_RINGN_SIZE(i); j++) { cas_rxc_init(rxc + j); } }}#if 0/* When we get a RX fifo overflow, the RX unit is probably hung * so we do the following. * * If any part of the reset goes wrong, we return 1 and that causes the * whole chip to be reset. */static int cas_rxmac_reset(struct cas *cp){ struct net_device *dev = cp->dev; int limit; u32 val; /* First, reset MAC RX. */ writel(cp->mac_rx_cfg & ~MAC_RX_CFG_EN, cp->regs + REG_MAC_RX_CFG); for (limit = 0; limit < STOP_TRIES; limit++) { if (!(readl(cp->regs + REG_MAC_RX_CFG) & MAC_RX_CFG_EN)) break; udelay(10); } if (limit == STOP_TRIES) { printk(KERN_ERR "%s: RX MAC will not disable, resetting whole " "chip.\n", dev->name); return 1; } /* Second, disable RX DMA. */ writel(0, cp->regs + REG_RX_CFG); for (limit = 0; limit < STOP_TRIES; limit++) { if (!(readl(cp->regs + REG_RX_CFG) & RX_CFG_DMA_EN)) break; udelay(10); } if (limit == STOP_TRIES) { printk(KERN_ERR "%s: RX DMA will not disable, resetting whole " "chip.\n", dev->name); return 1; } mdelay(5); /* Execute RX reset command. */ writel(SW_RESET_RX, cp->regs + REG_SW_RESET); for (limit = 0; limit < STOP_TRIES; limit++) { if (!(readl(cp->regs + REG_SW_RESET) & SW_RESET_RX)) break; udelay(10); } if (limit == STOP_TRIES) { printk(KERN_ERR "%s: RX reset command will not execute, " "resetting whole chip.\n", dev->name); return 1; } /* reset driver rx state */ cas_clean_rxds(cp); cas_clean_rxcs(cp); /* Now, reprogram the rest of RX unit. */ cas_init_rx_dma(cp); /* re-enable */ val = readl(cp->regs + REG_RX_CFG); writel(val | RX_CFG_DMA_EN, cp->regs + REG_RX_CFG); writel(MAC_RX_FRAME_RECV, cp->regs + REG_MAC_RX_MASK); val = readl(cp->regs + REG_MAC_RX_CFG); writel(val | MAC_RX_CFG_EN, cp->regs + REG_MAC_RX_CFG); return 0;}#endifstatic int cas_rxmac_interrupt(struct net_device *dev, struct cas *cp, u32 status){ u32 stat = readl(cp->regs + REG_MAC_RX_STATUS); if (!stat) return 0; if (netif_msg_intr(cp)) printk(KERN_DEBUG "%s: rxmac interrupt, stat: 0x%x\n", cp->dev->name, stat); /* these are all rollovers */ spin_lock(&cp->stat_lock[0]); if (stat & MAC_RX_ALIGN_ERR) cp->net_stats[0].rx_frame_errors += 0x10000; if (stat & MAC_RX_CRC_ERR) cp->net_stats[0].rx_crc_errors += 0x10000; if (stat & MAC_RX_LEN_ERR) cp->net_stats[0].rx_length_errors += 0x10000; if (stat & MAC_RX_OVERFLOW) { cp->net_stats[0].rx_over_errors++; cp->net_stats[0].rx_fifo_errors++; } /* We do not track MAC_RX_FRAME_COUNT and MAC_RX_VIOL_ERR * events. */ spin_unlock(&cp->stat_lock[0]); return 0;}static int cas_mac_interrupt(struct net_device *dev, struct cas *cp, u32 status){ u32 stat = readl(cp->regs + REG_MAC_CTRL_STATUS); if (!stat) return 0; if (netif_msg_intr(cp)) printk(KERN_DEBUG "%s: mac interrupt, stat: 0x%x\n", cp->dev->name, stat); /* This interrupt is just for pause frame and pause * tracking. It is useful for diagnostics and debug * but probably by default we will mask these events. */ if (stat & MAC_CTRL_PAUSE_STATE) cp->pause_entered++; if (stat & MAC_CTRL_PAUSE_RECEIVED) cp->pause_last_time_recvd = (stat >> 16); return 0;}/* Must be invoked under cp->lock. */static inline int cas_mdio_link_not_up(struct cas *cp){ u16 val; switch (cp->lstate) { case link_force_ret: if (netif_msg_link(cp)) printk(KERN_INFO "%s: Autoneg failed again, keeping" " forced mode\n", cp->dev->name); cas_phy_write(cp, MII_BMCR, cp->link_fcntl); cp->timer_ticks = 5; cp->lstate = link_force_ok; cp->link_transition = LINK_TRANSITION_LINK_CONFIG; break; case link_aneg: val = cas_phy_read(cp, MII_BMCR); /* Try forced modes. we try things in the following order: * 1000 full -> 100 full/half -> 10 half */ val &= ~(BMCR_ANRESTART | BMCR_ANENABLE); val |= BMCR_FULLDPLX; val |= (cp->cas_flags & CAS_FLAG_1000MB_CAP) ? CAS_BMCR_SPEED1000 : BMCR_SPEED100; cas_phy_write(cp, MII_BMCR, val); cp->timer_ticks = 5; cp->lstate = link_force_try; cp->link_transition = LINK_TRANSITION_LINK_CONFIG; break; case link_force_try: /* Downgrade from 1000 to 100 to 10 Mbps if necessary. */ val = cas_phy_read(cp, MII_BMCR); cp->timer_ticks = 5; if (val & CAS_BMCR_SPEED1000) { /* gigabit */ val &= ~CAS_BMCR_SPEED1000; val |= (BMCR_SPEED100 | BMCR_FULLDPLX); cas_phy_write(cp, MII_BMCR, val); break; } if (val & BMCR_SPEED100) { if (val & BMCR_FULLDPLX) /* fd failed */ val &= ~BMCR_FULLDPLX; else { /* 100Mbps failed */ val &= ~BMCR_SPEED100; } cas_phy_write(cp, MII_BMCR, val); break; } default: break; } return 0;}/* must be invoked with cp->lock held */static int cas_mii_link_check(struct cas *cp, const u16 bmsr){ int restart; if (bmsr & BMSR_LSTATUS) { /* Ok, here we got a link. If we had it due to a forced * fallback, and we were configured for autoneg, we * retry a short autoneg pass. If you know your hub is * broken, use ethtool ;) */ if ((cp->lstate == link_force_try) && (cp->link_cntl & BMCR_ANENABLE)) { cp->lstate = link_force_ret; cp->link_transition = LINK_TRANSITION_LINK_CONFIG; cas_mif_poll(cp, 0); cp->link_fcntl = cas_phy_read(cp, MII_BMCR); cp->timer_ticks = 5; if (cp->opened && netif_msg_link(cp)) printk(KERN_INFO "%s: Got link after fallback, retrying" " autoneg once...\n", cp->dev->name); cas_phy_write(cp, MII_BMCR, cp->link_fcntl | BMCR_ANENABLE | BMCR_ANRESTART); cas_mif_poll(cp, 1); } else if (cp->lstate != link_up) { cp->lstate = link_up; cp->link_transition = LINK_TRANSITION_LINK_UP; if (cp->opened) { cas_set_link_modes(cp); netif_carrier_on(cp->dev); } } return 0; } /* link not up. if the link was previously up, we restart the * whole process */ restart = 0; if (cp->lstate == link_up) { cp->lstate = link_down; cp->link_transition = LINK_TRANSITION_LINK_DOWN; netif_carrier_off(cp->dev); if (cp->opened && netif_msg_link(cp)) printk(KERN_INFO "%s: Link down\n", cp->dev->name); restart = 1; } else if (++cp->timer_ticks > 10) cas_mdio_link_not_up(cp); return restart;}static int cas_mif_interrupt(struct net_device *dev, struct cas *cp, u32 status){ u32 stat = readl(cp->regs + REG_MIF_STATUS); u16 bmsr; /* check for a link change */ if (CAS_VAL(MIF_STATUS_POLL_STATUS, stat) == 0) return 0; bmsr = CAS_VAL(MIF_STATUS_POLL_DATA, stat); return cas_mii_link_check(cp, bmsr);}static int cas_pci_interrupt(struct net_device *dev, struct cas *cp, u32 status){ u32 stat = readl(cp->regs + REG_PCI_ERR_STATUS); if (!stat) return 0; printk(KERN_ERR "%s: PCI error [%04x:%04x] ", dev->name, stat, readl(cp->regs + REG_BIM_DIAG)); /* cassini+ has this reserved */ if ((stat & PCI_ERR_BADACK) && ((cp->cas_flags & CAS_FLAG_REG_PLUS) == 0)) printk("<No ACK64# during ABS64 cycle> "); if (stat & PCI_ERR_DTRTO) printk("<Delayed transaction timeout> "); if (stat & PCI_ERR_OTHER) printk("<other> "); if (stat & PCI_ERR_BIM_DMA_WRITE) printk("<BIM DMA 0 write req> "); if (stat & PCI_ERR_BIM_DMA_READ) printk("<BIM DMA 0 read req> "); printk("\n"); if (stat & PCI_ERR_OTHER) { u16 cfg; /* Interrogate PCI config space for the * true cause. */ pci_read_config_word(cp->pdev, PCI_STATUS, &cfg); printk(KERN_ERR "%s: Read PCI cfg space status [%04x]\n", dev->name, cfg); if (cfg & PCI_STATUS_PARITY) printk(KERN_ERR "%s: PCI parity error detected.\n", dev->name); if (cfg & PCI_STATUS_SIG_TARGET_ABORT) printk(KERN_ERR "%s: PCI target abort.\n", dev->name); if (cfg & PCI_STATUS_REC_TARGET_ABORT) printk(KERN_ERR "%s: PCI master acks target abort.\n", dev->name); if (cfg & PCI_STATUS_REC_MASTER_ABORT) printk(KERN_ERR "%s: PCI master abort.\n", dev->name); if (cfg & PCI_STATUS_SIG_SYSTEM_ERROR) printk(KERN_ERR "%s: PCI system error SERR#.\n", dev->name); if (cfg & PCI_STATUS_DETECTED_PARITY) printk(KERN_ERR "%s: PCI parity error.\n", dev->name); /* Write the error bits back to clear them. */ cfg &= (PCI_STATUS_PARITY | PCI_STATUS_SIG_TARGET_ABORT | PCI_STATUS_REC_TARGET_ABORT | PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY); pci_write_config_word(cp->pdev, PCI_STATUS, cfg); } /* For all PCI errors, we should reset the chip. */ return 1;}/* All non-normal interrupt conditions get serviced here. * Returns non-zero if we should just exit the interrupt * handler right now (ie. if we reset the card which invalidates * all of the other original irq status bits). */static int cas_abnormal_irq(struct net_device *dev, struct cas *cp, u32 status){ if (status & INTR_RX_TAG_ERROR) { /* corrupt RX tag framing */ if (netif_msg_rx_err(cp)) printk(KERN_DEBUG "%s: corrupt rx tag framing\n", cp->dev->name); spin_lock(&cp->stat_lock[0]); cp->net_stats[0].rx_errors++; spin_unlock(&cp->stat_lock[0]); goto do_reset; } if (status & INTR_RX_LEN_MISMATCH) { /* length mismatch. */ if (netif_msg_rx_err(cp)) printk(KERN_DEBUG "%s: length mismatch for rx frame\n", cp->dev->name); spin_lock(&cp->stat_lock[0]); cp->net_stats[0].rx_errors++; spin_unlock(&cp->stat_lock[0]); goto do_reset; } if (status & INTR_PCS_STATUS) { if (cas_pcs_interrupt(dev, cp, status)) goto do_reset; } if (status & INTR_TX_MAC_STATUS) { if (cas_txmac_interrupt(dev, cp, status)) goto do_reset; } if (status & INTR_RX_MAC_STATUS) { if (cas_rxmac_interrupt(dev, cp, status)) goto do_reset; } if (status & INTR_MAC_CTRL_STATUS) { if (cas_mac_interrupt(dev, cp, status)) goto do_reset; } if (status & INTR_MIF_STATUS) { if (cas_mif_interrupt(dev, cp, status)) goto do_reset; } if (status & INTR_PCI_ERROR_STATUS) { if (cas_pci_interrupt(dev, cp, status)) goto do_reset; } return 0;do_reset:#if 1 atomic_inc(&cp->reset_task_pending); atomic_inc(&cp->reset_task_pending_all); printk(KERN_ERR "%s:reset called in cas_abnormal_irq [0x%x]\n", dev->name, status); schedule_work(&cp->reset_task);#else atomic_set(&cp->reset_task_pending, CAS_RESET_ALL); printk(KERN_ERR "reset called in cas_abnormal_irq\n"); schedule_work(&cp->reset_task);#endif return 1;}/* NOTE: CAS_TABORT returns 1 or 2 so that it can be used when * determining whether to do a netif_stop/wakeup */#define CAS_TABORT(x) (((x)->cas_flags & CAS_FLAG_TARGET_ABORT) ? 2 : 1)#define CAS_ROUND_PAGE(x) (((x) + PAGE_SIZE - 1) & PAGE_MASK)static inline int cas_calc_tabort(struct cas *cp, const unsigned long addr, const int len){ unsigned long off = addr + len; if (CAS_TABORT(cp) == 1) return 0; if ((CAS_ROUND_PAGE(off) - off) > TX_TARGET_ABORT_LEN) return 0; return TX_TARGET_ABORT_LEN;}static inline void cas_tx_ringN(struct cas *cp, int ring, int limit){ struct cas_tx_desc *txds; struct sk_buff **skbs; struct net_device *dev = cp->dev; int entry, count; spin_lock(&cp->tx_lock[ring]); txds = cp->init_txds[ring]; skbs = cp->tx_skbs[ring]; entry = cp->tx_old[ring]; count = TX_BUFF_COUNT(ring, entry, limit); while (entry != limit) { struct sk_buff *skb = skbs[entry]; dma_addr_t daddr; u32 dlen; int frag; if (!skb) { /* this should never occur */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?