?? fec.c
字號:
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 = dev->priv; 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); if (netif_queue_stopped(dev)) { netif_wake_queue(dev); } } else { netif_stop_queue(dev); fec_stop(dev); }}static void mii_queue_relink(uint mii_reg, struct net_device *dev, uint data){ 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, uint data){ 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, uint data){ struct fec_enet_private *fep; int i; fep = dev->priv; fep->phy_id |= (mii_reg & 0xffff); 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; 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, uint data){ struct fec_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_REG_PHYIR2), mii_discover_phy3, 0); } else { fep->phy_addr++; if (fep->phy_addr < 32) { mii_queue (dev, mk_mii_read(MII_REG_PHYIR1), mii_discover_phy, 0); } else { printk("fec: No PHY device found.\n"); } }}#endif /* CONFIG_USE_MDIO *//* 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{#ifdef CONFIG_USE_MDIO struct net_device *dev = dev_id; struct fec_enet_private *fep = dev->priv; volatile immap_t *immap = (immap_t *)IMAP_ADDR; volatile fec_t *fecp = &(immap->im_cpm.cp_fec); unsigned int ecntrl = fecp->fec_ecntrl; /* * Acknowledge the interrupt if possible. If we have not * found the PHY yet we can't process or acknowledge the * interrupt now. Instead we ignore this interrupt for now, * which we can do since it is edge triggered. It will be * acknowledged later by fec_enet_open(). */ if (fep->phy) { /* * We need the FEC enabled to access the MII */ if ((ecntrl & FEC_ECNTRL_ETHER_EN) == 0) { fecp->fec_ecntrl |= FEC_ECNTRL_ETHER_EN; } mii_do_cmd(dev, fep->phy->ack_int); mii_do_cmd(dev, phy_cmd_relink); /* restart and display status */ if ((ecntrl & FEC_ECNTRL_ETHER_EN) == 0) { fecp->fec_ecntrl = ecntrl; /* restore old settings */ } }#else printk ("FEC: unexpected Link interrupt\n");#endif /* CONFIG_USE_MDIO */}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. */#ifdef CONFIG_USE_MDIO 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);#if defined(CONFIG_USE_MDIO) && defined(CONFIG_FEC_DP83846A) if(fep->phy == &phy_info_dp83846a) { /* Initializing timers */ init_timer( &fep->phy_timer_list ); /* Starting timer for periodic link status check * After 100 milli-seconds, mdio_timer_callback function is called. */ fep->phy_timer_list.expires = jiffies + (100 * HZ / 1000); fep->phy_timer_list.data = (unsigned long)dev; fep->phy_timer_list.function = mdio_timer_callback; add_timer( &fep->phy_timer_list ); }#if defined(CONFIG_IP_PNP) printk("%s: Waiting for the link to be up...\n", dev->name); while ( fep->link == 0 || ((((volatile fec_t*)dev->base_addr)->fec_ecntrl & FEC_ECNTRL_ETHER_EN) == 0)) { schedule(); }#endif /* CONFIG_IP_PNP */#endif /* CONFIG_USE_MDIO && CONFIG_FEC_DP83846A */ netif_start_queue(dev); return 0; /* Success */ } return -ENODEV; /* No PHY we understand */#else fep->link = 1; netif_start_queue(dev); return 0; /* Success */#endif /* CONFIG_USE_MDIO */}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;}#ifdef CONFIG_USE_MDIO#if defined(CONFIG_FEC_DP83846A)/* Execute the ack_int command set and schedules next timer call back. */static void mdio_timer_callback(unsigned long data){ struct net_device *dev = (struct net_device *)data; struct fec_enet_private *fep = (struct fec_enet_private *)(dev->priv); mii_do_cmd(dev, fep->phy->ack_int); if(fep->link == 0) { fep->phy_timer_list.expires = jiffies + (100 * HZ / 1000); /* Sleep for 100ms */ } else { fep->phy_timer_list.expires = jiffies + (1 * HZ); /* Sleep for 1 sec. */ } add_timer( &fep->phy_timer_list );}#endif /* CONFIG_FEC_DP83846A */static void mdio_callback(uint regval, struct net_device *dev, uint data){ mdio_read_data_t* mrd = (mdio_read_data_t *)data; mrd->regval = 0xFFFF & regval; wake_up_process(mrd->sleeping_task);}static int mdio_read(struct net_device *dev, int phy_id, int location){ uint retval; mdio_read_data_t* mrd = (mdio_read_data_t *)kmalloc(sizeof(*mrd), GFP_KERNEL); mrd->sleeping_task = current; set_current_state(TASK_INTERRUPTIBLE); mii_queue(dev, mk_mii_read(location), mdio_callback, (unsigned int) mrd); schedule(); retval = mrd->regval; kfree(mrd); return retval;}void mdio_write(struct net_device *dev, int phy_id, int location, int value){ mii_queue(dev, mk_mii_write(location, value), NULL, 0);}static int fec_enet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){ struct fec_enet_private *cep = (struct fec_enet_private *)dev->priv; struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data; int phy = cep->phy_addr & 0x1f; int retval; if (data == NULL) { retval = -EINVAL; } else { switch(cmd) { case SIOCETHTOOL: return netdev_ethtool_ioctl(dev, (void*)rq->ifr_data); break; case SIOCGMIIPHY: /* Get address of MII PHY in use. */ case SIOCDEVPRIVATE: /* for binary compat, remove in 2.5 */ data->phy_id = phy; case SIOCGMIIREG: /* Read MII PHY register. */ case SIOCDEVPRIVATE+1: /* for binary compat, remove in 2.5 */ data->val_out = mdio_read (dev, data->phy_id & 0x1f, data->reg_num & 0x1f); retval = 0; break; case SIOCSMIIREG: /* Write MII PHY register. */ case SIOCDEVPRIVATE+2: /* for binary compat, remove in 2.5 */ if (!capable(CAP_NET_ADMIN)) { retval = -EPERM; } else { mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in); retval = 0; } break; default: retval = -EOPNOTSUPP; break; } } return retval;}static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr){ u32 ethcmd; /* dev_ioctl() in ../../net/core/dev.c has already checked capable(CAP_NET_ADMIN), so don't bother with that here. */ if (copy_from_user (ðcmd, useraddr, sizeof (ethcmd))) return -EFAULT; switch (ethcmd) { case ETHTOOL_GDRVINFO: { struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; strcpy (info.driver, dev->name); strcpy (info.version, "0.2"); strcpy (info.bus_info, ""); if (copy_to_user (useraddr, &info, sizeof (info))) return -EFAULT; return 0; } default: break; } return -EOPNOTSUPP;}#endif /* CONFIG_USE_MDIO *//* Returns the CRC needed when filling in the hash table for * multicast group filtering * pAddr must point to a MAC address (6 bytes) */static u32 fec_mulicast_calc_crc(char *pAddr){ u8 byte; int byte_count; int bit_count; u32 crc = 0xffffffff; u8 msb; for (byte_count=0; byte_count<6; byte_count++) { byte = pAddr[byte_count]; for (bit_count=0; bit_count<8; bit_count++) { msb = crc >> 31; crc <<= 1; if (msb ^ (byte & 0x1)) { crc ^= FEC_CRC_POLY; } byte >>= 1; } } return (crc);}/* 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 |= FEC_RCNTRL_PROM; } else { ep->fec_r_cntrl &= ~FEC_RCNTRL_PROM; 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; } else { struct dev_mc_list *pmc = dev->mc_list; /* Clear Hash-Table */ ep->fec_hash_table_high = 0; ep->fec_hash_table_low = 0; /* Now populate the hash table */#ifdef DEBUG_MULTICAST if (pmc) { printk ("%s: Recalculating hash-table:\n", dev->name); printk (" MAC Address high low\n"); }#endif while (pmc) { u32 crc; int temp; u32 csrVal; int hash_index; crc = fec_mulicast_calc_crc(pmc->dmi_addr); temp = (crc & 0x3f) >> 1; hash_index = ((temp & 0x01) << 4) | ((temp & 0x02) << 2) | ((temp & 0x04)) | ((temp & 0x08) >> 2) | ((temp & 0x10) >> 4); csrVal = (1 << hash_index); if (crc & 1) { ep->fec_hash_table_high |= csrVal; } else { ep->fec_hash_table_low |= csrVal; }#ifdef DEBUG_MULTICAST printk (" %02x:%02x:%02x:%02x:%02x:%02x %08x %08x\n", (int)pmc->dmi_addr[0], (int)pmc->dmi_addr[1], (int)pmc->dmi_addr[2], (int)pmc->dmi_addr[3], (int)pmc->dmi_addr[4], (int)pmc->dmi_addr[5], ep->fec_hash_table_high, ep->fec_hash_table_low );#endif pmc = pmc->next; } }#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++) {
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -