Пример #1
0
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;
	}
}
Пример #2
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;
}
Пример #3
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;
}
Пример #4
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;
}
Пример #5
0
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;
}
Пример #6
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;
}
Пример #7
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;
}
Пример #8
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;
}
Пример #9
0
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;
}
Пример #10
0
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);
}
Пример #11
0
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(&regs, addr, sizeof(regs)))
			return -EFAULT;
		e1000_ethtool_gregs(adapter, &regs, regs_buff);
		if(copy_to_user(addr, &regs, 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;
	}
}
Пример #12
0
/**
 * 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;
}