1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/pci.h>
3 #include <linux/delay.h>
4 
5 #include "nitrox_dev.h"
6 #include "nitrox_hal.h"
7 #include "nitrox_common.h"
8 #include "nitrox_isr.h"
9 
10 static inline bool num_vfs_valid(int num_vfs)
11 {
12 	bool valid = false;
13 
14 	switch (num_vfs) {
15 	case 16:
16 	case 32:
17 	case 64:
18 	case 128:
19 		valid = true;
20 		break;
21 	}
22 
23 	return valid;
24 }
25 
26 static inline enum vf_mode num_vfs_to_mode(int num_vfs)
27 {
28 	enum vf_mode mode = 0;
29 
30 	switch (num_vfs) {
31 	case 0:
32 		mode = __NDEV_MODE_PF;
33 		break;
34 	case 16:
35 		mode = __NDEV_MODE_VF16;
36 		break;
37 	case 32:
38 		mode = __NDEV_MODE_VF32;
39 		break;
40 	case 64:
41 		mode = __NDEV_MODE_VF64;
42 		break;
43 	case 128:
44 		mode = __NDEV_MODE_VF128;
45 		break;
46 	}
47 
48 	return mode;
49 }
50 
51 static void pf_sriov_cleanup(struct nitrox_device *ndev)
52 {
53 	 /* PF has no queues in SR-IOV mode */
54 	atomic_set(&ndev->state, __NDEV_NOT_READY);
55 	/* unregister crypto algorithms */
56 	nitrox_crypto_unregister();
57 
58 	/* cleanup PF resources */
59 	nitrox_unregister_interrupts(ndev);
60 	nitrox_common_sw_cleanup(ndev);
61 }
62 
63 static int pf_sriov_init(struct nitrox_device *ndev)
64 {
65 	int err;
66 
67 	/* allocate resources for PF */
68 	err = nitrox_common_sw_init(ndev);
69 	if (err)
70 		return err;
71 
72 	err = nitrox_register_interrupts(ndev);
73 	if (err) {
74 		nitrox_common_sw_cleanup(ndev);
75 		return err;
76 	}
77 
78 	/* configure the packet queues */
79 	nitrox_config_pkt_input_rings(ndev);
80 	nitrox_config_pkt_solicit_ports(ndev);
81 
82 	/* set device to ready state */
83 	atomic_set(&ndev->state, __NDEV_READY);
84 
85 	/* register crypto algorithms */
86 	return nitrox_crypto_register();
87 }
88 
89 static int nitrox_sriov_enable(struct pci_dev *pdev, int num_vfs)
90 {
91 	struct nitrox_device *ndev = pci_get_drvdata(pdev);
92 	int err;
93 
94 	if (!num_vfs_valid(num_vfs)) {
95 		dev_err(DEV(ndev), "Invalid num_vfs %d\n", num_vfs);
96 		return -EINVAL;
97 	}
98 
99 	if (pci_num_vf(pdev) == num_vfs)
100 		return num_vfs;
101 
102 	err = pci_enable_sriov(pdev, num_vfs);
103 	if (err) {
104 		dev_err(DEV(ndev), "failed to enable PCI sriov %d\n", err);
105 		return err;
106 	}
107 	dev_info(DEV(ndev), "Enabled VF(s) %d\n", num_vfs);
108 
109 	ndev->num_vfs = num_vfs;
110 	ndev->mode = num_vfs_to_mode(num_vfs);
111 	/* set bit in flags */
112 	set_bit(__NDEV_SRIOV_BIT, &ndev->flags);
113 
114 	/* cleanup PF resources */
115 	pf_sriov_cleanup(ndev);
116 
117 	config_nps_core_vfcfg_mode(ndev, ndev->mode);
118 
119 	return num_vfs;
120 }
121 
122 static int nitrox_sriov_disable(struct pci_dev *pdev)
123 {
124 	struct nitrox_device *ndev = pci_get_drvdata(pdev);
125 
126 	if (!test_bit(__NDEV_SRIOV_BIT, &ndev->flags))
127 		return 0;
128 
129 	if (pci_vfs_assigned(pdev)) {
130 		dev_warn(DEV(ndev), "VFs are attached to VM. Can't disable SR-IOV\n");
131 		return -EPERM;
132 	}
133 	pci_disable_sriov(pdev);
134 	/* clear bit in flags */
135 	clear_bit(__NDEV_SRIOV_BIT, &ndev->flags);
136 
137 	ndev->num_vfs = 0;
138 	ndev->mode = __NDEV_MODE_PF;
139 
140 	config_nps_core_vfcfg_mode(ndev, ndev->mode);
141 
142 	return pf_sriov_init(ndev);
143 }
144 
145 int nitrox_sriov_configure(struct pci_dev *pdev, int num_vfs)
146 {
147 	if (!num_vfs)
148 		return nitrox_sriov_disable(pdev);
149 
150 	return nitrox_sriov_enable(pdev, num_vfs);
151 }
152