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