1
0
Fork 0

Merge branch 'sfc-next'

Shradha Shah says:

====================
sfc: Get/Set MAC address and ndo_[set/get]_vf_* entrypoint functions

This is the second installment of patches towards supporting EF10 SRIOV.

This patch series implements the ndo_get_vf_config, ndo_set_vf_mac,
ndo_set_vf_vlan and ndo_set_vf_spoofcheck function callbacks for EF10.

This patch series also introduces privileges for the MCDI commands
based on which functions are allowed to call them, i.e. Link control
or primary function.

The patch series has been tested with and without CONFIG_SFC_SRIOV.

The ndo function callbacks are tested using ip link.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
hifive-unleashed-5.1
David S. Miller 2015-05-21 18:43:55 -04:00
commit 4e7b3be406
19 changed files with 1055 additions and 98 deletions

View File

@ -119,6 +119,26 @@ static int efx_ef10_get_pf_index(struct efx_nic *efx)
return 0;
}
#ifdef CONFIG_SFC_SRIOV
static int efx_ef10_get_vf_index(struct efx_nic *efx)
{
MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_FUNCTION_INFO_OUT_LEN);
struct efx_ef10_nic_data *nic_data = efx->nic_data;
size_t outlen;
int rc;
rc = efx_mcdi_rpc(efx, MC_CMD_GET_FUNCTION_INFO, NULL, 0, outbuf,
sizeof(outbuf), &outlen);
if (rc)
return rc;
if (outlen < sizeof(outbuf))
return -EIO;
nic_data->vf_index = MCDI_DWORD(outbuf, GET_FUNCTION_INFO_OUT_VF);
return 0;
}
#endif
static int efx_ef10_init_datapath_caps(struct efx_nic *efx)
{
MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_CAPABILITIES_OUT_LEN);
@ -178,7 +198,7 @@ static int efx_ef10_get_sysclk_freq(struct efx_nic *efx)
return rc > 0 ? rc : -ERANGE;
}
static int efx_ef10_get_mac_address(struct efx_nic *efx, u8 *mac_address)
static int efx_ef10_get_mac_address_pf(struct efx_nic *efx, u8 *mac_address)
{
MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_MAC_ADDRESSES_OUT_LEN);
size_t outlen;
@ -198,6 +218,34 @@ static int efx_ef10_get_mac_address(struct efx_nic *efx, u8 *mac_address)
return 0;
}
static int efx_ef10_get_mac_address_vf(struct efx_nic *efx, u8 *mac_address)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_VPORT_GET_MAC_ADDRESSES_IN_LEN);
MCDI_DECLARE_BUF(outbuf, MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMAX);
size_t outlen;
int num_addrs, rc;
MCDI_SET_DWORD(inbuf, VPORT_GET_MAC_ADDRESSES_IN_VPORT_ID,
EVB_PORT_ID_ASSIGNED);
rc = efx_mcdi_rpc(efx, MC_CMD_VPORT_GET_MAC_ADDRESSES, inbuf,
sizeof(inbuf), outbuf, sizeof(outbuf), &outlen);
if (rc)
return rc;
if (outlen < MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMIN)
return -EIO;
num_addrs = MCDI_DWORD(outbuf,
VPORT_GET_MAC_ADDRESSES_OUT_MACADDR_COUNT);
WARN_ON(num_addrs != 1);
ether_addr_copy(mac_address,
MCDI_PTR(outbuf, VPORT_GET_MAC_ADDRESSES_OUT_MACADDR));
return 0;
}
static int efx_ef10_probe(struct efx_nic *efx)
{
struct efx_ef10_nic_data *nic_data;
@ -279,7 +327,7 @@ static int efx_ef10_probe(struct efx_nic *efx)
goto fail3;
efx->port_num = rc;
rc = efx_ef10_get_mac_address(efx, efx->net_dev->perm_addr);
rc = efx->type->get_mac_address(efx, efx->net_dev->perm_addr);
if (rc)
goto fail3;
@ -328,26 +376,9 @@ fail1:
return rc;
}
static int efx_ef10_probe_pf(struct efx_nic *efx)
{
return efx_ef10_probe(efx);
}
#ifdef CONFIG_SFC_SRIOV
static int efx_ef10_probe_vf(struct efx_nic *efx)
{
return efx_ef10_probe(efx);
}
#else
static int efx_ef10_probe_vf(struct efx_nic *efx __attribute__ ((unused)))
{
return 0;
}
#endif
static int efx_ef10_free_vis(struct efx_nic *efx)
{
MCDI_DECLARE_BUF_OUT_OR_ERR(outbuf, 0);
MCDI_DECLARE_BUF_ERR(outbuf);
size_t outlen;
int rc = efx_mcdi_rpc_quiet(efx, MC_CMD_FREE_VIS, NULL, 0,
outbuf, sizeof(outbuf), &outlen);
@ -418,9 +449,9 @@ static int efx_ef10_alloc_piobufs(struct efx_nic *efx, unsigned int n)
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));
_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;
@ -429,6 +460,8 @@ static int efx_ef10_link_piobufs(struct efx_nic *efx)
BUILD_BUG_ON(MC_CMD_LINK_PIOBUF_OUT_LEN != 0);
BUILD_BUG_ON(MC_CMD_UNLINK_PIOBUF_OUT_LEN != 0);
memset(inbuf, 0, sizeof(inbuf));
/* 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,
@ -541,6 +574,25 @@ static void efx_ef10_remove(struct efx_nic *efx)
struct efx_ef10_nic_data *nic_data = efx->nic_data;
int rc;
#ifdef CONFIG_SFC_SRIOV
struct efx_ef10_nic_data *nic_data_pf;
struct pci_dev *pci_dev_pf;
struct efx_nic *efx_pf;
struct ef10_vf *vf;
if (efx->pci_dev->is_virtfn) {
pci_dev_pf = efx->pci_dev->physfn;
if (pci_dev_pf) {
efx_pf = pci_get_drvdata(pci_dev_pf);
nic_data_pf = efx_pf->nic_data;
vf = nic_data_pf->vf + nic_data->vf_index;
vf->efx = NULL;
} else
netif_info(efx, drv, efx->net_dev,
"Could not get the PF id from VF\n");
}
#endif
efx_ptp_remove(efx);
efx_mcdi_mon_remove(efx);
@ -561,6 +613,50 @@ static void efx_ef10_remove(struct efx_nic *efx)
kfree(nic_data);
}
static int efx_ef10_probe_pf(struct efx_nic *efx)
{
return efx_ef10_probe(efx);
}
#ifdef CONFIG_SFC_SRIOV
static int efx_ef10_probe_vf(struct efx_nic *efx)
{
int rc;
rc = efx_ef10_probe(efx);
if (rc)
return rc;
rc = efx_ef10_get_vf_index(efx);
if (rc)
goto fail;
if (efx->pci_dev->is_virtfn) {
if (efx->pci_dev->physfn) {
struct efx_nic *efx_pf =
pci_get_drvdata(efx->pci_dev->physfn);
struct efx_ef10_nic_data *nic_data_p = efx_pf->nic_data;
struct efx_ef10_nic_data *nic_data = efx->nic_data;
nic_data_p->vf[nic_data->vf_index].efx = efx;
} else
netif_info(efx, drv, efx->net_dev,
"Could not get the PF id from VF\n");
}
return 0;
fail:
efx_ef10_remove(efx);
return rc;
}
#else
static int efx_ef10_probe_vf(struct efx_nic *efx __attribute__ ((unused)))
{
return 0;
}
#endif
static int efx_ef10_alloc_vis(struct efx_nic *efx,
unsigned int min_vis, unsigned int max_vis)
{
@ -770,6 +866,14 @@ static void efx_ef10_reset_mc_allocations(struct efx_nic *efx)
nic_data->rx_rss_context = EFX_EF10_RSS_CONTEXT_INVALID;
}
static enum reset_type efx_ef10_map_reset_reason(enum reset_type reason)
{
if (reason == RESET_TYPE_MC_FAILURE)
return RESET_TYPE_DATAPATH;
return efx_mcdi_map_reset_reason(reason);
}
static int efx_ef10_map_reset_flags(u32 *flags)
{
enum {
@ -1312,17 +1416,17 @@ static void efx_ef10_tx_init(struct efx_tx_queue *tx_queue)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_INIT_TXQ_IN_LEN(EFX_MAX_DMAQ_SIZE * 8 /
EFX_BUF_SIZE));
MCDI_DECLARE_BUF(outbuf, MC_CMD_INIT_TXQ_OUT_LEN);
bool csum_offload = tx_queue->queue & EFX_TXQ_TYPE_OFFLOAD;
size_t entries = tx_queue->txd.buf.len / EFX_BUF_SIZE;
struct efx_channel *channel = tx_queue->channel;
struct efx_nic *efx = tx_queue->efx;
struct efx_ef10_nic_data *nic_data = efx->nic_data;
size_t inlen, outlen;
size_t inlen;
dma_addr_t dma_addr;
efx_qword_t *txd;
int rc;
int i;
BUILD_BUG_ON(MC_CMD_INIT_TXQ_OUT_LEN != 0);
MCDI_SET_DWORD(inbuf, INIT_TXQ_IN_SIZE, tx_queue->ptr_mask + 1);
MCDI_SET_DWORD(inbuf, INIT_TXQ_IN_TARGET_EVQ, channel->channel);
@ -1347,7 +1451,7 @@ static void efx_ef10_tx_init(struct efx_tx_queue *tx_queue)
inlen = MC_CMD_INIT_TXQ_IN_LEN(entries);
rc = efx_mcdi_rpc(efx, MC_CMD_INIT_TXQ, inbuf, inlen,
outbuf, sizeof(outbuf), &outlen);
NULL, 0, NULL);
if (rc)
goto fail;
@ -1380,7 +1484,7 @@ fail:
static void efx_ef10_tx_fini(struct efx_tx_queue *tx_queue)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_FINI_TXQ_IN_LEN);
MCDI_DECLARE_BUF(outbuf, MC_CMD_FINI_TXQ_OUT_LEN);
MCDI_DECLARE_BUF_ERR(outbuf);
struct efx_nic *efx = tx_queue->efx;
size_t outlen;
int rc;
@ -1687,15 +1791,15 @@ static void efx_ef10_rx_init(struct efx_rx_queue *rx_queue)
MCDI_DECLARE_BUF(inbuf,
MC_CMD_INIT_RXQ_IN_LEN(EFX_MAX_DMAQ_SIZE * 8 /
EFX_BUF_SIZE));
MCDI_DECLARE_BUF(outbuf, MC_CMD_INIT_RXQ_OUT_LEN);
struct efx_channel *channel = efx_rx_queue_channel(rx_queue);
size_t entries = rx_queue->rxd.buf.len / EFX_BUF_SIZE;
struct efx_nic *efx = rx_queue->efx;
struct efx_ef10_nic_data *nic_data = efx->nic_data;
size_t inlen, outlen;
size_t inlen;
dma_addr_t dma_addr;
int rc;
int i;
BUILD_BUG_ON(MC_CMD_INIT_RXQ_OUT_LEN != 0);
rx_queue->scatter_n = 0;
rx_queue->scatter_len = 0;
@ -1724,7 +1828,7 @@ static void efx_ef10_rx_init(struct efx_rx_queue *rx_queue)
inlen = MC_CMD_INIT_RXQ_IN_LEN(entries);
rc = efx_mcdi_rpc(efx, MC_CMD_INIT_RXQ, inbuf, inlen,
outbuf, sizeof(outbuf), &outlen);
NULL, 0, NULL);
if (rc)
netdev_WARN(efx->net_dev, "failed to initialise RXQ %d\n",
efx_rx_queue_index(rx_queue));
@ -1733,7 +1837,7 @@ static void efx_ef10_rx_init(struct efx_rx_queue *rx_queue)
static void efx_ef10_rx_fini(struct efx_rx_queue *rx_queue)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_FINI_RXQ_IN_LEN);
MCDI_DECLARE_BUF(outbuf, MC_CMD_FINI_RXQ_OUT_LEN);
MCDI_DECLARE_BUF_ERR(outbuf);
struct efx_nic *efx = rx_queue->efx;
size_t outlen;
int rc;
@ -1895,7 +1999,7 @@ static int efx_ef10_ev_init(struct efx_channel *channel)
static void efx_ef10_ev_fini(struct efx_channel *channel)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_FINI_EVQ_IN_LEN);
MCDI_DECLARE_BUF(outbuf, MC_CMD_FINI_EVQ_OUT_LEN);
MCDI_DECLARE_BUF_ERR(outbuf);
struct efx_nic *efx = channel->efx;
size_t outlen;
int rc;
@ -3248,6 +3352,9 @@ fail:
return rc;
}
/* Caller must hold efx->filter_sem for read if race against
* efx_ef10_filter_table_remove() is possible
*/
static void efx_ef10_filter_table_restore(struct efx_nic *efx)
{
struct efx_ef10_filter_table *table = efx->filter_state;
@ -3257,9 +3364,14 @@ static void efx_ef10_filter_table_restore(struct efx_nic *efx)
bool failed = false;
int rc;
WARN_ON(!rwsem_is_locked(&efx->filter_sem));
if (!nic_data->must_restore_filters)
return;
if (!table)
return;
spin_lock_bh(&efx->filter_lock);
for (filter_idx = 0; filter_idx < HUNT_FILTER_TBL_ROWS; filter_idx++) {
@ -3295,6 +3407,7 @@ static void efx_ef10_filter_table_restore(struct efx_nic *efx)
nic_data->must_restore_filters = false;
}
/* Caller must hold efx->filter_sem for write */
static void efx_ef10_filter_table_remove(struct efx_nic *efx)
{
struct efx_ef10_filter_table *table = efx->filter_state;
@ -3303,6 +3416,10 @@ static void efx_ef10_filter_table_remove(struct efx_nic *efx)
unsigned int filter_idx;
int rc;
efx->filter_state = NULL;
if (!table)
return;
for (filter_idx = 0; filter_idx < HUNT_FILTER_TBL_ROWS; filter_idx++) {
spec = efx_ef10_filter_entry_spec(table, filter_idx);
if (!spec)
@ -3328,6 +3445,9 @@ static void efx_ef10_filter_table_remove(struct efx_nic *efx)
kfree(table);
}
/* Caller must hold efx->filter_sem for read if race against
* efx_ef10_filter_table_remove() is possible
*/
static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
{
struct efx_ef10_filter_table *table = efx->filter_state;
@ -3342,6 +3462,9 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
if (!efx_dev_registered(efx))
return;
if (!table)
return;
/* Mark old filters that may need to be removed */
spin_lock_bh(&efx->filter_lock);
n = table->dev_uc_count < 0 ? 1 : table->dev_uc_count;
@ -3473,6 +3596,78 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
WARN_ON(remove_failed);
}
static int efx_ef10_set_mac_address(struct efx_nic *efx)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_VADAPTOR_SET_MAC_IN_LEN);
struct efx_ef10_nic_data *nic_data = efx->nic_data;
bool was_enabled = efx->port_enabled;
int rc;
efx_device_detach_sync(efx);
efx_net_stop(efx->net_dev);
down_write(&efx->filter_sem);
efx_ef10_filter_table_remove(efx);
ether_addr_copy(MCDI_PTR(inbuf, VADAPTOR_SET_MAC_IN_MACADDR),
efx->net_dev->dev_addr);
MCDI_SET_DWORD(inbuf, VADAPTOR_SET_MAC_IN_UPSTREAM_PORT_ID,
nic_data->vport_id);
rc = efx_mcdi_rpc(efx, MC_CMD_VADAPTOR_SET_MAC, inbuf,
sizeof(inbuf), NULL, 0, NULL);
efx_ef10_filter_table_probe(efx);
up_write(&efx->filter_sem);
if (was_enabled)
efx_net_open(efx->net_dev);
netif_device_attach(efx->net_dev);
#if !defined(CONFIG_SFC_SRIOV)
if (rc == -EPERM)
netif_err(efx, drv, efx->net_dev,
"Cannot change MAC address; use sfboot to enable mac-spoofing"
" on this interface\n");
#else
if (rc == -EPERM) {
struct pci_dev *pci_dev_pf = efx->pci_dev->physfn;
/* Switch to PF and change MAC address on vport */
if (efx->pci_dev->is_virtfn && pci_dev_pf) {
struct efx_nic *efx_pf = pci_get_drvdata(pci_dev_pf);
if (!efx_ef10_sriov_set_vf_mac(efx_pf,
nic_data->vf_index,
efx->net_dev->dev_addr))
return 0;
}
netif_err(efx, drv, efx->net_dev,
"Cannot change MAC address; use sfboot to enable mac-spoofing"
" on this interface\n");
} else if (efx->pci_dev->is_virtfn) {
/* Successfully changed by VF (with MAC spoofing), so update the
* parent PF if possible.
*/
struct pci_dev *pci_dev_pf = efx->pci_dev->physfn;
if (pci_dev_pf) {
struct efx_nic *efx_pf = pci_get_drvdata(pci_dev_pf);
struct efx_ef10_nic_data *nic_data = efx_pf->nic_data;
unsigned int i;
for (i = 0; i < efx_pf->vf_count; ++i) {
struct ef10_vf *vf = nic_data->vf + i;
if (vf->efx == efx) {
ether_addr_copy(vf->mac,
efx->net_dev->dev_addr);
return 0;
}
}
}
}
#endif
return rc;
}
static int efx_ef10_mac_reconfigure(struct efx_nic *efx)
{
efx_ef10_filter_sync_rx_mode(efx);
@ -3480,6 +3675,13 @@ static int efx_ef10_mac_reconfigure(struct efx_nic *efx)
return efx_mcdi_set_mac(efx);
}
static int efx_ef10_mac_reconfigure_vf(struct efx_nic *efx)
{
efx_ef10_filter_sync_rx_mode(efx);
return 0;
}
static int efx_ef10_start_bist(struct efx_nic *efx, u32 bist_type)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_START_BIST_IN_LEN);
@ -3818,7 +4020,7 @@ const struct efx_nic_type efx_hunt_a0_vf_nic_type = {
.dimension_resources = efx_ef10_dimension_resources,
.init = efx_ef10_init_nic,
.fini = efx_port_dummy_op_void,
.map_reset_reason = efx_mcdi_map_reset_reason,
.map_reset_reason = efx_ef10_map_reset_reason,
.map_reset_flags = efx_ef10_map_reset_flags,
.reset = efx_ef10_reset,
.probe_port = efx_mcdi_port_probe,
@ -3833,7 +4035,7 @@ const struct efx_nic_type efx_hunt_a0_vf_nic_type = {
.stop_stats = efx_port_dummy_op_void,
.set_id_led = efx_mcdi_set_id_led,
.push_irq_moderation = efx_ef10_push_irq_moderation,
.reconfigure_mac = efx_ef10_mac_reconfigure,
.reconfigure_mac = efx_ef10_mac_reconfigure_vf,
.check_mac_fault = efx_mcdi_mac_check_fault,
.reconfigure_port = efx_mcdi_port_reconfigure,
.get_wol = efx_ef10_get_wol_vf,
@ -3890,6 +4092,9 @@ const struct efx_nic_type efx_hunt_a0_vf_nic_type = {
.vswitching_restore = efx_ef10_vswitching_restore_vf,
.vswitching_remove = efx_ef10_vswitching_remove_vf,
#endif
.get_mac_address = efx_ef10_get_mac_address_vf,
.set_mac_address = efx_ef10_set_mac_address,
.revision = EFX_REV_HUNT_A0,
.max_dma_mask = DMA_BIT_MASK(ESF_DZ_TX_KER_BUF_ADDR_WIDTH),
.rx_prefix_size = ES_DZ_RX_PREFIX_SIZE,
@ -3916,7 +4121,7 @@ const struct efx_nic_type efx_hunt_a0_nic_type = {
.dimension_resources = efx_ef10_dimension_resources,
.init = efx_ef10_init_nic,
.fini = efx_port_dummy_op_void,
.map_reset_reason = efx_mcdi_map_reset_reason,
.map_reset_reason = efx_ef10_map_reset_reason,
.map_reset_flags = efx_ef10_map_reset_flags,
.reset = efx_ef10_reset,
.probe_port = efx_mcdi_port_probe,
@ -3995,7 +4200,6 @@ const struct efx_nic_type efx_hunt_a0_nic_type = {
.sriov_configure = efx_ef10_sriov_configure,
.sriov_init = efx_ef10_sriov_init,
.sriov_fini = efx_ef10_sriov_fini,
.sriov_mac_address_changed = efx_ef10_sriov_mac_address_changed,
.sriov_wanted = efx_ef10_sriov_wanted,
.sriov_reset = efx_ef10_sriov_reset,
.sriov_flr = efx_ef10_sriov_flr,
@ -4003,10 +4207,13 @@ const struct efx_nic_type efx_hunt_a0_nic_type = {
.sriov_set_vf_vlan = efx_ef10_sriov_set_vf_vlan,
.sriov_set_vf_spoofchk = efx_ef10_sriov_set_vf_spoofchk,
.sriov_get_vf_config = efx_ef10_sriov_get_vf_config,
.sriov_set_vf_link_state = efx_ef10_sriov_set_vf_link_state,
.vswitching_probe = efx_ef10_vswitching_probe_pf,
.vswitching_restore = efx_ef10_vswitching_restore_pf,
.vswitching_remove = efx_ef10_vswitching_remove_pf,
#endif
.get_mac_address = efx_ef10_get_mac_address_pf,
.set_mac_address = efx_ef10_set_mac_address,
.revision = EFX_REV_HUNT_A0,
.max_dma_mask = DMA_BIT_MASK(ESF_DZ_TX_KER_BUF_ADDR_WIDTH),

View File

@ -57,15 +57,29 @@ static int efx_ef10_vswitch_alloc(struct efx_nic *efx, unsigned int port_id,
unsigned int vswitch_type)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_VSWITCH_ALLOC_IN_LEN);
int rc;
MCDI_SET_DWORD(inbuf, VSWITCH_ALLOC_IN_UPSTREAM_PORT_ID, port_id);
MCDI_SET_DWORD(inbuf, VSWITCH_ALLOC_IN_TYPE, vswitch_type);
MCDI_SET_DWORD(inbuf, VSWITCH_ALLOC_IN_NUM_VLAN_TAGS, 0);
MCDI_SET_DWORD(inbuf, VSWITCH_ALLOC_IN_NUM_VLAN_TAGS, 2);
MCDI_POPULATE_DWORD_1(inbuf, VSWITCH_ALLOC_IN_FLAGS,
VSWITCH_ALLOC_IN_FLAG_AUTO_PORT, 0);
return efx_mcdi_rpc(efx, MC_CMD_VSWITCH_ALLOC, inbuf, sizeof(inbuf),
NULL, 0, NULL);
/* Quietly try to allocate 2 VLAN tags */
rc = efx_mcdi_rpc_quiet(efx, MC_CMD_VSWITCH_ALLOC, inbuf, sizeof(inbuf),
NULL, 0, NULL);
/* If 2 VLAN tags is too many, revert to trying with 1 VLAN tags */
if (rc == -EPROTO) {
MCDI_SET_DWORD(inbuf, VSWITCH_ALLOC_IN_NUM_VLAN_TAGS, 1);
rc = efx_mcdi_rpc(efx, MC_CMD_VSWITCH_ALLOC, inbuf,
sizeof(inbuf), NULL, 0, NULL);
} else if (rc) {
efx_mcdi_display_error(efx, MC_CMD_VSWITCH_ALLOC,
MC_CMD_VSWITCH_ALLOC_IN_LEN,
NULL, 0, rc);
}
return rc;
}
static int efx_ef10_vswitch_free(struct efx_nic *efx, unsigned int port_id)
@ -81,6 +95,7 @@ static int efx_ef10_vswitch_free(struct efx_nic *efx, unsigned int port_id)
static int efx_ef10_vport_alloc(struct efx_nic *efx,
unsigned int port_id_in,
unsigned int vport_type,
u16 vlan,
unsigned int *port_id_out)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_VPORT_ALLOC_IN_LEN);
@ -92,9 +107,13 @@ static int efx_ef10_vport_alloc(struct efx_nic *efx,
MCDI_SET_DWORD(inbuf, VPORT_ALLOC_IN_UPSTREAM_PORT_ID, port_id_in);
MCDI_SET_DWORD(inbuf, VPORT_ALLOC_IN_TYPE, vport_type);
MCDI_SET_DWORD(inbuf, VPORT_ALLOC_IN_NUM_VLAN_TAGS, 0);
MCDI_SET_DWORD(inbuf, VPORT_ALLOC_IN_NUM_VLAN_TAGS,
(vlan != EFX_EF10_NO_VLAN));
MCDI_POPULATE_DWORD_1(inbuf, VPORT_ALLOC_IN_FLAGS,
VPORT_ALLOC_IN_FLAG_AUTO_PORT, 0);
if (vlan != EFX_EF10_NO_VLAN)
MCDI_POPULATE_DWORD_1(inbuf, VPORT_ALLOC_IN_VLAN_TAGS,
VPORT_ALLOC_IN_VLAN_TAG_0, vlan);
rc = efx_mcdi_rpc(efx, MC_CMD_VPORT_ALLOC, inbuf, sizeof(inbuf),
outbuf, sizeof(outbuf), &outlen);
@ -160,6 +179,8 @@ static void efx_ef10_sriov_free_vf_vports(struct efx_nic *efx)
efx_ef10_vport_free(efx, vf->vport_id);
vf->vport_id = 0;
}
vf->efx = NULL;
}
}
@ -184,7 +205,7 @@ static int efx_ef10_sriov_assign_vf_vport(struct efx_nic *efx,
rc = efx_ef10_vport_alloc(efx, EVB_PORT_ID_ASSIGNED,
MC_CMD_VPORT_ALLOC_IN_VPORT_TYPE_NORMAL,
&vf->vport_id);
vf->vlan, &vf->vport_id);
if (rc)
return rc;
@ -215,6 +236,8 @@ static int efx_ef10_sriov_alloc_vf_vswitching(struct efx_nic *efx)
for (i = 0; i < efx->vf_count; i++) {
random_ether_addr(nic_data->vf[i].mac);
nic_data->vf[i].efx = NULL;
nic_data->vf[i].vlan = EFX_EF10_NO_VLAN;
rc = efx_ef10_sriov_assign_vf_vport(efx, i);
if (rc)
@ -268,7 +291,7 @@ int efx_ef10_vswitching_probe_pf(struct efx_nic *efx)
rc = efx_ef10_vport_alloc(efx, EVB_PORT_ID_ASSIGNED,
MC_CMD_VPORT_ALLOC_IN_VPORT_TYPE_NORMAL,
&nic_data->vport_id);
EFX_EF10_NO_VLAN, &nic_data->vport_id);
if (rc)
goto fail2;
@ -428,3 +451,288 @@ void efx_ef10_sriov_fini(struct efx_nic *efx)
else
netif_dbg(efx, drv, efx->net_dev, "SRIOV disabled\n");
}
static int efx_ef10_vport_del_vf_mac(struct efx_nic *efx, unsigned int port_id,
u8 *mac)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_VPORT_DEL_MAC_ADDRESS_IN_LEN);
MCDI_DECLARE_BUF_ERR(outbuf);
size_t outlen;
int rc;
MCDI_SET_DWORD(inbuf, VPORT_DEL_MAC_ADDRESS_IN_VPORT_ID, port_id);
ether_addr_copy(MCDI_PTR(inbuf, VPORT_DEL_MAC_ADDRESS_IN_MACADDR), mac);
rc = efx_mcdi_rpc(efx, MC_CMD_VPORT_DEL_MAC_ADDRESS, inbuf,
sizeof(inbuf), outbuf, sizeof(outbuf), &outlen);
return rc;
}
int efx_ef10_sriov_set_vf_mac(struct efx_nic *efx, int vf_i, u8 *mac)
{
struct efx_ef10_nic_data *nic_data = efx->nic_data;
struct ef10_vf *vf;
int rc;
if (!nic_data->vf)
return -EOPNOTSUPP;
if (vf_i >= efx->vf_count)
return -EINVAL;
vf = nic_data->vf + vf_i;
if (vf->efx) {
efx_device_detach_sync(vf->efx);
efx_net_stop(vf->efx->net_dev);
down_write(&vf->efx->filter_sem);
vf->efx->type->filter_table_remove(vf->efx);
rc = efx_ef10_vadaptor_free(vf->efx, EVB_PORT_ID_ASSIGNED);
if (rc) {
up_write(&vf->efx->filter_sem);
return rc;
}
}
rc = efx_ef10_evb_port_assign(efx, EVB_PORT_ID_NULL, vf_i);
if (rc)
return rc;
if (!is_zero_ether_addr(vf->mac)) {
rc = efx_ef10_vport_del_vf_mac(efx, vf->vport_id, vf->mac);
if (rc)
return rc;
}
if (!is_zero_ether_addr(mac)) {
rc = efx_ef10_vport_add_mac(efx, vf->vport_id, mac);
if (rc) {
eth_zero_addr(vf->mac);
goto fail;
}
if (vf->efx)
ether_addr_copy(vf->efx->net_dev->dev_addr, mac);
}
ether_addr_copy(vf->mac, mac);
rc = efx_ef10_evb_port_assign(efx, vf->vport_id, vf_i);
if (rc)
goto fail;
if (vf->efx) {
/* VF cannot use the vport_id that the PF created */
rc = efx_ef10_vadaptor_alloc(vf->efx, EVB_PORT_ID_ASSIGNED);
if (rc) {
up_write(&vf->efx->filter_sem);
return rc;
}
vf->efx->type->filter_table_probe(vf->efx);
up_write(&vf->efx->filter_sem);
efx_net_open(vf->efx->net_dev);
netif_device_attach(vf->efx->net_dev);
}
return 0;
fail:
memset(vf->mac, 0, ETH_ALEN);
return rc;
}
int efx_ef10_sriov_set_vf_vlan(struct efx_nic *efx, int vf_i, u16 vlan,
u8 qos)
{
struct efx_ef10_nic_data *nic_data = efx->nic_data;
struct ef10_vf *vf;
u16 old_vlan, new_vlan;
int rc = 0, rc2 = 0;
if (vf_i >= efx->vf_count)
return -EINVAL;
if (qos != 0)
return -EINVAL;
vf = nic_data->vf + vf_i;
new_vlan = (vlan == 0) ? EFX_EF10_NO_VLAN : vlan;
if (new_vlan == vf->vlan)
return 0;
if (vf->efx) {
efx_device_detach_sync(vf->efx);
efx_net_stop(vf->efx->net_dev);
down_write(&vf->efx->filter_sem);
vf->efx->type->filter_table_remove(vf->efx);
rc = efx_ef10_vadaptor_free(vf->efx, EVB_PORT_ID_ASSIGNED);
if (rc)
goto restore_filters;
}
if (vf->vport_assigned) {
rc = efx_ef10_evb_port_assign(efx, EVB_PORT_ID_NULL, vf_i);
if (rc) {
netif_warn(efx, drv, efx->net_dev,
"Failed to change vlan on VF %d.\n", vf_i);
netif_warn(efx, drv, efx->net_dev,
"This is likely because the VF is bound to a driver in a VM.\n");
netif_warn(efx, drv, efx->net_dev,
"Please unload the driver in the VM.\n");
goto restore_vadaptor;
}
vf->vport_assigned = 0;
}
if (!is_zero_ether_addr(vf->mac)) {
rc = efx_ef10_vport_del_mac(efx, vf->vport_id, vf->mac);
if (rc)
goto restore_evb_port;
}
if (vf->vport_id) {
rc = efx_ef10_vport_free(efx, vf->vport_id);
if (rc)
goto restore_mac;
vf->vport_id = 0;
}
/* Do the actual vlan change */
old_vlan = vf->vlan;
vf->vlan = new_vlan;
/* Restore everything in reverse order */
rc = efx_ef10_vport_alloc(efx, EVB_PORT_ID_ASSIGNED,
MC_CMD_VPORT_ALLOC_IN_VPORT_TYPE_NORMAL,
vf->vlan, &vf->vport_id);
if (rc)
goto reset_nic;
restore_mac:
if (!is_zero_ether_addr(vf->mac)) {
rc2 = efx_ef10_vport_add_mac(efx, vf->vport_id, vf->mac);
if (rc2) {
eth_zero_addr(vf->mac);
goto reset_nic;
}
}
restore_evb_port:
rc2 = efx_ef10_evb_port_assign(efx, vf->vport_id, vf_i);
if (rc2)
goto reset_nic;
else
vf->vport_assigned = 1;
restore_vadaptor:
if (vf->efx) {
rc2 = efx_ef10_vadaptor_alloc(vf->efx, EVB_PORT_ID_ASSIGNED);
if (rc2)
goto reset_nic;
}
restore_filters:
if (vf->efx) {
rc2 = vf->efx->type->filter_table_probe(vf->efx);
if (rc2)
goto reset_nic;
up_write(&vf->efx->filter_sem);
rc2 = efx_net_open(vf->efx->net_dev);
if (rc2)
goto reset_nic;
netif_device_attach(vf->efx->net_dev);
}
return rc;
reset_nic:
if (vf->efx) {
up_write(&vf->efx->filter_sem);
netif_err(efx, drv, efx->net_dev,
"Failed to restore VF - scheduling reset.\n");
efx_schedule_reset(vf->efx, RESET_TYPE_DATAPATH);
} else {
netif_err(efx, drv, efx->net_dev,
"Failed to restore the VF and cannot reset the VF "
"- VF is not functional.\n");
netif_err(efx, drv, efx->net_dev,
"Please reload the driver attached to the VF.\n");
}
return rc ? rc : rc2;
}
int efx_ef10_sriov_set_vf_spoofchk(struct efx_nic *efx, int vf_i,
bool spoofchk)
{
return spoofchk ? -EOPNOTSUPP : 0;
}
int efx_ef10_sriov_set_vf_link_state(struct efx_nic *efx, int vf_i,
int link_state)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_LINK_STATE_MODE_IN_LEN);
struct efx_ef10_nic_data *nic_data = efx->nic_data;
BUILD_BUG_ON(IFLA_VF_LINK_STATE_AUTO !=
MC_CMD_LINK_STATE_MODE_IN_LINK_STATE_AUTO);
BUILD_BUG_ON(IFLA_VF_LINK_STATE_ENABLE !=
MC_CMD_LINK_STATE_MODE_IN_LINK_STATE_UP);
BUILD_BUG_ON(IFLA_VF_LINK_STATE_DISABLE !=
MC_CMD_LINK_STATE_MODE_IN_LINK_STATE_DOWN);
MCDI_POPULATE_DWORD_2(inbuf, LINK_STATE_MODE_IN_FUNCTION,
LINK_STATE_MODE_IN_FUNCTION_PF,
nic_data->pf_index,
LINK_STATE_MODE_IN_FUNCTION_VF, vf_i);
MCDI_SET_DWORD(inbuf, LINK_STATE_MODE_IN_NEW_MODE, link_state);
return efx_mcdi_rpc(efx, MC_CMD_LINK_STATE_MODE, inbuf, sizeof(inbuf),
NULL, 0, NULL); /* don't care what old mode was */
}
int efx_ef10_sriov_get_vf_config(struct efx_nic *efx, int vf_i,
struct ifla_vf_info *ivf)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_LINK_STATE_MODE_IN_LEN);
MCDI_DECLARE_BUF(outbuf, MC_CMD_LINK_STATE_MODE_OUT_LEN);
struct efx_ef10_nic_data *nic_data = efx->nic_data;
struct ef10_vf *vf;
size_t outlen;
int rc;
if (vf_i >= efx->vf_count)
return -EINVAL;
if (!nic_data->vf)
return -EOPNOTSUPP;
vf = nic_data->vf + vf_i;
ivf->vf = vf_i;
ivf->min_tx_rate = 0;
ivf->max_tx_rate = 0;
ether_addr_copy(ivf->mac, vf->mac);
ivf->vlan = (vf->vlan == EFX_EF10_NO_VLAN) ? 0 : vf->vlan;
ivf->qos = 0;
MCDI_POPULATE_DWORD_2(inbuf, LINK_STATE_MODE_IN_FUNCTION,
LINK_STATE_MODE_IN_FUNCTION_PF,
nic_data->pf_index,
LINK_STATE_MODE_IN_FUNCTION_VF, vf_i);
MCDI_SET_DWORD(inbuf, LINK_STATE_MODE_IN_NEW_MODE,
MC_CMD_LINK_STATE_MODE_IN_DO_NOT_CHANGE);
rc = efx_mcdi_rpc(efx, MC_CMD_LINK_STATE_MODE, inbuf, sizeof(inbuf),
outbuf, sizeof(outbuf), &outlen);
if (rc)
return rc;
if (outlen < MC_CMD_LINK_STATE_MODE_OUT_LEN)
return -EIO;
ivf->linkstate = MCDI_DWORD(outbuf, LINK_STATE_MODE_OUT_OLD_MODE);
return 0;
}

