📄 natsemi.c
字号:
set_bit_le(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff, mc_filter); } rx_mode = RxFilterEnable | AcceptBroadcast | AcceptMulticast | AcceptMyPhys; for (i = 0; i < 64; i += 2) { writew(HASH_TABLE + i, ioaddr + RxFilterAddr); writew((mc_filter[i+1]<<8) + mc_filter[i], ioaddr + RxFilterData); } } writel(rx_mode, ioaddr + RxFilterAddr); np->cur_rx_mode = rx_mode;}static void set_rx_mode(struct net_device *dev){ struct netdev_private *np = dev->priv; spin_lock_irq(&np->lock); if (netif_device_present(dev)) __set_rx_mode(dev); spin_unlock_irq(&np->lock);}static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr){ struct netdev_private *np = dev->priv; u32 cmd; if (get_user(cmd, (u32 *)useraddr)) return -EFAULT; switch (cmd) { /* get driver info */ case ETHTOOL_GDRVINFO: { struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO}; strncpy(info.driver, DRV_NAME, ETHTOOL_BUSINFO_LEN); strncpy(info.version, DRV_VERSION, ETHTOOL_BUSINFO_LEN); info.fw_version[0] = '\0'; strncpy(info.bus_info, np->pci_dev->slot_name, ETHTOOL_BUSINFO_LEN); info.eedump_len = NATSEMI_EEPROM_SIZE; info.regdump_len = NATSEMI_REGS_SIZE; if (copy_to_user(useraddr, &info, sizeof(info))) return -EFAULT; return 0; } /* get settings */ case ETHTOOL_GSET: { struct ethtool_cmd ecmd = { ETHTOOL_GSET }; spin_lock_irq(&np->lock); netdev_get_ecmd(dev, &ecmd); spin_unlock_irq(&np->lock); if (copy_to_user(useraddr, &ecmd, sizeof(ecmd))) return -EFAULT; return 0; } /* set settings */ case ETHTOOL_SSET: { struct ethtool_cmd ecmd; int r; if (copy_from_user(&ecmd, useraddr, sizeof(ecmd))) return -EFAULT; spin_lock_irq(&np->lock); r = netdev_set_ecmd(dev, &ecmd); spin_unlock_irq(&np->lock); return r; } /* get wake-on-lan */ case ETHTOOL_GWOL: { struct ethtool_wolinfo wol = {ETHTOOL_GWOL}; spin_lock_irq(&np->lock); netdev_get_wol(dev, &wol.supported, &wol.wolopts); netdev_get_sopass(dev, wol.sopass); spin_unlock_irq(&np->lock); if (copy_to_user(useraddr, &wol, sizeof(wol))) return -EFAULT; return 0; } /* set wake-on-lan */ case ETHTOOL_SWOL: { struct ethtool_wolinfo wol; int r; if (copy_from_user(&wol, useraddr, sizeof(wol))) return -EFAULT; spin_lock_irq(&np->lock); netdev_set_wol(dev, wol.wolopts); r = netdev_set_sopass(dev, wol.sopass); spin_unlock_irq(&np->lock); return r; } /* get registers */ case ETHTOOL_GREGS: { struct ethtool_regs regs; u8 regbuf[NATSEMI_REGS_SIZE]; int r; if (copy_from_user(®s, useraddr, sizeof(regs))) return -EFAULT; if (regs.len > NATSEMI_REGS_SIZE) { regs.len = NATSEMI_REGS_SIZE; } regs.version = NATSEMI_REGS_VER; if (copy_to_user(useraddr, ®s, sizeof(regs))) return -EFAULT; useraddr += offsetof(struct ethtool_regs, data); spin_lock_irq(&np->lock); r = netdev_get_regs(dev, regbuf); spin_unlock_irq(&np->lock); if (r) return r; if (copy_to_user(useraddr, regbuf, regs.len)) return -EFAULT; return 0; } /* get message-level */ case ETHTOOL_GMSGLVL: { struct ethtool_value edata = {ETHTOOL_GMSGLVL}; edata.data = np->msg_enable; if (copy_to_user(useraddr, &edata, sizeof(edata))) return -EFAULT; return 0; } /* set message-level */ case ETHTOOL_SMSGLVL: { struct ethtool_value edata; if (copy_from_user(&edata, useraddr, sizeof(edata))) return -EFAULT; np->msg_enable = edata.data; return 0; } /* restart autonegotiation */ case ETHTOOL_NWAY_RST: { int tmp; int r = -EINVAL; /* if autoneg is off, it's an error */ tmp = mdio_read(dev, 1, MII_BMCR); if (tmp & BMCR_ANENABLE) { tmp |= (BMCR_ANRESTART); mdio_write(dev, 1, MII_BMCR, tmp); r = 0; } return r; } /* get link status */ case ETHTOOL_GLINK: { struct ethtool_value edata = {ETHTOOL_GLINK}; edata.data = (mdio_read(dev, 1, MII_BMSR)&BMSR_LSTATUS) ? 1:0; if (copy_to_user(useraddr, &edata, sizeof(edata))) return -EFAULT; return 0; } /* get EEPROM */ case ETHTOOL_GEEPROM: { struct ethtool_eeprom eeprom; u8 eebuf[NATSEMI_EEPROM_SIZE]; int r; if (copy_from_user(&eeprom, useraddr, sizeof(eeprom))) return -EFAULT; if ((eeprom.offset+eeprom.len) > NATSEMI_EEPROM_SIZE) { eeprom.len = NATSEMI_EEPROM_SIZE-eeprom.offset; } eeprom.magic = PCI_VENDOR_ID_NS | (PCI_DEVICE_ID_NS_83815<<16); if (copy_to_user(useraddr, &eeprom, sizeof(eeprom))) return -EFAULT; useraddr += offsetof(struct ethtool_eeprom, data); spin_lock_irq(&np->lock); r = netdev_get_eeprom(dev, eebuf); spin_unlock_irq(&np->lock); if (r) return r; if (copy_to_user(useraddr, eebuf+eeprom.offset, eeprom.len)) return -EFAULT; return 0; } } return -EOPNOTSUPP;}static int netdev_set_wol(struct net_device *dev, u32 newval){ struct netdev_private *np = dev->priv; u32 data = readl(dev->base_addr + WOLCmd) & ~WakeOptsSummary; /* translate to bitmasks this chip understands */ if (newval & WAKE_PHY) data |= WakePhy; if (newval & WAKE_UCAST) data |= WakeUnicast; if (newval & WAKE_MCAST) data |= WakeMulticast; if (newval & WAKE_BCAST) data |= WakeBroadcast; if (newval & WAKE_ARP) data |= WakeArp; if (newval & WAKE_MAGIC) data |= WakeMagic; if (np->srr >= SRR_REV_D) { if (newval & WAKE_MAGICSECURE) { data |= WakeMagicSecure; } } writel(data, dev->base_addr + WOLCmd); return 0;}static int netdev_get_wol(struct net_device *dev, u32 *supported, u32 *cur){ struct netdev_private *np = dev->priv; u32 regval = readl(dev->base_addr + WOLCmd); *supported = (WAKE_PHY | WAKE_UCAST | WAKE_MCAST | WAKE_BCAST | WAKE_ARP | WAKE_MAGIC); if (np->srr >= SRR_REV_D) { /* SOPASS works on revD and higher */ *supported |= WAKE_MAGICSECURE; } *cur = 0; /* translate from chip bitmasks */ if (regval & WakePhy) *cur |= WAKE_PHY; if (regval & WakeUnicast) *cur |= WAKE_UCAST; if (regval & WakeMulticast) *cur |= WAKE_MCAST; if (regval & WakeBroadcast) *cur |= WAKE_BCAST; if (regval & WakeArp) *cur |= WAKE_ARP; if (regval & WakeMagic) *cur |= WAKE_MAGIC; if (regval & WakeMagicSecure) { /* this can be on in revC, but it's broken */ *cur |= WAKE_MAGICSECURE; } return 0;}static int netdev_set_sopass(struct net_device *dev, u8 *newval){ struct netdev_private *np = dev->priv; u16 *sval = (u16 *)newval; u32 addr; if (np->srr < SRR_REV_D) { return 0; } /* enable writing to these registers by disabling the RX filter */ addr = readl(dev->base_addr + RxFilterAddr) & ~RFCRAddressMask; addr &= ~RxFilterEnable; writel(addr, dev->base_addr + RxFilterAddr); /* write the three words to (undocumented) RFCR vals 0xa, 0xc, 0xe */ writel(addr | 0xa, dev->base_addr + RxFilterAddr); writew(sval[0], dev->base_addr + RxFilterData); writel(addr | 0xc, dev->base_addr + RxFilterAddr); writew(sval[1], dev->base_addr + RxFilterData); writel(addr | 0xe, dev->base_addr + RxFilterAddr); writew(sval[2], dev->base_addr + RxFilterData); /* re-enable the RX filter */ writel(addr | RxFilterEnable, dev->base_addr + RxFilterAddr); return 0;}static int netdev_get_sopass(struct net_device *dev, u8 *data){ struct netdev_private *np = dev->priv; u16 *sval = (u16 *)data; u32 addr; if (np->srr < SRR_REV_D) { sval[0] = sval[1] = sval[2] = 0; return 0; } /* read the three words from (undocumented) RFCR vals 0xa, 0xc, 0xe */ addr = readl(dev->base_addr + RxFilterAddr) & ~RFCRAddressMask; writel(addr | 0xa, dev->base_addr + RxFilterAddr); sval[0] = readw(dev->base_addr + RxFilterData); writel(addr | 0xc, dev->base_addr + RxFilterAddr); sval[1] = readw(dev->base_addr + RxFilterData); writel(addr | 0xe, dev->base_addr + RxFilterAddr); sval[2] = readw(dev->base_addr + RxFilterData); writel(addr, dev->base_addr + RxFilterAddr); return 0;}static int netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd){ u32 tmp; ecmd->supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII); /* only supports twisted-pair or MII */ tmp = readl(dev->base_addr + ChipConfig); if (tmp & CfgExtPhy) ecmd->port = PORT_MII; else ecmd->port = PORT_TP; /* only supports internal transceiver */ ecmd->transceiver = XCVR_INTERNAL; /* not sure what this is for */ ecmd->phy_address = readw(dev->base_addr + PhyCtrl) & PhyAddrMask; ecmd->advertising = ADVERTISED_TP | ADVERTISED_MII; tmp = mdio_read(dev, 1, MII_ADVERTISE); if (tmp & ADVERTISE_10HALF) ecmd->advertising |= ADVERTISED_10baseT_Half; if (tmp & ADVERTISE_10FULL) ecmd->advertising |= ADVERTISED_10baseT_Full; if (tmp & ADVERTISE_100HALF) ecmd->advertising |= ADVERTISED_100baseT_Half; if (tmp & ADVERTISE_100FULL) ecmd->advertising |= ADVERTISED_100baseT_Full; tmp = mdio_read(dev, 1, MII_BMCR); if (tmp & BMCR_ANENABLE) { ecmd->advertising |= ADVERTISED_Autoneg; ecmd->autoneg = AUTONEG_ENABLE; } else { ecmd->autoneg = AUTONEG_DISABLE; } tmp = readl(dev->base_addr + ChipConfig); if (tmp & CfgSpeed100) { ecmd->speed = SPEED_100; } else { ecmd->speed = SPEED_10; } if (tmp & CfgFullDuplex) { ecmd->duplex = DUPLEX_FULL; } else { ecmd->duplex = DUPLEX_HALF; } /* ignore maxtxpkt, maxrxpkt for now */ return 0;}static int netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd){ struct netdev_private *np = dev->priv; u32 tmp; if (ecmd->speed != SPEED_10 && ecmd->speed != SPEED_100) return -EINVAL; if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL) return -EINVAL; if (ecmd->port != PORT_TP && ecmd->port != PORT_MII) return -EINVAL; if (ecmd->transceiver != XCVR_INTERNAL) return -EINVAL; if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE) return -EINVAL; /* ignore phy_address, maxtxpkt, maxrxpkt for now */ /* WHEW! now lets bang some bits */ tmp = mdio_read(dev, 1, MII_BMCR); if (ecmd->autoneg == AUTONEG_ENABLE) { /* turn on autonegotiation */ tmp |= BMCR_ANENABLE; np->advertising = mdio_read(dev, 1, MII_ADVERTISE); } else { /* turn off auto negotiation, set speed and duplexity */ tmp &= ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX); if (ecmd->speed == SPEED_100) tmp |= BMCR_SPEED100; if (ecmd->duplex == DUPLEX_FULL) tmp |= BMCR_FULLDPLX; else np->full_duplex = 0; } mdio_write(dev, 1, MII_BMCR, tmp); return 0;}static int netdev_get_regs(struct net_device *dev, u8 *buf){ int i; int j; u32 rfcr; u32 *rbuf = (u32 *)buf; /* read all of page 0 of registers */ for (i = 0; i < NATSEMI_PG0_NREGS; i++) { rbuf[i] = readl(dev->base_addr + i*4); } /* read only the 'magic' registers from page 1 */ writew(1, dev->base_addr + PGSEL); rbuf[i++] = readw(dev->base_addr + PMDCSR); rbuf[i++] = readw(dev->base_addr + TSTDAT); rbuf[i++] = readw(dev->base_addr + DSPCFG); rbuf[i++] = readw(dev->base_addr + SDCFG); writew(0, dev->base_addr + PGSEL); /* read RFCR indexed registers */ rfcr = readl(dev->base_addr + RxFilterAddr); for (j = 0; j < NATSEMI_RFDR_NREGS; j++) { writel(j*2, dev->base_addr + RxFilterAddr); rbuf[i++] = readw(dev->base_addr + RxFilterData); } writel(rfcr, dev->base_addr + RxFilterAddr); /* the interrupt status is clear-on-read - see if we missed any */ if (rbuf[4] & rbuf[5]) { printk(KERN_WARNING "%s: shoot, we dropped an interrupt (%#08x)\n", dev->name, rbuf[4] & rbuf[5]); } return 0;}#define SWAP_BITS(x) ( (((x) & 0x0001) << 15) | (((x) & 0x0002) << 13) \ | (((x) & 0x0004) << 11) | (((x) & 0x0008) << 9) \ | (((x) & 0x0010) << 7) | (((x) & 0x0020) << 5) \ | (((x) & 0x0040) << 3) | (((x) & 0
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -