sfc: support VI strides other than 8k
authorEdward Cree <ecree@solarflare.com>
Mon, 18 Dec 2017 16:56:19 +0000 (16:56 +0000)
committerDavid S. Miller <davem@davemloft.net>
Mon, 18 Dec 2017 18:07:49 +0000 (13:07 -0500)
Medford2 can also have 16k or 64k VI stride.  This is reported by MCDI in
 GET_CAPABILITIES, which fortunately is called before the driver does
 anything sensitive to the VI stride (such as accessing or even allocating
 VIs past the zeroth).

Signed-off-by: Edward Cree <ecree@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/sfc/ef10.c
drivers/net/ethernet/sfc/efx.c
drivers/net/ethernet/sfc/io.h
drivers/net/ethernet/sfc/mcdi.h
drivers/net/ethernet/sfc/net_driver.h

index 5cc786aec7c452adcf6f2d4ea629a992f7443bb6..dcd6be14a43089a16fd5f1853332cd1ef8ca4c01 100644 (file)
@@ -233,7 +233,7 @@ static int efx_ef10_get_vf_index(struct efx_nic *efx)
 
 static int efx_ef10_init_datapath_caps(struct efx_nic *efx)
 {
-       MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_CAPABILITIES_V2_OUT_LEN);
+       MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_CAPABILITIES_V3_OUT_LEN);
        struct efx_ef10_nic_data *nic_data = efx->nic_data;
        size_t outlen;
        int rc;
@@ -277,6 +277,35 @@ static int efx_ef10_init_datapath_caps(struct efx_nic *efx)
                return -ENODEV;
        }
 
+       if (outlen >= MC_CMD_GET_CAPABILITIES_V3_OUT_LEN) {
+               u8 vi_window_mode = MCDI_BYTE(outbuf,
+                               GET_CAPABILITIES_V3_OUT_VI_WINDOW_MODE);
+
+               switch (vi_window_mode) {
+               case MC_CMD_GET_CAPABILITIES_V3_OUT_VI_WINDOW_MODE_8K:
+                       efx->vi_stride = 8192;
+                       break;
+               case MC_CMD_GET_CAPABILITIES_V3_OUT_VI_WINDOW_MODE_16K:
+                       efx->vi_stride = 16384;
+                       break;
+               case MC_CMD_GET_CAPABILITIES_V3_OUT_VI_WINDOW_MODE_64K:
+                       efx->vi_stride = 65536;
+                       break;
+               default:
+                       netif_err(efx, probe, efx->net_dev,
+                                 "Unrecognised VI window mode %d\n",
+                                 vi_window_mode);
+                       return -EIO;
+               }
+               netif_dbg(efx, probe, efx->net_dev, "vi_stride = %u\n",
+                         efx->vi_stride);
+       } else {
+               /* keep default VI stride */
+               netif_dbg(efx, probe, efx->net_dev,
+                         "firmware did not report VI window mode, assuming vi_stride = %u\n",
+                         efx->vi_stride);
+       }
+
        return 0;
 }
 
@@ -609,17 +638,6 @@ static int efx_ef10_probe(struct efx_nic *efx)
        struct efx_ef10_nic_data *nic_data;
        int i, rc;
 
-       /* We can have one VI for each 8K region.  However, until we
-        * use TX option descriptors we need two TX queues per channel.
-        */
-       efx->max_channels = min_t(unsigned int,
-                                 EFX_MAX_CHANNELS,
-                                 efx_ef10_mem_map_size(efx) /
-                                 (EFX_VI_PAGE_SIZE * EFX_TXQ_TYPES));
-       efx->max_tx_channels = efx->max_channels;
-       if (WARN_ON(efx->max_channels == 0))
-               return -EIO;
-
        nic_data = kzalloc(sizeof(*nic_data), GFP_KERNEL);
        if (!nic_data)
                return -ENOMEM;
@@ -691,6 +709,20 @@ static int efx_ef10_probe(struct efx_nic *efx)
        if (rc < 0)
                goto fail5;
 
