18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <linux/pci.h> 38c2ecf20Sopenharmony_ci#include <linux/delay.h> 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci#include "nitrox_dev.h" 68c2ecf20Sopenharmony_ci#include "nitrox_hal.h" 78c2ecf20Sopenharmony_ci#include "nitrox_common.h" 88c2ecf20Sopenharmony_ci#include "nitrox_isr.h" 98c2ecf20Sopenharmony_ci#include "nitrox_mbx.h" 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci/** 128c2ecf20Sopenharmony_ci * num_vfs_valid - validate VF count 138c2ecf20Sopenharmony_ci * @num_vfs: number of VF(s) 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_cistatic inline bool num_vfs_valid(int num_vfs) 168c2ecf20Sopenharmony_ci{ 178c2ecf20Sopenharmony_ci bool valid = false; 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci switch (num_vfs) { 208c2ecf20Sopenharmony_ci case 16: 218c2ecf20Sopenharmony_ci case 32: 228c2ecf20Sopenharmony_ci case 64: 238c2ecf20Sopenharmony_ci case 128: 248c2ecf20Sopenharmony_ci valid = true; 258c2ecf20Sopenharmony_ci break; 268c2ecf20Sopenharmony_ci } 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci return valid; 298c2ecf20Sopenharmony_ci} 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic inline enum vf_mode num_vfs_to_mode(int num_vfs) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci enum vf_mode mode = 0; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci switch (num_vfs) { 368c2ecf20Sopenharmony_ci case 0: 378c2ecf20Sopenharmony_ci mode = __NDEV_MODE_PF; 388c2ecf20Sopenharmony_ci break; 398c2ecf20Sopenharmony_ci case 16: 408c2ecf20Sopenharmony_ci mode = __NDEV_MODE_VF16; 418c2ecf20Sopenharmony_ci break; 428c2ecf20Sopenharmony_ci case 32: 438c2ecf20Sopenharmony_ci mode = __NDEV_MODE_VF32; 448c2ecf20Sopenharmony_ci break; 458c2ecf20Sopenharmony_ci case 64: 468c2ecf20Sopenharmony_ci mode = __NDEV_MODE_VF64; 478c2ecf20Sopenharmony_ci break; 488c2ecf20Sopenharmony_ci case 128: 498c2ecf20Sopenharmony_ci mode = __NDEV_MODE_VF128; 508c2ecf20Sopenharmony_ci break; 518c2ecf20Sopenharmony_ci } 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci return mode; 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic inline int vf_mode_to_nr_queues(enum vf_mode mode) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci int nr_queues = 0; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci switch (mode) { 618c2ecf20Sopenharmony_ci case __NDEV_MODE_PF: 628c2ecf20Sopenharmony_ci nr_queues = MAX_PF_QUEUES; 638c2ecf20Sopenharmony_ci break; 648c2ecf20Sopenharmony_ci case __NDEV_MODE_VF16: 658c2ecf20Sopenharmony_ci nr_queues = 8; 668c2ecf20Sopenharmony_ci break; 678c2ecf20Sopenharmony_ci case __NDEV_MODE_VF32: 688c2ecf20Sopenharmony_ci nr_queues = 4; 698c2ecf20Sopenharmony_ci break; 708c2ecf20Sopenharmony_ci case __NDEV_MODE_VF64: 718c2ecf20Sopenharmony_ci nr_queues = 2; 728c2ecf20Sopenharmony_ci break; 738c2ecf20Sopenharmony_ci case __NDEV_MODE_VF128: 748c2ecf20Sopenharmony_ci nr_queues = 1; 758c2ecf20Sopenharmony_ci break; 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci return nr_queues; 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic void nitrox_pf_cleanup(struct nitrox_device *ndev) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci /* PF has no queues in SR-IOV mode */ 848c2ecf20Sopenharmony_ci atomic_set(&ndev->state, __NDEV_NOT_READY); 858c2ecf20Sopenharmony_ci /* unregister crypto algorithms */ 868c2ecf20Sopenharmony_ci nitrox_crypto_unregister(); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci /* cleanup PF resources */ 898c2ecf20Sopenharmony_ci nitrox_unregister_interrupts(ndev); 908c2ecf20Sopenharmony_ci nitrox_common_sw_cleanup(ndev); 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci/** 948c2ecf20Sopenharmony_ci * nitrox_pf_reinit - re-initialize PF resources once SR-IOV is disabled 958c2ecf20Sopenharmony_ci * @ndev: NITROX device 968c2ecf20Sopenharmony_ci */ 978c2ecf20Sopenharmony_cistatic int nitrox_pf_reinit(struct nitrox_device *ndev) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci int err; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci /* allocate resources for PF */ 1028c2ecf20Sopenharmony_ci err = nitrox_common_sw_init(ndev); 1038c2ecf20Sopenharmony_ci if (err) 1048c2ecf20Sopenharmony_ci return err; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci err = nitrox_register_interrupts(ndev); 1078c2ecf20Sopenharmony_ci if (err) { 1088c2ecf20Sopenharmony_ci nitrox_common_sw_cleanup(ndev); 1098c2ecf20Sopenharmony_ci return err; 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci /* configure the AQM queues */ 1138c2ecf20Sopenharmony_ci nitrox_config_aqm_rings(ndev); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci /* configure the packet queues */ 1168c2ecf20Sopenharmony_ci nitrox_config_pkt_input_rings(ndev); 1178c2ecf20Sopenharmony_ci nitrox_config_pkt_solicit_ports(ndev); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci /* set device to ready state */ 1208c2ecf20Sopenharmony_ci atomic_set(&ndev->state, __NDEV_READY); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci /* register crypto algorithms */ 1238c2ecf20Sopenharmony_ci return nitrox_crypto_register(); 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic void nitrox_sriov_cleanup(struct nitrox_device *ndev) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci /* unregister interrupts for PF in SR-IOV */ 1298c2ecf20Sopenharmony_ci nitrox_sriov_unregister_interrupts(ndev); 1308c2ecf20Sopenharmony_ci nitrox_mbox_cleanup(ndev); 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistatic int nitrox_sriov_init(struct nitrox_device *ndev) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci int ret; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci /* register interrupts for PF in SR-IOV */ 1388c2ecf20Sopenharmony_ci ret = nitrox_sriov_register_interupts(ndev); 1398c2ecf20Sopenharmony_ci if (ret) 1408c2ecf20Sopenharmony_ci return ret; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci ret = nitrox_mbox_init(ndev); 1438c2ecf20Sopenharmony_ci if (ret) 1448c2ecf20Sopenharmony_ci goto sriov_init_fail; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci return 0; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cisriov_init_fail: 1498c2ecf20Sopenharmony_ci nitrox_sriov_cleanup(ndev); 1508c2ecf20Sopenharmony_ci return ret; 1518c2ecf20Sopenharmony_ci} 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cistatic int nitrox_sriov_enable(struct pci_dev *pdev, int num_vfs) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci struct nitrox_device *ndev = pci_get_drvdata(pdev); 1568c2ecf20Sopenharmony_ci int err; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci if (!num_vfs_valid(num_vfs)) { 1598c2ecf20Sopenharmony_ci dev_err(DEV(ndev), "Invalid num_vfs %d\n", num_vfs); 1608c2ecf20Sopenharmony_ci return -EINVAL; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci if (pci_num_vf(pdev) == num_vfs) 1648c2ecf20Sopenharmony_ci return num_vfs; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci err = pci_enable_sriov(pdev, num_vfs); 1678c2ecf20Sopenharmony_ci if (err) { 1688c2ecf20Sopenharmony_ci dev_err(DEV(ndev), "failed to enable PCI sriov %d\n", err); 1698c2ecf20Sopenharmony_ci return err; 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci dev_info(DEV(ndev), "Enabled VF(s) %d\n", num_vfs); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci ndev->mode = num_vfs_to_mode(num_vfs); 1748c2ecf20Sopenharmony_ci ndev->iov.num_vfs = num_vfs; 1758c2ecf20Sopenharmony_ci ndev->iov.max_vf_queues = vf_mode_to_nr_queues(ndev->mode); 1768c2ecf20Sopenharmony_ci /* set bit in flags */ 1778c2ecf20Sopenharmony_ci set_bit(__NDEV_SRIOV_BIT, &ndev->flags); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci /* cleanup PF resources */ 1808c2ecf20Sopenharmony_ci nitrox_pf_cleanup(ndev); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci /* PF SR-IOV mode initialization */ 1838c2ecf20Sopenharmony_ci err = nitrox_sriov_init(ndev); 1848c2ecf20Sopenharmony_ci if (err) 1858c2ecf20Sopenharmony_ci goto iov_fail; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci config_nps_core_vfcfg_mode(ndev, ndev->mode); 1888c2ecf20Sopenharmony_ci return num_vfs; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ciiov_fail: 1918c2ecf20Sopenharmony_ci pci_disable_sriov(pdev); 1928c2ecf20Sopenharmony_ci /* clear bit in flags */ 1938c2ecf20Sopenharmony_ci clear_bit(__NDEV_SRIOV_BIT, &ndev->flags); 1948c2ecf20Sopenharmony_ci ndev->iov.num_vfs = 0; 1958c2ecf20Sopenharmony_ci ndev->mode = __NDEV_MODE_PF; 1968c2ecf20Sopenharmony_ci /* reset back to working mode in PF */ 1978c2ecf20Sopenharmony_ci nitrox_pf_reinit(ndev); 1988c2ecf20Sopenharmony_ci return err; 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic int nitrox_sriov_disable(struct pci_dev *pdev) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci struct nitrox_device *ndev = pci_get_drvdata(pdev); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci if (!test_bit(__NDEV_SRIOV_BIT, &ndev->flags)) 2068c2ecf20Sopenharmony_ci return 0; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci if (pci_vfs_assigned(pdev)) { 2098c2ecf20Sopenharmony_ci dev_warn(DEV(ndev), "VFs are attached to VM. Can't disable SR-IOV\n"); 2108c2ecf20Sopenharmony_ci return -EPERM; 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci pci_disable_sriov(pdev); 2138c2ecf20Sopenharmony_ci /* clear bit in flags */ 2148c2ecf20Sopenharmony_ci clear_bit(__NDEV_SRIOV_BIT, &ndev->flags); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci ndev->iov.num_vfs = 0; 2178c2ecf20Sopenharmony_ci ndev->iov.max_vf_queues = 0; 2188c2ecf20Sopenharmony_ci ndev->mode = __NDEV_MODE_PF; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci /* cleanup PF SR-IOV resources */ 2218c2ecf20Sopenharmony_ci nitrox_sriov_cleanup(ndev); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci config_nps_core_vfcfg_mode(ndev, ndev->mode); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci return nitrox_pf_reinit(ndev); 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ciint nitrox_sriov_configure(struct pci_dev *pdev, int num_vfs) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci if (!num_vfs) 2318c2ecf20Sopenharmony_ci return nitrox_sriov_disable(pdev); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci return nitrox_sriov_enable(pdev, num_vfs); 2348c2ecf20Sopenharmony_ci} 235