1 | // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) |
2 | /* QLogic qed NIC Driver |
3 | * Copyright (c) 2015-2017 QLogic Corporation |
4 | * Copyright (c) 2019-2020 Marvell International Ltd. |
5 | */ |
6 | |
7 | #include <linux/crc32.h> |
8 | #include <linux/etherdevice.h> |
9 | #include "qed.h" |
10 | #include "qed_sriov.h" |
11 | #include "qed_vf.h" |
12 | |
13 | static void *qed_vf_pf_prep(struct qed_hwfn *p_hwfn, u16 type, u16 length) |
14 | { |
15 | struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info; |
16 | void *p_tlv; |
17 | |
18 | /* This lock is released when we receive PF's response |
19 | * in qed_send_msg2pf(). |
20 | * So, qed_vf_pf_prep() and qed_send_msg2pf() |
21 | * must come in sequence. |
22 | */ |
23 | mutex_lock(&(p_iov->mutex)); |
24 | |
25 | DP_VERBOSE(p_hwfn, |
26 | QED_MSG_IOV, |
27 | "preparing to send 0x%04x tlv over vf pf channel\n" , |
28 | type); |
29 | |
30 | /* Reset Request offset */ |
31 | p_iov->offset = (u8 *)p_iov->vf2pf_request; |
32 | |
33 | /* Clear mailbox - both request and reply */ |
34 | memset(p_iov->vf2pf_request, 0, sizeof(union vfpf_tlvs)); |
35 | memset(p_iov->pf2vf_reply, 0, sizeof(union pfvf_tlvs)); |
36 | |
37 | /* Init type and length */ |
38 | p_tlv = qed_add_tlv(p_hwfn, offset: &p_iov->offset, type, length); |
39 | |
40 | /* Init first tlv header */ |
41 | ((struct vfpf_first_tlv *)p_tlv)->reply_address = |
42 | (u64)p_iov->pf2vf_reply_phys; |
43 | |
44 | return p_tlv; |
45 | } |
46 | |
47 | static void qed_vf_pf_req_end(struct qed_hwfn *p_hwfn, int req_status) |
48 | { |
49 | union pfvf_tlvs *resp = p_hwfn->vf_iov_info->pf2vf_reply; |
50 | |
51 | DP_VERBOSE(p_hwfn, QED_MSG_IOV, |
52 | "VF request status = 0x%x, PF reply status = 0x%x\n" , |
53 | req_status, resp->default_resp.hdr.status); |
54 | |
55 | mutex_unlock(lock: &(p_hwfn->vf_iov_info->mutex)); |
56 | } |
57 | |
58 | #define QED_VF_CHANNEL_USLEEP_ITERATIONS 90 |
59 | #define QED_VF_CHANNEL_USLEEP_DELAY 100 |
60 | #define QED_VF_CHANNEL_MSLEEP_ITERATIONS 10 |
61 | #define QED_VF_CHANNEL_MSLEEP_DELAY 25 |
62 | |
63 | static int qed_send_msg2pf(struct qed_hwfn *p_hwfn, u8 *done) |
64 | { |
65 | union vfpf_tlvs *p_req = p_hwfn->vf_iov_info->vf2pf_request; |
66 | struct ustorm_trigger_vf_zone trigger; |
67 | struct ustorm_vf_zone *zone_data; |
68 | int iter, rc = 0; |
69 | |
70 | zone_data = (struct ustorm_vf_zone *)PXP_VF_BAR0_START_USDM_ZONE_B; |
71 | |
72 | /* output tlvs list */ |
73 | qed_dp_tlv_list(p_hwfn, tlvs_list: p_req); |
74 | |
75 | /* Send TLVs over HW channel */ |
76 | memset(&trigger, 0, sizeof(struct ustorm_trigger_vf_zone)); |
77 | trigger.vf_pf_msg_valid = 1; |
78 | |
79 | DP_VERBOSE(p_hwfn, |
80 | QED_MSG_IOV, |
81 | "VF -> PF [%02x] message: [%08x, %08x] --> %p, %08x --> %p\n" , |
82 | GET_FIELD(p_hwfn->hw_info.concrete_fid, |
83 | PXP_CONCRETE_FID_PFID), |
84 | upper_32_bits(p_hwfn->vf_iov_info->vf2pf_request_phys), |
85 | lower_32_bits(p_hwfn->vf_iov_info->vf2pf_request_phys), |
86 | &zone_data->non_trigger.vf_pf_msg_addr, |
87 | *((u32 *)&trigger), &zone_data->trigger); |
88 | |
89 | REG_WR(p_hwfn, |
90 | (uintptr_t)&zone_data->non_trigger.vf_pf_msg_addr.lo, |
91 | lower_32_bits(p_hwfn->vf_iov_info->vf2pf_request_phys)); |
92 | |
93 | REG_WR(p_hwfn, |
94 | (uintptr_t)&zone_data->non_trigger.vf_pf_msg_addr.hi, |
95 | upper_32_bits(p_hwfn->vf_iov_info->vf2pf_request_phys)); |
96 | |
97 | /* The message data must be written first, to prevent trigger before |
98 | * data is written. |
99 | */ |
100 | wmb(); |
101 | |
102 | REG_WR(p_hwfn, (uintptr_t)&zone_data->trigger, *((u32 *)&trigger)); |
103 | |
104 | /* When PF would be done with the response, it would write back to the |
105 | * `done' address from a coherent DMA zone. Poll until then. |
106 | */ |
107 | |
108 | iter = QED_VF_CHANNEL_USLEEP_ITERATIONS; |
109 | while (!*done && iter--) { |
110 | udelay(QED_VF_CHANNEL_USLEEP_DELAY); |
111 | dma_rmb(); |
112 | } |
113 | |
114 | iter = QED_VF_CHANNEL_MSLEEP_ITERATIONS; |
115 | while (!*done && iter--) { |
116 | msleep(QED_VF_CHANNEL_MSLEEP_DELAY); |
117 | dma_rmb(); |
118 | } |
119 | |
120 | if (!*done) { |
121 | DP_NOTICE(p_hwfn, |
122 | "VF <-- PF Timeout [Type %d]\n" , |
123 | p_req->first_tlv.tl.type); |
124 | rc = -EBUSY; |
125 | } else { |
126 | if ((*done != PFVF_STATUS_SUCCESS) && |
127 | (*done != PFVF_STATUS_NO_RESOURCE)) |
128 | DP_NOTICE(p_hwfn, |
129 | "PF response: %d [Type %d]\n" , |
130 | *done, p_req->first_tlv.tl.type); |
131 | else |
132 | DP_VERBOSE(p_hwfn, QED_MSG_IOV, |
133 | "PF response: %d [Type %d]\n" , |
134 | *done, p_req->first_tlv.tl.type); |
135 | } |
136 | |
137 | return rc; |
138 | } |
139 | |
140 | static void qed_vf_pf_add_qid(struct qed_hwfn *p_hwfn, |
141 | struct qed_queue_cid *p_cid) |
142 | { |
143 | struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info; |
144 | struct vfpf_qid_tlv *p_qid_tlv; |
145 | |
146 | /* Only add QIDs for the queue if it was negotiated with PF */ |
147 | if (!(p_iov->acquire_resp.pfdev_info.capabilities & |
148 | PFVF_ACQUIRE_CAP_QUEUE_QIDS)) |
149 | return; |
150 | |
151 | p_qid_tlv = qed_add_tlv(p_hwfn, offset: &p_iov->offset, |
152 | type: CHANNEL_TLV_QID, length: sizeof(*p_qid_tlv)); |
153 | p_qid_tlv->qid = p_cid->qid_usage_idx; |
154 | } |
155 | |
156 | static int _qed_vf_pf_release(struct qed_hwfn *p_hwfn, bool b_final) |
157 | { |
158 | struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info; |
159 | struct pfvf_def_resp_tlv *resp; |
160 | struct vfpf_first_tlv *req; |
161 | u32 size; |
162 | int rc; |
163 | |
164 | /* clear mailbox and prep first tlv */ |
165 | req = qed_vf_pf_prep(p_hwfn, type: CHANNEL_TLV_RELEASE, length: sizeof(*req)); |
166 | |
167 | /* add list termination tlv */ |
168 | qed_add_tlv(p_hwfn, offset: &p_iov->offset, |
169 | type: CHANNEL_TLV_LIST_END, length: sizeof(struct channel_list_end_tlv)); |
170 | |
171 | resp = &p_iov->pf2vf_reply->default_resp; |
172 | rc = qed_send_msg2pf(p_hwfn, done: &resp->hdr.status); |
173 | |
174 | if (!rc && resp->hdr.status != PFVF_STATUS_SUCCESS) |
175 | rc = -EAGAIN; |
176 | |
177 | qed_vf_pf_req_end(p_hwfn, req_status: rc); |
178 | if (!b_final) |
179 | return rc; |
180 | |
181 | p_hwfn->b_int_enabled = 0; |
182 | |
183 | if (p_iov->vf2pf_request) |
184 | dma_free_coherent(dev: &p_hwfn->cdev->pdev->dev, |
185 | size: sizeof(union vfpf_tlvs), |
186 | cpu_addr: p_iov->vf2pf_request, |
187 | dma_handle: p_iov->vf2pf_request_phys); |
188 | if (p_iov->pf2vf_reply) |
189 | dma_free_coherent(dev: &p_hwfn->cdev->pdev->dev, |
190 | size: sizeof(union pfvf_tlvs), |
191 | cpu_addr: p_iov->pf2vf_reply, dma_handle: p_iov->pf2vf_reply_phys); |
192 | |
193 | if (p_iov->bulletin.p_virt) { |
194 | size = sizeof(struct qed_bulletin_content); |
195 | dma_free_coherent(dev: &p_hwfn->cdev->pdev->dev, |
196 | size, |
197 | cpu_addr: p_iov->bulletin.p_virt, dma_handle: p_iov->bulletin.phys); |
198 | } |
199 | |
200 | kfree(objp: p_hwfn->vf_iov_info); |
201 | p_hwfn->vf_iov_info = NULL; |
202 | |
203 | return rc; |
204 | } |
205 | |
206 | int qed_vf_pf_release(struct qed_hwfn *p_hwfn) |
207 | { |
208 | return _qed_vf_pf_release(p_hwfn, b_final: true); |
209 | } |
210 | |
211 | #define VF_ACQUIRE_THRESH 3 |
212 | static void qed_vf_pf_acquire_reduce_resc(struct qed_hwfn *p_hwfn, |
213 | struct vf_pf_resc_request *p_req, |
214 | struct pf_vf_resc *p_resp) |
215 | { |
216 | DP_VERBOSE(p_hwfn, |
217 | QED_MSG_IOV, |
218 | "PF unwilling to fulfill resource request: rxq [%02x/%02x] txq [%02x/%02x] sbs [%02x/%02x] mac [%02x/%02x] vlan [%02x/%02x] mc [%02x/%02x] cids [%02x/%02x]. Try PF recommended amount\n" , |
219 | p_req->num_rxqs, |
220 | p_resp->num_rxqs, |
221 | p_req->num_rxqs, |
222 | p_resp->num_txqs, |
223 | p_req->num_sbs, |
224 | p_resp->num_sbs, |
225 | p_req->num_mac_filters, |
226 | p_resp->num_mac_filters, |
227 | p_req->num_vlan_filters, |
228 | p_resp->num_vlan_filters, |
229 | p_req->num_mc_filters, |
230 | p_resp->num_mc_filters, p_req->num_cids, p_resp->num_cids); |
231 | |
232 | /* humble our request */ |
233 | p_req->num_txqs = p_resp->num_txqs; |
234 | p_req->num_rxqs = p_resp->num_rxqs; |
235 | p_req->num_sbs = p_resp->num_sbs; |
236 | p_req->num_mac_filters = p_resp->num_mac_filters; |
237 | p_req->num_vlan_filters = p_resp->num_vlan_filters; |
238 | p_req->num_mc_filters = p_resp->num_mc_filters; |
239 | p_req->num_cids = p_resp->num_cids; |
240 | } |
241 | |
242 | static int qed_vf_pf_acquire(struct qed_hwfn *p_hwfn) |
243 | { |
244 | struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info; |
245 | struct pfvf_acquire_resp_tlv *resp = &p_iov->pf2vf_reply->acquire_resp; |
246 | struct pf_vf_pfdev_info *pfdev_info = &resp->pfdev_info; |
247 | struct vf_pf_resc_request *p_resc; |
248 | u8 retry_cnt = VF_ACQUIRE_THRESH; |
249 | bool resources_acquired = false; |
250 | struct vfpf_acquire_tlv *req; |
251 | int rc = 0, attempts = 0; |
252 | |
253 | /* clear mailbox and prep first tlv */ |
254 | req = qed_vf_pf_prep(p_hwfn, type: CHANNEL_TLV_ACQUIRE, length: sizeof(*req)); |
255 | p_resc = &req->resc_request; |
256 | |
257 | /* starting filling the request */ |
258 | req->vfdev_info.opaque_fid = p_hwfn->hw_info.opaque_fid; |
259 | |
260 | p_resc->num_rxqs = QED_MAX_VF_CHAINS_PER_PF; |
261 | p_resc->num_txqs = QED_MAX_VF_CHAINS_PER_PF; |
262 | p_resc->num_sbs = QED_MAX_VF_CHAINS_PER_PF; |
263 | p_resc->num_mac_filters = QED_ETH_VF_NUM_MAC_FILTERS; |
264 | p_resc->num_vlan_filters = QED_ETH_VF_NUM_VLAN_FILTERS; |
265 | p_resc->num_cids = QED_ETH_VF_DEFAULT_NUM_CIDS; |
266 | |
267 | req->vfdev_info.os_type = VFPF_ACQUIRE_OS_LINUX; |
268 | req->vfdev_info.fw_major = FW_MAJOR_VERSION; |
269 | req->vfdev_info.fw_minor = FW_MINOR_VERSION; |
270 | req->vfdev_info.fw_revision = FW_REVISION_VERSION; |
271 | req->vfdev_info.fw_engineering = FW_ENGINEERING_VERSION; |
272 | req->vfdev_info.eth_fp_hsi_major = ETH_HSI_VER_MAJOR; |
273 | req->vfdev_info.eth_fp_hsi_minor = ETH_HSI_VER_MINOR; |
274 | |
275 | /* Fill capability field with any non-deprecated config we support */ |
276 | req->vfdev_info.capabilities |= VFPF_ACQUIRE_CAP_100G; |
277 | |
278 | /* If we've mapped the doorbell bar, try using queue qids */ |
279 | if (p_iov->b_doorbell_bar) { |
280 | req->vfdev_info.capabilities |= VFPF_ACQUIRE_CAP_PHYSICAL_BAR | |
281 | VFPF_ACQUIRE_CAP_QUEUE_QIDS; |
282 | p_resc->num_cids = QED_ETH_VF_MAX_NUM_CIDS; |
283 | } |
284 | |
285 | /* pf 2 vf bulletin board address */ |
286 | req->bulletin_addr = p_iov->bulletin.phys; |
287 | req->bulletin_size = p_iov->bulletin.size; |
288 | |
289 | /* add list termination tlv */ |
290 | qed_add_tlv(p_hwfn, offset: &p_iov->offset, |
291 | type: CHANNEL_TLV_LIST_END, length: sizeof(struct channel_list_end_tlv)); |
292 | |
293 | while (!resources_acquired) { |
294 | DP_VERBOSE(p_hwfn, |
295 | QED_MSG_IOV, "attempting to acquire resources\n" ); |
296 | |
297 | /* Clear response buffer, as this might be a re-send */ |
298 | memset(p_iov->pf2vf_reply, 0, sizeof(union pfvf_tlvs)); |
299 | |
300 | /* send acquire request */ |
301 | rc = qed_send_msg2pf(p_hwfn, done: &resp->hdr.status); |
302 | |
303 | /* Re-try acquire in case of vf-pf hw channel timeout */ |
304 | if (retry_cnt && rc == -EBUSY) { |
305 | DP_VERBOSE(p_hwfn, QED_MSG_IOV, |
306 | "VF retrying to acquire due to VPC timeout\n" ); |
307 | retry_cnt--; |
308 | continue; |
309 | } |
310 | |
311 | if (rc) |
312 | goto exit; |
313 | |
314 | /* copy acquire response from buffer to p_hwfn */ |
315 | memcpy(&p_iov->acquire_resp, resp, sizeof(p_iov->acquire_resp)); |
316 | |
317 | attempts++; |
318 | |
319 | if (resp->hdr.status == PFVF_STATUS_SUCCESS) { |
320 | /* PF agrees to allocate our resources */ |
321 | if (!(resp->pfdev_info.capabilities & |
322 | PFVF_ACQUIRE_CAP_POST_FW_OVERRIDE)) { |
323 | /* It's possible legacy PF mistakenly accepted; |
324 | * but we don't care - simply mark it as |
325 | * legacy and continue. |
326 | */ |
327 | req->vfdev_info.capabilities |= |
328 | VFPF_ACQUIRE_CAP_PRE_FP_HSI; |
329 | } |
330 | DP_VERBOSE(p_hwfn, QED_MSG_IOV, "resources acquired\n" ); |
331 | resources_acquired = true; |
332 | } else if (resp->hdr.status == PFVF_STATUS_NO_RESOURCE && |
333 | attempts < VF_ACQUIRE_THRESH) { |
334 | qed_vf_pf_acquire_reduce_resc(p_hwfn, p_req: p_resc, |
335 | p_resp: &resp->resc); |
336 | } else if (resp->hdr.status == PFVF_STATUS_NOT_SUPPORTED) { |
337 | if (pfdev_info->major_fp_hsi && |
338 | (pfdev_info->major_fp_hsi != ETH_HSI_VER_MAJOR)) { |
339 | DP_NOTICE(p_hwfn, |
340 | "PF uses an incompatible fastpath HSI %02x.%02x [VF requires %02x.%02x]. Please change to a VF driver using %02x.xx.\n" , |
341 | pfdev_info->major_fp_hsi, |
342 | pfdev_info->minor_fp_hsi, |
343 | ETH_HSI_VER_MAJOR, |
344 | ETH_HSI_VER_MINOR, |
345 | pfdev_info->major_fp_hsi); |
346 | rc = -EINVAL; |
347 | goto exit; |
348 | } |
349 | |
350 | if (!pfdev_info->major_fp_hsi) { |
351 | if (req->vfdev_info.capabilities & |
352 | VFPF_ACQUIRE_CAP_PRE_FP_HSI) { |
353 | DP_NOTICE(p_hwfn, |
354 | "PF uses very old drivers. Please change to a VF driver using no later than 8.8.x.x.\n" ); |
355 | rc = -EINVAL; |
356 | goto exit; |
357 | } else { |
358 | DP_INFO(p_hwfn, |
359 | "PF is old - try re-acquire to see if it supports FW-version override\n" ); |
360 | req->vfdev_info.capabilities |= |
361 | VFPF_ACQUIRE_CAP_PRE_FP_HSI; |
362 | continue; |
363 | } |
364 | } |
365 | |
366 | /* If PF/VF are using same Major, PF must have had |
367 | * it's reasons. Simply fail. |
368 | */ |
369 | DP_NOTICE(p_hwfn, "PF rejected acquisition by VF\n" ); |
370 | rc = -EINVAL; |
371 | goto exit; |
372 | } else { |
373 | DP_ERR(p_hwfn, |
374 | "PF returned error %d to VF acquisition request\n" , |
375 | resp->hdr.status); |
376 | rc = -EAGAIN; |
377 | goto exit; |
378 | } |
379 | } |
380 | |
381 | /* Mark the PF as legacy, if needed */ |
382 | if (req->vfdev_info.capabilities & VFPF_ACQUIRE_CAP_PRE_FP_HSI) |
383 | p_iov->b_pre_fp_hsi = true; |
384 | |
385 | /* In case PF doesn't support multi-queue Tx, update the number of |
386 | * CIDs to reflect the number of queues [older PFs didn't fill that |
387 | * field]. |
388 | */ |
389 | if (!(resp->pfdev_info.capabilities & PFVF_ACQUIRE_CAP_QUEUE_QIDS)) |
390 | resp->resc.num_cids = resp->resc.num_rxqs + resp->resc.num_txqs; |
391 | |
392 | /* Update bulletin board size with response from PF */ |
393 | p_iov->bulletin.size = resp->bulletin_size; |
394 | |
395 | /* get HW info */ |
396 | p_hwfn->cdev->type = resp->pfdev_info.dev_type; |
397 | p_hwfn->cdev->chip_rev = resp->pfdev_info.chip_rev; |
398 | |
399 | p_hwfn->cdev->chip_num = pfdev_info->chip_num & 0xffff; |
400 | |
401 | /* Learn of the possibility of CMT */ |
402 | if (IS_LEAD_HWFN(p_hwfn)) { |
403 | if (resp->pfdev_info.capabilities & PFVF_ACQUIRE_CAP_100G) { |
404 | DP_NOTICE(p_hwfn, "100g VF\n" ); |
405 | p_hwfn->cdev->num_hwfns = 2; |
406 | } |
407 | } |
408 | |
409 | if (!p_iov->b_pre_fp_hsi && |
410 | (resp->pfdev_info.minor_fp_hsi < ETH_HSI_VER_MINOR)) { |
411 | DP_INFO(p_hwfn, |
412 | "PF is using older fastpath HSI; %02x.%02x is configured\n" , |
413 | ETH_HSI_VER_MAJOR, resp->pfdev_info.minor_fp_hsi); |
414 | } |
415 | |
416 | exit: |
417 | qed_vf_pf_req_end(p_hwfn, req_status: rc); |
418 | |
419 | return rc; |
420 | } |
421 | |
422 | u32 qed_vf_hw_bar_size(struct qed_hwfn *p_hwfn, enum BAR_ID bar_id) |
423 | { |
424 | u32 bar_size; |
425 | |
426 | /* Regview size is fixed */ |
427 | if (bar_id == BAR_ID_0) |
428 | return 1 << 17; |
429 | |
430 | /* Doorbell is received from PF */ |
431 | bar_size = p_hwfn->vf_iov_info->acquire_resp.pfdev_info.bar_size; |
432 | if (bar_size) |
433 | return 1 << bar_size; |
434 | return 0; |
435 | } |
436 | |
437 | int qed_vf_hw_prepare(struct qed_hwfn *p_hwfn) |
438 | { |
439 | struct qed_hwfn *p_lead = QED_LEADING_HWFN(p_hwfn->cdev); |
440 | struct qed_vf_iov *p_iov; |
441 | u32 reg; |
442 | int rc; |
443 | |
444 | /* Set number of hwfns - might be overridden once leading hwfn learns |
445 | * actual configuration from PF. |
446 | */ |
447 | if (IS_LEAD_HWFN(p_hwfn)) |
448 | p_hwfn->cdev->num_hwfns = 1; |
449 | |
450 | reg = PXP_VF_BAR0_ME_OPAQUE_ADDRESS; |
451 | p_hwfn->hw_info.opaque_fid = (u16)REG_RD(p_hwfn, reg); |
452 | |
453 | reg = PXP_VF_BAR0_ME_CONCRETE_ADDRESS; |
454 | p_hwfn->hw_info.concrete_fid = REG_RD(p_hwfn, reg); |
455 | |
456 | /* Allocate vf sriov info */ |
457 | p_iov = kzalloc(size: sizeof(*p_iov), GFP_KERNEL); |
458 | if (!p_iov) |
459 | return -ENOMEM; |
460 | |
461 | /* Doorbells are tricky; Upper-layer has alreday set the hwfn doorbell |
462 | * value, but there are several incompatibily scenarios where that |
463 | * would be incorrect and we'd need to override it. |
464 | */ |
465 | if (!p_hwfn->doorbells) { |
466 | p_hwfn->doorbells = (u8 __iomem *)p_hwfn->regview + |
467 | PXP_VF_BAR0_START_DQ; |
468 | } else if (p_hwfn == p_lead) { |
469 | /* For leading hw-function, value is always correct, but need |
470 | * to handle scenario where legacy PF would not support 100g |
471 | * mapped bars later. |
472 | */ |
473 | p_iov->b_doorbell_bar = true; |
474 | } else { |
475 | /* here, value would be correct ONLY if the leading hwfn |
476 | * received indication that mapped-bars are supported. |
477 | */ |
478 | if (p_lead->vf_iov_info->b_doorbell_bar) |
479 | p_iov->b_doorbell_bar = true; |
480 | else |
481 | p_hwfn->doorbells = (u8 __iomem *) |
482 | p_hwfn->regview + PXP_VF_BAR0_START_DQ; |
483 | } |
484 | |
485 | /* Allocate vf2pf msg */ |
486 | p_iov->vf2pf_request = dma_alloc_coherent(dev: &p_hwfn->cdev->pdev->dev, |
487 | size: sizeof(union vfpf_tlvs), |
488 | dma_handle: &p_iov->vf2pf_request_phys, |
489 | GFP_KERNEL); |
490 | if (!p_iov->vf2pf_request) |
491 | goto free_p_iov; |
492 | |
493 | p_iov->pf2vf_reply = dma_alloc_coherent(dev: &p_hwfn->cdev->pdev->dev, |
494 | size: sizeof(union pfvf_tlvs), |
495 | dma_handle: &p_iov->pf2vf_reply_phys, |
496 | GFP_KERNEL); |
497 | if (!p_iov->pf2vf_reply) |
498 | goto free_vf2pf_request; |
499 | |
500 | DP_VERBOSE(p_hwfn, |
501 | QED_MSG_IOV, |
502 | "VF's Request mailbox [%p virt 0x%llx phys], Response mailbox [%p virt 0x%llx phys]\n" , |
503 | p_iov->vf2pf_request, |
504 | (u64)p_iov->vf2pf_request_phys, |
505 | p_iov->pf2vf_reply, (u64)p_iov->pf2vf_reply_phys); |
506 | |
507 | /* Allocate Bulletin board */ |
508 | p_iov->bulletin.size = sizeof(struct qed_bulletin_content); |
509 | p_iov->bulletin.p_virt = dma_alloc_coherent(dev: &p_hwfn->cdev->pdev->dev, |
510 | size: p_iov->bulletin.size, |
511 | dma_handle: &p_iov->bulletin.phys, |
512 | GFP_KERNEL); |
513 | if (!p_iov->bulletin.p_virt) |
514 | goto free_pf2vf_reply; |
515 | |
516 | DP_VERBOSE(p_hwfn, QED_MSG_IOV, |
517 | "VF's bulletin Board [%p virt 0x%llx phys 0x%08x bytes]\n" , |
518 | p_iov->bulletin.p_virt, |
519 | (u64)p_iov->bulletin.phys, p_iov->bulletin.size); |
520 | |
521 | mutex_init(&p_iov->mutex); |
522 | |
523 | p_hwfn->vf_iov_info = p_iov; |
524 | |
525 | p_hwfn->hw_info.personality = QED_PCI_ETH; |
526 | |
527 | rc = qed_vf_pf_acquire(p_hwfn); |
528 | |
529 | /* If VF is 100g using a mapped bar and PF is too old to support that, |
530 | * acquisition would succeed - but the VF would have no way knowing |
531 | * the size of the doorbell bar configured in HW and thus will not |
532 | * know how to split it for 2nd hw-function. |
533 | * In this case we re-try without the indication of the mapped |
534 | * doorbell. |
535 | */ |
536 | if (!rc && p_iov->b_doorbell_bar && |
537 | !qed_vf_hw_bar_size(p_hwfn, bar_id: BAR_ID_1) && |
538 | (p_hwfn->cdev->num_hwfns > 1)) { |
539 | rc = _qed_vf_pf_release(p_hwfn, b_final: false); |
540 | if (rc) |
541 | return rc; |
542 | |
543 | p_iov->b_doorbell_bar = false; |
544 | p_hwfn->doorbells = (u8 __iomem *)p_hwfn->regview + |
545 | PXP_VF_BAR0_START_DQ; |
546 | rc = qed_vf_pf_acquire(p_hwfn); |
547 | } |
548 | |
549 | DP_VERBOSE(p_hwfn, QED_MSG_IOV, |
550 | "Regview [%p], Doorbell [%p], Device-doorbell [%p]\n" , |
551 | p_hwfn->regview, p_hwfn->doorbells, p_hwfn->cdev->doorbells); |
552 | |
553 | return rc; |
554 | |
555 | free_pf2vf_reply: |
556 | dma_free_coherent(dev: &p_hwfn->cdev->pdev->dev, |
557 | size: sizeof(union pfvf_tlvs), |
558 | cpu_addr: p_iov->pf2vf_reply, dma_handle: p_iov->pf2vf_reply_phys); |
559 | free_vf2pf_request: |
560 | dma_free_coherent(dev: &p_hwfn->cdev->pdev->dev, |
561 | size: sizeof(union vfpf_tlvs), |
562 | cpu_addr: p_iov->vf2pf_request, dma_handle: p_iov->vf2pf_request_phys); |
563 | free_p_iov: |
564 | kfree(objp: p_iov); |
565 | |
566 | return -ENOMEM; |
567 | } |
568 | |
569 | #define TSTORM_QZONE_START PXP_VF_BAR0_START_SDM_ZONE_A |
570 | #define MSTORM_QZONE_START(dev) (TSTORM_QZONE_START + \ |
571 | (TSTORM_QZONE_SIZE * NUM_OF_L2_QUEUES(dev))) |
572 | |
573 | static void |
574 | __qed_vf_prep_tunn_req_tlv(struct vfpf_update_tunn_param_tlv *p_req, |
575 | struct qed_tunn_update_type *p_src, |
576 | enum qed_tunn_mode mask, u8 *p_cls) |
577 | { |
578 | if (p_src->b_update_mode) { |
579 | p_req->tun_mode_update_mask |= BIT(mask); |
580 | |
581 | if (p_src->b_mode_enabled) |
582 | p_req->tunn_mode |= BIT(mask); |
583 | } |
584 | |
585 | *p_cls = p_src->tun_cls; |
586 | } |
587 | |
588 | static void |
589 | qed_vf_prep_tunn_req_tlv(struct vfpf_update_tunn_param_tlv *p_req, |
590 | struct qed_tunn_update_type *p_src, |
591 | enum qed_tunn_mode mask, |
592 | u8 *p_cls, struct qed_tunn_update_udp_port *p_port, |
593 | u8 *p_update_port, u16 *p_udp_port) |
594 | { |
595 | if (p_port->b_update_port) { |
596 | *p_update_port = 1; |
597 | *p_udp_port = p_port->port; |
598 | } |
599 | |
600 | __qed_vf_prep_tunn_req_tlv(p_req, p_src, mask, p_cls); |
601 | } |
602 | |
603 | void qed_vf_set_vf_start_tunn_update_param(struct qed_tunnel_info *p_tun) |
604 | { |
605 | if (p_tun->vxlan.b_mode_enabled) |
606 | p_tun->vxlan.b_update_mode = true; |
607 | if (p_tun->l2_geneve.b_mode_enabled) |
608 | p_tun->l2_geneve.b_update_mode = true; |
609 | if (p_tun->ip_geneve.b_mode_enabled) |
610 | p_tun->ip_geneve.b_update_mode = true; |
611 | if (p_tun->l2_gre.b_mode_enabled) |
612 | p_tun->l2_gre.b_update_mode = true; |
613 | if (p_tun->ip_gre.b_mode_enabled) |
614 | p_tun->ip_gre.b_update_mode = true; |
615 | |
616 | p_tun->b_update_rx_cls = true; |
617 | p_tun->b_update_tx_cls = true; |
618 | } |
619 | |
620 | static void |
621 | __qed_vf_update_tunn_param(struct qed_tunn_update_type *p_tun, |
622 | u16 feature_mask, u8 tunn_mode, |
623 | u8 tunn_cls, enum qed_tunn_mode val) |
624 | { |
625 | if (feature_mask & BIT(val)) { |
626 | p_tun->b_mode_enabled = tunn_mode; |
627 | p_tun->tun_cls = tunn_cls; |
628 | } else { |
629 | p_tun->b_mode_enabled = false; |
630 | } |
631 | } |
632 | |
633 | static void qed_vf_update_tunn_param(struct qed_hwfn *p_hwfn, |
634 | struct qed_tunnel_info *p_tun, |
635 | struct pfvf_update_tunn_param_tlv *p_resp) |
636 | { |
637 | /* Update mode and classes provided by PF */ |
638 | u16 feat_mask = p_resp->tunn_feature_mask; |
639 | |
640 | __qed_vf_update_tunn_param(p_tun: &p_tun->vxlan, feature_mask: feat_mask, |
641 | tunn_mode: p_resp->vxlan_mode, tunn_cls: p_resp->vxlan_clss, |
642 | val: QED_MODE_VXLAN_TUNN); |
643 | __qed_vf_update_tunn_param(p_tun: &p_tun->l2_geneve, feature_mask: feat_mask, |
644 | tunn_mode: p_resp->l2geneve_mode, |
645 | tunn_cls: p_resp->l2geneve_clss, |
646 | val: QED_MODE_L2GENEVE_TUNN); |
647 | __qed_vf_update_tunn_param(p_tun: &p_tun->ip_geneve, feature_mask: feat_mask, |
648 | tunn_mode: p_resp->ipgeneve_mode, |
649 | tunn_cls: p_resp->ipgeneve_clss, |
650 | val: QED_MODE_IPGENEVE_TUNN); |
651 | __qed_vf_update_tunn_param(p_tun: &p_tun->l2_gre, feature_mask: feat_mask, |
652 | tunn_mode: p_resp->l2gre_mode, tunn_cls: p_resp->l2gre_clss, |
653 | val: QED_MODE_L2GRE_TUNN); |
654 | __qed_vf_update_tunn_param(p_tun: &p_tun->ip_gre, feature_mask: feat_mask, |
655 | tunn_mode: p_resp->ipgre_mode, tunn_cls: p_resp->ipgre_clss, |
656 | val: QED_MODE_IPGRE_TUNN); |
657 | p_tun->geneve_port.port = p_resp->geneve_udp_port; |
658 | p_tun->vxlan_port.port = p_resp->vxlan_udp_port; |
659 | |
660 | DP_VERBOSE(p_hwfn, QED_MSG_IOV, |
661 | "tunn mode: vxlan=0x%x, l2geneve=0x%x, ipgeneve=0x%x, l2gre=0x%x, ipgre=0x%x" , |
662 | p_tun->vxlan.b_mode_enabled, p_tun->l2_geneve.b_mode_enabled, |
663 | p_tun->ip_geneve.b_mode_enabled, |
664 | p_tun->l2_gre.b_mode_enabled, p_tun->ip_gre.b_mode_enabled); |
665 | } |
666 | |
667 | int qed_vf_pf_tunnel_param_update(struct qed_hwfn *p_hwfn, |
668 | struct qed_tunnel_info *p_src) |
669 | { |
670 | struct qed_tunnel_info *p_tun = &p_hwfn->cdev->tunnel; |
671 | struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info; |
672 | struct pfvf_update_tunn_param_tlv *p_resp; |
673 | struct vfpf_update_tunn_param_tlv *p_req; |
674 | int rc; |
675 | |
676 | p_req = qed_vf_pf_prep(p_hwfn, type: CHANNEL_TLV_UPDATE_TUNN_PARAM, |
677 | length: sizeof(*p_req)); |
678 | |
679 | if (p_src->b_update_rx_cls && p_src->b_update_tx_cls) |
680 | p_req->update_tun_cls = 1; |
681 | |
682 | qed_vf_prep_tunn_req_tlv(p_req, p_src: &p_src->vxlan, mask: QED_MODE_VXLAN_TUNN, |
683 | p_cls: &p_req->vxlan_clss, p_port: &p_src->vxlan_port, |
684 | p_update_port: &p_req->update_vxlan_port, |
685 | p_udp_port: &p_req->vxlan_port); |
686 | qed_vf_prep_tunn_req_tlv(p_req, p_src: &p_src->l2_geneve, |
687 | mask: QED_MODE_L2GENEVE_TUNN, |
688 | p_cls: &p_req->l2geneve_clss, p_port: &p_src->geneve_port, |
689 | p_update_port: &p_req->update_geneve_port, |
690 | p_udp_port: &p_req->geneve_port); |
691 | __qed_vf_prep_tunn_req_tlv(p_req, p_src: &p_src->ip_geneve, |
692 | mask: QED_MODE_IPGENEVE_TUNN, |
693 | p_cls: &p_req->ipgeneve_clss); |
694 | __qed_vf_prep_tunn_req_tlv(p_req, p_src: &p_src->l2_gre, |
695 | mask: QED_MODE_L2GRE_TUNN, p_cls: &p_req->l2gre_clss); |
696 | __qed_vf_prep_tunn_req_tlv(p_req, p_src: &p_src->ip_gre, |
697 | mask: QED_MODE_IPGRE_TUNN, p_cls: &p_req->ipgre_clss); |
698 | |
699 | /* add list termination tlv */ |
700 | qed_add_tlv(p_hwfn, offset: &p_iov->offset, |
701 | type: CHANNEL_TLV_LIST_END, |
702 | length: sizeof(struct channel_list_end_tlv)); |
703 | |
704 | p_resp = &p_iov->pf2vf_reply->tunn_param_resp; |
705 | rc = qed_send_msg2pf(p_hwfn, done: &p_resp->hdr.status); |
706 | |
707 | if (rc) |
708 | goto exit; |
709 | |
710 | if (p_resp->hdr.status != PFVF_STATUS_SUCCESS) { |
711 | DP_VERBOSE(p_hwfn, QED_MSG_IOV, |
712 | "Failed to update tunnel parameters\n" ); |
713 | rc = -EINVAL; |
714 | } |
715 | |
716 | qed_vf_update_tunn_param(p_hwfn, p_tun, p_resp); |
717 | exit: |
718 | qed_vf_pf_req_end(p_hwfn, req_status: rc); |
719 | return rc; |
720 | } |
721 | |
722 | int |
723 | qed_vf_pf_rxq_start(struct qed_hwfn *p_hwfn, |
724 | struct qed_queue_cid *p_cid, |
725 | u16 bd_max_bytes, |
726 | dma_addr_t bd_chain_phys_addr, |
727 | dma_addr_t cqe_pbl_addr, |
728 | u16 cqe_pbl_size, void __iomem **pp_prod) |
729 | { |
730 | struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info; |
731 | struct pfvf_start_queue_resp_tlv *resp; |
732 | struct vfpf_start_rxq_tlv *req; |
733 | u8 rx_qid = p_cid->rel.queue_id; |
734 | int rc; |
735 | |
736 | /* clear mailbox and prep first tlv */ |
737 | req = qed_vf_pf_prep(p_hwfn, type: CHANNEL_TLV_START_RXQ, length: sizeof(*req)); |
738 | |
739 | req->rx_qid = rx_qid; |
740 | req->cqe_pbl_addr = cqe_pbl_addr; |
741 | req->cqe_pbl_size = cqe_pbl_size; |
742 | req->rxq_addr = bd_chain_phys_addr; |
743 | req->hw_sb = p_cid->sb_igu_id; |
744 | req->sb_index = p_cid->sb_idx; |
745 | req->bd_max_bytes = bd_max_bytes; |
746 | req->stat_id = -1; |
747 | |
748 | /* If PF is legacy, we'll need to calculate producers ourselves |
749 | * as well as clean them. |
750 | */ |
751 | if (p_iov->b_pre_fp_hsi) { |
752 | u8 hw_qid = p_iov->acquire_resp.resc.hw_qid[rx_qid]; |
753 | u32 init_prod_val = 0; |
754 | |
755 | *pp_prod = (u8 __iomem *) |
756 | p_hwfn->regview + |
757 | MSTORM_QZONE_START(p_hwfn->cdev) + |
758 | hw_qid * MSTORM_QZONE_SIZE; |
759 | |
760 | /* Init the rcq, rx bd and rx sge (if valid) producers to 0 */ |
761 | __internal_ram_wr(p_hwfn, addr: *pp_prod, size: sizeof(u32), |
762 | data: (u32 *)(&init_prod_val)); |
763 | } |
764 | |
765 | qed_vf_pf_add_qid(p_hwfn, p_cid); |
766 | |
767 | /* add list termination tlv */ |
768 | qed_add_tlv(p_hwfn, offset: &p_iov->offset, |
769 | type: CHANNEL_TLV_LIST_END, length: sizeof(struct channel_list_end_tlv)); |
770 | |
771 | resp = &p_iov->pf2vf_reply->queue_start; |
772 | rc = qed_send_msg2pf(p_hwfn, done: &resp->hdr.status); |
773 | if (rc) |
774 | goto exit; |
775 | |
776 | if (resp->hdr.status != PFVF_STATUS_SUCCESS) { |
777 | rc = -EINVAL; |
778 | goto exit; |
779 | } |
780 | |
781 | /* Learn the address of the producer from the response */ |
782 | if (!p_iov->b_pre_fp_hsi) { |
783 | u32 init_prod_val = 0; |
784 | |
785 | *pp_prod = (u8 __iomem *)p_hwfn->regview + resp->offset; |
786 | DP_VERBOSE(p_hwfn, QED_MSG_IOV, |
787 | "Rxq[0x%02x]: producer at %p [offset 0x%08x]\n" , |
788 | rx_qid, *pp_prod, resp->offset); |
789 | |
790 | /* Init the rcq, rx bd and rx sge (if valid) producers to 0 */ |
791 | __internal_ram_wr(p_hwfn, addr: *pp_prod, size: sizeof(u32), |
792 | data: (u32 *)&init_prod_val); |
793 | } |
794 | exit: |
795 | qed_vf_pf_req_end(p_hwfn, req_status: rc); |
796 | |
797 | return rc; |
798 | } |
799 | |
800 | int qed_vf_pf_rxq_stop(struct qed_hwfn *p_hwfn, |
801 | struct qed_queue_cid *p_cid, bool cqe_completion) |
802 | { |
803 | struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info; |
804 | struct vfpf_stop_rxqs_tlv *req; |
805 | struct pfvf_def_resp_tlv *resp; |
806 | int rc; |
807 | |
808 | /* clear mailbox and prep first tlv */ |
809 | req = qed_vf_pf_prep(p_hwfn, type: CHANNEL_TLV_STOP_RXQS, length: sizeof(*req)); |
810 | |
811 | req->rx_qid = p_cid->rel.queue_id; |
812 | req->num_rxqs = 1; |
813 | req->cqe_completion = cqe_completion; |
814 | |
815 | qed_vf_pf_add_qid(p_hwfn, p_cid); |
816 | |
817 | /* add list termination tlv */ |
818 | qed_add_tlv(p_hwfn, offset: &p_iov->offset, |
819 | type: CHANNEL_TLV_LIST_END, length: sizeof(struct channel_list_end_tlv)); |
820 | |
821 | resp = &p_iov->pf2vf_reply->default_resp; |
822 | rc = qed_send_msg2pf(p_hwfn, done: &resp->hdr.status); |
823 | if (rc) |
824 | goto exit; |
825 | |
826 | if (resp->hdr.status != PFVF_STATUS_SUCCESS) { |
827 | rc = -EINVAL; |
828 | goto exit; |
829 | } |
830 | |
831 | exit: |
832 | qed_vf_pf_req_end(p_hwfn, req_status: rc); |
833 | |
834 | return rc; |
835 | } |
836 | |
837 | int |
838 | qed_vf_pf_txq_start(struct qed_hwfn *p_hwfn, |
839 | struct qed_queue_cid *p_cid, |
840 | dma_addr_t pbl_addr, |
841 | u16 pbl_size, void __iomem **pp_doorbell) |
842 | { |
843 | struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info; |
844 | struct pfvf_start_queue_resp_tlv *resp; |
845 | struct vfpf_start_txq_tlv *req; |
846 | u16 qid = p_cid->rel.queue_id; |
847 | int rc; |
848 | |
849 | /* clear mailbox and prep first tlv */ |
850 | req = qed_vf_pf_prep(p_hwfn, type: CHANNEL_TLV_START_TXQ, length: sizeof(*req)); |
851 | |
852 | req->tx_qid = qid; |
853 | |
854 | /* Tx */ |
855 | req->pbl_addr = pbl_addr; |
856 | req->pbl_size = pbl_size; |
857 | req->hw_sb = p_cid->sb_igu_id; |
858 | req->sb_index = p_cid->sb_idx; |
859 | |
860 | qed_vf_pf_add_qid(p_hwfn, p_cid); |
861 | |
862 | /* add list termination tlv */ |
863 | qed_add_tlv(p_hwfn, offset: &p_iov->offset, |
864 | type: CHANNEL_TLV_LIST_END, length: sizeof(struct channel_list_end_tlv)); |
865 | |
866 | resp = &p_iov->pf2vf_reply->queue_start; |
867 | rc = qed_send_msg2pf(p_hwfn, done: &resp->hdr.status); |
868 | if (rc) |
869 | goto exit; |
870 | |
871 | if (resp->hdr.status != PFVF_STATUS_SUCCESS) { |
872 | rc = -EINVAL; |
873 | goto exit; |
874 | } |
875 | |
876 | /* Modern PFs provide the actual offsets, while legacy |
877 | * provided only the queue id. |
878 | */ |
879 | if (!p_iov->b_pre_fp_hsi) { |
880 | *pp_doorbell = (u8 __iomem *)p_hwfn->doorbells + resp->offset; |
881 | } else { |
882 | u8 cid = p_iov->acquire_resp.resc.cid[qid]; |
883 | |
884 | *pp_doorbell = (u8 __iomem *)p_hwfn->doorbells + |
885 | qed_db_addr_vf(cid, |
886 | DQ_DEMS_LEGACY); |
887 | } |
888 | |
889 | DP_VERBOSE(p_hwfn, QED_MSG_IOV, |
890 | "Txq[0x%02x.%02x]: doorbell at %p [offset 0x%08x]\n" , |
891 | qid, p_cid->qid_usage_idx, *pp_doorbell, resp->offset); |
892 | exit: |
893 | qed_vf_pf_req_end(p_hwfn, req_status: rc); |
894 | |
895 | return rc; |
896 | } |
897 | |
898 | int qed_vf_pf_txq_stop(struct qed_hwfn *p_hwfn, struct qed_queue_cid *p_cid) |
899 | { |
900 | struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info; |
901 | struct vfpf_stop_txqs_tlv *req; |
902 | struct pfvf_def_resp_tlv *resp; |
903 | int rc; |
904 | |
905 | /* clear mailbox and prep first tlv */ |
906 | req = qed_vf_pf_prep(p_hwfn, type: CHANNEL_TLV_STOP_TXQS, length: sizeof(*req)); |
907 | |
908 | req->tx_qid = p_cid->rel.queue_id; |
909 | req->num_txqs = 1; |
910 | |
911 | qed_vf_pf_add_qid(p_hwfn, p_cid); |
912 | |
913 | /* add list termination tlv */ |
914 | qed_add_tlv(p_hwfn, offset: &p_iov->offset, |
915 | type: CHANNEL_TLV_LIST_END, length: sizeof(struct channel_list_end_tlv)); |
916 | |
917 | resp = &p_iov->pf2vf_reply->default_resp; |
918 | rc = qed_send_msg2pf(p_hwfn, done: &resp->hdr.status); |
919 | if (rc) |
920 | goto exit; |
921 | |
922 | if (resp->hdr.status != PFVF_STATUS_SUCCESS) { |
923 | rc = -EINVAL; |
924 | goto exit; |
925 | } |
926 | |
927 | exit: |
928 | qed_vf_pf_req_end(p_hwfn, req_status: rc); |
929 | |
930 | return rc; |
931 | } |
932 | |
933 | int qed_vf_pf_vport_start(struct qed_hwfn *p_hwfn, |
934 | u8 vport_id, |
935 | u16 mtu, |
936 | u8 inner_vlan_removal, |
937 | enum qed_tpa_mode tpa_mode, |
938 | u8 max_buffers_per_cqe, u8 only_untagged) |
939 | { |
940 | struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info; |
941 | struct vfpf_vport_start_tlv *req; |
942 | struct pfvf_def_resp_tlv *resp; |
943 | int rc, i; |
944 | |
945 | /* clear mailbox and prep first tlv */ |
946 | req = qed_vf_pf_prep(p_hwfn, type: CHANNEL_TLV_VPORT_START, length: sizeof(*req)); |
947 | |
948 | req->mtu = mtu; |
949 | req->vport_id = vport_id; |
950 | req->inner_vlan_removal = inner_vlan_removal; |
951 | req->tpa_mode = tpa_mode; |
952 | req->max_buffers_per_cqe = max_buffers_per_cqe; |
953 | req->only_untagged = only_untagged; |
954 | |
955 | /* status blocks */ |
956 | for (i = 0; i < p_hwfn->vf_iov_info->acquire_resp.resc.num_sbs; i++) { |
957 | struct qed_sb_info *p_sb = p_hwfn->vf_iov_info->sbs_info[i]; |
958 | |
959 | if (p_sb) |
960 | req->sb_addr[i] = p_sb->sb_phys; |
961 | } |
962 | |
963 | /* add list termination tlv */ |
964 | qed_add_tlv(p_hwfn, offset: &p_iov->offset, |
965 | type: CHANNEL_TLV_LIST_END, length: sizeof(struct channel_list_end_tlv)); |
966 | |
967 | resp = &p_iov->pf2vf_reply->default_resp; |
968 | rc = qed_send_msg2pf(p_hwfn, done: &resp->hdr.status); |
969 | if (rc) |
970 | goto exit; |
971 | |
972 | if (resp->hdr.status != PFVF_STATUS_SUCCESS) { |
973 | rc = -EINVAL; |
974 | goto exit; |
975 | } |
976 | |
977 | exit: |
978 | qed_vf_pf_req_end(p_hwfn, req_status: rc); |
979 | |
980 | return rc; |
981 | } |
982 | |
983 | int qed_vf_pf_vport_stop(struct qed_hwfn *p_hwfn) |
984 | { |
985 | struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info; |
986 | struct pfvf_def_resp_tlv *resp = &p_iov->pf2vf_reply->default_resp; |
987 | int rc; |
988 | |
989 | /* clear mailbox and prep first tlv */ |
990 | qed_vf_pf_prep(p_hwfn, type: CHANNEL_TLV_VPORT_TEARDOWN, |
991 | length: sizeof(struct vfpf_first_tlv)); |
992 | |
993 | /* add list termination tlv */ |
994 | qed_add_tlv(p_hwfn, offset: &p_iov->offset, |
995 | type: CHANNEL_TLV_LIST_END, length: sizeof(struct channel_list_end_tlv)); |
996 | |
997 | rc = qed_send_msg2pf(p_hwfn, done: &resp->hdr.status); |
998 | if (rc) |
999 | goto exit; |
1000 | |
1001 | if (resp->hdr.status != PFVF_STATUS_SUCCESS) { |
1002 | rc = -EINVAL; |
1003 | goto exit; |
1004 | } |
1005 | |
1006 | exit: |
1007 | qed_vf_pf_req_end(p_hwfn, req_status: rc); |
1008 | |
1009 | return rc; |
1010 | } |
1011 | |
1012 | static bool |
1013 | qed_vf_handle_vp_update_is_needed(struct qed_hwfn *p_hwfn, |
1014 | struct qed_sp_vport_update_params *p_data, |
1015 | u16 tlv) |
1016 | { |
1017 | switch (tlv) { |
1018 | case CHANNEL_TLV_VPORT_UPDATE_ACTIVATE: |
1019 | return !!(p_data->update_vport_active_rx_flg || |
1020 | p_data->update_vport_active_tx_flg); |
1021 | case CHANNEL_TLV_VPORT_UPDATE_TX_SWITCH: |
1022 | return !!p_data->update_tx_switching_flg; |
1023 | case CHANNEL_TLV_VPORT_UPDATE_VLAN_STRIP: |
1024 | return !!p_data->update_inner_vlan_removal_flg; |
1025 | case CHANNEL_TLV_VPORT_UPDATE_ACCEPT_ANY_VLAN: |
1026 | return !!p_data->update_accept_any_vlan_flg; |
1027 | case CHANNEL_TLV_VPORT_UPDATE_MCAST: |
1028 | return !!p_data->update_approx_mcast_flg; |
1029 | case CHANNEL_TLV_VPORT_UPDATE_ACCEPT_PARAM: |
1030 | return !!(p_data->accept_flags.update_rx_mode_config || |
1031 | p_data->accept_flags.update_tx_mode_config); |
1032 | case CHANNEL_TLV_VPORT_UPDATE_RSS: |
1033 | return !!p_data->rss_params; |
1034 | case CHANNEL_TLV_VPORT_UPDATE_SGE_TPA: |
1035 | return !!p_data->sge_tpa_params; |
1036 | default: |
1037 | DP_INFO(p_hwfn, "Unexpected vport-update TLV[%d]\n" , |
1038 | tlv); |
1039 | return false; |
1040 | } |
1041 | } |
1042 | |
1043 | static void |
1044 | qed_vf_handle_vp_update_tlvs_resp(struct qed_hwfn *p_hwfn, |
1045 | struct qed_sp_vport_update_params *p_data) |
1046 | { |
1047 | struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info; |
1048 | struct pfvf_def_resp_tlv *p_resp; |
1049 | u16 tlv; |
1050 | |
1051 | for (tlv = CHANNEL_TLV_VPORT_UPDATE_ACTIVATE; |
1052 | tlv < CHANNEL_TLV_VPORT_UPDATE_MAX; tlv++) { |
1053 | if (!qed_vf_handle_vp_update_is_needed(p_hwfn, p_data, tlv)) |
1054 | continue; |
1055 | |
1056 | p_resp = (struct pfvf_def_resp_tlv *) |
1057 | qed_iov_search_list_tlvs(p_hwfn, p_tlvs_list: p_iov->pf2vf_reply, |
1058 | req_type: tlv); |
1059 | if (p_resp && p_resp->hdr.status) |
1060 | DP_VERBOSE(p_hwfn, QED_MSG_IOV, |
1061 | "TLV[%d] Configuration %s\n" , |
1062 | tlv, |
1063 | (p_resp && p_resp->hdr.status) ? "succeeded" |
1064 | : "failed" ); |
1065 | } |
1066 | } |
1067 | |
1068 | int qed_vf_pf_vport_update(struct qed_hwfn *p_hwfn, |
1069 | struct qed_sp_vport_update_params *p_params) |
1070 | { |
1071 | struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info; |
1072 | struct vfpf_vport_update_tlv *req; |
1073 | struct pfvf_def_resp_tlv *resp; |
1074 | u8 update_rx, update_tx; |
1075 | u16 size, tlv; |
1076 | int rc; |
1077 | |
1078 | resp = &p_iov->pf2vf_reply->default_resp; |
1079 | |
1080 | update_rx = p_params->update_vport_active_rx_flg; |
1081 | update_tx = p_params->update_vport_active_tx_flg; |
1082 | |
1083 | /* clear mailbox and prep header tlv */ |
1084 | qed_vf_pf_prep(p_hwfn, type: CHANNEL_TLV_VPORT_UPDATE, length: sizeof(*req)); |
1085 | |
1086 | /* Prepare extended tlvs */ |
1087 | if (update_rx || update_tx) { |
1088 | struct vfpf_vport_update_activate_tlv *p_act_tlv; |
1089 | |
1090 | size = sizeof(struct vfpf_vport_update_activate_tlv); |
1091 | p_act_tlv = qed_add_tlv(p_hwfn, offset: &p_iov->offset, |
1092 | type: CHANNEL_TLV_VPORT_UPDATE_ACTIVATE, |
1093 | length: size); |
1094 | |
1095 | if (update_rx) { |
1096 | p_act_tlv->update_rx = update_rx; |
1097 | p_act_tlv->active_rx = p_params->vport_active_rx_flg; |
1098 | } |
1099 | |
1100 | if (update_tx) { |
1101 | p_act_tlv->update_tx = update_tx; |
1102 | p_act_tlv->active_tx = p_params->vport_active_tx_flg; |
1103 | } |
1104 | } |
1105 | |
1106 | if (p_params->update_tx_switching_flg) { |
1107 | struct vfpf_vport_update_tx_switch_tlv *p_tx_switch_tlv; |
1108 | |
1109 | size = sizeof(struct vfpf_vport_update_tx_switch_tlv); |
1110 | tlv = CHANNEL_TLV_VPORT_UPDATE_TX_SWITCH; |
1111 | p_tx_switch_tlv = qed_add_tlv(p_hwfn, offset: &p_iov->offset, |
1112 | type: tlv, length: size); |
1113 | |
1114 | p_tx_switch_tlv->tx_switching = p_params->tx_switching_flg; |
1115 | } |
1116 | |
1117 | if (p_params->update_approx_mcast_flg) { |
1118 | struct vfpf_vport_update_mcast_bin_tlv *p_mcast_tlv; |
1119 | |
1120 | size = sizeof(struct vfpf_vport_update_mcast_bin_tlv); |
1121 | p_mcast_tlv = qed_add_tlv(p_hwfn, offset: &p_iov->offset, |
1122 | type: CHANNEL_TLV_VPORT_UPDATE_MCAST, length: size); |
1123 | |
1124 | memcpy(p_mcast_tlv->bins, p_params->bins, |
1125 | sizeof(u32) * ETH_MULTICAST_MAC_BINS_IN_REGS); |
1126 | } |
1127 | |
1128 | update_rx = p_params->accept_flags.update_rx_mode_config; |
1129 | update_tx = p_params->accept_flags.update_tx_mode_config; |
1130 | |
1131 | if (update_rx || update_tx) { |
1132 | struct vfpf_vport_update_accept_param_tlv *p_accept_tlv; |
1133 | |
1134 | tlv = CHANNEL_TLV_VPORT_UPDATE_ACCEPT_PARAM; |
1135 | size = sizeof(struct vfpf_vport_update_accept_param_tlv); |
1136 | p_accept_tlv = qed_add_tlv(p_hwfn, offset: &p_iov->offset, type: tlv, length: size); |
1137 | |
1138 | if (update_rx) { |
1139 | p_accept_tlv->update_rx_mode = update_rx; |
1140 | p_accept_tlv->rx_accept_filter = |
1141 | p_params->accept_flags.rx_accept_filter; |
1142 | } |
1143 | |
1144 | if (update_tx) { |
1145 | p_accept_tlv->update_tx_mode = update_tx; |
1146 | p_accept_tlv->tx_accept_filter = |
1147 | p_params->accept_flags.tx_accept_filter; |
1148 | } |
1149 | } |
1150 | |
1151 | if (p_params->rss_params) { |
1152 | struct qed_rss_params * = p_params->rss_params; |
1153 | struct vfpf_vport_update_rss_tlv *; |
1154 | int i, table_size; |
1155 | |
1156 | size = sizeof(struct vfpf_vport_update_rss_tlv); |
1157 | p_rss_tlv = qed_add_tlv(p_hwfn, |
1158 | offset: &p_iov->offset, |
1159 | type: CHANNEL_TLV_VPORT_UPDATE_RSS, length: size); |
1160 | |
1161 | if (rss_params->update_rss_config) |
1162 | p_rss_tlv->update_rss_flags |= |
1163 | VFPF_UPDATE_RSS_CONFIG_FLAG; |
1164 | if (rss_params->update_rss_capabilities) |
1165 | p_rss_tlv->update_rss_flags |= |
1166 | VFPF_UPDATE_RSS_CAPS_FLAG; |
1167 | if (rss_params->update_rss_ind_table) |
1168 | p_rss_tlv->update_rss_flags |= |
1169 | VFPF_UPDATE_RSS_IND_TABLE_FLAG; |
1170 | if (rss_params->update_rss_key) |
1171 | p_rss_tlv->update_rss_flags |= VFPF_UPDATE_RSS_KEY_FLAG; |
1172 | |
1173 | p_rss_tlv->rss_enable = rss_params->rss_enable; |
1174 | p_rss_tlv->rss_caps = rss_params->rss_caps; |
1175 | p_rss_tlv->rss_table_size_log = rss_params->rss_table_size_log; |
1176 | |
1177 | table_size = min_t(int, T_ETH_INDIRECTION_TABLE_SIZE, |
1178 | 1 << p_rss_tlv->rss_table_size_log); |
1179 | for (i = 0; i < table_size; i++) { |
1180 | struct qed_queue_cid *p_queue; |
1181 | |
1182 | p_queue = rss_params->rss_ind_table[i]; |
1183 | p_rss_tlv->rss_ind_table[i] = p_queue->rel.queue_id; |
1184 | } |
1185 | memcpy(p_rss_tlv->rss_key, rss_params->rss_key, |
1186 | sizeof(rss_params->rss_key)); |
1187 | } |
1188 | |
1189 | if (p_params->update_accept_any_vlan_flg) { |
1190 | struct vfpf_vport_update_accept_any_vlan_tlv *p_any_vlan_tlv; |
1191 | |
1192 | size = sizeof(struct vfpf_vport_update_accept_any_vlan_tlv); |
1193 | tlv = CHANNEL_TLV_VPORT_UPDATE_ACCEPT_ANY_VLAN; |
1194 | p_any_vlan_tlv = qed_add_tlv(p_hwfn, offset: &p_iov->offset, type: tlv, length: size); |
1195 | |
1196 | p_any_vlan_tlv->accept_any_vlan = p_params->accept_any_vlan; |
1197 | p_any_vlan_tlv->update_accept_any_vlan_flg = |
1198 | p_params->update_accept_any_vlan_flg; |
1199 | } |
1200 | |
1201 | /* add list termination tlv */ |
1202 | qed_add_tlv(p_hwfn, offset: &p_iov->offset, |
1203 | type: CHANNEL_TLV_LIST_END, length: sizeof(struct channel_list_end_tlv)); |
1204 | |
1205 | rc = qed_send_msg2pf(p_hwfn, done: &resp->hdr.status); |
1206 | if (rc) |
1207 | goto exit; |
1208 | |
1209 | if (resp->hdr.status != PFVF_STATUS_SUCCESS) { |
1210 | rc = -EINVAL; |
1211 | goto exit; |
1212 | } |
1213 | |
1214 | qed_vf_handle_vp_update_tlvs_resp(p_hwfn, p_data: p_params); |
1215 | |
1216 | exit: |
1217 | qed_vf_pf_req_end(p_hwfn, req_status: rc); |
1218 | |
1219 | return rc; |
1220 | } |
1221 | |
1222 | int qed_vf_pf_reset(struct qed_hwfn *p_hwfn) |
1223 | { |
1224 | struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info; |
1225 | struct pfvf_def_resp_tlv *resp; |
1226 | struct vfpf_first_tlv *req; |
1227 | int rc; |
1228 | |
1229 | /* clear mailbox and prep first tlv */ |
1230 | req = qed_vf_pf_prep(p_hwfn, type: CHANNEL_TLV_CLOSE, length: sizeof(*req)); |
1231 | |
1232 | /* add list termination tlv */ |
1233 | qed_add_tlv(p_hwfn, offset: &p_iov->offset, |
1234 | type: CHANNEL_TLV_LIST_END, length: sizeof(struct channel_list_end_tlv)); |
1235 | |
1236 | resp = &p_iov->pf2vf_reply->default_resp; |
1237 | rc = qed_send_msg2pf(p_hwfn, done: &resp->hdr.status); |
1238 | if (rc) |
1239 | goto exit; |
1240 | |
1241 | if (resp->hdr.status != PFVF_STATUS_SUCCESS) { |
1242 | rc = -EAGAIN; |
1243 | goto exit; |
1244 | } |
1245 | |
1246 | p_hwfn->b_int_enabled = 0; |
1247 | |
1248 | exit: |
1249 | qed_vf_pf_req_end(p_hwfn, req_status: rc); |
1250 | |
1251 | return rc; |
1252 | } |
1253 | |
1254 | void qed_vf_pf_filter_mcast(struct qed_hwfn *p_hwfn, |
1255 | struct qed_filter_mcast *p_filter_cmd) |
1256 | { |
1257 | struct qed_sp_vport_update_params sp_params; |
1258 | int i; |
1259 | |
1260 | memset(&sp_params, 0, sizeof(sp_params)); |
1261 | sp_params.update_approx_mcast_flg = 1; |
1262 | |
1263 | if (p_filter_cmd->opcode == QED_FILTER_ADD) { |
1264 | for (i = 0; i < p_filter_cmd->num_mc_addrs; i++) { |
1265 | u32 bit; |
1266 | |
1267 | bit = qed_mcast_bin_from_mac(mac: p_filter_cmd->mac[i]); |
1268 | sp_params.bins[bit / 32] |= 1 << (bit % 32); |
1269 | } |
1270 | } |
1271 | |
1272 | qed_vf_pf_vport_update(p_hwfn, p_params: &sp_params); |
1273 | } |
1274 | |
1275 | int qed_vf_pf_filter_ucast(struct qed_hwfn *p_hwfn, |
1276 | struct qed_filter_ucast *p_ucast) |
1277 | { |
1278 | struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info; |
1279 | struct vfpf_ucast_filter_tlv *req; |
1280 | struct pfvf_def_resp_tlv *resp; |
1281 | int rc; |
1282 | |
1283 | /* clear mailbox and prep first tlv */ |
1284 | req = qed_vf_pf_prep(p_hwfn, type: CHANNEL_TLV_UCAST_FILTER, length: sizeof(*req)); |
1285 | req->opcode = (u8)p_ucast->opcode; |
1286 | req->type = (u8)p_ucast->type; |
1287 | memcpy(req->mac, p_ucast->mac, ETH_ALEN); |
1288 | req->vlan = p_ucast->vlan; |
1289 | |
1290 | /* add list termination tlv */ |
1291 | qed_add_tlv(p_hwfn, offset: &p_iov->offset, |
1292 | type: CHANNEL_TLV_LIST_END, length: sizeof(struct channel_list_end_tlv)); |
1293 | |
1294 | resp = &p_iov->pf2vf_reply->default_resp; |
1295 | rc = qed_send_msg2pf(p_hwfn, done: &resp->hdr.status); |
1296 | if (rc) |
1297 | goto exit; |
1298 | |
1299 | if (resp->hdr.status != PFVF_STATUS_SUCCESS) { |
1300 | rc = -EAGAIN; |
1301 | goto exit; |
1302 | } |
1303 | |
1304 | exit: |
1305 | qed_vf_pf_req_end(p_hwfn, req_status: rc); |
1306 | |
1307 | return rc; |
1308 | } |
1309 | |
1310 | int qed_vf_pf_int_cleanup(struct qed_hwfn *p_hwfn) |
1311 | { |
1312 | struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info; |
1313 | struct pfvf_def_resp_tlv *resp = &p_iov->pf2vf_reply->default_resp; |
1314 | int rc; |
1315 | |
1316 | /* clear mailbox and prep first tlv */ |
1317 | qed_vf_pf_prep(p_hwfn, type: CHANNEL_TLV_INT_CLEANUP, |
1318 | length: sizeof(struct vfpf_first_tlv)); |
1319 | |
1320 | /* add list termination tlv */ |
1321 | qed_add_tlv(p_hwfn, offset: &p_iov->offset, |
1322 | type: CHANNEL_TLV_LIST_END, length: sizeof(struct channel_list_end_tlv)); |
1323 | |
1324 | rc = qed_send_msg2pf(p_hwfn, done: &resp->hdr.status); |
1325 | if (rc) |
1326 | goto exit; |
1327 | |
1328 | if (resp->hdr.status != PFVF_STATUS_SUCCESS) { |
1329 | rc = -EINVAL; |
1330 | goto exit; |
1331 | } |
1332 | |
1333 | exit: |
1334 | qed_vf_pf_req_end(p_hwfn, req_status: rc); |
1335 | |
1336 | return rc; |
1337 | } |
1338 | |
1339 | int qed_vf_pf_get_coalesce(struct qed_hwfn *p_hwfn, |
1340 | u16 *p_coal, struct qed_queue_cid *p_cid) |
1341 | { |
1342 | struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info; |
1343 | struct pfvf_read_coal_resp_tlv *resp; |
1344 | struct vfpf_read_coal_req_tlv *req; |
1345 | int rc; |
1346 | |
1347 | /* clear mailbox and prep header tlv */ |
1348 | req = qed_vf_pf_prep(p_hwfn, type: CHANNEL_TLV_COALESCE_READ, length: sizeof(*req)); |
1349 | req->qid = p_cid->rel.queue_id; |
1350 | req->is_rx = p_cid->b_is_rx ? 1 : 0; |
1351 | |
1352 | qed_add_tlv(p_hwfn, offset: &p_iov->offset, type: CHANNEL_TLV_LIST_END, |
1353 | length: sizeof(struct channel_list_end_tlv)); |
1354 | resp = &p_iov->pf2vf_reply->read_coal_resp; |
1355 | |
1356 | rc = qed_send_msg2pf(p_hwfn, done: &resp->hdr.status); |
1357 | if (rc) |
1358 | goto exit; |
1359 | |
1360 | if (resp->hdr.status != PFVF_STATUS_SUCCESS) |
1361 | goto exit; |
1362 | |
1363 | *p_coal = resp->coal; |
1364 | exit: |
1365 | qed_vf_pf_req_end(p_hwfn, req_status: rc); |
1366 | |
1367 | return rc; |
1368 | } |
1369 | |
1370 | int |
1371 | qed_vf_pf_bulletin_update_mac(struct qed_hwfn *p_hwfn, |
1372 | const u8 *p_mac) |
1373 | { |
1374 | struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info; |
1375 | struct vfpf_bulletin_update_mac_tlv *p_req; |
1376 | struct pfvf_def_resp_tlv *p_resp; |
1377 | int rc; |
1378 | |
1379 | if (!p_mac) |
1380 | return -EINVAL; |
1381 | |
1382 | /* clear mailbox and prep header tlv */ |
1383 | p_req = qed_vf_pf_prep(p_hwfn, type: CHANNEL_TLV_BULLETIN_UPDATE_MAC, |
1384 | length: sizeof(*p_req)); |
1385 | ether_addr_copy(dst: p_req->mac, src: p_mac); |
1386 | DP_VERBOSE(p_hwfn, QED_MSG_IOV, |
1387 | "Requesting bulletin update for MAC[%pM]\n" , p_mac); |
1388 | |
1389 | /* add list termination tlv */ |
1390 | qed_add_tlv(p_hwfn, offset: &p_iov->offset, type: CHANNEL_TLV_LIST_END, |
1391 | length: sizeof(struct channel_list_end_tlv)); |
1392 | |
1393 | p_resp = &p_iov->pf2vf_reply->default_resp; |
1394 | rc = qed_send_msg2pf(p_hwfn, done: &p_resp->hdr.status); |
1395 | qed_vf_pf_req_end(p_hwfn, req_status: rc); |
1396 | return rc; |
1397 | } |
1398 | |
1399 | int |
1400 | qed_vf_pf_set_coalesce(struct qed_hwfn *p_hwfn, |
1401 | u16 rx_coal, u16 tx_coal, struct qed_queue_cid *p_cid) |
1402 | { |
1403 | struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info; |
1404 | struct vfpf_update_coalesce *req; |
1405 | struct pfvf_def_resp_tlv *resp; |
1406 | int rc; |
1407 | |
1408 | /* clear mailbox and prep header tlv */ |
1409 | req = qed_vf_pf_prep(p_hwfn, type: CHANNEL_TLV_COALESCE_UPDATE, length: sizeof(*req)); |
1410 | |
1411 | req->rx_coal = rx_coal; |
1412 | req->tx_coal = tx_coal; |
1413 | req->qid = p_cid->rel.queue_id; |
1414 | |
1415 | DP_VERBOSE(p_hwfn, |
1416 | QED_MSG_IOV, |
1417 | "Setting coalesce rx_coal = %d, tx_coal = %d at queue = %d\n" , |
1418 | rx_coal, tx_coal, req->qid); |
1419 | |
1420 | /* add list termination tlv */ |
1421 | qed_add_tlv(p_hwfn, offset: &p_iov->offset, type: CHANNEL_TLV_LIST_END, |
1422 | length: sizeof(struct channel_list_end_tlv)); |
1423 | |
1424 | resp = &p_iov->pf2vf_reply->default_resp; |
1425 | rc = qed_send_msg2pf(p_hwfn, done: &resp->hdr.status); |
1426 | if (rc) |
1427 | goto exit; |
1428 | |
1429 | if (resp->hdr.status != PFVF_STATUS_SUCCESS) |
1430 | goto exit; |
1431 | |
1432 | if (rx_coal) |
1433 | p_hwfn->cdev->rx_coalesce_usecs = rx_coal; |
1434 | |
1435 | if (tx_coal) |
1436 | p_hwfn->cdev->tx_coalesce_usecs = tx_coal; |
1437 | |
1438 | exit: |
1439 | qed_vf_pf_req_end(p_hwfn, req_status: rc); |
1440 | return rc; |
1441 | } |
1442 | |
1443 | u16 qed_vf_get_igu_sb_id(struct qed_hwfn *p_hwfn, u16 sb_id) |
1444 | { |
1445 | struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info; |
1446 | |
1447 | if (!p_iov) { |
1448 | DP_NOTICE(p_hwfn, "vf_sriov_info isn't initialized\n" ); |
1449 | return 0; |
1450 | } |
1451 | |
1452 | return p_iov->acquire_resp.resc.hw_sbs[sb_id].hw_sb_id; |
1453 | } |
1454 | |
1455 | void qed_vf_set_sb_info(struct qed_hwfn *p_hwfn, |
1456 | u16 sb_id, struct qed_sb_info *p_sb) |
1457 | { |
1458 | struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info; |
1459 | |
1460 | if (!p_iov) { |
1461 | DP_NOTICE(p_hwfn, "vf_sriov_info isn't initialized\n" ); |
1462 | return; |
1463 | } |
1464 | |
1465 | if (sb_id >= PFVF_MAX_SBS_PER_VF) { |
1466 | DP_NOTICE(p_hwfn, "Can't configure SB %04x\n" , sb_id); |
1467 | return; |
1468 | } |
1469 | |
1470 | p_iov->sbs_info[sb_id] = p_sb; |
1471 | } |
1472 | |
1473 | int qed_vf_read_bulletin(struct qed_hwfn *p_hwfn, u8 *p_change) |
1474 | { |
1475 | struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info; |
1476 | struct qed_bulletin_content shadow; |
1477 | u32 crc, crc_size; |
1478 | |
1479 | crc_size = sizeof(p_iov->bulletin.p_virt->crc); |
1480 | *p_change = 0; |
1481 | |
1482 | /* Need to guarantee PF is not in the middle of writing it */ |
1483 | memcpy(&shadow, p_iov->bulletin.p_virt, p_iov->bulletin.size); |
1484 | |
1485 | /* If version did not update, no need to do anything */ |
1486 | if (shadow.version == p_iov->bulletin_shadow.version) |
1487 | return 0; |
1488 | |
1489 | /* Verify the bulletin we see is valid */ |
1490 | crc = crc32(0, (u8 *)&shadow + crc_size, |
1491 | p_iov->bulletin.size - crc_size); |
1492 | if (crc != shadow.crc) |
1493 | return -EAGAIN; |
1494 | |
1495 | /* Set the shadow bulletin and process it */ |
1496 | memcpy(&p_iov->bulletin_shadow, &shadow, p_iov->bulletin.size); |
1497 | |
1498 | DP_VERBOSE(p_hwfn, QED_MSG_IOV, |
1499 | "Read a bulletin update %08x\n" , shadow.version); |
1500 | |
1501 | *p_change = 1; |
1502 | |
1503 | return 0; |
1504 | } |
1505 | |
1506 | void __qed_vf_get_link_params(struct qed_hwfn *p_hwfn, |
1507 | struct qed_mcp_link_params *p_params, |
1508 | struct qed_bulletin_content *p_bulletin) |
1509 | { |
1510 | memset(p_params, 0, sizeof(*p_params)); |
1511 | |
1512 | p_params->speed.autoneg = p_bulletin->req_autoneg; |
1513 | p_params->speed.advertised_speeds = p_bulletin->req_adv_speed; |
1514 | p_params->speed.forced_speed = p_bulletin->req_forced_speed; |
1515 | p_params->pause.autoneg = p_bulletin->req_autoneg_pause; |
1516 | p_params->pause.forced_rx = p_bulletin->req_forced_rx; |
1517 | p_params->pause.forced_tx = p_bulletin->req_forced_tx; |
1518 | p_params->loopback_mode = p_bulletin->req_loopback; |
1519 | } |
1520 | |
1521 | void qed_vf_get_link_params(struct qed_hwfn *p_hwfn, |
1522 | struct qed_mcp_link_params *params) |
1523 | { |
1524 | __qed_vf_get_link_params(p_hwfn, p_params: params, |
1525 | p_bulletin: &(p_hwfn->vf_iov_info->bulletin_shadow)); |
1526 | } |
1527 | |
1528 | void __qed_vf_get_link_state(struct qed_hwfn *p_hwfn, |
1529 | struct qed_mcp_link_state *p_link, |
1530 | struct qed_bulletin_content *p_bulletin) |
1531 | { |
1532 | memset(p_link, 0, sizeof(*p_link)); |
1533 | |
1534 | p_link->link_up = p_bulletin->link_up; |
1535 | p_link->speed = p_bulletin->speed; |
1536 | p_link->full_duplex = p_bulletin->full_duplex; |
1537 | p_link->an = p_bulletin->autoneg; |
1538 | p_link->an_complete = p_bulletin->autoneg_complete; |
1539 | p_link->parallel_detection = p_bulletin->parallel_detection; |
1540 | p_link->pfc_enabled = p_bulletin->pfc_enabled; |
1541 | p_link->partner_adv_speed = p_bulletin->partner_adv_speed; |
1542 | p_link->partner_tx_flow_ctrl_en = p_bulletin->partner_tx_flow_ctrl_en; |
1543 | p_link->partner_rx_flow_ctrl_en = p_bulletin->partner_rx_flow_ctrl_en; |
1544 | p_link->partner_adv_pause = p_bulletin->partner_adv_pause; |
1545 | p_link->sfp_tx_fault = p_bulletin->sfp_tx_fault; |
1546 | } |
1547 | |
1548 | void qed_vf_get_link_state(struct qed_hwfn *p_hwfn, |
1549 | struct qed_mcp_link_state *link) |
1550 | { |
1551 | __qed_vf_get_link_state(p_hwfn, p_link: link, |
1552 | p_bulletin: &(p_hwfn->vf_iov_info->bulletin_shadow)); |
1553 | } |
1554 | |
1555 | void __qed_vf_get_link_caps(struct qed_hwfn *p_hwfn, |
1556 | struct qed_mcp_link_capabilities *p_link_caps, |
1557 | struct qed_bulletin_content *p_bulletin) |
1558 | { |
1559 | memset(p_link_caps, 0, sizeof(*p_link_caps)); |
1560 | p_link_caps->speed_capabilities = p_bulletin->capability_speed; |
1561 | } |
1562 | |
1563 | void qed_vf_get_link_caps(struct qed_hwfn *p_hwfn, |
1564 | struct qed_mcp_link_capabilities *p_link_caps) |
1565 | { |
1566 | __qed_vf_get_link_caps(p_hwfn, p_link_caps, |
1567 | p_bulletin: &(p_hwfn->vf_iov_info->bulletin_shadow)); |
1568 | } |
1569 | |
1570 | void qed_vf_get_num_rxqs(struct qed_hwfn *p_hwfn, u8 *num_rxqs) |
1571 | { |
1572 | *num_rxqs = p_hwfn->vf_iov_info->acquire_resp.resc.num_rxqs; |
1573 | } |
1574 | |
1575 | void qed_vf_get_num_txqs(struct qed_hwfn *p_hwfn, u8 *num_txqs) |
1576 | { |
1577 | *num_txqs = p_hwfn->vf_iov_info->acquire_resp.resc.num_txqs; |
1578 | } |
1579 | |
1580 | void qed_vf_get_num_cids(struct qed_hwfn *p_hwfn, u8 *num_cids) |
1581 | { |
1582 | *num_cids = p_hwfn->vf_iov_info->acquire_resp.resc.num_cids; |
1583 | } |
1584 | |
1585 | void qed_vf_get_port_mac(struct qed_hwfn *p_hwfn, u8 *port_mac) |
1586 | { |
1587 | memcpy(port_mac, |
1588 | p_hwfn->vf_iov_info->acquire_resp.pfdev_info.port_mac, ETH_ALEN); |
1589 | } |
1590 | |
1591 | void qed_vf_get_num_vlan_filters(struct qed_hwfn *p_hwfn, u8 *num_vlan_filters) |
1592 | { |
1593 | struct qed_vf_iov *p_vf; |
1594 | |
1595 | p_vf = p_hwfn->vf_iov_info; |
1596 | *num_vlan_filters = p_vf->acquire_resp.resc.num_vlan_filters; |
1597 | } |
1598 | |
1599 | void qed_vf_get_num_mac_filters(struct qed_hwfn *p_hwfn, u8 *num_mac_filters) |
1600 | { |
1601 | struct qed_vf_iov *p_vf = p_hwfn->vf_iov_info; |
1602 | |
1603 | *num_mac_filters = p_vf->acquire_resp.resc.num_mac_filters; |
1604 | } |
1605 | |
1606 | bool qed_vf_check_mac(struct qed_hwfn *p_hwfn, u8 *mac) |
1607 | { |
1608 | struct qed_bulletin_content *bulletin; |
1609 | |
1610 | bulletin = &p_hwfn->vf_iov_info->bulletin_shadow; |
1611 | if (!(bulletin->valid_bitmap & (1 << MAC_ADDR_FORCED))) |
1612 | return true; |
1613 | |
1614 | /* Forbid VF from changing a MAC enforced by PF */ |
1615 | if (ether_addr_equal(addr1: bulletin->mac, addr2: mac)) |
1616 | return false; |
1617 | |
1618 | return false; |
1619 | } |
1620 | |
1621 | static bool qed_vf_bulletin_get_forced_mac(struct qed_hwfn *hwfn, |
1622 | u8 *dst_mac, u8 *p_is_forced) |
1623 | { |
1624 | struct qed_bulletin_content *bulletin; |
1625 | |
1626 | bulletin = &hwfn->vf_iov_info->bulletin_shadow; |
1627 | |
1628 | if (bulletin->valid_bitmap & (1 << MAC_ADDR_FORCED)) { |
1629 | if (p_is_forced) |
1630 | *p_is_forced = 1; |
1631 | } else if (bulletin->valid_bitmap & (1 << VFPF_BULLETIN_MAC_ADDR)) { |
1632 | if (p_is_forced) |
1633 | *p_is_forced = 0; |
1634 | } else { |
1635 | return false; |
1636 | } |
1637 | |
1638 | ether_addr_copy(dst: dst_mac, src: bulletin->mac); |
1639 | |
1640 | return true; |
1641 | } |
1642 | |
1643 | static void |
1644 | qed_vf_bulletin_get_udp_ports(struct qed_hwfn *p_hwfn, |
1645 | u16 *p_vxlan_port, u16 *p_geneve_port) |
1646 | { |
1647 | struct qed_bulletin_content *p_bulletin; |
1648 | |
1649 | p_bulletin = &p_hwfn->vf_iov_info->bulletin_shadow; |
1650 | |
1651 | *p_vxlan_port = p_bulletin->vxlan_udp_port; |
1652 | *p_geneve_port = p_bulletin->geneve_udp_port; |
1653 | } |
1654 | |
1655 | void qed_vf_get_fw_version(struct qed_hwfn *p_hwfn, |
1656 | u16 *fw_major, u16 *fw_minor, |
1657 | u16 *fw_rev, u16 *fw_eng) |
1658 | { |
1659 | struct pf_vf_pfdev_info *info; |
1660 | |
1661 | info = &p_hwfn->vf_iov_info->acquire_resp.pfdev_info; |
1662 | |
1663 | *fw_major = info->fw_major; |
1664 | *fw_minor = info->fw_minor; |
1665 | *fw_rev = info->fw_rev; |
1666 | *fw_eng = info->fw_eng; |
1667 | } |
1668 | |
1669 | static void qed_handle_bulletin_change(struct qed_hwfn *hwfn) |
1670 | { |
1671 | struct qed_eth_cb_ops *ops = hwfn->cdev->protocol_ops.eth; |
1672 | u8 mac[ETH_ALEN], is_mac_exist, is_mac_forced; |
1673 | void *cookie = hwfn->cdev->ops_cookie; |
1674 | u16 vxlan_port, geneve_port; |
1675 | |
1676 | qed_vf_bulletin_get_udp_ports(p_hwfn: hwfn, p_vxlan_port: &vxlan_port, p_geneve_port: &geneve_port); |
1677 | is_mac_exist = qed_vf_bulletin_get_forced_mac(hwfn, dst_mac: mac, |
1678 | p_is_forced: &is_mac_forced); |
1679 | if (is_mac_exist && cookie) |
1680 | ops->force_mac(cookie, mac, !!is_mac_forced); |
1681 | |
1682 | ops->ports_update(cookie, vxlan_port, geneve_port); |
1683 | |
1684 | /* Always update link configuration according to bulletin */ |
1685 | qed_link_update(hwfn, NULL); |
1686 | } |
1687 | |
1688 | void qed_iov_vf_task(struct work_struct *work) |
1689 | { |
1690 | struct qed_hwfn *hwfn = container_of(work, struct qed_hwfn, |
1691 | iov_task.work); |
1692 | u8 change = 0; |
1693 | |
1694 | if (test_and_clear_bit(nr: QED_IOV_WQ_STOP_WQ_FLAG, addr: &hwfn->iov_task_flags)) |
1695 | return; |
1696 | |
1697 | /* Handle bulletin board changes */ |
1698 | qed_vf_read_bulletin(p_hwfn: hwfn, p_change: &change); |
1699 | if (test_and_clear_bit(nr: QED_IOV_WQ_VF_FORCE_LINK_QUERY_FLAG, |
1700 | addr: &hwfn->iov_task_flags)) |
1701 | change = 1; |
1702 | if (change) |
1703 | qed_handle_bulletin_change(hwfn); |
1704 | |
1705 | /* As VF is polling bulletin board, need to constantly re-schedule */ |
1706 | queue_delayed_work(wq: hwfn->iov_wq, dwork: &hwfn->iov_task, HZ); |
1707 | } |
1708 | |