?? fec.c
字號:
/* Only support group multicast for now. */ if (!(dmi->dmi_addr[0] & 1)) continue; /* The address in dmi_addr is LSB first, * and taddr is MSB first. We have to * copy bytes MSB first from dmi_addr. */ mcptr = (u_char *)dmi->dmi_addr + 5; tdptr = (u_char *)&ep->sen_taddrh; for (j=0; j<6; j++) *tdptr++ = *mcptr--; /* Ask CPM to run CRC and set bit in * filter mask. */ cpmp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SCC1, CPM_CR_SET_GADDR) | CPM_CR_FLG; /* this delay is necessary here -- Cort */ udelay(10); while (cpmp->cp_cpcr & CPM_CR_FLG); } }#endif }}/* Initialize the FEC Ethernet on 860T. */int __init fec_enet_init(void){ struct net_device *dev; struct fec_enet_private *fep; int i, j; unsigned char *eap, *iap; unsigned long mem_addr; pte_t *pte; volatile cbd_t *bdp; cbd_t *cbd_base; volatile immap_t *immap; volatile fec_t *fecp; bd_t *bd; extern uint _get_IMMR(void);#ifdef CONFIG_SCC_ENET unsigned char tmpaddr[6];#endif immap = (immap_t *)IMAP_ADDR; /* pointer to internal registers */ bd = (bd_t *)__res; /* Allocate some private information. */ fep = (struct fec_enet_private *)kmalloc(sizeof(*fep), GFP_KERNEL); if (fep == NULL) return -ENOMEM; __clear_user(fep,sizeof(*fep)); /* Create an Ethernet device instance. */ dev = init_etherdev(0, 0); fecp = &(immap->im_cpm.cp_fec); /* Whack a reset. We should wait for this. */ fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_RESET; for (i = 0; (fecp->fec_ecntrl & FEC_ECNTRL_RESET) && (i < FEC_RESET_DELAY); ++i) { udelay(1); } if (i == FEC_RESET_DELAY) { printk ("FEC Reset timeout!\n"); } /* Set the Ethernet address. If using multiple Enets on the 8xx, * this needs some work to get unique addresses. */ eap = (unsigned char *)my_enet_addr; iap = bd->bi_enet1addr;#ifdef CONFIG_SCC_ENET /* * If a board has Ethernet configured both on a SCC and the * FEC, it needs (at least) 2 MAC addresses (we know that Sun * disagrees, but anyway). For the FEC port, we create * another address by setting one of the address bits above * something that would have (up to now) been allocated. */ for (i=0; i<6; i++) tmpaddr[i] = *iap++; tmpaddr[3] |= 0x80; iap = tmpaddr;#endif for (i=0; i<6; i++) { dev->dev_addr[i] = *eap++ = *iap++; } /* Allocate memory for buffer descriptors. */ if (((RX_RING_SIZE + TX_RING_SIZE) * sizeof(cbd_t)) > PAGE_SIZE) { printk("FEC init error. Need more space.\n"); printk("FEC initialization failed.\n"); return 1; } mem_addr = __get_free_page(GFP_KERNEL); cbd_base = (cbd_t *)mem_addr; /* Make it uncached. */ pte = va_to_pte(mem_addr); pte_val(*pte) |= _PAGE_NO_CACHE; flush_tlb_page(init_mm.mmap, mem_addr); /* Set receive and transmit descriptor base. */ fep->rx_bd_base = cbd_base; fep->tx_bd_base = cbd_base + RX_RING_SIZE; fep->skb_cur = fep->skb_dirty = 0; /* Initialize the receive buffer descriptors. */ bdp = fep->rx_bd_base; for (i=0; i<FEC_ENET_RX_PAGES; i++) { /* Allocate a page. */ mem_addr = __get_free_page(GFP_KERNEL); /* Make it uncached. */ pte = va_to_pte(mem_addr); pte_val(*pte) |= _PAGE_NO_CACHE; flush_tlb_page(init_mm.mmap, mem_addr); /* Initialize the BD for every fragment in the page. */ for (j=0; j<FEC_ENET_RX_FRPPG; j++) { bdp->cbd_sc = BD_ENET_RX_EMPTY; bdp->cbd_bufaddr = __pa(mem_addr); mem_addr += FEC_ENET_RX_FRSIZE; bdp++; } } /* Set the last buffer to wrap. */ bdp--; bdp->cbd_sc |= BD_SC_WRAP;#ifdef CONFIG_FEC_PACKETHOOK fep->ph_lock = 0; fep->ph_rxhandler = fep->ph_txhandler = NULL; fep->ph_proto = 0; fep->ph_regaddr = NULL; fep->ph_priv = NULL;#endif /* Install our interrupt handler. */ if (request_8xxirq(FEC_INTERRUPT, fec_enet_interrupt, 0, "fec", dev) != 0) panic("Could not allocate FEC IRQ!"); dev->base_addr = (unsigned long)fecp; dev->priv = fep;#ifdef CONFIG_RPXCLASSIC/* If MDIO is disabled the PHY should not be allowed to * generate interrupts telling us to read the PHY. */# ifdef CONFIG_USE_MDIO /* Make Port C, bit 15 an input that causes interrupts. */ immap->im_ioport.iop_pcpar &= ~0x0001; immap->im_ioport.iop_pcdir &= ~0x0001; immap->im_ioport.iop_pcso &= ~0x0001; immap->im_ioport.iop_pcint |= 0x0001; cpm_install_handler(CPMVEC_PIO_PC15, mii_link_interrupt, dev);# endif /* CONFIG_USE_MDIO */ /* Make LEDS reflect Link status. */ *((uint *) RPX_CSR_ADDR) &= ~BCSR2_FETHLEDMODE;#endif /* CONFIG_RPXCLASSIC */#ifdef CONFIG_USE_MDIO# ifndef PHY_INTERRUPT# error Want to use MII, but PHY_INTERRUPT not defined!# endif ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_siel |= (0x80000000 >> PHY_INTERRUPT); if (request_8xxirq(PHY_INTERRUPT, mii_link_interrupt, 0, "mii", dev) != 0) panic("Could not allocate MII IRQ!");#endif /* CONFIG_USE_MDIO */ dev->base_addr = (unsigned long)fecp; dev->priv = fep; /* The FEC Ethernet specific entries in the device structure. */ dev->open = fec_enet_open; dev->hard_start_xmit = fec_enet_start_xmit; dev->tx_timeout = fec_timeout; dev->watchdog_timeo = TX_TIMEOUT; dev->stop = fec_enet_close; dev->get_stats = fec_enet_get_stats; dev->set_multicast_list = set_multicast_list;#ifdef CONFIG_USE_MDIO dev->do_ioctl = fec_enet_ioctl; for (i=0; i<NMII-1; i++) mii_cmds[i].mii_next = &mii_cmds[i+1]; mii_free = mii_cmds;#endif /* CONFIG_USE_MDIO */#ifndef CONFIG_ICU862 /* Configure all of port D for MII. */ immap->im_ioport.iop_pdpar = 0x1fff;#else /* Configure port A for MII. */ /* Has Utopia been configured? */ if (immap->im_ioport.iop_pdpar & (0x8000 >> 1)) { /* * YES - Use MUXED mode for UTOPIA bus. * This frees Port A for use by MII (see 862UM table 41-6). */ immap->im_ioport.utmode &= ~0x80; } else { /* * NO - set SPLIT mode for UTOPIA bus. * * This doesn't really effect UTOPIA (which isn't * enabled anyway) but just tells the 862 * to use port A for MII (see 862UM table 41-6). */ immap->im_ioport.utmode |= 0x80; }#ifdef CONFIG_USE_MDIO /* Now configure MII_MDC pin */ immap->im_ioport.iop_pdpar |= (0x8000 >> 8);#endif /* CONFIG_USE_MDIO */#endif /* CONFIG_ICU862 */ /* Bits moved from Rev. D onward. */ if ((_get_IMMR() & 0xffff) < 0x0501) immap->im_ioport.iop_pddir = 0x1c58; /* Pre rev. D */ else immap->im_ioport.iop_pddir = 0x1fff; /* Rev. D and later */#ifdef CONFIG_USE_MDIO /* Set MII speed to 2.5 MHz */ fecp->fec_mii_speed = fep->phy_speed = ( ( ((bd->bi_intfreq * 1000000) + 500000) / 2500000 / 2 ) & 0x3F ) << 1;#else fecp->fec_mii_speed = 0; /* turn off MDIO */#endif /* CONFIG_USE_MDIO */ printk ("%s: FEC ENET Version 0.2, FEC irq %d"#ifdef PHY_INTERRUPT ", MII irq %d"#endif ", addr ", dev->name, FEC_INTERRUPT#ifdef PHY_INTERRUPT , PHY_INTERRUPT#endif ); for (i=0; i<6; i++) printk("%02x%c", dev->dev_addr[i], (i==5) ? '\n' : ':');#ifdef CONFIG_USE_MDIO /* start in full duplex mode, and negotiate speed */ fec_restart (dev, 1);#else /* always use half duplex mode only */ fec_restart (dev, 0);#endif#ifdef CONFIG_USE_MDIO /* Queue up command to detect the PHY and initialize the * remainder of the interface. */ fep->phy_id_done = 0; fep->phy_addr = 0; mii_queue(dev, mk_mii_read(MII_REG_PHYIR1), mii_discover_phy, 0);#endif /* CONFIG_USE_MDIO */ return 0;}/* This function is called to start or restart the FEC during a link * change. This only happens when switching between half and full * duplex. */static voidfec_restart(struct net_device *dev, int duplex){ struct fec_enet_private *fep; int i; volatile cbd_t *bdp; volatile immap_t *immap; volatile fec_t *fecp; immap = (immap_t *)IMAP_ADDR; /* pointer to internal registers */ fecp = &(immap->im_cpm.cp_fec); fep = dev->priv; /* Whack a reset. We should wait for this. */ fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_RESET; for (i = 0; (fecp->fec_ecntrl & FEC_ECNTRL_RESET) && (i < FEC_RESET_DELAY); ++i) { udelay(1); } if (i == FEC_RESET_DELAY) { printk ("FEC Reset timeout!\n"); } /* Set station address. */ fecp->fec_addr_low = (my_enet_addr[0] << 16) | my_enet_addr[1]; fecp->fec_addr_high = my_enet_addr[2]; /* Reset all multicast. */ fecp->fec_hash_table_high = 0; fecp->fec_hash_table_low = 0; /* Set maximum receive buffer size. */ fecp->fec_r_buff_size = PKT_MAXBLR_SIZE; fecp->fec_r_hash = PKT_MAXBUF_SIZE; /* Set receive and transmit descriptor base. */ fecp->fec_r_des_start = __pa((uint)(fep->rx_bd_base)); fecp->fec_x_des_start = __pa((uint)(fep->tx_bd_base)); fep->dirty_tx = fep->cur_tx = fep->tx_bd_base; fep->cur_rx = fep->rx_bd_base; /* Reset SKB transmit 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; } } /* Initialize the receive buffer descriptors. */ bdp = fep->rx_bd_base; for (i=0; i<RX_RING_SIZE; i++) { /* Initialize the BD for every fragment in the page. */ bdp->cbd_sc = BD_ENET_RX_EMPTY; bdp++; } /* Set the last buffer to wrap. */ bdp--; bdp->cbd_sc |= BD_SC_WRAP; /* ...and the same for transmmit. */ bdp = fep->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_bufaddr = 0; bdp++; } /* Set the last buffer to wrap. */ bdp--; bdp->cbd_sc |= BD_SC_WRAP; /* Enable MII mode. */ if (duplex) { fecp->fec_r_cntrl = FEC_RCNTRL_MII_MODE; /* MII enable */ fecp->fec_x_cntrl = FEC_TCNTRL_FDEN; /* FD enable */ } else { fecp->fec_r_cntrl = FEC_RCNTRL_MII_MODE | FEC_RCNTRL_DRT; fecp->fec_x_cntrl = 0; } fep->full_duplex = duplex; /* Enable big endian and don't care about SDMA FC. */ fecp->fec_fun_code = 0x78000000;#ifdef CONFIG_USE_MDIO /* Set MII speed. */ fecp->fec_mii_speed = fep->phy_speed;#endif /* CONFIG_USE_MDIO */ /* Clear any outstanding interrupt. */ fecp->fec_ievent = 0xffc0; fecp->fec_ivec = (FEC_INTERRUPT/2) << 29; /* Enable interrupts we wish to service. */ fecp->fec_imask = ( FEC_ENET_TXF | FEC_ENET_TXB | FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII ); /* And last, enable the transmit and receive processing. */ fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN; fecp->fec_r_des_active = 0x01000000; /* The tx ring is no longer full. */ if (fep->tx_full) { fep->tx_full = 0; netif_wake_queue(dev); }}static voidfec_stop(struct net_device *dev){ volatile immap_t *immap; volatile fec_t *fecp; struct fec_enet_private *fep; int i; immap = (immap_t *)IMAP_ADDR; /* pointer to internal registers */ fecp = &(immap->im_cpm.cp_fec); if ((fecp->fec_ecntrl & FEC_ECNTRL_ETHER_EN) == 0) return; /* already down */ fep = dev->priv; fecp->fec_x_cntrl = 0x01; /* Graceful transmit stop */ for (i = 0; ((fecp->fec_ievent & 0x10000000) == 0) && (i < FEC_RESET_DELAY); ++i) { udelay(1); } if (i == FEC_RESET_DELAY) { printk ("FEC timeout on graceful transmit stop\n"); } /* Clear outstanding MII command interrupts. */ fecp->fec_ievent = FEC_ENET_MII; /* Enable MII command finished interrupt */ fecp->fec_ivec = (FEC_INTERRUPT/2) << 29; fecp->fec_imask = FEC_ENET_MII;#ifdef CONFIG_USE_MDIO /* Set MII speed. */ fecp->fec_mii_speed = fep->phy_speed;#endif /* CONFIG_USE_MDIO */ /* Disable FEC */ fecp->fec_ecntrl &= ~(FEC_ECNTRL_ETHER_EN);}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -