diff options
Diffstat (limited to 'drivers/net/ixgbe/ixgbe_ethtool.c')
-rw-r--r-- | drivers/net/ixgbe/ixgbe_ethtool.c | 142 |
1 files changed, 98 insertions, 44 deletions
diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 23ff23e8b39..2002ea88ca2 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c | |||
@@ -1477,9 +1477,7 @@ static void ixgbe_free_desc_rings(struct ixgbe_adapter *adapter) | |||
1477 | reg_ctl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); | 1477 | reg_ctl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); |
1478 | reg_ctl &= ~IXGBE_RXCTRL_RXEN; | 1478 | reg_ctl &= ~IXGBE_RXCTRL_RXEN; |
1479 | IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, reg_ctl); | 1479 | IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, reg_ctl); |
1480 | reg_ctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(rx_ring->reg_idx)); | 1480 | ixgbe_disable_rx_queue(adapter, rx_ring); |
1481 | reg_ctl &= ~IXGBE_RXDCTL_ENABLE; | ||
1482 | IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rx_ring->reg_idx), reg_ctl); | ||
1483 | 1481 | ||
1484 | /* now Tx */ | 1482 | /* now Tx */ |
1485 | reg_ctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(tx_ring->reg_idx)); | 1483 | reg_ctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(tx_ring->reg_idx)); |
@@ -2279,10 +2277,11 @@ static int ixgbe_set_rx_ntuple(struct net_device *dev, | |||
2279 | struct ethtool_rx_ntuple *cmd) | 2277 | struct ethtool_rx_ntuple *cmd) |
2280 | { | 2278 | { |
2281 | struct ixgbe_adapter *adapter = netdev_priv(dev); | 2279 | struct ixgbe_adapter *adapter = netdev_priv(dev); |
2282 | struct ethtool_rx_ntuple_flow_spec fs = cmd->fs; | 2280 | struct ethtool_rx_ntuple_flow_spec *fs = &cmd->fs; |
2283 | struct ixgbe_atr_input input_struct; | 2281 | union ixgbe_atr_input input_struct; |
2284 | struct ixgbe_atr_input_masks input_masks; | 2282 | struct ixgbe_atr_input_masks input_masks; |
2285 | int target_queue; | 2283 | int target_queue; |
2284 | int err; | ||
2286 | 2285 | ||
2287 | if (adapter->hw.mac.type == ixgbe_mac_82598EB) | 2286 | if (adapter->hw.mac.type == ixgbe_mac_82598EB) |
2288 | return -EOPNOTSUPP; | 2287 | return -EOPNOTSUPP; |
@@ -2291,67 +2290,122 @@ static int ixgbe_set_rx_ntuple(struct net_device *dev, | |||
2291 | * Don't allow programming if the action is a queue greater than | 2290 | * Don't allow programming if the action is a queue greater than |
2292 | * the number of online Tx queues. | 2291 | * the number of online Tx queues. |
2293 | */ | 2292 | */ |
2294 | if ((fs.action >= adapter->num_tx_queues) || | 2293 | if ((fs->action >= adapter->num_tx_queues) || |
2295 | (fs.action < ETHTOOL_RXNTUPLE_ACTION_DROP)) | 2294 | (fs->action < ETHTOOL_RXNTUPLE_ACTION_DROP)) |
2296 | return -EINVAL; | 2295 | return -EINVAL; |
2297 | 2296 | ||
2298 | memset(&input_struct, 0, sizeof(struct ixgbe_atr_input)); | 2297 | memset(&input_struct, 0, sizeof(union ixgbe_atr_input)); |
2299 | memset(&input_masks, 0, sizeof(struct ixgbe_atr_input_masks)); | 2298 | memset(&input_masks, 0, sizeof(struct ixgbe_atr_input_masks)); |
2300 | 2299 | ||
2301 | input_masks.src_ip_mask = fs.m_u.tcp_ip4_spec.ip4src; | 2300 | /* record flow type */ |
2302 | input_masks.dst_ip_mask = fs.m_u.tcp_ip4_spec.ip4dst; | 2301 | switch (fs->flow_type) { |
2303 | input_masks.src_port_mask = fs.m_u.tcp_ip4_spec.psrc; | 2302 | case IPV4_FLOW: |
2304 | input_masks.dst_port_mask = fs.m_u.tcp_ip4_spec.pdst; | 2303 | input_struct.formatted.flow_type = IXGBE_ATR_FLOW_TYPE_IPV4; |
2305 | input_masks.vlan_id_mask = fs.vlan_tag_mask; | 2304 | break; |
2306 | /* only use the lowest 2 bytes for flex bytes */ | ||
2307 | input_masks.data_mask = (fs.data_mask & 0xffff); | ||
2308 | |||
2309 | switch (fs.flow_type) { | ||
2310 | case TCP_V4_FLOW: | 2305 | case TCP_V4_FLOW: |
2311 | ixgbe_atr_set_l4type_82599(&input_struct, IXGBE_ATR_L4TYPE_TCP); | 2306 | input_struct.formatted.flow_type = IXGBE_ATR_FLOW_TYPE_TCPV4; |
2312 | break; | 2307 | break; |
2313 | case UDP_V4_FLOW: | 2308 | case UDP_V4_FLOW: |
2314 | ixgbe_atr_set_l4type_82599(&input_struct, IXGBE_ATR_L4TYPE_UDP); | 2309 | input_struct.formatted.flow_type = IXGBE_ATR_FLOW_TYPE_UDPV4; |
2315 | break; | 2310 | break; |
2316 | case SCTP_V4_FLOW: | 2311 | case SCTP_V4_FLOW: |
2317 | ixgbe_atr_set_l4type_82599(&input_struct, IXGBE_ATR_L4TYPE_SCTP); | 2312 | input_struct.formatted.flow_type = IXGBE_ATR_FLOW_TYPE_SCTPV4; |
2318 | break; | 2313 | break; |
2319 | default: | 2314 | default: |
2320 | return -1; | 2315 | return -1; |
2321 | } | 2316 | } |
2322 | 2317 | ||
2323 | /* Mask bits from the inputs based on user-supplied mask */ | 2318 | /* copy vlan tag minus the CFI bit */ |
2324 | ixgbe_atr_set_src_ipv4_82599(&input_struct, | 2319 | if ((fs->vlan_tag & 0xEFFF) || (~fs->vlan_tag_mask & 0xEFFF)) { |
2325 | (fs.h_u.tcp_ip4_spec.ip4src & ~fs.m_u.tcp_ip4_spec.ip4src)); | 2320 | input_struct.formatted.vlan_id = htons(fs->vlan_tag & 0xEFFF); |
2326 | ixgbe_atr_set_dst_ipv4_82599(&input_struct, | 2321 | if (!fs->vlan_tag_mask) { |
2327 | (fs.h_u.tcp_ip4_spec.ip4dst & ~fs.m_u.tcp_ip4_spec.ip4dst)); | 2322 | input_masks.vlan_id_mask = htons(0xEFFF); |
2328 | /* 82599 expects these to be byte-swapped for perfect filtering */ | 2323 | } else { |
2329 | ixgbe_atr_set_src_port_82599(&input_struct, | 2324 | switch (~fs->vlan_tag_mask & 0xEFFF) { |
2330 | ((ntohs(fs.h_u.tcp_ip4_spec.psrc)) & ~fs.m_u.tcp_ip4_spec.psrc)); | 2325 | /* all of these are valid vlan-mask values */ |
2331 | ixgbe_atr_set_dst_port_82599(&input_struct, | 2326 | case 0xEFFF: |
2332 | ((ntohs(fs.h_u.tcp_ip4_spec.pdst)) & ~fs.m_u.tcp_ip4_spec.pdst)); | 2327 | case 0xE000: |
2333 | 2328 | case 0x0FFF: | |
2334 | /* VLAN and Flex bytes are either completely masked or not */ | 2329 | case 0x0000: |
2335 | if (!fs.vlan_tag_mask) | 2330 | input_masks.vlan_id_mask = |
2336 | ixgbe_atr_set_vlan_id_82599(&input_struct, fs.vlan_tag); | 2331 | htons(~fs->vlan_tag_mask); |
2337 | 2332 | break; | |
2338 | if (!input_masks.data_mask) | 2333 | /* exit with error if vlan-mask is invalid */ |
2339 | /* make sure we only use the first 2 bytes of user data */ | 2334 | default: |
2340 | ixgbe_atr_set_flex_byte_82599(&input_struct, | 2335 | e_err(drv, "Partial VLAN ID or " |
2341 | (fs.data & 0xffff)); | 2336 | "priority mask in vlan-mask is not " |
2337 | "supported by hardware\n"); | ||
2338 | return -1; | ||
2339 | } | ||
2340 | } | ||
2341 | } | ||
2342 | |||
2343 | /* make sure we only use the first 2 bytes of user data */ | ||
2344 | if ((fs->data & 0xFFFF) || (~fs->data_mask & 0xFFFF)) { | ||
2345 | input_struct.formatted.flex_bytes = htons(fs->data & 0xFFFF); | ||
2346 | if (!(fs->data_mask & 0xFFFF)) { | ||
2347 | input_masks.flex_mask = 0xFFFF; | ||
2348 | } else if (~fs->data_mask & 0xFFFF) { | ||
2349 | e_err(drv, "Partial user-def-mask is not " | ||
2350 | "supported by hardware\n"); | ||
2351 | return -1; | ||
2352 | } | ||
2353 | } | ||
2354 | |||
2355 | /* | ||
2356 | * Copy input into formatted structures | ||
2357 | * | ||
2358 | * These assignments are based on the following logic | ||
2359 | * If neither input or mask are set assume value is masked out. | ||
2360 | * If input is set, but mask is not mask should default to accept all. | ||
2361 | * If input is not set, but mask is set then mask likely results in 0. | ||
2362 | * If input is set and mask is set then assign both. | ||
2363 | */ | ||
2364 | if (fs->h_u.tcp_ip4_spec.ip4src || ~fs->m_u.tcp_ip4_spec.ip4src) { | ||
2365 | input_struct.formatted.src_ip[0] = fs->h_u.tcp_ip4_spec.ip4src; | ||
2366 | if (!fs->m_u.tcp_ip4_spec.ip4src) | ||
2367 | input_masks.src_ip_mask[0] = 0xFFFFFFFF; | ||
2368 | else | ||
2369 | input_masks.src_ip_mask[0] = | ||
2370 | ~fs->m_u.tcp_ip4_spec.ip4src; | ||
2371 | } | ||
2372 | if (fs->h_u.tcp_ip4_spec.ip4dst || ~fs->m_u.tcp_ip4_spec.ip4dst) { | ||
2373 | input_struct.formatted.dst_ip[0] = fs->h_u.tcp_ip4_spec.ip4dst; | ||
2374 | if (!fs->m_u.tcp_ip4_spec.ip4dst) | ||
2375 | input_masks.dst_ip_mask[0] = 0xFFFFFFFF; | ||
2376 | else | ||
2377 | input_masks.dst_ip_mask[0] = | ||
2378 | ~fs->m_u.tcp_ip4_spec.ip4dst; | ||
2379 | } | ||
2380 | if (fs->h_u.tcp_ip4_spec.psrc || ~fs->m_u.tcp_ip4_spec.psrc) { | ||
2381 | input_struct.formatted.src_port = fs->h_u.tcp_ip4_spec.psrc; | ||
2382 | if (!fs->m_u.tcp_ip4_spec.psrc) | ||
2383 | input_masks.src_port_mask = 0xFFFF; | ||
2384 | else | ||
2385 | input_masks.src_port_mask = ~fs->m_u.tcp_ip4_spec.psrc; | ||
2386 | } | ||
2387 | if (fs->h_u.tcp_ip4_spec.pdst || ~fs->m_u.tcp_ip4_spec.pdst) { | ||
2388 | input_struct.formatted.dst_port = fs->h_u.tcp_ip4_spec.pdst; | ||
2389 | if (!fs->m_u.tcp_ip4_spec.pdst) | ||
2390 | input_masks.dst_port_mask = 0xFFFF; | ||
2391 | else | ||
2392 | input_masks.dst_port_mask = ~fs->m_u.tcp_ip4_spec.pdst; | ||
2393 | } | ||
2342 | 2394 | ||
2343 | /* determine if we need to drop or route the packet */ | 2395 | /* determine if we need to drop or route the packet */ |
2344 | if (fs.action == ETHTOOL_RXNTUPLE_ACTION_DROP) | 2396 | if (fs->action == ETHTOOL_RXNTUPLE_ACTION_DROP) |
2345 | target_queue = MAX_RX_QUEUES - 1; | 2397 | target_queue = MAX_RX_QUEUES - 1; |
2346 | else | 2398 | else |
2347 | target_queue = fs.action; | 2399 | target_queue = fs->action; |
2348 | 2400 | ||
2349 | spin_lock(&adapter->fdir_perfect_lock); | 2401 | spin_lock(&adapter->fdir_perfect_lock); |
2350 | ixgbe_fdir_add_perfect_filter_82599(&adapter->hw, &input_struct, | 2402 | err = ixgbe_fdir_add_perfect_filter_82599(&adapter->hw, |
2351 | &input_masks, 0, target_queue); | 2403 | &input_struct, |
2404 | &input_masks, 0, | ||
2405 | target_queue); | ||
2352 | spin_unlock(&adapter->fdir_perfect_lock); | 2406 | spin_unlock(&adapter->fdir_perfect_lock); |
2353 | 2407 | ||
2354 | return 0; | 2408 | return err ? -1 : 0; |
2355 | } | 2409 | } |
2356 | 2410 | ||
2357 | static const struct ethtool_ops ixgbe_ethtool_ops = { | 2411 | static const struct ethtool_ops ixgbe_ethtool_ops = { |