From d1708933bb48a3d86be336d6c9603300131ff70f Mon Sep 17 00:00:00 2001 From: Gautam Dawar Date: Mon, 10 Jun 2019 08:38:36 +0100 Subject: [PATCH] net/sfc/base: implement vSwitch create/destroy The vSwitch create API takes an array of num_vports client driver allocated vPort config entries where entry at index 0 contains the PF configuration and rest num_vports-1 entries refer to vPort configuration for VFs 0 to (num_vports-2). The required hierarchy (vswitch/vport/vadaptor) is created within this API. The destroy API tears down this hierarchy and releases memory for the vSwitch object. Signed-off-by: Gautam Dawar Signed-off-by: Andrew Rybchenko --- drivers/net/sfc/base/efx.h | 40 +++++ drivers/net/sfc/base/efx_evb.c | 269 +++++++++++++++++++++++++++++++- drivers/net/sfc/base/efx_impl.h | 16 ++ 3 files changed, 324 insertions(+), 1 deletion(-) diff --git a/drivers/net/sfc/base/efx.h b/drivers/net/sfc/base/efx.h index 664efc854d..492c8c6bf4 100644 --- a/drivers/net/sfc/base/efx.h +++ b/drivers/net/sfc/base/efx.h @@ -1411,6 +1411,9 @@ typedef struct efx_nic_cfg_s { uint32_t enc_assigned_port; } efx_nic_cfg_t; +#define EFX_VPORT_PCI_FUNCTION_IS_PF(configp) \ + ((configp)->evc_function == 0xffff) + #define EFX_PCI_FUNCTION_IS_PF(_encp) ((_encp)->enc_vf == 0xffff) #define EFX_PCI_FUNCTION_IS_VF(_encp) ((_encp)->enc_vf != 0xffff) @@ -3369,6 +3372,31 @@ typedef enum efx_vport_type_e { #define EFX_FILTER_VID_UNSPEC 0xffff #define EFX_DEFAULT_VSWITCH_ID 1 +/* Default VF VLAN ID on creation */ +#define EFX_VF_VID_DEFAULT EFX_FILTER_VID_UNSPEC +#define EFX_VPORT_ID_INVALID 0 + +typedef struct efx_vport_config_s { + /* Either VF index or 0xffff for PF */ + uint16_t evc_function; + /* VLAN ID of the associated function */ + uint16_t evc_vid; + /* vport id shared with client driver */ + efx_vport_id_t evc_vport_id; + /* MAC address of the associated function */ + uint8_t evc_mac_addr[EFX_MAC_ADDR_LEN]; + /* + * vports created with this flag set may only transfer traffic on the + * VLANs permitted by the vport. Also, an attempt to install filter with + * VLAN will be refused unless requesting function has VLAN privilege. + */ + boolean_t evc_vlan_restrict; + /* Whether this function is assigned or not */ + boolean_t evc_vport_assigned; +} efx_vport_config_t; + +typedef struct efx_vswitch_s efx_vswitch_t; + extern __checkReturn efx_rc_t efx_evb_init( __in efx_nic_t *enp); @@ -3377,6 +3405,18 @@ extern void efx_evb_fini( __in efx_nic_t *enp); +extern __checkReturn efx_rc_t +efx_evb_vswitch_create( + __in efx_nic_t *enp, + __in uint32_t num_vports, + __inout_ecount(num_vports) efx_vport_config_t *vport_configp, + __deref_out efx_vswitch_t **evpp); + +extern __checkReturn efx_rc_t +efx_evb_vswitch_destroy( + __in efx_nic_t *enp, + __in efx_vswitch_t *evp); + #endif /* EFSYS_OPT_EVB */ #ifdef __cplusplus diff --git a/drivers/net/sfc/base/efx_evb.c b/drivers/net/sfc/base/efx_evb.c index ff240f942c..27b466f8b5 100644 --- a/drivers/net/sfc/base/efx_evb.c +++ b/drivers/net/sfc/base/efx_evb.c @@ -107,7 +107,7 @@ fail1: return (rc); } - void + void efx_evb_fini( __in efx_nic_t *enp) { @@ -125,4 +125,271 @@ efx_evb_fini( enp->en_mod_flags &= ~EFX_MOD_EVB; } +/* + * efx_is_zero_eth_addr returns TRUE if the passed MAC address has all bytes + * equal to zero. A vport is assigned a MAC address after creation and this + * function checks if that has happened. It is called in the clean-up function + * before calling eeo_vport_mac_addr_del to ensure that the vport actually had + * an allocated MAC address. + */ + +__checkReturn boolean_t +efx_is_zero_eth_addr( + __in_bcount(EFX_MAC_ADDR_LEN) const uint8_t *addrp) +{ + return (!(addrp[0] | addrp[1] | addrp[2] | + addrp[3] | addrp[4] | addrp[5])); +} + +static void +efx_evb_free_vport( + __in efx_nic_t *enp, + __in efx_vswitch_id_t vswitch_id, + __inout efx_vport_config_t *configp) +{ + const efx_evb_ops_t *eeop = enp->en_eeop; + + /* If any callback fails, continue clean-up with others functions */ + if (EFX_VPORT_PCI_FUNCTION_IS_PF(configp)) { + /* free vadaptor */ + if ((configp->evc_vport_id != EFX_VPORT_ID_INVALID) && + (eeop->eeo_vadaptor_free(enp, vswitch_id, + configp->evc_vport_id) != 0)) { + EFSYS_PROBE2(eeo_vadaptor_free, + uint16_t, configp->evc_function, + uint32_t, configp->evc_vport_id); + } + } else { + if (configp->evc_vport_assigned == B_TRUE) { + if (eeop->eeo_vport_assign(enp, vswitch_id, + EVB_PORT_ID_NULL, + configp->evc_function) != 0) { + EFSYS_PROBE1(eeo_vport_assign, + uint16_t, configp->evc_function); + } + configp->evc_vport_assigned = B_FALSE; + } + } + + /* + * Call eeo_vport_mac_addr_del after checking that this vport is + * actually allocated a MAC address in call to efx_evb_configure_vport + */ + if (!efx_is_zero_eth_addr(configp->evc_mac_addr)) { + if (eeop->eeo_vport_mac_addr_del(enp, vswitch_id, + configp->evc_vport_id, + configp->evc_mac_addr) != 0) { + EFSYS_PROBE1(eeo_vport_mac_addr_del, + uint16_t, configp->evc_function); + } + memset(configp->evc_mac_addr, 0x00, EFX_MAC_ADDR_LEN); + } + + if (configp->evc_vport_id != EFX_VPORT_ID_INVALID) { + if (eeop->eeo_vport_free(enp, vswitch_id, + configp->evc_vport_id) != 0) { + EFSYS_PROBE1(eeo_vport_free, + uint16_t, configp->evc_function); + } + configp->evc_vport_id = EFX_VPORT_ID_INVALID; + } +} + +static void +efx_evb_free_vports( + __in efx_nic_t *enp, + __in efx_vswitch_id_t vswitch_id, + __in uint32_t num_vports, + __inout_ecount(num_vports) efx_vport_config_t *vport_configp) +{ + efx_vport_config_t *configp; + uint32_t i; + + if (vport_configp == NULL) { + EFSYS_PROBE(null_vport_config); + return; + } + + for (i = 0; i < num_vports; i++) { + configp = vport_configp + i; + efx_evb_free_vport(enp, vswitch_id, configp); + } +} + +static __checkReturn efx_rc_t +efx_evb_configure_vport( + __in efx_nic_t *enp, + __in efx_vswitch_id_t vswitch_id, + __in const efx_evb_ops_t *eeop, + __inout efx_vport_config_t *configp) +{ + efx_rc_t rc; + efx_vport_id_t vport_id; + + if ((rc = eeop->eeo_vport_alloc(enp, vswitch_id, + EFX_VPORT_TYPE_NORMAL, configp->evc_vid, + configp->evc_vlan_restrict, &vport_id)) != 0) + goto fail1; + + configp->evc_vport_id = vport_id; + + if ((rc = eeop->eeo_vport_mac_addr_add(enp, vswitch_id, + configp->evc_vport_id, + configp->evc_mac_addr)) != 0) + goto fail2; + + if (EFX_VPORT_PCI_FUNCTION_IS_PF(configp)) { + if ((rc = eeop->eeo_vadaptor_alloc(enp, vswitch_id, + configp->evc_vport_id)) != 0) + goto fail3; + } else { + if ((rc = eeop->eeo_vport_assign(enp, vswitch_id, + configp->evc_vport_id, + configp->evc_function)) != 0) + goto fail4; + configp->evc_vport_assigned = B_TRUE; + } + + return (0); + +fail4: + EFSYS_PROBE(fail4); +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +efx_evb_vswitch_create( + __in efx_nic_t *enp, + __in uint32_t num_vports, + __inout_ecount(num_vports) efx_vport_config_t *vport_configp, + __deref_out efx_vswitch_t **evpp) +{ + efx_vswitch_t *evp; + efx_rc_t rc; + efx_vswitch_id_t vswitch_id; + efx_vport_config_t *configp; + const efx_evb_ops_t *eeop = enp->en_eeop; + uint32_t i; + + /* vport_configp is a caller allocated array filled in with vports + * configuration. Index 0 carries the PF vport configuration and next + * num_vports - 1 indices carry VFs configuration. + */ + EFSYS_ASSERT((num_vports != 0) && (vport_configp != NULL) && + (evpp != NULL)); + EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_EVB); + EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC)); + + if ((eeop->eeo_vswitch_alloc == NULL) || + (eeop->eeo_vport_alloc == NULL) || + (eeop->eeo_vport_free == NULL) || + (eeop->eeo_vport_mac_addr_add == NULL) || + (eeop->eeo_vport_mac_addr_del == NULL) || + (eeop->eeo_vadaptor_alloc == NULL) || + (eeop->eeo_vadaptor_free == NULL) || + (eeop->eeo_vport_assign == NULL) || + (eeop->eeo_vswitch_free == NULL)) { + rc = ENOTSUP; + goto fail1; + } + + /* Allocate a vSwitch object */ + EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (efx_vswitch_t), evp); + + if (evp == NULL) { + rc = ENOMEM; + goto fail2; + } + + if ((rc = eeop->eeo_vswitch_alloc(enp, &vswitch_id)) != 0) + goto fail3; + + evp->ev_enp = enp; + evp->ev_num_vports = num_vports; + evp->ev_evcp = vport_configp; + evp->ev_vswitch_id = vswitch_id; + + for (i = 0; i < num_vports; i++) { + configp = vport_configp + i; + + if ((rc = efx_evb_configure_vport(enp, vswitch_id, eeop, + configp)) != 0) + goto fail4; + } + + enp->en_vswitchp = evp; + *evpp = evp; + return (0); + +fail4: + EFSYS_PROBE(fail4); + efx_evb_free_vports(enp, vswitch_id, i + 1, vport_configp); + /* Free the vSwitch */ + eeop->eeo_vswitch_free(enp, vswitch_id); + +fail3: + EFSYS_PROBE(fail3); + /* Free the vSwitch object */ + EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_vswitch_t), evp); + +fail2: + EFSYS_PROBE(fail2); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + + __checkReturn efx_rc_t +efx_evb_vswitch_destroy( + __in efx_nic_t *enp, + __in efx_vswitch_t *evp) +{ + const efx_evb_ops_t *eeop = enp->en_eeop; + efx_vswitch_id_t vswitch_id; + efx_rc_t rc; + + EFSYS_ASSERT(evp != NULL); + EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_EVB); + + if ((eeop->eeo_vport_mac_addr_del == NULL) || + (eeop->eeo_vadaptor_free == NULL) || + (eeop->eeo_vport_assign == NULL) || + (eeop->eeo_vport_free == NULL) || + (eeop->eeo_vswitch_free == NULL)) { + rc = ENOTSUP; + goto fail1; + } + + vswitch_id = evp->ev_vswitch_id; + efx_evb_free_vports(enp, vswitch_id, + evp->ev_num_vports, evp->ev_evcp); + + /* Free the vSwitch object */ + EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_vswitch_t), evp); + enp->en_vswitchp = NULL; + + /* Free the vSwitch */ + if ((rc = eeop->eeo_vswitch_free(enp, vswitch_id)) != 0) + goto fail2; + + return (0); + +fail2: + EFSYS_PROBE(fail2); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + return (rc); +} + #endif diff --git a/drivers/net/sfc/base/efx_impl.h b/drivers/net/sfc/base/efx_impl.h index ef6a97a690..46d5389dd4 100644 --- a/drivers/net/sfc/base/efx_impl.h +++ b/drivers/net/sfc/base/efx_impl.h @@ -652,6 +652,17 @@ typedef struct efx_lic_ops_s { #if EFSYS_OPT_EVB +struct efx_vswitch_s { + efx_nic_t *ev_enp; + efx_vswitch_id_t ev_vswitch_id; + uint32_t ev_num_vports; + /* + * Vport configuration array: index 0 to store PF configuration + * and next ev_num_vports-1 entries hold VFs configuration. + */ + efx_vport_config_t *ev_evcp; +}; + typedef struct efx_evb_ops_s { efx_rc_t (*eeo_init)(efx_nic_t *); void (*eeo_fini)(efx_nic_t *); @@ -674,6 +685,10 @@ typedef struct efx_evb_ops_s { efx_vport_id_t, uint32_t); } efx_evb_ops_t; +extern __checkReturn boolean_t +efx_is_zero_eth_addr( + __in_bcount(EFX_MAC_ADDR_LEN) const uint8_t *addrp); + #endif /* EFSYS_OPT_EVB */ #define EFX_DRV_VER_MAX 20 @@ -776,6 +791,7 @@ struct efx_nic_s { #endif /* EFX_OPTS_EF10() */ #if EFSYS_OPT_EVB const efx_evb_ops_t *en_eeop; + struct efx_vswitch_s *en_vswitchp; #endif /* EFSYS_OPT_EVB */ }; -- 2.20.1