mv_list = kcalloc(num_vf_macvlans, sizeof(struct vf_macvlans),
GFP_KERNEL); if (!mv_list) return -ENOMEM;
for (i = 0; i < num_vf_macvlans; i++) {
mv_list[i].vf = -1;
mv_list[i].free = true;
list_add(&mv_list[i].mvlist, &wx->vf_mvs.mvlist);
}
wx->mv_list = mv_list;
return 0;
}
staticvoid wx_sriov_clear_data(struct wx *wx)
{ /* set num VFs to 0 to prevent access to vfinfo */
wx->num_vfs = 0;
/* free VF control structures */
kfree(wx->vfinfo);
wx->vfinfo = NULL;
/* free macvlan list */
kfree(wx->mv_list);
wx->mv_list = NULL;
/* set default pool back to 0 */
wr32m(wx, WX_PSR_VM_CTL, WX_PSR_VM_CTL_POOL_MASK, 0);
wx->ring_feature[RING_F_VMDQ].offset = 0;
clear_bit(WX_FLAG_IRQ_VECTOR_SHARED, wx->flags);
clear_bit(WX_FLAG_SRIOV_ENABLED, wx->flags); /* Disable VMDq flag so device will be set in NM mode */ if (wx->ring_feature[RING_F_VMDQ].limit == 1)
clear_bit(WX_FLAG_VMDQ_ENABLED, wx->flags);
}
staticint __wx_enable_sriov(struct wx *wx, u8 num_vfs)
{ int i, ret = 0;
u32 value = 0;
set_bit(WX_FLAG_SRIOV_ENABLED, wx->flags);
dev_info(&wx->pdev->dev, "SR-IOV enabled with %d VFs\n", num_vfs);
if (num_vfs == 7 && wx->mac.type == wx_mac_em)
set_bit(WX_FLAG_IRQ_VECTOR_SHARED, wx->flags);
/* Enable VMDq flag so device will be set in VM mode */
set_bit(WX_FLAG_VMDQ_ENABLED, wx->flags); if (!wx->ring_feature[RING_F_VMDQ].limit)
wx->ring_feature[RING_F_VMDQ].limit = 1;
wx->ring_feature[RING_F_VMDQ].offset = num_vfs;
wx->vfinfo = kcalloc(num_vfs, sizeof(struct vf_data_storage),
GFP_KERNEL); if (!wx->vfinfo) return -ENOMEM;
ret = wx_alloc_vf_macvlans(wx, num_vfs); if (ret) return ret;
/* reset the filters for the device */
wx_vf_reset_event(wx, vf);
/* set vf mac address */ if (!is_zero_ether_addr(vf_mac))
wx_set_vf_mac(wx, vf, vf_mac);
index = WX_VF_REG_OFFSET(vf);
vf_bit = WX_VF_IND_SHIFT(vf);
/* force drop enable for all VF Rx queues */
wx_write_qde(wx, vf, 1);
/* set transmit and receive for vf */
wx_set_vf_rx_tx(wx, vf);
pf_max_frame = dev->mtu + ETH_HLEN;
if (pf_max_frame > ETH_FRAME_LEN)
reg = BIT(vf_bit);
wr32(wx, WX_RDM_VFRE_CLR(index), reg);
/* enable VF mailbox for further messages */
wx->vfinfo[vf].clear_to_send = true;
/* reply to reset with ack and vf mac address */
msgbuf[0] = WX_VF_RESET; if (!is_zero_ether_addr(vf_mac)) {
msgbuf[0] |= WX_VT_MSGTYPE_ACK;
memcpy(addr, vf_mac, ETH_ALEN);
} else {
msgbuf[0] |= WX_VT_MSGTYPE_NACK;
wx_err(wx, "VF %d has no MAC address assigned", vf);
}
if (!is_valid_ether_addr(new_mac)) {
wx_err(wx, "VF %d attempted to set invalid mac\n", vf); return -EINVAL;
}
if (wx->vfinfo[vf].pf_set_mac &&
memcmp(wx->vfinfo[vf].vf_mac_addr, new_mac, ETH_ALEN)) {
wx_err(wx, "VF %d attempt to set a MAC but it already had a MAC.",
vf); return -EBUSY;
}
ret = wx_set_vf_mac(wx, vf, new_mac); if (ret < 0) return ret;
/* short cut the special case */ if (vlan == 0) return 0;
/* Search for the vlan id in the VLVF entries */ for (regindex = 1; regindex < WX_PSR_VLAN_SWC_ENTRIES; regindex++) {
wr32(wx, WX_PSR_VLAN_SWC_IDX, regindex);
vlvf = rd32(wx, WX_PSR_VLAN_SWC); if ((vlvf & VLAN_VID_MASK) == vlan) break;
}
/* Return a negative value if not found */ if (regindex >= WX_PSR_VLAN_SWC_ENTRIES)
regindex = -EINVAL;
staticint wx_set_vf_vlan_msg(struct wx *wx, u32 *msgbuf, u16 vf)
{ int add = (msgbuf[0] & WX_VT_MSGINFO_MASK) >> WX_VT_MSGINFO_SHIFT; int vid = (msgbuf[1] & WX_PSR_VLAN_SWC_VLANID_MASK); int ret;
if (add)
wx->vfinfo[vf].vlan_count++; elseif (wx->vfinfo[vf].vlan_count)
wx->vfinfo[vf].vlan_count--;
/* in case of promiscuous mode any VLAN filter set for a VF must * also have the PF pool added to it.
*/ if (add && wx->netdev->flags & IFF_PROMISC)
wx_set_vf_vlan(wx, add, vid, VMDQ_P(0));
ret = wx_set_vf_vlan(wx, add, vid, vf); if (!ret && wx->vfinfo[vf].spoofchk_enabled)
wx_set_vlan_anti_spoofing(wx, true, vf);
/* Go through all the checks to see if the VLAN filter should * be wiped completely.
*/ if (!add && wx->netdev->flags & IFF_PROMISC) {
u32 bits = 0, vlvf; int reg_ndx;
reg_ndx = wx_find_vlvf_entry(wx, vid); if (reg_ndx < 0) return -ENOSPC;
wr32(wx, WX_PSR_VLAN_SWC_IDX, reg_ndx);
vlvf = rd32(wx, WX_PSR_VLAN_SWC); /* See if any other pools are set for this VLAN filter * entry other than the PF.
*/ if (VMDQ_P(0) < 32) {
bits = rd32(wx, WX_PSR_VLAN_SWC_VM_L);
bits &= ~BIT(VMDQ_P(0)); if (test_bit(WX_FLAG_MULTI_64_FUNC, wx->flags))
bits |= rd32(wx, WX_PSR_VLAN_SWC_VM_H);
} else { if (test_bit(WX_FLAG_MULTI_64_FUNC, wx->flags))
bits = rd32(wx, WX_PSR_VLAN_SWC_VM_H);
bits &= ~BIT(VMDQ_P(0) % 32);
bits |= rd32(wx, WX_PSR_VLAN_SWC_VM_L);
} /* If the filter was removed then ensure PF pool bit * is cleared if the PF only added itself to the pool * because the PF is in promiscuous mode.
*/ if ((vlvf & VLAN_VID_MASK) == vid && !bits)
wx_set_vf_vlan(wx, add, vid, VMDQ_P(0));
}
return 0;
}
staticint wx_set_vf_macvlan_msg(struct wx *wx, u32 *msgbuf, u16 vf)
{ int index = (msgbuf[0] & WX_VT_MSGINFO_MASK) >>
WX_VT_MSGINFO_SHIFT;
u8 *new_mac = ((u8 *)(&msgbuf[1])); int err;
if (wx->vfinfo[vf].pf_set_mac && index > 0) {
wx_err(wx, "VF %d request MACVLAN filter but is denied\n", vf); return -EINVAL;
}
/* An non-zero index indicates the VF is setting a filter */ if (index) { if (!is_valid_ether_addr(new_mac)) {
wx_err(wx, "VF %d attempted to set invalid mac\n", vf); return -EINVAL;
} /* If the VF is allowed to set MAC filters then turn off * anti-spoofing to avoid false positives.
*/ if (wx->vfinfo[vf].spoofchk_enabled)
wx_set_vf_spoofchk(wx->netdev, vf, false);
}
err = wx_set_vf_macvlan(wx, vf, index, new_mac); if (err == -ENOSPC)
wx_err(wx, "VF %d request MACVLAN filter but there is no space\n",
vf); if (err < 0) return err;
return 0;
}
staticint wx_negotiate_vf_api(struct wx *wx, u32 *msgbuf, u32 vf)
{ int api = msgbuf[1];
switch (api) { case wx_mbox_api_13:
wx->vfinfo[vf].vf_api = api; return 0; default:
wx_err(wx, "VF %d requested invalid api version %u\n", vf, api); return -EINVAL;
}
}
retval = wx_read_mbx_pf(wx, msgbuf, mbx_size, vf); if (retval) {
wx_err(wx, "Error receiving message from VF\n"); return;
}
/* this is a message we already processed, do nothing */ if (msgbuf[0] & (WX_VT_MSGTYPE_ACK | WX_VT_MSGTYPE_NACK)) return;
if (msgbuf[0] == WX_VF_RESET) {
wx_vf_reset_msg(wx, vf); return;
}
/* until the vf completes a virtual function reset it should not be * allowed to start any configuration.
*/ if (!wx->vfinfo[vf].clear_to_send) {
msgbuf[0] |= WX_VT_MSGTYPE_NACK;
wx_write_mbx_pf(wx, msgbuf, 1, vf); return;
}
switch ((msgbuf[0] & U16_MAX)) { case WX_VF_SET_MAC_ADDR:
retval = wx_set_vf_mac_addr(wx, msgbuf, vf); break; case WX_VF_SET_MULTICAST:
wx_set_vf_multicasts(wx, msgbuf, vf);
retval = 0; break; case WX_VF_SET_VLAN:
retval = wx_set_vf_vlan_msg(wx, msgbuf, vf); break; case WX_VF_SET_LPE:
wx_set_vf_lpe(wx, msgbuf[1], vf);
retval = 0; break; case WX_VF_SET_MACVLAN:
retval = wx_set_vf_macvlan_msg(wx, msgbuf, vf); break; case WX_VF_API_NEGOTIATE:
retval = wx_negotiate_vf_api(wx, msgbuf, vf); break; case WX_VF_GET_QUEUES:
retval = wx_get_vf_queues(wx, msgbuf, vf); break; case WX_VF_GET_LINK_STATE:
retval = wx_get_vf_link_state(wx, msgbuf, vf); break; case WX_VF_GET_FW_VERSION:
retval = wx_get_fw_version(wx, msgbuf, vf); break; case WX_VF_UPDATE_XCAST_MODE:
retval = wx_update_vf_xcast_mode(wx, msgbuf, vf); break; case WX_VF_BACKUP: break; default:
wx_err(wx, "Unhandled Msg %8.8x\n", msgbuf[0]); break;
}
/* notify the VF of the results of what it sent us */ if (retval)
msgbuf[0] |= WX_VT_MSGTYPE_NACK; else
msgbuf[0] |= WX_VT_MSGTYPE_ACK;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.