diff options
author | David S. Miller <davem@davemloft.net> | 2020-08-03 18:22:55 -0700 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2020-08-03 18:22:55 -0700 |
commit | c4b83061dc860767188390a44f035da5dbcdb29e (patch) | |
tree | 028455813a1f058ccb994aab260ee88688a9e5c0 | |
parent | 215602a8d21209545923d39b92e9839093b1dcec (diff) | |
parent | d61592a112928a11cd04081adf51ba4f752859ed (diff) |
Merge branch 'sfc-driver-for-EF100-family-NICs-part-2'
Edward Cree says:
====================
sfc: driver for EF100 family NICs, part 2
This series implements the data path and various other functionality
for Xilinx/Solarflare EF100 NICs.
Changed from v2:
* Improved error handling of design params (patch #3)
* Removed 'inline' from .c file in patch #4
* Don't report common stats to ethtool -S (patch #8)
Changed from v1:
* Fixed build errors on CONFIG_RFS_ACCEL=n (patch #5) and 32-bit
(patch #8)
* Dropped patch #10 (ethtool ops) as it's buggy and will need a
bigger rework to fix.
====================
Acked-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/sfc/ef100.c | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/ef100_netdev.c | 16 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/ef100_nic.c | 657 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/ef100_nic.h | 48 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/ef100_rx.c | 150 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/ef100_rx.h | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/ef100_tx.c | 367 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/ef100_tx.h | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/net_driver.h | 21 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/tx_common.c | 1 |
10 files changed, 1255 insertions, 12 deletions
diff --git a/drivers/net/ethernet/sfc/ef100.c b/drivers/net/ethernet/sfc/ef100.c index de611c0f94e7..9729983f4840 100644 --- a/drivers/net/ethernet/sfc/ef100.c +++ b/drivers/net/ethernet/sfc/ef100.c @@ -527,6 +527,8 @@ fail: static const struct pci_device_id ef100_pci_table[] = { {PCI_DEVICE(PCI_VENDOR_ID_XILINX, 0x0100), /* Riverhead PF */ .driver_data = (unsigned long) &ef100_pf_nic_type }, + {PCI_DEVICE(PCI_VENDOR_ID_XILINX, 0x1100), /* Riverhead VF */ + .driver_data = (unsigned long) &ef100_vf_nic_type }, {0} /* end of list */ }; diff --git a/drivers/net/ethernet/sfc/ef100_netdev.c b/drivers/net/ethernet/sfc/ef100_netdev.c index ec9ca81fed85..63c311ba28b9 100644 --- a/drivers/net/ethernet/sfc/ef100_netdev.c +++ b/drivers/net/ethernet/sfc/ef100_netdev.c @@ -86,9 +86,11 @@ static int ef100_net_stop(struct net_device *net_dev) netif_stop_queue(net_dev); efx_stop_all(efx); + efx_mcdi_mac_fini_stats(efx); efx_disable_interrupts(efx); efx_clear_interrupt_affinity(efx); efx_nic_fini_interrupt(efx); + efx_remove_filters(efx); efx_fini_napi(efx); efx_remove_channels(efx); efx_mcdi_free_vis(efx); @@ -138,6 +140,10 @@ static int ef100_net_open(struct net_device *net_dev) efx_init_napi(efx); + rc = efx_probe_filters(efx); + if (rc) + goto fail; + rc = efx_nic_init_interrupt(efx); if (rc) goto fail; @@ -152,6 +158,10 @@ static int ef100_net_open(struct net_device *net_dev) */ (void) efx_mcdi_poll_reboot(efx); + rc = efx_mcdi_mac_init_stats(efx); + if (rc) + goto fail; + efx_start_all(efx); /* Link state detection is normally event-driven; we have @@ -207,8 +217,14 @@ static const struct net_device_ops ef100_netdev_ops = { .ndo_open = ef100_net_open, .ndo_stop = ef100_net_stop, .ndo_start_xmit = ef100_hard_start_xmit, + .ndo_get_stats64 = efx_net_stats, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_rx_mode = efx_set_rx_mode, /* Lookout */ .ndo_get_phys_port_id = efx_get_phys_port_id, .ndo_get_phys_port_name = efx_get_phys_port_name, +#ifdef CONFIG_RFS_ACCEL + .ndo_rx_flow_steer = efx_filter_rfs, +#endif }; /* Netdev registration diff --git a/drivers/net/ethernet/sfc/ef100_nic.c b/drivers/net/ethernet/sfc/ef100_nic.c index 6a00f2a2dc2b..8a2126fec078 100644 --- a/drivers/net/ethernet/sfc/ef100_nic.c +++ b/drivers/net/ethernet/sfc/ef100_nic.c @@ -260,9 +260,16 @@ static int ef100_ev_process(struct efx_channel *channel, int quota) ev_type = EFX_QWORD_FIELD(*p_event, ESF_GZ_E_TYPE); switch (ev_type) { + case ESE_GZ_EF100_EV_RX_PKTS: + efx_ef100_ev_rx(channel, p_event); + ++spent; + break; case ESE_GZ_EF100_EV_MCDI: efx_mcdi_process_event(channel, p_event); break; + case ESE_GZ_EF100_EV_TX_COMPLETION: + ef100_ev_tx(channel, p_event); + break; case ESE_GZ_EF100_EV_DRIVER: netif_info(efx, drv, efx->net_dev, "Driver initiated event " EFX_QWORD_FMT "\n", @@ -344,6 +351,37 @@ static int ef100_phy_probe(struct efx_nic *efx) return 0; } +static int ef100_filter_table_probe(struct efx_nic *efx) +{ + return efx_mcdi_filter_table_probe(efx, true); +} + +static int ef100_filter_table_up(struct efx_nic *efx) +{ + int rc; + + rc = efx_mcdi_filter_add_vlan(efx, EFX_FILTER_VID_UNSPEC); + if (rc) { + efx_mcdi_filter_table_down(efx); + return rc; + } + + rc = efx_mcdi_filter_add_vlan(efx, 0); + if (rc) { + efx_mcdi_filter_del_vlan(efx, EFX_FILTER_VID_UNSPEC); + efx_mcdi_filter_table_down(efx); + } + + return rc; +} + +static void ef100_filter_table_down(struct efx_nic *efx) +{ + efx_mcdi_filter_del_vlan(efx, 0); + efx_mcdi_filter_del_vlan(efx, EFX_FILTER_VID_UNSPEC); + efx_mcdi_filter_table_down(efx); +} + /* Other */ static int ef100_reconfigure_mac(struct efx_nic *efx, bool mtu_only) @@ -390,12 +428,24 @@ static int ef100_reset(struct efx_nic *efx, enum reset_type reset_type) __clear_bit(reset_type, &efx->reset_pending); rc = dev_open(efx->net_dev, NULL); } else if (reset_type == RESET_TYPE_ALL) { + /* A RESET_TYPE_ALL will cause filters to be removed, so we remove filters + * and reprobe after reset to avoid removing filters twice + */ + down_read(&efx->filter_sem); + ef100_filter_table_down(efx); + up_read(&efx->filter_sem); rc = efx_mcdi_reset(efx, reset_type); if (rc) return rc; netif_device_attach(efx->net_dev); + down_read(&efx->filter_sem); + rc = ef100_filter_table_up(efx); + up_read(&efx->filter_sem); + if (rc) + return rc; + rc = dev_open(efx->net_dev, NULL); } else { rc = 1; /* Leave the device closed */ @@ -403,6 +453,171 @@ static int ef100_reset(struct efx_nic *efx, enum reset_type reset_type) return rc; } +static void ef100_common_stat_mask(unsigned long *mask) +{ + __set_bit(EF100_STAT_port_rx_packets, mask); + __set_bit(EF100_STAT_port_tx_packets, mask); + __set_bit(EF100_STAT_port_rx_bytes, mask); + __set_bit(EF100_STAT_port_tx_bytes, mask); + __set_bit(EF100_STAT_port_rx_multicast, mask); + __set_bit(EF100_STAT_port_rx_bad, mask); + __set_bit(EF100_STAT_port_rx_align_error, mask); + __set_bit(EF100_STAT_port_rx_overflow, mask); +} + +static void ef100_ethtool_stat_mask(unsigned long *mask) +{ + __set_bit(EF100_STAT_port_tx_pause, mask); + __set_bit(EF100_STAT_port_tx_unicast, mask); + __set_bit(EF100_STAT_port_tx_multicast, mask); + __set_bit(EF100_STAT_port_tx_broadcast, mask); + __set_bit(EF100_STAT_port_tx_lt64, mask); + __set_bit(EF100_STAT_port_tx_64, mask); + __set_bit(EF100_STAT_port_tx_65_to_127, mask); + __set_bit(EF100_STAT_port_tx_128_to_255, mask); + __set_bit(EF100_STAT_port_tx_256_to_511, mask); + __set_bit(EF100_STAT_port_tx_512_to_1023, mask); + __set_bit(EF100_STAT_port_tx_1024_to_15xx, mask); + __set_bit(EF100_STAT_port_tx_15xx_to_jumbo, mask); + __set_bit(EF100_STAT_port_rx_good, mask); + __set_bit(EF100_STAT_port_rx_pause, mask); + __set_bit(EF100_STAT_port_rx_unicast, mask); + __set_bit(EF100_STAT_port_rx_broadcast, mask); + __set_bit(EF100_STAT_port_rx_lt64, mask); + __set_bit(EF100_STAT_port_rx_64, mask); + __set_bit(EF100_STAT_port_rx_65_to_127, mask); + __set_bit(EF100_STAT_port_rx_128_to_255, mask); + __set_bit(EF100_STAT_port_rx_256_to_511, mask); + __set_bit(EF100_STAT_port_rx_512_to_1023, mask); + __set_bit(EF100_STAT_port_rx_1024_to_15xx, mask); + __set_bit(EF100_STAT_port_rx_15xx_to_jumbo, mask); + __set_bit(EF100_STAT_port_rx_gtjumbo, mask); + __set_bit(EF100_STAT_port_rx_bad_gtjumbo, mask); + __set_bit(EF100_STAT_port_rx_length_error, mask); + __set_bit(EF100_STAT_port_rx_nodesc_drops, mask); + __set_bit(GENERIC_STAT_rx_nodesc_trunc, mask); + __set_bit(GENERIC_STAT_rx_noskb_drops, mask); +} + +#define EF100_DMA_STAT(ext_name, mcdi_name) \ + [EF100_STAT_ ## ext_name] = \ + { #ext_name, 64, 8 * MC_CMD_MAC_ ## mcdi_name } + +static const struct efx_hw_stat_desc ef100_stat_desc[EF100_STAT_COUNT] = { + EF100_DMA_STAT(port_tx_bytes, TX_BYTES), + EF100_DMA_STAT(port_tx_packets, TX_PKTS), + EF100_DMA_STAT(port_tx_pause, TX_PAUSE_PKTS), + EF100_DMA_STAT(port_tx_unicast, TX_UNICAST_PKTS), + EF100_DMA_STAT(port_tx_multicast, TX_MULTICAST_PKTS), + EF100_DMA_STAT(port_tx_broadcast, TX_BROADCAST_PKTS), + EF100_DMA_STAT(port_tx_lt64, TX_LT64_PKTS), + EF100_DMA_STAT(port_tx_64, TX_64_PKTS), + EF100_DMA_STAT(port_tx_65_to_127, TX_65_TO_127_PKTS), + EF100_DMA_STAT(port_tx_128_to_255, TX_128_TO_255_PKTS), + EF100_DMA_STAT(port_tx_256_to_511, TX_256_TO_511_PKTS), + EF100_DMA_STAT(port_tx_512_to_1023, TX_512_TO_1023_PKTS), + EF100_DMA_STAT(port_tx_1024_to_15xx, TX_1024_TO_15XX_PKTS), + EF100_DMA_STAT(port_tx_15xx_to_jumbo, TX_15XX_TO_JUMBO_PKTS), + EF100_DMA_STAT(port_rx_bytes, RX_BYTES), + EF100_DMA_STAT(port_rx_packets, RX_PKTS), + EF100_DMA_STAT(port_rx_good, RX_GOOD_PKTS), + EF100_DMA_STAT(port_rx_bad, RX_BAD_FCS_PKTS), + EF100_DMA_STAT(port_rx_pause, RX_PAUSE_PKTS), + EF100_DMA_STAT(port_rx_unicast, RX_UNICAST_PKTS), + EF100_DMA_STAT(port_rx_multicast, RX_MULTICAST_PKTS), + EF100_DMA_STAT(port_rx_broadcast, RX_BROADCAST_PKTS), + EF100_DMA_STAT(port_rx_lt64, RX_UNDERSIZE_PKTS), + EF100_DMA_STAT(port_rx_64, RX_64_PKTS), + EF100_DMA_STAT(port_rx_65_to_127, RX_65_TO_127_PKTS), + EF100_DMA_STAT(port_rx_128_to_255, RX_128_TO_255_PKTS), + EF100_DMA_STAT(port_rx_256_to_511, RX_256_TO_511_PKTS), + EF100_DMA_STAT(port_rx_512_to_1023, RX_512_TO_1023_PKTS), + EF100_DMA_STAT(port_rx_1024_to_15xx, RX_1024_TO_15XX_PKTS), + EF100_DMA_STAT(port_rx_15xx_to_jumbo, RX_15XX_TO_JUMBO_PKTS), + EF100_DMA_STAT(port_rx_gtjumbo, RX_GTJUMBO_PKTS), + EF100_DMA_STAT(port_rx_bad_gtjumbo, RX_JABBER_PKTS), + EF100_DMA_STAT(port_rx_align_error, RX_ALIGN_ERROR_PKTS), + EF100_DMA_STAT(port_rx_length_error, RX_LENGTH_ERROR_PKTS), + EF100_DMA_STAT(port_rx_overflow, RX_OVERFLOW_PKTS), + EF100_DMA_STAT(port_rx_nodesc_drops, RX_NODESC_DROPS), + EFX_GENERIC_SW_STAT(rx_nodesc_trunc), + EFX_GENERIC_SW_STAT(rx_noskb_drops), +}; + +static size_t ef100_describe_stats(struct efx_nic *efx, u8 *names) +{ + DECLARE_BITMAP(mask, EF100_STAT_COUNT) = {}; + + ef100_ethtool_stat_mask(mask); + return efx_nic_describe_stats(ef100_stat_desc, EF100_STAT_COUNT, + mask, names); +} + +static size_t ef100_update_stats_common(struct efx_nic *efx, u64 *full_stats, + struct rtnl_link_stats64 *core_stats) +{ + struct ef100_nic_data *nic_data = efx->nic_data; + DECLARE_BITMAP(mask, EF100_STAT_COUNT) = {}; + size_t stats_count = 0, index; + u64 *stats = nic_data->stats; + + ef100_ethtool_stat_mask(mask); + + if (full_stats) { + for_each_set_bit(index, mask, EF100_STAT_COUNT) { + if (ef100_stat_desc[index].name) { + *full_stats++ = stats[index]; + ++stats_count; + } + } + } + + if (!core_stats) + return stats_count; + + core_stats->rx_packets = stats[EF100_STAT_port_rx_packets]; + core_stats->tx_packets = stats[EF100_STAT_port_tx_packets]; + core_stats->rx_bytes = stats[EF100_STAT_port_rx_bytes]; + core_stats->tx_bytes = stats[EF100_STAT_port_tx_bytes]; + core_stats->rx_dropped = stats[EF100_STAT_port_rx_nodesc_drops] + + stats[GENERIC_STAT_rx_nodesc_trunc] + + stats[GENERIC_STAT_rx_noskb_drops]; + core_stats->multicast = stats[EF100_STAT_port_rx_multicast]; + core_stats->rx_length_errors = + stats[EF100_STAT_port_rx_gtjumbo] + + stats[EF100_STAT_port_rx_length_error]; + core_stats->rx_crc_errors = stats[EF100_STAT_port_rx_bad]; + core_stats->rx_frame_errors = + stats[EF100_STAT_port_rx_align_error]; + core_stats->rx_fifo_errors = stats[EF100_STAT_port_rx_overflow]; + core_stats->rx_errors = (core_stats->rx_length_errors + + core_stats->rx_crc_errors + + core_stats->rx_frame_errors); + + return stats_count; +} + +static size_t ef100_update_stats(struct efx_nic *efx, + u64 *full_stats, + struct rtnl_link_stats64 *core_stats) +{ + __le64 *mc_stats = kmalloc(array_size(efx->num_mac_stats, sizeof(__le64)), GFP_ATOMIC); + struct ef100_nic_data *nic_data = efx->nic_data; + DECLARE_BITMAP(mask, EF100_STAT_COUNT) = {}; + u64 *stats = nic_data->stats; + + ef100_common_stat_mask(mask); + ef100_ethtool_stat_mask(mask); + + efx_nic_copy_stats(efx, mc_stats); + efx_nic_update_stats(ef100_stat_desc, EF100_STAT_COUNT, mask, + stats, mc_stats, false); + + kfree(mc_stats); + + return ef100_update_stats_common(efx, full_stats, core_stats); +} + static int efx_ef100_get_phys_port_id(struct efx_nic *efx, struct netdev_phys_item_id *ppid) { @@ -417,6 +632,50 @@ static int efx_ef100_get_phys_port_id(struct efx_nic *efx, return 0; } +static int efx_ef100_irq_test_generate(struct efx_nic *efx) +{ + MCDI_DECLARE_BUF(inbuf, MC_CMD_TRIGGER_INTERRUPT_IN_LEN); + + BUILD_BUG_ON(MC_CMD_TRIGGER_INTERRUPT_OUT_LEN != 0); + + MCDI_SET_DWORD(inbuf, TRIGGER_INTERRUPT_IN_INTR_LEVEL, efx->irq_level); + return efx_mcdi_rpc_quiet(efx, MC_CMD_TRIGGER_INTERRUPT, + inbuf, sizeof(inbuf), NULL, 0, NULL); +} + +#define EFX_EF100_TEST 1 + +static void efx_ef100_ev_test_generate(struct efx_channel *channel) +{ + MCDI_DECLARE_BUF(inbuf, MC_CMD_DRIVER_EVENT_IN_LEN); + struct efx_nic *efx = channel->efx; + efx_qword_t event; + int rc; + + EFX_POPULATE_QWORD_2(event, + ESF_GZ_E_TYPE, ESE_GZ_EF100_EV_DRIVER, + ESF_GZ_DRIVER_DATA, EFX_EF100_TEST); + + MCDI_SET_DWORD(inbuf, DRIVER_EVENT_IN_EVQ, channel->channel); + + /* MCDI_SET_QWORD is not appropriate here since EFX_POPULATE_* has + * already swapped the data to little-endian order. + */ + memcpy(MCDI_PTR(inbuf, DRIVER_EVENT_IN_DATA), &event.u64[0], + sizeof(efx_qword_t)); + + rc = efx_mcdi_rpc(efx, MC_CMD_DRIVER_EVENT, inbuf, sizeof(inbuf), + NULL, 0, NULL); + if (rc && (rc != -ENETDOWN)) + goto fail; + + return; + +fail: + WARN_ON(true); + netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc); +} + static unsigned int ef100_check_caps(const struct efx_nic *efx, u8 flag, u32 offset) { @@ -436,10 +695,16 @@ static unsigned int ef100_check_caps(const struct efx_nic *efx, /* NIC level access functions */ +#define EF100_OFFLOAD_FEATURES (NETIF_F_HW_CSUM | NETIF_F_RXCSUM | \ + NETIF_F_HIGHDMA | NETIF_F_SG | NETIF_F_FRAGLIST | \ + NETIF_F_RXHASH | NETIF_F_RXFCS | NETIF_F_TSO_ECN | NETIF_F_RXALL | \ + NETIF_F_TSO_MANGLEID | NETIF_F_HW_VLAN_CTAG_TX) + const struct efx_nic_type ef100_pf_nic_type = { .revision = EFX_REV_EF100, .is_vf = false, .probe = ef100_probe_pf, + .offload_features = EF100_OFFLOAD_FEATURES, .mcdi_max_ver = 2, .mcdi_request = ef100_mcdi_request, .mcdi_poll_response = ef100_mcdi_poll_response, @@ -447,6 +712,7 @@ const struct efx_nic_type ef100_pf_nic_type = { .mcdi_poll_reboot = ef100_mcdi_poll_reboot, .mcdi_reboot_detected = ef100_mcdi_reboot_detected, .irq_enable_master = efx_port_dummy_op_void, + .irq_test_generate = efx_ef100_irq_test_generate, .irq_disable_non_ev = efx_port_dummy_op_void, .push_irq_moderation = efx_channel_dummy_op_void, .min_interrupt_mode = EFX_INT_MODE_MSIX, @@ -463,6 +729,7 @@ const struct efx_nic_type ef100_pf_nic_type = { .irq_handle_msi = ef100_msi_interrupt, .ev_process = ef100_ev_process, .ev_read_ack = ef100_ev_read_ack, + .ev_test_generate = efx_ef100_ev_test_generate, .tx_probe = ef100_tx_probe, .tx_init = ef100_tx_init, .tx_write = ef100_tx_write, @@ -472,10 +739,41 @@ const struct efx_nic_type ef100_pf_nic_type = { .rx_remove = efx_mcdi_rx_remove, .rx_write = ef100_rx_write, .rx_packet = __ef100_rx_packet, + .fini_dmaq = efx_fini_dmaq, + .max_rx_ip_filters = EFX_MCDI_FILTER_TBL_ROWS, + .filter_table_probe = ef100_filter_table_up, + .filter_table_restore = efx_mcdi_filter_table_restore, + .filter_table_remove = ef100_filter_table_down, + .filter_insert = efx_mcdi_filter_insert, + .filter_remove_safe = efx_mcdi_filter_remove_safe, + .filter_get_safe = efx_mcdi_filter_get_safe, + .filter_clear_rx = efx_mcdi_filter_clear_rx, + .filter_count_rx_used = efx_mcdi_filter_count_rx_used, + .filter_get_rx_id_limit = efx_mcdi_filter_get_rx_id_limit, + .filter_get_rx_ids = efx_mcdi_filter_get_rx_ids, +#ifdef CONFIG_RFS_ACCEL + .filter_rfs_expire_one = efx_mcdi_filter_rfs_expire_one, +#endif .get_phys_port_id = efx_ef100_get_phys_port_id, + .rx_prefix_size = ESE_GZ_RX_PKT_PREFIX_LEN, + .rx_hash_offset = ESF_GZ_RX_PREFIX_RSS_HASH_LBN / 8, + .rx_ts_offset = ESF_GZ_RX_PREFIX_PARTIAL_TSTAMP_LBN / 8, + .rx_hash_key_size = 40, + .rx_pull_rss_config = efx_mcdi_rx_pull_rss_config, + .rx_push_rss_config = efx_mcdi_pf_rx_push_rss_config, + .rx_push_rss_context_config = efx_mcdi_rx_push_rss_context_config, + .rx_pull_rss_context_config = efx_mcdi_rx_pull_rss_context_config, + .rx_restore_rss_contexts = efx_mcdi_rx_restore_rss_contexts, + .reconfigure_mac = ef100_reconfigure_mac, + .test_nvram = efx_new_mcdi_nvram_test_all, + .describe_stats = ef100_describe_stats, + .start_stats = efx_mcdi_mac_start_stats, + .update_stats = ef100_update_stats, + .pull_stats = efx_mcdi_mac_pull_stats, + .stop_stats = efx_mcdi_mac_stop_stats, /* Per-type bar/size configuration not used on ef100. Location of * registers is defined by extended capabilities. @@ -485,6 +783,310 @@ const struct efx_nic_type ef100_pf_nic_type = { }; +const struct efx_nic_type ef100_vf_nic_type = { + .revision = EFX_REV_EF100, + .is_vf = true, + .probe = ef100_probe_vf, + .offload_features = EF100_OFFLOAD_FEATURES, + .mcdi_max_ver = 2, + .mcdi_request = ef100_mcdi_request, + .mcdi_poll_response = ef100_mcdi_poll_response, + .mcdi_read_response = ef100_mcdi_read_response, + .mcdi_poll_reboot = ef100_mcdi_poll_reboot, + .mcdi_reboot_detected = ef100_mcdi_reboot_detected, + .irq_enable_master = efx_port_dummy_op_void, + .irq_test_generate = efx_ef100_irq_test_generate, + .irq_disable_non_ev = efx_port_dummy_op_void, + .push_irq_moderation = efx_channel_dummy_op_void, + .min_interrupt_mode = EFX_INT_MODE_MSIX, + .map_reset_reason = ef100_map_reset_reason, + .map_reset_flags = ef100_map_reset_flags, + .reset = ef100_reset, + .check_caps = ef100_check_caps, + .ev_probe = ef100_ev_probe, + .ev_init = ef100_ev_init, + .ev_fini = efx_mcdi_ev_fini, + .ev_remove = efx_mcdi_ev_remove, + .irq_handle_msi = ef100_msi_interrupt, + .ev_process = ef100_ev_process, + .ev_read_ack = ef100_ev_read_ack, + .ev_test_generate = efx_ef100_ev_test_generate, + .tx_probe = ef100_tx_probe, + .tx_init = ef100_tx_init, + .tx_write = ef100_tx_write, + .tx_enqueue = ef100_enqueue_skb, + .rx_probe = efx_mcdi_rx_probe, + .rx_init = efx_mcdi_rx_init, + .rx_remove = efx_mcdi_rx_remove, + .rx_write = ef100_rx_write, + .rx_packet = __ef100_rx_packet, + .fini_dmaq = efx_fini_dmaq, + .max_rx_ip_filters = EFX_MCDI_FILTER_TBL_ROWS, + .filter_table_probe = ef100_filter_table_up, + .filter_table_restore = efx_mcdi_filter_table_restore, + .filter_table_remove = ef100_filter_table_down, + .filter_insert = efx_mcdi_filter_insert, + .filter_remove_safe = efx_mcdi_filter_remove_safe, + .filter_get_safe = efx_mcdi_filter_get_safe, + .filter_clear_rx = efx_mcdi_filter_clear_rx, + .filter_count_rx_used = efx_mcdi_filter_count_rx_used, + .filter_get_rx_id_limit = efx_mcdi_filter_get_rx_id_limit, + .filter_get_rx_ids = efx_mcdi_filter_get_rx_ids, + .filter_rfs_expire_one = efx_mcdi_filter_rfs_expire_one, + + .rx_prefix_size = ESE_GZ_RX_PKT_PREFIX_LEN, + .rx_hash_offset = ESF_GZ_RX_PREFIX_RSS_HASH_LBN / 8, + .rx_ts_offset = ESF_GZ_RX_PREFIX_PARTIAL_TSTAMP_LBN / 8, + .rx_hash_key_size = 40, + .rx_pull_rss_config = efx_mcdi_rx_pull_rss_config, + .rx_push_rss_config = efx_mcdi_pf_rx_push_rss_config, + .rx_restore_rss_contexts = efx_mcdi_rx_restore_rss_contexts, + + .reconfigure_mac = ef100_reconfigure_mac, + .test_nvram = efx_new_mcdi_nvram_test_all, + .describe_stats = ef100_describe_stats, + .start_stats = efx_mcdi_mac_start_stats, + .update_stats = ef100_update_stats, + .pull_stats = efx_mcdi_mac_pull_stats, + .stop_stats = efx_mcdi_mac_stop_stats, + + .mem_bar = NULL, + .mem_map_size = NULL, + +}; + +static int compare_versions(const char *a, const char *b) +{ + int a_major, a_minor, a_point, a_patch; + int b_major, b_minor, b_point, b_patch; + int a_matched, b_matched; + + a_matched = sscanf(a, "%d.%d.%d.%d", &a_major, &a_minor, &a_point, &a_patch); + b_matched = sscanf(b, "%d.%d.%d.%d", &b_major, &b_minor, &b_point, &b_patch); + + if (a_matched == 4 && b_matched != 4) + return +1; + + if (a_matched != 4 && b_matched == 4) + return -1; + + if (a_matched != 4 && b_matched != 4) + return 0; + + if (a_major != b_major) + return a_major - b_major; + + if (a_minor != b_minor) + return a_minor - b_minor; + + if (a_point != b_point) + return a_point - b_point; + + return a_patch - b_patch; +} + +enum ef100_tlv_state_machine { + EF100_TLV_TYPE, + EF100_TLV_TYPE_CONT, + EF100_TLV_LENGTH, + EF100_TLV_VALUE +}; + +struct ef100_tlv_state { + enum ef100_tlv_state_machine state; + u64 value; + u32 value_offset; + u16 type; + u8 len; +}; + +static int ef100_tlv_feed(struct ef100_tlv_state *state, u8 byte) +{ + switch (state->state) { + case EF100_TLV_TYPE: + state->type = byte & 0x7f; + state->state = (byte & 0x80) ? EF100_TLV_TYPE_CONT + : EF100_TLV_LENGTH; + /* Clear ready to read in a new entry */ + state->value = 0; + state->value_offset = 0; + return 0; + case EF100_TLV_TYPE_CONT: + state->type |= byte << 7; + state->state = EF100_TLV_LENGTH; + return 0; + case EF100_TLV_LENGTH: + state->len = byte; + /* We only handle TLVs that fit in a u64 */ + if (state->len > sizeof(state->value)) + return -EOPNOTSUPP; + /* len may be zero, implying a value of zero */ + state->state = state->len ? EF100_TLV_VALUE : EF100_TLV_TYPE; + return 0; + case EF100_TLV_VALUE: + state->value |= ((u64)byte) << (state->value_offset * 8); + state->value_offset++; + if (state->value_offset >= state->len) + state->state = EF100_TLV_TYPE; + return 0; + default: /* state machine error, can't happen */ + WARN_ON_ONCE(1); + return -EIO; + } +} + +static int ef100_process_design_param(struct efx_nic *efx, + const struct ef100_tlv_state *reader) +{ + struct ef100_nic_data *nic_data = efx->nic_data; + + switch (reader->type) { + case ESE_EF100_DP_GZ_PAD: /* padding, skip it */ + return 0; + case ESE_EF100_DP_GZ_PARTIAL_TSTAMP_SUB_NANO_BITS: + /* Driver doesn't support timestamping yet, so we don't care */ + return 0; + case ESE_EF100_DP_GZ_EVQ_UNSOL_CREDIT_SEQ_BITS: + /* Driver doesn't support unsolicited-event credits yet, so + * we don't care + */ + return 0; + case ESE_EF100_DP_GZ_NMMU_GROUP_SIZE: + /* Driver doesn't manage the NMMU (so we don't care) */ + return 0; + case ESE_EF100_DP_GZ_RX_L4_CSUM_PROTOCOLS: + /* Driver uses CHECKSUM_COMPLETE, so we don't care about + * protocol checksum validation + */ + return 0; + case ESE_EF100_DP_GZ_TSO_MAX_HDR_LEN: + nic_data->tso_max_hdr_len = min_t(u64, reader->value, 0xffff); + return 0; + case ESE_EF100_DP_GZ_TSO_MAX_HDR_NUM_SEGS: + /* We always put HDR_NUM_SEGS=1 in our TSO descriptors */ + if (!reader->value) { + netif_err(efx, probe, efx->net_dev, + "TSO_MAX_HDR_NUM_SEGS < 1\n"); + return -EOPNOTSUPP; + } + return 0; + case ESE_EF100_DP_GZ_RXQ_SIZE_GRANULARITY: + case ESE_EF100_DP_GZ_TXQ_SIZE_GRANULARITY: + /* Our TXQ and RXQ sizes are always power-of-two and thus divisible by + * EFX_MIN_DMAQ_SIZE, so we just need to check that + * EFX_MIN_DMAQ_SIZE is divisible by GRANULARITY. + * This is very unlikely to fail. + */ + if (EFX_MIN_DMAQ_SIZE % reader->value) { + netif_err(efx, probe, efx->net_dev, + "%s size granularity is %llu, can't guarantee safety\n", + reader->type == ESE_EF100_DP_GZ_RXQ_SIZE_GRANULARITY ? "RXQ" : "TXQ", + reader->value); + return -EOPNOTSUPP; + } + return 0; + case ESE_EF100_DP_GZ_TSO_MAX_PAYLOAD_LEN: + nic_data->tso_max_payload_len = min_t(u64, reader->value, GSO_MAX_SIZE); + efx->net_dev->gso_max_size = nic_data->tso_max_payload_len; + return 0; + case ESE_EF100_DP_GZ_TSO_MAX_PAYLOAD_NUM_SEGS: + nic_data->tso_max_payload_num_segs = min_t(u64, reader->value, 0xffff); + efx->net_dev->gso_max_segs = nic_data->tso_max_payload_num_segs; + return 0; + case ESE_EF100_DP_GZ_TSO_MAX_NUM_FRAMES: + nic_data->tso_max_frames = min_t(u64, reader->value, 0xffff); + return 0; + case ESE_EF100_DP_GZ_COMPAT: + if (reader->value) { + netif_err(efx, probe, efx->net_dev, + "DP_COMPAT has unknown bits %#llx, driver not compatible with this hw\n", + reader->value); + return -EOPNOTSUPP; + } + return 0; + case ESE_EF100_DP_GZ_MEM2MEM_MAX_LEN: + /* Driver doesn't use mem2mem transfers */ + return 0; + case ESE_EF100_DP_GZ_EVQ_TIMER_TICK_NANOS: + /* Driver doesn't currently use EVQ_TIMER */ + return 0; + case ESE_EF100_DP_GZ_NMMU_PAGE_SIZES: + /* Driver doesn't manage the NMMU (so we don't care) */ + return 0; + case ESE_EF100_DP_GZ_VI_STRIDES: + /* We never try to set the VI stride, and we don't rely on + * being able to find VIs past VI 0 until after we've learned + * the current stride from MC_CMD_GET_CAPABILITIES. + * So the value of this shouldn't matter. + */ + if (reader->value != ESE_EF100_DP_GZ_VI_STRIDES_DEFAULT) + netif_dbg(efx, probe, efx->net_dev, + "NIC has other than default VI_STRIDES (mask " + "%#llx), early probing might use wrong one\n", + reader->value); + return 0; + case ESE_EF100_DP_GZ_RX_MAX_RUNT: + /* Driver doesn't look at L2_STATUS:LEN_ERR bit, so we don't + * care whether it indicates runt or overlength for any given + * packet, so we don't care about this parameter. + */ + return 0; + default: + /* Host interface says "Drivers should ignore design parameters + * that they do not recognise." + */ + netif_dbg(efx, probe, efx->net_dev, + "Ignoring unrecognised design parameter %u\n", + reader->type); + return 0; + } +} + +static int ef100_check_design_params(struct efx_nic *efx) +{ + struct ef100_tlv_state reader = {}; + u32 total_len, offset = 0; + efx_dword_t reg; + int rc = 0, i; + u32 data; + + efx_readd(efx, ®, ER_GZ_PARAMS_TLV_LEN); + total_len = EFX_DWORD_FIELD(reg, EFX_DWORD_0); + netif_dbg(efx, probe, efx->net_dev, "%u bytes of design parameters\n", + total_len); + while (offset < total_len) { + efx_readd(efx, ®, ER_GZ_PARAMS_TLV + offset); + data = EFX_DWORD_FIELD(reg, EFX_DWORD_0); + for (i = 0; i < sizeof(data); i++) { + rc = ef100_tlv_feed(&reader, data); + /* Got a complete value? */ + if (!rc && reader.state == EF100_TLV_TYPE) + rc = ef100_process_design_param(efx, &reader); + if (rc) + goto out; + data >>= 8; + offset++; + } + } + /* Check we didn't end halfway through a TLV entry, which could either + * mean that the TLV stream is truncated or just that it's corrupted + * and our state machine is out of sync. + */ + if (reader.state != EF100_TLV_TYPE) { + if (reader.state == EF100_TLV_TYPE_CONT) + netif_err(efx, probe, efx->net_dev, + "truncated design parameter (incomplete type %u)\n", + reader.type); + else + netif_err(efx, probe, efx->net_dev, + "truncated design parameter %u\n", + reader.type); + rc = -EIO; + } +out: + return rc; +} + /* NIC probe and remove */ static int ef100_probe_main(struct efx_nic *efx) @@ -492,6 +1094,7 @@ static int ef100_probe_main(struct efx_nic *efx) unsigned int bar_size = resource_size(&efx->pci_dev->resource[efx->mem_bar]); struct net_device *net_dev = efx->net_dev; struct ef100_nic_data *nic_data; + char fw_version[32]; int i, rc; if (WARN_ON(bar_size == 0)) @@ -505,6 +1108,20 @@ static int ef100_probe_main(struct efx_nic *efx) net_dev->features |= efx->type->offload_features; net_dev->hw_features |= efx->type->offload_features; + /* Populate design-parameter defaults */ + nic_data->tso_max_hdr_len = ESE_EF100_DP_GZ_TSO_MAX_HDR_LEN_DEFAULT; + nic_data->tso_max_frames = ESE_EF100_DP_GZ_TSO_MAX_NUM_FRAMES_DEFAULT; + nic_data->tso_max_payload_num_segs = ESE_EF100_DP_GZ_TSO_MAX_PAYLOAD_NUM_SEGS_DEFAULT; + nic_data->tso_max_payload_len = ESE_EF100_DP_GZ_TSO_MAX_PAYLOAD_LEN_DEFAULT; + net_dev->gso_max_segs = ESE_EF100_DP_GZ_TSO_MAX_HDR_NUM_SEGS_DEFAULT; + /* Read design parameters */ + rc = ef100_check_design_params(efx); + if (rc) { + netif_err(efx, probe, efx->net_dev, + "Unsupported design parameters\n"); + goto fail; + } + /* we assume later that we can copy from this buffer in dwords */ BUILD_BUG_ON(MCDI_CTL_SDU_LEN_MAX_V2 % 4); @@ -551,6 +1168,10 @@ static int ef100_probe_main(struct efx_nic *efx) if (rc) goto fail; + rc = efx_get_pf_index(efx, &nic_data->pf_index); + if (rc) + goto fail; + rc = efx_ef100_init_datapath_caps(efx); if (rc < 0) goto fail; @@ -562,6 +1183,21 @@ static int ef100_probe_main(struct efx_nic *efx) goto fail; efx->port_num = rc; + efx_mcdi_print_fwver(efx, fw_version, sizeof(fw_version)); + netif_dbg(efx, drv, efx->net_dev, "Firmware version %s\n", fw_version); + + if (compare_versions(fw_version, "1.1.0.1000") < 0) { + netif_info(efx, drv, efx->net_dev, "Firmware uses old event descriptors\n"); + rc = -EINVAL; + goto fail; + } + + if (efx_has_cap(efx, UNSOL_EV_CREDIT_SUPPORTED)) { + netif_info(efx, drv, efx->net_dev, "Firmware uses unsolicited-event credits\n"); + rc = -EINVAL; + goto fail; + } + rc = ef100_phy_probe(efx); if (rc) goto fail; @@ -570,6 +1206,18 @@ static int ef100_probe_main(struct efx_nic *efx) if (rc) goto fail; + down_write(&efx->filter_sem); + rc = ef100_filter_table_probe(efx); + up_write(&efx->filter_sem); + if (rc) + goto fail; + + netdev_rss_key_fill(efx->rss_context.rx_hash_key, + sizeof(efx->rss_context.rx_hash_key)); + + /* Don't fail init if RSS setup doesn't work. */ + efx_mcdi_push_default_indir_table(efx, efx->n_rx_channels); + rc = ef100_register_netdev(efx); if (rc) goto fail; @@ -602,11 +1250,20 @@ fail: return rc; } +int ef100_probe_vf(struct efx_nic *efx) +{ + return ef100_probe_main(efx); +} + void ef100_remove(struct efx_nic *efx) { struct ef100_nic_data *nic_data = efx->nic_data; ef100_unregister_netdev(efx); + + down_write(&efx->filter_sem); + efx_mcdi_filter_table_remove(efx); + up_write(&efx->filter_sem); efx_fini_channels(efx); kfree(efx->phy_data); efx->phy_data = NULL; diff --git a/drivers/net/ethernet/sfc/ef100_nic.h b/drivers/net/ethernet/sfc/ef100_nic.h index 6367bbb2c9b3..e799688d5264 100644 --- a/drivers/net/ethernet/sfc/ef100_nic.h +++ b/drivers/net/ethernet/sfc/ef100_nic.h @@ -13,19 +13,67 @@ #include "nic_common.h" extern const struct efx_nic_type ef100_pf_nic_type; +extern const struct efx_nic_type ef100_vf_nic_type; int ef100_probe_pf(struct efx_nic *efx); +int ef100_probe_vf(struct efx_nic *efx); void ef100_remove(struct efx_nic *efx); +enum { + EF100_STAT_port_tx_bytes = GENERIC_STAT_COUNT, + EF100_STAT_port_tx_packets, + EF100_STAT_port_tx_pause, + EF100_STAT_port_tx_unicast, + EF100_STAT_port_tx_multicast, + EF100_STAT_port_tx_broadcast, + EF100_STAT_port_tx_lt64, + EF100_STAT_port_tx_64, + EF100_STAT_port_tx_65_to_127, + EF100_STAT_port_tx_128_to_255, + EF100_STAT_port_tx_256_to_511, + EF100_STAT_port_tx_512_to_1023, + EF100_STAT_port_tx_1024_to_15xx, + EF100_STAT_port_tx_15xx_to_jumbo, + EF100_STAT_port_rx_bytes, + EF100_STAT_port_rx_packets, + EF100_STAT_port_rx_good, + EF100_STAT_port_rx_bad, + EF100_STAT_port_rx_pause, + EF100_STAT_port_rx_unicast, + EF100_STAT_port_rx_multicast, + EF100_STAT_port_rx_broadcast, + EF100_STAT_port_rx_lt64, + EF100_STAT_port_rx_64, + EF100_STAT_port_rx_65_to_127, + EF100_STAT_port_rx_128_to_255, + EF100_STAT_port_rx_256_to_511, + EF100_STAT_port_rx_512_to_1023, + EF100_STAT_port_rx_1024_to_15xx, + EF100_STAT_port_rx_15xx_to_jumbo, + EF100_STAT_port_rx_gtjumbo, + EF100_STAT_port_rx_bad_gtjumbo, + EF100_STAT_port_rx_align_error, + EF100_STAT_port_rx_length_error, + EF100_STAT_port_rx_overflow, + EF100_STAT_port_rx_nodesc_drops, + EF100_STAT_COUNT +}; + struct ef100_nic_data { struct efx_nic *efx; struct efx_buffer mcdi_buf; u32 datapath_caps; u32 datapath_caps2; u32 datapath_caps3; + unsigned int pf_index; u16 warm_boot_count; u8 port_id[ETH_ALEN]; DECLARE_BITMAP(evq_phases, EFX_MAX_CHANNELS); + u64 stats[EF100_STAT_COUNT]; + u16 tso_max_hdr_len; + u16 tso_max_payload_num_segs; + u16 tso_max_frames; + unsigned int tso_max_payload_len; }; #define efx_ef100_has_cap(caps, flag) \ diff --git a/drivers/net/ethernet/sfc/ef100_rx.c b/drivers/net/ethernet/sfc/ef100_rx.c index 4223a38f46d3..13ba1a4f66fc 100644 --- a/drivers/net/ethernet/sfc/ef100_rx.c +++ b/drivers/net/ethernet/sfc/ef100_rx.c @@ -12,20 +12,156 @@ #include "ef100_rx.h" #include "rx_common.h" #include "efx.h" +#include "nic_common.h" +#include "mcdi_functions.h" +#include "ef100_regs.h" +#include "ef100_nic.h" +#include "io.h" -/* RX stubs */ +/* Get the value of a field in the RX prefix */ +#define PREFIX_OFFSET_W(_f) (ESF_GZ_RX_PREFIX_ ## _f ## _LBN / 32) +#define PREFIX_OFFSET_B(_f) (ESF_GZ_RX_PREFIX_ ## _f ## _LBN % 32) +#define PREFIX_WIDTH_MASK(_f) ((1UL << ESF_GZ_RX_PREFIX_ ## _f ## _WIDTH) - 1) +#define PREFIX_WORD(_p, _f) le32_to_cpu((__force __le32)(_p)[PREFIX_OFFSET_W(_f)]) +#define PREFIX_FIELD(_p, _f) ((PREFIX_WORD(_p, _f) >> PREFIX_OFFSET_B(_f)) & \ + PREFIX_WIDTH_MASK(_f)) -void ef100_rx_write(struct efx_rx_queue *rx_queue) +#define ESF_GZ_RX_PREFIX_NT_OR_INNER_L3_CLASS_LBN \ + (ESF_GZ_RX_PREFIX_CLASS_LBN + ESF_GZ_RX_PREFIX_HCLASS_NT_OR_INNER_L3_CLASS_LBN) +#define ESF_GZ_RX_PREFIX_NT_OR_ |