| 1 | |
| 2 | * Copyright 2014 Advanced Micro Devices, Inc.
|
| 3 | *
|
| 4 | * Permission is hereby granted, free of charge, to any person obtaining a
|
| 5 | * copy of this software and associated documentation files (the "Software"),
|
| 6 | * to deal in the Software without restriction, including without limitation
|
| 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
| 8 | * and/or sell copies of the Software, and to permit persons to whom the
|
| 9 | * Software is furnished to do so, subject to the following conditions:
|
| 10 | *
|
| 11 | * The above copyright notice and this permission notice shall be included in
|
| 12 | * all copies or substantial portions of the Software.
|
| 13 | *
|
| 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
| 17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
| 18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
| 19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
| 20 | * OTHER DEALINGS IN THE SOFTWARE.
|
| 21 | *
|
| 22 |
|
| 23 |
|
| 24 | #include "amdgpu.h"
|
| 25 | #include "nbio/nbio_6_1_offset.h"
|
| 26 | #include "nbio/nbio_6_1_sh_mask.h"
|
| 27 | #include "gc/gc_9_0_offset.h"
|
| 28 | #include "gc/gc_9_0_sh_mask.h"
|
| 29 | #include "mp/mp_9_0_offset.h"
|
| 30 | #include "soc15.h"
|
| 31 | #include "vega10_ih.h"
|
| 32 | #include "soc15_common.h"
|
| 33 | #include "mxgpu_ai.h"
|
| 34 |
|
| 35 | #include "amdgpu_reset.h"
|
| 36 |
|
| 37 | static void xgpu_ai_mailbox_send_ack(struct amdgpu_device *adev)
|
| 38 | {
|
| 39 | WREG8(AI_MAIBOX_CONTROL_RCV_OFFSET_BYTE, 2);
|
| 40 | }
|
| 41 |
|
| 42 | static void xgpu_ai_mailbox_set_valid(struct amdgpu_device *adev, bool val)
|
| 43 | {
|
| 44 | WREG8(AI_MAIBOX_CONTROL_TRN_OFFSET_BYTE, val ? 1 : 0);
|
| 45 | }
|
| 46 |
|
| 47 | |
| 48 | * this peek_msg could *only* be called in IRQ routine becuase in IRQ routine
|
| 49 | * RCV_MSG_VALID filed of BIF_BX_PF0_MAILBOX_CONTROL must already be set to 1
|
| 50 | * by host.
|
| 51 | *
|
| 52 | * if called no in IRQ routine, this peek_msg cannot guaranteed to return the
|
| 53 | * correct value since it doesn't return the RCV_DW0 under the case that
|
| 54 | * RCV_MSG_VALID is set by host.
|
| 55 |
|
| 56 | static enum idh_event xgpu_ai_mailbox_peek_msg(struct amdgpu_device *adev)
|
| 57 | {
|
| 58 | return RREG32_NO_KIQ(SOC15_REG_OFFSET(NBIO, 0,
|
| 59 | mmBIF_BX_PF0_MAILBOX_MSGBUF_RCV_DW0));
|
| 60 | }
|
| 61 |
|
| 62 |
|
| 63 | static int xgpu_ai_mailbox_rcv_msg(struct amdgpu_device *adev,
|
| 64 | enum idh_event event)
|
| 65 | {
|
| 66 | u32 reg;
|
| 67 |
|
| 68 | reg = RREG32_NO_KIQ(SOC15_REG_OFFSET(NBIO, 0,
|
| 69 | mmBIF_BX_PF0_MAILBOX_MSGBUF_RCV_DW0));
|
| 70 | if (reg != event)
|
| 71 | return -ENOENT;
|
| 72 |
|
| 73 | xgpu_ai_mailbox_send_ack(adev);
|
| 74 |
|
| 75 | return 0;
|
| 76 | }
|
| 77 |
|
| 78 | static uint8_t xgpu_ai_peek_ack(struct amdgpu_device *adev) {
|
| 79 | return RREG8(AI_MAIBOX_CONTROL_TRN_OFFSET_BYTE) & 2;
|
| 80 | }
|
| 81 |
|
| 82 | static int xgpu_ai_poll_ack(struct amdgpu_device *adev)
|
| 83 | {
|
| 84 | int timeout = AI_MAILBOX_POLL_ACK_TIMEDOUT;
|
| 85 | u8 reg;
|
| 86 |
|
| 87 | do {
|
| 88 | reg = RREG8(AI_MAIBOX_CONTROL_TRN_OFFSET_BYTE);
|
| 89 | if (reg & 2)
|
| 90 | return 0;
|
| 91 |
|
| 92 | mdelay(5);
|
| 93 | timeout -= 5;
|
| 94 | } while (timeout > 1);
|
| 95 |
|
| 96 | dev_err(adev->dev, "Doesn't get TRN_MSG_ACK from pf in %d msec\n", AI_MAILBOX_POLL_ACK_TIMEDOUT);
|
| 97 |
|
| 98 | return -ETIME;
|
| 99 | }
|
| 100 |
|
| 101 | static int xgpu_ai_poll_msg(struct amdgpu_device *adev, enum idh_event event)
|
| 102 | {
|
| 103 | int r, timeout = AI_MAILBOX_POLL_MSG_TIMEDOUT;
|
| 104 |
|
| 105 | do {
|
| 106 | r = xgpu_ai_mailbox_rcv_msg(adev, event);
|
| 107 | if (!r)
|
| 108 | return 0;
|
| 109 |
|
| 110 | msleep(10);
|
| 111 | timeout -= 10;
|
| 112 | } while (timeout > 1);
|
| 113 |
|
| 114 | dev_err(adev->dev, "Doesn't get msg:%d from pf, error=%d\n", event, r);
|
| 115 |
|
| 116 | return -ETIME;
|
| 117 | }
|
| 118 |
|
| 119 | static void xgpu_ai_mailbox_trans_msg (struct amdgpu_device *adev,
|
| 120 | enum idh_request req, u32 data1, u32 data2, u32 data3) {
|
| 121 | u32 reg;
|
| 122 | int r;
|
| 123 | uint8_t trn;
|
| 124 |
|
| 125 | |
| 126 | * clear TRN_MSG_VALID valid to clear host's RCV_MSG_ACK
|
| 127 | * and with host's RCV_MSG_ACK cleared hw automatically clear host's RCV_MSG_ACK
|
| 128 | * which lead to VF's TRN_MSG_ACK cleared, otherwise below xgpu_ai_poll_ack()
|
| 129 | * will return immediatly
|
| 130 |
|
| 131 | do {
|
| 132 | xgpu_ai_mailbox_set_valid(adev, false);
|
| 133 | trn = xgpu_ai_peek_ack(adev);
|
| 134 | if (trn) {
|
| 135 | dev_err_ratelimited(adev->dev, "trn=%x ACK should not assert! wait again !\n", trn);
|
| 136 | msleep(1);
|
| 137 | }
|
| 138 | } while(trn);
|
| 139 |
|
| 140 | reg = RREG32_NO_KIQ(SOC15_REG_OFFSET(NBIO, 0,
|
| 141 | mmBIF_BX_PF0_MAILBOX_MSGBUF_TRN_DW0));
|
| 142 | reg = REG_SET_FIELD(reg, BIF_BX_PF0_MAILBOX_MSGBUF_TRN_DW0,
|
| 143 | MSGBUF_DATA, req);
|
| 144 | WREG32_NO_KIQ(SOC15_REG_OFFSET(NBIO, 0, mmBIF_BX_PF0_MAILBOX_MSGBUF_TRN_DW0),
|
| 145 | reg);
|
| 146 | WREG32_NO_KIQ(SOC15_REG_OFFSET(NBIO, 0, mmBIF_BX_PF0_MAILBOX_MSGBUF_TRN_DW1),
|
| 147 | data1);
|
| 148 | WREG32_NO_KIQ(SOC15_REG_OFFSET(NBIO, 0, mmBIF_BX_PF0_MAILBOX_MSGBUF_TRN_DW2),
|
| 149 | data2);
|
| 150 | WREG32_NO_KIQ(SOC15_REG_OFFSET(NBIO, 0, mmBIF_BX_PF0_MAILBOX_MSGBUF_TRN_DW3),
|
| 151 | data3);
|
| 152 |
|
| 153 | xgpu_ai_mailbox_set_valid(adev, true);
|
| 154 |
|
| 155 |
|
| 156 | r = xgpu_ai_poll_ack(adev);
|
| 157 | if (r)
|
| 158 | dev_err(adev->dev, "Doesn't get ack from pf, continue\n");
|
| 159 |
|
| 160 | xgpu_ai_mailbox_set_valid(adev, false);
|
| 161 | }
|
| 162 |
|
| 163 | static int xgpu_ai_send_access_requests(struct amdgpu_device *adev,
|
| 164 | enum idh_request req)
|
| 165 | {
|
| 166 | int r;
|
| 167 |
|
| 168 | xgpu_ai_mailbox_trans_msg(adev, req, 0, 0, 0);
|
| 169 |
|
| 170 |
|
| 171 | if (req == IDH_REQ_GPU_INIT_ACCESS ||
|
| 172 | req == IDH_REQ_GPU_FINI_ACCESS ||
|
| 173 | req == IDH_REQ_GPU_RESET_ACCESS) {
|
| 174 | r = xgpu_ai_poll_msg(adev, IDH_READY_TO_ACCESS_GPU);
|
| 175 | if (r) {
|
| 176 | dev_err(adev->dev, "Doesn't get READY_TO_ACCESS_GPU from pf, give up\n");
|
| 177 | return r;
|
| 178 | }
|
| 179 |
|
| 180 | if (req == IDH_REQ_GPU_INIT_ACCESS || req == IDH_REQ_GPU_RESET_ACCESS) {
|
| 181 | adev->virt.fw_reserve.checksum_key =
|
| 182 | RREG32_NO_KIQ(SOC15_REG_OFFSET(NBIO, 0,
|
| 183 | mmBIF_BX_PF0_MAILBOX_MSGBUF_RCV_DW2));
|
| 184 | }
|
| 185 | } else if (req == IDH_REQ_GPU_INIT_DATA){
|
| 186 |
|
| 187 | r = xgpu_ai_poll_msg(adev, IDH_REQ_GPU_INIT_DATA_READY);
|
| 188 | |
| 189 | * AI uses the GPU_CRIT_REGION_V1 layout in practice, so fix the
|
| 190 | * dummy version value to match the actual init-data format.
|
| 191 |
|
| 192 | adev->virt.req_init_data_ver = GPU_CRIT_REGION_V1;
|
| 193 | }
|
| 194 |
|
| 195 | return 0;
|
| 196 | }
|
| 197 |
|
| 198 | static int xgpu_ai_request_reset(struct amdgpu_device *adev)
|
| 199 | {
|
| 200 | int ret, i = 0;
|
| 201 |
|
| 202 | while (i < AI_MAILBOX_POLL_MSG_REP_MAX) {
|
| 203 | ret = xgpu_ai_send_access_requests(adev, IDH_REQ_GPU_RESET_ACCESS);
|
| 204 | if (!ret)
|
| 205 | break;
|
| 206 | i++;
|
| 207 | }
|
| 208 |
|
| 209 | return ret;
|
| 210 | }
|
| 211 |
|
| 212 | static int xgpu_ai_request_full_gpu_access(struct amdgpu_device *adev,
|
| 213 | bool init)
|
| 214 | {
|
| 215 | enum idh_request req;
|
| 216 |
|
| 217 | req = init ? IDH_REQ_GPU_INIT_ACCESS : IDH_REQ_GPU_FINI_ACCESS;
|
| 218 | return xgpu_ai_send_access_requests(adev, req);
|
| 219 | }
|
| 220 |
|
| 221 | static int xgpu_ai_release_full_gpu_access(struct amdgpu_device *adev,
|
| 222 | bool init)
|
| 223 | {
|
| 224 | enum idh_request req;
|
| 225 | int r = 0;
|
| 226 |
|
| 227 | req = init ? IDH_REL_GPU_INIT_ACCESS : IDH_REL_GPU_FINI_ACCESS;
|
| 228 | r = xgpu_ai_send_access_requests(adev, req);
|
| 229 |
|
| 230 | return r;
|
| 231 | }
|
| 232 |
|
| 233 | static int xgpu_ai_mailbox_ack_irq(struct amdgpu_device *adev,
|
| 234 | struct amdgpu_irq_src *source,
|
| 235 | struct amdgpu_iv_entry *entry)
|
| 236 | {
|
| 237 | dev_dbg(adev->dev, "get ack intr and do nothing.\n");
|
| 238 | return 0;
|
| 239 | }
|
| 240 |
|
| 241 | static int xgpu_ai_set_mailbox_ack_irq(struct amdgpu_device *adev,
|
| 242 | struct amdgpu_irq_src *source,
|
| 243 | unsigned type,
|
| 244 | enum amdgpu_interrupt_state state)
|
| 245 | {
|
| 246 | u32 tmp = RREG32_NO_KIQ(SOC15_REG_OFFSET(NBIO, 0, mmBIF_BX_PF0_MAILBOX_INT_CNTL));
|
| 247 |
|
| 248 | tmp = REG_SET_FIELD(tmp, BIF_BX_PF0_MAILBOX_INT_CNTL, ACK_INT_EN,
|
| 249 | (state == AMDGPU_IRQ_STATE_ENABLE) ? 1 : 0);
|
| 250 | WREG32_NO_KIQ(SOC15_REG_OFFSET(NBIO, 0, mmBIF_BX_PF0_MAILBOX_INT_CNTL), tmp);
|
| 251 |
|
| 252 | return 0;
|
| 253 | }
|
| 254 |
|
| 255 | static void xgpu_ai_ready_to_reset(struct amdgpu_device *adev)
|
| 256 | {
|
| 257 | xgpu_ai_mailbox_trans_msg(adev, IDH_READY_TO_RESET, 0, 0, 0);
|
| 258 | }
|
| 259 |
|
| 260 | static int xgpu_ai_wait_reset(struct amdgpu_device *adev)
|
| 261 | {
|
| 262 | int timeout = AI_MAILBOX_POLL_FLR_TIMEDOUT;
|
| 263 | do {
|
| 264 | if (xgpu_ai_mailbox_peek_msg(adev) == IDH_FLR_NOTIFICATION_CMPL) {
|
| 265 | dev_dbg(adev->dev, "Got AI IDH_FLR_NOTIFICATION_CMPL after %d ms\n", AI_MAILBOX_POLL_FLR_TIMEDOUT - timeout);
|
| 266 | return 0;
|
| 267 | }
|
| 268 | msleep(10);
|
| 269 | timeout -= 10;
|
| 270 | } while (timeout > 1);
|
| 271 |
|
| 272 | dev_dbg(adev->dev, "waiting AI IDH_FLR_NOTIFICATION_CMPL timeout\n");
|
| 273 | return -ETIME;
|
| 274 | }
|
| 275 |
|
| 276 | static void xgpu_ai_mailbox_flr_work(struct work_struct *work)
|
| 277 | {
|
| 278 | struct amdgpu_virt *virt = container_of(work, struct amdgpu_virt, flr_work);
|
| 279 | struct amdgpu_device *adev = container_of(virt, struct amdgpu_device, virt);
|
| 280 | struct amdgpu_reset_context reset_context = { 0 };
|
| 281 |
|
| 282 | amdgpu_virt_fini_data_exchange(adev);
|
| 283 |
|
| 284 |
|
| 285 | if (amdgpu_device_should_recover_gpu(adev)
|
| 286 | && (!amdgpu_device_has_job_running(adev) ||
|
| 287 | adev->sdma_timeout == MAX_SCHEDULE_TIMEOUT)) {
|
| 288 |
|
| 289 | reset_context.method = AMD_RESET_METHOD_NONE;
|
| 290 | reset_context.reset_req_dev = adev;
|
| 291 | clear_bit(AMDGPU_NEED_FULL_RESET, &reset_context.flags);
|
| 292 | set_bit(AMDGPU_HOST_FLR, &reset_context.flags);
|
| 293 |
|
| 294 | amdgpu_device_gpu_recover(adev, NULL, &reset_context);
|
| 295 | }
|
| 296 | }
|
| 297 |
|
| 298 | static void xgpu_ai_mailbox_req_bad_pages_work(struct work_struct *work)
|
| 299 | {
|
| 300 | struct amdgpu_virt *virt = container_of(work, struct amdgpu_virt, req_bad_pages_work);
|
| 301 | struct amdgpu_device *adev = container_of(virt, struct amdgpu_device, virt);
|
| 302 |
|
| 303 | if (down_read_trylock(&adev->reset_domain->sem)) {
|
| 304 | amdgpu_virt_fini_data_exchange(adev);
|
| 305 | amdgpu_virt_request_bad_pages(adev);
|
| 306 | up_read(&adev->reset_domain->sem);
|
| 307 | }
|
| 308 | }
|
| 309 |
|
| 310 | |
| 311 | * xgpu_ai_mailbox_handle_bad_pages_work - Reinitialize the data exchange region to get fresh bad page information
|
| 312 | * @work: pointer to the work_struct
|
| 313 | *
|
| 314 | * This work handler is triggered when bad pages are ready, and it reinitializes
|
| 315 | * the data exchange region to retrieve updated bad page information from the host.
|
| 316 |
|
| 317 | static void xgpu_ai_mailbox_handle_bad_pages_work(struct work_struct *work)
|
| 318 | {
|
| 319 | struct amdgpu_virt *virt = container_of(work, struct amdgpu_virt, handle_bad_pages_work);
|
| 320 | struct amdgpu_device *adev = container_of(virt, struct amdgpu_device, virt);
|
| 321 |
|
| 322 | if (down_read_trylock(&adev->reset_domain->sem)) {
|
| 323 | amdgpu_virt_fini_data_exchange(adev);
|
| 324 | amdgpu_virt_init_data_exchange(adev);
|
| 325 | up_read(&adev->reset_domain->sem);
|
| 326 | }
|
| 327 | }
|
| 328 |
|
| 329 | static int xgpu_ai_set_mailbox_rcv_irq(struct amdgpu_device *adev,
|
| 330 | struct amdgpu_irq_src *src,
|
| 331 | unsigned type,
|
| 332 | enum amdgpu_interrupt_state state)
|
| 333 | {
|
| 334 | u32 tmp = RREG32_NO_KIQ(SOC15_REG_OFFSET(NBIO, 0, mmBIF_BX_PF0_MAILBOX_INT_CNTL));
|
| 335 |
|
| 336 | tmp = REG_SET_FIELD(tmp, BIF_BX_PF0_MAILBOX_INT_CNTL, VALID_INT_EN,
|
| 337 | (state == AMDGPU_IRQ_STATE_ENABLE) ? 1 : 0);
|
| 338 | WREG32_NO_KIQ(SOC15_REG_OFFSET(NBIO, 0, mmBIF_BX_PF0_MAILBOX_INT_CNTL), tmp);
|
| 339 |
|
| 340 | return 0;
|
| 341 | }
|
| 342 |
|
| 343 | static int xgpu_ai_mailbox_rcv_irq(struct amdgpu_device *adev,
|
| 344 | struct amdgpu_irq_src *source,
|
| 345 | struct amdgpu_iv_entry *entry)
|
| 346 | {
|
| 347 | enum idh_event event = xgpu_ai_mailbox_peek_msg(adev);
|
| 348 | struct amdgpu_ras *ras = amdgpu_ras_get_context(adev);
|
| 349 |
|
| 350 | switch (event) {
|
| 351 | case IDH_RAS_BAD_PAGES_READY:
|
| 352 | xgpu_ai_mailbox_send_ack(adev);
|
| 353 | if (amdgpu_sriov_runtime(adev))
|
| 354 | schedule_work(&adev->virt.handle_bad_pages_work);
|
| 355 | break;
|
| 356 | case IDH_RAS_BAD_PAGES_NOTIFICATION:
|
| 357 | xgpu_ai_mailbox_send_ack(adev);
|
| 358 | if (amdgpu_sriov_runtime(adev))
|
| 359 | schedule_work(&adev->virt.req_bad_pages_work);
|
| 360 | break;
|
| 361 | case IDH_UNRECOV_ERR_NOTIFICATION:
|
| 362 | xgpu_ai_mailbox_send_ack(adev);
|
| 363 | ras->is_rma = true;
|
| 364 | dev_err(adev->dev, "VF is in an unrecoverable state. Runtime Services are halted.\n");
|
| 365 | if (amdgpu_sriov_runtime(adev))
|
| 366 | WARN_ONCE(!amdgpu_reset_domain_schedule(adev->reset_domain,
|
| 367 | &adev->virt.flr_work),
|
| 368 | "Failed to queue work! at %s",
|
| 369 | __func__);
|
| 370 | break;
|
| 371 | case IDH_FLR_NOTIFICATION:
|
| 372 | if (amdgpu_sriov_runtime(adev))
|
| 373 | WARN_ONCE(!amdgpu_reset_domain_schedule(adev->reset_domain,
|
| 374 | &adev->virt.flr_work),
|
| 375 | "Failed to queue work! at %s",
|
| 376 | __func__);
|
| 377 | break;
|
| 378 | case IDH_QUERY_ALIVE:
|
| 379 | xgpu_ai_mailbox_send_ack(adev);
|
| 380 | break;
|
| 381 | |
| 382 | * it byfar since that polling thread will handle it,
|
| 383 | * other msg like flr complete is not handled here.
|
| 384 |
|
| 385 | case IDH_CLR_MSG_BUF:
|
| 386 | case IDH_FLR_NOTIFICATION_CMPL:
|
| 387 | case IDH_READY_TO_ACCESS_GPU:
|
| 388 | default:
|
| 389 | break;
|
| 390 | }
|
| 391 |
|
| 392 | return 0;
|
| 393 | }
|
| 394 |
|
| 395 | static const struct amdgpu_irq_src_funcs xgpu_ai_mailbox_ack_irq_funcs = {
|
| 396 | .set = xgpu_ai_set_mailbox_ack_irq,
|
| 397 | .process = xgpu_ai_mailbox_ack_irq,
|
| 398 | };
|
| 399 |
|
| 400 | static const struct amdgpu_irq_src_funcs xgpu_ai_mailbox_rcv_irq_funcs = {
|
| 401 | .set = xgpu_ai_set_mailbox_rcv_irq,
|
| 402 | .process = xgpu_ai_mailbox_rcv_irq,
|
| 403 | };
|
| 404 |
|
| 405 | void xgpu_ai_mailbox_set_irq_funcs(struct amdgpu_device *adev)
|
| 406 | {
|
| 407 | adev->virt.ack_irq.num_types = 1;
|
| 408 | adev->virt.ack_irq.funcs = &xgpu_ai_mailbox_ack_irq_funcs;
|
| 409 | adev->virt.rcv_irq.num_types = 1;
|
| 410 | adev->virt.rcv_irq.funcs = &xgpu_ai_mailbox_rcv_irq_funcs;
|
| 411 | }
|
| 412 |
|
| 413 | int xgpu_ai_mailbox_add_irq_id(struct amdgpu_device *adev)
|
| 414 | {
|
| 415 | int r;
|
| 416 |
|
| 417 | r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_BIF, 135, &adev->virt.rcv_irq);
|
| 418 | if (r)
|
| 419 | return r;
|
| 420 |
|
| 421 | r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_BIF, 138, &adev->virt.ack_irq);
|
| 422 | if (r) {
|
| 423 | amdgpu_irq_put(adev, &adev->virt.rcv_irq, 0);
|
| 424 | return r;
|
| 425 | }
|
| 426 |
|
| 427 | return 0;
|
| 428 | }
|
| 429 |
|
| 430 | int xgpu_ai_mailbox_get_irq(struct amdgpu_device *adev)
|
| 431 | {
|
| 432 | int r;
|
| 433 |
|
| 434 | r = amdgpu_irq_get(adev, &adev->virt.rcv_irq, 0);
|
| 435 | if (r)
|
| 436 | return r;
|
| 437 | r = amdgpu_irq_get(adev, &adev->virt.ack_irq, 0);
|
| 438 | if (r) {
|
| 439 | amdgpu_irq_put(adev, &adev->virt.rcv_irq, 0);
|
| 440 | return r;
|
| 441 | }
|
| 442 |
|
| 443 | INIT_WORK(&adev->virt.flr_work, xgpu_ai_mailbox_flr_work);
|
| 444 | INIT_WORK(&adev->virt.req_bad_pages_work, xgpu_ai_mailbox_req_bad_pages_work);
|
| 445 | INIT_WORK(&adev->virt.handle_bad_pages_work, xgpu_ai_mailbox_handle_bad_pages_work);
|
| 446 |
|
| 447 | return 0;
|
| 448 | }
|
| 449 |
|
| 450 | void xgpu_ai_mailbox_put_irq(struct amdgpu_device *adev)
|
| 451 | {
|
| 452 | amdgpu_irq_put(adev, &adev->virt.ack_irq, 0);
|
| 453 | amdgpu_irq_put(adev, &adev->virt.rcv_irq, 0);
|
| 454 | }
|
| 455 |
|
| 456 | static int xgpu_ai_request_init_data(struct amdgpu_device *adev)
|
| 457 | {
|
| 458 | return xgpu_ai_send_access_requests(adev, IDH_REQ_GPU_INIT_DATA);
|
| 459 | }
|
| 460 |
|
| 461 | static void xgpu_ai_ras_poison_handler(struct amdgpu_device *adev,
|
| 462 | enum amdgpu_ras_block block)
|
| 463 | {
|
| 464 | xgpu_ai_send_access_requests(adev, IDH_RAS_POISON);
|
| 465 | }
|
| 466 |
|
| 467 | static bool xgpu_ai_rcvd_ras_intr(struct amdgpu_device *adev)
|
| 468 | {
|
| 469 | enum idh_event msg = xgpu_ai_mailbox_peek_msg(adev);
|
| 470 |
|
| 471 | return (msg == IDH_RAS_ERROR_DETECTED || msg == 0xFFFFFFFF);
|
| 472 | }
|
| 473 |
|
| 474 | const struct amdgpu_virt_ops xgpu_ai_virt_ops = {
|
| 475 | .req_full_gpu = xgpu_ai_request_full_gpu_access,
|
| 476 | .rel_full_gpu = xgpu_ai_release_full_gpu_access,
|
| 477 | .reset_gpu = xgpu_ai_request_reset,
|
| 478 | .ready_to_reset = xgpu_ai_ready_to_reset,
|
| 479 | .wait_reset = xgpu_ai_wait_reset,
|
| 480 | .trans_msg = xgpu_ai_mailbox_trans_msg,
|
| 481 | .req_init_data = xgpu_ai_request_init_data,
|
| 482 | .ras_poison_handler = xgpu_ai_ras_poison_handler,
|
| 483 | .rcvd_ras_intr = xgpu_ai_rcvd_ras_intr,
|
| 484 | };
|