diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvkm/subdev')
97 files changed, 2114 insertions, 1670 deletions
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/Kbuild index 2cb24fff7e32..4c2f6fc4ef58 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/Kbuild @@ -23,4 +23,5 @@ include $(src)/nvkm/subdev/privring/Kbuild include $(src)/nvkm/subdev/therm/Kbuild include $(src)/nvkm/subdev/timer/Kbuild include $(src)/nvkm/subdev/top/Kbuild +include $(src)/nvkm/subdev/vfn/Kbuild include $(src)/nvkm/subdev/volt/Kbuild diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/Kbuild index 5b9f64a8957f..5731f35b11e1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/Kbuild @@ -1,10 +1,12 @@ # SPDX-License-Identifier: MIT nvkm-y += nvkm/subdev/acr/base.o -nvkm-y += nvkm/subdev/acr/hsfw.o nvkm-y += nvkm/subdev/acr/lsfw.o nvkm-y += nvkm/subdev/acr/gm200.o nvkm-y += nvkm/subdev/acr/gm20b.o nvkm-y += nvkm/subdev/acr/gp102.o nvkm-y += nvkm/subdev/acr/gp108.o +nvkm-y += nvkm/subdev/acr/gv100.o nvkm-y += nvkm/subdev/acr/gp10b.o nvkm-y += nvkm/subdev/acr/tu102.o +nvkm-y += nvkm/subdev/acr/ga100.o +nvkm-y += nvkm/subdev/acr/ga102.o diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/base.c index af6cac696d43..795f3a649b12 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/base.c @@ -24,50 +24,63 @@ #include <core/firmware.h> #include <core/memory.h> #include <subdev/mmu.h> +#include <subdev/gsp.h> +#include <subdev/pmu.h> +#include <engine/sec2.h> +#include <engine/nvdec.h> -static struct nvkm_acr_hsf * -nvkm_acr_hsf_find(struct nvkm_acr *acr, const char *name) +static struct nvkm_acr_hsfw * +nvkm_acr_hsfw_find(struct nvkm_acr *acr, const char *name) { - struct nvkm_acr_hsf *hsf; - list_for_each_entry(hsf, &acr->hsf, head) { - if (!strcmp(hsf->name, name)) - return hsf; + struct nvkm_acr_hsfw *hsfw; + + list_for_each_entry(hsfw, &acr->hsfw, head) { + if (!strcmp(hsfw->fw.fw.name, name)) + return hsfw; } + return NULL; } int -nvkm_acr_hsf_boot(struct nvkm_acr *acr, const char *name) +nvkm_acr_hsfw_boot(struct nvkm_acr *acr, const char *name) { struct nvkm_subdev *subdev = &acr->subdev; - struct nvkm_acr_hsf *hsf; - int ret; + struct nvkm_acr_hsfw *hsfw; - hsf = nvkm_acr_hsf_find(acr, name); - if (!hsf) + hsfw = nvkm_acr_hsfw_find(acr, name); + if (!hsfw) return -EINVAL; - nvkm_debug(subdev, "executing %s binary\n", hsf->name); - ret = nvkm_falcon_get(hsf->falcon, subdev); - if (ret) - return ret; + return nvkm_falcon_fw_boot(&hsfw->fw, subdev, true, NULL, NULL, + hsfw->boot_mbox0, hsfw->intr_clear); +} - ret = hsf->func->boot(acr, hsf); - nvkm_falcon_put(hsf->falcon, subdev); - if (ret) { - nvkm_error(subdev, "%s binary failed\n", hsf->name); - return ret; +static struct nvkm_acr_lsf * +nvkm_acr_rtos(struct nvkm_acr *acr) +{ + struct nvkm_acr_lsf *lsf; + + if (acr) { + list_for_each_entry(lsf, &acr->lsf, head) { + if (lsf->func->bootstrap_falcon) + return lsf; + } } - nvkm_debug(subdev, "%s binary completed successfully\n", hsf->name); - return 0; + return NULL; } static void nvkm_acr_unload(struct nvkm_acr *acr) { if (acr->done) { - nvkm_acr_hsf_boot(acr, "unload"); + if (acr->rtos) { + nvkm_subdev_unref(acr->rtos->falcon->owner); + acr->rtos = NULL; + } + + nvkm_acr_hsfw_boot(acr, "unload"); acr->done = false; } } @@ -76,7 +89,7 @@ static int nvkm_acr_load(struct nvkm_acr *acr) { struct nvkm_subdev *subdev = &acr->subdev; - struct nvkm_acr_lsf *lsf; + struct nvkm_acr_lsf *rtos = nvkm_acr_rtos(acr); u64 start, limit; int ret; @@ -100,12 +113,12 @@ nvkm_acr_load(struct nvkm_acr *acr) acr->done = true; - list_for_each_entry(lsf, &acr->lsf, head) { - if (lsf->func->boot) { - ret = lsf->func->boot(lsf->falcon); - if (ret) - break; - } + if (rtos) { + ret = nvkm_subdev_ref(rtos->falcon->owner); + if (ret) + return ret; + + acr->rtos = rtos; } return ret; @@ -118,33 +131,17 @@ nvkm_acr_reload(struct nvkm_acr *acr) return nvkm_acr_load(acr); } -static struct nvkm_acr_lsf * -nvkm_acr_falcon(struct nvkm_device *device) -{ - struct nvkm_acr *acr = device->acr; - struct nvkm_acr_lsf *lsf; - - if (acr) { - list_for_each_entry(lsf, &acr->lsf, head) { - if (lsf->func->bootstrap_falcon) - return lsf; - } - } - - return NULL; -} - int nvkm_acr_bootstrap_falcons(struct nvkm_device *device, unsigned long mask) { - struct nvkm_acr_lsf *acrflcn = nvkm_acr_falcon(device); struct nvkm_acr *acr = device->acr; + struct nvkm_acr_lsf *rtos = nvkm_acr_rtos(acr); unsigned long id; /* If there's no LS FW managing bootstrapping of other LS falcons, * we depend on the HS firmware being able to do it instead. */ - if (!acrflcn) { + if (!rtos) { /* Which isn't possible everywhere... */ if ((mask & acr->func->bootstrap_falcons) == mask) { int ret = nvkm_acr_reload(acr); @@ -156,16 +153,14 @@ nvkm_acr_bootstrap_falcons(struct nvkm_device *device, unsigned long mask) return -ENOSYS; } - if ((mask & acrflcn->func->bootstrap_falcons) != mask) + if ((mask & rtos->func->bootstrap_falcons) != mask) return -ENOSYS; - if (acrflcn->func->bootstrap_multiple_falcons) { - return acrflcn->func-> - bootstrap_multiple_falcons(acrflcn->falcon, mask); - } + if (rtos->func->bootstrap_multiple_falcons) + return rtos->func->bootstrap_multiple_falcons(rtos->falcon, mask); for_each_set_bit(id, &mask, NVKM_ACR_LSF_NUM) { - int ret = acrflcn->func->bootstrap_falcon(acrflcn->falcon, id); + int ret = rtos->func->bootstrap_falcon(rtos->falcon, id); if (ret) return ret; } @@ -189,6 +184,9 @@ nvkm_acr_managed_falcon(struct nvkm_device *device, enum nvkm_acr_lsf_id id) static int nvkm_acr_fini(struct nvkm_subdev *subdev, bool suspend) { + if (!subdev->use.enabled) + return 0; + nvkm_acr_unload(nvkm_acr(subdev)); return 0; } @@ -196,17 +194,19 @@ nvkm_acr_fini(struct nvkm_subdev *subdev, bool suspend) static int nvkm_acr_init(struct nvkm_subdev *subdev) { - if (!nvkm_acr_falcon(subdev->device)) + struct nvkm_acr *acr = nvkm_acr(subdev); + + if (!nvkm_acr_rtos(acr)) return 0; - return nvkm_acr_load(nvkm_acr(subdev)); + return nvkm_acr_load(acr); } static void nvkm_acr_cleanup(struct nvkm_acr *acr) { nvkm_acr_lsfw_del_all(acr); - nvkm_acr_hsfw_del_all(acr); + nvkm_firmware_put(acr->wpr_fw); acr->wpr_fw = NULL; } @@ -218,7 +218,8 @@ nvkm_acr_oneinit(struct nvkm_subdev *subdev) struct nvkm_acr *acr = nvkm_acr(subdev); struct nvkm_acr_hsfw *hsfw; struct nvkm_acr_lsfw *lsfw, *lsft; - struct nvkm_acr_lsf *lsf; + struct nvkm_acr_lsf *lsf, *rtos; + struct nvkm_falcon *falcon; u32 wpr_size = 0; u64 falcons; int ret, i; @@ -260,10 +261,10 @@ nvkm_acr_oneinit(struct nvkm_subdev *subdev) } /* Ensure the falcon that'll provide ACR functions is booted first. */ - lsf = nvkm_acr_falcon(device); - if (lsf) { - falcons = lsf->func->bootstrap_falcons; - list_move(&lsf->head, &acr->lsf); + rtos = nvkm_acr_rtos(acr); + if (rtos) { + falcons = rtos->func->bootstrap_falcons; + list_move(&rtos->head, &acr->lsf); } else { falcons = acr->func->bootstrap_falcons; } @@ -301,7 +302,7 @@ nvkm_acr_oneinit(struct nvkm_subdev *subdev) nvkm_wobj(acr->wpr, 0, acr->wpr_fw->data, acr->wpr_fw->size); if (!acr->wpr_fw || acr->wpr_comp) - acr->func->wpr_build(acr, nvkm_acr_falcon(device)); + acr->func->wpr_build(acr, rtos); acr->func->wpr_patch(acr, (s64)acr->wpr_start - acr->wpr_prev); if (acr->wpr_fw && acr->wpr_comp) { @@ -336,8 +337,16 @@ nvkm_acr_oneinit(struct nvkm_subdev *subdev) /* Load HS firmware blobs into ACR VMM. */ list_for_each_entry(hsfw, &acr->hsfw, head) { - nvkm_debug(subdev, "loading %s fw\n", hsfw->name); - ret = hsfw->func->load(acr, hsfw); + switch (hsfw->falcon_id) { + case NVKM_ACR_HSF_PMU : falcon = &device->pmu->falcon; break; + case NVKM_ACR_HSF_SEC2: falcon = &device->sec2->falcon; break; + case NVKM_ACR_HSF_GSP : falcon = &device->gsp->falcon; break; + default: + WARN_ON(1); + return -EINVAL; + } + + ret = nvkm_falcon_fw_oneinit(&hsfw->fw, falcon, acr->vmm, acr->inst); if (ret) return ret; } @@ -351,15 +360,13 @@ static void * nvkm_acr_dtor(struct nvkm_subdev *subdev) { struct nvkm_acr *acr = nvkm_acr(subdev); - struct nvkm_acr_hsf *hsf, *hst; + struct nvkm_acr_hsfw *hsfw, *hsft; struct nvkm_acr_lsf *lsf, *lst; - list_for_each_entry_safe(hsf, hst, &acr->hsf, head) { - nvkm_vmm_put(acr->vmm, &hsf->vma); - nvkm_memory_unref(&hsf->ucode); - kfree(hsf->imem); - list_del(&hsf->head); - kfree(hsf); + list_for_each_entry_safe(hsfw, hsft, &acr->hsfw, head) { + nvkm_falcon_fw_dtor(&hsfw->fw); + list_del(&hsfw->head); + kfree(hsfw); } nvkm_vmm_part(acr->vmm, acr->inst); @@ -420,7 +427,6 @@ nvkm_acr_new_(const struct nvkm_acr_fwif *fwif, struct nvkm_device *device, nvkm_subdev_ctor(&nvkm_acr, device, type, inst, &acr->subdev); INIT_LIST_HEAD(&acr->hsfw); INIT_LIST_HEAD(&acr->lsfw); - INIT_LIST_HEAD(&acr->hsf); INIT_LIST_HEAD(&acr->lsf); fwif = nvkm_firmware_load(&acr->subdev, fwif, "Acr", acr); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/ga100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/ga100.c new file mode 100644 index 000000000000..e3370c1551c0 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/ga100.c @@ -0,0 +1,49 @@ +/* + * Copyright 2021 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +#include "priv.h" + +void +ga100_acr_wpr_check(struct nvkm_acr *acr, u64 *start, u64 *limit) +{ + struct nvkm_device *device = acr->subdev.device; + + *start = (u64)(nvkm_rd32(device, 0x1fa81c) & 0xffffff00) << 8; + *limit = (u64)(nvkm_rd32(device, 0x1fa820) & 0xffffff00) << 8; + *limit = *limit + 0x20000; +} + +int +ga100_acr_hsfw_ctor(struct nvkm_acr *acr, const char *bl, const char *fw, + const char *name, int ver, const struct nvkm_acr_hsf_fwif *fwif) +{ + struct nvkm_acr_hsfw *hsfw; + + if (!(hsfw = kzalloc(sizeof(*hsfw), GFP_KERNEL))) + return -ENOMEM; + + hsfw->falcon_id = fwif->falcon_id; + hsfw->boot_mbox0 = fwif->boot_mbox0; + hsfw->intr_clear = fwif->intr_clear; + list_add_tail(&hsfw->head, &acr->hsfw); + + return nvkm_falcon_fw_ctor_hs_v2(fwif->func, name, &acr->subdev, fw, ver, NULL, &hsfw->fw); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/ga102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/ga102.c new file mode 100644 index 000000000000..45dcf493e972 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/ga102.c @@ -0,0 +1,326 @@ +/* + * Copyright 2021 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +#include "priv.h" + +#include <nvfw/acr.h> + +static int +ga102_acr_wpr_patch(struct nvkm_acr *acr, s64 adjust) +{ + struct wpr_header_v2 hdr; + struct lsb_header_v2 *lsb; + struct nvkm_acr_lsfw *lsfw; + u32 offset = 0; + + lsb = kvmalloc(sizeof(*lsb), GFP_KERNEL); + if (!lsb) + return -ENOMEM; + + do { + nvkm_robj(acr->wpr, offset, &hdr, sizeof(hdr)); + wpr_header_v2_dump(&acr->subdev, &hdr); + + list_for_each_entry(lsfw, &acr->lsfw, head) { + if (lsfw->id != hdr.wpr.falcon_id) + continue; + + nvkm_robj(acr->wpr, hdr.wpr.lsb_offset, lsb, sizeof(*lsb)); + lsb_header_v2_dump(&acr->subdev, lsb); + + lsfw->func->bld_patch(acr, lsb->bl_data_off, adjust); + break; + } + + offset += sizeof(hdr); + } while (hdr.wpr.falcon_id != WPR_HEADER_V1_FALCON_ID_INVALID); + + kvfree(lsb); + return 0; +} + +static int +ga102_acr_wpr_build_lsb(struct nvkm_acr *acr, struct nvkm_acr_lsfw *lsfw) +{ + struct lsb_header_v2 *hdr; + int ret = 0; + + if (WARN_ON(lsfw->sig->size != sizeof(hdr->signature))) + return -EINVAL; + + hdr = kvzalloc(sizeof(*hdr), GFP_KERNEL); + if (!hdr) + return -ENOMEM; + + hdr->hdr.identifier = WPR_GENERIC_HEADER_ID_LSF_LSB_HEADER; + hdr->hdr.version = 2; + hdr->hdr.size = sizeof(*hdr); + + memcpy(&hdr->signature, lsfw->sig->data, lsfw->sig->size); + hdr->ucode_off = lsfw->offset.img; + hdr->ucode_size = lsfw->ucode_size; + hdr->data_size = lsfw->data_size; + hdr->bl_code_size = lsfw->bootloader_size; + hdr->bl_imem_off = lsfw->bootloader_imem_offset; + hdr->bl_data_off = lsfw->offset.bld; + hdr->bl_data_size = lsfw->bl_data_size; + hdr->app_code_off = lsfw->app_start_offset + lsfw->app_resident_code_offset; + hdr->app_code_size = ALIGN(lsfw->app_resident_code_size, 0x100); + hdr->app_data_off = lsfw->app_start_offset + lsfw->app_resident_data_offset; + hdr->app_data_size = ALIGN(lsfw->app_resident_data_size, 0x100); + hdr->app_imem_offset = lsfw->app_imem_offset; + hdr->app_dmem_offset = lsfw->app_dmem_offset; + hdr->flags = lsfw->func->flags; + hdr->monitor_code_offset = 0; + hdr->monitor_data_offset = 0; + hdr->manifest_offset = 0; + + if (lsfw->secure_bootloader) { + struct nvkm_falcon_fw fw = { + .fw.img = hdr->hs_fmc_params.pkc_signature, + .fw.name = "LSFW", + .func = &(const struct nvkm_falcon_fw_func) { + .signature = ga100_flcn_fw_signature, + }, + .sig_size = lsfw->sig_size, + .sig_nr = lsfw->sig_nr, + .sigs = lsfw->sigs, + .fuse_ver = lsfw->fuse_ver, + .engine_id = lsfw->engine_id, + .ucode_id = lsfw->ucode_id, + .falcon = lsfw->falcon, + + }; + + ret = nvkm_falcon_get(fw.falcon, &acr->subdev); + if (ret == 0) { + hdr->hs_fmc_params.hs_fmc = 1; + hdr->hs_fmc_params.pkc_algo = 0; + hdr->hs_fmc_params.pkc_algo_version = 1; + hdr->hs_fmc_params.engid_mask = lsfw->engine_id; + hdr->hs_fmc_params.ucode_id = lsfw->ucode_id; + hdr->hs_fmc_params.fuse_ver = lsfw->fuse_ver; + ret = nvkm_falcon_fw_patch(&fw); + nvkm_falcon_put(fw.falcon, &acr->subdev); + } + } + + nvkm_wobj(acr->wpr, lsfw->offset.lsb, hdr, sizeof(*hdr)); + kvfree(hdr); + return ret; +} + +static int +ga102_acr_wpr_build(struct nvkm_acr *acr, struct nvkm_acr_lsf *rtos) +{ + struct nvkm_acr_lsfw *lsfw; + struct wpr_header_v2 hdr; + u32 offset = 0; + int ret; + + /*XXX: shared sub-WPR headers, fill terminator for now. */ + nvkm_wo32(acr->wpr, 0x300, (2 << 16) | WPR_GENERIC_HEADER_ID_LSF_SHARED_SUB_WPR); + nvkm_wo32(acr->wpr, 0x304, 0x14); + nvkm_wo32(acr->wpr, 0x308, 0xffffffff); + nvkm_wo32(acr->wpr, 0x30c, 0); + nvkm_wo32(acr->wpr, 0x310, 0); + + /* Fill per-LSF structures. */ + list_for_each_entry(lsfw, &acr->lsfw, head) { + struct lsf_signature_v2 *sig = (void *)lsfw->sig->data; + + hdr.hdr.identifier = WPR_GENERIC_HEADER_ID_LSF_WPR_HEADER; + hdr.hdr.version = 2; + hdr.hdr.size = sizeof(hdr); + hdr.wpr.falcon_id = lsfw->id; + hdr.wpr.lsb_offset = lsfw->offset.lsb; + hdr.wpr.bootstrap_owner = NVKM_ACR_LSF_GSPLITE; + hdr.wpr.lazy_bootstrap = 1; + hdr.wpr.bin_version = sig->ls_ucode_version; + hdr.wpr.status = WPR_HEADER_V1_STATUS_COPY; + + /* Write WPR header. */ + nvkm_wobj(acr->wpr, offset, &hdr, sizeof(hdr)); + offset += sizeof(hdr); + + /* Write LSB header. */ + ret = ga102_acr_wpr_build_lsb(acr, lsfw); + if (ret) + return ret; + + /* Write ucode image. */ + nvkm_wobj(acr->wpr, lsfw->offset.img, + lsfw->img.data, + lsfw->img.size); + + /* Write bootloader data. */ + lsfw->func->bld_write(acr, lsfw->offset.bld, lsfw); + } + + /* Finalise WPR. */ + hdr.hdr.identifier = WPR_GENERIC_HEADER_ID_LSF_WPR_HEADER; + hdr.hdr.version = 2; + hdr.hdr.size = sizeof(hdr); + hdr.wpr.falcon_id = WPR_HEADER_V1_FALCON_ID_INVALID; + nvkm_wobj(acr->wpr, offset, &hdr, sizeof(hdr)); + return 0; +} + +static u32 +ga102_acr_wpr_layout(struct nvkm_acr *acr) +{ + struct nvkm_acr_lsfw *lsfw; + u32 wpr = 0; + + wpr += 21 /* MAX_LSF */ * sizeof(struct wpr_header_v2); + wpr = ALIGN(wpr, 256); + + wpr += 0x100; /* Shared sub-WPR headers. */ + + list_for_each_entry(lsfw, &acr->lsfw, head) { + wpr = ALIGN(wpr, 256); + lsfw->offset.lsb = wpr; + wpr += sizeof(struct lsb_header_v2); + + wpr = ALIGN(wpr, 4096); + lsfw->offset.img = wpr; + wpr += lsfw->img.size; + + wpr = ALIGN(wpr, 256); + lsfw->offset.bld = wpr; + lsfw->bl_data_size = ALIGN(lsfw->func->bld_size, 256); + wpr += lsfw->bl_data_size; + } + + return wpr; +} + +static int +ga102_acr_wpr_parse(struct nvkm_acr *acr) +{ + const struct wpr_header_v2 *hdr = (void *)acr->wpr_fw->data; + + while (hdr->wpr.falcon_id != WPR_HEADER_V1_FALCON_ID_INVALID) { + wpr_header_v2_dump(&acr->subdev, hdr); + if (!nvkm_acr_lsfw_add(NULL, acr, NULL, (hdr++)->wpr.falcon_id)) + return -ENOMEM; + } + + return 0; +} + +MODULE_FIRMWARE("nvidia/ga102/acr/ucode_unload.bin"); +MODULE_FIRMWARE("nvidia/ga103/acr/ucode_unload.bin"); +MODULE_FIRMWARE("nvidia/ga104/acr/ucode_unload.bin"); +MODULE_FIRMWARE("nvidia/ga106/acr/ucode_unload.bin"); +MODULE_FIRMWARE("nvidia/ga107/acr/ucode_unload.bin"); + +static const struct nvkm_acr_hsf_fwif +ga102_acr_unload_fwif[] = { + { 0, ga100_acr_hsfw_ctor, &ga102_flcn_fw, NVKM_ACR_HSF_SEC2 }, + {} +}; + +MODULE_FIRMWARE("nvidia/ga102/acr/ucode_asb.bin"); +MODULE_FIRMWARE("nvidia/ga103/acr/ucode_asb.bin"); +MODULE_FIRMWARE("nvidia/ga104/acr/ucode_asb.bin"); +MODULE_FIRMWARE("nvidia/ga106/acr/ucode_asb.bin"); +MODULE_FIRMWARE("nvidia/ga107/acr/ucode_asb.bin"); + +static const struct nvkm_acr_hsf_fwif +ga102_acr_asb_fwif[] = { + { 0, ga100_acr_hsfw_ctor, &ga102_flcn_fw, NVKM_ACR_HSF_GSP }, + {} +}; + +static const struct nvkm_falcon_fw_func +ga102_acr_ahesasc_0 = { + .signature = ga100_flcn_fw_signature, + .reset = gm200_flcn_fw_reset, + .setup = gp102_acr_load_setup, + .load = ga102_flcn_fw_load, + .boot = ga102_flcn_fw_boot, +}; + +MODULE_FIRMWARE("nvidia/ga102/acr/ucode_ahesasc.bin"); +MODULE_FIRMWARE("nvidia/ga103/acr/ucode_ahesasc.bin"); +MODULE_FIRMWARE("nvidia/ga104/acr/ucode_ahesasc.bin"); +MODULE_FIRMWARE("nvidia/ga106/acr/ucode_ahesasc.bin"); +MODULE_FIRMWARE("nvidia/ga107/acr/ucode_ahesasc.bin"); + +static const struct nvkm_acr_hsf_fwif +ga102_acr_ahesasc_fwif[] = { + { 0, ga100_acr_hsfw_ctor, &ga102_acr_ahesasc_0, NVKM_ACR_HSF_SEC2 }, + {} +}; + +static const struct nvkm_acr_func +ga102_acr = { + .ahesasc = ga102_acr_ahesasc_fwif, + .asb = ga102_acr_asb_fwif, + .unload = ga102_acr_unload_fwif, + .wpr_parse = ga102_acr_wpr_parse, + .wpr_layout = ga102_acr_wpr_layout, + .wpr_alloc = gp102_acr_wpr_alloc, + .wpr_patch = ga102_acr_wpr_patch, + .wpr_build = ga102_acr_wpr_build, + .wpr_check = ga100_acr_wpr_check, + .init = tu102_acr_init, +}; + +static int +ga102_acr_load(struct nvkm_acr *acr, int version, + const struct nvkm_acr_fwif *fwif) +{ + struct nvkm_subdev *subdev = &acr->subdev; + const struct nvkm_acr_hsf_fwif *hsfwif; + + hsfwif = nvkm_firmware_load(subdev, fwif->func->ahesasc, "AcrAHESASC", + acr, NULL, "acr/ucode_ahesasc", "AHESASC"); + if (IS_ERR(hsfwif)) + return PTR_ERR(hsfwif); + + hsfwif = nvkm_firmware_load(subdev, fwif->func->asb, "AcrASB", + acr, NULL, "acr/ucode_asb", "ASB"); + if (IS_ERR(hsfwif)) + return PTR_ERR(hsfwif); + + hsfwif = nvkm_firmware_load(subdev, fwif->func->unload, "AcrUnload", + acr, NULL, "acr/ucode_unload", "unload"); + if (IS_ERR(hsfwif)) + return PTR_ERR(hsfwif); + + return 0; +} + +static const struct nvkm_acr_fwif +ga102_acr_fwif[] = { + { 0, ga102_acr_load, &ga102_acr }, + { -1, gm200_acr_nofw, &gm200_acr }, + {} +}; + +int +ga102_acr_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, + struct nvkm_acr **pacr) +{ + return nvkm_acr_new_(ga102_acr_fwif, device, type, inst, pacr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gm200.c b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gm200.c index 82b4c8e1457c..31079c947758 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gm200.c @@ -46,7 +46,7 @@ gm200_acr_nofw(struct nvkm_acr *acr, int ver, const struct nvkm_acr_fwif *fwif) int gm200_acr_init(struct nvkm_acr *acr) { - return nvkm_acr_hsf_boot(acr, "load"); + return nvkm_acr_hsfw_boot(acr, "load"); } void @@ -61,7 +61,7 @@ gm200_acr_wpr_check(struct nvkm_acr *acr, u64 *start, u64 *limit) *limit = *limit + 0x20000; } -void +int gm200_acr_wpr_patch(struct nvkm_acr *acr, s64 adjust) { struct nvkm_subdev *subdev = &acr->subdev; @@ -86,6 +86,8 @@ gm200_acr_wpr_patch(struct nvkm_acr *acr, s64 adjust) } offset += sizeof(hdr); } while (hdr.falcon_id != WPR_HEADER_V0_FALCON_ID_INVALID); + + return 0; } void @@ -219,162 +221,50 @@ gm200_acr_wpr_parse(struct nvkm_acr *acr) return 0; } -void -gm200_acr_hsfw_bld(struct nvkm_acr *acr, struct nvkm_acr_hsf *hsf) +int +gm200_acr_hsfw_load_bld(struct nvkm_falcon_fw *fw) { struct flcn_bl_dmem_desc_v1 hsdesc = { .ctx_dma = FALCON_DMAIDX_VIRT, - .code_dma_base = hsf->vma->addr, - .non_sec_code_off = hsf->non_sec_addr, - .non_sec_code_size = hsf->non_sec_size, - .sec_code_off = hsf->sec_addr, - .sec_code_size = hsf->sec_size, + .code_dma_base = fw->vma->addr, + .non_sec_code_off = fw->nmem_base, + .non_sec_code_size = fw->nmem_size, + .sec_code_off = fw->imem_base, + .sec_code_size = fw->imem_size, .code_entry_point = 0, - .data_dma_base = hsf->vma->addr + hsf->data_addr, - .data_size = hsf->data_size, + .data_dma_base = fw->vma->addr + fw->dmem_base_img, + .data_size = fw->dmem_size, }; - flcn_bl_dmem_desc_v1_dump(&acr->subdev, &hsdesc); - - nvkm_falcon_load_dmem(hsf->falcon, &hsdesc, 0, sizeof(hsdesc), 0); -} - -int -gm200_acr_hsfw_boot(struct nvkm_acr *acr, struct nvkm_acr_hsf *hsf, - u32 intr_clear, u32 mbox0_ok) -{ - struct nvkm_subdev *subdev = &acr->subdev; - struct nvkm_device *device = subdev->device; - struct nvkm_falcon *falcon = hsf->falcon; - u32 mbox0, mbox1; - int ret; - - /* Reset falcon. */ - nvkm_falcon_reset(falcon); - nvkm_falcon_bind_context(falcon, acr->inst); + flcn_bl_dmem_desc_v1_dump(fw->falcon->user, &hsdesc); - /* Load bootloader into IMEM. */ - nvkm_falcon_load_imem(falcon, hsf->imem, - falcon->code.limit - hsf->imem_size, - hsf->imem_size, - hsf->imem_tag, - 0, false); - - /* Load bootloader data into DMEM. */ - hsf->func->bld(acr, hsf); - - /* Boot the falcon. */ - nvkm_mc_intr_mask(device, falcon->owner->type, falcon->owner->inst, false); - - nvkm_falcon_wr32(falcon, 0x040, 0xdeada5a5); - nvkm_falcon_set_start_addr(falcon, hsf->imem_tag << 8); - nvkm_falcon_start(falcon); - ret = nvkm_falcon_wait_for_halt(falcon, 100); - if (ret) - return ret; - - /* Check for successful completion. */ - mbox0 = nvkm_falcon_rd32(falcon, 0x040); - mbox1 = nvkm_falcon_rd32(falcon, 0x044); - nvkm_debug(subdev, "mailbox %08x %08x\n", mbox0, mbox1); - if (mbox0 && mbox0 != mbox0_ok) - return -EIO; - - nvkm_falcon_clear_interrupt(falcon, intr_clear); - nvkm_mc_intr_mask(device, falcon->owner->type, falcon->owner->inst, true); - return ret; + return nvkm_falcon_pio_wr(fw->falcon, (u8 *)&hsdesc, 0, 0, DMEM, 0, sizeof(hsdesc), 0, 0); } int -gm200_acr_hsfw_load(struct nvkm_acr *acr, struct nvkm_acr_hsfw *hsfw, - struct nvkm_falcon *falcon) +gm200_acr_hsfw_ctor(struct nvkm_acr *acr, const char *bl, const char *fw, const char *name, int ver, + const struct nvkm_acr_hsf_fwif *fwif) { - struct nvkm_subdev *subdev = &acr->subdev; - struct nvkm_acr_hsf *hsf; - int ret; - - /* Patch the appropriate signature (production/debug) into the FW - * image, as determined by the mode the falcon is in. - */ - ret = nvkm_falcon_get(falcon, subdev); - if (ret) - return ret; - - if (hsfw->sig.patch_loc) { - if (!falcon->debug) { - nvkm_debug(subdev, "patching production signature\n"); - memcpy(hsfw->image + hsfw->sig.patch_loc, - hsfw->sig.prod.data, - hsfw->sig.prod.size); - } else { - nvkm_debug(subdev, "patching debug signature\n"); - memcpy(hsfw->image + hsfw->sig.patch_loc, - hsfw->sig.dbg.data, - hsfw->sig.dbg.size); - } - } - - nvkm_falcon_put(falcon, subdev); + struct nvkm_acr_hsfw *hsfw; - if (!(hsf = kzalloc(sizeof(*hsf), GFP_KERNEL))) + if (!(hsfw = kzalloc(sizeof(*hsfw), GFP_KERNEL))) return -ENOMEM; - hsf->func = hsfw->func; - hsf->name = hsfw->name; - list_add_tail(&hsf->head, &acr->hsf); - - hsf->imem_size = hsfw->imem_size; - hsf->imem_tag = hsfw->imem_tag; - hsf->imem = kmemdup(hsfw->imem, hsfw->imem_size, GFP_KERNEL); - if (!hsf->imem) - return -ENOMEM; - - hsf->non_sec_addr = hsfw->non_sec_addr; - hsf->non_sec_size = hsfw->non_sec_size; - hsf->sec_addr = hsfw->sec_addr; - hsf->sec_size = hsfw->sec_size; - hsf->data_addr = hsfw->data_addr; - hsf->data_size = hsfw->data_size; - - /* Make the FW image accessible to the HS bootloader. */ - ret = nvkm_memory_new(subdev->device, NVKM_MEM_TARGET_INST, - hsfw->image_size, 0x1000, false, &hsf->ucode); - if (ret) - return ret; - - nvkm_kmap(hsf->ucode); - nvkm_wobj(hsf->ucode, 0, hsfw->image, hsfw->image_size); - nvkm_done(hsf->ucode); - - ret = nvkm_vmm_get(acr->vmm, 12, nvkm_memory_size(hsf->ucode), - &hsf->vma); - if (ret) - return ret; - - ret = nvkm_memory_map(hsf->ucode, 0, acr->vmm, hsf->vma, NULL, 0); - if (ret) - return ret; - hsf->falcon = falcon; - return 0; -} + hsfw->falcon_id = fwif->falcon_id; + hsfw->boot_mbox0 = fwif->boot_mbox0; + hsfw->intr_clear = fwif->intr_clear; + list_add_tail(&hsfw->head, &acr->hsfw); -int -gm200_acr_unload_boot(struct nvkm_acr *acr, struct nvkm_acr_hsf *hsf) -{ - return gm200_acr_hsfw_boot(acr, hsf, 0, 0x1d); -} - -int -gm200_acr_unload_load(struct nvkm_acr *acr, struct nvkm_acr_hsfw *hsfw) -{ - return gm200_acr_hsfw_load(acr, hsfw, &acr->subdev.device->pmu->falcon); + return nvkm_falcon_fw_ctor_hs(fwif->func, name, &acr->subdev, bl, fw, ver, NULL, &hsfw->fw); } -const struct nvkm_acr_hsf_func +const struct nvkm_falcon_fw_func gm200_acr_unload_0 = { - .load = gm200_acr_unload_load, - .boot = gm200_acr_unload_boot, - .bld = gm200_acr_hsfw_bld, + .signature = gm200_flcn_fw_signature, + .reset = gm200_flcn_fw_reset, + .load = gm200_flcn_fw_load, + .load_bld = gm200_acr_hsfw_load_bld, + .boot = gm200_flcn_fw_boot, }; MODULE_FIRMWARE("nvidia/gm200/acr/ucode_unload.bin"); @@ -384,20 +274,15 @@ MODULE_FIRMWARE("nvidia/gp100/acr/ucode_unload.bin"); static const struct nvkm_acr_hsf_fwif gm200_acr_unload_fwif[] = { - { 0, nvkm_acr_hsfw_load, &gm200_acr_unload_0 }, + { 0, gm200_acr_hsfw_ctor, &gm200_acr_unload_0, NVKM_ACR_HSF_PMU, 0, 0x00000010 }, {} }; -int -gm200_acr_load_boot(struct nvkm_acr *acr, struct nvkm_acr_hsf *hsf) -{ - return gm200_acr_hsfw_boot(acr, hsf, 0x10, 0); -} - static int -gm200_acr_load_load(struct nvkm_acr *acr, struct nvkm_acr_hsfw *hsfw) +gm200_acr_load_setup(struct nvkm_falcon_fw *fw) { - struct flcn_acr_desc *desc = (void *)&hsfw->image[hsfw->data_addr]; + struct flcn_acr_desc *desc = (void *)&fw->fw.img[fw->dmem_base_img]; + struct nvkm_acr *acr = fw->falcon->owner->device->acr; desc->wpr_region_id = 1; desc->regions.no_regions = 2; @@ -408,15 +293,17 @@ gm200_acr_load_load(struct nvkm_acr *acr, struct nvkm_acr_hsfw *hsfw) desc->regions.region_props[0].write_mask = 0xc; desc->regions.region_props[0].client_mask = 0x2; flcn_acr_desc_dump(&acr->subdev, desc); - - return gm200_acr_hsfw_load(acr, hsfw, &acr->subdev.device->pmu->falcon); + return 0; } -static const struct nvkm_acr_hsf_func +static const struct nvkm_falcon_fw_func gm200_acr_load_0 = { - .load = gm200_acr_load_load, - .boot = gm200_acr_load_boot, - .bld = gm200_acr_hsfw_bld, + .signature = gm200_flcn_fw_signature, + .reset = gm200_flcn_fw_reset, + .setup = gm200_acr_load_setup, + .load = gm200_flcn_fw_load, + .load_bld = gm200_acr_hsfw_load_bld, + .boot = gm200_flcn_fw_boot, }; MODULE_FIRMWARE("nvidia/gm200/acr/bl.bin"); @@ -433,7 +320,7 @@ MODULE_FIRMWARE("nvidia/gp100/acr/ucode_load.bin"); static const struct nvkm_acr_hsf_fwif gm200_acr_load_fwif[] = { - { 0, nvkm_acr_hsfw_load, &gm200_acr_load_0 }, + { 0, gm200_acr_hsfw_ctor, &gm200_acr_load_0, NVKM_ACR_HSF_PMU, 0, 0x00000010 }, {} }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gm20b.c index 54e996f2f630..ef5fb79128b1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gm20b.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gm20b.c @@ -45,43 +45,47 @@ gm20b_acr_wpr_alloc(struct nvkm_acr *acr, u32 wpr_size) wpr_size, 0, true, &acr->wpr); } -static void -gm20b_acr_load_bld(struct nvkm_acr *acr, struct nvkm_acr_hsf *hsf) +static int +gm20b_acr_hsfw_load_bld(struct nvkm_falcon_fw *fw) { struct flcn_bl_dmem_desc hsdesc = { .ctx_dma = FALCON_DMAIDX_VIRT, - .code_dma_base = hsf->vma->addr >> 8, - .non_sec_code_off = hsf->non_sec_addr, - .non_sec_code_size = hsf->non_sec_size, - .sec_code_off = hsf->sec_addr, - .sec_code_size = hsf->sec_size, + .code_dma_base = fw->vma->addr >> 8, + .non_sec_code_off = fw->nmem_base, + .non_sec_code_size = fw->nmem_size, + .sec_code_off = fw->imem_base, + .sec_code_size = fw->imem_size, .code_entry_point = 0, - .data_dma_base = (hsf->vma->addr + hsf->data_addr) >> 8, - .data_size = hsf->data_size, + .data_dma_base = (fw->vma->addr + fw->dmem_base_img) >> 8, + .data_size = fw->dmem_size, }; - flcn_bl_dmem_desc_dump(&acr->subdev, &hsdesc); + flcn_bl_dmem_desc_dump(fw->falcon->user, &hsdesc); - nvkm_falcon_load_dmem(hsf->falcon, &hsdesc, 0, sizeof(hsdesc), 0); + return nvkm_falcon_pio_wr(fw->falcon, (u8 *)&hsdesc, 0, 0, DMEM, 0, sizeof(hsdesc), 0, 0); } + static int -gm20b_acr_load_load(struct nvkm_acr *acr, struct nvkm_acr_hsfw *hsfw) +gm20b_acr_load_setup(struct nvkm_falcon_fw *fw) { - struct flcn_acr_desc *desc = (void *)&hsfw->image[hsfw->data_addr]; + struct flcn_acr_desc *desc = (void *)&fw->fw.img[fw->dmem_base_img]; + struct nvkm_acr *acr = fw->falcon->owner->device->acr; desc->ucode_blob_base = nvkm_memory_addr(acr->wpr); desc->ucode_blob_size = nvkm_memory_size(acr->wpr); flcn_acr_desc_dump(&acr->subdev, desc); - - return gm200_acr_hsfw_load(acr, hsfw, &acr->subdev.device->pmu->falcon); + return 0; } -const struct nvkm_acr_hsf_func +const struct nvkm_falcon_fw_func gm20b_acr_load_0 = { - .load = gm20b_acr_load_load, - .boot = gm200_acr_load_boot, - .bld = gm20b_acr_load_bld, + .signature = gm200_flcn_fw_signature, + .reset = gm200_flcn_fw_reset, + .setup = gm20b_acr_load_setup, + .load = gm200_flcn_fw_load, + .load_bld = gm20b_acr_hsfw_load_bld, + .boot = gm200_flcn_fw_boot, }; #if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC) @@ -91,7 +95,7 @@ MODULE_FIRMWARE("nvidia/gm20b/acr/ucode_load.bin"); static const struct nvkm_acr_hsf_fwif gm20b_acr_load_fwif[] = { - { 0, nvkm_acr_hsfw_load, &gm20b_acr_load_0 }, + { 0, gm200_acr_hsfw_ctor, &gm20b_acr_load_0, NVKM_ACR_HSF_PMU, 0, 0x10 }, {} }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gp102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gp102.c index fd97a935a380..084f28449e52 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gp102.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gp102.c @@ -29,7 +29,7 @@ #include <nvfw/acr.h> #include <nvfw/flcn.h> -void +int gp102_acr_wpr_patch(struct nvkm_acr *acr, s64 adjust) { struct wpr_header_v1 hdr; @@ -54,6 +54,8 @@ gp102_acr_wpr_patch(struct nvkm_acr *acr, s64 adjust) offset += sizeof(hdr); } while (hdr.falcon_id != WPR_HEADER_V1_FALCON_ID_INVALID); + + return 0; } int @@ -187,14 +189,15 @@ MODULE_FIRMWARE("nvidia/gp107/acr/ucode_unload.bin"); static const struct nvkm_acr_hsf_fwif gp102_acr_unload_fwif[] = { - { 0, nvkm_acr_hsfw_load, &gm200_acr_unload_0 }, + { 0, gm200_acr_hsfw_ctor, &gm200_acr_unload_0, NVKM_ACR_HSF_PMU, 0x1d, 0x00000010 }, {} }; int -gp102_acr_load_load(struct nvkm_acr *acr, struct nvkm_acr_hsfw *hsfw) +gp102_acr_load_setup(struct nvkm_falcon_fw *fw) { - struct flcn_acr_desc_v1 *desc = (void *)&hsfw->image[hsfw->data_addr]; + struct flcn_acr_desc_v1 *desc = (void *)&fw->fw.img[fw->dmem_base_img]; + struct nvkm_acr *acr = fw->falcon->owner->device->acr; desc->wpr_region_id = 1; desc->regions.no_regions = 2; @@ -204,19 +207,19 @@ gp102_acr_load_load(struct nvkm_acr *acr, struct nvkm_acr_hsfw *hsfw) desc->regions.region_props[0].read_mask = 0xf; desc->regions.region_props[0].write_mask = 0xc; desc->regions.region_props[0].client_mask = 0x2; - desc->regions.region_props[0].shadow_mem_start_addr = - acr->shadow_start >> 8; + desc->regions.region_props[0].shadow_mem_start_addr = acr->shadow_start >> 8; flcn_acr_desc_v1_dump(&acr->subdev, desc); - - return gm200_acr_hsfw_load(acr, hsfw, - &acr->subdev.device->sec2->falcon); + return 0; } -static const struct nvkm_acr_hsf_func +static const struct nvkm_falcon_fw_func gp102_acr_load_0 = { - .load = gp102_acr_load_load, - .boot = gm200_acr_load_boot, - .bld = gm200_acr_hsfw_bld, + .signature = gm200_flcn_fw_signature, + .reset = gm200_flcn_fw_reset, + .setup = gp102_acr_load_setup, + .load = gm200_flcn_fw_load, + .load_bld = gm200_acr_hsfw_load_bld, + .boot = gm200_flcn_fw_boot, }; MODULE_FIRMWARE("nvidia/gp102/acr/bl.bin"); @@ -233,7 +236,7 @@ MODULE_FIRMWARE("nvidia/gp107/acr/ucode_load.bin"); static const struct nvkm_acr_hsf_fwif gp102_acr_load_fwif[] = { - { 0, nvkm_acr_hsfw_load, &gp102_acr_load_0 }, + { 0, gm200_acr_hsfw_ctor, &gp102_acr_load_0, NVKM_ACR_HSF_SEC2, 0, 0x00000010 }, {} }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gp108.c b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gp108.c index 373d638a2177..6ab9d4959c17 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gp108.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gp108.c @@ -25,63 +25,62 @@ #include <nvfw/flcn.h> -void -gp108_acr_hsfw_bld(struct nvkm_acr *acr, struct nvkm_acr_hsf *hsf) +int +gp108_acr_hsfw_load_bld(struct nvkm_falcon_fw *fw) { struct flcn_bl_dmem_desc_v2 hsdesc = { .ctx_dma = FALCON_DMAIDX_VIRT, - .code_dma_base = hsf->vma->addr, - .non_sec_code_off = hsf->non_sec_addr, - .non_sec_code_size = hsf->non_sec_size, - .sec_code_off = hsf->sec_addr, - .sec_code_size = hsf->sec_size, + .code_dma_base = fw->vma->addr, + .non_sec_code_off = fw->nmem_base, + .non_sec_code_size = fw->nmem_size, + .sec_code_off = fw->imem_base, + .sec_code_size = fw->imem_size, .code_entry_point = 0, - .data_dma_base = hsf->vma->addr + hsf->data_addr, - .data_size = hsf->data_size, + .data_dma_base = fw->vma->addr + fw->dmem_base_img, + .data_size = fw->dmem_size, .argc = 0, .argv = 0, }; - flcn_bl_dmem_desc_v2_dump(&acr->subdev, &hsdesc); + flcn_bl_dmem_desc_v2_dump(fw->falcon->user, &hsdesc); - nvkm_falcon_load_dmem(hsf->falcon, &hsdesc, 0, sizeof(hsdesc), 0); + return nvkm_falcon_pio_wr(fw->falcon, (u8 *)&hsdesc, 0, 0, DMEM, 0, sizeof(hsdesc), 0, 0); } -const struct nvkm_acr_hsf_func -gp108_acr_unload_0 = { - .load = gm200_acr_unload_load, - .boot = gm200_acr_unload_boot, - .bld = gp108_acr_hsfw_bld, +const struct nvkm_falcon_fw_func +gp108_acr_hsfw_0 = { + .signature = gm200_flcn_fw_signature, + .reset = gm200_flcn_fw_reset, + .load = gm200_flcn_fw_load, + .load_bld = gp108_acr_hsfw_load_bld, + .boot = gm200_flcn_fw_boot, }; MODULE_FIRMWARE("nvidia/gp108/acr/unload_bl.bin"); MODULE_FIRMWARE("nvidia/gp108/acr/ucode_unload.bin"); -MODULE_FIRMWARE("nvidia/gv100/acr/unload_bl.bin"); -MODULE_FIRMWARE("nvidia/gv100/acr/ucode_unload.bin"); - static const struct nvkm_acr_hsf_fwif gp108_acr_unload_fwif[] = { - { 0, nvkm_acr_hsfw_load, &gp108_acr_unload_0 }, + { 0, gm200_acr_hsfw_ctor, &gp108_acr_hsfw_0, NVKM_ACR_HSF_PMU, 0x1d, 0x00000010 }, {} }; -static const struct nvkm_acr_hsf_func +const struct nvkm_falcon_fw_func gp108_acr_load_0 = { - .load = gp102_acr_load_load, - .boot = gm200_acr_load_boot, - .bld = gp108_acr_hsfw_bld, + .signature = gm200_flcn_fw_signature, + .reset = gm200_flcn_fw_reset, + .setup = gp102_acr_load_setup, + .load = gm200_flcn_fw_load, + .load_bld = gp108_acr_hsfw_load_bld, + .boot = gm200_flcn_fw_boot, }; MODULE_FIRMWARE("nvidia/gp108/acr/bl.bin"); MODULE_FIRMWARE("nvidia/gp108/acr/ucode_load.bin"); -MODULE_FIRMWARE("nvidia/gv100/acr/bl.bin"); -MODULE_FIRMWARE("nvidia/gv100/acr/ucode_load.bin"); - static const struct nvkm_acr_hsf_fwif gp108_acr_load_fwif[] = { - { 0, nvkm_acr_hsfw_load, &gp108_acr_load_0 }, + { 0, gm200_acr_hsfw_ctor, &gp108_acr_load_0, NVKM_ACR_HSF_SEC2, 0, 0x00000010 }, {} }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gp10b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gp10b.c index f03ba028867b..a3422ab6deab 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gp10b.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gp10b.c @@ -28,7 +28,7 @@ MODULE_FIRMWARE("nvidia/gp10b/acr/ucode_load.bin"); static const struct nvkm_acr_hsf_fwif gp10b_acr_load_fwif[] = { - { 0, nvkm_acr_hsfw_load, &gm20b_acr_load_0 }, + { 0, gm200_acr_hsfw_ctor, &gm20b_acr_load_0, NVKM_ACR_HSF_PMU, 0, 0x00000010 }, {} }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gv100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gv100.c new file mode 100644 index 000000000000..4c5ca6b40027 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gv100.c @@ -0,0 +1,67 @@ +/* + * Copyright 2022 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +#include "priv.h" + +MODULE_FIRMWARE("nvidia/gv100/acr/unload_bl.bin"); +MODULE_FIRMWARE("nvidia/gv100/acr/ucode_unload.bin"); + +static const struct nvkm_acr_hsf_fwif +gv100_acr_unload_fwif[] = { + { 0, gm200_acr_hsfw_ctor, &gp108_acr_hsfw_0, NVKM_ACR_HSF_PMU, 0, 0x00000000 }, + {} +}; + +MODULE_FIRMWARE("nvidia/gv100/acr/bl.bin"); +MODULE_FIRMWARE("nvidia/gv100/acr/ucode_load.bin"); + +static const struct nvkm_acr_hsf_fwif +gv100_acr_load_fwif[] = { + { 0, gm200_acr_hsfw_ctor, &gp108_acr_load_0, NVKM_ACR_HSF_SEC2, 0, 0x00000010 }, + {} +}; + +static const struct nvkm_acr_func +gv100_acr = { + .load = gv100_acr_load_fwif, + .unload = gv100_acr_unload_fwif, + .wpr_parse = gp102_acr_wpr_parse, + .wpr_layout = gp102_acr_wpr_layout, + .wpr_alloc = gp102_acr_wpr_alloc, + .wpr_build = gp102_acr_wpr_build, + .wpr_patch = gp102_acr_wpr_patch, + .wpr_check = gm200_acr_wpr_check, + .init = gm200_acr_init, +}; + +static const struct nvkm_acr_fwif +gv100_acr_fwif[] = { + { 0, gp102_acr_load, &gv100_acr }, + { -1, gm200_acr_nofw, &gm200_acr }, + {} +}; + +int +gv100_acr_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, + struct nvkm_acr **pacr) +{ + return nvkm_acr_new_(gv100_acr_fwif, device, type, inst, pacr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/hsfw.c b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/hsfw.c deleted file mode 100644 index a6ea89a5d51a..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/hsfw.c +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright 2019 Red Hat Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ -#include "priv.h" - -#include <core/firmware.h> - -#include <nvfw/fw.h> -#include <nvfw/hs.h> - -static void -nvkm_acr_hsfw_del(struct nvkm_acr_hsfw *hsfw) -{ - list_del(&hsfw->head); - kfree(hsfw->imem); - kfree(hsfw->image); - kfree(hsfw->sig.prod.data); - kfree(hsfw->sig.dbg.data); - kfree(hsfw); -} - -void -nvkm_acr_hsfw_del_all(struct nvkm_acr *acr) -{ - struct nvkm_acr_hsfw *hsfw, *hsft; - list_for_each_entry_safe(hsfw, hsft, &acr->hsfw, head) { - nvkm_acr_hsfw_del(hsfw); - } -} - -static int -nvkm_acr_hsfw_load_image(struct nvkm_acr *acr, const char *name, int ver, - struct nvkm_acr_hsfw *hsfw) -{ - struct nvkm_subdev *subdev = &acr->subdev; - const struct firmware *fw; - const struct nvfw_bin_hdr *hdr; - const struct nvfw_hs_header *fwhdr; - const struct nvfw_hs_load_header *lhdr; - u32 loc, sig; - int ret; - - ret = nvkm_firmware_get(subdev, name, ver, &fw); - if (ret < 0) - return ret; - - hdr = nvfw_bin_hdr(subdev, fw->data); - fwhdr = nvfw_hs_header(subdev, fw->data + hdr->header_offset); - - /* Earlier FW releases by NVIDIA for Nouveau's use aren't in NVIDIA's - * standard format, and don't have the indirection seen in the 0x10de - * case. - */ - switch (hdr->bin_magic) { - case 0x000010de: - loc = *(u32 *)(fw->data + fwhdr->patch_loc); - sig = *(u32 *)(fw->data + fwhdr->patch_sig); - break; - case 0x3b1d14f0: - loc = fwhdr->patch_loc; - sig = fwhdr->patch_sig; - break; - default: - ret = -EINVAL; - goto done; - } - - lhdr = nvfw_hs_load_header(subdev, fw->data + fwhdr->hdr_offset); - - if (!(hsfw->image = kmalloc(hdr->data_size, GFP_KERNEL))) { - ret = -ENOMEM; - goto done; - } - - memcpy(hsfw->image, fw->data + hdr->data_offset, hdr->data_size); - hsfw->image_size = hdr->data_size; - hsfw->non_sec_addr = lhdr->non_sec_code_off; - hsfw->non_sec_size = lhdr->non_sec_code_size; - hsfw->sec_addr = lhdr->apps[0]; - hsfw->sec_size = lhdr->apps[lhdr->num_apps]; - hsfw->data_addr = lhdr->data_dma_base; - hsfw->data_size = lhdr->data_size; - - hsfw->sig.prod.size = fwhdr->sig_prod_size; - hsfw->sig.prod.data = kmemdup(fw->data + fwhdr->sig_prod_offset + sig, - hsfw->sig.prod.size, GFP_KERNEL); - if (!hsfw->sig.prod.data) { - ret = -ENOMEM; - goto done; - } - - hsfw->sig.dbg.size = fwhdr->sig_dbg_size; - hsfw->sig.dbg.data = kmemdup(fw->data + fwhdr->sig_dbg_offset + sig, - hsfw->sig.dbg.size, GFP_KERNEL); - if (!hsfw->sig.dbg.data) { - ret = -ENOMEM; - goto done; - } - - hsfw->sig.patch_loc = loc; -done: - nvkm_firmware_put(fw); - return ret; -} - -static int -nvkm_acr_hsfw_load_bl(struct nvkm_acr *acr, const char *name, int ver, - struct nvkm_acr_hsfw *hsfw) -{ - struct nvkm_subdev *subdev = &acr->subdev; - const struct nvfw_bin_hdr *hdr; - const struct nvfw_bl_desc *desc; - const struct firmware *fw; - u8 *data; - int ret; - - ret = nvkm_firmware_get(subdev, name, ver, &fw); - if (ret) - return ret; - - hdr = nvfw_bin_hdr(subdev, fw->data); - desc = nvfw_bl_desc(subdev, fw->data + hdr->header_offset); - data = (void *)fw->data + hdr->data_offset; - - hsfw->imem_size = desc->code_size; - hsfw->imem_tag = desc->start_tag; - hsfw->imem = kmemdup(data + desc->code_off, desc->code_size, GFP_KERNEL); - nvkm_firmware_put(fw); - if (!hsfw->imem) - return -ENOMEM; - else - return 0; -} - -int -nvkm_acr_hsfw_load(struct nvkm_acr *acr, const char *bl, const char *fw, - const char *name, int version, - const struct nvkm_acr_hsf_fwif *fwif) -{ - struct nvkm_acr_hsfw *hsfw; - int ret; - - if (!(hsfw = kzalloc(sizeof(*hsfw), GFP_KERNEL))) - return -ENOMEM; - - hsfw->func = fwif->func; - hsfw->name = name; - list_add_tail(&hsfw->head, &acr->hsfw); - - ret = nvkm_acr_hsfw_load_bl(acr, bl, version, hsfw); - if (ret) - goto done; - - ret = nvkm_acr_hsfw_load_image(acr, fw, version, hsfw); -done: - if (ret) - nvkm_acr_hsfw_del(hsfw); - return ret; -} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/lsfw.c b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/lsfw.c index 9b1cf6711ae9..f36a359d4531 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/lsfw.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/lsfw.c @@ -29,6 +29,7 @@ void nvkm_acr_lsfw_del(struct nvkm_acr_lsfw *lsfw) { nvkm_blob_dtor(&lsfw->img); + kfree(lsfw->sigs); nvkm_firmware_put(lsfw->sig); list_del(&lsfw->head); kfree(lsfw); @@ -177,6 +178,75 @@ nvkm_acr_lsfw_load_sig_image_desc_v1(struct nvkm_subdev *subdev, } int +nvkm_acr_lsfw_load_sig_image_desc_v2(struct nvkm_subdev *subdev, + struct nvkm_falcon *falcon, + enum nvkm_acr_lsf_id id, + const char *path, int ver, + const struct nvkm_acr_lsf_func *func) +{ + const struct firmware *fw; + struct nvkm_acr_lsfw *lsfw; + const struct nvfw_ls_desc_v2 *desc; + int ret = 0; + + lsfw = nvkm_acr_lsfw_load_sig_image_desc_(subdev, falcon, id, path, ver, func, &fw); + if (IS_ERR(lsfw)) + return PTR_ERR(lsfw); + + desc = nvfw_ls_desc_v2(subdev, fw->data); + + lsfw->secure_bootloader = desc->secure_bootloader; + lsfw->bootloader_size = ALIGN(desc->bootloader_size, 256); + lsfw->bootloader_imem_offset = desc->bootloader_imem_offset; + + lsfw->app_size = ALIGN(desc->app_size, 256); + lsfw->app_start_offset = desc->app_start_offset; + lsfw->app_imem_entry = desc->app_imem_entry; + lsfw->app_resident_code_offset = desc->app_resident_code_offset; + lsfw->app_resident_code_size = desc->app_resident_code_size; + lsfw->app_resident_data_offset = desc->app_resident_data_offset; + lsfw->app_resident_data_size = desc->app_resident_data_size; + lsfw->app_imem_offset = desc->app_imem_offset; + lsfw->app_dmem_offset = desc->app_dmem_offset; + + lsfw->ucode_size = ALIGN(lsfw->app_resident_data_offset, 256) + lsfw->bootloader_size; + lsfw->data_size = lsfw->app_size + lsfw->bootloader_size - lsfw->ucode_size; + + nvkm_firmware_put(fw); + + if (lsfw->secure_bootloader) { + const struct firmware *hsbl; + const struct nvfw_ls_hsbl_bin_hdr *hdr; + const struct nvfw_ls_hsbl_hdr *hshdr; + u32 loc, sig, cnt, *meta; + + ret = nvkm_firmware_load_name(subdev, path, "hs_bl_sig", ver, &hsbl); + if (ret) + return ret; + + hdr = nvfw_ls_hsbl_bin_hdr(subdev, hsbl->data); + hshdr = nvfw_ls_hsbl_hdr(subdev, hsbl->data + hdr->header_offset); + meta = (u32 *)(hsbl->data + hshdr->meta_data_offset); + loc = *(u32 *)(hsbl->data + hshdr->patch_loc); + sig = *(u32 *)(hsbl->data + hshdr->patch_sig); + cnt = *(u32 *)(hsbl->data + hshdr->num_sig); + + lsfw->fuse_ver = meta[0]; + lsfw->engine_id = meta[1]; + lsfw->ucode_id = meta[2]; + lsfw->sig_size = hshdr->sig_prod_size / cnt; + lsfw->sig_nr = cnt; + lsfw->sigs = kmemdup(hsbl->data + hshdr->sig_prod_offset + sig, + lsfw->sig_nr * lsfw->sig_size, GFP_KERNEL); + nvkm_firmware_put(hsbl); + if (!lsfw->sigs) + ret = -ENOMEM; + } + + return ret; +} + +int nvkm_acr_lsfw_load_bl_inst_data_sig(struct nvkm_subdev *subdev, struct nvkm_falcon *falcon, enum nvkm_acr_lsf_id id, @@ -251,3 +321,78 @@ done: nvkm_firmware_put(bl); return ret; } + +int +nvkm_acr_lsfw_load_bl_sig_net(struct nvkm_subdev *subdev, + struct nvkm_falcon *falcon, + enum nvkm_acr_lsf_id id, + const char *path, int ver, + const struct nvkm_acr_lsf_func *func, + const void *inst_data, u32 inst_size, + const void *data_data, u32 data_size) +{ + struct nvkm_acr *acr = subdev->device->acr; + struct nvkm_acr_lsfw *lsfw; + const struct firmware _inst = { .data = inst_data, .size = inst_size }; + const struct firmware _data = { .data = data_data, .size = data_size }; + const struct firmware *bl = NULL, *inst = &_inst, *data = &_data; + const struct { + int bin_magic; + int bin_version; + int bin_size; + int header_offset; + int header_size; + } *hdr; + u32 *bldata; + int ret; + + if (IS_ERR((lsfw = nvkm_acr_lsfw_add(func, acr, falcon, id)))) + return PTR_ERR(lsfw); + + ret = nvkm_firmware_load_name(subdev, path, "bl", ver, &bl); + if (ret) + goto done; + + hdr = (const void *)bl->data; + bldata = (void *)(bl->data + hdr->header_offset); + + ret = nvkm_firmware_load_name(subdev, path, "sig", ver, &lsfw->sig); + if (ret) + goto done; + + lsfw->bootloader_size = ALIGN(hdr->header_size, 256); + lsfw->bootloader_imem_offset = func->bl_entry; + + lsfw->app_start_offset = lsfw->bootloader_size; + lsfw->app_imem_entry = 0; + lsfw->app_resident_code_offset = 0; + lsfw->app_resident_code_size = ALIGN(inst->size, 256); + lsfw->app_resident_data_offset = lsfw->app_resident_code_size; + lsfw->app_resident_data_size = ALIGN(data->size, 256); + lsfw->app_imem_offset = 0; + lsfw->app_dmem_offset = 0; + lsfw->app_size = lsfw->app_resident_code_size + lsfw->app_resident_data_size; + + lsfw->img.size = lsfw->bootloader_size + lsfw->app_size; + if (!(lsfw->img.data = kzalloc(lsfw->img.size, GFP_KERNEL))) { + ret = -ENOMEM; + goto done; + } + + memcpy(lsfw->img.data, bldata, lsfw->bootloader_size); + memcpy(lsfw->img.data + lsfw->app_start_offset + + lsfw->app_resident_code_offset, inst->data, inst->size); + memcpy(lsfw->img.data + lsfw->app_start_offset + + lsfw->app_resident_data_offset, data->data, data->size); + + lsfw->ucode_size = ALIGN(lsfw->app_resident_data_offset, 256) + + lsfw->bootloader_size; + lsfw->data_size = lsfw->app_size + lsfw->bootloader_size - + lsfw->ucode_size; + +done: + if (ret) + nvkm_acr_lsfw_del(lsfw); + nvkm_firmware_put(bl); + return ret; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/priv.h index c30b841c9d35..4881c8ba3880 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/priv.h @@ -24,7 +24,7 @@ struct nvkm_acr_func { u32 (*wpr_layout)(struct nvkm_acr *); int (*wpr_alloc)(struct nvkm_acr *, u32 wpr_size); int (*wpr_build)(struct nvkm_acr *, struct nvkm_acr_lsf *rtos); - void (*wpr_patch)(struct nvkm_acr *, s64 adjust); + int (*wpr_patch)(struct nvkm_acr *, s64 adjust); void (*wpr_check)(struct nvkm_acr *, u64 *start, u64 *limit); int (*init)(struct nvkm_acr *); void (*fini)(struct nvkm_acr *); @@ -35,7 +35,7 @@ extern const struct nvkm_acr_func gm200_acr; int gm200_acr_wpr_parse(struct nvkm_acr *); u32 gm200_acr_wpr_layout(struct nvkm_acr *); int gm200_acr_wpr_build(struct nvkm_acr *, struct nvkm_acr_lsf *); -void gm200_acr_wpr_patch(struct nvkm_acr *, s64); +int gm200_acr_wpr_patch(struct nvkm_acr *, s64); void gm200_acr_wpr_check(struct nvkm_acr *, u64 *, u64 *); void gm200_acr_wpr_build_lsb_tail(struct nvkm_acr_lsfw *, struct lsb_header_tail *); @@ -48,96 +48,60 @@ u32 gp102_acr_wpr_layout(struct nvkm_acr *); int gp102_acr_wpr_alloc(struct nvkm_acr *, u32 wpr_size); int gp102_acr_wpr_build(struct nvkm_acr *, struct nvkm_acr_lsf *); int gp102_acr_wpr_build_lsb(struct nvkm_acr *, struct nvkm_acr_lsfw *); -void gp102_acr_wpr_patch(struct nvkm_acr *, s64); +int gp102_acr_wpr_patch(struct nvkm_acr *, s64); + +int tu102_acr_init(struct nvkm_acr *); + +void ga100_acr_wpr_check(struct nvkm_acr *, u64 *, u64 *); struct nvkm_acr_hsfw { - const struct nvkm_acr_hsf_func *func; - const char *name; - struct list_head head; + struct nvkm_falcon_fw fw; + + enum nvkm_acr_hsf_id { + NVKM_ACR_HSF_PMU, + NVKM_ACR_HSF_SEC2, + NVKM_ACR_HSF_GSP, + } falcon_id; + u32 boot_mbox0; + u32 intr_clear; - u32 imem_size; - u32 imem_tag; - u32 *imem; - - u8 *image; - u32 image_size; - u32 non_sec_addr; - u32 non_sec_size; - u32 sec_addr; - u32 sec_size; - u32 data_addr; - u32 data_size; - - struct { - struct { - void *data; - u32 size; - } prod, dbg; - u32 patch_loc; - } sig; + struct list_head head; }; +int nvkm_acr_hsfw_boot(struct nvkm_acr *, const char *name); + struct nvkm_acr_hsf_fwif { int version; int (*load)(struct nvkm_acr *, const char *bl, const char *fw, const char *name, int version, const struct nvkm_acr_hsf_fwif *); - const struct nvkm_acr_hsf_func *func; -}; + const struct nvkm_falcon_fw_func *func; -int nvkm_acr_hsfw_load(struct nvkm_acr *, const char *, const char *, - const char *, int, const struct nvkm_acr_hsf_fwif *); -void nvkm_acr_hsfw_del_all(struct nvkm_acr *); - -struct nvkm_acr_hsf { - const struct nvkm_acr_hsf_func *func; - const char *name; - struct list_head head; - - u32 imem_size; - u32 imem_tag; - u32 *imem; - - u32 non_sec_addr; - u32 non_sec_size; - u32 sec_addr; - u32 sec_size; - u32 data_addr; - u32 data_size; - - struct nvkm_memory *ucode; - struct nvkm_vma *vma; - struct nvkm_falcon *falcon; + enum nvkm_acr_hsf_id falcon_id; + u32 boot_mbox0; + u32 intr_clear; }; -struct nvkm_acr_hsf_func { - int (*load)(struct nvkm_acr *, struct nvkm_acr_hsfw *); - int (*boot)(struct nvkm_acr *, struct nvkm_acr_hsf *); - void (*bld)(struct nvkm_acr *, struct nvkm_acr_hsf *); -}; -int gm200_acr_hsfw_load(struct nvkm_acr *, struct nvkm_acr_hsfw *, - struct nvkm_falcon *); -int gm200_acr_hsfw_boot(struct nvkm_acr *, struct nvkm_acr_hsf *, - u32 clear_intr, u32 mbox0_ok); +int gm200_acr_hsfw_ctor(struct nvkm_acr *, const char *, const char *, const char *, int, + const struct nvkm_acr_hsf_fwif *); +int gm200_acr_hsfw_load_bld(struct nvkm_falcon_fw *); +extern const struct nvkm_falcon_fw_func gm200_acr_unload_0; -int gm200_acr_load_boot(struct nvkm_acr *, struct nvkm_acr_hsf *); +extern const struct nvkm_falcon_fw_func gm20b_acr_load_0; -extern const struct nvkm_acr_hsf_func gm200_acr_unload_0; -int gm200_acr_unload_load(struct nvkm_acr *, struct nvkm_acr_hsfw *); -int gm200_acr_unload_boot(struct nvkm_acr *, struct nvkm_acr_hsf *); -void gm200_acr_hsfw_bld(struct nvkm_acr *, struct nvkm_acr_hsf *); +int gp102_acr_load_setup(struct nvkm_falcon_fw *); -extern const struct nvkm_acr_hsf_func gm20b_acr_load_0; +extern const struct nvkm_falcon_fw_func gp108_acr_load_0; -int gp102_acr_load_load(struct nvkm_acr *, struct nvkm_acr_hsfw *); +extern const struct nvkm_falcon_fw_func gp108_acr_hsfw_0; +int gp108_acr_hsfw_load_bld(struct nvkm_falcon_fw *); -extern const struct nvkm_acr_hsf_func gp108_acr_unload_0; -void gp108_acr_hsfw_bld(struct nvkm_acr *, struct nvkm_acr_hsf *); +int ga100_acr_hsfw_ctor(struct nvkm_acr *, const char *, const char *, const char *, int, + const struct nvkm_acr_hsf_fwif *); int nvkm_acr_new_(const struct nvkm_acr_fwif *, struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_acr **); -int nvkm_acr_hsf_boot(struct nvkm_acr *, const char *name); struct nvkm_acr_lsf { const struct nvkm_acr_lsf_func *func; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/tu102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/tu102.c index 05a87e77525f..c22d551c0078 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/tu102.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/tu102.c @@ -29,14 +29,14 @@ #include <nvfw/acr.h> -static int +int tu102_acr_init(struct nvkm_acr *acr) { - int ret = nvkm_acr_hsf_boot(acr, "AHESASC"); + int ret = nvkm_acr_hsfw_boot(acr, "AHESASC"); if (ret) return ret; - return nvkm_acr_hsf_boot(acr, "ASB"); + return nvkm_acr_hsfw_boot(acr, "ASB"); } static int @@ -85,12 +85,6 @@ tu102_acr_wpr_build(struct nvkm_acr *acr, struct nvkm_acr_lsf *rtos) } static int -tu102_acr_hsfw_boot(struct nvkm_acr *acr, struct nvkm_acr_hsf *hsf) -{ - return gm200_acr_hsfw_boot(acr, hsf, 0, 0); -} - -static int tu102_acr_hsfw_nofw(struct nvkm_acr *acr, const char *bl, const char *fw, const char *name, int version, const struct nvkm_acr_hsf_fwif *fwif) @@ -115,24 +109,11 @@ MODULE_FIRMWARE("nvidia/tu117/acr/ucode_unload.bin"); static const struct nvkm_acr_hsf_fwif tu102_acr_unload_fwif[] = { - { 0, nvkm_acr_hsfw_load, &gp108_acr_unload_0 }, + { 0, gm200_acr_hsfw_ctor, &gp108_acr_hsfw_0, NVKM_ACR_HSF_PMU, 0, 0x00000000 }, { -1, tu102_acr_hsfw_nofw }, {} }; -static int -tu102_acr_asb_load(struct nvkm_acr *acr, struct nvkm_acr_hsfw *hsfw) -{ - return gm200_acr_hsfw_load(acr, hsfw, &acr->subdev.device->gsp->falcon); -} - -static const struct nvkm_acr_hsf_func -tu102_acr_asb_0 = { - .load = tu102_acr_asb_load, - .boot = tu102_acr_hsfw_boot, - .bld = gp108_acr_hsfw_bld, -}; - MODULE_FIRMWARE("nvidia/tu102/acr/ucode_asb.bin"); MODULE_FIRMWARE("nvidia/tu104/acr/ucode_asb.bin"); MODULE_FIRMWARE("nvidia/tu106/acr/ucode_asb.bin"); @@ -141,18 +122,11 @@ MODULE_FIRMWARE("nvidia/tu117/acr/ucode_asb.bin"); static const struct nvkm_acr_hsf_fwif tu102_acr_asb_fwif[] = { - { 0, nvkm_acr_hsfw_load, &tu102_acr_asb_0 }, + { 0, gm200_acr_hsfw_ctor, &gp108_acr_hsfw_0, NVKM_ACR_HSF_GSP, 0, 0x00000000 }, { -1, tu102_acr_hsfw_nofw }, {} }; -static const struct nvkm_acr_hsf_func -tu102_acr_ahesasc_0 = { - .load = gp102_acr_load_load, - .boot = tu102_acr_hsfw_boot, - .bld = gp108_acr_hsfw_bld, -}; - MODULE_FIRMWARE("nvidia/tu102/acr/bl.bin"); MODULE_FIRMWARE("nvidia/tu102/acr/ucode_ahesasc.bin"); @@ -170,7 +144,7 @@ MODULE_FIRMWARE("nvidia/tu117/acr/ucode_ahesasc.bin"); static const struct nvkm_acr_hsf_fwif tu102_acr_ahesasc_fwif[] = { - { 0, nvkm_acr_hsfw_load, &tu102_acr_ahesasc_0 }, + { 0, gm200_acr_hsfw_ctor, &gp108_acr_load_0, NVKM_ACR_HSF_SEC2, 0, 0x00000000 }, { -1, tu102_acr_hsfw_nofw }, {} }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm200.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm200.c index a308b9bde449..f30718d7e61a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm200.c @@ -26,6 +26,7 @@ #include <subdev/bios.h> #include <subdev/bios/bit.h> #include <subdev/bios/pmu.h> +#include <subdev/pmu.h> #include <subdev/timer.h> static void @@ -85,13 +86,18 @@ pmu_load(struct nv50_devinit *init, u8 type, bool post, struct nvkm_subdev *subdev = &init->base.subdev; struct nvkm_bios *bios = subdev->device->bios; struct nvbios_pmuR pmu; + int ret; if (!nvbios_pmuRm(bios, type, &pmu)) return -EINVAL; - if (!post) + if (!post || !subdev->device->pmu) return 0; + ret = nvkm_falcon_reset(&subdev->device->pmu->falcon); + if (ret) + return ret; + pmu_code(init, pmu.boot_addr_pmu, pmu.boot_addr, pmu.boot_size, false); pmu_code(init, pmu.code_addr_pmu, pmu.code_addr, pmu.code_size, true); pmu_data(init, pmu.data_addr_pmu, pmu.data_addr, pmu.data_size); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/base.c index fd54fa504efa..b53ac9a2552f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/base.c @@ -22,7 +22,6 @@ #include "priv.h" #include <core/memory.h> -#include <core/notify.h> static void nvkm_fault_ntfy_fini(struct nvkm_event *event, int type, int index) @@ -38,23 +37,8 @@ nvkm_fault_ntfy_init(struct nvkm_event *event, int type, int index) fault->func->buffer.intr(fault->buffer[index], true); } -static int -nvkm_fault_ntfy_ctor(struct nvkm_object *object, void *argv, u32 argc, - struct nvkm_notify *notify) -{ - struct nvkm_fault_buffer *buffer = nvkm_fault_buffer(object); - if (argc == 0) { - notify->size = 0; - notify->types = 1; - notify->index = buffer->id; - return 0; - } - return -ENOSYS; -} - static const struct nvkm_event_func nvkm_fault_ntfy = { - .ctor = nvkm_fault_ntfy_ctor, .init = nvkm_fault_ntfy_init, .fini = nvkm_fault_ntfy_fini, }; @@ -130,8 +114,7 @@ nvkm_fault_oneinit(struct nvkm_subdev *subdev) } } - ret = nvkm_event_init(&nvkm_fault_ntfy, 1, fault->buffer_nr, - &fault->event); + ret = nvkm_event_init(&nvkm_fault_ntfy, subdev, 1, fault->buffer_nr, &fault->event); if (ret) return ret; @@ -146,7 +129,7 @@ nvkm_fault_dtor(struct nvkm_subdev *subdev) struct nvkm_fault *fault = nvkm_fault(subdev); int i; - nvkm_notify_fini(&fault->nrpfb); + nvkm_event_ntfy_del(&fault->nrpfb); nvkm_event_fini(&fault->event); for (i = 0; i < fault->buffer_nr; i++) { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/gp100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/gp100.c index 6af7959e02ea..04c7526888bc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/gp100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/gp100.c @@ -65,7 +65,7 @@ gp100_fault_buffer_info(struct nvkm_fault_buffer *buffer) void gp100_fault_intr(struct nvkm_fault *fault) { - nvkm_event_send(&fault->event, 1, 0, NULL, 0); + nvkm_event_ntfy(&fault->event, 0, NVKM_FAULT_BUFFER_EVENT_PENDING); } static const struct nvkm_fault_func diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/gv100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/gv100.c index cd9d2ade5ac7..8e34d40e7649 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/gv100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/gv100.c @@ -27,10 +27,12 @@ #include <nvif/class.h> -static void -gv100_fault_buffer_process(struct nvkm_fault_buffer *buffer) +void +gv100_fault_buffer_process(struct work_struct *work) { - struct nvkm_device *device = buffer->fault->subdev.device; + struct nvkm_fault *fault = container_of(work, typeof(*fault), nrpfb_work); + struct nvkm_fault_buffer *buffer = fault->buffer[0]; + struct nvkm_device *device = fault->subdev.device; struct nvkm_memory *mem = buffer->mem; u32 get = nvkm_rd32(device, buffer->get); u32 put = nvkm_rd32(device, buffer->put); @@ -115,11 +117,12 @@ gv100_fault_buffer_info(struct nvkm_fault_buffer *buffer) } static int -gv100_fault_ntfy_nrpfb(struct nvkm_notify *notify) +gv100_fault_ntfy_nrpfb(struct nvkm_event_ntfy *ntfy, u32 bits) { - struct nvkm_fault *fault = container_of(notify, typeof(*fault), nrpfb); - gv100_fault_buffer_process(fault->buffer[0]); - return NVKM_NOTIFY_KEEP; + struct nvkm_fault *fault = container_of(ntfy, typeof(*fault), nrpfb); + + schedule_work(&fault->nrpfb_work); + return NVKM_EVENT_KEEP; } static void @@ -163,14 +166,14 @@ gv100_fault_intr(struct nvkm_fault *fault) if (stat & 0x20000000) { if (fault->buffer[0]) { - nvkm_event_send(&fault->event, 1, 0, NULL, 0); + nvkm_event_ntfy(&fault->event, 0, NVKM_FAULT_BUFFER_EVENT_PENDING); stat &= ~0x20000000; } } if (stat & 0x08000000) { if (fault->buffer[1]) { - nvkm_event_send(&fault->event, 1, 1, NULL, 0); + nvkm_event_ntfy(&fault->event, 1, NVKM_FAULT_BUFFER_EVENT_PENDING); stat &= ~0x08000000; } } @@ -183,9 +186,12 @@ gv100_fault_intr(struct nvkm_fault *fault) static void gv100_fault_fini(struct nvkm_fault *fault) { - nvkm_notify_put(&fault->nrpfb); + nvkm_event_ntfy_block(&fault->nrpfb); + flush_work(&fault->nrpfb_work); + if (fault->buffer[0]) fault->func->buffer.fini(fault->buffer[0]); + nvkm_mask(fault->subdev.device, 0x100a34, 0x80000000, 0x80000000); } @@ -194,15 +200,15 @@ gv100_fault_init(struct nvkm_fault *fault) { nvkm_mask(fault->subdev.device, 0x100a2c, 0x80000000, 0x80000000); fault->func->buffer.init(fault->buffer[0]); - nvkm_notify_get(&fault->nrpfb); + nvkm_event_ntfy_allow(&fault->nrpfb); } int gv100_fault_oneinit(struct nvkm_fault *fault) { - return nvkm_notify_init(&fault->buffer[0]->object, &fault->event, - gv100_fault_ntfy_nrpfb, true, NULL, 0, 0, - &fault->nrpfb); + nvkm_event_ntfy_add(&fault->event, 0, NVKM_FAULT_BUFFER_EVENT_PENDING, true, + gv100_fault_ntfy_nrpfb, &fault->nrpfb); + return 0; } static const struct nvkm_fault_func @@ -231,5 +237,10 @@ int gv100_fault_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fault **pfault) { - return nvkm_fault_new_(&gv100_fault, device, type, inst, pfault); + int ret = nvkm_fault_new_(&gv100_fault, device, type, inst, pfault); + if (ret) + return ret; + + INIT_WORK(&(*pfault)->nrpfb_work, gv100_fault_buffer_process); + return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/priv.h index 36681c347fb5..a5510332c402 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/priv.h @@ -16,6 +16,8 @@ struct nvkm_fault_buffer { u32 put; struct nvkm_memory *mem; u64 addr; + + struct nvkm_inth inth; }; int nvkm_fault_new_(const struct nvkm_fault_func *, struct nvkm_device *, enum nvkm_subdev_type, @@ -46,6 +48,7 @@ void gp100_fault_buffer_fini(struct nvkm_fault_buffer *); void gp100_fault_buffer_init(struct nvkm_fault_buffer *); u64 gp100_fault_buffer_pin(struct nvkm_fault_buffer *); void gp100_fault_buffer_info(struct nvkm_fault_buffer *); +void gv100_fault_buffer_process(struct work_struct *); void gp100_fault_intr(struct nvkm_fault *); u64 gp10b_fault_buffer_pin(struct nvkm_fault_buffer *); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/tu102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/tu102.c index 91eb6729c84d..967efaddae28 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/tu102.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/tu102.c @@ -24,20 +24,27 @@ #include <core/memory.h> #include <subdev/mc.h> #include <subdev/mmu.h> +#include <subdev/vfn.h> #include <engine/fifo.h> #include <nvif/class.h> +static irqreturn_t +tu102_fault_buffer_notify(struct nvkm_inth *inth) +{ + struct nvkm_fault_buffer *buffer = container_of(inth, typeof(*buffer), inth); + + nvkm_event_ntfy(&buffer->fault->event, buffer->id, NVKM_FAULT_BUFFER_EVENT_PENDING); + return IRQ_HANDLED; +} + static void tu102_fault_buffer_intr(struct nvkm_fault_buffer *buffer, bool enable) { - /*XXX: Earlier versions of RM touched the old regs on Turing, - * which don't appear to actually work anymore, but newer - * versions of RM don't appear to touch anything at all.. - */ - struct nvkm_device *device = buffer->fault->subdev.device; - - nvkm_mc_intr_mask(device, NVKM_SUBDEV_FAULT, 0, enable); + if (enable) + nvkm_inth_allow(&buffer->inth); + else + nvkm_inth_block(&buffer->inth); } static void @@ -46,10 +53,6 @@ tu102_fault_buffer_fini(struct nvkm_fault_buffer *buffer) struct nvkm_device *device = buffer->fault->subdev.device; const u32 foff = buffer->id * 0x20; - /* Disable the fault interrupts */ - nvkm_wr32(device, 0xb81408, 0x1); - nvkm_wr32(device, 0xb81410, 0x10); - nvkm_mask(device, 0xb83010 + foff, 0x80000000, 0x00000000); } @@ -59,10 +62,6 @@ tu102_fault_buffer_init(struct nvkm_fault_buffer *buffer) struct nvkm_device *device = buffer->fault->subdev.device; const u32 foff = buffer->id * 0x20; - /* Enable the fault interrupts */ - nvkm_wr32(device, 0xb81208, 0x1); - nvkm_wr32(device, 0xb81210, 0x10); - nvkm_mask(device, 0xb83010 + foff, 0xc0000000, 0x40000000); nvkm_wr32(device, 0xb83004 + foff, upper_32_bits(buffer->addr)); nvkm_wr32(device, 0xb83000 + foff, lower_32_bits(buffer->addr)); @@ -82,9 +81,10 @@ tu102_fault_buffer_info(struct nvkm_fault_buffer *buffer) buffer->put = 0xb8300c + foff; } -static void -tu102_fault_intr_fault(struct nvkm_fault *fault) +static irqreturn_t +tu102_fault_info_fault(struct nvkm_inth *inth) { + struct nvkm_fault *fault = container_of(inth, typeof(*fault), info_fault); struct nvkm_subdev *subdev = &fault->subdev; struct nvkm_device *device = subdev->device; struct nvkm_fault_data info; @@ -106,70 +106,61 @@ tu102_fault_intr_fault(struct nvkm_fault *fault) info.reason = (info1 & 0x0000001f); nvkm_fifo_fault(device->fifo, &info); -} - -static void -tu102_fault_intr(struct nvkm_fault *fault) -{ - struct nvkm_subdev *subdev = &fault->subdev; - struct nvkm_device *device = subdev->device; - u32 stat = nvkm_rd32(device, 0xb83094); - - if (stat & 0x80000000) { - tu102_fault_intr_fault(fault); - nvkm_wr32(device, 0xb83094, 0x80000000); - stat &= ~0x80000000; - } - if (stat & 0x00000200) { - /* Clear the associated interrupt flag */ - nvkm_wr32(device, 0xb81010, 0x10); - - if (fault->buffer[0]) { - nvkm_event_send(&fault->event, 1, 0, NULL, 0); - stat &= ~0x00000200; - } - } - - /* Replayable MMU fault */ - if (stat & 0x00000100) { - /* Clear the associated interrupt flag */ - nvkm_wr32(device, 0xb81008, 0x1); - - if (fault->buffer[1]) { - nvkm_event_send(&fault->event, 1, 1, NULL, 0); - stat &= ~0x00000100; - } - } - - if (stat) { - nvkm_debug(subdev, "intr %08x\n", stat); - } + nvkm_wr32(device, 0xb83094, 0x80000000); + return IRQ_HANDLED; } static void tu102_fault_fini(struct nvkm_fault *fault) { - nvkm_notify_put(&fault->nrpfb); + nvkm_event_ntfy_block(&fault->nrpfb); + flush_work(&fault->nrpfb_work); + if (fault->buffer[0]) fault->func->buffer.fini(fault->buffer[0]); - /*XXX: disable priv faults */ + + nvkm_inth_block(&fault->info_fault); } static void tu102_fault_init(struct nvkm_fault *fault) { - /*XXX: enable priv faults */ + nvkm_inth_allow(&fault->info_fault); + fault->func->buffer.init(fault->buffer[0]); - nvkm_notify_get(&fault->nrpfb); + nvkm_event_ntfy_allow(&fault->nrpfb); +} + +static int +tu102_fault_oneinit(struct nvkm_fault *fault) +{ + struct nvkm_device *device = fault->subdev.device; + struct nvkm_intr *intr = &device->vfn->intr; + int ret, i; + + ret = nvkm_inth_add(intr, nvkm_rd32(device, 0x100ee0) & 0x0000ffff, + NVKM_INTR_PRIO_NORMAL, &fault->subdev, tu102_fault_info_fault, + &fault->info_fault); + if (ret) + return ret; + + for (i = 0; i < fault->buffer_nr; i++) { + ret = nvkm_inth_add(intr, nvkm_rd32(device, 0x100ee4 + (i * 4)) >> 16, + NVKM_INTR_PRIO_NORMAL, &fault->subdev, + tu102_fault_buffer_notify, &fault->buffer[i]->inth); + if (ret) + return ret; + } + + return gv100_fault_oneinit(fault); } static const struct nvkm_fault_func tu102_fault = { - .oneinit = gv100_fault_oneinit, + .oneinit = tu102_fault_oneinit, .init = tu102_fault_init, .fini = tu102_fault_fini, - .intr = tu102_fault_intr, .buffer.nr = 2, .buffer.entry_size = 32, .buffer.info = tu102_fault_buffer_info, @@ -184,5 +175,10 @@ int tu102_fault_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fault **pfault) { - return nvkm_fault_new_(&tu102_fault, device, type, inst, pfault); + int ret = nvkm_fault_new_(&tu102_fault, device, type, inst, pfault); + if (ret) + return ret; + + INIT_WORK(&(*pfault)->nrpfb_work, gv100_fault_buffer_process); + return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/user.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/user.c index ac835c9582fd..c123e5893d76 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/user.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/user.c @@ -22,12 +22,28 @@ #include "priv.h" #include <core/memory.h> +#include <core/event.h> #include <subdev/mmu.h> #include <nvif/clb069.h> #include <nvif/unpack.h> static int +nvkm_ufault_uevent(struct nvkm_object *object, void *argv, u32 argc, struct nvkm_uevent *uevent) +{ + struct nvkm_fault_buffer *buffer = nvkm_fault_buffer(object); + union nvif_clb069_event_args *args = argv; + + if (!uevent) + return 0; + if (argc != sizeof(args->vn)) + return -ENOSYS; + + return nvkm_uevent_add(uevent, &buffer->fault->event, buffer->id, + NVKM_FAULT_BUFFER_EVENT_PENDING, NULL); +} + +static int nvkm_ufault_map(struct nvkm_object *object, void *argv, u32 argc, enum nvkm_object_map *type, u64 *addr, u64 *size) { @@ -40,18 +56,6 @@ nvkm_ufault_map(struct nvkm_object *object, void *argv, u32 argc, } static int -nvkm_ufault_ntfy(struct nvkm_object *object, u32 type, - struct nvkm_event **pevent) -{ - struct nvkm_fault_buffer *buffer = nvkm_fault_buffer(object); - if (type == NVB069_V0_NTFY_FAULT) { - *pevent = &buffer->fault->event; - return 0; - } - return -EINVAL; -} - -static int nvkm_ufault_fini(struct nvkm_object *object, bool suspend) { struct nvkm_fault_buffer *buffer = nvkm_fault_buffer(object); @@ -78,8 +82,8 @@ nvkm_ufault = { .dtor = nvkm_ufault_dtor, .init = nvkm_ufault_init, .fini = nvkm_ufault_fini, - .ntfy = nvkm_ufault_ntfy, .map = nvkm_ufault_map, + .uevent = nvkm_ufault_uevent, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c index 6faaea948fc4..bac7dcc4c2c1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c @@ -57,6 +57,15 @@ nvkm_fb_tile_prog(struct nvkm_fb *fb, int region, struct nvkm_fb_tile *tile) } } +static void +nvkm_fb_sysmem_flush_page_init(struct nvkm_device *device) +{ + struct nvkm_fb *fb = device->fb; + + if (fb->func->sysmem.flush_page_init) + fb->func->sysmem.flush_page_init(fb); +} + int nvkm_fb_bios_memtype(struct nvkm_bios *bios) { @@ -125,12 +134,20 @@ nvkm_fb_oneinit(struct nvkm_subdev *subdev) return nvkm_mm_init(&fb->tags.mm, 0, 0, tags, 1); } -static int -nvkm_fb_init_scrub_vpr(struct nvkm_fb *fb) +int +nvkm_fb_mem_unlock(struct nvkm_fb *fb) { struct nvkm_subdev *subdev = &fb->subdev; int ret; + if (!fb->func->vpr.scrub_required) + return 0; + + if (!fb->func->vpr.scrub_required(fb)) { + nvkm_debug(subdev, "VPR not locked\n"); + return 0; + } + nvkm_debug(subdev, "VPR locked, running scrubber binary\n"); if (!fb->vpr_scrubber.size) { @@ -168,6 +185,8 @@ nvkm_fb_init(struct nvkm_subdev *subdev) for (i = 0; i < fb->tile.regions; i++) fb->func->tile.prog(fb, i, &fb->tile.region[i]); + nvkm_fb_sysmem_flush_page_init(subdev->device); + if (fb->func->init) fb->func->init(fb); @@ -183,13 +202,13 @@ nvkm_fb_init(struct nvkm_subdev *subdev) if (fb->func->init_unkn) fb->func->init_unkn(fb); - if (fb->func->vpr.scrub_required && - fb->func->vpr.scrub_required(fb)) { - ret = nvkm_fb_init_scrub_vpr(fb); - if (ret) - return ret; - } + return 0; +} +static int +nvkm_fb_preinit(struct nvkm_subdev *subdev) +{ + nvkm_fb_sysmem_flush_page_init(subdev->device); return 0; } @@ -212,20 +231,28 @@ nvkm_fb_dtor(struct nvkm_subdev *subdev) nvkm_blob_dtor(&fb->vpr_scrubber); + if (fb->sysmem.flush_page) { + dma_unmap_page(subdev->device->dev, fb->sysmem.flush_page_addr, + PAGE_SIZE, DMA_BIDIRECTIONAL); + __free_page(fb->sysmem.flush_page); + } + if (fb->func->dtor) return fb->func->dtor(fb); + return fb; } static const struct nvkm_subdev_func nvkm_fb = { .dtor = nvkm_fb_dtor, + .preinit = nvkm_fb_preinit, .oneinit = nvkm_fb_oneinit, .init = nvkm_fb_init, .intr = nvkm_fb_intr, }; -void +int nvkm_fb_ctor(const struct nvkm_fb_func *func, struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb *fb) { @@ -234,6 +261,19 @@ nvkm_fb_ctor(const struct nvkm_fb_func *func, struct nvkm_device *device, fb->tile.regions = fb->func->tile.regions; fb->page = nvkm_longopt(device->cfgopt, "NvFbBigPage", fb->func->default_bigpage); mutex_init(&fb->tags.mutex); + + if (func->sysmem.flush_page_init) { + fb->sysmem.flush_page = alloc_page(GFP_KERNEL | __GFP_ZERO); + if (!fb->sysmem.flush_page) + return -ENOMEM; + + fb->sysmem.flush_page_addr = dma_map_page(device->dev, fb->sysmem.flush_page, + 0, PAGE_SIZE, DMA_BIDIRECTIONAL); + if (dma_mapping_error(device->dev, fb->sysmem.flush_page_addr)) + return -EFAULT; + } + + return 0; } int @@ -242,6 +282,5 @@ nvkm_fb_new_(const struct nvkm_fb_func *func, struct nvkm_device *device, { if (!(*pfb = kzalloc(sizeof(**pfb), GFP_KERNEL))) return -ENOMEM; - nvkm_fb_ctor(func, device, type, inst, *pfb); - return 0; + return nvkm_fb_ctor(func, device, type, inst, *pfb); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ga100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ga100.c index b47bebfbc26f..5098f219e3e6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ga100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ga100.c @@ -26,9 +26,10 @@ static const struct nvkm_fb_func ga100_fb = { .dtor = gf100_fb_dtor, .oneinit = gf100_fb_oneinit, - .init = gp100_fb_init, + .init = gm200_fb_init, .init_page = gv100_fb_init_page, .init_unkn = gp100_fb_init_unkn, + .sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init, .ram_new = gp100_ram_new, .default_bigpage = 16, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ga102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ga102.c index 6ea7908f0563..8b7c8ea5e8a5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ga102.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ga102.c @@ -22,15 +22,42 @@ #include "gf100.h" #include "ram.h" +#include <engine/nvdec.h> + +static int +ga102_fb_vpr_scrub(struct nvkm_fb *fb) +{ + struct nvkm_falcon_fw fw = {}; + int ret; + + ret = nvkm_falcon_fw_ctor_hs_v2(&ga102_flcn_fw, "mem-unlock", &fb->subdev, "nvdec/scrubber", + 0, &fb->subdev.device->nvdec[0]->falcon, &fw); + if (ret) + return ret; + + ret = nvkm_falcon_fw_boot(&fw, &fb->subdev, true, NULL, NULL, 0, 0); + nvkm_falcon_fw_dtor(&fw); + return ret; +} + +static bool +ga102_fb_vpr_scrub_required(struct nvkm_fb *fb) +{ + return (nvkm_rd32(fb->subdev.device, 0x1fa80c) & 0x00000010) != 0; +} + static const struct nvkm_fb_func ga102_fb = { .dtor = gf100_fb_dtor, .oneinit = gf100_fb_oneinit, - .init = gp100_fb_init, + .init = gm200_fb_init, .init_page = gv100_fb_init_page, .init_unkn = gp100_fb_init_unkn, + .sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init, .ram_new = ga102_ram_new, .default_bigpage = 16, + .vpr.scrub_required = ga102_fb_vpr_scrub_required, + .vpr.scrub = ga102_fb_vpr_scrub, }; int @@ -38,3 +65,9 @@ ga102_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, s { return gp102_fb_new_(&ga102_fb, device, type, inst, pfb); } + +MODULE_FIRMWARE("nvidia/ga102/nvdec/scrubber.bin"); +MODULE_FIRMWARE("nvidia/ga103/nvdec/scrubber.bin"); +MODULE_FIRMWARE("nvidia/ga104/nvdec/scrubber.bin"); +MODULE_FIRMWARE("nvidia/ga106/nvdec/scrubber.bin"); +MODULE_FIRMWARE("nvidia/ga107/nvdec/scrubber.bin"); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c index 9dcc40f9ef79..07db9b397ac1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c @@ -61,14 +61,6 @@ gf100_fb_oneinit(struct nvkm_fb *base) if (ret) return ret; - fb->r100c10_page = alloc_page(GFP_KERNEL | __GFP_ZERO); - if (fb->r100c10_page) { - fb->r100c10 = dma_map_page(device->dev, fb->r100c10_page, 0, - PAGE_SIZE, DMA_BIDIRECTIONAL); - if (dma_mapping_error(device->dev, fb->r100c10)) - return -EFAULT; - } - return 0; } @@ -86,14 +78,17 @@ gf100_fb_init_page(struct nvkm_fb *fb) } void +gf100_fb_sysmem_flush_page_init(struct nvkm_fb *fb) +{ + nvkm_wr32(fb->subdev.device, 0x100c10, fb->sysmem.flush_page_addr >> 8); +} + +void gf100_fb_init(struct nvkm_fb *base) { struct gf100_fb *fb = gf100_fb(base); struct nvkm_device *device = fb->base.subdev.device; - if (fb->r100c10_page) - nvkm_wr32(device, 0x100c10, fb->r100c10 >> 8); - if (base->func->clkgate_pack) { nvkm_therm_clkgate_init(device->therm, base->func->clkgate_pack); @@ -104,13 +99,6 @@ void * gf100_fb_dtor(struct nvkm_fb *base) { struct gf100_fb *fb = gf100_fb(base); - struct nvkm_device *device = fb->base.subdev.device; - - if (fb->r100c10_page) { - dma_unmap_page(device->dev, fb->r100c10, PAGE_SIZE, - DMA_BIDIRECTIONAL); - __free_page(fb->r100c10_page); - } return fb; } @@ -136,6 +124,7 @@ gf100_fb = { .init = gf100_fb_init, .init_page = gf100_fb_init_page, .intr = gf100_fb_intr, + .sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init, .ram_new = gf100_ram_new, .default_bigpage = 17, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h index 0cac7b06acc8..77472b558591 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h @@ -6,8 +6,6 @@ struct gf100_fb { struct nvkm_fb base; - struct page *r100c10_page; - dma_addr_t r100c10; }; int gf100_fb_new_(const struct nvkm_fb_func *, struct nvkm_device *, enum nvkm_subdev_type, int, @@ -16,7 +14,5 @@ void *gf100_fb_dtor(struct nvkm_fb *); void gf100_fb_init(struct nvkm_fb *); void gf100_fb_intr(struct nvkm_fb *); -void gp100_fb_init(struct nvkm_fb *); - void gm200_fb_init(struct nvkm_fb *base); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm200.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm200.c index 5acf8d15d06f..fb02092a65eb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm200.c @@ -46,9 +46,6 @@ gm200_fb_init(struct nvkm_fb *base) struct gf100_fb *fb = gf100_fb(base); struct nvkm_device *device = fb->base.subdev.device; - if (fb->r100c10_page) - nvkm_wr32(device, 0x100c10, fb->r100c10 >> 8); - nvkm_wr32(device, 0x100cc8, nvkm_memory_addr(fb->base.mmu_wr) >> 8); nvkm_wr32(device, 0x100ccc, nvkm_memory_addr(fb->base.mmu_rd) >> 8); nvkm_mask(device, 0x100cc4, 0x00060000, @@ -62,6 +59,7 @@ gm200_fb = { .init = gm200_fb_init, .init_page = gm200_fb_init_page, .intr = gf100_fb_intr, + .sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init, .ram_new = gm200_ram_new, .default_bigpage = 0 /* per-instance. */, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm20b.c index 86f61a3f2fea..50875af94c18 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm20b.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm20b.c @@ -30,6 +30,7 @@ gm20b_fb = { .init = gm200_fb_init, .init_page = gm200_fb_init_page, .intr = gf100_fb_intr, + .sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init, .default_bigpage = 0 /* per-instance. */, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gp100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gp100.c index 09e943edc362..110c08c94849 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gp100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gp100.c @@ -44,29 +44,15 @@ gp100_fb_init_remapper(struct nvkm_fb *fb) nvkm_mask(device, 0x100c14, 0x00040000, 0x00000000); } -void -gp100_fb_init(struct nvkm_fb *base) -{ - struct gf100_fb *fb = gf100_fb(base); - struct nvkm_device *device = fb->base.subdev.device; - - if (fb->r100c10_page) - nvkm_wr32(device, 0x100c10, fb->r100c10 >> 8); - - nvkm_wr32(device, 0x100cc8, nvkm_memory_addr(fb->base.mmu_wr) >> 8); - nvkm_wr32(device, 0x100ccc, nvkm_memory_addr(fb->base.mmu_rd) >> 8); - nvkm_mask(device, 0x100cc4, 0x00060000, - min(nvkm_memory_size(fb->base.mmu_rd) >> 16, (u64)2) << 17); -} - static const struct nvkm_fb_func gp100_fb = { .dtor = gf100_fb_dtor, .oneinit = gf100_fb_oneinit, - .init = gp100_fb_init, + .init = gm200_fb_init, .init_remapper = gp100_fb_init_remapper, .init_page = gm200_fb_init_page, .init_unkn = gp100_fb_init_unkn, + .sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init, .ram_new = gp100_ram_new, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gp102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gp102.c index 0e78b3d734a0..2658481d575b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gp102.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gp102.c @@ -24,71 +24,22 @@ #include "gf100.h" #include "ram.h" -#include <core/firmware.h> -#include <core/memory.h> -#include <nvfw/fw.h> -#include <nvfw/hs.h> #include <engine/nvdec.h> int gp102_fb_vpr_scrub(struct nvkm_fb *fb) { struct nvkm_subdev *subdev = &fb->subdev; - struct nvkm_device *device = subdev->device; - struct nvkm_falcon *falcon = &device->nvdec[0]->falcon; - struct nvkm_blob *blob = &fb->vpr_scrubber; - const struct nvfw_bin_hdr *hsbin_hdr; - const struct nvfw_hs_header *fw_hdr; - const struct nvfw_hs_load_header *lhdr; - void *scrub_data; - u32 patch_loc, patch_sig; + struct nvkm_falcon_fw fw = {}; int ret; - nvkm_falcon_get(falcon, subdev); - - hsbin_hdr = nvfw_bin_hdr(subdev, blob->data); - fw_hdr = nvfw_hs_header(subdev, blob->data + hsbin_hdr->header_offset); - lhdr = nvfw_hs_load_header(subdev, blob->data + fw_hdr->hdr_offset); - scrub_data = blob->data + hsbin_hdr->data_offset; - - patch_loc = *(u32 *)(blob->data + fw_hdr->patch_loc); - patch_sig = *(u32 *)(blob->data + fw_hdr->patch_sig); - if (falcon->debug) { - memcpy(scrub_data + patch_loc, - blob->data + fw_hdr->sig_dbg_offset + patch_sig, - fw_hdr->sig_dbg_size); - } else { - memcpy(scrub_data + patch_loc, - blob->data + fw_hdr->sig_prod_offset + patch_sig, - fw_hdr->sig_prod_size); - } - - nvkm_falcon_reset(falcon); - nvkm_falcon_bind_context(falcon, NULL); - - nvkm_falcon_load_imem(falcon, scrub_data, lhdr->non_sec_code_off, - lhdr->non_sec_code_size, - lhdr->non_sec_code_off >> 8, 0, false); - nvkm_falcon_load_imem(falcon, scrub_data + lhdr->apps[0], - ALIGN(lhdr->apps[0], 0x100), - lhdr->apps[1], - lhdr->apps[0] >> 8, 0, true); - nvkm_falcon_load_dmem(falcon, scrub_data + lhdr->data_dma_base, 0, - lhdr->data_size, 0); - - nvkm_falcon_set_start_addr(falcon, 0x0); - nvkm_falcon_start(falcon); - - ret = nvkm_falcon_wait_for_halt(falcon, 500); - if (ret < 0) { - ret = -ETIMEDOUT; - goto end; - } + ret = nvkm_falcon_fw_ctor_hs(&gm200_flcn_fw, "mem-unlock", subdev, NULL, + "nvdec/scrubber", 0, &subdev->device->nvdec[0]->falcon, &fw); + if (ret) + return ret; - /* put nvdec in clean state - without reset it will remain in HS mode */ - nvkm_falcon_reset(falcon); -end: - nvkm_falcon_put(falcon, subdev); + ret = nvkm_falcon_fw_boot(&fw, subdev, true, NULL, NULL, 0, 0x00000000); + nvkm_falcon_fw_dtor(&fw); return ret; } @@ -104,9 +55,10 @@ static const struct nvkm_fb_func gp102_fb = { .dtor = gf100_fb_dtor, .oneinit = gf100_fb_oneinit, - .init = gp100_fb_init, + .init = gm200_fb_init, .init_remapper = gp100_fb_init_remapper, .init_page = gm200_fb_init_page, + .sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init, .vpr.scrub_required = gp102_fb_vpr_scrub_required, .vpr.scrub = gp102_fb_vpr_scrub, .ram_new = gp100_ram_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gp10b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gp10b.c index 84c9815a6d48..a04a5f712019 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gp10b.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gp10b.c @@ -28,6 +28,7 @@ gp10b_fb = { .init = gm200_fb_init, .init_page = gm200_fb_init_page, .intr = gf100_fb_intr, + .sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gv100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gv100.c index 63daa83ae12d..1f0126437c1a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gv100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gv100.c @@ -32,9 +32,10 @@ static const struct nvkm_fb_func gv100_fb = { .dtor = gf100_fb_dtor, .oneinit = gf100_fb_oneinit, - .init = gp100_fb_init, + .init = gm200_fb_init, .init_page = gv100_fb_init_page, .init_unkn = gp100_fb_init_unkn, + .sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init, .vpr.scrub_required = gp102_fb_vpr_scrub_required, .vpr.scrub = gp102_fb_vpr_scrub, .ram_new = gp100_ram_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c index 95fd8f834010..a6efbd913c13 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c @@ -137,8 +137,7 @@ nv50_fb_intr(struct nvkm_fb *base) struct nv50_fb *fb = nv50_fb(base); struct nvkm_subdev *subdev = &fb->base.subdev; struct nvkm_device *device = subdev->device; - struct nvkm_fifo *fifo = device->fifo; - struct nvkm_fifo_chan *chan; + struct nvkm_chan *chan; const struct nvkm_enum *en, *re, *cl, *sc; u32 trap[6], idx, inst; u8 st0, st1, st2, st3; @@ -178,35 +177,18 @@ nv50_fb_intr(struct nvkm_fb *base) else if (en && en->data) sc = nvkm_enum_find(en->data, st3); else sc = NULL; - chan = nvkm_fifo_chan_inst(fifo, inst, &flags); + chan = nvkm_chan_get_inst(&device->fifo->engine, inst, &flags); nvkm_error(subdev, "trapped %s at %02x%04x%04x on channel %d [%08x %s] " "engine %02x [%s] client %02x [%s] " "subclient %02x [%s] reason %08x [%s]\n", (trap[5] & 0x00000100) ? "read" : "write", trap[5] & 0xff, trap[4] & 0xffff, trap[3] & 0xffff, - chan ? chan->chid : -1, inst, - chan ? chan->object.client->name : "unknown", + chan ? chan->id : -1, inst, + chan ? chan->name : "unknown", st0, en ? en->name : "", st2, cl ? cl->name : "", st3, sc ? sc->name : "", st1, re ? re->name : ""); - nvkm_fifo_chan_put(fifo, flags, &chan); -} - -static int -nv50_fb_oneinit(struct nvkm_fb *base) -{ - struct nv50_fb *fb = nv50_fb(base); - struct nvkm_device *device = fb->base.subdev.device; - - fb->r100c08_page = alloc_page(GFP_KERNEL | __GFP_ZERO); - if (fb->r100c08_page) { - fb->r100c08 = dma_map_page(device->dev, fb->r100c08_page, 0, - PAGE_SIZE, DMA_BIDIRECTIONAL); - if (dma_mapping_error(device->dev, fb->r100c08)) - return -EFAULT; - } - - return 0; + nvkm_chan_put(&chan, flags); } static void @@ -215,12 +197,6 @@ nv50_fb_init(struct nvkm_fb *base) struct nv50_fb *fb = nv50_fb(base); struct nvkm_device *device = fb->base.subdev.device; - /* Not a clue what this is exactly. Without pointing it at a - * scratch page, VRAM->GART blits with M2MF (as in DDX DFS) - * cause IOMMU "read from address 0" errors (rh#561267) - */ - nvkm_wr32(device, 0x100c08, fb->r100c08 >> 8); - /* This is needed to get meaningful information from 100c90 * on traps. No idea what these values mean exactly. */ nvkm_wr32(device, 0x100c90, fb->func->trap); @@ -235,17 +211,16 @@ nv50_fb_tags(struct nvkm_fb *base) return 0; } +static void +nv50_fb_sysmem_flush_page_init(struct nvkm_fb *fb) +{ + nvkm_wr32(fb->subdev.device, 0x100c08, fb->sysmem.flush_page_addr >> 8); +} + static void * nv50_fb_dtor(struct nvkm_fb *base) { struct nv50_fb *fb = nv50_fb(base); - struct nvkm_device *device = fb->base.subdev.device; - - if (fb->r100c08_page) { - dma_unmap_page(device->dev, fb->r100c08, PAGE_SIZE, - DMA_BIDIRECTIONAL); - __free_page(fb->r100c08_page); - } return fb; } @@ -254,9 +229,9 @@ static const struct nvkm_fb_func nv50_fb_ = { .dtor = nv50_fb_dtor, .tags = nv50_fb_tags, - .oneinit = nv50_fb_oneinit, .init = nv50_fb_init, .intr = nv50_fb_intr, + .sysmem.flush_page_init = nv50_fb_sysmem_flush_page_init, .ram_new = nv50_fb_ram_new, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.h index a5e673859a90..4f68bc4513a7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.h @@ -7,8 +7,6 @@ struct nv50_fb { const struct nv50_fb_func *func; struct nvkm_fb base; - struct page *r100c08_page; - dma_addr_t r100c08; }; struct nv50_fb_func { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h index 3f1be9780c65..ac03eac0f261 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h @@ -16,6 +16,10 @@ struct nvkm_fb_func { void (*init_unkn)(struct nvkm_fb *); void (*intr)(struct nvkm_fb *); + struct nvkm_fb_func_sysmem { + void (*flush_page_init)(struct nvkm_fb *); + } sysmem; + struct { bool (*scrub_required)(struct nvkm_fb *); int (*scrub)(struct nvkm_fb *); @@ -37,8 +41,8 @@ struct nvkm_fb_func { const struct nvkm_therm_clkgate_pack *clkgate_pack; }; -void nvkm_fb_ctor(const struct nvkm_fb_func *, struct nvkm_device *device, - enum nvkm_subdev_type type, int inst, struct nvkm_fb *); +int nvkm_fb_ctor(const struct nvkm_fb_func *, struct nvkm_device *device, + enum nvkm_subdev_type type, int inst, struct nvkm_fb *); int nvkm_fb_new_(const struct nvkm_fb_func *, struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **); int nvkm_fb_bios_memtype(struct nvkm_bios *); @@ -72,6 +76,7 @@ void nv46_fb_tile_init(struct nvkm_fb *, int i, u32 addr, u32 size, int gf100_fb_oneinit(struct nvkm_fb *); int gf100_fb_init_page(struct nvkm_fb *); +void gf100_fb_sysmem_flush_page_init(struct nvkm_fb *); int gm200_fb_init_page(struct nvkm_fb *); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.c index 03b1bdb27770..5c34416cb637 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.c @@ -25,6 +25,7 @@ #include "ram.h" #include <core/memory.h> +#include <subdev/instmem.h> #include <subdev/mmu.h> struct nvkm_vram { @@ -35,6 +36,12 @@ struct nvkm_vram { }; static int +nvkm_vram_kmap(struct nvkm_memory *memory, struct nvkm_memory **pmemory) +{ + return nvkm_instobj_wrap(nvkm_vram(memory)->ram->fb->subdev.device, memory, pmemory); +} + +static int nvkm_vram_map(struct nvkm_memory *memory, u64 offset, struct nvkm_vmm *vmm, struct nvkm_vma *vma, void *argv, u32 argc) { @@ -98,6 +105,7 @@ nvkm_vram = { .addr = nvkm_vram_addr, .size = nvkm_vram_size, .map = nvkm_vram_map, + .kmap = nvkm_vram_kmap, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c index 048bcc70c3f4..b196baa376dc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c @@ -24,7 +24,6 @@ #include "priv.h" #include <core/option.h> -#include <core/notify.h> static int nvkm_gpio_drive(struct nvkm_gpio *gpio, int idx, int line, int dir, int out) @@ -123,23 +122,8 @@ nvkm_gpio_intr_init(struct nvkm_event *event, int type, int index) gpio->func->intr_mask(gpio, type, 1 << index, 1 << index); } -static int -nvkm_gpio_intr_ctor(struct nvkm_object *object, void *data, u32 size, - struct nvkm_notify *notify) -{ - struct nvkm_gpio_ntfy_req *req = data; - if (!WARN_ON(size != sizeof(*req))) { - notify->size = sizeof(struct nvkm_gpio_ntfy_rep); - notify->types = req->mask; - notify->index = req->line; - return 0; - } - return -EINVAL; -} - static const struct nvkm_event_func nvkm_gpio_intr_func = { - .ctor = nvkm_gpio_intr_ctor, .init = nvkm_gpio_intr_init, .fini = nvkm_gpio_intr_fini, }; @@ -153,11 +137,9 @@ nvkm_gpio_intr(struct nvkm_subdev *subdev) gpio->func->intr_stat(gpio, &hi, &lo); for (i = 0; (hi | lo) && i < gpio->func->lines; i++) { - struct nvkm_gpio_ntfy_rep rep = { - .mask = (NVKM_GPIO_HI * !!(hi & (1 << i))) | - (NVKM_GPIO_LO * !!(lo & (1 << i))), - }; - nvkm_event_send(&gpio->event, rep.mask, i, &rep, sizeof(rep)); + u32 mask = (NVKM_GPIO_HI * !!(hi & (1 << i))) | + (NVKM_GPIO_LO * !!(lo & (1 << i))); + nvkm_event_ntfy(&gpio->event, i, mask); } } @@ -251,6 +233,5 @@ nvkm_gpio_new_(const struct nvkm_gpio_func *func, struct nvkm_device *device, nvkm_subdev_ctor(&nvkm_gpio, device, type, inst, &gpio->subdev); gpio->func = func; - return nvkm_event_init(&nvkm_gpio_intr_func, 2, func->lines, - &gpio->event); + return nvkm_event_init(&nvkm_gpio_intr_func, &gpio->subdev, 2, func->lines, &gpio->event); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/Kbuild index 67cc3b320169..7f61a1ed158b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/Kbuild @@ -1,3 +1,4 @@ # SPDX-License-Identifier: MIT nvkm-y += nvkm/subdev/gsp/base.o nvkm-y += nvkm/subdev/gsp/gv100.o +nvkm-y += nvkm/subdev/gsp/ga102.o diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/base.c index 22574886b819..591ac95c2669 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/base.c @@ -53,5 +53,7 @@ nvkm_gsp_new_(const struct nvkm_gsp_fwif *fwif, struct nvkm_device *device, if (IS_ERR(fwif)) return PTR_ERR(fwif); - return nvkm_falcon_ctor(fwif->flcn, &gsp->subdev, gsp->subdev.name, 0, &gsp->falcon); + gsp->func = fwif->func; + + return nvkm_falcon_ctor(gsp->func->flcn, &gsp->subdev, gsp->subdev.name, 0, &gsp->falcon); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ga102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ga102.c new file mode 100644 index 000000000000..525267412c3e --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ga102.c @@ -0,0 +1,59 @@ +/* + * Copyright 2021 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +#include "priv.h" + +static const struct nvkm_falcon_func +ga102_gsp_flcn = { + .disable = gm200_flcn_disable, + .enable = gm200_flcn_enable, + .select = ga102_flcn_select, + .addr2 = 0x1000, + .reset_eng = gp102_flcn_reset_eng, + .reset_prep = ga102_flcn_reset_prep, + .reset_wait_mem_scrubbing = ga102_flcn_reset_wait_mem_scrubbing, + .imem_dma = &ga102_flcn_dma, + .dmem_dma = &ga102_flcn_dma, +}; + +static const struct nvkm_gsp_func +ga102_gsp = { + .flcn = &ga102_gsp_flcn, +}; + +static int +ga102_gsp_nofw(struct nvkm_gsp *gsp, int ver, const struct nvkm_gsp_fwif *fwif) +{ + return 0; +} + +struct nvkm_gsp_fwif +ga102_gsps[] = { + { -1, ga102_gsp_nofw, &ga102_gsp }, + {} +}; + +int +ga102_gsp_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, + struct nvkm_gsp **pgsp) +{ + return nvkm_gsp_new_(ga102_gsps, device, type, inst, pgsp); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/gv100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/gv100.c index 6c4ef62a746a..da6a809cd317 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/gv100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/gv100.c @@ -23,17 +23,20 @@ static const struct nvkm_falcon_func gv100_gsp_flcn = { - .fbif = 0x600, - .load_imem = nvkm_falcon_v1_load_imem, - .load_dmem = nvkm_falcon_v1_load_dmem, - .read_dmem = nvkm_falcon_v1_read_dmem, - .bind_context = gp102_sec2_flcn_bind_context, - .wait_for_halt = nvkm_falcon_v1_wait_for_halt, - .clear_interrupt = nvkm_falcon_v1_clear_interrupt, - .set_start_addr = nvkm_falcon_v1_set_start_addr, - .start = nvkm_falcon_v1_start, - .enable = gp102_sec2_flcn_enable, - .disable = nvkm_falcon_v1_disable, + .disable = gm200_flcn_disable, + .enable = gm200_flcn_enable, + .reset_eng = gp102_flcn_reset_eng, + .reset_wait_mem_scrubbing = gm200_flcn_reset_wait_mem_scrubbing, + .bind_inst = gm200_flcn_bind_inst, + .bind_stat = gm200_flcn_bind_stat, + .bind_intr = true, + .imem_pio = &gm200_flcn_imem_pio, + .dmem_pio = &gm200_flcn_dmem_pio, +}; + +static const struct nvkm_gsp_func +gv100_gsp = { + .flcn = &gv100_gsp_flcn, }; static int @@ -43,8 +46,8 @@ gv100_gsp_nofw(struct nvkm_gsp *gsp, int ver, const struct nvkm_gsp_fwif *fwif) } static struct nvkm_gsp_fwif -gv100_gsp[] = { - { -1, gv100_gsp_nofw, &gv100_gsp_flcn }, +gv100_gsps[] = { + { -1, gv100_gsp_nofw, &gv100_gsp }, {} }; @@ -52,5 +55,5 @@ int gv100_gsp_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_gsp **pgsp) { - return nvkm_gsp_new_(gv100_gsp, device, type, inst, pgsp); + return nvkm_gsp_new_(gv100_gsps, device, type, inst, pgsp); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h index 19381ddd38d4..89749a40203c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h @@ -4,10 +4,14 @@ #include <subdev/gsp.h> enum nvkm_acr_lsf_id; +struct nvkm_gsp_func { + const struct nvkm_falcon_func *flcn; +}; + struct nvkm_gsp_fwif { int version; int (*load)(struct nvkm_gsp *, int ver, const struct nvkm_gsp_fwif *); - const struct nvkm_falcon_func *flcn; + const struct nvkm_gsp_func *func; }; int nvkm_gsp_new_(const struct nvkm_gsp_fwif *, struct nvkm_device *, enum nvkm_subdev_type, int, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c index cb5cb533d91c..976539de4220 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c @@ -26,7 +26,6 @@ #include "bus.h" #include "pad.h" -#include <core/notify.h> #include <core/option.h> #include <subdev/bios.h> #include <subdev/bios/dcb.h> @@ -104,23 +103,8 @@ nvkm_i2c_intr_init(struct nvkm_event *event, int type, int id) i2c->func->aux_mask(i2c, type, aux->intr, aux->intr); } -static int -nvkm_i2c_intr_ctor(struct nvkm_object *object, void *data, u32 size, - struct nvkm_notify *notify) -{ - struct nvkm_i2c_ntfy_req *req = data; - if (!WARN_ON(size != sizeof(*req))) { - notify->size = sizeof(struct nvkm_i2c_ntfy_rep); - notify->types = req->mask; - notify->index = req->port; - return 0; - } - return -EINVAL; -} - static const struct nvkm_event_func nvkm_i2c_intr_func = { - .ctor = nvkm_i2c_intr_ctor, .init = nvkm_i2c_intr_init, .fini = nvkm_i2c_intr_fini, }; @@ -145,13 +129,8 @@ nvkm_i2c_intr(struct nvkm_subdev *subdev) if (lo & aux->intr) mask |= NVKM_I2C_UNPLUG; if (rq & aux->intr) mask |= NVKM_I2C_IRQ; if (tx & aux->intr) mask |= NVKM_I2C_DONE; - if (mask) { - struct nvkm_i2c_ntfy_rep rep = { - .mask = mask, - }; - nvkm_event_send(&i2c->event, rep.mask, aux->id, - &rep, sizeof(rep)); - } + if (mask) + nvkm_event_ntfy(&i2c->event, aux->id, mask); } } @@ -427,5 +406,5 @@ nvkm_i2c_new_(const struct nvkm_i2c_func *func, struct nvkm_device *device, } } - return nvkm_event_init(&nvkm_i2c_intr_func, 4, i, &i2c->event); + return nvkm_event_init(&nvkm_i2c_intr_func, &i2c->subdev, 4, i, &i2c->event); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c index cd8163a52bb6..e0e4f97be029 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c @@ -90,6 +90,18 @@ nvkm_instobj_ctor(const struct nvkm_memory_func *func, } int +nvkm_instobj_wrap(struct nvkm_device *device, + struct nvkm_memory *memory, struct nvkm_memory **pmemory) +{ + struct nvkm_instmem *imem = device->imem; + + if (!imem->func->memory_wrap) + return -ENOSYS; + + return imem->func->memory_wrap(imem, memory, pmemory); +} + +int nvkm_instobj_new(struct nvkm_instmem *imem, u32 size, u32 align, bool zero, struct nvkm_memory **pmemory) { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c index c51bac76174c..4b2d7465d22f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c @@ -348,13 +348,11 @@ nv50_instobj_func = { }; static int -nv50_instobj_new(struct nvkm_instmem *base, u32 size, u32 align, bool zero, - struct nvkm_memory **pmemory) +nv50_instobj_wrap(struct nvkm_instmem *base, + struct nvkm_memory *memory, struct nvkm_memory **pmemory) { struct nv50_instmem *imem = nv50_instmem(base); struct nv50_instobj *iobj; - struct nvkm_device *device = imem->base.subdev.device; - u8 page = max(order_base_2(align), 12); if (!(iobj = kzalloc(sizeof(*iobj), GFP_KERNEL))) return -ENOMEM; @@ -365,7 +363,25 @@ nv50_instobj_new(struct nvkm_instmem *base, u32 size, u32 align, bool zero, refcount_set(&iobj->maps, 0); INIT_LIST_HEAD(&iobj->lru); - return nvkm_ram_get(device, 0, 1, page, size, true, true, &iobj->ram); + iobj->ram = nvkm_memory_ref(memory); + return 0; +} + +static int +nv50_instobj_new(struct nvkm_instmem *imem, u32 size, u32 align, bool zero, + struct nvkm_memory **pmemory) +{ + u8 page = max(order_base_2(align), 12); + struct nvkm_memory *ram; + int ret; + + ret = nvkm_ram_get(imem->subdev.device, 0, 1, page, size, true, true, &ram); + if (ret) + return ret; + + ret = nv50_instobj_wrap(imem, ram, pmemory); + nvkm_memory_unref(&ram); + return ret; } /****************************************************************************** @@ -382,6 +398,7 @@ static const struct nvkm_instmem_func nv50_instmem = { .fini = nv50_instmem_fini, .memory_new = nv50_instobj_new, + .memory_wrap = nv50_instobj_wrap, .zero = false, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h index 56c15e30a5dd..fe92986a3885 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h @@ -12,6 +12,7 @@ struct nvkm_instmem_func { void (*wr32)(struct nvkm_instmem *, u32 addr, u32 data); int (*memory_new)(struct nvkm_instmem *, u32 size, u32 align, bool zero, struct nvkm_memory **); + int (*memory_wrap)(struct nvkm_instmem *, struct nvkm_memory *, struct nvkm_memory **); bool zero; }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/Kbuild index 728d75010847..0d8a915d727e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/Kbuild @@ -7,3 +7,4 @@ nvkm-y += nvkm/subdev/ltc/gm200.o nvkm-y += nvkm/subdev/ltc/gp100.o nvkm-y += nvkm/subdev/ltc/gp102.o nvkm-y += nvkm/subdev/ltc/gp10b.o +nvkm-y += nvkm/subdev/ltc/ga102.o diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/base.c index fa683c190795..f742a7b7b175 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/base.c @@ -97,8 +97,10 @@ nvkm_ltc_init(struct nvkm_subdev *subdev) struct nvkm_ltc *ltc = nvkm_ltc(subdev); int i; - for (i = ltc->zbc_min; i <= ltc->zbc_max; i++) { + for (i = ltc->zbc_color_min; i <= ltc->zbc_color_max; i++) ltc->func->zbc_clear_color(ltc, i, ltc->zbc_color[i]); + + for (i = ltc->zbc_depth_min; i <= ltc->zbc_depth_max; i++) { ltc->func->zbc_clear_depth(ltc, i, ltc->zbc_depth[i]); if (ltc->func->zbc_clear_stencil) ltc->func->zbc_clear_stencil(ltc, i, ltc->zbc_stencil[i]); @@ -137,7 +139,9 @@ nvkm_ltc_new_(const struct nvkm_ltc_func *func, struct nvkm_device *device, nvkm_subdev_ctor(&nvkm_ltc, device, type, inst, <c->subdev); ltc->func = func; mutex_init(<c->mutex); - ltc->zbc_min = 1; /* reserve 0 for disabled */ - ltc->zbc_max = min(func->zbc, NVKM_LTC_MAX_ZBC_CNT) - 1; + ltc->zbc_color_min = 1; /* reserve 0 for disabled */ + ltc->zbc_color_max = min(func->zbc_color, NVKM_LTC_MAX_ZBC_COLOR_CNT) - 1; + ltc->zbc_depth_min = 1; /* reserve 0 for disabled */ + ltc->zbc_depth_max = min(func->zbc_depth, NVKM_LTC_MAX_ZBC_DEPTH_CNT) - 1; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/ga102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/ga102.c new file mode 100644 index 000000000000..159d9f8c95f3 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/ga102.c @@ -0,0 +1,57 @@ +/* + * Copyright 2021 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +#include "priv.h" + +static void +ga102_ltc_zbc_clear_color(struct nvkm_ltc *ltc, int i, const u32 color[4]) +{ + struct nvkm_device *device = ltc->subdev.device; + + nvkm_mask(device, 0x17e338, 0x0000001f, i); + nvkm_wr32(device, 0x17e33c, color[0]); + nvkm_wr32(device, 0x17e340, color[1]); + nvkm_wr32(device, 0x17e344, color[2]); + nvkm_wr32(device, 0x17e348, color[3]); +} + +static const struct nvkm_ltc_func +ga102_ltc = { + .oneinit = gp100_ltc_oneinit, + .init = gp100_ltc_init, + .intr = gp100_ltc_intr, + .cbc_clear = gm107_ltc_cbc_clear, + .cbc_wait = gm107_ltc_cbc_wait, + .zbc_color = 31, + .zbc_depth = 16, + .zbc_clear_color = ga102_ltc_zbc_clear_color, + .zbc_clear_depth = gm107_ltc_zbc_clear_depth, + .zbc_clear_stencil = gp102_ltc_zbc_clear_stencil, + .invalidate = gf100_ltc_invalidate, + .flush = gf100_ltc_flush, +}; + +int +ga102_ltc_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, + struct nvkm_ltc **pltc) +{ + return nvkm_ltc_new_(&ga102_ltc, device, type, inst, pltc); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c index fd8aeafc812d..de71ba3c9292 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c @@ -241,7 +241,8 @@ gf100_ltc = { .intr = gf100_ltc_intr, .cbc_clear = gf100_ltc_cbc_clear, .cbc_wait = gf100_ltc_cbc_wait, - .zbc = 16, + .zbc_color = 16, + .zbc_depth = 16, .zbc_clear_color = gf100_ltc_zbc_clear_color, .zbc_clear_depth = gf100_ltc_zbc_clear_depth, .invalidate = gf100_ltc_invalidate, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gk104.c index 94aa09244d67..5d61e3c6ff59 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gk104.c @@ -42,7 +42,8 @@ gk104_ltc = { .intr = gf100_ltc_intr, .cbc_clear = gf100_ltc_cbc_clear, .cbc_wait = gf100_ltc_cbc_wait, - .zbc = 16, + .zbc_color = 16, + .zbc_depth = 16, .zbc_clear_color = gf100_ltc_zbc_clear_color, .zbc_clear_depth = gf100_ltc_zbc_clear_depth, .invalidate = gf100_ltc_invalidate, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c index 54d1d65d5a85..18685d849657 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c @@ -137,7 +137,8 @@ gm107_ltc = { .intr = gm107_ltc_intr, .cbc_clear = gm107_ltc_cbc_clear, .cbc_wait = gm107_ltc_cbc_wait, - .zbc = 16, + .zbc_color = 16, + .zbc_depth = 16, .zbc_clear_color = gm107_ltc_zbc_clear_color, .zbc_clear_depth = gm107_ltc_zbc_clear_depth, .invalidate = gf100_ltc_invalidate, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm200.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm200.c index 8cfdbbdd8e8d..7a9464b9def5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm200.c @@ -49,7 +49,8 @@ gm200_ltc = { .intr = gm107_ltc_intr, .cbc_clear = gm107_ltc_cbc_clear, .cbc_wait = gm107_ltc_cbc_wait, - .zbc = 16, + .zbc_color = 16, + .zbc_depth = 16, .zbc_clear_color = gm107_ltc_zbc_clear_color, .zbc_clear_depth = gm107_ltc_zbc_clear_depth, .invalidate = gf100_ltc_invalidate, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp100.c index a4a6cd9b435a..1a17a451754c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp100.c @@ -61,7 +61,8 @@ gp100_ltc = { .intr = gp100_ltc_intr, .cbc_clear = gm107_ltc_cbc_clear, .cbc_wait = gm107_ltc_cbc_wait, - .zbc = 16, + .zbc_color = 16, + .zbc_depth = 16, .zbc_clear_color = gm107_ltc_zbc_clear_color, .zbc_clear_depth = gm107_ltc_zbc_clear_depth, .invalidate = gf100_ltc_invalidate, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp102.c index ff05d617e7f4..265a05fd5f6b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp102.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp102.c @@ -36,7 +36,8 @@ gp102_ltc = { .intr = gp100_ltc_intr, .cbc_clear = gm107_ltc_cbc_clear, .cbc_wait = gm107_ltc_cbc_wait, - .zbc = 16, + .zbc_color = 16, + .zbc_depth = 16, .zbc_clear_color = gm107_ltc_zbc_clear_color, .zbc_clear_depth = gm107_ltc_zbc_clear_depth, .zbc_clear_stencil = gp102_ltc_zbc_clear_stencil, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp10b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp10b.c index dfebd796cb4b..e7e8fdf3adab 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp10b.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp10b.c @@ -50,7 +50,8 @@ gp10b_ltc = { .intr = gp100_ltc_intr, .cbc_clear = gm107_ltc_cbc_clear, .cbc_wait = gm107_ltc_cbc_wait, - .zbc = 16, + .zbc_color = 16, + .zbc_depth = 16, .zbc_clear_color = gm107_ltc_zbc_clear_color, .zbc_clear_depth = gm107_ltc_zbc_clear_depth, .zbc_clear_stencil = gp102_ltc_zbc_clear_stencil, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h index 2bebe139005d..134e90c9e861 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h @@ -16,7 +16,8 @@ struct nvkm_ltc_func { void (*cbc_clear)(struct nvkm_ltc *, u32 start, u32 limit); void (*cbc_wait)(struct nvkm_ltc *); - int zbc; + int zbc_color; + int zbc_depth; void (*zbc_clear_color)(struct nvkm_ltc *, int, const u32[4]); void (*zbc_clear_depth)(struct nvkm_ltc *, int, const u32); void (*zbc_clear_stencil)(struct nvkm_ltc *, int, const u32); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/Kbuild index ac2b34e9ac6a..2a3255ced8b7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/Kbuild @@ -13,5 +13,4 @@ nvkm-y += nvkm/subdev/mc/gk104.o nvkm-y += nvkm/subdev/mc/gk20a.o nvkm-y += nvkm/subdev/mc/gp100.o nvkm-y += nvkm/subdev/mc/gp10b.o -nvkm-y += nvkm/subdev/mc/tu102.o nvkm-y += nvkm/subdev/mc/ga100.o diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c index 21c4af3f81d5..c85600ba69f9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c @@ -37,84 +37,14 @@ nvkm_mc_unk260(struct nvkm_device *device, u32 data) void nvkm_mc_intr_mask(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, bool en) { - struct nvkm_mc *mc = device->mc; - const struct nvkm_mc_map *map; - if (likely(mc) && mc->func->intr_mask) { - u32 mask = nvkm_top_intr_mask(device, type, inst); - for (map = mc->func->intr; !mask && map->stat; map++) { - if (map->type == type && map->inst == inst) - mask = map->stat; - } - mc->func->intr_mask(mc, mask, en ? mask : 0); - } -} - -void -nvkm_mc_intr_unarm(struct nvkm_device *device) -{ - struct nvkm_mc *mc = device->mc; - if (likely(mc)) - mc->func->intr_unarm(mc); -} - -void -nvkm_mc_intr_rearm(struct nvkm_device *device) -{ - struct nvkm_mc *mc = device->mc; - if (likely(mc)) - mc->func->intr_rearm(mc); -} - -static u32 -nvkm_mc_intr_stat(struct nvkm_mc *mc) -{ - u32 intr = mc->func->intr_stat(mc); - if (WARN_ON_ONCE(intr == 0xffffffff)) - intr = 0; /* likely fallen off the bus */ - return intr; -} - -void -nvkm_mc_intr(struct nvkm_device *device, bool *handled) -{ - struct nvkm_mc *mc = device->mc; - struct nvkm_top *top = device->top; - struct nvkm_top_device *tdev; - struct nvkm_subdev *subdev; - const struct nvkm_mc_map *map; - u32 stat, intr; - - if (unlikely(!mc)) - return; - - stat = intr = nvkm_mc_intr_stat(mc); - - if (top) { - list_for_each_entry(tdev, &top->device, head) { - if (tdev->intr >= 0 && (stat & BIT(tdev->intr))) { - subdev = nvkm_device_subdev(device, tdev->type, tdev->inst); - if (subdev) { - nvkm_subdev_intr(subdev); - stat &= ~BIT(tdev->intr); - if (!stat) - break; - } - } - } - } + struct nvkm_subdev *subdev = nvkm_device_subdev(device, type, inst); - for (map = mc->func->intr; map->stat; map++) { - if (intr & map->stat) { - subdev = nvkm_device_subdev(device, map->type, map->inst); - if (subdev) - nvkm_subdev_intr(subdev); - stat &= ~map->stat; - } + if (subdev) { + if (en) + nvkm_intr_allow(subdev, NVKM_INTR_SUBDEV); + else + nvkm_intr_block(subdev, NVKM_INTR_SUBDEV); } - - if (stat) - nvkm_error(&mc->subdev, "intr %08x\n", stat); - *handled = intr != 0; } static u32 @@ -143,9 +73,8 @@ nvkm_mc_reset(struct nvkm_device *device, enum nvkm_subdev_type type, int inst) { u64 pmc_enable = nvkm_mc_reset_mask(device, true, type, inst); if (pmc_enable) { - nvkm_mask(device, 0x000200, pmc_enable, 0x00000000); - nvkm_mask(device, 0x000200, pmc_enable, pmc_enable); - nvkm_rd32(device, 0x000200); + device->mc->func->device->disable(device->mc, pmc_enable); + device->mc->func->device->enable(device->mc, pmc_enable); } } @@ -154,17 +83,15 @@ nvkm_mc_disable(struct nvkm_device *device, enum nvkm_subdev_type type, int inst { u64 pmc_enable = nvkm_mc_reset_mask(device, false, type, inst); if (pmc_enable) - nvkm_mask(device, 0x000200, pmc_enable, 0x00000000); + device->mc->func->device->disable(device->mc, pmc_enable); } void nvkm_mc_enable(struct nvkm_device *device, enum nvkm_subdev_type type, int inst) { u64 pmc_enable = nvkm_mc_reset_mask(device, false, type, inst); - if (pmc_enable) { - nvkm_mask(device, 0x000200, pmc_enable, pmc_enable); - nvkm_rd32(device, 0x000200); - } + if (pmc_enable) + device->mc->func->device->enable(device->mc, pmc_enable); } bool @@ -172,16 +99,7 @@ nvkm_mc_enabled(struct nvkm_device *device, enum nvkm_subdev_type type, int inst { u64 pmc_enable = nvkm_mc_reset_mask(device, false, type, inst); - return (pmc_enable != 0) && - ((nvkm_rd32(device, 0x000200) & pmc_enable) == pmc_enable); -} - - -static int -nvkm_mc_fini(struct nvkm_subdev *subdev, bool suspend) -{ - nvkm_mc_intr_unarm(subdev->device); - return 0; + return (pmc_enable != 0) && device->mc->func->device->enabled(device->mc, pmc_enable); } static int @@ -190,7 +108,6 @@ nvkm_mc_init(struct nvkm_subdev *subdev) struct nvkm_mc *mc = nvkm_mc(subdev); if (mc->func->init) mc->func->init(mc); - nvkm_mc_intr_rearm(subdev->device); return 0; } @@ -204,24 +121,27 @@ static const struct nvkm_subdev_func nvkm_mc = { .dtor = nvkm_mc_dtor, .init = nvkm_mc_init, - .fini = nvkm_mc_fini, }; -void -nvkm_mc_ctor(const struct nvkm_mc_func *func, struct nvkm_device *device, - enum nvkm_subdev_type type, int inst, struct nvkm_mc *mc) -{ - nvkm_subdev_ctor(&nvkm_mc, device, type, inst, &mc->subdev); - mc->func = func; -} - int nvkm_mc_new_(const struct nvkm_mc_func *func, struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_mc **pmc) { struct nvkm_mc *mc; + int ret; + if (!(mc = *pmc = kzalloc(sizeof(*mc), GFP_KERNEL))) return -ENOMEM; - nvkm_mc_ctor(func, device, type, inst, *pmc); + + nvkm_subdev_ctor(&nvkm_mc, device, type, inst, &mc->subdev); + mc->func = func; + + if (mc->func->intr) { + ret = nvkm_intr_add(mc->func->intr, mc->func->intrs, &mc->subdev, + mc->func->intr_nonstall ? 2 : 1, &mc->intr); + if (ret) + return ret; + } + return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g84.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g84.c index 4cfc1c984006..f4ee99137b1f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g84.c @@ -34,30 +34,29 @@ g84_mc_reset[] = { {} }; -static const struct nvkm_mc_map -g84_mc_intr[] = { - { 0x04000000, NVKM_ENGINE_DISP }, - { 0x00020000, NVKM_ENGINE_VP }, - { 0x00008000, NVKM_ENGINE_BSP }, - { 0x00004000, NVKM_ENGINE_CIPHER }, - { 0x00001000, NVKM_ENGINE_GR }, - { 0x00000100, NVKM_ENGINE_FIFO }, - { 0x00000001, NVKM_ENGINE_MPEG }, - { 0x0002d101, NVKM_SUBDEV_FB }, - { 0x10000000, NVKM_SUBDEV_BUS }, - { 0x00200000, NVKM_SUBDEV_GPIO }, - { 0x00200000, NVKM_SUBDEV_I2C }, - { 0x00100000, NVKM_SUBDEV_TIMER }, +static const struct nvkm_intr_data +g84_mc_intrs[] = { + { NVKM_ENGINE_DISP , 0, 0, 0x04000000, true }, + { NVKM_ENGINE_VP , 0, 0, 0x00020000, true }, + { NVKM_ENGINE_BSP , 0, 0, 0x00008000, true }, + { NVKM_ENGINE_CIPHER, 0, 0, 0x00004000, true }, + { NVKM_ENGINE_GR , 0, 0, 0x00001000, true }, + { NVKM_ENGINE_FIFO , 0, 0, 0x00000100 }, + { NVKM_ENGINE_MPEG , 0, 0, 0x00000001, true }, + { NVKM_SUBDEV_FB , 0, 0, 0x0002d101, true }, + { NVKM_SUBDEV_BUS , 0, 0, 0x10000000, true }, + { NVKM_SUBDEV_GPIO , 0, 0, 0x00200000, true }, + { NVKM_SUBDEV_I2C , 0, 0, 0x00200000, true }, + { NVKM_SUBDEV_TIMER , 0, 0, 0x00100000, true }, {}, }; static const struct nvkm_mc_func g84_mc = { .init = nv50_mc_init, - .intr = g84_mc_intr, - .intr_unarm = nv04_mc_intr_unarm, - .intr_rearm = nv04_mc_intr_rearm, - .intr_stat = nv04_mc_intr_stat, + .intr = &nv04_mc_intr, + .intrs = g84_mc_intrs, + .device = &nv04_mc_device, .reset = g84_mc_reset, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c index b7e58d75d894..f42684809f08 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c @@ -34,30 +34,29 @@ g98_mc_reset[] = { {} }; -static const struct nvkm_mc_map -g98_mc_intr[] = { - { 0x04000000, NVKM_ENGINE_DISP }, - { 0x00020000, NVKM_ENGINE_MSPDEC }, - { 0x00008000, NVKM_ENGINE_MSVLD }, - { 0x00004000, NVKM_ENGINE_SEC }, - { 0x00001000, NVKM_ENGINE_GR }, - { 0x00000100, NVKM_ENGINE_FIFO }, - { 0x00000001, NVKM_ENGINE_MSPPP }, - { 0x0002d101, NVKM_SUBDEV_FB }, - { 0x10000000, NVKM_SUBDEV_BUS }, - { 0x00200000, NVKM_SUBDEV_GPIO }, - { 0x00200000, NVKM_SUBDEV_I2C }, - { 0x00100000, NVKM_SUBDEV_TIMER }, +static const struct nvkm_intr_data +g98_mc_intrs[] = { + { NVKM_ENGINE_DISP , 0, 0, 0x04000000, true }, + { NVKM_ENGINE_MSPDEC, 0, 0, 0x00020000, true }, + { NVKM_ENGINE_MSVLD , 0, 0, 0x00008000, true }, + { NVKM_ENGINE_SEC , 0, 0, 0x00004000, true }, + { NVKM_ENGINE_GR , 0, 0, 0x00001000, true }, + { NVKM_ENGINE_FIFO , 0, 0, 0x00000100 }, + { NVKM_ENGINE_MSPPP , 0, 0, 0x00000001, true }, + { NVKM_SUBDEV_FB , 0, 0, 0x0002d101, true }, + { NVKM_SUBDEV_BUS , 0, 0, 0x10000000, true }, + { NVKM_SUBDEV_GPIO , 0, 0, 0x00200000, true }, + { NVKM_SUBDEV_I2C , 0, 0, 0x00200000, true }, + { NVKM_SUBDEV_TIMER , 0, 0, 0x00100000, true }, {}, }; static const struct nvkm_mc_func g98_mc = { .init = nv50_mc_init, - .intr = g98_mc_intr, - .intr_unarm = nv04_mc_intr_unarm, - .intr_rearm = nv04_mc_intr_rearm, - .intr_stat = nv04_mc_intr_stat, + .intr = &nv04_mc_intr, + .intrs = g98_mc_intrs, + .device = &nv04_mc_device, .reset = g98_mc_reset, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/ga100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/ga100.c index 4105175dfccd..1e2eabec1a76 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/ga100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/ga100.c @@ -22,49 +22,51 @@ #include "priv.h" static void -ga100_mc_intr_unarm(struct nvkm_mc *mc) +ga100_mc_device_disable(struct nvkm_mc *mc, u32 mask) { - nvkm_wr32(mc->subdev.device, 0xb81610, 0x00000004); -} + struct nvkm_device *device = mc->subdev.device; -static void -ga100_mc_intr_rearm(struct nvkm_mc *mc) -{ - nvkm_wr32(mc->subdev.device, 0xb81608, 0x00000004); + nvkm_mask(device, 0x000600, mask, 0x00000000); + nvkm_rd32(device, 0x000600); + nvkm_rd32(device, 0x000600); } static void -ga100_mc_intr_mask(struct nvkm_mc *mc, u32 mask, u32 intr) +ga100_mc_device_enable(struct nvkm_mc *mc, u32 mask) { - nvkm_wr32(mc->subdev.device, 0xb81210, mask & intr ); - nvkm_wr32(mc->subdev.device, 0xb81410, mask & ~(mask & intr)); + struct nvkm_device *device = mc->subdev.device; + + nvkm_mask(device, 0x000600, mask, mask); + nvkm_rd32(device, 0x000600); + nvkm_rd32(device, 0x000600); } -static u32 -ga100_mc_intr_stat(struct nvkm_mc *mc) +static bool +ga100_mc_device_enabled(struct nvkm_mc *mc, u32 mask) { - u32 intr_top = nvkm_rd32(mc->subdev.device, 0xb81600), intr = 0x00000000; - if (intr_top & 0x00000004) - intr = nvkm_mask(mc->subdev.device, 0xb81010, 0x00000000, 0x00000000); - return intr; + return (nvkm_rd32(mc->subdev.device, 0x000600) & mask) == mask; } +const struct nvkm_mc_device_func +ga100_mc_device = { + .enabled = ga100_mc_device_enabled, + .enable = ga100_mc_device_enable, + .disable = ga100_mc_device_disable, +}; + static void ga100_mc_init(struct nvkm_mc *mc) { - nv50_mc_init(mc); - nvkm_wr32(mc->subdev.device, 0xb81210, 0xffffffff); + struct nvkm_device *device = mc->subdev.device; + + nvkm_wr32(device, 0x000200, 0xffffffff); + nvkm_wr32(device, 0x000600, 0xffffffff); } static const struct nvkm_mc_func ga100_mc = { .init = ga100_mc_init, - .intr = gp100_mc_intr, - .intr_unarm = ga100_mc_intr_unarm, - .intr_rearm = ga100_mc_intr_rearm, - .intr_mask = ga100_mc_intr_mask, - .intr_stat = ga100_mc_intr_stat, - .reset = gk104_mc_reset, + .device = &ga100_mc_device, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c index 3a589c6f7fad..ab1eaa37123a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c @@ -36,64 +36,29 @@ gf100_mc_reset[] = { {} }; -static const struct nvkm_mc_map -gf100_mc_intr[] = { - { 0x04000000, NVKM_ENGINE_DISP }, - { 0x00020000, NVKM_ENGINE_MSPDEC }, - { 0x00008000, NVKM_ENGINE_MSVLD }, - { 0x00001000, NVKM_ENGINE_GR }, - { 0x00000100, NVKM_ENGINE_FIFO }, - { 0x00000040, NVKM_ENGINE_CE, 1 }, - { 0x00000020, NVKM_ENGINE_CE, 0 }, - { 0x00000001, NVKM_ENGINE_MSPPP }, - { 0x40000000, NVKM_SUBDEV_PRIVRING }, - { 0x10000000, NVKM_SUBDEV_BUS }, - { 0x08000000, NVKM_SUBDEV_FB }, - { 0x02000000, NVKM_SUBDEV_LTC }, - { 0x01000000, NVKM_SUBDEV_PMU }, - { 0x00200000, NVKM_SUBDEV_GPIO }, - { 0x00200000, NVKM_SUBDEV_I2C }, - { 0x00100000, NVKM_SUBDEV_TIMER }, - { 0x00040000, NVKM_SUBDEV_THERM }, - { 0x00002000, NVKM_SUBDEV_FB }, +static const struct nvkm_intr_data +gf100_mc_intrs[] = { + { NVKM_ENGINE_DISP , 0, 0, 0x04000000, true }, + { NVKM_ENGINE_MSPDEC , 0, 0, 0x00020000, true }, + { NVKM_ENGINE_MSVLD , 0, 0, 0x00008000, true }, + { NVKM_ENGINE_GR , 0, 0, 0x00001000 }, + { NVKM_ENGINE_FIFO , 0, 0, 0x00000100 }, + { NVKM_ENGINE_CE , 1, 0, 0x00000040, true }, + { NVKM_ENGINE_CE , 0, 0, 0x00000020, true }, + { NVKM_ENGINE_MSPPP , 0, 0, 0x00000001, true }, + { NVKM_SUBDEV_PRIVRING, 0, 0, 0x40000000, true }, + { NVKM_SUBDEV_BUS , 0, 0, 0x10000000, true }, + { NVKM_SUBDEV_FB , 0, 0, 0x08002000, true }, + { NVKM_SUBDEV_LTC , 0, 0, 0x02000000, true }, + { NVKM_SUBDEV_PMU , 0, 0, 0x01000000, true }, + { NVKM_SUBDEV_GPIO , 0, 0, 0x00200000, true }, + { NVKM_SUBDEV_I2C , 0, 0, 0x00200000, true }, + { NVKM_SUBDEV_TIMER , 0, 0, 0x00100000, true }, + { NVKM_SUBDEV_THERM , 0, 0, 0x00040000, true }, {}, }; void -gf100_mc_intr_unarm(struct nvkm_mc *mc) -{ - struct nvkm_device *device = mc->subdev.device; - nvkm_wr32(device, 0x000140, 0x00000000); - nvkm_wr32(device, 0x000144, 0x00000000); - nvkm_rd32(device, 0x000140); -} - -void -gf100_mc_intr_rearm(struct nvkm_mc *mc) -{ - struct nvkm_device *device = mc->subdev.device; - nvkm_wr32(device, 0x000140, 0x00000001); - nvkm_wr32(device, 0x000144, 0x00000001); -} - -u32 -gf100_mc_intr_stat(struct nvkm_mc *mc) -{ - struct nvkm_device *device = mc->subdev.device; - u32 intr0 = nvkm_rd32(device, 0x000100); - u32 intr1 = nvkm_rd32(device, 0x000104); - return intr0 | intr1; -} - -void -gf100_mc_intr_mask(struct nvkm_mc *mc, u32 mask, u32 stat) -{ - struct nvkm_device *device = mc->subdev.device; - nvkm_mask(device, 0x000640, mask, stat); - nvkm_mask(device, 0x000644, mask, stat); -} - -void gf100_mc_unk260(struct nvkm_mc *mc, u32 data) { nvkm_wr32(mc->subdev.device, 0x000260, data); @@ -102,12 +67,11 @@ gf100_mc_unk260(struct nvkm_mc *mc, u32 data) static const struct nvkm_mc_func gf100_mc = { .init = nv50_mc_init, - .intr = gf100_mc_intr, - .intr_unarm = gf100_mc_intr_unarm, - .intr_rearm = gf100_mc_intr_rearm, - .intr_mask = gf100_mc_intr_mask, - .intr_stat = gf100_mc_intr_stat, + .intr = >215_mc_intr, + .intrs = gf100_mc_intrs, + .intr_nonstall = true, .reset = gf100_mc_reset, + .device = &nv04_mc_device, .unk260 = gf100_mc_unk260, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk104.c index d9b9067fa93f..66829586a124 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk104.c @@ -30,32 +30,32 @@ gk104_mc_reset[] = { {} }; -const struct nvkm_mc_map -gk104_mc_intr[] = { - { 0x04000000, NVKM_ENGINE_DISP }, - { 0x00000100, NVKM_ENGINE_FIFO }, - { 0x40000000, NVKM_SUBDEV_PRIVRING }, - { 0x10000000, NVKM_SUBDEV_BUS }, - { 0x08000000, NVKM_SUBDEV_FB }, - { 0x02000000, NVKM_SUBDEV_LTC }, - { 0x01000000, NVKM_SUBDEV_PMU }, - { 0x00200000, NVKM_SUBDEV_GPIO }, - { 0x00200000, NVKM_SUBDEV_I2C }, - { 0x00100000, NVKM_SUBDEV_TIMER }, - { 0x00040000, NVKM_SUBDEV_THERM }, - { 0x00002000, NVKM_SUBDEV_FB }, +const struct nvkm_intr_data +gk104_mc_intrs[] = { + { NVKM_ENGINE_DISP , 0, 0, 0x04000000, true }, + { NVKM_ENGINE_FIFO , 0, 0, 0x00000100 }, + { NVKM_SUBDEV_PRIVRING, 0, 0, 0x40000000, true }, + { NVKM_SUBDEV_BUS , 0, 0, 0x10000000, true }, + { NVKM_SUBDEV_FB , 0, 0, 0x08002000, true }, + { NVKM_SUBDEV_LTC , 0, 0, 0x02000000, true }, + { NVKM_SUBDEV_PMU , 0, 0, 0x01000000, true }, + { NVKM_SUBDEV_GPIO , 0, 0, 0x00200000, true }, + { NVKM_SUBDEV_I2C , 0, 0, 0x00200000, true }, + { NVKM_SUBDEV_TIMER , 0, 0, 0x00100000, true }, + { NVKM_SUBDEV_THERM , 0, 0, 0x00040000, true }, + { NVKM_SUBDEV_TOP , 0, 0, 0x00001000 }, + { NVKM_SUBDEV_TOP , 0, 0, 0xffffefff, true }, {}, }; static const struct nvkm_mc_func gk104_mc = { .init = nv50_mc_init, - .intr = gk104_mc_intr, - .intr_unarm = gf100_mc_intr_unarm, - .intr_rearm = gf100_mc_intr_rearm, - .intr_mask = gf100_mc_intr_mask, - .intr_stat = gf100_mc_intr_stat, + .intr = >215_mc_intr, + .intrs = gk104_mc_intrs, + .intr_nonstall = true, .reset = gk104_mc_reset, + .device = &nv04_mc_device, .unk260 = gf100_mc_unk260, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c index 03590292749a..d98a6563a411 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c @@ -26,11 +26,10 @@ static const struct nvkm_mc_func gk20a_mc = { .init = nv50_mc_init, - .intr = gk104_mc_intr, - .intr_unarm = gf100_mc_intr_unarm, - .intr_rearm = gf100_mc_intr_rearm, - .intr_mask = gf100_mc_intr_mask, - .intr_stat = gf100_mc_intr_stat, + .intr = >215_mc_intr, + .intrs = gk104_mc_intrs, + .intr_nonstall = true, + .device = &nv04_mc_device, .reset = gk104_mc_reset, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gp100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gp100.c index 5fd1a0595c33..eb2ab03f4360 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gp100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gp100.c @@ -21,108 +21,82 @@ * * Authors: Ben Skeggs */ -#define gp100_mc(p) container_of((p), struct gp100_mc, base) #include "priv.h" -struct gp100_mc { - struct nvkm_mc base; - spinlock_t lock; - bool intr; - u32 mask; +const struct nvkm_intr_data +gp100_mc_intrs[] = { + { NVKM_ENGINE_DISP , 0, 0, 0x04000000, true }, + { NVKM_ENGINE_FIFO , 0, 0, 0x00000100 }, + { NVKM_SUBDEV_FAULT , 0, 0, 0x00000200, true }, + { NVKM_SUBDEV_PRIVRING, 0, 0, 0x40000000, true }, + { NVKM_SUBDEV_BUS , 0, 0, 0x10000000, true }, + { NVKM_SUBDEV_FB , 0, 0, 0x08002000, true }, + { NVKM_SUBDEV_LTC , 0, 0, 0x02000000, true }, + { NVKM_SUBDEV_PMU , 0, 0, 0x01000000, true }, + { NVKM_SUBDEV_GPIO , 0, 0, 0x00200000, true }, + { NVKM_SUBDEV_I2C , 0, 0, 0x00200000, true }, + { NVKM_SUBDEV_TIMER , 0, 0, 0x00100000, true }, + { NVKM_SUBDEV_THERM , 0, 0, 0x00040000, true }, + { NVKM_SUBDEV_TOP , 0, 0, 0x00009000 }, + { NVKM_SUBDEV_TOP , 0, 0, 0xffff6fff, true }, + {}, }; static void -gp100_mc_intr_update(struct gp100_mc *mc) +gp100_mc_intr_allow(struct nvkm_intr *intr, int leaf, u32 mask) { - struct nvkm_device *device = mc->base.subdev.device; - u32 mask = mc->intr ? mc->mask : 0, i; - for (i = 0; i < 2; i++) { - nvkm_wr32(device, 0x000180 + (i * 0x04), ~mask); - nvkm_wr32(device, 0x000160 + (i * 0x04), mask); - } + struct nvkm_mc *mc = container_of(intr, typeof(*mc), intr); + + nvkm_wr32(mc->subdev.device, 0x000160 + (leaf * 4), mask); } -void -gp100_mc_intr_unarm(struct nvkm_mc *base) +static void +gp100_mc_intr_block(struct nvkm_intr *intr, int leaf, u32 mask) { - struct gp100_mc *mc = gp100_mc(base); - unsigned long flags; - spin_lock_irqsave(&mc->lock, flags); - mc->intr = false; - gp100_mc_intr_update(mc); - spin_unlock_irqrestore(&mc->lock, flags); + struct nvkm_mc *mc = container_of(intr, typeof(*mc), intr); + + nvkm_wr32(mc->subdev.device, 0x000180 + (leaf * 4), mask); } -void -gp100_mc_intr_rearm(struct nvkm_mc *base) +static void +gp100_mc_intr_rearm(struct nvkm_intr *intr) { - struct gp100_mc *mc = gp100_mc(base); - unsigned long flags; - spin_lock_irqsave(&mc->lock, flags); - mc->intr = true; - gp100_mc_intr_update(mc); - spin_unlock_irqrestore(&mc->lock, flags); + int i; + + for (i = 0; i < intr->leaves; i++) + intr->func->allow(intr, i, intr->mask[i]); } -void -gp100_mc_intr_mask(struct nvkm_mc *base, u32 mask, u32 intr) +static void +gp100_mc_intr_unarm(struct nvkm_intr *intr) { - struct gp100_mc *mc = gp100_mc(base); - unsigned long flags; - spin_lock_irqsave(&mc->lock, flags); - mc->mask = (mc->mask & ~mask) | intr; - gp100_mc_intr_update(mc); - spin_unlock_irqrestore(&mc->lock, flags); + int i; + + for (i = 0; i < intr->leaves; i++) + intr->func->block(intr, i, 0xffffffff); } -const struct nvkm_mc_map -gp100_mc_intr[] = { - { 0x04000000, NVKM_ENGINE_DISP }, - { 0x00000100, NVKM_ENGINE_FIFO }, - { 0x00000200, NVKM_SUBDEV_FAULT }, - { 0x40000000, NVKM_SUBDEV_PRIVRING }, - { 0x10000000, NVKM_SUBDEV_BUS }, - { 0x08000000, NVKM_SUBDEV_FB }, - { 0x02000000, NVKM_SUBDEV_LTC }, - { 0x01000000, NVKM_SUBDEV_PMU }, - { 0x00200000, NVKM_SUBDEV_GPIO }, - { 0x00200000, NVKM_SUBDEV_I2C }, - { 0x00100000, NVKM_SUBDEV_TIMER }, - { 0x00040000, NVKM_SUBDEV_THERM }, - { 0x00002000, NVKM_SUBDEV_FB }, - {}, +const struct nvkm_intr_func +gp100_mc_intr = { + .pending = nv04_mc_intr_pending, + .unarm = gp100_mc_intr_unarm, + .rearm = gp100_mc_intr_rearm, + .block = gp100_mc_intr_block, + .allow = gp100_mc_intr_allow, }; static const struct nvkm_mc_func gp100_mc = { .init = nv50_mc_init, - .intr = gp100_mc_intr, - .intr_unarm = gp100_mc_intr_unarm, - .intr_rearm = gp100_mc_intr_rearm, - .intr_mask = gp100_mc_intr_mask, - .intr_stat = gf100_mc_intr_stat, + .intr = &gp100_mc_intr, + .intrs = gp100_mc_intrs, + .intr_nonstall = true, + .device = &nv04_mc_device, .reset = gk104_mc_reset, }; int -gp100_mc_new_(const struct nvkm_mc_func *func, struct nvkm_device *device, - enum nvkm_subdev_type type, int inst, struct nvkm_mc **pmc) -{ - struct gp100_mc *mc; - - if (!(mc = kzalloc(sizeof(*mc), GFP_KERNEL))) - return -ENOMEM; - nvkm_mc_ctor(func, device, type, inst, &mc->base); - *pmc = &mc->base; - - spin_lock_init(&mc->lock); - mc->intr = false; - mc->mask = 0x7fffffff; - return 0; -} - -int gp100_mc_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_mc **pmc) { - return gp100_mc_new_(&gp100_mc, device, type, inst, pmc); + return nvkm_mc_new_(&gp100_mc, device, type, inst, pmc); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gp10b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gp10b.c index dd581d030ced..9bed9c5ea5d3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gp10b.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gp10b.c @@ -34,16 +34,15 @@ gp10b_mc_init(struct nvkm_mc *mc) static const struct nvkm_mc_func gp10b_mc = { .init = gp10b_mc_init, - .intr = gp100_mc_intr, - .intr_unarm = gp100_mc_intr_unarm, - .intr_rearm = gp100_mc_intr_rearm, - .intr_mask = gp100_mc_intr_mask, - .intr_stat = gf100_mc_intr_stat, + .intr = &gp100_mc_intr, + .intrs = gp100_mc_intrs, + .intr_nonstall = true, + .device = &nv04_mc_device, .reset = gk104_mc_reset, }; int gp10b_mc_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_mc **pmc) { - return gp100_mc_new_(&gp10b_mc, device, type, inst, pmc); + return nvkm_mc_new_(&gp10b_mc, device, type, inst, pmc); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gt215.c index 1b4d43531dba..3d61836e42a3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gt215.c @@ -34,39 +34,56 @@ gt215_mc_reset[] = { {} }; -static const struct nvkm_mc_map -gt215_mc_intr[] = { - { 0x04000000, NVKM_ENGINE_DISP }, - { 0x00400000, NVKM_ENGINE_CE, 0 }, - { 0x00020000, NVKM_ENGINE_MSPDEC }, - { 0x00008000, NVKM_ENGINE_MSVLD }, - { 0x00001000, NVKM_ENGINE_GR }, - { 0x00000100, NVKM_ENGINE_FIFO }, - { 0x00000001, NVKM_ENGINE_MSPPP }, - { 0x00429101, NVKM_SUBDEV_FB }, - { 0x10000000, NVKM_SUBDEV_BUS }, - { 0x00200000, NVKM_SUBDEV_GPIO }, - { 0x00200000, NVKM_SUBDEV_I2C }, - { 0x00100000, NVKM_SUBDEV_TIMER }, - { 0x00080000, NVKM_SUBDEV_THERM }, - { 0x00040000, NVKM_SUBDEV_PMU }, +static const struct nvkm_intr_data +gt215_mc_intrs[] = { + { NVKM_ENGINE_DISP , 0, 0, 0x04000000, true }, + { NVKM_ENGINE_CE , 0, 0, 0x00400000, true }, + { NVKM_ENGINE_MSPDEC, 0, 0, 0x00020000, true }, + { NVKM_ENGINE_MSVLD , 0, 0, 0x00008000, true }, + { NVKM_ENGINE_GR , 0, 0, 0x00001000, true }, + { NVKM_ENGINE_FIFO , 0, 0, 0x00000100 }, + { NVKM_ENGINE_MSPPP , 0, 0, 0x00000001, true }, + { NVKM_SUBDEV_FB , 0, 0, 0x00429101, true }, + { NVKM_SUBDEV_BUS , 0, 0, 0x10000000, true }, + { NVKM_SUBDEV_GPIO , 0, 0, 0x00200000, true }, + { NVKM_SUBDEV_I2C , 0, 0, 0x00200000, true }, + { NVKM_SUBDEV_TIMER , 0, 0, 0x00100000, true }, + { NVKM_SUBDEV_THERM , 0, 0, 0x00080000, true }, + { NVKM_SUBDEV_PMU , 0, 0, 0x00040000, true }, {}, }; static void -gt215_mc_intr_mask(struct nvkm_mc *mc, u32 mask, u32 stat) +gt215_mc_intr_allow(struct nvkm_intr *intr, int leaf, u32 mask) +{ + struct nvkm_mc *mc = container_of(intr, typeof(*mc), intr); + + nvkm_mask(mc->subdev.device, 0x000640 + (leaf * 4), mask, mask); +} + +static void +gt215_mc_intr_block(struct nvkm_intr *intr, int leaf, u32 mask) { - nvkm_mask(mc->subdev.device, 0x000640, mask, stat); + struct nvkm_mc *mc = container_of(intr, typeof(*mc), intr); + + nvkm_mask(mc->subdev.device, 0x000640 + (leaf * 4), mask, 0); } +const struct nvkm_intr_func +gt215_mc_intr = { + .pending = nv04_mc_intr_pending, + .unarm = nv04_mc_intr_unarm, + .rearm = nv04_mc_intr_rearm, + .block = gt215_mc_intr_block, + .allow = gt215_mc_intr_allow, +}; + static const struct nvkm_mc_func gt215_mc = { .init = nv50_mc_init, - .intr = gt215_mc_intr, - .intr_unarm = nv04_mc_intr_unarm, - .intr_rearm = nv04_mc_intr_rearm, - .intr_mask = gt215_mc_intr_mask, - .intr_stat = nv04_mc_intr_stat, + .intr = &nv04_mc_intr, + .intrs = gt215_mc_intrs, + .device = &nv04_mc_device, .reset = gt215_mc_reset, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c index bc0d09bafa99..8482a5550e5f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c @@ -30,37 +30,89 @@ nv04_mc_reset[] = { {} }; -static const struct nvkm_mc_map -nv04_mc_intr[] = { - { 0x01010000, NVKM_ENGINE_DISP }, - { 0x00001000, NVKM_ENGINE_GR }, - { 0x00000100, NVKM_ENGINE_FIFO }, - { 0x10000000, NVKM_SUBDEV_BUS }, - { 0x00100000, NVKM_SUBDEV_TIMER }, +static void +nv04_mc_device_disable(struct nvkm_mc *mc, u32 mask) +{ + nvkm_mask(mc->subdev.device, 0x000200, mask, 0x00000000); +} + +static void +nv04_mc_device_enable(struct nvkm_mc *mc, u32 mask) +{ + struct nvkm_device *device = mc->subdev.device; + + nvkm_mask(device, 0x000200, mask, mask); + nvkm_rd32(device, 0x000200); +} + +static bool +nv04_mc_device_enabled(struct nvkm_mc *mc, u32 mask) +{ + return (nvkm_rd32(mc->subdev.device, 0x000200) & mask) == mask; +} + +const struct nvkm_mc_device_func +nv04_mc_device = { + .enabled = nv04_mc_device_enabled, + .enable = nv04_mc_device_enable, + .disable = nv04_mc_device_disable, +}; + +static const struct nvkm_intr_data +nv04_mc_intrs[] = { + { NVKM_ENGINE_DISP , 0, 0, 0x01010000, true }, + { NVKM_ENGINE_GR , 0, 0, 0x00001000, true }, + { NVKM_ENGINE_FIFO , 0, 0, 0x00000100 }, + { NVKM_SUBDEV_BUS , 0, 0, 0x10000000, true }, + { NVKM_SUBDEV_TIMER, 0, 0, 0x00100000, true }, {} }; void -nv04_mc_intr_unarm(struct nvkm_mc *mc) +nv04_mc_intr_rearm(struct nvkm_intr *intr) { - struct nvkm_device *device = mc->subdev.device; - nvkm_wr32(device, 0x000140, 0x00000000); - nvkm_rd32(device, 0x000140); + struct nvkm_mc *mc = container_of(intr, typeof(*mc), intr); + int leaf; + + for (leaf = 0; leaf < intr->leaves; leaf++) + nvkm_wr32(mc->subdev.device, 0x000140 + (leaf * 4), 0x00000001); } void -nv04_mc_intr_rearm(struct nvkm_mc *mc) +nv04_mc_intr_unarm(struct nvkm_intr *intr) { - struct nvkm_device *device = mc->subdev.device; - nvkm_wr32(device, 0x000140, 0x00000001); + struct nvkm_mc *mc = container_of(intr, typeof(*mc), intr); + int leaf; + + for (leaf = 0; leaf < intr->leaves; leaf++) + nvkm_wr32(mc->subdev.device, 0x000140 + (leaf * 4), 0x00000000); + + nvkm_rd32(mc->subdev.device, 0x000140); } -u32 -nv04_mc_intr_stat(struct nvkm_mc *mc) +bool +nv04_mc_intr_pending(struct nvkm_intr *intr) { - return nvkm_rd32(mc->subdev.device, 0x000100); + struct nvkm_mc *mc = container_of(intr, typeof(*mc), intr); + bool pending = false; + int leaf; + + for (leaf = 0; leaf < intr->leaves; leaf++) { + intr->stat[leaf] = nvkm_rd32(mc->subdev.device, 0x000100 + (leaf * 4)); + if (intr->stat[leaf]) + pending = true; + } + + return pending; } +const struct nvkm_intr_func +nv04_mc_intr = { + .pending = nv04_mc_intr_pending, + .unarm = nv04_mc_intr_unarm, + .rearm = nv04_mc_intr_rearm, +}; + void nv04_mc_init(struct nvkm_mc *mc) { @@ -72,10 +124,9 @@ nv04_mc_init(struct nvkm_mc *mc) static const struct nvkm_mc_func nv04_mc = { .init = nv04_mc_init, - .intr = nv04_mc_intr, - .intr_unarm = nv04_mc_intr_unarm, - .intr_rearm = nv04_mc_intr_rearm, - .intr_stat = nv04_mc_intr_stat, + .intr = &nv04_mc_intr, + .intrs = nv04_mc_intrs, + .device = &nv04_mc_device, .reset = nv04_mc_reset, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv11.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv11.c index ab59ca1ee068..6d6278f434a4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv11.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv11.c @@ -23,23 +23,22 @@ */ #include "priv.h" -static const struct nvkm_mc_map -nv11_mc_intr[] = { - { 0x03010000, NVKM_ENGINE_DISP }, - { 0x00001000, NVKM_ENGINE_GR }, - { 0x00000100, NVKM_ENGINE_FIFO }, - { 0x10000000, NVKM_SUBDEV_BUS }, - { 0x00100000, NVKM_SUBDEV_TIMER }, +static const struct nvkm_intr_data +nv11_mc_intrs[] = { + { NVKM_ENGINE_DISP , 0, 0, 0x03010000, true }, + { NVKM_ENGINE_GR , 0, 0, 0x00001000, true }, + { NVKM_ENGINE_FIFO , 0, 0, 0x00000100 }, + { NVKM_SUBDEV_BUS , 0, 0, 0x10000000, true }, + { NVKM_SUBDEV_TIMER, 0, 0, 0x00100000, true }, {} }; static const struct nvkm_mc_func nv11_mc = { .init = nv04_mc_init, - .intr = nv11_mc_intr, - .intr_unarm = nv04_mc_intr_unarm, - .intr_rearm = nv04_mc_intr_rearm, - .intr_stat = nv04_mc_intr_stat, + .intr = &nv04_mc_intr, + .intrs = nv11_mc_intrs, + .device = &nv04_mc_device, .reset = nv04_mc_reset, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv17.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv17.c index 03d756e26e57..dbad7c111ceb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv17.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv17.c @@ -31,24 +31,23 @@ nv17_mc_reset[] = { {} }; -const struct nvkm_mc_map -nv17_mc_intr[] = { - { 0x03010000, NVKM_ENGINE_DISP }, - { 0x00001000, NVKM_ENGINE_GR }, - { 0x00000100, NVKM_ENGINE_FIFO }, - { 0x00000001, NVKM_ENGINE_MPEG }, - { 0x10000000, NVKM_SUBDEV_BUS }, - { 0x00100000, NVKM_SUBDEV_TIMER }, +const struct nvkm_intr_data +nv17_mc_intrs[] = { + { NVKM_ENGINE_DISP , 0, 0, 0x03010000, true }, + { NVKM_ENGINE_GR , 0, 0, 0x00001000, true }, + { NVKM_ENGINE_FIFO , 0, 0, 0x00000100 }, + { NVKM_ENGINE_MPEG , 0, 0, 0x00000001, true }, + { NVKM_SUBDEV_BUS , 0, 0, 0x10000000, true }, + { NVKM_SUBDEV_TIMER, 0, 0, 0x00100000, true }, {} }; static const struct nvkm_mc_func nv17_mc = { .init = nv04_mc_init, - .intr = nv17_mc_intr, - .intr_unarm = nv04_mc_intr_unarm, - .intr_rearm = nv04_mc_intr_rearm, - .intr_stat = nv04_mc_intr_stat, + .intr = &nv04_mc_intr, + .intrs = nv17_mc_intrs, + .device = &nv04_mc_device, .reset = nv17_mc_reset, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c index 95f65766e8b0..649a9fcc0a2f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c @@ -40,10 +40,9 @@ nv44_mc_init(struct nvkm_mc *mc) static const struct nvkm_mc_func nv44_mc = { .init = nv44_mc_init, - .intr = nv17_mc_intr, - .intr_unarm = nv04_mc_intr_unarm, - .intr_rearm = nv04_mc_intr_rearm, - .intr_stat = nv04_mc_intr_stat, + .intr = &nv04_mc_intr, + .intrs = nv17_mc_intrs, + .device = &nv04_mc_device, .reset = nv17_mc_reset, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c index fce3613cdfa5..d41099d35690 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c @@ -23,17 +23,17 @@ */ #include "priv.h" -static const struct nvkm_mc_map -nv50_mc_intr[] = { - { 0x04000000, NVKM_ENGINE_DISP }, - { 0x00001000, NVKM_ENGINE_GR }, - { 0x00000100, NVKM_ENGINE_FIFO }, - { 0x00000001, NVKM_ENGINE_MPEG }, - { 0x00001101, NVKM_SUBDEV_FB }, - { 0x10000000, NVKM_SUBDEV_BUS }, - { 0x00200000, NVKM_SUBDEV_GPIO }, - { 0x00200000, NVKM_SUBDEV_I2C }, - { 0x00100000, NVKM_SUBDEV_TIMER }, +static const struct nvkm_intr_data +nv50_mc_intrs[] = { + { NVKM_ENGINE_DISP , 0, 0, 0x04000000, true }, + { NVKM_ENGINE_GR , 0, 0, 0x00001000, true }, + { NVKM_ENGINE_FIFO , 0, 0, 0x00000100 }, + { NVKM_ENGINE_MPEG , 0, 0, 0x00000001, true }, + { NVKM_SUBDEV_FB , 0, 0, 0x00001101, true }, + { NVKM_SUBDEV_BUS , 0, 0, 0x10000000, true }, + { NVKM_SUBDEV_GPIO , 0, 0, 0x00200000, true }, + { NVKM_SUBDEV_I2C , 0, 0, 0x00200000, true }, + { NVKM_SUBDEV_TIMER, 0, 0, 0x00100000, true }, {}, }; @@ -47,10 +47,9 @@ nv50_mc_init(struct nvkm_mc *mc) static const struct nvkm_mc_func nv50_mc = { .init = nv50_mc_init, - .intr = nv50_mc_intr, - .intr_unarm = nv04_mc_intr_unarm, - .intr_rearm = nv04_mc_intr_rearm, - .intr_stat = nv04_mc_intr_stat, + .intr = &nv04_mc_intr, + .intrs = nv50_mc_intrs, + .device = &nv04_mc_device, .reset = nv17_mc_reset, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h index c8bcabb98f99..7f38d54b4bc2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h @@ -4,8 +4,6 @@ #define nvkm_mc(p) container_of((p), struct nvkm_mc, subdev) #include <subdev/mc.h> -void nvkm_mc_ctor(const struct nvkm_mc_func *, struct nvkm_device *, enum nvkm_subdev_type, int, - struct nvkm_mc *); int nvkm_mc_new_(const struct nvkm_mc_func *, struct nvkm_device *, enum nvkm_subdev_type, int, struct nvkm_mc **); @@ -18,46 +16,44 @@ struct nvkm_mc_map { struct nvkm_mc_func { void (*init)(struct nvkm_mc *); - const struct nvkm_mc_map *intr; - /* disable reporting of interrupts to host */ - void (*intr_unarm)(struct nvkm_mc *); - /* enable reporting of interrupts to host */ - void (*intr_rearm)(struct nvkm_mc *); - /* (un)mask delivery of specific interrupts */ - void (*intr_mask)(struct nvkm_mc *, u32 mask, u32 stat); - /* retrieve pending interrupt mask (NV_PMC_INTR) */ - u32 (*intr_stat)(struct nvkm_mc *); + + const struct nvkm_intr_func *intr; + const struct nvkm_intr_data *intrs; + bool intr_nonstall; + + const struct nvkm_mc_device_func { + bool (*enabled)(struct nvkm_mc *, u32 mask); + void (*enable)(struct nvkm_mc *, u32 mask); + void (*disable)(struct nvkm_mc *, u32 mask); + } *device; + const struct nvkm_mc_map *reset; + void (*unk260)(struct nvkm_mc *, u32); }; void nv04_mc_init(struct nvkm_mc *); -void nv04_mc_intr_unarm(struct nvkm_mc *); -void nv04_mc_intr_rearm(struct nvkm_mc *); -u32 nv04_mc_intr_stat(struct nvkm_mc *); +extern const struct nvkm_intr_func nv04_mc_intr; +bool nv04_mc_intr_pending(struct nvkm_intr *); +void nv04_mc_intr_unarm(struct nvkm_intr *); +void nv04_mc_intr_rearm(struct nvkm_intr *); +extern const struct nvkm_mc_device_func nv04_mc_device; extern const struct nvkm_mc_map nv04_mc_reset[]; -extern const struct nvkm_mc_map nv17_mc_intr[]; +extern const struct nvkm_intr_data nv17_mc_intrs[]; extern const struct nvkm_mc_map nv17_mc_reset[]; void nv44_mc_init(struct nvkm_mc *); void nv50_mc_init(struct nvkm_mc *); -void gk104_mc_init(struct nvkm_mc *); -void gf100_mc_intr_unarm(struct nvkm_mc *); -void gf100_mc_intr_rearm(struct nvkm_mc *); -void gf100_mc_intr_mask(struct nvkm_mc *, u32, u32); -u32 gf100_mc_intr_stat(struct nvkm_mc *); +extern const struct nvkm_intr_func gt215_mc_intr; void gf100_mc_unk260(struct nvkm_mc *, u32); -void gp100_mc_intr_unarm(struct nvkm_mc *); -void gp100_mc_intr_rearm(struct nvkm_mc *); -void gp100_mc_intr_mask(struct nvkm_mc *, u32, u32); -int gp100_mc_new_(const struct nvkm_mc_func *, struct nvkm_device *, enum nvkm_subdev_type, int, - struct nvkm_mc **); -extern const struct nvkm_mc_map gk104_mc_intr[]; +void gk104_mc_init(struct nvkm_mc *); +extern const struct nvkm_intr_data gk104_mc_intrs[]; extern const struct nvkm_mc_map gk104_mc_reset[]; -extern const struct nvkm_mc_map gp100_mc_intr[]; +extern const struct nvkm_intr_func gp100_mc_intr; +extern const struct nvkm_intr_data gp100_mc_intrs[]; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/tu102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/tu102.c deleted file mode 100644 index a96084b34a78..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/tu102.c +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright 2018 Red Hat Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ -#define tu102_mc(p) container_of((p), struct tu102_mc, base) -#include "priv.h" - -struct tu102_mc { - struct nvkm_mc base; - spinlock_t lock; - bool intr; - u32 mask; -}; - -static void -tu102_mc_intr_update(struct tu102_mc *mc) -{ - struct nvkm_device *device = mc->base.subdev.device; - u32 mask = mc->intr ? mc->mask : 0, i; - - for (i = 0; i < 2; i++) { - nvkm_wr32(device, 0x000180 + (i * 0x04), ~mask); - nvkm_wr32(device, 0x000160 + (i * 0x04), mask); - } - - if (mask & 0x00000200) - nvkm_wr32(device, 0xb81608, 0x6); - else - nvkm_wr32(device, 0xb81610, 0x6); -} - -static void -tu102_mc_intr_unarm(struct nvkm_mc *base) -{ - struct tu102_mc *mc = tu102_mc(base); - unsigned long flags; - - spin_lock_irqsave(&mc->lock, flags); - mc->intr = false; - tu102_mc_intr_update(mc); - spin_unlock_irqrestore(&mc->lock, flags); -} - -static void -tu102_mc_intr_rearm(struct nvkm_mc *base) -{ - struct tu102_mc *mc = tu102_mc(base); - unsigned long flags; - - spin_lock_irqsave(&mc->lock, flags); - mc->intr = true; - tu102_mc_intr_update(mc); - spin_unlock_irqrestore(&mc->lock, flags); -} - -static void -tu102_mc_intr_mask(struct nvkm_mc *base, u32 mask, u32 intr) -{ - struct tu102_mc *mc = tu102_mc(base); - unsigned long flags; - - spin_lock_irqsave(&mc->lock, flags); - mc->mask = (mc->mask & ~mask) | intr; - tu102_mc_intr_update(mc); - spin_unlock_irqrestore(&mc->lock, flags); -} - -static u32 -tu102_mc_intr_stat(struct nvkm_mc *mc) -{ - struct nvkm_device *device = mc->subdev.device; - u32 intr0 = nvkm_rd32(device, 0x000100); - u32 intr1 = nvkm_rd32(device, 0x000104); - u32 intr_top = nvkm_rd32(device, 0xb81600); - - /* Turing and above route the MMU fault interrupts via a different - * interrupt tree with different control registers. For the moment remap - * them back to the old PMC vector. - */ - if (intr_top & 0x00000006) - intr0 |= 0x00000200; - - return intr0 | intr1; -} - - -static const struct nvkm_mc_func -tu102_mc = { - .init = nv50_mc_init, - .intr = gp100_mc_intr, - .intr_unarm = tu102_mc_intr_unarm, - .intr_rearm = tu102_mc_intr_rearm, - .intr_mask = tu102_mc_intr_mask, - .intr_stat = tu102_mc_intr_stat, - .reset = gk104_mc_reset, -}; - -static int -tu102_mc_new_(const struct nvkm_mc_func *func, struct nvkm_device *device, - enum nvkm_subdev_type type, int inst, struct nvkm_mc **pmc) -{ - struct tu102_mc *mc; - - if (!(mc = kzalloc(sizeof(*mc), GFP_KERNEL))) - return -ENOMEM; - nvkm_mc_ctor(func, device, type, inst, &mc->base); - *pmc = &mc->base; - - spin_lock_init(&mc->lock); - mc->intr = false; - mc->mask = 0x7fffffff; - return 0; -} - -int -tu102_mc_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_mc **pmc) -{ - return tu102_mc_new_(&tu102_mc, device, type, inst, pmc); -} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/uvmm.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/uvmm.c index 186b4e63e559..524cd3c0e3fe 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/uvmm.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/uvmm.c @@ -39,7 +39,7 @@ nvkm_uvmm_search(struct nvkm_client *client, u64 handle) if (IS_ERR(object)) return (void *)object; - return nvkm_uvmm(object)->vmm; + return nvkm_vmm_ref(nvkm_uvmm(object)->vmm); } static int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c index a7d42ea8ba28..5a0de45d36ce 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c @@ -26,7 +26,15 @@ #include <core/option.h> #include <core/pci.h> -#include <subdev/mc.h> + +void +nvkm_pci_msi_rearm(struct nvkm_device *device) +{ + struct nvkm_pci *pci = device->pci; + + if (pci && pci->msi) + pci->func->msi_rearm(pci); +} u32 nvkm_pci_rd32(struct nvkm_pci *pci, u16 addr) @@ -65,24 +73,6 @@ nvkm_pci_rom_shadow(struct nvkm_pci *pci, bool shadow) nvkm_pci_wr32(pci, 0x0050, data); } -static irqreturn_t -nvkm_pci_intr(int irq, void *arg) -{ - struct nvkm_pci *pci = arg; - struct nvkm_device *device = pci->subdev.device; - bool handled = false; - - if (pci->irq < 0) - return IRQ_HANDLED; - - nvkm_mc_intr_unarm(device); - if (pci->msi) - pci->func->msi_rearm(pci); - nvkm_mc_intr(device, &handled); - nvkm_mc_intr_rearm(device); - return handled ? IRQ_HANDLED : IRQ_NONE; -} - static int nvkm_pci_fini(struct nvkm_subdev *subdev, bool suspend) { @@ -107,7 +97,6 @@ static int nvkm_pci_oneinit(struct nvkm_subdev *subdev) { struct nvkm_pci *pci = nvkm_pci(subdev); - struct pci_dev *pdev = pci->pdev; int ret; if (pci_is_pcie(pci->pdev)) { @@ -116,11 +105,6 @@ nvkm_pci_oneinit(struct nvkm_subdev *subdev) return ret; } - ret = request_irq(pdev->irq, nvkm_pci_intr, IRQF_SHARED, "nvkm", pci); - if (ret) - return ret; - - pci->irq = pdev->irq; return 0; } @@ -157,15 +141,6 @@ nvkm_pci_dtor(struct nvkm_subdev *subdev) nvkm_agp_dtor(pci); - if (pci->irq >= 0) { - /* freq_irq() will call the handler, we use pci->irq == -1 - * to signal that it's been torn down and should be a noop. - */ - int irq = pci->irq; - pci->irq = -1; - free_irq(irq, pci); - } - if (pci->msi) pci_disable_msi(pci->pdev); @@ -192,7 +167,6 @@ nvkm_pci_new_(const struct nvkm_pci_func *func, struct nvkm_device *device, nvkm_subdev_ctor(&nvkm_pci_func, device, type, inst, &pci->subdev); pci->func = func; pci->pdev = device->func->pci(device)->pdev; - pci->irq = -1; pci->pcie.speed = -1; pci->pcie.width = -1; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c index 455e95a89259..8f2f50ad4ded 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c @@ -81,43 +81,12 @@ nvkm_pmu_fini(struct nvkm_subdev *subdev, bool suspend) { struct nvkm_pmu *pmu = nvkm_pmu(subdev); + if (!subdev->use.enabled) + return 0; + if (pmu->func->fini) pmu->func->fini(pmu); - flush_work(&pmu->recv.work); - - reinit_completion(&pmu->wpr_ready); - - nvkm_falcon_cmdq_fini(pmu->lpq); - nvkm_falcon_cmdq_fini(pmu->hpq); - pmu->initmsg_received = false; - return 0; -} - -static void -nvkm_pmu_reset(struct nvkm_pmu *pmu) -{ - struct nvkm_device *device = pmu->subdev.device; - - if (!pmu->func->enabled(pmu)) - return; - - /* Reset. */ - if (pmu->func->reset) - pmu->func->reset(pmu); - - /* Wait for IMEM/DMEM scrubbing to be complete. */ - nvkm_msec(device, 2000, - if (!(nvkm_rd32(device, 0x10a10c) & 0x00000006)) - break; - ); -} - -static int -nvkm_pmu_preinit(struct nvkm_subdev *subdev) -{ - struct nvkm_pmu *pmu = nvkm_pmu(subdev); - nvkm_pmu_reset(pmu); return 0; } @@ -125,22 +94,10 @@ static int nvkm_pmu_init(struct nvkm_subdev *subdev) { struct nvkm_pmu *pmu = nvkm_pmu(subdev); - struct nvkm_device *device = pmu->subdev.device; if (!pmu->func->init) return 0; - if (pmu->func->enabled(pmu)) { - /* Inhibit interrupts, and wait for idle. */ - nvkm_wr32(device, 0x10a014, 0x0000ffff); - nvkm_msec(device, 2000, - if (!nvkm_rd32(device, 0x10a04c)) - break; - ); - - nvkm_pmu_reset(pmu); - } - return pmu->func->init(pmu); } @@ -160,7 +117,6 @@ nvkm_pmu_dtor(struct nvkm_subdev *subdev) static const struct nvkm_subdev_func nvkm_pmu = { .dtor = nvkm_pmu_dtor, - .preinit = nvkm_pmu_preinit, .init = nvkm_pmu_init, .fini = nvkm_pmu_fini, .intr = nvkm_pmu_intr, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c index a67a42e73f08..b5e52b35f5d0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c @@ -197,7 +197,6 @@ gk20a_dvfs_data= { static const struct nvkm_pmu_func gk20a_pmu = { .flcn = >215_pmu_flcn, - .enabled = gf100_pmu_enabled, .init = gk20a_pmu_init, .fini = gk20a_pmu_fini, .reset = gf100_pmu_reset, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm200.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm200.c index 40439e329aa9..7359991f94c2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm200.c @@ -24,30 +24,36 @@ #include "priv.h" static int -gm200_pmu_flcn_reset(struct nvkm_falcon *falcon) +gm200_pmu_flcn_bind_stat(struct nvkm_falcon *falcon, bool intr) { - struct nvkm_pmu *pmu = container_of(falcon, typeof(*pmu), falcon); + nvkm_falcon_wr32(falcon, 0x200, 0x0000030e); + return (nvkm_falcon_rd32(falcon, 0x20c) & 0x00007000) >> 12; +} - nvkm_falcon_wr32(falcon, 0x014, 0x0000ffff); - pmu->func->reset(pmu); - return nvkm_falcon_enable(falcon); +void +gm200_pmu_flcn_bind_inst(struct nvkm_falcon *falcon, int target, u64 addr) +{ + nvkm_falcon_wr32(falcon, 0xe00, 4); /* DMAIDX_UCODE */ + nvkm_falcon_wr32(falcon, 0xe04, 0); /* DMAIDX_VIRT */ + nvkm_falcon_wr32(falcon, 0xe08, 4); /* DMAIDX_PHYS_VID */ + nvkm_falcon_wr32(falcon, 0xe0c, 5); /* DMAIDX_PHYS_SYS_COH */ + nvkm_falcon_wr32(falcon, 0xe10, 6); /* DMAIDX_PHYS_SYS_NCOH */ + nvkm_falcon_mask(falcon, 0x090, 0x00010000, 0x00010000); + nvkm_falcon_wr32(falcon, 0x480, (1 << 30) | (target << 28) | (addr >> 12)); } const struct nvkm_falcon_func gm200_pmu_flcn = { + .disable = gm200_flcn_disable, + .enable = gm200_flcn_enable, + .reset_pmc = true, + .reset_wait_mem_scrubbing = gm200_flcn_reset_wait_mem_scrubbing, .debug = 0xc08, - .fbif = 0xe00, - .load_imem = nvkm_falcon_v1_load_imem, - .load_dmem = nvkm_falcon_v1_load_dmem, - .read_dmem = nvkm_falcon_v1_read_dmem, - .bind_context = nvkm_falcon_v1_bind_context, - .wait_for_halt = nvkm_falcon_v1_wait_for_halt, - .clear_interrupt = nvkm_falcon_v1_clear_interrupt, - .set_start_addr = nvkm_falcon_v1_set_start_addr, + .bind_inst = gm200_pmu_flcn_bind_inst, + .bind_stat = gm200_pmu_flcn_bind_stat, + .imem_pio = &gm200_flcn_imem_pio, + .dmem_pio = &gm200_flcn_dmem_pio, .start = nvkm_falcon_v1_start, - .enable = nvkm_falcon_v1_enable, - .disable = nvkm_falcon_v1_disable, - .reset = gm200_pmu_flcn_reset, .cmdq = { 0x4a0, 0x4b0, 4 }, .msgq = { 0x4c8, 0x4cc, 0 }, }; @@ -55,11 +61,9 @@ gm200_pmu_flcn = { static const struct nvkm_pmu_func gm200_pmu = { .flcn = &gm200_pmu_flcn, - .enabled = gf100_pmu_enabled, .reset = gf100_pmu_reset, }; - int gm200_pmu_nofw(struct nvkm_pmu *pmu, int ver, const struct nvkm_pmu_fwif *fwif) { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm20b.c index 612310d5d481..a72403777329 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm20b.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm20b.c @@ -62,16 +62,6 @@ gm20b_pmu_acr_bootstrap_falcon(struct nvkm_falcon *falcon, return ret; } -int -gm20b_pmu_acr_boot(struct nvkm_falcon *falcon) -{ - struct nv_pmu_args args = { .secure_mode = true }; - const u32 addr_args = falcon->data.limit - sizeof(struct nv_pmu_args); - nvkm_falcon_load_dmem(falcon, &args, addr_args, sizeof(args), 0); - nvkm_falcon_start(falcon); - return 0; -} - void gm20b_pmu_acr_bld_patch(struct nvkm_acr *acr, u32 bld, s64 adjust) { @@ -125,7 +115,6 @@ gm20b_pmu_acr = { .bld_size = sizeof(struct loader_config), .bld_write = gm20b_pmu_acr_bld_write, .bld_patch = gm20b_pmu_acr_bld_patch, - .boot = gm20b_pmu_acr_boot, .bootstrap_falcons = BIT_ULL(NVKM_ACR_LSF_PMU) | BIT_ULL(NVKM_ACR_LSF_FECS) | BIT_ULL(NVKM_ACR_LSF_GPCCS), @@ -166,7 +155,7 @@ gm20b_pmu_acr_init_wpr(struct nvkm_pmu *pmu) gm20b_pmu_acr_init_wpr_callback, pmu, 0); } -int +static int gm20b_pmu_initmsg(struct nvkm_pmu *pmu) { struct nv_pmu_init_msg msg; @@ -192,14 +181,13 @@ gm20b_pmu_initmsg(struct nvkm_pmu *pmu) return gm20b_pmu_acr_init_wpr(pmu); } -void +static void gm20b_pmu_recv(struct nvkm_pmu *pmu) { if (!pmu->initmsg_received) { int ret = pmu->func->initmsg(pmu); if (ret) { - nvkm_error(&pmu->subdev, - "error parsing init message: %d\n", ret); + nvkm_error(&pmu->subdev, "error parsing init message: %d\n", ret); return; } @@ -209,10 +197,44 @@ gm20b_pmu_recv(struct nvkm_pmu *pmu) nvkm_falcon_msgq_recv(pmu->msgq); } -static const struct nvkm_pmu_func +static void +gm20b_pmu_fini(struct nvkm_pmu *pmu) +{ + /*TODO: shutdown RTOS. */ + + flush_work(&pmu->recv.work); + nvkm_falcon_cmdq_fini(pmu->lpq); + nvkm_falcon_cmdq_fini(pmu->hpq); + + reinit_completion(&pmu->wpr_ready); + + nvkm_falcon_put(&pmu->falcon, &pmu->subdev); +} + +static int +gm20b_pmu_init(struct nvkm_pmu *pmu) +{ + struct nvkm_falcon *falcon = &pmu->falcon; + struct nv_pmu_args args = { .secure_mode = true }; + u32 addr_args = falcon->data.limit - sizeof(args); + int ret; + + ret = nvkm_falcon_get(&pmu->falcon, &pmu->subdev); + if (ret) + return ret; + + pmu->initmsg_received = false; + + nvkm_falcon_load_dmem(falcon, &args, addr_args, sizeof(args), 0); + nvkm_falcon_start(falcon); + return 0; +} + +const struct nvkm_pmu_func gm20b_pmu = { .flcn = &gm200_pmu_flcn, - .enabled = gf100_pmu_enabled, + .init = gm20b_pmu_init, + .fini = gm20b_pmu_fini, .intr = gt215_pmu_intr, .recv = gm20b_pmu_recv, .initmsg = gm20b_pmu_initmsg, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp102.c index 1a6f9c3af5ec..cd3148360996 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp102.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp102.c @@ -23,25 +23,25 @@ */ #include "priv.h" -void -gp102_pmu_reset(struct nvkm_pmu *pmu) -{ - struct nvkm_device *device = pmu->subdev.device; - nvkm_mask(device, 0x10a3c0, 0x00000001, 0x00000001); - nvkm_mask(device, 0x10a3c0, 0x00000001, 0x00000000); -} - -static bool -gp102_pmu_enabled(struct nvkm_pmu *pmu) -{ - return !(nvkm_rd32(pmu->subdev.device, 0x10a3c0) & 0x00000001); -} +static const struct nvkm_falcon_func +gp102_pmu_flcn = { + .disable = gm200_flcn_disable, + .enable = gm200_flcn_enable, + .reset_eng = gp102_flcn_reset_eng, + .reset_wait_mem_scrubbing = gm200_flcn_reset_wait_mem_scrubbing, + .debug = 0xc08, + .bind_inst = gm200_pmu_flcn_bind_inst, + .bind_stat = gm200_flcn_bind_stat, + .imem_pio = &gm200_flcn_imem_pio, + .dmem_pio = &gm200_flcn_dmem_pio, + .start = nvkm_falcon_v1_start, + .cmdq = { 0x4a0, 0x4b0, 4 }, + .msgq = { 0x4c8, 0x4cc, 0 }, +}; static const struct nvkm_pmu_func gp102_pmu = { - .flcn = &gm200_pmu_flcn, - .enabled = gp102_pmu_enabled, - .reset = gp102_pmu_reset, + .flcn = &gp102_pmu_flcn, }; static const struct nvkm_pmu_fwif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp10b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp10b.c index 94cfb1791af6..a6f410ba60bc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp10b.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp10b.c @@ -68,7 +68,6 @@ gp10b_pmu_acr = { .bld_size = sizeof(struct loader_config), .bld_write = gm20b_pmu_acr_bld_write, .bld_patch = gm20b_pmu_acr_bld_patch, - .boot = gm20b_pmu_acr_boot, .bootstrap_falcons = BIT_ULL(NVKM_ACR_LSF_PMU) | BIT_ULL(NVKM_ACR_LSF_FECS) | BIT_ULL(NVKM_ACR_LSF_GPCCS), @@ -76,16 +75,6 @@ gp10b_pmu_acr = { .bootstrap_multiple_falcons = gp10b_pmu_acr_bootstrap_multiple_falcons, }; -static const struct nvkm_pmu_func -gp10b_pmu = { - .flcn = &gm200_pmu_flcn, - .enabled = gf100_pmu_enabled, - .intr = gt215_pmu_intr, - .recv = gm20b_pmu_recv, - .initmsg = gm20b_pmu_initmsg, - .reset = gp102_pmu_reset, -}; - #if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC) MODULE_FIRMWARE("nvidia/gp10b/pmu/desc.bin"); MODULE_FIRMWARE("nvidia/gp10b/pmu/image.bin"); @@ -94,8 +83,8 @@ MODULE_FIRMWARE("nvidia/gp10b/pmu/sig.bin"); static const struct nvkm_pmu_fwif gp10b_pmu_fwif[] = { - { 0, gm20b_pmu_load, &gp10b_pmu, &gp10b_pmu_acr }, - { -1, gm200_pmu_nofw, &gp10b_pmu }, + { 0, gm20b_pmu_load, &gm20b_pmu, &gp10b_pmu_acr }, + { -1, gm200_pmu_nofw, &gm20b_pmu }, {} }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c index b0407b86bc10..32cee21ed858 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c @@ -178,12 +178,14 @@ void gt215_pmu_fini(struct nvkm_pmu *pmu) { nvkm_wr32(pmu->subdev.device, 0x10a014, 0x00000060); + flush_work(&pmu->recv.work); } static void gt215_pmu_reset(struct nvkm_pmu *pmu) { struct nvkm_device *device = pmu->subdev.device; + nvkm_mask(device, 0x022210, 0x00000001, 0x00000000); nvkm_mask(device, 0x022210, 0x00000001, 0x00000001); nvkm_rd32(device, 0x022210); @@ -201,6 +203,23 @@ gt215_pmu_init(struct nvkm_pmu *pmu) struct nvkm_device *device = pmu->subdev.device; int i; + /* Inhibit interrupts, and wait for idle. */ + if (pmu->func->enabled(pmu)) { + nvkm_wr32(device, 0x10a014, 0x0000ffff); + nvkm_msec(device, 2000, + if (!nvkm_rd32(device, 0x10a04c)) + break; + ); + } + + pmu->func->reset(pmu); + + /* Wait for IMEM/DMEM scrubbing to be complete. */ + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x10a10c) & 0x00000006)) + break; + ); + /* upload data segment */ nvkm_wr32(device, 0x10a1c0, 0x01000000); for (i = 0; i < pmu->func->data.size / 4; i++) @@ -243,20 +262,6 @@ gt215_pmu_init(struct nvkm_pmu *pmu) const struct nvkm_falcon_func gt215_pmu_flcn = { - .debug = 0xc08, - .fbif = 0xe00, - .load_imem = nvkm_falcon_v1_load_imem, - .load_dmem = nvkm_falcon_v1_load_dmem, - .read_dmem = nvkm_falcon_v1_read_dmem, - .bind_context = nvkm_falcon_v1_bind_context, - .wait_for_halt = nvkm_falcon_v1_wait_for_halt, - .clear_interrupt = nvkm_falcon_v1_clear_interrupt, - .set_start_addr = nvkm_falcon_v1_set_start_addr, - .start = nvkm_falcon_v1_start, - .enable = nvkm_falcon_v1_enable, - .disable = nvkm_falcon_v1_disable, - .cmdq = { 0x4a0, 0x4b0, 4 }, - .msgq = { 0x4c8, 0x4cc, 0 }, }; static const struct nvkm_pmu_func diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h index 21abf31f4442..2d0a8fa6f196 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h @@ -46,13 +46,12 @@ void gp102_pmu_reset(struct nvkm_pmu *pmu); void gk110_pmu_pgob(struct nvkm_pmu *, bool); extern const struct nvkm_falcon_func gm200_pmu_flcn; +void gm200_pmu_flcn_bind_inst(struct nvkm_falcon *, int, u64); +extern const struct nvkm_pmu_func gm20b_pmu; void gm20b_pmu_acr_bld_patch(struct nvkm_acr *, u32, s64); void gm20b_pmu_acr_bld_write(struct nvkm_acr *, u32, struct nvkm_acr_lsfw *); -int gm20b_pmu_acr_boot(struct nvkm_falcon *); int gm20b_pmu_acr_bootstrap_falcon(struct nvkm_falcon *, enum nvkm_acr_lsf_id); -void gm20b_pmu_recv(struct nvkm_pmu *); -int gm20b_pmu_initmsg(struct nvkm_pmu *); struct nvkm_pmu_fwif { int version; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/top/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/top/base.c index 28d0789f50fe..eb348dfc1d7a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/top/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/top/base.c @@ -117,11 +117,15 @@ nvkm_top_fault(struct nvkm_device *device, int fault) return NULL; } -static int -nvkm_top_oneinit(struct nvkm_subdev *subdev) +int +nvkm_top_parse(struct nvkm_device *device) { - struct nvkm_top *top = nvkm_top(subdev); - return top->func->oneinit(top); + struct nvkm_top *top = device->top; + + if (!top || !list_empty(&top->device)) + return 0; + + return top->func->parse(top); } static void * @@ -141,7 +145,6 @@ nvkm_top_dtor(struct nvkm_subdev *subdev) static const struct nvkm_subdev_func nvkm_top = { .dtor = nvkm_top_dtor, - .oneinit = nvkm_top_oneinit, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/top/ga100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/top/ga100.c index c982d834c8d9..84790cf52b90 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/top/ga100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/top/ga100.c @@ -22,7 +22,7 @@ #include "priv.h" static int -ga100_top_oneinit(struct nvkm_top *top) +ga100_top_parse(struct nvkm_top *top) { struct nvkm_subdev *subdev = &top->subdev; struct nvkm_device *device = subdev->device; @@ -97,7 +97,7 @@ ga100_top_oneinit(struct nvkm_top *top) static const struct nvkm_top_func ga100_top = { - .oneinit = ga100_top_oneinit, + .parse = ga100_top_parse, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/top/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/top/gk104.c index 4dcad97bd505..2bbba8244cbf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/top/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/top/gk104.c @@ -24,7 +24,7 @@ #include "priv.h" static int -gk104_top_oneinit(struct nvkm_top *top) +gk104_top_parse(struct nvkm_top *top) { struct nvkm_subdev *subdev = &top->subdev; struct nvkm_device *device = subdev->device; @@ -108,7 +108,7 @@ gk104_top_oneinit(struct nvkm_top *top) static const struct nvkm_top_func gk104_top = { - .oneinit = gk104_top_oneinit, + .parse = gk104_top_parse, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/top/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/top/priv.h index 8e103a836705..532be91d8fd9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/top/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/top/priv.h @@ -5,7 +5,7 @@ #include <subdev/top.h> struct nvkm_top_func { - int (*oneinit)(struct nvkm_top *); + int (*parse)(struct nvkm_top *); }; int nvkm_top_new_(const struct nvkm_top_func *, struct nvkm_device *, enum nvkm_subdev_type, int, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/Kbuild new file mode 100644 index 000000000000..23cd21b40a25 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/Kbuild @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: MIT +nvkm-y += nvkm/subdev/vfn/base.o +nvkm-y += nvkm/subdev/vfn/uvfn.o +nvkm-y += nvkm/subdev/vfn/gv100.o +nvkm-y += nvkm/subdev/vfn/tu102.o +nvkm-y += nvkm/subdev/vfn/ga100.o diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/base.c new file mode 100644 index 000000000000..62e81d551f44 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/base.c @@ -0,0 +1,60 @@ +/* + * Copyright 2021 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +#include "priv.h" + +static void * +nvkm_vfn_dtor(struct nvkm_subdev *subdev) +{ + return nvkm_vfn(subdev); +} + +static const struct nvkm_subdev_func +nvkm_vfn = { + .dtor = nvkm_vfn_dtor, +}; + +int +nvkm_vfn_new_(const struct nvkm_vfn_func *func, struct nvkm_device *device, + enum nvkm_subdev_type type, int inst, u32 addr, struct nvkm_vfn **pvfn) +{ + struct nvkm_vfn *vfn; + int ret; + + if (!(vfn = *pvfn = kzalloc(sizeof(*vfn), GFP_KERNEL))) + return -ENOMEM; + + nvkm_subdev_ctor(&nvkm_vfn, device, type, inst, &vfn->subdev); + vfn->func = func; + vfn->addr.priv = addr; + vfn->addr.user = vfn->addr.priv + func->user.addr; + + if (vfn->func->intr) { + ret = nvkm_intr_add(vfn->func->intr, vfn->func->intrs, + &vfn->subdev, 8, &vfn->intr); + if (ret) + return ret; + } + + vfn->user.ctor = nvkm_uvfn_new; + vfn->user.base = func->user.base; + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/ga100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/ga100.c new file mode 100644 index 000000000000..fd5c6931322d --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/ga100.c @@ -0,0 +1,47 @@ +/* + * Copyright 2021 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +#include "priv.h" + +#include <nvif/class.h> + +static const struct nvkm_intr_data +ga100_vfn_intrs[] = { + { NVKM_ENGINE_DISP , 0, 4, 0x04000000, true }, + { NVKM_SUBDEV_GPIO , 0, 4, 0x00200000, true }, + { NVKM_SUBDEV_I2C , 0, 4, 0x00200000, true }, + { NVKM_SUBDEV_PRIVRING, 0, 4, 0x40000000, true }, + {} +}; + +static const struct nvkm_vfn_func +ga100_vfn = { + .intr = &tu102_vfn_intr, + .intrs = ga100_vfn_intrs, + .user = { 0x030000, 0x010000, { -1, -1, AMPERE_USERMODE_A } }, +}; + +int +ga100_vfn_new(struct nvkm_device *device, + enum nvkm_subdev_type type, int inst, struct nvkm_vfn **pvfn) +{ + return nvkm_vfn_new_(&ga100_vfn, device, type, inst, 0xb80000, pvfn); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/gv100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/gv100.c new file mode 100644 index 000000000000..ddd39d714c4a --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/gv100.c @@ -0,0 +1,36 @@ +/* + * Copyright 2021 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +#include "priv.h" + +#include <nvif/class.h> + +static const struct nvkm_vfn_func +gv100_vfn = { + .user = { 0x810000, 0x010000, { -1, -1, VOLTA_USERMODE_A } }, +}; + +int +gv100_vfn_new(struct nvkm_device *device, + enum nvkm_subdev_type type, int inst, struct nvkm_vfn **pvfn) +{ + return nvkm_vfn_new_(&gv100_vfn, device, type, inst, 0, pvfn); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/priv.h new file mode 100644 index 000000000000..96d53c02041b --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/priv.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: MIT */ +#ifndef __NVKM_VFN_PRIV_H__ +#define __NVKM_VFN_PRIV_H__ +#define nvkm_vfn(p) container_of((p), struct nvkm_vfn, subdev) +#include <subdev/vfn.h> + +struct nvkm_vfn_func { + const struct nvkm_intr_func *intr; + const struct nvkm_intr_data *intrs; + + struct { + u32 addr; + u32 size; + const struct nvkm_sclass base; + } user; +}; + +int nvkm_vfn_new_(const struct nvkm_vfn_func *, struct nvkm_device *, enum nvkm_subdev_type, int, + u32 addr, struct nvkm_vfn **); + +extern const struct nvkm_intr_func tu102_vfn_intr; + +int nvkm_uvfn_new(struct nvkm_device *, const struct nvkm_oclass *, void *, u32, + struct nvkm_object **); +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/tu102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/tu102.c new file mode 100644 index 000000000000..3d063fb5e136 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/tu102.c @@ -0,0 +1,108 @@ +/* + * Copyright 2021 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +#include "priv.h" + +#include <nvif/class.h> + +static void +tu102_vfn_intr_reset(struct nvkm_intr *intr, int leaf, u32 mask) +{ + struct nvkm_vfn *vfn = container_of(intr, typeof(*vfn), intr); + + nvkm_wr32(vfn->subdev.device, vfn->addr.priv + 0x1000 + (leaf * 4), mask); +} + +static void +tu102_vfn_intr_allow(struct nvkm_intr *intr, int leaf, u32 mask) +{ + struct nvkm_vfn *vfn = container_of(intr, typeof(*vfn), intr); + + nvkm_wr32(vfn->subdev.device, vfn->addr.priv + 0x1200 + (leaf * 4), mask); +} + +static void +tu102_vfn_intr_block(struct nvkm_intr *intr, int leaf, u32 mask) +{ + struct nvkm_vfn *vfn = container_of(intr, typeof(*vfn), intr); + + nvkm_wr32(vfn->subdev.device, vfn->addr.priv + 0x1400 + (leaf * 4), mask); +} + +static void +tu102_vfn_intr_rearm(struct nvkm_intr *intr) +{ + struct nvkm_vfn *vfn = container_of(intr, typeof(*vfn), intr); + + nvkm_wr32(vfn->subdev.device, vfn->addr.priv + 0x1608, 0x0000000f); +} + +static void +tu102_vfn_intr_unarm(struct nvkm_intr *intr) +{ + struct nvkm_vfn *vfn = container_of(intr, typeof(*vfn), intr); + + nvkm_wr32(vfn->subdev.device, vfn->addr.priv + 0x1610, 0x0000000f); +} + +static bool +tu102_vfn_intr_pending(struct nvkm_intr *intr) +{ + struct nvkm_vfn *vfn = container_of(intr, typeof(*vfn), intr); + struct nvkm_device *device = vfn->subdev.device; + u32 intr_top = nvkm_rd32(device, vfn->addr.priv + 0x1600); + int pending = 0, leaf; + + for (leaf = 0; leaf < 8; leaf++) { + if (intr_top & BIT(leaf / 2)) { + intr->stat[leaf] = nvkm_rd32(device, vfn->addr.priv + 0x1000 + (leaf * 4)); + if (intr->stat[leaf]) + pending++; + } else { + intr->stat[leaf] = 0; + } + } + + return pending != 0; +} + +const struct nvkm_intr_func +tu102_vfn_intr = { + .pending = tu102_vfn_intr_pending, + .unarm = tu102_vfn_intr_unarm, + .rearm = tu102_vfn_intr_rearm, + .block = tu102_vfn_intr_block, + .allow = tu102_vfn_intr_allow, + .reset = tu102_vfn_intr_reset, +}; + +static const struct nvkm_vfn_func +tu102_vfn = { + .intr = &tu102_vfn_intr, + .user = { 0x030000, 0x010000, { -1, -1, TURING_USERMODE_A } }, +}; + +int +tu102_vfn_new(struct nvkm_device *device, + enum nvkm_subdev_type type, int inst, struct nvkm_vfn **pvfn) +{ + return nvkm_vfn_new_(&tu102_vfn, device, type, inst, 0xb80000, pvfn); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/uvfn.c b/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/uvfn.c new file mode 100644 index 000000000000..c5460a14c541 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/uvfn.c @@ -0,0 +1,67 @@ +/* + * Copyright 2021 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +#define nvkm_uvfn(p) container_of((p), struct nvkm_uvfn, object) +#include "priv.h" + +#include <core/object.h> + +struct nvkm_uvfn { + struct nvkm_object object; + struct nvkm_vfn *vfn; +}; + +static int +nvkm_uvfn_map(struct nvkm_object *object, void *argv, u32 argc, + enum nvkm_object_map *type, u64 *addr, u64 *size) +{ + struct nvkm_vfn *vfn = nvkm_uvfn(object)->vfn; + struct nvkm_device *device = vfn->subdev.device; + + *addr = device->func->resource_addr(device, 0) + vfn->addr.user; + *size = vfn->func->user.size; + *type = NVKM_OBJECT_MAP_IO; + return 0; +} + +static const struct nvkm_object_func +nvkm_uvfn = { + .map = nvkm_uvfn_map, +}; + +int +nvkm_uvfn_new(struct nvkm_device *device, const struct nvkm_oclass *oclass, + void *argv, u32 argc, struct nvkm_object **pobject) +{ + struct nvkm_uvfn *uvfn; + + if (argc != 0) + return -ENOSYS; + + if (!(uvfn = kzalloc(sizeof(*uvfn), GFP_KERNEL))) + return -ENOMEM; + + nvkm_object_ctor(&nvkm_uvfn, oclass, &uvfn->object); + uvfn->vfn = device->vfn; + + *pobject = &uvfn->object; + return 0; +} |