18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright(c) 2013 - 2019 Intel Corporation. */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include "fm10k.h" 58c2ecf20Sopenharmony_ci#include "fm10k_vf.h" 68c2ecf20Sopenharmony_ci#include "fm10k_pf.h" 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_cistatic s32 fm10k_iov_msg_error(struct fm10k_hw *hw, u32 **results, 98c2ecf20Sopenharmony_ci struct fm10k_mbx_info *mbx) 108c2ecf20Sopenharmony_ci{ 118c2ecf20Sopenharmony_ci struct fm10k_vf_info *vf_info = (struct fm10k_vf_info *)mbx; 128c2ecf20Sopenharmony_ci struct fm10k_intfc *interface = hw->back; 138c2ecf20Sopenharmony_ci struct pci_dev *pdev = interface->pdev; 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Unknown message ID %u on VF %d\n", 168c2ecf20Sopenharmony_ci **results & FM10K_TLV_ID_MASK, vf_info->vf_idx); 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci return fm10k_tlv_msg_error(hw, results, mbx); 198c2ecf20Sopenharmony_ci} 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/** 228c2ecf20Sopenharmony_ci * fm10k_iov_msg_queue_mac_vlan - Message handler for MAC/VLAN request from VF 238c2ecf20Sopenharmony_ci * @hw: Pointer to hardware structure 248c2ecf20Sopenharmony_ci * @results: Pointer array to message, results[0] is pointer to message 258c2ecf20Sopenharmony_ci * @mbx: Pointer to mailbox information structure 268c2ecf20Sopenharmony_ci * 278c2ecf20Sopenharmony_ci * This function is a custom handler for MAC/VLAN requests from the VF. The 288c2ecf20Sopenharmony_ci * assumption is that it is acceptable to directly hand off the message from 298c2ecf20Sopenharmony_ci * the VF to the PF's switch manager. However, we use a MAC/VLAN message 308c2ecf20Sopenharmony_ci * queue to avoid overloading the mailbox when a large number of requests 318c2ecf20Sopenharmony_ci * come in. 328c2ecf20Sopenharmony_ci **/ 338c2ecf20Sopenharmony_cistatic s32 fm10k_iov_msg_queue_mac_vlan(struct fm10k_hw *hw, u32 **results, 348c2ecf20Sopenharmony_ci struct fm10k_mbx_info *mbx) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci struct fm10k_vf_info *vf_info = (struct fm10k_vf_info *)mbx; 378c2ecf20Sopenharmony_ci struct fm10k_intfc *interface = hw->back; 388c2ecf20Sopenharmony_ci u8 mac[ETH_ALEN]; 398c2ecf20Sopenharmony_ci u32 *result; 408c2ecf20Sopenharmony_ci int err = 0; 418c2ecf20Sopenharmony_ci bool set; 428c2ecf20Sopenharmony_ci u16 vlan; 438c2ecf20Sopenharmony_ci u32 vid; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci /* we shouldn't be updating rules on a disabled interface */ 468c2ecf20Sopenharmony_ci if (!FM10K_VF_FLAG_ENABLED(vf_info)) 478c2ecf20Sopenharmony_ci err = FM10K_ERR_PARAM; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci if (!err && !!results[FM10K_MAC_VLAN_MSG_VLAN]) { 508c2ecf20Sopenharmony_ci result = results[FM10K_MAC_VLAN_MSG_VLAN]; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci /* record VLAN id requested */ 538c2ecf20Sopenharmony_ci err = fm10k_tlv_attr_get_u32(result, &vid); 548c2ecf20Sopenharmony_ci if (err) 558c2ecf20Sopenharmony_ci return err; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci set = !(vid & FM10K_VLAN_CLEAR); 588c2ecf20Sopenharmony_ci vid &= ~FM10K_VLAN_CLEAR; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci /* if the length field has been set, this is a multi-bit 618c2ecf20Sopenharmony_ci * update request. For multi-bit requests, simply disallow 628c2ecf20Sopenharmony_ci * them when the pf_vid has been set. In this case, the PF 638c2ecf20Sopenharmony_ci * should have already cleared the VLAN_TABLE, and if we 648c2ecf20Sopenharmony_ci * allowed them, it could allow a rogue VF to receive traffic 658c2ecf20Sopenharmony_ci * on a VLAN it was not assigned. In the single-bit case, we 668c2ecf20Sopenharmony_ci * need to modify requests for VLAN 0 to use the default PF or 678c2ecf20Sopenharmony_ci * SW vid when assigned. 688c2ecf20Sopenharmony_ci */ 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci if (vid >> 16) { 718c2ecf20Sopenharmony_ci /* prevent multi-bit requests when PF has 728c2ecf20Sopenharmony_ci * administratively set the VLAN for this VF 738c2ecf20Sopenharmony_ci */ 748c2ecf20Sopenharmony_ci if (vf_info->pf_vid) 758c2ecf20Sopenharmony_ci return FM10K_ERR_PARAM; 768c2ecf20Sopenharmony_ci } else { 778c2ecf20Sopenharmony_ci err = fm10k_iov_select_vid(vf_info, (u16)vid); 788c2ecf20Sopenharmony_ci if (err < 0) 798c2ecf20Sopenharmony_ci return err; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci vid = err; 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci /* update VSI info for VF in regards to VLAN table */ 858c2ecf20Sopenharmony_ci err = hw->mac.ops.update_vlan(hw, vid, vf_info->vsi, set); 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci if (!err && !!results[FM10K_MAC_VLAN_MSG_MAC]) { 898c2ecf20Sopenharmony_ci result = results[FM10K_MAC_VLAN_MSG_MAC]; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci /* record unicast MAC address requested */ 928c2ecf20Sopenharmony_ci err = fm10k_tlv_attr_get_mac_vlan(result, mac, &vlan); 938c2ecf20Sopenharmony_ci if (err) 948c2ecf20Sopenharmony_ci return err; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci /* block attempts to set MAC for a locked device */ 978c2ecf20Sopenharmony_ci if (is_valid_ether_addr(vf_info->mac) && 988c2ecf20Sopenharmony_ci !ether_addr_equal(mac, vf_info->mac)) 998c2ecf20Sopenharmony_ci return FM10K_ERR_PARAM; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci set = !(vlan & FM10K_VLAN_CLEAR); 1028c2ecf20Sopenharmony_ci vlan &= ~FM10K_VLAN_CLEAR; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci err = fm10k_iov_select_vid(vf_info, vlan); 1058c2ecf20Sopenharmony_ci if (err < 0) 1068c2ecf20Sopenharmony_ci return err; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci vlan = (u16)err; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci /* Add this request to the MAC/VLAN queue */ 1118c2ecf20Sopenharmony_ci err = fm10k_queue_mac_request(interface, vf_info->glort, 1128c2ecf20Sopenharmony_ci mac, vlan, set); 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci if (!err && !!results[FM10K_MAC_VLAN_MSG_MULTICAST]) { 1168c2ecf20Sopenharmony_ci result = results[FM10K_MAC_VLAN_MSG_MULTICAST]; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci /* record multicast MAC address requested */ 1198c2ecf20Sopenharmony_ci err = fm10k_tlv_attr_get_mac_vlan(result, mac, &vlan); 1208c2ecf20Sopenharmony_ci if (err) 1218c2ecf20Sopenharmony_ci return err; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci /* verify that the VF is allowed to request multicast */ 1248c2ecf20Sopenharmony_ci if (!(vf_info->vf_flags & FM10K_VF_FLAG_MULTI_ENABLED)) 1258c2ecf20Sopenharmony_ci return FM10K_ERR_PARAM; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci set = !(vlan & FM10K_VLAN_CLEAR); 1288c2ecf20Sopenharmony_ci vlan &= ~FM10K_VLAN_CLEAR; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci err = fm10k_iov_select_vid(vf_info, vlan); 1318c2ecf20Sopenharmony_ci if (err < 0) 1328c2ecf20Sopenharmony_ci return err; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci vlan = (u16)err; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci /* Add this request to the MAC/VLAN queue */ 1378c2ecf20Sopenharmony_ci err = fm10k_queue_mac_request(interface, vf_info->glort, 1388c2ecf20Sopenharmony_ci mac, vlan, set); 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci return err; 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic const struct fm10k_msg_data iov_mbx_data[] = { 1458c2ecf20Sopenharmony_ci FM10K_TLV_MSG_TEST_HANDLER(fm10k_tlv_msg_test), 1468c2ecf20Sopenharmony_ci FM10K_VF_MSG_MSIX_HANDLER(fm10k_iov_msg_msix_pf), 1478c2ecf20Sopenharmony_ci FM10K_VF_MSG_MAC_VLAN_HANDLER(fm10k_iov_msg_queue_mac_vlan), 1488c2ecf20Sopenharmony_ci FM10K_VF_MSG_LPORT_STATE_HANDLER(fm10k_iov_msg_lport_state_pf), 1498c2ecf20Sopenharmony_ci FM10K_TLV_MSG_ERROR_HANDLER(fm10k_iov_msg_error), 1508c2ecf20Sopenharmony_ci}; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cis32 fm10k_iov_event(struct fm10k_intfc *interface) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci struct fm10k_hw *hw = &interface->hw; 1558c2ecf20Sopenharmony_ci struct fm10k_iov_data *iov_data; 1568c2ecf20Sopenharmony_ci s64 vflre; 1578c2ecf20Sopenharmony_ci int i; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci /* if there is no iov_data then there is no mailbox to process */ 1608c2ecf20Sopenharmony_ci if (!READ_ONCE(interface->iov_data)) 1618c2ecf20Sopenharmony_ci return 0; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci rcu_read_lock(); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci iov_data = interface->iov_data; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci /* check again now that we are in the RCU block */ 1688c2ecf20Sopenharmony_ci if (!iov_data) 1698c2ecf20Sopenharmony_ci goto read_unlock; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci if (!(fm10k_read_reg(hw, FM10K_EICR) & FM10K_EICR_VFLR)) 1728c2ecf20Sopenharmony_ci goto read_unlock; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci /* read VFLRE to determine if any VFs have been reset */ 1758c2ecf20Sopenharmony_ci vflre = fm10k_read_reg(hw, FM10K_PFVFLRE(1)); 1768c2ecf20Sopenharmony_ci vflre <<= 32; 1778c2ecf20Sopenharmony_ci vflre |= fm10k_read_reg(hw, FM10K_PFVFLRE(0)); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci i = iov_data->num_vfs; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci for (vflre <<= 64 - i; vflre && i--; vflre += vflre) { 1828c2ecf20Sopenharmony_ci struct fm10k_vf_info *vf_info = &iov_data->vf_info[i]; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci if (vflre >= 0) 1858c2ecf20Sopenharmony_ci continue; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci hw->iov.ops.reset_resources(hw, vf_info); 1888c2ecf20Sopenharmony_ci vf_info->mbx.ops.connect(hw, &vf_info->mbx); 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ciread_unlock: 1928c2ecf20Sopenharmony_ci rcu_read_unlock(); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci return 0; 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cis32 fm10k_iov_mbx(struct fm10k_intfc *interface) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci struct fm10k_hw *hw = &interface->hw; 2008c2ecf20Sopenharmony_ci struct fm10k_iov_data *iov_data; 2018c2ecf20Sopenharmony_ci int i; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci /* if there is no iov_data then there is no mailbox to process */ 2048c2ecf20Sopenharmony_ci if (!READ_ONCE(interface->iov_data)) 2058c2ecf20Sopenharmony_ci return 0; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci rcu_read_lock(); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci iov_data = interface->iov_data; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci /* check again now that we are in the RCU block */ 2128c2ecf20Sopenharmony_ci if (!iov_data) 2138c2ecf20Sopenharmony_ci goto read_unlock; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci /* lock the mailbox for transmit and receive */ 2168c2ecf20Sopenharmony_ci fm10k_mbx_lock(interface); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci /* Most VF messages sent to the PF cause the PF to respond by 2198c2ecf20Sopenharmony_ci * requesting from the SM mailbox. This means that too many VF 2208c2ecf20Sopenharmony_ci * messages processed at once could cause a mailbox timeout on the PF. 2218c2ecf20Sopenharmony_ci * To prevent this, store a pointer to the next VF mbx to process. Use 2228c2ecf20Sopenharmony_ci * that as the start of the loop so that we don't starve whichever VF 2238c2ecf20Sopenharmony_ci * got ignored on the previous run. 2248c2ecf20Sopenharmony_ci */ 2258c2ecf20Sopenharmony_ciprocess_mbx: 2268c2ecf20Sopenharmony_ci for (i = iov_data->next_vf_mbx ? : iov_data->num_vfs; i--;) { 2278c2ecf20Sopenharmony_ci struct fm10k_vf_info *vf_info = &iov_data->vf_info[i]; 2288c2ecf20Sopenharmony_ci struct fm10k_mbx_info *mbx = &vf_info->mbx; 2298c2ecf20Sopenharmony_ci u16 glort = vf_info->glort; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci /* process the SM mailbox first to drain outgoing messages */ 2328c2ecf20Sopenharmony_ci hw->mbx.ops.process(hw, &hw->mbx); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci /* verify port mapping is valid, if not reset port */ 2358c2ecf20Sopenharmony_ci if (vf_info->vf_flags && !fm10k_glort_valid_pf(hw, glort)) { 2368c2ecf20Sopenharmony_ci hw->iov.ops.reset_lport(hw, vf_info); 2378c2ecf20Sopenharmony_ci fm10k_clear_macvlan_queue(interface, glort, false); 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci /* reset VFs that have mailbox timed out */ 2418c2ecf20Sopenharmony_ci if (!mbx->timeout) { 2428c2ecf20Sopenharmony_ci hw->iov.ops.reset_resources(hw, vf_info); 2438c2ecf20Sopenharmony_ci mbx->ops.connect(hw, mbx); 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci /* guarantee we have free space in the SM mailbox */ 2478c2ecf20Sopenharmony_ci if (hw->mbx.state == FM10K_STATE_OPEN && 2488c2ecf20Sopenharmony_ci !hw->mbx.ops.tx_ready(&hw->mbx, FM10K_VFMBX_MSG_MTU)) { 2498c2ecf20Sopenharmony_ci /* keep track of how many times this occurs */ 2508c2ecf20Sopenharmony_ci interface->hw_sm_mbx_full++; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci /* make sure we try again momentarily */ 2538c2ecf20Sopenharmony_ci fm10k_service_event_schedule(interface); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci break; 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci /* cleanup mailbox and process received messages */ 2598c2ecf20Sopenharmony_ci mbx->ops.process(hw, mbx); 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci /* if we stopped processing mailboxes early, update next_vf_mbx. 2638c2ecf20Sopenharmony_ci * Otherwise, reset next_vf_mbx, and restart loop so that we process 2648c2ecf20Sopenharmony_ci * the remaining mailboxes we skipped at the start. 2658c2ecf20Sopenharmony_ci */ 2668c2ecf20Sopenharmony_ci if (i >= 0) { 2678c2ecf20Sopenharmony_ci iov_data->next_vf_mbx = i + 1; 2688c2ecf20Sopenharmony_ci } else if (iov_data->next_vf_mbx) { 2698c2ecf20Sopenharmony_ci iov_data->next_vf_mbx = 0; 2708c2ecf20Sopenharmony_ci goto process_mbx; 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci /* free the lock */ 2748c2ecf20Sopenharmony_ci fm10k_mbx_unlock(interface); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ciread_unlock: 2778c2ecf20Sopenharmony_ci rcu_read_unlock(); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci return 0; 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_civoid fm10k_iov_suspend(struct pci_dev *pdev) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci struct fm10k_intfc *interface = pci_get_drvdata(pdev); 2858c2ecf20Sopenharmony_ci struct fm10k_iov_data *iov_data = interface->iov_data; 2868c2ecf20Sopenharmony_ci struct fm10k_hw *hw = &interface->hw; 2878c2ecf20Sopenharmony_ci int num_vfs, i; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci /* pull out num_vfs from iov_data */ 2908c2ecf20Sopenharmony_ci num_vfs = iov_data ? iov_data->num_vfs : 0; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci /* shut down queue mapping for VFs */ 2938c2ecf20Sopenharmony_ci fm10k_write_reg(hw, FM10K_DGLORTMAP(fm10k_dglort_vf_rss), 2948c2ecf20Sopenharmony_ci FM10K_DGLORTMAP_NONE); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci /* Stop any active VFs and reset their resources */ 2978c2ecf20Sopenharmony_ci for (i = 0; i < num_vfs; i++) { 2988c2ecf20Sopenharmony_ci struct fm10k_vf_info *vf_info = &iov_data->vf_info[i]; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci hw->iov.ops.reset_resources(hw, vf_info); 3018c2ecf20Sopenharmony_ci hw->iov.ops.reset_lport(hw, vf_info); 3028c2ecf20Sopenharmony_ci fm10k_clear_macvlan_queue(interface, vf_info->glort, false); 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cistatic void fm10k_mask_aer_comp_abort(struct pci_dev *pdev) 3078c2ecf20Sopenharmony_ci{ 3088c2ecf20Sopenharmony_ci u32 err_mask; 3098c2ecf20Sopenharmony_ci int pos; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR); 3128c2ecf20Sopenharmony_ci if (!pos) 3138c2ecf20Sopenharmony_ci return; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci /* Mask the completion abort bit in the ERR_UNCOR_MASK register, 3168c2ecf20Sopenharmony_ci * preventing the device from reporting these errors to the upstream 3178c2ecf20Sopenharmony_ci * PCIe root device. This avoids bringing down platforms which upgrade 3188c2ecf20Sopenharmony_ci * non-fatal completer aborts into machine check exceptions. Completer 3198c2ecf20Sopenharmony_ci * aborts can occur whenever a VF reads a queue it doesn't own. 3208c2ecf20Sopenharmony_ci */ 3218c2ecf20Sopenharmony_ci pci_read_config_dword(pdev, pos + PCI_ERR_UNCOR_MASK, &err_mask); 3228c2ecf20Sopenharmony_ci err_mask |= PCI_ERR_UNC_COMP_ABORT; 3238c2ecf20Sopenharmony_ci pci_write_config_dword(pdev, pos + PCI_ERR_UNCOR_MASK, err_mask); 3248c2ecf20Sopenharmony_ci} 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ciint fm10k_iov_resume(struct pci_dev *pdev) 3278c2ecf20Sopenharmony_ci{ 3288c2ecf20Sopenharmony_ci struct fm10k_intfc *interface = pci_get_drvdata(pdev); 3298c2ecf20Sopenharmony_ci struct fm10k_iov_data *iov_data = interface->iov_data; 3308c2ecf20Sopenharmony_ci struct fm10k_dglort_cfg dglort = { 0 }; 3318c2ecf20Sopenharmony_ci struct fm10k_hw *hw = &interface->hw; 3328c2ecf20Sopenharmony_ci int num_vfs, i; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci /* pull out num_vfs from iov_data */ 3358c2ecf20Sopenharmony_ci num_vfs = iov_data ? iov_data->num_vfs : 0; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci /* return error if iov_data is not already populated */ 3388c2ecf20Sopenharmony_ci if (!iov_data) 3398c2ecf20Sopenharmony_ci return -ENOMEM; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci /* Lower severity of completer abort error reporting as 3428c2ecf20Sopenharmony_ci * the VFs can trigger this any time they read a queue 3438c2ecf20Sopenharmony_ci * that they don't own. 3448c2ecf20Sopenharmony_ci */ 3458c2ecf20Sopenharmony_ci fm10k_mask_aer_comp_abort(pdev); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci /* allocate hardware resources for the VFs */ 3488c2ecf20Sopenharmony_ci hw->iov.ops.assign_resources(hw, num_vfs, num_vfs); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci /* configure DGLORT mapping for RSS */ 3518c2ecf20Sopenharmony_ci dglort.glort = hw->mac.dglort_map & FM10K_DGLORTMAP_NONE; 3528c2ecf20Sopenharmony_ci dglort.idx = fm10k_dglort_vf_rss; 3538c2ecf20Sopenharmony_ci dglort.inner_rss = 1; 3548c2ecf20Sopenharmony_ci dglort.rss_l = fls(fm10k_queues_per_pool(hw) - 1); 3558c2ecf20Sopenharmony_ci dglort.queue_b = fm10k_vf_queue_index(hw, 0); 3568c2ecf20Sopenharmony_ci dglort.vsi_l = fls(hw->iov.total_vfs - 1); 3578c2ecf20Sopenharmony_ci dglort.vsi_b = 1; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci hw->mac.ops.configure_dglort_map(hw, &dglort); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci /* assign resources to the device */ 3628c2ecf20Sopenharmony_ci for (i = 0; i < num_vfs; i++) { 3638c2ecf20Sopenharmony_ci struct fm10k_vf_info *vf_info = &iov_data->vf_info[i]; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci /* allocate all but the last GLORT to the VFs */ 3668c2ecf20Sopenharmony_ci if (i == (~hw->mac.dglort_map >> FM10K_DGLORTMAP_MASK_SHIFT)) 3678c2ecf20Sopenharmony_ci break; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci /* assign GLORT to VF, and restrict it to multicast */ 3708c2ecf20Sopenharmony_ci hw->iov.ops.set_lport(hw, vf_info, i, 3718c2ecf20Sopenharmony_ci FM10K_VF_FLAG_MULTI_CAPABLE); 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci /* mailbox is disconnected so we don't send a message */ 3748c2ecf20Sopenharmony_ci hw->iov.ops.assign_default_mac_vlan(hw, vf_info); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci /* now we are ready so we can connect */ 3778c2ecf20Sopenharmony_ci vf_info->mbx.ops.connect(hw, &vf_info->mbx); 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci return 0; 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_cis32 fm10k_iov_update_pvid(struct fm10k_intfc *interface, u16 glort, u16 pvid) 3848c2ecf20Sopenharmony_ci{ 3858c2ecf20Sopenharmony_ci struct fm10k_iov_data *iov_data = interface->iov_data; 3868c2ecf20Sopenharmony_ci struct fm10k_hw *hw = &interface->hw; 3878c2ecf20Sopenharmony_ci struct fm10k_vf_info *vf_info; 3888c2ecf20Sopenharmony_ci u16 vf_idx = (glort - hw->mac.dglort_map) & FM10K_DGLORTMAP_NONE; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci /* no IOV support, not our message to process */ 3918c2ecf20Sopenharmony_ci if (!iov_data) 3928c2ecf20Sopenharmony_ci return FM10K_ERR_PARAM; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci /* glort outside our range, not our message to process */ 3958c2ecf20Sopenharmony_ci if (vf_idx >= iov_data->num_vfs) 3968c2ecf20Sopenharmony_ci return FM10K_ERR_PARAM; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci /* determine if an update has occurred and if so notify the VF */ 3998c2ecf20Sopenharmony_ci vf_info = &iov_data->vf_info[vf_idx]; 4008c2ecf20Sopenharmony_ci if (vf_info->sw_vid != pvid) { 4018c2ecf20Sopenharmony_ci vf_info->sw_vid = pvid; 4028c2ecf20Sopenharmony_ci hw->iov.ops.assign_default_mac_vlan(hw, vf_info); 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci return 0; 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_cistatic void fm10k_iov_free_data(struct pci_dev *pdev) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci struct fm10k_intfc *interface = pci_get_drvdata(pdev); 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci if (!interface->iov_data) 4138c2ecf20Sopenharmony_ci return; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci /* reclaim hardware resources */ 4168c2ecf20Sopenharmony_ci fm10k_iov_suspend(pdev); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci /* drop iov_data from interface */ 4198c2ecf20Sopenharmony_ci kfree_rcu(interface->iov_data, rcu); 4208c2ecf20Sopenharmony_ci interface->iov_data = NULL; 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_cistatic s32 fm10k_iov_alloc_data(struct pci_dev *pdev, int num_vfs) 4248c2ecf20Sopenharmony_ci{ 4258c2ecf20Sopenharmony_ci struct fm10k_intfc *interface = pci_get_drvdata(pdev); 4268c2ecf20Sopenharmony_ci struct fm10k_iov_data *iov_data = interface->iov_data; 4278c2ecf20Sopenharmony_ci struct fm10k_hw *hw = &interface->hw; 4288c2ecf20Sopenharmony_ci size_t size; 4298c2ecf20Sopenharmony_ci int i; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci /* return error if iov_data is already populated */ 4328c2ecf20Sopenharmony_ci if (iov_data) 4338c2ecf20Sopenharmony_ci return -EBUSY; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci /* The PF should always be able to assign resources */ 4368c2ecf20Sopenharmony_ci if (!hw->iov.ops.assign_resources) 4378c2ecf20Sopenharmony_ci return -ENODEV; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci /* nothing to do if no VFs are requested */ 4408c2ecf20Sopenharmony_ci if (!num_vfs) 4418c2ecf20Sopenharmony_ci return 0; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci /* allocate memory for VF storage */ 4448c2ecf20Sopenharmony_ci size = offsetof(struct fm10k_iov_data, vf_info[num_vfs]); 4458c2ecf20Sopenharmony_ci iov_data = kzalloc(size, GFP_KERNEL); 4468c2ecf20Sopenharmony_ci if (!iov_data) 4478c2ecf20Sopenharmony_ci return -ENOMEM; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci /* record number of VFs */ 4508c2ecf20Sopenharmony_ci iov_data->num_vfs = num_vfs; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci /* loop through vf_info structures initializing each entry */ 4538c2ecf20Sopenharmony_ci for (i = 0; i < num_vfs; i++) { 4548c2ecf20Sopenharmony_ci struct fm10k_vf_info *vf_info = &iov_data->vf_info[i]; 4558c2ecf20Sopenharmony_ci int err; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci /* Record VF VSI value */ 4588c2ecf20Sopenharmony_ci vf_info->vsi = i + 1; 4598c2ecf20Sopenharmony_ci vf_info->vf_idx = i; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci /* initialize mailbox memory */ 4628c2ecf20Sopenharmony_ci err = fm10k_pfvf_mbx_init(hw, &vf_info->mbx, iov_mbx_data, i); 4638c2ecf20Sopenharmony_ci if (err) { 4648c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 4658c2ecf20Sopenharmony_ci "Unable to initialize SR-IOV mailbox\n"); 4668c2ecf20Sopenharmony_ci kfree(iov_data); 4678c2ecf20Sopenharmony_ci return err; 4688c2ecf20Sopenharmony_ci } 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci /* assign iov_data to interface */ 4728c2ecf20Sopenharmony_ci interface->iov_data = iov_data; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci /* allocate hardware resources for the VFs */ 4758c2ecf20Sopenharmony_ci fm10k_iov_resume(pdev); 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci return 0; 4788c2ecf20Sopenharmony_ci} 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_civoid fm10k_iov_disable(struct pci_dev *pdev) 4818c2ecf20Sopenharmony_ci{ 4828c2ecf20Sopenharmony_ci if (pci_num_vf(pdev) && pci_vfs_assigned(pdev)) 4838c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 4848c2ecf20Sopenharmony_ci "Cannot disable SR-IOV while VFs are assigned\n"); 4858c2ecf20Sopenharmony_ci else 4868c2ecf20Sopenharmony_ci pci_disable_sriov(pdev); 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci fm10k_iov_free_data(pdev); 4898c2ecf20Sopenharmony_ci} 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ciint fm10k_iov_configure(struct pci_dev *pdev, int num_vfs) 4928c2ecf20Sopenharmony_ci{ 4938c2ecf20Sopenharmony_ci int current_vfs = pci_num_vf(pdev); 4948c2ecf20Sopenharmony_ci int err = 0; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci if (current_vfs && pci_vfs_assigned(pdev)) { 4978c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 4988c2ecf20Sopenharmony_ci "Cannot modify SR-IOV while VFs are assigned\n"); 4998c2ecf20Sopenharmony_ci num_vfs = current_vfs; 5008c2ecf20Sopenharmony_ci } else { 5018c2ecf20Sopenharmony_ci pci_disable_sriov(pdev); 5028c2ecf20Sopenharmony_ci fm10k_iov_free_data(pdev); 5038c2ecf20Sopenharmony_ci } 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci /* allocate resources for the VFs */ 5068c2ecf20Sopenharmony_ci err = fm10k_iov_alloc_data(pdev, num_vfs); 5078c2ecf20Sopenharmony_ci if (err) 5088c2ecf20Sopenharmony_ci return err; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci /* allocate VFs if not already allocated */ 5118c2ecf20Sopenharmony_ci if (num_vfs && num_vfs != current_vfs) { 5128c2ecf20Sopenharmony_ci err = pci_enable_sriov(pdev, num_vfs); 5138c2ecf20Sopenharmony_ci if (err) { 5148c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 5158c2ecf20Sopenharmony_ci "Enable PCI SR-IOV failed: %d\n", err); 5168c2ecf20Sopenharmony_ci return err; 5178c2ecf20Sopenharmony_ci } 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci return num_vfs; 5218c2ecf20Sopenharmony_ci} 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci/** 5248c2ecf20Sopenharmony_ci * fm10k_iov_update_stats - Update stats for all VFs 5258c2ecf20Sopenharmony_ci * @interface: device private structure 5268c2ecf20Sopenharmony_ci * 5278c2ecf20Sopenharmony_ci * Updates the VF statistics for all enabled VFs. Expects to be called by 5288c2ecf20Sopenharmony_ci * fm10k_update_stats and assumes that locking via the __FM10K_UPDATING_STATS 5298c2ecf20Sopenharmony_ci * bit is already handled. 5308c2ecf20Sopenharmony_ci */ 5318c2ecf20Sopenharmony_civoid fm10k_iov_update_stats(struct fm10k_intfc *interface) 5328c2ecf20Sopenharmony_ci{ 5338c2ecf20Sopenharmony_ci struct fm10k_iov_data *iov_data = interface->iov_data; 5348c2ecf20Sopenharmony_ci struct fm10k_hw *hw = &interface->hw; 5358c2ecf20Sopenharmony_ci int i; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci if (!iov_data) 5388c2ecf20Sopenharmony_ci return; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci for (i = 0; i < iov_data->num_vfs; i++) 5418c2ecf20Sopenharmony_ci hw->iov.ops.update_stats(hw, iov_data->vf_info[i].stats, i); 5428c2ecf20Sopenharmony_ci} 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_cistatic inline void fm10k_reset_vf_info(struct fm10k_intfc *interface, 5458c2ecf20Sopenharmony_ci struct fm10k_vf_info *vf_info) 5468c2ecf20Sopenharmony_ci{ 5478c2ecf20Sopenharmony_ci struct fm10k_hw *hw = &interface->hw; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci /* assigning the MAC address will send a mailbox message */ 5508c2ecf20Sopenharmony_ci fm10k_mbx_lock(interface); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci /* disable LPORT for this VF which clears switch rules */ 5538c2ecf20Sopenharmony_ci hw->iov.ops.reset_lport(hw, vf_info); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci fm10k_clear_macvlan_queue(interface, vf_info->glort, false); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci /* assign new MAC+VLAN for this VF */ 5588c2ecf20Sopenharmony_ci hw->iov.ops.assign_default_mac_vlan(hw, vf_info); 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci /* re-enable the LPORT for this VF */ 5618c2ecf20Sopenharmony_ci hw->iov.ops.set_lport(hw, vf_info, vf_info->vf_idx, 5628c2ecf20Sopenharmony_ci FM10K_VF_FLAG_MULTI_CAPABLE); 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci fm10k_mbx_unlock(interface); 5658c2ecf20Sopenharmony_ci} 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ciint fm10k_ndo_set_vf_mac(struct net_device *netdev, int vf_idx, u8 *mac) 5688c2ecf20Sopenharmony_ci{ 5698c2ecf20Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(netdev); 5708c2ecf20Sopenharmony_ci struct fm10k_iov_data *iov_data = interface->iov_data; 5718c2ecf20Sopenharmony_ci struct fm10k_vf_info *vf_info; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci /* verify SR-IOV is active and that vf idx is valid */ 5748c2ecf20Sopenharmony_ci if (!iov_data || vf_idx >= iov_data->num_vfs) 5758c2ecf20Sopenharmony_ci return -EINVAL; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci /* verify MAC addr is valid */ 5788c2ecf20Sopenharmony_ci if (!is_zero_ether_addr(mac) && !is_valid_ether_addr(mac)) 5798c2ecf20Sopenharmony_ci return -EINVAL; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci /* record new MAC address */ 5828c2ecf20Sopenharmony_ci vf_info = &iov_data->vf_info[vf_idx]; 5838c2ecf20Sopenharmony_ci ether_addr_copy(vf_info->mac, mac); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci fm10k_reset_vf_info(interface, vf_info); 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci return 0; 5888c2ecf20Sopenharmony_ci} 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ciint fm10k_ndo_set_vf_vlan(struct net_device *netdev, int vf_idx, u16 vid, 5918c2ecf20Sopenharmony_ci u8 qos, __be16 vlan_proto) 5928c2ecf20Sopenharmony_ci{ 5938c2ecf20Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(netdev); 5948c2ecf20Sopenharmony_ci struct fm10k_iov_data *iov_data = interface->iov_data; 5958c2ecf20Sopenharmony_ci struct fm10k_hw *hw = &interface->hw; 5968c2ecf20Sopenharmony_ci struct fm10k_vf_info *vf_info; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci /* verify SR-IOV is active and that vf idx is valid */ 5998c2ecf20Sopenharmony_ci if (!iov_data || vf_idx >= iov_data->num_vfs) 6008c2ecf20Sopenharmony_ci return -EINVAL; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci /* QOS is unsupported and VLAN IDs accepted range 0-4094 */ 6038c2ecf20Sopenharmony_ci if (qos || (vid > (VLAN_VID_MASK - 1))) 6048c2ecf20Sopenharmony_ci return -EINVAL; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci /* VF VLAN Protocol part to default is unsupported */ 6078c2ecf20Sopenharmony_ci if (vlan_proto != htons(ETH_P_8021Q)) 6088c2ecf20Sopenharmony_ci return -EPROTONOSUPPORT; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci vf_info = &iov_data->vf_info[vf_idx]; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci /* exit if there is nothing to do */ 6138c2ecf20Sopenharmony_ci if (vf_info->pf_vid == vid) 6148c2ecf20Sopenharmony_ci return 0; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci /* record default VLAN ID for VF */ 6178c2ecf20Sopenharmony_ci vf_info->pf_vid = vid; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci /* Clear the VLAN table for the VF */ 6208c2ecf20Sopenharmony_ci hw->mac.ops.update_vlan(hw, FM10K_VLAN_ALL, vf_info->vsi, false); 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci fm10k_reset_vf_info(interface, vf_info); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci return 0; 6258c2ecf20Sopenharmony_ci} 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ciint fm10k_ndo_set_vf_bw(struct net_device *netdev, int vf_idx, 6288c2ecf20Sopenharmony_ci int __always_unused min_rate, int max_rate) 6298c2ecf20Sopenharmony_ci{ 6308c2ecf20Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(netdev); 6318c2ecf20Sopenharmony_ci struct fm10k_iov_data *iov_data = interface->iov_data; 6328c2ecf20Sopenharmony_ci struct fm10k_hw *hw = &interface->hw; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci /* verify SR-IOV is active and that vf idx is valid */ 6358c2ecf20Sopenharmony_ci if (!iov_data || vf_idx >= iov_data->num_vfs) 6368c2ecf20Sopenharmony_ci return -EINVAL; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci /* rate limit cannot be less than 10Mbs or greater than link speed */ 6398c2ecf20Sopenharmony_ci if (max_rate && 6408c2ecf20Sopenharmony_ci (max_rate < FM10K_VF_TC_MIN || max_rate > FM10K_VF_TC_MAX)) 6418c2ecf20Sopenharmony_ci return -EINVAL; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci /* store values */ 6448c2ecf20Sopenharmony_ci iov_data->vf_info[vf_idx].rate = max_rate; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci /* update hardware configuration */ 6478c2ecf20Sopenharmony_ci hw->iov.ops.configure_tc(hw, vf_idx, max_rate); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci return 0; 6508c2ecf20Sopenharmony_ci} 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ciint fm10k_ndo_get_vf_config(struct net_device *netdev, 6538c2ecf20Sopenharmony_ci int vf_idx, struct ifla_vf_info *ivi) 6548c2ecf20Sopenharmony_ci{ 6558c2ecf20Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(netdev); 6568c2ecf20Sopenharmony_ci struct fm10k_iov_data *iov_data = interface->iov_data; 6578c2ecf20Sopenharmony_ci struct fm10k_vf_info *vf_info; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci /* verify SR-IOV is active and that vf idx is valid */ 6608c2ecf20Sopenharmony_ci if (!iov_data || vf_idx >= iov_data->num_vfs) 6618c2ecf20Sopenharmony_ci return -EINVAL; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci vf_info = &iov_data->vf_info[vf_idx]; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci ivi->vf = vf_idx; 6668c2ecf20Sopenharmony_ci ivi->max_tx_rate = vf_info->rate; 6678c2ecf20Sopenharmony_ci ivi->min_tx_rate = 0; 6688c2ecf20Sopenharmony_ci ether_addr_copy(ivi->mac, vf_info->mac); 6698c2ecf20Sopenharmony_ci ivi->vlan = vf_info->pf_vid; 6708c2ecf20Sopenharmony_ci ivi->qos = 0; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci return 0; 6738c2ecf20Sopenharmony_ci} 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ciint fm10k_ndo_get_vf_stats(struct net_device *netdev, 6768c2ecf20Sopenharmony_ci int vf_idx, struct ifla_vf_stats *stats) 6778c2ecf20Sopenharmony_ci{ 6788c2ecf20Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(netdev); 6798c2ecf20Sopenharmony_ci struct fm10k_iov_data *iov_data = interface->iov_data; 6808c2ecf20Sopenharmony_ci struct fm10k_hw *hw = &interface->hw; 6818c2ecf20Sopenharmony_ci struct fm10k_hw_stats_q *hw_stats; 6828c2ecf20Sopenharmony_ci u32 idx, qpp; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci /* verify SR-IOV is active and that vf idx is valid */ 6858c2ecf20Sopenharmony_ci if (!iov_data || vf_idx >= iov_data->num_vfs) 6868c2ecf20Sopenharmony_ci return -EINVAL; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci qpp = fm10k_queues_per_pool(hw); 6898c2ecf20Sopenharmony_ci hw_stats = iov_data->vf_info[vf_idx].stats; 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci for (idx = 0; idx < qpp; idx++) { 6928c2ecf20Sopenharmony_ci stats->rx_packets += hw_stats[idx].rx_packets.count; 6938c2ecf20Sopenharmony_ci stats->tx_packets += hw_stats[idx].tx_packets.count; 6948c2ecf20Sopenharmony_ci stats->rx_bytes += hw_stats[idx].rx_bytes.count; 6958c2ecf20Sopenharmony_ci stats->tx_bytes += hw_stats[idx].tx_bytes.count; 6968c2ecf20Sopenharmony_ci stats->rx_dropped += hw_stats[idx].rx_drops.count; 6978c2ecf20Sopenharmony_ci } 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci return 0; 7008c2ecf20Sopenharmony_ci} 701