View File

@ -14,14 +14,19 @@
/**
* struct ef10_vf - PF's store of VF data
* @efx: efx_nic struct for the current VF
* @vport_id: vport ID for the VF
* @vport_assigned: record whether the vport is currently assigned to the VF
* @mac: MAC address for the VF, zero when address is removed from the vport
* @vlan: Default VLAN for the VF or #EFX_EF10_NO_VLAN
*/
struct ef10_vf {
struct efx_nic *efx;
unsigned int vport_id;
unsigned int vport_assigned;
u8 mac[ETH_ALEN];
u16 vlan;
#define EFX_EF10_NO_VLAN 0
};
static inline bool efx_ef10_sriov_wanted(struct efx_nic *efx)
@ -31,34 +36,23 @@ static inline bool efx_ef10_sriov_wanted(struct efx_nic *efx)
int efx_ef10_sriov_configure(struct efx_nic *efx, int num_vfs);
int efx_ef10_sriov_init(struct efx_nic *efx);
static inline void efx_ef10_sriov_mac_address_changed(struct efx_nic *efx) {}
static inline void efx_ef10_sriov_reset(struct efx_nic *efx) {}
void efx_ef10_sriov_fini(struct efx_nic *efx);
static inline void efx_ef10_sriov_flr(struct efx_nic *efx, unsigned vf_i) {}
static inline int efx_ef10_sriov_set_vf_mac(struct efx_nic *efx, int vf,
u8 *mac)
{
return -EOPNOTSUPP;
}
int efx_ef10_sriov_set_vf_mac(struct efx_nic *efx, int vf, u8 *mac);
static inline int efx_ef10_sriov_set_vf_vlan(struct efx_nic *efx, int vf,
u16 vlan, u8 qos)
{
return -EOPNOTSUPP;
}
int efx_ef10_sriov_set_vf_vlan(struct efx_nic *efx, int vf_i,
u16 vlan, u8 qos);
static inline int efx_ef10_sriov_set_vf_spoofchk(struct efx_nic *efx, int vf,
bool spoofchk)
{
return -EOPNOTSUPP;
}
int efx_ef10_sriov_set_vf_spoofchk(struct efx_nic *efx, int vf,
bool spoofchk);
static inline int efx_ef10_sriov_get_vf_config(struct efx_nic *efx, int vf,
struct ifla_vf_info *ivf)
{
return -EOPNOTSUPP;
}
int efx_ef10_sriov_get_vf_config(struct efx_nic *efx, int vf_i,
struct ifla_vf_info *ivf);
int efx_ef10_sriov_set_vf_link_state(struct efx_nic *efx, int vf_i,
int link_state);
int efx_ef10_vswitching_probe_pf(struct efx_nic *efx);
int efx_ef10_vswitching_probe_vf(struct efx_nic *efx);