+       /* We can have one VI for each vi_stride-byte region.
+        * However, until we use TX option descriptors we need two TX queues
+        * per channel.
+        */
+       efx->max_channels = min_t(unsigned int,
+                                 EFX_MAX_CHANNELS,
+                                 efx_ef10_mem_map_size(efx) /
+                                 (efx->vi_stride * EFX_TXQ_TYPES));
+       efx->max_tx_channels = efx->max_channels;
+       if (WARN_ON(efx->max_channels == 0)) {
+               rc = -EIO;
+               goto fail5;
+       }
+
        efx->rx_packet_len_offset =
                ES_DZ_RX_PREFIX_PKTLEN_OFST - ES_DZ_RX_PREFIX_SIZE;
 
@@ -927,7 +959,7 @@ static int efx_ef10_link_piobufs(struct efx_nic *efx)
                        } else {
                                tx_queue->piobuf =
                                        nic_data->pio_write_base +
-                                       index * EFX_VI_PAGE_SIZE + offset;
+                                       index * efx->vi_stride + 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",
@@ -1273,19 +1305,19 @@ static int efx_ef10_dimension_resources(struct efx_nic *efx)
         * for writing PIO buffers through.
         *
         * The UC mapping contains (channel_vis - 1) complete VIs and the
-        * first half of the next VI.  Then the WC mapping begins with
-        * the second half of this last VI.
+        * first 4K of the next VI.  Then the WC mapping begins with
+        * the remainder of this last VI.
         */
-       uc_mem_map_size = PAGE_ALIGN((channel_vis - 1) * EFX_VI_PAGE_SIZE +
+       uc_mem_map_size = PAGE_ALIGN((channel_vis - 1) * efx->vi_stride +
                                     ER_DZ_TX_PIOBUF);
        if (nic_data->n_piobufs) {
                /* pio_write_vi_base rounds down to give the number of complete
                 * VIs inside the UC mapping.
                 */
-               pio_write_vi_base = uc_mem_map_size / EFX_VI_PAGE_SIZE;
+               pio_write_vi_base = uc_mem_map_size / efx->vi_stride;
                wc_mem_map_size = (PAGE_ALIGN((pio_write_vi_base +
                                               nic_data->n_piobufs) *
-                                             EFX_VI_PAGE_SIZE) -
+                                             efx->vi_stride) -
                                   uc_mem_map_size);
                max_vis = pio_write_vi_base + nic_data->n_piobufs;
        } else {
@@ -1357,7 +1389,7 @@ static int efx_ef10_dimension_resources(struct efx_nic *efx)
                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 -
+                       (pio_write_vi_base * efx->vi_stride + ER_DZ_TX_PIOBUF -
                         uc_mem_map_size);
 
                rc = efx_ef10_link_piobufs(efx);
index bbe4ace7dd9d35eaa71c2ac822216bc35bdc561b..e50049cba50bf98243842e7eb56766941fe27cc6 100644 (file)
@@ -27,6 +27,7 @@
 #include <net/udp_tunnel.h>
 #include "efx.h"
 #include "nic.h"
+#include "io.h"
 #include "selftest.h"
 #include "sriov.h"
 
@@ -2977,6 +2978,7 @@ static int efx_init_struct(struct efx_nic *efx,
        efx->rx_packet_ts_offset =
                efx->type->rx_ts_offset - efx->type->rx_prefix_size;
        spin_lock_init(&efx->stats_lock);
+       efx->vi_stride = EFX_DEFAULT_VI_STRIDE;
        mutex_init(&efx->mac_lock);
        efx->phy_op = &efx_dummy_phy_operations;
        efx->mdio.dev = net_dev;
index afb94aa2c15e9f8eb8ec5ebfc8a02ef8f8bc505e..89563170af5216ef99239089d584e3e5ffb61e34 100644 (file)
@@ -222,18 +222,21 @@ static inline void efx_reado_table(struct efx_nic *efx, efx_oword_t *value,
        efx_reado(efx, value, reg + index * sizeof(efx_oword_t));
 }
 
-/* Page size used as step between per-VI registers */
-#define EFX_VI_PAGE_SIZE 0x2000
+/* default VI stride (step between per-VI registers) is 8K */
+#define EFX_DEFAULT_VI_STRIDE 0x2000
 
 /* Calculate offset to page-mapped register */
-#define EFX_PAGED_REG(page, reg) \
-       ((page) * EFX_VI_PAGE_SIZE + (reg))
+static inline unsigned int efx_paged_reg(struct efx_nic *efx, unsigned int page,
+                                        unsigned int reg)
+{
+       return page * efx->vi_stride + reg;
+}
 
 /* Write the whole of RX_DESC_UPD or TX_DESC_UPD */
 static inline void _efx_writeo_page(struct efx_nic *efx, efx_oword_t *value,
                                    unsigned int reg, unsigned int page)
 {
-       reg = EFX_PAGED_REG(page, reg);
+       reg = efx_paged_reg(efx, page, reg);
 
        netif_vdbg(efx, hw, efx->net_dev,
                   "writing register %x with " EFX_OWORD_FMT "\n", reg,
@@ -262,7 +265,7 @@ static inline void
 _efx_writed_page(struct efx_nic *efx, const efx_dword_t *value,
                 unsigned int reg, unsigned int page)
 {
-       efx_writed(efx, value, EFX_PAGED_REG(page, reg));
+       efx_writed(efx, value, efx_paged_reg(efx, page, reg));
 }
 #define efx_writed_page(efx, value, reg, page)                         \
        _efx_writed_page(efx, value,                                    \
@@ -288,10 +291,10 @@ static inline void _efx_writed_page_locked(struct efx_nic *efx,
 
        if (page == 0) {
                spin_lock_irqsave(&efx->biu_lock, flags);
-               efx_writed(efx, value, EFX_PAGED_REG(page, reg));
+               efx_writed(efx, value, efx_paged_reg(efx, page, reg));
                spin_unlock_irqrestore(&efx->biu_lock, flags);
        } else {
-               efx_writed(efx, value, EFX_PAGED_REG(page, reg));
+               efx_writed(efx, value, efx_paged_reg(efx, page, reg));
        }
 }
 #define efx_writed_page_locked(efx, value, reg, page)                  \
index 154ef41d19275ded25c7b34a84ac8769b99be013..ebd95972ae7bccdb84d24cf0d6883babaddeeea8 100644 (file)
@@ -208,6 +208,9 @@ void efx_mcdi_sensor_event(struct efx_nic *efx, efx_qword_t *ev);
 #define _MCDI_DWORD(_buf, _field)                                      \
        ((_buf) + (_MCDI_CHECK_ALIGN(MC_CMD_ ## _field ## _OFST, 4) >> 2))
 
+#define MCDI_BYTE(_buf, _field)                                                \
+       ((void)BUILD_BUG_ON_ZERO(MC_CMD_ ## _field ## _LEN != 1),       \
+        *MCDI_PTR(_buf, _field))
 #define MCDI_WORD(_buf, _field)                                                \
        ((u16)BUILD_BUG_ON_ZERO(MC_CMD_ ## _field ## _LEN != 2) +       \
         le16_to_cpu(*(__force const __le16 *)MCDI_PTR(_buf, _field)))
index 2b6599f8d9fa9c92f0f5725d50eb7d5dc7cdd3c7..2e41f2c39c4a2eec411515fcb70544d2b11b4c75 100644 (file)
@@ -708,6 +708,7 @@ struct vfdi_status;
  * @reset_work: Scheduled reset workitem
  * @membase_phys: Memory BAR value as physical address
  * @membase: Memory BAR value
+ * @vi_stride: step between per-VI registers / memory regions
  * @interrupt_mode: Interrupt mode
  * @timer_quantum_ns: Interrupt timer quantum, in nanoseconds
  * @timer_max_ns: Interrupt timer maximum value, in nanoseconds
@@ -842,6 +843,8 @@ struct efx_nic {
        resource_size_t membase_phys;
        void __iomem *membase;
 
+       unsigned int vi_stride;
+
        enum efx_int_mode interrupt_mode;
        unsigned int timer_quantum_ns;
        unsigned int timer_max_ns;