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 + -
显示快捷键?