diff options
-rw-r--r-- | drivers/net/ethernet/intel/fm10k/fm10k.h | 9 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/fm10k/fm10k_dcbnl.c | 6 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/fm10k/fm10k_debugfs.c | 8 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c | 93 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/fm10k/fm10k_iov.c | 51 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/fm10k/fm10k_main.c | 33 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/fm10k/fm10k_mbx.c | 34 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/fm10k/fm10k_netdev.c | 37 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/fm10k/fm10k_pci.c | 61 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/fm10k/fm10k_pf.c | 10 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/fm10k/fm10k_ptp.c | 5 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/fm10k/fm10k_vf.c | 6 |
12 files changed, 215 insertions, 138 deletions
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k.h b/drivers/net/ethernet/intel/fm10k/fm10k.h index 59edfd4446cd..c8c8c5baefda 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k.h +++ b/drivers/net/ethernet/intel/fm10k/fm10k.h @@ -1,5 +1,5 @@ /* 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 * under the terms and conditions of the GNU General Public License, @@ -235,6 +235,9 @@ struct fm10k_vxlan_port { __be16 port; }; +/* one work queue for entire driver */ +extern struct workqueue_struct *fm10k_workqueue; + struct fm10k_intfc { unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)]; struct net_device *netdev; @@ -266,7 +269,6 @@ struct fm10k_intfc { u64 tx_csum_errors; u64 alloc_failed; u64 rx_csum_errors; - u64 rx_errors; u64 tx_bytes_nic; u64 tx_packets_nic; @@ -458,6 +460,9 @@ void fm10k_down(struct fm10k_intfc *interface); void fm10k_update_stats(struct fm10k_intfc *interface); void fm10k_service_event_schedule(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 */ struct net_device *fm10k_alloc_netdev(void); diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_dcbnl.c b/drivers/net/ethernet/intel/fm10k/fm10k_dcbnl.c index 212a92dad222..5c7a4d7662d8 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_dcbnl.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_dcbnl.c @@ -1,5 +1,5 @@ /* 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 * 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) * * 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; } @@ -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 **/ -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; } diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_debugfs.c b/drivers/net/ethernet/intel/fm10k/fm10k_debugfs.c index 4327f86218b9..f45b4d71adb8 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_debugfs.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_debugfs.c @@ -1,5 +1,5 @@ /* 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 * 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) 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; 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. */ } diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c b/drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c index 33b6106c764b..4b9d9f88af70 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c @@ -1,5 +1,5 @@ /* 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 * under the terms and conditions of the GNU General Public License, @@ -57,13 +57,12 @@ static const struct fm10k_stats fm10k_gstrings_net_stats[] = { .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_busy", tx_busy), FM10K_STAT("tx_csum_errors", tx_csum_errors), FM10K_STAT("rx_alloc_failed", alloc_failed), 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_bytes_nic", tx_bytes_nic), @@ -73,38 +72,42 @@ static const struct fm10k_stats fm10k_gstrings_stats[] = { FM10K_STAT("rx_overrun_pf", rx_overrun_pf), 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("mac_rules_used", hw.swapi.mac.used), FM10K_STAT("mac_rules_avail", hw.swapi.mac.avail), 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_dwords", hw.mbx.tx_dwords), FM10K_STAT("mbx_rx_messages", hw.mbx.rx_messages), FM10K_STAT("mbx_rx_dwords", hw.mbx.rx_dwords), 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), }; -#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 \ - (MAX_QUEUES * 2 * (sizeof(struct fm10k_queue_stats) / sizeof(u64))) +#define FM10K_QUEUE_STATS_LEN(_n) \ + ( (_n) * 2 * (sizeof(struct fm10k_queue_stats) / sizeof(u64))) -#define FM10K_STATS_LEN (FM10K_GLOBAL_STATS_LEN + \ - FM10K_NETDEV_STATS_LEN + \ - FM10K_QUEUE_STATS_LEN) +#define FM10K_STATIC_STATS_LEN (FM10K_GLOBAL_STATS_LEN + \ + FM10K_NETDEV_STATS_LEN) static const char fm10k_gstrings_test[][ETH_GSTRING_LEN] = { "Mailbox test (on/offline)" @@ -117,9 +120,9 @@ enum fm10k_self_test_types { FM10K_TEST_MAX = FM10K_TEST_LEN }; -static void fm10k_get_strings(struct net_device *dev, u32 stringset, - u8 *data) +static void fm10k_get_strings(struct net_device *dev, u32 stringset, u8 *data) { + struct fm10k_intfc *interface = netdev_priv(dev); char *p = (char *)data; int i; @@ -135,12 +138,19 @@ static void fm10k_get_strings(struct net_device *dev, u32 stringset, p += ETH_GSTRING_LEN; } 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); 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); p += ETH_GSTRING_LEN; sprintf(p, "tx_queue_%u_bytes", i); @@ -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) { + struct fm10k_intfc *interface = netdev_priv(dev); + struct fm10k_hw *hw = &interface->hw; + int stats_len = FM10K_STATIC_STATS_LEN; + switch (sset) { case ETH_SS_TEST: return FM10K_TEST_LEN; 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: return -EOPNOTSUPP; } } 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); struct fm10k_intfc *interface = netdev_priv(netdev); @@ -184,12 +204,21 @@ static void fm10k_get_ethtool_stats(struct net_device *netdev, } for (i = 0; i < FM10K_GLOBAL_STATS_LEN; i++) { - p = (char *)interface + fm10k_gstrings_stats[i].stat_offset; - *(data++) = (fm10k_gstrings_stats[i].sizeof_stat == + p = (char *)interface + + fm10k_gstrings_global_stats[i].stat_offset; + *(data++) = (fm10k_gstrings_global_stats[i].sizeof_stat == 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; u64 *queue_stat; @@ -369,7 +398,7 @@ static void fm10k_get_drvinfo(struct net_device *dev, strncpy(info->bus_info, pci_name(interface->pdev), 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); } @@ -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, - u32 *rule_locs) + u32 __always_unused *rule_locs) { struct fm10k_intfc *interface = netdev_priv(dev); int ret = -EOPNOTSUPP; @@ -851,7 +880,7 @@ static void fm10k_self_test(struct net_device *dev, 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; } @@ -911,7 +940,7 @@ static int fm10k_set_reta(struct net_device *netdev, const u32 *indir) 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; } diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_iov.c b/drivers/net/ethernet/intel/fm10k/fm10k_iov.c index a02308f5048f..5b08e6284a3c 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_iov.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_iov.c @@ -1,5 +1,5 @@ /* 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 * under the terms and conditions of the GNU General Public License, @@ -47,7 +47,7 @@ s32 fm10k_iov_event(struct fm10k_intfc *interface) { struct fm10k_hw *hw = &interface->hw; struct fm10k_iov_data *iov_data; - s64 mbicr, vflre; + s64 vflre; int i; /* 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) goto read_unlock; 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 */ do { @@ -86,32 +86,6 @@ s32 fm10k_iov_event(struct fm10k_intfc *interface) } } 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: rcu_read_unlock(); @@ -139,6 +113,13 @@ s32 fm10k_iov_mbx(struct fm10k_intfc *interface) /* lock the mailbox for transmit and receive */ 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: for (i = iov_data->next_vf_mbx ? : iov_data->num_vfs; i--;) { struct fm10k_vf_info *vf_info = &iov_data->vf_info[i]; @@ -155,10 +136,6 @@ process_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 */ if (!hw->mbx.ops.tx_ready(&hw->mbx, FM10K_VFMBX_MSG_MTU)) break; @@ -167,6 +144,10 @@ process_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) { iov_data->next_vf_mbx = i + 1; } 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, return 0; } -int fm10k_ndo_set_vf_bw(struct net_device *netdev, int vf_idx, int unused, - int rate) +int fm10k_ndo_set_vf_bw(struct net_device *netdev, int vf_idx, + int __always_unused unused, int rate) { struct fm10k_intfc *interface = netdev_priv(netdev); struct fm10k_iov_data *iov_data = interface->iov_data; diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_main.c b/drivers/net/ethernet/intel/fm10k/fm10k_main.c index c325bc0c8338..1b0661e3573b 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_main.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_main.c @@ -28,7 +28,7 @@ #include "fm10k.h" -#define DRV_VERSION "0.12.2-k" +#define DRV_VERSION "0.15.2-k" const char fm10k_driver_version[] = DRV_VERSION; char fm10k_driver_name[] = "fm10k"; static const char fm10k_driver_string[] = @@ -41,6 +41,9 @@ MODULE_DESCRIPTION("Intel(R) Ethernet Switch Host Interface Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); +/* single workqueue for entire fm10k driver */ +struct workqueue_struct *fm10k_workqueue = NULL; + /** * fm10k_init_module - Driver Registration Routine * @@ -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\n", fm10k_copyright); + /* create driver workqueue */ + if (!fm10k_workqueue) + fm10k_workqueue = create_workqueue("fm10k"); + fm10k_dbg_init(); return fm10k_register_pci_driver(); @@ -69,6 +76,11 @@ static void __exit fm10k_exit_module(void) fm10k_unregister_pci_driver(); fm10k_dbg_exit(); + + /* destroy driver workqueue */ + flush_workqueue(fm10k_workqueue); + destroy_workqueue(fm10k_workqueue); + fm10k_workqueue = NULL; } module_exit(fm10k_exit_module); @@ -209,7 +221,7 @@ static inline bool fm10k_page_is_reserved(struct page *page) static bool fm10k_can_reuse_rx_page(struct fm10k_rx_buffer *rx_buffer, struct page *page, - unsigned int truesize) + unsigned int __maybe_unused truesize) { /* avoid re-using remote pages */ if (unlikely(fm10k_page_is_reserved(page))) @@ -240,7 +252,6 @@ static bool fm10k_can_reuse_rx_page(struct fm10k_rx_buffer *rx_buffer, /** * fm10k_add_rx_frag - Add contents of Rx buffer to sk_buff - * @rx_ring: rx descriptor ring to transact packets on * @rx_buffer: buffer containing page to add * @rx_desc: descriptor containing length of buffer written by hardware * @skb: sk_buff to place the data into @@ -253,8 +264,7 @@ static bool fm10k_can_reuse_rx_page(struct fm10k_rx_buffer *rx_buffer, * The function will then update the page offset if necessary and return * true if the buffer can be reused by the interface. **/ -static bool fm10k_add_rx_frag(struct fm10k_ring *rx_ring, - struct fm10k_rx_buffer *rx_buffer, +static bool fm10k_add_rx_frag(struct fm10k_rx_buffer *rx_buffer, union fm10k_rx_desc *rx_desc, struct sk_buff *skb) { @@ -330,7 +340,7 @@ static struct sk_buff *fm10k_fetch_rx_buffer(struct fm10k_ring *rx_ring, DMA_FROM_DEVICE); /* pull page into skb */ - if (fm10k_add_rx_frag(rx_ring, rx_buffer, rx_desc, skb)) { + if (fm10k_add_rx_frag(rx_buffer, rx_desc, skb)) { /* hand second half of page back to the ring */ fm10k_reuse_rx_page(rx_ring, rx_buffer); } else { @@ -412,7 +422,7 @@ static void fm10k_rx_hwtstamp(struct fm10k_ring *rx_ring, } static void fm10k_type_trans(struct fm10k_ring *rx_ring, - union fm10k_rx_desc *rx_desc, + union fm10k_rx_desc __maybe_unused *rx_desc, struct sk_buff *skb) { struct net_device *dev = rx_ring->netdev; @@ -509,8 +519,6 @@ static bool fm10k_is_non_eop(struct fm10k_ring *rx_ring, /** * fm10k_pull_tail - fm10k specific version of skb_pull_tail - * @rx_ring: rx descriptor ring packet is being transacted on - * @rx_desc: pointer to the EOP Rx descriptor * @skb: pointer to current skb being adjusted * * This function is an fm10k specific version of __pskb_pull_tail. The @@ -520,9 +528,7 @@ static bool fm10k_is_non_eop(struct fm10k_ring *rx_ring, * As a result we can do things like drop a frag and maintain an accurate * truesize for the skb. */ -static void fm10k_pull_tail(struct fm10k_ring *rx_ring, - union fm10k_rx_desc *rx_desc, - struct sk_buff *skb) +static void fm10k_pull_tail(struct sk_buff *skb) { struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[0]; unsigned char *va; @@ -576,7 +582,7 @@ static bool fm10k_cleanup_headers(struct fm10k_ring *rx_ring, /* place header in linear portion of buffer */ if (skb_is_nonlinear(skb)) - fm10k_pull_tail(rx_ring, rx_desc, skb); + fm10k_pull_tail(skb); /* if eth_skb_pad returns an error the skb was freed */ if (eth_skb_pad(skb)) @@ -1197,7 +1203,6 @@ void fm10k_tx_timeout_reset(struct fm10k_intfc *interface) { /* Do the reset outside of interrupt context */ if (!test_bit(__FM10K_DOWN, &interface->state)) { - netdev_err(interface->netdev, "Reset interface\n"); interface->tx_timeout_count++; interface->flags |= FM10K_FLAG_RESET_REQUESTED; fm10k_service_event_schedule(interface); diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_mbx.c b/drivers/net/ethernet/intel/fm10k/fm10k_mbx.c index 14ee696e9830..1b2738380518 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_mbx.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_mbx.c @@ -1,5 +1,5 @@ /* 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 * under the terms and conditions of the GNU General Public License, @@ -126,6 +126,18 @@ static u16 fm10k_fifo_head_drop(struct fm10k_mbx_fifo *fifo) } /** + * fm10k_fifo_drop_all - Drop all messages in FIFO + * @fifo: pointer to FIFO + * + * This function resets the head pointer to drop all messages in the FIFO, + * and ensure the FIFO is empty. + **/ +static void fm10k_fifo_drop_all(struct fm10k_mbx_fifo *fifo) +{ + fifo->head = fifo->tail; +} + +/** * fm10k_mbx_index_len - Convert a head/tail index into a length value * @mbx: pointer to mailbox * @head: head index @@ -315,7 +327,7 @@ static u16 fm10k_mbx_validate_msg_size(struct fm10k_mbx_info *mbx, u16 len) } while (total_len < len); /* message extends out of pushed section, but fits in FIFO */ - if ((len < total_len) && (msg_len <= mbx->rx.size)) + if ((len < total_len) && (msg_len <= mbx->max_size)) return 0; /* return length of invalid section */ @@ -326,8 +338,7 @@ static u16 fm10k_mbx_validate_msg_size(struct fm10k_mbx_info *mbx, u16 len) * fm10k_mbx_write_copy - pulls data off of Tx FIFO and places it in mbmem * @mbx: pointer to mailbox * - * This function will take a section of the Rx FIFO and copy it into the - mbx->tail--; + * This function will take a section of the Tx FIFO and copy it into the * mailbox memory. The offset in mbmem is based on the lower bits of the * tail and len determines the length to copy. **/ @@ -818,7 +829,7 @@ static void fm10k_mbx_write(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx) /* write new msg header to notify recipient of change */ fm10k_write_reg(hw, mbmem, mbx->mbx_hdr); - /* write mailbox to sent interrupt */ + /* write mailbox to send interrupt */ if (mbx->mbx_lock) fm10k_write_reg(hw, mbx->mbx_reg, mbx->mbx_lock); @@ -1052,8 +1063,11 @@ static void fm10k_mbx_reset_work(struct fm10k_mbx_info *mbx) * @mbx: pointer to mailbox * @size: new value for max_size * - * This function will update the max_size value and drop any outgoing messages - * from the head of the Tx FIFO that are larger than max_size. + * This function updates the max_size value and drops any outgoing messages + * at the head of the Tx FIFO if they are larger than max_size. It does not + * drop all messages, as this is too difficult to parse and remove them from + * the FIFO. Instead, rely on the checking to ensure that messages larger + * than max_size aren't pushed into the memory buffer. **/ static void fm10k_mbx_update_max_size(struct fm10k_mbx_info *mbx, u16 size) { @@ -1371,9 +1385,11 @@ static void fm10k_mbx_disconnect(struct fm10k_hw *hw, timeout -= FM10K_MBX_POLL_DELAY; } while ((timeout > 0) && (mbx->state != FM10K_STATE_CLOSED)); - /* in case we didn't close just force the mailbox into shutdown */ + /* in case we didn't close, just force the mailbox into shutdown and + * drop all left over messages in the FIFO. + */ fm10k_mbx_connect_reset(mbx); - fm10k_mbx_update_max_size(mbx, 0); + fm10k_fifo_drop_all(&mbx->tx); fm10k_write_reg(hw, mbx->mbmem_reg, 0); } diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c index d5b303dad95e..2f4f41b7eae7 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c @@ -1,5 +1,5 @@ /* 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 * under the terms and conditions of the GNU General Public License, @@ -770,15 +770,15 @@ static int fm10k_update_vid(struct net_device *netdev, u16 vid, bool set) if (hw->mac.vlan_override) return -EACCES; - /* if default VLAN is already present do nothing */ - if (vid == hw->mac.default_vid) - return -EBUSY; - /* update active_vlans bitmask */ set_bit(vid, interface->active_vlans); if (!set) clear_bit(vid, interface->active_vlans); + /* if default VLAN is already present do nothing */ + if (vid == hw->mac.default_vid) + return 0; + fm10k_mbx_lock(interface); /* only need to update the VLAN if not in promiscuous mode */ @@ -970,14 +970,7 @@ static void fm10k_set_rx_mode(struct net_device *dev) fm10k_mbx_lock(interface); - /* synchronize all of the addresses */ - if (xcast_mode != FM10K_XCAST_MODE_PROMISC) { - __dev_uc_sync(dev, fm10k_uc_sync, fm10k_uc_unsync); - if (xcast_mode != FM10K_XCAST_MODE_ALLMULTI) - __dev_mc_sync(dev, fm10k_mc_sync, fm10k_mc_unsync); - } - - /* if we aren't changing modes there is nothing to do */ + /* update xcast mode first, but only if it changed */ if (interface->xcast_mode != xcast_mode) { /* update VLAN table */ if (xcast_mode == FM10K_XCAST_MODE_PROMISC) @@ -992,6 +985,13 @@ static void fm10k_set_rx_mode(struct net_device *dev) interface->xcast_mode = xcast_mode; } + /* synchronize all of the addresses */ + if (xcast_mode != FM10K_XCAST_MODE_PROMISC) { + __dev_uc_sync(dev, fm10k_uc_sync, fm10k_uc_unsync); + if (xcast_mode != FM10K_XCAST_MODE_ALLMULTI) + __dev_mc_sync(dev, fm10k_mc_sync, fm10k_mc_unsync); + } + fm10k_mbx_unlock(interface); } @@ -1051,6 +1051,9 @@ void fm10k_restore_rx_state(struct fm10k_intfc *interface) vid, true, 0); } + /* update xcast mode before syncronizing addresses */ + hw->mac.ops.update_xcast_mode(hw, glort, xcast_mode); + /* synchronize all of the addresses */ if (xcast_mode != FM10K_XCAST_MODE_PROMISC) { __dev_uc_sync(netdev, fm10k_uc_sync, fm10k_uc_unsync); @@ -1058,9 +1061,6 @@ void fm10k_restore_rx_state(struct fm10k_intfc *interface) __dev_mc_sync(netdev, fm10k_mc_sync, fm10k_mc_unsync); } - /* update xcast mode */ - hw->mac.ops.update_xcast_mode(hw, glort, xcast_mode); - fm10k_mbx_unlock(interface); /* record updated xcast mode state */ @@ -1126,7 +1126,7 @@ static struct rtnl_link_stats64 *fm10k_get_stats64(struct net_device *netdev, } for (i = 0; i < interface->num_tx_queues; i++) { - ring = ACCESS_ONCE(interface->rx_ring[i]); + ring = ACCESS_ONCE(interface->tx_ring[i]); if (!ring) continue; @@ -1382,6 +1382,9 @@ static const struct net_device_ops fm10k_netdev_ops = { .ndo_do_ioctl = fm10k_ioctl, .ndo_dfwd_add_station = fm10k_dfwd_add_station, .ndo_dfwd_del_station = fm10k_dfwd_del_station, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = fm10k_netpoll, +#endif .ndo_features_check = fm10k_features_check, }; diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_pci.c b/drivers/net/ethernet/intel/fm10k/fm10k_pci.c index 8978d55a1c51..df9fda38bdd1 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_pci.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_pci.c @@ -1,5 +1,5 @@ /* 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 * under the terms and conditions of the GNU General Public License, @@ -94,7 +94,7 @@ void fm10k_service_event_schedule(struct fm10k_intfc *interface) { if (!test_bit(__FM10K_SERVICE_DISABLE, &interface->state) && !test_and_set_bit(__FM10K_SERVICE_SCHED, &interface->state)) - schedule_work(&interface->service_task); + queue_work(fm10k_workqueue, &interface->service_task); } static void fm10k_service_event_complete(struct fm10k_intfc *interface) @@ -191,7 +191,6 @@ static void fm10k_reset_subtask(struct fm10k_intfc *interface) interface->flags &= ~FM10K_FLAG_RESET_REQUESTED; netdev_err(interface->netdev, "Reset interface\n"); - interface->tx_timeout_count++; fm10k_reinit(interface); } @@ -357,11 +356,10 @@ void fm10k_update_stats(struct fm10k_intfc *interface) net_stats->rx_packets = pkts; interface->alloc_failed = alloc_failed; interface->rx_csum_errors = rx_csum_errors; - interface->rx_errors = rx_errors; hw->mac.ops.update_hw_stats(hw, &interface->stats); - for (i = 0; i < FM10K_MAX_QUEUES_PF; i++) { + for (i = 0; i < hw->mac.max_queues; i++) { struct fm10k_hw_stats_q *q = &interface->stats.q[i]; tx_bytes_nic += q->tx_bytes.count; @@ -378,7 +376,7 @@ void fm10k_update_stats(struct fm10k_intfc *interface) interface->rx_drops_nic = rx_drops_nic; /* Fill out the OS statistics structure */ - net_stats->rx_errors = interface->stats.xec.count; + net_stats->rx_errors = rx_errors; net_stats->rx_dropped = interface->stats.nodesc_drop.count; } @@ -808,7 +806,7 @@ static void fm10k_napi_enable_all(struct fm10k_intfc *interface) } } -static irqreturn_t fm10k_msix_clean_rings(int irq, void *data) +static irqreturn_t fm10k_msix_clean_rings(int __always_unused irq, void *data) { struct fm10k_q_vector *q_vector = data; @@ -818,7 +816,7 @@ static irqreturn_t fm10k_msix_clean_rings(int irq, void *data) return IRQ_HANDLED; } -static irqreturn_t fm10k_msix_mbx_vf(int irq, void *data) +static irqreturn_t fm10k_msix_mbx_vf(int __always_unused irq, void *data) { struct fm10k_intfc *interface = data; struct fm10k_hw *hw = &interface->hw; @@ -840,6 +838,28 @@ static irqreturn_t fm10k_msix_mbx_vf(int irq, void *data) return IRQ_HANDLED; } +#ifdef CONFIG_NET_POLL_CONTROLLER +/** + * fm10k_netpoll - A Polling 'interrupt' handler + * @netdev: network interface device structure + * + * This is used by netconsole to send skbs without having to re-enable + * interrupts. It's not called while the normal interrupt routine is executing. + **/ +void fm10k_netpoll(struct net_device *netdev) +{ + struct fm10k_intfc *interface = netdev_priv(netdev); + int i; + + /* if interface is down do nothing */ + if (test_bit(__FM10K_DOWN, &interface->state)) + return; + + for (i = 0; i < interface->num_q_vectors; i++) + fm10k_msix_clean_rings(0, interface->q_vector[i]); +} + +#endif #define FM10K_ERR_MSG(type) case (type): error = #type; break static void fm10k_print_fault(struct fm10k_intfc *interface, int type, struct fm10k_fault *fault) @@ -964,7 +984,7 @@ static void fm10k_reset_drop_on_empty(struct fm10k_intfc *interface, u32 eicr) } } -static irqreturn_t fm10k_msix_mbx_pf(int irq, void *data) +static irqreturn_t fm10k_msix_mbx_pf(int __always_unused irq, void *data) { struct fm10k_intfc *interface = data; struct fm10k_hw *hw = &interface->hw; @@ -986,6 +1006,7 @@ static irqreturn_t fm10k_msix_mbx_pf(int irq, void *data) /* service mailboxes */ if (fm10k_mbx_trylock(interface)) { mbx->ops.process(hw, mbx); + /* handle VFLRE events */ fm10k_iov_event(interface); fm10k_mbx_unlock(interface); } @@ -1002,6 +1023,8 @@ static irqreturn_t fm10k_msix_mbx_pf(int irq, void *data) /* we should validate host state after interrupt event */ hw->mac.get_host_state = 1; + + /* validate host state, and handle VF mailboxes in the service task */ fm10k_service_event_schedule(interface); /* re-enable mailbox interrupt and indicate 20us delay */ @@ -1069,7 +1092,7 @@ static s32 fm10k_mbx_mac_addr(struct fm10k_hw *hw, u32 **results, } static s32 fm10k_1588_msg_vf(struct fm10k_hw *hw, u32 **results, - struct fm10k_mbx_info *mbx) + struct fm10k_mbx_info __always_unused *mbx) { struct fm10k_intfc *interface; u64 timestamp; @@ -1089,7 +1112,7 @@ static s32 fm10k_1588_msg_vf(struct fm10k_hw *hw, u32 **results, /* generic error handler for mailbox issues */ static s32 fm10k_mbx_error(struct fm10k_hw *hw, u32 **results, - struct fm10k_mbx_info *mbx) + struct fm10k_mbx_info __always_unused *mbx) { struct fm10k_intfc *interface; struct pci_dev *pdev; @@ -1165,7 +1188,7 @@ static s32 fm10k_lport_map(struct fm10k_hw *hw, u32 **results, } static s32 fm10k_update_pvid(struct fm10k_hw *hw, u32 **results, - struct fm10k_mbx_info *mbx) + struct fm10k_mbx_info __always_unused *mbx) { struct fm10k_intfc *interface; u16 glort, pvid; @@ -1206,7 +1229,7 @@ static s32 fm10k_update_pvid(struct fm10k_hw *hw, u32 **results, } static s32 fm10k_1588_msg_pf(struct fm10k_hw *hw, u32 **results, - struct fm10k_mbx_info *mbx) + struct fm10k_mbx_info __always_unused *mbx) { struct fm10k_swapi_1588_timestamp timestamp; struct fm10k_iov_data *iov_data; @@ -1488,7 +1511,7 @@ void fm10k_up(struct fm10k_intfc *interface) /* enable transmits */ netif_tx_start_all_queues(interface->netdev); - /* kick off the service timer */ + /* kick off the service timer now */ hw->mac.get_host_state = 1; mod_timer(&interface->service_timer, jiffies); } @@ -1528,8 +1551,6 @@ void fm10k_down(struct fm10k_intfc *interface) /* disable polling routines */ fm10k_napi_disable_all(interface); - del_timer_sync(&interface->service_timer); - /* capture stats one last time before stopping interface */ fm10k_update_stats(interface); @@ -1655,6 +1676,9 @@ static int fm10k_sw_init(struct fm10k_intfc *interface, (unsigned long)interface); INIT_WORK(&interface->service_task, fm10k_service_task); + /* kick off service timer now, even when interface is down */ + mod_timer(&interface->service_timer, (HZ * 2) + jiffies); + /* Intitialize timestamp data */ fm10k_ts_init(interface); @@ -1871,6 +1895,8 @@ static void fm10k_remove(struct pci_dev *pdev) struct fm10k_intfc *interface = pci_get_drvdata(pdev); struct net_device *netdev = interface->netdev; + del_timer_sync(&interface->service_timer); + set_bit(__FM10K_SERVICE_DISABLE, &interface->state); cancel_work_sync(&interface->service_task); @@ -1984,7 +2010,8 @@ static int fm10k_resume(struct pci_dev *pdev) * a sleep state. The fm10k hardware does not support wake on lan so the * driver simply needs to shut down the device so it is in a low power state. **/ -static int fm10k_suspend(struct pci_dev *pdev, pm_message_t state) +static int fm10k_suspend(struct pci_dev *pdev, + pm_message_t __always_unused state) { struct fm10k_intfc *interface = pci_get_drvdata(pdev); struct net_device *netdev = interface->netdev; diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_pf.c b/drivers/net/ethernet/intel/fm10k/fm10k_pf.c index 159cd8463800..891e21874b2a 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_pf.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_pf.c @@ -329,6 +329,9 @@ static s32 fm10k_update_xc_addr_pf(struct fm10k_hw *hw, u16 glort, struct fm10k_mac_update mac_update; u32 msg[5]; + /* clear set bit from VLAN ID */ + vid &= ~FM10K_VLAN_CLEAR; + /* if glort or vlan are not valid return error */ if (!fm10k_glort_valid_pf(hw, glort) || vid >= FM10K_VLAN_TABLE_VID_MAX) return FM10K_ERR_PARAM; @@ -676,7 +679,8 @@ static s32 fm10k_iov_assign_resources_pf(struct fm10k_hw *hw, u16 num_vfs, /* loop through unallocated rings assigning them back to PF */ for (i = FM10K_MAX_QUEUES_PF; i < vf_q_idx; i++) { fm10k_write_reg(hw, FM10K_TXDCTL(i), 0); - fm10k_write_reg(hw, FM10K_TXQCTL(i), FM10K_TXQCTL_PF | vid); + fm10k_write_reg(hw, FM10K_TXQCTL(i), FM10K_TXQCTL_PF | + FM10K_TXQCTL_UNLIMITED_BW | vid); fm10k_write_reg(hw, FM10K_RXQCTL(i), FM10K_RXQCTL_PF); } @@ -1249,8 +1253,8 @@ s32 fm10k_iov_msg_mac_vlan_pf(struct fm10k_hw *hw, u32 **results, } /* notify switch of request for new multicast address */ - err = hw->mac.ops.update_mc_addr(hw, vf_info->glort, mac, - !(vlan & FM10K_VLAN_CLEAR), 0); + err = hw->mac.ops.update_mc_addr(hw, vf_info->glort, mac, vlan, + !(vlan & FM10K_VLAN_CLEAR)); } return err; diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_ptp.c b/drivers/net/ethernet/intel/fm10k/fm10k_ptp.c index 02008e976d18..9043633c3e50 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_ptp.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_ptp.c @@ -1,5 +1,5 @@ /* 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 * under the terms and conditions of the GNU General Public License, @@ -319,7 +319,8 @@ static int fm10k_ptp_settime(struct ptp_clock_info *ptp, } static int fm10k_ptp_enable(struct ptp_clock_info *ptp, - struct ptp_clock_request *rq, int on) + struct ptp_clock_request *rq, + int __always_unused on) { struct ptp_clock_time *t = &rq->perout.period; struct fm10k_intfc *interface; diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_vf.c b/drivers/net/ethernet/intel/fm10k/fm10k_vf.c index 17219678439a..94f0f6a146d9 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_vf.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_vf.c @@ -1,5 +1,5 @@ /* 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 * under the terms and conditions of the GNU General Public License, @@ -124,6 +124,10 @@ static s32 fm10k_init_hw_vf(struct fm10k_hw *hw) /* record maximum queue count */ hw->mac.max_queues = i; + /* fetch default VLAN */ + hw->mac.default_vid = (fm10k_read_reg(hw, FM10K_TXQCTL(0)) & + FM10K_TXQCTL_VID_MASK) >> FM10K_TXQCTL_VID_SHIFT; + return 0; } |