2015-05-06 00:55:58 +01:00
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2015 Solarflare Communications Inc .
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation , incorporated herein by reference .
*/
# include <linux/pci.h>
# include <linux/module.h>
# include "net_driver.h"
# include "ef10_sriov.h"
# include "efx.h"
# include "nic.h"
# include "mcdi_pcol.h"
2015-05-06 00:58:31 +01:00
static int efx_ef10_evb_port_assign ( struct efx_nic * efx , unsigned int port_id ,
unsigned int vf_fn )
2015-05-06 00:55:58 +01:00
{
2015-05-06 00:58:31 +01:00
MCDI_DECLARE_BUF ( inbuf , MC_CMD_EVB_PORT_ASSIGN_IN_LEN ) ;
struct efx_ef10_nic_data * nic_data = efx - > nic_data ;
2015-05-06 00:55:58 +01:00
2015-05-06 00:58:31 +01:00
MCDI_SET_DWORD ( inbuf , EVB_PORT_ASSIGN_IN_PORT_ID , port_id ) ;
MCDI_POPULATE_DWORD_2 ( inbuf , EVB_PORT_ASSIGN_IN_FUNCTION ,
EVB_PORT_ASSIGN_IN_PF , nic_data - > pf_index ,
EVB_PORT_ASSIGN_IN_VF , vf_fn ) ;
return efx_mcdi_rpc ( efx , MC_CMD_EVB_PORT_ASSIGN , inbuf , sizeof ( inbuf ) ,
NULL , 0 , NULL ) ;
2015-05-06 00:55:58 +01:00
}
2015-05-06 00:58:31 +01:00
static int efx_ef10_vport_add_mac ( struct efx_nic * efx ,
unsigned int port_id , u8 * mac )
2015-05-06 00:55:58 +01:00
{
2015-05-06 00:58:31 +01:00
MCDI_DECLARE_BUF ( inbuf , MC_CMD_VPORT_ADD_MAC_ADDRESS_IN_LEN ) ;
2015-05-06 00:55:58 +01:00
2015-05-06 00:58:31 +01:00
MCDI_SET_DWORD ( inbuf , VPORT_ADD_MAC_ADDRESS_IN_VPORT_ID , port_id ) ;
ether_addr_copy ( MCDI_PTR ( inbuf , VPORT_ADD_MAC_ADDRESS_IN_MACADDR ) , mac ) ;
2015-05-06 00:55:58 +01:00
2015-05-06 00:58:31 +01:00
return efx_mcdi_rpc ( efx , MC_CMD_VPORT_ADD_MAC_ADDRESS , inbuf ,
sizeof ( inbuf ) , NULL , 0 , NULL ) ;
2015-05-06 00:55:58 +01:00
}
2015-05-06 00:57:34 +01:00
2015-05-06 00:58:31 +01:00
static int efx_ef10_vport_del_mac ( struct efx_nic * efx ,
unsigned int port_id , u8 * mac )
2015-05-06 00:58:14 +01:00
{
2015-05-06 00:58:31 +01:00
MCDI_DECLARE_BUF ( inbuf , MC_CMD_VPORT_DEL_MAC_ADDRESS_IN_LEN ) ;
2015-05-06 00:58:14 +01:00
2015-05-06 00:58:31 +01:00
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 ) ;
2015-05-06 00:58:14 +01:00
2015-05-06 00:58:31 +01:00
return efx_mcdi_rpc ( efx , MC_CMD_VPORT_DEL_MAC_ADDRESS , inbuf ,
sizeof ( inbuf ) , NULL , 0 , NULL ) ;
2015-05-06 00:58:14 +01:00
}
2015-05-06 00:57:34 +01:00
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 ) ;
2015-05-20 11:11:54 +01:00
int rc ;
2015-05-06 00:57:34 +01:00
MCDI_SET_DWORD ( inbuf , VSWITCH_ALLOC_IN_UPSTREAM_PORT_ID , port_id ) ;
MCDI_SET_DWORD ( inbuf , VSWITCH_ALLOC_IN_TYPE , vswitch_type ) ;
2015-05-20 11:11:54 +01:00
MCDI_SET_DWORD ( inbuf , VSWITCH_ALLOC_IN_NUM_VLAN_TAGS , 2 ) ;
2015-05-06 00:57:34 +01:00
MCDI_POPULATE_DWORD_1 ( inbuf , VSWITCH_ALLOC_IN_FLAGS ,
VSWITCH_ALLOC_IN_FLAG_AUTO_PORT , 0 ) ;
2015-05-20 11:11:54 +01:00
/* 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 ;
2015-05-06 00:57:34 +01:00
}
static int efx_ef10_vswitch_free ( struct efx_nic * efx , unsigned int port_id )
{
MCDI_DECLARE_BUF ( inbuf , MC_CMD_VSWITCH_FREE_IN_LEN ) ;
MCDI_SET_DWORD ( inbuf , VSWITCH_FREE_IN_UPSTREAM_PORT_ID , port_id ) ;
return efx_mcdi_rpc ( efx , MC_CMD_VSWITCH_FREE , inbuf , sizeof ( inbuf ) ,
NULL , 0 , NULL ) ;
}
static int efx_ef10_vport_alloc ( struct efx_nic * efx ,
unsigned int port_id_in ,
unsigned int vport_type ,
2015-05-20 11:11:54 +01:00
u16 vlan ,
2015-05-06 00:57:34 +01:00
unsigned int * port_id_out )
{
MCDI_DECLARE_BUF ( inbuf , MC_CMD_VPORT_ALLOC_IN_LEN ) ;
MCDI_DECLARE_BUF ( outbuf , MC_CMD_VPORT_ALLOC_OUT_LEN ) ;
size_t outlen ;
int rc ;
EFX_WARN_ON_PARANOID ( ! port_id_out ) ;
MCDI_SET_DWORD ( inbuf , VPORT_ALLOC_IN_UPSTREAM_PORT_ID , port_id_in ) ;
MCDI_SET_DWORD ( inbuf , VPORT_ALLOC_IN_TYPE , vport_type ) ;
2015-05-20 11:11:54 +01:00
MCDI_SET_DWORD ( inbuf , VPORT_ALLOC_IN_NUM_VLAN_TAGS ,
( vlan ! = EFX_EF10_NO_VLAN ) ) ;
2015-05-06 00:57:34 +01:00
MCDI_POPULATE_DWORD_1 ( inbuf , VPORT_ALLOC_IN_FLAGS ,
VPORT_ALLOC_IN_FLAG_AUTO_PORT , 0 ) ;
2015-05-20 11:11:54 +01:00
if ( vlan ! = EFX_EF10_NO_VLAN )
MCDI_POPULATE_DWORD_1 ( inbuf , VPORT_ALLOC_IN_VLAN_TAGS ,
VPORT_ALLOC_IN_VLAN_TAG_0 , vlan ) ;
2015-05-06 00:57:34 +01:00
rc = efx_mcdi_rpc ( efx , MC_CMD_VPORT_ALLOC , inbuf , sizeof ( inbuf ) ,
outbuf , sizeof ( outbuf ) , & outlen ) ;
if ( rc )
return rc ;
if ( outlen < MC_CMD_VPORT_ALLOC_OUT_LEN )
return - EIO ;
* port_id_out = MCDI_DWORD ( outbuf , VPORT_ALLOC_OUT_VPORT_ID ) ;
return 0 ;
}
static int efx_ef10_vport_free ( struct efx_nic * efx , unsigned int port_id )
{
MCDI_DECLARE_BUF ( inbuf , MC_CMD_VPORT_FREE_IN_LEN ) ;
MCDI_SET_DWORD ( inbuf , VPORT_FREE_IN_VPORT_ID , port_id ) ;
return efx_mcdi_rpc ( efx , MC_CMD_VPORT_FREE , inbuf , sizeof ( inbuf ) ,
NULL , 0 , NULL ) ;
}
2015-05-06 00:58:54 +01:00
static int efx_ef10_vadaptor_alloc ( struct efx_nic * efx , unsigned int port_id )
{
MCDI_DECLARE_BUF ( inbuf , MC_CMD_VADAPTOR_ALLOC_IN_LEN ) ;
MCDI_SET_DWORD ( inbuf , VADAPTOR_ALLOC_IN_UPSTREAM_PORT_ID , port_id ) ;
return efx_mcdi_rpc ( efx , MC_CMD_VADAPTOR_ALLOC , inbuf , sizeof ( inbuf ) ,
NULL , 0 , NULL ) ;
}
static int efx_ef10_vadaptor_free ( struct efx_nic * efx , unsigned int port_id )
{
MCDI_DECLARE_BUF ( inbuf , MC_CMD_VADAPTOR_FREE_IN_LEN ) ;
MCDI_SET_DWORD ( inbuf , VADAPTOR_FREE_IN_UPSTREAM_PORT_ID , port_id ) ;
return efx_mcdi_rpc ( efx , MC_CMD_VADAPTOR_FREE , inbuf , sizeof ( inbuf ) ,
NULL , 0 , NULL ) ;
}
2015-05-06 00:58:31 +01:00
static void efx_ef10_sriov_free_vf_vports ( struct efx_nic * efx )
{
struct efx_ef10_nic_data * nic_data = efx - > nic_data ;
int i ;
if ( ! nic_data - > vf )
return ;
for ( i = 0 ; i < efx - > vf_count ; i + + ) {
struct ef10_vf * vf = nic_data - > vf + i ;
if ( vf - > vport_assigned ) {
efx_ef10_evb_port_assign ( efx , EVB_PORT_ID_NULL , i ) ;
vf - > vport_assigned = 0 ;
}
if ( ! is_zero_ether_addr ( vf - > mac ) ) {
efx_ef10_vport_del_mac ( efx , vf - > vport_id , vf - > mac ) ;
eth_zero_addr ( vf - > mac ) ;
}
if ( vf - > vport_id ) {
efx_ef10_vport_free ( efx , vf - > vport_id ) ;
vf - > vport_id = 0 ;
}
2015-05-20 11:09:46 +01:00
vf - > efx = NULL ;
2015-05-06 00:58:31 +01:00
}
}
static void efx_ef10_sriov_free_vf_vswitching ( struct efx_nic * efx )
{
struct efx_ef10_nic_data * nic_data = efx - > nic_data ;
efx_ef10_sriov_free_vf_vports ( efx ) ;
kfree ( nic_data - > vf ) ;
nic_data - > vf = NULL ;
}
static int efx_ef10_sriov_assign_vf_vport ( struct efx_nic * efx ,
unsigned int vf_i )
{
struct efx_ef10_nic_data * nic_data = efx - > nic_data ;
struct ef10_vf * vf = nic_data - > vf + vf_i ;
int rc ;
if ( WARN_ON_ONCE ( ! nic_data - > vf ) )
return - EOPNOTSUPP ;
rc = efx_ef10_vport_alloc ( efx , EVB_PORT_ID_ASSIGNED ,
MC_CMD_VPORT_ALLOC_IN_VPORT_TYPE_NORMAL ,
2015-05-20 11:11:54 +01:00
vf - > vlan , & vf - > vport_id ) ;
2015-05-06 00:58:31 +01:00
if ( rc )
return rc ;
rc = efx_ef10_vport_add_mac ( efx , vf - > vport_id , vf - > mac ) ;
if ( rc ) {
eth_zero_addr ( vf - > mac ) ;
return rc ;
}
rc = efx_ef10_evb_port_assign ( efx , vf - > vport_id , vf_i ) ;
if ( rc )
return rc ;
vf - > vport_assigned = 1 ;
return 0 ;
}
static int efx_ef10_sriov_alloc_vf_vswitching ( struct efx_nic * efx )
{
struct efx_ef10_nic_data * nic_data = efx - > nic_data ;
unsigned int i ;
int rc ;
nic_data - > vf = kcalloc ( efx - > vf_count , sizeof ( struct ef10_vf ) ,
GFP_KERNEL ) ;
if ( ! nic_data - > vf )
return - ENOMEM ;
for ( i = 0 ; i < efx - > vf_count ; i + + ) {
random_ether_addr ( nic_data - > vf [ i ] . mac ) ;
2015-05-20 11:09:46 +01:00
nic_data - > vf [ i ] . efx = NULL ;
2015-05-20 11:11:54 +01:00
nic_data - > vf [ i ] . vlan = EFX_EF10_NO_VLAN ;
2015-05-06 00:58:31 +01:00
rc = efx_ef10_sriov_assign_vf_vport ( efx , i ) ;
if ( rc )
goto fail ;
}
return 0 ;
fail :
efx_ef10_sriov_free_vf_vports ( efx ) ;
kfree ( nic_data - > vf ) ;
nic_data - > vf = NULL ;
return rc ;
}
static int efx_ef10_sriov_restore_vf_vswitching ( struct efx_nic * efx )
{
unsigned int i ;
int rc ;
for ( i = 0 ; i < efx - > vf_count ; i + + ) {
rc = efx_ef10_sriov_assign_vf_vport ( efx , i ) ;
if ( rc )
goto fail ;
}
return 0 ;
fail :
efx_ef10_sriov_free_vf_vswitching ( efx ) ;
return rc ;
}
2015-05-06 00:57:34 +01:00
/* On top of the default firmware vswitch setup, create a VEB vswitch and
* expansion vport for use by this function .
*/
2015-05-06 00:58:54 +01:00
int efx_ef10_vswitching_probe_pf ( struct efx_nic * efx )
2015-05-06 00:57:34 +01:00
{
struct efx_ef10_nic_data * nic_data = efx - > nic_data ;
2015-05-06 00:58:31 +01:00
struct net_device * net_dev = efx - > net_dev ;
2015-05-06 00:57:34 +01:00
int rc ;
2015-05-06 00:58:54 +01:00
if ( pci_sriov_get_totalvfs ( efx - > pci_dev ) < = 0 ) {
/* vswitch not needed as we have no VFs */
efx_ef10_vadaptor_alloc ( efx , nic_data - > vport_id ) ;
return 0 ;
}
2015-05-06 00:57:34 +01:00
rc = efx_ef10_vswitch_alloc ( efx , EVB_PORT_ID_ASSIGNED ,
MC_CMD_VSWITCH_ALLOC_IN_VSWITCH_TYPE_VEB ) ;
if ( rc )
goto fail1 ;
rc = efx_ef10_vport_alloc ( efx , EVB_PORT_ID_ASSIGNED ,
MC_CMD_VPORT_ALLOC_IN_VPORT_TYPE_NORMAL ,
2015-05-20 11:11:54 +01:00
EFX_EF10_NO_VLAN , & nic_data - > vport_id ) ;
2015-05-06 00:57:34 +01:00
if ( rc )
goto fail2 ;
2015-05-06 00:58:31 +01:00
rc = efx_ef10_vport_add_mac ( efx , nic_data - > vport_id , net_dev - > dev_addr ) ;
if ( rc )
goto fail3 ;
ether_addr_copy ( nic_data - > vport_mac , net_dev - > dev_addr ) ;
2015-05-06 00:58:54 +01:00
rc = efx_ef10_vadaptor_alloc ( efx , nic_data - > vport_id ) ;
if ( rc )
goto fail4 ;
2015-05-06 00:57:34 +01:00
return 0 ;
2015-05-06 00:58:54 +01:00
fail4 :
efx_ef10_vport_del_mac ( efx , nic_data - > vport_id , nic_data - > vport_mac ) ;
eth_zero_addr ( nic_data - > vport_mac ) ;
2015-05-06 00:58:31 +01:00
fail3 :
efx_ef10_vport_free ( efx , nic_data - > vport_id ) ;
nic_data - > vport_id = EVB_PORT_ID_ASSIGNED ;
2015-05-06 00:57:34 +01:00
fail2 :
efx_ef10_vswitch_free ( efx , EVB_PORT_ID_ASSIGNED ) ;
fail1 :
return rc ;
}
2015-05-06 00:58:54 +01:00
int efx_ef10_vswitching_probe_vf ( struct efx_nic * efx )
{
struct efx_ef10_nic_data * nic_data = efx - > nic_data ;
return efx_ef10_vadaptor_alloc ( efx , nic_data - > vport_id ) ;
}
int efx_ef10_vswitching_restore_pf ( struct efx_nic * efx )
2015-05-06 00:57:34 +01:00
{
struct efx_ef10_nic_data * nic_data = efx - > nic_data ;
int rc ;
if ( ! nic_data - > must_probe_vswitching )
return 0 ;
2015-05-06 00:58:54 +01:00
rc = efx_ef10_vswitching_probe_pf ( efx ) ;
2015-05-06 00:58:31 +01:00
if ( rc )
goto fail ;
rc = efx_ef10_sriov_restore_vf_vswitching ( efx ) ;
if ( rc )
goto fail ;
2015-05-06 00:57:34 +01:00
2015-05-06 00:58:31 +01:00
nic_data - > must_probe_vswitching = false ;
fail :
2015-05-06 00:57:34 +01:00
return rc ;
}
2015-05-06 00:58:54 +01:00
int efx_ef10_vswitching_restore_vf ( struct efx_nic * efx )
{
struct efx_ef10_nic_data * nic_data = efx - > nic_data ;
int rc ;
if ( ! nic_data - > must_probe_vswitching )
return 0 ;
rc = efx_ef10_vadaptor_free ( efx , EVB_PORT_ID_ASSIGNED ) ;
if ( rc )
return rc ;
nic_data - > must_probe_vswitching = false ;
return 0 ;
}
void efx_ef10_vswitching_remove_pf ( struct efx_nic * efx )
2015-05-06 00:57:34 +01:00
{
struct efx_ef10_nic_data * nic_data = efx - > nic_data ;
2015-05-06 00:58:31 +01:00
efx_ef10_sriov_free_vf_vswitching ( efx ) ;
2015-05-06 00:58:54 +01:00
efx_ef10_vadaptor_free ( efx , nic_data - > vport_id ) ;
2015-05-06 00:57:34 +01:00
if ( nic_data - > vport_id = = EVB_PORT_ID_ASSIGNED )
return ; /* No vswitch was ever created */
2015-05-06 00:58:31 +01:00
if ( ! is_zero_ether_addr ( nic_data - > vport_mac ) ) {
efx_ef10_vport_del_mac ( efx , nic_data - > vport_id ,
efx - > net_dev - > dev_addr ) ;
eth_zero_addr ( nic_data - > vport_mac ) ;
}
2015-05-06 00:57:34 +01:00
efx_ef10_vport_free ( efx , nic_data - > vport_id ) ;
nic_data - > vport_id = EVB_PORT_ID_ASSIGNED ;
efx_ef10_vswitch_free ( efx , nic_data - > vport_id ) ;
}
2015-05-06 00:58:31 +01:00
2015-05-06 00:58:54 +01:00
void efx_ef10_vswitching_remove_vf ( struct efx_nic * efx )
{
efx_ef10_vadaptor_free ( efx , EVB_PORT_ID_ASSIGNED ) ;
}
2015-05-06 00:58:31 +01:00
static int efx_ef10_pci_sriov_enable ( struct efx_nic * efx , int num_vfs )
{
int rc = 0 ;
struct pci_dev * dev = efx - > pci_dev ;
efx - > vf_count = num_vfs ;
rc = efx_ef10_sriov_alloc_vf_vswitching ( efx ) ;
if ( rc )
goto fail1 ;
rc = pci_enable_sriov ( dev , num_vfs ) ;
if ( rc )
goto fail2 ;
return 0 ;
fail2 :
efx_ef10_sriov_free_vf_vswitching ( efx ) ;
fail1 :
efx - > vf_count = 0 ;
netif_err ( efx , probe , efx - > net_dev ,
" Failed to enable SRIOV VFs \n " ) ;
return rc ;
}
static int efx_ef10_pci_sriov_disable ( struct efx_nic * efx )
{
struct pci_dev * dev = efx - > pci_dev ;
pci_disable_sriov ( dev ) ;
efx_ef10_sriov_free_vf_vswitching ( efx ) ;
efx - > vf_count = 0 ;
return 0 ;
}
int efx_ef10_sriov_configure ( struct efx_nic * efx , int num_vfs )
{
if ( num_vfs = = 0 )
return efx_ef10_pci_sriov_disable ( efx ) ;
else
return efx_ef10_pci_sriov_enable ( efx , num_vfs ) ;
}
int efx_ef10_sriov_init ( struct efx_nic * efx )
{
return 0 ;
}
void efx_ef10_sriov_fini ( struct efx_nic * efx )
{
struct efx_ef10_nic_data * nic_data = efx - > nic_data ;
int rc ;
if ( ! nic_data - > vf )
return ;
rc = efx_ef10_pci_sriov_disable ( efx ) ;
if ( rc )
netif_dbg ( efx , drv , efx - > net_dev ,
" Disabling SRIOV was not successful rc=%d \n " , rc ) ;
else
netif_dbg ( efx , drv , efx - > net_dev , " SRIOV disabled \n " ) ;
}
2015-05-20 11:11:03 +01:00
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 ;
}
2015-05-20 11:11:18 +01:00
2015-05-20 11:11:54 +01:00
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 ;
}
2015-05-20 11:12:30 +01:00
int efx_ef10_sriov_set_vf_spoofchk ( struct efx_nic * efx , int vf_i ,
bool spoofchk )
{
return spoofchk ? - EOPNOTSUPP : 0 ;
}
2015-05-20 11:12:13 +01:00
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 */
}
2015-05-20 11:11:18 +01:00
int efx_ef10_sriov_get_vf_config ( struct efx_nic * efx , int vf_i ,
struct ifla_vf_info * ivf )
{
2015-05-20 11:12:13 +01:00
MCDI_DECLARE_BUF ( inbuf , MC_CMD_LINK_STATE_MODE_IN_LEN ) ;
MCDI_DECLARE_BUF ( outbuf , MC_CMD_LINK_STATE_MODE_OUT_LEN ) ;
2015-05-20 11:11:18 +01:00
struct efx_ef10_nic_data * nic_data = efx - > nic_data ;
struct ef10_vf * vf ;
2015-05-20 11:12:13 +01:00
size_t outlen ;
int rc ;
2015-05-20 11:11:18 +01:00
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 ) ;
2015-05-20 11:11:54 +01:00
ivf - > vlan = ( vf - > vlan = = EFX_EF10_NO_VLAN ) ? 0 : vf - > vlan ;
2015-05-20 11:11:18 +01:00
ivf - > qos = 0 ;
2015-05-20 11:12:13 +01:00
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 ) ;
2015-05-20 11:11:18 +01:00
return 0 ;
}
2015-06-02 11:38:16 +01:00
int efx_ef10_sriov_get_phys_port_id ( struct efx_nic * efx ,
struct netdev_phys_item_id * ppid )
{
struct efx_ef10_nic_data * nic_data = efx - > nic_data ;
if ( ! is_valid_ether_addr ( nic_data - > port_id ) )
return - EOPNOTSUPP ;
ppid - > id_len = ETH_ALEN ;
memcpy ( ppid - > id , nic_data - > port_id , ppid - > id_len ) ;
return 0 ;
}