From 7fa8d547049aae543a5f21f1fe0e14414f1e7fdc Mon Sep 17 00:00:00 2001 From: Shradha Shah Date: Wed, 6 May 2015 00:55:13 +0100 Subject: [PATCH 01/14] sfc: Own header for nic-specific sriov functions, single instance of netdev_ops and sriov removed from Falcon code By putting all the efx_{siena,ef10}_sriov_* declarations in {siena,ef10}_sriov.h, ensure they cannot be called from nic-generic code. Also fixes up an instance of this, where mcdi.c was calling efx_siena_sriov_flr. The single instance of netdev_ops should call general high level functions that can then call something adapter specific in efx_nic_type. We should only do adapter specialisation via efx_nic_type. Removal of sriov functionality from the Falcon code means that tests are needed for the presence of some callbacks. Signed-off-by: Shradha Shah Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/Makefile | 2 +- drivers/net/ethernet/sfc/ef10.c | 8 ++ drivers/net/ethernet/sfc/ef10_sriov.h | 54 ++++++++++++ drivers/net/ethernet/sfc/efx.c | 104 +++++++++++------------ drivers/net/ethernet/sfc/efx.h | 7 ++ drivers/net/ethernet/sfc/falcon.c | 10 --- drivers/net/ethernet/sfc/farch.c | 56 ++++++++----- drivers/net/ethernet/sfc/mcdi.c | 4 +- drivers/net/ethernet/sfc/net_driver.h | 8 ++ drivers/net/ethernet/sfc/nic.h | 111 ------------------------- drivers/net/ethernet/sfc/siena.c | 10 +++ drivers/net/ethernet/sfc/siena_sriov.c | 18 ++-- drivers/net/ethernet/sfc/siena_sriov.h | 78 +++++++++++++++++ drivers/net/ethernet/sfc/sriov.c | 60 +++++++++++++ drivers/net/ethernet/sfc/sriov.h | 27 ++++++ 15 files changed, 351 insertions(+), 206 deletions(-) create mode 100644 drivers/net/ethernet/sfc/ef10_sriov.h create mode 100644 drivers/net/ethernet/sfc/siena_sriov.h create mode 100644 drivers/net/ethernet/sfc/sriov.c create mode 100644 drivers/net/ethernet/sfc/sriov.h diff --git a/drivers/net/ethernet/sfc/Makefile b/drivers/net/ethernet/sfc/Makefile index 3a83c0dca8e6..a08a789f8378 100644 --- a/drivers/net/ethernet/sfc/Makefile +++ b/drivers/net/ethernet/sfc/Makefile @@ -3,6 +3,6 @@ sfc-y += efx.o nic.o farch.o falcon.o siena.o ef10.o tx.o \ tenxpress.o txc43128_phy.o falcon_boards.o \ mcdi.o mcdi_port.o mcdi_mon.o ptp.o sfc-$(CONFIG_SFC_MTD) += mtd.o -sfc-$(CONFIG_SFC_SRIOV) += siena_sriov.o +sfc-$(CONFIG_SFC_SRIOV) += sriov.o siena_sriov.o obj-$(CONFIG_SFC) += sfc.o diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index fbb6cfa0f5f1..a031f7bc005e 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -15,6 +15,7 @@ #include "nic.h" #include "workarounds.h" #include "selftest.h" +#include "ef10_sriov.h" #include #include #include @@ -3689,11 +3690,18 @@ const struct efx_nic_type efx_hunt_a0_nic_type = { .ptp_write_host_time = efx_ef10_ptp_write_host_time, .ptp_set_ts_sync_events = efx_ef10_ptp_set_ts_sync_events, .ptp_set_ts_config = efx_ef10_ptp_set_ts_config, +#ifdef CONFIG_SFC_SRIOV .sriov_init = efx_ef10_sriov_init, .sriov_fini = efx_ef10_sriov_fini, .sriov_mac_address_changed = efx_ef10_sriov_mac_address_changed, .sriov_wanted = efx_ef10_sriov_wanted, .sriov_reset = efx_ef10_sriov_reset, + .sriov_flr = efx_ef10_sriov_flr, + .sriov_set_vf_mac = efx_ef10_sriov_set_vf_mac, + .sriov_set_vf_vlan = efx_ef10_sriov_set_vf_vlan, + .sriov_set_vf_spoofchk = efx_ef10_sriov_set_vf_spoofchk, + .sriov_get_vf_config = efx_ef10_sriov_get_vf_config, +#endif .revision = EFX_REV_HUNT_A0, .max_dma_mask = DMA_BIT_MASK(ESF_DZ_TX_KER_BUF_ADDR_WIDTH), diff --git a/drivers/net/ethernet/sfc/ef10_sriov.h b/drivers/net/ethernet/sfc/ef10_sriov.h new file mode 100644 index 000000000000..1ba9ecc6d78f --- /dev/null +++ b/drivers/net/ethernet/sfc/ef10_sriov.h @@ -0,0 +1,54 @@ +/**************************************************************************** + * Driver for Solarflare network controllers and boards + * Copyright 2015 Solarflare Communications Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, incorporated herein by reference. + */ + +#ifndef EF10_SRIOV_H +#define EF10_SRIOV_H + +#include "net_driver.h" + +static inline bool efx_ef10_sriov_wanted(struct efx_nic *efx) +{ + return false; +} + +static inline int efx_ef10_sriov_init(struct efx_nic *efx) +{ + return -EOPNOTSUPP; +} + +static inline void efx_ef10_sriov_mac_address_changed(struct efx_nic *efx) {} +static inline void efx_ef10_sriov_reset(struct efx_nic *efx) {} +static inline void efx_ef10_sriov_fini(struct efx_nic *efx) {} +static inline void efx_ef10_sriov_flr(struct efx_nic *efx, unsigned vf_i) {} + +static inline int efx_ef10_sriov_set_vf_mac(struct efx_nic *efx, int vf, + u8 *mac) +{ + return -EOPNOTSUPP; +} + +static inline int efx_ef10_sriov_set_vf_vlan(struct efx_nic *efx, int vf, + u16 vlan, u8 qos) +{ + return -EOPNOTSUPP; +} + +static inline int efx_ef10_sriov_set_vf_spoofchk(struct efx_nic *efx, int vf, + bool spoofchk) +{ + return -EOPNOTSUPP; +} + +static inline int efx_ef10_sriov_get_vf_config(struct efx_nic *efx, int vf, + struct ifla_vf_info *ivf) +{ + return -EOPNOTSUPP; +} + +#endif /* EF10_SRIOV_H */ diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 4b00545a3ace..fe8fe20eaa77 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -26,6 +26,7 @@ #include "efx.h" #include "nic.h" #include "selftest.h" +#include "sriov.h" #include "mcdi.h" #include "workarounds.h" @@ -1314,15 +1315,19 @@ static unsigned int efx_wanted_parallelism(struct efx_nic *efx) /* If RSS is requested for the PF *and* VFs then we can't write RSS * table entries that are inaccessible to VFs */ - if (efx->type->sriov_wanted(efx) && efx_vf_size(efx) > 1 && - count > efx_vf_size(efx)) { - netif_warn(efx, probe, efx->net_dev, - "Reducing number of RSS channels from %u to %u for " - "VF support. Increase vf-msix-limit to use more " - "channels on the PF.\n", - count, efx_vf_size(efx)); - count = efx_vf_size(efx); +#ifdef CONFIG_SFC_SRIOV + if (efx->type->sriov_wanted) { + if (efx->type->sriov_wanted(efx) && efx_vf_size(efx) > 1 && + count > efx_vf_size(efx)) { + netif_warn(efx, probe, efx->net_dev, + "Reducing number of RSS channels from %u to %u for " + "VF support. Increase vf-msix-limit to use more " + "channels on the PF.\n", + count, efx_vf_size(efx)); + count = efx_vf_size(efx); + } } +#endif return count; } @@ -1426,11 +1431,15 @@ static int efx_probe_interrupts(struct efx_nic *efx) } /* RSS might be usable on VFs even if it is disabled on the PF */ - - efx->rss_spread = ((efx->n_rx_channels > 1 || - !efx->type->sriov_wanted(efx)) ? - efx->n_rx_channels : efx_vf_size(efx)); - +#ifdef CONFIG_SFC_SRIOV + if (efx->type->sriov_wanted) { + efx->rss_spread = ((efx->n_rx_channels > 1 || + !efx->type->sriov_wanted(efx)) ? + efx->n_rx_channels : efx_vf_size(efx)); + return 0; + } +#endif + efx->rss_spread = efx->n_rx_channels; return 0; } @@ -2168,7 +2177,8 @@ static int efx_set_mac_address(struct net_device *net_dev, void *data) } ether_addr_copy(net_dev->dev_addr, new_addr); - efx->type->sriov_mac_address_changed(efx); + if (efx->type->sriov_mac_address_changed) + efx->type->sriov_mac_address_changed(efx); /* Reconfigure the MAC */ mutex_lock(&efx->mac_lock); @@ -2199,7 +2209,7 @@ static int efx_set_features(struct net_device *net_dev, netdev_features_t data) return 0; } -static const struct net_device_ops efx_farch_netdev_ops = { +static const struct net_device_ops efx_netdev_ops = { .ndo_open = efx_net_open, .ndo_stop = efx_net_stop, .ndo_get_stats64 = efx_net_stats, @@ -2212,10 +2222,10 @@ static const struct net_device_ops efx_farch_netdev_ops = { .ndo_set_rx_mode = efx_set_rx_mode, .ndo_set_features = efx_set_features, #ifdef CONFIG_SFC_SRIOV - .ndo_set_vf_mac = efx_siena_sriov_set_vf_mac, - .ndo_set_vf_vlan = efx_siena_sriov_set_vf_vlan, - .ndo_set_vf_spoofchk = efx_siena_sriov_set_vf_spoofchk, - .ndo_get_vf_config = efx_siena_sriov_get_vf_config, + .ndo_set_vf_mac = efx_sriov_set_vf_mac, + .ndo_set_vf_vlan = efx_sriov_set_vf_vlan, + .ndo_set_vf_spoofchk = efx_sriov_set_vf_spoofchk, + .ndo_get_vf_config = efx_sriov_get_vf_config, #endif #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = efx_netpoll, @@ -2229,29 +2239,6 @@ static const struct net_device_ops efx_farch_netdev_ops = { #endif }; -static const struct net_device_ops efx_ef10_netdev_ops = { - .ndo_open = efx_net_open, - .ndo_stop = efx_net_stop, - .ndo_get_stats64 = efx_net_stats, - .ndo_tx_timeout = efx_watchdog, - .ndo_start_xmit = efx_hard_start_xmit, - .ndo_validate_addr = eth_validate_addr, - .ndo_do_ioctl = efx_ioctl, - .ndo_change_mtu = efx_change_mtu, - .ndo_set_mac_address = efx_set_mac_address, - .ndo_set_rx_mode = efx_set_rx_mode, - .ndo_set_features = efx_set_features, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = efx_netpoll, -#endif -#ifdef CONFIG_NET_RX_BUSY_POLL - .ndo_busy_poll = efx_busy_poll, -#endif -#ifdef CONFIG_RFS_ACCEL - .ndo_rx_flow_steer = efx_filter_rfs, -#endif -}; - static void efx_update_name(struct efx_nic *efx) { strcpy(efx->name, efx->net_dev->name); @@ -2264,8 +2251,7 @@ static int efx_netdev_event(struct notifier_block *this, { struct net_device *net_dev = netdev_notifier_info_to_dev(ptr); - if ((net_dev->netdev_ops == &efx_farch_netdev_ops || - net_dev->netdev_ops == &efx_ef10_netdev_ops) && + if ((net_dev->netdev_ops == &efx_netdev_ops) && event == NETDEV_CHANGENAME) efx_update_name(netdev_priv(net_dev)); @@ -2292,12 +2278,9 @@ static int efx_register_netdev(struct efx_nic *efx) net_dev->watchdog_timeo = 5 * HZ; net_dev->irq = efx->pci_dev->irq; - if (efx_nic_rev(efx) >= EFX_REV_HUNT_A0) { - net_dev->netdev_ops = &efx_ef10_netdev_ops; + net_dev->netdev_ops = &efx_netdev_ops; + if (efx_nic_rev(efx) >= EFX_REV_HUNT_A0) net_dev->priv_flags |= IFF_UNICAST_FLT; - } else { - net_dev->netdev_ops = &efx_farch_netdev_ops; - } net_dev->ethtool_ops = &efx_ethtool_ops; net_dev->gso_max_segs = EFX_TSO_MAX_SEGS; @@ -2435,7 +2418,8 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok) if (rc) goto fail; efx_restore_filters(efx); - efx->type->sriov_reset(efx); + if (efx->type->sriov_reset) + efx->type->sriov_reset(efx); mutex_unlock(&efx->mac_lock); @@ -2826,7 +2810,9 @@ static void efx_pci_remove(struct pci_dev *pci_dev) efx_disable_interrupts(efx); rtnl_unlock(); - efx->type->sriov_fini(efx); + if (efx->type->sriov_fini) + efx->type->sriov_fini(efx); + efx_unregister_netdev(efx); efx_mtd_remove(efx); @@ -3023,10 +3009,12 @@ static int efx_pci_probe(struct pci_dev *pci_dev, if (rc) goto fail4; - rc = efx->type->sriov_init(efx); - if (rc) - netif_err(efx, probe, efx->net_dev, - "SR-IOV can't be enabled rc %d\n", rc); + if (efx->type->sriov_init) { + rc = efx->type->sriov_init(efx); + if (rc) + netif_err(efx, probe, efx->net_dev, + "SR-IOV can't be enabled rc %d\n", rc); + } netif_dbg(efx, probe, efx->net_dev, "initialisation successful\n"); @@ -3302,9 +3290,11 @@ static int __init efx_init_module(void) if (rc) goto err_notifier; +#ifdef CONFIG_SFC_SRIOV rc = efx_init_sriov(); if (rc) goto err_sriov; +#endif reset_workqueue = create_singlethread_workqueue("sfc_reset"); if (!reset_workqueue) { @@ -3321,8 +3311,10 @@ static int __init efx_init_module(void) err_pci: destroy_workqueue(reset_workqueue); err_reset: +#ifdef CONFIG_SFC_SRIOV efx_fini_sriov(); err_sriov: +#endif unregister_netdevice_notifier(&efx_netdev_notifier); err_notifier: return rc; @@ -3334,7 +3326,9 @@ static void __exit efx_exit_module(void) pci_unregister_driver(&efx_pci_driver); destroy_workqueue(reset_workqueue); +#ifdef CONFIG_SFC_SRIOV efx_fini_sriov(); +#endif unregister_netdevice_notifier(&efx_netdev_notifier); } diff --git a/drivers/net/ethernet/sfc/efx.h b/drivers/net/ethernet/sfc/efx.h index 2587c582a821..bc4e4b3e6aad 100644 --- a/drivers/net/ethernet/sfc/efx.h +++ b/drivers/net/ethernet/sfc/efx.h @@ -220,6 +220,13 @@ static inline void efx_mtd_rename(struct efx_nic *efx) {} static inline void efx_mtd_remove(struct efx_nic *efx) {} #endif +#ifdef CONFIG_SFC_SRIOV +static inline unsigned int efx_vf_size(struct efx_nic *efx) +{ + return 1 << efx->vi_scale; +} +#endif + static inline void efx_schedule_channel(struct efx_channel *channel) { netif_vdbg(channel->efx, intr, channel->efx->net_dev, diff --git a/drivers/net/ethernet/sfc/falcon.c b/drivers/net/ethernet/sfc/falcon.c index f166c8ef38a3..157037546d30 100644 --- a/drivers/net/ethernet/sfc/falcon.c +++ b/drivers/net/ethernet/sfc/falcon.c @@ -2766,11 +2766,6 @@ const struct efx_nic_type falcon_a1_nic_type = { .mtd_write = falcon_mtd_write, .mtd_sync = falcon_mtd_sync, #endif - .sriov_init = efx_falcon_sriov_init, - .sriov_fini = efx_falcon_sriov_fini, - .sriov_mac_address_changed = efx_falcon_sriov_mac_address_changed, - .sriov_wanted = efx_falcon_sriov_wanted, - .sriov_reset = efx_falcon_sriov_reset, .revision = EFX_REV_FALCON_A1, .txd_ptr_tbl_base = FR_AA_TX_DESC_PTR_TBL_KER, @@ -2867,11 +2862,6 @@ const struct efx_nic_type falcon_b0_nic_type = { .mtd_write = falcon_mtd_write, .mtd_sync = falcon_mtd_sync, #endif - .sriov_init = efx_falcon_sriov_init, - .sriov_fini = efx_falcon_sriov_fini, - .sriov_mac_address_changed = efx_falcon_sriov_mac_address_changed, - .sriov_wanted = efx_falcon_sriov_wanted, - .sriov_reset = efx_falcon_sriov_reset, .revision = EFX_REV_FALCON_B0, .txd_ptr_tbl_base = FR_BZ_TX_DESC_PTR_TBL, diff --git a/drivers/net/ethernet/sfc/farch.c b/drivers/net/ethernet/sfc/farch.c index bb89e96a125e..f08266f0eca2 100644 --- a/drivers/net/ethernet/sfc/farch.c +++ b/drivers/net/ethernet/sfc/farch.c @@ -20,6 +20,8 @@ #include "efx.h" #include "nic.h" #include "farch_regs.h" +#include "sriov.h" +#include "siena_sriov.h" #include "io.h" #include "workarounds.h" @@ -1198,13 +1200,17 @@ efx_farch_handle_driver_event(struct efx_channel *channel, efx_qword_t *event) netif_vdbg(efx, hw, efx->net_dev, "channel %d TXQ %d flushed\n", channel->channel, ev_sub_data); efx_farch_handle_tx_flush_done(efx, event); +#ifdef CONFIG_SFC_SRIOV efx_siena_sriov_tx_flush_done(efx, event); +#endif break; case FSE_AZ_RX_DESCQ_FLS_DONE_EV: netif_vdbg(efx, hw, efx->net_dev, "channel %d RXQ %d flushed\n", channel->channel, ev_sub_data); efx_farch_handle_rx_flush_done(efx, event); +#ifdef CONFIG_SFC_SRIOV efx_siena_sriov_rx_flush_done(efx, event); +#endif break; case FSE_AZ_EVQ_INIT_DONE_EV: netif_dbg(efx, hw, efx->net_dev, @@ -1242,8 +1248,11 @@ efx_farch_handle_driver_event(struct efx_channel *channel, efx_qword_t *event) " RX Q %d is disabled.\n", ev_sub_data, ev_sub_data); efx_schedule_reset(efx, RESET_TYPE_DMA_ERROR); - } else + } +#ifdef CONFIG_SFC_SRIOV + else efx_siena_sriov_desc_fetch_err(efx, ev_sub_data); +#endif break; case FSE_BZ_TX_DSC_ERROR_EV: if (ev_sub_data < EFX_VI_BASE) { @@ -1252,8 +1261,11 @@ efx_farch_handle_driver_event(struct efx_channel *channel, efx_qword_t *event) " TX Q %d is disabled.\n", ev_sub_data, ev_sub_data); efx_schedule_reset(efx, RESET_TYPE_DMA_ERROR); - } else + } +#ifdef CONFIG_SFC_SRIOV + else efx_siena_sriov_desc_fetch_err(efx, ev_sub_data); +#endif break; default: netif_vdbg(efx, hw, efx->net_dev, @@ -1317,9 +1329,11 @@ int efx_farch_ev_process(struct efx_channel *channel, int budget) case FSE_AZ_EV_CODE_DRIVER_EV: efx_farch_handle_driver_event(channel, &event); break; +#ifdef CONFIG_SFC_SRIOV case FSE_CZ_EV_CODE_USER_EV: efx_siena_sriov_event(channel, &event); break; +#endif case FSE_CZ_EV_CODE_MCDI_EV: efx_mcdi_process_event(channel, &event); break; @@ -1685,28 +1699,32 @@ void efx_farch_dimension_resources(struct efx_nic *efx, unsigned sram_lim_qw) vi_count = max(efx->n_channels, efx->n_tx_channels * EFX_TXQ_TYPES); #ifdef CONFIG_SFC_SRIOV - if (efx->type->sriov_wanted(efx)) { - unsigned vi_dc_entries, buftbl_free, entries_per_vf, vf_limit; + if (efx->type->sriov_wanted) { + if (efx->type->sriov_wanted(efx)) { + unsigned vi_dc_entries, buftbl_free; + unsigned entries_per_vf, vf_limit; - nic_data->vf_buftbl_base = buftbl_min; + nic_data->vf_buftbl_base = buftbl_min; - vi_dc_entries = RX_DC_ENTRIES + TX_DC_ENTRIES; - vi_count = max(vi_count, EFX_VI_BASE); - buftbl_free = (sram_lim_qw - buftbl_min - - vi_count * vi_dc_entries); + vi_dc_entries = RX_DC_ENTRIES + TX_DC_ENTRIES; + vi_count = max(vi_count, EFX_VI_BASE); + buftbl_free = (sram_lim_qw - buftbl_min - + vi_count * vi_dc_entries); - entries_per_vf = ((vi_dc_entries + EFX_VF_BUFTBL_PER_VI) * - efx_vf_size(efx)); - vf_limit = min(buftbl_free / entries_per_vf, - (1024U - EFX_VI_BASE) >> efx->vi_scale); + entries_per_vf = ((vi_dc_entries + + EFX_VF_BUFTBL_PER_VI) * + efx_vf_size(efx)); + vf_limit = min(buftbl_free / entries_per_vf, + (1024U - EFX_VI_BASE) >> efx->vi_scale); - if (efx->vf_count > vf_limit) { - netif_err(efx, probe, efx->net_dev, - "Reducing VF count from from %d to %d\n", - efx->vf_count, vf_limit); - efx->vf_count = vf_limit; + if (efx->vf_count > vf_limit) { + netif_err(efx, probe, efx->net_dev, + "Reducing VF count from from %d to %d\n", + efx->vf_count, vf_limit); + efx->vf_count = vf_limit; + } + vi_count += efx->vf_count * efx_vf_size(efx); } - vi_count += efx->vf_count * efx_vf_size(efx); } #endif diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c index d37928f01949..6502ada36d49 100644 --- a/drivers/net/ethernet/sfc/mcdi.c +++ b/drivers/net/ethernet/sfc/mcdi.c @@ -1035,7 +1035,9 @@ void efx_mcdi_process_event(struct efx_channel *channel, /* MAC stats are gather lazily. We can ignore this. */ break; case MCDI_EVENT_CODE_FLR: - efx_siena_sriov_flr(efx, MCDI_EVENT_FIELD(*event, FLR_VF)); + if (efx->type->sriov_flr) + efx->type->sriov_flr(efx, + MCDI_EVENT_FIELD(*event, FLR_VF)); break; case MCDI_EVENT_CODE_PTP_RX: case MCDI_EVENT_CODE_PTP_FAULT: diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index 325dd94bca46..ae0d145a5bed 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -1335,6 +1335,14 @@ struct efx_nic_type { void (*sriov_mac_address_changed)(struct efx_nic *efx); bool (*sriov_wanted)(struct efx_nic *efx); void (*sriov_reset)(struct efx_nic *efx); + void (*sriov_flr)(struct efx_nic *efx, unsigned vf_i); + int (*sriov_set_vf_mac)(struct efx_nic *efx, int vf_i, u8 *mac); + int (*sriov_set_vf_vlan)(struct efx_nic *efx, int vf_i, u16 vlan, + u8 qos); + int (*sriov_set_vf_spoofchk)(struct efx_nic *efx, int vf_i, + bool spoofchk); + int (*sriov_get_vf_config)(struct efx_nic *efx, int vf_i, + struct ifla_vf_info *ivi); int revision; unsigned int txd_ptr_tbl_base; diff --git a/drivers/net/ethernet/sfc/nic.h b/drivers/net/ethernet/sfc/nic.h index 93d10cbbd1cf..ea4ca18df7c5 100644 --- a/drivers/net/ethernet/sfc/nic.h +++ b/drivers/net/ethernet/sfc/nic.h @@ -509,120 +509,9 @@ struct efx_ef10_nic_data { u32 datapath_caps; }; -/* - * On the SFC9000 family each port is associated with 1 PCI physical - * function (PF) handled by sfc and a configurable number of virtual - * functions (VFs) that may be handled by some other driver, often in - * a VM guest. The queue pointer registers are mapped in both PF and - * VF BARs such that an 8K region provides access to a single RX, TX - * and event queue (collectively a Virtual Interface, VI or VNIC). - * - * The PF has access to all 1024 VIs while VFs are mapped to VIs - * according to VI_BASE and VI_SCALE: VF i has access to VIs numbered - * in range [VI_BASE + i << VI_SCALE, VI_BASE + i + 1 << VI_SCALE). - * The number of VIs and the VI_SCALE value are configurable but must - * be established at boot time by firmware. - */ - -/* Maximum VI_SCALE parameter supported by Siena */ -#define EFX_VI_SCALE_MAX 6 -/* Base VI to use for SR-IOV. Must be aligned to (1 << EFX_VI_SCALE_MAX), - * so this is the smallest allowed value. */ -#define EFX_VI_BASE 128U -/* Maximum number of VFs allowed */ -#define EFX_VF_COUNT_MAX 127 -/* Limit EVQs on VFs to be only 8k to reduce buffer table reservation */ -#define EFX_MAX_VF_EVQ_SIZE 8192UL -/* The number of buffer table entries reserved for each VI on a VF */ -#define EFX_VF_BUFTBL_PER_VI \ - ((EFX_MAX_VF_EVQ_SIZE + 2 * EFX_MAX_DMAQ_SIZE) * \ - sizeof(efx_qword_t) / EFX_BUF_SIZE) - -#ifdef CONFIG_SFC_SRIOV - -/* SIENA */ -static inline bool efx_siena_sriov_wanted(struct efx_nic *efx) -{ - return efx->vf_count != 0; -} - -static inline bool efx_siena_sriov_enabled(struct efx_nic *efx) -{ - return efx->vf_init_count != 0; -} - -static inline unsigned int efx_vf_size(struct efx_nic *efx) -{ - return 1 << efx->vi_scale; -} - int efx_init_sriov(void); -void efx_siena_sriov_probe(struct efx_nic *efx); -int efx_siena_sriov_init(struct efx_nic *efx); -void efx_siena_sriov_mac_address_changed(struct efx_nic *efx); -void efx_siena_sriov_tx_flush_done(struct efx_nic *efx, efx_qword_t *event); -void efx_siena_sriov_rx_flush_done(struct efx_nic *efx, efx_qword_t *event); -void efx_siena_sriov_event(struct efx_channel *channel, efx_qword_t *event); -void efx_siena_sriov_desc_fetch_err(struct efx_nic *efx, unsigned dmaq); -void efx_siena_sriov_flr(struct efx_nic *efx, unsigned flr); -void efx_siena_sriov_reset(struct efx_nic *efx); -void efx_siena_sriov_fini(struct efx_nic *efx); void efx_fini_sriov(void); -/* EF10 */ -static inline bool efx_ef10_sriov_wanted(struct efx_nic *efx) { return false; } -static inline int efx_ef10_sriov_init(struct efx_nic *efx) { return -EOPNOTSUPP; } -static inline void efx_ef10_sriov_mac_address_changed(struct efx_nic *efx) {} -static inline void efx_ef10_sriov_reset(struct efx_nic *efx) {} -static inline void efx_ef10_sriov_fini(struct efx_nic *efx) {} - -#else - -/* SIENA */ -static inline bool efx_siena_sriov_wanted(struct efx_nic *efx) { return false; } -static inline bool efx_siena_sriov_enabled(struct efx_nic *efx) { return false; } -static inline unsigned int efx_vf_size(struct efx_nic *efx) { return 0; } -static inline int efx_init_sriov(void) { return 0; } -static inline void efx_siena_sriov_probe(struct efx_nic *efx) {} -static inline int efx_siena_sriov_init(struct efx_nic *efx) { return -EOPNOTSUPP; } -static inline void efx_siena_sriov_mac_address_changed(struct efx_nic *efx) {} -static inline void efx_siena_sriov_tx_flush_done(struct efx_nic *efx, - efx_qword_t *event) {} -static inline void efx_siena_sriov_rx_flush_done(struct efx_nic *efx, - efx_qword_t *event) {} -static inline void efx_siena_sriov_event(struct efx_channel *channel, - efx_qword_t *event) {} -static inline void efx_siena_sriov_desc_fetch_err(struct efx_nic *efx, - unsigned dmaq) {} -static inline void efx_siena_sriov_flr(struct efx_nic *efx, unsigned flr) {} -static inline void efx_siena_sriov_reset(struct efx_nic *efx) {} -static inline void efx_siena_sriov_fini(struct efx_nic *efx) {} -static inline void efx_fini_sriov(void) {} - -/* EF10 */ -static inline bool efx_ef10_sriov_wanted(struct efx_nic *efx) { return false; } -static inline int efx_ef10_sriov_init(struct efx_nic *efx) { return -EOPNOTSUPP; } -static inline void efx_ef10_sriov_mac_address_changed(struct efx_nic *efx) {} -static inline void efx_ef10_sriov_reset(struct efx_nic *efx) {} -static inline void efx_ef10_sriov_fini(struct efx_nic *efx) {} - -#endif - -/* FALCON */ -static inline bool efx_falcon_sriov_wanted(struct efx_nic *efx) { return false; } -static inline int efx_falcon_sriov_init(struct efx_nic *efx) { return -EOPNOTSUPP; } -static inline void efx_falcon_sriov_mac_address_changed(struct efx_nic *efx) {} -static inline void efx_falcon_sriov_reset(struct efx_nic *efx) {} -static inline void efx_falcon_sriov_fini(struct efx_nic *efx) {} - -int efx_siena_sriov_set_vf_mac(struct net_device *dev, int vf, u8 *mac); -int efx_siena_sriov_set_vf_vlan(struct net_device *dev, int vf, - u16 vlan, u8 qos); -int efx_siena_sriov_get_vf_config(struct net_device *dev, int vf, - struct ifla_vf_info *ivf); -int efx_siena_sriov_set_vf_spoofchk(struct net_device *net_dev, int vf, - bool spoofchk); - struct ethtool_ts_info; int efx_ptp_probe(struct efx_nic *efx, struct efx_channel *channel); void efx_ptp_defer_probe_with_channel(struct efx_nic *efx); diff --git a/drivers/net/ethernet/sfc/siena.c b/drivers/net/ethernet/sfc/siena.c index f12c811938d2..b9d4ee596eff 100644 --- a/drivers/net/ethernet/sfc/siena.c +++ b/drivers/net/ethernet/sfc/siena.c @@ -25,6 +25,7 @@ #include "mcdi.h" #include "mcdi_pcol.h" #include "selftest.h" +#include "siena_sriov.h" /* Hardware control for SFC9000 family including SFL9021 (aka Siena). */ @@ -306,7 +307,9 @@ static int siena_probe_nic(struct efx_nic *efx) if (rc) goto fail5; +#ifdef CONFIG_SFC_SRIOV efx_siena_sriov_probe(efx); +#endif efx_ptp_defer_probe_with_channel(efx); return 0; @@ -996,11 +999,18 @@ const struct efx_nic_type siena_a0_nic_type = { #endif .ptp_write_host_time = siena_ptp_write_host_time, .ptp_set_ts_config = siena_ptp_set_ts_config, +#ifdef CONFIG_SFC_SRIOV .sriov_init = efx_siena_sriov_init, .sriov_fini = efx_siena_sriov_fini, .sriov_mac_address_changed = efx_siena_sriov_mac_address_changed, .sriov_wanted = efx_siena_sriov_wanted, .sriov_reset = efx_siena_sriov_reset, + .sriov_flr = efx_siena_sriov_flr, + .sriov_set_vf_mac = efx_siena_sriov_set_vf_mac, + .sriov_set_vf_vlan = efx_siena_sriov_set_vf_vlan, + .sriov_set_vf_spoofchk = efx_siena_sriov_set_vf_spoofchk, + .sriov_get_vf_config = efx_siena_sriov_get_vf_config, +#endif .revision = EFX_REV_SIENA_A0, .txd_ptr_tbl_base = FR_BZ_TX_DESC_PTR_TBL, diff --git a/drivers/net/ethernet/sfc/siena_sriov.c b/drivers/net/ethernet/sfc/siena_sriov.c index fe83430796fd..b7c281638d93 100644 --- a/drivers/net/ethernet/sfc/siena_sriov.c +++ b/drivers/net/ethernet/sfc/siena_sriov.c @@ -16,6 +16,7 @@ #include "filter.h" #include "mcdi_pcol.h" #include "farch_regs.h" +#include "siena_sriov.h" #include "vfdi.h" /* Number of longs required to track all the VIs in a VF */ @@ -1573,7 +1574,6 @@ int efx_init_sriov(void) vfdi_workqueue = create_singlethread_workqueue("sfc_vfdi"); if (!vfdi_workqueue) return -ENOMEM; - return 0; } @@ -1582,9 +1582,8 @@ void efx_fini_sriov(void) destroy_workqueue(vfdi_workqueue); } -int efx_siena_sriov_set_vf_mac(struct net_device *net_dev, int vf_i, u8 *mac) +int efx_siena_sriov_set_vf_mac(struct efx_nic *efx, int vf_i, u8 *mac) { - struct efx_nic *efx = netdev_priv(net_dev); struct efx_vf *vf; if (vf_i >= efx->vf_init_count) @@ -1599,10 +1598,9 @@ int efx_siena_sriov_set_vf_mac(struct net_device *net_dev, int vf_i, u8 *mac) return 0; } -int efx_siena_sriov_set_vf_vlan(struct net_device *net_dev, int vf_i, +int efx_siena_sriov_set_vf_vlan(struct efx_nic *efx, int vf_i, u16 vlan, u8 qos) { - struct efx_nic *efx = netdev_priv(net_dev); struct efx_vf *vf; u16 tci; @@ -1619,10 +1617,9 @@ int efx_siena_sriov_set_vf_vlan(struct net_device *net_dev, int vf_i, return 0; } -int efx_siena_sriov_set_vf_spoofchk(struct net_device *net_dev, int vf_i, +int efx_siena_sriov_set_vf_spoofchk(struct efx_nic *efx, int vf_i, bool spoofchk) { - struct efx_nic *efx = netdev_priv(net_dev); struct efx_vf *vf; int rc; @@ -1643,10 +1640,9 @@ int efx_siena_sriov_set_vf_spoofchk(struct net_device *net_dev, int vf_i, return rc; } -int efx_siena_sriov_get_vf_config(struct net_device *net_dev, int vf_i, +int efx_siena_sriov_get_vf_config(struct efx_nic *efx, int vf_i, struct ifla_vf_info *ivi) { - struct efx_nic *efx = netdev_priv(net_dev); struct efx_vf *vf; u16 tci; @@ -1666,3 +1662,7 @@ int efx_siena_sriov_get_vf_config(struct net_device *net_dev, int vf_i, return 0; } +bool efx_siena_sriov_wanted(struct efx_nic *efx) +{ + return efx->vf_count != 0; +} diff --git a/drivers/net/ethernet/sfc/siena_sriov.h b/drivers/net/ethernet/sfc/siena_sriov.h new file mode 100644 index 000000000000..b3a08d156943 --- /dev/null +++ b/drivers/net/ethernet/sfc/siena_sriov.h @@ -0,0 +1,78 @@ +/**************************************************************************** + * Driver for Solarflare network controllers and boards + * Copyright 2015 Solarflare Communications Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, incorporated herein by reference. + */ + +#ifndef SIENA_SRIOV_H +#define SIENA_SRIOV_H + +#include "net_driver.h" + +/* On the SFC9000 family each port is associated with 1 PCI physical + * function (PF) handled by sfc and a configurable number of virtual + * functions (VFs) that may be handled by some other driver, often in + * a VM guest. The queue pointer registers are mapped in both PF and + * VF BARs such that an 8K region provides access to a single RX, TX + * and event queue (collectively a Virtual Interface, VI or VNIC). + * + * The PF has access to all 1024 VIs while VFs are mapped to VIs + * according to VI_BASE and VI_SCALE: VF i has access to VIs numbered + * in range [VI_BASE + i << VI_SCALE, VI_BASE + i + 1 << VI_SCALE). + * The number of VIs and the VI_SCALE value are configurable but must + * be established at boot time by firmware. + */ + +/* Maximum VI_SCALE parameter supported by Siena */ +#define EFX_VI_SCALE_MAX 6 +/* Base VI to use for SR-IOV. Must be aligned to (1 << EFX_VI_SCALE_MAX), + * so this is the smallest allowed value. + */ +#define EFX_VI_BASE 128U +/* Maximum number of VFs allowed */ +#define EFX_VF_COUNT_MAX 127 +/* Limit EVQs on VFs to be only 8k to reduce buffer table reservation */ +#define EFX_MAX_VF_EVQ_SIZE 8192UL +/* The number of buffer table entries reserved for each VI on a VF */ +#define EFX_VF_BUFTBL_PER_VI \ + ((EFX_MAX_VF_EVQ_SIZE + 2 * EFX_MAX_DMAQ_SIZE) * \ + sizeof(efx_qword_t) / EFX_BUF_SIZE) + +int efx_siena_sriov_init(struct efx_nic *efx); +void efx_siena_sriov_fini(struct efx_nic *efx); +void efx_siena_sriov_mac_address_changed(struct efx_nic *efx); +bool efx_siena_sriov_wanted(struct efx_nic *efx); +void efx_siena_sriov_reset(struct efx_nic *efx); +void efx_siena_sriov_flr(struct efx_nic *efx, unsigned flr); + +int efx_siena_sriov_set_vf_mac(struct efx_nic *efx, int vf, u8 *mac); +int efx_siena_sriov_set_vf_vlan(struct efx_nic *efx, int vf, + u16 vlan, u8 qos); +int efx_siena_sriov_set_vf_spoofchk(struct efx_nic *efx, int vf, + bool spoofchk); +int efx_siena_sriov_get_vf_config(struct efx_nic *efx, int vf, + struct ifla_vf_info *ivf); + +#ifdef CONFIG_SFC_SRIOV + +static inline bool efx_siena_sriov_enabled(struct efx_nic *efx) +{ + return efx->vf_init_count != 0; +} +#else /* !CONFIG_SFC_SRIOV */ +static inline bool efx_siena_sriov_enabled(struct efx_nic *efx) +{ + return false; +} +#endif /* CONFIG_SFC_SRIOV */ + +void efx_siena_sriov_probe(struct efx_nic *efx); +void efx_siena_sriov_tx_flush_done(struct efx_nic *efx, efx_qword_t *event); +void efx_siena_sriov_rx_flush_done(struct efx_nic *efx, efx_qword_t *event); +void efx_siena_sriov_event(struct efx_channel *channel, efx_qword_t *event); +void efx_siena_sriov_desc_fetch_err(struct efx_nic *efx, unsigned dmaq); + +#endif /* SIENA_SRIOV_H */ diff --git a/drivers/net/ethernet/sfc/sriov.c b/drivers/net/ethernet/sfc/sriov.c new file mode 100644 index 000000000000..d4b74452a677 --- /dev/null +++ b/drivers/net/ethernet/sfc/sriov.c @@ -0,0 +1,60 @@ +/**************************************************************************** + * Driver for Solarflare network controllers and boards + * Copyright 2014-2015 Solarflare Communications Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, incorporated herein by reference. + */ +#include +#include "net_driver.h" +#include "nic.h" +#include "sriov.h" + +int efx_sriov_set_vf_mac(struct net_device *net_dev, int vf_i, u8 *mac) +{ + struct efx_nic *efx = netdev_priv(net_dev); + + if (efx->type->sriov_set_vf_mac) + return efx->type->sriov_set_vf_mac(efx, vf_i, mac); + else + return -EOPNOTSUPP; +} + +int efx_sriov_set_vf_vlan(struct net_device *net_dev, int vf_i, u16 vlan, + u8 qos) +{ + struct efx_nic *efx = netdev_priv(net_dev); + + if (efx->type->sriov_set_vf_vlan) { + if ((vlan & ~VLAN_VID_MASK) || + (qos & ~(VLAN_PRIO_MASK >> VLAN_PRIO_SHIFT))) + return -EINVAL; + + return efx->type->sriov_set_vf_vlan(efx, vf_i, vlan, qos); + } else { + return -EOPNOTSUPP; + } +} + +int efx_sriov_set_vf_spoofchk(struct net_device *net_dev, int vf_i, + bool spoofchk) +{ + struct efx_nic *efx = netdev_priv(net_dev); + + if (efx->type->sriov_set_vf_spoofchk) + return efx->type->sriov_set_vf_spoofchk(efx, vf_i, spoofchk); + else + return -EOPNOTSUPP; +} + +int efx_sriov_get_vf_config(struct net_device *net_dev, int vf_i, + struct ifla_vf_info *ivi) +{ + struct efx_nic *efx = netdev_priv(net_dev); + + if (efx->type->sriov_get_vf_config) + return efx->type->sriov_get_vf_config(efx, vf_i, ivi); + else + return -EOPNOTSUPP; +} diff --git a/drivers/net/ethernet/sfc/sriov.h b/drivers/net/ethernet/sfc/sriov.h new file mode 100644 index 000000000000..0b9f0f6acf3b --- /dev/null +++ b/drivers/net/ethernet/sfc/sriov.h @@ -0,0 +1,27 @@ +/**************************************************************************** + * Driver for Solarflare network controllers and boards + * Copyright 2014-2015 Solarflare Communications Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, incorporated herein by reference. + */ + +#ifndef EFX_SRIOV_H +#define EFX_SRIOV_H + +#include "net_driver.h" + +#ifdef CONFIG_SFC_SRIOV + +int efx_sriov_set_vf_mac(struct net_device *net_dev, int vf_i, u8 *mac); +int efx_sriov_set_vf_vlan(struct net_device *net_dev, int vf_i, u16 vlan, + u8 qos); +int efx_sriov_set_vf_spoofchk(struct net_device *net_dev, int vf_i, + bool spoofchk); +int efx_sriov_get_vf_config(struct net_device *net_dev, int vf_i, + struct ifla_vf_info *ivi); + +#endif /* CONFIG_SFC_SRIOV */ + +#endif /* EFX_SRIOV_H */ From bf3d0156c5b7b31a74845b21d131276f9eb31493 Mon Sep 17 00:00:00 2001 From: Daniel Pieczko Date: Wed, 6 May 2015 00:55:36 +0100 Subject: [PATCH 02/14] sfc: Move and rename efx_vf struct to siena_vf The efx_vf struct contains Siena-specific fields for VFs, so rename to siena_vf. Also move it into the siena_nic_data struct, as EF10 will track its VFs in its own ef10_nic_data, storing much less information about them since VFDI is no longer used. Signed-off-by: Shradha Shah Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/net_driver.h | 3 - drivers/net/ethernet/sfc/nic.h | 2 + drivers/net/ethernet/sfc/siena_sriov.c | 119 ++++++++++++++----------- 3 files changed, 67 insertions(+), 57 deletions(-) diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index ae0d145a5bed..e3054b2a71f7 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -793,7 +793,6 @@ union efx_multicast_hash { efx_oword_t oword[EFX_MCAST_HASH_ENTRIES / sizeof(efx_oword_t) / 8]; }; -struct efx_vf; struct vfdi_status; /** @@ -909,7 +908,6 @@ struct vfdi_status; * completed (either success or failure). Not used when MCDI is used to * flush receive queues. * @flush_wq: wait queue used by efx_nic_flush_queues() to wait for flush completions. - * @vf: Array of &struct efx_vf objects. * @vf_count: Number of VFs intended to be enabled. * @vf_init_count: Number of VFs that have been fully initialised. * @vi_scale: log2 number of vnics per VF. @@ -1053,7 +1051,6 @@ struct efx_nic { wait_queue_head_t flush_wq; #ifdef CONFIG_SFC_SRIOV - struct efx_vf *vf; unsigned vf_count; unsigned vf_init_count; unsigned vi_scale; diff --git a/drivers/net/ethernet/sfc/nic.h b/drivers/net/ethernet/sfc/nic.h index ea4ca18df7c5..65dcbc7f3d83 100644 --- a/drivers/net/ethernet/sfc/nic.h +++ b/drivers/net/ethernet/sfc/nic.h @@ -381,6 +381,7 @@ enum { * @efx: Pointer back to main interface structure * @wol_filter_id: Wake-on-LAN packet filter id * @stats: Hardware statistics + * @vf: Array of &struct siena_vf objects * @vf_buftbl_base: The zeroth buffer table index used to back VF queues. * @vfdi_status: Common VFDI status page to be dmad to VF address space. * @local_addr_list: List of local addresses. Protected by %local_lock. @@ -394,6 +395,7 @@ struct siena_nic_data { int wol_filter_id; u64 stats[SIENA_STAT_COUNT]; #ifdef CONFIG_SFC_SRIOV + struct siena_vf *vf; struct efx_channel *vfdi_channel; unsigned vf_buftbl_base; struct efx_buffer vfdi_status; diff --git a/drivers/net/ethernet/sfc/siena_sriov.c b/drivers/net/ethernet/sfc/siena_sriov.c index b7c281638d93..2044e929f48d 100644 --- a/drivers/net/ethernet/sfc/siena_sriov.c +++ b/drivers/net/ethernet/sfc/siena_sriov.c @@ -39,7 +39,7 @@ enum efx_vf_tx_filter_mode { }; /** - * struct efx_vf - Back-end resource and protocol state for a PCI VF + * struct siena_vf - Back-end resource and protocol state for a PCI VF * @efx: The Efx NIC owning this VF * @pci_rid: The PCI requester ID for this VF * @pci_name: The PCI name (formatted address) of this VF @@ -84,7 +84,7 @@ enum efx_vf_tx_filter_mode { * @rxq_retry_count: Number of receive queues in @rxq_retry_mask. * @reset_work: Work item to schedule a VF reset. */ -struct efx_vf { +struct siena_vf { struct efx_nic *efx; unsigned int pci_rid; char pci_name[13]; /* dddd:bb:dd.f */ @@ -190,7 +190,7 @@ MODULE_PARM_DESC(max_vfs, */ static struct workqueue_struct *vfdi_workqueue; -static unsigned abs_index(struct efx_vf *vf, unsigned index) +static unsigned abs_index(struct siena_vf *vf, unsigned index) { return EFX_VI_BASE + vf->index * efx_vf_size(vf->efx) + index; } @@ -300,7 +300,7 @@ out: /* The TX filter is entirely controlled by this driver, and is modified * underneath the feet of the VF */ -static void efx_siena_sriov_reset_tx_filter(struct efx_vf *vf) +static void efx_siena_sriov_reset_tx_filter(struct siena_vf *vf) { struct efx_nic *efx = vf->efx; struct efx_filter_spec filter; @@ -344,7 +344,7 @@ static void efx_siena_sriov_reset_tx_filter(struct efx_vf *vf) } /* The RX filter is managed here on behalf of the VF driver */ -static void efx_siena_sriov_reset_rx_filter(struct efx_vf *vf) +static void efx_siena_sriov_reset_rx_filter(struct siena_vf *vf) { struct efx_nic *efx = vf->efx; struct efx_filter_spec filter; @@ -383,7 +383,7 @@ static void efx_siena_sriov_reset_rx_filter(struct efx_vf *vf) } } -static void __efx_siena_sriov_update_vf_addr(struct efx_vf *vf) +static void __efx_siena_sriov_update_vf_addr(struct siena_vf *vf) { struct efx_nic *efx = vf->efx; struct siena_nic_data *nic_data = efx->nic_data; @@ -398,7 +398,7 @@ static void __efx_siena_sriov_update_vf_addr(struct efx_vf *vf) * local_page_list, either by acquiring local_lock or by running from * efx_siena_sriov_peer_work() */ -static void __efx_siena_sriov_push_vf_status(struct efx_vf *vf) +static void __efx_siena_sriov_push_vf_status(struct siena_vf *vf) { struct efx_nic *efx = vf->efx; struct siena_nic_data *nic_data = efx->nic_data; @@ -510,8 +510,9 @@ static bool bad_buf_count(unsigned buf_count, unsigned max_entry_count) * Optionally set VF index and VI index within the VF. */ static bool map_vi_index(struct efx_nic *efx, unsigned abs_index, - struct efx_vf **vf_out, unsigned *rel_index_out) + struct siena_vf **vf_out, unsigned *rel_index_out) { + struct siena_nic_data *nic_data = efx->nic_data; unsigned vf_i; if (abs_index < EFX_VI_BASE) @@ -521,13 +522,13 @@ static bool map_vi_index(struct efx_nic *efx, unsigned abs_index, return true; if (vf_out) - *vf_out = efx->vf + vf_i; + *vf_out = nic_data->vf + vf_i; if (rel_index_out) *rel_index_out = abs_index % efx_vf_size(efx); return false; } -static int efx_vfdi_init_evq(struct efx_vf *vf) +static int efx_vfdi_init_evq(struct siena_vf *vf) { struct efx_nic *efx = vf->efx; struct vfdi_req *req = vf->buf.addr; @@ -568,7 +569,7 @@ static int efx_vfdi_init_evq(struct efx_vf *vf) return VFDI_RC_SUCCESS; } -static int efx_vfdi_init_rxq(struct efx_vf *vf) +static int efx_vfdi_init_rxq(struct siena_vf *vf) { struct efx_nic *efx = vf->efx; struct vfdi_req *req = vf->buf.addr; @@ -609,7 +610,7 @@ static int efx_vfdi_init_rxq(struct efx_vf *vf) return VFDI_RC_SUCCESS; } -static int efx_vfdi_init_txq(struct efx_vf *vf) +static int efx_vfdi_init_txq(struct siena_vf *vf) { struct efx_nic *efx = vf->efx; struct vfdi_req *req = vf->buf.addr; @@ -656,7 +657,7 @@ static int efx_vfdi_init_txq(struct efx_vf *vf) } /* Returns true when efx_vfdi_fini_all_queues should wake */ -static bool efx_vfdi_flush_wake(struct efx_vf *vf) +static bool efx_vfdi_flush_wake(struct siena_vf *vf) { /* Ensure that all updates are visible to efx_vfdi_fini_all_queues() */ smp_mb(); @@ -665,7 +666,7 @@ static bool efx_vfdi_flush_wake(struct efx_vf *vf) atomic_read(&vf->rxq_retry_count); } -static void efx_vfdi_flush_clear(struct efx_vf *vf) +static void efx_vfdi_flush_clear(struct siena_vf *vf) { memset(vf->txq_mask, 0, sizeof(vf->txq_mask)); vf->txq_count = 0; @@ -675,7 +676,7 @@ static void efx_vfdi_flush_clear(struct efx_vf *vf) atomic_set(&vf->rxq_retry_count, 0); } -static int efx_vfdi_fini_all_queues(struct efx_vf *vf) +static int efx_vfdi_fini_all_queues(struct siena_vf *vf) { struct efx_nic *efx = vf->efx; efx_oword_t reg; @@ -758,7 +759,7 @@ static int efx_vfdi_fini_all_queues(struct efx_vf *vf) return timeout ? 0 : VFDI_RC_ETIMEDOUT; } -static int efx_vfdi_insert_filter(struct efx_vf *vf) +static int efx_vfdi_insert_filter(struct siena_vf *vf) { struct efx_nic *efx = vf->efx; struct siena_nic_data *nic_data = efx->nic_data; @@ -790,7 +791,7 @@ static int efx_vfdi_insert_filter(struct efx_vf *vf) return VFDI_RC_SUCCESS; } -static int efx_vfdi_remove_all_filters(struct efx_vf *vf) +static int efx_vfdi_remove_all_filters(struct siena_vf *vf) { struct efx_nic *efx = vf->efx; struct siena_nic_data *nic_data = efx->nic_data; @@ -802,7 +803,7 @@ static int efx_vfdi_remove_all_filters(struct efx_vf *vf) return VFDI_RC_SUCCESS; } -static int efx_vfdi_set_status_page(struct efx_vf *vf) +static int efx_vfdi_set_status_page(struct siena_vf *vf) { struct efx_nic *efx = vf->efx; struct siena_nic_data *nic_data = efx->nic_data; @@ -847,7 +848,7 @@ static int efx_vfdi_set_status_page(struct efx_vf *vf) return VFDI_RC_SUCCESS; } -static int efx_vfdi_clear_status_page(struct efx_vf *vf) +static int efx_vfdi_clear_status_page(struct siena_vf *vf) { mutex_lock(&vf->status_lock); vf->status_addr = 0; @@ -856,7 +857,7 @@ static int efx_vfdi_clear_status_page(struct efx_vf *vf) return VFDI_RC_SUCCESS; } -typedef int (*efx_vfdi_op_t)(struct efx_vf *vf); +typedef int (*efx_vfdi_op_t)(struct siena_vf *vf); static const efx_vfdi_op_t vfdi_ops[VFDI_OP_LIMIT] = { [VFDI_OP_INIT_EVQ] = efx_vfdi_init_evq, @@ -871,7 +872,7 @@ static const efx_vfdi_op_t vfdi_ops[VFDI_OP_LIMIT] = { static void efx_siena_sriov_vfdi(struct work_struct *work) { - struct efx_vf *vf = container_of(work, struct efx_vf, req); + struct siena_vf *vf = container_of(work, struct siena_vf, req); struct efx_nic *efx = vf->efx; struct vfdi_req *req = vf->buf.addr; struct efx_memcpy_req copy[2]; @@ -937,7 +938,8 @@ static void efx_siena_sriov_vfdi(struct work_struct *work) * event ring in guest memory with VFDI reset events, then (re-initialise) the * event queue to raise an interrupt. The guest driver will then recover. */ -static void efx_siena_sriov_reset_vf(struct efx_vf *vf, + +static void efx_siena_sriov_reset_vf(struct siena_vf *vf, struct efx_buffer *buffer) { struct efx_nic *efx = vf->efx; @@ -1007,7 +1009,7 @@ static void efx_siena_sriov_reset_vf(struct efx_vf *vf, static void efx_siena_sriov_reset_vf_work(struct work_struct *work) { - struct efx_vf *vf = container_of(work, struct efx_vf, req); + struct siena_vf *vf = container_of(work, struct siena_vf, req); struct efx_nic *efx = vf->efx; struct efx_buffer buf; @@ -1078,7 +1080,7 @@ static void efx_siena_sriov_peer_work(struct work_struct *data) peer_work); struct efx_nic *efx = nic_data->efx; struct vfdi_status *vfdi_status = nic_data->vfdi_status.addr; - struct efx_vf *vf; + struct siena_vf *vf; struct efx_local_addr *local_addr; struct vfdi_endpoint *peer; struct efx_endpoint_page *epp; @@ -1100,7 +1102,7 @@ static void efx_siena_sriov_peer_work(struct work_struct *data) peer_space = ARRAY_SIZE(vfdi_status->peers) - 1; peer_count = 1; for (pos = 0; pos < efx->vf_count; ++pos) { - vf = efx->vf + pos; + vf = nic_data->vf + pos; mutex_lock(&vf->status_lock); if (vf->rx_filtering && !is_zero_ether_addr(vf->addr.mac_addr)) { @@ -1156,7 +1158,7 @@ static void efx_siena_sriov_peer_work(struct work_struct *data) /* Finally, push the pages */ for (pos = 0; pos < efx->vf_count; ++pos) { - vf = efx->vf + pos; + vf = nic_data->vf + pos; mutex_lock(&vf->status_lock); if (vf->status_addr) @@ -1191,14 +1193,16 @@ static void efx_siena_sriov_free_local(struct efx_nic *efx) static int efx_siena_sriov_vf_alloc(struct efx_nic *efx) { unsigned index; - struct efx_vf *vf; + struct siena_vf *vf; + struct siena_nic_data *nic_data = efx->nic_data; - efx->vf = kzalloc(sizeof(struct efx_vf) * efx->vf_count, GFP_KERNEL); - if (!efx->vf) + nic_data->vf = kcalloc(efx->vf_count, sizeof(*nic_data->vf), + GFP_KERNEL); + if (!nic_data->vf) return -ENOMEM; for (index = 0; index < efx->vf_count; ++index) { - vf = efx->vf + index; + vf = nic_data->vf + index; vf->efx = efx; vf->index = index; @@ -1217,11 +1221,12 @@ static int efx_siena_sriov_vf_alloc(struct efx_nic *efx) static void efx_siena_sriov_vfs_fini(struct efx_nic *efx) { - struct efx_vf *vf; + struct siena_nic_data *nic_data = efx->nic_data; + struct siena_vf *vf; unsigned int pos; for (pos = 0; pos < efx->vf_count; ++pos) { - vf = efx->vf + pos; + vf = nic_data->vf + pos; efx_nic_free_buffer(efx, &vf->buf); kfree(vf->peer_page_addrs); @@ -1238,7 +1243,7 @@ static int efx_siena_sriov_vfs_init(struct efx_nic *efx) struct siena_nic_data *nic_data = efx->nic_data; unsigned index, devfn, sriov, buftbl_base; u16 offset, stride; - struct efx_vf *vf; + struct siena_vf *vf; int rc; sriov = pci_find_ext_capability(pci_dev, PCI_EXT_CAP_ID_SRIOV); @@ -1251,7 +1256,7 @@ static int efx_siena_sriov_vfs_init(struct efx_nic *efx) buftbl_base = nic_data->vf_buftbl_base; devfn = pci_dev->devfn + offset; for (index = 0; index < efx->vf_count; ++index) { - vf = efx->vf + index; + vf = nic_data->vf + index; /* Reserve buffer entries */ vf->buftbl_base = buftbl_base; @@ -1351,7 +1356,7 @@ fail_pci: fail_vfs: cancel_work_sync(&nic_data->peer_work); efx_siena_sriov_free_local(efx); - kfree(efx->vf); + kfree(nic_data->vf); fail_alloc: efx_nic_free_buffer(efx, &nic_data->vfdi_status); fail_status: @@ -1362,7 +1367,7 @@ fail_cmd: void efx_siena_sriov_fini(struct efx_nic *efx) { - struct efx_vf *vf; + struct siena_vf *vf; unsigned int pos; struct siena_nic_data *nic_data = efx->nic_data; @@ -1378,7 +1383,7 @@ void efx_siena_sriov_fini(struct efx_nic *efx) /* Flush all reconfiguration work */ for (pos = 0; pos < efx->vf_count; ++pos) { - vf = efx->vf + pos; + vf = nic_data->vf + pos; cancel_work_sync(&vf->req); cancel_work_sync(&vf->reset_work); } @@ -1389,7 +1394,7 @@ void efx_siena_sriov_fini(struct efx_nic *efx) /* Tear down back-end state */ efx_siena_sriov_vfs_fini(efx); efx_siena_sriov_free_local(efx); - kfree(efx->vf); + kfree(nic_data->vf); efx_nic_free_buffer(efx, &nic_data->vfdi_status); efx_siena_sriov_cmd(efx, false, NULL, NULL); } @@ -1397,7 +1402,7 @@ void efx_siena_sriov_fini(struct efx_nic *efx) void efx_siena_sriov_event(struct efx_channel *channel, efx_qword_t *event) { struct efx_nic *efx = channel->efx; - struct efx_vf *vf; + struct siena_vf *vf; unsigned qid, seq, type, data; qid = EFX_QWORD_FIELD(*event, FSF_CZ_USER_QID); @@ -1453,11 +1458,12 @@ error: void efx_siena_sriov_flr(struct efx_nic *efx, unsigned vf_i) { - struct efx_vf *vf; + struct siena_nic_data *nic_data = efx->nic_data; + struct siena_vf *vf; if (vf_i > efx->vf_init_count) return; - vf = efx->vf + vf_i; + vf = nic_data->vf + vf_i; netif_info(efx, hw, efx->net_dev, "FLR on VF %s\n", vf->pci_name); @@ -1482,7 +1488,7 @@ void efx_siena_sriov_mac_address_changed(struct efx_nic *efx) void efx_siena_sriov_tx_flush_done(struct efx_nic *efx, efx_qword_t *event) { - struct efx_vf *vf; + struct siena_vf *vf; unsigned queue, qid; queue = EFX_QWORD_FIELD(*event, FSF_AZ_DRIVER_EV_SUBDATA); @@ -1501,7 +1507,7 @@ void efx_siena_sriov_tx_flush_done(struct efx_nic *efx, efx_qword_t *event) void efx_siena_sriov_rx_flush_done(struct efx_nic *efx, efx_qword_t *event) { - struct efx_vf *vf; + struct siena_vf *vf; unsigned ev_failed, queue, qid; queue = EFX_QWORD_FIELD(*event, FSF_AZ_DRIVER_EV_RX_DESCQ_ID); @@ -1526,7 +1532,7 @@ void efx_siena_sriov_rx_flush_done(struct efx_nic *efx, efx_qword_t *event) /* Called from napi. Schedule the reset work item */ void efx_siena_sriov_desc_fetch_err(struct efx_nic *efx, unsigned dmaq) { - struct efx_vf *vf; + struct siena_vf *vf; unsigned int rel; if (map_vi_index(efx, dmaq, &vf, &rel)) @@ -1542,9 +1548,10 @@ void efx_siena_sriov_desc_fetch_err(struct efx_nic *efx, unsigned dmaq) /* Reset all VFs */ void efx_siena_sriov_reset(struct efx_nic *efx) { + struct siena_nic_data *nic_data = efx->nic_data; unsigned int vf_i; struct efx_buffer buf; - struct efx_vf *vf; + struct siena_vf *vf; ASSERT_RTNL(); @@ -1558,7 +1565,7 @@ void efx_siena_sriov_reset(struct efx_nic *efx) return; for (vf_i = 0; vf_i < efx->vf_init_count; ++vf_i) { - vf = efx->vf + vf_i; + vf = nic_data->vf + vf_i; efx_siena_sriov_reset_vf(vf, &buf); } @@ -1584,11 +1591,12 @@ void efx_fini_sriov(void) int efx_siena_sriov_set_vf_mac(struct efx_nic *efx, int vf_i, u8 *mac) { - struct efx_vf *vf; + struct siena_nic_data *nic_data = efx->nic_data; + struct siena_vf *vf; if (vf_i >= efx->vf_init_count) return -EINVAL; - vf = efx->vf + vf_i; + vf = nic_data->vf + vf_i; mutex_lock(&vf->status_lock); ether_addr_copy(vf->addr.mac_addr, mac); @@ -1601,12 +1609,13 @@ int efx_siena_sriov_set_vf_mac(struct efx_nic *efx, int vf_i, u8 *mac) int efx_siena_sriov_set_vf_vlan(struct efx_nic *efx, int vf_i, u16 vlan, u8 qos) { - struct efx_vf *vf; + struct siena_nic_data *nic_data = efx->nic_data; + struct siena_vf *vf; u16 tci; if (vf_i >= efx->vf_init_count) return -EINVAL; - vf = efx->vf + vf_i; + vf = nic_data->vf + vf_i; mutex_lock(&vf->status_lock); tci = (vlan & VLAN_VID_MASK) | ((qos & 0x7) << VLAN_PRIO_SHIFT); @@ -1620,12 +1629,13 @@ int efx_siena_sriov_set_vf_vlan(struct efx_nic *efx, int vf_i, int efx_siena_sriov_set_vf_spoofchk(struct efx_nic *efx, int vf_i, bool spoofchk) { - struct efx_vf *vf; + struct siena_nic_data *nic_data = efx->nic_data; + struct siena_vf *vf; int rc; if (vf_i >= efx->vf_init_count) return -EINVAL; - vf = efx->vf + vf_i; + vf = nic_data->vf + vf_i; mutex_lock(&vf->txq_lock); if (vf->txq_count == 0) { @@ -1643,12 +1653,13 @@ int efx_siena_sriov_set_vf_spoofchk(struct efx_nic *efx, int vf_i, int efx_siena_sriov_get_vf_config(struct efx_nic *efx, int vf_i, struct ifla_vf_info *ivi) { - struct efx_vf *vf; + struct siena_nic_data *nic_data = efx->nic_data; + struct siena_vf *vf; u16 tci; if (vf_i >= efx->vf_init_count) return -EINVAL; - vf = efx->vf + vf_i; + vf = nic_data->vf + vf_i; ivi->vf = vf_i; ether_addr_copy(ivi->mac, vf->addr.mac_addr); From 834e23dd0a27b5f0d424cc5a41bed42a6a588479 Mon Sep 17 00:00:00 2001 From: Shradha Shah Date: Wed, 6 May 2015 00:55:58 +0100 Subject: [PATCH 03/14] sfc: Enable VF's via a write to the sysfs file sriov_numvfs This patch adds support for the use of sriov_configure on EF10 to enable Virtual Functions while the driver is loaded. Signed-off-by: Shradha Shah Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/Makefile | 2 +- drivers/net/ethernet/sfc/ef10.c | 1 + drivers/net/ethernet/sfc/ef10_sriov.c | 47 ++++++++++++++++++++++++++ drivers/net/ethernet/sfc/ef10_sriov.h | 2 ++ drivers/net/ethernet/sfc/efx.c | 23 +++++++++++++ drivers/net/ethernet/sfc/net_driver.h | 1 + drivers/net/ethernet/sfc/siena.c | 1 + drivers/net/ethernet/sfc/siena_sriov.c | 5 +++ drivers/net/ethernet/sfc/siena_sriov.h | 1 + 9 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ethernet/sfc/ef10_sriov.c diff --git a/drivers/net/ethernet/sfc/Makefile b/drivers/net/ethernet/sfc/Makefile index a08a789f8378..ce8470fe79d5 100644 --- a/drivers/net/ethernet/sfc/Makefile +++ b/drivers/net/ethernet/sfc/Makefile @@ -3,6 +3,6 @@ sfc-y += efx.o nic.o farch.o falcon.o siena.o ef10.o tx.o \ tenxpress.o txc43128_phy.o falcon_boards.o \ mcdi.o mcdi_port.o mcdi_mon.o ptp.o sfc-$(CONFIG_SFC_MTD) += mtd.o -sfc-$(CONFIG_SFC_SRIOV) += sriov.o siena_sriov.o +sfc-$(CONFIG_SFC_SRIOV) += sriov.o siena_sriov.o ef10_sriov.o obj-$(CONFIG_SFC) += sfc.o diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index a031f7bc005e..e8450bbd292d 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -3691,6 +3691,7 @@ const struct efx_nic_type efx_hunt_a0_nic_type = { .ptp_set_ts_sync_events = efx_ef10_ptp_set_ts_sync_events, .ptp_set_ts_config = efx_ef10_ptp_set_ts_config, #ifdef CONFIG_SFC_SRIOV + .sriov_configure = efx_ef10_sriov_configure, .sriov_init = efx_ef10_sriov_init, .sriov_fini = efx_ef10_sriov_fini, .sriov_mac_address_changed = efx_ef10_sriov_mac_address_changed, diff --git a/drivers/net/ethernet/sfc/ef10_sriov.c b/drivers/net/ethernet/sfc/ef10_sriov.c new file mode 100644 index 000000000000..63d7b0d9deb1 --- /dev/null +++ b/drivers/net/ethernet/sfc/ef10_sriov.c @@ -0,0 +1,47 @@ +/**************************************************************************** + * Driver for Solarflare network controllers and boards + * Copyright 2015 Solarflare Communications Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, incorporated herein by reference. + */ +#include +#include +#include "net_driver.h" +#include "ef10_sriov.h" +#include "efx.h" +#include "nic.h" +#include "mcdi_pcol.h" + +static int efx_ef10_pci_sriov_enable(struct efx_nic *efx, int num_vfs) +{ + int rc = 0; + struct pci_dev *dev = efx->pci_dev; + + efx->vf_count = num_vfs; + rc = pci_enable_sriov(dev, num_vfs); + if (rc) { + efx->vf_count = 0; + netif_err(efx, probe, efx->net_dev, + "Failed to enable SRIOV VFs\n"); + } + return rc; +} + +static int efx_ef10_pci_sriov_disable(struct efx_nic *efx) +{ + struct pci_dev *dev = efx->pci_dev; + + efx->vf_count = 0; + pci_disable_sriov(dev); + return 0; +} + +int efx_ef10_sriov_configure(struct efx_nic *efx, int num_vfs) +{ + if (num_vfs == 0) + return efx_ef10_pci_sriov_disable(efx); + else + return efx_ef10_pci_sriov_enable(efx, num_vfs); +} diff --git a/drivers/net/ethernet/sfc/ef10_sriov.h b/drivers/net/ethernet/sfc/ef10_sriov.h index 1ba9ecc6d78f..5f26d1bb8bea 100644 --- a/drivers/net/ethernet/sfc/ef10_sriov.h +++ b/drivers/net/ethernet/sfc/ef10_sriov.h @@ -17,6 +17,8 @@ static inline bool efx_ef10_sriov_wanted(struct efx_nic *efx) return false; } +int efx_ef10_sriov_configure(struct efx_nic *efx, int num_vfs); + static inline int efx_ef10_sriov_init(struct efx_nic *efx) { return -EOPNOTSUPP; diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index fe8fe20eaa77..917b137f1452 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -3046,6 +3046,26 @@ static int efx_pci_probe(struct pci_dev *pci_dev, return rc; } +/* efx_pci_sriov_configure returns the actual number of Virtual Functions + * enabled on success + */ +#ifdef CONFIG_SFC_SRIOV +static int efx_pci_sriov_configure(struct pci_dev *dev, int num_vfs) +{ + int rc; + struct efx_nic *efx = pci_get_drvdata(dev); + + if (efx->type->sriov_configure) { + rc = efx->type->sriov_configure(efx, num_vfs); + if (rc) + return rc; + else + return num_vfs; + } else + return -EOPNOTSUPP; +} +#endif + static int efx_pm_freeze(struct device *dev) { struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); @@ -3268,6 +3288,9 @@ static struct pci_driver efx_pci_driver = { .remove = efx_pci_remove, .driver.pm = &efx_pm_ops, .err_handler = &efx_err_handlers, +#ifdef CONFIG_SFC_SRIOV + .sriov_configure = efx_pci_sriov_configure, +#endif }; /************************************************************************** diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index e3054b2a71f7..339dc326d37e 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -1327,6 +1327,7 @@ struct efx_nic_type { int (*ptp_set_ts_sync_events)(struct efx_nic *efx, bool en, bool temp); int (*ptp_set_ts_config)(struct efx_nic *efx, struct hwtstamp_config *init); + int (*sriov_configure)(struct efx_nic *efx, int num_vfs); int (*sriov_init)(struct efx_nic *efx); void (*sriov_fini)(struct efx_nic *efx); void (*sriov_mac_address_changed)(struct efx_nic *efx); diff --git a/drivers/net/ethernet/sfc/siena.c b/drivers/net/ethernet/sfc/siena.c index b9d4ee596eff..72e8a6b26ac2 100644 --- a/drivers/net/ethernet/sfc/siena.c +++ b/drivers/net/ethernet/sfc/siena.c @@ -1000,6 +1000,7 @@ const struct efx_nic_type siena_a0_nic_type = { .ptp_write_host_time = siena_ptp_write_host_time, .ptp_set_ts_config = siena_ptp_set_ts_config, #ifdef CONFIG_SFC_SRIOV + .sriov_configure = efx_siena_sriov_configure, .sriov_init = efx_siena_sriov_init, .sriov_fini = efx_siena_sriov_fini, .sriov_mac_address_changed = efx_siena_sriov_mac_address_changed, diff --git a/drivers/net/ethernet/sfc/siena_sriov.c b/drivers/net/ethernet/sfc/siena_sriov.c index 2044e929f48d..caf701ac274f 100644 --- a/drivers/net/ethernet/sfc/siena_sriov.c +++ b/drivers/net/ethernet/sfc/siena_sriov.c @@ -1677,3 +1677,8 @@ bool efx_siena_sriov_wanted(struct efx_nic *efx) { return efx->vf_count != 0; } + +int efx_siena_sriov_configure(struct efx_nic *efx, int num_vfs) +{ + return 0; +} diff --git a/drivers/net/ethernet/sfc/siena_sriov.h b/drivers/net/ethernet/sfc/siena_sriov.h index b3a08d156943..64e3e018929e 100644 --- a/drivers/net/ethernet/sfc/siena_sriov.h +++ b/drivers/net/ethernet/sfc/siena_sriov.h @@ -41,6 +41,7 @@ ((EFX_MAX_VF_EVQ_SIZE + 2 * EFX_MAX_DMAQ_SIZE) * \ sizeof(efx_qword_t) / EFX_BUF_SIZE) +int efx_siena_sriov_configure(struct efx_nic *efx, int num_vfs); int efx_siena_sriov_init(struct efx_nic *efx); void efx_siena_sriov_fini(struct efx_nic *efx); void efx_siena_sriov_mac_address_changed(struct efx_nic *efx); From e3d3629387e5f613dea3a6231f138a4471ffe61e Mon Sep 17 00:00:00 2001 From: Shradha Shah Date: Wed, 6 May 2015 00:56:24 +0100 Subject: [PATCH 04/14] sfc: Use MCDI to set FILTER_OP_IN_TX_DOMAIN The TX_DOMAIN field is currently reserved but its safer to set it to 0 for future compatibility. Signed-off-by: Shradha Shah Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index e8450bbd292d..ad2301861609 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -2292,6 +2292,7 @@ static void efx_ef10_filter_push_prep(struct efx_nic *efx, spec->dmaq_id == EFX_FILTER_RX_DMAQ_ID_DROP ? MC_CMD_FILTER_OP_IN_RX_DEST_DROP : MC_CMD_FILTER_OP_IN_RX_DEST_HOST); + MCDI_SET_DWORD(inbuf, FILTER_OP_IN_TX_DOMAIN, 0); MCDI_SET_DWORD(inbuf, FILTER_OP_IN_TX_DEST, MC_CMD_FILTER_OP_IN_TX_DEST_DEFAULT); MCDI_SET_DWORD(inbuf, FILTER_OP_IN_RX_QUEUE, From 8d9f9dd4487e4792601759b4376441bcc9e54f95 Mon Sep 17 00:00:00 2001 From: Daniel Pieczko Date: Wed, 6 May 2015 00:56:55 +0100 Subject: [PATCH 05/14] sfc: Record [rt]x_dpcpu_fw_id in EF10 nic_data The (future) code to add/remove vswitches and vports will be dependent on the firmware variant. To simplify the checking of the firmware variant, record values for rx_dpcpu_fw_id and tx_dpcpu_fw_id in EF10 nic_data. There was only one place where this was previously used: efx_mcdi_print_fwver() in ethtool.c. The MC_CMD_GET_CAPABILITIES can be replaced and the values from nic_data used instead. Note that the printing of "?" if the MC command fails or if the outlength is incorrect no longer apply, because errors are returned in efx_ef10_init_datapath_caps() in both of these cases. Signed-off-by: Shradha Shah Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 7 +++++++ drivers/net/ethernet/sfc/mcdi.c | 22 ++++++---------------- drivers/net/ethernet/sfc/nic.h | 4 ++++ 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index ad2301861609..4f9775f6126a 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -118,6 +118,13 @@ static int efx_ef10_init_datapath_caps(struct efx_nic *efx) nic_data->datapath_caps = MCDI_DWORD(outbuf, GET_CAPABILITIES_OUT_FLAGS1); + /* record the DPCPU firmware IDs to determine VEB vswitching support. + */ + nic_data->rx_dpcpu_fw_id = + MCDI_WORD(outbuf, GET_CAPABILITIES_OUT_RX_DPCPU_FW_ID); + nic_data->tx_dpcpu_fw_id = + MCDI_WORD(outbuf, GET_CAPABILITIES_OUT_TX_DPCPU_FW_ID); + if (!(nic_data->datapath_caps & (1 << MC_CMD_GET_CAPABILITIES_OUT_TX_TSO_LBN))) { netif_err(efx, drv, efx->net_dev, diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c index 6502ada36d49..6e0c7895872e 100644 --- a/drivers/net/ethernet/sfc/mcdi.c +++ b/drivers/net/ethernet/sfc/mcdi.c @@ -1083,9 +1083,7 @@ void efx_mcdi_process_event(struct efx_channel *channel, void efx_mcdi_print_fwver(struct efx_nic *efx, char *buf, size_t len) { - MCDI_DECLARE_BUF(outbuf, - max(MC_CMD_GET_VERSION_OUT_LEN, - MC_CMD_GET_CAPABILITIES_OUT_LEN)); + MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_VERSION_OUT_LEN); size_t outlength; const __le16 *ver_words; size_t offset; @@ -1110,19 +1108,11 @@ void efx_mcdi_print_fwver(struct efx_nic *efx, char *buf, size_t len) * single version. Report which variants are running. */ if (efx_nic_rev(efx) >= EFX_REV_HUNT_A0) { - BUILD_BUG_ON(MC_CMD_GET_CAPABILITIES_IN_LEN != 0); - rc = efx_mcdi_rpc(efx, MC_CMD_GET_CAPABILITIES, NULL, 0, - outbuf, sizeof(outbuf), &outlength); - if (rc || outlength < MC_CMD_GET_CAPABILITIES_OUT_LEN) - offset += snprintf( - buf + offset, len - offset, " rx? tx?"); - else - offset += snprintf( - buf + offset, len - offset, " rx%x tx%x", - MCDI_WORD(outbuf, - GET_CAPABILITIES_OUT_RX_DPCPU_FW_ID), - MCDI_WORD(outbuf, - GET_CAPABILITIES_OUT_TX_DPCPU_FW_ID)); + struct efx_ef10_nic_data *nic_data = efx->nic_data; + + offset += snprintf(buf + offset, len - offset, " rx%x tx%x", + nic_data->rx_dpcpu_fw_id, + nic_data->tx_dpcpu_fw_id); /* It's theoretically possible for the string to exceed 31 * characters, though in practice the first three version diff --git a/drivers/net/ethernet/sfc/nic.h b/drivers/net/ethernet/sfc/nic.h index 65dcbc7f3d83..17ee3ae9eb73 100644 --- a/drivers/net/ethernet/sfc/nic.h +++ b/drivers/net/ethernet/sfc/nic.h @@ -491,6 +491,8 @@ enum { * after MC reboot * @datapath_caps: Capabilities of datapath firmware (FLAGS1 field of * %MC_CMD_GET_CAPABILITIES response) + * @rx_dpcpu_fw_id: Firmware ID of the RxDPCPU + * @tx_dpcpu_fw_id: Firmware ID of the TxDPCPU */ struct efx_ef10_nic_data { struct efx_buffer mcdi_buf; @@ -509,6 +511,8 @@ struct efx_ef10_nic_data { bool workaround_35388; bool must_check_datapath_caps; u32 datapath_caps; + unsigned int rx_dpcpu_fw_id; + unsigned int tx_dpcpu_fw_id; }; int efx_init_sriov(void); From 45b2449e3f7d870bdd06c6a8557e8d95d59f8737 Mon Sep 17 00:00:00 2001 From: Daniel Pieczko Date: Wed, 6 May 2015 00:57:14 +0100 Subject: [PATCH 06/14] sfc: record the PF's vport ID in nic_data The default port ID of EVB_PORT_ID_ASSIGNED is a "magic" number for the MCFW to select the physical port of the PF. If other vswitches and vports are created on top of the default firmware configuration, the ID of the newly created vport is then required when passed to MCDI commands. Currently, this doesn't happen so the vport_id is never changed, but a subsequent patch will change this behaviour so that other vswitches and vports are created. The vport_id recorded in nic_data is only relevant for PFs. VFs will have their vports created by their parent PF, and in that case the parent PF will record the vport ID of each VF. For a VF, nic_data->vport_id is expected to remain at the default value. Signed-off-by: Shradha Shah Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 13 +++++++++---- drivers/net/ethernet/sfc/nic.h | 2 ++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 4f9775f6126a..8db717ed5d82 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -217,6 +217,8 @@ static int efx_ef10_probe(struct efx_nic *efx) nic_data->rx_rss_context = EFX_EF10_RSS_CONTEXT_INVALID; + nic_data->vport_id = EVB_PORT_ID_ASSIGNED; + /* In case we're recovering from a crash (kexec), we want to * cancel any outstanding request by the previous user of this * function. We send a special message using the least @@ -1245,6 +1247,7 @@ static void efx_ef10_tx_init(struct efx_tx_queue *tx_queue) size_t entries = tx_queue->txd.buf.len / EFX_BUF_SIZE; struct efx_channel *channel = tx_queue->channel; struct efx_nic *efx = tx_queue->efx; + struct efx_ef10_nic_data *nic_data = efx->nic_data; size_t inlen, outlen; dma_addr_t dma_addr; efx_qword_t *txd; @@ -1259,7 +1262,7 @@ static void efx_ef10_tx_init(struct efx_tx_queue *tx_queue) INIT_TXQ_IN_FLAG_IP_CSUM_DIS, !csum_offload, INIT_TXQ_IN_FLAG_TCP_CSUM_DIS, !csum_offload); MCDI_SET_DWORD(inbuf, INIT_TXQ_IN_OWNER_ID, 0); - MCDI_SET_DWORD(inbuf, INIT_TXQ_IN_PORT_ID, EVB_PORT_ID_ASSIGNED); + MCDI_SET_DWORD(inbuf, INIT_TXQ_IN_PORT_ID, nic_data->vport_id); dma_addr = tx_queue->txd.buf.dma_addr; @@ -1390,11 +1393,12 @@ static int efx_ef10_alloc_rss_context(struct efx_nic *efx, u32 *context) { MCDI_DECLARE_BUF(inbuf, MC_CMD_RSS_CONTEXT_ALLOC_IN_LEN); MCDI_DECLARE_BUF(outbuf, MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN); + struct efx_ef10_nic_data *nic_data = efx->nic_data; size_t outlen; int rc; MCDI_SET_DWORD(inbuf, RSS_CONTEXT_ALLOC_IN_UPSTREAM_PORT_ID, - EVB_PORT_ID_ASSIGNED); + nic_data->vport_id); MCDI_SET_DWORD(inbuf, RSS_CONTEXT_ALLOC_IN_TYPE, MC_CMD_RSS_CONTEXT_ALLOC_IN_TYPE_EXCLUSIVE); MCDI_SET_DWORD(inbuf, RSS_CONTEXT_ALLOC_IN_NUM_QUEUES, @@ -1508,6 +1512,7 @@ static void efx_ef10_rx_init(struct efx_rx_queue *rx_queue) struct efx_channel *channel = efx_rx_queue_channel(rx_queue); size_t entries = rx_queue->rxd.buf.len / EFX_BUF_SIZE; struct efx_nic *efx = rx_queue->efx; + struct efx_ef10_nic_data *nic_data = efx->nic_data; size_t inlen, outlen; dma_addr_t dma_addr; int rc; @@ -1525,7 +1530,7 @@ static void efx_ef10_rx_init(struct efx_rx_queue *rx_queue) INIT_RXQ_IN_FLAG_PREFIX, 1, INIT_RXQ_IN_FLAG_TIMESTAMP, 1); MCDI_SET_DWORD(inbuf, INIT_RXQ_IN_OWNER_ID, 0); - MCDI_SET_DWORD(inbuf, INIT_RXQ_IN_PORT_ID, EVB_PORT_ID_ASSIGNED); + MCDI_SET_DWORD(inbuf, INIT_RXQ_IN_PORT_ID, nic_data->vport_id); dma_addr = rx_queue->rxd.buf.dma_addr; @@ -2294,7 +2299,7 @@ static void efx_ef10_filter_push_prep(struct efx_nic *efx, match_fields); } - MCDI_SET_DWORD(inbuf, FILTER_OP_IN_PORT_ID, EVB_PORT_ID_ASSIGNED); + MCDI_SET_DWORD(inbuf, FILTER_OP_IN_PORT_ID, nic_data->vport_id); MCDI_SET_DWORD(inbuf, FILTER_OP_IN_RX_DEST, spec->dmaq_id == EFX_FILTER_RX_DMAQ_ID_DROP ? MC_CMD_FILTER_OP_IN_RX_DEST_DROP : diff --git a/drivers/net/ethernet/sfc/nic.h b/drivers/net/ethernet/sfc/nic.h index 17ee3ae9eb73..f29e4ecad2ed 100644 --- a/drivers/net/ethernet/sfc/nic.h +++ b/drivers/net/ethernet/sfc/nic.h @@ -493,6 +493,7 @@ enum { * %MC_CMD_GET_CAPABILITIES response) * @rx_dpcpu_fw_id: Firmware ID of the RxDPCPU * @tx_dpcpu_fw_id: Firmware ID of the TxDPCPU + * @vport_id: The function's vport ID, only relevant for PFs */ struct efx_ef10_nic_data { struct efx_buffer mcdi_buf; @@ -513,6 +514,7 @@ struct efx_ef10_nic_data { u32 datapath_caps; unsigned int rx_dpcpu_fw_id; unsigned int tx_dpcpu_fw_id; + unsigned int vport_id; }; int efx_init_sriov(void); From 6d8aaaf6f7980af1d228061ec08f6411e6bb2344 Mon Sep 17 00:00:00 2001 From: Daniel Pieczko Date: Wed, 6 May 2015 00:57:34 +0100 Subject: [PATCH 07/14] sfc: create VEB vswitch and vport above default firmware setup Adds functions to allocate and free vswitches and vports; vadaptors are automatically allocated and freed when TX/RX queues are initialised and finalised. This vswitching structure is only created if the firmware supports it, so a check that full-featured firmware is running is performed first. If the MC resets, the vswitching infrastructure will need to be recreated, so mark the "must_probe_vswitching" flag when an MC reboot is detected. Don't try to create a vswitch if vf-count=0 This allocation of vswitches and vports does not currently support configuring VLAN tags, but that can be added in a future change. Signed-off-by: Shradha Shah Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 7 ++ drivers/net/ethernet/sfc/ef10_sriov.c | 121 ++++++++++++++++++++++++++ drivers/net/ethernet/sfc/ef10_sriov.h | 4 + drivers/net/ethernet/sfc/efx.c | 30 ++++++- drivers/net/ethernet/sfc/net_driver.h | 3 + drivers/net/ethernet/sfc/nic.h | 2 + drivers/net/ethernet/sfc/siena.c | 3 + 7 files changed, 167 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 8db717ed5d82..91a58962f188 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -1133,6 +1133,10 @@ static int efx_ef10_mcdi_poll_reboot(struct efx_nic *efx) /* All our allocations have been reset */ efx_ef10_reset_mc_allocations(efx); + /* Driver-created vswitches and vports must be re-created */ + nic_data->must_probe_vswitching = true; + nic_data->vport_id = EVB_PORT_ID_ASSIGNED; + /* The datapath firmware might have been changed */ nic_data->must_check_datapath_caps = true; @@ -3715,6 +3719,9 @@ const struct efx_nic_type efx_hunt_a0_nic_type = { .sriov_set_vf_vlan = efx_ef10_sriov_set_vf_vlan, .sriov_set_vf_spoofchk = efx_ef10_sriov_set_vf_spoofchk, .sriov_get_vf_config = efx_ef10_sriov_get_vf_config, + .vswitching_probe = efx_ef10_vswitching_probe, + .vswitching_restore = efx_ef10_vswitching_restore, + .vswitching_remove = efx_ef10_vswitching_remove, #endif .revision = EFX_REV_HUNT_A0, diff --git a/drivers/net/ethernet/sfc/ef10_sriov.c b/drivers/net/ethernet/sfc/ef10_sriov.c index 63d7b0d9deb1..2aba7b7234ea 100644 --- a/drivers/net/ethernet/sfc/ef10_sriov.c +++ b/drivers/net/ethernet/sfc/ef10_sriov.c @@ -45,3 +45,124 @@ int efx_ef10_sriov_configure(struct efx_nic *efx, int num_vfs) else return efx_ef10_pci_sriov_enable(efx, num_vfs); } + +static int efx_ef10_vswitch_alloc(struct efx_nic *efx, unsigned int port_id, + unsigned int vswitch_type) +{ + MCDI_DECLARE_BUF(inbuf, MC_CMD_VSWITCH_ALLOC_IN_LEN); + + MCDI_SET_DWORD(inbuf, VSWITCH_ALLOC_IN_UPSTREAM_PORT_ID, port_id); + MCDI_SET_DWORD(inbuf, VSWITCH_ALLOC_IN_TYPE, vswitch_type); + MCDI_SET_DWORD(inbuf, VSWITCH_ALLOC_IN_NUM_VLAN_TAGS, 0); + MCDI_POPULATE_DWORD_1(inbuf, VSWITCH_ALLOC_IN_FLAGS, + VSWITCH_ALLOC_IN_FLAG_AUTO_PORT, 0); + + return efx_mcdi_rpc(efx, MC_CMD_VSWITCH_ALLOC, inbuf, sizeof(inbuf), + NULL, 0, NULL); +} + +static int efx_ef10_vswitch_free(struct efx_nic *efx, unsigned int port_id) +{ + MCDI_DECLARE_BUF(inbuf, MC_CMD_VSWITCH_FREE_IN_LEN); + + MCDI_SET_DWORD(inbuf, VSWITCH_FREE_IN_UPSTREAM_PORT_ID, port_id); + + return efx_mcdi_rpc(efx, MC_CMD_VSWITCH_FREE, inbuf, sizeof(inbuf), + NULL, 0, NULL); +} + +static int efx_ef10_vport_alloc(struct efx_nic *efx, + unsigned int port_id_in, + unsigned int vport_type, + unsigned int *port_id_out) +{ + MCDI_DECLARE_BUF(inbuf, MC_CMD_VPORT_ALLOC_IN_LEN); + MCDI_DECLARE_BUF(outbuf, MC_CMD_VPORT_ALLOC_OUT_LEN); + size_t outlen; + int rc; + + EFX_WARN_ON_PARANOID(!port_id_out); + + MCDI_SET_DWORD(inbuf, VPORT_ALLOC_IN_UPSTREAM_PORT_ID, port_id_in); + MCDI_SET_DWORD(inbuf, VPORT_ALLOC_IN_TYPE, vport_type); + MCDI_SET_DWORD(inbuf, VPORT_ALLOC_IN_NUM_VLAN_TAGS, 0); + MCDI_POPULATE_DWORD_1(inbuf, VPORT_ALLOC_IN_FLAGS, + VPORT_ALLOC_IN_FLAG_AUTO_PORT, 0); + + rc = efx_mcdi_rpc(efx, MC_CMD_VPORT_ALLOC, inbuf, sizeof(inbuf), + outbuf, sizeof(outbuf), &outlen); + if (rc) + return rc; + if (outlen < MC_CMD_VPORT_ALLOC_OUT_LEN) + return -EIO; + + *port_id_out = MCDI_DWORD(outbuf, VPORT_ALLOC_OUT_VPORT_ID); + return 0; +} + +static int efx_ef10_vport_free(struct efx_nic *efx, unsigned int port_id) +{ + MCDI_DECLARE_BUF(inbuf, MC_CMD_VPORT_FREE_IN_LEN); + + MCDI_SET_DWORD(inbuf, VPORT_FREE_IN_VPORT_ID, port_id); + + return efx_mcdi_rpc(efx, MC_CMD_VPORT_FREE, inbuf, sizeof(inbuf), + NULL, 0, NULL); +} + +/* On top of the default firmware vswitch setup, create a VEB vswitch and + * expansion vport for use by this function. + */ +int efx_ef10_vswitching_probe(struct efx_nic *efx) +{ + struct efx_ef10_nic_data *nic_data = efx->nic_data; + int rc; + + if (pci_sriov_get_totalvfs(efx->pci_dev) <= 0) + return 0; /* vswitch not needed as we have no VFs */ + + rc = efx_ef10_vswitch_alloc(efx, EVB_PORT_ID_ASSIGNED, + MC_CMD_VSWITCH_ALLOC_IN_VSWITCH_TYPE_VEB); + if (rc) + goto fail1; + + rc = efx_ef10_vport_alloc(efx, EVB_PORT_ID_ASSIGNED, + MC_CMD_VPORT_ALLOC_IN_VPORT_TYPE_NORMAL, + &nic_data->vport_id); + if (rc) + goto fail2; + + return 0; +fail2: + efx_ef10_vswitch_free(efx, EVB_PORT_ID_ASSIGNED); +fail1: + return rc; +} + +int efx_ef10_vswitching_restore(struct efx_nic *efx) +{ + struct efx_ef10_nic_data *nic_data = efx->nic_data; + int rc; + + if (!nic_data->must_probe_vswitching) + return 0; + + rc = efx_ef10_vswitching_probe(efx); + + if (!rc) + nic_data->must_probe_vswitching = false; + return rc; +} + +void efx_ef10_vswitching_remove(struct efx_nic *efx) +{ + struct efx_ef10_nic_data *nic_data = efx->nic_data; + + if (nic_data->vport_id == EVB_PORT_ID_ASSIGNED) + return; /* No vswitch was ever created */ + + efx_ef10_vport_free(efx, nic_data->vport_id); + nic_data->vport_id = EVB_PORT_ID_ASSIGNED; + + efx_ef10_vswitch_free(efx, nic_data->vport_id); +} diff --git a/drivers/net/ethernet/sfc/ef10_sriov.h b/drivers/net/ethernet/sfc/ef10_sriov.h index 5f26d1bb8bea..676b00ced063 100644 --- a/drivers/net/ethernet/sfc/ef10_sriov.h +++ b/drivers/net/ethernet/sfc/ef10_sriov.h @@ -53,4 +53,8 @@ static inline int efx_ef10_sriov_get_vf_config(struct efx_nic *efx, int vf, return -EOPNOTSUPP; } +int efx_ef10_vswitching_probe(struct efx_nic *efx); +int efx_ef10_vswitching_restore(struct efx_nic *efx); +void efx_ef10_vswitching_remove(struct efx_nic *efx); + #endif /* EF10_SRIOV_H */ diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 917b137f1452..f1dd34c1b464 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -1721,21 +1721,33 @@ static int efx_probe_all(struct efx_nic *efx) } efx->rxq_entries = efx->txq_entries = EFX_DEFAULT_DMAQ_SIZE; +#ifdef CONFIG_SFC_SRIOV + rc = efx->type->vswitching_probe(efx); + if (rc) /* not fatal; the PF will still work fine */ + netif_warn(efx, probe, efx->net_dev, + "failed to setup vswitching rc=%d;" + " VFs may not function\n", rc); +#endif + rc = efx_probe_filters(efx); if (rc) { netif_err(efx, probe, efx->net_dev, "failed to create filter tables\n"); - goto fail3; + goto fail4; } rc = efx_probe_channels(efx); if (rc) - goto fail4; + goto fail5; return 0; - fail4: + fail5: efx_remove_filters(efx); + fail4: +#ifdef CONFIG_SFC_SRIOV + efx->type->vswitching_remove(efx); +#endif fail3: efx_remove_port(efx); fail2: @@ -1825,6 +1837,9 @@ static void efx_remove_all(struct efx_nic *efx) { efx_remove_channels(efx); efx_remove_filters(efx); +#ifdef CONFIG_SFC_SRIOV + efx->type->vswitching_remove(efx); +#endif efx_remove_port(efx); efx_remove_nic(efx); } @@ -2417,6 +2432,15 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok) rc = efx_enable_interrupts(efx); if (rc) goto fail; + +#ifdef CONFIG_SFC_SRIOV + rc = efx->type->vswitching_restore(efx); + if (rc) /* not fatal; the PF will still work fine */ + netif_warn(efx, probe, efx->net_dev, + "failed to restore vswitching rc=%d;" + " VFs may not function\n", rc); +#endif + efx_restore_filters(efx); if (efx->type->sriov_reset) efx->type->sriov_reset(efx); diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index 339dc326d37e..0cb3e0e3c784 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -1341,6 +1341,9 @@ struct efx_nic_type { bool spoofchk); int (*sriov_get_vf_config)(struct efx_nic *efx, int vf_i, struct ifla_vf_info *ivi); + int (*vswitching_probe)(struct efx_nic *efx); + int (*vswitching_restore)(struct efx_nic *efx); + void (*vswitching_remove)(struct efx_nic *efx); int revision; unsigned int txd_ptr_tbl_base; diff --git a/drivers/net/ethernet/sfc/nic.h b/drivers/net/ethernet/sfc/nic.h index f29e4ecad2ed..d7dcc0193200 100644 --- a/drivers/net/ethernet/sfc/nic.h +++ b/drivers/net/ethernet/sfc/nic.h @@ -494,6 +494,7 @@ enum { * @rx_dpcpu_fw_id: Firmware ID of the RxDPCPU * @tx_dpcpu_fw_id: Firmware ID of the TxDPCPU * @vport_id: The function's vport ID, only relevant for PFs + * @must_probe_vswitching: Flag: vswitching has yet to be setup after MC reboot */ struct efx_ef10_nic_data { struct efx_buffer mcdi_buf; @@ -515,6 +516,7 @@ struct efx_ef10_nic_data { unsigned int rx_dpcpu_fw_id; unsigned int tx_dpcpu_fw_id; unsigned int vport_id; + bool must_probe_vswitching; }; int efx_init_sriov(void); diff --git a/drivers/net/ethernet/sfc/siena.c b/drivers/net/ethernet/sfc/siena.c index 72e8a6b26ac2..5c2995eafd00 100644 --- a/drivers/net/ethernet/sfc/siena.c +++ b/drivers/net/ethernet/sfc/siena.c @@ -1011,6 +1011,9 @@ const struct efx_nic_type siena_a0_nic_type = { .sriov_set_vf_vlan = efx_siena_sriov_set_vf_vlan, .sriov_set_vf_spoofchk = efx_siena_sriov_set_vf_spoofchk, .sriov_get_vf_config = efx_siena_sriov_get_vf_config, + .vswitching_probe = efx_port_dummy_op_int, + .vswitching_restore = efx_port_dummy_op_int, + .vswitching_remove = efx_port_dummy_op_void, #endif .revision = EFX_REV_SIENA_A0, From 1cd9ecbbe6e9261578510962ad899415053acc1d Mon Sep 17 00:00:00 2001 From: Daniel Pieczko Date: Wed, 6 May 2015 00:57:53 +0100 Subject: [PATCH 08/14] sfc: get the PF number and record in nic_data Use MC_CMD_GET_FUNCTION_INFO to record the PF number in nic_data. This will be needed when assigned vports to VFs. Signed-off-by: Shradha Shah Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 22 ++++++++++++++++++++++ drivers/net/ethernet/sfc/nic.h | 2 ++ 2 files changed, 24 insertions(+) diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 91a58962f188..4d6d194dbc4c 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -96,6 +96,24 @@ static unsigned int efx_ef10_mem_map_size(struct efx_nic *efx) return resource_size(&efx->pci_dev->resource[EFX_MEM_BAR]); } +static int efx_ef10_get_pf_index(struct efx_nic *efx) +{ + MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_FUNCTION_INFO_OUT_LEN); + struct efx_ef10_nic_data *nic_data = efx->nic_data; + size_t outlen; + int rc; + + rc = efx_mcdi_rpc(efx, MC_CMD_GET_FUNCTION_INFO, NULL, 0, outbuf, + sizeof(outbuf), &outlen); + if (rc) + return rc; + if (outlen < sizeof(outbuf)) + return -EIO; + + nic_data->pf_index = MCDI_DWORD(outbuf, GET_FUNCTION_INFO_OUT_PF); + return 0; +} + static int efx_ef10_init_datapath_caps(struct efx_nic *efx) { MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_CAPABILITIES_OUT_LEN); @@ -240,6 +258,10 @@ static int efx_ef10_probe(struct efx_nic *efx) if (rc) goto fail3; + rc = efx_ef10_get_pf_index(efx); + if (rc) + goto fail3; + rc = efx_ef10_init_datapath_caps(efx); if (rc < 0) goto fail3; diff --git a/drivers/net/ethernet/sfc/nic.h b/drivers/net/ethernet/sfc/nic.h index d7dcc0193200..3ab88401a5fd 100644 --- a/drivers/net/ethernet/sfc/nic.h +++ b/drivers/net/ethernet/sfc/nic.h @@ -495,6 +495,7 @@ enum { * @tx_dpcpu_fw_id: Firmware ID of the TxDPCPU * @vport_id: The function's vport ID, only relevant for PFs * @must_probe_vswitching: Flag: vswitching has yet to be setup after MC reboot + * @pf_index: The number for this PF, or the parent PF if this is a VF */ struct efx_ef10_nic_data { struct efx_buffer mcdi_buf; @@ -517,6 +518,7 @@ struct efx_ef10_nic_data { unsigned int tx_dpcpu_fw_id; unsigned int vport_id; bool must_probe_vswitching; + unsigned int pf_index; }; int efx_init_sriov(void); From 02246a7f966c2e66ff0453d12d9b8d1bff895cf9 Mon Sep 17 00:00:00 2001 From: Shradha Shah Date: Wed, 6 May 2015 00:58:14 +0100 Subject: [PATCH 09/14] sfc: Prepare to bind the sfc driver to the VF. Added efx_nic_type structure for VF. Mapped a different BAR for VF as it uses BAR 0 for memory. Added functions sriov_init and sriov_fini. Signed-off-by: Shradha Shah Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 143 +++++++++++++++++++++++++- drivers/net/ethernet/sfc/ef10_sriov.c | 17 +++ drivers/net/ethernet/sfc/ef10_sriov.h | 9 +- drivers/net/ethernet/sfc/efx.c | 15 ++- drivers/net/ethernet/sfc/efx.h | 2 + drivers/net/ethernet/sfc/falcon.c | 2 + drivers/net/ethernet/sfc/net_driver.h | 2 + drivers/net/ethernet/sfc/nic.h | 1 + drivers/net/ethernet/sfc/siena.c | 1 + 9 files changed, 176 insertions(+), 16 deletions(-) diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 4d6d194dbc4c..ae98e423e426 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -93,7 +93,10 @@ static int efx_ef10_get_warm_boot_count(struct efx_nic *efx) static unsigned int efx_ef10_mem_map_size(struct efx_nic *efx) { - return resource_size(&efx->pci_dev->resource[EFX_MEM_BAR]); + int bar; + + bar = efx->type->mem_bar; + return resource_size(&efx->pci_dev->resource[bar]); } static int efx_ef10_get_pf_index(struct efx_nic *efx) @@ -204,7 +207,7 @@ static int efx_ef10_probe(struct efx_nic *efx) efx->max_channels = min_t(unsigned int, EFX_MAX_CHANNELS, - resource_size(&efx->pci_dev->resource[EFX_MEM_BAR]) / + efx_ef10_mem_map_size(efx) / (EFX_VI_PAGE_SIZE * EFX_TXQ_TYPES)); if (WARN_ON(efx->max_channels == 0)) return -EIO; @@ -311,6 +314,23 @@ fail1: return rc; } +static int efx_ef10_probe_pf(struct efx_nic *efx) +{ + return efx_ef10_probe(efx); +} + +#ifdef CONFIG_SFC_SRIOV +static int efx_ef10_probe_vf(struct efx_nic *efx) +{ + return efx_ef10_probe(efx); +} +#else +static int efx_ef10_probe_vf(struct efx_nic *efx __attribute__ ((unused))) +{ + return 0; +} +#endif + static int efx_ef10_free_vis(struct efx_nic *efx) { MCDI_DECLARE_BUF_OUT_OR_ERR(outbuf, 0); @@ -1076,6 +1096,14 @@ static void efx_ef10_push_irq_moderation(struct efx_channel *channel) } } +static void efx_ef10_get_wol_vf(struct efx_nic *efx, + struct ethtool_wolinfo *wol) {} + +static int efx_ef10_set_wol_vf(struct efx_nic *efx, u32 type) +{ + return -EOPNOTSUPP; +} + static void efx_ef10_get_wol(struct efx_nic *efx, struct ethtool_wolinfo *wol) { wol->supported = 0; @@ -3534,6 +3562,9 @@ static void efx_ef10_ptp_write_host_time(struct efx_nic *efx, u32 host_time) _efx_writed(efx, cpu_to_le32(host_time), ER_DZ_MC_DB_LWRD); } +static void efx_ef10_ptp_write_host_time_vf(struct efx_nic *efx, + u32 host_time) {} + static int efx_ef10_rx_enable_timestamping(struct efx_channel *channel, bool temp) { @@ -3611,6 +3642,12 @@ static int efx_ef10_ptp_set_ts_sync_events(struct efx_nic *efx, bool en, return 0; } +static int efx_ef10_ptp_set_ts_config_vf(struct efx_nic *efx, + struct hwtstamp_config *init) +{ + return -EOPNOTSUPP; +} + static int efx_ef10_ptp_set_ts_config(struct efx_nic *efx, struct hwtstamp_config *init) { @@ -3647,9 +3684,107 @@ static int efx_ef10_ptp_set_ts_config(struct efx_nic *efx, } } -const struct efx_nic_type efx_hunt_a0_nic_type = { +const struct efx_nic_type efx_hunt_a0_vf_nic_type = { + .mem_bar = EFX_MEM_VF_BAR, .mem_map_size = efx_ef10_mem_map_size, - .probe = efx_ef10_probe, + .probe = efx_ef10_probe_vf, + .remove = efx_ef10_remove, + .dimension_resources = efx_ef10_dimension_resources, + .init = efx_ef10_init_nic, + .fini = efx_port_dummy_op_void, + .map_reset_reason = efx_mcdi_map_reset_reason, + .map_reset_flags = efx_ef10_map_reset_flags, + .reset = efx_ef10_reset, + .probe_port = efx_mcdi_port_probe, + .remove_port = efx_mcdi_port_remove, + .fini_dmaq = efx_ef10_fini_dmaq, + .prepare_flr = efx_ef10_prepare_flr, + .finish_flr = efx_port_dummy_op_void, + .describe_stats = efx_ef10_describe_stats, + .update_stats = efx_ef10_update_stats, + .start_stats = efx_port_dummy_op_void, + .pull_stats = efx_port_dummy_op_void, + .stop_stats = efx_port_dummy_op_void, + .set_id_led = efx_mcdi_set_id_led, + .push_irq_moderation = efx_ef10_push_irq_moderation, + .reconfigure_mac = efx_ef10_mac_reconfigure, + .check_mac_fault = efx_mcdi_mac_check_fault, + .reconfigure_port = efx_mcdi_port_reconfigure, + .get_wol = efx_ef10_get_wol_vf, + .set_wol = efx_ef10_set_wol_vf, + .resume_wol = efx_port_dummy_op_void, + .mcdi_request = efx_ef10_mcdi_request, + .mcdi_poll_response = efx_ef10_mcdi_poll_response, + .mcdi_read_response = efx_ef10_mcdi_read_response, + .mcdi_poll_reboot = efx_ef10_mcdi_poll_reboot, + .irq_enable_master = efx_port_dummy_op_void, + .irq_test_generate = efx_ef10_irq_test_generate, + .irq_disable_non_ev = efx_port_dummy_op_void, + .irq_handle_msi = efx_ef10_msi_interrupt, + .irq_handle_legacy = efx_ef10_legacy_interrupt, + .tx_probe = efx_ef10_tx_probe, + .tx_init = efx_ef10_tx_init, + .tx_remove = efx_ef10_tx_remove, + .tx_write = efx_ef10_tx_write, + .rx_push_rss_config = efx_ef10_rx_push_rss_config, + .rx_probe = efx_ef10_rx_probe, + .rx_init = efx_ef10_rx_init, + .rx_remove = efx_ef10_rx_remove, + .rx_write = efx_ef10_rx_write, + .rx_defer_refill = efx_ef10_rx_defer_refill, + .ev_probe = efx_ef10_ev_probe, + .ev_init = efx_ef10_ev_init, + .ev_fini = efx_ef10_ev_fini, + .ev_remove = efx_ef10_ev_remove, + .ev_process = efx_ef10_ev_process, + .ev_read_ack = efx_ef10_ev_read_ack, + .ev_test_generate = efx_ef10_ev_test_generate, + .filter_table_probe = efx_ef10_filter_table_probe, + .filter_table_restore = efx_ef10_filter_table_restore, + .filter_table_remove = efx_ef10_filter_table_remove, + .filter_update_rx_scatter = efx_ef10_filter_update_rx_scatter, + .filter_insert = efx_ef10_filter_insert, + .filter_remove_safe = efx_ef10_filter_remove_safe, + .filter_get_safe = efx_ef10_filter_get_safe, + .filter_clear_rx = efx_ef10_filter_clear_rx, + .filter_count_rx_used = efx_ef10_filter_count_rx_used, + .filter_get_rx_id_limit = efx_ef10_filter_get_rx_id_limit, + .filter_get_rx_ids = efx_ef10_filter_get_rx_ids, +#ifdef CONFIG_RFS_ACCEL + .filter_rfs_insert = efx_ef10_filter_rfs_insert, + .filter_rfs_expire_one = efx_ef10_filter_rfs_expire_one, +#endif +#ifdef CONFIG_SFC_MTD + .mtd_probe = efx_port_dummy_op_int, +#endif + .ptp_write_host_time = efx_ef10_ptp_write_host_time_vf, + .ptp_set_ts_config = efx_ef10_ptp_set_ts_config_vf, +#ifdef CONFIG_SFC_SRIOV + .vswitching_probe = efx_port_dummy_op_int, + .vswitching_restore = efx_port_dummy_op_int, + .vswitching_remove = efx_port_dummy_op_void, +#endif + .revision = EFX_REV_HUNT_A0, + .max_dma_mask = DMA_BIT_MASK(ESF_DZ_TX_KER_BUF_ADDR_WIDTH), + .rx_prefix_size = ES_DZ_RX_PREFIX_SIZE, + .rx_hash_offset = ES_DZ_RX_PREFIX_HASH_OFST, + .rx_ts_offset = ES_DZ_RX_PREFIX_TSTAMP_OFST, + .can_rx_scatter = true, + .always_rx_scatter = true, + .max_interrupt_mode = EFX_INT_MODE_MSIX, + .timer_period_max = 1 << ERF_DD_EVQ_IND_TIMER_VAL_WIDTH, + .offload_features = (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_RXHASH | NETIF_F_NTUPLE), + .mcdi_max_ver = 2, + .max_rx_ip_filters = HUNT_FILTER_TBL_ROWS, + .hwtstamp_filters = 1 << HWTSTAMP_FILTER_NONE | + 1 << HWTSTAMP_FILTER_ALL, +}; + +const struct efx_nic_type efx_hunt_a0_nic_type = { + .mem_bar = EFX_MEM_BAR, + .mem_map_size = efx_ef10_mem_map_size, + .probe = efx_ef10_probe_pf, .remove = efx_ef10_remove, .dimension_resources = efx_ef10_dimension_resources, .init = efx_ef10_init_nic, diff --git a/drivers/net/ethernet/sfc/ef10_sriov.c b/drivers/net/ethernet/sfc/ef10_sriov.c index 2aba7b7234ea..be74a7065bad 100644 --- a/drivers/net/ethernet/sfc/ef10_sriov.c +++ b/drivers/net/ethernet/sfc/ef10_sriov.c @@ -46,6 +46,23 @@ int efx_ef10_sriov_configure(struct efx_nic *efx, int num_vfs) return efx_ef10_pci_sriov_enable(efx, num_vfs); } +int efx_ef10_sriov_init(struct efx_nic *efx) +{ + return 0; +} + +void efx_ef10_sriov_fini(struct efx_nic *efx) +{ + int rc; + + rc = efx_ef10_pci_sriov_disable(efx); + if (rc) + netif_dbg(efx, drv, efx->net_dev, + "Disabling SRIOV was not successful rc=%d\n", rc); + else + netif_dbg(efx, drv, efx->net_dev, "SRIOV disabled\n"); +} + static int efx_ef10_vswitch_alloc(struct efx_nic *efx, unsigned int port_id, unsigned int vswitch_type) { diff --git a/drivers/net/ethernet/sfc/ef10_sriov.h b/drivers/net/ethernet/sfc/ef10_sriov.h index 676b00ced063..40833dbdb973 100644 --- a/drivers/net/ethernet/sfc/ef10_sriov.h +++ b/drivers/net/ethernet/sfc/ef10_sriov.h @@ -18,15 +18,10 @@ static inline bool efx_ef10_sriov_wanted(struct efx_nic *efx) } int efx_ef10_sriov_configure(struct efx_nic *efx, int num_vfs); - -static inline int efx_ef10_sriov_init(struct efx_nic *efx) -{ - return -EOPNOTSUPP; -} - +int efx_ef10_sriov_init(struct efx_nic *efx); static inline void efx_ef10_sriov_mac_address_changed(struct efx_nic *efx) {} static inline void efx_ef10_sriov_reset(struct efx_nic *efx) {} -static inline void efx_ef10_sriov_fini(struct efx_nic *efx) {} +void efx_ef10_sriov_fini(struct efx_nic *efx); static inline void efx_ef10_sriov_flr(struct efx_nic *efx, unsigned vf_i) {} static inline int efx_ef10_sriov_set_vf_mac(struct efx_nic *efx, int vf, diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index f1dd34c1b464..8b2edda65d73 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -1201,10 +1201,12 @@ static int efx_init_io(struct efx_nic *efx) struct pci_dev *pci_dev = efx->pci_dev; dma_addr_t dma_mask = efx->type->max_dma_mask; unsigned int mem_map_size = efx->type->mem_map_size(efx); - int rc; + int rc, bar; netif_dbg(efx, probe, efx->net_dev, "initialising I/O\n"); + bar = efx->type->mem_bar; + rc = pci_enable_device(pci_dev); if (rc) { netif_err(efx, probe, efx->net_dev, @@ -1235,8 +1237,8 @@ static int efx_init_io(struct efx_nic *efx) netif_dbg(efx, probe, efx->net_dev, "using DMA mask %llx\n", (unsigned long long) dma_mask); - efx->membase_phys = pci_resource_start(efx->pci_dev, EFX_MEM_BAR); - rc = pci_request_region(pci_dev, EFX_MEM_BAR, "sfc"); + efx->membase_phys = pci_resource_start(efx->pci_dev, bar); + rc = pci_request_region(pci_dev, bar, "sfc"); if (rc) { netif_err(efx, probe, efx->net_dev, "request for memory BAR failed\n"); @@ -1259,7 +1261,7 @@ static int efx_init_io(struct efx_nic *efx) return 0; fail4: - pci_release_region(efx->pci_dev, EFX_MEM_BAR); + pci_release_region(efx->pci_dev, bar); fail3: efx->membase_phys = 0; fail2: @@ -1270,6 +1272,8 @@ static int efx_init_io(struct efx_nic *efx) static void efx_fini_io(struct efx_nic *efx) { + int bar; + netif_dbg(efx, drv, efx->net_dev, "shutting down I/O\n"); if (efx->membase) { @@ -1278,7 +1282,8 @@ static void efx_fini_io(struct efx_nic *efx) } if (efx->membase_phys) { - pci_release_region(efx->pci_dev, EFX_MEM_BAR); + bar = efx->type->mem_bar; + pci_release_region(efx->pci_dev, bar); efx->membase_phys = 0; } diff --git a/drivers/net/ethernet/sfc/efx.h b/drivers/net/ethernet/sfc/efx.h index bc4e4b3e6aad..946607fbc0cc 100644 --- a/drivers/net/ethernet/sfc/efx.h +++ b/drivers/net/ethernet/sfc/efx.h @@ -15,7 +15,9 @@ #include "filter.h" /* All controllers use BAR 0 for I/O space and BAR 2(&3) for memory */ +/* All VFs use BAR 0/1 for memory */ #define EFX_MEM_BAR 2 +#define EFX_MEM_VF_BAR 0 /* TX */ int efx_probe_tx_queue(struct efx_tx_queue *tx_queue); diff --git a/drivers/net/ethernet/sfc/falcon.c b/drivers/net/ethernet/sfc/falcon.c index 157037546d30..5a23435efcfb 100644 --- a/drivers/net/ethernet/sfc/falcon.c +++ b/drivers/net/ethernet/sfc/falcon.c @@ -2687,6 +2687,7 @@ static int falcon_set_wol(struct efx_nic *efx, u32 type) */ const struct efx_nic_type falcon_a1_nic_type = { + .mem_bar = EFX_MEM_BAR, .mem_map_size = falcon_a1_mem_map_size, .probe = falcon_probe_nic, .remove = falcon_remove_nic, @@ -2783,6 +2784,7 @@ const struct efx_nic_type falcon_a1_nic_type = { }; const struct efx_nic_type falcon_b0_nic_type = { + .mem_bar = EFX_MEM_BAR, .mem_map_size = falcon_b0_mem_map_size, .probe = falcon_probe_nic, .remove = falcon_remove_nic, diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index 0cb3e0e3c784..dd7134ef58df 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -1089,6 +1089,7 @@ struct efx_mtd_partition { /** * struct efx_nic_type - Efx device type definition + * @mem_bar: Get the memory BAR * @mem_map_size: Get memory BAR mapped size * @probe: Probe the controller * @remove: Free resources allocated by probe() @@ -1223,6 +1224,7 @@ struct efx_mtd_partition { * @hwtstamp_filters: Mask of hardware timestamp filter types supported */ struct efx_nic_type { + unsigned int mem_bar; unsigned int (*mem_map_size)(struct efx_nic *efx); int (*probe)(struct efx_nic *efx); void (*remove)(struct efx_nic *efx); diff --git a/drivers/net/ethernet/sfc/nic.h b/drivers/net/ethernet/sfc/nic.h index 3ab88401a5fd..b350c396bcc5 100644 --- a/drivers/net/ethernet/sfc/nic.h +++ b/drivers/net/ethernet/sfc/nic.h @@ -555,6 +555,7 @@ extern const struct efx_nic_type falcon_a1_nic_type; extern const struct efx_nic_type falcon_b0_nic_type; extern const struct efx_nic_type siena_a0_nic_type; extern const struct efx_nic_type efx_hunt_a0_nic_type; +extern const struct efx_nic_type efx_hunt_a0_vf_nic_type; /************************************************************************** * diff --git a/drivers/net/ethernet/sfc/siena.c b/drivers/net/ethernet/sfc/siena.c index 5c2995eafd00..95babe2a213c 100644 --- a/drivers/net/ethernet/sfc/siena.c +++ b/drivers/net/ethernet/sfc/siena.c @@ -912,6 +912,7 @@ fail: */ const struct efx_nic_type siena_a0_nic_type = { + .mem_bar = EFX_MEM_BAR, .mem_map_size = siena_mem_map_size, .probe = siena_probe_nic, .remove = siena_remove_nic, From 3c5eb87605e85146a78de589b5070a37862425db Mon Sep 17 00:00:00 2001 From: Shradha Shah Date: Wed, 6 May 2015 00:58:31 +0100 Subject: [PATCH 10/14] sfc: create vports for VFs and assign random MAC addresses The parent PF creates vports for all its child VFs and adds MAC addresses to these. When the VF driver loads, it can make an MCDI call to get the MAC address that the parent PF assigned it. The parent PF also assigns a mac address to its own vport because implicit creation of a vAdaptor will only work on evb ports with MAC addresses assigned. The vport MAC address needs to be stored in the PF's nic_data struct as it can later be changed on the vadaptor (and its net_dev struct). When removing a vport the original MAC address must be deleted. A new flag is needed in the VF data structure to identify whether a vport has been assigned to the VF. This is to determine whether it needs to be un-assigned before freeing the vport. Also, attempting to un-assign a vport which is not assigned will result in an EALREADY error. Signed-off-by: Shradha Shah Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10_sriov.c | 264 ++++++++++++++++++++++---- drivers/net/ethernet/sfc/ef10_sriov.h | 12 ++ drivers/net/ethernet/sfc/nic.h | 7 + 3 files changed, 245 insertions(+), 38 deletions(-) diff --git a/drivers/net/ethernet/sfc/ef10_sriov.c b/drivers/net/ethernet/sfc/ef10_sriov.c index be74a7065bad..b9545bf03798 100644 --- a/drivers/net/ethernet/sfc/ef10_sriov.c +++ b/drivers/net/ethernet/sfc/ef10_sriov.c @@ -14,53 +14,43 @@ #include "nic.h" #include "mcdi_pcol.h" -static int efx_ef10_pci_sriov_enable(struct efx_nic *efx, int num_vfs) +static int efx_ef10_evb_port_assign(struct efx_nic *efx, unsigned int port_id, + unsigned int vf_fn) { - int rc = 0; - struct pci_dev *dev = efx->pci_dev; + MCDI_DECLARE_BUF(inbuf, MC_CMD_EVB_PORT_ASSIGN_IN_LEN); + struct efx_ef10_nic_data *nic_data = efx->nic_data; - efx->vf_count = num_vfs; - rc = pci_enable_sriov(dev, num_vfs); - if (rc) { - efx->vf_count = 0; - netif_err(efx, probe, efx->net_dev, - "Failed to enable SRIOV VFs\n"); - } - return rc; + MCDI_SET_DWORD(inbuf, EVB_PORT_ASSIGN_IN_PORT_ID, port_id); + MCDI_POPULATE_DWORD_2(inbuf, EVB_PORT_ASSIGN_IN_FUNCTION, + EVB_PORT_ASSIGN_IN_PF, nic_data->pf_index, + EVB_PORT_ASSIGN_IN_VF, vf_fn); + + return efx_mcdi_rpc(efx, MC_CMD_EVB_PORT_ASSIGN, inbuf, sizeof(inbuf), + NULL, 0, NULL); } -static int efx_ef10_pci_sriov_disable(struct efx_nic *efx) +static int efx_ef10_vport_add_mac(struct efx_nic *efx, + unsigned int port_id, u8 *mac) { - struct pci_dev *dev = efx->pci_dev; + MCDI_DECLARE_BUF(inbuf, MC_CMD_VPORT_ADD_MAC_ADDRESS_IN_LEN); - efx->vf_count = 0; - pci_disable_sriov(dev); - return 0; + MCDI_SET_DWORD(inbuf, VPORT_ADD_MAC_ADDRESS_IN_VPORT_ID, port_id); + ether_addr_copy(MCDI_PTR(inbuf, VPORT_ADD_MAC_ADDRESS_IN_MACADDR), mac); + + return efx_mcdi_rpc(efx, MC_CMD_VPORT_ADD_MAC_ADDRESS, inbuf, + sizeof(inbuf), NULL, 0, NULL); } -int efx_ef10_sriov_configure(struct efx_nic *efx, int num_vfs) +static int efx_ef10_vport_del_mac(struct efx_nic *efx, + unsigned int port_id, u8 *mac) { - if (num_vfs == 0) - return efx_ef10_pci_sriov_disable(efx); - else - return efx_ef10_pci_sriov_enable(efx, num_vfs); -} + MCDI_DECLARE_BUF(inbuf, MC_CMD_VPORT_DEL_MAC_ADDRESS_IN_LEN); -int efx_ef10_sriov_init(struct efx_nic *efx) -{ - return 0; -} + MCDI_SET_DWORD(inbuf, VPORT_DEL_MAC_ADDRESS_IN_VPORT_ID, port_id); + ether_addr_copy(MCDI_PTR(inbuf, VPORT_DEL_MAC_ADDRESS_IN_MACADDR), mac); -void efx_ef10_sriov_fini(struct efx_nic *efx) -{ - int rc; - - rc = efx_ef10_pci_sriov_disable(efx); - if (rc) - netif_dbg(efx, drv, efx->net_dev, - "Disabling SRIOV was not successful rc=%d\n", rc); - else - netif_dbg(efx, drv, efx->net_dev, "SRIOV disabled\n"); + return efx_mcdi_rpc(efx, MC_CMD_VPORT_DEL_MAC_ADDRESS, inbuf, + sizeof(inbuf), NULL, 0, NULL); } static int efx_ef10_vswitch_alloc(struct efx_nic *efx, unsigned int port_id, @@ -127,12 +117,124 @@ static int efx_ef10_vport_free(struct efx_nic *efx, unsigned int port_id) NULL, 0, NULL); } +static void efx_ef10_sriov_free_vf_vports(struct efx_nic *efx) +{ + struct efx_ef10_nic_data *nic_data = efx->nic_data; + int i; + + if (!nic_data->vf) + return; + + for (i = 0; i < efx->vf_count; i++) { + struct ef10_vf *vf = nic_data->vf + i; + + if (vf->vport_assigned) { + efx_ef10_evb_port_assign(efx, EVB_PORT_ID_NULL, i); + vf->vport_assigned = 0; + } + + if (!is_zero_ether_addr(vf->mac)) { + efx_ef10_vport_del_mac(efx, vf->vport_id, vf->mac); + eth_zero_addr(vf->mac); + } + + if (vf->vport_id) { + efx_ef10_vport_free(efx, vf->vport_id); + vf->vport_id = 0; + } + } +} + +static void efx_ef10_sriov_free_vf_vswitching(struct efx_nic *efx) +{ + struct efx_ef10_nic_data *nic_data = efx->nic_data; + + efx_ef10_sriov_free_vf_vports(efx); + kfree(nic_data->vf); + nic_data->vf = NULL; +} + +static int efx_ef10_sriov_assign_vf_vport(struct efx_nic *efx, + unsigned int vf_i) +{ + struct efx_ef10_nic_data *nic_data = efx->nic_data; + struct ef10_vf *vf = nic_data->vf + vf_i; + int rc; + + if (WARN_ON_ONCE(!nic_data->vf)) + return -EOPNOTSUPP; + + rc = efx_ef10_vport_alloc(efx, EVB_PORT_ID_ASSIGNED, + MC_CMD_VPORT_ALLOC_IN_VPORT_TYPE_NORMAL, + &vf->vport_id); + if (rc) + return rc; + + rc = efx_ef10_vport_add_mac(efx, vf->vport_id, vf->mac); + if (rc) { + eth_zero_addr(vf->mac); + return rc; + } + + rc = efx_ef10_evb_port_assign(efx, vf->vport_id, vf_i); + if (rc) + return rc; + + vf->vport_assigned = 1; + return 0; +} + +static int efx_ef10_sriov_alloc_vf_vswitching(struct efx_nic *efx) +{ + struct efx_ef10_nic_data *nic_data = efx->nic_data; + unsigned int i; + int rc; + + nic_data->vf = kcalloc(efx->vf_count, sizeof(struct ef10_vf), + GFP_KERNEL); + if (!nic_data->vf) + return -ENOMEM; + + for (i = 0; i < efx->vf_count; i++) { + random_ether_addr(nic_data->vf[i].mac); + + rc = efx_ef10_sriov_assign_vf_vport(efx, i); + if (rc) + goto fail; + } + + return 0; +fail: + efx_ef10_sriov_free_vf_vports(efx); + kfree(nic_data->vf); + nic_data->vf = NULL; + return rc; +} + +static int efx_ef10_sriov_restore_vf_vswitching(struct efx_nic *efx) +{ + unsigned int i; + int rc; + + for (i = 0; i < efx->vf_count; i++) { + rc = efx_ef10_sriov_assign_vf_vport(efx, i); + if (rc) + goto fail; + } + + return 0; +fail: + efx_ef10_sriov_free_vf_vswitching(efx); + return rc; +} + /* On top of the default firmware vswitch setup, create a VEB vswitch and * expansion vport for use by this function. */ int efx_ef10_vswitching_probe(struct efx_nic *efx) { struct efx_ef10_nic_data *nic_data = efx->nic_data; + struct net_device *net_dev = efx->net_dev; int rc; if (pci_sriov_get_totalvfs(efx->pci_dev) <= 0) @@ -149,7 +251,16 @@ int efx_ef10_vswitching_probe(struct efx_nic *efx) if (rc) goto fail2; + rc = efx_ef10_vport_add_mac(efx, nic_data->vport_id, net_dev->dev_addr); + if (rc) + goto fail3; + + ether_addr_copy(nic_data->vport_mac, net_dev->dev_addr); + return 0; +fail3: + efx_ef10_vport_free(efx, nic_data->vport_id); + nic_data->vport_id = EVB_PORT_ID_ASSIGNED; fail2: efx_ef10_vswitch_free(efx, EVB_PORT_ID_ASSIGNED); fail1: @@ -165,9 +276,15 @@ int efx_ef10_vswitching_restore(struct efx_nic *efx) return 0; rc = efx_ef10_vswitching_probe(efx); + if (rc) + goto fail; - if (!rc) - nic_data->must_probe_vswitching = false; + rc = efx_ef10_sriov_restore_vf_vswitching(efx); + if (rc) + goto fail; + + nic_data->must_probe_vswitching = false; +fail: return rc; } @@ -175,11 +292,82 @@ void efx_ef10_vswitching_remove(struct efx_nic *efx) { struct efx_ef10_nic_data *nic_data = efx->nic_data; + efx_ef10_sriov_free_vf_vswitching(efx); + if (nic_data->vport_id == EVB_PORT_ID_ASSIGNED) return; /* No vswitch was ever created */ + if (!is_zero_ether_addr(nic_data->vport_mac)) { + efx_ef10_vport_del_mac(efx, nic_data->vport_id, + efx->net_dev->dev_addr); + eth_zero_addr(nic_data->vport_mac); + } efx_ef10_vport_free(efx, nic_data->vport_id); nic_data->vport_id = EVB_PORT_ID_ASSIGNED; efx_ef10_vswitch_free(efx, nic_data->vport_id); } + +static int efx_ef10_pci_sriov_enable(struct efx_nic *efx, int num_vfs) +{ + int rc = 0; + struct pci_dev *dev = efx->pci_dev; + + efx->vf_count = num_vfs; + + rc = efx_ef10_sriov_alloc_vf_vswitching(efx); + if (rc) + goto fail1; + + rc = pci_enable_sriov(dev, num_vfs); + if (rc) + goto fail2; + + return 0; +fail2: + efx_ef10_sriov_free_vf_vswitching(efx); +fail1: + efx->vf_count = 0; + netif_err(efx, probe, efx->net_dev, + "Failed to enable SRIOV VFs\n"); + return rc; +} + +static int efx_ef10_pci_sriov_disable(struct efx_nic *efx) +{ + struct pci_dev *dev = efx->pci_dev; + + pci_disable_sriov(dev); + efx_ef10_sriov_free_vf_vswitching(efx); + efx->vf_count = 0; + return 0; +} + +int efx_ef10_sriov_configure(struct efx_nic *efx, int num_vfs) +{ + if (num_vfs == 0) + return efx_ef10_pci_sriov_disable(efx); + else + return efx_ef10_pci_sriov_enable(efx, num_vfs); +} + +int efx_ef10_sriov_init(struct efx_nic *efx) +{ + return 0; +} + +void efx_ef10_sriov_fini(struct efx_nic *efx) +{ + struct efx_ef10_nic_data *nic_data = efx->nic_data; + int rc; + + if (!nic_data->vf) + return; + + rc = efx_ef10_pci_sriov_disable(efx); + if (rc) + netif_dbg(efx, drv, efx->net_dev, + "Disabling SRIOV was not successful rc=%d\n", rc); + else + netif_dbg(efx, drv, efx->net_dev, "SRIOV disabled\n"); +} diff --git a/drivers/net/ethernet/sfc/ef10_sriov.h b/drivers/net/ethernet/sfc/ef10_sriov.h index 40833dbdb973..42d7145026a6 100644 --- a/drivers/net/ethernet/sfc/ef10_sriov.h +++ b/drivers/net/ethernet/sfc/ef10_sriov.h @@ -12,6 +12,18 @@ #include "net_driver.h" +/** + * struct ef10_vf - PF's store of VF data + * @vport_id: vport ID for the VF + * @vport_assigned: record whether the vport is currently assigned to the VF + * @mac: MAC address for the VF, zero when address is removed from the vport + */ +struct ef10_vf { + unsigned int vport_id; + unsigned int vport_assigned; + u8 mac[ETH_ALEN]; +}; + static inline bool efx_ef10_sriov_wanted(struct efx_nic *efx) { return false; diff --git a/drivers/net/ethernet/sfc/nic.h b/drivers/net/ethernet/sfc/nic.h index b350c396bcc5..e833e973b79d 100644 --- a/drivers/net/ethernet/sfc/nic.h +++ b/drivers/net/ethernet/sfc/nic.h @@ -496,6 +496,9 @@ enum { * @vport_id: The function's vport ID, only relevant for PFs * @must_probe_vswitching: Flag: vswitching has yet to be setup after MC reboot * @pf_index: The number for this PF, or the parent PF if this is a VF +#ifdef CONFIG_SFC_SRIOV + * @vf: Pointer to VF data structure +#endif */ struct efx_ef10_nic_data { struct efx_buffer mcdi_buf; @@ -519,6 +522,10 @@ struct efx_ef10_nic_data { unsigned int vport_id; bool must_probe_vswitching; unsigned int pf_index; +#ifdef CONFIG_SFC_SRIOV + struct ef10_vf *vf; +#endif + u8 vport_mac[ETH_ALEN]; }; int efx_init_sriov(void); From 7b8c7b54f0070edb207add4777e68e4e79d7c3fe Mon Sep 17 00:00:00 2001 From: Shradha Shah Date: Wed, 6 May 2015 00:58:54 +0100 Subject: [PATCH 11/14] sfc: manually allocate and free vadaptors To be able to use MC_CMD_VADAPTOR_SET_MAC, vadaptors must be manually allocated and freed as automatic vadaptors will disappear when their reference_count reaches zero, which must happen before the MAC address is changed. Vadaptors are allocated and freed in the vswitching_probe/remove functions for PFs and VFs, and this means that vadaptors are restored correctly following an MC reboot or other reset when required. Signed-off-by: Shradha Shah Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 12 ++--- drivers/net/ethernet/sfc/ef10_sriov.c | 71 ++++++++++++++++++++++++--- drivers/net/ethernet/sfc/ef10_sriov.h | 9 ++-- 3 files changed, 76 insertions(+), 16 deletions(-) diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index ae98e423e426..0dff8123da04 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -3760,9 +3760,9 @@ const struct efx_nic_type efx_hunt_a0_vf_nic_type = { .ptp_write_host_time = efx_ef10_ptp_write_host_time_vf, .ptp_set_ts_config = efx_ef10_ptp_set_ts_config_vf, #ifdef CONFIG_SFC_SRIOV - .vswitching_probe = efx_port_dummy_op_int, - .vswitching_restore = efx_port_dummy_op_int, - .vswitching_remove = efx_port_dummy_op_void, + .vswitching_probe = efx_ef10_vswitching_probe_vf, + .vswitching_restore = efx_ef10_vswitching_restore_vf, + .vswitching_remove = efx_ef10_vswitching_remove_vf, #endif .revision = EFX_REV_HUNT_A0, .max_dma_mask = DMA_BIT_MASK(ESF_DZ_TX_KER_BUF_ADDR_WIDTH), @@ -3876,9 +3876,9 @@ const struct efx_nic_type efx_hunt_a0_nic_type = { .sriov_set_vf_vlan = efx_ef10_sriov_set_vf_vlan, .sriov_set_vf_spoofchk = efx_ef10_sriov_set_vf_spoofchk, .sriov_get_vf_config = efx_ef10_sriov_get_vf_config, - .vswitching_probe = efx_ef10_vswitching_probe, - .vswitching_restore = efx_ef10_vswitching_restore, - .vswitching_remove = efx_ef10_vswitching_remove, + .vswitching_probe = efx_ef10_vswitching_probe_pf, + .vswitching_restore = efx_ef10_vswitching_restore_pf, + .vswitching_remove = efx_ef10_vswitching_remove_pf, #endif .revision = EFX_REV_HUNT_A0, diff --git a/drivers/net/ethernet/sfc/ef10_sriov.c b/drivers/net/ethernet/sfc/ef10_sriov.c index b9545bf03798..1b93acf2d28d 100644 --- a/drivers/net/ethernet/sfc/ef10_sriov.c +++ b/drivers/net/ethernet/sfc/ef10_sriov.c @@ -117,6 +117,24 @@ static int efx_ef10_vport_free(struct efx_nic *efx, unsigned int port_id) NULL, 0, NULL); } +static int efx_ef10_vadaptor_alloc(struct efx_nic *efx, unsigned int port_id) +{ + MCDI_DECLARE_BUF(inbuf, MC_CMD_VADAPTOR_ALLOC_IN_LEN); + + MCDI_SET_DWORD(inbuf, VADAPTOR_ALLOC_IN_UPSTREAM_PORT_ID, port_id); + return efx_mcdi_rpc(efx, MC_CMD_VADAPTOR_ALLOC, inbuf, sizeof(inbuf), + NULL, 0, NULL); +} + +static int efx_ef10_vadaptor_free(struct efx_nic *efx, unsigned int port_id) +{ + MCDI_DECLARE_BUF(inbuf, MC_CMD_VADAPTOR_FREE_IN_LEN); + + MCDI_SET_DWORD(inbuf, VADAPTOR_FREE_IN_UPSTREAM_PORT_ID, port_id); + return efx_mcdi_rpc(efx, MC_CMD_VADAPTOR_FREE, inbuf, sizeof(inbuf), + NULL, 0, NULL); +} + static void efx_ef10_sriov_free_vf_vports(struct efx_nic *efx) { struct efx_ef10_nic_data *nic_data = efx->nic_data; @@ -231,14 +249,17 @@ fail: /* On top of the default firmware vswitch setup, create a VEB vswitch and * expansion vport for use by this function. */ -int efx_ef10_vswitching_probe(struct efx_nic *efx) +int efx_ef10_vswitching_probe_pf(struct efx_nic *efx) { struct efx_ef10_nic_data *nic_data = efx->nic_data; struct net_device *net_dev = efx->net_dev; int rc; - if (pci_sriov_get_totalvfs(efx->pci_dev) <= 0) - return 0; /* vswitch not needed as we have no VFs */ + if (pci_sriov_get_totalvfs(efx->pci_dev) <= 0) { + /* vswitch not needed as we have no VFs */ + efx_ef10_vadaptor_alloc(efx, nic_data->vport_id); + return 0; + } rc = efx_ef10_vswitch_alloc(efx, EVB_PORT_ID_ASSIGNED, MC_CMD_VSWITCH_ALLOC_IN_VSWITCH_TYPE_VEB); @@ -254,10 +275,16 @@ int efx_ef10_vswitching_probe(struct efx_nic *efx) rc = efx_ef10_vport_add_mac(efx, nic_data->vport_id, net_dev->dev_addr); if (rc) goto fail3; - ether_addr_copy(nic_data->vport_mac, net_dev->dev_addr); + rc = efx_ef10_vadaptor_alloc(efx, nic_data->vport_id); + if (rc) + goto fail4; + return 0; +fail4: + efx_ef10_vport_del_mac(efx, nic_data->vport_id, nic_data->vport_mac); + eth_zero_addr(nic_data->vport_mac); fail3: efx_ef10_vport_free(efx, nic_data->vport_id); nic_data->vport_id = EVB_PORT_ID_ASSIGNED; @@ -267,7 +294,14 @@ fail1: return rc; } -int efx_ef10_vswitching_restore(struct efx_nic *efx) +int efx_ef10_vswitching_probe_vf(struct efx_nic *efx) +{ + struct efx_ef10_nic_data *nic_data = efx->nic_data; + + return efx_ef10_vadaptor_alloc(efx, nic_data->vport_id); +} + +int efx_ef10_vswitching_restore_pf(struct efx_nic *efx) { struct efx_ef10_nic_data *nic_data = efx->nic_data; int rc; @@ -275,7 +309,7 @@ int efx_ef10_vswitching_restore(struct efx_nic *efx) if (!nic_data->must_probe_vswitching) return 0; - rc = efx_ef10_vswitching_probe(efx); + rc = efx_ef10_vswitching_probe_pf(efx); if (rc) goto fail; @@ -288,12 +322,30 @@ fail: return rc; } -void efx_ef10_vswitching_remove(struct efx_nic *efx) +int efx_ef10_vswitching_restore_vf(struct efx_nic *efx) +{ + struct efx_ef10_nic_data *nic_data = efx->nic_data; + int rc; + + if (!nic_data->must_probe_vswitching) + return 0; + + rc = efx_ef10_vadaptor_free(efx, EVB_PORT_ID_ASSIGNED); + if (rc) + return rc; + + nic_data->must_probe_vswitching = false; + return 0; +} + +void efx_ef10_vswitching_remove_pf(struct efx_nic *efx) { struct efx_ef10_nic_data *nic_data = efx->nic_data; efx_ef10_sriov_free_vf_vswitching(efx); + efx_ef10_vadaptor_free(efx, nic_data->vport_id); + if (nic_data->vport_id == EVB_PORT_ID_ASSIGNED) return; /* No vswitch was ever created */ @@ -308,6 +360,11 @@ void efx_ef10_vswitching_remove(struct efx_nic *efx) efx_ef10_vswitch_free(efx, nic_data->vport_id); } +void efx_ef10_vswitching_remove_vf(struct efx_nic *efx) +{ + efx_ef10_vadaptor_free(efx, EVB_PORT_ID_ASSIGNED); +} + static int efx_ef10_pci_sriov_enable(struct efx_nic *efx, int num_vfs) { int rc = 0; diff --git a/drivers/net/ethernet/sfc/ef10_sriov.h b/drivers/net/ethernet/sfc/ef10_sriov.h index 42d7145026a6..86bac7ebb01a 100644 --- a/drivers/net/ethernet/sfc/ef10_sriov.h +++ b/drivers/net/ethernet/sfc/ef10_sriov.h @@ -60,8 +60,11 @@ static inline int efx_ef10_sriov_get_vf_config(struct efx_nic *efx, int vf, return -EOPNOTSUPP; } -int efx_ef10_vswitching_probe(struct efx_nic *efx); -int efx_ef10_vswitching_restore(struct efx_nic *efx); -void efx_ef10_vswitching_remove(struct efx_nic *efx); +int efx_ef10_vswitching_probe_pf(struct efx_nic *efx); +int efx_ef10_vswitching_probe_vf(struct efx_nic *efx); +int efx_ef10_vswitching_restore_pf(struct efx_nic *efx); +int efx_ef10_vswitching_restore_vf(struct efx_nic *efx); +void efx_ef10_vswitching_remove_pf(struct efx_nic *efx); +void efx_ef10_vswitching_remove_vf(struct efx_nic *efx); #endif /* EF10_SRIOV_H */ From 267d9d73872966c4e7d0271fed314d8ace65e895 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Wed, 6 May 2015 00:59:18 +0100 Subject: [PATCH 12/14] sfc: Cope with permissions enforcement added to firmware for SR-IOV * Accept EPERM in some simple cases, the following cases are handled: 1) efx_mcdi_read_assertion() Unprivileged PCI functions aren't allowed to GET_ASSERTS. We return success as it's up to the primary PF to deal with asserts. 2) efx_mcdi_mon_probe() in efx_ef10_probe() Unprivileged PCI functions aren't allowed to read sensor info, and worrying about sensor data is the primary PF's job. 3) phy_op->reconfigure() in efx_init_port() and efx_reset_up() Unprivileged functions aren't allowed to MC_CMD_SET_LINK, they just have to accept the settings (including flow-control, which is what efx_init_port() is worried about) they've been given. 4) Fallback to GET_WORKAROUNDS in efx_ef10_probe() Unprivileged PCI functions aren't allowed to set workarounds. So if efx_mcdi_set_workaround() fails EPERM, use efx_mcdi_get_workarounds() to find out if workaround_35388 is enabled. 5) If DRV_ATTACH gets EPERM, try without specifying fw-variant Unprivileged PCI functions have to use a FIRMWARE_ID of 0xffffffff (MC_CMD_FW_DONT_CARE). 6) Don't try to exit_assertion unless one had fired Previously we called efx_mcdi_exit_assertion even if efx_mcdi_read_assertion had received MC_CMD_GET_ASSERTS_FLAGS_NO_FAILS. This is unnecessary, and the resulting MC_CMD_REBOOT, even if the AFTER_ASSERTION flag made it a no-op, would fail EPERM for unprivileged PCI functions. So make efx_mcdi_read_assertion return whether an assert happened, and only call efx_mcdi_exit_assertion if it has. Signed-off-by: Shradha Shah Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 16 +++++- drivers/net/ethernet/sfc/efx.c | 5 +- drivers/net/ethernet/sfc/mcdi.c | 82 +++++++++++++++++++++++----- drivers/net/ethernet/sfc/mcdi.h | 2 + drivers/net/ethernet/sfc/mcdi_pcol.h | 23 ++++++++ 5 files changed, 111 insertions(+), 17 deletions(-) diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 0dff8123da04..ae0ed2aa6eca 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -286,10 +286,22 @@ static int efx_ef10_probe(struct efx_nic *efx) goto fail3; efx->timer_quantum_ns = 1536000 / rc; /* 1536 cycles */ - /* Check whether firmware supports bug 35388 workaround */ + /* Check whether firmware supports bug 35388 workaround. + * First try to enable it, then if we get EPERM, just + * ask if it's already enabled + */ rc = efx_mcdi_set_workaround(efx, MC_CMD_WORKAROUND_BUG35388, true); if (rc == 0) nic_data->workaround_35388 = true; + else if (rc == -EPERM) { + unsigned int enabled; + + rc = efx_mcdi_get_workarounds(efx, NULL, &enabled); + if (rc) + goto fail3; + nic_data->workaround_35388 = enabled & + MC_CMD_GET_WORKAROUNDS_OUT_BUG35388; + } else if (rc != -ENOSYS && rc != -ENOENT) goto fail3; netif_dbg(efx, probe, efx->net_dev, @@ -297,7 +309,7 @@ static int efx_ef10_probe(struct efx_nic *efx) nic_data->workaround_35388 ? "en" : "dis"); rc = efx_mcdi_mon_probe(efx); - if (rc) + if (rc && rc != -EPERM) goto fail3; efx_ptp_probe(efx, NULL); diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 8b2edda65d73..78f77605c067 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -1046,7 +1046,7 @@ static int efx_init_port(struct efx_nic *efx) /* Ensure the PHY advertises the correct flow control settings */ rc = efx->phy_op->reconfigure(efx); - if (rc) + if (rc && rc != -EPERM) goto fail2; mutex_unlock(&efx->mac_lock); @@ -2429,7 +2429,8 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok) rc = efx->phy_op->init(efx); if (rc) goto fail; - if (efx->phy_op->reconfigure(efx)) + rc = efx->phy_op->reconfigure(efx); + if (rc && rc != -EPERM) netif_err(efx, drv, efx->net_dev, "could not restore PHY settings\n"); } diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c index 6e0c7895872e..1ffe289313f1 100644 --- a/drivers/net/ethernet/sfc/mcdi.c +++ b/drivers/net/ethernet/sfc/mcdi.c @@ -1142,10 +1142,26 @@ static int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating, MCDI_SET_DWORD(inbuf, DRV_ATTACH_IN_UPDATE, 1); MCDI_SET_DWORD(inbuf, DRV_ATTACH_IN_FIRMWARE_ID, MC_CMD_FW_LOW_LATENCY); - rc = efx_mcdi_rpc(efx, MC_CMD_DRV_ATTACH, inbuf, sizeof(inbuf), - outbuf, sizeof(outbuf), &outlen); - if (rc) + rc = efx_mcdi_rpc_quiet(efx, MC_CMD_DRV_ATTACH, inbuf, sizeof(inbuf), + outbuf, sizeof(outbuf), &outlen); + /* If we're not the primary PF, trying to ATTACH with a FIRMWARE_ID + * specified will fail with EPERM, and we have to tell the MC we don't + * care what firmware we get. + */ + if (rc == -EPERM) { + netif_dbg(efx, probe, efx->net_dev, + "efx_mcdi_drv_attach with fw-variant setting failed EPERM, trying without it\n"); + MCDI_SET_DWORD(inbuf, DRV_ATTACH_IN_FIRMWARE_ID, + MC_CMD_FW_DONT_CARE); + rc = efx_mcdi_rpc_quiet(efx, MC_CMD_DRV_ATTACH, inbuf, + sizeof(inbuf), outbuf, sizeof(outbuf), + &outlen); + } + if (rc) { + efx_mcdi_display_error(efx, MC_CMD_DRV_ATTACH, sizeof(inbuf), + outbuf, outlen, rc); goto fail; + } if (outlen < MC_CMD_DRV_ATTACH_OUT_LEN) { rc = -EIO; goto fail; @@ -1377,6 +1393,9 @@ fail1: return rc; } +/* Returns 1 if an assertion was read, 0 if no assertion had fired, + * negative on error. + */ static int efx_mcdi_read_assertion(struct efx_nic *efx) { MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_ASSERTS_IN_LEN); @@ -1398,6 +1417,8 @@ static int efx_mcdi_read_assertion(struct efx_nic *efx) rc = efx_mcdi_rpc_quiet(efx, MC_CMD_GET_ASSERTS, inbuf, MC_CMD_GET_ASSERTS_IN_LEN, outbuf, sizeof(outbuf), &outlen); + if (rc == -EPERM) + return 0; } while ((rc == -EINTR || rc == -EIO) && retry-- > 0); if (rc) { @@ -1435,24 +1456,31 @@ static int efx_mcdi_read_assertion(struct efx_nic *efx) MCDI_ARRAY_DWORD(outbuf, GET_ASSERTS_OUT_GP_REGS_OFFS, index)); - return 0; + return 1; } -static void efx_mcdi_exit_assertion(struct efx_nic *efx) +static int efx_mcdi_exit_assertion(struct efx_nic *efx) { MCDI_DECLARE_BUF(inbuf, MC_CMD_REBOOT_IN_LEN); + int rc; /* If the MC is running debug firmware, it might now be * waiting for a debugger to attach, but we just want it to * reboot. We set a flag that makes the command a no-op if it - * has already done so. We don't know what return code to - * expect (0 or -EIO), so ignore it. + * has already done so. + * The MCDI will thus return either 0 or -EIO. */ BUILD_BUG_ON(MC_CMD_REBOOT_OUT_LEN != 0); MCDI_SET_DWORD(inbuf, REBOOT_IN_FLAGS, MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION); - (void) efx_mcdi_rpc(efx, MC_CMD_REBOOT, inbuf, MC_CMD_REBOOT_IN_LEN, - NULL, 0, NULL); + rc = efx_mcdi_rpc_quiet(efx, MC_CMD_REBOOT, inbuf, MC_CMD_REBOOT_IN_LEN, + NULL, 0, NULL); + if (rc == -EIO) + rc = 0; + if (rc) + efx_mcdi_display_error(efx, MC_CMD_REBOOT, MC_CMD_REBOOT_IN_LEN, + NULL, 0, rc); + return rc; } int efx_mcdi_handle_assertion(struct efx_nic *efx) @@ -1460,12 +1488,10 @@ int efx_mcdi_handle_assertion(struct efx_nic *efx) int rc; rc = efx_mcdi_read_assertion(efx); - if (rc) + if (rc <= 0) return rc; - efx_mcdi_exit_assertion(efx); - - return 0; + return efx_mcdi_exit_assertion(efx); } void efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode) @@ -1680,6 +1706,36 @@ int efx_mcdi_set_workaround(struct efx_nic *efx, u32 type, bool enabled) NULL, 0, NULL); } +int efx_mcdi_get_workarounds(struct efx_nic *efx, unsigned int *impl_out, + unsigned int *enabled_out) +{ + MCDI_DECLARE_BUF_OUT_OR_ERR(outbuf, MC_CMD_GET_WORKAROUNDS_OUT_LEN); + size_t outlen; + int rc; + + rc = efx_mcdi_rpc(efx, MC_CMD_GET_WORKAROUNDS, NULL, 0, + outbuf, sizeof(outbuf), &outlen); + if (rc) + goto fail; + + if (outlen < MC_CMD_GET_WORKAROUNDS_OUT_LEN) { + rc = -EIO; + goto fail; + } + + if (impl_out) + *impl_out = MCDI_DWORD(outbuf, GET_WORKAROUNDS_OUT_IMPLEMENTED); + + if (enabled_out) + *enabled_out = MCDI_DWORD(outbuf, GET_WORKAROUNDS_OUT_ENABLED); + + return 0; + +fail: + netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc); + return rc; +} + #ifdef CONFIG_SFC_MTD #define EFX_MCDI_NVRAM_LEN_MAX 128 diff --git a/drivers/net/ethernet/sfc/mcdi.h b/drivers/net/ethernet/sfc/mcdi.h index 56465f7465a2..5df1e986e39e 100644 --- a/drivers/net/ethernet/sfc/mcdi.h +++ b/drivers/net/ethernet/sfc/mcdi.h @@ -339,6 +339,8 @@ bool efx_mcdi_mac_check_fault(struct efx_nic *efx); enum reset_type efx_mcdi_map_reset_reason(enum reset_type reason); int efx_mcdi_reset(struct efx_nic *efx, enum reset_type method); int efx_mcdi_set_workaround(struct efx_nic *efx, u32 type, bool enabled); +int efx_mcdi_get_workarounds(struct efx_nic *efx, unsigned int *impl_out, + unsigned int *enabled_out); #ifdef CONFIG_SFC_MCDI_MON int efx_mcdi_mon_probe(struct efx_nic *efx); diff --git a/drivers/net/ethernet/sfc/mcdi_pcol.h b/drivers/net/ethernet/sfc/mcdi_pcol.h index e028de10e1b7..4fa6eb27cc56 100644 --- a/drivers/net/ethernet/sfc/mcdi_pcol.h +++ b/drivers/net/ethernet/sfc/mcdi_pcol.h @@ -1875,6 +1875,8 @@ #define MC_CMD_FW_FULL_FEATURED 0x0 /* enum: Prefer to use firmware with fewer features but lower latency */ #define MC_CMD_FW_LOW_LATENCY 0x1 +/* enum: Only this option is allowed for non-admin functions */ +#define MC_CMD_FW_DONT_CARE 0xffffffff /* MC_CMD_DRV_ATTACH_OUT msgresponse */ #define MC_CMD_DRV_ATTACH_OUT_LEN 4 @@ -4086,6 +4088,27 @@ #define LICENSED_APP_ID_ID_WIDTH 32 +/***********************************/ +/* MC_CMD_GET_WORKAROUNDS + * Read the list of all implemented and all currently enabled workarounds. The + * enums here must correspond with those in MC_CMD_WORKAROUND. + */ +#define MC_CMD_GET_WORKAROUNDS 0x59 + +/* MC_CMD_GET_WORKAROUNDS_OUT msgresponse */ +#define MC_CMD_GET_WORKAROUNDS_OUT_LEN 8 +/* Each workaround is represented by a single bit according to the enums below. + */ +#define MC_CMD_GET_WORKAROUNDS_OUT_IMPLEMENTED_OFST 0 +#define MC_CMD_GET_WORKAROUNDS_OUT_ENABLED_OFST 4 +/* enum: Bug 17230 work around. */ +#define MC_CMD_GET_WORKAROUNDS_OUT_BUG17230 0x2 +/* enum: Bug 35388 work around (unsafe EVQ writes). */ +#define MC_CMD_GET_WORKAROUNDS_OUT_BUG35388 0x4 +/* enum: Bug35017 workaround (A64 tables must be identity map) */ +#define MC_CMD_GET_WORKAROUNDS_OUT_BUG35017 0x8 + + /***********************************/ /* MC_CMD_READ_REGS * Get a dump of the MCPU registers From 267c01571bd38ea807bae1da93788d3b577661cf Mon Sep 17 00:00:00 2001 From: Jon Cooper Date: Wed, 6 May 2015 00:59:38 +0100 Subject: [PATCH 13/14] sfc: Add use of shared RSS contexts. Allow PFs to allocate shared RSS contexts if we exhaust our exclusive RSS contexts. Make VFs use shared RSS contexts in all cases. Spruce up error handling so that the shadow copy of the RSS table is updated after successful update, rather than in all cases, so that we report the actual contents of the RSS table after a failure to set it, rather than what we'd like it to be. Populate context_size parameter when vacuously allocating RSS context of size 1. Signed-off-by: Shradha Shah Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 157 ++++++++++++++++++++++---- drivers/net/ethernet/sfc/efx.c | 17 ++- drivers/net/ethernet/sfc/efx.h | 1 + drivers/net/ethernet/sfc/ethtool.c | 5 +- drivers/net/ethernet/sfc/falcon.c | 19 +++- drivers/net/ethernet/sfc/net_driver.h | 3 +- drivers/net/ethernet/sfc/nic.h | 2 + drivers/net/ethernet/sfc/siena.c | 9 +- 8 files changed, 177 insertions(+), 36 deletions(-) diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index ae0ed2aa6eca..7a67202fb1cb 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -31,6 +31,9 @@ enum { /* The reserved RSS context value */ #define EFX_EF10_RSS_CONTEXT_INVALID 0xffffffff +/* The maximum size of a shared RSS context */ +/* TODO: this should really be from the mcdi protocol export */ +#define EFX_EF10_MAX_SHARED_RSS_CONTEXT_SIZE 64UL /* The filter table(s) are managed by firmware and we have write-only * access. When removing filters we must identify them to the @@ -78,7 +81,6 @@ struct efx_ef10_filter_table { /* An arbitrary search limit for the software hash table */ #define EFX_EF10_FILTER_SEARCH_LIMIT 200 -static void efx_ef10_rx_push_rss_config(struct efx_nic *efx); static void efx_ef10_rx_free_indir_table(struct efx_nic *efx); static void efx_ef10_filter_table_remove(struct efx_nic *efx); @@ -751,7 +753,9 @@ static int efx_ef10_init_nic(struct efx_nic *efx) nic_data->must_restore_piobufs = false; } - efx_ef10_rx_push_rss_config(efx); + /* don't fail init if RSS setup doesn't work */ + efx->type->rx_push_rss_config(efx, false, efx->rx_indir_table); + return 0; } @@ -1455,20 +1459,33 @@ static void efx_ef10_tx_write(struct efx_tx_queue *tx_queue) } } -static int efx_ef10_alloc_rss_context(struct efx_nic *efx, u32 *context) +static int efx_ef10_alloc_rss_context(struct efx_nic *efx, u32 *context, + bool exclusive, unsigned *context_size) { MCDI_DECLARE_BUF(inbuf, MC_CMD_RSS_CONTEXT_ALLOC_IN_LEN); MCDI_DECLARE_BUF(outbuf, MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN); struct efx_ef10_nic_data *nic_data = efx->nic_data; size_t outlen; int rc; + u32 alloc_type = exclusive ? + MC_CMD_RSS_CONTEXT_ALLOC_IN_TYPE_EXCLUSIVE : + MC_CMD_RSS_CONTEXT_ALLOC_IN_TYPE_SHARED; + unsigned rss_spread = exclusive ? + efx->rss_spread : + min(rounddown_pow_of_two(efx->rss_spread), + EFX_EF10_MAX_SHARED_RSS_CONTEXT_SIZE); + + if (!exclusive && rss_spread == 1) { + *context = EFX_EF10_RSS_CONTEXT_INVALID; + if (context_size) + *context_size = 1; + return 0; + } MCDI_SET_DWORD(inbuf, RSS_CONTEXT_ALLOC_IN_UPSTREAM_PORT_ID, nic_data->vport_id); - MCDI_SET_DWORD(inbuf, RSS_CONTEXT_ALLOC_IN_TYPE, - MC_CMD_RSS_CONTEXT_ALLOC_IN_TYPE_EXCLUSIVE); - MCDI_SET_DWORD(inbuf, RSS_CONTEXT_ALLOC_IN_NUM_QUEUES, - EFX_MAX_CHANNELS); + MCDI_SET_DWORD(inbuf, RSS_CONTEXT_ALLOC_IN_TYPE, alloc_type); + MCDI_SET_DWORD(inbuf, RSS_CONTEXT_ALLOC_IN_NUM_QUEUES, rss_spread); rc = efx_mcdi_rpc(efx, MC_CMD_RSS_CONTEXT_ALLOC, inbuf, sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); @@ -1480,6 +1497,9 @@ static int efx_ef10_alloc_rss_context(struct efx_nic *efx, u32 *context) *context = MCDI_DWORD(outbuf, RSS_CONTEXT_ALLOC_OUT_RSS_CONTEXT_ID); + if (context_size) + *context_size = rss_spread; + return 0; } @@ -1496,7 +1516,8 @@ static void efx_ef10_free_rss_context(struct efx_nic *efx, u32 context) WARN_ON(rc != 0); } -static int efx_ef10_populate_rss_table(struct efx_nic *efx, u32 context) +static int efx_ef10_populate_rss_table(struct efx_nic *efx, u32 context, + const u32 *rx_indir_table) { MCDI_DECLARE_BUF(tablebuf, MC_CMD_RSS_CONTEXT_SET_TABLE_IN_LEN); MCDI_DECLARE_BUF(keybuf, MC_CMD_RSS_CONTEXT_SET_KEY_IN_LEN); @@ -1510,7 +1531,7 @@ static int efx_ef10_populate_rss_table(struct efx_nic *efx, u32 context) for (i = 0; i < ARRAY_SIZE(efx->rx_indir_table); ++i) MCDI_PTR(tablebuf, RSS_CONTEXT_SET_TABLE_IN_INDIRECTION_TABLE)[i] = - (u8) efx->rx_indir_table[i]; + (u8) rx_indir_table[i]; rc = efx_mcdi_rpc(efx, MC_CMD_RSS_CONTEXT_SET_TABLE, tablebuf, sizeof(tablebuf), NULL, 0, NULL); @@ -1538,27 +1559,119 @@ static void efx_ef10_rx_free_indir_table(struct efx_nic *efx) nic_data->rx_rss_context = EFX_EF10_RSS_CONTEXT_INVALID; } -static void efx_ef10_rx_push_rss_config(struct efx_nic *efx) +static int efx_ef10_rx_push_shared_rss_config(struct efx_nic *efx, + unsigned *context_size) +{ + u32 new_rx_rss_context; + struct efx_ef10_nic_data *nic_data = efx->nic_data; + int rc = efx_ef10_alloc_rss_context(efx, &new_rx_rss_context, + false, context_size); + + if (rc != 0) + return rc; + + nic_data->rx_rss_context = new_rx_rss_context; + nic_data->rx_rss_context_exclusive = false; + efx_set_default_rx_indir_table(efx); + return 0; +} + +static int efx_ef10_rx_push_exclusive_rss_config(struct efx_nic *efx, + const u32 *rx_indir_table) { struct efx_ef10_nic_data *nic_data = efx->nic_data; int rc; + u32 new_rx_rss_context; - netif_dbg(efx, drv, efx->net_dev, "pushing RSS config\n"); - - if (nic_data->rx_rss_context == EFX_EF10_RSS_CONTEXT_INVALID) { - rc = efx_ef10_alloc_rss_context(efx, &nic_data->rx_rss_context); - if (rc != 0) - goto fail; + if (nic_data->rx_rss_context == EFX_EF10_RSS_CONTEXT_INVALID || + !nic_data->rx_rss_context_exclusive) { + rc = efx_ef10_alloc_rss_context(efx, &new_rx_rss_context, + true, NULL); + if (rc == -EOPNOTSUPP) + return rc; + else if (rc != 0) + goto fail1; + } else { + new_rx_rss_context = nic_data->rx_rss_context; } - rc = efx_ef10_populate_rss_table(efx, nic_data->rx_rss_context); + rc = efx_ef10_populate_rss_table(efx, new_rx_rss_context, + rx_indir_table); if (rc != 0) - goto fail; + goto fail2; - return; + if (nic_data->rx_rss_context != new_rx_rss_context) + efx_ef10_rx_free_indir_table(efx); + nic_data->rx_rss_context = new_rx_rss_context; + nic_data->rx_rss_context_exclusive = true; + if (rx_indir_table != efx->rx_indir_table) + memcpy(efx->rx_indir_table, rx_indir_table, + sizeof(efx->rx_indir_table)); + return 0; -fail: +fail2: + if (new_rx_rss_context != nic_data->rx_rss_context) + efx_ef10_free_rss_context(efx, new_rx_rss_context); +fail1: netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc); + return rc; +} + +static int efx_ef10_pf_rx_push_rss_config(struct efx_nic *efx, bool user, + const u32 *rx_indir_table) +{ + int rc; + + if (efx->rss_spread == 1) + return 0; + + rc = efx_ef10_rx_push_exclusive_rss_config(efx, rx_indir_table); + + if (rc == -ENOBUFS && !user) { + unsigned context_size; + bool mismatch = false; + size_t i; + + for (i = 0; i < ARRAY_SIZE(efx->rx_indir_table) && !mismatch; + i++) + mismatch = rx_indir_table[i] != + ethtool_rxfh_indir_default(i, efx->rss_spread); + + rc = efx_ef10_rx_push_shared_rss_config(efx, &context_size); + if (rc == 0) { + if (context_size != efx->rss_spread) + netif_warn(efx, probe, efx->net_dev, + "Could not allocate an exclusive RSS" + " context; allocated a shared one of" + " different size." + " Wanted %u, got %u.\n", + efx->rss_spread, context_size); + else if (mismatch) + netif_warn(efx, probe, efx->net_dev, + "Could not allocate an exclusive RSS" + " context; allocated a shared one but" + " could not apply custom" + " indirection.\n"); + else + netif_info(efx, probe, efx->net_dev, + "Could not allocate an exclusive RSS" + " context; allocated a shared one.\n"); + } + } + return rc; +} + +static int efx_ef10_vf_rx_push_rss_config(struct efx_nic *efx, bool user, + const u32 *rx_indir_table + __attribute__ ((unused))) +{ + struct efx_ef10_nic_data *nic_data = efx->nic_data; + + if (user) + return -EOPNOTSUPP; + if (nic_data->rx_rss_context != EFX_EF10_RSS_CONTEXT_INVALID) + return 0; + return efx_ef10_rx_push_shared_rss_config(efx, NULL); } static int efx_ef10_rx_probe(struct efx_rx_queue *rx_queue) @@ -3738,7 +3851,7 @@ const struct efx_nic_type efx_hunt_a0_vf_nic_type = { .tx_init = efx_ef10_tx_init, .tx_remove = efx_ef10_tx_remove, .tx_write = efx_ef10_tx_write, - .rx_push_rss_config = efx_ef10_rx_push_rss_config, + .rx_push_rss_config = efx_ef10_vf_rx_push_rss_config, .rx_probe = efx_ef10_rx_probe, .rx_init = efx_ef10_rx_init, .rx_remove = efx_ef10_rx_remove, @@ -3837,7 +3950,7 @@ const struct efx_nic_type efx_hunt_a0_nic_type = { .tx_init = efx_ef10_tx_init, .tx_remove = efx_ef10_tx_remove, .tx_write = efx_ef10_tx_write, - .rx_push_rss_config = efx_ef10_rx_push_rss_config, + .rx_push_rss_config = efx_ef10_pf_rx_push_rss_config, .rx_probe = efx_ef10_rx_probe, .rx_init = efx_ef10_rx_init, .rx_remove = efx_ef10_rx_remove, diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 78f77605c067..706b936ad52d 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -1290,6 +1290,15 @@ static void efx_fini_io(struct efx_nic *efx) pci_disable_device(efx->pci_dev); } +void efx_set_default_rx_indir_table(struct efx_nic *efx) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(efx->rx_indir_table); i++) + efx->rx_indir_table[i] = + ethtool_rxfh_indir_default(i, efx->rss_spread); +} + static unsigned int efx_wanted_parallelism(struct efx_nic *efx) { cpumask_var_t thread_mask; @@ -1607,7 +1616,6 @@ static void efx_set_channels(struct efx_nic *efx) static int efx_probe_nic(struct efx_nic *efx) { - size_t i; int rc; netif_dbg(efx, probe, efx->net_dev, "creating NIC\n"); @@ -1630,10 +1638,9 @@ static int efx_probe_nic(struct efx_nic *efx) goto fail2; if (efx->n_channels > 1) - netdev_rss_key_fill(&efx->rx_hash_key, sizeof(efx->rx_hash_key)); - for (i = 0; i < ARRAY_SIZE(efx->rx_indir_table); i++) - efx->rx_indir_table[i] = - ethtool_rxfh_indir_default(i, efx->rss_spread); + netdev_rss_key_fill(&efx->rx_hash_key, + sizeof(efx->rx_hash_key)); + efx_set_default_rx_indir_table(efx); netif_set_real_num_tx_queues(efx->net_dev, efx->n_tx_channels); netif_set_real_num_rx_queues(efx->net_dev, efx->n_rx_channels); diff --git a/drivers/net/ethernet/sfc/efx.h b/drivers/net/ethernet/sfc/efx.h index 946607fbc0cc..9097906ecfb4 100644 --- a/drivers/net/ethernet/sfc/efx.h +++ b/drivers/net/ethernet/sfc/efx.h @@ -34,6 +34,7 @@ unsigned int efx_tx_max_skb_descs(struct efx_nic *efx); extern unsigned int efx_piobuf_size; /* RX */ +void efx_set_default_rx_indir_table(struct efx_nic *efx); void efx_rx_config_page_split(struct efx_nic *efx); int efx_probe_rx_queue(struct efx_rx_queue *rx_queue); void efx_remove_rx_queue(struct efx_rx_queue *rx_queue); diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c index 4835bc0d0de8..03829b48547a 100644 --- a/drivers/net/ethernet/sfc/ethtool.c +++ b/drivers/net/ethernet/sfc/ethtool.c @@ -1109,9 +1109,8 @@ static int efx_ethtool_set_rxfh(struct net_device *net_dev, const u32 *indir, return -EOPNOTSUPP; if (!indir) return 0; - memcpy(efx->rx_indir_table, indir, sizeof(efx->rx_indir_table)); - efx->type->rx_push_rss_config(efx); - return 0; + + return efx->type->rx_push_rss_config(efx, true, indir); } static int efx_ethtool_get_ts_info(struct net_device *net_dev, diff --git a/drivers/net/ethernet/sfc/falcon.c b/drivers/net/ethernet/sfc/falcon.c index 5a23435efcfb..3bb1da854b60 100644 --- a/drivers/net/ethernet/sfc/falcon.c +++ b/drivers/net/ethernet/sfc/falcon.c @@ -477,16 +477,29 @@ static irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id) * ************************************************************************** */ +static int dummy_rx_push_rss_config(struct efx_nic *efx, bool user, + const u32 *rx_indir_table) +{ + (void) efx; + (void) user; + (void) rx_indir_table; + return -ENOSYS; +} -static void falcon_b0_rx_push_rss_config(struct efx_nic *efx) +static int falcon_b0_rx_push_rss_config(struct efx_nic *efx, bool user, + const u32 *rx_indir_table) { efx_oword_t temp; + (void) user; /* Set hash key for IPv4 */ memcpy(&temp, efx->rx_hash_key, sizeof(temp)); efx_writeo(efx, &temp, FR_BZ_RX_RSS_TKEY); + memcpy(efx->rx_indir_table, rx_indir_table, + sizeof(efx->rx_indir_table)); efx_farch_rx_push_indir_table(efx); + return 0; } /************************************************************************** @@ -2507,7 +2520,7 @@ static int falcon_init_nic(struct efx_nic *efx) falcon_init_rx_cfg(efx); if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) { - falcon_b0_rx_push_rss_config(efx); + falcon_b0_rx_push_rss_config(efx, false, efx->rx_indir_table); /* Set destination of both TX and RX Flush events */ EFX_POPULATE_OWORD_1(temp, FRF_BZ_FLS_EVQ_ID, 0); @@ -2730,7 +2743,7 @@ const struct efx_nic_type falcon_a1_nic_type = { .tx_init = efx_farch_tx_init, .tx_remove = efx_farch_tx_remove, .tx_write = efx_farch_tx_write, - .rx_push_rss_config = efx_port_dummy_op_void, + .rx_push_rss_config = dummy_rx_push_rss_config, .rx_probe = efx_farch_rx_probe, .rx_init = efx_farch_rx_init, .rx_remove = efx_farch_rx_remove, diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index dd7134ef58df..9498a427887d 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -1276,7 +1276,8 @@ struct efx_nic_type { void (*tx_init)(struct efx_tx_queue *tx_queue); void (*tx_remove)(struct efx_tx_queue *tx_queue); void (*tx_write)(struct efx_tx_queue *tx_queue); - void (*rx_push_rss_config)(struct efx_nic *efx); + int (*rx_push_rss_config)(struct efx_nic *efx, bool user, + const u32 *rx_indir_table); int (*rx_probe)(struct efx_rx_queue *rx_queue); void (*rx_init)(struct efx_rx_queue *rx_queue); void (*rx_remove)(struct efx_rx_queue *rx_queue); diff --git a/drivers/net/ethernet/sfc/nic.h b/drivers/net/ethernet/sfc/nic.h index e833e973b79d..2fd30556e6c3 100644 --- a/drivers/net/ethernet/sfc/nic.h +++ b/drivers/net/ethernet/sfc/nic.h @@ -485,6 +485,7 @@ enum { * @must_restore_piobufs: Flag: PIO buffers have yet to be restored after MC * reboot * @rx_rss_context: Firmware handle for our RSS context + * @rx_rss_context_exclusive: Whether our RSS context is exclusive or shared * @stats: Hardware statistics * @workaround_35388: Flag: firmware supports workaround for bug 35388 * @must_check_datapath_caps: Flag: @datapath_caps needs to be revalidated @@ -513,6 +514,7 @@ struct efx_ef10_nic_data { unsigned int piobuf_handle[EF10_TX_PIOBUF_COUNT]; bool must_restore_piobufs; u32 rx_rss_context; + bool rx_rss_context_exclusive; u64 stats[EF10_STAT_COUNT]; bool workaround_35388; bool must_check_datapath_caps; diff --git a/drivers/net/ethernet/sfc/siena.c b/drivers/net/ethernet/sfc/siena.c index 95babe2a213c..a36ed1b603ed 100644 --- a/drivers/net/ethernet/sfc/siena.c +++ b/drivers/net/ethernet/sfc/siena.c @@ -324,7 +324,8 @@ fail1: return rc; } -static void siena_rx_push_rss_config(struct efx_nic *efx) +static int siena_rx_push_rss_config(struct efx_nic *efx, bool user, + const u32 *rx_indir_table) { efx_oword_t temp; @@ -346,7 +347,11 @@ static void siena_rx_push_rss_config(struct efx_nic *efx) FRF_CZ_RX_RSS_IPV6_TKEY_HI_WIDTH / 8); efx_writeo(efx, &temp, FR_CZ_RX_RSS_IPV6_REG3); + memcpy(efx->rx_indir_table, rx_indir_table, + sizeof(efx->rx_indir_table)); efx_farch_rx_push_indir_table(efx); + + return 0; } /* This call performs hardware-specific global initialisation, such as @@ -389,7 +394,7 @@ static int siena_init_nic(struct efx_nic *efx) EFX_RX_USR_BUF_SIZE >> 5); efx_writeo(efx, &temp, FR_AZ_RX_CFG); - siena_rx_push_rss_config(efx); + siena_rx_push_rss_config(efx, false, efx->rx_indir_table); /* Enable event logging */ rc = efx_mcdi_log_ctrl(efx, true, false, 0); From 6f7f8aa69acb391ba98f5186ca09434d9d0f52ee Mon Sep 17 00:00:00 2001 From: Shradha Shah Date: Wed, 6 May 2015 01:00:07 +0100 Subject: [PATCH 14/14] sfc: Bind the sfc driver to any available VF's Add the device ID of the VF to the PCI device ID table. Added a boolean flag is_vf in efx_nic_type to differentiate between a VF and PF at probe time. This flag is useful in later patches while setting MAC address specially in the PCI-passthrough case. Signed-off-by: Shradha Shah Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 2 ++ drivers/net/ethernet/sfc/efx.c | 6 +++++- drivers/net/ethernet/sfc/falcon.c | 2 ++ drivers/net/ethernet/sfc/mcdi.c | 10 ---------- drivers/net/ethernet/sfc/net_driver.h | 1 + drivers/net/ethernet/sfc/siena.c | 1 + 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 7a67202fb1cb..882117a43c3a 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -3810,6 +3810,7 @@ static int efx_ef10_ptp_set_ts_config(struct efx_nic *efx, } const struct efx_nic_type efx_hunt_a0_vf_nic_type = { + .is_vf = true, .mem_bar = EFX_MEM_VF_BAR, .mem_map_size = efx_ef10_mem_map_size, .probe = efx_ef10_probe_vf, @@ -3907,6 +3908,7 @@ const struct efx_nic_type efx_hunt_a0_vf_nic_type = { }; const struct efx_nic_type efx_hunt_a0_nic_type = { + .is_vf = false, .mem_bar = EFX_MEM_BAR, .mem_map_size = efx_ef10_mem_map_size, .probe = efx_ef10_probe_pf, diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 706b936ad52d..0f127a01b5e8 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -1454,6 +1454,7 @@ static int efx_probe_interrupts(struct efx_nic *efx) } #endif efx->rss_spread = efx->n_rx_channels; + return 0; } @@ -2676,6 +2677,8 @@ static const struct pci_device_id efx_pci_table[] = { .driver_data = (unsigned long) &siena_a0_nic_type}, {PCI_DEVICE(PCI_VENDOR_ID_SOLARFLARE, 0x0903), /* SFC9120 PF */ .driver_data = (unsigned long) &efx_hunt_a0_nic_type}, + {PCI_DEVICE(PCI_VENDOR_ID_SOLARFLARE, 0x1903), /* SFC9120 VF */ + .driver_data = (unsigned long) &efx_hunt_a0_vf_nic_type}, {PCI_DEVICE(PCI_VENDOR_ID_SOLARFLARE, 0x0923), /* SFC9140 PF */ .driver_data = (unsigned long) &efx_hunt_a0_nic_type}, {0} /* end of list */ @@ -3031,7 +3034,8 @@ static int efx_pci_probe(struct pci_dev *pci_dev, netif_info(efx, probe, efx->net_dev, "Solarflare NIC detected\n"); - efx_probe_vpd_strings(efx); + if (!efx->type->is_vf) + efx_probe_vpd_strings(efx); /* Set up basic I/O (BAR mappings etc) */ rc = efx_init_io(efx); diff --git a/drivers/net/ethernet/sfc/falcon.c b/drivers/net/ethernet/sfc/falcon.c index 3bb1da854b60..80e69af21642 100644 --- a/drivers/net/ethernet/sfc/falcon.c +++ b/drivers/net/ethernet/sfc/falcon.c @@ -2700,6 +2700,7 @@ static int falcon_set_wol(struct efx_nic *efx, u32 type) */ const struct efx_nic_type falcon_a1_nic_type = { + .is_vf = false, .mem_bar = EFX_MEM_BAR, .mem_map_size = falcon_a1_mem_map_size, .probe = falcon_probe_nic, @@ -2797,6 +2798,7 @@ const struct efx_nic_type falcon_a1_nic_type = { }; const struct efx_nic_type falcon_b0_nic_type = { + .is_vf = false, .mem_bar = EFX_MEM_BAR, .mem_map_size = falcon_b0_mem_map_size, .probe = falcon_probe_nic, diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c index 1ffe289313f1..b44ee31f1a7a 100644 --- a/drivers/net/ethernet/sfc/mcdi.c +++ b/drivers/net/ethernet/sfc/mcdi.c @@ -1186,16 +1186,6 @@ static int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating, * and are completely trusted by firmware. Abort probing * if that's not true for this function. */ - if (driver_operating && - (efx->mcdi->fn_flags & - (1 << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_LINKCTRL | - 1 << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_TRUSTED)) != - (1 << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_LINKCTRL | - 1 << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_TRUSTED)) { - netif_err(efx, probe, efx->net_dev, - "This driver version only supports one function per port\n"); - return -ENODEV; - } if (was_attached != NULL) *was_attached = MCDI_DWORD(outbuf, DRV_ATTACH_OUT_OLD_STATE); diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index 9498a427887d..031a3385ad4b 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -1224,6 +1224,7 @@ struct efx_mtd_partition { * @hwtstamp_filters: Mask of hardware timestamp filter types supported */ struct efx_nic_type { + bool is_vf; unsigned int mem_bar; unsigned int (*mem_map_size)(struct efx_nic *efx); int (*probe)(struct efx_nic *efx); diff --git a/drivers/net/ethernet/sfc/siena.c b/drivers/net/ethernet/sfc/siena.c index a36ed1b603ed..8b4130abad66 100644 --- a/drivers/net/ethernet/sfc/siena.c +++ b/drivers/net/ethernet/sfc/siena.c @@ -917,6 +917,7 @@ fail: */ const struct efx_nic_type siena_a0_nic_type = { + .is_vf = false, .mem_bar = EFX_MEM_BAR, .mem_map_size = siena_mem_map_size, .probe = siena_probe_nic,