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 | #include "nitrox_mbx.h" |
10 | |
11 | /** |
12 | * num_vfs_valid - validate VF count |
13 | * @num_vfs: number of VF(s) |
14 | */ |
15 | static inline bool num_vfs_valid(int num_vfs) |
16 | { |
17 | bool valid = false; |
18 | |
19 | switch (num_vfs) { |
20 | case 16: |
21 | case 32: |
22 | case 64: |
23 | case 128: |
24 | valid = true; |
25 | break; |
26 | } |
27 | |
28 | return valid; |
29 | } |
30 | |
31 | static inline enum vf_mode num_vfs_to_mode(int num_vfs) |
32 | { |
33 | enum vf_mode mode = 0; |
34 | |
35 | switch (num_vfs) { |
36 | case 0: |
37 | mode = __NDEV_MODE_PF; |
38 | break; |
39 | case 16: |
40 | mode = __NDEV_MODE_VF16; |
41 | break; |
42 | case 32: |
43 | mode = __NDEV_MODE_VF32; |
44 | break; |
45 | case 64: |
46 | mode = __NDEV_MODE_VF64; |
47 | break; |
48 | case 128: |
49 | mode = __NDEV_MODE_VF128; |
50 | break; |
51 | } |
52 | |
53 | return mode; |
54 | } |
55 | |
56 | static inline int vf_mode_to_nr_queues(enum vf_mode mode) |
57 | { |
58 | int nr_queues = 0; |
59 | |
60 | switch (mode) { |
61 | case __NDEV_MODE_PF: |
62 | nr_queues = MAX_PF_QUEUES; |
63 | break; |
64 | case __NDEV_MODE_VF16: |
65 | nr_queues = 8; |
66 | break; |
67 | case __NDEV_MODE_VF32: |
68 | nr_queues = 4; |
69 | break; |
70 | case __NDEV_MODE_VF64: |
71 | nr_queues = 2; |
72 | break; |
73 | case __NDEV_MODE_VF128: |
74 | nr_queues = 1; |
75 | break; |
76 | } |
77 | |
78 | return nr_queues; |
79 | } |
80 | |
81 | static void nitrox_pf_cleanup(struct nitrox_device *ndev) |
82 | { |
83 | /* PF has no queues in SR-IOV mode */ |
84 | atomic_set(v: &ndev->state, i: __NDEV_NOT_READY); |
85 | /* unregister crypto algorithms */ |
86 | nitrox_crypto_unregister(); |
87 | |
88 | /* cleanup PF resources */ |
89 | nitrox_unregister_interrupts(ndev); |
90 | nitrox_common_sw_cleanup(ndev); |
91 | } |
92 | |
93 | /** |
94 | * nitrox_pf_reinit - re-initialize PF resources once SR-IOV is disabled |
95 | * @ndev: NITROX device |
96 | */ |
97 | static int nitrox_pf_reinit(struct nitrox_device *ndev) |
98 | { |
99 | int err; |
100 | |
101 | /* allocate resources for PF */ |
102 | err = nitrox_common_sw_init(ndev); |
103 | if (err) |
104 | return err; |
105 | |
106 | err = nitrox_register_interrupts(ndev); |
107 | if (err) { |
108 | nitrox_common_sw_cleanup(ndev); |
109 | return err; |
110 | } |
111 | |
112 | /* configure the AQM queues */ |
113 | nitrox_config_aqm_rings(ndev); |
114 | |
115 | /* configure the packet queues */ |
116 | nitrox_config_pkt_input_rings(ndev); |
117 | nitrox_config_pkt_solicit_ports(ndev); |
118 | |
119 | /* set device to ready state */ |
120 | atomic_set(v: &ndev->state, i: __NDEV_READY); |
121 | |
122 | /* register crypto algorithms */ |
123 | return nitrox_crypto_register(); |
124 | } |
125 | |
126 | static void nitrox_sriov_cleanup(struct nitrox_device *ndev) |
127 | { |
128 | /* unregister interrupts for PF in SR-IOV */ |
129 | nitrox_sriov_unregister_interrupts(ndev); |
130 | nitrox_mbox_cleanup(ndev); |
131 | } |
132 | |
133 | static int nitrox_sriov_init(struct nitrox_device *ndev) |
134 | { |
135 | int ret; |
136 | |
137 | /* register interrupts for PF in SR-IOV */ |
138 | ret = nitrox_sriov_register_interupts(ndev); |
139 | if (ret) |
140 | return ret; |
141 | |
142 | ret = nitrox_mbox_init(ndev); |
143 | if (ret) |
144 | goto sriov_init_fail; |
145 | |
146 | return 0; |
147 | |
148 | sriov_init_fail: |
149 | nitrox_sriov_cleanup(ndev); |
150 | return ret; |
151 | } |
152 | |
153 | static int nitrox_sriov_enable(struct pci_dev *pdev, int num_vfs) |
154 | { |
155 | struct nitrox_device *ndev = pci_get_drvdata(pdev); |
156 | int err; |
157 | |
158 | if (!num_vfs_valid(num_vfs)) { |
159 | dev_err(DEV(ndev), "Invalid num_vfs %d\n" , num_vfs); |
160 | return -EINVAL; |
161 | } |
162 | |
163 | if (pci_num_vf(dev: pdev) == num_vfs) |
164 | return num_vfs; |
165 | |
166 | err = pci_enable_sriov(dev: pdev, nr_virtfn: num_vfs); |
167 | if (err) { |
168 | dev_err(DEV(ndev), "failed to enable PCI sriov %d\n" , err); |
169 | return err; |
170 | } |
171 | dev_info(DEV(ndev), "Enabled VF(s) %d\n" , num_vfs); |
172 | |
173 | ndev->mode = num_vfs_to_mode(num_vfs); |
174 | ndev->iov.num_vfs = num_vfs; |
175 | ndev->iov.max_vf_queues = vf_mode_to_nr_queues(mode: ndev->mode); |
176 | /* set bit in flags */ |
177 | set_bit(__NDEV_SRIOV_BIT, addr: &ndev->flags); |
178 | |
179 | /* cleanup PF resources */ |
180 | nitrox_pf_cleanup(ndev); |
181 | |
182 | /* PF SR-IOV mode initialization */ |
183 | err = nitrox_sriov_init(ndev); |
184 | if (err) |
185 | goto iov_fail; |
186 | |
187 | config_nps_core_vfcfg_mode(ndev, mode: ndev->mode); |
188 | return num_vfs; |
189 | |
190 | iov_fail: |
191 | pci_disable_sriov(dev: pdev); |
192 | /* clear bit in flags */ |
193 | clear_bit(__NDEV_SRIOV_BIT, addr: &ndev->flags); |
194 | ndev->iov.num_vfs = 0; |
195 | ndev->mode = __NDEV_MODE_PF; |
196 | /* reset back to working mode in PF */ |
197 | nitrox_pf_reinit(ndev); |
198 | return err; |
199 | } |
200 | |
201 | static int nitrox_sriov_disable(struct pci_dev *pdev) |
202 | { |
203 | struct nitrox_device *ndev = pci_get_drvdata(pdev); |
204 | |
205 | if (!test_bit(__NDEV_SRIOV_BIT, &ndev->flags)) |
206 | return 0; |
207 | |
208 | if (pci_vfs_assigned(dev: pdev)) { |
209 | dev_warn(DEV(ndev), "VFs are attached to VM. Can't disable SR-IOV\n" ); |
210 | return -EPERM; |
211 | } |
212 | pci_disable_sriov(dev: pdev); |
213 | /* clear bit in flags */ |
214 | clear_bit(__NDEV_SRIOV_BIT, addr: &ndev->flags); |
215 | |
216 | ndev->iov.num_vfs = 0; |
217 | ndev->iov.max_vf_queues = 0; |
218 | ndev->mode = __NDEV_MODE_PF; |
219 | |
220 | /* cleanup PF SR-IOV resources */ |
221 | nitrox_sriov_cleanup(ndev); |
222 | |
223 | config_nps_core_vfcfg_mode(ndev, mode: ndev->mode); |
224 | |
225 | return nitrox_pf_reinit(ndev); |
226 | } |
227 | |
228 | int nitrox_sriov_configure(struct pci_dev *pdev, int num_vfs) |
229 | { |
230 | if (!num_vfs) |
231 | return nitrox_sriov_disable(pdev); |
232 | |
233 | return nitrox_sriov_enable(pdev, num_vfs); |
234 | } |
235 | |