View File

@ -77,6 +77,7 @@ const char *const efx_reset_type_names[] = {
[RESET_TYPE_RECOVER_OR_ALL] = "RECOVER_OR_ALL",
[RESET_TYPE_WORLD] = "WORLD",
[RESET_TYPE_RECOVER_OR_DISABLE] = "RECOVER_OR_DISABLE",
[RESET_TYPE_DATAPATH] = "DATAPATH",
[RESET_TYPE_MC_BIST] = "MC_BIST",
[RESET_TYPE_DISABLE] = "DISABLE",
[RESET_TYPE_TX_WATCHDOG] = "TX_WATCHDOG",
@ -949,6 +950,16 @@ void efx_link_set_wanted_fc(struct efx_nic *efx, u8 wanted_fc)
static void efx_fini_port(struct efx_nic *efx);
/* We assume that efx->type->reconfigure_mac will always try to sync RX
* filters and therefore needs to read-lock the filter table against freeing
*/
void efx_mac_reconfigure(struct efx_nic *efx)
{
down_read(&efx->filter_sem);
efx->type->reconfigure_mac(efx);
up_read(&efx->filter_sem);
}
/* Push loopback/power/transmit disable settings to the PHY, and reconfigure
* the MAC appropriately. All other PHY configuration changes are pushed
* through phy_op->set_settings(), and pushed asynchronously to the MAC
@ -1002,7 +1013,7 @@ static void efx_mac_work(struct work_struct *data)
mutex_lock(&efx->mac_lock);
if (efx->port_enabled)
efx->type->reconfigure_mac(efx);
efx_mac_reconfigure(efx);
mutex_unlock(&efx->mac_lock);
}
@ -1042,7 +1053,7 @@ static int efx_init_port(struct efx_nic *efx)
/* Reconfigure the MAC before creating dma queues (required for
* Falcon/A1 where RX_INGR_EN/TX_DRAIN_EN isn't supported) */
efx->type->reconfigure_mac(efx);
efx_mac_reconfigure(efx);
/* Ensure the PHY advertises the correct flow control settings */
rc = efx->phy_op->reconfigure(efx);
@ -1068,7 +1079,7 @@ static void efx_start_port(struct efx_nic *efx)
efx->port_enabled = true;
/* Ensure MAC ingress/egress is enabled */
efx->type->reconfigure_mac(efx);
efx_mac_reconfigure(efx);
mutex_unlock(&efx->mac_lock);
}
@ -1672,10 +1683,11 @@ static int efx_probe_filters(struct efx_nic *efx)
int rc;
spin_lock_init(&efx->filter_lock);
init_rwsem(&efx->filter_sem);
down_write(&efx->filter_sem);
rc = efx->type->filter_table_probe(efx);
if (rc)
return rc;
goto out_unlock;
#ifdef CONFIG_RFS_ACCEL
if (efx->type->offload_features & NETIF_F_NTUPLE) {
@ -1684,12 +1696,14 @@ static int efx_probe_filters(struct efx_nic *efx)
GFP_KERNEL);
if (!efx->rps_flow_id) {
efx->type->filter_table_remove(efx);
return -ENOMEM;
rc = -ENOMEM;
goto out_unlock;
}
}
#endif
return 0;
out_unlock:
up_write(&efx->filter_sem);
return rc;
}
static void efx_remove_filters(struct efx_nic *efx)
@ -1697,12 +1711,16 @@ static void efx_remove_filters(struct efx_nic *efx)
#ifdef CONFIG_RFS_ACCEL
kfree(efx->rps_flow_id);
#endif
down_write(&efx->filter_sem);
efx->type->filter_table_remove(efx);
up_write(&efx->filter_sem);
}
static void efx_restore_filters(struct efx_nic *efx)
{
down_read(&efx->filter_sem);
efx->type->filter_table_restore(efx);
up_read(&efx->filter_sem);
}
/**************************************************************************
@ -2096,7 +2114,7 @@ static int efx_busy_poll(struct napi_struct *napi)
*************************************************************************/
/* Context: process, rtnl_lock() held. */
static int efx_net_open(struct net_device *net_dev)
int efx_net_open(struct net_device *net_dev)
{
struct efx_nic *efx = netdev_priv(net_dev);
int rc;
@ -2125,7 +2143,7 @@ static int efx_net_open(struct net_device *net_dev)
* Note that the kernel will ignore our return code; this method
* should really be a void.
*/
static int efx_net_stop(struct net_device *net_dev)
int efx_net_stop(struct net_device *net_dev)
{
struct efx_nic *efx = netdev_priv(net_dev);
@ -2183,7 +2201,7 @@ static int efx_change_mtu(struct net_device *net_dev, int new_mtu)
mutex_lock(&efx->mac_lock);
net_dev->mtu = new_mtu;
efx->type->reconfigure_mac(efx);
efx_mac_reconfigure(efx);
mutex_unlock(&efx->mac_lock);
efx_start_all(efx);
@ -2196,6 +2214,8 @@ static int efx_set_mac_address(struct net_device *net_dev, void *data)
struct efx_nic *efx = netdev_priv(net_dev);
struct sockaddr *addr = data;
u8 *new_addr = addr->sa_data;
u8 old_addr[6];
int rc;
if (!is_valid_ether_addr(new_addr)) {
netif_err(efx, drv, efx->net_dev,
@ -2204,13 +2224,20 @@ static int efx_set_mac_address(struct net_device *net_dev, void *data)
return -EADDRNOTAVAIL;
}
/* save old address */
ether_addr_copy(old_addr, net_dev->dev_addr);
ether_addr_copy(net_dev->dev_addr, new_addr);
if (efx->type->sriov_mac_address_changed)
efx->type->sriov_mac_address_changed(efx);
if (efx->type->set_mac_address) {
rc = efx->type->set_mac_address(efx);
if (rc) {
ether_addr_copy(net_dev->dev_addr, old_addr);
return rc;
}
}
/* Reconfigure the MAC */
mutex_lock(&efx->mac_lock);
efx->type->reconfigure_mac(efx);
efx_mac_reconfigure(efx);
mutex_unlock(&efx->mac_lock);
return 0;
@ -2254,6 +2281,7 @@ static const struct net_device_ops efx_netdev_ops = {
.ndo_set_vf_vlan = efx_sriov_set_vf_vlan,
.ndo_set_vf_spoofchk = efx_sriov_set_vf_spoofchk,
.ndo_get_vf_config = efx_sriov_get_vf_config,
.ndo_set_vf_link_state = efx_sriov_set_vf_link_state,
#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = efx_netpoll,
@ -2404,7 +2432,8 @@ void efx_reset_down(struct efx_nic *efx, enum reset_type method)
efx_disable_interrupts(efx);
mutex_lock(&efx->mac_lock);
if (efx->port_initialized && method != RESET_TYPE_INVISIBLE)
if (efx->port_initialized && method != RESET_TYPE_INVISIBLE &&
method != RESET_TYPE_DATAPATH)
efx->phy_op->fini(efx);
efx->type->fini(efx);
}
@ -2433,7 +2462,8 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok)
if (!ok)
goto fail;
if (efx->port_initialized && method != RESET_TYPE_INVISIBLE) {
if (efx->port_initialized && method != RESET_TYPE_INVISIBLE &&
method != RESET_TYPE_DATAPATH) {
rc = efx->phy_op->init(efx);
if (rc)
goto fail;
@ -2455,7 +2485,9 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok)
" VFs may not function\n", rc);
#endif
down_read(&efx->filter_sem);
efx_restore_filters(efx);
up_read(&efx->filter_sem);
if (efx->type->sriov_reset)
efx->type->sriov_reset(efx);
@ -2627,6 +2659,7 @@ void efx_schedule_reset(struct efx_nic *efx, enum reset_type type)
case RESET_TYPE_WORLD:
case RESET_TYPE_DISABLE:
case RESET_TYPE_RECOVER_OR_DISABLE:
case RESET_TYPE_DATAPATH:
case RESET_TYPE_MC_BIST:
case RESET_TYPE_MCDI_TIMEOUT:
method = type;

View File

@ -19,6 +19,9 @@
#define EFX_MEM_BAR 2
#define EFX_MEM_VF_BAR 0
int efx_net_open(struct net_device *net_dev);
int efx_net_stop(struct net_device *net_dev);
/* TX */
int efx_probe_tx_queue(struct efx_tx_queue *tx_queue);
void efx_remove_tx_queue(struct efx_tx_queue *tx_queue);
@ -74,6 +77,8 @@ void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue);
/* Filters */
void efx_mac_reconfigure(struct efx_nic *efx);
/**
* efx_filter_insert_filter - add or replace a filter
* @efx: NIC in which to insert the filter

View File

@ -143,6 +143,7 @@ enum efx_loopback_mode {
* @RESET_TYPE_WORLD: Reset as much as possible
* @RESET_TYPE_RECOVER_OR_DISABLE: Try to recover. Apply RESET_TYPE_DISABLE if
* unsuccessful.
* @RESET_TYPE_DATAPATH: Reset datapath only.
* @RESET_TYPE_MC_BIST: MC entering BIST mode.
* @RESET_TYPE_DISABLE: Reset datapath, MAC and PHY; leave NIC disabled
* @RESET_TYPE_TX_WATCHDOG: reset due to TX watchdog
@ -159,6 +160,7 @@ enum reset_type {
RESET_TYPE_ALL,
RESET_TYPE_WORLD,
RESET_TYPE_RECOVER_OR_DISABLE,
RESET_TYPE_DATAPATH,
RESET_TYPE_MC_BIST,
RESET_TYPE_DISABLE,
RESET_TYPE_MAX_METHOD,

View File

@ -734,7 +734,7 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev,
/* Reconfigure the MAC. The PHY *may* generate a link state change event
* if the user just changed the advertised capabilities, but there's no
* harm doing this twice */
efx->type->reconfigure_mac(efx);
efx_mac_reconfigure(efx);
out:
mutex_unlock(&efx->mac_lock);

View File

@ -406,7 +406,7 @@ static bool efx_mcdi_complete_async(struct efx_mcdi_iface *mcdi, bool timeout)
struct efx_mcdi_async_param *async;
size_t hdr_len, data_len, err_len;
efx_dword_t *outbuf;
MCDI_DECLARE_BUF_OUT_OR_ERR(errbuf, 0);
MCDI_DECLARE_BUF_ERR(errbuf);
int rc;
if (cmpxchg(&mcdi->state,
@ -534,7 +534,7 @@ static int _efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned cmd, size_t inlen,
size_t *outlen_actual, bool quiet)
{
struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
MCDI_DECLARE_BUF_OUT_OR_ERR(errbuf, 0);
MCDI_DECLARE_BUF_ERR(errbuf);
int rc;
if (mcdi->mode == MCDI_MODE_POLL)
@ -1389,7 +1389,7 @@ fail1:
static int efx_mcdi_read_assertion(struct efx_nic *efx)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_ASSERTS_IN_LEN);
MCDI_DECLARE_BUF_OUT_OR_ERR(outbuf, MC_CMD_GET_ASSERTS_OUT_LEN);
MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_ASSERTS_OUT_LEN);
unsigned int flags, index;
const char *reason;
size_t outlen;
@ -1558,7 +1558,9 @@ int efx_mcdi_reset(struct efx_nic *efx, enum reset_type method)
if (rc)
return rc;
if (method == RESET_TYPE_WORLD)
if (method == RESET_TYPE_DATAPATH)
return 0;
else if (method == RESET_TYPE_WORLD)
return efx_mcdi_reset_mc(efx);
else
return efx_mcdi_reset_func(efx);
@ -1699,7 +1701,7 @@ int efx_mcdi_set_workaround(struct efx_nic *efx, u32 type, bool enabled)
int efx_mcdi_get_workarounds(struct efx_nic *efx, unsigned int *impl_out,
unsigned int *enabled_out)
{
MCDI_DECLARE_BUF_OUT_OR_ERR(outbuf, MC_CMD_GET_WORKAROUNDS_OUT_LEN);
MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_WORKAROUNDS_OUT_LEN);
size_t outlen;
int rc;

View File

@ -176,10 +176,12 @@ void efx_mcdi_sensor_event(struct efx_nic *efx, efx_qword_t *ev);
* 32-bit-aligned. Also, on Siena we must copy to the MC shared
* memory strictly 32 bits at a time, so add any necessary padding.
*/
#define MCDI_DECLARE_BUF(_name, _len) \
#define _MCDI_DECLARE_BUF(_name, _len) \
efx_dword_t _name[DIV_ROUND_UP(_len, 4)]
#define MCDI_DECLARE_BUF_OUT_OR_ERR(_name, _len) \
MCDI_DECLARE_BUF(_name, max_t(size_t, _len, 8))
#define MCDI_DECLARE_BUF(_name, _len) \
_MCDI_DECLARE_BUF(_name, _len) = {{{0}}}
#define MCDI_DECLARE_BUF_ERR(_name) \
MCDI_DECLARE_BUF(_name, 8)
#define _MCDI_PTR(_buf, _offset) \
((u8 *)(_buf) + (_offset))
#define MCDI_PTR(_buf, _field) \

File diff suppressed because it is too large Load Diff

View File

@ -865,6 +865,7 @@ int efx_mcdi_set_mac(struct efx_nic *efx)
BUILD_BUG_ON(MC_CMD_SET_MAC_OUT_LEN != 0);
/* This has no effect on EF10 */
ether_addr_copy(MCDI_PTR(cmdbytes, SET_MAC_IN_ADDR),
efx->net_dev->dev_addr);

View File

@ -25,6 +25,7 @@
#include <linux/highmem.h>
#include <linux/workqueue.h>
#include <linux/mutex.h>
#include <linux/rwsem.h>
#include <linux/vmalloc.h>
#include <linux/i2c.h>
#include <linux/mtd/mtd.h>
@ -896,7 +897,8 @@ struct vfdi_status;
* @loopback_mode: Loopback status
* @loopback_modes: Supported loopback mode bitmask
* @loopback_selftest: Offline self-test private state
* @filter_lock: Filter table lock
* @filter_sem: Filter table rw_semaphore, for freeing the table
* @filter_lock: Filter table lock, for mere content changes
* @filter_state: Architecture-dependent filter table state
* @rps_flow_id: Flow IDs of filters allocated for accelerated RFS,
* indexed by filter ID
@ -1038,6 +1040,7 @@ struct efx_nic {
void *loopback_selftest;
struct rw_semaphore filter_sem;
spinlock_t filter_lock;
void *filter_state;
#ifdef CONFIG_RFS_ACCEL
@ -1202,6 +1205,7 @@ struct efx_mtd_partition {
* @ptp_set_ts_config: Set hardware timestamp configuration. The flags
* and tx_type will already have been validated but this operation
* must validate and update rx_filter.
* @set_mac_address: Set the MAC address of the device
* @revision: Hardware architecture revision
* @txd_ptr_tbl_base: TX descriptor ring base address
* @rxd_ptr_tbl_base: RX descriptor ring base address
@ -1334,7 +1338,6 @@ struct efx_nic_type {
int (*sriov_configure)(struct efx_nic *efx, int num_vfs);
int (*sriov_init)(struct efx_nic *efx);
void (*sriov_fini)(struct efx_nic *efx);
void (*sriov_mac_address_changed)(struct efx_nic *efx);
bool (*sriov_wanted)(struct efx_nic *efx);
void (*sriov_reset)(struct efx_nic *efx);
void (*sriov_flr)(struct efx_nic *efx, unsigned vf_i);
@ -1345,9 +1348,13 @@ struct efx_nic_type {
bool spoofchk);
int (*sriov_get_vf_config)(struct efx_nic *efx, int vf_i,
struct ifla_vf_info *ivi);
int (*sriov_set_vf_link_state)(struct efx_nic *efx, int vf_i,
int link_state);
int (*vswitching_probe)(struct efx_nic *efx);
int (*vswitching_restore)(struct efx_nic *efx);
void (*vswitching_remove)(struct efx_nic *efx);
int (*get_mac_address)(struct efx_nic *efx, unsigned char *perm_addr);
int (*set_mac_address)(struct efx_nic *efx);
int revision;
unsigned int txd_ptr_tbl_base;

View File

@ -525,6 +525,7 @@ struct efx_ef10_nic_data {
bool must_probe_vswitching;
unsigned int pf_index;
#ifdef CONFIG_SFC_SRIOV
unsigned int vf_index;
struct ef10_vf *vf;
#endif
u8 vport_mac[ETH_ALEN];

View File

@ -306,7 +306,7 @@ struct efx_ptp_data {
struct work_struct pps_work;
struct workqueue_struct *pps_workwq;
bool nic_ts_enabled;
MCDI_DECLARE_BUF(txbuf, MC_CMD_PTP_IN_TRANSMIT_LENMAX);
_MCDI_DECLARE_BUF(txbuf, MC_CMD_PTP_IN_TRANSMIT_LENMAX);
unsigned int good_syncs;
unsigned int fast_syncs;
@ -573,7 +573,7 @@ static int efx_ptp_get_timestamp_corrections(struct efx_nic *efx)
static int efx_ptp_enable(struct efx_nic *efx)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_PTP_IN_ENABLE_LEN);
MCDI_DECLARE_BUF_OUT_OR_ERR(outbuf, 0);
MCDI_DECLARE_BUF_ERR(outbuf);
int rc;
MCDI_SET_DWORD(inbuf, PTP_IN_OP, MC_CMD_PTP_OP_ENABLE);
@ -601,7 +601,7 @@ static int efx_ptp_enable(struct efx_nic *efx)
static int efx_ptp_disable(struct efx_nic *efx)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_PTP_IN_DISABLE_LEN);
MCDI_DECLARE_BUF_OUT_OR_ERR(outbuf, 0);
MCDI_DECLARE_BUF_ERR(outbuf);
int rc;
MCDI_SET_DWORD(inbuf, PTP_IN_OP, MC_CMD_PTP_OP_DISABLE);

View File

@ -1010,7 +1010,6 @@ const struct efx_nic_type siena_a0_nic_type = {
.sriov_configure = efx_siena_sriov_configure,
.sriov_init = efx_siena_sriov_init,
.sriov_fini = efx_siena_sriov_fini,
.sriov_mac_address_changed = efx_siena_sriov_mac_address_changed,
.sriov_wanted = efx_siena_sriov_wanted,
.sriov_reset = efx_siena_sriov_reset,
.sriov_flr = efx_siena_sriov_flr,
@ -1021,6 +1020,7 @@ const struct efx_nic_type siena_a0_nic_type = {
.vswitching_probe = efx_port_dummy_op_int,
.vswitching_restore = efx_port_dummy_op_int,
.vswitching_remove = efx_port_dummy_op_void,
.set_mac_address = efx_siena_sriov_mac_address_changed,
#endif
.revision = EFX_REV_SIENA_A0,

View File

@ -1476,16 +1476,18 @@ void efx_siena_sriov_flr(struct efx_nic *efx, unsigned vf_i)
vf->evq0_count = 0;
}
void efx_siena_sriov_mac_address_changed(struct efx_nic *efx)
int efx_siena_sriov_mac_address_changed(struct efx_nic *efx)
{
struct siena_nic_data *nic_data = efx->nic_data;
struct vfdi_status *vfdi_status = nic_data->vfdi_status.addr;
if (!efx->vf_init_count)
return;
return 0;
ether_addr_copy(vfdi_status->peers[0].mac_addr,
efx->net_dev->dev_addr);
queue_work(vfdi_workqueue, &nic_data->peer_work);
return 0;
}
void efx_siena_sriov_tx_flush_done(struct efx_nic *efx, efx_qword_t *event)

View File

@ -44,7 +44,7 @@
int efx_siena_sriov_configure(struct efx_nic *efx, int num_vfs);
int efx_siena_sriov_init(struct efx_nic *efx);
void efx_siena_sriov_fini(struct efx_nic *efx);
void efx_siena_sriov_mac_address_changed(struct efx_nic *efx);
int efx_siena_sriov_mac_address_changed(struct efx_nic *efx);
bool efx_siena_sriov_wanted(struct efx_nic *efx);
void efx_siena_sriov_reset(struct efx_nic *efx);
void efx_siena_sriov_flr(struct efx_nic *efx, unsigned flr);

View File

@ -58,3 +58,15 @@ int efx_sriov_get_vf_config(struct net_device *net_dev, int vf_i,
else
return -EOPNOTSUPP;
}
int efx_sriov_set_vf_link_state(struct net_device *net_dev, int vf_i,
int link_state)
{
struct efx_nic *efx = netdev_priv(net_dev);
if (efx->type->sriov_set_vf_link_state)
return efx->type->sriov_set_vf_link_state(efx, vf_i,
link_state);
else
return -EOPNOTSUPP;
}

View File

@ -21,6 +21,8 @@ int efx_sriov_set_vf_spoofchk(struct net_device *net_dev, int vf_i,
bool spoofchk);
int efx_sriov_get_vf_config(struct net_device *net_dev, int vf_i,
struct ifla_vf_info *ivi);
int efx_sriov_set_vf_link_state(struct net_device *net_dev, int vf_i,
int link_state);
#endif /* CONFIG_SFC_SRIOV */