📄 fcc_enet.c
字号:
if (s & PHY_STAT_FAULT) printk(", remote fault"); printk(".\n");}static void mii_display_config(void *data){ struct net_device *dev = data; volatile struct fcc_enet_private *fep = dev->priv; 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 fcc_enet_private *fep = dev->priv; int duplex = 0; fep->old_link = fep->link; fep->link = (fep->phy_status & PHY_STAT_LINK) ? 1 : 0;#ifdef MDIO_DEBUG printk(" mii_relink: link=%d\n", fep->link);#endif if (fep->link) { if (fep->phy_status & (PHY_STAT_100FDX | PHY_STAT_10FDX)) duplex = 1; fcc_restart(dev, duplex);#ifdef MDIO_DEBUG printk(" mii_relink: duplex=%d\n", duplex);#endif }}static void mii_queue_relink(uint mii_reg, struct net_device *dev){ struct fcc_enet_private *fep = dev->priv; mii_relink(dev); schedule_work(&fep->phy_relink);}static void mii_queue_config(uint mii_reg, struct net_device *dev){ struct fcc_enet_private *fep = dev->priv; schedule_work(&fep->phy_display_config);}phy_cmd_t phy_cmd_relink[] = { { mk_mii_read(MII_BMCR), mii_queue_relink }, { mk_mii_end, } };phy_cmd_t phy_cmd_config[] = { { mk_mii_read(MII_BMCR), mii_queue_config }, { mk_mii_end, } };/* Read remainder of PHY ID.*/static voidmii_discover_phy3(uint mii_reg, struct net_device *dev){ struct fcc_enet_private *fep; int i; fep = dev->priv; printk("mii_reg: %08x\n", mii_reg); fep->phy_id |= (mii_reg & 0xffff); for(i = 0; phy_info[i]; i++) if((phy_info[i]->id == (fep->phy_id >> 4)) || !phy_info[i]->id) 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; printk("%s: Phy @ 0x%x, type %s (0x%08x)\n", dev->name, fep->phy_addr, fep->phy->name, fep->phy_id);}/* 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 fcc_enet_private *fep; uint phytype; fep = dev->priv; 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_PHYSID2), mii_discover_phy3); } else { fep->phy_addr++; if (fep->phy_addr < 32) { mii_queue(dev, mk_mii_read(MII_PHYSID1), mii_discover_phy); } else { printk("fec: No PHY device found.\n"); } }}#endif /* CONFIG_USE_MDIO */#ifdef PHY_INTERRUPT/* This interrupt occurs when the PHY detects a link change. */static irqreturn_tmii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs){ struct net_device *dev = dev_id; struct fcc_enet_private *fep = dev->priv; fcc_info_t *fip = fep->fip; if (fep->phy) { /* We don't want to be interrupted by an FCC * interrupt here. */ disable_irq_nosync(fip->fc_interrupt); mii_do_cmd(dev, fep->phy->ack_int); /* restart and display status */ mii_do_cmd(dev, phy_cmd_relink); enable_irq(fip->fc_interrupt); } return IRQ_HANDLED;}#endif /* ifdef PHY_INTERRUPT */#if 0 /* This should be fixed someday *//* 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 voidset_multicast_list(struct net_device *dev){ struct fcc_enet_private *cep; struct dev_mc_list *dmi; u_char *mcptr, *tdptr; volatile fcc_enet_t *ep; int i, j; cep = (struct fcc_enet_private *)dev->priv;return; /* Get pointer to FCC area in parameter RAM. */ ep = (fcc_enet_t *)dev->base_addr; if (dev->flags&IFF_PROMISC) { /* Log any net taps. */ printk("%s: Promiscuous mode enabled.\n", dev->name); cep->fccp->fcc_fpsmr |= FCC_PSMR_PRO; } else { cep->fccp->fcc_fpsmr &= ~FCC_PSMR_PRO; if (dev->flags & IFF_ALLMULTI) { /* Catch all multicast addresses, so set the * filter to all 1's. */ ep->fen_gaddrh = 0xffffffff; ep->fen_gaddrl = 0xffffffff; } else { /* Clear filter and add the addresses in the list. */ ep->fen_gaddrh = 0; ep->fen_gaddrl = 0; dmi = dev->mc_list; for (i=0; i<dev->mc_count; i++, dmi = dmi->next) { /* 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->fen_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(cep->fip->fc_cpmpage, cep->fip->fc_cpmblock, 0x0c, CPM_CR_SET_GADDR) | CPM_CR_FLG; udelay(10); while (cpmp->cp_cpcr & CPM_CR_FLG); } } }}#endif /* if 0 *//* Set the individual MAC address. */int fcc_enet_set_mac_address(struct net_device *dev, void *p){ struct sockaddr *addr= (struct sockaddr *) p; struct fcc_enet_private *cep; volatile fcc_enet_t *ep; unsigned char *eap; int i; cep = (struct fcc_enet_private *)(dev->priv); ep = cep->ep; if (netif_running(dev)) return -EBUSY; memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); eap = (unsigned char *) &(ep->fen_paddrh); for (i=5; i>=0; i--) *eap++ = addr->sa_data[i]; return 0;}/* Initialize the CPM Ethernet on FCC. */static int __init fec_enet_init(void){ struct net_device *dev; struct fcc_enet_private *cep; fcc_info_t *fip; int i, np, err; volatile cpm2_map_t *immap; volatile iop_cpm2_t *io; immap = (cpm2_map_t *)CPM_MAP_ADDR; /* and to internal registers */ io = &immap->im_ioport; np = sizeof(fcc_ports) / sizeof(fcc_info_t); fip = fcc_ports; while (np-- > 0) { /* Create an Ethernet device instance. */ dev = alloc_etherdev(sizeof(*cep)); if (!dev) return -ENOMEM; cep = dev->priv; spin_lock_init(&cep->lock); cep->fip = fip; init_fcc_shutdown(fip, cep, immap); init_fcc_ioports(fip, io, immap); init_fcc_param(fip, dev, immap); dev->base_addr = (unsigned long)(cep->ep); /* The CPM Ethernet specific entries in the device * structure. */ dev->open = fcc_enet_open; dev->hard_start_xmit = fcc_enet_start_xmit; dev->tx_timeout = fcc_enet_timeout; dev->watchdog_timeo = TX_TIMEOUT; dev->stop = fcc_enet_close; dev->get_stats = fcc_enet_get_stats; /* dev->set_multicast_list = set_multicast_list; */ dev->set_mac_address = fcc_enet_set_mac_address; init_fcc_startup(fip, dev); err = register_netdev(dev); if (err) { free_netdev(dev); return err; } printk("%s: FCC ENET Version 0.3, ", dev->name); for (i=0; i<5; i++) printk("%02x:", dev->dev_addr[i]); printk("%02x\n", dev->dev_addr[5]);#ifdef CONFIG_USE_MDIO /* Queue up command to detect the PHY and initialize the * remainder of the interface. */ cep->phy_id_done = 0; cep->phy_addr = fip->fc_phyaddr; mii_queue(dev, mk_mii_read(MII_PHYSID1), mii_discover_phy); INIT_WORK(&cep->phy_relink, mii_display_status, dev); INIT_WORK(&cep->phy_display_config, mii_display_config, dev);#endif /* CONFIG_USE_MDIO */ fip++; } return 0;}module_init(fec_enet_init);/* Make sure the device is shut down during initialization.*/static void __initinit_fcc_shutdown(fcc_info_t *fip, struct fcc_enet_private *cep, volatile cpm2_map_t *immap){ volatile fcc_enet_t *ep; volatile fcc_t *fccp; /* Get pointer to FCC area in parameter RAM. */ ep = (fcc_enet_t *)(&immap->im_dprambase[fip->fc_proff]); /* And another to the FCC register area. */ fccp = (volatile fcc_t *)(&immap->im_fcc[fip->fc_fccnum]); cep->fccp = fccp; /* Keep the pointers handy */ cep->ep = ep; /* Disable receive and transmit in case someone left it running. */ fccp->fcc_gfmr &= ~(FCC_GFMR_ENR | FCC_GFMR_ENT);}/* Initialize the I/O pins for the FCC Ethernet.*/static void __initinit_fcc_ioports(fcc_info_t *fip, volatile iop_cpm2_t *io, volatile cpm2_map_t *immap){ /* FCC1 pins are on port A/C. FCC2/3 are port B/C. */ if (fip->fc_proff == PROFF_FCC1) { /* Configure port A and C pins for FCC1 Ethernet. */ io->iop_pdira &= ~PA1_DIRA_BOUT; io->iop_pdira |= PA1_DIRA_BIN; io->iop_psora &= ~PA1_PSORA_BOUT; io->iop_psora |= PA1_PSORA_BIN; io->iop_ppara |= (PA1_DIRA_BOUT | PA1_DIRA_BIN); } if (fip->fc_proff == PROFF_FCC2) { /* Configure port B and C pins for FCC Ethernet. */ io->iop_pdirb &= ~PB2_DIRB_BOUT; io->iop_pdirb |= PB2_DIRB_BIN; io->iop_psorb &= ~PB2_PSORB_BOUT; io->iop_psorb |= PB2_PSORB_BIN; io->iop_pparb |= (PB2_DIRB_BOUT | PB2_DIRB_BIN); } if (fip->fc_proff == PROFF_FCC3) { /* Configure port B and C pins for FCC Ethernet. */ io->iop_pdirb &= ~PB3_DIRB_BOUT; io->iop_pdirb |= PB3_DIRB_BIN; io->iop_psorb &= ~PB3_PSORB_BOUT; io->iop_psorb |= PB3_PSORB_BIN; io->iop_pparb |= (PB3_DIRB_BOUT | PB3_DIRB_BIN); io->iop_pdirc &= ~PC3_DIRC_BOUT; io->iop_pdirc |= PC3_DIRC_BIN; io->iop_psorc &= ~PC3_PSORC_BOUT; io->iop_psorc |= PC3_PSORC_BIN; io->iop_pparc |= (PC3_DIRC_BOUT | PC3_DIRC_BIN); } /* Port C has clocks...... */ io->iop_psorc &= ~(fip->fc_trxclocks); io->iop_pdirc &= ~(fip->fc_trxclocks); io->iop_pparc |= fip->fc_trxclocks;#ifdef CONFIG_USE_MDIO /* ....and the MII serial clock/data. */ io->iop_pdatc |= (fip->fc_mdio | fip->fc_mdck); io->iop_podrc &= ~(fip->fc_mdio | fip->fc_mdck); io->iop_pdirc |= (fip->fc_mdio | fip->fc_mdck); io->iop_pparc &= ~(fip->fc_mdio | fip->fc_mdck);#endif /* CONFIG_USE_MDIO */ /* Configure Serial Interface clock routing. * First, clear all FCC bits to zero, * then set the ones we want. */ immap->im_cpmux.cmx_fcr &= ~(fip->fc_clockmask); immap->im_cpmux.cmx_fcr |= fip->fc_clockroute;}static void __initinit_fcc_param(fcc_info_t *fip, struct net_device *dev, volatile cpm2_map_t *immap){ unsigned char *eap; unsigned long mem_addr; bd_t *bd; int i, j; struct fcc_enet_private *cep; volatile fcc_enet_t *ep; volatile cbd_t *bdp; volatile cpm_cpm2_t *cp; cep = (struct fcc_enet_private *)(dev->priv); ep = cep->ep; cp = cpmp; bd = (bd_t *)__res; /* Zero the whole thing.....I must have missed some individually. * It works when I do this. */ memset((char *)ep, 0, sizeof(fcc_enet_t)); /* Allocate space for the buffer descriptors from regular memory. * Initialize base addresses for the buffer descriptors. */ cep->rx_bd_base = (cbd_t *)kmalloc(sizeof(cbd_t) * RX_RING_SIZE, GFP_KERNEL | GFP_DMA); ep->fen_genfcc.fcc_rbase = __pa(cep->rx_bd_base); cep->tx_bd_base = (cbd_t *)kmalloc(sizeof(cbd_t) * TX_RING_SIZE, GFP_KERNEL | GFP_DMA); ep->fen_genfcc.fcc_tbase = __pa(cep->tx_bd_base); cep->dirty_tx = cep->cur_tx = cep->tx_bd_base; cep->cur_rx = cep->rx_bd_base;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -