static void e1000_diag_test(struct net_device *netdev, struct ethtool_test *eth_test, uint64_t *data) { struct e1000_adapter *adapter = netdev->priv; boolean_t if_running = netif_running(netdev); if(eth_test->flags == ETH_TEST_FL_OFFLINE) { /* Offline tests */ /* save speed, duplex, autoneg settings */ uint16_t autoneg_advertised = adapter->hw.autoneg_advertised; uint8_t forced_speed_duplex = adapter->hw.forced_speed_duplex; uint8_t autoneg = adapter->hw.autoneg; /* Link test performed before hardware reset so autoneg doesn't * interfere with test result */ if(e1000_link_test(adapter, &data[4])) eth_test->flags |= ETH_TEST_FL_FAILED; if(if_running) e1000_down(adapter); else e1000_reset(adapter); if(e1000_reg_test(adapter, &data[0])) eth_test->flags |= ETH_TEST_FL_FAILED; e1000_reset(adapter); if(e1000_eeprom_test(adapter, &data[1])) eth_test->flags |= ETH_TEST_FL_FAILED; e1000_reset(adapter); if(e1000_intr_test(adapter, &data[2])) eth_test->flags |= ETH_TEST_FL_FAILED; e1000_reset(adapter); if(e1000_loopback_test(adapter, &data[3])) eth_test->flags |= ETH_TEST_FL_FAILED; /* restore speed, duplex, autoneg settings */ adapter->hw.autoneg_advertised = autoneg_advertised; adapter->hw.forced_speed_duplex = forced_speed_duplex; adapter->hw.autoneg = autoneg; e1000_reset(adapter); if(if_running) e1000_up(adapter); } else { /* Online tests */ if(e1000_link_test(adapter, &data[4])) eth_test->flags |= ETH_TEST_FL_FAILED; /* Offline tests aren't run; pass by default */ data[0] = 0; data[1] = 0; data[2] = 0; data[3] = 0; } }
static int e1000_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) { struct e1000_adapter *adapter = netdev->priv; struct e1000_hw *hw = &adapter->hw; if(ecmd->autoneg == AUTONEG_ENABLE) { hw->autoneg = 1; hw->autoneg_advertised = 0x002F; ecmd->advertising = 0x002F; } else if(e1000_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) return -EINVAL; /* reset the link */ if(netif_running(adapter->netdev)) { e1000_down(adapter); e1000_reset(adapter); e1000_up(adapter); } else e1000_reset(adapter); return 0; }
static int e1000_ethtool_test(struct e1000_adapter *adapter, struct ethtool_test *eth_test, uint64_t *data) { boolean_t if_running = netif_running(adapter->netdev); if(eth_test->flags == ETH_TEST_FL_OFFLINE) { /* Offline tests */ /* Link test performed before hardware reset so autoneg doesn't * interfere with test result */ if(e1000_link_test(adapter, &data[4])) eth_test->flags |= ETH_TEST_FL_FAILED; if(if_running) e1000_down(adapter); else e1000_reset(adapter); if(e1000_reg_test(adapter, &data[0])) eth_test->flags |= ETH_TEST_FL_FAILED; e1000_reset(adapter); if(e1000_eeprom_test(adapter, &data[1])) eth_test->flags |= ETH_TEST_FL_FAILED; e1000_reset(adapter); if(e1000_intr_test(adapter, &data[2])) eth_test->flags |= ETH_TEST_FL_FAILED; e1000_reset(adapter); if(e1000_loopback_test(adapter, &data[3])) eth_test->flags |= ETH_TEST_FL_FAILED; e1000_reset(adapter); if(if_running) e1000_up(adapter); } else { /* Online tests */ if(e1000_link_test(adapter, &data[4])) eth_test->flags |= ETH_TEST_FL_FAILED; /* Offline tests aren't run; pass by default */ data[0] = 0; data[1] = 0; data[2] = 0; data[3] = 0; } return 0; }
void e1000_mod_exit(void) { uint32_t size; struct e1000_dev *dev; size = CONFIG_E1000_N_TX_DESC * sizeof(struct tx_desc) + CONFIG_E1000_N_TX_DESC * CONFIG_E1000_BUFF_SIZE + CONFIG_E1000_N_RX_DESC * sizeof(struct rx_desc) + CONFIG_E1000_N_RX_DESC * CONFIG_E1000_BUFF_SIZE; size = ROUNDUP(size, PGSIZE); for (dev=e1000_list.next; dev!=NULL; dev=dev->next) { netdev_unregister(&dev->uip_dev); e1000_reset(dev); wd_delete(dev->txpoll); wd_delete(dev->txtimeout); rgmp_memremap((uintptr_t)dev->tx_ring.desc, size); free(dev->tx_ring.desc); pci_free_irq(dev->pci_addr); rgmp_memunmap((uintptr_t)dev->io_mem_base, dev->mem_size); kfree(dev); } e1000_list.next = NULL; }
static int e1000_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) { struct e1000_adapter *adapter = netdev->priv; struct e1000_hw *hw = &adapter->hw; adapter->fc_autoneg = pause->autoneg; if(pause->rx_pause && pause->tx_pause) hw->fc = e1000_fc_full; else if(pause->rx_pause && !pause->tx_pause) hw->fc = e1000_fc_rx_pause; else if(!pause->rx_pause && pause->tx_pause) hw->fc = e1000_fc_tx_pause; else if(!pause->rx_pause && !pause->tx_pause) hw->fc = e1000_fc_none; hw->original_fc = hw->fc; if(adapter->fc_autoneg == AUTONEG_ENABLE) { if(netif_running(adapter->netdev)) { e1000_down(adapter); e1000_up(adapter); } else e1000_reset(adapter); } else return ((hw->media_type == e1000_media_type_fiber) ? e1000_setup_link(hw) : e1000_force_mac_fc(hw)); return 0; }
static int e1000_ethtool_spause(struct e1000_adapter *adapter, struct ethtool_pauseparam *epause) { struct e1000_hw *hw = &adapter->hw; adapter->fc_autoneg = epause->autoneg; if(epause->rx_pause && epause->tx_pause) hw->fc = e1000_fc_full; else if(epause->rx_pause && !epause->tx_pause) hw->fc = e1000_fc_rx_pause; else if(!epause->rx_pause && epause->tx_pause) hw->fc = e1000_fc_tx_pause; else if(!epause->rx_pause && !epause->tx_pause) hw->fc = e1000_fc_none; hw->original_fc = hw->fc; if(adapter->fc_autoneg == AUTONEG_ENABLE) { if(netif_running(adapter->netdev)) { e1000_down(adapter); e1000_up(adapter); } else e1000_reset(adapter); } else return e1000_force_mac_fc(hw); return 0; }
static int e1000_set_rx_csum(struct net_device *netdev, uint32_t data) { struct e1000_adapter *adapter = netdev->priv; adapter->rx_csum = data; if(netif_running(netdev)) { e1000_down(adapter); e1000_up(adapter); } else e1000_reset(adapter); return 0; }
/** * e1000_open - Called when a network interface is made active * * @v netdev network interface device structure * @ret rc Return status code, 0 on success, negative value on failure * **/ static int e1000_open ( struct net_device *netdev ) { struct e1000_adapter *adapter = netdev_priv(netdev); int err; DBG ( "e1000_open\n" ); /* allocate transmit descriptors */ err = e1000_setup_tx_resources ( adapter ); if ( err ) { DBG ( "Error setting up TX resources!\n" ); goto err_setup_tx; } /* allocate receive descriptors */ err = e1000_setup_rx_resources ( adapter ); if ( err ) { DBG ( "Error setting up RX resources!\n" ); goto err_setup_rx; } e1000_configure_tx ( adapter ); e1000_configure_rx ( adapter ); DBG ( "E1000_RXDCTL(0): %#08x\n", E1000_READ_REG ( &adapter->hw, E1000_RXDCTL(0) ) ); return 0; err_setup_rx: e1000_free_tx_resources ( adapter ); err_setup_tx: e1000_reset ( adapter ); return err; }
static int e1000_probe(uint16_t addr, pci_id_t id) { uint32_t mmio_base, mmio_size; uint32_t size; int err; void *kmem, *omem; struct e1000_dev *dev; // alloc e1000_dev memory if ((dev = kzalloc(sizeof(struct e1000_dev))) == NULL) return -1; // save pci addr dev->pci_addr = addr; // enable device if ((err = pci_enable_device(addr, PCI_BUS_MASTER)) < 0) goto error; // get e1000 device type dev->pci_dev_id = id.join; // remap the controller's i/o-memory into kernel's address-space mmio_base = pci_resource_start(addr, 0); mmio_size = pci_resource_len(addr, 0); err = rgmp_memmap_nocache(mmio_base, mmio_size, mmio_base); if (err) goto error; dev->phy_mem_base = mmio_base; dev->io_mem_base = mmio_base; dev->mem_size = mmio_size; // MAC address memset(dev->dst_mac, 0xFF, 6); memcpy(dev->src_mac, (void *)(dev->io_mem_base+E1000_RA), 6); // IRQ setup dev->int_desc.handler = e1000_interrupt_handler; dev->int_desc.dev_id = dev; if ((err = pci_request_irq(addr, &dev->int_desc, 0)) < 0) goto err0; // Here we alloc a big block of memory once and make it // aligned to page boundary and multiple of page size. This // is because the memory can be modified by E1000 DMA and // should be mapped no-cache which will hugely reduce memory // access performance. The page size alloc will restrict // this bad effect only within the memory we alloc here. // // NEED FIX: the memalign may alloc memory continous in // virtual address but dis-continous in physical address // due to RGMP memory setup. size = CONFIG_E1000_N_TX_DESC * sizeof(struct tx_desc) + CONFIG_E1000_N_TX_DESC * CONFIG_E1000_BUFF_SIZE + CONFIG_E1000_N_RX_DESC * sizeof(struct rx_desc) + CONFIG_E1000_N_RX_DESC * CONFIG_E1000_BUFF_SIZE; size = ROUNDUP(size, PGSIZE); omem = kmem = memalign(PGSIZE, size); if (kmem == NULL) { err = -ENOMEM; goto err1; } rgmp_memremap_nocache((uintptr_t)kmem, size); // alloc memory for tx ring dev->tx_ring.desc = (struct tx_desc*)kmem; kmem += CONFIG_E1000_N_TX_DESC * sizeof(struct tx_desc); dev->tx_ring.buf = kmem; kmem += CONFIG_E1000_N_TX_DESC * CONFIG_E1000_BUFF_SIZE; // alloc memory for rx rings dev->rx_ring.desc = (struct rx_desc*)kmem; kmem += CONFIG_E1000_N_RX_DESC * sizeof(struct rx_desc); dev->rx_ring.buf = kmem; /* Initialize the driver structure */ dev->uip_dev.d_ifup = e1000_ifup; /* I/F up (new IP address) callback */ dev->uip_dev.d_ifdown = e1000_ifdown; /* I/F down callback */ dev->uip_dev.d_txavail = e1000_txavail; /* New TX data callback */ #ifdef CONFIG_NET_IGMP dev->uip_dev.d_addmac = e1000_addmac; /* Add multicast MAC address */ dev->uip_dev.d_rmmac = e1000_rmmac; /* Remove multicast MAC address */ #endif dev->uip_dev.d_private = dev; /* Used to recover private state from dev */ /* Create a watchdog for timing polling for and timing of transmisstions */ dev->txpoll = wd_create(); /* Create periodic poll timer */ dev->txtimeout = wd_create(); /* Create TX timeout timer */ // Put the interface in the down state. // e1000 reset e1000_reset(dev); /* Read the MAC address from the hardware */ memcpy(dev->uip_dev.d_mac.ether_addr_octet, (void *)(dev->io_mem_base+E1000_RA), 6); /* Register the device with the OS so that socket IOCTLs can be performed */ err = netdev_register(&dev->uip_dev); if (err) goto err2; // insert into e1000_list dev->next = e1000_list.next; e1000_list.next = dev; cprintf("bring up e1000 device: %04x %08x\n", addr, id.join); return 0; err2: rgmp_memremap((uintptr_t)omem, size); free(omem); err1: pci_free_irq(addr); err0: rgmp_memunmap(mmio_base, mmio_size); error: kfree(dev); cprintf("e1000 device probe fail: %d\n", err); return err; }
void e1000_init(struct e1000_dev *dev) { uint32_t rxd_phys, txd_phys, kmem_phys; uint32_t rx_control, tx_control; uint32_t pba; int i; e1000_reset(dev); // configure the controller's 'receive' engine rx_control = 0; rx_control |= (0<<1); // EN-bit (Enable) rx_control |= (0<<2); // SPB-bit (Store Bad Packets) rx_control |= (0<<3); // UPE-bit (Unicast Promiscuous Mode) rx_control |= (1<<4); // MPE-bit (Multicast Promiscuous Mode) rx_control |= (0<<5); // LPE-bit (Long Packet Enable) rx_control |= (0<<6); // LBM=0 (Loop-Back Mode) rx_control |= (0<<8); // RDMTS=0 (Rx Descriptor Min Threshold Size) rx_control |= (0<<10); // DTYPE=0 (Descriptor Type) rx_control |= (0<<12); // MO=0 (Multicast Offset) rx_control |= (1<<15); // BAM-bit (Broadcast Address Mode) rx_control |= (0<<16); // BSIZE=0 (Buffer Size = 2048) rx_control |= (0<<18); // VLE-bit (VLAN filter Enable) rx_control |= (0<<19); // CFIEN-bit (Canonical Form Indicator Enable) rx_control |= (0<<20); // CFI-bit (Canonical Form Indicator) rx_control |= (1<<22); // DPF-bit (Discard Pause Frames) rx_control |= (0<<23); // PMCF-bit (Pass MAC Control Frames) rx_control |= (0<<25); // BSEX=0 (Buffer Size EXtension) rx_control |= (1<<26); // SECRC-bit (Strip Ethernet CRC) rx_control |= (0<<27); // FLEXBUF=0 (Flexible Buffer size) e1000_outl(dev, E1000_RCTL, rx_control); // configure the controller's 'transmit' engine tx_control = 0; tx_control |= (0<<1); // EN-bit (Enable) tx_control |= (1<<3); // PSP-bit (Pad Short Packets) tx_control |= (15<<4); // CT=15 (Collision Threshold) tx_control |= (63<<12); // COLD=63 (Collision Distance) tx_control |= (0<<22); // SWXOFF-bit (Software XOFF) tx_control |= (1<<24); // RTLC-bit (Re-Transmit on Late Collision) tx_control |= (0<<25); // UNORTX-bit (Underrun No Re-Transmit) tx_control |= (0<<26); // TXCSCMT=0 (TxDesc Mininum Threshold) tx_control |= (0<<28); // MULR-bit (Multiple Request Support) e1000_outl(dev, E1000_TCTL, tx_control); // hardware flow control pba = e1000_inl(dev, E1000_PBA); // get receive FIFO size pba = (pba & 0x000000ff)<<10; e1000_outl(dev, E1000_FCAL, 0x00C28001); e1000_outl(dev, E1000_FCAH, 0x00000100); e1000_outl(dev, E1000_FCT, 0x00008808); e1000_outl(dev, E1000_FCTTV, 0x00000680); e1000_outl(dev, E1000_FCRTL, (pba*8/10)|0x80000000); e1000_outl(dev, E1000_FCRTH, pba*9/10); // setup tx rings txd_phys = PADDR((uintptr_t)dev->tx_ring.desc); kmem_phys = PADDR((uintptr_t)dev->tx_ring.buf); for (i=0; i<CONFIG_E1000_N_TX_DESC; i++,kmem_phys+=CONFIG_E1000_BUFF_SIZE) { dev->tx_ring.desc[i].base_address = kmem_phys; dev->tx_ring.desc[i].packet_length = 0; dev->tx_ring.desc[i].cksum_offset = 0; dev->tx_ring.desc[i].cksum_origin = 0; dev->tx_ring.desc[i].desc_status = 1; dev->tx_ring.desc[i].desc_command = (1<<0)|(1<<1)|(1<<3); dev->tx_ring.desc[i].special_info = 0; } dev->tx_ring.tail = 0; e1000_outl(dev, E1000_TDT, 0); e1000_outl(dev, E1000_TDH, 0); // tell controller the location, size, and fetch-policy for Tx queue e1000_outl(dev, E1000_TDBAL, txd_phys); e1000_outl(dev, E1000_TDBAH, 0x00000000); e1000_outl(dev, E1000_TDLEN, CONFIG_E1000_N_TX_DESC*16); e1000_outl(dev, E1000_TXDCTL, 0x01010000); // setup rx rings rxd_phys = PADDR((uintptr_t)dev->rx_ring.desc); kmem_phys = PADDR((uintptr_t)dev->rx_ring.buf); for (i=0; i<CONFIG_E1000_N_RX_DESC; i++,kmem_phys+=CONFIG_E1000_BUFF_SIZE) { dev->rx_ring.desc[i].base_address = kmem_phys; dev->rx_ring.desc[i].packet_length = 0; dev->rx_ring.desc[i].packet_cksum = 0; dev->rx_ring.desc[i].desc_status = 0; dev->rx_ring.desc[i].desc_errors = 0; dev->rx_ring.desc[i].vlan_tag = 0; } dev->rx_ring.head = 0; dev->rx_ring.tail = CONFIG_E1000_N_RX_DESC-1; dev->rx_ring.free = 0; // give the controller ownership of all receive descriptors e1000_outl(dev, E1000_RDH, 0); e1000_outl(dev, E1000_RDT, CONFIG_E1000_N_RX_DESC-1); // tell controller the location, size, and fetch-policy for RX queue e1000_outl(dev, E1000_RDBAL, rxd_phys); e1000_outl(dev, E1000_RDBAH, 0x00000000); e1000_outl(dev, E1000_RDLEN, CONFIG_E1000_N_RX_DESC*16); e1000_outl(dev, E1000_RXDCTL, 0x01010000); e1000_turn_on(dev); }
int e1000_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr) { struct e1000_adapter *adapter = netdev->priv; void *addr = ifr->ifr_data; uint32_t cmd; if(get_user(cmd, (uint32_t *) addr)) return -EFAULT; switch(cmd) { case ETHTOOL_GSET: { struct ethtool_cmd ecmd = {ETHTOOL_GSET}; e1000_ethtool_gset(adapter, &ecmd); if(copy_to_user(addr, &ecmd, sizeof(ecmd))) return -EFAULT; return 0; } case ETHTOOL_SSET: { struct ethtool_cmd ecmd; if(copy_from_user(&ecmd, addr, sizeof(ecmd))) return -EFAULT; return e1000_ethtool_sset(adapter, &ecmd); } case ETHTOOL_GDRVINFO: { struct ethtool_drvinfo drvinfo = {ETHTOOL_GDRVINFO}; e1000_ethtool_gdrvinfo(adapter, &drvinfo); if(copy_to_user(addr, &drvinfo, sizeof(drvinfo))) return -EFAULT; return 0; } case ETHTOOL_GSTRINGS: { struct ethtool_gstrings gstrings = { ETHTOOL_GSTRINGS }; char *strings = NULL; int err = 0; if(copy_from_user(&gstrings, addr, sizeof(gstrings))) return -EFAULT; switch(gstrings.string_set) { case ETH_SS_TEST: gstrings.len = E1000_TEST_LEN; strings = kmalloc(E1000_TEST_LEN * ETH_GSTRING_LEN, GFP_KERNEL); if(!strings) return -ENOMEM; memcpy(strings, e1000_gstrings_test, E1000_TEST_LEN * ETH_GSTRING_LEN); break; case ETH_SS_STATS: { int i; gstrings.len = E1000_STATS_LEN; strings = kmalloc(E1000_STATS_LEN * ETH_GSTRING_LEN, GFP_KERNEL); if(!strings) return -ENOMEM; for(i=0; i < E1000_STATS_LEN; i++) { memcpy(&strings[i * ETH_GSTRING_LEN], e1000_gstrings_stats[i].stat_string, ETH_GSTRING_LEN); } break; } default: return -EOPNOTSUPP; } if(copy_to_user(addr, &gstrings, sizeof(gstrings))) err = -EFAULT; addr += offsetof(struct ethtool_gstrings, data); if(!err && copy_to_user(addr, strings, gstrings.len * ETH_GSTRING_LEN)) err = -EFAULT; kfree(strings); return err; } case ETHTOOL_GREGS: { struct ethtool_regs regs = {ETHTOOL_GREGS}; uint32_t regs_buff[E1000_REGS_LEN]; if(copy_from_user(®s, addr, sizeof(regs))) return -EFAULT; e1000_ethtool_gregs(adapter, ®s, regs_buff); if(copy_to_user(addr, ®s, sizeof(regs))) return -EFAULT; addr += offsetof(struct ethtool_regs, data); if(copy_to_user(addr, regs_buff, regs.len)) return -EFAULT; return 0; } case ETHTOOL_NWAY_RST: { if(netif_running(netdev)) { e1000_down(adapter); e1000_up(adapter); } return 0; } case ETHTOOL_PHYS_ID: { struct ethtool_value id; if(copy_from_user(&id, addr, sizeof(id))) return -EFAULT; return e1000_ethtool_led_blink(adapter, &id); } case ETHTOOL_GLINK: { struct ethtool_value link = {ETHTOOL_GLINK}; link.data = netif_carrier_ok(netdev); if(copy_to_user(addr, &link, sizeof(link))) return -EFAULT; return 0; } case ETHTOOL_GWOL: { struct ethtool_wolinfo wol = {ETHTOOL_GWOL}; e1000_ethtool_gwol(adapter, &wol); if(copy_to_user(addr, &wol, sizeof(wol)) != 0) return -EFAULT; return 0; } case ETHTOOL_SWOL: { struct ethtool_wolinfo wol; if(copy_from_user(&wol, addr, sizeof(wol)) != 0) return -EFAULT; return e1000_ethtool_swol(adapter, &wol); } case ETHTOOL_GEEPROM: { struct ethtool_eeprom eeprom = {ETHTOOL_GEEPROM}; struct e1000_hw *hw = &adapter->hw; uint16_t *eeprom_buff; void *ptr; int err = 0; if(copy_from_user(&eeprom, addr, sizeof(eeprom))) return -EFAULT; eeprom_buff = kmalloc(hw->eeprom.word_size * 2, GFP_KERNEL); if(!eeprom_buff) return -ENOMEM; if((err = e1000_ethtool_geeprom(adapter, &eeprom, eeprom_buff))) goto err_geeprom_ioctl; if(copy_to_user(addr, &eeprom, sizeof(eeprom))) { err = -EFAULT; goto err_geeprom_ioctl; } addr += offsetof(struct ethtool_eeprom, data); ptr = ((void *)eeprom_buff) + (eeprom.offset & 1); if(copy_to_user(addr, ptr, eeprom.len)) err = -EFAULT; err_geeprom_ioctl: kfree(eeprom_buff); return err; } case ETHTOOL_SEEPROM: { struct ethtool_eeprom eeprom; if(copy_from_user(&eeprom, addr, sizeof(eeprom))) return -EFAULT; addr += offsetof(struct ethtool_eeprom, data); return e1000_ethtool_seeprom(adapter, &eeprom, addr); } case ETHTOOL_GPAUSEPARAM: { struct ethtool_pauseparam epause = {ETHTOOL_GPAUSEPARAM}; e1000_ethtool_gpause(adapter, &epause); if(copy_to_user(addr, &epause, sizeof(epause))) return -EFAULT; return 0; } case ETHTOOL_SPAUSEPARAM: { struct ethtool_pauseparam epause; if(copy_from_user(&epause, addr, sizeof(epause))) return -EFAULT; return e1000_ethtool_spause(adapter, &epause); } case ETHTOOL_GSTATS: { struct { struct ethtool_stats eth_stats; uint64_t data[E1000_STATS_LEN]; } stats = { {ETHTOOL_GSTATS, E1000_STATS_LEN} }; int i; for(i = 0; i < E1000_STATS_LEN; i++) stats.data[i] = (e1000_gstrings_stats[i].sizeof_stat == sizeof(uint64_t)) ? *(uint64_t *)((char *)adapter + e1000_gstrings_stats[i].stat_offset) : *(uint32_t *)((char *)adapter + e1000_gstrings_stats[i].stat_offset); if(copy_to_user(addr, &stats, sizeof(stats))) return -EFAULT; return 0; } case ETHTOOL_TEST: { struct { struct ethtool_test eth_test; uint64_t data[E1000_TEST_LEN]; } test = { {ETHTOOL_TEST} }; int err; if(copy_from_user(&test.eth_test, addr, sizeof(test.eth_test))) return -EFAULT; test.eth_test.len = E1000_TEST_LEN; if((err = e1000_ethtool_test(adapter, &test.eth_test, test.data))) return err; if(copy_to_user(addr, &test, sizeof(test)) != 0) return -EFAULT; return 0; } case ETHTOOL_GRXCSUM: { struct ethtool_value edata = { ETHTOOL_GRXCSUM }; edata.data = adapter->rx_csum; if (copy_to_user(addr, &edata, sizeof(edata))) return -EFAULT; return 0; } case ETHTOOL_SRXCSUM: { struct ethtool_value edata; if (copy_from_user(&edata, addr, sizeof(edata))) return -EFAULT; adapter->rx_csum = edata.data; if(netif_running(netdev)) { e1000_down(adapter); e1000_up(adapter); } else e1000_reset(adapter); return 0; } case ETHTOOL_GTXCSUM: { struct ethtool_value edata = { ETHTOOL_GTXCSUM }; edata.data = (netdev->features & NETIF_F_HW_CSUM) != 0; if (copy_to_user(addr, &edata, sizeof(edata))) return -EFAULT; return 0; } case ETHTOOL_STXCSUM: { struct ethtool_value edata; if (copy_from_user(&edata, addr, sizeof(edata))) return -EFAULT; if(adapter->hw.mac_type < e1000_82543) { if (edata.data != 0) return -EINVAL; return 0; } if (edata.data) netdev->features |= NETIF_F_HW_CSUM; else netdev->features &= ~NETIF_F_HW_CSUM; return 0; } case ETHTOOL_GSG: { struct ethtool_value edata = { ETHTOOL_GSG }; edata.data = (netdev->features & NETIF_F_SG) != 0; if (copy_to_user(addr, &edata, sizeof(edata))) return -EFAULT; return 0; } case ETHTOOL_SSG: { struct ethtool_value edata; if (copy_from_user(&edata, addr, sizeof(edata))) return -EFAULT; if (edata.data) netdev->features |= NETIF_F_SG; else netdev->features &= ~NETIF_F_SG; return 0; } #ifdef NETIF_F_TSO case ETHTOOL_GTSO: { struct ethtool_value edata = { ETHTOOL_GTSO }; edata.data = (netdev->features & NETIF_F_TSO) != 0; if (copy_to_user(addr, &edata, sizeof(edata))) return -EFAULT; return 0; } case ETHTOOL_STSO: { struct ethtool_value edata; if (copy_from_user(&edata, addr, sizeof(edata))) return -EFAULT; if ((adapter->hw.mac_type < e1000_82544) || (adapter->hw.mac_type == e1000_82547)) { if (edata.data != 0) return -EINVAL; return 0; } if (edata.data) netdev->features |= NETIF_F_TSO; else netdev->features &= ~NETIF_F_TSO; return 0; } #endif default: return -EOPNOTSUPP; } }
/** * e1000_probe - Initial configuration of e1000 NIC * * @v pci PCI device * @v id PCI IDs * * @ret rc Return status code **/ int e1000_probe ( struct pci_device *pdev ) { int i, err; struct net_device *netdev; struct e1000_adapter *adapter; unsigned long mmio_start, mmio_len; DBG ( "e1000_probe\n" ); err = -ENOMEM; /* Allocate net device ( also allocates memory for netdev->priv and makes netdev-priv point to it ) */ netdev = alloc_etherdev ( sizeof ( struct e1000_adapter ) ); if ( ! netdev ) goto err_alloc_etherdev; /* Associate e1000-specific network operations operations with * generic network device layer */ netdev_init ( netdev, &e1000_operations ); /* Associate this network device with given PCI device */ pci_set_drvdata ( pdev, netdev ); netdev->dev = &pdev->dev; /* Initialize driver private storage */ adapter = netdev_priv ( netdev ); memset ( adapter, 0, ( sizeof ( *adapter ) ) ); adapter->pdev = pdev; adapter->ioaddr = pdev->ioaddr; adapter->hw.io_base = pdev->ioaddr; adapter->irqno = pdev->irq; adapter->netdev = netdev; adapter->hw.back = adapter; adapter->tx_ring_size = sizeof ( *adapter->tx_base ) * NUM_TX_DESC; adapter->rx_ring_size = sizeof ( *adapter->rx_base ) * NUM_RX_DESC; mmio_start = pci_bar_start ( pdev, PCI_BASE_ADDRESS_0 ); mmio_len = pci_bar_size ( pdev, PCI_BASE_ADDRESS_0 ); DBG ( "mmio_start: %#08lx\n", mmio_start ); DBG ( "mmio_len: %#08lx\n", mmio_len ); /* Fix up PCI device */ adjust_pci_device ( pdev ); err = -EIO; adapter->hw.hw_addr = ioremap ( mmio_start, mmio_len ); DBG ( "adapter->hw.hw_addr: %p\n", adapter->hw.hw_addr ); if ( ! adapter->hw.hw_addr ) goto err_ioremap; /* Hardware features, flags and workarounds */ if (adapter->hw.mac.type >= e1000_82540) { adapter->flags |= E1000_FLAG_HAS_SMBUS; adapter->flags |= E1000_FLAG_HAS_INTR_MODERATION; } if (adapter->hw.mac.type == e1000_82543) adapter->flags |= E1000_FLAG_BAD_TX_CARRIER_STATS_FD; adapter->hw.phy.autoneg_wait_to_complete = true; adapter->hw.mac.adaptive_ifs = true; /* setup the private structure */ if ( ( err = e1000_sw_init ( adapter ) ) ) goto err_sw_init; if ((err = e1000_init_mac_params(&adapter->hw))) goto err_hw_init; if ((err = e1000_init_nvm_params(&adapter->hw))) goto err_hw_init; /* Force auto-negotiated speed and duplex */ adapter->hw.mac.autoneg = 1; if ((err = e1000_init_phy_params(&adapter->hw))) goto err_hw_init; DBG ( "adapter->hw.mac.type: %#08x\n", adapter->hw.mac.type ); /* before reading the EEPROM, reset the controller to * put the device in a known good starting state */ err = e1000_reset_hw ( &adapter->hw ); if ( err < 0 ) { DBG ( "Hardware Initialization Failed\n" ); goto err_reset; } /* make sure the NVM is good */ if ( e1000_validate_nvm_checksum(&adapter->hw) < 0 ) { DBG ( "The NVM Checksum Is Not Valid\n" ); err = -EIO; goto err_eeprom; } /* copy the MAC address out of the EEPROM */ if ( e1000_read_mac_addr ( &adapter->hw ) ) DBG ( "EEPROM Read Error\n" ); memcpy ( netdev->hw_addr, adapter->hw.mac.perm_addr, ETH_ALEN ); /* reset the hardware with the new settings */ e1000_reset ( adapter ); if ( ( err = register_netdev ( netdev ) ) != 0) goto err_register; /* Mark as link up; we don't yet handle link state */ netdev_link_up ( netdev ); for (i = 0; i < 6; i++) DBG ("%02x%s", netdev->ll_addr[i], i == 5 ? "\n" : ":"); DBG ( "e1000_probe succeeded!\n" ); /* No errors, return success */ return 0; /* Error return paths */ err_reset: err_register: err_hw_init: err_eeprom: if (!e1000_check_reset_block(&adapter->hw)) e1000_phy_hw_reset(&adapter->hw); if (adapter->hw.flash_address) iounmap(adapter->hw.flash_address); err_sw_init: iounmap ( adapter->hw.hw_addr ); err_ioremap: netdev_put ( netdev ); err_alloc_etherdev: return err; }