diff options
author | Dave Airlie <airlied@redhat.com> | 2022-11-09 10:48:44 +1000 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2022-11-09 11:18:56 +1000 |
commit | a143bc517bf31c4575191efbaac216a11ec016e0 (patch) | |
tree | e88d120c60d148c165551d17493cc3abef651019 | |
parent | 49e8e6343df688d68b12c2af50791ca37520f0b7 (diff) | |
parent | c4bdac754ca0bb21bad598b47dd8c2c86eee1cc1 (diff) | |
download | linux-a143bc517bf31c4575191efbaac216a11ec016e0.tar.gz |
Merge branch '00.06-gr-ampere' of https://gitlab.freedesktop.org/skeggsb/nouveau into drm-next
This is the pull request for a whole bunch of fixes and prep-work that
was done to support Ampere acceleration prior to GSP-RM being
available. It uses the ACR firmware released by NVIDIA in
linux-firmware, as we do on earlier GPUs. The work to support running
on top of GSP-RM also heavily depends on various pieces of this
series.
In addition to the new HW support, general stability of the driver
should be improved, especially around recovering HW from bugs that can
be generated by userspace driver components.
Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Ben Skeggs <bskeggs@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/CABDvA==s+nZD0n7CuRWLPE=Pj+02CN13r+ZQJxoHQ_EmR+o=XQ@mail.gmail.com
407 files changed, 15697 insertions, 13193 deletions
diff --git a/drivers/gpu/drm/nouveau/Kbuild b/drivers/gpu/drm/nouveau/Kbuild index 60586fb8275e..5e5617006da5 100644 --- a/drivers/gpu/drm/nouveau/Kbuild +++ b/drivers/gpu/drm/nouveau/Kbuild @@ -54,10 +54,6 @@ nouveau-y += nouveau_bios.o nouveau-y += nouveau_connector.o nouveau-y += nouveau_display.o nouveau-y += nouveau_dp.o -nouveau-y += nouveau_fbcon.o -nouveau-y += nv04_fbcon.o -nouveau-y += nv50_fbcon.o -nouveau-y += nvc0_fbcon.o include $(src)/dispnv04/Kbuild include $(src)/dispnv50/Kbuild diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c index ee92d576d277..0e0f117bc70b 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c +++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c @@ -23,6 +23,7 @@ * DEALINGS IN THE SOFTWARE. */ #include <drm/drm_crtc_helper.h> +#include <drm/drm_fb_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_plane_helper.h> #include <drm/drm_vblank.h> @@ -37,7 +38,6 @@ #include "nouveau_crtc.h" #include "hw.h" #include "nvreg.h" -#include "nouveau_fbcon.h" #include "disp.h" #include "nouveau_dma.h" @@ -761,7 +761,8 @@ static void nv_crtc_destroy(struct drm_crtc *crtc) nouveau_bo_unmap(nv_crtc->cursor.nvbo); nouveau_bo_unpin(nv_crtc->cursor.nvbo); nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo); - nvif_notify_dtor(&nv_crtc->vblank); + nvif_event_dtor(&nv_crtc->vblank); + nvif_head_dtor(&nv_crtc->head); kfree(nv_crtc); } @@ -914,14 +915,6 @@ nv04_crtc_mode_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, int x, int y, enum mode_set_atomic state) { - struct nouveau_drm *drm = nouveau_drm(crtc->dev); - struct drm_device *dev = drm->dev; - - if (state == ENTER_ATOMIC_MODE_SET) - nouveau_fbcon_accel_save_disable(dev); - else - nouveau_fbcon_accel_restore(dev); - return nv04_crtc_do_mode_set_base(crtc, fb, x, y, true); } @@ -1080,10 +1073,10 @@ nv04_finish_page_flip(struct nouveau_channel *chan, } int -nv04_flip_complete(struct nvif_notify *notify) +nv04_flip_complete(struct nvif_event *event, void *argv, u32 argc) { - struct nouveau_cli *cli = (void *)notify->object->client; - struct nouveau_drm *drm = cli->drm; + struct nv04_display *disp = container_of(event, typeof(*disp), flip); + struct nouveau_drm *drm = disp->drm; struct nouveau_channel *chan = drm->channel; struct nv04_page_flip_state state; @@ -1094,7 +1087,7 @@ nv04_flip_complete(struct nvif_notify *notify) state.bpp / 8); } - return NVIF_NOTIFY_KEEP; + return NVIF_EVENT_KEEP; } static int @@ -1279,13 +1272,13 @@ static const struct drm_plane_funcs nv04_primary_plane_funcs = { DRM_PLANE_NON_ATOMIC_FUNCS, }; -static int nv04_crtc_vblank_handler(struct nvif_notify *notify) +static int +nv04_crtc_vblank_handler(struct nvif_event *event, void *repv, u32 repc) { - struct nouveau_crtc *nv_crtc = - container_of(notify, struct nouveau_crtc, vblank); + struct nouveau_crtc *nv_crtc = container_of(event, struct nouveau_crtc, vblank); drm_crtc_handle_vblank(&nv_crtc->base); - return NVIF_NOTIFY_KEEP; + return NVIF_EVENT_KEEP; } int @@ -1341,14 +1334,10 @@ nv04_crtc_create(struct drm_device *dev, int crtc_num) nv04_cursor_init(nv_crtc); - ret = nvif_notify_ctor(&disp->disp.object, "kmsVbl", nv04_crtc_vblank_handler, - false, NV04_DISP_NTFY_VBLANK, - &(struct nvif_notify_head_req_v0) { - .head = nv_crtc->index, - }, - sizeof(struct nvif_notify_head_req_v0), - sizeof(struct nvif_notify_head_rep_v0), - &nv_crtc->vblank); + ret = nvif_head_ctor(&disp->disp, nv_crtc->base.name, nv_crtc->index, &nv_crtc->head); + if (ret) + return ret; - return ret; + return nvif_head_vblank_event_ctor(&nv_crtc->head, "kmsVbl", nv04_crtc_vblank_handler, + false, &nv_crtc->vblank); } diff --git a/drivers/gpu/drm/nouveau/dispnv04/disp.c b/drivers/gpu/drm/nouveau/dispnv04/disp.c index 99fee4d8cd31..e9ac3fb27ff7 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv04/disp.c @@ -61,7 +61,7 @@ nv04_display_fini(struct drm_device *dev, bool runtime, bool suspend) struct drm_crtc *crtc; /* Disable flip completion events. */ - nvif_notify_put(&disp->flip); + nvif_event_block(&disp->flip); /* Disable vblank interrupts. */ NVWriteCRTC(dev, 0, NV_PCRTC_INTR_EN_0, 0); @@ -121,7 +121,7 @@ nv04_display_init(struct drm_device *dev, bool resume, bool runtime) encoder->enc_save(&encoder->base.base); /* Enable flip completion events. */ - nvif_notify_get(&disp->flip); + nvif_event_allow(&disp->flip); if (!resume) return 0; @@ -202,7 +202,7 @@ nv04_display_destroy(struct drm_device *dev) nouveau_hw_save_vga_fonts(dev, 0); - nvif_notify_dtor(&disp->flip); + nvif_event_dtor(&disp->flip); nouveau_display(dev)->priv = NULL; vfree(disp); @@ -227,6 +227,8 @@ nv04_display_create(struct drm_device *dev) if (!disp) return -ENOMEM; + disp->drm = drm; + nvif_object_map(&drm->client.device.object, NULL, 0); nouveau_display(dev)->priv = disp; @@ -239,9 +241,10 @@ nv04_display_create(struct drm_device *dev) /* Request page flip completion event. */ if (drm->channel) { - nvif_notify_ctor(&drm->channel->nvsw, "kmsFlip", nv04_flip_complete, - false, NV04_NVSW_NTFY_UEVENT, - NULL, 0, 0, &disp->flip); + ret = nvif_event_ctor(&drm->channel->nvsw, "kmsFlip", 0, nv04_flip_complete, + true, NULL, 0, &disp->flip); + if (ret) + return ret; } nouveau_hw_save_vga_fonts(dev, 1); diff --git a/drivers/gpu/drm/nouveau/dispnv04/disp.h b/drivers/gpu/drm/nouveau/dispnv04/disp.h index f0a24126641a..11a6663758ec 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/disp.h +++ b/drivers/gpu/drm/nouveau/dispnv04/disp.h @@ -6,6 +6,8 @@ #include "nouveau_display.h" +#include <nvif/event.h> + struct nouveau_encoder; enum nv04_fp_display_regs { @@ -84,7 +86,8 @@ struct nv04_display { uint32_t saved_vga_font[4][16384]; uint32_t dac_users[4]; struct nouveau_bo *image[2]; - struct nvif_notify flip; + struct nvif_event flip; + struct nouveau_drm *drm; }; static inline struct nv04_display * @@ -179,5 +182,5 @@ nouveau_bios_run_init_table(struct drm_device *dev, u16 table, ); } -int nv04_flip_complete(struct nvif_notify *); +int nv04_flip_complete(struct nvif_event *, void *, u32); #endif diff --git a/drivers/gpu/drm/nouveau/dispnv50/crc.c b/drivers/gpu/drm/nouveau/dispnv50/crc.c index b834e8a9ae77..9c942fbd836d 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/crc.c +++ b/drivers/gpu/drm/nouveau/dispnv50/crc.c @@ -463,7 +463,7 @@ void nv50_crc_atomic_set(struct nv50_head *head, if (!outp) return; - func->set_src(head, outp->or, nv50_crc_source_type(outp, asyh->crc.src), + func->set_src(head, outp->outp.or.id, nv50_crc_source_type(outp, asyh->crc.src), &crc->ctx[crc->ctx_idx]); } diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index aa94f8e284dd..b7084c17f9c1 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -46,8 +46,8 @@ #include <nvif/class.h> #include <nvif/cl0002.h> -#include <nvif/cl5070.h> #include <nvif/event.h> +#include <nvif/if0012.h> #include <nvif/if0014.h> #include <nvif/timer.h> @@ -64,7 +64,6 @@ #include "nouveau_connector.h" #include "nouveau_encoder.h" #include "nouveau_fence.h" -#include "nouveau_fbcon.h" #include <subdev/bios/dp.h> @@ -317,52 +316,6 @@ nv50_outp_dump_caps(struct nouveau_drm *drm, outp->base.base.name, outp->caps.dp_interlace); } -static void -nv50_outp_release(struct nouveau_encoder *nv_encoder) -{ - struct nv50_disp *disp = nv50_disp(nv_encoder->base.base.dev); - struct { - struct nv50_disp_mthd_v1 base; - } args = { - .base.version = 1, - .base.method = NV50_DISP_MTHD_V1_RELEASE, - .base.hasht = nv_encoder->dcb->hasht, - .base.hashm = nv_encoder->dcb->hashm, - }; - - nvif_mthd(&disp->disp->object, 0, &args, sizeof(args)); - nv_encoder->or = -1; - nv_encoder->link = 0; -} - -static int -nv50_outp_acquire(struct nouveau_encoder *nv_encoder, bool hda) -{ - struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev); - struct nv50_disp *disp = nv50_disp(drm->dev); - struct { - struct nv50_disp_mthd_v1 base; - struct nv50_disp_acquire_v0 info; - } args = { - .base.version = 1, - .base.method = NV50_DISP_MTHD_V1_ACQUIRE, - .base.hasht = nv_encoder->dcb->hasht, - .base.hashm = nv_encoder->dcb->hashm, - .info.hda = hda, - }; - int ret; - - ret = nvif_mthd(&disp->disp->object, 0, &args, sizeof(args)); - if (ret) { - NV_ERROR(drm, "error acquiring output path: %d\n", ret); - return ret; - } - - nv_encoder->or = args.info.or; - nv_encoder->link = args.info.link; - return 0; -} - static int nv50_outp_atomic_check_view(struct drm_encoder *encoder, struct drm_crtc_state *crtc_state, @@ -489,9 +442,9 @@ nv50_dac_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_state *st struct nv50_core *core = nv50_disp(encoder->dev)->core; const u32 ctrl = NVDEF(NV507D, DAC_SET_CONTROL, OWNER, NONE); - core->func->dac->ctrl(core, nv_encoder->or, ctrl, NULL); + core->func->dac->ctrl(core, nv_encoder->outp.or.id, ctrl, NULL); nv_encoder->crtc = NULL; - nv50_outp_release(nv_encoder); + nvif_outp_release(&nv_encoder->outp); } static void @@ -516,9 +469,9 @@ nv50_dac_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *sta ctrl |= NVDEF(NV507D, DAC_SET_CONTROL, PROTOCOL, RGB_CRT); - nv50_outp_acquire(nv_encoder, false); + nvif_outp_acquire_rgb_crt(&nv_encoder->outp); - core->func->dac->ctrl(core, nv_encoder->or, ctrl, asyh); + core->func->dac->ctrl(core, nv_encoder->outp.or.id, ctrl, asyh); asyh->or.depth = 0; nv_encoder->crtc = &nv_crtc->base; @@ -634,7 +587,7 @@ nv50_audio_component_get_eld(struct device *kdev, int port, int dev_id, nv_connector = nouveau_connector(nv_encoder->audio.connector); nv_crtc = nouveau_crtc(nv_encoder->crtc); - if (!nv_crtc || nv_encoder->or != port || nv_crtc->index != dev_id) + if (!nv_crtc || nv_encoder->outp.or.id != port || nv_crtc->index != dev_id) continue; *enabled = nv_encoder->audio.enabled; @@ -718,33 +671,37 @@ nv50_audio_component_fini(struct nouveau_drm *drm) /****************************************************************************** * Audio *****************************************************************************/ +static bool +nv50_audio_supported(struct drm_encoder *encoder) +{ + struct nv50_disp *disp = nv50_disp(encoder->dev); + + if (disp->disp->object.oclass <= GT200_DISP || + disp->disp->object.oclass == GT206_DISP) + return false; + + return true; +} + static void nv50_audio_disable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc) { struct nouveau_drm *drm = nouveau_drm(encoder->dev); struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - struct nv50_disp *disp = nv50_disp(encoder->dev); - struct { - struct nv50_disp_mthd_v1 base; - struct nv50_disp_sor_hda_eld_v0 eld; - } args = { - .base.version = 1, - .base.method = NV50_DISP_MTHD_V1_SOR_HDA_ELD, - .base.hasht = nv_encoder->dcb->hasht, - .base.hashm = (0xf0ff & nv_encoder->dcb->hashm) | - (0x0100 << nv_crtc->index), - }; + struct nvif_outp *outp = &nv_encoder->outp; + + if (!nv50_audio_supported(encoder)) + return; mutex_lock(&drm->audio.lock); if (nv_encoder->audio.enabled) { nv_encoder->audio.enabled = false; nv_encoder->audio.connector = NULL; - nvif_mthd(&disp->disp->object, 0, &args, sizeof(args)); + nvif_outp_hda_eld(&nv_encoder->outp, nv_crtc->index, NULL, 0); } mutex_unlock(&drm->audio.lock); - nv50_audio_component_eld_notify(drm->audio.component, nv_encoder->or, - nv_crtc->index); + nv50_audio_component_eld_notify(drm->audio.component, outp->or.id, nv_crtc->index); } static void @@ -754,159 +711,105 @@ nv50_audio_enable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc, { struct nouveau_drm *drm = nouveau_drm(encoder->dev); struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - struct nv50_disp *disp = nv50_disp(encoder->dev); - struct __packed { - struct { - struct nv50_disp_mthd_v1 mthd; - struct nv50_disp_sor_hda_eld_v0 eld; - } base; - u8 data[sizeof(nv_connector->base.eld)]; - } args = { - .base.mthd.version = 1, - .base.mthd.method = NV50_DISP_MTHD_V1_SOR_HDA_ELD, - .base.mthd.hasht = nv_encoder->dcb->hasht, - .base.mthd.hashm = (0xf0ff & nv_encoder->dcb->hashm) | - (0x0100 << nv_crtc->index), - }; - - if (!drm_detect_monitor_audio(nv_connector->edid)) + struct nvif_outp *outp = &nv_encoder->outp; + + if (!nv50_audio_supported(encoder) || !drm_detect_monitor_audio(nv_connector->edid)) return; mutex_lock(&drm->audio.lock); - memcpy(args.data, nv_connector->base.eld, sizeof(args.data)); - - nvif_mthd(&disp->disp->object, 0, &args, - sizeof(args.base) + drm_eld_size(args.data)); + nvif_outp_hda_eld(&nv_encoder->outp, nv_crtc->index, nv_connector->base.eld, + drm_eld_size(nv_connector->base.eld)); nv_encoder->audio.enabled = true; nv_encoder->audio.connector = &nv_connector->base; mutex_unlock(&drm->audio.lock); - nv50_audio_component_eld_notify(drm->audio.component, nv_encoder->or, - nv_crtc->index); + nv50_audio_component_eld_notify(drm->audio.component, outp->or.id, nv_crtc->index); } /****************************************************************************** * HDMI *****************************************************************************/ static void -nv50_hdmi_disable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc) -{ - struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - struct nv50_disp *disp = nv50_disp(encoder->dev); - struct { - struct nv50_disp_mthd_v1 base; - struct nv50_disp_sor_hdmi_pwr_v0 pwr; - } args = { - .base.version = 1, - .base.method = NV50_DISP_MTHD_V1_SOR_HDMI_PWR, - .base.hasht = nv_encoder->dcb->hasht, - .base.hashm = (0xf0ff & nv_encoder->dcb->hashm) | - (0x0100 << nv_crtc->index), - }; - - nvif_mthd(&disp->disp->object, 0, &args, sizeof(args)); -} - -static void nv50_hdmi_enable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc, struct nouveau_connector *nv_connector, struct drm_atomic_state *state, - struct drm_display_mode *mode) + struct drm_display_mode *mode, bool hda) { struct nouveau_drm *drm = nouveau_drm(encoder->dev); struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - struct nv50_disp *disp = nv50_disp(encoder->dev); - struct { - struct nv50_disp_mthd_v1 base; - struct nv50_disp_sor_hdmi_pwr_v0 pwr; - u8 infoframes[2 * 17]; /* two frames, up to 17 bytes each */ - } args = { - .base.version = 1, - .base.method = NV50_DISP_MTHD_V1_SOR_HDMI_PWR, - .base.hasht = nv_encoder->dcb->hasht, - .base.hashm = (0xf0ff & nv_encoder->dcb->hashm) | - (0x0100 << nv_crtc->index), - .pwr.state = 1, - .pwr.rekey = 56, /* binary driver, and tegra, constant */ - }; - struct drm_hdmi_info *hdmi; + struct drm_hdmi_info *hdmi = &nv_connector->base.display_info.hdmi; + union hdmi_infoframe infoframe; + const u8 rekey = 56; /* binary driver, and tegra, constant */ + u8 config, scdc = 0; u32 max_ac_packet; - union hdmi_infoframe avi_frame; - union hdmi_infoframe vendor_frame; - bool high_tmds_clock_ratio = false, scrambling = false; - u8 config; - int ret; - int size; - - if (!drm_detect_hdmi_monitor(nv_connector->edid)) - return; - - hdmi = &nv_connector->base.display_info.hdmi; - - ret = drm_hdmi_avi_infoframe_from_display_mode(&avi_frame.avi, - &nv_connector->base, mode); - if (!ret) { - drm_hdmi_avi_infoframe_quant_range(&avi_frame.avi, - &nv_connector->base, mode, - HDMI_QUANTIZATION_RANGE_FULL); - /* We have an AVI InfoFrame, populate it to the display */ - args.pwr.avi_infoframe_length - = hdmi_infoframe_pack(&avi_frame, args.infoframes, 17); - } - - ret = drm_hdmi_vendor_infoframe_from_display_mode(&vendor_frame.vendor.hdmi, - &nv_connector->base, mode); - if (!ret) { - /* We have a Vendor InfoFrame, populate it to the display */ - args.pwr.vendor_infoframe_length - = hdmi_infoframe_pack(&vendor_frame, - args.infoframes - + args.pwr.avi_infoframe_length, - 17); - } + struct { + struct nvif_outp_infoframe_v0 infoframe; + u8 data[17]; + } args; + int ret, size; max_ac_packet = mode->htotal - mode->hdisplay; - max_ac_packet -= args.pwr.rekey; + max_ac_packet -= rekey; max_ac_packet -= 18; /* constant from tegra */ - args.pwr.max_ac_packet = max_ac_packet / 32; + max_ac_packet /= 32; if (hdmi->scdc.scrambling.supported) { - high_tmds_clock_ratio = mode->clock > 340000; - scrambling = high_tmds_clock_ratio || - hdmi->scdc.scrambling.low_rates; - } + const bool high_tmds_clock_ratio = mode->clock > 340000; - args.pwr.scdc = - NV50_DISP_SOR_HDMI_PWR_V0_SCDC_SCRAMBLE * scrambling | - NV50_DISP_SOR_HDMI_PWR_V0_SCDC_DIV_BY_4 * high_tmds_clock_ratio; + ret = drm_scdc_readb(nv_encoder->i2c, SCDC_TMDS_CONFIG, &config); + if (ret < 0) { + NV_ERROR(drm, "Failure to read SCDC_TMDS_CONFIG: %d\n", ret); + return; + } - size = sizeof(args.base) - + sizeof(args.pwr) - + args.pwr.avi_infoframe_length - + args.pwr.vendor_infoframe_length; - nvif_mthd(&disp->disp->object, 0, &args, size); + config &= ~(SCDC_TMDS_BIT_CLOCK_RATIO_BY_40 | SCDC_SCRAMBLING_ENABLE); + if (high_tmds_clock_ratio || hdmi->scdc.scrambling.low_rates) + config |= SCDC_SCRAMBLING_ENABLE; + if (high_tmds_clock_ratio) + config |= SCDC_TMDS_BIT_CLOCK_RATIO_BY_40; - nv50_audio_enable(encoder, nv_crtc, nv_connector, state, mode); + ret = drm_scdc_writeb(nv_encoder->i2c, SCDC_TMDS_CONFIG, config); + if (ret < 0) + NV_ERROR(drm, "Failure to write SCDC_TMDS_CONFIG = 0x%02x: %d\n", + config, ret); - /* If SCDC is supported by the downstream monitor, update - * divider / scrambling settings to what we programmed above. - */ - if (!hdmi->scdc.scrambling.supported) - return; + if (high_tmds_clock_ratio || hdmi->scdc.scrambling.low_rates) + scdc |= NVIF_OUTP_ACQUIRE_V0_TMDS_HDMI_SCDC_SCRAMBLE; + if (high_tmds_clock_ratio) + scdc |= NVIF_OUTP_ACQUIRE_V0_TMDS_HDMI_SCDC_DIV_BY_4; + } - ret = drm_scdc_readb(nv_encoder->i2c, SCDC_TMDS_CONFIG, &config); - if (ret < 0) { - NV_ERROR(drm, "Failure to read SCDC_TMDS_CONFIG: %d\n", ret); + ret = nvif_outp_acquire_tmds(&nv_encoder->outp, nv_crtc->index, true, + max_ac_packet, rekey, scdc, hda); + if (ret) return; + + /* AVI InfoFrame. */ + args.infoframe.version = 0; + args.infoframe.head = nv_crtc->index; + + if (!drm_hdmi_avi_infoframe_from_display_mode(&infoframe.avi, &nv_connector->base, mode)) { + drm_hdmi_avi_infoframe_quant_range(&infoframe.avi, &nv_connector->base, mode, + HDMI_QUANTIZATION_RANGE_FULL); + + size = hdmi_infoframe_pack(&infoframe, args.data, 17); + } else { + size = 0; } - config &= ~(SCDC_TMDS_BIT_CLOCK_RATIO_BY_40 | SCDC_SCRAMBLING_ENABLE); - config |= SCDC_TMDS_BIT_CLOCK_RATIO_BY_40 * high_tmds_clock_ratio; - config |= SCDC_SCRAMBLING_ENABLE * scrambling; - ret = drm_scdc_writeb(nv_encoder->i2c, SCDC_TMDS_CONFIG, config); - if (ret < 0) - NV_ERROR(drm, "Failure to write SCDC_TMDS_CONFIG = 0x%02x: %d\n", - config, ret); + + nvif_outp_infoframe(&nv_encoder->outp, NVIF_OUTP_INFOFRAME_V0_AVI, &args.infoframe, size); + + /* Vendor InfoFrame. */ + if (!drm_hdmi_vendor_infoframe_from_display_mode(&infoframe.vendor.hdmi, + &nv_connector->base, mode)) + size = hdmi_infoframe_pack(&infoframe, args.data, 17); + else + size = 0; + + nvif_outp_infoframe(&nv_encoder->outp, NVIF_OUTP_INFOFRAME_V0_VSI, &args.infoframe, size); + + nv50_audio_enable(encoder, nv_crtc, nv_connector, state, mode); } /****************************************************************************** @@ -979,16 +882,6 @@ nv50_msto_prepare(struct drm_atomic_state *state, struct nv50_mstc *mstc = msto->mstc; struct nv50_mstm *mstm = mstc->mstm; struct drm_dp_mst_atomic_payload *payload; - struct { - struct nv50_disp_mthd_v1 base; - struct nv50_disp_sor_dp_mst_vcpi_v0 vcpi; - } args = { - .base.version = 1, - .base.method = NV50_DISP_MTHD_V1_SOR_DP_MST_VCPI, - .base.hasht = mstm->outp->dcb->hasht, - .base.hashm = (0xf0ff & mstm->outp->dcb->hashm) | - (0x0100 << msto->head->base.index), - }; NV_ATOMIC(drm, "%s: msto prepare\n", msto->encoder.name); @@ -997,22 +890,16 @@ nv50_msto_prepare(struct drm_atomic_state *state, // TODO: Figure out if we want to do a better job of handling VCPI allocation failures here? if (msto->disabled) { drm_dp_remove_payload(mgr, mst_state, payload); + + nvif_outp_dp_mst_vcpi(&mstm->outp->outp, msto->head->base.index, 0, 0, 0, 0); } else { if (msto->enabled) drm_dp_add_payload_part1(mgr, mst_state, payload); - args.vcpi.start_slot = payload->vc_start_slot; - args.vcpi.num_slots = payload->time_slots; - args.vcpi.pbn = payload->pbn; - args.vcpi.aligned_pbn = payload->time_slots * mst_state->pbn_div; + nvif_outp_dp_mst_vcpi(&mstm->outp->outp, msto->head->base.index, + payload->vc_start_slot, payload->time_slots, + payload->pbn, payload->time_slots * mst_state->pbn_div); } - - NV_ATOMIC(drm, "%s: %s: %02x %02x %04x %04x\n", - msto->encoder.name, msto->head->base.base.name, - args.vcpi.start_slot, args.vcpi.num_slots, - args.vcpi.pbn, args.vcpi.aligned_pbn); - - nvif_mthd(&drm->display->disp.object, 0, &args, sizeof(args)); } static int @@ -1107,10 +994,12 @@ nv50_msto_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *st if (WARN_ON(!mstc)) return; - if (!mstm->links++) - nv50_outp_acquire(mstm->outp, false /*XXX: MST audio.*/); + if (!mstm->links++) { + /*XXX: MST audio. */ + nvif_outp_acquire_dp(&mstm->outp->outp, mstm->outp->dp.dpcd, 0, 0, false, true); + } - if (mstm->outp->link & 1) + if (mstm->outp->outp.or.link & 1) proto = NV917D_SOR_SET_CONTROL_PROTOCOL_DP_A; else proto = NV917D_SOR_SET_CONTROL_PROTOCOL_DP_B; @@ -1405,7 +1294,7 @@ nv50_mstm_prepare(struct drm_atomic_state *state, if (mstm->disabled) { if (!mstm->links) - nv50_outp_release(mstm->outp); + nvif_outp_release(&mstm->outp->outp); mstm->disabled = false; } } @@ -1473,26 +1362,6 @@ nv50_mstm_remove(struct nv50_mstm *mstm) drm_dp_mst_topology_mgr_set_mst(&mstm->mgr, false); } -static int -nv50_mstm_enable(struct nv50_mstm *mstm, int state) -{ - struct nouveau_encoder *outp = mstm->outp; - struct { - struct nv50_disp_mthd_v1 base; - struct nv50_disp_sor_dp_mst_link_v0 mst; - } args = { - .base.version = 1, - .base.method = NV50_DISP_MTHD_V1_SOR_DP_MST_LINK, - .base.hasht = outp->dcb->hasht, - .base.hashm = outp->dcb->hashm, - .mst.state = state, - }; - struct nouveau_drm *drm = nouveau_drm(outp->base.base.dev); - struct nvif_object *disp = &drm->display->disp.object; - - return nvif_mthd(disp, 0, &args, sizeof(args)); -} - int nv50_mstm_detect(struct nouveau_encoder *outp) { @@ -1513,15 +1382,9 @@ nv50_mstm_detect(struct nouveau_encoder *outp) return ret; /* And start enabling */ - ret = nv50_mstm_enable(mstm, true); - if (ret) - return ret; - ret = drm_dp_mst_topology_mgr_set_mst(&mstm->mgr, true); - if (ret) { - nv50_mstm_enable(mstm, false); + if (ret) return ret; - } mstm->is_mst = true; return 1; @@ -1623,7 +1486,7 @@ nv50_sor_update(struct nouveau_encoder *nv_encoder, u8 head, asyh->or.depth = depth; } - core->func->sor->ctrl(core, nv_encoder->or, nv_encoder->ctrl, asyh); + core->func->sor->ctrl(core, nv_encoder->outp.or.id, nv_encoder->ctrl, asyh); } /* TODO: Should we extend this to PWM-only backlights? @@ -1666,8 +1529,7 @@ nv50_sor_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_state *st nv_encoder->update(nv_encoder, nv_crtc->index, NULL, 0, 0); nv50_audio_disable(encoder, nv_crtc); - nv50_hdmi_disable(&nv_encoder->base.base, nv_crtc); - nv50_outp_release(nv_encoder); + nvif_outp_release(&nv_encoder->outp); nv_encoder->crtc = NULL; } @@ -1679,16 +1541,8 @@ nv50_sor_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *sta struct nv50_head_atom *asyh = nv50_head_atom(drm_atomic_get_new_crtc_state(state, &nv_crtc->base)); struct drm_display_mode *mode = &asyh->state.adjusted_mode; - struct { - struct nv50_disp_mthd_v1 base; - struct nv50_disp_sor_lvds_script_v0 lvds; - } lvds = { - .base.version = 1, - .base.method = NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT, - .base.hasht = nv_encoder->dcb->hasht, - .base.hashm = nv_encoder->dcb->hashm, - }; struct nv50_disp *disp = nv50_disp(encoder->dev); + struct nvif_outp *outp = &nv_encoder->outp; struct drm_device *dev = encoder->dev; struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_connector *nv_connector; @@ -1696,7 +1550,7 @@ nv50_sor_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *sta struct nouveau_backlight *backlight; #endif struct nvbios *bios = &drm->vbios; - bool hda = false; + bool lvds_dual = false, lvds_8bpc = false, hda = false; u8 proto = NV507D_SOR_SET_CONTROL_PROTOCOL_CUSTOM; u8 depth = NV837D_SOR_SET_CONTROL_PIXEL_DEPTH_DEFAULT; @@ -1707,11 +1561,16 @@ nv50_sor_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *sta disp->disp->object.oclass >= GF110_DISP) && drm_detect_monitor_audio(nv_connector->edid)) hda = true; - nv50_outp_acquire(nv_encoder, hda); switch (nv_encoder->dcb->type) { case DCB_OUTPUT_TMDS: - if (nv_encoder->link & 1) { + if (disp->disp->object.oclass == NV50_DISP || + !drm_detect_hdmi_monitor(nv_connector->edid)) + nvif_outp_acquire_tmds(outp, nv_crtc->index, false, 0, 0, 0, false); + else + nv50_hdmi_enable(encoder, nv_crtc, nv_connector, state, mode, hda); + + if (nv_encoder->outp.or.link & 1) { proto = NV507D_SOR_SET_CONTROL_PROTOCOL_SINGLE_TMDS_A; /* Only enable dual-link if: * - Need to (i.e. rate > 165MHz) @@ -1726,44 +1585,41 @@ nv50_sor_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *sta } else { proto = NV507D_SOR_SET_CONTROL_PROTOCOL_SINGLE_TMDS_B; } - - nv50_hdmi_enable(&nv_encoder->base.base, nv_crtc, nv_connector, state, mode); break; case DCB_OUTPUT_LVDS: proto = NV507D_SOR_SET_CONTROL_PROTOCOL_LVDS_CUSTOM; if (bios->fp_no_ddc) { - if (bios->fp.dual_link) - lvds.lvds.script |= 0x0100; - if (bios->fp.if_is_24bit) - lvds.lvds.script |= 0x0200; + lvds_dual = bios->fp.dual_link; + lvds_8bpc = bios->fp.if_is_24bit; } else { if (nv_connector->type == DCB_CONNECTOR_LVDS_SPWG) { if (((u8 *)nv_connector->edid)[121] == 2) - lvds.lvds.script |= 0x0100; + lvds_dual = true; } else if (mode->clock >= bios->fp.duallink_transition_clk) { - lvds.lvds.script |= 0x0100; + lvds_dual = true; } - if (lvds.lvds.script & 0x0100) { + if (lvds_dual) { if (bios->fp.strapless_is_24bit & 2) - lvds.lvds.script |= 0x0200; + lvds_8bpc = true; } else { if (bios->fp.strapless_is_24bit & 1) - lvds.lvds.script |= 0x0200; + lvds_8bpc = true; } if (asyh->or.bpc == 8) - lvds.lvds.script |= 0x0200; + lvds_8bpc = true; } - nvif_mthd(&disp->disp->object, 0, &lvds, sizeof(lvds)); + nvif_outp_acquire_lvds(&nv_encoder->outp, lvds_dual, lvds_8bpc); break; case DCB_OUTPUT_DP: + nvif_outp_acquire_dp(&nv_encoder->outp, nv_encoder->dp.dpcd, 0, 0, hda, false); depth = nv50_dp_bpc_to_depth(asyh->or.bpc); - if (nv_encoder->link & 1) + if (nv_encoder->outp.or.link & 1) proto = NV887D_SOR_SET_CONTROL_PROTOCOL_DP_A; else proto = NV887D_SOR_SET_CONTROL_PROTOCOL_DP_B; @@ -1921,9 +1777,9 @@ nv50_pior_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_state *s struct nv50_core *core = nv50_disp(encoder->dev)->core; const u32 ctrl = NVDEF(NV507D, PIOR_SET_CONTROL, OWNER, NONE); - core->func->pior->ctrl(core, nv_encoder->or, ctrl, NULL); + core->func->pior->ctrl(core, nv_encoder->outp.or.id, ctrl, NULL); nv_encoder->crtc = NULL; - nv50_outp_release(nv_encoder); + nvif_outp_release(&nv_encoder->outp); } static void @@ -1944,8 +1800,6 @@ nv50_pior_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *st break; } - nv50_outp_acquire(nv_encoder, false); - switch (asyh->or.bpc) { case 10: asyh->or.depth = NV837D_PIOR_SET_CONTROL_PIXEL_DEPTH_BPP_30_444; break; case 8: asyh->or.depth = NV837D_PIOR_SET_CONTROL_PIXEL_DEPTH_BPP_24_444; break; @@ -1955,15 +1809,19 @@ nv50_pior_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *st switch (nv_encoder->dcb->type) { case DCB_OUTPUT_TMDS: + ctrl |= NVDEF(NV507D, PIOR_SET_CONTROL, PROTOCOL, EXT_TMDS_ENC); + nvif_outp_acquire_tmds(&nv_encoder->outp, false, false, 0, 0, 0, false); + break; case DCB_OUTPUT_DP: ctrl |= NVDEF(NV507D, PIOR_SET_CONTROL, PROTOCOL, EXT_TMDS_ENC); + nvif_outp_acquire_dp(&nv_encoder->outp, nv_encoder->dp.dpcd, 0, 0, false, false); break; default: BUG(); break; } - core->func->pior->ctrl(core, nv_encoder->or, ctrl, asyh); + core->func->pior->ctrl(core, nv_encoder->outp.or.id, ctrl, asyh); nv_encoder->crtc = &nv_crtc->base; } @@ -2587,7 +2445,7 @@ nv50_disp_atomic_state_alloc(struct drm_device *dev) static const struct drm_mode_config_funcs nv50_disp_func = { .fb_create = nouveau_user_framebuffer_create, - .output_poll_changed = nouveau_fbcon_output_poll_changed, + .output_poll_changed = drm_fb_helper_output_poll_changed, .atomic_check = nv50_disp_atomic_check, .atomic_commit = nv50_disp_atomic_commit, .atomic_state_alloc = nv50_disp_atomic_state_alloc, diff --git a/drivers/gpu/drm/nouveau/dispnv50/head.c b/drivers/gpu/drm/nouveau/dispnv50/head.c index c3c57be54e1c..f006e56e1e08 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/head.c +++ b/drivers/gpu/drm/nouveau/dispnv50/head.c @@ -517,7 +517,8 @@ nv50_head_destroy(struct drm_crtc *crtc) { struct nv50_head *head = nv50_head(crtc); - nvif_notify_dtor(&head->base.vblank); + nvif_event_dtor(&head->base.vblank); + nvif_head_dtor(&head->base.head); nv50_lut_fini(&head->olut); drm_crtc_cleanup(crtc); kfree(head); @@ -554,15 +555,15 @@ nvd9_head_func = { .late_register = nv50_head_late_register, }; -static int nv50_head_vblank_handler(struct nvif_notify *notify) +static int +nv50_head_vblank_handler(struct nvif_event *event, void *repv, u32 repc) { - struct nouveau_crtc *nv_crtc = - container_of(notify, struct nouveau_crtc, vblank); + struct nouveau_crtc *nv_crtc = container_of(event, struct nouveau_crtc, vblank); if (drm_crtc_handle_vblank(&nv_crtc->base)) nv50_crc_handle_vblank(nv50_head(&nv_crtc->base)); - return NVIF_NOTIFY_KEEP; + return NVIF_EVENT_KEEP; } struct nv50_head * @@ -624,14 +625,12 @@ nv50_head_create(struct drm_device *dev, int index) } } - ret = nvif_notify_ctor(&disp->disp->object, "kmsVbl", nv50_head_vblank_handler, - false, NV04_DISP_NTFY_VBLANK, - &(struct nvif_notify_head_req_v0) { - .head = nv_crtc->index, - }, - sizeof(struct nvif_notify_head_req_v0), - sizeof(struct nvif_notify_head_rep_v0), - &nv_crtc->vblank); + ret = nvif_head_ctor(disp->disp, head->base.base.name, head->base.index, &head->base.head); + if (ret) + return ERR_PTR(ret); + + ret = nvif_head_vblank_event_ctor(&head->base.head, "kmsVbl", nv50_head_vblank_handler, + false, &nv_crtc->vblank); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/nouveau/include/nvfw/acr.h b/drivers/gpu/drm/nouveau/include/nvfw/acr.h index e65d6a8db104..6f19560bc54b 100644 --- a/drivers/gpu/drm/nouveau/include/nvfw/acr.h +++ b/drivers/gpu/drm/nouveau/include/nvfw/acr.h @@ -39,6 +39,23 @@ struct wpr_header_v1 { void wpr_header_v1_dump(struct nvkm_subdev *, const struct wpr_header_v1 *); +struct wpr_generic_header { +#define WPR_GENERIC_HEADER_ID_LSF_UCODE_DESC 1 +#define WPR_GENERIC_HEADER_ID_LSF_WPR_HEADER 2 +#define WPR_GENERIC_HEADER_ID_LSF_SHARED_SUB_WPR 3 +#define WPR_GENERIC_HEADER_ID_LSF_LSB_HEADER 4 + u16 identifier; + u16 version; + u32 size; +}; + +struct wpr_header_v2 { + struct wpr_generic_header hdr; + struct wpr_header_v1 wpr; +}; + +void wpr_header_v2_dump(struct nvkm_subdev *, const struct wpr_header_v2 *); + struct lsf_signature { u8 prd_keys[2][16]; u8 dbg_keys[2][16]; @@ -89,6 +106,74 @@ struct lsb_header_v1 { void lsb_header_v1_dump(struct nvkm_subdev *, struct lsb_header_v1 *); +struct lsb_header_v2 { + struct wpr_generic_header hdr; + struct lsf_signature_v2 { + struct wpr_generic_header hdr; + u32 falcon_id; + u8 prd_present; + u8 dbg_present; + u16 reserved; + u32 sig_size; + u8 prod_sig[2][384 + 128]; + u8 debug_sig[2][384 + 128]; + u16 sig_algo_ver; + u16 sig_algo; + u16 hash_algo_ver; + u16 hash_algo; + u32 sig_algo_padding_type; + u8 depmap[11 * 2 * 4]; + u32 depmap_count; + u8 supports_versioning; + u8 pad[3]; + u32 ls_ucode_version; + u32 ls_ucode_id; + u32 ucode_ls_encrypted; + u32 ls_eng_algo_type; + u32 ls_eng_algo_ver; + u8 ls_enc_iv[16]; + u8 rsvd[36]; + } signature; + u32 ucode_off; + u32 ucode_size; + u32 data_size; + u32 bl_code_size; + u32 bl_imem_off; + u32 bl_data_off; + u32 bl_data_size; + u32 rsvd0; + u32 app_code_off; + u32 app_code_size; + u32 app_data_off; + u32 app_data_size; + u32 app_imem_offset; + u32 app_dmem_offset; + u32 flags; + u32 monitor_code_offset; + u32 monitor_data_offset; + u32 manifest_offset; + struct hs_fmc_params { + u8 hs_fmc; + u8 padding[3]; + u16 pkc_algo; + u16 pkc_algo_version; + u32 engid_mask; + u32 ucode_id; + u32 fuse_ver; + u8 pkc_signature[384 + 128]; + u8 pkc_key[2048]; + u8 rsvd[4]; + } hs_fmc_params; + struct hs_ovl_sig_blob_params { + u8 hs_ovl_sig_blob_present; + u32 hs_ovl_sig_blob_offset; + u32 hs_ovl_sig_blob_size; + } hs_ovl_sig_blob_params; + u8 rsvd[20]; +}; + +void lsb_header_v2_dump(struct nvkm_subdev *, struct lsb_header_v2 *); + struct flcn_acr_desc { union { u8 reserved_dmem[0x200]; diff --git a/drivers/gpu/drm/nouveau/include/nvfw/hs.h b/drivers/gpu/drm/nouveau/include/nvfw/hs.h index b53bbc4cd130..8c4cd08a7b5f 100644 --- a/drivers/gpu/drm/nouveau/include/nvfw/hs.h +++ b/drivers/gpu/drm/nouveau/include/nvfw/hs.h @@ -17,6 +17,20 @@ struct nvfw_hs_header { const struct nvfw_hs_header *nvfw_hs_header(struct nvkm_subdev *, const void *); +struct nvfw_hs_header_v2 { + u32 sig_prod_offset; + u32 sig_prod_size; + u32 patch_loc; + u32 patch_sig; + u32 meta_data_offset; + u32 meta_data_size; + u32 num_sig; + u32 header_offset; + u32 header_size; +}; + +const struct nvfw_hs_header_v2 *nvfw_hs_header_v2(struct nvkm_subdev *, const void *); + struct nvfw_hs_load_header { u32 non_sec_code_off; u32 non_sec_code_size; @@ -28,4 +42,18 @@ struct nvfw_hs_load_header { const struct nvfw_hs_load_header * nvfw_hs_load_header(struct nvkm_subdev *, const void *); + +struct nvfw_hs_load_header_v2 { + u32 os_code_offset; + u32 os_code_size; + u32 os_data_offset; + u32 os_data_size; + u32 num_apps; + struct { + u32 offset; + u32 size; + } app[0]; +}; + +const struct nvfw_hs_load_header_v2 *nvfw_hs_load_header_v2(struct nvkm_subdev *, const void *); #endif diff --git a/drivers/gpu/drm/nouveau/include/nvfw/ls.h b/drivers/gpu/drm/nouveau/include/nvfw/ls.h index f63692a2a16c..d531121bfa35 100644 --- a/drivers/gpu/drm/nouveau/include/nvfw/ls.h +++ b/drivers/gpu/drm/nouveau/include/nvfw/ls.h @@ -50,4 +50,55 @@ struct nvfw_ls_desc_v1 { const struct nvfw_ls_desc_v1 * nvfw_ls_desc_v1(struct nvkm_subdev *, const void *); + +struct nvfw_ls_desc_v2 { + u32 descriptor_size; + u32 image_size; + u32 tools_version; + u32 app_version; + char date[64]; + u32 secure_bootloader; + u32 bootloader_start_offset; + u32 bootloader_size; + u32 bootloader_imem_offset; + u32 bootloader_entry_point; + u32 app_start_offset; + u32 app_size; + u32 app_imem_offset; + u32 app_imem_entry; + u32 app_dmem_offset; + u32 app_resident_code_offset; + u32 app_resident_code_size; + u32 app_resident_data_offset; + u32 app_resident_data_size; + u32 nb_imem_overlays; + u32 nb_dmem_overlays; + struct { + u32 start; + u32 size; + } load_ovl[64]; +}; + +const struct nvfw_ls_desc_v2 *nvfw_ls_desc_v2(struct nvkm_subdev *, const void *); + +struct nvfw_ls_hsbl_bin_hdr { + u32 bin_magic; + u32 bin_ver; + u32 bin_size; + u32 header_offset; +}; + +const struct nvfw_ls_hsbl_bin_hdr *nvfw_ls_hsbl_bin_hdr(struct nvkm_subdev *, const void *); + +struct nvfw_ls_hsbl_hdr { + u32 sig_prod_offset; + u32 sig_prod_size; + u32 patch_loc; + u32 patch_sig; + u32 meta_data_offset; + u32 meta_data_size; + u32 num_sig; +}; + +const struct nvfw_ls_hsbl_hdr *nvfw_ls_hsbl_hdr(struct nvkm_subdev *, const void *); #endif diff --git a/drivers/gpu/drm/nouveau/include/nvfw/sec2.h b/drivers/gpu/drm/nouveau/include/nvfw/sec2.h index 9a37ad4179cb..b3331d679c4e 100644 --- a/drivers/gpu/drm/nouveau/include/nvfw/sec2.h +++ b/drivers/gpu/drm/nouveau/include/nvfw/sec2.h @@ -10,6 +10,7 @@ struct nv_sec2_args { }; #define NV_SEC2_UNIT_INIT 0x01 +#define NV_SEC2_UNIT_UNLOAD 0x06 #define NV_SEC2_UNIT_ACR 0x08 struct nv_sec2_init_msg { @@ -33,6 +34,29 @@ struct nv_sec2_init_msg { u16 sw_managed_area_size; }; +struct nv_sec2_init_msg_v1 { + struct nvfw_falcon_msg hdr; +#define NV_SEC2_INIT_MSG_INIT 0x00 + u8 msg_type; + + u8 num_queues; + u16 os_debug_entry_point; + + struct { + u32 offset; + u16 size; + u8 index; +#define NV_SEC2_INIT_MSG_QUEUE_ID_CMDQ 0x00 +#define NV_SEC2_INIT_MSG_QUEUE_ID_MSGQ 0x01 + u8 id; + } queue_info[2]; + + u32 sw_managed_area_offset; + u16 sw_managed_area_size; + + u32 unkn[8]; +}; + struct nv_sec2_acr_cmd { struct nvfw_falcon_cmd hdr; #define NV_SEC2_ACR_CMD_BOOTSTRAP_FALCON 0x00 @@ -57,4 +81,25 @@ struct nv_sec2_acr_bootstrap_falcon_msg { u32 error_code; u32 falcon_id; }; + +#define NV_SEC2_UNIT_V2_INIT 0x01 +#define NV_SEC2_UNIT_V2_UNLOAD 0x05 +#define NV_SEC2_UNIT_V2_ACR 0x07 + +struct nv_sec2_acr_bootstrap_falcon_cmd_v1 { + struct nv_sec2_acr_cmd cmd; +#define NV_SEC2_ACR_BOOTSTRAP_FALCON_FLAGS_RESET_YES 0x00000000 +#define NV_SEC2_ACR_BOOTSTRAP_FALCON_FLAGS_RESET_NO 0x00000001 + u32 flags; + u32 falcon_id; + u32 unkn08; + u32 unkn0c; +}; + +struct nv_sec2_acr_bootstrap_falcon_msg_v1 { + struct nv_sec2_acr_msg msg; + u32 error_code; + u32 falcon_id; + u32 unkn08; +}; #endif diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl0046.h b/drivers/gpu/drm/nouveau/include/nvif/cl0046.h index d490d401870a..eca7c3950654 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/cl0046.h +++ b/drivers/gpu/drm/nouveau/include/nvif/cl0046.h @@ -2,28 +2,5 @@ #ifndef __NVIF_CL0046_H__ #define __NVIF_CL0046_H__ -#define NV04_DISP_NTFY_VBLANK 0x00 #define NV04_DISP_NTFY_CONN 0x01 - -struct nv04_disp_mthd_v0 { - __u8 version; -#define NV04_DISP_SCANOUTPOS 0x00 - __u8 method; - __u8 head; - __u8 pad03[5]; -}; - -struct nv04_disp_scanoutpos_v0 { - __u8 version; - __u8 pad01[7]; - __s64 time[2]; - __u16 vblanks; - __u16 vblanke; - __u16 vtotal; - __u16 vline; - __u16 hblanks; - __u16 hblanke; - __u16 htotal; - __u16 hline; -}; #endif diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl006b.h b/drivers/gpu/drm/nouveau/include/nvif/cl006b.h deleted file mode 100644 index c960c449e430..000000000000 --- a/drivers/gpu/drm/nouveau/include/nvif/cl006b.h +++ /dev/null @@ -1,12 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -#ifndef __NVIF_CL006B_H__ -#define __NVIF_CL006B_H__ - -struct nv03_channel_dma_v0 { - __u8 version; - __u8 chid; - __u8 pad02[2]; - __u32 offset; - __u64 pushbuf; -}; -#endif diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl0080.h b/drivers/gpu/drm/nouveau/include/nvif/cl0080.h index 59759c4fb62e..8b5a240d57e4 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/cl0080.h +++ b/drivers/gpu/drm/nouveau/include/nvif/cl0080.h @@ -68,7 +68,7 @@ struct nv_device_time_v0 { /* Returns the number of available runlists. */ #define NV_DEVICE_HOST_RUNLISTS NV_DEVICE_HOST(0x00000000) -/* Returns the number of available channels. */ +/* Returns the number of available channels (0 if per-runlist). */ #define NV_DEVICE_HOST_CHANNELS NV_DEVICE_HOST(0x00000001) /* Returns a mask of available engine types on runlist(data). */ @@ -90,4 +90,6 @@ struct nv_device_time_v0 { #define NV_DEVICE_HOST_RUNLIST_ENGINES_SEC2 0x00004000 #define NV_DEVICE_HOST_RUNLIST_ENGINES_NVDEC 0x00008000 #define NV_DEVICE_HOST_RUNLIST_ENGINES_NVENC 0x00010000 +/* Returns the number of available channels on runlist(data). */ +#define NV_DEVICE_HOST_RUNLIST_CHANNELS NV_DEVICE_HOST(0x00000101) #endif diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl506e.h b/drivers/gpu/drm/nouveau/include/nvif/cl506e.h deleted file mode 100644 index 9df289c7a84f..000000000000 --- a/drivers/gpu/drm/nouveau/include/nvif/cl506e.h +++ /dev/null @@ -1,13 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -#ifndef __NVIF_CL506E_H__ -#define __NVIF_CL506E_H__ - -struct nv50_channel_dma_v0 { - __u8 version; - __u8 chid; - __u8 pad02[6]; - __u64 vmm; - __u64 pushbuf; - __u64 offset; -}; -#endif diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl506f.h b/drivers/gpu/drm/nouveau/include/nvif/cl506f.h deleted file mode 100644 index 327c96a994bb..000000000000 --- a/drivers/gpu/drm/nouveau/include/nvif/cl506f.h +++ /dev/null @@ -1,14 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -#ifndef __NVIF_CL506F_H__ -#define __NVIF_CL506F_H__ - -struct nv50_channel_gpfifo_v0 { - __u8 version; - __u8 chid; - __u8 pad02[2]; - __u32 ilength; - __u64 ioffset; - __u64 pushbuf; - __u64 vmm; -}; -#endif diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl5070.h b/drivers/gpu/drm/nouveau/include/nvif/cl5070.h deleted file mode 100644 index 56affb606adf..000000000000 --- a/drivers/gpu/drm/nouveau/include/nvif/cl5070.h +++ /dev/null @@ -1,92 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -#ifndef __NVIF_CL5070_H__ -#define __NVIF_CL5070_H__ - -#define NV50_DISP_MTHD 0x00 - -struct nv50_disp_mthd_v0 { - __u8 version; -#define NV50_DISP_SCANOUTPOS 0x00 - __u8 method; - __u8 head; - __u8 pad03[5]; -}; - -struct nv50_disp_scanoutpos_v0 { - __u8 version; - __u8 pad01[7]; - __s64 time[2]; - __u16 vblanks; - __u16 vblanke; - __u16 vtotal; - __u16 vline; - __u16 hblanks; - __u16 hblanke; - __u16 htotal; - __u16 hline; -}; - -struct nv50_disp_mthd_v1 { - __u8 version; -#define NV50_DISP_MTHD_V1_ACQUIRE 0x01 -#define NV50_DISP_MTHD_V1_RELEASE 0x02 -#define NV50_DISP_MTHD_V1_SOR_HDA_ELD 0x21 -#define NV50_DISP_MTHD_V1_SOR_HDMI_PWR 0x22 -#define NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT 0x23 -#define NV50_DISP_MTHD_V1_SOR_DP_MST_LINK 0x25 -#define NV50_DISP_MTHD_V1_SOR_DP_MST_VCPI 0x26 - __u8 method; - __u16 hasht; - __u16 hashm; - __u8 pad06[2]; -}; - -struct nv50_disp_acquire_v0 { - __u8 version; - __u8 or; - __u8 link; - __u8 hda; - __u8 pad04[4]; -}; - -struct nv50_disp_sor_hda_eld_v0 { - __u8 version; - __u8 pad01[7]; - __u8 data[]; -}; - -struct nv50_disp_sor_hdmi_pwr_v0 { - __u8 version; - __u8 state; - __u8 max_ac_packet; - __u8 rekey; - __u8 avi_infoframe_length; - __u8 vendor_infoframe_length; -#define NV50_DISP_SOR_HDMI_PWR_V0_SCDC_SCRAMBLE (1 << 0) -#define NV50_DISP_SOR_HDMI_PWR_V0_SCDC_DIV_BY_4 (1 << 1) - __u8 scdc; - __u8 pad07[1]; -}; - -struct nv50_disp_sor_lvds_script_v0 { - __u8 version; - __u8 pad01[1]; - __u16 script; - __u8 pad04[4]; -}; - -struct nv50_disp_sor_dp_mst_link_v0 { - __u8 version; - __u8 state; - __u8 pad02[6]; -}; - -struct nv50_disp_sor_dp_mst_vcpi_v0 { - __u8 version; - __u8 pad01[1]; - __u8 start_slot; - __u8 num_slots; - __u16 pbn; - __u16 aligned_pbn; -}; -#endif diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl826e.h b/drivers/gpu/drm/nouveau/include/nvif/cl826e.h deleted file mode 100644 index 1b6496d31580..000000000000 --- a/drivers/gpu/drm/nouveau/include/nvif/cl826e.h +++ /dev/null @@ -1,15 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -#ifndef __NVIF_CL826E_H__ -#define __NVIF_CL826E_H__ - -struct g82_channel_dma_v0 { - __u8 version; - __u8 chid; - __u8 pad02[6]; - __u64 vmm; - __u64 pushbuf; - __u64 offset; -}; - -#define NV826E_V0_NTFY_NON_STALL_INTERRUPT 0x00 -#endif diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl826f.h b/drivers/gpu/drm/nouveau/include/nvif/cl826f.h deleted file mode 100644 index 148602264a76..000000000000 --- a/drivers/gpu/drm/nouveau/include/nvif/cl826f.h +++ /dev/null @@ -1,16 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -#ifndef __NVIF_CL826F_H__ -#define __NVIF_CL826F_H__ - -struct g82_channel_gpfifo_v0 { - __u8 version; - __u8 chid; - __u8 pad02[2]; - __u32 ilength; - __u64 ioffset; - __u64 pushbuf; - __u64 vmm; -}; - -#define NV826F_V0_NTFY_NON_STALL_INTERRUPT 0x00 -#endif diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl906f.h b/drivers/gpu/drm/nouveau/include/nvif/cl906f.h deleted file mode 100644 index 3823d6891b55..000000000000 --- a/drivers/gpu/drm/nouveau/include/nvif/cl906f.h +++ /dev/null @@ -1,16 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -#ifndef __NVIF_CL906F_H__ -#define __NVIF_CL906F_H__ - -struct fermi_channel_gpfifo_v0 { - __u8 version; - __u8 chid; - __u8 pad02[2]; - __u32 ilength; - __u64 ioffset; - __u64 vmm; -}; - -#define NV906F_V0_NTFY_NON_STALL_INTERRUPT 0x00 -#define NV906F_V0_NTFY_KILLED 0x01 -#endif diff --git a/drivers/gpu/drm/nouveau/include/nvif/cla06f.h b/drivers/gpu/drm/nouveau/include/nvif/cla06f.h deleted file mode 100644 index cfa18f1fbf83..000000000000 --- a/drivers/gpu/drm/nouveau/include/nvif/cla06f.h +++ /dev/null @@ -1,18 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -#ifndef __NVIF_CLA06F_H__ -#define __NVIF_CLA06F_H__ - -struct kepler_channel_gpfifo_a_v0 { - __u8 version; - __u8 priv; - __u16 chid; - __u32 ilength; - __u64 ioffset; - __u64 runlist; - __u64 vmm; - __u64 inst; -}; - -#define NVA06F_V0_NTFY_NON_STALL_INTERRUPT 0x00 -#define NVA06F_V0_NTFY_KILLED 0x01 -#endif diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h b/drivers/gpu/drm/nouveau/include/nvif/class.h index 8641db649f48..ad1e5de84e80 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/class.h +++ b/drivers/gpu/drm/nouveau/include/nvif/class.h @@ -32,11 +32,17 @@ #define NVIF_CLASS_VMM_GM200 /* ifb00d.h */ 0x8000b00d #define NVIF_CLASS_VMM_GP100 /* ifc00d.h */ 0x8000c00d +#define NVIF_CLASS_EVENT /* if000e.h */ 0x8000000e + #define NVIF_CLASS_DISP /* if0010.h */ 0x80000010 #define NVIF_CLASS_CONN /* if0011.h */ 0x80000011 #define NVIF_CLASS_OUTP /* if0012.h */ 0x80000012 +#define NVIF_CLASS_HEAD /* if0013.h */ 0x80000013 #define NVIF_CLASS_DISP_CHAN /* if0014.h */ 0x80000014 +#define NVIF_CLASS_CHAN /* if0020.h */ 0x80000020 +#define NVIF_CLASS_CGRP /* if0021.h */ 0x80000021 + /* the below match nvidia-assigned (either in hw, or sw) class numbers */ #define NV_NULL_CLASS 0x00000030 @@ -58,25 +64,30 @@ #define NV04_DISP /* cl0046.h */ 0x00000046 #define VOLTA_USERMODE_A 0x0000c361 +#define TURING_USERMODE_A 0x0000c461 +#define AMPERE_USERMODE_A 0x0000c561 #define MAXWELL_FAULT_BUFFER_A /* clb069.h */ 0x0000b069 #define VOLTA_FAULT_BUFFER_A /* clb069.h */ 0x0000c369 -#define NV03_CHANNEL_DMA /* cl506b.h */ 0x0000006b -#define NV10_CHANNEL_DMA /* cl506b.h */ 0x0000006e -#define NV17_CHANNEL_DMA /* cl506b.h */ 0x0000176e -#define NV40_CHANNEL_DMA /* cl506b.h */ 0x0000406e - -#define NV50_CHANNEL_GPFIFO /* cl506f.h */ 0x0000506f -#define G82_CHANNEL_GPFIFO /* cl826f.h */ 0x0000826f -#define FERMI_CHANNEL_GPFIFO /* cl906f.h */ 0x0000906f -#define KEPLER_CHANNEL_GPFIFO_A /* cla06f.h */ 0x0000a06f -#define KEPLER_CHANNEL_GPFIFO_B /* cla06f.h */ 0x0000a16f -#define MAXWELL_CHANNEL_GPFIFO_A /* cla06f.h */ 0x0000b06f -#define PASCAL_CHANNEL_GPFIFO_A /* cla06f.h */ 0x0000c06f -#define VOLTA_CHANNEL_GPFIFO_A /* clc36f.h */ 0x0000c36f -#define TURING_CHANNEL_GPFIFO_A /* clc36f.h */ 0x0000c46f -#define AMPERE_CHANNEL_GPFIFO_B /* clc36f.h */ 0x0000c76f +#define NV03_CHANNEL_DMA /* if0020.h */ 0x0000006b +#define NV10_CHANNEL_DMA /* if0020.h */ 0x0000006e +#define NV17_CHANNEL_DMA /* if0020.h */ 0x0000176e +#define NV40_CHANNEL_DMA /* if0020.h */ 0x0000406e + +#define KEPLER_CHANNEL_GROUP_A /* if0021.h */ 0x0000a06c + +#define NV50_CHANNEL_GPFIFO /* if0020.h */ 0x0000506f +#define G82_CHANNEL_GPFIFO /* if0020.h */ 0x0000826f +#define FERMI_CHANNEL_GPFIFO /* if0020.h */ 0x0000906f +#define KEPLER_CHANNEL_GPFIFO_A /* if0020.h */ 0x0000a06f +#define KEPLER_CHANNEL_GPFIFO_B /* if0020.h */ 0x0000a16f +#define MAXWELL_CHANNEL_GPFIFO_A /* if0020.h */ 0x0000b06f +#define PASCAL_CHANNEL_GPFIFO_A /* if0020.h */ 0x0000c06f +#define VOLTA_CHANNEL_GPFIFO_A /* if0020.h */ 0x0000c36f +#define TURING_CHANNEL_GPFIFO_A /* if0020.h */ 0x0000c46f +#define AMPERE_CHANNEL_GPFIFO_A /* if0020.h */ 0x0000c56f +#define AMPERE_CHANNEL_GPFIFO_B /* if0020.h */ 0x0000c76f #define NV50_DISP /* if0010.h */ 0x00005070 #define G82_DISP /* if0010.h */ 0x00008270 @@ -179,6 +190,8 @@ #define TURING_A /* cl9097.h */ 0x0000c597 +#define AMPERE_B /* cl9097.h */ 0x0000c797 + #define NV74_BSP 0x000074b0 #define GT212_MSVLD 0x000085b1 @@ -206,6 +219,7 @@ #define PASCAL_DMA_COPY_B 0x0000c1b5 #define VOLTA_DMA_COPY_A 0x0000c3b5 #define TURING_DMA_COPY_A 0x0000c5b5 +#define AMPERE_DMA_COPY_A 0x0000c6b5 #define AMPERE_DMA_COPY_B 0x0000c7b5 #define FERMI_DECOMPRESS 0x000090b8 @@ -222,6 +236,7 @@ #define PASCAL_COMPUTE_B 0x0000c1c0 #define VOLTA_COMPUTE_A 0x0000c3c0 #define TURING_COMPUTE_A 0x0000c5c0 +#define AMPERE_COMPUTE_B 0x0000c7c0 #define NV74_CIPHER 0x000074c1 #endif diff --git a/drivers/gpu/drm/nouveau/include/nvif/clb069.h b/drivers/gpu/drm/nouveau/include/nvif/clb069.h index eef5d0227bab..d7689de35ab2 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/clb069.h +++ b/drivers/gpu/drm/nouveau/include/nvif/clb069.h @@ -8,5 +8,8 @@ struct nvif_clb069_v0 { __u32 put; }; -#define NVB069_V0_NTFY_FAULT 0x00 +union nvif_clb069_event_args { + struct nvif_clb069_event_vn { + } vn; +}; #endif diff --git a/drivers/gpu/drm/nouveau/include/nvif/clc36f.h b/drivers/gpu/drm/nouveau/include/nvif/clc36f.h deleted file mode 100644 index f66885891238..000000000000 --- a/drivers/gpu/drm/nouveau/include/nvif/clc36f.h +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -#ifndef __NVIF_CLC36F_H__ -#define __NVIF_CLC36F_H__ - -struct volta_channel_gpfifo_a_v0 { - __u8 version; - __u8 priv; - __u16 chid; - __u32 ilength; - __u64 ioffset; - __u64 runlist; - __u64 vmm; - __u64 inst; - __u32 token; -}; - -#define NVC36F_V0_NTFY_NON_STALL_INTERRUPT 0x00 -#define NVC36F_V0_NTFY_KILLED 0x01 -#endif diff --git a/drivers/gpu/drm/nouveau/include/nvif/conn.h b/drivers/gpu/drm/nouveau/include/nvif/conn.h index f72a8f138f47..dc355e1dfafa 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/conn.h +++ b/drivers/gpu/drm/nouveau/include/nvif/conn.h @@ -2,6 +2,7 @@ #ifndef __NVIF_CONN_H__ #define __NVIF_CONN_H__ #include <nvif/object.h> +#include <nvif/event.h> struct nvif_disp; struct nvif_conn { @@ -11,8 +12,17 @@ struct nvif_conn { int nvif_conn_ctor(struct nvif_disp *, const char *name, int id, struct nvif_conn *); void nvif_conn_dtor(struct nvif_conn *); +static inline int +nvif_conn_id(struct nvif_conn *conn) +{ + return conn->object.handle; +} + #define NVIF_CONN_HPD_STATUS_UNSUPPORTED 0 /* negative if query fails */ #define NVIF_CONN_HPD_STATUS_NOT_PRESENT 1 #define NVIF_CONN_HPD_STATUS_PRESENT 2 int nvif_conn_hpd_status(struct nvif_conn *); + +int nvif_conn_event_ctor(struct nvif_conn *, const char *name, nvif_event_func, u8 types, + struct nvif_event *); #endif diff --git a/drivers/gpu/drm/nouveau/include/nvif/disp.h b/drivers/gpu/drm/nouveau/include/nvif/disp.h index 742632ad3bea..56eb7293e01c 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/disp.h +++ b/drivers/gpu/drm/nouveau/include/nvif/disp.h @@ -7,6 +7,7 @@ struct nvif_disp { struct nvif_object object; unsigned long conn_mask; unsigned long outp_mask; + unsigned long head_mask; }; int nvif_disp_ctor(struct nvif_device *, const char *name, s32 oclass, diff --git a/drivers/gpu/drm/nouveau/include/nvif/event.h b/drivers/gpu/drm/nouveau/include/nvif/event.h index a6b1ee4f10ca..68bf6635841f 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/event.h +++ b/drivers/gpu/drm/nouveau/include/nvif/event.h @@ -1,63 +1,36 @@ /* SPDX-License-Identifier: MIT */ #ifndef __NVIF_EVENT_H__ #define __NVIF_EVENT_H__ - -struct nvif_notify_req_v0 { - __u8 version; - __u8 reply; - __u8 pad02[5]; -#define NVIF_NOTIFY_V0_ROUTE_NVIF 0x00 - __u8 route; - __u64 token; /* must be unique */ - __u8 data[]; /* request data (below) */ -}; - -struct nvif_notify_rep_v0 { - __u8 version; - __u8 pad01[6]; - __u8 route; - __u64 token; - __u8 data[]; /* reply data (below) */ -}; - -struct nvif_notify_head_req_v0 { - /* nvif_notify_req ... */ - __u8 version; - __u8 head; - __u8 pad02[6]; -}; - -struct nvif_notify_head_rep_v0 { - /* nvif_notify_rep ... */ - __u8 version; - __u8 pad01[7]; -}; - -struct nvif_notify_conn_req_v0 { - /* nvif_notify_req ... */ - __u8 version; -#define NVIF_NOTIFY_CONN_V0_PLUG 0x01 -#define NVIF_NOTIFY_CONN_V0_UNPLUG 0x02 -#define NVIF_NOTIFY_CONN_V0_IRQ 0x04 -#define NVIF_NOTIFY_CONN_V0_ANY 0x07 - __u8 mask; - __u8 conn; - __u8 pad03[5]; -}; - -struct nvif_notify_conn_rep_v0 { - /* nvif_notify_rep ... */ - __u8 version; - __u8 mask; - __u8 pad02[6]; -}; - -struct nvif_notify_uevent_req { - /* nvif_notify_req ... */ -}; - -struct nvif_notify_uevent_rep { - /* nvif_notify_rep ... */ -}; - +#include <nvif/object.h> +#include <nvif/if000e.h> +struct nvif_event; + +#define NVIF_EVENT_KEEP 0 +#define NVIF_EVENT_DROP 1 +typedef int (*nvif_event_func)(struct nvif_event *, void *repv, u32 repc); + +struct nvif_event { + struct nvif_object object; + nvif_event_func func; +}; + +static inline bool +nvif_event_constructed(struct nvif_event *event) +{ + return nvif_object_constructed(&event->object); +} + +int nvif_event_ctor_(struct nvif_object *, const char *, u32, nvif_event_func, bool, + struct nvif_event_v0 *, u32, bool, struct nvif_event *); + +static inline int +nvif_event_ctor(struct nvif_object *parent, const char *name, u32 handle, nvif_event_func func, + bool wait, struct nvif_event_v0 *args, u32 argc, struct nvif_event *event) +{ + return nvif_event_ctor_(parent, name, handle, func, wait, args, argc, true, event); +} + +void nvif_event_dtor(struct nvif_event *); +int nvif_event_allow(struct nvif_event *); +int nvif_event_block(struct nvif_event *); #endif diff --git a/drivers/gpu/drm/nouveau/include/nvif/head.h b/drivers/gpu/drm/nouveau/include/nvif/head.h new file mode 100644 index 000000000000..3ec36999e956 --- /dev/null +++ b/drivers/gpu/drm/nouveau/include/nvif/head.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: MIT */ +#ifndef __NVIF_HEAD_H__ +#define __NVIF_HEAD_H__ +#include <nvif/object.h> +#include <nvif/event.h> +struct nvif_disp; + +struct nvif_head { + struct nvif_object object; +}; + +int nvif_head_ctor(struct nvif_disp *, const char *name, int id, struct nvif_head *); +void nvif_head_dtor(struct nvif_head *); + +static inline int +nvif_head_id(struct nvif_head *head) +{ + return head->object.handle; +} + +int nvif_head_vblank_event_ctor(struct nvif_head *, const char *name, nvif_event_func, bool wait, + struct nvif_event *); +#endif diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0004.h b/drivers/gpu/drm/nouveau/include/nvif/if0004.h index d324c73c27fb..1d916a137941 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/if0004.h +++ b/drivers/gpu/drm/nouveau/include/nvif/if0004.h @@ -2,7 +2,10 @@ #ifndef __NVIF_IF0004_H__ #define __NVIF_IF0004_H__ -#define NV04_NVSW_NTFY_UEVENT 0x00 +union nv04_nvsw_event_args { + struct nv04_nvsw_event_vn { + } vn; +}; #define NV04_NVSW_GET_REF 0x00 diff --git a/drivers/gpu/drm/nouveau/include/nvif/if000e.h b/drivers/gpu/drm/nouveau/include/nvif/if000e.h new file mode 100644 index 000000000000..90a936cb1766 --- /dev/null +++ b/drivers/gpu/drm/nouveau/include/nvif/if000e.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: MIT */ +#ifndef __NVIF_IF000E_H__ +#define __NVIF_IF000E_H__ + +union nvif_event_args { + struct nvif_event_v0 { + __u8 version; + __u8 wait; + __u8 pad02[6]; + __u8 data[]; + } v0; +}; + +#define NVIF_EVENT_V0_ALLOW 0x00 +#define NVIF_EVENT_V0_BLOCK 0x01 + +union nvif_event_allow_args { + struct nvif_event_allow_vn { + } vn; +}; + +union nvif_event_block_args { + struct nvif_event_block_vn { + } vn; +}; +#endif diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0010.h b/drivers/gpu/drm/nouveau/include/nvif/if0010.h index fc236ef28965..4c835bbe6fe3 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/if0010.h +++ b/drivers/gpu/drm/nouveau/include/nvif/if0010.h @@ -8,6 +8,7 @@ union nvif_disp_args { __u8 pad01[3]; __u32 conn_mask; __u32 outp_mask; + __u32 head_mask; } v0; }; #endif diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0011.h b/drivers/gpu/drm/nouveau/include/nvif/if0011.h index 04ba6581f840..69b0b779f942 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/if0011.h +++ b/drivers/gpu/drm/nouveau/include/nvif/if0011.h @@ -10,6 +10,17 @@ union nvif_conn_args { } v0; }; +union nvif_conn_event_args { + struct nvif_conn_event_v0 { + __u8 version; +#define NVIF_CONN_EVENT_V0_PLUG 0x01 +#define NVIF_CONN_EVENT_V0_UNPLUG 0x02 +#define NVIF_CONN_EVENT_V0_IRQ 0x04 + __u8 types; + __u8 pad02[6]; + } v0; +}; + #define NVIF_CONN_V0_HPD_STATUS 0x00000000 union nvif_conn_hpd_status_args { diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0012.h b/drivers/gpu/drm/nouveau/include/nvif/if0012.h index 243bd35d942f..eb99d84eb844 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/if0012.h +++ b/drivers/gpu/drm/nouveau/include/nvif/if0012.h @@ -11,6 +11,13 @@ union nvif_outp_args { }; #define NVIF_OUTP_V0_LOAD_DETECT 0x00 +#define NVIF_OUTP_V0_ACQUIRE 0x01 +#define NVIF_OUTP_V0_RELEASE 0x02 +#define NVIF_OUTP_V0_INFOFRAME 0x03 +#define NVIF_OUTP_V0_HDA_ELD 0x04 +#define NVIF_OUTP_V0_DP_AUX_PWR 0x05 +#define NVIF_OUTP_V0_DP_RETRAIN 0x06 +#define NVIF_OUTP_V0_DP_MST_VCPI 0x07 union nvif_outp_load_detect_args { struct nvif_outp_load_detect_v0 { @@ -20,4 +27,95 @@ union nvif_outp_load_detect_args { __u32 data; /*TODO: move vbios loadval parsing into nvkm */ } v0; }; + +union nvif_outp_acquire_args { + struct nvif_outp_acquire_v0 { + __u8 version; +#define NVIF_OUTP_ACQUIRE_V0_RGB_CRT 0x00 +#define NVIF_OUTP_ACQUIRE_V0_TV 0x01 +#define NVIF_OUTP_ACQUIRE_V0_TMDS 0x02 +#define NVIF_OUTP_ACQUIRE_V0_LVDS 0x03 +#define NVIF_OUTP_ACQUIRE_V0_DP 0x04 + __u8 proto; + __u8 or; + __u8 link; + __u8 pad04[4]; + union { + struct { + __u8 head; + __u8 hdmi; + __u8 hdmi_max_ac_packet; + __u8 hdmi_rekey; +#define NVIF_OUTP_ACQUIRE_V0_TMDS_HDMI_SCDC_SCRAMBLE (1 << 0) +#define NVIF_OUTP_ACQUIRE_V0_TMDS_HDMI_SCDC_DIV_BY_4 (1 << 1) + __u8 hdmi_scdc; + __u8 hdmi_hda; + __u8 pad06[2]; + } tmds; + struct { + __u8 dual; + __u8 bpc8; + __u8 pad02[6]; + } lvds; + struct { + __u8 link_nr; /* 0 = highest possible. */ + __u8 link_bw; /* 0 = highest possible, DP BW code otherwise. */ + __u8 hda; + __u8 mst; + __u8 pad04[4]; + __u8 dpcd[16]; + } dp; + }; + } v0; +}; + +union nvif_outp_release_args { + struct nvif_outp_release_vn { + } vn; +}; + +union nvif_outp_infoframe_args { + struct nvif_outp_infoframe_v0 { + __u8 version; +#define NVIF_OUTP_INFOFRAME_V0_AVI 0 +#define NVIF_OUTP_INFOFRAME_V0_VSI 1 + __u8 type; + __u8 head; + __u8 pad03[5]; + __u8 data[]; + } v0; +}; + +union nvif_outp_hda_eld_args { + struct nvif_outp_hda_eld_v0 { + __u8 version; + __u8 head; + __u8 pad02[6]; + __u8 data[]; + } v0; +}; + +union nvif_outp_dp_aux_pwr_args { + struct nvif_outp_dp_aux_pwr_v0 { + __u8 version; + __u8 state; + __u8 pad02[6]; + } v0; +}; + +union nvif_outp_dp_retrain_args { + struct nvif_outp_dp_retrain_vn { + } vn; +}; + +union nvif_outp_dp_mst_vcpi_args { + struct nvif_outp_dp_mst_vcpi_v0 { + __u8 version; + __u8 head; + __u8 start_slot; + __u8 num_slots; + __u16 pbn; + __u16 aligned_pbn; + } v0; +}; #endif diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0013.h b/drivers/gpu/drm/nouveau/include/nvif/if0013.h new file mode 100644 index 000000000000..6756c7467ae4 --- /dev/null +++ b/drivers/gpu/drm/nouveau/include/nvif/if0013.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: MIT */ +#ifndef __NVIF_IF0013_H__ +#define __NVIF_IF0013_H__ + +union nvif_head_args { + struct nvif_head_v0 { + __u8 version; + __u8 id; + __u8 pad02[6]; + } v0; +}; + +union nvif_head_event_args { + struct nvif_head_event_vn { + } vn; +}; + +#define NVIF_HEAD_V0_SCANOUTPOS 0x00 + +union nvif_head_scanoutpos_args { + struct nvif_head_scanoutpos_v0 { + __u8 version; + __u8 pad01[7]; + __s64 time[2]; + __u16 vblanks; + __u16 vblanke; + __u16 vtotal; + __u16 vline; + __u16 hblanks; + __u16 hblanke; + __u16 htotal; + __u16 hline; + } v0; +}; +#endif diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0020.h b/drivers/gpu/drm/nouveau/include/nvif/if0020.h new file mode 100644 index 000000000000..085e0ae8a450 --- /dev/null +++ b/drivers/gpu/drm/nouveau/include/nvif/if0020.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: MIT */ +#ifndef __NVIF_IF0020_H__ +#define __NVIF_IF0020_H__ + +union nvif_chan_args { + struct nvif_chan_v0 { + __u8 version; + __u8 namelen; + __u8 runlist; + __u8 runq; + __u8 priv; + __u8 pad05; + __u16 devm; + __u64 vmm; + + __u64 ctxdma; + __u64 offset; + __u64 length; + + __u64 huserd; + __u64 ouserd; + + __u32 token; + __u16 chid; + __u8 pad3e; +#define NVIF_CHAN_V0_INST_APER_VRAM 0 +#define NVIF_CHAN_V0_INST_APER_HOST 1 +#define NVIF_CHAN_V0_INST_APER_NCOH 2 +#define NVIF_CHAN_V0_INST_APER_INST 0xff + __u8 aper; + __u64 inst; + + __u8 name[]; + } v0; +}; + +union nvif_chan_event_args { + struct nvif_chan_event_v0 { + __u8 version; +#define NVIF_CHAN_EVENT_V0_NON_STALL_INTR 0x00 +#define NVIF_CHAN_EVENT_V0_KILLED 0x01 + __u8 type; + } v0; +}; +#endif diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0021.h b/drivers/gpu/drm/nouveau/include/nvif/if0021.h new file mode 100644 index 000000000000..5013def90455 --- /dev/null +++ b/drivers/gpu/drm/nouveau/include/nvif/if0021.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: MIT */ +#ifndef __NVIF_IF0021_H__ +#define __NVIF_IF0021_H__ + +union nvif_cgrp_args { + struct nvif_cgrp_v0 { + __u8 version; + __u8 namelen; + __u8 runlist; + __u8 pad03[3]; + __u16 cgid; + __u64 vmm; + __u8 name[]; + } v0; +}; +#endif diff --git a/drivers/gpu/drm/nouveau/include/nvif/ioctl.h b/drivers/gpu/drm/nouveau/include/nvif/ioctl.h index 886c63fe753f..4e047bb1fc07 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/ioctl.h +++ b/drivers/gpu/drm/nouveau/include/nvif/ioctl.h @@ -15,10 +15,6 @@ struct nvif_ioctl_v0 { #define NVIF_IOCTL_V0_WR 0x06 #define NVIF_IOCTL_V0_MAP 0x07 #define NVIF_IOCTL_V0_UNMAP 0x08 -#define NVIF_IOCTL_V0_NTFY_NEW 0x09 -#define NVIF_IOCTL_V0_NTFY_DEL 0x0a -#define NVIF_IOCTL_V0_NTFY_GET 0x0b -#define NVIF_IOCTL_V0_NTFY_PUT 0x0c __u8 type; __u8 pad02[4]; #define NVIF_IOCTL_V0_OWNER_NVIF 0x00 @@ -63,6 +59,14 @@ struct nvif_ioctl_new_v0 { struct nvif_ioctl_del { }; +struct nvif_ioctl_mthd_v0 { + /* nvif_ioctl ... */ + __u8 version; + __u8 method; + __u8 pad02[6]; + __u8 data[]; /* method data (class.h) */ +}; + struct nvif_ioctl_rd_v0 { /* nvif_ioctl ... */ __u8 version; @@ -95,43 +99,4 @@ struct nvif_ioctl_map_v0 { struct nvif_ioctl_unmap { }; - -struct nvif_ioctl_ntfy_new_v0 { - /* nvif_ioctl ... */ - __u8 version; - __u8 event; - __u8 index; - __u8 pad03[5]; - __u8 data[]; /* event request data (event.h) */ -}; - -struct nvif_ioctl_ntfy_del_v0 { - /* nvif_ioctl ... */ - __u8 version; - __u8 index; - __u8 pad02[6]; -}; - -struct nvif_ioctl_ntfy_get_v0 { - /* nvif_ioctl ... */ - __u8 version; - __u8 index; - __u8 pad02[6]; -}; - -struct nvif_ioctl_ntfy_put_v0 { - /* nvif_ioctl ... */ - __u8 version; - __u8 index; - __u8 pad02[6]; -}; - -struct nvif_ioctl_mthd_v0 { - /* nvif_ioctl ... */ - __u8 version; - __u8 method; - __u8 pad02[6]; - __u8 data[]; /* method data (class.h) */ -}; - #endif diff --git a/drivers/gpu/drm/nouveau/include/nvif/notify.h b/drivers/gpu/drm/nouveau/include/nvif/notify.h deleted file mode 100644 index 39f6b7ee1719..000000000000 --- a/drivers/gpu/drm/nouveau/include/nvif/notify.h +++ /dev/null @@ -1,35 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -#ifndef __NVIF_NOTIFY_H__ -#define __NVIF_NOTIFY_H__ - -struct nvif_notify { - struct nvif_object *object; - const char *name; - int index; - -#define NVIF_NOTIFY_USER 0 -#define NVIF_NOTIFY_WORK 1 - unsigned long flags; - atomic_t putcnt; - void (*dtor)(struct nvif_notify *); -#define NVIF_NOTIFY_DROP 0 -#define NVIF_NOTIFY_KEEP 1 - int (*func)(struct nvif_notify *); - - /* this is const for a *very* good reason - the data might be on the - * stack from an irq handler. if you're not nvif/notify.c then you - * should probably think twice before casting it away... - */ - const void *data; - u32 size; - struct work_struct work; -}; - -int nvif_notify_ctor(struct nvif_object *, const char *name, - int (*func)(struct nvif_notify *), bool work, u8 type, - void *data, u32 size, u32 reply, struct nvif_notify *); -int nvif_notify_dtor(struct nvif_notify *); -int nvif_notify_get(struct nvif_notify *); -int nvif_notify_put(struct nvif_notify *); -int nvif_notify(const void *, u32, const void *, u32); -#endif diff --git a/drivers/gpu/drm/nouveau/include/nvif/outp.h b/drivers/gpu/drm/nouveau/include/nvif/outp.h index 0d6aa07a9184..45daadec3c0c 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/outp.h +++ b/drivers/gpu/drm/nouveau/include/nvif/outp.h @@ -2,13 +2,32 @@ #ifndef __NVIF_OUTP_H__ #define __NVIF_OUTP_H__ #include <nvif/object.h> +#include <nvif/if0012.h> struct nvif_disp; struct nvif_outp { struct nvif_object object; + + struct { + int id; + int link; + } or; }; int nvif_outp_ctor(struct nvif_disp *, const char *name, int id, struct nvif_outp *); void nvif_outp_dtor(struct nvif_outp *); int nvif_outp_load_detect(struct nvif_outp *, u32 loadval); +int nvif_outp_acquire_rgb_crt(struct nvif_outp *); +int nvif_outp_acquire_tmds(struct nvif_outp *, int head, + bool hdmi, u8 max_ac_packet, u8 rekey, u8 scdc, bool hda); +int nvif_outp_acquire_lvds(struct nvif_outp *, bool dual, bool bpc8); +int nvif_outp_acquire_dp(struct nvif_outp *, u8 dpcd[16], + int link_nr, int link_bw, bool hda, bool mst); +void nvif_outp_release(struct nvif_outp *); +int nvif_outp_infoframe(struct nvif_outp *, u8 type, struct nvif_outp_infoframe_v0 *, u32 size); +int nvif_outp_hda_eld(struct nvif_outp *, int head, void *data, u32 size); +int nvif_outp_dp_aux_pwr(struct nvif_outp *, bool enable); +int nvif_outp_dp_retrain(struct nvif_outp *); +int nvif_outp_dp_mst_vcpi(struct nvif_outp *, int head, + u8 start_slot, u8 num_slots, u16 pbn, u16 aligned_pbn); #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/client.h b/drivers/gpu/drm/nouveau/include/nvkm/core/client.h index 2f86606e708c..0d9fc741a719 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/client.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/client.h @@ -10,28 +10,19 @@ struct nvkm_client { u64 device; u32 debug; - struct nvkm_client_notify *notify[32]; struct rb_root objroot; void *data; - int (*ntfy)(const void *, u32, const void *, u32); + int (*event)(u64 token, void *argv, u32 argc); struct list_head umem; spinlock_t lock; }; -int nvkm_client_new(const char *name, u64 device, const char *cfg, - const char *dbg, - int (*)(const void *, u32, const void *, u32), - struct nvkm_client **); +int nvkm_client_new(const char *name, u64 device, const char *cfg, const char *dbg, + int (*)(u64, void *, u32), struct nvkm_client **); struct nvkm_client *nvkm_client_search(struct nvkm_client *, u64 handle); -int nvkm_client_notify_new(struct nvkm_object *, struct nvkm_event *, - void *data, u32 size); -int nvkm_client_notify_del(struct nvkm_client *, int index); -int nvkm_client_notify_get(struct nvkm_client *, int index); -int nvkm_client_notify_put(struct nvkm_client *, int index); - /* logging for client-facing objects */ #define nvif_printk(o,l,p,f,a...) do { \ const struct nvkm_object *_object = (o); \ diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h index efede1f11e1d..f65b5009acf7 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h @@ -2,6 +2,7 @@ #ifndef __NVKM_DEVICE_H__ #define __NVKM_DEVICE_H__ #include <core/oclass.h> +#include <core/intr.h> enum nvkm_subdev_type; enum nvkm_device_type { @@ -60,6 +61,16 @@ struct nvkm_device { #undef NVKM_LAYOUT_INST #undef NVKM_LAYOUT_ONCE struct list_head subdev; + + struct { + struct list_head intr; + struct list_head prio[NVKM_INTR_PRIO_NR]; + spinlock_t lock; + int irq; + bool alloc; + bool armed; + bool legacy_done; + } intr; }; struct nvkm_subdev *nvkm_device_subdev(struct nvkm_device *, int type, int inst); @@ -72,6 +83,7 @@ struct nvkm_device_func { int (*preinit)(struct nvkm_device *); int (*init)(struct nvkm_device *); void (*fini)(struct nvkm_device *, bool suspend); + int (*irq)(struct nvkm_device *); resource_size_t (*resource_addr)(struct nvkm_device *, unsigned bar); resource_size_t (*resource_size)(struct nvkm_device *, unsigned bar); bool cpu_coherent; diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h b/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h index e58923b67d74..b67b9c1a6b4e 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h @@ -12,12 +12,6 @@ struct nvkm_engine { const struct nvkm_engine_func *func; struct nvkm_subdev subdev; spinlock_t lock; - - struct { - refcount_t refcount; - struct mutex mutex; - bool enabled; - } use; }; struct nvkm_engine_func { @@ -27,6 +21,7 @@ struct nvkm_engine_func { int (*info)(struct nvkm_engine *, u64 mthd, u64 *data); int (*init)(struct nvkm_engine *); int (*fini)(struct nvkm_engine *, bool suspend); + int (*reset)(struct nvkm_engine *); void (*intr)(struct nvkm_engine *); void (*tile)(struct nvkm_engine *, int region, struct nvkm_fb_tile *); bool (*chsw_load)(struct nvkm_engine *); @@ -54,6 +49,7 @@ int nvkm_engine_new_(const struct nvkm_engine_func *, struct nvkm_device *, struct nvkm_engine *nvkm_engine_ref(struct nvkm_engine *); void nvkm_engine_unref(struct nvkm_engine **); +int nvkm_engine_reset(struct nvkm_engine *); void nvkm_engine_tile(struct nvkm_engine *, int region); bool nvkm_engine_chsw_load(struct nvkm_engine *); #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/event.h b/drivers/gpu/drm/nouveau/include/nvkm/core/event.h index a7a413f07a78..82b267c11147 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/event.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/event.h @@ -2,34 +2,76 @@ #ifndef __NVKM_EVENT_H__ #define __NVKM_EVENT_H__ #include <core/os.h> -struct nvkm_notify; struct nvkm_object; +struct nvkm_oclass; +struct nvkm_uevent; struct nvkm_event { const struct nvkm_event_func *func; + struct nvkm_subdev *subdev; int types_nr; int index_nr; spinlock_t refs_lock; spinlock_t list_lock; - struct list_head list; int *refs; + + struct list_head ntfy; }; struct nvkm_event_func { - int (*ctor)(struct nvkm_object *, void *data, u32 size, - struct nvkm_notify *); - void (*send)(void *data, u32 size, struct nvkm_notify *); void (*init)(struct nvkm_event *, int type, int index); void (*fini)(struct nvkm_event *, int type, int index); }; -int nvkm_event_init(const struct nvkm_event_func *func, int types_nr, - int index_nr, struct nvkm_event *); +int __nvkm_event_init(const struct nvkm_event_func *func, struct nvkm_subdev *, int types_nr, + int index_nr, struct nvkm_event *); + +/* Each nvkm_event needs its own lockdep class due to inter-dependencies, to + * prevent lockdep false-positives. + * + * Inlining the spinlock initialisation ensures each is unique. + */ +static __always_inline int +nvkm_event_init(const struct nvkm_event_func *func, struct nvkm_subdev *subdev, + int types_nr, int index_nr, struct nvkm_event *event) +{ + spin_lock_init(&event->refs_lock); + spin_lock_init(&event->list_lock); + return __nvkm_event_init(func, subdev, types_nr, index_nr, event); +} + void nvkm_event_fini(struct nvkm_event *); -void nvkm_event_get(struct nvkm_event *, u32 types, int index); -void nvkm_event_put(struct nvkm_event *, u32 types, int index); -void nvkm_event_send(struct nvkm_event *, u32 types, int index, - void *data, u32 size); + +#define NVKM_EVENT_KEEP 0 +#define NVKM_EVENT_DROP 1 +struct nvkm_event_ntfy; +typedef int (*nvkm_event_func)(struct nvkm_event_ntfy *, u32 bits); + +struct nvkm_event_ntfy { + struct nvkm_event *event; + int id; + u32 bits; + bool wait; + nvkm_event_func func; + + atomic_t allowed; + bool running; + + struct list_head head; +}; + +void nvkm_event_ntfy(struct nvkm_event *, int id, u32 bits); +bool nvkm_event_ntfy_valid(struct nvkm_event *, int id, u32 bits); +void nvkm_event_ntfy_add(struct nvkm_event *, int id, u32 bits, bool wait, nvkm_event_func, + struct nvkm_event_ntfy *); +void nvkm_event_ntfy_del(struct nvkm_event_ntfy *); +void nvkm_event_ntfy_allow(struct nvkm_event_ntfy *); +void nvkm_event_ntfy_block(struct nvkm_event_ntfy *); + +typedef int (*nvkm_uevent_func)(struct nvkm_object *, u64 token, u32 bits); + +int nvkm_uevent_new(const struct nvkm_oclass *, void *argv, u32 argc, struct nvkm_object **); +int nvkm_uevent_add(struct nvkm_uevent *, struct nvkm_event *, int id, u32 bits, nvkm_uevent_func); #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/falcon.h b/drivers/gpu/drm/nouveau/include/nvkm/core/falcon.h index fd9a3f9a518e..b857cf142c4a 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/falcon.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/falcon.h @@ -1,34 +1,166 @@ #ifndef __NVKM_FALCON_H__ #define __NVKM_FALCON_H__ +#include <core/firmware.h> #include <engine/falcon.h> +enum nvkm_falcon_mem { + IMEM, + DMEM, + EMEM, +}; + +static inline const char * +nvkm_falcon_mem(enum nvkm_falcon_mem mem) +{ + switch (mem) { + case IMEM: return "imem"; + case DMEM: return "dmem"; + case EMEM: return "emem"; + default: + WARN_ON(1); + return "?mem"; + } +} + +struct nvkm_falcon_func_pio { + int min; + int max; + void (*wr_init)(struct nvkm_falcon *, u8 port, bool sec, u32 mem_base); + void (*wr)(struct nvkm_falcon *, u8 port, const u8 *img, int len, u16 tag); + void (*rd_init)(struct nvkm_falcon *, u8 port, u32 mem_base); + void (*rd)(struct nvkm_falcon *, u8 port, const u8 *img, int len); +}; + +struct nvkm_falcon_func_dma { + int (*init)(struct nvkm_falcon *, u64 dma_addr, int xfer_len, + enum nvkm_falcon_mem, bool sec, u32 *cmd); + void (*xfer)(struct nvkm_falcon *, u32 mem_base, u32 dma_base, u32 cmd); + bool (*done)(struct nvkm_falcon *); +}; + int nvkm_falcon_ctor(const struct nvkm_falcon_func *, struct nvkm_subdev *owner, const char *name, u32 addr, struct nvkm_falcon *); void nvkm_falcon_dtor(struct nvkm_falcon *); +int nvkm_falcon_reset(struct nvkm_falcon *); +int nvkm_falcon_pio_wr(struct nvkm_falcon *, const u8 *img, u32 img_base, u8 port, + enum nvkm_falcon_mem mem_type, u32 mem_base, int len, u16 tag, bool sec); +int nvkm_falcon_pio_rd(struct nvkm_falcon *, u8 port, enum nvkm_falcon_mem type, u32 mem_base, + const u8 *img, u32 img_base, int len); +int nvkm_falcon_dma_wr(struct nvkm_falcon *, const u8 *img, u64 dma_addr, u32 dma_base, + enum nvkm_falcon_mem mem_type, u32 mem_base, int len, bool sec); + +int gm200_flcn_reset_wait_mem_scrubbing(struct nvkm_falcon *); +int gm200_flcn_disable(struct nvkm_falcon *); +int gm200_flcn_enable(struct nvkm_falcon *); +void gm200_flcn_bind_inst(struct nvkm_falcon *, int, u64); +int gm200_flcn_bind_stat(struct nvkm_falcon *, bool); +extern const struct nvkm_falcon_func_pio gm200_flcn_imem_pio; +extern const struct nvkm_falcon_func_pio gm200_flcn_dmem_pio; +void gm200_flcn_tracepc(struct nvkm_falcon *); + +int gp102_flcn_reset_eng(struct nvkm_falcon *); +extern const struct nvkm_falcon_func_pio gp102_flcn_emem_pio; + +int ga102_flcn_select(struct nvkm_falcon *); +int ga102_flcn_reset_prep(struct nvkm_falcon *); +int ga102_flcn_reset_wait_mem_scrubbing(struct nvkm_falcon *); +extern const struct nvkm_falcon_func_dma ga102_flcn_dma; void nvkm_falcon_v1_load_imem(struct nvkm_falcon *, void *, u32, u32, u16, u8, bool); void nvkm_falcon_v1_load_dmem(struct nvkm_falcon *, void *, u32, u32, u8); -void nvkm_falcon_v1_read_dmem(struct nvkm_falcon *, u32, u32, u8, void *); -void nvkm_falcon_v1_bind_context(struct nvkm_falcon *, struct nvkm_memory *); -int nvkm_falcon_v1_wait_for_halt(struct nvkm_falcon *, u32); -int nvkm_falcon_v1_clear_interrupt(struct nvkm_falcon *, u32); -void nvkm_falcon_v1_set_start_addr(struct nvkm_falcon *, u32 start_addr); void nvkm_falcon_v1_start(struct nvkm_falcon *); -int nvkm_falcon_v1_enable(struct nvkm_falcon *); -void nvkm_falcon_v1_disable(struct nvkm_falcon *); -void gp102_sec2_flcn_bind_context(struct nvkm_falcon *, struct nvkm_memory *); -int gp102_sec2_flcn_enable(struct nvkm_falcon *); +#define FLCN_PRINTK(f,l,p,fmt,a...) ({ \ + if ((f)->owner->name != (f)->name) \ + nvkm_printk___((f)->owner, (f)->user, NV_DBG_##l, p, "%s:"fmt, (f)->name, ##a); \ + else \ + nvkm_printk___((f)->owner, (f)->user, NV_DBG_##l, p, fmt, ##a); \ +}) +#define FLCN_DBG(f,fmt,a...) FLCN_PRINTK((f), DEBUG, info, " "fmt"\n", ##a) +#define FLCN_ERR(f,fmt,a...) FLCN_PRINTK((f), ERROR, err, " "fmt"\n", ##a) +#define FLCN_ERRON(f,c,fmt,a...) \ + ({ bool _cond = (c); _cond ? FLCN_ERR(f, fmt, ##a) : FLCN_DBG(f, fmt, ##a); _cond; }) + + +struct nvkm_falcon_fw { + const struct nvkm_falcon_fw_func { + int (*signature)(struct nvkm_falcon_fw *, u32 *sig_base_src); + int (*reset)(struct nvkm_falcon_fw *); + int (*setup)(struct nvkm_falcon_fw *); + int (*load)(struct nvkm_falcon_fw *); + int (*load_bld)(struct nvkm_falcon_fw *); + int (*boot)(struct nvkm_falcon_fw *, + u32 *mbox0, u32 *mbox1, u32 mbox0_ok, u32 irqsclr); + } *func; + struct nvkm_firmware fw; + + u32 sig_base_prd; + u32 sig_base_dbg; + u32 sig_base_img; + u32 sig_size; + int sig_nr; + u8 *sigs; + u32 fuse_ver; + u32 engine_id; + u32 ucode_id; + + u32 nmem_base_img; + u32 nmem_base; + u32 nmem_size; + + u32 imem_base_img; + u32 imem_base; + u32 imem_size; + + u32 dmem_base_img; + u32 dmem_base; + u32 dmem_size; + u32 dmem_sign; + + u8 *boot; + u32 boot_size; + u32 boot_addr; + + struct nvkm_falcon *falcon; + struct nvkm_memory *inst; + struct nvkm_vmm *vmm; + struct nvkm_vma *vma; +}; + +int nvkm_falcon_fw_ctor(const struct nvkm_falcon_fw_func *, const char *name, struct nvkm_device *, + bool bl, const void *src, u32 len, struct nvkm_falcon *, + struct nvkm_falcon_fw *); +int nvkm_falcon_fw_ctor_hs(const struct nvkm_falcon_fw_func *, const char *name, + struct nvkm_subdev *, const char *bl, const char *img, int ver, + struct nvkm_falcon *falcon, struct nvkm_falcon_fw *fw); +int nvkm_falcon_fw_ctor_hs_v2(const struct nvkm_falcon_fw_func *, const char *name, + struct nvkm_subdev *, const char *img, int ver, struct nvkm_falcon *, + struct nvkm_falcon_fw *); +int nvkm_falcon_fw_sign(struct nvkm_falcon_fw *, u32 sig_base_img, u32 sig_size, const u8 *sigs, + int sig_nr_prd, u32 sig_base_prd, int sig_nr_dbg, u32 sig_base_dbg); +int nvkm_falcon_fw_patch(struct nvkm_falcon_fw *); +void nvkm_falcon_fw_dtor(struct nvkm_falcon_fw *); +int nvkm_falcon_fw_oneinit(struct nvkm_falcon_fw *, struct nvkm_falcon *, struct nvkm_vmm *, + struct nvkm_memory *inst); +int nvkm_falcon_fw_boot(struct nvkm_falcon_fw *, struct nvkm_subdev *user, + bool release, u32 *pmbox0, u32 *pmbox1, u32 mbox0_ok, u32 irqsclr); + +extern const struct nvkm_falcon_fw_func gm200_flcn_fw; +int gm200_flcn_fw_signature(struct nvkm_falcon_fw *, u32 *); +int gm200_flcn_fw_reset(struct nvkm_falcon_fw *); +int gm200_flcn_fw_load(struct nvkm_falcon_fw *); +int gm200_flcn_fw_boot(struct nvkm_falcon_fw *, u32 *, u32 *, u32, u32); + +int ga100_flcn_fw_signature(struct nvkm_falcon_fw *, u32 *); + +extern const struct nvkm_falcon_fw_func ga102_flcn_fw; +int ga102_flcn_fw_load(struct nvkm_falcon_fw *); +int ga102_flcn_fw_boot(struct nvkm_falcon_fw *, u32 *, u32 *, u32, u32); -#define FLCN_PRINTK(t,f,fmt,a...) do { \ - if ((f)->owner->name != (f)->name) \ - nvkm_##t((f)->owner, "%s: "fmt"\n", (f)->name, ##a); \ - else \ - nvkm_##t((f)->owner, fmt"\n", ##a); \ -} while(0) -#define FLCN_DBG(f,fmt,a...) FLCN_PRINTK(debug, (f), fmt, ##a) -#define FLCN_ERR(f,fmt,a...) FLCN_PRINTK(error, (f), fmt, ##a) +#define FLCNFW_PRINTK(f,l,p,fmt,a...) FLCN_PRINTK((f)->falcon, l, p, "%s: "fmt, (f)->fw.name, ##a) +#define FLCNFW_DBG(f,fmt,a...) FLCNFW_PRINTK((f), DEBUG, info, fmt"\n", ##a) +#define FLCNFW_ERR(f,fmt,a...) FLCNFW_PRINTK((f), ERROR, err, fmt"\n", ##a) /** * struct nvfw_falcon_msg - header for all messages @@ -72,6 +204,7 @@ int nvkm_falcon_msgq_new(struct nvkm_falcon_qmgr *, const char *name, void nvkm_falcon_msgq_del(struct nvkm_falcon_msgq **); void nvkm_falcon_msgq_init(struct nvkm_falcon_msgq *, u32 index, u32 offset, u32 size); +bool nvkm_falcon_msgq_empty(struct nvkm_falcon_msgq *); int nvkm_falcon_msgq_recv_initmsg(struct nvkm_falcon_msgq *, void *, u32 size); void nvkm_falcon_msgq_recv(struct nvkm_falcon_msgq *); #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/firmware.h b/drivers/gpu/drm/nouveau/include/nvkm/core/firmware.h index 85bcb80f6873..d4e507e252b1 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/firmware.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/firmware.h @@ -1,9 +1,34 @@ /* SPDX-License-Identifier: MIT */ #ifndef __NVKM_FIRMWARE_H__ #define __NVKM_FIRMWARE_H__ +#include <core/memory.h> #include <core/option.h> #include <core/subdev.h> +struct nvkm_firmware { + const struct nvkm_firmware_func { + enum nvkm_firmware_type { + NVKM_FIRMWARE_IMG_RAM, + NVKM_FIRMWARE_IMG_DMA, + } type; + } *func; + const char *name; + struct nvkm_device *device; + + int len; + u8 *img; + u64 phys; + + struct nvkm_firmware_mem { + struct nvkm_memory memory; + struct scatterlist sgl; + } mem; +}; + +int nvkm_firmware_ctor(const struct nvkm_firmware_func *, const char *name, struct nvkm_device *, + const void *ptr, int len, struct nvkm_firmware *); +void nvkm_firmware_dtor(struct nvkm_firmware *); + int nvkm_firmware_get(const struct nvkm_subdev *, const char *fwname, int ver, const struct firmware **); void nvkm_firmware_put(const struct firmware *); diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/intr.h b/drivers/gpu/drm/nouveau/include/nvkm/core/intr.h new file mode 100644 index 000000000000..a003d6a544b0 --- /dev/null +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/intr.h @@ -0,0 +1,73 @@ +/* SPDX-License-Identifier: MIT */ +#ifndef __NVKM_INTR_H__ +#define __NVKM_INTR_H__ +#include <core/os.h> +struct nvkm_device; +struct nvkm_subdev; + +enum nvkm_intr_prio { + NVKM_INTR_PRIO_VBLANK = 0, + NVKM_INTR_PRIO_NORMAL, + NVKM_INTR_PRIO_NR +}; + +enum nvkm_intr_type { + NVKM_INTR_SUBDEV = -1, /* lookup vector by requesting subdev, in mapping table. */ + NVKM_INTR_VECTOR_0 = 0, +}; + +struct nvkm_intr { + const struct nvkm_intr_func { + bool (*pending)(struct nvkm_intr *); + void (*unarm)(struct nvkm_intr *); + void (*rearm)(struct nvkm_intr *); + void (*block)(struct nvkm_intr *, int leaf, u32 mask); + void (*allow)(struct nvkm_intr *, int leaf, u32 mask); + void (*reset)(struct nvkm_intr *, int leaf, u32 mask); + } *func; + const struct nvkm_intr_data { + int type; /* enum nvkm_subdev_type (+ve), enum nvkm_intr_type (-ve) */ + int inst; + int leaf; + u32 mask; /* 0-terminated. */ + bool legacy; /* auto-create "legacy" nvkm_subdev_intr() handler */ + } *data; + + struct nvkm_subdev *subdev; + int leaves; + u32 *stat; + u32 *mask; + + struct list_head head; +}; + +void nvkm_intr_ctor(struct nvkm_device *); +void nvkm_intr_dtor(struct nvkm_device *); +int nvkm_intr_install(struct nvkm_device *); +void nvkm_intr_unarm(struct nvkm_device *); +void nvkm_intr_rearm(struct nvkm_device *); + +int nvkm_intr_add(const struct nvkm_intr_func *, const struct nvkm_intr_data *, + struct nvkm_subdev *, int leaves, struct nvkm_intr *); +void nvkm_intr_block(struct nvkm_subdev *, enum nvkm_intr_type); +void nvkm_intr_allow(struct nvkm_subdev *, enum nvkm_intr_type); + +struct nvkm_inth; +typedef irqreturn_t (*nvkm_inth_func)(struct nvkm_inth *); + +struct nvkm_inth { + struct nvkm_intr *intr; + int leaf; + u32 mask; + nvkm_inth_func func; + + atomic_t allowed; + + struct list_head head; +}; + +int nvkm_inth_add(struct nvkm_intr *, enum nvkm_intr_type, enum nvkm_intr_prio, + struct nvkm_subdev *, nvkm_inth_func, struct nvkm_inth *); +void nvkm_inth_allow(struct nvkm_inth *); +void nvkm_inth_block(struct nvkm_inth *); +#endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/layout.h b/drivers/gpu/drm/nouveau/include/nvkm/core/layout.h index 7afe1579b20f..58108dea5aeb 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/layout.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/layout.h @@ -1,8 +1,10 @@ /* SPDX-License-Identifier: MIT */ +NVKM_LAYOUT_ONCE(NVKM_SUBDEV_TOP , struct nvkm_top , top) +NVKM_LAYOUT_ONCE(NVKM_SUBDEV_GSP , struct nvkm_gsp , gsp) +NVKM_LAYOUT_ONCE(NVKM_SUBDEV_VFN , struct nvkm_vfn , vfn) NVKM_LAYOUT_ONCE(NVKM_SUBDEV_PCI , struct nvkm_pci , pci) NVKM_LAYOUT_ONCE(NVKM_SUBDEV_VBIOS , struct nvkm_bios , bios) NVKM_LAYOUT_ONCE(NVKM_SUBDEV_DEVINIT , struct nvkm_devinit , devinit) -NVKM_LAYOUT_ONCE(NVKM_SUBDEV_TOP , struct nvkm_top , top) NVKM_LAYOUT_ONCE(NVKM_SUBDEV_PRIVRING, struct nvkm_subdev , privring) NVKM_LAYOUT_ONCE(NVKM_SUBDEV_GPIO , struct nvkm_gpio , gpio) NVKM_LAYOUT_ONCE(NVKM_SUBDEV_I2C , struct nvkm_i2c , i2c) @@ -23,7 +25,6 @@ NVKM_LAYOUT_ONCE(NVKM_SUBDEV_VOLT , struct nvkm_volt , volt) NVKM_LAYOUT_ONCE(NVKM_SUBDEV_ICCSENSE, struct nvkm_iccsense, iccsense) NVKM_LAYOUT_ONCE(NVKM_SUBDEV_THERM , struct nvkm_therm , therm) NVKM_LAYOUT_ONCE(NVKM_SUBDEV_CLK , struct nvkm_clk , clk) -NVKM_LAYOUT_ONCE(NVKM_SUBDEV_GSP , struct nvkm_gsp , gsp) NVKM_LAYOUT_INST(NVKM_SUBDEV_IOCTRL , struct nvkm_subdev , ioctrl, 3) NVKM_LAYOUT_ONCE(NVKM_SUBDEV_FLA , struct nvkm_subdev , fla) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/memory.h b/drivers/gpu/drm/nouveau/include/nvkm/core/memory.h index 74d3f1a809d7..d3b6a68ddda3 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/memory.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/memory.h @@ -37,6 +37,7 @@ struct nvkm_memory_func { void (*release)(struct nvkm_memory *); int (*map)(struct nvkm_memory *, u64 offset, struct nvkm_vmm *, struct nvkm_vma *, void *argv, u32 argc); + int (*kmap)(struct nvkm_memory *, struct nvkm_memory **); }; struct nvkm_memory_ptrs { @@ -63,6 +64,7 @@ void nvkm_memory_tags_put(struct nvkm_memory *, struct nvkm_device *, #define nvkm_memory_boot(p,v) (p)->func->boot((p),(v)) #define nvkm_memory_map(p,o,vm,va,av,ac) \ (p)->func->map((p),(o),(vm),(va),(av),(ac)) +#define nvkm_memory_kmap(p,i) ((p)->func->kmap ? (p)->func->kmap((p), (i)) : -ENOSYS) /* accessor macros - kmap()/done() must bracket use of the other accessor * macros to guarantee correct behaviour across all chipsets diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/notify.h b/drivers/gpu/drm/nouveau/include/nvkm/core/notify.h deleted file mode 100644 index 3d358a66db3a..000000000000 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/notify.h +++ /dev/null @@ -1,39 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -#ifndef __NVKM_NOTIFY_H__ -#define __NVKM_NOTIFY_H__ -#include <core/os.h> -struct nvkm_object; - -struct nvkm_notify { - struct nvkm_event *event; - struct list_head head; -#define NVKM_NOTIFY_USER 0 -#define NVKM_NOTIFY_WORK 1 - unsigned long flags; - int block; -#define NVKM_NOTIFY_DROP 0 -#define NVKM_NOTIFY_KEEP 1 - int (*func)(struct nvkm_notify *); - - /* set by nvkm_event ctor */ - u32 types; - int index; - u32 size; - - struct work_struct work; - /* this is const for a *very* good reason - the data might be on the - * stack from an irq handler. if you're not core/notify.c then you - * should probably think twice before casting it away... - */ - const void *data; -}; - -int nvkm_notify_init(struct nvkm_object *, struct nvkm_event *, - int (*func)(struct nvkm_notify *), bool work, - void *data, u32 size, u32 reply, - struct nvkm_notify *); -void nvkm_notify_fini(struct nvkm_notify *); -void nvkm_notify_get(struct nvkm_notify *); -void nvkm_notify_put(struct nvkm_notify *); -void nvkm_notify_send(struct nvkm_notify *, void *data, u32 size); -#endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/object.h b/drivers/gpu/drm/nouveau/include/nvkm/core/object.h index 7efcd5d2f2ff..ed1f66360782 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/object.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/object.h @@ -4,6 +4,7 @@ #include <core/oclass.h> struct nvkm_event; struct nvkm_gpuobj; +struct nvkm_uevent; struct nvkm_object { const struct nvkm_object_func *func; @@ -43,6 +44,7 @@ struct nvkm_object_func { int (*bind)(struct nvkm_object *, struct nvkm_gpuobj *, int align, struct nvkm_gpuobj **); int (*sclass)(struct nvkm_object *, int index, struct nvkm_oclass *); + int (*uevent)(struct nvkm_object *, void *argv, u32 argc, struct nvkm_uevent *); }; void nvkm_object_ctor(const struct nvkm_object_func *, diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/os.h b/drivers/gpu/drm/nouveau/include/nvkm/core/os.h index d7ba3205207f..4486d9862849 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/os.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/os.h @@ -34,4 +34,24 @@ nvkm_blob_dtor(struct nvkm_blob *blob) blob->data = NULL; blob->size = 0; } + +#define nvkm_list_find_next(p,h,m,c) ({ \ + typeof(p) _p = NULL; \ + list_for_each_entry_continue(p, (h), m) { \ + if (c) { \ + _p = p; \ + break; \ + } \ + } \ + _p; \ +}) +#define nvkm_list_find(p,h,m,c) \ + (p = container_of((h), typeof(*p), m), nvkm_list_find_next(p, (h), m, (c))) +#define nvkm_list_foreach(p,h,m,c) \ + for (p = nvkm_list_find(p, (h), m, (c)); p; p = nvkm_list_find_next(p, (h), m, (c))) + +/*FIXME: remove after */ +#define nvkm_fifo_chan nvkm_chan +#define nvkm_fifo_chan_func nvkm_chan_func +#define nvkm_fifo_cgrp nvkm_cgrp #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h b/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h index 96113c8bee8c..bce6e1ba09ea 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h @@ -17,10 +17,19 @@ struct nvkm_subdev { struct nvkm_device *device; enum nvkm_subdev_type type; int inst; + char name[16]; u32 debug; - struct list_head head; + struct { + refcount_t refcount; + struct mutex mutex; + bool enabled; + } use; + + struct nvkm_inth inth; + + struct list_head head; void **pself; bool oneinit; }; @@ -38,22 +47,41 @@ struct nvkm_subdev_func { extern const char *nvkm_subdev_type[NVKM_SUBDEV_NR]; int nvkm_subdev_new_(const struct nvkm_subdev_func *, struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_subdev **); -void nvkm_subdev_ctor(const struct nvkm_subdev_func *, struct nvkm_device *, - enum nvkm_subdev_type, int inst, struct nvkm_subdev *); +void __nvkm_subdev_ctor(const struct nvkm_subdev_func *, struct nvkm_device *, + enum nvkm_subdev_type, int inst, struct nvkm_subdev *); + +static inline void +nvkm_subdev_ctor(const struct nvkm_subdev_func *func, struct nvkm_device *device, + enum nvkm_subdev_type type, int inst, struct nvkm_subdev *subdev) +{ + __nvkm_subdev_ctor(func, device, type, inst, subdev); + mutex_init(&subdev->use.mutex); +} + void nvkm_subdev_disable(struct nvkm_device *, enum nvkm_subdev_type, int inst); void nvkm_subdev_del(struct nvkm_subdev **); +int nvkm_subdev_ref(struct nvkm_subdev *); +void nvkm_subdev_unref(struct nvkm_subdev *); int nvkm_subdev_preinit(struct nvkm_subdev *); +int nvkm_subdev_oneinit(struct nvkm_subdev *); int nvkm_subdev_init(struct nvkm_subdev *); int nvkm_subdev_fini(struct nvkm_subdev *, bool suspend); int nvkm_subdev_info(struct nvkm_subdev *, u64, u64 *); void nvkm_subdev_intr(struct nvkm_subdev *); /* subdev logging */ -#define nvkm_printk_(s,l,p,f,a...) do { \ - const struct nvkm_subdev *_subdev = (s); \ - if (CONFIG_NOUVEAU_DEBUG >= (l) && _subdev->debug >= (l)) \ - dev_##p(_subdev->device->dev, "%s: "f, _subdev->name, ##a); \ +#define nvkm_printk_ok(s,u,l) \ + ((CONFIG_NOUVEAU_DEBUG >= (l)) && ((s)->debug >= (l) || ((u) && (u)->debug >= (l)))) +#define nvkm_printk___(s,u,l,p,f,a...) do { \ + if (nvkm_printk_ok((s), (u), (l))) { \ + if ((u) && (u) != (s)) \ + dev_##p((s)->device->dev, "%s(%s):"f, (s)->name, (u)->name, ##a); \ + else \ + dev_##p((s)->device->dev, "%s:"f, (s)->name, ##a); \ + } \ } while(0) +#define nvkm_printk__(s,l,p,f,a...) nvkm_printk___((s), (s), (l), p, f, ##a) +#define nvkm_printk_(s,l,p,f,a...) nvkm_printk__((s), (l), p, " "f, ##a) #define nvkm_printk(s,l,p,f,a...) nvkm_printk_((s), NV_DBG_##l, p, f, ##a) #define nvkm_fatal(s,f,a...) nvkm_printk((s), FATAL, crit, f, ##a) #define nvkm_error(s,f,a...) nvkm_printk((s), ERROR, err, f, ##a) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/tegra.h b/drivers/gpu/drm/nouveau/include/nvkm/core/tegra.h index 924009dd2bb0..ccee53d4e4ec 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/tegra.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/tegra.h @@ -8,7 +8,6 @@ struct nvkm_device_tegra { const struct nvkm_device_tegra_func *func; struct nvkm_device device; struct platform_device *pdev; - int irq; struct reset_control *rst; struct clk *clk; diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h index cfd2da8e66fe..b616a1e8ca02 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h @@ -12,4 +12,6 @@ int gp100_ce_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct n int gp102_ce_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_engine **); int gv100_ce_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_engine **); int tu102_ce_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_engine **); +int ga100_ce_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_engine **); +int ga102_ce_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_engine **); #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h index 8b5d8a434be8..ad9aef2df48f 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h @@ -16,6 +16,7 @@ struct nvkm_disp { struct list_head conns; struct nvkm_event hpd; +#define NVKM_DISP_HEAD_EVENT_VBLANK BIT(0) struct nvkm_event vblank; struct { @@ -31,13 +32,7 @@ struct nvkm_disp { struct { unsigned long mask; int nr; - } wndw, head, dac; - - struct { - unsigned long mask; - int nr; - u32 lvdsconf; - } sor; + } wndw, head, dac, sor; struct { unsigned long mask; diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h index b593407b9e36..cd86d9198e4a 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h @@ -16,15 +16,16 @@ enum nvkm_falcon_dmaidx { struct nvkm_falcon { const struct nvkm_falcon_func *func; - const struct nvkm_subdev *owner; + struct nvkm_subdev *owner; const char *name; u32 addr; + u32 addr2; struct mutex mutex; struct mutex dmem_mutex; bool oneinit; - const struct nvkm_subdev *user; + struct nvkm_subdev *user; u8 version; u8 secret; @@ -50,13 +51,42 @@ struct nvkm_falcon { struct nvkm_engine engine; }; -int nvkm_falcon_get(struct nvkm_falcon *, const struct nvkm_subdev *); -void nvkm_falcon_put(struct nvkm_falcon *, const struct nvkm_subdev *); +int nvkm_falcon_get(struct nvkm_falcon *, struct nvkm_subdev *); +void nvkm_falcon_put(struct nvkm_falcon *, struct nvkm_subdev *); int nvkm_falcon_new_(const struct nvkm_falcon_func *, struct nvkm_device *, enum nvkm_subdev_type, int inst, bool enable, u32 addr, struct nvkm_engine **); struct nvkm_falcon_func { + int (*disable)(struct nvkm_falcon *); + int (*enable)(struct nvkm_falcon *); + int (*select)(struct nvkm_falcon *); + u32 addr2; + bool reset_pmc; + int (*reset_eng)(struct nvkm_falcon *); + int (*reset_prep)(struct nvkm_falcon *); + int (*reset_wait_mem_scrubbing)(struct nvkm_falcon *); + + u32 debug; + void (*bind_inst)(struct nvkm_falcon *, int target, u64 addr); + int (*bind_stat)(struct nvkm_falcon *, bool intr); + bool bind_intr; + + const struct nvkm_falcon_func_pio *imem_pio; + const struct nvkm_falcon_func_dma *imem_dma; + + const struct nvkm_falcon_func_pio *dmem_pio; + const struct nvkm_falcon_func_dma *dmem_dma; + + u32 emem_addr; + const struct nvkm_falcon_func_pio *emem_pio; + + struct { + u32 head; + u32 tail; + u32 stride; + } cmdq, msgq; + struct { u32 *data; u32 size; @@ -66,29 +96,11 @@ struct nvkm_falcon_func { u32 size; } data; void (*init)(struct nvkm_falcon *); - void (*intr)(struct nvkm_falcon *, struct nvkm_fifo_chan *); - - u32 debug; - u32 fbif; + void (*intr)(struct nvkm_falcon *, struct nvkm_chan *); void (*load_imem)(struct nvkm_falcon *, void *, u32, u32, u16, u8, bool); void (*load_dmem)(struct nvkm_falcon *, void *, u32, u32, u8); - void (*read_dmem)(struct nvkm_falcon *, u32, u32, u8, void *); - u32 emem_addr; - void (*bind_context)(struct nvkm_falcon *, struct nvkm_memory *); - int (*wait_for_halt)(struct nvkm_falcon *, u32); - int (*clear_interrupt)(struct nvkm_falcon *, u32); - void (*set_start_addr)(struct nvkm_falcon *, u32 start_addr); void (*start)(struct nvkm_falcon *); - int (*enable)(struct nvkm_falcon *falcon); - void (*disable)(struct nvkm_falcon *falcon); - int (*reset)(struct nvkm_falcon *); - - struct { - u32 head; - u32 tail; - u32 stride; - } cmdq, msgq; struct nvkm_sclass sclass[]; }; @@ -116,13 +128,5 @@ nvkm_falcon_mask(struct nvkm_falcon *falcon, u32 addr, u32 mask, u32 val) void nvkm_falcon_load_imem(struct nvkm_falcon *, void *, u32, u32, u16, u8, bool); void nvkm_falcon_load_dmem(struct nvkm_falcon *, void *, u32, u32, u8); -void nvkm_falcon_read_dmem(struct nvkm_falcon *, u32, u32, u8, void *); -void nvkm_falcon_bind_context(struct nvkm_falcon *, struct nvkm_memory *); -void nvkm_falcon_set_start_addr(struct nvkm_falcon *, u32); void nvkm_falcon_start(struct nvkm_falcon *); -int nvkm_falcon_wait_for_halt(struct nvkm_falcon *, u32); -int nvkm_falcon_clear_interrupt(struct nvkm_falcon *, u32); -int nvkm_falcon_enable(struct nvkm_falcon *); -void nvkm_falcon_disable(struct nvkm_falcon *); -int nvkm_falcon_reset(struct nvkm_falcon *); #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h index 15099913504d..221abd6c4310 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h @@ -6,56 +6,76 @@ #include <core/event.h> struct nvkm_fault_data; -#define NVKM_FIFO_CHID_NR 4096 #define NVKM_FIFO_ENGN_NR 16 -struct nvkm_fifo_engn { - struct nvkm_object *object; - int refcount; - int usecount; -}; - -struct nvkm_fifo_chan { - const struct nvkm_fifo_chan_func *func; - struct nvkm_fifo *fifo; - u32 engm; - struct nvkm_object object; +struct nvkm_chan { + const struct nvkm_chan_func *func; + char name[64]; + struct nvkm_cgrp *cgrp; + int runq; - struct list_head head; - u16 chid; struct nvkm_gpuobj *inst; - struct nvkm_gpuobj *push; struct nvkm_vmm *vmm; - u64 addr; - u32 size; + struct nvkm_gpuobj *push; + int id; + + struct { + struct nvkm_memory *mem; + u32 base; + } userd; + + u32 ramfc_offset; + struct nvkm_gpuobj *ramfc; + struct nvkm_gpuobj *cache; + struct nvkm_gpuobj *eng; + struct nvkm_gpuobj *pgd; + struct nvkm_ramht *ramht; + + spinlock_t lock; + atomic_t blocked; + atomic_t errored; - struct nvkm_fifo_engn engn[NVKM_FIFO_ENGN_NR]; + struct list_head cctxs; + struct list_head head; }; +struct nvkm_chan *nvkm_chan_get_chid(struct nvkm_engine *, int id, unsigned long *irqflags); +struct nvkm_chan *nvkm_chan_get_inst(struct nvkm_engine *, u64 inst, unsigned long *irqflags); +void nvkm_chan_put(struct nvkm_chan **, unsigned long irqflags); + struct nvkm_fifo { const struct nvkm_fifo_func *func; struct nvkm_engine engine; - DECLARE_BITMAP(mask, NVKM_FIFO_CHID_NR); - int nr; - struct list_head chan; + struct nvkm_chid *chid; + struct nvkm_chid *cgid; + + struct list_head runqs; + struct list_head runls; + + struct { +#define NVKM_FIFO_NONSTALL_EVENT BIT(0) + struct nvkm_event event; + struct nvkm_inth intr; + } nonstall; + + struct { + u32 chan_msec; + } timeout; + + struct { + struct nvkm_memory *mem; + struct nvkm_vma *bar1; + } userd; + spinlock_t lock; struct mutex mutex; - - struct nvkm_event uevent; /* async user trigger */ - struct nvkm_event kevent; /* channel killed */ }; void nvkm_fifo_fault(struct nvkm_fifo *, struct nvkm_fault_data *); void nvkm_fifo_pause(struct nvkm_fifo *, unsigned long *); void nvkm_fifo_start(struct nvkm_fifo *, unsigned long *); - -void nvkm_fifo_chan_put(struct nvkm_fifo *, unsigned long flags, - struct nvkm_fifo_chan **); -struct nvkm_fifo_chan * -nvkm_fifo_chan_inst(struct nvkm_fifo *, u64 inst, unsigned long *flags); -struct nvkm_fifo_chan * -nvkm_fifo_chan_chid(struct nvkm_fifo *, int chid, unsigned long *flags); +bool nvkm_fifo_ctxsw_in_progress(struct nvkm_engine *); int nv04_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **); int nv10_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **); @@ -63,6 +83,7 @@ int nv17_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct int nv40_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **); int nv50_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **); int g84_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **); +int g98_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **); int gf100_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **); int gk104_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **); int gk110_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **); @@ -70,10 +91,9 @@ int gk208_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct int gk20a_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **); int gm107_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **); int gm200_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **); -int gm20b_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **); int gp100_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **); -int gp10b_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **); int gv100_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **); int tu102_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **); +int ga100_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **); int ga102_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **); #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h index b28b752ffaa2..a2333cfe6955 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h @@ -54,4 +54,5 @@ int gp108_gr_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct n int gp10b_gr_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_gr **); int gv100_gr_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_gr **); int tu102_gr_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_gr **); +int ga102_gr_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_gr **); #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/nvdec.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/nvdec.h index 97bd3092f68a..9baf197ac833 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/nvdec.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/nvdec.h @@ -12,4 +12,5 @@ struct nvkm_nvdec { }; int gm107_nvdec_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_nvdec **); +int ga102_nvdec_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_nvdec **); #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/sec2.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/sec2.h index 06264c840eae..8d48fb20fa54 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/sec2.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/sec2.h @@ -10,15 +10,18 @@ struct nvkm_sec2 { struct nvkm_engine engine; struct nvkm_falcon falcon; + atomic_t running; + atomic_t initmsg; + struct nvkm_falcon_qmgr *qmgr; struct nvkm_falcon_cmdq *cmdq; struct nvkm_falcon_msgq *msgq; struct work_struct work; - bool initmsg_received; }; int gp102_sec2_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_sec2 **); int gp108_sec2_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_sec2 **); int tu102_sec2_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_sec2 **); +int ga102_sec2_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_sec2 **); #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/acr.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/acr.h index c0b254f7f0b5..73d2a6ae9ab2 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/acr.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/acr.h @@ -36,7 +36,7 @@ struct nvkm_acr { const struct nvkm_acr_func *func; struct nvkm_subdev subdev; - struct list_head hsfw, hsf; + struct list_head hsfw; struct list_head lsfw, lsf; u64 managed_falcons; @@ -50,6 +50,7 @@ struct nvkm_acr { struct nvkm_vmm *vmm; bool done; + struct nvkm_acr_lsf *rtos; const struct firmware *wpr_fw; bool wpr_comp; @@ -64,7 +65,9 @@ int gm20b_acr_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct int gp102_acr_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_acr **); int gp108_acr_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_acr **); int gp10b_acr_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_acr **); +int gv100_acr_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_acr **); int tu102_acr_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_acr **); +int ga102_acr_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_acr **); struct nvkm_acr_lsfw { const struct nvkm_acr_lsf_func *func; @@ -77,6 +80,7 @@ struct nvkm_acr_lsfw { const struct firmware *sig; + bool secure_bootloader; u32 bootloader_size; u32 bootloader_imem_offset; @@ -87,10 +91,19 @@ struct nvkm_acr_lsfw { u32 app_resident_code_size; u32 app_resident_data_offset; u32 app_resident_data_size; + u32 app_imem_offset; + u32 app_dmem_offset; u32 ucode_size; u32 data_size; + u32 fuse_ver; + u32 engine_id; + u32 ucode_id; + u32 sig_size; + u32 sig_nr; + u8 *sigs; + struct { u32 lsb; u32 img; @@ -105,10 +118,10 @@ struct nvkm_acr_lsf_func { #define NVKM_ACR_LSF_DMACTL_REQ_CTX 0x00000004 #define NVKM_ACR_LSF_FORCE_PRIV_LOAD 0x00000008 u32 flags; + u32 bl_entry; u32 bld_size; void (*bld_write)(struct nvkm_acr *, u32 bld, struct nvkm_acr_lsfw *); void (*bld_patch)(struct nvkm_acr *, u32 bld, s64 adjust); - int (*boot)(struct nvkm_falcon *); u64 bootstrap_falcons; int (*bootstrap_falcon)(struct nvkm_falcon *, enum nvkm_acr_lsf_id); int (*bootstrap_multiple_falcons)(struct nvkm_falcon *, u32 mask); @@ -122,8 +135,20 @@ int nvkm_acr_lsfw_load_sig_image_desc_v1(struct nvkm_subdev *, struct nvkm_falcon *, enum nvkm_acr_lsf_id, const char *path, int ver, const struct nvkm_acr_lsf_func *); + +int +nvkm_acr_lsfw_load_sig_image_desc_v2(struct nvkm_subdev *, struct nvkm_falcon *, + enum nvkm_acr_lsf_id, const char *path, + int ver, const struct nvkm_acr_lsf_func *); + int nvkm_acr_lsfw_load_bl_inst_data_sig(struct nvkm_subdev *, struct nvkm_falcon *, enum nvkm_acr_lsf_id, const char *path, int ver, const struct nvkm_acr_lsf_func *); + +int +nvkm_acr_lsfw_load_bl_sig_net(struct nvkm_subdev *, struct nvkm_falcon *, + enum nvkm_acr_lsf_id, const char *path, + int ver, const struct nvkm_acr_lsf_func *, + const void *, u32, const void *, u32); #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fault.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fault.h index 9c78f072d62b..e40bbf378a8d 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fault.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fault.h @@ -2,18 +2,21 @@ #define __NVKM_FAULT_H__ #include <core/subdev.h> #include <core/event.h> -#include <core/notify.h> struct nvkm_fault { const struct nvkm_fault_func *func; struct nvkm_subdev subdev; + struct nvkm_inth info_fault; + struct nvkm_fault_buffer *buffer[2]; int buffer_nr; +#define NVKM_FAULT_BUFFER_EVENT_PENDING BIT(0) struct nvkm_event event; - struct nvkm_notify nrpfb; + struct nvkm_event_ntfy nrpfb; + struct work_struct nrpfb_work; struct nvkm_device_oclass user; }; diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h index ef6a6297148c..40768373cdd9 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h @@ -35,6 +35,11 @@ struct nvkm_fb { struct nvkm_blob vpr_scrubber; + struct { + struct page *flush_page; + dma_addr_t flush_page_addr; + } sysmem; + struct nvkm_ram *ram; struct { @@ -53,6 +58,8 @@ struct nvkm_fb { struct nvkm_memory *mmu_wr; }; +int nvkm_fb_mem_unlock(struct nvkm_fb *); + void nvkm_fb_tile_init(struct nvkm_fb *, int region, u32 addr, u32 size, u32 pitch, u32 flags, struct nvkm_fb_tile *); void nvkm_fb_tile_fini(struct nvkm_fb *, int region, struct nvkm_fb_tile *); diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/gpio.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/gpio.h index 0e46ea1fe972..537c4fc58b4f 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/gpio.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/gpio.h @@ -8,9 +8,6 @@ #include <subdev/bios/gpio.h> struct nvkm_gpio_ntfy_req { -#define NVKM_GPIO_HI 0x01 -#define NVKM_GPIO_LO 0x02 -#define NVKM_GPIO_TOGGLED 0x03 u8 mask; u8 line; }; @@ -23,6 +20,9 @@ struct nvkm_gpio { const struct nvkm_gpio_func *func; struct nvkm_subdev subdev; +#define NVKM_GPIO_HI BIT(0) +#define NVKM_GPIO_LO BIT(1) +#define NVKM_GPIO_TOGGLED (NVKM_GPIO_HI | NVKM_GPIO_LO) struct nvkm_event event; }; diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h index cf42a59d4e58..72619d7df73e 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h @@ -5,9 +5,12 @@ #include <core/falcon.h> struct nvkm_gsp { + const struct nvkm_gsp_func *func; struct nvkm_subdev subdev; + struct nvkm_falcon falcon; }; int gv100_gsp_new(struct nvkm_device *, enum nvkm_subdev_type, int, struct nvkm_gsp **); +int ga102_gsp_new(struct nvkm_device *, enum nvkm_subdev_type, int, struct nvkm_gsp **); #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h index 146e13292203..40a1065ae626 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h @@ -7,20 +7,6 @@ #include <subdev/bios.h> #include <subdev/bios/i2c.h> -struct nvkm_i2c_ntfy_req { -#define NVKM_I2C_PLUG 0x01 -#define NVKM_I2C_UNPLUG 0x02 -#define NVKM_I2C_IRQ 0x04 -#define NVKM_I2C_DONE 0x08 -#define NVKM_I2C_ANY 0x0f - u8 mask; - u8 port; -}; - -struct nvkm_i2c_ntfy_rep { - u8 mask; -}; - struct nvkm_i2c_bus_probe { struct i2c_board_info dev; u8 udelay; /* set to 0 to use the standard delay */ @@ -79,6 +65,11 @@ struct nvkm_i2c { struct list_head bus; struct list_head aux; +#define NVKM_I2C_PLUG BIT(0) +#define NVKM_I2C_UNPLUG BIT(1) +#define NVKM_I2C_IRQ BIT(2) +#define NVKM_I2C_DONE BIT(3) +#define NVKM_I2C_ANY (NVKM_I2C_PLUG | NVKM_I2C_UNPLUG | NVKM_I2C_IRQ | NVKM_I2C_DONE) struct nvkm_event event; }; diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h index f967b97d163c..fcdaefc99fe8 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h @@ -28,7 +28,7 @@ u32 nvkm_instmem_rd32(struct nvkm_instmem *, u32 addr); void nvkm_instmem_wr32(struct nvkm_instmem *, u32 addr, u32 data); int nvkm_instobj_new(struct nvkm_instmem *, u32 size, u32 align, bool zero, struct nvkm_memory **); - +int nvkm_instobj_wrap(struct nvkm_device *, struct nvkm_memory *, struct nvkm_memory **); int nv04_instmem_new(struct nvkm_device *, enum nvkm_subdev_type, int, struct nvkm_instmem **); int nv40_instmem_new(struct nvkm_device *, enum nvkm_subdev_type, int, struct nvkm_instmem **); diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/ltc.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/ltc.h index d32a326a9290..64294042ec07 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/ltc.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/ltc.h @@ -4,7 +4,8 @@ #include <core/subdev.h> #include <core/mm.h> -#define NVKM_LTC_MAX_ZBC_CNT 16 +#define NVKM_LTC_MAX_ZBC_COLOR_CNT 32 +#define NVKM_LTC_MAX_ZBC_DEPTH_CNT 16 struct nvkm_ltc { const struct nvkm_ltc_func *func; @@ -18,11 +19,13 @@ struct nvkm_ltc { u32 tag_base; struct nvkm_memory *tag_ram; - int zbc_min; - int zbc_max; - u32 zbc_color[NVKM_LTC_MAX_ZBC_CNT][4]; - u32 zbc_depth[NVKM_LTC_MAX_ZBC_CNT]; - u32 zbc_stencil[NVKM_LTC_MAX_ZBC_CNT]; + int zbc_color_min; + int zbc_color_max; + u32 zbc_color[NVKM_LTC_MAX_ZBC_COLOR_CNT][4]; + int zbc_depth_min; + int zbc_depth_max; + u32 zbc_depth[NVKM_LTC_MAX_ZBC_DEPTH_CNT]; + u32 zbc_stencil[NVKM_LTC_MAX_ZBC_DEPTH_CNT]; }; void nvkm_ltc_tags_clear(struct nvkm_device *, u32 first, u32 count); @@ -41,4 +44,5 @@ int gm200_ltc_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct int gp100_ltc_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_ltc **); int gp102_ltc_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_ltc **); int gp10b_ltc_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_ltc **); +int ga102_ltc_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_ltc **); #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h index cb86a56e68d4..127ac545e4b2 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h @@ -6,15 +6,14 @@ struct nvkm_mc { const struct nvkm_mc_func *func; struct nvkm_subdev subdev; + + struct nvkm_intr intr; }; void nvkm_mc_enable(struct nvkm_device *, enum nvkm_subdev_type, int); void nvkm_mc_disable(struct nvkm_device *, enum nvkm_subdev_type, int); bool nvkm_mc_enabled(struct nvkm_device *, enum nvkm_subdev_type, int); void nvkm_mc_reset(struct nvkm_device *, enum nvkm_subdev_type, int); -void nvkm_mc_intr(struct nvkm_device *, bool *handled); -void nvkm_mc_intr_unarm(struct nvkm_device *); -void nvkm_mc_intr_rearm(struct nvkm_device *); void nvkm_mc_intr_mask(struct nvkm_device *, enum nvkm_subdev_type, int, bool enable); void nvkm_mc_unk260(struct nvkm_device *, u32 data); @@ -31,6 +30,5 @@ int gk104_mc_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct n int gk20a_mc_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_mc **); int gp100_mc_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_mc **); int gp10b_mc_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_mc **); -int tu102_mc_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_mc **); int ga100_mc_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_mc **); #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h index 74c19bdfb757..3c103101d5fc 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h @@ -13,7 +13,6 @@ struct nvkm_pci { const struct nvkm_pci_func *func; struct nvkm_subdev subdev; struct pci_dev *pdev; - int irq; struct { struct agp_bridge_data *bridge; @@ -38,6 +37,7 @@ void nvkm_pci_wr08(struct nvkm_pci *, u16 addr, u8 data); void nvkm_pci_wr32(struct nvkm_pci *, u16 addr, u32 data); u32 nvkm_pci_mask(struct nvkm_pci *, u16 addr, u32 mask, u32 value); void nvkm_pci_rom_shadow(struct nvkm_pci *, bool shadow); +void nvkm_pci_msi_rearm(struct nvkm_device *); int nv04_pci_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_pci **); int nv40_pci_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_pci **); diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/top.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/top.h index ee75c5524c43..73e717b980b8 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/top.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/top.h @@ -21,6 +21,7 @@ struct nvkm_top_device { struct list_head head; }; +int nvkm_top_parse(struct nvkm_device *); u32 nvkm_top_addr(struct nvkm_device *, enum nvkm_subdev_type, int); u32 nvkm_top_reset(struct nvkm_device *, enum nvkm_subdev_type, int); u32 nvkm_top_intr_mask(struct nvkm_device *, enum nvkm_subdev_type, int); diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/vfn.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/vfn.h new file mode 100644 index 000000000000..cc6d0796c265 --- /dev/null +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/vfn.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: MIT */ +#ifndef __NVKM_VFN_H__ +#define __NVKM_VFN_H__ +#include <core/subdev.h> + +struct nvkm_vfn { + const struct nvkm_vfn_func *func; + struct nvkm_subdev subdev; + + struct { + u32 priv; + u32 user; + } addr; + + struct nvkm_intr intr; + + struct nvkm_device_oclass user; +}; + +int gv100_vfn_new(struct nvkm_device *, enum nvkm_subdev_type, int, struct nvkm_vfn **); +int tu102_vfn_new(struct nvkm_device *, enum nvkm_subdev_type, int, struct nvkm_vfn **); +int ga100_vfn_new(struct nvkm_device *, enum nvkm_subdev_type, int, struct nvkm_vfn **); +#endif diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c index 5bee655e7e63..82dab51d8aeb 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.c +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c @@ -27,7 +27,6 @@ #include <nvif/ioctl.h> #include <nvif/class.h> #include <nvif/cl0002.h> -#include <nvif/cla06f.h> #include <nvif/unpack.h> #include "nouveau_drv.h" @@ -253,7 +252,7 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS) struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv); struct nouveau_abi16_chan *chan; struct nvif_device *device; - u64 engine; + u64 engine, runm; int ret; if (unlikely(!abi16)) @@ -263,6 +262,7 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS) return nouveau_abi16_put(abi16, -ENODEV); device = &abi16->device; + engine = NV_DEVICE_HOST_RUNLIST_ENGINES_GR; /* hack to allow channel engine type specification on kepler */ if (device->info.family >= NV_DEVICE_INFO_V0_KEPLER) { @@ -276,19 +276,18 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS) default: return nouveau_abi16_put(abi16, -ENOSYS); } - } else { - engine = NV_DEVICE_HOST_RUNLIST_ENGINES_GR; - } - if (engine != NV_DEVICE_HOST_RUNLIST_ENGINES_CE) - engine = nvif_fifo_runlist(device, engine); - else - engine = nvif_fifo_runlist_ce(device); - init->fb_ctxdma_handle = engine; - init->tt_ctxdma_handle = 0; + init->fb_ctxdma_handle = 0; + init->tt_ctxdma_handle = 0; + } } - if (init->fb_ctxdma_handle == ~0 || init->tt_ctxdma_handle == ~0) + if (engine != NV_DEVICE_HOST_RUNLIST_ENGINES_CE) + runm = nvif_fifo_runlist(device, engine); + else + runm = nvif_fifo_runlist_ce(device); + + if (!runm || init->fb_ctxdma_handle == ~0 || init->tt_ctxdma_handle == ~0) return nouveau_abi16_put(abi16, -EINVAL); /* allocate "abi16 channel" data and make up a handle for it */ @@ -300,8 +299,8 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS) list_add(&chan->head, &abi16->channels); /* create channel object and initialise dma and fence management */ - ret = nouveau_channel_new(drm, device, init->fb_ctxdma_handle, - init->tt_ctxdma_handle, false, &chan->chan); + ret = nouveau_channel_new(drm, device, false, runm, init->fb_ctxdma_handle, + init->tt_ctxdma_handle, &chan->chan); if (ret) goto done; diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 813937ad1dc2..a11871e3119c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -856,6 +856,9 @@ nouveau_bo_move_init(struct nouveau_drm *drm) int (*init)(struct nouveau_channel *, u32 handle); } _methods[] = { { "COPY", 4, 0xc7b5, nve0_bo_move_copy, nve0_bo_move_init }, + { "GRCE", 0, 0xc7b5, nve0_bo_move_copy, nvc0_bo_move_init }, + { "COPY", 4, 0xc6b5, nve0_bo_move_copy, nve0_bo_move_init }, + { "GRCE", 0, 0xc6b5, nve0_bo_move_copy, nvc0_bo_move_init }, { "COPY", 4, 0xc5b5, nve0_bo_move_copy, nve0_bo_move_init }, { "GRCE", 0, 0xc5b5, nve0_bo_move_copy, nvc0_bo_move_init }, { "COPY", 4, 0xc3b5, nve0_bo_move_copy, nve0_bo_move_init }, diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c b/drivers/gpu/drm/nouveau/nouveau_chan.c index 48dea5d0c580..e648ecd0c1a0 100644 --- a/drivers/gpu/drm/nouveau/nouveau_chan.c +++ b/drivers/gpu/drm/nouveau/nouveau_chan.c @@ -25,12 +25,7 @@ #include <nvif/class.h> #include <nvif/cl0002.h> -#include <nvif/cl006b.h> -#include <nvif/cl506f.h> -#include <nvif/cl906f.h> -#include <nvif/cla06f.h> -#include <nvif/clc36f.h> -#include <nvif/ioctl.h> +#include <nvif/if0020.h> #include "nouveau_drv.h" #include "nouveau_dma.h" @@ -46,15 +41,17 @@ int nouveau_vram_pushbuf; module_param_named(vram_pushbuf, nouveau_vram_pushbuf, int, 0400); static int -nouveau_channel_killed(struct nvif_notify *ntfy) +nouveau_channel_killed(struct nvif_event *event, void *repv, u32 repc) { - struct nouveau_channel *chan = container_of(ntfy, typeof(*chan), kill); + struct nouveau_channel *chan = container_of(event, typeof(*chan), kill); struct nouveau_cli *cli = (void *)chan->user.client; + NV_PRINTK(warn, cli, "channel %d killed!\n", chan->chid); atomic_set(&chan->killed, 1); if (chan->fence) nouveau_fence_context_kill(chan->fence, -ENODEV); - return NVIF_NOTIFY_DROP; + + return NVIF_EVENT_DROP; } int @@ -96,8 +93,9 @@ nouveau_channel_del(struct nouveau_channel **pchan) nvif_object_dtor(&chan->nvsw); nvif_object_dtor(&chan->gart); nvif_object_dtor(&chan->vram); - nvif_notify_dtor(&chan->kill); + nvif_event_dtor(&chan->kill); nvif_object_dtor(&chan->user); + nvif_mem_dtor(&chan->mem_userd); nvif_object_dtor(&chan->push.ctxdma); nouveau_vma_del(&chan->push.vma); nouveau_bo_unmap(chan->push.buffer); @@ -247,134 +245,113 @@ nouveau_channel_prep(struct nouveau_drm *drm, struct nvif_device *device, } static int -nouveau_channel_ind(struct nouveau_drm *drm, struct nvif_device *device, - u64 runlist, bool priv, struct nouveau_channel **pchan) +nouveau_channel_ctor(struct nouveau_drm *drm, struct nvif_device *device, bool priv, u64 runm, + struct nouveau_channel **pchan) { - static const u16 oclasses[] = { AMPERE_CHANNEL_GPFIFO_B, - TURING_CHANNEL_GPFIFO_A, - VOLTA_CHANNEL_GPFIFO_A, - PASCAL_CHANNEL_GPFIFO_A, - MAXWELL_CHANNEL_GPFIFO_A, - KEPLER_CHANNEL_GPFIFO_B, - KEPLER_CHANNEL_GPFIFO_A, - FERMI_CHANNEL_GPFIFO, - G82_CHANNEL_GPFIFO, - NV50_CHANNEL_GPFIFO, - 0 }; - const u16 *oclass = oclasses; - union { - struct nv50_channel_gpfifo_v0 nv50; - struct fermi_channel_gpfifo_v0 fermi; - struct kepler_channel_gpfifo_a_v0 kepler; - struct volta_channel_gpfifo_a_v0 volta; + static const struct { + s32 oclass; + int version; + } hosts[] = { + { AMPERE_CHANNEL_GPFIFO_B, 0 }, + { AMPERE_CHANNEL_GPFIFO_A, 0 }, + { TURING_CHANNEL_GPFIFO_A, 0 }, + { VOLTA_CHANNEL_GPFIFO_A, 0 }, + { PASCAL_CHANNEL_GPFIFO_A, 0 }, + { MAXWELL_CHANNEL_GPFIFO_A, 0 }, + { KEPLER_CHANNEL_GPFIFO_B, 0 }, + { KEPLER_CHANNEL_GPFIFO_A, 0 }, + { FERMI_CHANNEL_GPFIFO , 0 }, + { G82_CHANNEL_GPFIFO , 0 }, + { NV50_CHANNEL_GPFIFO , 0 }, + { NV40_CHANNEL_DMA , 0 }, + { NV17_CHANNEL_DMA , 0 }, + { NV10_CHANNEL_DMA , 0 }, + { NV03_CHANNEL_DMA , 0 }, + {} + }; + struct { + struct nvif_chan_v0 chan; + char name[TASK_COMM_LEN+16]; } args; + struct nouveau_cli *cli = (void *)device->object.client; struct nouveau_channel *chan; - u32 size; - int ret; + const u64 plength = 0x10000; + const u64 ioffset = plength; + const u64 ilength = 0x02000; + char name[TASK_COMM_LEN]; + int cid, ret; + u64 size; + + cid = nvif_mclass(&device->object, hosts); + if (cid < 0) + return cid; + + if (hosts[cid].oclass < NV50_CHANNEL_GPFIFO) + size = plength; + else + size = ioffset + ilength; /* allocate dma push buffer */ - ret = nouveau_channel_prep(drm, device, 0x12000, &chan); + ret = nouveau_channel_prep(drm, device, size, &chan); *pchan = chan; if (ret) return ret; /* create channel object */ - do { - if (oclass[0] >= VOLTA_CHANNEL_GPFIFO_A) { - args.volta.version = 0; - args.volta.ilength = 0x02000; - args.volta.ioffset = 0x10000 + chan->push.addr; - args.volta.runlist = runlist; - args.volta.vmm = nvif_handle(&chan->vmm->vmm.object); - args.volta.priv = priv; - size = sizeof(args.volta); - } else - if (oclass[0] >= KEPLER_CHANNEL_GPFIFO_A) { - args.kepler.version = 0; - args.kepler.ilength = 0x02000; - args.kepler.ioffset = 0x10000 + chan->push.addr; - args.kepler.runlist = runlist; - args.kepler.vmm = nvif_handle(&chan->vmm->vmm.object); - args.kepler.priv = priv; - size = sizeof(args.kepler); - } else - if (oclass[0] >= FERMI_CHANNEL_GPFIFO) { - args.fermi.version = 0; - args.fermi.ilength = 0x02000; - args.fermi.ioffset = 0x10000 + chan->push.addr; - args.fermi.vmm = nvif_handle(&chan->vmm->vmm.object); - size = sizeof(args.fermi); - } else { - args.nv50.version = 0; - args.nv50.ilength = 0x02000; - args.nv50.ioffset = 0x10000 + chan->push.addr; - args.nv50.pushbuf = nvif_handle(&chan->push.ctxdma); - args.nv50.vmm = nvif_handle(&chan->vmm->vmm.object); - size = sizeof(args.nv50); - } - - ret = nvif_object_ctor(&device->object, "abi16ChanUser", 0, - *oclass++, &args, size, &chan->user); - if (ret == 0) { - if (chan->user.oclass >= VOLTA_CHANNEL_GPFIFO_A) { - chan->chid = args.volta.chid; - chan->inst = args.volta.inst; - chan->token = args.volta.token; - } else - if (chan->user.oclass >= KEPLER_CHANNEL_GPFIFO_A) { - chan->chid = args.kepler.chid; - chan->inst = args.kepler.inst; - } else - if (chan->user.oclass >= FERMI_CHANNEL_GPFIFO) { - chan->chid = args.fermi.chid; - } else { - chan->chid = args.nv50.chid; - } + args.chan.version = 0; + args.chan.namelen = sizeof(args.name); + args.chan.runlist = __ffs64(runm); + args.chan.runq = 0; + args.chan.priv = priv; + args.chan.devm = BIT(0); + if (hosts[cid].oclass < NV50_CHANNEL_GPFIFO) { + args.chan.vmm = 0; + args.chan.ctxdma = nvif_handle(&chan->push.ctxdma); + args.chan.offset = chan->push.addr; + args.chan.length = 0; + } else { + args.chan.vmm = nvif_handle(&chan->vmm->vmm.object); + if (hosts[cid].oclass < FERMI_CHANNEL_GPFIFO) + args.chan.ctxdma = nvif_handle(&chan->push.ctxdma); + else + args.chan.ctxdma = 0; + args.chan.offset = ioffset + chan->push.addr; + args.chan.length = ilength; + } + args.chan.huserd = 0; + args.chan.ouserd = 0; + + /* allocate userd */ + if (hosts[cid].oclass >= VOLTA_CHANNEL_GPFIFO_A) { + ret = nvif_mem_ctor(&cli->mmu, "abi16ChanUSERD", NVIF_CLASS_MEM_GF100, + NVIF_MEM_VRAM | NVIF_MEM_COHERENT | NVIF_MEM_MAPPABLE, + 0, PAGE_SIZE, NULL, 0, &chan->mem_userd); + if (ret) return ret; - } - } while (*oclass); - nouveau_channel_del(pchan); - return ret; -} + args.chan.huserd = nvif_handle(&chan->mem_userd.object); + args.chan.ouserd = 0; -static int -nouveau_channel_dma(struct nouveau_drm *drm, struct nvif_device *device, - struct nouveau_channel **pchan) -{ - static const u16 oclasses[] = { NV40_CHANNEL_DMA, - NV17_CHANNEL_DMA, - NV10_CHANNEL_DMA, - NV03_CHANNEL_DMA, - 0 }; - const u16 *oclass = oclasses; - struct nv03_channel_dma_v0 args; - struct nouveau_channel *chan; - int ret; + chan->userd = &chan->mem_userd.object; + } else { + chan->userd = &chan->user; + } - /* allocate dma push buffer */ - ret = nouveau_channel_prep(drm, device, 0x10000, &chan); - *pchan = chan; - if (ret) - return ret; + get_task_comm(name, current); + snprintf(args.name, sizeof(args.name), "%s[%d]", name, task_pid_nr(current)); - /* create channel object */ - args.version = 0; - args.pushbuf = nvif_handle(&chan->push.ctxdma); - args.offset = chan->push.addr; - - do { - ret = nvif_object_ctor(&device->object, "abi16ChanUser", 0, - *oclass++, &args, sizeof(args), - &chan->user); - if (ret == 0) { - chan->chid = args.chid; - return ret; - } - } while (ret && *oclass); + ret = nvif_object_ctor(&device->object, "abi16ChanUser", 0, hosts[cid].oclass, + &args, sizeof(args), &chan->user); + if (ret) { + nouveau_channel_del(pchan); + return ret; + } - nouveau_channel_del(pchan); - return ret; + chan->runlist = args.chan.runlist; + chan->chid = args.chan.chid; + chan->inst = args.chan.inst; + chan->token = args.chan.token; + return 0; } static int @@ -385,18 +362,24 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart) struct nv_dma_v0 args = {}; int ret, i; - ret = nvif_object_map(&chan->user, NULL, 0); + ret = nvif_object_map(chan->userd, NULL, 0); if (ret) return ret; - if (chan->user.oclass >= FERMI_CHANNEL_GPFIFO && - chan->user.oclass < AMPERE_CHANNEL_GPFIFO_B) { - ret = nvif_notify_ctor(&chan->user, "abi16ChanKilled", - nouveau_channel_killed, - true, NV906F_V0_NTFY_KILLED, - NULL, 0, 0, &chan->kill); + if (chan->user.oclass >= FERMI_CHANNEL_GPFIFO) { + struct { + struct nvif_event_v0 base; + struct nvif_chan_event_v0 host; + } args; + + args.host.version = 0; + args.host.type = NVIF_CHAN_EVENT_V0_KILLED; + + ret = nvif_event_ctor(&chan->user, "abi16ChanKilled", chan->chid, + nouveau_channel_killed, false, + &args.base, sizeof(args), &chan->kill); if (ret == 0) - ret = nvif_notify_get(&chan->kill); + ret = nvif_event_allow(&chan->kill); if (ret) { NV_ERROR(drm, "Failed to request channel kill " "notification: %d\n", ret); @@ -503,24 +486,18 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart) int nouveau_channel_new(struct nouveau_drm *drm, struct nvif_device *device, - u32 arg0, u32 arg1, bool priv, - struct nouveau_channel **pchan) + bool priv, u64 runm, u32 vram, u32 gart, struct nouveau_channel **pchan) { struct nouveau_cli *cli = (void *)device->object.client; int ret; - /* hack until fencenv50 is fixed, and agp access relaxed */ - ret = nouveau_channel_ind(drm, device, arg0, priv, pchan); + ret = nouveau_channel_ctor(drm, device, priv, runm, pchan); if (ret) { - NV_PRINTK(dbg, cli, "ib channel create, %d\n", ret); - ret = nouveau_channel_dma(drm, device, pchan); - if (ret) { - NV_PRINTK(dbg, cli, "dma channel create, %d\n", ret); - return ret; - } + NV_PRINTK(dbg, cli, "channel create, %d\n", ret); + return ret; } - ret = nouveau_channel_init(*pchan, arg0, arg1); + ret = nouveau_channel_init(*pchan, vram, gart); if (ret) { NV_PRINTK(err, cli, "channel failed to initialise, %d\n", ret); nouveau_channel_del(pchan); @@ -534,6 +511,12 @@ nouveau_channel_new(struct nouveau_drm *drm, struct nvif_device *device, return ret; } +void +nouveau_channels_fini(struct nouveau_drm *drm) +{ + kfree(drm->runl); +} + int nouveau_channels_init(struct nouveau_drm *drm) { @@ -541,20 +524,53 @@ nouveau_channels_init(struct nouveau_drm *drm) struct nv_device_info_v1 m; struct { struct nv_device_info_v1_data channels; + struct nv_device_info_v1_data runlists; } v; } args = { .m.version = 1, .m.count = sizeof(args.v) / sizeof(args.v.channels), .v.channels.mthd = NV_DEVICE_HOST_CHANNELS, + .v.runlists.mthd = NV_DEVICE_HOST_RUNLISTS, }; struct nvif_object *device = &drm->client.device.object; - int ret; + int ret, i; ret = nvif_object_mthd(device, NV_DEVICE_V0_INFO, &args, sizeof(args)); - if (ret || args.v.channels.mthd == NV_DEVICE_INFO_INVALID) + if (ret || + args.v.runlists.mthd == NV_DEVICE_INFO_INVALID || !args.v.runlists.data || + args.v.channels.mthd == NV_DEVICE_INFO_INVALID) return -ENODEV; - drm->chan.nr = args.v.channels.data; - drm->chan.context_base = dma_fence_context_alloc(drm->chan.nr); + drm->chan_nr = drm->chan_total = args.v.channels.data; + drm->runl_nr = fls64(args.v.runlists.data); + drm->runl = kcalloc(drm->runl_nr, sizeof(*drm->runl), GFP_KERNEL); + if (!drm->runl) + return -ENOMEM; + + if (drm->chan_nr == 0) { + for (i = 0; i < drm->runl_nr; i++) { + if (!(args.v.runlists.data & BIT(i))) + continue; + + args.v.channels.mthd = NV_DEVICE_HOST_RUNLIST_CHANNELS; + args.v.channels.data = i; + + ret = nvif_object_mthd(device, NV_DEVICE_V0_INFO, &args, sizeof(args)); + if (ret || args.v.channels.mthd == NV_DEVICE_INFO_INVALID) + return -ENODEV; + + drm->runl[i].chan_nr = args.v.channels.data; + drm->runl[i].chan_id_base = drm->chan_total; + drm->runl[i].context_base = dma_fence_context_alloc(drm->runl[i].chan_nr); + + drm->chan_total += drm->runl[i].chan_nr; + } + } else { + drm->runl[0].context_base = dma_fence_context_alloc(drm->chan_nr); + for (i = 1; i < drm->runl_nr; i++) + drm->runl[i].context_base = drm->runl[0].context_base; + + } + return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.h b/drivers/gpu/drm/nouveau/nouveau_chan.h index 98ba9d27e6b4..e06a8ffed31a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_chan.h +++ b/drivers/gpu/drm/nouveau/nouveau_chan.h @@ -2,7 +2,7 @@ #ifndef __NOUVEAU_CHAN_H__ #define __NOUVEAU_CHAN_H__ #include <nvif/object.h> -#include <nvif/notify.h> +#include <nvif/event.h> #include <nvif/push.h> struct nvif_device; @@ -16,6 +16,10 @@ struct nouveau_channel { struct nouveau_drm *drm; struct nouveau_vmm *vmm; + struct nvif_mem mem_userd; + struct nvif_object *userd; + + int runlist; int chid; u64 inst; u32 token; @@ -50,15 +54,15 @@ struct nouveau_channel { struct nvif_object user; - struct nvif_notify kill; + struct nvif_event kill; atomic_t killed; }; int nouveau_channels_init(struct nouveau_drm *); +void nouveau_channels_fini(struct nouveau_drm *); -int nouveau_channel_new(struct nouveau_drm *, struct nvif_device *, - u32 arg0, u32 arg1, bool priv, - struct nouveau_channel **); +int nouveau_channel_new(struct nouveau_drm *, struct nvif_device *, bool priv, u64 runm, + u32 vram, u32 gart, struct nouveau_channel **); void nouveau_channel_del(struct nouveau_channel **); int nouveau_channel_idle(struct nouveau_channel *); diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 1991bbb1d05c..086b66b60d91 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -47,8 +47,7 @@ #include "nouveau_crtc.h" #include <nvif/class.h> -#include <nvif/cl0046.h> -#include <nvif/event.h> +#include <nvif/if0011.h> struct drm_display_mode * nouveau_conn_native_mode(struct drm_connector *connector) @@ -396,7 +395,8 @@ static void nouveau_connector_destroy(struct drm_connector *connector) { struct nouveau_connector *nv_connector = nouveau_connector(connector); - nvif_notify_dtor(&nv_connector->hpd); + nvif_event_dtor(&nv_connector->irq); + nvif_event_dtor(&nv_connector->hpd); kfree(nv_connector->edid); drm_connector_unregister(connector); drm_connector_cleanup(connector); @@ -1162,39 +1162,38 @@ nouveau_connector_funcs_lvds = { }; void -nouveau_connector_hpd(struct drm_connector *connector) +nouveau_connector_hpd(struct nouveau_connector *nv_connector, u64 bits) { - struct nouveau_drm *drm = nouveau_drm(connector->dev); - u32 mask = drm_connector_mask(connector); + struct nouveau_drm *drm = nouveau_drm(nv_connector->base.dev); + u32 mask = drm_connector_mask(&nv_connector->base); + unsigned long flags; - mutex_lock(&drm->hpd_lock); + spin_lock_irqsave(&drm->hpd_lock, flags); if (!(drm->hpd_pending & mask)) { + nv_connector->hpd_pending |= bits; drm->hpd_pending |= mask; schedule_work(&drm->hpd_work); } - mutex_unlock(&drm->hpd_lock); + spin_unlock_irqrestore(&drm->hpd_lock, flags); } static int -nouveau_connector_hotplug(struct nvif_notify *notify) +nouveau_connector_irq(struct nvif_event *event, void *repv, u32 repc) { - struct nouveau_connector *nv_connector = - container_of(notify, typeof(*nv_connector), hpd); - struct drm_connector *connector = &nv_connector->base; - struct drm_device *dev = connector->dev; - struct nouveau_drm *drm = nouveau_drm(dev); - const struct nvif_notify_conn_rep_v0 *rep = notify->data; - bool plugged = (rep->mask != NVIF_NOTIFY_CONN_V0_UNPLUG); + struct nouveau_connector *nv_connector = container_of(event, typeof(*nv_connector), irq); - if (rep->mask & NVIF_NOTIFY_CONN_V0_IRQ) { - nouveau_dp_irq(drm, nv_connector); - return NVIF_NOTIFY_KEEP; - } + schedule_work(&nv_connector->irq_work); + return NVIF_EVENT_KEEP; +} - NV_DEBUG(drm, "%splugged %s\n", plugged ? "" : "un", connector->name); - nouveau_connector_hpd(connector); +static int +nouveau_connector_hotplug(struct nvif_event *event, void *repv, u32 repc) +{ + struct nouveau_connector *nv_connector = container_of(event, typeof(*nv_connector), hpd); + struct nvif_conn_event_v0 *rep = repv; - return NVIF_NOTIFY_KEEP; + nouveau_connector_hpd(nv_connector, rep->types); + return NVIF_EVENT_KEEP; } static ssize_t @@ -1290,6 +1289,7 @@ nouveau_connector_create(struct drm_device *dev, connector = &nv_connector->base; nv_connector->index = index; + INIT_WORK(&nv_connector->irq_work, nouveau_dp_irq); /* attempt to parse vbios connector type and hotplug gpio */ nv_connector->dcb = olddcb_conn(dev, index); @@ -1401,6 +1401,7 @@ nouveau_connector_create(struct drm_device *dev, drm_connector_init(dev, connector, funcs, type); drm_connector_helper_add(connector, &nouveau_connector_helper_funcs); + connector->polled = DRM_CONNECTOR_POLL_CONNECT; if (nv_connector->dcb && (disp->disp.conn_mask & BIT(nv_connector->index))) { ret = nvif_conn_ctor(&disp->disp, nv_connector->base.name, nv_connector->index, @@ -1409,6 +1410,25 @@ nouveau_connector_create(struct drm_device *dev, kfree(nv_connector); return ERR_PTR(ret); } + + ret = nvif_conn_event_ctor(&nv_connector->conn, "kmsHotplug", + nouveau_connector_hotplug, + NVIF_CONN_EVENT_V0_PLUG | NVIF_CONN_EVENT_V0_UNPLUG, + &nv_connector->hpd); + if (ret == 0) + connector->polled = DRM_CONNECTOR_POLL_HPD; + + if (nv_connector->aux.transfer) { + ret = nvif_conn_event_ctor(&nv_connector->conn, "kmsDpIrq", + nouveau_connector_irq, NVIF_CONN_EVENT_V0_IRQ, + &nv_connector->irq); + if (ret) { + nvif_event_dtor(&nv_connector->hpd); + nvif_conn_dtor(&nv_connector->conn); + kfree(nv_connector); + return ERR_PTR(ret); + } + } } connector->funcs->reset(connector); @@ -1452,21 +1472,6 @@ nouveau_connector_create(struct drm_device *dev, break; } - ret = nvif_notify_ctor(&disp->disp.object, "kmsHotplug", - nouveau_connector_hotplug, - true, NV04_DISP_NTFY_CONN, - &(struct nvif_notify_conn_req_v0) { - .mask = NVIF_NOTIFY_CONN_V0_ANY, - .conn = index, - }, - sizeof(struct nvif_notify_conn_req_v0), - sizeof(struct nvif_notify_conn_rep_v0), - &nv_connector->hpd); - if (ret) - connector->polled = DRM_CONNECTOR_POLL_CONNECT; - else - connector->polled = DRM_CONNECTOR_POLL_HPD; - drm_connector_register(connector); return connector; } diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h index f4e17ff68bf9..35bcb541722b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.h +++ b/drivers/gpu/drm/nouveau/nouveau_connector.h @@ -27,7 +27,7 @@ #ifndef __NOUVEAU_CONNECTOR_H__ #define __NOUVEAU_CONNECTOR_H__ #include <nvif/conn.h> -#include <nvif/notify.h> +#include <nvif/event.h> #include <nvhw/class/cl507d.h> #include <nvhw/class/cl907d.h> @@ -124,7 +124,10 @@ struct nouveau_connector { u8 *dcb; struct nvif_conn conn; - struct nvif_notify hpd; + u64 hpd_pending; + struct nvif_event hpd; + struct nvif_event irq; + struct work_struct irq_work; struct drm_dp_aux aux; @@ -198,7 +201,7 @@ nouveau_crtc_connector_get(struct nouveau_crtc *nv_crtc) struct drm_connector * nouveau_connector_create(struct drm_device *, const struct dcb_output *); -void nouveau_connector_hpd(struct drm_connector *connector); +void nouveau_connector_hpd(struct nouveau_connector *, u64 bits); extern int nouveau_tv_disable; extern int nouveau_ignorelid; diff --git a/drivers/gpu/drm/nouveau/nouveau_crtc.h b/drivers/gpu/drm/nouveau/nouveau_crtc.h index 7f63be2ec35d..c717f664a7b8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_crtc.h +++ b/drivers/gpu/drm/nouveau/nouveau_crtc.h @@ -26,16 +26,17 @@ #ifndef __NOUVEAU_CRTC_H__ #define __NOUVEAU_CRTC_H__ - #include <drm/drm_crtc.h> -#include <nvif/notify.h> +#include <nvif/head.h> +#include <nvif/event.h> struct nouveau_crtc { struct drm_crtc base; + struct nvif_head head; int index; - struct nvif_notify vblank; + struct nvif_event vblank; uint32_t dpms_saved_fp_control; uint32_t fp_users; diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 2e97186090c8..ec3ffff487fc 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -35,15 +35,14 @@ #include <drm/drm_probe_helper.h> #include <drm/drm_vblank.h> -#include "nouveau_fbcon.h" #include "nouveau_crtc.h" #include "nouveau_gem.h" #include "nouveau_connector.h" #include "nv50_display.h" #include <nvif/class.h> -#include <nvif/cl0046.h> -#include <nvif/event.h> +#include <nvif/if0011.h> +#include <nvif/if0013.h> #include <dispnv50/crc.h> int @@ -52,7 +51,7 @@ nouveau_display_vblank_enable(struct drm_crtc *crtc) struct nouveau_crtc *nv_crtc; nv_crtc = nouveau_crtc(crtc); - nvif_notify_get(&nv_crtc->vblank); + nvif_event_allow(&nv_crtc->vblank); return 0; } @@ -63,7 +62,7 @@ nouveau_display_vblank_disable(struct drm_crtc *crtc) struct nouveau_crtc *nv_crtc; nv_crtc = nouveau_crtc(crtc); - nvif_notify_put(&nv_crtc->vblank); + nvif_event_block(&nv_crtc->vblank); } static inline int @@ -84,24 +83,20 @@ static bool nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos, ktime_t *stime, ktime_t *etime) { - struct { - struct nv04_disp_mthd_v0 base; - struct nv04_disp_scanoutpos_v0 scan; - } args = { - .base.method = NV04_DISP_SCANOUTPOS, - .base.head = nouveau_crtc(crtc)->index, - }; - struct nouveau_display *disp = nouveau_display(crtc->dev); struct drm_vblank_crtc *vblank = &crtc->dev->vblank[drm_crtc_index(crtc)]; + struct nvif_head *head = &nouveau_crtc(crtc)->head; + struct nvif_head_scanoutpos_v0 args; int retry = 20; bool ret = false; + args.version = 0; + do { - ret = nvif_mthd(&disp->disp.object, 0, &args, sizeof(args)); + ret = nvif_mthd(&head->object, NVIF_HEAD_V0_SCANOUTPOS, &args, sizeof(args)); if (ret != 0) return false; - if (args.scan.vline) { + if (args.vline) { ret = true; break; } @@ -109,11 +104,10 @@ nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos, if (retry) ndelay(vblank->linedur_ns); } while (retry--); - *hpos = args.scan.hline; - *vpos = calc(args.scan.vblanks, args.scan.vblanke, - args.scan.vtotal, args.scan.vline); - if (stime) *stime = ns_to_ktime(args.scan.time[0]); - if (etime) *etime = ns_to_ktime(args.scan.time[1]); + *hpos = args.hline; + *vpos = calc(args.vblanks, args.vblanke, args.vtotal, args.vline); + if (stime) *stime = ns_to_ktime(args.time[0]); + if (etime) *etime = ns_to_ktime(args.time[1]); return ret; } @@ -397,7 +391,7 @@ nouveau_user_framebuffer_create(struct drm_device *dev, static const struct drm_mode_config_funcs nouveau_mode_config_funcs = { .fb_create = nouveau_user_framebuffer_create, - .output_poll_changed = nouveau_fbcon_output_poll_changed, + .output_poll_changed = drm_fb_helper_output_poll_changed, }; @@ -456,9 +450,9 @@ nouveau_display_hpd_resume(struct drm_device *dev) { struct nouveau_drm *drm = nouveau_drm(dev); - mutex_lock(&drm->hpd_lock); + spin_lock_irq(&drm->hpd_lock); drm->hpd_pending = ~0; - mutex_unlock(&drm->hpd_lock); + spin_unlock_irq(&drm->hpd_lock); schedule_work(&drm->hpd_work); } @@ -475,10 +469,10 @@ nouveau_display_hpd_work(struct work_struct *work) pm_runtime_get_sync(dev->dev); - mutex_lock(&drm->hpd_lock); + spin_lock_irq(&drm->hpd_lock); pending = drm->hpd_pending; drm->hpd_pending = 0; - mutex_unlock(&drm->hpd_lock); + spin_unlock_irq(&drm->hpd_lock); /* Nothing to do, exit early without updating the last busy counter */ if (!pending) @@ -488,14 +482,30 @@ nouveau_display_hpd_work(struct work_struct *work) drm_connector_list_iter_begin(dev, &conn_iter); nouveau_for_each_non_mst_connector_iter(connector, &conn_iter) { + struct nouveau_connector *nv_connector = nouveau_connector(connector); enum drm_connector_status old_status = connector->status; - u64 old_epoch_counter = connector->epoch_counter; + u64 bits, old_epoch_counter = connector->epoch_counter; if (!(pending & drm_connector_mask(connector))) continue; - connector->status = drm_helper_probe_detect(connector, NULL, - false); + spin_lock_irq(&drm->hpd_lock); + bits = nv_connector->hpd_pending; + nv_connector->hpd_pending = 0; + spin_unlock_irq(&drm->hpd_lock); + + drm_dbg_kms(dev, "[CONNECTOR:%d:%s] plug:%d unplug:%d irq:%d\n", + connector->base.id, connector->name, + !!(bits & NVIF_CONN_EVENT_V0_PLUG), + !!(bits & NVIF_CONN_EVENT_V0_UNPLUG), + !!(bits & NVIF_CONN_EVENT_V0_IRQ)); + + if (bits & NVIF_CONN_EVENT_V0_IRQ) { + if (nouveau_dp_link_check(nv_connector)) + continue; + } + + connector->status = drm_helper_probe_detect(connector, NULL, false); if (old_epoch_counter == connector->epoch_counter) continue; @@ -573,7 +583,8 @@ nouveau_display_init(struct drm_device *dev, bool resume, bool runtime) drm_connector_list_iter_begin(dev, &conn_iter); nouveau_for_each_non_mst_connector_iter(connector, &conn_iter) { struct nouveau_connector *conn = nouveau_connector(connector); - nvif_notify_get(&conn->hpd); + nvif_event_allow(&conn->hpd); + nvif_event_allow(&conn->irq); } drm_connector_list_iter_end(&conn_iter); @@ -608,7 +619,8 @@ nouveau_display_fini(struct drm_device *dev, bool suspend, bool runtime) drm_connector_list_iter_begin(dev, &conn_iter); nouveau_for_each_non_mst_connector_iter(connector, &conn_iter) { struct nouveau_connector *conn = nouveau_connector(connector); - nvif_notify_put(&conn->hpd); + nvif_event_block(&conn->irq); + nvif_event_block(&conn->hpd); } drm_connector_list_iter_end(&conn_iter); @@ -732,7 +744,7 @@ nouveau_display_create(struct drm_device *dev) } INIT_WORK(&drm->hpd_work, nouveau_display_hpd_work); - mutex_init(&drm->hpd_lock); + spin_lock_init(&drm->hpd_lock); #ifdef CONFIG_ACPI drm->acpi_nb.notifier_call = nouveau_display_acpi_ntfy; register_acpi_notifier(&drm->acpi_nb); @@ -766,8 +778,7 @@ nouveau_display_destroy(struct drm_device *dev) nvif_disp_dtor(&disp->disp); - nouveau_drm(dev)->display = NULL; - mutex_destroy(&drm->hpd_lock); + drm->display = NULL; kfree(disp); } @@ -776,6 +787,9 @@ nouveau_display_suspend(struct drm_device *dev, bool runtime) { struct nouveau_display *disp = nouveau_display(dev); + /* Disable console. */ + drm_fb_helper_set_suspend_unlocked(dev->fb_helper, true); + if (drm_drv_uses_atomic_modeset(dev)) { if (!runtime) { disp->suspend = drm_atomic_helper_suspend(dev); @@ -803,8 +817,10 @@ nouveau_display_resume(struct drm_device *dev, bool runtime) drm_atomic_helper_resume(dev, disp->suspend); disp->suspend = NULL; } - return; } + + /* Enable console. */ + drm_fb_helper_set_suspend_unlocked(dev->fb_helper, false); } int diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.c b/drivers/gpu/drm/nouveau/nouveau_dma.c index ddb75d80bc53..b90cac6d5772 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dma.c +++ b/drivers/gpu/drm/nouveau/nouveau_dma.c @@ -42,9 +42,9 @@ READ_GET(struct nouveau_channel *chan, uint64_t *prev_get, int *timeout) { uint64_t val; - val = nvif_rd32(&chan->user, chan->user_get); + val = nvif_rd32(chan->userd, chan->user_get); if (chan->user_get_hi) - val |= (uint64_t)nvif_rd32(&chan->user, chan->user_get_hi) << 32; + val |= (uint64_t)nvif_rd32(chan->userd, chan->user_get_hi) << 32; /* reset counter as long as GET is still advancing, this is * to avoid misdetecting a GPU lockup if the GPU happens to @@ -86,7 +86,7 @@ nv50_dma_push(struct nouveau_channel *chan, u64 offset, int length) /* Flush writes. */ nouveau_bo_rd32(pb, 0); - nvif_wr32(&chan->user, 0x8c, chan->dma.ib_put); + nvif_wr32(chan->userd, 0x8c, chan->dma.ib_put); if (user->func && user->func->doorbell) user->func->doorbell(user, chan->token); chan->dma.ib_free--; @@ -98,7 +98,7 @@ nv50_dma_push_wait(struct nouveau_channel *chan, int count) uint32_t cnt = 0, prev_get = 0; while (chan->dma.ib_free < count) { - uint32_t get = nvif_rd32(&chan->user, 0x88); + uint32_t get = nvif_rd32(chan->userd, 0x88); if (get != prev_get) { prev_get = get; cnt = 0; diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c index 20db8ea1a0ba..e00876f92aee 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dp.c +++ b/drivers/gpu/drm/nouveau/nouveau_dp.c @@ -29,8 +29,7 @@ #include "nouveau_encoder.h" #include "nouveau_crtc.h" -#include <nvif/class.h> -#include <nvif/cl5070.h> +#include <nvif/if0011.h> MODULE_PARM_DESC(mst, "Enable DisplayPort multi-stream (default: enabled)"); static int nouveau_mst = 1; @@ -140,12 +139,17 @@ nouveau_dp_detect(struct nouveau_connector *nv_connector, * TODO: look into checking this before probing I2C to detect DVI/HDMI */ hpd = nvif_conn_hpd_status(&nv_connector->conn); - if (hpd == NVIF_CONN_HPD_STATUS_NOT_PRESENT) + if (hpd == NVIF_CONN_HPD_STATUS_NOT_PRESENT) { + nvif_outp_dp_aux_pwr(&nv_encoder->outp, false); goto out; + } + nvif_outp_dp_aux_pwr(&nv_encoder->outp, true); status = nouveau_dp_probe_dpcd(nv_connector, nv_encoder); - if (status == connector_status_disconnected) + if (status == connector_status_disconnected) { + nvif_outp_dp_aux_pwr(&nv_encoder->outp, false); goto out; + } /* If we're in MST mode, we're done here */ if (mstm && mstm->can_mst && mstm->is_mst) { @@ -193,6 +197,7 @@ nouveau_dp_detect(struct nouveau_connector *nv_connector, ret = NOUVEAU_DP_MST; goto out; } else if (ret != 0) { + nvif_outp_dp_aux_pwr(&nv_encoder->outp, false); goto out; } } @@ -206,14 +211,28 @@ out: return ret; } -void nouveau_dp_irq(struct nouveau_drm *drm, - struct nouveau_connector *nv_connector) +bool +nouveau_dp_link_check(struct nouveau_connector *nv_connector) +{ + struct nouveau_encoder *nv_encoder = find_encoder(&nv_connector->base, DCB_OUTPUT_DP); + + if (!nv_encoder || nv_encoder->outp.or.id < 0) + return true; + + return nvif_outp_dp_retrain(&nv_encoder->outp) == 0; +} + +void +nouveau_dp_irq(struct work_struct *work) { + struct nouveau_connector *nv_connector = + container_of(work, typeof(*nv_connector), irq_work); struct drm_connector *connector = &nv_connector->base; struct nouveau_encoder *outp = find_encoder(connector, DCB_OUTPUT_DP); + struct nouveau_drm *drm = nouveau_drm(outp->base.base.dev); struct nv50_mstm *mstm; + u64 hpd = 0; int ret; - bool send_hpd = false; if (!outp) return; @@ -225,14 +244,14 @@ void nouveau_dp_irq(struct nouveau_drm *drm, if (mstm && mstm->is_mst) { if (!nv50_mstm_service(drm, nv_connector, mstm)) - send_hpd = true; + hpd |= NVIF_CONN_EVENT_V0_UNPLUG; } else { drm_dp_cec_irq(&nv_connector->aux); if (nouveau_dp_has_sink_count(connector, outp)) { ret = drm_dp_read_sink_count(&nv_connector->aux); if (ret != outp->dp.sink_count) - send_hpd = true; + hpd |= NVIF_CONN_EVENT_V0_PLUG; if (ret >= 0) outp->dp.sink_count = ret; } @@ -240,8 +259,7 @@ void nouveau_dp_irq(struct nouveau_drm *drm, mutex_unlock(&outp->dp.hpd_irq_lock); - if (send_hpd) - nouveau_connector_hpd(connector); + nouveau_connector_hpd(nv_connector, NVIF_CONN_EVENT_V0_IRQ | hpd); } /* TODO: diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index fd99ec0f4257..a19f18b251f3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -33,6 +33,7 @@ #include <drm/drm_aperture.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_drv.h> +#include <drm/drm_fb_helper.h> #include <drm/drm_gem_ttm_helper.h> #include <drm/drm_ioctl.h> #include <drm/drm_vblank.h> @@ -49,7 +50,6 @@ #include <nvif/class.h> #include <nvif/cl0002.h> -#include <nvif/cla06f.h> #include "nouveau_drv.h" #include "nouveau_dma.h" @@ -62,7 +62,6 @@ #include "nouveau_bios.h" #include "nouveau_ioctl.h" #include "nouveau_abi16.h" -#include "nouveau_fbcon.h" #include "nouveau_fence.h" #include "nouveau_debugfs.h" #include "nouveau_usif.h" @@ -316,28 +315,19 @@ static void nouveau_accel_ce_init(struct nouveau_drm *drm) { struct nvif_device *device = &drm->client.device; + u64 runm; int ret = 0; /* Allocate channel that has access to a (preferably async) copy * engine, to use for TTM buffer moves. */ - if (device->info.family >= NV_DEVICE_INFO_V0_KEPLER) { - ret = nouveau_channel_new(drm, device, - nvif_fifo_runlist_ce(device), 0, - true, &drm->cechan); - } else - if (device->info.chipset >= 0xa3 && - device->info.chipset != 0xaa && - device->info.chipset != 0xac) { - /* Prior to Kepler, there's only a single runlist, so all - * engines can be accessed from any channel. - * - * We still want to use a separate channel though. - */ - ret = nouveau_channel_new(drm, device, NvDmaFB, NvDmaTT, false, - &drm->cechan); + runm = nvif_fifo_runlist_ce(device); + if (!runm) { + NV_DEBUG(drm, "no ce runlist\n"); + return; } + ret = nouveau_channel_new(drm, device, false, runm, NvDmaFB, NvDmaTT, &drm->cechan); if (ret) NV_ERROR(drm, "failed to create ce channel, %d\n", ret); } @@ -355,23 +345,17 @@ static void nouveau_accel_gr_init(struct nouveau_drm *drm) { struct nvif_device *device = &drm->client.device; - u32 arg0, arg1; + u64 runm; int ret; - if (device->info.family >= NV_DEVICE_INFO_V0_AMPERE) - return; - /* Allocate channel that has access to the graphics engine. */ - if (device->info.family >= NV_DEVICE_INFO_V0_KEPLER) { - arg0 = nvif_fifo_runlist(device, NV_DEVICE_HOST_RUNLIST_ENGINES_GR); - arg1 = 1; - } else { - arg0 = NvDmaFB; - arg1 = NvDmaTT; + runm = nvif_fifo_runlist(device, NV_DEVICE_HOST_RUNLIST_ENGINES_GR); + if (!runm) { + NV_DEBUG(drm, "no gr runlist\n"); + return; } - ret = nouveau_channel_new(drm, device, arg0, arg1, false, - &drm->channel); + ret = nouveau_channel_new(drm, device, false, runm, NvDmaFB, NvDmaTT, &drm->channel); if (ret) { NV_ERROR(drm, "failed to create kernel channel, %d\n", ret); nouveau_accel_gr_fini(drm); @@ -436,6 +420,7 @@ nouveau_accel_fini(struct nouveau_drm *drm) nouveau_accel_gr_fini(drm); if (drm->fence) nouveau_fence(drm)->dtor(drm); + nouveau_channels_fini(drm); } static void @@ -485,6 +470,7 @@ nouveau_accel_init(struct nouveau_drm *drm) case PASCAL_CHANNEL_GPFIFO_A: case VOLTA_CHANNEL_GPFIFO_A: case TURING_CHANNEL_GPFIFO_A: + case AMPERE_CHANNEL_GPFIFO_A: case AMPERE_CHANNEL_GPFIFO_B: ret = nvc0_fence_create(drm); break; @@ -611,7 +597,6 @@ nouveau_drm_device_init(struct drm_device *dev) nouveau_hwmon_init(dev); nouveau_svm_init(drm); nouveau_dmem_init(drm); - nouveau_fbcon_init(dev); nouveau_led_init(dev); if (nouveau_pmops_runtime()) { @@ -655,7 +640,6 @@ nouveau_drm_device_fini(struct drm_device *dev) } nouveau_led_fini(dev); - nouveau_fbcon_fini(dev); nouveau_dmem_fini(drm); nouveau_svm_fini(drm); nouveau_hwmon_fini(dev); @@ -809,6 +793,11 @@ static int nouveau_drm_probe(struct pci_dev *pdev, if (ret) goto fail_drm_dev_init; + if (nouveau_drm(drm_dev)->client.device.info.ram_size <= 32 * 1024 * 1024) + drm_fbdev_generic_setup(drm_dev, 8); + else + drm_fbdev_generic_setup(drm_dev, 32); + quirk_broken_nv_runpm(pdev); return 0; @@ -865,8 +854,6 @@ nouveau_do_suspend(struct drm_device *dev, bool runtime) nouveau_led_suspend(dev); if (dev->mode_config.num_crtc) { - NV_DEBUG(drm, "suspending console...\n"); - nouveau_fbcon_set_suspend(dev, 1); NV_DEBUG(drm, "suspending display...\n"); ret = nouveau_display_suspend(dev, runtime); if (ret) @@ -940,8 +927,6 @@ nouveau_do_resume(struct drm_device *dev, bool runtime) if (dev->mode_config.num_crtc) { NV_DEBUG(drm, "resuming display...\n"); nouveau_display_resume(dev, runtime); - NV_DEBUG(drm, "resuming console...\n"); - nouveau_fbcon_set_suspend(dev, 0); } nouveau_led_resume(dev); @@ -1296,7 +1281,6 @@ static void nouveau_display_options(void) DRM_DEBUG_DRIVER("... tv_disable : %d\n", nouveau_tv_disable); DRM_DEBUG_DRIVER("... ignorelid : %d\n", nouveau_ignorelid); DRM_DEBUG_DRIVER("... duallink : %d\n", nouveau_duallink); - DRM_DEBUG_DRIVER("... nofbaccel : %d\n", nouveau_nofbaccel); DRM_DEBUG_DRIVER("... config : %s\n", nouveau_config); DRM_DEBUG_DRIVER("... debug : %s\n", nouveau_debug); DRM_DEBUG_DRIVER("... noaccel : %d\n", nouveau_noaccel); diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 84df5ddae4d0..d6dd07bfa64a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -78,11 +78,6 @@ enum nouveau_drm_object_route { NVDRM_OBJECT_ANY = NVIF_IOCTL_V0_OWNER_ANY, }; -enum nouveau_drm_notify_route { - NVDRM_NOTIFY_NVIF = 0, - NVDRM_NOTIFY_USIF -}; - enum nouveau_drm_handle { NVDRM_CHAN = 0xcccc0000, /* |= client chid */ NVDRM_NVSW = 0x55550000, @@ -179,16 +174,19 @@ struct nouveau_drm { void *fence; /* Global channel management. */ + int chan_total; /* Number of channels across all runlists. */ + int chan_nr; /* 0 if per-runlist CHIDs. */ + int runl_nr; struct { - int nr; + int chan_nr; + int chan_id_base; u64 context_base; - } chan; + } *runl; /* context for accelerated drm-internal operations */ struct nouveau_channel *cechan; struct nouveau_channel *channel; struct nvkm_gpuobj *notify; - struct nouveau_fbdev *fbcon; struct nvif_object ntfy; /* nv10-nv40 tiling regions */ @@ -201,10 +199,8 @@ struct nouveau_drm { struct nvbios vbios; struct nouveau_display *display; struct work_struct hpd_work; - struct mutex hpd_lock; + spinlock_t hpd_lock; u32 hpd_pending; - struct work_struct fbcon_work; - int fbcon_new_state; #ifdef CONFIG_ACPI struct notifier_block acpi_nb; #endif diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h index b72e5783a00f..70c1ad6c4d9d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_encoder.h +++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h @@ -48,7 +48,6 @@ struct nouveau_encoder { struct dcb_output *dcb; struct nvif_outp outp; int or; - int link; struct i2c_adapter *i2c; struct nvkm_i2c_aux *aux; @@ -142,8 +141,8 @@ enum nouveau_dp_status { }; int nouveau_dp_detect(struct nouveau_connector *, struct nouveau_encoder *); -void nouveau_dp_irq(struct nouveau_drm *drm, - struct nouveau_connector *nv_connector); +bool nouveau_dp_link_check(struct nouveau_connector *); +void nouveau_dp_irq(struct work_struct *); enum drm_mode_status nv50_dp_mode_valid(struct drm_connector *, struct nouveau_encoder *, const struct drm_display_mode *, diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c deleted file mode 100644 index 3c7e0c9d6baf..000000000000 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ /dev/null @@ -1,614 +0,0 @@ -/* - * Copyright © 2007 David Airlie - * - * 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 (including the next - * paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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. - * - * Authors: - * David Airlie - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/tty.h> -#include <linux/sysrq.h> -#include <linux/delay.h> -#include <linux/init.h> -#include <linux/screen_info.h> -#include <linux/vga_switcheroo.h> -#include <linux/console.h> - -#include <drm/drm_crtc.h> -#include <drm/drm_crtc_helper.h> -#include <drm/drm_probe_helper.h> -#include <drm/drm_fb_helper.h> -#include <drm/drm_fourcc.h> -#include <drm/drm_atomic.h> - -#include "nouveau_drv.h" -#include "nouveau_gem.h" -#include "nouveau_bo.h" -#include "nouveau_fbcon.h" -#include "nouveau_chan.h" -#include "nouveau_vmm.h" - -#include "nouveau_crtc.h" - -MODULE_PARM_DESC(nofbaccel, "Disable fbcon acceleration"); -int nouveau_nofbaccel = 0; -module_param_named(nofbaccel, nouveau_nofbaccel, int, 0400); - -MODULE_PARM_DESC(fbcon_bpp, "fbcon bits-per-pixel (default: auto)"); -static int nouveau_fbcon_bpp; -module_param_named(fbcon_bpp, nouveau_fbcon_bpp, int, 0400); - -static void -nouveau_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) -{ - struct nouveau_fbdev *fbcon = info->par; - struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev); - struct nvif_device *device = &drm->client.device; - int ret; - - if (info->state != FBINFO_STATE_RUNNING) - return; - - ret = -ENODEV; - if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED) && - mutex_trylock(&drm->client.mutex)) { - if (device->info.family < NV_DEVICE_INFO_V0_TESLA) - ret = nv04_fbcon_fillrect(info, rect); - else - if (device->info.family < NV_DEVICE_INFO_V0_FERMI) - ret = nv50_fbcon_fillrect(info, rect); - else - ret = nvc0_fbcon_fillrect(info, rect); - mutex_unlock(&drm->client.mutex); - } - - if (ret == 0) - return; - - if (ret != -ENODEV) - nouveau_fbcon_gpu_lockup(info); - drm_fb_helper_cfb_fillrect(info, rect); -} - -static void -nouveau_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *image) -{ - struct nouveau_fbdev *fbcon = info->par; - struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev); - struct nvif_device *device = &drm->client.device; - int ret; - - if (info->state != FBINFO_STATE_RUNNING) - return; - - ret = -ENODEV; - if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED) && - mutex_trylock(&drm->client.mutex)) { - if (device->info.family < NV_DEVICE_INFO_V0_TESLA) - ret = nv04_fbcon_copyarea(info, image); - else - if (device->info.family < NV_DEVICE_INFO_V0_FERMI) - ret = nv50_fbcon_copyarea(info, image); - else - ret = nvc0_fbcon_copyarea(info, image); - mutex_unlock(&drm->client.mutex); - } - - if (ret == 0) - return; - - if (ret != -ENODEV) - nouveau_fbcon_gpu_lockup(info); - drm_fb_helper_cfb_copyarea(info, image); -} - -static void -nouveau_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) -{ - struct nouveau_fbdev *fbcon = info->par; - struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev); - struct nvif_device *device = &drm->client.device; - int ret; - - if (info->state != FBINFO_STATE_RUNNING) - return; - - ret = -ENODEV; - if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED) && - mutex_trylock(&drm->client.mutex)) { - if (device->info.family < NV_DEVICE_INFO_V0_TESLA) - ret = nv04_fbcon_imageblit(info, image); - else - if (device->info.family < NV_DEVICE_INFO_V0_FERMI) - ret = nv50_fbcon_imageblit(info, image); - else - ret = nvc0_fbcon_imageblit(info, image); - mutex_unlock(&drm->client.mutex); - } - - if (ret == 0) - return; - - if (ret != -ENODEV) - nouveau_fbcon_gpu_lockup(info); - drm_fb_helper_cfb_imageblit(info, image); -} - -static int -nouveau_fbcon_sync(struct fb_info *info) -{ - struct nouveau_fbdev *fbcon = info->par; - struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev); - struct nouveau_channel *chan = drm->channel; - int ret; - - if (!chan || !chan->accel_done || in_interrupt() || - info->state != FBINFO_STATE_RUNNING || - info->flags & FBINFO_HWACCEL_DISABLED) - return 0; - - if (!mutex_trylock(&drm->client.mutex)) - return 0; - - ret = nouveau_channel_idle(chan); - mutex_unlock(&drm->client.mutex); - if (ret) { - nouveau_fbcon_gpu_lockup(info); - return 0; - } - - chan->accel_done = false; - return 0; -} - -static int -nouveau_fbcon_open(struct fb_info *info, int user) -{ - struct nouveau_fbdev *fbcon = info->par; - struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev); - int ret = pm_runtime_get_sync(drm->dev->dev); - if (ret < 0 && ret != -EACCES) { - pm_runtime_put(drm->dev->dev); - return ret; - } - return 0; -} - -static int -nouveau_fbcon_release(struct fb_info *info, int user) -{ - struct nouveau_fbdev *fbcon = info->par; - struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev); - pm_runtime_put(drm->dev->dev); - return 0; -} - -static const struct fb_ops nouveau_fbcon_ops = { - .owner = THIS_MODULE, - DRM_FB_HELPER_DEFAULT_OPS, - .fb_open = nouveau_fbcon_open, - .fb_release = nouveau_fbcon_release, - .fb_fillrect = nouveau_fbcon_fillrect, - .fb_copyarea = nouveau_fbcon_copyarea, - .fb_imageblit = nouveau_fbcon_imageblit, - .fb_sync = nouveau_fbcon_sync, -}; - -static const struct fb_ops nouveau_fbcon_sw_ops = { - .owner = THIS_MODULE, - DRM_FB_HELPER_DEFAULT_OPS, - .fb_open = nouveau_fbcon_open, - .fb_release = nouveau_fbcon_release, - .fb_fillrect = drm_fb_helper_cfb_fillrect, - .fb_copyarea = drm_fb_helper_cfb_copyarea, - .fb_imageblit = drm_fb_helper_cfb_imageblit, -}; - -void -nouveau_fbcon_accel_save_disable(struct drm_device *dev) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - if (drm->fbcon && drm->fbcon->helper.fbdev) { - drm->fbcon->saved_flags = drm->fbcon->helper.fbdev->flags; - drm->fbcon->helper.fbdev->flags |= FBINFO_HWACCEL_DISABLED; - } -} - -void -nouveau_fbcon_accel_restore(struct drm_device *dev) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - if (drm->fbcon && drm->fbcon->helper.fbdev) { - drm->fbcon->helper.fbdev->flags = drm->fbcon->saved_flags; - } -} - -static void -nouveau_fbcon_accel_fini(struct drm_device *dev) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_fbdev *fbcon = drm->fbcon; - if (fbcon && drm->channel) { - console_lock(); - if (fbcon->helper.fbdev) - fbcon->helper.fbdev->flags |= FBINFO_HWACCEL_DISABLED; - console_unlock(); - nouveau_channel_idle(drm->channel); - nvif_object_dtor(&fbcon->twod); - nvif_object_dtor(&fbcon->blit); - nvif_object_dtor(&fbcon->gdi); - nvif_object_dtor(&fbcon->patt); - nvif_object_dtor(&fbcon->rop); - nvif_object_dtor(&fbcon->clip); - nvif_object_dtor(&fbcon->surf2d); - } -} - -static void -nouveau_fbcon_accel_init(struct drm_device *dev) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_fbdev *fbcon = drm->fbcon; - struct fb_info *info = fbcon->helper.fbdev; - int ret; - - if (drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA) - ret = nv04_fbcon_accel_init(info); - else - if (drm->client.device.info.family < NV_DEVICE_INFO_V0_FERMI) - ret = nv50_fbcon_accel_init(info); - else - ret = nvc0_fbcon_accel_init(info); - - if (ret == 0) - info->fbops = &nouveau_fbcon_ops; -} - -static void -nouveau_fbcon_zfill(struct drm_device *dev, struct nouveau_fbdev *fbcon) -{ - struct fb_info *info = fbcon->helper.fbdev; - struct fb_fillrect rect; - - /* Clear the entire fbcon. The drm will program every connector - * with it's preferred mode. If the sizes differ, one display will - * quite likely have garbage around the console. - */ - rect.dx = rect.dy = 0; - rect.width = info->var.xres_virtual; - rect.height = info->var.yres_virtual; - rect.color = 0; - rect.rop = ROP_COPY; - info->fbops->fb_fillrect(info, &rect); -} - -static int -nouveau_fbcon_create(struct drm_fb_helper *helper, - struct drm_fb_helper_surface_size *sizes) -{ - struct nouveau_fbdev *fbcon = - container_of(helper, struct nouveau_fbdev, helper); - struct drm_device *dev = fbcon->helper.dev; - struct nouveau_drm *drm = nouveau_drm(dev); - struct nvif_device *device = &drm->client.device; - struct fb_info *info; - struct drm_framebuffer *fb; - struct nouveau_channel *chan; - struct nouveau_bo *nvbo; - struct drm_mode_fb_cmd2 mode_cmd = {}; - int ret; - - mode_cmd.width = sizes->surface_width; - mode_cmd.height = sizes->surface_height; - - mode_cmd.pitches[0] = mode_cmd.width * (sizes->surface_bpp >> 3); - mode_cmd.pitches[0] = roundup(mode_cmd.pitches[0], 256); - - mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, - sizes->surface_depth); - - ret = nouveau_gem_new(&drm->client, mode_cmd.pitches[0] * - mode_cmd.height, 0, NOUVEAU_GEM_DOMAIN_VRAM, - 0, 0x0000, &nvbo); - if (ret) { - NV_ERROR(drm, "failed to allocate framebuffer\n"); - goto out; - } - - ret = nouveau_framebuffer_new(dev, &mode_cmd, &nvbo->bo.base, &fb); - if (ret) - goto out_unref; - - ret = nouveau_bo_pin(nvbo, NOUVEAU_GEM_DOMAIN_VRAM, false); - if (ret) { - NV_ERROR(drm, "failed to pin fb: %d\n", ret); - goto out_unref; - } - - ret = nouveau_bo_map(nvbo); - if (ret) { - NV_ERROR(drm, "failed to map fb: %d\n", ret); - goto out_unpin; - } - - chan = nouveau_nofbaccel ? NULL : drm->channel; - if (chan && device->info.family >= NV_DEVICE_INFO_V0_TESLA) { - ret = nouveau_vma_new(nvbo, chan->vmm, &fbcon->vma); - if (ret) { - NV_ERROR(drm, "failed to map fb into chan: %d\n", ret); - chan = NULL; - } - } - - info = drm_fb_helper_alloc_fbi(helper); - if (IS_ERR(info)) { - ret = PTR_ERR(info); - goto out_unlock; - } - - /* setup helper */ - fbcon->helper.fb = fb; - - if (!chan) - info->flags = FBINFO_HWACCEL_DISABLED; - else - info->flags = FBINFO_HWACCEL_COPYAREA | - FBINFO_HWACCEL_FILLRECT | - FBINFO_HWACCEL_IMAGEBLIT; - info->fbops = &nouveau_fbcon_sw_ops; - info->fix.smem_start = nvbo->bo.resource->bus.offset; - info->fix.smem_len = nvbo->bo.base.size; - - info->screen_base = nvbo_kmap_obj_iovirtual(nvbo); - info->screen_size = nvbo->bo.base.size; - - drm_fb_helper_fill_info(info, &fbcon->helper, sizes); - - /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */ - - if (chan) - nouveau_fbcon_accel_init(dev); - nouveau_fbcon_zfill(dev, fbcon); - - /* To allow resizeing without swapping buffers */ - NV_INFO(drm, "allocated %dx%d fb: 0x%llx, bo %p\n", - fb->width, fb->height, nvbo->offset, nvbo); - - if (dev_is_pci(dev->dev)) - vga_switcheroo_client_fb_set(to_pci_dev(dev->dev), info); - - return 0; - -out_unlock: - if (chan) - nouveau_vma_del(&fbcon->vma); - nouveau_bo_unmap(nvbo); -out_unpin: - nouveau_bo_unpin(nvbo); -out_unref: - nouveau_bo_ref(NULL, &nvbo); -out: - return ret; -} - -static int -nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *fbcon) -{ - struct drm_framebuffer *fb = fbcon->helper.fb; - struct nouveau_bo *nvbo; - - drm_fb_helper_unregister_fbi(&fbcon->helper); - drm_fb_helper_fini(&fbcon->helper); - - if (fb && fb->obj[0]) { - nvbo = nouveau_gem_object(fb->obj[0]); - nouveau_vma_del(&fbcon->vma); - nouveau_bo_unmap(nvbo); - nouveau_bo_unpin(nvbo); - drm_framebuffer_put(fb); - } - - return 0; -} - -void nouveau_fbcon_gpu_lockup(struct fb_info *info) -{ - struct nouveau_fbdev *fbcon = info->par; - struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev); - - NV_ERROR(drm, "GPU lockup - switching to software fbcon\n"); - info->flags |= FBINFO_HWACCEL_DISABLED; -} - -static const struct drm_fb_helper_funcs nouveau_fbcon_helper_funcs = { - .fb_probe = nouveau_fbcon_create, -}; - -static void -nouveau_fbcon_set_suspend_work(struct work_struct *work) -{ - struct nouveau_drm *drm = container_of(work, typeof(*drm), fbcon_work); - int state = READ_ONCE(drm->fbcon_new_state); - - if (state == FBINFO_STATE_RUNNING) - pm_runtime_get_sync(drm->dev->dev); - - console_lock(); - if (state == FBINFO_STATE_RUNNING) - nouveau_fbcon_accel_restore(drm->dev); - drm_fb_helper_set_suspend(&drm->fbcon->helper, state); - if (state != FBINFO_STATE_RUNNING) - nouveau_fbcon_accel_save_disable(drm->dev); - console_unlock(); - - if (state == FBINFO_STATE_RUNNING) { - nouveau_fbcon_hotplug_resume(drm->fbcon); - pm_runtime_mark_last_busy(drm->dev->dev); - pm_runtime_put_autosuspend(drm->dev->dev); - } -} - -void -nouveau_fbcon_set_suspend(struct drm_device *dev, int state) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - - if (!drm->fbcon) - return; - - drm->fbcon_new_state = state; - /* Since runtime resume can happen as a result of a sysfs operation, - * it's possible we already have the console locked. So handle fbcon - * init/deinit from a seperate work thread - */ - schedule_work(&drm->fbcon_work); -} - -void -nouveau_fbcon_output_poll_changed(struct drm_device *dev) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_fbdev *fbcon = drm->fbcon; - int ret; - - if (!fbcon) - return; - - mutex_lock(&fbcon->hotplug_lock); - - ret = pm_runtime_get(dev->dev); - if (ret == 1 || ret == -EACCES) { - drm_fb_helper_hotplug_event(&fbcon->helper); - - pm_runtime_mark_last_busy(dev->dev); - pm_runtime_put_autosuspend(dev->dev); - } else if (ret == 0) { - /* If the GPU was already in the process of suspending before - * this event happened, then we can't block here as we'll - * deadlock the runtime pmops since they wait for us to - * finish. So, just defer this event for when we runtime - * resume again. It will be handled by fbcon_work. - */ - NV_DEBUG(drm, "fbcon HPD event deferred until runtime resume\n"); - fbcon->hotplug_waiting = true; - pm_runtime_put_noidle(drm->dev->dev); - } else { - DRM_WARN("fbcon HPD event lost due to RPM failure: %d\n", - ret); - } - - mutex_unlock(&fbcon->hotplug_lock); -} - -void -nouveau_fbcon_hotplug_resume(struct nouveau_fbdev *fbcon) -{ - struct nouveau_drm *drm; - - if (!fbcon) - return; - drm = nouveau_drm(fbcon->helper.dev); - - mutex_lock(&fbcon->hotplug_lock); - if (fbcon->hotplug_waiting) { - fbcon->hotplug_waiting = false; - - NV_DEBUG(drm, "Handling deferred fbcon HPD events\n"); - drm_fb_helper_hotplug_event(&fbcon->helper); - } - mutex_unlock(&fbcon->hotplug_lock); -} - -int -nouveau_fbcon_init(struct drm_device *dev) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_fbdev *fbcon; - int preferred_bpp = nouveau_fbcon_bpp; - int ret; - - if (!dev->mode_config.num_crtc || - (to_pci_dev(dev->dev)->class >> 8) != PCI_CLASS_DISPLAY_VGA) - return 0; - - fbcon = kzalloc(sizeof(struct nouveau_fbdev), GFP_KERNEL); - if (!fbcon) - return -ENOMEM; - - drm->fbcon = fbcon; - INIT_WORK(&drm->fbcon_work, nouveau_fbcon_set_suspend_work); - mutex_init(&fbcon->hotplug_lock); - - drm_fb_helper_prepare(dev, &fbcon->helper, &nouveau_fbcon_helper_funcs); - - ret = drm_fb_helper_init(dev, &fbcon->helper); - if (ret) - goto free; - - if (preferred_bpp != 8 && preferred_bpp != 16 && preferred_bpp != 32) { - if (drm->client.device.info.ram_size <= 32 * 1024 * 1024) - preferred_bpp = 8; - else - if (drm->client.device.info.ram_size <= 64 * 1024 * 1024) - preferred_bpp = 16; - else - preferred_bpp = 32; - } - - /* disable all the possible outputs/crtcs before entering KMS mode */ - if (!drm_drv_uses_atomic_modeset(dev)) - drm_helper_disable_unused_functions(dev); - - ret = drm_fb_helper_initial_config(&fbcon->helper, preferred_bpp); - if (ret) - goto fini; - - if (fbcon->helper.fbdev) - fbcon->helper.fbdev->pixmap.buf_align = 4; - return 0; - -fini: - drm_fb_helper_fini(&fbcon->helper); -free: - kfree(fbcon); - drm->fbcon = NULL; - return ret; -} - -void -nouveau_fbcon_fini(struct drm_device *dev) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - - if (!drm->fbcon) - return; - - drm_kms_helper_poll_fini(dev); - nouveau_fbcon_accel_fini(dev); - nouveau_fbcon_destroy(dev, drm->fbcon); - kfree(drm->fbcon); - drm->fbcon = NULL; -} diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.h b/drivers/gpu/drm/nouveau/nouveau_fbcon.h deleted file mode 100644 index 1796d8824580..000000000000 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2008 Maarten Maathuis. - * All Rights Reserved. - * - * 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 (including the - * next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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. - * - */ - -#ifndef __NOUVEAU_FBCON_H__ -#define __NOUVEAU_FBCON_H__ - -#include <drm/drm_fb_helper.h> - -#include "nouveau_display.h" - -struct nouveau_vma; - -struct nouveau_fbdev { - struct drm_fb_helper helper; /* must be first */ - unsigned int saved_flags; - struct nvif_object surf2d; - struct nvif_object clip; - struct nvif_object rop; - struct nvif_object patt; - struct nvif_object gdi; - struct nvif_object blit; - struct nvif_object twod; - struct nouveau_vma *vma; - - struct mutex hotplug_lock; - bool hotplug_waiting; -}; - -void nouveau_fbcon_restore(void); - -int nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region); -int nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect); -int nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image); -int nv04_fbcon_accel_init(struct fb_info *info); - -int nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect); -int nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region); -int nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image); -int nv50_fbcon_accel_init(struct fb_info *info); - -int nvc0_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect); -int nvc0_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region); -int nvc0_fbcon_imageblit(struct fb_info *info, const struct fb_image *image); -int nvc0_fbcon_accel_init(struct fb_info *info); - -void nouveau_fbcon_gpu_lockup(struct fb_info *info); - -int nouveau_fbcon_init(struct drm_device *dev); -void nouveau_fbcon_fini(struct drm_device *dev); -void nouveau_fbcon_set_suspend(struct drm_device *dev, int state); -void nouveau_fbcon_accel_save_disable(struct drm_device *dev); -void nouveau_fbcon_accel_restore(struct drm_device *dev); - -void nouveau_fbcon_output_poll_changed(struct drm_device *dev); -void nouveau_fbcon_hotplug_resume(struct nouveau_fbdev *fbcon); -extern int nouveau_nofbaccel; - -#endif /* __NV50_FBCON_H__ */ - diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index abcac7db4347..ee5e9d40c166 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -29,9 +29,7 @@ #include <linux/sched/signal.h> #include <trace/events/dma_fence.h> -#include <nvif/cl826e.h> -#include <nvif/notify.h> -#include <nvif/event.h> +#include <nvif/if0020.h> #include "nouveau_drv.h" #include "nouveau_dma.h" @@ -79,10 +77,6 @@ nouveau_local_fence(struct dma_fence *fence, struct nouveau_drm *drm) fence->ops != &nouveau_fence_ops_uevent) return NULL; - if (fence->context < drm->chan.context_base || - fence->context >= drm->chan.context_base + drm->chan.nr) - return NULL; - return from_fence(fence); } @@ -90,8 +84,9 @@ void nouveau_fence_context_kill(struct nouveau_fence_chan *fctx, int error) { struct nouveau_fence *fence; + unsigned long flags; - spin_lock_irq(&fctx->lock); + spin_lock_irqsave(&fctx->lock, flags); while (!list_empty(&fctx->pending)) { fence = list_entry(fctx->pending.next, typeof(*fence), head); @@ -99,16 +94,16 @@ nouveau_fence_context_kill(struct nouveau_fence_chan *fctx, int error) dma_fence_set_error(&fence->base, error); if (nouveau_fence_signal(fence)) - nvif_notify_put(&fctx->notify); + nvif_event_block(&fctx->event); } - spin_unlock_irq(&fctx->lock); + spin_unlock_irqrestore(&fctx->lock, flags); } void nouveau_fence_context_del(struct nouveau_fence_chan *fctx) { nouveau_fence_context_kill(fctx, 0); - nvif_notify_dtor(&fctx->notify); + nvif_event_dtor(&fctx->event); fctx->dead = 1; /* @@ -150,12 +145,11 @@ nouveau_fence_update(struct nouveau_channel *chan, struct nouveau_fence_chan *fc } static int -nouveau_fence_wait_uevent_handler(struct nvif_notify *notify) +nouveau_fence_wait_uevent_handler(struct nvif_event *event, void *repv, u32 repc) { - struct nouveau_fence_chan *fctx = - container_of(notify, typeof(*fctx), notify); + struct nouveau_fence_chan *fctx = container_of(event, typeof(*fctx), event); unsigned long flags; - int ret = NVIF_NOTIFY_KEEP; + int ret = NVIF_EVENT_KEEP; spin_lock_irqsave(&fctx->lock, flags); if (!list_empty(&fctx->pending)) { @@ -165,7 +159,7 @@ nouveau_fence_wait_uevent_handler(struct nvif_notify *notify) fence = list_entry(fctx->pending.next, typeof(*fence), head); chan = rcu_dereference_protected(fence->channel, lockdep_is_held(&fctx->lock)); if (nouveau_fence_update(chan, fctx)) - ret = NVIF_NOTIFY_DROP; + ret = NVIF_EVENT_DROP; } spin_unlock_irqrestore(&fctx->lock, flags); @@ -177,12 +171,16 @@ nouveau_fence_context_new(struct nouveau_channel *chan, struct nouveau_fence_cha { struct nouveau_fence_priv *priv = (void*)chan->drm->fence; struct nouveau_cli *cli = (void *)chan->user.client; + struct { + struct nvif_event_v0 base; + struct nvif_chan_event_v0 host; + } args; int ret; INIT_LIST_HEAD(&fctx->flip); INIT_LIST_HEAD(&fctx->pending); spin_lock_init(&fctx->lock); - fctx->context = chan->drm->chan.context_base + chan->chid; + fctx->context = chan->drm->runl[chan->runlist].context_base + chan->chid; if (chan == chan->drm->cechan) strcpy(fctx->name, "copy engine channel"); @@ -195,13 +193,12 @@ nouveau_fence_context_new(struct nouveau_channel *chan, struct nouveau_fence_cha if (!priv->uevent) return; - ret = nvif_notify_ctor(&chan->user, "fenceNonStallIntr", - nouveau_fence_wait_uevent_handler, - false, NV826E_V0_NTFY_NON_STALL_INTERRUPT, - &(struct nvif_notify_uevent_req) { }, - sizeof(struct nvif_notify_uevent_req), - sizeof(struct nvif_notify_uevent_rep), - &fctx->notify); + args.host.version = 0; + args.host.type = NVIF_CHAN_EVENT_V0_NON_STALL_INTR; + + ret = nvif_event_ctor(&chan->user, "fenceNonStallIntr", (chan->runlist << 16) | chan->chid, + nouveau_fence_wait_uevent_handler, false, + &args.base, sizeof(args), &fctx->event); WARN_ON(ret); } @@ -230,7 +227,7 @@ nouveau_fence_emit(struct nouveau_fence *fence, struct nouveau_channel *chan) spin_lock_irq(&fctx->lock); if (nouveau_fence_update(chan, fctx)) - nvif_notify_put(&fctx->notify); + nvif_event_block(&fctx->event); list_add_tail(&fence->head, &fctx->pending); spin_unlock_irq(&fctx->lock); @@ -254,7 +251,7 @@ nouveau_fence_done(struct nouveau_fence *fence) spin_lock_irqsave(&fctx->lock, flags); chan = rcu_dereference_protected(fence->channel, lockdep_is_held(&fctx->lock)); if (chan && nouveau_fence_update(chan, fctx)) - nvif_notify_put(&fctx->notify); + nvif_event_block(&fctx->event); spin_unlock_irqrestore(&fctx->lock, flags); } return dma_fence_is_signaled(&fence->base); @@ -505,13 +502,13 @@ static bool nouveau_fence_enable_signaling(struct dma_fence *f) bool ret; if (!fctx->notify_ref++) - nvif_notify_get(&fctx->notify); + nvif_event_allow(&fctx->event); ret = nouveau_fence_no_signaling(f); if (ret) set_bit(DMA_FENCE_FLAG_USER_BITS, &fence->base.flags); else if (!--fctx->notify_ref) - nvif_notify_put(&fctx->notify); + nvif_event_block(&fctx->event); return ret; } diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.h b/drivers/gpu/drm/nouveau/nouveau_fence.h index 4887caa69c65..0ca2bc85adf6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.h +++ b/drivers/gpu/drm/nouveau/nouveau_fence.h @@ -3,7 +3,7 @@ #define __NOUVEAU_FENCE_H__ #include <linux/dma-fence.h> -#include <nvif/notify.h> +#include <nvif/event.h> struct nouveau_drm; struct nouveau_bo; @@ -44,7 +44,7 @@ struct nouveau_fence_chan { u32 context; char name[32]; - struct nvif_notify notify; + struct nvif_event event; int notify_ref, dead; }; diff --git a/drivers/gpu/drm/nouveau/nouveau_nvif.c b/drivers/gpu/drm/nouveau/nouveau_nvif.c index df0fe58ca3ab..1d49ebdfd5dc 100644 --- a/drivers/gpu/drm/nouveau/nouveau_nvif.c +++ b/drivers/gpu/drm/nouveau/nouveau_nvif.c @@ -27,12 +27,10 @@ ******************************************************************************/ #include <core/client.h> -#include <core/notify.h> #include <core/ioctl.h> #include <nvif/client.h> #include <nvif/driver.h> -#include <nvif/notify.h> #include <nvif/event.h> #include <nvif/ioctl.h> @@ -72,10 +70,23 @@ nvkm_client_suspend(void *priv) } static int +nvkm_client_event(u64 token, void *repv, u32 repc) +{ + struct nvif_object *object = (void *)(unsigned long)token; + struct nvif_event *event = container_of(object, typeof(*event), object); + + if (event->func(event, repv, repc) == NVIF_EVENT_KEEP) + return NVKM_EVENT_KEEP; + + return NVKM_EVENT_DROP; +} + +static int nvkm_client_driver_init(const char *name, u64 device, const char *cfg, const char *dbg, void **ppriv) { - return nvkm_client_new(name, device, cfg, dbg, nvif_notify, (struct nvkm_client **)ppriv); + return nvkm_client_new(name, device, cfg, dbg, nvkm_client_event, + (struct nvkm_client **)ppriv); } const struct nvif_driver diff --git a/drivers/gpu/drm/nouveau/nouveau_svm.c b/drivers/gpu/drm/nouveau/nouveau_svm.c index 31a5b81ee9fc..a74ba8d84ba7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_svm.c +++ b/drivers/gpu/drm/nouveau/nouveau_svm.c @@ -24,7 +24,7 @@ #include "nouveau_chan.h" #include "nouveau_dmem.h" -#include <nvif/notify.h> +#include <nvif/event.h> #include <nvif/object.h> #include <nvif/vmm.h> @@ -51,7 +51,8 @@ struct nouveau_svm { u32 putaddr; u32 get; u32 put; - struct nvif_notify notify; + struct nvif_event notify; + struct work_struct work; struct nouveau_svm_fault { u64 inst; @@ -711,13 +712,11 @@ out: return ret; } -static int -nouveau_svm_fault(struct nvif_notify *notify) +static void +nouveau_svm_fault(struct work_struct *work) { - struct nouveau_svm_fault_buffer *buffer = - container_of(notify, typeof(*buffer), notify); - struct nouveau_svm *svm = - container_of(buffer, typeof(*svm), buffer[buffer->id]); + struct nouveau_svm_fault_buffer *buffer = container_of(work, typeof(*buffer), work); + struct nouveau_svm *svm = container_of(buffer, typeof(*svm), buffer[buffer->id]); struct nvif_object *device = &svm->drm->client.device.object; struct nouveau_svmm *svmm; struct { @@ -737,7 +736,7 @@ nouveau_svm_fault(struct nvif_notify *notify) buffer->put = nvif_rd32(device, buffer->putaddr); buffer->get = nvif_rd32(device, buffer->getaddr); if (buffer->get == buffer->put) - return NVIF_NOTIFY_KEEP; + return; } buffer->fault_nr = 0; @@ -881,7 +880,15 @@ nouveau_svm_fault(struct nvif_notify *notify) /* Issue fault replay to the GPU. */ if (replay) nouveau_svm_fault_replay(svm); - return NVIF_NOTIFY_KEEP; +} + +static int +nouveau_svm_event(struct nvif_event *event, void *argv, u32 argc) +{ + struct nouveau_svm_fault_buffer *buffer = container_of(event, typeof(*buffer), notify); + + schedule_work(&buffer->work); + return NVIF_EVENT_KEEP; } static struct nouveau_pfnmap_args * @@ -936,7 +943,9 @@ static void nouveau_svm_fault_buffer_fini(struct nouveau_svm *svm, int id) { struct nouveau_svm_fault_buffer *buffer = &svm->buffer[id]; - nvif_notify_put(&buffer->notify); + + nvif_event_block(&buffer->notify); + flush_work(&buffer->work); } static int @@ -944,10 +953,12 @@ nouveau_svm_fault_buffer_init(struct nouveau_svm *svm, int id) { struct nouveau_svm_fault_buffer *buffer = &svm->buffer[id]; struct nvif_object *device = &svm->drm->client.device.object; + buffer->get = nvif_rd32(device, buffer->getaddr); buffer->put = nvif_rd32(device, buffer->putaddr); SVM_DBG(svm, "get %08x put %08x (init)", buffer->get, buffer->put); - return nvif_notify_get(&buffer->notify); + + return nvif_event_allow(&buffer->notify); } static void @@ -956,15 +967,18 @@ nouveau_svm_fault_buffer_dtor(struct nouveau_svm *svm, int id) struct nouveau_svm_fault_buffer *buffer = &svm->buffer[id]; int i; + if (!nvif_object_constructed(&buffer->object)) + return; + + nouveau_svm_fault_buffer_fini(svm, id); + if (buffer->fault) { for (i = 0; buffer->fault[i] && i < buffer->entries; i++) kfree(buffer->fault[i]); kvfree(buffer->fault); } - nouveau_svm_fault_buffer_fini(svm, id); - - nvif_notify_dtor(&buffer->notify); + nvif_event_dtor(&buffer->notify); nvif_object_dtor(&buffer->object); } @@ -990,10 +1004,10 @@ nouveau_svm_fault_buffer_ctor(struct nouveau_svm *svm, s32 oclass, int id) buffer->entries = args.entries; buffer->getaddr = args.get; buffer->putaddr = args.put; + INIT_WORK(&buffer->work, nouveau_svm_fault); - ret = nvif_notify_ctor(&buffer->object, "svmFault", nouveau_svm_fault, - true, NVB069_V0_NTFY_FAULT, NULL, 0, 0, - &buffer->notify); + ret = nvif_event_ctor(&buffer->object, "svmFault", id, nouveau_svm_event, true, NULL, 0, + &buffer->notify); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nouveau_usif.c b/drivers/gpu/drm/nouveau/nouveau_usif.c index 36df6840c099..002d1479ba89 100644 --- a/drivers/gpu/drm/nouveau/nouveau_usif.c +++ b/drivers/gpu/drm/nouveau/nouveau_usif.c @@ -151,12 +151,6 @@ usif_ioctl(struct drm_file *filp, void __user *user, u32 argc) case NVIF_IOCTL_V0_NEW: ret = usif_object_new(filp, data, size, argv, argc, abi16); break; - case NVIF_IOCTL_V0_NTFY_NEW: - case NVIF_IOCTL_V0_NTFY_DEL: - case NVIF_IOCTL_V0_NTFY_GET: - case NVIF_IOCTL_V0_NTFY_PUT: - ret = -ENOSYS; - break; default: ret = nvif_client_ioctl(client, argv, argc); break; diff --git a/drivers/gpu/drm/nouveau/nouveau_vga.c b/drivers/gpu/drm/nouveau/nouveau_vga.c index 60cd8c0463df..789393b94291 100644 --- a/drivers/gpu/drm/nouveau/nouveau_vga.c +++ b/drivers/gpu/drm/nouveau/nouveau_vga.c @@ -7,7 +7,6 @@ #include "nouveau_drv.h" #include "nouveau_acpi.h" -#include "nouveau_fbcon.h" #include "nouveau_vga.h" static unsigned int diff --git a/drivers/gpu/drm/nouveau/nv04_fbcon.c b/drivers/gpu/drm/nouveau/nv04_fbcon.c deleted file mode 100644 index c30b8dacd86b..000000000000 --- a/drivers/gpu/drm/nouveau/nv04_fbcon.c +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright 2009 Ben Skeggs - * Copyright 2008 Stuart Bennett - * - * 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 (including the next - * paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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 NVIF_DEBUG_PRINT_DISABLE -#include "nouveau_drv.h" -#include "nouveau_dma.h" -#include "nouveau_fbcon.h" - -#include <nvif/push006c.h> - -int -nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) -{ - struct nouveau_fbdev *nfbdev = info->par; - struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev); - struct nouveau_channel *chan = drm->channel; - struct nvif_push *push = chan->chan.push; - int ret; - - ret = PUSH_WAIT(push, 4); - if (ret) - return ret; - - PUSH_NVSQ(push, NV05F, 0x0300, (region->sy << 16) | region->sx, - 0x0304, (region->dy << 16) | region->dx, - 0x0308, (region->height << 16) | region->width); - PUSH_KICK(push); - return 0; -} - -int -nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) -{ - struct nouveau_fbdev *nfbdev = info->par; - struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev); - struct nouveau_channel *chan = drm->channel; - struct nvif_push *push = chan->chan.push; - int ret; - - ret = PUSH_WAIT(push, 7); - if (ret) - return ret; - - PUSH_NVSQ(push, NV04A, 0x02fc, (rect->rop != ROP_COPY) ? 1 : 3); - if (info->fix.visual == FB_VISUAL_TRUECOLOR || - info->fix.visual == FB_VISUAL_DIRECTCOLOR) - PUSH_NVSQ(push, NV04A, 0x03fc, ((uint32_t *)info->pseudo_palette)[rect->color]); - else - PUSH_NVSQ(push, NV04A, 0x03fc, rect->color); - PUSH_NVSQ(push, NV04A, 0x0400, (rect->dx << 16) | rect->dy, - 0x0404, (rect->width << 16) | rect->height); - PUSH_KICK(push); - return 0; -} - -int -nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) -{ - struct nouveau_fbdev *nfbdev = info->par; - struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev); - struct nouveau_channel *chan = drm->channel; - struct nvif_push *push = chan->chan.push; - uint32_t fg; - uint32_t bg; - uint32_t dsize; - uint32_t *data = (uint32_t *)image->data; - int ret; - - if (image->depth != 1) - return -ENODEV; - - ret = PUSH_WAIT(push, 8); - if (ret) - return ret; - - if (info->fix.visual == FB_VISUAL_TRUECOLOR || - info->fix.visual == FB_VISUAL_DIRECTCOLOR) { - fg = ((uint32_t *) info->pseudo_palette)[image->fg_color]; - bg = ((uint32_t *) info->pseudo_palette)[image->bg_color]; - } else { - fg = image->fg_color; - bg = image->bg_color; - } - - PUSH_NVSQ(push, NV04A, 0x0be4, (image->dy << 16) | (image->dx & 0xffff), - 0x0be8, ((image->dy + image->height) << 16) | - ((image->dx + image->width) & 0xffff), - 0x0bec, bg, - 0x0bf0, fg, - 0x0bf4, (image->height << 16) | ALIGN(image->width, 8), - 0x0bf8, (image->height << 16) | image->width, - 0x0bfc, (image->dy << 16) | (image->dx & 0xffff)); - - dsize = ALIGN(ALIGN(image->width, 8) * image->height, 32) >> 5; - while (dsize) { - int iter_len = dsize > 128 ? 128 : dsize; - - ret = PUSH_WAIT(push, iter_len + 1); - if (ret) - return ret; - - PUSH_NVSQ(push, NV04A, 0x0c00, data, iter_len); - data += iter_len; - dsize -= iter_len; - } - - PUSH_KICK(push); - return 0; -} - -int -nv04_fbcon_accel_init(struct fb_info *info) -{ - struct nouveau_fbdev *nfbdev = info->par; - struct drm_device *dev = nfbdev->helper.dev; - struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_channel *chan = drm->channel; - struct nvif_device *device = &drm->client.device; - struct nvif_push *push = chan->chan.push; - struct nvkm_device *nvkm_device = nvxx_device(&drm->client.device); - resource_size_t fb_base = nvkm_device->func->resource_addr(nvkm_device, 1); - int surface_fmt, pattern_fmt, rect_fmt; - int ret; - - switch (info->var.bits_per_pixel) { - case 8: - surface_fmt = 1; - pattern_fmt = 3; - rect_fmt = 3; - break; - case 16: - surface_fmt = 4; - pattern_fmt = 1; - rect_fmt = 1; - break; - case 32: - switch (info->var.transp.length) { - case 0: /* depth 24 */ - case 8: /* depth 32 */ - break; - default: - return -EINVAL; - } - - surface_fmt = 6; - pattern_fmt = 3; - rect_fmt = 3; - break; - default: - return -EINVAL; - } - - ret = nvif_object_ctor(&chan->user, "fbconCtxSurf2d", 0x0062, - device->info.family >= NV_DEVICE_INFO_V0_CELSIUS ? - 0x0062 : 0x0042, NULL, 0, &nfbdev->surf2d); - if (ret) - return ret; - - ret = nvif_object_ctor(&chan->user, "fbconCtxClip", 0x0019, 0x0019, - NULL, 0, &nfbdev->clip); - if (ret) - return ret; - - ret = nvif_object_ctor(&chan->user, "fbconCtxRop", 0x0043, 0x0043, - NULL, 0, &nfbdev->rop); - if (ret) - return ret; - - ret = nvif_object_ctor(&chan->user, "fbconCtxPatt", 0x0044, 0x0044, - NULL, 0, &nfbdev->patt); - if (ret) - return ret; - - ret = nvif_object_ctor(&chan->user, "fbconGdiRectText", 0x004a, 0x004a, - NULL, 0, &nfbdev->gdi); - if (ret) - return ret; - - ret = nvif_object_ctor(&chan->user, "fbconImageBlit", 0x005f, - device->info.chipset >= 0x11 ? 0x009f : 0x005f, - NULL, 0, &nfbdev->blit); - if (ret) - return ret; - - if (PUSH_WAIT(push, 49 + (device->info.chipset >= 0x11 ? 4 : 0))) { - nouveau_fbcon_gpu_lockup(info); - return 0; - } - - PUSH_NVSQ(push, NV042, 0x0000, nfbdev->surf2d.handle); - PUSH_NVSQ(push, NV042, 0x0184, chan->vram.handle, - 0x0188, chan->vram.handle); - PUSH_NVSQ(push, NV042, 0x0300, surface_fmt, - 0x0304, info->fix.line_length | (info->fix.line_length << 16), - 0x0308, info->fix.smem_start - fb_base, - 0x030c, info->fix.smem_start - fb_base); - - PUSH_NVSQ(push, NV043, 0x0000, nfbdev->rop.handle); - PUSH_NVSQ(push, NV043, 0x0300, 0x55); - - PUSH_NVSQ(push, NV044, 0x0000, nfbdev->patt.handle); - PUSH_NVSQ(push, NV044, 0x0300, pattern_fmt, -#ifdef __BIG_ENDIAN - 0x0304, 2, -#else - 0x0304, 1, -#endif - 0x0308, 0, - 0x030c, 1, - 0x0310, ~0, - 0x0314, ~0, - 0x0318, ~0, - 0x031c, ~0); - - PUSH_NVSQ(push, NV019, 0x0000, nfbdev->clip.handle); - PUSH_NVSQ(push, NV019, 0x0300, 0, - 0x0304, (info->var.yres_virtual << 16) | info->var.xres_virtual); - - PUSH_NVSQ(push, NV05F, 0x0000, nfbdev->blit.handle); - PUSH_NVSQ(push, NV05F, 0x019c, nfbdev->surf2d.handle); - PUSH_NVSQ(push, NV05F, 0x02fc, 3); - if (nfbdev->blit.oclass == 0x009f) { - PUSH_NVSQ(push, NV09F, 0x0120, 0, - 0x0124, 1, - 0x0128, 2); - } - - PUSH_NVSQ(push, NV04A, 0x0000, nfbdev->gdi.handle); - PUSH_NVSQ(push, NV04A, 0x0198, nfbdev->surf2d.handle); - PUSH_NVSQ(push, NV04A, 0x0188, nfbdev->patt.handle, - 0x018c, nfbdev->rop.handle); - PUSH_NVSQ(push, NV04A, 0x0304, 1); - PUSH_NVSQ(push, NV04A, 0x0300, rect_fmt); - PUSH_NVSQ(push, NV04A, 0x02fc, 3); - - PUSH_KICK(push); - return 0; -} - diff --git a/drivers/gpu/drm/nouveau/nv50_fbcon.c b/drivers/gpu/drm/nouveau/nv50_fbcon.c deleted file mode 100644 index 71f92e4750f9..000000000000 --- a/drivers/gpu/drm/nouveau/nv50_fbcon.c +++ /dev/null @@ -1,299 +0,0 @@ -/* - * Copyright 2010 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. - * - * Authors: Ben Skeggs - */ -#define NVIF_DEBUG_PRINT_DISABLE -#include "nouveau_drv.h" -#include "nouveau_dma.h" -#include "nouveau_fbcon.h" -#include "nouveau_vmm.h" - -#include <nvif/push206e.h> - -#include <nvhw/class/cl502d.h> - -int -nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) -{ - struct nouveau_fbdev *nfbdev = info->par; - struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev); - struct nouveau_channel *chan = drm->channel; - struct nvif_push *push = chan->chan.push; - u32 colour; - int ret; - - if (info->fix.visual == FB_VISUAL_TRUECOLOR || - info->fix.visual == FB_VISUAL_DIRECTCOLOR) - colour = ((uint32_t *)info->pseudo_palette)[rect->color]; - else - colour = rect->color; - - ret = PUSH_WAIT(push, rect->rop == ROP_COPY ? 7 : 11); - if (ret) - return ret; - - if (rect->rop != ROP_COPY) { - PUSH_MTHD(push, NV502D, SET_OPERATION, - NVDEF(NV502D, SET_OPERATION, V, ROP_AND)); - } - - PUSH_MTHD(push, NV502D, SET_RENDER_SOLID_PRIM_COLOR, colour); - - PUSH_MTHD(push, NV502D, RENDER_SOLID_PRIM_POINT_SET_X(0), rect->dx, - RENDER_SOLID_PRIM_POINT_Y(0), rect->dy, - RENDER_SOLID_PRIM_POINT_SET_X(1), rect->dx + rect->width, - RENDER_SOLID_PRIM_POINT_Y(1), rect->dy + rect->height); - - if (rect->rop != ROP_COPY) { - PUSH_MTHD(push, NV502D, SET_OPERATION, - NVDEF(NV502D, SET_OPERATION, V, SRCCOPY)); - } - - PUSH_KICK(push); - return 0; -} - -int -nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) -{ - struct nouveau_fbdev *nfbdev = info->par; - struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev); - struct nouveau_channel *chan = drm->channel; - struct nvif_push *push = chan->chan.push; - int ret; - - ret = PUSH_WAIT(push, 12); - if (ret) - return ret; - - PUSH_MTHD(push, NV502D, WAIT_FOR_IDLE, 0); - - PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_MEMORY_DST_X0, region->dx, - SET_PIXELS_FROM_MEMORY_DST_Y0, region->dy, - SET_PIXELS_FROM_MEMORY_DST_WIDTH, region->width, - SET_PIXELS_FROM_MEMORY_DST_HEIGHT, region->height); - - PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_MEMORY_SRC_X0_FRAC, 0, - SET_PIXELS_FROM_MEMORY_SRC_X0_INT, region->sx, - SET_PIXELS_FROM_MEMORY_SRC_Y0_FRAC, 0, - PIXELS_FROM_MEMORY_SRC_Y0_INT, region->sy); - PUSH_KICK(push); - return 0; -} - -int -nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) -{ - struct nouveau_fbdev *nfbdev = info->par; - struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev); - struct nouveau_channel *chan = drm->channel; - struct nvif_push *push = chan->chan.push; - uint32_t dwords, *data = (uint32_t *)image->data; - uint32_t mask = ~(~0 >> (32 - info->var.bits_per_pixel)); - uint32_t *palette = info->pseudo_palette, bg, fg; - int ret; - - if (image->depth != 1) - return -ENODEV; - - if (info->fix.visual == FB_VISUAL_TRUECOLOR || - info->fix.visual == FB_VISUAL_DIRECTCOLOR) { - bg = palette[image->bg_color] | mask; - fg = palette[image->fg_color] | mask; - } else { - bg = image->bg_color; - fg = image->fg_color; - } - - ret = PUSH_WAIT(push, 11); - if (ret) - return ret; - - PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_CPU_COLOR0, bg, - SET_PIXELS_FROM_CPU_COLOR1, fg); - - PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_CPU_SRC_WIDTH, image->width, - SET_PIXELS_FROM_CPU_SRC_HEIGHT, image->height); - - PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_CPU_DST_X0_FRAC, 0, - SET_PIXELS_FROM_CPU_DST_X0_INT, image->dx, - SET_PIXELS_FROM_CPU_DST_Y0_FRAC, 0, - SET_PIXELS_FROM_CPU_DST_Y0_INT, image->dy); - - dwords = ALIGN(ALIGN(image->width, 8) * image->height, 32) >> 5; - while (dwords) { - int count = dwords > 2047 ? 2047 : dwords; - - ret = PUSH_WAIT(push, count + 1); - if (ret) - return ret; - - dwords -= count; - - PUSH_NINC(push, NV502D, PIXELS_FROM_CPU_DATA, data, count); - data += count; - } - - PUSH_KICK(push); - return 0; -} - -int -nv50_fbcon_accel_init(struct fb_info *info) -{ - struct nouveau_fbdev *nfbdev = info->par; - struct drm_device *dev = nfbdev->helper.dev; - struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_channel *chan = drm->channel; - struct nvif_push *push = chan->chan.push; - int ret, format; - - switch (info->var.bits_per_pixel) { - case 8: - format = NV502D_SET_DST_FORMAT_V_Y8; - break; - case 15: - format = NV502D_SET_DST_FORMAT_V_X1R5G5B5; - break; - case 16: - format = NV502D_SET_DST_FORMAT_V_R5G6B5; - break; - case 32: - switch (info->var.transp.length) { - case 0: /* depth 24 */ - case 8: /* depth 32, just use 24.. */ - format = NV502D_SET_DST_FORMAT_V_X8R8G8B8; - break; - case 2: /* depth 30 */ - format = NV502D_SET_DST_FORMAT_V_A2B10G10R10; - break; - default: - return -EINVAL; - } - break; - default: - return -EINVAL; - } - - ret = nvif_object_ctor(&chan->user, "fbconTwoD", 0x502d, 0x502d, - NULL, 0, &nfbdev->twod); - if (ret) - return ret; - - ret = PUSH_WAIT(push, 56); - if (ret) { - nouveau_fbcon_gpu_lockup(info); - return ret; - } - - PUSH_MTHD(push, NV502D, SET_OBJECT, nfbdev->twod.handle); - PUSH_MTHD(push, NV502D, SET_DST_CONTEXT_DMA, chan->vram.handle, - SET_SRC_CONTEXT_DMA, chan->vram.handle, - SET_SEMAPHORE_CONTEXT_DMA, chan->vram.handle); - - PUSH_MTHD(push, NV502D, SET_DST_FORMAT, - NVVAL(NV502D, SET_DST_FORMAT, V, format), - - SET_DST_MEMORY_LAYOUT, - NVDEF(NV502D, SET_DST_MEMORY_LAYOUT, V, PITCH)); - - PUSH_MTHD(push, NV502D, SET_DST_PITCH, info->fix.line_length, - SET_DST_WIDTH, info->var.xres_virtual, - SET_DST_HEIGHT, info->var.yres_virtual, - - SET_DST_OFFSET_UPPER, - NVVAL(NV502D, SET_DST_OFFSET_UPPER, V, upper_32_bits(nfbdev->vma->addr)), - - SET_DST_OFFSET_LOWER, - NVVAL(NV502D, SET_DST_OFFSET_LOWER, V, lower_32_bits(nfbdev->vma->addr))); - - PUSH_MTHD(push, NV502D, SET_SRC_FORMAT, - NVVAL(NV502D, SET_SRC_FORMAT, V, format), - - SET_SRC_MEMORY_LAYOUT, - NVDEF(NV502D, SET_SRC_MEMORY_LAYOUT, V, PITCH)); - - PUSH_MTHD(push, NV502D, SET_SRC_PITCH, info->fix.line_length, - SET_SRC_WIDTH, info->var.xres_virtual, - SET_SRC_HEIGHT, info->var.yres_virtual, - - SET_SRC_OFFSET_UPPER, - NVVAL(NV502D, SET_SRC_OFFSET_UPPER, V, upper_32_bits(nfbdev->vma->addr)), - - SET_SRC_OFFSET_LOWER, - NVVAL(NV502D, SET_SRC_OFFSET_LOWER, V, lower_32_bits(nfbdev->vma->addr))); - - PUSH_MTHD(push, NV502D, SET_CLIP_ENABLE, - NVDEF(NV502D, SET_CLIP_ENABLE, V, FALSE)); - - PUSH_MTHD(push, NV502D, SET_ROP, - NVVAL(NV502D, SET_ROP, V, 0x55)); - - PUSH_MTHD(push, NV502D, SET_OPERATION, - NVDEF(NV502D, SET_OPERATION, V, SRCCOPY)); - - PUSH_MTHD(push, NV502D, SET_MONOCHROME_PATTERN_COLOR_FORMAT, - NVDEF(NV502D, SET_MONOCHROME_PATTERN_COLOR_FORMAT, V, A8R8G8B8), - - SET_MONOCHROME_PATTERN_FORMAT, - NVDEF(NV502D, SET_MONOCHROME_PATTERN_FORMAT, V, LE_M1)); - - PUSH_MTHD(push, NV502D, RENDER_SOLID_PRIM_MODE, - NVDEF(NV502D, RENDER_SOLID_PRIM_MODE, V, RECTS), - - SET_RENDER_SOLID_PRIM_COLOR_FORMAT, - NVVAL(NV502D, SET_RENDER_SOLID_PRIM_COLOR_FORMAT, V, format)); - - PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_CPU_DATA_TYPE, - NVDEF(NV502D, SET_PIXELS_FROM_CPU_DATA_TYPE, V, INDEX), - - SET_PIXELS_FROM_CPU_COLOR_FORMAT, - NVVAL(NV502D, SET_PIXELS_FROM_CPU_COLOR_FORMAT, V, format), - - SET_PIXELS_FROM_CPU_INDEX_FORMAT, - NVDEF(NV502D, SET_PIXELS_FROM_CPU_INDEX_FORMAT, V, I1), - - SET_PIXELS_FROM_CPU_MONO_FORMAT, - NVDEF(NV502D, SET_PIXELS_FROM_CPU_MONO_FORMAT, V, CGA6_M1), - - SET_PIXELS_FROM_CPU_WRAP, - NVDEF(NV502D, SET_PIXELS_FROM_CPU_WRAP, V, WRAP_BYTE)); - - PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_CPU_MONO_OPACITY, - NVDEF(NV502D, SET_PIXELS_FROM_CPU_MONO_OPACITY, V, OPAQUE)); - - PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_CPU_DX_DU_FRAC, 0, - SET_PIXELS_FROM_CPU_DX_DU_INT, 1, - SET_PIXELS_FROM_CPU_DY_DV_FRAC, 0, - SET_PIXELS_FROM_CPU_DY_DV_INT, 1); - - PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_MEMORY_SAFE_OVERLAP, - NVDEF(NV502D, SET_PIXELS_FROM_MEMORY_SAFE_OVERLAP, V, TRUE)); - - PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_MEMORY_DU_DX_FRAC, 0, - SET_PIXELS_FROM_MEMORY_DU_DX_INT, 1, - SET_PIXELS_FROM_MEMORY_DV_DY_FRAC, 0, - SET_PIXELS_FROM_MEMORY_DV_DY_INT, 1); - PUSH_KICK(push); - return 0; -} - diff --git a/drivers/gpu/drm/nouveau/nv84_fence.c b/drivers/gpu/drm/nouveau/nv84_fence.c index c3526a8622e3..812b8c62eeba 100644 --- a/drivers/gpu/drm/nouveau/nv84_fence.c +++ b/drivers/gpu/drm/nouveau/nv84_fence.c @@ -76,12 +76,18 @@ nv84_fence_sync32(struct nouveau_channel *chan, u64 virtual, u32 sequence) return ret; } +static inline u32 +nv84_fence_chid(struct nouveau_channel *chan) +{ + return chan->drm->runl[chan->runlist].chan_id_base + chan->chid; +} + static int nv84_fence_emit(struct nouveau_fence *fence) { struct nouveau_channel *chan = fence->channel; struct nv84_fence_chan *fctx = chan->fence; - u64 addr = fctx->vma->addr + chan->chid * 16; + u64 addr = fctx->vma->addr + nv84_fence_chid(chan) * 16; return fctx->base.emit32(chan, addr, fence->base.seqno); } @@ -91,7 +97,7 @@ nv84_fence_sync(struct nouveau_fence *fence, struct nouveau_channel *prev, struct nouveau_channel *chan) { struct nv84_fence_chan *fctx = chan->fence; - u64 addr = fctx->vma->addr + prev->chid * 16; + u64 addr = fctx->vma->addr + nv84_fence_chid(prev) * 16; return fctx->base.sync32(chan, addr, fence->base.seqno); } @@ -100,7 +106,7 @@ static u32 nv84_fence_read(struct nouveau_channel *chan) { struct nv84_fence_priv *priv = chan->drm->fence; - return nouveau_bo_rd32(priv->bo, chan->chid * 16/4); + return nouveau_bo_rd32(priv->bo, nv84_fence_chid(chan) * 16/4); } static void @@ -109,7 +115,7 @@ nv84_fence_context_del(struct nouveau_channel *chan) struct nv84_fence_priv *priv = chan->drm->fence; struct nv84_fence_chan *fctx = chan->fence; - nouveau_bo_wr32(priv->bo, chan->chid * 16 / 4, fctx->base.sequence); + nouveau_bo_wr32(priv->bo, nv84_fence_chid(chan) * 16 / 4, fctx->base.sequence); mutex_lock(&priv->mutex); nouveau_vma_del(&fctx->vma); mutex_unlock(&priv->mutex); @@ -152,9 +158,9 @@ nv84_fence_suspend(struct nouveau_drm *drm) struct nv84_fence_priv *priv = drm->fence; int i; - priv->suspend = vmalloc(array_size(sizeof(u32), drm->chan.nr)); + priv->suspend = vmalloc(array_size(sizeof(u32), drm->chan_total)); if (priv->suspend) { - for (i = 0; i < drm->chan.nr; i++) + for (i = 0; i < drm->chan_total; i++) priv->suspend[i] = nouveau_bo_rd32(priv->bo, i*4); } @@ -168,7 +174,7 @@ nv84_fence_resume(struct nouveau_drm *drm) int i; if (priv->suspend) { - for (i = 0; i < drm->chan.nr; i++) + for (i = 0; i < drm->chan_total; i++) nouveau_bo_wr32(priv->bo, i*4, priv->suspend[i]); vfree(priv->suspend); priv->suspend = NULL; @@ -204,7 +210,7 @@ nv84_fence_create(struct nouveau_drm *drm) priv->base.context_new = nv84_fence_context_new; priv->base.context_del = nv84_fence_context_del; - priv->base.uevent = drm->client.device.info.family < NV_DEVICE_INFO_V0_AMPERE; + priv->base.uevent = true; mutex_init(&priv->mutex); @@ -216,7 +222,7 @@ nv84_fence_create(struct nouveau_drm *drm) * will lose CPU/GPU coherency! */ NOUVEAU_GEM_DOMAIN_GART | NOUVEAU_GEM_DOMAIN_COHERENT; - ret = nouveau_bo_new(&drm->client, 16 * drm->chan.nr, 0, + ret = nouveau_bo_new(&drm->client, 16 * drm->chan_total, 0, domain, 0, 0, NULL, NULL, &priv->bo); if (ret == 0) { ret = nouveau_bo_pin(priv->bo, domain, false); diff --git a/drivers/gpu/drm/nouveau/nvc0_fbcon.c b/drivers/gpu/drm/nouveau/nvc0_fbcon.c deleted file mode 100644 index 7908a1a3e00f..000000000000 --- a/drivers/gpu/drm/nouveau/nvc0_fbcon.c +++ /dev/null @@ -1,297 +0,0 @@ -/* - * Copyright 2010 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. - * - * Authors: Ben Skeggs - */ -#define NVIF_DEBUG_PRINT_DISABLE -#include "nouveau_drv.h" -#include "nouveau_dma.h" -#include "nouveau_fbcon.h" -#include "nouveau_vmm.h" - -#include <nvif/push906f.h> - -#include <nvhw/class/cl902d.h> - -int -nvc0_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) -{ - struct nouveau_fbdev *nfbdev = info->par; - struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev); - struct nouveau_channel *chan = drm->channel; - struct nvif_push *push = chan->chan.push; - u32 colour; - int ret; - - if (info->fix.visual == FB_VISUAL_TRUECOLOR || - info->fix.visual == FB_VISUAL_DIRECTCOLOR) - colour = ((uint32_t *)info->pseudo_palette)[rect->color]; - else - colour = rect->color; - - ret = PUSH_WAIT(push, rect->rop == ROP_COPY ? 7 : 9); - if (ret) - return ret; - - if (rect->rop != ROP_COPY) { - PUSH_IMMD(push, NV902D, SET_OPERATION, - NVDEF(NV902D, SET_OPERATION, V, ROP_AND)); - } - - PUSH_MTHD(push, NV902D, SET_RENDER_SOLID_PRIM_COLOR, colour); - - PUSH_MTHD(push, NV902D, RENDER_SOLID_PRIM_POINT_SET_X(0), rect->dx, - RENDER_SOLID_PRIM_POINT_Y(0), rect->dy, - RENDER_SOLID_PRIM_POINT_SET_X(1), rect->dx + rect->width, - RENDER_SOLID_PRIM_POINT_Y(1), rect->dy + rect->height); - - if (rect->rop != ROP_COPY) { - PUSH_IMMD(push, NV902D, SET_OPERATION, - NVDEF(NV902D, SET_OPERATION, V, SRCCOPY)); - } - - PUSH_KICK(push); - return 0; -} - -int -nvc0_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) -{ - struct nouveau_fbdev *nfbdev = info->par; - struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev); - struct nouveau_channel *chan = drm->channel; - struct nvif_push *push = chan->chan.push; - int ret; - - ret = PUSH_WAIT(push, 11); - if (ret) - return ret; - - PUSH_IMMD(push, NV902D, WAIT_FOR_IDLE, 0); - - PUSH_MTHD(push, NV902D, SET_PIXELS_FROM_MEMORY_DST_X0, region->dx, - SET_PIXELS_FROM_MEMORY_DST_Y0, region->dy, - SET_PIXELS_FROM_MEMORY_DST_WIDTH, region->width, - SET_PIXELS_FROM_MEMORY_DST_HEIGHT, region->height); - - PUSH_MTHD(push, NV902D, SET_PIXELS_FROM_MEMORY_SRC_X0_FRAC, 0, - SET_PIXELS_FROM_MEMORY_SRC_X0_INT, region->sx, - SET_PIXELS_FROM_MEMORY_SRC_Y0_FRAC, 0, - PIXELS_FROM_MEMORY_SRC_Y0_INT, region->sy); - PUSH_KICK(push); - return 0; -} - -int -nvc0_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) -{ - struct nouveau_fbdev *nfbdev = info->par; - struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev); - struct nouveau_channel *chan = drm->channel; - struct nvif_push *push = chan->chan.push; - uint32_t dwords, *data = (uint32_t *)image->data; - uint32_t mask = ~(~0 >> (32 - info->var.bits_per_pixel)); - uint32_t *palette = info->pseudo_palette, bg, fg; - int ret; - - if (image->depth != 1) - return -ENODEV; - - if (info->fix.visual == FB_VISUAL_TRUECOLOR || - info->fix.visual == FB_VISUAL_DIRECTCOLOR) { - bg = palette[image->bg_color] | mask; - fg = palette[image->fg_color] | mask; - } else { - bg = image->bg_color; - fg = image->fg_color; - } - - ret = PUSH_WAIT(push, 11); - if (ret) - return ret; - - PUSH_MTHD(push, NV902D, SET_PIXELS_FROM_CPU_COLOR0, bg, - SET_PIXELS_FROM_CPU_COLOR1, fg); - - PUSH_MTHD(push, NV902D, SET_PIXELS_FROM_CPU_SRC_WIDTH, image->width, - SET_PIXELS_FROM_CPU_SRC_HEIGHT, image->height); - - PUSH_MTHD(push, NV902D, SET_PIXELS_FROM_CPU_DST_X0_FRAC, 0, - SET_PIXELS_FROM_CPU_DST_X0_INT, image->dx, - SET_PIXELS_FROM_CPU_DST_Y0_FRAC, 0, - SET_PIXELS_FROM_CPU_DST_Y0_INT, image->dy); - - dwords = ALIGN(ALIGN(image->width, 8) * image->height, 32) >> 5; - while (dwords) { - int count = dwords > 2047 ? 2047 : dwords; - - ret = PUSH_WAIT(push, count + 1); - if (ret) - return ret; - - dwords -= count; - - PUSH_NINC(push, NV902D, PIXELS_FROM_CPU_DATA, data, count); - data += count; - } - - PUSH_KICK(push); - return 0; -} - -int -nvc0_fbcon_accel_init(struct fb_info *info) -{ - struct nouveau_fbdev *nfbdev = info->par; - struct drm_device *dev = nfbdev->helper.dev; - struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_channel *chan = drm->channel; - struct nvif_push *push = chan->chan.push; - int ret, format; - - ret = nvif_object_ctor(&chan->user, "fbconTwoD", 0x902d, 0x902d, - NULL, 0, &nfbdev->twod); - if (ret) - return ret; - - switch (info->var.bits_per_pixel) { - case 8: - format = NV902D_SET_DST_FORMAT_V_Y8; - break; - case 15: - format = NV902D_SET_DST_FORMAT_V_X1R5G5B5; - break; - case 16: - format = NV902D_SET_DST_FORMAT_V_R5G6B5; - break; - case 32: - switch (info->var.transp.length) { - case 0: /* depth 24 */ - case 8: /* depth 32, just use 24.. */ - format = NV902D_SET_DST_FORMAT_V_X8R8G8B8; - break; - case 2: /* depth 30 */ - format = NV902D_SET_DST_FORMAT_V_A2B10G10R10; - break; - default: - return -EINVAL; - } - break; - default: - return -EINVAL; - } - - ret = PUSH_WAIT(push, 52); - if (ret) { - WARN_ON(1); - nouveau_fbcon_gpu_lockup(info); - return ret; - } - - PUSH_MTHD(push, NV902D, SET_OBJECT, nfbdev->twod.handle); - - PUSH_MTHD(push, NV902D, SET_DST_FORMAT, - NVVAL(NV902D, SET_DST_FORMAT, V, format), - - SET_DST_MEMORY_LAYOUT, - NVDEF(NV902D, SET_DST_MEMORY_LAYOUT, V, PITCH)); - - PUSH_MTHD(push, NV902D, SET_DST_PITCH, info->fix.line_length, - SET_DST_WIDTH, info->var.xres_virtual, - SET_DST_HEIGHT, info->var.yres_virtual, - - SET_DST_OFFSET_UPPER, - NVVAL(NV902D, SET_DST_OFFSET_UPPER, V, upper_32_bits(nfbdev->vma->addr)), - - SET_DST_OFFSET_LOWER, - NVVAL(NV902D, SET_DST_OFFSET_LOWER, V, lower_32_bits(nfbdev->vma->addr))); - - PUSH_MTHD(push, NV902D, SET_SRC_FORMAT, - NVVAL(NV902D, SET_SRC_FORMAT, V, format), - - SET_SRC_MEMORY_LAYOUT, - NVDEF(NV902D, SET_SRC_MEMORY_LAYOUT, V, PITCH)); - - PUSH_MTHD(push, NV902D, SET_SRC_PITCH, info->fix.line_length, - SET_SRC_WIDTH, info->var.xres_virtual, - SET_SRC_HEIGHT, info->var.yres_virtual, - - SET_SRC_OFFSET_UPPER, - NVVAL(NV902D, SET_SRC_OFFSET_UPPER, V, upper_32_bits(nfbdev->vma->addr)), - - SET_SRC_OFFSET_LOWER, - NVVAL(NV902D, SET_SRC_OFFSET_LOWER, V, lower_32_bits(nfbdev->vma->addr))); - - PUSH_IMMD(push, NV902D, SET_CLIP_ENABLE, - NVDEF(NV902D, SET_CLIP_ENABLE, V, FALSE)); - - PUSH_IMMD(push, NV902D, SET_ROP, - NVVAL(NV902D, SET_ROP, V, 0x55)); - - PUSH_IMMD(push, NV902D, SET_OPERATION, - NVDEF(NV902D, SET_OPERATION, V, SRCCOPY)); - - PUSH_MTHD(push, NV902D, SET_MONOCHROME_PATTERN_COLOR_FORMAT, - NVDEF(NV902D, SET_MONOCHROME_PATTERN_COLOR_FORMAT, V, A8R8G8B8), - - SET_MONOCHROME_PATTERN_FORMAT, - NVDEF(NV902D, SET_MONOCHROME_PATTERN_FORMAT, V, LE_M1)); - - PUSH_MTHD(push, NV902D, RENDER_SOLID_PRIM_MODE, - NVDEF(NV902D, RENDER_SOLID_PRIM_MODE, V, RECTS), - - SET_RENDER_SOLID_PRIM_COLOR_FORMAT, - NVVAL(NV902D, SET_RENDER_SOLID_PRIM_COLOR_FORMAT, V, format)); - - PUSH_MTHD(push, NV902D, SET_PIXELS_FROM_CPU_DATA_TYPE, - NVDEF(NV902D, SET_PIXELS_FROM_CPU_DATA_TYPE, V, INDEX), - - SET_PIXELS_FROM_CPU_COLOR_FORMAT, - NVVAL(NV902D, SET_PIXELS_FROM_CPU_COLOR_FORMAT, V, format), - - SET_PIXELS_FROM_CPU_INDEX_FORMAT, - NVDEF(NV902D, SET_PIXELS_FROM_CPU_INDEX_FORMAT, V, I1), - - SET_PIXELS_FROM_CPU_MONO_FORMAT, - NVDEF(NV902D, SET_PIXELS_FROM_CPU_MONO_FORMAT, V, CGA6_M1), - - SET_PIXELS_FROM_CPU_WRAP, - NVDEF(NV902D, SET_PIXELS_FROM_CPU_WRAP, V, WRAP_BYTE)); - - PUSH_IMMD(push, NV902D, SET_PIXELS_FROM_CPU_MONO_OPACITY, - NVDEF(NV902D, SET_PIXELS_FROM_CPU_MONO_OPACITY, V, OPAQUE)); - - PUSH_MTHD(push, NV902D, SET_PIXELS_FROM_CPU_DX_DU_FRAC, 0, - SET_PIXELS_FROM_CPU_DX_DU_INT, 1, - SET_PIXELS_FROM_CPU_DY_DV_FRAC, 0, - SET_PIXELS_FROM_CPU_DY_DV_INT, 1); - - PUSH_IMMD(push, NV902D, SET_PIXELS_FROM_MEMORY_SAFE_OVERLAP, - NVDEF(NV902D, SET_PIXELS_FROM_MEMORY_SAFE_OVERLAP, V, TRUE)); - - PUSH_MTHD(push, NV902D, SET_PIXELS_FROM_MEMORY_DU_DX_FRAC, 0, - SET_PIXELS_FROM_MEMORY_DU_DX_INT, 1, - SET_PIXELS_FROM_MEMORY_DV_DY_FRAC, 0, - SET_PIXELS_FROM_MEMORY_DV_DY_INT, 1); - PUSH_KICK(push); - return 0; -} - diff --git a/drivers/gpu/drm/nouveau/nvif/Kbuild b/drivers/gpu/drm/nouveau/nvif/Kbuild index 6abc4bc42e35..b7963a39dd91 100644 --- a/drivers/gpu/drm/nouveau/nvif/Kbuild +++ b/drivers/gpu/drm/nouveau/nvif/Kbuild @@ -5,10 +5,11 @@ nvif-y += nvif/conn.o nvif-y += nvif/device.o nvif-y += nvif/disp.o nvif-y += nvif/driver.o +nvif-y += nvif/event.o nvif-y += nvif/fifo.o +nvif-y += nvif/head.o nvif-y += nvif/mem.o nvif-y += nvif/mmu.o -nvif-y += nvif/notify.o nvif-y += nvif/outp.o nvif-y += nvif/timer.o nvif-y += nvif/vmm.o diff --git a/drivers/gpu/drm/nouveau/nvif/conn.c b/drivers/gpu/drm/nouveau/nvif/conn.c index 4ce935d58c90..a3cf91aeae2d 100644 --- a/drivers/gpu/drm/nouveau/nvif/conn.c +++ b/drivers/gpu/drm/nouveau/nvif/conn.c @@ -27,6 +27,25 @@ #include <nvif/if0011.h> int +nvif_conn_event_ctor(struct nvif_conn *conn, const char *name, nvif_event_func func, u8 types, + struct nvif_event *event) +{ + struct { + struct nvif_event_v0 base; + struct nvif_conn_event_v0 conn; + } args; + int ret; + + args.conn.version = 0; + args.conn.types = types; + + ret = nvif_event_ctor_(&conn->object, name ?: "nvifConnHpd", nvif_conn_id(conn), + func, true, &args.base, sizeof(args), false, event); + NVIF_DEBUG(&conn->object, "[NEW EVENT:HPD types:%02x]", types); + return ret; +} + +int nvif_conn_hpd_status(struct nvif_conn *conn) { struct nvif_conn_hpd_status_v0 args; diff --git a/drivers/gpu/drm/nouveau/nvif/disp.c b/drivers/gpu/drm/nouveau/nvif/disp.c index 926b0c04b1e8..09915f2715af 100644 --- a/drivers/gpu/drm/nouveau/nvif/disp.c +++ b/drivers/gpu/drm/nouveau/nvif/disp.c @@ -72,9 +72,10 @@ nvif_disp_ctor(struct nvif_device *device, const char *name, s32 oclass, struct if (ret) return ret; - NVIF_DEBUG(&disp->object, "[NEW] conn_mask:%08x outp_mask:%08x", - args.conn_mask, args.outp_mask); + NVIF_DEBUG(&disp->object, "[NEW] conn_mask:%08x outp_mask:%08x head_mask:%08x", + args.conn_mask, args.outp_mask, args.head_mask); disp->conn_mask = args.conn_mask; disp->outp_mask = args.outp_mask; + disp->head_mask = args.head_mask; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvif/event.c b/drivers/gpu/drm/nouveau/nvif/event.c new file mode 100644 index 000000000000..61ff4d6eba9f --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvif/event.c @@ -0,0 +1,81 @@ +/* + * 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 <nvif/event.h> +#include <nvif/printf.h> + +#include <nvif/class.h> +#include <nvif/if000e.h> + +int +nvif_event_block(struct nvif_event *event) +{ + if (nvif_event_constructed(event)) { + int ret = nvif_mthd(&event->object, NVIF_EVENT_V0_BLOCK, NULL, 0); + NVIF_ERRON(ret, &event->object, "[BLOCK]"); + return ret; + } + return 0; +} + +int +nvif_event_allow(struct nvif_event *event) +{ + if (nvif_event_constructed(event)) { + int ret = nvif_mthd(&event->object, NVIF_EVENT_V0_ALLOW, NULL, 0); + NVIF_ERRON(ret, &event->object, "[ALLOW]"); + return ret; + } + return 0; +} + +void +nvif_event_dtor(struct nvif_event *event) +{ + nvif_object_dtor(&event->object); +} + +int +nvif_event_ctor_(struct nvif_object *parent, const char *name, u32 handle, nvif_event_func func, + bool wait, struct nvif_event_v0 *args, u32 argc, bool warn, + struct nvif_event *event) +{ + struct nvif_event_v0 _args; + int ret; + + if (!args) { + args = &_args; + argc = sizeof(_args); + } + + args->version = 0; + args->wait = wait; + + ret = nvif_object_ctor(parent, name ?: "nvifEvent", handle, + NVIF_CLASS_EVENT, args, argc, &event->object); + NVIF_ERRON(ret && warn, parent, "[NEW EVENT wait:%d size:%zd]", + args->wait, argc - sizeof(*args)); + if (ret) + return ret; + + event->func = func; + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvif/head.c b/drivers/gpu/drm/nouveau/nvif/head.c new file mode 100644 index 000000000000..f00e01d232db --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvif/head.c @@ -0,0 +1,58 @@ +/* + * 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 <nvif/head.h> +#include <nvif/disp.h> +#include <nvif/printf.h> + +#include <nvif/class.h> +#include <nvif/if0013.h> + +int +nvif_head_vblank_event_ctor(struct nvif_head *head, const char *name, nvif_event_func func, + bool wait, struct nvif_event *event) +{ + int ret = nvif_event_ctor(&head->object, name ?: "nvifHeadVBlank", nvif_head_id(head), + func, wait, NULL, 0, event); + NVIF_ERRON(ret, &head->object, "[NEW EVENT:VBLANK]"); + return ret; +} + +void +nvif_head_dtor(struct nvif_head *head) +{ + nvif_object_dtor(&head->object); +} + +int +nvif_head_ctor(struct nvif_disp *disp, const char *name, int id, struct nvif_head *head) +{ + struct nvif_head_v0 args; + int ret; + + args.version = 0; + args.id = id; + + ret = nvif_object_ctor(&disp->object, name ? name : "nvifHead", id, NVIF_CLASS_HEAD, + &args, sizeof(args), &head->object); + NVIF_ERRON(ret, &disp->object, "[NEW head id:%d]", args.id); + return ret; +} diff --git a/drivers/gpu/drm/nouveau/nvif/notify.c b/drivers/gpu/drm/nouveau/nvif/notify.c deleted file mode 100644 index 143c8dc6889e..000000000000 --- a/drivers/gpu/drm/nouveau/nvif/notify.c +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright 2014 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. - * - * Authors: Ben Skeggs <bskeggs@redhat.com> - */ - -#include <nvif/client.h> -#include <nvif/driver.h> -#include <nvif/notify.h> -#include <nvif/object.h> -#include <nvif/ioctl.h> -#include <nvif/event.h> - -static inline int -nvif_notify_put_(struct nvif_notify *notify) -{ - struct nvif_object *object = notify->object; - struct { - struct nvif_ioctl_v0 ioctl; - struct nvif_ioctl_ntfy_put_v0 ntfy; - } args = { - .ioctl.type = NVIF_IOCTL_V0_NTFY_PUT, - .ntfy.index = notify->index, - }; - - if (atomic_inc_return(¬ify->putcnt) != 1) - return 0; - - return nvif_object_ioctl(object, &args, sizeof(args), NULL); -} - -int -nvif_notify_put(struct nvif_notify *notify) -{ - if (likely(notify->object) && - test_and_clear_bit(NVIF_NOTIFY_USER, ¬ify->flags)) { - int ret = nvif_notify_put_(notify); - if (test_bit(NVIF_NOTIFY_WORK, ¬ify->flags)) - flush_work(¬ify->work); - return ret; - } - return 0; -} - -static inline int -nvif_notify_get_(struct nvif_notify *notify) -{ - struct nvif_object *object = notify->object; - struct { - struct nvif_ioctl_v0 ioctl; - struct nvif_ioctl_ntfy_get_v0 ntfy; - } args = { - .ioctl.type = NVIF_IOCTL_V0_NTFY_GET, - .ntfy.index = notify->index, - }; - - if (atomic_dec_return(¬ify->putcnt) != 0) - return 0; - - return nvif_object_ioctl(object, &args, sizeof(args), NULL); -} - -int -nvif_notify_get(struct nvif_notify *notify) -{ - if (likely(notify->object) && - !test_and_set_bit(NVIF_NOTIFY_USER, ¬ify->flags)) - return nvif_notify_get_(notify); - return 0; -} - -static inline int -nvif_notify_func(struct nvif_notify *notify, bool keep) -{ - int ret = notify->func(notify); - if (ret == NVIF_NOTIFY_KEEP || - !test_and_clear_bit(NVIF_NOTIFY_USER, ¬ify->flags)) { - if (!keep) - atomic_dec(¬ify->putcnt); - else - nvif_notify_get_(notify); - } - return ret; -} - -static void -nvif_notify_work(struct work_struct *work) -{ - struct nvif_notify *notify = container_of(work, typeof(*notify), work); - nvif_notify_func(notify, true); -} - -int -nvif_notify(const void *header, u32 length, const void *data, u32 size) -{ - struct nvif_notify *notify = NULL; - const union { - struct nvif_notify_rep_v0 v0; - } *args = header; - int ret = NVIF_NOTIFY_DROP; - - if (length == sizeof(args->v0) && args->v0.version == 0) { - if (WARN_ON(args->v0.route)) - return NVIF_NOTIFY_DROP; - notify = (void *)(unsigned long)args->v0.token; - } - - if (!WARN_ON(notify == NULL)) { - struct nvif_client *client = notify->object->client; - if (!WARN_ON(notify->size != size)) { - atomic_inc(¬ify->putcnt); - if (test_bit(NVIF_NOTIFY_WORK, ¬ify->flags)) { - memcpy((void *)notify->data, data, size); - schedule_work(¬ify->work); - return NVIF_NOTIFY_DROP; - } - notify->data = data; - ret = nvif_notify_func(notify, client->driver->keep); - notify->data = NULL; - } - } - - return ret; -} - -int -nvif_notify_dtor(struct nvif_notify *notify) -{ - struct nvif_object *object = notify->object; - struct { - struct nvif_ioctl_v0 ioctl; - struct nvif_ioctl_ntfy_del_v0 ntfy; - } args = { - .ioctl.type = NVIF_IOCTL_V0_NTFY_DEL, - .ntfy.index = notify->index, - }; - int ret = nvif_notify_put(notify); - if (ret >= 0 && object) { - ret = nvif_object_ioctl(object, &args, sizeof(args), NULL); - notify->object = NULL; - kfree((void *)notify->data); - } - return ret; -} - -int -nvif_notify_ctor(struct nvif_object *object, const char *name, - int (*func)(struct nvif_notify *), bool work, u8 event, - void *data, u32 size, u32 reply, struct nvif_notify *notify) -{ - struct { - struct nvif_ioctl_v0 ioctl; - struct nvif_ioctl_ntfy_new_v0 ntfy; - struct nvif_notify_req_v0 req; - } *args; - int ret = -ENOMEM; - - notify->object = object; - notify->name = name ? name : "nvifNotify"; - notify->flags = 0; - atomic_set(¬ify->putcnt, 1); - notify->func = func; - notify->data = NULL; - notify->size = reply; - if (work) { - INIT_WORK(¬ify->work, nvif_notify_work); - set_bit(NVIF_NOTIFY_WORK, ¬ify->flags); - notify->data = kmalloc(notify->size, GFP_KERNEL); - if (!notify->data) - goto done; - } - - if (!(args = kmalloc(sizeof(*args) + size, GFP_KERNEL))) - goto done; - args->ioctl.version = 0; - args->ioctl.type = NVIF_IOCTL_V0_NTFY_NEW; - args->ntfy.version = 0; - args->ntfy.event = event; - args->req.version = 0; - args->req.reply = notify->size; - args->req.route = 0; - args->req.token = (unsigned long)(void *)notify; - - memcpy(args->req.data, data, size); - ret = nvif_object_ioctl(object, args, sizeof(*args) + size, NULL); - notify->index = args->ntfy.index; - kfree(args); -done: - if (ret) - nvif_notify_dtor(notify); - return ret; -} diff --git a/drivers/gpu/drm/nouveau/nvif/outp.c b/drivers/gpu/drm/nouveau/nvif/outp.c index 7bfe91a8d6f9..7da39f1eae9f 100644 --- a/drivers/gpu/drm/nouveau/nvif/outp.c +++ b/drivers/gpu/drm/nouveau/nvif/outp.c @@ -24,7 +24,177 @@ #include <nvif/printf.h> #include <nvif/class.h> -#include <nvif/if0012.h> + +int +nvif_outp_dp_mst_vcpi(struct nvif_outp *outp, int head, + u8 start_slot, u8 num_slots, u16 pbn, u16 aligned_pbn) +{ + struct nvif_outp_dp_mst_vcpi_v0 args; + int ret; + + args.version = 0; + args.head = head; + args.start_slot = start_slot; + args.num_slots = num_slots; + args.pbn = pbn; + args.aligned_pbn = aligned_pbn; + + ret = nvif_object_mthd(&outp->object, NVIF_OUTP_V0_DP_MST_VCPI, &args, sizeof(args)); + NVIF_ERRON(ret, &outp->object, + "[DP_MST_VCPI head:%d start_slot:%02x num_slots:%02x pbn:%04x aligned_pbn:%04x]", + args.head, args.start_slot, args.num_slots, args.pbn, args.aligned_pbn); + return ret; +} + +int +nvif_outp_dp_retrain(struct nvif_outp *outp) +{ + int ret = nvif_object_mthd(&outp->object, NVIF_OUTP_V0_DP_RETRAIN, NULL, 0); + NVIF_ERRON(ret, &outp->object, "[DP_RETRAIN]"); + return ret; +} + +int +nvif_outp_dp_aux_pwr(struct nvif_outp *outp, bool enable) +{ + struct nvif_outp_dp_aux_pwr_v0 args; + int ret; + + args.version = 0; + args.state = enable; + + ret = nvif_object_mthd(&outp->object, NVIF_OUTP_V0_DP_AUX_PWR, &args, sizeof(args)); + NVIF_ERRON(ret, &outp->object, "[DP_AUX_PWR state:%d]", args.state); + return ret; +} + +int +nvif_outp_hda_eld(struct nvif_outp *outp, int head, void *data, u32 size) +{ + struct { + struct nvif_outp_hda_eld_v0 mthd; + u8 data[128]; + } args; + int ret; + + if (WARN_ON(size > ARRAY_SIZE(args.data))) + return -EINVAL; + + args.mthd.version = 0; + args.mthd.head = head; + + memcpy(args.data, data, size); + ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_HDA_ELD, &args, sizeof(args.mthd) + size); + NVIF_ERRON(ret, &outp->object, "[HDA_ELD head:%d size:%d]", head, size); + return ret; +} + +int +nvif_outp_infoframe(struct nvif_outp *outp, u8 type, struct nvif_outp_infoframe_v0 *args, u32 size) +{ + int ret; + + args->type = type; + + ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_INFOFRAME, args, sizeof(*args) + size); + NVIF_ERRON(ret, &outp->object, "[INFOFRAME type:%d size:%d]", type, size); + return ret; +} + +void +nvif_outp_release(struct nvif_outp *outp) +{ + int ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_RELEASE, NULL, 0); + NVIF_ERRON(ret, &outp->object, "[RELEASE]"); + outp->or.id = -1; +} + +static inline int +nvif_outp_acquire(struct nvif_outp *outp, u8 proto, struct nvif_outp_acquire_v0 *args) +{ + int ret; + + args->version = 0; + args->proto = proto; + + ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_ACQUIRE, args, sizeof(*args)); + if (ret) + return ret; + + outp->or.id = args->or; + outp->or.link = args->link; + return 0; +} + +int +nvif_outp_acquire_dp(struct nvif_outp *outp, u8 dpcd[16], + int link_nr, int link_bw, bool hda, bool mst) +{ + struct nvif_outp_acquire_v0 args; + int ret; + + args.dp.link_nr = link_nr; + args.dp.link_bw = link_bw; + args.dp.hda = hda; + args.dp.mst = mst; + memcpy(args.dp.dpcd, dpcd, sizeof(args.dp.dpcd)); + + ret = nvif_outp_acquire(outp, NVIF_OUTP_ACQUIRE_V0_DP, &args); + NVIF_ERRON(ret, &outp->object, + "[ACQUIRE proto:DP link_nr:%d link_bw:%02x hda:%d mst:%d] or:%d link:%d", + args.dp.link_nr, args.dp.link_bw, args.dp.hda, args.dp.mst, args.or, args.link); + return ret; +} + +int +nvif_outp_acquire_lvds(struct nvif_outp *outp, bool dual, bool bpc8) +{ + struct nvif_outp_acquire_v0 args; + int ret; + + args.lvds.dual = dual; + args.lvds.bpc8 = bpc8; + + ret = nvif_outp_acquire(outp, NVIF_OUTP_ACQUIRE_V0_LVDS, &args); + NVIF_ERRON(ret, &outp->object, + "[ACQUIRE proto:LVDS dual:%d 8bpc:%d] or:%d link:%d", + args.lvds.dual, args.lvds.bpc8, args.or, args.link); + return ret; +} + +int +nvif_outp_acquire_tmds(struct nvif_outp *outp, int head, + bool hdmi, u8 max_ac_packet, u8 rekey, u8 scdc, bool hda) +{ + struct nvif_outp_acquire_v0 args; + int ret; + + args.tmds.head = head; + args.tmds.hdmi = hdmi; + args.tmds.hdmi_max_ac_packet = max_ac_packet; + args.tmds.hdmi_rekey = rekey; + args.tmds.hdmi_scdc = scdc; + args.tmds.hdmi_hda = hda; + + ret = nvif_outp_acquire(outp, NVIF_OUTP_ACQUIRE_V0_TMDS, &args); + NVIF_ERRON(ret, &outp->object, + "[ACQUIRE proto:TMDS head:%d hdmi:%d max_ac_packet:%d rekey:%d scdc:%d hda:%d]" + " or:%d link:%d", args.tmds.head, args.tmds.hdmi, args.tmds.hdmi_max_ac_packet, + args.tmds.hdmi_rekey, args.tmds.hdmi_scdc, args.tmds.hdmi_hda, + args.or, args.link); + return ret; +} + +int +nvif_outp_acquire_rgb_crt(struct nvif_outp *outp) +{ + struct nvif_outp_acquire_v0 args; + int ret; + + ret = nvif_outp_acquire(outp, NVIF_OUTP_ACQUIRE_V0_RGB_CRT, &args); + NVIF_ERRON(ret, &outp->object, "[ACQUIRE proto:RGB_CRT] or:%d", args.or); + return ret; +} int nvif_outp_load_detect(struct nvif_outp *outp, u32 loadval) @@ -58,5 +228,9 @@ nvif_outp_ctor(struct nvif_disp *disp, const char *name, int id, struct nvif_out ret = nvif_object_ctor(&disp->object, name ?: "nvifOutp", id, NVIF_CLASS_OUTP, &args, sizeof(args), &outp->object); NVIF_ERRON(ret, &disp->object, "[NEW outp id:%d]", id); - return ret; + if (ret) + return ret; + + outp->or.id = -1; + return 0; } diff --git a/drivers/gpu/drm/nouveau/nvif/user.c b/drivers/gpu/drm/nouveau/nvif/user.c index d89f5b67b304..b648a5e036af 100644 --- a/drivers/gpu/drm/nouveau/nvif/user.c +++ b/drivers/gpu/drm/nouveau/nvif/user.c @@ -41,7 +41,9 @@ nvif_user_ctor(struct nvif_device *device, const char *name) int version; const struct nvif_user_func *func; } users[] = { - { VOLTA_USERMODE_A, -1, &nvif_userc361 }, + { AMPERE_USERMODE_A, -1, &nvif_userc361 }, + { TURING_USERMODE_A, -1, &nvif_userc361 }, + { VOLTA_USERMODE_A, -1, &nvif_userc361 }, {} }; int cid, ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/core/Kbuild b/drivers/gpu/drm/nouveau/nvkm/core/Kbuild index 2b471ab585b4..e40712023c73 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/core/Kbuild @@ -5,12 +5,13 @@ nvkm-y += nvkm/core/enum.o nvkm-y += nvkm/core/event.o nvkm-y += nvkm/core/firmware.o nvkm-y += nvkm/core/gpuobj.o +nvkm-y += nvkm/core/intr.o nvkm-y += nvkm/core/ioctl.o nvkm-y += nvkm/core/memory.o nvkm-y += nvkm/core/mm.o -nvkm-y += nvkm/core/notify.o nvkm-y += nvkm/core/object.o nvkm-y += nvkm/core/oproxy.o nvkm-y += nvkm/core/option.o nvkm-y += nvkm/core/ramht.o nvkm-y += nvkm/core/subdev.o +nvkm-y += nvkm/core/uevent.o diff --git a/drivers/gpu/drm/nouveau/nvkm/core/client.c b/drivers/gpu/drm/nouveau/nvkm/core/client.c index 0c8c55c73b12..ebdeb8eb9e77 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/client.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/client.c @@ -23,7 +23,6 @@ */ #include <core/client.h> #include <core/device.h> -#include <core/notify.h> #include <core/option.h> #include <nvif/class.h> @@ -44,7 +43,7 @@ nvkm_uclient_new(const struct nvkm_oclass *oclass, void *argv, u32 argc, if (!(ret = nvif_unpack(ret, &argv, &argc, args->v0, 0, 0, false))){ args->v0.name[sizeof(args->v0.name) - 1] = 0; ret = nvkm_client_new(args->v0.name, args->v0.device, NULL, - NULL, oclass->client->ntfy, &client); + NULL, oclass->client->event, &client); if (ret) return ret; } else @@ -68,113 +67,6 @@ nvkm_uclient_sclass = { .ctor = nvkm_uclient_new, }; -struct nvkm_client_notify { - struct nvkm_client *client; - struct nvkm_notify n; - u8 version; - u8 size; - union { - struct nvif_notify_rep_v0 v0; - } rep; -}; - -static int -nvkm_client_notify(struct nvkm_notify *n) -{ - struct nvkm_client_notify *notify = container_of(n, typeof(*notify), n); - struct nvkm_client *client = notify->client; - return client->ntfy(¬ify->rep, notify->size, n->data, n->size); -} - -int -nvkm_client_notify_put(struct nvkm_client *client, int index) -{ - if (index < ARRAY_SIZE(client->notify)) { - if (client->notify[index]) { - nvkm_notify_put(&client->notify[index]->n); - return 0; - } - } - return -ENOENT; -} - -int -nvkm_client_notify_get(struct nvkm_client *client, int index) -{ - if (index < ARRAY_SIZE(client->notify)) { - if (client->notify[index]) { - nvkm_notify_get(&client->notify[index]->n); - return 0; - } - } - return -ENOENT; -} - -int -nvkm_client_notify_del(struct nvkm_client *client, int index) -{ - if (index < ARRAY_SIZE(client->notify)) { - if (client->notify[index]) { - nvkm_notify_fini(&client->notify[index]->n); - kfree(client->notify[index]); - client->notify[index] = NULL; - return 0; - } - } - return -ENOENT; -} - -int -nvkm_client_notify_new(struct nvkm_object *object, - struct nvkm_event *event, void *data, u32 size) -{ - struct nvkm_client *client = object->client; - struct nvkm_client_notify *notify; - union { - struct nvif_notify_req_v0 v0; - } *req = data; - u8 index, reply; - int ret = -ENOSYS; - - for (index = 0; index < ARRAY_SIZE(client->notify); index++) { - if (!client->notify[index]) - break; - } - - if (index == ARRAY_SIZE(client->notify)) - return -ENOSPC; - - notify = kzalloc(sizeof(*notify), GFP_KERNEL); - if (!notify) - return -ENOMEM; - - nvif_ioctl(object, "notify new size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, req->v0, 0, 0, true))) { - nvif_ioctl(object, "notify new vers %d reply %d route %02x " - "token %llx\n", req->v0.version, - req->v0.reply, req->v0.route, req->v0.token); - notify->version = req->v0.version; - notify->size = sizeof(notify->rep.v0); - notify->rep.v0.version = req->v0.version; - notify->rep.v0.route = req->v0.route; - notify->rep.v0.token = req->v0.token; - reply = req->v0.reply; - } - - if (ret == 0) { - ret = nvkm_notify_init(object, event, nvkm_client_notify, - false, data, size, reply, ¬ify->n); - if (ret == 0) { - client->notify[index] = notify; - notify->client = client; - return index; - } - } - - kfree(notify); - return ret; -} - static const struct nvkm_object_func nvkm_client; struct nvkm_client * nvkm_client_search(struct nvkm_client *client, u64 handle) @@ -255,23 +147,13 @@ nvkm_client_child_get(struct nvkm_object *object, int index, static int nvkm_client_fini(struct nvkm_object *object, bool suspend) { - struct nvkm_client *client = nvkm_client(object); - const char *name[2] = { "fini", "suspend" }; - int i; - nvif_debug(object, "%s notify\n", name[suspend]); - for (i = 0; i < ARRAY_SIZE(client->notify); i++) - nvkm_client_notify_put(client, i); return 0; } static void * nvkm_client_dtor(struct nvkm_object *object) { - struct nvkm_client *client = nvkm_client(object); - int i; - for (i = 0; i < ARRAY_SIZE(client->notify); i++) - nvkm_client_notify_del(client, i); - return client; + return nvkm_client(object); } static const struct nvkm_object_func @@ -283,10 +165,8 @@ nvkm_client = { }; int -nvkm_client_new(const char *name, u64 device, const char *cfg, - const char *dbg, - int (*ntfy)(const void *, u32, const void *, u32), - struct nvkm_client **pclient) +nvkm_client_new(const char *name, u64 device, const char *cfg, const char *dbg, + int (*event)(u64, void *, u32), struct nvkm_client **pclient) { struct nvkm_oclass oclass = { .base = nvkm_uclient_sclass }; struct nvkm_client *client; @@ -300,7 +180,7 @@ nvkm_client_new(const char *name, u64 device, const char *cfg, client->device = device; client->debug = nvkm_dbgopt(dbg, "CLIENT"); client->objroot = RB_ROOT; - client->ntfy = ntfy; + client->event = event; INIT_LIST_HEAD(&client->umem); spin_lock_init(&client->lock); return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/core/engine.c b/drivers/gpu/drm/nouveau/nvkm/core/engine.c index e41a39ae1597..36a31e9eea22 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/engine.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/engine.c @@ -35,16 +35,23 @@ nvkm_engine_chsw_load(struct nvkm_engine *engine) return false; } +int +nvkm_engine_reset(struct nvkm_engine *engine) +{ + if (engine->func->reset) + return engine->func->reset(engine); + + nvkm_subdev_fini(&engine->subdev, false); + return nvkm_subdev_init(&engine->subdev); +} + void nvkm_engine_unref(struct nvkm_engine **pengine) { struct nvkm_engine *engine = *pengine; + if (engine) { - if (refcount_dec_and_mutex_lock(&engine->use.refcount, &engine->use.mutex)) { - nvkm_subdev_fini(&engine->subdev, false); - engine->use.enabled = false; - mutex_unlock(&engine->use.mutex); - } + nvkm_subdev_unref(&engine->subdev); *pengine = NULL; } } @@ -53,21 +60,13 @@ struct nvkm_engine * nvkm_engine_ref(struct nvkm_engine *engine) { int ret; + if (engine) { - if (!refcount_inc_not_zero(&engine->use.refcount)) { - mutex_lock(&engine->use.mutex); - if (!refcount_inc_not_zero(&engine->use.refcount)) { - engine->use.enabled = true; - if ((ret = nvkm_subdev_init(&engine->subdev))) { - engine->use.enabled = false; - mutex_unlock(&engine->use.mutex); - return ERR_PTR(ret); - } - refcount_set(&engine->use.refcount, 1); - } - mutex_unlock(&engine->use.mutex); - } + ret = nvkm_subdev_ref(&engine->subdev); + if (ret) + return ERR_PTR(ret); } + return engine; } @@ -91,14 +90,10 @@ static int nvkm_engine_info(struct nvkm_subdev *subdev, u64 mthd, u64 *data) { struct nvkm_engine *engine = nvkm_engine(subdev); - if (engine->func->info) { - if (!IS_ERR((engine = nvkm_engine_ref(engine)))) { - int ret = engine->func->info(engine, mthd, data); - nvkm_engine_unref(&engine); - return ret; - } - return PTR_ERR(engine); - } + + if (engine->func->info) + return engine->func->info(engine, mthd, data); + return -ENOSYS; } @@ -117,26 +112,6 @@ nvkm_engine_init(struct nvkm_subdev *subdev) struct nvkm_engine *engine = nvkm_engine(subdev); struct nvkm_fb *fb = subdev->device->fb; int ret = 0, i; - s64 time; - - if (!engine->use.enabled) { - nvkm_trace(subdev, "init skipped, engine has no users\n"); - return ret; - } - - if (engine->func->oneinit && !engine->subdev.oneinit) { - nvkm_trace(subdev, "one-time init running...\n"); - time = ktime_to_us(ktime_get()); - ret = engine->func->oneinit(engine); - if (ret) { - nvkm_trace(subdev, "one-time init failed, %d\n", ret); - return ret; - } - - engine->subdev.oneinit = true; - time = ktime_to_us(ktime_get()) - time; - nvkm_trace(subdev, "one-time init completed in %lldus\n", time); - } if (engine->func->init) ret = engine->func->init(engine); @@ -147,6 +122,17 @@ nvkm_engine_init(struct nvkm_subdev *subdev) } static int +nvkm_engine_oneinit(struct nvkm_subdev *subdev) +{ + struct nvkm_engine *engine = nvkm_engine(subdev); + + if (engine->func->oneinit) + return engine->func->oneinit(engine); + + return 0; +} + +static int nvkm_engine_preinit(struct nvkm_subdev *subdev) { struct nvkm_engine *engine = nvkm_engine(subdev); @@ -161,7 +147,6 @@ nvkm_engine_dtor(struct nvkm_subdev *subdev) struct nvkm_engine *engine = nvkm_engine(subdev); if (engine->func->dtor) return engine->func->dtor(engine); - mutex_destroy(&engine->use.mutex); return engine; } @@ -169,6 +154,7 @@ const struct nvkm_subdev_func nvkm_engine = { .dtor = nvkm_engine_dtor, .preinit = nvkm_engine_preinit, + .oneinit = nvkm_engine_oneinit, .init = nvkm_engine_init, .fini = nvkm_engine_fini, .info = nvkm_engine_info, @@ -179,10 +165,9 @@ int nvkm_engine_ctor(const struct nvkm_engine_func *func, struct nvkm_device *device, enum nvkm_subdev_type type, int inst, bool enable, struct nvkm_engine *engine) { - nvkm_subdev_ctor(&nvkm_engine, device, type, inst, &engine->subdev); engine->func = func; - refcount_set(&engine->use.refcount, 0); - mutex_init(&engine->use.mutex); + nvkm_subdev_ctor(&nvkm_engine, device, type, inst, &engine->subdev); + refcount_set(&engine->subdev.use.refcount, 0); if (!nvkm_boolopt(device->cfgopt, engine->subdev.name, enable)) { nvkm_debug(&engine->subdev, "disabled\n"); diff --git a/drivers/gpu/drm/nouveau/nvkm/core/event.c b/drivers/gpu/drm/nouveau/nvkm/core/event.c index 006618d77aa4..a6c877135598 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/event.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/event.c @@ -20,54 +20,171 @@ * OTHER DEALINGS IN THE SOFTWARE. */ #include <core/event.h> -#include <core/notify.h> +#include <core/subdev.h> -void +static void nvkm_event_put(struct nvkm_event *event, u32 types, int index) { assert_spin_locked(&event->refs_lock); + + nvkm_trace(event->subdev, "event: decr %08x on %d\n", types, index); + while (types) { int type = __ffs(types); types &= ~(1 << type); if (--event->refs[index * event->types_nr + type] == 0) { + nvkm_trace(event->subdev, "event: blocking %d on %d\n", type, index); if (event->func->fini) event->func->fini(event, 1 << type, index); } } } -void +static void nvkm_event_get(struct nvkm_event *event, u32 types, int index) { assert_spin_locked(&event->refs_lock); + + nvkm_trace(event->subdev, "event: incr %08x on %d\n", types, index); + while (types) { int type = __ffs(types); types &= ~(1 << type); if (++event->refs[index * event->types_nr + type] == 1) { + nvkm_trace(event->subdev, "event: allowing %d on %d\n", type, index); if (event->func->init) event->func->init(event, 1 << type, index); } } } +static void +nvkm_event_ntfy_state(struct nvkm_event_ntfy *ntfy) +{ + struct nvkm_event *event = ntfy->event; + unsigned long flags; + + nvkm_trace(event->subdev, "event: ntfy state changed\n"); + spin_lock_irqsave(&event->refs_lock, flags); + + if (atomic_read(&ntfy->allowed) != ntfy->running) { + if (ntfy->running) { + nvkm_event_put(ntfy->event, ntfy->bits, ntfy->id); + ntfy->running = false; + } else { + nvkm_event_get(ntfy->event, ntfy->bits, ntfy->id); + ntfy->running = true; + } + } + + spin_unlock_irqrestore(&event->refs_lock, flags); +} + +static void +nvkm_event_ntfy_remove(struct nvkm_event_ntfy *ntfy) +{ + spin_lock_irq(&ntfy->event->list_lock); + list_del_init(&ntfy->head); + spin_unlock_irq(&ntfy->event->list_lock); +} + +static void +nvkm_event_ntfy_insert(struct nvkm_event_ntfy *ntfy) +{ + spin_lock_irq(&ntfy->event->list_lock); + list_add_tail(&ntfy->head, &ntfy->event->ntfy); + spin_unlock_irq(&ntfy->event->list_lock); +} + +static void +nvkm_event_ntfy_block_(struct nvkm_event_ntfy *ntfy, bool wait) +{ + struct nvkm_subdev *subdev = ntfy->event->subdev; + + nvkm_trace(subdev, "event: ntfy block %08x on %d wait:%d\n", ntfy->bits, ntfy->id, wait); + + if (atomic_xchg(&ntfy->allowed, 0) == 1) { + nvkm_event_ntfy_state(ntfy); + if (wait) + nvkm_event_ntfy_remove(ntfy); + } +} + void -nvkm_event_send(struct nvkm_event *event, u32 types, int index, - void *data, u32 size) +nvkm_event_ntfy_block(struct nvkm_event_ntfy *ntfy) { - struct nvkm_notify *notify; + if (ntfy->event) + nvkm_event_ntfy_block_(ntfy, ntfy->wait); +} + +void +nvkm_event_ntfy_allow(struct nvkm_event_ntfy *ntfy) +{ + nvkm_trace(ntfy->event->subdev, "event: ntfy allow %08x on %d\n", ntfy->bits, ntfy->id); + + if (atomic_xchg(&ntfy->allowed, 1) == 0) { + nvkm_event_ntfy_state(ntfy); + if (ntfy->wait) + nvkm_event_ntfy_insert(ntfy); + } +} + +void +nvkm_event_ntfy_del(struct nvkm_event_ntfy *ntfy) +{ + struct nvkm_event *event = ntfy->event; + + if (!event) + return; + + nvkm_trace(event->subdev, "event: ntfy del %08x on %d\n", ntfy->bits, ntfy->id); + + nvkm_event_ntfy_block_(ntfy, false); + nvkm_event_ntfy_remove(ntfy); + ntfy->event = NULL; +} + +void +nvkm_event_ntfy_add(struct nvkm_event *event, int id, u32 bits, bool wait, nvkm_event_func func, + struct nvkm_event_ntfy *ntfy) +{ + nvkm_trace(event->subdev, "event: ntfy add %08x on %d wait:%d\n", id, bits, wait); + + ntfy->event = event; + ntfy->id = id; + ntfy->bits = bits; + ntfy->wait = wait; + ntfy->func = func; + atomic_set(&ntfy->allowed, 0); + ntfy->running = false; + INIT_LIST_HEAD(&ntfy->head); + if (!ntfy->wait) + nvkm_event_ntfy_insert(ntfy); +} + +bool +nvkm_event_ntfy_valid(struct nvkm_event *event, int id, u32 bits) +{ + return true; +} + +void +nvkm_event_ntfy(struct nvkm_event *event, int id, u32 bits) +{ + struct nvkm_event_ntfy *ntfy, *ntmp; unsigned long flags; - if (!event->refs || WARN_ON(index >= event->index_nr)) + if (!event->refs || WARN_ON(id >= event->index_nr)) return; + nvkm_trace(event->subdev, "event: ntfy %08x on %d\n", bits, id); spin_lock_irqsave(&event->list_lock, flags); - list_for_each_entry(notify, &event->list, head) { - if (notify->index == index && (notify->types & types)) { - if (event->func->send) { - event->func->send(data, size, notify); - continue; - } - nvkm_notify_send(notify, data, size); + + list_for_each_entry_safe(ntfy, ntmp, &event->ntfy, head) { + if (ntfy->id == id && ntfy->bits & bits) { + if (atomic_read(&ntfy->allowed)) + ntfy->func(ntfy, ntfy->bits & bits); } } + spin_unlock_irqrestore(&event->list_lock, flags); } @@ -81,20 +198,17 @@ nvkm_event_fini(struct nvkm_event *event) } int -nvkm_event_init(const struct nvkm_event_func *func, int types_nr, int index_nr, - struct nvkm_event *event) +__nvkm_event_init(const struct nvkm_event_func *func, struct nvkm_subdev *subdev, + int types_nr, int index_nr, struct nvkm_event *event) { - event->refs = kzalloc(array3_size(index_nr, types_nr, - sizeof(*event->refs)), - GFP_KERNEL); + event->refs = kzalloc(array3_size(index_nr, types_nr, sizeof(*event->refs)), GFP_KERNEL); if (!event->refs) return -ENOMEM; event->func = func; + event->subdev = subdev; event->types_nr = types_nr; event->index_nr = index_nr; - spin_lock_init(&event->refs_lock); - spin_lock_init(&event->list_lock); - INIT_LIST_HEAD(&event->list); + INIT_LIST_HEAD(&event->ntfy); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/core/firmware.c b/drivers/gpu/drm/nouveau/nvkm/core/firmware.c index ca1f8463cff5..fcf2a002f6cb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/firmware.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/firmware.c @@ -22,6 +22,9 @@ #include <core/device.h> #include <core/firmware.h> +#include <subdev/fb.h> +#include <subdev/mmu.h> + int nvkm_firmware_load_name(const struct nvkm_subdev *subdev, const char *base, const char *name, int ver, const struct firmware **pfw) @@ -107,3 +110,127 @@ nvkm_firmware_put(const struct firmware *fw) { release_firmware(fw); } + +#define nvkm_firmware_mem(p) container_of((p), struct nvkm_firmware, mem.memory) + +static int +nvkm_firmware_mem_map(struct nvkm_memory *memory, u64 offset, struct nvkm_vmm *vmm, + struct nvkm_vma *vma, void *argv, u32 argc) +{ + struct nvkm_firmware *fw = nvkm_firmware_mem(memory); + struct nvkm_vmm_map map = { + .memory = &fw->mem.memory, + .offset = offset, + .sgl = &fw->mem.sgl, + }; + + if (WARN_ON(fw->func->type != NVKM_FIRMWARE_IMG_DMA)) + return -ENOSYS; + + return nvkm_vmm_map(vmm, vma, argv, argc, &map); +} + +static u64 +nvkm_firmware_mem_size(struct nvkm_memory *memory) +{ + return sg_dma_len(&nvkm_firmware_mem(memory)->mem.sgl); +} + +static u64 +nvkm_firmware_mem_addr(struct nvkm_memory *memory) +{ + return nvkm_firmware_mem(memory)->phys; +} + +static u8 +nvkm_firmware_mem_page(struct nvkm_memory *memory) +{ + return PAGE_SHIFT; +} + +static enum nvkm_memory_target +nvkm_firmware_mem_target(struct nvkm_memory *memory) +{ + return NVKM_MEM_TARGET_HOST; +} + +static void * +nvkm_firmware_mem_dtor(struct nvkm_memory *memory) +{ + return NULL; +} + +static const struct nvkm_memory_func +nvkm_firmware_mem = { + .dtor = nvkm_firmware_mem_dtor, + .target = nvkm_firmware_mem_target, + .page = nvkm_firmware_mem_page, + .addr = nvkm_firmware_mem_addr, + .size = nvkm_firmware_mem_size, + .map = nvkm_firmware_mem_map, +}; + +void +nvkm_firmware_dtor(struct nvkm_firmware *fw) +{ + struct nvkm_memory *memory = &fw->mem.memory; + + if (!fw->img) + return; + + switch (fw->func->type) { + case NVKM_FIRMWARE_IMG_RAM: + kfree(fw->img); + break; + case NVKM_FIRMWARE_IMG_DMA: + nvkm_memory_unref(&memory); + dma_free_coherent(fw->device->dev, sg_dma_len(&fw->mem.sgl), fw->img, fw->phys); + break; + default: + WARN_ON(1); + break; + } + + fw->img = NULL; +} + +int +nvkm_firmware_ctor(const struct nvkm_firmware_func *func, const char *name, + struct nvkm_device *device, const void *src, int len, struct nvkm_firmware *fw) +{ + fw->func = func; + fw->name = name; + fw->device = device; + fw->len = len; + + switch (fw->func->type) { + case NVKM_FIRMWARE_IMG_RAM: + fw->img = kmemdup(src, fw->len, GFP_KERNEL); + break; + case NVKM_FIRMWARE_IMG_DMA: { + dma_addr_t addr; + + len = ALIGN(fw->len, PAGE_SIZE); + + fw->img = dma_alloc_coherent(fw->device->dev, len, &addr, GFP_KERNEL); + if (fw->img) { + memcpy(fw->img, src, fw->len); + fw->phys = addr; + } + + sg_init_one(&fw->mem.sgl, fw->img, len); + sg_dma_address(&fw->mem.sgl) = fw->phys; + sg_dma_len(&fw->mem.sgl) = len; + } + break; + default: + WARN_ON(1); + return -EINVAL; + } + + if (!fw->img) + return -ENOMEM; + + nvkm_memory_ctor(&nvkm_firmware_mem, &fw->mem.memory); + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/core/intr.c b/drivers/gpu/drm/nouveau/nvkm/core/intr.c new file mode 100644 index 000000000000..e20b7ca218c3 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/core/intr.c @@ -0,0 +1,442 @@ +/* + * 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 <core/intr.h> +#include <core/device.h> +#include <core/subdev.h> +#include <subdev/pci.h> +#include <subdev/top.h> + +static int +nvkm_intr_xlat(struct nvkm_subdev *subdev, struct nvkm_intr *intr, + enum nvkm_intr_type type, int *leaf, u32 *mask) +{ + struct nvkm_device *device = subdev->device; + + if (type < NVKM_INTR_VECTOR_0) { + if (type == NVKM_INTR_SUBDEV) { + const struct nvkm_intr_data *data = intr->data; + struct nvkm_top_device *tdev; + + while (data && data->mask) { + if (data->type == NVKM_SUBDEV_TOP) { + list_for_each_entry(tdev, &device->top->device, head) { + if (tdev->intr >= 0 && + tdev->type == subdev->type && + tdev->inst == subdev->inst) { + if (data->mask & BIT(tdev->intr)) { + *leaf = data->leaf; + *mask = BIT(tdev->intr); + return 0; + } + } + } + } else + if (data->type == subdev->type && data->inst == subdev->inst) { + *leaf = data->leaf; + *mask = data->mask; + return 0; + } + + data++; + } + } else { + return -ENOSYS; + } + } else { + if (type < intr->leaves * sizeof(*intr->stat) * 8) { + *leaf = type / 32; + *mask = BIT(type % 32); + return 0; + } + } + + return -EINVAL; +} + +static struct nvkm_intr * +nvkm_intr_find(struct nvkm_subdev *subdev, enum nvkm_intr_type type, int *leaf, u32 *mask) +{ + struct nvkm_intr *intr; + int ret; + + list_for_each_entry(intr, &subdev->device->intr.intr, head) { + ret = nvkm_intr_xlat(subdev, intr, type, leaf, mask); + if (ret == 0) + return intr; + } + + return NULL; +} + +static void +nvkm_intr_allow_locked(struct nvkm_intr *intr, int leaf, u32 mask) +{ + intr->mask[leaf] |= mask; + if (intr->func->allow) { + if (intr->func->reset) + intr->func->reset(intr, leaf, mask); + intr->func->allow(intr, leaf, mask); + } +} + +void +nvkm_intr_allow(struct nvkm_subdev *subdev, enum nvkm_intr_type type) +{ + struct nvkm_device *device = subdev->device; + struct nvkm_intr *intr; + unsigned long flags; + int leaf; + u32 mask; + + intr = nvkm_intr_find(subdev, type, &leaf, &mask); + if (intr) { + nvkm_debug(intr->subdev, "intr %d/%08x allowed by %s\n", leaf, mask, subdev->name); + spin_lock_irqsave(&device->intr.lock, flags); + nvkm_intr_allow_locked(intr, leaf, mask); + spin_unlock_irqrestore(&device->intr.lock, flags); + } +} + +static void +nvkm_intr_block_locked(struct nvkm_intr *intr, int leaf, u32 mask) +{ + intr->mask[leaf] &= ~mask; + if (intr->func->block) + intr->func->block(intr, leaf, mask); +} + +void +nvkm_intr_block(struct nvkm_subdev *subdev, enum nvkm_intr_type type) +{ + struct nvkm_device *device = subdev->device; + struct nvkm_intr *intr; + unsigned long flags; + int leaf; + u32 mask; + + intr = nvkm_intr_find(subdev, type, &leaf, &mask); + if (intr) { + nvkm_debug(intr->subdev, "intr %d/%08x blocked by %s\n", leaf, mask, subdev->name); + spin_lock_irqsave(&device->intr.lock, flags); + nvkm_intr_block_locked(intr, leaf, mask); + spin_unlock_irqrestore(&device->intr.lock, flags); + } +} + +static void +nvkm_intr_rearm_locked(struct nvkm_device *device) +{ + struct nvkm_intr *intr; + + list_for_each_entry(intr, &device->intr.intr, head) + intr->func->rearm(intr); +} + +static void +nvkm_intr_unarm_locked(struct nvkm_device *device) +{ + struct nvkm_intr *intr; + + list_for_each_entry(intr, &device->intr.intr, head) + intr->func->unarm(intr); +} + +static irqreturn_t +nvkm_intr(int irq, void *arg) +{ + struct nvkm_device *device = arg; + struct nvkm_intr *intr; + struct nvkm_inth *inth; + irqreturn_t ret = IRQ_NONE; + bool pending = false; + int prio, leaf; + + /* Disable all top-level interrupt sources, and re-arm MSI interrupts. */ + spin_lock(&device->intr.lock); + if (!device->intr.armed) + goto done_unlock; + + nvkm_intr_unarm_locked(device); + nvkm_pci_msi_rearm(device); + + /* Fetch pending interrupt masks. */ + list_for_each_entry(intr, &device->intr.intr, head) { + if (intr->func->pending(intr)) + pending = true; + } + + if (!pending) + goto done; + + /* Check that GPU is still on the bus by reading NV_PMC_BOOT_0. */ + if (WARN_ON(nvkm_rd32(device, 0x000000) == 0xffffffff)) + goto done; + + /* Execute handlers. */ + for (prio = 0; prio < ARRAY_SIZE(device->intr.prio); prio++) { + list_for_each_entry(inth, &device->intr.prio[prio], head) { + struct nvkm_intr *intr = inth->intr; + + if (intr->stat[inth->leaf] & inth->mask) { + if (atomic_read(&inth->allowed)) { + if (intr->func->reset) + intr->func->reset(intr, inth->leaf, inth->mask); + if (inth->func(inth) == IRQ_HANDLED) + ret = IRQ_HANDLED; + } + } + } + } + + /* Nothing handled? Some debugging/protection from IRQ storms is in order... */ + if (ret == IRQ_NONE) { + list_for_each_entry(intr, &device->intr.intr, head) { + for (leaf = 0; leaf < intr->leaves; leaf++) { + if (intr->stat[leaf]) { + nvkm_warn(intr->subdev, "intr%d: %08x\n", + leaf, intr->stat[leaf]); + nvkm_intr_block_locked(intr, leaf, intr->stat[leaf]); + } + } + } + } + +done: + /* Re-enable all top-level interrupt sources. */ + nvkm_intr_rearm_locked(device); +done_unlock: + spin_unlock(&device->intr.lock); + return ret; +} + +int +nvkm_intr_add(const struct nvkm_intr_func *func, const struct nvkm_intr_data *data, + struct nvkm_subdev *subdev, int leaves, struct nvkm_intr *intr) +{ + struct nvkm_device *device = subdev->device; + int i; + + intr->func = func; + intr->data = data; + intr->subdev = subdev; + intr->leaves = leaves; + intr->stat = kcalloc(leaves, sizeof(*intr->stat), GFP_KERNEL); + intr->mask = kcalloc(leaves, sizeof(*intr->mask), GFP_KERNEL); + if (!intr->stat || !intr->mask) { + kfree(intr->stat); + return -ENOMEM; + } + + if (intr->subdev->debug >= NV_DBG_DEBUG) { + for (i = 0; i < intr->leaves; i++) + intr->mask[i] = ~0; + } + + spin_lock_irq(&device->intr.lock); + list_add_tail(&intr->head, &device->intr.intr); + spin_unlock_irq(&device->intr.lock); + return 0; +} + +static irqreturn_t +nvkm_intr_subdev(struct nvkm_inth *inth) +{ + struct nvkm_subdev *subdev = container_of(inth, typeof(*subdev), inth); + + nvkm_subdev_intr(subdev); + return IRQ_HANDLED; +} + +static void +nvkm_intr_subdev_add_dev(struct nvkm_intr *intr, enum nvkm_subdev_type type, int inst) +{ + struct nvkm_subdev *subdev; + enum nvkm_intr_prio prio; + int ret; + + subdev = nvkm_device_subdev(intr->subdev->device, type, inst); + if (!subdev || !subdev->func->intr) + return; + + if (type == NVKM_ENGINE_DISP) + prio = NVKM_INTR_PRIO_VBLANK; + else + prio = NVKM_INTR_PRIO_NORMAL; + + ret = nvkm_inth_add(intr, NVKM_INTR_SUBDEV, prio, subdev, nvkm_intr_subdev, &subdev->inth); + if (WARN_ON(ret)) + return; + + nvkm_inth_allow(&subdev->inth); +} + +static void +nvkm_intr_subdev_add(struct nvkm_intr *intr) +{ + const struct nvkm_intr_data *data; + struct nvkm_device *device = intr->subdev->device; + struct nvkm_top_device *tdev; + + for (data = intr->data; data && data->mask; data++) { + if (data->legacy) { + if (data->type == NVKM_SUBDEV_TOP) { + list_for_each_entry(tdev, &device->top->device, head) { + if (tdev->intr < 0 || !(data->mask & BIT(tdev->intr))) + continue; + + nvkm_intr_subdev_add_dev(intr, tdev->type, tdev->inst); + } + } else { + nvkm_intr_subdev_add_dev(intr, data->type, data->inst); + } + } + } +} + +void +nvkm_intr_rearm(struct nvkm_device *device) +{ + struct nvkm_intr *intr; + int i; + + if (unlikely(!device->intr.legacy_done)) { + list_for_each_entry(intr, &device->intr.intr, head) + nvkm_intr_subdev_add(intr); + device->intr.legacy_done = true; + } + + spin_lock_irq(&device->intr.lock); + list_for_each_entry(intr, &device->intr.intr, head) { + for (i = 0; intr->func->block && i < intr->leaves; i++) { + intr->func->block(intr, i, ~0); + intr->func->allow(intr, i, intr->mask[i]); + } + } + + nvkm_intr_rearm_locked(device); + device->intr.armed = true; + spin_unlock_irq(&device->intr.lock); +} + +void +nvkm_intr_unarm(struct nvkm_device *device) +{ + spin_lock_irq(&device->intr.lock); + nvkm_intr_unarm_locked(device); + device->intr.armed = false; + spin_unlock_irq(&device->intr.lock); +} + +int +nvkm_intr_install(struct nvkm_device *device) +{ + int ret; + + device->intr.irq = device->func->irq(device); + if (device->intr.irq < 0) + return device->intr.irq; + + ret = request_irq(device->intr.irq, nvkm_intr, IRQF_SHARED, "nvkm", device); + if (ret) + return ret; + + device->intr.alloc = true; + return 0; +} + +void +nvkm_intr_dtor(struct nvkm_device *device) +{ + struct nvkm_intr *intr, *intt; + + list_for_each_entry_safe(intr, intt, &device->intr.intr, head) { + list_del(&intr->head); + kfree(intr->mask); + kfree(intr->stat); + } + + if (device->intr.alloc) + free_irq(device->intr.irq, device); +} + +void +nvkm_intr_ctor(struct nvkm_device *device) +{ + int i; + + INIT_LIST_HEAD(&device->intr.intr); + for (i = 0; i < ARRAY_SIZE(device->intr.prio); i++) + INIT_LIST_HEAD(&device->intr.prio[i]); + + spin_lock_init(&device->intr.lock); + device->intr.armed = false; +} + +void +nvkm_inth_block(struct nvkm_inth *inth) +{ + if (unlikely(!inth->intr)) + return; + + atomic_set(&inth->allowed, 0); +} + +void +nvkm_inth_allow(struct nvkm_inth *inth) +{ + struct nvkm_intr *intr = inth->intr; + unsigned long flags; + + if (unlikely(!inth->intr)) + return; + + spin_lock_irqsave(&intr->subdev->device->intr.lock, flags); + if (!atomic_xchg(&inth->allowed, 1)) { + if ((intr->mask[inth->leaf] & inth->mask) != inth->mask) + nvkm_intr_allow_locked(intr, inth->leaf, inth->mask); + } + spin_unlock_irqrestore(&intr->subdev->device->intr.lock, flags); +} + +int +nvkm_inth_add(struct nvkm_intr *intr, enum nvkm_intr_type type, enum nvkm_intr_prio prio, + struct nvkm_subdev *subdev, nvkm_inth_func func, struct nvkm_inth *inth) +{ + struct nvkm_device *device = subdev->device; + int ret; + + if (WARN_ON(inth->mask)) + return -EBUSY; + + ret = nvkm_intr_xlat(subdev, intr, type, &inth->leaf, &inth->mask); + if (ret) + return ret; + + nvkm_debug(intr->subdev, "intr %d/%08x requested by %s\n", + inth->leaf, inth->mask, subdev->name); + + inth->intr = intr; + inth->func = func; + atomic_set(&inth->allowed, 0); + list_add_tail(&inth->head, &device->intr.prio[prio]); + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c b/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c index 45f920da89af..0b33287e43a7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c @@ -47,6 +47,26 @@ nvkm_ioctl_nop(struct nvkm_client *client, return ret; } +#include <nvif/class.h> + +static int +nvkm_ioctl_sclass_(struct nvkm_object *object, int index, struct nvkm_oclass *oclass) +{ + if ( object->func->uevent && + !object->func->uevent(object, NULL, 0, NULL) && index-- == 0) { + oclass->ctor = nvkm_uevent_new; + oclass->base.minver = 0; + oclass->base.maxver = 0; + oclass->base.oclass = NVIF_CLASS_EVENT; + return 0; + } + + if (object->func->sclass) + return object->func->sclass(object, index, oclass); + + return -ENOSYS; +} + static int nvkm_ioctl_sclass(struct nvkm_client *client, struct nvkm_object *object, void *data, u32 size) @@ -64,8 +84,7 @@ nvkm_ioctl_sclass(struct nvkm_client *client, if (size != args->v0.count * sizeof(args->v0.oclass[0])) return -EINVAL; - while (object->func->sclass && - object->func->sclass(object, i, &oclass) >= 0) { + while (nvkm_ioctl_sclass_(object, i, &oclass) >= 0) { if (i < args->v0.count) { args->v0.oclass[i].oclass = oclass.base.oclass; args->v0.oclass[i].minver = oclass.base.minver; @@ -100,7 +119,7 @@ nvkm_ioctl_new(struct nvkm_client *client, } else return ret; - if (!parent->func->sclass) { + if (!parent->func->sclass && !parent->func->uevent) { nvif_ioctl(parent, "cannot have children\n"); return -EINVAL; } @@ -113,7 +132,7 @@ nvkm_ioctl_new(struct nvkm_client *client, oclass.object = args->v0.object; oclass.client = client; oclass.parent = parent; - ret = parent->func->sclass(parent, i++, &oclass); + ret = nvkm_ioctl_sclass_(parent, i++, &oclass); if (ret) return ret; } while (oclass.base.oclass != args->v0.oclass); @@ -294,90 +313,6 @@ nvkm_ioctl_unmap(struct nvkm_client *client, return ret; } -static int -nvkm_ioctl_ntfy_new(struct nvkm_client *client, - struct nvkm_object *object, void *data, u32 size) -{ - union { - struct nvif_ioctl_ntfy_new_v0 v0; - } *args = data; - struct nvkm_event *event; - int ret = -ENOSYS; - - nvif_ioctl(object, "ntfy new size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) { - nvif_ioctl(object, "ntfy new vers %d event %02x\n", - args->v0.version, args->v0.event); - ret = nvkm_object_ntfy(object, args->v0.event, &event); - if (ret == 0) { - ret = nvkm_client_notify_new(object, event, data, size); - if (ret >= 0) { - args->v0.index = ret; - ret = 0; - } - } - } - - return ret; -} - -static int -nvkm_ioctl_ntfy_del(struct nvkm_client *client, - struct nvkm_object *object, void *data, u32 size) -{ - union { - struct nvif_ioctl_ntfy_del_v0 v0; - } *args = data; - int ret = -ENOSYS; - - nvif_ioctl(object, "ntfy del size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { - nvif_ioctl(object, "ntfy del vers %d index %d\n", - args->v0.version, args->v0.index); - ret = nvkm_client_notify_del(client, args->v0.index); - } - - return ret; -} - -static int -nvkm_ioctl_ntfy_get(struct nvkm_client *client, - struct nvkm_object *object, void *data, u32 size) -{ - union { - struct nvif_ioctl_ntfy_get_v0 v0; - } *args = data; - int ret = -ENOSYS; - - nvif_ioctl(object, "ntfy get size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { - nvif_ioctl(object, "ntfy get vers %d index %d\n", - args->v0.version, args->v0.index); - ret = nvkm_client_notify_get(client, args->v0.index); - } - - return ret; -} - -static int -nvkm_ioctl_ntfy_put(struct nvkm_client *client, - struct nvkm_object *object, void *data, u32 size) -{ - union { - struct nvif_ioctl_ntfy_put_v0 v0; - } *args = data; - int ret = -ENOSYS; - - nvif_ioctl(object, "ntfy put size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { - nvif_ioctl(object, "ntfy put vers %d index %d\n", - args->v0.version, args->v0.index); - ret = nvkm_client_notify_put(client, args->v0.index); - } - - return ret; -} - static struct { int version; int (*func)(struct nvkm_client *, struct nvkm_object *, void *, u32); @@ -392,10 +327,6 @@ nvkm_ioctl_v0[] = { { 0x00, nvkm_ioctl_wr }, { 0x00, nvkm_ioctl_map }, { 0x00, nvkm_ioctl_unmap }, - { 0x00, nvkm_ioctl_ntfy_new }, - { 0x00, nvkm_ioctl_ntfy_del }, - { 0x00, nvkm_ioctl_ntfy_get }, - { 0x00, nvkm_ioctl_ntfy_put }, }; static int diff --git a/drivers/gpu/drm/nouveau/nvkm/core/notify.c b/drivers/gpu/drm/nouveau/nvkm/core/notify.c deleted file mode 100644 index 023610d01458..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/core/notify.c +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright 2014 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. - * - * Authors: Ben Skeggs <bskeggs@redhat.com> - */ -#include <core/notify.h> -#include <core/event.h> - -static inline void -nvkm_notify_put_locked(struct nvkm_notify *notify) -{ - if (notify->block++ == 0) - nvkm_event_put(notify->event, notify->types, notify->index); -} - -void -nvkm_notify_put(struct nvkm_notify *notify) -{ - struct nvkm_event *event = notify->event; - unsigned long flags; - if (likely(event) && - test_and_clear_bit(NVKM_NOTIFY_USER, ¬ify->flags)) { - spin_lock_irqsave(&event->refs_lock, flags); - nvkm_notify_put_locked(notify); - spin_unlock_irqrestore(&event->refs_lock, flags); - if (test_bit(NVKM_NOTIFY_WORK, ¬ify->flags)) - flush_work(¬ify->work); - } -} - -static inline void -nvkm_notify_get_locked(struct nvkm_notify *notify) -{ - if (--notify->block == 0) - nvkm_event_get(notify->event, notify->types, notify->index); -} - -void -nvkm_notify_get(struct nvkm_notify *notify) -{ - struct nvkm_event *event = notify->event; - unsigned long flags; - if (likely(event) && - !test_and_set_bit(NVKM_NOTIFY_USER, ¬ify->flags)) { - spin_lock_irqsave(&event->refs_lock, flags); - nvkm_notify_get_locked(notify); - spin_unlock_irqrestore(&event->refs_lock, flags); - } -} - -static inline void -nvkm_notify_func(struct nvkm_notify *notify) -{ - struct nvkm_event *event = notify->event; - int ret = notify->func(notify); - unsigned long flags; - if ((ret == NVKM_NOTIFY_KEEP) || - !test_and_clear_bit(NVKM_NOTIFY_USER, ¬ify->flags)) { - spin_lock_irqsave(&event->refs_lock, flags); - nvkm_notify_get_locked(notify); - spin_unlock_irqrestore(&event->refs_lock, flags); - } -} - -static void -nvkm_notify_work(struct work_struct *work) -{ - struct nvkm_notify *notify = container_of(work, typeof(*notify), work); - nvkm_notify_func(notify); -} - -void -nvkm_notify_send(struct nvkm_notify *notify, void *data, u32 size) -{ - struct nvkm_event *event = notify->event; - unsigned long flags; - - assert_spin_locked(&event->list_lock); - BUG_ON(size != notify->size); - - spin_lock_irqsave(&event->refs_lock, flags); - if (notify->block) { - spin_unlock_irqrestore(&event->refs_lock, flags); - return; - } - nvkm_notify_put_locked(notify); - spin_unlock_irqrestore(&event->refs_lock, flags); - - if (test_bit(NVKM_NOTIFY_WORK, ¬ify->flags)) { - memcpy((void *)notify->data, data, size); - schedule_work(¬ify->work); - } else { - notify->data = data; - nvkm_notify_func(notify); - notify->data = NULL; - } -} - -void -nvkm_notify_fini(struct nvkm_notify *notify) -{ - unsigned long flags; - if (notify->event) { - nvkm_notify_put(notify); - spin_lock_irqsave(¬ify->event->list_lock, flags); - list_del(¬ify->head); - spin_unlock_irqrestore(¬ify->event->list_lock, flags); - kfree((void *)notify->data); - notify->event = NULL; - } -} - -int -nvkm_notify_init(struct nvkm_object *object, struct nvkm_event *event, - int (*func)(struct nvkm_notify *), bool work, - void *data, u32 size, u32 reply, - struct nvkm_notify *notify) -{ - unsigned long flags; - int ret = -ENODEV; - if ((notify->event = event), event->refs) { - ret = event->func->ctor(object, data, size, notify); - if (ret == 0 && (ret = -EINVAL, notify->size == reply)) { - notify->flags = 0; - notify->block = 1; - notify->func = func; - notify->data = NULL; - if (ret = 0, work) { - INIT_WORK(¬ify->work, nvkm_notify_work); - set_bit(NVKM_NOTIFY_WORK, ¬ify->flags); - notify->data = kmalloc(reply, GFP_KERNEL); - if (!notify->data) - ret = -ENOMEM; - } - } - if (ret == 0) { - spin_lock_irqsave(&event->list_lock, flags); - list_add_tail(¬ify->head, &event->list); - spin_unlock_irqrestore(&event->list_lock, flags); - } - } - if (ret) - notify->event = NULL; - return ret; -} diff --git a/drivers/gpu/drm/nouveau/nvkm/core/oproxy.c b/drivers/gpu/drm/nouveau/nvkm/core/oproxy.c index 16299837a296..3385528da650 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/oproxy.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/oproxy.c @@ -47,7 +47,12 @@ nvkm_oproxy_map(struct nvkm_object *object, void *argv, u32 argc, static int nvkm_oproxy_unmap(struct nvkm_object *object) { - return nvkm_object_unmap(nvkm_oproxy(object)->object); + struct nvkm_oproxy *oproxy = nvkm_oproxy(object); + + if (unlikely(!oproxy->object)) + return 0; + + return nvkm_object_unmap(oproxy->object); } static int @@ -106,6 +111,18 @@ nvkm_oproxy_sclass(struct nvkm_object *object, int index, } static int +nvkm_oproxy_uevent(struct nvkm_object *object, void *argv, u32 argc, + struct nvkm_uevent *uevent) +{ + struct nvkm_oproxy *oproxy = nvkm_oproxy(object); + + if (!oproxy->object->func->uevent) + return -ENOSYS; + + return oproxy->object->func->uevent(oproxy->object, argv, argc, uevent); +} + +static int nvkm_oproxy_fini(struct nvkm_object *object, bool suspend) { struct nvkm_oproxy *oproxy = nvkm_oproxy(object); @@ -188,6 +205,7 @@ nvkm_oproxy_func = { .wr32 = nvkm_oproxy_wr32, .bind = nvkm_oproxy_bind, .sclass = nvkm_oproxy_sclass, + .uevent = nvkm_oproxy_uevent, }; void diff --git a/drivers/gpu/drm/nouveau/nvkm/core/subdev.c b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c index a74b7acb6832..6c20e827a069 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/subdev.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c @@ -54,7 +54,7 @@ int nvkm_subdev_fini(struct nvkm_subdev *subdev, bool suspend) { struct nvkm_device *device = subdev->device; - const char *action = suspend ? "suspend" : "fini"; + const char *action = suspend ? "suspend" : subdev->use.enabled ? "fini" : "reset"; s64 time; nvkm_trace(subdev, "%s running...\n", action); @@ -68,6 +68,7 @@ nvkm_subdev_fini(struct nvkm_subdev *subdev, bool suspend) return ret; } } + subdev->use.enabled = false; nvkm_mc_reset(device, subdev->type, subdev->inst); @@ -97,30 +98,49 @@ nvkm_subdev_preinit(struct nvkm_subdev *subdev) return 0; } -int -nvkm_subdev_init(struct nvkm_subdev *subdev) +static int +nvkm_subdev_oneinit_(struct nvkm_subdev *subdev) { s64 time; int ret; - nvkm_trace(subdev, "init running...\n"); + if (!subdev->func->oneinit || subdev->oneinit) + return 0; + + nvkm_trace(subdev, "one-time init running...\n"); time = ktime_to_us(ktime_get()); + ret = subdev->func->oneinit(subdev); + if (ret) { + nvkm_error(subdev, "one-time init failed, %d\n", ret); + return ret; + } - if (subdev->func->oneinit && !subdev->oneinit) { - s64 time; - nvkm_trace(subdev, "one-time init running...\n"); - time = ktime_to_us(ktime_get()); - ret = subdev->func->oneinit(subdev); - if (ret) { - nvkm_error(subdev, "one-time init failed, %d\n", ret); - return ret; - } + subdev->oneinit = true; + time = ktime_to_us(ktime_get()) - time; + nvkm_trace(subdev, "one-time init completed in %lldus\n", time); + return 0; +} - subdev->oneinit = true; - time = ktime_to_us(ktime_get()) - time; - nvkm_trace(subdev, "one-time init completed in %lldus\n", time); +static int +nvkm_subdev_init_(struct nvkm_subdev *subdev) +{ + s64 time; + int ret; + + if (subdev->use.enabled) { + nvkm_trace(subdev, "init skipped, already running\n"); + return 0; } + nvkm_trace(subdev, "init running...\n"); + time = ktime_to_us(ktime_get()); + + ret = nvkm_subdev_oneinit_(subdev); + if (ret) + return ret; + + subdev->use.enabled = true; + if (subdev->func->init) { ret = subdev->func->init(subdev); if (ret) { @@ -134,6 +154,64 @@ nvkm_subdev_init(struct nvkm_subdev *subdev) return 0; } +int +nvkm_subdev_init(struct nvkm_subdev *subdev) +{ + int ret; + + mutex_lock(&subdev->use.mutex); + if (refcount_read(&subdev->use.refcount) == 0) { + nvkm_trace(subdev, "init skipped, no users\n"); + mutex_unlock(&subdev->use.mutex); + return 0; + } + + ret = nvkm_subdev_init_(subdev); + mutex_unlock(&subdev->use.mutex); + return ret; +} + +int +nvkm_subdev_oneinit(struct nvkm_subdev *subdev) +{ + int ret; + + mutex_lock(&subdev->use.mutex); + ret = nvkm_subdev_oneinit_(subdev); + mutex_unlock(&subdev->use.mutex); + return ret; +} + +void +nvkm_subdev_unref(struct nvkm_subdev *subdev) +{ + if (refcount_dec_and_mutex_lock(&subdev->use.refcount, &subdev->use.mutex)) { + nvkm_subdev_fini(subdev, false); + mutex_unlock(&subdev->use.mutex); + } +} + +int +nvkm_subdev_ref(struct nvkm_subdev *subdev) +{ + int ret; + + if (subdev && !refcount_inc_not_zero(&subdev->use.refcount)) { + mutex_lock(&subdev->use.mutex); + if (!refcount_inc_not_zero(&subdev->use.refcount)) { + if ((ret = nvkm_subdev_init_(subdev))) { + mutex_unlock(&subdev->use.mutex); + return ret; + } + + refcount_set(&subdev->use.refcount, 1); + } + mutex_unlock(&subdev->use.mutex); + } + + return 0; +} + void nvkm_subdev_del(struct nvkm_subdev **psubdev) { @@ -146,6 +224,7 @@ nvkm_subdev_del(struct nvkm_subdev **psubdev) list_del(&subdev->head); if (subdev->func->dtor) *psubdev = subdev->func->dtor(subdev); + mutex_destroy(&subdev->use.mutex); time = ktime_to_us(ktime_get()) - time; nvkm_trace(subdev, "destroy completed in %lldus\n", time); kfree(*psubdev); @@ -167,8 +246,8 @@ nvkm_subdev_disable(struct nvkm_device *device, enum nvkm_subdev_type type, int } void -nvkm_subdev_ctor(const struct nvkm_subdev_func *func, struct nvkm_device *device, - enum nvkm_subdev_type type, int inst, struct nvkm_subdev *subdev) +__nvkm_subdev_ctor(const struct nvkm_subdev_func *func, struct nvkm_device *device, + enum nvkm_subdev_type type, int inst, struct nvkm_subdev *subdev) { subdev->func = func; subdev->device = device; @@ -180,6 +259,8 @@ nvkm_subdev_ctor(const struct nvkm_subdev_func *func, struct nvkm_device *device else strscpy(subdev->name, nvkm_subdev_type[type], sizeof(subdev->name)); subdev->debug = nvkm_dbgopt(device->dbgopt, subdev->name); + + refcount_set(&subdev->use.refcount, 1); list_add_tail(&subdev->head, &device->subdev); } diff --git a/drivers/gpu/drm/nouveau/nvkm/core/uevent.c b/drivers/gpu/drm/nouveau/nvkm/core/uevent.c new file mode 100644 index 000000000000..ba9d9edaec75 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/core/uevent.c @@ -0,0 +1,157 @@ +/* + * 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_uevent(p) container_of((p), struct nvkm_uevent, object) +#include <core/event.h> +#include <core/client.h> + +#include <nvif/if000e.h> + +struct nvkm_uevent { + struct nvkm_object object; + struct nvkm_object *parent; + nvkm_uevent_func func; + bool wait; + + struct nvkm_event_ntfy ntfy; + atomic_t allowed; +}; + +static int +nvkm_uevent_mthd_block(struct nvkm_uevent *uevent, union nvif_event_block_args *args, u32 argc) +{ + if (argc != sizeof(args->vn)) + return -ENOSYS; + + nvkm_event_ntfy_block(&uevent->ntfy); + atomic_set(&uevent->allowed, 0); + return 0; +} + +static int +nvkm_uevent_mthd_allow(struct nvkm_uevent *uevent, union nvif_event_allow_args *args, u32 argc) +{ + if (argc != sizeof(args->vn)) + return -ENOSYS; + + nvkm_event_ntfy_allow(&uevent->ntfy); + atomic_set(&uevent->allowed, 1); + return 0; +} + +static int +nvkm_uevent_mthd(struct nvkm_object *object, u32 mthd, void *argv, u32 argc) +{ + struct nvkm_uevent *uevent = nvkm_uevent(object); + + switch (mthd) { + case NVIF_EVENT_V0_ALLOW: return nvkm_uevent_mthd_allow(uevent, argv, argc); + case NVIF_EVENT_V0_BLOCK: return nvkm_uevent_mthd_block(uevent, argv, argc); + default: + break; + } + + return -EINVAL; +} + +static int +nvkm_uevent_fini(struct nvkm_object *object, bool suspend) +{ + struct nvkm_uevent *uevent = nvkm_uevent(object); + + nvkm_event_ntfy_block(&uevent->ntfy); + return 0; +} + +static int +nvkm_uevent_init(struct nvkm_object *object) +{ + struct nvkm_uevent *uevent = nvkm_uevent(object); + + if (atomic_read(&uevent->allowed)) + nvkm_event_ntfy_allow(&uevent->ntfy); + + return 0; +} + +static void * +nvkm_uevent_dtor(struct nvkm_object *object) +{ + struct nvkm_uevent *uevent = nvkm_uevent(object); + + nvkm_event_ntfy_del(&uevent->ntfy); + return uevent; +} + +static const struct nvkm_object_func +nvkm_uevent = { + .dtor = nvkm_uevent_dtor, + .init = nvkm_uevent_init, + .fini = nvkm_uevent_fini, + .mthd = nvkm_uevent_mthd, +}; + +static int +nvkm_uevent_ntfy(struct nvkm_event_ntfy *ntfy, u32 bits) +{ + struct nvkm_uevent *uevent = container_of(ntfy, typeof(*uevent), ntfy); + struct nvkm_client *client = uevent->object.client; + + if (uevent->func) + return uevent->func(uevent->parent, uevent->object.token, bits); + + return client->event(uevent->object.token, NULL, 0); +} + +int +nvkm_uevent_add(struct nvkm_uevent *uevent, struct nvkm_event *event, int id, u32 bits, + nvkm_uevent_func func) +{ + if (WARN_ON(uevent->func)) + return -EBUSY; + + nvkm_event_ntfy_add(event, id, bits, uevent->wait, nvkm_uevent_ntfy, &uevent->ntfy); + uevent->func = func; + return 0; +} + +int +nvkm_uevent_new(const struct nvkm_oclass *oclass, void *argv, u32 argc, + struct nvkm_object **pobject) +{ + struct nvkm_object *parent = oclass->parent; + struct nvkm_uevent *uevent; + union nvif_event_args *args = argv; + + if (argc < sizeof(args->v0) || args->v0.version != 0) + return -ENOSYS; + + if (!(uevent = kzalloc(sizeof(*uevent), GFP_KERNEL))) + return -ENOMEM; + *pobject = &uevent->object; + + nvkm_object_ctor(&nvkm_uevent, oclass, &uevent->object); + uevent->parent = parent; + uevent->func = NULL; + uevent->wait = args->v0.wait; + uevent->ntfy.event = NULL; + return parent->func->uevent(parent, &args->v0.data, argc - sizeof(args->v0), uevent); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/ce/Kbuild index ba88613e1e46..8bf1635ffabc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/Kbuild @@ -8,3 +8,5 @@ nvkm-y += nvkm/engine/ce/gp100.o nvkm-y += nvkm/engine/ce/gp102.o nvkm-y += nvkm/engine/ce/gv100.o nvkm-y += nvkm/engine/ce/tu102.o +nvkm-y += nvkm/engine/ce/ga100.o +nvkm-y += nvkm/engine/ce/ga102.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/ga100.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/ga100.c new file mode 100644 index 000000000000..6648ed62daa6 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/ga100.c @@ -0,0 +1,82 @@ +/* + * 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 <subdev/vfn.h> + +#include <nvif/class.h> + +static irqreturn_t +ga100_ce_intr(struct nvkm_inth *inth) +{ + struct nvkm_subdev *subdev = container_of(inth, typeof(*subdev), inth); + + /*TODO*/ + nvkm_error(subdev, "intr\n"); + return IRQ_NONE; +} + +int +ga100_ce_fini(struct nvkm_engine *engine, bool suspend) +{ + nvkm_inth_block(&engine->subdev.inth); + return 0; +} + +int +ga100_ce_init(struct nvkm_engine *engine) +{ + nvkm_inth_allow(&engine->subdev.inth); + return 0; +} + +int +ga100_ce_oneinit(struct nvkm_engine *engine) +{ + struct nvkm_subdev *subdev = &engine->subdev; + struct nvkm_device *device = subdev->device; + u32 vector; + + vector = nvkm_rd32(device, 0x10442c + (subdev->inst * 0x80)) & 0x00000fff; + + return nvkm_inth_add(&device->vfn->intr, vector, NVKM_INTR_PRIO_NORMAL, + subdev, ga100_ce_intr, &subdev->inth); +} + +static const struct nvkm_engine_func +ga100_ce = { + .oneinit = ga100_ce_oneinit, + .init = ga100_ce_init, + .fini = ga100_ce_fini, + .cclass = &gv100_ce_cclass, + .sclass = { + { -1, -1, AMPERE_DMA_COPY_A }, + {} + } +}; + +int +ga100_ce_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, + struct nvkm_engine **pengine) +{ + return nvkm_engine_new_(&ga100_ce, device, type, inst, true, pengine); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/usertu102.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/ga102.c index 217268f8ccad..9f3448ad625f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/usertu102.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/ga102.c @@ -1,5 +1,5 @@ /* - * Copyright 2018 Red Hat Inc. + * 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"), @@ -19,27 +19,26 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ -#include "user.h" +#include "priv.h" -static int -tu102_fifo_user_map(struct nvkm_object *object, void *argv, u32 argc, - enum nvkm_object_map *type, u64 *addr, u64 *size) -{ - struct nvkm_device *device = object->engine->subdev.device; - *addr = 0xbb0000 + device->func->resource_addr(device, 0); - *size = 0x010000; - *type = NVKM_OBJECT_MAP_IO; - return 0; -} +#include <nvif/class.h> -static const struct nvkm_object_func -tu102_fifo_user = { - .map = tu102_fifo_user_map, +static const struct nvkm_engine_func +ga102_ce = { + .oneinit = ga100_ce_oneinit, + .init = ga100_ce_init, + .fini = ga100_ce_fini, + .cclass = &gv100_ce_cclass, + .sclass = { + { -1, -1, AMPERE_DMA_COPY_A }, + { -1, -1, AMPERE_DMA_COPY_B }, + {} + } }; int -tu102_fifo_user_new(const struct nvkm_oclass *oclass, void *argv, u32 argc, - struct nvkm_object **pobject) +ga102_ce_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, + struct nvkm_engine **pengine) { - return nvkm_object_new_(&tu102_fifo_user, oclass, argv, argc, pobject); + return nvkm_engine_new_(&ga102_ce, device, type, inst, true, pengine); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c index 09a112af2f89..c9bf6305c3ec 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c @@ -40,7 +40,7 @@ gt215_ce_isr_error_name[] = { }; void -gt215_ce_intr(struct nvkm_falcon *ce, struct nvkm_fifo_chan *chan) +gt215_ce_intr(struct nvkm_falcon *ce, struct nvkm_chan *chan) { struct nvkm_subdev *subdev = &ce->engine.subdev; struct nvkm_device *device = subdev->device; @@ -55,9 +55,9 @@ gt215_ce_intr(struct nvkm_falcon *ce, struct nvkm_fifo_chan *chan) nvkm_error(subdev, "DISPATCH_ERROR %04x [%s] ch %d [%010llx %s] " "subc %d mthd %04x data %08x\n", ssta, - en ? en->name : "", chan ? chan->chid : -1, + en ? en->name : "", chan ? chan->id : -1, chan ? chan->inst->addr : 0, - chan ? chan->object.client->name : "unknown", + chan ? chan->name : "unknown", subc, mthd, data); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/ce/priv.h index cd53b93664d6..c4c046916fa6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/priv.h @@ -8,4 +8,8 @@ void gk104_ce_intr(struct nvkm_engine *); void gp100_ce_intr(struct nvkm_engine *); extern const struct nvkm_object_func gv100_ce_cclass; + +int ga100_ce_oneinit(struct nvkm_engine *); +int ga100_ce_init(struct nvkm_engine *); +int ga100_ce_fini(struct nvkm_engine *, bool); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c index be2a7181dc15..caca4f639895 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c @@ -81,8 +81,7 @@ g84_cipher_intr(struct nvkm_engine *cipher) { struct nvkm_subdev *subdev = &cipher->subdev; struct nvkm_device *device = subdev->device; - struct nvkm_fifo *fifo = device->fifo; - struct nvkm_fifo_chan *chan; + struct nvkm_chan *chan; u32 stat = nvkm_rd32(device, 0x102130); u32 mthd = nvkm_rd32(device, 0x102190); u32 data = nvkm_rd32(device, 0x102194); @@ -90,16 +89,16 @@ g84_cipher_intr(struct nvkm_engine *cipher) unsigned long flags; char msg[128]; - chan = nvkm_fifo_chan_inst(fifo, (u64)inst << 12, &flags); + chan = nvkm_chan_get_inst(cipher, (u64)inst << 12, &flags); if (stat) { nvkm_snprintbf(msg, sizeof(msg), g84_cipher_intr_mask, stat); nvkm_error(subdev, "%08x [%s] ch %d [%010llx %s] " "mthd %04x data %08x\n", stat, msg, - chan ? chan->chid : -1, (u64)inst << 12, - chan ? chan->object.client->name : "unknown", + chan ? chan->id : -1, (u64)inst << 12, + chan ? chan->name : "unknown", mthd, data); } - nvkm_fifo_chan_put(fifo, flags, &chan); + nvkm_chan_put(&chan, flags); nvkm_wr32(device, 0x102130, stat); nvkm_wr32(device, 0x10200c, 0x10); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index d8cf71fb0512..364fea320cb3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -1095,7 +1095,7 @@ nv98_chipset = { .volt = { 0x00000001, nv40_volt_new }, .disp = { 0x00000001, g94_disp_new }, .dma = { 0x00000001, nv50_dma_new }, - .fifo = { 0x00000001, g84_fifo_new }, + .fifo = { 0x00000001, g98_fifo_new }, .gr = { 0x00000001, g84_gr_new }, .mspdec = { 0x00000001, g98_mspdec_new }, .msppp = { 0x00000001, g98_msppp_new }, @@ -1161,7 +1161,7 @@ nva3_chipset = { .ce = { 0x00000001, gt215_ce_new }, .disp = { 0x00000001, gt215_disp_new }, .dma = { 0x00000001, nv50_dma_new }, - .fifo = { 0x00000001, g84_fifo_new }, + .fifo = { 0x00000001, g98_fifo_new }, .gr = { 0x00000001, gt215_gr_new }, .mpeg = { 0x00000001, g84_mpeg_new }, .mspdec = { 0x00000001, gt215_mspdec_new }, @@ -1195,7 +1195,7 @@ nva5_chipset = { .ce = { 0x00000001, gt215_ce_new }, .disp = { 0x00000001, gt215_disp_new }, .dma = { 0x00000001, nv50_dma_new }, - .fifo = { 0x00000001, g84_fifo_new }, + .fifo = { 0x00000001, g98_fifo_new }, .gr = { 0x00000001, gt215_gr_new }, .mspdec = { 0x00000001, gt215_mspdec_new }, .msppp = { 0x00000001, gt215_msppp_new }, @@ -1228,7 +1228,7 @@ nva8_chipset = { .ce = { 0x00000001, gt215_ce_new }, .disp = { 0x00000001, gt215_disp_new }, .dma = { 0x00000001, nv50_dma_new }, - .fifo = { 0x00000001, g84_fifo_new }, + .fifo = { 0x00000001, g98_fifo_new }, .gr = { 0x00000001, gt215_gr_new }, .mspdec = { 0x00000001, gt215_mspdec_new }, .msppp = { 0x00000001, gt215_msppp_new }, @@ -1259,7 +1259,7 @@ nvaa_chipset = { .volt = { 0x00000001, nv40_volt_new }, .disp = { 0x00000001, mcp77_disp_new }, .dma = { 0x00000001, nv50_dma_new }, - .fifo = { 0x00000001, g84_fifo_new }, + .fifo = { 0x00000001, g98_fifo_new }, .gr = { 0x00000001, gt200_gr_new }, .mspdec = { 0x00000001, g98_mspdec_new }, .msppp = { 0x00000001, g98_msppp_new }, @@ -1291,7 +1291,7 @@ nvac_chipset = { .volt = { 0x00000001, nv40_volt_new }, .disp = { 0x00000001, mcp77_disp_new }, .dma = { 0x00000001, nv50_dma_new }, - .fifo = { 0x00000001, g84_fifo_new }, + .fifo = { 0x00000001, g98_fifo_new }, .gr = { 0x00000001, mcp79_gr_new }, .mspdec = { 0x00000001, g98_mspdec_new }, .msppp = { 0x00000001, g98_msppp_new }, @@ -1325,7 +1325,7 @@ nvaf_chipset = { .ce = { 0x00000001, gt215_ce_new }, .disp = { 0x00000001, mcp89_disp_new }, .dma = { 0x00000001, nv50_dma_new }, - .fifo = { 0x00000001, g84_fifo_new }, + .fifo = { 0x00000001, g98_fifo_new }, .gr = { 0x00000001, mcp89_gr_new }, .mspdec = { 0x00000001, gt215_mspdec_new }, .msppp = { 0x00000001, gt215_msppp_new }, @@ -2130,7 +2130,7 @@ nv12b_chipset = { .volt = { 0x00000001, gm20b_volt_new }, .ce = { 0x00000004, gm200_ce_new }, .dma = { 0x00000001, gf119_dma_new }, - .fifo = { 0x00000001, gm20b_fifo_new }, + .fifo = { 0x00000001, gm200_fifo_new }, .gr = { 0x00000001, gm20b_gr_new }, .sw = { 0x00000001, gf100_sw_new }, }; @@ -2356,7 +2356,7 @@ nv13b_chipset = { .top = { 0x00000001, gk104_top_new }, .ce = { 0x00000001, gp100_ce_new }, .dma = { 0x00000001, gf119_dma_new }, - .fifo = { 0x00000001, gp10b_fifo_new }, + .fifo = { 0x00000001, gp100_fifo_new }, .gr = { 0x00000001, gp10b_gr_new }, .sw = { 0x00000001, gf100_sw_new }, }; @@ -2364,7 +2364,7 @@ nv13b_chipset = { static const struct nvkm_device_chip nv140_chipset = { .name = "GV100", - .acr = { 0x00000001, gp108_acr_new }, + .acr = { 0x00000001, gv100_acr_new }, .bar = { 0x00000001, gm107_bar_new }, .bios = { 0x00000001, nvkm_bios_new }, .bus = { 0x00000001, gf100_bus_new }, @@ -2385,6 +2385,7 @@ nv140_chipset = { .therm = { 0x00000001, gp100_therm_new }, .timer = { 0x00000001, gk20a_timer_new }, .top = { 0x00000001, gk104_top_new }, + .vfn = { 0x00000001, gv100_vfn_new }, .ce = { 0x000001ff, gv100_ce_new }, .disp = { 0x00000001, gv100_disp_new }, .dma = { 0x00000001, gv100_dma_new }, @@ -2411,7 +2412,7 @@ nv162_chipset = { .i2c = { 0x00000001, gm200_i2c_new }, .imem = { 0x00000001, nv50_instmem_new }, .ltc = { 0x00000001, gp102_ltc_new }, - .mc = { 0x00000001, tu102_mc_new }, + .mc = { 0x00000001, gp100_mc_new }, .mmu = { 0x00000001, tu102_mmu_new }, .pci = { 0x00000001, gp100_pci_new }, .pmu = { 0x00000001, gp102_pmu_new }, @@ -2419,6 +2420,7 @@ nv162_chipset = { .therm = { 0x00000001, gp100_therm_new }, .timer = { 0x00000001, gk20a_timer_new }, .top = { 0x00000001, gk104_top_new }, + .vfn = { 0x00000001, tu102_vfn_new }, .ce = { 0x0000001f, tu102_ce_new }, .disp = { 0x00000001, tu102_disp_new }, .dma = { 0x00000001, gv100_dma_new }, @@ -2445,7 +2447,7 @@ nv164_chipset = { .i2c = { 0x00000001, gm200_i2c_new }, .imem = { 0x00000001, nv50_instmem_new }, .ltc = { 0x00000001, gp102_ltc_new }, - .mc = { 0x00000001, tu102_mc_new }, + .mc = { 0x00000001, gp100_mc_new }, .mmu = { 0x00000001, tu102_mmu_new }, .pci = { 0x00000001, gp100_pci_new }, .pmu = { 0x00000001, gp102_pmu_new }, @@ -2453,6 +2455,7 @@ nv164_chipset = { .therm = { 0x00000001, gp100_therm_new }, .timer = { 0x00000001, gk20a_timer_new }, .top = { 0x00000001, gk104_top_new }, + .vfn = { 0x00000001, tu102_vfn_new }, .ce = { 0x0000001f, tu102_ce_new }, .disp = { 0x00000001, tu102_disp_new }, .dma = { 0x00000001, gv100_dma_new }, @@ -2479,7 +2482,7 @@ nv166_chipset = { .i2c = { 0x00000001, gm200_i2c_new }, .imem = { 0x00000001, nv50_instmem_new }, .ltc = { 0x00000001, gp102_ltc_new }, - .mc = { 0x00000001, tu102_mc_new }, + .mc = { 0x00000001, gp100_mc_new }, .mmu = { 0x00000001, tu102_mmu_new }, .pci = { 0x00000001, gp100_pci_new }, .pmu = { 0x00000001, gp102_pmu_new }, @@ -2487,6 +2490,7 @@ nv166_chipset = { .therm = { 0x00000001, gp100_therm_new }, .timer = { 0x00000001, gk20a_timer_new }, .top = { 0x00000001, gk104_top_new }, + .vfn = { 0x00000001, tu102_vfn_new }, .ce = { 0x0000001f, tu102_ce_new }, .disp = { 0x00000001, tu102_disp_new }, .dma = { 0x00000001, gv100_dma_new }, @@ -2513,7 +2517,7 @@ nv167_chipset = { .i2c = { 0x00000001, gm200_i2c_new }, .imem = { 0x00000001, nv50_instmem_new }, .ltc = { 0x00000001, gp102_ltc_new }, - .mc = { 0x00000001, tu102_mc_new }, + .mc = { 0x00000001, gp100_mc_new }, .mmu = { 0x00000001, tu102_mmu_new }, .pci = { 0x00000001, gp100_pci_new }, .pmu = { 0x00000001, gp102_pmu_new }, @@ -2521,6 +2525,7 @@ nv167_chipset = { .therm = { 0x00000001, gp100_therm_new }, .timer = { 0x00000001, gk20a_timer_new }, .top = { 0x00000001, gk104_top_new }, + .vfn = { 0x00000001, tu102_vfn_new }, .ce = { 0x0000001f, tu102_ce_new }, .disp = { 0x00000001, tu102_disp_new }, .dma = { 0x00000001, gv100_dma_new }, @@ -2547,7 +2552,7 @@ nv168_chipset = { .i2c = { 0x00000001, gm200_i2c_new }, .imem = { 0x00000001, nv50_instmem_new }, .ltc = { 0x00000001, gp102_ltc_new }, - .mc = { 0x00000001, tu102_mc_new }, + .mc = { 0x00000001, gp100_mc_new }, .mmu = { 0x00000001, tu102_mmu_new }, .pci = { 0x00000001, gp100_pci_new }, .pmu = { 0x00000001, gp102_pmu_new }, @@ -2555,6 +2560,7 @@ nv168_chipset = { .therm = { 0x00000001, gp100_therm_new }, .timer = { 0x00000001, gk20a_timer_new }, .top = { 0x00000001, gk104_top_new }, + .vfn = { 0x00000001, tu102_vfn_new }, .ce = { 0x0000001f, tu102_ce_new }, .disp = { 0x00000001, tu102_disp_new }, .dma = { 0x00000001, gv100_dma_new }, @@ -2571,6 +2577,7 @@ nv170_chipset = { .bar = { 0x00000001, tu102_bar_new }, .bios = { 0x00000001, nvkm_bios_new }, .devinit = { 0x00000001, ga100_devinit_new }, + .fault = { 0x00000001, tu102_fault_new }, .fb = { 0x00000001, ga100_fb_new }, .gpio = { 0x00000001, gk104_gpio_new }, .i2c = { 0x00000001, gm200_i2c_new }, @@ -2581,111 +2588,159 @@ nv170_chipset = { .privring = { 0x00000001, gm200_privring_new }, .timer = { 0x00000001, gk20a_timer_new }, .top = { 0x00000001, ga100_top_new }, + .vfn = { 0x00000001, ga100_vfn_new }, + .ce = { 0x000003ff, ga100_ce_new }, + .fifo = { 0x00000001, ga100_fifo_new }, }; static const struct nvkm_device_chip nv172_chipset = { .name = "GA102", + .acr = { 0x00000001, ga102_acr_new }, .bar = { 0x00000001, tu102_bar_new }, .bios = { 0x00000001, nvkm_bios_new }, .devinit = { 0x00000001, ga100_devinit_new }, + .fault = { 0x00000001, tu102_fault_new }, .fb = { 0x00000001, ga102_fb_new }, .gpio = { 0x00000001, ga102_gpio_new }, + .gsp = { 0x00000001, ga102_gsp_new }, .i2c = { 0x00000001, gm200_i2c_new }, .imem = { 0x00000001, nv50_instmem_new }, + .ltc = { 0x00000001, ga102_ltc_new }, .mc = { 0x00000001, ga100_mc_new }, .mmu = { 0x00000001, tu102_mmu_new }, .pci = { 0x00000001, gp100_pci_new }, .privring = { 0x00000001, gm200_privring_new }, .timer = { 0x00000001, gk20a_timer_new }, .top = { 0x00000001, ga100_top_new }, + .vfn = { 0x00000001, ga100_vfn_new }, + .ce = { 0x0000001f, ga102_ce_new }, .disp = { 0x00000001, ga102_disp_new }, .dma = { 0x00000001, gv100_dma_new }, .fifo = { 0x00000001, ga102_fifo_new }, + .gr = { 0x00000001, ga102_gr_new }, + .nvdec = { 0x00000001, ga102_nvdec_new }, + .sec2 = { 0x00000001, ga102_sec2_new }, }; static const struct nvkm_device_chip nv173_chipset = { .name = "GA103", + .acr = { 0x00000001, ga102_acr_new }, .bar = { 0x00000001, tu102_bar_new }, .bios = { 0x00000001, nvkm_bios_new }, .devinit = { 0x00000001, ga100_devinit_new }, + .fault = { 0x00000001, tu102_fault_new }, .fb = { 0x00000001, ga102_fb_new }, .gpio = { 0x00000001, ga102_gpio_new }, + .gsp = { 0x00000001, ga102_gsp_new }, .i2c = { 0x00000001, gm200_i2c_new }, .imem = { 0x00000001, nv50_instmem_new }, + .ltc = { 0x00000001, ga102_ltc_new }, .mc = { 0x00000001, ga100_mc_new }, .mmu = { 0x00000001, tu102_mmu_new }, .pci = { 0x00000001, gp100_pci_new }, .privring = { 0x00000001, gm200_privring_new }, .timer = { 0x00000001, gk20a_timer_new }, .top = { 0x00000001, ga100_top_new }, + .vfn = { 0x00000001, ga100_vfn_new }, + .ce = { 0x0000001f, ga102_ce_new }, .disp = { 0x00000001, ga102_disp_new }, .dma = { 0x00000001, gv100_dma_new }, .fifo = { 0x00000001, ga102_fifo_new }, + .gr = { 0x00000001, ga102_gr_new }, + .nvdec = { 0x00000001, ga102_nvdec_new }, + .sec2 = { 0x00000001, ga102_sec2_new }, }; static const struct nvkm_device_chip nv174_chipset = { .name = "GA104", + .acr = { 0x00000001, ga102_acr_new }, .bar = { 0x00000001, tu102_bar_new }, .bios = { 0x00000001, nvkm_bios_new }, .devinit = { 0x00000001, ga100_devinit_new }, + .fault = { 0x00000001, tu102_fault_new }, .fb = { 0x00000001, ga102_fb_new }, .gpio = { 0x00000001, ga102_gpio_new }, + .gsp = { 0x00000001, ga102_gsp_new }, .i2c = { 0x00000001, gm200_i2c_new }, .imem = { 0x00000001, nv50_instmem_new }, + .ltc = { 0x00000001, ga102_ltc_new }, .mc = { 0x00000001, ga100_mc_new }, .mmu = { 0x00000001, tu102_mmu_new }, .pci = { 0x00000001, gp100_pci_new }, .privring = { 0x00000001, gm200_privring_new }, .timer = { 0x00000001, gk20a_timer_new }, .top = { 0x00000001, ga100_top_new }, + .vfn = { 0x00000001, ga100_vfn_new }, + .ce = { 0x0000001f, ga102_ce_new }, .disp = { 0x00000001, ga102_disp_new }, .dma = { 0x00000001, gv100_dma_new }, .fifo = { 0x00000001, ga102_fifo_new }, + .gr = { 0x00000001, ga102_gr_new }, + .nvdec = { 0x00000001, ga102_nvdec_new }, + .sec2 = { 0x00000001, ga102_sec2_new }, }; static const struct nvkm_device_chip nv176_chipset = { .name = "GA106", + .acr = { 0x00000001, ga102_acr_new }, .bar = { 0x00000001, tu102_bar_new }, .bios = { 0x00000001, nvkm_bios_new }, .devinit = { 0x00000001, ga100_devinit_new }, + .fault = { 0x00000001, tu102_fault_new }, .fb = { 0x00000001, ga102_fb_new }, .gpio = { 0x00000001, ga102_gpio_new }, + .gsp = { 0x00000001, ga102_gsp_new }, .i2c = { 0x00000001, gm200_i2c_new }, .imem = { 0x00000001, nv50_instmem_new }, + .ltc = { 0x00000001, ga102_ltc_new }, .mc = { 0x00000001, ga100_mc_new }, .mmu = { 0x00000001, tu102_mmu_new }, .pci = { 0x00000001, gp100_pci_new }, .privring = { 0x00000001, gm200_privring_new }, .timer = { 0x00000001, gk20a_timer_new }, .top = { 0x00000001, ga100_top_new }, + .vfn = { 0x00000001, ga100_vfn_new }, + .ce = { 0x0000001f, ga102_ce_new }, .disp = { 0x00000001, ga102_disp_new }, .dma = { 0x00000001, gv100_dma_new }, .fifo = { 0x00000001, ga102_fifo_new }, + .gr = { 0x00000001, ga102_gr_new }, + .nvdec = { 0x00000001, ga102_nvdec_new }, + .sec2 = { 0x00000001, ga102_sec2_new }, }; static const struct nvkm_device_chip nv177_chipset = { .name = "GA107", + .acr = { 0x00000001, ga102_acr_new }, .bar = { 0x00000001, tu102_bar_new }, .bios = { 0x00000001, nvkm_bios_new }, .devinit = { 0x00000001, ga100_devinit_new }, + .fault = { 0x00000001, tu102_fault_new }, .fb = { 0x00000001, ga102_fb_new }, .gpio = { 0x00000001, ga102_gpio_new }, + .gsp = { 0x00000001, ga102_gsp_new }, .i2c = { 0x00000001, gm200_i2c_new }, .imem = { 0x00000001, nv50_instmem_new }, + .ltc = { 0x00000001, ga102_ltc_new }, .mc = { 0x00000001, ga100_mc_new }, .mmu = { 0x00000001, tu102_mmu_new }, .pci = { 0x00000001, gp100_pci_new }, .privring = { 0x00000001, gm200_privring_new }, .timer = { 0x00000001, gk20a_timer_new }, .top = { 0x00000001, ga100_top_new }, + .vfn = { 0x00000001, ga100_vfn_new }, + .ce = { 0x0000001f, ga102_ce_new }, .disp = { 0x00000001, ga102_disp_new }, .dma = { 0x00000001, gv100_dma_new }, .fifo = { 0x00000001, ga102_fifo_new }, + .gr = { 0x00000001, ga102_gr_new }, + .nvdec = { 0x00000001, ga102_nvdec_new }, + .sec2 = { 0x00000001, ga102_sec2_new }, }; struct nvkm_subdev * @@ -2734,6 +2789,8 @@ nvkm_device_fini(struct nvkm_device *device, bool suspend) if (device->func->fini) device->func->fini(device, suspend); + nvkm_intr_unarm(device); + time = ktime_to_us(ktime_get()) - time; nvdev_trace(device, "%s completed in %lldus...\n", action, time); return 0; @@ -2759,6 +2816,8 @@ nvkm_device_preinit(struct nvkm_device *device) nvdev_trace(device, "preinit running...\n"); time = ktime_to_us(ktime_get()); + nvkm_intr_unarm(device); + if (device->func->preinit) { ret = device->func->preinit(device); if (ret) @@ -2775,6 +2834,14 @@ nvkm_device_preinit(struct nvkm_device *device) if (ret) goto fail; + ret = nvkm_top_parse(device); + if (ret) + goto fail; + + ret = nvkm_fb_mem_unlock(device->fb); + if (ret) + goto fail; + time = ktime_to_us(ktime_get()) - time; nvdev_trace(device, "preinit completed in %lldus\n", time); return 0; @@ -2800,6 +2867,8 @@ nvkm_device_init(struct nvkm_device *device) nvdev_trace(device, "init running...\n"); time = ktime_to_us(ktime_get()); + nvkm_intr_rearm(device); + if (device->func->init) { ret = device->func->init(device); if (ret) @@ -2837,6 +2906,8 @@ nvkm_device_del(struct nvkm_device **pdevice) if (device) { mutex_lock(&nv_devices_mutex); + nvkm_intr_dtor(device); + list_for_each_entry_safe_reverse(subdev, subtmp, &device->subdev, head) nvkm_subdev_del(&subdev); @@ -3144,6 +3215,7 @@ nvkm_device_ctor(const struct nvkm_device_func *func, device->name = device->chip->name; mutex_init(&device->mutex); + nvkm_intr_ctor(device); #define NVKM_LAYOUT_ONCE(type,data,ptr) \ if (device->chip->ptr.inst && (subdev_mask & (BIT_ULL(type)))) { \ @@ -3185,7 +3257,7 @@ nvkm_device_ctor(const struct nvkm_device_func *func, #undef NVKM_LAYOUT_INST #undef NVKM_LAYOUT_ONCE - ret = 0; + ret = nvkm_intr_install(device); done: if (device->pri && (!mmio || ret)) { iounmap(device->pri); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c index f302d2b5782a..abccb2bb68a6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c @@ -1574,6 +1574,12 @@ nvkm_device_pci_resource_size(struct nvkm_device *device, unsigned bar) return pci_resource_len(pdev->pdev, bar); } +static int +nvkm_device_pci_irq(struct nvkm_device *device) +{ + return nvkm_device_pci(device)->pdev->irq; +} + static void nvkm_device_pci_fini(struct nvkm_device *device, bool suspend) { @@ -1612,6 +1618,7 @@ nvkm_device_pci_func = { .dtor = nvkm_device_pci_dtor, .preinit = nvkm_device_pci_preinit, .fini = nvkm_device_pci_fini, + .irq = nvkm_device_pci_irq, .resource_addr = nvkm_device_pci_resource_addr, .resource_size = nvkm_device_pci_resource_size, .cpu_coherent = !IS_ENABLED(CONFIG_ARM), diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h index 93949b3c7214..24faaac15891 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h @@ -27,6 +27,7 @@ #include <subdev/therm.h> #include <subdev/timer.h> #include <subdev/top.h> +#include <subdev/vfn.h> #include <subdev/volt.h> #include <engine/bsp.h> diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c index ac9e122586bc..87caa4a72921 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c @@ -206,45 +206,12 @@ nvkm_device_tegra_resource_size(struct nvkm_device *device, unsigned bar) return res ? resource_size(res) : 0; } -static irqreturn_t -nvkm_device_tegra_intr(int irq, void *arg) -{ - struct nvkm_device_tegra *tdev = arg; - struct nvkm_device *device = &tdev->device; - bool handled = false; - nvkm_mc_intr_unarm(device); - nvkm_mc_intr(device, &handled); - nvkm_mc_intr_rearm(device); - return handled ? IRQ_HANDLED : IRQ_NONE; -} - -static void -nvkm_device_tegra_fini(struct nvkm_device *device, bool suspend) -{ - struct nvkm_device_tegra *tdev = nvkm_device_tegra(device); - if (tdev->irq) { - free_irq(tdev->irq, tdev); - tdev->irq = 0; - } -} - static int -nvkm_device_tegra_init(struct nvkm_device *device) +nvkm_device_tegra_irq(struct nvkm_device *device) { struct nvkm_device_tegra *tdev = nvkm_device_tegra(device); - int irq, ret; - - irq = platform_get_irq_byname(tdev->pdev, "stall"); - if (irq < 0) - return irq; - ret = request_irq(irq, nvkm_device_tegra_intr, - IRQF_SHARED, "nvkm", tdev); - if (ret) - return ret; - - tdev->irq = irq; - return 0; + return platform_get_irq_byname(tdev->pdev, "stall"); } static void * @@ -260,8 +227,7 @@ static const struct nvkm_device_func nvkm_device_tegra_func = { .tegra = nvkm_device_tegra, .dtor = nvkm_device_tegra_dtor, - .init = nvkm_device_tegra_init, - .fini = nvkm_device_tegra_fini, + .irq = nvkm_device_tegra_irq, .resource_addr = nvkm_device_tegra_resource_addr, .resource_size = nvkm_device_tegra_resource_size, .cpu_coherent = false, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c index 45f509c11c36..9b39ec341615 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c @@ -342,6 +342,8 @@ nvkm_udevice_child_get(struct nvkm_object *object, int index, sclass = &device->mmu->user; else if (device->fault && index-- == 0) sclass = &device->fault->user; + else if (device->vfn && index-- == 0) + sclass = &device->vfn->user; else return -EINVAL; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild index 600072a904be..e1aecd3fe96c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild @@ -28,9 +28,7 @@ nvkm-y += nvkm/engine/disp/gv100.o nvkm-y += nvkm/engine/disp/tu102.o nvkm-y += nvkm/engine/disp/ga102.o -nvkm-y += nvkm/engine/disp/rootnv04.o -nvkm-y += nvkm/engine/disp/rootnv50.o - nvkm-y += nvkm/engine/disp/udisp.o nvkm-y += nvkm/engine/disp/uconn.o nvkm-y += nvkm/engine/disp/uoutp.o +nvkm-y += nvkm/engine/disp/uhead.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c index 65c99d948b68..73104b59f97f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c @@ -29,7 +29,6 @@ #include "outp.h" #include <core/client.h> -#include <core/notify.h> #include <core/ramht.h> #include <subdev/bios.h> #include <subdev/bios/dcb.h> @@ -57,32 +56,8 @@ nvkm_disp_vblank_init(struct nvkm_event *event, int type, int id) head->func->vblank_get(head); } -static int -nvkm_disp_vblank_ctor(struct nvkm_object *object, void *data, u32 size, - struct nvkm_notify *notify) -{ - struct nvkm_disp *disp = - container_of(notify->event, typeof(*disp), vblank); - union { - struct nvif_notify_head_req_v0 v0; - } *req = data; - int ret = -ENOSYS; - - if (!(ret = nvif_unpack(ret, &data, &size, req->v0, 0, 0, false))) { - notify->size = sizeof(struct nvif_notify_head_rep_v0); - if (ret = -ENXIO, req->v0.head <= disp->vblank.index_nr) { - notify->types = 1; - notify->index = req->v0.head; - return 0; - } - } - - return ret; -} - static const struct nvkm_event_func nvkm_disp_vblank_func = { - .ctor = nvkm_disp_vblank_ctor, .init = nvkm_disp_vblank_init, .fini = nvkm_disp_vblank_fini, }; @@ -90,59 +65,7 @@ nvkm_disp_vblank_func = { void nvkm_disp_vblank(struct nvkm_disp *disp, int head) { - struct nvif_notify_head_rep_v0 rep = {}; - nvkm_event_send(&disp->vblank, 1, head, &rep, sizeof(rep)); -} - -static int -nvkm_disp_hpd_ctor(struct nvkm_object *object, void *data, u32 size, - struct nvkm_notify *notify) -{ - struct nvkm_disp *disp = - container_of(notify->event, typeof(*disp), hpd); - union { - struct nvif_notify_conn_req_v0 v0; - } *req = data; - struct nvkm_outp *outp; - int ret = -ENOSYS; - - if (!(ret = nvif_unpack(ret, &data, &size, req->v0, 0, 0, false))) { - notify->size = sizeof(struct nvif_notify_conn_rep_v0); - list_for_each_entry(outp, &disp->outps, head) { - if (ret = -ENXIO, outp->conn->index == req->v0.conn) { - if (ret = -ENODEV, outp->conn->hpd.event) { - notify->types = req->v0.mask; - notify->index = req->v0.conn; - ret = 0; - } - break; - } - } - } - - return ret; -} - -static const struct nvkm_event_func -nvkm_disp_hpd_func = { - .ctor = nvkm_disp_hpd_ctor -}; - -int -nvkm_disp_ntfy(struct nvkm_object *object, u32 type, struct nvkm_event **event) -{ - struct nvkm_disp *disp = nvkm_disp(object->engine); - switch (type) { - case NV04_DISP_NTFY_VBLANK: - *event = &disp->vblank; - return 0; - case NV04_DISP_NTFY_CONN: - *event = &disp->hpd; - return 0; - default: - break; - } - return -EINVAL; + nvkm_event_ntfy(&disp->vblank, head, NVKM_DISP_HEAD_EVENT_VBLANK); } static int @@ -343,9 +266,7 @@ nvkm_disp_oneinit(struct nvkm_engine *engine) /* Apparently we need to create a new one! */ ret = nvkm_conn_new(disp, i, &connE, &outp->conn); if (ret) { - nvkm_error(&disp->engine.subdev, - "failed to create outp %d conn: %d\n", - outp->index, ret); + nvkm_error(subdev, "failed to create outp %d conn: %d\n", outp->index, ret); nvkm_conn_del(&outp->conn); list_del(&outp->head); nvkm_outp_del(&outp); @@ -355,10 +276,6 @@ nvkm_disp_oneinit(struct nvkm_engine *engine) list_add_tail(&outp->conn->head, &disp->conns); } - ret = nvkm_event_init(&nvkm_disp_hpd_func, 3, hpd, &disp->hpd); - if (ret) - return ret; - if (disp->func->oneinit) { ret = disp->func->oneinit(disp); if (ret) @@ -382,7 +299,7 @@ nvkm_disp_oneinit(struct nvkm_engine *engine) list_for_each_entry(head, &disp->heads, head) i = max(i, head->id + 1); - return nvkm_event_init(&nvkm_disp_vblank_func, 1, i, &disp->vblank); + return nvkm_event_init(&nvkm_disp_vblank_func, subdev, 1, i, &disp->vblank); } static void * @@ -406,7 +323,6 @@ nvkm_disp_dtor(struct nvkm_engine *engine) } nvkm_event_fini(&disp->vblank); - nvkm_event_fini(&disp->hpd); while (!list_empty(&disp->conns)) { conn = list_first_entry(&disp->conns, typeof(*conn), head); @@ -473,5 +389,6 @@ nvkm_disp_new_(const struct nvkm_disp_func *func, struct nvkm_device *device, mutex_init(&disp->super.mutex); } - return nvkm_event_init(func->uevent, 1, ARRAY_SIZE(disp->chan), &disp->uevent); + return nvkm_event_init(func->uevent, &disp->engine.subdev, 1, ARRAY_SIZE(disp->chan), + &disp->uevent); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c index 7ed11801a3ae..fbdae1137864 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c @@ -29,38 +29,14 @@ #include <nvif/event.h> -static int -nvkm_conn_hpd(struct nvkm_notify *notify) -{ - struct nvkm_conn *conn = container_of(notify, typeof(*conn), hpd); - struct nvkm_disp *disp = conn->disp; - struct nvkm_gpio *gpio = disp->engine.subdev.device->gpio; - const struct nvkm_gpio_ntfy_rep *line = notify->data; - struct nvif_notify_conn_rep_v0 rep; - int index = conn->index; - - CONN_DBG(conn, "HPD: %d", line->mask); - - if (!nvkm_gpio_get(gpio, 0, DCB_GPIO_UNUSED, conn->hpd.index)) - rep.mask = NVIF_NOTIFY_CONN_V0_UNPLUG; - else - rep.mask = NVIF_NOTIFY_CONN_V0_PLUG; - rep.version = 0; - - nvkm_event_send(&disp->hpd, rep.mask, index, &rep, sizeof(rep)); - return NVKM_NOTIFY_KEEP; -} - void nvkm_conn_fini(struct nvkm_conn *conn) { - nvkm_notify_put(&conn->hpd); } void nvkm_conn_init(struct nvkm_conn *conn) { - nvkm_notify_get(&conn->hpd); } void @@ -68,7 +44,6 @@ nvkm_conn_del(struct nvkm_conn **pconn) { struct nvkm_conn *conn = *pconn; if (conn) { - nvkm_notify_fini(&conn->hpd); kfree(*pconn); *pconn = NULL; } @@ -106,20 +81,6 @@ nvkm_conn_ctor(struct nvkm_disp *disp, int index, struct nvbios_connE *info, } conn->info.hpd = func.line; - - ret = nvkm_notify_init(NULL, &gpio->event, nvkm_conn_hpd, - true, &(struct nvkm_gpio_ntfy_req) { - .mask = NVKM_GPIO_TOGGLED, - .line = func.line, - }, - sizeof(struct nvkm_gpio_ntfy_req), - sizeof(struct nvkm_gpio_ntfy_rep), - &conn->hpd); - if (ret) { - CONN_ERR(conn, "func %02x failed, %d", info->hpd, ret); - } else { - CONN_DBG(conn, "func %02x (HPD)", info->hpd); - } } } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h index f109634ce5ca..a0600e72b0ec 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h @@ -3,7 +3,6 @@ #define __NVKM_DISP_CONN_H__ #include "priv.h" -#include <core/notify.h> #include <subdev/bios.h> #include <subdev/bios/conn.h> @@ -12,8 +11,6 @@ struct nvkm_conn { int index; struct nvbios_connE info; - struct nvkm_notify hpd; - struct list_head head; struct nvkm_object object; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index c1b3206f27e6..40c8ea43c42f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -274,70 +274,17 @@ nvkm_dp_train_cr(struct lt_state *lt) } static int -nvkm_dp_train_links(struct nvkm_outp *outp, int rate) +nvkm_dp_train_link(struct nvkm_outp *outp, int rate) { struct nvkm_ior *ior = outp->ior; - struct nvkm_disp *disp = outp->disp; - struct nvkm_subdev *subdev = &disp->engine.subdev; - struct nvkm_bios *bios = subdev->device->bios; struct lt_state lt = { .outp = outp, + .pc2 = outp->dp.dpcd[DPCD_RC02] & DPCD_RC02_TPS3_SUPPORTED, }; - u32 lnkcmp; u8 sink[2], data; int ret; - OUTP_DBG(outp, "training %d x %d MB/s", ior->dp.nr, ior->dp.bw * 27); - - /* Intersect misc. capabilities of the OR and sink. */ - if (disp->engine.subdev.device->chipset < 0x110) - outp->dp.dpcd[DPCD_RC03] &= ~DPCD_RC03_TPS4_SUPPORTED; - if (disp->engine.subdev.device->chipset < 0xd0) - outp->dp.dpcd[DPCD_RC02] &= ~DPCD_RC02_TPS3_SUPPORTED; - lt.pc2 = outp->dp.dpcd[DPCD_RC02] & DPCD_RC02_TPS3_SUPPORTED; - - if (AMPERE_IED_HACK(disp) && (lnkcmp = lt.outp->dp.info.script[0])) { - /* Execute BeforeLinkTraining script from DP Info table. */ - while (ior->dp.bw < nvbios_rd08(bios, lnkcmp)) - lnkcmp += 3; - lnkcmp = nvbios_rd16(bios, lnkcmp + 1); - - nvbios_init(&outp->disp->engine.subdev, lnkcmp, - init.outp = &outp->info; - init.or = ior->id; - init.link = ior->asy.link; - ); - } - - /* Set desired link configuration on the source. */ - if ((lnkcmp = lt.outp->dp.info.lnkcmp)) { - if (outp->dp.version < 0x30) { - while ((ior->dp.bw * 2700) < nvbios_rd16(bios, lnkcmp)) - lnkcmp += 4; - lnkcmp = nvbios_rd16(bios, lnkcmp + 2); - } else { - while (ior->dp.bw < nvbios_rd08(bios, lnkcmp)) - lnkcmp += 3; - lnkcmp = nvbios_rd16(bios, lnkcmp + 1); - } - - nvbios_init(subdev, lnkcmp, - init.outp = &outp->info; - init.or = ior->id; - init.link = ior->asy.link; - ); - } - - ret = ior->func->dp->links(ior, outp->dp.aux); - if (ret) { - if (ret < 0) { - OUTP_ERR(outp, "train failed with %d", ret); - return ret; - } - return 0; - } - - ior->func->dp->power(ior, ior->dp.nr); + OUTP_DBG(outp, "training %dx%02x", ior->dp.nr, ior->dp.bw); /* Select LTTPR non-transparent mode if we have a valid configuration, * use transparent mode otherwise. @@ -393,6 +340,71 @@ nvkm_dp_train_links(struct nvkm_outp *outp, int rate) return ret; } +static int +nvkm_dp_train_links(struct nvkm_outp *outp, int rate) +{ + struct nvkm_ior *ior = outp->ior; + struct nvkm_disp *disp = outp->disp; + struct nvkm_subdev *subdev = &disp->engine.subdev; + struct nvkm_bios *bios = subdev->device->bios; + u32 lnkcmp; + int ret; + + OUTP_DBG(outp, "programming link for %dx%02x", ior->dp.nr, ior->dp.bw); + + /* Intersect misc. capabilities of the OR and sink. */ + if (disp->engine.subdev.device->chipset < 0x110) + outp->dp.dpcd[DPCD_RC03] &= ~DPCD_RC03_TPS4_SUPPORTED; + if (disp->engine.subdev.device->chipset < 0xd0) + outp->dp.dpcd[DPCD_RC02] &= ~DPCD_RC02_TPS3_SUPPORTED; + + if (AMPERE_IED_HACK(disp) && (lnkcmp = outp->dp.info.script[0])) { + /* Execute BeforeLinkTraining script from DP Info table. */ + while (ior->dp.bw < nvbios_rd08(bios, lnkcmp)) + lnkcmp += 3; + lnkcmp = nvbios_rd16(bios, lnkcmp + 1); + + nvbios_init(&outp->disp->engine.subdev, lnkcmp, + init.outp = &outp->info; + init.or = ior->id; + init.link = ior->asy.link; + ); + } + + /* Set desired link configuration on the source. */ + if ((lnkcmp = outp->dp.info.lnkcmp)) { + if (outp->dp.version < 0x30) { + while ((ior->dp.bw * 2700) < nvbios_rd16(bios, lnkcmp)) + lnkcmp += 4; + lnkcmp = nvbios_rd16(bios, lnkcmp + 2); + } else { + while (ior->dp.bw < nvbios_rd08(bios, lnkcmp)) + lnkcmp += 3; + lnkcmp = nvbios_rd16(bios, lnkcmp + 1); + } + + nvbios_init(subdev, lnkcmp, + init.outp = &outp->info; + init.or = ior->id; + init.link = ior->asy.link; + ); + } + + ret = ior->func->dp->links(ior, outp->dp.aux); + if (ret) { + if (ret < 0) { + OUTP_ERR(outp, "train failed with %d", ret); + return ret; + } + return 0; + } + + ior->func->dp->power(ior, ior->dp.nr); + + /* Attempt to train the link in this configuration. */ + return nvkm_dp_train_link(outp, rate); +} + static void nvkm_dp_train_fini(struct nvkm_outp *outp) { @@ -439,6 +451,16 @@ nvkm_dp_train(struct nvkm_outp *outp, u32 dataKBps) int ret = -EINVAL, nr, rate; u8 pwr; + /* Retraining link? Skip source configuration, it can mess up the active modeset. */ + if (atomic_read(&outp->dp.lt.done)) { + for (rate = 0; rate < outp->dp.rates; rate++) { + if (outp->dp.rate[rate].rate == ior->dp.bw * 27000) + return nvkm_dp_train_link(outp, ret); + } + WARN_ON(1); + return -EINVAL; + } + /* Ensure sink is not in a low-power state. */ if (!nvkm_rdaux(outp->dp.aux, DPCD_SC00, &pwr, 1)) { if ((pwr & DPCD_SC00_SET_POWER) != DPCD_SC00_SET_POWER_D0) { @@ -455,6 +477,21 @@ nvkm_dp_train(struct nvkm_outp *outp, u32 dataKBps) /* Link training. */ OUTP_DBG(outp, "training"); nvkm_dp_train_init(outp); + + /* Validate and train at configuration requested (if any) on ACQUIRE. */ + if (outp->dp.lt.nr) { + for (nr = outp->dp.links; ret < 0 && nr; nr >>= 1) { + for (rate = 0; nr == outp->dp.lt.nr && rate < outp->dp.rates; rate++) { + if (outp->dp.rate[rate].rate / 27000 == outp->dp.lt.bw) { + ior->dp.bw = outp->dp.rate[rate].rate / 27000; + ior->dp.nr = nr; + ret = nvkm_dp_train_links(outp, rate); + } + } + } + } + + /* Otherwise, loop through all valid link configurations that support the data rate. */ for (nr = outp->dp.links; ret < 0 && nr; nr >>= 1) { for (rate = 0; ret < 0 && rate < outp->dp.rates; rate++) { if (outp->dp.rate[rate].rate * nr >= dataKBps || WARN_ON(!ior->dp.nr)) { @@ -465,6 +502,8 @@ nvkm_dp_train(struct nvkm_outp *outp, u32 dataKBps) } } } + + /* Finish up. */ nvkm_dp_train_fini(outp); if (ret < 0) OUTP_ERR(outp, "training failed"); @@ -595,18 +634,38 @@ nvkm_dp_enable_supported_link_rates(struct nvkm_outp *outp) return outp->dp.rates != 0; } -static bool -nvkm_dp_enable(struct nvkm_outp *outp, bool enable) +void +nvkm_dp_enable(struct nvkm_outp *outp, bool auxpwr) { + struct nvkm_gpio *gpio = outp->disp->engine.subdev.device->gpio; struct nvkm_i2c_aux *aux = outp->dp.aux; - if (enable) { - if (!outp->dp.present) { - OUTP_DBG(outp, "aux power -> always"); - nvkm_i2c_aux_monitor(aux, true); - outp->dp.present = true; + if (auxpwr && !outp->dp.aux_pwr) { + /* eDP panels need powering on by us (if the VBIOS doesn't default it + * to on) before doing any AUX channel transactions. LVDS panel power + * is handled by the SOR itself, and not required for LVDS DDC. + */ + if (outp->conn->info.type == DCB_CONNECTOR_eDP) { + int power = nvkm_gpio_get(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff); + if (power == 0) { + nvkm_gpio_set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, 1); + outp->dp.aux_pwr_pu = true; + } + + /* We delay here unconditionally, even if already powered, + * because some laptop panels having a significant resume + * delay before the panel begins responding. + * + * This is likely a bit of a hack, but no better idea for + * handling this at the moment. + */ + msleep(300); } + OUTP_DBG(outp, "aux power -> always"); + nvkm_i2c_aux_monitor(aux, true); + outp->dp.aux_pwr = true; + /* Detect any LTTPRs before reading DPCD receiver caps. */ if (!nvkm_rdaux(aux, DPCD_LTTPR_REV, outp->dp.lttpr, sizeof(outp->dp.lttpr)) && outp->dp.lttpr[0] >= 0x14 && outp->dp.lttpr[2]) { @@ -659,96 +718,41 @@ nvkm_dp_enable(struct nvkm_outp *outp, bool enable) outp->dp.rates++; } } - - return true; } - } - - if (outp->dp.present) { + } else + if (!auxpwr && outp->dp.aux_pwr) { OUTP_DBG(outp, "aux power -> demand"); nvkm_i2c_aux_monitor(aux, false); - outp->dp.present = false; - } - - atomic_set(&outp->dp.lt.done, 0); - return false; -} - -static int -nvkm_dp_hpd(struct nvkm_notify *notify) -{ - const struct nvkm_i2c_ntfy_rep *line = notify->data; - struct nvkm_outp *outp = container_of(notify, typeof(*outp), dp.hpd); - struct nvkm_conn *conn = outp->conn; - struct nvkm_disp *disp = outp->disp; - struct nvif_notify_conn_rep_v0 rep = {}; + outp->dp.aux_pwr = false; + atomic_set(&outp->dp.lt.done, 0); - OUTP_DBG(outp, "HPD: %d", line->mask); - if (line->mask & NVKM_I2C_IRQ) { - if (atomic_read(&outp->dp.lt.done)) - outp->func->acquire(outp); - rep.mask |= NVIF_NOTIFY_CONN_V0_IRQ; - } else { - nvkm_dp_enable(outp, true); + /* Restore eDP panel GPIO to its prior state if we changed it, as + * it could potentially interfere with other outputs. + */ + if (outp->conn->info.type == DCB_CONNECTOR_eDP) { + if (outp->dp.aux_pwr_pu) { + nvkm_gpio_set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, 0); + outp->dp.aux_pwr_pu = false; + } + } } - - if (line->mask & NVKM_I2C_UNPLUG) - rep.mask |= NVIF_NOTIFY_CONN_V0_UNPLUG; - if (line->mask & NVKM_I2C_PLUG) - rep.mask |= NVIF_NOTIFY_CONN_V0_PLUG; - - nvkm_event_send(&disp->hpd, rep.mask, conn->index, &rep, sizeof(rep)); - return NVKM_NOTIFY_KEEP; } static void nvkm_dp_fini(struct nvkm_outp *outp) { - nvkm_notify_put(&outp->dp.hpd); nvkm_dp_enable(outp, false); } static void nvkm_dp_init(struct nvkm_outp *outp) { - struct nvkm_gpio *gpio = outp->disp->engine.subdev.device->gpio; - - nvkm_notify_put(&outp->conn->hpd); - - /* eDP panels need powering on by us (if the VBIOS doesn't default it - * to on) before doing any AUX channel transactions. LVDS panel power - * is handled by the SOR itself, and not required for LVDS DDC. - */ - if (outp->conn->info.type == DCB_CONNECTOR_eDP) { - int power = nvkm_gpio_get(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff); - if (power == 0) - nvkm_gpio_set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, 1); - - /* We delay here unconditionally, even if already powered, - * because some laptop panels having a significant resume - * delay before the panel begins responding. - * - * This is likely a bit of a hack, but no better idea for - * handling this at the moment. - */ - msleep(300); - - /* If the eDP panel can't be detected, we need to restore - * the panel power GPIO to avoid breaking another output. - */ - if (!nvkm_dp_enable(outp, true) && power == 0) - nvkm_gpio_set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, 0); - } else { - nvkm_dp_enable(outp, true); - } - - nvkm_notify_get(&outp->dp.hpd); + nvkm_dp_enable(outp, outp->dp.enabled); } static void * nvkm_dp_dtor(struct nvkm_outp *outp) { - nvkm_notify_fini(&outp->dp.hpd); return outp; } @@ -797,21 +801,6 @@ nvkm_dp_new(struct nvkm_disp *disp, int index, struct dcb_output *dcbE, struct n OUTP_DBG(outp, "bios dp %02x %02x %02x %02x", outp->dp.version, hdr, cnt, len); - /* hotplug detect, replaces gpio-based mechanism with aux events */ - ret = nvkm_notify_init(NULL, &i2c->event, nvkm_dp_hpd, true, - &(struct nvkm_i2c_ntfy_req) { - .mask = NVKM_I2C_PLUG | NVKM_I2C_UNPLUG | - NVKM_I2C_IRQ, - .port = outp->dp.aux->id, - }, - sizeof(struct nvkm_i2c_ntfy_req), - sizeof(struct nvkm_i2c_ntfy_rep), - &outp->dp.hpd); - if (ret) { - OUTP_ERR(outp, "error monitoring aux hpd: %d", ret); - return ret; - } - mutex_init(&outp->dp.mutex); atomic_set(&outp->dp.lt.done, 0); return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h index 1d86baa6a424..9a6be43916bc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h @@ -6,6 +6,7 @@ int nvkm_dp_new(struct nvkm_disp *, int index, struct dcb_output *, struct nvkm_outp **); void nvkm_dp_disable(struct nvkm_outp *, struct nvkm_ior *); +void nvkm_dp_enable(struct nvkm_outp *, bool auxpwr); /* DPCD Receiver Capabilities */ #define DPCD_RC00_DPCD_REV 0x00000 diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c index 4966a51af3d7..23ae451ba473 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c @@ -29,9 +29,54 @@ #include <nvif/class.h> -void -g84_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packet, - u8 rekey, u8 *avi, u8 avi_size, u8 *vendor, u8 vendor_size) +static void +g84_sor_hdmi_infoframe_vsi(struct nvkm_ior *ior, int head, void *data, u32 size) +{ + struct nvkm_device *device = ior->disp->engine.subdev.device; + struct packed_hdmi_infoframe vsi; + const u32 hoff = head * 0x800; + + nvkm_mask(device, 0x61653c + hoff, 0x00010001, 0x00010000); + if (!size) + return; + + pack_hdmi_infoframe(&vsi, data, size); + + nvkm_wr32(device, 0x616544 + hoff, vsi.header); + nvkm_wr32(device, 0x616548 + hoff, vsi.subpack0_low); + nvkm_wr32(device, 0x61654c + hoff, vsi.subpack0_high); + /* Is there a second (or up to fourth?) set of subpack registers here? */ + /* nvkm_wr32(device, 0x616550 + hoff, vsi.subpack1_low); */ + /* nvkm_wr32(device, 0x616554 + hoff, vsi.subpack1_high); */ + + nvkm_mask(device, 0x61653c + hoff, 0x00010001, 0x00010001); +} + +static void +g84_sor_hdmi_infoframe_avi(struct nvkm_ior *ior, int head, void *data, u32 size) +{ + struct nvkm_device *device = ior->disp->engine.subdev.device; + struct packed_hdmi_infoframe avi; + const u32 hoff = head * 0x800; + + pack_hdmi_infoframe(&avi, data, size); + + nvkm_mask(device, 0x616520 + hoff, 0x00000001, 0x00000000); + if (!size) + return; + + nvkm_wr32(device, 0x616528 + hoff, avi.header); + nvkm_wr32(device, 0x61652c + hoff, avi.subpack0_low); + nvkm_wr32(device, 0x616530 + hoff, avi.subpack0_high); + nvkm_wr32(device, 0x616534 + hoff, avi.subpack1_low); + nvkm_wr32(device, 0x616538 + hoff, avi.subpack1_high); + + nvkm_mask(device, 0x616520 + hoff, 0x00000001, 0x00000001); +} + + +static void +g84_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packet, u8 rekey) { struct nvkm_device *device = ior->disp->engine.subdev.device; const u32 ctrl = 0x40000000 * enable | @@ -39,31 +84,13 @@ g84_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packet, max_ac_packet << 16 | rekey; const u32 hoff = head * 0x800; - struct packed_hdmi_infoframe avi_infoframe; - struct packed_hdmi_infoframe vendor_infoframe; - - pack_hdmi_infoframe(&avi_infoframe, avi, avi_size); - pack_hdmi_infoframe(&vendor_infoframe, vendor, vendor_size); if (!(ctrl & 0x40000000)) { nvkm_mask(device, 0x6165a4 + hoff, 0x40000000, 0x00000000); - nvkm_mask(device, 0x61653c + hoff, 0x00000001, 0x00000000); - nvkm_mask(device, 0x616520 + hoff, 0x00000001, 0x00000000); nvkm_mask(device, 0x616500 + hoff, 0x00000001, 0x00000000); return; } - /* AVI InfoFrame */ - nvkm_mask(device, 0x616520 + hoff, 0x00000001, 0x00000000); - if (avi_size) { - nvkm_wr32(device, 0x616528 + hoff, avi_infoframe.header); - nvkm_wr32(device, 0x61652c + hoff, avi_infoframe.subpack0_low); - nvkm_wr32(device, 0x616530 + hoff, avi_infoframe.subpack0_high); - nvkm_wr32(device, 0x616534 + hoff, avi_infoframe.subpack1_low); - nvkm_wr32(device, 0x616538 + hoff, avi_infoframe.subpack1_high); - nvkm_mask(device, 0x616520 + hoff, 0x00000001, 0x00000001); - } - /* Audio InfoFrame */ nvkm_mask(device, 0x616500 + hoff, 0x00000001, 0x00000000); nvkm_wr32(device, 0x616508 + hoff, 0x000a0184); @@ -71,17 +98,6 @@ g84_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packet, nvkm_wr32(device, 0x616510 + hoff, 0x00000000); nvkm_mask(device, 0x616500 + hoff, 0x00000001, 0x00000001); - /* Vendor InfoFrame */ - nvkm_mask(device, 0x61653c + hoff, 0x00010001, 0x00010000); - if (vendor_size) { - nvkm_wr32(device, 0x616544 + hoff, vendor_infoframe.header); - nvkm_wr32(device, 0x616548 + hoff, vendor_infoframe.subpack0_low); - nvkm_wr32(device, 0x61654c + hoff, vendor_infoframe.subpack0_high); - /* Is there a second (or up to fourth?) set of subpack registers here? */ - /* nvkm_wr32(device, 0x616550 + hoff, vendor_infoframe->subpack1_low); */ - /* nvkm_wr32(device, 0x616554 + hoff, vendor_infoframe->subpack1_high); */ - nvkm_mask(device, 0x61653c + hoff, 0x00010001, 0x00010001); - } nvkm_mask(device, 0x6165d0 + hoff, 0x00070001, 0x00010001); /* SPARE, HW_CTS */ nvkm_mask(device, 0x616568 + hoff, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */ @@ -96,14 +112,19 @@ g84_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packet, nvkm_mask(device, 0x6165a4 + hoff, 0x5f1f007f, ctrl); } +const struct nvkm_ior_func_hdmi +g84_sor_hdmi = { + .ctrl = g84_sor_hdmi_ctrl, + .infoframe_avi = g84_sor_hdmi_infoframe_avi, + .infoframe_vsi = g84_sor_hdmi_infoframe_vsi, +}; + static const struct nvkm_ior_func g84_sor = { .state = nv50_sor_state, .power = nv50_sor_power, .clock = nv50_sor_clock, - .hdmi = { - .ctrl = g84_sor_hdmi_ctrl, - }, + .hdmi = &g84_sor_hdmi, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ga102.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ga102.c index 7489d0d7fce0..52099b75f52a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ga102.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ga102.c @@ -105,10 +105,7 @@ ga102_sor = { .state = gv100_sor_state, .power = nv50_sor_power, .clock = ga102_sor_clock, - .hdmi = { - .ctrl = gv100_sor_hdmi_ctrl, - .scdc = gm200_sor_hdmi_scdc, - }, + .hdmi = &gv100_sor_hdmi, .dp = &ga102_sor_dp, .hda = &gv100_sor_hda, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c index 39822f1b5b95..a48e9bdf4cd0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c @@ -202,19 +202,61 @@ gf119_sor_dp = { }; static void -gf119_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packet, - u8 rekey, u8 *avi, u8 avi_size, u8 *vendor, u8 vendor_size) +gf119_sor_hdmi_infoframe_vsi(struct nvkm_ior *ior, int head, void *data, u32 size) +{ + struct nvkm_device *device = ior->disp->engine.subdev.device; + struct packed_hdmi_infoframe vsi; + const u32 hoff = head * 0x800; + + pack_hdmi_infoframe(&vsi, data, size); + + nvkm_mask(device, 0x616730 + hoff, 0x00010001, 0x00010000); + if (!size) + return; + + /* + * These appear to be the audio infoframe registers, + * but no other set of infoframe registers has yet + * been found. + */ + nvkm_wr32(device, 0x616738 + hoff, vsi.header); + nvkm_wr32(device, 0x61673c + hoff, vsi.subpack0_low); + nvkm_wr32(device, 0x616740 + hoff, vsi.subpack0_high); + /* Is there a second (or further?) set of subpack registers here? */ + + nvkm_mask(device, 0x616730 + hoff, 0x00000001, 0x00000001); +} + +static void +gf119_sor_hdmi_infoframe_avi(struct nvkm_ior *ior, int head, void *data, u32 size) +{ + struct nvkm_device *device = ior->disp->engine.subdev.device; + struct packed_hdmi_infoframe avi; + const u32 hoff = head * 0x800; + + pack_hdmi_infoframe(&avi, data, size); + + nvkm_mask(device, 0x616714 + hoff, 0x00000001, 0x00000000); + if (!size) + return; + + nvkm_wr32(device, 0x61671c + hoff, avi.header); + nvkm_wr32(device, 0x616720 + hoff, avi.subpack0_low); + nvkm_wr32(device, 0x616724 + hoff, avi.subpack0_high); + nvkm_wr32(device, 0x616728 + hoff, avi.subpack1_low); + nvkm_wr32(device, 0x61672c + hoff, avi.subpack1_high); + + nvkm_mask(device, 0x616714 + hoff, 0x00000001, 0x00000001); +} + +static void +gf119_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packet, u8 rekey) { struct nvkm_device *device = ior->disp->engine.subdev.device; const u32 ctrl = 0x40000000 * enable | max_ac_packet << 16 | rekey; const u32 hoff = head * 0x800; - struct packed_hdmi_infoframe avi_infoframe; - struct packed_hdmi_infoframe vendor_infoframe; - - pack_hdmi_infoframe(&avi_infoframe, avi, avi_size); - pack_hdmi_infoframe(&vendor_infoframe, vendor, vendor_size); if (!(ctrl & 0x40000000)) { nvkm_mask(device, 0x616798 + hoff, 0x40000000, 0x00000000); @@ -224,32 +266,6 @@ gf119_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packe return; } - /* AVI InfoFrame */ - nvkm_mask(device, 0x616714 + hoff, 0x00000001, 0x00000000); - if (avi_size) { - nvkm_wr32(device, 0x61671c + hoff, avi_infoframe.header); - nvkm_wr32(device, 0x616720 + hoff, avi_infoframe.subpack0_low); - nvkm_wr32(device, 0x616724 + hoff, avi_infoframe.subpack0_high); - nvkm_wr32(device, 0x616728 + hoff, avi_infoframe.subpack1_low); - nvkm_wr32(device, 0x61672c + hoff, avi_infoframe.subpack1_high); - nvkm_mask(device, 0x616714 + hoff, 0x00000001, 0x00000001); - } - - /* GENERIC(?) / Vendor InfoFrame? */ - nvkm_mask(device, 0x616730 + hoff, 0x00010001, 0x00010000); - if (vendor_size) { - /* - * These appear to be the audio infoframe registers, - * but no other set of infoframe registers has yet - * been found. - */ - nvkm_wr32(device, 0x616738 + hoff, vendor_infoframe.header); - nvkm_wr32(device, 0x61673c + hoff, vendor_infoframe.subpack0_low); - nvkm_wr32(device, 0x616740 + hoff, vendor_infoframe.subpack0_high); - /* Is there a second (or further?) set of subpack registers here? */ - nvkm_mask(device, 0x616730 + hoff, 0x00000001, 0x00000001); - } - /* ??? InfoFrame? */ nvkm_mask(device, 0x6167a4 + hoff, 0x00000001, 0x00000000); nvkm_wr32(device, 0x6167ac + hoff, 0x00000010); @@ -259,6 +275,13 @@ gf119_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packe nvkm_mask(device, 0x616798 + hoff, 0x401f007f, ctrl); } +static const struct nvkm_ior_func_hdmi +gf119_sor_hdmi = { + .ctrl = gf119_sor_hdmi_ctrl, + .infoframe_avi = gf119_sor_hdmi_infoframe_avi, + .infoframe_vsi = gf119_sor_hdmi_infoframe_vsi, +}; + void gf119_sor_clock(struct nvkm_ior *sor) { @@ -305,9 +328,7 @@ gf119_sor = { .state = gf119_sor_state, .power = nv50_sor_power, .clock = gf119_sor_clock, - .hdmi = { - .ctrl = gf119_sor_hdmi_ctrl, - }, + .hdmi = &gf119_sor_hdmi, .dp = &gf119_sor_dp, .hda = &gf119_sor_hda, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c index 7248e9ec835e..876a21a0cebb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c @@ -30,8 +30,51 @@ #include <nvif/class.h> void -gk104_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packet, - u8 rekey, u8 *avi, u8 avi_size, u8 *vendor, u8 vendor_size) +gk104_sor_hdmi_infoframe_vsi(struct nvkm_ior *ior, int head, void *data, u32 size) +{ + struct nvkm_device *device = ior->disp->engine.subdev.device; + struct packed_hdmi_infoframe vsi; + const u32 hoff = head * 0x400; + + pack_hdmi_infoframe(&vsi, data, size); + + /* GENERIC(?) / Vendor InfoFrame? */ + nvkm_mask(device, 0x690100 + hoff, 0x00010001, 0x00000000); + if (!size) + return; + + nvkm_wr32(device, 0x690108 + hoff, vsi.header); + nvkm_wr32(device, 0x69010c + hoff, vsi.subpack0_low); + nvkm_wr32(device, 0x690110 + hoff, vsi.subpack0_high); + /* Is there a second (or further?) set of subpack registers here? */ + nvkm_mask(device, 0x690100 + hoff, 0x00000001, 0x00000001); +} + +void +gk104_sor_hdmi_infoframe_avi(struct nvkm_ior *ior, int head, void *data, u32 size) +{ + struct nvkm_device *device = ior->disp->engine.subdev.device; + struct packed_hdmi_infoframe avi; + const u32 hoff = head * 0x400; + + pack_hdmi_infoframe(&avi, data, size); + + /* AVI InfoFrame */ + nvkm_mask(device, 0x690000 + hoff, 0x00000001, 0x00000000); + if (!size) + return; + + nvkm_wr32(device, 0x690008 + hoff, avi.header); + nvkm_wr32(device, 0x69000c + hoff, avi.subpack0_low); + nvkm_wr32(device, 0x690010 + hoff, avi.subpack0_high); + nvkm_wr32(device, 0x690014 + hoff, avi.subpack1_low); + nvkm_wr32(device, 0x690018 + hoff, avi.subpack1_high); + + nvkm_mask(device, 0x690000 + hoff, 0x00000001, 0x00000001); +} + +void +gk104_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packet, u8 rekey) { struct nvkm_device *device = ior->disp->engine.subdev.device; const u32 ctrl = 0x40000000 * enable | @@ -39,11 +82,6 @@ gk104_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packe rekey; const u32 hoff = head * 0x800; const u32 hdmi = head * 0x400; - struct packed_hdmi_infoframe avi_infoframe; - struct packed_hdmi_infoframe vendor_infoframe; - - pack_hdmi_infoframe(&avi_infoframe, avi, avi_size); - pack_hdmi_infoframe(&vendor_infoframe, vendor, vendor_size); if (!(ctrl & 0x40000000)) { nvkm_mask(device, 0x616798 + hoff, 0x40000000, 0x00000000); @@ -53,28 +91,6 @@ gk104_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packe return; } - /* AVI InfoFrame */ - nvkm_mask(device, 0x690000 + hdmi, 0x00000001, 0x00000000); - if (avi_size) { - nvkm_wr32(device, 0x690008 + hdmi, avi_infoframe.header); - nvkm_wr32(device, 0x69000c + hdmi, avi_infoframe.subpack0_low); - nvkm_wr32(device, 0x690010 + hdmi, avi_infoframe.subpack0_high); - nvkm_wr32(device, 0x690014 + hdmi, avi_infoframe.subpack1_low); - nvkm_wr32(device, 0x690018 + hdmi, avi_infoframe.subpack1_high); - nvkm_mask(device, 0x690000 + hdmi, 0x00000001, 0x00000001); - } - - /* GENERIC(?) / Vendor InfoFrame? */ - nvkm_mask(device, 0x690100 + hdmi, 0x00010001, 0x00000000); - if (vendor_size) { - nvkm_wr32(device, 0x690108 + hdmi, vendor_infoframe.header); - nvkm_wr32(device, 0x69010c + hdmi, vendor_infoframe.subpack0_low); - nvkm_wr32(device, 0x690110 + hdmi, vendor_infoframe.subpack0_high); - /* Is there a second (or further?) set of subpack registers here? */ - nvkm_mask(device, 0x690100 + hdmi, 0x00000001, 0x00000001); - } - - /* ??? InfoFrame? */ nvkm_mask(device, 0x6900c0 + hdmi, 0x00000001, 0x00000000); nvkm_wr32(device, 0x6900cc + hdmi, 0x00000010); @@ -87,14 +103,19 @@ gk104_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packe nvkm_mask(device, 0x616798 + hoff, 0x401f007f, ctrl); } +const struct nvkm_ior_func_hdmi +gk104_sor_hdmi = { + .ctrl = gk104_sor_hdmi_ctrl, + .infoframe_avi = gk104_sor_hdmi_infoframe_avi, + .infoframe_vsi = gk104_sor_hdmi_infoframe_vsi, +}; + static const struct nvkm_ior_func gk104_sor = { .state = gf119_sor_state, .power = nv50_sor_power, .clock = gf119_sor_clock, - .hdmi = { - .ctrl = gk104_sor_hdmi_ctrl, - }, + .hdmi = &gk104_sor_hdmi, .dp = &gf119_sor_dp, .hda = &gf119_sor_hda, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c index 9e9ef49bd8ac..b4d8e868616f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c @@ -70,9 +70,7 @@ gm107_sor = { .state = gf119_sor_state, .power = nv50_sor_power, .clock = gf119_sor_clock, - .hdmi = { - .ctrl = gk104_sor_hdmi_ctrl, - }, + .hdmi = &gk104_sor_hdmi, .dp = &gm107_sor_dp, .hda = &gf119_sor_hda, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c index 4ecc8f98af6e..562ebae57d44 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c @@ -79,6 +79,14 @@ gm200_sor_hdmi_scdc(struct nvkm_ior *ior, u8 scdc) ior->tmds.high_speed = !!(scdc & 0x2); } +const struct nvkm_ior_func_hdmi +gm200_sor_hdmi = { + .ctrl = gk104_sor_hdmi_ctrl, + .scdc = gm200_sor_hdmi_scdc, + .infoframe_avi = gk104_sor_hdmi_infoframe_avi, + .infoframe_vsi = gk104_sor_hdmi_infoframe_vsi, +}; + void gm200_sor_route_set(struct nvkm_outp *outp, struct nvkm_ior *ior) { @@ -131,10 +139,7 @@ gm200_sor = { .state = gf119_sor_state, .power = nv50_sor_power, .clock = gf119_sor_clock, - .hdmi = { - .ctrl = gk104_sor_hdmi_ctrl, - .scdc = gm200_sor_hdmi_scdc, - }, + .hdmi = &gm200_sor_hdmi, .dp = &gm200_sor_dp, .hda = &gf119_sor_hda, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c index 7172a9dfd89b..7f1eb4332040 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c @@ -37,10 +37,7 @@ gp100_sor = { .state = gf119_sor_state, .power = nv50_sor_power, .clock = gf119_sor_clock, - .hdmi = { - .ctrl = gk104_sor_hdmi_ctrl, - .scdc = gm200_sor_hdmi_scdc, - }, + .hdmi = &gm200_sor_hdmi, .dp = &gm200_sor_dp, .hda = &gf119_sor_hda, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c index 70c49e7af9cf..a2c7c6f83dcd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c @@ -92,9 +92,53 @@ gt215_sor_dp = { .watermark = g94_sor_dp_watermark, }; -void -gt215_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packet, - u8 rekey, u8 *avi, u8 avi_size, u8 *vendor, u8 vendor_size) +static void +gt215_sor_hdmi_infoframe_vsi(struct nvkm_ior *ior, int head, void *data, u32 size) +{ + struct nvkm_device *device = ior->disp->engine.subdev.device; + struct packed_hdmi_infoframe vsi; + const u32 soff = nv50_ior_base(ior); + + pack_hdmi_infoframe(&vsi, data, size); + + nvkm_mask(device, 0x61c53c + soff, 0x00010001, 0x00010000); + if (!size) + return; + + nvkm_wr32(device, 0x61c544 + soff, vsi.header); + nvkm_wr32(device, 0x61c548 + soff, vsi.subpack0_low); + nvkm_wr32(device, 0x61c54c + soff, vsi.subpack0_high); + /* Is there a second (or up to fourth?) set of subpack registers here? */ + /* nvkm_wr32(device, 0x61c550 + soff, vsi.subpack1_low); */ + /* nvkm_wr32(device, 0x61c554 + soff, vsi.subpack1_high); */ + + nvkm_mask(device, 0x61c53c + soff, 0x00010001, 0x00010001); +} + +static void +gt215_sor_hdmi_infoframe_avi(struct nvkm_ior *ior, int head, void *data, u32 size) +{ + struct nvkm_device *device = ior->disp->engine.subdev.device; + struct packed_hdmi_infoframe avi; + const u32 soff = nv50_ior_base(ior); + + pack_hdmi_infoframe(&avi, data, size); + + nvkm_mask(device, 0x61c520 + soff, 0x00000001, 0x00000000); + if (size) + return; + + nvkm_wr32(device, 0x61c528 + soff, avi.header); + nvkm_wr32(device, 0x61c52c + soff, avi.subpack0_low); + nvkm_wr32(device, 0x61c530 + soff, avi.subpack0_high); + nvkm_wr32(device, 0x61c534 + soff, avi.subpack1_low); + nvkm_wr32(device, 0x61c538 + soff, avi.subpack1_high); + + nvkm_mask(device, 0x61c520 + soff, 0x00000001, 0x00000001); +} + +static void +gt215_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packet, u8 rekey) { struct nvkm_device *device = ior->disp->engine.subdev.device; const u32 ctrl = 0x40000000 * enable | @@ -102,11 +146,6 @@ gt215_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packe max_ac_packet << 16 | rekey; const u32 soff = nv50_ior_base(ior); - struct packed_hdmi_infoframe avi_infoframe; - struct packed_hdmi_infoframe vendor_infoframe; - - pack_hdmi_infoframe(&avi_infoframe, avi, avi_size); - pack_hdmi_infoframe(&vendor_infoframe, vendor, vendor_size); if (!(ctrl & 0x40000000)) { nvkm_mask(device, 0x61c5a4 + soff, 0x40000000, 0x00000000); @@ -116,17 +155,6 @@ gt215_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packe return; } - /* AVI InfoFrame */ - nvkm_mask(device, 0x61c520 + soff, 0x00000001, 0x00000000); - if (avi_size) { - nvkm_wr32(device, 0x61c528 + soff, avi_infoframe.header); - nvkm_wr32(device, 0x61c52c + soff, avi_infoframe.subpack0_low); - nvkm_wr32(device, 0x61c530 + soff, avi_infoframe.subpack0_high); - nvkm_wr32(device, 0x61c534 + soff, avi_infoframe.subpack1_low); - nvkm_wr32(device, 0x61c538 + soff, avi_infoframe.subpack1_high); - nvkm_mask(device, 0x61c520 + soff, 0x00000001, 0x00000001); - } - /* Audio InfoFrame */ nvkm_mask(device, 0x61c500 + soff, 0x00000001, 0x00000000); nvkm_wr32(device, 0x61c508 + soff, 0x000a0184); @@ -134,18 +162,6 @@ gt215_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packe nvkm_wr32(device, 0x61c510 + soff, 0x00000000); nvkm_mask(device, 0x61c500 + soff, 0x00000001, 0x00000001); - /* Vendor InfoFrame */ - nvkm_mask(device, 0x61c53c + soff, 0x00010001, 0x00010000); - if (vendor_size) { - nvkm_wr32(device, 0x61c544 + soff, vendor_infoframe.header); - nvkm_wr32(device, 0x61c548 + soff, vendor_infoframe.subpack0_low); - nvkm_wr32(device, 0x61c54c + soff, vendor_infoframe.subpack0_high); - /* Is there a second (or up to fourth?) set of subpack registers here? */ - /* nvkm_wr32(device, 0x61c550 + soff, vendor_infoframe.subpack1_low); */ - /* nvkm_wr32(device, 0x61c554 + soff, vendor_infoframe.subpack1_high); */ - nvkm_mask(device, 0x61c53c + soff, 0x00010001, 0x00010001); - } - nvkm_mask(device, 0x61c5d0 + soff, 0x00070001, 0x00010001); /* SPARE, HW_CTS */ nvkm_mask(device, 0x61c568 + soff, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */ nvkm_mask(device, 0x61c578 + soff, 0x80000000, 0x80000000); /* ACR_0441_ENABLE */ @@ -159,14 +175,19 @@ gt215_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packe nvkm_mask(device, 0x61c5a4 + soff, 0x5f1f007f, ctrl); } +const struct nvkm_ior_func_hdmi +gt215_sor_hdmi = { + .ctrl = gt215_sor_hdmi_ctrl, + .infoframe_avi = gt215_sor_hdmi_infoframe_avi, + .infoframe_vsi = gt215_sor_hdmi_infoframe_vsi, +}; + static const struct nvkm_ior_func gt215_sor = { .state = g94_sor_state, .power = nv50_sor_power, .clock = nv50_sor_clock, - .hdmi = { - .ctrl = gt215_sor_hdmi_ctrl, - }, + .hdmi = >215_sor_hdmi, .dp = >215_sor_dp, .hda = >215_sor_hda, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c index 6b9d49270fa7..115d0997fd62 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c @@ -96,9 +96,54 @@ gv100_sor_dp = { .watermark = gv100_sor_dp_watermark, }; -void -gv100_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packet, - u8 rekey, u8 *avi, u8 avi_size, u8 *vendor, u8 vendor_size) +static void +gv100_sor_hdmi_infoframe_vsi(struct nvkm_ior *ior, int head, void *data, u32 size) +{ + struct nvkm_device *device = ior->disp->engine.subdev.device; + struct packed_hdmi_infoframe vsi; + const u32 hoff = head * 0x400; + + pack_hdmi_infoframe(&vsi, data, size); + + nvkm_mask(device, 0x6f0100 + hoff, 0x00010001, 0x00000000); + if (!size) + return; + + nvkm_wr32(device, 0x6f0108 + hoff, vsi.header); + nvkm_wr32(device, 0x6f010c + hoff, vsi.subpack0_low); + nvkm_wr32(device, 0x6f0110 + hoff, vsi.subpack0_high); + nvkm_wr32(device, 0x6f0114 + hoff, 0x00000000); + nvkm_wr32(device, 0x6f0118 + hoff, 0x00000000); + nvkm_wr32(device, 0x6f011c + hoff, 0x00000000); + nvkm_wr32(device, 0x6f0120 + hoff, 0x00000000); + nvkm_wr32(device, 0x6f0124 + hoff, 0x00000000); + nvkm_mask(device, 0x6f0100 + hoff, 0x00000001, 0x00000001); +} + +static void +gv100_sor_hdmi_infoframe_avi(struct nvkm_ior *ior, int head, void *data, u32 size) +{ + struct nvkm_device *device = ior->disp->engine.subdev.device; + struct packed_hdmi_infoframe avi; + const u32 hoff = head * 0x400; + + pack_hdmi_infoframe(&avi, data, size); + + nvkm_mask(device, 0x6f0000 + hoff, 0x00000001, 0x00000000); + if (!size) + return; + + nvkm_wr32(device, 0x6f0008 + hoff, avi.header); + nvkm_wr32(device, 0x6f000c + hoff, avi.subpack0_low); + nvkm_wr32(device, 0x6f0010 + hoff, avi.subpack0_high); + nvkm_wr32(device, 0x6f0014 + hoff, avi.subpack1_low); + nvkm_wr32(device, 0x6f0018 + hoff, avi.subpack1_high); + + nvkm_mask(device, 0x6f0000 + hoff, 0x00000001, 0x00000001); +} + +static void +gv100_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packet, u8 rekey) { struct nvkm_device *device = ior->disp->engine.subdev.device; const u32 ctrl = 0x40000000 * enable | @@ -106,11 +151,6 @@ gv100_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packe rekey; const u32 hoff = head * 0x800; const u32 hdmi = head * 0x400; - struct packed_hdmi_infoframe avi_infoframe; - struct packed_hdmi_infoframe vendor_infoframe; - - pack_hdmi_infoframe(&avi_infoframe, avi, avi_size); - pack_hdmi_infoframe(&vendor_infoframe, vendor, vendor_size); if (!(ctrl & 0x40000000)) { nvkm_mask(device, 0x6165c0 + hoff, 0x40000000, 0x00000000); @@ -120,32 +160,6 @@ gv100_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packe return; } - /* AVI InfoFrame (AVI). */ - nvkm_mask(device, 0x6f0000 + hdmi, 0x00000001, 0x00000000); - if (avi_size) { - nvkm_wr32(device, 0x6f0008 + hdmi, avi_infoframe.header); - nvkm_wr32(device, 0x6f000c + hdmi, avi_infoframe.subpack0_low); - nvkm_wr32(device, 0x6f0010 + hdmi, avi_infoframe.subpack0_high); - nvkm_wr32(device, 0x6f0014 + hdmi, avi_infoframe.subpack1_low); - nvkm_wr32(device, 0x6f0018 + hdmi, avi_infoframe.subpack1_high); - nvkm_mask(device, 0x6f0000 + hdmi, 0x00000001, 0x00000001); - } - - /* Vendor-specific InfoFrame (VSI). */ - nvkm_mask(device, 0x6f0100 + hdmi, 0x00010001, 0x00000000); - if (vendor_size) { - nvkm_wr32(device, 0x6f0108 + hdmi, vendor_infoframe.header); - nvkm_wr32(device, 0x6f010c + hdmi, vendor_infoframe.subpack0_low); - nvkm_wr32(device, 0x6f0110 + hdmi, vendor_infoframe.subpack0_high); - nvkm_wr32(device, 0x6f0114 + hdmi, 0x00000000); - nvkm_wr32(device, 0x6f0118 + hdmi, 0x00000000); - nvkm_wr32(device, 0x6f011c + hdmi, 0x00000000); - nvkm_wr32(device, 0x6f0120 + hdmi, 0x00000000); - nvkm_wr32(device, 0x6f0124 + hdmi, 0x00000000); - nvkm_mask(device, 0x6f0100 + hdmi, 0x00000001, 0x00000001); - } - - /* General Control (GCP). */ nvkm_mask(device, 0x6f00c0 + hdmi, 0x00000001, 0x00000000); nvkm_wr32(device, 0x6f00cc + hdmi, 0x00000010); @@ -158,6 +172,14 @@ gv100_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packe nvkm_mask(device, 0x6165c0 + hoff, 0x401f007f, ctrl); } +const struct nvkm_ior_func_hdmi +gv100_sor_hdmi = { + .ctrl = gv100_sor_hdmi_ctrl, + .scdc = gm200_sor_hdmi_scdc, + .infoframe_avi = gv100_sor_hdmi_infoframe_avi, + .infoframe_vsi = gv100_sor_hdmi_infoframe_vsi, +}; + void gv100_sor_state(struct nvkm_ior *sor, struct nvkm_ior_state *state) { @@ -190,10 +212,7 @@ gv100_sor = { .state = gv100_sor_state, .power = nv50_sor_power, .clock = gf119_sor_clock, - .hdmi = { - .ctrl = gv100_sor_hdmi_ctrl, - .scdc = gm200_sor_hdmi_scdc, - }, + .hdmi = &gv100_sor_hdmi, .dp = &gv100_sor_dp, .hda = &gv100_sor_hda, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.c index 83152c26fe3e..7f5d13d13c94 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.c @@ -39,44 +39,6 @@ nvkm_head_find(struct nvkm_disp *disp, int id) return NULL; } -int -nvkm_head_mthd_scanoutpos(struct nvkm_object *object, - struct nvkm_head *head, void *data, u32 size) -{ - union { - struct nv04_disp_scanoutpos_v0 v0; - } *args = data; - int ret = -ENOSYS; - - nvif_ioctl(object, "head scanoutpos size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { - nvif_ioctl(object, "head scanoutpos vers %d\n", - args->v0.version); - - head->func->state(head, &head->arm); - args->v0.vtotal = head->arm.vtotal; - args->v0.vblanks = head->arm.vblanks; - args->v0.vblanke = head->arm.vblanke; - args->v0.htotal = head->arm.htotal; - args->v0.hblanks = head->arm.hblanks; - args->v0.hblanke = head->arm.hblanke; - - /* We don't support reading htotal/vtotal on pre-NV50 VGA, - * so we have to give up and trigger the timestamping - * fallback in the drm core. - */ - if (!args->v0.vtotal || !args->v0.htotal) - return -ENOTSUPP; - - args->v0.time[0] = ktime_to_ns(ktime_get()); - head->func->rgpos(head, &args->v0.hline, &args->v0.vline); - args->v0.time[1] = ktime_to_ns(ktime_get()); - } else - return ret; - - return 0; -} - void nvkm_head_del(struct nvkm_head **phead) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h index 84a2989193cf..856252bf559a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: MIT */ #ifndef __NVKM_DISP_HEAD_H__ #define __NVKM_DISP_HEAD_H__ +#include <nvif/object.h> #include "priv.h" struct nvkm_head { @@ -26,12 +27,12 @@ struct nvkm_head { u8 depth; } or; } arm, asy; + + struct nvkm_object object; }; int nvkm_head_new_(const struct nvkm_head_func *, struct nvkm_disp *, int id); void nvkm_head_del(struct nvkm_head **); -int nvkm_head_mthd_scanoutpos(struct nvkm_object *, - struct nvkm_head *, void *, u32); struct nvkm_head *nvkm_head_find(struct nvkm_disp *, int id); struct nvkm_head_func { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h index 671c4674ffcc..da1b1a626ef2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h @@ -63,12 +63,12 @@ struct nvkm_ior_func { void (*war_2)(struct nvkm_ior *); void (*war_3)(struct nvkm_ior *); - struct { - void (*ctrl)(struct nvkm_ior *, int head, bool enable, - u8 max_ac_packet, u8 rekey, u8 *avi, u8 avi_size, - u8 *vendor, u8 vendor_size); + const struct nvkm_ior_func_hdmi { + void (*ctrl)(struct nvkm_ior *, int head, bool enable, u8 max_ac_packet, u8 rekey); void (*scdc)(struct nvkm_ior *, u8 scdc); - } hdmi; + void (*infoframe_avi)(struct nvkm_ior *, int head, void *data, u32 size); + void (*infoframe_vsi)(struct nvkm_ior *, int head, void *data, u32 size); + } *hdmi; const struct nvkm_ior_func_dp { u8 lanes[4]; @@ -124,9 +124,10 @@ void nv50_sor_power(struct nvkm_ior *, bool, bool, bool, bool, bool); void nv50_sor_clock(struct nvkm_ior *); int g84_sor_new(struct nvkm_disp *, int); -void g84_sor_hdmi_ctrl(struct nvkm_ior *, int, bool, u8, u8, u8 *, u8 , u8 *, u8); +extern const struct nvkm_ior_func_hdmi g84_sor_hdmi; int g94_sor_cnt(struct nvkm_disp *, unsigned long *); + void g94_sor_state(struct nvkm_ior *, struct nvkm_ior_state *); extern const struct nvkm_ior_func_dp g94_sor_dp; int g94_sor_dp_links(struct nvkm_ior *, struct nvkm_i2c_aux *); @@ -137,7 +138,7 @@ void g94_sor_dp_audio_sym(struct nvkm_ior *, int, u16, u32); void g94_sor_dp_activesym(struct nvkm_ior *, int, u8, u8, u8, u8); void g94_sor_dp_watermark(struct nvkm_ior *, int, u8); -void gt215_sor_hdmi_ctrl(struct nvkm_ior *, int, bool, u8, u8, u8 *, u8 , u8 *, u8); +extern const struct nvkm_ior_func_hdmi gt215_sor_hdmi; void gt215_sor_dp_audio(struct nvkm_ior *, int, bool); extern const struct nvkm_ior_func_hda gt215_sor_hda; @@ -156,12 +157,16 @@ void gf119_sor_hda_hpd(struct nvkm_ior *, int, bool); void gf119_sor_hda_eld(struct nvkm_ior *, int, u8 *, u8); int gk104_sor_new(struct nvkm_disp *, int); -void gk104_sor_hdmi_ctrl(struct nvkm_ior *, int, bool, u8, u8, u8 *, u8 , u8 *, u8); +extern const struct nvkm_ior_func_hdmi gk104_sor_hdmi; +void gk104_sor_hdmi_ctrl(struct nvkm_ior *, int, bool, u8, u8); +void gk104_sor_hdmi_infoframe_avi(struct nvkm_ior *, int, void *, u32); +void gk104_sor_hdmi_infoframe_vsi(struct nvkm_ior *, int, void *, u32); void gm107_sor_dp_pattern(struct nvkm_ior *, int); void gm200_sor_route_set(struct nvkm_outp *, struct nvkm_ior *); int gm200_sor_route_get(struct nvkm_outp *, int *); +extern const struct nvkm_ior_func_hdmi gm200_sor_hdmi; void gm200_sor_hdmi_scdc(struct nvkm_ior *, u8); extern const struct nvkm_ior_func_dp gm200_sor_dp; void gm200_sor_dp_drive(struct nvkm_ior *, int, int, int, int, int); @@ -170,7 +175,7 @@ int gp100_sor_new(struct nvkm_disp *, int); int gv100_sor_cnt(struct nvkm_disp *, unsigned long *); void gv100_sor_state(struct nvkm_ior *, struct nvkm_ior_state *); -void gv100_sor_hdmi_ctrl(struct nvkm_ior *, int, bool, u8, u8, u8 *, u8 , u8 *, u8); +extern const struct nvkm_ior_func_hdmi gv100_sor_hdmi; void gv100_sor_dp_audio(struct nvkm_ior *, int, bool); void gv100_sor_dp_audio_sym(struct nvkm_ior *, int, u16, u32); void gv100_sor_dp_watermark(struct nvkm_ior *, int, u8); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp77.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp77.c index 916b1d477b0b..841e3b69fcaf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp77.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp77.c @@ -31,9 +31,7 @@ mcp77_sor = { .state = g94_sor_state, .power = nv50_sor_power, .clock = nv50_sor_clock, - .hdmi = { - .ctrl = g84_sor_hdmi_ctrl, - }, + .hdmi = &g84_sor_hdmi, .dp = &g94_sor_dp, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c index a5a0b9439374..f96ba4752655 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c @@ -44,9 +44,7 @@ mcp89_sor = { .state = g94_sor_state, .power = nv50_sor_power, .clock = nv50_sor_clock, - .hdmi = { - .ctrl = gt215_sor_hdmi_ctrl, - }, + .hdmi = >215_sor_hdmi, .dp = &mcp89_sor_dp, .hda = >215_sor_hda, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index a46e13cc9ff1..be8116802960 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -503,7 +503,7 @@ nv50_disp_chan_uevent_init(struct nvkm_event *event, int types, int index) void nv50_disp_chan_uevent_send(struct nvkm_disp *disp, int chid) { - nvkm_event_send(&disp->uevent, NVKM_DISP_EVENT_CHAN_AWAKEN, chid, NULL, 0); + nvkm_event_ntfy(&disp->uevent, chid, NVKM_DISP_EVENT_CHAN_AWAKEN); } const struct nvkm_event_func @@ -1238,6 +1238,8 @@ nv50_disp_super_2_2(struct nvkm_disp *disp, struct nvkm_head *head) if (!ior) return; + outp = ior->asy.outp; + /* For some reason, NVIDIA decided not to: * * A) Give dual-link LVDS a separate EVO protocol, like for TMDS. @@ -1247,13 +1249,13 @@ nv50_disp_super_2_2(struct nvkm_disp *disp, struct nvkm_head *head) * Override the values we usually read from HW with the same * data we pass though an ioctl instead. */ - if (ior->type == SOR && ior->asy.proto == LVDS) { - head->asy.or.depth = (disp->sor.lvdsconf & 0x0200) ? 24 : 18; - ior->asy.link = (disp->sor.lvdsconf & 0x0100) ? 3 : 1; + if (outp && ior->type == SOR && ior->asy.proto == LVDS) { + head->asy.or.depth = outp->lvds.bpc8 ? 24 : 18; + ior->asy.link = outp->lvds.dual ? 3 : 1; } /* Handle any link training, etc. */ - if ((outp = ior->asy.outp) && outp->func->acquire) + if (outp && outp->func->acquire) outp->func->acquire(outp); /* Execute OnInt2 IED script. */ diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h index 3f3924c41957..b7631c1ab242 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h @@ -2,7 +2,6 @@ #ifndef __NVKM_DISP_OUTP_H__ #define __NVKM_DISP_OUTP_H__ #include "priv.h" -#include <core/notify.h> #include <subdev/bios.h> #include <subdev/bios/dcb.h> @@ -28,13 +27,19 @@ struct nvkm_outp { union { struct { + bool dual; + bool bpc8; + } lvds; + + struct { struct nvbios_dpout info; u8 version; struct nvkm_i2c_aux *aux; - struct nvkm_notify hpd; - bool present; + bool enabled; + bool aux_pwr; + bool aux_pwr_pu; u8 lttpr[6]; u8 lttprs; u8 dpcd[16]; @@ -49,12 +54,17 @@ struct nvkm_outp { struct mutex mutex; struct { atomic_t done; + u8 nr; + u8 bw; bool mst; } lt; } dp; }; struct nvkm_object object; + struct { + struct nvkm_head *head; + } asy; }; int nvkm_outp_new_(const struct nvkm_outp_func *, struct nvkm_disp *, int index, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h index cb25dfe849f0..ec5292a8f3c8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h @@ -42,10 +42,6 @@ struct nvkm_disp_func { } user[]; }; -int nvkm_disp_ntfy(struct nvkm_object *, u32, struct nvkm_event **); -int nv04_disp_mthd(struct nvkm_object *, u32, void *, u32); -int nv50_disp_root_mthd_(struct nvkm_object *, u32, void *, u32); - int nv50_disp_oneinit(struct nvkm_disp *); int nv50_disp_init(struct nvkm_disp *); void nv50_disp_fini(struct nvkm_disp *); @@ -86,4 +82,5 @@ extern const struct nvkm_event_func gv100_disp_chan_uevent; int nvkm_udisp_new(const struct nvkm_oclass *, void *, u32, struct nvkm_object **); int nvkm_uconn_new(const struct nvkm_oclass *, void *, u32, struct nvkm_object **); int nvkm_uoutp_new(const struct nvkm_oclass *, void *, u32, struct nvkm_object **); +int nvkm_uhead_new(const struct nvkm_oclass *, void *, u32, struct nvkm_object **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c deleted file mode 100644 index 0af45ccd140c..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright 2012 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. - * - * Authors: Ben Skeggs - */ -#include "chan.h" -#include "head.h" -#include "ior.h" -#include "outp.h" - -#include <core/client.h> - -#include <nvif/class.h> -#include <nvif/cl5070.h> -#include <nvif/unpack.h> - -int -nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size) -{ - union { - struct nv50_disp_mthd_v0 v0; - struct nv50_disp_mthd_v1 v1; - } *args = data; - struct nvkm_disp *disp = nvkm_udisp(object); - struct nvkm_outp *temp, *outp = NULL; - struct nvkm_head *head; - u16 type, mask = 0; - int hidx, ret = -ENOSYS; - - if (mthd != NV50_DISP_MTHD) - return -EINVAL; - - nvif_ioctl(object, "disp mthd size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) { - nvif_ioctl(object, "disp mthd vers %d mthd %02x head %d\n", - args->v0.version, args->v0.method, args->v0.head); - mthd = args->v0.method; - hidx = args->v0.head; - } else - if (!(ret = nvif_unpack(ret, &data, &size, args->v1, 1, 1, true))) { - nvif_ioctl(object, "disp mthd vers %d mthd %02x " - "type %04x mask %04x\n", - args->v1.version, args->v1.method, - args->v1.hasht, args->v1.hashm); - mthd = args->v1.method; - type = args->v1.hasht; - mask = args->v1.hashm; - hidx = ffs((mask >> 8) & 0x0f) - 1; - } else - return ret; - - if (!(head = nvkm_head_find(disp, hidx))) - return -ENXIO; - - if (mask) { - list_for_each_entry(temp, &disp->outps, head) { - if ((temp->info.hasht == type) && - (temp->info.hashm & mask) == mask) { - outp = temp; - break; - } - } - if (outp == NULL) - return -ENXIO; - } - - switch (mthd) { - case NV50_DISP_SCANOUTPOS: { - return nvkm_head_mthd_scanoutpos(object, head, data, size); - } - default: - break; - } - - switch (mthd * !!outp) { - case NV50_DISP_MTHD_V1_ACQUIRE: { - union { - struct nv50_disp_acquire_v0 v0; - } *args = data; - int ret = -ENOSYS; - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { - ret = nvkm_outp_acquire(outp, NVKM_OUTP_USER, args->v0.hda); - if (ret == 0) { - args->v0.or = outp->ior->id; - args->v0.link = outp->ior->asy.link; - } - } - return ret; - } - break; - case NV50_DISP_MTHD_V1_RELEASE: - nvkm_outp_release(outp, NVKM_OUTP_USER); - return 0; - case NV50_DISP_MTHD_V1_SOR_HDA_ELD: { - union { - struct nv50_disp_sor_hda_eld_v0 v0; - } *args = data; - struct nvkm_ior *ior = outp->ior; - int ret = -ENOSYS; - - nvif_ioctl(object, "disp sor hda eld size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) { - nvif_ioctl(object, "disp sor hda eld vers %d\n", - args->v0.version); - if (size > 0x60) - return -E2BIG; - } else - return ret; - - if (!ior->hda) - return -ENODEV; - - if (size && args->v0.data[0]) { - if (outp->info.type == DCB_OUTPUT_DP) - ior->func->dp->audio(ior, hidx, true); - ior->func->hda->hpd(ior, hidx, true); - ior->func->hda->eld(ior, hidx, data, size); - } else { - if (outp->info.type == DCB_OUTPUT_DP) - ior->func->dp->audio(ior, hidx, false); - ior->func->hda->hpd(ior, hidx, false); - } - - return 0; - } - break; - case NV50_DISP_MTHD_V1_SOR_HDMI_PWR: { - union { - struct nv50_disp_sor_hdmi_pwr_v0 v0; - } *args = data; - u8 *vendor, vendor_size; - u8 *avi, avi_size; - int ret = -ENOSYS; - - nvif_ioctl(object, "disp sor hdmi ctrl size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) { - nvif_ioctl(object, "disp sor hdmi ctrl vers %d state %d " - "max_ac_packet %d rekey %d scdc %d\n", - args->v0.version, args->v0.state, - args->v0.max_ac_packet, args->v0.rekey, - args->v0.scdc); - if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f) - return -EINVAL; - if ((args->v0.avi_infoframe_length - + args->v0.vendor_infoframe_length) > size) - return -EINVAL; - else - if ((args->v0.avi_infoframe_length - + args->v0.vendor_infoframe_length) < size) - return -E2BIG; - avi = data; - avi_size = args->v0.avi_infoframe_length; - vendor = avi + avi_size; - vendor_size = args->v0.vendor_infoframe_length; - } else - return ret; - - if (!outp->ior->func->hdmi.ctrl) - return -ENODEV; - - outp->ior->func->hdmi.ctrl(outp->ior, hidx, args->v0.state, - args->v0.max_ac_packet, - args->v0.rekey, avi, avi_size, - vendor, vendor_size); - - if (outp->ior->func->hdmi.scdc) - outp->ior->func->hdmi.scdc(outp->ior, args->v0.scdc); - - return 0; - } - break; - case NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT: { - union { - struct nv50_disp_sor_lvds_script_v0 v0; - } *args = data; - int ret = -ENOSYS; - nvif_ioctl(object, "disp sor lvds script size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { - nvif_ioctl(object, "disp sor lvds script " - "vers %d name %04x\n", - args->v0.version, args->v0.script); - disp->sor.lvdsconf = args->v0.script; - return 0; - } else - return ret; - } - break; - case NV50_DISP_MTHD_V1_SOR_DP_MST_LINK: { - union { - struct nv50_disp_sor_dp_mst_link_v0 v0; - } *args = data; - int ret = -ENOSYS; - nvif_ioctl(object, "disp sor dp mst link size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { - nvif_ioctl(object, "disp sor dp mst link vers %d state %d\n", - args->v0.version, args->v0.state); - outp->dp.lt.mst = !!args->v0.state; - return 0; - } else - return ret; - } - break; - case NV50_DISP_MTHD_V1_SOR_DP_MST_VCPI: { - union { - struct nv50_disp_sor_dp_mst_vcpi_v0 v0; - } *args = data; - int ret = -ENOSYS; - nvif_ioctl(object, "disp sor dp mst vcpi size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { - nvif_ioctl(object, "disp sor dp mst vcpi vers %d " - "slot %02x/%02x pbn %04x/%04x\n", - args->v0.version, args->v0.start_slot, - args->v0.num_slots, args->v0.pbn, - args->v0.aligned_pbn); - if (!outp->ior->func->dp->vcpi) - return -ENODEV; - outp->ior->func->dp->vcpi(outp->ior, hidx, - args->v0.start_slot, - args->v0.num_slots, - args->v0.pbn, - args->v0.aligned_pbn); - return 0; - } else - return ret; - } - break; - default: - break; - } - - return -EINVAL; -} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/tu102.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/tu102.c index e4ad1a6f6c88..f5242a672279 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/tu102.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/tu102.c @@ -88,10 +88,7 @@ tu102_sor = { .state = gv100_sor_state, .power = nv50_sor_power, .clock = gf119_sor_clock, - .hdmi = { - .ctrl = gv100_sor_hdmi_ctrl, - .scdc = gm200_sor_hdmi_scdc, - }, + .hdmi = &gv100_sor_hdmi, .dp = &tu102_sor_dp, .hda = &gv100_sor_hda, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c index fd9f18144c26..dad942be6679 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c @@ -21,12 +21,86 @@ */ #define nvkm_uconn(p) container_of((p), struct nvkm_conn, object) #include "conn.h" +#include "outp.h" +#include <core/client.h> +#include <core/event.h> #include <subdev/gpio.h> +#include <subdev/i2c.h> #include <nvif/if0011.h> static int +nvkm_uconn_uevent_aux(struct nvkm_object *object, u64 token, u32 bits) +{ + union nvif_conn_event_args args; + + args.v0.version = 0; + args.v0.types = 0; + if (bits & NVKM_I2C_PLUG) + args.v0.types |= NVIF_CONN_EVENT_V0_PLUG; + if (bits & NVKM_I2C_UNPLUG) + args.v0.types |= NVIF_CONN_EVENT_V0_UNPLUG; + if (bits & NVKM_I2C_IRQ) + args.v0.types |= NVIF_CONN_EVENT_V0_IRQ; + + return object->client->event(token, &args, sizeof(args.v0)); +} + +static int +nvkm_uconn_uevent_gpio(struct nvkm_object *object, u64 token, u32 bits) +{ + union nvif_conn_event_args args; + + args.v0.version = 0; + args.v0.types = 0; + if (bits & NVKM_GPIO_HI) + args.v0.types |= NVIF_CONN_EVENT_V0_PLUG; + if (bits & NVKM_GPIO_LO) + args.v0.types |= NVIF_CONN_EVENT_V0_UNPLUG; + + return object->client->event(token, &args, sizeof(args.v0)); +} + +static int +nvkm_uconn_uevent(struct nvkm_object *object, void *argv, u32 argc, struct nvkm_uevent *uevent) +{ + struct nvkm_conn *conn = nvkm_uconn(object); + struct nvkm_device *device = conn->disp->engine.subdev.device; + struct nvkm_outp *outp; + union nvif_conn_event_args *args = argv; + u64 bits = 0; + + if (!uevent) { + if (conn->info.hpd == DCB_GPIO_UNUSED) + return -ENOSYS; + return 0; + } + + if (argc != sizeof(args->v0) || args->v0.version != 0) + return -ENOSYS; + + list_for_each_entry(outp, &conn->disp->outps, head) { + if (outp->info.connector == conn->index && outp->dp.aux) { + if (args->v0.types & NVIF_CONN_EVENT_V0_PLUG ) bits |= NVKM_I2C_PLUG; + if (args->v0.types & NVIF_CONN_EVENT_V0_UNPLUG) bits |= NVKM_I2C_UNPLUG; + if (args->v0.types & NVIF_CONN_EVENT_V0_IRQ ) bits |= NVKM_I2C_IRQ; + + return nvkm_uevent_add(uevent, &device->i2c->event, outp->dp.aux->id, bits, + nvkm_uconn_uevent_aux); + } + } + + if (args->v0.types & NVIF_CONN_EVENT_V0_PLUG ) bits |= NVKM_GPIO_HI; + if (args->v0.types & NVIF_CONN_EVENT_V0_UNPLUG) bits |= NVKM_GPIO_LO; + if (args->v0.types & NVIF_CONN_EVENT_V0_IRQ) + return -EINVAL; + + return nvkm_uevent_add(uevent, &device->gpio->event, conn->info.hpd, bits, + nvkm_uconn_uevent_gpio); +} + +static int nvkm_uconn_mthd_hpd_status(struct nvkm_conn *conn, void *argv, u32 argc) { struct nvkm_gpio *gpio = conn->disp->engine.subdev.device->gpio; @@ -82,6 +156,7 @@ static const struct nvkm_object_func nvkm_uconn = { .dtor = nvkm_uconn_dtor, .mthd = nvkm_uconn_mthd, + .uevent = nvkm_uconn_uevent, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/udisp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/udisp.c index 0841e7ce0343..0268d1d75805 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/udisp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/udisp.c @@ -21,6 +21,7 @@ */ #include "priv.h" #include "conn.h" +#include "head.h" #include "outp.h" #include <nvif/class.h> @@ -43,6 +44,12 @@ nvkm_udisp_sclass(struct nvkm_object *object, int index, struct nvkm_oclass *scl return 0; } + if (index-- == 0) { + sclass->base = (struct nvkm_sclass) { 0, 0, NVIF_CLASS_HEAD }; + sclass->ctor = nvkm_uhead_new; + return 0; + } + if (disp->func->user[index].ctor) { sclass->base = disp->func->user[index].base; sclass->ctor = disp->func->user[index].ctor; @@ -52,17 +59,6 @@ nvkm_udisp_sclass(struct nvkm_object *object, int index, struct nvkm_oclass *scl return -EINVAL; } -static int -nvkm_udisp_mthd(struct nvkm_object *object, u32 mthd, void *argv, u32 argc) -{ - struct nvkm_disp *disp = nvkm_udisp(object); - - if (disp->engine.subdev.device->card_type >= NV_50) - return nv50_disp_root_mthd_(object, mthd, argv, argc); - - return nv04_disp_mthd(object, mthd, argv, argc); -} - static void * nvkm_udisp_dtor(struct nvkm_object *object) { @@ -78,8 +74,6 @@ nvkm_udisp_dtor(struct nvkm_object *object) static const struct nvkm_object_func nvkm_udisp = { .dtor = nvkm_udisp_dtor, - .mthd = nvkm_udisp_mthd, - .ntfy = nvkm_disp_ntfy, .sclass = nvkm_udisp_sclass, }; @@ -89,6 +83,7 @@ nvkm_udisp_new(const struct nvkm_oclass *oclass, void *argv, u32 argc, struct nv struct nvkm_disp *disp = nvkm_disp(oclass->engine); struct nvkm_conn *conn; struct nvkm_outp *outp; + struct nvkm_head *head; union nvif_disp_args *args = argv; if (argc != sizeof(args->v0) || args->v0.version != 0) @@ -111,5 +106,9 @@ nvkm_udisp_new(const struct nvkm_oclass *oclass, void *argv, u32 argc, struct nv list_for_each_entry(outp, &disp->outps, head) args->v0.outp_mask |= BIT(outp->index); + args->v0.head_mask = 0; + list_for_each_entry(head, &disp->heads, head) + args->v0.head_mask |= BIT(head->id); + return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uhead.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uhead.c new file mode 100644 index 000000000000..f072cec16040 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uhead.c @@ -0,0 +1,127 @@ +/* + * 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_uhead(p) container_of((p), struct nvkm_head, object) +#include "head.h" +#include <core/event.h> + +#include <nvif/if0013.h> + +#include <nvif/event.h> + +static int +nvkm_uhead_uevent(struct nvkm_object *object, void *argv, u32 argc, struct nvkm_uevent *uevent) +{ + struct nvkm_head *head = nvkm_uhead(object); + union nvif_head_event_args *args = argv; + + if (!uevent) + return 0; + if (argc != sizeof(args->vn)) + return -ENOSYS; + + return nvkm_uevent_add(uevent, &head->disp->vblank, head->id, + NVKM_DISP_HEAD_EVENT_VBLANK, NULL); +} + +static int +nvkm_uhead_mthd_scanoutpos(struct nvkm_head *head, void *argv, u32 argc) +{ + union nvif_head_scanoutpos_args *args = argv; + + if (argc != sizeof(args->v0) || args->v0.version != 0) + return -ENOSYS; + + head->func->state(head, &head->arm); + args->v0.vtotal = head->arm.vtotal; + args->v0.vblanks = head->arm.vblanks; + args->v0.vblanke = head->arm.vblanke; + args->v0.htotal = head->arm.htotal; + args->v0.hblanks = head->arm.hblanks; + args->v0.hblanke = head->arm.hblanke; + + /* We don't support reading htotal/vtotal on pre-NV50 VGA, + * so we have to give up and trigger the timestamping + * fallback in the drm core. + */ + if (!args->v0.vtotal || !args->v0.htotal) + return -ENOTSUPP; + + args->v0.time[0] = ktime_to_ns(ktime_get()); + head->func->rgpos(head, &args->v0.hline, &args->v0.vline); + args->v0.time[1] = ktime_to_ns(ktime_get()); + return 0; +} + +static int +nvkm_uhead_mthd(struct nvkm_object *object, u32 mthd, void *argv, u32 argc) +{ + struct nvkm_head *head = nvkm_uhead(object); + + switch (mthd) { + case NVIF_HEAD_V0_SCANOUTPOS: return nvkm_uhead_mthd_scanoutpos(head, argv, argc); + default: + return -EINVAL; + } +} + +static void * +nvkm_uhead_dtor(struct nvkm_object *object) +{ + struct nvkm_head *head = nvkm_uhead(object); + struct nvkm_disp *disp = head->disp; + + spin_lock(&disp->client.lock); + head->object.func = NULL; + spin_unlock(&disp->client.lock); + return NULL; +} + +static const struct nvkm_object_func +nvkm_uhead = { + .dtor = nvkm_uhead_dtor, + .mthd = nvkm_uhead_mthd, + .uevent = nvkm_uhead_uevent, +}; + +int +nvkm_uhead_new(const struct nvkm_oclass *oclass, void *argv, u32 argc, struct nvkm_object **pobject) +{ + struct nvkm_disp *disp = nvkm_udisp(oclass->parent); + struct nvkm_head *head; + union nvif_head_args *args = argv; + int ret; + + if (argc != sizeof(args->v0) || args->v0.version != 0) + return -ENOSYS; + if (!(head = nvkm_head_find(disp, args->v0.id))) + return -EINVAL; + + ret = -EBUSY; + spin_lock(&disp->client.lock); + if (!head->object.func) { + nvkm_object_ctor(&nvkm_uhead, oclass, &head->object); + *pobject = &head->object; + ret = 0; + } + spin_unlock(&disp->client.lock); + return ret; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c index abedb3e86361..d10ce1e04d32 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c @@ -21,11 +21,237 @@ */ #define nvkm_uoutp(p) container_of((p), struct nvkm_outp, object) #include "outp.h" +#include "dp.h" +#include "head.h" #include "ior.h" #include <nvif/if0012.h> static int +nvkm_uoutp_mthd_dp_mst_vcpi(struct nvkm_outp *outp, void *argv, u32 argc) +{ + struct nvkm_ior *ior = outp->ior; + union nvif_outp_dp_mst_vcpi_args *args = argv; + + if (argc != sizeof(args->v0) || args->v0.version != 0) + return -ENOSYS; + if (!ior->func->dp || !ior->func->dp->vcpi || !nvkm_head_find(outp->disp, args->v0.head)) + return -EINVAL; + + ior->func->dp->vcpi(ior, args->v0.head, args->v0.start_slot, args->v0.num_slots, + args->v0.pbn, args->v0.aligned_pbn); + return 0; +} + +static int +nvkm_uoutp_mthd_dp_retrain(struct nvkm_outp *outp, void *argv, u32 argc) +{ + union nvif_outp_dp_retrain_args *args = argv; + + if (argc != sizeof(args->vn)) + return -ENOSYS; + + if (!atomic_read(&outp->dp.lt.done)) + return 0; + + return outp->func->acquire(outp); +} + +static int +nvkm_uoutp_mthd_dp_aux_pwr(struct nvkm_outp *outp, void *argv, u32 argc) +{ + union nvif_outp_dp_aux_pwr_args *args = argv; + + if (argc != sizeof(args->v0) || args->v0.version != 0) + return -ENOSYS; + + outp->dp.enabled = !!args->v0.state; + nvkm_dp_enable(outp, outp->dp.enabled); + return 0; +} + +static int +nvkm_uoutp_mthd_hda_eld(struct nvkm_outp *outp, void *argv, u32 argc) +{ + struct nvkm_ior *ior = outp->ior; + union nvif_outp_hda_eld_args *args = argv; + + if (argc < sizeof(args->v0) || args->v0.version != 0) + return -ENOSYS; + argc -= sizeof(args->v0); + + if (!ior->hda || !nvkm_head_find(outp->disp, args->v0.head)) + return -EINVAL; + if (argc > 0x60) + return -E2BIG; + + if (argc && args->v0.data[0]) { + if (outp->info.type == DCB_OUTPUT_DP) + ior->func->dp->audio(ior, args->v0.head, true); + ior->func->hda->hpd(ior, args->v0.head, true); + ior->func->hda->eld(ior, args->v0.head, args->v0.data, argc); + } else { + if (outp->info.type == DCB_OUTPUT_DP) + ior->func->dp->audio(ior, args->v0.head, false); + ior->func->hda->hpd(ior, args->v0.head, false); + } + + return 0; +} + +static int +nvkm_uoutp_mthd_infoframe(struct nvkm_outp *outp, void *argv, u32 argc) +{ + struct nvkm_ior *ior = outp->ior; + union nvif_outp_infoframe_args *args = argv; + + if (argc < sizeof(args->v0) || args->v0.version != 0) + return -ENOSYS; + if (!nvkm_head_find(outp->disp, args->v0.head)) + return -EINVAL; + + switch (ior->func->hdmi ? args->v0.type : 0xff) { + case NVIF_OUTP_INFOFRAME_V0_AVI: + ior->func->hdmi->infoframe_avi(ior, args->v0.head, argv, argc); + return 0; + case NVIF_OUTP_INFOFRAME_V0_VSI: + ior->func->hdmi->infoframe_vsi(ior, args->v0.head, argv, argc); + return 0; + default: + break; + } + + return -EINVAL; +} + +static int +nvkm_uoutp_mthd_release(struct nvkm_outp *outp, void *argv, u32 argc) +{ + struct nvkm_head *head = outp->asy.head; + struct nvkm_ior *ior = outp->ior; + union nvif_outp_release_args *args = argv; + + if (argc != sizeof(args->vn)) + return -ENOSYS; + + if (ior->func->hdmi && head) { + ior->func->hdmi->infoframe_avi(ior, head->id, NULL, 0); + ior->func->hdmi->infoframe_vsi(ior, head->id, NULL, 0); + ior->func->hdmi->ctrl(ior, head->id, false, 0, 0); + } + + nvkm_outp_release(outp, NVKM_OUTP_USER); + return 0; +} + +static int +nvkm_uoutp_mthd_acquire_dp(struct nvkm_outp *outp, u8 dpcd[16], + u8 link_nr, u8 link_bw, bool hda, bool mst) +{ + int ret; + + ret = nvkm_outp_acquire(outp, NVKM_OUTP_USER, hda); + if (ret) + return ret; + + memcpy(outp->dp.dpcd, dpcd, sizeof(outp->dp.dpcd)); + outp->dp.lt.nr = link_nr; + outp->dp.lt.bw = link_bw; + outp->dp.lt.mst = mst; + return 0; +} + +static int +nvkm_uoutp_mthd_acquire_tmds(struct nvkm_outp *outp, u8 head, u8 hdmi, u8 hdmi_max_ac_packet, + u8 hdmi_rekey, u8 hdmi_scdc, u8 hdmi_hda) +{ + struct nvkm_ior *ior; + int ret; + + if (!(outp->asy.head = nvkm_head_find(outp->disp, head))) + return -EINVAL; + + ret = nvkm_outp_acquire(outp, NVKM_OUTP_USER, hdmi && hdmi_hda); + if (ret) + return ret; + + ior = outp->ior; + + if (hdmi) { + if (!ior->func->hdmi || + hdmi_max_ac_packet > 0x1f || hdmi_rekey > 0x7f || + (hdmi_scdc && !ior->func->hdmi->scdc)) { + nvkm_outp_release(outp, NVKM_OUTP_USER); + return -EINVAL; + } + + ior->func->hdmi->ctrl(ior, head, hdmi, hdmi_max_ac_packet, hdmi_rekey); + if (ior->func->hdmi->scdc) + ior->func->hdmi->scdc(ior, hdmi_scdc); + } + + return 0; +} + +static int +nvkm_uoutp_mthd_acquire_lvds(struct nvkm_outp *outp, bool dual, bool bpc8) +{ + if (outp->info.type != DCB_OUTPUT_LVDS) + return -EINVAL; + + outp->lvds.dual = dual; + outp->lvds.bpc8 = bpc8; + + return nvkm_outp_acquire(outp, NVKM_OUTP_USER, false); +} + +static int +nvkm_uoutp_mthd_acquire(struct nvkm_outp *outp, void *argv, u32 argc) +{ + union nvif_outp_acquire_args *args = argv; + int ret; + + if (argc != sizeof(args->v0) || args->v0.version != 0) + return -ENOSYS; + if (outp->ior) + return -EBUSY; + + switch (args->v0.proto) { + case NVIF_OUTP_ACQUIRE_V0_RGB_CRT: + ret = nvkm_outp_acquire(outp, NVKM_OUTP_USER, false); + break; + case NVIF_OUTP_ACQUIRE_V0_TMDS: + ret = nvkm_uoutp_mthd_acquire_tmds(outp, args->v0.tmds.head, + args->v0.tmds.hdmi, + args->v0.tmds.hdmi_max_ac_packet, + args->v0.tmds.hdmi_rekey, + args->v0.tmds.hdmi_scdc, + args->v0.tmds.hdmi_hda); + break; + case NVIF_OUTP_ACQUIRE_V0_LVDS: + ret = nvkm_uoutp_mthd_acquire_lvds(outp, args->v0.lvds.dual, args->v0.lvds.bpc8); + break; + case NVIF_OUTP_ACQUIRE_V0_DP: + ret = nvkm_uoutp_mthd_acquire_dp(outp, args->v0.dp.dpcd, + args->v0.dp.link_nr, + args->v0.dp.link_bw, + args->v0.dp.hda != 0, + args->v0.dp.mst != 0); + break; + default: + ret = -EINVAL; + break; + } + + if (ret) + return ret; + + args->v0.or = outp->ior->id; + args->v0.link = outp->ior->asy.link; + return 0; +} + +static int nvkm_uoutp_mthd_load_detect(struct nvkm_outp *outp, void *argv, u32 argc) { union nvif_outp_load_detect_args *args = argv; @@ -49,10 +275,28 @@ nvkm_uoutp_mthd_load_detect(struct nvkm_outp *outp, void *argv, u32 argc) } static int +nvkm_uoutp_mthd_acquired(struct nvkm_outp *outp, u32 mthd, void *argv, u32 argc) +{ + switch (mthd) { + case NVIF_OUTP_V0_RELEASE : return nvkm_uoutp_mthd_release (outp, argv, argc); + case NVIF_OUTP_V0_INFOFRAME : return nvkm_uoutp_mthd_infoframe (outp, argv, argc); + case NVIF_OUTP_V0_HDA_ELD : return nvkm_uoutp_mthd_hda_eld (outp, argv, argc); + case NVIF_OUTP_V0_DP_RETRAIN : return nvkm_uoutp_mthd_dp_retrain (outp, argv, argc); + case NVIF_OUTP_V0_DP_MST_VCPI: return nvkm_uoutp_mthd_dp_mst_vcpi(outp, argv, argc); + default: + break; + } + + return -EINVAL; +} + +static int nvkm_uoutp_mthd_noacquire(struct nvkm_outp *outp, u32 mthd, void *argv, u32 argc) { switch (mthd) { case NVIF_OUTP_V0_LOAD_DETECT: return nvkm_uoutp_mthd_load_detect(outp, argv, argc); + case NVIF_OUTP_V0_ACQUIRE : return nvkm_uoutp_mthd_acquire (outp, argv, argc); + case NVIF_OUTP_V0_DP_AUX_PWR : return nvkm_uoutp_mthd_dp_aux_pwr (outp, argv, argc); default: break; } @@ -73,6 +317,11 @@ nvkm_uoutp_mthd(struct nvkm_object *object, u32 mthd, void *argv, u32 argc) if (ret <= 0) goto done; + if (outp->ior) + ret = nvkm_uoutp_mthd_acquired(outp, mthd, argv, argc); + else + ret = -EIO; + done: mutex_unlock(&disp->super.mutex); return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c index 43b7dec45179..d619b40a42c3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c @@ -65,10 +65,10 @@ nvkm_falcon_intr(struct nvkm_engine *engine) u32 dest = nvkm_rd32(device, base + 0x01c); u32 intr = nvkm_rd32(device, base + 0x008) & dest & ~(dest >> 16); u32 inst = nvkm_rd32(device, base + 0x050) & 0x3fffffff; - struct nvkm_fifo_chan *chan; + struct nvkm_chan *chan; unsigned long flags; - chan = nvkm_fifo_chan_inst(device->fifo, (u64)inst << 12, &flags); + chan = nvkm_chan_get_inst(engine, (u64)inst << 12, &flags); if (intr & 0x00000040) { if (falcon->func->intr) { @@ -89,7 +89,7 @@ nvkm_falcon_intr(struct nvkm_engine *engine) nvkm_wr32(device, base + 0x004, intr); } - nvkm_fifo_chan_put(device->fifo, flags, &chan); + nvkm_chan_put(&chan, flags); } static int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild index 5e831d347a95..5a074b9970ab 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild @@ -1,11 +1,18 @@ # SPDX-License-Identifier: MIT nvkm-y += nvkm/engine/fifo/base.o +nvkm-y += nvkm/engine/fifo/cgrp.o +nvkm-y += nvkm/engine/fifo/chan.o +nvkm-y += nvkm/engine/fifo/chid.o +nvkm-y += nvkm/engine/fifo/runl.o +nvkm-y += nvkm/engine/fifo/runq.o + nvkm-y += nvkm/engine/fifo/nv04.o nvkm-y += nvkm/engine/fifo/nv10.o nvkm-y += nvkm/engine/fifo/nv17.o nvkm-y += nvkm/engine/fifo/nv40.o nvkm-y += nvkm/engine/fifo/nv50.o nvkm-y += nvkm/engine/fifo/g84.o +nvkm-y += nvkm/engine/fifo/g98.o nvkm-y += nvkm/engine/fifo/gf100.o nvkm-y += nvkm/engine/fifo/gk104.o nvkm-y += nvkm/engine/fifo/gk110.o @@ -13,28 +20,11 @@ nvkm-y += nvkm/engine/fifo/gk208.o nvkm-y += nvkm/engine/fifo/gk20a.o nvkm-y += nvkm/engine/fifo/gm107.o nvkm-y += nvkm/engine/fifo/gm200.o -nvkm-y += nvkm/engine/fifo/gm20b.o nvkm-y += nvkm/engine/fifo/gp100.o -nvkm-y += nvkm/engine/fifo/gp10b.o nvkm-y += nvkm/engine/fifo/gv100.o nvkm-y += nvkm/engine/fifo/tu102.o +nvkm-y += nvkm/engine/fifo/ga100.o nvkm-y += nvkm/engine/fifo/ga102.o -nvkm-y += nvkm/engine/fifo/chan.o -nvkm-y += nvkm/engine/fifo/channv50.o -nvkm-y += nvkm/engine/fifo/chang84.o - -nvkm-y += nvkm/engine/fifo/dmanv04.o -nvkm-y += nvkm/engine/fifo/dmanv10.o -nvkm-y += nvkm/engine/fifo/dmanv17.o -nvkm-y += nvkm/engine/fifo/dmanv40.o - -nvkm-y += nvkm/engine/fifo/gpfifonv50.o -nvkm-y += nvkm/engine/fifo/gpfifog84.o -nvkm-y += nvkm/engine/fifo/gpfifogf100.o -nvkm-y += nvkm/engine/fifo/gpfifogk104.o -nvkm-y += nvkm/engine/fifo/gpfifogv100.o -nvkm-y += nvkm/engine/fifo/gpfifotu102.o - -nvkm-y += nvkm/engine/fifo/usergv100.o -nvkm-y += nvkm/engine/fifo/usertu102.o +nvkm-y += nvkm/engine/fifo/ucgrp.o +nvkm-y += nvkm/engine/fifo/uchan.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c index 58b8df75fc40..5ea9a2ff0663 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c @@ -23,25 +23,32 @@ */ #include "priv.h" #include "chan.h" +#include "chid.h" +#include "runl.h" +#include "runq.h" -#include <core/client.h> #include <core/gpuobj.h> -#include <core/notify.h> +#include <subdev/bar.h> #include <subdev/mc.h> +#include <subdev/mmu.h> -#include <nvif/event.h> #include <nvif/cl0080.h> #include <nvif/unpack.h> -void -nvkm_fifo_recover_chan(struct nvkm_fifo *fifo, int chid) +bool +nvkm_fifo_ctxsw_in_progress(struct nvkm_engine *engine) { - unsigned long flags; - if (WARN_ON(!fifo->func->recover_chan)) - return; - spin_lock_irqsave(&fifo->lock, flags); - fifo->func->recover_chan(fifo, chid); - spin_unlock_irqrestore(&fifo->lock, flags); + struct nvkm_runl *runl; + struct nvkm_engn *engn; + + nvkm_runl_foreach(runl, engine->subdev.device->fifo) { + nvkm_runl_foreach_engn(engn, runl) { + if (engn->engine == engine) + return engn->func->chsw ? engn->func->chsw(engn) : false; + } + } + + return false; } void @@ -59,160 +66,23 @@ nvkm_fifo_start(struct nvkm_fifo *fifo, unsigned long *flags) void nvkm_fifo_fault(struct nvkm_fifo *fifo, struct nvkm_fault_data *info) { - return fifo->func->fault(fifo, info); -} - -void -nvkm_fifo_chan_put(struct nvkm_fifo *fifo, unsigned long flags, - struct nvkm_fifo_chan **pchan) -{ - struct nvkm_fifo_chan *chan = *pchan; - if (likely(chan)) { - *pchan = NULL; - spin_unlock_irqrestore(&fifo->lock, flags); - } -} - -struct nvkm_fifo_chan * -nvkm_fifo_chan_inst_locked(struct nvkm_fifo *fifo, u64 inst) -{ - struct nvkm_fifo_chan *chan; - list_for_each_entry(chan, &fifo->chan, head) { - if (chan->inst->addr == inst) { - list_del(&chan->head); - list_add(&chan->head, &fifo->chan); - return chan; - } - } - return NULL; -} - -struct nvkm_fifo_chan * -nvkm_fifo_chan_inst(struct nvkm_fifo *fifo, u64 inst, unsigned long *rflags) -{ - struct nvkm_fifo_chan *chan; - unsigned long flags; - spin_lock_irqsave(&fifo->lock, flags); - if ((chan = nvkm_fifo_chan_inst_locked(fifo, inst))) { - *rflags = flags; - return chan; - } - spin_unlock_irqrestore(&fifo->lock, flags); - return NULL; -} - -struct nvkm_fifo_chan * -nvkm_fifo_chan_chid(struct nvkm_fifo *fifo, int chid, unsigned long *rflags) -{ - struct nvkm_fifo_chan *chan; - unsigned long flags; - spin_lock_irqsave(&fifo->lock, flags); - list_for_each_entry(chan, &fifo->chan, head) { - if (chan->chid == chid) { - list_del(&chan->head); - list_add(&chan->head, &fifo->chan); - *rflags = flags; - return chan; - } - } - spin_unlock_irqrestore(&fifo->lock, flags); - return NULL; -} - -void -nvkm_fifo_kevent(struct nvkm_fifo *fifo, int chid) -{ - nvkm_event_send(&fifo->kevent, 1, chid, NULL, 0); -} - -static int -nvkm_fifo_kevent_ctor(struct nvkm_object *object, void *data, u32 size, - struct nvkm_notify *notify) -{ - struct nvkm_fifo_chan *chan = nvkm_fifo_chan(object); - if (size == 0) { - notify->size = 0; - notify->types = 1; - notify->index = chan->chid; - return 0; - } - return -ENOSYS; -} - -static const struct nvkm_event_func -nvkm_fifo_kevent_func = { - .ctor = nvkm_fifo_kevent_ctor, -}; - -static void -nvkm_fifo_uevent_fini(struct nvkm_event *event, int type, int index) -{ - struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent); - fifo->func->uevent_fini(fifo); -} - -static void -nvkm_fifo_uevent_init(struct nvkm_event *event, int type, int index) -{ - struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent); - fifo->func->uevent_init(fifo); -} - -static int -nvkm_fifo_uevent_ctor(struct nvkm_object *object, void *data, u32 size, - struct nvkm_notify *notify) -{ - union { - struct nvif_notify_uevent_req none; - } *req = data; - int ret = -ENOSYS; - - if (!(ret = nvif_unvers(ret, &data, &size, req->none))) { - notify->size = sizeof(struct nvif_notify_uevent_rep); - notify->types = 1; - notify->index = 0; - } - - return ret; -} - -static const struct nvkm_event_func -nvkm_fifo_uevent_func = { - .ctor = nvkm_fifo_uevent_ctor, - .init = nvkm_fifo_uevent_init, - .fini = nvkm_fifo_uevent_fini, -}; - -void -nvkm_fifo_uevent(struct nvkm_fifo *fifo) -{ - struct nvif_notify_uevent_rep rep = { - }; - nvkm_event_send(&fifo->uevent, 1, 0, &rep, sizeof(rep)); + return fifo->func->mmu_fault->recover(fifo, info); } static int -nvkm_fifo_class_new_(struct nvkm_device *device, - const struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nvkm_fifo_class_new(struct nvkm_device *device, const struct nvkm_oclass *oclass, + void *argv, u32 argc, struct nvkm_object **pobject) { struct nvkm_fifo *fifo = nvkm_fifo(oclass->engine); - return fifo->func->class_new(fifo, oclass, data, size, pobject); -} -static const struct nvkm_device_oclass -nvkm_fifo_class_ = { - .ctor = nvkm_fifo_class_new_, -}; + if (oclass->engn == &fifo->func->cgrp.user) + return nvkm_ucgrp_new(fifo, oclass, argv, argc, pobject); -static int -nvkm_fifo_class_new(struct nvkm_device *device, - const struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - const struct nvkm_fifo_chan_oclass *sclass = oclass->engn; - struct nvkm_fifo *fifo = nvkm_fifo(oclass->engine); - return sclass->ctor(fifo, oclass, data, size, pobject); + if (oclass->engn == &fifo->func->chan.user) + return nvkm_uchan_new(fifo, NULL, oclass, argv, argc, pobject); + + WARN_ON(1); + return -ENOSYS; } static const struct nvkm_device_oclass @@ -221,24 +91,28 @@ nvkm_fifo_class = { }; static int -nvkm_fifo_class_get(struct nvkm_oclass *oclass, int index, - const struct nvkm_device_oclass **class) +nvkm_fifo_class_get(struct nvkm_oclass *oclass, int index, const struct nvkm_device_oclass **class) { struct nvkm_fifo *fifo = nvkm_fifo(oclass->engine); - const struct nvkm_fifo_chan_oclass *sclass; + const struct nvkm_fifo_func_cgrp *cgrp = &fifo->func->cgrp; + const struct nvkm_fifo_func_chan *chan = &fifo->func->chan; int c = 0; - if (fifo->func->class_get) { - int ret = fifo->func->class_get(fifo, index, oclass); - if (ret == 0) - *class = &nvkm_fifo_class_; - return ret; + /* *_CHANNEL_GROUP_* */ + if (cgrp->user.oclass) { + if (c++ == index) { + oclass->base = cgrp->user; + oclass->engn = &fifo->func->cgrp.user; + *class = &nvkm_fifo_class; + return 0; + } } - while ((sclass = fifo->func->chan[c])) { + /* *_CHANNEL_DMA, *_CHANNEL_GPFIFO_* */ + if (chan->user.oclass) { if (c++ == index) { - oclass->base = sclass->base; - oclass->engn = sclass; + oclass->base = chan->user; + oclass->engn = &fifo->func->chan.user; *class = &nvkm_fifo_class; return 0; } @@ -247,19 +121,47 @@ nvkm_fifo_class_get(struct nvkm_oclass *oclass, int index, return c; } -static void -nvkm_fifo_intr(struct nvkm_engine *engine) +static int +nvkm_fifo_fini(struct nvkm_engine *engine, bool suspend) { struct nvkm_fifo *fifo = nvkm_fifo(engine); - fifo->func->intr(fifo); + struct nvkm_runl *runl; + + nvkm_inth_block(&fifo->engine.subdev.inth); + + nvkm_runl_foreach(runl, fifo) + nvkm_runl_fini(runl); + + return 0; } static int -nvkm_fifo_fini(struct nvkm_engine *engine, bool suspend) +nvkm_fifo_init(struct nvkm_engine *engine) { struct nvkm_fifo *fifo = nvkm_fifo(engine); - if (fifo->func->fini) - fifo->func->fini(fifo); + struct nvkm_runq *runq; + struct nvkm_runl *runl; + u32 mask = 0; + + if (fifo->func->init_pbdmas) { + nvkm_runq_foreach(runq, fifo) + mask |= BIT(runq->id); + + fifo->func->init_pbdmas(fifo, mask); + + nvkm_runq_foreach(runq, fifo) + runq->func->init(runq); + } + + nvkm_runl_foreach(runl, fifo) { + if (runl->func->init) + runl->func->init(runl); + } + + if (fifo->func->init) + fifo->func->init(fifo); + + nvkm_inth_allow(&fifo->engine.subdev.inth); return 0; } @@ -267,22 +169,146 @@ static int nvkm_fifo_info(struct nvkm_engine *engine, u64 mthd, u64 *data) { struct nvkm_fifo *fifo = nvkm_fifo(engine); + struct nvkm_runl *runl; + struct nvkm_engn *engn; + int ret; + + ret = nvkm_subdev_oneinit(&fifo->engine.subdev); + if (ret) + return ret; + switch (mthd) { - case NV_DEVICE_HOST_CHANNELS: *data = fifo->nr; return 0; + case NV_DEVICE_HOST_CHANNELS: *data = fifo->chid ? fifo->chid->nr : 0; return 0; + case NV_DEVICE_HOST_RUNLISTS: + *data = 0; + nvkm_runl_foreach(runl, fifo) + *data |= BIT(runl->id); + return 0; + case NV_DEVICE_HOST_RUNLIST_ENGINES: + runl = nvkm_runl_get(fifo, *data, 0); + if (runl) { + *data = 0; + nvkm_runl_foreach_engn(engn, runl) { +#define CASE(n) case NVKM_ENGINE_##n: *data |= NV_DEVICE_HOST_RUNLIST_ENGINES_##n; break + switch (engn->engine->subdev.type) { + case NVKM_ENGINE_DMAOBJ: + break; + CASE(SW ); + CASE(GR ); + CASE(MPEG ); + CASE(ME ); + CASE(CIPHER); + CASE(BSP ); + CASE(VP ); + CASE(CE ); + CASE(SEC ); + CASE(MSVLD ); + CASE(MSPDEC); + CASE(MSPPP ); + CASE(MSENC ); + CASE(VIC ); + CASE(SEC2 ); + CASE(NVDEC ); + CASE(NVENC ); + default: + WARN_ON(1); + break; + } +#undef CASE + } + return 0; + } + return -EINVAL; + case NV_DEVICE_HOST_RUNLIST_CHANNELS: + if (!fifo->chid) { + runl = nvkm_runl_get(fifo, *data, 0); + if (runl) { + *data = runl->chid->nr; + return 0; + } + } + return -EINVAL; default: - if (fifo->func->info) - return fifo->func->info(fifo, mthd, data); break; } + return -ENOSYS; } static int nvkm_fifo_oneinit(struct nvkm_engine *engine) { + struct nvkm_subdev *subdev = &engine->subdev; + struct nvkm_device *device = subdev->device; struct nvkm_fifo *fifo = nvkm_fifo(engine); - if (fifo->func->oneinit) - return fifo->func->oneinit(fifo); + struct nvkm_runl *runl; + struct nvkm_engn *engn; + int ret, nr, i; + + /* Initialise CHID/CGID allocator(s) on GPUs where they aren't per-runlist. */ + if (fifo->func->chid_nr) { + ret = fifo->func->chid_ctor(fifo, fifo->func->chid_nr(fifo)); + if (ret) + return ret; + } + + /* Create runqueues for each PBDMA. */ + if (fifo->func->runq_nr) { + for (nr = fifo->func->runq_nr(fifo), i = 0; i < nr; i++) { + if (!nvkm_runq_new(fifo, i)) + return -ENOMEM; + } + } + + /* Create runlists. */ + ret = fifo->func->runl_ctor(fifo); + if (ret) + return ret; + + nvkm_runl_foreach(runl, fifo) { + RUNL_DEBUG(runl, "chan:%06x", runl->chan); + nvkm_runl_foreach_engn(engn, runl) { + ENGN_DEBUG(engn, ""); + } + } + + /* Register interrupt handler. */ + if (fifo->func->intr) { + ret = nvkm_inth_add(&device->mc->intr, NVKM_INTR_SUBDEV, NVKM_INTR_PRIO_NORMAL, + subdev, fifo->func->intr, &subdev->inth); + if (ret) { + nvkm_error(subdev, "intr %d\n", ret); + return ret; + } + } + + /* Initialise non-stall intr handling. */ + if (fifo->func->nonstall_ctor) { + ret = fifo->func->nonstall_ctor(fifo); + if (ret) { + nvkm_error(subdev, "nonstall %d\n", ret); + } + } + + /* Allocate USERD + BAR1 polling area. */ + if (fifo->func->chan.func->userd->bar == 1) { + struct nvkm_vmm *bar1 = nvkm_bar_bar1_vmm(device); + + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, fifo->chid->nr * + fifo->func->chan.func->userd->size, 0, true, + &fifo->userd.mem); + if (ret) + return ret; + + ret = nvkm_vmm_get(bar1, 12, nvkm_memory_size(fifo->userd.mem), &fifo->userd.bar1); + if (ret) + return ret; + + ret = nvkm_memory_map(fifo->userd.mem, 0, bar1, fifo->userd.bar1, NULL, 0); + if (ret) + return ret; + } + return 0; } @@ -292,25 +318,28 @@ nvkm_fifo_preinit(struct nvkm_engine *engine) nvkm_mc_reset(engine->subdev.device, NVKM_ENGINE_FIFO, 0); } -static int -nvkm_fifo_init(struct nvkm_engine *engine) -{ - struct nvkm_fifo *fifo = nvkm_fifo(engine); - fifo->func->init(fifo); - return 0; -} - static void * nvkm_fifo_dtor(struct nvkm_engine *engine) { struct nvkm_fifo *fifo = nvkm_fifo(engine); - void *data = fifo; - if (fifo->func->dtor) - data = fifo->func->dtor(fifo); - nvkm_event_fini(&fifo->kevent); - nvkm_event_fini(&fifo->uevent); + struct nvkm_runl *runl, *runt; + struct nvkm_runq *runq, *rtmp; + + if (fifo->userd.bar1) + nvkm_vmm_put(nvkm_bar_bar1_vmm(engine->subdev.device), &fifo->userd.bar1); + nvkm_memory_unref(&fifo->userd.mem); + + list_for_each_entry_safe(runl, runt, &fifo->runls, head) + nvkm_runl_del(runl); + list_for_each_entry_safe(runq, rtmp, &fifo->runqs, head) + nvkm_runq_del(runq); + + nvkm_chid_unref(&fifo->cgid); + nvkm_chid_unref(&fifo->chid); + + nvkm_event_fini(&fifo->nonstall.event); mutex_destroy(&fifo->mutex); - return data; + return fifo; } static const struct nvkm_engine_func @@ -321,37 +350,40 @@ nvkm_fifo = { .info = nvkm_fifo_info, .init = nvkm_fifo_init, .fini = nvkm_fifo_fini, - .intr = nvkm_fifo_intr, .base.sclass = nvkm_fifo_class_get, }; int -nvkm_fifo_ctor(const struct nvkm_fifo_func *func, struct nvkm_device *device, - enum nvkm_subdev_type type, int inst, int nr, struct nvkm_fifo *fifo) +nvkm_fifo_new_(const struct nvkm_fifo_func *func, struct nvkm_device *device, + enum nvkm_subdev_type type, int inst, struct nvkm_fifo **pfifo) { + struct nvkm_fifo *fifo; int ret; + if (!(fifo = *pfifo = kzalloc(sizeof(*fifo), GFP_KERNEL))) + return -ENOMEM; + fifo->func = func; - INIT_LIST_HEAD(&fifo->chan); + INIT_LIST_HEAD(&fifo->runqs); + INIT_LIST_HEAD(&fifo->runls); + /*TODO: Needs to be >CTXSW_TIMEOUT, so RC can recover before this is hit. + * CTXSW_TIMEOUT HW default seems to differ between GPUs, so just a + * large number for now until we support changing it. + */ + fifo->timeout.chan_msec = 10000; spin_lock_init(&fifo->lock); mutex_init(&fifo->mutex); - if (WARN_ON(fifo->nr > NVKM_FIFO_CHID_NR)) - fifo->nr = NVKM_FIFO_CHID_NR; - else - fifo->nr = nr; - bitmap_clear(fifo->mask, 0, fifo->nr); - ret = nvkm_engine_ctor(&nvkm_fifo, device, type, inst, true, &fifo->engine); if (ret) return ret; - if (func->uevent_init) { - ret = nvkm_event_init(&nvkm_fifo_uevent_func, 1, 1, - &fifo->uevent); + if (func->nonstall) { + ret = nvkm_event_init(func->nonstall, &fifo->engine.subdev, 1, 1, + &fifo->nonstall.event); if (ret) return ret; } - return nvkm_event_init(&nvkm_fifo_kevent_func, 1, nr, &fifo->kevent); + return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/cgrp.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/cgrp.c new file mode 100644 index 000000000000..ea53fb3d5d06 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/cgrp.c @@ -0,0 +1,252 @@ +/* + * 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 "cgrp.h" +#include "chan.h" +#include "chid.h" +#include "runl.h" +#include "priv.h" + +#include <core/gpuobj.h> +#include <subdev/mmu.h> + +static void +nvkm_cgrp_ectx_put(struct nvkm_cgrp *cgrp, struct nvkm_ectx **pectx) +{ + struct nvkm_ectx *ectx = *pectx; + + if (ectx) { + struct nvkm_engn *engn = ectx->engn; + + if (refcount_dec_and_test(&ectx->refs)) { + CGRP_TRACE(cgrp, "dtor ectx %d[%s]", engn->id, engn->engine->subdev.name); + nvkm_object_del(&ectx->object); + list_del(&ectx->head); + kfree(ectx); + } + + *pectx = NULL; + } +} + +static int +nvkm_cgrp_ectx_get(struct nvkm_cgrp *cgrp, struct nvkm_engn *engn, struct nvkm_ectx **pectx, + struct nvkm_chan *chan, struct nvkm_client *client) +{ + struct nvkm_engine *engine = engn->engine; + struct nvkm_oclass cclass = { + .client = client, + .engine = engine, + }; + struct nvkm_ectx *ectx; + int ret = 0; + + /* Look for an existing context for this engine in the channel group. */ + ectx = nvkm_list_find(ectx, &cgrp->ectxs, head, ectx->engn == engn); + if (ectx) { + refcount_inc(&ectx->refs); + *pectx = ectx; + return 0; + } + + /* Nope - create a fresh one. */ + CGRP_TRACE(cgrp, "ctor ectx %d[%s]", engn->id, engn->engine->subdev.name); + if (!(ectx = *pectx = kzalloc(sizeof(*ectx), GFP_KERNEL))) + return -ENOMEM; + + ectx->engn = engn; + refcount_set(&ectx->refs, 1); + refcount_set(&ectx->uses, 0); + list_add_tail(&ectx->head, &cgrp->ectxs); + + /* Allocate the HW structures. */ + if (engine->func->fifo.cclass) + ret = engine->func->fifo.cclass(chan, &cclass, &ectx->object); + else if (engine->func->cclass) + ret = nvkm_object_new_(engine->func->cclass, &cclass, NULL, 0, &ectx->object); + + if (ret) + nvkm_cgrp_ectx_put(cgrp, pectx); + + return ret; +} + +void +nvkm_cgrp_vctx_put(struct nvkm_cgrp *cgrp, struct nvkm_vctx **pvctx) +{ + struct nvkm_vctx *vctx = *pvctx; + + if (vctx) { + struct nvkm_engn *engn = vctx->ectx->engn; + + if (refcount_dec_and_test(&vctx->refs)) { + CGRP_TRACE(cgrp, "dtor vctx %d[%s]", engn->id, engn->engine->subdev.name); + nvkm_vmm_put(vctx->vmm, &vctx->vma); + nvkm_gpuobj_del(&vctx->inst); + + nvkm_cgrp_ectx_put(cgrp, &vctx->ectx); + if (vctx->vmm) { + atomic_dec(&vctx->vmm->engref[engn->engine->subdev.type]); + nvkm_vmm_unref(&vctx->vmm); + } + list_del(&vctx->head); + kfree(vctx); + } + + *pvctx = NULL; + } +} + +int +nvkm_cgrp_vctx_get(struct nvkm_cgrp *cgrp, struct nvkm_engn *engn, struct nvkm_chan *chan, + struct nvkm_vctx **pvctx, struct nvkm_client *client) +{ + struct nvkm_ectx *ectx; + struct nvkm_vctx *vctx; + int ret; + + /* Look for an existing sub-context for this engine+VEID in the channel group. */ + vctx = nvkm_list_find(vctx, &cgrp->vctxs, head, + vctx->ectx->engn == engn && vctx->vmm == chan->vmm); + if (vctx) { + refcount_inc(&vctx->refs); + *pvctx = vctx; + return 0; + } + + /* Nope - create a fresh one. But, context first. */ + ret = nvkm_cgrp_ectx_get(cgrp, engn, &ectx, chan, client); + if (ret) { + CGRP_ERROR(cgrp, "ectx %d[%s]: %d", engn->id, engn->engine->subdev.name, ret); + return ret; + } + + /* Now, create the sub-context. */ + CGRP_TRACE(cgrp, "ctor vctx %d[%s]", engn->id, engn->engine->subdev.name); + if (!(vctx = *pvctx = kzalloc(sizeof(*vctx), GFP_KERNEL))) { + nvkm_cgrp_ectx_put(cgrp, &ectx); + return -ENOMEM; + } + + vctx->ectx = ectx; + vctx->vmm = nvkm_vmm_ref(chan->vmm); + refcount_set(&vctx->refs, 1); + list_add_tail(&vctx->head, &cgrp->vctxs); + + /* MMU on some GPUs needs to know engine usage for TLB invalidation. */ + if (vctx->vmm) + atomic_inc(&vctx->vmm->engref[engn->engine->subdev.type]); + + /* Allocate the HW structures. */ + if (engn->func->bind) { + ret = nvkm_object_bind(vctx->ectx->object, NULL, 0, &vctx->inst); + if (ret == 0 && engn->func->ctor) + ret = engn->func->ctor(engn, vctx); + } + + if (ret) + nvkm_cgrp_vctx_put(cgrp, pvctx); + + return ret; +} + +static void +nvkm_cgrp_del(struct kref *kref) +{ + struct nvkm_cgrp *cgrp = container_of(kref, typeof(*cgrp), kref); + struct nvkm_runl *runl = cgrp->runl; + + if (runl->cgid) + nvkm_chid_put(runl->cgid, cgrp->id, &cgrp->lock); + + mutex_destroy(&cgrp->mutex); + nvkm_vmm_unref(&cgrp->vmm); + kfree(cgrp); +} + +void +nvkm_cgrp_unref(struct nvkm_cgrp **pcgrp) +{ + struct nvkm_cgrp *cgrp = *pcgrp; + + if (!cgrp) + return; + + kref_put(&cgrp->kref, nvkm_cgrp_del); + *pcgrp = NULL; +} + +struct nvkm_cgrp * +nvkm_cgrp_ref(struct nvkm_cgrp *cgrp) +{ + if (cgrp) + kref_get(&cgrp->kref); + + return cgrp; +} + +void +nvkm_cgrp_put(struct nvkm_cgrp **pcgrp, unsigned long irqflags) +{ + struct nvkm_cgrp *cgrp = *pcgrp; + + if (!cgrp) + return; + + *pcgrp = NULL; + spin_unlock_irqrestore(&cgrp->lock, irqflags); +} + +int +nvkm_cgrp_new(struct nvkm_runl *runl, const char *name, struct nvkm_vmm *vmm, bool hw, + struct nvkm_cgrp **pcgrp) +{ + struct nvkm_cgrp *cgrp; + + if (!(cgrp = *pcgrp = kmalloc(sizeof(*cgrp), GFP_KERNEL))) + return -ENOMEM; + + cgrp->func = runl->fifo->func->cgrp.func; + strscpy(cgrp->name, name, sizeof(cgrp->name)); + cgrp->runl = runl; + cgrp->vmm = nvkm_vmm_ref(vmm); + cgrp->hw = hw; + cgrp->id = -1; + kref_init(&cgrp->kref); + INIT_LIST_HEAD(&cgrp->chans); + cgrp->chan_nr = 0; + spin_lock_init(&cgrp->lock); + INIT_LIST_HEAD(&cgrp->ectxs); + INIT_LIST_HEAD(&cgrp->vctxs); + mutex_init(&cgrp->mutex); + atomic_set(&cgrp->rc, NVKM_CGRP_RC_NONE); + + if (runl->cgid) { + cgrp->id = nvkm_chid_get(runl->cgid, cgrp); + if (cgrp->id < 0) { + RUNL_ERROR(runl, "!cgids"); + nvkm_cgrp_unref(pcgrp); + return -ENOSPC; + } + } + + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/cgrp.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/cgrp.h index d0ac60b06720..5f6abd59a6ff 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/cgrp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/cgrp.h @@ -1,11 +1,75 @@ -#ifndef __NVKM_FIFO_CGRP_H__ -#define __NVKM_FIFO_CGRP_H__ -#include "priv.h" +/* SPDX-License-Identifier: MIT */ +#ifndef __NVKM_CGRP_H__ +#define __NVKM_CGRP_H__ +#include <core/os.h> +struct nvkm_chan; +struct nvkm_client; + +struct nvkm_vctx { + struct nvkm_ectx *ectx; + struct nvkm_vmm *vmm; + refcount_t refs; + + struct nvkm_gpuobj *inst; + struct nvkm_vma *vma; -struct nvkm_fifo_cgrp { - int id; struct list_head head; - struct list_head chan; +}; + +struct nvkm_ectx { + struct nvkm_engn *engn; + refcount_t refs; + refcount_t uses; + + struct nvkm_object *object; + + struct list_head head; +}; + +struct nvkm_cgrp { + const struct nvkm_cgrp_func { + void (*preempt)(struct nvkm_cgrp *); + } *func; + char name[64]; + struct nvkm_runl *runl; + struct nvkm_vmm *vmm; + bool hw; + int id; + struct kref kref; + + struct list_head chans; int chan_nr; + + spinlock_t lock; /* protects irq handler channel (group) lookup */ + + struct list_head ectxs; + struct list_head vctxs; + struct mutex mutex; + +#define NVKM_CGRP_RC_NONE 0 +#define NVKM_CGRP_RC_PENDING 1 +#define NVKM_CGRP_RC_RUNNING 2 + atomic_t rc; + + struct list_head head; }; + +int nvkm_cgrp_new(struct nvkm_runl *, const char *name, struct nvkm_vmm *, bool hw, + struct nvkm_cgrp **); +struct nvkm_cgrp *nvkm_cgrp_ref(struct nvkm_cgrp *); +void nvkm_cgrp_unref(struct nvkm_cgrp **); +int nvkm_cgrp_vctx_get(struct nvkm_cgrp *, struct nvkm_engn *, struct nvkm_chan *, + struct nvkm_vctx **, struct nvkm_client *); +void nvkm_cgrp_vctx_put(struct nvkm_cgrp *, struct nvkm_vctx **); + +void nvkm_cgrp_put(struct nvkm_cgrp **, unsigned long irqflags); + +#define nvkm_cgrp_foreach_chan(chan,cgrp) list_for_each_entry((chan), &(cgrp)->chans, head) +#define nvkm_cgrp_foreach_chan_safe(chan,ctmp,cgrp) \ + list_for_each_entry_safe((chan), (ctmp), &(cgrp)->chans, head) + +#define CGRP_PRCLI(c,l,p,f,a...) RUNL_PRINT((c)->runl, l, p, "%04x:[%s]"f, (c)->id, (c)->name, ##a) +#define CGRP_PRINT(c,l,p,f,a...) RUNL_PRINT((c)->runl, l, p, "%04x:"f, (c)->id, ##a) +#define CGRP_ERROR(c,f,a...) CGRP_PRCLI((c), ERROR, err, " "f"\n", ##a) +#define CGRP_TRACE(c,f,a...) CGRP_PRINT((c), TRACE, info, " "f"\n", ##a) #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c index 2e7f32cebf2a..b7c9d6115bce 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c @@ -22,285 +22,265 @@ * Authors: Ben Skeggs */ #include "chan.h" +#include "chid.h" +#include "cgrp.h" +#include "chid.h" +#include "runl.h" +#include "priv.h" -#include <core/client.h> -#include <core/gpuobj.h> -#include <core/oproxy.h> +#include <core/ramht.h> #include <subdev/mmu.h> #include <engine/dma.h> -struct nvkm_fifo_chan_object { - struct nvkm_oproxy oproxy; - struct nvkm_fifo_chan *chan; - int hash; +#include <nvif/if0020.h> + +const struct nvkm_event_func +nvkm_chan_event = { }; -static struct nvkm_fifo_engn * -nvkm_fifo_chan_engn(struct nvkm_fifo_chan *chan, struct nvkm_engine *engine) +void +nvkm_chan_cctx_bind(struct nvkm_chan *chan, struct nvkm_engn *engn, struct nvkm_cctx *cctx) { - int engi = chan->fifo->func->engine_id(chan->fifo, engine); - if (engi >= 0) - return &chan->engn[engi]; - return NULL; + struct nvkm_cgrp *cgrp = chan->cgrp; + struct nvkm_runl *runl = cgrp->runl; + struct nvkm_engine *engine = engn->engine; + + if (!engn->func->bind) + return; + + CHAN_TRACE(chan, "%sbind cctx %d[%s]", cctx ? "" : "un", engn->id, engine->subdev.name); + + /* Prevent any channel in channel group from being rescheduled, kick them + * off host and any engine(s) they're loaded on. + */ + if (cgrp->hw) + nvkm_runl_block(runl); + else + nvkm_chan_block(chan); + nvkm_chan_preempt(chan, true); + + /* Update context pointer. */ + engn->func->bind(engn, cctx, chan); + + /* Resume normal operation. */ + if (cgrp->hw) + nvkm_runl_allow(runl); + else + nvkm_chan_allow(chan); } -static int -nvkm_fifo_chan_child_fini(struct nvkm_oproxy *base, bool suspend) +void +nvkm_chan_cctx_put(struct nvkm_chan *chan, struct nvkm_cctx **pcctx) { - struct nvkm_fifo_chan_object *object = - container_of(base, typeof(*object), oproxy); - struct nvkm_engine *engine = object->oproxy.object->engine; - struct nvkm_fifo_chan *chan = object->chan; - struct nvkm_fifo_engn *engn = nvkm_fifo_chan_engn(chan, engine); - const char *name = engine->subdev.name; - int ret = 0; - - if (--engn->usecount) - return 0; + struct nvkm_cctx *cctx = *pcctx; - if (chan->func->engine_fini) { - ret = chan->func->engine_fini(chan, engine, suspend); - if (ret) { - nvif_error(&chan->object, - "detach %s failed, %d\n", name, ret); - return ret; + if (cctx) { + struct nvkm_engn *engn = cctx->vctx->ectx->engn; + + if (refcount_dec_and_mutex_lock(&cctx->refs, &chan->cgrp->mutex)) { + CHAN_TRACE(chan, "dtor cctx %d[%s]", engn->id, engn->engine->subdev.name); + nvkm_cgrp_vctx_put(chan->cgrp, &cctx->vctx); + list_del(&cctx->head); + kfree(cctx); + mutex_unlock(&chan->cgrp->mutex); } - } - if (engn->object) { - ret = nvkm_object_fini(engn->object, suspend); - if (ret && suspend) - return ret; + *pcctx = NULL; } - - nvif_trace(&chan->object, "detached %s\n", name); - return ret; } -static int -nvkm_fifo_chan_child_init(struct nvkm_oproxy *base) +int +nvkm_chan_cctx_get(struct nvkm_chan *chan, struct nvkm_engn *engn, struct nvkm_cctx **pcctx, + struct nvkm_client *client) { - struct nvkm_fifo_chan_object *object = - container_of(base, typeof(*object), oproxy); - struct nvkm_engine *engine = object->oproxy.object->engine; - struct nvkm_fifo_chan *chan = object->chan; - struct nvkm_fifo_engn *engn = nvkm_fifo_chan_engn(chan, engine); - const char *name = engine->subdev.name; + struct nvkm_cgrp *cgrp = chan->cgrp; + struct nvkm_vctx *vctx; + struct nvkm_cctx *cctx; int ret; - if (engn->usecount++) + /* Look for an existing channel context for this engine+VEID. */ + mutex_lock(&cgrp->mutex); + cctx = nvkm_list_find(cctx, &chan->cctxs, head, + cctx->vctx->ectx->engn == engn && cctx->vctx->vmm == chan->vmm); + if (cctx) { + refcount_inc(&cctx->refs); + *pcctx = cctx; + mutex_unlock(&chan->cgrp->mutex); return 0; + } - if (engn->object) { - ret = nvkm_object_init(engn->object); - if (ret) - return ret; + /* Nope - create a fresh one. But, sub-context first. */ + ret = nvkm_cgrp_vctx_get(cgrp, engn, chan, &vctx, client); + if (ret) { + CHAN_ERROR(chan, "vctx %d[%s]: %d", engn->id, engn->engine->subdev.name, ret); + goto done; } - if (chan->func->engine_init) { - ret = chan->func->engine_init(chan, engine); - if (ret) { - nvif_error(&chan->object, - "attach %s failed, %d\n", name, ret); - return ret; - } + /* Now, create the channel context - to track engine binding. */ + CHAN_TRACE(chan, "ctor cctx %d[%s]", engn->id, engn->engine->subdev.name); + if (!(cctx = *pcctx = kzalloc(sizeof(*cctx), GFP_KERNEL))) { + nvkm_cgrp_vctx_put(cgrp, &vctx); + ret = -ENOMEM; + goto done; } - nvif_trace(&chan->object, "attached %s\n", name); - return 0; + cctx->vctx = vctx; + refcount_set(&cctx->refs, 1); + refcount_set(&cctx->uses, 0); + list_add_tail(&cctx->head, &chan->cctxs); +done: + mutex_unlock(&cgrp->mutex); + return ret; } -static void -nvkm_fifo_chan_child_del(struct nvkm_oproxy *base) +int +nvkm_chan_preempt_locked(struct nvkm_chan *chan, bool wait) { - struct nvkm_fifo_chan_object *object = - container_of(base, typeof(*object), oproxy); - struct nvkm_engine *engine = object->oproxy.base.engine; - struct nvkm_fifo_chan *chan = object->chan; - struct nvkm_fifo_engn *engn = nvkm_fifo_chan_engn(chan, engine); - - if (chan->func->object_dtor) - chan->func->object_dtor(chan, object->hash); - - if (!--engn->refcount) { - if (chan->func->engine_dtor) - chan->func->engine_dtor(chan, engine); - nvkm_object_del(&engn->object); - if (chan->vmm) - atomic_dec(&chan->vmm->engref[engine->subdev.type]); - } -} + struct nvkm_runl *runl = chan->cgrp->runl; -static const struct nvkm_oproxy_func -nvkm_fifo_chan_child_func = { - .dtor[0] = nvkm_fifo_chan_child_del, - .init[0] = nvkm_fifo_chan_child_init, - .fini[0] = nvkm_fifo_chan_child_fini, -}; + CHAN_TRACE(chan, "preempt"); + chan->func->preempt(chan); + if (!wait) + return 0; + + return nvkm_runl_preempt_wait(runl); +} -static int -nvkm_fifo_chan_child_new(const struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nvkm_chan_preempt(struct nvkm_chan *chan, bool wait) { - struct nvkm_engine *engine = oclass->engine; - struct nvkm_fifo_chan *chan = nvkm_fifo_chan(oclass->parent); - struct nvkm_fifo_engn *engn = nvkm_fifo_chan_engn(chan, engine); - struct nvkm_fifo_chan_object *object; - int ret = 0; + int ret; - if (!(object = kzalloc(sizeof(*object), GFP_KERNEL))) - return -ENOMEM; - nvkm_oproxy_ctor(&nvkm_fifo_chan_child_func, oclass, &object->oproxy); - object->chan = chan; - *pobject = &object->oproxy.base; - - if (!engn->refcount++) { - struct nvkm_oclass cclass = { - .client = oclass->client, - .engine = oclass->engine, - }; - - if (chan->vmm) - atomic_inc(&chan->vmm->engref[engine->subdev.type]); - - if (engine->func->fifo.cclass) { - ret = engine->func->fifo.cclass(chan, &cclass, - &engn->object); - } else - if (engine->func->cclass) { - ret = nvkm_object_new_(engine->func->cclass, &cclass, - NULL, 0, &engn->object); - } - if (ret) - return ret; + if (!chan->func->preempt) + return 0; - if (chan->func->engine_ctor) { - ret = chan->func->engine_ctor(chan, oclass->engine, - engn->object); - if (ret) - return ret; - } - } + mutex_lock(&chan->cgrp->runl->mutex); + ret = nvkm_chan_preempt_locked(chan, wait); + mutex_unlock(&chan->cgrp->runl->mutex); + return ret; +} - ret = oclass->base.ctor(&(const struct nvkm_oclass) { - .base = oclass->base, - .engn = oclass->engn, - .handle = oclass->handle, - .object = oclass->object, - .client = oclass->client, - .parent = engn->object ? - engn->object : - oclass->parent, - .engine = engine, - }, data, size, &object->oproxy.object); - if (ret) - return ret; +void +nvkm_chan_remove_locked(struct nvkm_chan *chan) +{ + struct nvkm_cgrp *cgrp = chan->cgrp; + struct nvkm_runl *runl = cgrp->runl; - if (chan->func->object_ctor) { - object->hash = - chan->func->object_ctor(chan, object->oproxy.object); - if (object->hash < 0) - return object->hash; - } + if (list_empty(&chan->head)) + return; - return 0; + CHAN_TRACE(chan, "remove"); + if (!--cgrp->chan_nr) { + runl->cgrp_nr--; + list_del(&cgrp->head); + } + runl->chan_nr--; + list_del_init(&chan->head); + atomic_set(&runl->changed, 1); } -static int -nvkm_fifo_chan_child_get(struct nvkm_object *object, int index, - struct nvkm_oclass *oclass) +void +nvkm_chan_remove(struct nvkm_chan *chan, bool preempt) { - struct nvkm_fifo_chan *chan = nvkm_fifo_chan(object); - struct nvkm_fifo *fifo = chan->fifo; - struct nvkm_engine *engine; - u32 engm = chan->engm; - int engi, ret, c; - - for (; c = 0, engi = __ffs(engm), engm; engm &= ~(1ULL << engi)) { - if (!(engine = fifo->func->id_engine(fifo, engi))) - continue; - oclass->engine = engine; - oclass->base.oclass = 0; - - if (engine->func->fifo.sclass) { - ret = engine->func->fifo.sclass(oclass, index); - if (oclass->base.oclass) { - if (!oclass->base.ctor) - oclass->base.ctor = nvkm_object_new; - oclass->ctor = nvkm_fifo_chan_child_new; - return 0; - } + struct nvkm_runl *runl = chan->cgrp->runl; + + mutex_lock(&runl->mutex); + if (preempt && chan->func->preempt) + nvkm_chan_preempt_locked(chan, true); + nvkm_chan_remove_locked(chan); + nvkm_runl_update_locked(runl, true); + mutex_unlock(&runl->mutex); +} - index -= ret; - continue; - } +void +nvkm_chan_insert(struct nvkm_chan *chan) +{ + struct nvkm_cgrp *cgrp = chan->cgrp; + struct nvkm_runl *runl = cgrp->runl; - while (engine->func->sclass[c].oclass) { - if (c++ == index) { - oclass->base = engine->func->sclass[index]; - if (!oclass->base.ctor) - oclass->base.ctor = nvkm_object_new; - oclass->ctor = nvkm_fifo_chan_child_new; - return 0; - } - } - index -= c; + mutex_lock(&runl->mutex); + if (WARN_ON(!list_empty(&chan->head))) { + mutex_unlock(&runl->mutex); + return; } - return -EINVAL; + CHAN_TRACE(chan, "insert"); + list_add_tail(&chan->head, &cgrp->chans); + runl->chan_nr++; + if (!cgrp->chan_nr++) { + list_add_tail(&cgrp->head, &cgrp->runl->cgrps); + runl->cgrp_nr++; + } + atomic_set(&runl->changed, 1); + nvkm_runl_update_locked(runl, true); + mutex_unlock(&runl->mutex); } -static int -nvkm_fifo_chan_ntfy(struct nvkm_object *object, u32 type, - struct nvkm_event **pevent) +static void +nvkm_chan_block_locked(struct nvkm_chan *chan) { - struct nvkm_fifo_chan *chan = nvkm_fifo_chan(object); - if (chan->func->ntfy) - return chan->func->ntfy(chan, type, pevent); - return -ENODEV; + CHAN_TRACE(chan, "block %d", atomic_read(&chan->blocked)); + if (atomic_inc_return(&chan->blocked) == 1) + chan->func->stop(chan); } -static int -nvkm_fifo_chan_map(struct nvkm_object *object, void *argv, u32 argc, - enum nvkm_object_map *type, u64 *addr, u64 *size) +void +nvkm_chan_error(struct nvkm_chan *chan, bool preempt) { - struct nvkm_fifo_chan *chan = nvkm_fifo_chan(object); - *type = NVKM_OBJECT_MAP_IO; - *addr = chan->addr; - *size = chan->size; - return 0; + unsigned long flags; + + spin_lock_irqsave(&chan->lock, flags); + if (atomic_inc_return(&chan->errored) == 1) { + CHAN_ERROR(chan, "errored - disabling channel"); + nvkm_chan_block_locked(chan); + if (preempt) + chan->func->preempt(chan); + nvkm_event_ntfy(&chan->cgrp->runl->chid->event, chan->id, NVKM_CHAN_EVENT_ERRORED); + } + spin_unlock_irqrestore(&chan->lock, flags); } -static int -nvkm_fifo_chan_fini(struct nvkm_object *object, bool suspend) +void +nvkm_chan_block(struct nvkm_chan *chan) { - struct nvkm_fifo_chan *chan = nvkm_fifo_chan(object); - chan->func->fini(chan); - return 0; + spin_lock_irq(&chan->lock); + nvkm_chan_block_locked(chan); + spin_unlock_irq(&chan->lock); } -static int -nvkm_fifo_chan_init(struct nvkm_object *object) +void +nvkm_chan_allow(struct nvkm_chan *chan) { - struct nvkm_fifo_chan *chan = nvkm_fifo_chan(object); - chan->func->init(chan); - return 0; + spin_lock_irq(&chan->lock); + CHAN_TRACE(chan, "allow %d", atomic_read(&chan->blocked)); + if (atomic_dec_and_test(&chan->blocked)) + chan->func->start(chan); + spin_unlock_irq(&chan->lock); } -static void * -nvkm_fifo_chan_dtor(struct nvkm_object *object) +void +nvkm_chan_del(struct nvkm_chan **pchan) { - struct nvkm_fifo_chan *chan = nvkm_fifo_chan(object); - struct nvkm_fifo *fifo = chan->fifo; - void *data = chan->func->dtor(chan); - unsigned long flags; + struct nvkm_chan *chan = *pchan; + + if (!chan) + return; + + if (chan->func->ramfc->clear) + chan->func->ramfc->clear(chan); - spin_lock_irqsave(&fifo->lock, flags); - if (!list_empty(&chan->head)) { - __clear_bit(chan->chid, fifo->mask); - list_del(&chan->head); + nvkm_ramht_del(&chan->ramht); + nvkm_gpuobj_del(&chan->pgd); + nvkm_gpuobj_del(&chan->eng); + nvkm_gpuobj_del(&chan->cache); + nvkm_gpuobj_del(&chan->ramfc); + + nvkm_memory_unref(&chan->userd.mem); + + if (chan->cgrp) { + nvkm_chid_put(chan->cgrp->runl->chid, chan->id, &chan->cgrp->lock); + nvkm_cgrp_unref(&chan->cgrp); } - spin_unlock_irqrestore(&fifo->lock, flags); if (chan->vmm) { nvkm_vmm_part(chan->vmm, chan->inst->memory); @@ -309,85 +289,192 @@ nvkm_fifo_chan_dtor(struct nvkm_object *object) nvkm_gpuobj_del(&chan->push); nvkm_gpuobj_del(&chan->inst); - return data; + kfree(chan); } -static const struct nvkm_object_func -nvkm_fifo_chan_func = { - .dtor = nvkm_fifo_chan_dtor, - .init = nvkm_fifo_chan_init, - .fini = nvkm_fifo_chan_fini, - .ntfy = nvkm_fifo_chan_ntfy, - .map = nvkm_fifo_chan_map, - .sclass = nvkm_fifo_chan_child_get, -}; +void +nvkm_chan_put(struct nvkm_chan **pchan, unsigned long irqflags) +{ + struct nvkm_chan *chan = *pchan; + + if (!chan) + return; + + *pchan = NULL; + spin_unlock_irqrestore(&chan->cgrp->lock, irqflags); +} + +struct nvkm_chan * +nvkm_chan_get_inst(struct nvkm_engine *engine, u64 inst, unsigned long *pirqflags) +{ + struct nvkm_fifo *fifo = engine->subdev.device->fifo; + struct nvkm_runl *runl; + struct nvkm_engn *engn; + struct nvkm_chan *chan; + + nvkm_runl_foreach(runl, fifo) { + nvkm_runl_foreach_engn(engn, runl) { + if (engine == &fifo->engine || engn->engine == engine) { + chan = nvkm_runl_chan_get_inst(runl, inst, pirqflags); + if (chan || engn->engine == engine) + return chan; + } + } + } + + return NULL; +} + +struct nvkm_chan * +nvkm_chan_get_chid(struct nvkm_engine *engine, int id, unsigned long *pirqflags) +{ + struct nvkm_fifo *fifo = engine->subdev.device->fifo; + struct nvkm_runl *runl; + struct nvkm_engn *engn; + + nvkm_runl_foreach(runl, fifo) { + nvkm_runl_foreach_engn(engn, runl) { + if (fifo->chid || engn->engine == engine) + return nvkm_runl_chan_get_chid(runl, id, pirqflags); + } + } + + return NULL; +} int -nvkm_fifo_chan_ctor(const struct nvkm_fifo_chan_func *func, - struct nvkm_fifo *fifo, u32 size, u32 align, bool zero, - u64 hvmm, u64 push, u32 engm, int bar, u32 base, - u32 user, const struct nvkm_oclass *oclass, - struct nvkm_fifo_chan *chan) +nvkm_chan_new_(const struct nvkm_chan_func *func, struct nvkm_runl *runl, int runq, + struct nvkm_cgrp *cgrp, const char *name, bool priv, u32 devm, struct nvkm_vmm *vmm, + struct nvkm_dmaobj *dmaobj, u64 offset, u64 length, + struct nvkm_memory *userd, u64 ouserd, struct nvkm_chan **pchan) { - struct nvkm_client *client = oclass->client; + struct nvkm_fifo *fifo = runl->fifo; struct nvkm_device *device = fifo->engine.subdev.device; - struct nvkm_dmaobj *dmaobj; - unsigned long flags; + struct nvkm_chan *chan; int ret; - nvkm_object_ctor(&nvkm_fifo_chan_func, oclass, &chan->object); + /* Validate arguments against class requirements. */ + if ((runq && runq >= runl->func->runqs) || + (!func->inst->vmm != !vmm) || + ((func->userd->bar < 0) == !userd) || + (!func->ramfc->ctxdma != !dmaobj) || + ((func->ramfc->devm < devm) && devm != BIT(0)) || + (!func->ramfc->priv && priv)) { + RUNL_DEBUG(runl, "args runq:%d:%d vmm:%d:%p userd:%d:%p " + "push:%d:%p devm:%08x:%08x priv:%d:%d", + runl->func->runqs, runq, func->inst->vmm, vmm, + func->userd->bar < 0, userd, func->ramfc->ctxdma, dmaobj, + func->ramfc->devm, devm, func->ramfc->priv, priv); + return -EINVAL; + } + + if (!(chan = *pchan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + chan->func = func; - chan->fifo = fifo; - chan->engm = engm; + strscpy(chan->name, name, sizeof(chan->name)); + chan->runq = runq; + chan->id = -1; + spin_lock_init(&chan->lock); + atomic_set(&chan->blocked, 1); + atomic_set(&chan->errored, 0); + INIT_LIST_HEAD(&chan->cctxs); INIT_LIST_HEAD(&chan->head); - /* instance memory */ - ret = nvkm_gpuobj_new(device, size, align, zero, NULL, &chan->inst); - if (ret) - return ret; + /* Join channel group. + * + * GK110 and newer support channel groups (aka TSGs), where individual channels + * share a timeslice, and, engine context(s). + * + * As such, engine contexts are tracked in nvkm_cgrp and we need them even when + * channels aren't in an API channel group, and on HW that doesn't support TSGs. + */ + if (!cgrp) { + ret = nvkm_cgrp_new(runl, chan->name, vmm, fifo->func->cgrp.force, &chan->cgrp); + if (ret) { + RUNL_DEBUG(runl, "cgrp %d", ret); + return ret; + } - /* allocate push buffer ctxdma instance */ - if (push) { - dmaobj = nvkm_dmaobj_search(client, push); - if (IS_ERR(dmaobj)) - return PTR_ERR(dmaobj); + cgrp = chan->cgrp; + } else { + if (cgrp->runl != runl || cgrp->vmm != vmm) { + RUNL_DEBUG(runl, "cgrp %d %d", cgrp->runl != runl, cgrp->vmm != vmm); + return -EINVAL; + } - ret = nvkm_object_bind(&dmaobj->object, chan->inst, -16, - &chan->push); - if (ret) - return ret; + chan->cgrp = nvkm_cgrp_ref(cgrp); } - /* channel address space */ - if (hvmm) { - struct nvkm_vmm *vmm = nvkm_uvmm_search(client, hvmm); - if (IS_ERR(vmm)) - return PTR_ERR(vmm); + /* Allocate instance block. */ + ret = nvkm_gpuobj_new(device, func->inst->size, 0x1000, func->inst->zero, NULL, + &chan->inst); + if (ret) { + RUNL_DEBUG(runl, "inst %d", ret); + return ret; + } - if (vmm->mmu != device->mmu) + /* Initialise virtual address-space. */ + if (func->inst->vmm) { + if (WARN_ON(vmm->mmu != device->mmu)) return -EINVAL; ret = nvkm_vmm_join(vmm, chan->inst->memory); - if (ret) + if (ret) { + RUNL_DEBUG(runl, "vmm %d", ret); return ret; + } chan->vmm = nvkm_vmm_ref(vmm); } - /* allocate channel id */ - spin_lock_irqsave(&fifo->lock, flags); - chan->chid = find_first_zero_bit(fifo->mask, NVKM_FIFO_CHID_NR); - if (chan->chid >= NVKM_FIFO_CHID_NR) { - spin_unlock_irqrestore(&fifo->lock, flags); + /* Allocate HW ctxdma for push buffer. */ + if (func->ramfc->ctxdma) { + ret = nvkm_object_bind(&dmaobj->object, chan->inst, -16, &chan->push); + if (ret) { + RUNL_DEBUG(runl, "bind %d", ret); + return ret; + } + } + + /* Allocate channel ID. */ + chan->id = nvkm_chid_get(runl->chid, chan); + if (chan->id < 0) { + RUNL_ERROR(runl, "!chids"); return -ENOSPC; } - list_add(&chan->head, &fifo->chan); - __set_bit(chan->chid, fifo->mask); - spin_unlock_irqrestore(&fifo->lock, flags); - - /* determine address of this channel's user registers */ - chan->addr = device->func->resource_addr(device, bar) + - base + user * chan->chid; - chan->size = user; + + if (cgrp->id < 0) + cgrp->id = chan->id; + + /* Initialise USERD. */ + if (func->userd->bar < 0) { + if (ouserd + chan->func->userd->size >= nvkm_memory_size(userd)) { + RUNL_DEBUG(runl, "ouserd %llx", ouserd); + return -EINVAL; + } + + ret = nvkm_memory_kmap(userd, &chan->userd.mem); + if (ret) { + RUNL_DEBUG(runl, "userd %d", ret); + return ret; + } + + chan->userd.base = ouserd; + } else { + chan->userd.mem = nvkm_memory_ref(fifo->userd.mem); + chan->userd.base = chan->id * chan->func->userd->size; + } + + if (chan->func->userd->clear) + chan->func->userd->clear(chan); + + /* Initialise RAMFC. */ + ret = chan->func->ramfc->write(chan, offset, length, devm, priv); + if (ret) { + RUNL_DEBUG(runl, "ramfc %d", ret); + return ret; + } + return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.h index e53504354841..85b94f699128 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.h @@ -1,35 +1,78 @@ /* SPDX-License-Identifier: MIT */ -#ifndef __NVKM_FIFO_CHAN_H__ -#define __NVKM_FIFO_CHAN_H__ -#define nvkm_fifo_chan(p) container_of((p), struct nvkm_fifo_chan, object) -#include "priv.h" - -struct nvkm_fifo_chan_func { - void *(*dtor)(struct nvkm_fifo_chan *); - void (*init)(struct nvkm_fifo_chan *); - void (*fini)(struct nvkm_fifo_chan *); - int (*ntfy)(struct nvkm_fifo_chan *, u32 type, struct nvkm_event **); - int (*engine_ctor)(struct nvkm_fifo_chan *, struct nvkm_engine *, - struct nvkm_object *); - void (*engine_dtor)(struct nvkm_fifo_chan *, struct nvkm_engine *); - int (*engine_init)(struct nvkm_fifo_chan *, struct nvkm_engine *); - int (*engine_fini)(struct nvkm_fifo_chan *, struct nvkm_engine *, - bool suspend); - int (*object_ctor)(struct nvkm_fifo_chan *, struct nvkm_object *); - void (*object_dtor)(struct nvkm_fifo_chan *, int); - u32 (*submit_token)(struct nvkm_fifo_chan *); +#ifndef __NVKM_CHAN_H__ +#define __NVKM_CHAN_H__ +#include <engine/fifo.h> +struct nvkm_dmaobj; +struct nvkm_engn; +struct nvkm_runl; + +extern const struct nvkm_event_func nvkm_chan_event; + +struct nvkm_cctx { + struct nvkm_vctx *vctx; + refcount_t refs; + refcount_t uses; + + struct list_head head; }; -int nvkm_fifo_chan_ctor(const struct nvkm_fifo_chan_func *, struct nvkm_fifo *, - u32 size, u32 align, bool zero, u64 vm, u64 push, - u32 engm, int bar, u32 base, u32 user, - const struct nvkm_oclass *, struct nvkm_fifo_chan *); +struct nvkm_chan_func { + const struct nvkm_chan_func_inst { + u32 size; + bool zero; + bool vmm; + } *inst; -struct nvkm_fifo_chan_oclass { - int (*ctor)(struct nvkm_fifo *, const struct nvkm_oclass *, - void *data, u32 size, struct nvkm_object **); - struct nvkm_sclass base; + const struct nvkm_chan_func_userd { + int bar; + u32 base; + u32 size; + void (*clear)(struct nvkm_chan *); + } *userd; + + const struct nvkm_chan_func_ramfc { + const struct nvkm_ramfc_layout { + unsigned bits:6; + unsigned ctxs:5; + unsigned ctxp:8; + unsigned regs:5; + unsigned regp; + } *layout; + int (*write)(struct nvkm_chan *, u64 offset, u64 length, u32 devm, bool priv); + void (*clear)(struct nvkm_chan *); + bool ctxdma; + u32 devm; + bool priv; + } *ramfc; + + void (*bind)(struct nvkm_chan *); + void (*unbind)(struct nvkm_chan *); + void (*start)(struct nvkm_chan *); + void (*stop)(struct nvkm_chan *); + void (*preempt)(struct nvkm_chan *); + u32 (*doorbell_handle)(struct nvkm_chan *); }; -int gf100_fifo_chan_ntfy(struct nvkm_fifo_chan *, u32, struct nvkm_event **); +int nvkm_chan_new_(const struct nvkm_chan_func *, struct nvkm_runl *, int runq, struct nvkm_cgrp *, + const char *name, bool priv, u32 devm, struct nvkm_vmm *, struct nvkm_dmaobj *, + u64 offset, u64 length, struct nvkm_memory *userd, u64 userd_bar1, + struct nvkm_chan **); +void nvkm_chan_del(struct nvkm_chan **); +void nvkm_chan_allow(struct nvkm_chan *); +void nvkm_chan_block(struct nvkm_chan *); +void nvkm_chan_error(struct nvkm_chan *, bool preempt); +void nvkm_chan_insert(struct nvkm_chan *); +void nvkm_chan_remove(struct nvkm_chan *, bool preempt); +void nvkm_chan_remove_locked(struct nvkm_chan *); +int nvkm_chan_preempt(struct nvkm_chan *, bool wait); +int nvkm_chan_preempt_locked(struct nvkm_chan *, bool wait); +int nvkm_chan_cctx_get(struct nvkm_chan *, struct nvkm_engn *, struct nvkm_cctx **, + struct nvkm_client * /*TODO: remove need for this */); +void nvkm_chan_cctx_put(struct nvkm_chan *, struct nvkm_cctx **); +void nvkm_chan_cctx_bind(struct nvkm_chan *, struct nvkm_engn *, struct nvkm_cctx *); + +#define CHAN_PRCLI(c,l,p,f,a...) CGRP_PRINT((c)->cgrp, l, p, "%04x:[%s]"f, (c)->id, (c)->name, ##a) +#define CHAN_PRINT(c,l,p,f,a...) CGRP_PRINT((c)->cgrp, l, p, "%04x:"f, (c)->id, ##a) +#define CHAN_ERROR(c,f,a...) CHAN_PRCLI((c), ERROR, err, " "f"\n", ##a) +#define CHAN_TRACE(c,f,a...) CHAN_PRINT((c), TRACE, info, " "f"\n", ##a) #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chang84.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chang84.c deleted file mode 100644 index 3492c561f2cf..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chang84.c +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright 2012 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. - * - * Authors: Ben Skeggs - */ -#include "channv50.h" - -#include <core/client.h> -#include <core/ramht.h> -#include <subdev/mmu.h> -#include <subdev/timer.h> - -#include <nvif/cl826e.h> - -static int -g84_fifo_chan_ntfy(struct nvkm_fifo_chan *chan, u32 type, - struct nvkm_event **pevent) -{ - switch (type) { - case NV826E_V0_NTFY_NON_STALL_INTERRUPT: - *pevent = &chan->fifo->uevent; - return 0; - default: - break; - } - return -EINVAL; -} - -static int -g84_fifo_chan_engine_addr(struct nvkm_engine *engine) -{ - switch (engine->subdev.type) { - case NVKM_ENGINE_DMAOBJ: - case NVKM_ENGINE_SW : return -1; - case NVKM_ENGINE_GR : return 0x0020; - case NVKM_ENGINE_VP : - case NVKM_ENGINE_MSPDEC: return 0x0040; - case NVKM_ENGINE_MPEG : - case NVKM_ENGINE_MSPPP : return 0x0060; - case NVKM_ENGINE_BSP : - case NVKM_ENGINE_MSVLD : return 0x0080; - case NVKM_ENGINE_CIPHER: - case NVKM_ENGINE_SEC : return 0x00a0; - case NVKM_ENGINE_CE : return 0x00c0; - default: - WARN_ON(1); - return -1; - } -} - -static int -g84_fifo_chan_engine_fini(struct nvkm_fifo_chan *base, - struct nvkm_engine *engine, bool suspend) -{ - struct nv50_fifo_chan *chan = nv50_fifo_chan(base); - struct nv50_fifo *fifo = chan->fifo; - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; - struct nvkm_device *device = subdev->device; - u32 engn, save; - int offset; - bool done; - - offset = g84_fifo_chan_engine_addr(engine); - if (offset < 0) - return 0; - - engn = fifo->base.func->engine_id(&fifo->base, engine) - 1; - save = nvkm_mask(device, 0x002520, 0x0000003f, 1 << engn); - nvkm_wr32(device, 0x0032fc, chan->base.inst->addr >> 12); - done = nvkm_msec(device, 2000, - if (nvkm_rd32(device, 0x0032fc) != 0xffffffff) - break; - ) >= 0; - nvkm_wr32(device, 0x002520, save); - if (!done) { - nvkm_error(subdev, "channel %d [%s] unload timeout\n", - chan->base.chid, chan->base.object.client->name); - if (suspend) - return -EBUSY; - } - - nvkm_kmap(chan->eng); - nvkm_wo32(chan->eng, offset + 0x00, 0x00000000); - nvkm_wo32(chan->eng, offset + 0x04, 0x00000000); - nvkm_wo32(chan->eng, offset + 0x08, 0x00000000); - nvkm_wo32(chan->eng, offset + 0x0c, 0x00000000); - nvkm_wo32(chan->eng, offset + 0x10, 0x00000000); - nvkm_wo32(chan->eng, offset + 0x14, 0x00000000); - nvkm_done(chan->eng); - return 0; -} - - -static int -g84_fifo_chan_engine_init(struct nvkm_fifo_chan *base, - struct nvkm_engine *engine) -{ - struct nv50_fifo_chan *chan = nv50_fifo_chan(base); - struct nvkm_gpuobj *engn = *nv50_fifo_chan_engine(chan, engine); - u64 limit, start; - int offset; - - offset = g84_fifo_chan_engine_addr(engine); - if (offset < 0) - return 0; - limit = engn->addr + engn->size - 1; - start = engn->addr; - - nvkm_kmap(chan->eng); - nvkm_wo32(chan->eng, offset + 0x00, 0x00190000); - nvkm_wo32(chan->eng, offset + 0x04, lower_32_bits(limit)); - nvkm_wo32(chan->eng, offset + 0x08, lower_32_bits(start)); - nvkm_wo32(chan->eng, offset + 0x0c, upper_32_bits(limit) << 24 | - upper_32_bits(start)); - nvkm_wo32(chan->eng, offset + 0x10, 0x00000000); - nvkm_wo32(chan->eng, offset + 0x14, 0x00000000); - nvkm_done(chan->eng); - return 0; -} - -static int -g84_fifo_chan_engine_ctor(struct nvkm_fifo_chan *base, - struct nvkm_engine *engine, - struct nvkm_object *object) -{ - struct nv50_fifo_chan *chan = nv50_fifo_chan(base); - - if (g84_fifo_chan_engine_addr(engine) < 0) - return 0; - - return nvkm_object_bind(object, NULL, 0, nv50_fifo_chan_engine(chan, engine)); -} - -static int -g84_fifo_chan_object_ctor(struct nvkm_fifo_chan *base, - struct nvkm_object *object) -{ - struct nv50_fifo_chan *chan = nv50_fifo_chan(base); - u32 handle = object->handle; - u32 context; - - switch (object->engine->subdev.type) { - case NVKM_ENGINE_DMAOBJ: - case NVKM_ENGINE_SW : context = 0x00000000; break; - case NVKM_ENGINE_GR : context = 0x00100000; break; - case NVKM_ENGINE_MPEG : - case NVKM_ENGINE_MSPPP : context = 0x00200000; break; - case NVKM_ENGINE_ME : - case NVKM_ENGINE_CE : context = 0x00300000; break; - case NVKM_ENGINE_VP : - case NVKM_ENGINE_MSPDEC: context = 0x00400000; break; - case NVKM_ENGINE_CIPHER: - case NVKM_ENGINE_SEC : - case NVKM_ENGINE_VIC : context = 0x00500000; break; - case NVKM_ENGINE_BSP : - case NVKM_ENGINE_MSVLD : context = 0x00600000; break; - default: - WARN_ON(1); - return -EINVAL; - } - - return nvkm_ramht_insert(chan->ramht, object, 0, 4, handle, context); -} - -static void -g84_fifo_chan_init(struct nvkm_fifo_chan *base) -{ - struct nv50_fifo_chan *chan = nv50_fifo_chan(base); - struct nv50_fifo *fifo = chan->fifo; - struct nvkm_device *device = fifo->base.engine.subdev.device; - u64 addr = chan->ramfc->addr >> 8; - u32 chid = chan->base.chid; - - nvkm_wr32(device, 0x002600 + (chid * 4), 0x80000000 | addr); - nv50_fifo_runlist_update(fifo); -} - -static const struct nvkm_fifo_chan_func -g84_fifo_chan_func = { - .dtor = nv50_fifo_chan_dtor, - .init = g84_fifo_chan_init, - .fini = nv50_fifo_chan_fini, - .ntfy = g84_fifo_chan_ntfy, - .engine_ctor = g84_fifo_chan_engine_ctor, - .engine_dtor = nv50_fifo_chan_engine_dtor, - .engine_init = g84_fifo_chan_engine_init, - .engine_fini = g84_fifo_chan_engine_fini, - .object_ctor = g84_fifo_chan_object_ctor, - .object_dtor = nv50_fifo_chan_object_dtor, -}; - -int -g84_fifo_chan_ctor(struct nv50_fifo *fifo, u64 vmm, u64 push, - const struct nvkm_oclass *oclass, - struct nv50_fifo_chan *chan) -{ - struct nvkm_device *device = fifo->base.engine.subdev.device; - int ret; - - if (!vmm) - return -EINVAL; - - ret = nvkm_fifo_chan_ctor(&g84_fifo_chan_func, &fifo->base, - 0x10000, 0x1000, false, vmm, push, - BIT(G84_FIFO_ENGN_SW) | - BIT(G84_FIFO_ENGN_GR) | - BIT(G84_FIFO_ENGN_MPEG) | - BIT(G84_FIFO_ENGN_MSPPP) | - BIT(G84_FIFO_ENGN_ME) | - BIT(G84_FIFO_ENGN_CE0) | - BIT(G84_FIFO_ENGN_VP) | - BIT(G84_FIFO_ENGN_MSPDEC) | - BIT(G84_FIFO_ENGN_CIPHER) | - BIT(G84_FIFO_ENGN_SEC) | - BIT(G84_FIFO_ENGN_VIC) | - BIT(G84_FIFO_ENGN_BSP) | - BIT(G84_FIFO_ENGN_MSVLD) | - BIT(G84_FIFO_ENGN_DMA), - 0, 0xc00000, 0x2000, oclass, &chan->base); - chan->fifo = fifo; - if (ret) - return ret; - - ret = nvkm_gpuobj_new(device, 0x0200, 0, true, chan->base.inst, - &chan->eng); - if (ret) - return ret; - - ret = nvkm_gpuobj_new(device, 0x4000, 0, false, chan->base.inst, - &chan->pgd); - if (ret) - return ret; - - ret = nvkm_gpuobj_new(device, 0x1000, 0x400, true, chan->base.inst, - &chan->cache); - if (ret) - return ret; - - ret = nvkm_gpuobj_new(device, 0x100, 0x100, true, chan->base.inst, - &chan->ramfc); - if (ret) - return ret; - - return nvkm_ramht_new(device, 0x8000, 16, chan->base.inst, &chan->ramht); -} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changf100.h deleted file mode 100644 index f7ac1061fa84..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changf100.h +++ /dev/null @@ -1,29 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -#ifndef __GF100_FIFO_CHAN_H__ -#define __GF100_FIFO_CHAN_H__ -#define gf100_fifo_chan(p) container_of((p), struct gf100_fifo_chan, base) -#include "chan.h" -#include "gf100.h" - -struct gf100_fifo_chan { - struct nvkm_fifo_chan base; - struct gf100_fifo *fifo; - - struct list_head head; - bool killed; - -#define GF100_FIFO_ENGN_GR 0 -#define GF100_FIFO_ENGN_MSPDEC 1 -#define GF100_FIFO_ENGN_MSPPP 2 -#define GF100_FIFO_ENGN_MSVLD 3 -#define GF100_FIFO_ENGN_CE0 4 -#define GF100_FIFO_ENGN_CE1 5 -#define GF100_FIFO_ENGN_SW 15 - struct gf100_fifo_engn { - struct nvkm_gpuobj *inst; - struct nvkm_vma *vma; - } engn[NVKM_FIFO_ENGN_NR]; -}; - -extern const struct nvkm_fifo_chan_oclass gf100_fifo_gpfifo_oclass; -#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changk104.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changk104.h deleted file mode 100644 index 9713daee6c76..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changk104.h +++ /dev/null @@ -1,52 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -#ifndef __GK104_FIFO_CHAN_H__ -#define __GK104_FIFO_CHAN_H__ -#define gk104_fifo_chan(p) container_of((p), struct gk104_fifo_chan, base) -#include "chan.h" -#include "gk104.h" - -struct gk104_fifo_chan { - struct nvkm_fifo_chan base; - struct gk104_fifo *fifo; - int runl; - - struct nvkm_fifo_cgrp *cgrp; - struct list_head head; - bool killed; - -#define GK104_FIFO_ENGN_SW 15 - struct gk104_fifo_engn { - struct nvkm_gpuobj *inst; - struct nvkm_vma *vma; - } engn[NVKM_FIFO_ENGN_NR]; -}; - -extern const struct nvkm_fifo_chan_func gk104_fifo_gpfifo_func; - -int gk104_fifo_gpfifo_new(struct gk104_fifo *, const struct nvkm_oclass *, - void *data, u32 size, struct nvkm_object **); -void *gk104_fifo_gpfifo_dtor(struct nvkm_fifo_chan *); -void gk104_fifo_gpfifo_init(struct nvkm_fifo_chan *); -void gk104_fifo_gpfifo_fini(struct nvkm_fifo_chan *); -struct gk104_fifo_engn *gk104_fifo_gpfifo_engine(struct gk104_fifo_chan *, struct nvkm_engine *); -int gk104_fifo_gpfifo_engine_ctor(struct nvkm_fifo_chan *, struct nvkm_engine *, - struct nvkm_object *); -void gk104_fifo_gpfifo_engine_dtor(struct nvkm_fifo_chan *, - struct nvkm_engine *); -int gk104_fifo_gpfifo_kick(struct gk104_fifo_chan *); -int gk104_fifo_gpfifo_kick_locked(struct gk104_fifo_chan *); - -int gv100_fifo_gpfifo_new(struct gk104_fifo *, const struct nvkm_oclass *, - void *data, u32 size, struct nvkm_object **); -int gv100_fifo_gpfifo_new_(const struct nvkm_fifo_chan_func *, - struct gk104_fifo *, u64 *, u16 *, u64, u64, u64, - u64 *, bool, u32 *, const struct nvkm_oclass *, - struct nvkm_object **); -int gv100_fifo_gpfifo_engine_init(struct nvkm_fifo_chan *, - struct nvkm_engine *); -int gv100_fifo_gpfifo_engine_fini(struct nvkm_fifo_chan *, - struct nvkm_engine *, bool); - -int tu102_fifo_gpfifo_new(struct gk104_fifo *, const struct nvkm_oclass *, - void *data, u32 size, struct nvkm_object **); -#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv04.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv04.h deleted file mode 100644 index 727bc8976b40..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv04.h +++ /dev/null @@ -1,29 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -#ifndef __NV04_FIFO_CHAN_H__ -#define __NV04_FIFO_CHAN_H__ -#define nv04_fifo_chan(p) container_of((p), struct nv04_fifo_chan, base) -#include "chan.h" -#include "nv04.h" - -struct nv04_fifo_chan { - struct nvkm_fifo_chan base; - struct nv04_fifo *fifo; - u32 ramfc; -#define NV04_FIFO_ENGN_SW 0 -#define NV04_FIFO_ENGN_GR 1 -#define NV04_FIFO_ENGN_MPEG 2 -#define NV04_FIFO_ENGN_DMA 3 - struct nvkm_gpuobj *engn[NVKM_FIFO_ENGN_NR]; -}; - -extern const struct nvkm_fifo_chan_func nv04_fifo_dma_func; -void *nv04_fifo_dma_dtor(struct nvkm_fifo_chan *); -void nv04_fifo_dma_init(struct nvkm_fifo_chan *); -void nv04_fifo_dma_fini(struct nvkm_fifo_chan *); -void nv04_fifo_dma_object_dtor(struct nvkm_fifo_chan *, int); - -extern const struct nvkm_fifo_chan_oclass nv04_fifo_dma_oclass; -extern const struct nvkm_fifo_chan_oclass nv10_fifo_dma_oclass; -extern const struct nvkm_fifo_chan_oclass nv17_fifo_dma_oclass; -extern const struct nvkm_fifo_chan_oclass nv40_fifo_dma_oclass; -#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.c deleted file mode 100644 index c44d7c81dd52..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.c +++ /dev/null @@ -1,276 +0,0 @@ -/* - * Copyright 2012 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. - * - * Authors: Ben Skeggs - */ -#include "channv50.h" - -#include <core/client.h> -#include <core/ramht.h> -#include <subdev/mmu.h> -#include <subdev/timer.h> - -static int -nv50_fifo_chan_engine_addr(struct nvkm_engine *engine) -{ - switch (engine->subdev.type) { - case NVKM_ENGINE_DMAOBJ: - case NVKM_ENGINE_SW : return -1; - case NVKM_ENGINE_GR : return 0x0000; - case NVKM_ENGINE_MPEG : return 0x0060; - default: - WARN_ON(1); - return -1; - } -} - -struct nvkm_gpuobj ** -nv50_fifo_chan_engine(struct nv50_fifo_chan *chan, struct nvkm_engine *engine) -{ - int engi = chan->base.fifo->func->engine_id(chan->base.fifo, engine); - if (engi >= 0) - return &chan->engn[engi]; - return NULL; -} - -static int -nv50_fifo_chan_engine_fini(struct nvkm_fifo_chan *base, - struct nvkm_engine *engine, bool suspend) -{ - struct nv50_fifo_chan *chan = nv50_fifo_chan(base); - struct nv50_fifo *fifo = chan->fifo; - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; - struct nvkm_device *device = subdev->device; - int offset, ret = 0; - u32 me; - - offset = nv50_fifo_chan_engine_addr(engine); - if (offset < 0) - return 0; - - /* HW bug workaround: - * - * PFIFO will hang forever if the connected engines don't report - * that they've processed the context switch request. - * - * In order for the kickoff to work, we need to ensure all the - * connected engines are in a state where they can answer. - * - * Newer chipsets don't seem to suffer from this issue, and well, - * there's also a "ignore these engines" bitmask reg we can use - * if we hit the issue there.. - */ - me = nvkm_mask(device, 0x00b860, 0x00000001, 0x00000001); - - /* do the kickoff... */ - nvkm_wr32(device, 0x0032fc, chan->base.inst->addr >> 12); - if (nvkm_msec(device, 2000, - if (nvkm_rd32(device, 0x0032fc) != 0xffffffff) - break; - ) < 0) { - nvkm_error(subdev, "channel %d [%s] unload timeout\n", - chan->base.chid, chan->base.object.client->name); - if (suspend) - ret = -EBUSY; - } - nvkm_wr32(device, 0x00b860, me); - - if (ret == 0) { - nvkm_kmap(chan->eng); - nvkm_wo32(chan->eng, offset + 0x00, 0x00000000); - nvkm_wo32(chan->eng, offset + 0x04, 0x00000000); - nvkm_wo32(chan->eng, offset + 0x08, 0x00000000); - nvkm_wo32(chan->eng, offset + 0x0c, 0x00000000); - nvkm_wo32(chan->eng, offset + 0x10, 0x00000000); - nvkm_wo32(chan->eng, offset + 0x14, 0x00000000); - nvkm_done(chan->eng); - } - - return ret; -} - -static int -nv50_fifo_chan_engine_init(struct nvkm_fifo_chan *base, - struct nvkm_engine *engine) -{ - struct nv50_fifo_chan *chan = nv50_fifo_chan(base); - struct nvkm_gpuobj *engn = *nv50_fifo_chan_engine(chan, engine); - u64 limit, start; - int offset; - - offset = nv50_fifo_chan_engine_addr(engine); - if (offset < 0) - return 0; - limit = engn->addr + engn->size - 1; - start = engn->addr; - - nvkm_kmap(chan->eng); - nvkm_wo32(chan->eng, offset + 0x00, 0x00190000); - nvkm_wo32(chan->eng, offset + 0x04, lower_32_bits(limit)); - nvkm_wo32(chan->eng, offset + 0x08, lower_32_bits(start)); - nvkm_wo32(chan->eng, offset + 0x0c, upper_32_bits(limit) << 24 | - upper_32_bits(start)); - nvkm_wo32(chan->eng, offset + 0x10, 0x00000000); - nvkm_wo32(chan->eng, offset + 0x14, 0x00000000); - nvkm_done(chan->eng); - return 0; -} - -void -nv50_fifo_chan_engine_dtor(struct nvkm_fifo_chan *base, - struct nvkm_engine *engine) -{ - struct nv50_fifo_chan *chan = nv50_fifo_chan(base); - nvkm_gpuobj_del(nv50_fifo_chan_engine(chan, engine)); -} - -static int -nv50_fifo_chan_engine_ctor(struct nvkm_fifo_chan *base, - struct nvkm_engine *engine, - struct nvkm_object *object) -{ - struct nv50_fifo_chan *chan = nv50_fifo_chan(base); - - if (nv50_fifo_chan_engine_addr(engine) < 0) - return 0; - - return nvkm_object_bind(object, NULL, 0, nv50_fifo_chan_engine(chan, engine)); -} - -void -nv50_fifo_chan_object_dtor(struct nvkm_fifo_chan *base, int cookie) -{ - struct nv50_fifo_chan *chan = nv50_fifo_chan(base); - nvkm_ramht_remove(chan->ramht, cookie); -} - -static int -nv50_fifo_chan_object_ctor(struct nvkm_fifo_chan *base, - struct nvkm_object *object) -{ - struct nv50_fifo_chan *chan = nv50_fifo_chan(base); - u32 handle = object->handle; - u32 context; - - switch (object->engine->subdev.type) { - case NVKM_ENGINE_DMAOBJ: - case NVKM_ENGINE_SW : context = 0x00000000; break; - case NVKM_ENGINE_GR : context = 0x00100000; break; - case NVKM_ENGINE_MPEG : context = 0x00200000; break; - default: - WARN_ON(1); - return -EINVAL; - } - - return nvkm_ramht_insert(chan->ramht, object, 0, 4, handle, context); -} - -void -nv50_fifo_chan_fini(struct nvkm_fifo_chan *base) -{ - struct nv50_fifo_chan *chan = nv50_fifo_chan(base); - struct nv50_fifo *fifo = chan->fifo; - struct nvkm_device *device = fifo->base.engine.subdev.device; - u32 chid = chan->base.chid; - - /* remove channel from runlist, fifo will unload context */ - nvkm_mask(device, 0x002600 + (chid * 4), 0x80000000, 0x00000000); - nv50_fifo_runlist_update(fifo); - nvkm_wr32(device, 0x002600 + (chid * 4), 0x00000000); -} - -static void -nv50_fifo_chan_init(struct nvkm_fifo_chan *base) -{ - struct nv50_fifo_chan *chan = nv50_fifo_chan(base); - struct nv50_fifo *fifo = chan->fifo; - struct nvkm_device *device = fifo->base.engine.subdev.device; - u64 addr = chan->ramfc->addr >> 12; - u32 chid = chan->base.chid; - - nvkm_wr32(device, 0x002600 + (chid * 4), 0x80000000 | addr); - nv50_fifo_runlist_update(fifo); -} - -void * -nv50_fifo_chan_dtor(struct nvkm_fifo_chan *base) -{ - struct nv50_fifo_chan *chan = nv50_fifo_chan(base); - nvkm_ramht_del(&chan->ramht); - nvkm_gpuobj_del(&chan->pgd); - nvkm_gpuobj_del(&chan->eng); - nvkm_gpuobj_del(&chan->cache); - nvkm_gpuobj_del(&chan->ramfc); - return chan; -} - -static const struct nvkm_fifo_chan_func -nv50_fifo_chan_func = { - .dtor = nv50_fifo_chan_dtor, - .init = nv50_fifo_chan_init, - .fini = nv50_fifo_chan_fini, - .engine_ctor = nv50_fifo_chan_engine_ctor, - .engine_dtor = nv50_fifo_chan_engine_dtor, - .engine_init = nv50_fifo_chan_engine_init, - .engine_fini = nv50_fifo_chan_engine_fini, - .object_ctor = nv50_fifo_chan_object_ctor, - .object_dtor = nv50_fifo_chan_object_dtor, -}; - -int -nv50_fifo_chan_ctor(struct nv50_fifo *fifo, u64 vmm, u64 push, - const struct nvkm_oclass *oclass, - struct nv50_fifo_chan *chan) -{ - struct nvkm_device *device = fifo->base.engine.subdev.device; - int ret; - - if (!vmm) - return -EINVAL; - - ret = nvkm_fifo_chan_ctor(&nv50_fifo_chan_func, &fifo->base, - 0x10000, 0x1000, false, vmm, push, - BIT(NV50_FIFO_ENGN_SW) | - BIT(NV50_FIFO_ENGN_GR) | - BIT(NV50_FIFO_ENGN_MPEG) | - BIT(NV50_FIFO_ENGN_DMA), - 0, 0xc00000, 0x2000, oclass, &chan->base); - chan->fifo = fifo; - if (ret) - return ret; - - ret = nvkm_gpuobj_new(device, 0x0200, 0x1000, true, chan->base.inst, - &chan->ramfc); - if (ret) - return ret; - - ret = nvkm_gpuobj_new(device, 0x1200, 0, true, chan->base.inst, - &chan->eng); - if (ret) - return ret; - - ret = nvkm_gpuobj_new(device, 0x4000, 0, false, chan->base.inst, - &chan->pgd); - if (ret) - return ret; - - return nvkm_ramht_new(device, 0x8000, 16, chan->base.inst, &chan->ramht); -} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.h deleted file mode 100644 index 3a95730d7ff5..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.h +++ /dev/null @@ -1,53 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -#ifndef __NV50_FIFO_CHAN_H__ -#define __NV50_FIFO_CHAN_H__ -#define nv50_fifo_chan(p) container_of((p), struct nv50_fifo_chan, base) -#include "chan.h" -#include "nv50.h" - -struct nv50_fifo_chan { - struct nv50_fifo *fifo; - struct nvkm_fifo_chan base; - - struct nvkm_gpuobj *ramfc; - struct nvkm_gpuobj *cache; - struct nvkm_gpuobj *eng; - struct nvkm_gpuobj *pgd; - struct nvkm_ramht *ramht; - -#define NV50_FIFO_ENGN_SW 0 -#define NV50_FIFO_ENGN_GR 1 -#define NV50_FIFO_ENGN_MPEG 2 -#define NV50_FIFO_ENGN_DMA 3 - -#define G84_FIFO_ENGN_SW 0 -#define G84_FIFO_ENGN_GR 1 -#define G84_FIFO_ENGN_MPEG 2 -#define G84_FIFO_ENGN_MSPPP 2 -#define G84_FIFO_ENGN_ME 3 -#define G84_FIFO_ENGN_CE0 3 -#define G84_FIFO_ENGN_VP 4 -#define G84_FIFO_ENGN_MSPDEC 4 -#define G84_FIFO_ENGN_CIPHER 5 -#define G84_FIFO_ENGN_SEC 5 -#define G84_FIFO_ENGN_VIC 5 -#define G84_FIFO_ENGN_BSP 6 -#define G84_FIFO_ENGN_MSVLD 6 -#define G84_FIFO_ENGN_DMA 7 - struct nvkm_gpuobj *engn[NVKM_FIFO_ENGN_NR]; -}; - -int nv50_fifo_chan_ctor(struct nv50_fifo *, u64 vmm, u64 push, - const struct nvkm_oclass *, struct nv50_fifo_chan *); -void *nv50_fifo_chan_dtor(struct nvkm_fifo_chan *); -void nv50_fifo_chan_fini(struct nvkm_fifo_chan *); -struct nvkm_gpuobj **nv50_fifo_chan_engine(struct nv50_fifo_chan *, struct nvkm_engine *); -void nv50_fifo_chan_engine_dtor(struct nvkm_fifo_chan *, struct nvkm_engine *); -void nv50_fifo_chan_object_dtor(struct nvkm_fifo_chan *, int); - -int g84_fifo_chan_ctor(struct nv50_fifo *, u64 vmm, u64 push, - const struct nvkm_oclass *, struct nv50_fifo_chan *); - -extern const struct nvkm_fifo_chan_oclass nv50_fifo_gpfifo_oclass; -extern const struct nvkm_fifo_chan_oclass g84_fifo_gpfifo_oclass; -#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chid.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chid.c new file mode 100644 index 000000000000..23944d95efd5 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chid.c @@ -0,0 +1,111 @@ +/* + * Copyright 2020 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 "chid.h" + +void +nvkm_chid_put(struct nvkm_chid *chid, int id, spinlock_t *data_lock) +{ + if (id >= 0) { + spin_lock_irq(&chid->lock); + spin_lock(data_lock); + chid->data[id] = NULL; + spin_unlock(data_lock); + clear_bit(id, chid->used); + spin_unlock_irq(&chid->lock); + } +} + +int +nvkm_chid_get(struct nvkm_chid *chid, void *data) +{ + int id = -1, cid; + + spin_lock_irq(&chid->lock); + cid = find_first_zero_bit(chid->used, chid->nr); + if (cid < chid->nr) { + set_bit(cid, chid->used); + chid->data[cid] = data; + id = cid; + } + spin_unlock_irq(&chid->lock); + return id; +} + +static void +nvkm_chid_del(struct kref *kref) +{ + struct nvkm_chid *chid = container_of(kref, typeof(*chid), kref); + + nvkm_event_fini(&chid->event); + + kvfree(chid->data); + kfree(chid); +} + +void +nvkm_chid_unref(struct nvkm_chid **pchid) +{ + struct nvkm_chid *chid = *pchid; + + if (!chid) + return; + + kref_put(&chid->kref, nvkm_chid_del); + *pchid = NULL; +} + +struct nvkm_chid * +nvkm_chid_ref(struct nvkm_chid *chid) +{ + if (chid) + kref_get(&chid->kref); + + return chid; +} + +int +nvkm_chid_new(const struct nvkm_event_func *func, struct nvkm_subdev *subdev, + int nr, int first, int count, struct nvkm_chid **pchid) +{ + struct nvkm_chid *chid; + int id; + + if (!(chid = *pchid = kzalloc(struct_size(chid, used, nr), GFP_KERNEL))) + return -ENOMEM; + + kref_init(&chid->kref); + chid->nr = nr; + chid->mask = chid->nr - 1; + spin_lock_init(&chid->lock); + + if (!(chid->data = kvzalloc(sizeof(*chid->data) * nr, GFP_KERNEL))) { + nvkm_chid_unref(pchid); + return -ENOMEM; + } + + for (id = 0; id < first; id++) + __set_bit(id, chid->used); + for (id = first + count; id < nr; id++) + __set_bit(id, chid->used); + + return nvkm_event_init(func, subdev, 1, nr, &chid->event); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chid.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chid.h new file mode 100644 index 000000000000..2a42efb18401 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chid.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: MIT */ +#ifndef __NVKM_CHID_H__ +#define __NVKM_CHID_H__ +#include <core/event.h> + +struct nvkm_chid { + struct kref kref; + int nr; + u32 mask; + + struct nvkm_event event; + + void **data; + + spinlock_t lock; + unsigned long used[]; +}; + +int nvkm_chid_new(const struct nvkm_event_func *, struct nvkm_subdev *, + int nr, int first, int count, struct nvkm_chid **pchid); +struct nvkm_chid *nvkm_chid_ref(struct nvkm_chid *); +void nvkm_chid_unref(struct nvkm_chid **); +int nvkm_chid_get(struct nvkm_chid *, void *data); +void nvkm_chid_put(struct nvkm_chid *, int id, spinlock_t *data_lock); +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv04.c deleted file mode 100644 index dbcdc5fab990..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv04.c +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright 2012 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. - * - * Authors: Ben Skeggs - */ -#include "channv04.h" -#include "regsnv04.h" - -#include <core/client.h> -#include <core/ramht.h> -#include <subdev/instmem.h> - -#include <nvif/class.h> -#include <nvif/cl006b.h> -#include <nvif/unpack.h> - -void -nv04_fifo_dma_object_dtor(struct nvkm_fifo_chan *base, int cookie) -{ - struct nv04_fifo_chan *chan = nv04_fifo_chan(base); - struct nvkm_instmem *imem = chan->fifo->base.engine.subdev.device->imem; - - mutex_lock(&chan->fifo->base.mutex); - nvkm_ramht_remove(imem->ramht, cookie); - mutex_unlock(&chan->fifo->base.mutex); -} - -static int -nv04_fifo_dma_object_ctor(struct nvkm_fifo_chan *base, - struct nvkm_object *object) -{ - struct nv04_fifo_chan *chan = nv04_fifo_chan(base); - struct nvkm_instmem *imem = chan->fifo->base.engine.subdev.device->imem; - u32 context = 0x80000000 | chan->base.chid << 24; - u32 handle = object->handle; - int hash; - - switch (object->engine->subdev.type) { - case NVKM_ENGINE_DMAOBJ: - case NVKM_ENGINE_SW : context |= 0x00000000; break; - case NVKM_ENGINE_GR : context |= 0x00010000; break; - case NVKM_ENGINE_MPEG : context |= 0x00020000; break; - default: - WARN_ON(1); - return -EINVAL; - } - - mutex_lock(&chan->fifo->base.mutex); - hash = nvkm_ramht_insert(imem->ramht, object, chan->base.chid, 4, - handle, context); - mutex_unlock(&chan->fifo->base.mutex); - return hash; -} - -void -nv04_fifo_dma_fini(struct nvkm_fifo_chan *base) -{ - struct nv04_fifo_chan *chan = nv04_fifo_chan(base); - struct nv04_fifo *fifo = chan->fifo; - struct nvkm_device *device = fifo->base.engine.subdev.device; - struct nvkm_memory *fctx = device->imem->ramfc; - const struct nv04_fifo_ramfc *c; - unsigned long flags; - u32 mask = fifo->base.nr - 1; - u32 data = chan->ramfc; - u32 chid; - - /* prevent fifo context switches */ - spin_lock_irqsave(&fifo->base.lock, flags); - nvkm_wr32(device, NV03_PFIFO_CACHES, 0); - - /* if this channel is active, replace it with a null context */ - chid = nvkm_rd32(device, NV03_PFIFO_CACHE1_PUSH1) & mask; - if (chid == chan->base.chid) { - nvkm_mask(device, NV04_PFIFO_CACHE1_DMA_PUSH, 0x00000001, 0); - nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH0, 0); - nvkm_mask(device, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0); - - c = fifo->ramfc; - nvkm_kmap(fctx); - do { - u32 rm = ((1ULL << c->bits) - 1) << c->regs; - u32 cm = ((1ULL << c->bits) - 1) << c->ctxs; - u32 rv = (nvkm_rd32(device, c->regp) & rm) >> c->regs; - u32 cv = (nvkm_ro32(fctx, c->ctxp + data) & ~cm); - nvkm_wo32(fctx, c->ctxp + data, cv | (rv << c->ctxs)); - } while ((++c)->bits); - nvkm_done(fctx); - - c = fifo->ramfc; - do { - nvkm_wr32(device, c->regp, 0x00000000); - } while ((++c)->bits); - - nvkm_wr32(device, NV03_PFIFO_CACHE1_GET, 0); - nvkm_wr32(device, NV03_PFIFO_CACHE1_PUT, 0); - nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, mask); - nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH0, 1); - nvkm_wr32(device, NV04_PFIFO_CACHE1_PULL0, 1); - } - - /* restore normal operation, after disabling dma mode */ - nvkm_mask(device, NV04_PFIFO_MODE, 1 << chan->base.chid, 0); - nvkm_wr32(device, NV03_PFIFO_CACHES, 1); - spin_unlock_irqrestore(&fifo->base.lock, flags); -} - -void -nv04_fifo_dma_init(struct nvkm_fifo_chan *base) -{ - struct nv04_fifo_chan *chan = nv04_fifo_chan(base); - struct nv04_fifo *fifo = chan->fifo; - struct nvkm_device *device = fifo->base.engine.subdev.device; - u32 mask = 1 << chan->base.chid; - unsigned long flags; - spin_lock_irqsave(&fifo->base.lock, flags); - nvkm_mask(device, NV04_PFIFO_MODE, mask, mask); - spin_unlock_irqrestore(&fifo->base.lock, flags); -} - -void * -nv04_fifo_dma_dtor(struct nvkm_fifo_chan *base) -{ - struct nv04_fifo_chan *chan = nv04_fifo_chan(base); - struct nv04_fifo *fifo = chan->fifo; - struct nvkm_instmem *imem = fifo->base.engine.subdev.device->imem; - const struct nv04_fifo_ramfc *c = fifo->ramfc; - - nvkm_kmap(imem->ramfc); - do { - nvkm_wo32(imem->ramfc, chan->ramfc + c->ctxp, 0x00000000); - } while ((++c)->bits); - nvkm_done(imem->ramfc); - return chan; -} - -const struct nvkm_fifo_chan_func -nv04_fifo_dma_func = { - .dtor = nv04_fifo_dma_dtor, - .init = nv04_fifo_dma_init, - .fini = nv04_fifo_dma_fini, - .object_ctor = nv04_fifo_dma_object_ctor, - .object_dtor = nv04_fifo_dma_object_dtor, -}; - -static int -nv04_fifo_dma_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, - void *data, u32 size, struct nvkm_object **pobject) -{ - struct nvkm_object *parent = oclass->parent; - union { - struct nv03_channel_dma_v0 v0; - } *args = data; - struct nv04_fifo *fifo = nv04_fifo(base); - struct nv04_fifo_chan *chan = NULL; - struct nvkm_device *device = fifo->base.engine.subdev.device; - struct nvkm_instmem *imem = device->imem; - int ret = -ENOSYS; - - nvif_ioctl(parent, "create channel dma size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { - nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx " - "offset %08x\n", args->v0.version, - args->v0.pushbuf, args->v0.offset); - if (!args->v0.pushbuf) - return -EINVAL; - } else - return ret; - - if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) - return -ENOMEM; - *pobject = &chan->base.object; - - ret = nvkm_fifo_chan_ctor(&nv04_fifo_dma_func, &fifo->base, - 0x1000, 0x1000, false, 0, args->v0.pushbuf, - BIT(NV04_FIFO_ENGN_SW) | - BIT(NV04_FIFO_ENGN_GR) | - BIT(NV04_FIFO_ENGN_DMA), - 0, 0x800000, 0x10000, oclass, &chan->base); - chan->fifo = fifo; - if (ret) - return ret; - - args->v0.chid = chan->base.chid; - chan->ramfc = chan->base.chid * 32; - - nvkm_kmap(imem->ramfc); - nvkm_wo32(imem->ramfc, chan->ramfc + 0x00, args->v0.offset); - nvkm_wo32(imem->ramfc, chan->ramfc + 0x04, args->v0.offset); - nvkm_wo32(imem->ramfc, chan->ramfc + 0x08, chan->base.push->addr >> 4); - nvkm_wo32(imem->ramfc, chan->ramfc + 0x10, - NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | - NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | -#ifdef __BIG_ENDIAN - NV_PFIFO_CACHE1_BIG_ENDIAN | -#endif - NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8); - nvkm_done(imem->ramfc); - return 0; -} - -const struct nvkm_fifo_chan_oclass -nv04_fifo_dma_oclass = { - .base.oclass = NV03_CHANNEL_DMA, - .base.minver = 0, - .base.maxver = 0, - .ctor = nv04_fifo_dma_new, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv10.c deleted file mode 100644 index 07d80d54a07c..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv10.c +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2012 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. - * - * Authors: Ben Skeggs - */ -#include "channv04.h" -#include "regsnv04.h" - -#include <core/client.h> -#include <core/gpuobj.h> -#include <subdev/instmem.h> - -#include <nvif/class.h> -#include <nvif/cl006b.h> -#include <nvif/unpack.h> - -static int -nv10_fifo_dma_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, - void *data, u32 size, struct nvkm_object **pobject) -{ - struct nvkm_object *parent = oclass->parent; - union { - struct nv03_channel_dma_v0 v0; - } *args = data; - struct nv04_fifo *fifo = nv04_fifo(base); - struct nv04_fifo_chan *chan = NULL; - struct nvkm_device *device = fifo->base.engine.subdev.device; - struct nvkm_instmem *imem = device->imem; - int ret = -ENOSYS; - - nvif_ioctl(parent, "create channel dma size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { - nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx " - "offset %08x\n", args->v0.version, - args->v0.pushbuf, args->v0.offset); - if (!args->v0.pushbuf) - return -EINVAL; - } else - return ret; - - if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) - return -ENOMEM; - *pobject = &chan->base.object; - - ret = nvkm_fifo_chan_ctor(&nv04_fifo_dma_func, &fifo->base, - 0x1000, 0x1000, false, 0, args->v0.pushbuf, - BIT(NV04_FIFO_ENGN_SW) | - BIT(NV04_FIFO_ENGN_GR) | - BIT(NV04_FIFO_ENGN_DMA), - 0, 0x800000, 0x10000, oclass, &chan->base); - chan->fifo = fifo; - if (ret) - return ret; - - args->v0.chid = chan->base.chid; - chan->ramfc = chan->base.chid * 32; - - nvkm_kmap(imem->ramfc); - nvkm_wo32(imem->ramfc, chan->ramfc + 0x00, args->v0.offset); - nvkm_wo32(imem->ramfc, chan->ramfc + 0x04, args->v0.offset); - nvkm_wo32(imem->ramfc, chan->ramfc + 0x0c, chan->base.push->addr >> 4); - nvkm_wo32(imem->ramfc, chan->ramfc + 0x14, - NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | - NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | -#ifdef __BIG_ENDIAN - NV_PFIFO_CACHE1_BIG_ENDIAN | -#endif - NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8); - nvkm_done(imem->ramfc); - return 0; -} - -const struct nvkm_fifo_chan_oclass -nv10_fifo_dma_oclass = { - .base.oclass = NV10_CHANNEL_DMA, - .base.minver = 0, - .base.maxver = 0, - .ctor = nv10_fifo_dma_new, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv17.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv17.c deleted file mode 100644 index edd70a114218..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv17.c +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2012 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. - * - * Authors: Ben Skeggs - */ -#include "channv04.h" -#include "regsnv04.h" - -#include <core/client.h> -#include <core/gpuobj.h> -#include <subdev/instmem.h> - -#include <nvif/class.h> -#include <nvif/cl006b.h> -#include <nvif/unpack.h> - -static int -nv17_fifo_dma_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, - void *data, u32 size, struct nvkm_object **pobject) -{ - struct nvkm_object *parent = oclass->parent; - union { - struct nv03_channel_dma_v0 v0; - } *args = data; - struct nv04_fifo *fifo = nv04_fifo(base); - struct nv04_fifo_chan *chan = NULL; - struct nvkm_device *device = fifo->base.engine.subdev.device; - struct nvkm_instmem *imem = device->imem; - int ret = -ENOSYS; - - nvif_ioctl(parent, "create channel dma size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { - nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx " - "offset %08x\n", args->v0.version, - args->v0.pushbuf, args->v0.offset); - if (!args->v0.pushbuf) - return -EINVAL; - } else - return ret; - - if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) - return -ENOMEM; - *pobject = &chan->base.object; - - ret = nvkm_fifo_chan_ctor(&nv04_fifo_dma_func, &fifo->base, - 0x1000, 0x1000, false, 0, args->v0.pushbuf, - BIT(NV04_FIFO_ENGN_SW) | - BIT(NV04_FIFO_ENGN_GR) | - BIT(NV04_FIFO_ENGN_MPEG) | /* NV31- */ - BIT(NV04_FIFO_ENGN_DMA), - 0, 0x800000, 0x10000, oclass, &chan->base); - chan->fifo = fifo; - if (ret) - return ret; - - args->v0.chid = chan->base.chid; - chan->ramfc = chan->base.chid * 64; - - nvkm_kmap(imem->ramfc); - nvkm_wo32(imem->ramfc, chan->ramfc + 0x00, args->v0.offset); - nvkm_wo32(imem->ramfc, chan->ramfc + 0x04, args->v0.offset); - nvkm_wo32(imem->ramfc, chan->ramfc + 0x0c, chan->base.push->addr >> 4); - nvkm_wo32(imem->ramfc, chan->ramfc + 0x14, - NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | - NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | -#ifdef __BIG_ENDIAN - NV_PFIFO_CACHE1_BIG_ENDIAN | -#endif - NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8); - nvkm_done(imem->ramfc); - return 0; -} - -const struct nvkm_fifo_chan_oclass -nv17_fifo_dma_oclass = { - .base.oclass = NV17_CHANNEL_DMA, - .base.minver = 0, - .base.maxver = 0, - .ctor = nv17_fifo_dma_new, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv40.c deleted file mode 100644 index 0411fb908457..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv40.c +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Copyright 2012 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. - * - * Authors: Ben Skeggs - */ -#include "channv04.h" -#include "regsnv04.h" - -#include <core/client.h> -#include <core/ramht.h> -#include <subdev/instmem.h> - -#include <nvif/class.h> -#include <nvif/cl006b.h> -#include <nvif/unpack.h> - -static bool -nv40_fifo_dma_engine(struct nvkm_engine *engine, u32 *reg, u32 *ctx) -{ - switch (engine->subdev.type) { - case NVKM_ENGINE_DMAOBJ: - case NVKM_ENGINE_SW: - return false; - case NVKM_ENGINE_GR: - *reg = 0x0032e0; - *ctx = 0x38; - return true; - case NVKM_ENGINE_MPEG: - if (engine->subdev.device->chipset < 0x44) - return false; - *reg = 0x00330c; - *ctx = 0x54; - return true; - default: - WARN_ON(1); - return false; - } -} - -static struct nvkm_gpuobj ** -nv40_fifo_dma_engn(struct nv04_fifo_chan *chan, struct nvkm_engine *engine) -{ - int engi = chan->base.fifo->func->engine_id(chan->base.fifo, engine); - if (engi >= 0) - return &chan->engn[engi]; - return NULL; -} - -static int -nv40_fifo_dma_engine_fini(struct nvkm_fifo_chan *base, - struct nvkm_engine *engine, bool suspend) -{ - struct nv04_fifo_chan *chan = nv04_fifo_chan(base); - struct nv04_fifo *fifo = chan->fifo; - struct nvkm_device *device = fifo->base.engine.subdev.device; - struct nvkm_instmem *imem = device->imem; - unsigned long flags; - u32 reg, ctx; - int chid; - - if (!nv40_fifo_dma_engine(engine, ®, &ctx)) - return 0; - - spin_lock_irqsave(&fifo->base.lock, flags); - nvkm_mask(device, 0x002500, 0x00000001, 0x00000000); - - chid = nvkm_rd32(device, 0x003204) & (fifo->base.nr - 1); - if (chid == chan->base.chid) - nvkm_wr32(device, reg, 0x00000000); - nvkm_kmap(imem->ramfc); - nvkm_wo32(imem->ramfc, chan->ramfc + ctx, 0x00000000); - nvkm_done(imem->ramfc); - - nvkm_mask(device, 0x002500, 0x00000001, 0x00000001); - spin_unlock_irqrestore(&fifo->base.lock, flags); - return 0; -} - -static int -nv40_fifo_dma_engine_init(struct nvkm_fifo_chan *base, - struct nvkm_engine *engine) -{ - struct nv04_fifo_chan *chan = nv04_fifo_chan(base); - struct nv04_fifo *fifo = chan->fifo; - struct nvkm_device *device = fifo->base.engine.subdev.device; - struct nvkm_instmem *imem = device->imem; - unsigned long flags; - u32 inst, reg, ctx; - int chid; - - if (!nv40_fifo_dma_engine(engine, ®, &ctx)) - return 0; - inst = (*nv40_fifo_dma_engn(chan, engine))->addr >> 4; - - spin_lock_irqsave(&fifo->base.lock, flags); - nvkm_mask(device, 0x002500, 0x00000001, 0x00000000); - - chid = nvkm_rd32(device, 0x003204) & (fifo->base.nr - 1); - if (chid == chan->base.chid) - nvkm_wr32(device, reg, inst); - nvkm_kmap(imem->ramfc); - nvkm_wo32(imem->ramfc, chan->ramfc + ctx, inst); - nvkm_done(imem->ramfc); - - nvkm_mask(device, 0x002500, 0x00000001, 0x00000001); - spin_unlock_irqrestore(&fifo->base.lock, flags); - return 0; -} - -static void -nv40_fifo_dma_engine_dtor(struct nvkm_fifo_chan *base, - struct nvkm_engine *engine) -{ - struct nv04_fifo_chan *chan = nv04_fifo_chan(base); - nvkm_gpuobj_del(nv40_fifo_dma_engn(chan, engine)); -} - -static int -nv40_fifo_dma_engine_ctor(struct nvkm_fifo_chan *base, - struct nvkm_engine *engine, - struct nvkm_object *object) -{ - struct nv04_fifo_chan *chan = nv04_fifo_chan(base); - u32 reg, ctx; - - if (!nv40_fifo_dma_engine(engine, ®, &ctx)) - return 0; - - return nvkm_object_bind(object, NULL, 0, nv40_fifo_dma_engn(chan, engine)); -} - -static int -nv40_fifo_dma_object_ctor(struct nvkm_fifo_chan *base, - struct nvkm_object *object) -{ - struct nv04_fifo_chan *chan = nv04_fifo_chan(base); - struct nvkm_instmem *imem = chan->fifo->base.engine.subdev.device->imem; - u32 context = chan->base.chid << 23; - u32 handle = object->handle; - int hash; - - switch (object->engine->subdev.type) { - case NVKM_ENGINE_DMAOBJ: - case NVKM_ENGINE_SW : context |= 0x00000000; break; - case NVKM_ENGINE_GR : context |= 0x00100000; break; - case NVKM_ENGINE_MPEG : context |= 0x00200000; break; - default: - WARN_ON(1); - return -EINVAL; - } - - mutex_lock(&chan->fifo->base.mutex); - hash = nvkm_ramht_insert(imem->ramht, object, chan->base.chid, 4, - handle, context); - mutex_unlock(&chan->fifo->base.mutex); - return hash; -} - -static const struct nvkm_fifo_chan_func -nv40_fifo_dma_func = { - .dtor = nv04_fifo_dma_dtor, - .init = nv04_fifo_dma_init, - .fini = nv04_fifo_dma_fini, - .engine_ctor = nv40_fifo_dma_engine_ctor, - .engine_dtor = nv40_fifo_dma_engine_dtor, - .engine_init = nv40_fifo_dma_engine_init, - .engine_fini = nv40_fifo_dma_engine_fini, - .object_ctor = nv40_fifo_dma_object_ctor, - .object_dtor = nv04_fifo_dma_object_dtor, -}; - -static int -nv40_fifo_dma_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, - void *data, u32 size, struct nvkm_object **pobject) -{ - struct nvkm_object *parent = oclass->parent; - union { - struct nv03_channel_dma_v0 v0; - } *args = data; - struct nv04_fifo *fifo = nv04_fifo(base); - struct nv04_fifo_chan *chan = NULL; - struct nvkm_device *device = fifo->base.engine.subdev.device; - struct nvkm_instmem *imem = device->imem; - int ret = -ENOSYS; - - nvif_ioctl(parent, "create channel dma size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { - nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx " - "offset %08x\n", args->v0.version, - args->v0.pushbuf, args->v0.offset); - if (!args->v0.pushbuf) - return -EINVAL; - } else - return ret; - - if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) - return -ENOMEM; - *pobject = &chan->base.object; - - ret = nvkm_fifo_chan_ctor(&nv40_fifo_dma_func, &fifo->base, - 0x1000, 0x1000, false, 0, args->v0.pushbuf, - BIT(NV04_FIFO_ENGN_SW) | - BIT(NV04_FIFO_ENGN_GR) | - BIT(NV04_FIFO_ENGN_MPEG) | - BIT(NV04_FIFO_ENGN_DMA), - 0, 0xc00000, 0x1000, oclass, &chan->base); - chan->fifo = fifo; - if (ret) - return ret; - - args->v0.chid = chan->base.chid; - chan->ramfc = chan->base.chid * 128; - - nvkm_kmap(imem->ramfc); - nvkm_wo32(imem->ramfc, chan->ramfc + 0x00, args->v0.offset); - nvkm_wo32(imem->ramfc, chan->ramfc + 0x04, args->v0.offset); - nvkm_wo32(imem->ramfc, chan->ramfc + 0x0c, chan->base.push->addr >> 4); - nvkm_wo32(imem->ramfc, chan->ramfc + 0x18, 0x30000000 | - NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | - NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | -#ifdef __BIG_ENDIAN - NV_PFIFO_CACHE1_BIG_ENDIAN | -#endif - NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8); - nvkm_wo32(imem->ramfc, chan->ramfc + 0x3c, 0x0001ffff); - nvkm_done(imem->ramfc); - return 0; -} - -const struct nvkm_fifo_chan_oclass -nv40_fifo_dma_oclass = { - .base.oclass = NV40_CHANNEL_DMA, - .base.minver = 0, - .base.maxver = 0, - .ctor = nv40_fifo_dma_new, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c index 3885c3830b94..6b229a3fbd97 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c @@ -21,112 +21,211 @@ * * Authors: Ben Skeggs */ -#include "nv50.h" -#include "channv50.h" +#include "priv.h" +#include "cgrp.h" +#include "chan.h" +#include "runl.h" + +#include <core/ramht.h> +#include <subdev/timer.h> + +#include <nvif/class.h> static void -g84_fifo_uevent_fini(struct nvkm_fifo *fifo) +g84_chan_bind(struct nvkm_chan *chan) { - struct nvkm_device *device = fifo->engine.subdev.device; - nvkm_mask(device, 0x002140, 0x40000000, 0x00000000); + struct nvkm_device *device = chan->cgrp->runl->fifo->engine.subdev.device; + + nvkm_wr32(device, 0x002600 + (chan->id * 4), chan->ramfc->addr >> 8); } -static void -g84_fifo_uevent_init(struct nvkm_fifo *fifo) +static int +g84_chan_ramfc_write(struct nvkm_chan *chan, u64 offset, u64 length, u32 devm, bool priv) { - struct nvkm_device *device = fifo->engine.subdev.device; - nvkm_mask(device, 0x002140, 0x40000000, 0x40000000); + struct nvkm_device *device = chan->cgrp->runl->fifo->engine.subdev.device; + const u32 limit2 = ilog2(length / 8); + int ret; + + ret = nvkm_gpuobj_new(device, 0x0200, 0, true, chan->inst, &chan->eng); + if (ret) + return ret; + + ret = nvkm_gpuobj_new(device, 0x4000, 0, false, chan->inst, &chan->pgd); + if (ret) + return ret; + + ret = nvkm_gpuobj_new(device, 0x1000, 0x400, true, chan->inst, &chan->cache); + if (ret) + return ret; + + ret = nvkm_gpuobj_new(device, 0x100, 0x100, true, chan->inst, &chan->ramfc); + if (ret) + return ret; + + ret = nvkm_ramht_new(device, 0x8000, 16, chan->inst, &chan->ramht); + if (ret) + return ret; + + nvkm_kmap(chan->ramfc); + nvkm_wo32(chan->ramfc, 0x3c, 0x403f6078); + nvkm_wo32(chan->ramfc, 0x44, 0x01003fff); + nvkm_wo32(chan->ramfc, 0x48, chan->push->node->offset >> 4); + nvkm_wo32(chan->ramfc, 0x50, lower_32_bits(offset)); + nvkm_wo32(chan->ramfc, 0x54, upper_32_bits(offset) | (limit2 << 16)); + nvkm_wo32(chan->ramfc, 0x60, 0x7fffffff); + nvkm_wo32(chan->ramfc, 0x78, 0x00000000); + nvkm_wo32(chan->ramfc, 0x7c, 0x30000000 | devm); + nvkm_wo32(chan->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | + (4 << 24) /* SEARCH_FULL */ | + (chan->ramht->gpuobj->node->offset >> 4)); + nvkm_wo32(chan->ramfc, 0x88, chan->cache->addr >> 10); + nvkm_wo32(chan->ramfc, 0x98, chan->inst->addr >> 12); + nvkm_done(chan->ramfc); + return 0; } -static struct nvkm_engine * -g84_fifo_id_engine(struct nvkm_fifo *fifo, int engi) +static const struct nvkm_chan_func_ramfc +g84_chan_ramfc = { + .write = g84_chan_ramfc_write, + .ctxdma = true, + .devm = 0xfff, +}; + +const struct nvkm_chan_func +g84_chan = { + .inst = &nv50_chan_inst, + .userd = &nv50_chan_userd, + .ramfc = &g84_chan_ramfc, + .bind = g84_chan_bind, + .unbind = nv50_chan_unbind, + .start = nv50_chan_start, + .stop = nv50_chan_stop, +}; + +static void +g84_ectx_bind(struct nvkm_engn *engn, struct nvkm_cctx *cctx, struct nvkm_chan *chan) { - struct nvkm_device *device = fifo->engine.subdev.device; - struct nvkm_engine *engine; - enum nvkm_subdev_type type; - - switch (engi) { - case G84_FIFO_ENGN_SW : type = NVKM_ENGINE_SW; break; - case G84_FIFO_ENGN_GR : type = NVKM_ENGINE_GR; break; - case G84_FIFO_ENGN_MPEG : - if ((engine = nvkm_device_engine(device, NVKM_ENGINE_MSPPP, 0))) - return engine; - type = NVKM_ENGINE_MPEG; - break; - case G84_FIFO_ENGN_ME : - if ((engine = nvkm_device_engine(device, NVKM_ENGINE_CE, 0))) - return engine; - type = NVKM_ENGINE_ME; - break; - case G84_FIFO_ENGN_VP : - if ((engine = nvkm_device_engine(device, NVKM_ENGINE_MSPDEC, 0))) - return engine; - type = NVKM_ENGINE_VP; - break; - case G84_FIFO_ENGN_CIPHER: - if ((engine = nvkm_device_engine(device, NVKM_ENGINE_VIC, 0))) - return engine; - if ((engine = nvkm_device_engine(device, NVKM_ENGINE_SEC, 0))) - return engine; - type = NVKM_ENGINE_CIPHER; - break; - case G84_FIFO_ENGN_BSP : - if ((engine = nvkm_device_engine(device, NVKM_ENGINE_MSVLD, 0))) - return engine; - type = NVKM_ENGINE_BSP; - break; - case G84_FIFO_ENGN_DMA : type = NVKM_ENGINE_DMAOBJ; break; + struct nvkm_subdev *subdev = &chan->cgrp->runl->fifo->engine.subdev; + struct nvkm_device *device = subdev->device; + u64 start = 0, limit = 0; + u32 flags = 0, ptr0, save; + + switch (engn->engine->subdev.type) { + case NVKM_ENGINE_GR : ptr0 = 0x0020; break; + case NVKM_ENGINE_VP : + case NVKM_ENGINE_MSPDEC: ptr0 = 0x0040; break; + case NVKM_ENGINE_MPEG : + case NVKM_ENGINE_MSPPP : ptr0 = 0x0060; break; + case NVKM_ENGINE_BSP : + case NVKM_ENGINE_MSVLD : ptr0 = 0x0080; break; + case NVKM_ENGINE_CIPHER: + case NVKM_ENGINE_SEC : ptr0 = 0x00a0; break; + case NVKM_ENGINE_CE : ptr0 = 0x00c0; break; default: WARN_ON(1); - return NULL; + return; + } + + if (!cctx) { + save = nvkm_mask(device, 0x002520, 0x0000003f, BIT(engn->id - 1)); + nvkm_wr32(device, 0x0032fc, chan->inst->addr >> 12); + nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x0032fc) != 0xffffffff) + break; + ); + nvkm_wr32(device, 0x002520, save); + } else { + flags = 0x00190000; + start = cctx->vctx->inst->addr; + limit = start + cctx->vctx->inst->size - 1; } - return nvkm_device_engine(fifo->engine.subdev.device, type, 0); + nvkm_kmap(chan->eng); + nvkm_wo32(chan->eng, ptr0 + 0x00, flags); + nvkm_wo32(chan->eng, ptr0 + 0x04, lower_32_bits(limit)); + nvkm_wo32(chan->eng, ptr0 + 0x08, lower_32_bits(start)); + nvkm_wo32(chan->eng, ptr0 + 0x0c, upper_32_bits(limit) << 24 | + lower_32_bits(start)); + nvkm_wo32(chan->eng, ptr0 + 0x10, 0x00000000); + nvkm_wo32(chan->eng, ptr0 + 0x14, 0x00000000); + nvkm_done(chan->eng); } +const struct nvkm_engn_func +g84_engn = { + .bind = g84_ectx_bind, + .ramht_add = nv50_eobj_ramht_add, + .ramht_del = nv50_eobj_ramht_del, +}; + +static void +g84_fifo_nonstall_block(struct nvkm_event *event, int type, int index) +{ + struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), nonstall.event); + unsigned long flags; + + spin_lock_irqsave(&fifo->lock, flags); + nvkm_mask(fifo->engine.subdev.device, 0x002140, 0x40000000, 0x00000000); + spin_unlock_irqrestore(&fifo->lock, flags); +} + +static void +g84_fifo_nonstall_allow(struct nvkm_event *event, int type, int index) +{ + struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), nonstall.event); + unsigned long flags; + + spin_lock_irqsave(&fifo->lock, flags); + nvkm_mask(fifo->engine.subdev.device, 0x002140, 0x40000000, 0x40000000); + spin_unlock_irqrestore(&fifo->lock, flags); +} + +const struct nvkm_event_func +g84_fifo_nonstall = { + .init = g84_fifo_nonstall_allow, + .fini = g84_fifo_nonstall_block, +}; + static int -g84_fifo_engine_id(struct nvkm_fifo *base, struct nvkm_engine *engine) +g84_fifo_runl_ctor(struct nvkm_fifo *fifo) { - switch (engine->subdev.type) { - case NVKM_ENGINE_SW : return G84_FIFO_ENGN_SW; - case NVKM_ENGINE_GR : return G84_FIFO_ENGN_GR; - case NVKM_ENGINE_MPEG : - case NVKM_ENGINE_MSPPP : return G84_FIFO_ENGN_MPEG; - case NVKM_ENGINE_CE : return G84_FIFO_ENGN_CE0; - case NVKM_ENGINE_VP : - case NVKM_ENGINE_MSPDEC: return G84_FIFO_ENGN_VP; - case NVKM_ENGINE_CIPHER: - case NVKM_ENGINE_SEC : return G84_FIFO_ENGN_CIPHER; - case NVKM_ENGINE_BSP : - case NVKM_ENGINE_MSVLD : return G84_FIFO_ENGN_BSP; - case NVKM_ENGINE_DMAOBJ: return G84_FIFO_ENGN_DMA; - default: - WARN_ON(1); - return -1; - } + struct nvkm_runl *runl; + + runl = nvkm_runl_new(fifo, 0, 0, 0); + if (IS_ERR(runl)) + return PTR_ERR(runl); + + nvkm_runl_add(runl, 0, fifo->func->engn_sw, NVKM_ENGINE_SW, 0); + nvkm_runl_add(runl, 0, fifo->func->engn_sw, NVKM_ENGINE_DMAOBJ, 0); + nvkm_runl_add(runl, 1, fifo->func->engn, NVKM_ENGINE_GR, 0); + nvkm_runl_add(runl, 2, fifo->func->engn, NVKM_ENGINE_MPEG, 0); + nvkm_runl_add(runl, 3, fifo->func->engn, NVKM_ENGINE_ME, 0); + nvkm_runl_add(runl, 4, fifo->func->engn, NVKM_ENGINE_VP, 0); + nvkm_runl_add(runl, 5, fifo->func->engn, NVKM_ENGINE_CIPHER, 0); + nvkm_runl_add(runl, 6, fifo->func->engn, NVKM_ENGINE_BSP, 0); + return 0; } static const struct nvkm_fifo_func g84_fifo = { - .dtor = nv50_fifo_dtor, - .oneinit = nv50_fifo_oneinit, + .chid_nr = nv50_fifo_chid_nr, + .chid_ctor = nv50_fifo_chid_ctor, + .runl_ctor = g84_fifo_runl_ctor, .init = nv50_fifo_init, .intr = nv04_fifo_intr, - .engine_id = g84_fifo_engine_id, - .id_engine = g84_fifo_id_engine, .pause = nv04_fifo_pause, .start = nv04_fifo_start, - .uevent_init = g84_fifo_uevent_init, - .uevent_fini = g84_fifo_uevent_fini, - .chan = { - &g84_fifo_gpfifo_oclass, - NULL - }, + .nonstall = &g84_fifo_nonstall, + .runl = &nv50_runl, + .engn = &g84_engn, + .engn_sw = &nv50_engn_sw, + .cgrp = {{ }, &nv04_cgrp }, + .chan = {{ 0, 0, G82_CHANNEL_GPFIFO }, &g84_chan }, }; int g84_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fifo **pfifo) { - return nv50_fifo_new_(&g84_fifo, device, type, inst, pfifo); + return nvkm_fifo_new_(&g84_fifo, device, type, inst, pfifo); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g98.c new file mode 100644 index 000000000000..c6ca050c38bf --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g98.c @@ -0,0 +1,70 @@ +/* + * 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 "chan.h" +#include "runl.h" + +#include <nvif/class.h> + +static int +g98_fifo_runl_ctor(struct nvkm_fifo *fifo) +{ + struct nvkm_runl *runl; + + runl = nvkm_runl_new(fifo, 0, 0, 0); + if (IS_ERR(runl)) + return PTR_ERR(runl); + + nvkm_runl_add(runl, 0, fifo->func->engn_sw, NVKM_ENGINE_SW, 0); + nvkm_runl_add(runl, 0, fifo->func->engn_sw, NVKM_ENGINE_DMAOBJ, 0); + nvkm_runl_add(runl, 1, fifo->func->engn, NVKM_ENGINE_GR, 0); + nvkm_runl_add(runl, 2, fifo->func->engn, NVKM_ENGINE_MSPPP, 0); + nvkm_runl_add(runl, 3, fifo->func->engn, NVKM_ENGINE_CE, 0); + nvkm_runl_add(runl, 4, fifo->func->engn, NVKM_ENGINE_MSPDEC, 0); + nvkm_runl_add(runl, 5, fifo->func->engn, NVKM_ENGINE_SEC, 0); + nvkm_runl_add(runl, 6, fifo->func->engn, NVKM_ENGINE_MSVLD, 0); + return 0; +} + +static const struct nvkm_fifo_func +g98_fifo = { + .chid_nr = nv50_fifo_chid_nr, + .chid_ctor = nv50_fifo_chid_ctor, + .runl_ctor = g98_fifo_runl_ctor, + .init = nv50_fifo_init, + .intr = nv04_fifo_intr, + .pause = nv04_fifo_pause, + .start = nv04_fifo_start, + .nonstall = &g84_fifo_nonstall, + .runl = &nv50_runl, + .engn = &g84_engn, + .engn_sw = &nv50_engn_sw, + .cgrp = {{ }, &nv04_cgrp }, + .chan = {{ 0, 0, G82_CHANNEL_GPFIFO }, &g84_chan }, +}; + +int +g98_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, + struct nvkm_fifo **pfifo) +{ + return nvkm_fifo_new_(&g98_fifo, device, type, inst, pfifo); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga100.c new file mode 100644 index 000000000000..12a5d99d5e77 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga100.c @@ -0,0 +1,550 @@ +/* + * 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 "cgrp.h" +#include "chan.h" +#include "chid.h" +#include "runl.h" +#include "runq.h" + +#include <core/gpuobj.h> +#include <subdev/top.h> +#include <subdev/vfn.h> + +#include <nvif/class.h> + +/*TODO: allocate? */ +#define GA100_FIFO_NONSTALL_VECTOR 0 + +static u32 +ga100_chan_doorbell_handle(struct nvkm_chan *chan) +{ + return (chan->cgrp->runl->doorbell << 16) | chan->id; +} + +static void +ga100_chan_stop(struct nvkm_chan *chan) +{ + struct nvkm_runl *runl = chan->cgrp->runl; + + nvkm_wr32(runl->fifo->engine.subdev.device, runl->chan + (chan->id * 4), 0x00000003); +} + +static void +ga100_chan_start(struct nvkm_chan *chan) +{ + struct nvkm_runl *runl = chan->cgrp->runl; + struct nvkm_device *device = runl->fifo->engine.subdev.device; + const int gfid = 0; + + nvkm_wr32(device, runl->chan + (chan->id * 4), 0x00000002); + nvkm_wr32(device, runl->addr + 0x0090, (gfid << 16) | chan->id); /* INTERNAL_DOORBELL. */ +} + +static void +ga100_chan_unbind(struct nvkm_chan *chan) +{ + struct nvkm_runl *runl = chan->cgrp->runl; + + nvkm_wr32(runl->fifo->engine.subdev.device, runl->chan + (chan->id * 4), 0xffffffff); +} + +static int +ga100_chan_ramfc_write(struct nvkm_chan *chan, u64 offset, u64 length, u32 devm, bool priv) +{ + const u32 limit2 = ilog2(length / 8); + + nvkm_kmap(chan->inst); + nvkm_wo32(chan->inst, 0x010, 0x0000face); + nvkm_wo32(chan->inst, 0x030, 0x7ffff902); + nvkm_wo32(chan->inst, 0x048, lower_32_bits(offset)); + nvkm_wo32(chan->inst, 0x04c, upper_32_bits(offset) | (limit2 << 16)); + nvkm_wo32(chan->inst, 0x084, 0x20400000); + nvkm_wo32(chan->inst, 0x094, 0x30000000 | devm); + nvkm_wo32(chan->inst, 0x0e4, priv ? 0x00000020 : 0x00000000); + nvkm_wo32(chan->inst, 0x0e8, chan->id); + nvkm_wo32(chan->inst, 0x0f4, 0x00001000 | (priv ? 0x00000100 : 0x00000000)); + nvkm_wo32(chan->inst, 0x0f8, 0x80000000 | GA100_FIFO_NONSTALL_VECTOR); + nvkm_mo32(chan->inst, 0x218, 0x00000000, 0x00000000); + nvkm_done(chan->inst); + return 0; +} + +static const struct nvkm_chan_func_ramfc +ga100_chan_ramfc = { + .write = ga100_chan_ramfc_write, + .devm = 0xfff, + .priv = true, +}; + +const struct nvkm_chan_func +ga100_chan = { + .inst = &gf100_chan_inst, + .userd = &gv100_chan_userd, + .ramfc = &ga100_chan_ramfc, + .unbind = ga100_chan_unbind, + .start = ga100_chan_start, + .stop = ga100_chan_stop, + .preempt = gk110_chan_preempt, + .doorbell_handle = ga100_chan_doorbell_handle, +}; + +static void +ga100_cgrp_preempt(struct nvkm_cgrp *cgrp) +{ + struct nvkm_runl *runl = cgrp->runl; + + nvkm_wr32(runl->fifo->engine.subdev.device, runl->addr + 0x098, 0x01000000 | cgrp->id); +} + +const struct nvkm_cgrp_func +ga100_cgrp = { + .preempt = ga100_cgrp_preempt, +}; + +static int +ga100_engn_cxid(struct nvkm_engn *engn, bool *cgid) +{ + struct nvkm_runl *runl = engn->runl; + struct nvkm_device *device = runl->fifo->engine.subdev.device; + u32 stat = nvkm_rd32(device, runl->addr + 0x200 + engn->id * 0x40); + + ENGN_DEBUG(engn, "status %08x", stat); + *cgid = true; + + switch ((stat & 0x0000e000) >> 13) { + case 0 /* INVALID */: return -ENODEV; + case 1 /* VALID */: + case 5 /* SAVE */: return (stat & 0x00000fff); + case 6 /* LOAD */: return (stat & 0x0fff0000) >> 16; + case 7 /* SWITCH */: + if (nvkm_engine_chsw_load(engn->engine)) + return (stat & 0x0fff0000) >> 16; + return (stat & 0x00000fff); + default: + WARN_ON(1); + break; + } + + return -ENODEV; +} + +const struct nvkm_engn_func +ga100_engn = { + .cxid = ga100_engn_cxid, + .ctor = gk104_ectx_ctor, + .bind = gv100_ectx_bind, +}; + +const struct nvkm_engn_func +ga100_engn_ce = { + .cxid = ga100_engn_cxid, + .ctor = gv100_ectx_ce_ctor, + .bind = gv100_ectx_ce_bind, +}; + +static bool +ga100_runq_idle(struct nvkm_runq *runq) +{ + struct nvkm_device *device = runq->fifo->engine.subdev.device; + + return !(nvkm_rd32(device, 0x04015c + (runq->id * 0x800)) & 0x0000e000); +} + +static bool +ga100_runq_intr_1(struct nvkm_runq *runq, struct nvkm_runl *runl) +{ + struct nvkm_device *device = runq->fifo->engine.subdev.device; + u32 inte = nvkm_rd32(device, 0x040180 + (runq->id * 0x800)); + u32 intr = nvkm_rd32(device, 0x040148 + (runq->id * 0x800)); + u32 stat = intr & inte; + + if (!stat) { + RUNQ_DEBUG(runq, "inte1 %08x %08x", intr, inte); + return false; + } + + if (stat & 0x80000000) { + u32 chid = nvkm_rd32(device, 0x040120 + (runq->id * 0x0800)) & runl->chid->mask; + struct nvkm_chan *chan; + unsigned long flags; + + RUNQ_ERROR(runq, "CTXNOTVALID chid:%d", chid); + chan = nvkm_runl_chan_get_chid(runl, chid, &flags); + if (chan) { + nvkm_chan_error(chan, true); + nvkm_chan_put(&chan, flags); + } + + nvkm_mask(device, 0x0400ac + (runq->id * 0x800), 0x00030000, 0x00030000); + stat &= ~0x80000000; + } + + if (stat) { + RUNQ_ERROR(runq, "intr1 %08x", stat); + nvkm_wr32(device, 0x0401a0 + (runq->id * 0x800), stat); + } + + nvkm_wr32(device, 0x040148 + (runq->id * 0x800), intr); + return true; +} + +static bool +ga100_runq_intr_0(struct nvkm_runq *runq, struct nvkm_runl *runl) +{ + struct nvkm_device *device = runq->fifo->engine.subdev.device; + u32 inte = nvkm_rd32(device, 0x040170 + (runq->id * 0x800)); + u32 intr = nvkm_rd32(device, 0x040108 + (runq->id * 0x800)); + u32 stat = intr & inte; + + if (!stat) { + RUNQ_DEBUG(runq, "inte0 %08x %08x", intr, inte); + return false; + } + + /*TODO: expand on this when fixing up gf100's version. */ + if (stat & 0xc6afe000) { + u32 chid = nvkm_rd32(device, 0x040120 + (runq->id * 0x0800)) & runl->chid->mask; + struct nvkm_chan *chan; + unsigned long flags; + + RUNQ_ERROR(runq, "intr0 %08x", stat); + chan = nvkm_runl_chan_get_chid(runl, chid, &flags); + if (chan) { + nvkm_chan_error(chan, true); + nvkm_chan_put(&chan, flags); + } + + stat &= ~0xc6afe000; + } + + if (stat) { + RUNQ_ERROR(runq, "intr0 %08x", stat); + nvkm_wr32(device, 0x040190 + (runq->id * 0x800), stat); + } + + nvkm_wr32(device, 0x040108 + (runq->id * 0x800), intr); + return true; +} + +static bool +ga100_runq_intr(struct nvkm_runq *runq, struct nvkm_runl *runl) +{ + bool intr0 = ga100_runq_intr_0(runq, runl); + bool intr1 = ga100_runq_intr_1(runq, runl); + + return intr0 || intr1; +} + +static void +ga100_runq_init(struct nvkm_runq *runq) +{ + struct nvkm_device *device = runq->fifo->engine.subdev.device; + + nvkm_wr32(device, 0x040108 + (runq->id * 0x800), 0xffffffff); /* INTR_0 */ + nvkm_wr32(device, 0x040148 + (runq->id * 0x800), 0xffffffff); /* INTR_1 */ + nvkm_wr32(device, 0x040170 + (runq->id * 0x800), 0xffffffff); /* INTR_0_EN_SET_TREE */ + nvkm_wr32(device, 0x040180 + (runq->id * 0x800), 0xffffffff); /* INTR_1_EN_SET_TREE */ +} + +const struct nvkm_runq_func +ga100_runq = { + .init = ga100_runq_init, + .intr = ga100_runq_intr, + .idle = ga100_runq_idle, +}; + +static bool +ga100_runl_preempt_pending(struct nvkm_runl *runl) +{ + return nvkm_rd32(runl->fifo->engine.subdev.device, runl->addr + 0x098) & 0x00100000; +} + +static void +ga100_runl_preempt(struct nvkm_runl *runl) +{ + nvkm_wr32(runl->fifo->engine.subdev.device, runl->addr + 0x098, 0x00000000); +} + +static void +ga100_runl_allow(struct nvkm_runl *runl, u32 engm) +{ + nvkm_mask(runl->fifo->engine.subdev.device, runl->addr + 0x094, 0x00000001, 0x00000000); +} + +static void +ga100_runl_block(struct nvkm_runl *runl, u32 engm) +{ + nvkm_mask(runl->fifo->engine.subdev.device, runl->addr + 0x094, 0x00000001, 0x00000001); +} + +static bool +ga100_runl_pending(struct nvkm_runl *runl) +{ + struct nvkm_device *device = runl->fifo->engine.subdev.device; + + return nvkm_rd32(device, runl->addr + 0x08c) & 0x00008000; +} + +static void +ga100_runl_commit(struct nvkm_runl *runl, struct nvkm_memory *memory, u32 start, int count) +{ + struct nvkm_device *device = runl->fifo->engine.subdev.device; + u64 addr = nvkm_memory_addr(memory) + start; + + nvkm_wr32(device, runl->addr + 0x080, lower_32_bits(addr)); + nvkm_wr32(device, runl->addr + 0x084, upper_32_bits(addr)); + nvkm_wr32(device, runl->addr + 0x088, count); +} + +static irqreturn_t +ga100_runl_intr(struct nvkm_inth *inth) +{ + struct nvkm_runl *runl = container_of(inth, typeof(*runl), inth); + struct nvkm_engn *engn; + struct nvkm_device *device = runl->fifo->engine.subdev.device; + u32 inte = nvkm_rd32(device, runl->addr + 0x120); + u32 intr = nvkm_rd32(device, runl->addr + 0x100); + u32 stat = intr & inte; + u32 info; + + if (!stat) { + RUNL_DEBUG(runl, "inte %08x %08x", intr, inte); + return IRQ_NONE; + } + + if (stat & 0x00000007) { + nvkm_runl_foreach_engn_cond(engn, runl, stat & BIT(engn->id)) { + info = nvkm_rd32(device, runl->addr + 0x224 + (engn->id * 0x40)); + + tu102_fifo_intr_ctxsw_timeout_info(engn, info); + + nvkm_wr32(device, runl->addr + 0x100, BIT(engn->id)); + stat &= ~BIT(engn->id); + } + } + + if (stat & 0x00000300) { + nvkm_wr32(device, runl->addr + 0x100, stat & 0x00000300); + stat &= ~0x00000300; + } + + if (stat & 0x00010000) { + if (runl->runq[0]) { + if (runl->runq[0]->func->intr(runl->runq[0], runl)) + stat &= ~0x00010000; + } + } + + if (stat & 0x00020000) { + if (runl->runq[1]) { + if (runl->runq[1]->func->intr(runl->runq[1], runl)) + stat &= ~0x00020000; + } + } + + if (stat) { + RUNL_ERROR(runl, "intr %08x", stat); + nvkm_wr32(device, runl->addr + 0x140, stat); + } + + nvkm_wr32(device, runl->addr + 0x180, 0x00000001); + return IRQ_HANDLED; +} + +static void +ga100_runl_fini(struct nvkm_runl *runl) +{ + nvkm_mask(runl->fifo->engine.subdev.device, runl->addr + 0x300, 0x80000000, 0x00000000); + nvkm_inth_block(&runl->inth); +} + +static void +ga100_runl_init(struct nvkm_runl *runl) +{ + struct nvkm_fifo *fifo = runl->fifo; + struct nvkm_runq *runq; + struct nvkm_device *device = fifo->engine.subdev.device; + int i; + + /* Submit NULL runlist and preempt. */ + nvkm_wr32(device, runl->addr + 0x088, 0x00000000); + runl->func->preempt(runl); + + /* Enable doorbell. */ + nvkm_mask(device, runl->addr + 0x300, 0x80000000, 0x80000000); + + nvkm_wr32(device, runl->addr + 0x100, 0xffffffff); /* INTR_0 */ + nvkm_wr32(device, runl->addr + 0x140, 0xffffffff); /* INTR_0_EN_CLEAR_TREE(0) */ + nvkm_wr32(device, runl->addr + 0x120, 0x000f1307); /* INTR_0_EN_SET_TREE(0) */ + nvkm_wr32(device, runl->addr + 0x148, 0xffffffff); /* INTR_0_EN_CLEAR_TREE(1) */ + nvkm_wr32(device, runl->addr + 0x128, 0x00000000); /* INTR_0_EN_SET_TREE(1) */ + + /* Init PBDMA(s). */ + for (i = 0; i < runl->runq_nr; i++) { + runq = runl->runq[i]; + runq->func->init(runq); + } + + nvkm_inth_allow(&runl->inth); +} + +const struct nvkm_runl_func +ga100_runl = { + .init = ga100_runl_init, + .fini = ga100_runl_fini, + .size = 16, + .update = nv50_runl_update, + .insert_cgrp = gv100_runl_insert_cgrp, + .insert_chan = gv100_runl_insert_chan, + .commit = ga100_runl_commit, + .wait = nv50_runl_wait, + .pending = ga100_runl_pending, + .block = ga100_runl_block, + .allow = ga100_runl_allow, + .preempt = ga100_runl_preempt, + .preempt_pending = ga100_runl_preempt_pending, +}; + +static int +ga100_runl_new(struct nvkm_fifo *fifo, int id, u32 addr, struct nvkm_runl **prunl) +{ + struct nvkm_device *device = fifo->engine.subdev.device; + struct nvkm_runl *runl; + u32 chcfg = nvkm_rd32(device, addr + 0x004); + u32 chnum = 1 << (chcfg & 0x0000000f); + u32 chaddr = (chcfg & 0xfffffff0); + u32 dbcfg = nvkm_rd32(device, addr + 0x008); + u32 vector = nvkm_rd32(device, addr + 0x160); + int i, ret; + + runl = *prunl = nvkm_runl_new(fifo, id, addr, chnum); + if (IS_ERR(runl)) + return PTR_ERR(runl); + + for (i = 0; i < 2; i++) { + u32 pbcfg = nvkm_rd32(device, addr + 0x010 + (i * 0x04)); + if (pbcfg & 0x80000000) { + runl->runq[runl->runq_nr] = + nvkm_runq_new(fifo, ((pbcfg & 0x03fffc00) - 0x040000) / 0x800); + if (!runl->runq[runl->runq_nr]) + return -ENOMEM; + + runl->runq_nr++; + } + } + + ret = nvkm_inth_add(&device->vfn->intr, vector & 0x00000fff, NVKM_INTR_PRIO_NORMAL, + &fifo->engine.subdev, ga100_runl_intr, &runl->inth); + if (ret) + return ret; + + runl->chan = chaddr; + runl->doorbell = dbcfg >> 16; + return 0; +} + +static irqreturn_t +ga100_fifo_nonstall_intr(struct nvkm_inth *inth) +{ + struct nvkm_fifo *fifo = container_of(inth, typeof(*fifo), nonstall.intr); + + nvkm_event_ntfy(&fifo->nonstall.event, 0, NVKM_FIFO_NONSTALL_EVENT); + return IRQ_HANDLED; +} + +static void +ga100_fifo_nonstall_block(struct nvkm_event *event, int type, int index) +{ + struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), nonstall.event); + + nvkm_inth_block(&fifo->nonstall.intr); +} + +static void +ga100_fifo_nonstall_allow(struct nvkm_event *event, int type, int index) +{ + struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), nonstall.event); + + nvkm_inth_allow(&fifo->nonstall.intr); +} + +const struct nvkm_event_func +ga100_fifo_nonstall = { + .init = ga100_fifo_nonstall_allow, + .fini = ga100_fifo_nonstall_block, +}; + +int +ga100_fifo_nonstall_ctor(struct nvkm_fifo *fifo) +{ + return nvkm_inth_add(&fifo->engine.subdev.device->vfn->intr, GA100_FIFO_NONSTALL_VECTOR, + NVKM_INTR_PRIO_NORMAL, &fifo->engine.subdev, ga100_fifo_nonstall_intr, + &fifo->nonstall.intr); +} + +int +ga100_fifo_runl_ctor(struct nvkm_fifo *fifo) +{ + struct nvkm_device *device = fifo->engine.subdev.device; + struct nvkm_top_device *tdev; + struct nvkm_runl *runl; + int id = 0, ret; + + nvkm_list_foreach(tdev, &device->top->device, head, tdev->runlist >= 0) { + runl = nvkm_runl_get(fifo, -1, tdev->runlist); + if (!runl) { + ret = ga100_runl_new(fifo, id++, tdev->runlist, &runl); + if (ret) + return ret; + } + + if (tdev->engine < 0) + continue; + + nvkm_runl_add(runl, tdev->engine, (tdev->type == NVKM_ENGINE_CE) ? + fifo->func->engn_ce : fifo->func->engn, tdev->type, tdev->inst); + } + + return 0; +} + +static const struct nvkm_fifo_func +ga100_fifo = { + .runl_ctor = ga100_fifo_runl_ctor, + .mmu_fault = &tu102_fifo_mmu_fault, + .nonstall_ctor = ga100_fifo_nonstall_ctor, + .nonstall = &ga100_fifo_nonstall, + .runl = &ga100_runl, + .runq = &ga100_runq, + .engn = &ga100_engn, + .engn_ce = &ga100_engn_ce, + .cgrp = {{ 0, 0, KEPLER_CHANNEL_GROUP_A }, &ga100_cgrp, .force = true }, + .chan = {{ 0, 0, AMPERE_CHANNEL_GPFIFO_A }, &ga100_chan }, +}; + +int +ga100_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, + struct nvkm_fifo **pfifo) +{ + return nvkm_fifo_new_(&ga100_fifo, device, type, inst, pfifo); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga102.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga102.c index c630dbd2911a..2cdf5da339b6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga102.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga102.c @@ -19,293 +19,27 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ -#define ga102_fifo(p) container_of((p), struct ga102_fifo, base.engine) -#define ga102_chan(p) container_of((p), struct ga102_chan, object) -#include <engine/fifo.h> -#include "user.h" +#include "priv.h" -#include <core/memory.h> -#include <subdev/mmu.h> -#include <subdev/timer.h> -#include <subdev/top.h> - -#include <nvif/cl0080.h> -#include <nvif/clc36f.h> #include <nvif/class.h> -struct ga102_fifo { - struct nvkm_fifo base; -}; - -struct ga102_chan { - struct nvkm_object object; - - struct { - u32 runl; - u32 chan; - } ctrl; - - struct nvkm_memory *mthd; - struct nvkm_memory *inst; - struct nvkm_memory *user; - struct nvkm_memory *runl; - - struct nvkm_vmm *vmm; -}; - -static int -ga102_chan_sclass(struct nvkm_object *object, int index, struct nvkm_oclass *oclass) -{ - if (index == 0) { - oclass->ctor = nvkm_object_new; - oclass->base = (struct nvkm_sclass) { -1, -1, AMPERE_DMA_COPY_B }; - return 0; - } - - return -EINVAL; -} - -static int -ga102_chan_map(struct nvkm_object *object, void *argv, u32 argc, - enum nvkm_object_map *type, u64 *addr, u64 *size) -{ - struct ga102_chan *chan = ga102_chan(object); - struct nvkm_device *device = chan->object.engine->subdev.device; - u64 bar2 = nvkm_memory_bar2(chan->user); - - if (bar2 == ~0ULL) - return -EFAULT; - - *type = NVKM_OBJECT_MAP_IO; - *addr = device->func->resource_addr(device, 3) + bar2; - *size = 0x1000; - return 0; -} - -static int -ga102_chan_fini(struct nvkm_object *object, bool suspend) -{ - struct ga102_chan *chan = ga102_chan(object); - struct nvkm_device *device = chan->object.engine->subdev.device; - - nvkm_wr32(device, chan->ctrl.chan, 0x00000003); - - nvkm_wr32(device, chan->ctrl.runl + 0x098, 0x01000000); - nvkm_msec(device, 2000, - if (!(nvkm_rd32(device, chan->ctrl.runl + 0x098) & 0x00100000)) - break; - ); - - nvkm_wr32(device, chan->ctrl.runl + 0x088, 0); - - nvkm_wr32(device, chan->ctrl.chan, 0xffffffff); - return 0; -} - -static int -ga102_chan_init(struct nvkm_object *object) -{ - struct ga102_chan *chan = ga102_chan(object); - struct nvkm_device *device = chan->object.engine->subdev.device; - - nvkm_mask(device, chan->ctrl.runl + 0x300, 0x80000000, 0x80000000); - - nvkm_wr32(device, chan->ctrl.runl + 0x080, lower_32_bits(nvkm_memory_addr(chan->runl))); - nvkm_wr32(device, chan->ctrl.runl + 0x084, upper_32_bits(nvkm_memory_addr(chan->runl))); - nvkm_wr32(device, chan->ctrl.runl + 0x088, 2); - - nvkm_wr32(device, chan->ctrl.chan, 0x00000002); - nvkm_wr32(device, chan->ctrl.runl + 0x0090, 0); - return 0; -} - -static void * -ga102_chan_dtor(struct nvkm_object *object) -{ - struct ga102_chan *chan = ga102_chan(object); - - if (chan->vmm) { - nvkm_vmm_part(chan->vmm, chan->inst); - nvkm_vmm_unref(&chan->vmm); - } - - nvkm_memory_unref(&chan->runl); - nvkm_memory_unref(&chan->user); - nvkm_memory_unref(&chan->inst); - nvkm_memory_unref(&chan->mthd); - return chan; -} - -static const struct nvkm_object_func -ga102_chan = { - .dtor = ga102_chan_dtor, - .init = ga102_chan_init, - .fini = ga102_chan_fini, - .map = ga102_chan_map, - .sclass = ga102_chan_sclass, -}; - -static int -ga102_chan_new(struct nvkm_device *device, - const struct nvkm_oclass *oclass, void *argv, u32 argc, struct nvkm_object **pobject) -{ - struct volta_channel_gpfifo_a_v0 *args = argv; - struct nvkm_top_device *tdev; - struct nvkm_vmm *vmm; - struct ga102_chan *chan; - int ret; - - if (argc != sizeof(*args)) - return -ENOSYS; - - vmm = nvkm_uvmm_search(oclass->client, args->vmm); - if (IS_ERR(vmm)) - return PTR_ERR(vmm); - - if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) - return -ENOMEM; - - nvkm_object_ctor(&ga102_chan, oclass, &chan->object); - *pobject = &chan->object; - - list_for_each_entry(tdev, &device->top->device, head) { - if (tdev->type == NVKM_ENGINE_CE) { - chan->ctrl.runl = tdev->runlist; - break; - } - } - - if (!chan->ctrl.runl) - return -ENODEV; - - chan->ctrl.chan = nvkm_rd32(device, chan->ctrl.runl + 0x004) & 0xfffffff0; - - args->chid = 0; - args->inst = 0; - args->token = nvkm_rd32(device, chan->ctrl.runl + 0x008) & 0xffff0000; - - ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 0x1000, true, &chan->mthd); - if (ret) - return ret; - - ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 0x1000, true, &chan->inst); - if (ret) - return ret; - - nvkm_kmap(chan->inst); - nvkm_wo32(chan->inst, 0x010, 0x0000face); - nvkm_wo32(chan->inst, 0x030, 0x7ffff902); - nvkm_wo32(chan->inst, 0x048, lower_32_bits(args->ioffset)); - nvkm_wo32(chan->inst, 0x04c, upper_32_bits(args->ioffset) | - (order_base_2(args->ilength / 8) << 16)); - nvkm_wo32(chan->inst, 0x084, 0x20400000); - nvkm_wo32(chan->inst, 0x094, 0x30000001); - nvkm_wo32(chan->inst, 0x0ac, 0x00020000); - nvkm_wo32(chan->inst, 0x0e4, 0x00000000); - nvkm_wo32(chan->inst, 0x0e8, 0); - nvkm_wo32(chan->inst, 0x0f4, 0x00001000); - nvkm_wo32(chan->inst, 0x0f8, 0x10003080); - nvkm_mo32(chan->inst, 0x218, 0x00000000, 0x00000000); - nvkm_wo32(chan->inst, 0x220, lower_32_bits(nvkm_memory_bar2(chan->mthd))); - nvkm_wo32(chan->inst, 0x224, upper_32_bits(nvkm_memory_bar2(chan->mthd))); - nvkm_done(chan->inst); - - ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 0x1000, true, &chan->user); - if (ret) - return ret; - - ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 0x1000, true, &chan->runl); - if (ret) - return ret; - - nvkm_kmap(chan->runl); - nvkm_wo32(chan->runl, 0x00, 0x80030001); - nvkm_wo32(chan->runl, 0x04, 1); - nvkm_wo32(chan->runl, 0x08, 0); - nvkm_wo32(chan->runl, 0x0c, 0x00000000); - nvkm_wo32(chan->runl, 0x10, lower_32_bits(nvkm_memory_addr(chan->user))); - nvkm_wo32(chan->runl, 0x14, upper_32_bits(nvkm_memory_addr(chan->user))); - nvkm_wo32(chan->runl, 0x18, lower_32_bits(nvkm_memory_addr(chan->inst))); - nvkm_wo32(chan->runl, 0x1c, upper_32_bits(nvkm_memory_addr(chan->inst))); - nvkm_done(chan->runl); - - ret = nvkm_vmm_join(vmm, chan->inst); - if (ret) - return ret; - - chan->vmm = nvkm_vmm_ref(vmm); - return 0; -} - -static const struct nvkm_device_oclass -ga102_chan_oclass = { - .ctor = ga102_chan_new, -}; - -static int -ga102_user_new(struct nvkm_device *device, - const struct nvkm_oclass *oclass, void *argv, u32 argc, struct nvkm_object **pobject) -{ - return tu102_fifo_user_new(oclass, argv, argc, pobject); -} - -static const struct nvkm_device_oclass -ga102_user_oclass = { - .ctor = ga102_user_new, -}; - -static int -ga102_fifo_sclass(struct nvkm_oclass *oclass, int index, const struct nvkm_device_oclass **class) -{ - if (index == 0) { - oclass->base = (struct nvkm_sclass) { -1, -1, VOLTA_USERMODE_A }; - *class = &ga102_user_oclass; - return 0; - } else - if (index == 1) { - oclass->base = (struct nvkm_sclass) { 0, 0, AMPERE_CHANNEL_GPFIFO_B }; - *class = &ga102_chan_oclass; - return 0; - } - - return 2; -} - -static int -ga102_fifo_info(struct nvkm_engine *engine, u64 mthd, u64 *data) -{ - switch (mthd) { - case NV_DEVICE_HOST_CHANNELS: *data = 1; return 0; - default: - break; - } - - return -ENOSYS; -} - -static void * -ga102_fifo_dtor(struct nvkm_engine *engine) -{ - return ga102_fifo(engine); -} - -static const struct nvkm_engine_func +static const struct nvkm_fifo_func ga102_fifo = { - .dtor = ga102_fifo_dtor, - .info = ga102_fifo_info, - .base.sclass = ga102_fifo_sclass, + .runl_ctor = ga100_fifo_runl_ctor, + .mmu_fault = &tu102_fifo_mmu_fault, + .nonstall_ctor = ga100_fifo_nonstall_ctor, + .nonstall = &ga100_fifo_nonstall, + .runl = &ga100_runl, + .runq = &ga100_runq, + .engn = &ga100_engn, + .engn_ce = &ga100_engn_ce, + .cgrp = {{ 0, 0, KEPLER_CHANNEL_GROUP_A }, &ga100_cgrp, .force = true }, + .chan = {{ 0, 0, AMPERE_CHANNEL_GPFIFO_B }, &ga100_chan }, }; int ga102_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fifo **pfifo) { - struct ga102_fifo *fifo; - - if (!(fifo = kzalloc(sizeof(*fifo), GFP_KERNEL))) - return -ENOMEM; - - nvkm_engine_ctor(&ga102_fifo, device, type, inst, true, &fifo->base.engine); - *pfifo = &fifo->base; - return 0; + return nvkm_fifo_new_(&ga102_fifo, device, type, inst, pfifo); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c index 8b4f36b3e34b..5bb65258c36d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c @@ -21,186 +21,456 @@ * * Authors: Ben Skeggs */ -#include "gf100.h" -#include "changf100.h" +#include "priv.h" +#include "cgrp.h" +#include "chan.h" +#include "chid.h" +#include "runl.h" +#include "runq.h" -#include <core/client.h> -#include <core/enum.h> #include <core/gpuobj.h> #include <subdev/bar.h> #include <subdev/fault.h> +#include <subdev/mc.h> +#include <subdev/mmu.h> #include <engine/sw.h> #include <nvif/class.h> +void +gf100_chan_preempt(struct nvkm_chan *chan) +{ + nvkm_wr32(chan->cgrp->runl->fifo->engine.subdev.device, 0x002634, chan->id); +} + static void -gf100_fifo_uevent_init(struct nvkm_fifo *fifo) +gf100_chan_stop(struct nvkm_chan *chan) { - struct nvkm_device *device = fifo->engine.subdev.device; - nvkm_mask(device, 0x002140, 0x80000000, 0x80000000); + struct nvkm_device *device = chan->cgrp->runl->fifo->engine.subdev.device; + + nvkm_mask(device, 0x003004 + (chan->id * 8), 0x00000001, 0x00000000); } static void -gf100_fifo_uevent_fini(struct nvkm_fifo *fifo) +gf100_chan_start(struct nvkm_chan *chan) { + struct nvkm_device *device = chan->cgrp->runl->fifo->engine.subdev.device; + + nvkm_wr32(device, 0x003004 + (chan->id * 8), 0x001f0001); +} + +static void gf100_fifo_intr_engine(struct nvkm_fifo *); + +static void +gf100_chan_unbind(struct nvkm_chan *chan) +{ + struct nvkm_fifo *fifo = chan->cgrp->runl->fifo; struct nvkm_device *device = fifo->engine.subdev.device; - nvkm_mask(device, 0x002140, 0x80000000, 0x00000000); + + /*TODO: Is this cargo-culted, or necessary? RM does *something* here... Why? */ + gf100_fifo_intr_engine(fifo); + + nvkm_wr32(device, 0x003000 + (chan->id * 8), 0x00000000); } +static void +gf100_chan_bind(struct nvkm_chan *chan) +{ + struct nvkm_device *device = chan->cgrp->runl->fifo->engine.subdev.device; + + nvkm_wr32(device, 0x003000 + (chan->id * 8), 0xc0000000 | chan->inst->addr >> 12); +} + +static int +gf100_chan_ramfc_write(struct nvkm_chan *chan, u64 offset, u64 length, u32 devm, bool priv) +{ + const u64 userd = nvkm_memory_addr(chan->userd.mem) + chan->userd.base; + const u32 limit2 = ilog2(length / 8); + + nvkm_kmap(chan->inst); + nvkm_wo32(chan->inst, 0x08, lower_32_bits(userd)); + nvkm_wo32(chan->inst, 0x0c, upper_32_bits(userd)); + nvkm_wo32(chan->inst, 0x10, 0x0000face); + nvkm_wo32(chan->inst, 0x30, 0xfffff902); + nvkm_wo32(chan->inst, 0x48, lower_32_bits(offset)); + nvkm_wo32(chan->inst, 0x4c, upper_32_bits(offset) | (limit2 << 16)); + nvkm_wo32(chan->inst, 0x54, 0x00000002); + nvkm_wo32(chan->inst, 0x84, 0x20400000); + nvkm_wo32(chan->inst, 0x94, 0x30000000 | devm); + nvkm_wo32(chan->inst, 0x9c, 0x00000100); + nvkm_wo32(chan->inst, 0xa4, 0x1f1f1f1f); + nvkm_wo32(chan->inst, 0xa8, 0x1f1f1f1f); + nvkm_wo32(chan->inst, 0xac, 0x0000001f); + nvkm_wo32(chan->inst, 0xb8, 0xf8000000); + nvkm_wo32(chan->inst, 0xf8, 0x10003080); /* 0x002310 */ + nvkm_wo32(chan->inst, 0xfc, 0x10000010); /* 0x002350 */ + nvkm_done(chan->inst); + return 0; +} + +static const struct nvkm_chan_func_ramfc +gf100_chan_ramfc = { + .write = gf100_chan_ramfc_write, + .devm = 0xfff, +}; + void -gf100_fifo_runlist_commit(struct gf100_fifo *fifo) +gf100_chan_userd_clear(struct nvkm_chan *chan) { - struct gf100_fifo_chan *chan; - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; - struct nvkm_device *device = subdev->device; - struct nvkm_memory *cur; - int nr = 0; - int target; + nvkm_kmap(chan->userd.mem); + nvkm_wo32(chan->userd.mem, chan->userd.base + 0x040, 0x00000000); + nvkm_wo32(chan->userd.mem, chan->userd.base + 0x044, 0x00000000); + nvkm_wo32(chan->userd.mem, chan->userd.base + 0x048, 0x00000000); + nvkm_wo32(chan->userd.mem, chan->userd.base + 0x04c, 0x00000000); + nvkm_wo32(chan->userd.mem, chan->userd.base + 0x050, 0x00000000); + nvkm_wo32(chan->userd.mem, chan->userd.base + 0x058, 0x00000000); + nvkm_wo32(chan->userd.mem, chan->userd.base + 0x05c, 0x00000000); + nvkm_wo32(chan->userd.mem, chan->userd.base + 0x060, 0x00000000); + nvkm_wo32(chan->userd.mem, chan->userd.base + 0x088, 0x00000000); + nvkm_wo32(chan->userd.mem, chan->userd.base + 0x08c, 0x00000000); + nvkm_done(chan->userd.mem); +} - mutex_lock(&fifo->base.mutex); - cur = fifo->runlist.mem[fifo->runlist.active]; - fifo->runlist.active = !fifo->runlist.active; +static const struct nvkm_chan_func_userd +gf100_chan_userd = { + .bar = 1, + .size = 0x1000, + .clear = gf100_chan_userd_clear, +}; - nvkm_kmap(cur); - list_for_each_entry(chan, &fifo->chan, head) { - nvkm_wo32(cur, (nr * 8) + 0, chan->base.chid); - nvkm_wo32(cur, (nr * 8) + 4, 0x00000004); - nr++; - } - nvkm_done(cur); +const struct nvkm_chan_func_inst +gf100_chan_inst = { + .size = 0x1000, + .zero = true, + .vmm = true, +}; - switch (nvkm_memory_target(cur)) { - case NVKM_MEM_TARGET_VRAM: target = 0; break; - case NVKM_MEM_TARGET_NCOH: target = 3; break; +static const struct nvkm_chan_func +gf100_chan = { + .inst = &gf100_chan_inst, + .userd = &gf100_chan_userd, + .ramfc = &gf100_chan_ramfc, + .bind = gf100_chan_bind, + .unbind = gf100_chan_unbind, + .start = gf100_chan_start, + .stop = gf100_chan_stop, + .preempt = gf100_chan_preempt, +}; + +static void +gf100_ectx_bind(struct nvkm_engn *engn, struct nvkm_cctx *cctx, struct nvkm_chan *chan) +{ + u64 addr = 0ULL; + u32 ptr0; + + switch (engn->engine->subdev.type) { + case NVKM_ENGINE_SW : return; + case NVKM_ENGINE_GR : ptr0 = 0x0210; break; + case NVKM_ENGINE_CE : ptr0 = 0x0230 + (engn->engine->subdev.inst * 0x10); break; + case NVKM_ENGINE_MSPDEC: ptr0 = 0x0250; break; + case NVKM_ENGINE_MSPPP : ptr0 = 0x0260; break; + case NVKM_ENGINE_MSVLD : ptr0 = 0x0270; break; default: - mutex_unlock(&fifo->base.mutex); WARN_ON(1); return; } - nvkm_wr32(device, 0x002270, (nvkm_memory_addr(cur) >> 12) | - (target << 28)); - nvkm_wr32(device, 0x002274, 0x01f00000 | nr); + if (cctx) { + addr = cctx->vctx->vma->addr; + addr |= 4ULL; + } - if (wait_event_timeout(fifo->runlist.wait, - !(nvkm_rd32(device, 0x00227c) & 0x00100000), - msecs_to_jiffies(2000)) == 0) - nvkm_error(subdev, "runlist update timeout\n"); - mutex_unlock(&fifo->base.mutex); + nvkm_kmap(chan->inst); + nvkm_wo32(chan->inst, ptr0 + 0, lower_32_bits(addr)); + nvkm_wo32(chan->inst, ptr0 + 4, upper_32_bits(addr)); + nvkm_done(chan->inst); } -void -gf100_fifo_runlist_remove(struct gf100_fifo *fifo, struct gf100_fifo_chan *chan) +static int +gf100_ectx_ctor(struct nvkm_engn *engn, struct nvkm_vctx *vctx) +{ + int ret; + + ret = nvkm_vmm_get(vctx->vmm, 12, vctx->inst->size, &vctx->vma); + if (ret) + return ret; + + return nvkm_memory_map(vctx->inst, 0, vctx->vmm, vctx->vma, NULL, 0); +} + +bool +gf100_engn_mmu_fault_triggered(struct nvkm_engn *engn) { - mutex_lock(&fifo->base.mutex); - list_del_init(&chan->head); - mutex_unlock(&fifo->base.mutex); + struct nvkm_runl *runl = engn->runl; + struct nvkm_fifo *fifo = runl->fifo; + struct nvkm_device *device = fifo->engine.subdev.device; + u32 data = nvkm_rd32(device, 0x002a30 + (engn->id * 4)); + + ENGN_DEBUG(engn, "%08x: mmu fault triggered", data); + if (!(data & 0x00000100)) + return false; + + spin_lock(&fifo->lock); + nvkm_mask(device, 0x002a30 + (engn->id * 4), 0x00000100, 0x00000000); + if (atomic_dec_and_test(&runl->rc_triggered)) + nvkm_mask(device, 0x002140, 0x00000100, 0x00000100); + spin_unlock(&fifo->lock); + return true; } void -gf100_fifo_runlist_insert(struct gf100_fifo *fifo, struct gf100_fifo_chan *chan) +gf100_engn_mmu_fault_trigger(struct nvkm_engn *engn) { - mutex_lock(&fifo->base.mutex); - list_add_tail(&chan->head, &fifo->chan); - mutex_unlock(&fifo->base.mutex); + struct nvkm_runl *runl = engn->runl; + struct nvkm_fifo *fifo = runl->fifo; + struct nvkm_device *device = fifo->engine.subdev.device; + + ENGN_DEBUG(engn, "triggering mmu fault on 0x%02x", engn->fault); + spin_lock(&fifo->lock); + if (atomic_inc_return(&runl->rc_triggered) == 1) + nvkm_mask(device, 0x002140, 0x00000100, 0x00000000); + nvkm_wr32(device, 0x002100, 0x00000100); + nvkm_wr32(device, 0x002a30 + (engn->id * 4), 0x00000100 | engn->fault); + spin_unlock(&fifo->lock); } -static struct nvkm_engine * -gf100_fifo_id_engine(struct nvkm_fifo *fifo, int engi) +/*TODO: clean all this up. */ +struct gf100_engn_status { + bool busy; + bool save; + bool unk0; + bool unk1; + u8 chid; +}; + +static void +gf100_engn_status(struct nvkm_engn *engn, struct gf100_engn_status *status) { - enum nvkm_subdev_type type; - int inst; + u32 stat = nvkm_rd32(engn->engine->subdev.device, 0x002640 + (engn->id * 4)); - switch (engi) { - case GF100_FIFO_ENGN_GR : type = NVKM_ENGINE_GR ; inst = 0; break; - case GF100_FIFO_ENGN_MSPDEC: type = NVKM_ENGINE_MSPDEC; inst = 0; break; - case GF100_FIFO_ENGN_MSPPP : type = NVKM_ENGINE_MSPPP ; inst = 0; break; - case GF100_FIFO_ENGN_MSVLD : type = NVKM_ENGINE_MSVLD ; inst = 0; break; - case GF100_FIFO_ENGN_CE0 : type = NVKM_ENGINE_CE ; inst = 0; break; - case GF100_FIFO_ENGN_CE1 : type = NVKM_ENGINE_CE ; inst = 1; break; - case GF100_FIFO_ENGN_SW : type = NVKM_ENGINE_SW ; inst = 0; break; - default: - WARN_ON(1); - return NULL; - } + status->busy = (stat & 0x10000000); + status->save = (stat & 0x00100000); + status->unk0 = (stat & 0x00004000); + status->unk1 = (stat & 0x00001000); + status->chid = (stat & 0x0000007f); - return nvkm_device_engine(fifo->engine.subdev.device, type, inst); + ENGN_DEBUG(engn, "%08x: busy %d save %d unk0 %d unk1 %d chid %d", + stat, status->busy, status->save, status->unk0, status->unk1, status->chid); } static int -gf100_fifo_engine_id(struct nvkm_fifo *base, struct nvkm_engine *engine) -{ - switch (engine->subdev.type) { - case NVKM_ENGINE_GR : return GF100_FIFO_ENGN_GR; - case NVKM_ENGINE_MSPDEC: return GF100_FIFO_ENGN_MSPDEC; - case NVKM_ENGINE_MSPPP : return GF100_FIFO_ENGN_MSPPP; - case NVKM_ENGINE_MSVLD : return GF100_FIFO_ENGN_MSVLD; - case NVKM_ENGINE_CE : return GF100_FIFO_ENGN_CE0 + engine->subdev.inst; - case NVKM_ENGINE_SW : return GF100_FIFO_ENGN_SW; - default: - WARN_ON(1); - return -1; +gf100_engn_cxid(struct nvkm_engn *engn, bool *cgid) +{ + struct gf100_engn_status status; + + gf100_engn_status(engn, &status); + if (status.busy) { + *cgid = false; + return status.chid; } + + return -ENODEV; } -static void -gf100_fifo_recover_work(struct work_struct *w) +static bool +gf100_engn_chsw(struct nvkm_engn *engn) { - struct gf100_fifo *fifo = container_of(w, typeof(*fifo), recover.work); - struct nvkm_device *device = fifo->base.engine.subdev.device; - struct nvkm_engine *engine; - unsigned long flags; - u32 engm, engn, todo; + struct gf100_engn_status status; + + gf100_engn_status(engn, &status); + if (status.busy && (status.unk0 || status.unk1)) + return true; - spin_lock_irqsave(&fifo->base.lock, flags); - engm = fifo->recover.mask; - fifo->recover.mask = 0ULL; - spin_unlock_irqrestore(&fifo->base.lock, flags); + return false; +} - nvkm_mask(device, 0x002630, engm, engm); +static const struct nvkm_engn_func +gf100_engn = { + .chsw = gf100_engn_chsw, + .cxid = gf100_engn_cxid, + .mmu_fault_trigger = gf100_engn_mmu_fault_trigger, + .mmu_fault_triggered = gf100_engn_mmu_fault_triggered, + .ctor = gf100_ectx_ctor, + .bind = gf100_ectx_bind, +}; - for (todo = engm; engn = __ffs(todo), todo; todo &= ~BIT_ULL(engn)) { - if ((engine = gf100_fifo_id_engine(&fifo->base, engn))) { - nvkm_subdev_fini(&engine->subdev, false); - WARN_ON(nvkm_subdev_init(&engine->subdev)); +const struct nvkm_engn_func +gf100_engn_sw = { +}; + +static const struct nvkm_bitfield +gf100_runq_intr_0_names[] = { +/* { 0x00008000, "" } seen with null ib push */ + { 0x00200000, "ILLEGAL_MTHD" }, + { 0x00800000, "EMPTY_SUBC" }, + {} +}; + +bool +gf100_runq_intr(struct nvkm_runq *runq, struct nvkm_runl *null) +{ + struct nvkm_subdev *subdev = &runq->fifo->engine.subdev; + struct nvkm_device *device = subdev->device; + u32 mask = nvkm_rd32(device, 0x04010c + (runq->id * 0x2000)); + u32 stat = nvkm_rd32(device, 0x040108 + (runq->id * 0x2000)) & mask; + u32 addr = nvkm_rd32(device, 0x0400c0 + (runq->id * 0x2000)); + u32 data = nvkm_rd32(device, 0x0400c4 + (runq->id * 0x2000)); + u32 chid = nvkm_rd32(device, 0x040120 + (runq->id * 0x2000)) & runq->fifo->chid->mask; + u32 subc = (addr & 0x00070000) >> 16; + u32 mthd = (addr & 0x00003ffc); + u32 show = stat; + struct nvkm_chan *chan; + unsigned long flags; + char msg[128]; + + if (stat & 0x00800000) { + if (device->sw) { + if (nvkm_sw_mthd(device->sw, chid, subc, mthd, data)) + show &= ~0x00800000; } } - gf100_fifo_runlist_commit(fifo); - nvkm_wr32(device, 0x00262c, engm); - nvkm_mask(device, 0x002630, engm, 0x00000000); + if (show) { + nvkm_snprintbf(msg, sizeof(msg), runq->func->intr_0_names, show); + chan = nvkm_chan_get_chid(&runq->fifo->engine, chid, &flags); + nvkm_error(subdev, "PBDMA%d: %08x [%s] ch %d [%010llx %s] " + "subc %d mthd %04x data %08x\n", + runq->id, show, msg, chid, chan ? chan->inst->addr : 0, + chan ? chan->name : "unknown", subc, mthd, data); + + /*TODO: use proper procedure for clearing each exception / debug output */ + if ((stat & 0xc67fe000) && chan) + nvkm_chan_error(chan, true); + nvkm_chan_put(&chan, flags); + } + + nvkm_wr32(device, 0x0400c0 + (runq->id * 0x2000), 0x80600008); + nvkm_wr32(device, 0x040108 + (runq->id * 0x2000), stat); + return true; +} + +void +gf100_runq_init(struct nvkm_runq *runq) +{ + struct nvkm_device *device = runq->fifo->engine.subdev.device; + + nvkm_mask(device, 0x04013c + (runq->id * 0x2000), 0x10000100, 0x00000000); + nvkm_wr32(device, 0x040108 + (runq->id * 0x2000), 0xffffffff); /* INTR */ + nvkm_wr32(device, 0x04010c + (runq->id * 0x2000), 0xfffffeff); /* INTREN */ +} + +static const struct nvkm_runq_func +gf100_runq = { + .init = gf100_runq_init, + .intr = gf100_runq_intr, + .intr_0_names = gf100_runq_intr_0_names, +}; + +bool +gf100_runl_preempt_pending(struct nvkm_runl *runl) +{ + return nvkm_rd32(runl->fifo->engine.subdev.device, 0x002634) & 0x00100000; } static void -gf100_fifo_recover(struct gf100_fifo *fifo, struct nvkm_engine *engine, - struct gf100_fifo_chan *chan) +gf100_runl_fault_clear(struct nvkm_runl *runl) { - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; - struct nvkm_device *device = subdev->device; - u32 chid = chan->base.chid; - int engi = gf100_fifo_engine_id(&fifo->base, engine); + nvkm_mask(runl->fifo->engine.subdev.device, 0x00262c, 0x00000000, 0x00000000); +} + +static void +gf100_runl_allow(struct nvkm_runl *runl, u32 engm) +{ + nvkm_mask(runl->fifo->engine.subdev.device, 0x002630, engm, 0x00000000); +} + +static void +gf100_runl_block(struct nvkm_runl *runl, u32 engm) +{ + nvkm_mask(runl->fifo->engine.subdev.device, 0x002630, engm, engm); +} + +static bool +gf100_runl_pending(struct nvkm_runl *runl) +{ + return nvkm_rd32(runl->fifo->engine.subdev.device, 0x00227c) & 0x00100000; +} + +static void +gf100_runl_commit(struct nvkm_runl *runl, struct nvkm_memory *memory, u32 start, int count) +{ + struct nvkm_device *device = runl->fifo->engine.subdev.device; + u64 addr = nvkm_memory_addr(memory) + start; + int target; + + switch (nvkm_memory_target(memory)) { + case NVKM_MEM_TARGET_VRAM: target = 0; break; + case NVKM_MEM_TARGET_NCOH: target = 3; break; + default: + WARN_ON(1); + return; + } + + nvkm_wr32(device, 0x002270, (target << 28) | (addr >> 12)); + nvkm_wr32(device, 0x002274, 0x01f00000 | count); +} + +static void +gf100_runl_insert_chan(struct nvkm_chan *chan, struct nvkm_memory *memory, u64 offset) +{ + nvkm_wo32(memory, offset + 0, chan->id); + nvkm_wo32(memory, offset + 4, 0x00000004); +} - nvkm_error(subdev, "%s engine fault on channel %d, recovering...\n", - engine->subdev.name, chid); - assert_spin_locked(&fifo->base.lock); +static const struct nvkm_runl_func +gf100_runl = { + .size = 8, + .update = nv50_runl_update, + .insert_chan = gf100_runl_insert_chan, + .commit = gf100_runl_commit, + .wait = nv50_runl_wait, + .pending = gf100_runl_pending, + .block = gf100_runl_block, + .allow = gf100_runl_allow, + .fault_clear = gf100_runl_fault_clear, + .preempt_pending = gf100_runl_preempt_pending, +}; - nvkm_mask(device, 0x003004 + (chid * 0x08), 0x00000001, 0x00000000); - list_del_init(&chan->head); - chan->killed = true; +static void +gf100_fifo_nonstall_allow(struct nvkm_event *event, int type, int index) +{ + struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), nonstall.event); + unsigned long flags; - if (engi >= 0 && engi != GF100_FIFO_ENGN_SW) - fifo->recover.mask |= BIT(engi); - schedule_work(&fifo->recover.work); - nvkm_fifo_kevent(&fifo->base, chid); + spin_lock_irqsave(&fifo->lock, flags); + nvkm_mask(fifo->engine.subdev.device, 0x002140, 0x80000000, 0x80000000); + spin_unlock_irqrestore(&fifo->lock, flags); } +void +gf100_fifo_nonstall_block(struct nvkm_event *event, int type, int index) +{ + struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), nonstall.event); + unsigned long flags; + + spin_lock_irqsave(&fifo->lock, flags); + nvkm_mask(fifo->engine.subdev.device, 0x002140, 0x80000000, 0x00000000); + spin_unlock_irqrestore(&fifo->lock, flags); +} + +const struct nvkm_event_func +gf100_fifo_nonstall = { + .init = gf100_fifo_nonstall_allow, + .fini = gf100_fifo_nonstall_block, +}; + static const struct nvkm_enum -gf100_fifo_fault_engine[] = { +gf100_fifo_mmu_fault_engine[] = { { 0x00, "PGRAPH", NULL, NVKM_ENGINE_GR }, { 0x03, "PEEPHOLE", NULL, NVKM_ENGINE_IFB }, { 0x04, "BAR1", NULL, NVKM_SUBDEV_BAR }, { 0x05, "BAR3", NULL, NVKM_SUBDEV_INSTMEM }, - { 0x07, "PFIFO", NULL, NVKM_ENGINE_FIFO }, + { 0x07, "PFIFO" }, { 0x10, "PMSVLD", NULL, NVKM_ENGINE_MSVLD }, { 0x11, "PMSPPP", NULL, NVKM_ENGINE_MSPPP }, { 0x13, "PCOUNTER" }, @@ -212,7 +482,7 @@ gf100_fifo_fault_engine[] = { }; static const struct nvkm_enum -gf100_fifo_fault_reason[] = { +gf100_fifo_mmu_fault_reason[] = { { 0x00, "PT_NOT_PRESENT" }, { 0x01, "PT_TOO_SHORT" }, { 0x02, "PAGE_NOT_PRESENT" }, @@ -226,7 +496,7 @@ gf100_fifo_fault_reason[] = { }; static const struct nvkm_enum -gf100_fifo_fault_hubclient[] = { +gf100_fifo_mmu_fault_hubclient[] = { { 0x01, "PCOPY0" }, { 0x02, "PCOPY1" }, { 0x04, "DISPATCH" }, @@ -245,7 +515,7 @@ gf100_fifo_fault_hubclient[] = { }; static const struct nvkm_enum -gf100_fifo_fault_gpcclient[] = { +gf100_fifo_mmu_fault_gpcclient[] = { { 0x01, "TEX" }, { 0x0c, "ESETUP" }, { 0x0e, "CTXCTL" }, @@ -253,29 +523,55 @@ gf100_fifo_fault_gpcclient[] = { {} }; -static void -gf100_fifo_fault(struct nvkm_fifo *base, struct nvkm_fault_data *info) +const struct nvkm_enum +gf100_fifo_mmu_fault_access[] = { + { 0x00, "READ" }, + { 0x01, "WRITE" }, + {} +}; + +void +gf100_fifo_mmu_fault_recover(struct nvkm_fifo *fifo, struct nvkm_fault_data *info) { - struct gf100_fifo *fifo = gf100_fifo(base); - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_subdev *subdev = &fifo->engine.subdev; struct nvkm_device *device = subdev->device; - const struct nvkm_enum *er, *eu, *ec; + const struct nvkm_enum *er, *ee, *ec, *ea; struct nvkm_engine *engine = NULL; - struct nvkm_fifo_chan *chan; + struct nvkm_runl *runl; + struct nvkm_engn *engn; + struct nvkm_chan *chan; unsigned long flags; - char gpcid[8] = ""; + char ct[8] = "HUB/"; + + /* Lookup engine by MMU fault ID. */ + nvkm_runl_foreach(runl, fifo) { + engn = nvkm_runl_find_engn(engn, runl, engn->fault == info->engine); + if (engn) { + /* Fault triggered by CTXSW_TIMEOUT recovery procedure. */ + if (engn->func->mmu_fault_triggered && + engn->func->mmu_fault_triggered(engn)) { + nvkm_runl_rc_engn(runl, engn); + return; + } + + engine = engn->engine; + break; + } + } - er = nvkm_enum_find(gf100_fifo_fault_reason, info->reason); - eu = nvkm_enum_find(gf100_fifo_fault_engine, info->engine); + er = nvkm_enum_find(fifo->func->mmu_fault->reason, info->reason); + ee = nvkm_enum_find(fifo->func->mmu_fault->engine, info->engine); if (info->hub) { - ec = nvkm_enum_find(gf100_fifo_fault_hubclient, info->client); + ec = nvkm_enum_find(fifo->func->mmu_fault->hubclient, info->client); } else { - ec = nvkm_enum_find(gf100_fifo_fault_gpcclient, info->client); - snprintf(gpcid, sizeof(gpcid), "GPC%d/", info->gpc); + ec = nvkm_enum_find(fifo->func->mmu_fault->gpcclient, info->client); + snprintf(ct, sizeof(ct), "GPC%d/", info->gpc); } + ea = nvkm_enum_find(fifo->func->mmu_fault->access, info->access); - if (eu && eu->data2) { - switch (eu->data2) { + /* Handle BAR faults. */ + if (ee && ee->data2) { + switch (ee->data2) { case NVKM_SUBDEV_BAR: nvkm_bar_bar1_reset(device); break; @@ -286,77 +582,104 @@ gf100_fifo_fault(struct nvkm_fifo *base, struct nvkm_fault_data *info) nvkm_mask(device, 0x001718, 0x00000000, 0x00000000); break; default: - engine = nvkm_device_engine(device, eu->data2, eu->inst); break; } } - chan = nvkm_fifo_chan_inst(&fifo->base, info->inst, &flags); + chan = nvkm_chan_get_inst(&fifo->engine, info->inst, &flags); nvkm_error(subdev, - "%s fault at %010llx engine %02x [%s] client %02x [%s%s] " - "reason %02x [%s] on channel %d [%010llx %s]\n", - info->access ? "write" : "read", info->addr, - info->engine, eu ? eu->name : "", - info->client, gpcid, ec ? ec->name : "", - info->reason, er ? er->name : "", chan ? chan->chid : -1, - info->inst, chan ? chan->object.client->name : "unknown"); - - if (engine && chan) - gf100_fifo_recover(fifo, engine, (void *)chan); - nvkm_fifo_chan_put(&fifo->base, flags, &chan); + "fault %02x [%s] at %016llx engine %02x [%s] client %02x " + "[%s%s] reason %02x [%s] on channel %d [%010llx %s]\n", + info->access, ea ? ea->name : "", info->addr, + info->engine, ee ? ee->name : engine ? engine->subdev.name : "", + info->client, ct, ec ? ec->name : "", + info->reason, er ? er->name : "", + chan ? chan->id : -1, info->inst, chan ? chan->name : "unknown"); + + /* Handle host/engine faults. */ + if (chan) + nvkm_runl_rc_cgrp(chan->cgrp); + + nvkm_chan_put(&chan, flags); } -static const struct nvkm_enum -gf100_fifo_sched_reason[] = { - { 0x0a, "CTXSW_TIMEOUT" }, - {} +static const struct nvkm_fifo_func_mmu_fault +gf100_fifo_mmu_fault = { + .recover = gf100_fifo_mmu_fault_recover, + .access = gf100_fifo_mmu_fault_access, + .engine = gf100_fifo_mmu_fault_engine, + .reason = gf100_fifo_mmu_fault_reason, + .hubclient = gf100_fifo_mmu_fault_hubclient, + .gpcclient = gf100_fifo_mmu_fault_gpcclient, }; -static void -gf100_fifo_intr_sched_ctxsw(struct gf100_fifo *fifo) +void +gf100_fifo_intr_ctxsw_timeout(struct nvkm_fifo *fifo, u32 engm) { - struct nvkm_device *device = fifo->base.engine.subdev.device; - struct nvkm_engine *engine; - struct gf100_fifo_chan *chan; - unsigned long flags; - u32 engn; - - spin_lock_irqsave(&fifo->base.lock, flags); - for (engn = 0; engn < 6; engn++) { - u32 stat = nvkm_rd32(device, 0x002640 + (engn * 0x04)); - u32 busy = (stat & 0x80000000); - u32 save = (stat & 0x00100000); /* maybe? */ - u32 unk0 = (stat & 0x00040000); - u32 unk1 = (stat & 0x00001000); - u32 chid = (stat & 0x0000007f); - (void)save; - - if (busy && unk0 && unk1) { - list_for_each_entry(chan, &fifo->chan, head) { - if (chan->base.chid == chid) { - engine = gf100_fifo_id_engine(&fifo->base, engn); - if (!engine) - break; - gf100_fifo_recover(fifo, engine, chan); - break; + struct nvkm_runl *runl; + struct nvkm_engn *engn, *engn2; + bool cgid, cgid2; + int id, id2; + + nvkm_runl_foreach(runl, fifo) { + /* Stop the runlist, and go through all engines serving it. */ + nvkm_runl_block(runl); + nvkm_runl_foreach_engn_cond(engn, runl, engm & BIT(engn->id)) { + /* Determine what channel (group) the engine is on. */ + id = engn->func->cxid(engn, &cgid); + if (id >= 0) { + /* Trigger MMU fault on any engine(s) on that channel (group). */ + nvkm_runl_foreach_engn_cond(engn2, runl, engn2->func->cxid) { + id2 = engn2->func->cxid(engn2, &cgid2); + if (cgid2 == cgid && id2 == id) + engn2->func->mmu_fault_trigger(engn2); } } } + nvkm_runl_allow(runl); /* HW will keep runlist blocked via ERROR_SCHED_DISABLE. */ } - spin_unlock_irqrestore(&fifo->base.lock, flags); } static void -gf100_fifo_intr_sched(struct gf100_fifo *fifo) +gf100_fifo_intr_sched_ctxsw(struct nvkm_fifo *fifo) { - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_runl *runl; + struct nvkm_engn *engn; + u32 engm = 0; + + /* Look for any engines that are busy, and awaiting chsw ack. */ + nvkm_runl_foreach(runl, fifo) { + nvkm_runl_foreach_engn_cond(engn, runl, engn->func->chsw) { + if (WARN_ON(engn->fault < 0) || !engn->func->chsw(engn)) + continue; + + engm |= BIT(engn->id); + } + } + + if (!engm) + return; + + fifo->func->intr_ctxsw_timeout(fifo, engm); +} + +static const struct nvkm_enum +gf100_fifo_intr_sched_names[] = { + { 0x0a, "CTXSW_TIMEOUT" }, + {} +}; + +void +gf100_fifo_intr_sched(struct nvkm_fifo *fifo) +{ + struct nvkm_subdev *subdev = &fifo->engine.subdev; struct nvkm_device *device = subdev->device; u32 intr = nvkm_rd32(device, 0x00254c); u32 code = intr & 0x000000ff; const struct nvkm_enum *en; - en = nvkm_enum_find(gf100_fifo_sched_reason, code); + en = nvkm_enum_find(gf100_fifo_intr_sched_names, code); nvkm_error(subdev, "SCHED_ERROR %02x [%s]\n", code, en ? en->name : ""); @@ -370,7 +693,7 @@ gf100_fifo_intr_sched(struct gf100_fifo *fifo) } void -gf100_fifo_intr_fault(struct nvkm_fifo *fifo, int unit) +gf100_fifo_intr_mmu_fault_unit(struct nvkm_fifo *fifo, int unit) { struct nvkm_device *device = fifo->engine.subdev.device; u32 inst = nvkm_rd32(device, 0x002800 + (unit * 0x10)); @@ -393,61 +716,45 @@ gf100_fifo_intr_fault(struct nvkm_fifo *fifo, int unit) nvkm_fifo_fault(fifo, &info); } -static const struct nvkm_bitfield -gf100_fifo_pbdma_intr[] = { -/* { 0x00008000, "" } seen with null ib push */ - { 0x00200000, "ILLEGAL_MTHD" }, - { 0x00800000, "EMPTY_SUBC" }, - {} -}; - -static void -gf100_fifo_intr_pbdma(struct gf100_fifo *fifo, int unit) +void +gf100_fifo_intr_mmu_fault(struct nvkm_fifo *fifo) { - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; - struct nvkm_device *device = subdev->device; - u32 stat = nvkm_rd32(device, 0x040108 + (unit * 0x2000)); - u32 addr = nvkm_rd32(device, 0x0400c0 + (unit * 0x2000)); - u32 data = nvkm_rd32(device, 0x0400c4 + (unit * 0x2000)); - u32 chid = nvkm_rd32(device, 0x040120 + (unit * 0x2000)) & 0x7f; - u32 subc = (addr & 0x00070000) >> 16; - u32 mthd = (addr & 0x00003ffc); - struct nvkm_fifo_chan *chan; - unsigned long flags; - u32 show= stat; - char msg[128]; + struct nvkm_device *device = fifo->engine.subdev.device; + unsigned long mask = nvkm_rd32(device, 0x00259c); + int unit; - if (stat & 0x00800000) { - if (device->sw) { - if (nvkm_sw_mthd(device->sw, chid, subc, mthd, data)) - show &= ~0x00800000; - } + for_each_set_bit(unit, &mask, 32) { + fifo->func->intr_mmu_fault_unit(fifo, unit); + nvkm_wr32(device, 0x00259c, BIT(unit)); } +} - if (show) { - nvkm_snprintbf(msg, sizeof(msg), gf100_fifo_pbdma_intr, show); - chan = nvkm_fifo_chan_chid(&fifo->base, chid, &flags); - nvkm_error(subdev, "PBDMA%d: %08x [%s] ch %d [%010llx %s] " - "subc %d mthd %04x data %08x\n", - unit, show, msg, chid, chan ? chan->inst->addr : 0, - chan ? chan->object.client->name : "unknown", - subc, mthd, data); - nvkm_fifo_chan_put(&fifo->base, flags, &chan); +bool +gf100_fifo_intr_pbdma(struct nvkm_fifo *fifo) +{ + struct nvkm_device *device = fifo->engine.subdev.device; + struct nvkm_runq *runq; + u32 mask = nvkm_rd32(device, 0x0025a0); + bool handled = false; + + nvkm_runq_foreach_cond(runq, fifo, mask & BIT(runq->id)) { + if (runq->func->intr(runq, NULL)) + handled = true; + + nvkm_wr32(device, 0x0025a0, BIT(runq->id)); } - nvkm_wr32(device, 0x0400c0 + (unit * 0x2000), 0x80600008); - nvkm_wr32(device, 0x040108 + (unit * 0x2000), stat); + return handled; } static void -gf100_fifo_intr_runlist(struct gf100_fifo *fifo) +gf100_fifo_intr_runlist(struct nvkm_fifo *fifo) { - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_subdev *subdev = &fifo->engine.subdev; struct nvkm_device *device = subdev->device; u32 intr = nvkm_rd32(device, 0x002a00); if (intr & 0x10000000) { - wake_up(&fifo->runlist.wait); nvkm_wr32(device, 0x002a00, 0x10000000); intr &= ~0x10000000; } @@ -459,9 +766,9 @@ gf100_fifo_intr_runlist(struct gf100_fifo *fifo) } static void -gf100_fifo_intr_engine_unit(struct gf100_fifo *fifo, int engn) +gf100_fifo_intr_engine_unit(struct nvkm_fifo *fifo, int engn) { - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_subdev *subdev = &fifo->engine.subdev; struct nvkm_device *device = subdev->device; u32 intr = nvkm_rd32(device, 0x0025a8 + (engn * 0x04)); u32 inte = nvkm_rd32(device, 0x002628); @@ -472,22 +779,22 @@ gf100_fifo_intr_engine_unit(struct gf100_fifo *fifo, int engn) for (unkn = 0; unkn < 8; unkn++) { u32 ints = (intr >> (unkn * 0x04)) & inte; if (ints & 0x1) { - nvkm_fifo_uevent(&fifo->base); + nvkm_event_ntfy(&fifo->nonstall.event, 0, NVKM_FIFO_NONSTALL_EVENT); ints &= ~1; } if (ints) { - nvkm_error(subdev, "ENGINE %d %d %01x", - engn, unkn, ints); + nvkm_error(subdev, "ENGINE %d %d %01x", engn, unkn, ints); nvkm_mask(device, 0x002628, ints, 0); } } } -void -gf100_fifo_intr_engine(struct gf100_fifo *fifo) +static void +gf100_fifo_intr_engine(struct nvkm_fifo *fifo) { - struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_device *device = fifo->engine.subdev.device; u32 mask = nvkm_rd32(device, 0x0025a4); + while (mask) { u32 unit = __ffs(mask); gf100_fifo_intr_engine_unit(fifo, unit); @@ -495,11 +802,11 @@ gf100_fifo_intr_engine(struct gf100_fifo *fifo) } } -static void -gf100_fifo_intr(struct nvkm_fifo *base) +static irqreturn_t +gf100_fifo_intr(struct nvkm_inth *inth) { - struct gf100_fifo *fifo = gf100_fifo(base); - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_fifo *fifo = container_of(inth, typeof(*fifo), engine.subdev.inth); + struct nvkm_subdev *subdev = &fifo->engine.subdev; struct nvkm_device *device = subdev->device; u32 mask = nvkm_rd32(device, 0x002140); u32 stat = nvkm_rd32(device, 0x002100) & mask; @@ -532,25 +839,13 @@ gf100_fifo_intr(struct nvkm_fifo *base) } if (stat & 0x10000000) { - u32 mask = nvkm_rd32(device, 0x00259c); - while (mask) { - u32 unit = __ffs(mask); - gf100_fifo_intr_fault(&fifo->base, unit); - nvkm_wr32(device, 0x00259c, (1 << unit)); - mask &= ~(1 << unit); - } + gf100_fifo_intr_mmu_fault(fifo); stat &= ~0x10000000; } if (stat & 0x20000000) { - u32 mask = nvkm_rd32(device, 0x0025a0); - while (mask) { - u32 unit = __ffs(mask); - gf100_fifo_intr_pbdma(fifo, unit); - nvkm_wr32(device, 0x0025a0, (1 << unit)); - mask &= ~(1 << unit); - } - stat &= ~0x20000000; + if (gf100_fifo_intr_pbdma(fifo)) + stat &= ~0x20000000; } if (stat & 0x40000000) { @@ -565,71 +860,26 @@ gf100_fifo_intr(struct nvkm_fifo *base) if (stat) { nvkm_error(subdev, "INTR %08x\n", stat); + spin_lock(&fifo->lock); nvkm_mask(device, 0x002140, stat, 0x00000000); + spin_unlock(&fifo->lock); nvkm_wr32(device, 0x002100, stat); } -} - -static int -gf100_fifo_oneinit(struct nvkm_fifo *base) -{ - struct gf100_fifo *fifo = gf100_fifo(base); - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; - struct nvkm_device *device = subdev->device; - struct nvkm_vmm *bar = nvkm_bar_bar1_vmm(device); - int ret; - - /* Determine number of PBDMAs by checking valid enable bits. */ - nvkm_wr32(device, 0x002204, 0xffffffff); - fifo->pbdma_nr = hweight32(nvkm_rd32(device, 0x002204)); - nvkm_debug(subdev, "%d PBDMA(s)\n", fifo->pbdma_nr); - - - ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 0x1000, - false, &fifo->runlist.mem[0]); - if (ret) - return ret; - - ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 0x1000, - false, &fifo->runlist.mem[1]); - if (ret) - return ret; - init_waitqueue_head(&fifo->runlist.wait); - - ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 128 * 0x1000, - 0x1000, false, &fifo->user.mem); - if (ret) - return ret; - - ret = nvkm_vmm_get(bar, 12, nvkm_memory_size(fifo->user.mem), - &fifo->user.bar); - if (ret) - return ret; - - return nvkm_memory_map(fifo->user.mem, 0, bar, fifo->user.bar, NULL, 0); -} - -static void -gf100_fifo_fini(struct nvkm_fifo *base) -{ - struct gf100_fifo *fifo = gf100_fifo(base); - flush_work(&fifo->recover.work); + return IRQ_HANDLED; } static void -gf100_fifo_init(struct nvkm_fifo *base) +gf100_fifo_init_pbdmas(struct nvkm_fifo *fifo, u32 mask) { - struct gf100_fifo *fifo = gf100_fifo(base); - struct nvkm_device *device = fifo->base.engine.subdev.device; - int i; + struct nvkm_device *device = fifo->engine.subdev.device; /* Enable PBDMAs. */ - nvkm_wr32(device, 0x000204, (1 << fifo->pbdma_nr) - 1); - nvkm_wr32(device, 0x002204, (1 << fifo->pbdma_nr) - 1); + nvkm_wr32(device, 0x000204, mask); + nvkm_wr32(device, 0x002204, mask); /* Assign engines to PBDMAs. */ - if (fifo->pbdma_nr >= 3) { + if ((mask & 7) == 7) { nvkm_wr32(device, 0x002208, ~(1 << 0)); /* PGRAPH */ nvkm_wr32(device, 0x00220c, ~(1 << 1)); /* PVP */ nvkm_wr32(device, 0x002210, ~(1 << 1)); /* PMSPP */ @@ -638,62 +888,82 @@ gf100_fifo_init(struct nvkm_fifo *base) nvkm_wr32(device, 0x00221c, ~(1 << 1)); /* PCE1 */ } - /* PBDMA[n] */ - for (i = 0; i < fifo->pbdma_nr; i++) { - nvkm_mask(device, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000); - nvkm_wr32(device, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */ - nvkm_wr32(device, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */ - } + nvkm_mask(device, 0x002a04, 0xbfffffff, 0xbfffffff); +} + +static void +gf100_fifo_init(struct nvkm_fifo *fifo) +{ + struct nvkm_device *device = fifo->engine.subdev.device; nvkm_mask(device, 0x002200, 0x00000001, 0x00000001); - nvkm_wr32(device, 0x002254, 0x10000000 | fifo->user.bar->addr >> 12); + nvkm_wr32(device, 0x002254, 0x10000000 | fifo->userd.bar1->addr >> 12); nvkm_wr32(device, 0x002100, 0xffffffff); nvkm_wr32(device, 0x002140, 0x7fffffff); nvkm_wr32(device, 0x002628, 0x00000001); /* ENGINE_INTR_EN */ } -static void * -gf100_fifo_dtor(struct nvkm_fifo *base) +static int +gf100_fifo_runl_ctor(struct nvkm_fifo *fifo) +{ + struct nvkm_runl *runl; + + runl = nvkm_runl_new(fifo, 0, 0, 0); + if (IS_ERR(runl)) + return PTR_ERR(runl); + + nvkm_runl_add(runl, 0, fifo->func->engn, NVKM_ENGINE_GR, 0); + nvkm_runl_add(runl, 1, fifo->func->engn, NVKM_ENGINE_MSPDEC, 0); + nvkm_runl_add(runl, 2, fifo->func->engn, NVKM_ENGINE_MSPPP, 0); + nvkm_runl_add(runl, 3, fifo->func->engn, NVKM_ENGINE_MSVLD, 0); + nvkm_runl_add(runl, 4, fifo->func->engn, NVKM_ENGINE_CE, 0); + nvkm_runl_add(runl, 5, fifo->func->engn, NVKM_ENGINE_CE, 1); + nvkm_runl_add(runl, 15, &gf100_engn_sw, NVKM_ENGINE_SW, 0); + return 0; +} + +int +gf100_fifo_runq_nr(struct nvkm_fifo *fifo) +{ + struct nvkm_device *device = fifo->engine.subdev.device; + u32 save; + + /* Determine number of PBDMAs by checking valid enable bits. */ + save = nvkm_mask(device, 0x000204, 0xffffffff, 0xffffffff); + save = nvkm_mask(device, 0x000204, 0xffffffff, save); + return hweight32(save); +} + +int +gf100_fifo_chid_ctor(struct nvkm_fifo *fifo, int nr) { - struct gf100_fifo *fifo = gf100_fifo(base); - struct nvkm_device *device = fifo->base.engine.subdev.device; - nvkm_vmm_put(nvkm_bar_bar1_vmm(device), &fifo->user.bar); - nvkm_memory_unref(&fifo->user.mem); - nvkm_memory_unref(&fifo->runlist.mem[0]); - nvkm_memory_unref(&fifo->runlist.mem[1]); - return fifo; + return nvkm_chid_new(&nvkm_chan_event, &fifo->engine.subdev, nr, 0, nr, &fifo->chid); } static const struct nvkm_fifo_func gf100_fifo = { - .dtor = gf100_fifo_dtor, - .oneinit = gf100_fifo_oneinit, + .chid_nr = nv50_fifo_chid_nr, + .chid_ctor = gf100_fifo_chid_ctor, + .runq_nr = gf100_fifo_runq_nr, + .runl_ctor = gf100_fifo_runl_ctor, .init = gf100_fifo_init, - .fini = gf100_fifo_fini, + .init_pbdmas = gf100_fifo_init_pbdmas, .intr = gf100_fifo_intr, - .fault = gf100_fifo_fault, - .engine_id = gf100_fifo_engine_id, - .id_engine = gf100_fifo_id_engine, - .uevent_init = gf100_fifo_uevent_init, - .uevent_fini = gf100_fifo_uevent_fini, - .chan = { - &gf100_fifo_gpfifo_oclass, - NULL - }, + .intr_mmu_fault_unit = gf100_fifo_intr_mmu_fault_unit, + .intr_ctxsw_timeout = gf100_fifo_intr_ctxsw_timeout, + .mmu_fault = &gf100_fifo_mmu_fault, + .nonstall = &gf100_fifo_nonstall, + .runl = &gf100_runl, + .runq = &gf100_runq, + .engn = &gf100_engn, + .cgrp = {{ }, &nv04_cgrp }, + .chan = {{ 0, 0, FERMI_CHANNEL_GPFIFO }, &gf100_chan }, }; int gf100_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fifo **pfifo) { - struct gf100_fifo *fifo; - - if (!(fifo = kzalloc(sizeof(*fifo), GFP_KERNEL))) - return -ENOMEM; - INIT_LIST_HEAD(&fifo->chan); - INIT_WORK(&fifo->recover.work, gf100_fifo_recover_work); - *pfifo = &fifo->base; - - return nvkm_fifo_ctor(&gf100_fifo, device, type, inst, 128, &fifo->base); + return nvkm_fifo_new_(&gf100_fifo, device, type, inst, pfifo); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.h deleted file mode 100644 index b8642490eb2f..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.h +++ /dev/null @@ -1,38 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -#ifndef __GF100_FIFO_H__ -#define __GF100_FIFO_H__ -#define gf100_fifo(p) container_of((p), struct gf100_fifo, base) -#include "priv.h" - -#include <subdev/mmu.h> - -struct gf100_fifo_chan; -struct gf100_fifo { - struct nvkm_fifo base; - - struct list_head chan; - - struct { - struct work_struct work; - u64 mask; - } recover; - - int pbdma_nr; - - struct { - struct nvkm_memory *mem[2]; - int active; - wait_queue_head_t wait; - } runlist; - - struct { - struct nvkm_memory *mem; - struct nvkm_vma *bar; - } user; -}; - -void gf100_fifo_intr_engine(struct gf100_fifo *); -void gf100_fifo_runlist_insert(struct gf100_fifo *, struct gf100_fifo_chan *); -void gf100_fifo_runlist_remove(struct gf100_fifo *, struct gf100_fifo_chan *); -void gf100_fifo_runlist_commit(struct gf100_fifo *); -#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c index e771bd519ee2..d8a4d773a58c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c @@ -21,643 +21,318 @@ * * Authors: Ben Skeggs */ -#include "gk104.h" +#include "priv.h" #include "cgrp.h" -#include "changk104.h" +#include "chan.h" +#include "chid.h" +#include "runl.h" +#include "runq.h" -#include <core/client.h> #include <core/gpuobj.h> -#include <subdev/bar.h> -#include <subdev/fault.h> -#include <subdev/timer.h> +#include <subdev/mc.h> +#include <subdev/mmu.h> #include <subdev/top.h> -#include <engine/sw.h> #include <nvif/class.h> -#include <nvif/cl0080.h> +#include <nvif/if900d.h> void -gk104_fifo_engine_status(struct gk104_fifo *fifo, int engn, - struct gk104_fifo_engine_status *status) +gk104_chan_stop(struct nvkm_chan *chan) { - struct nvkm_engine *engine = fifo->engine[engn].engine; - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; - struct nvkm_device *device = subdev->device; - u32 stat = nvkm_rd32(device, 0x002640 + (engn * 0x08)); - - status->busy = !!(stat & 0x80000000); - status->faulted = !!(stat & 0x40000000); - status->next.tsg = !!(stat & 0x10000000); - status->next.id = (stat & 0x0fff0000) >> 16; - status->chsw = !!(stat & 0x00008000); - status->save = !!(stat & 0x00004000); - status->load = !!(stat & 0x00002000); - status->prev.tsg = !!(stat & 0x00001000); - status->prev.id = (stat & 0x00000fff); - status->chan = NULL; - - if (status->busy && status->chsw) { - if (status->load && status->save) { - if (engine && nvkm_engine_chsw_load(engine)) - status->chan = &status->next; - else - status->chan = &status->prev; - } else - if (status->load) { - status->chan = &status->next; - } else { - status->chan = &status->prev; - } - } else - if (status->load) { - status->chan = &status->prev; - } + struct nvkm_device *device = chan->cgrp->runl->fifo->engine.subdev.device; - nvkm_debug(subdev, "engine %02d: busy %d faulted %d chsw %d " - "save %d load %d %sid %d%s-> %sid %d%s\n", - engn, status->busy, status->faulted, - status->chsw, status->save, status->load, - status->prev.tsg ? "tsg" : "ch", status->prev.id, - status->chan == &status->prev ? "*" : " ", - status->next.tsg ? "tsg" : "ch", status->next.id, - status->chan == &status->next ? "*" : " "); -} - -int -gk104_fifo_class_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, - void *argv, u32 argc, struct nvkm_object **pobject) -{ - struct gk104_fifo *fifo = gk104_fifo(base); - if (oclass->engn == &fifo->func->chan) { - const struct gk104_fifo_chan_user *user = oclass->engn; - return user->ctor(fifo, oclass, argv, argc, pobject); - } else - if (oclass->engn == &fifo->func->user) { - const struct gk104_fifo_user_user *user = oclass->engn; - return user->ctor(oclass, argv, argc, pobject); - } - WARN_ON(1); - return -EINVAL; -} - -int -gk104_fifo_class_get(struct nvkm_fifo *base, int index, - struct nvkm_oclass *oclass) -{ - struct gk104_fifo *fifo = gk104_fifo(base); - int c = 0; - - if (fifo->func->user.ctor && c++ == index) { - oclass->base = fifo->func->user.user; - oclass->engn = &fifo->func->user; - return 0; - } - - if (fifo->func->chan.ctor && c++ == index) { - oclass->base = fifo->func->chan.user; - oclass->engn = &fifo->func->chan; - return 0; - } - - return c; + nvkm_mask(device, 0x800004 + (chan->id * 8), 0x00000800, 0x00000800); } void -gk104_fifo_uevent_fini(struct nvkm_fifo *fifo) +gk104_chan_start(struct nvkm_chan *chan) { - struct nvkm_device *device = fifo->engine.subdev.device; - nvkm_mask(device, 0x002140, 0x80000000, 0x00000000); -} + struct nvkm_device *device = chan->cgrp->runl->fifo->engine.subdev.device; -void -gk104_fifo_uevent_init(struct nvkm_fifo *fifo) -{ - struct nvkm_device *device = fifo->engine.subdev.device; - nvkm_mask(device, 0x002140, 0x80000000, 0x80000000); + nvkm_mask(device, 0x800004 + (chan->id * 8), 0x00000400, 0x00000400); } void -gk104_fifo_runlist_commit(struct gk104_fifo *fifo, int runl, - struct nvkm_memory *mem, int nr) +gk104_chan_unbind(struct nvkm_chan *chan) { - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; - struct nvkm_device *device = subdev->device; - int target; + struct nvkm_device *device = chan->cgrp->runl->fifo->engine.subdev.device; - switch (nvkm_memory_target(mem)) { - case NVKM_MEM_TARGET_VRAM: target = 0; break; - case NVKM_MEM_TARGET_NCOH: target = 3; break; - default: - WARN_ON(1); - return; - } - - nvkm_wr32(device, 0x002270, (nvkm_memory_addr(mem) >> 12) | - (target << 28)); - nvkm_wr32(device, 0x002274, (runl << 20) | nr); - - if (nvkm_msec(device, 2000, - if (!(nvkm_rd32(device, 0x002284 + (runl * 0x08)) & 0x00100000)) - break; - ) < 0) - nvkm_error(subdev, "runlist %d update timeout\n", runl); + nvkm_wr32(device, 0x800000 + (chan->id * 8), 0x00000000); } void -gk104_fifo_runlist_update(struct gk104_fifo *fifo, int runl) +gk104_chan_bind_inst(struct nvkm_chan *chan) { - const struct gk104_fifo_runlist_func *func = fifo->func->runlist; - struct gk104_fifo_chan *chan; - struct nvkm_memory *mem; - struct nvkm_fifo_cgrp *cgrp; - int nr = 0; - - mutex_lock(&fifo->base.mutex); - mem = fifo->runlist[runl].mem[fifo->runlist[runl].next]; - fifo->runlist[runl].next = !fifo->runlist[runl].next; - - nvkm_kmap(mem); - list_for_each_entry(chan, &fifo->runlist[runl].chan, head) { - func->chan(chan, mem, nr++ * func->size); - } - - list_for_each_entry(cgrp, &fifo->runlist[runl].cgrp, head) { - func->cgrp(cgrp, mem, nr++ * func->size); - list_for_each_entry(chan, &cgrp->chan, head) { - func->chan(chan, mem, nr++ * func->size); - } - } - nvkm_done(mem); + struct nvkm_device *device = chan->cgrp->runl->fifo->engine.subdev.device; - func->commit(fifo, runl, mem, nr); - mutex_unlock(&fifo->base.mutex); + nvkm_wr32(device, 0x800000 + (chan->id * 8), 0x80000000 | chan->inst->addr >> 12); } void -gk104_fifo_runlist_remove(struct gk104_fifo *fifo, struct gk104_fifo_chan *chan) -{ - struct nvkm_fifo_cgrp *cgrp = chan->cgrp; - mutex_lock(&fifo->base.mutex); - if (!list_empty(&chan->head)) { - list_del_init(&chan->head); - if (cgrp && !--cgrp->chan_nr) - list_del_init(&cgrp->head); - } - mutex_unlock(&fifo->base.mutex); -} - -void -gk104_fifo_runlist_insert(struct gk104_fifo *fifo, struct gk104_fifo_chan *chan) -{ - struct nvkm_fifo_cgrp *cgrp = chan->cgrp; - mutex_lock(&fifo->base.mutex); - if (cgrp) { - if (!cgrp->chan_nr++) - list_add_tail(&cgrp->head, &fifo->runlist[chan->runl].cgrp); - list_add_tail(&chan->head, &cgrp->chan); - } else { - list_add_tail(&chan->head, &fifo->runlist[chan->runl].chan); - } - mutex_unlock(&fifo->base.mutex); -} - -void -gk104_fifo_runlist_chan(struct gk104_fifo_chan *chan, - struct nvkm_memory *memory, u32 offset) -{ - nvkm_wo32(memory, offset + 0, chan->base.chid); - nvkm_wo32(memory, offset + 4, 0x00000000); -} - -const struct gk104_fifo_runlist_func -gk104_fifo_runlist = { - .size = 8, - .chan = gk104_fifo_runlist_chan, - .commit = gk104_fifo_runlist_commit, +gk104_chan_bind(struct nvkm_chan *chan) +{ + struct nvkm_runl *runl = chan->cgrp->runl; + struct nvkm_device *device = runl->fifo->engine.subdev.device; + + nvkm_mask(device, 0x800004 + (chan->id * 8), 0x000f0000, runl->id << 16); + gk104_chan_bind_inst(chan); +} + +static int +gk104_chan_ramfc_write(struct nvkm_chan *chan, u64 offset, u64 length, u32 devm, bool priv) +{ + const u64 userd = nvkm_memory_addr(chan->userd.mem) + chan->userd.base; + const u32 limit2 = ilog2(length / 8); + + nvkm_kmap(chan->inst); + nvkm_wo32(chan->inst, 0x08, lower_32_bits(userd)); + nvkm_wo32(chan->inst, 0x0c, upper_32_bits(userd)); + nvkm_wo32(chan->inst, 0x10, 0x0000face); + nvkm_wo32(chan->inst, 0x30, 0xfffff902); + nvkm_wo32(chan->inst, 0x48, lower_32_bits(offset)); + nvkm_wo32(chan->inst, 0x4c, upper_32_bits(offset) | (limit2 << 16)); + nvkm_wo32(chan->inst, 0x84, 0x20400000); + nvkm_wo32(chan->inst, 0x94, 0x30000000 | devm); + nvkm_wo32(chan->inst, 0x9c, 0x00000100); + nvkm_wo32(chan->inst, 0xac, 0x0000001f); + nvkm_wo32(chan->inst, 0xe4, priv ? 0x00000020 : 0x00000000); + nvkm_wo32(chan->inst, 0xe8, chan->id); + nvkm_wo32(chan->inst, 0xb8, 0xf8000000); + nvkm_wo32(chan->inst, 0xf8, 0x10003080); /* 0x002310 */ + nvkm_wo32(chan->inst, 0xfc, 0x10000010); /* 0x002350 */ + nvkm_done(chan->inst); + return 0; +} + +const struct nvkm_chan_func_ramfc +gk104_chan_ramfc = { + .write = gk104_chan_ramfc_write, + .devm = 0xfff, + .priv = true, }; -void -gk104_fifo_pbdma_init(struct gk104_fifo *fifo) -{ - struct nvkm_device *device = fifo->base.engine.subdev.device; - nvkm_wr32(device, 0x000204, (1 << fifo->pbdma_nr) - 1); -} - -int -gk104_fifo_pbdma_nr(struct gk104_fifo *fifo) -{ - struct nvkm_device *device = fifo->base.engine.subdev.device; - /* Determine number of PBDMAs by checking valid enable bits. */ - nvkm_wr32(device, 0x000204, 0xffffffff); - return hweight32(nvkm_rd32(device, 0x000204)); -} - -const struct gk104_fifo_pbdma_func -gk104_fifo_pbdma = { - .nr = gk104_fifo_pbdma_nr, - .init = gk104_fifo_pbdma_init, +const struct nvkm_chan_func_userd +gk104_chan_userd = { + .bar = 1, + .size = 0x200, + .clear = gf100_chan_userd_clear, }; -struct nvkm_engine * -gk104_fifo_id_engine(struct nvkm_fifo *base, int engi) -{ - if (engi == GK104_FIFO_ENGN_SW) - return nvkm_device_engine(base->engine.subdev.device, NVKM_ENGINE_SW, 0); - - return gk104_fifo(base)->engine[engi].engine; -} - -int -gk104_fifo_engine_id(struct nvkm_fifo *base, struct nvkm_engine *engine) -{ - struct gk104_fifo *fifo = gk104_fifo(base); - int engn; +static const struct nvkm_chan_func +gk104_chan = { + .inst = &gf100_chan_inst, + .userd = &gk104_chan_userd, + .ramfc = &gk104_chan_ramfc, + .bind = gk104_chan_bind, + .unbind = gk104_chan_unbind, + .start = gk104_chan_start, + .stop = gk104_chan_stop, + .preempt = gf100_chan_preempt, +}; - if (engine->subdev.type == NVKM_ENGINE_SW) - return GK104_FIFO_ENGN_SW; +static void +gk104_ectx_bind(struct nvkm_engn *engn, struct nvkm_cctx *cctx, struct nvkm_chan *chan) +{ + u32 ptr0, ptr1 = 0; + u64 addr = 0ULL; + + switch (engn->engine->subdev.type) { + case NVKM_ENGINE_SW : return; + case NVKM_ENGINE_GR : ptr0 = 0x0210; break; + case NVKM_ENGINE_SEC : ptr0 = 0x0220; break; + case NVKM_ENGINE_MSPDEC: ptr0 = 0x0250; break; + case NVKM_ENGINE_MSPPP : ptr0 = 0x0260; break; + case NVKM_ENGINE_MSVLD : ptr0 = 0x0270; break; + case NVKM_ENGINE_VIC : ptr0 = 0x0280; break; + case NVKM_ENGINE_MSENC : ptr0 = 0x0290; break; + case NVKM_ENGINE_NVDEC : + ptr1 = 0x0270; + ptr0 = 0x0210; + break; + case NVKM_ENGINE_NVENC : + if (!engn->engine->subdev.inst) + ptr1 = 0x0290; + ptr0 = 0x0210; + break; + default: + WARN_ON(1); + return; + } - for (engn = 0; engn < fifo->engine_nr && engine; engn++) { - if (fifo->engine[engn].engine == engine) - return engn; + if (cctx) { + addr = cctx->vctx->vma->addr; + addr |= 4ULL; } - WARN_ON(1); - return -1; + nvkm_kmap(chan->inst); + nvkm_wo32(chan->inst, ptr0 + 0, lower_32_bits(addr)); + nvkm_wo32(chan->inst, ptr0 + 4, upper_32_bits(addr)); + if (ptr1) { + nvkm_wo32(chan->inst, ptr1 + 0, lower_32_bits(addr)); + nvkm_wo32(chan->inst, ptr1 + 4, upper_32_bits(addr)); + } + nvkm_done(chan->inst); } -static void -gk104_fifo_recover_work(struct work_struct *w) +int +gk104_ectx_ctor(struct nvkm_engn *engn, struct nvkm_vctx *vctx) { - struct gk104_fifo *fifo = container_of(w, typeof(*fifo), recover.work); - struct nvkm_device *device = fifo->base.engine.subdev.device; - struct nvkm_engine *engine; - unsigned long flags; - u32 engm, runm, todo; - int engn, runl; - - spin_lock_irqsave(&fifo->base.lock, flags); - runm = fifo->recover.runm; - engm = fifo->recover.engm; - fifo->recover.engm = 0; - fifo->recover.runm = 0; - spin_unlock_irqrestore(&fifo->base.lock, flags); - - nvkm_mask(device, 0x002630, runm, runm); - - for (todo = engm; engn = __ffs(todo), todo; todo &= ~BIT(engn)) { - if ((engine = fifo->engine[engn].engine)) { - nvkm_subdev_fini(&engine->subdev, false); - WARN_ON(nvkm_subdev_init(&engine->subdev)); - } - } + struct gf100_vmm_map_v0 args = { .priv = 1 }; + int ret; - for (todo = runm; runl = __ffs(todo), todo; todo &= ~BIT(runl)) - gk104_fifo_runlist_update(fifo, runl); + ret = nvkm_vmm_get(vctx->vmm, 12, vctx->inst->size, &vctx->vma); + if (ret) + return ret; - nvkm_wr32(device, 0x00262c, runm); - nvkm_mask(device, 0x002630, runm, 0x00000000); + return nvkm_memory_map(vctx->inst, 0, vctx->vmm, vctx->vma, &args, sizeof(args)); } -static void gk104_fifo_recover_engn(struct gk104_fifo *fifo, int engn); +/*TODO: clean this up */ +struct gk104_engn_status { + bool busy; + bool faulted; + bool chsw; + bool save; + bool load; + struct { + bool tsg; + u32 id; + } prev, next, *chan; +}; static void -gk104_fifo_recover_runl(struct gk104_fifo *fifo, int runl) -{ - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; - struct nvkm_device *device = subdev->device; - const u32 runm = BIT(runl); - - assert_spin_locked(&fifo->base.lock); - if (fifo->recover.runm & runm) - return; - fifo->recover.runm |= runm; - - /* Block runlist to prevent channel assignment(s) from changing. */ - nvkm_mask(device, 0x002630, runm, runm); - - /* Schedule recovery. */ - nvkm_warn(subdev, "runlist %d: scheduled for recovery\n", runl); - schedule_work(&fifo->recover.work); -} - -static struct gk104_fifo_chan * -gk104_fifo_recover_chid(struct gk104_fifo *fifo, int runl, int chid) +gk104_engn_status(struct nvkm_engn *engn, struct gk104_engn_status *status) { - struct gk104_fifo_chan *chan; - struct nvkm_fifo_cgrp *cgrp; + u32 stat = nvkm_rd32(engn->runl->fifo->engine.subdev.device, 0x002640 + (engn->id * 0x08)); - list_for_each_entry(chan, &fifo->runlist[runl].chan, head) { - if (chan->base.chid == chid) { - list_del_init(&chan->head); - return chan; - } - } + status->busy = !!(stat & 0x80000000); + status->faulted = !!(stat & 0x40000000); + status->next.tsg = !!(stat & 0x10000000); + status->next.id = (stat & 0x0fff0000) >> 16; + status->chsw = !!(stat & 0x00008000); + status->save = !!(stat & 0x00004000); + status->load = !!(stat & 0x00002000); + status->prev.tsg = !!(stat & 0x00001000); + status->prev.id = (stat & 0x00000fff); + status->chan = NULL; - list_for_each_entry(cgrp, &fifo->runlist[runl].cgrp, head) { - if (cgrp->id == chid) { - chan = list_first_entry(&cgrp->chan, typeof(*chan), head); - list_del_init(&chan->head); - if (!--cgrp->chan_nr) - list_del_init(&cgrp->head); - return chan; + if (status->busy && status->chsw) { + if (status->load && status->save) { + if (nvkm_engine_chsw_load(engn->engine)) + status->chan = &status->next; + else + status->chan = &status->prev; + } else + if (status->load) { + status->chan = &status->next; + } else { + status->chan = &status->prev; } + } else + if (status->load) { + status->chan = &status->prev; } - return NULL; -} - -static void -gk104_fifo_recover_chan(struct nvkm_fifo *base, int chid) -{ - struct gk104_fifo *fifo = gk104_fifo(base); - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; - struct nvkm_device *device = subdev->device; - const u32 stat = nvkm_rd32(device, 0x800004 + (chid * 0x08)); - const u32 runl = (stat & 0x000f0000) >> 16; - const bool used = (stat & 0x00000001); - unsigned long engn, engm = fifo->runlist[runl].engm; - struct gk104_fifo_chan *chan; - - assert_spin_locked(&fifo->base.lock); - if (!used) - return; - - /* Lookup SW state for channel, and mark it as dead. */ - chan = gk104_fifo_recover_chid(fifo, runl, chid); - if (chan) { - chan->killed = true; - nvkm_fifo_kevent(&fifo->base, chid); - } - - /* Disable channel. */ - nvkm_wr32(device, 0x800004 + (chid * 0x08), stat | 0x00000800); - nvkm_warn(subdev, "channel %d: killed\n", chid); - - /* Block channel assignments from changing during recovery. */ - gk104_fifo_recover_runl(fifo, runl); - - /* Schedule recovery for any engines the channel is on. */ - for_each_set_bit(engn, &engm, fifo->engine_nr) { - struct gk104_fifo_engine_status status; - gk104_fifo_engine_status(fifo, engn, &status); - if (!status.chan || status.chan->id != chid) - continue; - gk104_fifo_recover_engn(fifo, engn); - } + ENGN_DEBUG(engn, "%08x: busy %d faulted %d chsw %d save %d load %d %sid %d%s-> %sid %d%s", + stat, status->busy, status->faulted, status->chsw, status->save, status->load, + status->prev.tsg ? "tsg" : "ch", status->prev.id, + status->chan == &status->prev ? "*" : " ", + status->next.tsg ? "tsg" : "ch", status->next.id, + status->chan == &status->next ? "*" : " "); } -static void -gk104_fifo_recover_engn(struct gk104_fifo *fifo, int engn) +int +gk104_engn_cxid(struct nvkm_engn *engn, bool *cgid) { - struct nvkm_engine *engine = fifo->engine[engn].engine; - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; - struct nvkm_device *device = subdev->device; - const u32 runl = fifo->engine[engn].runl; - const u32 engm = BIT(engn); - struct gk104_fifo_engine_status status; - int mmui = -1; - - assert_spin_locked(&fifo->base.lock); - if (fifo->recover.engm & engm) - return; - fifo->recover.engm |= engm; - - /* Block channel assignments from changing during recovery. */ - gk104_fifo_recover_runl(fifo, runl); + struct gk104_engn_status status; - /* Determine which channel (if any) is currently on the engine. */ - gk104_fifo_engine_status(fifo, engn, &status); + gk104_engn_status(engn, &status); if (status.chan) { - /* The channel is not longer viable, kill it. */ - gk104_fifo_recover_chan(&fifo->base, status.chan->id); + *cgid = status.chan->tsg; + return status.chan->id; } - /* Determine MMU fault ID for the engine, if we're not being - * called from the fault handler already. - */ - if (!status.faulted && engine) { - mmui = nvkm_top_fault_id(device, engine->subdev.type, engine->subdev.inst); - if (mmui < 0) { - const struct nvkm_enum *en = fifo->func->fault.engine; - for (; en && en->name; en++) { - if (en->data2 == engine->subdev.type && - en->inst == engine->subdev.inst) { - mmui = en->value; - break; - } - } - } - WARN_ON(mmui < 0); - } - - /* Trigger a MMU fault for the engine. - * - * No good idea why this is needed, but nvgpu does something similar, - * and it makes recovery from CTXSW_TIMEOUT a lot more reliable. - */ - if (mmui >= 0) { - nvkm_wr32(device, 0x002a30 + (engn * 0x04), 0x00000100 | mmui); - - /* Wait for fault to trigger. */ - nvkm_msec(device, 2000, - gk104_fifo_engine_status(fifo, engn, &status); - if (status.faulted) - break; - ); - - /* Release MMU fault trigger, and ACK the fault. */ - nvkm_wr32(device, 0x002a30 + (engn * 0x04), 0x00000000); - nvkm_wr32(device, 0x00259c, BIT(mmui)); - nvkm_wr32(device, 0x002100, 0x10000000); - } - - /* Schedule recovery. */ - nvkm_warn(subdev, "engine %d: scheduled for recovery\n", engn); - schedule_work(&fifo->recover.work); + return -ENODEV; } -static void -gk104_fifo_fault(struct nvkm_fifo *base, struct nvkm_fault_data *info) +bool +gk104_engn_chsw(struct nvkm_engn *engn) { - struct gk104_fifo *fifo = gk104_fifo(base); - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; - struct nvkm_device *device = subdev->device; - const struct nvkm_enum *er, *ee, *ec, *ea; - struct nvkm_engine *engine = NULL; - struct nvkm_fifo_chan *chan; - unsigned long flags; - const char *en = ""; - char ct[8] = "HUB/"; - - er = nvkm_enum_find(fifo->func->fault.reason, info->reason); - ee = nvkm_enum_find(fifo->func->fault.engine, info->engine); - if (info->hub) { - ec = nvkm_enum_find(fifo->func->fault.hubclient, info->client); - } else { - ec = nvkm_enum_find(fifo->func->fault.gpcclient, info->client); - snprintf(ct, sizeof(ct), "GPC%d/", info->gpc); - } - ea = nvkm_enum_find(fifo->func->fault.access, info->access); + struct gk104_engn_status status; - if (ee && ee->data2) { - switch (ee->data2) { - case NVKM_SUBDEV_BAR: - nvkm_bar_bar1_reset(device); - break; - case NVKM_SUBDEV_INSTMEM: - nvkm_bar_bar2_reset(device); - break; - case NVKM_ENGINE_IFB: - nvkm_mask(device, 0x001718, 0x00000000, 0x00000000); - break; - default: - engine = nvkm_device_engine(device, ee->data2, 0); - break; - } - } - - if (ee == NULL) { - struct nvkm_subdev *subdev = nvkm_top_fault(device, info->engine); - if (subdev) { - if (subdev->func == &nvkm_engine) - engine = container_of(subdev, typeof(*engine), subdev); - en = engine->subdev.name; - } - } else { - en = ee->name; - } - - spin_lock_irqsave(&fifo->base.lock, flags); - chan = nvkm_fifo_chan_inst_locked(&fifo->base, info->inst); - - nvkm_error(subdev, - "fault %02x [%s] at %016llx engine %02x [%s] client %02x " - "[%s%s] reason %02x [%s] on channel %d [%010llx %s]\n", - info->access, ea ? ea->name : "", info->addr, - info->engine, ee ? ee->name : en, - info->client, ct, ec ? ec->name : "", - info->reason, er ? er->name : "", chan ? chan->chid : -1, - info->inst, chan ? chan->object.client->name : "unknown"); - - /* Kill the channel that caused the fault. */ - if (chan) - gk104_fifo_recover_chan(&fifo->base, chan->chid); - - /* Channel recovery will probably have already done this for the - * correct engine(s), but just in case we can't find the channel - * information... - */ - if (engine) { - int engn = fifo->base.func->engine_id(&fifo->base, engine); - if (engn >= 0 && engn != GK104_FIFO_ENGN_SW) - gk104_fifo_recover_engn(fifo, engn); - } + gk104_engn_status(engn, &status); + if (status.busy && status.chsw) + return true; - spin_unlock_irqrestore(&fifo->base.lock, flags); + return false; } -static const struct nvkm_enum -gk104_fifo_bind_reason[] = { - { 0x01, "BIND_NOT_UNBOUND" }, - { 0x02, "SNOOP_WITHOUT_BAR1" }, - { 0x03, "UNBIND_WHILE_RUNNING" }, - { 0x05, "INVALID_RUNLIST" }, - { 0x06, "INVALID_CTX_TGT" }, - { 0x0b, "UNBIND_WHILE_PARKED" }, - {} +const struct nvkm_engn_func +gk104_engn = { + .chsw = gk104_engn_chsw, + .cxid = gk104_engn_cxid, + .mmu_fault_trigger = gf100_engn_mmu_fault_trigger, + .mmu_fault_triggered = gf100_engn_mmu_fault_triggered, + .ctor = gk104_ectx_ctor, + .bind = gk104_ectx_bind, }; -void -gk104_fifo_intr_bind(struct gk104_fifo *fifo) +const struct nvkm_engn_func +gk104_engn_ce = { + .chsw = gk104_engn_chsw, + .cxid = gk104_engn_cxid, + .mmu_fault_trigger = gf100_engn_mmu_fault_trigger, + .mmu_fault_triggered = gf100_engn_mmu_fault_triggered, +}; + +bool +gk104_runq_idle(struct nvkm_runq *runq) { - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; - struct nvkm_device *device = subdev->device; - u32 intr = nvkm_rd32(device, 0x00252c); - u32 code = intr & 0x000000ff; - const struct nvkm_enum *en = - nvkm_enum_find(gk104_fifo_bind_reason, code); + struct nvkm_device *device = runq->fifo->engine.subdev.device; - nvkm_error(subdev, "BIND_ERROR %02x [%s]\n", code, en ? en->name : ""); + return !(nvkm_rd32(device, 0x003080 + (runq->id * 4)) & 0x0000e000); } -static const struct nvkm_enum -gk104_fifo_sched_reason[] = { - { 0x0a, "CTXSW_TIMEOUT" }, +static const struct nvkm_bitfield +gk104_runq_intr_1_names[] = { + { 0x00000001, "HCE_RE_ILLEGAL_OP" }, + { 0x00000002, "HCE_RE_ALIGNB" }, + { 0x00000004, "HCE_PRIV" }, + { 0x00000008, "HCE_ILLEGAL_MTHD" }, + { 0x00000010, "HCE_ILLEGAL_CLASS" }, {} }; -static void -gk104_fifo_intr_sched_ctxsw(struct gk104_fifo *fifo) +static bool +gk104_runq_intr_1(struct nvkm_runq *runq) { - struct nvkm_device *device = fifo->base.engine.subdev.device; - unsigned long flags, engm = 0; - u32 engn; - - /* We need to ACK the SCHED_ERROR here, and prevent it reasserting, - * as MMU_FAULT cannot be triggered while it's pending. - */ - spin_lock_irqsave(&fifo->base.lock, flags); - nvkm_mask(device, 0x002140, 0x00000100, 0x00000000); - nvkm_wr32(device, 0x002100, 0x00000100); - - for (engn = 0; engn < fifo->engine_nr; engn++) { - struct gk104_fifo_engine_status status; - - gk104_fifo_engine_status(fifo, engn, &status); - if (!status.busy || !status.chsw) - continue; - - engm |= BIT(engn); - } - - for_each_set_bit(engn, &engm, fifo->engine_nr) - gk104_fifo_recover_engn(fifo, engn); - - nvkm_mask(device, 0x002140, 0x00000100, 0x00000100); - spin_unlock_irqrestore(&fifo->base.lock, flags); -} - -static void -gk104_fifo_intr_sched(struct gk104_fifo *fifo) -{ - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_subdev *subdev = &runq->fifo->engine.subdev; struct nvkm_device *device = subdev->device; - u32 intr = nvkm_rd32(device, 0x00254c); - u32 code = intr & 0x000000ff; - const struct nvkm_enum *en = - nvkm_enum_find(gk104_fifo_sched_reason, code); - - nvkm_error(subdev, "SCHED_ERROR %02x [%s]\n", code, en ? en->name : ""); + u32 mask = nvkm_rd32(device, 0x04014c + (runq->id * 0x2000)); + u32 stat = nvkm_rd32(device, 0x040148 + (runq->id * 0x2000)) & mask; + u32 chid = nvkm_rd32(device, 0x040120 + (runq->id * 0x2000)) & 0xfff; + char msg[128]; - switch (code) { - case 0x0a: - gk104_fifo_intr_sched_ctxsw(fifo); - break; - default: - break; + if (stat & 0x80000000) { + if (runq->func->intr_1_ctxnotvalid && + runq->func->intr_1_ctxnotvalid(runq, chid)) + stat &= ~0x80000000; } -} -void -gk104_fifo_intr_chsw(struct gk104_fifo *fifo) -{ - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; - struct nvkm_device *device = subdev->device; - u32 stat = nvkm_rd32(device, 0x00256c); - nvkm_error(subdev, "CHSW_ERROR %08x\n", stat); - nvkm_wr32(device, 0x00256c, stat); -} + if (stat) { + nvkm_snprintbf(msg, sizeof(msg), gk104_runq_intr_1_names, stat); + nvkm_error(subdev, "PBDMA%d: %08x [%s] ch %d %08x %08x\n", + runq->id, stat, msg, chid, + nvkm_rd32(device, 0x040150 + (runq->id * 0x2000)), + nvkm_rd32(device, 0x040154 + (runq->id * 0x2000))); + } -void -gk104_fifo_intr_dropped_fault(struct gk104_fifo *fifo) -{ - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; - struct nvkm_device *device = subdev->device; - u32 stat = nvkm_rd32(device, 0x00259c); - nvkm_error(subdev, "DROPPED_MMU_FAULT %08x\n", stat); + nvkm_wr32(device, 0x040148 + (runq->id * 0x2000), stat); + return true; } -static const struct nvkm_bitfield gk104_fifo_pbdma_intr_0[] = { +const struct nvkm_bitfield +gk104_runq_intr_0_names[] = { { 0x00000001, "MEMREQ" }, { 0x00000002, "MEMACK_TIMEOUT" }, { 0x00000004, "MEMACK_EXTRA" }, @@ -691,430 +366,111 @@ static const struct nvkm_bitfield gk104_fifo_pbdma_intr_0[] = { {} }; -void -gk104_fifo_intr_pbdma_0(struct gk104_fifo *fifo, int unit) +bool +gk104_runq_intr(struct nvkm_runq *runq, struct nvkm_runl *null) { - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; - struct nvkm_device *device = subdev->device; - u32 mask = nvkm_rd32(device, 0x04010c + (unit * 0x2000)); - u32 stat = nvkm_rd32(device, 0x040108 + (unit * 0x2000)) & mask; - u32 addr = nvkm_rd32(device, 0x0400c0 + (unit * 0x2000)); - u32 data = nvkm_rd32(device, 0x0400c4 + (unit * 0x2000)); - u32 chid = nvkm_rd32(device, 0x040120 + (unit * 0x2000)) & 0xfff; - u32 subc = (addr & 0x00070000) >> 16; - u32 mthd = (addr & 0x00003ffc); - u32 show = stat; - struct nvkm_fifo_chan *chan; - unsigned long flags; - char msg[128]; - - if (stat & 0x00800000) { - if (device->sw) { - if (nvkm_sw_mthd(device->sw, chid, subc, mthd, data)) - show &= ~0x00800000; - } - } - - nvkm_wr32(device, 0x0400c0 + (unit * 0x2000), 0x80600008); - - if (show) { - nvkm_snprintbf(msg, sizeof(msg), gk104_fifo_pbdma_intr_0, show); - chan = nvkm_fifo_chan_chid(&fifo->base, chid, &flags); - nvkm_error(subdev, "PBDMA%d: %08x [%s] ch %d [%010llx %s] " - "subc %d mthd %04x data %08x\n", - unit, show, msg, chid, chan ? chan->inst->addr : 0, - chan ? chan->object.client->name : "unknown", - subc, mthd, data); - nvkm_fifo_chan_put(&fifo->base, flags, &chan); - } + bool intr0 = gf100_runq_intr(runq, NULL); + bool intr1 = gk104_runq_intr_1(runq); - nvkm_wr32(device, 0x040108 + (unit * 0x2000), stat); + return intr0 || intr1; } -static const struct nvkm_bitfield gk104_fifo_pbdma_intr_1[] = { - { 0x00000001, "HCE_RE_ILLEGAL_OP" }, - { 0x00000002, "HCE_RE_ALIGNB" }, - { 0x00000004, "HCE_PRIV" }, - { 0x00000008, "HCE_ILLEGAL_MTHD" }, - { 0x00000010, "HCE_ILLEGAL_CLASS" }, - {} -}; - void -gk104_fifo_intr_pbdma_1(struct gk104_fifo *fifo, int unit) +gk104_runq_init(struct nvkm_runq *runq) { - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; - struct nvkm_device *device = subdev->device; - u32 mask = nvkm_rd32(device, 0x04014c + (unit * 0x2000)); - u32 stat = nvkm_rd32(device, 0x040148 + (unit * 0x2000)) & mask; - u32 chid = nvkm_rd32(device, 0x040120 + (unit * 0x2000)) & 0xfff; - char msg[128]; + struct nvkm_device *device = runq->fifo->engine.subdev.device; - if (stat) { - nvkm_snprintbf(msg, sizeof(msg), gk104_fifo_pbdma_intr_1, stat); - nvkm_error(subdev, "PBDMA%d: %08x [%s] ch %d %08x %08x\n", - unit, stat, msg, chid, - nvkm_rd32(device, 0x040150 + (unit * 0x2000)), - nvkm_rd32(device, 0x040154 + (unit * 0x2000))); - } + gf100_runq_init(runq); - nvkm_wr32(device, 0x040148 + (unit * 0x2000), stat); + nvkm_wr32(device, 0x040148 + (runq->id * 0x2000), 0xffffffff); /* HCE.INTR */ + nvkm_wr32(device, 0x04014c + (runq->id * 0x2000), 0xffffffff); /* HCE.INTREN */ } -void -gk104_fifo_intr_runlist(struct gk104_fifo *fifo) +static u32 +gk104_runq_runm(struct nvkm_runq *runq) { - struct nvkm_device *device = fifo->base.engine.subdev.device; - u32 mask = nvkm_rd32(device, 0x002a00); - while (mask) { - int runl = __ffs(mask); - wake_up(&fifo->runlist[runl].wait); - nvkm_wr32(device, 0x002a00, 1 << runl); - mask &= ~(1 << runl); - } + return nvkm_rd32(runq->fifo->engine.subdev.device, 0x002390 + (runq->id * 0x04)); } +const struct nvkm_runq_func +gk104_runq = { + .init = gk104_runq_init, + .intr = gk104_runq_intr, + .intr_0_names = gk104_runq_intr_0_names, + .idle = gk104_runq_idle, +}; + void -gk104_fifo_intr_engine(struct gk104_fifo *fifo) +gk104_runl_fault_clear(struct nvkm_runl *runl) { - nvkm_fifo_uevent(&fifo->base); -} - -static void -gk104_fifo_intr(struct nvkm_fifo *base) -{ - struct gk104_fifo *fifo = gk104_fifo(base); - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; - struct nvkm_device *device = subdev->device; - u32 mask = nvkm_rd32(device, 0x002140); - u32 stat = nvkm_rd32(device, 0x002100) & mask; - - if (stat & 0x00000001) { - gk104_fifo_intr_bind(fifo); - nvkm_wr32(device, 0x002100, 0x00000001); - stat &= ~0x00000001; - } - - if (stat & 0x00000010) { - nvkm_error(subdev, "PIO_ERROR\n"); - nvkm_wr32(device, 0x002100, 0x00000010); - stat &= ~0x00000010; - } - - if (stat & 0x00000100) { - gk104_fifo_intr_sched(fifo); - nvkm_wr32(device, 0x002100, 0x00000100); - stat &= ~0x00000100; - } - - if (stat & 0x00010000) { - gk104_fifo_intr_chsw(fifo); - nvkm_wr32(device, 0x002100, 0x00010000); - stat &= ~0x00010000; - } - - if (stat & 0x00800000) { - nvkm_error(subdev, "FB_FLUSH_TIMEOUT\n"); - nvkm_wr32(device, 0x002100, 0x00800000); - stat &= ~0x00800000; - } - - if (stat & 0x01000000) { - nvkm_error(subdev, "LB_ERROR\n"); - nvkm_wr32(device, 0x002100, 0x01000000); - stat &= ~0x01000000; - } - - if (stat & 0x08000000) { - gk104_fifo_intr_dropped_fault(fifo); - nvkm_wr32(device, 0x002100, 0x08000000); - stat &= ~0x08000000; - } - - if (stat & 0x10000000) { - u32 mask = nvkm_rd32(device, 0x00259c); - while (mask) { - u32 unit = __ffs(mask); - fifo->func->intr.fault(&fifo->base, unit); - nvkm_wr32(device, 0x00259c, (1 << unit)); - mask &= ~(1 << unit); - } - stat &= ~0x10000000; - } - - if (stat & 0x20000000) { - u32 mask = nvkm_rd32(device, 0x0025a0); - while (mask) { - u32 unit = __ffs(mask); - gk104_fifo_intr_pbdma_0(fifo, unit); - gk104_fifo_intr_pbdma_1(fifo, unit); - nvkm_wr32(device, 0x0025a0, (1 << unit)); - mask &= ~(1 << unit); - } - stat &= ~0x20000000; - } - - if (stat & 0x40000000) { - gk104_fifo_intr_runlist(fifo); - stat &= ~0x40000000; - } - - if (stat & 0x80000000) { - nvkm_wr32(device, 0x002100, 0x80000000); - gk104_fifo_intr_engine(fifo); - stat &= ~0x80000000; - } - - if (stat) { - nvkm_error(subdev, "INTR %08x\n", stat); - nvkm_mask(device, 0x002140, stat, 0x00000000); - nvkm_wr32(device, 0x002100, stat); - } + nvkm_wr32(runl->fifo->engine.subdev.device, 0x00262c, BIT(runl->id)); } void -gk104_fifo_fini(struct nvkm_fifo *base) +gk104_runl_allow(struct nvkm_runl *runl, u32 engm) { - struct gk104_fifo *fifo = gk104_fifo(base); - struct nvkm_device *device = fifo->base.engine.subdev.device; - flush_work(&fifo->recover.work); - /* allow mmu fault interrupts, even when we're not using fifo */ - nvkm_mask(device, 0x002140, 0x10000000, 0x10000000); + nvkm_mask(runl->fifo->engine.subdev.device, 0x002630, BIT(runl->id), 0x00000000); } -int -gk104_fifo_info(struct nvkm_fifo *base, u64 mthd, u64 *data) +void +gk104_runl_block(struct nvkm_runl *runl, u32 engm) { - struct gk104_fifo *fifo = gk104_fifo(base); - switch (mthd) { - case NV_DEVICE_HOST_RUNLISTS: - *data = (1ULL << fifo->runlist_nr) - 1; - return 0; - case NV_DEVICE_HOST_RUNLIST_ENGINES: { - if (*data < fifo->runlist_nr) { - unsigned long engm = fifo->runlist[*data].engm; - struct nvkm_engine *engine; - int engn; - *data = 0; - for_each_set_bit(engn, &engm, fifo->engine_nr) { - if ((engine = fifo->engine[engn].engine)) { -#define CASE(n) case NVKM_ENGINE_##n: *data |= NV_DEVICE_HOST_RUNLIST_ENGINES_##n; break - switch (engine->subdev.type) { - CASE(SW ); - CASE(GR ); - CASE(MPEG ); - CASE(ME ); - CASE(CIPHER); - CASE(BSP ); - CASE(VP ); - CASE(CE ); - CASE(SEC ); - CASE(MSVLD ); - CASE(MSPDEC); - CASE(MSPPP ); - CASE(MSENC ); - CASE(VIC ); - CASE(SEC2 ); - CASE(NVDEC ); - CASE(NVENC ); - default: - WARN_ON(1); - break; - } - } - } - return 0; - } - } - return -EINVAL; - default: - return -EINVAL; - } + nvkm_mask(runl->fifo->engine.subdev.device, 0x002630, BIT(runl->id), BIT(runl->id)); } -int -gk104_fifo_oneinit(struct nvkm_fifo *base) +bool +gk104_runl_pending(struct nvkm_runl *runl) { - struct gk104_fifo *fifo = gk104_fifo(base); - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; - struct nvkm_device *device = subdev->device; - struct nvkm_vmm *bar = nvkm_bar_bar1_vmm(device); - struct nvkm_top_device *tdev; - int pbid, ret, i, j; - u32 *map; - - fifo->pbdma_nr = fifo->func->pbdma->nr(fifo); - nvkm_debug(subdev, "%d PBDMA(s)\n", fifo->pbdma_nr); - - /* Read PBDMA->runlist(s) mapping from HW. */ - if (!(map = kcalloc(fifo->pbdma_nr, sizeof(*map), GFP_KERNEL))) - return -ENOMEM; + struct nvkm_device *device = runl->fifo->engine.subdev.device; - for (i = 0; i < fifo->pbdma_nr; i++) - map[i] = nvkm_rd32(device, 0x002390 + (i * 0x04)); - - /* Determine runlist configuration from topology device info. */ - list_for_each_entry(tdev, &device->top->device, head) { - const int engn = tdev->engine; - char _en[16], *en; - - if (engn < 0) - continue; - - /* Determine which PBDMA handles requests for this engine. */ - for (j = 0, pbid = -1; j < fifo->pbdma_nr; j++) { - if (map[j] & BIT(tdev->runlist)) { - pbid = j; - break; - } - } - - fifo->engine[engn].engine = nvkm_device_engine(device, tdev->type, tdev->inst); - if (!fifo->engine[engn].engine) { - snprintf(_en, sizeof(_en), "%s, %d", - nvkm_subdev_type[tdev->type], tdev->inst); - en = _en; - } else { - en = fifo->engine[engn].engine->subdev.name; - } - - nvkm_debug(subdev, "engine %2d: runlist %2d pbdma %2d (%s)\n", - tdev->engine, tdev->runlist, pbid, en); - - fifo->engine[engn].runl = tdev->runlist; - fifo->engine[engn].pbid = pbid; - fifo->engine_nr = max(fifo->engine_nr, engn + 1); - fifo->runlist[tdev->runlist].engm |= BIT(engn); - fifo->runlist[tdev->runlist].engm_sw |= BIT(engn); - if (tdev->type == NVKM_ENGINE_GR) - fifo->runlist[tdev->runlist].engm_sw |= BIT(GK104_FIFO_ENGN_SW); - fifo->runlist_nr = max(fifo->runlist_nr, tdev->runlist + 1); - } - - kfree(map); - - for (i = 0; i < fifo->runlist_nr; i++) { - for (j = 0; j < ARRAY_SIZE(fifo->runlist[i].mem); j++) { - ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, - fifo->base.nr * 2/* TSG+chan */ * - fifo->func->runlist->size, - 0x1000, false, - &fifo->runlist[i].mem[j]); - if (ret) - return ret; - } - - init_waitqueue_head(&fifo->runlist[i].wait); - INIT_LIST_HEAD(&fifo->runlist[i].cgrp); - INIT_LIST_HEAD(&fifo->runlist[i].chan); - } - - ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, - fifo->base.nr * 0x200, 0x1000, true, - &fifo->user.mem); - if (ret) - return ret; - - ret = nvkm_vmm_get(bar, 12, nvkm_memory_size(fifo->user.mem), - &fifo->user.bar); - if (ret) - return ret; - - return nvkm_memory_map(fifo->user.mem, 0, bar, fifo->user.bar, NULL, 0); + return nvkm_rd32(device, 0x002284 + (runl->id * 0x08)) & 0x00100000; } void -gk104_fifo_init(struct nvkm_fifo *base) +gk104_runl_commit(struct nvkm_runl *runl, struct nvkm_memory *memory, u32 start, int count) { - struct gk104_fifo *fifo = gk104_fifo(base); - struct nvkm_device *device = fifo->base.engine.subdev.device; - int i; - - /* Enable PBDMAs. */ - fifo->func->pbdma->init(fifo); - - /* PBDMA[n] */ - for (i = 0; i < fifo->pbdma_nr; i++) { - nvkm_mask(device, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000); - nvkm_wr32(device, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */ - nvkm_wr32(device, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */ - } - - /* PBDMA[n].HCE */ - for (i = 0; i < fifo->pbdma_nr; i++) { - nvkm_wr32(device, 0x040148 + (i * 0x2000), 0xffffffff); /* INTR */ - nvkm_wr32(device, 0x04014c + (i * 0x2000), 0xffffffff); /* INTREN */ - } - - nvkm_wr32(device, 0x002254, 0x10000000 | fifo->user.bar->addr >> 12); - - if (fifo->func->pbdma->init_timeout) - fifo->func->pbdma->init_timeout(fifo); - - nvkm_wr32(device, 0x002100, 0xffffffff); - nvkm_wr32(device, 0x002140, 0x7fffffff); -} - -void * -gk104_fifo_dtor(struct nvkm_fifo *base) -{ - struct gk104_fifo *fifo = gk104_fifo(base); - struct nvkm_device *device = fifo->base.engine.subdev.device; - int i; - - nvkm_vmm_put(nvkm_bar_bar1_vmm(device), &fifo->user.bar); - nvkm_memory_unref(&fifo->user.mem); + struct nvkm_fifo *fifo = runl->fifo; + struct nvkm_device *device = fifo->engine.subdev.device; + u64 addr = nvkm_memory_addr(memory) + start; + int target; - for (i = 0; i < fifo->runlist_nr; i++) { - nvkm_memory_unref(&fifo->runlist[i].mem[1]); - nvkm_memory_unref(&fifo->runlist[i].mem[0]); + switch (nvkm_memory_target(memory)) { + case NVKM_MEM_TARGET_VRAM: target = 0; break; + case NVKM_MEM_TARGET_NCOH: target = 3; break; + default: + WARN_ON(1); + return; } - return fifo; + spin_lock_irq(&fifo->lock); + nvkm_wr32(device, 0x002270, (target << 28) | (addr >> 12)); + nvkm_wr32(device, 0x002274, (runl->id << 20) | count); + spin_unlock_irq(&fifo->lock); } -static const struct nvkm_fifo_func -gk104_fifo_ = { - .dtor = gk104_fifo_dtor, - .oneinit = gk104_fifo_oneinit, - .info = gk104_fifo_info, - .init = gk104_fifo_init, - .fini = gk104_fifo_fini, - .intr = gk104_fifo_intr, - .fault = gk104_fifo_fault, - .engine_id = gk104_fifo_engine_id, - .id_engine = gk104_fifo_id_engine, - .uevent_init = gk104_fifo_uevent_init, - .uevent_fini = gk104_fifo_uevent_fini, - .recover_chan = gk104_fifo_recover_chan, - .class_get = gk104_fifo_class_get, - .class_new = gk104_fifo_class_new, -}; - -int -gk104_fifo_new_(const struct gk104_fifo_func *func, struct nvkm_device *device, - enum nvkm_subdev_type type, int inst, int nr, struct nvkm_fifo **pfifo) +void +gk104_runl_insert_chan(struct nvkm_chan *chan, struct nvkm_memory *memory, u64 offset) { - struct gk104_fifo *fifo; - - if (!(fifo = kzalloc(sizeof(*fifo), GFP_KERNEL))) - return -ENOMEM; - fifo->func = func; - INIT_WORK(&fifo->recover.work, gk104_fifo_recover_work); - *pfifo = &fifo->base; - - return nvkm_fifo_ctor(&gk104_fifo_, device, type, inst, nr, &fifo->base); + nvkm_wo32(memory, offset + 0, chan->id); + nvkm_wo32(memory, offset + 4, 0x00000000); } -const struct nvkm_enum -gk104_fifo_fault_access[] = { - { 0x0, "READ" }, - { 0x1, "WRITE" }, - {} +static const struct nvkm_runl_func +gk104_runl = { + .size = 8, + .update = nv50_runl_update, + .insert_chan = gk104_runl_insert_chan, + .commit = gk104_runl_commit, + .wait = nv50_runl_wait, + .pending = gk104_runl_pending, + .block = gk104_runl_block, + .allow = gk104_runl_allow, + .fault_clear = gk104_runl_fault_clear, + .preempt_pending = gf100_runl_preempt_pending, }; -const struct nvkm_enum -gk104_fifo_fault_engine[] = { +static const struct nvkm_enum +gk104_fifo_mmu_fault_engine[] = { { 0x00, "GR", NULL, NVKM_ENGINE_GR }, { 0x01, "DISPLAY" }, { 0x02, "CAPTURE" }, @@ -1122,14 +478,14 @@ gk104_fifo_fault_engine[] = { { 0x04, "BAR1", NULL, NVKM_SUBDEV_BAR }, { 0x05, "BAR2", NULL, NVKM_SUBDEV_INSTMEM }, { 0x06, "SCHED" }, - { 0x07, "HOST0", NULL, NVKM_ENGINE_FIFO }, - { 0x08, "HOST1", NULL, NVKM_ENGINE_FIFO }, - { 0x09, "HOST2", NULL, NVKM_ENGINE_FIFO }, - { 0x0a, "HOST3", NULL, NVKM_ENGINE_FIFO }, - { 0x0b, "HOST4", NULL, NVKM_ENGINE_FIFO }, - { 0x0c, "HOST5", NULL, NVKM_ENGINE_FIFO }, - { 0x0d, "HOST6", NULL, NVKM_ENGINE_FIFO }, - { 0x0e, "HOST7", NULL, NVKM_ENGINE_FIFO }, + { 0x07, "HOST0" }, + { 0x08, "HOST1" }, + { 0x09, "HOST2" }, + { 0x0a, "HOST3" }, + { 0x0b, "HOST4" }, + { 0x0c, "HOST5" }, + { 0x0d, "HOST6" }, + { 0x0e, "HOST7" }, { 0x0f, "HOSTSR" }, { 0x10, "MSVLD", NULL, NVKM_ENGINE_MSVLD }, { 0x11, "MSPPP", NULL, NVKM_ENGINE_MSPPP }, @@ -1145,7 +501,7 @@ gk104_fifo_fault_engine[] = { }; const struct nvkm_enum -gk104_fifo_fault_reason[] = { +gk104_fifo_mmu_fault_reason[] = { { 0x00, "PDE" }, { 0x01, "PDE_SIZE" }, { 0x02, "PTE" }, @@ -1166,7 +522,7 @@ gk104_fifo_fault_reason[] = { }; const struct nvkm_enum -gk104_fifo_fault_hubclient[] = { +gk104_fifo_mmu_fault_hubclient[] = { { 0x00, "VIP" }, { 0x01, "CE0" }, { 0x02, "CE1" }, @@ -1203,7 +559,7 @@ gk104_fifo_fault_hubclient[] = { }; const struct nvkm_enum -gk104_fifo_fault_gpcclient[] = { +gk104_fifo_mmu_fault_gpcclient[] = { { 0x00, "L1_0" }, { 0x01, "T1_0" }, { 0x02, "PE_0" }, { 0x03, "L1_1" }, { 0x04, "T1_1" }, { 0x05, "PE_1" }, { 0x06, "L1_2" }, { 0x07, "T1_2" }, { 0x08, "PE_2" }, @@ -1228,22 +584,250 @@ gk104_fifo_fault_gpcclient[] = { {} }; -static const struct gk104_fifo_func +const struct nvkm_fifo_func_mmu_fault +gk104_fifo_mmu_fault = { + .recover = gf100_fifo_mmu_fault_recover, + .access = gf100_fifo_mmu_fault_access, + .engine = gk104_fifo_mmu_fault_engine, + .reason = gk104_fifo_mmu_fault_reason, + .hubclient = gk104_fifo_mmu_fault_hubclient, + .gpcclient = gk104_fifo_mmu_fault_gpcclient, +}; + +static const struct nvkm_enum +gk104_fifo_intr_bind_reason[] = { + { 0x01, "BIND_NOT_UNBOUND" }, + { 0x02, "SNOOP_WITHOUT_BAR1" }, + { 0x03, "UNBIND_WHILE_RUNNING" }, + { 0x05, "INVALID_RUNLIST" }, + { 0x06, "INVALID_CTX_TGT" }, + { 0x0b, "UNBIND_WHILE_PARKED" }, + {} +}; + +void +gk104_fifo_intr_bind(struct nvkm_fifo *fifo) +{ + struct nvkm_subdev *subdev = &fifo->engine.subdev; + u32 intr = nvkm_rd32(subdev->device, 0x00252c); + u32 code = intr & 0x000000ff; + const struct nvkm_enum *en = nvkm_enum_find(gk104_fifo_intr_bind_reason, code); + + nvkm_error(subdev, "BIND_ERROR %02x [%s]\n", code, en ? en->name : ""); +} + +void +gk104_fifo_intr_chsw(struct nvkm_fifo *fifo) +{ + struct nvkm_subdev *subdev = &fifo->engine.subdev; + struct nvkm_device *device = subdev->device; + u32 stat = nvkm_rd32(device, 0x00256c); + + nvkm_error(subdev, "CHSW_ERROR %08x\n", stat); + nvkm_wr32(device, 0x00256c, stat); +} + +static void +gk104_fifo_intr_dropped_fault(struct nvkm_fifo *fifo) +{ + struct nvkm_subdev *subdev = &fifo->engine.subdev; + u32 stat = nvkm_rd32(subdev->device, 0x00259c); + + nvkm_error(subdev, "DROPPED_MMU_FAULT %08x\n", stat); +} + +void +gk104_fifo_intr_runlist(struct nvkm_fifo *fifo) +{ + struct nvkm_device *device = fifo->engine.subdev.device; + struct nvkm_runl *runl; + u32 mask = nvkm_rd32(device, 0x002a00); + + nvkm_runl_foreach_cond(runl, fifo, mask & BIT(runl->id)) { + nvkm_wr32(device, 0x002a00, BIT(runl->id)); + } +} + +irqreturn_t +gk104_fifo_intr(struct nvkm_inth *inth) +{ + struct nvkm_fifo *fifo = container_of(inth, typeof(*fifo), engine.subdev.inth); + struct nvkm_subdev *subdev = &fifo->engine.subdev; + struct nvkm_device *device = subdev->device; + u32 mask = nvkm_rd32(device, 0x002140); + u32 stat = nvkm_rd32(device, 0x002100) & mask; + + if (stat & 0x00000001) { + gk104_fifo_intr_bind(fifo); + nvkm_wr32(device, 0x002100, 0x00000001); + stat &= ~0x00000001; + } + + if (stat & 0x00000010) { + nvkm_error(subdev, "PIO_ERROR\n"); + nvkm_wr32(device, 0x002100, 0x00000010); + stat &= ~0x00000010; + } + + if (stat & 0x00000100) { + gf100_fifo_intr_sched(fifo); + nvkm_wr32(device, 0x002100, 0x00000100); + stat &= ~0x00000100; + } + + if (stat & 0x00010000) { + gk104_fifo_intr_chsw(fifo); + nvkm_wr32(device, 0x002100, 0x00010000); + stat &= ~0x00010000; + } + + if (stat & 0x00800000) { + nvkm_error(subdev, "FB_FLUSH_TIMEOUT\n"); + nvkm_wr32(device, 0x002100, 0x00800000); + stat &= ~0x00800000; + } + + if (stat & 0x01000000) { + nvkm_error(subdev, "LB_ERROR\n"); + nvkm_wr32(device, 0x002100, 0x01000000); + stat &= ~0x01000000; + } + + if (stat & 0x08000000) { + gk104_fifo_intr_dropped_fault(fifo); + nvkm_wr32(device, 0x002100, 0x08000000); + stat &= ~0x08000000; + } + + if (stat & 0x10000000) { + gf100_fifo_intr_mmu_fault(fifo); + stat &= ~0x10000000; + } + + if (stat & 0x20000000) { + if (gf100_fifo_intr_pbdma(fifo)) + stat &= ~0x20000000; + } + + if (stat & 0x40000000) { + gk104_fifo_intr_runlist(fifo); + stat &= ~0x40000000; + } + + if (stat & 0x80000000) { + nvkm_wr32(device, 0x002100, 0x80000000); + nvkm_event_ntfy(&fifo->nonstall.event, 0, NVKM_FIFO_NONSTALL_EVENT); + stat &= ~0x80000000; + } + + if (stat) { + nvkm_error(subdev, "INTR %08x\n", stat); + spin_lock(&fifo->lock); + nvkm_mask(device, 0x002140, stat, 0x00000000); + spin_unlock(&fifo->lock); + nvkm_wr32(device, 0x002100, stat); + } + + return IRQ_HANDLED; +} + +void +gk104_fifo_init_pbdmas(struct nvkm_fifo *fifo, u32 mask) +{ + struct nvkm_device *device = fifo->engine.subdev.device; + + nvkm_wr32(device, 0x000204, mask); + nvkm_mask(device, 0x002a04, 0xbfffffff, 0xbfffffff); +} + +void +gk104_fifo_init(struct nvkm_fifo *fifo) +{ + struct nvkm_device *device = fifo->engine.subdev.device; + + if (fifo->func->chan.func->userd->bar == 1) + nvkm_wr32(device, 0x002254, 0x10000000 | fifo->userd.bar1->addr >> 12); + + nvkm_wr32(device, 0x002100, 0xffffffff); + nvkm_wr32(device, 0x002140, 0x7fffffff); +} + +int +gk104_fifo_runl_ctor(struct nvkm_fifo *fifo) +{ + struct nvkm_device *device = fifo->engine.subdev.device; + struct nvkm_top_device *tdev; + struct nvkm_runl *runl; + struct nvkm_runq *runq; + const struct nvkm_engn_func *func; + + nvkm_list_foreach(tdev, &device->top->device, head, tdev->runlist >= 0) { + runl = nvkm_runl_get(fifo, tdev->runlist, tdev->runlist); + if (!runl) { + runl = nvkm_runl_new(fifo, tdev->runlist, tdev->runlist, 0); + if (IS_ERR(runl)) + return PTR_ERR(runl); + + nvkm_runq_foreach_cond(runq, fifo, gk104_runq_runm(runq) & BIT(runl->id)) { + if (WARN_ON(runl->runq_nr == ARRAY_SIZE(runl->runq))) + return -ENOMEM; + + runl->runq[runl->runq_nr++] = runq; + } + + } + + if (tdev->engine < 0) + continue; + + switch (tdev->type) { + case NVKM_ENGINE_CE: + func = fifo->func->engn_ce; + break; + case NVKM_ENGINE_GR: + nvkm_runl_add(runl, 15, &gf100_engn_sw, NVKM_ENGINE_SW, 0); + fallthrough; + default: + func = fifo->func->engn; + break; + } + + nvkm_runl_add(runl, tdev->engine, func, tdev->type, tdev->inst); + } + + return 0; +} + +int +gk104_fifo_chid_nr(struct nvkm_fifo *fifo) +{ + return 4096; +} + +static const struct nvkm_fifo_func gk104_fifo = { - .intr.fault = gf100_fifo_intr_fault, - .pbdma = &gk104_fifo_pbdma, - .fault.access = gk104_fifo_fault_access, - .fault.engine = gk104_fifo_fault_engine, - .fault.reason = gk104_fifo_fault_reason, - .fault.hubclient = gk104_fifo_fault_hubclient, - .fault.gpcclient = gk104_fifo_fault_gpcclient, - .runlist = &gk104_fifo_runlist, - .chan = {{0,0,KEPLER_CHANNEL_GPFIFO_A}, gk104_fifo_gpfifo_new }, + .chid_nr = gk104_fifo_chid_nr, + .chid_ctor = gf100_fifo_chid_ctor, + .runq_nr = gf100_fifo_runq_nr, + .runl_ctor = gk104_fifo_runl_ctor, + .init = gk104_fifo_init, + .init_pbdmas = gk104_fifo_init_pbdmas, + .intr = gk104_fifo_intr, + .intr_mmu_fault_unit = gf100_fifo_intr_mmu_fault_unit, + .intr_ctxsw_timeout = gf100_fifo_intr_ctxsw_timeout, + .mmu_fault = &gk104_fifo_mmu_fault, + .nonstall = &gf100_fifo_nonstall, + .runl = &gk104_runl, + .runq = &gk104_runq, + .engn = &gk104_engn, + .engn_ce = &gk104_engn_ce, + .cgrp = {{ }, &nv04_cgrp }, + .chan = {{ 0, 0, KEPLER_CHANNEL_GPFIFO_A }, &gk104_chan }, }; int gk104_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fifo **pfifo) { - return gk104_fifo_new_(&gk104_fifo, device, type, inst, 4096, pfifo); + return nvkm_fifo_new_(&gk104_fifo, device, type, inst, pfifo); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h deleted file mode 100644 index f2d12ae73944..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h +++ /dev/null @@ -1,168 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -#ifndef __GK104_FIFO_H__ -#define __GK104_FIFO_H__ -#define gk104_fifo(p) container_of((p), struct gk104_fifo, base) -#include "priv.h" -struct nvkm_fifo_cgrp; - -#include <core/enum.h> -#include <subdev/mmu.h> - -struct gk104_fifo_chan; -struct gk104_fifo { - const struct gk104_fifo_func *func; - struct nvkm_fifo base; - - struct { - struct work_struct work; - u32 engm; - u32 runm; - } recover; - - int pbdma_nr; - - struct { - struct nvkm_engine *engine; - int runl; - int pbid; - } engine[16]; - int engine_nr; - - struct { - struct nvkm_memory *mem[2]; - int next; - wait_queue_head_t wait; - struct list_head cgrp; - struct list_head chan; - u32 engm; - u32 engm_sw; - } runlist[16]; - int runlist_nr; - - struct { - struct nvkm_memory *mem; - struct nvkm_vma *bar; - } user; -}; - -struct gk104_fifo_func { - struct { - void (*fault)(struct nvkm_fifo *, int unit); - } intr; - - const struct gk104_fifo_pbdma_func { - int (*nr)(struct gk104_fifo *); - void (*init)(struct gk104_fifo *); - void (*init_timeout)(struct gk104_fifo *); - } *pbdma; - - struct { - const struct nvkm_enum *access; - const struct nvkm_enum *engine; - const struct nvkm_enum *reason; - const struct nvkm_enum *hubclient; - const struct nvkm_enum *gpcclient; - } fault; - - const struct gk104_fifo_runlist_func { - u8 size; - void (*cgrp)(struct nvkm_fifo_cgrp *, - struct nvkm_memory *, u32 offset); - void (*chan)(struct gk104_fifo_chan *, - struct nvkm_memory *, u32 offset); - void (*commit)(struct gk104_fifo *, int runl, - struct nvkm_memory *, int entries); - } *runlist; - - struct gk104_fifo_user_user { - struct nvkm_sclass user; - int (*ctor)(const struct nvkm_oclass *, void *, u32, - struct nvkm_object **); - } user; - - struct gk104_fifo_chan_user { - struct nvkm_sclass user; - int (*ctor)(struct gk104_fifo *, const struct nvkm_oclass *, - void *, u32, struct nvkm_object **); - } chan; - bool cgrp_force; -}; - -struct gk104_fifo_engine_status { - bool busy; - bool faulted; - bool chsw; - bool save; - bool load; - struct { - bool tsg; - u32 id; - } prev, next, *chan; -}; - -int gk104_fifo_new_(const struct gk104_fifo_func *, struct nvkm_device *, enum nvkm_subdev_type, - int index, int nr, struct nvkm_fifo **); -void gk104_fifo_runlist_insert(struct gk104_fifo *, struct gk104_fifo_chan *); -void gk104_fifo_runlist_remove(struct gk104_fifo *, struct gk104_fifo_chan *); -void gk104_fifo_runlist_update(struct gk104_fifo *, int runl); -void gk104_fifo_engine_status(struct gk104_fifo *fifo, int engn, - struct gk104_fifo_engine_status *status); -void gk104_fifo_intr_bind(struct gk104_fifo *fifo); -void gk104_fifo_intr_chsw(struct gk104_fifo *fifo); -void gk104_fifo_intr_dropped_fault(struct gk104_fifo *fifo); -void gk104_fifo_intr_pbdma_0(struct gk104_fifo *fifo, int unit); -void gk104_fifo_intr_pbdma_1(struct gk104_fifo *fifo, int unit); -void gk104_fifo_intr_runlist(struct gk104_fifo *fifo); -void gk104_fifo_intr_engine(struct gk104_fifo *fifo); -void *gk104_fifo_dtor(struct nvkm_fifo *base); -int gk104_fifo_oneinit(struct nvkm_fifo *base); -int gk104_fifo_info(struct nvkm_fifo *base, u64 mthd, u64 *data); -void gk104_fifo_init(struct nvkm_fifo *base); -void gk104_fifo_fini(struct nvkm_fifo *base); -int gk104_fifo_class_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, - void *argv, u32 argc, struct nvkm_object **pobject); -int gk104_fifo_class_get(struct nvkm_fifo *base, int index, - struct nvkm_oclass *oclass); -void gk104_fifo_uevent_fini(struct nvkm_fifo *fifo); -void gk104_fifo_uevent_init(struct nvkm_fifo *fifo); - -extern const struct gk104_fifo_pbdma_func gk104_fifo_pbdma; -int gk104_fifo_pbdma_nr(struct gk104_fifo *); -void gk104_fifo_pbdma_init(struct gk104_fifo *); -extern const struct nvkm_enum gk104_fifo_fault_access[]; -extern const struct nvkm_enum gk104_fifo_fault_engine[]; -extern const struct nvkm_enum gk104_fifo_fault_reason[]; -extern const struct nvkm_enum gk104_fifo_fault_hubclient[]; -extern const struct nvkm_enum gk104_fifo_fault_gpcclient[]; -extern const struct gk104_fifo_runlist_func gk104_fifo_runlist; -void gk104_fifo_runlist_chan(struct gk104_fifo_chan *, - struct nvkm_memory *, u32); -void gk104_fifo_runlist_commit(struct gk104_fifo *, int runl, - struct nvkm_memory *, int); - -extern const struct gk104_fifo_runlist_func gk110_fifo_runlist; -void gk110_fifo_runlist_cgrp(struct nvkm_fifo_cgrp *, - struct nvkm_memory *, u32); - -extern const struct gk104_fifo_pbdma_func gk208_fifo_pbdma; -void gk208_fifo_pbdma_init_timeout(struct gk104_fifo *); - -void gm107_fifo_intr_fault(struct nvkm_fifo *, int); -extern const struct nvkm_enum gm107_fifo_fault_engine[]; -extern const struct gk104_fifo_runlist_func gm107_fifo_runlist; - -extern const struct gk104_fifo_pbdma_func gm200_fifo_pbdma; -int gm200_fifo_pbdma_nr(struct gk104_fifo *); - -void gp100_fifo_intr_fault(struct nvkm_fifo *, int); -extern const struct nvkm_enum gp100_fifo_fault_engine[]; - -extern const struct nvkm_enum gv100_fifo_fault_access[]; -extern const struct nvkm_enum gv100_fifo_fault_reason[]; -extern const struct nvkm_enum gv100_fifo_fault_hubclient[]; -extern const struct nvkm_enum gv100_fifo_fault_gpcclient[]; -void gv100_fifo_runlist_cgrp(struct nvkm_fifo_cgrp *, - struct nvkm_memory *, u32); -void gv100_fifo_runlist_chan(struct gk104_fifo_chan *, - struct nvkm_memory *, u32); -#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk110.c index 915278c7e012..a8ff21cf7712 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk110.c @@ -21,47 +21,112 @@ * * Authors: Ben Skeggs */ -#include "gk104.h" +#include "priv.h" #include "cgrp.h" -#include "changk104.h" +#include "chan.h" +#include "chid.h" +#include "runl.h" #include <core/memory.h> +#include <subdev/timer.h> #include <nvif/class.h> void -gk110_fifo_runlist_cgrp(struct nvkm_fifo_cgrp *cgrp, - struct nvkm_memory *memory, u32 offset) +gk110_chan_preempt(struct nvkm_chan *chan) +{ + struct nvkm_cgrp *cgrp = chan->cgrp; + + if (cgrp->hw) { + cgrp->func->preempt(cgrp); + return; + } + + gf100_chan_preempt(chan); +} + +const struct nvkm_chan_func +gk110_chan = { + .inst = &gf100_chan_inst, + .userd = &gk104_chan_userd, + .ramfc = &gk104_chan_ramfc, + .bind = gk104_chan_bind, + .unbind = gk104_chan_unbind, + .start = gk104_chan_start, + .stop = gk104_chan_stop, + .preempt = gk110_chan_preempt, +}; + +static void +gk110_cgrp_preempt(struct nvkm_cgrp *cgrp) +{ + nvkm_wr32(cgrp->runl->fifo->engine.subdev.device, 0x002634, 0x01000000 | cgrp->id); +} + +const struct nvkm_cgrp_func +gk110_cgrp = { + .preempt = gk110_cgrp_preempt, +}; + +void +gk110_runl_insert_cgrp(struct nvkm_cgrp *cgrp, struct nvkm_memory *memory, u64 offset) { nvkm_wo32(memory, offset + 0, (cgrp->chan_nr << 26) | (128 << 18) | (3 << 14) | 0x00002000 | cgrp->id); nvkm_wo32(memory, offset + 4, 0x00000000); } -const struct gk104_fifo_runlist_func -gk110_fifo_runlist = { +const struct nvkm_runl_func +gk110_runl = { .size = 8, - .cgrp = gk110_fifo_runlist_cgrp, - .chan = gk104_fifo_runlist_chan, - .commit = gk104_fifo_runlist_commit, + .update = nv50_runl_update, + .insert_cgrp = gk110_runl_insert_cgrp, + .insert_chan = gk104_runl_insert_chan, + .commit = gk104_runl_commit, + .wait = nv50_runl_wait, + .pending = gk104_runl_pending, + .block = gk104_runl_block, + .allow = gk104_runl_allow, + .fault_clear = gk104_runl_fault_clear, + .preempt_pending = gf100_runl_preempt_pending, }; -static const struct gk104_fifo_func +int +gk110_fifo_chid_ctor(struct nvkm_fifo *fifo, int nr) +{ + int ret; + + ret = nvkm_chid_new(&nvkm_chan_event, &fifo->engine.subdev, nr, 0, nr, &fifo->cgid); + if (ret) + return ret; + + return gf100_fifo_chid_ctor(fifo, nr); +} + +static const struct nvkm_fifo_func gk110_fifo = { - .intr.fault = gf100_fifo_intr_fault, - .pbdma = &gk104_fifo_pbdma, - .fault.access = gk104_fifo_fault_access, - .fault.engine = gk104_fifo_fault_engine, - .fault.reason = gk104_fifo_fault_reason, - .fault.hubclient = gk104_fifo_fault_hubclient, - .fault.gpcclient = gk104_fifo_fault_gpcclient, - .runlist = &gk110_fifo_runlist, - .chan = {{0,0,KEPLER_CHANNEL_GPFIFO_B}, gk104_fifo_gpfifo_new }, + .chid_nr = gk104_fifo_chid_nr, + .chid_ctor = gk110_fifo_chid_ctor, + .runq_nr = gf100_fifo_runq_nr, + .runl_ctor = gk104_fifo_runl_ctor, + .init = gk104_fifo_init, + .init_pbdmas = gk104_fifo_init_pbdmas, + .intr = gk104_fifo_intr, + .intr_mmu_fault_unit = gf100_fifo_intr_mmu_fault_unit, + .intr_ctxsw_timeout = gf100_fifo_intr_ctxsw_timeout, + .mmu_fault = &gk104_fifo_mmu_fault, + .nonstall = &gf100_fifo_nonstall, + .runl = &gk110_runl, + .runq = &gk104_runq, + .engn = &gk104_engn, + .engn_ce = &gk104_engn_ce, + .cgrp = {{ 0, 0, KEPLER_CHANNEL_GROUP_A }, &gk110_cgrp }, + .chan = {{ 0, 0, KEPLER_CHANNEL_GPFIFO_B }, &gk110_chan }, }; int gk110_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fifo **pfifo) { - return gk104_fifo_new_(&gk110_fifo, device, type, inst, 4096, pfifo); + return nvkm_fifo_new_(&gk110_fifo, device, type, inst, pfifo); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk208.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk208.c index cb703693de52..8fa2b0be141a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk208.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk208.c @@ -21,44 +21,57 @@ * * Authors: Ben Skeggs */ -#include "gk104.h" -#include "changk104.h" +#include "priv.h" +#include "runq.h" #include <nvif/class.h> void -gk208_fifo_pbdma_init_timeout(struct gk104_fifo *fifo) +gk208_runq_init(struct nvkm_runq *runq) { - struct nvkm_device *device = fifo->base.engine.subdev.device; - int i; + gk104_runq_init(runq); - for (i = 0; i < fifo->pbdma_nr; i++) - nvkm_wr32(device, 0x04012c + (i * 0x2000), 0x0000ffff); + nvkm_wr32(runq->fifo->engine.subdev.device, 0x04012c + (runq->id * 0x2000), 0x000f4240); } -const struct gk104_fifo_pbdma_func -gk208_fifo_pbdma = { - .nr = gk104_fifo_pbdma_nr, - .init = gk104_fifo_pbdma_init, - .init_timeout = gk208_fifo_pbdma_init_timeout, +const struct nvkm_runq_func +gk208_runq = { + .init = gk208_runq_init, + .intr = gk104_runq_intr, + .intr_0_names = gk104_runq_intr_0_names, + .idle = gk104_runq_idle, }; -static const struct gk104_fifo_func +static int +gk208_fifo_chid_nr(struct nvkm_fifo *fifo) +{ + return 1024; +} + +static const struct nvkm_fifo_func gk208_fifo = { - .intr.fault = gf100_fifo_intr_fault, - .pbdma = &gk208_fifo_pbdma, - .fault.access = gk104_fifo_fault_access, - .fault.engine = gk104_fifo_fault_engine, - .fault.reason = gk104_fifo_fault_reason, - .fault.hubclient = gk104_fifo_fault_hubclient, - .fault.gpcclient = gk104_fifo_fault_gpcclient, - .runlist = &gk110_fifo_runlist, - .chan = {{0,0,KEPLER_CHANNEL_GPFIFO_A}, gk104_fifo_gpfifo_new }, + .chid_nr = gk208_fifo_chid_nr, + .chid_ctor = gk110_fifo_chid_ctor, + .runq_nr = gf100_fifo_runq_nr, + .runl_ctor = gk104_fifo_runl_ctor, + .init = gk104_fifo_init, + .init_pbdmas = gk104_fifo_init_pbdmas, + .intr = gk104_fifo_intr, + .intr_mmu_fault_unit = gf100_fifo_intr_mmu_fault_unit, + .intr_ctxsw_timeout = gf100_fifo_intr_ctxsw_timeout, + .mmu_fault = &gk104_fifo_mmu_fault, + .nonstall = &gf100_fifo_nonstall, + .runl = &gk110_runl, + .runq = &gk208_runq, + .engn = &gk104_engn, + .engn_ce = &gk104_engn_ce, + .cgrp = {{ 0, 0, KEPLER_CHANNEL_GROUP_A }, &gk110_cgrp }, + .chan = {{ 0, 0, KEPLER_CHANNEL_GPFIFO_A }, &gk110_chan }, }; int gk208_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fifo **pfifo) { - return gk104_fifo_new_(&gk208_fifo, device, type, inst, 1024, pfifo); + return nvkm_fifo_new_(&gk208_fifo, device, type, inst, pfifo); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk20a.c index 6e35cf44c640..b63ca836130f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk20a.c @@ -19,27 +19,34 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ -#include "gk104.h" -#include "changk104.h" +#include "priv.h" #include <nvif/class.h> -static const struct gk104_fifo_func +static const struct nvkm_fifo_func gk20a_fifo = { - .intr.fault = gf100_fifo_intr_fault, - .pbdma = &gk208_fifo_pbdma, - .fault.access = gk104_fifo_fault_access, - .fault.engine = gk104_fifo_fault_engine, - .fault.reason = gk104_fifo_fault_reason, - .fault.hubclient = gk104_fifo_fault_hubclient, - .fault.gpcclient = gk104_fifo_fault_gpcclient, - .runlist = &gk110_fifo_runlist, - .chan = {{0,0,KEPLER_CHANNEL_GPFIFO_A}, gk104_fifo_gpfifo_new }, + .chid_nr = nv50_fifo_chid_nr, + .chid_ctor = gk110_fifo_chid_ctor, + .runq_nr = gf100_fifo_runq_nr, + .runl_ctor = gk104_fifo_runl_ctor, + .init = gk104_fifo_init, + .init_pbdmas = gk104_fifo_init_pbdmas, + .intr = gk104_fifo_intr, + .intr_mmu_fault_unit = gf100_fifo_intr_mmu_fault_unit, + .intr_ctxsw_timeout = gf100_fifo_intr_ctxsw_timeout, + .mmu_fault = &gk104_fifo_mmu_fault, + .nonstall = &gf100_fifo_nonstall, + .runl = &gk110_runl, + .runq = &gk208_runq, + .engn = &gk104_engn, + .engn_ce = &gk104_engn_ce, + .cgrp = {{ }, &gk110_cgrp }, + .chan = {{ 0, 0, KEPLER_CHANNEL_GPFIFO_A }, &gk110_chan }, }; int gk20a_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fifo **pfifo) { - return gk104_fifo_new_(&gk20a_fifo, device, type, inst, 128, pfifo); + return nvkm_fifo_new_(&gk20a_fifo, device, type, inst, pfifo); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm107.c index 7af6e687d474..5ba60021b510 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm107.c @@ -21,46 +21,65 @@ * * Authors: Ben Skeggs */ -#include "gk104.h" -#include "changk104.h" +#include "priv.h" +#include "chan.h" +#include "runl.h" #include <core/gpuobj.h> #include <subdev/fault.h> #include <nvif/class.h> +const struct nvkm_chan_func +gm107_chan = { + .inst = &gf100_chan_inst, + .userd = &gk104_chan_userd, + .ramfc = &gk104_chan_ramfc, + .bind = gk104_chan_bind_inst, + .unbind = gk104_chan_unbind, + .start = gk104_chan_start, + .stop = gk104_chan_stop, + .preempt = gk110_chan_preempt, +}; + static void -gm107_fifo_runlist_chan(struct gk104_fifo_chan *chan, - struct nvkm_memory *memory, u32 offset) +gm107_runl_insert_chan(struct nvkm_chan *chan, struct nvkm_memory *memory, u64 offset) { - nvkm_wo32(memory, offset + 0, chan->base.chid); - nvkm_wo32(memory, offset + 4, chan->base.inst->addr >> 12); + nvkm_wo32(memory, offset + 0, chan->id); + nvkm_wo32(memory, offset + 4, chan->inst->addr >> 12); } -const struct gk104_fifo_runlist_func -gm107_fifo_runlist = { +const struct nvkm_runl_func +gm107_runl = { .size = 8, - .cgrp = gk110_fifo_runlist_cgrp, - .chan = gm107_fifo_runlist_chan, - .commit = gk104_fifo_runlist_commit, + .update = nv50_runl_update, + .insert_cgrp = gk110_runl_insert_cgrp, + .insert_chan = gm107_runl_insert_chan, + .commit = gk104_runl_commit, + .wait = nv50_runl_wait, + .pending = gk104_runl_pending, + .block = gk104_runl_block, + .allow = gk104_runl_allow, + .fault_clear = gk104_runl_fault_clear, + .preempt_pending = gf100_runl_preempt_pending, }; -const struct nvkm_enum -gm107_fifo_fault_engine[] = { +static const struct nvkm_enum +gm107_fifo_mmu_fault_engine[] = { { 0x01, "DISPLAY" }, { 0x02, "CAPTURE" }, { 0x03, "IFB", NULL, NVKM_ENGINE_IFB }, { 0x04, "BAR1", NULL, NVKM_SUBDEV_BAR }, { 0x05, "BAR2", NULL, NVKM_SUBDEV_INSTMEM }, { 0x06, "SCHED" }, - { 0x07, "HOST0", NULL, NVKM_ENGINE_FIFO }, - { 0x08, "HOST1", NULL, NVKM_ENGINE_FIFO }, - { 0x09, "HOST2", NULL, NVKM_ENGINE_FIFO }, - { 0x0a, "HOST3", NULL, NVKM_ENGINE_FIFO }, - { 0x0b, "HOST4", NULL, NVKM_ENGINE_FIFO }, - { 0x0c, "HOST5", NULL, NVKM_ENGINE_FIFO }, - { 0x0d, "HOST6", NULL, NVKM_ENGINE_FIFO }, - { 0x0e, "HOST7", NULL, NVKM_ENGINE_FIFO }, + { 0x07, "HOST0" }, + { 0x08, "HOST1" }, + { 0x09, "HOST2" }, + { 0x0a, "HOST3" }, + { 0x0b, "HOST4" }, + { 0x0c, "HOST5" }, + { 0x0d, "HOST6" }, + { 0x0e, "HOST7" }, { 0x0f, "HOSTSR" }, { 0x13, "PERF" }, { 0x17, "PMU" }, @@ -68,8 +87,18 @@ gm107_fifo_fault_engine[] = { {} }; +const struct nvkm_fifo_func_mmu_fault +gm107_fifo_mmu_fault = { + .recover = gf100_fifo_mmu_fault_recover, + .access = gf100_fifo_mmu_fault_access, + .engine = gm107_fifo_mmu_fault_engine, + .reason = gk104_fifo_mmu_fault_reason, + .hubclient = gk104_fifo_mmu_fault_hubclient, + .gpcclient = gk104_fifo_mmu_fault_gpcclient, +}; + void -gm107_fifo_intr_fault(struct nvkm_fifo *fifo, int unit) +gm107_fifo_intr_mmu_fault_unit(struct nvkm_fifo *fifo, int unit) { struct nvkm_device *device = fifo->engine.subdev.device; u32 inst = nvkm_rd32(device, 0x002800 + (unit * 0x10)); @@ -92,22 +121,36 @@ gm107_fifo_intr_fault(struct nvkm_fifo *fifo, int unit) nvkm_fifo_fault(fifo, &info); } -static const struct gk104_fifo_func +static int +gm107_fifo_chid_nr(struct nvkm_fifo *fifo) +{ + return 2048; +} + +static const struct nvkm_fifo_func gm107_fifo = { - .intr.fault = gm107_fifo_intr_fault, - .pbdma = &gk208_fifo_pbdma, - .fault.access = gk104_fifo_fault_access, - .fault.engine = gm107_fifo_fault_engine, - .fault.reason = gk104_fifo_fault_reason, - .fault.hubclient = gk104_fifo_fault_hubclient, - .fault.gpcclient = gk104_fifo_fault_gpcclient, - .runlist = &gm107_fifo_runlist, - .chan = {{0,0,KEPLER_CHANNEL_GPFIFO_B}, gk104_fifo_gpfifo_new }, + .chid_nr = gm107_fifo_chid_nr, + .chid_ctor = gk110_fifo_chid_ctor, + .runq_nr = gf100_fifo_runq_nr, + .runl_ctor = gk104_fifo_runl_ctor, + .init = gk104_fifo_init, + .init_pbdmas = gk104_fifo_init_pbdmas, + .intr = gk104_fifo_intr, + .intr_mmu_fault_unit = gm107_fifo_intr_mmu_fault_unit, + .intr_ctxsw_timeout = gf100_fifo_intr_ctxsw_timeout, + .mmu_fault = &gm107_fifo_mmu_fault, + .nonstall = &gf100_fifo_nonstall, + .runl = &gm107_runl, + .runq = &gk208_runq, + .engn = &gk104_engn, + .engn_ce = &gk104_engn_ce, + .cgrp = {{ 0, 0, KEPLER_CHANNEL_GROUP_A }, &gk110_cgrp }, + .chan = {{ 0, 0, KEPLER_CHANNEL_GPFIFO_B }, &gm107_chan }, }; int gm107_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fifo **pfifo) { - return gk104_fifo_new_(&gm107_fifo, device, type, inst, 2048, pfifo); + return nvkm_fifo_new_(&gm107_fifo, device, type, inst, pfifo); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm200.c index 573658cb6c73..d92d1ac39191 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm200.c @@ -21,41 +21,46 @@ * * Authors: Ben Skeggs */ -#include "gk104.h" -#include "changk104.h" +#include "priv.h" #include <nvif/class.h> int -gm200_fifo_pbdma_nr(struct gk104_fifo *fifo) +gm200_fifo_runq_nr(struct nvkm_fifo *fifo) { - struct nvkm_device *device = fifo->base.engine.subdev.device; - return nvkm_rd32(device, 0x002004) & 0x000000ff; + return nvkm_rd32(fifo->engine.subdev.device, 0x002004) & 0x000000ff; } -const struct gk104_fifo_pbdma_func -gm200_fifo_pbdma = { - .nr = gm200_fifo_pbdma_nr, - .init = gk104_fifo_pbdma_init, - .init_timeout = gk208_fifo_pbdma_init_timeout, -}; +int +gm200_fifo_chid_nr(struct nvkm_fifo *fifo) +{ + return nvkm_rd32(fifo->engine.subdev.device, 0x002008); +} -static const struct gk104_fifo_func +static const struct nvkm_fifo_func gm200_fifo = { - .intr.fault = gm107_fifo_intr_fault, - .pbdma = &gm200_fifo_pbdma, - .fault.access = gk104_fifo_fault_access, - .fault.engine = gm107_fifo_fault_engine, - .fault.reason = gk104_fifo_fault_reason, - .fault.hubclient = gk104_fifo_fault_hubclient, - .fault.gpcclient = gk104_fifo_fault_gpcclient, - .runlist = &gm107_fifo_runlist, - .chan = {{0,0,MAXWELL_CHANNEL_GPFIFO_A}, gk104_fifo_gpfifo_new }, + .chid_nr = gm200_fifo_chid_nr, + .chid_ctor = gk110_fifo_chid_ctor, + .runq_nr = gm200_fifo_runq_nr, + .runl_ctor = gk104_fifo_runl_ctor, + .init = gk104_fifo_init, + .init_pbdmas = gk104_fifo_init_pbdmas, + .intr = gk104_fifo_intr, + .intr_mmu_fault_unit = gm107_fifo_intr_mmu_fault_unit, + .intr_ctxsw_timeout = gf100_fifo_intr_ctxsw_timeout, + .mmu_fault = &gm107_fifo_mmu_fault, + .nonstall = &gf100_fifo_nonstall, + .runl = &gm107_runl, + .runq = &gk208_runq, + .engn = &gk104_engn, + .engn_ce = &gk104_engn_ce, + .cgrp = {{ 0, 0, KEPLER_CHANNEL_GROUP_A }, &gk110_cgrp }, + .chan = {{ 0, 0, MAXWELL_CHANNEL_GPFIFO_A }, &gm107_chan }, }; int gm200_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fifo **pfifo) { - return gk104_fifo_new_(&gm200_fifo, device, type, inst, 4096, pfifo); + return nvkm_fifo_new_(&gm200_fifo, device, type, inst, pfifo); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm20b.c deleted file mode 100644 index 556c97e54f14..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm20b.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS 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 "gk104.h" -#include "changk104.h" - -#include <nvif/class.h> - -static const struct gk104_fifo_func -gm20b_fifo = { - .intr.fault = gm107_fifo_intr_fault, - .pbdma = &gm200_fifo_pbdma, - .fault.access = gk104_fifo_fault_access, - .fault.engine = gm107_fifo_fault_engine, - .fault.reason = gk104_fifo_fault_reason, - .fault.hubclient = gk104_fifo_fault_hubclient, - .fault.gpcclient = gk104_fifo_fault_gpcclient, - .runlist = &gm107_fifo_runlist, - .chan = {{0,0,MAXWELL_CHANNEL_GPFIFO_A}, gk104_fifo_gpfifo_new }, -}; - -int -gm20b_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, - struct nvkm_fifo **pfifo) -{ - return gk104_fifo_new_(&gm20b_fifo, device, type, inst, 512, pfifo); -} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gp100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gp100.c index 6b46b6b65b87..65bdb6a7d517 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gp100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gp100.c @@ -21,30 +21,54 @@ * * Authors: Ben Skeggs */ -#include "gk104.h" -#include "changk104.h" +#include "priv.h" +#include "runl.h" +#include <core/gpuobj.h> #include <subdev/fault.h> #include <nvif/class.h> -const struct nvkm_enum -gp100_fifo_fault_engine[] = { +static void +gp100_runl_insert_chan(struct nvkm_chan *chan, struct nvkm_memory *memory, u64 offset) +{ + nvkm_wo32(memory, offset + 0, chan->id | chan->runq << 14); + nvkm_wo32(memory, offset + 4, chan->inst->addr >> 12); +} + +static const struct nvkm_runl_func +gp100_runl = { + .runqs = 2, + .size = 8, + .update = nv50_runl_update, + .insert_cgrp = gk110_runl_insert_cgrp, + .insert_chan = gp100_runl_insert_chan, + .commit = gk104_runl_commit, + .wait = nv50_runl_wait, + .pending = gk104_runl_pending, + .block = gk104_runl_block, + .allow = gk104_runl_allow, + .fault_clear = gk104_runl_fault_clear, + .preempt_pending = gf100_runl_preempt_pending, +}; + +static const struct nvkm_enum +gp100_fifo_mmu_fault_engine[] = { { 0x01, "DISPLAY" }, { 0x03, "IFB", NULL, NVKM_ENGINE_IFB }, { 0x04, "BAR1", NULL, NVKM_SUBDEV_BAR }, { 0x05, "BAR2", NULL, NVKM_SUBDEV_INSTMEM }, - { 0x06, "HOST0", NULL, NVKM_ENGINE_FIFO }, - { 0x07, "HOST1", NULL, NVKM_ENGINE_FIFO }, - { 0x08, "HOST2", NULL, NVKM_ENGINE_FIFO }, - { 0x09, "HOST3", NULL, NVKM_ENGINE_FIFO }, - { 0x0a, "HOST4", NULL, NVKM_ENGINE_FIFO }, - { 0x0b, "HOST5", NULL, NVKM_ENGINE_FIFO }, - { 0x0c, "HOST6", NULL, NVKM_ENGINE_FIFO }, - { 0x0d, "HOST7", NULL, NVKM_ENGINE_FIFO }, - { 0x0e, "HOST8", NULL, NVKM_ENGINE_FIFO }, - { 0x0f, "HOST9", NULL, NVKM_ENGINE_FIFO }, - { 0x10, "HOST10", NULL, NVKM_ENGINE_FIFO }, + { 0x06, "HOST0" }, + { 0x07, "HOST1" }, + { 0x08, "HOST2" }, + { 0x09, "HOST3" }, + { 0x0a, "HOST4" }, + { 0x0b, "HOST5" }, + { 0x0c, "HOST6" }, + { 0x0d, "HOST7" }, + { 0x0e, "HOST8" }, + { 0x0f, "HOST9" }, + { 0x10, "HOST10" }, { 0x13, "PERF" }, { 0x17, "PMU" }, { 0x18, "PTP" }, @@ -52,8 +76,18 @@ gp100_fifo_fault_engine[] = { {} }; -void -gp100_fifo_intr_fault(struct nvkm_fifo *fifo, int unit) +static const struct nvkm_fifo_func_mmu_fault +gp100_fifo_mmu_fault = { + .recover = gf100_fifo_mmu_fault_recover, + .access = gf100_fifo_mmu_fault_access, + .engine = gp100_fifo_mmu_fault_engine, + .reason = gk104_fifo_mmu_fault_reason, + .hubclient = gk104_fifo_mmu_fault_hubclient, + .gpcclient = gk104_fifo_mmu_fault_gpcclient, +}; + +static void +gp100_fifo_intr_mmu_fault_unit(struct nvkm_fifo *fifo, int unit) { struct nvkm_device *device = fifo->engine.subdev.device; u32 inst = nvkm_rd32(device, 0x002800 + (unit * 0x10)); @@ -76,23 +110,30 @@ gp100_fifo_intr_fault(struct nvkm_fifo *fifo, int unit) nvkm_fifo_fault(fifo, &info); } -static const struct gk104_fifo_func +static const struct nvkm_fifo_func gp100_fifo = { - .intr.fault = gp100_fifo_intr_fault, - .pbdma = &gm200_fifo_pbdma, - .fault.access = gk104_fifo_fault_access, - .fault.engine = gp100_fifo_fault_engine, - .fault.reason = gk104_fifo_fault_reason, - .fault.hubclient = gk104_fifo_fault_hubclient, - .fault.gpcclient = gk104_fifo_fault_gpcclient, - .runlist = &gm107_fifo_runlist, - .chan = {{0,0,PASCAL_CHANNEL_GPFIFO_A}, gk104_fifo_gpfifo_new }, - .cgrp_force = true, + .chid_nr = gm200_fifo_chid_nr, + .chid_ctor = gk110_fifo_chid_ctor, + .runq_nr = gm200_fifo_runq_nr, + .runl_ctor = gk104_fifo_runl_ctor, + .init = gk104_fifo_init, + .init_pbdmas = gk104_fifo_init_pbdmas, + .intr = gk104_fifo_intr, + .intr_mmu_fault_unit = gp100_fifo_intr_mmu_fault_unit, + .intr_ctxsw_timeout = gf100_fifo_intr_ctxsw_timeout, + .mmu_fault = &gp100_fifo_mmu_fault, + .nonstall = &gf100_fifo_nonstall, + .runl = &gp100_runl, + .runq = &gk208_runq, + .engn = &gk104_engn, + .engn_ce = &gk104_engn_ce, + .cgrp = {{ 0, 0, KEPLER_CHANNEL_GROUP_A }, &gk110_cgrp, .force = true }, + .chan = {{ 0, 0, PASCAL_CHANNEL_GPFIFO_A }, &gm107_chan }, }; int gp100_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fifo **pfifo) { - return gk104_fifo_new_(&gp100_fifo, device, type, inst, 4096, pfifo); + return nvkm_fifo_new_(&gp100_fifo, device, type, inst, pfifo); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gp10b.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gp10b.c deleted file mode 100644 index 7a5929cb4d29..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gp10b.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS 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 "gk104.h" -#include "changk104.h" - -#include <nvif/class.h> - -static const struct gk104_fifo_func -gp10b_fifo = { - .intr.fault = gp100_fifo_intr_fault, - .pbdma = &gm200_fifo_pbdma, - .fault.access = gk104_fifo_fault_access, - .fault.engine = gp100_fifo_fault_engine, - .fault.reason = gk104_fifo_fault_reason, - .fault.hubclient = gk104_fifo_fault_hubclient, - .fault.gpcclient = gk104_fifo_fault_gpcclient, - .runlist = &gm107_fifo_runlist, - .chan = {{0,0,PASCAL_CHANNEL_GPFIFO_A}, gk104_fifo_gpfifo_new }, - .cgrp_force = true, -}; - -int -gp10b_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, - struct nvkm_fifo **pfifo) -{ - return gk104_fifo_new_(&gp10b_fifo, device, type, inst, 512, pfifo); -} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifog84.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifog84.c deleted file mode 100644 index 2121f517b1dd..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifog84.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2012 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. - * - * Authors: Ben Skeggs - */ -#include "channv50.h" - -#include <core/client.h> -#include <core/ramht.h> - -#include <nvif/class.h> -#include <nvif/cl826f.h> -#include <nvif/unpack.h> - -static int -g84_fifo_gpfifo_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, - void *data, u32 size, struct nvkm_object **pobject) -{ - struct nvkm_object *parent = oclass->parent; - union { - struct g82_channel_gpfifo_v0 v0; - } *args = data; - struct nv50_fifo *fifo = nv50_fifo(base); - struct nv50_fifo_chan *chan; - u64 ioffset, ilength; - int ret = -ENOSYS; - - nvif_ioctl(parent, "create channel gpfifo size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { - nvif_ioctl(parent, "create channel gpfifo vers %d vmm %llx " - "pushbuf %llx ioffset %016llx " - "ilength %08x\n", - args->v0.version, args->v0.vmm, args->v0.pushbuf, - args->v0.ioffset, args->v0.ilength); - if (!args->v0.pushbuf) - return -EINVAL; - } else - return ret; - - if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) - return -ENOMEM; - *pobject = &chan->base.object; - - ret = g84_fifo_chan_ctor(fifo, args->v0.vmm, args->v0.pushbuf, - oclass, chan); - if (ret) - return ret; - - args->v0.chid = chan->base.chid; - ioffset = args->v0.ioffset; - ilength = order_base_2(args->v0.ilength / 8); - - nvkm_kmap(chan->ramfc); - nvkm_wo32(chan->ramfc, 0x3c, 0x403f6078); - nvkm_wo32(chan->ramfc, 0x44, 0x01003fff); - nvkm_wo32(chan->ramfc, 0x48, chan->base.push->node->offset >> 4); - nvkm_wo32(chan->ramfc, 0x50, lower_32_bits(ioffset)); - nvkm_wo32(chan->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16)); - nvkm_wo32(chan->ramfc, 0x60, 0x7fffffff); - nvkm_wo32(chan->ramfc, 0x78, 0x00000000); - nvkm_wo32(chan->ramfc, 0x7c, 0x30000001); - nvkm_wo32(chan->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | - (4 << 24) /* SEARCH_FULL */ | - (chan->ramht->gpuobj->node->offset >> 4)); - nvkm_wo32(chan->ramfc, 0x88, chan->cache->addr >> 10); - nvkm_wo32(chan->ramfc, 0x98, chan->base.inst->addr >> 12); - nvkm_done(chan->ramfc); - return 0; -} - -const struct nvkm_fifo_chan_oclass -g84_fifo_gpfifo_oclass = { - .base.oclass = G82_CHANNEL_GPFIFO, - .base.minver = 0, - .base.maxver = 0, - .ctor = g84_fifo_gpfifo_new, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c deleted file mode 100644 index 4e78bbe3b94b..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c +++ /dev/null @@ -1,308 +0,0 @@ -/* - * Copyright 2012 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. - * - * Authors: Ben Skeggs - */ -#include "changf100.h" - -#include <core/client.h> -#include <core/gpuobj.h> -#include <subdev/fb.h> -#include <subdev/timer.h> - -#include <nvif/class.h> -#include <nvif/cl906f.h> -#include <nvif/unpack.h> - -int -gf100_fifo_chan_ntfy(struct nvkm_fifo_chan *chan, u32 type, - struct nvkm_event **pevent) -{ - switch (type) { - case NV906F_V0_NTFY_NON_STALL_INTERRUPT: - *pevent = &chan->fifo->uevent; - return 0; - case NV906F_V0_NTFY_KILLED: - *pevent = &chan->fifo->kevent; - return 0; - default: - break; - } - return -EINVAL; -} - -static u32 -gf100_fifo_gpfifo_engine_addr(struct nvkm_engine *engine) -{ - switch (engine->subdev.type) { - case NVKM_ENGINE_SW : return 0; - case NVKM_ENGINE_GR : return 0x0210; - case NVKM_ENGINE_CE : return 0x0230 + (engine->subdev.inst * 0x10); - case NVKM_ENGINE_MSPDEC: return 0x0250; - case NVKM_ENGINE_MSPPP : return 0x0260; - case NVKM_ENGINE_MSVLD : return 0x0270; - default: - WARN_ON(1); - return 0; - } -} - -static struct gf100_fifo_engn * -gf100_fifo_gpfifo_engine(struct gf100_fifo_chan *chan, struct nvkm_engine *engine) -{ - int engi = chan->base.fifo->func->engine_id(chan->base.fifo, engine); - if (engi >= 0) - return &chan->engn[engi]; - return NULL; -} - -static int -gf100_fifo_gpfifo_engine_fini(struct nvkm_fifo_chan *base, - struct nvkm_engine *engine, bool suspend) -{ - const u32 offset = gf100_fifo_gpfifo_engine_addr(engine); - struct gf100_fifo_chan *chan = gf100_fifo_chan(base); - struct nvkm_subdev *subdev = &chan->fifo->base.engine.subdev; - struct nvkm_device *device = subdev->device; - struct nvkm_gpuobj *inst = chan->base.inst; - int ret = 0; - - mutex_lock(&chan->fifo->base.mutex); - nvkm_wr32(device, 0x002634, chan->base.chid); - if (nvkm_msec(device, 2000, - if (nvkm_rd32(device, 0x002634) == chan->base.chid) - break; - ) < 0) { - nvkm_error(subdev, "channel %d [%s] kick timeout\n", - chan->base.chid, chan->base.object.client->name); - ret = -ETIMEDOUT; - } - mutex_unlock(&chan->fifo->base.mutex); - - if (ret && suspend) - return ret; - - if (offset) { - nvkm_kmap(inst); - nvkm_wo32(inst, offset + 0x00, 0x00000000); - nvkm_wo32(inst, offset + 0x04, 0x00000000); - nvkm_done(inst); - } - - return ret; -} - -static int -gf100_fifo_gpfifo_engine_init(struct nvkm_fifo_chan *base, - struct nvkm_engine *engine) -{ - const u32 offset = gf100_fifo_gpfifo_engine_addr(engine); - struct gf100_fifo_chan *chan = gf100_fifo_chan(base); - struct gf100_fifo_engn *engn = gf100_fifo_gpfifo_engine(chan, engine); - struct nvkm_gpuobj *inst = chan->base.inst; - - if (offset) { - nvkm_kmap(inst); - nvkm_wo32(inst, offset + 0x00, lower_32_bits(engn->vma->addr) | 4); - nvkm_wo32(inst, offset + 0x04, upper_32_bits(engn->vma->addr)); - nvkm_done(inst); - } - - return 0; -} - -static void -gf100_fifo_gpfifo_engine_dtor(struct nvkm_fifo_chan *base, - struct nvkm_engine *engine) -{ - struct gf100_fifo_chan *chan = gf100_fifo_chan(base); - struct gf100_fifo_engn *engn = gf100_fifo_gpfifo_engine(chan, engine); - nvkm_vmm_put(chan->base.vmm, &engn->vma); - nvkm_gpuobj_del(&engn->inst); -} - -static int -gf100_fifo_gpfifo_engine_ctor(struct nvkm_fifo_chan *base, - struct nvkm_engine *engine, - struct nvkm_object *object) -{ - struct gf100_fifo_chan *chan = gf100_fifo_chan(base); - struct gf100_fifo_engn *engn = gf100_fifo_gpfifo_engine(chan, engine); - int ret; - - if (!gf100_fifo_gpfifo_engine_addr(engine)) - return 0; - - ret = nvkm_object_bind(object, NULL, 0, &engn->inst); - if (ret) - return ret; - - ret = nvkm_vmm_get(chan->base.vmm, 12, engn->inst->size, &engn->vma); - if (ret) - return ret; - - return nvkm_memory_map(engn->inst, 0, chan->base.vmm, engn->vma, NULL, 0); -} - -static void -gf100_fifo_gpfifo_fini(struct nvkm_fifo_chan *base) -{ - struct gf100_fifo_chan *chan = gf100_fifo_chan(base); - struct gf100_fifo *fifo = chan->fifo; - struct nvkm_device *device = fifo->base.engine.subdev.device; - u32 coff = chan->base.chid * 8; - - if (!list_empty(&chan->head) && !chan->killed) { - gf100_fifo_runlist_remove(fifo, chan); - nvkm_mask(device, 0x003004 + coff, 0x00000001, 0x00000000); - gf100_fifo_runlist_commit(fifo); - } - - gf100_fifo_intr_engine(fifo); - - nvkm_wr32(device, 0x003000 + coff, 0x00000000); -} - -static void -gf100_fifo_gpfifo_init(struct nvkm_fifo_chan *base) -{ - struct gf100_fifo_chan *chan = gf100_fifo_chan(base); - struct gf100_fifo *fifo = chan->fifo; - struct nvkm_device *device = fifo->base.engine.subdev.device; - u32 addr = chan->base.inst->addr >> 12; - u32 coff = chan->base.chid * 8; - - nvkm_wr32(device, 0x003000 + coff, 0xc0000000 | addr); - - if (list_empty(&chan->head) && !chan->killed) { - gf100_fifo_runlist_insert(fifo, chan); - nvkm_wr32(device, 0x003004 + coff, 0x001f0001); - gf100_fifo_runlist_commit(fifo); - } -} - -static void * -gf100_fifo_gpfifo_dtor(struct nvkm_fifo_chan *base) -{ - return gf100_fifo_chan(base); -} - -static const struct nvkm_fifo_chan_func -gf100_fifo_gpfifo_func = { - .dtor = gf100_fifo_gpfifo_dtor, - .init = gf100_fifo_gpfifo_init, - .fini = gf100_fifo_gpfifo_fini, - .ntfy = gf100_fifo_chan_ntfy, - .engine_ctor = gf100_fifo_gpfifo_engine_ctor, - .engine_dtor = gf100_fifo_gpfifo_engine_dtor, - .engine_init = gf100_fifo_gpfifo_engine_init, - .engine_fini = gf100_fifo_gpfifo_engine_fini, -}; - -static int -gf100_fifo_gpfifo_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, - void *data, u32 size, struct nvkm_object **pobject) -{ - union { - struct fermi_channel_gpfifo_v0 v0; - } *args = data; - struct gf100_fifo *fifo = gf100_fifo(base); - struct nvkm_object *parent = oclass->parent; - struct gf100_fifo_chan *chan; - u64 usermem, ioffset, ilength; - int ret = -ENOSYS, i; - - nvif_ioctl(parent, "create channel gpfifo size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { - nvif_ioctl(parent, "create channel gpfifo vers %d vmm %llx " - "ioffset %016llx ilength %08x\n", - args->v0.version, args->v0.vmm, args->v0.ioffset, - args->v0.ilength); - if (!args->v0.vmm) - return -EINVAL; - } else - return ret; - - /* allocate channel */ - if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) - return -ENOMEM; - *pobject = &chan->base.object; - chan->fifo = fifo; - INIT_LIST_HEAD(&chan->head); - - ret = nvkm_fifo_chan_ctor(&gf100_fifo_gpfifo_func, &fifo->base, - 0x1000, 0x1000, true, args->v0.vmm, 0, - BIT(GF100_FIFO_ENGN_GR) | - BIT(GF100_FIFO_ENGN_MSPDEC) | - BIT(GF100_FIFO_ENGN_MSPPP) | - BIT(GF100_FIFO_ENGN_MSVLD) | - BIT(GF100_FIFO_ENGN_CE0) | - BIT(GF100_FIFO_ENGN_CE1) | - BIT(GF100_FIFO_ENGN_SW), - 1, fifo->user.bar->addr, 0x1000, - oclass, &chan->base); - if (ret) - return ret; - - args->v0.chid = chan->base.chid; - - /* clear channel control registers */ - - usermem = chan->base.chid * 0x1000; - ioffset = args->v0.ioffset; - ilength = order_base_2(args->v0.ilength / 8); - - nvkm_kmap(fifo->user.mem); - for (i = 0; i < 0x1000; i += 4) - nvkm_wo32(fifo->user.mem, usermem + i, 0x00000000); - nvkm_done(fifo->user.mem); - usermem = nvkm_memory_addr(fifo->user.mem) + usermem; - - /* RAMFC */ - nvkm_kmap(chan->base.inst); - nvkm_wo32(chan->base.inst, 0x08, lower_32_bits(usermem)); - nvkm_wo32(chan->base.inst, 0x0c, upper_32_bits(usermem)); - nvkm_wo32(chan->base.inst, 0x10, 0x0000face); - nvkm_wo32(chan->base.inst, 0x30, 0xfffff902); - nvkm_wo32(chan->base.inst, 0x48, lower_32_bits(ioffset)); - nvkm_wo32(chan->base.inst, 0x4c, upper_32_bits(ioffset) | - (ilength << 16)); - nvkm_wo32(chan->base.inst, 0x54, 0x00000002); - nvkm_wo32(chan->base.inst, 0x84, 0x20400000); - nvkm_wo32(chan->base.inst, 0x94, 0x30000001); - nvkm_wo32(chan->base.inst, 0x9c, 0x00000100); - nvkm_wo32(chan->base.inst, 0xa4, 0x1f1f1f1f); - nvkm_wo32(chan->base.inst, 0xa8, 0x1f1f1f1f); - nvkm_wo32(chan->base.inst, 0xac, 0x0000001f); - nvkm_wo32(chan->base.inst, 0xb8, 0xf8000000); - nvkm_wo32(chan->base.inst, 0xf8, 0x10003080); /* 0x002310 */ - nvkm_wo32(chan->base.inst, 0xfc, 0x10000010); /* 0x002350 */ - nvkm_done(chan->base.inst); - return 0; -} - -const struct nvkm_fifo_chan_oclass -gf100_fifo_gpfifo_oclass = { - .base.oclass = FERMI_CHANNEL_GPFIFO, - .base.minver = 0, - .base.maxver = 0, - .ctor = gf100_fifo_gpfifo_new, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c deleted file mode 100644 index 80456ec70e8a..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c +++ /dev/null @@ -1,361 +0,0 @@ -/* - * Copyright 2012 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. - * - * Authors: Ben Skeggs - */ -#include "changk104.h" -#include "cgrp.h" - -#include <core/client.h> -#include <core/gpuobj.h> -#include <subdev/fb.h> -#include <subdev/mmu.h> -#include <subdev/timer.h> - -#include <nvif/class.h> -#include <nvif/cla06f.h> -#include <nvif/unpack.h> - -int -gk104_fifo_gpfifo_kick_locked(struct gk104_fifo_chan *chan) -{ - struct gk104_fifo *fifo = chan->fifo; - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; - struct nvkm_device *device = subdev->device; - struct nvkm_client *client = chan->base.object.client; - struct nvkm_fifo_cgrp *cgrp = chan->cgrp; - int ret = 0; - - if (cgrp) - nvkm_wr32(device, 0x002634, cgrp->id | 0x01000000); - else - nvkm_wr32(device, 0x002634, chan->base.chid); - if (nvkm_msec(device, 2000, - if (!(nvkm_rd32(device, 0x002634) & 0x00100000)) - break; - ) < 0) { - nvkm_error(subdev, "%s %d [%s] kick timeout\n", - cgrp ? "tsg" : "channel", - cgrp ? cgrp->id : chan->base.chid, client->name); - nvkm_fifo_recover_chan(&fifo->base, chan->base.chid); - ret = -ETIMEDOUT; - } - return ret; -} - -int -gk104_fifo_gpfifo_kick(struct gk104_fifo_chan *chan) -{ - int ret; - mutex_lock(&chan->base.fifo->mutex); - ret = gk104_fifo_gpfifo_kick_locked(chan); - mutex_unlock(&chan->base.fifo->mutex); - return ret; -} - -static u32 -gk104_fifo_gpfifo_engine_addr(struct nvkm_engine *engine) -{ - switch (engine->subdev.type) { - case NVKM_ENGINE_SW : - case NVKM_ENGINE_CE : return 0; - case NVKM_ENGINE_GR : return 0x0210; - case NVKM_ENGINE_SEC : return 0x0220; - case NVKM_ENGINE_MSPDEC: return 0x0250; - case NVKM_ENGINE_MSPPP : return 0x0260; - case NVKM_ENGINE_MSVLD : return 0x0270; - case NVKM_ENGINE_VIC : return 0x0280; - case NVKM_ENGINE_MSENC : return 0x0290; - case NVKM_ENGINE_NVDEC : return 0x02100270; - case NVKM_ENGINE_NVENC : - if (engine->subdev.inst) - return 0x0210; - return 0x02100290; - default: - WARN_ON(1); - return 0; - } -} - -struct gk104_fifo_engn * -gk104_fifo_gpfifo_engine(struct gk104_fifo_chan *chan, struct nvkm_engine *engine) -{ - int engi = chan->base.fifo->func->engine_id(chan->base.fifo, engine); - if (engi >= 0) - return &chan->engn[engi]; - return NULL; -} - -static int -gk104_fifo_gpfifo_engine_fini(struct nvkm_fifo_chan *base, - struct nvkm_engine *engine, bool suspend) -{ - struct gk104_fifo_chan *chan = gk104_fifo_chan(base); - struct nvkm_gpuobj *inst = chan->base.inst; - u32 offset = gk104_fifo_gpfifo_engine_addr(engine); - int ret; - - ret = gk104_fifo_gpfifo_kick(chan); - if (ret && suspend) - return ret; - - if (offset) { - nvkm_kmap(inst); - nvkm_wo32(inst, (offset & 0xffff) + 0x00, 0x00000000); - nvkm_wo32(inst, (offset & 0xffff) + 0x04, 0x00000000); - if ((offset >>= 16)) { - nvkm_wo32(inst, offset + 0x00, 0x00000000); - nvkm_wo32(inst, offset + 0x04, 0x00000000); - } - nvkm_done(inst); - } - - return ret; -} - -static int -gk104_fifo_gpfifo_engine_init(struct nvkm_fifo_chan *base, - struct nvkm_engine *engine) -{ - struct gk104_fifo_chan *chan = gk104_fifo_chan(base); - struct gk104_fifo_engn *engn = gk104_fifo_gpfifo_engine(chan, engine); - struct nvkm_gpuobj *inst = chan->base.inst; - u32 offset = gk104_fifo_gpfifo_engine_addr(engine); - - if (offset) { - u32 datalo = lower_32_bits(engn->vma->addr) | 0x00000004; - u32 datahi = upper_32_bits(engn->vma->addr); - nvkm_kmap(inst); - nvkm_wo32(inst, (offset & 0xffff) + 0x00, datalo); - nvkm_wo32(inst, (offset & 0xffff) + 0x04, datahi); - if ((offset >>= 16)) { - nvkm_wo32(inst, offset + 0x00, datalo); - nvkm_wo32(inst, offset + 0x04, datahi); - } - nvkm_done(inst); - } - - return 0; -} - -void -gk104_fifo_gpfifo_engine_dtor(struct nvkm_fifo_chan *base, - struct nvkm_engine *engine) -{ - struct gk104_fifo_chan *chan = gk104_fifo_chan(base); - struct gk104_fifo_engn *engn = gk104_fifo_gpfifo_engine(chan, engine); - nvkm_vmm_put(chan->base.vmm, &engn->vma); - nvkm_gpuobj_del(&engn->inst); -} - -int -gk104_fifo_gpfifo_engine_ctor(struct nvkm_fifo_chan *base, - struct nvkm_engine *engine, - struct nvkm_object *object) -{ - struct gk104_fifo_chan *chan = gk104_fifo_chan(base); - struct gk104_fifo_engn *engn = gk104_fifo_gpfifo_engine(chan, engine); - int ret; - - if (!gk104_fifo_gpfifo_engine_addr(engine)) { - if (engine->subdev.type != NVKM_ENGINE_CE || - engine->subdev.device->card_type < GV100) - return 0; - } - - ret = nvkm_object_bind(object, NULL, 0, &engn->inst); - if (ret) - return ret; - - if (!gk104_fifo_gpfifo_engine_addr(engine)) - return 0; - - ret = nvkm_vmm_get(chan->base.vmm, 12, engn->inst->size, &engn->vma); - if (ret) - return ret; - - return nvkm_memory_map(engn->inst, 0, chan->base.vmm, engn->vma, NULL, 0); -} - -void -gk104_fifo_gpfifo_fini(struct nvkm_fifo_chan *base) -{ - struct gk104_fifo_chan *chan = gk104_fifo_chan(base); - struct gk104_fifo *fifo = chan->fifo; - struct nvkm_device *device = fifo->base.engine.subdev.device; - u32 coff = chan->base.chid * 8; - - if (!list_empty(&chan->head)) { - gk104_fifo_runlist_remove(fifo, chan); - nvkm_mask(device, 0x800004 + coff, 0x00000800, 0x00000800); - gk104_fifo_gpfifo_kick(chan); - gk104_fifo_runlist_update(fifo, chan->runl); - } - - nvkm_wr32(device, 0x800000 + coff, 0x00000000); -} - -void -gk104_fifo_gpfifo_init(struct nvkm_fifo_chan *base) -{ - struct gk104_fifo_chan *chan = gk104_fifo_chan(base); - struct gk104_fifo *fifo = chan->fifo; - struct nvkm_device *device = fifo->base.engine.subdev.device; - u32 addr = chan->base.inst->addr >> 12; - u32 coff = chan->base.chid * 8; - - nvkm_mask(device, 0x800004 + coff, 0x000f0000, chan->runl << 16); - nvkm_wr32(device, 0x800000 + coff, 0x80000000 | addr); - - if (list_empty(&chan->head) && !chan->killed) { - gk104_fifo_runlist_insert(fifo, chan); - nvkm_mask(device, 0x800004 + coff, 0x00000400, 0x00000400); - gk104_fifo_runlist_update(fifo, chan->runl); - nvkm_mask(device, 0x800004 + coff, 0x00000400, 0x00000400); - } -} - -void * -gk104_fifo_gpfifo_dtor(struct nvkm_fifo_chan *base) -{ - struct gk104_fifo_chan *chan = gk104_fifo_chan(base); - kfree(chan->cgrp); - return chan; -} - -const struct nvkm_fifo_chan_func -gk104_fifo_gpfifo_func = { - .dtor = gk104_fifo_gpfifo_dtor, - .init = gk104_fifo_gpfifo_init, - .fini = gk104_fifo_gpfifo_fini, - .ntfy = gf100_fifo_chan_ntfy, - .engine_ctor = gk104_fifo_gpfifo_engine_ctor, - .engine_dtor = gk104_fifo_gpfifo_engine_dtor, - .engine_init = gk104_fifo_gpfifo_engine_init, - .engine_fini = gk104_fifo_gpfifo_engine_fini, -}; - -static int -gk104_fifo_gpfifo_new_(struct gk104_fifo *fifo, u64 *runlists, u16 *chid, - u64 vmm, u64 ioffset, u64 ilength, u64 *inst, bool priv, - const struct nvkm_oclass *oclass, - struct nvkm_object **pobject) -{ - struct gk104_fifo_chan *chan; - int runlist = ffs(*runlists) -1, ret, i; - u64 usermem; - - if (!vmm || runlist < 0 || runlist >= fifo->runlist_nr) - return -EINVAL; - *runlists = BIT_ULL(runlist); - - /* Allocate the channel. */ - if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) - return -ENOMEM; - *pobject = &chan->base.object; - chan->fifo = fifo; - chan->runl = runlist; - INIT_LIST_HEAD(&chan->head); - - ret = nvkm_fifo_chan_ctor(&gk104_fifo_gpfifo_func, &fifo->base, - 0x1000, 0x1000, true, vmm, 0, fifo->runlist[runlist].engm_sw, - 1, fifo->user.bar->addr, 0x200, - oclass, &chan->base); - if (ret) - return ret; - - *chid = chan->base.chid; - *inst = chan->base.inst->addr; - - /* Hack to support GPUs where even individual channels should be - * part of a channel group. - */ - if (fifo->func->cgrp_force) { - if (!(chan->cgrp = kmalloc(sizeof(*chan->cgrp), GFP_KERNEL))) - return -ENOMEM; - chan->cgrp->id = chan->base.chid; - INIT_LIST_HEAD(&chan->cgrp->head); - INIT_LIST_HEAD(&chan->cgrp->chan); - chan->cgrp->chan_nr = 0; - } - - /* Clear channel control registers. */ - usermem = chan->base.chid * 0x200; - ilength = order_base_2(ilength / 8); - - nvkm_kmap(fifo->user.mem); - for (i = 0; i < 0x200; i += 4) - nvkm_wo32(fifo->user.mem, usermem + i, 0x00000000); - nvkm_done(fifo->user.mem); - usermem = nvkm_memory_addr(fifo->user.mem) + usermem; - - /* RAMFC */ - nvkm_kmap(chan->base.inst); - nvkm_wo32(chan->base.inst, 0x08, lower_32_bits(usermem)); - nvkm_wo32(chan->base.inst, 0x0c, upper_32_bits(usermem)); - nvkm_wo32(chan->base.inst, 0x10, 0x0000face); - nvkm_wo32(chan->base.inst, 0x30, 0xfffff902); - nvkm_wo32(chan->base.inst, 0x48, lower_32_bits(ioffset)); - nvkm_wo32(chan->base.inst, 0x4c, upper_32_bits(ioffset) | - (ilength << 16)); - nvkm_wo32(chan->base.inst, 0x84, 0x20400000); - nvkm_wo32(chan->base.inst, 0x94, 0x30000001); - nvkm_wo32(chan->base.inst, 0x9c, 0x00000100); - nvkm_wo32(chan->base.inst, 0xac, 0x0000001f); - nvkm_wo32(chan->base.inst, 0xe4, priv ? 0x00000020 : 0x00000000); - nvkm_wo32(chan->base.inst, 0xe8, chan->base.chid); - nvkm_wo32(chan->base.inst, 0xb8, 0xf8000000); - nvkm_wo32(chan->base.inst, 0xf8, 0x10003080); /* 0x002310 */ - nvkm_wo32(chan->base.inst, 0xfc, 0x10000010); /* 0x002350 */ - nvkm_done(chan->base.inst); - return 0; -} - -int -gk104_fifo_gpfifo_new(struct gk104_fifo *fifo, const struct nvkm_oclass *oclass, - void *data, u32 size, struct nvkm_object **pobject) -{ - struct nvkm_object *parent = oclass->parent; - union { - struct kepler_channel_gpfifo_a_v0 v0; - } *args = data; - int ret = -ENOSYS; - - nvif_ioctl(parent, "create channel gpfifo size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { - nvif_ioctl(parent, "create channel gpfifo vers %d vmm %llx " - "ioffset %016llx ilength %08x " - "runlist %016llx priv %d\n", - args->v0.version, args->v0.vmm, args->v0.ioffset, - args->v0.ilength, args->v0.runlist, args->v0.priv); - return gk104_fifo_gpfifo_new_(fifo, - &args->v0.runlist, - &args->v0.chid, - args->v0.vmm, - args->v0.ioffset, - args->v0.ilength, - &args->v0.inst, - args->v0.priv, - oclass, pobject); - } - - return ret; -} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogv100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogv100.c deleted file mode 100644 index 428f9b41165c..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogv100.c +++ /dev/null @@ -1,241 +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. - */ -#include "changk104.h" -#include "cgrp.h" - -#include <core/client.h> -#include <core/gpuobj.h> - -#include <nvif/clc36f.h> -#include <nvif/unpack.h> - -static u32 -gv100_fifo_gpfifo_submit_token(struct nvkm_fifo_chan *chan) -{ - return chan->chid; -} - -static int -gv100_fifo_gpfifo_engine_valid(struct gk104_fifo_chan *chan, bool ce, bool valid) -{ - struct nvkm_subdev *subdev = &chan->base.fifo->engine.subdev; - struct nvkm_device *device = subdev->device; - const u32 mask = ce ? 0x00020000 : 0x00010000; - const u32 data = valid ? mask : 0x00000000; - int ret; - - /* Block runlist to prevent the channel from being rescheduled. */ - mutex_lock(&chan->fifo->base.mutex); - nvkm_mask(device, 0x002630, BIT(chan->runl), BIT(chan->runl)); - - /* Preempt the channel. */ - ret = gk104_fifo_gpfifo_kick_locked(chan); - if (ret == 0) { - /* Update engine context validity. */ - nvkm_kmap(chan->base.inst); - nvkm_mo32(chan->base.inst, 0x0ac, mask, data); - nvkm_done(chan->base.inst); - } - - /* Resume runlist. */ - nvkm_mask(device, 0x002630, BIT(chan->runl), 0); - mutex_unlock(&chan->fifo->base.mutex); - return ret; -} - -int -gv100_fifo_gpfifo_engine_fini(struct nvkm_fifo_chan *base, - struct nvkm_engine *engine, bool suspend) -{ - struct gk104_fifo_chan *chan = gk104_fifo_chan(base); - struct nvkm_gpuobj *inst = chan->base.inst; - int ret; - - if (engine->subdev.type == NVKM_ENGINE_CE) { - ret = gv100_fifo_gpfifo_engine_valid(chan, true, false); - if (ret && suspend) - return ret; - - nvkm_kmap(inst); - nvkm_wo32(chan->base.inst, 0x220, 0x00000000); - nvkm_wo32(chan->base.inst, 0x224, 0x00000000); - nvkm_done(inst); - return ret; - } - - ret = gv100_fifo_gpfifo_engine_valid(chan, false, false); - if (ret && suspend) - return ret; - - nvkm_kmap(inst); - nvkm_wo32(inst, 0x0210, 0x00000000); - nvkm_wo32(inst, 0x0214, 0x00000000); - nvkm_done(inst); - return ret; -} - -int -gv100_fifo_gpfifo_engine_init(struct nvkm_fifo_chan *base, - struct nvkm_engine *engine) -{ - struct gk104_fifo_chan *chan = gk104_fifo_chan(base); - struct gk104_fifo_engn *engn = gk104_fifo_gpfifo_engine(chan, engine); - struct nvkm_gpuobj *inst = chan->base.inst; - - if (engine->subdev.type == NVKM_ENGINE_CE) { - const u64 bar2 = nvkm_memory_bar2(engn->inst->memory); - - nvkm_kmap(inst); - nvkm_wo32(chan->base.inst, 0x220, lower_32_bits(bar2)); - nvkm_wo32(chan->base.inst, 0x224, upper_32_bits(bar2)); - nvkm_done(inst); - - return gv100_fifo_gpfifo_engine_valid(chan, true, true); - } - - nvkm_kmap(inst); - nvkm_wo32(inst, 0x210, lower_32_bits(engn->vma->addr) | 0x00000004); - nvkm_wo32(inst, 0x214, upper_32_bits(engn->vma->addr)); - nvkm_done(inst); - - return gv100_fifo_gpfifo_engine_valid(chan, false, true); -} - -static const struct nvkm_fifo_chan_func -gv100_fifo_gpfifo = { - .dtor = gk104_fifo_gpfifo_dtor, - .init = gk104_fifo_gpfifo_init, - .fini = gk104_fifo_gpfifo_fini, - .ntfy = gf100_fifo_chan_ntfy, - .engine_ctor = gk104_fifo_gpfifo_engine_ctor, - .engine_dtor = gk104_fifo_gpfifo_engine_dtor, - .engine_init = gv100_fifo_gpfifo_engine_init, - .engine_fini = gv100_fifo_gpfifo_engine_fini, - .submit_token = gv100_fifo_gpfifo_submit_token, -}; - -int -gv100_fifo_gpfifo_new_(const struct nvkm_fifo_chan_func *func, - struct gk104_fifo *fifo, u64 *runlists, u16 *chid, - u64 vmm, u64 ioffset, u64 ilength, u64 *inst, bool priv, - u32 *token, const struct nvkm_oclass *oclass, - struct nvkm_object **pobject) -{ - struct gk104_fifo_chan *chan; - int runlist = ffs(*runlists) -1, ret, i; - u64 usermem; - - if (!vmm || runlist < 0 || runlist >= fifo->runlist_nr) - return -EINVAL; - *runlists = BIT_ULL(runlist); - - /* Allocate the channel. */ - if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) - return -ENOMEM; - *pobject = &chan->base.object; - chan->fifo = fifo; - chan->runl = runlist; - INIT_LIST_HEAD(&chan->head); - - ret = nvkm_fifo_chan_ctor(func, &fifo->base, 0x1000, 0x1000, true, vmm, - 0, fifo->runlist[runlist].engm, 1, fifo->user.bar->addr, 0x200, - oclass, &chan->base); - if (ret) - return ret; - - *chid = chan->base.chid; - *inst = chan->base.inst->addr; - *token = chan->base.func->submit_token(&chan->base); - - /* Hack to support GPUs where even individual channels should be - * part of a channel group. - */ - if (fifo->func->cgrp_force) { - if (!(chan->cgrp = kmalloc(sizeof(*chan->cgrp), GFP_KERNEL))) - return -ENOMEM; - chan->cgrp->id = chan->base.chid; - INIT_LIST_HEAD(&chan->cgrp->head); - INIT_LIST_HEAD(&chan->cgrp->chan); - chan->cgrp->chan_nr = 0; - } - - /* Clear channel control registers. */ - usermem = chan->base.chid * 0x200; - ilength = order_base_2(ilength / 8); - - nvkm_kmap(fifo->user.mem); - for (i = 0; i < 0x200; i += 4) - nvkm_wo32(fifo->user.mem, usermem + i, 0x00000000); - nvkm_done(fifo->user.mem); - usermem = nvkm_memory_addr(fifo->user.mem) + usermem; - - /* RAMFC */ - nvkm_kmap(chan->base.inst); - nvkm_wo32(chan->base.inst, 0x008, lower_32_bits(usermem)); - nvkm_wo32(chan->base.inst, 0x00c, upper_32_bits(usermem)); - nvkm_wo32(chan->base.inst, 0x010, 0x0000face); - nvkm_wo32(chan->base.inst, 0x030, 0x7ffff902); - nvkm_wo32(chan->base.inst, 0x048, lower_32_bits(ioffset)); - nvkm_wo32(chan->base.inst, 0x04c, upper_32_bits(ioffset) | - (ilength << 16)); - nvkm_wo32(chan->base.inst, 0x084, 0x20400000); - nvkm_wo32(chan->base.inst, 0x094, 0x30000001); - nvkm_wo32(chan->base.inst, 0x0e4, priv ? 0x00000020 : 0x00000000); - nvkm_wo32(chan->base.inst, 0x0e8, chan->base.chid); - nvkm_wo32(chan->base.inst, 0x0f4, 0x00001000); - nvkm_wo32(chan->base.inst, 0x0f8, 0x10003080); - nvkm_mo32(chan->base.inst, 0x218, 0x00000000, 0x00000000); - nvkm_done(chan->base.inst); - return 0; -} - -int -gv100_fifo_gpfifo_new(struct gk104_fifo *fifo, const struct nvkm_oclass *oclass, - void *data, u32 size, struct nvkm_object **pobject) -{ - struct nvkm_object *parent = oclass->parent; - union { - struct volta_channel_gpfifo_a_v0 v0; - } *args = data; - int ret = -ENOSYS; - - nvif_ioctl(parent, "create channel gpfifo size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { - nvif_ioctl(parent, "create channel gpfifo vers %d vmm %llx " - "ioffset %016llx ilength %08x " - "runlist %016llx priv %d\n", - args->v0.version, args->v0.vmm, args->v0.ioffset, - args->v0.ilength, args->v0.runlist, args->v0.priv); - return gv100_fifo_gpfifo_new_(&gv100_fifo_gpfifo, fifo, - &args->v0.runlist, - &args->v0.chid, - args->v0.vmm, - args->v0.ioffset, - args->v0.ilength, - &args->v0.inst, - args->v0.priv, - &args->v0.token, - oclass, pobject); - } - - return ret; -} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifonv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifonv50.c deleted file mode 100644 index d8f28ec1e4a8..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifonv50.c +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2012 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. - * - * Authors: Ben Skeggs - */ -#include "channv50.h" - -#include <core/client.h> -#include <core/ramht.h> - -#include <nvif/class.h> -#include <nvif/cl506f.h> -#include <nvif/unpack.h> - -static int -nv50_fifo_gpfifo_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, - void *data, u32 size, struct nvkm_object **pobject) -{ - struct nvkm_object *parent = oclass->parent; - union { - struct nv50_channel_gpfifo_v0 v0; - } *args = data; - struct nv50_fifo *fifo = nv50_fifo(base); - struct nv50_fifo_chan *chan; - u64 ioffset, ilength; - int ret = -ENOSYS; - - nvif_ioctl(parent, "create channel gpfifo size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { - nvif_ioctl(parent, "create channel gpfifo vers %d vmm %llx " - "pushbuf %llx ioffset %016llx " - "ilength %08x\n", - args->v0.version, args->v0.vmm, args->v0.pushbuf, - args->v0.ioffset, args->v0.ilength); - if (!args->v0.pushbuf) - return -EINVAL; - } else - return ret; - - if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) - return -ENOMEM; - *pobject = &chan->base.object; - - ret = nv50_fifo_chan_ctor(fifo, args->v0.vmm, args->v0.pushbuf, - oclass, chan); - if (ret) - return ret; - - args->v0.chid = chan->base.chid; - ioffset = args->v0.ioffset; - ilength = order_base_2(args->v0.ilength / 8); - - nvkm_kmap(chan->ramfc); - nvkm_wo32(chan->ramfc, 0x3c, 0x403f6078); - nvkm_wo32(chan->ramfc, 0x44, 0x01003fff); - nvkm_wo32(chan->ramfc, 0x48, chan->base.push->node->offset >> 4); - nvkm_wo32(chan->ramfc, 0x50, lower_32_bits(ioffset)); - nvkm_wo32(chan->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16)); - nvkm_wo32(chan->ramfc, 0x60, 0x7fffffff); - nvkm_wo32(chan->ramfc, 0x78, 0x00000000); - nvkm_wo32(chan->ramfc, 0x7c, 0x30000001); - nvkm_wo32(chan->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | - (4 << 24) /* SEARCH_FULL */ | - (chan->ramht->gpuobj->node->offset >> 4)); - nvkm_done(chan->ramfc); - return 0; -} - -const struct nvkm_fifo_chan_oclass -nv50_fifo_gpfifo_oclass = { - .base.oclass = NV50_CHANNEL_GPFIFO, - .base.minver = 0, - .base.maxver = 0, - .ctor = nv50_fifo_gpfifo_new, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifotu102.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifotu102.c deleted file mode 100644 index 99aafa103a31..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifotu102.c +++ /dev/null @@ -1,81 +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. - */ -#include "changk104.h" -#include "cgrp.h" - -#include <core/client.h> -#include <core/gpuobj.h> - -#include <nvif/clc36f.h> -#include <nvif/unpack.h> - -static u32 -tu102_fifo_gpfifo_submit_token(struct nvkm_fifo_chan *base) -{ - struct gk104_fifo_chan *chan = gk104_fifo_chan(base); - return (chan->runl << 16) | chan->base.chid; -} - -static const struct nvkm_fifo_chan_func -tu102_fifo_gpfifo = { - .dtor = gk104_fifo_gpfifo_dtor, - .init = gk104_fifo_gpfifo_init, - .fini = gk104_fifo_gpfifo_fini, - .ntfy = gf100_fifo_chan_ntfy, - .engine_ctor = gk104_fifo_gpfifo_engine_ctor, - .engine_dtor = gk104_fifo_gpfifo_engine_dtor, - .engine_init = gv100_fifo_gpfifo_engine_init, - .engine_fini = gv100_fifo_gpfifo_engine_fini, - .submit_token = tu102_fifo_gpfifo_submit_token, -}; - -int -tu102_fifo_gpfifo_new(struct gk104_fifo *fifo, const struct nvkm_oclass *oclass, - void *data, u32 size, struct nvkm_object **pobject) -{ - struct nvkm_object *parent = oclass->parent; - union { - struct volta_channel_gpfifo_a_v0 v0; - } *args = data; - int ret = -ENOSYS; - - nvif_ioctl(parent, "create channel gpfifo size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { - nvif_ioctl(parent, "create channel gpfifo vers %d vmm %llx " - "ioffset %016llx ilength %08x " - "runlist %016llx priv %d\n", - args->v0.version, args->v0.vmm, args->v0.ioffset, - args->v0.ilength, args->v0.runlist, args->v0.priv); - return gv100_fifo_gpfifo_new_(&tu102_fifo_gpfifo, fifo, - &args->v0.runlist, - &args->v0.chid, - args->v0.vmm, - args->v0.ioffset, - args->v0.ilength, - &args->v0.inst, - args->v0.priv, - &args->v0.token, - oclass, pobject); - } - - return ret; -} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gv100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gv100.c index faf0fe9f704c..33066c8cdc64 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gv100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gv100.c @@ -19,32 +19,180 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ -#include "gk104.h" +#include "priv.h" +#include "chan.h" +#include "chid.h" #include "cgrp.h" -#include "changk104.h" -#include "user.h" +#include "runl.h" +#include "runq.h" #include <core/gpuobj.h> +#include <subdev/mmu.h> #include <nvif/class.h> +static u32 +gv100_chan_doorbell_handle(struct nvkm_chan *chan) +{ + return chan->id; +} + +static int +gv100_chan_ramfc_write(struct nvkm_chan *chan, u64 offset, u64 length, u32 devm, bool priv) +{ + const u64 userd = nvkm_memory_addr(chan->userd.mem) + chan->userd.base; + const u32 limit2 = ilog2(length / 8); + + nvkm_kmap(chan->inst); + nvkm_wo32(chan->inst, 0x008, lower_32_bits(userd)); + nvkm_wo32(chan->inst, 0x00c, upper_32_bits(userd)); + nvkm_wo32(chan->inst, 0x010, 0x0000face); + nvkm_wo32(chan->inst, 0x030, 0x7ffff902); + nvkm_wo32(chan->inst, 0x048, lower_32_bits(offset)); + nvkm_wo32(chan->inst, 0x04c, upper_32_bits(offset) | (limit2 << 16)); + nvkm_wo32(chan->inst, 0x084, 0x20400000); + nvkm_wo32(chan->inst, 0x094, 0x30000000 | devm); + nvkm_wo32(chan->inst, 0x0e4, priv ? 0x00000020 : 0x00000000); + nvkm_wo32(chan->inst, 0x0e8, chan->id); + nvkm_wo32(chan->inst, 0x0f4, 0x00001000 | (priv ? 0x00000100 : 0x00000000)); + nvkm_wo32(chan->inst, 0x0f8, 0x10003080); + nvkm_mo32(chan->inst, 0x218, 0x00000000, 0x00000000); + nvkm_done(chan->inst); + return 0; +} + +const struct nvkm_chan_func_ramfc +gv100_chan_ramfc = { + .write = gv100_chan_ramfc_write, + .devm = 0xfff, + .priv = true, +}; + +const struct nvkm_chan_func_userd +gv100_chan_userd = { + .bar = -1, + .size = 0x200, + .clear = gf100_chan_userd_clear, +}; + +static const struct nvkm_chan_func +gv100_chan = { + .inst = &gf100_chan_inst, + .userd = &gv100_chan_userd, + .ramfc = &gv100_chan_ramfc, + .bind = gk104_chan_bind_inst, + .unbind = gk104_chan_unbind, + .start = gk104_chan_start, + .stop = gk104_chan_stop, + .preempt = gk110_chan_preempt, + .doorbell_handle = gv100_chan_doorbell_handle, +}; + +void +gv100_ectx_bind(struct nvkm_engn *engn, struct nvkm_cctx *cctx, struct nvkm_chan *chan) +{ + u64 addr = 0ULL; + + if (cctx) { + addr = cctx->vctx->vma->addr; + addr |= 4ULL; + } + + nvkm_kmap(chan->inst); + nvkm_wo32(chan->inst, 0x210, lower_32_bits(addr)); + nvkm_wo32(chan->inst, 0x214, upper_32_bits(addr)); + nvkm_mo32(chan->inst, 0x0ac, 0x00010000, cctx ? 0x00010000 : 0x00000000); + nvkm_done(chan->inst); +} + +const struct nvkm_engn_func +gv100_engn = { + .chsw = gk104_engn_chsw, + .cxid = gk104_engn_cxid, + .ctor = gk104_ectx_ctor, + .bind = gv100_ectx_bind, +}; + +void +gv100_ectx_ce_bind(struct nvkm_engn *engn, struct nvkm_cctx *cctx, struct nvkm_chan *chan) +{ + const u64 bar2 = cctx ? nvkm_memory_bar2(cctx->vctx->inst->memory) : 0ULL; + + nvkm_kmap(chan->inst); + nvkm_wo32(chan->inst, 0x220, lower_32_bits(bar2)); + nvkm_wo32(chan->inst, 0x224, upper_32_bits(bar2)); + nvkm_mo32(chan->inst, 0x0ac, 0x00020000, cctx ? 0x00020000 : 0x00000000); + nvkm_done(chan->inst); +} + +int +gv100_ectx_ce_ctor(struct nvkm_engn *engn, struct nvkm_vctx *vctx) +{ + if (nvkm_memory_bar2(vctx->inst->memory) == ~0ULL) + return -EFAULT; + + return 0; +} + +const struct nvkm_engn_func +gv100_engn_ce = { + .chsw = gk104_engn_chsw, + .cxid = gk104_engn_cxid, + .ctor = gv100_ectx_ce_ctor, + .bind = gv100_ectx_ce_bind, +}; + +static bool +gv100_runq_intr_1_ctxnotvalid(struct nvkm_runq *runq, int chid) +{ + struct nvkm_fifo *fifo = runq->fifo; + struct nvkm_device *device = fifo->engine.subdev.device; + struct nvkm_chan *chan; + unsigned long flags; + + RUNQ_ERROR(runq, "CTXNOTVALID chid:%d", chid); + + chan = nvkm_chan_get_chid(&fifo->engine, chid, &flags); + if (WARN_ON_ONCE(!chan)) + return false; + + nvkm_chan_error(chan, true); + nvkm_chan_put(&chan, flags); + + nvkm_mask(device, 0x0400ac + (runq->id * 0x2000), 0x00030000, 0x00030000); + nvkm_wr32(device, 0x040148 + (runq->id * 0x2000), 0x80000000); + return true; +} + +const struct nvkm_runq_func +gv100_runq = { + .init = gk208_runq_init, + .intr = gk104_runq_intr, + .intr_0_names = gk104_runq_intr_0_names, + .intr_1_ctxnotvalid = gv100_runq_intr_1_ctxnotvalid, + .idle = gk104_runq_idle, +}; + +void +gv100_runl_preempt(struct nvkm_runl *runl) +{ + nvkm_wr32(runl->fifo->engine.subdev.device, 0x002638, BIT(runl->id)); +} + void -gv100_fifo_runlist_chan(struct gk104_fifo_chan *chan, - struct nvkm_memory *memory, u32 offset) +gv100_runl_insert_chan(struct nvkm_chan *chan, struct nvkm_memory *memory, u64 offset) { - struct nvkm_memory *usermem = chan->fifo->user.mem; - const u64 user = nvkm_memory_addr(usermem) + (chan->base.chid * 0x200); - const u64 inst = chan->base.inst->addr; + const u64 user = nvkm_memory_addr(chan->userd.mem) + chan->userd.base; + const u64 inst = chan->inst->addr; - nvkm_wo32(memory, offset + 0x0, lower_32_bits(user)); + nvkm_wo32(memory, offset + 0x0, lower_32_bits(user) | chan->runq << 1); nvkm_wo32(memory, offset + 0x4, upper_32_bits(user)); - nvkm_wo32(memory, offset + 0x8, lower_32_bits(inst) | chan->base.chid); + nvkm_wo32(memory, offset + 0x8, lower_32_bits(inst) | chan->id); nvkm_wo32(memory, offset + 0xc, upper_32_bits(inst)); } void -gv100_fifo_runlist_cgrp(struct nvkm_fifo_cgrp *cgrp, - struct nvkm_memory *memory, u32 offset) +gv100_runl_insert_cgrp(struct nvkm_cgrp *cgrp, struct nvkm_memory *memory, u64 offset) { nvkm_wo32(memory, offset + 0x0, (128 << 24) | (3 << 16) | 0x00000001); nvkm_wo32(memory, offset + 0x4, cgrp->chan_nr); @@ -52,16 +200,24 @@ gv100_fifo_runlist_cgrp(struct nvkm_fifo_cgrp *cgrp, nvkm_wo32(memory, offset + 0xc, 0x00000000); } -static const struct gk104_fifo_runlist_func -gv100_fifo_runlist = { +static const struct nvkm_runl_func +gv100_runl = { + .runqs = 2, .size = 16, - .cgrp = gv100_fifo_runlist_cgrp, - .chan = gv100_fifo_runlist_chan, - .commit = gk104_fifo_runlist_commit, + .update = nv50_runl_update, + .insert_cgrp = gv100_runl_insert_cgrp, + .insert_chan = gv100_runl_insert_chan, + .commit = gk104_runl_commit, + .wait = nv50_runl_wait, + .pending = gk104_runl_pending, + .block = gk104_runl_block, + .allow = gk104_runl_allow, + .preempt = gv100_runl_preempt, + .preempt_pending = gf100_runl_preempt_pending, }; const struct nvkm_enum -gv100_fifo_fault_gpcclient[] = { +gv100_fifo_mmu_fault_gpcclient[] = { { 0x00, "T1_0" }, { 0x01, "T1_1" }, { 0x02, "T1_2" }, @@ -163,7 +319,7 @@ gv100_fifo_fault_gpcclient[] = { }; const struct nvkm_enum -gv100_fifo_fault_hubclient[] = { +gv100_fifo_mmu_fault_hubclient[] = { { 0x00, "VIP" }, { 0x01, "CE0" }, { 0x02, "CE1" }, @@ -225,7 +381,7 @@ gv100_fifo_fault_hubclient[] = { }; const struct nvkm_enum -gv100_fifo_fault_reason[] = { +gv100_fifo_mmu_fault_reason[] = { { 0x00, "PDE" }, { 0x01, "PDE_SIZE" }, { 0x02, "PTE" }, @@ -246,7 +402,7 @@ gv100_fifo_fault_reason[] = { }; static const struct nvkm_enum -gv100_fifo_fault_engine[] = { +gv100_fifo_mmu_fault_engine[] = { { 0x01, "DISPLAY" }, { 0x03, "PTP" }, { 0x04, "BAR1", NULL, NVKM_SUBDEV_BAR }, @@ -273,7 +429,7 @@ gv100_fifo_fault_engine[] = { }; const struct nvkm_enum -gv100_fifo_fault_access[] = { +gv100_fifo_mmu_fault_access[] = { { 0x0, "VIRT_READ" }, { 0x1, "VIRT_WRITE" }, { 0x2, "VIRT_ATOMIC" }, @@ -286,23 +442,51 @@ gv100_fifo_fault_access[] = { {} }; -static const struct gk104_fifo_func +static const struct nvkm_fifo_func_mmu_fault +gv100_fifo_mmu_fault = { + .recover = gf100_fifo_mmu_fault_recover, + .access = gv100_fifo_mmu_fault_access, + .engine = gv100_fifo_mmu_fault_engine, + .reason = gv100_fifo_mmu_fault_reason, + .hubclient = gv100_fifo_mmu_fault_hubclient, + .gpcclient = gv100_fifo_mmu_fault_gpcclient, +}; + +static void +gv100_fifo_intr_ctxsw_timeout(struct nvkm_fifo *fifo, u32 engm) +{ + struct nvkm_runl *runl; + struct nvkm_engn *engn; + + nvkm_runl_foreach(runl, fifo) { + nvkm_runl_foreach_engn_cond(engn, runl, engm & BIT(engn->id)) + nvkm_runl_rc_engn(runl, engn); + } +} + +static const struct nvkm_fifo_func gv100_fifo = { - .pbdma = &gm200_fifo_pbdma, - .fault.access = gv100_fifo_fault_access, - .fault.engine = gv100_fifo_fault_engine, - .fault.reason = gv100_fifo_fault_reason, - .fault.hubclient = gv100_fifo_fault_hubclient, - .fault.gpcclient = gv100_fifo_fault_gpcclient, - .runlist = &gv100_fifo_runlist, - .user = {{-1,-1,VOLTA_USERMODE_A }, gv100_fifo_user_new }, - .chan = {{ 0, 0,VOLTA_CHANNEL_GPFIFO_A}, gv100_fifo_gpfifo_new }, - .cgrp_force = true, + .chid_nr = gm200_fifo_chid_nr, + .chid_ctor = gk110_fifo_chid_ctor, + .runq_nr = gm200_fifo_runq_nr, + .runl_ctor = gk104_fifo_runl_ctor, + .init = gk104_fifo_init, + .init_pbdmas = gk104_fifo_init_pbdmas, + .intr = gk104_fifo_intr, + .intr_ctxsw_timeout = gv100_fifo_intr_ctxsw_timeout, + .mmu_fault = &gv100_fifo_mmu_fault, + .nonstall = &gf100_fifo_nonstall, + .runl = &gv100_runl, + .runq = &gv100_runq, + .engn = &gv100_engn, + .engn_ce = &gv100_engn_ce, + .cgrp = {{ 0, 0, KEPLER_CHANNEL_GROUP_A }, &gk110_cgrp, .force = true }, + .chan = {{ 0, 0, VOLTA_CHANNEL_GPFIFO_A }, &gv100_chan }, }; int gv100_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fifo **pfifo) { - return gk104_fifo_new_(&gv100_fifo, device, type, inst, 4096, pfifo); + return nvkm_fifo_new_(&gv100_fifo, device, type, inst, pfifo); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c index c6730c124769..674faf002b20 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c @@ -21,38 +21,201 @@ * * Authors: Ben Skeggs */ -#include "nv04.h" -#include "channv04.h" +#include "priv.h" +#include "cgrp.h" +#include "chan.h" +#include "chid.h" +#include "runl.h" + #include "regsnv04.h" -#include <core/client.h> #include <core/ramht.h> #include <subdev/instmem.h> +#include <subdev/mc.h> #include <subdev/timer.h> #include <engine/sw.h> -static const struct nv04_fifo_ramfc -nv04_fifo_ramfc[] = { - { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT }, - { 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET }, - { 16, 0, 0x08, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE }, - { 16, 16, 0x08, 0, NV04_PFIFO_CACHE1_DMA_DCOUNT }, - { 32, 0, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_STATE }, - { 32, 0, 0x10, 0, NV04_PFIFO_CACHE1_DMA_FETCH }, - { 32, 0, 0x14, 0, NV04_PFIFO_CACHE1_ENGINE }, - { 32, 0, 0x18, 0, NV04_PFIFO_CACHE1_PULL1 }, - {} +#include <nvif/class.h> + +void +nv04_chan_stop(struct nvkm_chan *chan) +{ + struct nvkm_fifo *fifo = chan->cgrp->runl->fifo; + struct nvkm_device *device = fifo->engine.subdev.device; + struct nvkm_memory *fctx = device->imem->ramfc; + const struct nvkm_ramfc_layout *c; + unsigned long flags; + u32 data = chan->ramfc_offset; + u32 chid; + + /* prevent fifo context switches */ + spin_lock_irqsave(&fifo->lock, flags); + nvkm_wr32(device, NV03_PFIFO_CACHES, 0); + + /* if this channel is active, replace it with a null context */ + chid = nvkm_rd32(device, NV03_PFIFO_CACHE1_PUSH1) & fifo->chid->mask; + if (chid == chan->id) { + nvkm_mask(device, NV04_PFIFO_CACHE1_DMA_PUSH, 0x00000001, 0); + nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH0, 0); + nvkm_mask(device, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0); + + c = chan->func->ramfc->layout; + nvkm_kmap(fctx); + do { + u32 rm = ((1ULL << c->bits) - 1) << c->regs; + u32 cm = ((1ULL << c->bits) - 1) << c->ctxs; + u32 rv = (nvkm_rd32(device, c->regp) & rm) >> c->regs; + u32 cv = (nvkm_ro32(fctx, c->ctxp + data) & ~cm); + nvkm_wo32(fctx, c->ctxp + data, cv | (rv << c->ctxs)); + } while ((++c)->bits); + nvkm_done(fctx); + + c = chan->func->ramfc->layout; + do { + nvkm_wr32(device, c->regp, 0x00000000); + } while ((++c)->bits); + + nvkm_wr32(device, NV03_PFIFO_CACHE1_GET, 0); + nvkm_wr32(device, NV03_PFIFO_CACHE1_PUT, 0); + nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, fifo->chid->mask); + nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH0, 1); + nvkm_wr32(device, NV04_PFIFO_CACHE1_PULL0, 1); + } + + /* restore normal operation, after disabling dma mode */ + nvkm_mask(device, NV04_PFIFO_MODE, BIT(chan->id), 0); + nvkm_wr32(device, NV03_PFIFO_CACHES, 1); + spin_unlock_irqrestore(&fifo->lock, flags); +} + +void +nv04_chan_start(struct nvkm_chan *chan) +{ + struct nvkm_fifo *fifo = chan->cgrp->runl->fifo; + unsigned long flags; + + spin_lock_irqsave(&fifo->lock, flags); + nvkm_mask(fifo->engine.subdev.device, NV04_PFIFO_MODE, BIT(chan->id), BIT(chan->id)); + spin_unlock_irqrestore(&fifo->lock, flags); +} + +void +nv04_chan_ramfc_clear(struct nvkm_chan *chan) +{ + struct nvkm_memory *ramfc = chan->cgrp->runl->fifo->engine.subdev.device->imem->ramfc; + const struct nvkm_ramfc_layout *c = chan->func->ramfc->layout; + + nvkm_kmap(ramfc); + do { + nvkm_wo32(ramfc, chan->ramfc_offset + c->ctxp, 0x00000000); + } while ((++c)->bits); + nvkm_done(ramfc); +} + +static int +nv04_chan_ramfc_write(struct nvkm_chan *chan, u64 offset, u64 length, u32 devm, bool priv) +{ + struct nvkm_memory *ramfc = chan->cgrp->runl->fifo->engine.subdev.device->imem->ramfc; + const u32 base = chan->id * 32; + + chan->ramfc_offset = base; + + nvkm_kmap(ramfc); + nvkm_wo32(ramfc, base + 0x00, offset); + nvkm_wo32(ramfc, base + 0x04, offset); + nvkm_wo32(ramfc, base + 0x08, chan->push->addr >> 4); + nvkm_wo32(ramfc, base + 0x10, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | + NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | +#ifdef __BIG_ENDIAN + NV_PFIFO_CACHE1_BIG_ENDIAN | +#endif + NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8); + nvkm_done(ramfc); + return 0; +} + +static const struct nvkm_chan_func_ramfc +nv04_chan_ramfc = { + .layout = (const struct nvkm_ramfc_layout[]) { + { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT }, + { 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET }, + { 16, 0, 0x08, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE }, + { 16, 16, 0x08, 0, NV04_PFIFO_CACHE1_DMA_DCOUNT }, + { 32, 0, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_STATE }, + { 32, 0, 0x10, 0, NV04_PFIFO_CACHE1_DMA_FETCH }, + { 32, 0, 0x14, 0, NV04_PFIFO_CACHE1_ENGINE }, + { 32, 0, 0x18, 0, NV04_PFIFO_CACHE1_PULL1 }, + {} + }, + .write = nv04_chan_ramfc_write, + .clear = nv04_chan_ramfc_clear, + .ctxdma = true, +}; + +const struct nvkm_chan_func_userd +nv04_chan_userd = { + .bar = 0, + .base = 0x800000, + .size = 0x010000, +}; + +const struct nvkm_chan_func_inst +nv04_chan_inst = { + .size = 0x1000, +}; + +static const struct nvkm_chan_func +nv04_chan = { + .inst = &nv04_chan_inst, + .userd = &nv04_chan_userd, + .ramfc = &nv04_chan_ramfc, + .start = nv04_chan_start, + .stop = nv04_chan_stop, +}; + +const struct nvkm_cgrp_func +nv04_cgrp = { +}; + +void +nv04_eobj_ramht_del(struct nvkm_chan *chan, int hash) +{ + struct nvkm_fifo *fifo = chan->cgrp->runl->fifo; + struct nvkm_instmem *imem = fifo->engine.subdev.device->imem; + + mutex_lock(&fifo->mutex); + nvkm_ramht_remove(imem->ramht, hash); + mutex_unlock(&fifo->mutex); +} + +static int +nv04_eobj_ramht_add(struct nvkm_engn *engn, struct nvkm_object *eobj, struct nvkm_chan *chan) +{ + struct nvkm_fifo *fifo = chan->cgrp->runl->fifo; + struct nvkm_instmem *imem = fifo->engine.subdev.device->imem; + u32 context = 0x80000000 | chan->id << 24 | engn->id << 16; + int hash; + + mutex_lock(&fifo->mutex); + hash = nvkm_ramht_insert(imem->ramht, eobj, chan->id, 4, eobj->handle, context); + mutex_unlock(&fifo->mutex); + return hash; +} + +const struct nvkm_engn_func +nv04_engn = { + .ramht_add = nv04_eobj_ramht_add, + .ramht_del = nv04_eobj_ramht_del, }; void -nv04_fifo_pause(struct nvkm_fifo *base, unsigned long *pflags) -__acquires(fifo->base.lock) +nv04_fifo_pause(struct nvkm_fifo *fifo, unsigned long *pflags) +__acquires(fifo->lock) { - struct nv04_fifo *fifo = nv04_fifo(base); - struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_device *device = fifo->engine.subdev.device; unsigned long flags; - spin_lock_irqsave(&fifo->base.lock, flags); + spin_lock_irqsave(&fifo->lock, flags); *pflags = flags; nvkm_wr32(device, NV03_PFIFO_CACHES, 0x00000000); @@ -81,50 +244,21 @@ __acquires(fifo->base.lock) } void -nv04_fifo_start(struct nvkm_fifo *base, unsigned long *pflags) -__releases(fifo->base.lock) +nv04_fifo_start(struct nvkm_fifo *fifo, unsigned long *pflags) +__releases(fifo->lock) { - struct nv04_fifo *fifo = nv04_fifo(base); - struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_device *device = fifo->engine.subdev.device; unsigned long flags = *pflags; nvkm_mask(device, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0x00000001); nvkm_wr32(device, NV03_PFIFO_CACHES, 0x00000001); - spin_unlock_irqrestore(&fifo->base.lock, flags); + spin_unlock_irqrestore(&fifo->lock, flags); } -struct nvkm_engine * -nv04_fifo_id_engine(struct nvkm_fifo *fifo, int engi) -{ - enum nvkm_subdev_type type; - - switch (engi) { - case NV04_FIFO_ENGN_SW : type = NVKM_ENGINE_SW; break; - case NV04_FIFO_ENGN_GR : type = NVKM_ENGINE_GR; break; - case NV04_FIFO_ENGN_MPEG: type = NVKM_ENGINE_MPEG; break; - case NV04_FIFO_ENGN_DMA : type = NVKM_ENGINE_DMAOBJ; break; - default: - WARN_ON(1); - return NULL; - } - - return nvkm_device_engine(fifo->engine.subdev.device, type, 0); -} - -int -nv04_fifo_engine_id(struct nvkm_fifo *base, struct nvkm_engine *engine) -{ - switch (engine->subdev.type) { - case NVKM_ENGINE_SW : return NV04_FIFO_ENGN_SW; - case NVKM_ENGINE_GR : return NV04_FIFO_ENGN_GR; - case NVKM_ENGINE_MPEG : return NV04_FIFO_ENGN_MPEG; - case NVKM_ENGINE_DMAOBJ: return NV04_FIFO_ENGN_DMA; - default: - WARN_ON(1); - return 0; - } -} +const struct nvkm_runl_func +nv04_runl = { +}; static const char * nv_dma_state_err(u32 state) @@ -166,11 +300,11 @@ nv04_fifo_swmthd(struct nvkm_device *device, u32 chid, u32 addr, u32 data) } static void -nv04_fifo_cache_error(struct nv04_fifo *fifo, u32 chid, u32 get) +nv04_fifo_intr_cache_error(struct nvkm_fifo *fifo, u32 chid, u32 get) { - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_subdev *subdev = &fifo->engine.subdev; struct nvkm_device *device = subdev->device; - struct nvkm_fifo_chan *chan; + struct nvkm_chan *chan; unsigned long flags; u32 pull0 = nvkm_rd32(device, 0x003250); u32 mthd, data; @@ -193,12 +327,12 @@ nv04_fifo_cache_error(struct nv04_fifo *fifo, u32 chid, u32 get) if (!(pull0 & 0x00000100) || !nv04_fifo_swmthd(device, chid, mthd, data)) { - chan = nvkm_fifo_chan_chid(&fifo->base, chid, &flags); + chan = nvkm_chan_get_chid(&fifo->engine, chid, &flags); nvkm_error(subdev, "CACHE_ERROR - " "ch %d [%s] subc %d mthd %04x data %08x\n", - chid, chan ? chan->object.client->name : "unknown", + chid, chan ? chan->name : "unknown", (mthd >> 13) & 7, mthd & 0x1ffc, data); - nvkm_fifo_chan_put(&fifo->base, flags, &chan); + nvkm_chan_put(&chan, flags); } nvkm_wr32(device, NV04_PFIFO_CACHE1_DMA_PUSH, 0); @@ -217,20 +351,20 @@ nv04_fifo_cache_error(struct nv04_fifo *fifo, u32 chid, u32 get) } static void -nv04_fifo_dma_pusher(struct nv04_fifo *fifo, u32 chid) +nv04_fifo_intr_dma_pusher(struct nvkm_fifo *fifo, u32 chid) { - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_subdev *subdev = &fifo->engine.subdev; struct nvkm_device *device = subdev->device; u32 dma_get = nvkm_rd32(device, 0x003244); u32 dma_put = nvkm_rd32(device, 0x003240); u32 push = nvkm_rd32(device, 0x003220); u32 state = nvkm_rd32(device, 0x003228); - struct nvkm_fifo_chan *chan; + struct nvkm_chan *chan; unsigned long flags; const char *name; - chan = nvkm_fifo_chan_chid(&fifo->base, chid, &flags); - name = chan ? chan->object.client->name : "unknown"; + chan = nvkm_chan_get_chid(&fifo->engine, chid, &flags); + name = chan ? chan->name : "unknown"; if (device->card_type == NV_50) { u32 ho_get = nvkm_rd32(device, 0x003328); u32 ho_put = nvkm_rd32(device, 0x003320); @@ -261,18 +395,18 @@ nv04_fifo_dma_pusher(struct nv04_fifo *fifo, u32 chid) if (dma_get != dma_put) nvkm_wr32(device, 0x003244, dma_put); } - nvkm_fifo_chan_put(&fifo->base, flags, &chan); + nvkm_chan_put(&chan, flags); nvkm_wr32(device, 0x003228, 0x00000000); nvkm_wr32(device, 0x003220, 0x00000001); nvkm_wr32(device, 0x002100, NV_PFIFO_INTR_DMA_PUSHER); } -void -nv04_fifo_intr(struct nvkm_fifo *base) +irqreturn_t +nv04_fifo_intr(struct nvkm_inth *inth) { - struct nv04_fifo *fifo = nv04_fifo(base); - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_fifo *fifo = container_of(inth, typeof(*fifo), engine.subdev.inth); + struct nvkm_subdev *subdev = &fifo->engine.subdev; struct nvkm_device *device = subdev->device; u32 mask = nvkm_rd32(device, NV03_PFIFO_INTR_EN_0); u32 stat = nvkm_rd32(device, NV03_PFIFO_INTR_0) & mask; @@ -281,16 +415,16 @@ nv04_fifo_intr(struct nvkm_fifo *base) reassign = nvkm_rd32(device, NV03_PFIFO_CACHES) & 1; nvkm_wr32(device, NV03_PFIFO_CACHES, 0); - chid = nvkm_rd32(device, NV03_PFIFO_CACHE1_PUSH1) & (fifo->base.nr - 1); + chid = nvkm_rd32(device, NV03_PFIFO_CACHE1_PUSH1) & fifo->chid->mask; get = nvkm_rd32(device, NV03_PFIFO_CACHE1_GET); if (stat & NV_PFIFO_INTR_CACHE_ERROR) { - nv04_fifo_cache_error(fifo, chid, get); + nv04_fifo_intr_cache_error(fifo, chid, get); stat &= ~NV_PFIFO_INTR_CACHE_ERROR; } if (stat & NV_PFIFO_INTR_DMA_PUSHER) { - nv04_fifo_dma_pusher(fifo, chid); + nv04_fifo_intr_dma_pusher(fifo, chid); stat &= ~NV_PFIFO_INTR_DMA_PUSHER; } @@ -313,7 +447,7 @@ nv04_fifo_intr(struct nvkm_fifo *base) if (stat & 0x40000000) { nvkm_wr32(device, 0x002100, 0x40000000); - nvkm_fifo_uevent(&fifo->base); + nvkm_event_ntfy(&fifo->nonstall.event, 0, NVKM_FIFO_NONSTALL_EVENT); stat &= ~0x40000000; } } @@ -325,13 +459,13 @@ nv04_fifo_intr(struct nvkm_fifo *base) } nvkm_wr32(device, NV03_PFIFO_CACHES, reassign); + return IRQ_HANDLED; } void -nv04_fifo_init(struct nvkm_fifo *base) +nv04_fifo_init(struct nvkm_fifo *fifo) { - struct nv04_fifo *fifo = nv04_fifo(base); - struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_device *device = fifo->engine.subdev.device; struct nvkm_instmem *imem = device->imem; struct nvkm_ramht *ramht = imem->ramht; struct nvkm_memory *ramro = imem->ramro; @@ -346,7 +480,7 @@ nv04_fifo_init(struct nvkm_fifo *base) nvkm_wr32(device, NV03_PFIFO_RAMRO, nvkm_memory_addr(ramro) >> 8); nvkm_wr32(device, NV03_PFIFO_RAMFC, nvkm_memory_addr(ramfc) >> 8); - nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, fifo->base.nr - 1); + nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, fifo->chid->mask); nvkm_wr32(device, NV03_PFIFO_INTR_0, 0xffffffff); nvkm_wr32(device, NV03_PFIFO_INTR_EN_0, 0xffffffff); @@ -357,43 +491,53 @@ nv04_fifo_init(struct nvkm_fifo *base) } int -nv04_fifo_new_(const struct nvkm_fifo_func *func, struct nvkm_device *device, - enum nvkm_subdev_type type, int inst, int nr, const struct nv04_fifo_ramfc *ramfc, - struct nvkm_fifo **pfifo) +nv04_fifo_runl_ctor(struct nvkm_fifo *fifo) { - struct nv04_fifo *fifo; - int ret; - - if (!(fifo = kzalloc(sizeof(*fifo), GFP_KERNEL))) - return -ENOMEM; - fifo->ramfc = ramfc; - *pfifo = &fifo->base; + struct nvkm_runl *runl; - ret = nvkm_fifo_ctor(func, device, type, inst, nr, &fifo->base); - if (ret) - return ret; + runl = nvkm_runl_new(fifo, 0, 0, 0); + if (IS_ERR(runl)) + return PTR_ERR(runl); - set_bit(nr - 1, fifo->base.mask); /* inactive channel */ + nvkm_runl_add(runl, 0, fifo->func->engn_sw, NVKM_ENGINE_SW, 0); + nvkm_runl_add(runl, 0, fifo->func->engn_sw, NVKM_ENGINE_DMAOBJ, 0); + nvkm_runl_add(runl, 1, fifo->func->engn , NVKM_ENGINE_GR, 0); + nvkm_runl_add(runl, 2, fifo->func->engn , NVKM_ENGINE_MPEG, 0); /* NV31- */ return 0; } +int +nv04_fifo_chid_ctor(struct nvkm_fifo *fifo, int nr) +{ + /* The last CHID is reserved by HW as a "channel invalid" marker. */ + return nvkm_chid_new(&nvkm_chan_event, &fifo->engine.subdev, nr, 0, nr - 1, &fifo->chid); +} + +static int +nv04_fifo_chid_nr(struct nvkm_fifo *fifo) +{ + return 16; +} + static const struct nvkm_fifo_func nv04_fifo = { + .chid_nr = nv04_fifo_chid_nr, + .chid_ctor = nv04_fifo_chid_ctor, + .runl_ctor = nv04_fifo_runl_ctor, .init = nv04_fifo_init, .intr = nv04_fifo_intr, - .engine_id = nv04_fifo_engine_id, - .id_engine = nv04_fifo_id_engine, .pause = nv04_fifo_pause, .start = nv04_fifo_start, - .chan = { - &nv04_fifo_dma_oclass, - NULL - }, + .runl = &nv04_runl, + .engn = &nv04_engn, + .engn_sw = &nv04_engn, + .cgrp = {{ }, &nv04_cgrp }, + .chan = {{ 0, 0, NV03_CHANNEL_DMA }, &nv04_chan }, }; int nv04_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fifo **pfifo) { - return nv04_fifo_new_(&nv04_fifo, device, type, inst, 16, nv04_fifo_ramfc, pfifo); + return nvkm_fifo_new_(&nv04_fifo, device, type, inst, pfifo); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.h deleted file mode 100644 index 3f23bcde4a54..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.h +++ /dev/null @@ -1,23 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -#ifndef __NV04_FIFO_H__ -#define __NV04_FIFO_H__ -#define nv04_fifo(p) container_of((p), struct nv04_fifo, base) -#include "priv.h" - -struct nv04_fifo_ramfc { - unsigned bits:6; - unsigned ctxs:5; - unsigned ctxp:8; - unsigned regs:5; - unsigned regp; -}; - -struct nv04_fifo { - struct nvkm_fifo base; - const struct nv04_fifo_ramfc *ramfc; -}; - -int nv04_fifo_new_(const struct nvkm_fifo_func *, struct nvkm_device *, enum nvkm_subdev_type, int, - int nr, const struct nv04_fifo_ramfc *, struct nvkm_fifo **); -void nv04_fifo_init(struct nvkm_fifo *); -#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c index f8887f0f2f82..a4bcf6b0a7e2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c @@ -21,41 +21,93 @@ * * Authors: Ben Skeggs */ -#include "nv04.h" -#include "channv04.h" +#include "priv.h" +#include "cgrp.h" +#include "chan.h" +#include "runl.h" + +#include <core/gpuobj.h> +#include <subdev/instmem.h> + #include "regsnv04.h" -static const struct nv04_fifo_ramfc -nv10_fifo_ramfc[] = { - { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT }, - { 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET }, - { 32, 0, 0x08, 0, NV10_PFIFO_CACHE1_REF_CNT }, - { 16, 0, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE }, - { 16, 16, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_DCOUNT }, - { 32, 0, 0x10, 0, NV04_PFIFO_CACHE1_DMA_STATE }, - { 32, 0, 0x14, 0, NV04_PFIFO_CACHE1_DMA_FETCH }, - { 32, 0, 0x18, 0, NV04_PFIFO_CACHE1_ENGINE }, - { 32, 0, 0x1c, 0, NV04_PFIFO_CACHE1_PULL1 }, - {} +#include <nvif/class.h> + +static int +nv10_chan_ramfc_write(struct nvkm_chan *chan, u64 offset, u64 length, u32 devm, bool priv) +{ + struct nvkm_memory *ramfc = chan->cgrp->runl->fifo->engine.subdev.device->imem->ramfc; + const u32 base = chan->id * 32; + + chan->ramfc_offset = base; + + nvkm_kmap(ramfc); + nvkm_wo32(ramfc, base + 0x00, offset); + nvkm_wo32(ramfc, base + 0x04, offset); + nvkm_wo32(ramfc, base + 0x0c, chan->push->addr >> 4); + nvkm_wo32(ramfc, base + 0x14, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | + NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | +#ifdef __BIG_ENDIAN + NV_PFIFO_CACHE1_BIG_ENDIAN | +#endif + NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8); + nvkm_done(ramfc); + return 0; +} + +static const struct nvkm_chan_func_ramfc +nv10_chan_ramfc = { + .layout = (const struct nvkm_ramfc_layout[]) { + { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT }, + { 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET }, + { 32, 0, 0x08, 0, NV10_PFIFO_CACHE1_REF_CNT }, + { 16, 0, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE }, + { 16, 16, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_DCOUNT }, + { 32, 0, 0x10, 0, NV04_PFIFO_CACHE1_DMA_STATE }, + { 32, 0, 0x14, 0, NV04_PFIFO_CACHE1_DMA_FETCH }, + { 32, 0, 0x18, 0, NV04_PFIFO_CACHE1_ENGINE }, + { 32, 0, 0x1c, 0, NV04_PFIFO_CACHE1_PULL1 }, + {} + }, + .write = nv10_chan_ramfc_write, + .clear = nv04_chan_ramfc_clear, + .ctxdma = true, +}; + +static const struct nvkm_chan_func +nv10_chan = { + .inst = &nv04_chan_inst, + .userd = &nv04_chan_userd, + .ramfc = &nv10_chan_ramfc, + .start = nv04_chan_start, + .stop = nv04_chan_stop, }; +int +nv10_fifo_chid_nr(struct nvkm_fifo *fifo) +{ + return 32; +} + static const struct nvkm_fifo_func nv10_fifo = { + .chid_nr = nv10_fifo_chid_nr, + .chid_ctor = nv04_fifo_chid_ctor, + .runl_ctor = nv04_fifo_runl_ctor, .init = nv04_fifo_init, .intr = nv04_fifo_intr, - .engine_id = nv04_fifo_engine_id, - .id_engine = nv04_fifo_id_engine, .pause = nv04_fifo_pause, .start = nv04_fifo_start, - .chan = { - &nv10_fifo_dma_oclass, - NULL - }, + .runl = &nv04_runl, + .engn = &nv04_engn, + .engn_sw = &nv04_engn, + .cgrp = {{ }, &nv04_cgrp }, + .chan = {{ 0, 0, NV10_CHANNEL_DMA }, &nv10_chan }, }; int nv10_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fifo **pfifo) { - return nv04_fifo_new_(&nv10_fifo, device, type, inst, 32, nv10_fifo_ramfc, pfifo); + return nvkm_fifo_new_(&nv10_fifo, device, type, inst, pfifo); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c index 3f94c7b5b054..c70f44fd4f3b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c @@ -21,37 +21,78 @@ * * Authors: Ben Skeggs */ -#include "nv04.h" -#include "channv04.h" +#include "priv.h" +#include "cgrp.h" +#include "chan.h" +#include "chid.h" +#include "runl.h" + #include "regsnv04.h" #include <core/ramht.h> #include <subdev/instmem.h> -static const struct nv04_fifo_ramfc -nv17_fifo_ramfc[] = { - { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT }, - { 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET }, - { 32, 0, 0x08, 0, NV10_PFIFO_CACHE1_REF_CNT }, - { 16, 0, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE }, - { 16, 16, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_DCOUNT }, - { 32, 0, 0x10, 0, NV04_PFIFO_CACHE1_DMA_STATE }, - { 32, 0, 0x14, 0, NV04_PFIFO_CACHE1_DMA_FETCH }, - { 32, 0, 0x18, 0, NV04_PFIFO_CACHE1_ENGINE }, - { 32, 0, 0x1c, 0, NV04_PFIFO_CACHE1_PULL1 }, - { 32, 0, 0x20, 0, NV10_PFIFO_CACHE1_ACQUIRE_VALUE }, - { 32, 0, 0x24, 0, NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP }, - { 32, 0, 0x28, 0, NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT }, - { 32, 0, 0x2c, 0, NV10_PFIFO_CACHE1_SEMAPHORE }, - { 32, 0, 0x30, 0, NV10_PFIFO_CACHE1_DMA_SUBROUTINE }, - {} +#include <nvif/class.h> + +static int +nv17_chan_ramfc_write(struct nvkm_chan *chan, u64 offset, u64 length, u32 devm, bool priv) +{ + struct nvkm_memory *ramfc = chan->cgrp->runl->fifo->engine.subdev.device->imem->ramfc; + const u32 base = chan->id * 64; + + chan->ramfc_offset = base; + + nvkm_kmap(ramfc); + nvkm_wo32(ramfc, base + 0x00, offset); + nvkm_wo32(ramfc, base + 0x04, offset); + nvkm_wo32(ramfc, base + 0x0c, chan->push->addr >> 4); + nvkm_wo32(ramfc, base + 0x14, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | + NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | +#ifdef __BIG_ENDIAN + NV_PFIFO_CACHE1_BIG_ENDIAN | +#endif + NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8); + nvkm_done(ramfc); + return 0; +} + +static const struct nvkm_chan_func_ramfc +nv17_chan_ramfc = { + .layout = (const struct nvkm_ramfc_layout[]) { + { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT }, + { 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET }, + { 32, 0, 0x08, 0, NV10_PFIFO_CACHE1_REF_CNT }, + { 16, 0, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE }, + { 16, 16, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_DCOUNT }, + { 32, 0, 0x10, 0, NV04_PFIFO_CACHE1_DMA_STATE }, + { 32, 0, 0x14, 0, NV04_PFIFO_CACHE1_DMA_FETCH }, + { 32, 0, 0x18, 0, NV04_PFIFO_CACHE1_ENGINE }, + { 32, 0, 0x1c, 0, NV04_PFIFO_CACHE1_PULL1 }, + { 32, 0, 0x20, 0, NV10_PFIFO_CACHE1_ACQUIRE_VALUE }, + { 32, 0, 0x24, 0, NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP }, + { 32, 0, 0x28, 0, NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT }, + { 32, 0, 0x2c, 0, NV10_PFIFO_CACHE1_SEMAPHORE }, + { 32, 0, 0x30, 0, NV10_PFIFO_CACHE1_DMA_SUBROUTINE }, + {} + }, + .write = nv17_chan_ramfc_write, + .clear = nv04_chan_ramfc_clear, + .ctxdma = true, +}; + +static const struct nvkm_chan_func +nv17_chan = { + .inst = &nv04_chan_inst, + .userd = &nv04_chan_userd, + .ramfc = &nv17_chan_ramfc, + .start = nv04_chan_start, + .stop = nv04_chan_stop, }; static void -nv17_fifo_init(struct nvkm_fifo *base) +nv17_fifo_init(struct nvkm_fifo *fifo) { - struct nv04_fifo *fifo = nv04_fifo(base); - struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_device *device = fifo->engine.subdev.device; struct nvkm_instmem *imem = device->imem; struct nvkm_ramht *ramht = imem->ramht; struct nvkm_memory *ramro = imem->ramro; @@ -67,7 +108,7 @@ nv17_fifo_init(struct nvkm_fifo *base) nvkm_wr32(device, NV03_PFIFO_RAMFC, nvkm_memory_addr(ramfc) >> 8 | 0x00010000); - nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, fifo->base.nr - 1); + nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, fifo->chid->mask); nvkm_wr32(device, NV03_PFIFO_INTR_0, 0xffffffff); nvkm_wr32(device, NV03_PFIFO_INTR_EN_0, 0xffffffff); @@ -79,21 +120,23 @@ nv17_fifo_init(struct nvkm_fifo *base) static const struct nvkm_fifo_func nv17_fifo = { + .chid_nr = nv10_fifo_chid_nr, + .chid_ctor = nv04_fifo_chid_ctor, + .runl_ctor = nv04_fifo_runl_ctor, .init = nv17_fifo_init, .intr = nv04_fifo_intr, - .engine_id = nv04_fifo_engine_id, - .id_engine = nv04_fifo_id_engine, .pause = nv04_fifo_pause, .start = nv04_fifo_start, - .chan = { - &nv17_fifo_dma_oclass, - NULL - }, + .runl = &nv04_runl, + .engn = &nv04_engn, + .engn_sw = &nv04_engn, + .cgrp = {{ }, &nv04_cgrp }, + .chan = {{ 0, 0, NV17_CHANNEL_DMA }, &nv17_chan }, }; int nv17_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fifo **pfifo) { - return nv04_fifo_new_(&nv17_fifo, device, type, inst, 32, nv17_fifo_ramfc, pfifo); + return nvkm_fifo_new_(&nv17_fifo, device, type, inst, pfifo); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c index f9ea46809bc0..e50a94b6d7f8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c @@ -21,46 +21,166 @@ * * Authors: Ben Skeggs */ -#include "nv04.h" -#include "channv04.h" +#include "priv.h" +#include "cgrp.h" +#include "chan.h" +#include "chid.h" +#include "runl.h" + #include "regsnv04.h" #include <core/ramht.h> #include <subdev/fb.h> #include <subdev/instmem.h> -static const struct nv04_fifo_ramfc -nv40_fifo_ramfc[] = { - { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT }, - { 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET }, - { 32, 0, 0x08, 0, NV10_PFIFO_CACHE1_REF_CNT }, - { 32, 0, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE }, - { 32, 0, 0x10, 0, NV04_PFIFO_CACHE1_DMA_DCOUNT }, - { 32, 0, 0x14, 0, NV04_PFIFO_CACHE1_DMA_STATE }, - { 28, 0, 0x18, 0, NV04_PFIFO_CACHE1_DMA_FETCH }, - { 2, 28, 0x18, 28, 0x002058 }, - { 32, 0, 0x1c, 0, NV04_PFIFO_CACHE1_ENGINE }, - { 32, 0, 0x20, 0, NV04_PFIFO_CACHE1_PULL1 }, - { 32, 0, 0x24, 0, NV10_PFIFO_CACHE1_ACQUIRE_VALUE }, - { 32, 0, 0x28, 0, NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP }, - { 32, 0, 0x2c, 0, NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT }, - { 32, 0, 0x30, 0, NV10_PFIFO_CACHE1_SEMAPHORE }, - { 32, 0, 0x34, 0, NV10_PFIFO_CACHE1_DMA_SUBROUTINE }, - { 32, 0, 0x38, 0, NV40_PFIFO_GRCTX_INSTANCE }, - { 17, 0, 0x3c, 0, NV04_PFIFO_DMA_TIMESLICE }, - { 32, 0, 0x40, 0, 0x0032e4 }, - { 32, 0, 0x44, 0, 0x0032e8 }, - { 32, 0, 0x4c, 0, 0x002088 }, - { 32, 0, 0x50, 0, 0x003300 }, - { 32, 0, 0x54, 0, 0x00330c }, - {} +#include <nvif/class.h> + +static int +nv40_chan_ramfc_write(struct nvkm_chan *chan, u64 offset, u64 length, u32 devm, bool priv) +{ + struct nvkm_memory *ramfc = chan->cgrp->runl->fifo->engine.subdev.device->imem->ramfc; + const u32 base = chan->id * 128; + + chan->ramfc_offset = base; + + nvkm_kmap(ramfc); + nvkm_wo32(ramfc, base + 0x00, offset); + nvkm_wo32(ramfc, base + 0x04, offset); + nvkm_wo32(ramfc, base + 0x0c, chan->push->addr >> 4); + nvkm_wo32(ramfc, base + 0x18, 0x30000000 | + NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | + NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | +#ifdef __BIG_ENDIAN + NV_PFIFO_CACHE1_BIG_ENDIAN | +#endif + NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8); + nvkm_wo32(ramfc, base + 0x3c, 0x0001ffff); + nvkm_done(ramfc); + return 0; +} + +static const struct nvkm_chan_func_ramfc +nv40_chan_ramfc = { + .layout = (const struct nvkm_ramfc_layout[]) { + { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT }, + { 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET }, + { 32, 0, 0x08, 0, NV10_PFIFO_CACHE1_REF_CNT }, + { 32, 0, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE }, + { 32, 0, 0x10, 0, NV04_PFIFO_CACHE1_DMA_DCOUNT }, + { 32, 0, 0x14, 0, NV04_PFIFO_CACHE1_DMA_STATE }, + { 28, 0, 0x18, 0, NV04_PFIFO_CACHE1_DMA_FETCH }, + { 2, 28, 0x18, 28, 0x002058 }, + { 32, 0, 0x1c, 0, NV04_PFIFO_CACHE1_ENGINE }, + { 32, 0, 0x20, 0, NV04_PFIFO_CACHE1_PULL1 }, + { 32, 0, 0x24, 0, NV10_PFIFO_CACHE1_ACQUIRE_VALUE }, + { 32, 0, 0x28, 0, NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP }, + { 32, 0, 0x2c, 0, NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT }, + { 32, 0, 0x30, 0, NV10_PFIFO_CACHE1_SEMAPHORE }, + { 32, 0, 0x34, 0, NV10_PFIFO_CACHE1_DMA_SUBROUTINE }, + { 32, 0, 0x38, 0, NV40_PFIFO_GRCTX_INSTANCE }, + { 17, 0, 0x3c, 0, NV04_PFIFO_DMA_TIMESLICE }, + { 32, 0, 0x40, 0, 0x0032e4 }, + { 32, 0, 0x44, 0, 0x0032e8 }, + { 32, 0, 0x4c, 0, 0x002088 }, + { 32, 0, 0x50, 0, 0x003300 }, + { 32, 0, 0x54, 0, 0x00330c }, + {} + }, + .write = nv40_chan_ramfc_write, + .clear = nv04_chan_ramfc_clear, + .ctxdma = true, +}; + +static const struct nvkm_chan_func_userd +nv40_chan_userd = { + .bar = 0, + .base = 0xc00000, + .size = 0x001000, +}; + +static const struct nvkm_chan_func +nv40_chan = { + .inst = &nv04_chan_inst, + .userd = &nv40_chan_userd, + .ramfc = &nv40_chan_ramfc, + .start = nv04_chan_start, + .stop = nv04_chan_stop, }; +static int +nv40_eobj_ramht_add(struct nvkm_engn *engn, struct nvkm_object *eobj, struct nvkm_chan *chan) +{ + struct nvkm_fifo *fifo = chan->cgrp->runl->fifo; + struct nvkm_instmem *imem = fifo->engine.subdev.device->imem; + u32 context = chan->id << 23 | engn->id << 20; + int hash; + + mutex_lock(&fifo->mutex); + hash = nvkm_ramht_insert(imem->ramht, eobj, chan->id, 4, eobj->handle, context); + mutex_unlock(&fifo->mutex); + return hash; +} + static void -nv40_fifo_init(struct nvkm_fifo *base) +nv40_ectx_bind(struct nvkm_engn *engn, struct nvkm_cctx *cctx, struct nvkm_chan *chan) { - struct nv04_fifo *fifo = nv04_fifo(base); - struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_fifo *fifo = chan->cgrp->runl->fifo; + struct nvkm_device *device = fifo->engine.subdev.device; + struct nvkm_memory *ramfc = device->imem->ramfc; + u32 inst = 0x00000000, reg, ctx; + int chid; + + switch (engn->engine->subdev.type) { + case NVKM_ENGINE_GR: + reg = 0x0032e0; + ctx = 0x38; + break; + case NVKM_ENGINE_MPEG: + if (WARN_ON(device->chipset < 0x44)) + return; + reg = 0x00330c; + ctx = 0x54; + break; + default: + WARN_ON(1); + return; + } + + if (cctx) + inst = cctx->vctx->inst->addr >> 4; + + spin_lock_irq(&fifo->lock); + nvkm_mask(device, 0x002500, 0x00000001, 0x00000000); + + chid = nvkm_rd32(device, 0x003204) & (fifo->chid->nr - 1); + if (chid == chan->id) + nvkm_wr32(device, reg, inst); + + nvkm_kmap(ramfc); + nvkm_wo32(ramfc, chan->ramfc_offset + ctx, inst); + nvkm_done(ramfc); + + nvkm_mask(device, 0x002500, 0x00000001, 0x00000001); + spin_unlock_irq(&fifo->lock); +} + +static const struct nvkm_engn_func +nv40_engn = { + .bind = nv40_ectx_bind, + .ramht_add = nv40_eobj_ramht_add, + .ramht_del = nv04_eobj_ramht_del, +}; + +static const struct nvkm_engn_func +nv40_engn_sw = { + .ramht_add = nv40_eobj_ramht_add, + .ramht_del = nv04_eobj_ramht_del, +}; + +static void +nv40_fifo_init(struct nvkm_fifo *fifo) +{ + struct nvkm_device *device = fifo->engine.subdev.device; struct nvkm_fb *fb = device->fb; struct nvkm_instmem *imem = device->imem; struct nvkm_ramht *ramht = imem->ramht; @@ -98,7 +218,7 @@ nv40_fifo_init(struct nvkm_fifo *base) break; } - nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, fifo->base.nr - 1); + nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, fifo->chid->mask); nvkm_wr32(device, NV03_PFIFO_INTR_0, 0xffffffff); nvkm_wr32(device, NV03_PFIFO_INTR_EN_0, 0xffffffff); @@ -110,21 +230,23 @@ nv40_fifo_init(struct nvkm_fifo *base) static const struct nvkm_fifo_func nv40_fifo = { + .chid_nr = nv10_fifo_chid_nr, + .chid_ctor = nv04_fifo_chid_ctor, + .runl_ctor = nv04_fifo_runl_ctor, .init = nv40_fifo_init, .intr = nv04_fifo_intr, - .engine_id = nv04_fifo_engine_id, - .id_engine = nv04_fifo_id_engine, .pause = nv04_fifo_pause, .start = nv04_fifo_start, - .chan = { - &nv40_fifo_dma_oclass, - NULL - }, + .runl = &nv04_runl, + .engn = &nv40_engn, + .engn_sw = &nv40_engn_sw, + .cgrp = {{ }, &nv04_cgrp }, + .chan = {{ 0, 0, NV40_CHANNEL_DMA }, &nv40_chan }, }; int nv40_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fifo **pfifo) { - return nv04_fifo_new_(&nv40_fifo, device, type, inst, 32, nv40_fifo_ramfc, pfifo); + return nvkm_fifo_new_(&nv40_fifo, device, type, inst, pfifo); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c index a08742cf425a..954b5f3a7d57 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c @@ -21,62 +21,325 @@ * * Authors: Ben Skeggs */ -#include "nv50.h" -#include "channv50.h" +#include "priv.h" +#include "cgrp.h" +#include "chan.h" +#include "chid.h" +#include "runl.h" -#include <core/gpuobj.h> +#include <core/ramht.h> +#include <subdev/timer.h> -static void -nv50_fifo_runlist_update_locked(struct nv50_fifo *fifo) +#include <nvif/class.h> + +void +nv50_eobj_ramht_del(struct nvkm_chan *chan, int hash) { - struct nvkm_device *device = fifo->base.engine.subdev.device; - struct nvkm_memory *cur; - int i, p; + nvkm_ramht_remove(chan->ramht, hash); +} - cur = fifo->runlist[fifo->cur_runlist]; - fifo->cur_runlist = !fifo->cur_runlist; +int +nv50_eobj_ramht_add(struct nvkm_engn *engn, struct nvkm_object *eobj, struct nvkm_chan *chan) +{ + return nvkm_ramht_insert(chan->ramht, eobj, 0, 4, eobj->handle, engn->id << 20); +} - nvkm_kmap(cur); - for (i = 0, p = 0; i < fifo->base.nr; i++) { - if (nvkm_rd32(device, 0x002600 + (i * 4)) & 0x80000000) - nvkm_wo32(cur, p++ * 4, i); - } - nvkm_done(cur); +void +nv50_chan_stop(struct nvkm_chan *chan) +{ + struct nvkm_device *device = chan->cgrp->runl->fifo->engine.subdev.device; - nvkm_wr32(device, 0x0032f4, nvkm_memory_addr(cur) >> 12); - nvkm_wr32(device, 0x0032ec, p); - nvkm_wr32(device, 0x002500, 0x00000101); + nvkm_mask(device, 0x002600 + (chan->id * 4), 0x80000000, 0x00000000); } void -nv50_fifo_runlist_update(struct nv50_fifo *fifo) +nv50_chan_start(struct nvkm_chan *chan) { - mutex_lock(&fifo->base.mutex); - nv50_fifo_runlist_update_locked(fifo); - mutex_unlock(&fifo->base.mutex); + struct nvkm_device *device = chan->cgrp->runl->fifo->engine.subdev.device; + + nvkm_mask(device, 0x002600 + (chan->id * 4), 0x80000000, 0x80000000); } -int -nv50_fifo_oneinit(struct nvkm_fifo *base) +void +nv50_chan_unbind(struct nvkm_chan *chan) { - struct nv50_fifo *fifo = nv50_fifo(base); - struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_device *device = chan->cgrp->runl->fifo->engine.subdev.device; + + nvkm_wr32(device, 0x002600 + (chan->id * 4), 0x00000000); +} + +static void +nv50_chan_bind(struct nvkm_chan *chan) +{ + struct nvkm_device *device = chan->cgrp->runl->fifo->engine.subdev.device; + + nvkm_wr32(device, 0x002600 + (chan->id * 4), chan->ramfc->addr >> 12); +} + +static int +nv50_chan_ramfc_write(struct nvkm_chan *chan, u64 offset, u64 length, u32 devm, bool priv) +{ + struct nvkm_device *device = chan->cgrp->runl->fifo->engine.subdev.device; + const u32 limit2 = ilog2(length / 8); int ret; - ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 128 * 4, 0x1000, - false, &fifo->runlist[0]); + ret = nvkm_gpuobj_new(device, 0x0200, 0x1000, true, chan->inst, &chan->ramfc); + if (ret) + return ret; + + ret = nvkm_gpuobj_new(device, 0x1200, 0, true, chan->inst, &chan->eng); if (ret) return ret; - return nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 128 * 4, 0x1000, - false, &fifo->runlist[1]); + ret = nvkm_gpuobj_new(device, 0x4000, 0, false, chan->inst, &chan->pgd); + if (ret) + return ret; + + ret = nvkm_ramht_new(device, 0x8000, 16, chan->inst, &chan->ramht); + if (ret) + return ret; + + nvkm_kmap(chan->ramfc); + nvkm_wo32(chan->ramfc, 0x3c, 0x403f6078); + nvkm_wo32(chan->ramfc, 0x44, 0x01003fff); + nvkm_wo32(chan->ramfc, 0x48, chan->push->node->offset >> 4); + nvkm_wo32(chan->ramfc, 0x50, lower_32_bits(offset)); + nvkm_wo32(chan->ramfc, 0x54, upper_32_bits(offset) | (limit2 << 16)); + nvkm_wo32(chan->ramfc, 0x60, 0x7fffffff); + nvkm_wo32(chan->ramfc, 0x78, 0x00000000); + nvkm_wo32(chan->ramfc, 0x7c, 0x30000000 | devm); + nvkm_wo32(chan->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | + (4 << 24) /* SEARCH_FULL */ | + (chan->ramht->gpuobj->node->offset >> 4)); + nvkm_done(chan->ramfc); + return 0; +} + +static const struct nvkm_chan_func_ramfc +nv50_chan_ramfc = { + .write = nv50_chan_ramfc_write, + .ctxdma = true, + .devm = 0xfff, +}; + +const struct nvkm_chan_func_userd +nv50_chan_userd = { + .bar = 0, + .base = 0xc00000, + .size = 0x002000, +}; + +const struct nvkm_chan_func_inst +nv50_chan_inst = { + .size = 0x10000, + .vmm = true, +}; + +static const struct nvkm_chan_func +nv50_chan = { + .inst = &nv50_chan_inst, + .userd = &nv50_chan_userd, + .ramfc = &nv50_chan_ramfc, + .bind = nv50_chan_bind, + .unbind = nv50_chan_unbind, + .start = nv50_chan_start, + .stop = nv50_chan_stop, +}; + +static void +nv50_ectx_bind(struct nvkm_engn *engn, struct nvkm_cctx *cctx, struct nvkm_chan *chan) +{ + struct nvkm_subdev *subdev = &chan->cgrp->runl->fifo->engine.subdev; + struct nvkm_device *device = subdev->device; + u64 start = 0, limit = 0; + u32 flags = 0, ptr0, save; + + switch (engn->engine->subdev.type) { + case NVKM_ENGINE_GR : ptr0 = 0x0000; break; + case NVKM_ENGINE_MPEG : ptr0 = 0x0060; break; + default: + WARN_ON(1); + return; + } + + if (!cctx) { + /* HW bug workaround: + * + * PFIFO will hang forever if the connected engines don't report + * that they've processed the context switch request. + * + * In order for the kickoff to work, we need to ensure all the + * connected engines are in a state where they can answer. + * + * Newer chipsets don't seem to suffer from this issue, and well, + * there's also a "ignore these engines" bitmask reg we can use + * if we hit the issue there.. + */ + save = nvkm_mask(device, 0x00b860, 0x00000001, 0x00000001); + + /* Tell engines to save out contexts. */ + nvkm_wr32(device, 0x0032fc, chan->inst->addr >> 12); + nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x0032fc) != 0xffffffff) + break; + ); + nvkm_wr32(device, 0x00b860, save); + } else { + flags = 0x00190000; + start = cctx->vctx->inst->addr; + limit = start + cctx->vctx->inst->size - 1; + } + + nvkm_kmap(chan->eng); + nvkm_wo32(chan->eng, ptr0 + 0x00, flags); + nvkm_wo32(chan->eng, ptr0 + 0x04, lower_32_bits(limit)); + nvkm_wo32(chan->eng, ptr0 + 0x08, lower_32_bits(start)); + nvkm_wo32(chan->eng, ptr0 + 0x0c, upper_32_bits(limit) << 24 | + lower_32_bits(start)); + nvkm_wo32(chan->eng, ptr0 + 0x10, 0x00000000); + nvkm_wo32(chan->eng, ptr0 + 0x14, 0x00000000); + nvkm_done(chan->eng); } +static const struct nvkm_engn_func +nv50_engn = { + .bind = nv50_ectx_bind, + .ramht_add = nv50_eobj_ramht_add, + .ramht_del = nv50_eobj_ramht_del, +}; + +const struct nvkm_engn_func +nv50_engn_sw = { + .ramht_add = nv50_eobj_ramht_add, + .ramht_del = nv50_eobj_ramht_del, +}; + +static bool +nv50_runl_pending(struct nvkm_runl *runl) +{ + return nvkm_rd32(runl->fifo->engine.subdev.device, 0x0032ec) & 0x00000100; +} + +int +nv50_runl_wait(struct nvkm_runl *runl) +{ + struct nvkm_fifo *fifo = runl->fifo; + + nvkm_msec(fifo->engine.subdev.device, fifo->timeout.chan_msec, + if (!nvkm_runl_update_pending(runl)) + return 0; + usleep_range(1, 2); + ); + + return -ETIMEDOUT; +} + +static void +nv50_runl_commit(struct nvkm_runl *runl, struct nvkm_memory *memory, u32 start, int count) +{ + struct nvkm_device *device = runl->fifo->engine.subdev.device; + u64 addr = nvkm_memory_addr(memory) + start; + + nvkm_wr32(device, 0x0032f4, addr >> 12); + nvkm_wr32(device, 0x0032ec, count); +} + +static void +nv50_runl_insert_chan(struct nvkm_chan *chan, struct nvkm_memory *memory, u64 offset) +{ + nvkm_wo32(memory, offset, chan->id); +} + +static struct nvkm_memory * +nv50_runl_alloc(struct nvkm_runl *runl, u32 *offset) +{ + const u32 segment = ALIGN((runl->cgrp_nr + runl->chan_nr) * runl->func->size, 0x1000); + const u32 maxsize = (runl->cgid ? runl->cgid->nr : 0) + runl->chid->nr; + int ret; + + if (unlikely(!runl->mem)) { + ret = nvkm_memory_new(runl->fifo->engine.subdev.device, NVKM_MEM_TARGET_INST, + maxsize * 2 * runl->func->size, 0, false, &runl->mem); + if (ret) { + RUNL_ERROR(runl, "alloc %d\n", ret); + return ERR_PTR(ret); + } + } else { + if (runl->offset + segment >= nvkm_memory_size(runl->mem)) { + ret = runl->func->wait(runl); + if (ret) { + RUNL_DEBUG(runl, "rewind timeout"); + return ERR_PTR(ret); + } + + runl->offset = 0; + } + } + + *offset = runl->offset; + runl->offset += segment; + return runl->mem; +} + +int +nv50_runl_update(struct nvkm_runl *runl) +{ + struct nvkm_memory *memory; + struct nvkm_cgrp *cgrp; + struct nvkm_chan *chan; + u32 start, offset, count; + + /*TODO: prio, interleaving. */ + + RUNL_TRACE(runl, "RAMRL: update cgrps:%d chans:%d", runl->cgrp_nr, runl->chan_nr); + memory = nv50_runl_alloc(runl, &start); + if (IS_ERR(memory)) + return PTR_ERR(memory); + + RUNL_TRACE(runl, "RAMRL: update start:%08x", start); + offset = start; + + nvkm_kmap(memory); + nvkm_runl_foreach_cgrp(cgrp, runl) { + if (cgrp->hw) { + CGRP_TRACE(cgrp, " RAMRL+%08x: chans:%d", offset, cgrp->chan_nr); + runl->func->insert_cgrp(cgrp, memory, offset); + offset += runl->func->size; + } + + nvkm_cgrp_foreach_chan(chan, cgrp) { + CHAN_TRACE(chan, "RAMRL+%08x: [%s]", offset, chan->name); + runl->func->insert_chan(chan, memory, offset); + offset += runl->func->size; + } + } + nvkm_done(memory); + + /*TODO: look into using features on newer HW to guarantee forward progress. */ + list_rotate_left(&runl->cgrps); + + count = (offset - start) / runl->func->size; + RUNL_TRACE(runl, "RAMRL: commit start:%08x count:%d", start, count); + + runl->func->commit(runl, memory, start, count); + return 0; +} + +const struct nvkm_runl_func +nv50_runl = { + .size = 4, + .update = nv50_runl_update, + .insert_chan = nv50_runl_insert_chan, + .commit = nv50_runl_commit, + .wait = nv50_runl_wait, + .pending = nv50_runl_pending, +}; + void -nv50_fifo_init(struct nvkm_fifo *base) +nv50_fifo_init(struct nvkm_fifo *fifo) { - struct nv50_fifo *fifo = nv50_fifo(base); - struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_runl *runl = nvkm_runl_first(fifo); + struct nvkm_device *device = fifo->engine.subdev.device; int i; nvkm_mask(device, 0x000200, 0x00000100, 0x00000000); @@ -89,61 +352,47 @@ nv50_fifo_init(struct nvkm_fifo *base) for (i = 0; i < 128; i++) nvkm_wr32(device, 0x002600 + (i * 4), 0x00000000); - nv50_fifo_runlist_update_locked(fifo); + + atomic_set(&runl->changed, 1); + runl->func->update(runl); nvkm_wr32(device, 0x003200, 0x00000001); nvkm_wr32(device, 0x003250, 0x00000001); nvkm_wr32(device, 0x002500, 0x00000001); } -void * -nv50_fifo_dtor(struct nvkm_fifo *base) +int +nv50_fifo_chid_ctor(struct nvkm_fifo *fifo, int nr) { - struct nv50_fifo *fifo = nv50_fifo(base); - nvkm_memory_unref(&fifo->runlist[1]); - nvkm_memory_unref(&fifo->runlist[0]); - return fifo; + /* CHID 0 is unusable (some kind of PIO channel?), 127 is "channel invalid". */ + return nvkm_chid_new(&nvkm_chan_event, &fifo->engine.subdev, nr, 1, nr - 2, &fifo->chid); } int -nv50_fifo_new_(const struct nvkm_fifo_func *func, struct nvkm_device *device, - enum nvkm_subdev_type type, int inst, struct nvkm_fifo **pfifo) +nv50_fifo_chid_nr(struct nvkm_fifo *fifo) { - struct nv50_fifo *fifo; - int ret; - - if (!(fifo = kzalloc(sizeof(*fifo), GFP_KERNEL))) - return -ENOMEM; - *pfifo = &fifo->base; - - ret = nvkm_fifo_ctor(func, device, type, inst, 128, &fifo->base); - if (ret) - return ret; - - set_bit(0, fifo->base.mask); /* PIO channel */ - set_bit(127, fifo->base.mask); /* inactive channel */ - return 0; + return 128; } static const struct nvkm_fifo_func nv50_fifo = { - .dtor = nv50_fifo_dtor, - .oneinit = nv50_fifo_oneinit, + .chid_nr = nv50_fifo_chid_nr, + .chid_ctor = nv50_fifo_chid_ctor, + .runl_ctor = nv04_fifo_runl_ctor, .init = nv50_fifo_init, .intr = nv04_fifo_intr, - .engine_id = nv04_fifo_engine_id, - .id_engine = nv04_fifo_id_engine, .pause = nv04_fifo_pause, .start = nv04_fifo_start, - .chan = { - &nv50_fifo_gpfifo_oclass, - NULL - }, + .runl = &nv50_runl, + .engn = &nv50_engn, + .engn_sw = &nv50_engn_sw, + .cgrp = {{ }, &nv04_cgrp }, + .chan = {{ 0, 0, NV50_CHANNEL_GPFIFO }, &nv50_chan }, }; int nv50_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fifo **pfifo) { - return nv50_fifo_new_(&nv50_fifo, device, type, inst, pfifo); + return nvkm_fifo_new_(&nv50_fifo, device, type, inst, pfifo); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.h deleted file mode 100644 index 0111e7e5a4e3..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.h +++ /dev/null @@ -1,20 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -#ifndef __NV50_FIFO_H__ -#define __NV50_FIFO_H__ -#define nv50_fifo(p) container_of((p), struct nv50_fifo, base) -#include "priv.h" - -struct nv50_fifo { - struct nvkm_fifo base; - struct nvkm_memory *runlist[2]; - int cur_runlist; -}; - -int nv50_fifo_new_(const struct nvkm_fifo_func *, struct nvkm_device *, enum nvkm_subdev_type, int, - struct nvkm_fifo **); - -void *nv50_fifo_dtor(struct nvkm_fifo *); -int nv50_fifo_oneinit(struct nvkm_fifo *); -void nv50_fifo_init(struct nvkm_fifo *); -void nv50_fifo_runlist_update(struct nv50_fifo *); -#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h index 79cec57647f0..4d448be19224 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h @@ -3,46 +3,207 @@ #define __NVKM_FIFO_PRIV_H__ #define nvkm_fifo(p) container_of((p), struct nvkm_fifo, engine) #include <engine/fifo.h> +#include <core/enum.h> +struct nvkm_cctx; +struct nvkm_cgrp; +struct nvkm_engn; +struct nvkm_memory; +struct nvkm_runl; +struct nvkm_runq; +struct nvkm_vctx; -int nvkm_fifo_ctor(const struct nvkm_fifo_func *, struct nvkm_device *, enum nvkm_subdev_type, int, - int nr, struct nvkm_fifo *); -void nvkm_fifo_uevent(struct nvkm_fifo *); -void nvkm_fifo_kevent(struct nvkm_fifo *, int chid); -void nvkm_fifo_recover_chan(struct nvkm_fifo *, int chid); - -struct nvkm_fifo_chan * -nvkm_fifo_chan_inst_locked(struct nvkm_fifo *, u64 inst); - -struct nvkm_fifo_chan_oclass; struct nvkm_fifo_func { - void *(*dtor)(struct nvkm_fifo *); - int (*oneinit)(struct nvkm_fifo *); - int (*info)(struct nvkm_fifo *, u64 mthd, u64 *data); + int (*chid_nr)(struct nvkm_fifo *); + int (*chid_ctor)(struct nvkm_fifo *, int nr); + int (*runq_nr)(struct nvkm_fifo *); + int (*runl_ctor)(struct nvkm_fifo *); + void (*init)(struct nvkm_fifo *); - void (*fini)(struct nvkm_fifo *); - void (*intr)(struct nvkm_fifo *); - void (*fault)(struct nvkm_fifo *, struct nvkm_fault_data *); - int (*engine_id)(struct nvkm_fifo *, struct nvkm_engine *); - struct nvkm_engine *(*id_engine)(struct nvkm_fifo *, int engi); + void (*init_pbdmas)(struct nvkm_fifo *, u32 mask); + + irqreturn_t (*intr)(struct nvkm_inth *); + void (*intr_mmu_fault_unit)(struct nvkm_fifo *, int unit); + void (*intr_ctxsw_timeout)(struct nvkm_fifo *, u32 engm); + + const struct nvkm_fifo_func_mmu_fault { + void (*recover)(struct nvkm_fifo *, struct nvkm_fault_data *); + const struct nvkm_enum *access; + const struct nvkm_enum *engine; + const struct nvkm_enum *reason; + const struct nvkm_enum *hubclient; + const struct nvkm_enum *gpcclient; + } *mmu_fault; + void (*pause)(struct nvkm_fifo *, unsigned long *); void (*start)(struct nvkm_fifo *, unsigned long *); - void (*uevent_init)(struct nvkm_fifo *); - void (*uevent_fini)(struct nvkm_fifo *); - void (*recover_chan)(struct nvkm_fifo *, int chid); - int (*class_get)(struct nvkm_fifo *, int index, struct nvkm_oclass *); - int (*class_new)(struct nvkm_fifo *, const struct nvkm_oclass *, - void *, u32, struct nvkm_object **); - const struct nvkm_fifo_chan_oclass *chan[]; + + int (*nonstall_ctor)(struct nvkm_fifo *); + const struct nvkm_event_func *nonstall; + + const struct nvkm_runl_func *runl; + const struct nvkm_runq_func *runq; + const struct nvkm_engn_func *engn; + const struct nvkm_engn_func *engn_sw; + const struct nvkm_engn_func *engn_ce; + + struct nvkm_fifo_func_cgrp { + struct nvkm_sclass user; + const struct nvkm_cgrp_func *func; + bool force; + } cgrp; + + struct nvkm_fifo_func_chan { + struct nvkm_sclass user; + const struct nvkm_chan_func *func; + } chan; }; -void nv04_fifo_intr(struct nvkm_fifo *); -int nv04_fifo_engine_id(struct nvkm_fifo *, struct nvkm_engine *); -struct nvkm_engine *nv04_fifo_id_engine(struct nvkm_fifo *, int); +int nvkm_fifo_new_(const struct nvkm_fifo_func *, struct nvkm_device *, enum nvkm_subdev_type, int, + struct nvkm_fifo **); + +int nv04_fifo_chid_ctor(struct nvkm_fifo *, int); +int nv04_fifo_runl_ctor(struct nvkm_fifo *); +void nv04_fifo_init(struct nvkm_fifo *); +irqreturn_t nv04_fifo_intr(struct nvkm_inth *); void nv04_fifo_pause(struct nvkm_fifo *, unsigned long *); void nv04_fifo_start(struct nvkm_fifo *, unsigned long *); +extern const struct nvkm_runl_func nv04_runl; +extern const struct nvkm_engn_func nv04_engn; +extern const struct nvkm_cgrp_func nv04_cgrp; +extern const struct nvkm_chan_func_inst nv04_chan_inst; +extern const struct nvkm_chan_func_userd nv04_chan_userd; +void nv04_chan_ramfc_clear(struct nvkm_chan *); +void nv04_chan_start(struct nvkm_chan *); +void nv04_chan_stop(struct nvkm_chan *); +void nv04_eobj_ramht_del(struct nvkm_chan *, int); + +int nv10_fifo_chid_nr(struct nvkm_fifo *); + +int nv50_fifo_chid_nr(struct nvkm_fifo *); +int nv50_fifo_chid_ctor(struct nvkm_fifo *, int); +void nv50_fifo_init(struct nvkm_fifo *); +extern const struct nvkm_runl_func nv50_runl; +int nv50_runl_update(struct nvkm_runl *); +int nv50_runl_wait(struct nvkm_runl *); +extern const struct nvkm_engn_func nv50_engn_sw; +extern const struct nvkm_chan_func_inst nv50_chan_inst; +extern const struct nvkm_chan_func_userd nv50_chan_userd; +void nv50_chan_unbind(struct nvkm_chan *); +void nv50_chan_start(struct nvkm_chan *); +void nv50_chan_stop(struct nvkm_chan *); +void nv50_chan_preempt(struct nvkm_chan *); +int nv50_eobj_ramht_add(struct nvkm_engn *, struct nvkm_object *, struct nvkm_chan *); +void nv50_eobj_ramht_del(struct nvkm_chan *, int); + +extern const struct nvkm_event_func g84_fifo_nonstall; +extern const struct nvkm_engn_func g84_engn; +extern const struct nvkm_chan_func g84_chan; + +int gf100_fifo_chid_ctor(struct nvkm_fifo *, int); +int gf100_fifo_runq_nr(struct nvkm_fifo *); +bool gf100_fifo_intr_pbdma(struct nvkm_fifo *); +void gf100_fifo_intr_mmu_fault(struct nvkm_fifo *); +void gf100_fifo_intr_mmu_fault_unit(struct nvkm_fifo *, int); +void gf100_fifo_intr_sched(struct nvkm_fifo *); +void gf100_fifo_intr_ctxsw_timeout(struct nvkm_fifo *, u32); +void gf100_fifo_mmu_fault_recover(struct nvkm_fifo *, struct nvkm_fault_data *); +extern const struct nvkm_enum gf100_fifo_mmu_fault_access[]; +extern const struct nvkm_event_func gf100_fifo_nonstall; +bool gf100_runl_preempt_pending(struct nvkm_runl *); +void gf100_runq_init(struct nvkm_runq *); +bool gf100_runq_intr(struct nvkm_runq *, struct nvkm_runl *); +void gf100_engn_mmu_fault_trigger(struct nvkm_engn *); +bool gf100_engn_mmu_fault_triggered(struct nvkm_engn *); +extern const struct nvkm_engn_func gf100_engn_sw; +extern const struct nvkm_chan_func_inst gf100_chan_inst; +void gf100_chan_userd_clear(struct nvkm_chan *); +void gf100_chan_preempt(struct nvkm_chan *); + +int gk104_fifo_chid_nr(struct nvkm_fifo *); +int gk104_fifo_runl_ctor(struct nvkm_fifo *); +void gk104_fifo_init(struct nvkm_fifo *); +void gk104_fifo_init_pbdmas(struct nvkm_fifo *, u32); +irqreturn_t gk104_fifo_intr(struct nvkm_inth *); +void gk104_fifo_intr_runlist(struct nvkm_fifo *); +void gk104_fifo_intr_chsw(struct nvkm_fifo *); +void gk104_fifo_intr_bind(struct nvkm_fifo *); +extern const struct nvkm_fifo_func_mmu_fault gk104_fifo_mmu_fault; +extern const struct nvkm_enum gk104_fifo_mmu_fault_reason[]; +extern const struct nvkm_enum gk104_fifo_mmu_fault_hubclient[]; +extern const struct nvkm_enum gk104_fifo_mmu_fault_gpcclient[]; +void gk104_runl_insert_chan(struct nvkm_chan *, struct nvkm_memory *, u64); +void gk104_runl_commit(struct nvkm_runl *, struct nvkm_memory *, u32, int); +bool gk104_runl_pending(struct nvkm_runl *); +void gk104_runl_block(struct nvkm_runl *, u32); +void gk104_runl_allow(struct nvkm_runl *, u32); +void gk104_runl_fault_clear(struct nvkm_runl *); +extern const struct nvkm_runq_func gk104_runq; +void gk104_runq_init(struct nvkm_runq *); +bool gk104_runq_intr(struct nvkm_runq *, struct nvkm_runl *); +extern const struct nvkm_bitfield gk104_runq_intr_0_names[]; +bool gk104_runq_idle(struct nvkm_runq *); +extern const struct nvkm_engn_func gk104_engn; +bool gk104_engn_chsw(struct nvkm_engn *); +int gk104_engn_cxid(struct nvkm_engn *, bool *cgid); +int gk104_ectx_ctor(struct nvkm_engn *, struct nvkm_vctx *); +extern const struct nvkm_engn_func gk104_engn_ce; +extern const struct nvkm_chan_func_userd gk104_chan_userd; +extern const struct nvkm_chan_func_ramfc gk104_chan_ramfc; +void gk104_chan_bind(struct nvkm_chan *); +void gk104_chan_bind_inst(struct nvkm_chan *); +void gk104_chan_unbind(struct nvkm_chan *); +void gk104_chan_start(struct nvkm_chan *); +void gk104_chan_stop(struct nvkm_chan *); + +int gk110_fifo_chid_ctor(struct nvkm_fifo *, int); +extern const struct nvkm_runl_func gk110_runl; +extern const struct nvkm_cgrp_func gk110_cgrp; +void gk110_runl_insert_cgrp(struct nvkm_cgrp *, struct nvkm_memory *, u64); +extern const struct nvkm_chan_func gk110_chan; +void gk110_chan_preempt(struct nvkm_chan *); + +extern const struct nvkm_runq_func gk208_runq; +void gk208_runq_init(struct nvkm_runq *); + +void gm107_fifo_intr_mmu_fault_unit(struct nvkm_fifo *, int); +extern const struct nvkm_fifo_func_mmu_fault gm107_fifo_mmu_fault; +extern const struct nvkm_runl_func gm107_runl; +extern const struct nvkm_chan_func gm107_chan; + +int gm200_fifo_chid_nr(struct nvkm_fifo *); +int gm200_fifo_runq_nr(struct nvkm_fifo *); + +extern const struct nvkm_enum gv100_fifo_mmu_fault_access[]; +extern const struct nvkm_enum gv100_fifo_mmu_fault_reason[]; +extern const struct nvkm_enum gv100_fifo_mmu_fault_hubclient[]; +extern const struct nvkm_enum gv100_fifo_mmu_fault_gpcclient[]; +void gv100_runl_insert_cgrp(struct nvkm_cgrp *, struct nvkm_memory *, u64); +void gv100_runl_insert_chan(struct nvkm_chan *, struct nvkm_memory *, u64); +void gv100_runl_preempt(struct nvkm_runl *); +extern const struct nvkm_runq_func gv100_runq; +extern const struct nvkm_engn_func gv100_engn; +void gv100_ectx_bind(struct nvkm_engn *, struct nvkm_cctx *, struct nvkm_chan *); +extern const struct nvkm_engn_func gv100_engn_ce; +int gv100_ectx_ce_ctor(struct nvkm_engn *, struct nvkm_vctx *); +void gv100_ectx_ce_bind(struct nvkm_engn *, struct nvkm_cctx *, struct nvkm_chan *); +extern const struct nvkm_chan_func_userd gv100_chan_userd; +extern const struct nvkm_chan_func_ramfc gv100_chan_ramfc; + +void tu102_fifo_intr_ctxsw_timeout_info(struct nvkm_engn *, u32 info); +extern const struct nvkm_fifo_func_mmu_fault tu102_fifo_mmu_fault; -void gf100_fifo_intr_fault(struct nvkm_fifo *, int); +int ga100_fifo_runl_ctor(struct nvkm_fifo *); +int ga100_fifo_nonstall_ctor(struct nvkm_fifo *); +extern const struct nvkm_event_func ga100_fifo_nonstall; +extern const struct nvkm_runl_func ga100_runl; +extern const struct nvkm_runq_func ga100_runq; +extern const struct nvkm_engn_func ga100_engn; +extern const struct nvkm_engn_func ga100_engn_ce; +extern const struct nvkm_cgrp_func ga100_cgrp; +extern const struct nvkm_chan_func ga100_chan; -int gk104_fifo_engine_id(struct nvkm_fifo *, struct nvkm_engine *); -struct nvkm_engine *gk104_fifo_id_engine(struct nvkm_fifo *, int); +int nvkm_uchan_new(struct nvkm_fifo *, struct nvkm_cgrp *, const struct nvkm_oclass *, + void *argv, u32 argc, struct nvkm_object **); +int nvkm_ucgrp_new(struct nvkm_fifo *, const struct nvkm_oclass *, void *argv, u32 argc, + struct nvkm_object **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/runl.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/runl.c new file mode 100644 index 000000000000..b5836cbc29aa --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/runl.c @@ -0,0 +1,430 @@ +/* + * 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 "runl.h" +#include "cgrp.h" +#include "chan.h" +#include "chid.h" +#include "priv.h" +#include "runq.h" + +#include <core/gpuobj.h> +#include <subdev/timer.h> +#include <subdev/top.h> + +struct nvkm_cgrp * +nvkm_engn_cgrp_get(struct nvkm_engn *engn, unsigned long *pirqflags) +{ + struct nvkm_cgrp *cgrp = NULL; + struct nvkm_chan *chan; + bool cgid; + int id; + + id = engn->func->cxid(engn, &cgid); + if (id < 0) + return NULL; + + if (!cgid) { + chan = nvkm_runl_chan_get_chid(engn->runl, id, pirqflags); + if (chan) + cgrp = chan->cgrp; + } else { + cgrp = nvkm_runl_cgrp_get_cgid(engn->runl, id, pirqflags); + } + + WARN_ON(!cgrp); + return cgrp; +} + +static void +nvkm_runl_rc(struct nvkm_runl *runl) +{ + struct nvkm_fifo *fifo = runl->fifo; + struct nvkm_cgrp *cgrp, *gtmp; + struct nvkm_chan *chan, *ctmp; + struct nvkm_engn *engn; + unsigned long flags; + int rc, state, i; + bool reset; + + /* Runlist is blocked before scheduling recovery - fetch count. */ + BUG_ON(!mutex_is_locked(&runl->mutex)); + rc = atomic_xchg(&runl->rc_pending, 0); + if (!rc) + return; + + /* Look for channel groups flagged for RC. */ + nvkm_runl_foreach_cgrp_safe(cgrp, gtmp, runl) { + state = atomic_cmpxchg(&cgrp->rc, NVKM_CGRP_RC_PENDING, NVKM_CGRP_RC_RUNNING); + if (state == NVKM_CGRP_RC_PENDING) { + /* Disable all channels in them, and remove from runlist. */ + nvkm_cgrp_foreach_chan_safe(chan, ctmp, cgrp) { + nvkm_chan_error(chan, false); + nvkm_chan_remove_locked(chan); + } + } + } + + /* On GPUs with runlist preempt, wait for PBDMA(s) servicing runlist to go idle. */ + if (runl->func->preempt) { + for (i = 0; i < runl->runq_nr; i++) { + struct nvkm_runq *runq = runl->runq[i]; + + if (runq) { + nvkm_msec(fifo->engine.subdev.device, 2000, + if (runq->func->idle(runq)) + break; + ); + } + } + } + + /* Look for engines that are still on flagged channel groups - reset them. */ + nvkm_runl_foreach_engn_cond(engn, runl, engn->func->cxid) { + cgrp = nvkm_engn_cgrp_get(engn, &flags); + if (!cgrp) { + ENGN_DEBUG(engn, "cxid not valid"); + continue; + } + + reset = atomic_read(&cgrp->rc) == NVKM_CGRP_RC_RUNNING; + nvkm_cgrp_put(&cgrp, flags); + if (!reset) { + ENGN_DEBUG(engn, "cxid not in recovery"); + continue; + } + + ENGN_DEBUG(engn, "resetting..."); + /*TODO: can we do something less of a potential catastrophe on failure? */ + WARN_ON(nvkm_engine_reset(engn->engine)); + } + + /* Submit runlist update, and clear any remaining exception state. */ + runl->func->update(runl); + if (runl->func->fault_clear) + runl->func->fault_clear(runl); + + /* Unblock runlist processing. */ + while (rc--) + nvkm_runl_allow(runl); + runl->func->wait(runl); +} + +static void +nvkm_runl_rc_runl(struct nvkm_runl *runl) +{ + RUNL_ERROR(runl, "rc scheduled"); + + nvkm_runl_block(runl); + if (runl->func->preempt) + runl->func->preempt(runl); + + atomic_inc(&runl->rc_pending); + schedule_work(&runl->work); +} + +void +nvkm_runl_rc_cgrp(struct nvkm_cgrp *cgrp) +{ + if (atomic_cmpxchg(&cgrp->rc, NVKM_CGRP_RC_NONE, NVKM_CGRP_RC_PENDING) != NVKM_CGRP_RC_NONE) + return; + + CGRP_ERROR(cgrp, "rc scheduled"); + nvkm_runl_rc_runl(cgrp->runl); +} + +void +nvkm_runl_rc_engn(struct nvkm_runl *runl, struct nvkm_engn *engn) +{ + struct nvkm_cgrp *cgrp; + unsigned long flags; + + /* Lookup channel group currently on engine. */ + cgrp = nvkm_engn_cgrp_get(engn, &flags); + if (!cgrp) { + ENGN_DEBUG(engn, "rc skipped, not on channel"); + return; + } + + nvkm_runl_rc_cgrp(cgrp); + nvkm_cgrp_put(&cgrp, flags); +} + +static void +nvkm_runl_work(struct work_struct *work) +{ + struct nvkm_runl *runl = container_of(work, typeof(*runl), work); + + mutex_lock(&runl->mutex); + nvkm_runl_rc(runl); + mutex_unlock(&runl->mutex); + +} + +struct nvkm_chan * +nvkm_runl_chan_get_inst(struct nvkm_runl *runl, u64 inst, unsigned long *pirqflags) +{ + struct nvkm_chid *chid = runl->chid; + struct nvkm_chan *chan; + unsigned long flags; + int id; + + spin_lock_irqsave(&chid->lock, flags); + for_each_set_bit(id, chid->used, chid->nr) { + chan = chid->data[id]; + if (likely(chan)) { + if (chan->inst->addr == inst) { + spin_lock(&chan->cgrp->lock); + *pirqflags = flags; + spin_unlock(&chid->lock); + return chan; + } + } + } + spin_unlock_irqrestore(&chid->lock, flags); + return NULL; +} + +struct nvkm_chan * +nvkm_runl_chan_get_chid(struct nvkm_runl *runl, int id, unsigned long *pirqflags) +{ + struct nvkm_chid *chid = runl->chid; + struct nvkm_chan *chan; + unsigned long flags; + + spin_lock_irqsave(&chid->lock, flags); + if (!WARN_ON(id >= chid->nr)) { + chan = chid->data[id]; + if (likely(chan)) { + spin_lock(&chan->cgrp->lock); + *pirqflags = flags; + spin_unlock(&chid->lock); + return chan; + } + } + spin_unlock_irqrestore(&chid->lock, flags); + return NULL; +} + +struct nvkm_cgrp * +nvkm_runl_cgrp_get_cgid(struct nvkm_runl *runl, int id, unsigned long *pirqflags) +{ + struct nvkm_chid *cgid = runl->cgid; + struct nvkm_cgrp *cgrp; + unsigned long flags; + + spin_lock_irqsave(&cgid->lock, flags); + if (!WARN_ON(id >= cgid->nr)) { + cgrp = cgid->data[id]; + if (likely(cgrp)) { + spin_lock(&cgrp->lock); + *pirqflags = flags; + spin_unlock(&cgid->lock); + return cgrp; + } + } + spin_unlock_irqrestore(&cgid->lock, flags); + return NULL; +} + +int +nvkm_runl_preempt_wait(struct nvkm_runl *runl) +{ + return nvkm_msec(runl->fifo->engine.subdev.device, runl->fifo->timeout.chan_msec, + if (!runl->func->preempt_pending(runl)) + break; + + nvkm_runl_rc(runl); + usleep_range(1, 2); + ) < 0 ? -ETIMEDOUT : 0; +} + +bool +nvkm_runl_update_pending(struct nvkm_runl *runl) +{ + if (!runl->func->pending(runl)) + return false; + + nvkm_runl_rc(runl); + return true; +} + +void +nvkm_runl_update_locked(struct nvkm_runl *runl, bool wait) +{ + if (atomic_xchg(&runl->changed, 0) && runl->func->update) { + runl->func->update(runl); + if (wait) + runl->func->wait(runl); + } +} + +void +nvkm_runl_allow(struct nvkm_runl *runl) +{ + struct nvkm_fifo *fifo = runl->fifo; + unsigned long flags; + + spin_lock_irqsave(&fifo->lock, flags); + if (!--runl->blocked) { + RUNL_TRACE(runl, "running"); + runl->func->allow(runl, ~0); + } + spin_unlock_irqrestore(&fifo->lock, flags); +} + +void +nvkm_runl_block(struct nvkm_runl *runl) +{ + struct nvkm_fifo *fifo = runl->fifo; + unsigned long flags; + + spin_lock_irqsave(&fifo->lock, flags); + if (!runl->blocked++) { + RUNL_TRACE(runl, "stopped"); + runl->func->block(runl, ~0); + } + spin_unlock_irqrestore(&fifo->lock, flags); +} + +void +nvkm_runl_fini(struct nvkm_runl *runl) +{ + if (runl->func->fini) + runl->func->fini(runl); + + flush_work(&runl->work); +} + +void +nvkm_runl_del(struct nvkm_runl *runl) +{ + struct nvkm_engn *engn, *engt; + + nvkm_memory_unref(&runl->mem); + + list_for_each_entry_safe(engn, engt, &runl->engns, head) { + list_del(&engn->head); + kfree(engn); + } + + nvkm_chid_unref(&runl->chid); + nvkm_chid_unref(&runl->cgid); + + list_del(&runl->head); + mutex_destroy(&runl->mutex); + kfree(runl); +} + +struct nvkm_engn * +nvkm_runl_add(struct nvkm_runl *runl, int engi, const struct nvkm_engn_func *func, + enum nvkm_subdev_type type, int inst) +{ + struct nvkm_fifo *fifo = runl->fifo; + struct nvkm_device *device = fifo->engine.subdev.device; + struct nvkm_engine *engine; + struct nvkm_engn *engn; + + engine = nvkm_device_engine(device, type, inst); + if (!engine) { + RUNL_DEBUG(runl, "engn %d.%d[%s] not found", engi, inst, nvkm_subdev_type[type]); + return NULL; + } + + if (!(engn = kzalloc(sizeof(*engn), GFP_KERNEL))) + return NULL; + + engn->func = func; + engn->runl = runl; + engn->id = engi; + engn->engine = engine; + engn->fault = -1; + list_add_tail(&engn->head, &runl->engns); + + /* Lookup MMU engine ID for fault handling. */ + if (device->top) + engn->fault = nvkm_top_fault_id(device, engine->subdev.type, engine->subdev.inst); + + if (engn->fault < 0 && fifo->func->mmu_fault) { + const struct nvkm_enum *map = fifo->func->mmu_fault->engine; + + while (map->name) { + if (map->data2 == engine->subdev.type && map->inst == engine->subdev.inst) { + engn->fault = map->value; + break; + } + map++; + } + } + + return engn; +} + +struct nvkm_runl * +nvkm_runl_get(struct nvkm_fifo *fifo, int runi, u32 addr) +{ + struct nvkm_runl *runl; + + nvkm_runl_foreach(runl, fifo) { + if ((runi >= 0 && runl->id == runi) || (runi < 0 && runl->addr == addr)) + return runl; + } + + return NULL; +} + +struct nvkm_runl * +nvkm_runl_new(struct nvkm_fifo *fifo, int runi, u32 addr, int id_nr) +{ + struct nvkm_subdev *subdev = &fifo->engine.subdev; + struct nvkm_runl *runl; + int ret; + + if (!(runl = kzalloc(sizeof(*runl), GFP_KERNEL))) + return NULL; + + runl->func = fifo->func->runl; + runl->fifo = fifo; + runl->id = runi; + runl->addr = addr; + INIT_LIST_HEAD(&runl->engns); + INIT_LIST_HEAD(&runl->cgrps); + atomic_set(&runl->changed, 0); + mutex_init(&runl->mutex); + INIT_WORK(&runl->work, nvkm_runl_work); + atomic_set(&runl->rc_triggered, 0); + atomic_set(&runl->rc_pending, 0); + list_add_tail(&runl->head, &fifo->runls); + + if (!fifo->chid) { + if ((ret = nvkm_chid_new(&nvkm_chan_event, subdev, id_nr, 0, id_nr, &runl->cgid)) || + (ret = nvkm_chid_new(&nvkm_chan_event, subdev, id_nr, 0, id_nr, &runl->chid))) { + RUNL_ERROR(runl, "cgid/chid: %d", ret); + nvkm_runl_del(runl); + return NULL; + } + } else { + runl->cgid = nvkm_chid_ref(fifo->cgid); + runl->chid = nvkm_chid_ref(fifo->chid); + } + + return runl; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/runl.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/runl.h new file mode 100644 index 000000000000..c93d21bb7bd5 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/runl.h @@ -0,0 +1,125 @@ +#ifndef __NVKM_RUNL_H__ +#define __NVKM_RUNL_H__ +#include <core/intr.h> +struct nvkm_cctx; +struct nvkm_cgrp; +struct nvkm_chan; +struct nvkm_memory; +struct nvkm_object; +struct nvkm_vctx; +enum nvkm_subdev_type; + +struct nvkm_engn { + const struct nvkm_engn_func { + bool (*chsw)(struct nvkm_engn *); + int (*cxid)(struct nvkm_engn *, bool *cgid); + void (*mmu_fault_trigger)(struct nvkm_engn *); + bool (*mmu_fault_triggered)(struct nvkm_engn *); + int (*ctor)(struct nvkm_engn *, struct nvkm_vctx *); + void (*bind)(struct nvkm_engn *, struct nvkm_cctx *, struct nvkm_chan *); + int (*ramht_add)(struct nvkm_engn *, struct nvkm_object *, struct nvkm_chan *); + void (*ramht_del)(struct nvkm_chan *, int hash); + } *func; + struct nvkm_runl *runl; + int id; + + struct nvkm_engine *engine; + + int fault; + + struct list_head head; +}; + +#define ENGN_PRINT(e,l,p,f,a...) \ + RUNL_PRINT((e)->runl, l, p, "%02d[%8s]:"f, (e)->id, (e)->engine->subdev.name, ##a) +#define ENGN_DEBUG(e,f,a...) ENGN_PRINT((e), DEBUG, info, " "f"\n", ##a) + +struct nvkm_runl { + const struct nvkm_runl_func { + void (*init)(struct nvkm_runl *); + void (*fini)(struct nvkm_runl *); + int runqs; + u8 size; + int (*update)(struct nvkm_runl *); + void (*insert_cgrp)(struct nvkm_cgrp *, struct nvkm_memory *, u64 offset); + void (*insert_chan)(struct nvkm_chan *, struct nvkm_memory *, u64 offset); + void (*commit)(struct nvkm_runl *, struct nvkm_memory *, u32 start, int count); + int (*wait)(struct nvkm_runl *); + bool (*pending)(struct nvkm_runl *); + void (*block)(struct nvkm_runl *, u32 engm); + void (*allow)(struct nvkm_runl *, u32 engm); + void (*fault_clear)(struct nvkm_runl *); + void (*preempt)(struct nvkm_runl *); + bool (*preempt_pending)(struct nvkm_runl *); + } *func; + struct nvkm_fifo *fifo; + int id; + u32 addr; + u32 chan; + u16 doorbell; + + struct nvkm_chid *cgid; +#define NVKM_CHAN_EVENT_ERRORED BIT(0) + struct nvkm_chid *chid; + + struct list_head engns; + + struct nvkm_runq *runq[2]; + int runq_nr; + + struct nvkm_inth inth; + + struct list_head cgrps; + int cgrp_nr; + int chan_nr; + atomic_t changed; + struct nvkm_memory *mem; + u32 offset; + struct mutex mutex; + + int blocked; + + struct work_struct work; + atomic_t rc_triggered; + atomic_t rc_pending; + + struct list_head head; +}; + +struct nvkm_runl *nvkm_runl_new(struct nvkm_fifo *, int runi, u32 addr, int id_nr); +struct nvkm_runl *nvkm_runl_get(struct nvkm_fifo *, int runi, u32 addr); +struct nvkm_engn *nvkm_runl_add(struct nvkm_runl *, int engi, const struct nvkm_engn_func *, + enum nvkm_subdev_type, int inst); +void nvkm_runl_del(struct nvkm_runl *); +void nvkm_runl_fini(struct nvkm_runl *); +void nvkm_runl_block(struct nvkm_runl *); +void nvkm_runl_allow(struct nvkm_runl *); +void nvkm_runl_update_locked(struct nvkm_runl *, bool wait); +bool nvkm_runl_update_pending(struct nvkm_runl *); +int nvkm_runl_preempt_wait(struct nvkm_runl *); + +void nvkm_runl_rc_engn(struct nvkm_runl *, struct nvkm_engn *); +void nvkm_runl_rc_cgrp(struct nvkm_cgrp *); + +struct nvkm_cgrp *nvkm_runl_cgrp_get_cgid(struct nvkm_runl *, int cgid, unsigned long *irqflags); +struct nvkm_chan *nvkm_runl_chan_get_chid(struct nvkm_runl *, int chid, unsigned long *irqflags); +struct nvkm_chan *nvkm_runl_chan_get_inst(struct nvkm_runl *, u64 inst, unsigned long *irqflags); + +#define nvkm_runl_find_engn(engn,runl,cond) nvkm_list_find(engn, &(runl)->engns, head, (cond)) + +#define nvkm_runl_first(fifo) list_first_entry(&(fifo)->runls, struct nvkm_runl, head) +#define nvkm_runl_foreach(runl,fifo) list_for_each_entry((runl), &(fifo)->runls, head) +#define nvkm_runl_foreach_cond(runl,fifo,cond) nvkm_list_foreach(runl, &(fifo)->runls, head, (cond)) +#define nvkm_runl_foreach_engn(engn,runl) list_for_each_entry((engn), &(runl)->engns, head) +#define nvkm_runl_foreach_engn_cond(engn,runl,cond) \ + nvkm_list_foreach(engn, &(runl)->engns, head, (cond)) +#define nvkm_runl_foreach_cgrp(cgrp,runl) list_for_each_entry((cgrp), &(runl)->cgrps, head) +#define nvkm_runl_foreach_cgrp_safe(cgrp,gtmp,runl) \ + list_for_each_entry_safe((cgrp), (gtmp), &(runl)->cgrps, head) + +#define RUNL_PRINT(r,l,p,f,a...) \ + nvkm_printk__(&(r)->fifo->engine.subdev, NV_DBG_##l, p, "%06x:"f, (r)->addr, ##a) +#define RUNL_ERROR(r,f,a...) RUNL_PRINT((r), ERROR, err, " "f"\n", ##a) +#define RUNL_DEBUG(r,f,a...) RUNL_PRINT((r), DEBUG, info, " "f"\n", ##a) +#define RUNL_TRACE(r,f,a...) RUNL_PRINT((r), TRACE, info, " "f"\n", ##a) +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/runq.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/runq.c new file mode 100644 index 000000000000..33bcf5fb3ef0 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/runq.c @@ -0,0 +1,45 @@ +/* + * 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 "runq.h" +#include "priv.h" + +void +nvkm_runq_del(struct nvkm_runq *runq) +{ + list_del(&runq->head); + kfree(runq); +} + +struct nvkm_runq * +nvkm_runq_new(struct nvkm_fifo *fifo, int pbid) +{ + struct nvkm_runq *runq; + + if (!(runq = kzalloc(sizeof(*runq), GFP_KERNEL))) + return NULL; + + runq->func = fifo->func->runq; + runq->fifo = fifo; + runq->id = pbid; + list_add_tail(&runq->head, &fifo->runqs); + return runq; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/runq.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/runq.h new file mode 100644 index 000000000000..2cb4836e8b31 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/runq.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: MIT */ +#ifndef __NVKM_RUNQ_H__ +#define __NVKM_RUNQ_H__ +#include <core/os.h> +struct nvkm_runl; + +struct nvkm_runq { + const struct nvkm_runq_func { + void (*init)(struct nvkm_runq *); + bool (*intr)(struct nvkm_runq *, struct nvkm_runl *); + const struct nvkm_bitfield *intr_0_names; + bool (*intr_1_ctxnotvalid)(struct nvkm_runq *, int chid); + bool (*idle)(struct nvkm_runq *); + } *func; + struct nvkm_fifo *fifo; + int id; + + struct list_head head; +}; + +struct nvkm_runq *nvkm_runq_new(struct nvkm_fifo *, int pbid); +void nvkm_runq_del(struct nvkm_runq *); + +#define nvkm_runq_foreach(runq,fifo) list_for_each_entry((runq), &(fifo)->runqs, head) +#define nvkm_runq_foreach_cond(runq,fifo,cond) nvkm_list_foreach(runq, &(fifo)->runqs, head, (cond)) + +#define RUNQ_PRINT(r,l,p,f,a...) \ + nvkm_printk__(&(r)->fifo->engine.subdev, NV_DBG_##l, p, "PBDMA%d:"f, (r)->id, ##a) +#define RUNQ_ERROR(r,f,a...) RUNQ_PRINT((r), ERROR, err, " "f"\n", ##a) +#define RUNQ_DEBUG(r,f,a...) RUNQ_PRINT((r), DEBUG, info, " "f"\n", ##a) +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/tu102.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/tu102.c index 260b197f81bc..ea9e151dbb48 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/tu102.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/tu102.c @@ -19,46 +19,83 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ -#include "gk104.h" +#include "priv.h" #include "cgrp.h" -#include "changk104.h" -#include "user.h" +#include "chan.h" +#include "runl.h" -#include <core/client.h> -#include <core/gpuobj.h> -#include <subdev/bar.h> -#include <subdev/fault.h> -#include <subdev/top.h> -#include <subdev/timer.h> -#include <engine/sw.h> +#include <core/memory.h> +#include <subdev/mc.h> +#include <subdev/vfn.h> #include <nvif/class.h> +static u32 +tu102_chan_doorbell_handle(struct nvkm_chan *chan) +{ + return (chan->cgrp->runl->id << 16) | chan->id; +} + static void -tu102_fifo_runlist_commit(struct gk104_fifo *fifo, int runl, - struct nvkm_memory *mem, int nr) +tu102_chan_start(struct nvkm_chan *chan) { - struct nvkm_device *device = fifo->base.engine.subdev.device; - u64 addr = nvkm_memory_addr(mem); - /*XXX: target? */ + struct nvkm_device *device = chan->cgrp->runl->fifo->engine.subdev.device; + + gk104_chan_start(chan); + nvkm_wr32(device, device->vfn->addr.user + 0x0090, chan->func->doorbell_handle(chan)); +} + +static const struct nvkm_chan_func +tu102_chan = { + .inst = &gf100_chan_inst, + .userd = &gv100_chan_userd, + .ramfc = &gv100_chan_ramfc, + .bind = gk104_chan_bind_inst, + .unbind = gk104_chan_unbind, + .start = tu102_chan_start, + .stop = gk104_chan_stop, + .preempt = gk110_chan_preempt, + .doorbell_handle = tu102_chan_doorbell_handle, +}; + +static bool +tu102_runl_pending(struct nvkm_runl *runl) +{ + struct nvkm_device *device = runl->fifo->engine.subdev.device; + + return nvkm_rd32(device, 0x002b0c + (runl->id * 0x10)) & 0x00008000; +} - nvkm_wr32(device, 0x002b00 + (runl * 0x10), lower_32_bits(addr)); - nvkm_wr32(device, 0x002b04 + (runl * 0x10), upper_32_bits(addr)); - nvkm_wr32(device, 0x002b08 + (runl * 0x10), nr); +static void +tu102_runl_commit(struct nvkm_runl *runl, struct nvkm_memory *memory, u32 start, int count) +{ + struct nvkm_device *device = runl->fifo->engine.subdev.device; + u64 addr = nvkm_memory_addr(memory) + start; + /*XXX: target? */ - /*XXX: how to wait? can you even wait? */ + nvkm_wr32(device, 0x002b00 + (runl->id * 0x10), lower_32_bits(addr)); + nvkm_wr32(device, 0x002b04 + (runl->id * 0x10), upper_32_bits(addr)); + nvkm_wr32(device, 0x002b08 + (runl->id * 0x10), count); } -static const struct gk104_fifo_runlist_func -tu102_fifo_runlist = { +static const struct nvkm_runl_func +tu102_runl = { + .runqs = 2, .size = 16, - .cgrp = gv100_fifo_runlist_cgrp, - .chan = gv100_fifo_runlist_chan, - .commit = tu102_fifo_runlist_commit, + .update = nv50_runl_update, + .insert_cgrp = gv100_runl_insert_cgrp, + .insert_chan = gv100_runl_insert_chan, + .commit = tu102_runl_commit, + .wait = nv50_runl_wait, + .pending = tu102_runl_pending, + .block = gk104_runl_block, + .allow = gk104_runl_allow, + .preempt = gv100_runl_preempt, + .preempt_pending = gf100_runl_preempt_pending, }; static const struct nvkm_enum -tu102_fifo_fault_engine[] = { +tu102_fifo_mmu_fault_engine[] = { { 0x01, "DISPLAY" }, { 0x03, "PTP" }, { 0x06, "PWR_PMU" }, @@ -85,305 +122,82 @@ tu102_fifo_fault_engine[] = { {} }; -static void -tu102_fifo_pbdma_init(struct gk104_fifo *fifo) -{ - struct nvkm_device *device = fifo->base.engine.subdev.device; - const u32 mask = (1 << fifo->pbdma_nr) - 1; - /*XXX: this is a bit of a guess at this point in time. */ - nvkm_mask(device, 0xb65000, 0x80000fff, 0x80000000 | mask); -} - -static const struct gk104_fifo_pbdma_func -tu102_fifo_pbdma = { - .nr = gm200_fifo_pbdma_nr, - .init = tu102_fifo_pbdma_init, - .init_timeout = gk208_fifo_pbdma_init_timeout, -}; - -static const struct gk104_fifo_func -tu102_fifo = { - .pbdma = &tu102_fifo_pbdma, - .fault.access = gv100_fifo_fault_access, - .fault.engine = tu102_fifo_fault_engine, - .fault.reason = gv100_fifo_fault_reason, - .fault.hubclient = gv100_fifo_fault_hubclient, - .fault.gpcclient = gv100_fifo_fault_gpcclient, - .runlist = &tu102_fifo_runlist, - .user = {{-1,-1,VOLTA_USERMODE_A }, tu102_fifo_user_new }, - .chan = {{ 0, 0,TURING_CHANNEL_GPFIFO_A}, tu102_fifo_gpfifo_new }, - .cgrp_force = true, +const struct nvkm_fifo_func_mmu_fault +tu102_fifo_mmu_fault = { + .recover = gf100_fifo_mmu_fault_recover, + .access = gv100_fifo_mmu_fault_access, + .engine = tu102_fifo_mmu_fault_engine, + .reason = gv100_fifo_mmu_fault_reason, + .hubclient = gv100_fifo_mmu_fault_hubclient, + .gpcclient = gv100_fifo_mmu_fault_gpcclient, }; -static void -tu102_fifo_recover_work(struct work_struct *w) +void +tu102_fifo_intr_ctxsw_timeout_info(struct nvkm_engn *engn, u32 info) { - struct gk104_fifo *fifo = container_of(w, typeof(*fifo), recover.work); - struct nvkm_device *device = fifo->base.engine.subdev.device; - struct nvkm_engine *engine; + struct nvkm_runl *runl = engn->runl; + struct nvkm_cgrp *cgrp; unsigned long flags; - u32 engm, runm, todo; - int engn, runl; - - spin_lock_irqsave(&fifo->base.lock, flags); - runm = fifo->recover.runm; - engm = fifo->recover.engm; - fifo->recover.engm = 0; - fifo->recover.runm = 0; - spin_unlock_irqrestore(&fifo->base.lock, flags); - - nvkm_mask(device, 0x002630, runm, runm); - - for (todo = engm; engn = __ffs(todo), todo; todo &= ~BIT(engn)) { - if ((engine = fifo->engine[engn].engine)) { - nvkm_subdev_fini(&engine->subdev, false); - WARN_ON(nvkm_subdev_init(&engine->subdev)); - } - } - - for (todo = runm; runl = __ffs(todo), todo; todo &= ~BIT(runl)) - gk104_fifo_runlist_update(fifo, runl); - - nvkm_mask(device, 0x002630, runm, 0x00000000); -} - -static void tu102_fifo_recover_engn(struct gk104_fifo *fifo, int engn); - -static void -tu102_fifo_recover_runl(struct gk104_fifo *fifo, int runl) -{ - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; - struct nvkm_device *device = subdev->device; - const u32 runm = BIT(runl); - - assert_spin_locked(&fifo->base.lock); - if (fifo->recover.runm & runm) - return; - fifo->recover.runm |= runm; - - /* Block runlist to prevent channel assignment(s) from changing. */ - nvkm_mask(device, 0x002630, runm, runm); - - /* Schedule recovery. */ - nvkm_warn(subdev, "runlist %d: scheduled for recovery\n", runl); - schedule_work(&fifo->recover.work); -} - -static struct gk104_fifo_chan * -tu102_fifo_recover_chid(struct gk104_fifo *fifo, int runl, int chid) -{ - struct gk104_fifo_chan *chan; - struct nvkm_fifo_cgrp *cgrp; - - list_for_each_entry(chan, &fifo->runlist[runl].chan, head) { - if (chan->base.chid == chid) { - list_del_init(&chan->head); - return chan; - } - } - - list_for_each_entry(cgrp, &fifo->runlist[runl].cgrp, head) { - if (cgrp->id == chid) { - chan = list_first_entry(&cgrp->chan, typeof(*chan), head); - list_del_init(&chan->head); - if (!--cgrp->chan_nr) - list_del_init(&cgrp->head); - return chan; - } - } - - return NULL; -} -static void -tu102_fifo_recover_chan(struct nvkm_fifo *base, int chid) -{ - struct gk104_fifo *fifo = gk104_fifo(base); - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; - struct nvkm_device *device = subdev->device; - const u32 stat = nvkm_rd32(device, 0x800004 + (chid * 0x08)); - const u32 runl = (stat & 0x000f0000) >> 16; - const bool used = (stat & 0x00000001); - unsigned long engn, engm = fifo->runlist[runl].engm; - struct gk104_fifo_chan *chan; - - assert_spin_locked(&fifo->base.lock); - if (!used) + /* Check that engine hasn't become unstuck since timeout raised. */ + ENGN_DEBUG(engn, "CTXSW_TIMEOUT %08x", info); + if (info & 0xc0000000) return; - /* Lookup SW state for channel, and mark it as dead. */ - chan = tu102_fifo_recover_chid(fifo, runl, chid); - if (chan) { - chan->killed = true; - nvkm_fifo_kevent(&fifo->base, chid); - } - - /* Disable channel. */ - nvkm_wr32(device, 0x800004 + (chid * 0x08), stat | 0x00000800); - nvkm_warn(subdev, "channel %d: killed\n", chid); - - /* Block channel assignments from changing during recovery. */ - tu102_fifo_recover_runl(fifo, runl); - - /* Schedule recovery for any engines the channel is on. */ - for_each_set_bit(engn, &engm, fifo->engine_nr) { - struct gk104_fifo_engine_status status; - - gk104_fifo_engine_status(fifo, engn, &status); - if (!status.chan || status.chan->id != chid) - continue; - tu102_fifo_recover_engn(fifo, engn); + /* Determine channel group the engine is stuck on, and schedule recovery. */ + switch (info & 0x0000c000) { + case 0x00004000: /* LOAD */ + cgrp = nvkm_runl_cgrp_get_cgid(runl, info & 0x3fff0000, &flags); + break; + case 0x00008000: /* SAVE */ + case 0x0000c000: /* SWITCH */ + cgrp = nvkm_runl_cgrp_get_cgid(runl, info & 0x00003fff, &flags); + break; + default: + cgrp = NULL; + break; } -} - -static void -tu102_fifo_recover_engn(struct gk104_fifo *fifo, int engn) -{ - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; - struct nvkm_device *device = subdev->device; - const u32 runl = fifo->engine[engn].runl; - const u32 engm = BIT(engn); - struct gk104_fifo_engine_status status; - - assert_spin_locked(&fifo->base.lock); - if (fifo->recover.engm & engm) - return; - fifo->recover.engm |= engm; - /* Block channel assignments from changing during recovery. */ - tu102_fifo_recover_runl(fifo, runl); - - /* Determine which channel (if any) is currently on the engine. */ - gk104_fifo_engine_status(fifo, engn, &status); - if (status.chan) { - /* The channel is not longer viable, kill it. */ - tu102_fifo_recover_chan(&fifo->base, status.chan->id); + if (!WARN_ON(!cgrp)) { + nvkm_runl_rc_cgrp(cgrp); + nvkm_cgrp_put(&cgrp, flags); } - - /* Preempt the runlist */ - nvkm_wr32(device, 0x2638, BIT(runl)); - - /* Schedule recovery. */ - nvkm_warn(subdev, "engine %d: scheduled for recovery\n", engn); - schedule_work(&fifo->recover.work); } static void -tu102_fifo_fault(struct nvkm_fifo *base, struct nvkm_fault_data *info) +tu102_fifo_intr_ctxsw_timeout(struct nvkm_fifo *fifo) { - struct gk104_fifo *fifo = gk104_fifo(base); - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; - struct nvkm_device *device = subdev->device; - const struct nvkm_enum *er, *ee, *ec, *ea; - struct nvkm_engine *engine = NULL; - struct nvkm_fifo_chan *chan; - unsigned long flags; - const char *en = ""; - char ct[8] = "HUB/"; - int engn; - - er = nvkm_enum_find(fifo->func->fault.reason, info->reason); - ee = nvkm_enum_find(fifo->func->fault.engine, info->engine); - if (info->hub) { - ec = nvkm_enum_find(fifo->func->fault.hubclient, info->client); - } else { - ec = nvkm_enum_find(fifo->func->fault.gpcclient, info->client); - snprintf(ct, sizeof(ct), "GPC%d/", info->gpc); - } - ea = nvkm_enum_find(fifo->func->fault.access, info->access); - - if (ee && ee->data2) { - switch (ee->data2) { - case NVKM_SUBDEV_BAR: - nvkm_bar_bar1_reset(device); - break; - case NVKM_SUBDEV_INSTMEM: - nvkm_bar_bar2_reset(device); - break; - case NVKM_ENGINE_IFB: - nvkm_mask(device, 0x001718, 0x00000000, 0x00000000); - break; - default: - engine = nvkm_device_engine(device, ee->data2, 0); - break; - } - } - - if (ee == NULL) { - struct nvkm_subdev *subdev = nvkm_top_fault(device, info->engine); - if (subdev) { - if (subdev->func == &nvkm_engine) - engine = container_of(subdev, typeof(*engine), subdev); - en = engine->subdev.name; + struct nvkm_device *device = fifo->engine.subdev.device; + struct nvkm_runl *runl; + struct nvkm_engn *engn; + u32 engm = nvkm_rd32(device, 0x002a30); + u32 info; + + nvkm_runl_foreach(runl, fifo) { + nvkm_runl_foreach_engn_cond(engn, runl, engm & BIT(engn->id)) { + info = nvkm_rd32(device, 0x003200 + (engn->id * 4)); + tu102_fifo_intr_ctxsw_timeout_info(engn, info); } - } else { - en = ee->name; } - spin_lock_irqsave(&fifo->base.lock, flags); - chan = nvkm_fifo_chan_inst_locked(&fifo->base, info->inst); - - nvkm_error(subdev, - "fault %02x [%s] at %016llx engine %02x [%s] client %02x " - "[%s%s] reason %02x [%s] on channel %d [%010llx %s]\n", - info->access, ea ? ea->name : "", info->addr, - info->engine, ee ? ee->name : en, - info->client, ct, ec ? ec->name : "", - info->reason, er ? er->name : "", chan ? chan->chid : -1, - info->inst, chan ? chan->object.client->name : "unknown"); - - /* Kill the channel that caused the fault. */ - if (chan) - tu102_fifo_recover_chan(&fifo->base, chan->chid); - - /* Channel recovery will probably have already done this for the - * correct engine(s), but just in case we can't find the channel - * information... - */ - for (engn = 0; engn < fifo->engine_nr && engine; engn++) { - if (fifo->engine[engn].engine == engine) { - tu102_fifo_recover_engn(fifo, engn); - break; - } - } - - spin_unlock_irqrestore(&fifo->base.lock, flags); -} - -static void -tu102_fifo_intr_ctxsw_timeout(struct gk104_fifo *fifo) -{ - struct nvkm_device *device = fifo->base.engine.subdev.device; - unsigned long flags, engm; - u32 engn; - - spin_lock_irqsave(&fifo->base.lock, flags); - - engm = nvkm_rd32(device, 0x2a30); - nvkm_wr32(device, 0x2a30, engm); - - for_each_set_bit(engn, &engm, 32) - tu102_fifo_recover_engn(fifo, engn); - - spin_unlock_irqrestore(&fifo->base.lock, flags); + nvkm_wr32(device, 0x002a30, engm); } static void -tu102_fifo_intr_sched(struct gk104_fifo *fifo) +tu102_fifo_intr_sched(struct nvkm_fifo *fifo) { - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; - struct nvkm_device *device = subdev->device; - u32 intr = nvkm_rd32(device, 0x00254c); + struct nvkm_subdev *subdev = &fifo->engine.subdev; + u32 intr = nvkm_rd32(subdev->device, 0x00254c); u32 code = intr & 0x000000ff; nvkm_error(subdev, "SCHED_ERROR %02x\n", code); } -static void -tu102_fifo_intr(struct nvkm_fifo *base) +static irqreturn_t +tu102_fifo_intr(struct nvkm_inth *inth) { - struct gk104_fifo *fifo = gk104_fifo(base); - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_fifo *fifo = container_of(inth, typeof(*fifo), engine.subdev.inth); + struct nvkm_subdev *subdev = &fifo->engine.subdev; struct nvkm_device *device = subdev->device; u32 mask = nvkm_rd32(device, 0x002140); u32 stat = nvkm_rd32(device, 0x002100) & mask; @@ -412,17 +226,8 @@ tu102_fifo_intr(struct nvkm_fifo *base) } if (stat & 0x20000000) { - u32 mask = nvkm_rd32(device, 0x0025a0); - - while (mask) { - u32 unit = __ffs(mask); - - gk104_fifo_intr_pbdma_0(fifo, unit); - gk104_fifo_intr_pbdma_1(fifo, unit); - nvkm_wr32(device, 0x0025a0, (1 << unit)); - mask &= ~(1 << unit); - } - stat &= ~0x20000000; + if (gf100_fifo_intr_pbdma(fifo)) + stat &= ~0x20000000; } if (stat & 0x40000000) { @@ -432,46 +237,50 @@ tu102_fifo_intr(struct nvkm_fifo *base) if (stat & 0x80000000) { nvkm_wr32(device, 0x002100, 0x80000000); - gk104_fifo_intr_engine(fifo); + nvkm_event_ntfy(&fifo->nonstall.event, 0, NVKM_FIFO_NONSTALL_EVENT); stat &= ~0x80000000; } if (stat) { nvkm_error(subdev, "INTR %08x\n", stat); + spin_lock(&fifo->lock); nvkm_mask(device, 0x002140, stat, 0x00000000); + spin_unlock(&fifo->lock); nvkm_wr32(device, 0x002100, stat); } + + return IRQ_HANDLED; +} + +static void +tu102_fifo_init_pbdmas(struct nvkm_fifo *fifo, u32 mask) +{ + /* Not directly related to PBDMAs, but, enables doorbell to function. */ + nvkm_mask(fifo->engine.subdev.device, 0xb65000, 0x80000000, 0x80000000); } static const struct nvkm_fifo_func -tu102_fifo_ = { - .dtor = gk104_fifo_dtor, - .oneinit = gk104_fifo_oneinit, - .info = gk104_fifo_info, +tu102_fifo = { + .chid_nr = gm200_fifo_chid_nr, + .chid_ctor = gk110_fifo_chid_ctor, + .runq_nr = gm200_fifo_runq_nr, + .runl_ctor = gk104_fifo_runl_ctor, .init = gk104_fifo_init, - .fini = gk104_fifo_fini, + .init_pbdmas = tu102_fifo_init_pbdmas, .intr = tu102_fifo_intr, - .fault = tu102_fifo_fault, - .engine_id = gk104_fifo_engine_id, - .id_engine = gk104_fifo_id_engine, - .uevent_init = gk104_fifo_uevent_init, - .uevent_fini = gk104_fifo_uevent_fini, - .recover_chan = tu102_fifo_recover_chan, - .class_get = gk104_fifo_class_get, - .class_new = gk104_fifo_class_new, + .mmu_fault = &tu102_fifo_mmu_fault, + .nonstall = &gf100_fifo_nonstall, + .runl = &tu102_runl, + .runq = &gv100_runq, + .engn = &gv100_engn, + .engn_ce = &gv100_engn_ce, + .cgrp = {{ 0, 0, KEPLER_CHANNEL_GROUP_A }, &gk110_cgrp, .force = true }, + .chan = {{ 0, 0, TURING_CHANNEL_GPFIFO_A }, &tu102_chan }, }; int tu102_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fifo **pfifo) { - struct gk104_fifo *fifo; - - if (!(fifo = kzalloc(sizeof(*fifo), GFP_KERNEL))) - return -ENOMEM; - fifo->func = &tu102_fifo; - INIT_WORK(&fifo->recover.work, tu102_fifo_recover_work); - *pfifo = &fifo->base; - - return nvkm_fifo_ctor(&tu102_fifo_, device, type, inst, 4096, &fifo->base); + return nvkm_fifo_new_(&tu102_fifo, device, type, inst, pfifo); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ucgrp.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ucgrp.c new file mode 100644 index 000000000000..52c594dfb1b8 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ucgrp.c @@ -0,0 +1,125 @@ +/* + * 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_ucgrp(p) container_of((p), struct nvkm_ucgrp, object) +#include "priv.h" +#include "cgrp.h" +#include "runl.h" + +#include <subdev/mmu.h> + +#include <nvif/if0021.h> + +struct nvkm_ucgrp { + struct nvkm_object object; + struct nvkm_cgrp *cgrp; +}; + +static int +nvkm_ucgrp_chan_new(const struct nvkm_oclass *oclass, void *argv, u32 argc, + struct nvkm_object **pobject) +{ + struct nvkm_cgrp *cgrp = nvkm_ucgrp(oclass->parent)->cgrp; + + return nvkm_uchan_new(cgrp->runl->fifo, cgrp, oclass, argv, argc, pobject); +} + +static int +nvkm_ucgrp_sclass(struct nvkm_object *object, int index, struct nvkm_oclass *oclass) +{ + struct nvkm_cgrp *cgrp = nvkm_ucgrp(object)->cgrp; + struct nvkm_fifo *fifo = cgrp->runl->fifo; + const struct nvkm_fifo_func_chan *chan = &fifo->func->chan; + int c = 0; + + /* *_CHANNEL_GPFIFO_* */ + if (chan->user.oclass) { + if (c++ == index) { + oclass->base = chan->user; + oclass->ctor = nvkm_ucgrp_chan_new; + return 0; + } + } + + return -EINVAL; +} + +static void * +nvkm_ucgrp_dtor(struct nvkm_object *object) +{ + struct nvkm_ucgrp *ucgrp = nvkm_ucgrp(object); + + nvkm_cgrp_unref(&ucgrp->cgrp); + return ucgrp; +} + +static const struct nvkm_object_func +nvkm_ucgrp = { + .dtor = nvkm_ucgrp_dtor, + .sclass = nvkm_ucgrp_sclass, +}; + +int +nvkm_ucgrp_new(struct nvkm_fifo *fifo, const struct nvkm_oclass *oclass, void *argv, u32 argc, + struct nvkm_object **pobject) +{ + union nvif_cgrp_args *args = argv; + struct nvkm_runl *runl; + struct nvkm_vmm *vmm; + struct nvkm_ucgrp *ucgrp; + int ret; + + if (argc < sizeof(args->v0) || args->v0.version != 0) + return -ENOSYS; + argc -= sizeof(args->v0); + + if (args->v0.namelen != argc) + return -EINVAL; + + /* Lookup objects referenced in args. */ + runl = nvkm_runl_get(fifo, args->v0.runlist, 0); + if (!runl) + return -EINVAL; + + vmm = nvkm_uvmm_search(oclass->client, args->v0.vmm); + if (IS_ERR(vmm)) + return PTR_ERR(vmm); + + /* Allocate channel group. */ + if (!(ucgrp = kzalloc(sizeof(*ucgrp), GFP_KERNEL))) { + ret = -ENOMEM; + goto done; + } + + nvkm_object_ctor(&nvkm_ucgrp, oclass, &ucgrp->object); + *pobject = &ucgrp->object; + + ret = nvkm_cgrp_new(runl, args->v0.name, vmm, true, &ucgrp->cgrp); + if (ret) + goto done; + + /* Return channel group info to caller. */ + args->v0.cgid = ucgrp->cgrp->id; + +done: + nvkm_vmm_unref(&vmm); + return ret; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/uchan.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/uchan.c new file mode 100644 index 000000000000..1dac95ae7b43 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/uchan.c @@ -0,0 +1,409 @@ +/* + * 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_uchan(p) container_of((p), struct nvkm_uchan, object) +#include "priv.h" +#include "cgrp.h" +#include "chan.h" +#include "chid.h" +#include "runl.h" + +#include <core/gpuobj.h> +#include <core/oproxy.h> +#include <subdev/mmu.h> +#include <engine/dma.h> + +#include <nvif/if0020.h> + +struct nvkm_uchan { + struct nvkm_object object; + struct nvkm_chan *chan; +}; + +static int +nvkm_uchan_uevent(struct nvkm_object *object, void *argv, u32 argc, struct nvkm_uevent *uevent) +{ + struct nvkm_chan *chan = nvkm_uchan(object)->chan; + struct nvkm_runl *runl = chan->cgrp->runl; + union nvif_chan_event_args *args = argv; + + if (!uevent) + return 0; + if (argc != sizeof(args->v0) || args->v0.version != 0) + return -ENOSYS; + + switch (args->v0.type) { + case NVIF_CHAN_EVENT_V0_NON_STALL_INTR: + return nvkm_uevent_add(uevent, &runl->fifo->nonstall.event, 0, + NVKM_FIFO_NONSTALL_EVENT, NULL); + case NVIF_CHAN_EVENT_V0_KILLED: + return nvkm_uevent_add(uevent, &runl->chid->event, chan->id, + NVKM_CHAN_EVENT_ERRORED, NULL); + default: + break; + } + + return -ENOSYS; +} + +struct nvkm_uobj { + struct nvkm_oproxy oproxy; + struct nvkm_chan *chan; + struct nvkm_cctx *cctx; + int hash; +}; + +static int +nvkm_uchan_object_fini_1(struct nvkm_oproxy *oproxy, bool suspend) +{ + struct nvkm_uobj *uobj = container_of(oproxy, typeof(*uobj), oproxy); + struct nvkm_chan *chan = uobj->chan; + struct nvkm_cctx *cctx = uobj->cctx; + struct nvkm_ectx *ectx = cctx->vctx->ectx; + + if (!ectx->object) + return 0; + + /* Unbind engine context from channel, if no longer required. */ + if (refcount_dec_and_mutex_lock(&cctx->uses, &chan->cgrp->mutex)) { + nvkm_chan_cctx_bind(chan, ectx->engn, NULL); + + if (refcount_dec_and_test(&ectx->uses)) + nvkm_object_fini(ectx->object, false); + mutex_unlock(&chan->cgrp->mutex); + } + + return 0; +} + +static int +nvkm_uchan_object_init_0(struct nvkm_oproxy *oproxy) +{ + struct nvkm_uobj *uobj = container_of(oproxy, typeof(*uobj), oproxy); + struct nvkm_chan *chan = uobj->chan; + struct nvkm_cctx *cctx = uobj->cctx; + struct nvkm_ectx *ectx = cctx->vctx->ectx; + int ret = 0; + + if (!ectx->object) + return 0; + + /* Bind engine context to channel, if it hasn't been already. */ + if (!refcount_inc_not_zero(&cctx->uses)) { + mutex_lock(&chan->cgrp->mutex); + if (!refcount_inc_not_zero(&cctx->uses)) { + if (!refcount_inc_not_zero(&ectx->uses)) { + ret = nvkm_object_init(ectx->object); + if (ret == 0) + refcount_set(&ectx->uses, 1); + } + + if (ret == 0) { + nvkm_chan_cctx_bind(chan, ectx->engn, cctx); + refcount_set(&cctx->uses, 1); + } + } + mutex_unlock(&chan->cgrp->mutex); + } + + return ret; +} + +static void +nvkm_uchan_object_dtor(struct nvkm_oproxy *oproxy) +{ + struct nvkm_uobj *uobj = container_of(oproxy, typeof(*uobj), oproxy); + struct nvkm_engn *engn; + + if (!uobj->cctx) + return; + + engn = uobj->cctx->vctx->ectx->engn; + if (engn->func->ramht_del) + engn->func->ramht_del(uobj->chan, uobj->hash); + + nvkm_chan_cctx_put(uobj->chan, &uobj->cctx); +} + +static const struct nvkm_oproxy_func +nvkm_uchan_object = { + .dtor[1] = nvkm_uchan_object_dtor, + .init[0] = nvkm_uchan_object_init_0, + .fini[1] = nvkm_uchan_object_fini_1, +}; + +static int +nvkm_uchan_object_new(const struct nvkm_oclass *oclass, void *argv, u32 argc, + struct nvkm_object **pobject) +{ + struct nvkm_chan *chan = nvkm_uchan(oclass->parent)->chan; + struct nvkm_cgrp *cgrp = chan->cgrp; + struct nvkm_engn *engn; + struct nvkm_uobj *uobj; + int ret; + + /* Lookup host engine state for target engine. */ + engn = nvkm_runl_find_engn(engn, cgrp->runl, engn->engine == oclass->engine); + if (WARN_ON(!engn)) + return -EINVAL; + + /* Allocate SW object. */ + if (!(uobj = kzalloc(sizeof(*uobj), GFP_KERNEL))) + return -ENOMEM; + + nvkm_oproxy_ctor(&nvkm_uchan_object, oclass, &uobj->oproxy); + uobj->chan = chan; + *pobject = &uobj->oproxy.base; + + /* Ref. channel context for target engine.*/ + ret = nvkm_chan_cctx_get(chan, engn, &uobj->cctx, oclass->client); + if (ret) + return ret; + + /* Allocate HW object. */ + ret = oclass->base.ctor(&(const struct nvkm_oclass) { + .base = oclass->base, + .engn = oclass->engn, + .handle = oclass->handle, + .object = oclass->object, + .client = oclass->client, + .parent = uobj->cctx->vctx->ectx->object ?: oclass->parent, + .engine = engn->engine, + }, argv, argc, &uobj->oproxy.object); + if (ret) + return ret; + + if (engn->func->ramht_add) { + uobj->hash = engn->func->ramht_add(engn, uobj->oproxy.object, uobj->chan); + if (uobj->hash < 0) + return uobj->hash; + } + + return 0; +} + +static int +nvkm_uchan_sclass(struct nvkm_object *object, int index, struct nvkm_oclass *oclass) +{ + struct nvkm_chan *chan = nvkm_uchan(object)->chan; + struct nvkm_engn *engn; + int ret, runq = 0; + + nvkm_runl_foreach_engn(engn, chan->cgrp->runl) { + struct nvkm_engine *engine = engn->engine; + int c = 0; + + /* Each runqueue, on runlists with multiple, has its own LCE. */ + if (engn->runl->func->runqs) { + if (engine->subdev.type == NVKM_ENGINE_CE) { + if (chan->runq != runq++) + continue; + } + } + + oclass->engine = engine; + oclass->base.oclass = 0; + + if (engine->func->fifo.sclass) { + ret = engine->func->fifo.sclass(oclass, index); + if (oclass->base.oclass) { + if (!oclass->base.ctor) + oclass->base.ctor = nvkm_object_new; + oclass->ctor = nvkm_uchan_object_new; + return 0; + } + + index -= ret; + continue; + } + + while (engine->func->sclass[c].oclass) { + if (c++ == index) { + oclass->base = engine->func->sclass[index]; + if (!oclass->base.ctor) + oclass->base.ctor = nvkm_object_new; + oclass->ctor = nvkm_uchan_object_new; + return 0; + } + } + + index -= c; + } + + return -EINVAL; +} + +static int +nvkm_uchan_map(struct nvkm_object *object, void *argv, u32 argc, + enum nvkm_object_map *type, u64 *addr, u64 *size) +{ + struct nvkm_chan *chan = nvkm_uchan(object)->chan; + struct nvkm_device *device = chan->cgrp->runl->fifo->engine.subdev.device; + + if (chan->func->userd->bar < 0) + return -ENOSYS; + + *type = NVKM_OBJECT_MAP_IO; + *addr = device->func->resource_addr(device, chan->func->userd->bar) + + chan->func->userd->base + chan->userd.base; + *size = chan->func->userd->size; + return 0; +} + +static int +nvkm_uchan_fini(struct nvkm_object *object, bool suspend) +{ + struct nvkm_chan *chan = nvkm_uchan(object)->chan; + + nvkm_chan_block(chan); + nvkm_chan_remove(chan, true); + + if (chan->func->unbind) + chan->func->unbind(chan); + + return 0; +} + +static int +nvkm_uchan_init(struct nvkm_object *object) +{ + struct nvkm_chan *chan = nvkm_uchan(object)->chan; + + if (atomic_read(&chan->errored)) + return 0; + + if (chan->func->bind) + chan->func->bind(chan); + + nvkm_chan_allow(chan); + nvkm_chan_insert(chan); + return 0; +} + +static void * +nvkm_uchan_dtor(struct nvkm_object *object) +{ + struct nvkm_uchan *uchan = nvkm_uchan(object); + + nvkm_chan_del(&uchan->chan); + return uchan; +} + +static const struct nvkm_object_func +nvkm_uchan = { + .dtor = nvkm_uchan_dtor, + .init = nvkm_uchan_init, + .fini = nvkm_uchan_fini, + .map = nvkm_uchan_map, + .sclass = nvkm_uchan_sclass, + .uevent = nvkm_uchan_uevent, +}; + +int +nvkm_uchan_new(struct nvkm_fifo *fifo, struct nvkm_cgrp *cgrp, const struct nvkm_oclass *oclass, + void *argv, u32 argc, struct nvkm_object **pobject) +{ + union nvif_chan_args *args = argv; + struct nvkm_runl *runl; + struct nvkm_vmm *vmm = NULL; + struct nvkm_dmaobj *ctxdma = NULL; + struct nvkm_memory *userd = NULL; + struct nvkm_uchan *uchan; + struct nvkm_chan *chan; + int ret; + + if (argc < sizeof(args->v0) || args->v0.version != 0) + return -ENOSYS; + argc -= sizeof(args->v0); + + if (args->v0.namelen != argc) + return -EINVAL; + + /* Lookup objects referenced in args. */ + runl = nvkm_runl_get(fifo, args->v0.runlist, 0); + if (!runl) + return -EINVAL; + + if (args->v0.vmm) { + vmm = nvkm_uvmm_search(oclass->client, args->v0.vmm); + if (IS_ERR(vmm)) + return PTR_ERR(vmm); + } + + if (args->v0.ctxdma) { + ctxdma = nvkm_dmaobj_search(oclass->client, args->v0.ctxdma); + if (IS_ERR(ctxdma)) { + ret = PTR_ERR(ctxdma); + goto done; + } + } + + if (args->v0.huserd) { + userd = nvkm_umem_search(oclass->client, args->v0.huserd); + if (IS_ERR(userd)) { + ret = PTR_ERR(userd); + userd = NULL; + goto done; + } + } + + /* Allocate channel. */ + if (!(uchan = kzalloc(sizeof(*uchan), GFP_KERNEL))) { + ret = -ENOMEM; + goto done; + } + + nvkm_object_ctor(&nvkm_uchan, oclass, &uchan->object); + *pobject = &uchan->object; + + ret = nvkm_chan_new_(fifo->func->chan.func, runl, args->v0.runq, cgrp, args->v0.name, + args->v0.priv != 0, args->v0.devm, vmm, ctxdma, args->v0.offset, + args->v0.length, userd, args->v0.ouserd, &uchan->chan); + if (ret) + goto done; + + chan = uchan->chan; + + /* Return channel info to caller. */ + if (chan->func->doorbell_handle) + args->v0.token = chan->func->doorbell_handle(chan); + else + args->v0.token = ~0; + + args->v0.chid = chan->id; + + switch (nvkm_memory_target(chan->inst->memory)) { + case NVKM_MEM_TARGET_INST: args->v0.aper = NVIF_CHAN_V0_INST_APER_INST; break; + case NVKM_MEM_TARGET_VRAM: args->v0.aper = NVIF_CHAN_V0_INST_APER_VRAM; break; + case NVKM_MEM_TARGET_HOST: args->v0.aper = NVIF_CHAN_V0_INST_APER_HOST; break; + case NVKM_MEM_TARGET_NCOH: args->v0.aper = NVIF_CHAN_V0_INST_APER_NCOH; break; + default: + WARN_ON(1); + ret = -EFAULT; + break; + } + + args->v0.inst = nvkm_memory_addr(chan->inst->memory); +done: + nvkm_memory_unref(&userd); + nvkm_vmm_unref(&vmm); + return ret; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/user.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/user.h deleted file mode 100644 index 54a3a3092cc0..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/user.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef __NVKM_FIFO_USER_H__ -#define __NVKM_FIFO_USER_H__ -#include "priv.h" -int gv100_fifo_user_new(const struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -int tu102_fifo_user_new(const struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild index 558c86fd8e82..b5418f05ccd8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild @@ -40,6 +40,7 @@ nvkm-y += nvkm/engine/gr/gp108.o nvkm-y += nvkm/engine/gr/gp10b.o nvkm-y += nvkm/engine/gr/gv100.o nvkm-y += nvkm/engine/gr/tu102.o +nvkm-y += nvkm/engine/gr/ga102.o nvkm-y += nvkm/engine/gr/ctxnv40.o nvkm-y += nvkm/engine/gr/ctxnv50.o @@ -63,3 +64,4 @@ nvkm-y += nvkm/engine/gr/ctxgp104.o nvkm-y += nvkm/engine/gr/ctxgp107.o nvkm-y += nvkm/engine/gr/ctxgv100.o nvkm-y += nvkm/engine/gr/ctxtu102.o +nvkm-y += nvkm/engine/gr/ctxga102.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/base.c index 61759f54406e..71b824e6da9d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/base.c @@ -136,6 +136,17 @@ nvkm_gr_oneinit(struct nvkm_engine *engine) } static int +nvkm_gr_reset(struct nvkm_engine *engine) +{ + struct nvkm_gr *gr = nvkm_gr(engine); + + if (gr->func->reset) + return gr->func->reset(gr); + + return -ENOSYS; +} + +static int nvkm_gr_init(struct nvkm_engine *engine) { struct nvkm_gr *gr = nvkm_gr(engine); @@ -166,6 +177,7 @@ nvkm_gr = { .oneinit = nvkm_gr_oneinit, .init = nvkm_gr_init, .fini = nvkm_gr_fini, + .reset = nvkm_gr_reset, .intr = nvkm_gr_intr, .tile = nvkm_gr_tile, .chsw_load = nvkm_gr_chsw_load, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxga102.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxga102.c new file mode 100644 index 000000000000..11461adf5036 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxga102.c @@ -0,0 +1,77 @@ +/* + * 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 "ctxgf100.h" + +static void +ga102_grctx_generate_sm_id(struct gf100_gr *gr, int gpc, int tpc, int sm) +{ + struct nvkm_device *device = gr->base.engine.subdev.device; + + tpc = gv100_gr_nonpes_aware_tpc(gr, gpc, tpc); + + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x608), sm); +} + +static void +ga102_grctx_generate_unkn(struct gf100_gr *gr) +{ + struct nvkm_device *device = gr->base.engine.subdev.device; + + nvkm_mask(device, 0x41980c, 0x00000010, 0x00000010); + nvkm_mask(device, 0x41be08, 0x00000004, 0x00000004); +} + +static void +ga102_grctx_generate_r419ea8(struct gf100_gr *gr) +{ + struct nvkm_device *device = gr->base.engine.subdev.device; + + nvkm_wr32(device, 0x419ea8, nvkm_rd32(device, 0x504728) | 0x08000000); +} + +const struct gf100_grctx_func +ga102_grctx = { + .main = gf100_grctx_generate_main, + .unkn = ga102_grctx_generate_unkn, + .bundle = gm107_grctx_generate_bundle, + .bundle_size = 0x3000, + .bundle_min_gpm_fifo_depth = 0x180, + .bundle_token_limit = 0x1140, + .pagepool = gp100_grctx_generate_pagepool, + .pagepool_size = 0x20000, + .attrib_cb_size = gp102_grctx_generate_attrib_cb_size, + .attrib_cb = gv100_grctx_generate_attrib_cb, + .attrib = gv100_grctx_generate_attrib, + .attrib_nr_max = 0x800, + .attrib_nr = 0x4a1, + .alpha_nr_max = 0xc00, + .alpha_nr = 0x800, + .unknown_size = 0x80000, + .unknown = tu102_grctx_generate_unknown, + .gfxp_nr = 0xd28, + .sm_id = ga102_grctx_generate_sm_id, + .skip_pd_num_tpc_per_gpc = true, + .rop_mapping = gv100_grctx_generate_rop_mapping, + .r406500 = gm200_grctx_generate_r406500, + .r400088 = gv100_grctx_generate_r400088, + .r419ea8 = ga102_grctx_generate_r419ea8, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c index 297915719bf2..cb390e0134a2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c @@ -26,6 +26,7 @@ #include <subdev/fb.h> #include <subdev/mc.h> #include <subdev/timer.h> +#include <engine/fifo.h> /******************************************************************************* * PGRAPH context register lists @@ -990,43 +991,16 @@ gf100_grctx_pack_tpc[] = { * PGRAPH context implementation ******************************************************************************/ -int -gf100_grctx_mmio_data(struct gf100_grctx *info, u32 size, u32 align, bool priv) -{ - if (info->data) { - info->buffer[info->buffer_nr] = round_up(info->addr, align); - info->addr = info->buffer[info->buffer_nr] + size; - info->data->size = size; - info->data->align = align; - info->data->priv = priv; - info->data++; - return info->buffer_nr++; - } - return -1; -} - void -gf100_grctx_mmio_item(struct gf100_grctx *info, u32 addr, u32 data, - int shift, int buffer) +gf100_grctx_patch_wr32(struct gf100_gr_chan *chan, u32 addr, u32 data) { - struct nvkm_device *device = info->gr->base.engine.subdev.device; - if (info->data) { - if (shift >= 0) { - info->mmio->addr = addr; - info->mmio->data = data; - info->mmio->shift = shift; - info->mmio->buffer = buffer; - if (buffer >= 0) - data |= info->buffer[buffer] >> shift; - info->mmio++; - } else - return; - } else { - if (buffer >= 0) - return; + if (unlikely(!chan->mmio)) { + nvkm_wr32(chan->gr->base.engine.subdev.device, addr, data); + return; } - nvkm_wr32(device, addr, data); + nvkm_wo32(chan->mmio, chan->mmio_nr++ * 4, addr); + nvkm_wo32(chan->mmio, chan->mmio_nr++ * 4, data); } void @@ -1037,56 +1011,60 @@ gf100_grctx_generate_r419cb8(struct gf100_gr *gr) } void -gf100_grctx_generate_bundle(struct gf100_grctx *info) +gf100_grctx_generate_bundle(struct gf100_gr_chan *chan, u64 addr, u32 size) { - const struct gf100_grctx_func *grctx = info->gr->func->grctx; - const int s = 8; - const int b = mmio_vram(info, grctx->bundle_size, (1 << s), true); - mmio_refn(info, 0x408004, 0x00000000, s, b); - mmio_wr32(info, 0x408008, 0x80000000 | (grctx->bundle_size >> s)); - mmio_refn(info, 0x418808, 0x00000000, s, b); - mmio_wr32(info, 0x41880c, 0x80000000 | (grctx->bundle_size >> s)); + gf100_grctx_patch_wr32(chan, 0x408004, addr >> 8); + gf100_grctx_patch_wr32(chan, 0x408008, 0x80000000 | (size >> 8)); + gf100_grctx_patch_wr32(chan, 0x418808, addr >> 8); + gf100_grctx_patch_wr32(chan, 0x41880c, 0x80000000 | (size >> 8)); } void -gf100_grctx_generate_pagepool(struct gf100_grctx *info) +gf100_grctx_generate_pagepool(struct gf100_gr_chan *chan, u64 addr) { - const struct gf100_grctx_func *grctx = info->gr->func->grctx; - const int s = 8; - const int b = mmio_vram(info, grctx->pagepool_size, (1 << s), true); - mmio_refn(info, 0x40800c, 0x00000000, s, b); - mmio_wr32(info, 0x408010, 0x80000000); - mmio_refn(info, 0x419004, 0x00000000, s, b); - mmio_wr32(info, 0x419008, 0x00000000); + gf100_grctx_patch_wr32(chan, 0x40800c, addr >> 8); + gf100_grctx_patch_wr32(chan, 0x408010, 0x80000000); + gf100_grctx_patch_wr32(chan, 0x419004, addr >> 8); + gf100_grctx_patch_wr32(chan, 0x419008, 0x00000000); } void -gf100_grctx_generate_attrib(struct gf100_grctx *info) +gf100_grctx_generate_attrib(struct gf100_gr_chan *chan) { - struct gf100_gr *gr = info->gr; + struct gf100_gr *gr = chan->gr; const struct gf100_grctx_func *grctx = gr->func->grctx; const u32 attrib = grctx->attrib_nr; - const u32 size = 0x20 * (grctx->attrib_nr_max + grctx->alpha_nr_max); - const int s = 12; - const int b = mmio_vram(info, size * gr->tpc_total, (1 << s), false); int gpc, tpc; u32 bo = 0; - mmio_refn(info, 0x418810, 0x80000000, s, b); - mmio_refn(info, 0x419848, 0x10000000, s, b); - mmio_wr32(info, 0x405830, (attrib << 16)); + gf100_grctx_patch_wr32(chan, 0x405830, (attrib << 16)); for (gpc = 0; gpc < gr->gpc_nr; gpc++) { for (tpc = 0; tpc < gr->tpc_nr[gpc]; tpc++) { const u32 o = TPC_UNIT(gpc, tpc, 0x0520); - mmio_skip(info, o, (attrib << 16) | ++bo); - mmio_wr32(info, o, (attrib << 16) | --bo); + + gf100_grctx_patch_wr32(chan, o, (attrib << 16) | bo); bo += grctx->attrib_nr_max; } } } void +gf100_grctx_generate_attrib_cb(struct gf100_gr_chan *chan, u64 addr, u32 size) +{ + gf100_grctx_patch_wr32(chan, 0x418810, 0x80000000 | addr >> 12); + gf100_grctx_patch_wr32(chan, 0x419848, 0x10000000 | addr >> 12); +} + +u32 +gf100_grctx_generate_attrib_cb_size(struct gf100_gr *gr) +{ + const struct gf100_grctx_func *grctx = gr->func->grctx; + + return 0x20 * (grctx->attrib_nr_max + grctx->alpha_nr_max) * gr->tpc_total; +} + +void gf100_grctx_generate_unkn(struct gf100_gr *gr) { } @@ -1361,8 +1339,9 @@ gf100_grctx_generate_floorsweep(struct gf100_gr *gr) } void -gf100_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) +gf100_grctx_generate_main(struct gf100_gr_chan *chan) { + struct gf100_gr *gr = chan->gr; struct nvkm_device *device = gr->base.engine.subdev.device; const struct gf100_grctx_func *grctx = gr->func->grctx; u32 idle_timeout; @@ -1380,15 +1359,23 @@ gf100_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) gf100_gr_mmio(gr, gr->sw_ctx); } + if (gr->func->init_419bd8) + gr->func->init_419bd8(gr); + if (grctx->r419ea8) + grctx->r419ea8(gr); + gf100_gr_wait_idle(gr); idle_timeout = nvkm_mask(device, 0x404154, 0xffffffff, 0x00000000); - grctx->pagepool(info); - grctx->bundle(info); - grctx->attrib(info); + grctx->pagepool(chan, chan->pagepool->addr); + grctx->bundle(chan, chan->bundle_cb->addr, grctx->bundle_size); + grctx->attrib_cb(chan, chan->attrib_cb->addr, grctx->attrib_cb_size(gr)); + grctx->attrib(chan); if (grctx->patch_ltc) - grctx->patch_ltc(info); + grctx->patch_ltc(chan); + if (grctx->unknown_size) + grctx->unknown(chan, chan->unknown->addr, grctx->unknown_size); grctx->unkn(gr); gf100_grctx_generate_floorsweep(gr); @@ -1396,12 +1383,23 @@ gf100_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) gf100_gr_wait_idle(gr); if (grctx->r400088) grctx->r400088(gr, false); + if (gr->bundle) gf100_gr_icmd(gr, gr->bundle); else gf100_gr_icmd(gr, grctx->icmd); - if (grctx->sw_veid_bundle_init) + + if (gr->bundle_veid) + gf100_gr_icmd(gr, gr->bundle_veid); + else gf100_gr_icmd(gr, grctx->sw_veid_bundle_init); + + if (gr->bundle64) + gf100_gr_icmd(gr, gr->bundle64); + else + if (grctx->sw_bundle64_init) + gf100_gr_icmd(gr, grctx->sw_bundle64_init); + if (grctx->r400088) grctx->r400088(gr, true); nvkm_wr32(device, 0x404154, idle_timeout); @@ -1428,21 +1426,20 @@ gf100_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) grctx->r408840(gr); if (grctx->r419c0c) grctx->r419c0c(gr); + + gf100_gr_wait_idle(gr); } #define CB_RESERVED 0x80000 int -gf100_grctx_generate(struct gf100_gr *gr) +gf100_grctx_generate(struct gf100_gr *gr, struct gf100_gr_chan *chan, struct nvkm_gpuobj *inst) { const struct gf100_grctx_func *grctx = gr->func->grctx; struct nvkm_subdev *subdev = &gr->base.engine.subdev; struct nvkm_device *device = subdev->device; - struct nvkm_memory *inst = NULL; struct nvkm_memory *data = NULL; - struct nvkm_vmm *vmm = NULL; struct nvkm_vma *ctx = NULL; - struct gf100_grctx info; int ret, i; u64 addr; @@ -1457,72 +1454,47 @@ gf100_grctx_generate(struct gf100_gr *gr) grctx->unkn88c(gr, true); /* Reset FECS. */ - nvkm_wr32(device, 0x409614, 0x00000070); - nvkm_usec(device, 10, NVKM_DELAY); - nvkm_mask(device, 0x409614, 0x00000700, 0x00000700); - nvkm_usec(device, 10, NVKM_DELAY); - nvkm_rd32(device, 0x409614); + gr->func->fecs.reset(gr); if (grctx->unkn88c) grctx->unkn88c(gr, false); /* NV_PGRAPH_FE_PWR_MODE_AUTO. */ nvkm_wr32(device, 0x404170, 0x00000010); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x404170) & 0x00000010)) + break; + ); /* Init SCC RAM. */ nvkm_wr32(device, 0x40802c, 0x00000001); - /* Allocate memory to for a "channel", which we'll use to generate - * the default context values. - */ - ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, - 0x1000, 0x1000, true, &inst); - if (ret) - goto done; - - ret = nvkm_vmm_new(device, 0, 0, NULL, 0, NULL, "grctx", &vmm); - if (ret) - goto done; - - vmm->debug = subdev->debug; - - ret = nvkm_vmm_join(vmm, inst); - if (ret) - goto done; - + /* Allocate memory to store context, and dummy global context buffers. */ ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, CB_RESERVED + gr->size, 0, true, &data); if (ret) goto done; - ret = nvkm_vmm_get(vmm, 0, nvkm_memory_size(data), &ctx); + ret = nvkm_vmm_get(chan->vmm, 0, nvkm_memory_size(data), &ctx); if (ret) goto done; - ret = nvkm_memory_map(data, 0, vmm, ctx, NULL, 0); + ret = nvkm_memory_map(data, 0, chan->vmm, ctx, NULL, 0); if (ret) goto done; - /* Setup context pointer. */ nvkm_kmap(inst); nvkm_wo32(inst, 0x0210, lower_32_bits(ctx->addr + CB_RESERVED) | 4); nvkm_wo32(inst, 0x0214, upper_32_bits(ctx->addr + CB_RESERVED)); nvkm_done(inst); - /* Setup default state for mmio list construction. */ - info.gr = gr; - info.data = gr->mmio_data; - info.mmio = gr->mmio_list; - info.addr = ctx->addr; - info.buffer_nr = 0; - /* Make channel current. */ - addr = nvkm_memory_addr(inst) >> 12; + addr = inst->addr >> 12; if (gr->firmware) { ret = gf100_gr_fecs_bind_pointer(gr, 0x80000000 | addr); if (ret) - goto done; + goto done_inst; nvkm_kmap(data); nvkm_wo32(data, 0x1c, 1); @@ -1540,19 +1512,27 @@ gf100_grctx_generate(struct gf100_gr *gr) ); } - grctx->main(gr, &info); + grctx->main(chan); - /* Trigger a context unload by unsetting the "next channel valid" bit - * and faking a context switch interrupt. - */ - nvkm_mask(device, 0x409b04, 0x80000000, 0x00000000); - nvkm_wr32(device, 0x409000, 0x00000100); - if (nvkm_msec(device, 2000, - if (!(nvkm_rd32(device, 0x409b00) & 0x80000000)) - break; - ) < 0) { - ret = -EBUSY; - goto done; + if (!gr->firmware) { + /* Trigger a context unload by unsetting the "next channel valid" bit + * and faking a context switch interrupt. + */ + nvkm_mask(device, 0x409b04, 0x80000000, 0x00000000); + nvkm_wr32(device, 0x409000, 0x00000100); + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x409b00) & 0x80000000)) + break; + ) < 0) { + ret = -EBUSY; + goto done_inst; + } + } else { + ret = gf100_gr_fecs_wfi_golden_save(gr, 0x80000000 | addr); + if (ret) + goto done_inst; + + nvkm_mask(device, 0x409b00, 0x80000000, 0x00000000); } gr->data = kmalloc(gr->size, GFP_KERNEL); @@ -1566,12 +1546,14 @@ gf100_grctx_generate(struct gf100_gr *gr) ret = -ENOMEM; } +done_inst: + nvkm_kmap(inst); + nvkm_wo32(inst, 0x0210, 0); + nvkm_wo32(inst, 0x0214, 0); + nvkm_done(inst); done: - nvkm_vmm_put(vmm, &ctx); + nvkm_vmm_put(chan->vmm, &ctx); nvkm_memory_unref(&data); - nvkm_vmm_part(vmm, inst); - nvkm_vmm_unref(&vmm); - nvkm_memory_unref(&inst); return ret; } @@ -1590,6 +1572,8 @@ gf100_grctx = { .bundle_size = 0x1800, .pagepool = gf100_grctx_generate_pagepool, .pagepool_size = 0x8000, + .attrib_cb_size = gf100_grctx_generate_attrib_cb_size, + .attrib_cb = gf100_grctx_generate_attrib_cb, .attrib = gf100_grctx_generate_attrib, .attrib_nr_max = 0x324, .attrib_nr = 0x218, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h index 32bbddc0993e..00dbeda7e346 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h @@ -3,27 +3,12 @@ #define __NVKM_GRCTX_NVC0_H__ #include "gf100.h" -struct gf100_grctx { - struct gf100_gr *gr; - struct gf100_gr_data *data; - struct gf100_gr_mmio *mmio; - int buffer_nr; - u64 buffer[4]; - u64 addr; -}; - -int gf100_grctx_mmio_data(struct gf100_grctx *, u32 size, u32 align, bool priv); -void gf100_grctx_mmio_item(struct gf100_grctx *, u32 addr, u32 data, int s, int); - -#define mmio_vram(a,b,c,d) gf100_grctx_mmio_data((a), (b), (c), (d)) -#define mmio_refn(a,b,c,d,e) gf100_grctx_mmio_item((a), (b), (c), (d), (e)) -#define mmio_skip(a,b,c) mmio_refn((a), (b), (c), -1, -1) -#define mmio_wr32(a,b,c) mmio_refn((a), (b), (c), 0, -1) +void gf100_grctx_patch_wr32(struct gf100_gr_chan *, u32 addr, u32 data); struct gf100_grctx_func { void (*unkn88c)(struct gf100_gr *, bool on); /* main context generation function */ - void (*main)(struct gf100_gr *, struct gf100_grctx *); + void (*main)(struct gf100_gr_chan *); /* context-specific modify-on-first-load list generation function */ void (*unkn)(struct gf100_gr *); /* mmio context data */ @@ -37,23 +22,29 @@ struct gf100_grctx_func { const struct gf100_gr_pack *icmd; const struct gf100_gr_pack *mthd; const struct gf100_gr_pack *sw_veid_bundle_init; + const struct gf100_gr_pack *sw_bundle64_init; /* bundle circular buffer */ - void (*bundle)(struct gf100_grctx *); + void (*bundle)(struct gf100_gr_chan *, u64 addr, u32 size); u32 bundle_size; u32 bundle_min_gpm_fifo_depth; u32 bundle_token_limit; /* pagepool */ - void (*pagepool)(struct gf100_grctx *); + void (*pagepool)(struct gf100_gr_chan *, u64 addr); u32 pagepool_size; /* attribute(/alpha) circular buffer */ - void (*attrib)(struct gf100_grctx *); + u32 (*attrib_cb_size)(struct gf100_gr *); + void (*attrib_cb)(struct gf100_gr_chan *, u64 addr, u32 size); + void (*attrib)(struct gf100_gr_chan *); u32 attrib_nr_max; u32 attrib_nr; u32 alpha_nr_max; u32 alpha_nr; u32 gfxp_nr; + /* some other context buffer */ + void (*unknown)(struct gf100_gr_chan *, u64 addr, u32 size); + u32 unknown_size; /* other patch buffer stuff */ - void (*patch_ltc)(struct gf100_grctx *); + void (*patch_ltc)(struct gf100_gr_chan *); /* floorsweeping */ void (*sm_id)(struct gf100_gr *, int gpc, int tpc, int sm); void (*tpc_nr)(struct gf100_gr *, int gpc); @@ -78,14 +69,17 @@ struct gf100_grctx_func { void (*r419a3c)(struct gf100_gr *); void (*r408840)(struct gf100_gr *); void (*r419c0c)(struct gf100_gr *); + void (*r419ea8)(struct gf100_gr *); }; extern const struct gf100_grctx_func gf100_grctx; -int gf100_grctx_generate(struct gf100_gr *); -void gf100_grctx_generate_main(struct gf100_gr *, struct gf100_grctx *); -void gf100_grctx_generate_bundle(struct gf100_grctx *); -void gf100_grctx_generate_pagepool(struct gf100_grctx *); -void gf100_grctx_generate_attrib(struct gf100_grctx *); +int gf100_grctx_generate(struct gf100_gr *, struct gf100_gr_chan *, struct nvkm_gpuobj *inst); +void gf100_grctx_generate_main(struct gf100_gr_chan *); +void gf100_grctx_generate_pagepool(struct gf100_gr_chan *, u64); +void gf100_grctx_generate_bundle(struct gf100_gr_chan *, u64, u32); +u32 gf100_grctx_generate_attrib_cb_size(struct gf100_gr *); +void gf100_grctx_generate_attrib_cb(struct gf100_gr_chan *, u64, u32); +void gf100_grctx_generate_attrib(struct gf100_gr_chan *); void gf100_grctx_generate_unkn(struct gf100_gr *); void gf100_grctx_generate_floorsweep(struct gf100_gr *); void gf100_grctx_generate_sm_id(struct gf100_gr *, int, int, int); @@ -97,14 +91,14 @@ void gf100_grctx_generate_max_ways_evict(struct gf100_gr *); void gf100_grctx_generate_r419cb8(struct gf100_gr *); extern const struct gf100_grctx_func gf108_grctx; -void gf108_grctx_generate_attrib(struct gf100_grctx *); +void gf108_grctx_generate_attrib(struct gf100_gr_chan *); void gf108_grctx_generate_unkn(struct gf100_gr *); extern const struct gf100_grctx_func gf104_grctx; extern const struct gf100_grctx_func gf110_grctx; extern const struct gf100_grctx_func gf117_grctx; -void gf117_grctx_generate_attrib(struct gf100_grctx *); +void gf117_grctx_generate_attrib(struct gf100_gr_chan *); void gf117_grctx_generate_rop_mapping(struct gf100_gr *); void gf117_grctx_generate_dist_skip_table(struct gf100_gr *); @@ -115,9 +109,9 @@ void gk104_grctx_generate_alpha_beta_tables(struct gf100_gr *); void gk104_grctx_generate_gpc_tpc_nr(struct gf100_gr *); extern const struct gf100_grctx_func gk20a_grctx; -void gk104_grctx_generate_bundle(struct gf100_grctx *); -void gk104_grctx_generate_pagepool(struct gf100_grctx *); -void gk104_grctx_generate_patch_ltc(struct gf100_grctx *); +void gk104_grctx_generate_pagepool(struct gf100_gr_chan *, u64); +void gk104_grctx_generate_bundle(struct gf100_gr_chan *, u64, u32); +void gk104_grctx_generate_patch_ltc(struct gf100_gr_chan *); void gk104_grctx_generate_unkn(struct gf100_gr *); void gk104_grctx_generate_r418800(struct gf100_gr *); @@ -128,9 +122,10 @@ extern const struct gf100_grctx_func gk110b_grctx; extern const struct gf100_grctx_func gk208_grctx; extern const struct gf100_grctx_func gm107_grctx; -void gm107_grctx_generate_bundle(struct gf100_grctx *); -void gm107_grctx_generate_pagepool(struct gf100_grctx *); -void gm107_grctx_generate_attrib(struct gf100_grctx *); +void gm107_grctx_generate_pagepool(struct gf100_gr_chan *, u64); +void gm107_grctx_generate_bundle(struct gf100_gr_chan *, u64, u32); +void gm107_grctx_generate_attrib_cb(struct gf100_gr_chan *, u64, u32); +void gm107_grctx_generate_attrib(struct gf100_gr_chan *); void gm107_grctx_generate_sm_id(struct gf100_gr *, int, int, int); extern const struct gf100_grctx_func gm200_grctx; @@ -143,11 +138,13 @@ void gm200_grctx_generate_r419a3c(struct gf100_gr *); extern const struct gf100_grctx_func gm20b_grctx; extern const struct gf100_grctx_func gp100_grctx; -void gp100_grctx_generate_pagepool(struct gf100_grctx *); +void gp100_grctx_generate_pagepool(struct gf100_gr_chan *, u64); +void gp100_grctx_generate_attrib_cb(struct gf100_gr_chan *, u64, u32); void gp100_grctx_generate_smid_config(struct gf100_gr *); extern const struct gf100_grctx_func gp102_grctx; -void gp102_grctx_generate_attrib(struct gf100_grctx *); +u32 gp102_grctx_generate_attrib_cb_size(struct gf100_gr *); +void gp102_grctx_generate_attrib(struct gf100_gr_chan *); extern const struct gf100_grctx_func gp104_grctx; @@ -158,11 +155,15 @@ extern const struct gf100_grctx_func gv100_grctx; extern const struct gf100_grctx_func tu102_grctx; void gv100_grctx_unkn88c(struct gf100_gr *, bool); void gv100_grctx_generate_unkn(struct gf100_gr *); -extern const struct gf100_gr_init gv100_grctx_init_sw_veid_bundle_init_0[]; -void gv100_grctx_generate_attrib(struct gf100_grctx *); +void gv100_grctx_generate_attrib_cb(struct gf100_gr_chan *, u64, u32); +void gv100_grctx_generate_attrib(struct gf100_gr_chan *); void gv100_grctx_generate_rop_mapping(struct gf100_gr *); void gv100_grctx_generate_r400088(struct gf100_gr *, bool); +void tu102_grctx_generate_unknown(struct gf100_gr_chan *, u64, u32); + +extern const struct gf100_grctx_func ga102_grctx; + /* context init value lists */ extern const struct gf100_gr_pack gf100_grctx_pack_icmd[]; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf104.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf104.c index 7a0564b6e3c7..ba63a3b46518 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf104.c @@ -94,6 +94,8 @@ gf104_grctx = { .bundle_size = 0x1800, .pagepool = gf100_grctx_generate_pagepool, .pagepool_size = 0x8000, + .attrib_cb_size = gf100_grctx_generate_attrib_cb_size, + .attrib_cb = gf100_grctx_generate_attrib_cb, .attrib = gf100_grctx_generate_attrib, .attrib_nr_max = 0x324, .attrib_nr = 0x218, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf108.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf108.c index dda2c32e6232..0bc2eab6ad98 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf108.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf108.c @@ -733,25 +733,20 @@ gf108_grctx_pack_tpc[] = { ******************************************************************************/ void -gf108_grctx_generate_attrib(struct gf100_grctx *info) +gf108_grctx_generate_attrib(struct gf100_gr_chan *chan) { - struct gf100_gr *gr = info->gr; + struct gf100_gr *gr = chan->gr; const struct gf100_grctx_func *grctx = gr->func->grctx; const u32 alpha = grctx->alpha_nr; const u32 beta = grctx->attrib_nr; - const u32 size = 0x20 * (grctx->attrib_nr_max + grctx->alpha_nr_max); - const int s = 12; - const int b = mmio_vram(info, size * gr->tpc_total, (1 << s), false); const int timeslice_mode = 1; const int max_batches = 0xffff; u32 bo = 0; u32 ao = bo + grctx->attrib_nr_max * gr->tpc_total; int gpc, tpc; - mmio_refn(info, 0x418810, 0x80000000, s, b); - mmio_refn(info, 0x419848, 0x10000000, s, b); - mmio_wr32(info, 0x405830, (beta << 16) | alpha); - mmio_wr32(info, 0x4064c4, ((alpha / 4) << 16) | max_batches); + gf100_grctx_patch_wr32(chan, 0x405830, (beta << 16) | alpha); + gf100_grctx_patch_wr32(chan, 0x4064c4, ((alpha / 4) << 16) | max_batches); for (gpc = 0; gpc < gr->gpc_nr; gpc++) { for (tpc = 0; tpc < gr->tpc_nr[gpc]; tpc++) { @@ -759,10 +754,10 @@ gf108_grctx_generate_attrib(struct gf100_grctx *info) const u32 b = beta; const u32 t = timeslice_mode; const u32 o = TPC_UNIT(gpc, tpc, 0x500); - mmio_skip(info, o + 0x20, (t << 28) | (b << 16) | ++bo); - mmio_wr32(info, o + 0x20, (t << 28) | (b << 16) | --bo); + + gf100_grctx_patch_wr32(chan, o + 0x20, (t << 28) | (b << 16) | bo); bo += grctx->attrib_nr_max; - mmio_wr32(info, o + 0x44, (a << 16) | ao); + gf100_grctx_patch_wr32(chan, o + 0x44, (a << 16) | ao); ao += grctx->alpha_nr_max; } } @@ -795,6 +790,8 @@ gf108_grctx = { .bundle_size = 0x1800, .pagepool = gf100_grctx_generate_pagepool, .pagepool_size = 0x8000, + .attrib_cb_size = gf100_grctx_generate_attrib_cb_size, + .attrib_cb = gf100_grctx_generate_attrib_cb, .attrib = gf108_grctx_generate_attrib, .attrib_nr_max = 0x324, .attrib_nr = 0x218, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf110.c index f5cca5e6a4f2..64b723b0afb5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf110.c @@ -342,6 +342,8 @@ gf110_grctx = { .bundle_size = 0x1800, .pagepool = gf100_grctx_generate_pagepool, .pagepool_size = 0x8000, + .attrib_cb_size = gf100_grctx_generate_attrib_cb_size, + .attrib_cb = gf100_grctx_generate_attrib_cb, .attrib = gf100_grctx_generate_attrib, .attrib_nr_max = 0x324, .attrib_nr = 0x218, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c index 276c282d19aa..e34c5da2a9ff 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c @@ -241,38 +241,34 @@ gf117_grctx_generate_rop_mapping(struct gf100_gr *gr) } void -gf117_grctx_generate_attrib(struct gf100_grctx *info) +gf117_grctx_generate_attrib(struct gf100_gr_chan *chan) { - struct gf100_gr *gr = info->gr; + struct gf100_gr *gr = chan->gr; const struct gf100_grctx_func *grctx = gr->func->grctx; const u32 alpha = grctx->alpha_nr; const u32 beta = grctx->attrib_nr; - const u32 size = 0x20 * (grctx->attrib_nr_max + grctx->alpha_nr_max); - const int s = 12; - const int b = mmio_vram(info, size * gr->tpc_total, (1 << s), false); const int timeslice_mode = 1; const int max_batches = 0xffff; u32 bo = 0; u32 ao = bo + grctx->attrib_nr_max * gr->tpc_total; int gpc, ppc; - mmio_refn(info, 0x418810, 0x80000000, s, b); - mmio_refn(info, 0x419848, 0x10000000, s, b); - mmio_wr32(info, 0x405830, (beta << 16) | alpha); - mmio_wr32(info, 0x4064c4, ((alpha / 4) << 16) | max_batches); + gf100_grctx_patch_wr32(chan, 0x405830, (beta << 16) | alpha); + gf100_grctx_patch_wr32(chan, 0x4064c4, ((alpha / 4) << 16) | max_batches); for (gpc = 0; gpc < gr->gpc_nr; gpc++) { - for (ppc = 0; ppc < gr->ppc_nr[gpc]; ppc++) { + for (ppc = 0; ppc < gr->func->ppc_nr; ppc++) { const u32 a = alpha * gr->ppc_tpc_nr[gpc][ppc]; const u32 b = beta * gr->ppc_tpc_nr[gpc][ppc]; const u32 t = timeslice_mode; const u32 o = PPC_UNIT(gpc, ppc, 0); + if (!(gr->ppc_mask[gpc] & (1 << ppc))) continue; - mmio_skip(info, o + 0xc0, (t << 28) | (b << 16) | ++bo); - mmio_wr32(info, o + 0xc0, (t << 28) | (b << 16) | --bo); + + gf100_grctx_patch_wr32(chan, o + 0xc0, (t << 28) | (b << 16) | bo); bo += grctx->attrib_nr_max * gr->ppc_tpc_nr[gpc][ppc]; - mmio_wr32(info, o + 0xe4, (a << 16) | ao); + gf100_grctx_patch_wr32(chan, o + 0xe4, (a << 16) | ao); ao += grctx->alpha_nr_max * gr->ppc_tpc_nr[gpc][ppc]; } } @@ -294,6 +290,8 @@ gf117_grctx = { .bundle_size = 0x1800, .pagepool = gf100_grctx_generate_pagepool, .pagepool_size = 0x8000, + .attrib_cb_size = gf100_grctx_generate_attrib_cb_size, + .attrib_cb = gf100_grctx_generate_attrib_cb, .attrib = gf117_grctx_generate_attrib, .attrib_nr_max = 0x324, .attrib_nr = 0x218, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf119.c index 0cfe46366af6..426ad1b8d426 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf119.c @@ -510,6 +510,8 @@ gf119_grctx = { .bundle_size = 0x1800, .pagepool = gf100_grctx_generate_pagepool, .pagepool_size = 0x8000, + .attrib_cb_size = gf100_grctx_generate_attrib_cb_size, + .attrib_cb = gf100_grctx_generate_attrib_cb, .attrib = gf108_grctx_generate_attrib, .attrib_nr_max = 0x324, .attrib_nr = 0x218, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c index 304e9d268bad..94233d0119df 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c @@ -861,43 +861,33 @@ gk104_grctx_generate_r418800(struct gf100_gr *gr) } void -gk104_grctx_generate_patch_ltc(struct gf100_grctx *info) +gk104_grctx_generate_patch_ltc(struct gf100_gr_chan *chan) { - struct nvkm_device *device = info->gr->base.engine.subdev.device; + struct nvkm_device *device = chan->gr->base.engine.subdev.device; u32 data0 = nvkm_rd32(device, 0x17e91c); u32 data1 = nvkm_rd32(device, 0x17e920); + /*XXX: Figure out how to modify this correctly! */ - mmio_wr32(info, 0x17e91c, data0); - mmio_wr32(info, 0x17e920, data1); + gf100_grctx_patch_wr32(chan, 0x17e91c, data0); + gf100_grctx_patch_wr32(chan, 0x17e920, data1); } void -gk104_grctx_generate_bundle(struct gf100_grctx *info) +gk104_grctx_generate_bundle(struct gf100_gr_chan *chan, u64 addr, u32 size) { - const struct gf100_grctx_func *grctx = info->gr->func->grctx; - const u32 state_limit = min(grctx->bundle_min_gpm_fifo_depth, - grctx->bundle_size / 0x20); + const struct gf100_grctx_func *grctx = chan->gr->func->grctx; + const u32 state_limit = min(grctx->bundle_min_gpm_fifo_depth, size / 0x20); const u32 token_limit = grctx->bundle_token_limit; - const int s = 8; - const int b = mmio_vram(info, grctx->bundle_size, (1 << s), true); - mmio_refn(info, 0x408004, 0x00000000, s, b); - mmio_wr32(info, 0x408008, 0x80000000 | (grctx->bundle_size >> s)); - mmio_refn(info, 0x418808, 0x00000000, s, b); - mmio_wr32(info, 0x41880c, 0x80000000 | (grctx->bundle_size >> s)); - mmio_wr32(info, 0x4064c8, (state_limit << 16) | token_limit); + + gf100_grctx_generate_bundle(chan, addr, size); + gf100_grctx_patch_wr32(chan, 0x4064c8, (state_limit << 16) | token_limit); } void -gk104_grctx_generate_pagepool(struct gf100_grctx *info) +gk104_grctx_generate_pagepool(struct gf100_gr_chan *chan, u64 addr) { - const struct gf100_grctx_func *grctx = info->gr->func->grctx; - const int s = 8; - const int b = mmio_vram(info, grctx->pagepool_size, (1 << s), true); - mmio_refn(info, 0x40800c, 0x00000000, s, b); - mmio_wr32(info, 0x408010, 0x80000000); - mmio_refn(info, 0x419004, 0x00000000, s, b); - mmio_wr32(info, 0x419008, 0x00000000); - mmio_wr32(info, 0x4064cc, 0x80000000); + gf100_grctx_generate_pagepool(chan, addr); + gf100_grctx_patch_wr32(chan, 0x4064cc, 0x80000000); } void @@ -991,6 +981,8 @@ gk104_grctx = { .bundle_token_limit = 0x600, .pagepool = gk104_grctx_generate_pagepool, .pagepool_size = 0x8000, + .attrib_cb_size = gf100_grctx_generate_attrib_cb_size, + .attrib_cb = gf100_grctx_generate_attrib_cb, .attrib = gf117_grctx_generate_attrib, .attrib_nr_max = 0x324, .attrib_nr = 0x218, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110.c index 86547cfc38dc..4391458e1fb2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110.c @@ -838,6 +838,8 @@ gk110_grctx = { .bundle_token_limit = 0x7c0, .pagepool = gk104_grctx_generate_pagepool, .pagepool_size = 0x8000, + .attrib_cb_size = gf100_grctx_generate_attrib_cb_size, + .attrib_cb = gf100_grctx_generate_attrib_cb, .attrib = gf117_grctx_generate_attrib, .attrib_nr_max = 0x324, .attrib_nr = 0x218, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110b.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110b.c index ebb947bd1446..7b9a34f9ec3c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110b.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110b.c @@ -87,6 +87,8 @@ gk110b_grctx = { .bundle_token_limit = 0x600, .pagepool = gk104_grctx_generate_pagepool, .pagepool_size = 0x8000, + .attrib_cb_size = gf100_grctx_generate_attrib_cb_size, + .attrib_cb = gf100_grctx_generate_attrib_cb, .attrib = gf117_grctx_generate_attrib, .attrib_nr_max = 0x324, .attrib_nr = 0x218, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk208.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk208.c index 4d40512b5c99..c78d07a8bb7d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk208.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk208.c @@ -553,6 +553,8 @@ gk208_grctx = { .bundle_token_limit = 0x200, .pagepool = gk104_grctx_generate_pagepool, .pagepool_size = 0x8000, + .attrib_cb_size = gf100_grctx_generate_attrib_cb_size, + .attrib_cb = gf100_grctx_generate_attrib_cb, .attrib = gf117_grctx_generate_attrib, .attrib_nr_max = 0x324, .attrib_nr = 0x218, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c index c0d36bc601f9..ac5fdcb5cd3f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c @@ -25,8 +25,9 @@ #include <subdev/mc.h> static void -gk20a_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) +gk20a_grctx_generate_main(struct gf100_gr_chan *chan) { + struct gf100_gr *gr = chan->gr; struct nvkm_device *device = gr->base.engine.subdev.device; const struct gf100_grctx_func *grctx = gr->func->grctx; u32 idle_timeout; @@ -38,7 +39,8 @@ gk20a_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) idle_timeout = nvkm_mask(device, 0x404154, 0xffffffff, 0x00000000); - grctx->attrib(info); + grctx->attrib_cb(chan, chan->attrib_cb->addr, grctx->attrib_cb_size(gr)); + grctx->attrib(chan); grctx->unkn(gr); @@ -60,8 +62,8 @@ gk20a_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) gf100_gr_wait_idle(gr); gf100_gr_icmd(gr, gr->bundle); - grctx->pagepool(info); - grctx->bundle(info); + grctx->pagepool(chan, chan->pagepool->addr); + grctx->bundle(chan, chan->bundle_cb->addr, grctx->bundle_size); } const struct gf100_grctx_func @@ -74,6 +76,8 @@ gk20a_grctx = { .bundle_token_limit = 0x100, .pagepool = gk104_grctx_generate_pagepool, .pagepool_size = 0x8000, + .attrib_cb_size = gf100_grctx_generate_attrib_cb_size, + .attrib_cb = gf100_grctx_generate_attrib_cb, .attrib = gf117_grctx_generate_attrib, .attrib_nr_max = 0x240, .attrib_nr = 0x240, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c index 0b3964e6b36e..beac66eb2a80 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c @@ -876,75 +876,70 @@ gm107_grctx_generate_r419e00(struct gf100_gr *gr) } void -gm107_grctx_generate_bundle(struct gf100_grctx *info) +gm107_grctx_generate_bundle(struct gf100_gr_chan *chan, u64 addr, u32 size) { - const struct gf100_grctx_func *grctx = info->gr->func->grctx; - const u32 state_limit = min(grctx->bundle_min_gpm_fifo_depth, - grctx->bundle_size / 0x20); + const struct gf100_grctx_func *grctx = chan->gr->func->grctx; + const u32 state_limit = min(grctx->bundle_min_gpm_fifo_depth, size / 0x20); const u32 token_limit = grctx->bundle_token_limit; - const int s = 8; - const int b = mmio_vram(info, grctx->bundle_size, (1 << s), true); - mmio_refn(info, 0x408004, 0x00000000, s, b); - mmio_wr32(info, 0x408008, 0x80000000 | (grctx->bundle_size >> s)); - mmio_refn(info, 0x418e24, 0x00000000, s, b); - mmio_wr32(info, 0x418e28, 0x80000000 | (grctx->bundle_size >> s)); - mmio_wr32(info, 0x4064c8, (state_limit << 16) | token_limit); + + gf100_grctx_patch_wr32(chan, 0x408004, addr >> 8); + gf100_grctx_patch_wr32(chan, 0x408008, 0x80000000 | (size >> 8)); + gf100_grctx_patch_wr32(chan, 0x418e24, addr >> 8); + gf100_grctx_patch_wr32(chan, 0x418e28, 0x80000000 | (size >> 8)); + gf100_grctx_patch_wr32(chan, 0x4064c8, (state_limit << 16) | token_limit); } void -gm107_grctx_generate_pagepool(struct gf100_grctx *info) +gm107_grctx_generate_pagepool(struct gf100_gr_chan *chan, u64 addr) { - const struct gf100_grctx_func *grctx = info->gr->func->grctx; - const int s = 8; - const int b = mmio_vram(info, grctx->pagepool_size, (1 << s), true); - mmio_refn(info, 0x40800c, 0x00000000, s, b); - mmio_wr32(info, 0x408010, 0x80000000); - mmio_refn(info, 0x419004, 0x00000000, s, b); - mmio_wr32(info, 0x419008, 0x00000000); - mmio_wr32(info, 0x4064cc, 0x80000000); - mmio_wr32(info, 0x418e30, 0x80000000); /* guess at it being related */ + gk104_grctx_generate_pagepool(chan, addr); + gf100_grctx_patch_wr32(chan, 0x418e30, 0x80000000); } void -gm107_grctx_generate_attrib(struct gf100_grctx *info) +gm107_grctx_generate_attrib(struct gf100_gr_chan *chan) { - struct gf100_gr *gr = info->gr; + struct gf100_gr *gr = chan->gr; const struct gf100_grctx_func *grctx = gr->func->grctx; const u32 alpha = grctx->alpha_nr; const u32 attrib = grctx->attrib_nr; - const u32 size = 0x20 * (grctx->attrib_nr_max + grctx->alpha_nr_max); - const int s = 12; - const int b = mmio_vram(info, size * gr->tpc_total, (1 << s), false); const int max_batches = 0xffff; u32 bo = 0; u32 ao = bo + grctx->attrib_nr_max * gr->tpc_total; int gpc, ppc, n = 0; - mmio_refn(info, 0x418810, 0x80000000, s, b); - mmio_refn(info, 0x419848, 0x10000000, s, b); - mmio_refn(info, 0x419c2c, 0x10000000, s, b); - mmio_wr32(info, 0x405830, (attrib << 16) | alpha); - mmio_wr32(info, 0x4064c4, ((alpha / 4) << 16) | max_batches); + gf100_grctx_patch_wr32(chan, 0x405830, (attrib << 16) | alpha); + gf100_grctx_patch_wr32(chan, 0x4064c4, ((alpha / 4) << 16) | max_batches); for (gpc = 0; gpc < gr->gpc_nr; gpc++) { - for (ppc = 0; ppc < gr->ppc_nr[gpc]; ppc++, n++) { + for (ppc = 0; ppc < gr->func->ppc_nr; ppc++, n++) { const u32 as = alpha * gr->ppc_tpc_nr[gpc][ppc]; const u32 bs = attrib * gr->ppc_tpc_nr[gpc][ppc]; const u32 u = 0x418ea0 + (n * 0x04); const u32 o = PPC_UNIT(gpc, ppc, 0); + if (!(gr->ppc_mask[gpc] & (1 << ppc))) continue; - mmio_wr32(info, o + 0xc0, bs); - mmio_wr32(info, o + 0xf4, bo); + + gf100_grctx_patch_wr32(chan, o + 0xc0, bs); + gf100_grctx_patch_wr32(chan, o + 0xf4, bo); bo += grctx->attrib_nr_max * gr->ppc_tpc_nr[gpc][ppc]; - mmio_wr32(info, o + 0xe4, as); - mmio_wr32(info, o + 0xf8, ao); + gf100_grctx_patch_wr32(chan, o + 0xe4, as); + gf100_grctx_patch_wr32(chan, o + 0xf8, ao); ao += grctx->alpha_nr_max * gr->ppc_tpc_nr[gpc][ppc]; - mmio_wr32(info, u, ((bs / 3) << 16) | bs); + gf100_grctx_patch_wr32(chan, u, ((bs / 3) << 16) | bs); } } } +void +gm107_grctx_generate_attrib_cb(struct gf100_gr_chan *chan, u64 addr, u32 size) +{ + gf100_grctx_generate_attrib_cb(chan, addr, size); + + gf100_grctx_patch_wr32(chan, 0x419c2c, 0x10000000 | addr >> 12); +} + static void gm107_grctx_generate_r406500(struct gf100_gr *gr) { @@ -978,6 +973,8 @@ gm107_grctx = { .bundle_token_limit = 0x2c0, .pagepool = gm107_grctx_generate_pagepool, .pagepool_size = 0x8000, + .attrib_cb_size = gf100_grctx_generate_attrib_cb_size, + .attrib_cb = gm107_grctx_generate_attrib_cb, .attrib = gm107_grctx_generate_attrib, .attrib_nr_max = 0xff0, .attrib_nr = 0xaa0, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm200.c index 013d05a0f0f6..175da8ac656c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm200.c @@ -87,7 +87,7 @@ gm200_grctx_generate_dist_skip_table(struct gf100_gr *gr) int gpc, ppc, i; for (gpc = 0; gpc < gr->gpc_nr; gpc++) { - for (ppc = 0; ppc < gr->ppc_nr[gpc]; ppc++) { + for (ppc = 0; ppc < gr->func->ppc_nr; ppc++) { u8 ppc_tpcs = gr->ppc_tpc_nr[gpc][ppc]; u8 ppc_tpcm = gr->ppc_tpc_mask[gpc][ppc]; while (ppc_tpcs-- > gr->ppc_tpc_min) @@ -111,6 +111,8 @@ gm200_grctx = { .bundle_token_limit = 0x780, .pagepool = gm107_grctx_generate_pagepool, .pagepool_size = 0x20000, + .attrib_cb_size = gf100_grctx_generate_attrib_cb_size, + .attrib_cb = gm107_grctx_generate_attrib_cb, .attrib = gm107_grctx_generate_attrib, .attrib_nr_max = 0x600, .attrib_nr = 0x400, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm20b.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm20b.c index 6b92f8aa18a3..b8edccfada58 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm20b.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm20b.c @@ -22,8 +22,9 @@ #include "ctxgf100.h" static void -gm20b_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) +gm20b_grctx_generate_main(struct gf100_gr_chan *chan) { + struct gf100_gr *gr = chan->gr; struct nvkm_device *device = gr->base.engine.subdev.device; const struct gf100_grctx_func *grctx = gr->func->grctx; u32 idle_timeout; @@ -35,7 +36,8 @@ gm20b_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) idle_timeout = nvkm_mask(device, 0x404154, 0xffffffff, 0x00000000); - grctx->attrib(info); + grctx->attrib_cb(chan, chan->attrib_cb->addr, grctx->attrib_cb_size(gr)); + grctx->attrib(chan); grctx->unkn(gr); @@ -63,8 +65,8 @@ gm20b_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) gf100_gr_wait_idle(gr); gf100_gr_icmd(gr, gr->bundle); - grctx->pagepool(info); - grctx->bundle(info); + grctx->pagepool(chan, chan->pagepool->addr); + grctx->bundle(chan, chan->bundle_cb->addr, grctx->bundle_size); } const struct gf100_grctx_func @@ -77,6 +79,8 @@ gm20b_grctx = { .bundle_token_limit = 0x1c0, .pagepool = gm107_grctx_generate_pagepool, .pagepool_size = 0x8000, + .attrib_cb_size = gf100_grctx_generate_attrib_cb_size, + .attrib_cb = gm107_grctx_generate_attrib_cb, .attrib = gm107_grctx_generate_attrib, .attrib_nr_max = 0x600, .attrib_nr = 0x400, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp100.c index 0b3326262e12..8485aaeae7a9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp100.c @@ -30,66 +30,76 @@ ******************************************************************************/ void -gp100_grctx_generate_pagepool(struct gf100_grctx *info) +gp100_grctx_generate_pagepool(struct gf100_gr_chan *chan, u64 addr) { - const struct gf100_grctx_func *grctx = info->gr->func->grctx; - const int s = 8; - const int b = mmio_vram(info, grctx->pagepool_size, (1 << s), true); - mmio_refn(info, 0x40800c, 0x00000000, s, b); - mmio_wr32(info, 0x408010, 0x8007d800); - mmio_refn(info, 0x419004, 0x00000000, s, b); - mmio_wr32(info, 0x419008, 0x00000000); + gf100_grctx_patch_wr32(chan, 0x40800c, addr >> 8); + gf100_grctx_patch_wr32(chan, 0x408010, 0x8007d800); + gf100_grctx_patch_wr32(chan, 0x419004, addr >> 8); + gf100_grctx_patch_wr32(chan, 0x419008, 0x00000000); } static void -gp100_grctx_generate_attrib(struct gf100_grctx *info) +gp100_grctx_generate_attrib(struct gf100_gr_chan *chan) { - struct gf100_gr *gr = info->gr; + struct gf100_gr *gr = chan->gr; const struct gf100_grctx_func *grctx = gr->func->grctx; const u32 alpha = grctx->alpha_nr; const u32 attrib = grctx->attrib_nr; - const int s = 12; const int max_batches = 0xffff; u32 size = grctx->alpha_nr_max * gr->tpc_total; u32 ao = 0; u32 bo = ao + size; - int gpc, ppc, b, n = 0; + int gpc, ppc, n = 0; - for (gpc = 0; gpc < gr->gpc_nr; gpc++) - size += grctx->attrib_nr_max * gr->ppc_nr[gpc] * gr->ppc_tpc_max; - size = ((size * 0x20) + 128) & ~127; - b = mmio_vram(info, size, (1 << s), false); - - mmio_refn(info, 0x418810, 0x80000000, s, b); - mmio_refn(info, 0x419848, 0x10000000, s, b); - mmio_refn(info, 0x419c2c, 0x10000000, s, b); - mmio_refn(info, 0x419b00, 0x00000000, s, b); - mmio_wr32(info, 0x419b04, 0x80000000 | size >> 7); - mmio_wr32(info, 0x405830, attrib); - mmio_wr32(info, 0x40585c, alpha); - mmio_wr32(info, 0x4064c4, ((alpha / 4) << 16) | max_batches); + gf100_grctx_patch_wr32(chan, 0x405830, attrib); + gf100_grctx_patch_wr32(chan, 0x40585c, alpha); + gf100_grctx_patch_wr32(chan, 0x4064c4, ((alpha / 4) << 16) | max_batches); for (gpc = 0; gpc < gr->gpc_nr; gpc++) { - for (ppc = 0; ppc < gr->ppc_nr[gpc]; ppc++, n++) { + for (ppc = 0; ppc < gr->func->ppc_nr; ppc++, n++) { const u32 as = alpha * gr->ppc_tpc_nr[gpc][ppc]; const u32 bs = attrib * gr->ppc_tpc_max; const u32 u = 0x418ea0 + (n * 0x04); const u32 o = PPC_UNIT(gpc, ppc, 0); + if (!(gr->ppc_mask[gpc] & (1 << ppc))) continue; - mmio_wr32(info, o + 0xc0, bs); - mmio_wr32(info, o + 0xf4, bo); - mmio_wr32(info, o + 0xf0, bs); + + gf100_grctx_patch_wr32(chan, o + 0xc0, bs); + gf100_grctx_patch_wr32(chan, o + 0xf4, bo); + gf100_grctx_patch_wr32(chan, o + 0xf0, bs); bo += grctx->attrib_nr_max * gr->ppc_tpc_max; - mmio_wr32(info, o + 0xe4, as); - mmio_wr32(info, o + 0xf8, ao); + gf100_grctx_patch_wr32(chan, o + 0xe4, as); + gf100_grctx_patch_wr32(chan, o + 0xf8, ao); ao += grctx->alpha_nr_max * gr->ppc_tpc_nr[gpc][ppc]; - mmio_wr32(info, u, bs); + gf100_grctx_patch_wr32(chan, u, bs); } } - mmio_wr32(info, 0x418eec, 0x00000000); - mmio_wr32(info, 0x41befc, 0x00000000); + gf100_grctx_patch_wr32(chan, 0x418eec, 0x00000000); + gf100_grctx_patch_wr32(chan, 0x41befc, 0x00000000); +} + +void +gp100_grctx_generate_attrib_cb(struct gf100_gr_chan *chan, u64 addr, u32 size) +{ + gm107_grctx_generate_attrib_cb(chan, addr, size); + + gf100_grctx_patch_wr32(chan, 0x419b00, 0x00000000 | addr >> 12); + gf100_grctx_patch_wr32(chan, 0x419b04, 0x80000000 | size >> 7); +} + +static u32 +gp100_grctx_generate_attrib_cb_size(struct gf100_gr *gr) +{ + const struct gf100_grctx_func *grctx = gr->func->grctx; + u32 size = grctx->alpha_nr_max * gr->tpc_total; + int gpc; + + for (gpc = 0; gpc < gr->gpc_nr; gpc++) + size += grctx->attrib_nr_max * gr->func->ppc_nr * gr->ppc_tpc_max; + + return ((size * 0x20) + 128) & ~127; } void @@ -123,6 +133,8 @@ gp100_grctx = { .bundle_token_limit = 0x1080, .pagepool = gp100_grctx_generate_pagepool, .pagepool_size = 0x20000, + .attrib_cb_size = gp100_grctx_generate_attrib_cb_size, + .attrib_cb = gp100_grctx_generate_attrib_cb, .attrib = gp100_grctx_generate_attrib, .attrib_nr_max = 0x660, .attrib_nr = 0x440, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp102.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp102.c index daee17bf7d0d..7537979a5492 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp102.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp102.c @@ -37,58 +37,62 @@ gp102_grctx_generate_r408840(struct gf100_gr *gr) } void -gp102_grctx_generate_attrib(struct gf100_grctx *info) +gp102_grctx_generate_attrib(struct gf100_gr_chan *chan) { - struct gf100_gr *gr = info->gr; + struct gf100_gr *gr = chan->gr; const struct gf100_grctx_func *grctx = gr->func->grctx; const u32 alpha = grctx->alpha_nr; const u32 attrib = grctx->attrib_nr; const u32 gfxp = grctx->gfxp_nr; - const int s = 12; const int max_batches = 0xffff; u32 size = grctx->alpha_nr_max * gr->tpc_total; u32 ao = 0; u32 bo = ao + size; - int gpc, ppc, b, n = 0; + int gpc, ppc, n = 0; - for (gpc = 0; gpc < gr->gpc_nr; gpc++) - size += grctx->gfxp_nr * gr->ppc_nr[gpc] * gr->ppc_tpc_max; - size = ((size * 0x20) + 128) & ~127; - b = mmio_vram(info, size, (1 << s), false); - - mmio_refn(info, 0x418810, 0x80000000, s, b); - mmio_refn(info, 0x419848, 0x10000000, s, b); - mmio_refn(info, 0x419c2c, 0x10000000, s, b); - mmio_refn(info, 0x419b00, 0x00000000, s, b); - mmio_wr32(info, 0x419b04, 0x80000000 | size >> 7); - mmio_wr32(info, 0x405830, attrib); - mmio_wr32(info, 0x40585c, alpha); - mmio_wr32(info, 0x4064c4, ((alpha / 4) << 16) | max_batches); + gf100_grctx_patch_wr32(chan, 0x405830, attrib); + gf100_grctx_patch_wr32(chan, 0x40585c, alpha); + gf100_grctx_patch_wr32(chan, 0x4064c4, ((alpha / 4) << 16) | max_batches); for (gpc = 0; gpc < gr->gpc_nr; gpc++) { - for (ppc = 0; ppc < gr->ppc_nr[gpc]; ppc++, n++) { + for (ppc = 0; ppc < gr->func->ppc_nr; ppc++, n++) { const u32 as = alpha * gr->ppc_tpc_nr[gpc][ppc]; const u32 bs = attrib * gr->ppc_tpc_max; const u32 gs = gfxp * gr->ppc_tpc_max; const u32 u = 0x418ea0 + (n * 0x04); const u32 o = PPC_UNIT(gpc, ppc, 0); const u32 p = GPC_UNIT(gpc, 0xc44 + (ppc * 4)); + if (!(gr->ppc_mask[gpc] & (1 << ppc))) continue; - mmio_wr32(info, o + 0xc0, gs); - mmio_wr32(info, p, bs); - mmio_wr32(info, o + 0xf4, bo); - mmio_wr32(info, o + 0xf0, bs); + + gf100_grctx_patch_wr32(chan, o + 0xc0, gs); + gf100_grctx_patch_wr32(chan, p, bs); + gf100_grctx_patch_wr32(chan, o + 0xf4, bo); + gf100_grctx_patch_wr32(chan, o + 0xf0, bs); bo += gs; - mmio_wr32(info, o + 0xe4, as); - mmio_wr32(info, o + 0xf8, ao); + gf100_grctx_patch_wr32(chan, o + 0xe4, as); + gf100_grctx_patch_wr32(chan, o + 0xf8, ao); ao += grctx->alpha_nr_max * gr->ppc_tpc_nr[gpc][ppc]; - mmio_wr32(info, u, bs); + gf100_grctx_patch_wr32(chan, u, bs); } } - mmio_wr32(info, 0x4181e4, 0x00000100); - mmio_wr32(info, 0x41befc, 0x00000100); + gf100_grctx_patch_wr32(chan, 0x4181e4, 0x00000100); + gf100_grctx_patch_wr32(chan, 0x41befc, 0x00000100); +} + +u32 +gp102_grctx_generate_attrib_cb_size(struct gf100_gr *gr) +{ + const struct gf100_grctx_func *grctx = gr->func->grctx; + u32 size = grctx->alpha_nr_max * gr->tpc_total; + int gpc; + + for (gpc = 0; gpc < gr->gpc_nr; gpc++) + size += grctx->gfxp_nr * gr->func->ppc_nr * gr->ppc_tpc_max; + + return ((size * 0x20) + 127) & ~127; } const struct gf100_grctx_func @@ -101,6 +105,8 @@ gp102_grctx = { .bundle_token_limit = 0x900, .pagepool = gp100_grctx_generate_pagepool, .pagepool_size = 0x20000, + .attrib_cb_size = gp102_grctx_generate_attrib_cb_size, + .attrib_cb = gp100_grctx_generate_attrib_cb, .attrib = gp102_grctx_generate_attrib, .attrib_nr_max = 0x4b0, .attrib_nr = 0x320, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp104.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp104.c index 3b85e3d326b2..90b5f793e567 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp104.c @@ -31,6 +31,8 @@ gp104_grctx = { .bundle_token_limit = 0x900, .pagepool = gp100_grctx_generate_pagepool, .pagepool_size = 0x20000, + .attrib_cb_size = gp102_grctx_generate_attrib_cb_size, + .attrib_cb = gp100_grctx_generate_attrib_cb, .attrib = gp102_grctx_generate_attrib, .attrib_nr_max = 0x4b0, .attrib_nr = 0x320, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp107.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp107.c index 5060c5ee5ce0..d191761a0471 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp107.c @@ -39,6 +39,8 @@ gp107_grctx = { .bundle_token_limit = 0x300, .pagepool = gp100_grctx_generate_pagepool, .pagepool_size = 0x20000, + .attrib_cb_size = gp102_grctx_generate_attrib_cb_size, + .attrib_cb = gp100_grctx_generate_attrib_cb, .attrib = gp102_grctx_generate_attrib, .attrib_nr_max = 0x15de, .attrib_nr = 0x540, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgv100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgv100.c index 39553d55d3f3..957ea9d6bad4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgv100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgv100.c @@ -25,7 +25,7 @@ * PGRAPH context implementation ******************************************************************************/ -const struct gf100_gr_init +static const struct gf100_gr_init gv100_grctx_init_sw_veid_bundle_init_0[] = { { 0x00001000, 64, 0x00100000, 0x00000008 }, { 0x00000941, 64, 0x00100000, 0x00000000 }, @@ -59,67 +59,70 @@ gv100_grctx_pack_sw_veid_bundle_init[] = { }; void -gv100_grctx_generate_attrib(struct gf100_grctx *info) +gv100_grctx_generate_attrib(struct gf100_gr_chan *chan) { - struct gf100_gr *gr = info->gr; + struct gf100_gr *gr = chan->gr; const struct gf100_grctx_func *grctx = gr->func->grctx; const u32 alpha = grctx->alpha_nr; const u32 attrib = grctx->attrib_nr; const u32 gfxp = grctx->gfxp_nr; - const int s = 12; + const int max_batches = 0xffff; u32 size = grctx->alpha_nr_max * gr->tpc_total; u32 ao = 0; u32 bo = ao + size; - int gpc, ppc, b, n = 0; + int gpc, ppc, n = 0; - for (gpc = 0; gpc < gr->gpc_nr; gpc++) - size += grctx->gfxp_nr * gr->ppc_nr[gpc] * gr->ppc_tpc_max; - size = ((size * 0x20) + 127) & ~127; - b = mmio_vram(info, size, (1 << s), false); - - mmio_refn(info, 0x418810, 0x80000000, s, b); - mmio_refn(info, 0x419848, 0x10000000, s, b); - mmio_refn(info, 0x419c2c, 0x10000000, s, b); - mmio_refn(info, 0x419e00, 0x00000000, s, b); - mmio_wr32(info, 0x419e04, 0x80000000 | size >> 7); - mmio_wr32(info, 0x405830, attrib); - mmio_wr32(info, 0x40585c, alpha); + gf100_grctx_patch_wr32(chan, 0x405830, attrib); + gf100_grctx_patch_wr32(chan, 0x40585c, alpha); + gf100_grctx_patch_wr32(chan, 0x4064c4, ((alpha / 4) << 16) | max_batches); for (gpc = 0; gpc < gr->gpc_nr; gpc++) { - for (ppc = 0; ppc < gr->ppc_nr[gpc]; ppc++, n++) { + for (ppc = 0; ppc < gr->func->ppc_nr; ppc++, n++) { const u32 as = alpha * gr->ppc_tpc_nr[gpc][ppc]; const u32 bs = attrib * gr->ppc_tpc_max; const u32 gs = gfxp * gr->ppc_tpc_max; const u32 u = 0x418ea0 + (n * 0x04); const u32 o = PPC_UNIT(gpc, ppc, 0); + if (!(gr->ppc_mask[gpc] & (1 << ppc))) continue; - mmio_wr32(info, o + 0xc0, gs); - mmio_wr32(info, o + 0xf4, bo); - mmio_wr32(info, o + 0xf0, bs); + + gf100_grctx_patch_wr32(chan, o + 0xc0, gs); + gf100_grctx_patch_wr32(chan, o + 0xf4, bo); + gf100_grctx_patch_wr32(chan, o + 0xf0, bs); bo += gs; - mmio_wr32(info, o + 0xe4, as); - mmio_wr32(info, o + 0xf8, ao); + gf100_grctx_patch_wr32(chan, o + 0xe4, as); + gf100_grctx_patch_wr32(chan, o + 0xf8, ao); ao += grctx->alpha_nr_max * gr->ppc_tpc_nr[gpc][ppc]; - mmio_wr32(info, u, bs); + gf100_grctx_patch_wr32(chan, u, bs); } } - mmio_wr32(info, 0x4181e4, 0x00000100); - mmio_wr32(info, 0x41befc, 0x00000100); + gf100_grctx_patch_wr32(chan, 0x4181e4, 0x00000100); + gf100_grctx_patch_wr32(chan, 0x41befc, 0x00000100); +} + +void +gv100_grctx_generate_attrib_cb(struct gf100_gr_chan *chan, u64 addr, u32 size) +{ + gm107_grctx_generate_attrib_cb(chan, addr, size); + + gf100_grctx_patch_wr32(chan, 0x419e00, 0x00000000 | addr >> 12); + gf100_grctx_patch_wr32(chan, 0x419e04, 0x80000000 | size >> 7); } void gv100_grctx_generate_rop_mapping(struct gf100_gr *gr) { struct nvkm_device *device = gr->base.engine.subdev.device; + const u32 mapregs = DIV_ROUND_UP(gr->func->gpc_nr * gr->func->tpc_nr, 6); u32 data; int i, j; /* Pack tile map into register format. */ nvkm_wr32(device, 0x418bb8, (gr->tpc_total << 8) | gr->screen_tile_row_offset); - for (i = 0; i < 11; i++) { + for (i = 0; i < mapregs; i++) { for (data = 0, j = 0; j < 6; j++) data |= (gr->tile[i * 6 + j] & 0x1f) << (j * 5); nvkm_wr32(device, 0x418b08 + (i * 4), data); @@ -157,6 +160,9 @@ static void gv100_grctx_generate_sm_id(struct gf100_gr *gr, int gpc, int tpc, int sm) { struct nvkm_device *device = gr->base.engine.subdev.device; + + tpc = gv100_gr_nonpes_aware_tpc(gr, gpc, tpc); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x608), sm); nvkm_wr32(device, GPC_UNIT(gpc, 0x0c10 + tpc * 4), sm); nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x088), sm); @@ -198,6 +204,8 @@ gv100_grctx = { .bundle_token_limit = 0x1680, .pagepool = gp100_grctx_generate_pagepool, .pagepool_size = 0x20000, + .attrib_cb_size = gp102_grctx_generate_attrib_cb_size, + .attrib_cb = gv100_grctx_generate_attrib_cb, .attrib = gv100_grctx_generate_attrib, .attrib_nr_max = 0x6c0, .attrib_nr = 0x480, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxtu102.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxtu102.c index 2299ca07d04a..542ab0c78be6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxtu102.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxtu102.c @@ -34,6 +34,9 @@ static void tu102_grctx_generate_sm_id(struct gf100_gr *gr, int gpc, int tpc, int sm) { struct nvkm_device *device = gr->base.engine.subdev.device; + + tpc = gv100_gr_nonpes_aware_tpc(gr, gpc, tpc); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x608), sm); nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x088), sm); } @@ -47,42 +50,38 @@ tu102_grctx_init_unknown_bundle_init_0[] = { }; static const struct gf100_gr_pack -tu102_grctx_pack_sw_veid_bundle_init[] = { - { gv100_grctx_init_sw_veid_bundle_init_0 }, - { tu102_grctx_init_unknown_bundle_init_0 }, +tu102_grctx_pack_sw_bundle64_init[] = { + { tu102_grctx_init_unknown_bundle_init_0, .type = 64 }, {} }; -static void -tu102_grctx_generate_attrib(struct gf100_grctx *info) +void +tu102_grctx_generate_unknown(struct gf100_gr_chan *chan, u64 addr, u32 size) { - const u64 size = 0x80000; /*XXX: educated guess */ - const int s = 8; - const int b = mmio_vram(info, size, (1 << s), true); - - gv100_grctx_generate_attrib(info); - - mmio_refn(info, 0x408070, 0x00000000, s, b); - mmio_wr32(info, 0x408074, size >> s); /*XXX: guess */ - mmio_refn(info, 0x419034, 0x00000000, s, b); - mmio_wr32(info, 0x408078, 0x00000000); + gf100_grctx_patch_wr32(chan, 0x408070, addr >> 8); + gf100_grctx_patch_wr32(chan, 0x408074, size >> 8); /*XXX: guess */ + gf100_grctx_patch_wr32(chan, 0x419034, addr >> 8); + gf100_grctx_patch_wr32(chan, 0x408078, 0x00000000); } const struct gf100_grctx_func tu102_grctx = { - .unkn88c = gv100_grctx_unkn88c, .main = gf100_grctx_generate_main, .unkn = gv100_grctx_generate_unkn, - .sw_veid_bundle_init = tu102_grctx_pack_sw_veid_bundle_init, + .sw_bundle64_init = tu102_grctx_pack_sw_bundle64_init, .bundle = gm107_grctx_generate_bundle, .bundle_size = 0x3000, .bundle_min_gpm_fifo_depth = 0x180, .bundle_token_limit = 0xa80, .pagepool = gp100_grctx_generate_pagepool, .pagepool_size = 0x20000, - .attrib = tu102_grctx_generate_attrib, + .attrib_cb_size = gp102_grctx_generate_attrib_cb_size, + .attrib_cb = gv100_grctx_generate_attrib_cb, + .attrib = gv100_grctx_generate_attrib, .attrib_nr_max = 0x800, .attrib_nr = 0x700, + .unknown_size = 0x80000, + .unknown = tu102_grctx_generate_unknown, .alpha_nr_max = 0xc00, .alpha_nr = 0x800, .gfxp_nr = 0xfa8, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ga102.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ga102.c new file mode 100644 index 000000000000..a5b5ac2755a2 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ga102.c @@ -0,0 +1,347 @@ +/* + * 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 "gf100.h" +#include "ctxgf100.h" + +#include <core/firmware.h> +#include <subdev/acr.h> +#include <subdev/timer.h> +#include <subdev/vfn.h> + +#include <nvfw/flcn.h> + +#include <nvif/class.h> + +static void +ga102_gr_zbc_clear_color(struct gf100_gr *gr, int zbc) +{ + struct nvkm_device *device = gr->base.engine.subdev.device; + u32 invalid[] = { 0, 0, 0, 0 }, *color; + + if (gr->zbc_color[zbc].format) + color = gr->zbc_color[zbc].l2; + else + color = invalid; + + nvkm_mask(device, 0x41bcb4, 0x0000001f, zbc); + nvkm_wr32(device, 0x41bcec, color[0]); + nvkm_wr32(device, 0x41bcf0, color[1]); + nvkm_wr32(device, 0x41bcf4, color[2]); + nvkm_wr32(device, 0x41bcf8, color[3]); +} + +static const struct gf100_gr_func_zbc +ga102_gr_zbc = { + .clear_color = ga102_gr_zbc_clear_color, + .clear_depth = gp100_gr_zbc_clear_depth, + .stencil_get = gp102_gr_zbc_stencil_get, + .clear_stencil = gp102_gr_zbc_clear_stencil, +}; + +static void +ga102_gr_gpccs_reset(struct gf100_gr *gr) +{ + struct nvkm_device *device = gr->base.engine.subdev.device; + + nvkm_wr32(device, 0x41a610, 0x00000000); + nvkm_msec(device, 1, NVKM_DELAY); + nvkm_wr32(device, 0x41a610, 0x00000001); +} + +static const struct nvkm_acr_lsf_func +ga102_gr_gpccs_acr = { + .flags = NVKM_ACR_LSF_FORCE_PRIV_LOAD, + .bl_entry = 0x3400, + .bld_size = sizeof(struct flcn_bl_dmem_desc_v2), + .bld_write = gp108_gr_acr_bld_write, + .bld_patch = gp108_gr_acr_bld_patch, +}; + +static void +ga102_gr_fecs_reset(struct gf100_gr *gr) +{ + struct nvkm_device *device = gr->base.engine.subdev.device; + + nvkm_wr32(device, 0x409614, 0x00000010); + nvkm_wr32(device, 0x41a614, 0x00000020); + nvkm_usec(device, 10, NVKM_DELAY); + nvkm_wr32(device, 0x409614, 0x00000110); + nvkm_wr32(device, 0x41a614, 0x00000a20); + nvkm_usec(device, 10, NVKM_DELAY); + nvkm_rd32(device, 0x409614); + nvkm_rd32(device, 0x41a614); +} + +static const struct nvkm_acr_lsf_func +ga102_gr_fecs_acr = { + .bl_entry = 0x7e00, + .bld_size = sizeof(struct flcn_bl_dmem_desc_v2), + .bld_write = gp108_gr_acr_bld_write, + .bld_patch = gp108_gr_acr_bld_patch, +}; + +static void +ga102_gr_init_rop_exceptions(struct gf100_gr *gr) +{ + struct nvkm_device *device = gr->base.engine.subdev.device; + + nvkm_wr32(device, 0x41bcbc, 0x40000000); + nvkm_wr32(device, 0x41bc38, 0x40000000); + nvkm_wr32(device, 0x41ac94, nvkm_rd32(device, 0x502c94)); +} + +static void +ga102_gr_init_40a790(struct gf100_gr *gr) +{ + nvkm_wr32(gr->base.engine.subdev.device, 0x40a790, 0xc0000000); +} + +static void +ga102_gr_init_gpc_mmu(struct gf100_gr *gr) +{ + struct nvkm_device *device = gr->base.engine.subdev.device; + + nvkm_wr32(device, 0x418880, nvkm_rd32(device, 0x100c80) & 0xf8001fff); + nvkm_wr32(device, 0x418894, 0x00000000); + + nvkm_wr32(device, 0x4188b4, nvkm_rd32(device, 0x100cc8)); + nvkm_wr32(device, 0x4188b8, nvkm_rd32(device, 0x100ccc)); + nvkm_wr32(device, 0x4188b0, nvkm_rd32(device, 0x100cc4)); +} + +static struct nvkm_intr * +ga102_gr_oneinit_intr(struct gf100_gr *gr, enum nvkm_intr_type *pvector) +{ + struct nvkm_device *device = gr->base.engine.subdev.device; + + *pvector = nvkm_rd32(device, 0x400154) & 0x00000fff; + return &device->vfn->intr; +} + +static const struct gf100_gr_func +ga102_gr = { + .oneinit_intr = ga102_gr_oneinit_intr, + .oneinit_tiles = gm200_gr_oneinit_tiles, + .oneinit_sm_id = gv100_gr_oneinit_sm_id, + .init = gf100_gr_init, + .init_419bd8 = gv100_gr_init_419bd8, + .init_gpc_mmu = ga102_gr_init_gpc_mmu, + .init_vsc_stream_master = gk104_gr_init_vsc_stream_master, + .init_zcull = tu102_gr_init_zcull, + .init_num_active_ltcs = gf100_gr_init_num_active_ltcs, + .init_swdx_pes_mask = gp102_gr_init_swdx_pes_mask, + .init_fs = tu102_gr_init_fs, + .init_fecs_exceptions = tu102_gr_init_fecs_exceptions, + .init_40a790 = ga102_gr_init_40a790, + .init_ds_hww_esr_2 = gm200_gr_init_ds_hww_esr_2, + .init_sked_hww_esr = gk104_gr_init_sked_hww_esr, + .init_ppc_exceptions = gk104_gr_init_ppc_exceptions, + .init_504430 = gv100_gr_init_504430, + .init_shader_exceptions = gv100_gr_init_shader_exceptions, + .init_rop_exceptions = ga102_gr_init_rop_exceptions, + .init_4188a4 = gv100_gr_init_4188a4, + .trap_mp = gv100_gr_trap_mp, + .fecs.reset = ga102_gr_fecs_reset, + .gpccs.reset = ga102_gr_gpccs_reset, + .rops = gm200_gr_rops, + .gpc_nr = 7, + .tpc_nr = 6, + .ppc_nr = 3, + .grctx = &ga102_grctx, + .zbc = &ga102_gr_zbc, + .sclass = { + { -1, -1, FERMI_TWOD_A }, + { -1, -1, KEPLER_INLINE_TO_MEMORY_B }, + { -1, -1, AMPERE_B, &gf100_fermi }, + { -1, -1, AMPERE_COMPUTE_B }, + {} + } +}; + +MODULE_FIRMWARE("nvidia/ga102/gr/fecs_bl.bin"); +MODULE_FIRMWARE("nvidia/ga102/gr/fecs_sig.bin"); +MODULE_FIRMWARE("nvidia/ga102/gr/gpccs_bl.bin"); +MODULE_FIRMWARE("nvidia/ga102/gr/gpccs_sig.bin"); +MODULE_FIRMWARE("nvidia/ga102/gr/NET_img.bin"); + +MODULE_FIRMWARE("nvidia/ga103/gr/fecs_bl.bin"); +MODULE_FIRMWARE("nvidia/ga103/gr/fecs_sig.bin"); +MODULE_FIRMWARE("nvidia/ga103/gr/gpccs_bl.bin"); +MODULE_FIRMWARE("nvidia/ga103/gr/gpccs_sig.bin"); +MODULE_FIRMWARE("nvidia/ga103/gr/NET_img.bin"); + +MODULE_FIRMWARE("nvidia/ga104/gr/fecs_bl.bin"); +MODULE_FIRMWARE("nvidia/ga104/gr/fecs_sig.bin"); +MODULE_FIRMWARE("nvidia/ga104/gr/gpccs_bl.bin"); +MODULE_FIRMWARE("nvidia/ga104/gr/gpccs_sig.bin"); +MODULE_FIRMWARE("nvidia/ga104/gr/NET_img.bin"); + +MODULE_FIRMWARE("nvidia/ga106/gr/fecs_bl.bin"); +MODULE_FIRMWARE("nvidia/ga106/gr/fecs_sig.bin"); +MODULE_FIRMWARE("nvidia/ga106/gr/gpccs_bl.bin"); +MODULE_FIRMWARE("nvidia/ga106/gr/gpccs_sig.bin"); +MODULE_FIRMWARE("nvidia/ga106/gr/NET_img.bin"); + +MODULE_FIRMWARE("nvidia/ga107/gr/fecs_bl.bin"); +MODULE_FIRMWARE("nvidia/ga107/gr/fecs_sig.bin"); +MODULE_FIRMWARE("nvidia/ga107/gr/gpccs_bl.bin"); +MODULE_FIRMWARE("nvidia/ga107/gr/gpccs_sig.bin"); +MODULE_FIRMWARE("nvidia/ga107/gr/NET_img.bin"); + +struct netlist_region { + u32 region_id; + u32 data_size; + u32 data_offset; +}; + +struct netlist_image_header { + u32 version; + u32 regions; +}; + +struct netlist_image { + struct netlist_image_header header; + struct netlist_region regions[]; +}; + +struct netlist_av64 { + u32 addr; + u32 data_hi; + u32 data_lo; +}; + +static int +ga102_gr_av64_to_init(struct nvkm_blob *blob, struct gf100_gr_pack **ppack) +{ + struct gf100_gr_init *init; + struct gf100_gr_pack *pack; + int nent; + int i; + + nent = (blob->size / sizeof(struct netlist_av64)); + pack = vzalloc((sizeof(*pack) * 2) + (sizeof(*init) * (nent + 1))); + if (!pack) + return -ENOMEM; + + init = (void *)(pack + 2); + pack[0].init = init; + pack[0].type = 64; + + for (i = 0; i < nent; i++) { + struct gf100_gr_init *ent = &init[i]; + struct netlist_av64 *av = &((struct netlist_av64 *)blob->data)[i]; + + ent->addr = av->addr; + ent->data = ((u64)av->data_hi << 32) | av->data_lo; + ent->count = 1; + ent->pitch = 1; + } + + *ppack = pack; + return 0; +} + +static int +ga102_gr_load(struct gf100_gr *gr, int ver, const struct gf100_gr_fwif *fwif) +{ + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + const struct firmware *fw; + const struct netlist_image *net; + const struct netlist_region *fecs_inst = NULL; + const struct netlist_region *fecs_data = NULL; + const struct netlist_region *gpccs_inst = NULL; + const struct netlist_region *gpccs_data = NULL; + int ret, i; + + ret = nvkm_firmware_get(subdev, "gr/NET_img", 0, &fw); + if (ret) + return ret; + + net = (const void *)fw->data; + nvkm_debug(subdev, "netlist version %d, %d regions\n", + net->header.version, net->header.regions); + + for (i = 0; i < net->header.regions; i++) { + const struct netlist_region *reg = &net->regions[i]; + struct nvkm_blob blob = { + .data = (void *)fw->data + reg->data_offset, + .size = reg->data_size, + }; + + nvkm_debug(subdev, "\t%2d: %08x %08x\n", + reg->region_id, reg->data_offset, reg->data_size); + + switch (reg->region_id) { + case 0: fecs_data = reg; break; + case 1: fecs_inst = reg; break; + case 2: gpccs_data = reg; break; + case 3: gpccs_inst = reg; break; + case 4: gk20a_gr_av_to_init(&blob, &gr->bundle); break; + case 5: gk20a_gr_aiv_to_init(&blob, &gr->sw_ctx); break; + case 7: gk20a_gr_av_to_method(&blob, &gr->method); break; + case 28: tu102_gr_av_to_init_veid(&blob, &gr->bundle_veid); break; + case 34: ga102_gr_av64_to_init(&blob, &gr->bundle64); break; + case 48: gk20a_gr_av_to_init(&blob, &gr->sw_nonctx1); break; + case 49: gk20a_gr_av_to_init(&blob, &gr->sw_nonctx2); break; + case 50: gk20a_gr_av_to_init(&blob, &gr->sw_nonctx3); break; + case 51: gk20a_gr_av_to_init(&blob, &gr->sw_nonctx4); break; + default: + break; + } + } + + ret = nvkm_acr_lsfw_load_bl_sig_net(subdev, &gr->fecs.falcon, NVKM_ACR_LSF_FECS, + "gr/fecs_", ver, fwif->fecs, + fw->data + fecs_inst->data_offset, + fecs_inst->data_size, + fw->data + fecs_data->data_offset, + fecs_data->data_size); + if (ret) + return ret; + + ret = nvkm_acr_lsfw_load_bl_sig_net(subdev, &gr->gpccs.falcon, NVKM_ACR_LSF_GPCCS, + "gr/gpccs_", ver, fwif->gpccs, + fw->data + gpccs_inst->data_offset, + gpccs_inst->data_size, + fw->data + gpccs_data->data_offset, + gpccs_data->data_size); + if (ret) + return ret; + + gr->firmware = true; + + nvkm_firmware_put(fw); + return 0; +} + +static const struct gf100_gr_fwif +ga102_gr_fwif[] = { + { 0, ga102_gr_load, &ga102_gr, &ga102_gr_fecs_acr, &ga102_gr_gpccs_acr }, + { -1, gm200_gr_nofw }, + {} +}; + +int +ga102_gr_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_gr **pgr) +{ + return gf100_gr_new_(ga102_gr_fwif, device, type, inst, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c index f16eabf4f642..5f20079c3660 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c @@ -67,7 +67,7 @@ gf100_gr_zbc_color_get(struct gf100_gr *gr, int format, struct nvkm_ltc *ltc = gr->base.engine.subdev.device->ltc; int zbc = -ENOSPC, i; - for (i = ltc->zbc_min; i <= ltc->zbc_max; i++) { + for (i = ltc->zbc_color_min; i <= ltc->zbc_color_max; i++) { if (gr->zbc_color[i].format) { if (gr->zbc_color[i].format != format) continue; @@ -114,7 +114,7 @@ gf100_gr_zbc_depth_get(struct gf100_gr *gr, int format, struct nvkm_ltc *ltc = gr->base.engine.subdev.device->ltc; int zbc = -ENOSPC, i; - for (i = ltc->zbc_min; i <= ltc->zbc_max; i++) { + for (i = ltc->zbc_depth_min; i <= ltc->zbc_depth_max; i++) { if (gr->zbc_depth[i].format) { if (gr->zbc_depth[i].format != format) continue; @@ -355,15 +355,14 @@ static void * gf100_gr_chan_dtor(struct nvkm_object *object) { struct gf100_gr_chan *chan = gf100_gr_chan(object); - int i; - - for (i = 0; i < ARRAY_SIZE(chan->data); i++) { - nvkm_vmm_put(chan->vmm, &chan->data[i].vma); - nvkm_memory_unref(&chan->data[i].mem); - } nvkm_vmm_put(chan->vmm, &chan->mmio_vma); nvkm_memory_unref(&chan->mmio); + + nvkm_vmm_put(chan->vmm, &chan->attrib_cb); + nvkm_vmm_put(chan->vmm, &chan->unknown); + nvkm_vmm_put(chan->vmm, &chan->bundle_cb); + nvkm_vmm_put(chan->vmm, &chan->pagepool); nvkm_vmm_unref(&chan->vmm); return chan; } @@ -380,12 +379,10 @@ gf100_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, struct nvkm_object **pobject) { struct gf100_gr *gr = gf100_gr(base); - struct gf100_gr_data *data = gr->mmio_data; - struct gf100_gr_mmio *mmio = gr->mmio_list; struct gf100_gr_chan *chan; struct gf100_vmm_map_v0 args = { .priv = 1 }; struct nvkm_device *device = gr->base.engine.subdev.device; - int ret, i; + int ret; if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) return -ENOMEM; @@ -394,63 +391,91 @@ gf100_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, chan->vmm = nvkm_vmm_ref(fifoch->vmm); *pobject = &chan->object; - /* allocate memory for a "mmio list" buffer that's used by the HUB - * fuc to modify some per-context register settings on first load - * of the context. - */ - ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 0x100, - false, &chan->mmio); + /* Map pagepool. */ + ret = nvkm_vmm_get(chan->vmm, 12, nvkm_memory_size(gr->pagepool), &chan->pagepool); if (ret) return ret; - ret = nvkm_vmm_get(fifoch->vmm, 12, 0x1000, &chan->mmio_vma); + ret = nvkm_memory_map(gr->pagepool, 0, chan->vmm, chan->pagepool, &args, sizeof(args)); if (ret) return ret; - ret = nvkm_memory_map(chan->mmio, 0, fifoch->vmm, - chan->mmio_vma, &args, sizeof(args)); + /* Map bundle circular buffer. */ + ret = nvkm_vmm_get(chan->vmm, 12, nvkm_memory_size(gr->bundle_cb), &chan->bundle_cb); + if (ret) + return ret; + + ret = nvkm_memory_map(gr->bundle_cb, 0, chan->vmm, chan->bundle_cb, &args, sizeof(args)); + if (ret) + return ret; + + /* Map attribute circular buffer. */ + ret = nvkm_vmm_get(chan->vmm, 12, nvkm_memory_size(gr->attrib_cb), &chan->attrib_cb); if (ret) return ret; - /* allocate buffers referenced by mmio list */ - for (i = 0; data->size && i < ARRAY_SIZE(gr->mmio_data); i++) { - ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, - data->size, data->align, false, - &chan->data[i].mem); + if (device->card_type < GP100) { + ret = nvkm_memory_map(gr->attrib_cb, 0, chan->vmm, chan->attrib_cb, NULL, 0); if (ret) return ret; - - ret = nvkm_vmm_get(fifoch->vmm, 12, - nvkm_memory_size(chan->data[i].mem), - &chan->data[i].vma); + } else { + ret = nvkm_memory_map(gr->attrib_cb, 0, chan->vmm, chan->attrib_cb, + &args, sizeof(args));; if (ret) return ret; + } - args.priv = data->priv; + /* Map some context buffer of unknown purpose. */ + if (gr->func->grctx->unknown_size) { + ret = nvkm_vmm_get(chan->vmm, 12, nvkm_memory_size(gr->unknown), &chan->unknown); + if (ret) + return ret; - ret = nvkm_memory_map(chan->data[i].mem, 0, chan->vmm, - chan->data[i].vma, &args, sizeof(args)); + ret = nvkm_memory_map(gr->unknown, 0, chan->vmm, chan->unknown, + &args, sizeof(args)); if (ret) return ret; + } - data++; + /* Generate golden context image. */ + mutex_lock(&gr->fecs.mutex); + if (gr->data == NULL) { + ret = gf100_grctx_generate(gr, chan, fifoch->inst); + if (ret) { + nvkm_error(&base->engine.subdev, "failed to construct context\n"); + return ret; + } } + mutex_unlock(&gr->fecs.mutex); - /* finally, fill in the mmio list and point the context at it */ - nvkm_kmap(chan->mmio); - for (i = 0; mmio->addr && i < ARRAY_SIZE(gr->mmio_list); i++) { - u32 addr = mmio->addr; - u32 data = mmio->data; + /* allocate memory for a "mmio list" buffer that's used by the HUB + * fuc to modify some per-context register settings on first load + * of the context. + */ + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 0x100, + false, &chan->mmio); + if (ret) + return ret; - if (mmio->buffer >= 0) { - u64 info = chan->data[mmio->buffer].vma->addr; - data |= info >> mmio->shift; - } + ret = nvkm_vmm_get(fifoch->vmm, 12, 0x1000, &chan->mmio_vma); + if (ret) + return ret; - nvkm_wo32(chan->mmio, chan->mmio_nr++ * 4, addr); - nvkm_wo32(chan->mmio, chan->mmio_nr++ * 4, data); - mmio++; - } + ret = nvkm_memory_map(chan->mmio, 0, fifoch->vmm, + chan->mmio_vma, &args, sizeof(args)); + if (ret) + return ret; + + /* finally, fill in the mmio list and point the context at it */ + nvkm_kmap(chan->mmio); + gr->func->grctx->pagepool(chan, chan->pagepool->addr); + gr->func->grctx->bundle(chan, chan->bundle_cb->addr, gr->func->grctx->bundle_size); + gr->func->grctx->attrib_cb(chan, chan->attrib_cb->addr, gr->func->grctx->attrib_cb_size(gr)); + gr->func->grctx->attrib(chan); + if (gr->func->grctx->patch_ltc) + gr->func->grctx->patch_ltc(chan); + if (gr->func->grctx->unknown_size) + gr->func->grctx->unknown(chan, chan->unknown->addr, gr->func->grctx->unknown_size); nvkm_done(chan->mmio); return 0; } @@ -727,7 +752,7 @@ gf100_gr_fecs_ctrl_ctxsw(struct gf100_gr *gr, u32 mthd) struct nvkm_device *device = gr->base.engine.subdev.device; nvkm_wr32(device, 0x409804, 0xffffffff); - nvkm_wr32(device, 0x409840, 0xffffffff); + nvkm_wr32(device, 0x409800, 0x00000000); nvkm_wr32(device, 0x409500, 0xffffffff); nvkm_wr32(device, 0x409504, mthd); nvkm_msec(device, 2000, @@ -771,12 +796,45 @@ gf100_gr_fecs_stop_ctxsw(struct nvkm_gr *base) return ret; } +static int +gf100_gr_fecs_halt_pipeline(struct gf100_gr *gr) +{ + int ret = 0; + + if (gr->firmware) { + mutex_lock(&gr->fecs.mutex); + ret = gf100_gr_fecs_ctrl_ctxsw(gr, 0x04); + mutex_unlock(&gr->fecs.mutex); + } + + return ret; +} + +int +gf100_gr_fecs_wfi_golden_save(struct gf100_gr *gr, u32 inst) +{ + struct nvkm_device *device = gr->base.engine.subdev.device; + + nvkm_mask(device, 0x409800, 0x00000003, 0x00000000); + nvkm_wr32(device, 0x409500, inst); + nvkm_wr32(device, 0x409504, 0x00000009); + nvkm_msec(device, 2000, + u32 stat = nvkm_rd32(device, 0x409800); + if (stat & 0x00000002) + return -EIO; + if (stat & 0x00000001) + return 0; + ); + + return -ETIMEDOUT; +} + int gf100_gr_fecs_bind_pointer(struct gf100_gr *gr, u32 inst) { struct nvkm_device *device = gr->base.engine.subdev.device; - nvkm_wr32(device, 0x409840, 0x00000030); + nvkm_mask(device, 0x409800, 0x00000030, 0x00000000); nvkm_wr32(device, 0x409500, inst); nvkm_wr32(device, 0x409504, 0x00000003); nvkm_msec(device, 2000, @@ -867,7 +925,7 @@ gf100_gr_fecs_discover_pm_image_size(struct gf100_gr *gr, u32 *psize) { struct nvkm_device *device = gr->base.engine.subdev.device; - nvkm_wr32(device, 0x409840, 0xffffffff); + nvkm_wr32(device, 0x409800, 0x00000000); nvkm_wr32(device, 0x409500, 0x00000000); nvkm_wr32(device, 0x409504, 0x00000025); nvkm_msec(device, 2000, @@ -883,7 +941,7 @@ gf100_gr_fecs_discover_zcull_image_size(struct gf100_gr *gr, u32 *psize) { struct nvkm_device *device = gr->base.engine.subdev.device; - nvkm_wr32(device, 0x409840, 0xffffffff); + nvkm_wr32(device, 0x409800, 0x00000000); nvkm_wr32(device, 0x409500, 0x00000000); nvkm_wr32(device, 0x409504, 0x00000016); nvkm_msec(device, 2000, @@ -899,7 +957,7 @@ gf100_gr_fecs_discover_image_size(struct gf100_gr *gr, u32 *psize) { struct nvkm_device *device = gr->base.engine.subdev.device; - nvkm_wr32(device, 0x409840, 0xffffffff); + nvkm_wr32(device, 0x409800, 0x00000000); nvkm_wr32(device, 0x409500, 0x00000000); nvkm_wr32(device, 0x409504, 0x00000010); nvkm_msec(device, 2000, @@ -915,7 +973,7 @@ gf100_gr_fecs_set_watchdog_timeout(struct gf100_gr *gr, u32 timeout) { struct nvkm_device *device = gr->base.engine.subdev.device; - nvkm_wr32(device, 0x409840, 0xffffffff); + nvkm_wr32(device, 0x409800, 0x00000000); nvkm_wr32(device, 0x409500, timeout); nvkm_wr32(device, 0x409504, 0x00000021); } @@ -955,7 +1013,7 @@ gf100_gr_zbc_init(struct gf100_gr *gr) const u32 f32_1[] = { 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000 }; struct nvkm_ltc *ltc = gr->base.engine.subdev.device->ltc; - int index, c = ltc->zbc_min, d = ltc->zbc_min, s = ltc->zbc_min; + int index, c = ltc->zbc_color_min, d = ltc->zbc_depth_min, s = ltc->zbc_depth_min; if (!gr->zbc_color[0].format) { gf100_gr_zbc_color_get(gr, 1, & zero[0], &zero[4]); c++; @@ -971,13 +1029,13 @@ gf100_gr_zbc_init(struct gf100_gr *gr) } } - for (index = c; index <= ltc->zbc_max; index++) + for (index = c; index <= ltc->zbc_color_max; index++) gr->func->zbc->clear_color(gr, index); - for (index = d; index <= ltc->zbc_max; index++) + for (index = d; index <= ltc->zbc_depth_max; index++) gr->func->zbc->clear_depth(gr, index); if (gr->func->zbc->clear_stencil) { - for (index = s; index <= ltc->zbc_max; index++) + for (index = s; index <= ltc->zbc_depth_max; index++) gr->func->zbc->clear_stencil(gr, index); } } @@ -1003,7 +1061,7 @@ gf100_gr_wait_idle(struct gf100_gr *gr) nvkm_rd32(device, 0x400700); gr_enabled = nvkm_rd32(device, 0x200) & 0x1000; - ctxsw_active = nvkm_rd32(device, 0x2640) & 0x8000; + ctxsw_active = nvkm_fifo_ctxsw_in_progress(&gr->base.engine); gr_busy = nvkm_rd32(device, 0x40060c) & 0x1; if (!gr_enabled || (!gr_busy && !ctxsw_active)) @@ -1039,7 +1097,7 @@ gf100_gr_icmd(struct gf100_gr *gr, const struct gf100_gr_pack *p) struct nvkm_device *device = gr->base.engine.subdev.device; const struct gf100_gr_pack *pack; const struct gf100_gr_init *init; - u32 data = 0; + u64 data = 0; nvkm_wr32(device, 0x400208, 0x80000000); @@ -1049,6 +1107,8 @@ gf100_gr_icmd(struct gf100_gr *gr, const struct gf100_gr_pack *p) if ((pack == p && init == p->init) || data != init->data) { nvkm_wr32(device, 0x400204, init->data); + if (pack->type == 64) + nvkm_wr32(device, 0x40020c, upper_32_bits(init->data)); data = init->data; } @@ -1542,13 +1602,13 @@ gf100_gr_ctxctl_isr(struct gf100_gr *gr) } } -static void -gf100_gr_intr(struct nvkm_gr *base) +static irqreturn_t +gf100_gr_intr(struct nvkm_inth *inth) { - struct gf100_gr *gr = gf100_gr(base); + struct gf100_gr *gr = container_of(inth, typeof(*gr), base.engine.subdev.inth); struct nvkm_subdev *subdev = &gr->base.engine.subdev; struct nvkm_device *device = subdev->device; - struct nvkm_fifo_chan *chan; + struct nvkm_chan *chan; unsigned long flags; u64 inst = nvkm_rd32(device, 0x409b00) & 0x0fffffff; u32 stat = nvkm_rd32(device, 0x400100); @@ -1561,10 +1621,10 @@ gf100_gr_intr(struct nvkm_gr *base) const char *name = "unknown"; int chid = -1; - chan = nvkm_fifo_chan_inst(device->fifo, (u64)inst << 12, &flags); + chan = nvkm_chan_get_inst(&gr->base.engine, (u64)inst << 12, &flags); if (chan) { - name = chan->object.client->name; - chid = chan->chid; + name = chan->name; + chid = chan->id; } if (device->card_type < NV_E0 || subc < 4) @@ -1631,7 +1691,8 @@ gf100_gr_intr(struct nvkm_gr *base) } nvkm_wr32(device, 0x400500, 0x00010001); - nvkm_fifo_chan_put(device->fifo, flags, &chan); + nvkm_chan_put(&chan, flags); + return IRQ_HANDLED; } static void @@ -1721,7 +1782,7 @@ gf100_gr_init_ctxctl_ext(struct gf100_gr *gr) nvkm_mc_unk260(device, 1); /* start both of them running */ - nvkm_wr32(device, 0x409840, 0xffffffff); + nvkm_wr32(device, 0x409800, 0x00000000); nvkm_wr32(device, 0x41a10c, 0x00000000); nvkm_wr32(device, 0x40910c, 0x00000000); @@ -1763,15 +1824,6 @@ gf100_gr_init_ctxctl_ext(struct gf100_gr *gr) return ret; } - /* Generate golden context image. */ - if (gr->data == NULL) { - int ret = gf100_grctx_generate(gr); - if (ret) { - nvkm_error(subdev, "failed to construct context\n"); - return ret; - } - } - return 0; } @@ -1823,14 +1875,6 @@ gf100_gr_init_ctxctl_int(struct gf100_gr *gr) } gr->size = nvkm_rd32(device, 0x409804); - if (gr->data == NULL) { - int ret = gf100_grctx_generate(gr); - if (ret) { - nvkm_error(subdev, "failed to construct context\n"); - return ret; - } - } - return 0; } @@ -1847,10 +1891,11 @@ gf100_gr_init_ctxctl(struct gf100_gr *gr) return ret; } -void +int gf100_gr_oneinit_sm_id(struct gf100_gr *gr) { int tpc, gpc; + for (tpc = 0; tpc < gr->tpc_max; tpc++) { for (gpc = 0; gpc < gr->gpc_nr; gpc++) { if (tpc < gr->tpc_nr[gpc]) { @@ -1860,6 +1905,8 @@ gf100_gr_oneinit_sm_id(struct gf100_gr *gr) } } } + + return 0; } void @@ -1944,7 +1991,17 @@ gf100_gr_oneinit(struct nvkm_gr *base) struct gf100_gr *gr = gf100_gr(base); struct nvkm_subdev *subdev = &gr->base.engine.subdev; struct nvkm_device *device = subdev->device; - int i, j; + struct nvkm_intr *intr = &device->mc->intr; + enum nvkm_intr_type intr_type = NVKM_INTR_SUBDEV; + int ret, i, j; + + if (gr->func->oneinit_intr) + intr = gr->func->oneinit_intr(gr, &intr_type); + + ret = nvkm_inth_add(intr, intr_type, NVKM_INTR_PRIO_NORMAL, &gr->base.engine.subdev, + gf100_gr_intr, &gr->base.engine.subdev.inth); + if (ret) + return ret; nvkm_pmu_pgob(device->pmu, false); @@ -1954,12 +2011,14 @@ gf100_gr_oneinit(struct nvkm_gr *base) gr->tpc_nr[i] = nvkm_rd32(device, GPC_UNIT(i, 0x2608)); gr->tpc_max = max(gr->tpc_max, gr->tpc_nr[i]); gr->tpc_total += gr->tpc_nr[i]; - gr->ppc_nr[i] = gr->func->ppc_nr; - for (j = 0; j < gr->ppc_nr[i]; j++) { + for (j = 0; j < gr->func->ppc_nr; j++) { gr->ppc_tpc_mask[i][j] = nvkm_rd32(device, GPC_UNIT(i, 0x0c30 + (j * 4))); if (gr->ppc_tpc_mask[i][j] == 0) continue; + + gr->ppc_nr[i]++; + gr->ppc_mask[i] |= (1 << j); gr->ppc_tpc_nr[i][j] = hweight8(gr->ppc_tpc_mask[i][j]); if (gr->ppc_tpc_min == 0 || @@ -1968,12 +2027,37 @@ gf100_gr_oneinit(struct nvkm_gr *base) if (gr->ppc_tpc_max < gr->ppc_tpc_nr[i][j]) gr->ppc_tpc_max = gr->ppc_tpc_nr[i][j]; } + + gr->ppc_total += gr->ppc_nr[i]; + } + + /* Allocate global context buffers. */ + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, gr->func->grctx->pagepool_size, + 0x100, false, &gr->pagepool); + if (ret) + return ret; + + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, gr->func->grctx->bundle_size, + 0x100, false, &gr->bundle_cb); + if (ret) + return ret; + + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, gr->func->grctx->attrib_cb_size(gr), + 0x1000, false, &gr->attrib_cb); + if (ret) + return ret; + + if (gr->func->grctx->unknown_size) { + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, gr->func->grctx->unknown_size, + 0x100, false, &gr->unknown); + if (ret) + return ret; } memset(gr->tile, 0xff, sizeof(gr->tile)); gr->func->oneinit_tiles(gr); - gr->func->oneinit_sm_id(gr); - return 0; + + return gr->func->oneinit_sm_id(gr); } static int @@ -1983,7 +2067,7 @@ gf100_gr_init_(struct nvkm_gr *base) struct nvkm_subdev *subdev = &base->engine.subdev; struct nvkm_device *device = subdev->device; bool reset = device->chipset == 0x137 || device->chipset == 0x138; - u32 ret; + int ret; /* On certain GP107/GP108 boards, we trigger a weird issue where * GR will stop responding to PRI accesses after we've asked the @@ -2019,7 +2103,12 @@ gf100_gr_init_(struct nvkm_gr *base) if (ret) return ret; - return gr->func->init(gr); + ret = gr->func->init(gr); + if (ret) + return ret; + + nvkm_inth_allow(&subdev->inth); + return 0; } static int @@ -2027,6 +2116,9 @@ gf100_gr_fini(struct nvkm_gr *base, bool suspend) { struct gf100_gr *gr = gf100_gr(base); struct nvkm_subdev *subdev = &gr->base.engine.subdev; + + nvkm_inth_block(&subdev->inth); + nvkm_falcon_put(&gr->gpccs.falcon, subdev); nvkm_falcon_put(&gr->fecs.falcon, subdev); return 0; @@ -2039,6 +2131,11 @@ gf100_gr_dtor(struct nvkm_gr *base) kfree(gr->data); + nvkm_memory_unref(&gr->unknown); + nvkm_memory_unref(&gr->attrib_cb); + nvkm_memory_unref(&gr->bundle_cb); + nvkm_memory_unref(&gr->pagepool); + nvkm_falcon_dtor(&gr->gpccs.falcon); nvkm_falcon_dtor(&gr->fecs.falcon); @@ -2047,81 +2144,27 @@ gf100_gr_dtor(struct nvkm_gr *base) nvkm_blob_dtor(&gr->gpccs.inst); nvkm_blob_dtor(&gr->gpccs.data); + vfree(gr->bundle64); + vfree(gr->bundle_veid); vfree(gr->bundle); vfree(gr->method); vfree(gr->sw_ctx); vfree(gr->sw_nonctx); + vfree(gr->sw_nonctx1); + vfree(gr->sw_nonctx2); + vfree(gr->sw_nonctx3); + vfree(gr->sw_nonctx4); return gr; } -static const struct nvkm_gr_func -gf100_gr_ = { - .dtor = gf100_gr_dtor, - .oneinit = gf100_gr_oneinit, - .init = gf100_gr_init_, - .fini = gf100_gr_fini, - .intr = gf100_gr_intr, - .units = gf100_gr_units, - .chan_new = gf100_gr_chan_new, - .object_get = gf100_gr_object_get, - .chsw_load = gf100_gr_chsw_load, - .ctxsw.pause = gf100_gr_fecs_stop_ctxsw, - .ctxsw.resume = gf100_gr_fecs_start_ctxsw, - .ctxsw.inst = gf100_gr_ctxsw_inst, -}; - static const struct nvkm_falcon_func gf100_gr_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 = 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, }; -int -gf100_gr_new_(const struct gf100_gr_fwif *fwif, struct nvkm_device *device, - enum nvkm_subdev_type type, int inst, struct nvkm_gr **pgr) -{ - struct gf100_gr *gr; - int ret; - - if (!(gr = kzalloc(sizeof(*gr), GFP_KERNEL))) - return -ENOMEM; - *pgr = &gr->base; - - ret = nvkm_gr_ctor(&gf100_gr_, device, type, inst, true, &gr->base); - if (ret) - return ret; - - fwif = nvkm_firmware_load(&gr->base.engine.subdev, fwif, "Gr", gr); - if (IS_ERR(fwif)) - return PTR_ERR(fwif); - - gr->func = fwif->func; - - ret = nvkm_falcon_ctor(&gf100_gr_flcn, &gr->base.engine.subdev, - "fecs", 0x409000, &gr->fecs.falcon); - if (ret) - return ret; - - mutex_init(&gr->fecs.mutex); - - ret = nvkm_falcon_ctor(&gf100_gr_flcn, &gr->base.engine.subdev, - "gpccs", 0x41a000, &gr->gpccs.falcon); - if (ret) - return ret; - - return 0; -} - void gf100_gr_init_num_tpc_per_gpc(struct gf100_gr *gr, bool pd, bool ds) { @@ -2146,6 +2189,29 @@ gf100_gr_init_400054(struct gf100_gr *gr) } void +gf100_gr_init_exception2(struct gf100_gr *gr) +{ + struct nvkm_device *device = gr->base.engine.subdev.device; + + nvkm_wr32(device, 0x40011c, 0xffffffff); + nvkm_wr32(device, 0x400134, 0xffffffff); +} + +void +gf100_gr_init_rop_exceptions(struct gf100_gr *gr) +{ + struct nvkm_device *device = gr->base.engine.subdev.device; + int rop; + + for (rop = 0; rop < gr->rop_nr; rop++) { + nvkm_wr32(device, ROP_UNIT(rop, 0x144), 0x40000000); + nvkm_wr32(device, ROP_UNIT(rop, 0x070), 0x40000000); + nvkm_wr32(device, ROP_UNIT(rop, 0x204), 0xffffffff); + nvkm_wr32(device, ROP_UNIT(rop, 0x208), 0xffffffff); + } +} + +void gf100_gr_init_shader_exceptions(struct gf100_gr *gr, int gpc, int tpc) { struct nvkm_device *device = gr->base.engine.subdev.device; @@ -2252,21 +2318,47 @@ gf100_gr_init_vsc_stream_master(struct gf100_gr *gr) nvkm_mask(device, TPC_UNIT(0, 0, 0x05c), 0x00000001, 0x00000001); } +static int +gf100_gr_reset(struct nvkm_gr *base) +{ + struct nvkm_subdev *subdev = &base->engine.subdev; + struct nvkm_device *device = subdev->device; + struct gf100_gr *gr = gf100_gr(base); + + nvkm_mask(device, 0x400500, 0x00000001, 0x00000000); + + WARN_ON(gf100_gr_fecs_halt_pipeline(gr)); + + subdev->func->fini(subdev, false); + nvkm_mc_disable(device, subdev->type, subdev->inst); + if (gr->func->gpccs.reset) + gr->func->gpccs.reset(gr); + + nvkm_mc_enable(device, subdev->type, subdev->inst); + return subdev->func->init(subdev); +} + int gf100_gr_init(struct gf100_gr *gr) { struct nvkm_device *device = gr->base.engine.subdev.device; - int gpc, tpc, rop; + int gpc, tpc; - if (gr->func->init_419bd8) - gr->func->init_419bd8(gr); + nvkm_mask(device, 0x400500, 0x00010001, 0x00000000); gr->func->init_gpc_mmu(gr); - if (gr->sw_nonctx) + if (gr->sw_nonctx1) { + gf100_gr_mmio(gr, gr->sw_nonctx1); + gf100_gr_mmio(gr, gr->sw_nonctx2); + gf100_gr_mmio(gr, gr->sw_nonctx3); + gf100_gr_mmio(gr, gr->sw_nonctx4); + } else + if (gr->sw_nonctx) { gf100_gr_mmio(gr, gr->sw_nonctx); - else + } else { gf100_gr_mmio(gr, gr->func->mmio); + } gf100_gr_wait_idle(gr); @@ -2298,6 +2390,10 @@ gf100_gr_init(struct gf100_gr *gr) nvkm_wr32(device, 0x400124, 0x00000002); gr->func->init_fecs_exceptions(gr); + + if (gr->func->init_40a790) + gr->func->init_40a790(gr); + if (gr->func->init_ds_hww_esr_2) gr->func->init_ds_hww_esr_2(gr); @@ -2346,19 +2442,14 @@ gf100_gr_init(struct gf100_gr *gr) nvkm_wr32(device, GPC_UNIT(gpc, 0x2c94), 0xffffffff); } - for (rop = 0; rop < gr->rop_nr; rop++) { - nvkm_wr32(device, ROP_UNIT(rop, 0x144), 0x40000000); - nvkm_wr32(device, ROP_UNIT(rop, 0x070), 0x40000000); - nvkm_wr32(device, ROP_UNIT(rop, 0x204), 0xffffffff); - nvkm_wr32(device, ROP_UNIT(rop, 0x208), 0xffffffff); - } + gr->func->init_rop_exceptions(gr); nvkm_wr32(device, 0x400108, 0xffffffff); nvkm_wr32(device, 0x400138, 0xffffffff); nvkm_wr32(device, 0x400118, 0xffffffff); nvkm_wr32(device, 0x400130, 0xffffffff); - nvkm_wr32(device, 0x40011c, 0xffffffff); - nvkm_wr32(device, 0x400134, 0xffffffff); + if (gr->func->init_exception2) + gr->func->init_exception2(gr); if (gr->func->init_400054) gr->func->init_400054(gr); @@ -2371,6 +2462,18 @@ gf100_gr_init(struct gf100_gr *gr) return gf100_gr_init_ctxctl(gr); } +void +gf100_gr_fecs_reset(struct gf100_gr *gr) +{ + struct nvkm_device *device = gr->base.engine.subdev.device; + + nvkm_wr32(device, 0x409614, 0x00000070); + nvkm_usec(device, 10, NVKM_DELAY); + nvkm_mask(device, 0x409614, 0x00000700, 0x00000700); + nvkm_usec(device, 10, NVKM_DELAY); + nvkm_rd32(device, 0x409614); +} + #include "fuc/hubgf100.fuc3.h" struct gf100_gr_ucode @@ -2391,6 +2494,22 @@ gf100_gr_gpccs_ucode = { .data.size = sizeof(gf100_grgpc_data), }; +static const struct nvkm_gr_func +gf100_gr_ = { + .dtor = gf100_gr_dtor, + .oneinit = gf100_gr_oneinit, + .init = gf100_gr_init_, + .fini = gf100_gr_fini, + .reset = gf100_gr_reset, + .units = gf100_gr_units, + .chan_new = gf100_gr_chan_new, + .object_get = gf100_gr_object_get, + .chsw_load = gf100_gr_chsw_load, + .ctxsw.pause = gf100_gr_fecs_stop_ctxsw, + .ctxsw.resume = gf100_gr_fecs_start_ctxsw, + .ctxsw.inst = gf100_gr_ctxsw_inst, +}; + static const struct gf100_gr_func gf100_gr = { .oneinit_tiles = gf100_gr_oneinit_tiles, @@ -2406,10 +2525,13 @@ gf100_gr = { .init_419eb4 = gf100_gr_init_419eb4, .init_tex_hww_esr = gf100_gr_init_tex_hww_esr, .init_shader_exceptions = gf100_gr_init_shader_exceptions, + .init_rop_exceptions = gf100_gr_init_rop_exceptions, + .init_exception2 = gf100_gr_init_exception2, .init_400054 = gf100_gr_init_400054, .trap_mp = gf100_gr_trap_mp, .mmio = gf100_gr_pack_mmio, .fecs.ucode = &gf100_gr_fecs_ucode, + .fecs.reset = gf100_gr_fecs_reset, .gpccs.ucode = &gf100_gr_gpccs_ucode, .rops = gf100_gr_rops, .grctx = &gf100_grctx, @@ -2483,6 +2605,42 @@ gf100_gr_fwif[] = { }; int +gf100_gr_new_(const struct gf100_gr_fwif *fwif, struct nvkm_device *device, + enum nvkm_subdev_type type, int inst, struct nvkm_gr **pgr) +{ + struct gf100_gr *gr; + int ret; + + if (!(gr = kzalloc(sizeof(*gr), GFP_KERNEL))) + return -ENOMEM; + *pgr = &gr->base; + + ret = nvkm_gr_ctor(&gf100_gr_, device, type, inst, true, &gr->base); + if (ret) + return ret; + + fwif = nvkm_firmware_load(&gr->base.engine.subdev, fwif, "Gr", gr); + if (IS_ERR(fwif)) + return PTR_ERR(fwif); + + gr->func = fwif->func; + + ret = nvkm_falcon_ctor(&gf100_gr_flcn, &gr->base.engine.subdev, + "fecs", 0x409000, &gr->fecs.falcon); + if (ret) + return ret; + + mutex_init(&gr->fecs.mutex); + + ret = nvkm_falcon_ctor(&gf100_gr_flcn, &gr->base.engine.subdev, + "gpccs", 0x41a000, &gr->gpccs.falcon); + if (ret) + return ret; + + return 0; +} + +int gf100_gr_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_gr **pgr) { return gf100_gr_new_(gf100_gr_fwif, device, type, inst, pgr); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h index c0038f906135..94ca7ac16acf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h @@ -44,19 +44,6 @@ struct nvkm_acr_lsfw; #define PPC_UNIT(t, m, r) (0x503000 + (t) * 0x8000 + (m) * 0x200 + (r)) #define TPC_UNIT(t, m, r) (0x504000 + (t) * 0x8000 + (m) * 0x800 + (r)) -struct gf100_gr_data { - u32 size; - u32 align; - bool priv; -}; - -struct gf100_gr_mmio { - u32 addr; - u32 data; - u32 shift; - int buffer; -}; - struct gf100_gr_zbc_color { u32 format; u32 ds[4]; @@ -101,13 +88,19 @@ struct gf100_gr { * using hardcoded arrays. To be allocated with vzalloc(). */ struct gf100_gr_pack *sw_nonctx; + struct gf100_gr_pack *sw_nonctx1; + struct gf100_gr_pack *sw_nonctx2; + struct gf100_gr_pack *sw_nonctx3; + struct gf100_gr_pack *sw_nonctx4; struct gf100_gr_pack *sw_ctx; struct gf100_gr_pack *bundle; + struct gf100_gr_pack *bundle_veid; + struct gf100_gr_pack *bundle64; struct gf100_gr_pack *method; - struct gf100_gr_zbc_color zbc_color[NVKM_LTC_MAX_ZBC_CNT]; - struct gf100_gr_zbc_depth zbc_depth[NVKM_LTC_MAX_ZBC_CNT]; - struct gf100_gr_zbc_stencil zbc_stencil[NVKM_LTC_MAX_ZBC_CNT]; + struct gf100_gr_zbc_color zbc_color[NVKM_LTC_MAX_ZBC_COLOR_CNT]; + struct gf100_gr_zbc_depth zbc_depth[NVKM_LTC_MAX_ZBC_DEPTH_CNT]; + struct gf100_gr_zbc_stencil zbc_stencil[NVKM_LTC_MAX_ZBC_DEPTH_CNT]; u8 rop_nr; u8 gpc_nr; @@ -120,6 +113,12 @@ struct gf100_gr { u8 ppc_tpc_nr[GPC_MAX][4]; u8 ppc_tpc_min; u8 ppc_tpc_max; + u8 ppc_total; + + struct nvkm_memory *pagepool; + struct nvkm_memory *bundle_cb; + struct nvkm_memory *attrib_cb; + struct nvkm_memory *unknown; u8 screen_tile_row_offset; u8 tile[TPC_MAX]; @@ -130,8 +129,6 @@ struct gf100_gr { } sm[TPC_MAX]; u8 sm_nr; - struct gf100_gr_data mmio_data[4]; - struct gf100_gr_mmio mmio_list[4096/8]; u32 size; u32 *data; u32 size_zcull; @@ -139,6 +136,7 @@ struct gf100_gr { }; int gf100_gr_fecs_bind_pointer(struct gf100_gr *, u32 inst); +int gf100_gr_fecs_wfi_golden_save(struct gf100_gr *, u32 inst); struct gf100_gr_func_zbc { void (*clear_color)(struct gf100_gr *, int zbc); @@ -149,8 +147,9 @@ struct gf100_gr_func_zbc { }; struct gf100_gr_func { + struct nvkm_intr *(*oneinit_intr)(struct gf100_gr *, enum nvkm_intr_type *); void (*oneinit_tiles)(struct gf100_gr *); - void (*oneinit_sm_id)(struct gf100_gr *); + int (*oneinit_sm_id)(struct gf100_gr *); int (*init)(struct gf100_gr *); void (*init_419bd8)(struct gf100_gr *); void (*init_gpc_mmu)(struct gf100_gr *); @@ -164,6 +163,7 @@ struct gf100_gr_func { void (*init_swdx_pes_mask)(struct gf100_gr *); void (*init_fs)(struct gf100_gr *); void (*init_fecs_exceptions)(struct gf100_gr *); + void (*init_40a790)(struct gf100_gr *); void (*init_ds_hww_esr_2)(struct gf100_gr *); void (*init_40601c)(struct gf100_gr *); void (*init_sked_hww_esr)(struct gf100_gr *); @@ -174,6 +174,8 @@ struct gf100_gr_func { void (*init_tex_hww_esr)(struct gf100_gr *, int gpc, int tpc); void (*init_504430)(struct gf100_gr *, int gpc, int tpc); void (*init_shader_exceptions)(struct gf100_gr *, int gpc, int tpc); + void (*init_rop_exceptions)(struct gf100_gr *); + void (*init_exception2)(struct gf100_gr *); void (*init_400054)(struct gf100_gr *); void (*init_4188a4)(struct gf100_gr *); void (*trap_mp)(struct gf100_gr *, int gpc, int tpc); @@ -181,9 +183,11 @@ struct gf100_gr_func { const struct gf100_gr_pack *mmio; struct { struct gf100_gr_ucode *ucode; + void (*reset)(struct gf100_gr *); } fecs; struct { struct gf100_gr_ucode *ucode; + void (*reset)(struct gf100_gr *); } gpccs; int (*rops)(struct gf100_gr *); int gpc_nr; @@ -197,7 +201,7 @@ struct gf100_gr_func { int gf100_gr_rops(struct gf100_gr *); void gf100_gr_oneinit_tiles(struct gf100_gr *); -void gf100_gr_oneinit_sm_id(struct gf100_gr *); +int gf100_gr_oneinit_sm_id(struct gf100_gr *); int gf100_gr_init(struct gf100_gr *); void gf100_gr_init_vsc_stream_master(struct gf100_gr *); void gf100_gr_init_zcull(struct gf100_gr *); @@ -208,9 +212,12 @@ void gf100_gr_init_419cc0(struct gf100_gr *); void gf100_gr_init_419eb4(struct gf100_gr *); void gf100_gr_init_tex_hww_esr(struct gf100_gr *, int, int); void gf100_gr_init_shader_exceptions(struct gf100_gr *, int, int); +void gf100_gr_init_rop_exceptions(struct gf100_gr *); +void gf100_gr_init_exception2(struct gf100_gr *); void gf100_gr_init_400054(struct gf100_gr *); void gf100_gr_init_num_tpc_per_gpc(struct gf100_gr *, bool, bool); extern const struct gf100_gr_func_zbc gf100_gr_zbc; +void gf100_gr_fecs_reset(struct gf100_gr *); void gf117_gr_init_zcull(struct gf100_gr *); @@ -226,9 +233,13 @@ void gm107_gr_init_shader_exceptions(struct gf100_gr *, int, int); void gm107_gr_init_400054(struct gf100_gr *); int gk20a_gr_init(struct gf100_gr *); +int gk20a_gr_av_to_init_(struct nvkm_blob *, u8 count, u32 pitch, struct gf100_gr_pack **); +int gk20a_gr_av_to_init(struct nvkm_blob *, struct gf100_gr_pack **); +int gk20a_gr_aiv_to_init(struct nvkm_blob *, struct gf100_gr_pack **); +int gk20a_gr_av_to_method(struct nvkm_blob *, struct gf100_gr_pack **); void gm200_gr_oneinit_tiles(struct gf100_gr *); -void gm200_gr_oneinit_sm_id(struct gf100_gr *); +int gm200_gr_oneinit_sm_id(struct gf100_gr *); int gm200_gr_rops(struct gf100_gr *); void gm200_gr_init_num_active_ltcs(struct gf100_gr *); void gm200_gr_init_ds_hww_esr_2(struct gf100_gr *); @@ -242,14 +253,24 @@ extern const struct gf100_gr_func_zbc gp100_gr_zbc; void gp102_gr_init_swdx_pes_mask(struct gf100_gr *); extern const struct gf100_gr_func_zbc gp102_gr_zbc; +int gp102_gr_zbc_stencil_get(struct gf100_gr *, int, const u32, const u32); +void gp102_gr_zbc_clear_stencil(struct gf100_gr *, int); extern const struct gf100_gr_func gp107_gr; +int gv100_gr_oneinit_sm_id(struct gf100_gr *); +u32 gv100_gr_nonpes_aware_tpc(struct gf100_gr *gr, u32 gpc, u32 tpc); void gv100_gr_init_419bd8(struct gf100_gr *); void gv100_gr_init_504430(struct gf100_gr *, int, int); void gv100_gr_init_shader_exceptions(struct gf100_gr *, int, int); +void gv100_gr_init_4188a4(struct gf100_gr *); void gv100_gr_trap_mp(struct gf100_gr *, int, int); +int tu102_gr_av_to_init_veid(struct nvkm_blob *, struct gf100_gr_pack **); +void tu102_gr_init_zcull(struct gf100_gr *); +void tu102_gr_init_fs(struct gf100_gr *); +void tu102_gr_init_fecs_exceptions(struct gf100_gr *); + #define gf100_gr_chan(p) container_of((p), struct gf100_gr_chan, object) #include <core/object.h> @@ -258,14 +279,14 @@ struct gf100_gr_chan { struct gf100_gr *gr; struct nvkm_vmm *vmm; + struct nvkm_vma *pagepool; + struct nvkm_vma *bundle_cb; + struct nvkm_vma *attrib_cb; + struct nvkm_vma *unknown; + struct nvkm_memory *mmio; struct nvkm_vma *mmio_vma; int mmio_nr; - - struct { - struct nvkm_memory *mem; - struct nvkm_vma *vma; - } data[4]; }; void gf100_gr_ctxctl_debug(struct gf100_gr *); @@ -279,7 +300,7 @@ struct gf100_gr_init { u32 addr; u8 count; u32 pitch; - u32 data; + u64 data; }; struct gf100_gr_pack { @@ -403,6 +424,9 @@ int gf100_gr_load(struct gf100_gr *, int, const struct gf100_gr_fwif *); int gf100_gr_nofw(struct gf100_gr *, int, const struct gf100_gr_fwif *); int gk20a_gr_load_sw(struct gf100_gr *, const char *path, int ver); +int gk20a_gr_load_net(struct gf100_gr *, const char *, const char *, int, + int (*)(struct nvkm_blob *, struct gf100_gr_pack **), + struct gf100_gr_pack **); int gm200_gr_nofw(struct gf100_gr *, int, const struct gf100_gr_fwif *); int gm200_gr_load(struct gf100_gr *, int, const struct gf100_gr_fwif *); @@ -415,6 +439,8 @@ void gm20b_gr_acr_bld_patch(struct nvkm_acr *, u32, s64); extern const struct nvkm_acr_lsf_func gp108_gr_gpccs_acr; extern const struct nvkm_acr_lsf_func gp108_gr_fecs_acr; +void gp108_gr_acr_bld_write(struct nvkm_acr *, u32, struct nvkm_acr_lsfw *); +void gp108_gr_acr_bld_patch(struct nvkm_acr *, u32, s64); int gf100_gr_new_(const struct gf100_gr_fwif *, struct nvkm_device *, enum nvkm_subdev_type, int, struct nvkm_gr **); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf104.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf104.c index 3acd99c306f2..63bd29c22fe1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf104.c @@ -127,10 +127,13 @@ gf104_gr = { .init_419eb4 = gf100_gr_init_419eb4, .init_tex_hww_esr = gf100_gr_init_tex_hww_esr, .init_shader_exceptions = gf100_gr_init_shader_exceptions, + .init_rop_exceptions = gf100_gr_init_rop_exceptions, + .init_exception2 = gf100_gr_init_exception2, .init_400054 = gf100_gr_init_400054, .trap_mp = gf100_gr_trap_mp, .mmio = gf104_gr_pack_mmio, .fecs.ucode = &gf100_gr_fecs_ucode, + .fecs.reset = gf100_gr_fecs_reset, .gpccs.ucode = &gf100_gr_gpccs_ucode, .rops = gf100_gr_rops, .grctx = &gf104_grctx, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf108.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf108.c index ab3760e804b8..495a844f925f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf108.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf108.c @@ -125,10 +125,13 @@ gf108_gr = { .init_419eb4 = gf100_gr_init_419eb4, .init_tex_hww_esr = gf100_gr_init_tex_hww_esr, .init_shader_exceptions = gf100_gr_init_shader_exceptions, + .init_rop_exceptions = gf100_gr_init_rop_exceptions, + .init_exception2 = gf100_gr_init_exception2, .init_400054 = gf100_gr_init_400054, .trap_mp = gf100_gr_trap_mp, .mmio = gf108_gr_pack_mmio, .fecs.ucode = &gf100_gr_fecs_ucode, + .fecs.reset = gf100_gr_fecs_reset, .gpccs.ucode = &gf100_gr_gpccs_ucode, .rops = gf100_gr_rops, .grctx = &gf108_grctx, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf110.c index 616e2def1865..70fad235d161 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf110.c @@ -99,10 +99,13 @@ gf110_gr = { .init_419eb4 = gf100_gr_init_419eb4, .init_tex_hww_esr = gf100_gr_init_tex_hww_esr, .init_shader_exceptions = gf100_gr_init_shader_exceptions, + .init_rop_exceptions = gf100_gr_init_rop_exceptions, + .init_exception2 = gf100_gr_init_exception2, .init_400054 = gf100_gr_init_400054, .trap_mp = gf100_gr_trap_mp, .mmio = gf110_gr_pack_mmio, .fecs.ucode = &gf100_gr_fecs_ucode, + .fecs.reset = gf100_gr_fecs_reset, .gpccs.ucode = &gf100_gr_gpccs_ucode, .rops = gf100_gr_rops, .grctx = &gf110_grctx, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf117.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf117.c index 669e7536970e..f12728248048 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf117.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf117.c @@ -125,7 +125,9 @@ gf117_gr_init_zcull(struct gf100_gr *gr) { struct nvkm_device *device = gr->base.engine.subdev.device; const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, gr->tpc_total); - const u8 tile_nr = ALIGN(gr->tpc_total, 32); + /*TODO: fill in litter vals for gf117-gm2xx */ + const u8 tile_nr = !gr->func->gpc_nr ? ALIGN(gr->tpc_total, 32) : + (gr->func->gpc_nr * gr->func->tpc_nr); u8 bank[GPC_MAX] = {}, gpc, i, j; u32 data; @@ -163,10 +165,13 @@ gf117_gr = { .init_419eb4 = gf100_gr_init_419eb4, .init_tex_hww_esr = gf100_gr_init_tex_hww_esr, .init_shader_exceptions = gf100_gr_init_shader_exceptions, + .init_rop_exceptions = gf100_gr_init_rop_exceptions, + .init_exception2 = gf100_gr_init_exception2, .init_400054 = gf100_gr_init_400054, .trap_mp = gf100_gr_trap_mp, .mmio = gf117_gr_pack_mmio, .fecs.ucode = &gf117_gr_fecs_ucode, + .fecs.reset = gf100_gr_fecs_reset, .gpccs.ucode = &gf117_gr_gpccs_ucode, .rops = gf100_gr_rops, .ppc_nr = 1, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf119.c index 5b09bda8110c..75ceb514c06e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf119.c @@ -190,10 +190,13 @@ gf119_gr = { .init_419eb4 = gf100_gr_init_419eb4, .init_tex_hww_esr = gf100_gr_init_tex_hww_esr, .init_shader_exceptions = gf100_gr_init_shader_exceptions, + .init_rop_exceptions = gf100_gr_init_rop_exceptions, + .init_exception2 = gf100_gr_init_exception2, .init_400054 = gf100_gr_init_400054, .trap_mp = gf100_gr_trap_mp, .mmio = gf119_gr_pack_mmio, .fecs.ucode = &gf100_gr_fecs_ucode, + .fecs.reset = gf100_gr_fecs_reset, .gpccs.ucode = &gf100_gr_gpccs_ucode, .rops = gf100_gr_rops, .grctx = &gf119_grctx, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c index b680eaa0f350..e53ade24ad23 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c @@ -418,7 +418,7 @@ gk104_gr_init_ppc_exceptions(struct gf100_gr *gr) int gpc, ppc; for (gpc = 0; gpc < gr->gpc_nr; gpc++) { - for (ppc = 0; ppc < gr->ppc_nr[gpc]; ppc++) { + for (ppc = 0; ppc < gr->func->ppc_nr; ppc++) { if (!(gr->ppc_mask[gpc] & (1 << ppc))) continue; nvkm_wr32(device, PPC_UNIT(gpc, ppc, 0x038), 0xc0000000); @@ -470,10 +470,13 @@ gk104_gr = { .init_ppc_exceptions = gk104_gr_init_ppc_exceptions, .init_tex_hww_esr = gf100_gr_init_tex_hww_esr, .init_shader_exceptions = gf100_gr_init_shader_exceptions, + .init_rop_exceptions = gf100_gr_init_rop_exceptions, + .init_exception2 = gf100_gr_init_exception2, .init_400054 = gf100_gr_init_400054, .trap_mp = gf100_gr_trap_mp, .mmio = gk104_gr_pack_mmio, .fecs.ucode = &gk104_gr_fecs_ucode, + .fecs.reset = gf100_gr_fecs_reset, .gpccs.ucode = &gk104_gr_gpccs_ucode, .rops = gf100_gr_rops, .ppc_nr = 1, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.c index 103e06a77e65..c7e1c5dbc6a9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.c @@ -366,10 +366,13 @@ gk110_gr = { .init_ppc_exceptions = gk104_gr_init_ppc_exceptions, .init_tex_hww_esr = gf100_gr_init_tex_hww_esr, .init_shader_exceptions = gf100_gr_init_shader_exceptions, + .init_rop_exceptions = gf100_gr_init_rop_exceptions, + .init_exception2 = gf100_gr_init_exception2, .init_400054 = gf100_gr_init_400054, .trap_mp = gf100_gr_trap_mp, .mmio = gk110_gr_pack_mmio, .fecs.ucode = &gk110_gr_fecs_ucode, + .fecs.reset = gf100_gr_fecs_reset, .gpccs.ucode = &gk110_gr_gpccs_ucode, .rops = gf100_gr_rops, .ppc_nr = 2, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110b.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110b.c index 034d0b11a17d..458abae571bf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110b.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110b.c @@ -118,10 +118,13 @@ gk110b_gr = { .init_ppc_exceptions = gk104_gr_init_ppc_exceptions, .init_tex_hww_esr = gf100_gr_init_tex_hww_esr, .init_shader_exceptions = gf100_gr_init_shader_exceptions, + .init_rop_exceptions = gf100_gr_init_rop_exceptions, + .init_exception2 = gf100_gr_init_exception2, .init_400054 = gf100_gr_init_400054, .trap_mp = gf100_gr_trap_mp, .mmio = gk110b_gr_pack_mmio, .fecs.ucode = &gk110_gr_fecs_ucode, + .fecs.reset = gf100_gr_fecs_reset, .gpccs.ucode = &gk110_gr_gpccs_ucode, .rops = gf100_gr_rops, .ppc_nr = 2, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk208.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk208.c index 116d682f9f96..d3f6b65c21d2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk208.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk208.c @@ -176,10 +176,13 @@ gk208_gr = { .init_ppc_exceptions = gk104_gr_init_ppc_exceptions, .init_tex_hww_esr = gf100_gr_init_tex_hww_esr, .init_shader_exceptions = gf100_gr_init_shader_exceptions, + .init_rop_exceptions = gf100_gr_init_rop_exceptions, + .init_exception2 = gf100_gr_init_exception2, .init_400054 = gf100_gr_init_400054, .trap_mp = gf100_gr_trap_mp, .mmio = gk208_gr_pack_mmio, .fecs.ucode = &gk208_gr_fecs_ucode, + .fecs.reset = gf100_gr_fecs_reset, .gpccs.ucode = &gk208_gr_gpccs_ucode, .rops = gf100_gr_rops, .ppc_nr = 1, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c index be0b2cefd8e8..035ea213f543 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c @@ -33,47 +33,40 @@ struct gk20a_fw_av u32 data; }; -static int -gk20a_gr_av_to_init(struct gf100_gr *gr, const char *path, const char *name, - int ver, struct gf100_gr_pack **ppack) +int +gk20a_gr_av_to_init_(struct nvkm_blob *blob, u8 count, u32 pitch, struct gf100_gr_pack **ppack) { - struct nvkm_subdev *subdev = &gr->base.engine.subdev; - struct nvkm_blob blob; struct gf100_gr_init *init; struct gf100_gr_pack *pack; int nent; - int ret; int i; - ret = nvkm_firmware_load_blob(subdev, path, name, ver, &blob); - if (ret) - return ret; - - nent = (blob.size / sizeof(struct gk20a_fw_av)); + nent = (blob->size / sizeof(struct gk20a_fw_av)); pack = vzalloc((sizeof(*pack) * 2) + (sizeof(*init) * (nent + 1))); - if (!pack) { - ret = -ENOMEM; - goto end; - } + if (!pack) + return -ENOMEM; init = (void *)(pack + 2); pack[0].init = init; for (i = 0; i < nent; i++) { struct gf100_gr_init *ent = &init[i]; - struct gk20a_fw_av *av = &((struct gk20a_fw_av *)blob.data)[i]; + struct gk20a_fw_av *av = &((struct gk20a_fw_av *)blob->data)[i]; ent->addr = av->addr; ent->data = av->data; - ent->count = 1; - ent->pitch = 1; + ent->count = ((ent->addr & 0xffff) != 0xe100) ? count : 1; + ent->pitch = pitch; } *ppack = pack; + return 0; +} -end: - nvkm_blob_dtor(&blob); - return ret; +int +gk20a_gr_av_to_init(struct nvkm_blob *blob, struct gf100_gr_pack **ppack) +{ + return gk20a_gr_av_to_init_(blob, 1, 1, ppack); } struct gk20a_fw_aiv @@ -83,35 +76,25 @@ struct gk20a_fw_aiv u32 data; }; -static int -gk20a_gr_aiv_to_init(struct gf100_gr *gr, const char *path, const char *name, - int ver, struct gf100_gr_pack **ppack) +int +gk20a_gr_aiv_to_init(struct nvkm_blob *blob, struct gf100_gr_pack **ppack) { - struct nvkm_subdev *subdev = &gr->base.engine.subdev; - struct nvkm_blob blob; struct gf100_gr_init *init; struct gf100_gr_pack *pack; int nent; - int ret; int i; - ret = nvkm_firmware_load_blob(subdev, path, name, ver, &blob); - if (ret) - return ret; - - nent = (blob.size / sizeof(struct gk20a_fw_aiv)); + nent = (blob->size / sizeof(struct gk20a_fw_aiv)); pack = vzalloc((sizeof(*pack) * 2) + (sizeof(*init) * (nent + 1))); - if (!pack) { - ret = -ENOMEM; - goto end; - } + if (!pack) + return -ENOMEM; init = (void *)(pack + 2); pack[0].init = init; for (i = 0; i < nent; i++) { struct gf100_gr_init *ent = &init[i]; - struct gk20a_fw_aiv *av = &((struct gk20a_fw_aiv *)blob.data)[i]; + struct gk20a_fw_aiv *av = &((struct gk20a_fw_aiv *)blob->data)[i]; ent->addr = av->addr; ent->data = av->data; @@ -120,44 +103,30 @@ gk20a_gr_aiv_to_init(struct gf100_gr *gr, const char *path, const char *name, } *ppack = pack; - -end: - nvkm_blob_dtor(&blob); - return ret; + return 0; } -static int -gk20a_gr_av_to_method(struct gf100_gr *gr, const char *path, const char *name, - int ver, struct gf100_gr_pack **ppack) +int +gk20a_gr_av_to_method(struct nvkm_blob *blob, struct gf100_gr_pack **ppack) { - struct nvkm_subdev *subdev = &gr->base.engine.subdev; - struct nvkm_blob blob; struct gf100_gr_init *init; struct gf100_gr_pack *pack; /* We don't suppose we will initialize more than 16 classes here... */ static const unsigned int max_classes = 16; u32 classidx = 0, prevclass = 0; int nent; - int ret; int i; - ret = nvkm_firmware_load_blob(subdev, path, name, ver, &blob); - if (ret) - return ret; - - nent = (blob.size / sizeof(struct gk20a_fw_av)); - + nent = (blob->size / sizeof(struct gk20a_fw_av)); pack = vzalloc((sizeof(*pack) * (max_classes + 1)) + (sizeof(*init) * (nent + max_classes + 1))); - if (!pack) { - ret = -ENOMEM; - goto end; - } + if (!pack) + return -ENOMEM; init = (void *)(pack + max_classes + 1); for (i = 0; i < nent; i++, init++) { - struct gk20a_fw_av *av = &((struct gk20a_fw_av *)blob.data)[i]; + struct gk20a_fw_av *av = &((struct gk20a_fw_av *)blob->data)[i]; u32 class = av->addr & 0xffff; u32 addr = (av->addr & 0xffff0000) >> 14; @@ -169,8 +138,7 @@ gk20a_gr_av_to_method(struct gf100_gr *gr, const char *path, const char *name, prevclass = class; if (++classidx >= max_classes) { vfree(pack); - ret = -ENOSPC; - goto end; + return -ENOSPC; } } @@ -181,10 +149,7 @@ gk20a_gr_av_to_method(struct gf100_gr *gr, const char *path, const char *name, } *ppack = pack; - -end: - nvkm_blob_dtor(&blob); - return ret; + return 0; } static int @@ -294,6 +259,7 @@ gk20a_gr = { .init_rop_active_fbps = gk104_gr_init_rop_active_fbps, .trap_mp = gf100_gr_trap_mp, .set_hww_esr_report_mask = gk20a_gr_set_hww_esr_report_mask, + .fecs.reset = gf100_gr_fecs_reset, .rops = gf100_gr_rops, .ppc_nr = 1, .grctx = &gk20a_grctx, @@ -308,12 +274,29 @@ gk20a_gr = { }; int +gk20a_gr_load_net(struct gf100_gr *gr, const char *path, const char *name, int ver, + int (*load)(struct nvkm_blob *, struct gf100_gr_pack **), + struct gf100_gr_pack **ppack) +{ + struct nvkm_blob blob; + int ret; + + ret = nvkm_firmware_load_blob(&gr->base.engine.subdev, path, name, ver, &blob); + if (ret) + return ret; + + ret = load(&blob, ppack); + nvkm_blob_dtor(&blob); + return 0; +} + +int gk20a_gr_load_sw(struct gf100_gr *gr, const char *path, int ver) { - if (gk20a_gr_av_to_init(gr, path, "sw_nonctx", ver, &gr->sw_nonctx) || - gk20a_gr_aiv_to_init(gr, path, "sw_ctx", ver, &gr->sw_ctx) || - gk20a_gr_av_to_init(gr, path, "sw_bundle_init", ver, &gr->bundle) || - gk20a_gr_av_to_method(gr, path, "sw_method_init", ver, &gr->method)) + if (gk20a_gr_load_net(gr, path, "sw_nonctx", ver, gk20a_gr_av_to_init, &gr->sw_nonctx) || + gk20a_gr_load_net(gr, path, "sw_ctx", ver, gk20a_gr_aiv_to_init, &gr->sw_ctx) || + gk20a_gr_load_net(gr, path, "sw_bundle_init", ver, gk20a_gr_av_to_init, &gr->bundle) || + gk20a_gr_load_net(gr, path, "sw_method_init", ver, gk20a_gr_av_to_method, &gr->method)) return -ENOENT; return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c index 310987174cb5..797b828a943b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c @@ -411,10 +411,13 @@ gm107_gr = { .init_tex_hww_esr = gf100_gr_init_tex_hww_esr, .init_504430 = gm107_gr_init_504430, .init_shader_exceptions = gm107_gr_init_shader_exceptions, + .init_rop_exceptions = gf100_gr_init_rop_exceptions, + .init_exception2 = gf100_gr_init_exception2, .init_400054 = gm107_gr_init_400054, .trap_mp = gf100_gr_trap_mp, .mmio = gm107_gr_pack_mmio, .fecs.ucode = &gm107_gr_fecs_ucode, + .fecs.reset = gf100_gr_fecs_reset, .gpccs.ucode = &gm107_gr_gpccs_ucode, .rops = gf100_gr_rops, .ppc_nr = 2, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm200.c index 385cfd91b266..b5210b31c1b2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm200.c @@ -148,11 +148,11 @@ gm200_gr_tile_map_2_8[] = { 0, 1, 1, 0, 0, 1, 1, 0, }; -void +int gm200_gr_oneinit_sm_id(struct gf100_gr *gr) { /*XXX: There's a different algorithm here I've not yet figured out. */ - gf100_gr_oneinit_sm_id(gr); + return gf100_gr_oneinit_sm_id(gr); } void @@ -199,8 +199,11 @@ gm200_gr = { .init_tex_hww_esr = gf100_gr_init_tex_hww_esr, .init_504430 = gm107_gr_init_504430, .init_shader_exceptions = gm107_gr_init_shader_exceptions, + .init_rop_exceptions = gf100_gr_init_rop_exceptions, + .init_exception2 = gf100_gr_init_exception2, .init_400054 = gm107_gr_init_400054, .trap_mp = gf100_gr_trap_mp, + .fecs.reset = gf100_gr_fecs_reset, .rops = gm200_gr_rops, .tpc_nr = 4, .ppc_nr = 2, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm20b.c index ec1c46e47e00..458cd1a00d3f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm20b.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm20b.c @@ -123,6 +123,7 @@ gm20b_gr = { .init_rop_active_fbps = gk104_gr_init_rop_active_fbps, .trap_mp = gf100_gr_trap_mp, .set_hww_esr_report_mask = gm20b_gr_set_hww_esr_report_mask, + .fecs.reset = gf100_gr_fecs_reset, .rops = gm200_gr_rops, .ppc_nr = 1, .grctx = &gm20b_grctx, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp100.c index 0550dd6f46f1..851e743d2cab 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp100.c @@ -87,7 +87,7 @@ gp100_gr_init_419c9c(struct gf100_gr *gr) void gp100_gr_init_fecs_exceptions(struct gf100_gr *gr) { - nvkm_wr32(gr->base.engine.subdev.device, 0x409c24, 0x000f0002); + nvkm_wr32(gr->base.engine.subdev.device, 0x409c24, 0x000e0002); } void @@ -119,7 +119,10 @@ gp100_gr = { .init_tex_hww_esr = gf100_gr_init_tex_hww_esr, .init_504430 = gm107_gr_init_504430, .init_shader_exceptions = gp100_gr_init_shader_exceptions, + .init_rop_exceptions = gf100_gr_init_rop_exceptions, + .init_exception2 = gf100_gr_init_exception2, .trap_mp = gf100_gr_trap_mp, + .fecs.reset = gf100_gr_fecs_reset, .rops = gm200_gr_rops, .gpc_nr = 6, .tpc_nr = 5, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp102.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp102.c index 5b001f374be0..0e223b7b5f0e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp102.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp102.c @@ -26,7 +26,7 @@ #include <nvif/class.h> -static void +void gp102_gr_zbc_clear_stencil(struct gf100_gr *gr, int zbc) { struct nvkm_device *device = gr->base.engine.subdev.device; @@ -40,14 +40,14 @@ gp102_gr_zbc_clear_stencil(struct gf100_gr *gr, int zbc) gr->zbc_stencil[zbc].format << ((znum % 4) * 7)); } -static int +int gp102_gr_zbc_stencil_get(struct gf100_gr *gr, int format, const u32 ds, const u32 l2) { struct nvkm_ltc *ltc = gr->base.engine.subdev.device->ltc; int zbc = -ENOSPC, i; - for (i = ltc->zbc_min; i <= ltc->zbc_max; i++) { + for (i = ltc->zbc_depth_min; i <= ltc->zbc_depth_max; i++) { if (gr->zbc_stencil[i].format) { if (gr->zbc_stencil[i].format != format) continue; @@ -115,7 +115,10 @@ gp102_gr = { .init_tex_hww_esr = gf100_gr_init_tex_hww_esr, .init_504430 = gm107_gr_init_504430, .init_shader_exceptions = gp100_gr_init_shader_exceptions, + .init_rop_exceptions = gf100_gr_init_rop_exceptions, + .init_exception2 = gf100_gr_init_exception2, .trap_mp = gf100_gr_trap_mp, + .fecs.reset = gf100_gr_fecs_reset, .rops = gm200_gr_rops, .gpc_nr = 6, .tpc_nr = 5, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp104.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp104.c index 2655574ec63b..6802cb9b199f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp104.c @@ -43,7 +43,10 @@ gp104_gr = { .init_tex_hww_esr = gf100_gr_init_tex_hww_esr, .init_504430 = gm107_gr_init_504430, .init_shader_exceptions = gp100_gr_init_shader_exceptions, + .init_rop_exceptions = gf100_gr_init_rop_exceptions, + .init_exception2 = gf100_gr_init_exception2, .trap_mp = gf100_gr_trap_mp, + .fecs.reset = gf100_gr_fecs_reset, .rops = gm200_gr_rops, .gpc_nr = 6, .tpc_nr = 5, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp107.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp107.c index adabc04d4f3a..cc2bb0d0a987 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp107.c @@ -45,7 +45,10 @@ gp107_gr = { .init_tex_hww_esr = gf100_gr_init_tex_hww_esr, .init_504430 = gm107_gr_init_504430, .init_shader_exceptions = gp100_gr_init_shader_exceptions, + .init_rop_exceptions = gf100_gr_init_rop_exceptions, + .init_exception2 = gf100_gr_init_exception2, .trap_mp = gf100_gr_trap_mp, + .fecs.reset = gf100_gr_fecs_reset, .rops = gm200_gr_rops, .gpc_nr = 2, .tpc_nr = 3, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp108.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp108.c index 7310f0466bb7..311f703439e4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp108.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp108.c @@ -25,7 +25,7 @@ #include <nvfw/flcn.h> -static void +void gp108_gr_acr_bld_patch(struct nvkm_acr *acr, u32 bld, s64 adjust) { struct flcn_bl_dmem_desc_v2 hdr; @@ -36,7 +36,7 @@ gp108_gr_acr_bld_patch(struct nvkm_acr *acr, u32 bld, s64 adjust) flcn_bl_dmem_desc_v2_dump(&acr->subdev, &hdr); } -static void +void gp108_gr_acr_bld_write(struct nvkm_acr *acr, u32 bld, struct nvkm_acr_lsfw *lsfw) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp10b.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp10b.c index e13683b6e7b1..5008881ca079 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp10b.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp10b.c @@ -55,7 +55,10 @@ gp10b_gr = { .init_tex_hww_esr = gf100_gr_init_tex_hww_esr, .init_504430 = gm107_gr_init_504430, .init_shader_exceptions = gp100_gr_init_shader_exceptions, + .init_rop_exceptions = gf100_gr_init_rop_exceptions, + .init_exception2 = gf100_gr_init_exception2, .trap_mp = gf100_gr_trap_mp, + .fecs.reset = gf100_gr_fecs_reset, .rops = gm200_gr_rops, .gpc_nr = 1, .tpc_nr = 2, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gv100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gv100.c index 4d043c1173ea..7f7404a76140 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gv100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gv100.c @@ -52,10 +52,11 @@ gv100_gr_trap_mp(struct gf100_gr *gr, int gpc, int tpc) gv100_gr_trap_sm(gr, gpc, tpc, 1); } -static void +void gv100_gr_init_4188a4(struct gf100_gr *gr) { struct nvkm_device *device = gr->base.engine.subdev.device; + nvkm_mask(device, 0x4188a4, 0x03000000, 0x03000000); } @@ -65,7 +66,6 @@ gv100_gr_init_shader_exceptions(struct gf100_gr *gr, int gpc, int tpc) struct nvkm_device *device = gr->base.engine.subdev.device; int sm; for (sm = 0; sm < 0x100; sm += 0x80) { - nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x728 + sm), 0x0085eb64); nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x610), 0x00000001); nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x72c + sm), 0x00000004); } @@ -85,10 +85,202 @@ gv100_gr_init_419bd8(struct gf100_gr *gr) nvkm_mask(device, 0x419bd8, 0x00000700, 0x00000000); } +u32 +gv100_gr_nonpes_aware_tpc(struct gf100_gr *gr, u32 gpc, u32 tpc) +{ + u32 pes, temp, tpc_new = 0; + + for (pes = 0; pes < gr->ppc_nr[gpc]; pes++) { + if (gr->ppc_tpc_mask[gpc][pes] & BIT(tpc)) + break; + + tpc_new += gr->ppc_tpc_nr[gpc][pes]; + } + + temp = (BIT(tpc) - 1) & gr->ppc_tpc_mask[gpc][pes]; + temp = hweight32(temp); + return tpc_new + temp; +} + +static int +gv100_gr_scg_estimate_perf(struct gf100_gr *gr, unsigned long *gpc_tpc_mask, + u32 disable_gpc, u32 disable_tpc, int *perf) +{ + const u32 scale_factor = 512UL; /* Use fx23.9 */ + const u32 pix_scale = 1024*1024UL; /* Pix perf in [29:20] */ + const u32 world_scale = 1024UL; /* World performance in [19:10] */ + const u32 tpc_scale = 1; /* TPC balancing in [9:0] */ + u32 scg_num_pes = 0; + u32 min_scg_gpc_pix_perf = scale_factor; /* Init perf as maximum */ + u32 average_tpcs = 0; /* Average of # of TPCs per GPC */ + u32 deviation; /* absolute diff between TPC# and average_tpcs, averaged across GPCs */ + u32 norm_tpc_deviation; /* deviation/max_tpc_per_gpc */ + u32 tpc_balance; + u32 scg_gpc_pix_perf; + u32 scg_world_perf; + u32 gpc; + u32 pes; + int diff; + bool tpc_removed_gpc = false; + bool tpc_removed_pes = false; + u32 max_tpc_gpc = 0; + u32 num_tpc_mask; + u32 *num_tpc_gpc; + int ret = -EINVAL; + + if (!(num_tpc_gpc = kcalloc(gr->gpc_nr, sizeof(*num_tpc_gpc), GFP_KERNEL))) + return -ENOMEM; + + /* Calculate pix-perf-reduction-rate per GPC and find bottleneck TPC */ + for (gpc = 0; gpc < gr->gpc_nr; gpc++) { + num_tpc_mask = gpc_tpc_mask[gpc]; + + if ((gpc == disable_gpc) && num_tpc_mask & BIT(disable_tpc)) { + /* Safety check if a TPC is removed twice */ + if (WARN_ON(tpc_removed_gpc)) + goto done; + + /* Remove logical TPC from set */ + num_tpc_mask &= ~BIT(disable_tpc); + tpc_removed_gpc = true; + } + + /* track balancing of tpcs across gpcs */ + num_tpc_gpc[gpc] = hweight32(num_tpc_mask); + average_tpcs += num_tpc_gpc[gpc]; + + /* save the maximum numer of gpcs */ + max_tpc_gpc = num_tpc_gpc[gpc] > max_tpc_gpc ? num_tpc_gpc[gpc] : max_tpc_gpc; + + /* + * Calculate ratio between TPC count and post-FS and post-SCG + * + * ratio represents relative throughput of the GPC + */ + scg_gpc_pix_perf = scale_factor * num_tpc_gpc[gpc] / gr->tpc_nr[gpc]; + if (min_scg_gpc_pix_perf > scg_gpc_pix_perf) + min_scg_gpc_pix_perf = scg_gpc_pix_perf; + + /* Calculate # of surviving PES */ + for (pes = 0; pes < gr->ppc_nr[gpc]; pes++) { + /* Count the number of TPC on the set */ + num_tpc_mask = gr->ppc_tpc_mask[gpc][pes] & gpc_tpc_mask[gpc]; + + if ((gpc == disable_gpc) && (num_tpc_mask & BIT(disable_tpc))) { + if (WARN_ON(tpc_removed_pes)) + goto done; + + num_tpc_mask &= ~BIT(disable_tpc); + tpc_removed_pes = true; + } + + if (hweight32(num_tpc_mask)) + scg_num_pes++; + } + } + + if (WARN_ON(!tpc_removed_gpc || !tpc_removed_pes)) + goto done; + + if (max_tpc_gpc == 0) { + *perf = 0; + goto done_ok; + } + + /* Now calculate perf */ + scg_world_perf = (scale_factor * scg_num_pes) / gr->ppc_total; + deviation = 0; + average_tpcs = scale_factor * average_tpcs / gr->gpc_nr; + for (gpc = 0; gpc < gr->gpc_nr; gpc++) { + diff = average_tpcs - scale_factor * num_tpc_gpc[gpc]; + if (diff < 0) + diff = -diff; + + deviation += diff; + } + + deviation /= gr->gpc_nr; + + norm_tpc_deviation = deviation / max_tpc_gpc; + + tpc_balance = scale_factor - norm_tpc_deviation; + + if ((tpc_balance > scale_factor) || + (scg_world_perf > scale_factor) || + (min_scg_gpc_pix_perf > scale_factor) || + (norm_tpc_deviation > scale_factor)) { + WARN_ON(1); + goto done; + } + + *perf = (pix_scale * min_scg_gpc_pix_perf) + + (world_scale * scg_world_perf) + + (tpc_scale * tpc_balance); +done_ok: + ret = 0; +done: + kfree(num_tpc_gpc); + return ret; +} + +int +gv100_gr_oneinit_sm_id(struct gf100_gr *gr) +{ + unsigned long *gpc_tpc_mask; + u32 *tpc_table, *gpc_table; + u32 gpc, tpc, pes, gtpc; + int perf, maxperf, ret = 0; + + gpc_tpc_mask = kcalloc(gr->gpc_nr, sizeof(*gpc_tpc_mask), GFP_KERNEL); + gpc_table = kcalloc(gr->tpc_total, sizeof(*gpc_table), GFP_KERNEL); + tpc_table = kcalloc(gr->tpc_total, sizeof(*tpc_table), GFP_KERNEL); + if (!gpc_table || !tpc_table || !gpc_tpc_mask) { + ret = -ENOMEM; + goto done; + } + + for (gpc = 0; gpc < gr->gpc_nr; gpc++) { + for (pes = 0; pes < gr->ppc_nr[gpc]; pes++) + gpc_tpc_mask[gpc] |= gr->ppc_tpc_mask[gpc][pes]; + } + + for (gtpc = 0; gtpc < gr->tpc_total; gtpc++) { + for (maxperf = -1, gpc = 0; gpc < gr->gpc_nr; gpc++) { + for_each_set_bit(tpc, &gpc_tpc_mask[gpc], gr->tpc_nr[gpc]) { + ret = gv100_gr_scg_estimate_perf(gr, gpc_tpc_mask, gpc, tpc, &perf); + if (ret) + goto done; + + /* nvgpu does ">=" here, but this gets us RM's numbers. */ + if (perf > maxperf) { + maxperf = perf; + gpc_table[gtpc] = gpc; + tpc_table[gtpc] = tpc; + } + } + } + + gpc_tpc_mask[gpc_table[gtpc]] &= ~BIT(tpc_table[gtpc]); + } + + /*TODO: build table for sm_per_tpc != 1, don't use yet, but might need later? */ + for (gtpc = 0; gtpc < gr->tpc_total; gtpc++) { + gr->sm[gtpc].gpc = gpc_table[gtpc]; + gr->sm[gtpc].tpc = tpc_table[gtpc]; + gr->sm_nr++; + } + +done: + kfree(gpc_table); + kfree(tpc_table); + kfree(gpc_tpc_mask); + return ret; +} + static const struct gf100_gr_func gv100_gr = { .oneinit_tiles = gm200_gr_oneinit_tiles, - .oneinit_sm_id = gm200_gr_oneinit_sm_id, + .oneinit_sm_id = gv100_gr_oneinit_sm_id, .init = gf100_gr_init, .init_419bd8 = gv100_gr_init_419bd8, .init_gpc_mmu = gm200_gr_init_gpc_mmu, @@ -103,11 +295,14 @@ gv100_gr = { .init_ppc_exceptions = gk104_gr_init_ppc_exceptions, .init_504430 = gv100_gr_init_504430, .init_shader_exceptions = gv100_gr_init_shader_exceptions, + .init_rop_exceptions = gf100_gr_init_rop_exceptions, + .init_exception2 = gf100_gr_init_exception2, .init_4188a4 = gv100_gr_init_4188a4, .trap_mp = gv100_gr_trap_mp, + .fecs.reset = gf100_gr_fecs_reset, .rops = gm200_gr_rops, .gpc_nr = 6, - .tpc_nr = 5, + .tpc_nr = 7, .ppc_nr = 3, .grctx = &gv100_grctx, .zbc = &gp102_gr_zbc, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c index 0bc1a238de43..81bd682c2102 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c @@ -1192,7 +1192,7 @@ nv04_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, return -ENOMEM; nvkm_object_ctor(&nv04_gr_chan, oclass, &chan->object); chan->gr = gr; - chan->chid = fifoch->chid; + chan->chid = fifoch->id; *pobject = &chan->object; *ctx_reg(chan, NV04_PGRAPH_DEBUG_3) = 0xfad4ff31; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c index 942450b33bc6..7fe6e58f6bab 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c @@ -1011,7 +1011,7 @@ nv10_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, return -ENOMEM; nvkm_object_ctor(&nv10_gr_chan, oclass, &chan->object); chan->gr = gr; - chan->chid = fifoch->chid; + chan->chid = fifoch->id; *pobject = &chan->object; NV_WRITE_CTX(0x00400e88, 0x08000000); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c index 6bff10cee71b..75434f5de7ad 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c @@ -83,7 +83,7 @@ nv20_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, return -ENOMEM; nvkm_object_ctor(&nv20_gr_chan, oclass, &chan->object); chan->gr = gr; - chan->chid = fifoch->chid; + chan->chid = fifoch->id; *pobject = &chan->object; ret = nvkm_memory_new(gr->base.engine.subdev.device, @@ -182,7 +182,7 @@ nv20_gr_intr(struct nvkm_gr *base) struct nv20_gr *gr = nv20_gr(base); struct nvkm_subdev *subdev = &gr->base.engine.subdev; struct nvkm_device *device = subdev->device; - struct nvkm_fifo_chan *chan; + struct nvkm_chan *chan; u32 stat = nvkm_rd32(device, NV03_PGRAPH_INTR); u32 nsource = nvkm_rd32(device, NV03_PGRAPH_NSOURCE); u32 nstatus = nvkm_rd32(device, NV03_PGRAPH_NSTATUS); @@ -196,7 +196,7 @@ nv20_gr_intr(struct nvkm_gr *base) char msg[128], src[128], sta[128]; unsigned long flags; - chan = nvkm_fifo_chan_chid(device->fifo, chid, &flags); + chan = nvkm_chan_get_chid(&gr->base.engine, chid, &flags); nvkm_wr32(device, NV03_PGRAPH_INTR, stat); nvkm_wr32(device, NV04_PGRAPH_FIFO, 0x00000001); @@ -209,11 +209,11 @@ nv20_gr_intr(struct nvkm_gr *base) "nstatus %08x [%s] ch %d [%s] subc %d " "class %04x mthd %04x data %08x\n", show, msg, nsource, src, nstatus, sta, chid, - chan ? chan->object.client->name : "unknown", + chan ? chan->name : "unknown", subc, class, mthd, data); } - nvkm_fifo_chan_put(device->fifo, flags, &chan); + nvkm_chan_put(&chan, flags); } int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c index f3a56f17d94a..94685e4d4f87 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c @@ -29,7 +29,7 @@ nv25_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, return -ENOMEM; nvkm_object_ctor(&nv25_gr_chan, oclass, &chan->object); chan->gr = gr; - chan->chid = fifoch->chid; + chan->chid = fifoch->id; *pobject = &chan->object; ret = nvkm_memory_new(gr->base.engine.subdev.device, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c index f268d2642d29..2d6273675291 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c @@ -29,7 +29,7 @@ nv2a_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, return -ENOMEM; nvkm_object_ctor(&nv2a_gr_chan, oclass, &chan->object); chan->gr = gr; - chan->chid = fifoch->chid; + chan->chid = fifoch->id; *pobject = &chan->object; ret = nvkm_memory_new(gr->base.engine.subdev.device, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c index e5737cdf2fa1..647bd6fede04 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c @@ -30,7 +30,7 @@ nv30_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, return -ENOMEM; nvkm_object_ctor(&nv30_gr_chan, oclass, &chan->object); chan->gr = gr; - chan->chid = fifoch->chid; + chan->chid = fifoch->id; *pobject = &chan->object; ret = nvkm_memory_new(gr->base.engine.subdev.device, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c index 1ab2da8ebf4e..2eae3fe4ef4e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c @@ -29,7 +29,7 @@ nv34_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, return -ENOMEM; nvkm_object_ctor(&nv34_gr_chan, oclass, &chan->object); chan->gr = gr; - chan->chid = fifoch->chid; + chan->chid = fifoch->id; *pobject = &chan->object; ret = nvkm_memory_new(gr->base.engine.subdev.device, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c index 591260f5676b..657d7cdba369 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c @@ -29,7 +29,7 @@ nv35_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, return -ENOMEM; nvkm_object_ctor(&nv35_gr_chan, oclass, &chan->object); chan->gr = gr; - chan->chid = fifoch->chid; + chan->chid = fifoch->id; *pobject = &chan->object; ret = nvkm_memory_new(gr->base.engine.subdev.device, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c index 67f3535ff97e..d2df097a6cf6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c @@ -275,8 +275,8 @@ nv40_gr_intr(struct nvkm_gr *base) "nstatus %08x [%s] ch %d [%08x %s] subc %d " "class %04x mthd %04x data %08x\n", show, msg, nsource, src, nstatus, sta, - chan ? chan->fifo->chid : -1, inst << 4, - chan ? chan->fifo->object.client->name : "unknown", + chan ? chan->fifo->id : -1, inst << 4, + chan ? chan->fifo->name : "unknown", subc, class, mthd, data); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c index 563a10097e95..1ba18a8e380f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c @@ -622,7 +622,7 @@ nv50_gr_intr(struct nvkm_gr *base) struct nv50_gr *gr = nv50_gr(base); struct nvkm_subdev *subdev = &gr->base.engine.subdev; struct nvkm_device *device = subdev->device; - struct nvkm_fifo_chan *chan; + struct nvkm_chan *chan; u32 stat = nvkm_rd32(device, 0x400100); u32 inst = nvkm_rd32(device, 0x40032c) & 0x0fffffff; u32 addr = nvkm_rd32(device, 0x400704); @@ -637,10 +637,10 @@ nv50_gr_intr(struct nvkm_gr *base) char msg[128]; int chid = -1; - chan = nvkm_fifo_chan_inst(device->fifo, (u64)inst << 12, &flags); + chan = nvkm_chan_get_inst(&gr->base.engine, (u64)inst << 12, &flags); if (chan) { - name = chan->object.client->name; - chid = chan->chid; + name = chan->name; + chid = chan->id; } if (show & 0x00100000) { @@ -672,7 +672,7 @@ nv50_gr_intr(struct nvkm_gr *base) if (nvkm_rd32(device, 0x400824) & (1 << 31)) nvkm_wr32(device, 0x400824, nvkm_rd32(device, 0x400824) & ~(1 << 31)); - nvkm_fifo_chan_put(device->fifo, flags, &chan); + nvkm_chan_put(&chan, flags); } int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/priv.h index 9b2c66e8be90..08d5c96e6458 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/priv.h @@ -17,6 +17,7 @@ struct nvkm_gr_func { int (*oneinit)(struct nvkm_gr *); int (*init)(struct nvkm_gr *); int (*fini)(struct nvkm_gr *, bool); + int (*reset)(struct nvkm_gr *); void (*intr)(struct nvkm_gr *); void (*tile)(struct nvkm_gr *, int region, struct nvkm_fb_tile *); int (*tlb_flush)(struct nvkm_gr *); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/tu102.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/tu102.c index 1a8a21844e12..3b6c8100a242 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/tu102.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/tu102.c @@ -24,13 +24,13 @@ #include <nvif/class.h> -static void +void tu102_gr_init_fecs_exceptions(struct gf100_gr *gr) { - nvkm_wr32(gr->base.engine.subdev.device, 0x409c24, 0x006f0002); + nvkm_wr32(gr->base.engine.subdev.device, 0x409c24, 0x006e0003); } -static void +void tu102_gr_init_fs(struct gf100_gr *gr) { struct nvkm_device *device = gr->base.engine.subdev.device; @@ -40,20 +40,21 @@ tu102_gr_init_fs(struct gf100_gr *gr) gk104_grctx_generate_gpc_tpc_nr(gr); for (sm = 0; sm < gr->sm_nr; sm++) { - nvkm_wr32(device, GPC_UNIT(gr->sm[sm].gpc, 0x0c10 + - gr->sm[sm].tpc * 4), sm); + int tpc = gv100_gr_nonpes_aware_tpc(gr, gr->sm[sm].gpc, gr->sm[sm].tpc); + + nvkm_wr32(device, GPC_UNIT(gr->sm[sm].gpc, 0x0c10 + tpc * 4), sm); } gm200_grctx_generate_dist_skip_table(gr); gf100_gr_init_num_tpc_per_gpc(gr, true, true); } -static void +void tu102_gr_init_zcull(struct gf100_gr *gr) { struct nvkm_device *device = gr->base.engine.subdev.device; const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, gr->tpc_total); - const u8 tile_nr = ALIGN(gr->tpc_total, 64); + const u8 tile_nr = gr->func->gpc_nr * gr->func->tpc_nr; u8 bank[GPC_MAX] = {}, gpc, i, j; u32 data; @@ -93,7 +94,7 @@ tu102_gr_init_gpc_mmu(struct gf100_gr *gr) static const struct gf100_gr_func tu102_gr = { .oneinit_tiles = gm200_gr_oneinit_tiles, - .oneinit_sm_id = gm200_gr_oneinit_sm_id, + .oneinit_sm_id = gv100_gr_oneinit_sm_id, .init = gf100_gr_init, .init_419bd8 = gv100_gr_init_419bd8, .init_gpc_mmu = tu102_gr_init_gpc_mmu, @@ -109,10 +110,14 @@ tu102_gr = { .init_ppc_exceptions = gk104_gr_init_ppc_exceptions, .init_504430 = gv100_gr_init_504430, .init_shader_exceptions = gv100_gr_init_shader_exceptions, + .init_rop_exceptions = gf100_gr_init_rop_exceptions, + .init_exception2 = gf100_gr_init_exception2, + .init_4188a4 = gv100_gr_init_4188a4, .trap_mp = gv100_gr_trap_mp, + .fecs.reset = gf100_gr_fecs_reset, .rops = gm200_gr_rops, .gpc_nr = 6, - .tpc_nr = 5, + .tpc_nr = 6, .ppc_nr = 3, .grctx = &tu102_grctx, .zbc = &gp102_gr_zbc, @@ -137,6 +142,7 @@ MODULE_FIRMWARE("nvidia/tu102/gr/sw_ctx.bin"); MODULE_FIRMWARE("nvidia/tu102/gr/sw_nonctx.bin"); MODULE_FIRMWARE("nvidia/tu102/gr/sw_bundle_init.bin"); MODULE_FIRMWARE("nvidia/tu102/gr/sw_method_init.bin"); +MODULE_FIRMWARE("nvidia/tu102/gr/sw_veid_bundle_init.bin"); MODULE_FIRMWARE("nvidia/tu104/gr/fecs_bl.bin"); MODULE_FIRMWARE("nvidia/tu104/gr/fecs_inst.bin"); @@ -150,6 +156,7 @@ MODULE_FIRMWARE("nvidia/tu104/gr/sw_ctx.bin"); MODULE_FIRMWARE("nvidia/tu104/gr/sw_nonctx.bin"); MODULE_FIRMWARE("nvidia/tu104/gr/sw_bundle_init.bin"); MODULE_FIRMWARE("nvidia/tu104/gr/sw_method_init.bin"); +MODULE_FIRMWARE("nvidia/tu104/gr/sw_veid_bundle_init.bin"); MODULE_FIRMWARE("nvidia/tu106/gr/fecs_bl.bin"); MODULE_FIRMWARE("nvidia/tu106/gr/fecs_inst.bin"); @@ -163,6 +170,7 @@ MODULE_FIRMWARE("nvidia/tu106/gr/sw_ctx.bin"); MODULE_FIRMWARE("nvidia/tu106/gr/sw_nonctx.bin"); MODULE_FIRMWARE("nvidia/tu106/gr/sw_bundle_init.bin"); MODULE_FIRMWARE("nvidia/tu106/gr/sw_method_init.bin"); +MODULE_FIRMWARE("nvidia/tu106/gr/sw_veid_bundle_init.bin"); MODULE_FIRMWARE("nvidia/tu117/gr/fecs_bl.bin"); MODULE_FIRMWARE("nvidia/tu117/gr/fecs_inst.bin"); @@ -176,6 +184,7 @@ MODULE_FIRMWARE("nvidia/tu117/gr/sw_ctx.bin"); MODULE_FIRMWARE("nvidia/tu117/gr/sw_nonctx.bin"); MODULE_FIRMWARE("nvidia/tu117/gr/sw_bundle_init.bin"); MODULE_FIRMWARE("nvidia/tu117/gr/sw_method_init.bin"); +MODULE_FIRMWARE("nvidia/tu117/gr/sw_veid_bundle_init.bin"); MODULE_FIRMWARE("nvidia/tu116/gr/fecs_bl.bin"); MODULE_FIRMWARE("nvidia/tu116/gr/fecs_inst.bin"); @@ -189,6 +198,26 @@ MODULE_FIRMWARE("nvidia/tu116/gr/sw_ctx.bin"); MODULE_FIRMWARE("nvidia/tu116/gr/sw_nonctx.bin"); MODULE_FIRMWARE("nvidia/tu116/gr/sw_bundle_init.bin"); MODULE_FIRMWARE("nvidia/tu116/gr/sw_method_init.bin"); +MODULE_FIRMWARE("nvidia/tu116/gr/sw_veid_bundle_init.bin"); + +int +tu102_gr_av_to_init_veid(struct nvkm_blob *blob, struct gf100_gr_pack **ppack) +{ + return gk20a_gr_av_to_init_(blob, 64, 0x00100000, ppack); +} + +int +tu102_gr_load(struct gf100_gr *gr, int ver, const struct gf100_gr_fwif *fwif) +{ + int ret; + + ret = gm200_gr_load(gr, ver, fwif); + if (ret) + return ret; + + return gk20a_gr_load_net(gr, "gr/", "sw_veid_bundle_init", ver, tu102_gr_av_to_init_veid, + &gr->bundle_veid); +} static const struct gf100_gr_fwif tu102_gr_fwif[] = { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c index b1054db4c1b8..cb0c3991b2ad 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c @@ -213,8 +213,8 @@ nv31_mpeg_intr(struct nvkm_engine *engine) if (show) { nvkm_error(subdev, "ch %d [%s] %08x %08x %08x %08x\n", - mpeg->chan ? mpeg->chan->fifo->chid : -1, - mpeg->chan ? mpeg->chan->object.client->name : + mpeg->chan ? mpeg->chan->fifo->id : -1, + mpeg->chan ? mpeg->chan->fifo->name : "unknown", stat, type, mthd, data); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c index 521ce43a2871..0890a279458e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c @@ -182,8 +182,8 @@ nv44_mpeg_intr(struct nvkm_engine *engine) if (show) { nvkm_error(subdev, "ch %d [%08x %s] %08x %08x %08x %08x\n", - chan ? chan->fifo->chid : -1, inst << 4, - chan ? chan->object.client->name : "unknown", + chan ? chan->fifo->id : -1, inst << 4, + chan ? chan->fifo->name : "unknown", stat, type, mthd, data); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/Kbuild index 9a0fd9812750..f05e79670d22 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/Kbuild @@ -1,3 +1,4 @@ # SPDX-License-Identifier: MIT nvkm-y += nvkm/engine/nvdec/base.o nvkm-y += nvkm/engine/nvdec/gm107.o +nvkm-y += nvkm/engine/nvdec/ga102.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/base.c index b0181cc5953b..1f6e3b32ba16 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/base.c @@ -37,7 +37,7 @@ nvkm_nvdec = { int nvkm_nvdec_new_(const struct nvkm_nvdec_fwif *fwif, struct nvkm_device *device, - enum nvkm_subdev_type type, int inst, struct nvkm_nvdec **pnvdec) + enum nvkm_subdev_type type, int inst, u32 addr, struct nvkm_nvdec **pnvdec) { struct nvkm_nvdec *nvdec; int ret; @@ -57,5 +57,5 @@ nvkm_nvdec_new_(const struct nvkm_nvdec_fwif *fwif, struct nvkm_device *device, nvdec->func = fwif->func; return nvkm_falcon_ctor(nvdec->func->flcn, &nvdec->engine.subdev, - nvdec->engine.subdev.name, 0, &nvdec->falcon); + nvdec->engine.subdev.name, addr, &nvdec->falcon); }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/ga102.c b/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/ga102.c new file mode 100644 index 000000000000..37d8c3c0f3ab --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/ga102.c @@ -0,0 +1,61 @@ +/* + * 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 <subdev/mc.h> +#include <subdev/timer.h> + +static const struct nvkm_falcon_func +ga102_nvdec_flcn = { + .disable = gm200_flcn_disable, + .enable = gm200_flcn_enable, + .addr2 = 0x1c00, + .reset_pmc = true, + .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_nvdec_func +ga102_nvdec = { + .flcn = &ga102_nvdec_flcn, +}; + +static int +ga102_nvdec_nofw(struct nvkm_nvdec *nvdec, int ver, const struct nvkm_nvdec_fwif *fwif) +{ + return 0; +} + +static const struct nvkm_nvdec_fwif +ga102_nvdec_fwif[] = { + { -1, ga102_nvdec_nofw, &ga102_nvdec }, + {} +}; + +int +ga102_nvdec_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, + struct nvkm_nvdec **pnvdec) +{ + return nvkm_nvdec_new_(ga102_nvdec_fwif, device, type, inst, 0x848000, pnvdec); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/gm107.c index 8c44ce44a6d7..564f7e8960a2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/gm107.c @@ -23,18 +23,13 @@ static const struct nvkm_falcon_func gm107_nvdec_flcn = { + .disable = gm200_flcn_disable, + .enable = gm200_flcn_enable, + .reset_pmc = true, + .reset_wait_mem_scrubbing = gm200_flcn_reset_wait_mem_scrubbing, .debug = 0xd00, - .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 = 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, + .imem_pio = &gm200_flcn_imem_pio, + .dmem_pio = &gm200_flcn_dmem_pio, }; static const struct nvkm_nvdec_func @@ -59,5 +54,5 @@ int gm107_nvdec_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_nvdec **pnvdec) { - return nvkm_nvdec_new_(gm107_nvdec_fwif, device, type, inst, pnvdec); + return nvkm_nvdec_new_(gm107_nvdec_fwif, device, type, inst, 0, pnvdec); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/priv.h index 0920f6a887e2..61e1f7aaa509 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/nvdec/priv.h @@ -15,5 +15,5 @@ struct nvkm_nvdec_fwif { }; int nvkm_nvdec_new_(const struct nvkm_nvdec_fwif *fwif, struct nvkm_device *, - enum nvkm_subdev_type, int, struct nvkm_nvdec **); + enum nvkm_subdev_type, int, u32 addr, struct nvkm_nvdec **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/nvenc/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/nvenc/gm107.c index f44d41bf2034..ad27d8b97569 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/nvenc/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/nvenc/gm107.c @@ -24,17 +24,6 @@ static const struct nvkm_falcon_func gm107_nvenc_flcn = { - .fbif = 0x800, - .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, }; static const struct nvkm_nvenc_func diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c index 1b87df03c823..c15b2cbf506b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c @@ -40,7 +40,7 @@ static const struct nvkm_enum g98_sec_isr_error_name[] = { }; static void -g98_sec_intr(struct nvkm_falcon *sec, struct nvkm_fifo_chan *chan) +g98_sec_intr(struct nvkm_falcon *sec, struct nvkm_chan *chan) { struct nvkm_subdev *subdev = &sec->engine.subdev; struct nvkm_device *device = subdev->device; @@ -54,9 +54,9 @@ g98_sec_intr(struct nvkm_falcon *sec, struct nvkm_fifo_chan *chan) nvkm_error(subdev, "DISPATCH_ERROR %04x [%s] ch %d [%010llx %s] " "subc %d mthd %04x data %08x\n", ssta, - en ? en->name : "UNKNOWN", chan ? chan->chid : -1, + en ? en->name : "UNKNOWN", chan ? chan->id : -1, chan ? chan->inst->addr : 0, - chan ? chan->object.client->name : "unknown", + chan ? chan->name : "unknown", subc, mthd, data); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/Kbuild index 63cd2be3de08..19feadb1f67b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/Kbuild @@ -3,3 +3,4 @@ nvkm-y += nvkm/engine/sec2/base.o nvkm-y += nvkm/engine/sec2/gp102.o nvkm-y += nvkm/engine/sec2/gp108.o nvkm-y += nvkm/engine/sec2/tu102.o +nvkm-y += nvkm/engine/sec2/ga102.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/base.c index 092c6d0b8e01..f2c60da5d1e8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/base.c @@ -22,53 +22,99 @@ #include "priv.h" #include <core/firmware.h> -#include <subdev/top.h> +#include <subdev/mc.h> +#include <subdev/timer.h> -static void -nvkm_sec2_recv(struct work_struct *work) +#include <nvfw/sec2.h> + +static int +nvkm_sec2_finimsg(void *priv, struct nvfw_falcon_msg *hdr) +{ + struct nvkm_sec2 *sec2 = priv; + + atomic_set(&sec2->running, 0); + return 0; +} + +static int +nvkm_sec2_fini(struct nvkm_engine *engine, bool suspend) { - struct nvkm_sec2 *sec2 = container_of(work, typeof(*sec2), work); + struct nvkm_sec2 *sec2 = nvkm_sec2(engine); + struct nvkm_subdev *subdev = &sec2->engine.subdev; + struct nvkm_falcon *falcon = &sec2->falcon; + struct nvkm_falcon_cmdq *cmdq = sec2->cmdq; + struct nvfw_falcon_cmd cmd = { + .unit_id = sec2->func->unit_unload, + .size = sizeof(cmd), + }; + int ret; - if (!sec2->initmsg_received) { - int ret = sec2->func->initmsg(sec2); - if (ret) { - nvkm_error(&sec2->engine.subdev, - "error parsing init message: %d\n", ret); - return; - } + if (!subdev->use.enabled) + return 0; - sec2->initmsg_received = true; + if (atomic_read(&sec2->initmsg) == 1) { + ret = nvkm_falcon_cmdq_send(cmdq, &cmd, nvkm_sec2_finimsg, sec2, + msecs_to_jiffies(1000)); + WARN_ON(ret); + + nvkm_msec(subdev->device, 2000, + if (nvkm_falcon_rd32(falcon, 0x100) & 0x00000010) + break; + ); } - nvkm_falcon_msgq_recv(sec2->msgq); + nvkm_inth_block(&subdev->inth); + + nvkm_falcon_cmdq_fini(cmdq); + falcon->func->disable(falcon); + nvkm_falcon_put(falcon, subdev); + return 0; } -static void -nvkm_sec2_intr(struct nvkm_engine *engine) +static int +nvkm_sec2_init(struct nvkm_engine *engine) { struct nvkm_sec2 *sec2 = nvkm_sec2(engine); - sec2->func->intr(sec2); + struct nvkm_subdev *subdev = &sec2->engine.subdev; + struct nvkm_falcon *falcon = &sec2->falcon; + int ret; + + ret = nvkm_falcon_get(falcon, subdev); + if (ret) + return ret; + + nvkm_falcon_wr32(falcon, 0x014, 0xffffffff); + atomic_set(&sec2->initmsg, 0); + atomic_set(&sec2->running, 1); + nvkm_inth_allow(&subdev->inth); + + nvkm_falcon_start(falcon); + return 0; } static int -nvkm_sec2_fini(struct nvkm_engine *engine, bool suspend) +nvkm_sec2_oneinit(struct nvkm_engine *engine) { struct nvkm_sec2 *sec2 = nvkm_sec2(engine); - - flush_work(&sec2->work); - - if (suspend) { - nvkm_falcon_cmdq_fini(sec2->cmdq); - sec2->initmsg_received = false; + struct nvkm_subdev *subdev = &sec2->engine.subdev; + struct nvkm_intr *intr = &sec2->engine.subdev.device->mc->intr; + enum nvkm_intr_type type = NVKM_INTR_SUBDEV; + + if (sec2->func->intr_vector) { + intr = sec2->func->intr_vector(sec2, &type); + if (IS_ERR(intr)) + return PTR_ERR(intr); } - return 0; + return nvkm_inth_add(intr, type, NVKM_INTR_PRIO_NORMAL, subdev, sec2->func->intr, + &subdev->inth); } static void * nvkm_sec2_dtor(struct nvkm_engine *engine) { struct nvkm_sec2 *sec2 = nvkm_sec2(engine); + nvkm_falcon_msgq_del(&sec2->msgq); nvkm_falcon_cmdq_del(&sec2->cmdq); nvkm_falcon_qmgr_del(&sec2->qmgr); @@ -79,8 +125,9 @@ nvkm_sec2_dtor(struct nvkm_engine *engine) static const struct nvkm_engine_func nvkm_sec2 = { .dtor = nvkm_sec2_dtor, + .oneinit = nvkm_sec2_oneinit, + .init = nvkm_sec2_init, .fini = nvkm_sec2_fini, - .intr = nvkm_sec2_intr, }; int @@ -113,6 +160,5 @@ nvkm_sec2_new_(const struct nvkm_sec2_fwif *fwif, struct nvkm_device *device, (ret = nvkm_falcon_msgq_new(sec2->qmgr, "msgq", &sec2->msgq))) return ret; - INIT_WORK(&sec2->work, nvkm_sec2_recv); return 0; }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/ga102.c b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/ga102.c new file mode 100644 index 000000000000..945abb8156d7 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/ga102.c @@ -0,0 +1,197 @@ +/* + * 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 <subdev/acr.h> +#include <subdev/vfn.h> + +#include <nvfw/flcn.h> +#include <nvfw/sec2.h> + +static int +ga102_sec2_initmsg(struct nvkm_sec2 *sec2) +{ + struct nv_sec2_init_msg_v1 msg; + int ret, i; + + ret = nvkm_falcon_msgq_recv_initmsg(sec2->msgq, &msg, sizeof(msg)); + if (ret) + return ret; + + if (msg.hdr.unit_id != NV_SEC2_UNIT_INIT || + msg.msg_type != NV_SEC2_INIT_MSG_INIT) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(msg.queue_info); i++) { + if (msg.queue_info[i].id == NV_SEC2_INIT_MSG_QUEUE_ID_MSGQ) { + nvkm_falcon_msgq_init(sec2->msgq, msg.queue_info[i].index, + msg.queue_info[i].offset, + msg.queue_info[i].size); + } else { + nvkm_falcon_cmdq_init(sec2->cmdq, msg.queue_info[i].index, + msg.queue_info[i].offset, + msg.queue_info[i].size); + } + } + + return 0; +} + +static struct nvkm_intr * +ga102_sec2_intr_vector(struct nvkm_sec2 *sec2, enum nvkm_intr_type *pvector) +{ + struct nvkm_device *device = sec2->engine.subdev.device; + struct nvkm_falcon *falcon = &sec2->falcon; + int ret; + + ret = ga102_flcn_select(falcon); + if (ret) + return ERR_PTR(ret); + + *pvector = nvkm_rd32(device, 0x8403e0) & 0x000000ff; + return &device->vfn->intr; +} + +static int +ga102_sec2_acr_bootstrap_falcon_callback(void *priv, struct nvfw_falcon_msg *hdr) +{ + struct nv_sec2_acr_bootstrap_falcon_msg_v1 *msg = + container_of(hdr, typeof(*msg), msg.hdr); + struct nvkm_subdev *subdev = priv; + const char *name = nvkm_acr_lsf_id(msg->falcon_id); + + if (msg->error_code) { + nvkm_error(subdev, "ACR_BOOTSTRAP_FALCON failed for falcon %d [%s]: %08x %08x\n", + msg->falcon_id, name, msg->error_code, msg->unkn08); + return -EINVAL; + } + + nvkm_debug(subdev, "%s booted\n", name); + return 0; +} + +static int +ga102_sec2_acr_bootstrap_falcon(struct nvkm_falcon *falcon, enum nvkm_acr_lsf_id id) +{ + struct nvkm_sec2 *sec2 = container_of(falcon, typeof(*sec2), falcon); + struct nv_sec2_acr_bootstrap_falcon_cmd_v1 cmd = { + .cmd.hdr.unit_id = sec2->func->unit_acr, + .cmd.hdr.size = sizeof(cmd), + .cmd.cmd_type = NV_SEC2_ACR_CMD_BOOTSTRAP_FALCON, + .flags = NV_SEC2_ACR_BOOTSTRAP_FALCON_FLAGS_RESET_YES, + .falcon_id = id, + }; + + return nvkm_falcon_cmdq_send(sec2->cmdq, &cmd.cmd.hdr, + ga102_sec2_acr_bootstrap_falcon_callback, + &sec2->engine.subdev, + msecs_to_jiffies(1000)); +} + +static const struct nvkm_acr_lsf_func +ga102_sec2_acr_0 = { + .bld_size = sizeof(struct flcn_bl_dmem_desc_v2), + .bld_write = gp102_sec2_acr_bld_write_1, + .bld_patch = gp102_sec2_acr_bld_patch_1, + .bootstrap_falcons = BIT_ULL(NVKM_ACR_LSF_FECS) | + BIT_ULL(NVKM_ACR_LSF_GPCCS) | + BIT_ULL(NVKM_ACR_LSF_SEC2), + .bootstrap_falcon = ga102_sec2_acr_bootstrap_falcon, +}; + +static const struct nvkm_falcon_func +ga102_sec2_flcn = { + .disable = gm200_flcn_disable, + .enable = gm200_flcn_enable, + .select = ga102_flcn_select, + .addr2 = 0x1000, + .reset_pmc = true, + .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_pio = &gm200_flcn_dmem_pio, + .dmem_dma = &ga102_flcn_dma, + .emem_addr = 0x01000000, + .emem_pio = &gp102_flcn_emem_pio, + .start = nvkm_falcon_v1_start, + .cmdq = { 0xc00, 0xc04, 8 }, + .msgq = { 0xc80, 0xc84, 8 }, +}; + +static const struct nvkm_sec2_func +ga102_sec2 = { + .flcn = &ga102_sec2_flcn, + .intr_vector = ga102_sec2_intr_vector, + .intr = gp102_sec2_intr, + .initmsg = ga102_sec2_initmsg, + .unit_acr = NV_SEC2_UNIT_V2_ACR, + .unit_unload = NV_SEC2_UNIT_V2_UNLOAD, +}; + +MODULE_FIRMWARE("nvidia/ga102/sec2/desc.bin"); +MODULE_FIRMWARE("nvidia/ga102/sec2/image.bin"); +MODULE_FIRMWARE("nvidia/ga102/sec2/sig.bin"); +MODULE_FIRMWARE("nvidia/ga102/sec2/hs_bl_sig.bin"); + +MODULE_FIRMWARE("nvidia/ga103/sec2/desc.bin"); +MODULE_FIRMWARE("nvidia/ga103/sec2/image.bin"); +MODULE_FIRMWARE("nvidia/ga103/sec2/sig.bin"); +MODULE_FIRMWARE("nvidia/ga103/sec2/hs_bl_sig.bin"); + +MODULE_FIRMWARE("nvidia/ga104/sec2/desc.bin"); +MODULE_FIRMWARE("nvidia/ga104/sec2/image.bin"); +MODULE_FIRMWARE("nvidia/ga104/sec2/sig.bin"); +MODULE_FIRMWARE("nvidia/ga104/sec2/hs_bl_sig.bin"); + +MODULE_FIRMWARE("nvidia/ga106/sec2/desc.bin"); +MODULE_FIRMWARE("nvidia/ga106/sec2/image.bin"); +MODULE_FIRMWARE("nvidia/ga106/sec2/sig.bin"); +MODULE_FIRMWARE("nvidia/ga106/sec2/hs_bl_sig.bin"); + +MODULE_FIRMWARE("nvidia/ga107/sec2/desc.bin"); +MODULE_FIRMWARE("nvidia/ga107/sec2/image.bin"); +MODULE_FIRMWARE("nvidia/ga107/sec2/sig.bin"); +MODULE_FIRMWARE("nvidia/ga107/sec2/hs_bl_sig.bin"); + +static int +ga102_sec2_load(struct nvkm_sec2 *sec2, int ver, + const struct nvkm_sec2_fwif *fwif) +{ + return nvkm_acr_lsfw_load_sig_image_desc_v2(&sec2->engine.subdev, &sec2->falcon, + NVKM_ACR_LSF_SEC2, "sec2/", ver, fwif->acr); +} + +static const struct nvkm_sec2_fwif +ga102_sec2_fwif[] = { + { 0, ga102_sec2_load, &ga102_sec2, &ga102_sec2_acr_0 }, + { -1, gp102_sec2_nofw, &ga102_sec2 } +}; + +int +ga102_sec2_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, + struct nvkm_sec2 **psec2) +{ + /* TOP info wasn't updated on Turing to reflect the PRI + * address change for some reason. We override it here. + */ + return nvkm_sec2_new_(ga102_sec2_fwif, device, type, inst, 0x840000, psec2); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/gp102.c b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/gp102.c index 44e39f5743d5..c64013d10500 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/gp102.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/gp102.c @@ -74,16 +74,6 @@ gp102_sec2_acr_bootstrap_falcon(struct nvkm_falcon *falcon, msecs_to_jiffies(1000)); } -static int -gp102_sec2_acr_boot(struct nvkm_falcon *falcon) -{ - struct nv_sec2_args args = {}; - nvkm_falcon_load_dmem(falcon, &args, - falcon->func->emem_addr, sizeof(args), 0); - nvkm_falcon_start(falcon); - return 0; -} - static void gp102_sec2_acr_bld_patch(struct nvkm_acr *acr, u32 bld, s64 adjust) { @@ -122,7 +112,6 @@ gp102_sec2_acr_0 = { .bld_size = sizeof(struct loader_config_v1), .bld_write = gp102_sec2_acr_bld_write, .bld_patch = gp102_sec2_acr_bld_patch, - .boot = gp102_sec2_acr_boot, .bootstrap_falcons = BIT_ULL(NVKM_ACR_LSF_FECS) | BIT_ULL(NVKM_ACR_LSF_GPCCS) | BIT_ULL(NVKM_ACR_LSF_SEC2), @@ -160,89 +149,68 @@ gp102_sec2_initmsg(struct nvkm_sec2 *sec2) return 0; } -void -gp102_sec2_intr(struct nvkm_sec2 *sec2) +irqreturn_t +gp102_sec2_intr(struct nvkm_inth *inth) { + struct nvkm_sec2 *sec2 = container_of(inth, typeof(*sec2), engine.subdev.inth); struct nvkm_subdev *subdev = &sec2->engine.subdev; struct nvkm_falcon *falcon = &sec2->falcon; u32 disp = nvkm_falcon_rd32(falcon, 0x01c); u32 intr = nvkm_falcon_rd32(falcon, 0x008) & disp & ~(disp >> 16); if (intr & 0x00000040) { - schedule_work(&sec2->work); + if (unlikely(atomic_read(&sec2->initmsg) == 0)) { + int ret = sec2->func->initmsg(sec2); + + if (ret) + nvkm_error(subdev, "error parsing init message: %d\n", ret); + + atomic_set(&sec2->initmsg, ret ?: 1); + } + + if (atomic_read(&sec2->initmsg) > 0) { + if (!nvkm_falcon_msgq_empty(sec2->msgq)) + nvkm_falcon_msgq_recv(sec2->msgq); + } + nvkm_falcon_wr32(falcon, 0x004, 0x00000040); intr &= ~0x00000040; } + if (intr & 0x00000010) { + if (atomic_read(&sec2->running)) { + FLCN_ERR(falcon, "halted"); + gm200_flcn_tracepc(falcon); + } + + nvkm_falcon_wr32(falcon, 0x004, 0x00000010); + intr &= ~0x00000010; + } + if (intr) { nvkm_error(subdev, "unhandled intr %08x\n", intr); nvkm_falcon_wr32(falcon, 0x004, intr); } -} -int -gp102_sec2_flcn_enable(struct nvkm_falcon *falcon) -{ - nvkm_falcon_mask(falcon, 0x3c0, 0x00000001, 0x00000001); - udelay(10); - nvkm_falcon_mask(falcon, 0x3c0, 0x00000001, 0x00000000); - return nvkm_falcon_v1_enable(falcon); -} - -void -gp102_sec2_flcn_bind_context(struct nvkm_falcon *falcon, - struct nvkm_memory *ctx) -{ - struct nvkm_device *device = falcon->owner->device; - - nvkm_falcon_v1_bind_context(falcon, ctx); - if (!ctx) - return; - - /* Not sure if this is a WAR for a HW issue, or some additional - * programming sequence that's needed to properly complete the - * context switch we trigger above. - * - * Fixes unreliability of booting the SEC2 RTOS on Quadro P620, - * particularly when resuming from suspend. - * - * Also removes the need for an odd workaround where we needed - * to program SEC2's FALCON_CPUCTL_ALIAS_STARTCPU twice before - * the SEC2 RTOS would begin executing. - */ - nvkm_msec(device, 10, - u32 irqstat = nvkm_falcon_rd32(falcon, 0x008); - u32 flcn0dc = nvkm_falcon_rd32(falcon, 0x0dc); - if ((irqstat & 0x00000008) && - (flcn0dc & 0x00007000) == 0x00005000) - break; - ); - - nvkm_falcon_mask(falcon, 0x004, 0x00000008, 0x00000008); - nvkm_falcon_mask(falcon, 0x058, 0x00000002, 0x00000002); - - nvkm_msec(device, 10, - u32 flcn0dc = nvkm_falcon_rd32(falcon, 0x0dc); - if ((flcn0dc & 0x00007000) == 0x00000000) - break; - ); + return IRQ_HANDLED; } static const struct nvkm_falcon_func gp102_sec2_flcn = { + .disable = gm200_flcn_disable, + .enable = gm200_flcn_enable, + .reset_pmc = true, + .reset_eng = gp102_flcn_reset_eng, + .reset_wait_mem_scrubbing = gm200_flcn_reset_wait_mem_scrubbing, .debug = 0x408, - .fbif = 0x600, - .load_imem = nvkm_falcon_v1_load_imem, - .load_dmem = nvkm_falcon_v1_load_dmem, - .read_dmem = nvkm_falcon_v1_read_dmem, + .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, .emem_addr = 0x01000000, - .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, + .emem_pio = &gp102_flcn_emem_pio, .start = nvkm_falcon_v1_start, - .enable = gp102_sec2_flcn_enable, - .disable = nvkm_falcon_v1_disable, .cmdq = { 0xa00, 0xa04, 8 }, .msgq = { 0xa30, 0xa34, 8 }, }; @@ -250,6 +218,7 @@ gp102_sec2_flcn = { const struct nvkm_sec2_func gp102_sec2 = { .flcn = &gp102_sec2_flcn, + .unit_unload = NV_SEC2_UNIT_UNLOAD, .unit_acr = NV_SEC2_UNIT_ACR, .intr = gp102_sec2_intr, .initmsg = gp102_sec2_initmsg, @@ -268,7 +237,7 @@ MODULE_FIRMWARE("nvidia/gp107/sec2/desc.bin"); MODULE_FIRMWARE("nvidia/gp107/sec2/image.bin"); MODULE_FIRMWARE("nvidia/gp107/sec2/sig.bin"); -static void +void gp102_sec2_acr_bld_patch_1(struct nvkm_acr *acr, u32 bld, s64 adjust) { struct flcn_bl_dmem_desc_v2 hdr; @@ -279,7 +248,7 @@ gp102_sec2_acr_bld_patch_1(struct nvkm_acr *acr, u32 bld, s64 adjust) flcn_bl_dmem_desc_v2_dump(&acr->subdev, &hdr); } -static void +void gp102_sec2_acr_bld_write_1(struct nvkm_acr *acr, u32 bld, struct nvkm_acr_lsfw *lsfw) { @@ -304,7 +273,6 @@ gp102_sec2_acr_1 = { .bld_size = sizeof(struct flcn_bl_dmem_desc_v2), .bld_write = gp102_sec2_acr_bld_write_1, .bld_patch = gp102_sec2_acr_bld_patch_1, - .boot = gp102_sec2_acr_boot, .bootstrap_falcons = BIT_ULL(NVKM_ACR_LSF_FECS) | BIT_ULL(NVKM_ACR_LSF_GPCCS) | BIT_ULL(NVKM_ACR_LSF_SEC2), diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/priv.h index af19229e885d..172d2705c199 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/priv.h @@ -2,15 +2,18 @@ #ifndef __NVKM_SEC2_PRIV_H__ #define __NVKM_SEC2_PRIV_H__ #include <engine/sec2.h> +struct nvkm_acr_lsfw; struct nvkm_sec2_func { const struct nvkm_falcon_func *flcn; + u8 unit_unload; u8 unit_acr; - void (*intr)(struct nvkm_sec2 *); + struct nvkm_intr *(*intr_vector)(struct nvkm_sec2 *, enum nvkm_intr_type *); + irqreturn_t (*intr)(struct nvkm_inth *); int (*initmsg)(struct nvkm_sec2 *); }; -void gp102_sec2_intr(struct nvkm_sec2 *); +irqreturn_t gp102_sec2_intr(struct nvkm_inth *); int gp102_sec2_initmsg(struct nvkm_sec2 *); struct nvkm_sec2_fwif { @@ -24,6 +27,8 @@ int gp102_sec2_nofw(struct nvkm_sec2 *, int, const struct nvkm_sec2_fwif *); int gp102_sec2_load(struct nvkm_sec2 *, int, const struct nvkm_sec2_fwif *); extern const struct nvkm_sec2_func gp102_sec2; extern const struct nvkm_acr_lsf_func gp102_sec2_acr_1; +void gp102_sec2_acr_bld_write_1(struct nvkm_acr *, u32, struct nvkm_acr_lsfw *); +void gp102_sec2_acr_bld_patch_1(struct nvkm_acr *, u32, s64); int nvkm_sec2_new_(const struct nvkm_sec2_fwif *, struct nvkm_device *, enum nvkm_subdev_type, int, u32 addr, struct nvkm_sec2 **); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/tu102.c b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/tu102.c index f3faeb705575..0afc4b2fa529 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/tu102.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/tu102.c @@ -22,21 +22,24 @@ #include "priv.h" #include <subdev/acr.h> +#include <nvfw/sec2.h> + static const struct nvkm_falcon_func tu102_sec2_flcn = { + .disable = gm200_flcn_disable, + .enable = gm200_flcn_enable, + .reset_pmc = true, + .reset_eng = gp102_flcn_reset_eng, + .reset_wait_mem_scrubbing = gm200_flcn_reset_wait_mem_scrubbing, .debug = 0x408, - .fbif = 0x600, - .load_imem = nvkm_falcon_v1_load_imem, - .load_dmem = nvkm_falcon_v1_load_dmem, - .read_dmem = nvkm_falcon_v1_read_dmem, + .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, .emem_addr = 0x01000000, - .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, + .emem_pio = &gp102_flcn_emem_pio, .start = nvkm_falcon_v1_start, - .enable = nvkm_falcon_v1_enable, - .disable = nvkm_falcon_v1_disable, .cmdq = { 0xc00, 0xc04, 8 }, .msgq = { 0xc80, 0xc84, 8 }, }; @@ -44,7 +47,8 @@ tu102_sec2_flcn = { static const struct nvkm_sec2_func tu102_sec2 = { .flcn = &tu102_sec2_flcn, - .unit_acr = 0x07, + .unit_unload = NV_SEC2_UNIT_V2_UNLOAD, + .unit_acr = NV_SEC2_UNIT_V2_ACR, .intr = gp102_sec2_intr, .initmsg = gp102_sec2_initmsg, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/base.c index 14871d0bd746..a9d464db6974 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/base.c @@ -35,7 +35,7 @@ nvkm_sw_mthd(struct nvkm_sw *sw, int chid, int subc, u32 mthd, u32 data) spin_lock_irqsave(&sw->engine.lock, flags); list_for_each_entry(chan, &sw->chan, head) { - if (chan->fifo->chid == chid) { + if (chan->fifo->id == chid) { handled = nvkm_sw_chan_mthd(chan, subc, mthd, data); list_del(&chan->head); list_add(&chan->head, &sw->chan); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.c index f28967065639..834b8cbed51d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.c @@ -23,7 +23,6 @@ */ #include "chan.h" -#include <core/notify.h> #include <engine/fifo.h> #include <nvif/event.h> @@ -36,7 +35,7 @@ nvkm_sw_chan_mthd(struct nvkm_sw_chan *chan, int subc, u32 mthd, u32 data) case 0x0000: return true; case 0x0500: - nvkm_event_send(&chan->event, 1, 0, NULL, 0); + nvkm_event_ntfy(&chan->event, 0, NVKM_SW_CHAN_EVENT_PAGE_FLIP); return true; default: if (chan->func->mthd) @@ -46,27 +45,8 @@ nvkm_sw_chan_mthd(struct nvkm_sw_chan *chan, int subc, u32 mthd, u32 data) return false; } -static int -nvkm_sw_chan_event_ctor(struct nvkm_object *object, void *data, u32 size, - struct nvkm_notify *notify) -{ - union { - struct nvif_notify_uevent_req none; - } *req = data; - int ret = -ENOSYS; - - if (!(ret = nvif_unvers(ret, &data, &size, req->none))) { - notify->size = sizeof(struct nvif_notify_uevent_rep); - notify->types = 1; - notify->index = 0; - } - - return ret; -} - static const struct nvkm_event_func nvkm_sw_chan_event = { - .ctor = nvkm_sw_chan_event_ctor, }; static void * @@ -107,5 +87,5 @@ nvkm_sw_chan_ctor(const struct nvkm_sw_chan_func *func, struct nvkm_sw *sw, list_add(&chan->head, &sw->chan); spin_unlock_irqrestore(&sw->engine.lock, flags); - return nvkm_event_init(&nvkm_sw_chan_event, 1, 1, &chan->event); + return nvkm_event_init(&nvkm_sw_chan_event, &sw->engine.subdev, 1, 1, &chan->event); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.h b/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.h index 32de53427aa4..67b2e5ea93d9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.h @@ -14,6 +14,7 @@ struct nvkm_sw_chan { struct nvkm_fifo_chan *fifo; struct list_head head; +#define NVKM_SW_CHAN_EVENT_PAGE_FLIP BIT(0) struct nvkm_event event; }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c index 55abf839f29d..c3cf6f2ff86c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c @@ -36,10 +36,10 @@ ******************************************************************************/ static int -gf100_sw_chan_vblsem_release(struct nvkm_notify *notify) +gf100_sw_chan_vblsem_release(struct nvkm_event_ntfy *notify, u32 bits) { struct nv50_sw_chan *chan = - container_of(notify, typeof(*chan), vblank.notify[notify->index]); + container_of(notify, typeof(*chan), vblank.notify[notify->id]); struct nvkm_sw *sw = chan->base.sw; struct nvkm_device *device = sw->engine.subdev.device; u32 inst = chan->base.fifo->inst->addr >> 12; @@ -50,7 +50,7 @@ gf100_sw_chan_vblsem_release(struct nvkm_notify *notify) nvkm_wr32(device, 0x060010, lower_32_bits(chan->vblank.offset)); nvkm_wr32(device, 0x060014, chan->vblank.value); - return NVKM_NOTIFY_DROP; + return NVKM_EVENT_DROP; } static bool @@ -73,7 +73,7 @@ gf100_sw_chan_mthd(struct nvkm_sw_chan *base, int subc, u32 mthd, u32 data) return true; case 0x040c: if (data < device->disp->vblank.index_nr) { - nvkm_notify_get(&chan->vblank.notify[data]); + nvkm_event_ntfy_allow(&chan->vblank.notify[data]); return true; } break; @@ -120,16 +120,8 @@ gf100_sw_chan_new(struct nvkm_sw *sw, struct nvkm_fifo_chan *fifoch, return ret; for (i = 0; disp && i < disp->vblank.index_nr; i++) { - ret = nvkm_notify_init(NULL, &disp->vblank, - gf100_sw_chan_vblsem_release, false, - &(struct nvif_notify_head_req_v0) { - .head = i, - }, - sizeof(struct nvif_notify_head_req_v0), - sizeof(struct nvif_notify_head_rep_v0), - &chan->vblank.notify[i]); - if (ret) - return ret; + nvkm_event_ntfy_add(&disp->vblank, i, NVKM_DISP_HEAD_EVENT_VBLANK, true, + gf100_sw_chan_vblsem_release, &chan->vblank.notify[i]); } return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c index 1fdd094c8b7e..9d7a9b7d5be3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c @@ -36,10 +36,10 @@ ******************************************************************************/ static int -nv50_sw_chan_vblsem_release(struct nvkm_notify *notify) +nv50_sw_chan_vblsem_release(struct nvkm_event_ntfy *notify, u32 bits) { struct nv50_sw_chan *chan = - container_of(notify, typeof(*chan), vblank.notify[notify->index]); + container_of(notify, typeof(*chan), vblank.notify[notify->id]); struct nvkm_sw *sw = chan->base.sw; struct nvkm_device *device = sw->engine.subdev.device; @@ -55,7 +55,7 @@ nv50_sw_chan_vblsem_release(struct nvkm_notify *notify) nvkm_wr32(device, 0x060014, chan->vblank.value); } - return NVKM_NOTIFY_DROP; + return NVKM_EVENT_DROP; } static bool @@ -70,7 +70,7 @@ nv50_sw_chan_mthd(struct nvkm_sw_chan *base, int subc, u32 mthd, u32 data) case 0x0404: chan->vblank.value = data; return true; case 0x0408: if (data < device->disp->vblank.index_nr) { - nvkm_notify_get(&chan->vblank.notify[data]); + nvkm_event_ntfy_allow(&chan->vblank.notify[data]); return true; } break; @@ -85,8 +85,10 @@ nv50_sw_chan_dtor(struct nvkm_sw_chan *base) { struct nv50_sw_chan *chan = nv50_sw_chan(base); int i; + for (i = 0; i < ARRAY_SIZE(chan->vblank.notify); i++) - nvkm_notify_fini(&chan->vblank.notify[i]); + nvkm_event_ntfy_del(&chan->vblank.notify[i]); + return chan; } @@ -113,16 +115,8 @@ nv50_sw_chan_new(struct nvkm_sw *sw, struct nvkm_fifo_chan *fifoch, return ret; for (i = 0; disp && i < disp->vblank.index_nr; i++) { - ret = nvkm_notify_init(NULL, &disp->vblank, - nv50_sw_chan_vblsem_release, false, - &(struct nvif_notify_head_req_v0) { - .head = i, - }, - sizeof(struct nvif_notify_head_req_v0), - sizeof(struct nvif_notify_head_rep_v0), - &chan->vblank.notify[i]); - if (ret) - return ret; + nvkm_event_ntfy_add(&disp->vblank, i, NVKM_DISP_HEAD_EVENT_VBLANK, true, + nv50_sw_chan_vblsem_release, &chan->vblank.notify[i]); } return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h index 6d364d7b406a..b42289ce8826 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h @@ -5,12 +5,12 @@ #include "priv.h" #include "chan.h" #include "nvsw.h" -#include <core/notify.h> +#include <core/event.h> struct nv50_sw_chan { struct nvkm_sw_chan base; struct { - struct nvkm_notify notify[4]; + struct nvkm_event_ntfy notify[4]; u32 ctxdma; u64 offset; u32 value; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.c index 33dd03fff3c4..f5affa1c8f34 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.c @@ -27,33 +27,34 @@ #include <nvif/if0004.h> static int -nvkm_nvsw_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size) +nvkm_nvsw_uevent(struct nvkm_object *object, void *argv, u32 argc, struct nvkm_uevent *uevent) { - struct nvkm_nvsw *nvsw = nvkm_nvsw(object); - if (nvsw->func->mthd) - return nvsw->func->mthd(nvsw, mthd, data, size); - return -ENODEV; + union nv04_nvsw_event_args *args = argv; + + if (!uevent) + return 0; + if (argc != sizeof(args->vn)) + return -ENOSYS; + + return nvkm_uevent_add(uevent, &nvkm_nvsw(object)->chan->event, 0, + NVKM_SW_CHAN_EVENT_PAGE_FLIP, NULL); } static int -nvkm_nvsw_ntfy_(struct nvkm_object *object, u32 mthd, - struct nvkm_event **pevent) +nvkm_nvsw_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) { struct nvkm_nvsw *nvsw = nvkm_nvsw(object); - switch (mthd) { - case NV04_NVSW_NTFY_UEVENT: - *pevent = &nvsw->chan->event; - return 0; - default: - break; - } - return -EINVAL; + + if (nvsw->func->mthd) + return nvsw->func->mthd(nvsw, mthd, data, size); + + return -ENODEV; } static const struct nvkm_object_func nvkm_nvsw_ = { - .mthd = nvkm_nvsw_mthd_, - .ntfy = nvkm_nvsw_ntfy_, + .mthd = nvkm_nvsw_mthd, + .uevent = nvkm_nvsw_uevent, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/Kbuild b/drivers/gpu/drm/nouveau/nvkm/falcon/Kbuild index d79d783904ee..9ffe7b921ccb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/falcon/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/falcon/Kbuild @@ -1,6 +1,12 @@ # SPDX-License-Identifier: MIT nvkm-y += nvkm/falcon/base.o nvkm-y += nvkm/falcon/cmdq.o +nvkm-y += nvkm/falcon/fw.o nvkm-y += nvkm/falcon/msgq.o nvkm-y += nvkm/falcon/qmgr.o nvkm-y += nvkm/falcon/v1.o + +nvkm-y += nvkm/falcon/gm200.o +nvkm-y += nvkm/falcon/gp102.o +nvkm-y += nvkm/falcon/ga100.o +nvkm-y += nvkm/falcon/ga102.o diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/base.c b/drivers/gpu/drm/nouveau/nvkm/falcon/base.c index f3f90c1063dd..235149f73a69 100644 --- a/drivers/gpu/drm/nouveau/nvkm/falcon/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/falcon/base.c @@ -22,119 +22,217 @@ #include "priv.h" #include <subdev/mc.h> +#include <subdev/timer.h> #include <subdev/top.h> -void -nvkm_falcon_load_imem(struct nvkm_falcon *falcon, void *data, u32 start, - u32 size, u16 tag, u8 port, bool secure) +static const struct nvkm_falcon_func_dma * +nvkm_falcon_dma(struct nvkm_falcon *falcon, enum nvkm_falcon_mem *mem_type, u32 *mem_base) { - if (secure && !falcon->secret) { - nvkm_warn(falcon->user, - "writing with secure tag on a non-secure falcon!\n"); - return; + switch (*mem_type) { + case IMEM: return falcon->func->imem_dma; + case DMEM: return falcon->func->dmem_dma; + default: + return NULL; } - - falcon->func->load_imem(falcon, data, start, size, tag, port, - secure); } -void -nvkm_falcon_load_dmem(struct nvkm_falcon *falcon, void *data, u32 start, - u32 size, u8 port) +int +nvkm_falcon_dma_wr(struct nvkm_falcon *falcon, const u8 *img, u64 dma_addr, u32 dma_base, + enum nvkm_falcon_mem mem_type, u32 mem_base, int len, bool sec) { - mutex_lock(&falcon->dmem_mutex); - - falcon->func->load_dmem(falcon, data, start, size, port); + const struct nvkm_falcon_func_dma *dma = nvkm_falcon_dma(falcon, &mem_type, &mem_base); + const char *type = nvkm_falcon_mem(mem_type); + const int dmalen = 256; + u32 dma_start = 0; + u32 dst, src, cmd; + int ret, i; + + if (WARN_ON(!dma->xfer)) + return -EINVAL; + + if (mem_type == DMEM) { + dma_start = dma_base; + dma_addr += dma_base; + } - mutex_unlock(&falcon->dmem_mutex); -} + FLCN_DBG(falcon, "%s %08x <- %08x bytes at %08x (%010llx %08x)", + type, mem_base, len, dma_base, dma_addr - dma_base, dma_start); + if (WARN_ON(!len || (len & (dmalen - 1)))) + return -EINVAL; -void -nvkm_falcon_read_dmem(struct nvkm_falcon *falcon, u32 start, u32 size, u8 port, - void *data) -{ - mutex_lock(&falcon->dmem_mutex); + ret = dma->init(falcon, dma_addr, dmalen, mem_type, sec, &cmd); + if (ret) + return ret; - falcon->func->read_dmem(falcon, start, size, port, data); + dst = mem_base; + src = dma_base; + if (len) { + while (len >= dmalen) { + dma->xfer(falcon, dst, src - dma_start, cmd); + + if (img && nvkm_printk_ok(falcon->owner, falcon->user, NV_DBG_TRACE)) { + for (i = 0; i < dmalen; i += 4, mem_base += 4) { + const int w = 8, x = (i / 4) % w; + + if (x == 0) + printk(KERN_INFO "%s %08x <-", type, mem_base); + printk(KERN_CONT " %08x", *(u32 *)(img + src + i)); + if (x == (w - 1) || ((i + 4) == dmalen)) + printk(KERN_CONT " <- %08x+%08x", dma_base, + src + i - dma_base - (x * 4)); + if (i == (7 * 4)) + printk(KERN_CONT " *"); + } + } + + if (nvkm_msec(falcon->owner->device, 2000, + if (dma->done(falcon)) + break; + ) < 0) + return -ETIMEDOUT; + + src += dmalen; + dst += dmalen; + len -= dmalen; + } + WARN_ON(len); + } - mutex_unlock(&falcon->dmem_mutex); + return 0; } -void -nvkm_falcon_bind_context(struct nvkm_falcon *falcon, struct nvkm_memory *inst) +static const struct nvkm_falcon_func_pio * +nvkm_falcon_pio(struct nvkm_falcon *falcon, enum nvkm_falcon_mem *mem_type, u32 *mem_base) { - if (!falcon->func->bind_context) { - nvkm_error(falcon->user, - "Context binding not supported on this falcon!\n"); - return; + switch (*mem_type) { + case IMEM: + return falcon->func->imem_pio; + case DMEM: + if (!falcon->func->emem_addr || *mem_base < falcon->func->emem_addr) + return falcon->func->dmem_pio; + + *mem_base -= falcon->func->emem_addr; + fallthrough; + case EMEM: + return falcon->func->emem_pio; + default: + return NULL; } - - falcon->func->bind_context(falcon, inst); } -void -nvkm_falcon_set_start_addr(struct nvkm_falcon *falcon, u32 start_addr) +int +nvkm_falcon_pio_rd(struct nvkm_falcon *falcon, u8 port, enum nvkm_falcon_mem mem_type, u32 mem_base, + const u8 *img, u32 img_base, int len) { - falcon->func->set_start_addr(falcon, start_addr); -} + const struct nvkm_falcon_func_pio *pio = nvkm_falcon_pio(falcon, &mem_type, &mem_base); + const char *type = nvkm_falcon_mem(mem_type); + int xfer_len; + + if (WARN_ON(!pio || !pio->rd)) + return -EINVAL; + + FLCN_DBG(falcon, "%s %08x -> %08x bytes at %08x", type, mem_base, len, img_base); + if (WARN_ON(!len || (len & (pio->min - 1)))) + return -EINVAL; + + pio->rd_init(falcon, port, mem_base); + do { + xfer_len = min(len, pio->max); + pio->rd(falcon, port, img, xfer_len); + + if (nvkm_printk_ok(falcon->owner, falcon->user, NV_DBG_TRACE)) { + for (img_base = 0; img_base < xfer_len; img_base += 4, mem_base += 4) { + if (((img_base / 4) % 8) == 0) + printk(KERN_INFO "%s %08x ->", type, mem_base); + printk(KERN_CONT " %08x", *(u32 *)(img + img_base)); + } + } + + img += xfer_len; + len -= xfer_len; + } while (len); -void -nvkm_falcon_start(struct nvkm_falcon *falcon) -{ - falcon->func->start(falcon); + return 0; } int -nvkm_falcon_enable(struct nvkm_falcon *falcon) +nvkm_falcon_pio_wr(struct nvkm_falcon *falcon, const u8 *img, u32 img_base, u8 port, + enum nvkm_falcon_mem mem_type, u32 mem_base, int len, u16 tag, bool sec) { - struct nvkm_device *device = falcon->owner->device; - int ret; - - nvkm_mc_enable(device, falcon->owner->type, falcon->owner->inst); - ret = falcon->func->enable(falcon); - if (ret) { - nvkm_mc_disable(device, falcon->owner->type, falcon->owner->inst); - return ret; - } + const struct nvkm_falcon_func_pio *pio = nvkm_falcon_pio(falcon, &mem_type, &mem_base); + const char *type = nvkm_falcon_mem(mem_type); + int xfer_len; + + if (WARN_ON(!pio || !pio->wr)) + return -EINVAL; + + FLCN_DBG(falcon, "%s %08x <- %08x bytes at %08x", type, mem_base, len, img_base); + if (WARN_ON(!len || (len & (pio->min - 1)))) + return -EINVAL; + + pio->wr_init(falcon, port, sec, mem_base); + do { + xfer_len = min(len, pio->max); + pio->wr(falcon, port, img, xfer_len, tag++); + + if (nvkm_printk_ok(falcon->owner, falcon->user, NV_DBG_TRACE)) { + for (img_base = 0; img_base < xfer_len; img_base += 4, mem_base += 4) { + if (((img_base / 4) % 8) == 0) + printk(KERN_INFO "%s %08x <-", type, mem_base); + printk(KERN_CONT " %08x", *(u32 *)(img + img_base)); + if ((img_base / 4) == 7 && mem_type == IMEM) + printk(KERN_CONT " %04x", tag - 1); + } + } + + img += xfer_len; + len -= xfer_len; + } while (len); return 0; } void -nvkm_falcon_disable(struct nvkm_falcon *falcon) +nvkm_falcon_load_imem(struct nvkm_falcon *falcon, void *data, u32 start, + u32 size, u16 tag, u8 port, bool secure) { - struct nvkm_device *device = falcon->owner->device; - - /* already disabled, return or wait_idle will timeout */ - if (!nvkm_mc_enabled(device, falcon->owner->type, falcon->owner->inst)) + if (secure && !falcon->secret) { + nvkm_warn(falcon->user, + "writing with secure tag on a non-secure falcon!\n"); return; + } - falcon->func->disable(falcon); - - nvkm_mc_disable(device, falcon->owner->type, falcon->owner->inst); + falcon->func->load_imem(falcon, data, start, size, tag, port, + secure); } -int -nvkm_falcon_reset(struct nvkm_falcon *falcon) +void +nvkm_falcon_load_dmem(struct nvkm_falcon *falcon, void *data, u32 start, + u32 size, u8 port) { - if (!falcon->func->reset) { - nvkm_falcon_disable(falcon); - return nvkm_falcon_enable(falcon); - } + mutex_lock(&falcon->dmem_mutex); - return falcon->func->reset(falcon); + falcon->func->load_dmem(falcon, data, start, size, port); + + mutex_unlock(&falcon->dmem_mutex); } -int -nvkm_falcon_wait_for_halt(struct nvkm_falcon *falcon, u32 ms) +void +nvkm_falcon_start(struct nvkm_falcon *falcon) { - return falcon->func->wait_for_halt(falcon, ms); + falcon->func->start(falcon); } int -nvkm_falcon_clear_interrupt(struct nvkm_falcon *falcon, u32 mask) +nvkm_falcon_reset(struct nvkm_falcon *falcon) { - return falcon->func->clear_interrupt(falcon, mask); + int ret; + + ret = falcon->func->disable(falcon); + if (WARN_ON(ret)) + return ret; + + return nvkm_falcon_enable(falcon); } static int @@ -169,7 +267,7 @@ nvkm_falcon_oneinit(struct nvkm_falcon *falcon) } void -nvkm_falcon_put(struct nvkm_falcon *falcon, const struct nvkm_subdev *user) +nvkm_falcon_put(struct nvkm_falcon *falcon, struct nvkm_subdev *user) { if (unlikely(!falcon)) return; @@ -183,7 +281,7 @@ nvkm_falcon_put(struct nvkm_falcon *falcon, const struct nvkm_subdev *user) } int -nvkm_falcon_get(struct nvkm_falcon *falcon, const struct nvkm_subdev *user) +nvkm_falcon_get(struct nvkm_falcon *falcon, struct nvkm_subdev *user) { int ret = 0; @@ -217,6 +315,7 @@ nvkm_falcon_ctor(const struct nvkm_falcon_func *func, falcon->owner = subdev; falcon->name = name; falcon->addr = addr; + falcon->addr2 = func->addr2; mutex_init(&falcon->mutex); mutex_init(&falcon->dmem_mutex); return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/cmdq.c b/drivers/gpu/drm/nouveau/nvkm/falcon/cmdq.c index 44cf6a8862e1..211ebe7afac6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/falcon/cmdq.c +++ b/drivers/gpu/drm/nouveau/nvkm/falcon/cmdq.c @@ -51,7 +51,7 @@ static void nvkm_falcon_cmdq_push(struct nvkm_falcon_cmdq *cmdq, void *data, u32 size) { struct nvkm_falcon *falcon = cmdq->qmgr->falcon; - nvkm_falcon_load_dmem(falcon, data, cmdq->position, size, 0); + nvkm_falcon_pio_wr(falcon, data, 0, 0, DMEM, cmdq->position, size, 0, false); cmdq->position += ALIGN(size, QUEUE_ALIGNMENT); } diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/fw.c b/drivers/gpu/drm/nouveau/nvkm/falcon/fw.c new file mode 100644 index 000000000000..80a480b12174 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/falcon/fw.c @@ -0,0 +1,354 @@ +/* + * 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" + +#include <core/memory.h> +#include <subdev/mmu.h> + +#include <nvfw/fw.h> +#include <nvfw/hs.h> + +int +nvkm_falcon_fw_patch(struct nvkm_falcon_fw *fw) +{ + struct nvkm_falcon *falcon = fw->falcon; + u32 sig_base_src = fw->sig_base_prd; + u32 src, dst, len, i; + int idx = 0; + + FLCNFW_DBG(fw, "patching sigs:%d size:%d", fw->sig_nr, fw->sig_size); + if (fw->func->signature) { + idx = fw->func->signature(fw, &sig_base_src); + if (idx < 0) + return idx; + } + + src = idx * fw->sig_size; + dst = fw->sig_base_img; + len = fw->sig_size / 4; + FLCNFW_DBG(fw, "patch idx:%d src:%08x dst:%08x", idx, sig_base_src + src, dst); + for (i = 0; i < len; i++) { + u32 sig = *(u32 *)(fw->sigs + src); + + if (nvkm_printk_ok(falcon->owner, falcon->user, NV_DBG_TRACE)) { + if (i % 8 == 0) + printk(KERN_INFO "sig -> %08x:", dst); + printk(KERN_CONT " %08x", sig); + } + + *(u32 *)(fw->fw.img + dst) = sig; + src += 4; + dst += 4; + } + + return 0; +} + +static void +nvkm_falcon_fw_dtor_sigs(struct nvkm_falcon_fw *fw) +{ + kfree(fw->sigs); + fw->sigs = NULL; +} + +int +nvkm_falcon_fw_boot(struct nvkm_falcon_fw *fw, struct nvkm_subdev *user, + bool release, u32 *pmbox0, u32 *pmbox1, u32 mbox0_ok, u32 irqsclr) +{ + struct nvkm_falcon *falcon = fw->falcon; + int ret; + + ret = nvkm_falcon_get(falcon, user); + if (ret) + return ret; + + if (fw->sigs) { + ret = nvkm_falcon_fw_patch(fw); + if (ret) + goto done; + + nvkm_falcon_fw_dtor_sigs(fw); + } + + FLCNFW_DBG(fw, "resetting"); + fw->func->reset(fw); + + FLCNFW_DBG(fw, "loading"); + if (fw->func->setup) { + ret = fw->func->setup(fw); + if (ret) + goto done; + } + + ret = fw->func->load(fw); + if (ret) + goto done; + + FLCNFW_DBG(fw, "booting"); + ret = fw->func->boot(fw, pmbox0, pmbox1, mbox0_ok, irqsclr); + if (ret) + FLCNFW_ERR(fw, "boot failed: %d", ret); + else + FLCNFW_DBG(fw, "booted"); + +done: + if (ret || release) + nvkm_falcon_put(falcon, user); + return ret; +} + +int +nvkm_falcon_fw_oneinit(struct nvkm_falcon_fw *fw, struct nvkm_falcon *falcon, + struct nvkm_vmm *vmm, struct nvkm_memory *inst) +{ + int ret; + + fw->falcon = falcon; + fw->vmm = nvkm_vmm_ref(vmm); + fw->inst = nvkm_memory_ref(inst); + + if (fw->boot) { + FLCN_DBG(falcon, "mapping %s fw", fw->fw.name); + ret = nvkm_vmm_get(fw->vmm, 12, nvkm_memory_size(&fw->fw.mem.memory), &fw->vma); + if (ret) { + FLCN_ERR(falcon, "get %d", ret); + return ret; + } + + ret = nvkm_memory_map(&fw->fw.mem.memory, 0, fw->vmm, fw->vma, NULL, 0); + if (ret) { + FLCN_ERR(falcon, "map %d", ret); + return ret; + } + } + + return 0; +} + +void +nvkm_falcon_fw_dtor(struct nvkm_falcon_fw *fw) +{ + nvkm_vmm_put(fw->vmm, &fw->vma); + nvkm_vmm_unref(&fw->vmm); + nvkm_memory_unref(&fw->inst); + nvkm_falcon_fw_dtor_sigs(fw); + nvkm_firmware_dtor(&fw->fw); +} + +static const struct nvkm_firmware_func +nvkm_falcon_fw_dma = { + .type = NVKM_FIRMWARE_IMG_DMA, +}; + +static const struct nvkm_firmware_func +nvkm_falcon_fw = { + .type = NVKM_FIRMWARE_IMG_RAM, +}; + +int +nvkm_falcon_fw_sign(struct nvkm_falcon_fw *fw, u32 sig_base_img, u32 sig_size, const u8 *sigs, + int sig_nr_prd, u32 sig_base_prd, int sig_nr_dbg, u32 sig_base_dbg) +{ + fw->sig_base_prd = sig_base_prd; + fw->sig_base_dbg = sig_base_dbg; + fw->sig_base_img = sig_base_img; + fw->sig_size = sig_size; + fw->sig_nr = sig_nr_prd + sig_nr_dbg; + + fw->sigs = kmalloc_array(fw->sig_nr, fw->sig_size, GFP_KERNEL); + if (!fw->sigs) + return -ENOMEM; + + memcpy(fw->sigs, sigs + sig_base_prd, sig_nr_prd * fw->sig_size); + if (sig_nr_dbg) + memcpy(fw->sigs + sig_size, sigs + sig_base_dbg, sig_nr_dbg * fw->sig_size); + + return 0; +} + +int +nvkm_falcon_fw_ctor(const struct nvkm_falcon_fw_func *func, const char *name, + struct nvkm_device *device, bool dma, const void *src, u32 len, + struct nvkm_falcon *falcon, struct nvkm_falcon_fw *fw) +{ + const struct nvkm_firmware_func *type = dma ? &nvkm_falcon_fw_dma : &nvkm_falcon_fw; + int ret; + + fw->func = func; + + ret = nvkm_firmware_ctor(type, name, device, src, len, &fw->fw); + if (ret) + return ret; + + return falcon ? nvkm_falcon_fw_oneinit(fw, falcon, NULL, NULL) : 0; +} + +int +nvkm_falcon_fw_ctor_hs(const struct nvkm_falcon_fw_func *func, const char *name, + struct nvkm_subdev *subdev, const char *bl, const char *img, int ver, + struct nvkm_falcon *falcon, struct nvkm_falcon_fw *fw) +{ + const struct firmware *blob; + const struct nvfw_bin_hdr *hdr; + const struct nvfw_hs_header *hshdr; + const struct nvfw_hs_load_header *lhdr; + const struct nvfw_bl_desc *desc; + u32 loc, sig; + int ret; + + ret = nvkm_firmware_load_name(subdev, img, "", ver, &blob); + if (ret) + return ret; + + hdr = nvfw_bin_hdr(subdev, blob->data); + hshdr = nvfw_hs_header(subdev, blob->data + hdr->header_offset); + + ret = nvkm_falcon_fw_ctor(func, name, subdev->device, bl != NULL, + blob->data + hdr->data_offset, hdr->data_size, falcon, fw); + if (ret) + goto done; + + /* 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 *)(blob->data + hshdr->patch_loc); + sig = *(u32 *)(blob->data + hshdr->patch_sig); + break; + case 0x3b1d14f0: + loc = hshdr->patch_loc; + sig = hshdr->patch_sig; + break; + default: + WARN_ON(1); + ret = -EINVAL; + goto done; + } + + ret = nvkm_falcon_fw_sign(fw, loc, hshdr->sig_prod_size, blob->data, + 1, hshdr->sig_prod_offset + sig, + 1, hshdr->sig_dbg_offset + sig); + if (ret) + goto done; + + lhdr = nvfw_hs_load_header(subdev, blob->data + hshdr->hdr_offset); + + fw->nmem_base_img = 0; + fw->nmem_base = lhdr->non_sec_code_off; + fw->nmem_size = lhdr->non_sec_code_size; + + fw->imem_base_img = lhdr->apps[0]; + fw->imem_base = ALIGN(lhdr->apps[0], 0x100); + fw->imem_size = lhdr->apps[lhdr->num_apps + 0]; + + fw->dmem_base_img = lhdr->data_dma_base; + fw->dmem_base = 0; + fw->dmem_size = lhdr->data_size; + fw->dmem_sign = loc - lhdr->data_dma_base; + + if (bl) { + nvkm_firmware_put(blob); + + ret = nvkm_firmware_load_name(subdev, bl, "", ver, &blob); + if (ret) + return ret; + + hdr = nvfw_bin_hdr(subdev, blob->data); + desc = nvfw_bl_desc(subdev, blob->data + hdr->header_offset); + + fw->boot_addr = desc->start_tag << 8; + fw->boot_size = desc->code_size; + fw->boot = kmemdup(blob->data + hdr->data_offset + desc->code_off, + fw->boot_size, GFP_KERNEL); + if (!fw->boot) + ret = -ENOMEM; + } else { + fw->boot_addr = fw->nmem_base; + } + +done: + if (ret) + nvkm_falcon_fw_dtor(fw); + + nvkm_firmware_put(blob); + return ret; +} + +int +nvkm_falcon_fw_ctor_hs_v2(const struct nvkm_falcon_fw_func *func, const char *name, + struct nvkm_subdev *subdev, const char *img, int ver, + struct nvkm_falcon *falcon, struct nvkm_falcon_fw *fw) +{ + const struct nvfw_bin_hdr *hdr; + const struct nvfw_hs_header_v2 *hshdr; + const struct nvfw_hs_load_header_v2 *lhdr; + const struct firmware *blob; + u32 loc, sig, cnt, *meta; + int ret; + + ret = nvkm_firmware_load_name(subdev, img, "", ver, &blob); + if (ret) + return ret; + + hdr = nvfw_bin_hdr(subdev, blob->data); + hshdr = nvfw_hs_header_v2(subdev, blob->data + hdr->header_offset); + meta = (u32 *)(blob->data + hshdr->meta_data_offset); + loc = *(u32 *)(blob->data + hshdr->patch_loc); + sig = *(u32 *)(blob->data + hshdr->patch_sig); + cnt = *(u32 *)(blob->data + hshdr->num_sig); + + ret = nvkm_falcon_fw_ctor(func, name, subdev->device, true, + blob->data + hdr->data_offset, hdr->data_size, falcon, fw); + if (ret) + goto done; + + ret = nvkm_falcon_fw_sign(fw, loc, hshdr->sig_prod_size / cnt, blob->data, + cnt, hshdr->sig_prod_offset + sig, 0, 0); + if (ret) + goto done; + + lhdr = nvfw_hs_load_header_v2(subdev, blob->data + hshdr->header_offset); + + fw->imem_base_img = lhdr->app[0].offset; + fw->imem_base = 0; + fw->imem_size = lhdr->app[0].size; + + fw->dmem_base_img = lhdr->os_data_offset; + fw->dmem_base = 0; + fw->dmem_size = lhdr->os_data_size; + fw->dmem_sign = loc - lhdr->os_data_offset; + + fw->boot_addr = lhdr->app[0].offset; + + fw->fuse_ver = meta[0]; + fw->engine_id = meta[1]; + fw->ucode_id = meta[2]; + +done: + if (ret) + nvkm_falcon_fw_dtor(fw); + + nvkm_firmware_put(blob); + return ret; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/ga100.c b/drivers/gpu/drm/nouveau/nvkm/falcon/ga100.c new file mode 100644 index 000000000000..49fd32943916 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/falcon/ga100.c @@ -0,0 +1,62 @@ +/* + * 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" + +int +ga100_flcn_fw_signature(struct nvkm_falcon_fw *fw, u32 *src_base_src) +{ + struct nvkm_falcon *falcon = fw->falcon; + struct nvkm_device *device = falcon->owner->device; + u32 reg_fuse_version; + int idx; + + FLCN_DBG(falcon, "brom: %08x %08x", fw->engine_id, fw->ucode_id); + FLCN_DBG(falcon, "fuse_version: %d", fw->fuse_ver); + + if (fw->engine_id & 0x00000001) { + reg_fuse_version = nvkm_rd32(device, 0x824140 + (fw->ucode_id - 1) * 4); + } else + if (fw->engine_id & 0x00000004) { + reg_fuse_version = nvkm_rd32(device, 0x824100 + (fw->ucode_id - 1) * 4); + } else + if (fw->engine_id & 0x00000400) { + reg_fuse_version = nvkm_rd32(device, 0x8241c0 + (fw->ucode_id - 1) * 4); + } else { + WARN_ON(1); + return -ENOSYS; + } + + FLCN_DBG(falcon, "reg_fuse_version: %08x", reg_fuse_version); + if (reg_fuse_version) { + reg_fuse_version = fls(reg_fuse_version); + FLCN_DBG(falcon, "reg_fuse_version: %d", reg_fuse_version); + + if (WARN_ON(fw->fuse_ver < reg_fuse_version)) + return -EINVAL; + + idx = fw->fuse_ver - reg_fuse_version; + } else { + idx = fw->sig_nr - 1; + } + + return idx; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/ga102.c b/drivers/gpu/drm/nouveau/nvkm/falcon/ga102.c new file mode 100644 index 000000000000..0ff450fe3590 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/falcon/ga102.c @@ -0,0 +1,148 @@ +/* + * 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" + +#include <subdev/mc.h> +#include <subdev/timer.h> + +static bool +ga102_flcn_dma_done(struct nvkm_falcon *falcon) +{ + return !!(nvkm_falcon_rd32(falcon, 0x118) & 0x00000002); +} + +static void +ga102_flcn_dma_xfer(struct nvkm_falcon *falcon, u32 mem_base, u32 dma_base, u32 cmd) +{ + nvkm_falcon_wr32(falcon, 0x114, mem_base); + nvkm_falcon_wr32(falcon, 0x11c, dma_base); + nvkm_falcon_wr32(falcon, 0x118, cmd); +} + +static int +ga102_flcn_dma_init(struct nvkm_falcon *falcon, u64 dma_addr, int xfer_len, + enum nvkm_falcon_mem mem_type, bool sec, u32 *cmd) +{ + *cmd = (ilog2(xfer_len) - 2) << 8; + if (mem_type == IMEM) + *cmd |= 0x00000010; + if (sec) + *cmd |= 0x00000004; + + nvkm_falcon_wr32(falcon, 0x110, dma_addr >> 8); + nvkm_falcon_wr32(falcon, 0x128, 0x00000000); + return 0; +} + +const struct nvkm_falcon_func_dma +ga102_flcn_dma = { + .init = ga102_flcn_dma_init, + .xfer = ga102_flcn_dma_xfer, + .done = ga102_flcn_dma_done, +}; + +int +ga102_flcn_reset_wait_mem_scrubbing(struct nvkm_falcon *falcon) +{ + nvkm_falcon_mask(falcon, 0x040, 0x00000000, 0x00000000); + + if (nvkm_msec(falcon->owner->device, 20, + if (!(nvkm_falcon_rd32(falcon, 0x0f4) & 0x00001000)) + break; + ) < 0) + return -ETIMEDOUT; + + return 0; +} + +int +ga102_flcn_reset_prep(struct nvkm_falcon *falcon) +{ + nvkm_falcon_rd32(falcon, 0x0f4); + + nvkm_usec(falcon->owner->device, 150, + if (nvkm_falcon_rd32(falcon, 0x0f4) & 0x80000000) + break; + _warn = false; + ); + + return 0; +} + +int +ga102_flcn_select(struct nvkm_falcon *falcon) +{ + if ((nvkm_falcon_rd32(falcon, falcon->addr2 + 0x668) & 0x00000010) != 0x00000000) { + nvkm_falcon_wr32(falcon, falcon->addr2 + 0x668, 0x00000000); + if (nvkm_msec(falcon->owner->device, 10, + if (nvkm_falcon_rd32(falcon, falcon->addr2 + 0x668) & 0x00000001) + break; + ) < 0) + return -ETIMEDOUT; + } + + return 0; +} + +int +ga102_flcn_fw_boot(struct nvkm_falcon_fw *fw, u32 *mbox0, u32 *mbox1, u32 mbox0_ok, u32 irqsclr) +{ + struct nvkm_falcon *falcon = fw->falcon; + + nvkm_falcon_wr32(falcon, falcon->addr2 + 0x210, fw->dmem_sign); + nvkm_falcon_wr32(falcon, falcon->addr2 + 0x19c, fw->engine_id); + nvkm_falcon_wr32(falcon, falcon->addr2 + 0x198, fw->ucode_id); + nvkm_falcon_wr32(falcon, falcon->addr2 + 0x180, 0x00000001); + + return gm200_flcn_fw_boot(fw, mbox0, mbox1, mbox0_ok, irqsclr); +} + +int +ga102_flcn_fw_load(struct nvkm_falcon_fw *fw) +{ + struct nvkm_falcon *falcon = fw->falcon; + int ret = 0; + + nvkm_falcon_mask(falcon, 0x624, 0x00000080, 0x00000080); + nvkm_falcon_wr32(falcon, 0x10c, 0x00000000); + nvkm_falcon_mask(falcon, 0x600, 0x00010007, (0 << 16) | (1 << 2) | 1); + + ret = nvkm_falcon_dma_wr(falcon, fw->fw.img, fw->fw.phys, fw->imem_base_img, + IMEM, fw->imem_base, fw->imem_size, true); + if (ret) + return ret; + + ret = nvkm_falcon_dma_wr(falcon, fw->fw.img, fw->fw.phys, fw->dmem_base_img, + DMEM, fw->dmem_base, fw->dmem_size, false); + if (ret) + return ret; + + return 0; +} + +const struct nvkm_falcon_fw_func +ga102_flcn_fw = { + .signature = ga100_flcn_fw_signature, + .reset = gm200_flcn_fw_reset, + .load = ga102_flcn_fw_load, + .boot = ga102_flcn_fw_boot, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/gm200.c b/drivers/gpu/drm/nouveau/nvkm/falcon/gm200.c new file mode 100644 index 000000000000..393ade9f7e6c --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/falcon/gm200.c @@ -0,0 +1,345 @@ +/* + * 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" + +#include <core/memory.h> +#include <subdev/mc.h> +#include <subdev/timer.h> + +void +gm200_flcn_tracepc(struct nvkm_falcon *falcon) +{ + u32 sctl = nvkm_falcon_rd32(falcon, 0x240); + u32 tidx = nvkm_falcon_rd32(falcon, 0x148); + int nr = (tidx & 0x00ff0000) >> 16, sp, ip; + + FLCN_ERR(falcon, "TRACEPC SCTL %08x TIDX %08x", sctl, tidx); + for (sp = 0; sp < nr; sp++) { + nvkm_falcon_wr32(falcon, 0x148, sp); + ip = nvkm_falcon_rd32(falcon, 0x14c); + FLCN_ERR(falcon, "TRACEPC: %08x", ip); + } +} + +static void +gm200_flcn_pio_dmem_rd(struct nvkm_falcon *falcon, u8 port, const u8 *img, int len) +{ + while (len >= 4) { + *(u32 *)img = nvkm_falcon_rd32(falcon, 0x1c4 + (port * 8)); + img += 4; + len -= 4; + } +} + +static void +gm200_flcn_pio_dmem_rd_init(struct nvkm_falcon *falcon, u8 port, u32 dmem_base) +{ + nvkm_falcon_wr32(falcon, 0x1c0 + (port * 8), BIT(25) | dmem_base); +} + +static void +gm200_flcn_pio_dmem_wr(struct nvkm_falcon *falcon, u8 port, const u8 *img, int len, u16 tag) +{ + while (len >= 4) { + nvkm_falcon_wr32(falcon, 0x1c4 + (port * 8), *(u32 *)img); + img += 4; + len -= 4; + } +} + +static void +gm200_flcn_pio_dmem_wr_init(struct nvkm_falcon *falcon, u8 port, bool sec, u32 dmem_base) +{ + nvkm_falcon_wr32(falcon, 0x1c0 + (port * 8), BIT(24) | dmem_base); +} + +const struct nvkm_falcon_func_pio +gm200_flcn_dmem_pio = { + .min = 4, + .max = 0x100, + .wr_init = gm200_flcn_pio_dmem_wr_init, + .wr = gm200_flcn_pio_dmem_wr, + .rd_init = gm200_flcn_pio_dmem_rd_init, + .rd = gm200_flcn_pio_dmem_rd, +}; + +static void +gm200_flcn_pio_imem_wr_init(struct nvkm_falcon *falcon, u8 port, bool sec, u32 imem_base) +{ + nvkm_falcon_wr32(falcon, 0x180 + (port * 0x10), (sec ? BIT(28) : 0) | BIT(24) | imem_base); +} + +static void +gm200_flcn_pio_imem_wr(struct nvkm_falcon *falcon, u8 port, const u8 *img, int len, u16 tag) +{ + nvkm_falcon_wr32(falcon, 0x188 + (port * 0x10), tag++); + while (len >= 4) { + nvkm_falcon_wr32(falcon, 0x184 + (port * 0x10), *(u32 *)img); + img += 4; + len -= 4; + } +} + +const struct nvkm_falcon_func_pio +gm200_flcn_imem_pio = { + .min = 0x100, + .max = 0x100, + .wr_init = gm200_flcn_pio_imem_wr_init, + .wr = gm200_flcn_pio_imem_wr, +}; + +int +gm200_flcn_bind_stat(struct nvkm_falcon *falcon, bool intr) +{ + if (intr && !(nvkm_falcon_rd32(falcon, 0x008) & 0x00000008)) + return -1; + + return (nvkm_falcon_rd32(falcon, 0x0dc) & 0x00007000) >> 12; +} + +void +gm200_flcn_bind_inst(struct nvkm_falcon *falcon, int target, u64 addr) +{ + nvkm_falcon_mask(falcon, 0x604, 0x00000007, 0x00000000); /* DMAIDX_VIRT */ + nvkm_falcon_wr32(falcon, 0x054, (1 << 30) | (target << 28) | (addr >> 12)); + nvkm_falcon_mask(falcon, 0x090, 0x00010000, 0x00010000); + nvkm_falcon_mask(falcon, 0x0a4, 0x00000008, 0x00000008); +} + +int +gm200_flcn_reset_wait_mem_scrubbing(struct nvkm_falcon *falcon) +{ + nvkm_falcon_mask(falcon, 0x040, 0x00000000, 0x00000000); + + if (nvkm_msec(falcon->owner->device, 10, + if (!(nvkm_falcon_rd32(falcon, 0x10c) & 0x00000006)) + break; + ) < 0) + return -ETIMEDOUT; + + return 0; +} + +int +gm200_flcn_enable(struct nvkm_falcon *falcon) +{ + struct nvkm_device *device = falcon->owner->device; + int ret; + + if (falcon->func->reset_eng) { + ret = falcon->func->reset_eng(falcon); + if (ret) + return ret; + } + + if (falcon->func->select) { + ret = falcon->func->select(falcon); + if (ret) + return ret; + } + + if (falcon->func->reset_pmc) + nvkm_mc_enable(device, falcon->owner->type, falcon->owner->inst); + + ret = falcon->func->reset_wait_mem_scrubbing(falcon); + if (ret) + return ret; + + nvkm_falcon_wr32(falcon, 0x084, nvkm_rd32(device, 0x000000)); + return 0; +} + +int +gm200_flcn_disable(struct nvkm_falcon *falcon) +{ + struct nvkm_device *device = falcon->owner->device; + int ret; + + if (falcon->func->select) { + ret = falcon->func->select(falcon); + if (ret) + return ret; + } + + nvkm_falcon_mask(falcon, 0x048, 0x00000003, 0x00000000); + nvkm_falcon_wr32(falcon, 0x014, 0xffffffff); + + if (falcon->func->reset_pmc) { + if (falcon->func->reset_prep) { + ret = falcon->func->reset_prep(falcon); + if (ret) + return ret; + } + + nvkm_mc_disable(device, falcon->owner->type, falcon->owner->inst); + } + + if (falcon->func->reset_eng) { + ret = falcon->func->reset_eng(falcon); + if (ret) + return ret; + } + + return 0; +} + +int +gm200_flcn_fw_boot(struct nvkm_falcon_fw *fw, u32 *pmbox0, u32 *pmbox1, u32 mbox0_ok, u32 irqsclr) +{ + struct nvkm_falcon *falcon = fw->falcon; + u32 mbox0, mbox1; + int ret = 0; + + nvkm_falcon_wr32(falcon, 0x040, pmbox0 ? *pmbox0 : 0xcafebeef); + if (pmbox1) + nvkm_falcon_wr32(falcon, 0x044, *pmbox1); + + nvkm_falcon_wr32(falcon, 0x104, fw->boot_addr); + nvkm_falcon_wr32(falcon, 0x100, 0x00000002); + + if (nvkm_msec(falcon->owner->device, 2000, + if (nvkm_falcon_rd32(falcon, 0x100) & 0x00000010) + break; + ) < 0) + ret = -ETIMEDOUT; + + mbox0 = nvkm_falcon_rd32(falcon, 0x040); + mbox1 = nvkm_falcon_rd32(falcon, 0x044); + if (FLCN_ERRON(falcon, ret || mbox0 != mbox0_ok, "mbox %08x %08x", mbox0, mbox1)) + ret = ret ?: -EIO; + + if (irqsclr) + nvkm_falcon_mask(falcon, 0x004, 0xffffffff, irqsclr); + + return ret; +} + +int +gm200_flcn_fw_load(struct nvkm_falcon_fw *fw) +{ + struct nvkm_falcon *falcon = fw->falcon; + int target, ret; + + if (fw->inst) { + nvkm_falcon_mask(falcon, 0x048, 0x00000001, 0x00000001); + + switch (nvkm_memory_target(fw->inst)) { + case NVKM_MEM_TARGET_VRAM: target = 0; break; + case NVKM_MEM_TARGET_HOST: target = 2; break; + case NVKM_MEM_TARGET_NCOH: target = 3; break; + default: + WARN_ON(1); + return -EINVAL; + } + + falcon->func->bind_inst(falcon, target, nvkm_memory_addr(fw->inst)); + + if (nvkm_msec(falcon->owner->device, 10, + if (falcon->func->bind_stat(falcon, falcon->func->bind_intr) == 5) + break; + ) < 0) + return -ETIMEDOUT; + + nvkm_falcon_mask(falcon, 0x004, 0x00000008, 0x00000008); + nvkm_falcon_mask(falcon, 0x058, 0x00000002, 0x00000002); + + if (nvkm_msec(falcon->owner->device, 10, + if (falcon->func->bind_stat(falcon, false) == 0) + break; + ) < 0) + return -ETIMEDOUT; + } else { + nvkm_falcon_mask(falcon, 0x624, 0x00000080, 0x00000080); + nvkm_falcon_wr32(falcon, 0x10c, 0x00000000); + } + + if (fw->boot) { + switch (nvkm_memory_target(&fw->fw.mem.memory)) { + case NVKM_MEM_TARGET_VRAM: target = 4; break; + case NVKM_MEM_TARGET_HOST: target = 5; break; + case NVKM_MEM_TARGET_NCOH: target = 6; break; + default: + WARN_ON(1); + return -EINVAL; + } + + ret = nvkm_falcon_pio_wr(falcon, fw->boot, 0, 0, + IMEM, falcon->code.limit - fw->boot_size, fw->boot_size, + fw->boot_addr >> 8, false); + if (ret) + return ret; + + return fw->func->load_bld(fw); + } + + ret = nvkm_falcon_pio_wr(falcon, fw->fw.img + fw->nmem_base_img, fw->nmem_base_img, 0, + IMEM, fw->nmem_base, fw->nmem_size, fw->nmem_base >> 8, false); + if (ret) + return ret; + + ret = nvkm_falcon_pio_wr(falcon, fw->fw.img + fw->imem_base_img, fw->imem_base_img, 0, + IMEM, fw->imem_base, fw->imem_size, fw->imem_base >> 8, true); + if (ret) + return ret; + + ret = nvkm_falcon_pio_wr(falcon, fw->fw.img + fw->dmem_base_img, fw->dmem_base_img, 0, + DMEM, fw->dmem_base, fw->dmem_size, 0, false); + if (ret) + return ret; + + return 0; +} + +int +gm200_flcn_fw_reset(struct nvkm_falcon_fw *fw) +{ + return nvkm_falcon_reset(fw->falcon); +} + +int +gm200_flcn_fw_signature(struct nvkm_falcon_fw *fw, u32 *sig_base_src) +{ + struct nvkm_falcon *falcon = fw->falcon; + u32 addr = falcon->func->debug; + int ret = 0; + + if (addr) { + ret = nvkm_falcon_enable(falcon); + if (ret) + return ret; + + if (nvkm_falcon_rd32(falcon, addr) & 0x00100000) { + *sig_base_src = fw->sig_base_dbg; + return 1; + } + } + + return ret; +} + +const struct nvkm_falcon_fw_func +gm200_flcn_fw = { + .signature = gm200_flcn_fw_signature, + .reset = gm200_flcn_fw_reset, + .load = gm200_flcn_fw_load, + .boot = gm200_flcn_fw_boot, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/gp102.c b/drivers/gpu/drm/nouveau/nvkm/falcon/gp102.c new file mode 100644 index 000000000000..c774935f3077 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/falcon/gp102.c @@ -0,0 +1,82 @@ +/* + * 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" + +static void +gp102_flcn_pio_emem_rd(struct nvkm_falcon *falcon, u8 port, const u8 *img, int len) +{ + while (len >= 4) { + *(u32 *)img = nvkm_falcon_rd32(falcon, 0xac4 + (port * 8)); + img += 4; + len -= 4; + } +} + +static void +gp102_flcn_pio_emem_rd_init(struct nvkm_falcon *falcon, u8 port, u32 dmem_base) +{ + nvkm_falcon_wr32(falcon, 0xac0 + (port * 8), BIT(25) | dmem_base); +} + +static void +gp102_flcn_pio_emem_wr(struct nvkm_falcon *falcon, u8 port, const u8 *img, int len, u16 tag) +{ + while (len >= 4) { + nvkm_falcon_wr32(falcon, 0xac4 + (port * 8), *(u32 *)img); + img += 4; + len -= 4; + } +} + +static void +gp102_flcn_pio_emem_wr_init(struct nvkm_falcon *falcon, u8 port, bool sec, u32 emem_base) +{ + nvkm_falcon_wr32(falcon, 0xac0 + (port * 8), BIT(24) | emem_base); +} + +const struct nvkm_falcon_func_pio +gp102_flcn_emem_pio = { + .min = 4, + .max = 0x100, + .wr_init = gp102_flcn_pio_emem_wr_init, + .wr = gp102_flcn_pio_emem_wr, + .rd_init = gp102_flcn_pio_emem_rd_init, + .rd = gp102_flcn_pio_emem_rd, +}; + +int +gp102_flcn_reset_eng(struct nvkm_falcon *falcon) +{ + int ret; + + if (falcon->func->reset_prep) { + ret = falcon->func->reset_prep(falcon); + if (ret) + return ret; + } + + nvkm_falcon_mask(falcon, 0x3c0, 0x00000001, 0x00000001); + udelay(10); + nvkm_falcon_mask(falcon, 0x3c0, 0x00000001, 0x00000000); + + return falcon->func->reset_wait_mem_scrubbing(falcon); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/msgq.c b/drivers/gpu/drm/nouveau/nvkm/falcon/msgq.c index e74371dffc76..16b246fda666 100644 --- a/drivers/gpu/drm/nouveau/nvkm/falcon/msgq.c +++ b/drivers/gpu/drm/nouveau/nvkm/falcon/msgq.c @@ -25,7 +25,7 @@ static void nvkm_falcon_msgq_open(struct nvkm_falcon_msgq *msgq) { - mutex_lock(&msgq->mutex); + spin_lock(&msgq->lock); msgq->position = nvkm_falcon_rd32(msgq->qmgr->falcon, msgq->tail_reg); } @@ -37,10 +37,10 @@ nvkm_falcon_msgq_close(struct nvkm_falcon_msgq *msgq, bool commit) if (commit) nvkm_falcon_wr32(falcon, msgq->tail_reg, msgq->position); - mutex_unlock(&msgq->mutex); + spin_unlock(&msgq->lock); } -static bool +bool nvkm_falcon_msgq_empty(struct nvkm_falcon_msgq *msgq) { u32 head = nvkm_falcon_rd32(msgq->qmgr->falcon, msgq->head_reg); @@ -68,7 +68,7 @@ nvkm_falcon_msgq_pop(struct nvkm_falcon_msgq *msgq, void *data, u32 size) return -EINVAL; } - nvkm_falcon_read_dmem(falcon, tail, size, 0, data); + nvkm_falcon_pio_rd(falcon, 0, DMEM, tail, data, 0, size); msgq->position += ALIGN(size, QUEUE_ALIGNMENT); return 0; } @@ -208,6 +208,6 @@ nvkm_falcon_msgq_new(struct nvkm_falcon_qmgr *qmgr, const char *name, msgq->qmgr = qmgr; msgq->name = name; - mutex_init(&msgq->mutex); + spin_lock_init(&msgq->lock); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/priv.h b/drivers/gpu/drm/nouveau/nvkm/falcon/priv.h index 466188752eb0..11a24b9c8569 100644 --- a/drivers/gpu/drm/nouveau/nvkm/falcon/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/falcon/priv.h @@ -2,4 +2,12 @@ #ifndef __NVKM_FALCON_PRIV_H__ #define __NVKM_FALCON_PRIV_H__ #include <core/falcon.h> + +static inline int +nvkm_falcon_enable(struct nvkm_falcon *falcon) +{ + if (falcon->func->enable) + return falcon->func->enable(falcon); + return 0; +} #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/qmgr.h b/drivers/gpu/drm/nouveau/nvkm/falcon/qmgr.h index 976cb7b7aa99..79f0da9e749f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/falcon/qmgr.h +++ b/drivers/gpu/drm/nouveau/nvkm/falcon/qmgr.h @@ -73,7 +73,7 @@ struct nvkm_falcon_cmdq { struct nvkm_falcon_msgq { struct nvkm_falcon_qmgr *qmgr; const char *name; - struct mutex mutex; + spinlock_t lock; u32 head_reg; u32 tail_reg; @@ -82,8 +82,7 @@ struct nvkm_falcon_msgq { u32 position; }; -#define FLCNQ_PRINTK(t,q,f,a...) \ - FLCN_PRINTK(t, (q)->qmgr->falcon, "%s: "f, (q)->name, ##a) -#define FLCNQ_DBG(q,f,a...) FLCNQ_PRINTK(debug, (q), f, ##a) -#define FLCNQ_ERR(q,f,a...) FLCNQ_PRINTK(error, (q), f, ##a) +#define FLCNQ_PRINTK(q,l,p,f,a...) FLCN_PRINTK((q)->qmgr->falcon, l, p, "%s: "f, (q)->name, ##a) +#define FLCNQ_DBG(q,f,a...) FLCNQ_PRINTK((q), DEBUG, info, f, ##a) +#define FLCNQ_ERR(q,f,a...) FLCNQ_PRINTK((q), ERROR, err, f, ##a) #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/v1.c b/drivers/gpu/drm/nouveau/nvkm/falcon/v1.c index b0ee4c31414c..dd2ddc54ac60 100644 --- a/drivers/gpu/drm/nouveau/nvkm/falcon/v1.c +++ b/drivers/gpu/drm/nouveau/nvkm/falcon/v1.c @@ -64,44 +64,13 @@ nvkm_falcon_v1_load_imem(struct nvkm_falcon *falcon, void *data, u32 start, nvkm_falcon_wr32(falcon, 0x184 + (port * 16), 0); } -static void -nvkm_falcon_v1_load_emem(struct nvkm_falcon *falcon, void *data, u32 start, - u32 size, u8 port) -{ - u8 rem = size % 4; - int i; - - size -= rem; - - nvkm_falcon_wr32(falcon, 0xac0 + (port * 8), start | (0x1 << 24)); - for (i = 0; i < size / 4; i++) - nvkm_falcon_wr32(falcon, 0xac4 + (port * 8), ((u32 *)data)[i]); - - /* - * If size is not a multiple of 4, mask the last word to ensure garbage - * does not get written - */ - if (rem) { - u32 extra = ((u32 *)data)[i]; - - nvkm_falcon_wr32(falcon, 0xac4 + (port * 8), - extra & (BIT(rem * 8) - 1)); - } -} - void nvkm_falcon_v1_load_dmem(struct nvkm_falcon *falcon, void *data, u32 start, u32 size, u8 port) { - const struct nvkm_falcon_func *func = falcon->func; u8 rem = size % 4; int i; - if (func->emem_addr && start >= func->emem_addr) - return nvkm_falcon_v1_load_emem(falcon, data, - start - func->emem_addr, size, - port); - size -= rem; nvkm_falcon_wr32(falcon, 0x1c0 + (port * 8), start | (0x1 << 24)); @@ -120,113 +89,6 @@ nvkm_falcon_v1_load_dmem(struct nvkm_falcon *falcon, void *data, u32 start, } } -static void -nvkm_falcon_v1_read_emem(struct nvkm_falcon *falcon, u32 start, u32 size, - u8 port, void *data) -{ - u8 rem = size % 4; - int i; - - size -= rem; - - nvkm_falcon_wr32(falcon, 0xac0 + (port * 8), start | (0x1 << 25)); - for (i = 0; i < size / 4; i++) - ((u32 *)data)[i] = nvkm_falcon_rd32(falcon, 0xac4 + (port * 8)); - - /* - * If size is not a multiple of 4, mask the last word to ensure garbage - * does not get read - */ - if (rem) { - u32 extra = nvkm_falcon_rd32(falcon, 0xac4 + (port * 8)); - - for (i = size; i < size + rem; i++) { - ((u8 *)data)[i] = (u8)(extra & 0xff); - extra >>= 8; - } - } -} - -void -nvkm_falcon_v1_read_dmem(struct nvkm_falcon *falcon, u32 start, u32 size, - u8 port, void *data) -{ - const struct nvkm_falcon_func *func = falcon->func; - u8 rem = size % 4; - int i; - - if (func->emem_addr && start >= func->emem_addr) - return nvkm_falcon_v1_read_emem(falcon, start - func->emem_addr, - size, port, data); - - size -= rem; - - nvkm_falcon_wr32(falcon, 0x1c0 + (port * 8), start | (0x1 << 25)); - for (i = 0; i < size / 4; i++) - ((u32 *)data)[i] = nvkm_falcon_rd32(falcon, 0x1c4 + (port * 8)); - - /* - * If size is not a multiple of 4, mask the last word to ensure garbage - * does not get read - */ - if (rem) { - u32 extra = nvkm_falcon_rd32(falcon, 0x1c4 + (port * 8)); - - for (i = size; i < size + rem; i++) { - ((u8 *)data)[i] = (u8)(extra & 0xff); - extra >>= 8; - } - } -} - -void -nvkm_falcon_v1_bind_context(struct nvkm_falcon *falcon, struct nvkm_memory *ctx) -{ - const u32 fbif = falcon->func->fbif; - u32 inst_loc; - - /* disable instance block binding */ - if (ctx == NULL) { - nvkm_falcon_wr32(falcon, 0x10c, 0x0); - return; - } - - nvkm_falcon_wr32(falcon, 0x10c, 0x1); - - /* setup apertures - virtual */ - nvkm_falcon_wr32(falcon, fbif + 4 * FALCON_DMAIDX_UCODE, 0x4); - nvkm_falcon_wr32(falcon, fbif + 4 * FALCON_DMAIDX_VIRT, 0x0); - /* setup apertures - physical */ - nvkm_falcon_wr32(falcon, fbif + 4 * FALCON_DMAIDX_PHYS_VID, 0x4); - nvkm_falcon_wr32(falcon, fbif + 4 * FALCON_DMAIDX_PHYS_SYS_COH, 0x5); - nvkm_falcon_wr32(falcon, fbif + 4 * FALCON_DMAIDX_PHYS_SYS_NCOH, 0x6); - - /* Set context */ - switch (nvkm_memory_target(ctx)) { - case NVKM_MEM_TARGET_VRAM: inst_loc = 0; break; - case NVKM_MEM_TARGET_HOST: inst_loc = 2; break; - case NVKM_MEM_TARGET_NCOH: inst_loc = 3; break; - default: - WARN_ON(1); - return; - } - - /* Enable context */ - nvkm_falcon_mask(falcon, 0x048, 0x1, 0x1); - nvkm_falcon_wr32(falcon, 0x054, - ((nvkm_memory_addr(ctx) >> 12) & 0xfffffff) | - (inst_loc << 28) | (1 << 30)); - - nvkm_falcon_mask(falcon, 0x090, 0x10000, 0x10000); - nvkm_falcon_mask(falcon, 0x0a4, 0x8, 0x8); -} - -void -nvkm_falcon_v1_set_start_addr(struct nvkm_falcon *falcon, u32 start_addr) -{ - nvkm_falcon_wr32(falcon, 0x104, start_addr); -} - void nvkm_falcon_v1_start(struct nvkm_falcon *falcon) { @@ -237,75 +99,3 @@ nvkm_falcon_v1_start(struct nvkm_falcon *falcon) else nvkm_falcon_wr32(falcon, 0x100, 0x2); } - -int -nvkm_falcon_v1_wait_for_halt(struct nvkm_falcon *falcon, u32 ms) -{ - struct nvkm_device *device = falcon->owner->device; - int ret; - - ret = nvkm_wait_msec(device, ms, falcon->addr + 0x100, 0x10, 0x10); - if (ret < 0) - return ret; - - return 0; -} - -int -nvkm_falcon_v1_clear_interrupt(struct nvkm_falcon *falcon, u32 mask) -{ - struct nvkm_device *device = falcon->owner->device; - int ret; - - /* clear interrupt(s) */ - nvkm_falcon_mask(falcon, 0x004, mask, mask); - /* wait until interrupts are cleared */ - ret = nvkm_wait_msec(device, 10, falcon->addr + 0x008, mask, 0x0); - if (ret < 0) - return ret; - - return 0; -} - -static int -falcon_v1_wait_idle(struct nvkm_falcon *falcon) -{ - struct nvkm_device *device = falcon->owner->device; - int ret; - - ret = nvkm_wait_msec(device, 10, falcon->addr + 0x04c, 0xffff, 0x0); - if (ret < 0) - return ret; - - return 0; -} - -int -nvkm_falcon_v1_enable(struct nvkm_falcon *falcon) -{ - struct nvkm_device *device = falcon->owner->device; - int ret; - - ret = nvkm_wait_msec(device, 10, falcon->addr + 0x10c, 0x6, 0x0); - if (ret < 0) { - nvkm_error(falcon->user, "Falcon mem scrubbing timeout\n"); - return ret; - } - - ret = falcon_v1_wait_idle(falcon); - if (ret) - return ret; - - /* enable IRQs */ - nvkm_falcon_wr32(falcon, 0x010, 0xff); - - return 0; -} - -void -nvkm_falcon_v1_disable(struct nvkm_falcon *falcon) -{ - /* disable IRQs and wait for any previous code to complete */ - nvkm_falcon_wr32(falcon, 0x014, 0xff); - falcon_v1_wait_idle(falcon); -} diff --git a/drivers/gpu/drm/nouveau/nvkm/nvfw/acr.c b/drivers/gpu/drm/nouveau/nvkm/nvfw/acr.c index bef790ad8f2f..83a9c48bc58c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/nvfw/acr.c +++ b/drivers/gpu/drm/nouveau/nvkm/nvfw/acr.c @@ -45,6 +45,47 @@ wpr_header_v1_dump(struct nvkm_subdev *subdev, const struct wpr_header_v1 *hdr) nvkm_debug(subdev, "\tstatus : %d\n", hdr->status); } +void +wpr_generic_header_dump(struct nvkm_subdev *subdev, const struct wpr_generic_header *hdr) +{ + nvkm_debug(subdev, "wprGenericHeader\n"); + nvkm_debug(subdev, "\tidentifier : %04x\n", hdr->identifier); + nvkm_debug(subdev, "\tversion : %04x\n", hdr->version); + nvkm_debug(subdev, "\tsize : %08x\n", hdr->size); +} + +void +wpr_header_v2_dump(struct nvkm_subdev *subdev, const struct wpr_header_v2 *hdr) +{ + wpr_generic_header_dump(subdev, &hdr->hdr); + wpr_header_v1_dump(subdev, &hdr->wpr); +} + +void +lsb_header_v2_dump(struct nvkm_subdev *subdev, struct lsb_header_v2 *hdr) +{ + wpr_generic_header_dump(subdev, &hdr->hdr); + nvkm_debug(subdev, "lsbHeader\n"); + nvkm_debug(subdev, "\tucodeOff : 0x%x\n", hdr->ucode_off); + nvkm_debug(subdev, "\tucodeSize : 0x%x\n", hdr->ucode_size); + nvkm_debug(subdev, "\tdataSize : 0x%x\n", hdr->data_size); + nvkm_debug(subdev, "\tblCodeSize : 0x%x\n", hdr->bl_code_size); + nvkm_debug(subdev, "\tblImemOff : 0x%x\n", hdr->bl_imem_off); + nvkm_debug(subdev, "\tblDataOff : 0x%x\n", hdr->bl_data_off); + nvkm_debug(subdev, "\tblDataSize : 0x%x\n", hdr->bl_data_size); + nvkm_debug(subdev, "\treserved0 : %08x\n", hdr->rsvd0); + nvkm_debug(subdev, "\tappCodeOff : 0x%x\n", hdr->app_code_off); + nvkm_debug(subdev, "\tappCodeSize : 0x%x\n", hdr->app_code_size); + nvkm_debug(subdev, "\tappDataOff : 0x%x\n", hdr->app_data_off); + nvkm_debug(subdev, "\tappDataSize : 0x%x\n", hdr->app_data_size); + nvkm_debug(subdev, "\tappImemOffset : 0x%x\n", hdr->app_imem_offset); + nvkm_debug(subdev, "\tappDmemOffset : 0x%x\n", hdr->app_dmem_offset); + nvkm_debug(subdev, "\tflags : 0x%x\n", hdr->flags); + nvkm_debug(subdev, "\tmonitorCodeOff: 0x%x\n", hdr->monitor_code_offset); + nvkm_debug(subdev, "\tmonitorDataOff: 0x%x\n", hdr->monitor_data_offset); + nvkm_debug(subdev, "\tmanifestOffset: 0x%x\n", hdr->manifest_offset); +} + static void lsb_header_tail_dump(struct nvkm_subdev *subdev, struct lsb_header_tail *hdr) { diff --git a/drivers/gpu/drm/nouveau/nvkm/nvfw/hs.c b/drivers/gpu/drm/nouveau/nvkm/nvfw/hs.c index 04ed77cb2eba..a7e0583401d0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/nvfw/hs.c +++ b/drivers/gpu/drm/nouveau/nvkm/nvfw/hs.c @@ -38,6 +38,24 @@ nvfw_hs_header(struct nvkm_subdev *subdev, const void *data) return hdr; } +const struct nvfw_hs_header_v2 * +nvfw_hs_header_v2(struct nvkm_subdev *subdev, const void *data) +{ + const struct nvfw_hs_header_v2 *hdr = data; + + nvkm_debug(subdev, "hsHeader:\n"); + nvkm_debug(subdev, "\tsigProdOffset : 0x%x\n", hdr->sig_prod_offset); + nvkm_debug(subdev, "\tsigProdSize : 0x%x\n", hdr->sig_prod_size); + nvkm_debug(subdev, "\tpatchLoc : 0x%x\n", hdr->patch_loc); + nvkm_debug(subdev, "\tpatchSig : 0x%x\n", hdr->patch_sig); + nvkm_debug(subdev, "\tmetadataOffset : 0x%x\n", hdr->meta_data_offset); + nvkm_debug(subdev, "\tmetadataSize : 0x%x\n", hdr->meta_data_size); + nvkm_debug(subdev, "\tnumSig : 0x%x\n", hdr->num_sig); + nvkm_debug(subdev, "\theaderOffset : 0x%x\n", hdr->header_offset); + nvkm_debug(subdev, "\theaderSize : 0x%x\n", hdr->header_size); + return hdr; +} + const struct nvfw_hs_load_header * nvfw_hs_load_header(struct nvkm_subdev *subdev, const void *data) { @@ -60,3 +78,24 @@ nvfw_hs_load_header(struct nvkm_subdev *subdev, const void *data) return hdr; } + +const struct nvfw_hs_load_header_v2 * +nvfw_hs_load_header_v2(struct nvkm_subdev *subdev, const void *data) +{ + const struct nvfw_hs_load_header_v2 *hdr = data; + int i; + + nvkm_debug(subdev, "hsLoadHeader:\n"); + nvkm_debug(subdev, "\tosCodeOffset : 0x%x\n", hdr->os_code_offset); + nvkm_debug(subdev, "\tosCodeSize : 0x%x\n", hdr->os_code_size); + nvkm_debug(subdev, "\tosDataOffset : 0x%x\n", hdr->os_data_offset); + nvkm_debug(subdev, "\tosDataSize : 0x%x\n", hdr->os_data_size); + nvkm_debug(subdev, "\tnumApps : 0x%x\n", hdr->num_apps); + for (i = 0; i < hdr->num_apps; i++) { + nvkm_debug(subdev, + "\tApp[%d] : offset 0x%x size 0x%x\n", i, + hdr->app[i].offset, hdr->app[i].size); + } + + return hdr; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/nvfw/ls.c b/drivers/gpu/drm/nouveau/nvkm/nvfw/ls.c index b847f281ce97..45c3a6c5e088 100644 --- a/drivers/gpu/drm/nouveau/nvkm/nvfw/ls.c +++ b/drivers/gpu/drm/nouveau/nvkm/nvfw/ls.c @@ -106,3 +106,75 @@ nvfw_ls_desc_v1(struct nvkm_subdev *subdev, const void *data) return hdr; } + +const struct nvfw_ls_desc_v2 * +nvfw_ls_desc_v2(struct nvkm_subdev *subdev, const void *data) +{ + const struct nvfw_ls_desc_v2 *hdr = data; + char *date; + int i; + + nvkm_debug(subdev, "lsUcodeImgDesc:\n"); + nvkm_debug(subdev, "\tdescriptorSize : %d\n", hdr->descriptor_size); + nvkm_debug(subdev, "\timageSize : %d\n", hdr->image_size); + nvkm_debug(subdev, "\ttoolsVersion : 0x%x\n", hdr->tools_version); + nvkm_debug(subdev, "\tappVersion : 0x%x\n", hdr->app_version); + + date = kstrndup(hdr->date, sizeof(hdr->date), GFP_KERNEL); + nvkm_debug(subdev, "\tdate : %s\n", date); + kfree(date); + + nvkm_debug(subdev, "\tsecureBootloader : 0x%x\n", hdr->secure_bootloader); + nvkm_debug(subdev, "\tbootloaderStartOffset: 0x%x\n", hdr->bootloader_start_offset); + nvkm_debug(subdev, "\tbootloaderSize : 0x%x\n", hdr->bootloader_size); + nvkm_debug(subdev, "\tbootloaderImemOffset : 0x%x\n", hdr->bootloader_imem_offset); + nvkm_debug(subdev, "\tbootloaderEntryPoint : 0x%x\n", hdr->bootloader_entry_point); + + nvkm_debug(subdev, "\tappStartOffset : 0x%x\n", hdr->app_start_offset); + nvkm_debug(subdev, "\tappSize : 0x%x\n", hdr->app_size); + nvkm_debug(subdev, "\tappImemOffset : 0x%x\n", hdr->app_imem_offset); + nvkm_debug(subdev, "\tappImemEntry : 0x%x\n", hdr->app_imem_entry); + nvkm_debug(subdev, "\tappDmemOffset : 0x%x\n", hdr->app_dmem_offset); + nvkm_debug(subdev, "\tappResidentCodeOffset: 0x%x\n", hdr->app_resident_code_offset); + nvkm_debug(subdev, "\tappResidentCodeSize : 0x%x\n", hdr->app_resident_code_size); + nvkm_debug(subdev, "\tappResidentDataOffset: 0x%x\n", hdr->app_resident_data_offset); + nvkm_debug(subdev, "\tappResidentDataSize : 0x%x\n", hdr->app_resident_data_size); + + nvkm_debug(subdev, "\tnbImemOverlays : %d\n", hdr->nb_imem_overlays); + nvkm_debug(subdev, "\tnbDmemOverlays : %d\n", hdr->nb_dmem_overlays); + for (i = 0; i < ARRAY_SIZE(hdr->load_ovl); i++) { + nvkm_debug(subdev, "\tloadOvl[%d] : 0x%x %d\n", i, + hdr->load_ovl[i].start, hdr->load_ovl[i].size); + } + + return hdr; +} + +const struct nvfw_ls_hsbl_bin_hdr * +nvfw_ls_hsbl_bin_hdr(struct nvkm_subdev *subdev, const void *data) +{ + const struct nvfw_ls_hsbl_bin_hdr *hdr = data; + + nvkm_debug(subdev, "lsHsblBinHdr:\n"); + nvkm_debug(subdev, "\tbinMagic : 0x%08x\n", hdr->bin_magic); + nvkm_debug(subdev, "\tbinVer : %d\n", hdr->bin_ver); + nvkm_debug(subdev, "\tbinSize : %d\n", hdr->bin_size); + nvkm_debug(subdev, "\theaderOffset : 0x%x\n", hdr->header_offset); + return hdr; +} + +const struct nvfw_ls_hsbl_hdr * +nvfw_ls_hsbl_hdr(struct nvkm_subdev *subdev, const void *data) +{ + const struct nvfw_ls_hsbl_hdr *hdr = data; + + nvkm_debug(subdev, "lsHsblHdr:\n"); + nvkm_debug(subdev, "\tsigProdOffset : 0x%x\n", hdr->sig_prod_offset); + nvkm_debug(subdev, "\tsigProdSize : 0x%x\n", hdr->sig_prod_size); + nvkm_debug(subdev, "\tpatchLoc : 0x%x\n", hdr->patch_loc); + nvkm_debug(subdev, "\tpatchSig : 0x%x\n", hdr->patch_sig); + nvkm_debug(subdev, "\tmetadataOffset : 0x%x\n", hdr->meta_data_offset); + nvkm_debug(subdev, "\tmetadataSize : 0x%x\n", hdr->meta_data_size); + nvkm_debug(subdev, "\tnumSig : 0x%x\n", hdr->num_sig); + return hdr; +} 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/engine/disp/rootnv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/base.c index 9acaec5c271e..62e81d551f44 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/base.c @@ -1,5 +1,5 @@ /* - * Copyright 2012 Red Hat Inc. + * 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"), @@ -18,45 +18,43 @@ * 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. - * - * Authors: Ben Skeggs */ #include "priv.h" -#include "head.h" -#include <core/client.h> +static void * +nvkm_vfn_dtor(struct nvkm_subdev *subdev) +{ + return nvkm_vfn(subdev); +} -#include <nvif/cl0046.h> -#include <nvif/unpack.h> +static const struct nvkm_subdev_func +nvkm_vfn = { + .dtor = nvkm_vfn_dtor, +}; int -nv04_disp_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) +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_disp *disp = nvkm_disp(object->engine); - union { - struct nv04_disp_mthd_v0 v0; - } *args = data; - struct nvkm_head *head; - int id, ret = -ENOSYS; + struct nvkm_vfn *vfn; + int ret; - nvif_ioctl(object, "disp mthd size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) { - nvif_ioctl(object, "disp mthd vers %d mthd %02x head %d\n", - args->v0.version, args->v0.method, args->v0.head); - mthd = args->v0.method; - id = args->v0.head; - } else - return ret; + if (!(vfn = *pvfn = kzalloc(sizeof(*vfn), GFP_KERNEL))) + return -ENOMEM; - if (!(head = nvkm_head_find(disp, id))) - return -ENXIO; + 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; - switch (mthd) { - case NV04_DISP_SCANOUTPOS: - return nvkm_head_mthd_scanoutpos(object, head, data, size); - default: - break; + if (vfn->func->intr) { + ret = nvkm_intr_add(vfn->func->intr, vfn->func->intrs, + &vfn->subdev, 8, &vfn->intr); + if (ret) + return ret; } - return -EINVAL; + 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/engine/fifo/usergv100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/gv100.c index 3dc3b8b312de..ddd39d714c4a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/usergv100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/gv100.c @@ -1,5 +1,5 @@ /* - * Copyright 2018 Red Hat Inc. + * 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"), @@ -19,27 +19,18 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ -#include "user.h" +#include "priv.h" -static int -gv100_fifo_user_map(struct nvkm_object *object, void *argv, u32 argc, - enum nvkm_object_map *type, u64 *addr, u64 *size) -{ - struct nvkm_device *device = object->engine->subdev.device; - *addr = 0x810000 + device->func->resource_addr(device, 0); - *size = 0x010000; - *type = NVKM_OBJECT_MAP_IO; - return 0; -} +#include <nvif/class.h> -static const struct nvkm_object_func -gv100_fifo_user = { - .map = gv100_fifo_user_map, +static const struct nvkm_vfn_func +gv100_vfn = { + .user = { 0x810000, 0x010000, { -1, -1, VOLTA_USERMODE_A } }, }; int -gv100_fifo_user_new(const struct nvkm_oclass *oclass, void *argv, u32 argc, - struct nvkm_object **pobject) +gv100_vfn_new(struct nvkm_device *device, + enum nvkm_subdev_type type, int inst, struct nvkm_vfn **pvfn) { - return nvkm_object_new_(&gv100_fifo_user, oclass, argv, argc, pobject); + 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; +} |