| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 1 | /**************************************************************************** | 
|  | 2 | * Driver for Solarflare Solarstorm network controllers and boards | 
|  | 3 | * Copyright 2005-2006 Fen Systems Ltd. | 
| Ben Hutchings | 0a6f40c | 2011-02-25 00:01:34 +0000 | [diff] [blame] | 4 | * Copyright 2006-2010 Solarflare Communications Inc. | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 5 | * | 
|  | 6 | * This program is free software; you can redistribute it and/or modify it | 
|  | 7 | * under the terms of the GNU General Public License version 2 as published | 
|  | 8 | * by the Free Software Foundation, incorporated herein by reference. | 
|  | 9 | */ | 
|  | 10 |  | 
|  | 11 | #include <linux/netdevice.h> | 
|  | 12 | #include <linux/ethtool.h> | 
|  | 13 | #include <linux/rtnetlink.h> | 
| Ben Hutchings | c39d35e | 2010-12-07 19:11:26 +0000 | [diff] [blame] | 14 | #include <linux/in.h> | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 15 | #include "net_driver.h" | 
| Ben Hutchings | 04cc8ca | 2008-12-12 21:50:46 -0800 | [diff] [blame] | 16 | #include "workarounds.h" | 
| Ben Hutchings | 3273c2e | 2008-05-07 13:36:19 +0100 | [diff] [blame] | 17 | #include "selftest.h" | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 18 | #include "efx.h" | 
| Ben Hutchings | b4187e4 | 2010-09-20 08:43:42 +0000 | [diff] [blame] | 19 | #include "filter.h" | 
| Ben Hutchings | 744093c | 2009-11-29 15:12:08 +0000 | [diff] [blame] | 20 | #include "nic.h" | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 21 |  | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 22 | struct ethtool_string { | 
|  | 23 | char name[ETH_GSTRING_LEN]; | 
|  | 24 | }; | 
|  | 25 |  | 
|  | 26 | struct efx_ethtool_stat { | 
|  | 27 | const char *name; | 
|  | 28 | enum { | 
|  | 29 | EFX_ETHTOOL_STAT_SOURCE_mac_stats, | 
|  | 30 | EFX_ETHTOOL_STAT_SOURCE_nic, | 
| Ben Hutchings | 119226c | 2011-02-18 19:14:13 +0000 | [diff] [blame] | 31 | EFX_ETHTOOL_STAT_SOURCE_channel, | 
|  | 32 | EFX_ETHTOOL_STAT_SOURCE_tx_queue | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 33 | } source; | 
|  | 34 | unsigned offset; | 
|  | 35 | u64(*get_stat) (void *field); /* Reader function */ | 
|  | 36 | }; | 
|  | 37 |  | 
|  | 38 | /* Initialiser for a struct #efx_ethtool_stat with type-checking */ | 
|  | 39 | #define EFX_ETHTOOL_STAT(stat_name, source_name, field, field_type, \ | 
|  | 40 | get_stat_function) {			\ | 
|  | 41 | .name = #stat_name,						\ | 
|  | 42 | .source = EFX_ETHTOOL_STAT_SOURCE_##source_name,		\ | 
|  | 43 | .offset = ((((field_type *) 0) ==				\ | 
|  | 44 | &((struct efx_##source_name *)0)->field) ?	\ | 
|  | 45 | offsetof(struct efx_##source_name, field) :		\ | 
|  | 46 | offsetof(struct efx_##source_name, field)),		\ | 
|  | 47 | .get_stat = get_stat_function,					\ | 
|  | 48 | } | 
|  | 49 |  | 
|  | 50 | static u64 efx_get_uint_stat(void *field) | 
|  | 51 | { | 
|  | 52 | return *(unsigned int *)field; | 
|  | 53 | } | 
|  | 54 |  | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 55 | static u64 efx_get_u64_stat(void *field) | 
|  | 56 | { | 
|  | 57 | return *(u64 *) field; | 
|  | 58 | } | 
|  | 59 |  | 
|  | 60 | static u64 efx_get_atomic_stat(void *field) | 
|  | 61 | { | 
|  | 62 | return atomic_read((atomic_t *) field); | 
|  | 63 | } | 
|  | 64 |  | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 65 | #define EFX_ETHTOOL_U64_MAC_STAT(field)				\ | 
| Ben Hutchings | 9c636ba | 2012-01-05 17:19:45 +0000 | [diff] [blame] | 66 | EFX_ETHTOOL_STAT(field, mac_stats, field,		\ | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 67 | u64, efx_get_u64_stat) | 
|  | 68 |  | 
|  | 69 | #define EFX_ETHTOOL_UINT_NIC_STAT(name)				\ | 
|  | 70 | EFX_ETHTOOL_STAT(name, nic, n_##name,			\ | 
|  | 71 | unsigned int, efx_get_uint_stat) | 
|  | 72 |  | 
|  | 73 | #define EFX_ETHTOOL_ATOMIC_NIC_ERROR_STAT(field)		\ | 
|  | 74 | EFX_ETHTOOL_STAT(field, nic, field,			\ | 
|  | 75 | atomic_t, efx_get_atomic_stat) | 
|  | 76 |  | 
|  | 77 | #define EFX_ETHTOOL_UINT_CHANNEL_STAT(field)			\ | 
|  | 78 | EFX_ETHTOOL_STAT(field, channel, n_##field,		\ | 
|  | 79 | unsigned int, efx_get_uint_stat) | 
|  | 80 |  | 
| Ben Hutchings | 119226c | 2011-02-18 19:14:13 +0000 | [diff] [blame] | 81 | #define EFX_ETHTOOL_UINT_TXQ_STAT(field)			\ | 
|  | 82 | EFX_ETHTOOL_STAT(tx_##field, tx_queue, field,		\ | 
|  | 83 | unsigned int, efx_get_uint_stat) | 
|  | 84 |  | 
| Ben Hutchings | 18e83e4 | 2012-01-05 19:05:20 +0000 | [diff] [blame] | 85 | static const struct efx_ethtool_stat efx_ethtool_stats[] = { | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 86 | EFX_ETHTOOL_U64_MAC_STAT(tx_bytes), | 
|  | 87 | EFX_ETHTOOL_U64_MAC_STAT(tx_good_bytes), | 
|  | 88 | EFX_ETHTOOL_U64_MAC_STAT(tx_bad_bytes), | 
| Ben Hutchings | f9c7625 | 2011-10-12 17:20:25 +0100 | [diff] [blame] | 89 | EFX_ETHTOOL_U64_MAC_STAT(tx_packets), | 
|  | 90 | EFX_ETHTOOL_U64_MAC_STAT(tx_bad), | 
|  | 91 | EFX_ETHTOOL_U64_MAC_STAT(tx_pause), | 
|  | 92 | EFX_ETHTOOL_U64_MAC_STAT(tx_control), | 
|  | 93 | EFX_ETHTOOL_U64_MAC_STAT(tx_unicast), | 
|  | 94 | EFX_ETHTOOL_U64_MAC_STAT(tx_multicast), | 
|  | 95 | EFX_ETHTOOL_U64_MAC_STAT(tx_broadcast), | 
|  | 96 | EFX_ETHTOOL_U64_MAC_STAT(tx_lt64), | 
|  | 97 | EFX_ETHTOOL_U64_MAC_STAT(tx_64), | 
|  | 98 | EFX_ETHTOOL_U64_MAC_STAT(tx_65_to_127), | 
|  | 99 | EFX_ETHTOOL_U64_MAC_STAT(tx_128_to_255), | 
|  | 100 | EFX_ETHTOOL_U64_MAC_STAT(tx_256_to_511), | 
|  | 101 | EFX_ETHTOOL_U64_MAC_STAT(tx_512_to_1023), | 
|  | 102 | EFX_ETHTOOL_U64_MAC_STAT(tx_1024_to_15xx), | 
|  | 103 | EFX_ETHTOOL_U64_MAC_STAT(tx_15xx_to_jumbo), | 
|  | 104 | EFX_ETHTOOL_U64_MAC_STAT(tx_gtjumbo), | 
|  | 105 | EFX_ETHTOOL_U64_MAC_STAT(tx_collision), | 
|  | 106 | EFX_ETHTOOL_U64_MAC_STAT(tx_single_collision), | 
|  | 107 | EFX_ETHTOOL_U64_MAC_STAT(tx_multiple_collision), | 
|  | 108 | EFX_ETHTOOL_U64_MAC_STAT(tx_excessive_collision), | 
|  | 109 | EFX_ETHTOOL_U64_MAC_STAT(tx_deferred), | 
|  | 110 | EFX_ETHTOOL_U64_MAC_STAT(tx_late_collision), | 
|  | 111 | EFX_ETHTOOL_U64_MAC_STAT(tx_excessive_deferred), | 
|  | 112 | EFX_ETHTOOL_U64_MAC_STAT(tx_non_tcpudp), | 
|  | 113 | EFX_ETHTOOL_U64_MAC_STAT(tx_mac_src_error), | 
|  | 114 | EFX_ETHTOOL_U64_MAC_STAT(tx_ip_src_error), | 
| Ben Hutchings | 119226c | 2011-02-18 19:14:13 +0000 | [diff] [blame] | 115 | EFX_ETHTOOL_UINT_TXQ_STAT(tso_bursts), | 
|  | 116 | EFX_ETHTOOL_UINT_TXQ_STAT(tso_long_headers), | 
|  | 117 | EFX_ETHTOOL_UINT_TXQ_STAT(tso_packets), | 
|  | 118 | EFX_ETHTOOL_UINT_TXQ_STAT(pushes), | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 119 | EFX_ETHTOOL_U64_MAC_STAT(rx_bytes), | 
|  | 120 | EFX_ETHTOOL_U64_MAC_STAT(rx_good_bytes), | 
|  | 121 | EFX_ETHTOOL_U64_MAC_STAT(rx_bad_bytes), | 
| Ben Hutchings | f9c7625 | 2011-10-12 17:20:25 +0100 | [diff] [blame] | 122 | EFX_ETHTOOL_U64_MAC_STAT(rx_packets), | 
|  | 123 | EFX_ETHTOOL_U64_MAC_STAT(rx_good), | 
|  | 124 | EFX_ETHTOOL_U64_MAC_STAT(rx_bad), | 
|  | 125 | EFX_ETHTOOL_U64_MAC_STAT(rx_pause), | 
|  | 126 | EFX_ETHTOOL_U64_MAC_STAT(rx_control), | 
|  | 127 | EFX_ETHTOOL_U64_MAC_STAT(rx_unicast), | 
|  | 128 | EFX_ETHTOOL_U64_MAC_STAT(rx_multicast), | 
|  | 129 | EFX_ETHTOOL_U64_MAC_STAT(rx_broadcast), | 
|  | 130 | EFX_ETHTOOL_U64_MAC_STAT(rx_lt64), | 
|  | 131 | EFX_ETHTOOL_U64_MAC_STAT(rx_64), | 
|  | 132 | EFX_ETHTOOL_U64_MAC_STAT(rx_65_to_127), | 
|  | 133 | EFX_ETHTOOL_U64_MAC_STAT(rx_128_to_255), | 
|  | 134 | EFX_ETHTOOL_U64_MAC_STAT(rx_256_to_511), | 
|  | 135 | EFX_ETHTOOL_U64_MAC_STAT(rx_512_to_1023), | 
|  | 136 | EFX_ETHTOOL_U64_MAC_STAT(rx_1024_to_15xx), | 
|  | 137 | EFX_ETHTOOL_U64_MAC_STAT(rx_15xx_to_jumbo), | 
|  | 138 | EFX_ETHTOOL_U64_MAC_STAT(rx_gtjumbo), | 
|  | 139 | EFX_ETHTOOL_U64_MAC_STAT(rx_bad_lt64), | 
|  | 140 | EFX_ETHTOOL_U64_MAC_STAT(rx_bad_64_to_15xx), | 
|  | 141 | EFX_ETHTOOL_U64_MAC_STAT(rx_bad_15xx_to_jumbo), | 
|  | 142 | EFX_ETHTOOL_U64_MAC_STAT(rx_bad_gtjumbo), | 
|  | 143 | EFX_ETHTOOL_U64_MAC_STAT(rx_overflow), | 
|  | 144 | EFX_ETHTOOL_U64_MAC_STAT(rx_missed), | 
|  | 145 | EFX_ETHTOOL_U64_MAC_STAT(rx_false_carrier), | 
|  | 146 | EFX_ETHTOOL_U64_MAC_STAT(rx_symbol_error), | 
|  | 147 | EFX_ETHTOOL_U64_MAC_STAT(rx_align_error), | 
|  | 148 | EFX_ETHTOOL_U64_MAC_STAT(rx_length_error), | 
|  | 149 | EFX_ETHTOOL_U64_MAC_STAT(rx_internal_error), | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 150 | EFX_ETHTOOL_UINT_NIC_STAT(rx_nodesc_drop_cnt), | 
|  | 151 | EFX_ETHTOOL_ATOMIC_NIC_ERROR_STAT(rx_reset), | 
|  | 152 | EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_tobe_disc), | 
|  | 153 | EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_ip_hdr_chksum_err), | 
|  | 154 | EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_tcp_udp_chksum_err), | 
| Ben Hutchings | c1ac403 | 2009-11-28 05:36:29 +0000 | [diff] [blame] | 155 | EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_mcast_mismatch), | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 156 | EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_frm_trunc), | 
|  | 157 | }; | 
|  | 158 |  | 
|  | 159 | /* Number of ethtool statistics */ | 
|  | 160 | #define EFX_ETHTOOL_NUM_STATS ARRAY_SIZE(efx_ethtool_stats) | 
|  | 161 |  | 
| Ben Hutchings | 4a5b504 | 2008-09-01 12:47:16 +0100 | [diff] [blame] | 162 | #define EFX_ETHTOOL_EEPROM_MAGIC 0xEFAB | 
| Ben Hutchings | 4a5b504 | 2008-09-01 12:47:16 +0100 | [diff] [blame] | 163 |  | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 164 | /************************************************************************** | 
|  | 165 | * | 
|  | 166 | * Ethtool operations | 
|  | 167 | * | 
|  | 168 | ************************************************************************** | 
|  | 169 | */ | 
|  | 170 |  | 
|  | 171 | /* Identify device by flashing LEDs */ | 
| Ben Hutchings | c5e129a | 2011-04-02 00:43:46 +0100 | [diff] [blame] | 172 | static int efx_ethtool_phys_id(struct net_device *net_dev, | 
|  | 173 | enum ethtool_phys_id_state state) | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 174 | { | 
| Ben Hutchings | 767e468 | 2008-09-01 12:43:14 +0100 | [diff] [blame] | 175 | struct efx_nic *efx = netdev_priv(net_dev); | 
| Allan, Bruce W | fce5592 | 2011-04-13 13:09:10 +0000 | [diff] [blame] | 176 | enum efx_led_mode mode = EFX_LED_DEFAULT; | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 177 |  | 
| Ben Hutchings | c5e129a | 2011-04-02 00:43:46 +0100 | [diff] [blame] | 178 | switch (state) { | 
|  | 179 | case ETHTOOL_ID_ON: | 
|  | 180 | mode = EFX_LED_ON; | 
|  | 181 | break; | 
|  | 182 | case ETHTOOL_ID_OFF: | 
|  | 183 | mode = EFX_LED_OFF; | 
|  | 184 | break; | 
|  | 185 | case ETHTOOL_ID_INACTIVE: | 
|  | 186 | mode = EFX_LED_DEFAULT; | 
|  | 187 | break; | 
| Allan, Bruce W | fce5592 | 2011-04-13 13:09:10 +0000 | [diff] [blame] | 188 | case ETHTOOL_ID_ACTIVE: | 
|  | 189 | return 1;	/* cycle on/off once per second */ | 
| Ben Hutchings | c5e129a | 2011-04-02 00:43:46 +0100 | [diff] [blame] | 190 | } | 
| Ben Hutchings | 398468e | 2009-11-23 16:03:45 +0000 | [diff] [blame] | 191 |  | 
| Ben Hutchings | c5e129a | 2011-04-02 00:43:46 +0100 | [diff] [blame] | 192 | efx->type->set_id_led(efx, mode); | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 193 | return 0; | 
|  | 194 | } | 
|  | 195 |  | 
|  | 196 | /* This must be called with rtnl_lock held. */ | 
| stephen hemminger | d215697 | 2010-10-18 05:27:31 +0000 | [diff] [blame] | 197 | static int efx_ethtool_get_settings(struct net_device *net_dev, | 
|  | 198 | struct ethtool_cmd *ecmd) | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 199 | { | 
| Ben Hutchings | 767e468 | 2008-09-01 12:43:14 +0100 | [diff] [blame] | 200 | struct efx_nic *efx = netdev_priv(net_dev); | 
| Ben Hutchings | d3245b2 | 2009-11-29 03:42:41 +0000 | [diff] [blame] | 201 | struct efx_link_state *link_state = &efx->link_state; | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 202 |  | 
|  | 203 | mutex_lock(&efx->mac_lock); | 
| Ben Hutchings | 177dfcd | 2008-12-12 21:50:08 -0800 | [diff] [blame] | 204 | efx->phy_op->get_settings(efx, ecmd); | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 205 | mutex_unlock(&efx->mac_lock); | 
|  | 206 |  | 
| Ben Hutchings | 754c653 | 2010-02-03 09:31:57 +0000 | [diff] [blame] | 207 | /* GMAC does not support 1000Mbps HD */ | 
| Ben Hutchings | 177dfcd | 2008-12-12 21:50:08 -0800 | [diff] [blame] | 208 | ecmd->supported &= ~SUPPORTED_1000baseT_Half; | 
| Ben Hutchings | d3245b2 | 2009-11-29 03:42:41 +0000 | [diff] [blame] | 209 | /* Both MACs support pause frames (bidirectional and respond-only) */ | 
|  | 210 | ecmd->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; | 
|  | 211 |  | 
|  | 212 | if (LOOPBACK_INTERNAL(efx)) { | 
| David Decotigny | 7073949 | 2011-04-27 18:32:40 +0000 | [diff] [blame] | 213 | ethtool_cmd_speed_set(ecmd, link_state->speed); | 
| Ben Hutchings | d3245b2 | 2009-11-29 03:42:41 +0000 | [diff] [blame] | 214 | ecmd->duplex = link_state->fd ? DUPLEX_FULL : DUPLEX_HALF; | 
|  | 215 | } | 
| Ben Hutchings | 177dfcd | 2008-12-12 21:50:08 -0800 | [diff] [blame] | 216 |  | 
|  | 217 | return 0; | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 218 | } | 
|  | 219 |  | 
|  | 220 | /* This must be called with rtnl_lock held. */ | 
| stephen hemminger | d215697 | 2010-10-18 05:27:31 +0000 | [diff] [blame] | 221 | static int efx_ethtool_set_settings(struct net_device *net_dev, | 
|  | 222 | struct ethtool_cmd *ecmd) | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 223 | { | 
| Ben Hutchings | 767e468 | 2008-09-01 12:43:14 +0100 | [diff] [blame] | 224 | struct efx_nic *efx = netdev_priv(net_dev); | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 225 | int rc; | 
|  | 226 |  | 
| Ben Hutchings | 754c653 | 2010-02-03 09:31:57 +0000 | [diff] [blame] | 227 | /* GMAC does not support 1000Mbps HD */ | 
| David Decotigny | 25db033 | 2011-04-27 18:32:39 +0000 | [diff] [blame] | 228 | if ((ethtool_cmd_speed(ecmd) == SPEED_1000) && | 
|  | 229 | (ecmd->duplex != DUPLEX_FULL)) { | 
| Ben Hutchings | 62776d0 | 2010-06-23 11:30:07 +0000 | [diff] [blame] | 230 | netif_dbg(efx, drv, efx->net_dev, | 
|  | 231 | "rejecting unsupported 1000Mbps HD setting\n"); | 
| Ben Hutchings | 177dfcd | 2008-12-12 21:50:08 -0800 | [diff] [blame] | 232 | return -EINVAL; | 
|  | 233 | } | 
|  | 234 |  | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 235 | mutex_lock(&efx->mac_lock); | 
| Ben Hutchings | 177dfcd | 2008-12-12 21:50:08 -0800 | [diff] [blame] | 236 | rc = efx->phy_op->set_settings(efx, ecmd); | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 237 | mutex_unlock(&efx->mac_lock); | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 238 | return rc; | 
|  | 239 | } | 
|  | 240 |  | 
|  | 241 | static void efx_ethtool_get_drvinfo(struct net_device *net_dev, | 
|  | 242 | struct ethtool_drvinfo *info) | 
|  | 243 | { | 
| Ben Hutchings | 767e468 | 2008-09-01 12:43:14 +0100 | [diff] [blame] | 244 | struct efx_nic *efx = netdev_priv(net_dev); | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 245 |  | 
| Ben Hutchings | c5d5f5f | 2010-06-23 11:30:26 +0000 | [diff] [blame] | 246 | strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver)); | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 247 | strlcpy(info->version, EFX_DRIVER_VERSION, sizeof(info->version)); | 
| Ben Hutchings | 8880f4e | 2009-11-29 15:15:41 +0000 | [diff] [blame] | 248 | if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0) | 
| Ben Hutchings | e5f0fd2 | 2011-02-24 23:57:47 +0000 | [diff] [blame] | 249 | efx_mcdi_print_fwver(efx, info->fw_version, | 
|  | 250 | sizeof(info->fw_version)); | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 251 | strlcpy(info->bus_info, pci_name(efx->pci_dev), sizeof(info->bus_info)); | 
|  | 252 | } | 
|  | 253 |  | 
| Ben Hutchings | 5b98c1b | 2010-06-21 03:06:53 +0000 | [diff] [blame] | 254 | static int efx_ethtool_get_regs_len(struct net_device *net_dev) | 
|  | 255 | { | 
|  | 256 | return efx_nic_get_regs_len(netdev_priv(net_dev)); | 
|  | 257 | } | 
|  | 258 |  | 
|  | 259 | static void efx_ethtool_get_regs(struct net_device *net_dev, | 
|  | 260 | struct ethtool_regs *regs, void *buf) | 
|  | 261 | { | 
|  | 262 | struct efx_nic *efx = netdev_priv(net_dev); | 
|  | 263 |  | 
|  | 264 | regs->version = efx->type->revision; | 
|  | 265 | efx_nic_get_regs(efx, buf); | 
|  | 266 | } | 
|  | 267 |  | 
| Ben Hutchings | 62776d0 | 2010-06-23 11:30:07 +0000 | [diff] [blame] | 268 | static u32 efx_ethtool_get_msglevel(struct net_device *net_dev) | 
|  | 269 | { | 
|  | 270 | struct efx_nic *efx = netdev_priv(net_dev); | 
|  | 271 | return efx->msg_enable; | 
|  | 272 | } | 
|  | 273 |  | 
|  | 274 | static void efx_ethtool_set_msglevel(struct net_device *net_dev, u32 msg_enable) | 
|  | 275 | { | 
|  | 276 | struct efx_nic *efx = netdev_priv(net_dev); | 
|  | 277 | efx->msg_enable = msg_enable; | 
|  | 278 | } | 
|  | 279 |  | 
| Ben Hutchings | 3273c2e | 2008-05-07 13:36:19 +0100 | [diff] [blame] | 280 | /** | 
|  | 281 | * efx_fill_test - fill in an individual self-test entry | 
|  | 282 | * @test_index:		Index of the test | 
|  | 283 | * @strings:		Ethtool strings, or %NULL | 
|  | 284 | * @data:		Ethtool test results, or %NULL | 
|  | 285 | * @test:		Pointer to test result (used only if data != %NULL) | 
| Ben Hutchings | 740ced9 | 2008-12-12 21:41:55 -0800 | [diff] [blame] | 286 | * @unit_format:	Unit name format (e.g. "chan\%d") | 
|  | 287 | * @unit_id:		Unit id (e.g. 0 for "chan0") | 
| Ben Hutchings | 3273c2e | 2008-05-07 13:36:19 +0100 | [diff] [blame] | 288 | * @test_format:	Test name format (e.g. "loopback.\%s.tx.sent") | 
| Ben Hutchings | 740ced9 | 2008-12-12 21:41:55 -0800 | [diff] [blame] | 289 | * @test_id:		Test id (e.g. "PHYXS" for "loopback.PHYXS.tx_sent") | 
| Ben Hutchings | 3273c2e | 2008-05-07 13:36:19 +0100 | [diff] [blame] | 290 | * | 
|  | 291 | * Fill in an individual self-test entry. | 
|  | 292 | */ | 
|  | 293 | static void efx_fill_test(unsigned int test_index, | 
|  | 294 | struct ethtool_string *strings, u64 *data, | 
|  | 295 | int *test, const char *unit_format, int unit_id, | 
|  | 296 | const char *test_format, const char *test_id) | 
|  | 297 | { | 
|  | 298 | struct ethtool_string unit_str, test_str; | 
|  | 299 |  | 
|  | 300 | /* Fill data value, if applicable */ | 
|  | 301 | if (data) | 
|  | 302 | data[test_index] = *test; | 
|  | 303 |  | 
|  | 304 | /* Fill string, if applicable */ | 
|  | 305 | if (strings) { | 
| Ben Hutchings | 11e6696 | 2008-12-12 22:05:48 -0800 | [diff] [blame] | 306 | if (strchr(unit_format, '%')) | 
|  | 307 | snprintf(unit_str.name, sizeof(unit_str.name), | 
|  | 308 | unit_format, unit_id); | 
|  | 309 | else | 
|  | 310 | strcpy(unit_str.name, unit_format); | 
| Ben Hutchings | 3273c2e | 2008-05-07 13:36:19 +0100 | [diff] [blame] | 311 | snprintf(test_str.name, sizeof(test_str.name), | 
|  | 312 | test_format, test_id); | 
|  | 313 | snprintf(strings[test_index].name, | 
|  | 314 | sizeof(strings[test_index].name), | 
| Ben Hutchings | 740ced9 | 2008-12-12 21:41:55 -0800 | [diff] [blame] | 315 | "%-6s %-24s", unit_str.name, test_str.name); | 
| Ben Hutchings | 3273c2e | 2008-05-07 13:36:19 +0100 | [diff] [blame] | 316 | } | 
|  | 317 | } | 
|  | 318 |  | 
| Ben Hutchings | 740ced9 | 2008-12-12 21:41:55 -0800 | [diff] [blame] | 319 | #define EFX_CHANNEL_NAME(_channel) "chan%d", _channel->channel | 
| Ben Hutchings | 3273c2e | 2008-05-07 13:36:19 +0100 | [diff] [blame] | 320 | #define EFX_TX_QUEUE_NAME(_tx_queue) "txq%d", _tx_queue->queue | 
|  | 321 | #define EFX_RX_QUEUE_NAME(_rx_queue) "rxq%d", _rx_queue->queue | 
|  | 322 | #define EFX_LOOPBACK_NAME(_mode, _counter)			\ | 
| Ben Hutchings | c459302 | 2009-11-23 16:08:17 +0000 | [diff] [blame] | 323 | "loopback.%s." _counter, STRING_TABLE_LOOKUP(_mode, efx_loopback_mode) | 
| Ben Hutchings | 3273c2e | 2008-05-07 13:36:19 +0100 | [diff] [blame] | 324 |  | 
|  | 325 | /** | 
|  | 326 | * efx_fill_loopback_test - fill in a block of loopback self-test entries | 
|  | 327 | * @efx:		Efx NIC | 
|  | 328 | * @lb_tests:		Efx loopback self-test results structure | 
|  | 329 | * @mode:		Loopback test mode | 
|  | 330 | * @test_index:		Starting index of the test | 
|  | 331 | * @strings:		Ethtool strings, or %NULL | 
|  | 332 | * @data:		Ethtool test results, or %NULL | 
|  | 333 | */ | 
|  | 334 | static int efx_fill_loopback_test(struct efx_nic *efx, | 
|  | 335 | struct efx_loopback_self_tests *lb_tests, | 
|  | 336 | enum efx_loopback_mode mode, | 
|  | 337 | unsigned int test_index, | 
|  | 338 | struct ethtool_string *strings, u64 *data) | 
|  | 339 | { | 
| Ben Hutchings | 1ac0226 | 2012-09-13 02:22:52 +0100 | [diff] [blame] | 340 | struct efx_channel *channel = | 
|  | 341 | efx_get_channel(efx, efx->tx_channel_offset); | 
| Ben Hutchings | 3273c2e | 2008-05-07 13:36:19 +0100 | [diff] [blame] | 342 | struct efx_tx_queue *tx_queue; | 
|  | 343 |  | 
| Ben Hutchings | f7d12cd | 2010-09-10 06:41:47 +0000 | [diff] [blame] | 344 | efx_for_each_channel_tx_queue(tx_queue, channel) { | 
| Ben Hutchings | 3273c2e | 2008-05-07 13:36:19 +0100 | [diff] [blame] | 345 | efx_fill_test(test_index++, strings, data, | 
|  | 346 | &lb_tests->tx_sent[tx_queue->queue], | 
|  | 347 | EFX_TX_QUEUE_NAME(tx_queue), | 
|  | 348 | EFX_LOOPBACK_NAME(mode, "tx_sent")); | 
|  | 349 | efx_fill_test(test_index++, strings, data, | 
|  | 350 | &lb_tests->tx_done[tx_queue->queue], | 
|  | 351 | EFX_TX_QUEUE_NAME(tx_queue), | 
|  | 352 | EFX_LOOPBACK_NAME(mode, "tx_done")); | 
|  | 353 | } | 
|  | 354 | efx_fill_test(test_index++, strings, data, | 
|  | 355 | &lb_tests->rx_good, | 
| Ben Hutchings | 11e6696 | 2008-12-12 22:05:48 -0800 | [diff] [blame] | 356 | "rx", 0, | 
| Ben Hutchings | 3273c2e | 2008-05-07 13:36:19 +0100 | [diff] [blame] | 357 | EFX_LOOPBACK_NAME(mode, "rx_good")); | 
|  | 358 | efx_fill_test(test_index++, strings, data, | 
|  | 359 | &lb_tests->rx_bad, | 
| Ben Hutchings | 11e6696 | 2008-12-12 22:05:48 -0800 | [diff] [blame] | 360 | "rx", 0, | 
| Ben Hutchings | 3273c2e | 2008-05-07 13:36:19 +0100 | [diff] [blame] | 361 | EFX_LOOPBACK_NAME(mode, "rx_bad")); | 
|  | 362 |  | 
|  | 363 | return test_index; | 
|  | 364 | } | 
|  | 365 |  | 
|  | 366 | /** | 
|  | 367 | * efx_ethtool_fill_self_tests - get self-test details | 
|  | 368 | * @efx:		Efx NIC | 
|  | 369 | * @tests:		Efx self-test results structure, or %NULL | 
|  | 370 | * @strings:		Ethtool strings, or %NULL | 
|  | 371 | * @data:		Ethtool test results, or %NULL | 
|  | 372 | */ | 
|  | 373 | static int efx_ethtool_fill_self_tests(struct efx_nic *efx, | 
|  | 374 | struct efx_self_tests *tests, | 
|  | 375 | struct ethtool_string *strings, | 
|  | 376 | u64 *data) | 
|  | 377 | { | 
|  | 378 | struct efx_channel *channel; | 
| Ben Hutchings | 1796721 | 2008-12-26 13:47:25 -0800 | [diff] [blame] | 379 | unsigned int n = 0, i; | 
| Ben Hutchings | 3273c2e | 2008-05-07 13:36:19 +0100 | [diff] [blame] | 380 | enum efx_loopback_mode mode; | 
|  | 381 |  | 
| Ben Hutchings | 4f16c07 | 2010-02-03 09:30:50 +0000 | [diff] [blame] | 382 | efx_fill_test(n++, strings, data, &tests->phy_alive, | 
|  | 383 | "phy", 0, "alive", NULL); | 
| Ben Hutchings | 8c8661e | 2008-09-01 12:49:02 +0100 | [diff] [blame] | 384 | efx_fill_test(n++, strings, data, &tests->nvram, | 
|  | 385 | "core", 0, "nvram", NULL); | 
| Ben Hutchings | 3273c2e | 2008-05-07 13:36:19 +0100 | [diff] [blame] | 386 | efx_fill_test(n++, strings, data, &tests->interrupt, | 
|  | 387 | "core", 0, "interrupt", NULL); | 
|  | 388 |  | 
|  | 389 | /* Event queues */ | 
|  | 390 | efx_for_each_channel(channel, efx) { | 
|  | 391 | efx_fill_test(n++, strings, data, | 
|  | 392 | &tests->eventq_dma[channel->channel], | 
|  | 393 | EFX_CHANNEL_NAME(channel), | 
|  | 394 | "eventq.dma", NULL); | 
|  | 395 | efx_fill_test(n++, strings, data, | 
|  | 396 | &tests->eventq_int[channel->channel], | 
|  | 397 | EFX_CHANNEL_NAME(channel), | 
|  | 398 | "eventq.int", NULL); | 
| Ben Hutchings | 3273c2e | 2008-05-07 13:36:19 +0100 | [diff] [blame] | 399 | } | 
|  | 400 |  | 
| Ben Hutchings | 8c8661e | 2008-09-01 12:49:02 +0100 | [diff] [blame] | 401 | efx_fill_test(n++, strings, data, &tests->registers, | 
|  | 402 | "core", 0, "registers", NULL); | 
| Ben Hutchings | 1796721 | 2008-12-26 13:47:25 -0800 | [diff] [blame] | 403 |  | 
| Ben Hutchings | c1c4f45 | 2009-11-29 15:08:55 +0000 | [diff] [blame] | 404 | if (efx->phy_op->run_tests != NULL) { | 
|  | 405 | EFX_BUG_ON_PARANOID(efx->phy_op->test_name == NULL); | 
|  | 406 |  | 
|  | 407 | for (i = 0; true; ++i) { | 
|  | 408 | const char *name; | 
|  | 409 |  | 
|  | 410 | EFX_BUG_ON_PARANOID(i >= EFX_MAX_PHY_TESTS); | 
|  | 411 | name = efx->phy_op->test_name(efx, i); | 
|  | 412 | if (name == NULL) | 
|  | 413 | break; | 
|  | 414 |  | 
| Ben Hutchings | 4f16c07 | 2010-02-03 09:30:50 +0000 | [diff] [blame] | 415 | efx_fill_test(n++, strings, data, &tests->phy_ext[i], | 
| Ben Hutchings | c1c4f45 | 2009-11-29 15:08:55 +0000 | [diff] [blame] | 416 | "phy", 0, name, NULL); | 
|  | 417 | } | 
|  | 418 | } | 
| Ben Hutchings | 3273c2e | 2008-05-07 13:36:19 +0100 | [diff] [blame] | 419 |  | 
|  | 420 | /* Loopback tests */ | 
| Ben Hutchings | 8c8661e | 2008-09-01 12:49:02 +0100 | [diff] [blame] | 421 | for (mode = LOOPBACK_NONE; mode <= LOOPBACK_TEST_MAX; mode++) { | 
| Ben Hutchings | 3273c2e | 2008-05-07 13:36:19 +0100 | [diff] [blame] | 422 | if (!(efx->loopback_modes & (1 << mode))) | 
|  | 423 | continue; | 
|  | 424 | n = efx_fill_loopback_test(efx, | 
|  | 425 | &tests->loopback[mode], mode, n, | 
|  | 426 | strings, data); | 
|  | 427 | } | 
|  | 428 |  | 
|  | 429 | return n; | 
|  | 430 | } | 
|  | 431 |  | 
| Ben Hutchings | 3594e13 | 2008-09-01 12:48:12 +0100 | [diff] [blame] | 432 | static int efx_ethtool_get_sset_count(struct net_device *net_dev, | 
|  | 433 | int string_set) | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 434 | { | 
| Ben Hutchings | 3594e13 | 2008-09-01 12:48:12 +0100 | [diff] [blame] | 435 | switch (string_set) { | 
|  | 436 | case ETH_SS_STATS: | 
|  | 437 | return EFX_ETHTOOL_NUM_STATS; | 
|  | 438 | case ETH_SS_TEST: | 
|  | 439 | return efx_ethtool_fill_self_tests(netdev_priv(net_dev), | 
|  | 440 | NULL, NULL, NULL); | 
|  | 441 | default: | 
|  | 442 | return -EINVAL; | 
|  | 443 | } | 
| Ben Hutchings | 3273c2e | 2008-05-07 13:36:19 +0100 | [diff] [blame] | 444 | } | 
|  | 445 |  | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 446 | static void efx_ethtool_get_strings(struct net_device *net_dev, | 
|  | 447 | u32 string_set, u8 *strings) | 
|  | 448 | { | 
| Ben Hutchings | 767e468 | 2008-09-01 12:43:14 +0100 | [diff] [blame] | 449 | struct efx_nic *efx = netdev_priv(net_dev); | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 450 | struct ethtool_string *ethtool_strings = | 
|  | 451 | (struct ethtool_string *)strings; | 
|  | 452 | int i; | 
|  | 453 |  | 
| Ben Hutchings | 3273c2e | 2008-05-07 13:36:19 +0100 | [diff] [blame] | 454 | switch (string_set) { | 
|  | 455 | case ETH_SS_STATS: | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 456 | for (i = 0; i < EFX_ETHTOOL_NUM_STATS; i++) | 
| Ben Hutchings | a4ed2d4 | 2012-07-02 21:36:59 +0100 | [diff] [blame] | 457 | strlcpy(ethtool_strings[i].name, | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 458 | efx_ethtool_stats[i].name, | 
|  | 459 | sizeof(ethtool_strings[i].name)); | 
| Ben Hutchings | 3273c2e | 2008-05-07 13:36:19 +0100 | [diff] [blame] | 460 | break; | 
|  | 461 | case ETH_SS_TEST: | 
|  | 462 | efx_ethtool_fill_self_tests(efx, NULL, | 
|  | 463 | ethtool_strings, NULL); | 
|  | 464 | break; | 
|  | 465 | default: | 
|  | 466 | /* No other string sets */ | 
|  | 467 | break; | 
|  | 468 | } | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 469 | } | 
|  | 470 |  | 
|  | 471 | static void efx_ethtool_get_stats(struct net_device *net_dev, | 
|  | 472 | struct ethtool_stats *stats, | 
|  | 473 | u64 *data) | 
|  | 474 | { | 
| Ben Hutchings | 767e468 | 2008-09-01 12:43:14 +0100 | [diff] [blame] | 475 | struct efx_nic *efx = netdev_priv(net_dev); | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 476 | struct efx_mac_stats *mac_stats = &efx->mac_stats; | 
| Ben Hutchings | 18e83e4 | 2012-01-05 19:05:20 +0000 | [diff] [blame] | 477 | const struct efx_ethtool_stat *stat; | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 478 | struct efx_channel *channel; | 
| Ben Hutchings | 119226c | 2011-02-18 19:14:13 +0000 | [diff] [blame] | 479 | struct efx_tx_queue *tx_queue; | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 480 | int i; | 
|  | 481 |  | 
|  | 482 | EFX_BUG_ON_PARANOID(stats->n_stats != EFX_ETHTOOL_NUM_STATS); | 
|  | 483 |  | 
| Ben Hutchings | 1cb3452 | 2011-09-02 23:23:00 +0100 | [diff] [blame] | 484 | spin_lock_bh(&efx->stats_lock); | 
|  | 485 |  | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 486 | /* Update MAC and NIC statistics */ | 
| Ben Hutchings | 1cb3452 | 2011-09-02 23:23:00 +0100 | [diff] [blame] | 487 | efx->type->update_stats(efx); | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 488 |  | 
|  | 489 | /* Fill detailed statistics buffer */ | 
|  | 490 | for (i = 0; i < EFX_ETHTOOL_NUM_STATS; i++) { | 
|  | 491 | stat = &efx_ethtool_stats[i]; | 
|  | 492 | switch (stat->source) { | 
|  | 493 | case EFX_ETHTOOL_STAT_SOURCE_mac_stats: | 
|  | 494 | data[i] = stat->get_stat((void *)mac_stats + | 
|  | 495 | stat->offset); | 
|  | 496 | break; | 
|  | 497 | case EFX_ETHTOOL_STAT_SOURCE_nic: | 
|  | 498 | data[i] = stat->get_stat((void *)efx + stat->offset); | 
|  | 499 | break; | 
|  | 500 | case EFX_ETHTOOL_STAT_SOURCE_channel: | 
|  | 501 | data[i] = 0; | 
|  | 502 | efx_for_each_channel(channel, efx) | 
|  | 503 | data[i] += stat->get_stat((void *)channel + | 
|  | 504 | stat->offset); | 
|  | 505 | break; | 
| Ben Hutchings | 119226c | 2011-02-18 19:14:13 +0000 | [diff] [blame] | 506 | case EFX_ETHTOOL_STAT_SOURCE_tx_queue: | 
|  | 507 | data[i] = 0; | 
|  | 508 | efx_for_each_channel(channel, efx) { | 
|  | 509 | efx_for_each_channel_tx_queue(tx_queue, channel) | 
|  | 510 | data[i] += | 
|  | 511 | stat->get_stat((void *)tx_queue | 
|  | 512 | + stat->offset); | 
|  | 513 | } | 
|  | 514 | break; | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 515 | } | 
|  | 516 | } | 
| Ben Hutchings | 1cb3452 | 2011-09-02 23:23:00 +0100 | [diff] [blame] | 517 |  | 
|  | 518 | spin_unlock_bh(&efx->stats_lock); | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 519 | } | 
|  | 520 |  | 
| Ben Hutchings | 3273c2e | 2008-05-07 13:36:19 +0100 | [diff] [blame] | 521 | static void efx_ethtool_self_test(struct net_device *net_dev, | 
|  | 522 | struct ethtool_test *test, u64 *data) | 
|  | 523 | { | 
| Ben Hutchings | 767e468 | 2008-09-01 12:43:14 +0100 | [diff] [blame] | 524 | struct efx_nic *efx = netdev_priv(net_dev); | 
| Eric Dumazet | 28801f3 | 2011-02-16 03:48:38 +0000 | [diff] [blame] | 525 | struct efx_self_tests *efx_tests; | 
| Ben Hutchings | 2ef3068 | 2008-12-26 13:47:04 -0800 | [diff] [blame] | 526 | int already_up; | 
| Eric Dumazet | 28801f3 | 2011-02-16 03:48:38 +0000 | [diff] [blame] | 527 | int rc = -ENOMEM; | 
|  | 528 |  | 
|  | 529 | efx_tests = kzalloc(sizeof(*efx_tests), GFP_KERNEL); | 
|  | 530 | if (!efx_tests) | 
|  | 531 | goto fail; | 
|  | 532 |  | 
| Ben Hutchings | f16aeea | 2012-07-27 19:31:16 +0100 | [diff] [blame] | 533 | if (efx->state != STATE_READY) { | 
| Ben Hutchings | 3273c2e | 2008-05-07 13:36:19 +0100 | [diff] [blame] | 534 | rc = -EIO; | 
|  | 535 | goto fail1; | 
|  | 536 | } | 
|  | 537 |  | 
| Ben Hutchings | ac33ac6 | 2010-12-07 18:29:52 +0000 | [diff] [blame] | 538 | netif_info(efx, drv, efx->net_dev, "starting %sline testing\n", | 
|  | 539 | (test->flags & ETH_TEST_FL_OFFLINE) ? "off" : "on"); | 
|  | 540 |  | 
| Ben Hutchings | 3273c2e | 2008-05-07 13:36:19 +0100 | [diff] [blame] | 541 | /* We need rx buffers and interrupts. */ | 
|  | 542 | already_up = (efx->net_dev->flags & IFF_UP); | 
|  | 543 | if (!already_up) { | 
|  | 544 | rc = dev_open(efx->net_dev); | 
|  | 545 | if (rc) { | 
| Ben Hutchings | 62776d0 | 2010-06-23 11:30:07 +0000 | [diff] [blame] | 546 | netif_err(efx, drv, efx->net_dev, | 
|  | 547 | "failed opening device.\n"); | 
| Eric Dumazet | 28801f3 | 2011-02-16 03:48:38 +0000 | [diff] [blame] | 548 | goto fail1; | 
| Ben Hutchings | 3273c2e | 2008-05-07 13:36:19 +0100 | [diff] [blame] | 549 | } | 
|  | 550 | } | 
|  | 551 |  | 
| Eric Dumazet | 28801f3 | 2011-02-16 03:48:38 +0000 | [diff] [blame] | 552 | rc = efx_selftest(efx, efx_tests, test->flags); | 
| Ben Hutchings | 3273c2e | 2008-05-07 13:36:19 +0100 | [diff] [blame] | 553 |  | 
| Ben Hutchings | 3273c2e | 2008-05-07 13:36:19 +0100 | [diff] [blame] | 554 | if (!already_up) | 
|  | 555 | dev_close(efx->net_dev); | 
|  | 556 |  | 
| Ben Hutchings | ac33ac6 | 2010-12-07 18:29:52 +0000 | [diff] [blame] | 557 | netif_info(efx, drv, efx->net_dev, "%s %sline self-tests\n", | 
|  | 558 | rc == 0 ? "passed" : "failed", | 
|  | 559 | (test->flags & ETH_TEST_FL_OFFLINE) ? "off" : "on"); | 
| Ben Hutchings | 3273c2e | 2008-05-07 13:36:19 +0100 | [diff] [blame] | 560 |  | 
| Eric Dumazet | 28801f3 | 2011-02-16 03:48:38 +0000 | [diff] [blame] | 561 | fail1: | 
| Ben Hutchings | 3273c2e | 2008-05-07 13:36:19 +0100 | [diff] [blame] | 562 | /* Fill ethtool results structures */ | 
| Eric Dumazet | 28801f3 | 2011-02-16 03:48:38 +0000 | [diff] [blame] | 563 | efx_ethtool_fill_self_tests(efx, efx_tests, NULL, data); | 
|  | 564 | kfree(efx_tests); | 
|  | 565 | fail: | 
| Ben Hutchings | 3273c2e | 2008-05-07 13:36:19 +0100 | [diff] [blame] | 566 | if (rc) | 
|  | 567 | test->flags |= ETH_TEST_FL_FAILED; | 
|  | 568 | } | 
|  | 569 |  | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 570 | /* Restart autonegotiation */ | 
|  | 571 | static int efx_ethtool_nway_reset(struct net_device *net_dev) | 
|  | 572 | { | 
| Ben Hutchings | 767e468 | 2008-09-01 12:43:14 +0100 | [diff] [blame] | 573 | struct efx_nic *efx = netdev_priv(net_dev); | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 574 |  | 
| Ben Hutchings | 68e7f45 | 2009-04-29 08:05:08 +0000 | [diff] [blame] | 575 | return mdio45_nway_restart(&efx->mdio); | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 576 | } | 
|  | 577 |  | 
| Ben Hutchings | a0c4faf | 2011-09-05 07:42:25 +0000 | [diff] [blame] | 578 | /* | 
|  | 579 | * Each channel has a single IRQ and moderation timer, started by any | 
|  | 580 | * completion (or other event).  Unless the module parameter | 
|  | 581 | * separate_tx_channels is set, IRQs and moderation are therefore | 
|  | 582 | * shared between RX and TX completions.  In this case, when RX IRQ | 
|  | 583 | * moderation is explicitly changed then TX IRQ moderation is | 
|  | 584 | * automatically changed too, but otherwise we fail if the two values | 
|  | 585 | * are requested to be different. | 
|  | 586 | * | 
| Ben Hutchings | 1322597 | 2011-09-05 07:43:49 +0000 | [diff] [blame] | 587 | * The hardware does not support a limit on the number of completions | 
|  | 588 | * before an IRQ, so we do not use the max_frames fields.  We should | 
|  | 589 | * report and require that max_frames == (usecs != 0), but this would | 
|  | 590 | * invalidate existing user documentation. | 
|  | 591 | * | 
|  | 592 | * The hardware does not have distinct settings for interrupt | 
|  | 593 | * moderation while the previous IRQ is being handled, so we should | 
|  | 594 | * not use the 'irq' fields.  However, an earlier developer | 
|  | 595 | * misunderstood the meaning of the 'irq' fields and the driver did | 
|  | 596 | * not support the standard fields.  To avoid invalidating existing | 
|  | 597 | * user documentation, we report and accept changes through either the | 
|  | 598 | * standard or 'irq' fields.  If both are changed at the same time, we | 
|  | 599 | * prefer the standard field. | 
|  | 600 | * | 
| Ben Hutchings | a0c4faf | 2011-09-05 07:42:25 +0000 | [diff] [blame] | 601 | * We implement adaptive IRQ moderation, but use a different algorithm | 
|  | 602 | * from that assumed in the definition of struct ethtool_coalesce. | 
|  | 603 | * Therefore we do not use any of the adaptive moderation parameters | 
|  | 604 | * in it. | 
|  | 605 | */ | 
|  | 606 |  | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 607 | static int efx_ethtool_get_coalesce(struct net_device *net_dev, | 
|  | 608 | struct ethtool_coalesce *coalesce) | 
|  | 609 | { | 
| Ben Hutchings | 767e468 | 2008-09-01 12:43:14 +0100 | [diff] [blame] | 610 | struct efx_nic *efx = netdev_priv(net_dev); | 
| Ben Hutchings | a0c4faf | 2011-09-05 07:42:25 +0000 | [diff] [blame] | 611 | unsigned int tx_usecs, rx_usecs; | 
|  | 612 | bool rx_adaptive; | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 613 |  | 
| Ben Hutchings | a0c4faf | 2011-09-05 07:42:25 +0000 | [diff] [blame] | 614 | efx_get_irq_moderation(efx, &tx_usecs, &rx_usecs, &rx_adaptive); | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 615 |  | 
| Ben Hutchings | 1322597 | 2011-09-05 07:43:49 +0000 | [diff] [blame] | 616 | coalesce->tx_coalesce_usecs = tx_usecs; | 
| Ben Hutchings | a0c4faf | 2011-09-05 07:42:25 +0000 | [diff] [blame] | 617 | coalesce->tx_coalesce_usecs_irq = tx_usecs; | 
| Ben Hutchings | 1322597 | 2011-09-05 07:43:49 +0000 | [diff] [blame] | 618 | coalesce->rx_coalesce_usecs = rx_usecs; | 
| Ben Hutchings | a0c4faf | 2011-09-05 07:42:25 +0000 | [diff] [blame] | 619 | coalesce->rx_coalesce_usecs_irq = rx_usecs; | 
|  | 620 | coalesce->use_adaptive_rx_coalesce = rx_adaptive; | 
| Ben Hutchings | 0d86ebd | 2009-10-23 08:32:13 +0000 | [diff] [blame] | 621 |  | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 622 | return 0; | 
|  | 623 | } | 
|  | 624 |  | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 625 | static int efx_ethtool_set_coalesce(struct net_device *net_dev, | 
|  | 626 | struct ethtool_coalesce *coalesce) | 
|  | 627 | { | 
| Ben Hutchings | 767e468 | 2008-09-01 12:43:14 +0100 | [diff] [blame] | 628 | struct efx_nic *efx = netdev_priv(net_dev); | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 629 | struct efx_channel *channel; | 
| Ben Hutchings | b548f97 | 2011-09-05 07:41:44 +0000 | [diff] [blame] | 630 | unsigned int tx_usecs, rx_usecs; | 
| Ben Hutchings | 9e393b3 | 2011-09-05 07:43:04 +0000 | [diff] [blame] | 631 | bool adaptive, rx_may_override_tx; | 
|  | 632 | int rc; | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 633 |  | 
| Ben Hutchings | 6fb70fd | 2009-03-20 13:30:37 +0000 | [diff] [blame] | 634 | if (coalesce->use_adaptive_tx_coalesce) | 
| Ben Hutchings | 9f85ee9 | 2011-09-05 07:41:27 +0000 | [diff] [blame] | 635 | return -EINVAL; | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 636 |  | 
| Ben Hutchings | a0c4faf | 2011-09-05 07:42:25 +0000 | [diff] [blame] | 637 | efx_get_irq_moderation(efx, &tx_usecs, &rx_usecs, &adaptive); | 
|  | 638 |  | 
| Ben Hutchings | 1322597 | 2011-09-05 07:43:49 +0000 | [diff] [blame] | 639 | if (coalesce->rx_coalesce_usecs != rx_usecs) | 
|  | 640 | rx_usecs = coalesce->rx_coalesce_usecs; | 
|  | 641 | else | 
|  | 642 | rx_usecs = coalesce->rx_coalesce_usecs_irq; | 
|  | 643 |  | 
| Ben Hutchings | 6fb70fd | 2009-03-20 13:30:37 +0000 | [diff] [blame] | 644 | adaptive = coalesce->use_adaptive_rx_coalesce; | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 645 |  | 
| Ben Hutchings | a0c4faf | 2011-09-05 07:42:25 +0000 | [diff] [blame] | 646 | /* If channels are shared, TX IRQ moderation can be quietly | 
|  | 647 | * overridden unless it is changed from its old value. | 
|  | 648 | */ | 
| Ben Hutchings | 1322597 | 2011-09-05 07:43:49 +0000 | [diff] [blame] | 649 | rx_may_override_tx = (coalesce->tx_coalesce_usecs == tx_usecs && | 
|  | 650 | coalesce->tx_coalesce_usecs_irq == tx_usecs); | 
|  | 651 | if (coalesce->tx_coalesce_usecs != tx_usecs) | 
|  | 652 | tx_usecs = coalesce->tx_coalesce_usecs; | 
|  | 653 | else | 
|  | 654 | tx_usecs = coalesce->tx_coalesce_usecs_irq; | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 655 |  | 
| Ben Hutchings | 9e393b3 | 2011-09-05 07:43:04 +0000 | [diff] [blame] | 656 | rc = efx_init_irq_moderation(efx, tx_usecs, rx_usecs, adaptive, | 
|  | 657 | rx_may_override_tx); | 
|  | 658 | if (rc != 0) | 
|  | 659 | return rc; | 
|  | 660 |  | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 661 | efx_for_each_channel(channel, efx) | 
| Ben Hutchings | ef2b90e | 2009-11-29 03:42:31 +0000 | [diff] [blame] | 662 | efx->type->push_irq_moderation(channel); | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 663 |  | 
|  | 664 | return 0; | 
|  | 665 | } | 
|  | 666 |  | 
| Ben Hutchings | 4642610 | 2010-09-10 06:42:33 +0000 | [diff] [blame] | 667 | static void efx_ethtool_get_ringparam(struct net_device *net_dev, | 
|  | 668 | struct ethtool_ringparam *ring) | 
|  | 669 | { | 
|  | 670 | struct efx_nic *efx = netdev_priv(net_dev); | 
|  | 671 |  | 
|  | 672 | ring->rx_max_pending = EFX_MAX_DMAQ_SIZE; | 
|  | 673 | ring->tx_max_pending = EFX_MAX_DMAQ_SIZE; | 
| Ben Hutchings | 4642610 | 2010-09-10 06:42:33 +0000 | [diff] [blame] | 674 | ring->rx_pending = efx->rxq_entries; | 
|  | 675 | ring->tx_pending = efx->txq_entries; | 
| Ben Hutchings | 4642610 | 2010-09-10 06:42:33 +0000 | [diff] [blame] | 676 | } | 
|  | 677 |  | 
|  | 678 | static int efx_ethtool_set_ringparam(struct net_device *net_dev, | 
|  | 679 | struct ethtool_ringparam *ring) | 
|  | 680 | { | 
|  | 681 | struct efx_nic *efx = netdev_priv(net_dev); | 
| Ben Hutchings | 7e6d06f | 2012-07-30 15:57:44 +0000 | [diff] [blame] | 682 | u32 txq_entries; | 
| Ben Hutchings | 4642610 | 2010-09-10 06:42:33 +0000 | [diff] [blame] | 683 |  | 
|  | 684 | if (ring->rx_mini_pending || ring->rx_jumbo_pending || | 
|  | 685 | ring->rx_pending > EFX_MAX_DMAQ_SIZE || | 
|  | 686 | ring->tx_pending > EFX_MAX_DMAQ_SIZE) | 
|  | 687 | return -EINVAL; | 
|  | 688 |  | 
| Ben Hutchings | 7e6d06f | 2012-07-30 15:57:44 +0000 | [diff] [blame] | 689 | if (ring->rx_pending < EFX_RXQ_MIN_ENT) { | 
| Ben Hutchings | 4642610 | 2010-09-10 06:42:33 +0000 | [diff] [blame] | 690 | netif_err(efx, drv, efx->net_dev, | 
| Ben Hutchings | 7e6d06f | 2012-07-30 15:57:44 +0000 | [diff] [blame] | 691 | "RX queues cannot be smaller than %u\n", | 
|  | 692 | EFX_RXQ_MIN_ENT); | 
| Ben Hutchings | 4642610 | 2010-09-10 06:42:33 +0000 | [diff] [blame] | 693 | return -EINVAL; | 
|  | 694 | } | 
|  | 695 |  | 
| Ben Hutchings | 7e6d06f | 2012-07-30 15:57:44 +0000 | [diff] [blame] | 696 | txq_entries = max(ring->tx_pending, EFX_TXQ_MIN_ENT(efx)); | 
|  | 697 | if (txq_entries != ring->tx_pending) | 
|  | 698 | netif_warn(efx, drv, efx->net_dev, | 
|  | 699 | "increasing TX queue size to minimum of %u\n", | 
|  | 700 | txq_entries); | 
|  | 701 |  | 
|  | 702 | return efx_realloc_channels(efx, ring->rx_pending, txq_entries); | 
| Ben Hutchings | 4642610 | 2010-09-10 06:42:33 +0000 | [diff] [blame] | 703 | } | 
|  | 704 |  | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 705 | static int efx_ethtool_set_pauseparam(struct net_device *net_dev, | 
|  | 706 | struct ethtool_pauseparam *pause) | 
|  | 707 | { | 
| Ben Hutchings | 767e468 | 2008-09-01 12:43:14 +0100 | [diff] [blame] | 708 | struct efx_nic *efx = netdev_priv(net_dev); | 
| David S. Miller | b562694 | 2011-05-17 17:53:22 -0400 | [diff] [blame] | 709 | u8 wanted_fc, old_fc; | 
| Ben Hutchings | d3245b2 | 2009-11-29 03:42:41 +0000 | [diff] [blame] | 710 | u32 old_adv; | 
| Ben Hutchings | 04cc8ca | 2008-12-12 21:50:46 -0800 | [diff] [blame] | 711 | bool reset; | 
| Ben Hutchings | d3245b2 | 2009-11-29 03:42:41 +0000 | [diff] [blame] | 712 | int rc = 0; | 
|  | 713 |  | 
|  | 714 | mutex_lock(&efx->mac_lock); | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 715 |  | 
| Ben Hutchings | 04cc8ca | 2008-12-12 21:50:46 -0800 | [diff] [blame] | 716 | wanted_fc = ((pause->rx_pause ? EFX_FC_RX : 0) | | 
|  | 717 | (pause->tx_pause ? EFX_FC_TX : 0) | | 
|  | 718 | (pause->autoneg ? EFX_FC_AUTO : 0)); | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 719 |  | 
| Ben Hutchings | 04cc8ca | 2008-12-12 21:50:46 -0800 | [diff] [blame] | 720 | if ((wanted_fc & EFX_FC_TX) && !(wanted_fc & EFX_FC_RX)) { | 
| Ben Hutchings | 62776d0 | 2010-06-23 11:30:07 +0000 | [diff] [blame] | 721 | netif_dbg(efx, drv, efx->net_dev, | 
|  | 722 | "Flow control unsupported: tx ON rx OFF\n"); | 
| Ben Hutchings | d3245b2 | 2009-11-29 03:42:41 +0000 | [diff] [blame] | 723 | rc = -EINVAL; | 
|  | 724 | goto out; | 
| Ben Hutchings | 04cc8ca | 2008-12-12 21:50:46 -0800 | [diff] [blame] | 725 | } | 
|  | 726 |  | 
| Ben Hutchings | d3245b2 | 2009-11-29 03:42:41 +0000 | [diff] [blame] | 727 | if ((wanted_fc & EFX_FC_AUTO) && !efx->link_advertising) { | 
| Ben Hutchings | 62776d0 | 2010-06-23 11:30:07 +0000 | [diff] [blame] | 728 | netif_dbg(efx, drv, efx->net_dev, | 
|  | 729 | "Autonegotiation is disabled\n"); | 
| Ben Hutchings | d3245b2 | 2009-11-29 03:42:41 +0000 | [diff] [blame] | 730 | rc = -EINVAL; | 
|  | 731 | goto out; | 
| Ben Hutchings | 04cc8ca | 2008-12-12 21:50:46 -0800 | [diff] [blame] | 732 | } | 
|  | 733 |  | 
|  | 734 | /* TX flow control may automatically turn itself off if the | 
|  | 735 | * link partner (intermittently) stops responding to pause | 
|  | 736 | * frames. There isn't any indication that this has happened, | 
|  | 737 | * so the best we do is leave it up to the user to spot this | 
|  | 738 | * and fix it be cycling transmit flow control on this end. */ | 
|  | 739 | reset = (wanted_fc & EFX_FC_TX) && !(efx->wanted_fc & EFX_FC_TX); | 
|  | 740 | if (EFX_WORKAROUND_11482(efx) && reset) { | 
| Ben Hutchings | daeda63 | 2009-11-28 05:36:04 +0000 | [diff] [blame] | 741 | if (efx_nic_rev(efx) == EFX_REV_FALCON_B0) { | 
| Ben Hutchings | 04cc8ca | 2008-12-12 21:50:46 -0800 | [diff] [blame] | 742 | /* Recover by resetting the EM block */ | 
| Ben Hutchings | d3245b2 | 2009-11-29 03:42:41 +0000 | [diff] [blame] | 743 | falcon_stop_nic_stats(efx); | 
|  | 744 | falcon_drain_tx_fifo(efx); | 
| Ben Hutchings | 710b208 | 2011-09-03 00:15:00 +0100 | [diff] [blame] | 745 | falcon_reconfigure_xmac(efx); | 
| Ben Hutchings | d3245b2 | 2009-11-29 03:42:41 +0000 | [diff] [blame] | 746 | falcon_start_nic_stats(efx); | 
| Ben Hutchings | 04cc8ca | 2008-12-12 21:50:46 -0800 | [diff] [blame] | 747 | } else { | 
|  | 748 | /* Schedule a reset to recover */ | 
|  | 749 | efx_schedule_reset(efx, RESET_TYPE_INVISIBLE); | 
|  | 750 | } | 
|  | 751 | } | 
|  | 752 |  | 
| Ben Hutchings | d3245b2 | 2009-11-29 03:42:41 +0000 | [diff] [blame] | 753 | old_adv = efx->link_advertising; | 
|  | 754 | old_fc = efx->wanted_fc; | 
|  | 755 | efx_link_set_wanted_fc(efx, wanted_fc); | 
|  | 756 | if (efx->link_advertising != old_adv || | 
|  | 757 | (efx->wanted_fc ^ old_fc) & EFX_FC_AUTO) { | 
|  | 758 | rc = efx->phy_op->reconfigure(efx); | 
|  | 759 | if (rc) { | 
| Ben Hutchings | 62776d0 | 2010-06-23 11:30:07 +0000 | [diff] [blame] | 760 | netif_err(efx, drv, efx->net_dev, | 
|  | 761 | "Unable to advertise requested flow " | 
|  | 762 | "control setting\n"); | 
| Ben Hutchings | d3245b2 | 2009-11-29 03:42:41 +0000 | [diff] [blame] | 763 | goto out; | 
|  | 764 | } | 
|  | 765 | } | 
| Ben Hutchings | 04cc8ca | 2008-12-12 21:50:46 -0800 | [diff] [blame] | 766 |  | 
| Ben Hutchings | d3245b2 | 2009-11-29 03:42:41 +0000 | [diff] [blame] | 767 | /* Reconfigure the MAC. The PHY *may* generate a link state change event | 
|  | 768 | * if the user just changed the advertised capabilities, but there's no | 
|  | 769 | * harm doing this twice */ | 
| Ben Hutchings | 710b208 | 2011-09-03 00:15:00 +0100 | [diff] [blame] | 770 | efx->type->reconfigure_mac(efx); | 
| Ben Hutchings | 04cc8ca | 2008-12-12 21:50:46 -0800 | [diff] [blame] | 771 |  | 
| Ben Hutchings | d3245b2 | 2009-11-29 03:42:41 +0000 | [diff] [blame] | 772 | out: | 
| Ben Hutchings | 04cc8ca | 2008-12-12 21:50:46 -0800 | [diff] [blame] | 773 | mutex_unlock(&efx->mac_lock); | 
|  | 774 |  | 
| Ben Hutchings | d3245b2 | 2009-11-29 03:42:41 +0000 | [diff] [blame] | 775 | return rc; | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 776 | } | 
|  | 777 |  | 
|  | 778 | static void efx_ethtool_get_pauseparam(struct net_device *net_dev, | 
|  | 779 | struct ethtool_pauseparam *pause) | 
|  | 780 | { | 
| Ben Hutchings | 767e468 | 2008-09-01 12:43:14 +0100 | [diff] [blame] | 781 | struct efx_nic *efx = netdev_priv(net_dev); | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 782 |  | 
| Ben Hutchings | 04cc8ca | 2008-12-12 21:50:46 -0800 | [diff] [blame] | 783 | pause->rx_pause = !!(efx->wanted_fc & EFX_FC_RX); | 
|  | 784 | pause->tx_pause = !!(efx->wanted_fc & EFX_FC_TX); | 
|  | 785 | pause->autoneg = !!(efx->wanted_fc & EFX_FC_AUTO); | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 786 | } | 
|  | 787 |  | 
|  | 788 |  | 
| Ben Hutchings | 89c758f | 2009-11-29 03:43:07 +0000 | [diff] [blame] | 789 | static void efx_ethtool_get_wol(struct net_device *net_dev, | 
|  | 790 | struct ethtool_wolinfo *wol) | 
|  | 791 | { | 
|  | 792 | struct efx_nic *efx = netdev_priv(net_dev); | 
|  | 793 | return efx->type->get_wol(efx, wol); | 
|  | 794 | } | 
|  | 795 |  | 
|  | 796 |  | 
|  | 797 | static int efx_ethtool_set_wol(struct net_device *net_dev, | 
|  | 798 | struct ethtool_wolinfo *wol) | 
|  | 799 | { | 
|  | 800 | struct efx_nic *efx = netdev_priv(net_dev); | 
|  | 801 | return efx->type->set_wol(efx, wol->wolopts); | 
|  | 802 | } | 
|  | 803 |  | 
| stephen hemminger | d215697 | 2010-10-18 05:27:31 +0000 | [diff] [blame] | 804 | static int efx_ethtool_reset(struct net_device *net_dev, u32 *flags) | 
| Ben Hutchings | eb9f674 | 2009-11-29 03:43:15 +0000 | [diff] [blame] | 805 | { | 
|  | 806 | struct efx_nic *efx = netdev_priv(net_dev); | 
| Ben Hutchings | 0e2a9c7 | 2011-06-24 20:50:07 +0100 | [diff] [blame] | 807 | int rc; | 
| Ben Hutchings | eb9f674 | 2009-11-29 03:43:15 +0000 | [diff] [blame] | 808 |  | 
| Ben Hutchings | 0e2a9c7 | 2011-06-24 20:50:07 +0100 | [diff] [blame] | 809 | rc = efx->type->map_reset_flags(flags); | 
|  | 810 | if (rc < 0) | 
|  | 811 | return rc; | 
| Ben Hutchings | eb9f674 | 2009-11-29 03:43:15 +0000 | [diff] [blame] | 812 |  | 
| Ben Hutchings | 0e2a9c7 | 2011-06-24 20:50:07 +0100 | [diff] [blame] | 813 | return efx_reset(efx, rc); | 
| Ben Hutchings | eb9f674 | 2009-11-29 03:43:15 +0000 | [diff] [blame] | 814 | } | 
|  | 815 |  | 
| Ben Hutchings | c274d65 | 2012-02-02 22:41:49 +0000 | [diff] [blame] | 816 | /* MAC address mask including only MC flag */ | 
|  | 817 | static const u8 mac_addr_mc_mask[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 }; | 
|  | 818 |  | 
| Ben Hutchings | b2bb7b7 | 2012-01-03 12:05:47 +0000 | [diff] [blame] | 819 | static int efx_ethtool_get_class_rule(struct efx_nic *efx, | 
|  | 820 | struct ethtool_rx_flow_spec *rule) | 
|  | 821 | { | 
|  | 822 | struct ethtool_tcpip4_spec *ip_entry = &rule->h_u.tcp_ip4_spec; | 
|  | 823 | struct ethtool_tcpip4_spec *ip_mask = &rule->m_u.tcp_ip4_spec; | 
| Ben Hutchings | c274d65 | 2012-02-02 22:41:49 +0000 | [diff] [blame] | 824 | struct ethhdr *mac_entry = &rule->h_u.ether_spec; | 
|  | 825 | struct ethhdr *mac_mask = &rule->m_u.ether_spec; | 
| Ben Hutchings | b2bb7b7 | 2012-01-03 12:05:47 +0000 | [diff] [blame] | 826 | struct efx_filter_spec spec; | 
|  | 827 | u16 vid; | 
|  | 828 | u8 proto; | 
|  | 829 | int rc; | 
|  | 830 |  | 
|  | 831 | rc = efx_filter_get_filter_safe(efx, EFX_FILTER_PRI_MANUAL, | 
|  | 832 | rule->location, &spec); | 
|  | 833 | if (rc) | 
|  | 834 | return rc; | 
|  | 835 |  | 
|  | 836 | if (spec.dmaq_id == 0xfff) | 
|  | 837 | rule->ring_cookie = RX_CLS_FLOW_DISC; | 
|  | 838 | else | 
|  | 839 | rule->ring_cookie = spec.dmaq_id; | 
|  | 840 |  | 
| Ben Hutchings | c274d65 | 2012-02-02 22:41:49 +0000 | [diff] [blame] | 841 | if (spec.type == EFX_FILTER_MC_DEF || spec.type == EFX_FILTER_UC_DEF) { | 
|  | 842 | rule->flow_type = ETHER_FLOW; | 
|  | 843 | memcpy(mac_mask->h_dest, mac_addr_mc_mask, ETH_ALEN); | 
|  | 844 | if (spec.type == EFX_FILTER_MC_DEF) | 
|  | 845 | memcpy(mac_entry->h_dest, mac_addr_mc_mask, ETH_ALEN); | 
|  | 846 | return 0; | 
|  | 847 | } | 
|  | 848 |  | 
|  | 849 | rc = efx_filter_get_eth_local(&spec, &vid, mac_entry->h_dest); | 
| Ben Hutchings | b2bb7b7 | 2012-01-03 12:05:47 +0000 | [diff] [blame] | 850 | if (rc == 0) { | 
|  | 851 | rule->flow_type = ETHER_FLOW; | 
| Ben Hutchings | c274d65 | 2012-02-02 22:41:49 +0000 | [diff] [blame] | 852 | memset(mac_mask->h_dest, ~0, ETH_ALEN); | 
| Ben Hutchings | b2bb7b7 | 2012-01-03 12:05:47 +0000 | [diff] [blame] | 853 | if (vid != EFX_FILTER_VID_UNSPEC) { | 
|  | 854 | rule->flow_type |= FLOW_EXT; | 
|  | 855 | rule->h_ext.vlan_tci = htons(vid); | 
|  | 856 | rule->m_ext.vlan_tci = htons(0xfff); | 
|  | 857 | } | 
|  | 858 | return 0; | 
|  | 859 | } | 
|  | 860 |  | 
|  | 861 | rc = efx_filter_get_ipv4_local(&spec, &proto, | 
|  | 862 | &ip_entry->ip4dst, &ip_entry->pdst); | 
|  | 863 | if (rc != 0) { | 
|  | 864 | rc = efx_filter_get_ipv4_full( | 
| Ben Hutchings | ac70b2e | 2012-08-15 18:09:15 +0100 | [diff] [blame] | 865 | &spec, &proto, &ip_entry->ip4dst, &ip_entry->pdst, | 
|  | 866 | &ip_entry->ip4src, &ip_entry->psrc); | 
| Ben Hutchings | b2bb7b7 | 2012-01-03 12:05:47 +0000 | [diff] [blame] | 867 | EFX_WARN_ON_PARANOID(rc); | 
|  | 868 | ip_mask->ip4src = ~0; | 
|  | 869 | ip_mask->psrc = ~0; | 
|  | 870 | } | 
|  | 871 | rule->flow_type = (proto == IPPROTO_TCP) ? TCP_V4_FLOW : UDP_V4_FLOW; | 
|  | 872 | ip_mask->ip4dst = ~0; | 
|  | 873 | ip_mask->pdst = ~0; | 
|  | 874 | return rc; | 
|  | 875 | } | 
|  | 876 |  | 
| Ben Hutchings | 765c9f4 | 2010-06-30 05:06:28 +0000 | [diff] [blame] | 877 | static int | 
|  | 878 | efx_ethtool_get_rxnfc(struct net_device *net_dev, | 
| Ben Hutchings | b2bb7b7 | 2012-01-03 12:05:47 +0000 | [diff] [blame] | 879 | struct ethtool_rxnfc *info, u32 *rule_locs) | 
| Ben Hutchings | 765c9f4 | 2010-06-30 05:06:28 +0000 | [diff] [blame] | 880 | { | 
|  | 881 | struct efx_nic *efx = netdev_priv(net_dev); | 
|  | 882 |  | 
|  | 883 | switch (info->cmd) { | 
|  | 884 | case ETHTOOL_GRXRINGS: | 
|  | 885 | info->data = efx->n_rx_channels; | 
|  | 886 | return 0; | 
|  | 887 |  | 
|  | 888 | case ETHTOOL_GRXFH: { | 
|  | 889 | unsigned min_revision = 0; | 
|  | 890 |  | 
|  | 891 | info->data = 0; | 
|  | 892 | switch (info->flow_type) { | 
|  | 893 | case TCP_V4_FLOW: | 
|  | 894 | info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; | 
|  | 895 | /* fall through */ | 
|  | 896 | case UDP_V4_FLOW: | 
|  | 897 | case SCTP_V4_FLOW: | 
|  | 898 | case AH_ESP_V4_FLOW: | 
|  | 899 | case IPV4_FLOW: | 
|  | 900 | info->data |= RXH_IP_SRC | RXH_IP_DST; | 
|  | 901 | min_revision = EFX_REV_FALCON_B0; | 
|  | 902 | break; | 
|  | 903 | case TCP_V6_FLOW: | 
|  | 904 | info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; | 
|  | 905 | /* fall through */ | 
|  | 906 | case UDP_V6_FLOW: | 
|  | 907 | case SCTP_V6_FLOW: | 
|  | 908 | case AH_ESP_V6_FLOW: | 
|  | 909 | case IPV6_FLOW: | 
|  | 910 | info->data |= RXH_IP_SRC | RXH_IP_DST; | 
|  | 911 | min_revision = EFX_REV_SIENA_A0; | 
|  | 912 | break; | 
|  | 913 | default: | 
|  | 914 | break; | 
|  | 915 | } | 
|  | 916 | if (efx_nic_rev(efx) < min_revision) | 
|  | 917 | info->data = 0; | 
|  | 918 | return 0; | 
|  | 919 | } | 
|  | 920 |  | 
| Ben Hutchings | b2bb7b7 | 2012-01-03 12:05:47 +0000 | [diff] [blame] | 921 | case ETHTOOL_GRXCLSRLCNT: | 
|  | 922 | info->data = efx_filter_get_rx_id_limit(efx); | 
|  | 923 | if (info->data == 0) | 
|  | 924 | return -EOPNOTSUPP; | 
|  | 925 | info->data |= RX_CLS_LOC_SPECIAL; | 
|  | 926 | info->rule_cnt = | 
|  | 927 | efx_filter_count_rx_used(efx, EFX_FILTER_PRI_MANUAL); | 
|  | 928 | return 0; | 
|  | 929 |  | 
|  | 930 | case ETHTOOL_GRXCLSRULE: | 
|  | 931 | if (efx_filter_get_rx_id_limit(efx) == 0) | 
|  | 932 | return -EOPNOTSUPP; | 
|  | 933 | return efx_ethtool_get_class_rule(efx, &info->fs); | 
|  | 934 |  | 
|  | 935 | case ETHTOOL_GRXCLSRLALL: { | 
|  | 936 | s32 rc; | 
|  | 937 | info->data = efx_filter_get_rx_id_limit(efx); | 
|  | 938 | if (info->data == 0) | 
|  | 939 | return -EOPNOTSUPP; | 
|  | 940 | rc = efx_filter_get_rx_ids(efx, EFX_FILTER_PRI_MANUAL, | 
|  | 941 | rule_locs, info->rule_cnt); | 
|  | 942 | if (rc < 0) | 
|  | 943 | return rc; | 
|  | 944 | info->rule_cnt = rc; | 
|  | 945 | return 0; | 
|  | 946 | } | 
|  | 947 |  | 
| Ben Hutchings | 765c9f4 | 2010-06-30 05:06:28 +0000 | [diff] [blame] | 948 | default: | 
|  | 949 | return -EOPNOTSUPP; | 
|  | 950 | } | 
|  | 951 | } | 
|  | 952 |  | 
| Ben Hutchings | b2bb7b7 | 2012-01-03 12:05:47 +0000 | [diff] [blame] | 953 | static int efx_ethtool_set_class_rule(struct efx_nic *efx, | 
|  | 954 | struct ethtool_rx_flow_spec *rule) | 
| Ben Hutchings | b4187e4 | 2010-09-20 08:43:42 +0000 | [diff] [blame] | 955 | { | 
| Ben Hutchings | b2bb7b7 | 2012-01-03 12:05:47 +0000 | [diff] [blame] | 956 | struct ethtool_tcpip4_spec *ip_entry = &rule->h_u.tcp_ip4_spec; | 
|  | 957 | struct ethtool_tcpip4_spec *ip_mask = &rule->m_u.tcp_ip4_spec; | 
|  | 958 | struct ethhdr *mac_entry = &rule->h_u.ether_spec; | 
|  | 959 | struct ethhdr *mac_mask = &rule->m_u.ether_spec; | 
|  | 960 | struct efx_filter_spec spec; | 
| Ben Hutchings | c39d35e | 2010-12-07 19:11:26 +0000 | [diff] [blame] | 961 | int rc; | 
| Ben Hutchings | b4187e4 | 2010-09-20 08:43:42 +0000 | [diff] [blame] | 962 |  | 
| Ben Hutchings | b2bb7b7 | 2012-01-03 12:05:47 +0000 | [diff] [blame] | 963 | /* Check that user wants us to choose the location */ | 
| Ben Hutchings | 9e0f9a1 | 2012-09-04 18:57:25 +0100 | [diff] [blame] | 964 | if (rule->location != RX_CLS_LOC_ANY) | 
| Ben Hutchings | b4187e4 | 2010-09-20 08:43:42 +0000 | [diff] [blame] | 965 | return -EINVAL; | 
|  | 966 |  | 
| Ben Hutchings | b2bb7b7 | 2012-01-03 12:05:47 +0000 | [diff] [blame] | 967 | /* Range-check ring_cookie */ | 
|  | 968 | if (rule->ring_cookie >= efx->n_rx_channels && | 
|  | 969 | rule->ring_cookie != RX_CLS_FLOW_DISC) | 
| Ben Hutchings | b4187e4 | 2010-09-20 08:43:42 +0000 | [diff] [blame] | 970 | return -EINVAL; | 
|  | 971 |  | 
| Ben Hutchings | b2bb7b7 | 2012-01-03 12:05:47 +0000 | [diff] [blame] | 972 | /* Check for unsupported extensions */ | 
|  | 973 | if ((rule->flow_type & FLOW_EXT) && | 
|  | 974 | (rule->m_ext.vlan_etype | rule->m_ext.data[0] | | 
|  | 975 | rule->m_ext.data[1])) | 
|  | 976 | return -EINVAL; | 
| Ben Hutchings | c39d35e | 2010-12-07 19:11:26 +0000 | [diff] [blame] | 977 |  | 
| Ben Hutchings | 9e0f9a1 | 2012-09-04 18:57:25 +0100 | [diff] [blame] | 978 | efx_filter_init_rx(&spec, EFX_FILTER_PRI_MANUAL, 0, | 
| Ben Hutchings | b2bb7b7 | 2012-01-03 12:05:47 +0000 | [diff] [blame] | 979 | (rule->ring_cookie == RX_CLS_FLOW_DISC) ? | 
|  | 980 | 0xfff : rule->ring_cookie); | 
|  | 981 |  | 
|  | 982 | switch (rule->flow_type) { | 
| Ben Hutchings | b4187e4 | 2010-09-20 08:43:42 +0000 | [diff] [blame] | 983 | case TCP_V4_FLOW: | 
| Ben Hutchings | c39d35e | 2010-12-07 19:11:26 +0000 | [diff] [blame] | 984 | case UDP_V4_FLOW: { | 
| Ben Hutchings | b2bb7b7 | 2012-01-03 12:05:47 +0000 | [diff] [blame] | 985 | u8 proto = (rule->flow_type == TCP_V4_FLOW ? | 
| Ben Hutchings | c39d35e | 2010-12-07 19:11:26 +0000 | [diff] [blame] | 986 | IPPROTO_TCP : IPPROTO_UDP); | 
|  | 987 |  | 
| Ben Hutchings | b4187e4 | 2010-09-20 08:43:42 +0000 | [diff] [blame] | 988 | /* Must match all of destination, */ | 
| Ben Hutchings | b2bb7b7 | 2012-01-03 12:05:47 +0000 | [diff] [blame] | 989 | if ((__force u32)~ip_mask->ip4dst | | 
|  | 990 | (__force u16)~ip_mask->pdst) | 
| Ben Hutchings | b4187e4 | 2010-09-20 08:43:42 +0000 | [diff] [blame] | 991 | return -EINVAL; | 
|  | 992 | /* all or none of source, */ | 
|  | 993 | if ((ip_mask->ip4src | ip_mask->psrc) && | 
|  | 994 | ((__force u32)~ip_mask->ip4src | | 
|  | 995 | (__force u16)~ip_mask->psrc)) | 
|  | 996 | return -EINVAL; | 
|  | 997 | /* and nothing else */ | 
| Ben Hutchings | b2bb7b7 | 2012-01-03 12:05:47 +0000 | [diff] [blame] | 998 | if (ip_mask->tos | rule->m_ext.vlan_tci) | 
| Ben Hutchings | b4187e4 | 2010-09-20 08:43:42 +0000 | [diff] [blame] | 999 | return -EINVAL; | 
| Ben Hutchings | c39d35e | 2010-12-07 19:11:26 +0000 | [diff] [blame] | 1000 |  | 
| Ben Hutchings | b2bb7b7 | 2012-01-03 12:05:47 +0000 | [diff] [blame] | 1001 | if (ip_mask->ip4src) | 
|  | 1002 | rc = efx_filter_set_ipv4_full(&spec, proto, | 
| Ben Hutchings | c39d35e | 2010-12-07 19:11:26 +0000 | [diff] [blame] | 1003 | ip_entry->ip4dst, | 
|  | 1004 | ip_entry->pdst, | 
|  | 1005 | ip_entry->ip4src, | 
|  | 1006 | ip_entry->psrc); | 
|  | 1007 | else | 
| Ben Hutchings | b2bb7b7 | 2012-01-03 12:05:47 +0000 | [diff] [blame] | 1008 | rc = efx_filter_set_ipv4_local(&spec, proto, | 
| Ben Hutchings | c39d35e | 2010-12-07 19:11:26 +0000 | [diff] [blame] | 1009 | ip_entry->ip4dst, | 
|  | 1010 | ip_entry->pdst); | 
|  | 1011 | if (rc) | 
|  | 1012 | return rc; | 
| Ben Hutchings | b4187e4 | 2010-09-20 08:43:42 +0000 | [diff] [blame] | 1013 | break; | 
| Ben Hutchings | c39d35e | 2010-12-07 19:11:26 +0000 | [diff] [blame] | 1014 | } | 
|  | 1015 |  | 
| Ben Hutchings | b2bb7b7 | 2012-01-03 12:05:47 +0000 | [diff] [blame] | 1016 | case ETHER_FLOW | FLOW_EXT: | 
| Ben Hutchings | c274d65 | 2012-02-02 22:41:49 +0000 | [diff] [blame] | 1017 | case ETHER_FLOW: { | 
|  | 1018 | u16 vlan_tag_mask = (rule->flow_type & FLOW_EXT ? | 
|  | 1019 | ntohs(rule->m_ext.vlan_tci) : 0); | 
|  | 1020 |  | 
|  | 1021 | /* Must not match on source address or Ethertype */ | 
| Ben Hutchings | b2bb7b7 | 2012-01-03 12:05:47 +0000 | [diff] [blame] | 1022 | if (!is_zero_ether_addr(mac_mask->h_source) || | 
|  | 1023 | mac_mask->h_proto) | 
| Ben Hutchings | b4187e4 | 2010-09-20 08:43:42 +0000 | [diff] [blame] | 1024 | return -EINVAL; | 
| Ben Hutchings | c39d35e | 2010-12-07 19:11:26 +0000 | [diff] [blame] | 1025 |  | 
| Ben Hutchings | c274d65 | 2012-02-02 22:41:49 +0000 | [diff] [blame] | 1026 | /* Is it a default UC or MC filter? */ | 
| Joe Perches | 2e42e47 | 2012-05-09 17:17:46 +0000 | [diff] [blame] | 1027 | if (ether_addr_equal(mac_mask->h_dest, mac_addr_mc_mask) && | 
| Ben Hutchings | c274d65 | 2012-02-02 22:41:49 +0000 | [diff] [blame] | 1028 | vlan_tag_mask == 0) { | 
|  | 1029 | if (is_multicast_ether_addr(mac_entry->h_dest)) | 
|  | 1030 | rc = efx_filter_set_mc_def(&spec); | 
|  | 1031 | else | 
|  | 1032 | rc = efx_filter_set_uc_def(&spec); | 
|  | 1033 | } | 
|  | 1034 | /* Otherwise, it must match all of destination and all | 
|  | 1035 | * or none of VID. | 
|  | 1036 | */ | 
|  | 1037 | else if (is_broadcast_ether_addr(mac_mask->h_dest) && | 
|  | 1038 | (vlan_tag_mask == 0xfff || vlan_tag_mask == 0)) { | 
|  | 1039 | rc = efx_filter_set_eth_local( | 
|  | 1040 | &spec, | 
|  | 1041 | vlan_tag_mask ? | 
|  | 1042 | ntohs(rule->h_ext.vlan_tci) : EFX_FILTER_VID_UNSPEC, | 
|  | 1043 | mac_entry->h_dest); | 
|  | 1044 | } else { | 
|  | 1045 | rc = -EINVAL; | 
|  | 1046 | } | 
| Ben Hutchings | c39d35e | 2010-12-07 19:11:26 +0000 | [diff] [blame] | 1047 | if (rc) | 
|  | 1048 | return rc; | 
| Ben Hutchings | b4187e4 | 2010-09-20 08:43:42 +0000 | [diff] [blame] | 1049 | break; | 
| Ben Hutchings | c274d65 | 2012-02-02 22:41:49 +0000 | [diff] [blame] | 1050 | } | 
| Ben Hutchings | c39d35e | 2010-12-07 19:11:26 +0000 | [diff] [blame] | 1051 |  | 
| Ben Hutchings | b4187e4 | 2010-09-20 08:43:42 +0000 | [diff] [blame] | 1052 | default: | 
|  | 1053 | return -EINVAL; | 
|  | 1054 | } | 
|  | 1055 |  | 
| Ben Hutchings | b2bb7b7 | 2012-01-03 12:05:47 +0000 | [diff] [blame] | 1056 | rc = efx_filter_insert_filter(efx, &spec, true); | 
|  | 1057 | if (rc < 0) | 
|  | 1058 | return rc; | 
| Ben Hutchings | 47a8467 | 2011-05-14 02:35:25 +0100 | [diff] [blame] | 1059 |  | 
| Ben Hutchings | b2bb7b7 | 2012-01-03 12:05:47 +0000 | [diff] [blame] | 1060 | rule->location = rc; | 
|  | 1061 | return 0; | 
|  | 1062 | } | 
|  | 1063 |  | 
|  | 1064 | static int efx_ethtool_set_rxnfc(struct net_device *net_dev, | 
|  | 1065 | struct ethtool_rxnfc *info) | 
|  | 1066 | { | 
|  | 1067 | struct efx_nic *efx = netdev_priv(net_dev); | 
|  | 1068 |  | 
|  | 1069 | if (efx_filter_get_rx_id_limit(efx) == 0) | 
|  | 1070 | return -EOPNOTSUPP; | 
|  | 1071 |  | 
|  | 1072 | switch (info->cmd) { | 
|  | 1073 | case ETHTOOL_SRXCLSRLINS: | 
|  | 1074 | return efx_ethtool_set_class_rule(efx, &info->fs); | 
|  | 1075 |  | 
|  | 1076 | case ETHTOOL_SRXCLSRLDEL: | 
|  | 1077 | return efx_filter_remove_id_safe(efx, EFX_FILTER_PRI_MANUAL, | 
|  | 1078 | info->fs.location); | 
|  | 1079 |  | 
|  | 1080 | default: | 
|  | 1081 | return -EOPNOTSUPP; | 
|  | 1082 | } | 
| Ben Hutchings | b4187e4 | 2010-09-20 08:43:42 +0000 | [diff] [blame] | 1083 | } | 
|  | 1084 |  | 
| Ben Hutchings | 7850f63 | 2011-12-15 13:55:01 +0000 | [diff] [blame] | 1085 | static u32 efx_ethtool_get_rxfh_indir_size(struct net_device *net_dev) | 
| Ben Hutchings | 765c9f4 | 2010-06-30 05:06:28 +0000 | [diff] [blame] | 1086 | { | 
|  | 1087 | struct efx_nic *efx = netdev_priv(net_dev); | 
| Ben Hutchings | 765c9f4 | 2010-06-30 05:06:28 +0000 | [diff] [blame] | 1088 |  | 
| Ben Hutchings | cd2d5b5 | 2012-02-14 00:48:07 +0000 | [diff] [blame] | 1089 | return ((efx_nic_rev(efx) < EFX_REV_FALCON_B0 || | 
|  | 1090 | efx->n_rx_channels == 1) ? | 
| Ben Hutchings | 7850f63 | 2011-12-15 13:55:01 +0000 | [diff] [blame] | 1091 | 0 : ARRAY_SIZE(efx->rx_indir_table)); | 
|  | 1092 | } | 
| Ben Hutchings | 765c9f4 | 2010-06-30 05:06:28 +0000 | [diff] [blame] | 1093 |  | 
| Ben Hutchings | 7850f63 | 2011-12-15 13:55:01 +0000 | [diff] [blame] | 1094 | static int efx_ethtool_get_rxfh_indir(struct net_device *net_dev, u32 *indir) | 
|  | 1095 | { | 
|  | 1096 | struct efx_nic *efx = netdev_priv(net_dev); | 
|  | 1097 |  | 
|  | 1098 | memcpy(indir, efx->rx_indir_table, sizeof(efx->rx_indir_table)); | 
| Ben Hutchings | 765c9f4 | 2010-06-30 05:06:28 +0000 | [diff] [blame] | 1099 | return 0; | 
|  | 1100 | } | 
|  | 1101 |  | 
|  | 1102 | static int efx_ethtool_set_rxfh_indir(struct net_device *net_dev, | 
| Ben Hutchings | 7850f63 | 2011-12-15 13:55:01 +0000 | [diff] [blame] | 1103 | const u32 *indir) | 
| Ben Hutchings | 765c9f4 | 2010-06-30 05:06:28 +0000 | [diff] [blame] | 1104 | { | 
|  | 1105 | struct efx_nic *efx = netdev_priv(net_dev); | 
| Ben Hutchings | 765c9f4 | 2010-06-30 05:06:28 +0000 | [diff] [blame] | 1106 |  | 
| Ben Hutchings | 7850f63 | 2011-12-15 13:55:01 +0000 | [diff] [blame] | 1107 | memcpy(efx->rx_indir_table, indir, sizeof(efx->rx_indir_table)); | 
| Ben Hutchings | 765c9f4 | 2010-06-30 05:06:28 +0000 | [diff] [blame] | 1108 | efx_nic_push_rx_indir_table(efx); | 
|  | 1109 | return 0; | 
|  | 1110 | } | 
|  | 1111 |  | 
| Stuart Hodgson | c087bd2 | 2012-05-01 18:50:43 +0100 | [diff] [blame] | 1112 | static int efx_ethtool_get_module_eeprom(struct net_device *net_dev, | 
|  | 1113 | struct ethtool_eeprom *ee, | 
|  | 1114 | u8 *data) | 
|  | 1115 | { | 
|  | 1116 | struct efx_nic *efx = netdev_priv(net_dev); | 
|  | 1117 | int ret; | 
|  | 1118 |  | 
|  | 1119 | if (!efx->phy_op || !efx->phy_op->get_module_eeprom) | 
|  | 1120 | return -EOPNOTSUPP; | 
|  | 1121 |  | 
|  | 1122 | mutex_lock(&efx->mac_lock); | 
|  | 1123 | ret = efx->phy_op->get_module_eeprom(efx, ee, data); | 
|  | 1124 | mutex_unlock(&efx->mac_lock); | 
|  | 1125 |  | 
|  | 1126 | return ret; | 
|  | 1127 | } | 
|  | 1128 |  | 
|  | 1129 | static int efx_ethtool_get_module_info(struct net_device *net_dev, | 
|  | 1130 | struct ethtool_modinfo *modinfo) | 
|  | 1131 | { | 
|  | 1132 | struct efx_nic *efx = netdev_priv(net_dev); | 
|  | 1133 | int ret; | 
|  | 1134 |  | 
|  | 1135 | if (!efx->phy_op || !efx->phy_op->get_module_info) | 
|  | 1136 | return -EOPNOTSUPP; | 
|  | 1137 |  | 
|  | 1138 | mutex_lock(&efx->mac_lock); | 
|  | 1139 | ret = efx->phy_op->get_module_info(efx, modinfo); | 
|  | 1140 | mutex_unlock(&efx->mac_lock); | 
|  | 1141 |  | 
|  | 1142 | return ret; | 
|  | 1143 | } | 
|  | 1144 |  | 
| Stephen Hemminger | 0fc0b73 | 2009-09-02 01:03:33 -0700 | [diff] [blame] | 1145 | const struct ethtool_ops efx_ethtool_ops = { | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 1146 | .get_settings		= efx_ethtool_get_settings, | 
|  | 1147 | .set_settings		= efx_ethtool_set_settings, | 
|  | 1148 | .get_drvinfo		= efx_ethtool_get_drvinfo, | 
| Ben Hutchings | 5b98c1b | 2010-06-21 03:06:53 +0000 | [diff] [blame] | 1149 | .get_regs_len		= efx_ethtool_get_regs_len, | 
|  | 1150 | .get_regs		= efx_ethtool_get_regs, | 
| Ben Hutchings | 62776d0 | 2010-06-23 11:30:07 +0000 | [diff] [blame] | 1151 | .get_msglevel		= efx_ethtool_get_msglevel, | 
|  | 1152 | .set_msglevel		= efx_ethtool_set_msglevel, | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 1153 | .nway_reset		= efx_ethtool_nway_reset, | 
| Ben Hutchings | ed4ba4b | 2010-12-09 12:10:25 +0000 | [diff] [blame] | 1154 | .get_link		= ethtool_op_get_link, | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 1155 | .get_coalesce		= efx_ethtool_get_coalesce, | 
|  | 1156 | .set_coalesce		= efx_ethtool_set_coalesce, | 
| Ben Hutchings | 4642610 | 2010-09-10 06:42:33 +0000 | [diff] [blame] | 1157 | .get_ringparam		= efx_ethtool_get_ringparam, | 
|  | 1158 | .set_ringparam		= efx_ethtool_set_ringparam, | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 1159 | .get_pauseparam         = efx_ethtool_get_pauseparam, | 
|  | 1160 | .set_pauseparam         = efx_ethtool_set_pauseparam, | 
| Ben Hutchings | 3594e13 | 2008-09-01 12:48:12 +0100 | [diff] [blame] | 1161 | .get_sset_count		= efx_ethtool_get_sset_count, | 
| Ben Hutchings | 3273c2e | 2008-05-07 13:36:19 +0100 | [diff] [blame] | 1162 | .self_test		= efx_ethtool_self_test, | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 1163 | .get_strings		= efx_ethtool_get_strings, | 
| Ben Hutchings | c5e129a | 2011-04-02 00:43:46 +0100 | [diff] [blame] | 1164 | .set_phys_id		= efx_ethtool_phys_id, | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 1165 | .get_ethtool_stats	= efx_ethtool_get_stats, | 
| Ben Hutchings | 89c758f | 2009-11-29 03:43:07 +0000 | [diff] [blame] | 1166 | .get_wol                = efx_ethtool_get_wol, | 
|  | 1167 | .set_wol                = efx_ethtool_set_wol, | 
| Ben Hutchings | eb9f674 | 2009-11-29 03:43:15 +0000 | [diff] [blame] | 1168 | .reset			= efx_ethtool_reset, | 
| Ben Hutchings | 765c9f4 | 2010-06-30 05:06:28 +0000 | [diff] [blame] | 1169 | .get_rxnfc		= efx_ethtool_get_rxnfc, | 
| Ben Hutchings | b2bb7b7 | 2012-01-03 12:05:47 +0000 | [diff] [blame] | 1170 | .set_rxnfc		= efx_ethtool_set_rxnfc, | 
| Ben Hutchings | 7850f63 | 2011-12-15 13:55:01 +0000 | [diff] [blame] | 1171 | .get_rxfh_indir_size	= efx_ethtool_get_rxfh_indir_size, | 
| Ben Hutchings | 765c9f4 | 2010-06-30 05:06:28 +0000 | [diff] [blame] | 1172 | .get_rxfh_indir		= efx_ethtool_get_rxfh_indir, | 
|  | 1173 | .set_rxfh_indir		= efx_ethtool_set_rxfh_indir, | 
| Stuart Hodgson | 7c236c4 | 2012-09-03 11:09:36 +0100 | [diff] [blame] | 1174 | .get_ts_info		= efx_ptp_get_ts_info, | 
| Stuart Hodgson | c087bd2 | 2012-05-01 18:50:43 +0100 | [diff] [blame] | 1175 | .get_module_info	= efx_ethtool_get_module_info, | 
|  | 1176 | .get_module_eeprom	= efx_ethtool_get_module_eeprom, | 
| Ben Hutchings | 8ceee66 | 2008-04-27 12:55:59 +0100 | [diff] [blame] | 1177 | }; |