Commit 9f915141 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/next-queue



Jeff Kirsher says:

====================
Intel Wired LAN Driver Updates 2015-04-14

This series contains updates to fm10k only.

Fixed transmit statistics which was actually using values from the
receive ring, instead of the transmit ring.  Fixed up spelling mistakes
in code comments and resolved unused argument warnings.  Added support
for netconsole.  Fixed up statistic reporting so that we are only
reporting from actual queues as well as display PF only stats for
just the PF and not the VF.  Also fixed an issue that when returning
virtualization queues from the VF back to the PF, we were retaining
the VF rate limiter.

Fixed up the driver to use a separate workqueue, which helps reduce
and stabilize latency between scheduling the work in our interrupt and
actually performing the work.

Fixed a bug where the VF tried to set a multicast address before
requesting the required xcast mode.

Fix VF multicast update since VFs were being improperly added to the
switch's mutlicast group.  The error stems from the fact that incorrect
arguments were passed to the update_mc_addr().

Thanks to Alex Duyck for the extensive review.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents bae97d84 f4f88c6d
/* Intel Ethernet Switch Host Interface Driver /* Intel Ethernet Switch Host Interface Driver
* Copyright(c) 2013 - 2014 Intel Corporation. * Copyright(c) 2013 - 2015 Intel Corporation.
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
...@@ -235,6 +235,9 @@ struct fm10k_vxlan_port { ...@@ -235,6 +235,9 @@ struct fm10k_vxlan_port {
__be16 port; __be16 port;
}; };
/* one work queue for entire driver */
extern struct workqueue_struct *fm10k_workqueue;
struct fm10k_intfc { struct fm10k_intfc {
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)]; unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
struct net_device *netdev; struct net_device *netdev;
...@@ -266,7 +269,6 @@ struct fm10k_intfc { ...@@ -266,7 +269,6 @@ struct fm10k_intfc {
u64 tx_csum_errors; u64 tx_csum_errors;
u64 alloc_failed; u64 alloc_failed;
u64 rx_csum_errors; u64 rx_csum_errors;
u64 rx_errors;
u64 tx_bytes_nic; u64 tx_bytes_nic;
u64 tx_packets_nic; u64 tx_packets_nic;
...@@ -458,6 +460,9 @@ void fm10k_down(struct fm10k_intfc *interface); ...@@ -458,6 +460,9 @@ void fm10k_down(struct fm10k_intfc *interface);
void fm10k_update_stats(struct fm10k_intfc *interface); void fm10k_update_stats(struct fm10k_intfc *interface);
void fm10k_service_event_schedule(struct fm10k_intfc *interface); void fm10k_service_event_schedule(struct fm10k_intfc *interface);
void fm10k_update_rx_drop_en(struct fm10k_intfc *interface); void fm10k_update_rx_drop_en(struct fm10k_intfc *interface);
#ifdef CONFIG_NET_POLL_CONTROLLER
void fm10k_netpoll(struct net_device *netdev);
#endif
/* Netdev */ /* Netdev */
struct net_device *fm10k_alloc_netdev(void); struct net_device *fm10k_alloc_netdev(void);
......
/* Intel Ethernet Switch Host Interface Driver /* Intel Ethernet Switch Host Interface Driver
* Copyright(c) 2013 - 2014 Intel Corporation. * Copyright(c) 2013 - 2015 Intel Corporation.
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
...@@ -128,7 +128,7 @@ static int fm10k_dcbnl_ieee_setpfc(struct net_device *dev, struct ieee_pfc *pfc) ...@@ -128,7 +128,7 @@ static int fm10k_dcbnl_ieee_setpfc(struct net_device *dev, struct ieee_pfc *pfc)
* *
* Returns that we support only IEEE DCB for this interface * Returns that we support only IEEE DCB for this interface
**/ **/
static u8 fm10k_dcbnl_getdcbx(struct net_device *dev) static u8 fm10k_dcbnl_getdcbx(struct net_device __always_unused *dev)
{ {
return DCB_CAP_DCBX_HOST | DCB_CAP_DCBX_VER_IEEE; return DCB_CAP_DCBX_HOST | DCB_CAP_DCBX_VER_IEEE;
} }
...@@ -140,7 +140,7 @@ static u8 fm10k_dcbnl_getdcbx(struct net_device *dev) ...@@ -140,7 +140,7 @@ static u8 fm10k_dcbnl_getdcbx(struct net_device *dev)
* *
* Returns error on attempt to enable anything but IEEE DCB for this interface * Returns error on attempt to enable anything but IEEE DCB for this interface
**/ **/
static u8 fm10k_dcbnl_setdcbx(struct net_device *dev, u8 mode) static u8 fm10k_dcbnl_setdcbx(struct net_device __always_unused *dev, u8 mode)
{ {
return (mode != (DCB_CAP_DCBX_HOST | DCB_CAP_DCBX_VER_IEEE)) ? 1 : 0; return (mode != (DCB_CAP_DCBX_HOST | DCB_CAP_DCBX_VER_IEEE)) ? 1 : 0;
} }
......
/* Intel Ethernet Switch Host Interface Driver /* Intel Ethernet Switch Host Interface Driver
* Copyright(c) 2013 - 2014 Intel Corporation. * Copyright(c) 2013 - 2015 Intel Corporation.
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
...@@ -36,14 +36,16 @@ static void *fm10k_dbg_desc_seq_start(struct seq_file *s, loff_t *pos) ...@@ -36,14 +36,16 @@ static void *fm10k_dbg_desc_seq_start(struct seq_file *s, loff_t *pos)
return (*pos < ring->count) ? pos : NULL; return (*pos < ring->count) ? pos : NULL;
} }
static void *fm10k_dbg_desc_seq_next(struct seq_file *s, void *v, loff_t *pos) static void *fm10k_dbg_desc_seq_next(struct seq_file *s,
void __always_unused *v, loff_t *pos)
{ {
struct fm10k_ring *ring = s->private; struct fm10k_ring *ring = s->private;
return (++(*pos) < ring->count) ? pos : NULL; return (++(*pos) < ring->count) ? pos : NULL;
} }
static void fm10k_dbg_desc_seq_stop(struct seq_file *s, void *v) static void fm10k_dbg_desc_seq_stop(struct seq_file __always_unused *s,
__always_unused void *v)
{ {
/* Do nothing. */ /* Do nothing. */
} }
......
/* Intel Ethernet Switch Host Interface Driver /* Intel Ethernet Switch Host Interface Driver
* Copyright(c) 2013 - 2014 Intel Corporation. * Copyright(c) 2013 - 2015 Intel Corporation.
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
...@@ -57,13 +57,12 @@ static const struct fm10k_stats fm10k_gstrings_net_stats[] = { ...@@ -57,13 +57,12 @@ static const struct fm10k_stats fm10k_gstrings_net_stats[] = {
.stat_offset = offsetof(struct fm10k_intfc, _stat) \ .stat_offset = offsetof(struct fm10k_intfc, _stat) \
} }
static const struct fm10k_stats fm10k_gstrings_stats[] = { static const struct fm10k_stats fm10k_gstrings_global_stats[] = {
FM10K_STAT("tx_restart_queue", restart_queue), FM10K_STAT("tx_restart_queue", restart_queue),
FM10K_STAT("tx_busy", tx_busy), FM10K_STAT("tx_busy", tx_busy),
FM10K_STAT("tx_csum_errors", tx_csum_errors), FM10K_STAT("tx_csum_errors", tx_csum_errors),
FM10K_STAT("rx_alloc_failed", alloc_failed), FM10K_STAT("rx_alloc_failed", alloc_failed),
FM10K_STAT("rx_csum_errors", rx_csum_errors), FM10K_STAT("rx_csum_errors", rx_csum_errors),
FM10K_STAT("rx_errors", rx_errors),
FM10K_STAT("tx_packets_nic", tx_packets_nic), FM10K_STAT("tx_packets_nic", tx_packets_nic),
FM10K_STAT("tx_bytes_nic", tx_bytes_nic), FM10K_STAT("tx_bytes_nic", tx_bytes_nic),
...@@ -73,38 +72,42 @@ static const struct fm10k_stats fm10k_gstrings_stats[] = { ...@@ -73,38 +72,42 @@ static const struct fm10k_stats fm10k_gstrings_stats[] = {
FM10K_STAT("rx_overrun_pf", rx_overrun_pf), FM10K_STAT("rx_overrun_pf", rx_overrun_pf),
FM10K_STAT("rx_overrun_vf", rx_overrun_vf), FM10K_STAT("rx_overrun_vf", rx_overrun_vf),
FM10K_STAT("timeout", stats.timeout.count),
FM10K_STAT("ur", stats.ur.count),
FM10K_STAT("ca", stats.ca.count),
FM10K_STAT("um", stats.um.count),
FM10K_STAT("xec", stats.xec.count),
FM10K_STAT("vlan_drop", stats.vlan_drop.count),
FM10K_STAT("loopback_drop", stats.loopback_drop.count),
FM10K_STAT("nodesc_drop", stats.nodesc_drop.count),
FM10K_STAT("swapi_status", hw.swapi.status), FM10K_STAT("swapi_status", hw.swapi.status),
FM10K_STAT("mac_rules_used", hw.swapi.mac.used), FM10K_STAT("mac_rules_used", hw.swapi.mac.used),
FM10K_STAT("mac_rules_avail", hw.swapi.mac.avail), FM10K_STAT("mac_rules_avail", hw.swapi.mac.avail),
FM10K_STAT("mbx_tx_busy", hw.mbx.tx_busy), FM10K_STAT("mbx_tx_busy", hw.mbx.tx_busy),
FM10K_STAT("mbx_tx_dropped", hw.mbx.tx_dropped), FM10K_STAT("mbx_tx_oversized", hw.mbx.tx_dropped),
FM10K_STAT("mbx_tx_messages", hw.mbx.tx_messages), FM10K_STAT("mbx_tx_messages", hw.mbx.tx_messages),
FM10K_STAT("mbx_tx_dwords", hw.mbx.tx_dwords), FM10K_STAT("mbx_tx_dwords", hw.mbx.tx_dwords),
FM10K_STAT("mbx_rx_messages", hw.mbx.rx_messages), FM10K_STAT("mbx_rx_messages", hw.mbx.rx_messages),
FM10K_STAT("mbx_rx_dwords", hw.mbx.rx_dwords), FM10K_STAT("mbx_rx_dwords", hw.mbx.rx_dwords),
FM10K_STAT("mbx_rx_parse_err", hw.mbx.rx_parse_err), FM10K_STAT("mbx_rx_parse_err", hw.mbx.rx_parse_err),
FM10K_STAT("tx_hang_count", tx_timeout_count),
FM10K_STAT("tx_hwtstamp_timeouts", tx_hwtstamp_timeouts), FM10K_STAT("tx_hwtstamp_timeouts", tx_hwtstamp_timeouts),
}; };
#define FM10K_GLOBAL_STATS_LEN ARRAY_SIZE(fm10k_gstrings_stats) static const struct fm10k_stats fm10k_gstrings_pf_stats[] = {
FM10K_STAT("timeout", stats.timeout.count),
FM10K_STAT("ur", stats.ur.count),
FM10K_STAT("ca", stats.ca.count),
FM10K_STAT("um", stats.um.count),
FM10K_STAT("xec", stats.xec.count),
FM10K_STAT("vlan_drop", stats.vlan_drop.count),
FM10K_STAT("loopback_drop", stats.loopback_drop.count),
FM10K_STAT("nodesc_drop", stats.nodesc_drop.count),
};
#define FM10K_GLOBAL_STATS_LEN ARRAY_SIZE(fm10k_gstrings_global_stats)
#define FM10K_PF_STATS_LEN ARRAY_SIZE(fm10k_gstrings_pf_stats)
#define FM10K_QUEUE_STATS_LEN \ #define FM10K_QUEUE_STATS_LEN(_n) \
(MAX_QUEUES * 2 * (sizeof(struct fm10k_queue_stats) / sizeof(u64))) ( (_n) * 2 * (sizeof(struct fm10k_queue_stats) / sizeof(u64)))
#define FM10K_STATS_LEN (FM10K_GLOBAL_STATS_LEN + \ #define FM10K_STATIC_STATS_LEN (FM10K_GLOBAL_STATS_LEN + \
FM10K_NETDEV_STATS_LEN + \ FM10K_NETDEV_STATS_LEN)
FM10K_QUEUE_STATS_LEN)
static const char fm10k_gstrings_test[][ETH_GSTRING_LEN] = { static const char fm10k_gstrings_test[][ETH_GSTRING_LEN] = {
"Mailbox test (on/offline)" "Mailbox test (on/offline)"
...@@ -117,9 +120,9 @@ enum fm10k_self_test_types { ...@@ -117,9 +120,9 @@ enum fm10k_self_test_types {
FM10K_TEST_MAX = FM10K_TEST_LEN FM10K_TEST_MAX = FM10K_TEST_LEN
}; };
static void fm10k_get_strings(struct net_device *dev, u32 stringset, static void fm10k_get_strings(struct net_device *dev, u32 stringset, u8 *data)
u8 *data)
{ {
struct fm10k_intfc *interface = netdev_priv(dev);
char *p = (char *)data; char *p = (char *)data;
int i; int i;
...@@ -135,12 +138,19 @@ static void fm10k_get_strings(struct net_device *dev, u32 stringset, ...@@ -135,12 +138,19 @@ static void fm10k_get_strings(struct net_device *dev, u32 stringset,
p += ETH_GSTRING_LEN; p += ETH_GSTRING_LEN;
} }
for (i = 0; i < FM10K_GLOBAL_STATS_LEN; i++) { for (i = 0; i < FM10K_GLOBAL_STATS_LEN; i++) {
memcpy(p, fm10k_gstrings_stats[i].stat_string, memcpy(p, fm10k_gstrings_global_stats[i].stat_string,
ETH_GSTRING_LEN); ETH_GSTRING_LEN);
p += ETH_GSTRING_LEN; p += ETH_GSTRING_LEN;
} }
for (i = 0; i < MAX_QUEUES; i++) { if (interface->hw.mac.type != fm10k_mac_vf)
for (i = 0; i < FM10K_PF_STATS_LEN; i++) {
memcpy(p, fm10k_gstrings_pf_stats[i].stat_string,
ETH_GSTRING_LEN);
p += ETH_GSTRING_LEN;
}
for (i = 0; i < interface->hw.mac.max_queues; i++) {
sprintf(p, "tx_queue_%u_packets", i); sprintf(p, "tx_queue_%u_packets", i);
p += ETH_GSTRING_LEN; p += ETH_GSTRING_LEN;
sprintf(p, "tx_queue_%u_bytes", i); sprintf(p, "tx_queue_%u_bytes", i);
...@@ -156,18 +166,28 @@ static void fm10k_get_strings(struct net_device *dev, u32 stringset, ...@@ -156,18 +166,28 @@ static void fm10k_get_strings(struct net_device *dev, u32 stringset,
static int fm10k_get_sset_count(struct net_device *dev, int sset) static int fm10k_get_sset_count(struct net_device *dev, int sset)
{ {
struct fm10k_intfc *interface = netdev_priv(dev);
struct fm10k_hw *hw = &interface->hw;
int stats_len = FM10K_STATIC_STATS_LEN;
switch (sset) { switch (sset) {
case ETH_SS_TEST: case ETH_SS_TEST:
return FM10K_TEST_LEN; return FM10K_TEST_LEN;
case ETH_SS_STATS: case ETH_SS_STATS:
return FM10K_STATS_LEN; stats_len += FM10K_QUEUE_STATS_LEN(hw->mac.max_queues);
if (hw->mac.type != fm10k_mac_vf)
stats_len += FM10K_PF_STATS_LEN;
return stats_len;
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
} }
static void fm10k_get_ethtool_stats(struct net_device *netdev, static void fm10k_get_ethtool_stats(struct net_device *netdev,
struct ethtool_stats *stats, u64 *data) struct ethtool_stats __always_unused *stats,
u64 *data)
{ {
const int stat_count = sizeof(struct fm10k_queue_stats) / sizeof(u64); const int stat_count = sizeof(struct fm10k_queue_stats) / sizeof(u64);
struct fm10k_intfc *interface = netdev_priv(netdev); struct fm10k_intfc *interface = netdev_priv(netdev);
...@@ -184,12 +204,21 @@ static void fm10k_get_ethtool_stats(struct net_device *netdev, ...@@ -184,12 +204,21 @@ static void fm10k_get_ethtool_stats(struct net_device *netdev,
} }
for (i = 0; i < FM10K_GLOBAL_STATS_LEN; i++) { for (i = 0; i < FM10K_GLOBAL_STATS_LEN; i++) {
p = (char *)interface + fm10k_gstrings_stats[i].stat_offset; p = (char *)interface +
*(data++) = (fm10k_gstrings_stats[i].sizeof_stat == fm10k_gstrings_global_stats[i].stat_offset;
*(data++) = (fm10k_gstrings_global_stats[i].sizeof_stat ==
sizeof(u64)) ? *(u64 *)p : *(u32 *)p; sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
} }
for (i = 0; i < MAX_QUEUES; i++) { if (interface->hw.mac.type != fm10k_mac_vf)
for (i = 0; i < FM10K_PF_STATS_LEN; i++) {
p = (char *)interface +
fm10k_gstrings_pf_stats[i].stat_offset;
*(data++) = (fm10k_gstrings_pf_stats[i].sizeof_stat ==
sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
}
for (i = 0; i < interface->hw.mac.max_queues; i++) {
struct fm10k_ring *ring; struct fm10k_ring *ring;
u64 *queue_stat; u64 *queue_stat;
...@@ -369,7 +398,7 @@ static void fm10k_get_drvinfo(struct net_device *dev, ...@@ -369,7 +398,7 @@ static void fm10k_get_drvinfo(struct net_device *dev,
strncpy(info->bus_info, pci_name(interface->pdev), strncpy(info->bus_info, pci_name(interface->pdev),
sizeof(info->bus_info) - 1); sizeof(info->bus_info) - 1);
info->n_stats = FM10K_STATS_LEN; info->n_stats = fm10k_get_sset_count(dev, ETH_SS_STATS);
info->regdump_len = fm10k_get_regs_len(dev); info->regdump_len = fm10k_get_regs_len(dev);
} }
...@@ -645,7 +674,7 @@ static int fm10k_get_rss_hash_opts(struct fm10k_intfc *interface, ...@@ -645,7 +674,7 @@ static int fm10k_get_rss_hash_opts(struct fm10k_intfc *interface,
} }
static int fm10k_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, static int fm10k_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
u32 *rule_locs) u32 __always_unused *rule_locs)
{ {
struct fm10k_intfc *interface = netdev_priv(dev); struct fm10k_intfc *interface = netdev_priv(dev);
int ret = -EOPNOTSUPP; int ret = -EOPNOTSUPP;
...@@ -851,7 +880,7 @@ static void fm10k_self_test(struct net_device *dev, ...@@ -851,7 +880,7 @@ static void fm10k_self_test(struct net_device *dev,
eth_test->flags |= ETH_TEST_FL_FAILED; eth_test->flags |= ETH_TEST_FL_FAILED;
} }
static u32 fm10k_get_reta_size(struct net_device *netdev) static u32 fm10k_get_reta_size(struct net_device __always_unused *netdev)
{ {
return FM10K_RETA_SIZE * FM10K_RETA_ENTRIES_PER_REG; return FM10K_RETA_SIZE * FM10K_RETA_ENTRIES_PER_REG;
} }
...@@ -911,7 +940,7 @@ static int fm10k_set_reta(struct net_device *netdev, const u32 *indir) ...@@ -911,7 +940,7 @@ static int fm10k_set_reta(struct net_device *netdev, const u32 *indir)
return 0; return 0;
} }
static u32 fm10k_get_rssrk_size(struct net_device *netdev) static u32 fm10k_get_rssrk_size(struct net_device __always_unused *netdev)
{ {
return FM10K_RSSRK_SIZE * FM10K_RSSRK_ENTRIES_PER_REG; return FM10K_RSSRK_SIZE * FM10K_RSSRK_ENTRIES_PER_REG;
} }
......
/* Intel Ethernet Switch Host Interface Driver /* Intel Ethernet Switch Host Interface Driver
* Copyright(c) 2013 - 2014 Intel Corporation. * Copyright(c) 2013 - 2015 Intel Corporation.
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
...@@ -47,7 +47,7 @@ s32 fm10k_iov_event(struct fm10k_intfc *interface) ...@@ -47,7 +47,7 @@ s32 fm10k_iov_event(struct fm10k_intfc *interface)
{ {
struct fm10k_hw *hw = &interface->hw; struct fm10k_hw *hw = &interface->hw;
struct fm10k_iov_data *iov_data; struct fm10k_iov_data *iov_data;
s64 mbicr, vflre; s64 vflre;
int i; int i;
/* if there is no iov_data then there is no mailboxes to process */ /* if there is no iov_data then there is no mailboxes to process */
...@@ -63,7 +63,7 @@ s32 fm10k_iov_event(struct fm10k_intfc *interface) ...@@ -63,7 +63,7 @@ s32 fm10k_iov_event(struct fm10k_intfc *interface)
goto read_unlock; goto read_unlock;
if (!(fm10k_read_reg(hw, FM10K_EICR) & FM10K_EICR_VFLR)) if (!(fm10k_read_reg(hw, FM10K_EICR) & FM10K_EICR_VFLR))
goto process_mbx; goto read_unlock;
/* read VFLRE to determine if any VFs have been reset */ /* read VFLRE to determine if any VFs have been reset */
do { do {
...@@ -86,32 +86,6 @@ s32 fm10k_iov_event(struct fm10k_intfc *interface) ...@@ -86,32 +86,6 @@ s32 fm10k_iov_event(struct fm10k_intfc *interface)
} }
} while (i != iov_data->num_vfs); } while (i != iov_data->num_vfs);
process_mbx:
/* read MBICR to determine which VFs require attention */
mbicr = fm10k_read_reg(hw, FM10K_MBICR(1));
mbicr <<= 32;
mbicr |= fm10k_read_reg(hw, FM10K_MBICR(0));
i = iov_data->next_vf_mbx ? : iov_data->num_vfs;
for (mbicr <<= 64 - i; i--; mbicr += mbicr) {
struct fm10k_mbx_info *mbx = &iov_data->vf_info[i].mbx;
if (mbicr >= 0)
continue;
if (!hw->mbx.ops.tx_ready(&hw->mbx, FM10K_VFMBX_MSG_MTU))
break;
mbx->ops.process(hw, mbx);
}
if (i >= 0) {
iov_data->next_vf_mbx = i + 1;
} else if (iov_data->next_vf_mbx) {
iov_data->next_vf_mbx = 0;
goto process_mbx;
}
read_unlock: read_unlock:
rcu_read_unlock(); rcu_read_unlock();
...@@ -139,6 +113,13 @@ s32 fm10k_iov_mbx(struct fm10k_intfc *interface) ...@@ -139,6 +113,13 @@ s32 fm10k_iov_mbx(struct fm10k_intfc *interface)
/* lock the mailbox for transmit and receive */ /* lock the mailbox for transmit and receive */
fm10k_mbx_lock(interface); fm10k_mbx_lock(interface);
/* Most VF messages sent to the PF cause the PF to respond by
* requesting from the SM mailbox. This means that too many VF
* messages processed at once could cause a mailbox timeout on the PF.
* To prevent this, store a pointer to the next VF mbx to process. Use
* that as the start of the loop so that we don't starve whichever VF
* got ignored on the previous run.
*/
process_mbx: process_mbx:
for (i = iov_data->next_vf_mbx ? : iov_data->num_vfs; i--;) { for (i = iov_data->next_vf_mbx ? : iov_data->num_vfs; i--;) {
struct fm10k_vf_info *vf_info = &iov_data->vf_info[i]; struct fm10k_vf_info *vf_info = &iov_data->vf_info[i];
...@@ -155,10 +136,6 @@ process_mbx: ...@@ -155,10 +136,6 @@ process_mbx:
mbx->ops.connect(hw, mbx); mbx->ops.connect(hw, mbx);
} }
/* no work pending, then just continue */
if (mbx->ops.tx_complete(mbx) && !mbx->ops.rx_ready(mbx))
continue;
/* guarantee we have free space in the SM mailbox */ /* guarantee we have free space in the SM mailbox */
if (!hw->mbx.ops.tx_ready(&hw->mbx, FM10K_VFMBX_MSG_MTU)) if (!hw->mbx.ops.tx_ready(&hw->mbx, FM10K_VFMBX_MSG_MTU))
break; break;
...@@ -167,6 +144,10 @@ process_mbx: ...@@ -167,6 +144,10 @@ process_mbx:
mbx->ops.process(hw, mbx); mbx->ops.process(hw, mbx);
} }
/* if we stopped processing mailboxes early, update next_vf_mbx.
* Otherwise, reset next_vf_mbx, and restart loop so that we process
* the remaining mailboxes we skipped at the start.
*/
if (i >= 0) { if (i >= 0) {
iov_data->next_vf_mbx = i + 1; iov_data->next_vf_mbx = i + 1;
} else if (iov_data->next_vf_mbx) { } else if (iov_data->next_vf_mbx) {
...@@ -488,8 +469,8 @@ int fm10k_ndo_set_vf_vlan(struct net_device *netdev, int vf_idx, u16 vid, ...@@ -488,8 +469,8 @@ int fm10k_ndo_set_vf_vlan(struct net_device *netdev, int vf_idx, u16 vid,
return 0; return 0;
} }
int fm10k_ndo_set_vf_bw(struct net_device *netdev, int vf_idx, int unused, int fm10k_ndo_set_vf_bw(struct net_device *netdev, int vf_idx,
int rate) int __always_unused unused, int rate)
{ {
struct fm10k_intfc *interface = netdev_priv(netdev); struct fm10k_intfc *interface = netdev_priv(netdev);
struct fm10k_iov_data *iov_data = interface->iov_data; struct fm10k_iov_data *iov_data = interface->iov_data;
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
#include "fm10k.h" #include "fm10k.h"
#define DRV_VERSION "0.12.2-k" #define DRV_VERSION "0.15.2-k"
const char fm10k_driver_version[] = DRV_VERSION; const char fm10k_driver_version[] = DRV_VERSION;
char fm10k_driver_name[] = "fm10k"; char fm10k_driver_name[] = "fm10k";
static const char fm10k_driver_string[] = static const char fm10k_driver_string[] =
...@@ -41,6 +41,9 @@ MODULE_DESCRIPTION("Intel(R) Ethernet Switch Host Interface Driver"); ...@@ -41,6 +41,9 @@ MODULE_DESCRIPTION("Intel(R) Ethernet Switch Host Interface Driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION); MODULE_VERSION(DRV_VERSION);
/* single workqueue for entire fm10k driver */
struct workqueue_struct *fm10k_workqueue = NULL;
/** /**
* fm10k_init_module - Driver Registration Routine * fm10k_init_module - Driver Registration Routine
* *
...@@ -52,6 +55,10 @@ static int __init fm10k_init_module(void) ...@@ -52,6 +55,10 @@ static int __init fm10k_init_module(void)
pr_info("%s - version %s\n", fm10k_driver_string, fm10k_driver_version); pr_info("%s - version %s\n", fm10k_driver_string, fm10k_driver_version);
pr_info("%s\n", fm10k_copyright); pr_info("%s\n", fm10k_copyright);
/* create driver workqueue */
if (!fm10k_workqueue)
fm10k_workqueue = create_workqueue("fm10k");
fm10k_dbg_init(); fm10k_dbg_init();
return fm10k_register_pci_driver(); return fm10k_register_pci_driver();
...@@ -69,6 +76,11 @@ static void __exit fm10k_exit_module(void) ...@@ -69,6 +76,11 @@ static void __exit fm10k_exit_module(void)
fm10k_unregister_pci_driver(); fm10k_unregister_pci_driver();
fm10k_dbg_exit(); fm10k_dbg_exit();
/* destroy driver workqueue */
flush_workqueue(fm10k_workqueue);
destroy_workqueue(fm10k_workqueue);