⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fec.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 3 页
字号:
	}	else		fec_stop(dev);#if 0	enable_irq(fep->mii_irq);#endif}static void mii_queue_relink(uint mii_reg, struct net_device *dev){	struct fec_enet_private *fep = dev->priv;	fep->phy_task.routine = (void *)mii_relink;	fep->phy_task.data = dev;	schedule_task(&fep->phy_task);}static void mii_queue_config(uint mii_reg, struct net_device *dev){	struct fec_enet_private *fep = dev->priv;	fep->phy_task.routine = (void *)mii_display_config;	fep->phy_task.data = dev;	schedule_task(&fep->phy_task);}phy_cmd_t phy_cmd_relink[] = { { mk_mii_read(MII_REG_CR), mii_queue_relink },			       { mk_mii_end, } };phy_cmd_t phy_cmd_config[] = { { mk_mii_read(MII_REG_CR), mii_queue_config },			       { mk_mii_end, } };/* Read remainder of PHY ID.*/static voidmii_discover_phy3(uint mii_reg, struct net_device *dev){	struct fec_enet_private *fep;	int	i;	fep = dev->priv;	fep->phy_id |= (mii_reg & 0xffff);	printk("fec: Phy @ 0x%x, type 0x%08x\n", fep->phy_addr, fep->phy_id);	for(i = 0; phy_info[i]; i++)		if(phy_info[i]->id == (fep->phy_id >> 4))			break;	if(!phy_info[i])		panic("%s: PHY id 0x%08x is not supported!\n", 		      dev->name, fep->phy_id);      	fep->phy = phy_info[i];	fep->phy_id_done = 1;}/* Scan all of the MII PHY addresses looking for someone to respond * with a valid ID.  This usually happens quickly. */static voidmii_discover_phy(uint mii_reg, struct net_device *dev){	struct fec_enet_private *fep;	uint	phytype;	fep = dev->priv;	if (fep->phy_addr < 32) {		if ((phytype = (mii_reg & 0xffff)) != 0xffff) {						/* Got first part of ID, now get remainder.			*/			fep->phy_id = phytype << 16;			mii_queue(dev, mk_mii_read(MII_REG_PHYIR2),							mii_discover_phy3);		}		else {			fep->phy_addr++;			mii_queue(dev, mk_mii_read(MII_REG_PHYIR1),							mii_discover_phy);		}	}	else {		printk("FEC: No PHY device found.\n");	}}/* This interrupt occurs when the PHY detects a link change.*/static void#ifdef CONFIG_RPXCLASSICmii_link_interrupt(void *dev_id)#elsemii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs)#endif{	struct	net_device *dev = dev_id;	struct fec_enet_private *fep = dev->priv;#if 0	disable_irq(fep->mii_irq);  /* disable now, enable later */#endif	mii_do_cmd(dev, fep->phy->ack_int);	mii_do_cmd(dev, phy_cmd_relink);  /* restart and display status */}static intfec_enet_open(struct net_device *dev){	struct fec_enet_private *fep = dev->priv;	/* I should reset the ring buffers here, but I don't yet know	 * a simple way to do that.	 */	fep->sequence_done = 0;	fep->link = 0;	if (fep->phy) {		mii_do_cmd(dev, fep->phy->ack_int);		mii_do_cmd(dev, fep->phy->config);		mii_do_cmd(dev, phy_cmd_config);  /* display configuration */		while(!fep->sequence_done)			schedule();		mii_do_cmd(dev, fep->phy->startup);		netif_start_queue(dev);		return 0;		/* Success */	}	return -ENODEV;		/* No PHY we understand */}static intfec_enet_close(struct net_device *dev){	/* Don't know what to do yet.	*/	netif_stop_queue(dev);	fec_stop(dev);	return 0;}static struct net_device_stats *fec_enet_get_stats(struct net_device *dev){	struct fec_enet_private *fep = (struct fec_enet_private *)dev->priv;	return &fep->stats;}/* Set or clear the multicast filter for this adaptor. * Skeleton taken from sunlance driver. * The CPM Ethernet implementation allows Multicast as well as individual * MAC address filtering.  Some of the drivers check to make sure it is * a group multicast address, and discard those that are not.  I guess I * will do the same for now, but just remove the test if you want * individual filtering as well (do the upper net layers want or support * this kind of feature?). */static void set_multicast_list(struct net_device *dev){	struct	fec_enet_private *fep;	volatile fec_t *ep;	fep = (struct fec_enet_private *)dev->priv;	ep = &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec);	if (dev->flags&IFF_PROMISC) {	  		/* Log any net taps. */		printk("%s: Promiscuous mode enabled.\n", dev->name);		ep->fec_r_cntrl |= 0x0008;	} else {		ep->fec_r_cntrl &= ~0x0008;		if (dev->flags & IFF_ALLMULTI) {			/* Catch all multicast addresses, so set the			 * filter to all 1's.			 */			ep->fec_hash_table_high = 0xffffffff;			ep->fec_hash_table_low = 0xffffffff;		}#if 0		else {			/* Clear filter and add the addresses in the list.			*/			ep->sen_gaddr1 = 0;			ep->sen_gaddr2 = 0;			ep->sen_gaddr3 = 0;			ep->sen_gaddr4 = 0;			dmi = dev->mc_list;			for (i=0; i<dev->mc_count; i++) {								/* 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_RPXCLASSIC	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);	__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 = 1;	udelay(10);	/* 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_enetaddr;#ifdef CONFIG_RPXCLASSIC	/* The Embedded Planet boards have only one MAC address in	 * the EEPROM, but can have two Ethernet ports.  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->dirty_tx = fep->cur_tx = fep->tx_bd_base;	fep->cur_rx = fep->rx_bd_base;	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!");#ifdef CONFIG_RPXCLASSIC	/* 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);	/* Make LEDS reflect Link status.	*/	*((uint *) RPX_CSR_ADDR) &= ~BCSR2_FETHLEDMODE;#endif#ifdef CONFIG_FADS	if (request_8xxirq(SIU_IRQ2, mii_link_interrupt, 0, "mii", dev) != 0)		panic("Could not allocate MII IRQ!");#endif	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;	for (i=0; i<NMII-1; i++)		mii_cmds[i].mii_next = &mii_cmds[i+1];	mii_free = mii_cmds;	/* Configure all of port D for MII.	*/	immap->im_ioport.iop_pdpar = 0x1fff;	/* 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 */		/* Set MII speed to 2.5 MHz	*/	fecp->fec_mii_speed = fep->phy_speed = 		((bd->bi_busfreq * 1000000) / 2500000) & 0x7e;	printk("%s: FEC ENET Version 0.2, ", dev->name);	for (i=0; i<5; i++)		printk("%02x:", dev->dev_addr[i]);	printk("%02x\n", dev->dev_addr[5]);	/* 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);	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;	unsigned char	*eap;	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 = 1;	udelay(10);	/* Enable interrupts we wish to service.	*/	fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB |				FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII);	/* Clear any outstanding interrupt.	*/	fecp->fec_ievent = 0xffc0;	fecp->fec_ivec = (FEC_INTERRUPT/2) << 29;	/* Set station address.	*/	fecp->fec_addr_low = (my_enet_addr[0] << 16) | my_enet_addr[1];	fecp->fec_addr_high = my_enet_addr[2];	eap = (unsigned char *)&my_enet_addr[0];	for (i=0; i<6; i++)		dev->dev_addr[i] = *eap++;	/* 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 = 0x04;	/* MII enable */		fecp->fec_x_cntrl = 0x04;	/* FD enable */	}	else {		fecp->fec_r_cntrl = 0x06;	/* MII enable|No Rcv on Xmit */		fecp->fec_x_cntrl = 0x00;	}	fep->full_duplex = duplex;	/* Enable big endian and don't care about SDMA FC.	*/	fecp->fec_fun_code = 0x78000000;	/* Set MII speed.	*/	fecp->fec_mii_speed = fep->phy_speed;	/* And last, enable the transmit and receive processing.	*/	fecp->fec_ecntrl = 6;	fecp->fec_r_des_active = 0x01000000;}static voidfec_stop(struct net_device *dev){	volatile	immap_t	*immap;	volatile	fec_t	*fecp;	struct fec_enet_private *fep;	immap = (immap_t *)IMAP_ADDR;	/* pointer to internal registers */		fecp = &(immap->im_cpm.cp_fec);		fep = dev->priv;	fecp->fec_x_cntrl = 0x01;	/* Graceful transmit stop */	while(!(fecp->fec_ievent & 0x10000000));	/* Whack a reset.  We should wait for this.	*/	fecp->fec_ecntrl = 1;	udelay(10);	/* Clear outstanding MII command interrupts.	*/	fecp->fec_ievent = FEC_ENET_MII;	/* Enable MII command finihed interrupt 	*/	fecp->fec_ivec = (FEC_INTERRUPT/2) << 29;	fecp->fec_imask = FEC_ENET_MII;	/* Set MII speed.	*/	fecp->fec_mii_speed = fep->phy_speed;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -