OSDN Git Service

ice: Add handlers for VF netdevice operations
authorAnirudh Venkataramanan <anirudh.venkataramanan@intel.com>
Thu, 20 Sep 2018 00:42:58 +0000 (17:42 -0700)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Wed, 3 Oct 2018 14:42:30 +0000 (07:42 -0700)
This patch implements handlers for the following NDO operations:

.ndo_set_vf_spoofchk
.ndo_set_vf_mac
.ndo_get_vf_config
.ndo_set_vf_trust
.ndo_set_vf_vlan
.ndo_set_vf_link_state

Signed-off-by: Anirudh Venkataramanan <anirudh.venkataramanan@intel.com>
Tested-by: Andrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h
drivers/net/ethernet/intel/ice/ice_main.c
drivers/net/ethernet/intel/ice/ice_sriov.c
drivers/net/ethernet/intel/ice/ice_sriov.h
drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c
drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h

index f5269f7..7d2a667 100644 (file)
@@ -474,4 +474,16 @@ static inline struct ice_rx_ptype_decoded ice_decode_rx_desc_ptype(u16 ptype)
 {
        return ice_ptype_lkup[ptype];
 }
+
+#define ICE_LINK_SPEED_UNKNOWN         0
+#define ICE_LINK_SPEED_10MBPS          10
+#define ICE_LINK_SPEED_100MBPS         100
+#define ICE_LINK_SPEED_1000MBPS                1000
+#define ICE_LINK_SPEED_2500MBPS                2500
+#define ICE_LINK_SPEED_5000MBPS                5000
+#define ICE_LINK_SPEED_10000MBPS       10000
+#define ICE_LINK_SPEED_20000MBPS       20000
+#define ICE_LINK_SPEED_25000MBPS       25000
+#define ICE_LINK_SPEED_40000MBPS       40000
+
 #endif /* _ICE_LAN_TX_RX_H_ */
