X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fnet%2Fixgb%2Fixgb_ethtool.c;h=e3ba1410af48fb477e12fa95699e5c75aba70cd2;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=78469e91e0fe014179136cc566845dee6b46eaaf;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c index 78469e91e..e3ba1410a 100644 --- a/drivers/net/ixgb/ixgb_ethtool.c +++ b/drivers/net/ixgb/ixgb_ethtool.c @@ -1,7 +1,7 @@ /******************************************************************************* - Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. + Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free @@ -23,6 +23,7 @@ Contact Information: Linux NICS Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + *******************************************************************************/ /* ethtool support for ixgb */ @@ -35,33 +36,75 @@ extern char ixgb_driver_name[]; extern char ixgb_driver_version[]; extern int ixgb_up(struct ixgb_adapter *adapter); -extern int ixgb_down(struct ixgb_adapter *adapter); - -/** - * ixgb_ethtool_ioctl - Ethtool Ioctl Support - * @netdev: net device structure - * @ifr: interface request structure - **/ - -static inline int -ixgb_eeprom_size(struct ixgb_hw *hw) -{ - /* return size in bytes */ - return (IXGB_EEPROM_SIZE << 1); -} - -#define SPEED_10000 10000 +extern void ixgb_down(struct ixgb_adapter *adapter, boolean_t kill_watchdog); +extern void ixgb_reset(struct ixgb_adapter *adapter); +extern int ixgb_setup_rx_resources(struct ixgb_adapter *adapter); +extern int ixgb_setup_tx_resources(struct ixgb_adapter *adapter); +extern void ixgb_free_rx_resources(struct ixgb_adapter *adapter); +extern void ixgb_free_tx_resources(struct ixgb_adapter *adapter); +extern void ixgb_update_stats(struct ixgb_adapter *adapter); + +struct ixgb_stats { + char stat_string[ETH_GSTRING_LEN]; + int sizeof_stat; + int stat_offset; +}; + +#define IXGB_STAT(m) sizeof(((struct ixgb_adapter *)0)->m), \ + offsetof(struct ixgb_adapter, m) +static struct ixgb_stats ixgb_gstrings_stats[] = { + {"rx_packets", IXGB_STAT(net_stats.rx_packets)}, + {"tx_packets", IXGB_STAT(net_stats.tx_packets)}, + {"rx_bytes", IXGB_STAT(net_stats.rx_bytes)}, + {"tx_bytes", IXGB_STAT(net_stats.tx_bytes)}, + {"rx_errors", IXGB_STAT(net_stats.rx_errors)}, + {"tx_errors", IXGB_STAT(net_stats.tx_errors)}, + {"rx_dropped", IXGB_STAT(net_stats.rx_dropped)}, + {"tx_dropped", IXGB_STAT(net_stats.tx_dropped)}, + {"multicast", IXGB_STAT(net_stats.multicast)}, + {"collisions", IXGB_STAT(net_stats.collisions)}, +/* { "rx_length_errors", IXGB_STAT(net_stats.rx_length_errors) }, */ + {"rx_over_errors", IXGB_STAT(net_stats.rx_over_errors)}, + {"rx_crc_errors", IXGB_STAT(net_stats.rx_crc_errors)}, + {"rx_frame_errors", IXGB_STAT(net_stats.rx_frame_errors)}, + {"rx_fifo_errors", IXGB_STAT(net_stats.rx_fifo_errors)}, + {"rx_missed_errors", IXGB_STAT(net_stats.rx_missed_errors)}, + {"tx_aborted_errors", IXGB_STAT(net_stats.tx_aborted_errors)}, + {"tx_carrier_errors", IXGB_STAT(net_stats.tx_carrier_errors)}, + {"tx_fifo_errors", IXGB_STAT(net_stats.tx_fifo_errors)}, + {"tx_heartbeat_errors", IXGB_STAT(net_stats.tx_heartbeat_errors)}, + {"tx_window_errors", IXGB_STAT(net_stats.tx_window_errors)}, + {"tx_deferred_ok", IXGB_STAT(stats.dc)}, + {"rx_long_length_errors", IXGB_STAT(stats.roc)}, + {"rx_short_length_errors", IXGB_STAT(stats.ruc)}, +#ifdef NETIF_F_TSO + {"tx_tcp_seg_good", IXGB_STAT(stats.tsctc)}, + {"tx_tcp_seg_failed", IXGB_STAT(stats.tsctfc)}, +#endif + {"rx_flow_control_xon", IXGB_STAT(stats.xonrxc)}, + {"rx_flow_control_xoff", IXGB_STAT(stats.xoffrxc)}, + {"tx_flow_control_xon", IXGB_STAT(stats.xontxc)}, + {"tx_flow_control_xoff", IXGB_STAT(stats.xofftxc)}, + {"rx_csum_offload_good", IXGB_STAT(hw_csum_rx_good)}, + {"rx_csum_offload_errors", IXGB_STAT(hw_csum_rx_error)}, + {"tx_csum_offload_good", IXGB_STAT(hw_csum_tx_good)}, + {"tx_csum_offload_errors", IXGB_STAT(hw_csum_tx_error)} +}; + +#define IXGB_STATS_LEN \ + sizeof(ixgb_gstrings_stats) / sizeof(struct ixgb_stats) -static void -ixgb_ethtool_gset(struct ixgb_adapter *adapter, struct ethtool_cmd *ecmd) +static int +ixgb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) { + struct ixgb_adapter *adapter = netdev->priv; ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); ecmd->advertising = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); ecmd->port = PORT_FIBRE; ecmd->transceiver = XCVR_EXTERNAL; - if (netif_carrier_ok(adapter->netdev)) { - ecmd->speed = 10000; + if(netif_carrier_ok(adapter->netdev)) { + ecmd->speed = SPEED_10000; ecmd->duplex = DUPLEX_FULL; } else { ecmd->speed = -1; @@ -69,76 +112,144 @@ ixgb_ethtool_gset(struct ixgb_adapter *adapter, struct ethtool_cmd *ecmd) } ecmd->autoneg = AUTONEG_DISABLE; + return 0; } static int -ixgb_ethtool_sset(struct ixgb_adapter *adapter, struct ethtool_cmd *ecmd) +ixgb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) { - if (ecmd->autoneg == AUTONEG_ENABLE || - ecmd->speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL) + struct ixgb_adapter *adapter = netdev->priv; + if(ecmd->autoneg == AUTONEG_ENABLE || + ecmd->speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL) return -EINVAL; - else { - ixgb_down(adapter); + + if(netif_running(adapter->netdev)) { + ixgb_down(adapter, TRUE); + ixgb_reset(adapter); ixgb_up(adapter); - } + } else + ixgb_reset(adapter); return 0; } -#if 0 -static int -ixgb_ethtool_promiscuous(struct ixgb_adapter *adapter, - struct ethtool_pmode *pmode) +static void +ixgb_get_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) { - u32 rctl = IXGB_READ_REG(&adapter->hw, RCTL); + struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_hw *hw = &adapter->hw; + + pause->autoneg = AUTONEG_DISABLE; + + if(hw->fc.type == ixgb_fc_rx_pause) + pause->rx_pause = 1; + else if(hw->fc.type == ixgb_fc_tx_pause) + pause->tx_pause = 1; + else if(hw->fc.type == ixgb_fc_full) { + pause->rx_pause = 1; + pause->tx_pause = 1; + } +} - pmode->rctl_old = rctl; - if (pmode->upe) - rctl |= IXGB_RCTL_UPE; - else - rctl &= ~IXGB_RCTL_UPE; +static int +ixgb_set_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) +{ + struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_hw *hw = &adapter->hw; + + if(pause->autoneg == AUTONEG_ENABLE) + return -EINVAL; - if (pmode->mpe) - rctl |= IXGB_RCTL_MPE; - else - rctl &= ~IXGB_RCTL_MPE; + if(pause->rx_pause && pause->tx_pause) + hw->fc.type = ixgb_fc_full; + else if(pause->rx_pause && !pause->tx_pause) + hw->fc.type = ixgb_fc_rx_pause; + else if(!pause->rx_pause && pause->tx_pause) + hw->fc.type = ixgb_fc_tx_pause; + else if(!pause->rx_pause && !pause->tx_pause) + hw->fc.type = ixgb_fc_none; + + if(netif_running(adapter->netdev)) { + ixgb_down(adapter, TRUE); + ixgb_up(adapter); + } else + ixgb_reset(adapter); + + return 0; +} - IXGB_WRITE_REG(&adapter->hw, RCTL, rctl); +static uint32_t +ixgb_get_rx_csum(struct net_device *netdev) +{ + struct ixgb_adapter *adapter = netdev->priv; + return adapter->rx_csum; +} - pmode->rctl_new = IXGB_READ_REG(&adapter->hw, RCTL); +static int +ixgb_set_rx_csum(struct net_device *netdev, uint32_t data) +{ + struct ixgb_adapter *adapter = netdev->priv; + adapter->rx_csum = data; + if(netif_running(netdev)) { + ixgb_down(adapter,TRUE); + ixgb_up(adapter); + } else + ixgb_reset(adapter); return 0; } -#endif + +static uint32_t +ixgb_get_tx_csum(struct net_device *netdev) +{ + return (netdev->features & NETIF_F_HW_CSUM) != 0; +} -#define IXGB_REG_DUMP_LEN 136*sizeof(u32) -static void -ixgb_ethtool_gdrvinfo(struct ixgb_adapter *adapter, - struct ethtool_drvinfo *drvinfo) +static int +ixgb_set_tx_csum(struct net_device *netdev, uint32_t data) { - strncpy(drvinfo->driver, ixgb_driver_name, 32); - strncpy(drvinfo->version, ixgb_driver_version, 32); - strncpy(drvinfo->fw_version, "", 32); - strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); -#ifdef ETHTOOL_GREGS - drvinfo->regdump_len = IXGB_REG_DUMP_LEN; -#endif /* ETHTOOL_GREGS */ - drvinfo->eedump_len = ixgb_eeprom_size(&adapter->hw); + if (data) + netdev->features |= NETIF_F_HW_CSUM; + else + netdev->features &= ~NETIF_F_HW_CSUM; + + return 0; } -#ifdef ETHTOOL_GREGS +#ifdef NETIF_F_TSO +static int +ixgb_set_tso(struct net_device *netdev, uint32_t data) +{ + if(data) + netdev->features |= NETIF_F_TSO; + else + netdev->features &= ~NETIF_F_TSO; + return 0; +} +#endif /* NETIF_F_TSO */ + #define IXGB_GET_STAT(_A_, _R_) _A_->stats._R_ + +static int +ixgb_get_regs_len(struct net_device *netdev) +{ +#define IXGB_REG_DUMP_LEN 136*sizeof(uint32_t) + return IXGB_REG_DUMP_LEN; +} + static void -ixgb_ethtool_gregs(struct ixgb_adapter *adapter, - struct ethtool_regs *regs, u8 * regs_buff) +ixgb_get_regs(struct net_device *netdev, + struct ethtool_regs *regs, void *p) { + struct ixgb_adapter *adapter = netdev->priv; struct ixgb_hw *hw = &adapter->hw; - u32 *reg = (u32 *) regs_buff; - u32 *reg_start = reg; - u8 i; + uint32_t *reg = p; + uint32_t *reg_start = reg; + uint8_t i; - regs->version = - (adapter->hw.device_id << 16) | adapter->hw.subsystem_id; + regs->version = (adapter->hw.device_id << 16) | adapter->hw.subsystem_id; /* General Registers */ *reg++ = IXGB_READ_REG(hw, CTRL0); /* 0 */ @@ -168,8 +279,8 @@ ixgb_ethtool_gregs(struct ixgb_adapter *adapter, *reg++ = IXGB_READ_REG(hw, RXCSUM); /* 20 */ for (i = 0; i < IXGB_RAR_ENTRIES; i++) { - *reg++ = IXGB_READ_REG_ARRAY(hw, RAL, (i << 1)); /*21,...,51 */ - *reg++ = IXGB_READ_REG_ARRAY(hw, RAH, (i << 1)); /*22,...,52 */ + *reg++ = IXGB_READ_REG_ARRAY(hw, RAL, (i << 1)); /*21,...,51 */ + *reg++ = IXGB_READ_REG_ARRAY(hw, RAH, (i << 1)); /*22,...,52 */ } /* Transmit */ @@ -199,15 +310,6 @@ ixgb_ethtool_gregs(struct ixgb_adapter *adapter, *reg++ = IXGB_READ_REG(hw, MSCA); /* 74 */ *reg++ = IXGB_READ_REG(hw, MSRWD); /* 75 */ -#if 0 - /* Wake-up */ - reg[IXGB_WUFC] = IXGB_READ_REG(hw, WUFC); - reg[IXGB_WUS] = IXGB_READ_REG(hw, WUS); - reg[IXGB_FFLT] = IXGB_READ_REG(hw, FFLT); - reg[IXGB_FFMT] = IXGB_READ_REG(hw, FFMT); - reg[IXGB_FTVT] = IXGB_READ_REG(hw, FTVT); -#endif - /* Statistics */ *reg++ = IXGB_GET_STAT(adapter, tprl); /* 76 */ *reg++ = IXGB_GET_STAT(adapter, tprh); /* 77 */ @@ -270,111 +372,226 @@ ixgb_ethtool_gregs(struct ixgb_adapter *adapter, *reg++ = IXGB_GET_STAT(adapter, xofftxc); /* 134 */ *reg++ = IXGB_GET_STAT(adapter, rjc); /* 135 */ -#if 0 -#endif - regs->len = (reg - reg_start) * sizeof (u32); + regs->len = (reg - reg_start) * sizeof(uint32_t); +} + +static int +ixgb_get_eeprom_len(struct net_device *netdev) +{ + /* return size in bytes */ + return (IXGB_EEPROM_SIZE << 1); } -#endif /* ETHTOOL_GREGS */ static int -ixgb_ethtool_geeprom(struct ixgb_adapter *adapter, - struct ethtool_eeprom *eeprom, u16 * eeprom_buff) +ixgb_get_eeprom(struct net_device *netdev, + struct ethtool_eeprom *eeprom, uint8_t *bytes) { + struct ixgb_adapter *adapter = netdev->priv; struct ixgb_hw *hw = &adapter->hw; + uint16_t *eeprom_buff; int i, max_len, first_word, last_word; - IXGB_DBG("ixgb_ethtool_geeprom\n"); + int ret_val = 0; - if (eeprom->len == 0) - return -EINVAL; + if(eeprom->len == 0) { + ret_val = -EINVAL; + goto geeprom_error; + } eeprom->magic = hw->vendor_id | (hw->device_id << 16); - max_len = ixgb_eeprom_size(hw); - - /* use our function to read the eeprom and update our cache */ - ixgb_get_eeprom_data(hw); + max_len = ixgb_get_eeprom_len(netdev); - if (eeprom->offset > eeprom->offset + eeprom->len) - return -EINVAL; + if(eeprom->offset > eeprom->offset + eeprom->len) { + ret_val = -EINVAL; + goto geeprom_error; + } - if ((eeprom->offset + eeprom->len) > max_len) + if((eeprom->offset + eeprom->len) > max_len) eeprom->len = (max_len - eeprom->offset); first_word = eeprom->offset >> 1; last_word = (eeprom->offset + eeprom->len - 1) >> 1; - for (i = 0; i <= (last_word - first_word); i++) { - eeprom_buff[i] = hw->eeprom[first_word + i]; + eeprom_buff = kmalloc(sizeof(uint16_t) * + (last_word - first_word + 1), GFP_KERNEL); + if(!eeprom_buff) + return -ENOMEM; + + /* note the eeprom was good because the driver loaded */ + for(i = 0; i <= (last_word - first_word); i++) { + eeprom_buff[i] = ixgb_get_eeprom_word(hw, (first_word + i)); } - return 0; + memcpy(bytes, (uint8_t *)eeprom_buff + (eeprom->offset & 1), + eeprom->len); + kfree(eeprom_buff); + +geeprom_error: + return ret_val; } + static int -ixgb_ethtool_seeprom(struct ixgb_adapter *adapter, - struct ethtool_eeprom *eeprom, void *user_data) +ixgb_set_eeprom(struct net_device *netdev, + struct ethtool_eeprom *eeprom, uint8_t *bytes) { + struct ixgb_adapter *adapter = netdev->priv; struct ixgb_hw *hw = &adapter->hw; - u16 eeprom_buff[256]; - int i, max_len, first_word, last_word; + uint16_t *eeprom_buff; void *ptr; + int max_len, first_word, last_word; + uint16_t i; - if (eeprom->magic != (hw->vendor_id | (hw->device_id << 16))) - return -EFAULT; - - if (eeprom->len == 0) + if(eeprom->len == 0) return -EINVAL; - max_len = ixgb_eeprom_size(hw); + if(eeprom->magic != (hw->vendor_id | (hw->device_id << 16))) + return -EFAULT; + + max_len = ixgb_get_eeprom_len(netdev); - if (eeprom->offset > eeprom->offset + eeprom->len) + if(eeprom->offset > eeprom->offset + eeprom->len) return -EINVAL; - if ((eeprom->offset + eeprom->len) > max_len) + if((eeprom->offset + eeprom->len) > max_len) eeprom->len = (max_len - eeprom->offset); first_word = eeprom->offset >> 1; last_word = (eeprom->offset + eeprom->len - 1) >> 1; - ptr = (void *) eeprom_buff; + eeprom_buff = kmalloc(max_len, GFP_KERNEL); + if(!eeprom_buff) + return -ENOMEM; - if (eeprom->offset & 1) { + ptr = (void *)eeprom_buff; + + if(eeprom->offset & 1) { /* need read/modify/write of first changed EEPROM word */ /* only the second byte of the word is being modified */ eeprom_buff[0] = ixgb_read_eeprom(hw, first_word); ptr++; } - if ((eeprom->offset + eeprom->len) & 1) { + if((eeprom->offset + eeprom->len) & 1) { /* need read/modify/write of last changed EEPROM word */ /* only the first byte of the word is being modified */ - eeprom_buff[last_word - first_word] - = ixgb_read_eeprom(hw, last_word); + eeprom_buff[last_word - first_word] + = ixgb_read_eeprom(hw, last_word); } - if (copy_from_user(ptr, user_data, eeprom->len)) - return -EFAULT; - for (i = 0; i <= (last_word - first_word); i++) + memcpy(ptr, bytes, eeprom->len); + for(i = 0; i <= (last_word - first_word); i++) ixgb_write_eeprom(hw, first_word + i, eeprom_buff[i]); /* Update the checksum over the first part of the EEPROM if needed */ - if (first_word <= EEPROM_CHECKSUM_REG) + if(first_word <= EEPROM_CHECKSUM_REG) ixgb_update_eeprom_checksum(hw); + kfree(eeprom_buff); return 0; } -#ifdef ETHTOOL_PHYS_ID +static void +ixgb_get_drvinfo(struct net_device *netdev, + struct ethtool_drvinfo *drvinfo) +{ + struct ixgb_adapter *adapter = netdev->priv; + + strncpy(drvinfo->driver, ixgb_driver_name, 32); + strncpy(drvinfo->version, ixgb_driver_version, 32); + strncpy(drvinfo->fw_version, "N/A", 32); + strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); + drvinfo->n_stats = IXGB_STATS_LEN; + drvinfo->regdump_len = ixgb_get_regs_len(netdev); + drvinfo->eedump_len = ixgb_get_eeprom_len(netdev); +} + +static void +ixgb_get_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) +{ + struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_desc_ring *txdr = &adapter->tx_ring; + struct ixgb_desc_ring *rxdr = &adapter->rx_ring; + + ring->rx_max_pending = MAX_RXD; + ring->tx_max_pending = MAX_TXD; + ring->rx_mini_max_pending = 0; + ring->rx_jumbo_max_pending = 0; + ring->rx_pending = rxdr->count; + ring->tx_pending = txdr->count; + ring->rx_mini_pending = 0; + ring->rx_jumbo_pending = 0; +} + +static int +ixgb_set_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) +{ + struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_desc_ring *txdr = &adapter->tx_ring; + struct ixgb_desc_ring *rxdr = &adapter->rx_ring; + struct ixgb_desc_ring tx_old, tx_new, rx_old, rx_new; + int err; + + tx_old = adapter->tx_ring; + rx_old = adapter->rx_ring; + + if((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) + return -EINVAL; + + if(netif_running(adapter->netdev)) + ixgb_down(adapter,TRUE); + + rxdr->count = max(ring->rx_pending,(uint32_t)MIN_RXD); + rxdr->count = min(rxdr->count,(uint32_t)MAX_RXD); + IXGB_ROUNDUP(rxdr->count, IXGB_REQ_RX_DESCRIPTOR_MULTIPLE); + + txdr->count = max(ring->tx_pending,(uint32_t)MIN_TXD); + txdr->count = min(txdr->count,(uint32_t)MAX_TXD); + IXGB_ROUNDUP(txdr->count, IXGB_REQ_TX_DESCRIPTOR_MULTIPLE); + + if(netif_running(adapter->netdev)) { + /* Try to get new resources before deleting old */ + if((err = ixgb_setup_rx_resources(adapter))) + goto err_setup_rx; + if((err = ixgb_setup_tx_resources(adapter))) + goto err_setup_tx; + + /* save the new, restore the old in order to free it, + * then restore the new back again */ + + rx_new = adapter->rx_ring; + tx_new = adapter->tx_ring; + adapter->rx_ring = rx_old; + adapter->tx_ring = tx_old; + ixgb_free_rx_resources(adapter); + ixgb_free_tx_resources(adapter); + adapter->rx_ring = rx_new; + adapter->tx_ring = tx_new; + if((err = ixgb_up(adapter))) + return err; + } + + return 0; +err_setup_tx: + ixgb_free_rx_resources(adapter); +err_setup_rx: + adapter->rx_ring = rx_old; + adapter->tx_ring = tx_old; + ixgb_up(adapter); + return err; +} /* toggle LED 4 times per second = 2 "blinks" per second */ -#define IXGB_ID_INTERVAL (HZ/4) +#define IXGB_ID_INTERVAL (HZ/4) /* bit defines for adapter->led_status */ -#define IXGB_LED_ON 0 +#define IXGB_LED_ON 0 static void ixgb_led_blink_callback(unsigned long data) { - struct ixgb_adapter *adapter = (struct ixgb_adapter *) data; + struct ixgb_adapter *adapter = (struct ixgb_adapter *)data; - if (test_and_change_bit(IXGB_LED_ON, &adapter->led_status)) + if(test_and_change_bit(IXGB_LED_ON, &adapter->led_status)) ixgb_led_off(&adapter->hw); else ixgb_led_on(&adapter->hw); @@ -383,19 +600,24 @@ ixgb_led_blink_callback(unsigned long data) } static int -ixgb_ethtool_led_blink(struct ixgb_adapter *adapter, struct ethtool_value *id) +ixgb_phys_id(struct net_device *netdev, uint32_t data) { - if (!adapter->blink_timer.function) { + struct ixgb_adapter *adapter = netdev->priv; + + if(!data || data > (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ)) + data = (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ); + + if(!adapter->blink_timer.function) { init_timer(&adapter->blink_timer); adapter->blink_timer.function = ixgb_led_blink_callback; - adapter->blink_timer.data = (unsigned long) adapter; + adapter->blink_timer.data = (unsigned long)adapter; } mod_timer(&adapter->blink_timer, jiffies); set_current_state(TASK_INTERRUPTIBLE); - if (id->data) - schedule_timeout(id->data * HZ); + if(data) + schedule_timeout(data * HZ); else schedule_timeout(MAX_SCHEDULE_TIMEOUT); @@ -405,142 +627,75 @@ ixgb_ethtool_led_blink(struct ixgb_adapter *adapter, struct ethtool_value *id) return 0; } -#endif /* ETHTOOL_PHYS_ID */ -int -ixgb_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr) +static int +ixgb_get_stats_count(struct net_device *netdev) { - struct ixgb_adapter *adapter = netdev->priv; - void *addr = ifr->ifr_data; - u32 cmd; - - if (get_user(cmd, (u32 *) addr)) - return -EFAULT; - - switch (cmd) { -#if 0 - case ETHTOOL_PROMISCUOUS:{ - struct ethtool_pmode pmode; - - if (copy_from_user(&pmode, addr, sizeof (pmode))) - return -EFAULT; - - ixgb_ethtool_promiscuous(adapter, &pmode); - - if (copy_to_user(addr, &pmode, sizeof (pmode))) - return -EFAULT; - - return 0; - } - case ETHTOOL_DOWN_UP: - ixgb_down(netdev->priv); - ixgb_up(netdev->priv); - return 0; -#endif - case ETHTOOL_GSET:{ - struct ethtool_cmd ecmd = { ETHTOOL_GSET }; - - ixgb_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 ixgb_ethtool_sset(adapter, &ecmd); - } - case ETHTOOL_GDRVINFO: - { - struct ethtool_drvinfo drvinfo = { ETHTOOL_GDRVINFO }; - - ixgb_ethtool_gdrvinfo(adapter, &drvinfo); - if (copy_to_user(addr, &drvinfo, sizeof (drvinfo))) - return -EFAULT; - return 0; - } -#if defined(ETHTOOL_GREGS) && defined(ETHTOOL_GEEPROM) - case ETHTOOL_GREGS:{ - struct ethtool_regs regs = { ETHTOOL_GREGS }; - u8 regs_buff[IXGB_REG_DUMP_LEN]; - - ixgb_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; - } -#endif /* ETHTOOL_GREGS */ - case ETHTOOL_NWAY_RST:{ - IXGB_DBG("ETHTOOL_NWAY_RST\n"); - ixgb_down(adapter); - ixgb_up(adapter); - - return 0; - } -#ifdef ETHTOOL_PHYS_ID - case ETHTOOL_PHYS_ID:{ - struct ethtool_value id; - - IXGB_DBG("ETHTOOL_PHYS_ID\n"); - if (copy_from_user(&id, addr, sizeof (id))) - return -EFAULT; - return ixgb_ethtool_led_blink(adapter, &id); - } -#endif /* ETHTOOL_PHYS_ID */ - case ETHTOOL_GLINK:{ - struct ethtool_value link = { ETHTOOL_GLINK }; - - IXGB_DBG("ETHTOOL_GLINK\n"); - link.data = netif_carrier_ok(netdev); - if (copy_to_user(addr, &link, sizeof (link))) - return -EFAULT; - return 0; - } - - case ETHTOOL_GEEPROM:{ - struct ethtool_eeprom eeprom = { ETHTOOL_GEEPROM }; - u16 eeprom_buff[IXGB_EEPROM_SIZE]; - void *ptr; - int err; - - IXGB_DBG("ETHTOOL_GEEPROM\n"); - if (copy_from_user(&eeprom, addr, sizeof (eeprom))) - return -EFAULT; - - if ((err = - ixgb_ethtool_geeprom(adapter, &eeprom, - eeprom_buff)) < 0) - return err; + return IXGB_STATS_LEN; +} - if (copy_to_user(addr, &eeprom, sizeof (eeprom))) - return -EFAULT; +static void +ixgb_get_ethtool_stats(struct net_device *netdev, + struct ethtool_stats *stats, uint64_t *data) +{ + struct ixgb_adapter *adapter = netdev->priv; + int i; - addr += offsetof(struct ethtool_eeprom, data); + ixgb_update_stats(adapter); + for(i = 0; i < IXGB_STATS_LEN; i++) { + char *p = (char *)adapter+ixgb_gstrings_stats[i].stat_offset; + data[i] = (ixgb_gstrings_stats[i].sizeof_stat == + sizeof(uint64_t)) ? *(uint64_t *)p : *(uint32_t *)p; + } +} - ptr = ((void *) eeprom_buff) + (eeprom.offset & 1); - if (copy_to_user(addr, ptr, eeprom.len)) - return -EFAULT; - return 0; +static void +ixgb_get_strings(struct net_device *netdev, uint32_t stringset, uint8_t *data) +{ + int i; + + switch(stringset) { + case ETH_SS_STATS: + for(i=0; i < IXGB_STATS_LEN; i++) { + memcpy(data + i * ETH_GSTRING_LEN, + ixgb_gstrings_stats[i].stat_string, + ETH_GSTRING_LEN); } - case ETHTOOL_SEEPROM:{ - struct ethtool_eeprom eeprom; + break; + } +} - IXGB_DBG("ETHTOOL_SEEPROM\n"); - if (copy_from_user(&eeprom, addr, sizeof (eeprom))) - return -EFAULT; +struct ethtool_ops ixgb_ethtool_ops = { + .get_settings = ixgb_get_settings, + .set_settings = ixgb_set_settings, + .get_drvinfo = ixgb_get_drvinfo, + .get_regs_len = ixgb_get_regs_len, + .get_regs = ixgb_get_regs, + .get_link = ethtool_op_get_link, + .get_eeprom_len = ixgb_get_eeprom_len, + .get_eeprom = ixgb_get_eeprom, + .set_eeprom = ixgb_set_eeprom, + .get_ringparam = ixgb_get_ringparam, + .set_ringparam = ixgb_set_ringparam, + .get_pauseparam = ixgb_get_pauseparam, + .set_pauseparam = ixgb_set_pauseparam, + .get_rx_csum = ixgb_get_rx_csum, + .set_rx_csum = ixgb_set_rx_csum, + .get_tx_csum = ixgb_get_tx_csum, + .set_tx_csum = ixgb_set_tx_csum, + .get_sg = ethtool_op_get_sg, + .set_sg = ethtool_op_set_sg, +#ifdef NETIF_F_TSO + .get_tso = ethtool_op_get_tso, + .set_tso = ixgb_set_tso, +#endif + .get_strings = ixgb_get_strings, + .phys_id = ixgb_phys_id, + .get_stats_count = ixgb_get_stats_count, + .get_ethtool_stats = ixgb_get_ethtool_stats, +}; - addr += offsetof(struct ethtool_eeprom, data); - return ixgb_ethtool_seeprom(adapter, &eeprom, addr); - } - default: - return -EOPNOTSUPP; - } +void ixgb_set_ethtool_ops(struct net_device *netdev) +{ + SET_ETHTOOL_OPS(netdev, &ixgb_ethtool_ops); }