diff options
Diffstat (limited to 'drivers/net/ethernet/sfc')
-rw-r--r-- | drivers/net/ethernet/sfc/ef10.c | 319 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/ef10_regs.h | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/efx.c | 12 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/efx.h | 105 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/ethtool.c | 5 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/io.h | 5 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/mcdi.h | 122 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/mcdi_mon.c | 78 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/mdio_10g.h | 26 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/net_driver.h | 10 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/nic.c | 73 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/nic.h | 256 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/phy.h | 8 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/rx.c | 90 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/selftest.h | 15 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/tx.c | 426 |
16 files changed, 469 insertions, 1082 deletions
diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 676c3c0..21f9ad6 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -285,181 +285,6 @@ static int efx_ef10_free_vis(struct efx_nic *efx) return rc; } -#ifdef EFX_USE_PIO - -static void efx_ef10_free_piobufs(struct efx_nic *efx) -{ - struct efx_ef10_nic_data *nic_data = efx->nic_data; - MCDI_DECLARE_BUF(inbuf, MC_CMD_FREE_PIOBUF_IN_LEN); - unsigned int i; - int rc; - - BUILD_BUG_ON(MC_CMD_FREE_PIOBUF_OUT_LEN != 0); - - for (i = 0; i < nic_data->n_piobufs; i++) { - MCDI_SET_DWORD(inbuf, FREE_PIOBUF_IN_PIOBUF_HANDLE, - nic_data->piobuf_handle[i]); - rc = efx_mcdi_rpc(efx, MC_CMD_FREE_PIOBUF, inbuf, sizeof(inbuf), - NULL, 0, NULL); - WARN_ON(rc); - } - - nic_data->n_piobufs = 0; -} - -static int efx_ef10_alloc_piobufs(struct efx_nic *efx, unsigned int n) -{ - struct efx_ef10_nic_data *nic_data = efx->nic_data; - MCDI_DECLARE_BUF(outbuf, MC_CMD_ALLOC_PIOBUF_OUT_LEN); - unsigned int i; - size_t outlen; - int rc = 0; - - BUILD_BUG_ON(MC_CMD_ALLOC_PIOBUF_IN_LEN != 0); - - for (i = 0; i < n; i++) { - rc = efx_mcdi_rpc(efx, MC_CMD_ALLOC_PIOBUF, NULL, 0, - outbuf, sizeof(outbuf), &outlen); - if (rc) - break; - if (outlen < MC_CMD_ALLOC_PIOBUF_OUT_LEN) { - rc = -EIO; - break; - } - nic_data->piobuf_handle[i] = - MCDI_DWORD(outbuf, ALLOC_PIOBUF_OUT_PIOBUF_HANDLE); - netif_dbg(efx, probe, efx->net_dev, - "allocated PIO buffer %u handle %x\n", i, - nic_data->piobuf_handle[i]); - } - - nic_data->n_piobufs = i; - if (rc) - efx_ef10_free_piobufs(efx); - return rc; -} - -static int efx_ef10_link_piobufs(struct efx_nic *efx) -{ - struct efx_ef10_nic_data *nic_data = efx->nic_data; - MCDI_DECLARE_BUF(inbuf, - max(MC_CMD_LINK_PIOBUF_IN_LEN, - MC_CMD_UNLINK_PIOBUF_IN_LEN)); - struct efx_channel *channel; - struct efx_tx_queue *tx_queue; - unsigned int offset, index; - int rc; - - BUILD_BUG_ON(MC_CMD_LINK_PIOBUF_OUT_LEN != 0); - BUILD_BUG_ON(MC_CMD_UNLINK_PIOBUF_OUT_LEN != 0); - - /* Link a buffer to each VI in the write-combining mapping */ - for (index = 0; index < nic_data->n_piobufs; ++index) { - MCDI_SET_DWORD(inbuf, LINK_PIOBUF_IN_PIOBUF_HANDLE, - nic_data->piobuf_handle[index]); - MCDI_SET_DWORD(inbuf, LINK_PIOBUF_IN_TXQ_INSTANCE, - nic_data->pio_write_vi_base + index); - rc = efx_mcdi_rpc(efx, MC_CMD_LINK_PIOBUF, - inbuf, MC_CMD_LINK_PIOBUF_IN_LEN, - NULL, 0, NULL); - if (rc) { - netif_err(efx, drv, efx->net_dev, - "failed to link VI %u to PIO buffer %u (%d)\n", - nic_data->pio_write_vi_base + index, index, - rc); - goto fail; - } - netif_dbg(efx, probe, efx->net_dev, - "linked VI %u to PIO buffer %u\n", - nic_data->pio_write_vi_base + index, index); - } - - /* Link a buffer to each TX queue */ - efx_for_each_channel(channel, efx) { - efx_for_each_channel_tx_queue(tx_queue, channel) { - /* We assign the PIO buffers to queues in - * reverse order to allow for the following - * special case. - */ - offset = ((efx->tx_channel_offset + efx->n_tx_channels - - tx_queue->channel->channel - 1) * - efx_piobuf_size); - index = offset / ER_DZ_TX_PIOBUF_SIZE; - offset = offset % ER_DZ_TX_PIOBUF_SIZE; - - /* When the host page size is 4K, the first - * host page in the WC mapping may be within - * the same VI page as the last TX queue. We - * can only link one buffer to each VI. - */ - if (tx_queue->queue == nic_data->pio_write_vi_base) { - BUG_ON(index != 0); - rc = 0; - } else { - MCDI_SET_DWORD(inbuf, - LINK_PIOBUF_IN_PIOBUF_HANDLE, - nic_data->piobuf_handle[index]); - MCDI_SET_DWORD(inbuf, - LINK_PIOBUF_IN_TXQ_INSTANCE, - tx_queue->queue); - rc = efx_mcdi_rpc(efx, MC_CMD_LINK_PIOBUF, - inbuf, MC_CMD_LINK_PIOBUF_IN_LEN, - NULL, 0, NULL); - } - - if (rc) { - /* This is non-fatal; the TX path just - * won't use PIO for this queue - */ - netif_err(efx, drv, efx->net_dev, - "failed to link VI %u to PIO buffer %u (%d)\n", - tx_queue->queue, index, rc); - tx_queue->piobuf = NULL; - } else { - tx_queue->piobuf = - nic_data->pio_write_base + - index * EFX_VI_PAGE_SIZE + offset; - tx_queue->piobuf_offset = offset; - netif_dbg(efx, probe, efx->net_dev, - "linked VI %u to PIO buffer %u offset %x addr %p\n", - tx_queue->queue, index, - tx_queue->piobuf_offset, - tx_queue->piobuf); - } - } - } - - return 0; - -fail: - while (index--) { - MCDI_SET_DWORD(inbuf, UNLINK_PIOBUF_IN_TXQ_INSTANCE, - nic_data->pio_write_vi_base + index); - efx_mcdi_rpc(efx, MC_CMD_UNLINK_PIOBUF, - inbuf, MC_CMD_UNLINK_PIOBUF_IN_LEN, - NULL, 0, NULL); - } - return rc; -} - -#else /* !EFX_USE_PIO */ - -static int efx_ef10_alloc_piobufs(struct efx_nic *efx, unsigned int n) -{ - return n == 0 ? 0 : -ENOBUFS; -} - -static int efx_ef10_link_piobufs(struct efx_nic *efx) -{ - return 0; -} - -static void efx_ef10_free_piobufs(struct efx_nic *efx) -{ -} - -#endif /* EFX_USE_PIO */ - static void efx_ef10_remove(struct efx_nic *efx) { struct efx_ef10_nic_data *nic_data = efx->nic_data; @@ -470,15 +295,9 @@ static void efx_ef10_remove(struct efx_nic *efx) /* This needs to be after efx_ptp_remove_channel() with no filters */ efx_ef10_rx_free_indir_table(efx); - if (nic_data->wc_membase) - iounmap(nic_data->wc_membase); - rc = efx_ef10_free_vis(efx); WARN_ON(rc != 0); - if (!nic_data->must_restore_piobufs) - efx_ef10_free_piobufs(efx); - efx_mcdi_fini(efx); efx_nic_free_buffer(efx, &nic_data->mcdi_buf); kfree(nic_data); @@ -511,126 +330,12 @@ static int efx_ef10_alloc_vis(struct efx_nic *efx, return 0; } -/* Note that the failure path of this function does not free - * resources, as this will be done by efx_ef10_remove(). - */ static int efx_ef10_dimension_resources(struct efx_nic *efx) { - struct efx_ef10_nic_data *nic_data = efx->nic_data; - unsigned int uc_mem_map_size, wc_mem_map_size; - unsigned int min_vis, pio_write_vi_base, max_vis; - void __iomem *membase; - int rc; - - min_vis = max(efx->n_channels, efx->n_tx_channels * EFX_TXQ_TYPES); - -#ifdef EFX_USE_PIO - /* Try to allocate PIO buffers if wanted and if the full - * number of PIO buffers would be sufficient to allocate one - * copy-buffer per TX channel. Failure is non-fatal, as there - * are only a small number of PIO buffers shared between all - * functions of the controller. - */ - if (efx_piobuf_size != 0 && - ER_DZ_TX_PIOBUF_SIZE / efx_piobuf_size * EF10_TX_PIOBUF_COUNT >= - efx->n_tx_channels) { - unsigned int n_piobufs = - DIV_ROUND_UP(efx->n_tx_channels, - ER_DZ_TX_PIOBUF_SIZE / efx_piobuf_size); - - rc = efx_ef10_alloc_piobufs(efx, n_piobufs); - if (rc) - netif_err(efx, probe, efx->net_dev, - "failed to allocate PIO buffers (%d)\n", rc); - else - netif_dbg(efx, probe, efx->net_dev, - "allocated %u PIO buffers\n", n_piobufs); - } -#else - nic_data->n_piobufs = 0; -#endif + unsigned int n_vis = + max(efx->n_channels, efx->n_tx_channels * EFX_TXQ_TYPES); - /* PIO buffers should be mapped with write-combining enabled, - * and we want to make single UC and WC mappings rather than - * several of each (in fact that's the only option if host - * page size is >4K). So we may allocate some extra VIs just - * for writing PIO buffers through. - */ - uc_mem_map_size = PAGE_ALIGN((min_vis - 1) * EFX_VI_PAGE_SIZE + - ER_DZ_TX_PIOBUF); - if (nic_data->n_piobufs) { - pio_write_vi_base = uc_mem_map_size / EFX_VI_PAGE_SIZE; - wc_mem_map_size = (PAGE_ALIGN((pio_write_vi_base + - nic_data->n_piobufs) * - EFX_VI_PAGE_SIZE) - - uc_mem_map_size); - max_vis = pio_write_vi_base + nic_data->n_piobufs; - } else { - pio_write_vi_base = 0; - wc_mem_map_size = 0; - max_vis = min_vis; - } - - /* In case the last attached driver failed to free VIs, do it now */ - rc = efx_ef10_free_vis(efx); - if (rc != 0) - return rc; - - rc = efx_ef10_alloc_vis(efx, min_vis, max_vis); - if (rc != 0) - return rc; - - /* If we didn't get enough VIs to map all the PIO buffers, free the - * PIO buffers - */ - if (nic_data->n_piobufs && - nic_data->n_allocated_vis < - pio_write_vi_base + nic_data->n_piobufs) { - netif_dbg(efx, probe, efx->net_dev, - "%u VIs are not sufficient to map %u PIO buffers\n", - nic_data->n_allocated_vis, nic_data->n_piobufs); - efx_ef10_free_piobufs(efx); - } - - /* Shrink the original UC mapping of the memory BAR */ - membase = ioremap_nocache(efx->membase_phys, uc_mem_map_size); - if (!membase) { - netif_err(efx, probe, efx->net_dev, - "could not shrink memory BAR to %x\n", - uc_mem_map_size); - return -ENOMEM; - } - iounmap(efx->membase); - efx->membase = membase; - - /* Set up the WC mapping if needed */ - if (wc_mem_map_size) { - nic_data->wc_membase = ioremap_wc(efx->membase_phys + - uc_mem_map_size, - wc_mem_map_size); - if (!nic_data->wc_membase) { - netif_err(efx, probe, efx->net_dev, - "could not allocate WC mapping of size %x\n", - wc_mem_map_size); - return -ENOMEM; - } - nic_data->pio_write_vi_base = pio_write_vi_base; - nic_data->pio_write_base = - nic_data->wc_membase + - (pio_write_vi_base * EFX_VI_PAGE_SIZE + ER_DZ_TX_PIOBUF - - uc_mem_map_size); - - rc = efx_ef10_link_piobufs(efx); - if (rc) - efx_ef10_free_piobufs(efx); - } - - netif_dbg(efx, probe, efx->net_dev, - "memory BAR at %pa (virtual %p+%x UC, %p+%x WC)\n", - &efx->membase_phys, efx->membase, uc_mem_map_size, - nic_data->wc_membase, wc_mem_map_size); - - return 0; + return efx_ef10_alloc_vis(efx, n_vis, n_vis); } static int efx_ef10_init_nic(struct efx_nic *efx) @@ -654,21 +359,6 @@ static int efx_ef10_init_nic(struct efx_nic *efx) nic_data->must_realloc_vis = false; } - if (nic_data->must_restore_piobufs && nic_data->n_piobufs) { - rc = efx_ef10_alloc_piobufs(efx, nic_data->n_piobufs); - if (rc == 0) { - rc = efx_ef10_link_piobufs(efx); - if (rc) - efx_ef10_free_piobufs(efx); - } - - /* Log an error on failure, but this is non-fatal */ - if (rc) - netif_err(efx, drv, efx->net_dev, - "failed to restore PIO buffers (%d)\n", rc); - nic_data->must_restore_piobufs = false; - } - efx_ef10_rx_push_indir_table(efx); return 0; } @@ -1069,7 +759,6 @@ static int efx_ef10_mcdi_poll_reboot(struct efx_nic *efx) /* All our allocations have been reset */ nic_data->must_realloc_vis = true; nic_data->must_restore_filters = true; - nic_data->must_restore_piobufs = true; nic_data->rx_rss_context = EFX_EF10_RSS_CONTEXT_INVALID; /* The datapath firmware might have been changed */ @@ -2491,7 +2180,7 @@ out_unlock: return rc; } -static void efx_ef10_filter_update_rx_scatter(struct efx_nic *efx) +void efx_ef10_filter_update_rx_scatter(struct efx_nic *efx) { /* no need to do anything here on EF10 */ } diff --git a/drivers/net/ethernet/sfc/ef10_regs.h b/drivers/net/ethernet/sfc/ef10_regs.h index 207ac9a..b3f4e37 100644 --- a/drivers/net/ethernet/sfc/ef10_regs.h +++ b/drivers/net/ethernet/sfc/ef10_regs.h @@ -315,7 +315,6 @@ #define ESF_DZ_TX_PIO_TYPE_WIDTH 1 #define ESF_DZ_TX_PIO_OPT_LBN 60 #define ESF_DZ_TX_PIO_OPT_WIDTH 3 -#define ESE_DZ_TX_OPTION_DESC_PIO 1 #define ESF_DZ_TX_PIO_CONT_LBN 59 #define ESF_DZ_TX_PIO_CONT_WIDTH 1 #define ESF_DZ_TX_PIO_BYTE_CNT_LBN 32 diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 2e27837..07c9bc4 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -1121,7 +1121,7 @@ static int efx_init_io(struct efx_nic *efx) */ while (dma_mask > 0x7fffffffUL) { if (dma_supported(&pci_dev->dev, dma_mask)) { - rc = dma_set_mask_and_coherent(&pci_dev->dev, dma_mask); + rc = dma_set_mask(&pci_dev->dev, dma_mask); if (rc == 0) break; } @@ -1134,6 +1134,16 @@ 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); + rc = dma_set_coherent_mask(&pci_dev->dev, dma_mask); + if (rc) { + /* dma_set_coherent_mask() is not *allowed* to + * fail with a mask that dma_set_mask() accepted, + * but just in case... + */ + netif_err(efx, probe, efx->net_dev, + "failed to set consistent DMA mask\n"); + goto fail2; + } efx->membase_phys = pci_resource_start(efx->pci_dev, EFX_MEM_BAR); rc = pci_request_region(pci_dev, EFX_MEM_BAR, "sfc"); diff --git a/drivers/net/ethernet/sfc/efx.h b/drivers/net/ethernet/sfc/efx.h index b8235ee..34d00f5 100644 --- a/drivers/net/ethernet/sfc/efx.h +++ b/drivers/net/ethernet/sfc/efx.h @@ -18,36 +18,37 @@ #define EFX_MEM_BAR 2 /* TX */ -int efx_probe_tx_queue(struct efx_tx_queue *tx_queue); -void efx_remove_tx_queue(struct efx_tx_queue *tx_queue); -void efx_init_tx_queue(struct efx_tx_queue *tx_queue); -void efx_init_tx_queue_core_txq(struct efx_tx_queue *tx_queue); -void efx_fini_tx_queue(struct efx_tx_queue *tx_queue); -netdev_tx_t efx_hard_start_xmit(struct sk_buff *skb, - struct net_device *net_dev); -netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb); -void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index); -int efx_setup_tc(struct net_device *net_dev, u8 num_tc); -unsigned int efx_tx_max_skb_descs(struct efx_nic *efx); -extern unsigned int efx_piobuf_size; +extern int efx_probe_tx_queue(struct efx_tx_queue *tx_queue); +extern void efx_remove_tx_queue(struct efx_tx_queue *tx_queue); +extern void efx_init_tx_queue(struct efx_tx_queue *tx_queue); +extern void efx_init_tx_queue_core_txq(struct efx_tx_queue *tx_queue); +extern void efx_fini_tx_queue(struct efx_tx_queue *tx_queue); +extern netdev_tx_t +efx_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev); +extern netdev_tx_t +efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb); +extern void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index); +extern int efx_setup_tc(struct net_device *net_dev, u8 num_tc); +extern unsigned int efx_tx_max_skb_descs(struct efx_nic *efx); /* RX */ -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); -void efx_init_rx_queue(struct efx_rx_queue *rx_queue); -void efx_fini_rx_queue(struct efx_rx_queue *rx_queue); -void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue); -void efx_rx_slow_fill(unsigned long context); -void __efx_rx_packet(struct efx_channel *channel); -void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index, - unsigned int n_frags, unsigned int len, u16 flags); +extern void efx_rx_config_page_split(struct efx_nic *efx); +extern int efx_probe_rx_queue(struct efx_rx_queue *rx_queue); +extern void efx_remove_rx_queue(struct efx_rx_queue *rx_queue); +extern void efx_init_rx_queue(struct efx_rx_queue *rx_queue); +extern void efx_fini_rx_queue(struct efx_rx_queue *rx_queue); +extern void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue); +extern void efx_rx_slow_fill(unsigned long context); +extern void __efx_rx_packet(struct efx_channel *channel); +extern void efx_rx_packet(struct efx_rx_queue *rx_queue, + unsigned int index, unsigned int n_frags, + unsigned int len, u16 flags); static inline void efx_rx_flush_packet(struct efx_channel *channel) { if (channel->rx_pkt_n_frags) __efx_rx_packet(channel); } -void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue); +extern void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue); #define EFX_MAX_DMAQ_SIZE 4096UL #define EFX_DEFAULT_DMAQ_SIZE 1024UL @@ -161,9 +162,9 @@ static inline s32 efx_filter_get_rx_ids(struct efx_nic *efx, return efx->type->filter_get_rx_ids(efx, priority, buf, size); } #ifdef CONFIG_RFS_ACCEL -int efx_filter_rfs(struct net_device *net_dev, const struct sk_buff *skb, - u16 rxq_index, u32 flow_id); -bool __efx_filter_rfs_expire(struct efx_nic *efx, unsigned quota); +extern int efx_filter_rfs(struct net_device *net_dev, const struct sk_buff *skb, + u16 rxq_index, u32 flow_id); +extern bool __efx_filter_rfs_expire(struct efx_nic *efx, unsigned quota); static inline void efx_filter_rfs_expire(struct efx_channel *channel) { if (channel->rfs_filters_added >= 60 && @@ -175,48 +176,50 @@ static inline void efx_filter_rfs_expire(struct efx_channel *channel) static inline void efx_filter_rfs_expire(struct efx_channel *channel) {} #define efx_filter_rfs_enabled() 0 #endif -bool efx_filter_is_mc_recipient(const struct efx_filter_spec *spec); +extern bool efx_filter_is_mc_recipient(const struct efx_filter_spec *spec); /* Channels */ -int efx_channel_dummy_op_int(struct efx_channel *channel); -void efx_channel_dummy_op_void(struct efx_channel *channel); -int efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries); +extern int efx_channel_dummy_op_int(struct efx_channel *channel); +extern void efx_channel_dummy_op_void(struct efx_channel *channel); +extern int +efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries); /* Ports */ -int efx_reconfigure_port(struct efx_nic *efx); -int __efx_reconfigure_port(struct efx_nic *efx); +extern int efx_reconfigure_port(struct efx_nic *efx); +extern int __efx_reconfigure_port(struct efx_nic *efx); /* Ethtool support */ extern const struct ethtool_ops efx_ethtool_ops; /* Reset handling */ -int efx_reset(struct efx_nic *efx, enum reset_type method); -void efx_reset_down(struct efx_nic *efx, enum reset_type method); -int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok); -int efx_try_recovery(struct efx_nic *efx); +extern int efx_reset(struct efx_nic *efx, enum reset_type method); +extern void efx_reset_down(struct efx_nic *efx, enum reset_type method); +extern int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok); +extern int efx_try_recovery(struct efx_nic *efx); /* Global */ -void efx_schedule_reset(struct efx_nic *efx, enum reset_type type); -int efx_init_irq_moderation(struct efx_nic *efx, unsigned int tx_usecs, - unsigned int rx_usecs, bool rx_adaptive, - bool rx_may_override_tx); -void efx_get_irq_moderation(struct efx_nic *efx, unsigned int *tx_usecs, - unsigned int *rx_usecs, bool *rx_adaptive); +extern void efx_schedule_reset(struct efx_nic *efx, enum reset_type type); +extern int efx_init_irq_moderation(struct efx_nic *efx, unsigned int tx_usecs, + unsigned int rx_usecs, bool rx_adaptive, + bool rx_may_override_tx); +extern void efx_get_irq_moderation(struct efx_nic *efx, unsigned int *tx_usecs, + unsigned int *rx_usecs, bool *rx_adaptive); /* Dummy PHY ops for PHY drivers */ -int efx_port_dummy_op_int(struct efx_nic *efx); -void efx_port_dummy_op_void(struct efx_nic *efx); +extern int efx_port_dummy_op_int(struct efx_nic *efx); +extern void efx_port_dummy_op_void(struct efx_nic *efx); + /* MTD */ #ifdef CONFIG_SFC_MTD -int efx_mtd_add(struct efx_nic *efx, struct efx_mtd_partition *parts, - size_t n_parts, size_t sizeof_part); +extern int efx_mtd_add(struct efx_nic *efx, struct efx_mtd_partition *parts, + size_t n_parts, size_t sizeof_part); static inline int efx_mtd_probe(struct efx_nic *efx) { return efx->type->mtd_probe(efx); } -void efx_mtd_rename(struct efx_nic *efx); -void efx_mtd_remove(struct efx_nic *efx); +extern void efx_mtd_rename(struct efx_nic *efx); +extern void efx_mtd_remove(struct efx_nic *efx); #else static inline int efx_mtd_probe(struct efx_nic *efx) { return 0; } static inline void efx_mtd_rename(struct efx_nic *efx) {} @@ -238,9 +241,9 @@ static inline void efx_schedule_channel_irq(struct efx_channel *channel) efx_schedule_channel(channel); } -void efx_link_status_changed(struct efx_nic *efx); -void efx_link_set_advertising(struct efx_nic *efx, u32); -void efx_link_set_wanted_fc(struct efx_nic *efx, u8); +extern void efx_link_status_changed(struct efx_nic *efx); +extern void efx_link_set_advertising(struct efx_nic *efx, u32); +extern void efx_link_set_wanted_fc(struct efx_nic *efx, u8); static inline void efx_device_detach_sync(struct efx_nic *efx) { diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c index 1f529fa..5b471cf 100644 --- a/drivers/net/ethernet/sfc/ethtool.c +++ b/drivers/net/ethernet/sfc/ethtool.c @@ -70,7 +70,6 @@ static const struct efx_sw_stat_desc efx_sw_stat_desc[] = { EFX_ETHTOOL_UINT_TXQ_STAT(tso_long_headers), EFX_ETHTOOL_UINT_TXQ_STAT(tso_packets), EFX_ETHTOOL_UINT_TXQ_STAT(pushes), - EFX_ETHTOOL_UINT_TXQ_STAT(pio_packets), EFX_ETHTOOL_ATOMIC_NIC_ERROR_STAT(rx_reset), EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_tobe_disc), EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_ip_hdr_chksum_err), @@ -1036,8 +1035,8 @@ static int efx_ethtool_set_rxfh_indir(struct net_device *net_dev, return 0; } -static int efx_ethtool_get_ts_info(struct net_device *net_dev, - struct ethtool_ts_info *ts_info) +int efx_ethtool_get_ts_info(struct net_device *net_dev, + struct ethtool_ts_info *ts_info) { struct efx_nic *efx = netdev_priv(net_dev); diff --git a/drivers/net/ethernet/sfc/io.h b/drivers/net/ethernet/sfc/io.h index 4d3f119..96ce507 100644 --- a/drivers/net/ethernet/sfc/io.h +++ b/drivers/net/ethernet/sfc/io.h @@ -66,11 +66,6 @@ #define EFX_USE_QWORD_IO 1 #endif -/* PIO is a win only if write-combining is possible */ -#ifdef ARCH_HAS_IOREMAP_WC -#define EFX_USE_PIO 1 -#endif - #ifdef EFX_USE_QWORD_IO static inline void _efx_writeq(struct efx_nic *efx, __le64 value, unsigned int reg) diff --git a/drivers/net/ethernet/sfc/mcdi.h b/drivers/net/ethernet/sfc/mcdi.h index 15816ca..c34d0d4 100644 --- a/drivers/net/ethernet/sfc/mcdi.h +++ b/drivers/net/ethernet/sfc/mcdi.h @@ -75,8 +75,6 @@ struct efx_mcdi_mon { unsigned long last_update; struct device *device; struct efx_mcdi_mon_attribute *attrs; - struct attribute_group group; - const struct attribute_group *groups[2]; unsigned int n_attrs; }; @@ -110,35 +108,38 @@ static inline struct efx_mcdi_mon *efx_mcdi_mon(struct efx_nic *efx) } #endif -int efx_mcdi_init(struct efx_nic *efx); -void efx_mcdi_fini(struct efx_nic *efx); +extern int efx_mcdi_init(struct efx_nic *efx); +extern void efx_mcdi_fini(struct efx_nic *efx); -int efx_mcdi_rpc(struct efx_nic *efx, unsigned cmd, const efx_dword_t *inbuf, - size_t inlen, efx_dword_t *outbuf, size_t outlen, - size_t *outlen_actual); - -int efx_mcdi_rpc_start(struct efx_nic *efx, unsigned cmd, - const efx_dword_t *inbuf, size_t inlen); -int efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned cmd, size_t inlen, +extern int efx_mcdi_rpc(struct efx_nic *efx, unsigned cmd, + const efx_dword_t *inbuf, size_t inlen, efx_dword_t *outbuf, size_t outlen, size_t *outlen_actual); +extern int efx_mcdi_rpc_start(struct efx_nic *efx, unsigned cmd, + const efx_dword_t *inbuf, size_t inlen); +extern int efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned cmd, size_t inlen, + efx_dword_t *outbuf, size_t outlen, + size_t *outlen_actual); + typedef void efx_mcdi_async_completer(struct efx_nic *efx, unsigned long cookie, int rc, efx_dword_t *outbuf, size_t outlen_actual); -int efx_mcdi_rpc_async(struct efx_nic *efx, unsigned int cmd, - const efx_dword_t *inbuf, size_t inlen, size_t outlen, - efx_mcdi_async_completer *complete, - unsigned long cookie); +extern int efx_mcdi_rpc_async(struct efx_nic *efx, unsigned int cmd, + const efx_dword_t *inbuf, size_t inlen, + size_t outlen, + efx_mcdi_async_completer *complete, + unsigned long cookie); -int efx_mcdi_poll_reboot(struct efx_nic *efx); -void efx_mcdi_mode_poll(struct efx_nic *efx); -void efx_mcdi_mode_event(struct efx_nic *efx); -void efx_mcdi_flush_async(struct efx_nic *efx); +extern int efx_mcdi_poll_reboot(struct efx_nic *efx); +extern void efx_mcdi_mode_poll(struct efx_nic *efx); +extern void efx_mcdi_mode_event(struct efx_nic *efx); +extern void efx_mcdi_flush_async(struct efx_nic *efx); -void efx_mcdi_process_event(struct efx_channel *channel, efx_qword_t *event); -void efx_mcdi_sensor_event(struct efx_nic *efx, efx_qword_t *ev); +extern void efx_mcdi_process_event(struct efx_channel *channel, + efx_qword_t *event); +extern void efx_mcdi_sensor_event(struct efx_nic *efx, efx_qword_t *ev); /* We expect that 16- and 32-bit fields in MCDI requests and responses * are appropriately aligned, but 64-bit fields are only @@ -274,54 +275,55 @@ void efx_mcdi_sensor_event(struct efx_nic *efx, efx_qword_t *ev); #define MCDI_EVENT_FIELD(_ev, _field) \ EFX_QWORD_FIELD(_ev, MCDI_EVENT_ ## _field) -void efx_mcdi_print_fwver(struct efx_nic *efx, char *buf, size_t len); -int efx_mcdi_get_board_cfg(struct efx_nic *efx, u8 *mac_address, - u16 *fw_subtype_list, u32 *capabilities); -int efx_mcdi_log_ctrl(struct efx_nic *efx, bool evq, bool uart, u32 dest_evq); -int efx_mcdi_nvram_types(struct efx_nic *efx, u32 *nvram_types_out); -int efx_mcdi_nvram_info(struct efx_nic *efx, unsigned int type, - size_t *size_out, size_t *erase_size_out, - bool *protected_out); -int efx_mcdi_nvram_test_all(struct efx_nic *efx); -int efx_mcdi_handle_assertion(struct efx_nic *efx); -void efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode); -int efx_mcdi_wol_filter_set_magic(struct efx_nic *efx, const u8 *mac, - int *id_out); -int efx_mcdi_wol_filter_get_magic(struct efx_nic *efx, int *id_out); -int efx_mcdi_wol_filter_remove(struct efx_nic *efx, int id); -int efx_mcdi_wol_filter_reset(struct efx_nic *efx); -int efx_mcdi_flush_rxqs(struct efx_nic *efx); -int efx_mcdi_port_probe(struct efx_nic *efx); -void efx_mcdi_port_remove(struct efx_nic *efx); -int efx_mcdi_port_reconfigure(struct efx_nic *efx); -int efx_mcdi_port_get_number(struct efx_nic *efx); -u32 efx_mcdi_phy_get_caps(struct efx_nic *efx); -void efx_mcdi_process_link_change(struct efx_nic *efx, efx_qword_t *ev); -int efx_mcdi_set_mac(struct efx_nic *efx); +extern void efx_mcdi_print_fwver(struct efx_nic *efx, char *buf, size_t len); +extern int efx_mcdi_get_board_cfg(struct efx_nic *efx, u8 *mac_address, + u16 *fw_subtype_list, u32 *capabilities); +extern int efx_mcdi_log_ctrl(struct efx_nic *efx, bool evq, bool uart, + u32 dest_evq); +extern int efx_mcdi_nvram_types(struct efx_nic *efx, u32 *nvram_types_out); +extern int efx_mcdi_nvram_info(struct efx_nic *efx, unsigned int type, + size_t *size_out, size_t *erase_size_out, + bool *protected_out); +extern int efx_mcdi_nvram_test_all(struct efx_nic *efx); +extern int efx_mcdi_handle_assertion(struct efx_nic *efx); +extern void efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode); +extern int efx_mcdi_wol_filter_set_magic(struct efx_nic *efx, + const u8 *mac, int *id_out); +extern int efx_mcdi_wol_filter_get_magic(struct efx_nic *efx, int *id_out); +extern int efx_mcdi_wol_filter_remove(struct efx_nic *efx, int id); +extern int efx_mcdi_wol_filter_reset(struct efx_nic *efx); +extern int efx_mcdi_flush_rxqs(struct efx_nic *efx); +extern int efx_mcdi_port_probe(struct efx_nic *efx); +extern void efx_mcdi_port_remove(struct efx_nic *efx); +extern int efx_mcdi_port_reconfigure(struct efx_nic *efx); +extern int efx_mcdi_port_get_number(struct efx_nic *efx); +extern u32 efx_mcdi_phy_get_caps(struct efx_nic *efx); +extern void efx_mcdi_process_link_change(struct efx_nic *efx, efx_qword_t *ev); +extern int efx_mcdi_set_mac(struct efx_nic *efx); #define EFX_MC_STATS_GENERATION_INVALID ((__force __le64)(-1)) -void efx_mcdi_mac_start_stats(struct efx_nic *efx); -void efx_mcdi_mac_stop_stats(struct efx_nic *efx); -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); +extern void efx_mcdi_mac_start_stats(struct efx_nic *efx); +extern void efx_mcdi_mac_stop_stats(struct efx_nic *efx); +extern bool efx_mcdi_mac_check_fault(struct efx_nic *efx); +extern enum reset_type efx_mcdi_map_reset_reason(enum reset_type reason); +extern int efx_mcdi_reset(struct efx_nic *efx, enum reset_type method); +extern int efx_mcdi_set_workaround(struct efx_nic *efx, u32 type, bool enabled); #ifdef CONFIG_SFC_MCDI_MON -int efx_mcdi_mon_probe(struct efx_nic *efx); -void efx_mcdi_mon_remove(struct efx_nic *efx); +extern int efx_mcdi_mon_probe(struct efx_nic *efx); +extern void efx_mcdi_mon_remove(struct efx_nic *efx); #else static inline int efx_mcdi_mon_probe(struct efx_nic *efx) { return 0; } static inline void efx_mcdi_mon_remove(struct efx_nic *efx) {} #endif #ifdef CONFIG_SFC_MTD -int efx_mcdi_mtd_read(struct mtd_info *mtd, loff_t start, size_t len, - size_t *retlen, u8 *buffer); -int efx_mcdi_mtd_erase(struct mtd_info *mtd, loff_t start, size_t len); -int efx_mcdi_mtd_write(struct mtd_info *mtd, loff_t start, size_t len, - size_t *retlen, const u8 *buffer); -int efx_mcdi_mtd_sync(struct mtd_info *mtd); -void efx_mcdi_mtd_rename(struct efx_mtd_partition *part); +extern int efx_mcdi_mtd_read(struct mtd_info *mtd, loff_t start, + size_t len, size_t *retlen, u8 *buffer); +extern int efx_mcdi_mtd_erase(struct mtd_info *mtd, loff_t start, size_t len); +extern int efx_mcdi_mtd_write(struct mtd_info *mtd, loff_t start, + size_t len, size_t *retlen, const u8 *buffer); +extern int efx_mcdi_mtd_sync(struct mtd_info *mtd); +extern void efx_mcdi_mtd_rename(struct efx_mtd_partition *part); #endif #endif /* EFX_MCDI_H */ diff --git a/drivers/net/ethernet/sfc/mcdi_mon.c b/drivers/net/ethernet/sfc/mcdi_mon.c index d72ad4f..4cc5d95 100644 --- a/drivers/net/ethernet/sfc/mcdi_mon.c +++ b/drivers/net/ethernet/sfc/mcdi_mon.c @@ -139,10 +139,17 @@ static int efx_mcdi_mon_update(struct efx_nic *efx) return rc; } +static ssize_t efx_mcdi_mon_show_name(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%s\n", KBUILD_MODNAME); +} + static int efx_mcdi_mon_get_entry(struct device *dev, unsigned int index, efx_dword_t *entry) { - struct efx_nic *efx = dev_get_drvdata(dev->parent); + struct efx_nic *efx = dev_get_drvdata(dev); struct efx_mcdi_mon *hwmon = efx_mcdi_mon(efx); int rc; @@ -256,7 +263,7 @@ static ssize_t efx_mcdi_mon_show_label(struct device *dev, efx_mcdi_sensor_type[mon_attr->type].label); } -static void +static int efx_mcdi_mon_add_attr(struct efx_nic *efx, const char *name, ssize_t (*reader)(struct device *, struct device_attribute *, char *), @@ -265,6 +272,7 @@ efx_mcdi_mon_add_attr(struct efx_nic *efx, const char *name, { struct efx_mcdi_mon *hwmon = efx_mcdi_mon(efx); struct efx_mcdi_mon_attribute *attr = &hwmon->attrs[hwmon->n_attrs]; + int rc; strlcpy(attr->name, name, sizeof(attr->name)); attr->index = index; @@ -278,7 +286,10 @@ efx_mcdi_mon_add_attr(struct efx_nic *efx, const char *name, attr->dev_attr.attr.name = attr->name; attr->dev_attr.attr.mode = S_IRUGO; attr->dev_attr.show = reader; - hwmon->group.attrs[hwmon->n_attrs++] = &attr->dev_attr.attr; + rc = device_create_file(&efx->pci_dev->dev, &attr->dev_attr); + if (rc == 0) + ++hwmon->n_attrs; + return rc; } int efx_mcdi_mon_probe(struct efx_nic *efx) @@ -327,22 +338,26 @@ int efx_mcdi_mon_probe(struct efx_nic *efx) efx_mcdi_mon_update(efx); /* Allocate space for the maximum possible number of - * attributes for this set of sensors: + * attributes for this set of sensors: name of the driver plus * value, min, max, crit, alarm and label for each sensor. */ - n_attrs = 6 * n_sensors; + n_attrs = 1 + 6 * n_sensors; hwmon->attrs = kcalloc(n_attrs, sizeof(*hwmon->attrs), GFP_KERNEL); if (!hwmon->attrs) { rc = -ENOMEM; goto fail; } - hwmon->group.attrs = kcalloc(n_attrs + 1, sizeof(struct attribute *), - GFP_KERNEL); - if (!hwmon->group.attrs) { - rc = -ENOMEM; + + hwmon->device = hwmon_device_register(&efx->pci_dev->dev); + if (IS_ERR(hwmon->device)) { + rc = PTR_ERR(hwmon->device); goto fail; } + rc = efx_mcdi_mon_add_attr(efx, "name", efx_mcdi_mon_show_name, 0, 0, 0); + if (rc) + goto fail; + for (i = 0, j = -1, type = -1; ; i++) { enum efx_hwmon_type hwmon_type; const char *hwmon_prefix; @@ -357,7 +372,7 @@ int efx_mcdi_mon_probe(struct efx_nic *efx) page = type / 32; j = -1; if (page == n_pages) - goto hwmon_register; + return 0; MCDI_SET_DWORD(inbuf, SENSOR_INFO_EXT_IN_PAGE, page); @@ -438,22 +453,28 @@ int efx_mcdi_mon_probe(struct efx_nic *efx) if (min1 != max1) { snprintf(name, sizeof(name), "%s%u_input", hwmon_prefix, hwmon_index); - efx_mcdi_mon_add_attr( + rc = efx_mcdi_mon_add_attr( efx, name, efx_mcdi_mon_show_value, i, type, 0); + if (rc) + goto fail; if (hwmon_type != EFX_HWMON_POWER) { snprintf(name, sizeof(name), "%s%u_min", hwmon_prefix, hwmon_index); - efx_mcdi_mon_add_attr( + rc = efx_mcdi_mon_add_attr( efx, name, efx_mcdi_mon_show_limit, i, type, min1); + if (rc) + goto fail; } snprintf(name, sizeof(name), "%s%u_max", hwmon_prefix, hwmon_index); - efx_mcdi_mon_add_attr( + rc = efx_mcdi_mon_add_attr( efx, name, efx_mcdi_mon_show_limit, i, type, max1); + if (rc) + goto fail; if (min2 != max2) { /* Assume max2 is critical value. @@ -461,38 +482,32 @@ int efx_mcdi_mon_probe(struct efx_nic *efx) */ snprintf(name, sizeof(name), "%s%u_crit", hwmon_prefix, hwmon_index); - efx_mcdi_mon_add_attr( + rc = efx_mcdi_mon_add_attr( efx, name, efx_mcdi_mon_show_limit, i, type, max2); + if (rc) + goto fail; } } snprintf(name, sizeof(name), "%s%u_alarm", hwmon_prefix, hwmon_index); - efx_mcdi_mon_add_attr( + rc = efx_mcdi_mon_add_attr( efx, name, efx_mcdi_mon_show_alarm, i, type, 0); + if (rc) + goto fail; if (type < ARRAY_SIZE(efx_mcdi_sensor_type) && efx_mcdi_sensor_type[type].label) { snprintf(name, sizeof(name), "%s%u_label", hwmon_prefix, hwmon_index); - efx_mcdi_mon_add_attr( + rc = efx_mcdi_mon_add_attr( efx, name, efx_mcdi_mon_show_label, i, type, 0); + if (rc) + goto fail; } } -hwmon_register: - hwmon->groups[0] = &hwmon->group; - hwmon->device = hwmon_device_register_with_groups(&efx->pci_dev->dev, - KBUILD_MODNAME, NULL, - hwmon->groups); - if (IS_ERR(hwmon->device)) { - rc = PTR_ERR(hwmon->device); - goto fail; - } - - return 0; - fail: efx_mcdi_mon_remove(efx); return rc; @@ -501,11 +516,14 @@ fail: void efx_mcdi_mon_remove(struct efx_nic *efx) { struct efx_mcdi_mon *hwmon = efx_mcdi_mon(efx); + unsigned int i; + for (i = 0; i < hwmon->n_attrs; i++) + device_remove_file(&efx->pci_dev->dev, + &hwmon->attrs[i].dev_attr); + kfree(hwmon->attrs); if (hwmon->device) hwmon_device_unregister(hwmon->device); - kfree(hwmon->attrs); - kfree(hwmon->group.attrs); efx_nic_free_buffer(efx, &hwmon->dma_buf); } diff --git a/drivers/net/ethernet/sfc/mdio_10g.h b/drivers/net/ethernet/sfc/mdio_10g.h index 4a2dc4c..16824fe 100644 --- a/drivers/net/ethernet/sfc/mdio_10g.h +++ b/drivers/net/ethernet/sfc/mdio_10g.h @@ -20,7 +20,7 @@ static inline unsigned efx_mdio_id_rev(u32 id) { return id & 0xf; } static inline unsigned efx_mdio_id_model(u32 id) { return (id >> 4) & 0x3f; } -unsigned efx_mdio_id_oui(u32 id); +extern unsigned efx_mdio_id_oui(u32 id); static inline int efx_mdio_read(struct efx_nic *efx, int devad, int addr) { @@ -56,7 +56,7 @@ static inline bool efx_mdio_phyxgxs_lane_sync(struct efx_nic *efx) return sync; } -const char *efx_mdio_mmd_name(int mmd); +extern const char *efx_mdio_mmd_name(int mmd); /* * Reset a specific MMD and wait for reset to clear. @@ -64,29 +64,30 @@ const char *efx_mdio_mmd_name(int mmd); * * This function will sleep */ -int efx_mdio_reset_mmd(struct efx_nic *efx, int mmd, int spins, int spintime); +extern int efx_mdio_reset_mmd(struct efx_nic *efx, int mmd, + int spins, int spintime); /* As efx_mdio_check_mmd but for multiple MMDs */ int efx_mdio_check_mmds(struct efx_nic *efx, unsigned int mmd_mask); /* Check the link status of specified mmds in bit mask */ -bool efx_mdio_links_ok(struct efx_nic *efx, unsigned int mmd_mask); +extern bool efx_mdio_links_ok(struct efx_nic *efx, unsigned int mmd_mask); /* Generic transmit disable support though PMAPMD */ -void efx_mdio_transmit_disable(struct efx_nic *efx); +extern void efx_mdio_transmit_disable(struct efx_nic *efx); /* Generic part of reconfigure: set/clear loopback bits */ -void efx_mdio_phy_reconfigure(struct efx_nic *efx); +extern void efx_mdio_phy_reconfigure(struct efx_nic *efx); /* Set the power state of the specified MMDs */ -void efx_mdio_set_mmds_lpower(struct efx_nic *efx, int low_power, - unsigned int mmd_mask); +extern void efx_mdio_set_mmds_lpower(struct efx_nic *efx, + int low_power, unsigned int mmd_mask); /* Set (some of) the PHY settings over MDIO */ -int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd); +extern int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd); /* Push advertising flags and restart autonegotiation */ -void efx_mdio_an_reconfigure(struct efx_nic *efx); +extern void efx_mdio_an_reconfigure(struct efx_nic *efx); /* Get pause parameters from AN if available (otherwise return * requested pause parameters) @@ -94,7 +95,8 @@ void efx_mdio_an_reconfigure(struct efx_nic *efx); u8 efx_mdio_get_pause(struct efx_nic *efx); /* Wait for specified MMDs to exit reset within a timeout */ -int efx_mdio_wait_reset_mmds(struct efx_nic *efx, unsigned int mmd_mask); +extern int efx_mdio_wait_reset_mmds(struct efx_nic *efx, + unsigned int mmd_mask); /* Set or clear flag, debouncing */ static inline void @@ -105,6 +107,6 @@ efx_mdio_set_flag(struct efx_nic *efx, int devad, int addr, } /* Liveness self-test for MDIO PHYs */ -int efx_mdio_test_alive(struct efx_nic *efx); +extern int efx_mdio_test_alive(struct efx_nic *efx); #endif /* EFX_MDIO_10G_H */ diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index b14a717..b172ed1 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -141,8 +141,6 @@ struct efx_special_buffer { * @len: Length of this fragment. * This field is zero when the queue slot is empty. * @unmap_len: Length of this fragment to unmap - * @dma_offset: Offset of @dma_addr from the address of the backing DMA mapping. - * Only valid if @unmap_len != 0. */ struct efx_tx_buffer { union { @@ -156,7 +154,6 @@ struct efx_tx_buffer { unsigned short flags; unsigned short len; unsigned short unmap_len; - unsigned short dma_offset; }; #define EFX_TX_BUF_CONT 1 /* not last descriptor of packet */ #define EFX_TX_BUF_SKB 2 /* buffer is last part of skb */ @@ -185,9 +182,6 @@ struct efx_tx_buffer { * @tsoh_page: Array of pages of TSO header buffers * @txd: The hardware descriptor ring * @ptr_mask: The size of the ring minus 1. - * @piobuf: PIO buffer region for this TX queue (shared with its partner). - * Size of the region is efx_piobuf_size. - * @piobuf_offset: Buffer offset to be specified in PIO descriptors * @initialised: Has hardware queue been initialised? * @read_count: Current read pointer. * This is the number of buffers that have been removed from both rings. @@ -215,7 +209,6 @@ struct efx_tx_buffer { * blocks * @tso_packets: Number of packets via the TSO xmit path * @pushes: Number of times the TX push feature has been used - * @pio_packets: Number of times the TX PIO feature has been used * @empty_read_count: If the completion path has seen the queue as empty * and the transmission path has not yet checked this, the value of * @read_count bitwise-added to %EFX_EMPTY_COUNT_VALID; otherwise 0. @@ -230,8 +223,6 @@ struct efx_tx_queue { struct efx_buffer *tsoh_page; struct efx_special_buffer txd; unsigned int ptr_mask; - void __iomem *piobuf; - unsigned int piobuf_offset; bool initialised; /* Members used mainly on the completion path */ @@ -247,7 +238,6 @@ struct efx_tx_queue { unsigned int tso_long_headers; unsigned int tso_packets; unsigned int pushes; - unsigned int pio_packets; /* Members shared between paths and sometimes updated */ unsigned int empty_read_count ____cacheline_aligned_in_smp; diff --git a/drivers/net/ethernet/sfc/nic.c b/drivers/net/ethernet/sfc/nic.c index 9c90bf5..9826594 100644 --- a/drivers/net/ethernet/sfc/nic.c +++ b/drivers/net/ethernet/sfc/nic.c @@ -19,7 +19,6 @@ #include "bitfield.h" #include "efx.h" #include "nic.h" -#include "ef10_regs.h" #include "farch_regs.h" #include "io.h" #include "workarounds.h" @@ -167,30 +166,26 @@ void efx_nic_fini_interrupt(struct efx_nic *efx) /* Register dump */ -#define REGISTER_REVISION_FA 1 -#define REGISTER_REVISION_FB 2 -#define REGISTER_REVISION_FC 3 -#define REGISTER_REVISION_FZ 3 /* last Falcon arch revision */ -#define REGISTER_REVISION_ED 4 -#define REGISTER_REVISION_EZ 4 /* latest EF10 revision */ +#define REGISTER_REVISION_A 1 +#define REGISTER_REVISION_B 2 +#define REGISTER_REVISION_C 3 +#define REGISTER_REVISION_Z 3 /* latest revision */ struct efx_nic_reg { u32 offset:24; - u32 min_revision:3, max_revision:3; + u32 min_revision:2, max_revision:2; }; -#define REGISTER(name, arch, min_rev, max_rev) { \ - arch ## R_ ## min_rev ## max_rev ## _ ## name, \ - REGISTER_REVISION_ ## arch ## min_rev, \ - REGISTER_REVISION_ ## arch ## max_rev \ +#define REGISTER(name, min_rev, max_rev) { \ + FR_ ## min_rev ## max_rev ## _ ## name, \ + REGISTER_REVISION_ ## min_rev, REGISTER_REVISION_ ## max_rev \ } -#define REGISTER_AA(name) REGISTER(name, F, A, A) -#define REGISTER_AB(name) REGISTER(name, F, A, B) -#define REGISTER_AZ(name) REGISTER(name, F, A, Z) -#define REGISTER_BB(name) REGISTER(name, F, B, B) -#define REGISTER_BZ(name) REGISTER(name, F, B, Z) -#define REGISTER_CZ(name) REGISTER(name, F, C, Z) -#define REGISTER_DZ(name) REGISTER(name, E, D, Z) +#define REGISTER_AA(name) REGISTER(name, A, A) +#define REGISTER_AB(name) REGISTER(name, A, B) +#define REGISTER_AZ(name) REGISTER(name, A, Z) +#define REGISTER_BB(name) REGISTER(name, B, B) +#define REGISTER_BZ(name) REGISTER(name, B, Z) +#define REGISTER_CZ(name) REGISTER(name, C, Z) static const struct efx_nic_reg efx_nic_regs[] = { REGISTER_AZ(ADR_REGION), @@ -297,42 +292,37 @@ static const struct efx_nic_reg efx_nic_regs[] = { REGISTER_AB(XX_TXDRV_CTL), /* XX_PRBS_CTL, XX_PRBS_CHK and XX_PRBS_ERR are not used */ /* XX_CORE_STAT is partly RC */ - REGISTER_DZ(BIU_HW_REV_ID), - REGISTER_DZ(MC_DB_LWRD), - REGISTER_DZ(MC_DB_HWRD), }; struct efx_nic_reg_table { u32 offset:24; - u32 min_revision:3, max_revision:3; + u32 min_revision:2, max_revision:2; u32 step:6, rows:21; }; -#define REGISTER_TABLE_DIMENSIONS(_, offset, arch, min_rev, max_rev, step, rows) { \ +#define REGISTER_TABLE_DIMENSIONS(_, offset, min_rev, max_rev, step, rows) { \ offset, \ - REGISTER_REVISION_ ## arch ## min_rev, \ - REGISTER_REVISION_ ## arch ## max_rev, \ + REGISTER_REVISION_ ## min_rev, REGISTER_REVISION_ ## max_rev, \ step, rows \ } -#define REGISTER_TABLE(name, arch, min_rev, max_rev) \ +#define REGISTER_TABLE(name, min_rev, max_rev) \ REGISTER_TABLE_DIMENSIONS( \ - name, arch ## R_ ## min_rev ## max_rev ## _ ## name, \ - arch, min_rev, max_rev, \ - arch ## R_ ## min_rev ## max_rev ## _ ## name ## _STEP, \ - arch ## R_ ## min_rev ## max_rev ## _ ## name ## _ROWS) -#define REGISTER_TABLE_AA(name) REGISTER_TABLE(name, F, A, A) -#define REGISTER_TABLE_AZ(name) REGISTER_TABLE(name, F, A, Z) -#define REGISTER_TABLE_BB(name) REGISTER_TABLE(name, F, B, B) -#define REGISTER_TABLE_BZ(name) REGISTER_TABLE(name, F, B, Z) + name, FR_ ## min_rev ## max_rev ## _ ## name, \ + min_rev, max_rev, \ + FR_ ## min_rev ## max_rev ## _ ## name ## _STEP, \ + FR_ ## min_rev ## max_rev ## _ ## name ## _ROWS) +#define REGISTER_TABLE_AA(name) REGISTER_TABLE(name, A, A) +#define REGISTER_TABLE_AZ(name) REGISTER_TABLE(name, A, Z) +#define REGISTER_TABLE_BB(name) REGISTER_TABLE(name, B, B) +#define REGISTER_TABLE_BZ(name) REGISTER_TABLE(name, B, Z) #define REGISTER_TABLE_BB_CZ(name) \ - REGISTER_TABLE_DIMENSIONS(name, FR_BZ_ ## name, F, B, B, \ + REGISTER_TABLE_DIMENSIONS(name, FR_BZ_ ## name, B, B, \ FR_BZ_ ## name ## _STEP, \ FR_BB_ ## name ## _ROWS), \ - REGISTER_TABLE_DIMENSIONS(name, FR_BZ_ ## name, F, C, Z, \ + REGISTER_TABLE_DIMENSIONS(name, FR_BZ_ ## name, C, Z, \ FR_BZ_ ## name ## _STEP, \ FR_CZ_ ## name ## _ROWS) -#define REGISTER_TABLE_CZ(name) REGISTER_TABLE(name, F, C, Z) -#define REGISTER_TABLE_DZ(name) REGISTER_TABLE(name, E, D, Z) +#define REGISTER_TABLE_CZ(name) REGISTER_TABLE(name, C, Z) static const struct efx_nic_reg_table efx_nic_reg_tables[] = { /* DRIVER is not used */ @@ -350,9 +340,9 @@ static const struct efx_nic_reg_table efx_nic_reg_tables[] = { * 1K entries allows for some expansion of queue count and * size before we need to change the version. */ REGISTER_TABLE_DIMENSIONS(BUF_FULL_TBL_KER, FR_AA_BUF_FULL_TBL_KER, - F, A, A, 8, 1024), + A, A, 8, 1024), REGISTER_TABLE_DIMENSIONS(BUF_FULL_TBL, FR_BZ_BUF_FULL_TBL, - F, B, Z, 8, 1024), + B, Z, 8, 1024), REGISTER_TABLE_CZ(RX_MAC_FILTER_TBL0), REGISTER_TABLE_BB_CZ(TIMER_TBL), REGISTER_TABLE_BB_CZ(TX_PACE_TBL), @@ -363,7 +353,6 @@ static const struct efx_nic_reg_table efx_nic_reg_tables[] = { /* MSIX_PBA_TABLE is not mapped */ /* SRM_DBG is not mapped (and is redundant with BUF_FLL_TBL) */ REGISTER_TABLE_BZ(RX_FILTER_TBL0), - REGISTER_TABLE_DZ(BIU_MC_SFT_STATUS), }; size_t efx_nic_get_regs_len(struct efx_nic *efx) diff --git a/drivers/net/ethernet/sfc/nic.h b/drivers/net/ethernet/sfc/nic.h index 11b6112..890bbbe 100644 --- a/drivers/net/ethernet/sfc/nic.h +++ b/drivers/net/ethernet/sfc/nic.h @@ -30,7 +30,7 @@ static inline int efx_nic_rev(struct efx_nic *efx) return efx->type->revision; } -u32 efx_farch_fpga_ver(struct efx_nic *efx); +extern u32 efx_farch_fpga_ver(struct efx_nic *efx); /* NIC has two interlinked PCI functions for the same port. */ static inline bool efx_nic_is_dual_func(struct efx_nic *efx) @@ -71,26 +71,6 @@ efx_tx_desc(struct efx_tx_queue *tx_queue, unsigned int index) return ((efx_qword_t *) (tx_queue->txd.buf.addr)) + index; } -/* Report whether the NIC considers this TX queue empty, given the - * write_count used for the last doorbell push. May return false - * negative. - */ -static inline bool __efx_nic_tx_is_empty(struct efx_tx_queue *tx_queue, - unsigned int write_count) -{ - unsigned int empty_read_count = ACCESS_ONCE(tx_queue->empty_read_count); - - if (empty_read_count == 0) - return false; - - return ((empty_read_count ^ write_count) & ~EFX_EMPTY_COUNT_VALID) == 0; -} - -static inline bool efx_nic_tx_is_empty(struct efx_tx_queue *tx_queue) -{ - return __efx_nic_tx_is_empty(tx_queue, tx_queue->write_count); -} - /* Decide whether to push a TX descriptor to the NIC vs merely writing * the doorbell. This can reduce latency when we are adding a single * descriptor to an empty queue, but is otherwise pointless. Further, @@ -100,10 +80,14 @@ static inline bool efx_nic_tx_is_empty(struct efx_tx_queue *tx_queue) static inline bool efx_nic_may_push_tx_desc(struct efx_tx_queue *tx_queue, unsigned int write_count) { - bool was_empty = __efx_nic_tx_is_empty(tx_queue, write_count); + unsigned empty_read_count = ACCESS_ONCE(tx_queue->empty_read_count); + + if (empty_read_count == 0) + return false; tx_queue->empty_read_count = 0; - return was_empty && tx_queue->write_count - write_count == 1; + return ((empty_read_count ^ write_count) & ~EFX_EMPTY_COUNT_VALID) == 0 + && tx_queue->write_count - write_count == 1; } /* Returns a pointer to the specified descriptor in the RX descriptor queue */ @@ -417,12 +401,6 @@ enum { EF10_STAT_COUNT }; -/* Maximum number of TX PIO buffers we may allocate to a function. - * This matches the total number of buffers on each SFC9100-family - * controller. - */ -#define EF10_TX_PIOBUF_COUNT 16 - /** * struct efx_ef10_nic_data - EF10 architecture NIC state * @mcdi_buf: DMA buffer for MCDI @@ -431,13 +409,6 @@ enum { * @n_allocated_vis: Number of VIs allocated to this function * @must_realloc_vis: Flag: VIs have yet to be reallocated after MC reboot * @must_restore_filters: Flag: filters have yet to be restored after MC reboot - * @n_piobufs: Number of PIO buffers allocated to this function - * @wc_membase: Base address of write-combining mapping of the memory BAR - * @pio_write_base: Base address for writing PIO buffers - * @pio_write_vi_base: Relative VI number for @pio_write_base - * @piobuf_handle: Handle of each PIO buffer allocated - * @must_restore_piobufs: Flag: PIO buffers have yet to be restored after MC - * reboot * @rx_rss_context: Firmware handle for our RSS context * @stats: Hardware statistics * @workaround_35388: Flag: firmware supports workaround for bug 35388 @@ -453,11 +424,6 @@ struct efx_ef10_nic_data { unsigned int n_allocated_vis; bool must_realloc_vis; bool must_restore_filters; - unsigned int n_piobufs; - void __iomem *wc_membase, *pio_write_base; - unsigned int pio_write_vi_base; - unsigned int piobuf_handle[EF10_TX_PIOBUF_COUNT]; - bool must_restore_piobufs; u32 rx_rss_context; u64 stats[EF10_STAT_COUNT]; bool workaround_35388; @@ -509,18 +475,18 @@ static inline unsigned int efx_vf_size(struct efx_nic *efx) return 1 << efx->vi_scale; } -int efx_init_sriov(void); -void efx_sriov_probe(struct efx_nic *efx); -int efx_sriov_init(struct efx_nic *efx); -void efx_sriov_mac_address_changed(struct efx_nic *efx); -void efx_sriov_tx_flush_done(struct efx_nic *efx, efx_qword_t *event); -void efx_sriov_rx_flush_done(struct efx_nic *efx, efx_qword_t *event); -void efx_sriov_event(struct efx_channel *channel, efx_qword_t *event); -void efx_sriov_desc_fetch_err(struct efx_nic *efx, unsigned dmaq); -void efx_sriov_flr(struct efx_nic *efx, unsigned flr); -void efx_sriov_reset(struct efx_nic *efx); -void efx_sriov_fini(struct efx_nic *efx); -void efx_fini_sriov(void); +extern int efx_init_sriov(void); +extern void efx_sriov_probe(struct efx_nic *efx); +extern int efx_sriov_init(struct efx_nic *efx); +extern void efx_sriov_mac_address_changed(struct efx_nic *efx); +extern void efx_sriov_tx_flush_done(struct efx_nic *efx, efx_qword_t *event); +extern void efx_sriov_rx_flush_done(struct efx_nic *efx, efx_qword_t *event); +extern void efx_sriov_event(struct efx_channel *channel, efx_qword_t *event); +extern void efx_sriov_desc_fetch_err(struct efx_nic *efx, unsigned dmaq); +extern void efx_sriov_flr(struct efx_nic *efx, unsigned flr); +extern void efx_sriov_reset(struct efx_nic *efx); +extern void efx_sriov_fini(struct efx_nic *efx); +extern void efx_fini_sriov(void); #else @@ -546,20 +512,22 @@ static inline void efx_fini_sriov(void) {} #endif -int efx_sriov_set_vf_mac(struct net_device *dev, int vf, u8 *mac); -int efx_sriov_set_vf_vlan(struct net_device *dev, int vf, u16 vlan, u8 qos); -int efx_sriov_get_vf_config(struct net_device *dev, int vf, - struct ifla_vf_info *ivf); -int efx_sriov_set_vf_spoofchk(struct net_device *net_dev, int vf, - bool spoofchk); +extern int efx_sriov_set_vf_mac(struct net_device *dev, int vf, u8 *mac); +extern int efx_sriov_set_vf_vlan(struct net_device *dev, int vf, + u16 vlan, u8 qos); +extern int efx_sriov_get_vf_config(struct net_device *dev, int vf, + struct ifla_vf_info *ivf); +extern int efx_sriov_set_vf_spoofchk(struct net_device *net_dev, int vf, + bool spoofchk); struct ethtool_ts_info; -void efx_ptp_probe(struct efx_nic *efx); -int efx_ptp_ioctl(struct efx_nic *efx, struct ifreq *ifr, int cmd); -void efx_ptp_get_ts_info(struct efx_nic *efx, struct ethtool_ts_info *ts_info); -bool efx_ptp_is_ptp_tx(struct efx_nic *efx, struct sk_buff *skb); -int efx_ptp_tx(struct efx_nic *efx, struct sk_buff *skb); -void efx_ptp_event(struct efx_nic *efx, efx_qword_t *ev); +extern void efx_ptp_probe(struct efx_nic *efx); +extern int efx_ptp_ioctl(struct efx_nic *efx, struct ifreq *ifr, int cmd); +extern void efx_ptp_get_ts_info(struct efx_nic *efx, + struct ethtool_ts_info *ts_info); +extern bool efx_ptp_is_ptp_tx(struct efx_nic *efx, struct sk_buff *skb); +extern int efx_ptp_tx(struct efx_nic *efx, struct sk_buff *skb); +extern void efx_ptp_event(struct efx_nic *efx, efx_qword_t *ev); extern const struct efx_nic_type falcon_a1_nic_type; extern const struct efx_nic_type falcon_b0_nic_type; @@ -573,7 +541,7 @@ extern const struct efx_nic_type efx_hunt_a0_nic_type; ************************************************************************** */ -int falcon_probe_board(struct efx_nic *efx, u16 revision_info); +extern int falcon_probe_board(struct efx_nic *efx, u16 revision_info); /* TX data path */ static inline int efx_nic_probe_tx(struct efx_tx_queue *tx_queue) @@ -641,58 +609,58 @@ static inline void efx_nic_eventq_read_ack(struct efx_channel *channel) { channel->efx->type->ev_read_ack(channel); } -void efx_nic_event_test_start(struct efx_channel *channel); +extern void efx_nic_event_test_start(struct efx_channel *channel); /* Falcon/Siena queue operations */ -int efx_farch_tx_probe(struct efx_tx_queue *tx_queue); -void efx_farch_tx_init(struct efx_tx_queue *tx_queue); -void efx_farch_tx_fini(struct efx_tx_queue *tx_queue); -void efx_farch_tx_remove(struct efx_tx_queue *tx_queue); -void efx_farch_tx_write(struct efx_tx_queue *tx_queue); -int efx_farch_rx_probe(struct efx_rx_queue *rx_queue); -void efx_farch_rx_init(struct efx_rx_queue *rx_queue); -void efx_farch_rx_fini(struct efx_rx_queue *rx_queue); -void efx_farch_rx_remove(struct efx_rx_queue *rx_queue); -void efx_farch_rx_write(struct efx_rx_queue *rx_queue); -void efx_farch_rx_defer_refill(struct efx_rx_queue *rx_queue); -int efx_farch_ev_probe(struct efx_channel *channel); -int efx_farch_ev_init(struct efx_channel *channel); -void efx_farch_ev_fini(struct efx_channel *channel); -void efx_farch_ev_remove(struct efx_channel *channel); -int efx_farch_ev_process(struct efx_channel *channel, int quota); -void efx_farch_ev_read_ack(struct efx_channel *channel); -void efx_farch_ev_test_generate(struct efx_channel *channel); +extern int efx_farch_tx_probe(struct efx_tx_queue *tx_queue); +extern void efx_farch_tx_init(struct efx_tx_queue *tx_queue); +extern void efx_farch_tx_fini(struct efx_tx_queue *tx_queue); +extern void efx_farch_tx_remove(struct efx_tx_queue *tx_queue); +extern void efx_farch_tx_write(struct efx_tx_queue *tx_queue); +extern int efx_farch_rx_probe(struct efx_rx_queue *rx_queue); +extern void efx_farch_rx_init(struct efx_rx_queue *rx_queue); +extern void efx_farch_rx_fini(struct efx_rx_queue *rx_queue); +extern void efx_farch_rx_remove(struct efx_rx_queue *rx_queue); +extern void efx_farch_rx_write(struct efx_rx_queue *rx_queue); +extern void efx_farch_rx_defer_refill(struct efx_rx_queue *rx_queue); +extern int efx_farch_ev_probe(struct efx_channel *channel); +extern int efx_farch_ev_init(struct efx_channel *channel); +extern void efx_farch_ev_fini(struct efx_channel *channel); +extern void efx_farch_ev_remove(struct efx_channel *channel); +extern int efx_farch_ev_process(struct efx_channel *channel, int quota); +extern void efx_farch_ev_read_ack(struct efx_channel *channel); +extern void efx_farch_ev_test_generate(struct efx_channel *channel); /* Falcon/Siena filter operations */ -int efx_farch_filter_table_probe(struct efx_nic *efx); -void efx_farch_filter_table_restore(struct efx_nic *efx); -void efx_farch_filter_table_remove(struct efx_nic *efx); -void efx_farch_filter_update_rx_scatter(struct efx_nic *efx); -s32 efx_farch_filter_insert(struct efx_nic *efx, struct efx_filter_spec *spec, - bool replace); -int efx_farch_filter_remove_safe(struct efx_nic *efx, - enum efx_filter_priority priority, - u32 filter_id); -int efx_farch_filter_get_safe(struct efx_nic *efx, - enum efx_filter_priority priority, u32 filter_id, - struct efx_filter_spec *); -void efx_farch_filter_clear_rx(struct efx_nic *efx, - enum efx_filter_priority priority); -u32 efx_farch_filter_count_rx_used(struct efx_nic *efx, - enum efx_filter_priority priority); -u32 efx_farch_filter_get_rx_id_limit(struct efx_nic *efx); -s32 efx_farch_filter_get_rx_ids(struct efx_nic *efx, - enum efx_filter_priority priority, u32 *buf, - u32 size); +extern int efx_farch_filter_table_probe(struct efx_nic *efx); +extern void efx_farch_filter_table_restore(struct efx_nic *efx); +extern void efx_farch_filter_table_remove(struct efx_nic *efx); +extern void efx_farch_filter_update_rx_scatter(struct efx_nic *efx); +extern s32 efx_farch_filter_insert(struct efx_nic *efx, + struct efx_filter_spec *spec, bool replace); +extern int efx_farch_filter_remove_safe(struct efx_nic *efx, + enum efx_filter_priority priority, + u32 filter_id); +extern int efx_farch_filter_get_safe(struct efx_nic *efx, + enum efx_filter_priority priority, + u32 filter_id, struct efx_filter_spec *); +extern void efx_farch_filter_clear_rx(struct efx_nic *efx, + enum efx_filter_priority priority); +extern u32 efx_farch_filter_count_rx_used(struct efx_nic *efx, + enum efx_filter_priority priority); +extern u32 efx_farch_filter_get_rx_id_limit(struct efx_nic *efx); +extern s32 efx_farch_filter_get_rx_ids(struct efx_nic *efx, + enum efx_filter_priority priority, + u32 *buf, u32 size); #ifdef CONFIG_RFS_ACCEL -s32 efx_farch_filter_rfs_insert(struct efx_nic *efx, - struct efx_filter_spec *spec); -bool efx_farch_filter_rfs_expire_one(struct efx_nic *efx, u32 flow_id, - unsigned int index); +extern s32 efx_farch_filter_rfs_insert(struct efx_nic *efx, + struct efx_filter_spec *spec); +extern bool efx_farch_filter_rfs_expire_one(struct efx_nic *efx, u32 flow_id, + unsigned int index); #endif -void efx_farch_filter_sync_rx_mode(struct efx_nic *efx); +extern void efx_farch_filter_sync_rx_mode(struct efx_nic *efx); -bool efx_nic_event_present(struct efx_channel *channel); +extern bool efx_nic_event_present(struct efx_channel *channel); /* Some statistics are computed as A - B where A and B each increase * linearly with some hardware counter(s) and the counters are read @@ -713,17 +681,17 @@ static inline void efx_update_diff_stat(u64 *stat, u64 diff) } /* Interrupts */ -int efx_nic_init_interrupt(struct efx_nic *efx); -void efx_nic_irq_test_start(struct efx_nic *efx); -void efx_nic_fini_interrupt(struct efx_nic *efx); +extern int efx_nic_init_interrupt(struct efx_nic *efx); +extern void efx_nic_irq_test_start(struct efx_nic *efx); +extern void efx_nic_fini_interrupt(struct efx_nic *efx); /* Falcon/Siena interrupts */ -void efx_farch_irq_enable_master(struct efx_nic *efx); -void efx_farch_irq_test_generate(struct efx_nic *efx); -void efx_farch_irq_disable_master(struct efx_nic *efx); -irqreturn_t efx_farch_msi_interrupt(int irq, void *dev_id); -irqreturn_t efx_farch_legacy_interrupt(int irq, void *dev_id); -irqreturn_t efx_farch_fatal_interrupt(struct efx_nic *efx); +extern void efx_farch_irq_enable_master(struct efx_nic *efx); +extern void efx_farch_irq_test_generate(struct efx_nic *efx); +extern void efx_farch_irq_disable_master(struct efx_nic *efx); +extern irqreturn_t efx_farch_msi_interrupt(int irq, void *dev_id); +extern irqreturn_t efx_farch_legacy_interrupt(int irq, void *dev_id); +extern irqreturn_t efx_farch_fatal_interrupt(struct efx_nic *efx); static inline int efx_nic_event_test_irq_cpu(struct efx_channel *channel) { @@ -735,21 +703,21 @@ static inline int efx_nic_irq_test_irq_cpu(struct efx_nic *efx) } /* Global Resources */ -int efx_nic_flush_queues(struct efx_nic *efx); -void siena_prepare_flush(struct efx_nic *efx); -int efx_farch_fini_dmaq(struct efx_nic *efx); -void siena_finish_flush(struct efx_nic *efx); -void falcon_start_nic_stats(struct efx_nic *efx); -void falcon_stop_nic_stats(struct efx_nic *efx); -int falcon_reset_xaui(struct efx_nic *efx); -void efx_farch_dimension_resources(struct efx_nic *efx, unsigned sram_lim_qw); -void efx_farch_init_common(struct efx_nic *efx); -void efx_ef10_handle_drain_event(struct efx_nic *efx); +extern int efx_nic_flush_queues(struct efx_nic *efx); +extern void siena_prepare_flush(struct efx_nic *efx); +extern int efx_farch_fini_dmaq(struct efx_nic *efx); +extern void siena_finish_flush(struct efx_nic *efx); +extern void falcon_start_nic_stats(struct efx_nic *efx); +extern void falcon_stop_nic_stats(struct efx_nic *efx); +extern int falcon_reset_xaui(struct efx_nic *efx); +extern void efx_farch_dimension_resources(struct efx_nic *efx, unsigned sram_lim_qw); +extern void efx_farch_init_common(struct efx_nic *efx); +extern void efx_ef10_handle_drain_event(struct efx_nic *efx); static inline void efx_nic_push_rx_indir_table(struct efx_nic *efx) { efx->type->rx_push_indir_table(efx); } -void efx_farch_rx_push_indir_table(struct efx_nic *efx); +extern void efx_farch_rx_push_indir_table(struct efx_nic *efx); int efx_nic_alloc_buffer(struct efx_nic *efx, struct efx_buffer *buffer, unsigned int len, gfp_t gfp_flags); @@ -760,22 +728,24 @@ struct efx_farch_register_test { unsigned address; efx_oword_t mask; }; -int efx_farch_test_registers(struct efx_nic *efx, - const struct efx_farch_register_test *regs, - size_t n_regs); +extern int efx_farch_test_registers(struct efx_nic *efx, + const struct efx_farch_register_test *regs, + size_t n_regs); -size_t efx_nic_get_regs_len(struct efx_nic *efx); -void efx_nic_get_regs(struct efx_nic *efx, void *buf); +extern size_t efx_nic_get_regs_len(struct efx_nic *efx); +extern void efx_nic_get_regs(struct efx_nic *efx, void *buf); -size_t efx_nic_describe_stats(const struct efx_hw_stat_desc *desc, size_t count, - const unsigned long *mask, u8 *names); -void efx_nic_update_stats(const struct efx_hw_stat_desc *desc, size_t count, - const unsigned long *mask, u64 *stats, - const void *dma_buf, bool accumulate); +extern size_t +efx_nic_describe_stats(const struct efx_hw_stat_desc *desc, size_t count, + const unsigned long *mask, u8 *names); +extern void +efx_nic_update_stats(const struct efx_hw_stat_desc *desc, size_t count, + const unsigned long *mask, + u64 *stats, const void *dma_buf, bool accumulate); #define EFX_MAX_FLUSH_TIME 5000 -void efx_farch_generate_event(struct efx_nic *efx, unsigned int evq, - efx_qword_t *event); +extern void efx_farch_generate_event(struct efx_nic *efx, unsigned int evq, + efx_qword_t *event); #endif /* EFX_NIC_H */ diff --git a/drivers/net/ethernet/sfc/phy.h b/drivers/net/ethernet/sfc/phy.h index 803bf44..45eeb70 100644 --- a/drivers/net/ethernet/sfc/phy.h +++ b/drivers/net/ethernet/sfc/phy.h @@ -15,7 +15,7 @@ */ extern const struct efx_phy_operations falcon_sfx7101_phy_ops; -void tenxpress_set_id_led(struct efx_nic *efx, enum efx_led_mode mode); +extern void tenxpress_set_id_led(struct efx_nic *efx, enum efx_led_mode mode); /**************************************************************************** * AMCC/Quake QT202x PHYs @@ -34,7 +34,7 @@ extern const struct efx_phy_operations falcon_qt202x_phy_ops; #define QUAKE_LED_TXLINK (0) #define QUAKE_LED_RXLINK (8) -void falcon_qt202x_set_led(struct efx_nic *p, int led, int state); +extern void falcon_qt202x_set_led(struct efx_nic *p, int led, int state); /**************************************************************************** * Transwitch CX4 retimer @@ -44,7 +44,7 @@ extern const struct efx_phy_operations falcon_txc_phy_ops; #define TXC_GPIO_DIR_INPUT 0 #define TXC_GPIO_DIR_OUTPUT 1 -void falcon_txc_set_gpio_dir(struct efx_nic *efx, int pin, int dir); -void falcon_txc_set_gpio_val(struct efx_nic *efx, int pin, int val); +extern void falcon_txc_set_gpio_dir(struct efx_nic *efx, int pin, int dir); +extern void falcon_txc_set_gpio_val(struct efx_nic *efx, int pin, int val); #endif diff --git a/drivers/net/ethernet/sfc/rx.c b/drivers/net/ethernet/sfc/rx.c index 8f09e68..4a59672 100644 --- a/drivers/net/ethernet/sfc/rx.c +++ b/drivers/net/ethernet/sfc/rx.c @@ -12,7 +12,6 @@ #include <linux/in.h> #include <linux/slab.h> #include <linux/ip.h> -#include <linux/ipv6.h> #include <linux/tcp.h> #include <linux/udp.h> #include <linux/prefetch.h> @@ -819,70 +818,44 @@ int efx_filter_rfs(struct net_device *net_dev, const struct sk_buff *skb, struct efx_nic *efx = netdev_priv(net_dev); struct efx_channel *channel; struct efx_filter_spec spec; + const struct iphdr *ip; const __be16 *ports; - __be16 ether_type; int nhoff; int rc; - /* The core RPS/RFS code has already parsed and validated - * VLAN, IP and transport headers. We assume they are in the - * header area. - */ + nhoff = skb_network_offset(skb); if (skb->protocol == htons(ETH_P_8021Q)) { - const struct vlan_hdr *vh = - (const struct vlan_hdr *)skb->data; + EFX_BUG_ON_PARANOID(skb_headlen(skb) < + nhoff + sizeof(struct vlan_hdr)); + if (((const struct vlan_hdr *)skb->data + nhoff)-> + h_vlan_encapsulated_proto != htons(ETH_P_IP)) + return -EPROTONOSUPPORT; - /* We can't filter on the IP 5-tuple and the vlan - * together, so just strip the vlan header and filter - * on the IP part. + /* This is IP over 802.1q VLAN. We can't filter on the + * IP 5-tuple and the vlan together, so just strip the + * vlan header and filter on the IP part. */ - EFX_BUG_ON_PARANOID(skb_headlen(skb) < sizeof(*vh)); - ether_type = vh->h_vlan_encapsulated_proto; - nhoff = sizeof(struct vlan_hdr); - } else { - ether_type = skb->protocol; - nhoff = 0; + nhoff += sizeof(struct vlan_hdr); + } else if (skb->protocol != htons(ETH_P_IP)) { + return -EPROTONOSUPPORT; } - if (ether_type != htons(ETH_P_IP) && ether_type != htons(ETH_P_IPV6)) + /* RFS must validate the IP header length before calling us */ + EFX_BUG_ON_PARANOID(skb_headlen(skb) < nhoff + sizeof(*ip)); + ip = (const struct iphdr *)(skb->data + nhoff); + if (ip_is_fragment(ip)) return -EPROTONOSUPPORT; + EFX_BUG_ON_PARANOID(skb_headlen(skb) < nhoff + 4 * ip->ihl + 4); + ports = (const __be16 *)(skb->data + nhoff + 4 * ip->ihl); efx_filter_init_rx(&spec, EFX_FILTER_PRI_HINT, efx->rx_scatter ? EFX_FILTER_FLAG_RX_SCATTER : 0, rxq_index); - spec.match_flags = - EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO | - EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT | - EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT; - spec.ether_type = ether_type; - - if (ether_type == htons(ETH_P_IP)) { - const struct iphdr *ip = - (const struct iphdr *)(skb->data + nhoff); - - EFX_BUG_ON_PARANOID(skb_headlen(skb) < nhoff + sizeof(*ip)); - if (ip_is_fragment(ip)) - return -EPROTONOSUPPORT; - spec.ip_proto = ip->protocol; - spec.rem_host[0] = ip->saddr; - spec.loc_host[0] = ip->daddr; - EFX_BUG_ON_PARANOID(skb_headlen(skb) < nhoff + 4 * ip->ihl + 4); - ports = (const __be16 *)(skb->data + nhoff + 4 * ip->ihl); - } else { - const struct ipv6hdr *ip6 = - (const struct ipv6hdr *)(skb->data + nhoff); - - EFX_BUG_ON_PARANOID(skb_headlen(skb) < - nhoff + sizeof(*ip6) + 4); - spec.ip_proto = ip6->nexthdr; - memcpy(spec.rem_host, &ip6->saddr, sizeof(ip6->saddr)); - memcpy(spec.loc_host, &ip6->daddr, sizeof(ip6->daddr)); - ports = (const __be16 *)(ip6 + 1); - } - - spec.rem_port = ports[0]; - spec.loc_port = ports[1]; + rc = efx_filter_set_ipv4_full(&spec, ip->protocol, + ip->daddr, ports[1], ip->saddr, ports[0]); + if (rc) + return rc; rc = efx->type->filter_rfs_insert(efx, &spec); if (rc < 0) @@ -893,18 +866,11 @@ int efx_filter_rfs(struct net_device *net_dev, const struct sk_buff *skb, channel = efx_get_channel(efx, skb_get_rx_queue(skb)); ++channel->rfs_filters_added; - if (ether_type == htons(ETH_P_IP)) - netif_info(efx, rx_status, efx->net_dev, - "steering %s %pI4:%u:%pI4:%u to queue %u [flow %u filter %d]\n", - (spec.ip_proto == IPPROTO_TCP) ? "TCP" : "UDP", - spec.rem_host, ntohs(ports[0]), spec.loc_host, - ntohs(ports[1]), rxq_index, flow_id, rc); - else - netif_info(efx, rx_status, efx->net_dev, - "steering %s [%pI6]:%u:[%pI6]:%u to queue %u [flow %u filter %d]\n", - (spec.ip_proto == IPPROTO_TCP) ? "TCP" : "UDP", - spec.rem_host, ntohs(ports[0]), spec.loc_host, - ntohs(ports[1]), rxq_index, flow_id, rc); + netif_info(efx, rx_status, efx->net_dev, + "steering %s %pI4:%u:%pI4:%u to queue %u [flow %u filter %d]\n", + (ip->protocol == IPPROTO_TCP) ? "TCP" : "UDP", + &ip->saddr, ntohs(ports[0]), &ip->daddr, ntohs(ports[1]), + rxq_index, flow_id, rc); return rc; } diff --git a/drivers/net/ethernet/sfc/selftest.h b/drivers/net/ethernet/sfc/selftest.h index a2f4a06..87698ae 100644 --- a/drivers/net/ethernet/sfc/selftest.h +++ b/drivers/net/ethernet/sfc/selftest.h @@ -43,12 +43,13 @@ struct efx_self_tests { struct efx_loopback_self_tests loopback[LOOPBACK_TEST_MAX + 1]; }; -void efx_loopback_rx_packet(struct efx_nic *efx, const char *buf_ptr, - int pkt_len); -int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, - unsigned flags); -void efx_selftest_async_start(struct efx_nic *efx); -void efx_selftest_async_cancel(struct efx_nic *efx); -void efx_selftest_async_work(struct work_struct *data); +extern void efx_loopback_rx_packet(struct efx_nic *efx, + const char *buf_ptr, int pkt_len); +extern int efx_selftest(struct efx_nic *efx, + struct efx_self_tests *tests, + unsigned flags); +extern void efx_selftest_async_start(struct efx_nic *efx); +extern void efx_selftest_async_cancel(struct efx_nic *efx); +extern void efx_selftest_async_work(struct work_struct *data); #endif /* EFX_SELFTEST_H */ diff --git a/drivers/net/ethernet/sfc/tx.c b/drivers/net/ethernet/sfc/tx.c index c49d1fb..2ac91c5 100644 --- a/drivers/net/ethernet/sfc/tx.c +++ b/drivers/net/ethernet/sfc/tx.c @@ -17,46 +17,10 @@ #include <net/ipv6.h> #include <linux/if_ether.h> #include <linux/highmem.h> -#include <linux/cache.h> #include "net_driver.h" #include "efx.h" -#include "io.h" #include "nic.h" #include "workarounds.h" -#include "ef10_regs.h" - -#ifdef EFX_USE_PIO - -#define EFX_PIOBUF_SIZE_MAX ER_DZ_TX_PIOBUF_SIZE -#define EFX_PIOBUF_SIZE_DEF ALIGN(256, L1_CACHE_BYTES) -unsigned int efx_piobuf_size __read_mostly = EFX_PIOBUF_SIZE_DEF; - -#endif /* EFX_USE_PIO */ - -static inline unsigned int -efx_tx_queue_get_insert_index(const struct efx_tx_queue *tx_queue) -{ - return tx_queue->insert_count & tx_queue->ptr_mask; -} - -static inline struct efx_tx_buffer * -__efx_tx_queue_get_insert_buffer(const struct efx_tx_queue *tx_queue) -{ - return &tx_queue->buffer[efx_tx_queue_get_insert_index(tx_queue)]; -} - -static inline struct efx_tx_buffer * -efx_tx_queue_get_insert_buffer(const struct efx_tx_queue *tx_queue) -{ - struct efx_tx_buffer *buffer = - __efx_tx_queue_get_insert_buffer(tx_queue); - - EFX_BUG_ON_PARANOID(buffer->len); - EFX_BUG_ON_PARANOID(buffer->flags); - EFX_BUG_ON_PARANOID(buffer->unmap_len); - - return buffer; -} static void efx_dequeue_buffer(struct efx_tx_queue *tx_queue, struct efx_tx_buffer *buffer, @@ -65,7 +29,8 @@ static void efx_dequeue_buffer(struct efx_tx_queue *tx_queue, { if (buffer->unmap_len) { struct device *dma_dev = &tx_queue->efx->pci_dev->dev; - dma_addr_t unmap_addr = buffer->dma_addr - buffer->dma_offset; + dma_addr_t unmap_addr = (buffer->dma_addr + buffer->len - + buffer->unmap_len); if (buffer->flags & EFX_TX_BUF_MAP_SINGLE) dma_unmap_single(dma_dev, unmap_addr, buffer->unmap_len, DMA_TO_DEVICE); @@ -118,10 +83,8 @@ unsigned int efx_tx_max_skb_descs(struct efx_nic *efx) */ unsigned int max_descs = EFX_TSO_MAX_SEGS * 2 + MAX_SKB_FRAGS; - /* Possibly one more per segment for the alignment workaround, - * or for option descriptors - */ - if (EFX_WORKAROUND_5391(efx) || efx_nic_rev(efx) >= EFX_REV_HUNT_A0) + /* Possibly one more per segment for the alignment workaround */ + if (EFX_WORKAROUND_5391(efx)) max_descs += EFX_TSO_MAX_SEGS; /* Possibly more for PCIe page boundaries within input fragments */ @@ -182,145 +145,6 @@ static void efx_tx_maybe_stop_queue(struct efx_tx_queue *txq1) } } -#ifdef EFX_USE_PIO - -struct efx_short_copy_buffer { - int used; - u8 buf[L1_CACHE_BYTES]; -}; - -/* Copy to PIO, respecting that writes to PIO buffers must be dword aligned. - * Advances piobuf pointer. Leaves additional data in the copy buffer. - */ -static void efx_memcpy_toio_aligned(struct efx_nic *efx, u8 __iomem **piobuf, - u8 *data, int len, - struct efx_short_copy_buffer *copy_buf) -{ - int block_len = len & ~(sizeof(copy_buf->buf) - 1); - - memcpy_toio(*piobuf, data, block_len); - *piobuf += block_len; - len -= block_len; - - if (len) { - data += block_len; - BUG_ON(copy_buf->used); - BUG_ON(len > sizeof(copy_buf->buf)); - memcpy(copy_buf->buf, data, len); - copy_buf->used = len; - } -} - -/* Copy to PIO, respecting dword alignment, popping data from copy buffer first. - * Advances piobuf pointer. Leaves additional data in the copy buffer. - */ -static void efx_memcpy_toio_aligned_cb(struct efx_nic *efx, u8 __iomem **piobuf, - u8 *data, int len, - struct efx_short_copy_buffer *copy_buf) -{ - if (copy_buf->used) { - /* if the copy buffer is partially full, fill it up and write */ - int copy_to_buf = - min_t(int, sizeof(copy_buf->buf) - copy_buf->used, len); - - memcpy(copy_buf->buf + copy_buf->used, data, copy_to_buf); - copy_buf->used += copy_to_buf; - - /* if we didn't fill it up then we're done for now */ - if (copy_buf->used < sizeof(copy_buf->buf)) - return; - - memcpy_toio(*piobuf, copy_buf->buf, sizeof(copy_buf->buf)); - *piobuf += sizeof(copy_buf->buf); - data += copy_to_buf; - len -= copy_to_buf; - copy_buf->used = 0; - } - - efx_memcpy_toio_aligned(efx, piobuf, data, len, copy_buf); -} - -static void efx_flush_copy_buffer(struct efx_nic *efx, u8 __iomem *piobuf, - struct efx_short_copy_buffer *copy_buf) -{ - /* if there's anything in it, write the whole buffer, including junk */ - if (copy_buf->used) - memcpy_toio(piobuf, copy_buf->buf, sizeof(copy_buf->buf)); -} - -/* Traverse skb structure and copy fragments in to PIO buffer. - * Advances piobuf pointer. - */ -static void efx_skb_copy_bits_to_pio(struct efx_nic *efx, struct sk_buff *skb, - u8 __iomem **piobuf, - struct efx_short_copy_buffer *copy_buf) -{ - int i; - - efx_memcpy_toio_aligned(efx, piobuf, skb->data, skb_headlen(skb), - copy_buf); - - for (i = 0; i < skb_shinfo(skb)->nr_frags; ++i) { - skb_frag_t *f = &skb_shinfo(skb)->frags[i]; - u8 *vaddr; - - vaddr = kmap_atomic(skb_frag_page(f)); - - efx_memcpy_toio_aligned_cb(efx, piobuf, vaddr + f->page_offset, - skb_frag_size(f), copy_buf); - kunmap_atomic(vaddr); - } - - EFX_BUG_ON_PARANOID(skb_shinfo(skb)->frag_list); -} - -static struct efx_tx_buffer * -efx_enqueue_skb_pio(struct efx_tx_queue *tx_queue, struct sk_buff *skb) -{ - struct efx_tx_buffer *buffer = - efx_tx_queue_get_insert_buffer(tx_queue); - u8 __iomem *piobuf = tx_queue->piobuf; - - /* Copy to PIO buffer. Ensure the writes are padded to the end - * of a cache line, as this is required for write-combining to be - * effective on at least x86. - */ - - if (skb_shinfo(skb)->nr_frags) { - /* The size of the copy buffer will ensure all writes - * are the size of a cache line. - */ - struct efx_short_copy_buffer copy_buf; - - copy_buf.used = 0; - - efx_skb_copy_bits_to_pio(tx_queue->efx, skb, - &piobuf, ©_buf); - efx_flush_copy_buffer(tx_queue->efx, piobuf, ©_buf); - } else { - /* Pad the write to the size of a cache line. - * We can do this because we know the skb_shared_info sruct is - * after the source, and the destination buffer is big enough. - */ - BUILD_BUG_ON(L1_CACHE_BYTES > - SKB_DATA_ALIGN(sizeof(struct skb_shared_info))); - memcpy_toio(tx_queue->piobuf, skb->data, - ALIGN(skb->len, L1_CACHE_BYTES)); - } - - EFX_POPULATE_QWORD_5(buffer->option, - ESF_DZ_TX_DESC_IS_OPT, 1, - ESF_DZ_TX_OPTION_TYPE, ESE_DZ_TX_OPTION_DESC_PIO, - ESF_DZ_TX_PIO_CONT, 0, - ESF_DZ_TX_PIO_BYTE_CNT, skb->len, - ESF_DZ_TX_PIO_BUF_ADDR, - tx_queue->piobuf_offset); - ++tx_queue->pio_packets; - ++tx_queue->insert_count; - return buffer; -} -#endif /* EFX_USE_PIO */ - /* * Add a socket buffer to a TX queue * @@ -343,7 +167,7 @@ netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb) struct device *dma_dev = &efx->pci_dev->dev; struct efx_tx_buffer *buffer; skb_frag_t *fragment; - unsigned int len, unmap_len = 0; + unsigned int len, unmap_len = 0, insert_ptr; dma_addr_t dma_addr, unmap_addr = 0; unsigned int dma_len; unsigned short dma_flags; @@ -365,17 +189,6 @@ netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb) return NETDEV_TX_OK; } - /* Consider using PIO for short packets */ -#ifdef EFX_USE_PIO - if (skb->len <= efx_piobuf_size && tx_queue->piobuf && - efx_nic_tx_is_empty(tx_queue) && - efx_nic_tx_is_empty(efx_tx_queue_partner(tx_queue))) { - buffer = efx_enqueue_skb_pio(tx_queue, skb); - dma_flags = EFX_TX_BUF_OPTION; - goto finish_packet; - } -#endif - /* Map for DMA. Use dma_map_single rather than dma_map_page * since this is more efficient on machines with sparse * memory. @@ -395,7 +208,11 @@ netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb) /* Add to TX queue, splitting across DMA boundaries */ do { - buffer = efx_tx_queue_get_insert_buffer(tx_queue); + insert_ptr = tx_queue->insert_count & tx_queue->ptr_mask; + buffer = &tx_queue->buffer[insert_ptr]; + EFX_BUG_ON_PARANOID(buffer->flags); + EFX_BUG_ON_PARANOID(buffer->len); + EFX_BUG_ON_PARANOID(buffer->unmap_len); dma_len = efx_max_tx_len(efx, dma_addr); if (likely(dma_len >= len)) @@ -413,7 +230,6 @@ netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb) /* Transfer ownership of the unmapping to the final buffer */ buffer->flags = EFX_TX_BUF_CONT | dma_flags; buffer->unmap_len = unmap_len; - buffer->dma_offset = buffer->dma_addr - unmap_addr; unmap_len = 0; /* Get address and size of next fragment */ @@ -429,7 +245,6 @@ netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb) } /* Transfer ownership of the skb to the final buffer */ -finish_packet: buffer->skb = skb; buffer->flags = EFX_TX_BUF_SKB | dma_flags; @@ -455,7 +270,8 @@ finish_packet: while (tx_queue->insert_count != tx_queue->write_count) { unsigned int pkts_compl = 0, bytes_compl = 0; --tx_queue->insert_count; - buffer = __efx_tx_queue_get_insert_buffer(tx_queue); + insert_ptr = tx_queue->insert_count & tx_queue->ptr_mask; + buffer = &tx_queue->buffer[insert_ptr]; efx_dequeue_buffer(tx_queue, buffer, &pkts_compl, &bytes_compl); } @@ -812,9 +628,6 @@ void efx_remove_tx_queue(struct efx_tx_queue *tx_queue) * @tcp_off: Offset of TCP header * @header_len: Number of bytes of header * @ip_base_len: IPv4 tot_len or IPv6 payload_len, before TCP payload - * @header_dma_addr: Header DMA address, when using option descriptors - * @header_unmap_len: Header DMA mapped length, or 0 if not using option - * descriptors * * The state used during segmentation. It is put into this data structure * just to make it easy to pass into inline functions. @@ -823,7 +636,7 @@ struct tso_state { /* Output position */ unsigned out_len; unsigned seqnum; - u16 ipv4_id; + unsigned ipv4_id; unsigned packet_space; /* Input position */ @@ -838,8 +651,6 @@ struct tso_state { unsigned int tcp_off; unsigned header_len; unsigned int ip_base_len; - dma_addr_t header_dma_addr; - unsigned int header_unmap_len; }; @@ -926,18 +737,23 @@ static void efx_tx_queue_insert(struct efx_tx_queue *tx_queue, { struct efx_tx_buffer *buffer; struct efx_nic *efx = tx_queue->efx; - unsigned dma_len; + unsigned dma_len, insert_ptr; EFX_BUG_ON_PARANOID(len <= 0); while (1) { - buffer = efx_tx_queue_get_insert_buffer(tx_queue); + insert_ptr = tx_queue->insert_count & tx_queue->ptr_mask; + buffer = &tx_queue->buffer[insert_ptr]; ++tx_queue->insert_count; EFX_BUG_ON_PARANOID(tx_queue->insert_count - tx_queue->read_count >= efx->txq_entries); + EFX_BUG_ON_PARANOID(buffer->len); + EFX_BUG_ON_PARANOID(buffer->unmap_len); + EFX_BUG_ON_PARANOID(buffer->flags); + buffer->dma_addr = dma_addr; dma_len = efx_max_tx_len(efx, dma_addr); @@ -980,7 +796,6 @@ static int efx_tso_put_header(struct efx_tx_queue *tx_queue, return -ENOMEM; } buffer->unmap_len = buffer->len; - buffer->dma_offset = 0; buffer->flags |= EFX_TX_BUF_MAP_SINGLE; } @@ -999,27 +814,19 @@ static void efx_enqueue_unwind(struct efx_tx_queue *tx_queue) /* Work backwards until we hit the original insert pointer value */ while (tx_queue->insert_count != tx_queue->write_count) { --tx_queue->insert_count; - buffer = __efx_tx_queue_get_insert_buffer(tx_queue); + buffer = &tx_queue->buffer[tx_queue->insert_count & + tx_queue->ptr_mask]; efx_dequeue_buffer(tx_queue, buffer, NULL, NULL); } } /* Parse the SKB header and initialise state. */ -static int tso_start(struct tso_state *st, struct efx_nic *efx, - const struct sk_buff *skb) +static void tso_start(struct tso_state *st, const struct sk_buff *skb) { - bool use_options = efx_nic_rev(efx) >= EFX_REV_HUNT_A0; - struct device *dma_dev = &efx->pci_dev->dev; - unsigned int header_len, in_len; - dma_addr_t dma_addr; - st->ip_off = skb_network_header(skb) - skb->data; st->tcp_off = skb_transport_header(skb) - skb->data; - header_len = st->tcp_off + (tcp_hdr(skb)->doff << 2u); - in_len = skb_headlen(skb) - header_len; - st->header_len = header_len; - st->in_len = in_len; + st->header_len = st->tcp_off + (tcp_hdr(skb)->doff << 2u); if (st->protocol == htons(ETH_P_IP)) { st->ip_base_len = st->header_len - st->ip_off; st->ipv4_id = ntohs(ip_hdr(skb)->id); @@ -1033,34 +840,9 @@ static int tso_start(struct tso_state *st, struct efx_nic *efx, EFX_BUG_ON_PARANOID(tcp_hdr(skb)->syn); EFX_BUG_ON_PARANOID(tcp_hdr(skb)->rst); - st->out_len = skb->len - header_len; - - if (!use_options) { - st->header_unmap_len = 0; - - if (likely(in_len == 0)) { - st->dma_flags = 0; - st->unmap_len = 0; - return 0; - } - - dma_addr = dma_map_single(dma_dev, skb->data + header_len, - in_len, DMA_TO_DEVICE); - st->dma_flags = EFX_TX_BUF_MAP_SINGLE; - st->dma_addr = dma_addr; - st->unmap_addr = dma_addr; - st->unmap_len = in_len; - } else { - dma_addr = dma_map_single(dma_dev, skb->data, - skb_headlen(skb), DMA_TO_DEVICE); - st->header_dma_addr = dma_addr; - st->header_unmap_len = skb_headlen(skb); - st->dma_flags = 0; - st->dma_addr = dma_addr + header_len; - st->unmap_len = 0; - } - - return unlikely(dma_mapping_error(dma_dev, dma_addr)) ? -ENOMEM : 0; + st->out_len = skb->len - st->header_len; + st->unmap_len = 0; + st->dma_flags = 0; } static int tso_get_fragment(struct tso_state *st, struct efx_nic *efx, @@ -1078,6 +860,24 @@ static int tso_get_fragment(struct tso_state *st, struct efx_nic *efx, return -ENOMEM; } +static int tso_get_head_fragment(struct tso_state *st, struct efx_nic *efx, + const struct sk_buff *skb) +{ + int hl = st->header_len; + int len = skb_headlen(skb) - hl; + + st->unmap_addr = dma_map_single(&efx->pci_dev->dev, skb->data + hl, + len, DMA_TO_DEVICE); + if (likely(!dma_mapping_error(&efx->pci_dev->dev, st->unmap_addr))) { + st->dma_flags = EFX_TX_BUF_MAP_SINGLE; + st->unmap_len = len; + st->in_len = len; + st->dma_addr = st->unmap_addr; + return 0; + } + return -ENOMEM; +} + /** * tso_fill_packet_with_fragment - form descriptors for the current fragment @@ -1122,7 +922,6 @@ static void tso_fill_packet_with_fragment(struct efx_tx_queue *tx_queue, if (st->in_len == 0) { /* Transfer ownership of the DMA mapping */ buffer->unmap_len = st->unmap_len; - buffer->dma_offset = buffer->unmap_len - buffer->len; buffer->flags |= st->dma_flags; st->unmap_len = 0; } @@ -1145,98 +944,55 @@ static int tso_start_new_packet(struct efx_tx_queue *tx_queue, struct tso_state *st) { struct efx_tx_buffer *buffer = - efx_tx_queue_get_insert_buffer(tx_queue); - bool is_last = st->out_len <= skb_shinfo(skb)->gso_size; - u8 tcp_flags_clear; + &tx_queue->buffer[tx_queue->insert_count & tx_queue->ptr_mask]; + struct tcphdr *tsoh_th; + unsigned ip_length; + u8 *header; + int rc; - if (!is_last) { + /* Allocate and insert a DMA-mapped header buffer. */ + header = efx_tsoh_get_buffer(tx_queue, buffer, st->header_len); + if (!header) + return -ENOMEM; + + tsoh_th = (struct tcphdr *)(header + st->tcp_off); + + /* Copy and update the headers. */ + memcpy(header, skb->data, st->header_len); + + tsoh_th->seq = htonl(st->seqnum); + st->seqnum += skb_shinfo(skb)->gso_size; + if (st->out_len > skb_shinfo(skb)->gso_size) { + /* This packet will not finish the TSO burst. */ st->packet_space = skb_shinfo(skb)->gso_size; - tcp_flags_clear = 0x09; /* mask out FIN and PSH */ + tsoh_th->fin = 0; + tsoh_th->psh = 0; } else { + /* This packet will be the last in the TSO burst. */ st->packet_space = st->out_len; - tcp_flags_clear = 0x00; + tsoh_th->fin = tcp_hdr(skb)->fin; + tsoh_th->psh = tcp_hdr(skb)->psh; } + ip_length = st->ip_base_len + st->packet_space; - if (!st->header_unmap_len) { - /* Allocate and insert a DMA-mapped header buffer. */ - struct tcphdr *tsoh_th; - unsigned ip_length; - u8 *header; - int rc; - - header = efx_tsoh_get_buffer(tx_queue, buffer, st->header_len); - if (!header) - return -ENOMEM; - - tsoh_th = (struct tcphdr *)(header + st->tcp_off); - - /* Copy and update the headers. */ - memcpy(header, skb->data, st->header_len); - - tsoh_th->seq = htonl(st->seqnum); - ((u8 *)tsoh_th)[13] &= ~tcp_flags_clear; - - ip_length = st->ip_base_len + st->packet_space; - - if (st->protocol == htons(ETH_P_IP)) { - struct iphdr *tsoh_iph = - (struct iphdr *)(header + st->ip_off); - - tsoh_iph->tot_len = htons(ip_length); - tsoh_iph->id = htons(st->ipv4_id); - } else { - struct ipv6hdr *tsoh_iph = - (struct ipv6hdr *)(header + st->ip_off); + if (st->protocol == htons(ETH_P_IP)) { + struct iphdr *tsoh_iph = (struct iphdr *)(header + st->ip_off); - tsoh_iph->payload_len = htons(ip_length); - } + tsoh_iph->tot_len = htons(ip_length); - rc = efx_tso_put_header(tx_queue, buffer, header); - if (unlikely(rc)) - return rc; + /* Linux leaves suitable gaps in the IP ID space for us to fill. */ + tsoh_iph->id = htons(st->ipv4_id); + st->ipv4_id++; } else { - /* Send the original headers with a TSO option descriptor - * in front - */ - u8 tcp_flags = ((u8 *)tcp_hdr(skb))[13] & ~tcp_flags_clear; + struct ipv6hdr *tsoh_iph = + (struct ipv6hdr *)(header + st->ip_off); - buffer->flags = EFX_TX_BUF_OPTION; - buffer->len = 0; - buffer->unmap_len = 0; - EFX_POPULATE_QWORD_5(buffer->option, - ESF_DZ_TX_DESC_IS_OPT, 1, - ESF_DZ_TX_OPTION_TYPE, - ESE_DZ_TX_OPTION_DESC_TSO, - ESF_DZ_TX_TSO_TCP_FLAGS, tcp_flags, - ESF_DZ_TX_TSO_IP_ID, st->ipv4_id, - ESF_DZ_TX_TSO_TCP_SEQNO, st->seqnum); - ++tx_queue->insert_count; - - /* We mapped the headers in tso_start(). Unmap them - * when the last segment is completed. - */ - buffer = efx_tx_queue_get_insert_buffer(tx_queue); - buffer->dma_addr = st->header_dma_addr; - buffer->len = st->header_len; - if (is_last) { - buffer->flags = EFX_TX_BUF_CONT | EFX_TX_BUF_MAP_SINGLE; - buffer->unmap_len = st->header_unmap_len; - buffer->dma_offset = 0; - /* Ensure we only unmap them once in case of a - * later DMA mapping error and rollback - */ - st->header_unmap_len = 0; - } else { - buffer->flags = EFX_TX_BUF_CONT; - buffer->unmap_len = 0; - } - ++tx_queue->insert_count; + tsoh_iph->payload_len = htons(ip_length); } - st->seqnum += skb_shinfo(skb)->gso_size; - - /* Linux leaves suitable gaps in the IP ID space for us to fill. */ - ++st->ipv4_id; + rc = efx_tso_put_header(tx_queue, buffer, header); + if (unlikely(rc)) + return rc; ++tx_queue->tso_packets; @@ -1267,11 +1023,12 @@ static int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue, EFX_BUG_ON_PARANOID(tx_queue->write_count != tx_queue->insert_count); - rc = tso_start(&state, efx, skb); - if (rc) - goto mem_err; + tso_start(&state, skb); - if (likely(state.in_len == 0)) { + /* Assume that skb header area contains exactly the headers, and + * all payload is in the frag list. + */ + if (skb_headlen(skb) == state.header_len) { /* Grab the first payload fragment. */ EFX_BUG_ON_PARANOID(skb_shinfo(skb)->nr_frags < 1); frag_i = 0; @@ -1280,7 +1037,9 @@ static int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue, if (rc) goto mem_err; } else { - /* Payload starts in the header area. */ + rc = tso_get_head_fragment(&state, efx, skb); + if (rc) + goto mem_err; frag_i = -1; } @@ -1332,11 +1091,6 @@ static int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue, state.unmap_len, DMA_TO_DEVICE); } - /* Free the header DMA mapping, if using option descriptors */ - if (state.header_unmap_len) - dma_unmap_single(&efx->pci_dev->dev, state.header_dma_addr, - state.header_unmap_len, DMA_TO_DEVICE); - efx_enqueue_unwind(tx_queue); return NETDEV_TX_OK; } |