index f1a116c..01112ae 100644 (file)
@@ -3884,6 +3884,12 @@ static const struct net_device_ops ice_netdev_ops = {
        .ndo_validate_addr = eth_validate_addr,
        .ndo_change_mtu = ice_change_mtu,
        .ndo_get_stats64 = ice_get_stats64,
+       .ndo_set_vf_spoofchk = ice_set_vf_spoofchk,
+       .ndo_set_vf_mac = ice_set_vf_mac,
+       .ndo_get_vf_config = ice_get_vf_cfg,
+       .ndo_set_vf_trust = ice_set_vf_trust,
+       .ndo_set_vf_vlan = ice_set_vf_port_vlan,
+       .ndo_set_vf_link_state = ice_set_vf_link_state,
        .ndo_vlan_rx_add_vid = ice_vlan_rx_add_vid,
        .ndo_vlan_rx_kill_vid = ice_vlan_rx_kill_vid,
        .ndo_set_features = ice_set_features,
index 191e832..027eba4 100644 (file)
@@ -39,3 +39,89 @@ ice_aq_send_msg_to_vf(struct ice_hw *hw, u16 vfid, u32 v_opcode, u32 v_retval,
 
        return ice_sq_send_cmd(hw, &hw->mailboxq, &desc, msg, msglen, cd);
 }
+
+/**
+ * ice_conv_link_speed_to_virtchnl
+ * @adv_link_support: determines the format of the returned link speed
+ * @link_speed: variable containing the link_speed to be converted
+ *
+ * Convert link speed supported by HW to link speed supported by virtchnl.
+ * If adv_link_support is true, then return link speed in Mbps.  Else return
+ * link speed as a VIRTCHNL_LINK_SPEED_* casted to a u32. Note that the caller
+ * needs to cast back to an enum virtchnl_link_speed in the case where
+ * adv_link_support is false, but when adv_link_support is true the caller can
+ * expect the speed in Mbps.
+ */
+u32 ice_conv_link_speed_to_virtchnl(bool adv_link_support, u16 link_speed)
+{
+       u32 speed;
+
+       if (adv_link_support)
+               switch (link_speed) {
+               case ICE_AQ_LINK_SPEED_10MB:
+                       speed = ICE_LINK_SPEED_10MBPS;
+                       break;
+               case ICE_AQ_LINK_SPEED_100MB:
+                       speed = ICE_LINK_SPEED_100MBPS;
+                       break;
+               case ICE_AQ_LINK_SPEED_1000MB:
+                       speed = ICE_LINK_SPEED_1000MBPS;
+                       break;
+               case ICE_AQ_LINK_SPEED_2500MB:
+                       speed = ICE_LINK_SPEED_2500MBPS;
+                       break;
+               case ICE_AQ_LINK_SPEED_5GB:
+                       speed = ICE_LINK_SPEED_5000MBPS;
+                       break;
+               case ICE_AQ_LINK_SPEED_10GB:
+                       speed = ICE_LINK_SPEED_10000MBPS;
+                       break;
+               case ICE_AQ_LINK_SPEED_20GB:
+                       speed = ICE_LINK_SPEED_20000MBPS;
+                       break;
+               case ICE_AQ_LINK_SPEED_25GB:
+                       speed = ICE_LINK_SPEED_25000MBPS;
+                       break;
+               case ICE_AQ_LINK_SPEED_40GB:
+                       speed = ICE_LINK_SPEED_40000MBPS;
+                       break;
+               default:
+                       speed = ICE_LINK_SPEED_UNKNOWN;
+                       break;
+               }
+       else
+               /* Virtchnl speeds are not defined for every speed supported in
+                * the hardware. To maintain compatibility with older AVF
+                * drivers, while reporting the speed the new speed values are
+                * resolved to the closest known virtchnl speeds
+                */
+               switch (link_speed) {
+               case ICE_AQ_LINK_SPEED_10MB:
+               case ICE_AQ_LINK_SPEED_100MB:
+                       speed = (u32)VIRTCHNL_LINK_SPEED_100MB;
+                       break;
+               case ICE_AQ_LINK_SPEED_1000MB:
+               case ICE_AQ_LINK_SPEED_2500MB:
+               case ICE_AQ_LINK_SPEED_5GB:
+                       speed = (u32)VIRTCHNL_LINK_SPEED_1GB;
+                       break;
+               case ICE_AQ_LINK_SPEED_10GB:
+                       speed = (u32)VIRTCHNL_LINK_SPEED_10GB;
+                       break;
+               case ICE_AQ_LINK_SPEED_20GB:
+                       speed = (u32)VIRTCHNL_LINK_SPEED_20GB;
+                       break;
+               case ICE_AQ_LINK_SPEED_25GB:
+                       speed = (u32)VIRTCHNL_LINK_SPEED_25GB;
+                       break;
+               case ICE_AQ_LINK_SPEED_40GB:
+                       /* fall through */
+                       speed = (u32)VIRTCHNL_LINK_SPEED_40GB;
+                       break;
+               default:
+                       speed = (u32)VIRTCHNL_LINK_SPEED_UNKNOWN;
+                       break;
+               }
+
+       return speed;
+}
index f9b86fd..3d78a07 100644 (file)
@@ -11,6 +11,7 @@ enum ice_status
 ice_aq_send_msg_to_vf(struct ice_hw *hw, u16 vfid, u32 v_opcode, u32 v_retval,
                      u8 *msg, u16 msglen, struct ice_sq_cd *cd);
 
+u32 ice_conv_link_speed_to_virtchnl(bool adv_link_support, u16 link_speed);
 #else /* CONFIG_PCI_IOV */
 static inline enum ice_status
 ice_aq_send_msg_to_vf(struct ice_hw __always_unused *hw,
@@ -21,5 +22,13 @@ ice_aq_send_msg_to_vf(struct ice_hw __always_unused *hw,
 {
        return 0;
 }
+
+static inline u32
+ice_conv_link_speed_to_virtchnl(bool __always_unused adv_link_support,
+                               u16 __always_unused link_speed)
+{
+       return 0;
+}
+
 #endif /* CONFIG_PCI_IOV */
 #endif /* _ICE_SRIOV_H_ */
index 6653c17..cf4517f 100644 (file)
@@ -35,6 +35,51 @@ ice_vc_vf_broadcast(struct ice_pf *pf, enum virtchnl_ops v_opcode,
 }
 
 /**
+ * ice_set_pfe_link - Set the link speed/status of the virtchnl_pf_event
+ * @vf: pointer to the VF structure
+ * @pfe: pointer to the virtchnl_pf_event to set link speed/status for
+ * @ice_link_speed: link speed specified by ICE_AQ_LINK_SPEED_*
+ * @link_up: whether or not to set the link up/down
+ */
+static void
+ice_set_pfe_link(struct ice_vf *vf, struct virtchnl_pf_event *pfe,
+                int ice_link_speed, bool link_up)
+{
+       if (vf->driver_caps & VIRTCHNL_VF_CAP_ADV_LINK_SPEED) {
+               pfe->event_data.link_event_adv.link_status = link_up;
+               /* Speed in Mbps */
+               pfe->event_data.link_event_adv.link_speed =
+                       ice_conv_link_speed_to_virtchnl(true, ice_link_speed);
+       } else {
+               pfe->event_data.link_event.link_status = link_up;
+               /* Legacy method for virtchnl link speeds */
+               pfe->event_data.link_event.link_speed =
+                       (enum virtchnl_link_speed)
+                       ice_conv_link_speed_to_virtchnl(false, ice_link_speed);
+       }
+}
+
+/**
+ * ice_set_pfe_link_forced - Force the virtchnl_pf_event link speed/status
+ * @vf: pointer to the VF structure
+ * @pfe: pointer to the virtchnl_pf_event to set link speed/status for
+ * @link_up: whether or not to set the link up/down
+ */
+static void
+ice_set_pfe_link_forced(struct ice_vf *vf, struct virtchnl_pf_event *pfe,
+                       bool link_up)
+{
+       u16 link_speed;
+
+       if (link_up)
+               link_speed = ICE_AQ_LINK_SPEED_40GB;
+       else
+               link_speed = ICE_AQ_LINK_SPEED_UNKNOWN;
+
+       ice_set_pfe_link(vf, pfe, link_speed, link_up);
+}
+
+/**
  * ice_get_vf_vector - get VF interrupt vector register offset
  * @vf_msix: number of MSIx vector per VF on a PF
  * @vf_id: VF identifier
@@ -292,6 +337,24 @@ static int ice_vsi_set_pvid(struct ice_vsi *vsi, u16 vid)
 }
 
 /**
+ * ice_vsi_kill_pvid - Remove port VLAN id from the VSI
+ * @vsi: the VSI being changed
+ */
+static int ice_vsi_kill_pvid(struct ice_vsi *vsi)
+{
+       struct ice_pf *pf = vsi->back;
+
+       if (ice_vsi_manage_vlan_stripping(vsi, false)) {
+               dev_err(&pf->pdev->dev, "Error removing Port VLAN on VSI %i\n",
+                       vsi->vsi_num);
+               return -ENODEV;
+       }
+
+       vsi->info.pvid = 0;
+       return 0;
+}
+
+/**
  * ice_vf_vsi_setup - Set up a VF VSI
  * @pf: board private structure
  * @pi: pointer to the port_info instance
@@ -815,6 +878,29 @@ void ice_vc_notify_reset(struct ice_pf *pf)
 }
 
 /**
+ * ice_vc_notify_vf_reset - Notify VF of a reset event
+ * @vf: pointer to the VF structure
+ */
+static void ice_vc_notify_vf_reset(struct ice_vf *vf)
+{
+       struct virtchnl_pf_event pfe;
+
+       /* validate the request */
+       if (!vf || vf->vf_id >= vf->pf->num_alloc_vfs)
+               return;
+
+       /* verify if the VF is in either init or active before proceeding */
+       if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states) &&
+           !test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states))
+               return;
+
+       pfe.event = VIRTCHNL_EVENT_RESET_IMPENDING;
+       pfe.severity = PF_EVENT_SEVERITY_CERTAIN_DOOM;
+       ice_aq_send_msg_to_vf(&vf->pf->hw, vf->vf_id, VIRTCHNL_OP_EVENT, 0,
+                             (u8 *)&pfe, sizeof(pfe), NULL);
+}
+
+/**
  * ice_alloc_vfs - Allocate and set up VFs resources
  * @pf: pointer to the PF structure
  * @num_alloc_vfs: number of VFs to allocate
@@ -1008,3 +1094,355 @@ void ice_process_vflr_event(struct ice_pf *pf)
                        ice_reset_vf(vf, true);
        }
 }
+
+/**
+ * ice_vc_dis_vf - Disable a given VF via SW reset
+ * @vf: pointer to the VF info
+ *
+ * Disable the VF through a SW reset
+ */
+static void ice_vc_dis_vf(struct ice_vf *vf)
+{
+       ice_vc_notify_vf_reset(vf);
+       ice_reset_vf(vf, false);
+}
+
+/**
+ * ice_set_vf_port_vlan
+ * @netdev: network interface device structure
+ * @vf_id: VF identifier
+ * @vlan_id: VLAN id being set
+ * @qos: priority setting
+ * @vlan_proto: VLAN protocol
+ *
+ * program VF Port VLAN id and/or qos
+ */
+int
+ice_set_vf_port_vlan(struct net_device *netdev, int vf_id, u16 vlan_id, u8 qos,
+                    __be16 vlan_proto)
+{
+       u16 vlanprio = vlan_id | (qos << ICE_VLAN_PRIORITY_S);
+       struct ice_netdev_priv *np = netdev_priv(netdev);
+       struct ice_pf *pf = np->vsi->back;
+       struct ice_vsi *vsi;
+       struct ice_vf *vf;
+       int ret = 0;
+
+       /* validate the request */
+       if (vf_id >= pf->num_alloc_vfs) {
+               dev_err(&pf->pdev->dev, "invalid VF id: %d\n", vf_id);
+               return -EINVAL;
+       }
+
+       if (vlan_id > ICE_MAX_VLANID || qos > 7) {
+               dev_err(&pf->pdev->dev, "Invalid VF Parameters\n");
+               return -EINVAL;
+       }
+
+       if (vlan_proto != htons(ETH_P_8021Q)) {
+               dev_err(&pf->pdev->dev, "VF VLAN protocol is not supported\n");
+               return -EPROTONOSUPPORT;
+       }
+
+       vf = &pf->vf[vf_id];
+       vsi = pf->vsi[vf->lan_vsi_idx];
+       if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states)) {
+               dev_err(&pf->pdev->dev, "VF %d in reset. Try again.\n", vf_id);
+               return -EBUSY;
+       }
+
+       if (le16_to_cpu(vsi->info.pvid) == vlanprio) {
+               /* duplicate request, so just return success */
+               dev_info(&pf->pdev->dev,
+                        "Duplicate pvid %d request\n", vlanprio);
+               return ret;
+       }
+
+       /* If pvid, then remove all filters on the old VLAN */
+       if (vsi->info.pvid)
+               ice_vsi_kill_vlan(vsi, (le16_to_cpu(vsi->info.pvid) &
+                                 VLAN_VID_MASK));
+
+       if (vlan_id || qos) {
+               ret = ice_vsi_set_pvid(vsi, vlanprio);
+               if (ret)
+                       goto error_set_pvid;
+       } else {
+               ice_vsi_kill_pvid(vsi);
+       }
+
+       if (vlan_id) {
+               dev_info(&pf->pdev->dev, "Setting VLAN %d, QOS 0x%x on VF %d\n",
+                        vlan_id, qos, vf_id);
+
+               /* add new VLAN filter for each MAC */
+               ret = ice_vsi_add_vlan(vsi, vlan_id);
+               if (ret)
+                       goto error_set_pvid;
+       }
+
+       /* The Port VLAN needs to be saved across resets the same as the
+        * default LAN MAC address.
+        */
+       vf->port_vlan_id = le16_to_cpu(vsi->info.pvid);
+
+error_set_pvid:
+       return ret;
+}
+
+/**
+ * ice_get_vf_cfg
+ * @netdev: network interface device structure
+ * @vf_id: VF identifier
+ * @ivi: VF configuration structure
+ *
+ * return VF configuration
+ */
+int ice_get_vf_cfg(struct net_device *netdev, int vf_id,
+                  struct ifla_vf_info *ivi)
+{
+       struct ice_netdev_priv *np = netdev_priv(netdev);
+       struct ice_vsi *vsi = np->vsi;
+       struct ice_pf *pf = vsi->back;
+       struct ice_vf *vf;
+
+       /* validate the request */
+       if (vf_id >= pf->num_alloc_vfs) {
+               netdev_err(netdev, "invalid VF id: %d\n", vf_id);
+               return -EINVAL;
+       }
+
+       vf = &pf->vf[vf_id];
+       vsi = pf->vsi[vf->lan_vsi_idx];
+
+       if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states)) {
+               netdev_err(netdev, "VF %d in reset. Try again.\n", vf_id);
+               return -EBUSY;
+       }
+
+       ivi->vf = vf_id;
+       ether_addr_copy(ivi->mac, vf->dflt_lan_addr.addr);
+
+       /* VF configuration for VLAN and applicable QoS */
+       ivi->vlan = le16_to_cpu(vsi->info.pvid) & ICE_VLAN_M;
+       ivi->qos = (le16_to_cpu(vsi->info.pvid) & ICE_PRIORITY_M) >>
+                   ICE_VLAN_PRIORITY_S;
+
+       ivi->trusted = vf->trusted;
+       ivi->spoofchk = vf->spoofchk;
+       if (!vf->link_forced)
+               ivi->linkstate = IFLA_VF_LINK_STATE_AUTO;
+       else if (vf->link_up)
+               ivi->linkstate = IFLA_VF_LINK_STATE_ENABLE;
+       else
+               ivi->linkstate = IFLA_VF_LINK_STATE_DISABLE;
+       ivi->max_tx_rate = vf->tx_rate;
+       ivi->min_tx_rate = 0;
+       return 0;
+}
+
+/**
+ * ice_set_vf_spoofchk
+ * @netdev: network interface device structure
+ * @vf_id: VF identifier
+ * @ena: flag to enable or disable feature
+ *
+ * Enable or disable VF spoof checking
+ */
+int ice_set_vf_spoofchk(struct net_device *netdev, int vf_id, bool ena)
+{
+       struct ice_netdev_priv *np = netdev_priv(netdev);
+       struct ice_vsi_ctx ctx = { 0 };
+       struct ice_vsi *vsi = np->vsi;
+       struct ice_pf *pf = vsi->back;
+       struct ice_vf *vf;
+       int status;
+
+       /* validate the request */
+       if (vf_id >= pf->num_alloc_vfs) {
+               netdev_err(netdev, "invalid VF id: %d\n", vf_id);
+               return -EINVAL;
+       }
+
+       vf = &pf->vf[vf_id];
+       if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states)) {
+               netdev_err(netdev, "VF %d in reset. Try again.\n", vf_id);
+               return -EBUSY;
+       }
+
+       if (ena == vf->spoofchk) {
+               dev_dbg(&pf->pdev->dev, "VF spoofchk already %s\n",
+                       ena ? "ON" : "OFF");
+               return 0;
+       }
+
+       ctx.info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_SECURITY_VALID);
+
+       if (ena) {
+               ctx.info.sec_flags |= ICE_AQ_VSI_SEC_FLAG_ENA_MAC_ANTI_SPOOF;
+               ctx.info.sw_flags2 |= ICE_AQ_VSI_SW_FLAG_RX_PRUNE_EN_M;
+       }
+
+       status = ice_update_vsi(&pf->hw, vsi->idx, &ctx, NULL);
+       if (status) {
+               dev_dbg(&pf->pdev->dev,
+                       "Error %d, failed to update VSI* parameters\n", status);
+               return -EIO;
+       }
+
+       vf->spoofchk = ena;
+       vsi->info.sec_flags = ctx.info.sec_flags;
+       vsi->info.sw_flags2 = ctx.info.sw_flags2;
+
+       return status;
+}
+
+/**
+ * ice_set_vf_mac
+ * @netdev: network interface device structure
+ * @vf_id: VF identifier
+ * @mac: mac address
+ *
+ * program VF mac address
+ */
+int ice_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
+{
+       struct ice_netdev_priv *np = netdev_priv(netdev);
+       struct ice_vsi *vsi = np->vsi;
+       struct ice_pf *pf = vsi->back;
+       struct ice_vf *vf;
+       int ret = 0;
+
+       /* validate the request */
+       if (vf_id >= pf->num_alloc_vfs) {
+               netdev_err(netdev, "invalid VF id: %d\n", vf_id);
+               return -EINVAL;
+       }
+
+       vf = &pf->vf[vf_id];
+       if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states)) {
+               netdev_err(netdev, "VF %d in reset. Try again.\n", vf_id);
+               return -EBUSY;
+       }
+
+       if (is_zero_ether_addr(mac) || is_multicast_ether_addr(mac)) {
+               netdev_err(netdev, "%pM not a valid unicast address\n", mac);
+               return -EINVAL;
+       }
+
+       /* copy mac into dflt_lan_addr and trigger a VF reset. The reset
+        * flow will use the updated dflt_lan_addr and add a MAC filter
+        * using ice_add_mac. Also set pf_set_mac to indicate that the PF has
+        * set the MAC address for this VF.
+        */
+       ether_addr_copy(vf->dflt_lan_addr.addr, mac);
+       vf->pf_set_mac = true;
+       netdev_info(netdev,
+                   "mac on VF %d set to %pM\n. VF driver will be reinitialized\n",
+                   vf_id, mac);
+
+       ice_vc_dis_vf(vf);
+       return ret;
+}
+
+/**
+ * ice_set_vf_trust
+ * @netdev: network interface device structure
+ * @vf_id: VF identifier
+ * @trusted: Boolean value to enable/disable trusted VF
+ *
+ * Enable or disable a given VF as trusted
+ */
+int ice_set_vf_trust(struct net_device *netdev, int vf_id, bool trusted)
+{
+       struct ice_netdev_priv *np = netdev_priv(netdev);
+       struct ice_vsi *vsi = np->vsi;
+       struct ice_pf *pf = vsi->back;
+       struct ice_vf *vf;
+
+       /* validate the request */
+       if (vf_id >= pf->num_alloc_vfs) {
+               dev_err(&pf->pdev->dev, "invalid VF id: %d\n", vf_id);
+               return -EINVAL;
+       }
+
+       vf = &pf->vf[vf_id];
+       if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states)) {
+               dev_err(&pf->pdev->dev, "VF %d in reset. Try again.\n", vf_id);
+               return -EBUSY;
+       }
+
+       /* Check if already trusted */
+       if (trusted == vf->trusted)
+               return 0;
+
+       vf->trusted = trusted;
+       ice_vc_dis_vf(vf);
+       dev_info(&pf->pdev->dev, "VF %u is now %strusted\n",
+                vf_id, trusted ? "" : "un");
+
+       return 0;
+}
+
+/**
+ * ice_set_vf_link_state
+ * @netdev: network interface device structure
+ * @vf_id: VF identifier
+ * @link_state: required link state
+ *
+ * Set VF's link state, irrespective of physical link state status
+ */
+int ice_set_vf_link_state(struct net_device *netdev, int vf_id, int link_state)
+{
+       struct ice_netdev_priv *np = netdev_priv(netdev);
+       struct ice_pf *pf = np->vsi->back;
+       struct virtchnl_pf_event pfe = { 0 };
+       struct ice_link_status *ls;
+       struct ice_vf *vf;
+       struct ice_hw *hw;
+
+       if (vf_id >= pf->num_alloc_vfs) {
+               dev_err(&pf->pdev->dev, "Invalid VF Identifier %d\n", vf_id);
+               return -EINVAL;
+       }
+
+       vf = &pf->vf[vf_id];
+       hw = &pf->hw;
+       ls = &pf->hw.port_info->phy.link_info;
+
+       if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states)) {
+               dev_err(&pf->pdev->dev, "vf %d in reset. Try again.\n", vf_id);
+               return -EBUSY;
+       }
+
+       pfe.event = VIRTCHNL_EVENT_LINK_CHANGE;
+       pfe.severity = PF_EVENT_SEVERITY_INFO;
+
+       switch (link_state) {
+       case IFLA_VF_LINK_STATE_AUTO:
+               vf->link_forced = false;
+               vf->link_up = ls->link_info & ICE_AQ_LINK_UP;
+               break;
+       case IFLA_VF_LINK_STATE_ENABLE:
+               vf->link_forced = true;
+               vf->link_up = true;
+               break;
+       case IFLA_VF_LINK_STATE_DISABLE:
+               vf->link_forced = true;
+               vf->link_up = false;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (vf->link_forced)
+               ice_set_pfe_link_forced(vf, &pfe, vf->link_up);
+       else
+               ice_set_pfe_link(vf, &pfe, ls->link_speed, vf->link_up);
+
+       /* Notify the VF of its new link state */
+       ice_aq_send_msg_to_vf(hw, vf->vf_id, VIRTCHNL_OP_EVENT, 0, (u8 *)&pfe,
+                             sizeof(pfe), NULL);
+
+       return 0;
+}
index 0043061..c4597ab 100644 (file)
@@ -5,6 +5,11 @@
 #define _ICE_VIRTCHNL_PF_H_
 #include "ice.h"
 
