Commit 71827443 authored by Edward Cree's avatar Edward Cree Committed by David S. Miller

sfc: support VI strides other than 8k

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: default avatarEdward Cree <ecree@solarflare.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 03714bbb
...@@ -233,7 +233,7 @@ static int efx_ef10_get_vf_index(struct efx_nic *efx) ...@@ -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) 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; struct efx_ef10_nic_data *nic_data = efx->nic_data;
size_t outlen; size_t outlen;
int rc; int rc;
...@@ -277,6 +277,35 @@ static int efx_ef10_init_datapath_caps(struct efx_nic *efx) ...@@ -277,6 +277,35 @@ static int efx_ef10_init_datapath_caps(struct efx_nic *efx)
return -ENODEV; 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; return 0;
} }
...@@ -609,17 +638,6 @@ static int efx_ef10_probe(struct efx_nic *efx) ...@@ -609,17 +638,6 @@ static int efx_ef10_probe(struct efx_nic *efx)
struct efx_ef10_nic_data *nic_data; struct efx_ef10_nic_data *nic_data;
int i, rc; 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); nic_data = kzalloc(sizeof(*nic_data), GFP_KERNEL);
if (!nic_data) if (!nic_data)
return -ENOMEM; return -ENOMEM;
...@@ -691,6 +709,20 @@ static int efx_ef10_probe(struct efx_nic *efx) ...@@ -691,6 +709,20 @@ static int efx_ef10_probe(struct efx_nic *efx)
if (rc < 0) if (rc < 0)
goto fail5; 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 = efx->rx_packet_len_offset =
ES_DZ_RX_PREFIX_PKTLEN_OFST - ES_DZ_RX_PREFIX_SIZE; 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) ...@@ -927,7 +959,7 @@ static int efx_ef10_link_piobufs(struct efx_nic *efx)
} else { } else {
tx_queue->piobuf = tx_queue->piobuf =
nic_data->pio_write_base + nic_data->pio_write_base +
index * EFX_VI_PAGE_SIZE + offset; index * efx->vi_stride + offset;
tx_queue->piobuf_offset = offset; tx_queue->piobuf_offset = offset;
netif_dbg(efx, probe, efx->net_dev, netif_dbg(efx, probe, efx->net_dev,
"linked VI %u to PIO buffer %u offset %x addr %p\n", "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) ...@@ -1273,19 +1305,19 @@ static int efx_ef10_dimension_resources(struct efx_nic *efx)
* for writing PIO buffers through. * for writing PIO buffers through.
* *
* The UC mapping contains (channel_vis - 1) complete VIs and the * The UC mapping contains (channel_vis - 1) complete VIs and the
* first half of the next VI. Then the WC mapping begins with * first 4K of the next VI. Then the WC mapping begins with
* the second half of this last VI. * 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); ER_DZ_TX_PIOBUF);
if (nic_data->n_piobufs) { if (nic_data->n_piobufs) {
/* pio_write_vi_base rounds down to give the number of complete /* pio_write_vi_base rounds down to give the number of complete
* VIs inside the UC mapping. * 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 + wc_mem_map_size = (PAGE_ALIGN((pio_write_vi_base +
nic_data->n_piobufs) * nic_data->n_piobufs) *
EFX_VI_PAGE_SIZE) - efx->vi_stride) -
uc_mem_map_size); uc_mem_map_size);
max_vis = pio_write_vi_base + nic_data->n_piobufs; max_vis = pio_write_vi_base + nic_data->n_piobufs;
} else { } else {
...@@ -1357,7 +1389,7 @@ static int efx_ef10_dimension_resources(struct efx_nic *efx) ...@@ -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_vi_base = pio_write_vi_base;
nic_data->pio_write_base = nic_data->pio_write_base =
nic_data->wc_membase + 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); uc_mem_map_size);
rc = efx_ef10_link_piobufs(efx); rc = efx_ef10_link_piobufs(efx);
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <net/udp_tunnel.h> #include <net/udp_tunnel.h>
#include "efx.h" #include "efx.h"
#include "nic.h" #include "nic.h"
#include "io.h"
#include "selftest.h" #include "selftest.h"
#include "sriov.h" #include "sriov.h"
...@@ -2977,6 +2978,7 @@ static int efx_init_struct(struct efx_nic *efx, ...@@ -2977,6 +2978,7 @@ static int efx_init_struct(struct efx_nic *efx,
efx->rx_packet_ts_offset = efx->rx_packet_ts_offset =
efx->type->rx_ts_offset - efx->type->rx_prefix_size; efx->type->rx_ts_offset - efx->type->rx_prefix_size;
spin_lock_init(&efx->stats_lock); spin_lock_init(&efx->stats_lock);
efx->vi_stride = EFX_DEFAULT_VI_STRIDE;
mutex_init(&efx->mac_lock); mutex_init(&efx->mac_lock);
efx->phy_op = &efx_dummy_phy_operations; efx->phy_op = &efx_dummy_phy_operations;
efx->mdio.dev = net_dev; efx->mdio.dev = net_dev;
......
...@@ -222,18 +222,21 @@ static inline void efx_reado_table(struct efx_nic *efx, efx_oword_t *value, ...@@ -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)); efx_reado(efx, value, reg + index * sizeof(efx_oword_t));
} }
/* Page size used as step between per-VI registers */ /* default VI stride (step between per-VI registers) is 8K */
#define EFX_VI_PAGE_SIZE 0x2000 #define EFX_DEFAULT_VI_STRIDE 0x2000
/* Calculate offset to page-mapped register */ /* Calculate offset to page-mapped register */
#define EFX_PAGED_REG(page, reg) \ static inline unsigned int efx_paged_reg(struct efx_nic *efx, unsigned int page,
((page) * EFX_VI_PAGE_SIZE + (reg)) unsigned int reg)
{
return page * efx->vi_stride + reg;
}
/* Write the whole of RX_DESC_UPD or TX_DESC_UPD */ /* 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, static inline void _efx_writeo_page(struct efx_nic *efx, efx_oword_t *value,
unsigned int reg, unsigned int page) 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, netif_vdbg(efx, hw, efx->net_dev,
"writing register %x with " EFX_OWORD_FMT "\n", reg, "writing register %x with " EFX_OWORD_FMT "\n", reg,
...@@ -262,7 +265,7 @@ static inline void ...@@ -262,7 +265,7 @@ static inline void
_efx_writed_page(struct efx_nic *efx, const efx_dword_t *value, _efx_writed_page(struct efx_nic *efx, const efx_dword_t *value,
unsigned int reg, unsigned int page) 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) \ #define efx_writed_page(efx, value, reg, page) \
_efx_writed_page(efx, value, \ _efx_writed_page(efx, value, \
...@@ -288,10 +291,10 @@ static inline void _efx_writed_page_locked(struct efx_nic *efx, ...@@ -288,10 +291,10 @@ static inline void _efx_writed_page_locked(struct efx_nic *efx,
if (page == 0) { if (page == 0) {
spin_lock_irqsave(&efx->biu_lock, flags); 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); spin_unlock_irqrestore(&efx->biu_lock, flags);
} else { } 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) \ #define efx_writed_page_locked(efx, value, reg, page) \
......
...@@ -208,6 +208,9 @@ void efx_mcdi_sensor_event(struct efx_nic *efx, efx_qword_t *ev); ...@@ -208,6 +208,9 @@ void efx_mcdi_sensor_event(struct efx_nic *efx, efx_qword_t *ev);
#define _MCDI_DWORD(_buf, _field) \ #define _MCDI_DWORD(_buf, _field) \
((_buf) + (_MCDI_CHECK_ALIGN(MC_CMD_ ## _field ## _OFST, 4) >> 2)) ((_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) \ #define MCDI_WORD(_buf, _field) \
((u16)BUILD_BUG_ON_ZERO(MC_CMD_ ## _field ## _LEN != 2) + \ ((u16)BUILD_BUG_ON_ZERO(MC_CMD_ ## _field ## _LEN != 2) + \
le16_to_cpu(*(__force const __le16 *)MCDI_PTR(_buf, _field))) le16_to_cpu(*(__force const __le16 *)MCDI_PTR(_buf, _field)))
......
...@@ -708,6 +708,7 @@ struct vfdi_status; ...@@ -708,6 +708,7 @@ struct vfdi_status;
* @reset_work: Scheduled reset workitem * @reset_work: Scheduled reset workitem
* @membase_phys: Memory BAR value as physical address * @membase_phys: Memory BAR value as physical address
* @membase: Memory BAR value * @membase: Memory BAR value
* @vi_stride: step between per-VI registers / memory regions
* @interrupt_mode: Interrupt mode * @interrupt_mode: Interrupt mode
* @timer_quantum_ns: Interrupt timer quantum, in nanoseconds * @timer_quantum_ns: Interrupt timer quantum, in nanoseconds
* @timer_max_ns: Interrupt timer maximum value, in nanoseconds * @timer_max_ns: Interrupt timer maximum value, in nanoseconds
...@@ -842,6 +843,8 @@ struct efx_nic { ...@@ -842,6 +843,8 @@ struct efx_nic {
resource_size_t membase_phys; resource_size_t membase_phys;
void __iomem *membase; void __iomem *membase;
unsigned int vi_stride;
enum efx_int_mode interrupt_mode; enum efx_int_mode interrupt_mode;
unsigned int timer_quantum_ns; unsigned int timer_quantum_ns;
unsigned int timer_max_ns; unsigned int timer_max_ns;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment