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 + -
显示快捷键?