net/sfc/base: implement vSwitch create/destroy
[dpdk.git] / drivers / net / sfc / base / efx_evb.c
index ff240f9..27b466f 100644 (file)
@@ -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