+#define ICE_MAX_VLANID                 4095
+#define ICE_VLAN_PRIORITY_S            12
+#define ICE_VLAN_M                     0xFFF
+#define ICE_PRIORITY_M                 0x7000
+
 /* Static VF transaction/status register def */
 #define VF_DEVICE_STATUS               0xAA
 #define VF_TRANS_PENDING_M             0x20
@@ -36,15 +41,20 @@ struct ice_vf {
        struct ice_pf *pf;
 
        s16 vf_id;                      /* VF id in the PF space */
+       u32 driver_caps;                /* reported by VF driver */
        int first_vector_idx;           /* first vector index of this VF */
        struct ice_sw *vf_sw_id;        /* switch id the VF VSIs connect to */
        struct virtchnl_ether_addr dflt_lan_addr;
        u16 port_vlan_id;
+       u8 pf_set_mac;                  /* VF MAC address set by VMM admin */
        u8 trusted;
        u16 lan_vsi_idx;                /* index into PF struct */
        u16 lan_vsi_num;                /* ID as used by firmware */
        unsigned long vf_caps;          /* vf's adv. capabilities */
        DECLARE_BITMAP(vf_states, ICE_VF_STATES_NBITS); /* VF runtime states */
+       unsigned int tx_rate;           /* Tx bandwidth limit in Mbps */
+       u8 link_forced;
+       u8 link_up;                     /* only valid if VF link is forced */
        u8 spoofchk;
        u16 num_mac;
        u16 num_vlan;
@@ -53,14 +63,29 @@ struct ice_vf {
 #ifdef CONFIG_PCI_IOV
 void ice_process_vflr_event(struct ice_pf *pf);
 int ice_sriov_configure(struct pci_dev *pdev, int num_vfs);
+int ice_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac);
+int ice_get_vf_cfg(struct net_device *netdev, int vf_id,
+                  struct ifla_vf_info *ivi);
+
 void ice_free_vfs(struct ice_pf *pf);
 void ice_vc_notify_reset(struct ice_pf *pf);
 bool ice_reset_all_vfs(struct ice_pf *pf, bool is_vflr);
+
+int ice_set_vf_port_vlan(struct net_device *netdev, int vf_id,
+                        u16 vlan_id, u8 qos, __be16 vlan_proto);
+
+int ice_set_vf_bw(struct net_device *netdev, int vf_id, int min_tx_rate,
+                 int max_tx_rate);
+
+int ice_set_vf_trust(struct net_device *netdev, int vf_id, bool trusted);
+
+int ice_set_vf_link_state(struct net_device *netdev, int vf_id, int link_state);
+
+int ice_set_vf_spoofchk(struct net_device *netdev, int vf_id, bool ena);
 #else /* CONFIG_PCI_IOV */
 #define ice_process_vflr_event(pf) do {} while (0)
 #define ice_free_vfs(pf) do {} while (0)
 #define ice_vc_notify_reset(pf) do {} while (0)
-
 static inline bool
 ice_reset_all_vfs(struct ice_pf __always_unused *pf,
                  bool __always_unused is_vflr)
@@ -74,5 +99,57 @@ ice_sriov_configure(struct pci_dev __always_unused *pdev,
 {
        return -EOPNOTSUPP;
 }
+
+static inline int
+ice_set_vf_mac(struct net_device __always_unused *netdev,
+              int __always_unused vf_id, u8 __always_unused *mac)
+{
+       return -EOPNOTSUPP;
+}
+
+static inline int
+ice_get_vf_cfg(struct net_device __always_unused *netdev,
+              int __always_unused vf_id,
+              struct ifla_vf_info __always_unused *ivi)
+{
+       return -EOPNOTSUPP;
+}
+
+static inline int
+ice_set_vf_trust(struct net_device __always_unused *netdev,
+                int __always_unused vf_id, bool __always_unused trusted)
+{
+       return -EOPNOTSUPP;
+}
+
+static inline int
+ice_set_vf_port_vlan(struct net_device __always_unused *netdev,
+                    int __always_unused vf_id, u16 __always_unused vid,
+                    u8 __always_unused qos, __be16 __always_unused v_proto)
+{
+       return -EOPNOTSUPP;
+}
+
+static inline int
+ice_set_vf_spoofchk(struct net_device __always_unused *netdev,
+                   int __always_unused vf_id, bool __always_unused ena)
+{
+       return -EOPNOTSUPP;
+}
+
+static inline int
+ice_set_vf_link_state(struct net_device __always_unused *netdev,
+                     int __always_unused vf_id, int __always_unused link_state)
+{
+       return -EOPNOTSUPP;
+}
+
+static inline int
+ice_set_vf_bw(struct net_device __always_unused *netdev,
+             int __always_unused vf_id, int __always_unused min_tx_rate,
+             int __always_unused max_tx_rate)
+{
+       return -EOPNOTSUPP;
+}
 #endif /* CONFIG_PCI_IOV */
 #endif /* _ICE_VIRTCHNL_PF_H_ */