📄 fcc_enet.c
字号:
ep->fen_genfcc.fcc_rstate = (CPMFCR_GBL | CPMFCR_EB) << 24; ep->fen_genfcc.fcc_tstate = (CPMFCR_GBL | CPMFCR_EB) << 24; /* Set maximum bytes per receive buffer. * It must be a multiple of 32. */ ep->fen_genfcc.fcc_mrblr = PKT_MAXBLR_SIZE; /* Allocate space in the reserved FCC area of DPRAM for the * internal buffers. No one uses this space (yet), so we * can do this. Later, we will add resource management for * this area. */ mem_addr = CPM_FCC_SPECIAL_BASE + (fip->fc_fccnum * 128); ep->fen_genfcc.fcc_riptr = mem_addr; ep->fen_genfcc.fcc_tiptr = mem_addr+32; ep->fen_padptr = mem_addr+64; memset((char *)(&(immap->im_dprambase[(mem_addr+64)])), 0x88, 32); ep->fen_genfcc.fcc_rbptr = 0; ep->fen_genfcc.fcc_tbptr = 0; ep->fen_genfcc.fcc_rcrc = 0; ep->fen_genfcc.fcc_tcrc = 0; ep->fen_genfcc.fcc_res1 = 0; ep->fen_genfcc.fcc_res2 = 0; ep->fen_camptr = 0; /* CAM isn't used in this driver */ /* Set CRC preset and mask. */ ep->fen_cmask = 0xdebb20e3; ep->fen_cpres = 0xffffffff; ep->fen_crcec = 0; /* CRC Error counter */ ep->fen_alec = 0; /* alignment error counter */ ep->fen_disfc = 0; /* discard frame counter */ ep->fen_retlim = 15; /* Retry limit threshold */ ep->fen_pper = 0; /* Normal persistence */ /* Clear hash filter tables. */ ep->fen_gaddrh = 0; ep->fen_gaddrl = 0; ep->fen_iaddrh = 0; ep->fen_iaddrl = 0; /* Clear the Out-of-sequence TxBD. */ ep->fen_tfcstat = 0; ep->fen_tfclen = 0; ep->fen_tfcptr = 0; ep->fen_mflr = PKT_MAXBUF_SIZE; /* maximum frame length register */ ep->fen_minflr = PKT_MINBUF_SIZE; /* minimum frame length register */ /* Set Ethernet station address. * * This is supplied in the board information structure, so we * copy that into the controller. * So, far we have only been given one Ethernet address. We make * it unique by setting a few bits in the upper byte of the * non-static part of the address. */ eap = (unsigned char *)&(ep->fen_paddrh); for (i=5; i>=0; i--) {/* * The EP8260 only uses FCC3, so we can safely give it the real * MAC address. */#ifdef CONFIG_SBC82xx if (i == 5) { /* bd->bi_enetaddr holds the SCC0 address; the FCC devices count up from there */ dev->dev_addr[i] = bd->bi_enetaddr[i] & ~3; dev->dev_addr[i] += 1 + fip->fc_fccnum; *eap++ = dev->dev_addr[i]; }#else#ifndef CONFIG_RPX8260 if (i == 3) { dev->dev_addr[i] = bd->bi_enetaddr[i]; dev->dev_addr[i] |= (1 << (7 - fip->fc_fccnum)); *eap++ = dev->dev_addr[i]; } else#endif { *eap++ = dev->dev_addr[i] = bd->bi_enetaddr[i]; }#endif } ep->fen_taddrh = 0; ep->fen_taddrm = 0; ep->fen_taddrl = 0; ep->fen_maxd1 = PKT_MAXDMA_SIZE; /* maximum DMA1 length */ ep->fen_maxd2 = PKT_MAXDMA_SIZE; /* maximum DMA2 length */ /* Clear stat counters, in case we ever enable RMON. */ ep->fen_octc = 0; ep->fen_colc = 0; ep->fen_broc = 0; ep->fen_mulc = 0; ep->fen_uspc = 0; ep->fen_frgc = 0; ep->fen_ospc = 0; ep->fen_jbrc = 0; ep->fen_p64c = 0; ep->fen_p65c = 0; ep->fen_p128c = 0; ep->fen_p256c = 0; ep->fen_p512c = 0; ep->fen_p1024c = 0; ep->fen_rfthr = 0; /* Suggested by manual */ ep->fen_rfcnt = 0; ep->fen_cftype = 0; /* Now allocate the host memory pages and initialize the * buffer descriptors. */ bdp = cep->tx_bd_base; for (i=0; i<TX_RING_SIZE; i++) { /* Initialize the BD for every fragment in the page. */ bdp->cbd_sc = 0; bdp->cbd_datlen = 0; bdp->cbd_bufaddr = 0; bdp++; } /* Set the last buffer to wrap. */ bdp--; bdp->cbd_sc |= BD_SC_WRAP; bdp = cep->rx_bd_base; for (i=0; i<FCC_ENET_RX_PAGES; i++) { /* Allocate a page. */ mem_addr = __get_free_page(GFP_KERNEL); /* Initialize the BD for every fragment in the page. */ for (j=0; j<FCC_ENET_RX_FRPPG; j++) { bdp->cbd_sc = BD_ENET_RX_EMPTY | BD_ENET_RX_INTR; bdp->cbd_datlen = 0; bdp->cbd_bufaddr = __pa(mem_addr); mem_addr += FCC_ENET_RX_FRSIZE; bdp++; } } /* Set the last buffer to wrap. */ bdp--; bdp->cbd_sc |= BD_SC_WRAP; /* Let's re-initialize the channel now. We have to do it later * than the manual describes because we have just now finished * the BD initialization. */ cp->cp_cpcr = mk_cr_cmd(fip->fc_cpmpage, fip->fc_cpmblock, 0x0c, CPM_CR_INIT_TRX) | CPM_CR_FLG; while (cp->cp_cpcr & CPM_CR_FLG); cep->skb_cur = cep->skb_dirty = 0;}/* Let 'er rip.*/static void __initinit_fcc_startup(fcc_info_t *fip, struct net_device *dev){ volatile fcc_t *fccp; struct fcc_enet_private *cep; cep = (struct fcc_enet_private *)(dev->priv); fccp = cep->fccp;#ifdef CONFIG_RPX8260#ifdef PHY_INTERRUPT /* Route PHY interrupt to IRQ. The following code only works for * IRQ1 - IRQ7. It does not work for Port C interrupts. */ *((volatile u_char *) (RPX_CSR_ADDR + 13)) &= ~BCSR13_FETH_IRQMASK; *((volatile u_char *) (RPX_CSR_ADDR + 13)) |= ((PHY_INTERRUPT - SIU_INT_IRQ1 + 1) << 4);#endif /* Initialize MDIO pins. */ *((volatile u_char *) (RPX_CSR_ADDR + 4)) &= ~BCSR4_MII_MDC; *((volatile u_char *) (RPX_CSR_ADDR + 4)) |= BCSR4_MII_READ | BCSR4_MII_MDIO; /* Enable external LXT971 PHY. */ *((volatile u_char *) (RPX_CSR_ADDR + 4)) |= BCSR4_EN_PHY; udelay(1000); *((volatile u_char *) (RPX_CSR_ADDR+ 4)) |= BCSR4_EN_MII; udelay(1000);#endif /* ifdef CONFIG_RPX8260 */ fccp->fcc_fcce = 0xffff; /* Clear any pending events */ /* Leave FCC interrupts masked for now. Will be unmasked by * fcc_restart(). */ fccp->fcc_fccm = 0; /* Install our interrupt handler. */ if (request_irq(fip->fc_interrupt, fcc_enet_interrupt, 0, "fenet", dev) < 0) printk("Can't get FCC IRQ %d\n", fip->fc_interrupt);#ifdef PHY_INTERRUPT#ifdef CONFIG_ADS8272 if (request_irq(PHY_INTERRUPT, mii_link_interrupt, SA_SHIRQ, "mii", dev) < 0) printk(KERN_CRIT "Can't get MII IRQ %d\n", PHY_INTERRUPT);#else /* Make IRQn edge triggered. This does not work if PHY_INTERRUPT is * on Port C. */ ((volatile cpm2_map_t *) CPM_MAP_ADDR)->im_intctl.ic_siexr |= (1 << (14 - (PHY_INTERRUPT - SIU_INT_IRQ1))); if (request_irq(PHY_INTERRUPT, mii_link_interrupt, 0, "mii", dev) < 0) printk(KERN_CRIT "Can't get MII IRQ %d\n", PHY_INTERRUPT);#endif#endif /* PHY_INTERRUPT */ /* Set GFMR to enable Ethernet operating mode. */ fccp->fcc_gfmr = (FCC_GFMR_TCI | FCC_GFMR_MODE_ENET); /* Set sync/delimiters. */ fccp->fcc_fdsr = 0xd555; /* Set protocol specific processing mode for Ethernet. * This has to be adjusted for Full Duplex operation after we can * determine how to detect that. */ fccp->fcc_fpsmr = FCC_PSMR_ENCRC;#ifdef CONFIG_PQ2ADS /* Enable the PHY. */ *(volatile uint *)(BCSR_ADDR + 4) &= ~BCSR1_FETHIEN; *(volatile uint *)(BCSR_ADDR + 4) |= BCSR1_FETH_RST;#endif#if defined(CONFIG_PQ2ADS) || defined(CONFIG_PQ2FADS) /* Enable the 2nd PHY. */ *(volatile uint *)(BCSR_ADDR + 12) &= ~BCSR3_FETHIEN2; *(volatile uint *)(BCSR_ADDR + 12) |= BCSR3_FETH2_RST;#endif#if defined(CONFIG_USE_MDIO) || defined(CONFIG_TQM8260) /* start in full duplex mode, and negotiate speed */ fcc_restart (dev, 1);#else /* start in half duplex mode */ fcc_restart (dev, 0);#endif}#ifdef CONFIG_USE_MDIO/* MII command/status interface. * I'm not going to describe all of the details. You can find the * protocol definition in many other places, including the data sheet * of most PHY parts. * I wonder what "they" were thinking (maybe weren't) when they leave * the I2C in the CPM but I have to toggle these bits...... */#ifdef CONFIG_RPX8260 /* The EP8260 has the MDIO pins in a BCSR instead of on Port C * like most other boards. */#define MDIO_ADDR ((volatile u_char *)(RPX_CSR_ADDR + 4))#define MAKE_MDIO_OUTPUT *MDIO_ADDR &= ~BCSR4_MII_READ#define MAKE_MDIO_INPUT *MDIO_ADDR |= BCSR4_MII_READ | BCSR4_MII_MDIO#define OUT_MDIO(bit) \ if (bit) \ *MDIO_ADDR |= BCSR4_MII_MDIO; \ else \ *MDIO_ADDR &= ~BCSR4_MII_MDIO;#define IN_MDIO (*MDIO_ADDR & BCSR4_MII_MDIO)#define OUT_MDC(bit) \ if (bit) \ *MDIO_ADDR |= BCSR4_MII_MDC; \ else \ *MDIO_ADDR &= ~BCSR4_MII_MDC;#else /* ifdef CONFIG_RPX8260 */ /* This is for the usual case where the MDIO pins are on Port C. */#define MDIO_ADDR (((volatile cpm2_map_t *)CPM_MAP_ADDR)->im_ioport)#define MAKE_MDIO_OUTPUT MDIO_ADDR.iop_pdirc |= fip->fc_mdio#define MAKE_MDIO_INPUT MDIO_ADDR.iop_pdirc &= ~fip->fc_mdio#define OUT_MDIO(bit) \ if (bit) \ MDIO_ADDR.iop_pdatc |= fip->fc_mdio; \ else \ MDIO_ADDR.iop_pdatc &= ~fip->fc_mdio;#define IN_MDIO ((MDIO_ADDR.iop_pdatc) & fip->fc_mdio)#define OUT_MDC(bit) \ if (bit) \ MDIO_ADDR.iop_pdatc |= fip->fc_mdck; \ else \ MDIO_ADDR.iop_pdatc &= ~fip->fc_mdck;#endif /* ifdef CONFIG_RPX8260 */static uintmii_send_receive(fcc_info_t *fip, uint cmd){ uint retval; int read_op, i, off; const int us = 1; read_op = ((cmd & 0xf0000000) == 0x60000000); /* Write preamble */ OUT_MDIO(1); MAKE_MDIO_OUTPUT; OUT_MDIO(1); for (i = 0; i < 32; i++) { udelay(us); OUT_MDC(1); udelay(us); OUT_MDC(0); } /* Write data */ for (i = 0, off = 31; i < (read_op ? 14 : 32); i++, --off) { OUT_MDIO((cmd >> off) & 0x00000001); udelay(us); OUT_MDC(1); udelay(us); OUT_MDC(0); } retval = cmd; if (read_op) { retval >>= 16; MAKE_MDIO_INPUT; udelay(us); OUT_MDC(1); udelay(us); OUT_MDC(0); for (i = 0; i < 16; i++) { udelay(us); OUT_MDC(1); udelay(us); retval <<= 1; if (IN_MDIO) retval++; OUT_MDC(0); } } MAKE_MDIO_INPUT; udelay(us); OUT_MDC(1); udelay(us); OUT_MDC(0); return retval;}#endif /* CONFIG_USE_MDIO */static voidfcc_stop(struct net_device *dev){ struct fcc_enet_private *fep= (struct fcc_enet_private *)(dev->priv); volatile fcc_t *fccp = fep->fccp; fcc_info_t *fip = fep->fip; volatile fcc_enet_t *ep = fep->ep; volatile cpm_cpm2_t *cp = cpmp; volatile cbd_t *bdp; int i; if ((fccp->fcc_gfmr & (FCC_GFMR_ENR | FCC_GFMR_ENT)) == 0) return; /* already down */ fccp->fcc_fccm = 0; /* issue the graceful stop tx command */ while (cp->cp_cpcr & CPM_CR_FLG); cp->cp_cpcr = mk_cr_cmd(fip->fc_cpmpage, fip->fc_cpmblock, 0x0c, CPM_CR_GRA_STOP_TX) | CPM_CR_FLG; while (cp->cp_cpcr & CPM_CR_FLG); /* Disable transmit/receive */ fccp->fcc_gfmr &= ~(FCC_GFMR_ENR | FCC_GFMR_ENT); /* issue the restart tx command */ fccp->fcc_fcce = FCC_ENET_GRA; while (cp->cp_cpcr & CPM_CR_FLG); cp->cp_cpcr = mk_cr_cmd(fip->fc_cpmpage, fip->fc_cpmblock, 0x0c, CPM_CR_RESTART_TX) | CPM_CR_FLG; while (cp->cp_cpcr & CPM_CR_FLG); /* free tx buffers */ fep->skb_cur = fep->skb_dirty = 0; for (i=0; i<=TX_RING_MOD_MASK; i++) { if (fep->tx_skbuff[i] != NULL) { dev_kfree_skb(fep->tx_skbuff[i]); fep->tx_skbuff[i] = NULL; } } fep->dirty_tx = fep->cur_tx = fep->tx_bd_base; fep->tx_free = TX_RING_SIZE; ep->fen_genfcc.fcc_tbptr = ep->fen_genfcc.fcc_tbase; /* Initialize the tx buffer descriptors. */ bdp = fep->tx_bd_base; for (i=0; i<TX_RING_SIZE; i++) { bdp->cbd_sc = 0; bdp->cbd_datlen = 0; bdp->cbd_bufaddr = 0; bdp++; } /* Set the last buffer to wrap. */ bdp--; bdp->cbd_sc |= BD_SC_WRAP;}static voidfcc_restart(struct net_device *dev, int duplex){ struct fcc_enet_private *fep = (struct fcc_enet_private *)(dev->priv); volatile fcc_t *fccp = fep->fccp; /* stop any transmissions in progress */ fcc_stop(dev); if (duplex) fccp->fcc_fpsmr |= FCC_PSMR_FDE | FCC_PSMR_LPB; else fccp->fcc_fpsmr &= ~(FCC_PSMR_FDE | FCC_PSMR_LPB); /* Enable interrupts for transmit error, complete frame * received, and any transmit buffer we have also set the * interrupt flag. */ fccp->fcc_fccm = (FCC_ENET_TXE | FCC_ENET_RXF | FCC_ENET_TXB); /* Enable transmit/receive */ fccp->fcc_gfmr |= FCC_GFMR_ENR | FCC_GFMR_ENT;}static intfcc_enet_open(struct net_device *dev){ struct fcc_enet_private *fep = dev->priv;#ifdef CONFIG_USE_MDIO fep->sequence_done = 0; fep->link = 0; if (fep-
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -