Skip to content

Commit

Permalink
Merge branch '100GbE' of git://git.kernel.org/pub/scm/linux/kernel/gi…
Browse files Browse the repository at this point in the history
…t/jkirsher/next-queue

Jeff Kirsher says:

====================
100GbE Intel Wired LAN Driver Updates 2017-04-05

This series contains updates to fm10k only.

Phil Turnbull from Oracle fixes an issue where the argument provided to
FM10K_REMOVED macro was not what was expecting.

Jake modifies the driver to replace the bitwise operators and defines with
a BITMAP and enumeration values to avoid race conditions.  Also future
proof the driver so that developers do not have to remember to re-size the
bitmaps when adding new values.  Fixed the wording of a code comment to
avoid stating that we return a value for a void function.

Ngai-Mint makes sure that when configuring the receive ring, we make sure
the receive queue is disabled.  Fixed an issue where interfaces were
resetting because the transmit mailbox FIFO was becoming full since the
host was not ready, so ensure the host is ready before queueing up
mailbox messages.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Apr 6, 2017
2 parents 6d2d34a + 7d4fe0d commit b404127
Show file tree
Hide file tree
Showing 5 changed files with 239 additions and 133 deletions.
68 changes: 44 additions & 24 deletions drivers/net/ethernet/intel/fm10k/fm10k.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* Intel(R) Ethernet Switch Host Interface Driver
* Copyright(c) 2013 - 2016 Intel Corporation.
* Copyright(c) 2013 - 2017 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
Expand Down Expand Up @@ -65,14 +65,16 @@ enum fm10k_ring_state_t {
__FM10K_TX_DETECT_HANG,
__FM10K_HANG_CHECK_ARMED,
__FM10K_TX_XPS_INIT_DONE,
/* This must be last and is used to calculate BITMAP size */
__FM10K_TX_STATE_SIZE__,
};

#define check_for_tx_hang(ring) \
test_bit(__FM10K_TX_DETECT_HANG, &(ring)->state)
test_bit(__FM10K_TX_DETECT_HANG, (ring)->state)
#define set_check_for_tx_hang(ring) \
set_bit(__FM10K_TX_DETECT_HANG, &(ring)->state)
set_bit(__FM10K_TX_DETECT_HANG, (ring)->state)
#define clear_check_for_tx_hang(ring) \
clear_bit(__FM10K_TX_DETECT_HANG, &(ring)->state)
clear_bit(__FM10K_TX_DETECT_HANG, (ring)->state)

