1 /* SPDX-License-Identifier: BSD-3-Clause 2 * 3 * Copyright(c) 2020-2021 Xilinx, Inc. 4 */ 5 6 #include "efx.h" 7 #include "efx_impl.h" 8 9 #if EFSYS_OPT_RIVERHEAD && EFSYS_OPT_VIRTIO 10 11 /* 12 * Get function-local index of the associated VI from the 13 * virtqueue number queue 0 is reserved for MCDI 14 */ 15 #define EFX_VIRTIO_GET_VI_INDEX(vq_num) (((vq_num) / 2) + 1) 16 17 __checkReturn efx_rc_t 18 rhead_virtio_qstart( 19 __in efx_virtio_vq_t *evvp, 20 __in efx_virtio_vq_cfg_t *evvcp, 21 __in_opt efx_virtio_vq_dyncfg_t *evvdp) 22 23 { 24 efx_nic_t *enp = evvp->evv_enp; 25 efx_mcdi_req_t req; 26 uint32_t vi_index; 27 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_VIRTIO_INIT_QUEUE_REQ_LEN, 28 MC_CMD_VIRTIO_INIT_QUEUE_RESP_LEN); 29 efx_rc_t rc; 30 31 EFX_STATIC_ASSERT(EFX_VIRTIO_VQ_TYPE_NET_RXQ == 32 MC_CMD_VIRTIO_INIT_QUEUE_REQ_NET_RXQ); 33 EFX_STATIC_ASSERT(EFX_VIRTIO_VQ_TYPE_NET_TXQ == 34 MC_CMD_VIRTIO_INIT_QUEUE_REQ_NET_TXQ); 35 EFX_STATIC_ASSERT(EFX_VIRTIO_VQ_TYPE_BLOCK == 36 MC_CMD_VIRTIO_INIT_QUEUE_REQ_BLOCK); 37 38 if (evvcp->evvc_type >= EFX_VIRTIO_VQ_NTYPES) { 39 rc = EINVAL; 40 goto fail1; 41 } 42 43 /* virtqueue size must be power of 2 */ 44 if ((!ISP2(evvcp->evvc_vq_size)) || 45 (evvcp->evvc_vq_size > EFX_VIRTIO_MAX_VQ_SIZE)) { 46 rc = EINVAL; 47 goto fail2; 48 } 49 50 if (evvdp != NULL) { 51 if ((evvdp->evvd_vq_cidx > evvcp->evvc_vq_size) || 52 (evvdp->evvd_vq_pidx > evvcp->evvc_vq_size)) { 53 rc = EINVAL; 54 goto fail3; 55 } 56 } 57 58 req.emr_cmd = MC_CMD_VIRTIO_INIT_QUEUE; 59 req.emr_in_buf = payload; 60 req.emr_in_length = MC_CMD_VIRTIO_INIT_QUEUE_REQ_LEN; 61 req.emr_out_buf = payload; 62 req.emr_out_length = MC_CMD_VIRTIO_INIT_QUEUE_RESP_LEN; 63 64 MCDI_IN_SET_BYTE(req, VIRTIO_INIT_QUEUE_REQ_QUEUE_TYPE, 65 evvcp->evvc_type); 66 MCDI_IN_SET_WORD(req, VIRTIO_INIT_QUEUE_REQ_TARGET_VF, 67 evvcp->evvc_target_vf); 68 69 vi_index = EFX_VIRTIO_GET_VI_INDEX(evvcp->evvc_vq_num); 70 MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_INSTANCE, vi_index); 71 72 MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_SIZE, 73 evvcp->evvc_vq_size); 74 75 MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_DESC_TBL_ADDR_LO, 76 evvcp->evvc_desc_tbl_addr & 0xFFFFFFFF); 77 MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_DESC_TBL_ADDR_HI, 78 evvcp->evvc_desc_tbl_addr >> 32); 79 80 MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_AVAIL_RING_ADDR_LO, 81 evvcp->evvc_avail_ring_addr & 0xFFFFFFFF); 82 MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_AVAIL_RING_ADDR_HI, 83 evvcp->evvc_avail_ring_addr >> 32); 84 85 MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_USED_RING_ADDR_LO, 86 evvcp->evvc_used_ring_addr & 0xFFFFFFFF); 87 MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_USED_RING_ADDR_HI, 88 evvcp->evvc_used_ring_addr >> 32); 89 90 if (evvcp->evvc_use_pasid) { 91 MCDI_IN_POPULATE_DWORD_1(req, VIRTIO_INIT_QUEUE_REQ_FLAGS, 92 VIRTIO_INIT_QUEUE_REQ_USE_PASID, 1); 93 MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_PASID, 94 evvcp->evvc_pas_id); 95 } 96 97 MCDI_IN_SET_WORD(req, VIRTIO_INIT_QUEUE_REQ_MSIX_VECTOR, 98 evvcp->evvc_msix_vector); 99 100 MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_FEATURES_LO, 101 evvcp->evcc_features & 0xFFFFFFFF); 102 MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_FEATURES_HI, 103 evvcp->evcc_features >> 32); 104 105 if (evvdp != NULL) { 106 MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_INITIAL_PIDX, 107 evvdp->evvd_vq_pidx); 108 MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_INITIAL_CIDX, 109 evvdp->evvd_vq_cidx); 110 } 111 112 MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_MPORT_SELECTOR, 113 MAE_MPORT_SELECTOR_ASSIGNED); 114 115 efx_mcdi_execute(enp, &req); 116 117 if (req.emr_rc != 0) { 118 rc = req.emr_rc; 119 goto fail4; 120 } 121 122 evvp->evv_vi_index = vi_index; 123 124 return (0); 125 126 fail4: 127 EFSYS_PROBE(fail4); 128 fail3: 129 EFSYS_PROBE(fail3); 130 fail2: 131 EFSYS_PROBE(fail2); 132 fail1: 133 EFSYS_PROBE1(fail1, efx_rc_t, rc); 134 135 return (rc); 136 } 137 138 __checkReturn efx_rc_t 139 rhead_virtio_qstop( 140 __in efx_virtio_vq_t *evvp, 141 __out_opt efx_virtio_vq_dyncfg_t *evvdp) 142 { 143 efx_mcdi_req_t req; 144 efx_nic_t *enp = evvp->evv_enp; 145 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_VIRTIO_FINI_QUEUE_REQ_LEN, 146 MC_CMD_VIRTIO_FINI_QUEUE_RESP_LEN); 147 efx_rc_t rc; 148 149 req.emr_cmd = MC_CMD_VIRTIO_FINI_QUEUE; 150 req.emr_in_buf = payload; 151 req.emr_in_length = MC_CMD_VIRTIO_FINI_QUEUE_REQ_LEN; 152 req.emr_out_buf = payload; 153 req.emr_out_length = MC_CMD_VIRTIO_FINI_QUEUE_RESP_LEN; 154 155 MCDI_IN_SET_BYTE(req, VIRTIO_FINI_QUEUE_REQ_QUEUE_TYPE, evvp->evv_type); 156 MCDI_IN_SET_WORD(req, VIRTIO_INIT_QUEUE_REQ_TARGET_VF, 157 evvp->evv_target_vf); 158 MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_INSTANCE, 159 evvp->evv_vi_index); 160 161 efx_mcdi_execute(enp, &req); 162 163 if (req.emr_rc != 0) { 164 rc = req.emr_rc; 165 goto fail1; 166 } 167 168 if (req.emr_out_length_used < MC_CMD_VIRTIO_FINI_QUEUE_RESP_LEN) { 169 rc = EMSGSIZE; 170 goto fail2; 171 } 172 173 if (evvdp != NULL) { 174 evvdp->evvd_vq_pidx = 175 MCDI_OUT_DWORD(req, VIRTIO_FINI_QUEUE_RESP_FINAL_PIDX); 176 evvdp->evvd_vq_cidx = 177 MCDI_OUT_DWORD(req, VIRTIO_FINI_QUEUE_RESP_FINAL_CIDX); 178 } 179 180 return (0); 181 182 fail2: 183 EFSYS_PROBE(fail2); 184 fail1: 185 EFSYS_PROBE1(fail1, efx_rc_t, rc); 186 187 return (rc); 188 } 189 190 __checkReturn efx_rc_t 191 rhead_virtio_get_doorbell_offset( 192 __in efx_virtio_vq_t *evvp, 193 __out uint32_t *offsetp) 194 { 195 efx_nic_t *enp = evvp->evv_enp; 196 efx_mcdi_req_t req; 197 uint32_t type; 198 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_VIRTIO_GET_DOORBELL_OFFSET_REQ_LEN, 199 MC_CMD_VIRTIO_GET_NET_DOORBELL_OFFSET_RESP_LEN); 200 efx_rc_t rc; 201 202 req.emr_cmd = MC_CMD_VIRTIO_GET_DOORBELL_OFFSET; 203 req.emr_in_buf = payload; 204 req.emr_in_length = MC_CMD_VIRTIO_GET_DOORBELL_OFFSET_REQ_LEN; 205 req.emr_out_buf = payload; 206 req.emr_out_length = MC_CMD_VIRTIO_GET_NET_DOORBELL_OFFSET_RESP_LEN; 207 208 switch (evvp->evv_type) { 209 case EFX_VIRTIO_VQ_TYPE_NET_RXQ: 210 case EFX_VIRTIO_VQ_TYPE_NET_TXQ: 211 type = MC_CMD_VIRTIO_GET_FEATURES_IN_NET; 212 break; 213 case EFX_VIRTIO_VQ_TYPE_BLOCK: 214 type = MC_CMD_VIRTIO_GET_FEATURES_IN_BLOCK; 215 break; 216 default: 217 rc = EINVAL; 218 goto fail1; 219 } 220 221 MCDI_IN_SET_BYTE(req, VIRTIO_GET_DOORBELL_OFFSET_REQ_DEVICE_ID, 222 type); 223 MCDI_IN_SET_WORD(req, VIRTIO_GET_DOORBELL_OFFSET_REQ_TARGET_VF, 224 evvp->evv_target_vf); 225 MCDI_IN_SET_DWORD(req, VIRTIO_GET_DOORBELL_OFFSET_REQ_INSTANCE, 226 evvp->evv_vi_index); 227 228 efx_mcdi_execute(enp, &req); 229 230 if (req.emr_rc != 0) { 231 rc = req.emr_rc; 232 goto fail2; 233 } 234 235 switch (type) { 236 case MC_CMD_VIRTIO_GET_FEATURES_IN_NET: 237 if (req.emr_out_length_used < 238 MC_CMD_VIRTIO_GET_NET_DOORBELL_OFFSET_RESP_LEN) { 239 rc = EMSGSIZE; 240 goto fail3; 241 } 242 243 if (evvp->evv_type == EFX_VIRTIO_VQ_TYPE_NET_RXQ) { 244 *offsetp = MCDI_OUT_DWORD(req, 245 VIRTIO_GET_NET_DOORBELL_OFFSET_RESP_RX_DBL_OFFSET); 246 } else if (evvp->evv_type == EFX_VIRTIO_VQ_TYPE_NET_TXQ) { 247 *offsetp = MCDI_OUT_DWORD(req, 248 VIRTIO_GET_NET_DOORBELL_OFFSET_RESP_TX_DBL_OFFSET); 249 } 250 break; 251 case MC_CMD_VIRTIO_GET_FEATURES_IN_BLOCK: 252 if (req.emr_out_length_used < 253 MC_CMD_VIRTIO_GET_BLOCK_DOORBELL_OFFSET_RESP_LEN) { 254 rc = EMSGSIZE; 255 goto fail4; 256 } 257 258 *offsetp = MCDI_OUT_DWORD(req, 259 VIRTIO_GET_BLOCK_DOORBELL_OFFSET_RESP_DBL_OFFSET); 260 break; 261 default: 262 EFSYS_ASSERT(0); 263 rc = EINVAL; 264 goto fail5; 265 } 266 267 return (0); 268 269 fail5: 270 EFSYS_PROBE(fail5); 271 fail4: 272 EFSYS_PROBE(fail4); 273 fail3: 274 EFSYS_PROBE(fail3); 275 fail2: 276 EFSYS_PROBE(fail2); 277 fail1: 278 EFSYS_PROBE1(fail1, efx_rc_t, rc); 279 280 return (rc); 281 } 282 283 __checkReturn efx_rc_t 284 rhead_virtio_get_features( 285 __in efx_nic_t *enp, 286 __in efx_virtio_device_type_t type, 287 __out uint64_t *featuresp) 288 { 289 efx_mcdi_req_t req; 290 uint32_t features_lo; 291 uint32_t features_hi; 292 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_VIRTIO_GET_FEATURES_IN_LEN, 293 MC_CMD_VIRTIO_GET_FEATURES_OUT_LEN); 294 efx_rc_t rc; 295 296 EFX_STATIC_ASSERT(EFX_VIRTIO_DEVICE_TYPE_NET == 297 MC_CMD_VIRTIO_GET_FEATURES_IN_NET); 298 EFX_STATIC_ASSERT(EFX_VIRTIO_DEVICE_TYPE_BLOCK == 299 MC_CMD_VIRTIO_GET_FEATURES_IN_BLOCK); 300 301 req.emr_cmd = MC_CMD_VIRTIO_GET_FEATURES; 302 req.emr_in_buf = payload; 303 req.emr_in_length = MC_CMD_VIRTIO_GET_FEATURES_IN_LEN; 304 req.emr_out_buf = payload; 305 req.emr_out_length = MC_CMD_VIRTIO_GET_FEATURES_OUT_LEN; 306 307 MCDI_IN_SET_DWORD(req, VIRTIO_GET_FEATURES_IN_DEVICE_ID, type); 308 309 efx_mcdi_execute(enp, &req); 310 311 if (req.emr_rc != 0) { 312 rc = req.emr_rc; 313 goto fail1; 314 } 315 316 if (req.emr_out_length_used < MC_CMD_VIRTIO_GET_FEATURES_OUT_LEN) { 317 rc = EMSGSIZE; 318 goto fail2; 319 } 320 321 features_lo = MCDI_OUT_DWORD(req, VIRTIO_GET_FEATURES_OUT_FEATURES_LO); 322 features_hi = MCDI_OUT_DWORD(req, VIRTIO_GET_FEATURES_OUT_FEATURES_HI); 323 *featuresp = ((uint64_t)features_hi << 32) | features_lo; 324 325 return (0); 326 327 fail2: 328 EFSYS_PROBE(fail2); 329 fail1: 330 EFSYS_PROBE1(fail1, efx_rc_t, rc); 331 332 return (rc); 333 } 334 335 __checkReturn efx_rc_t 336 rhead_virtio_verify_features( 337 __in efx_nic_t *enp, 338 __in efx_virtio_device_type_t type, 339 __in uint64_t features) 340 { 341 efx_mcdi_req_t req; 342 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_VIRTIO_TEST_FEATURES_IN_LEN, 343 MC_CMD_VIRTIO_TEST_FEATURES_OUT_LEN); 344 efx_rc_t rc; 345 346 EFX_STATIC_ASSERT(EFX_VIRTIO_DEVICE_TYPE_NET == 347 MC_CMD_VIRTIO_GET_FEATURES_IN_NET); 348 EFX_STATIC_ASSERT(EFX_VIRTIO_DEVICE_TYPE_BLOCK == 349 MC_CMD_VIRTIO_GET_FEATURES_IN_BLOCK); 350 351 req.emr_cmd = MC_CMD_VIRTIO_TEST_FEATURES; 352 req.emr_in_buf = payload; 353 req.emr_in_length = MC_CMD_VIRTIO_TEST_FEATURES_IN_LEN; 354 req.emr_out_buf = payload; 355 req.emr_out_length = MC_CMD_VIRTIO_TEST_FEATURES_OUT_LEN; 356 357 MCDI_IN_SET_DWORD(req, VIRTIO_TEST_FEATURES_IN_DEVICE_ID, type); 358 359 MCDI_IN_SET_DWORD(req, VIRTIO_TEST_FEATURES_IN_FEATURES_LO, 360 features & 0xFFFFFFFF); 361 MCDI_IN_SET_DWORD(req, VIRTIO_TEST_FEATURES_IN_FEATURES_HI, 362 ((features >> 32) & 0xFFFFFFFF)); 363 364 efx_mcdi_execute(enp, &req); 365 366 if (req.emr_rc != 0) { 367 rc = req.emr_rc; 368 goto fail1; 369 } 370 371 return (0); 372 373 fail1: 374 EFSYS_PROBE1(fail1, efx_rc_t, rc); 375 376 return (rc); 377 } 378 379 #endif /* EFSYS_OPT_RIVERHEAD && EFSYS_OPT_VIRTIO */ 380