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)
#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);
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
return (rc);
}
- void
+ void
efx_evb_fini(
__in efx_nic_t *enp)
{
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