struct fm10k_tx_buffer {
struct fm10k_tx_desc *next_to_watch;
Expand Down Expand Up @@ -126,7 +128,7 @@ struct fm10k_ring {
struct fm10k_rx_buffer *rx_buffer;
};
u32 __iomem *tail;
unsigned long state;
DECLARE_BITMAP(state, __FM10K_TX_STATE_SIZE__);
dma_addr_t dma; /* phys. address of descriptor ring */
unsigned int size; /* length in bytes */

Expand Down Expand Up @@ -249,18 +251,46 @@ struct fm10k_udp_port {
/* one work queue for entire driver */
extern struct workqueue_struct *fm10k_workqueue;

/* The following enumeration contains flags which indicate or enable modified
* driver behaviors. To avoid race conditions, the flags are stored in
* a BITMAP in the fm10k_intfc structure. The BITMAP should be accessed using
* atomic *_bit() operations.
*/
enum fm10k_flags_t {
FM10K_FLAG_RESET_REQUESTED,
FM10K_FLAG_RSS_FIELD_IPV4_UDP,
FM10K_FLAG_RSS_FIELD_IPV6_UDP,
FM10K_FLAG_SWPRI_CONFIG,
/* __FM10K_FLAGS_SIZE__ is used to calculate the size of
* interface->flags and must be the last value in this
* enumeration.
*/
__FM10K_FLAGS_SIZE__
};

enum fm10k_state_t {
__FM10K_RESETTING,
__FM10K_DOWN,
__FM10K_SERVICE_SCHED,
__FM10K_SERVICE_REQUEST,
__FM10K_SERVICE_DISABLE,
__FM10K_MBX_LOCK,
__FM10K_LINK_DOWN,
__FM10K_UPDATING_STATS,
/* This value must be last and determines the BITMAP size */
__FM10K_STATE_SIZE__,
};

struct fm10k_intfc {
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
struct net_device *netdev;
struct fm10k_l2_accel *l2_accel; /* pointer to L2 acceleration list */
struct pci_dev *pdev;
unsigned long state;
DECLARE_BITMAP(state, __FM10K_STATE_SIZE__);

/* Access flag values using atomic *_bit() operations */
DECLARE_BITMAP(flags, __FM10K_FLAGS_SIZE__);

u32 flags;
#define FM10K_FLAG_RESET_REQUESTED (u32)(BIT(0))
#define FM10K_FLAG_RSS_FIELD_IPV4_UDP (u32)(BIT(1))
#define FM10K_FLAG_RSS_FIELD_IPV6_UDP (u32)(BIT(2))
#define FM10K_FLAG_SWPRI_CONFIG (u32)(BIT(3))
int xcast_mode;

/* Tx fast path data */
Expand Down Expand Up @@ -352,35 +382,25 @@ struct fm10k_intfc {
u16 vid;
};

enum fm10k_state_t {
__FM10K_RESETTING,
__FM10K_DOWN,
__FM10K_SERVICE_SCHED,
__FM10K_SERVICE_DISABLE,
__FM10K_MBX_LOCK,
__FM10K_LINK_DOWN,
__FM10K_UPDATING_STATS,
};

static inline void fm10k_mbx_lock(struct fm10k_intfc *interface)
{
/* busy loop if we cannot obtain the lock as some calls
* such as ndo_set_rx_mode may be made in atomic context
*/
while (test_and_set_bit(__FM10K_MBX_LOCK, &interface->state))
while (test_and_set_bit(__FM10K_MBX_LOCK, interface->state))
udelay(20);
}

static inline void fm10k_mbx_unlock(struct fm10k_intfc *interface)
{
/* flush memory to make sure state is correct */
smp_mb__before_atomic();
clear_bit(__FM10K_MBX_LOCK, &interface->state);
clear_bit(__FM10K_MBX_LOCK, interface->state);
}

static inline int fm10k_mbx_trylock(struct fm10k_intfc *interface)
{
return !test_and_set_bit(__FM10K_MBX_LOCK, &interface->state);
return !test_and_set_bit(__FM10K_MBX_LOCK, interface->state);
}

/* fm10k_test_staterr - test bits in Rx descriptor status and error fields */
Expand Down
68 changes: 44 additions & 24 deletions drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* Intel(R) Ethernet Switch Host Interface Driver
* Copyright(c) 2013 - 2016 Intel Corporation.
* Copyright(c) 2013 - 2017 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
Expand Down Expand Up @@ -562,7 +562,7 @@ static int fm10k_set_ringparam(struct net_device *netdev,
return 0;
}

while (test_and_set_bit(__FM10K_RESETTING, &interface->state))
while (test_and_set_bit(__FM10K_RESETTING, interface->state))
usleep_range(1000, 2000);

if (!netif_running(interface->netdev)) {
Expand Down Expand Up @@ -648,7 +648,7 @@ static int fm10k_set_ringparam(struct net_device *netdev,
fm10k_up(interface);
vfree(temp_ring);
clear_reset:
clear_bit(__FM10K_RESETTING, &interface->state);
clear_bit(__FM10K_RESETTING, interface->state);
return err;
}

Expand Down Expand Up @@ -716,7 +716,8 @@ static int fm10k_get_rss_hash_opts(struct fm10k_intfc *interface,
cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
/* fall through */
case UDP_V4_FLOW:
if (interface->flags & FM10K_FLAG_RSS_FIELD_IPV4_UDP)
if (test_bit(FM10K_FLAG_RSS_FIELD_IPV4_UDP,
interface->flags))
cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
/* fall through */
case SCTP_V4_FLOW:
Expand All @@ -732,7 +733,8 @@ static int fm10k_get_rss_hash_opts(struct fm10k_intfc *interface,
cmd->data |= RXH_IP_SRC | RXH_IP_DST;
break;
case UDP_V6_FLOW:
if (interface->flags & FM10K_FLAG_RSS_FIELD_IPV6_UDP)
if (test_bit(FM10K_FLAG_RSS_FIELD_IPV6_UDP,
interface->flags))
cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
cmd->data |= RXH_IP_SRC | RXH_IP_DST;
break;
Expand Down Expand Up @@ -764,12 +766,13 @@ static int fm10k_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
return ret;
}

#define UDP_RSS_FLAGS (FM10K_FLAG_RSS_FIELD_IPV4_UDP | \
FM10K_FLAG_RSS_FIELD_IPV6_UDP)
static int fm10k_set_rss_hash_opt(struct fm10k_intfc *interface,
struct ethtool_rxnfc *nfc)
{
u32 flags = interface->flags;
int rss_ipv4_udp = test_bit(FM10K_FLAG_RSS_FIELD_IPV4_UDP,
interface->flags);
int rss_ipv6_udp = test_bit(FM10K_FLAG_RSS_FIELD_IPV6_UDP,
interface->flags);

/* RSS does not support anything other than hashing
* to queues on src and dst IPs and ports
Expand All @@ -793,10 +796,12 @@ static int fm10k_set_rss_hash_opt(struct fm10k_intfc *interface,
return -EINVAL;
switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
case 0:
flags &= ~FM10K_FLAG_RSS_FIELD_IPV4_UDP;
clear_bit(FM10K_FLAG_RSS_FIELD_IPV4_UDP,
interface->flags);
break;
case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
flags |= FM10K_FLAG_RSS_FIELD_IPV4_UDP;
set_bit(FM10K_FLAG_RSS_FIELD_IPV4_UDP,
interface->flags);
break;
default:
return -EINVAL;
Expand All @@ -808,10 +813,12 @@ static int fm10k_set_rss_hash_opt(struct fm10k_intfc *interface,
return -EINVAL;
switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
case 0:
flags &= ~FM10K_FLAG_RSS_FIELD_IPV6_UDP;
clear_bit(FM10K_FLAG_RSS_FIELD_IPV6_UDP,
interface->flags);
break;
case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
flags |= FM10K_FLAG_RSS_FIELD_IPV6_UDP;
set_bit(FM10K_FLAG_RSS_FIELD_IPV6_UDP,
interface->flags);
break;
default:
return -EINVAL;
Expand All @@ -835,28 +842,41 @@ static int fm10k_set_rss_hash_opt(struct fm10k_intfc *interface,
return -EINVAL;
}

/* if we changed something we need to update flags */
if (flags != interface->flags) {
/* If something changed we need to update the MRQC register. Note that
* test_bit() is guaranteed to return strictly 0 or 1, so testing for
* equality is safe.
*/
if ((rss_ipv4_udp != test_bit(FM10K_FLAG_RSS_FIELD_IPV4_UDP,
interface->flags)) ||
(rss_ipv6_udp != test_bit(FM10K_FLAG_RSS_FIELD_IPV6_UDP,
interface->flags))) {
struct fm10k_hw *hw = &interface->hw;
bool warn = false;
u32 mrqc;

if ((flags & UDP_RSS_FLAGS) &&
!(interface->flags & UDP_RSS_FLAGS))
netif_warn(interface, drv, interface->netdev,
"enabling UDP RSS: fragmented packets may arrive out of order to the stack above\n");

interface->flags = flags;

/* Perform hash on these packet types */
mrqc = FM10K_MRQC_IPV4 |
FM10K_MRQC_TCP_IPV4 |
FM10K_MRQC_IPV6 |
FM10K_MRQC_TCP_IPV6;

if (flags & FM10K_FLAG_RSS_FIELD_IPV4_UDP)
if (test_bit(FM10K_FLAG_RSS_FIELD_IPV4_UDP,
interface->flags)) {
mrqc |= FM10K_MRQC_UDP_IPV4;
if (flags & FM10K_FLAG_RSS_FIELD_IPV6_UDP)
warn = true;
}
if (test_bit(FM10K_FLAG_RSS_FIELD_IPV6_UDP,
interface->flags)) {
mrqc |= FM10K_MRQC_UDP_IPV6;
warn = true;
}

/* If we enable UDP RSS display a warning that this may cause
* fragmented UDP packets to arrive out of order.
*/
if (warn)
netif_warn(interface, drv, interface->netdev,
"enabling UDP RSS: fragmented packets may arrive out of order to the stack above\n");

fm10k_write_reg(hw, FM10K_MRQC(0), mrqc);
}
Expand Down Expand Up @@ -939,7 +959,7 @@ static void fm10k_self_test(struct net_device *dev,

memset(data, 0, sizeof(*data) * FM10K_TEST_LEN);

if (FM10K_REMOVED(hw)) {
if (FM10K_REMOVED(hw->hw_addr)) {
netif_err(interface, drv, dev,
"Interface removed - test blocked\n");
eth_test->flags |= ETH_TEST_FL_FAILED;
Expand Down
16 changes: 8 additions & 8 deletions drivers/net/ethernet/intel/fm10k/fm10k_main.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* Intel(R) Ethernet Switch Host Interface Driver
* Copyright(c) 2013 - 2016 Intel Corporation.
* Copyright(c) 2013 - 2017 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
Expand Down Expand Up @@ -34,7 +34,7 @@ const char fm10k_driver_version[] = DRV_VERSION;
char fm10k_driver_name[] = "fm10k";
static const char fm10k_driver_string[] = DRV_SUMMARY;
static const char fm10k_copyright[] =
"Copyright (c) 2013 - 2016 Intel Corporation.";
"Copyright(c) 2013 - 2017 Intel Corporation.";

MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
MODULE_DESCRIPTION(DRV_SUMMARY);
Expand Down Expand Up @@ -1175,13 +1175,13 @@ bool fm10k_check_tx_hang(struct fm10k_ring *tx_ring)
/* update completed stats and continue */
tx_ring->tx_stats.tx_done_old = tx_done;
/* reset the countdown */
clear_bit(__FM10K_HANG_CHECK_ARMED, &tx_ring->state);
clear_bit(__FM10K_HANG_CHECK_ARMED, tx_ring->state);

return false;
}

/* make sure it is true for two checks in a row */
return test_and_set_bit(__FM10K_HANG_CHECK_ARMED, &tx_ring->state);
return test_and_set_bit(__FM10K_HANG_CHECK_ARMED, tx_ring->state);
}

/**
Expand All @@ -1191,9 +1191,9 @@ bool fm10k_check_tx_hang(struct fm10k_ring *tx_ring)
void fm10k_tx_timeout_reset(struct fm10k_intfc *interface)
{
/* Do the reset outside of interrupt context */
if (!test_bit(__FM10K_DOWN, &interface->state)) {
if (!test_bit(__FM10K_DOWN, interface->state)) {
interface->tx_timeout_count++;
interface->flags |= FM10K_FLAG_RESET_REQUESTED;
set_bit(FM10K_FLAG_RESET_REQUESTED, interface->flags);
fm10k_service_event_schedule(interface);
}
}
Expand All @@ -1214,7 +1214,7 @@ static bool fm10k_clean_tx_irq(struct fm10k_q_vector *q_vector,
unsigned int budget = q_vector->tx.work_limit;
unsigned int i = tx_ring->next_to_clean;

if (test_bit(__FM10K_DOWN, &interface->state))
if (test_bit(__FM10K_DOWN, interface->state))
return true;

tx_buffer = &tx_ring->tx_buffer[i];
Expand Down Expand Up @@ -1344,7 +1344,7 @@ static bool fm10k_clean_tx_irq(struct fm10k_q_vector *q_vector,
smp_mb();
if (__netif_subqueue_stopped(tx_ring->netdev,
tx_ring->queue_index) &&
!test_bit(__FM10K_DOWN, &interface->state)) {
!test_bit(__FM10K_DOWN, interface->state)) {
netif_wake_subqueue(tx_ring->netdev,
tx_ring->queue_index);
++tx_ring->tx_stats.restart_queue;
Expand Down
Loading

0 comments on commit b404127

Please sign in to comment.