fec.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,975 行 · 第 1/4 页

C
1,975
字号
	*s &= ~(PHY_STAT_SPMASK | PHY_STAT_ANC);	if (mii_reg & 0x0080)		*s |= PHY_STAT_ANC;	if (mii_reg & 0x0400)		*s |= ((mii_reg & 0x0800) ? PHY_STAT_100FDX : PHY_STAT_100HDX);	else		*s |= ((mii_reg & 0x0800) ? PHY_STAT_10FDX : PHY_STAT_10HDX);}static phy_info_t phy_info_am79c874 = {	0x00022561, 	"AM79C874",		(const phy_cmd_t []) {  /* config */  		/* limit to 10MBit because my protorype board 		 * doesn't work with 100. */		{ mk_mii_read(MII_REG_CR), mii_parse_cr },		{ mk_mii_read(MII_REG_ANAR), mii_parse_anar },		{ mk_mii_read(MII_AM79C874_DR), mii_parse_am79c874_dr },		{ mk_mii_end, }	},	(const phy_cmd_t []) {  /* startup - enable interrupts */		{ mk_mii_write(MII_AM79C874_ICSR, 0xff00), NULL },		{ mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */		{ 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_AM79C874_DR), mii_parse_am79c874_dr },		/* we only need to read ISR to acknowledge */		{ mk_mii_read(MII_AM79C874_ICSR), NULL },		{ mk_mii_end, }	},	(const phy_cmd_t []) {  /* shutdown - disable interrupts */		{ mk_mii_write(MII_AM79C874_ICSR, 0x0000), NULL },		{ mk_mii_end, }	},};/* ------------------------------------------------------------------------- */static phy_info_t *phy_info[] = {	&phy_info_lxt970,	&phy_info_lxt971,	&phy_info_qs6612,	&phy_info_am79c874,	NULL};/* ------------------------------------------------------------------------- */static void#ifdef CONFIG_RPXCLASSICmii_link_interrupt(void *dev_id);#elsemii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs);#endif#ifdef CONFIG_M5272/* *	Code specific to Coldfire 5272 setup. */static void __inline__ fec_request_intrs(struct net_device *dev, volatile fec_t *fecp){	volatile unsigned long *icrp;	/* Setup interrupt handlers. */	if (request_irq(86, fec_enet_interrupt, 0, "fec(RX)", dev) != 0)		printk("FEC: Could not allocate FEC(RC) IRQ(86)!\n");	if (request_irq(87, fec_enet_interrupt, 0, "fec(TX)", dev) != 0)		printk("FEC: Could not allocate FEC(RC) IRQ(87)!\n");	if (request_irq(88, fec_enet_interrupt, 0, "fec(OTHER)", dev) != 0)		printk("FEC: Could not allocate FEC(OTHER) IRQ(88)!\n");	if (request_irq(66, mii_link_interrupt, 0, "fec(MII)", dev) != 0)		printk("FEC: Could not allocate MII IRQ(66)!\n");	/* Unmask interrupt at ColdFire 5272 SIM */	icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR3);	*icrp = 0x00000ddd;	icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1);	*icrp = (*icrp & 0x70777777) | 0x0d000000;}static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep){	volatile fec_t *fecp;	fecp = fec_hwp;	fecp->fec_r_cntrl = 0x04;	fecp->fec_x_cntrl = 0x00;	/* Set MII speed to 2.5 MHz	*/	fecp->fec_mii_speed = fep->phy_speed = 0x0e;	fec_restart(dev, 0);}static void __inline__ fec_get_mac(struct net_device *dev, struct fec_enet_private *fep){	volatile fec_t *fecp;	unsigned char *eap, *iap, tmpaddr[6];	int i;	fecp = fec_hwp;	eap = (unsigned char *) my_enet_addr;	if (fec_flashmac) {		/*		 * Get MAC address from FLASH.		 * If it is all 1's or 0's, use the default.		 */		iap = fec_flashmac;		if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) &&		    (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0))			iap = eap;		if ((iap[0] == 0xff) && (iap[1] == 0xff) && (iap[2] == 0xff) &&		    (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff))			iap = eap;	} else {		*((unsigned long *) &tmpaddr[0]) = fecp->fec_addr_low;		*((unsigned short *) &tmpaddr[4]) = (fecp->fec_addr_high >> 16);		iap = &tmpaddr[0];	}	for (i=0; i<6; i++)		dev->dev_addr[i] = *eap++ = *iap++;}static void __inline__ fec_enable_phy_intr(void){}static void __inline__ fec_disable_phy_intr(void){	volatile unsigned long *icrp;	icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1);	*icrp = (*icrp & 0x70777777) | 0x08000000;}static void __inline__ fec_phy_ack_intr(void){	volatile unsigned long *icrp;	/* Acknowledge the interrupt */	icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1);	*icrp = (*icrp & 0x77777777) | 0x08000000;}static void __inline__ fec_localhw_setup(void){}/* *	Do not need to make region uncached on 5272. */static void __inline__ fec_uncache(unsigned long addr){}/* ------------------------------------------------------------------------- */#else/* *	Code sepcific to the MPC860T setup. */static void __inline__ fec_request_intrs(struct net_device *dev, volatile fec_t *fecp){	volatile immap_t *immap;	immap = (immap_t *)IMAP_ADDR;	/* pointer to internal registers */	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}static void __inline__ fec_get_mac(struct net_device *dev, struct fec_enet_private *fep){	unsigned char *eap, *iap, tmpaddr[6];	bd_t *bd;	int i;	eap = (unsigned char *)my_enet_addr;	iap = bd->bi_enetaddr;	bd = (bd_t *)__res;#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++;}static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep){	extern uint _get_IMMR(void);	volatile immap_t *immap;	volatile fec_t *fecp;	fecp = fec_hwp;	immap = (immap_t *)IMAP_ADDR;	/* pointer to internal registers */	/* 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;}static void __inline__ fec_enable_phy_intr(void){	volatile fec_t *fecp;	fecp = fec_hwp;	/* Enable MII command finished interrupt 	*/	fecp->fec_ivec = (FEC_INTERRUPT/2) << 29;}static void __inline__ fec_disable_phy_intr(void){}static void __inline__ fec_phy_ack_intr(void){}static void __inline__ fec_localhw_setup(void){	volatile fec_t *fecp;	fecp = fec_hwp;	fecp->fec_r_hash = PKT_MAXBUF_SIZE;	/* Enable big endian and don't care about SDMA FC.	*/	fecp->fec_fun_code = 0x78000000;}static void __inline__ fec_uncache(unsigned long addr){	pte_t *pte;	pte = va_to_pte(mem_addr);	pte_val(*pte) |= _PAGE_NO_CACHE;	flush_tlb_page(init_mm.mmap, mem_addr);}#endif/* ------------------------------------------------------------------------- */static void mii_display_status(struct net_device *dev){	struct fec_enet_private *fep = netdev_priv(dev);	volatile uint *s = &(fep->phy_status);	if (!fep->link && !fep->old_link) {		/* Link is still down - don't print anything */		return;	}	printk("%s: status: ", dev->name);	if (!fep->link) {		printk("link down");	} else {		printk("link up");		switch(*s & PHY_STAT_SPMASK) {		case PHY_STAT_100FDX: printk(", 100MBit Full Duplex"); break;		case PHY_STAT_100HDX: printk(", 100MBit Half Duplex"); break;		case PHY_STAT_10FDX: printk(", 10MBit Full Duplex"); break;		case PHY_STAT_10HDX: printk(", 10MBit Half Duplex"); break;		default:			printk(", Unknown speed/duplex");		}		if (*s & PHY_STAT_ANC)			printk(", auto-negotiation complete");	}	if (*s & PHY_STAT_FAULT)		printk(", remote fault");	printk(".\n");}static void mii_display_config(struct net_device *dev){	struct fec_enet_private *fep = netdev_priv(dev);	volatile uint *s = &(fep->phy_status);	printk("%s: config: auto-negotiation ", dev->name);	if (*s & PHY_CONF_ANE)		printk("on");	else		printk("off");	if (*s & PHY_CONF_100FDX)		printk(", 100FDX");	if (*s & PHY_CONF_100HDX)		printk(", 100HDX");	if (*s & PHY_CONF_10FDX)		printk(", 10FDX");	if (*s & PHY_CONF_10HDX)		printk(", 10HDX");	if (!(*s & PHY_CONF_SPMASK))		printk(", No speed/duplex selected?");	if (*s & PHY_CONF_LOOP)		printk(", loopback enabled");		printk(".\n");	fep->sequence_done = 1;}static void mii_relink(struct net_device *dev){	struct fec_enet_private *fep = netdev_priv(dev);	int duplex;	fep->link = (fep->phy_status & PHY_STAT_LINK) ? 1 : 0;	mii_display_status(dev);	fep->old_link = fep->link;	if (fep->link) {		duplex = 0;		if (fep->phy_status 		    & (PHY_STAT_100FDX | PHY_STAT_10FDX))			duplex = 1;		fec_restart(dev, duplex);	}	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 = netdev_priv(dev);	INIT_WORK(&fep->phy_task, (void*)mii_relink, dev);	schedule_work(&fep->phy_task);}static void mii_queue_config(uint mii_reg, struct net_device *dev){	struct fec_enet_private *fep = netdev_priv(dev);	INIT_WORK(&fep->phy_task, (void*)mii_display_config, dev);	schedule_work(&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 = netdev_priv(dev);	fep->phy_id |= (mii_reg & 0xffff);	printk("fec: PHY @ 0x%x, ID 0x%08x", 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])		printk(" -- %s\n", phy_info[i]->name);	else		printk(" -- unknown PHY!\n");      	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;	volatile fec_t *fecp;	uint phytype;	fep = netdev_priv(dev);	fecp = fec_hwp;	if (fep->phy_addr < 32) {		if ((phytype = (mii_reg & 0xffff)) != 0xffff && phytype != 0) {						/* 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");		/* Disable external MII interface */		fecp->fec_mii_speed = fep->phy_speed = 0;		fec_disable_phy_intr();	}}/* 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 = netdev_priv(dev);	fec_phy_ack_intr();#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 int

⌨️ 快捷键说明

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