fcc_enet.c
来自「是关于linux2.5.1的完全源码」· C语言 代码 · 共 1,911 行 · 第 1/4 页
C
1,911 行
/* Check for a transmit error. The manual is a little unclear * about this, so the debug code until I get it figured out. It * appears that if TXE is set, then TXB is not set. However, * if carrier sense is lost during frame transmission, the TXE * bit is set, "and continues the buffer transmission normally." * I don't know if "normally" implies TXB is set when the buffer * descriptor is closed.....trial and error :-). */ /* Transmit OK, or non-fatal error. Update the buffer descriptors. */ if (int_events & (FCC_ENET_TXE | FCC_ENET_TXB)) { spin_lock(&cep->lock); bdp = cep->dirty_tx; while ((bdp->cbd_sc&BD_ENET_TX_READY)==0) { if ((bdp==cep->cur_tx) && (cep->tx_full == 0)) break; if (bdp->cbd_sc & BD_ENET_TX_HB) /* No heartbeat */ cep->stats.tx_heartbeat_errors++; if (bdp->cbd_sc & BD_ENET_TX_LC) /* Late collision */ cep->stats.tx_window_errors++; if (bdp->cbd_sc & BD_ENET_TX_RL) /* Retrans limit */ cep->stats.tx_aborted_errors++; if (bdp->cbd_sc & BD_ENET_TX_UN) /* Underrun */ cep->stats.tx_fifo_errors++; if (bdp->cbd_sc & BD_ENET_TX_CSL) /* Carrier lost */ cep->stats.tx_carrier_errors++; /* No heartbeat or Lost carrier are not really bad errors. * The others require a restart transmit command. */ if (bdp->cbd_sc & (BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN)) { must_restart = 1; cep->stats.tx_errors++; } cep->stats.tx_packets++; /* Deferred means some collisions occurred during transmit, * but we eventually sent the packet OK. */ if (bdp->cbd_sc & BD_ENET_TX_DEF) cep->stats.collisions++; /* Free the sk buffer associated with this last transmit. */ dev_kfree_skb_irq(cep->tx_skbuff[cep->skb_dirty]); cep->skb_dirty = (cep->skb_dirty + 1) & TX_RING_MOD_MASK; /* Update pointer to next buffer descriptor to be transmitted. */ if (bdp->cbd_sc & BD_ENET_TX_WRAP) bdp = cep->tx_bd_base; else bdp++; /* I don't know if we can be held off from processing these * interrupts for more than one frame time. I really hope * not. In such a case, we would now want to check the * currently available BD (cur_tx) and determine if any * buffers between the dirty_tx and cur_tx have also been * sent. We would want to process anything in between that * does not have BD_ENET_TX_READY set. */ /* Since we have freed up a buffer, the ring is no longer * full. */ if (cep->tx_full) { cep->tx_full = 0; if (netif_queue_stopped(dev)) { netif_wake_queue(dev); } } cep->dirty_tx = (cbd_t *)bdp; } if (must_restart) { volatile cpm8260_t *cp; /* Some transmit errors cause the transmitter to shut * down. We now issue a restart transmit. Since the * errors close the BD and update the pointers, the restart * _should_ pick up without having to reset any of our * pointers either. Also, To workaround 8260 device erratum * CPM37, we must disable and then re-enable the transmitter * following a Late Collision, Underrun, or Retry Limit error. */ cep->fccp->fcc_gfmr &= ~FCC_GFMR_ENT; udelay(10); /* wait a few microseconds just on principle */ cep->fccp->fcc_gfmr |= FCC_GFMR_ENT; cp = cpmp; cp->cp_cpcr = mk_cr_cmd(cep->fip->fc_cpmpage, cep->fip->fc_cpmblock, 0x0c, CPM_CR_RESTART_TX) | CPM_CR_FLG; while (cp->cp_cpcr & CPM_CR_FLG); } spin_unlock(&cep->lock); } /* Check for receive busy, i.e. packets coming but no place to * put them. */ if (int_events & FCC_ENET_BSY) { cep->stats.rx_dropped++; } return;}/* During a receive, the cur_rx points to the current incoming buffer. * When we update through the ring, if the next incoming buffer has * not been given to the system, we just set the empty indicator, * effectively tossing the packet. */static intfcc_enet_rx(struct net_device *dev){ struct fcc_enet_private *cep; volatile cbd_t *bdp; struct sk_buff *skb; ushort pkt_len; cep = (struct fcc_enet_private *)dev->priv; /* First, grab all of the stats for the incoming packet. * These get messed up if we get called due to a busy condition. */ bdp = cep->cur_rx;for (;;) { if (bdp->cbd_sc & BD_ENET_RX_EMPTY) break; #ifndef final_version /* Since we have allocated space to hold a complete frame, both * the first and last indicators should be set. */ if ((bdp->cbd_sc & (BD_ENET_RX_FIRST | BD_ENET_RX_LAST)) != (BD_ENET_RX_FIRST | BD_ENET_RX_LAST)) printk("CPM ENET: rcv is not first+last\n");#endif /* Frame too long or too short. */ if (bdp->cbd_sc & (BD_ENET_RX_LG | BD_ENET_RX_SH)) cep->stats.rx_length_errors++; if (bdp->cbd_sc & BD_ENET_RX_NO) /* Frame alignment */ cep->stats.rx_frame_errors++; if (bdp->cbd_sc & BD_ENET_RX_CR) /* CRC Error */ cep->stats.rx_crc_errors++; if (bdp->cbd_sc & BD_ENET_RX_OV) /* FIFO overrun */ cep->stats.rx_crc_errors++; if (bdp->cbd_sc & BD_ENET_RX_CL) /* Late Collision */ cep->stats.rx_frame_errors++; if (!(bdp->cbd_sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV | BD_ENET_RX_CL))) { /* Process the incoming frame. */ cep->stats.rx_packets++; /* Remove the FCS from the packet length. */ pkt_len = bdp->cbd_datlen - 4; cep->stats.rx_bytes += pkt_len; /* This does 16 byte alignment, much more than we need. */ skb = dev_alloc_skb(pkt_len); if (skb == NULL) { printk("%s: Memory squeeze, dropping packet.\n", dev->name); cep->stats.rx_dropped++; } else { skb->dev = dev; skb_put(skb,pkt_len); /* Make room */ eth_copy_and_sum(skb, (unsigned char *)__va(bdp->cbd_bufaddr), pkt_len, 0); skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); } } /* Clear the status flags for this buffer. */ bdp->cbd_sc &= ~BD_ENET_RX_STATS; /* Mark the buffer empty. */ bdp->cbd_sc |= BD_ENET_RX_EMPTY; /* Update BD pointer to next entry. */ if (bdp->cbd_sc & BD_ENET_RX_WRAP) bdp = cep->rx_bd_base; else bdp++; } cep->cur_rx = (cbd_t *)bdp; return 0;}static intfcc_enet_close(struct net_device *dev){ /* Don't know what to do yet. */ netif_stop_queue(dev); return 0;}static struct net_device_stats *fcc_enet_get_stats(struct net_device *dev){ struct fcc_enet_private *cep = (struct fcc_enet_private *)dev->priv; return &cep->stats;}#ifdef CONFIG_USE_MDIO/* NOTE: Most of the following comes from the FEC driver for 860. The * overall structure of MII code has been retained (as it's proved stable * and well-tested), but actual transfer requests are processed "at once" * instead of being queued (there's no interrupt-driven MII transfer * mechanism, one has to toggle the data/clock bits manually). */static intmii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_device *)){ struct fcc_enet_private *fep; int retval, tmp; /* Add PHY address to register command. */ fep = dev->priv; regval |= fep->phy_addr << 23; retval = 0; tmp = mii_send_receive(fep->fip, regval); if (func) func(tmp, dev); return retval;}static void mii_do_cmd(struct net_device *dev, const phy_cmd_t *c){ int k; if(!c) return; for(k = 0; (c+k)->mii_data != mk_mii_end; k++) mii_queue(dev, (c+k)->mii_data, (c+k)->funct);}static void mii_parse_sr(uint mii_reg, struct net_device *dev){ volatile struct fcc_enet_private *fep = dev->priv; uint s = fep->phy_status; s &= ~(PHY_STAT_LINK | PHY_STAT_FAULT | PHY_STAT_ANC); if (mii_reg & 0x0004) s |= PHY_STAT_LINK; if (mii_reg & 0x0010) s |= PHY_STAT_FAULT; if (mii_reg & 0x0020) s |= PHY_STAT_ANC; fep->phy_status = s; fep->link = (s & PHY_STAT_LINK) ? 1 : 0;}static void mii_parse_cr(uint mii_reg, struct net_device *dev){ volatile struct fcc_enet_private *fep = dev->priv; uint s = fep->phy_status; s &= ~(PHY_CONF_ANE | PHY_CONF_LOOP); if (mii_reg & 0x1000) s |= PHY_CONF_ANE; if (mii_reg & 0x4000) s |= PHY_CONF_LOOP; fep->phy_status = s;}static void mii_parse_anar(uint mii_reg, struct net_device *dev){ volatile struct fcc_enet_private *fep = dev->priv; uint s = fep->phy_status; s &= ~(PHY_CONF_SPMASK); if (mii_reg & 0x0020) s |= PHY_CONF_10HDX; if (mii_reg & 0x0040) s |= PHY_CONF_10FDX; if (mii_reg & 0x0080) s |= PHY_CONF_100HDX; if (mii_reg & 0x00100) s |= PHY_CONF_100FDX; fep->phy_status = s;}/* ------------------------------------------------------------------------- *//* The Level one LXT970 is used by many boards */#ifdef CONFIG_FCC_LXT970#define MII_LXT970_MIRROR 16 /* Mirror register */#define MII_LXT970_IER 17 /* Interrupt Enable Register */#define MII_LXT970_ISR 18 /* Interrupt Status Register */#define MII_LXT970_CONFIG 19 /* Configuration Register */#define MII_LXT970_CSR 20 /* Chip Status Register */static void mii_parse_lxt970_csr(uint mii_reg, struct net_device *dev){ volatile struct fcc_enet_private *fep = dev->priv; uint s = fep->phy_status; s &= ~(PHY_STAT_SPMASK); if (mii_reg & 0x0800) { if (mii_reg & 0x1000) s |= PHY_STAT_100FDX; else s |= PHY_STAT_100HDX; } else { if (mii_reg & 0x1000) s |= PHY_STAT_10FDX; else s |= PHY_STAT_10HDX; } fep->phy_status = s;}static phy_info_t phy_info_lxt970 = { 0x07810000, "LXT970", (const phy_cmd_t []) { /* config */#if 0// { mk_mii_write(MII_REG_ANAR, 0x0021), NULL }, /* Set default operation of 100-TX....for some reason * some of these bits are set on power up, which is wrong. */ { mk_mii_write(MII_LXT970_CONFIG, 0), NULL },#endif { mk_mii_read(MII_REG_CR), mii_parse_cr }, { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, { mk_mii_end, } }, (const phy_cmd_t []) { /* startup - enable interrupts */ { mk_mii_write(MII_LXT970_IER, 0x0002), NULL }, { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ { mk_mii_end, } }, (const phy_cmd_t []) { /* ack_int */ /* read SR and ISR to acknowledge */ { mk_mii_read(MII_REG_SR), mii_parse_sr }, { mk_mii_read(MII_LXT970_ISR), NULL }, /* find out the current status */ { mk_mii_read(MII_LXT970_CSR), mii_parse_lxt970_csr }, { mk_mii_end, } }, (const phy_cmd_t []) { /* shutdown - disable interrupts */ { mk_mii_write(MII_LXT970_IER, 0x0000), NULL }, { mk_mii_end, } },};#endif /* CONFIG_FEC_LXT970 *//* ------------------------------------------------------------------------- *//* The Level one LXT971 is used on some of my custom boards */#ifdef CONFIG_FCC_LXT971/* register definitions for the 971 */#define MII_LXT971_PCR 16 /* Port Control Register */#define MII_LXT971_SR2 17 /* Status Register 2 */#define MII_LXT971_IER 18 /* Interrupt Enable Register */#define MII_LXT971_ISR 19 /* Interrupt Status Register */#define MII_LXT971_LCR 20 /* LED Control Register */#define MII_LXT971_TCR 30 /* Transmit Control Register *//* * I had some nice ideas of running the MDIO faster... * The 971 should support 8MHz and I tried it, but things acted really * weird, so 2.5 MHz ought to be enough for anyone... */static void mii_parse_lxt971_sr2(uint mii_reg, struct net_device *dev){ volatile struct fcc_enet_private *fep = dev->priv; uint s = fep->phy_status; s &= ~(PHY_STAT_SPMASK); if (mii_reg & 0x4000) { if (mii_reg & 0x0200) s |= PHY_STAT_100FDX; else s |= PHY_STAT_100HDX; } else { if (mii_reg & 0x0200) s |= PHY_STAT_10FDX; else s |= PHY_STAT_10HDX; } if (mii_reg & 0x0008) s |= PHY_STAT_FAULT; fep->phy_status = s;}static phy_info_t phy_info_lxt971 = { 0x0001378e, "LXT971", (const phy_cmd_t []) { /* config */// { mk_mii_write(MII_REG_ANAR, 0x021), NULL }, /* 10 Mbps, HD */ { mk_mii_read(MII_REG_CR), mii_parse_cr }, { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, { mk_mii_end, } }, (const phy_cmd_t []) { /* startup - enable interrupts */ { mk_mii_write(MII_LXT971_IER, 0x00f2), NULL }, { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ /* Somehow does the 971 tell me that the link is down * the first read after power-up. * read here to get a valid value in ack_int */ { mk_mii_read(MII_REG_SR), mii_parse_sr }, { mk_mii_end, } }, (const phy_cmd_t []) { /* ack_int */ /* find out the current status */ { mk_mii_read(MII_REG_SR), mii_parse_sr }, { mk_mii_read(MII_LXT971_SR2), mii_parse_lxt971_sr2 }, /* we only need to read ISR to acknowledge */ { mk_mii_read(MII_LXT971_ISR), NULL }, { mk_mii_end, } }, (const phy_cmd_t []) { /* shutdown - disable interrupts */ { mk_mii_write(MII_LXT971_IER, 0x0000), NULL }, { mk_mii_end, } },};#endif /* CONFIG_FEC_LXT970 *//* ------------------------------------------------------------------------- *//* The Quality Semiconductor QS6612 is used on the RPX CLLF */#ifdef CONFIG_FCC_QS6612/* register definitions */#define MII_QS6612_MCR 17 /* Mode Control Register */#define MII_QS6612_FTR 27 /* Factory Test Register */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?