drm-misc-next for 6.19: UAPI Changes: - panfrost: Add PANFROST_BO_SYNC ioctl - panthor: Add PANTHOR_BO_SYNC ioctl Core Changes: - atomic: Add drm_device pointer to drm_private_obj - bridge: Introduce drm_bridge_unplug, drm_bridge_enter, and drm_bridge_exit - dma-buf: Improve sg_table debugging - dma-fence: Add new helpers, and use them when needed - dp_mst: Avoid out-of-bounds access with VCPI==0 - gem: Reduce page table overhead with transparent huge pages - panic: Report invalid panic modes - sched: Add TODO entries - ttm: Various cleanups - vblank: Various refactoring and cleanups - Kconfig cleanups - Removed support for kdb Driver Changes: - amdxdna: Fix race conditions at suspend, Improve handling of zero tail pointers, Fix cu_idx being overwritten during command setup - ast: Support imported cursor buffers - - panthor: Enable timestamp propagation, Multiple improvements and fixes to improve the overall robustness, notably of the scheduler. - panels: - panel-edp: Support for CSW MNE007QB3-1, AUO B140HAN06.4, AUO B140QAX01.H Signed-off-by: Dave Airlie <airlied@redhat.com> [airlied: fix mm conflict] From: Maxime Ripard <mripard@redhat.com> Link: https://patch.msgid.link/20251212-spectacular-agama-of-abracadabra-aaef32@penduick
Unified · Split
| @@ -155,7 +155,12 @@ drm_gem_object_init() will create an shmfs file of the · 154 unmodified lines | |||
| 155 | requested size and store it into the struct :c:type:`struct | 155 | requested size and store it into the struct :c:type:`struct |
| 156 | drm_gem_object <drm_gem_object>` filp field. The memory is | 156 | drm_gem_object <drm_gem_object>` filp field. The memory is |
| 157 | used as either main storage for the object when the graphics hardware | 157 | used as either main storage for the object when the graphics hardware |
| 158 | uses system memory directly or as a backing store otherwise. | 158 | uses system memory directly or as a backing store otherwise. Drivers |
| 159 | can call drm_gem_huge_mnt_create() to create, mount and use a huge | ||
| 160 | shmem mountpoint instead of the default one ('shm_mnt'). For builds | ||
| 161 | with CONFIG_TRANSPARENT_HUGEPAGE enabled, further calls to | ||
| 162 | drm_gem_object_init() will let shmem allocate huge pages when | ||
| 163 | possible. | ||
| 159 | 164 | ||
| 160 | Drivers are responsible for the actual physical pages allocation by | 165 | Drivers are responsible for the actual physical pages allocation by |
| 161 | calling shmem_read_mapping_page_gfp() for each page. | 166 | calling shmem_read_mapping_page_gfp() for each page. |
| @@ -290,15 +295,27 @@ The open and close operations must update the GEM object reference · 128 unmodified lines | |||
| 290 | count. Drivers can use the drm_gem_vm_open() and drm_gem_vm_close() helper | 295 | count. Drivers can use the drm_gem_vm_open() and drm_gem_vm_close() helper |
| 291 | functions directly as open and close handlers. | 296 | functions directly as open and close handlers. |
| 292 | 297 | ||
| 293 | The fault operation handler is responsible for mapping individual pages | 298 | The fault operation handler is responsible for mapping pages to |
| 294 | to userspace when a page fault occurs. Depending on the memory | 299 | userspace when a page fault occurs. Depending on the memory allocation |
| 295 | allocation scheme, drivers can allocate pages at fault time, or can | 300 | scheme, drivers can allocate pages at fault time, or can decide to |
| 296 | decide to allocate memory for the GEM object at the time the object is | 301 | allocate memory for the GEM object at the time the object is created. |
| 297 | created. | ||
| 298 | 302 | ||
| 299 | Drivers that want to map the GEM object upfront instead of handling page | 303 | Drivers that want to map the GEM object upfront instead of handling page |
| 300 | faults can implement their own mmap file operation handler. | 304 | faults can implement their own mmap file operation handler. |
| 301 | 305 | ||
| 306 | In order to reduce page table overhead, if the internal shmem mountpoint | ||
| 307 | "shm_mnt" is configured to use transparent huge pages (for builds with | ||
| 308 | CONFIG_TRANSPARENT_HUGEPAGE enabled) and if the shmem backing store | ||
| 309 | managed to allocate a huge page for a faulty address, the fault handler | ||
| 310 | will first attempt to insert that huge page into the VMA before falling | ||
| 311 | back to individual page insertion. mmap() user address alignment for GEM | ||
| 312 | objects is handled by providing a custom get_unmapped_area file | ||
| 313 | operation which forwards to the shmem backing store. For most drivers, | ||
| 314 | which don't create a huge mountpoint by default or through a module | ||
| 315 | parameter, transparent huge pages can be enabled by either setting the | ||
| 316 | "transparent_hugepage_shmem" kernel parameter or the | ||
| 317 | "/sys/kernel/mm/transparent_hugepage/shmem_enabled" sysfs knob. | ||
| 318 | |||
| 302 | For platforms without MMU the GEM core provides a helper method | 319 | For platforms without MMU the GEM core provides a helper method |
| 303 | drm_gem_dma_get_unmapped_area(). The mmap() routines will call this to get a | 320 | drm_gem_dma_get_unmapped_area(). The mmap() routines will call this to get a |
| 304 | proposed address for the mapping. | 321 | proposed address for the mapping. |
| @@ -878,6 +878,51 @@ Contact: Christian König · 877 unmodified lines | |||
| 878 | 878 | ||
| 879 | Level: Starter | 879 | Level: Starter |
| 880 | 880 | ||
| 881 | DRM GPU Scheduler | ||
| 882 | ================= | ||
| 883 | |||
| 884 | Provide a universal successor for drm_sched_resubmit_jobs() | ||
| 885 | ----------------------------------------------------------- | ||
| 886 | |||
| 887 | drm_sched_resubmit_jobs() is deprecated. Main reason being that it leads to | ||
| 888 | reinitializing dma_fences. See that function's docu for details. The better | ||
| 889 | approach for valid resubmissions by amdgpu and Xe is (apparently) to figure out | ||
| 890 | which job (and, through association: which entity) caused the hang. Then, the | ||
| 891 | job's buffer data, together with all other jobs' buffer data currently in the | ||
| 892 | same hardware ring, must be invalidated. This can for example be done by | ||
| 893 | overwriting it. amdgpu currently determines which jobs are in the ring and need | ||
| 894 | to be overwritten by keeping copies of the job. Xe obtains that information by | ||
| 895 | directly accessing drm_sched's pending_list. | ||
| 896 | |||
| 897 | Tasks: | ||
| 898 | |||
| 899 | 1. implement scheduler functionality through which the driver can obtain the | ||
| 900 | information which *broken* jobs are currently in the hardware ring. | ||
| 901 | 2. Such infrastructure would then typically be used in | ||
| 902 | drm_sched_backend_ops.timedout_job(). Document that. | ||
| 903 | 3. Port a driver as first user. | ||
| 904 | 4. Document the new alternative in the docu of deprecated | ||
| 905 | drm_sched_resubmit_jobs(). | ||
| 906 | |||
| 907 | Contact: Christian König <christian.koenig@amd.com> | ||
| 908 | Philipp Stanner <phasta@kernel.org> | ||
| 909 | |||
| 910 | Level: Advanced | ||
| 911 | |||
| 912 | Add locking for runqueues | ||
| 913 | ------------------------- | ||
| 914 | |||
| 915 | There is an old FIXME by Sima in include/drm/gpu_scheduler.h. It details that | ||
| 916 | struct drm_sched_rq is read at many places without any locks, not even with a | ||
| 917 | READ_ONCE. At XDC 2025 no one could really tell why that is the case, whether | ||
| 918 | locks are needed and whether they could be added. (But for real, that should | ||
| 919 | probably be locked!). Check whether it's possible to add locks everywhere, and | ||
| 920 | do so if yes. | ||
| 921 | |||
| 922 | Contact: Philipp Stanner <phasta@kernel.org> | ||
| 923 | |||
| 924 | Level: Intermediate | ||
| 925 | |||
| 881 | Outside DRM | 926 | Outside DRM |
| 882 | =========== | 927 | =========== |
| 883 | 928 | ||
| @@ -889,34 +889,6 @@ in the virtual console layer. On resuming kernel execution, the kernel · 888 unmodified lines | |||
| 889 | debugger calls kgdboc_post_exp_handler() which in turn calls | 889 | debugger calls kgdboc_post_exp_handler() which in turn calls |
| 890 | con_debug_leave(). | 890 | con_debug_leave(). |
| 891 | 891 | ||
| 892 | Any video driver that wants to be compatible with the kernel debugger | ||
| 893 | and the atomic kms callbacks must implement the ``mode_set_base_atomic``, | ||
| 894 | ``fb_debug_enter`` and ``fb_debug_leave operations``. For the | ||
| 895 | ``fb_debug_enter`` and ``fb_debug_leave`` the option exists to use the | ||
| 896 | generic drm fb helper functions or implement something custom for the | ||
| 897 | hardware. The following example shows the initialization of the | ||
| 898 | .mode_set_base_atomic operation in | ||
| 899 | drivers/gpu/drm/i915/intel_display.c:: | ||
| 900 | |||
| 901 | |||
| 902 | static const struct drm_crtc_helper_funcs intel_helper_funcs = { | ||
| 903 | [...] | ||
| 904 | .mode_set_base_atomic = intel_pipe_set_base_atomic, | ||
| 905 | [...] | ||
| 906 | }; | ||
| 907 | |||
| 908 | |||
| 909 | Here is an example of how the i915 driver initializes the | ||
| 910 | fb_debug_enter and fb_debug_leave functions to use the generic drm | ||
| 911 | helpers in ``drivers/gpu/drm/i915/intel_fb.c``:: | ||
| 912 | |||
| 913 | |||
| 914 | static struct fb_ops intelfb_ops = { | ||
| 915 | [...] | ||
| 916 | .fb_debug_enter = drm_fb_helper_debug_enter, | ||
| 917 | .fb_debug_leave = drm_fb_helper_debug_leave, | ||
| 918 | [...] | ||
| 919 | }; | ||
| 920 | 892 | ||
| 921 | 893 | ||
| 922 | Credits | 894 | Credits |
| @@ -39,7 +39,6 @@ static int aie2_send_mgmt_msg_wait(struct amdxdna_dev_hdl *ndev, · 38 unmodified lines | |||
| 39 | if (!ndev->mgmt_chann) | 39 | if (!ndev->mgmt_chann) |
| 40 | return -ENODEV; | 40 | return -ENODEV; |
| 41 | 41 | ||
| 42 | drm_WARN_ON(&xdna->ddev, xdna->rpm_on && !mutex_is_locked(&xdna->dev_lock)); | ||
| 43 | ret = xdna_send_msg_wait(xdna, ndev->mgmt_chann, msg); | 42 | ret = xdna_send_msg_wait(xdna, ndev->mgmt_chann, msg); |
| 44 | if (ret == -ETIME) { | 43 | if (ret == -ETIME) { |
| 45 | xdna_mailbox_stop_channel(ndev->mgmt_chann); | 44 | xdna_mailbox_stop_channel(ndev->mgmt_chann); |
| @@ -59,8 +58,15 @@ static int aie2_send_mgmt_msg_wait(struct amdxdna_dev_hdl *ndev, · 13 unmodified lines | |||
| 59 | int aie2_suspend_fw(struct amdxdna_dev_hdl *ndev) | 58 | int aie2_suspend_fw(struct amdxdna_dev_hdl *ndev) |
| 60 | { | 59 | { |
| 61 | DECLARE_AIE2_MSG(suspend, MSG_OP_SUSPEND); | 60 | DECLARE_AIE2_MSG(suspend, MSG_OP_SUSPEND); |
| 61 | int ret; | ||
| 62 | 62 | ||
| 63 | return aie2_send_mgmt_msg_wait(ndev, &msg); | 63 | ret = aie2_send_mgmt_msg_wait(ndev, &msg); |
| 64 | if (ret) { | ||
| 65 | XDNA_ERR(ndev->xdna, "Failed to suspend fw, ret %d", ret); | ||
| 66 | return ret; | ||
| 67 | } | ||
| 68 | |||
| 69 | return aie2_psp_waitmode_poll(ndev->psp_hdl); | ||
| 64 | } | 70 | } |
| 65 | 71 | ||
| 66 | int aie2_resume_fw(struct amdxdna_dev_hdl *ndev) | 72 | int aie2_resume_fw(struct amdxdna_dev_hdl *ndev) |
| @@ -646,6 +652,7 @@ aie2_cmdlist_fill_npu_cf(struct amdxdna_gem_obj *cmd_bo, void *slot, size_t *siz · 579 unmodified lines | |||
| 646 | u32 cmd_len; | 652 | u32 cmd_len; |
| 647 | void *cmd; | 653 | void *cmd; |
| 648 | 654 | ||
| 655 | memset(npu_slot, 0, sizeof(*npu_slot)); | ||
| 649 | cmd = amdxdna_cmd_get_payload(cmd_bo, &cmd_len); | 656 | cmd = amdxdna_cmd_get_payload(cmd_bo, &cmd_len); |
| 650 | if (*size < sizeof(*npu_slot) + cmd_len) | 657 | if (*size < sizeof(*npu_slot) + cmd_len) |
| 651 | return -EINVAL; | 658 | return -EINVAL; |
| @@ -654,7 +661,6 @@ aie2_cmdlist_fill_npu_cf(struct amdxdna_gem_obj *cmd_bo, void *slot, size_t *siz · 2 unmodified lines | |||
| 654 | if (npu_slot->cu_idx == INVALID_CU_IDX) | 661 | if (npu_slot->cu_idx == INVALID_CU_IDX) |
| 655 | return -EINVAL; | 662 | return -EINVAL; |
| 656 | 663 | ||
| 657 | memset(npu_slot, 0, sizeof(*npu_slot)); | ||
| 658 | npu_slot->type = EXEC_NPU_TYPE_NON_ELF; | 664 | npu_slot->type = EXEC_NPU_TYPE_NON_ELF; |
| 659 | npu_slot->arg_cnt = cmd_len / sizeof(u32); | 665 | npu_slot->arg_cnt = cmd_len / sizeof(u32); |
| 660 | memcpy(npu_slot->args, cmd, cmd_len); | 666 | memcpy(npu_slot->args, cmd, cmd_len); |
| @@ -671,6 +677,7 @@ aie2_cmdlist_fill_npu_dpu(struct amdxdna_gem_obj *cmd_bo, void *slot, size_t *si · 10 unmodified lines | |||
| 671 | u32 cmd_len; | 677 | u32 cmd_len; |
| 672 | u32 arg_sz; | 678 | u32 arg_sz; |
| 673 | 679 | ||
| 680 | memset(npu_slot, 0, sizeof(*npu_slot)); | ||
| 674 | sn = amdxdna_cmd_get_payload(cmd_bo, &cmd_len); | 681 | sn = amdxdna_cmd_get_payload(cmd_bo, &cmd_len); |
| 675 | arg_sz = cmd_len - sizeof(*sn); | 682 | arg_sz = cmd_len - sizeof(*sn); |
| 676 | if (cmd_len < sizeof(*sn) || arg_sz > MAX_NPU_ARGS_SIZE) | 683 | if (cmd_len < sizeof(*sn) || arg_sz > MAX_NPU_ARGS_SIZE) |
| @@ -683,7 +690,6 @@ aie2_cmdlist_fill_npu_dpu(struct amdxdna_gem_obj *cmd_bo, void *slot, size_t *si · 6 unmodified lines | |||
| 683 | if (npu_slot->cu_idx == INVALID_CU_IDX) | 690 | if (npu_slot->cu_idx == INVALID_CU_IDX) |
| 684 | return -EINVAL; | 691 | return -EINVAL; |
| 685 | 692 | ||
| 686 | memset(npu_slot, 0, sizeof(*npu_slot)); | ||
| 687 | npu_slot->type = EXEC_NPU_TYPE_PARTIAL_ELF; | 693 | npu_slot->type = EXEC_NPU_TYPE_PARTIAL_ELF; |
| 688 | npu_slot->inst_buf_addr = sn->buffer; | 694 | npu_slot->inst_buf_addr = sn->buffer; |
| 689 | npu_slot->inst_size = sn->buffer_size; | 695 | npu_slot->inst_size = sn->buffer_size; |
| @@ -703,6 +709,7 @@ aie2_cmdlist_fill_npu_preempt(struct amdxdna_gem_obj *cmd_bo, void *slot, size_t · 13 unmodified lines | |||
| 703 | u32 cmd_len; | 709 | u32 cmd_len; |
| 704 | u32 arg_sz; | 710 | u32 arg_sz; |
| 705 | 711 | ||
| 712 | memset(npu_slot, 0, sizeof(*npu_slot)); | ||
| 706 | pd = amdxdna_cmd_get_payload(cmd_bo, &cmd_len); | 713 | pd = amdxdna_cmd_get_payload(cmd_bo, &cmd_len); |
| 707 | arg_sz = cmd_len - sizeof(*pd); | 714 | arg_sz = cmd_len - sizeof(*pd); |
| 708 | if (cmd_len < sizeof(*pd) || arg_sz > MAX_NPU_ARGS_SIZE) | 715 | if (cmd_len < sizeof(*pd) || arg_sz > MAX_NPU_ARGS_SIZE) |
| @@ -715,7 +722,6 @@ aie2_cmdlist_fill_npu_preempt(struct amdxdna_gem_obj *cmd_bo, void *slot, size_t · 6 unmodified lines | |||
| 715 | if (npu_slot->cu_idx == INVALID_CU_IDX) | 722 | if (npu_slot->cu_idx == INVALID_CU_IDX) |
| 716 | return -EINVAL; | 723 | return -EINVAL; |
| 717 | 724 | ||
| 718 | memset(npu_slot, 0, sizeof(*npu_slot)); | ||
| 719 | npu_slot->type = EXEC_NPU_TYPE_PREEMPT; | 725 | npu_slot->type = EXEC_NPU_TYPE_PREEMPT; |
| 720 | npu_slot->inst_buf_addr = pd->inst_buf; | 726 | npu_slot->inst_buf_addr = pd->inst_buf; |
| 721 | npu_slot->save_buf_addr = pd->save_buf; | 727 | npu_slot->save_buf_addr = pd->save_buf; |
| @@ -739,6 +745,7 @@ aie2_cmdlist_fill_npu_elf(struct amdxdna_gem_obj *cmd_bo, void *slot, size_t *si · 17 unmodified lines | |||
| 739 | u32 cmd_len; | 745 | u32 cmd_len; |
| 740 | u32 arg_sz; | 746 | u32 arg_sz; |
| 741 | 747 | ||
| 748 | memset(npu_slot, 0, sizeof(*npu_slot)); | ||
| 742 | pd = amdxdna_cmd_get_payload(cmd_bo, &cmd_len); | 749 | pd = amdxdna_cmd_get_payload(cmd_bo, &cmd_len); |
| 743 | arg_sz = cmd_len - sizeof(*pd); | 750 | arg_sz = cmd_len - sizeof(*pd); |
| 744 | if (cmd_len < sizeof(*pd) || arg_sz > MAX_NPU_ARGS_SIZE) | 751 | if (cmd_len < sizeof(*pd) || arg_sz > MAX_NPU_ARGS_SIZE) |
| @@ -747,7 +754,6 @@ aie2_cmdlist_fill_npu_elf(struct amdxdna_gem_obj *cmd_bo, void *slot, size_t *si · 2 unmodified lines | |||
| 747 | if (*size < sizeof(*npu_slot) + arg_sz) | 754 | if (*size < sizeof(*npu_slot) + arg_sz) |
| 748 | return -EINVAL; | 755 | return -EINVAL; |
| 749 | 756 | ||
| 750 | memset(npu_slot, 0, sizeof(*npu_slot)); | ||
| 751 | npu_slot->type = EXEC_NPU_TYPE_ELF; | 757 | npu_slot->type = EXEC_NPU_TYPE_ELF; |
| 752 | npu_slot->inst_buf_addr = pd->inst_buf; | 758 | npu_slot->inst_buf_addr = pd->inst_buf; |
| 753 | npu_slot->save_buf_addr = pd->save_buf; | 759 | npu_slot->save_buf_addr = pd->save_buf; |
| @@ -322,7 +322,7 @@ static int aie2_xrs_set_dft_dpm_level(struct drm_device *ddev, u32 dpm_level) · 321 unmodified lines | |||
| 322 | if (ndev->pw_mode != POWER_MODE_DEFAULT || ndev->dpm_level == dpm_level) | 322 | if (ndev->pw_mode != POWER_MODE_DEFAULT || ndev->dpm_level == dpm_level) |
| 323 | return 0; | 323 | return 0; |
| 324 | 324 | ||
| 325 | return ndev->priv->hw_ops.set_dpm(ndev, dpm_level); | 325 | return aie2_pm_set_dpm(ndev, dpm_level); |
| 326 | } | 326 | } |
| 327 | 327 | ||
| 328 | static struct xrs_action_ops aie2_xrs_actions = { | 328 | static struct xrs_action_ops aie2_xrs_actions = { |
| @@ -70,6 +70,7 @@ enum psp_reg_idx { · 69 unmodified lines | |||
| 70 | PSP_INTR_REG = PSP_NUM_IN_REGS, | 70 | PSP_INTR_REG = PSP_NUM_IN_REGS, |
| 71 | PSP_STATUS_REG, | 71 | PSP_STATUS_REG, |
| 72 | PSP_RESP_REG, | 72 | PSP_RESP_REG, |
| 73 | PSP_PWAITMODE_REG, | ||
| 73 | PSP_MAX_REGS /* Keep this at the end */ | 74 | PSP_MAX_REGS /* Keep this at the end */ |
| 74 | }; | 75 | }; |
| 75 | 76 | ||
| @@ -285,11 +286,13 @@ int npu4_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level); · 209 unmodified lines | |||
| 285 | /* aie2_pm.c */ | 286 | /* aie2_pm.c */ |
| 286 | int aie2_pm_init(struct amdxdna_dev_hdl *ndev); | 287 | int aie2_pm_init(struct amdxdna_dev_hdl *ndev); |
| 287 | int aie2_pm_set_mode(struct amdxdna_dev_hdl *ndev, enum amdxdna_power_mode_type target); | 288 | int aie2_pm_set_mode(struct amdxdna_dev_hdl *ndev, enum amdxdna_power_mode_type target); |
| 289 | int aie2_pm_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level); | ||
| 288 | 290 | ||
| 289 | /* aie2_psp.c */ | 291 | /* aie2_psp.c */ |
| 290 | struct psp_device *aie2m_psp_create(struct drm_device *ddev, struct psp_config *conf); | 292 | struct psp_device *aie2m_psp_create(struct drm_device *ddev, struct psp_config *conf); |
| 291 | int aie2_psp_start(struct psp_device *psp); | 293 | int aie2_psp_start(struct psp_device *psp); |
| 292 | void aie2_psp_stop(struct psp_device *psp); | 294 | void aie2_psp_stop(struct psp_device *psp); |
| 295 | int aie2_psp_waitmode_poll(struct psp_device *psp); | ||
| 293 | 296 | ||
| 294 | /* aie2_error.c */ | 297 | /* aie2_error.c */ |
| 295 | int aie2_error_async_events_alloc(struct amdxdna_dev_hdl *ndev); | 298 | int aie2_error_async_events_alloc(struct amdxdna_dev_hdl *ndev); |
| @@ -10,6 +10,7 @@ · 9 unmodified lines | |||
| 10 | 10 | ||
| 11 | #include "aie2_pci.h" | 11 | #include "aie2_pci.h" |
| 12 | #include "amdxdna_pci_drv.h" | 12 | #include "amdxdna_pci_drv.h" |
| 13 | #include "amdxdna_pm.h" | ||
| 13 | 14 | ||
| 14 | #define AIE2_CLK_GATING_ENABLE 1 | 15 | #define AIE2_CLK_GATING_ENABLE 1 |
| 15 | #define AIE2_CLK_GATING_DISABLE 0 | 16 | #define AIE2_CLK_GATING_DISABLE 0 |
| @@ -26,6 +27,20 @@ static int aie2_pm_set_clk_gating(struct amdxdna_dev_hdl *ndev, u32 val) · 10 unmodified lines | |||
| 26 | return 0; | 27 | return 0; |
| 27 | } | 28 | } |
| 28 | 29 | ||
| 30 | int aie2_pm_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level) | ||
| 31 | { | ||
| 32 | int ret; | ||
| 33 | |||
| 34 | ret = amdxdna_pm_resume_get(ndev->xdna); | ||
| 35 | if (ret) | ||
| 36 | return ret; | ||
| 37 | |||
| 38 | ret = ndev->priv->hw_ops.set_dpm(ndev, dpm_level); | ||
| 39 | amdxdna_pm_suspend_put(ndev->xdna); | ||
| 40 | |||
| 41 | return ret; | ||
| 42 | } | ||
| 43 | |||
| 29 | int aie2_pm_init(struct amdxdna_dev_hdl *ndev) | 44 | int aie2_pm_init(struct amdxdna_dev_hdl *ndev) |
| 30 | { | 45 | { |
| 31 | int ret; | 46 | int ret; |
| @@ -94,7 +109,7 @@ int aie2_pm_set_mode(struct amdxdna_dev_hdl *ndev, enum amdxdna_power_mode_type · 62 unmodified lines | |||
| 94 | return -EOPNOTSUPP; | 109 | return -EOPNOTSUPP; |
| 95 | } | 110 | } |
| 96 | 111 | ||
| 97 | ret = ndev->priv->hw_ops.set_dpm(ndev, dpm_level); | 112 | ret = aie2_pm_set_dpm(ndev, dpm_level); |
| 98 | if (ret) | 113 | if (ret) |
| 99 | return ret; | 114 | return ret; |
| 100 | 115 | ||
| @@ -76,6 +76,21 @@ static int psp_exec(struct psp_device *psp, u32 *reg_vals) · 75 unmodified lines | |||
| 76 | return 0; | 76 | return 0; |
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | int aie2_psp_waitmode_poll(struct psp_device *psp) | ||
| 80 | { | ||
| 81 | struct amdxdna_dev *xdna = to_xdna_dev(psp->ddev); | ||
| 82 | u32 mode_reg; | ||
| 83 | int ret; | ||
| 84 | |||
| 85 | ret = readx_poll_timeout(readl, PSP_REG(psp, PSP_PWAITMODE_REG), mode_reg, | ||
| 86 | (mode_reg & 0x1) == 1, | ||
| 87 | PSP_POLL_INTERVAL, PSP_POLL_TIMEOUT); | ||
| 88 | if (ret) | ||
| 89 | XDNA_ERR(xdna, "fw waitmode reg error, ret %d", ret); | ||
| 90 | |||
| 91 | return ret; | ||
| 92 | } | ||
| 93 | |||
| 79 | void aie2_psp_stop(struct psp_device *psp) | 94 | void aie2_psp_stop(struct psp_device *psp) |
| 80 | { | 95 | { |
| 81 | u32 reg_vals[PSP_NUM_IN_REGS] = { PSP_RELEASE_TMR, }; | 96 | u32 reg_vals[PSP_NUM_IN_REGS] = { PSP_RELEASE_TMR, }; |
| @@ -11,7 +11,6 @@ · 10 unmodified lines | |||
| 11 | 11 | ||
| 12 | #include "aie2_pci.h" | 12 | #include "aie2_pci.h" |
| 13 | #include "amdxdna_pci_drv.h" | 13 | #include "amdxdna_pci_drv.h" |
| 14 | #include "amdxdna_pm.h" | ||
| 15 | 14 | ||
| 16 | #define SMU_RESULT_OK 1 | 15 | #define SMU_RESULT_OK 1 |
| 17 | 16 | ||
| @@ -67,16 +66,12 @@ int npu1_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level) · 49 unmodified lines | |||
| 67 | u32 freq; | 66 | u32 freq; |
| 68 | int ret; | 67 | int ret; |
| 69 | 68 | ||
| 70 | ret = amdxdna_pm_resume_get(ndev->xdna); | ||
| 71 | if (ret) | ||
| 72 | return ret; | ||
| 73 | |||
| 74 | ret = aie2_smu_exec(ndev, AIE2_SMU_SET_MPNPUCLK_FREQ, | 69 | ret = aie2_smu_exec(ndev, AIE2_SMU_SET_MPNPUCLK_FREQ, |
| 75 | ndev->priv->dpm_clk_tbl[dpm_level].npuclk, &freq); | 70 | ndev->priv->dpm_clk_tbl[dpm_level].npuclk, &freq); |
| 76 | if (ret) { | 71 | if (ret) { |
| 77 | XDNA_ERR(ndev->xdna, "Set npu clock to %d failed, ret %d\n", | 72 | XDNA_ERR(ndev->xdna, "Set npu clock to %d failed, ret %d\n", |
| 78 | ndev->priv->dpm_clk_tbl[dpm_level].npuclk, ret); | 73 | ndev->priv->dpm_clk_tbl[dpm_level].npuclk, ret); |
| 79 | goto suspend_put; | 74 | return ret; |
| 80 | } | 75 | } |
| 81 | ndev->npuclk_freq = freq; | 76 | ndev->npuclk_freq = freq; |
| 82 | 77 | ||
| @@ -85,10 +80,9 @@ int npu1_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level) · 2 unmodified lines | |||
| 85 | if (ret) { | 80 | if (ret) { |
| 86 | XDNA_ERR(ndev->xdna, "Set h clock to %d failed, ret %d\n", | 81 | XDNA_ERR(ndev->xdna, "Set h clock to %d failed, ret %d\n", |
| 87 | ndev->priv->dpm_clk_tbl[dpm_level].hclk, ret); | 82 | ndev->priv->dpm_clk_tbl[dpm_level].hclk, ret); |
| 88 | goto suspend_put; | 83 | return ret; |
| 89 | } | 84 | } |
| 90 | 85 | ||
| 91 | amdxdna_pm_suspend_put(ndev->xdna); | ||
| 92 | ndev->hclk_freq = freq; | 86 | ndev->hclk_freq = freq; |
| 93 | ndev->dpm_level = dpm_level; | 87 | ndev->dpm_level = dpm_level; |
| 94 | ndev->max_tops = 2 * ndev->total_col; | 88 | ndev->max_tops = 2 * ndev->total_col; |
| @@ -98,35 +92,26 @@ int npu1_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level) · 3 unmodified lines | |||
| 98 | ndev->npuclk_freq, ndev->hclk_freq); | 92 | ndev->npuclk_freq, ndev->hclk_freq); |
| 99 | 93 | ||
| 100 | return 0; | 94 | return 0; |
| 101 | |||
| 102 | suspend_put: | ||
| 103 | amdxdna_pm_suspend_put(ndev->xdna); | ||
| 104 | return ret; | ||
| 105 | } | 95 | } |
| 106 | 96 | ||
| 107 | int npu4_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level) | 97 | int npu4_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level) |
| 108 | { | 98 | { |
| 109 | int ret; | 99 | int ret; |
| 110 | 100 | ||
| 111 | ret = amdxdna_pm_resume_get(ndev->xdna); | ||
| 112 | if (ret) | ||
| 113 | return ret; | ||
| 114 | |||
| 115 | ret = aie2_smu_exec(ndev, AIE2_SMU_SET_HARD_DPMLEVEL, dpm_level, NULL); | 101 | ret = aie2_smu_exec(ndev, AIE2_SMU_SET_HARD_DPMLEVEL, dpm_level, NULL); |
| 116 | if (ret) { | 102 | if (ret) { |
| 117 | XDNA_ERR(ndev->xdna, "Set hard dpm level %d failed, ret %d ", | 103 | XDNA_ERR(ndev->xdna, "Set hard dpm level %d failed, ret %d ", |
| 118 | dpm_level, ret); | 104 | dpm_level, ret); |
| 119 | goto suspend_put; | 105 | return ret; |
| 120 | } | 106 | } |
| 121 | 107 | ||
| 122 | ret = aie2_smu_exec(ndev, AIE2_SMU_SET_SOFT_DPMLEVEL, dpm_level, NULL); | 108 | ret = aie2_smu_exec(ndev, AIE2_SMU_SET_SOFT_DPMLEVEL, dpm_level, NULL); |
| 123 | if (ret) { | 109 | if (ret) { |
| 124 | XDNA_ERR(ndev->xdna, "Set soft dpm level %d failed, ret %d", | 110 | XDNA_ERR(ndev->xdna, "Set soft dpm level %d failed, ret %d", |
| 125 | dpm_level, ret); | 111 | dpm_level, ret); |
| 126 | goto suspend_put; | 112 | return ret; |
| 127 | } | 113 | } |
| 128 | 114 | ||
| 129 | amdxdna_pm_suspend_put(ndev->xdna); | ||
| 130 | ndev->npuclk_freq = ndev->priv->dpm_clk_tbl[dpm_level].npuclk; | 115 | ndev->npuclk_freq = ndev->priv->dpm_clk_tbl[dpm_level].npuclk; |
| 131 | ndev->hclk_freq = ndev->priv->dpm_clk_tbl[dpm_level].hclk; | 116 | ndev->hclk_freq = ndev->priv->dpm_clk_tbl[dpm_level].hclk; |
| 132 | ndev->dpm_level = dpm_level; | 117 | ndev->dpm_level = dpm_level; |
| @@ -137,10 +122,6 @@ int npu4_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level) · 4 unmodified lines | |||
| 137 | ndev->npuclk_freq, ndev->hclk_freq); | 122 | ndev->npuclk_freq, ndev->hclk_freq); |
| 138 | 123 | ||
| 139 | return 0; | 124 | return 0; |
| 140 | |||
| 141 | suspend_put: | ||
| 142 | amdxdna_pm_suspend_put(ndev->xdna); | ||
| 143 | return ret; | ||
| 144 | } | 125 | } |
| 145 | 126 | ||
| 146 | int aie2_smu_init(struct amdxdna_dev_hdl *ndev) | 127 | int aie2_smu_init(struct amdxdna_dev_hdl *ndev) |
| @@ -112,22 +112,6 @@ static u32 mailbox_reg_read(struct mailbox_channel *mb_chann, u32 mbox_reg) · 111 unmodified lines | |||
| 112 | return readl(ringbuf_addr); | 112 | return readl(ringbuf_addr); |
| 113 | } | 113 | } |
| 114 | 114 | ||
| 115 | static int mailbox_reg_read_non_zero(struct mailbox_channel *mb_chann, u32 mbox_reg, u32 *val) | ||
| 116 | { | ||
| 117 | struct xdna_mailbox_res *mb_res = &mb_chann->mb->res; | ||
| 118 | void __iomem *ringbuf_addr = mb_res->mbox_base + mbox_reg; | ||
| 119 | int ret, value; | ||
| 120 | |||
| 121 | /* Poll till value is not zero */ | ||
| 122 | ret = readx_poll_timeout(readl, ringbuf_addr, value, | ||
| 123 | value, 1 /* us */, 100); | ||
| 124 | if (ret < 0) | ||
| 125 | return ret; | ||
| 126 | |||
| 127 | *val = value; | ||
| 128 | return 0; | ||
| 129 | } | ||
| 130 | |||
| 131 | static inline void | 115 | static inline void |
| 132 | mailbox_set_headptr(struct mailbox_channel *mb_chann, u32 headptr_val) | 116 | mailbox_set_headptr(struct mailbox_channel *mb_chann, u32 headptr_val) |
| 133 | { | 117 | { |
| @@ -286,8 +270,7 @@ static int mailbox_get_msg(struct mailbox_channel *mb_chann) · 152 unmodified lines | |||
| 286 | u32 start_addr; | 270 | u32 start_addr; |
| 287 | int ret; | 271 | int ret; |
| 288 | 272 | ||
| 289 | if (mailbox_reg_read_non_zero(mb_chann, mb_chann->res[CHAN_RES_I2X].mb_tail_ptr_reg, &tail)) | 273 | tail = mailbox_get_tailptr(mb_chann, CHAN_RES_I2X); |
| 290 | return -EINVAL; | ||
| 291 | head = mb_chann->i2x_head; | 274 | head = mb_chann->i2x_head; |
| 292 | ringbuf_size = mailbox_get_ringbuf_size(mb_chann, CHAN_RES_I2X); | 275 | ringbuf_size = mailbox_get_ringbuf_size(mb_chann, CHAN_RES_I2X); |
| 293 | start_addr = mb_chann->res[CHAN_RES_I2X].rb_start_addr; | 276 | start_addr = mb_chann->res[CHAN_RES_I2X].rb_start_addr; |
| @@ -101,7 +101,6 @@ struct amdxdna_dev { · 100 unmodified lines | |||
| 101 | struct amdxdna_fw_ver fw_ver; | 101 | struct amdxdna_fw_ver fw_ver; |
| 102 | struct rw_semaphore notifier_lock; /* for mmu notifier*/ | 102 | struct rw_semaphore notifier_lock; /* for mmu notifier*/ |
| 103 | struct workqueue_struct *notifier_wq; | 103 | struct workqueue_struct *notifier_wq; |
| 104 | bool rpm_on; | ||
| 105 | }; | 104 | }; |
| 106 | 105 | ||
| 107 | /* | 106 | /* |
| @@ -15,14 +15,9 @@ int amdxdna_pm_suspend(struct device *dev) · 14 unmodified lines | |||
| 15 | { | 15 | { |
| 16 | struct amdxdna_dev *xdna = to_xdna_dev(dev_get_drvdata(dev)); | 16 | struct amdxdna_dev *xdna = to_xdna_dev(dev_get_drvdata(dev)); |
| 17 | int ret = -EOPNOTSUPP; | 17 | int ret = -EOPNOTSUPP; |
| 18 | bool rpm; | ||
| 19 | 18 | ||
| 20 | if (xdna->dev_info->ops->suspend) { | 19 | if (xdna->dev_info->ops->suspend) |
| 21 | rpm = xdna->rpm_on; | ||
| 22 | xdna->rpm_on = false; | ||
| 23 | ret = xdna->dev_info->ops->suspend(xdna); | 20 | ret = xdna->dev_info->ops->suspend(xdna); |
| 24 | xdna->rpm_on = rpm; | ||
| 25 | } | ||
| 26 | 21 | ||
| 27 | XDNA_DBG(xdna, "Suspend done ret %d", ret); | 22 | XDNA_DBG(xdna, "Suspend done ret %d", ret); |
| 28 | return ret; | 23 | return ret; |
| @@ -32,14 +27,9 @@ int amdxdna_pm_resume(struct device *dev) · 3 unmodified lines | |||
| 32 | { | 27 | { |
| 33 | struct amdxdna_dev *xdna = to_xdna_dev(dev_get_drvdata(dev)); | 28 | struct amdxdna_dev *xdna = to_xdna_dev(dev_get_drvdata(dev)); |
| 34 | int ret = -EOPNOTSUPP; | 29 | int ret = -EOPNOTSUPP; |
| 35 | bool rpm; | ||
| 36 | 30 | ||
| 37 | if (xdna->dev_info->ops->resume) { | 31 | if (xdna->dev_info->ops->resume) |
| 38 | rpm = xdna->rpm_on; | ||
| 39 | xdna->rpm_on = false; | ||
| 40 | ret = xdna->dev_info->ops->resume(xdna); | 32 | ret = xdna->dev_info->ops->resume(xdna); |
| 41 | xdna->rpm_on = rpm; | ||
| 42 | } | ||
| 43 | 33 | ||
| 44 | XDNA_DBG(xdna, "Resume done ret %d", ret); | 34 | XDNA_DBG(xdna, "Resume done ret %d", ret); |
| 45 | return ret; | 35 | return ret; |
| @@ -50,9 +40,6 @@ int amdxdna_pm_resume_get(struct amdxdna_dev *xdna) · 4 unmodified lines | |||
| 50 | struct device *dev = xdna->ddev.dev; | 40 | struct device *dev = xdna->ddev.dev; |
| 51 | int ret; | 41 | int ret; |
| 52 | 42 | ||
| 53 | if (!xdna->rpm_on) | ||
| 54 | return 0; | ||
| 55 | |||
| 56 | ret = pm_runtime_resume_and_get(dev); | 43 | ret = pm_runtime_resume_and_get(dev); |
| 57 | if (ret) { | 44 | if (ret) { |
| 58 | XDNA_ERR(xdna, "Resume failed: %d", ret); | 45 | XDNA_ERR(xdna, "Resume failed: %d", ret); |
| @@ -66,9 +53,6 @@ void amdxdna_pm_suspend_put(struct amdxdna_dev *xdna) · 7 unmodified lines | |||
| 66 | { | 53 | { |
| 67 | struct device *dev = xdna->ddev.dev; | 54 | struct device *dev = xdna->ddev.dev; |
| 68 | 55 | ||
| 69 | if (!xdna->rpm_on) | ||
| 70 | return; | ||
| 71 | |||
| 72 | pm_runtime_put_autosuspend(dev); | 56 | pm_runtime_put_autosuspend(dev); |
| 73 | } | 57 | } |
| 74 | 58 | ||
| @@ -81,14 +65,12 @@ void amdxdna_pm_init(struct amdxdna_dev *xdna) · 6 unmodified lines | |||
| 81 | pm_runtime_use_autosuspend(dev); | 65 | pm_runtime_use_autosuspend(dev); |
| 82 | pm_runtime_allow(dev); | 66 | pm_runtime_allow(dev); |
| 83 | pm_runtime_put_autosuspend(dev); | 67 | pm_runtime_put_autosuspend(dev); |
| 84 | xdna->rpm_on = true; | ||
| 85 | } | 68 | } |
| 86 | 69 | ||
| 87 | void amdxdna_pm_fini(struct amdxdna_dev *xdna) | 70 | void amdxdna_pm_fini(struct amdxdna_dev *xdna) |
| 88 | { | 71 | { |
| 89 | struct device *dev = xdna->ddev.dev; | 72 | struct device *dev = xdna->ddev.dev; |
| 90 | 73 | ||
| 91 | xdna->rpm_on = false; | ||
| 92 | pm_runtime_get_noresume(dev); | 74 | pm_runtime_get_noresume(dev); |
| 93 | pm_runtime_forbid(dev); | 75 | pm_runtime_forbid(dev); |
| 94 | } | 76 | } |
| @@ -13,6 +13,7 @@ · 12 unmodified lines | |||
| 13 | #include "amdxdna_pci_drv.h" | 13 | #include "amdxdna_pci_drv.h" |
| 14 | 14 | ||
| 15 | /* Address definition from NPU1 docs */ | 15 | /* Address definition from NPU1 docs */ |
| 16 | #define MPNPU_PWAITMODE 0x3010034 | ||
| 16 | #define MPNPU_PUB_SEC_INTR 0x3010090 | 17 | #define MPNPU_PUB_SEC_INTR 0x3010090 |
| 17 | #define MPNPU_PUB_PWRMGMT_INTR 0x3010094 | 18 | #define MPNPU_PUB_PWRMGMT_INTR 0x3010094 |
| 18 | #define MPNPU_PUB_SCRATCH2 0x30100A0 | 19 | #define MPNPU_PUB_SCRATCH2 0x30100A0 |
| @@ -92,6 +93,7 @@ static const struct amdxdna_dev_priv npu1_dev_priv = { · 73 unmodified lines | |||
| 92 | DEFINE_BAR_OFFSET(PSP_INTR_REG, NPU1_PSP, MPNPU_PUB_SEC_INTR), | 93 | DEFINE_BAR_OFFSET(PSP_INTR_REG, NPU1_PSP, MPNPU_PUB_SEC_INTR), |
| 93 | DEFINE_BAR_OFFSET(PSP_STATUS_REG, NPU1_PSP, MPNPU_PUB_SCRATCH2), | 94 | DEFINE_BAR_OFFSET(PSP_STATUS_REG, NPU1_PSP, MPNPU_PUB_SCRATCH2), |
| 94 | DEFINE_BAR_OFFSET(PSP_RESP_REG, NPU1_PSP, MPNPU_PUB_SCRATCH3), | 95 | DEFINE_BAR_OFFSET(PSP_RESP_REG, NPU1_PSP, MPNPU_PUB_SCRATCH3), |
| 96 | DEFINE_BAR_OFFSET(PSP_PWAITMODE_REG, NPU1_PSP, MPNPU_PWAITMODE), | ||
| 95 | }, | 97 | }, |
| 96 | .smu_regs_off = { | 98 | .smu_regs_off = { |
| 97 | DEFINE_BAR_OFFSET(SMU_CMD_REG, NPU1_SMU, MPNPU_PUB_SCRATCH5), | 99 | DEFINE_BAR_OFFSET(SMU_CMD_REG, NPU1_SMU, MPNPU_PUB_SCRATCH5), |
| @@ -13,6 +13,7 @@ · 12 unmodified lines | |||
| 13 | #include "amdxdna_pci_drv.h" | 13 | #include "amdxdna_pci_drv.h" |
| 14 | 14 | ||
| 15 | /* NPU Public Registers on MpNPUAxiXbar (refer to Diag npu_registers.h) */ | 15 | /* NPU Public Registers on MpNPUAxiXbar (refer to Diag npu_registers.h) */ |
| 16 | #define MPNPU_PWAITMODE 0x301003C | ||
| 16 | #define MPNPU_PUB_SEC_INTR 0x3010060 | 17 | #define MPNPU_PUB_SEC_INTR 0x3010060 |
| 17 | #define MPNPU_PUB_PWRMGMT_INTR 0x3010064 | 18 | #define MPNPU_PUB_PWRMGMT_INTR 0x3010064 |
| 18 | #define MPNPU_PUB_SCRATCH0 0x301006C | 19 | #define MPNPU_PUB_SCRATCH0 0x301006C |
| @@ -85,6 +86,7 @@ static const struct amdxdna_dev_priv npu2_dev_priv = { · 66 unmodified lines | |||
| 85 | DEFINE_BAR_OFFSET(PSP_INTR_REG, NPU2_PSP, MP0_C2PMSG_73), | 86 | DEFINE_BAR_OFFSET(PSP_INTR_REG, NPU2_PSP, MP0_C2PMSG_73), |
| 86 | DEFINE_BAR_OFFSET(PSP_STATUS_REG, NPU2_PSP, MP0_C2PMSG_123), | 87 | DEFINE_BAR_OFFSET(PSP_STATUS_REG, NPU2_PSP, MP0_C2PMSG_123), |
| 87 | DEFINE_BAR_OFFSET(PSP_RESP_REG, NPU2_REG, MPNPU_PUB_SCRATCH3), | 88 | DEFINE_BAR_OFFSET(PSP_RESP_REG, NPU2_REG, MPNPU_PUB_SCRATCH3), |
| 89 | DEFINE_BAR_OFFSET(PSP_PWAITMODE_REG, NPU2_REG, MPNPU_PWAITMODE), | ||
| 88 | }, | 90 | }, |
| 89 | .smu_regs_off = { | 91 | .smu_regs_off = { |
| 90 | DEFINE_BAR_OFFSET(SMU_CMD_REG, NPU2_SMU, MP1_C2PMSG_0), | 92 | DEFINE_BAR_OFFSET(SMU_CMD_REG, NPU2_SMU, MP1_C2PMSG_0), |
| @@ -13,6 +13,7 @@ · 12 unmodified lines | |||
| 13 | #include "amdxdna_pci_drv.h" | 13 | #include "amdxdna_pci_drv.h" |
| 14 | 14 | ||
| 15 | /* NPU Public Registers on MpNPUAxiXbar (refer to Diag npu_registers.h) */ | 15 | /* NPU Public Registers on MpNPUAxiXbar (refer to Diag npu_registers.h) */ |
| 16 | #define MPNPU_PWAITMODE 0x301003C | ||
| 16 | #define MPNPU_PUB_SEC_INTR 0x3010060 | 17 | #define MPNPU_PUB_SEC_INTR 0x3010060 |
| 17 | #define MPNPU_PUB_PWRMGMT_INTR 0x3010064 | 18 | #define MPNPU_PUB_PWRMGMT_INTR 0x3010064 |
| 18 | #define MPNPU_PUB_SCRATCH0 0x301006C | 19 | #define MPNPU_PUB_SCRATCH0 0x301006C |
| @@ -116,6 +117,7 @@ static const struct amdxdna_dev_priv npu4_dev_priv = { · 97 unmodified lines | |||
| 116 | DEFINE_BAR_OFFSET(PSP_INTR_REG, NPU4_PSP, MP0_C2PMSG_73), | 117 | DEFINE_BAR_OFFSET(PSP_INTR_REG, NPU4_PSP, MP0_C2PMSG_73), |
| 117 | DEFINE_BAR_OFFSET(PSP_STATUS_REG, NPU4_PSP, MP0_C2PMSG_123), | 118 | DEFINE_BAR_OFFSET(PSP_STATUS_REG, NPU4_PSP, MP0_C2PMSG_123), |
| 118 | DEFINE_BAR_OFFSET(PSP_RESP_REG, NPU4_REG, MPNPU_PUB_SCRATCH3), | 119 | DEFINE_BAR_OFFSET(PSP_RESP_REG, NPU4_REG, MPNPU_PUB_SCRATCH3), |
| 120 | DEFINE_BAR_OFFSET(PSP_PWAITMODE_REG, NPU4_REG, MPNPU_PWAITMODE), | ||
| 119 | }, | 121 | }, |
| 120 | .smu_regs_off = { | 122 | .smu_regs_off = { |
| 121 | DEFINE_BAR_OFFSET(SMU_CMD_REG, NPU4_SMU, MP1_C2PMSG_0), | 123 | DEFINE_BAR_OFFSET(SMU_CMD_REG, NPU4_SMU, MP1_C2PMSG_0), |
| @@ -13,6 +13,7 @@ · 12 unmodified lines | |||
| 13 | #include "amdxdna_pci_drv.h" | 13 | #include "amdxdna_pci_drv.h" |
| 14 | 14 | ||
| 15 | /* NPU Public Registers on MpNPUAxiXbar (refer to Diag npu_registers.h) */ | 15 | /* NPU Public Registers on MpNPUAxiXbar (refer to Diag npu_registers.h) */ |
| 16 | #define MPNPU_PWAITMODE 0x301003C | ||
| 16 | #define MPNPU_PUB_SEC_INTR 0x3010060 | 17 | #define MPNPU_PUB_SEC_INTR 0x3010060 |
| 17 | #define MPNPU_PUB_PWRMGMT_INTR 0x3010064 | 18 | #define MPNPU_PUB_PWRMGMT_INTR 0x3010064 |
| 18 | #define MPNPU_PUB_SCRATCH0 0x301006C | 19 | #define MPNPU_PUB_SCRATCH0 0x301006C |
| @@ -85,6 +86,7 @@ static const struct amdxdna_dev_priv npu5_dev_priv = { · 66 unmodified lines | |||
| 85 | DEFINE_BAR_OFFSET(PSP_INTR_REG, NPU5_PSP, MP0_C2PMSG_73), | 86 | DEFINE_BAR_OFFSET(PSP_INTR_REG, NPU5_PSP, MP0_C2PMSG_73), |
| 86 | DEFINE_BAR_OFFSET(PSP_STATUS_REG, NPU5_PSP, MP0_C2PMSG_123), | 87 | DEFINE_BAR_OFFSET(PSP_STATUS_REG, NPU5_PSP, MP0_C2PMSG_123), |
| 87 | DEFINE_BAR_OFFSET(PSP_RESP_REG, NPU5_REG, MPNPU_PUB_SCRATCH3), | 88 | DEFINE_BAR_OFFSET(PSP_RESP_REG, NPU5_REG, MPNPU_PUB_SCRATCH3), |
| 89 | DEFINE_BAR_OFFSET(PSP_PWAITMODE_REG, NPU5_REG, MPNPU_PWAITMODE), | ||
| 88 | }, | 90 | }, |
| 89 | .smu_regs_off = { | 91 | .smu_regs_off = { |
| 90 | DEFINE_BAR_OFFSET(SMU_CMD_REG, NPU5_SMU, MP1_C2PMSG_0), | 92 | DEFINE_BAR_OFFSET(SMU_CMD_REG, NPU5_SMU, MP1_C2PMSG_0), |
| @@ -13,6 +13,7 @@ · 12 unmodified lines | |||
| 13 | #include "amdxdna_pci_drv.h" | 13 | #include "amdxdna_pci_drv.h" |
| 14 | 14 | ||
| 15 | /* NPU Public Registers on MpNPUAxiXbar (refer to Diag npu_registers.h) */ | 15 | /* NPU Public Registers on MpNPUAxiXbar (refer to Diag npu_registers.h) */ |
| 16 | #define MPNPU_PWAITMODE 0x301003C | ||
| 16 | #define MPNPU_PUB_SEC_INTR 0x3010060 | 17 | #define MPNPU_PUB_SEC_INTR 0x3010060 |
| 17 | #define MPNPU_PUB_PWRMGMT_INTR 0x3010064 | 18 | #define MPNPU_PUB_PWRMGMT_INTR 0x3010064 |
| 18 | #define MPNPU_PUB_SCRATCH0 0x301006C | 19 | #define MPNPU_PUB_SCRATCH0 0x301006C |
| @@ -85,6 +86,7 @@ static const struct amdxdna_dev_priv npu6_dev_priv = { · 66 unmodified lines | |||
| 85 | DEFINE_BAR_OFFSET(PSP_INTR_REG, NPU6_PSP, MP0_C2PMSG_73), | 86 | DEFINE_BAR_OFFSET(PSP_INTR_REG, NPU6_PSP, MP0_C2PMSG_73), |
| 86 | DEFINE_BAR_OFFSET(PSP_STATUS_REG, NPU6_PSP, MP0_C2PMSG_123), | 87 | DEFINE_BAR_OFFSET(PSP_STATUS_REG, NPU6_PSP, MP0_C2PMSG_123), |
| 87 | DEFINE_BAR_OFFSET(PSP_RESP_REG, NPU6_REG, MPNPU_PUB_SCRATCH3), | 88 | DEFINE_BAR_OFFSET(PSP_RESP_REG, NPU6_REG, MPNPU_PUB_SCRATCH3), |
| 89 | DEFINE_BAR_OFFSET(PSP_PWAITMODE_REG, NPU6_REG, MPNPU_PWAITMODE), | ||
| 88 | }, | 90 | }, |
| 89 | .smu_regs_off = { | 91 | .smu_regs_off = { |
| 90 | DEFINE_BAR_OFFSET(SMU_CMD_REG, NPU6_SMU, MP1_C2PMSG_0), | 92 | DEFINE_BAR_OFFSET(SMU_CMD_REG, NPU6_SMU, MP1_C2PMSG_0), |
| @@ -55,7 +55,7 @@ config DMABUF_MOVE_NOTIFY · 54 unmodified lines | |||
| 55 | config DMABUF_DEBUG | 55 | config DMABUF_DEBUG |
| 56 | bool "DMA-BUF debug checks" | 56 | bool "DMA-BUF debug checks" |
| 57 | depends on DMA_SHARED_BUFFER | 57 | depends on DMA_SHARED_BUFFER |
| 58 | default y if DMA_API_DEBUG | 58 | default y if DEBUG |
| 59 | help | 59 | help |
| 60 | This option enables additional checks for DMA-BUF importers and | 60 | This option enables additional checks for DMA-BUF importers and |
| 61 | exporters. Specifically it validates that importers do not peek at the | 61 | exporters. Specifically it validates that importers do not peek at the |
| @@ -35,6 +35,12 @@ · 34 unmodified lines | |||
| 35 | 35 | ||
| 36 | #include "dma-buf-sysfs-stats.h" | 36 | #include "dma-buf-sysfs-stats.h" |
| 37 | 37 | ||
| 38 | /* Wrapper to hide the sg_table page link from the importer */ | ||
| 39 | struct dma_buf_sg_table_wrapper { | ||
| 40 | struct sg_table *original; | ||
| 41 | struct sg_table wrapper; | ||
| 42 | }; | ||
| 43 | |||
| 38 | static inline int is_dma_buf_file(struct file *); | 44 | static inline int is_dma_buf_file(struct file *); |
| 39 | 45 | ||
| 40 | static DEFINE_MUTEX(dmabuf_list_mutex); | 46 | static DEFINE_MUTEX(dmabuf_list_mutex); |
| @@ -820,21 +826,59 @@ void dma_buf_put(struct dma_buf *dmabuf) · 779 unmodified lines | |||
| 820 | } | 826 | } |
| 821 | EXPORT_SYMBOL_NS_GPL(dma_buf_put, "DMA_BUF"); | 827 | EXPORT_SYMBOL_NS_GPL(dma_buf_put, "DMA_BUF"); |
| 822 | 828 | ||
| 823 | static void mangle_sg_table(struct sg_table *sg_table) | 829 | static int dma_buf_wrap_sg_table(struct sg_table **sg_table) |
| 824 | { | 830 | { |
| 825 | #ifdef CONFIG_DMABUF_DEBUG | 831 | struct scatterlist *to_sg, *from_sg; |
| 826 | int i; | 832 | struct sg_table *from = *sg_table; |
| 827 | struct scatterlist *sg; | 833 | struct dma_buf_sg_table_wrapper *to; |
| 828 | 834 | int i, ret; | |
| 829 | /* To catch abuse of the underlying struct page by importers mix | 835 | |
| 830 | * up the bits, but take care to preserve the low SG_ bits to | 836 | if (!IS_ENABLED(CONFIG_DMABUF_DEBUG)) |
| 831 | * not corrupt the sgt. The mixing is undone on unmap | 837 | return 0; |
| 832 | * before passing the sgt back to the exporter. | 838 | |
| 839 | /* | ||
| 840 | * To catch abuse of the underlying struct page by importers copy the | ||
| 841 | * sg_table without copying the page_link and give only the copy back to | ||
| 842 | * the importer. | ||
| 833 | */ | 843 | */ |
| 834 | for_each_sgtable_sg(sg_table, sg, i) | 844 | to = kzalloc(sizeof(*to), GFP_KERNEL); |
| 835 | sg->page_link ^= ~0xffUL; | 845 | if (!to) |
| 836 | #endif | 846 | return -ENOMEM; |
| 847 | |||
| 848 | ret = sg_alloc_table(&to->wrapper, from->nents, GFP_KERNEL); | ||
| 849 | if (ret) | ||
| 850 | goto free_to; | ||
| 851 | |||
| 852 | to_sg = to->wrapper.sgl; | ||
| 853 | for_each_sgtable_dma_sg(from, from_sg, i) { | ||
| 854 | to_sg->offset = 0; | ||
| 855 | to_sg->length = 0; | ||
| 856 | sg_assign_page(to_sg, NULL); | ||
| 857 | sg_dma_address(to_sg) = sg_dma_address(from_sg); | ||
| 858 | sg_dma_len(to_sg) = sg_dma_len(from_sg); | ||
| 859 | to_sg = sg_next(to_sg); | ||
| 860 | } | ||
| 837 | 861 | ||
| 862 | to->original = from; | ||
| 863 | *sg_table = &to->wrapper; | ||
| 864 | return 0; | ||
| 865 | |||
| 866 | free_to: | ||
| 867 | kfree(to); | ||
| 868 | return ret; | ||
| 869 | } | ||
| 870 | |||
| 871 | static void dma_buf_unwrap_sg_table(struct sg_table **sg_table) | ||
| 872 | { | ||
| 873 | struct dma_buf_sg_table_wrapper *copy; | ||
| 874 | |||
| 875 | if (!IS_ENABLED(CONFIG_DMABUF_DEBUG)) | ||
| 876 | return; | ||
| 877 | |||
| 878 | copy = container_of(*sg_table, typeof(*copy), wrapper); | ||
| 879 | *sg_table = copy->original; | ||
| 880 | sg_free_table(©->wrapper); | ||
| 881 | kfree(copy); | ||
| 838 | } | 882 | } |
| 839 | 883 | ||
| 840 | static inline bool | 884 | static inline bool |
| @@ -1131,10 +1175,11 @@ struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *attach, · 290 unmodified lines | |||
| 1131 | if (ret < 0) | 1175 | if (ret < 0) |
| 1132 | goto error_unmap; | 1176 | goto error_unmap; |
| 1133 | } | 1177 | } |
| 1134 | mangle_sg_table(sg_table); | 1178 | ret = dma_buf_wrap_sg_table(&sg_table); |
| 1179 | if (ret) | ||
| 1180 | goto error_unmap; | ||
| 1135 | 1181 | ||
| 1136 | #ifdef CONFIG_DMA_API_DEBUG | 1182 | if (IS_ENABLED(CONFIG_DMA_API_DEBUG)) { |
| 1137 | { | ||
| 1138 | struct scatterlist *sg; | 1183 | struct scatterlist *sg; |
| 1139 | u64 addr; | 1184 | u64 addr; |
| 1140 | int len; | 1185 | int len; |
| @@ -1146,10 +1191,10 @@ struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *attach, · 5 unmodified lines | |||
| 1146 | if (!PAGE_ALIGNED(addr) || !PAGE_ALIGNED(len)) { | 1191 | if (!PAGE_ALIGNED(addr) || !PAGE_ALIGNED(len)) { |
| 1147 | pr_debug("%s: addr %llx or len %x is not page aligned!\n", | 1192 | pr_debug("%s: addr %llx or len %x is not page aligned!\n", |
| 1148 | __func__, addr, len); | 1193 | __func__, addr, len); |
| 1194 | break; | ||
| 1149 | } | 1195 | } |
| 1150 | } | 1196 | } |
| 1151 | } | 1197 | } |
| 1152 | #endif /* CONFIG_DMA_API_DEBUG */ | ||
| 1153 | return sg_table; | 1198 | return sg_table; |
| 1154 | 1199 | ||
| 1155 | error_unmap: | 1200 | error_unmap: |
| @@ -1213,7 +1258,7 @@ void dma_buf_unmap_attachment(struct dma_buf_attachment *attach, · 57 unmodified lines | |||
| 1213 | 1258 | ||
| 1214 | dma_resv_assert_held(attach->dmabuf->resv); | 1259 | dma_resv_assert_held(attach->dmabuf->resv); |
| 1215 | 1260 | ||
| 1216 | mangle_sg_table(sg_table); | 1261 | dma_buf_unwrap_sg_table(&sg_table); |
| 1217 | attach->dmabuf->ops->unmap_dma_buf(attach, sg_table, direction); | 1262 | attach->dmabuf->ops->unmap_dma_buf(attach, sg_table, direction); |
| 1218 | 1263 | ||
| 1219 | if (dma_buf_pin_on_map(attach)) | 1264 | if (dma_buf_pin_on_map(attach)) |
| @@ -358,11 +358,8 @@ void __dma_fence_might_wait(void) · 357 unmodified lines | |||
| 358 | * | 358 | * |
| 359 | * Unlike dma_fence_signal_timestamp(), this function must be called with | 359 | * Unlike dma_fence_signal_timestamp(), this function must be called with |
| 360 | * &dma_fence.lock held. | 360 | * &dma_fence.lock held. |
| 361 | * | ||
| 362 | * Returns 0 on success and a negative error value when @fence has been | ||
| 363 | * signalled already. | ||
| 364 | */ | 361 | */ |
| 365 | int dma_fence_signal_timestamp_locked(struct dma_fence *fence, | 362 | void dma_fence_signal_timestamp_locked(struct dma_fence *fence, |
| 366 | ktime_t timestamp) | 363 | ktime_t timestamp) |
| 367 | { | 364 | { |
| 368 | struct dma_fence_cb *cur, *tmp; | 365 | struct dma_fence_cb *cur, *tmp; |
| @@ -372,7 +369,7 @@ int dma_fence_signal_timestamp_locked(struct dma_fence *fence, · 3 unmodified lines | |||
| 372 | 369 | ||
| 373 | if (unlikely(test_and_set_bit(DMA_FENCE_FLAG_SIGNALED_BIT, | 370 | if (unlikely(test_and_set_bit(DMA_FENCE_FLAG_SIGNALED_BIT, |
| 374 | &fence->flags))) | 371 | &fence->flags))) |
| 375 | return -EINVAL; | 372 | return; |
| 376 | 373 | ||
| 377 | /* Stash the cb_list before replacing it with the timestamp */ | 374 | /* Stash the cb_list before replacing it with the timestamp */ |
| 378 | list_replace(&fence->cb_list, &cb_list); | 375 | list_replace(&fence->cb_list, &cb_list); |
| @@ -385,8 +382,6 @@ int dma_fence_signal_timestamp_locked(struct dma_fence *fence, · 6 unmodified lines | |||
| 385 | INIT_LIST_HEAD(&cur->node); | 382 | INIT_LIST_HEAD(&cur->node); |
| 386 | cur->func(fence, cur); | 383 | cur->func(fence, cur); |
| 387 | } | 384 | } |
| 388 | |||
| 389 | return 0; | ||
| 390 | } | 385 | } |
| 391 | EXPORT_SYMBOL(dma_fence_signal_timestamp_locked); | 386 | EXPORT_SYMBOL(dma_fence_signal_timestamp_locked); |
| 392 | 387 | ||
| @@ -401,23 +396,17 @@ EXPORT_SYMBOL(dma_fence_signal_timestamp_locked); · 8 unmodified lines | |||
| 401 | * can only go from the unsignaled to the signaled state and not back, it will | 396 | * can only go from the unsignaled to the signaled state and not back, it will |
| 402 | * only be effective the first time. Set the timestamp provided as the fence | 397 | * only be effective the first time. Set the timestamp provided as the fence |
| 403 | * signal timestamp. | 398 | * signal timestamp. |
| 404 | * | ||
| 405 | * Returns 0 on success and a negative error value when @fence has been | ||
| 406 | * signalled already. | ||
| 407 | */ | 399 | */ |
| 408 | int dma_fence_signal_timestamp(struct dma_fence *fence, ktime_t timestamp) | 400 | void dma_fence_signal_timestamp(struct dma_fence *fence, ktime_t timestamp) |
| 409 | { | 401 | { |
| 410 | unsigned long flags; | 402 | unsigned long flags; |
| 411 | int ret; | ||
| 412 | 403 | ||
| 413 | if (WARN_ON(!fence)) | 404 | if (WARN_ON(!fence)) |
| 414 | return -EINVAL; | 405 | return; |
| 415 | 406 | ||
| 416 | spin_lock_irqsave(fence->lock, flags); | 407 | spin_lock_irqsave(fence->lock, flags); |
| 417 | ret = dma_fence_signal_timestamp_locked(fence, timestamp); | 408 | dma_fence_signal_timestamp_locked(fence, timestamp); |
| 418 | spin_unlock_irqrestore(fence->lock, flags); | 409 | spin_unlock_irqrestore(fence->lock, flags); |
| 419 | |||
| 420 | return ret; | ||
| 421 | } | 410 | } |
| 422 | EXPORT_SYMBOL(dma_fence_signal_timestamp); | 411 | EXPORT_SYMBOL(dma_fence_signal_timestamp); |
| 423 | 412 | ||
| @@ -433,16 +422,57 @@ EXPORT_SYMBOL(dma_fence_signal_timestamp); · 9 unmodified lines | |||
| 433 | * | 422 | * |
| 434 | * Unlike dma_fence_signal(), this function must be called with &dma_fence.lock | 423 | * Unlike dma_fence_signal(), this function must be called with &dma_fence.lock |
| 435 | * held. | 424 | * held. |
| 436 | * | ||
| 437 | * Returns 0 on success and a negative error value when @fence has been | ||
| 438 | * signalled already. | ||
| 439 | */ | 425 | */ |
| 440 | int dma_fence_signal_locked(struct dma_fence *fence) | 426 | void dma_fence_signal_locked(struct dma_fence *fence) |
| 441 | { | 427 | { |
| 442 | return dma_fence_signal_timestamp_locked(fence, ktime_get()); | 428 | dma_fence_signal_timestamp_locked(fence, ktime_get()); |
| 443 | } | 429 | } |
| 444 | EXPORT_SYMBOL(dma_fence_signal_locked); | 430 | EXPORT_SYMBOL(dma_fence_signal_locked); |
| 445 | 431 | ||
| 432 | /** | ||
| 433 | * dma_fence_check_and_signal_locked - signal the fence if it's not yet signaled | ||
| 434 | * @fence: the fence to check and signal | ||
| 435 | * | ||
| 436 | * Checks whether a fence was signaled and signals it if it was not yet signaled. | ||
| 437 | * | ||
| 438 | * Unlike dma_fence_check_and_signal(), this function must be called with | ||
| 439 | * &struct dma_fence.lock being held. | ||
| 440 | * | ||
| 441 | * Return: true if fence has been signaled already, false otherwise. | ||
| 442 | */ | ||
| 443 | bool dma_fence_check_and_signal_locked(struct dma_fence *fence) | ||
| 444 | { | ||
| 445 | bool ret; | ||
| 446 | |||
| 447 | ret = dma_fence_test_signaled_flag(fence); | ||
| 448 | dma_fence_signal_locked(fence); | ||
| 449 | |||
| 450 | return ret; | ||
| 451 | } | ||
| 452 | EXPORT_SYMBOL(dma_fence_check_and_signal_locked); | ||
| 453 | |||
| 454 | /** | ||
| 455 | * dma_fence_check_and_signal - signal the fence if it's not yet signaled | ||
| 456 | * @fence: the fence to check and signal | ||
| 457 | * | ||
| 458 | * Checks whether a fence was signaled and signals it if it was not yet signaled. | ||
| 459 | * All this is done in a race-free manner. | ||
| 460 | * | ||
| 461 | * Return: true if fence has been signaled already, false otherwise. | ||
| 462 | */ | ||
| 463 | bool dma_fence_check_and_signal(struct dma_fence *fence) | ||
| 464 | { | ||
| 465 | unsigned long flags; | ||
| 466 | bool ret; | ||
| 467 | |||
| 468 | spin_lock_irqsave(fence->lock, flags); | ||
| 469 | ret = dma_fence_check_and_signal_locked(fence); | ||
| 470 | spin_unlock_irqrestore(fence->lock, flags); | ||
| 471 | |||
| 472 | return ret; | ||
| 473 | } | ||
| 474 | EXPORT_SYMBOL(dma_fence_check_and_signal); | ||
| 475 | |||
| 446 | /** | 476 | /** |
| 447 | * dma_fence_signal - signal completion of a fence | 477 | * dma_fence_signal - signal completion of a fence |
| 448 | * @fence: the fence to signal | 478 | * @fence: the fence to signal |
| @@ -452,28 +482,22 @@ EXPORT_SYMBOL(dma_fence_signal_locked); · 3 unmodified lines | |||
| 452 | * dma_fence_add_callback(). Can be called multiple times, but since a fence | 482 | * dma_fence_add_callback(). Can be called multiple times, but since a fence |
| 453 | * can only go from the unsignaled to the signaled state and not back, it will | 483 | * can only go from the unsignaled to the signaled state and not back, it will |
| 454 | * only be effective the first time. | 484 | * only be effective the first time. |
| 455 | * | ||
| 456 | * Returns 0 on success and a negative error value when @fence has been | ||
| 457 | * signalled already. | ||
| 458 | */ | 485 | */ |
| 459 | int dma_fence_signal(struct dma_fence *fence) | 486 | void dma_fence_signal(struct dma_fence *fence) |
| 460 | { | 487 | { |
| 461 | unsigned long flags; | 488 | unsigned long flags; |
| 462 | int ret; | ||
| 463 | bool tmp; | 489 | bool tmp; |
| 464 | 490 | ||
| 465 | if (WARN_ON(!fence)) | 491 | if (WARN_ON(!fence)) |
| 466 | return -EINVAL; | 492 | return; |
| 467 | 493 | ||
| 468 | tmp = dma_fence_begin_signalling(); | 494 | tmp = dma_fence_begin_signalling(); |
| 469 | 495 | ||
| 470 | spin_lock_irqsave(fence->lock, flags); | 496 | spin_lock_irqsave(fence->lock, flags); |
| 471 | ret = dma_fence_signal_timestamp_locked(fence, ktime_get()); | 497 | dma_fence_signal_timestamp_locked(fence, ktime_get()); |
| 472 | spin_unlock_irqrestore(fence->lock, flags); | 498 | spin_unlock_irqrestore(fence->lock, flags); |
| 473 | 499 | ||
| 474 | dma_fence_end_signalling(tmp); | 500 | dma_fence_end_signalling(tmp); |
| 475 | |||
| 476 | return ret; | ||
| 477 | } | 501 | } |
| 478 | EXPORT_SYMBOL(dma_fence_signal); | 502 | EXPORT_SYMBOL(dma_fence_signal); |
| 479 | 503 | ||
| @@ -543,7 +567,7 @@ void dma_fence_release(struct kref *kref) · 63 unmodified lines | |||
| 543 | trace_dma_fence_destroy(fence); | 567 | trace_dma_fence_destroy(fence); |
| 544 | 568 | ||
| 545 | if (!list_empty(&fence->cb_list) && | 569 | if (!list_empty(&fence->cb_list) && |
| 546 | !test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) { | 570 | !dma_fence_test_signaled_flag(fence)) { |
| 547 | const char __rcu *timeline; | 571 | const char __rcu *timeline; |
| 548 | const char __rcu *driver; | 572 | const char __rcu *driver; |
| 549 | unsigned long flags; | 573 | unsigned long flags; |
| @@ -600,7 +624,7 @@ static bool __dma_fence_enable_signaling(struct dma_fence *fence) · 50 unmodified lines | |||
| 600 | was_set = test_and_set_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, | 624 | was_set = test_and_set_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, |
| 601 | &fence->flags); | 625 | &fence->flags); |
| 602 | 626 | ||
| 603 | if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) | 627 | if (dma_fence_test_signaled_flag(fence)) |
| 604 | return false; | 628 | return false; |
| 605 | 629 | ||
| 606 | if (!was_set && fence->ops->enable_signaling) { | 630 | if (!was_set && fence->ops->enable_signaling) { |
| @@ -664,7 +688,7 @@ int dma_fence_add_callback(struct dma_fence *fence, struct dma_fence_cb *cb, · 57 unmodified lines | |||
| 664 | if (WARN_ON(!fence || !func)) | 688 | if (WARN_ON(!fence || !func)) |
| 665 | return -EINVAL; | 689 | return -EINVAL; |
| 666 | 690 | ||
| 667 | if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) { | 691 | if (dma_fence_test_signaled_flag(fence)) { |
| 668 | INIT_LIST_HEAD(&cb->node); | 692 | INIT_LIST_HEAD(&cb->node); |
| 669 | return -ENOENT; | 693 | return -ENOENT; |
| 670 | } | 694 | } |
| @@ -781,7 +805,7 @@ dma_fence_default_wait(struct dma_fence *fence, bool intr, signed long timeout) · 110 unmodified lines | |||
| 781 | 805 | ||
| 782 | spin_lock_irqsave(fence->lock, flags); | 806 | spin_lock_irqsave(fence->lock, flags); |
| 783 | 807 | ||
| 784 | if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) | 808 | if (dma_fence_test_signaled_flag(fence)) |
| 785 | goto out; | 809 | goto out; |
| 786 | 810 | ||
| 787 | if (intr && signal_pending(current)) { | 811 | if (intr && signal_pending(current)) { |
| @@ -798,7 +822,7 @@ dma_fence_default_wait(struct dma_fence *fence, bool intr, signed long timeout) · 10 unmodified lines | |||
| 798 | cb.task = current; | 822 | cb.task = current; |
| 799 | list_add(&cb.base.node, &fence->cb_list); | 823 | list_add(&cb.base.node, &fence->cb_list); |
| 800 | 824 | ||
| 801 | while (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags) && ret > 0) { | 825 | while (!dma_fence_test_signaled_flag(fence) && ret > 0) { |
| 802 | if (intr) | 826 | if (intr) |
| 803 | __set_current_state(TASK_INTERRUPTIBLE); | 827 | __set_current_state(TASK_INTERRUPTIBLE); |
| 804 | else | 828 | else |
| @@ -830,7 +854,7 @@ dma_fence_test_signaled_any(struct dma_fence **fences, uint32_t count, · 25 unmodified lines | |||
| 830 | 854 | ||
| 831 | for (i = 0; i < count; ++i) { | 855 | for (i = 0; i < count; ++i) { |
| 832 | struct dma_fence *fence = fences[i]; | 856 | struct dma_fence *fence = fences[i]; |
| 833 | if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) { | 857 | if (dma_fence_test_signaled_flag(fence)) { |
| 834 | if (idx) | 858 | if (idx) |
| 835 | *idx = i; | 859 | *idx = i; |
| 836 | return true; | 860 | return true; |
| @@ -1108,7 +1132,7 @@ const char __rcu *dma_fence_driver_name(struct dma_fence *fence) · 271 unmodified lines | |||
| 1108 | RCU_LOCKDEP_WARN(!rcu_read_lock_held(), | 1132 | RCU_LOCKDEP_WARN(!rcu_read_lock_held(), |
| 1109 | "RCU protection is required for safe access to returned string"); | 1133 | "RCU protection is required for safe access to returned string"); |
| 1110 | 1134 | ||
| 1111 | if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) | 1135 | if (!dma_fence_test_signaled_flag(fence)) |
| 1112 | return fence->ops->get_driver_name(fence); | 1136 | return fence->ops->get_driver_name(fence); |
| 1113 | else | 1137 | else |
| 1114 | return "detached-driver"; | 1138 | return "detached-driver"; |
| @@ -1140,7 +1164,7 @@ const char __rcu *dma_fence_timeline_name(struct dma_fence *fence) · 25 unmodified lines | |||
| 1140 | RCU_LOCKDEP_WARN(!rcu_read_lock_held(), | 1164 | RCU_LOCKDEP_WARN(!rcu_read_lock_held(), |
| 1141 | "RCU protection is required for safe access to returned string"); | 1165 | "RCU protection is required for safe access to returned string"); |
| 1142 | 1166 | ||
| 1143 | if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) | 1167 | if (!dma_fence_test_signaled_flag(fence)) |
| 1144 | return fence->ops->get_timeline_name(fence); | 1168 | return fence->ops->get_timeline_name(fence); |
| 1145 | else | 1169 | else |
| 1146 | return "signaled-timeline"; | 1170 | return "signaled-timeline"; |
| @@ -126,7 +126,7 @@ static int test_signaling(void *arg) · 125 unmodified lines | |||
| 126 | goto err_free; | 126 | goto err_free; |
| 127 | } | 127 | } |
| 128 | 128 | ||
| 129 | if (dma_fence_signal(f)) { | 129 | if (dma_fence_check_and_signal(f)) { |
| 130 | pr_err("Fence reported being already signaled\n"); | 130 | pr_err("Fence reported being already signaled\n"); |
| 131 | goto err_free; | 131 | goto err_free; |
| 132 | } | 132 | } |
| @@ -136,7 +136,7 @@ static int test_signaling(void *arg) · 3 unmodified lines | |||
| 136 | goto err_free; | 136 | goto err_free; |
| 137 | } | 137 | } |
| 138 | 138 | ||
| 139 | if (!dma_fence_signal(f)) { | 139 | if (!dma_fence_test_signaled_flag(f)) { |
| 140 | pr_err("Fence reported not being already signaled\n"); | 140 | pr_err("Fence reported not being already signaled\n"); |
| 141 | goto err_free; | 141 | goto err_free; |
| 142 | } | 142 | } |
| @@ -265,164 +265,83 @@ config DRM_SCHED · 264 unmodified lines | |||
| 265 | tristate | 265 | tristate |
| 266 | depends on DRM | 266 | depends on DRM |
| 267 | 267 | ||
| 268 | source "drivers/gpu/drm/sysfb/Kconfig" | 268 | # Separate option as not all DRM drivers use it |
| 269 | config DRM_PANEL_BACKLIGHT_QUIRKS | ||
| 270 | tristate | ||
| 269 | 271 | ||
| 270 | source "drivers/gpu/drm/arm/Kconfig" | 272 | config DRM_LIB_RANDOM |
| 273 | bool | ||
| 274 | default n | ||
| 271 | 275 | ||
| 272 | source "drivers/gpu/drm/radeon/Kconfig" | 276 | config DRM_PRIVACY_SCREEN |
| 277 | bool | ||
| 278 | default n | ||
| 273 | 279 | ||
| 280 | # DRM driver Kconfig files, sorted | ||
| 281 | source "drivers/gpu/drm/adp/Kconfig" | ||
| 274 | source "drivers/gpu/drm/amd/amdgpu/Kconfig" | 282 | source "drivers/gpu/drm/amd/amdgpu/Kconfig" |
| 275 | 283 | source "drivers/gpu/drm/arm/Kconfig" | |
| 276 | source "drivers/gpu/drm/nouveau/Kconfig" | ||
| 277 | |||
| 278 | source "drivers/gpu/drm/nova/Kconfig" | ||
| 279 | |||
| 280 | source "drivers/gpu/drm/i915/Kconfig" | ||
| 281 | |||
| 282 | source "drivers/gpu/drm/xe/Kconfig" | ||
| 283 | |||
| 284 | source "drivers/gpu/drm/kmb/Kconfig" | ||
| 285 | |||
| 286 | config DRM_VGEM | ||
| 287 | tristate "Virtual GEM provider" | ||
| 288 | depends on DRM && MMU | ||
| 289 | select DRM_GEM_SHMEM_HELPER | ||
| 290 | help | ||
| 291 | Choose this option to get a virtual graphics memory manager, | ||
| 292 | as used by Mesa's software renderer for enhanced performance. | ||
| 293 | If M is selected the module will be called vgem. | ||
| 294 | |||
| 295 | source "drivers/gpu/drm/vkms/Kconfig" | ||
| 296 | |||
| 297 | source "drivers/gpu/drm/exynos/Kconfig" | ||
| 298 | |||
| 299 | source "drivers/gpu/drm/rockchip/Kconfig" | ||
| 300 | |||
| 301 | source "drivers/gpu/drm/vmwgfx/Kconfig" | ||
| 302 | |||
| 303 | source "drivers/gpu/drm/gma500/Kconfig" | ||
| 304 | |||
| 305 | source "drivers/gpu/drm/udl/Kconfig" | ||
| 306 | |||
| 307 | source "drivers/gpu/drm/ast/Kconfig" | ||
| 308 | |||
| 309 | source "drivers/gpu/drm/mgag200/Kconfig" | ||
| 310 | |||
| 311 | source "drivers/gpu/drm/armada/Kconfig" | 284 | source "drivers/gpu/drm/armada/Kconfig" |
| 312 | 285 | source "drivers/gpu/drm/aspeed/Kconfig" | |
| 286 | source "drivers/gpu/drm/ast/Kconfig" | ||
| 313 | source "drivers/gpu/drm/atmel-hlcdc/Kconfig" | 287 | source "drivers/gpu/drm/atmel-hlcdc/Kconfig" |
| 314 | |||
| 315 | source "drivers/gpu/drm/renesas/Kconfig" | ||
| 316 | |||
| 317 | source "drivers/gpu/drm/sun4i/Kconfig" | ||
| 318 | |||
| 319 | source "drivers/gpu/drm/omapdrm/Kconfig" | ||
| 320 | |||
| 321 | source "drivers/gpu/drm/tilcdc/Kconfig" | ||
| 322 | |||
| 323 | source "drivers/gpu/drm/qxl/Kconfig" | ||
| 324 | |||
| 325 | source "drivers/gpu/drm/virtio/Kconfig" | ||
| 326 | |||
| 327 | source "drivers/gpu/drm/msm/Kconfig" | ||
| 328 | |||
| 329 | source "drivers/gpu/drm/fsl-dcu/Kconfig" | ||
| 330 | |||
| 331 | source "drivers/gpu/drm/tegra/Kconfig" | ||
| 332 | |||
| 333 | source "drivers/gpu/drm/stm/Kconfig" | ||
| 334 | |||
| 335 | source "drivers/gpu/drm/panel/Kconfig" | ||
| 336 | |||
| 337 | source "drivers/gpu/drm/bridge/Kconfig" | 288 | source "drivers/gpu/drm/bridge/Kconfig" |
| 338 | |||
| 339 | source "drivers/gpu/drm/sti/Kconfig" | ||
| 340 | |||
| 341 | source "drivers/gpu/drm/imx/Kconfig" | ||
| 342 | |||
| 343 | source "drivers/gpu/drm/ingenic/Kconfig" | ||
| 344 | |||
| 345 | source "drivers/gpu/drm/v3d/Kconfig" | ||
| 346 | |||
| 347 | source "drivers/gpu/drm/vc4/Kconfig" | ||
| 348 | |||
| 349 | source "drivers/gpu/drm/loongson/Kconfig" | ||
| 350 | |||
| 351 | source "drivers/gpu/drm/etnaviv/Kconfig" | 289 | source "drivers/gpu/drm/etnaviv/Kconfig" |
| 352 | 290 | source "drivers/gpu/drm/exynos/Kconfig" | |
| 291 | source "drivers/gpu/drm/fsl-dcu/Kconfig" | ||
| 292 | source "drivers/gpu/drm/gma500/Kconfig" | ||
| 293 | source "drivers/gpu/drm/gud/Kconfig" | ||
| 353 | source "drivers/gpu/drm/hisilicon/Kconfig" | 294 | source "drivers/gpu/drm/hisilicon/Kconfig" |
| 354 | 295 | source "drivers/gpu/drm/hyperv/Kconfig" | |
| 296 | source "drivers/gpu/drm/i915/Kconfig" | ||
| 297 | source "drivers/gpu/drm/imagination/Kconfig" | ||
| 298 | source "drivers/gpu/drm/imx/Kconfig" | ||
| 299 | source "drivers/gpu/drm/ingenic/Kconfig" | ||
| 300 | source "drivers/gpu/drm/kmb/Kconfig" | ||
| 301 | source "drivers/gpu/drm/lima/Kconfig" | ||
| 355 | source "drivers/gpu/drm/logicvc/Kconfig" | 302 | source "drivers/gpu/drm/logicvc/Kconfig" |
| 356 | 303 | source "drivers/gpu/drm/loongson/Kconfig" | |
| 304 | source "drivers/gpu/drm/mcde/Kconfig" | ||
| 357 | source "drivers/gpu/drm/mediatek/Kconfig" | 305 | source "drivers/gpu/drm/mediatek/Kconfig" |
| 358 | |||
| 359 | source "drivers/gpu/drm/mxsfb/Kconfig" | ||
| 360 | |||
| 361 | source "drivers/gpu/drm/meson/Kconfig" | 306 | source "drivers/gpu/drm/meson/Kconfig" |
| 362 | 307 | source "drivers/gpu/drm/mgag200/Kconfig" | |
| 363 | source "drivers/gpu/drm/tiny/Kconfig" | 308 | source "drivers/gpu/drm/msm/Kconfig" |
| 364 | 309 | source "drivers/gpu/drm/mxsfb/Kconfig" | |
| 365 | source "drivers/gpu/drm/pl111/Kconfig" | 310 | source "drivers/gpu/drm/nouveau/Kconfig" |
| 366 | 311 | source "drivers/gpu/drm/nova/Kconfig" | |
| 367 | source "drivers/gpu/drm/tve200/Kconfig" | 312 | source "drivers/gpu/drm/omapdrm/Kconfig" |
| 368 | 313 | source "drivers/gpu/drm/panel/Kconfig" | |
| 369 | source "drivers/gpu/drm/xen/Kconfig" | ||
| 370 | |||
| 371 | source "drivers/gpu/drm/vboxvideo/Kconfig" | ||
| 372 | |||
| 373 | source "drivers/gpu/drm/lima/Kconfig" | ||
| 374 | |||
| 375 | source "drivers/gpu/drm/panfrost/Kconfig" | 314 | source "drivers/gpu/drm/panfrost/Kconfig" |
| 376 | |||
| 377 | source "drivers/gpu/drm/panthor/Kconfig" | 315 | source "drivers/gpu/drm/panthor/Kconfig" |
| 378 | 316 | source "drivers/gpu/drm/pl111/Kconfig" | |
| 379 | source "drivers/gpu/drm/aspeed/Kconfig" | 317 | source "drivers/gpu/drm/qxl/Kconfig" |
| 380 | 318 | source "drivers/gpu/drm/radeon/Kconfig" | |
| 381 | source "drivers/gpu/drm/mcde/Kconfig" | 319 | source "drivers/gpu/drm/renesas/Kconfig" |
| 382 | 320 | source "drivers/gpu/drm/rockchip/Kconfig" | |
| 383 | source "drivers/gpu/drm/tidss/Kconfig" | ||
| 384 | |||
| 385 | source "drivers/gpu/drm/adp/Kconfig" | ||
| 386 | |||
| 387 | source "drivers/gpu/drm/xlnx/Kconfig" | ||
| 388 | |||
| 389 | source "drivers/gpu/drm/gud/Kconfig" | ||
| 390 | |||
| 391 | source "drivers/gpu/drm/sitronix/Kconfig" | 321 | source "drivers/gpu/drm/sitronix/Kconfig" |
| 392 | |||
| 393 | source "drivers/gpu/drm/solomon/Kconfig" | 322 | source "drivers/gpu/drm/solomon/Kconfig" |
| 394 | |||
| 395 | source "drivers/gpu/drm/sprd/Kconfig" | 323 | source "drivers/gpu/drm/sprd/Kconfig" |
| 396 | 324 | source "drivers/gpu/drm/sti/Kconfig" | |
| 397 | source "drivers/gpu/drm/imagination/Kconfig" | 325 | source "drivers/gpu/drm/stm/Kconfig" |
| 398 | 326 | source "drivers/gpu/drm/sun4i/Kconfig" | |
| 327 | source "drivers/gpu/drm/sysfb/Kconfig" | ||
| 328 | source "drivers/gpu/drm/tegra/Kconfig" | ||
| 329 | source "drivers/gpu/drm/tidss/Kconfig" | ||
| 330 | source "drivers/gpu/drm/tilcdc/Kconfig" | ||
| 331 | source "drivers/gpu/drm/tiny/Kconfig" | ||
| 332 | source "drivers/gpu/drm/tve200/Kconfig" | ||
| 399 | source "drivers/gpu/drm/tyr/Kconfig" | 333 | source "drivers/gpu/drm/tyr/Kconfig" |
| 400 | 334 | source "drivers/gpu/drm/udl/Kconfig" | |
| 401 | config DRM_HYPERV | 335 | source "drivers/gpu/drm/v3d/Kconfig" |
| 402 | tristate "DRM Support for Hyper-V synthetic video device" | 336 | source "drivers/gpu/drm/vboxvideo/Kconfig" |
| 403 | depends on DRM && PCI && HYPERV_VMBUS | 337 | source "drivers/gpu/drm/vc4/Kconfig" |
| 404 | select DRM_CLIENT_SELECTION | 338 | source "drivers/gpu/drm/vgem/Kconfig" |
| 405 | select DRM_KMS_HELPER | 339 | source "drivers/gpu/drm/virtio/Kconfig" |
| 406 | select DRM_GEM_SHMEM_HELPER | 340 | source "drivers/gpu/drm/vkms/Kconfig" |
| 407 | help | 341 | source "drivers/gpu/drm/vmwgfx/Kconfig" |
| 408 | This is a KMS driver for Hyper-V synthetic video device. Choose this | 342 | source "drivers/gpu/drm/xe/Kconfig" |
| 409 | option if you would like to enable drm driver for Hyper-V virtual | 343 | source "drivers/gpu/drm/xen/Kconfig" |
| 410 | machine. Unselect Hyper-V framebuffer driver (CONFIG_FB_HYPERV) so | 344 | source "drivers/gpu/drm/xlnx/Kconfig" |
| 411 | that DRM driver is used by default. | ||
| 412 | |||
| 413 | If M is selected the module will be called hyperv_drm. | ||
| 414 | |||
| 415 | # Separate option as not all DRM drivers use it | ||
| 416 | config DRM_PANEL_BACKLIGHT_QUIRKS | ||
| 417 | tristate | ||
| 418 | |||
| 419 | config DRM_LIB_RANDOM | ||
| 420 | bool | ||
| 421 | default n | ||
| 422 | |||
| 423 | config DRM_PRIVACY_SCREEN | ||
| 424 | bool | ||
| 425 | default n | ||
| 426 | 345 | ||
| 427 | endif | 346 | endif |
| 428 | 347 | ||
| @@ -1838,7 +1838,7 @@ static void dce_v10_0_grph_enable(struct drm_crtc *crtc, bool enable) · 1837 unmodified lines | |||
| 1838 | 1838 | ||
| 1839 | static int dce_v10_0_crtc_do_set_base(struct drm_crtc *crtc, | 1839 | static int dce_v10_0_crtc_do_set_base(struct drm_crtc *crtc, |
| 1840 | struct drm_framebuffer *fb, | 1840 | struct drm_framebuffer *fb, |
| 1841 | int x, int y, int atomic) | 1841 | int x, int y) |
| 1842 | { | 1842 | { |
| 1843 | struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); | 1843 | struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); |
| 1844 | struct drm_device *dev = crtc->dev; | 1844 | struct drm_device *dev = crtc->dev; |
| @@ -1855,15 +1855,12 @@ static int dce_v10_0_crtc_do_set_base(struct drm_crtc *crtc, · 10 unmodified lines | |||
| 1855 | bool bypass_lut = false; | 1855 | bool bypass_lut = false; |
| 1856 | 1856 | ||
| 1857 | /* no fb bound */ | 1857 | /* no fb bound */ |
| 1858 | if (!atomic && !crtc->primary->fb) { | 1858 | if (!crtc->primary->fb) { |
| 1859 | DRM_DEBUG_KMS("No FB bound\n"); | 1859 | DRM_DEBUG_KMS("No FB bound\n"); |
| 1860 | return 0; | 1860 | return 0; |
| 1861 | } | 1861 | } |
| 1862 | 1862 | ||
| 1863 | if (atomic) | 1863 | target_fb = crtc->primary->fb; |
| 1864 | target_fb = fb; | ||
| 1865 | else | ||
| 1866 | target_fb = crtc->primary->fb; | ||
| 1867 | 1864 | ||
| 1868 | /* If atomic, assume fb object is pinned & idle & fenced and | 1865 | /* If atomic, assume fb object is pinned & idle & fenced and |
| 1869 | * just update base pointers | 1866 | * just update base pointers |
| @@ -1874,13 +1871,11 @@ static int dce_v10_0_crtc_do_set_base(struct drm_crtc *crtc, · 4 unmodified lines | |||
| 1874 | if (unlikely(r != 0)) | 1871 | if (unlikely(r != 0)) |
| 1875 | return r; | 1872 | return r; |
| 1876 | 1873 | ||
| 1877 | if (!atomic) { | 1874 | abo->flags |= AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS; |
| 1878 | abo->flags |= AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS; | 1875 | r = amdgpu_bo_pin(abo, AMDGPU_GEM_DOMAIN_VRAM); |
| 1879 | r = amdgpu_bo_pin(abo, AMDGPU_GEM_DOMAIN_VRAM); | 1876 | if (unlikely(r != 0)) { |
| 1880 | if (unlikely(r != 0)) { | 1877 | amdgpu_bo_unreserve(abo); |
| 1881 | amdgpu_bo_unreserve(abo); | 1878 | return -EINVAL; |
| 1882 | return -EINVAL; | ||
| 1883 | } | ||
| 1884 | } | 1879 | } |
| 1885 | fb_location = amdgpu_bo_gpu_offset(abo); | 1880 | fb_location = amdgpu_bo_gpu_offset(abo); |
| 1886 | 1881 | ||
| @@ -2068,7 +2063,7 @@ static int dce_v10_0_crtc_do_set_base(struct drm_crtc *crtc, · 181 unmodified lines | |||
| 2068 | /* set pageflip to happen anywhere in vblank interval */ | 2063 | /* set pageflip to happen anywhere in vblank interval */ |
| 2069 | WREG32(mmMASTER_UPDATE_MODE + amdgpu_crtc->crtc_offset, 0); | 2064 | WREG32(mmMASTER_UPDATE_MODE + amdgpu_crtc->crtc_offset, 0); |
| 2070 | 2065 | ||
| 2071 | if (!atomic && fb && fb != crtc->primary->fb) { | 2066 | if (fb && fb != crtc->primary->fb) { |
| 2072 | abo = gem_to_amdgpu_bo(fb->obj[0]); | 2067 | abo = gem_to_amdgpu_bo(fb->obj[0]); |
| 2073 | r = amdgpu_bo_reserve(abo, true); | 2068 | r = amdgpu_bo_reserve(abo, true); |
| 2074 | if (unlikely(r != 0)) | 2069 | if (unlikely(r != 0)) |
| @@ -2611,7 +2606,7 @@ static int dce_v10_0_crtc_mode_set(struct drm_crtc *crtc, · 536 unmodified lines | |||
| 2611 | 2606 | ||
| 2612 | amdgpu_atombios_crtc_set_pll(crtc, adjusted_mode); | 2607 | amdgpu_atombios_crtc_set_pll(crtc, adjusted_mode); |
| 2613 | amdgpu_atombios_crtc_set_dtd_timing(crtc, adjusted_mode); | 2608 | amdgpu_atombios_crtc_set_dtd_timing(crtc, adjusted_mode); |
| 2614 | dce_v10_0_crtc_do_set_base(crtc, old_fb, x, y, 0); | 2609 | dce_v10_0_crtc_do_set_base(crtc, old_fb, x, y); |
| 2615 | amdgpu_atombios_crtc_overscan_setup(crtc, mode, adjusted_mode); | 2610 | amdgpu_atombios_crtc_overscan_setup(crtc, mode, adjusted_mode); |
| 2616 | amdgpu_atombios_crtc_scaler_setup(crtc); | 2611 | amdgpu_atombios_crtc_scaler_setup(crtc); |
| 2617 | dce_v10_0_cursor_reset(crtc); | 2612 | dce_v10_0_cursor_reset(crtc); |
| @@ -2659,14 +2654,7 @@ static bool dce_v10_0_crtc_mode_fixup(struct drm_crtc *crtc, · 41 unmodified lines | |||
| 2659 | static int dce_v10_0_crtc_set_base(struct drm_crtc *crtc, int x, int y, | 2654 | static int dce_v10_0_crtc_set_base(struct drm_crtc *crtc, int x, int y, |
| 2660 | struct drm_framebuffer *old_fb) | 2655 | struct drm_framebuffer *old_fb) |
| 2661 | { | 2656 | { |
| 2662 | return dce_v10_0_crtc_do_set_base(crtc, old_fb, x, y, 0); | 2657 | return dce_v10_0_crtc_do_set_base(crtc, old_fb, x, y); |
| 2663 | } | ||
| 2664 | |||
| 2665 | static int dce_v10_0_crtc_set_base_atomic(struct drm_crtc *crtc, | ||
| 2666 | struct drm_framebuffer *fb, | ||
| 2667 | int x, int y, enum mode_set_atomic state) | ||
| 2668 | { | ||
| 2669 | return dce_v10_0_crtc_do_set_base(crtc, fb, x, y, 1); | ||
| 2670 | } | 2658 | } |
| 2671 | 2659 | ||
| 2672 | static const struct drm_crtc_helper_funcs dce_v10_0_crtc_helper_funcs = { | 2660 | static const struct drm_crtc_helper_funcs dce_v10_0_crtc_helper_funcs = { |
| @@ -2674,7 +2662,6 @@ static const struct drm_crtc_helper_funcs dce_v10_0_crtc_helper_funcs = { · 1 unmodified line | |||
| 2674 | .mode_fixup = dce_v10_0_crtc_mode_fixup, | 2662 | .mode_fixup = dce_v10_0_crtc_mode_fixup, |
| 2675 | .mode_set = dce_v10_0_crtc_mode_set, | 2663 | .mode_set = dce_v10_0_crtc_mode_set, |
| 2676 | .mode_set_base = dce_v10_0_crtc_set_base, | 2664 | .mode_set_base = dce_v10_0_crtc_set_base, |
| 2677 | .mode_set_base_atomic = dce_v10_0_crtc_set_base_atomic, | ||
| 2678 | .prepare = dce_v10_0_crtc_prepare, | 2665 | .prepare = dce_v10_0_crtc_prepare, |
| 2679 | .commit = dce_v10_0_crtc_commit, | 2666 | .commit = dce_v10_0_crtc_commit, |
| 2680 | .disable = dce_v10_0_crtc_disable, | 2667 | .disable = dce_v10_0_crtc_disable, |
| @@ -1876,7 +1876,7 @@ static void dce_v6_0_grph_enable(struct drm_crtc *crtc, bool enable) · 1875 unmodified lines | |||
| 1876 | 1876 | ||
| 1877 | static int dce_v6_0_crtc_do_set_base(struct drm_crtc *crtc, | 1877 | static int dce_v6_0_crtc_do_set_base(struct drm_crtc *crtc, |
| 1878 | struct drm_framebuffer *fb, | 1878 | struct drm_framebuffer *fb, |
| 1879 | int x, int y, int atomic) | 1879 | int x, int y) |
| 1880 | { | 1880 | { |
| 1881 | struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); | 1881 | struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); |
| 1882 | struct drm_device *dev = crtc->dev; | 1882 | struct drm_device *dev = crtc->dev; |
| @@ -1892,15 +1892,12 @@ static int dce_v6_0_crtc_do_set_base(struct drm_crtc *crtc, · 9 unmodified lines | |||
| 1892 | bool bypass_lut = false; | 1892 | bool bypass_lut = false; |
| 1893 | 1893 | ||
| 1894 | /* no fb bound */ | 1894 | /* no fb bound */ |
| 1895 | if (!atomic && !crtc->primary->fb) { | 1895 | if (!crtc->primary->fb) { |
| 1896 | DRM_DEBUG_KMS("No FB bound\n"); | 1896 | DRM_DEBUG_KMS("No FB bound\n"); |
| 1897 | return 0; | 1897 | return 0; |
| 1898 | } | 1898 | } |
| 1899 | 1899 | ||
| 1900 | if (atomic) | 1900 | target_fb = crtc->primary->fb; |
| 1901 | target_fb = fb; | ||
| 1902 | else | ||
| 1903 | target_fb = crtc->primary->fb; | ||
| 1904 | 1901 | ||
| 1905 | /* If atomic, assume fb object is pinned & idle & fenced and | 1902 | /* If atomic, assume fb object is pinned & idle & fenced and |
| 1906 | * just update base pointers | 1903 | * just update base pointers |
| @@ -1911,13 +1908,11 @@ static int dce_v6_0_crtc_do_set_base(struct drm_crtc *crtc, · 4 unmodified lines | |||
| 1911 | if (unlikely(r != 0)) | 1908 | if (unlikely(r != 0)) |
| 1912 | return r; | 1909 | return r; |
| 1913 | 1910 | ||
| 1914 | if (!atomic) { | 1911 | abo->flags |= AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS; |
| 1915 | abo->flags |= AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS; | 1912 | r = amdgpu_bo_pin(abo, AMDGPU_GEM_DOMAIN_VRAM); |
| 1916 | r = amdgpu_bo_pin(abo, AMDGPU_GEM_DOMAIN_VRAM); | 1913 | if (unlikely(r != 0)) { |
| 1917 | if (unlikely(r != 0)) { | 1914 | amdgpu_bo_unreserve(abo); |
| 1918 | amdgpu_bo_unreserve(abo); | 1915 | return -EINVAL; |
| 1919 | return -EINVAL; | ||
| 1920 | } | ||
| 1921 | } | 1916 | } |
| 1922 | fb_location = amdgpu_bo_gpu_offset(abo); | 1917 | fb_location = amdgpu_bo_gpu_offset(abo); |
| 1923 | 1918 | ||
| @@ -2083,7 +2078,7 @@ static int dce_v6_0_crtc_do_set_base(struct drm_crtc *crtc, · 159 unmodified lines | |||
| 2083 | /* set pageflip to happen anywhere in vblank interval */ | 2078 | /* set pageflip to happen anywhere in vblank interval */ |
| 2084 | WREG32(mmMASTER_UPDATE_MODE + amdgpu_crtc->crtc_offset, 0); | 2079 | WREG32(mmMASTER_UPDATE_MODE + amdgpu_crtc->crtc_offset, 0); |
| 2085 | 2080 | ||
| 2086 | if (!atomic && fb && fb != crtc->primary->fb) { | 2081 | if (fb && fb != crtc->primary->fb) { |
| 2087 | abo = gem_to_amdgpu_bo(fb->obj[0]); | 2082 | abo = gem_to_amdgpu_bo(fb->obj[0]); |
| 2088 | r = amdgpu_bo_reserve(abo, true); | 2083 | r = amdgpu_bo_reserve(abo, true); |
| 2089 | if (unlikely(r != 0)) | 2084 | if (unlikely(r != 0)) |
| @@ -2578,7 +2573,7 @@ static int dce_v6_0_crtc_mode_set(struct drm_crtc *crtc, · 488 unmodified lines | |||
| 2578 | 2573 | ||
| 2579 | amdgpu_atombios_crtc_set_pll(crtc, adjusted_mode); | 2574 | amdgpu_atombios_crtc_set_pll(crtc, adjusted_mode); |
| 2580 | amdgpu_atombios_crtc_set_dtd_timing(crtc, adjusted_mode); | 2575 | amdgpu_atombios_crtc_set_dtd_timing(crtc, adjusted_mode); |
| 2581 | dce_v6_0_crtc_do_set_base(crtc, old_fb, x, y, 0); | 2576 | dce_v6_0_crtc_do_set_base(crtc, old_fb, x, y); |
| 2582 | amdgpu_atombios_crtc_overscan_setup(crtc, mode, adjusted_mode); | 2577 | amdgpu_atombios_crtc_overscan_setup(crtc, mode, adjusted_mode); |
| 2583 | amdgpu_atombios_crtc_scaler_setup(crtc); | 2578 | amdgpu_atombios_crtc_scaler_setup(crtc); |
| 2584 | dce_v6_0_cursor_reset(crtc); | 2579 | dce_v6_0_cursor_reset(crtc); |
| @@ -2626,14 +2621,7 @@ static bool dce_v6_0_crtc_mode_fixup(struct drm_crtc *crtc, · 41 unmodified lines | |||
| 2626 | static int dce_v6_0_crtc_set_base(struct drm_crtc *crtc, int x, int y, | 2621 | static int dce_v6_0_crtc_set_base(struct drm_crtc *crtc, int x, int y, |
| 2627 | struct drm_framebuffer *old_fb) | 2622 | struct drm_framebuffer *old_fb) |
| 2628 | { | 2623 | { |
| 2629 | return dce_v6_0_crtc_do_set_base(crtc, old_fb, x, y, 0); | 2624 | return dce_v6_0_crtc_do_set_base(crtc, old_fb, x, y); |
| 2630 | } | ||
| 2631 | |||
| 2632 | static int dce_v6_0_crtc_set_base_atomic(struct drm_crtc *crtc, | ||
| 2633 | struct drm_framebuffer *fb, | ||
| 2634 | int x, int y, enum mode_set_atomic state) | ||
| 2635 | { | ||
| 2636 | return dce_v6_0_crtc_do_set_base(crtc, fb, x, y, 1); | ||
| 2637 | } | 2625 | } |
| 2638 | 2626 | ||
| 2639 | static const struct drm_crtc_helper_funcs dce_v6_0_crtc_helper_funcs = { | 2627 | static const struct drm_crtc_helper_funcs dce_v6_0_crtc_helper_funcs = { |
| @@ -2641,7 +2629,6 @@ static const struct drm_crtc_helper_funcs dce_v6_0_crtc_helper_funcs = { · 1 unmodified line | |||
| 2641 | .mode_fixup = dce_v6_0_crtc_mode_fixup, | 2629 | .mode_fixup = dce_v6_0_crtc_mode_fixup, |
| 2642 | .mode_set = dce_v6_0_crtc_mode_set, | 2630 | .mode_set = dce_v6_0_crtc_mode_set, |
| 2643 | .mode_set_base = dce_v6_0_crtc_set_base, | 2631 | .mode_set_base = dce_v6_0_crtc_set_base, |
| 2644 | .mode_set_base_atomic = dce_v6_0_crtc_set_base_atomic, | ||
| 2645 | .prepare = dce_v6_0_crtc_prepare, | 2632 | .prepare = dce_v6_0_crtc_prepare, |
| 2646 | .commit = dce_v6_0_crtc_commit, | 2633 | .commit = dce_v6_0_crtc_commit, |
| 2647 | .disable = dce_v6_0_crtc_disable, | 2634 | .disable = dce_v6_0_crtc_disable, |
| @@ -1785,7 +1785,7 @@ static void dce_v8_0_grph_enable(struct drm_crtc *crtc, bool enable) · 1784 unmodified lines | |||
| 1785 | 1785 | ||
| 1786 | static int dce_v8_0_crtc_do_set_base(struct drm_crtc *crtc, | 1786 | static int dce_v8_0_crtc_do_set_base(struct drm_crtc *crtc, |
| 1787 | struct drm_framebuffer *fb, | 1787 | struct drm_framebuffer *fb, |
| 1788 | int x, int y, int atomic) | 1788 | int x, int y) |
| 1789 | { | 1789 | { |
| 1790 | struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); | 1790 | struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); |
| 1791 | struct drm_device *dev = crtc->dev; | 1791 | struct drm_device *dev = crtc->dev; |
| @@ -1802,15 +1802,12 @@ static int dce_v8_0_crtc_do_set_base(struct drm_crtc *crtc, · 10 unmodified lines | |||
| 1802 | bool bypass_lut = false; | 1802 | bool bypass_lut = false; |
| 1803 | 1803 | ||
| 1804 | /* no fb bound */ | 1804 | /* no fb bound */ |
| 1805 | if (!atomic && !crtc->primary->fb) { | 1805 | if (!crtc->primary->fb) { |
| 1806 | DRM_DEBUG_KMS("No FB bound\n"); | 1806 | DRM_DEBUG_KMS("No FB bound\n"); |
| 1807 | return 0; | 1807 | return 0; |
| 1808 | } | 1808 | } |
| 1809 | 1809 | ||
| 1810 | if (atomic) | 1810 | target_fb = crtc->primary->fb; |
| 1811 | target_fb = fb; | ||
| 1812 | else | ||
| 1813 | target_fb = crtc->primary->fb; | ||
| 1814 | 1811 | ||
| 1815 | /* If atomic, assume fb object is pinned & idle & fenced and | 1812 | /* If atomic, assume fb object is pinned & idle & fenced and |
| 1816 | * just update base pointers | 1813 | * just update base pointers |
| @@ -1821,13 +1818,11 @@ static int dce_v8_0_crtc_do_set_base(struct drm_crtc *crtc, · 4 unmodified lines | |||
| 1821 | if (unlikely(r != 0)) | 1818 | if (unlikely(r != 0)) |
| 1822 | return r; | 1819 | return r; |
| 1823 | 1820 | ||
| 1824 | if (!atomic) { | 1821 | abo->flags |= AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS; |
| 1825 | abo->flags |= AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS; | 1822 | r = amdgpu_bo_pin(abo, AMDGPU_GEM_DOMAIN_VRAM); |
| 1826 | r = amdgpu_bo_pin(abo, AMDGPU_GEM_DOMAIN_VRAM); | 1823 | if (unlikely(r != 0)) { |
| 1827 | if (unlikely(r != 0)) { | 1824 | amdgpu_bo_unreserve(abo); |
| 1828 | amdgpu_bo_unreserve(abo); | 1825 | return -EINVAL; |
| 1829 | return -EINVAL; | ||
| 1830 | } | ||
| 1831 | } | 1826 | } |
| 1832 | fb_location = amdgpu_bo_gpu_offset(abo); | 1827 | fb_location = amdgpu_bo_gpu_offset(abo); |
| 1833 | 1828 | ||
| @@ -1995,7 +1990,7 @@ static int dce_v8_0_crtc_do_set_base(struct drm_crtc *crtc, · 161 unmodified lines | |||
| 1995 | /* set pageflip to happen anywhere in vblank interval */ | 1990 | /* set pageflip to happen anywhere in vblank interval */ |
| 1996 | WREG32(mmMASTER_UPDATE_MODE + amdgpu_crtc->crtc_offset, 0); | 1991 | WREG32(mmMASTER_UPDATE_MODE + amdgpu_crtc->crtc_offset, 0); |
| 1997 | 1992 | ||
| 1998 | if (!atomic && fb && fb != crtc->primary->fb) { | 1993 | if (fb && fb != crtc->primary->fb) { |
| 1999 | abo = gem_to_amdgpu_bo(fb->obj[0]); | 1994 | abo = gem_to_amdgpu_bo(fb->obj[0]); |
| 2000 | r = amdgpu_bo_reserve(abo, true); | 1995 | r = amdgpu_bo_reserve(abo, true); |
| 2001 | if (unlikely(r != 0)) | 1996 | if (unlikely(r != 0)) |
| @@ -2537,7 +2532,7 @@ static int dce_v8_0_crtc_mode_set(struct drm_crtc *crtc, · 535 unmodified lines | |||
| 2537 | 2532 | ||
| 2538 | amdgpu_atombios_crtc_set_pll(crtc, adjusted_mode); | 2533 | amdgpu_atombios_crtc_set_pll(crtc, adjusted_mode); |
| 2539 | amdgpu_atombios_crtc_set_dtd_timing(crtc, adjusted_mode); | 2534 | amdgpu_atombios_crtc_set_dtd_timing(crtc, adjusted_mode); |
| 2540 | dce_v8_0_crtc_do_set_base(crtc, old_fb, x, y, 0); | 2535 | dce_v8_0_crtc_do_set_base(crtc, old_fb, x, y); |
| 2541 | amdgpu_atombios_crtc_overscan_setup(crtc, mode, adjusted_mode); | 2536 | amdgpu_atombios_crtc_overscan_setup(crtc, mode, adjusted_mode); |
| 2542 | amdgpu_atombios_crtc_scaler_setup(crtc); | 2537 | amdgpu_atombios_crtc_scaler_setup(crtc); |
| 2543 | dce_v8_0_cursor_reset(crtc); | 2538 | dce_v8_0_cursor_reset(crtc); |
| @@ -2585,14 +2580,7 @@ static bool dce_v8_0_crtc_mode_fixup(struct drm_crtc *crtc, · 41 unmodified lines | |||
| 2585 | static int dce_v8_0_crtc_set_base(struct drm_crtc *crtc, int x, int y, | 2580 | static int dce_v8_0_crtc_set_base(struct drm_crtc *crtc, int x, int y, |
| 2586 | struct drm_framebuffer *old_fb) | 2581 | struct drm_framebuffer *old_fb) |
| 2587 | { | 2582 | { |
| 2588 | return dce_v8_0_crtc_do_set_base(crtc, old_fb, x, y, 0); | 2583 | return dce_v8_0_crtc_do_set_base(crtc, old_fb, x, y); |
| 2589 | } | ||
| 2590 | |||
| 2591 | static int dce_v8_0_crtc_set_base_atomic(struct drm_crtc *crtc, | ||
| 2592 | struct drm_framebuffer *fb, | ||
| 2593 | int x, int y, enum mode_set_atomic state) | ||
| 2594 | { | ||
| 2595 | return dce_v8_0_crtc_do_set_base(crtc, fb, x, y, 1); | ||
| 2596 | } | 2584 | } |
| 2597 | 2585 | ||
| 2598 | static const struct drm_crtc_helper_funcs dce_v8_0_crtc_helper_funcs = { | 2586 | static const struct drm_crtc_helper_funcs dce_v8_0_crtc_helper_funcs = { |
| @@ -2600,7 +2588,6 @@ static const struct drm_crtc_helper_funcs dce_v8_0_crtc_helper_funcs = { · 1 unmodified line | |||
| 2600 | .mode_fixup = dce_v8_0_crtc_mode_fixup, | 2588 | .mode_fixup = dce_v8_0_crtc_mode_fixup, |
| 2601 | .mode_set = dce_v8_0_crtc_mode_set, | 2589 | .mode_set = dce_v8_0_crtc_mode_set, |
| 2602 | .mode_set_base = dce_v8_0_crtc_set_base, | 2590 | .mode_set_base = dce_v8_0_crtc_set_base, |
| 2603 | .mode_set_base_atomic = dce_v8_0_crtc_set_base_atomic, | ||
| 2604 | .prepare = dce_v8_0_crtc_prepare, | 2591 | .prepare = dce_v8_0_crtc_prepare, |
| 2605 | .commit = dce_v8_0_crtc_commit, | 2592 | .commit = dce_v8_0_crtc_commit, |
| 2606 | .disable = dce_v8_0_crtc_disable, | 2593 | .disable = dce_v8_0_crtc_disable, |
| @@ -1987,10 +1987,10 @@ kfd_process_gpuid_from_node(struct kfd_process *p, struct kfd_node *node, · 1986 unmodified lines | |||
| 1987 | return -EINVAL; | 1987 | return -EINVAL; |
| 1988 | } | 1988 | } |
| 1989 | 1989 | ||
| 1990 | static int signal_eviction_fence(struct kfd_process *p) | 1990 | static bool signal_eviction_fence(struct kfd_process *p) |
| 1991 | { | 1991 | { |
| 1992 | struct dma_fence *ef; | 1992 | struct dma_fence *ef; |
| 1993 | int ret; | 1993 | bool ret; |
| 1994 | 1994 | ||
| 1995 | rcu_read_lock(); | 1995 | rcu_read_lock(); |
| 1996 | ef = dma_fence_get_rcu_safe(&p->ef); | 1996 | ef = dma_fence_get_rcu_safe(&p->ef); |
| @@ -1998,7 +1998,7 @@ static int signal_eviction_fence(struct kfd_process *p) · 1 unmodified line | |||
| 1998 | if (!ef) | 1998 | if (!ef) |
| 1999 | return -EINVAL; | 1999 | return -EINVAL; |
| 2000 | 2000 | ||
| 2001 | ret = dma_fence_signal(ef); | 2001 | ret = dma_fence_check_and_signal(ef); |
| 2002 | dma_fence_put(ef); | 2002 | dma_fence_put(ef); |
| 2003 | 2003 | ||
| 2004 | return ret; | 2004 | return ret; |
| @@ -28,6 +28,7 @@ · 27 unmodified lines | |||
| 28 | #include <drm/drm_damage_helper.h> | 28 | #include <drm/drm_damage_helper.h> |
| 29 | #include <drm/drm_format_helper.h> | 29 | #include <drm/drm_format_helper.h> |
| 30 | #include <drm/drm_gem_atomic_helper.h> | 30 | #include <drm/drm_gem_atomic_helper.h> |
| 31 | #include <drm/drm_gem_framebuffer_helper.h> | ||
| 31 | #include <drm/drm_print.h> | 32 | #include <drm/drm_print.h> |
| 32 | 33 | ||
| 33 | #include "ast_drv.h" | 34 | #include "ast_drv.h" |
| @@ -181,6 +182,62 @@ static int ast_cursor_plane_helper_atomic_check(struct drm_plane *plane, · 147 unmodified lines | |||
| 181 | return 0; | 182 | return 0; |
| 182 | } | 183 | } |
| 183 | 184 | ||
| 185 | static const u8 *ast_cursor_plane_get_argb4444(struct ast_cursor_plane *ast_cursor_plane, | ||
| 186 | struct drm_shadow_plane_state *shadow_plane_state, | ||
| 187 | const struct drm_rect *clip) | ||
| 188 | { | ||
| 189 | struct drm_plane_state *plane_state = &shadow_plane_state->base; | ||
| 190 | struct drm_framebuffer *fb = plane_state->fb; | ||
| 191 | u8 *argb4444 = NULL; | ||
| 192 | |||
| 193 | if (drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE) == 0) { | ||
| 194 | switch (fb->format->format) { | ||
| 195 | case DRM_FORMAT_ARGB4444: | ||
| 196 | if (shadow_plane_state->data[0].is_iomem) { | ||
| 197 | struct iosys_map argb4444_dst[DRM_FORMAT_MAX_PLANES] = { | ||
| 198 | IOSYS_MAP_INIT_VADDR(ast_cursor_plane->argb4444), | ||
| 199 | }; | ||
| 200 | unsigned int argb4444_dst_pitch[DRM_FORMAT_MAX_PLANES] = { | ||
| 201 | AST_HWC_PITCH, | ||
| 202 | }; | ||
| 203 | |||
| 204 | drm_fb_memcpy(argb4444_dst, argb4444_dst_pitch, | ||
| 205 | shadow_plane_state->data, fb, clip); | ||
| 206 | argb4444 = argb4444_dst[0].vaddr; | ||
| 207 | } else { | ||
| 208 | argb4444 = shadow_plane_state->data[0].vaddr; | ||
| 209 | } | ||
| 210 | break; | ||
| 211 | case DRM_FORMAT_ARGB8888: | ||
| 212 | { | ||
| 213 | struct iosys_map argb4444_dst[DRM_FORMAT_MAX_PLANES] = { | ||
| 214 | IOSYS_MAP_INIT_VADDR(ast_cursor_plane->argb4444), | ||
| 215 | }; | ||
| 216 | unsigned int argb4444_dst_pitch[DRM_FORMAT_MAX_PLANES] = { | ||
| 217 | AST_HWC_PITCH, | ||
| 218 | }; | ||
| 219 | |||
| 220 | drm_fb_argb8888_to_argb4444(argb4444_dst, argb4444_dst_pitch, | ||
| 221 | shadow_plane_state->data, fb, clip, | ||
| 222 | &shadow_plane_state->fmtcnv_state); | ||
| 223 | argb4444 = argb4444_dst[0].vaddr; | ||
| 224 | } | ||
| 225 | break; | ||
| 226 | } | ||
| 227 | |||
| 228 | drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE); | ||
| 229 | } else { | ||
| 230 | /* | ||
| 231 | * Fall back to white square if GEM object is not ready. Gives | ||
| 232 | * the user an indication where the cursor is located. | ||
| 233 | */ | ||
| 234 | memset(ast_cursor_plane->argb4444, 0xff, sizeof(ast_cursor_plane->argb4444)); | ||
| 235 | argb4444 = ast_cursor_plane->argb4444; | ||
| 236 | } | ||
| 237 | |||
| 238 | return argb4444; | ||
| 239 | } | ||
| 240 | |||
| 184 | static void ast_cursor_plane_helper_atomic_update(struct drm_plane *plane, | 241 | static void ast_cursor_plane_helper_atomic_update(struct drm_plane *plane, |
| 185 | struct drm_atomic_state *state) | 242 | struct drm_atomic_state *state) |
| 186 | { | 243 | { |
| @@ -205,29 +262,13 @@ static void ast_cursor_plane_helper_atomic_update(struct drm_plane *plane, · 18 unmodified lines | |||
| 205 | */ | 262 | */ |
| 206 | 263 | ||
| 207 | if (drm_atomic_helper_damage_merged(old_plane_state, plane_state, &damage)) { | 264 | if (drm_atomic_helper_damage_merged(old_plane_state, plane_state, &damage)) { |
| 208 | u8 *argb4444; | 265 | const u8 *argb4444 = ast_cursor_plane_get_argb4444(ast_cursor_plane, |
| 266 | shadow_plane_state, | ||
| 267 | &damage); | ||
| 209 | 268 | ||
| 210 | switch (fb->format->format) { | 269 | if (argb4444) |
| 211 | case DRM_FORMAT_ARGB4444: | 270 | ast_set_cursor_image(ast, argb4444, fb->width, fb->height); |
| 212 | argb4444 = shadow_plane_state->data[0].vaddr; | ||
| 213 | break; | ||
| 214 | default: | ||
| 215 | argb4444 = ast_cursor_plane->argb4444; | ||
| 216 | { | ||
| 217 | struct iosys_map argb4444_dst[DRM_FORMAT_MAX_PLANES] = { | ||
| 218 | IOSYS_MAP_INIT_VADDR(argb4444), | ||
| 219 | }; | ||
| 220 | unsigned int argb4444_dst_pitch[DRM_FORMAT_MAX_PLANES] = { | ||
| 221 | AST_HWC_PITCH, | ||
| 222 | }; | ||
| 223 | 271 | ||
| 224 | drm_fb_argb8888_to_argb4444(argb4444_dst, argb4444_dst_pitch, | ||
| 225 | shadow_plane_state->data, fb, &damage, | ||
| 226 | &shadow_plane_state->fmtcnv_state); | ||
| 227 | } | ||
| 228 | break; | ||
| 229 | } | ||
| 230 | ast_set_cursor_image(ast, argb4444, fb->width, fb->height); | ||
| 231 | ast_set_cursor_base(ast, dst_off); | 272 | ast_set_cursor_base(ast, dst_off); |
| 232 | } | 273 | } |
| 233 | 274 | ||
| @@ -406,6 +406,10 @@ static void sn65dsi83_reset_work(struct work_struct *ws) · 405 unmodified lines | |||
| 406 | { | 406 | { |
| 407 | struct sn65dsi83 *ctx = container_of(ws, struct sn65dsi83, reset_work); | 407 | struct sn65dsi83 *ctx = container_of(ws, struct sn65dsi83, reset_work); |
| 408 | int ret; | 408 | int ret; |
| 409 | int idx; | ||
| 410 | |||
| 411 | if (!drm_bridge_enter(&ctx->bridge, &idx)) | ||
| 412 | return; | ||
| 409 | 413 | ||
| 410 | /* Reset the pipe */ | 414 | /* Reset the pipe */ |
| 411 | ret = sn65dsi83_reset_pipe(ctx); | 415 | ret = sn65dsi83_reset_pipe(ctx); |
| @@ -415,12 +419,18 @@ static void sn65dsi83_reset_work(struct work_struct *ws) · 3 unmodified lines | |||
| 415 | } | 419 | } |
| 416 | if (ctx->irq) | 420 | if (ctx->irq) |
| 417 | enable_irq(ctx->irq); | 421 | enable_irq(ctx->irq); |
| 422 | |||
| 423 | drm_bridge_exit(idx); | ||
| 418 | } | 424 | } |
| 419 | 425 | ||
| 420 | static void sn65dsi83_handle_errors(struct sn65dsi83 *ctx) | 426 | static void sn65dsi83_handle_errors(struct sn65dsi83 *ctx) |
| 421 | { | 427 | { |
| 422 | unsigned int irq_stat; | 428 | unsigned int irq_stat; |
| 423 | int ret; | 429 | int ret; |
| 430 | int idx; | ||
| 431 | |||
| 432 | if (!drm_bridge_enter(&ctx->bridge, &idx)) | ||
| 433 | return; | ||
| 424 | 434 | ||
| 425 | /* | 435 | /* |
| 426 | * Schedule a reset in case of: | 436 | * Schedule a reset in case of: |
| @@ -448,6 +458,8 @@ static void sn65dsi83_handle_errors(struct sn65dsi83 *ctx) · 21 unmodified lines | |||
| 448 | 458 | ||
| 449 | schedule_work(&ctx->reset_work); | 459 | schedule_work(&ctx->reset_work); |
| 450 | } | 460 | } |
| 461 | |||
| 462 | drm_bridge_exit(idx); | ||
| 451 | } | 463 | } |
| 452 | 464 | ||
| 453 | static void sn65dsi83_monitor_work(struct work_struct *work) | 465 | static void sn65dsi83_monitor_work(struct work_struct *work) |
| @@ -470,6 +482,37 @@ static void sn65dsi83_monitor_stop(struct sn65dsi83 *ctx) · 16 unmodified lines | |||
| 470 | cancel_delayed_work_sync(&ctx->monitor_work); | 482 | cancel_delayed_work_sync(&ctx->monitor_work); |
| 471 | } | 483 | } |
| 472 | 484 | ||
| 485 | /* | ||
| 486 | * Release resources taken by sn65dsi83_atomic_pre_enable(). | ||
| 487 | * | ||
| 488 | * Invoked by sn65dsi83_atomic_disable() normally, or by devres after | ||
| 489 | * sn65dsi83_remove() in case this happens befora atomic_disable. | ||
| 490 | */ | ||
| 491 | static void sn65dsi83_release_resources(void *data) | ||
| 492 | { | ||
| 493 | struct sn65dsi83 *ctx = (struct sn65dsi83 *)data; | ||
| 494 | int ret; | ||
| 495 | |||
| 496 | if (ctx->irq) { | ||
| 497 | /* Disable irq */ | ||
| 498 | regmap_write(ctx->regmap, REG_IRQ_EN, 0x0); | ||
| 499 | regmap_write(ctx->regmap, REG_IRQ_GLOBAL, 0x0); | ||
| 500 | } else { | ||
| 501 | /* Stop the polling task */ | ||
| 502 | sn65dsi83_monitor_stop(ctx); | ||
| 503 | } | ||
| 504 | |||
| 505 | /* Put the chip in reset, pull EN line low, and assure 10ms reset low timing. */ | ||
| 506 | gpiod_set_value_cansleep(ctx->enable_gpio, 0); | ||
| 507 | usleep_range(10000, 11000); | ||
| 508 | |||
| 509 | ret = regulator_disable(ctx->vcc); | ||
| 510 | if (ret) | ||
| 511 | dev_err(ctx->dev, "Failed to disable vcc: %d\n", ret); | ||
| 512 | |||
| 513 | regcache_mark_dirty(ctx->regmap); | ||
| 514 | } | ||
| 515 | |||
| 473 | static void sn65dsi83_atomic_pre_enable(struct drm_bridge *bridge, | 516 | static void sn65dsi83_atomic_pre_enable(struct drm_bridge *bridge, |
| 474 | struct drm_atomic_state *state) | 517 | struct drm_atomic_state *state) |
| 475 | { | 518 | { |
| @@ -485,11 +528,15 @@ static void sn65dsi83_atomic_pre_enable(struct drm_bridge *bridge, · 9 unmodified lines | |||
| 485 | __le16 le16val; | 528 | __le16 le16val; |
| 486 | u16 val; | 529 | u16 val; |
| 487 | int ret; | 530 | int ret; |
| 531 | int idx; | ||
| 532 | |||
| 533 | if (!drm_bridge_enter(bridge, &idx)) | ||
| 534 | return; | ||
| 488 | 535 | ||
| 489 | ret = regulator_enable(ctx->vcc); | 536 | ret = regulator_enable(ctx->vcc); |
| 490 | if (ret) { | 537 | if (ret) { |
| 491 | dev_err(ctx->dev, "Failed to enable vcc: %d\n", ret); | 538 | dev_err(ctx->dev, "Failed to enable vcc: %d\n", ret); |
| 492 | return; | 539 | goto err_exit; |
| 493 | } | 540 | } |
| 494 | 541 | ||
| 495 | /* Deassert reset */ | 542 | /* Deassert reset */ |
| @@ -632,7 +679,7 @@ static void sn65dsi83_atomic_pre_enable(struct drm_bridge *bridge, · 136 unmodified lines | |||
| 632 | dev_err(ctx->dev, "failed to lock PLL, ret=%i\n", ret); | 679 | dev_err(ctx->dev, "failed to lock PLL, ret=%i\n", ret); |
| 633 | /* On failure, disable PLL again and exit. */ | 680 | /* On failure, disable PLL again and exit. */ |
| 634 | regmap_write(ctx->regmap, REG_RC_PLL_EN, 0x00); | 681 | regmap_write(ctx->regmap, REG_RC_PLL_EN, 0x00); |
| 635 | return; | 682 | goto err_add_action; |
| 636 | } | 683 | } |
| 637 | 684 | ||
| 638 | /* Trigger reset after CSR register update. */ | 685 | /* Trigger reset after CSR register update. */ |
| @@ -640,6 +687,11 @@ static void sn65dsi83_atomic_pre_enable(struct drm_bridge *bridge, · 1 unmodified line | |||
| 640 | 687 | ||
| 641 | /* Wait for 10ms after soft reset as specified in datasheet */ | 688 | /* Wait for 10ms after soft reset as specified in datasheet */ |
| 642 | usleep_range(10000, 12000); | 689 | usleep_range(10000, 12000); |
| 690 | |||
| 691 | err_add_action: | ||
| 692 | devm_add_action(ctx->dev, sn65dsi83_release_resources, ctx); | ||
| 693 | err_exit: | ||
| 694 | drm_bridge_exit(idx); | ||
| 643 | } | 695 | } |
| 644 | 696 | ||
| 645 | static void sn65dsi83_atomic_enable(struct drm_bridge *bridge, | 697 | static void sn65dsi83_atomic_enable(struct drm_bridge *bridge, |
| @@ -647,6 +699,10 @@ static void sn65dsi83_atomic_enable(struct drm_bridge *bridge, · 1 unmodified line | |||
| 647 | { | 699 | { |
| 648 | struct sn65dsi83 *ctx = bridge_to_sn65dsi83(bridge); | 700 | struct sn65dsi83 *ctx = bridge_to_sn65dsi83(bridge); |
| 649 | unsigned int pval; | 701 | unsigned int pval; |
| 702 | int idx; | ||
| 703 | |||
| 704 | if (!drm_bridge_enter(bridge, &idx)) | ||
| 705 | return; | ||
| 650 | 706 | ||
| 651 | /* Clear all errors that got asserted during initialization. */ | 707 | /* Clear all errors that got asserted during initialization. */ |
| 652 | regmap_read(ctx->regmap, REG_IRQ_STAT, &pval); | 708 | regmap_read(ctx->regmap, REG_IRQ_STAT, &pval); |
| @@ -666,32 +722,22 @@ static void sn65dsi83_atomic_enable(struct drm_bridge *bridge, · 13 unmodified lines | |||
| 666 | /* Use the polling task */ | 722 | /* Use the polling task */ |
| 667 | sn65dsi83_monitor_start(ctx); | 723 | sn65dsi83_monitor_start(ctx); |
| 668 | } | 724 | } |
| 725 | |||
| 726 | drm_bridge_exit(idx); | ||
| 669 | } | 727 | } |
| 670 | 728 | ||
| 671 | static void sn65dsi83_atomic_disable(struct drm_bridge *bridge, | 729 | static void sn65dsi83_atomic_disable(struct drm_bridge *bridge, |
| 672 | struct drm_atomic_state *state) | 730 | struct drm_atomic_state *state) |
| 673 | { | 731 | { |
| 674 | struct sn65dsi83 *ctx = bridge_to_sn65dsi83(bridge); | 732 | struct sn65dsi83 *ctx = bridge_to_sn65dsi83(bridge); |
| 675 | int ret; | 733 | int idx; |
| 676 | 734 | ||
| 677 | if (ctx->irq) { | 735 | if (!drm_bridge_enter(bridge, &idx)) |
| 678 | /* Disable irq */ | 736 | return; |
| 679 | regmap_write(ctx->regmap, REG_IRQ_EN, 0x0); | ||
| 680 | regmap_write(ctx->regmap, REG_IRQ_GLOBAL, 0x0); | ||
| 681 | } else { | ||
| 682 | /* Stop the polling task */ | ||
| 683 | sn65dsi83_monitor_stop(ctx); | ||
| 684 | } | ||
| 685 | |||
| 686 | /* Put the chip in reset, pull EN line low, and assure 10ms reset low timing. */ | ||
| 687 | gpiod_set_value_cansleep(ctx->enable_gpio, 0); | ||
| 688 | usleep_range(10000, 11000); | ||
| 689 | 737 | ||
| 690 | ret = regulator_disable(ctx->vcc); | 738 | devm_release_action(ctx->dev, sn65dsi83_release_resources, ctx); |
| 691 | if (ret) | ||
| 692 | dev_err(ctx->dev, "Failed to disable vcc: %d\n", ret); | ||
| 693 | 739 | ||
| 694 | regcache_mark_dirty(ctx->regmap); | 740 | drm_bridge_exit(idx); |
| 695 | } | 741 | } |
| 696 | 742 | ||
| 697 | static enum drm_mode_status | 743 | static enum drm_mode_status |
| @@ -1012,7 +1058,7 @@ static void sn65dsi83_remove(struct i2c_client *client) · 314 unmodified lines | |||
| 1012 | { | 1058 | { |
| 1013 | struct sn65dsi83 *ctx = i2c_get_clientdata(client); | 1059 | struct sn65dsi83 *ctx = i2c_get_clientdata(client); |
| 1014 | 1060 | ||
| 1015 | drm_bridge_remove(&ctx->bridge); | 1061 | drm_bridge_unplug(&ctx->bridge); |
| 1016 | } | 1062 | } |
| 1017 | 1063 | ||
| 1018 | static const struct i2c_device_id sn65dsi83_id[] = { | 1064 | static const struct i2c_device_id sn65dsi83_id[] = { |
| @@ -4572,7 +4572,8 @@ int drm_dp_atomic_release_time_slots(struct drm_atomic_state *state, · 4571 unmodified lines | |||
| 4572 | if (!payload->delete) { | 4572 | if (!payload->delete) { |
| 4573 | payload->pbn = 0; | 4573 | payload->pbn = 0; |
| 4574 | payload->delete = true; | 4574 | payload->delete = true; |
| 4575 | topology_state->payload_mask &= ~BIT(payload->vcpi - 1); | 4575 | if (payload->vcpi > 0) |
| 4576 | topology_state->payload_mask &= ~BIT(payload->vcpi - 1); | ||
| 4576 | } | 4577 | } |
| 4577 | 4578 | ||
| 4578 | return 0; | 4579 | return 0; |
| @@ -906,6 +906,7 @@ drm_atomic_private_obj_init(struct drm_device *dev, · 905 unmodified lines | |||
| 906 | 906 | ||
| 907 | drm_modeset_lock_init(&obj->lock); | 907 | drm_modeset_lock_init(&obj->lock); |
| 908 | 908 | ||
| 909 | obj->dev = dev; | ||
| 909 | obj->state = state; | 910 | obj->state = state; |
| 910 | obj->funcs = funcs; | 911 | obj->funcs = funcs; |
| 911 | list_add_tail(&obj->head, &dev->mode_config.privobj_list); | 912 | list_add_tail(&obj->head, &dev->mode_config.privobj_list); |
| @@ -27,6 +27,7 @@ · 26 unmodified lines | |||
| 27 | #include <linux/media-bus-format.h> | 27 | #include <linux/media-bus-format.h> |
| 28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
| 29 | #include <linux/mutex.h> | 29 | #include <linux/mutex.h> |
| 30 | #include <linux/srcu.h> | ||
| 30 | 31 | ||
| 31 | #include <drm/drm_atomic_state_helper.h> | 32 | #include <drm/drm_atomic_state_helper.h> |
| 32 | #include <drm/drm_bridge.h> | 33 | #include <drm/drm_bridge.h> |
| @@ -202,6 +203,67 @@ static DEFINE_MUTEX(bridge_lock); · 169 unmodified lines | |||
| 202 | static LIST_HEAD(bridge_list); | 203 | static LIST_HEAD(bridge_list); |
| 203 | static LIST_HEAD(bridge_lingering_list); | 204 | static LIST_HEAD(bridge_lingering_list); |
| 204 | 205 | ||
| 206 | DEFINE_STATIC_SRCU(drm_bridge_unplug_srcu); | ||
| 207 | |||
| 208 | /** | ||
| 209 | * drm_bridge_enter - Enter DRM bridge critical section | ||
| 210 | * @bridge: DRM bridge | ||
| 211 | * @idx: Pointer to index that will be passed to the matching drm_bridge_exit() | ||
| 212 | * | ||
| 213 | * This function marks and protects the beginning of a section that should not | ||
| 214 | * be entered after the bridge has been unplugged. The section end is marked | ||
| 215 | * with drm_bridge_exit(). Calls to this function can be nested. | ||
| 216 | * | ||
| 217 | * Returns: | ||
| 218 | * True if it is OK to enter the section, false otherwise. | ||
| 219 | */ | ||
| 220 | bool drm_bridge_enter(struct drm_bridge *bridge, int *idx) | ||
| 221 | { | ||
| 222 | *idx = srcu_read_lock(&drm_bridge_unplug_srcu); | ||
| 223 | |||
| 224 | if (bridge->unplugged) { | ||
| 225 | srcu_read_unlock(&drm_bridge_unplug_srcu, *idx); | ||
| 226 | return false; | ||
| 227 | } | ||
| 228 | |||
| 229 | return true; | ||
| 230 | } | ||
| 231 | EXPORT_SYMBOL(drm_bridge_enter); | ||
| 232 | |||
| 233 | /** | ||
| 234 | * drm_bridge_exit - Exit DRM bridge critical section | ||
| 235 | * @idx: index returned by drm_bridge_enter() | ||
| 236 | * | ||
| 237 | * This function marks the end of a section that should not be entered after | ||
| 238 | * the bridge has been unplugged. | ||
| 239 | */ | ||
| 240 | void drm_bridge_exit(int idx) | ||
| 241 | { | ||
| 242 | srcu_read_unlock(&drm_bridge_unplug_srcu, idx); | ||
| 243 | } | ||
| 244 | EXPORT_SYMBOL(drm_bridge_exit); | ||
| 245 | |||
| 246 | /** | ||
| 247 | * drm_bridge_unplug - declare a DRM bridge was unplugged and remove it | ||
| 248 | * @bridge: DRM bridge | ||
| 249 | * | ||
| 250 | * This tells the bridge has been physically unplugged and no operations on | ||
| 251 | * device resources must be done anymore. Entry-points can use | ||
| 252 | * drm_bridge_enter() and drm_bridge_exit() to protect device resources in | ||
| 253 | * a race free manner. | ||
| 254 | * | ||
| 255 | * Also unregisters the bridge. | ||
| 256 | */ | ||
| 257 | void drm_bridge_unplug(struct drm_bridge *bridge) | ||
| 258 | { | ||
| 259 | bridge->unplugged = true; | ||
| 260 | |||
| 261 | synchronize_srcu(&drm_bridge_unplug_srcu); | ||
| 262 | |||
| 263 | drm_bridge_remove(bridge); | ||
| 264 | } | ||
| 265 | EXPORT_SYMBOL(drm_bridge_unplug); | ||
| 266 | |||
| 205 | static void __drm_bridge_free(struct kref *kref) | 267 | static void __drm_bridge_free(struct kref *kref) |
| 206 | { | 268 | { |
| 207 | struct drm_bridge *bridge = container_of(kref, struct drm_bridge, refcount); | 269 | struct drm_bridge *bridge = container_of(kref, struct drm_bridge, refcount); |
| @@ -75,9 +75,6 @@ MODULE_PARM_DESC(drm_leak_fbdev_smem, · 74 unmodified lines | |||
| 75 | "Allow unsafe leaking fbdev physical smem address [default=false]"); | 75 | "Allow unsafe leaking fbdev physical smem address [default=false]"); |
| 76 | #endif | 76 | #endif |
| 77 | 77 | ||
| 78 | static LIST_HEAD(kernel_fb_helper_list); | ||
| 79 | static DEFINE_MUTEX(kernel_fb_helper_lock); | ||
| 80 | |||
| 81 | /** | 78 | /** |
| 82 | * DOC: fbdev helpers | 79 | * DOC: fbdev helpers |
| 83 | * | 80 | * |
| @@ -115,101 +112,6 @@ static DEFINE_MUTEX(kernel_fb_helper_lock); · 31 unmodified lines | |||
| 115 | * mmap page writes. | 112 | * mmap page writes. |
| 116 | */ | 113 | */ |
| 117 | 114 | ||
| 118 | static void drm_fb_helper_restore_lut_atomic(struct drm_crtc *crtc) | ||
| 119 | { | ||
| 120 | uint16_t *r_base, *g_base, *b_base; | ||
| 121 | |||
| 122 | if (crtc->funcs->gamma_set == NULL) | ||
| 123 | return; | ||
| 124 | |||
| 125 | r_base = crtc->gamma_store; | ||
| 126 | g_base = r_base + crtc->gamma_size; | ||
| 127 | b_base = g_base + crtc->gamma_size; | ||
| 128 | |||
| 129 | crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, | ||
| 130 | crtc->gamma_size, NULL); | ||
| 131 | } | ||
| 132 | |||
| 133 | /** | ||
| 134 | * drm_fb_helper_debug_enter - implementation for &fb_ops.fb_debug_enter | ||
| 135 | * @info: fbdev registered by the helper | ||
| 136 | */ | ||
| 137 | int drm_fb_helper_debug_enter(struct fb_info *info) | ||
| 138 | { | ||
| 139 | struct drm_fb_helper *helper = info->par; | ||
| 140 | const struct drm_crtc_helper_funcs *funcs; | ||
| 141 | struct drm_mode_set *mode_set; | ||
| 142 | |||
| 143 | list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) { | ||
| 144 | mutex_lock(&helper->client.modeset_mutex); | ||
| 145 | drm_client_for_each_modeset(mode_set, &helper->client) { | ||
| 146 | if (!mode_set->crtc->enabled) | ||
| 147 | continue; | ||
| 148 | |||
| 149 | funcs = mode_set->crtc->helper_private; | ||
| 150 | if (funcs->mode_set_base_atomic == NULL) | ||
| 151 | continue; | ||
| 152 | |||
| 153 | if (drm_drv_uses_atomic_modeset(mode_set->crtc->dev)) | ||
| 154 | continue; | ||
| 155 | |||
| 156 | funcs->mode_set_base_atomic(mode_set->crtc, | ||
| 157 | mode_set->fb, | ||
| 158 | mode_set->x, | ||
| 159 | mode_set->y, | ||
| 160 | ENTER_ATOMIC_MODE_SET); | ||
| 161 | } | ||
| 162 | mutex_unlock(&helper->client.modeset_mutex); | ||
| 163 | } | ||
| 164 | |||
| 165 | return 0; | ||
| 166 | } | ||
| 167 | EXPORT_SYMBOL(drm_fb_helper_debug_enter); | ||
| 168 | |||
| 169 | /** | ||
| 170 | * drm_fb_helper_debug_leave - implementation for &fb_ops.fb_debug_leave | ||
| 171 | * @info: fbdev registered by the helper | ||
| 172 | */ | ||
| 173 | int drm_fb_helper_debug_leave(struct fb_info *info) | ||
| 174 | { | ||
| 175 | struct drm_fb_helper *helper = info->par; | ||
| 176 | struct drm_client_dev *client = &helper->client; | ||
| 177 | struct drm_device *dev = helper->dev; | ||
| 178 | struct drm_crtc *crtc; | ||
| 179 | const struct drm_crtc_helper_funcs *funcs; | ||
| 180 | struct drm_mode_set *mode_set; | ||
| 181 | struct drm_framebuffer *fb; | ||
| 182 | |||
| 183 | mutex_lock(&client->modeset_mutex); | ||
| 184 | drm_client_for_each_modeset(mode_set, client) { | ||
| 185 | crtc = mode_set->crtc; | ||
| 186 | if (drm_drv_uses_atomic_modeset(crtc->dev)) | ||
| 187 | continue; | ||
| 188 | |||
| 189 | funcs = crtc->helper_private; | ||
| 190 | fb = crtc->primary->fb; | ||
| 191 | |||
| 192 | if (!crtc->enabled) | ||
| 193 | continue; | ||
| 194 | |||
| 195 | if (!fb) { | ||
| 196 | drm_err(dev, "no fb to restore?\n"); | ||
| 197 | continue; | ||
| 198 | } | ||
| 199 | |||
| 200 | if (funcs->mode_set_base_atomic == NULL) | ||
| 201 | continue; | ||
| 202 | |||
| 203 | drm_fb_helper_restore_lut_atomic(mode_set->crtc); | ||
| 204 | funcs->mode_set_base_atomic(mode_set->crtc, fb, crtc->x, | ||
| 205 | crtc->y, LEAVE_ATOMIC_MODE_SET); | ||
| 206 | } | ||
| 207 | mutex_unlock(&client->modeset_mutex); | ||
| 208 | |||
| 209 | return 0; | ||
| 210 | } | ||
| 211 | EXPORT_SYMBOL(drm_fb_helper_debug_leave); | ||
| 212 | |||
| 213 | static int | 115 | static int |
| 214 | __drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper, | 116 | __drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper, |
| 215 | bool force) | 117 | bool force) |
| @@ -397,7 +299,6 @@ void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper, · 181 unmodified lines | |||
| 397 | if (!preferred_bpp) | 299 | if (!preferred_bpp) |
| 398 | preferred_bpp = 32; | 300 | preferred_bpp = 32; |
| 399 | 301 | ||
| 400 | INIT_LIST_HEAD(&helper->kernel_fb_list); | ||
| 401 | spin_lock_init(&helper->damage_lock); | 302 | spin_lock_init(&helper->damage_lock); |
| 402 | INIT_WORK(&helper->resume_work, drm_fb_helper_resume_worker); | 303 | INIT_WORK(&helper->resume_work, drm_fb_helper_resume_worker); |
| 403 | INIT_WORK(&helper->damage_work, drm_fb_helper_damage_work); | 304 | INIT_WORK(&helper->damage_work, drm_fb_helper_damage_work); |
| @@ -534,11 +435,6 @@ void drm_fb_helper_fini(struct drm_fb_helper *fb_helper) · 130 unmodified lines | |||
| 534 | 435 | ||
| 535 | drm_fb_helper_release_info(fb_helper); | 436 | drm_fb_helper_release_info(fb_helper); |
| 536 | 437 | ||
| 537 | mutex_lock(&kernel_fb_helper_lock); | ||
| 538 | if (!list_empty(&fb_helper->kernel_fb_list)) | ||
| 539 | list_del(&fb_helper->kernel_fb_list); | ||
| 540 | mutex_unlock(&kernel_fb_helper_lock); | ||
| 541 | |||
| 542 | if (!fb_helper->client.funcs) | 438 | if (!fb_helper->client.funcs) |
| 543 | drm_client_release(&fb_helper->client); | 439 | drm_client_release(&fb_helper->client); |
| 544 | } | 440 | } |
| @@ -1766,10 +1662,6 @@ __drm_fb_helper_initial_config_and_unlock(struct drm_fb_helper *fb_helper) · 1221 unmodified lines | |||
| 1766 | drm_info(dev, "fb%d: %s frame buffer device\n", | 1662 | drm_info(dev, "fb%d: %s frame buffer device\n", |
| 1767 | info->node, info->fix.id); | 1663 | info->node, info->fix.id); |
| 1768 | 1664 | ||
| 1769 | mutex_lock(&kernel_fb_helper_lock); | ||
| 1770 | list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list); | ||
| 1771 | mutex_unlock(&kernel_fb_helper_lock); | ||
| 1772 | |||
| 1773 | return 0; | 1665 | return 0; |
| 1774 | 1666 | ||
| 1775 | err_drm_fb_helper_release_info: | 1667 | err_drm_fb_helper_release_info: |
| @@ -29,6 +29,9 @@ · 28 unmodified lines | |||
| 29 | #include <linux/export.h> | 29 | #include <linux/export.h> |
| 30 | #include <linux/file.h> | 30 | #include <linux/file.h> |
| 31 | #include <linux/fs.h> | 31 | #include <linux/fs.h> |
| 32 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE | ||
| 33 | #include <linux/fs_context.h> | ||
| 34 | #endif | ||
| 32 | #include <linux/iosys-map.h> | 35 | #include <linux/iosys-map.h> |
| 33 | #include <linux/mem_encrypt.h> | 36 | #include <linux/mem_encrypt.h> |
| 34 | #include <linux/mm.h> | 37 | #include <linux/mm.h> |
| @@ -36,6 +39,7 @@ · 1 unmodified line | |||
| 36 | #include <linux/module.h> | 39 | #include <linux/module.h> |
| 37 | #include <linux/pagemap.h> | 40 | #include <linux/pagemap.h> |
| 38 | #include <linux/pagevec.h> | 41 | #include <linux/pagevec.h> |
| 42 | #include <linux/sched/mm.h> | ||
| 39 | #include <linux/shmem_fs.h> | 43 | #include <linux/shmem_fs.h> |
| 40 | #include <linux/slab.h> | 44 | #include <linux/slab.h> |
| 41 | #include <linux/string_helpers.h> | 45 | #include <linux/string_helpers.h> |
| @@ -81,6 +85,60 @@ · 39 unmodified lines | |||
| 81 | * up at a later date, and as our interface with shmfs for memory allocation. | 85 | * up at a later date, and as our interface with shmfs for memory allocation. |
| 82 | */ | 86 | */ |
| 83 | 87 | ||
| 88 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE | ||
| 89 | static void drm_gem_huge_mnt_free(struct drm_device *dev, void *data) | ||
| 90 | { | ||
| 91 | kern_unmount(dev->huge_mnt); | ||
| 92 | } | ||
| 93 | |||
| 94 | /** | ||
| 95 | * drm_gem_huge_mnt_create - Create, mount and use a huge tmpfs mountpoint | ||
| 96 | * @dev: DRM device that will use the huge tmpfs mountpoint | ||
| 97 | * @value: huge tmpfs mount option value | ||
| 98 | * | ||
| 99 | * This function creates and mounts a dedicated huge tmpfs mountpoint for the | ||
| 100 | * lifetime of the DRM device @dev which is used at GEM object initialization | ||
| 101 | * with drm_gem_object_init(). | ||
| 102 | * | ||
| 103 | * The most common option for @value is "within_size" which only allocates huge | ||
| 104 | * pages if the page will be fully within the GEM object size. "always", | ||
| 105 | * "advise" and "never" are supported too but the latter would just create a | ||
| 106 | * mountpoint similar to the default one (`shm_mnt`). See shmemfs and | ||
| 107 | * Transparent Hugepage for more information. | ||
| 108 | * | ||
| 109 | * Returns: | ||
| 110 | * 0 on success or a negative error code on failure. | ||
| 111 | */ | ||
| 112 | int drm_gem_huge_mnt_create(struct drm_device *dev, const char *value) | ||
| 113 | { | ||
| 114 | struct file_system_type *type; | ||
| 115 | struct fs_context *fc; | ||
| 116 | int ret; | ||
| 117 | |||
| 118 | if (unlikely(drm_gem_get_huge_mnt(dev))) | ||
| 119 | return 0; | ||
| 120 | |||
| 121 | type = get_fs_type("tmpfs"); | ||
| 122 | if (unlikely(!type)) | ||
| 123 | return -EOPNOTSUPP; | ||
| 124 | fc = fs_context_for_mount(type, SB_KERNMOUNT); | ||
| 125 | if (IS_ERR(fc)) | ||
| 126 | return PTR_ERR(fc); | ||
| 127 | ret = vfs_parse_fs_string(fc, "source", "tmpfs"); | ||
| 128 | if (unlikely(ret)) | ||
| 129 | return -ENOPARAM; | ||
| 130 | ret = vfs_parse_fs_string(fc, "huge", value); | ||
| 131 | if (unlikely(ret)) | ||
| 132 | return -ENOPARAM; | ||
| 133 | |||
| 134 | dev->huge_mnt = fc_mount_longterm(fc); | ||
| 135 | put_fs_context(fc); | ||
| 136 | |||
| 137 | return drmm_add_action_or_reset(dev, drm_gem_huge_mnt_free, NULL); | ||
| 138 | } | ||
| 139 | EXPORT_SYMBOL_GPL(drm_gem_huge_mnt_create); | ||
| 140 | #endif | ||
| 141 | |||
| 84 | static void | 142 | static void |
| 85 | drm_gem_init_release(struct drm_device *dev, void *ptr) | 143 | drm_gem_init_release(struct drm_device *dev, void *ptr) |
| 86 | { | 144 | { |
| @@ -113,29 +171,28 @@ drm_gem_init(struct drm_device *dev) · 26 unmodified lines | |||
| 113 | } | 171 | } |
| 114 | 172 | ||
| 115 | /** | 173 | /** |
| 116 | * drm_gem_object_init_with_mnt - initialize an allocated shmem-backed GEM | 174 | * drm_gem_object_init - initialize an allocated shmem-backed GEM object |
| 117 | * object in a given shmfs mountpoint | ||
| 118 | * | 175 | * |
| 119 | * @dev: drm_device the object should be initialized for | 176 | * @dev: drm_device the object should be initialized for |
| 120 | * @obj: drm_gem_object to initialize | 177 | * @obj: drm_gem_object to initialize |
| 121 | * @size: object size | 178 | * @size: object size |
| 122 | * @gemfs: tmpfs mount where the GEM object will be created. If NULL, use | ||
| 123 | * the usual tmpfs mountpoint (`shm_mnt`). | ||
| 124 | * | 179 | * |
| 125 | * Initialize an already allocated GEM object of the specified size with | 180 | * Initialize an already allocated GEM object of the specified size with |
| 126 | * shmfs backing store. | 181 | * shmfs backing store. A huge mountpoint can be used by calling |
| 182 | * drm_gem_huge_mnt_create() beforehand. | ||
| 127 | */ | 183 | */ |
| 128 | int drm_gem_object_init_with_mnt(struct drm_device *dev, | 184 | int drm_gem_object_init(struct drm_device *dev, struct drm_gem_object *obj, |
| 129 | struct drm_gem_object *obj, size_t size, | 185 | size_t size) |
| 130 | struct vfsmount *gemfs) | ||
| 131 | { | 186 | { |
| 187 | struct vfsmount *huge_mnt; | ||
| 132 | struct file *filp; | 188 | struct file *filp; |
| 133 | 189 | ||
| 134 | drm_gem_private_object_init(dev, obj, size); | 190 | drm_gem_private_object_init(dev, obj, size); |
| 135 | 191 | ||
| 136 | if (gemfs) | 192 | huge_mnt = drm_gem_get_huge_mnt(dev); |
| 137 | filp = shmem_file_setup_with_mnt(gemfs, "drm mm object", size, | 193 | if (huge_mnt) |
| 138 | VM_NORESERVE); | 194 | filp = shmem_file_setup_with_mnt(huge_mnt, "drm mm object", |
| 195 | size, VM_NORESERVE); | ||
| 139 | else | 196 | else |
| 140 | filp = shmem_file_setup("drm mm object", size, VM_NORESERVE); | 197 | filp = shmem_file_setup("drm mm object", size, VM_NORESERVE); |
| 141 | 198 | ||
| @@ -146,22 +203,6 @@ int drm_gem_object_init_with_mnt(struct drm_device *dev, · 4 unmodified lines | |||
| 146 | 203 | ||
| 147 | return 0; | 204 | return 0; |
| 148 | } | 205 | } |
| 149 | EXPORT_SYMBOL(drm_gem_object_init_with_mnt); | ||
| 150 | |||
| 151 | /** | ||
| 152 | * drm_gem_object_init - initialize an allocated shmem-backed GEM object | ||
| 153 | * @dev: drm_device the object should be initialized for | ||
| 154 | * @obj: drm_gem_object to initialize | ||
| 155 | * @size: object size | ||
| 156 | * | ||
| 157 | * Initialize an already allocated GEM object of the specified size with | ||
| 158 | * shmfs backing store. | ||
| 159 | */ | ||
| 160 | int drm_gem_object_init(struct drm_device *dev, struct drm_gem_object *obj, | ||
| 161 | size_t size) | ||
| 162 | { | ||
| 163 | return drm_gem_object_init_with_mnt(dev, obj, size, NULL); | ||
| 164 | } | ||
| 165 | EXPORT_SYMBOL(drm_gem_object_init); | 206 | EXPORT_SYMBOL(drm_gem_object_init); |
| 166 | 207 | ||
| 167 | /** | 208 | /** |
| @@ -1181,36 +1222,27 @@ err_drm_gem_object_put: · 1013 unmodified lines | |||
| 1181 | } | 1222 | } |
| 1182 | EXPORT_SYMBOL(drm_gem_mmap_obj); | 1223 | EXPORT_SYMBOL(drm_gem_mmap_obj); |
| 1183 | 1224 | ||
| 1184 | /** | 1225 | /* |
| 1185 | * drm_gem_mmap - memory map routine for GEM objects | 1226 | * Look up a GEM object in offset space based on the exact start address. The |
| 1186 | * @filp: DRM file pointer | 1227 | * caller must be granted access to the object. Returns a GEM object on success |
| 1187 | * @vma: VMA for the area to be mapped | 1228 | * or a negative error code on failure. The returned GEM object needs to be |
| 1188 | * | 1229 | * released with drm_gem_object_put(). |
| 1189 | * If a driver supports GEM object mapping, mmap calls on the DRM file | ||
| 1190 | * descriptor will end up here. | ||
| 1191 | * | ||
| 1192 | * Look up the GEM object based on the offset passed in (vma->vm_pgoff will | ||
| 1193 | * contain the fake offset we created when the GTT map ioctl was called on | ||
| 1194 | * the object) and map it with a call to drm_gem_mmap_obj(). | ||
| 1195 | * | ||
| 1196 | * If the caller is not granted access to the buffer object, the mmap will fail | ||
| 1197 | * with EACCES. Please see the vma manager for more information. | ||
| 1198 | */ | 1230 | */ |
| 1199 | int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) | 1231 | static struct drm_gem_object * |
| 1232 | drm_gem_object_lookup_at_offset(struct file *filp, unsigned long start, | ||
| 1233 | unsigned long pages) | ||
| 1200 | { | 1234 | { |
| 1201 | struct drm_file *priv = filp->private_data; | 1235 | struct drm_file *priv = filp->private_data; |
| 1202 | struct drm_device *dev = priv->minor->dev; | 1236 | struct drm_device *dev = priv->minor->dev; |
| 1203 | struct drm_gem_object *obj = NULL; | 1237 | struct drm_gem_object *obj = NULL; |
| 1204 | struct drm_vma_offset_node *node; | 1238 | struct drm_vma_offset_node *node; |
| 1205 | int ret; | ||
| 1206 | 1239 | ||
| 1207 | if (drm_dev_is_unplugged(dev)) | 1240 | if (drm_dev_is_unplugged(dev)) |
| 1208 | return -ENODEV; | 1241 | return ERR_PTR(-ENODEV); |
| 1209 | 1242 | ||
| 1210 | drm_vma_offset_lock_lookup(dev->vma_offset_manager); | 1243 | drm_vma_offset_lock_lookup(dev->vma_offset_manager); |
| 1211 | node = drm_vma_offset_exact_lookup_locked(dev->vma_offset_manager, | 1244 | node = drm_vma_offset_exact_lookup_locked(dev->vma_offset_manager, |
| 1212 | vma->vm_pgoff, | 1245 | start, pages); |
| 1213 | vma_pages(vma)); | ||
| 1214 | if (likely(node)) { | 1246 | if (likely(node)) { |
| 1215 | obj = container_of(node, struct drm_gem_object, vma_node); | 1247 | obj = container_of(node, struct drm_gem_object, vma_node); |
| 1216 | /* | 1248 | /* |
| @@ -1229,14 +1261,88 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) · 12 unmodified lines | |||
| 1229 | drm_vma_offset_unlock_lookup(dev->vma_offset_manager); | 1261 | drm_vma_offset_unlock_lookup(dev->vma_offset_manager); |
| 1230 | 1262 | ||
| 1231 | if (!obj) | 1263 | if (!obj) |
| 1232 | return -EINVAL; | 1264 | return ERR_PTR(-EINVAL); |
| 1233 | 1265 | ||
| 1234 | if (!drm_vma_node_is_allowed(node, priv)) { | 1266 | if (!drm_vma_node_is_allowed(node, priv)) { |
| 1235 | drm_gem_object_put(obj); | 1267 | drm_gem_object_put(obj); |
| 1236 | return -EACCES; | 1268 | return ERR_PTR(-EACCES); |
| 1237 | } | 1269 | } |
| 1238 | 1270 | ||
| 1239 | ret = drm_gem_mmap_obj(obj, drm_vma_node_size(node) << PAGE_SHIFT, | 1271 | return obj; |
| 1272 | } | ||
| 1273 | |||
| 1274 | #ifdef CONFIG_MMU | ||
| 1275 | /** | ||
| 1276 | * drm_gem_get_unmapped_area - get memory mapping region routine for GEM objects | ||
| 1277 | * @filp: DRM file pointer | ||
| 1278 | * @uaddr: User address hint | ||
| 1279 | * @len: Mapping length | ||
| 1280 | * @pgoff: Offset (in pages) | ||
| 1281 | * @flags: Mapping flags | ||
| 1282 | * | ||
| 1283 | * If a driver supports GEM object mapping, before ending up in drm_gem_mmap(), | ||
| 1284 | * mmap calls on the DRM file descriptor will first try to find a free linear | ||
| 1285 | * address space large enough for a mapping. Since GEM objects are backed by | ||
| 1286 | * shmem buffers, this should preferably be handled by the shmem virtual memory | ||
| 1287 | * filesystem which can appropriately align addresses to huge page sizes when | ||
| 1288 | * needed. | ||
| 1289 | * | ||
| 1290 | * Look up the GEM object based on the offset passed in (vma->vm_pgoff will | ||
| 1291 | * contain the fake offset we created) and call shmem_get_unmapped_area() with | ||
| 1292 | * the right file pointer. | ||
| 1293 | * | ||
| 1294 | * If a GEM object is not available at the given offset or if the caller is not | ||
| 1295 | * granted access to it, fall back to mm_get_unmapped_area(). | ||
| 1296 | */ | ||
| 1297 | unsigned long drm_gem_get_unmapped_area(struct file *filp, unsigned long uaddr, | ||
| 1298 | unsigned long len, unsigned long pgoff, | ||
| 1299 | unsigned long flags) | ||
| 1300 | { | ||
| 1301 | struct drm_gem_object *obj; | ||
| 1302 | unsigned long ret; | ||
| 1303 | |||
| 1304 | obj = drm_gem_object_lookup_at_offset(filp, pgoff, len >> PAGE_SHIFT); | ||
| 1305 | if (IS_ERR(obj) || !obj->filp || !obj->filp->f_op->get_unmapped_area) | ||
| 1306 | return mm_get_unmapped_area(filp, uaddr, len, 0, | ||
| 1307 | flags); | ||
| 1308 | |||
| 1309 | ret = obj->filp->f_op->get_unmapped_area(obj->filp, uaddr, len, 0, | ||
| 1310 | flags); | ||
| 1311 | |||
| 1312 | drm_gem_object_put(obj); | ||
| 1313 | |||
| 1314 | return ret; | ||
| 1315 | } | ||
| 1316 | EXPORT_SYMBOL_GPL(drm_gem_get_unmapped_area); | ||
| 1317 | #endif | ||
| 1318 | |||
| 1319 | /** | ||
| 1320 | * drm_gem_mmap - memory map routine for GEM objects | ||
| 1321 | * @filp: DRM file pointer | ||
| 1322 | * @vma: VMA for the area to be mapped | ||
| 1323 | * | ||
| 1324 | * If a driver supports GEM object mapping, mmap calls on the DRM file | ||
| 1325 | * descriptor will end up here. | ||
| 1326 | * | ||
| 1327 | * Look up the GEM object based on the offset passed in (vma->vm_pgoff will | ||
| 1328 | * contain the fake offset we created) and map it with a call to | ||
| 1329 | * drm_gem_mmap_obj(). | ||
| 1330 | * | ||
| 1331 | * If the caller is not granted access to the buffer object, the mmap will fail | ||
| 1332 | * with EACCES. Please see the vma manager for more information. | ||
| 1333 | */ | ||
| 1334 | int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) | ||
| 1335 | { | ||
| 1336 | struct drm_gem_object *obj; | ||
| 1337 | int ret; | ||
| 1338 | |||
| 1339 | obj = drm_gem_object_lookup_at_offset(filp, vma->vm_pgoff, | ||
| 1340 | vma_pages(vma)); | ||
| 1341 | if (IS_ERR(obj)) | ||
| 1342 | return PTR_ERR(obj); | ||
| 1343 | |||
| 1344 | ret = drm_gem_mmap_obj(obj, | ||
| 1345 | drm_vma_node_size(&obj->vma_node) << PAGE_SHIFT, | ||
| 1240 | vma); | 1346 | vma); |
| 1241 | 1347 | ||
| 1242 | drm_gem_object_put(obj); | 1348 | drm_gem_object_put(obj); |
| @@ -50,7 +50,7 @@ static const struct drm_gem_object_funcs drm_gem_shmem_funcs = { · 49 unmodified lines | |||
| 50 | }; | 50 | }; |
| 51 | 51 | ||
| 52 | static int __drm_gem_shmem_init(struct drm_device *dev, struct drm_gem_shmem_object *shmem, | 52 | static int __drm_gem_shmem_init(struct drm_device *dev, struct drm_gem_shmem_object *shmem, |
| 53 | size_t size, bool private, struct vfsmount *gemfs) | 53 | size_t size, bool private) |
| 54 | { | 54 | { |
| 55 | struct drm_gem_object *obj = &shmem->base; | 55 | struct drm_gem_object *obj = &shmem->base; |
| 56 | int ret = 0; | 56 | int ret = 0; |
| @@ -62,7 +62,7 @@ static int __drm_gem_shmem_init(struct drm_device *dev, struct drm_gem_shmem_obj · 5 unmodified lines | |||
| 62 | drm_gem_private_object_init(dev, obj, size); | 62 | drm_gem_private_object_init(dev, obj, size); |
| 63 | shmem->map_wc = false; /* dma-buf mappings use always writecombine */ | 63 | shmem->map_wc = false; /* dma-buf mappings use always writecombine */ |
| 64 | } else { | 64 | } else { |
| 65 | ret = drm_gem_object_init_with_mnt(dev, obj, size, gemfs); | 65 | ret = drm_gem_object_init(dev, obj, size); |
| 66 | } | 66 | } |
| 67 | if (ret) { | 67 | if (ret) { |
| 68 | drm_gem_private_object_fini(obj); | 68 | drm_gem_private_object_fini(obj); |
| @@ -103,13 +103,12 @@ err_release: · 34 unmodified lines | |||
| 103 | */ | 103 | */ |
| 104 | int drm_gem_shmem_init(struct drm_device *dev, struct drm_gem_shmem_object *shmem, size_t size) | 104 | int drm_gem_shmem_init(struct drm_device *dev, struct drm_gem_shmem_object *shmem, size_t size) |
| 105 | { | 105 | { |
| 106 | return __drm_gem_shmem_init(dev, shmem, size, false, NULL); | 106 | return __drm_gem_shmem_init(dev, shmem, size, false); |
| 107 | } | 107 | } |
| 108 | EXPORT_SYMBOL_GPL(drm_gem_shmem_init); | 108 | EXPORT_SYMBOL_GPL(drm_gem_shmem_init); |
| 109 | 109 | ||
| 110 | static struct drm_gem_shmem_object * | 110 | static struct drm_gem_shmem_object * |
| 111 | __drm_gem_shmem_create(struct drm_device *dev, size_t size, bool private, | 111 | __drm_gem_shmem_create(struct drm_device *dev, size_t size, bool private) |
| 112 | struct vfsmount *gemfs) | ||
| 113 | { | 112 | { |
| 114 | struct drm_gem_shmem_object *shmem; | 113 | struct drm_gem_shmem_object *shmem; |
| 115 | struct drm_gem_object *obj; | 114 | struct drm_gem_object *obj; |
| @@ -129,7 +128,7 @@ __drm_gem_shmem_create(struct drm_device *dev, size_t size, bool private, · 13 unmodified lines | |||
| 129 | obj = &shmem->base; | 128 | obj = &shmem->base; |
| 130 | } | 129 | } |
| 131 | 130 | ||
| 132 | ret = __drm_gem_shmem_init(dev, shmem, size, private, gemfs); | 131 | ret = __drm_gem_shmem_init(dev, shmem, size, private); |
| 133 | if (ret) { | 132 | if (ret) { |
| 134 | kfree(obj); | 133 | kfree(obj); |
| 135 | return ERR_PTR(ret); | 134 | return ERR_PTR(ret); |
| @@ -150,31 +149,10 @@ __drm_gem_shmem_create(struct drm_device *dev, size_t size, bool private, · 14 unmodified lines | |||
| 150 | */ | 149 | */ |
| 151 | struct drm_gem_shmem_object *drm_gem_shmem_create(struct drm_device *dev, size_t size) | 150 | struct drm_gem_shmem_object *drm_gem_shmem_create(struct drm_device *dev, size_t size) |
| 152 | { | 151 | { |
| 153 | return __drm_gem_shmem_create(dev, size, false, NULL); | 152 | return __drm_gem_shmem_create(dev, size, false); |
| 154 | } | 153 | } |
| 155 | EXPORT_SYMBOL_GPL(drm_gem_shmem_create); | 154 | EXPORT_SYMBOL_GPL(drm_gem_shmem_create); |
| 156 | 155 | ||
| 157 | /** | ||
| 158 | * drm_gem_shmem_create_with_mnt - Allocate an object with the given size in a | ||
| 159 | * given mountpoint | ||
| 160 | * @dev: DRM device | ||
| 161 | * @size: Size of the object to allocate | ||
| 162 | * @gemfs: tmpfs mount where the GEM object will be created | ||
| 163 | * | ||
| 164 | * This function creates a shmem GEM object in a given tmpfs mountpoint. | ||
| 165 | * | ||
| 166 | * Returns: | ||
| 167 | * A struct drm_gem_shmem_object * on success or an ERR_PTR()-encoded negative | ||
| 168 | * error code on failure. | ||
| 169 | */ | ||
| 170 | struct drm_gem_shmem_object *drm_gem_shmem_create_with_mnt(struct drm_device *dev, | ||
| 171 | size_t size, | ||
| 172 | struct vfsmount *gemfs) | ||
| 173 | { | ||
| 174 | return __drm_gem_shmem_create(dev, size, false, gemfs); | ||
| 175 | } | ||
| 176 | EXPORT_SYMBOL_GPL(drm_gem_shmem_create_with_mnt); | ||
| 177 | |||
| 178 | /** | 156 | /** |
| 179 | * drm_gem_shmem_release - Release resources associated with a shmem GEM object. | 157 | * drm_gem_shmem_release - Release resources associated with a shmem GEM object. |
| 180 | * @shmem: shmem GEM object | 158 | * @shmem: shmem GEM object |
| @@ -567,6 +545,26 @@ int drm_gem_shmem_dumb_create(struct drm_file *file, struct drm_device *dev, · 386 unmodified lines | |||
| 567 | } | 545 | } |
| 568 | EXPORT_SYMBOL_GPL(drm_gem_shmem_dumb_create); | 546 | EXPORT_SYMBOL_GPL(drm_gem_shmem_dumb_create); |
| 569 | 547 | ||
| 548 | static bool drm_gem_shmem_try_map_pmd(struct vm_fault *vmf, unsigned long addr, | ||
| 549 | struct page *page) | ||
| 550 | { | ||
| 551 | #ifdef CONFIG_ARCH_SUPPORTS_PMD_PFNMAP | ||
| 552 | unsigned long pfn = page_to_pfn(page); | ||
| 553 | unsigned long paddr = pfn << PAGE_SHIFT; | ||
| 554 | bool aligned = (addr & ~PMD_MASK) == (paddr & ~PMD_MASK); | ||
| 555 | |||
| 556 | if (aligned && | ||
| 557 | pmd_none(*vmf->pmd) && | ||
| 558 | folio_test_pmd_mappable(page_folio(page))) { | ||
| 559 | pfn &= PMD_MASK >> PAGE_SHIFT; | ||
| 560 | if (vmf_insert_pfn_pmd(vmf, pfn, false) == VM_FAULT_NOPAGE) | ||
| 561 | return true; | ||
| 562 | } | ||
| 563 | #endif | ||
| 564 | |||
| 565 | return false; | ||
| 566 | } | ||
| 567 | |||
| 570 | static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf) | 568 | static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf) |
| 571 | { | 569 | { |
| 572 | struct vm_area_struct *vma = vmf->vma; | 570 | struct vm_area_struct *vma = vmf->vma; |
| @@ -574,11 +572,12 @@ static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf) · 1 unmodified line | |||
| 574 | struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); | 572 | struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); |
| 575 | loff_t num_pages = obj->size >> PAGE_SHIFT; | 573 | loff_t num_pages = obj->size >> PAGE_SHIFT; |
| 576 | vm_fault_t ret; | 574 | vm_fault_t ret; |
| 577 | struct page *page; | 575 | struct page **pages = shmem->pages; |
| 578 | pgoff_t page_offset; | 576 | pgoff_t page_offset; |
| 577 | unsigned long pfn; | ||
| 579 | 578 | ||
| 580 | /* We don't use vmf->pgoff since that has the fake offset */ | 579 | /* Offset to faulty address in the VMA. */ |
| 581 | page_offset = (vmf->address - vma->vm_start) >> PAGE_SHIFT; | 580 | page_offset = vmf->pgoff - vma->vm_pgoff; |
| 582 | 581 | ||
| 583 | dma_resv_lock(shmem->base.resv, NULL); | 582 | dma_resv_lock(shmem->base.resv, NULL); |
| 584 | 583 | ||
| @@ -586,12 +585,18 @@ static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf) · 1 unmodified line | |||
| 586 | drm_WARN_ON_ONCE(obj->dev, !shmem->pages) || | 585 | drm_WARN_ON_ONCE(obj->dev, !shmem->pages) || |
| 587 | shmem->madv < 0) { | 586 | shmem->madv < 0) { |
| 588 | ret = VM_FAULT_SIGBUS; | 587 | ret = VM_FAULT_SIGBUS; |
| 589 | } else { | 588 | goto out; |
| 590 | page = shmem->pages[page_offset]; | 589 | } |
| 591 | 590 | ||
| 592 | ret = vmf_insert_pfn(vma, vmf->address, page_to_pfn(page)); | 591 | if (drm_gem_shmem_try_map_pmd(vmf, vmf->address, pages[page_offset])) { |
| 592 | ret = VM_FAULT_NOPAGE; | ||
| 593 | goto out; | ||
| 593 | } | 594 | } |
| 594 | 595 | ||
| 596 | pfn = page_to_pfn(pages[page_offset]); | ||
| 597 | ret = vmf_insert_pfn(vma, vmf->address, pfn); | ||
| 598 | |||
| 599 | out: | ||
| 595 | dma_resv_unlock(shmem->base.resv); | 600 | dma_resv_unlock(shmem->base.resv); |
| 596 | 601 | ||
| 597 | return ret; | 602 | return ret; |
| @@ -824,7 +829,7 @@ drm_gem_shmem_prime_import_sg_table(struct drm_device *dev, · 226 unmodified lines | |||
| 824 | size_t size = PAGE_ALIGN(attach->dmabuf->size); | 829 | size_t size = PAGE_ALIGN(attach->dmabuf->size); |
| 825 | struct drm_gem_shmem_object *shmem; | 830 | struct drm_gem_shmem_object *shmem; |
| 826 | 831 | ||
| 827 | shmem = __drm_gem_shmem_create(dev, size, true, NULL); | 832 | shmem = __drm_gem_shmem_create(dev, size, true); |
| 828 | if (IS_ERR(shmem)) | 833 | if (IS_ERR(shmem)) |
| 829 | return ERR_CAST(shmem); | 834 | return ERR_CAST(shmem); |
| 830 | 835 | ||
| @@ -872,7 +877,7 @@ struct drm_gem_object *drm_gem_shmem_prime_import_no_map(struct drm_device *dev, · 41 unmodified lines | |||
| 872 | 877 | ||
| 873 | size = PAGE_ALIGN(attach->dmabuf->size); | 878 | size = PAGE_ALIGN(attach->dmabuf->size); |
| 874 | 879 | ||
| 875 | shmem = __drm_gem_shmem_create(dev, size, true, NULL); | 880 | shmem = __drm_gem_shmem_create(dev, size, true); |
| 876 | if (IS_ERR(shmem)) { | 881 | if (IS_ERR(shmem)) { |
| 877 | ret = PTR_ERR(shmem); | 882 | ret = PTR_ERR(shmem); |
| 878 | goto fail_detach; | 883 | goto fail_detach; |
| @@ -39,12 +39,6 @@ MODULE_AUTHOR("Jocelyn Falempe"); · 38 unmodified lines | |||
| 39 | MODULE_DESCRIPTION("DRM panic handler"); | 39 | MODULE_DESCRIPTION("DRM panic handler"); |
| 40 | MODULE_LICENSE("GPL"); | 40 | MODULE_LICENSE("GPL"); |
| 41 | 41 | ||
| 42 | static char drm_panic_screen[16] = CONFIG_DRM_PANIC_SCREEN; | ||
| 43 | module_param_string(panic_screen, drm_panic_screen, sizeof(drm_panic_screen), 0644); | ||
| 44 | MODULE_PARM_DESC(panic_screen, | ||
| 45 | "Choose what will be displayed by drm_panic, 'user' or 'kmsg' [default=" | ||
| 46 | CONFIG_DRM_PANIC_SCREEN "]"); | ||
| 47 | |||
| 48 | /** | 42 | /** |
| 49 | * DOC: overview | 43 | * DOC: overview |
| 50 | * | 44 | * |
| @@ -813,14 +807,59 @@ static void draw_panic_static_qr_code(struct drm_scanout_buffer *sb) · 762 unmodified lines | |||
| 813 | draw_panic_static_user(sb); | 807 | draw_panic_static_user(sb); |
| 814 | } | 808 | } |
| 815 | #else | 809 | #else |
| 816 | static void draw_panic_static_qr_code(struct drm_scanout_buffer *sb) | 810 | static void drm_panic_qr_init(void) {}; |
| 811 | static void drm_panic_qr_exit(void) {}; | ||
| 812 | #endif | ||
| 813 | |||
| 814 | enum drm_panic_type { | ||
| 815 | DRM_PANIC_TYPE_KMSG, | ||
| 816 | DRM_PANIC_TYPE_USER, | ||
| 817 | DRM_PANIC_TYPE_QR, | ||
| 818 | }; | ||
| 819 | |||
| 820 | static enum drm_panic_type drm_panic_type = -1; | ||
| 821 | |||
| 822 | static const char *drm_panic_type_map[] = { | ||
| 823 | [DRM_PANIC_TYPE_KMSG] = "kmsg", | ||
| 824 | [DRM_PANIC_TYPE_USER] = "user", | ||
| 825 | #if IS_ENABLED(CONFIG_DRM_PANIC_SCREEN_QR_CODE) | ||
| 826 | [DRM_PANIC_TYPE_QR] = "qr", | ||
| 827 | #endif | ||
| 828 | }; | ||
| 829 | |||
| 830 | static int drm_panic_type_set(const char *val, const struct kernel_param *kp) | ||
| 817 | { | 831 | { |
| 818 | draw_panic_static_user(sb); | 832 | unsigned int i; |
| 833 | |||
| 834 | for (i = 0; i < ARRAY_SIZE(drm_panic_type_map); i++) { | ||
| 835 | if (!strcmp(val, drm_panic_type_map[i])) { | ||
| 836 | drm_panic_type = i; | ||
| 837 | return 0; | ||
| 838 | } | ||
| 839 | } | ||
| 840 | |||
| 841 | return -EINVAL; | ||
| 819 | } | 842 | } |
| 820 | 843 | ||
| 821 | static void drm_panic_qr_init(void) {}; | 844 | static int drm_panic_type_get(char *buffer, const struct kernel_param *kp) |
| 822 | static void drm_panic_qr_exit(void) {}; | 845 | { |
| 846 | return scnprintf(buffer, PAGE_SIZE, "%s\n", | ||
| 847 | drm_panic_type_map[drm_panic_type]); | ||
| 848 | } | ||
| 849 | |||
| 850 | static const struct kernel_param_ops drm_panic_ops = { | ||
| 851 | .set = drm_panic_type_set, | ||
| 852 | .get = drm_panic_type_get, | ||
| 853 | }; | ||
| 854 | |||
| 855 | module_param_cb(panic_screen, &drm_panic_ops, NULL, 0644); | ||
| 856 | MODULE_PARM_DESC(panic_screen, | ||
| 857 | #if IS_ENABLED(CONFIG_DRM_PANIC_SCREEN_QR_CODE) | ||
| 858 | "Choose what will be displayed by drm_panic, 'user', 'kmsg' or 'qr' [default=" | ||
| 859 | #else | ||
| 860 | "Choose what will be displayed by drm_panic, 'user' or 'kmsg' [default=" | ||
| 823 | #endif | 861 | #endif |
| 862 | CONFIG_DRM_PANIC_SCREEN "]"); | ||
| 824 | 863 | ||
| 825 | /* | 864 | /* |
| 826 | * drm_panic_is_format_supported() | 865 | * drm_panic_is_format_supported() |
| @@ -838,11 +877,19 @@ static bool drm_panic_is_format_supported(const struct drm_format_info *format) · 11 unmodified lines | |||
| 838 | 877 | ||
| 839 | static void draw_panic_dispatch(struct drm_scanout_buffer *sb) | 878 | static void draw_panic_dispatch(struct drm_scanout_buffer *sb) |
| 840 | { | 879 | { |
| 841 | if (!strcmp(drm_panic_screen, "kmsg")) { | 880 | switch (drm_panic_type) { |
| 881 | case DRM_PANIC_TYPE_KMSG: | ||
| 842 | draw_panic_static_kmsg(sb); | 882 | draw_panic_static_kmsg(sb); |
| 843 | } else if (!strcmp(drm_panic_screen, "qr_code")) { | 883 | break; |
| 884 | |||
| 885 | #if IS_ENABLED(CONFIG_DRM_PANIC_SCREEN_QR_CODE) | ||
| 886 | case DRM_PANIC_TYPE_QR: | ||
| 844 | draw_panic_static_qr_code(sb); | 887 | draw_panic_static_qr_code(sb); |
| 845 | } else { | 888 | break; |
| 889 | #endif | ||
| 890 | |||
| 891 | case DRM_PANIC_TYPE_USER: | ||
| 892 | default: | ||
| 846 | draw_panic_static_user(sb); | 893 | draw_panic_static_user(sb); |
| 847 | } | 894 | } |
| 848 | } | 895 | } |
| @@ -1025,6 +1072,8 @@ void drm_panic_unregister(struct drm_device *dev) · 176 unmodified lines | |||
| 1025 | */ | 1072 | */ |
| 1026 | void __init drm_panic_init(void) | 1073 | void __init drm_panic_init(void) |
| 1027 | { | 1074 | { |
| 1075 | if (drm_panic_type == -1) | ||
| 1076 | drm_panic_type_set(CONFIG_DRM_PANIC_SCREEN, NULL); | ||
| 1028 | drm_panic_qr_init(); | 1077 | drm_panic_qr_init(); |
| 1029 | } | 1078 | } |
| 1030 | 1079 | ||
| @@ -1867,9 +1867,9 @@ int drm_plane_create_color_pipeline_property(struct drm_plane *plane, · 1866 unmodified lines | |||
| 1867 | prop = drm_property_create_enum(plane->dev, DRM_MODE_PROP_ATOMIC, | 1867 | prop = drm_property_create_enum(plane->dev, DRM_MODE_PROP_ATOMIC, |
| 1868 | "COLOR_PIPELINE", | 1868 | "COLOR_PIPELINE", |
| 1869 | all_pipelines, len); | 1869 | all_pipelines, len); |
| 1870 | if (IS_ERR(prop)) { | 1870 | if (!prop) { |
| 1871 | kfree(all_pipelines); | 1871 | kfree(all_pipelines); |
| 1872 | return PTR_ERR(prop); | 1872 | return -ENOMEM; |
| 1873 | } | 1873 | } |
| 1874 | 1874 | ||
| 1875 | drm_object_attach_property(&plane->base, prop, 0); | 1875 | drm_object_attach_property(&plane->base, prop, 0); |
| @@ -551,7 +551,7 @@ int drm_vblank_init(struct drm_device *dev, unsigned int num_crtcs) · 550 unmodified lines | |||
| 551 | dev->num_crtcs = num_crtcs; | 551 | dev->num_crtcs = num_crtcs; |
| 552 | 552 | ||
| 553 | for (i = 0; i < num_crtcs; i++) { | 553 | for (i = 0; i < num_crtcs; i++) { |
| 554 | struct drm_vblank_crtc *vblank = &dev->vblank[i]; | 554 | struct drm_vblank_crtc *vblank = drm_vblank_crtc(dev, i); |
| 555 | 555 | ||
| 556 | vblank->dev = dev; | 556 | vblank->dev = dev; |
| 557 | vblank->pipe = i; | 557 | vblank->pipe = i; |
| @@ -605,7 +605,9 @@ EXPORT_SYMBOL(drm_dev_has_vblank); · 47 unmodified lines | |||
| 605 | */ | 605 | */ |
| 606 | wait_queue_head_t *drm_crtc_vblank_waitqueue(struct drm_crtc *crtc) | 606 | wait_queue_head_t *drm_crtc_vblank_waitqueue(struct drm_crtc *crtc) |
| 607 | { | 607 | { |
| 608 | return &crtc->dev->vblank[drm_crtc_index(crtc)].queue; | 608 | struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc); |
| 609 | |||
| 610 | return &vblank->queue; | ||
| 609 | } | 611 | } |
| 610 | EXPORT_SYMBOL(drm_crtc_vblank_waitqueue); | 612 | EXPORT_SYMBOL(drm_crtc_vblank_waitqueue); |
| 611 | 613 | ||
| @@ -710,7 +712,6 @@ drm_crtc_vblank_helper_get_vblank_timestamp_internal( · 98 unmodified lines | |||
| 710 | { | 712 | { |
| 711 | struct drm_device *dev = crtc->dev; | 713 | struct drm_device *dev = crtc->dev; |
| 712 | unsigned int pipe = crtc->index; | 714 | unsigned int pipe = crtc->index; |
| 713 | struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; | ||
| 714 | struct timespec64 ts_etime, ts_vblank_time; | 715 | struct timespec64 ts_etime, ts_vblank_time; |
| 715 | ktime_t stime, etime; | 716 | ktime_t stime, etime; |
| 716 | bool vbl_status; | 717 | bool vbl_status; |
| @@ -729,10 +730,13 @@ drm_crtc_vblank_helper_get_vblank_timestamp_internal( · 12 unmodified lines | |||
| 729 | return false; | 730 | return false; |
| 730 | } | 731 | } |
| 731 | 732 | ||
| 732 | if (drm_drv_uses_atomic_modeset(dev)) | 733 | if (drm_drv_uses_atomic_modeset(dev)) { |
| 734 | struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc); | ||
| 735 | |||
| 733 | mode = &vblank->hwmode; | 736 | mode = &vblank->hwmode; |
| 734 | else | 737 | } else { |
| 735 | mode = &crtc->hwmode; | 738 | mode = &crtc->hwmode; |
| 739 | } | ||
| 736 | 740 | ||
| 737 | /* If mode timing undefined, just return as no-op: | 741 | /* If mode timing undefined, just return as no-op: |
| 738 | * Happens during initial modesetting of a crtc. | 742 | * Happens during initial modesetting of a crtc. |
| @@ -1285,29 +1289,27 @@ void drm_crtc_vblank_put(struct drm_crtc *crtc) · 546 unmodified lines | |||
| 1285 | EXPORT_SYMBOL(drm_crtc_vblank_put); | 1289 | EXPORT_SYMBOL(drm_crtc_vblank_put); |
| 1286 | 1290 | ||
| 1287 | /** | 1291 | /** |
| 1288 | * drm_wait_one_vblank - wait for one vblank | 1292 | * drm_crtc_wait_one_vblank - wait for one vblank |
| 1289 | * @dev: DRM device | 1293 | * @crtc: DRM crtc |
| 1290 | * @pipe: CRTC index | ||
| 1291 | * | 1294 | * |
| 1292 | * This waits for one vblank to pass on @pipe, using the irq driver interfaces. | 1295 | * This waits for one vblank to pass on @crtc, using the irq driver interfaces. |
| 1293 | * It is a failure to call this when the vblank irq for @pipe is disabled, e.g. | 1296 | * It is a failure to call this when the vblank irq for @crtc is disabled, e.g. |
| 1294 | * due to lack of driver support or because the crtc is off. | 1297 | * due to lack of driver support or because the crtc is off. |
| 1295 | * | 1298 | * |
| 1296 | * This is the legacy version of drm_crtc_wait_one_vblank(). | 1299 | * Returns: 0 on success, negative error on failures. |
| 1297 | */ | 1300 | */ |
| 1298 | void drm_wait_one_vblank(struct drm_device *dev, unsigned int pipe) | 1301 | int drm_crtc_wait_one_vblank(struct drm_crtc *crtc) |
| 1299 | { | 1302 | { |
| 1300 | struct drm_vblank_crtc *vblank = drm_vblank_crtc(dev, pipe); | 1303 | struct drm_device *dev = crtc->dev; |
| 1304 | int pipe = drm_crtc_index(crtc); | ||
| 1305 | struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc); | ||
| 1301 | int ret; | 1306 | int ret; |
| 1302 | u64 last; | 1307 | u64 last; |
| 1303 | 1308 | ||
| 1304 | if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) | ||
| 1305 | return; | ||
| 1306 | |||
| 1307 | ret = drm_vblank_get(dev, pipe); | 1309 | ret = drm_vblank_get(dev, pipe); |
| 1308 | if (drm_WARN(dev, ret, "vblank not available on crtc %i, ret=%i\n", | 1310 | if (drm_WARN(dev, ret, "vblank not available on crtc %i, ret=%i\n", |
| 1309 | pipe, ret)) | 1311 | pipe, ret)) |
| 1310 | return; | 1312 | return ret; |
| 1311 | 1313 | ||
| 1312 | last = drm_vblank_count(dev, pipe); | 1314 | last = drm_vblank_count(dev, pipe); |
| 1313 | 1315 | ||
| @@ -1318,20 +1320,8 @@ void drm_wait_one_vblank(struct drm_device *dev, unsigned int pipe) · 4 unmodified lines | |||
| 1318 | drm_WARN(dev, ret == 0, "vblank wait timed out on crtc %i\n", pipe); | 1320 | drm_WARN(dev, ret == 0, "vblank wait timed out on crtc %i\n", pipe); |
| 1319 | 1321 | ||
| 1320 | drm_vblank_put(dev, pipe); | 1322 | drm_vblank_put(dev, pipe); |
| 1321 | } | ||
| 1322 | EXPORT_SYMBOL(drm_wait_one_vblank); | ||
| 1323 | 1323 | ||
| 1324 | /** | 1324 | return ret ? 0 : -ETIMEDOUT; |
| 1325 | * drm_crtc_wait_one_vblank - wait for one vblank | ||
| 1326 | * @crtc: DRM crtc | ||
| 1327 | * | ||
| 1328 | * This waits for one vblank to pass on @crtc, using the irq driver interfaces. | ||
| 1329 | * It is a failure to call this when the vblank irq for @crtc is disabled, e.g. | ||
| 1330 | * due to lack of driver support or because the crtc is off. | ||
| 1331 | */ | ||
| 1332 | void drm_crtc_wait_one_vblank(struct drm_crtc *crtc) | ||
| 1333 | { | ||
| 1334 | drm_wait_one_vblank(crtc->dev, drm_crtc_index(crtc)); | ||
| 1335 | } | 1325 | } |
| 1336 | EXPORT_SYMBOL(drm_crtc_wait_one_vblank); | 1326 | EXPORT_SYMBOL(drm_crtc_wait_one_vblank); |
| 1337 | 1327 | ||
| @@ -1794,7 +1784,7 @@ int drm_wait_vblank_ioctl(struct drm_device *dev, void *data, · 456 unmodified lines | |||
| 1794 | if (pipe >= dev->num_crtcs) | 1784 | if (pipe >= dev->num_crtcs) |
| 1795 | return -EINVAL; | 1785 | return -EINVAL; |
| 1796 | 1786 | ||
| 1797 | vblank = &dev->vblank[pipe]; | 1787 | vblank = drm_vblank_crtc(dev, pipe); |
| 1798 | 1788 | ||
| 1799 | /* If the counter is currently enabled and accurate, short-circuit | 1789 | /* If the counter is currently enabled and accurate, short-circuit |
| 1800 | * queries to return the cached timestamp of the last vblank. | 1790 | * queries to return the cached timestamp of the last vblank. |
| @@ -0,0 +1,14 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0-only | ||
| 2 | config DRM_HYPERV | ||
| 3 | tristate "DRM Support for Hyper-V synthetic video device" | ||
| 4 | depends on DRM && PCI && HYPERV_VMBUS | ||
| 5 | select DRM_CLIENT_SELECTION | ||
| 6 | select DRM_KMS_HELPER | ||
| 7 | select DRM_GEM_SHMEM_HELPER | ||
| 8 | help | ||
| 9 | This is a KMS driver for Hyper-V synthetic video device. Choose this | ||
| 10 | option if you would like to enable drm driver for Hyper-V virtual | ||
| 11 | machine. Unselect Hyper-V framebuffer driver (CONFIG_FB_HYPERV) so | ||
| 12 | that DRM driver is used by default. | ||
| 13 | |||
| 14 | If M is selected the module will be called hyperv_drm. | ||
| @@ -170,8 +170,7 @@ gem-y += \ · 169 unmodified lines | |||
| 170 | gem/i915_gem_ttm_move.o \ | 170 | gem/i915_gem_ttm_move.o \ |
| 171 | gem/i915_gem_ttm_pm.o \ | 171 | gem/i915_gem_ttm_pm.o \ |
| 172 | gem/i915_gem_userptr.o \ | 172 | gem/i915_gem_userptr.o \ |
| 173 | gem/i915_gem_wait.o \ | 173 | gem/i915_gem_wait.o |
| 174 | gem/i915_gemfs.o | ||
| 175 | i915-y += \ | 174 | i915-y += \ |
| 176 | $(gem-y) \ | 175 | $(gem-y) \ |
| 177 | i915_active.o \ | 176 | i915_active.o \ |
| @@ -348,12 +348,13 @@ struct drm_i915_gem_object { · 347 unmodified lines | |||
| 348 | */ | 348 | */ |
| 349 | #define I915_BO_ALLOC_GPU_ONLY BIT(6) | 349 | #define I915_BO_ALLOC_GPU_ONLY BIT(6) |
| 350 | #define I915_BO_ALLOC_CCS_AUX BIT(7) | 350 | #define I915_BO_ALLOC_CCS_AUX BIT(7) |
| 351 | #define I915_BO_ALLOC_NOTHP BIT(8) | ||
| 351 | /* | 352 | /* |
| 352 | * Object is allowed to retain its initial data and will not be cleared on first | 353 | * Object is allowed to retain its initial data and will not be cleared on first |
| 353 | * access if used along with I915_BO_ALLOC_USER. This is mainly to keep | 354 | * access if used along with I915_BO_ALLOC_USER. This is mainly to keep |
| 354 | * preallocated framebuffer data intact while transitioning it to i915drmfb. | 355 | * preallocated framebuffer data intact while transitioning it to i915drmfb. |
| 355 | */ | 356 | */ |
| 356 | #define I915_BO_PREALLOC BIT(8) | 357 | #define I915_BO_PREALLOC BIT(9) |
| 357 | #define I915_BO_ALLOC_FLAGS (I915_BO_ALLOC_CONTIGUOUS | \ | 358 | #define I915_BO_ALLOC_FLAGS (I915_BO_ALLOC_CONTIGUOUS | \ |
| 358 | I915_BO_ALLOC_VOLATILE | \ | 359 | I915_BO_ALLOC_VOLATILE | \ |
| 359 | I915_BO_ALLOC_CPU_CLEAR | \ | 360 | I915_BO_ALLOC_CPU_CLEAR | \ |
| @@ -362,10 +363,11 @@ struct drm_i915_gem_object { · 2 unmodified lines | |||
| 362 | I915_BO_ALLOC_PM_EARLY | \ | 363 | I915_BO_ALLOC_PM_EARLY | \ |
| 363 | I915_BO_ALLOC_GPU_ONLY | \ | 364 | I915_BO_ALLOC_GPU_ONLY | \ |
| 364 | I915_BO_ALLOC_CCS_AUX | \ | 365 | I915_BO_ALLOC_CCS_AUX | \ |
| 366 | I915_BO_ALLOC_NOTHP | \ | ||
| 365 | I915_BO_PREALLOC) | 367 | I915_BO_PREALLOC) |
| 366 | #define I915_BO_READONLY BIT(9) | 368 | #define I915_BO_READONLY BIT(10) |
| 367 | #define I915_TILING_QUIRK_BIT 10 /* unknown swizzling; do not release! */ | 369 | #define I915_TILING_QUIRK_BIT 11 /* unknown swizzling; do not release! */ |
| 368 | #define I915_BO_PROTECTED BIT(11) | 370 | #define I915_BO_PROTECTED BIT(12) |
| 369 | /** | 371 | /** |
| 370 | * @mem_flags - Mutable placement-related flags | 372 | * @mem_flags - Mutable placement-related flags |
| 371 | * | 373 | * |
| @@ -9,14 +9,16 @@ · 8 unmodified lines | |||
| 9 | #include <linux/uio.h> | 9 | #include <linux/uio.h> |
| 10 | 10 | ||
| 11 | #include <drm/drm_cache.h> | 11 | #include <drm/drm_cache.h> |
| 12 | #include <drm/drm_gem.h> | ||
| 13 | #include <drm/drm_print.h> | ||
| 12 | 14 | ||
| 13 | #include "gem/i915_gem_region.h" | 15 | #include "gem/i915_gem_region.h" |
| 14 | #include "i915_drv.h" | 16 | #include "i915_drv.h" |
| 15 | #include "i915_gem_object.h" | 17 | #include "i915_gem_object.h" |
| 16 | #include "i915_gem_tiling.h" | 18 | #include "i915_gem_tiling.h" |
| 17 | #include "i915_gemfs.h" | ||
| 18 | #include "i915_scatterlist.h" | 19 | #include "i915_scatterlist.h" |
| 19 | #include "i915_trace.h" | 20 | #include "i915_trace.h" |
| 21 | #include "i915_utils.h" | ||
| 20 | 22 | ||
| 21 | /* | 23 | /* |
| 22 | * Move folios to appropriate lru and release the batch, decrementing the | 24 | * Move folios to appropriate lru and release the batch, decrementing the |
| @@ -494,9 +496,11 @@ const struct drm_i915_gem_object_ops i915_gem_shmem_ops = { · 471 unmodified lines | |||
| 494 | 496 | ||
| 495 | static int __create_shmem(struct drm_i915_private *i915, | 497 | static int __create_shmem(struct drm_i915_private *i915, |
| 496 | struct drm_gem_object *obj, | 498 | struct drm_gem_object *obj, |
| 497 | resource_size_t size) | 499 | resource_size_t size, |
| 500 | unsigned int flags) | ||
| 498 | { | 501 | { |
| 499 | unsigned long flags = VM_NORESERVE; | 502 | unsigned long shmem_flags = VM_NORESERVE; |
| 503 | struct vfsmount *huge_mnt; | ||
| 500 | struct file *filp; | 504 | struct file *filp; |
| 501 | 505 | ||
| 502 | drm_gem_private_object_init(&i915->drm, obj, size); | 506 | drm_gem_private_object_init(&i915->drm, obj, size); |
| @@ -515,11 +519,12 @@ static int __create_shmem(struct drm_i915_private *i915, · 12 unmodified lines | |||
| 515 | if (BITS_PER_LONG == 64 && size > MAX_LFS_FILESIZE) | 519 | if (BITS_PER_LONG == 64 && size > MAX_LFS_FILESIZE) |
| 516 | return -E2BIG; | 520 | return -E2BIG; |
| 517 | 521 | ||
| 518 | if (i915->mm.gemfs) | 522 | huge_mnt = drm_gem_get_huge_mnt(&i915->drm); |
| 519 | filp = shmem_file_setup_with_mnt(i915->mm.gemfs, "i915", size, | 523 | if (!(flags & I915_BO_ALLOC_NOTHP) && huge_mnt) |
| 520 | flags); | 524 | filp = shmem_file_setup_with_mnt(huge_mnt, "i915", size, |
| 525 | shmem_flags); | ||
| 521 | else | 526 | else |
| 522 | filp = shmem_file_setup("i915", size, flags); | 527 | filp = shmem_file_setup("i915", size, shmem_flags); |
| 523 | if (IS_ERR(filp)) | 528 | if (IS_ERR(filp)) |
| 524 | return PTR_ERR(filp); | 529 | return PTR_ERR(filp); |
| 525 | 530 | ||
| @@ -548,7 +553,7 @@ static int shmem_object_init(struct intel_memory_region *mem, · 22 unmodified lines | |||
| 548 | gfp_t mask; | 553 | gfp_t mask; |
| 549 | int ret; | 554 | int ret; |
| 550 | 555 | ||
| 551 | ret = __create_shmem(i915, &obj->base, size); | 556 | ret = __create_shmem(i915, &obj->base, size, flags); |
| 552 | if (ret) | 557 | if (ret) |
| 553 | return ret; | 558 | return ret; |
| 554 | 559 | ||
| @@ -644,21 +649,40 @@ fail: · 89 unmodified lines | |||
| 644 | 649 | ||
| 645 | static int init_shmem(struct intel_memory_region *mem) | 650 | static int init_shmem(struct intel_memory_region *mem) |
| 646 | { | 651 | { |
| 647 | i915_gemfs_init(mem->i915); | 652 | struct drm_i915_private *i915 = mem->i915; |
| 648 | intel_memory_region_set_name(mem, "system"); | ||
| 649 | 653 | ||
| 650 | return 0; /* We have fallback to the kernel mnt if gemfs init failed. */ | 654 | /* |
| 651 | } | 655 | * By creating our own shmemfs mountpoint, we can pass in |
| 656 | * mount flags that better match our usecase. | ||
| 657 | * | ||
| 658 | * One example, although it is probably better with a per-file | ||
| 659 | * control, is selecting huge page allocations ("huge=within_size"). | ||
| 660 | * However, we only do so on platforms which benefit from it, or to | ||
| 661 | * offset the overhead of iommu lookups, where with latter it is a net | ||
| 662 | * win even on platforms which would otherwise see some performance | ||
| 663 | * regressions such a slow reads issue on Broadwell and Skylake. | ||
| 664 | */ | ||
| 652 | 665 | ||
| 653 | static int release_shmem(struct intel_memory_region *mem) | 666 | if (GRAPHICS_VER(i915) < 11 && !i915_vtd_active(i915)) |
| 654 | { | 667 | goto no_thp; |
| 655 | i915_gemfs_fini(mem->i915); | 668 | |
| 656 | return 0; | 669 | drm_gem_huge_mnt_create(&i915->drm, "within_size"); |
| 670 | if (drm_gem_get_huge_mnt(&i915->drm)) | ||
| 671 | drm_info(&i915->drm, "Using Transparent Hugepages\n"); | ||
| 672 | else | ||
| 673 | drm_notice(&i915->drm, | ||
| 674 | "Transparent Hugepage support is recommended for optimal performance%s\n", | ||
| 675 | GRAPHICS_VER(i915) >= 11 ? " on this platform!" : | ||
| 676 | " when IOMMU is enabled!"); | ||
| 677 | |||
| 678 | no_thp: | ||
| 679 | intel_memory_region_set_name(mem, "system"); | ||
| 680 | |||
| 681 | return 0; /* We have fallback to the kernel mnt if huge mnt failed. */ | ||
| 657 | } | 682 | } |
| 658 | 683 | ||
| 659 | static const struct intel_memory_region_ops shmem_region_ops = { | 684 | static const struct intel_memory_region_ops shmem_region_ops = { |
| 660 | .init = init_shmem, | 685 | .init = init_shmem, |
| 661 | .release = release_shmem, | ||
| 662 | .init_object = shmem_object_init, | 686 | .init_object = shmem_object_init, |
| 663 | }; | 687 | }; |
| 664 | 688 | ||
| @@ -1,71 +0,0 @@ | |||
| 1 | // SPDX-License-Identifier: MIT | ||
| 2 | /* | ||
| 3 | * Copyright © 2017 Intel Corporation | ||
| 4 | */ | ||
| 5 | |||
| 6 | #include <linux/fs.h> | ||
| 7 | #include <linux/mount.h> | ||
| 8 | #include <linux/fs_context.h> | ||
| 9 | |||
| 10 | #include <drm/drm_print.h> | ||
| 11 | |||
| 12 | #include "i915_drv.h" | ||
| 13 | #include "i915_gemfs.h" | ||
| 14 | #include "i915_utils.h" | ||
| 15 | |||
| 16 | void i915_gemfs_init(struct drm_i915_private *i915) | ||
| 17 | { | ||
| 18 | struct file_system_type *type; | ||
| 19 | struct fs_context *fc; | ||
| 20 | struct vfsmount *gemfs; | ||
| 21 | int ret; | ||
| 22 | |||
| 23 | /* | ||
| 24 | * By creating our own shmemfs mountpoint, we can pass in | ||
| 25 | * mount flags that better match our usecase. | ||
| 26 | * | ||
| 27 | * One example, although it is probably better with a per-file | ||
| 28 | * control, is selecting huge page allocations ("huge=within_size"). | ||
| 29 | * However, we only do so on platforms which benefit from it, or to | ||
| 30 | * offset the overhead of iommu lookups, where with latter it is a net | ||
| 31 | * win even on platforms which would otherwise see some performance | ||
| 32 | * regressions such a slow reads issue on Broadwell and Skylake. | ||
| 33 | */ | ||
| 34 | |||
| 35 | if (GRAPHICS_VER(i915) < 11 && !i915_vtd_active(i915)) | ||
| 36 | return; | ||
| 37 | |||
| 38 | if (!IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) | ||
| 39 | goto err; | ||
| 40 | |||
| 41 | type = get_fs_type("tmpfs"); | ||
| 42 | if (!type) | ||
| 43 | goto err; | ||
| 44 | |||
| 45 | fc = fs_context_for_mount(type, SB_KERNMOUNT); | ||
| 46 | if (IS_ERR(fc)) | ||
| 47 | goto err; | ||
| 48 | ret = vfs_parse_fs_string(fc, "source", "tmpfs"); | ||
| 49 | if (!ret) | ||
| 50 | ret = vfs_parse_fs_string(fc, "huge", "within_size"); | ||
| 51 | if (!ret) | ||
| 52 | gemfs = fc_mount_longterm(fc); | ||
| 53 | put_fs_context(fc); | ||
| 54 | if (ret) | ||
| 55 | goto err; | ||
| 56 | |||
| 57 | i915->mm.gemfs = gemfs; | ||
| 58 | drm_info(&i915->drm, "Using Transparent Hugepages\n"); | ||
| 59 | return; | ||
| 60 | |||
| 61 | err: | ||
| 62 | drm_notice(&i915->drm, | ||
| 63 | "Transparent Hugepage support is recommended for optimal performance%s\n", | ||
| 64 | GRAPHICS_VER(i915) >= 11 ? " on this platform!" : | ||
| 65 | " when IOMMU is enabled!"); | ||
| 66 | } | ||
| 67 | |||
| 68 | void i915_gemfs_fini(struct drm_i915_private *i915) | ||
| 69 | { | ||
| 70 | kern_unmount(i915->mm.gemfs); | ||
| 71 | } | ||
| @@ -1,14 +0,0 @@ | |||
| 1 | /* SPDX-License-Identifier: MIT */ | ||
| 2 | /* | ||
| 3 | * Copyright © 2017 Intel Corporation | ||
| 4 | */ | ||
| 5 | |||
| 6 | #ifndef __I915_GEMFS_H__ | ||
| 7 | #define __I915_GEMFS_H__ | ||
| 8 | |||
| 9 | struct drm_i915_private; | ||
| 10 | |||
| 11 | void i915_gemfs_init(struct drm_i915_private *i915); | ||
| 12 | void i915_gemfs_fini(struct drm_i915_private *i915); | ||
| 13 | |||
| 14 | #endif | ||
| @@ -1316,7 +1316,7 @@ typedef struct drm_i915_gem_object * · 1315 unmodified lines | |||
| 1316 | 1316 | ||
| 1317 | static inline bool igt_can_allocate_thp(struct drm_i915_private *i915) | 1317 | static inline bool igt_can_allocate_thp(struct drm_i915_private *i915) |
| 1318 | { | 1318 | { |
| 1319 | return i915->mm.gemfs && has_transparent_hugepage(); | 1319 | return !!drm_gem_get_huge_mnt(&i915->drm); |
| 1320 | } | 1320 | } |
| 1321 | 1321 | ||
| 1322 | static struct drm_i915_gem_object * | 1322 | static struct drm_i915_gem_object * |
| @@ -1761,7 +1761,6 @@ static int igt_tmpfs_fallback(void *arg) · 438 unmodified lines | |||
| 1761 | struct drm_i915_private *i915 = arg; | 1761 | struct drm_i915_private *i915 = arg; |
| 1762 | struct i915_address_space *vm; | 1762 | struct i915_address_space *vm; |
| 1763 | struct i915_gem_context *ctx; | 1763 | struct i915_gem_context *ctx; |
| 1764 | struct vfsmount *gemfs = i915->mm.gemfs; | ||
| 1765 | struct drm_i915_gem_object *obj; | 1764 | struct drm_i915_gem_object *obj; |
| 1766 | struct i915_vma *vma; | 1765 | struct i915_vma *vma; |
| 1767 | struct file *file; | 1766 | struct file *file; |
| @@ -1779,15 +1778,8 @@ static int igt_tmpfs_fallback(void *arg) · 11 unmodified lines | |||
| 1779 | } | 1778 | } |
| 1780 | vm = i915_gem_context_get_eb_vm(ctx); | 1779 | vm = i915_gem_context_get_eb_vm(ctx); |
| 1781 | 1780 | ||
| 1782 | /* | 1781 | obj = i915_gem_object_create_region(i915->mm.regions[INTEL_REGION_SMEM], |
| 1783 | * Make sure that we don't burst into a ball of flames upon falling back | 1782 | PAGE_SIZE, 0, I915_BO_ALLOC_NOTHP); |
| 1784 | * to tmpfs, which we rely on if on the off-chance we encounter a failure | ||
| 1785 | * when setting up gemfs. | ||
| 1786 | */ | ||
| 1787 | |||
| 1788 | i915->mm.gemfs = NULL; | ||
| 1789 | |||
| 1790 | obj = i915_gem_object_create_shmem(i915, PAGE_SIZE); | ||
| 1791 | if (IS_ERR(obj)) { | 1783 | if (IS_ERR(obj)) { |
| 1792 | err = PTR_ERR(obj); | 1784 | err = PTR_ERR(obj); |
| 1793 | goto out_restore; | 1785 | goto out_restore; |
| @@ -1819,7 +1811,6 @@ static int igt_tmpfs_fallback(void *arg) · 25 unmodified lines | |||
| 1819 | out_put: | 1811 | out_put: |
| 1820 | i915_gem_object_put(obj); | 1812 | i915_gem_object_put(obj); |
| 1821 | out_restore: | 1813 | out_restore: |
| 1822 | i915->mm.gemfs = gemfs; | ||
| 1823 | 1814 | ||
| 1824 | i915_vm_put(vm); | 1815 | i915_vm_put(vm); |
| 1825 | out: | 1816 | out: |
| @@ -141,11 +141,6 @@ struct i915_gem_mm { · 140 unmodified lines | |||
| 141 | */ | 141 | */ |
| 142 | atomic_t free_count; | 142 | atomic_t free_count; |
| 143 | 143 | ||
| 144 | /** | ||
| 145 | * tmpfs instance used for shmem backed objects | ||
| 146 | */ | ||
| 147 | struct vfsmount *gemfs; | ||
| 148 | |||
| 149 | struct intel_memory_region *regions[INTEL_REGION_UNKNOWN]; | 144 | struct intel_memory_region *regions[INTEL_REGION_UNKNOWN]; |
| 150 | 145 | ||
| 151 | struct notifier_block oom_notifier; | 146 | struct notifier_block oom_notifier; |
| @@ -837,7 +837,7 @@ nv_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, · 836 unmodified lines | |||
| 837 | static int | 837 | static int |
| 838 | nv04_crtc_do_mode_set_base(struct drm_crtc *crtc, | 838 | nv04_crtc_do_mode_set_base(struct drm_crtc *crtc, |
| 839 | struct drm_framebuffer *passed_fb, | 839 | struct drm_framebuffer *passed_fb, |
| 840 | int x, int y, bool atomic) | 840 | int x, int y) |
| 841 | { | 841 | { |
| 842 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); | 842 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); |
| 843 | struct drm_device *dev = crtc->dev; | 843 | struct drm_device *dev = crtc->dev; |
| @@ -850,19 +850,12 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc, · 6 unmodified lines | |||
| 850 | NV_DEBUG(drm, "index %d\n", nv_crtc->index); | 850 | NV_DEBUG(drm, "index %d\n", nv_crtc->index); |
| 851 | 851 | ||
| 852 | /* no fb bound */ | 852 | /* no fb bound */ |
| 853 | if (!atomic && !crtc->primary->fb) { | 853 | if (!crtc->primary->fb) { |
| 854 | NV_DEBUG(drm, "No FB bound\n"); | 854 | NV_DEBUG(drm, "No FB bound\n"); |
| 855 | return 0; | 855 | return 0; |
| 856 | } | 856 | } |
| 857 | 857 | ||
| 858 | /* If atomic, we want to switch to the fb we were passed, so | 858 | drm_fb = crtc->primary->fb; |
| 859 | * now we update pointers to do that. | ||
| 860 | */ | ||
| 861 | if (atomic) { | ||
| 862 | drm_fb = passed_fb; | ||
| 863 | } else { | ||
| 864 | drm_fb = crtc->primary->fb; | ||
| 865 | } | ||
| 866 | 859 | ||
| 867 | nvbo = nouveau_gem_object(drm_fb->obj[0]); | 860 | nvbo = nouveau_gem_object(drm_fb->obj[0]); |
| 868 | nv_crtc->fb.offset = nvbo->offset; | 861 | nv_crtc->fb.offset = nvbo->offset; |
| @@ -920,15 +913,7 @@ nv04_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, · 51 unmodified lines | |||
| 920 | int ret = nv_crtc_swap_fbs(crtc, old_fb); | 913 | int ret = nv_crtc_swap_fbs(crtc, old_fb); |
| 921 | if (ret) | 914 | if (ret) |
| 922 | return ret; | 915 | return ret; |
| 923 | return nv04_crtc_do_mode_set_base(crtc, old_fb, x, y, false); | 916 | return nv04_crtc_do_mode_set_base(crtc, old_fb, x, y); |
| 924 | } | ||
| 925 | |||
| 926 | static int | ||
| 927 | nv04_crtc_mode_set_base_atomic(struct drm_crtc *crtc, | ||
| 928 | struct drm_framebuffer *fb, | ||
| 929 | int x, int y, enum mode_set_atomic state) | ||
| 930 | { | ||
| 931 | return nv04_crtc_do_mode_set_base(crtc, fb, x, y, true); | ||
| 932 | } | 917 | } |
| 933 | 918 | ||
| 934 | static void nv04_cursor_upload(struct drm_device *dev, struct nouveau_bo *src, | 919 | static void nv04_cursor_upload(struct drm_device *dev, struct nouveau_bo *src, |
| @@ -1274,7 +1259,6 @@ static const struct drm_crtc_helper_funcs nv04_crtc_helper_funcs = { · 339 unmodified lines | |||
| 1274 | .commit = nv_crtc_commit, | 1259 | .commit = nv_crtc_commit, |
| 1275 | .mode_set = nv_crtc_mode_set, | 1260 | .mode_set = nv_crtc_mode_set, |
| 1276 | .mode_set_base = nv04_crtc_mode_set_base, | 1261 | .mode_set_base = nv04_crtc_mode_set_base, |
| 1277 | .mode_set_base_atomic = nv04_crtc_mode_set_base_atomic, | ||
| 1278 | .disable = nv_crtc_disable, | 1262 | .disable = nv_crtc_disable, |
| 1279 | .get_scanout_position = nouveau_display_scanoutpos, | 1263 | .get_scanout_position = nouveau_display_scanoutpos, |
| 1280 | }; | 1264 | }; |
| @@ -1880,6 +1880,7 @@ static const struct panel_delay delay_80_500_e50_d50 = { · 1879 unmodified lines | |||
| 1880 | */ | 1880 | */ |
| 1881 | static const struct edp_panel_entry edp_panels[] = { | 1881 | static const struct edp_panel_entry edp_panels[] = { |
| 1882 | EDP_PANEL_ENTRY('A', 'U', 'O', 0x04a4, &delay_200_500_e50, "B122UAN01.0"), | 1882 | EDP_PANEL_ENTRY('A', 'U', 'O', 0x04a4, &delay_200_500_e50, "B122UAN01.0"), |
| 1883 | EDP_PANEL_ENTRY('A', 'U', 'O', 0x0ba4, &delay_200_500_e50, "B140QAX01.H"), | ||
| 1883 | EDP_PANEL_ENTRY('A', 'U', 'O', 0x105c, &delay_200_500_e50, "B116XTN01.0"), | 1884 | EDP_PANEL_ENTRY('A', 'U', 'O', 0x105c, &delay_200_500_e50, "B116XTN01.0"), |
| 1884 | EDP_PANEL_ENTRY('A', 'U', 'O', 0x1062, &delay_200_500_e50, "B120XAN01.0"), | 1885 | EDP_PANEL_ENTRY('A', 'U', 'O', 0x1062, &delay_200_500_e50, "B120XAN01.0"), |
| 1885 | EDP_PANEL_ENTRY('A', 'U', 'O', 0x125c, &delay_200_500_e50, "Unknown"), | 1886 | EDP_PANEL_ENTRY('A', 'U', 'O', 0x125c, &delay_200_500_e50, "Unknown"), |
| @@ -1904,6 +1905,7 @@ static const struct edp_panel_entry edp_panels[] = { · 18 unmodified lines | |||
| 1904 | EDP_PANEL_ENTRY('A', 'U', 'O', 0x615c, &delay_200_500_e50, "B116XAN06.1"), | 1905 | EDP_PANEL_ENTRY('A', 'U', 'O', 0x615c, &delay_200_500_e50, "B116XAN06.1"), |
| 1905 | EDP_PANEL_ENTRY('A', 'U', 'O', 0x635c, &delay_200_500_e50, "B116XAN06.3"), | 1906 | EDP_PANEL_ENTRY('A', 'U', 'O', 0x635c, &delay_200_500_e50, "B116XAN06.3"), |
| 1906 | EDP_PANEL_ENTRY('A', 'U', 'O', 0x639c, &delay_200_500_e50, "B140HAK02.7"), | 1907 | EDP_PANEL_ENTRY('A', 'U', 'O', 0x639c, &delay_200_500_e50, "B140HAK02.7"), |
| 1908 | EDP_PANEL_ENTRY('A', 'U', 'O', 0x643d, &delay_200_500_e50, "B140HAN06.4"), | ||
| 1907 | EDP_PANEL_ENTRY('A', 'U', 'O', 0x723c, &delay_200_500_e50, "B140XTN07.2"), | 1909 | EDP_PANEL_ENTRY('A', 'U', 'O', 0x723c, &delay_200_500_e50, "B140XTN07.2"), |
| 1908 | EDP_PANEL_ENTRY('A', 'U', 'O', 0x73aa, &delay_200_500_e50, "B116XTN02.3"), | 1910 | EDP_PANEL_ENTRY('A', 'U', 'O', 0x73aa, &delay_200_500_e50, "B116XTN02.3"), |
| 1909 | EDP_PANEL_ENTRY('A', 'U', 'O', 0x8594, &delay_200_500_e50, "B133UAN01.0"), | 1911 | EDP_PANEL_ENTRY('A', 'U', 'O', 0x8594, &delay_200_500_e50, "B133UAN01.0"), |
| @@ -2033,6 +2035,7 @@ static const struct edp_panel_entry edp_panels[] = { · 123 unmodified lines | |||
| 2033 | EDP_PANEL_ENTRY('C', 'S', 'W', 0x1462, &delay_200_500_e50, "MNE007QS5-2"), | 2035 | EDP_PANEL_ENTRY('C', 'S', 'W', 0x1462, &delay_200_500_e50, "MNE007QS5-2"), |
| 2034 | EDP_PANEL_ENTRY('C', 'S', 'W', 0x1468, &delay_200_500_e50, "MNE007QB2-2"), | 2036 | EDP_PANEL_ENTRY('C', 'S', 'W', 0x1468, &delay_200_500_e50, "MNE007QB2-2"), |
| 2035 | EDP_PANEL_ENTRY('C', 'S', 'W', 0x146e, &delay_80_500_e50_d50, "MNE007QB3-1"), | 2037 | EDP_PANEL_ENTRY('C', 'S', 'W', 0x146e, &delay_80_500_e50_d50, "MNE007QB3-1"), |
| 2038 | EDP_PANEL_ENTRY('C', 'S', 'W', 0x147c, &delay_200_500_e50_d100, "MNE007QB3-1"), | ||
| 2036 | EDP_PANEL_ENTRY('C', 'S', 'W', 0x1519, &delay_200_500_e80_d50, "MNF601BS1-3"), | 2039 | EDP_PANEL_ENTRY('C', 'S', 'W', 0x1519, &delay_200_500_e80_d50, "MNF601BS1-3"), |
| 2037 | 2040 | ||
| 2038 | EDP_PANEL_ENTRY('E', 'T', 'C', 0x0000, &delay_50_500_e200_d200_po2e335, "LP079QX1-SP0V"), | 2041 | EDP_PANEL_ENTRY('E', 'T', 'C', 0x0000, &delay_50_500_e200_d200_po2e335, "LP079QX1-SP0V"), |
| @@ -12,6 +12,7 @@ · 11 unmodified lines | |||
| 12 | #include "panfrost_device.h" | 12 | #include "panfrost_device.h" |
| 13 | #include "panfrost_devfreq.h" | 13 | #include "panfrost_devfreq.h" |
| 14 | #include "panfrost_features.h" | 14 | #include "panfrost_features.h" |
| 15 | #include "panfrost_gem.h" | ||
| 15 | #include "panfrost_issues.h" | 16 | #include "panfrost_issues.h" |
| 16 | #include "panfrost_gpu.h" | 17 | #include "panfrost_gpu.h" |
| 17 | #include "panfrost_job.h" | 18 | #include "panfrost_job.h" |
| @@ -267,6 +268,8 @@ int panfrost_device_init(struct panfrost_device *pfdev) · 249 unmodified lines | |||
| 267 | if (err) | 268 | if (err) |
| 268 | goto out_job; | 269 | goto out_job; |
| 269 | 270 | ||
| 271 | panfrost_gem_init(pfdev); | ||
| 272 | |||
| 270 | return 0; | 273 | return 0; |
| 271 | out_job: | 274 | out_job: |
| 272 | panfrost_jm_fini(pfdev); | 275 | panfrost_jm_fini(pfdev); |
| @@ -79,6 +79,7 @@ struct panfrost_features { · 78 unmodified lines | |||
| 79 | u32 thread_max_workgroup_sz; | 79 | u32 thread_max_workgroup_sz; |
| 80 | u32 thread_max_barrier_sz; | 80 | u32 thread_max_barrier_sz; |
| 81 | u32 coherency_features; | 81 | u32 coherency_features; |
| 82 | u32 selected_coherency; | ||
| 82 | u32 afbc_features; | 83 | u32 afbc_features; |
| 83 | u32 texture_features[4]; | 84 | u32 texture_features[4]; |
| 84 | u32 js_features[16]; | 85 | u32 js_features[16]; |
| @@ -95,6 +95,7 @@ static int panfrost_ioctl_get_param(struct drm_device *ddev, void *data, struct · 94 unmodified lines | |||
| 95 | PANFROST_FEATURE_ARRAY(JS_FEATURES, js_features, 15); | 95 | PANFROST_FEATURE_ARRAY(JS_FEATURES, js_features, 15); |
| 96 | PANFROST_FEATURE(NR_CORE_GROUPS, nr_core_groups); | 96 | PANFROST_FEATURE(NR_CORE_GROUPS, nr_core_groups); |
| 97 | PANFROST_FEATURE(THREAD_TLS_ALLOC, thread_tls_alloc); | 97 | PANFROST_FEATURE(THREAD_TLS_ALLOC, thread_tls_alloc); |
| 98 | PANFROST_FEATURE(SELECTED_COHERENCY, selected_coherency); | ||
| 98 | 99 | ||
| 99 | case DRM_PANFROST_PARAM_SYSTEM_TIMESTAMP: | 100 | case DRM_PANFROST_PARAM_SYSTEM_TIMESTAMP: |
| 100 | ret = panfrost_ioctl_query_timestamp(pfdev, ¶m->value); | 101 | ret = panfrost_ioctl_query_timestamp(pfdev, ¶m->value); |
| @@ -125,6 +126,10 @@ static int panfrost_ioctl_get_param(struct drm_device *ddev, void *data, struct · 24 unmodified lines | |||
| 125 | return 0; | 126 | return 0; |
| 126 | } | 127 | } |
| 127 | 128 | ||
| 129 | #define PANFROST_BO_FLAGS (PANFROST_BO_NOEXEC | \ | ||
| 130 | PANFROST_BO_HEAP | \ | ||
| 131 | PANFROST_BO_WB_MMAP) | ||
| 132 | |||
| 128 | static int panfrost_ioctl_create_bo(struct drm_device *dev, void *data, | 133 | static int panfrost_ioctl_create_bo(struct drm_device *dev, void *data, |
| 129 | struct drm_file *file) | 134 | struct drm_file *file) |
| 130 | { | 135 | { |
| @@ -134,8 +139,7 @@ static int panfrost_ioctl_create_bo(struct drm_device *dev, void *data, · 3 unmodified lines | |||
| 134 | struct panfrost_gem_mapping *mapping; | 139 | struct panfrost_gem_mapping *mapping; |
| 135 | int ret; | 140 | int ret; |
| 136 | 141 | ||
| 137 | if (!args->size || args->pad || | 142 | if (!args->size || args->pad || (args->flags & ~PANFROST_BO_FLAGS)) |
| 138 | (args->flags & ~(PANFROST_BO_NOEXEC | PANFROST_BO_HEAP))) | ||
| 139 | return -EINVAL; | 143 | return -EINVAL; |
| 140 | 144 | ||
| 141 | /* Heaps should never be executable */ | 145 | /* Heaps should never be executable */ |
| @@ -579,6 +583,91 @@ static int panfrost_ioctl_jm_ctx_destroy(struct drm_device *dev, void *data, · 437 unmodified lines | |||
| 579 | return panfrost_jm_ctx_destroy(file, args->handle); | 583 | return panfrost_jm_ctx_destroy(file, args->handle); |
| 580 | } | 584 | } |
| 581 | 585 | ||
| 586 | static int panfrost_ioctl_sync_bo(struct drm_device *ddev, void *data, | ||
| 587 | struct drm_file *file) | ||
| 588 | { | ||
| 589 | struct drm_panfrost_sync_bo *args = data; | ||
| 590 | struct drm_panfrost_bo_sync_op *ops; | ||
| 591 | struct drm_gem_object *obj; | ||
| 592 | int ret; | ||
| 593 | u32 i; | ||
| 594 | |||
| 595 | if (args->pad) | ||
| 596 | return -EINVAL; | ||
| 597 | |||
| 598 | if (!args->op_count) | ||
| 599 | return 0; | ||
| 600 | |||
| 601 | ops = kvmalloc_array(args->op_count, sizeof(*ops), GFP_KERNEL); | ||
| 602 | if (!ops) { | ||
| 603 | DRM_DEBUG("Failed to allocate incoming BO sync ops array\n"); | ||
| 604 | return -ENOMEM; | ||
| 605 | } | ||
| 606 | |||
| 607 | if (copy_from_user(ops, (void __user *)(uintptr_t)args->ops, | ||
| 608 | args->op_count * sizeof(*ops))) { | ||
| 609 | DRM_DEBUG("Failed to copy in BO sync ops\n"); | ||
| 610 | ret = -EFAULT; | ||
| 611 | goto err_ops; | ||
| 612 | } | ||
| 613 | |||
| 614 | for (i = 0; i < args->op_count; i++) { | ||
| 615 | obj = drm_gem_object_lookup(file, ops[i].handle); | ||
| 616 | if (!obj) { | ||
| 617 | ret = -ENOENT; | ||
| 618 | goto err_ops; | ||
| 619 | } | ||
| 620 | |||
| 621 | ret = panfrost_gem_sync(obj, ops[i].type, | ||
| 622 | ops[i].offset, ops[i].size); | ||
| 623 | |||
| 624 | drm_gem_object_put(obj); | ||
| 625 | |||
| 626 | if (ret) | ||
| 627 | goto err_ops; | ||
| 628 | } | ||
| 629 | |||
| 630 | err_ops: | ||
| 631 | kvfree(ops); | ||
| 632 | |||
| 633 | return ret; | ||
| 634 | } | ||
| 635 | |||
| 636 | static int panfrost_ioctl_query_bo_info(struct drm_device *dev, void *data, | ||
| 637 | struct drm_file *file_priv) | ||
| 638 | { | ||
| 639 | struct drm_panfrost_query_bo_info *args = data; | ||
| 640 | struct drm_gem_object *gem_obj; | ||
| 641 | struct panfrost_gem_object *bo; | ||
| 642 | |||
| 643 | gem_obj = drm_gem_object_lookup(file_priv, args->handle); | ||
| 644 | if (!gem_obj) { | ||
| 645 | DRM_DEBUG("Failed to look up GEM BO %d\n", args->handle); | ||
| 646 | return -ENOENT; | ||
| 647 | } | ||
| 648 | |||
| 649 | bo = to_panfrost_bo(gem_obj); | ||
| 650 | args->pad = 0; | ||
| 651 | args->create_flags = 0; | ||
| 652 | args->extra_flags = 0; | ||
| 653 | |||
| 654 | if (drm_gem_is_imported(gem_obj)) { | ||
| 655 | args->extra_flags |= DRM_PANFROST_BO_IS_IMPORTED; | ||
| 656 | } else { | ||
| 657 | if (bo->noexec) | ||
| 658 | args->create_flags |= PANFROST_BO_NOEXEC; | ||
| 659 | |||
| 660 | if (bo->is_heap) | ||
| 661 | args->create_flags |= PANFROST_BO_HEAP; | ||
| 662 | |||
| 663 | if (!bo->base.map_wc) | ||
| 664 | args->create_flags |= PANFROST_BO_WB_MMAP; | ||
| 665 | } | ||
| 666 | |||
| 667 | drm_gem_object_put(gem_obj); | ||
| 668 | return 0; | ||
| 669 | } | ||
| 670 | |||
| 582 | int panfrost_unstable_ioctl_check(void) | 671 | int panfrost_unstable_ioctl_check(void) |
| 583 | { | 672 | { |
| 584 | if (!unstable_ioctls) | 673 | if (!unstable_ioctls) |
| @@ -648,6 +737,8 @@ static const struct drm_ioctl_desc panfrost_drm_driver_ioctls[] = { · 63 unmodified lines | |||
| 648 | PANFROST_IOCTL(SET_LABEL_BO, set_label_bo, DRM_RENDER_ALLOW), | 737 | PANFROST_IOCTL(SET_LABEL_BO, set_label_bo, DRM_RENDER_ALLOW), |
| 649 | PANFROST_IOCTL(JM_CTX_CREATE, jm_ctx_create, DRM_RENDER_ALLOW), | 738 | PANFROST_IOCTL(JM_CTX_CREATE, jm_ctx_create, DRM_RENDER_ALLOW), |
| 650 | PANFROST_IOCTL(JM_CTX_DESTROY, jm_ctx_destroy, DRM_RENDER_ALLOW), | 739 | PANFROST_IOCTL(JM_CTX_DESTROY, jm_ctx_destroy, DRM_RENDER_ALLOW), |
| 740 | PANFROST_IOCTL(SYNC_BO, sync_bo, DRM_RENDER_ALLOW), | ||
| 741 | PANFROST_IOCTL(QUERY_BO_INFO, query_bo_info, DRM_RENDER_ALLOW), | ||
| 651 | }; | 742 | }; |
| 652 | 743 | ||
| 653 | static void panfrost_gpu_show_fdinfo(struct panfrost_device *pfdev, | 744 | static void panfrost_gpu_show_fdinfo(struct panfrost_device *pfdev, |
| @@ -837,6 +928,9 @@ static void panfrost_debugfs_init(struct drm_minor *minor) · 183 unmodified lines | |||
| 837 | * - 1.4 - adds SET_LABEL_BO | 928 | * - 1.4 - adds SET_LABEL_BO |
| 838 | * - 1.5 - adds JM_CTX_{CREATE,DESTROY} ioctls and extend SUBMIT to allow | 929 | * - 1.5 - adds JM_CTX_{CREATE,DESTROY} ioctls and extend SUBMIT to allow |
| 839 | * context creation with configurable priorities/affinity | 930 | * context creation with configurable priorities/affinity |
| 931 | * - 1.6 - adds PANFROST_BO_MAP_WB, PANFROST_IOCTL_SYNC_BO, | ||
| 932 | * PANFROST_IOCTL_QUERY_BO_INFO and | ||
| 933 | * DRM_PANFROST_PARAM_SELECTED_COHERENCY | ||
| 840 | */ | 934 | */ |
| 841 | static const struct drm_driver panfrost_drm_driver = { | 935 | static const struct drm_driver panfrost_drm_driver = { |
| 842 | .driver_features = DRIVER_RENDER | DRIVER_GEM | DRIVER_SYNCOBJ, | 936 | .driver_features = DRIVER_RENDER | DRIVER_GEM | DRIVER_SYNCOBJ, |
| @@ -849,15 +943,22 @@ static const struct drm_driver panfrost_drm_driver = { · 6 unmodified lines | |||
| 849 | .name = "panfrost", | 943 | .name = "panfrost", |
| 850 | .desc = "panfrost DRM", | 944 | .desc = "panfrost DRM", |
| 851 | .major = 1, | 945 | .major = 1, |
| 852 | .minor = 5, | 946 | .minor = 6, |
| 853 | 947 | ||
| 854 | .gem_create_object = panfrost_gem_create_object, | 948 | .gem_create_object = panfrost_gem_create_object, |
| 949 | .gem_prime_import = panfrost_gem_prime_import, | ||
| 855 | .gem_prime_import_sg_table = panfrost_gem_prime_import_sg_table, | 950 | .gem_prime_import_sg_table = panfrost_gem_prime_import_sg_table, |
| 856 | #ifdef CONFIG_DEBUG_FS | 951 | #ifdef CONFIG_DEBUG_FS |
| 857 | .debugfs_init = panfrost_debugfs_init, | 952 | .debugfs_init = panfrost_debugfs_init, |
| 858 | #endif | 953 | #endif |
| 859 | }; | 954 | }; |
| 860 | 955 | ||
| 956 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE | ||
| 957 | bool panfrost_transparent_hugepage = true; | ||
| 958 | module_param_named(transparent_hugepage, panfrost_transparent_hugepage, bool, 0400); | ||
| 959 | MODULE_PARM_DESC(transparent_hugepage, "Use a dedicated tmpfs mount point with Transparent Hugepage enabled (true = default)"); | ||
| 960 | #endif | ||
| 961 | |||
| 861 | static int panfrost_probe(struct platform_device *pdev) | 962 | static int panfrost_probe(struct platform_device *pdev) |
| 862 | { | 963 | { |
| 863 | struct panfrost_device *pfdev; | 964 | struct panfrost_device *pfdev; |
| @@ -0,0 +1,9 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 or MIT */ | ||
| 2 | /* Copyright 2025 Amazon.com, Inc. or its affiliates */ | ||
| 3 | |||
| 4 | #ifndef __PANFROST_DRV_H__ | ||
| 5 | #define __PANFROST_DRV_H__ | ||
| 6 | |||
| 7 | extern bool panfrost_transparent_hugepage; | ||
| 8 | |||
| 9 | #endif | ||
| @@ -1,5 +1,6 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | /* Copyright 2019 Linaro, Ltd, Rob Herring <robh@kernel.org> */ | 2 | /* Copyright 2019 Linaro, Ltd, Rob Herring <robh@kernel.org> */ |
| 3 | /* Copyright 2025 Amazon.com, Inc. or its affiliates */ | ||
| 3 | 4 | ||
| 4 | #include <linux/cleanup.h> | 5 | #include <linux/cleanup.h> |
| 5 | #include <linux/err.h> | 6 | #include <linux/err.h> |
| @@ -10,9 +11,26 @@ · 4 unmodified lines | |||
| 10 | #include <drm/panfrost_drm.h> | 11 | #include <drm/panfrost_drm.h> |
| 11 | #include <drm/drm_print.h> | 12 | #include <drm/drm_print.h> |
| 12 | #include "panfrost_device.h" | 13 | #include "panfrost_device.h" |
| 14 | #include "panfrost_drv.h" | ||
| 13 | #include "panfrost_gem.h" | 15 | #include "panfrost_gem.h" |
| 14 | #include "panfrost_mmu.h" | 16 | #include "panfrost_mmu.h" |
| 15 | 17 | ||
| 18 | void panfrost_gem_init(struct panfrost_device *pfdev) | ||
| 19 | { | ||
| 20 | int err; | ||
| 21 | |||
| 22 | if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) && | ||
| 23 | !panfrost_transparent_hugepage) | ||
| 24 | return; | ||
| 25 | |||
| 26 | err = drm_gem_huge_mnt_create(&pfdev->base, "within_size"); | ||
| 27 | if (drm_gem_get_huge_mnt(&pfdev->base)) | ||
| 28 | drm_info(&pfdev->base, "Using Transparent Hugepage\n"); | ||
| 29 | else if (err) | ||
| 30 | drm_warn(&pfdev->base, "Can't use Transparent Hugepage (%d)\n", | ||
| 31 | err); | ||
| 32 | } | ||
| 33 | |||
| 16 | #ifdef CONFIG_DEBUG_FS | 34 | #ifdef CONFIG_DEBUG_FS |
| 17 | static void panfrost_gem_debugfs_bo_add(struct panfrost_device *pfdev, | 35 | static void panfrost_gem_debugfs_bo_add(struct panfrost_device *pfdev, |
| 18 | struct panfrost_gem_object *bo) | 36 | struct panfrost_gem_object *bo) |
| @@ -259,6 +277,128 @@ static size_t panfrost_gem_rss(struct drm_gem_object *obj) · 240 unmodified lines | |||
| 259 | return 0; | 277 | return 0; |
| 260 | } | 278 | } |
| 261 | 279 | ||
| 280 | static struct sg_table * | ||
| 281 | panfrost_gem_prime_map_dma_buf(struct dma_buf_attachment *attach, | ||
| 282 | enum dma_data_direction dir) | ||
| 283 | { | ||
| 284 | struct sg_table *sgt = drm_gem_map_dma_buf(attach, dir); | ||
| 285 | |||
| 286 | if (!IS_ERR(sgt)) | ||
| 287 | attach->priv = sgt; | ||
| 288 | |||
| 289 | return sgt; | ||
| 290 | } | ||
| 291 | |||
| 292 | static void | ||
| 293 | panfrost_gem_prime_unmap_dma_buf(struct dma_buf_attachment *attach, | ||
| 294 | struct sg_table *sgt, | ||
| 295 | enum dma_data_direction dir) | ||
| 296 | { | ||
| 297 | attach->priv = NULL; | ||
| 298 | drm_gem_unmap_dma_buf(attach, sgt, dir); | ||
| 299 | } | ||
| 300 | |||
| 301 | static int | ||
| 302 | panfrost_gem_prime_begin_cpu_access(struct dma_buf *dma_buf, | ||
| 303 | enum dma_data_direction dir) | ||
| 304 | { | ||
| 305 | struct drm_gem_object *obj = dma_buf->priv; | ||
| 306 | struct drm_device *dev = obj->dev; | ||
| 307 | struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); | ||
| 308 | struct dma_buf_attachment *attach; | ||
| 309 | |||
| 310 | dma_resv_lock(obj->resv, NULL); | ||
| 311 | if (shmem->sgt) | ||
| 312 | dma_sync_sgtable_for_cpu(dev->dev, shmem->sgt, dir); | ||
| 313 | |||
| 314 | if (shmem->vaddr) | ||
| 315 | invalidate_kernel_vmap_range(shmem->vaddr, shmem->base.size); | ||
| 316 | |||
| 317 | list_for_each_entry(attach, &dma_buf->attachments, node) { | ||
| 318 | struct sg_table *sgt = attach->priv; | ||
| 319 | |||
| 320 | if (sgt) | ||
| 321 | dma_sync_sgtable_for_cpu(attach->dev, sgt, dir); | ||
| 322 | } | ||
| 323 | dma_resv_unlock(obj->resv); | ||
| 324 | |||
| 325 | return 0; | ||
| 326 | } | ||
| 327 | |||
| 328 | static int | ||
| 329 | panfrost_gem_prime_end_cpu_access(struct dma_buf *dma_buf, | ||
| 330 | enum dma_data_direction dir) | ||
| 331 | { | ||
| 332 | struct drm_gem_object *obj = dma_buf->priv; | ||
| 333 | struct drm_device *dev = obj->dev; | ||
| 334 | struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); | ||
| 335 | struct dma_buf_attachment *attach; | ||
| 336 | |||
| 337 | dma_resv_lock(obj->resv, NULL); | ||
| 338 | list_for_each_entry(attach, &dma_buf->attachments, node) { | ||
| 339 | struct sg_table *sgt = attach->priv; | ||
| 340 | |||
| 341 | if (sgt) | ||
| 342 | dma_sync_sgtable_for_device(attach->dev, sgt, dir); | ||
| 343 | } | ||
| 344 | |||
| 345 | if (shmem->vaddr) | ||
| 346 | flush_kernel_vmap_range(shmem->vaddr, shmem->base.size); | ||
| 347 | |||
| 348 | if (shmem->sgt) | ||
| 349 | dma_sync_sgtable_for_device(dev->dev, shmem->sgt, dir); | ||
| 350 | |||
| 351 | dma_resv_unlock(obj->resv); | ||
| 352 | return 0; | ||
| 353 | } | ||
| 354 | |||
| 355 | static const struct dma_buf_ops panfrost_dma_buf_ops = { | ||
| 356 | .attach = drm_gem_map_attach, | ||
| 357 | .detach = drm_gem_map_detach, | ||
| 358 | .map_dma_buf = panfrost_gem_prime_map_dma_buf, | ||
| 359 | .unmap_dma_buf = panfrost_gem_prime_unmap_dma_buf, | ||
| 360 | .release = drm_gem_dmabuf_release, | ||
| 361 | .mmap = drm_gem_dmabuf_mmap, | ||
| 362 | .vmap = drm_gem_dmabuf_vmap, | ||
| 363 | .vunmap = drm_gem_dmabuf_vunmap, | ||
| 364 | .begin_cpu_access = panfrost_gem_prime_begin_cpu_access, | ||
| 365 | .end_cpu_access = panfrost_gem_prime_end_cpu_access, | ||
| 366 | }; | ||
| 367 | |||
| 368 | static struct dma_buf * | ||
| 369 | panfrost_gem_prime_export(struct drm_gem_object *obj, int flags) | ||
| 370 | { | ||
| 371 | struct drm_device *dev = obj->dev; | ||
| 372 | struct dma_buf_export_info exp_info = { | ||
| 373 | .exp_name = KBUILD_MODNAME, | ||
| 374 | .owner = THIS_MODULE, | ||
| 375 | .ops = &panfrost_dma_buf_ops, | ||
| 376 | .size = obj->size, | ||
| 377 | .flags = flags, | ||
| 378 | .priv = obj, | ||
| 379 | .resv = obj->resv, | ||
| 380 | }; | ||
| 381 | |||
| 382 | return drm_gem_dmabuf_export(dev, &exp_info); | ||
| 383 | } | ||
| 384 | |||
| 385 | struct drm_gem_object * | ||
| 386 | panfrost_gem_prime_import(struct drm_device *dev, | ||
| 387 | struct dma_buf *dma_buf) | ||
| 388 | { | ||
| 389 | struct drm_gem_object *obj = dma_buf->priv; | ||
| 390 | |||
| 391 | if (dma_buf->ops == &panfrost_dma_buf_ops && obj->dev == dev) { | ||
| 392 | /* Importing dmabuf exported from our own gem increases | ||
| 393 | * refcount on gem itself instead of f_count of dmabuf. | ||
| 394 | */ | ||
| 395 | drm_gem_object_get(obj); | ||
| 396 | return obj; | ||
| 397 | } | ||
| 398 | |||
| 399 | return drm_gem_prime_import(dev, dma_buf); | ||
| 400 | } | ||
| 401 | |||
| 262 | static const struct drm_gem_object_funcs panfrost_gem_funcs = { | 402 | static const struct drm_gem_object_funcs panfrost_gem_funcs = { |
| 263 | .free = panfrost_gem_free_object, | 403 | .free = panfrost_gem_free_object, |
| 264 | .open = panfrost_gem_open, | 404 | .open = panfrost_gem_open, |
| @@ -267,6 +407,7 @@ static const struct drm_gem_object_funcs panfrost_gem_funcs = { · 2 unmodified lines | |||
| 267 | .pin = panfrost_gem_pin, | 407 | .pin = panfrost_gem_pin, |
| 268 | .unpin = drm_gem_shmem_object_unpin, | 408 | .unpin = drm_gem_shmem_object_unpin, |
| 269 | .get_sg_table = drm_gem_shmem_object_get_sg_table, | 409 | .get_sg_table = drm_gem_shmem_object_get_sg_table, |
| 410 | .export = panfrost_gem_prime_export, | ||
| 270 | .vmap = drm_gem_shmem_object_vmap, | 411 | .vmap = drm_gem_shmem_object_vmap, |
| 271 | .vunmap = drm_gem_shmem_object_vunmap, | 412 | .vunmap = drm_gem_shmem_object_vunmap, |
| 272 | .mmap = drm_gem_shmem_object_mmap, | 413 | .mmap = drm_gem_shmem_object_mmap, |
| @@ -303,12 +444,42 @@ struct drm_gem_object *panfrost_gem_create_object(struct drm_device *dev, size_t · 30 unmodified lines | |||
| 303 | return &obj->base.base; | 444 | return &obj->base.base; |
| 304 | } | 445 | } |
| 305 | 446 | ||
| 447 | static bool | ||
| 448 | should_map_wc(struct panfrost_gem_object *bo) | ||
| 449 | { | ||
| 450 | struct panfrost_device *pfdev = to_panfrost_device(bo->base.base.dev); | ||
| 451 | |||
| 452 | /* We can't do uncached mappings if the device is coherent, | ||
| 453 | * because the zeroing done by the shmem layer at page allocation | ||
| 454 | * time happens on a cached mapping which isn't CPU-flushed (at least | ||
| 455 | * not on Arm64 where the flush is deferred to PTE setup time, and | ||
| 456 | * only done conditionally based on the mapping permissions). We can't | ||
| 457 | * rely on dma_map_sgtable()/dma_sync_sgtable_for_xxx() either to flush | ||
| 458 | * those, because they are NOPed if dma_dev_coherent() returns true. | ||
| 459 | */ | ||
| 460 | if (pfdev->coherent) | ||
| 461 | return false; | ||
| 462 | |||
| 463 | /* Cached mappings are explicitly requested, so no write-combine. */ | ||
| 464 | if (bo->wb_mmap) | ||
| 465 | return false; | ||
| 466 | |||
| 467 | /* The default is write-combine. */ | ||
| 468 | return true; | ||
| 469 | } | ||
| 470 | |||
| 306 | struct panfrost_gem_object * | 471 | struct panfrost_gem_object * |
| 307 | panfrost_gem_create(struct drm_device *dev, size_t size, u32 flags) | 472 | panfrost_gem_create(struct drm_device *dev, size_t size, u32 flags) |
| 308 | { | 473 | { |
| 309 | struct drm_gem_shmem_object *shmem; | 474 | struct drm_gem_shmem_object *shmem; |
| 310 | struct panfrost_gem_object *bo; | 475 | struct panfrost_gem_object *bo; |
| 311 | 476 | ||
| 477 | /* The heap buffer is not supposed to be CPU-visible, so don't allow | ||
| 478 | * WB_MMAP on those. | ||
| 479 | */ | ||
| 480 | if ((flags & PANFROST_BO_HEAP) && (flags & PANFROST_BO_WB_MMAP)) | ||
| 481 | return ERR_PTR(-EINVAL); | ||
| 482 | |||
| 312 | /* Round up heap allocations to 2MB to keep fault handling simple */ | 483 | /* Round up heap allocations to 2MB to keep fault handling simple */ |
| 313 | if (flags & PANFROST_BO_HEAP) | 484 | if (flags & PANFROST_BO_HEAP) |
| 314 | size = roundup(size, SZ_2M); | 485 | size = roundup(size, SZ_2M); |
| @@ -320,6 +491,8 @@ panfrost_gem_create(struct drm_device *dev, size_t size, u32 flags) · 5 unmodified lines | |||
| 320 | bo = to_panfrost_bo(&shmem->base); | 491 | bo = to_panfrost_bo(&shmem->base); |
| 321 | bo->noexec = !!(flags & PANFROST_BO_NOEXEC); | 492 | bo->noexec = !!(flags & PANFROST_BO_NOEXEC); |
| 322 | bo->is_heap = !!(flags & PANFROST_BO_HEAP); | 493 | bo->is_heap = !!(flags & PANFROST_BO_HEAP); |
| 494 | bo->wb_mmap = !!(flags & PANFROST_BO_WB_MMAP); | ||
| 495 | bo->base.map_wc = should_map_wc(bo); | ||
| 323 | 496 | ||
| 324 | return bo; | 497 | return bo; |
| 325 | } | 498 | } |
| @@ -366,6 +539,90 @@ panfrost_gem_set_label(struct drm_gem_object *obj, const char *label) · 40 unmodified lines | |||
| 366 | kfree_const(old_label); | 539 | kfree_const(old_label); |
| 367 | } | 540 | } |
| 368 | 541 | ||
| 542 | int | ||
| 543 | panfrost_gem_sync(struct drm_gem_object *obj, u32 type, u32 offset, u32 size) | ||
| 544 | { | ||
| 545 | struct panfrost_gem_object *bo = to_panfrost_bo(obj); | ||
| 546 | struct drm_gem_shmem_object *shmem = &bo->base; | ||
| 547 | const struct drm_device *dev = shmem->base.dev; | ||
| 548 | struct sg_table *sgt; | ||
| 549 | struct scatterlist *sgl; | ||
| 550 | unsigned int count; | ||
| 551 | |||
| 552 | /* Make sure the range is in bounds. */ | ||
| 553 | if (offset + size < offset || offset + size > shmem->base.size) | ||
| 554 | return -EINVAL; | ||
| 555 | |||
| 556 | /* Disallow CPU-cache maintenance on imported buffers. */ | ||
| 557 | if (drm_gem_is_imported(&shmem->base)) | ||
| 558 | return -EINVAL; | ||
| 559 | |||
| 560 | switch (type) { | ||
| 561 | case PANFROST_BO_SYNC_CPU_CACHE_FLUSH: | ||
| 562 | case PANFROST_BO_SYNC_CPU_CACHE_FLUSH_AND_INVALIDATE: | ||
| 563 | break; | ||
| 564 | |||
| 565 | default: | ||
| 566 | return -EINVAL; | ||
| 567 | } | ||
| 568 | |||
| 569 | /* Don't bother if it's WC-mapped */ | ||
| 570 | if (shmem->map_wc) | ||
| 571 | return 0; | ||
| 572 | |||
| 573 | /* Nothing to do if the size is zero. */ | ||
| 574 | if (size == 0) | ||
| 575 | return 0; | ||
| 576 | |||
| 577 | sgt = drm_gem_shmem_get_pages_sgt(shmem); | ||
| 578 | if (IS_ERR(sgt)) | ||
| 579 | return PTR_ERR(sgt); | ||
| 580 | |||
| 581 | for_each_sgtable_dma_sg(sgt, sgl, count) { | ||
| 582 | if (size == 0) | ||
| 583 | break; | ||
| 584 | |||
| 585 | dma_addr_t paddr = sg_dma_address(sgl); | ||
| 586 | size_t len = sg_dma_len(sgl); | ||
| 587 | |||
| 588 | if (len <= offset) { | ||
| 589 | offset -= len; | ||
| 590 | continue; | ||
| 591 | } | ||
| 592 | |||
| 593 | paddr += offset; | ||
| 594 | len -= offset; | ||
| 595 | len = min_t(size_t, len, size); | ||
| 596 | size -= len; | ||
| 597 | offset = 0; | ||
| 598 | |||
| 599 | /* It's unclear whether dma_sync_xxx() is the right API to do CPU | ||
| 600 | * cache maintenance given an IOMMU can register their own | ||
| 601 | * implementation doing more than just CPU cache flushes/invalidation, | ||
| 602 | * and what we really care about here is CPU caches only, but that's | ||
| 603 | * the best we have that is both arch-agnostic and does at least the | ||
| 604 | * CPU cache maintenance on a <page,offset,size> tuple. | ||
| 605 | * | ||
| 606 | * Also, I wish we could do a single | ||
| 607 | * | ||
| 608 | * dma_sync_single_for_device(BIDIR) | ||
| 609 | * | ||
| 610 | * and get a flush+invalidate, but that's not how it's implemented | ||
| 611 | * in practice (at least on arm64), so we have to make it | ||
| 612 | * | ||
| 613 | * dma_sync_single_for_device(TO_DEVICE) | ||
| 614 | * dma_sync_single_for_cpu(FROM_DEVICE) | ||
| 615 | * | ||
| 616 | * for the flush+invalidate case. | ||
| 617 | */ | ||
| 618 | dma_sync_single_for_device(dev->dev, paddr, len, DMA_TO_DEVICE); | ||
| 619 | if (type == PANFROST_BO_SYNC_CPU_CACHE_FLUSH_AND_INVALIDATE) | ||
| 620 | dma_sync_single_for_cpu(dev->dev, paddr, len, DMA_FROM_DEVICE); | ||
| 621 | } | ||
| 622 | |||
| 623 | return 0; | ||
| 624 | } | ||
| 625 | |||
| 369 | void | 626 | void |
| 370 | panfrost_gem_internal_set_label(struct drm_gem_object *obj, const char *label) | 627 | panfrost_gem_internal_set_label(struct drm_gem_object *obj, const char *label) |
| 371 | { | 628 | { |
| @@ -98,6 +98,11 @@ struct panfrost_gem_object { · 97 unmodified lines | |||
| 98 | bool noexec :1; | 98 | bool noexec :1; |
| 99 | bool is_heap :1; | 99 | bool is_heap :1; |
| 100 | 100 | ||
| 101 | /* On coherent devices, this reflects the creation flags, not the true | ||
| 102 | * cacheability attribute of the mapping. | ||
| 103 | */ | ||
| 104 | bool wb_mmap :1; | ||
| 105 | |||
| 101 | #ifdef CONFIG_DEBUG_FS | 106 | #ifdef CONFIG_DEBUG_FS |
| 102 | struct panfrost_gem_debugfs debugfs; | 107 | struct panfrost_gem_debugfs debugfs; |
| 103 | #endif | 108 | #endif |
| @@ -124,12 +129,17 @@ drm_mm_node_to_panfrost_mapping(struct drm_mm_node *node) · 20 unmodified lines | |||
| 124 | return container_of(node, struct panfrost_gem_mapping, mmnode); | 129 | return container_of(node, struct panfrost_gem_mapping, mmnode); |
| 125 | } | 130 | } |
| 126 | 131 | ||
| 132 | void panfrost_gem_init(struct panfrost_device *pfdev); | ||
| 133 | |||
| 127 | struct drm_gem_object *panfrost_gem_create_object(struct drm_device *dev, size_t size); | 134 | struct drm_gem_object *panfrost_gem_create_object(struct drm_device *dev, size_t size); |
| 128 | 135 | ||
| 129 | struct drm_gem_object * | 136 | struct drm_gem_object * |
| 130 | panfrost_gem_prime_import_sg_table(struct drm_device *dev, | 137 | panfrost_gem_prime_import_sg_table(struct drm_device *dev, |
| 131 | struct dma_buf_attachment *attach, | 138 | struct dma_buf_attachment *attach, |
| 132 | struct sg_table *sgt); | 139 | struct sg_table *sgt); |
| 140 | struct drm_gem_object * | ||
| 141 | panfrost_gem_prime_import(struct drm_device *dev, | ||
| 142 | struct dma_buf *dma_buf); | ||
| 133 | 143 | ||
| 134 | struct panfrost_gem_object * | 144 | struct panfrost_gem_object * |
| 135 | panfrost_gem_create(struct drm_device *dev, size_t size, u32 flags); | 145 | panfrost_gem_create(struct drm_device *dev, size_t size, u32 flags); |
| @@ -148,6 +158,8 @@ int panfrost_gem_shrinker_init(struct drm_device *dev); · 12 unmodified lines | |||
| 148 | void panfrost_gem_shrinker_cleanup(struct drm_device *dev); | 158 | void panfrost_gem_shrinker_cleanup(struct drm_device *dev); |
| 149 | 159 | ||
| 150 | void panfrost_gem_set_label(struct drm_gem_object *obj, const char *label); | 160 | void panfrost_gem_set_label(struct drm_gem_object *obj, const char *label); |
| 161 | int panfrost_gem_sync(struct drm_gem_object *obj, u32 type, | ||
| 162 | u32 offset, u32 size); | ||
| 151 | void panfrost_gem_internal_set_label(struct drm_gem_object *obj, const char *label); | 163 | void panfrost_gem_internal_set_label(struct drm_gem_object *obj, const char *label); |
| 152 | 164 | ||
| 153 | #ifdef CONFIG_DEBUG_FS | 165 | #ifdef CONFIG_DEBUG_FS |
| @@ -159,8 +159,8 @@ static void panfrost_gpu_init_quirks(struct panfrost_device *pfdev) · 158 unmodified lines | |||
| 159 | pfdev->features.revision >= 0x2000) | 159 | pfdev->features.revision >= 0x2000) |
| 160 | quirks |= JM_MAX_JOB_THROTTLE_LIMIT << JM_JOB_THROTTLE_LIMIT_SHIFT; | 160 | quirks |= JM_MAX_JOB_THROTTLE_LIMIT << JM_JOB_THROTTLE_LIMIT_SHIFT; |
| 161 | else if (panfrost_model_eq(pfdev, 0x6000) && | 161 | else if (panfrost_model_eq(pfdev, 0x6000) && |
| 162 | pfdev->features.coherency_features == COHERENCY_ACE) | 162 | pfdev->features.coherency_features == BIT(COHERENCY_ACE)) |
| 163 | quirks |= (COHERENCY_ACE_LITE | COHERENCY_ACE) << | 163 | quirks |= (BIT(COHERENCY_ACE_LITE) | BIT(COHERENCY_ACE)) << |
| 164 | JM_FORCE_COHERENCY_FEATURES_SHIFT; | 164 | JM_FORCE_COHERENCY_FEATURES_SHIFT; |
| 165 | 165 | ||
| 166 | if (panfrost_has_hw_feature(pfdev, HW_FEATURE_IDVS_GROUP_SIZE)) | 166 | if (panfrost_has_hw_feature(pfdev, HW_FEATURE_IDVS_GROUP_SIZE)) |
| @@ -263,7 +263,27 @@ static int panfrost_gpu_init_features(struct panfrost_device *pfdev) · 96 unmodified lines | |||
| 263 | pfdev->features.max_threads = gpu_read(pfdev, GPU_THREAD_MAX_THREADS); | 263 | pfdev->features.max_threads = gpu_read(pfdev, GPU_THREAD_MAX_THREADS); |
| 264 | pfdev->features.thread_max_workgroup_sz = gpu_read(pfdev, GPU_THREAD_MAX_WORKGROUP_SIZE); | 264 | pfdev->features.thread_max_workgroup_sz = gpu_read(pfdev, GPU_THREAD_MAX_WORKGROUP_SIZE); |
| 265 | pfdev->features.thread_max_barrier_sz = gpu_read(pfdev, GPU_THREAD_MAX_BARRIER_SIZE); | 265 | pfdev->features.thread_max_barrier_sz = gpu_read(pfdev, GPU_THREAD_MAX_BARRIER_SIZE); |
| 266 | pfdev->features.coherency_features = gpu_read(pfdev, GPU_COHERENCY_FEATURES); | 266 | |
| 267 | if (panfrost_has_hw_feature(pfdev, HW_FEATURE_COHERENCY_REG)) | ||
| 268 | pfdev->features.coherency_features = gpu_read(pfdev, GPU_COHERENCY_FEATURES); | ||
| 269 | else | ||
| 270 | pfdev->features.coherency_features = BIT(COHERENCY_ACE_LITE); | ||
| 271 | |||
| 272 | BUILD_BUG_ON(COHERENCY_ACE_LITE != DRM_PANFROST_GPU_COHERENCY_ACE_LITE); | ||
| 273 | BUILD_BUG_ON(COHERENCY_ACE != DRM_PANFROST_GPU_COHERENCY_ACE); | ||
| 274 | BUILD_BUG_ON(COHERENCY_NONE != DRM_PANFROST_GPU_COHERENCY_NONE); | ||
| 275 | |||
| 276 | if (!pfdev->coherent) { | ||
| 277 | pfdev->features.selected_coherency = COHERENCY_NONE; | ||
| 278 | } else if (pfdev->features.coherency_features & BIT(COHERENCY_ACE)) { | ||
| 279 | pfdev->features.selected_coherency = COHERENCY_ACE; | ||
| 280 | } else if (pfdev->features.coherency_features & BIT(COHERENCY_ACE_LITE)) { | ||
| 281 | pfdev->features.selected_coherency = COHERENCY_ACE_LITE; | ||
| 282 | } else { | ||
| 283 | drm_WARN(&pfdev->base, true, "No known coherency protocol supported"); | ||
| 284 | pfdev->features.selected_coherency = COHERENCY_NONE; | ||
| 285 | } | ||
| 286 | |||
| 267 | pfdev->features.afbc_features = gpu_read(pfdev, GPU_AFBC_FEATURES); | 287 | pfdev->features.afbc_features = gpu_read(pfdev, GPU_AFBC_FEATURES); |
| 268 | for (i = 0; i < 4; i++) | 288 | for (i = 0; i < 4; i++) |
| 269 | pfdev->features.texture_features[i] = gpu_read(pfdev, GPU_TEXTURE_FEATURES(i)); | 289 | pfdev->features.texture_features[i] = gpu_read(pfdev, GPU_TEXTURE_FEATURES(i)); |
| @@ -102,9 +102,15 @@ · 101 unmodified lines | |||
| 102 | #define GPU_L2_PRESENT_LO 0x120 /* (RO) Level 2 cache present bitmap, low word */ | 102 | #define GPU_L2_PRESENT_LO 0x120 /* (RO) Level 2 cache present bitmap, low word */ |
| 103 | #define GPU_L2_PRESENT_HI 0x124 /* (RO) Level 2 cache present bitmap, high word */ | 103 | #define GPU_L2_PRESENT_HI 0x124 /* (RO) Level 2 cache present bitmap, high word */ |
| 104 | 104 | ||
| 105 | /* GPU_COHERENCY_FEATURES is a bitmask of BIT(COHERENCY_xxx) values encoding the | ||
| 106 | * set of supported coherency protocols. GPU_COHERENCY_ENABLE is passed a | ||
| 107 | * COHERENCY_xxx value. | ||
| 108 | */ | ||
| 105 | #define GPU_COHERENCY_FEATURES 0x300 /* (RO) Coherency features present */ | 109 | #define GPU_COHERENCY_FEATURES 0x300 /* (RO) Coherency features present */ |
| 106 | #define COHERENCY_ACE_LITE BIT(0) | 110 | #define GPU_COHERENCY_ENABLE 0x304 /* (RW) Coherency protocol selection */ |
| 107 | #define COHERENCY_ACE BIT(1) | 111 | #define COHERENCY_ACE_LITE 0 |
| 112 | #define COHERENCY_ACE 1 | ||
| 113 | #define COHERENCY_NONE 31 | ||
| 108 | 114 | ||
| 109 | #define GPU_STACK_PRESENT_LO 0xE00 /* (RO) Core stack present bitmap, low word */ | 115 | #define GPU_STACK_PRESENT_LO 0xE00 /* (RO) Core stack present bitmap, low word */ |
| 110 | #define GPU_STACK_PRESENT_HI 0xE04 /* (RO) Core stack present bitmap, high word */ | 116 | #define GPU_STACK_PRESENT_HI 0xE04 /* (RO) Core stack present bitmap, high word */ |
| @@ -18,6 +18,7 @@ · 17 unmodified lines | |||
| 18 | #include "panthor_devfreq.h" | 18 | #include "panthor_devfreq.h" |
| 19 | #include "panthor_device.h" | 19 | #include "panthor_device.h" |
| 20 | #include "panthor_fw.h" | 20 | #include "panthor_fw.h" |
| 21 | #include "panthor_gem.h" | ||
| 21 | #include "panthor_gpu.h" | 22 | #include "panthor_gpu.h" |
| 22 | #include "panthor_hw.h" | 23 | #include "panthor_hw.h" |
| 23 | #include "panthor_mmu.h" | 24 | #include "panthor_mmu.h" |
| @@ -27,6 +28,12 @@ · 3 unmodified lines | |||
| 27 | 28 | ||
| 28 | static int panthor_gpu_coherency_init(struct panthor_device *ptdev) | 29 | static int panthor_gpu_coherency_init(struct panthor_device *ptdev) |
| 29 | { | 30 | { |
| 31 | BUILD_BUG_ON(GPU_COHERENCY_NONE != DRM_PANTHOR_GPU_COHERENCY_NONE); | ||
| 32 | BUILD_BUG_ON(GPU_COHERENCY_ACE_LITE != DRM_PANTHOR_GPU_COHERENCY_ACE_LITE); | ||
| 33 | BUILD_BUG_ON(GPU_COHERENCY_ACE != DRM_PANTHOR_GPU_COHERENCY_ACE); | ||
| 34 | |||
| 35 | /* Start with no coherency, and update it if the device is flagged coherent. */ | ||
| 36 | ptdev->gpu_info.selected_coherency = GPU_COHERENCY_NONE; | ||
| 30 | ptdev->coherent = device_get_dma_attr(ptdev->base.dev) == DEV_DMA_COHERENT; | 37 | ptdev->coherent = device_get_dma_attr(ptdev->base.dev) == DEV_DMA_COHERENT; |
| 31 | 38 | ||
| 32 | if (!ptdev->coherent) | 39 | if (!ptdev->coherent) |
| @@ -36,8 +43,10 @@ static int panthor_gpu_coherency_init(struct panthor_device *ptdev) · 3 unmodified lines | |||
| 36 | * ACE protocol has never been supported for command stream frontend GPUs. | 43 | * ACE protocol has never been supported for command stream frontend GPUs. |
| 37 | */ | 44 | */ |
| 38 | if ((gpu_read(ptdev, GPU_COHERENCY_FEATURES) & | 45 | if ((gpu_read(ptdev, GPU_COHERENCY_FEATURES) & |
| 39 | GPU_COHERENCY_PROT_BIT(ACE_LITE))) | 46 | GPU_COHERENCY_PROT_BIT(ACE_LITE))) { |
| 47 | ptdev->gpu_info.selected_coherency = GPU_COHERENCY_ACE_LITE; | ||
| 40 | return 0; | 48 | return 0; |
| 49 | } | ||
| 41 | 50 | ||
| 42 | drm_err(&ptdev->base, "Coherency not supported by the device"); | 51 | drm_err(&ptdev->base, "Coherency not supported by the device"); |
| 43 | return -ENOTSUPP; | 52 | return -ENOTSUPP; |
| @@ -294,6 +303,8 @@ int panthor_device_init(struct panthor_device *ptdev) · 250 unmodified lines | |||
| 294 | if (ret) | 303 | if (ret) |
| 295 | goto err_unplug_fw; | 304 | goto err_unplug_fw; |
| 296 | 305 | ||
| 306 | panthor_gem_init(ptdev); | ||
| 307 | |||
| 297 | /* ~3 frames */ | 308 | /* ~3 frames */ |
| 298 | pm_runtime_set_autosuspend_delay(ptdev->base.dev, 50); | 309 | pm_runtime_set_autosuspend_delay(ptdev->base.dev, 50); |
| 299 | pm_runtime_use_autosuspend(ptdev->base.dev); | 310 | pm_runtime_use_autosuspend(ptdev->base.dev); |
| @@ -177,7 +177,8 @@ panthor_get_uobj_array(const struct drm_panthor_obj_array *in, u32 min_stride, · 176 unmodified lines | |||
| 177 | PANTHOR_UOBJ_DECL(struct drm_panthor_sync_op, timeline_value), \ | 177 | PANTHOR_UOBJ_DECL(struct drm_panthor_sync_op, timeline_value), \ |
| 178 | PANTHOR_UOBJ_DECL(struct drm_panthor_queue_submit, syncs), \ | 178 | PANTHOR_UOBJ_DECL(struct drm_panthor_queue_submit, syncs), \ |
| 179 | PANTHOR_UOBJ_DECL(struct drm_panthor_queue_create, ringbuf_size), \ | 179 | PANTHOR_UOBJ_DECL(struct drm_panthor_queue_create, ringbuf_size), \ |
| 180 | PANTHOR_UOBJ_DECL(struct drm_panthor_vm_bind_op, syncs)) | 180 | PANTHOR_UOBJ_DECL(struct drm_panthor_vm_bind_op, syncs), \ |
| 181 | PANTHOR_UOBJ_DECL(struct drm_panthor_bo_sync_op, size)) | ||
| 181 | 182 | ||
| 182 | /** | 183 | /** |
| 183 | * PANTHOR_UOBJ_SET() - Copy a kernel object to a user object. | 184 | * PANTHOR_UOBJ_SET() - Copy a kernel object to a user object. |
| @@ -901,7 +902,8 @@ static int panthor_ioctl_vm_destroy(struct drm_device *ddev, void *data, · 717 unmodified lines | |||
| 901 | return panthor_vm_pool_destroy_vm(pfile->vms, args->id); | 902 | return panthor_vm_pool_destroy_vm(pfile->vms, args->id); |
| 902 | } | 903 | } |
| 903 | 904 | ||
| 904 | #define PANTHOR_BO_FLAGS DRM_PANTHOR_BO_NO_MMAP | 905 | #define PANTHOR_BO_FLAGS (DRM_PANTHOR_BO_NO_MMAP | \ |
| 906 | DRM_PANTHOR_BO_WB_MMAP) | ||
| 905 | 907 | ||
| 906 | static int panthor_ioctl_bo_create(struct drm_device *ddev, void *data, | 908 | static int panthor_ioctl_bo_create(struct drm_device *ddev, void *data, |
| 907 | struct drm_file *file) | 909 | struct drm_file *file) |
| @@ -920,6 +922,10 @@ static int panthor_ioctl_bo_create(struct drm_device *ddev, void *data, · 12 unmodified lines | |||
| 920 | goto out_dev_exit; | 922 | goto out_dev_exit; |
| 921 | } | 923 | } |
| 922 | 924 | ||
| 925 | if ((args->flags & DRM_PANTHOR_BO_NO_MMAP) && | ||
| 926 | (args->flags & DRM_PANTHOR_BO_WB_MMAP)) | ||
| 927 | return -EINVAL; | ||
| 928 | |||
| 923 | if (args->exclusive_vm_id) { | 929 | if (args->exclusive_vm_id) { |
| 924 | vm = panthor_vm_pool_get_vm(pfile->vms, args->exclusive_vm_id); | 930 | vm = panthor_vm_pool_get_vm(pfile->vms, args->exclusive_vm_id); |
| 925 | if (!vm) { | 931 | if (!vm) { |
| @@ -1396,6 +1402,66 @@ static int panthor_ioctl_set_user_mmio_offset(struct drm_device *ddev, · 470 unmodified lines | |||
| 1396 | return 0; | 1402 | return 0; |
| 1397 | } | 1403 | } |
| 1398 | 1404 | ||
| 1405 | static int panthor_ioctl_bo_sync(struct drm_device *ddev, void *data, | ||
| 1406 | struct drm_file *file) | ||
| 1407 | { | ||
| 1408 | struct drm_panthor_bo_sync *args = data; | ||
| 1409 | struct drm_panthor_bo_sync_op *ops; | ||
| 1410 | struct drm_gem_object *obj; | ||
| 1411 | int ret; | ||
| 1412 | |||
| 1413 | if (!args->ops.count) | ||
| 1414 | return 0; | ||
| 1415 | |||
| 1416 | ret = PANTHOR_UOBJ_GET_ARRAY(ops, &args->ops); | ||
| 1417 | if (ret) | ||
| 1418 | return ret; | ||
| 1419 | |||
| 1420 | for (u32 i = 0; i < args->ops.count; i++) { | ||
| 1421 | obj = drm_gem_object_lookup(file, ops[i].handle); | ||
| 1422 | if (!obj) { | ||
| 1423 | ret = -ENOENT; | ||
| 1424 | goto err_ops; | ||
| 1425 | } | ||
| 1426 | |||
| 1427 | ret = panthor_gem_sync(obj, ops[i].type, ops[i].offset, | ||
| 1428 | ops[i].size); | ||
| 1429 | |||
| 1430 | drm_gem_object_put(obj); | ||
| 1431 | |||
| 1432 | if (ret) | ||
| 1433 | goto err_ops; | ||
| 1434 | } | ||
| 1435 | |||
| 1436 | err_ops: | ||
| 1437 | kvfree(ops); | ||
| 1438 | |||
| 1439 | return ret; | ||
| 1440 | } | ||
| 1441 | |||
| 1442 | static int panthor_ioctl_bo_query_info(struct drm_device *ddev, void *data, | ||
| 1443 | struct drm_file *file) | ||
| 1444 | { | ||
| 1445 | struct drm_panthor_bo_query_info *args = data; | ||
| 1446 | struct panthor_gem_object *bo; | ||
| 1447 | struct drm_gem_object *obj; | ||
| 1448 | |||
| 1449 | obj = drm_gem_object_lookup(file, args->handle); | ||
| 1450 | if (!obj) | ||
| 1451 | return -ENOENT; | ||
| 1452 | |||
| 1453 | bo = to_panthor_bo(obj); | ||
| 1454 | args->pad = 0; | ||
| 1455 | args->create_flags = bo->flags; | ||
| 1456 | |||
| 1457 | args->extra_flags = 0; | ||
| 1458 | if (drm_gem_is_imported(&bo->base.base)) | ||
| 1459 | args->extra_flags |= DRM_PANTHOR_BO_IS_IMPORTED; | ||
| 1460 | |||
| 1461 | drm_gem_object_put(obj); | ||
| 1462 | return 0; | ||
| 1463 | } | ||
| 1464 | |||
| 1399 | static int | 1465 | static int |
| 1400 | panthor_open(struct drm_device *ddev, struct drm_file *file) | 1466 | panthor_open(struct drm_device *ddev, struct drm_file *file) |
| 1401 | { | 1467 | { |
| @@ -1470,6 +1536,8 @@ static const struct drm_ioctl_desc panthor_drm_driver_ioctls[] = { · 68 unmodified lines | |||
| 1470 | PANTHOR_IOCTL(GROUP_SUBMIT, group_submit, DRM_RENDER_ALLOW), | 1536 | PANTHOR_IOCTL(GROUP_SUBMIT, group_submit, DRM_RENDER_ALLOW), |
| 1471 | PANTHOR_IOCTL(BO_SET_LABEL, bo_set_label, DRM_RENDER_ALLOW), | 1537 | PANTHOR_IOCTL(BO_SET_LABEL, bo_set_label, DRM_RENDER_ALLOW), |
| 1472 | PANTHOR_IOCTL(SET_USER_MMIO_OFFSET, set_user_mmio_offset, DRM_RENDER_ALLOW), | 1538 | PANTHOR_IOCTL(SET_USER_MMIO_OFFSET, set_user_mmio_offset, DRM_RENDER_ALLOW), |
| 1539 | PANTHOR_IOCTL(BO_SYNC, bo_sync, DRM_RENDER_ALLOW), | ||
| 1540 | PANTHOR_IOCTL(BO_QUERY_INFO, bo_query_info, DRM_RENDER_ALLOW), | ||
| 1473 | }; | 1541 | }; |
| 1474 | 1542 | ||
| 1475 | static int panthor_mmap(struct file *filp, struct vm_area_struct *vma) | 1543 | static int panthor_mmap(struct file *filp, struct vm_area_struct *vma) |
| @@ -1559,6 +1627,7 @@ static const struct file_operations panthor_drm_driver_fops = { · 83 unmodified lines | |||
| 1559 | .read = drm_read, | 1627 | .read = drm_read, |
| 1560 | .llseek = noop_llseek, | 1628 | .llseek = noop_llseek, |
| 1561 | .mmap = panthor_mmap, | 1629 | .mmap = panthor_mmap, |
| 1630 | .get_unmapped_area = drm_gem_get_unmapped_area, | ||
| 1562 | .show_fdinfo = drm_show_fdinfo, | 1631 | .show_fdinfo = drm_show_fdinfo, |
| 1563 | .fop_flags = FOP_UNSIGNED_OFFSET, | 1632 | .fop_flags = FOP_UNSIGNED_OFFSET, |
| 1564 | }; | 1633 | }; |
| @@ -1604,6 +1673,11 @@ static void panthor_debugfs_init(struct drm_minor *minor) · 39 unmodified lines | |||
| 1604 | * - 1.3 - adds DRM_PANTHOR_GROUP_STATE_INNOCENT flag | 1673 | * - 1.3 - adds DRM_PANTHOR_GROUP_STATE_INNOCENT flag |
| 1605 | * - 1.4 - adds DRM_IOCTL_PANTHOR_BO_SET_LABEL ioctl | 1674 | * - 1.4 - adds DRM_IOCTL_PANTHOR_BO_SET_LABEL ioctl |
| 1606 | * - 1.5 - adds DRM_PANTHOR_SET_USER_MMIO_OFFSET ioctl | 1675 | * - 1.5 - adds DRM_PANTHOR_SET_USER_MMIO_OFFSET ioctl |
| 1676 | * - 1.6 - enables GLB_COUNTER_EN | ||
| 1677 | * - 1.7 - adds DRM_PANTHOR_BO_WB_MMAP flag | ||
| 1678 | * - adds DRM_IOCTL_PANTHOR_BO_SYNC ioctl | ||
| 1679 | * - adds DRM_IOCTL_PANTHOR_BO_QUERY_INFO ioctl | ||
| 1680 | * - adds drm_panthor_gpu_info::selected_coherency | ||
| 1607 | */ | 1681 | */ |
| 1608 | static const struct drm_driver panthor_drm_driver = { | 1682 | static const struct drm_driver panthor_drm_driver = { |
| 1609 | .driver_features = DRIVER_RENDER | DRIVER_GEM | DRIVER_SYNCOBJ | | 1683 | .driver_features = DRIVER_RENDER | DRIVER_GEM | DRIVER_SYNCOBJ | |
| @@ -1617,15 +1691,22 @@ static const struct drm_driver panthor_drm_driver = { · 7 unmodified lines | |||
| 1617 | .name = "panthor", | 1691 | .name = "panthor", |
| 1618 | .desc = "Panthor DRM driver", | 1692 | .desc = "Panthor DRM driver", |
| 1619 | .major = 1, | 1693 | .major = 1, |
| 1620 | .minor = 5, | 1694 | .minor = 7, |
| 1621 | 1695 | ||
| 1622 | .gem_create_object = panthor_gem_create_object, | 1696 | .gem_create_object = panthor_gem_create_object, |
| 1623 | .gem_prime_import_sg_table = drm_gem_shmem_prime_import_sg_table, | 1697 | .gem_prime_import_sg_table = drm_gem_shmem_prime_import_sg_table, |
| 1698 | .gem_prime_import = panthor_gem_prime_import, | ||
| 1624 | #ifdef CONFIG_DEBUG_FS | 1699 | #ifdef CONFIG_DEBUG_FS |
| 1625 | .debugfs_init = panthor_debugfs_init, | 1700 | .debugfs_init = panthor_debugfs_init, |
| 1626 | #endif | 1701 | #endif |
| 1627 | }; | 1702 | }; |
| 1628 | 1703 | ||
| 1704 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE | ||
| 1705 | bool panthor_transparent_hugepage = true; | ||
| 1706 | module_param_named(transparent_hugepage, panthor_transparent_hugepage, bool, 0400); | ||
| 1707 | MODULE_PARM_DESC(transparent_hugepage, "Use a dedicated tmpfs mount point with Transparent Hugepage enabled (true = default)"); | ||
| 1708 | #endif | ||
| 1709 | |||
| 1629 | static int panthor_probe(struct platform_device *pdev) | 1710 | static int panthor_probe(struct platform_device *pdev) |
| 1630 | { | 1711 | { |
| 1631 | struct panthor_device *ptdev; | 1712 | struct panthor_device *ptdev; |
| @@ -0,0 +1,9 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 or MIT */ | ||
| 2 | /* Copyright 2025 Amazon.com, Inc. or its affiliates */ | ||
| 3 | |||
| 4 | #ifndef __PANTHOR_DRV_H__ | ||
| 5 | #define __PANTHOR_DRV_H__ | ||
| 6 | |||
| 7 | extern bool panthor_transparent_hugepage; | ||
| 8 | |||
| 9 | #endif | ||
| @@ -1044,7 +1044,8 @@ static void panthor_fw_init_global_iface(struct panthor_device *ptdev) · 1043 unmodified lines | |||
| 1044 | if (panthor_fw_has_glb_state(ptdev)) | 1044 | if (panthor_fw_has_glb_state(ptdev)) |
| 1045 | glb_iface->input->ack_irq_mask |= GLB_STATE_MASK; | 1045 | glb_iface->input->ack_irq_mask |= GLB_STATE_MASK; |
| 1046 | 1046 | ||
| 1047 | panthor_fw_update_reqs(glb_iface, req, GLB_IDLE_EN, GLB_IDLE_EN); | 1047 | panthor_fw_update_reqs(glb_iface, req, GLB_IDLE_EN | GLB_COUNTER_EN, |
| 1048 | GLB_IDLE_EN | GLB_COUNTER_EN); | ||
| 1048 | panthor_fw_toggle_reqs(glb_iface, req, ack, | 1049 | panthor_fw_toggle_reqs(glb_iface, req, ack, |
| 1049 | GLB_CFG_ALLOC_EN | | 1050 | GLB_CFG_ALLOC_EN | |
| 1050 | GLB_CFG_POWEROFF_TIMER | | 1051 | GLB_CFG_POWEROFF_TIMER | |
| @@ -1187,7 +1188,6 @@ void panthor_fw_pre_reset(struct panthor_device *ptdev, bool on_hang) · 136 unmodified lines | |||
| 1187 | else | 1188 | else |
| 1188 | ptdev->reset.fast = true; | 1189 | ptdev->reset.fast = true; |
| 1189 | } | 1190 | } |
| 1190 | panthor_fw_stop(ptdev); | ||
| 1191 | 1191 | ||
| 1192 | panthor_job_irq_suspend(&ptdev->fw->irq); | 1192 | panthor_job_irq_suspend(&ptdev->fw->irq); |
| 1193 | panthor_fw_stop(ptdev); | 1193 | panthor_fw_stop(ptdev); |
| @@ -1,6 +1,7 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 or MIT | 1 | // SPDX-License-Identifier: GPL-2.0 or MIT |
| 2 | /* Copyright 2019 Linaro, Ltd, Rob Herring <robh@kernel.org> */ | 2 | /* Copyright 2019 Linaro, Ltd, Rob Herring <robh@kernel.org> */ |
| 3 | /* Copyright 2023 Collabora ltd. */ | 3 | /* Copyright 2023 Collabora ltd. */ |
| 4 | /* Copyright 2025 Amazon.com, Inc. or its affiliates */ | ||
| 4 | 5 | ||
| 5 | #include <linux/cleanup.h> | 6 | #include <linux/cleanup.h> |
| 6 | #include <linux/dma-buf.h> | 7 | #include <linux/dma-buf.h> |
| @@ -12,10 +13,27 @@ · 5 unmodified lines | |||
| 12 | #include <drm/panthor_drm.h> | 13 | #include <drm/panthor_drm.h> |
| 13 | 14 | ||
| 14 | #include "panthor_device.h" | 15 | #include "panthor_device.h" |
| 16 | #include "panthor_drv.h" | ||
| 15 | #include "panthor_fw.h" | 17 | #include "panthor_fw.h" |
| 16 | #include "panthor_gem.h" | 18 | #include "panthor_gem.h" |
| 17 | #include "panthor_mmu.h" | 19 | #include "panthor_mmu.h" |
| 18 | 20 | ||
| 21 | void panthor_gem_init(struct panthor_device *ptdev) | ||
| 22 | { | ||
| 23 | int err; | ||
| 24 | |||
| 25 | if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) && | ||
| 26 | !panthor_transparent_hugepage) | ||
| 27 | return; | ||
| 28 | |||
| 29 | err = drm_gem_huge_mnt_create(&ptdev->base, "within_size"); | ||
| 30 | if (drm_gem_get_huge_mnt(&ptdev->base)) | ||
| 31 | drm_info(&ptdev->base, "Using Transparent Hugepage\n"); | ||
| 32 | else if (err) | ||
| 33 | drm_warn(&ptdev->base, "Can't use Transparent Hugepage (%d)\n", | ||
| 34 | err); | ||
| 35 | } | ||
| 36 | |||
| 19 | #ifdef CONFIG_DEBUG_FS | 37 | #ifdef CONFIG_DEBUG_FS |
| 20 | static void panthor_gem_debugfs_bo_init(struct panthor_gem_object *bo) | 38 | static void panthor_gem_debugfs_bo_init(struct panthor_gem_object *bo) |
| 21 | { | 39 | { |
| @@ -59,6 +77,39 @@ static void panthor_gem_debugfs_set_usage_flags(struct panthor_gem_object *bo, u · 37 unmodified lines | |||
| 59 | static void panthor_gem_debugfs_bo_init(struct panthor_gem_object *bo) {} | 77 | static void panthor_gem_debugfs_bo_init(struct panthor_gem_object *bo) {} |
| 60 | #endif | 78 | #endif |
| 61 | 79 | ||
| 80 | static bool | ||
| 81 | should_map_wc(struct panthor_gem_object *bo, struct panthor_vm *exclusive_vm) | ||
| 82 | { | ||
| 83 | struct panthor_device *ptdev = container_of(bo->base.base.dev, struct panthor_device, base); | ||
| 84 | |||
| 85 | /* We can't do uncached mappings if the device is coherent, | ||
| 86 | * because the zeroing done by the shmem layer at page allocation | ||
| 87 | * time happens on a cached mapping which isn't CPU-flushed (at least | ||
| 88 | * not on Arm64 where the flush is deferred to PTE setup time, and | ||
| 89 | * only done conditionally based on the mapping permissions). We can't | ||
| 90 | * rely on dma_map_sgtable()/dma_sync_sgtable_for_xxx() either to flush | ||
| 91 | * those, because they are NOPed if dma_dev_coherent() returns true. | ||
| 92 | * | ||
| 93 | * FIXME: Note that this problem is going to pop up again when we | ||
| 94 | * decide to support mapping buffers with the NO_MMAP flag as | ||
| 95 | * non-shareable (AKA buffers accessed only by the GPU), because we | ||
| 96 | * need the same CPU flush to happen after page allocation, otherwise | ||
| 97 | * there's a risk of data leak or late corruption caused by a dirty | ||
| 98 | * cacheline being evicted. At this point we'll need a way to force | ||
| 99 | * CPU cache maintenance regardless of whether the device is coherent | ||
| 100 | * or not. | ||
| 101 | */ | ||
| 102 | if (ptdev->coherent) | ||
| 103 | return false; | ||
| 104 | |||
| 105 | /* Cached mappings are explicitly requested, so no write-combine. */ | ||
| 106 | if (bo->flags & DRM_PANTHOR_BO_WB_MMAP) | ||
| 107 | return false; | ||
| 108 | |||
| 109 | /* The default is write-combine. */ | ||
| 110 | return true; | ||
| 111 | } | ||
| 112 | |||
| 62 | static void panthor_gem_free_object(struct drm_gem_object *obj) | 113 | static void panthor_gem_free_object(struct drm_gem_object *obj) |
| 63 | { | 114 | { |
| 64 | struct panthor_gem_object *bo = to_panthor_bo(obj); | 115 | struct panthor_gem_object *bo = to_panthor_bo(obj); |
| @@ -145,6 +196,7 @@ panthor_kernel_bo_create(struct panthor_device *ptdev, struct panthor_vm *vm, · 80 unmodified lines | |||
| 145 | bo = to_panthor_bo(&obj->base); | 196 | bo = to_panthor_bo(&obj->base); |
| 146 | kbo->obj = &obj->base; | 197 | kbo->obj = &obj->base; |
| 147 | bo->flags = bo_flags; | 198 | bo->flags = bo_flags; |
| 199 | bo->base.map_wc = should_map_wc(bo, vm); | ||
| 148 | bo->exclusive_vm_root_gem = panthor_vm_root_gem(vm); | 200 | bo->exclusive_vm_root_gem = panthor_vm_root_gem(vm); |
| 149 | drm_gem_object_get(bo->exclusive_vm_root_gem); | 201 | drm_gem_object_get(bo->exclusive_vm_root_gem); |
| 150 | bo->base.base.resv = bo->exclusive_vm_root_gem->resv; | 202 | bo->base.base.resv = bo->exclusive_vm_root_gem->resv; |
| @@ -184,14 +236,130 @@ err_free_bo: · 33 unmodified lines | |||
| 184 | return ERR_PTR(ret); | 236 | return ERR_PTR(ret); |
| 185 | } | 237 | } |
| 186 | 238 | ||
| 239 | static struct sg_table * | ||
| 240 | panthor_gem_prime_map_dma_buf(struct dma_buf_attachment *attach, | ||
| 241 | enum dma_data_direction dir) | ||
| 242 | { | ||
| 243 | struct sg_table *sgt = drm_gem_map_dma_buf(attach, dir); | ||
| 244 | |||
| 245 | if (!IS_ERR(sgt)) | ||
| 246 | attach->priv = sgt; | ||
| 247 | |||
| 248 | return sgt; | ||
| 249 | } | ||
| 250 | |||
| 251 | static void | ||
| 252 | panthor_gem_prime_unmap_dma_buf(struct dma_buf_attachment *attach, | ||
| 253 | struct sg_table *sgt, | ||
| 254 | enum dma_data_direction dir) | ||
| 255 | { | ||
| 256 | attach->priv = NULL; | ||
| 257 | drm_gem_unmap_dma_buf(attach, sgt, dir); | ||
| 258 | } | ||
| 259 | |||
| 260 | static int | ||
| 261 | panthor_gem_prime_begin_cpu_access(struct dma_buf *dma_buf, | ||
| 262 | enum dma_data_direction dir) | ||
| 263 | { | ||
| 264 | struct drm_gem_object *obj = dma_buf->priv; | ||
| 265 | struct drm_device *dev = obj->dev; | ||
| 266 | struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); | ||
| 267 | struct dma_buf_attachment *attach; | ||
| 268 | |||
| 269 | dma_resv_lock(obj->resv, NULL); | ||
| 270 | if (shmem->sgt) | ||
| 271 | dma_sync_sgtable_for_cpu(dev->dev, shmem->sgt, dir); | ||
| 272 | |||
| 273 | if (shmem->vaddr) | ||
| 274 | invalidate_kernel_vmap_range(shmem->vaddr, shmem->base.size); | ||
| 275 | |||
| 276 | list_for_each_entry(attach, &dma_buf->attachments, node) { | ||
| 277 | struct sg_table *sgt = attach->priv; | ||
| 278 | |||
| 279 | if (sgt) | ||
| 280 | dma_sync_sgtable_for_cpu(attach->dev, sgt, dir); | ||
| 281 | } | ||
| 282 | dma_resv_unlock(obj->resv); | ||
| 283 | |||
| 284 | return 0; | ||
| 285 | } | ||
| 286 | |||
| 287 | static int | ||
| 288 | panthor_gem_prime_end_cpu_access(struct dma_buf *dma_buf, | ||
| 289 | enum dma_data_direction dir) | ||
| 290 | { | ||
| 291 | struct drm_gem_object *obj = dma_buf->priv; | ||
| 292 | struct drm_device *dev = obj->dev; | ||
| 293 | struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); | ||
| 294 | struct dma_buf_attachment *attach; | ||
| 295 | |||
| 296 | dma_resv_lock(obj->resv, NULL); | ||
| 297 | list_for_each_entry(attach, &dma_buf->attachments, node) { | ||
| 298 | struct sg_table *sgt = attach->priv; | ||
| 299 | |||
| 300 | if (sgt) | ||
| 301 | dma_sync_sgtable_for_device(attach->dev, sgt, dir); | ||
| 302 | } | ||
| 303 | |||
| 304 | if (shmem->vaddr) | ||
| 305 | flush_kernel_vmap_range(shmem->vaddr, shmem->base.size); | ||
| 306 | |||
| 307 | if (shmem->sgt) | ||
| 308 | dma_sync_sgtable_for_device(dev->dev, shmem->sgt, dir); | ||
| 309 | |||
| 310 | dma_resv_unlock(obj->resv); | ||
| 311 | return 0; | ||
| 312 | } | ||
| 313 | |||
| 314 | static const struct dma_buf_ops panthor_dma_buf_ops = { | ||
| 315 | .attach = drm_gem_map_attach, | ||
| 316 | .detach = drm_gem_map_detach, | ||
| 317 | .map_dma_buf = panthor_gem_prime_map_dma_buf, | ||
| 318 | .unmap_dma_buf = panthor_gem_prime_unmap_dma_buf, | ||
| 319 | .release = drm_gem_dmabuf_release, | ||
| 320 | .mmap = drm_gem_dmabuf_mmap, | ||
| 321 | .vmap = drm_gem_dmabuf_vmap, | ||
| 322 | .vunmap = drm_gem_dmabuf_vunmap, | ||
| 323 | .begin_cpu_access = panthor_gem_prime_begin_cpu_access, | ||
| 324 | .end_cpu_access = panthor_gem_prime_end_cpu_access, | ||
| 325 | }; | ||
| 326 | |||
| 187 | static struct dma_buf * | 327 | static struct dma_buf * |
| 188 | panthor_gem_prime_export(struct drm_gem_object *obj, int flags) | 328 | panthor_gem_prime_export(struct drm_gem_object *obj, int flags) |
| 189 | { | 329 | { |
| 330 | struct drm_device *dev = obj->dev; | ||
| 331 | struct dma_buf_export_info exp_info = { | ||
| 332 | .exp_name = KBUILD_MODNAME, | ||
| 333 | .owner = THIS_MODULE, | ||
| 334 | .ops = &panthor_dma_buf_ops, | ||
| 335 | .size = obj->size, | ||
| 336 | .flags = flags, | ||
| 337 | .priv = obj, | ||
| 338 | .resv = obj->resv, | ||
| 339 | }; | ||
| 340 | |||
| 190 | /* We can't export GEMs that have an exclusive VM. */ | 341 | /* We can't export GEMs that have an exclusive VM. */ |
| 191 | if (to_panthor_bo(obj)->exclusive_vm_root_gem) | 342 | if (to_panthor_bo(obj)->exclusive_vm_root_gem) |
| 192 | return ERR_PTR(-EINVAL); | 343 | return ERR_PTR(-EINVAL); |
| 193 | 344 | ||
| 194 | return drm_gem_prime_export(obj, flags); | 345 | return drm_gem_dmabuf_export(dev, &exp_info); |
| 346 | } | ||
| 347 | |||
| 348 | struct drm_gem_object * | ||
| 349 | panthor_gem_prime_import(struct drm_device *dev, | ||
| 350 | struct dma_buf *dma_buf) | ||
| 351 | { | ||
| 352 | struct drm_gem_object *obj = dma_buf->priv; | ||
| 353 | |||
| 354 | if (dma_buf->ops == &panthor_dma_buf_ops && obj->dev == dev) { | ||
| 355 | /* Importing dmabuf exported from our own gem increases | ||
| 356 | * refcount on gem itself instead of f_count of dmabuf. | ||
| 357 | */ | ||
| 358 | drm_gem_object_get(obj); | ||
| 359 | return obj; | ||
| 360 | } | ||
| 361 | |||
| 362 | return drm_gem_prime_import(dev, dma_buf); | ||
| 195 | } | 363 | } |
| 196 | 364 | ||
| 197 | static enum drm_gem_object_status panthor_gem_status(struct drm_gem_object *obj) | 365 | static enum drm_gem_object_status panthor_gem_status(struct drm_gem_object *obj) |
| @@ -229,7 +397,6 @@ static const struct drm_gem_object_funcs panthor_gem_funcs = { · 31 unmodified lines | |||
| 229 | */ | 397 | */ |
| 230 | struct drm_gem_object *panthor_gem_create_object(struct drm_device *ddev, size_t size) | 398 | struct drm_gem_object *panthor_gem_create_object(struct drm_device *ddev, size_t size) |
| 231 | { | 399 | { |
| 232 | struct panthor_device *ptdev = container_of(ddev, struct panthor_device, base); | ||
| 233 | struct panthor_gem_object *obj; | 400 | struct panthor_gem_object *obj; |
| 234 | 401 | ||
| 235 | obj = kzalloc(sizeof(*obj), GFP_KERNEL); | 402 | obj = kzalloc(sizeof(*obj), GFP_KERNEL); |
| @@ -237,7 +404,6 @@ struct drm_gem_object *panthor_gem_create_object(struct drm_device *ddev, size_t · 1 unmodified line | |||
| 237 | return ERR_PTR(-ENOMEM); | 404 | return ERR_PTR(-ENOMEM); |
| 238 | 405 | ||
| 239 | obj->base.base.funcs = &panthor_gem_funcs; | 406 | obj->base.base.funcs = &panthor_gem_funcs; |
| 240 | obj->base.map_wc = !ptdev->coherent; | ||
| 241 | mutex_init(&obj->label.lock); | 407 | mutex_init(&obj->label.lock); |
| 242 | 408 | ||
| 243 | panthor_gem_debugfs_bo_init(obj); | 409 | panthor_gem_debugfs_bo_init(obj); |
| @@ -272,6 +438,7 @@ panthor_gem_create_with_handle(struct drm_file *file, · 28 unmodified lines | |||
| 272 | 438 | ||
| 273 | bo = to_panthor_bo(&shmem->base); | 439 | bo = to_panthor_bo(&shmem->base); |
| 274 | bo->flags = flags; | 440 | bo->flags = flags; |
| 441 | bo->base.map_wc = should_map_wc(bo, exclusive_vm); | ||
| 275 | 442 | ||
| 276 | if (exclusive_vm) { | 443 | if (exclusive_vm) { |
| 277 | bo->exclusive_vm_root_gem = panthor_vm_root_gem(exclusive_vm); | 444 | bo->exclusive_vm_root_gem = panthor_vm_root_gem(exclusive_vm); |
| @@ -349,6 +516,91 @@ panthor_gem_kernel_bo_set_label(struct panthor_kernel_bo *bo, const char *label) · 71 unmodified lines | |||
| 349 | panthor_gem_bo_set_label(bo->obj, str); | 516 | panthor_gem_bo_set_label(bo->obj, str); |
| 350 | } | 517 | } |
| 351 | 518 | ||
| 519 | int | ||
| 520 | panthor_gem_sync(struct drm_gem_object *obj, u32 type, | ||
| 521 | u64 offset, u64 size) | ||
| 522 | { | ||
| 523 | struct panthor_gem_object *bo = to_panthor_bo(obj); | ||
| 524 | struct drm_gem_shmem_object *shmem = &bo->base; | ||
| 525 | const struct drm_device *dev = shmem->base.dev; | ||
| 526 | struct sg_table *sgt; | ||
| 527 | struct scatterlist *sgl; | ||
| 528 | unsigned int count; | ||
| 529 | |||
| 530 | /* Make sure the range is in bounds. */ | ||
| 531 | if (offset + size < offset || offset + size > shmem->base.size) | ||
| 532 | return -EINVAL; | ||
| 533 | |||
| 534 | /* Disallow CPU-cache maintenance on imported buffers. */ | ||
| 535 | if (drm_gem_is_imported(&shmem->base)) | ||
| 536 | return -EINVAL; | ||
| 537 | |||
| 538 | switch (type) { | ||
| 539 | case DRM_PANTHOR_BO_SYNC_CPU_CACHE_FLUSH: | ||
| 540 | case DRM_PANTHOR_BO_SYNC_CPU_CACHE_FLUSH_AND_INVALIDATE: | ||
| 541 | break; | ||
| 542 | |||
| 543 | default: | ||
| 544 | return -EINVAL; | ||
| 545 | } | ||
| 546 | |||
| 547 | /* Don't bother if it's WC-mapped */ | ||
| 548 | if (shmem->map_wc) | ||
| 549 | return 0; | ||
| 550 | |||
| 551 | /* Nothing to do if the size is zero. */ | ||
| 552 | if (size == 0) | ||
| 553 | return 0; | ||
| 554 | |||
| 555 | sgt = drm_gem_shmem_get_pages_sgt(shmem); | ||
| 556 | if (IS_ERR(sgt)) | ||
| 557 | return PTR_ERR(sgt); | ||
| 558 | |||
| 559 | for_each_sgtable_dma_sg(sgt, sgl, count) { | ||
| 560 | if (size == 0) | ||
| 561 | break; | ||
| 562 | |||
| 563 | dma_addr_t paddr = sg_dma_address(sgl); | ||
| 564 | size_t len = sg_dma_len(sgl); | ||
| 565 | |||
| 566 | if (len <= offset) { | ||
| 567 | offset -= len; | ||
| 568 | continue; | ||
| 569 | } | ||
| 570 | |||
| 571 | paddr += offset; | ||
| 572 | len -= offset; | ||
| 573 | len = min_t(size_t, len, size); | ||
| 574 | size -= len; | ||
| 575 | offset = 0; | ||
| 576 | |||
| 577 | /* It's unclear whether dma_sync_xxx() is the right API to do CPU | ||
| 578 | * cache maintenance given an IOMMU can register their own | ||
| 579 | * implementation doing more than just CPU cache flushes/invalidation, | ||
| 580 | * and what we really care about here is CPU caches only, but that's | ||
| 581 | * the best we have that is both arch-agnostic and does at least the | ||
| 582 | * CPU cache maintenance on a <page,offset,size> tuple. | ||
| 583 | * | ||
| 584 | * Also, I wish we could do a single | ||
| 585 | * | ||
| 586 | * dma_sync_single_for_device(BIDIR) | ||
| 587 | * | ||
| 588 | * and get a flush+invalidate, but that's not how it's implemented | ||
| 589 | * in practice (at least on arm64), so we have to make it | ||
| 590 | * | ||
| 591 | * dma_sync_single_for_device(TO_DEVICE) | ||
| 592 | * dma_sync_single_for_cpu(FROM_DEVICE) | ||
| 593 | * | ||
| 594 | * for the flush+invalidate case. | ||
| 595 | */ | ||
| 596 | dma_sync_single_for_device(dev->dev, paddr, len, DMA_TO_DEVICE); | ||
| 597 | if (type == DRM_PANTHOR_BO_SYNC_CPU_CACHE_FLUSH_AND_INVALIDATE) | ||
| 598 | dma_sync_single_for_cpu(dev->dev, paddr, len, DMA_FROM_DEVICE); | ||
| 599 | } | ||
| 600 | |||
| 601 | return 0; | ||
| 602 | } | ||
| 603 | |||
| 352 | #ifdef CONFIG_DEBUG_FS | 604 | #ifdef CONFIG_DEBUG_FS |
| 353 | struct gem_size_totals { | 605 | struct gem_size_totals { |
| 354 | size_t size; | 606 | size_t size; |
| @@ -136,6 +136,8 @@ struct panthor_gem_object *to_panthor_bo(struct drm_gem_object *obj) · 135 unmodified lines | |||
| 136 | return container_of(to_drm_gem_shmem_obj(obj), struct panthor_gem_object, base); | 136 | return container_of(to_drm_gem_shmem_obj(obj), struct panthor_gem_object, base); |
| 137 | } | 137 | } |
| 138 | 138 | ||
| 139 | void panthor_gem_init(struct panthor_device *ptdev); | ||
| 140 | |||
| 139 | struct drm_gem_object *panthor_gem_create_object(struct drm_device *ddev, size_t size); | 141 | struct drm_gem_object *panthor_gem_create_object(struct drm_device *ddev, size_t size); |
| 140 | 142 | ||
| 141 | int | 143 | int |
| @@ -146,6 +148,12 @@ panthor_gem_create_with_handle(struct drm_file *file, · 4 unmodified lines | |||
| 146 | 148 | ||
| 147 | void panthor_gem_bo_set_label(struct drm_gem_object *obj, const char *label); | 149 | void panthor_gem_bo_set_label(struct drm_gem_object *obj, const char *label); |
| 148 | void panthor_gem_kernel_bo_set_label(struct panthor_kernel_bo *bo, const char *label); | 150 | void panthor_gem_kernel_bo_set_label(struct panthor_kernel_bo *bo, const char *label); |
| 151 | int panthor_gem_sync(struct drm_gem_object *obj, | ||
| 152 | u32 type, u64 offset, u64 size); | ||
| 153 | |||
| 154 | struct drm_gem_object * | ||
| 155 | panthor_gem_prime_import(struct drm_device *dev, | ||
| 156 | struct dma_buf *dma_buf); | ||
| 149 | 157 | ||
| 150 | static inline u64 | 158 | static inline u64 |
| 151 | panthor_kernel_bo_gpuva(struct panthor_kernel_bo *bo) | 159 | panthor_kernel_bo_gpuva(struct panthor_kernel_bo *bo) |
| @@ -51,7 +51,7 @@ struct panthor_gpu { · 50 unmodified lines | |||
| 51 | static void panthor_gpu_coherency_set(struct panthor_device *ptdev) | 51 | static void panthor_gpu_coherency_set(struct panthor_device *ptdev) |
| 52 | { | 52 | { |
| 53 | gpu_write(ptdev, GPU_COHERENCY_PROTOCOL, | 53 | gpu_write(ptdev, GPU_COHERENCY_PROTOCOL, |
| 54 | ptdev->coherent ? GPU_COHERENCY_PROT_BIT(ACE_LITE) : GPU_COHERENCY_NONE); | 54 | ptdev->gpu_info.selected_coherency); |
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | static void panthor_gpu_l2_config_set(struct panthor_device *ptdev) | 57 | static void panthor_gpu_l2_config_set(struct panthor_device *ptdev) |
| @@ -289,38 +289,42 @@ int panthor_gpu_l2_power_on(struct panthor_device *ptdev) · 231 unmodified lines | |||
| 289 | int panthor_gpu_flush_caches(struct panthor_device *ptdev, | 289 | int panthor_gpu_flush_caches(struct panthor_device *ptdev, |
| 290 | u32 l2, u32 lsc, u32 other) | 290 | u32 l2, u32 lsc, u32 other) |
| 291 | { | 291 | { |
| 292 | bool timedout = false; | ||
| 293 | unsigned long flags; | 292 | unsigned long flags; |
| 293 | int ret = 0; | ||
| 294 | 294 | ||
| 295 | /* Serialize cache flush operations. */ | 295 | /* Serialize cache flush operations. */ |
| 296 | guard(mutex)(&ptdev->gpu->cache_flush_lock); | 296 | guard(mutex)(&ptdev->gpu->cache_flush_lock); |
| 297 | 297 | ||
| 298 | spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags); | 298 | spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags); |
| 299 | if (!drm_WARN_ON(&ptdev->base, | 299 | if (!(ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED)) { |
| 300 | ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED)) { | ||
| 301 | ptdev->gpu->pending_reqs |= GPU_IRQ_CLEAN_CACHES_COMPLETED; | 300 | ptdev->gpu->pending_reqs |= GPU_IRQ_CLEAN_CACHES_COMPLETED; |
| 302 | gpu_write(ptdev, GPU_CMD, GPU_FLUSH_CACHES(l2, lsc, other)); | 301 | gpu_write(ptdev, GPU_CMD, GPU_FLUSH_CACHES(l2, lsc, other)); |
| 302 | } else { | ||
| 303 | ret = -EIO; | ||
| 303 | } | 304 | } |
| 304 | spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags); | 305 | spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags); |
| 305 | 306 | ||
| 307 | if (ret) | ||
| 308 | return ret; | ||
| 309 | |||
| 306 | if (!wait_event_timeout(ptdev->gpu->reqs_acked, | 310 | if (!wait_event_timeout(ptdev->gpu->reqs_acked, |
| 307 | !(ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED), | 311 | !(ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED), |
| 308 | msecs_to_jiffies(100))) { | 312 | msecs_to_jiffies(100))) { |
| 309 | spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags); | 313 | spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags); |
| 310 | if ((ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED) != 0 && | 314 | if ((ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED) != 0 && |
| 311 | !(gpu_read(ptdev, GPU_INT_RAWSTAT) & GPU_IRQ_CLEAN_CACHES_COMPLETED)) | 315 | !(gpu_read(ptdev, GPU_INT_RAWSTAT) & GPU_IRQ_CLEAN_CACHES_COMPLETED)) |
| 312 | timedout = true; | 316 | ret = -ETIMEDOUT; |
| 313 | else | 317 | else |
| 314 | ptdev->gpu->pending_reqs &= ~GPU_IRQ_CLEAN_CACHES_COMPLETED; | 318 | ptdev->gpu->pending_reqs &= ~GPU_IRQ_CLEAN_CACHES_COMPLETED; |
| 315 | spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags); | 319 | spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags); |
| 316 | } | 320 | } |
| 317 | 321 | ||
| 318 | if (timedout) { | 322 | if (ret) { |
| 323 | panthor_device_schedule_reset(ptdev); | ||
| 319 | drm_err(&ptdev->base, "Flush caches timeout"); | 324 | drm_err(&ptdev->base, "Flush caches timeout"); |
| 320 | return -ETIMEDOUT; | ||
| 321 | } | 325 | } |
| 322 | 326 | ||
| 323 | return 0; | 327 | return ret; |
| 324 | } | 328 | } |
| 325 | 329 | ||
| 326 | /** | 330 | /** |
| @@ -360,6 +364,7 @@ int panthor_gpu_soft_reset(struct panthor_device *ptdev) · 33 unmodified lines | |||
| 360 | return -ETIMEDOUT; | 364 | return -ETIMEDOUT; |
| 361 | } | 365 | } |
| 362 | 366 | ||
| 367 | ptdev->gpu->pending_reqs = 0; | ||
| 363 | return 0; | 368 | return 0; |
| 364 | } | 369 | } |
| 365 | 370 | ||
| @@ -375,6 +375,15 @@ struct panthor_vm { · 374 unmodified lines | |||
| 375 | * flagged as faulty as a result. | 375 | * flagged as faulty as a result. |
| 376 | */ | 376 | */ |
| 377 | bool unhandled_fault; | 377 | bool unhandled_fault; |
| 378 | |||
| 379 | /** @locked_region: Information about the currently locked region currently. */ | ||
| 380 | struct { | ||
| 381 | /** @locked_region.start: Start of the locked region. */ | ||
| 382 | u64 start; | ||
| 383 | |||
| 384 | /** @locked_region.size: Size of the locked region. */ | ||
| 385 | u64 size; | ||
| 386 | } locked_region; | ||
| 378 | }; | 387 | }; |
| 379 | 388 | ||
| 380 | /** | 389 | /** |
| @@ -510,27 +519,27 @@ static int wait_ready(struct panthor_device *ptdev, u32 as_nr) · 129 unmodified lines | |||
| 510 | return ret; | 519 | return ret; |
| 511 | } | 520 | } |
| 512 | 521 | ||
| 513 | static int write_cmd(struct panthor_device *ptdev, u32 as_nr, u32 cmd) | 522 | static int as_send_cmd_and_wait(struct panthor_device *ptdev, u32 as_nr, u32 cmd) |
| 514 | { | 523 | { |
| 515 | int status; | 524 | int status; |
| 516 | 525 | ||
| 517 | /* write AS_COMMAND when MMU is ready to accept another command */ | 526 | /* write AS_COMMAND when MMU is ready to accept another command */ |
| 518 | status = wait_ready(ptdev, as_nr); | 527 | status = wait_ready(ptdev, as_nr); |
| 519 | if (!status) | 528 | if (!status) { |
| 520 | gpu_write(ptdev, AS_COMMAND(as_nr), cmd); | 529 | gpu_write(ptdev, AS_COMMAND(as_nr), cmd); |
| 530 | status = wait_ready(ptdev, as_nr); | ||
| 531 | } | ||
| 521 | 532 | ||
| 522 | return status; | 533 | return status; |
| 523 | } | 534 | } |
| 524 | 535 | ||
| 525 | static void lock_region(struct panthor_device *ptdev, u32 as_nr, | 536 | static u64 pack_region_range(struct panthor_device *ptdev, u64 region_start, u64 size) |
| 526 | u64 region_start, u64 size) | ||
| 527 | { | 537 | { |
| 528 | u8 region_width; | 538 | u8 region_width; |
| 529 | u64 region; | ||
| 530 | u64 region_end = region_start + size; | 539 | u64 region_end = region_start + size; |
| 531 | 540 | ||
| 532 | if (!size) | 541 | if (drm_WARN_ON_ONCE(&ptdev->base, !size)) |
| 533 | return; | 542 | return 0; |
| 534 | 543 | ||
| 535 | /* | 544 | /* |
| 536 | * The locked region is a naturally aligned power of 2 block encoded as | 545 | * The locked region is a naturally aligned power of 2 block encoded as |
| @@ -549,106 +558,51 @@ static void lock_region(struct panthor_device *ptdev, u32 as_nr, · 12 unmodified lines | |||
| 549 | */ | 558 | */ |
| 550 | region_start &= GENMASK_ULL(63, region_width); | 559 | region_start &= GENMASK_ULL(63, region_width); |
| 551 | 560 | ||
| 552 | region = region_width | region_start; | 561 | return region_width | region_start; |
| 553 | |||
| 554 | /* Lock the region that needs to be updated */ | ||
| 555 | gpu_write64(ptdev, AS_LOCKADDR(as_nr), region); | ||
| 556 | write_cmd(ptdev, as_nr, AS_COMMAND_LOCK); | ||
| 557 | } | ||
| 558 | |||
| 559 | static int mmu_hw_do_operation_locked(struct panthor_device *ptdev, int as_nr, | ||
| 560 | u64 iova, u64 size, u32 op) | ||
| 561 | { | ||
| 562 | const u32 l2_flush_op = CACHE_CLEAN | CACHE_INV; | ||
| 563 | u32 lsc_flush_op; | ||
| 564 | int ret; | ||
| 565 | |||
| 566 | lockdep_assert_held(&ptdev->mmu->as.slots_lock); | ||
| 567 | |||
| 568 | switch (op) { | ||
| 569 | case AS_COMMAND_FLUSH_MEM: | ||
| 570 | lsc_flush_op = CACHE_CLEAN | CACHE_INV; | ||
| 571 | break; | ||
| 572 | case AS_COMMAND_FLUSH_PT: | ||
| 573 | lsc_flush_op = 0; | ||
| 574 | break; | ||
| 575 | default: | ||
| 576 | drm_WARN(&ptdev->base, 1, "Unexpected AS_COMMAND: %d", op); | ||
| 577 | return -EINVAL; | ||
| 578 | } | ||
| 579 | |||
| 580 | if (as_nr < 0) | ||
| 581 | return 0; | ||
| 582 | |||
| 583 | /* | ||
| 584 | * If the AS number is greater than zero, then we can be sure | ||
| 585 | * the device is up and running, so we don't need to explicitly | ||
| 586 | * power it up | ||
| 587 | */ | ||
| 588 | |||
| 589 | lock_region(ptdev, as_nr, iova, size); | ||
| 590 | |||
| 591 | ret = wait_ready(ptdev, as_nr); | ||
| 592 | if (ret) | ||
| 593 | return ret; | ||
| 594 | |||
| 595 | ret = panthor_gpu_flush_caches(ptdev, l2_flush_op, lsc_flush_op, 0); | ||
| 596 | if (ret) | ||
| 597 | return ret; | ||
| 598 | |||
| 599 | /* | ||
| 600 | * Explicitly unlock the region as the AS is not unlocked automatically | ||
| 601 | * at the end of the GPU_CONTROL cache flush command, unlike | ||
| 602 | * AS_COMMAND_FLUSH_MEM or AS_COMMAND_FLUSH_PT. | ||
| 603 | */ | ||
| 604 | write_cmd(ptdev, as_nr, AS_COMMAND_UNLOCK); | ||
| 605 | |||
| 606 | /* Wait for the unlock command to complete */ | ||
| 607 | return wait_ready(ptdev, as_nr); | ||
| 608 | } | ||
| 609 | |||
| 610 | static int mmu_hw_do_operation(struct panthor_vm *vm, | ||
| 611 | u64 iova, u64 size, u32 op) | ||
| 612 | { | ||
| 613 | struct panthor_device *ptdev = vm->ptdev; | ||
| 614 | int ret; | ||
| 615 | |||
| 616 | mutex_lock(&ptdev->mmu->as.slots_lock); | ||
| 617 | ret = mmu_hw_do_operation_locked(ptdev, vm->as.id, iova, size, op); | ||
| 618 | mutex_unlock(&ptdev->mmu->as.slots_lock); | ||
| 619 | |||
| 620 | return ret; | ||
| 621 | } | 562 | } |
| 622 | 563 | ||
| 623 | static int panthor_mmu_as_enable(struct panthor_device *ptdev, u32 as_nr, | 564 | static int panthor_mmu_as_enable(struct panthor_device *ptdev, u32 as_nr, |
| 624 | u64 transtab, u64 transcfg, u64 memattr) | 565 | u64 transtab, u64 transcfg, u64 memattr) |
| 625 | { | 566 | { |
| 626 | int ret; | ||
| 627 | |||
| 628 | ret = mmu_hw_do_operation_locked(ptdev, as_nr, 0, ~0ULL, AS_COMMAND_FLUSH_MEM); | ||
| 629 | if (ret) | ||
| 630 | return ret; | ||
| 631 | |||
| 632 | gpu_write64(ptdev, AS_TRANSTAB(as_nr), transtab); | 567 | gpu_write64(ptdev, AS_TRANSTAB(as_nr), transtab); |
| 633 | gpu_write64(ptdev, AS_MEMATTR(as_nr), memattr); | 568 | gpu_write64(ptdev, AS_MEMATTR(as_nr), memattr); |
| 634 | gpu_write64(ptdev, AS_TRANSCFG(as_nr), transcfg); | 569 | gpu_write64(ptdev, AS_TRANSCFG(as_nr), transcfg); |
| 635 | 570 | ||
| 636 | return write_cmd(ptdev, as_nr, AS_COMMAND_UPDATE); | 571 | return as_send_cmd_and_wait(ptdev, as_nr, AS_COMMAND_UPDATE); |
| 637 | } | 572 | } |
| 638 | 573 | ||
| 639 | static int panthor_mmu_as_disable(struct panthor_device *ptdev, u32 as_nr) | 574 | static int panthor_mmu_as_disable(struct panthor_device *ptdev, u32 as_nr, |
| 575 | bool recycle_slot) | ||
| 640 | { | 576 | { |
| 577 | struct panthor_vm *vm = ptdev->mmu->as.slots[as_nr].vm; | ||
| 641 | int ret; | 578 | int ret; |
| 642 | 579 | ||
| 643 | ret = mmu_hw_do_operation_locked(ptdev, as_nr, 0, ~0ULL, AS_COMMAND_FLUSH_MEM); | 580 | lockdep_assert_held(&ptdev->mmu->as.slots_lock); |
| 581 | |||
| 582 | /* Flush+invalidate RW caches, invalidate RO ones. */ | ||
| 583 | ret = panthor_gpu_flush_caches(ptdev, CACHE_CLEAN | CACHE_INV, | ||
| 584 | CACHE_CLEAN | CACHE_INV, CACHE_INV); | ||
| 644 | if (ret) | 585 | if (ret) |
| 645 | return ret; | 586 | return ret; |
| 646 | 587 | ||
| 588 | if (vm && vm->locked_region.size) { | ||
| 589 | /* Unlock the region if there's a lock pending. */ | ||
| 590 | ret = as_send_cmd_and_wait(ptdev, vm->as.id, AS_COMMAND_UNLOCK); | ||
| 591 | if (ret) | ||
| 592 | return ret; | ||
| 593 | } | ||
| 594 | |||
| 595 | /* If the slot is going to be used immediately, don't bother changing | ||
| 596 | * the config. | ||
| 597 | */ | ||
| 598 | if (recycle_slot) | ||
| 599 | return 0; | ||
| 600 | |||
| 647 | gpu_write64(ptdev, AS_TRANSTAB(as_nr), 0); | 601 | gpu_write64(ptdev, AS_TRANSTAB(as_nr), 0); |
| 648 | gpu_write64(ptdev, AS_MEMATTR(as_nr), 0); | 602 | gpu_write64(ptdev, AS_MEMATTR(as_nr), 0); |
| 649 | gpu_write64(ptdev, AS_TRANSCFG(as_nr), AS_TRANSCFG_ADRMODE_UNMAPPED); | 603 | gpu_write64(ptdev, AS_TRANSCFG(as_nr), AS_TRANSCFG_ADRMODE_UNMAPPED); |
| 650 | 604 | ||
| 651 | return write_cmd(ptdev, as_nr, AS_COMMAND_UPDATE); | 605 | return as_send_cmd_and_wait(ptdev, as_nr, AS_COMMAND_UPDATE); |
| 652 | } | 606 | } |
| 653 | 607 | ||
| 654 | static u32 panthor_mmu_fault_mask(struct panthor_device *ptdev, u32 value) | 608 | static u32 panthor_mmu_fault_mask(struct panthor_device *ptdev, u32 value) |
| @@ -722,6 +676,10 @@ int panthor_vm_active(struct panthor_vm *vm) · 67 unmodified lines | |||
| 722 | if (refcount_inc_not_zero(&vm->as.active_cnt)) | 676 | if (refcount_inc_not_zero(&vm->as.active_cnt)) |
| 723 | goto out_dev_exit; | 677 | goto out_dev_exit; |
| 724 | 678 | ||
| 679 | /* Make sure we don't race with lock/unlock_region() calls | ||
| 680 | * happening around VM bind operations. | ||
| 681 | */ | ||
| 682 | mutex_lock(&vm->op_lock); | ||
| 725 | mutex_lock(&ptdev->mmu->as.slots_lock); | 683 | mutex_lock(&ptdev->mmu->as.slots_lock); |
| 726 | 684 | ||
| 727 | if (refcount_inc_not_zero(&vm->as.active_cnt)) | 685 | if (refcount_inc_not_zero(&vm->as.active_cnt)) |
| @@ -759,6 +717,11 @@ int panthor_vm_active(struct panthor_vm *vm) · 31 unmodified lines | |||
| 759 | 717 | ||
| 760 | drm_WARN_ON(&ptdev->base, refcount_read(&lru_vm->as.active_cnt)); | 718 | drm_WARN_ON(&ptdev->base, refcount_read(&lru_vm->as.active_cnt)); |
| 761 | as = lru_vm->as.id; | 719 | as = lru_vm->as.id; |
| 720 | |||
| 721 | ret = panthor_mmu_as_disable(ptdev, as, true); | ||
| 722 | if (ret) | ||
| 723 | goto out_unlock; | ||
| 724 | |||
| 762 | panthor_vm_release_as_locked(lru_vm); | 725 | panthor_vm_release_as_locked(lru_vm); |
| 763 | } | 726 | } |
| 764 | 727 | ||
| @@ -789,6 +752,10 @@ out_enable_as: · 24 unmodified lines | |||
| 789 | gpu_write(ptdev, MMU_INT_MASK, ~ptdev->mmu->as.faulty_mask); | 752 | gpu_write(ptdev, MMU_INT_MASK, ~ptdev->mmu->as.faulty_mask); |
| 790 | } | 753 | } |
| 791 | 754 | ||
| 755 | /* The VM update is guarded by ::op_lock, which we take at the beginning | ||
| 756 | * of this function, so we don't expect any locked region here. | ||
| 757 | */ | ||
| 758 | drm_WARN_ON(&vm->ptdev->base, vm->locked_region.size > 0); | ||
| 792 | ret = panthor_mmu_as_enable(vm->ptdev, vm->as.id, transtab, transcfg, vm->memattr); | 759 | ret = panthor_mmu_as_enable(vm->ptdev, vm->as.id, transtab, transcfg, vm->memattr); |
| 793 | 760 | ||
| 794 | out_make_active: | 761 | out_make_active: |
| @@ -799,6 +766,7 @@ out_make_active: · 4 unmodified lines | |||
| 799 | 766 | ||
| 800 | out_unlock: | 767 | out_unlock: |
| 801 | mutex_unlock(&ptdev->mmu->as.slots_lock); | 768 | mutex_unlock(&ptdev->mmu->as.slots_lock); |
| 769 | mutex_unlock(&vm->op_lock); | ||
| 802 | 770 | ||
| 803 | out_dev_exit: | 771 | out_dev_exit: |
| 804 | drm_dev_exit(cookie); | 772 | drm_dev_exit(cookie); |
| @@ -882,44 +850,64 @@ static size_t get_pgsize(u64 addr, size_t size, size_t *count) · 77 unmodified lines | |||
| 882 | return SZ_2M; | 850 | return SZ_2M; |
| 883 | } | 851 | } |
| 884 | 852 | ||
| 885 | static int panthor_vm_flush_range(struct panthor_vm *vm, u64 iova, u64 size) | 853 | static void panthor_vm_declare_unusable(struct panthor_vm *vm) |
| 886 | { | 854 | { |
| 887 | struct panthor_device *ptdev = vm->ptdev; | 855 | struct panthor_device *ptdev = vm->ptdev; |
| 888 | int ret = 0, cookie; | 856 | int cookie; |
| 889 | |||
| 890 | if (vm->as.id < 0) | ||
| 891 | return 0; | ||
| 892 | 857 | ||
| 893 | /* If the device is unplugged, we just silently skip the flush. */ | 858 | if (vm->unusable) |
| 894 | if (!drm_dev_enter(&ptdev->base, &cookie)) | 859 | return; |
| 895 | return 0; | ||
| 896 | |||
| 897 | ret = mmu_hw_do_operation(vm, iova, size, AS_COMMAND_FLUSH_PT); | ||
| 898 | 860 | ||
| 899 | drm_dev_exit(cookie); | 861 | vm->unusable = true; |
| 900 | return ret; | 862 | mutex_lock(&ptdev->mmu->as.slots_lock); |
| 863 | if (vm->as.id >= 0 && drm_dev_enter(&ptdev->base, &cookie)) { | ||
| 864 | panthor_mmu_as_disable(ptdev, vm->as.id, false); | ||
| 865 | drm_dev_exit(cookie); | ||
| 866 | } | ||
| 867 | mutex_unlock(&ptdev->mmu->as.slots_lock); | ||
| 901 | } | 868 | } |
| 902 | 869 | ||
| 903 | static int panthor_vm_unmap_pages(struct panthor_vm *vm, u64 iova, u64 size) | 870 | static void panthor_vm_unmap_pages(struct panthor_vm *vm, u64 iova, u64 size) |
| 904 | { | 871 | { |
| 905 | struct panthor_device *ptdev = vm->ptdev; | 872 | struct panthor_device *ptdev = vm->ptdev; |
| 906 | struct io_pgtable_ops *ops = vm->pgtbl_ops; | 873 | struct io_pgtable_ops *ops = vm->pgtbl_ops; |
| 907 | u64 start_iova = iova; | 874 | u64 start_iova = iova; |
| 908 | u64 offset = 0; | 875 | u64 offset = 0; |
| 909 | 876 | ||
| 877 | if (!size) | ||
| 878 | return; | ||
| 879 | |||
| 880 | drm_WARN_ON(&ptdev->base, | ||
| 881 | (iova < vm->locked_region.start) || | ||
| 882 | (iova + size > vm->locked_region.start + vm->locked_region.size)); | ||
| 883 | |||
| 910 | while (offset < size) { | 884 | while (offset < size) { |
| 911 | size_t unmapped_sz = 0, pgcount; | 885 | size_t unmapped_sz = 0, pgcount; |
| 912 | size_t pgsize = get_pgsize(iova + offset, size - offset, &pgcount); | 886 | size_t pgsize = get_pgsize(iova + offset, size - offset, &pgcount); |
| 913 | 887 | ||
| 914 | unmapped_sz = ops->unmap_pages(ops, iova + offset, pgsize, pgcount, NULL); | 888 | unmapped_sz = ops->unmap_pages(ops, iova + offset, pgsize, pgcount, NULL); |
| 889 | if (drm_WARN_ON_ONCE(&ptdev->base, unmapped_sz != pgsize * pgcount)) { | ||
| 890 | /* Gracefully handle sparsely unmapped regions to avoid leaving | ||
| 891 | * page table pages behind when the drm_gpuvm and VM page table | ||
| 892 | * are out-of-sync. This is not supposed to happen, hence the | ||
| 893 | * above WARN_ON(). | ||
| 894 | */ | ||
| 895 | while (!ops->iova_to_phys(ops, iova + unmapped_sz) && | ||
| 896 | unmapped_sz < pgsize * pgcount) | ||
| 897 | unmapped_sz += SZ_4K; | ||
| 898 | |||
| 899 | /* We're passed the point where we can try to fix things, | ||
| 900 | * so flag the VM unusable to make sure it's not going | ||
| 901 | * to be used anymore. | ||
| 902 | */ | ||
| 903 | panthor_vm_declare_unusable(vm); | ||
| 915 | 904 | ||
| 916 | if (drm_WARN_ON(&ptdev->base, unmapped_sz != pgsize * pgcount)) { | 905 | /* If we don't make progress, we're screwed. That also means |
| 917 | drm_err(&ptdev->base, "failed to unmap range %llx-%llx (requested range %llx-%llx)\n", | 906 | * something else prevents us from unmapping the region, but |
| 918 | iova + offset + unmapped_sz, | 907 | * there's not much we can do here: time for debugging. |
| 919 | iova + offset + pgsize * pgcount, | 908 | */ |
| 920 | iova, iova + size); | 909 | if (drm_WARN_ON_ONCE(&ptdev->base, !unmapped_sz)) |
| 921 | panthor_vm_flush_range(vm, iova, offset + unmapped_sz); | 910 | return; |
| 922 | return -EINVAL; | ||
| 923 | } | 911 | } |
| 924 | 912 | ||
| 925 | drm_dbg(&ptdev->base, | 913 | drm_dbg(&ptdev->base, |
| @@ -929,8 +917,6 @@ static int panthor_vm_unmap_pages(struct panthor_vm *vm, u64 iova, u64 size) · 3 unmodified lines | |||
| 929 | 917 | ||
| 930 | offset += unmapped_sz; | 918 | offset += unmapped_sz; |
| 931 | } | 919 | } |
| 932 | |||
| 933 | return panthor_vm_flush_range(vm, iova, size); | ||
| 934 | } | 920 | } |
| 935 | 921 | ||
| 936 | static int | 922 | static int |
| @@ -948,6 +934,10 @@ panthor_vm_map_pages(struct panthor_vm *vm, u64 iova, int prot, · 11 unmodified lines | |||
| 948 | if (!size) | 934 | if (!size) |
| 949 | return 0; | 935 | return 0; |
| 950 | 936 | ||
| 937 | drm_WARN_ON(&ptdev->base, | ||
| 938 | (iova < vm->locked_region.start) || | ||
| 939 | (iova + size > vm->locked_region.start + vm->locked_region.size)); | ||
| 940 | |||
| 951 | for_each_sgtable_dma_sg(sgt, sgl, count) { | 941 | for_each_sgtable_dma_sg(sgt, sgl, count) { |
| 952 | dma_addr_t paddr = sg_dma_address(sgl); | 942 | dma_addr_t paddr = sg_dma_address(sgl); |
| 953 | size_t len = sg_dma_len(sgl); | 943 | size_t len = sg_dma_len(sgl); |
| @@ -978,16 +968,17 @@ panthor_vm_map_pages(struct panthor_vm *vm, u64 iova, int prot, · 24 unmodified lines | |||
| 978 | paddr += mapped; | 968 | paddr += mapped; |
| 979 | len -= mapped; | 969 | len -= mapped; |
| 980 | 970 | ||
| 981 | if (drm_WARN_ON(&ptdev->base, !ret && !mapped)) | 971 | /* If nothing was mapped, consider it an ENOMEM. */ |
| 972 | if (!ret && !mapped) | ||
| 982 | ret = -ENOMEM; | 973 | ret = -ENOMEM; |
| 983 | 974 | ||
| 984 | if (ret) { | 975 | /* If something fails, we stop there, and flag the VM unusable. */ |
| 985 | /* If something failed, unmap what we've already mapped before | 976 | if (drm_WARN_ON_ONCE(&ptdev->base, ret)) { |
| 986 | * returning. The unmap call is not supposed to fail. | 977 | /* Unmap what we've already mapped to avoid leaving page |
| 978 | * table pages behind. | ||
| 987 | */ | 979 | */ |
| 988 | drm_WARN_ON(&ptdev->base, | 980 | panthor_vm_unmap_pages(vm, start_iova, iova - start_iova); |
| 989 | panthor_vm_unmap_pages(vm, start_iova, | 981 | panthor_vm_declare_unusable(vm); |
| 990 | iova - start_iova)); | ||
| 991 | return ret; | 982 | return ret; |
| 992 | } | 983 | } |
| 993 | } | 984 | } |
| @@ -998,7 +989,7 @@ panthor_vm_map_pages(struct panthor_vm *vm, u64 iova, int prot, · 4 unmodified lines | |||
| 998 | offset = 0; | 989 | offset = 0; |
| 999 | } | 990 | } |
| 1000 | 991 | ||
| 1001 | return panthor_vm_flush_range(vm, start_iova, iova - start_iova); | 992 | return 0; |
| 1002 | } | 993 | } |
| 1003 | 994 | ||
| 1004 | static int flags_to_prot(u32 flags) | 995 | static int flags_to_prot(u32 flags) |
| @@ -1641,6 +1632,62 @@ static const char *access_type_name(struct panthor_device *ptdev, · 636 unmodified lines | |||
| 1641 | } | 1632 | } |
| 1642 | } | 1633 | } |
| 1643 | 1634 | ||
| 1635 | static int panthor_vm_lock_region(struct panthor_vm *vm, u64 start, u64 size) | ||
| 1636 | { | ||
| 1637 | struct panthor_device *ptdev = vm->ptdev; | ||
| 1638 | int ret = 0; | ||
| 1639 | |||
| 1640 | mutex_lock(&ptdev->mmu->as.slots_lock); | ||
| 1641 | drm_WARN_ON(&ptdev->base, vm->locked_region.start || vm->locked_region.size); | ||
| 1642 | if (vm->as.id >= 0 && size) { | ||
| 1643 | /* Lock the region that needs to be updated */ | ||
| 1644 | gpu_write64(ptdev, AS_LOCKADDR(vm->as.id), | ||
| 1645 | pack_region_range(ptdev, start, size)); | ||
| 1646 | |||
| 1647 | /* If the lock succeeded, update the locked_region info. */ | ||
| 1648 | ret = as_send_cmd_and_wait(ptdev, vm->as.id, AS_COMMAND_LOCK); | ||
| 1649 | } | ||
| 1650 | |||
| 1651 | if (!ret) { | ||
| 1652 | vm->locked_region.start = start; | ||
| 1653 | vm->locked_region.size = size; | ||
| 1654 | } | ||
| 1655 | mutex_unlock(&ptdev->mmu->as.slots_lock); | ||
| 1656 | |||
| 1657 | return ret; | ||
| 1658 | } | ||
| 1659 | |||
| 1660 | static void panthor_vm_unlock_region(struct panthor_vm *vm) | ||
| 1661 | { | ||
| 1662 | struct panthor_device *ptdev = vm->ptdev; | ||
| 1663 | |||
| 1664 | mutex_lock(&ptdev->mmu->as.slots_lock); | ||
| 1665 | if (vm->as.id >= 0) { | ||
| 1666 | int ret; | ||
| 1667 | |||
| 1668 | /* flush+invalidate RW caches and invalidate RO ones. | ||
| 1669 | * TODO: See if we can use FLUSH_PA_RANGE when the physical | ||
| 1670 | * range is narrow enough and the HW supports it. | ||
| 1671 | */ | ||
| 1672 | ret = panthor_gpu_flush_caches(ptdev, CACHE_CLEAN | CACHE_INV, | ||
| 1673 | CACHE_CLEAN | CACHE_INV, | ||
| 1674 | CACHE_INV); | ||
| 1675 | |||
| 1676 | /* Unlock the region if the flush is effective. */ | ||
| 1677 | if (!ret) | ||
| 1678 | ret = as_send_cmd_and_wait(ptdev, vm->as.id, AS_COMMAND_UNLOCK); | ||
| 1679 | |||
| 1680 | /* If we fail to flush or unlock the region, schedule a GPU reset | ||
| 1681 | * to unblock the situation. | ||
| 1682 | */ | ||
| 1683 | if (ret) | ||
| 1684 | panthor_device_schedule_reset(ptdev); | ||
| 1685 | } | ||
| 1686 | vm->locked_region.start = 0; | ||
| 1687 | vm->locked_region.size = 0; | ||
| 1688 | mutex_unlock(&ptdev->mmu->as.slots_lock); | ||
| 1689 | } | ||
| 1690 | |||
| 1644 | static void panthor_mmu_irq_handler(struct panthor_device *ptdev, u32 status) | 1691 | static void panthor_mmu_irq_handler(struct panthor_device *ptdev, u32 status) |
| 1645 | { | 1692 | { |
| 1646 | bool has_unhandled_faults = false; | 1693 | bool has_unhandled_faults = false; |
| @@ -1701,7 +1748,7 @@ static void panthor_mmu_irq_handler(struct panthor_device *ptdev, u32 status) · 54 unmodified lines | |||
| 1701 | ptdev->mmu->as.slots[as].vm->unhandled_fault = true; | 1748 | ptdev->mmu->as.slots[as].vm->unhandled_fault = true; |
| 1702 | 1749 | ||
| 1703 | /* Disable the MMU to kill jobs on this AS. */ | 1750 | /* Disable the MMU to kill jobs on this AS. */ |
| 1704 | panthor_mmu_as_disable(ptdev, as); | 1751 | panthor_mmu_as_disable(ptdev, as, false); |
| 1705 | mutex_unlock(&ptdev->mmu->as.slots_lock); | 1752 | mutex_unlock(&ptdev->mmu->as.slots_lock); |
| 1706 | 1753 | ||
| 1707 | status &= ~mask; | 1754 | status &= ~mask; |
| @@ -1730,7 +1777,8 @@ void panthor_mmu_suspend(struct panthor_device *ptdev) · 22 unmodified lines | |||
| 1730 | struct panthor_vm *vm = ptdev->mmu->as.slots[i].vm; | 1777 | struct panthor_vm *vm = ptdev->mmu->as.slots[i].vm; |
| 1731 | 1778 | ||
| 1732 | if (vm) { | 1779 | if (vm) { |
| 1733 | drm_WARN_ON(&ptdev->base, panthor_mmu_as_disable(ptdev, i)); | 1780 | drm_WARN_ON(&ptdev->base, |
| 1781 | panthor_mmu_as_disable(ptdev, i, false)); | ||
| 1734 | panthor_vm_release_as_locked(vm); | 1782 | panthor_vm_release_as_locked(vm); |
| 1735 | } | 1783 | } |
| 1736 | } | 1784 | } |
| @@ -1845,12 +1893,13 @@ static void panthor_vm_free(struct drm_gpuvm *gpuvm) · 108 unmodified lines | |||
| 1845 | drm_sched_entity_destroy(&vm->entity); | 1893 | drm_sched_entity_destroy(&vm->entity); |
| 1846 | drm_sched_fini(&vm->sched); | 1894 | drm_sched_fini(&vm->sched); |
| 1847 | 1895 | ||
| 1896 | mutex_lock(&vm->op_lock); | ||
| 1848 | mutex_lock(&ptdev->mmu->as.slots_lock); | 1897 | mutex_lock(&ptdev->mmu->as.slots_lock); |
| 1849 | if (vm->as.id >= 0) { | 1898 | if (vm->as.id >= 0) { |
| 1850 | int cookie; | 1899 | int cookie; |
| 1851 | 1900 | ||
| 1852 | if (drm_dev_enter(&ptdev->base, &cookie)) { | 1901 | if (drm_dev_enter(&ptdev->base, &cookie)) { |
| 1853 | panthor_mmu_as_disable(ptdev, vm->as.id); | 1902 | panthor_mmu_as_disable(ptdev, vm->as.id, false); |
| 1854 | drm_dev_exit(cookie); | 1903 | drm_dev_exit(cookie); |
| 1855 | } | 1904 | } |
| 1856 | 1905 | ||
| @@ -1859,6 +1908,7 @@ static void panthor_vm_free(struct drm_gpuvm *gpuvm) · 2 unmodified lines | |||
| 1859 | list_del(&vm->as.lru_node); | 1908 | list_del(&vm->as.lru_node); |
| 1860 | } | 1909 | } |
| 1861 | mutex_unlock(&ptdev->mmu->as.slots_lock); | 1910 | mutex_unlock(&ptdev->mmu->as.slots_lock); |
| 1911 | mutex_unlock(&vm->op_lock); | ||
| 1862 | 1912 | ||
| 1863 | free_io_pgtable_ops(vm->pgtbl_ops); | 1913 | free_io_pgtable_ops(vm->pgtbl_ops); |
| 1864 | 1914 | ||
| @@ -2060,12 +2110,9 @@ static int panthor_gpuva_sm_step_remap(struct drm_gpuva_op *op, · 195 unmodified lines | |||
| 2060 | struct panthor_vm_op_ctx *op_ctx = vm->op_ctx; | 2110 | struct panthor_vm_op_ctx *op_ctx = vm->op_ctx; |
| 2061 | struct panthor_vma *prev_vma = NULL, *next_vma = NULL; | 2111 | struct panthor_vma *prev_vma = NULL, *next_vma = NULL; |
| 2062 | u64 unmap_start, unmap_range; | 2112 | u64 unmap_start, unmap_range; |
| 2063 | int ret; | ||
| 2064 | 2113 | ||
| 2065 | drm_gpuva_op_remap_to_unmap_range(&op->remap, &unmap_start, &unmap_range); | 2114 | drm_gpuva_op_remap_to_unmap_range(&op->remap, &unmap_start, &unmap_range); |
| 2066 | ret = panthor_vm_unmap_pages(vm, unmap_start, unmap_range); | 2115 | panthor_vm_unmap_pages(vm, unmap_start, unmap_range); |
| 2067 | if (ret) | ||
| 2068 | return ret; | ||
| 2069 | 2116 | ||
| 2070 | if (op->remap.prev) { | 2117 | if (op->remap.prev) { |
| 2071 | prev_vma = panthor_vm_op_ctx_get_vma(op_ctx); | 2118 | prev_vma = panthor_vm_op_ctx_get_vma(op_ctx); |
| @@ -2103,13 +2150,9 @@ static int panthor_gpuva_sm_step_unmap(struct drm_gpuva_op *op, · 31 unmodified lines | |||
| 2103 | { | 2150 | { |
| 2104 | struct panthor_vma *unmap_vma = container_of(op->unmap.va, struct panthor_vma, base); | 2151 | struct panthor_vma *unmap_vma = container_of(op->unmap.va, struct panthor_vma, base); |
| 2105 | struct panthor_vm *vm = priv; | 2152 | struct panthor_vm *vm = priv; |
| 2106 | int ret; | ||
| 2107 | |||
| 2108 | ret = panthor_vm_unmap_pages(vm, unmap_vma->base.va.addr, | ||
| 2109 | unmap_vma->base.va.range); | ||
| 2110 | if (drm_WARN_ON(&vm->ptdev->base, ret)) | ||
| 2111 | return ret; | ||
| 2112 | 2153 | ||
| 2154 | panthor_vm_unmap_pages(vm, unmap_vma->base.va.addr, | ||
| 2155 | unmap_vma->base.va.range); | ||
| 2113 | drm_gpuva_unmap(&op->unmap); | 2156 | drm_gpuva_unmap(&op->unmap); |
| 2114 | panthor_vma_unlink(unmap_vma); | 2157 | panthor_vma_unlink(unmap_vma); |
| 2115 | return 0; | 2158 | return 0; |
| @@ -2154,6 +2197,11 @@ panthor_vm_exec_op(struct panthor_vm *vm, struct panthor_vm_op_ctx *op, · 38 unmodified lines | |||
| 2154 | 2197 | ||
| 2155 | mutex_lock(&vm->op_lock); | 2198 | mutex_lock(&vm->op_lock); |
| 2156 | vm->op_ctx = op; | 2199 | vm->op_ctx = op; |
| 2200 | |||
| 2201 | ret = panthor_vm_lock_region(vm, op->va.addr, op->va.range); | ||
| 2202 | if (ret) | ||
| 2203 | goto out; | ||
| 2204 | |||
| 2157 | switch (op_type) { | 2205 | switch (op_type) { |
| 2158 | case DRM_PANTHOR_VM_BIND_OP_TYPE_MAP: { | 2206 | case DRM_PANTHOR_VM_BIND_OP_TYPE_MAP: { |
| 2159 | const struct drm_gpuvm_map_req map_req = { | 2207 | const struct drm_gpuvm_map_req map_req = { |
| @@ -2181,8 +2229,11 @@ panthor_vm_exec_op(struct panthor_vm *vm, struct panthor_vm_op_ctx *op, · 21 unmodified lines | |||
| 2181 | break; | 2229 | break; |
| 2182 | } | 2230 | } |
| 2183 | 2231 | ||
| 2232 | panthor_vm_unlock_region(vm); | ||
| 2233 | |||
| 2234 | out: | ||
| 2184 | if (ret && flag_vm_unusable_on_failure) | 2235 | if (ret && flag_vm_unusable_on_failure) |
| 2185 | vm->unusable = true; | 2236 | panthor_vm_declare_unusable(vm); |
| 2186 | 2237 | ||
| 2187 | vm->op_ctx = NULL; | 2238 | vm->op_ctx = NULL; |
| 2188 | mutex_unlock(&vm->op_lock); | 2239 | mutex_unlock(&vm->op_lock); |
| @@ -2694,7 +2745,8 @@ void panthor_mmu_unplug(struct panthor_device *ptdev) · 505 unmodified lines | |||
| 2694 | struct panthor_vm *vm = ptdev->mmu->as.slots[i].vm; | 2745 | struct panthor_vm *vm = ptdev->mmu->as.slots[i].vm; |
| 2695 | 2746 | ||
| 2696 | if (vm) { | 2747 | if (vm) { |
| 2697 | drm_WARN_ON(&ptdev->base, panthor_mmu_as_disable(ptdev, i)); | 2748 | drm_WARN_ON(&ptdev->base, |
| 2749 | panthor_mmu_as_disable(ptdev, i, false)); | ||
| 2698 | panthor_vm_release_as_locked(vm); | 2750 | panthor_vm_release_as_locked(vm); |
| 2699 | } | 2751 | } |
| 2700 | } | 2752 | } |
| @@ -108,15 +108,6 @@ struct panthor_csg_slot { · 107 unmodified lines | |||
| 108 | 108 | ||
| 109 | /** @priority: Group priority. */ | 109 | /** @priority: Group priority. */ |
| 110 | u8 priority; | 110 | u8 priority; |
| 111 | |||
| 112 | /** | ||
| 113 | * @idle: True if the group bound to this slot is idle. | ||
| 114 | * | ||
| 115 | * A group is idle when it has nothing waiting for execution on | ||
| 116 | * all its queues, or when queues are blocked waiting for something | ||
| 117 | * to happen (synchronization object). | ||
| 118 | */ | ||
| 119 | bool idle; | ||
| 120 | }; | 111 | }; |
| 121 | 112 | ||
| 122 | /** | 113 | /** |
| @@ -878,8 +869,11 @@ panthor_queue_get_syncwait_obj(struct panthor_group *group, struct panthor_queue · 755 unmodified lines | |||
| 878 | struct iosys_map map; | 869 | struct iosys_map map; |
| 879 | int ret; | 870 | int ret; |
| 880 | 871 | ||
| 881 | if (queue->syncwait.kmap) | 872 | if (queue->syncwait.kmap) { |
| 882 | return queue->syncwait.kmap + queue->syncwait.offset; | 873 | bo = container_of(queue->syncwait.obj, |
| 874 | struct panthor_gem_object, base.base); | ||
| 875 | goto out_sync; | ||
| 876 | } | ||
| 883 | 877 | ||
| 884 | bo = panthor_vm_get_bo_for_va(group->vm, | 878 | bo = panthor_vm_get_bo_for_va(group->vm, |
| 885 | queue->syncwait.gpu_va, | 879 | queue->syncwait.gpu_va, |
| @@ -896,6 +890,17 @@ panthor_queue_get_syncwait_obj(struct panthor_group *group, struct panthor_queue · 10 unmodified lines | |||
| 896 | if (drm_WARN_ON(&ptdev->base, !queue->syncwait.kmap)) | 890 | if (drm_WARN_ON(&ptdev->base, !queue->syncwait.kmap)) |
| 897 | goto err_put_syncwait_obj; | 891 | goto err_put_syncwait_obj; |
| 898 | 892 | ||
| 893 | out_sync: | ||
| 894 | /* Make sure the CPU caches are invalidated before the seqno is read. | ||
| 895 | * drm_gem_shmem_sync() is a NOP if map_wc=true, so no need to check | ||
| 896 | * it here. | ||
| 897 | */ | ||
| 898 | panthor_gem_sync(&bo->base.base, queue->syncwait.offset, | ||
| 899 | queue->syncwait.sync64 ? | ||
| 900 | sizeof(struct panthor_syncobj_64b) : | ||
| 901 | sizeof(struct panthor_syncobj_32b), | ||
| 902 | DRM_PANTHOR_BO_SYNC_CPU_CACHE_FLUSH_AND_INVALIDATE); | ||
| 903 | |||
| 899 | return queue->syncwait.kmap + queue->syncwait.offset; | 904 | return queue->syncwait.kmap + queue->syncwait.offset; |
| 900 | 905 | ||
| 901 | err_put_syncwait_obj: | 906 | err_put_syncwait_obj: |
| @@ -908,9 +913,8 @@ static void group_free_queue(struct panthor_group *group, struct panthor_queue * · 6 unmodified lines | |||
| 908 | if (IS_ERR_OR_NULL(queue)) | 913 | if (IS_ERR_OR_NULL(queue)) |
| 909 | return; | 914 | return; |
| 910 | 915 | ||
| 911 | /* This should have been disabled before that point. */ | 916 | /* Disable the timeout before tearing down drm_sched components. */ |
| 912 | drm_WARN_ON(&group->ptdev->base, | 917 | disable_delayed_work_sync(&queue->timeout.work); |
| 913 | disable_delayed_work_sync(&queue->timeout.work)); | ||
| 914 | 918 | ||
| 915 | if (queue->entity.fence_context) | 919 | if (queue->entity.fence_context) |
| 916 | drm_sched_entity_destroy(&queue->entity); | 920 | drm_sched_entity_destroy(&queue->entity); |
| @@ -1062,28 +1066,11 @@ group_unbind_locked(struct panthor_group *group) · 145 unmodified lines | |||
| 1062 | static bool | 1066 | static bool |
| 1063 | group_is_idle(struct panthor_group *group) | 1067 | group_is_idle(struct panthor_group *group) |
| 1064 | { | 1068 | { |
| 1065 | struct panthor_device *ptdev = group->ptdev; | 1069 | u32 inactive_queues = group->idle_queues | group->blocked_queues; |
| 1066 | u32 inactive_queues; | ||
| 1067 | |||
| 1068 | if (group->csg_id >= 0) | ||
| 1069 | return ptdev->scheduler->csg_slots[group->csg_id].idle; | ||
| 1070 | 1070 | ||
| 1071 | inactive_queues = group->idle_queues | group->blocked_queues; | ||
| 1072 | return hweight32(inactive_queues) == group->queue_count; | 1071 | return hweight32(inactive_queues) == group->queue_count; |
| 1073 | } | 1072 | } |
| 1074 | 1073 | ||
| 1075 | static void | ||
| 1076 | queue_reset_timeout_locked(struct panthor_queue *queue) | ||
| 1077 | { | ||
| 1078 | lockdep_assert_held(&queue->fence_ctx.lock); | ||
| 1079 | |||
| 1080 | if (queue->timeout.remaining != MAX_SCHEDULE_TIMEOUT) { | ||
| 1081 | mod_delayed_work(queue->scheduler.timeout_wq, | ||
| 1082 | &queue->timeout.work, | ||
| 1083 | msecs_to_jiffies(JOB_TIMEOUT_MS)); | ||
| 1084 | } | ||
| 1085 | } | ||
| 1086 | |||
| 1087 | static bool | 1074 | static bool |
| 1088 | group_can_run(struct panthor_group *group) | 1075 | group_can_run(struct panthor_group *group) |
| 1089 | { | 1076 | { |
| @@ -1100,6 +1087,18 @@ queue_timeout_is_suspended(struct panthor_queue *queue) · 10 unmodified lines | |||
| 1100 | return queue->timeout.remaining != MAX_SCHEDULE_TIMEOUT; | 1087 | return queue->timeout.remaining != MAX_SCHEDULE_TIMEOUT; |
| 1101 | } | 1088 | } |
| 1102 | 1089 | ||
| 1090 | static void | ||
| 1091 | queue_reset_timeout_locked(struct panthor_queue *queue) | ||
| 1092 | { | ||
| 1093 | lockdep_assert_held(&queue->fence_ctx.lock); | ||
| 1094 | |||
| 1095 | if (!queue_timeout_is_suspended(queue)) { | ||
| 1096 | mod_delayed_work(queue->scheduler.timeout_wq, | ||
| 1097 | &queue->timeout.work, | ||
| 1098 | msecs_to_jiffies(JOB_TIMEOUT_MS)); | ||
| 1099 | } | ||
| 1100 | } | ||
| 1101 | |||
| 1103 | static void | 1102 | static void |
| 1104 | queue_suspend_timeout_locked(struct panthor_queue *queue) | 1103 | queue_suspend_timeout_locked(struct panthor_queue *queue) |
| 1105 | { | 1104 | { |
| @@ -1200,12 +1199,10 @@ cs_slot_prog_locked(struct panthor_device *ptdev, u32 csg_id, u32 cs_id) · 94 unmodified lines | |||
| 1200 | panthor_fw_update_reqs(cs_iface, req, | 1199 | panthor_fw_update_reqs(cs_iface, req, |
| 1201 | CS_IDLE_SYNC_WAIT | | 1200 | CS_IDLE_SYNC_WAIT | |
| 1202 | CS_IDLE_EMPTY | | 1201 | CS_IDLE_EMPTY | |
| 1203 | CS_STATE_START | | 1202 | CS_STATE_START, |
| 1204 | CS_EXTRACT_EVENT, | ||
| 1205 | CS_IDLE_SYNC_WAIT | | 1203 | CS_IDLE_SYNC_WAIT | |
| 1206 | CS_IDLE_EMPTY | | 1204 | CS_IDLE_EMPTY | |
| 1207 | CS_STATE_MASK | | 1205 | CS_STATE_MASK); |
| 1208 | CS_EXTRACT_EVENT); | ||
| 1209 | if (queue->iface.input->insert != queue->iface.input->extract) | 1206 | if (queue->iface.input->insert != queue->iface.input->extract) |
| 1210 | queue_resume_timeout(queue); | 1207 | queue_resume_timeout(queue); |
| 1211 | } | 1208 | } |
| @@ -1725,17 +1722,6 @@ static bool cs_slot_process_irq_locked(struct panthor_device *ptdev, · 513 unmodified lines | |||
| 1725 | return (events & (CS_FAULT | CS_TILER_OOM)) != 0; | 1722 | return (events & (CS_FAULT | CS_TILER_OOM)) != 0; |
| 1726 | } | 1723 | } |
| 1727 | 1724 | ||
| 1728 | static void csg_slot_sync_idle_state_locked(struct panthor_device *ptdev, u32 csg_id) | ||
| 1729 | { | ||
| 1730 | struct panthor_csg_slot *csg_slot = &ptdev->scheduler->csg_slots[csg_id]; | ||
| 1731 | struct panthor_fw_csg_iface *csg_iface; | ||
| 1732 | |||
| 1733 | lockdep_assert_held(&ptdev->scheduler->lock); | ||
| 1734 | |||
| 1735 | csg_iface = panthor_fw_get_csg_iface(ptdev, csg_id); | ||
| 1736 | csg_slot->idle = csg_iface->output->status_state & CSG_STATUS_STATE_IS_IDLE; | ||
| 1737 | } | ||
| 1738 | |||
| 1739 | static void csg_slot_process_idle_event_locked(struct panthor_device *ptdev, u32 csg_id) | 1725 | static void csg_slot_process_idle_event_locked(struct panthor_device *ptdev, u32 csg_id) |
| 1740 | { | 1726 | { |
| 1741 | struct panthor_scheduler *sched = ptdev->scheduler; | 1727 | struct panthor_scheduler *sched = ptdev->scheduler; |
| @@ -1997,10 +1983,8 @@ static int csgs_upd_ctx_apply_locked(struct panthor_device *ptdev, · 255 unmodified lines | |||
| 1997 | if (acked & CSG_STATE_MASK) | 1983 | if (acked & CSG_STATE_MASK) |
| 1998 | csg_slot_sync_state_locked(ptdev, csg_id); | 1984 | csg_slot_sync_state_locked(ptdev, csg_id); |
| 1999 | 1985 | ||
| 2000 | if (acked & CSG_STATUS_UPDATE) { | 1986 | if (acked & CSG_STATUS_UPDATE) |
| 2001 | csg_slot_sync_queues_state_locked(ptdev, csg_id); | 1987 | csg_slot_sync_queues_state_locked(ptdev, csg_id); |
| 2002 | csg_slot_sync_idle_state_locked(ptdev, csg_id); | ||
| 2003 | } | ||
| 2004 | 1988 | ||
| 2005 | if (ret && acked != req_mask && | 1989 | if (ret && acked != req_mask && |
| 2006 | ((csg_iface->input->req ^ csg_iface->output->ack) & req_mask) != 0) { | 1990 | ((csg_iface->input->req ^ csg_iface->output->ack) & req_mask) != 0) { |
| @@ -2020,10 +2004,10 @@ struct panthor_sched_tick_ctx { · 13 unmodified lines | |||
| 2020 | struct list_head groups[PANTHOR_CSG_PRIORITY_COUNT]; | 2004 | struct list_head groups[PANTHOR_CSG_PRIORITY_COUNT]; |
| 2021 | u32 idle_group_count; | 2005 | u32 idle_group_count; |
| 2022 | u32 group_count; | 2006 | u32 group_count; |
| 2023 | enum panthor_csg_priority min_priority; | ||
| 2024 | struct panthor_vm *vms[MAX_CS_PER_CSG]; | 2007 | struct panthor_vm *vms[MAX_CS_PER_CSG]; |
| 2025 | u32 as_count; | 2008 | u32 as_count; |
| 2026 | bool immediate_tick; | 2009 | bool immediate_tick; |
| 2010 | bool stop_tick; | ||
| 2027 | u32 csg_upd_failed_mask; | 2011 | u32 csg_upd_failed_mask; |
| 2028 | }; | 2012 | }; |
| 2029 | 2013 | ||
| @@ -2066,17 +2050,21 @@ tick_ctx_pick_groups_from_list(const struct panthor_scheduler *sched, · 36 unmodified lines | |||
| 2066 | if (!owned_by_tick_ctx) | 2050 | if (!owned_by_tick_ctx) |
| 2067 | group_get(group); | 2051 | group_get(group); |
| 2068 | 2052 | ||
| 2069 | list_move_tail(&group->run_node, &ctx->groups[group->priority]); | ||
| 2070 | ctx->group_count++; | 2053 | ctx->group_count++; |
| 2054 | |||
| 2055 | /* If we have more than one active group with the same priority, | ||
| 2056 | * we need to keep ticking to rotate the CSG priority. | ||
| 2057 | */ | ||
| 2071 | if (group_is_idle(group)) | 2058 | if (group_is_idle(group)) |
| 2072 | ctx->idle_group_count++; | 2059 | ctx->idle_group_count++; |
| 2060 | else if (!list_empty(&ctx->groups[group->priority])) | ||
| 2061 | ctx->stop_tick = false; | ||
| 2062 | |||
| 2063 | list_move_tail(&group->run_node, &ctx->groups[group->priority]); | ||
| 2073 | 2064 | ||
| 2074 | if (i == ctx->as_count) | 2065 | if (i == ctx->as_count) |
| 2075 | ctx->vms[ctx->as_count++] = group->vm; | 2066 | ctx->vms[ctx->as_count++] = group->vm; |
| 2076 | 2067 | ||
| 2077 | if (ctx->min_priority > group->priority) | ||
| 2078 | ctx->min_priority = group->priority; | ||
| 2079 | |||
| 2080 | if (tick_ctx_is_full(sched, ctx)) | 2068 | if (tick_ctx_is_full(sched, ctx)) |
| 2081 | return; | 2069 | return; |
| 2082 | } | 2070 | } |
| @@ -2085,31 +2073,22 @@ tick_ctx_pick_groups_from_list(const struct panthor_scheduler *sched, · 2 unmodified lines | |||
| 2085 | static void | 2073 | static void |
| 2086 | tick_ctx_insert_old_group(struct panthor_scheduler *sched, | 2074 | tick_ctx_insert_old_group(struct panthor_scheduler *sched, |
| 2087 | struct panthor_sched_tick_ctx *ctx, | 2075 | struct panthor_sched_tick_ctx *ctx, |
| 2088 | struct panthor_group *group, | 2076 | struct panthor_group *group) |
| 2089 | bool full_tick) | ||
| 2090 | { | 2077 | { |
| 2091 | struct panthor_csg_slot *csg_slot = &sched->csg_slots[group->csg_id]; | 2078 | struct panthor_csg_slot *csg_slot = &sched->csg_slots[group->csg_id]; |
| 2092 | struct panthor_group *other_group; | 2079 | struct panthor_group *other_group; |
| 2093 | 2080 | ||
| 2094 | if (!full_tick) { | 2081 | /* Class groups in descending priority order so we can easily rotate. */ |
| 2095 | list_add_tail(&group->run_node, &ctx->old_groups[group->priority]); | ||
| 2096 | return; | ||
| 2097 | } | ||
| 2098 | |||
| 2099 | /* Rotate to make sure groups with lower CSG slot | ||
| 2100 | * priorities have a chance to get a higher CSG slot | ||
| 2101 | * priority next time they get picked. This priority | ||
| 2102 | * has an impact on resource request ordering, so it's | ||
| 2103 | * important to make sure we don't let one group starve | ||
| 2104 | * all other groups with the same group priority. | ||
| 2105 | */ | ||
| 2106 | list_for_each_entry(other_group, | 2082 | list_for_each_entry(other_group, |
| 2107 | &ctx->old_groups[csg_slot->group->priority], | 2083 | &ctx->old_groups[csg_slot->group->priority], |
| 2108 | run_node) { | 2084 | run_node) { |
| 2109 | struct panthor_csg_slot *other_csg_slot = &sched->csg_slots[other_group->csg_id]; | 2085 | struct panthor_csg_slot *other_csg_slot = &sched->csg_slots[other_group->csg_id]; |
| 2110 | 2086 | ||
| 2111 | if (other_csg_slot->priority > csg_slot->priority) { | 2087 | /* Our group has a higher prio than the one we're testing against, |
| 2112 | list_add_tail(&csg_slot->group->run_node, &other_group->run_node); | 2088 | * place it just before. |
| 2089 | */ | ||
| 2090 | if (csg_slot->priority > other_csg_slot->priority) { | ||
| 2091 | list_add_tail(&group->run_node, &other_group->run_node); | ||
| 2113 | return; | 2092 | return; |
| 2114 | } | 2093 | } |
| 2115 | } | 2094 | } |
| @@ -2119,8 +2098,7 @@ tick_ctx_insert_old_group(struct panthor_scheduler *sched, · 3 unmodified lines | |||
| 2119 | 2098 | ||
| 2120 | static void | 2099 | static void |
| 2121 | tick_ctx_init(struct panthor_scheduler *sched, | 2100 | tick_ctx_init(struct panthor_scheduler *sched, |
| 2122 | struct panthor_sched_tick_ctx *ctx, | 2101 | struct panthor_sched_tick_ctx *ctx) |
| 2123 | bool full_tick) | ||
| 2124 | { | 2102 | { |
| 2125 | struct panthor_device *ptdev = sched->ptdev; | 2103 | struct panthor_device *ptdev = sched->ptdev; |
| 2126 | struct panthor_csg_slots_upd_ctx upd_ctx; | 2104 | struct panthor_csg_slots_upd_ctx upd_ctx; |
| @@ -2130,7 +2108,7 @@ tick_ctx_init(struct panthor_scheduler *sched, · 3 unmodified lines | |||
| 2130 | memset(ctx, 0, sizeof(*ctx)); | 2108 | memset(ctx, 0, sizeof(*ctx)); |
| 2131 | csgs_upd_ctx_init(&upd_ctx); | 2109 | csgs_upd_ctx_init(&upd_ctx); |
| 2132 | 2110 | ||
| 2133 | ctx->min_priority = PANTHOR_CSG_PRIORITY_COUNT; | 2111 | ctx->stop_tick = true; |
| 2134 | for (i = 0; i < ARRAY_SIZE(ctx->groups); i++) { | 2112 | for (i = 0; i < ARRAY_SIZE(ctx->groups); i++) { |
| 2135 | INIT_LIST_HEAD(&ctx->groups[i]); | 2113 | INIT_LIST_HEAD(&ctx->groups[i]); |
| 2136 | INIT_LIST_HEAD(&ctx->old_groups[i]); | 2114 | INIT_LIST_HEAD(&ctx->old_groups[i]); |
| @@ -2158,7 +2136,7 @@ tick_ctx_init(struct panthor_scheduler *sched, · 21 unmodified lines | |||
| 2158 | group->fatal_queues |= GENMASK(group->queue_count - 1, 0); | 2136 | group->fatal_queues |= GENMASK(group->queue_count - 1, 0); |
| 2159 | } | 2137 | } |
| 2160 | 2138 | ||
| 2161 | tick_ctx_insert_old_group(sched, ctx, group, full_tick); | 2139 | tick_ctx_insert_old_group(sched, ctx, group); |
| 2162 | csgs_upd_ctx_queue_reqs(ptdev, &upd_ctx, i, | 2140 | csgs_upd_ctx_queue_reqs(ptdev, &upd_ctx, i, |
| 2163 | csg_iface->output->ack ^ CSG_STATUS_UPDATE, | 2141 | csg_iface->output->ack ^ CSG_STATUS_UPDATE, |
| 2164 | CSG_STATUS_UPDATE); | 2142 | CSG_STATUS_UPDATE); |
| @@ -2442,32 +2420,18 @@ static u64 · 277 unmodified lines | |||
| 2442 | tick_ctx_update_resched_target(struct panthor_scheduler *sched, | 2420 | tick_ctx_update_resched_target(struct panthor_scheduler *sched, |
| 2443 | const struct panthor_sched_tick_ctx *ctx) | 2421 | const struct panthor_sched_tick_ctx *ctx) |
| 2444 | { | 2422 | { |
| 2445 | /* We had space left, no need to reschedule until some external event happens. */ | 2423 | u64 resched_target; |
| 2446 | if (!tick_ctx_is_full(sched, ctx)) | ||
| 2447 | goto no_tick; | ||
| 2448 | |||
| 2449 | /* If idle groups were scheduled, no need to wake up until some external | ||
| 2450 | * event happens (group unblocked, new job submitted, ...). | ||
| 2451 | */ | ||
| 2452 | if (ctx->idle_group_count) | ||
| 2453 | goto no_tick; | ||
| 2454 | 2424 | ||
| 2455 | if (drm_WARN_ON(&sched->ptdev->base, ctx->min_priority >= PANTHOR_CSG_PRIORITY_COUNT)) | 2425 | if (ctx->stop_tick) |
| 2456 | goto no_tick; | 2426 | goto no_tick; |
| 2457 | 2427 | ||
| 2458 | /* If there are groups of the same priority waiting, we need to | 2428 | resched_target = sched->last_tick + sched->tick_period; |
| 2459 | * keep the scheduler ticking, otherwise, we'll just wait for | ||
| 2460 | * new groups with higher priority to be queued. | ||
| 2461 | */ | ||
| 2462 | if (!list_empty(&sched->groups.runnable[ctx->min_priority])) { | ||
| 2463 | u64 resched_target = sched->last_tick + sched->tick_period; | ||
| 2464 | 2429 | ||
| 2465 | if (time_before64(sched->resched_target, sched->last_tick) || | 2430 | if (time_before64(sched->resched_target, sched->last_tick) || |
| 2466 | time_before64(resched_target, sched->resched_target)) | 2431 | time_before64(resched_target, sched->resched_target)) |
| 2467 | sched->resched_target = resched_target; | 2432 | sched->resched_target = resched_target; |
| 2468 | 2433 | ||
| 2469 | return sched->resched_target - sched->last_tick; | 2434 | return sched->resched_target - sched->last_tick; |
| 2470 | } | ||
| 2471 | 2435 | ||
| 2472 | no_tick: | 2436 | no_tick: |
| 2473 | sched->resched_target = U64_MAX; | 2437 | sched->resched_target = U64_MAX; |
| @@ -2480,9 +2444,11 @@ static void tick_work(struct work_struct *work) · 6 unmodified lines | |||
| 2480 | tick_work.work); | 2444 | tick_work.work); |
| 2481 | struct panthor_device *ptdev = sched->ptdev; | 2445 | struct panthor_device *ptdev = sched->ptdev; |
| 2482 | struct panthor_sched_tick_ctx ctx; | 2446 | struct panthor_sched_tick_ctx ctx; |
| 2447 | u64 resched_target = sched->resched_target; | ||
| 2483 | u64 remaining_jiffies = 0, resched_delay; | 2448 | u64 remaining_jiffies = 0, resched_delay; |
| 2484 | u64 now = get_jiffies_64(); | 2449 | u64 now = get_jiffies_64(); |
| 2485 | int prio, ret, cookie; | 2450 | int prio, ret, cookie; |
| 2451 | bool full_tick; | ||
| 2486 | 2452 | ||
| 2487 | if (!drm_dev_enter(&ptdev->base, &cookie)) | 2453 | if (!drm_dev_enter(&ptdev->base, &cookie)) |
| 2488 | return; | 2454 | return; |
| @@ -2491,18 +2457,24 @@ static void tick_work(struct work_struct *work) · 2 unmodified lines | |||
| 2491 | if (drm_WARN_ON(&ptdev->base, ret)) | 2457 | if (drm_WARN_ON(&ptdev->base, ret)) |
| 2492 | goto out_dev_exit; | 2458 | goto out_dev_exit; |
| 2493 | 2459 | ||
| 2494 | if (time_before64(now, sched->resched_target)) | 2460 | /* If the tick is stopped, calculate when the next tick would be */ |
| 2495 | remaining_jiffies = sched->resched_target - now; | 2461 | if (resched_target == U64_MAX) |
| 2462 | resched_target = sched->last_tick + sched->tick_period; | ||
| 2463 | |||
| 2464 | if (time_before64(now, resched_target)) | ||
| 2465 | remaining_jiffies = resched_target - now; | ||
| 2466 | |||
| 2467 | full_tick = remaining_jiffies == 0; | ||
| 2496 | 2468 | ||
| 2497 | mutex_lock(&sched->lock); | 2469 | mutex_lock(&sched->lock); |
| 2498 | if (panthor_device_reset_is_pending(sched->ptdev)) | 2470 | if (panthor_device_reset_is_pending(sched->ptdev)) |
| 2499 | goto out_unlock; | 2471 | goto out_unlock; |
| 2500 | 2472 | ||
| 2501 | tick_ctx_init(sched, &ctx, remaining_jiffies != 0); | 2473 | tick_ctx_init(sched, &ctx); |
| 2502 | if (ctx.csg_upd_failed_mask) | 2474 | if (ctx.csg_upd_failed_mask) |
| 2503 | goto out_cleanup_ctx; | 2475 | goto out_cleanup_ctx; |
| 2504 | 2476 | ||
| 2505 | if (remaining_jiffies) { | 2477 | if (!full_tick) { |
| 2506 | /* Scheduling forced in the middle of a tick. Only RT groups | 2478 | /* Scheduling forced in the middle of a tick. Only RT groups |
| 2507 | * can preempt non-RT ones. Currently running RT groups can't be | 2479 | * can preempt non-RT ones. Currently running RT groups can't be |
| 2508 | * preempted. | 2480 | * preempted. |
| @@ -2524,9 +2496,29 @@ static void tick_work(struct work_struct *work) · 15 unmodified lines | |||
| 2524 | for (prio = PANTHOR_CSG_PRIORITY_COUNT - 1; | 2496 | for (prio = PANTHOR_CSG_PRIORITY_COUNT - 1; |
| 2525 | prio >= 0 && !tick_ctx_is_full(sched, &ctx); | 2497 | prio >= 0 && !tick_ctx_is_full(sched, &ctx); |
| 2526 | prio--) { | 2498 | prio--) { |
| 2499 | struct panthor_group *old_highest_prio_group = | ||
| 2500 | list_first_entry_or_null(&ctx.old_groups[prio], | ||
| 2501 | struct panthor_group, run_node); | ||
| 2502 | |||
| 2503 | /* Pull out the group with the highest prio for rotation. */ | ||
| 2504 | if (old_highest_prio_group) | ||
| 2505 | list_del(&old_highest_prio_group->run_node); | ||
| 2506 | |||
| 2507 | /* Re-insert old active groups so they get a chance to run with higher prio. */ | ||
| 2508 | tick_ctx_pick_groups_from_list(sched, &ctx, &ctx.old_groups[prio], true, true); | ||
| 2509 | |||
| 2510 | /* Fill the remaining slots with runnable groups. */ | ||
| 2527 | tick_ctx_pick_groups_from_list(sched, &ctx, &sched->groups.runnable[prio], | 2511 | tick_ctx_pick_groups_from_list(sched, &ctx, &sched->groups.runnable[prio], |
| 2528 | true, false); | 2512 | true, false); |
| 2529 | tick_ctx_pick_groups_from_list(sched, &ctx, &ctx.old_groups[prio], true, true); | 2513 | |
| 2514 | /* Re-insert the old group with the highest prio, and give it a chance to be | ||
| 2515 | * scheduled again (but with a lower prio) if there's room left. | ||
| 2516 | */ | ||
| 2517 | if (old_highest_prio_group) { | ||
| 2518 | list_add_tail(&old_highest_prio_group->run_node, &ctx.old_groups[prio]); | ||
| 2519 | tick_ctx_pick_groups_from_list(sched, &ctx, &ctx.old_groups[prio], | ||
| 2520 | true, true); | ||
| 2521 | } | ||
| 2530 | } | 2522 | } |
| 2531 | 2523 | ||
| 2532 | /* If we have free CSG slots left, pick idle groups */ | 2524 | /* If we have free CSG slots left, pick idle groups */ |
| @@ -2651,14 +2643,33 @@ static void sync_upd_work(struct work_struct *work) · 118 unmodified lines | |||
| 2651 | sched_queue_delayed_work(sched, tick, 0); | 2643 | sched_queue_delayed_work(sched, tick, 0); |
| 2652 | } | 2644 | } |
| 2653 | 2645 | ||
| 2646 | static void sched_resume_tick(struct panthor_device *ptdev) | ||
| 2647 | { | ||
| 2648 | struct panthor_scheduler *sched = ptdev->scheduler; | ||
| 2649 | u64 delay_jiffies, now; | ||
| 2650 | |||
| 2651 | drm_WARN_ON(&ptdev->base, sched->resched_target != U64_MAX); | ||
| 2652 | |||
| 2653 | /* Scheduler tick was off, recalculate the resched_target based on the | ||
| 2654 | * last tick event, and queue the scheduler work. | ||
| 2655 | */ | ||
| 2656 | now = get_jiffies_64(); | ||
| 2657 | sched->resched_target = sched->last_tick + sched->tick_period; | ||
| 2658 | if (sched->used_csg_slot_count == sched->csg_slot_count && | ||
| 2659 | time_before64(now, sched->resched_target)) | ||
| 2660 | delay_jiffies = min_t(unsigned long, sched->resched_target - now, ULONG_MAX); | ||
| 2661 | else | ||
| 2662 | delay_jiffies = 0; | ||
| 2663 | |||
| 2664 | sched_queue_delayed_work(sched, tick, delay_jiffies); | ||
| 2665 | } | ||
| 2666 | |||
| 2654 | static void group_schedule_locked(struct panthor_group *group, u32 queue_mask) | 2667 | static void group_schedule_locked(struct panthor_group *group, u32 queue_mask) |
| 2655 | { | 2668 | { |
| 2656 | struct panthor_device *ptdev = group->ptdev; | 2669 | struct panthor_device *ptdev = group->ptdev; |
| 2657 | struct panthor_scheduler *sched = ptdev->scheduler; | 2670 | struct panthor_scheduler *sched = ptdev->scheduler; |
| 2658 | struct list_head *queue = &sched->groups.runnable[group->priority]; | 2671 | struct list_head *queue = &sched->groups.runnable[group->priority]; |
| 2659 | u64 delay_jiffies = 0; | ||
| 2660 | bool was_idle; | 2672 | bool was_idle; |
| 2661 | u64 now; | ||
| 2662 | 2673 | ||
| 2663 | if (!group_can_run(group)) | 2674 | if (!group_can_run(group)) |
| 2664 | return; | 2675 | return; |
| @@ -2703,13 +2714,7 @@ static void group_schedule_locked(struct panthor_group *group, u32 queue_mask) · 38 unmodified lines | |||
| 2703 | /* Scheduler tick was off, recalculate the resched_target based on the | 2714 | /* Scheduler tick was off, recalculate the resched_target based on the |
| 2704 | * last tick event, and queue the scheduler work. | 2715 | * last tick event, and queue the scheduler work. |
| 2705 | */ | 2716 | */ |
| 2706 | now = get_jiffies_64(); | 2717 | sched_resume_tick(ptdev); |
| 2707 | sched->resched_target = sched->last_tick + sched->tick_period; | ||
| 2708 | if (sched->used_csg_slot_count == sched->csg_slot_count && | ||
| 2709 | time_before64(now, sched->resched_target)) | ||
| 2710 | delay_jiffies = min_t(unsigned long, sched->resched_target - now, ULONG_MAX); | ||
| 2711 | |||
| 2712 | sched_queue_delayed_work(sched, tick, delay_jiffies); | ||
| 2713 | } | 2718 | } |
| 2714 | 2719 | ||
| 2715 | static void queue_stop(struct panthor_queue *queue, | 2720 | static void queue_stop(struct panthor_queue *queue, |
| @@ -2767,13 +2772,6 @@ static void panthor_group_start(struct panthor_group *group) · 51 unmodified lines | |||
| 2767 | group_put(group); | 2772 | group_put(group); |
| 2768 | } | 2773 | } |
| 2769 | 2774 | ||
| 2770 | static void panthor_sched_immediate_tick(struct panthor_device *ptdev) | ||
| 2771 | { | ||
| 2772 | struct panthor_scheduler *sched = ptdev->scheduler; | ||
| 2773 | |||
| 2774 | sched_queue_delayed_work(sched, tick, 0); | ||
| 2775 | } | ||
| 2776 | |||
| 2777 | /** | 2775 | /** |
| 2778 | * panthor_sched_report_mmu_fault() - Report MMU faults to the scheduler. | 2776 | * panthor_sched_report_mmu_fault() - Report MMU faults to the scheduler. |
| 2779 | */ | 2777 | */ |
| @@ -2781,13 +2779,13 @@ void panthor_sched_report_mmu_fault(struct panthor_device *ptdev) · 1 unmodified line | |||
| 2781 | { | 2779 | { |
| 2782 | /* Force a tick to immediately kill faulty groups. */ | 2780 | /* Force a tick to immediately kill faulty groups. */ |
| 2783 | if (ptdev->scheduler) | 2781 | if (ptdev->scheduler) |
| 2784 | panthor_sched_immediate_tick(ptdev); | 2782 | sched_queue_delayed_work(ptdev->scheduler, tick, 0); |
| 2785 | } | 2783 | } |
| 2786 | 2784 | ||
| 2787 | void panthor_sched_resume(struct panthor_device *ptdev) | 2785 | void panthor_sched_resume(struct panthor_device *ptdev) |
| 2788 | { | 2786 | { |
| 2789 | /* Force a tick to re-evaluate after a resume. */ | 2787 | /* Force a tick to re-evaluate after a resume. */ |
| 2790 | panthor_sched_immediate_tick(ptdev); | 2788 | sched_queue_delayed_work(ptdev->scheduler, tick, 0); |
| 2791 | } | 2789 | } |
| 2792 | 2790 | ||
| 2793 | void panthor_sched_suspend(struct panthor_device *ptdev) | 2791 | void panthor_sched_suspend(struct panthor_device *ptdev) |
| @@ -2943,8 +2941,6 @@ void panthor_sched_pre_reset(struct panthor_device *ptdev) · 149 unmodified lines | |||
| 2943 | * new jobs while we're resetting. | 2941 | * new jobs while we're resetting. |
| 2944 | */ | 2942 | */ |
| 2945 | for (i = 0; i < ARRAY_SIZE(sched->groups.runnable); i++) { | 2943 | for (i = 0; i < ARRAY_SIZE(sched->groups.runnable); i++) { |
| 2946 | /* All groups should be in the idle lists. */ | ||
| 2947 | drm_WARN_ON(&ptdev->base, !list_empty(&sched->groups.runnable[i])); | ||
| 2948 | list_for_each_entry_safe(group, group_tmp, &sched->groups.runnable[i], run_node) | 2944 | list_for_each_entry_safe(group, group_tmp, &sched->groups.runnable[i], run_node) |
| 2949 | panthor_group_stop(group); | 2945 | panthor_group_stop(group); |
| 2950 | } | 2946 | } |
| @@ -3343,6 +3339,18 @@ queue_run_job(struct drm_sched_job *sched_job) · 392 unmodified lines | |||
| 3343 | if (group->csg_id < 0) { | 3339 | if (group->csg_id < 0) { |
| 3344 | group_schedule_locked(group, BIT(job->queue_idx)); | 3340 | group_schedule_locked(group, BIT(job->queue_idx)); |
| 3345 | } else { | 3341 | } else { |
| 3342 | u32 queue_mask = BIT(job->queue_idx); | ||
| 3343 | bool resume_tick = group_is_idle(group) && | ||
| 3344 | (group->idle_queues & queue_mask) && | ||
| 3345 | !(group->blocked_queues & queue_mask) && | ||
| 3346 | sched->resched_target == U64_MAX; | ||
| 3347 | |||
| 3348 | /* We just added something to the queue, so it's no longer idle. */ | ||
| 3349 | group->idle_queues &= ~queue_mask; | ||
| 3350 | |||
| 3351 | if (resume_tick) | ||
| 3352 | sched_resume_tick(ptdev); | ||
| 3353 | |||
| 3346 | gpu_write(ptdev, CSF_DOORBELL(queue->doorbell_id), 1); | 3354 | gpu_write(ptdev, CSF_DOORBELL(queue->doorbell_id), 1); |
| 3347 | if (!sched->pm.has_ref && | 3355 | if (!sched->pm.has_ref && |
| 3348 | !(group->blocked_queues & BIT(job->queue_idx))) { | 3356 | !(group->blocked_queues & BIT(job->queue_idx))) { |
| @@ -138,7 +138,7 @@ static void pl111_display_enable(struct drm_simple_display_pipe *pipe, · 137 unmodified lines | |||
| 138 | 138 | ||
| 139 | ret = clk_set_rate(priv->clk, mode->clock * 1000); | 139 | ret = clk_set_rate(priv->clk, mode->clock * 1000); |
| 140 | if (ret) { | 140 | if (ret) { |
| 141 | dev_err(drm->dev, | 141 | drm_err(drm, |
| 142 | "Failed to set pixel clock rate to %d: %d\n", | 142 | "Failed to set pixel clock rate to %d: %d\n", |
| 143 | mode->clock * 1000, ret); | 143 | mode->clock * 1000, ret); |
| 144 | } | 144 | } |
| @@ -553,7 +553,7 @@ pl111_init_clock_divider(struct drm_device *drm) · 408 unmodified lines | |||
| 553 | int ret; | 553 | int ret; |
| 554 | 554 | ||
| 555 | if (IS_ERR(parent)) { | 555 | if (IS_ERR(parent)) { |
| 556 | dev_err(drm->dev, "CLCD: unable to get clcdclk.\n"); | 556 | drm_err(drm, "CLCD: unable to get clcdclk.\n"); |
| 557 | return PTR_ERR(parent); | 557 | return PTR_ERR(parent); |
| 558 | } | 558 | } |
| 559 | 559 | ||
| @@ -55,6 +55,7 @@ · 54 unmodified lines | |||
| 55 | #include <drm/drm_gem_framebuffer_helper.h> | 55 | #include <drm/drm_gem_framebuffer_helper.h> |
| 56 | #include <drm/drm_of.h> | 56 | #include <drm/drm_of.h> |
| 57 | #include <drm/drm_panel.h> | 57 | #include <drm/drm_panel.h> |
| 58 | #include <drm/drm_print.h> | ||
| 58 | #include <drm/drm_probe_helper.h> | 59 | #include <drm/drm_probe_helper.h> |
| 59 | #include <drm/drm_vblank.h> | 60 | #include <drm/drm_vblank.h> |
| 60 | 61 | ||
| @@ -98,7 +99,7 @@ static int pl111_modeset_init(struct drm_device *dev) · 37 unmodified lines | |||
| 98 | struct drm_panel *tmp_panel; | 99 | struct drm_panel *tmp_panel; |
| 99 | struct drm_bridge *tmp_bridge; | 100 | struct drm_bridge *tmp_bridge; |
| 100 | 101 | ||
| 101 | dev_dbg(dev->dev, "checking endpoint %d\n", i); | 102 | drm_dbg(dev, "checking endpoint %d\n", i); |
| 102 | 103 | ||
| 103 | ret = drm_of_find_panel_or_bridge(dev->dev->of_node, | 104 | ret = drm_of_find_panel_or_bridge(dev->dev->of_node, |
| 104 | 0, i, | 105 | 0, i, |
| @@ -114,18 +115,18 @@ static int pl111_modeset_init(struct drm_device *dev) · 9 unmodified lines | |||
| 114 | defer = true; | 115 | defer = true; |
| 115 | } else if (ret != -ENODEV) { | 116 | } else if (ret != -ENODEV) { |
| 116 | /* Continue, maybe something else is working */ | 117 | /* Continue, maybe something else is working */ |
| 117 | dev_err(dev->dev, | 118 | drm_err(dev, |
| 118 | "endpoint %d returns %d\n", i, ret); | 119 | "endpoint %d returns %d\n", i, ret); |
| 119 | } | 120 | } |
| 120 | } | 121 | } |
| 121 | 122 | ||
| 122 | if (tmp_panel) { | 123 | if (tmp_panel) { |
| 123 | dev_info(dev->dev, | 124 | drm_info(dev, |
| 124 | "found panel on endpoint %d\n", i); | 125 | "found panel on endpoint %d\n", i); |
| 125 | panel = tmp_panel; | 126 | panel = tmp_panel; |
| 126 | } | 127 | } |
| 127 | if (tmp_bridge) { | 128 | if (tmp_bridge) { |
| 128 | dev_info(dev->dev, | 129 | drm_info(dev, |
| 129 | "found bridge on endpoint %d\n", i); | 130 | "found bridge on endpoint %d\n", i); |
| 130 | bridge = tmp_bridge; | 131 | bridge = tmp_bridge; |
| 131 | } | 132 | } |
| @@ -149,9 +150,9 @@ static int pl111_modeset_init(struct drm_device *dev) · 17 unmodified lines | |||
| 149 | goto finish; | 150 | goto finish; |
| 150 | } | 151 | } |
| 151 | } else if (bridge) { | 152 | } else if (bridge) { |
| 152 | dev_info(dev->dev, "Using non-panel bridge\n"); | 153 | drm_info(dev, "Using non-panel bridge\n"); |
| 153 | } else { | 154 | } else { |
| 154 | dev_err(dev->dev, "No bridge, exiting\n"); | 155 | drm_err(dev, "No bridge, exiting\n"); |
| 155 | return -ENODEV; | 156 | return -ENODEV; |
| 156 | } | 157 | } |
| 157 | 158 | ||
| @@ -163,7 +164,7 @@ static int pl111_modeset_init(struct drm_device *dev) · 5 unmodified lines | |||
| 163 | 164 | ||
| 164 | ret = pl111_display_init(dev); | 165 | ret = pl111_display_init(dev); |
| 165 | if (ret != 0) { | 166 | if (ret != 0) { |
| 166 | dev_err(dev->dev, "Failed to init display\n"); | 167 | drm_err(dev, "Failed to init display\n"); |
| 167 | goto out_bridge; | 168 | goto out_bridge; |
| 168 | } | 169 | } |
| 169 | 170 | ||
| @@ -175,7 +176,7 @@ static int pl111_modeset_init(struct drm_device *dev) · 5 unmodified lines | |||
| 175 | if (!priv->variant->broken_vblank) { | 176 | if (!priv->variant->broken_vblank) { |
| 176 | ret = drm_vblank_init(dev, 1); | 177 | ret = drm_vblank_init(dev, 1); |
| 177 | if (ret != 0) { | 178 | if (ret != 0) { |
| 178 | dev_err(dev->dev, "Failed to init vblank\n"); | 179 | drm_err(dev, "Failed to init vblank\n"); |
| 179 | goto out_bridge; | 180 | goto out_bridge; |
| 180 | } | 181 | } |
| 181 | } | 182 | } |
| @@ -255,13 +256,13 @@ static int pl111_amba_probe(struct amba_device *amba_dev, · 73 unmodified lines | |||
| 255 | 256 | ||
| 256 | ret = of_reserved_mem_device_init(dev); | 257 | ret = of_reserved_mem_device_init(dev); |
| 257 | if (!ret) { | 258 | if (!ret) { |
| 258 | dev_info(dev, "using device-specific reserved memory\n"); | 259 | drm_info(drm, "using device-specific reserved memory\n"); |
| 259 | priv->use_device_memory = true; | 260 | priv->use_device_memory = true; |
| 260 | } | 261 | } |
| 261 | 262 | ||
| 262 | if (of_property_read_u32(dev->of_node, "max-memory-bandwidth", | 263 | if (of_property_read_u32(dev->of_node, "max-memory-bandwidth", |
| 263 | &priv->memory_bw)) { | 264 | &priv->memory_bw)) { |
| 264 | dev_info(dev, "no max memory bandwidth specified, assume unlimited\n"); | 265 | drm_info(drm, "no max memory bandwidth specified, assume unlimited\n"); |
| 265 | priv->memory_bw = 0; | 266 | priv->memory_bw = 0; |
| 266 | } | 267 | } |
| 267 | 268 | ||
| @@ -276,17 +277,17 @@ static int pl111_amba_probe(struct amba_device *amba_dev, · 8 unmodified lines | |||
| 276 | 277 | ||
| 277 | priv->regs = devm_ioremap_resource(dev, &amba_dev->res); | 278 | priv->regs = devm_ioremap_resource(dev, &amba_dev->res); |
| 278 | if (IS_ERR(priv->regs)) { | 279 | if (IS_ERR(priv->regs)) { |
| 279 | dev_err(dev, "%s failed mmio\n", __func__); | 280 | drm_err(drm, "%s failed mmio\n", __func__); |
| 280 | ret = PTR_ERR(priv->regs); | 281 | ret = PTR_ERR(priv->regs); |
| 281 | goto dev_put; | 282 | goto dev_put; |
| 282 | } | 283 | } |
| 283 | 284 | ||
| 284 | /* This may override some variant settings */ | 285 | /* This may override some variant settings */ |
| 285 | ret = pl111_versatile_init(dev, priv); | 286 | ret = pl111_versatile_init(drm, priv); |
| 286 | if (ret) | 287 | if (ret) |
| 287 | goto dev_put; | 288 | goto dev_put; |
| 288 | 289 | ||
| 289 | pl111_nomadik_init(dev); | 290 | pl111_nomadik_init(drm); |
| 290 | 291 | ||
| 291 | /* turn off interrupts before requesting the irq */ | 292 | /* turn off interrupts before requesting the irq */ |
| 292 | writel(0, priv->regs + priv->ienb); | 293 | writel(0, priv->regs + priv->ienb); |
| @@ -294,7 +295,7 @@ static int pl111_amba_probe(struct amba_device *amba_dev, · 1 unmodified line | |||
| 294 | ret = devm_request_irq(dev, amba_dev->irq[0], pl111_irq, 0, | 295 | ret = devm_request_irq(dev, amba_dev->irq[0], pl111_irq, 0, |
| 295 | variant->name, priv); | 296 | variant->name, priv); |
| 296 | if (ret != 0) { | 297 | if (ret != 0) { |
| 297 | dev_err(dev, "%s failed irq %d\n", __func__, ret); | 298 | drm_err(drm, "%s failed irq %d\n", __func__, ret); |
| 298 | return ret; | 299 | return ret; |
| 299 | } | 300 | } |
| 300 | 301 | ||
| @@ -9,7 +9,7 @@ · 8 unmodified lines | |||
| 9 | #define PMU_CTRL_OFFSET 0x0000 | 9 | #define PMU_CTRL_OFFSET 0x0000 |
| 10 | #define PMU_CTRL_LCDNDIF BIT(26) | 10 | #define PMU_CTRL_LCDNDIF BIT(26) |
| 11 | 11 | ||
| 12 | void pl111_nomadik_init(struct device *dev) | 12 | void pl111_nomadik_init(struct drm_device *dev) |
| 13 | { | 13 | { |
| 14 | struct regmap *pmu_regmap; | 14 | struct regmap *pmu_regmap; |
| 15 | 15 | ||
| @@ -31,6 +31,6 @@ void pl111_nomadik_init(struct device *dev) · 15 unmodified lines | |||
| 31 | PMU_CTRL_OFFSET, | 31 | PMU_CTRL_OFFSET, |
| 32 | PMU_CTRL_LCDNDIF, | 32 | PMU_CTRL_LCDNDIF, |
| 33 | 0); | 33 | 0); |
| 34 | dev_info(dev, "set Nomadik PMU mux to CLCD mode\n"); | 34 | drm_info(dev, "set Nomadik PMU mux to CLCD mode\n"); |
| 35 | } | 35 | } |
| 36 | EXPORT_SYMBOL_GPL(pl111_nomadik_init); | 36 | EXPORT_SYMBOL_GPL(pl111_nomadik_init); |
| @@ -8,11 +8,11 @@ struct device; · 7 unmodified lines | |||
| 8 | 8 | ||
| 9 | #ifdef CONFIG_ARCH_NOMADIK | 9 | #ifdef CONFIG_ARCH_NOMADIK |
| 10 | 10 | ||
| 11 | void pl111_nomadik_init(struct device *dev); | 11 | void pl111_nomadik_init(struct drm_device *dev); |
| 12 | 12 | ||
| 13 | #else | 13 | #else |
| 14 | 14 | ||
| 15 | static inline void pl111_nomadik_init(struct device *dev) | 15 | static inline void pl111_nomadik_init(struct drm_device *dev) |
| 16 | { | 16 | { |
| 17 | } | 17 | } |
| 18 | 18 | ||
| @@ -20,6 +20,7 @@ · 19 unmodified lines | |||
| 20 | #include <linux/vexpress.h> | 20 | #include <linux/vexpress.h> |
| 21 | 21 | ||
| 22 | #include <drm/drm_fourcc.h> | 22 | #include <drm/drm_fourcc.h> |
| 23 | #include <drm/drm_print.h> | ||
| 23 | 24 | ||
| 24 | #include "pl111_versatile.h" | 25 | #include "pl111_versatile.h" |
| 25 | #include "pl111_drm.h" | 26 | #include "pl111_drm.h" |
| @@ -116,7 +117,7 @@ static void pl111_integrator_enable(struct drm_device *drm, u32 format) · 90 unmodified lines | |||
| 116 | { | 117 | { |
| 117 | u32 val; | 118 | u32 val; |
| 118 | 119 | ||
| 119 | dev_info(drm->dev, "enable Integrator CLCD connectors\n"); | 120 | drm_info(drm, "enable Integrator CLCD connectors\n"); |
| 120 | 121 | ||
| 121 | /* FIXME: really needed? */ | 122 | /* FIXME: really needed? */ |
| 122 | val = INTEGRATOR_CLCD_LCD_STATIC1 | INTEGRATOR_CLCD_LCD_STATIC2 | | 123 | val = INTEGRATOR_CLCD_LCD_STATIC1 | INTEGRATOR_CLCD_LCD_STATIC2 | |
| @@ -134,7 +135,7 @@ static void pl111_integrator_enable(struct drm_device *drm, u32 format) · 11 unmodified lines | |||
| 134 | val |= INTEGRATOR_CLCD_LCDMUX_VGA555; | 135 | val |= INTEGRATOR_CLCD_LCDMUX_VGA555; |
| 135 | break; | 136 | break; |
| 136 | default: | 137 | default: |
| 137 | dev_err(drm->dev, "unhandled format on Integrator 0x%08x\n", | 138 | drm_err(drm, "unhandled format on Integrator 0x%08x\n", |
| 138 | format); | 139 | format); |
| 139 | break; | 140 | break; |
| 140 | } | 141 | } |
| @@ -156,7 +157,7 @@ static void pl111_impd1_enable(struct drm_device *drm, u32 format) · 15 unmodified lines | |||
| 156 | { | 157 | { |
| 157 | u32 val; | 158 | u32 val; |
| 158 | 159 | ||
| 159 | dev_info(drm->dev, "enable IM-PD1 CLCD connectors\n"); | 160 | drm_info(drm, "enable IM-PD1 CLCD connectors\n"); |
| 160 | val = IMPD1_CTRL_DISP_VGA | IMPD1_CTRL_DISP_ENABLE; | 161 | val = IMPD1_CTRL_DISP_VGA | IMPD1_CTRL_DISP_ENABLE; |
| 161 | 162 | ||
| 162 | regmap_update_bits(versatile_syscon_map, | 163 | regmap_update_bits(versatile_syscon_map, |
| @@ -167,7 +168,7 @@ static void pl111_impd1_enable(struct drm_device *drm, u32 format) · 4 unmodified lines | |||
| 167 | 168 | ||
| 168 | static void pl111_impd1_disable(struct drm_device *drm) | 169 | static void pl111_impd1_disable(struct drm_device *drm) |
| 169 | { | 170 | { |
| 170 | dev_info(drm->dev, "disable IM-PD1 CLCD connectors\n"); | 171 | drm_info(drm, "disable IM-PD1 CLCD connectors\n"); |
| 171 | 172 | ||
| 172 | regmap_update_bits(versatile_syscon_map, | 173 | regmap_update_bits(versatile_syscon_map, |
| 173 | IMPD1_CTRL_OFFSET, | 174 | IMPD1_CTRL_OFFSET, |
| @@ -194,7 +195,7 @@ static void pl111_impd1_disable(struct drm_device *drm) · 20 unmodified lines | |||
| 194 | 195 | ||
| 195 | static void pl111_versatile_disable(struct drm_device *drm) | 196 | static void pl111_versatile_disable(struct drm_device *drm) |
| 196 | { | 197 | { |
| 197 | dev_info(drm->dev, "disable Versatile CLCD connectors\n"); | 198 | drm_info(drm, "disable Versatile CLCD connectors\n"); |
| 198 | regmap_update_bits(versatile_syscon_map, | 199 | regmap_update_bits(versatile_syscon_map, |
| 199 | SYS_CLCD, | 200 | SYS_CLCD, |
| 200 | SYS_CLCD_CONNECTOR_MASK, | 201 | SYS_CLCD_CONNECTOR_MASK, |
| @@ -205,7 +206,7 @@ static void pl111_versatile_enable(struct drm_device *drm, u32 format) · 4 unmodified lines | |||
| 205 | { | 206 | { |
| 206 | u32 val = 0; | 207 | u32 val = 0; |
| 207 | 208 | ||
| 208 | dev_info(drm->dev, "enable Versatile CLCD connectors\n"); | 209 | drm_info(drm, "enable Versatile CLCD connectors\n"); |
| 209 | 210 | ||
| 210 | switch (format) { | 211 | switch (format) { |
| 211 | case DRM_FORMAT_ABGR8888: | 212 | case DRM_FORMAT_ABGR8888: |
| @@ -227,7 +228,7 @@ static void pl111_versatile_enable(struct drm_device *drm, u32 format) · 15 unmodified lines | |||
| 227 | val |= SYS_CLCD_MODE_5551; | 228 | val |= SYS_CLCD_MODE_5551; |
| 228 | break; | 229 | break; |
| 229 | default: | 230 | default: |
| 230 | dev_err(drm->dev, "unhandled format on Versatile 0x%08x\n", | 231 | drm_err(drm, "unhandled format on Versatile 0x%08x\n", |
| 231 | format); | 232 | format); |
| 232 | break; | 233 | break; |
| 233 | } | 234 | } |
| @@ -247,7 +248,7 @@ static void pl111_versatile_enable(struct drm_device *drm, u32 format) · 13 unmodified lines | |||
| 247 | 248 | ||
| 248 | static void pl111_realview_clcd_disable(struct drm_device *drm) | 249 | static void pl111_realview_clcd_disable(struct drm_device *drm) |
| 249 | { | 250 | { |
| 250 | dev_info(drm->dev, "disable RealView CLCD connectors\n"); | 251 | drm_info(drm, "disable RealView CLCD connectors\n"); |
| 251 | regmap_update_bits(versatile_syscon_map, | 252 | regmap_update_bits(versatile_syscon_map, |
| 252 | SYS_CLCD, | 253 | SYS_CLCD, |
| 253 | SYS_CLCD_CONNECTOR_MASK, | 254 | SYS_CLCD_CONNECTOR_MASK, |
| @@ -256,7 +257,7 @@ static void pl111_realview_clcd_disable(struct drm_device *drm) · 2 unmodified lines | |||
| 256 | 257 | ||
| 257 | static void pl111_realview_clcd_enable(struct drm_device *drm, u32 format) | 258 | static void pl111_realview_clcd_enable(struct drm_device *drm, u32 format) |
| 258 | { | 259 | { |
| 259 | dev_info(drm->dev, "enable RealView CLCD connectors\n"); | 260 | drm_info(drm, "enable RealView CLCD connectors\n"); |
| 260 | regmap_update_bits(versatile_syscon_map, | 261 | regmap_update_bits(versatile_syscon_map, |
| 261 | SYS_CLCD, | 262 | SYS_CLCD, |
| 262 | SYS_CLCD_CONNECTOR_MASK, | 263 | SYS_CLCD_CONNECTOR_MASK, |
| @@ -376,7 +377,7 @@ static const struct pl111_variant_data pl111_vexpress = { · 113 unmodified lines | |||
| 376 | #define VEXPRESS_FPGAMUX_DAUGHTERBOARD_1 0x01 | 377 | #define VEXPRESS_FPGAMUX_DAUGHTERBOARD_1 0x01 |
| 377 | #define VEXPRESS_FPGAMUX_DAUGHTERBOARD_2 0x02 | 378 | #define VEXPRESS_FPGAMUX_DAUGHTERBOARD_2 0x02 |
| 378 | 379 | ||
| 379 | static int pl111_vexpress_clcd_init(struct device *dev, struct device_node *np, | 380 | static int pl111_vexpress_clcd_init(struct drm_device *dev, struct device_node *np, |
| 380 | struct pl111_drm_dev_private *priv) | 381 | struct pl111_drm_dev_private *priv) |
| 381 | { | 382 | { |
| 382 | struct platform_device *pdev; | 383 | struct platform_device *pdev; |
| @@ -433,22 +434,22 @@ static int pl111_vexpress_clcd_init(struct device *dev, struct device_node *np, · 50 unmodified lines | |||
| 433 | mux_motherboard = false; | 434 | mux_motherboard = false; |
| 434 | 435 | ||
| 435 | if (mux_motherboard) { | 436 | if (mux_motherboard) { |
| 436 | dev_info(dev, "DVI muxed to motherboard CLCD\n"); | 437 | drm_info(dev, "DVI muxed to motherboard CLCD\n"); |
| 437 | val = VEXPRESS_FPGAMUX_MOTHERBOARD; | 438 | val = VEXPRESS_FPGAMUX_MOTHERBOARD; |
| 438 | } else if (ct_clcd == dev->of_node) { | 439 | } else if (ct_clcd == dev->dev->of_node) { |
| 439 | dev_info(dev, | 440 | drm_info(dev, |
| 440 | "DVI muxed to daughterboard 1 (core tile) CLCD\n"); | 441 | "DVI muxed to daughterboard 1 (core tile) CLCD\n"); |
| 441 | val = VEXPRESS_FPGAMUX_DAUGHTERBOARD_1; | 442 | val = VEXPRESS_FPGAMUX_DAUGHTERBOARD_1; |
| 442 | } else { | 443 | } else { |
| 443 | dev_info(dev, "core tile graphics present\n"); | 444 | drm_info(dev, "core tile graphics present\n"); |
| 444 | dev_info(dev, "this device will be deactivated\n"); | 445 | drm_info(dev, "this device will be deactivated\n"); |
| 445 | return -ENODEV; | 446 | return -ENODEV; |
| 446 | } | 447 | } |
| 447 | 448 | ||
| 448 | /* Call into deep Vexpress configuration API */ | 449 | /* Call into deep Vexpress configuration API */ |
| 449 | pdev = of_find_device_by_node(np); | 450 | pdev = of_find_device_by_node(np); |
| 450 | if (!pdev) { | 451 | if (!pdev) { |
| 451 | dev_err(dev, "can't find the sysreg device, deferring\n"); | 452 | drm_err(dev, "can't find the sysreg device, deferring\n"); |
| 452 | return -EPROBE_DEFER; | 453 | return -EPROBE_DEFER; |
| 453 | } | 454 | } |
| 454 | 455 | ||
| @@ -461,17 +462,17 @@ static int pl111_vexpress_clcd_init(struct device *dev, struct device_node *np, · 6 unmodified lines | |||
| 461 | ret = regmap_write(map, 0, val); | 462 | ret = regmap_write(map, 0, val); |
| 462 | platform_device_put(pdev); | 463 | platform_device_put(pdev); |
| 463 | if (ret) { | 464 | if (ret) { |
| 464 | dev_err(dev, "error setting DVI muxmode\n"); | 465 | drm_err(dev, "error setting DVI muxmode\n"); |
| 465 | return -ENODEV; | 466 | return -ENODEV; |
| 466 | } | 467 | } |
| 467 | 468 | ||
| 468 | priv->variant = &pl111_vexpress; | 469 | priv->variant = &pl111_vexpress; |
| 469 | dev_info(dev, "initializing Versatile Express PL111\n"); | 470 | drm_info(dev, "initializing Versatile Express PL111\n"); |
| 470 | 471 | ||
| 471 | return 0; | 472 | return 0; |
| 472 | } | 473 | } |
| 473 | 474 | ||
| 474 | int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv) | 475 | int pl111_versatile_init(struct drm_device *dev, struct pl111_drm_dev_private *priv) |
| 475 | { | 476 | { |
| 476 | const struct of_device_id *clcd_id; | 477 | const struct of_device_id *clcd_id; |
| 477 | enum versatile_clcd versatile_clcd_type; | 478 | enum versatile_clcd versatile_clcd_type; |
| @@ -492,7 +493,7 @@ int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv) · 14 unmodified lines | |||
| 492 | int ret = pl111_vexpress_clcd_init(dev, np, priv); | 493 | int ret = pl111_vexpress_clcd_init(dev, np, priv); |
| 493 | of_node_put(np); | 494 | of_node_put(np); |
| 494 | if (ret) | 495 | if (ret) |
| 495 | dev_err(dev, "Versatile Express init failed - %d", ret); | 496 | drm_err(dev, "Versatile Express init failed - %d", ret); |
| 496 | return ret; | 497 | return ret; |
| 497 | } | 498 | } |
| 498 | 499 | ||
| @@ -511,7 +512,7 @@ int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv) · 12 unmodified lines | |||
| 511 | map = syscon_node_to_regmap(np); | 512 | map = syscon_node_to_regmap(np); |
| 512 | of_node_put(np); | 513 | of_node_put(np); |
| 513 | if (IS_ERR(map)) { | 514 | if (IS_ERR(map)) { |
| 514 | dev_err(dev, "no Versatile syscon regmap\n"); | 515 | drm_err(dev, "no Versatile syscon regmap\n"); |
| 515 | return PTR_ERR(map); | 516 | return PTR_ERR(map); |
| 516 | } | 517 | } |
| 517 | 518 | ||
| @@ -520,14 +521,14 @@ int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv) · 2 unmodified lines | |||
| 520 | versatile_syscon_map = map; | 521 | versatile_syscon_map = map; |
| 521 | priv->variant = &pl110_integrator; | 522 | priv->variant = &pl110_integrator; |
| 522 | priv->variant_display_enable = pl111_integrator_enable; | 523 | priv->variant_display_enable = pl111_integrator_enable; |
| 523 | dev_info(dev, "set up callbacks for Integrator PL110\n"); | 524 | drm_info(dev, "set up callbacks for Integrator PL110\n"); |
| 524 | break; | 525 | break; |
| 525 | case INTEGRATOR_IMPD1: | 526 | case INTEGRATOR_IMPD1: |
| 526 | versatile_syscon_map = map; | 527 | versatile_syscon_map = map; |
| 527 | priv->variant = &pl110_impd1; | 528 | priv->variant = &pl110_impd1; |
| 528 | priv->variant_display_enable = pl111_impd1_enable; | 529 | priv->variant_display_enable = pl111_impd1_enable; |
| 529 | priv->variant_display_disable = pl111_impd1_disable; | 530 | priv->variant_display_disable = pl111_impd1_disable; |
| 530 | dev_info(dev, "set up callbacks for IM-PD1 PL110\n"); | 531 | drm_info(dev, "set up callbacks for IM-PD1 PL110\n"); |
| 531 | break; | 532 | break; |
| 532 | case VERSATILE_CLCD: | 533 | case VERSATILE_CLCD: |
| 533 | versatile_syscon_map = map; | 534 | versatile_syscon_map = map; |
| @@ -542,7 +543,7 @@ int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv) · 8 unmodified lines | |||
| 542 | */ | 543 | */ |
| 543 | priv->ienb = CLCD_PL111_IENB; | 544 | priv->ienb = CLCD_PL111_IENB; |
| 544 | priv->ctrl = CLCD_PL111_CNTL; | 545 | priv->ctrl = CLCD_PL111_CNTL; |
| 545 | dev_info(dev, "set up callbacks for Versatile PL110\n"); | 546 | drm_info(dev, "set up callbacks for Versatile PL110\n"); |
| 546 | break; | 547 | break; |
| 547 | case REALVIEW_CLCD_EB: | 548 | case REALVIEW_CLCD_EB: |
| 548 | case REALVIEW_CLCD_PB1176: | 549 | case REALVIEW_CLCD_PB1176: |
| @@ -553,10 +554,10 @@ int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv) · 4 unmodified lines | |||
| 553 | priv->variant = &pl111_realview; | 554 | priv->variant = &pl111_realview; |
| 554 | priv->variant_display_enable = pl111_realview_clcd_enable; | 555 | priv->variant_display_enable = pl111_realview_clcd_enable; |
| 555 | priv->variant_display_disable = pl111_realview_clcd_disable; | 556 | priv->variant_display_disable = pl111_realview_clcd_disable; |
| 556 | dev_info(dev, "set up callbacks for RealView PL111\n"); | 557 | drm_info(dev, "set up callbacks for RealView PL111\n"); |
| 557 | break; | 558 | break; |
| 558 | default: | 559 | default: |
| 559 | dev_info(dev, "unknown Versatile system controller\n"); | 560 | drm_info(dev, "unknown Versatile system controller\n"); |
| 560 | break; | 561 | break; |
| 561 | } | 562 | } |
| 562 | 563 | ||
| @@ -7,6 +7,6 @@ · 6 unmodified lines | |||
| 7 | struct device; | 7 | struct device; |
| 8 | struct pl111_drm_dev_private; | 8 | struct pl111_drm_dev_private; |
| 9 | 9 | ||
| 10 | int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv); | 10 | int pl111_versatile_init(struct drm_device *dev, struct pl111_drm_dev_private *priv); |
| 11 | 11 | ||
| 12 | #endif | 12 | #endif |
| @@ -1133,7 +1133,7 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode · 1132 unmodified lines | |||
| 1133 | 1133 | ||
| 1134 | static int dce4_crtc_do_set_base(struct drm_crtc *crtc, | 1134 | static int dce4_crtc_do_set_base(struct drm_crtc *crtc, |
| 1135 | struct drm_framebuffer *fb, | 1135 | struct drm_framebuffer *fb, |
| 1136 | int x, int y, int atomic) | 1136 | int x, int y) |
| 1137 | { | 1137 | { |
| 1138 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); | 1138 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
| 1139 | struct drm_device *dev = crtc->dev; | 1139 | struct drm_device *dev = crtc->dev; |
| @@ -1150,33 +1150,23 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc, · 10 unmodified lines | |||
| 1150 | bool bypass_lut = false; | 1150 | bool bypass_lut = false; |
| 1151 | 1151 | ||
| 1152 | /* no fb bound */ | 1152 | /* no fb bound */ |
| 1153 | if (!atomic && !crtc->primary->fb) { | 1153 | if (!crtc->primary->fb) { |
| 1154 | DRM_DEBUG_KMS("No FB bound\n"); | 1154 | DRM_DEBUG_KMS("No FB bound\n"); |
| 1155 | return 0; | 1155 | return 0; |
| 1156 | } | 1156 | } |
| 1157 | 1157 | ||
| 1158 | if (atomic) | 1158 | target_fb = crtc->primary->fb; |
| 1159 | target_fb = fb; | ||
| 1160 | else | ||
| 1161 | target_fb = crtc->primary->fb; | ||
| 1162 | 1159 | ||
| 1163 | /* If atomic, assume fb object is pinned & idle & fenced and | ||
| 1164 | * just update base pointers | ||
| 1165 | */ | ||
| 1166 | obj = target_fb->obj[0]; | 1160 | obj = target_fb->obj[0]; |
| 1167 | rbo = gem_to_radeon_bo(obj); | 1161 | rbo = gem_to_radeon_bo(obj); |
| 1168 | r = radeon_bo_reserve(rbo, false); | 1162 | r = radeon_bo_reserve(rbo, false); |
| 1169 | if (unlikely(r != 0)) | 1163 | if (unlikely(r != 0)) |
| 1170 | return r; | 1164 | return r; |
| 1171 | 1165 | ||
| 1172 | if (atomic) | 1166 | r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location); |
| 1173 | fb_location = radeon_bo_gpu_offset(rbo); | 1167 | if (unlikely(r != 0)) { |
| 1174 | else { | 1168 | radeon_bo_unreserve(rbo); |
| 1175 | r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location); | 1169 | return -EINVAL; |
| 1176 | if (unlikely(r != 0)) { | ||
| 1177 | radeon_bo_unreserve(rbo); | ||
| 1178 | return -EINVAL; | ||
| 1179 | } | ||
| 1180 | } | 1170 | } |
| 1181 | 1171 | ||
| 1182 | radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL); | 1172 | radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL); |
| @@ -1437,7 +1427,7 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc, · 254 unmodified lines | |||
| 1437 | /* set pageflip to happen anywhere in vblank interval */ | 1427 | /* set pageflip to happen anywhere in vblank interval */ |
| 1438 | WREG32(EVERGREEN_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0); | 1428 | WREG32(EVERGREEN_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0); |
| 1439 | 1429 | ||
| 1440 | if (!atomic && fb && fb != crtc->primary->fb) { | 1430 | if (fb && fb != crtc->primary->fb) { |
| 1441 | rbo = gem_to_radeon_bo(fb->obj[0]); | 1431 | rbo = gem_to_radeon_bo(fb->obj[0]); |
| 1442 | r = radeon_bo_reserve(rbo, false); | 1432 | r = radeon_bo_reserve(rbo, false); |
| 1443 | if (unlikely(r != 0)) | 1433 | if (unlikely(r != 0)) |
| @@ -1454,7 +1444,7 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc, · 10 unmodified lines | |||
| 1454 | 1444 | ||
| 1455 | static int avivo_crtc_do_set_base(struct drm_crtc *crtc, | 1445 | static int avivo_crtc_do_set_base(struct drm_crtc *crtc, |
| 1456 | struct drm_framebuffer *fb, | 1446 | struct drm_framebuffer *fb, |
| 1457 | int x, int y, int atomic) | 1447 | int x, int y) |
| 1458 | { | 1448 | { |
| 1459 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); | 1449 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
| 1460 | struct drm_device *dev = crtc->dev; | 1450 | struct drm_device *dev = crtc->dev; |
| @@ -1470,15 +1460,12 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc, · 9 unmodified lines | |||
| 1470 | bool bypass_lut = false; | 1460 | bool bypass_lut = false; |
| 1471 | 1461 | ||
| 1472 | /* no fb bound */ | 1462 | /* no fb bound */ |
| 1473 | if (!atomic && !crtc->primary->fb) { | 1463 | if (!crtc->primary->fb) { |
| 1474 | DRM_DEBUG_KMS("No FB bound\n"); | 1464 | DRM_DEBUG_KMS("No FB bound\n"); |
| 1475 | return 0; | 1465 | return 0; |
| 1476 | } | 1466 | } |
| 1477 | 1467 | ||
| 1478 | if (atomic) | 1468 | target_fb = crtc->primary->fb; |
| 1479 | target_fb = fb; | ||
| 1480 | else | ||
| 1481 | target_fb = crtc->primary->fb; | ||
| 1482 | 1469 | ||
| 1483 | obj = target_fb->obj[0]; | 1470 | obj = target_fb->obj[0]; |
| 1484 | rbo = gem_to_radeon_bo(obj); | 1471 | rbo = gem_to_radeon_bo(obj); |
| @@ -1486,17 +1473,10 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc, · 1 unmodified line | |||
| 1486 | if (unlikely(r != 0)) | 1473 | if (unlikely(r != 0)) |
| 1487 | return r; | 1474 | return r; |
| 1488 | 1475 | ||
| 1489 | /* If atomic, assume fb object is pinned & idle & fenced and | 1476 | r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location); |
| 1490 | * just update base pointers | 1477 | if (unlikely(r != 0)) { |
| 1491 | */ | 1478 | radeon_bo_unreserve(rbo); |
| 1492 | if (atomic) | 1479 | return -EINVAL; |
| 1493 | fb_location = radeon_bo_gpu_offset(rbo); | ||
| 1494 | else { | ||
| 1495 | r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location); | ||
| 1496 | if (unlikely(r != 0)) { | ||
| 1497 | radeon_bo_unreserve(rbo); | ||
| 1498 | return -EINVAL; | ||
| 1499 | } | ||
| 1500 | } | 1480 | } |
| 1501 | radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL); | 1481 | radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL); |
| 1502 | radeon_bo_unreserve(rbo); | 1482 | radeon_bo_unreserve(rbo); |
| @@ -1645,7 +1625,7 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc, · 142 unmodified lines | |||
| 1645 | /* set pageflip to happen only at start of vblank interval (front porch) */ | 1625 | /* set pageflip to happen only at start of vblank interval (front porch) */ |
| 1646 | WREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 3); | 1626 | WREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 3); |
| 1647 | 1627 | ||
| 1648 | if (!atomic && fb && fb != crtc->primary->fb) { | 1628 | if (fb && fb != crtc->primary->fb) { |
| 1649 | rbo = gem_to_radeon_bo(fb->obj[0]); | 1629 | rbo = gem_to_radeon_bo(fb->obj[0]); |
| 1650 | r = radeon_bo_reserve(rbo, false); | 1630 | r = radeon_bo_reserve(rbo, false); |
| 1651 | if (unlikely(r != 0)) | 1631 | if (unlikely(r != 0)) |
| @@ -1667,26 +1647,11 @@ int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y, · 15 unmodified lines | |||
| 1667 | struct radeon_device *rdev = dev->dev_private; | 1647 | struct radeon_device *rdev = dev->dev_private; |
| 1668 | 1648 | ||
| 1669 | if (ASIC_IS_DCE4(rdev)) | 1649 | if (ASIC_IS_DCE4(rdev)) |
| 1670 | return dce4_crtc_do_set_base(crtc, old_fb, x, y, 0); | 1650 | return dce4_crtc_do_set_base(crtc, old_fb, x, y); |
| 1671 | else if (ASIC_IS_AVIVO(rdev)) | ||
| 1672 | return avivo_crtc_do_set_base(crtc, old_fb, x, y, 0); | ||
| 1673 | else | ||
| 1674 | return radeon_crtc_do_set_base(crtc, old_fb, x, y, 0); | ||
| 1675 | } | ||
| 1676 | |||
| 1677 | int atombios_crtc_set_base_atomic(struct drm_crtc *crtc, | ||
| 1678 | struct drm_framebuffer *fb, | ||
| 1679 | int x, int y, enum mode_set_atomic state) | ||
| 1680 | { | ||
| 1681 | struct drm_device *dev = crtc->dev; | ||
| 1682 | struct radeon_device *rdev = dev->dev_private; | ||
| 1683 | |||
| 1684 | if (ASIC_IS_DCE4(rdev)) | ||
| 1685 | return dce4_crtc_do_set_base(crtc, fb, x, y, 1); | ||
| 1686 | else if (ASIC_IS_AVIVO(rdev)) | 1651 | else if (ASIC_IS_AVIVO(rdev)) |
| 1687 | return avivo_crtc_do_set_base(crtc, fb, x, y, 1); | 1652 | return avivo_crtc_do_set_base(crtc, old_fb, x, y); |
| 1688 | else | 1653 | else |
| 1689 | return radeon_crtc_do_set_base(crtc, fb, x, y, 1); | 1654 | return radeon_crtc_do_set_base(crtc, old_fb, x, y); |
| 1690 | } | 1655 | } |
| 1691 | 1656 | ||
| 1692 | /* properly set additional regs when using atombios */ | 1657 | /* properly set additional regs when using atombios */ |
| @@ -2215,7 +2180,6 @@ static const struct drm_crtc_helper_funcs atombios_helper_funcs = { · 522 unmodified lines | |||
| 2215 | .mode_fixup = atombios_crtc_mode_fixup, | 2180 | .mode_fixup = atombios_crtc_mode_fixup, |
| 2216 | .mode_set = atombios_crtc_mode_set, | 2181 | .mode_set = atombios_crtc_mode_set, |
| 2217 | .mode_set_base = atombios_crtc_set_base, | 2182 | .mode_set_base = atombios_crtc_set_base, |
| 2218 | .mode_set_base_atomic = atombios_crtc_set_base_atomic, | ||
| 2219 | .prepare = atombios_crtc_prepare, | 2183 | .prepare = atombios_crtc_prepare, |
| 2220 | .commit = atombios_crtc_commit, | 2184 | .commit = atombios_crtc_commit, |
| 2221 | .disable = atombios_crtc_disable, | 2185 | .disable = atombios_crtc_disable, |
| @@ -360,19 +360,12 @@ static void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) · 359 unmodified lines | |||
| 360 | int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y, | 360 | int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y, |
| 361 | struct drm_framebuffer *old_fb) | 361 | struct drm_framebuffer *old_fb) |
| 362 | { | 362 | { |
| 363 | return radeon_crtc_do_set_base(crtc, old_fb, x, y, 0); | 363 | return radeon_crtc_do_set_base(crtc, old_fb, x, y); |
| 364 | } | ||
| 365 | |||
| 366 | int radeon_crtc_set_base_atomic(struct drm_crtc *crtc, | ||
| 367 | struct drm_framebuffer *fb, | ||
| 368 | int x, int y, enum mode_set_atomic state) | ||
| 369 | { | ||
| 370 | return radeon_crtc_do_set_base(crtc, fb, x, y, 1); | ||
| 371 | } | 364 | } |
| 372 | 365 | ||
| 373 | int radeon_crtc_do_set_base(struct drm_crtc *crtc, | 366 | int radeon_crtc_do_set_base(struct drm_crtc *crtc, |
| 374 | struct drm_framebuffer *fb, | 367 | struct drm_framebuffer *fb, |
| 375 | int x, int y, int atomic) | 368 | int x, int y) |
| 376 | { | 369 | { |
| 377 | struct drm_device *dev = crtc->dev; | 370 | struct drm_device *dev = crtc->dev; |
| 378 | struct radeon_device *rdev = dev->dev_private; | 371 | struct radeon_device *rdev = dev->dev_private; |
| @@ -390,15 +383,12 @@ int radeon_crtc_do_set_base(struct drm_crtc *crtc, · 11 unmodified lines | |||
| 390 | 383 | ||
| 391 | DRM_DEBUG_KMS("\n"); | 384 | DRM_DEBUG_KMS("\n"); |
| 392 | /* no fb bound */ | 385 | /* no fb bound */ |
| 393 | if (!atomic && !crtc->primary->fb) { | 386 | if (!crtc->primary->fb) { |
| 394 | DRM_DEBUG_KMS("No FB bound\n"); | 387 | DRM_DEBUG_KMS("No FB bound\n"); |
| 395 | return 0; | 388 | return 0; |
| 396 | } | 389 | } |
| 397 | 390 | ||
| 398 | if (atomic) | 391 | target_fb = crtc->primary->fb; |
| 399 | target_fb = fb; | ||
| 400 | else | ||
| 401 | target_fb = crtc->primary->fb; | ||
| 402 | 392 | ||
| 403 | switch (target_fb->format->cpp[0] * 8) { | 393 | switch (target_fb->format->cpp[0] * 8) { |
| 404 | case 8: | 394 | case 8: |
| @@ -445,7 +435,7 @@ retry: · 40 unmodified lines | |||
| 445 | * We don't shutdown the display controller because new buffer | 435 | * We don't shutdown the display controller because new buffer |
| 446 | * will end up in same spot. | 436 | * will end up in same spot. |
| 447 | */ | 437 | */ |
| 448 | if (!atomic && fb && fb != crtc->primary->fb) { | 438 | if (fb && fb != crtc->primary->fb) { |
| 449 | struct radeon_bo *old_rbo; | 439 | struct radeon_bo *old_rbo; |
| 450 | unsigned long nsize, osize; | 440 | unsigned long nsize, osize; |
| 451 | 441 | ||
| @@ -555,7 +545,7 @@ retry: · 103 unmodified lines | |||
| 555 | WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, crtc_offset); | 545 | WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, crtc_offset); |
| 556 | WREG32(RADEON_CRTC_PITCH + radeon_crtc->crtc_offset, crtc_pitch); | 546 | WREG32(RADEON_CRTC_PITCH + radeon_crtc->crtc_offset, crtc_pitch); |
| 557 | 547 | ||
| 558 | if (!atomic && fb && fb != crtc->primary->fb) { | 548 | if (fb && fb != crtc->primary->fb) { |
| 559 | rbo = gem_to_radeon_bo(fb->obj[0]); | 549 | rbo = gem_to_radeon_bo(fb->obj[0]); |
| 560 | r = radeon_bo_reserve(rbo, false); | 550 | r = radeon_bo_reserve(rbo, false); |
| 561 | if (unlikely(r != 0)) | 551 | if (unlikely(r != 0)) |
| @@ -1108,7 +1098,6 @@ static const struct drm_crtc_helper_funcs legacy_helper_funcs = { · 546 unmodified lines | |||
| 1108 | .mode_fixup = radeon_crtc_mode_fixup, | 1098 | .mode_fixup = radeon_crtc_mode_fixup, |
| 1109 | .mode_set = radeon_crtc_mode_set, | 1099 | .mode_set = radeon_crtc_mode_set, |
| 1110 | .mode_set_base = radeon_crtc_set_base, | 1100 | .mode_set_base = radeon_crtc_set_base, |
| 1111 | .mode_set_base_atomic = radeon_crtc_set_base_atomic, | ||
| 1112 | .prepare = radeon_crtc_prepare, | 1101 | .prepare = radeon_crtc_prepare, |
| 1113 | .commit = radeon_crtc_commit, | 1102 | .commit = radeon_crtc_commit, |
| 1114 | .disable = radeon_crtc_disable, | 1103 | .disable = radeon_crtc_disable, |
| @@ -804,10 +804,6 @@ extern bool radeon_encoder_is_digital(struct drm_encoder *encoder); · 803 unmodified lines | |||
| 804 | extern void radeon_crtc_load_lut(struct drm_crtc *crtc); | 804 | extern void radeon_crtc_load_lut(struct drm_crtc *crtc); |
| 805 | extern int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y, | 805 | extern int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y, |
| 806 | struct drm_framebuffer *old_fb); | 806 | struct drm_framebuffer *old_fb); |
| 807 | extern int atombios_crtc_set_base_atomic(struct drm_crtc *crtc, | ||
| 808 | struct drm_framebuffer *fb, | ||
| 809 | int x, int y, | ||
| 810 | enum mode_set_atomic state); | ||
| 811 | extern int atombios_crtc_mode_set(struct drm_crtc *crtc, | 807 | extern int atombios_crtc_mode_set(struct drm_crtc *crtc, |
| 812 | struct drm_display_mode *mode, | 808 | struct drm_display_mode *mode, |
| 813 | struct drm_display_mode *adjusted_mode, | 809 | struct drm_display_mode *adjusted_mode, |
| @@ -817,13 +813,9 @@ extern void atombios_crtc_dpms(struct drm_crtc *crtc, int mode); · 3 unmodified lines | |||
| 817 | 813 | ||
| 818 | extern int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y, | 814 | extern int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y, |
| 819 | struct drm_framebuffer *old_fb); | 815 | struct drm_framebuffer *old_fb); |
| 820 | extern int radeon_crtc_set_base_atomic(struct drm_crtc *crtc, | ||
| 821 | struct drm_framebuffer *fb, | ||
| 822 | int x, int y, | ||
| 823 | enum mode_set_atomic state); | ||
| 824 | extern int radeon_crtc_do_set_base(struct drm_crtc *crtc, | 816 | extern int radeon_crtc_do_set_base(struct drm_crtc *crtc, |
| 825 | struct drm_framebuffer *fb, | 817 | struct drm_framebuffer *fb, |
| 826 | int x, int y, int atomic); | 818 | int x, int y); |
| 827 | extern int radeon_crtc_cursor_set2(struct drm_crtc *crtc, | 819 | extern int radeon_crtc_cursor_set2(struct drm_crtc *crtc, |
| 828 | struct drm_file *file_priv, | 820 | struct drm_file *file_priv, |
| 829 | uint32_t handle, | 821 | uint32_t handle, |
| @@ -692,7 +692,7 @@ static int threaded_fence_signal(void *arg) · 691 unmodified lines | |||
| 692 | 692 | ||
| 693 | msleep(20); | 693 | msleep(20); |
| 694 | 694 | ||
| 695 | return dma_fence_signal(fence); | 695 | return dma_fence_check_and_signal(fence) ? -EINVAL : 0; |
| 696 | } | 696 | } |
| 697 | 697 | ||
| 698 | static void ttm_bo_validate_move_fence_not_signaled(struct kunit *test) | 698 | static void ttm_bo_validate_move_fence_not_signaled(struct kunit *test) |
| @@ -268,8 +268,8 @@ static void ttm_bo_release(struct kref *kref) · 267 unmodified lines | |||
| 268 | 30 * HZ); | 268 | 30 * HZ); |
| 269 | } | 269 | } |
| 270 | 270 | ||
| 271 | if (bo->bdev->funcs->release_notify) | 271 | if (bdev->funcs->release_notify) |
| 272 | bo->bdev->funcs->release_notify(bo); | 272 | bdev->funcs->release_notify(bo); |
| 273 | 273 | ||
| 274 | drm_vma_offset_remove(bdev->vma_manager, &bo->base.vma_node); | 274 | drm_vma_offset_remove(bdev->vma_manager, &bo->base.vma_node); |
| 275 | ttm_mem_io_free(bdev, bo->resource); | 275 | ttm_mem_io_free(bdev, bo->resource); |
| @@ -283,7 +283,7 @@ static void ttm_bo_release(struct kref *kref) · 7 unmodified lines | |||
| 283 | ttm_bo_flush_all_fences(bo); | 283 | ttm_bo_flush_all_fences(bo); |
| 284 | bo->deleted = true; | 284 | bo->deleted = true; |
| 285 | 285 | ||
| 286 | spin_lock(&bo->bdev->lru_lock); | 286 | spin_lock(&bdev->lru_lock); |
| 287 | 287 | ||
| 288 | /* | 288 | /* |
| 289 | * Make pinned bos immediately available to | 289 | * Make pinned bos immediately available to |
| @@ -299,7 +299,7 @@ static void ttm_bo_release(struct kref *kref) · 9 unmodified lines | |||
| 299 | } | 299 | } |
| 300 | 300 | ||
| 301 | kref_init(&bo->kref); | 301 | kref_init(&bo->kref); |
| 302 | spin_unlock(&bo->bdev->lru_lock); | 302 | spin_unlock(&bdev->lru_lock); |
| 303 | 303 | ||
| 304 | INIT_WORK(&bo->delayed_delete, ttm_bo_delayed_delete); | 304 | INIT_WORK(&bo->delayed_delete, ttm_bo_delayed_delete); |
| 305 | 305 | ||
| @@ -359,7 +359,6 @@ static int ttm_bo_bounce_temp_buffer(struct ttm_buffer_object *bo, · 53 unmodified lines | |||
| 359 | static int ttm_bo_evict(struct ttm_buffer_object *bo, | 359 | static int ttm_bo_evict(struct ttm_buffer_object *bo, |
| 360 | struct ttm_operation_ctx *ctx) | 360 | struct ttm_operation_ctx *ctx) |
| 361 | { | 361 | { |
| 362 | struct ttm_device *bdev = bo->bdev; | ||
| 363 | struct ttm_resource *evict_mem; | 362 | struct ttm_resource *evict_mem; |
| 364 | struct ttm_placement placement; | 363 | struct ttm_placement placement; |
| 365 | struct ttm_place hop; | 364 | struct ttm_place hop; |
| @@ -370,7 +369,7 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo, · 4 unmodified lines | |||
| 370 | dma_resv_assert_held(bo->base.resv); | 369 | dma_resv_assert_held(bo->base.resv); |
| 371 | 370 | ||
| 372 | placement.num_placement = 0; | 371 | placement.num_placement = 0; |
| 373 | bdev->funcs->evict_flags(bo, &placement); | 372 | bo->bdev->funcs->evict_flags(bo, &placement); |
| 374 | 373 | ||
| 375 | if (!placement.num_placement) { | 374 | if (!placement.num_placement) { |
| 376 | ret = ttm_bo_wait_ctx(bo, ctx); | 375 | ret = ttm_bo_wait_ctx(bo, ctx); |
| @@ -423,16 +422,16 @@ bool ttm_bo_eviction_valuable(struct ttm_buffer_object *bo, · 46 unmodified lines | |||
| 423 | const struct ttm_place *place) | 422 | const struct ttm_place *place) |
| 424 | { | 423 | { |
| 425 | struct ttm_resource *res = bo->resource; | 424 | struct ttm_resource *res = bo->resource; |
| 426 | struct ttm_device *bdev = bo->bdev; | ||
| 427 | 425 | ||
| 428 | dma_resv_assert_held(bo->base.resv); | 426 | dma_resv_assert_held(bo->base.resv); |
| 429 | if (bo->resource->mem_type == TTM_PL_SYSTEM) | 427 | |
| 428 | if (res->mem_type == TTM_PL_SYSTEM) | ||
| 430 | return true; | 429 | return true; |
| 431 | 430 | ||
| 432 | /* Don't evict this BO if it's outside of the | 431 | /* Don't evict this BO if it's outside of the |
| 433 | * requested placement range | 432 | * requested placement range |
| 434 | */ | 433 | */ |
| 435 | return ttm_resource_intersects(bdev, res, place, bo->base.size); | 434 | return ttm_resource_intersects(bo->bdev, res, place, bo->base.size); |
| 436 | } | 435 | } |
| 437 | EXPORT_SYMBOL(ttm_bo_eviction_valuable); | 436 | EXPORT_SYMBOL(ttm_bo_eviction_valuable); |
| 438 | 437 | ||
| @@ -1027,7 +1026,7 @@ int ttm_bo_init_validate(struct ttm_device *bdev, struct ttm_buffer_object *bo, · 588 unmodified lines | |||
| 1027 | struct sg_table *sg, struct dma_resv *resv, | 1026 | struct sg_table *sg, struct dma_resv *resv, |
| 1028 | void (*destroy) (struct ttm_buffer_object *)) | 1027 | void (*destroy) (struct ttm_buffer_object *)) |
| 1029 | { | 1028 | { |
| 1030 | struct ttm_operation_ctx ctx = { interruptible, false }; | 1029 | struct ttm_operation_ctx ctx = { .interruptible = interruptible }; |
| 1031 | int ret; | 1030 | int ret; |
| 1032 | 1031 | ||
| 1033 | ret = ttm_bo_init_reserved(bdev, bo, type, placement, alignment, &ctx, | 1032 | ret = ttm_bo_init_reserved(bdev, bo, type, placement, alignment, &ctx, |
| @@ -1108,10 +1107,13 @@ struct ttm_bo_swapout_walk { · 74 unmodified lines | |||
| 1108 | static s64 | 1107 | static s64 |
| 1109 | ttm_bo_swapout_cb(struct ttm_lru_walk *walk, struct ttm_buffer_object *bo) | 1108 | ttm_bo_swapout_cb(struct ttm_lru_walk *walk, struct ttm_buffer_object *bo) |
| 1110 | { | 1109 | { |
| 1111 | struct ttm_place place = {.mem_type = bo->resource->mem_type}; | 1110 | struct ttm_resource *res = bo->resource; |
| 1111 | struct ttm_place place = { .mem_type = res->mem_type }; | ||
| 1112 | struct ttm_bo_swapout_walk *swapout_walk = | 1112 | struct ttm_bo_swapout_walk *swapout_walk = |
| 1113 | container_of(walk, typeof(*swapout_walk), walk); | 1113 | container_of(walk, typeof(*swapout_walk), walk); |
| 1114 | struct ttm_operation_ctx *ctx = walk->arg.ctx; | 1114 | struct ttm_operation_ctx *ctx = walk->arg.ctx; |
| 1115 | struct ttm_device *bdev = bo->bdev; | ||
| 1116 | struct ttm_tt *tt = bo->ttm; | ||
| 1115 | s64 ret; | 1117 | s64 ret; |
| 1116 | 1118 | ||
| 1117 | /* | 1119 | /* |
| @@ -1120,20 +1122,19 @@ ttm_bo_swapout_cb(struct ttm_lru_walk *walk, struct ttm_buffer_object *bo) · 2 unmodified lines | |||
| 1120 | * The driver may use the fact that we're moving from SYSTEM | 1122 | * The driver may use the fact that we're moving from SYSTEM |
| 1121 | * as an indication that we're about to swap out. | 1123 | * as an indication that we're about to swap out. |
| 1122 | */ | 1124 | */ |
| 1123 | if (bo->pin_count || !bo->bdev->funcs->eviction_valuable(bo, &place)) { | 1125 | if (bo->pin_count || !bdev->funcs->eviction_valuable(bo, &place)) { |
| 1124 | ret = -EBUSY; | 1126 | ret = -EBUSY; |
| 1125 | goto out; | 1127 | goto out; |
| 1126 | } | 1128 | } |
| 1127 | 1129 | ||
| 1128 | if (!bo->ttm || !ttm_tt_is_populated(bo->ttm) || | 1130 | if (!tt || !ttm_tt_is_populated(tt) || |
| 1129 | bo->ttm->page_flags & TTM_TT_FLAG_EXTERNAL || | 1131 | tt->page_flags & (TTM_TT_FLAG_EXTERNAL | TTM_TT_FLAG_SWAPPED)) { |
| 1130 | bo->ttm->page_flags & TTM_TT_FLAG_SWAPPED) { | ||
| 1131 | ret = -EBUSY; | 1132 | ret = -EBUSY; |
| 1132 | goto out; | 1133 | goto out; |
| 1133 | } | 1134 | } |
| 1134 | 1135 | ||
| 1135 | if (bo->deleted) { | 1136 | if (bo->deleted) { |
| 1136 | pgoff_t num_pages = bo->ttm->num_pages; | 1137 | pgoff_t num_pages = tt->num_pages; |
| 1137 | 1138 | ||
| 1138 | ret = ttm_bo_wait_ctx(bo, ctx); | 1139 | ret = ttm_bo_wait_ctx(bo, ctx); |
| 1139 | if (ret) | 1140 | if (ret) |
| @@ -1147,7 +1148,7 @@ ttm_bo_swapout_cb(struct ttm_lru_walk *walk, struct ttm_buffer_object *bo) · 7 unmodified lines | |||
| 1147 | /* | 1148 | /* |
| 1148 | * Move to system cached | 1149 | * Move to system cached |
| 1149 | */ | 1150 | */ |
| 1150 | if (bo->resource->mem_type != TTM_PL_SYSTEM) { | 1151 | if (res->mem_type != TTM_PL_SYSTEM) { |
| 1151 | struct ttm_resource *evict_mem; | 1152 | struct ttm_resource *evict_mem; |
| 1152 | struct ttm_place hop; | 1153 | struct ttm_place hop; |
| 1153 | 1154 | ||
| @@ -1174,21 +1175,21 @@ ttm_bo_swapout_cb(struct ttm_lru_walk *walk, struct ttm_buffer_object *bo) · 20 unmodified lines | |||
| 1174 | goto out; | 1175 | goto out; |
| 1175 | 1176 | ||
| 1176 | ttm_bo_unmap_virtual(bo); | 1177 | ttm_bo_unmap_virtual(bo); |
| 1177 | if (bo->bdev->funcs->swap_notify) | 1178 | if (bdev->funcs->swap_notify) |
| 1178 | bo->bdev->funcs->swap_notify(bo); | 1179 | bdev->funcs->swap_notify(bo); |
| 1179 | 1180 | ||
| 1180 | if (ttm_tt_is_populated(bo->ttm)) { | 1181 | if (ttm_tt_is_populated(tt)) { |
| 1181 | spin_lock(&bo->bdev->lru_lock); | 1182 | spin_lock(&bdev->lru_lock); |
| 1182 | ttm_resource_del_bulk_move(bo->resource, bo); | 1183 | ttm_resource_del_bulk_move(res, bo); |
| 1183 | spin_unlock(&bo->bdev->lru_lock); | 1184 | spin_unlock(&bdev->lru_lock); |
| 1184 | 1185 | ||
| 1185 | ret = ttm_tt_swapout(bo->bdev, bo->ttm, swapout_walk->gfp_flags); | 1186 | ret = ttm_tt_swapout(bdev, tt, swapout_walk->gfp_flags); |
| 1186 | 1187 | ||
| 1187 | spin_lock(&bo->bdev->lru_lock); | 1188 | spin_lock(&bdev->lru_lock); |
| 1188 | if (ret) | 1189 | if (ret) |
| 1189 | ttm_resource_add_bulk_move(bo->resource, bo); | 1190 | ttm_resource_add_bulk_move(res, bo); |
| 1190 | ttm_resource_move_to_lru_tail(bo->resource); | 1191 | ttm_resource_move_to_lru_tail(res); |
| 1191 | spin_unlock(&bo->bdev->lru_lock); | 1192 | spin_unlock(&bdev->lru_lock); |
| 1192 | } | 1193 | } |
| 1193 | 1194 | ||
| 1194 | out: | 1195 | out: |
| @@ -1261,6 +1262,7 @@ void ttm_bo_tt_destroy(struct ttm_buffer_object *bo) · 66 unmodified lines | |||
| 1261 | int ttm_bo_populate(struct ttm_buffer_object *bo, | 1262 | int ttm_bo_populate(struct ttm_buffer_object *bo, |
| 1262 | struct ttm_operation_ctx *ctx) | 1263 | struct ttm_operation_ctx *ctx) |
| 1263 | { | 1264 | { |
| 1265 | struct ttm_device *bdev = bo->bdev; | ||
| 1264 | struct ttm_tt *tt = bo->ttm; | 1266 | struct ttm_tt *tt = bo->ttm; |
| 1265 | bool swapped; | 1267 | bool swapped; |
| 1266 | int ret; | 1268 | int ret; |
| @@ -1271,16 +1273,16 @@ int ttm_bo_populate(struct ttm_buffer_object *bo, · 4 unmodified lines | |||
| 1271 | return 0; | 1273 | return 0; |
| 1272 | 1274 | ||
| 1273 | swapped = ttm_tt_is_swapped(tt); | 1275 | swapped = ttm_tt_is_swapped(tt); |
| 1274 | ret = ttm_tt_populate(bo->bdev, tt, ctx); | 1276 | ret = ttm_tt_populate(bdev, tt, ctx); |
| 1275 | if (ret) | 1277 | if (ret) |
| 1276 | return ret; | 1278 | return ret; |
| 1277 | 1279 | ||
| 1278 | if (swapped && !ttm_tt_is_swapped(tt) && !bo->pin_count && | 1280 | if (swapped && !ttm_tt_is_swapped(tt) && !bo->pin_count && |
| 1279 | bo->resource) { | 1281 | bo->resource) { |
| 1280 | spin_lock(&bo->bdev->lru_lock); | 1282 | spin_lock(&bdev->lru_lock); |
| 1281 | ttm_resource_add_bulk_move(bo->resource, bo); | 1283 | ttm_resource_add_bulk_move(bo->resource, bo); |
| 1282 | ttm_resource_move_to_lru_tail(bo->resource); | 1284 | ttm_resource_move_to_lru_tail(bo->resource); |
| 1283 | spin_unlock(&bo->bdev->lru_lock); | 1285 | spin_unlock(&bdev->lru_lock); |
| 1284 | } | 1286 | } |
| 1285 | 1287 | ||
| 1286 | return 0; | 1288 | return 0; |
| @@ -174,13 +174,13 @@ int ttm_bo_move_memcpy(struct ttm_buffer_object *bo, · 173 unmodified lines | |||
| 174 | 174 | ||
| 175 | dst_iter = ttm_kmap_iter_linear_io_init(&_dst_iter.io, bdev, dst_mem); | 175 | dst_iter = ttm_kmap_iter_linear_io_init(&_dst_iter.io, bdev, dst_mem); |
| 176 | if (PTR_ERR(dst_iter) == -EINVAL && dst_man->use_tt) | 176 | if (PTR_ERR(dst_iter) == -EINVAL && dst_man->use_tt) |
| 177 | dst_iter = ttm_kmap_iter_tt_init(&_dst_iter.tt, bo->ttm); | 177 | dst_iter = ttm_kmap_iter_tt_init(&_dst_iter.tt, ttm); |
| 178 | if (IS_ERR(dst_iter)) | 178 | if (IS_ERR(dst_iter)) |
| 179 | return PTR_ERR(dst_iter); | 179 | return PTR_ERR(dst_iter); |
| 180 | 180 | ||
| 181 | src_iter = ttm_kmap_iter_linear_io_init(&_src_iter.io, bdev, src_mem); | 181 | src_iter = ttm_kmap_iter_linear_io_init(&_src_iter.io, bdev, src_mem); |
| 182 | if (PTR_ERR(src_iter) == -EINVAL && src_man->use_tt) | 182 | if (PTR_ERR(src_iter) == -EINVAL && src_man->use_tt) |
| 183 | src_iter = ttm_kmap_iter_tt_init(&_src_iter.tt, bo->ttm); | 183 | src_iter = ttm_kmap_iter_tt_init(&_src_iter.tt, ttm); |
| 184 | if (IS_ERR(src_iter)) { | 184 | if (IS_ERR(src_iter)) { |
| 185 | ret = PTR_ERR(src_iter); | 185 | ret = PTR_ERR(src_iter); |
| 186 | goto out_src_iter; | 186 | goto out_src_iter; |
| @@ -318,11 +318,11 @@ static int ttm_bo_ioremap(struct ttm_buffer_object *bo, · 131 unmodified lines | |||
| 318 | { | 318 | { |
| 319 | struct ttm_resource *mem = bo->resource; | 319 | struct ttm_resource *mem = bo->resource; |
| 320 | 320 | ||
| 321 | if (bo->resource->bus.addr) { | 321 | if (mem->bus.addr) { |
| 322 | map->bo_kmap_type = ttm_bo_map_premapped; | 322 | map->bo_kmap_type = ttm_bo_map_premapped; |
| 323 | map->virtual = ((u8 *)bo->resource->bus.addr) + offset; | 323 | map->virtual = ((u8 *)mem->bus.addr) + offset; |
| 324 | } else { | 324 | } else { |
| 325 | resource_size_t res = bo->resource->bus.offset + offset; | 325 | resource_size_t res = mem->bus.offset + offset; |
| 326 | 326 | ||
| 327 | map->bo_kmap_type = ttm_bo_map_iomap; | 327 | map->bo_kmap_type = ttm_bo_map_iomap; |
| 328 | if (mem->bus.caching == ttm_write_combined) | 328 | if (mem->bus.caching == ttm_write_combined) |
| @@ -343,13 +343,10 @@ static int ttm_bo_kmap_ttm(struct ttm_buffer_object *bo, · 14 unmodified lines | |||
| 343 | struct ttm_bo_kmap_obj *map) | 343 | struct ttm_bo_kmap_obj *map) |
| 344 | { | 344 | { |
| 345 | struct ttm_resource *mem = bo->resource; | 345 | struct ttm_resource *mem = bo->resource; |
| 346 | struct ttm_operation_ctx ctx = { | 346 | struct ttm_operation_ctx ctx = { }; |
| 347 | .interruptible = false, | ||
| 348 | .no_wait_gpu = false | ||
| 349 | }; | ||
| 350 | struct ttm_tt *ttm = bo->ttm; | 347 | struct ttm_tt *ttm = bo->ttm; |
| 351 | struct ttm_resource_manager *man = | 348 | struct ttm_resource_manager *man = |
| 352 | ttm_manager_type(bo->bdev, bo->resource->mem_type); | 349 | ttm_manager_type(bo->bdev, mem->mem_type); |
| 353 | pgprot_t prot; | 350 | pgprot_t prot; |
| 354 | int ret; | 351 | int ret; |
| 355 | 352 | ||
| @@ -428,20 +425,21 @@ int ttm_bo_kmap(struct ttm_buffer_object *bo, · 72 unmodified lines | |||
| 428 | unsigned long start_page, unsigned long num_pages, | 425 | unsigned long start_page, unsigned long num_pages, |
| 429 | struct ttm_bo_kmap_obj *map) | 426 | struct ttm_bo_kmap_obj *map) |
| 430 | { | 427 | { |
| 428 | struct ttm_resource *res = bo->resource; | ||
| 431 | unsigned long offset, size; | 429 | unsigned long offset, size; |
| 432 | int ret; | 430 | int ret; |
| 433 | 431 | ||
| 434 | map->virtual = NULL; | 432 | map->virtual = NULL; |
| 435 | map->bo = bo; | 433 | map->bo = bo; |
| 436 | if (num_pages > PFN_UP(bo->resource->size)) | 434 | if (num_pages > PFN_UP(res->size)) |
| 437 | return -EINVAL; | 435 | return -EINVAL; |
| 438 | if ((start_page + num_pages) > PFN_UP(bo->resource->size)) | 436 | if ((start_page + num_pages) > PFN_UP(res->size)) |
| 439 | return -EINVAL; | 437 | return -EINVAL; |
| 440 | 438 | ||
| 441 | ret = ttm_mem_io_reserve(bo->bdev, bo->resource); | 439 | ret = ttm_mem_io_reserve(bo->bdev, res); |
| 442 | if (ret) | 440 | if (ret) |
| 443 | return ret; | 441 | return ret; |
| 444 | if (!bo->resource->bus.is_iomem) { | 442 | if (!res->bus.is_iomem) { |
| 445 | return ttm_bo_kmap_ttm(bo, start_page, num_pages, map); | 443 | return ttm_bo_kmap_ttm(bo, start_page, num_pages, map); |
| 446 | } else { | 444 | } else { |
| 447 | offset = start_page << PAGE_SHIFT; | 445 | offset = start_page << PAGE_SHIFT; |
| @@ -530,10 +528,7 @@ int ttm_bo_vmap(struct ttm_buffer_object *bo, struct iosys_map *map) · 82 unmodified lines | |||
| 530 | iosys_map_set_vaddr_iomem(map, vaddr_iomem); | 528 | iosys_map_set_vaddr_iomem(map, vaddr_iomem); |
| 531 | 529 | ||
| 532 | } else { | 530 | } else { |
| 533 | struct ttm_operation_ctx ctx = { | 531 | struct ttm_operation_ctx ctx = { }; |
| 534 | .interruptible = false, | ||
| 535 | .no_wait_gpu = false | ||
| 536 | }; | ||
| 537 | struct ttm_tt *ttm = bo->ttm; | 532 | struct ttm_tt *ttm = bo->ttm; |
| 538 | pgprot_t prot; | 533 | pgprot_t prot; |
| 539 | void *vaddr; | 534 | void *vaddr; |
| @@ -581,7 +576,7 @@ void ttm_bo_vunmap(struct ttm_buffer_object *bo, struct iosys_map *map) · 41 unmodified lines | |||
| 581 | iounmap(map->vaddr_iomem); | 576 | iounmap(map->vaddr_iomem); |
| 582 | iosys_map_clear(map); | 577 | iosys_map_clear(map); |
| 583 | 578 | ||
| 584 | ttm_mem_io_free(bo->bdev, bo->resource); | 579 | ttm_mem_io_free(bo->bdev, mem); |
| 585 | } | 580 | } |
| 586 | EXPORT_SYMBOL(ttm_bo_vunmap); | 581 | EXPORT_SYMBOL(ttm_bo_vunmap); |
| 587 | 582 | ||
| @@ -644,12 +639,11 @@ static int ttm_bo_move_to_ghost(struct ttm_buffer_object *bo, · 56 unmodified lines | |||
| 644 | static void ttm_bo_move_pipeline_evict(struct ttm_buffer_object *bo, | 639 | static void ttm_bo_move_pipeline_evict(struct ttm_buffer_object *bo, |
| 645 | struct dma_fence *fence) | 640 | struct dma_fence *fence) |
| 646 | { | 641 | { |
| 647 | struct ttm_device *bdev = bo->bdev; | ||
| 648 | struct ttm_resource_manager *from; | 642 | struct ttm_resource_manager *from; |
| 649 | struct dma_fence *tmp; | 643 | struct dma_fence *tmp; |
| 650 | int i; | 644 | int i; |
| 651 | 645 | ||
| 652 | from = ttm_manager_type(bdev, bo->resource->mem_type); | 646 | from = ttm_manager_type(bo->bdev, bo->resource->mem_type); |
| 653 | 647 | ||
| 654 | /** | 648 | /** |
| 655 | * BO doesn't have a TTM we need to bind/unbind. Just remember | 649 | * BO doesn't have a TTM we need to bind/unbind. Just remember |
| @@ -743,8 +737,8 @@ EXPORT_SYMBOL(ttm_bo_move_accel_cleanup); · 87 unmodified lines | |||
| 743 | void ttm_bo_move_sync_cleanup(struct ttm_buffer_object *bo, | 737 | void ttm_bo_move_sync_cleanup(struct ttm_buffer_object *bo, |
| 744 | struct ttm_resource *new_mem) | 738 | struct ttm_resource *new_mem) |
| 745 | { | 739 | { |
| 746 | struct ttm_device *bdev = bo->bdev; | 740 | struct ttm_resource_manager *man = |
| 747 | struct ttm_resource_manager *man = ttm_manager_type(bdev, new_mem->mem_type); | 741 | ttm_manager_type(bo->bdev, new_mem->mem_type); |
| 748 | int ret; | 742 | int ret; |
| 749 | 743 | ||
| 750 | ret = ttm_bo_wait_free_node(bo, man->use_tt); | 744 | ret = ttm_bo_wait_free_node(bo, man->use_tt); |
| @@ -848,13 +842,12 @@ static int ttm_lru_walk_ticketlock(struct ttm_bo_lru_cursor *curs, · 97 unmodified lines | |||
| 848 | struct ttm_buffer_object *bo) | 842 | struct ttm_buffer_object *bo) |
| 849 | { | 843 | { |
| 850 | struct ttm_lru_walk_arg *arg = curs->arg; | 844 | struct ttm_lru_walk_arg *arg = curs->arg; |
| 851 | struct dma_resv *resv = bo->base.resv; | ||
| 852 | int ret; | 845 | int ret; |
| 853 | 846 | ||
| 854 | if (arg->ctx->interruptible) | 847 | if (arg->ctx->interruptible) |
| 855 | ret = dma_resv_lock_interruptible(resv, arg->ticket); | 848 | ret = dma_resv_lock_interruptible(bo->base.resv, arg->ticket); |
| 856 | else | 849 | else |
| 857 | ret = dma_resv_lock(resv, arg->ticket); | 850 | ret = dma_resv_lock(bo->base.resv, arg->ticket); |
| 858 | 851 | ||
| 859 | if (!ret) { | 852 | if (!ret) { |
| 860 | curs->needs_unlock = true; | 853 | curs->needs_unlock = true; |
| @@ -1098,7 +1091,7 @@ long ttm_bo_shrink(struct ttm_operation_ctx *ctx, struct ttm_buffer_object *bo, · 237 unmodified lines | |||
| 1098 | .num_placement = 1, | 1091 | .num_placement = 1, |
| 1099 | .placement = &sys_placement_flags, | 1092 | .placement = &sys_placement_flags, |
| 1100 | }; | 1093 | }; |
| 1101 | struct ttm_tt *tt = bo->ttm; | 1094 | struct ttm_device *bdev = bo->bdev; |
| 1102 | long lret; | 1095 | long lret; |
| 1103 | 1096 | ||
| 1104 | dma_resv_assert_held(bo->base.resv); | 1097 | dma_resv_assert_held(bo->base.resv); |
| @@ -1120,19 +1113,19 @@ long ttm_bo_shrink(struct ttm_operation_ctx *ctx, struct ttm_buffer_object *bo, · 15 unmodified lines | |||
| 1120 | return lret; | 1113 | return lret; |
| 1121 | 1114 | ||
| 1122 | if (bo->bulk_move) { | 1115 | if (bo->bulk_move) { |
| 1123 | spin_lock(&bo->bdev->lru_lock); | 1116 | spin_lock(&bdev->lru_lock); |
| 1124 | ttm_resource_del_bulk_move(bo->resource, bo); | 1117 | ttm_resource_del_bulk_move(bo->resource, bo); |
| 1125 | spin_unlock(&bo->bdev->lru_lock); | 1118 | spin_unlock(&bdev->lru_lock); |
| 1126 | } | 1119 | } |
| 1127 | 1120 | ||
| 1128 | lret = ttm_tt_backup(bo->bdev, tt, (struct ttm_backup_flags) | 1121 | lret = ttm_tt_backup(bdev, bo->ttm, (struct ttm_backup_flags) |
| 1129 | {.purge = flags.purge, | 1122 | {.purge = flags.purge, |
| 1130 | .writeback = flags.writeback}); | 1123 | .writeback = flags.writeback}); |
| 1131 | 1124 | ||
| 1132 | if (lret <= 0 && bo->bulk_move) { | 1125 | if (lret <= 0 && bo->bulk_move) { |
| 1133 | spin_lock(&bo->bdev->lru_lock); | 1126 | spin_lock(&bdev->lru_lock); |
| 1134 | ttm_resource_add_bulk_move(bo->resource, bo); | 1127 | ttm_resource_add_bulk_move(bo->resource, bo); |
| 1135 | spin_unlock(&bo->bdev->lru_lock); | 1128 | spin_unlock(&bdev->lru_lock); |
| 1136 | } | 1129 | } |
| 1137 | 1130 | ||
| 1138 | if (lret < 0 && lret != -EINTR) | 1131 | if (lret < 0 && lret != -EINTR) |
| @@ -186,7 +186,6 @@ vm_fault_t ttm_bo_vm_fault_reserved(struct vm_fault *vmf, · 185 unmodified lines | |||
| 186 | { | 186 | { |
| 187 | struct vm_area_struct *vma = vmf->vma; | 187 | struct vm_area_struct *vma = vmf->vma; |
| 188 | struct ttm_buffer_object *bo = vma->vm_private_data; | 188 | struct ttm_buffer_object *bo = vma->vm_private_data; |
| 189 | struct ttm_device *bdev = bo->bdev; | ||
| 190 | unsigned long page_offset; | 189 | unsigned long page_offset; |
| 191 | unsigned long page_last; | 190 | unsigned long page_last; |
| 192 | unsigned long pfn; | 191 | unsigned long pfn; |
| @@ -205,7 +204,7 @@ vm_fault_t ttm_bo_vm_fault_reserved(struct vm_fault *vmf, · 12 unmodified lines | |||
| 205 | if (unlikely(ret != 0)) | 204 | if (unlikely(ret != 0)) |
| 206 | return ret; | 205 | return ret; |
| 207 | 206 | ||
| 208 | err = ttm_mem_io_reserve(bdev, bo->resource); | 207 | err = ttm_mem_io_reserve(bo->bdev, bo->resource); |
| 209 | if (unlikely(err != 0)) | 208 | if (unlikely(err != 0)) |
| 210 | return VM_FAULT_SIGBUS; | 209 | return VM_FAULT_SIGBUS; |
| 211 | 210 | ||
| @@ -293,7 +292,6 @@ vm_fault_t ttm_bo_vm_dummy_page(struct vm_fault *vmf, pgprot_t prot) · 81 unmodified lines | |||
| 293 | { | 292 | { |
| 294 | struct vm_area_struct *vma = vmf->vma; | 293 | struct vm_area_struct *vma = vmf->vma; |
| 295 | struct ttm_buffer_object *bo = vma->vm_private_data; | 294 | struct ttm_buffer_object *bo = vma->vm_private_data; |
| 296 | struct drm_device *ddev = bo->base.dev; | ||
| 297 | vm_fault_t ret = VM_FAULT_NOPAGE; | 295 | vm_fault_t ret = VM_FAULT_NOPAGE; |
| 298 | unsigned long address; | 296 | unsigned long address; |
| 299 | unsigned long pfn; | 297 | unsigned long pfn; |
| @@ -305,7 +303,8 @@ vm_fault_t ttm_bo_vm_dummy_page(struct vm_fault *vmf, pgprot_t prot) · 5 unmodified lines | |||
| 305 | return VM_FAULT_OOM; | 303 | return VM_FAULT_OOM; |
| 306 | 304 | ||
| 307 | /* Set the page to be freed using drmm release action */ | 305 | /* Set the page to be freed using drmm release action */ |
| 308 | if (drmm_add_action_or_reset(ddev, ttm_bo_release_dummy_page, page)) | 306 | if (drmm_add_action_or_reset(bo->base.dev, ttm_bo_release_dummy_page, |
| 307 | page)) | ||
| 309 | return VM_FAULT_OOM; | 308 | return VM_FAULT_OOM; |
| 310 | 309 | ||
| 311 | pfn = page_to_pfn(page); | 310 | pfn = page_to_pfn(page); |
| @@ -322,10 +321,9 @@ EXPORT_SYMBOL(ttm_bo_vm_dummy_page); · 10 unmodified lines | |||
| 322 | vm_fault_t ttm_bo_vm_fault(struct vm_fault *vmf) | 321 | vm_fault_t ttm_bo_vm_fault(struct vm_fault *vmf) |
| 323 | { | 322 | { |
| 324 | struct vm_area_struct *vma = vmf->vma; | 323 | struct vm_area_struct *vma = vmf->vma; |
| 325 | pgprot_t prot; | ||
| 326 | struct ttm_buffer_object *bo = vma->vm_private_data; | 324 | struct ttm_buffer_object *bo = vma->vm_private_data; |
| 327 | struct drm_device *ddev = bo->base.dev; | ||
| 328 | vm_fault_t ret; | 325 | vm_fault_t ret; |
| 326 | pgprot_t prot; | ||
| 329 | int idx; | 327 | int idx; |
| 330 | 328 | ||
| 331 | ret = ttm_bo_vm_reserve(bo, vmf); | 329 | ret = ttm_bo_vm_reserve(bo, vmf); |
| @@ -333,7 +331,7 @@ vm_fault_t ttm_bo_vm_fault(struct vm_fault *vmf) · 1 unmodified line | |||
| 333 | return ret; | 331 | return ret; |
| 334 | 332 | ||
| 335 | prot = vma->vm_page_prot; | 333 | prot = vma->vm_page_prot; |
| 336 | if (drm_dev_enter(ddev, &idx)) { | 334 | if (drm_dev_enter(bo->base.dev, &idx)) { |
| 337 | ret = ttm_bo_vm_fault_reserved(vmf, prot, TTM_BO_VM_NUM_PREFAULT); | 335 | ret = ttm_bo_vm_fault_reserved(vmf, prot, TTM_BO_VM_NUM_PREFAULT); |
| 338 | drm_dev_exit(idx); | 336 | drm_dev_exit(idx); |
| 339 | } else { | 337 | } else { |
| @@ -135,10 +135,7 @@ out: · 134 unmodified lines | |||
| 135 | */ | 135 | */ |
| 136 | int ttm_device_prepare_hibernation(struct ttm_device *bdev) | 136 | int ttm_device_prepare_hibernation(struct ttm_device *bdev) |
| 137 | { | 137 | { |
| 138 | struct ttm_operation_ctx ctx = { | 138 | struct ttm_operation_ctx ctx = { }; |
| 139 | .interruptible = false, | ||
| 140 | .no_wait_gpu = false, | ||
| 141 | }; | ||
| 142 | int ret; | 139 | int ret; |
| 143 | 140 | ||
| 144 | do { | 141 | do { |
| @@ -845,32 +845,34 @@ EXPORT_SYMBOL(ttm_pool_alloc); · 844 unmodified lines | |||
| 845 | int ttm_pool_restore_and_alloc(struct ttm_pool *pool, struct ttm_tt *tt, | 845 | int ttm_pool_restore_and_alloc(struct ttm_pool *pool, struct ttm_tt *tt, |
| 846 | const struct ttm_operation_ctx *ctx) | 846 | const struct ttm_operation_ctx *ctx) |
| 847 | { | 847 | { |
| 848 | struct ttm_pool_tt_restore *restore = tt->restore; | ||
| 848 | struct ttm_pool_alloc_state alloc; | 849 | struct ttm_pool_alloc_state alloc; |
| 849 | 850 | ||
| 850 | if (WARN_ON(!ttm_tt_is_backed_up(tt))) | 851 | if (WARN_ON(!ttm_tt_is_backed_up(tt))) |
| 851 | return -EINVAL; | 852 | return -EINVAL; |
| 852 | 853 | ||
| 853 | if (!tt->restore) { | 854 | if (!restore) { |
| 854 | gfp_t gfp = GFP_KERNEL | __GFP_NOWARN; | 855 | gfp_t gfp = GFP_KERNEL | __GFP_NOWARN; |
| 855 | 856 | ||
| 856 | ttm_pool_alloc_state_init(tt, &alloc); | 857 | ttm_pool_alloc_state_init(tt, &alloc); |
| 857 | if (ctx->gfp_retry_mayfail) | 858 | if (ctx->gfp_retry_mayfail) |
| 858 | gfp |= __GFP_RETRY_MAYFAIL; | 859 | gfp |= __GFP_RETRY_MAYFAIL; |
| 859 | 860 | ||
| 860 | tt->restore = kzalloc(sizeof(*tt->restore), gfp); | 861 | restore = kzalloc(sizeof(*restore), gfp); |
| 861 | if (!tt->restore) | 862 | if (!restore) |
| 862 | return -ENOMEM; | 863 | return -ENOMEM; |
| 863 | 864 | ||
| 864 | tt->restore->snapshot_alloc = alloc; | 865 | restore->snapshot_alloc = alloc; |
| 865 | tt->restore->pool = pool; | 866 | restore->pool = pool; |
| 866 | tt->restore->restored_pages = 1; | 867 | restore->restored_pages = 1; |
| 867 | } else { | ||
| 868 | struct ttm_pool_tt_restore *restore = tt->restore; | ||
| 869 | int ret; | ||
| 870 | 868 | ||
| 869 | tt->restore = restore; | ||
| 870 | } else { | ||
| 871 | alloc = restore->snapshot_alloc; | 871 | alloc = restore->snapshot_alloc; |
| 872 | if (ttm_pool_restore_valid(tt->restore)) { | 872 | if (ttm_pool_restore_valid(restore)) { |
| 873 | ret = ttm_pool_restore_commit(restore, tt->backup, ctx, &alloc); | 873 | int ret = ttm_pool_restore_commit(restore, tt->backup, |
| 874 | ctx, &alloc); | ||
| 875 | |||
| 874 | if (ret) | 876 | if (ret) |
| 875 | return ret; | 877 | return ret; |
| 876 | } | 878 | } |
| @@ -878,7 +880,7 @@ int ttm_pool_restore_and_alloc(struct ttm_pool *pool, struct ttm_tt *tt, · 1 unmodified line | |||
| 878 | return 0; | 880 | return 0; |
| 879 | } | 881 | } |
| 880 | 882 | ||
| 881 | return __ttm_pool_alloc(pool, tt, ctx, &alloc, tt->restore); | 883 | return __ttm_pool_alloc(pool, tt, ctx, &alloc, restore); |
| 882 | } | 884 | } |
| 883 | 885 | ||
| 884 | /** | 886 | /** |
| @@ -446,9 +446,6 @@ bool ttm_resource_intersects(struct ttm_device *bdev, · 445 unmodified lines | |||
| 446 | { | 446 | { |
| 447 | struct ttm_resource_manager *man; | 447 | struct ttm_resource_manager *man; |
| 448 | 448 | ||
| 449 | if (!res) | ||
| 450 | return false; | ||
| 451 | |||
| 452 | man = ttm_manager_type(bdev, res->mem_type); | 449 | man = ttm_manager_type(bdev, res->mem_type); |
| 453 | if (!place || !man->func->intersects) | 450 | if (!place || !man->func->intersects) |
| 454 | return true; | 451 | return true; |
| @@ -548,10 +545,7 @@ EXPORT_SYMBOL(ttm_resource_manager_init); · 93 unmodified lines | |||
| 548 | int ttm_resource_manager_evict_all(struct ttm_device *bdev, | 545 | int ttm_resource_manager_evict_all(struct ttm_device *bdev, |
| 549 | struct ttm_resource_manager *man) | 546 | struct ttm_resource_manager *man) |
| 550 | { | 547 | { |
| 551 | struct ttm_operation_ctx ctx = { | 548 | struct ttm_operation_ctx ctx = { }; |
| 552 | .interruptible = false, | ||
| 553 | .no_wait_gpu = false, | ||
| 554 | }; | ||
| 555 | struct dma_fence *fence; | 549 | struct dma_fence *fence; |
| 556 | int ret, i; | 550 | int ret, i; |
| 557 | 551 | ||
| @@ -628,11 +622,11 @@ ttm_resource_cursor_check_bulk(struct ttm_resource_cursor *cursor, · 70 unmodified lines | |||
| 628 | struct ttm_lru_item *next_lru) | 622 | struct ttm_lru_item *next_lru) |
| 629 | { | 623 | { |
| 630 | struct ttm_resource *next = ttm_lru_item_to_res(next_lru); | 624 | struct ttm_resource *next = ttm_lru_item_to_res(next_lru); |
| 631 | struct ttm_lru_bulk_move *bulk = NULL; | 625 | struct ttm_lru_bulk_move *bulk; |
| 632 | struct ttm_buffer_object *bo = next->bo; | ||
| 633 | 626 | ||
| 634 | lockdep_assert_held(&cursor->man->bdev->lru_lock); | 627 | lockdep_assert_held(&cursor->man->bdev->lru_lock); |
| 635 | bulk = bo->bulk_move; | 628 | |
| 629 | bulk = next->bo->bulk_move; | ||
| 636 | 630 | ||
| 637 | if (cursor->bulk != bulk) { | 631 | if (cursor->bulk != bulk) { |
| 638 | if (bulk) { | 632 | if (bulk) { |
| @@ -456,7 +456,7 @@ EXPORT_SYMBOL_FOR_TESTS_ONLY(ttm_tt_unpopulate); · 455 unmodified lines | |||
| 456 | /* Test the shrinker functions and dump the result */ | 456 | /* Test the shrinker functions and dump the result */ |
| 457 | static int ttm_tt_debugfs_shrink_show(struct seq_file *m, void *data) | 457 | static int ttm_tt_debugfs_shrink_show(struct seq_file *m, void *data) |
| 458 | { | 458 | { |
| 459 | struct ttm_operation_ctx ctx = { false, false }; | 459 | struct ttm_operation_ctx ctx = { }; |
| 460 | 460 | ||
| 461 | seq_printf(m, "%d\n", ttm_global_swapout(&ctx, GFP_KERNEL)); | 461 | seq_printf(m, "%d\n", ttm_global_swapout(&ctx, GFP_KERNEL)); |
| 462 | return 0; | 462 | return 0; |
| @@ -13,8 +13,7 @@ v3d-y := \ · 12 unmodified lines | |||
| 13 | v3d_trace_points.o \ | 13 | v3d_trace_points.o \ |
| 14 | v3d_sched.o \ | 14 | v3d_sched.o \ |
| 15 | v3d_sysfs.o \ | 15 | v3d_sysfs.o \ |
| 16 | v3d_submit.o \ | 16 | v3d_submit.o |
| 17 | v3d_gemfs.o | ||
| 18 | 17 | ||
| 19 | v3d-$(CONFIG_DEBUG_FS) += v3d_debugfs.o | 18 | v3d-$(CONFIG_DEBUG_FS) += v3d_debugfs.o |
| 20 | 19 | ||
| @@ -114,7 +114,7 @@ v3d_bo_create_finish(struct drm_gem_object *obj) · 113 unmodified lines | |||
| 114 | if (IS_ERR(sgt)) | 114 | if (IS_ERR(sgt)) |
| 115 | return PTR_ERR(sgt); | 115 | return PTR_ERR(sgt); |
| 116 | 116 | ||
| 117 | if (!v3d->gemfs) | 117 | if (!drm_gem_get_huge_mnt(obj->dev)) |
| 118 | align = SZ_4K; | 118 | align = SZ_4K; |
| 119 | else if (obj->size >= SZ_1M) | 119 | else if (obj->size >= SZ_1M) |
| 120 | align = SZ_1M; | 120 | align = SZ_1M; |
| @@ -150,12 +150,10 @@ struct v3d_bo *v3d_bo_create(struct drm_device *dev, struct drm_file *file_priv, · 29 unmodified lines | |||
| 150 | size_t unaligned_size) | 150 | size_t unaligned_size) |
| 151 | { | 151 | { |
| 152 | struct drm_gem_shmem_object *shmem_obj; | 152 | struct drm_gem_shmem_object *shmem_obj; |
| 153 | struct v3d_dev *v3d = to_v3d_dev(dev); | ||
| 154 | struct v3d_bo *bo; | 153 | struct v3d_bo *bo; |
| 155 | int ret; | 154 | int ret; |
| 156 | 155 | ||
| 157 | shmem_obj = drm_gem_shmem_create_with_mnt(dev, unaligned_size, | 156 | shmem_obj = drm_gem_shmem_create(dev, unaligned_size); |
| 158 | v3d->gemfs); | ||
| 159 | if (IS_ERR(shmem_obj)) | 157 | if (IS_ERR(shmem_obj)) |
| 160 | return ERR_CAST(shmem_obj); | 158 | return ERR_CAST(shmem_obj); |
| 161 | bo = to_v3d_bo(&shmem_obj->base); | 159 | bo = to_v3d_bo(&shmem_obj->base); |
| @@ -107,7 +107,7 @@ static int v3d_get_param_ioctl(struct drm_device *dev, void *data, · 106 unmodified lines | |||
| 107 | args->value = v3d->perfmon_info.max_counters; | 107 | args->value = v3d->perfmon_info.max_counters; |
| 108 | return 0; | 108 | return 0; |
| 109 | case DRM_V3D_PARAM_SUPPORTS_SUPER_PAGES: | 109 | case DRM_V3D_PARAM_SUPPORTS_SUPER_PAGES: |
| 110 | args->value = !!v3d->gemfs; | 110 | args->value = !!drm_gem_get_huge_mnt(dev); |
| 111 | return 0; | 111 | return 0; |
| 112 | case DRM_V3D_PARAM_GLOBAL_RESET_COUNTER: | 112 | case DRM_V3D_PARAM_GLOBAL_RESET_COUNTER: |
| 113 | mutex_lock(&v3d->reset_lock); | 113 | mutex_lock(&v3d->reset_lock); |
| @@ -158,11 +158,6 @@ struct v3d_dev { · 157 unmodified lines | |||
| 158 | struct drm_mm mm; | 158 | struct drm_mm mm; |
| 159 | spinlock_t mm_lock; | 159 | spinlock_t mm_lock; |
| 160 | 160 | ||
| 161 | /* | ||
| 162 | * tmpfs instance used for shmem backed objects | ||
| 163 | */ | ||
| 164 | struct vfsmount *gemfs; | ||
| 165 | |||
| 166 | struct work_struct overflow_mem_work; | 161 | struct work_struct overflow_mem_work; |
| 167 | 162 | ||
| 168 | struct v3d_queue_state queue[V3D_MAX_QUEUES]; | 163 | struct v3d_queue_state queue[V3D_MAX_QUEUES]; |
| @@ -569,6 +564,7 @@ extern const struct dma_fence_ops v3d_fence_ops; · 400 unmodified lines | |||
| 569 | struct dma_fence *v3d_fence_create(struct v3d_dev *v3d, enum v3d_queue q); | 564 | struct dma_fence *v3d_fence_create(struct v3d_dev *v3d, enum v3d_queue q); |
| 570 | 565 | ||
| 571 | /* v3d_gem.c */ | 566 | /* v3d_gem.c */ |
| 567 | extern bool super_pages; | ||
| 572 | int v3d_gem_init(struct drm_device *dev); | 568 | int v3d_gem_init(struct drm_device *dev); |
| 573 | void v3d_gem_destroy(struct drm_device *dev); | 569 | void v3d_gem_destroy(struct drm_device *dev); |
| 574 | void v3d_reset_sms(struct v3d_dev *v3d); | 570 | void v3d_reset_sms(struct v3d_dev *v3d); |
| @@ -576,11 +572,6 @@ void v3d_reset(struct v3d_dev *v3d); · 1 unmodified line | |||
| 576 | void v3d_invalidate_caches(struct v3d_dev *v3d); | 572 | void v3d_invalidate_caches(struct v3d_dev *v3d); |
| 577 | void v3d_clean_caches(struct v3d_dev *v3d); | 573 | void v3d_clean_caches(struct v3d_dev *v3d); |
| 578 | 574 | ||
| 579 | /* v3d_gemfs.c */ | ||
| 580 | extern bool super_pages; | ||
| 581 | void v3d_gemfs_init(struct v3d_dev *v3d); | ||
| 582 | void v3d_gemfs_fini(struct v3d_dev *v3d); | ||
| 583 | |||
| 584 | /* v3d_submit.c */ | 575 | /* v3d_submit.c */ |
| 585 | void v3d_job_cleanup(struct v3d_job *job); | 576 | void v3d_job_cleanup(struct v3d_job *job); |
| 586 | void v3d_job_put(struct v3d_job *job); | 577 | void v3d_job_put(struct v3d_job *job); |
| @@ -259,6 +259,24 @@ v3d_invalidate_caches(struct v3d_dev *v3d) · 258 unmodified lines | |||
| 259 | v3d_invalidate_slices(v3d, 0); | 259 | v3d_invalidate_slices(v3d, 0); |
| 260 | } | 260 | } |
| 261 | 261 | ||
| 262 | static void | ||
| 263 | v3d_huge_mnt_init(struct v3d_dev *v3d) | ||
| 264 | { | ||
| 265 | int err = 0; | ||
| 266 | |||
| 267 | if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) && super_pages) | ||
| 268 | err = drm_gem_huge_mnt_create(&v3d->drm, "within_size"); | ||
| 269 | |||
| 270 | if (drm_gem_get_huge_mnt(&v3d->drm)) | ||
| 271 | drm_info(&v3d->drm, "Using Transparent Hugepages\n"); | ||
| 272 | else if (err) | ||
| 273 | drm_warn(&v3d->drm, "Can't use Transparent Hugepages (%d)\n", | ||
| 274 | err); | ||
| 275 | else | ||
| 276 | drm_notice(&v3d->drm, | ||
| 277 | "Transparent Hugepage support is recommended for optimal performance on this platform!\n"); | ||
| 278 | } | ||
| 279 | |||
| 262 | int | 280 | int |
| 263 | v3d_gem_init(struct drm_device *dev) | 281 | v3d_gem_init(struct drm_device *dev) |
| 264 | { | 282 | { |
| @@ -310,7 +328,7 @@ v3d_gem_init(struct drm_device *dev) · 45 unmodified lines | |||
| 310 | v3d_init_hw_state(v3d); | 328 | v3d_init_hw_state(v3d); |
| 311 | v3d_mmu_set_page_table(v3d); | 329 | v3d_mmu_set_page_table(v3d); |
| 312 | 330 | ||
| 313 | v3d_gemfs_init(v3d); | 331 | v3d_huge_mnt_init(v3d); |
| 314 | 332 | ||
| 315 | ret = v3d_sched_init(v3d); | 333 | ret = v3d_sched_init(v3d); |
| 316 | if (ret) { | 334 | if (ret) { |
| @@ -330,7 +348,6 @@ v3d_gem_destroy(struct drm_device *dev) · 13 unmodified lines | |||
| 330 | enum v3d_queue q; | 348 | enum v3d_queue q; |
| 331 | 349 | ||
| 332 | v3d_sched_fini(v3d); | 350 | v3d_sched_fini(v3d); |
| 333 | v3d_gemfs_fini(v3d); | ||
| 334 | 351 | ||
| 335 | /* Waiting for jobs to finish would need to be done before | 352 | /* Waiting for jobs to finish would need to be done before |
| 336 | * unregistering V3D. | 353 | * unregistering V3D. |
| @@ -1,62 +0,0 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0+ | ||
| 2 | /* Copyright (C) 2024 Raspberry Pi */ | ||
| 3 | |||
| 4 | #include <linux/fs.h> | ||
| 5 | #include <linux/mount.h> | ||
| 6 | #include <linux/fs_context.h> | ||
| 7 | |||
| 8 | #include <drm/drm_print.h> | ||
| 9 | |||
| 10 | #include "v3d_drv.h" | ||
| 11 | |||
| 12 | void v3d_gemfs_init(struct v3d_dev *v3d) | ||
| 13 | { | ||
| 14 | struct file_system_type *type; | ||
| 15 | struct fs_context *fc; | ||
| 16 | struct vfsmount *gemfs; | ||
| 17 | int ret; | ||
| 18 | |||
| 19 | /* | ||
| 20 | * By creating our own shmemfs mountpoint, we can pass in | ||
| 21 | * mount flags that better match our usecase. However, we | ||
| 22 | * only do so on platforms which benefit from it. | ||
| 23 | */ | ||
| 24 | if (!IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) | ||
| 25 | goto err; | ||
| 26 | |||
| 27 | /* The user doesn't want to enable Super Pages */ | ||
| 28 | if (!super_pages) | ||
| 29 | goto err; | ||
| 30 | |||
| 31 | type = get_fs_type("tmpfs"); | ||
| 32 | if (!type) | ||
| 33 | goto err; | ||
| 34 | |||
| 35 | fc = fs_context_for_mount(type, SB_KERNMOUNT); | ||
| 36 | if (IS_ERR(fc)) | ||
| 37 | goto err; | ||
| 38 | ret = vfs_parse_fs_string(fc, "source", "tmpfs"); | ||
| 39 | if (!ret) | ||
| 40 | ret = vfs_parse_fs_string(fc, "huge", "within_size"); | ||
| 41 | if (!ret) | ||
| 42 | gemfs = fc_mount_longterm(fc); | ||
| 43 | put_fs_context(fc); | ||
| 44 | if (ret) | ||
| 45 | goto err; | ||
| 46 | |||
| 47 | v3d->gemfs = gemfs; | ||
| 48 | drm_info(&v3d->drm, "Using Transparent Hugepages\n"); | ||
| 49 | |||
| 50 | return; | ||
| 51 | |||
| 52 | err: | ||
| 53 | v3d->gemfs = NULL; | ||
| 54 | drm_notice(&v3d->drm, | ||
| 55 | "Transparent Hugepage support is recommended for optimal performance on this platform!\n"); | ||
| 56 | } | ||
| 57 | |||
| 58 | void v3d_gemfs_fini(struct v3d_dev *v3d) | ||
| 59 | { | ||
| 60 | if (v3d->gemfs) | ||
| 61 | kern_unmount(v3d->gemfs); | ||
| 62 | } | ||
| @@ -0,0 +1,9 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0-only | ||
| 2 | config DRM_VGEM | ||
| 3 | tristate "Virtual GEM provider" | ||
| 4 | depends on DRM && MMU | ||
| 5 | select DRM_GEM_SHMEM_HELPER | ||
| 6 | help | ||
| 7 | Choose this option to get a virtual graphics memory manager, | ||
| 8 | as used by Mesa's software renderer for enhanced performance. | ||
| 9 | If M is selected the module will be called vgem. | ||
| @@ -85,7 +85,6 @@ void xe_hw_fence_irq_finish(struct xe_hw_fence_irq *irq) · 84 unmodified lines | |||
| 85 | { | 85 | { |
| 86 | struct xe_hw_fence *fence, *next; | 86 | struct xe_hw_fence *fence, *next; |
| 87 | unsigned long flags; | 87 | unsigned long flags; |
| 88 | int err; | ||
| 89 | bool tmp; | 88 | bool tmp; |
| 90 | 89 | ||
| 91 | if (XE_WARN_ON(!list_empty(&irq->pending))) { | 90 | if (XE_WARN_ON(!list_empty(&irq->pending))) { |
| @@ -93,9 +92,8 @@ void xe_hw_fence_irq_finish(struct xe_hw_fence_irq *irq) · 1 unmodified line | |||
| 93 | spin_lock_irqsave(&irq->lock, flags); | 92 | spin_lock_irqsave(&irq->lock, flags); |
| 94 | list_for_each_entry_safe(fence, next, &irq->pending, irq_link) { | 93 | list_for_each_entry_safe(fence, next, &irq->pending, irq_link) { |
| 95 | list_del_init(&fence->irq_link); | 94 | list_del_init(&fence->irq_link); |
| 96 | err = dma_fence_signal_locked(&fence->dma); | 95 | XE_WARN_ON(dma_fence_check_and_signal_locked(&fence->dma)); |
| 97 | dma_fence_put(&fence->dma); | 96 | dma_fence_put(&fence->dma); |
| 98 | XE_WARN_ON(err); | ||
| 99 | } | 97 | } |
| 100 | spin_unlock_irqrestore(&irq->lock, flags); | 98 | spin_unlock_irqrestore(&irq->lock, flags); |
| 101 | dma_fence_end_signalling(tmp); | 99 | dma_fence_end_signalling(tmp); |
| @@ -2289,28 +2289,6 @@ static bool fbcon_blank(struct vc_data *vc, enum vesa_blank_mode blank, · 2288 unmodified lines | |||
| 2289 | return false; | 2289 | return false; |
| 2290 | } | 2290 | } |
| 2291 | 2291 | ||
| 2292 | static void fbcon_debug_enter(struct vc_data *vc) | ||
| 2293 | { | ||
| 2294 | struct fb_info *info = fbcon_info_from_console(vc->vc_num); | ||
| 2295 | struct fbcon_par *par = info->fbcon_par; | ||
| 2296 | |||
| 2297 | par->save_graphics = par->graphics; | ||
| 2298 | par->graphics = 0; | ||
| 2299 | if (info->fbops->fb_debug_enter) | ||
| 2300 | info->fbops->fb_debug_enter(info); | ||
| 2301 | fbcon_set_palette(vc, color_table); | ||
| 2302 | } | ||
| 2303 | |||
| 2304 | static void fbcon_debug_leave(struct vc_data *vc) | ||
| 2305 | { | ||
| 2306 | struct fb_info *info = fbcon_info_from_console(vc->vc_num); | ||
| 2307 | struct fbcon_par *par = info->fbcon_par; | ||
| 2308 | |||
| 2309 | par->graphics = par->save_graphics; | ||
| 2310 | if (info->fbops->fb_debug_leave) | ||
| 2311 | info->fbops->fb_debug_leave(info); | ||
| 2312 | } | ||
| 2313 | |||
| 2314 | static int fbcon_get_font(struct vc_data *vc, struct console_font *font, unsigned int vpitch) | 2292 | static int fbcon_get_font(struct vc_data *vc, struct console_font *font, unsigned int vpitch) |
| 2315 | { | 2293 | { |
| 2316 | u8 *fontdata = vc->vc_font.data; | 2294 | u8 *fontdata = vc->vc_font.data; |
| @@ -3214,8 +3192,6 @@ static const struct consw fb_con = { · 897 unmodified lines | |||
| 3214 | .con_set_palette = fbcon_set_palette, | 3192 | .con_set_palette = fbcon_set_palette, |
| 3215 | .con_invert_region = fbcon_invert_region, | 3193 | .con_invert_region = fbcon_invert_region, |
| 3216 | .con_resize = fbcon_resize, | 3194 | .con_resize = fbcon_resize, |
| 3217 | .con_debug_enter = fbcon_debug_enter, | ||
| 3218 | .con_debug_leave = fbcon_debug_leave, | ||
| 3219 | }; | 3195 | }; |
| 3220 | 3196 | ||
| 3221 | static ssize_t rotate_store(struct device *device, | 3197 | static ssize_t rotate_store(struct device *device, |
| @@ -79,7 +79,6 @@ struct fbcon_par { · 78 unmodified lines | |||
| 79 | int cursor_reset; | 79 | int cursor_reset; |
| 80 | int blank_state; | 80 | int blank_state; |
| 81 | int graphics; | 81 | int graphics; |
| 82 | int save_graphics; /* for debug enter/leave */ | ||
| 83 | bool initialized; | 82 | bool initialized; |
| 84 | int rotate; | 83 | int rotate; |
| 85 | int cur_rotate; | 84 | int cur_rotate; |
| @@ -339,6 +339,11 @@ struct drm_private_state_funcs { · 338 unmodified lines | |||
| 339 | * drm_atomic_helper_wait_for_dependencies(). | 339 | * drm_atomic_helper_wait_for_dependencies(). |
| 340 | */ | 340 | */ |
| 341 | struct drm_private_obj { | 341 | struct drm_private_obj { |
| 342 | /** | ||
| 343 | * @dev: parent DRM device | ||
| 344 | */ | ||
| 345 | struct drm_device *dev; | ||
| 346 | |||
| 342 | /** | 347 | /** |
| 343 | * @head: List entry used to attach a private object to a &drm_device | 348 | * @head: List entry used to attach a private object to a &drm_device |
| 344 | * (queued to &drm_mode_config.privobj_list). | 349 | * (queued to &drm_mode_config.privobj_list). |
| @@ -1143,6 +1143,14 @@ struct drm_bridge { · 1142 unmodified lines | |||
| 1143 | */ | 1143 | */ |
| 1144 | struct kref refcount; | 1144 | struct kref refcount; |
| 1145 | 1145 | ||
| 1146 | /** | ||
| 1147 | * @unplugged: | ||
| 1148 | * | ||
| 1149 | * Flag to tell if the bridge has been unplugged. | ||
| 1150 | * See drm_bridge_enter() and drm_bridge_unplug(). | ||
| 1151 | */ | ||
| 1152 | bool unplugged; | ||
| 1153 | |||
| 1146 | /** @driver_private: pointer to the bridge driver's internal context */ | 1154 | /** @driver_private: pointer to the bridge driver's internal context */ |
| 1147 | void *driver_private; | 1155 | void *driver_private; |
| 1148 | /** @ops: bitmask of operations supported by the bridge */ | 1156 | /** @ops: bitmask of operations supported by the bridge */ |
| @@ -1278,6 +1286,10 @@ drm_priv_to_bridge(struct drm_private_obj *priv) · 129 unmodified lines | |||
| 1278 | return container_of(priv, struct drm_bridge, base); | 1286 | return container_of(priv, struct drm_bridge, base); |
| 1279 | } | 1287 | } |
| 1280 | 1288 | ||
| 1289 | bool drm_bridge_enter(struct drm_bridge *bridge, int *idx); | ||
| 1290 | void drm_bridge_exit(int idx); | ||
| 1291 | void drm_bridge_unplug(struct drm_bridge *bridge); | ||
| 1292 | |||
| 1281 | struct drm_bridge *drm_bridge_get(struct drm_bridge *bridge); | 1293 | struct drm_bridge *drm_bridge_get(struct drm_bridge *bridge); |
| 1282 | void drm_bridge_put(struct drm_bridge *bridge); | 1294 | void drm_bridge_put(struct drm_bridge *bridge); |
| 1283 | 1295 | ||
| @@ -3,6 +3,9 @@ · 2 unmodified lines | |||
| 3 | 3 | ||
| 4 | #include <linux/list.h> | 4 | #include <linux/list.h> |
| 5 | #include <linux/kref.h> | 5 | #include <linux/kref.h> |
| 6 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE | ||
| 7 | #include <linux/mount.h> | ||
| 8 | #endif | ||
| 6 | #include <linux/mutex.h> | 9 | #include <linux/mutex.h> |
| 7 | #include <linux/idr.h> | 10 | #include <linux/idr.h> |
| 8 | #include <linux/sched.h> | 11 | #include <linux/sched.h> |
| @@ -168,6 +171,18 @@ struct drm_device { · 159 unmodified lines | |||
| 168 | */ | 171 | */ |
| 169 | struct drm_master *master; | 172 | struct drm_master *master; |
| 170 | 173 | ||
| 174 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE | ||
| 175 | /** | ||
| 176 | * @huge_mnt: | ||
| 177 | * | ||
| 178 | * Huge tmpfs mountpoint used at GEM object initialization | ||
| 179 | * drm_gem_object_init(). Drivers can call drm_gem_huge_mnt_create() to | ||
| 180 | * create, mount and use it. The default tmpfs mountpoint (`shm_mnt`) is | ||
| 181 | * used if NULL. | ||
| 182 | */ | ||
| 183 | struct vfsmount *huge_mnt; | ||
| 184 | #endif | ||
| 185 | |||
| 171 | /** | 186 | /** |
| 172 | * @driver_features: per-device driver features | 187 | * @driver_features: per-device driver features |
| 173 | * | 188 | * |
| @@ -166,13 +166,6 @@ struct drm_fb_helper { · 165 unmodified lines | |||
| 166 | */ | 166 | */ |
| 167 | struct mutex lock; | 167 | struct mutex lock; |
| 168 | 168 | ||
| 169 | /** | ||
| 170 | * @kernel_fb_list: | ||
| 171 | * | ||
| 172 | * Entry on the global kernel_fb_helper_list, used for kgdb entry/exit. | ||
| 173 | */ | ||
| 174 | struct list_head kernel_fb_list; | ||
| 175 | |||
| 176 | /** | 169 | /** |
| 177 | * @delayed_hotplug: | 170 | * @delayed_hotplug: |
| 178 | * | 171 | * |
| @@ -236,8 +229,6 @@ drm_fb_helper_from_client(struct drm_client_dev *client) · 57 unmodified lines | |||
| 236 | .fb_setcmap = drm_fb_helper_setcmap, \ | 229 | .fb_setcmap = drm_fb_helper_setcmap, \ |
| 237 | .fb_blank = drm_fb_helper_blank, \ | 230 | .fb_blank = drm_fb_helper_blank, \ |
| 238 | .fb_pan_display = drm_fb_helper_pan_display, \ | 231 | .fb_pan_display = drm_fb_helper_pan_display, \ |
| 239 | .fb_debug_enter = drm_fb_helper_debug_enter, \ | ||
| 240 | .fb_debug_leave = drm_fb_helper_debug_leave, \ | ||
| 241 | .fb_ioctl = drm_fb_helper_ioctl | 232 | .fb_ioctl = drm_fb_helper_ioctl |
| 242 | 233 | ||
| 243 | #ifdef CONFIG_DRM_FBDEV_EMULATION | 234 | #ifdef CONFIG_DRM_FBDEV_EMULATION |
| @@ -280,8 +271,6 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd, · 36 unmodified lines | |||
| 280 | 271 | ||
| 281 | int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper); | 272 | int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper); |
| 282 | int drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper); | 273 | int drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper); |
| 283 | int drm_fb_helper_debug_enter(struct fb_info *info); | ||
| 284 | int drm_fb_helper_debug_leave(struct fb_info *info); | ||
| 285 | #else | 274 | #else |
| 286 | static inline void drm_fb_helper_prepare(struct drm_device *dev, | 275 | static inline void drm_fb_helper_prepare(struct drm_device *dev, |
| 287 | struct drm_fb_helper *helper, | 276 | struct drm_fb_helper *helper, |
| @@ -387,16 +376,6 @@ static inline int drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper) · 99 unmodified lines | |||
| 387 | { | 376 | { |
| 388 | return 0; | 377 | return 0; |
| 389 | } | 378 | } |
| 390 | |||
| 391 | static inline int drm_fb_helper_debug_enter(struct fb_info *info) | ||
| 392 | { | ||
| 393 | return 0; | ||
| 394 | } | ||
| 395 | |||
| 396 | static inline int drm_fb_helper_debug_leave(struct fb_info *info) | ||
| 397 | { | ||
| 398 | return 0; | ||
| 399 | } | ||
| 400 | #endif | 379 | #endif |
| 401 | 380 | ||
| 402 | #endif | 381 | #endif |
| @@ -40,6 +40,9 @@ · 39 unmodified lines | |||
| 40 | #include <linux/list.h> | 40 | #include <linux/list.h> |
| 41 | #include <linux/mutex.h> | 41 | #include <linux/mutex.h> |
| 42 | 42 | ||
| 43 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE | ||
| 44 | #include <drm/drm_device.h> | ||
| 45 | #endif | ||
| 43 | #include <drm/drm_vma_manager.h> | 46 | #include <drm/drm_vma_manager.h> |
| 44 | 47 | ||
| 45 | struct iosys_map; | 48 | struct iosys_map; |
| @@ -469,6 +472,7 @@ struct drm_gem_object { · 423 unmodified lines | |||
| 469 | .poll = drm_poll,\ | 472 | .poll = drm_poll,\ |
| 470 | .read = drm_read,\ | 473 | .read = drm_read,\ |
| 471 | .llseek = noop_llseek,\ | 474 | .llseek = noop_llseek,\ |
| 475 | .get_unmapped_area = drm_gem_get_unmapped_area,\ | ||
| 472 | .mmap = drm_gem_mmap, \ | 476 | .mmap = drm_gem_mmap, \ |
| 473 | .fop_flags = FOP_UNSIGNED_OFFSET | 477 | .fop_flags = FOP_UNSIGNED_OFFSET |
| 474 | 478 | ||
| @@ -491,13 +495,40 @@ struct drm_gem_object { · 16 unmodified lines | |||
| 491 | DRM_GEM_FOPS,\ | 495 | DRM_GEM_FOPS,\ |
| 492 | } | 496 | } |
| 493 | 497 | ||
| 498 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE | ||
| 499 | int drm_gem_huge_mnt_create(struct drm_device *dev, const char *value); | ||
| 500 | #else | ||
| 501 | static inline int drm_gem_huge_mnt_create(struct drm_device *dev, | ||
| 502 | const char *value) | ||
| 503 | { | ||
| 504 | return 0; | ||
| 505 | } | ||
| 506 | #endif | ||
| 507 | |||
| 508 | /** | ||
| 509 | * drm_gem_get_huge_mnt - Get the huge tmpfs mountpoint used by a DRM device | ||
| 510 | * @dev: DRM device | ||
| 511 | |||
| 512 | * This function gets the huge tmpfs mountpoint used by DRM device @dev. A huge | ||
| 513 | * tmpfs mountpoint is used instead of `shm_mnt` after a successful call to | ||
| 514 | * drm_gem_huge_mnt_create() when CONFIG_TRANSPARENT_HUGEPAGE is enabled. | ||
| 515 | |||
| 516 | * Returns: | ||
| 517 | * The huge tmpfs mountpoint in use, NULL otherwise. | ||
| 518 | */ | ||
| 519 | static inline struct vfsmount *drm_gem_get_huge_mnt(struct drm_device *dev) | ||
| 520 | { | ||
| 521 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE | ||
| 522 | return dev->huge_mnt; | ||
| 523 | #else | ||
| 524 | return NULL; | ||
| 525 | #endif | ||
| 526 | } | ||
| 527 | |||
| 494 | void drm_gem_object_release(struct drm_gem_object *obj); | 528 | void drm_gem_object_release(struct drm_gem_object *obj); |
| 495 | void drm_gem_object_free(struct kref *kref); | 529 | void drm_gem_object_free(struct kref *kref); |
| 496 | int drm_gem_object_init(struct drm_device *dev, | 530 | int drm_gem_object_init(struct drm_device *dev, |
| 497 | struct drm_gem_object *obj, size_t size); | 531 | struct drm_gem_object *obj, size_t size); |
| 498 | int drm_gem_object_init_with_mnt(struct drm_device *dev, | ||
| 499 | struct drm_gem_object *obj, size_t size, | ||
| 500 | struct vfsmount *gemfs); | ||
| 501 | void drm_gem_private_object_init(struct drm_device *dev, | 532 | void drm_gem_private_object_init(struct drm_device *dev, |
| 502 | struct drm_gem_object *obj, size_t size); | 533 | struct drm_gem_object *obj, size_t size); |
| 503 | void drm_gem_private_object_fini(struct drm_gem_object *obj); | 534 | void drm_gem_private_object_fini(struct drm_gem_object *obj); |
| @@ -507,6 +538,14 @@ int drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size, · 3 unmodified lines | |||
| 507 | struct vm_area_struct *vma); | 538 | struct vm_area_struct *vma); |
| 508 | int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma); | 539 | int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma); |
| 509 | 540 | ||
| 541 | #ifdef CONFIG_MMU | ||
| 542 | unsigned long drm_gem_get_unmapped_area(struct file *filp, unsigned long uaddr, | ||
| 543 | unsigned long len, unsigned long pgoff, | ||
| 544 | unsigned long flags); | ||
| 545 | #else | ||
| 546 | #define drm_gem_get_unmapped_area NULL | ||
| 547 | #endif | ||
| 548 | |||
| 510 | /** | 549 | /** |
| 511 | * drm_gem_object_get - acquire a GEM buffer object reference | 550 | * drm_gem_object_get - acquire a GEM buffer object reference |
| 512 | * @obj: GEM buffer object | 551 | * @obj: GEM buffer object |
| @@ -109,9 +109,6 @@ struct drm_gem_shmem_object { · 108 unmodified lines | |||
| 109 | 109 | ||
| 110 | int drm_gem_shmem_init(struct drm_device *dev, struct drm_gem_shmem_object *shmem, size_t size); | 110 | int drm_gem_shmem_init(struct drm_device *dev, struct drm_gem_shmem_object *shmem, size_t size); |
| 111 | struct drm_gem_shmem_object *drm_gem_shmem_create(struct drm_device *dev, size_t size); | 111 | struct drm_gem_shmem_object *drm_gem_shmem_create(struct drm_device *dev, size_t size); |
| 112 | struct drm_gem_shmem_object *drm_gem_shmem_create_with_mnt(struct drm_device *dev, | ||
| 113 | size_t size, | ||
| 114 | struct vfsmount *gemfs); | ||
| 115 | void drm_gem_shmem_release(struct drm_gem_shmem_object *shmem); | 112 | void drm_gem_shmem_release(struct drm_gem_shmem_object *shmem); |
| 116 | void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem); | 113 | void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem); |
| 117 | 114 | ||
| @@ -52,11 +52,6 @@ struct drm_scanout_buffer; · 51 unmodified lines | |||
| 52 | struct drm_writeback_connector; | 52 | struct drm_writeback_connector; |
| 53 | struct drm_writeback_job; | 53 | struct drm_writeback_job; |
| 54 | 54 | ||
| 55 | enum mode_set_atomic { | ||
| 56 | LEAVE_ATOMIC_MODE_SET, | ||
| 57 | ENTER_ATOMIC_MODE_SET, | ||
| 58 | }; | ||
| 59 | |||
| 60 | /** | 55 | /** |
| 61 | * struct drm_crtc_helper_funcs - helper operations for CRTCs | 56 | * struct drm_crtc_helper_funcs - helper operations for CRTCs |
| 62 | * | 57 | * |
| @@ -253,24 +248,6 @@ struct drm_crtc_helper_funcs { · 190 unmodified lines | |||
| 253 | int (*mode_set_base)(struct drm_crtc *crtc, int x, int y, | 248 | int (*mode_set_base)(struct drm_crtc *crtc, int x, int y, |
| 254 | struct drm_framebuffer *old_fb); | 249 | struct drm_framebuffer *old_fb); |
| 255 | 250 | ||
| 256 | /** | ||
| 257 | * @mode_set_base_atomic: | ||
| 258 | * | ||
| 259 | * This callback is used by the fbdev helpers to set a new framebuffer | ||
| 260 | * and scanout without sleeping, i.e. from an atomic calling context. It | ||
| 261 | * is only used to implement kgdb support. | ||
| 262 | * | ||
| 263 | * This callback is optional and only needed for kgdb support in the fbdev | ||
| 264 | * helpers. | ||
| 265 | * | ||
| 266 | * RETURNS: | ||
| 267 | * | ||
| 268 | * 0 on success or a negative error code on failure. | ||
| 269 | */ | ||
| 270 | int (*mode_set_base_atomic)(struct drm_crtc *crtc, | ||
| 271 | struct drm_framebuffer *fb, int x, int y, | ||
| 272 | enum mode_set_atomic); | ||
| 273 | |||
| 274 | /** | 251 | /** |
| 275 | * @disable: | 252 | * @disable: |
| 276 | * | 253 | * |
| @@ -302,8 +302,7 @@ bool drm_handle_vblank(struct drm_device *dev, unsigned int pipe); · 301 unmodified lines | |||
| 302 | bool drm_crtc_handle_vblank(struct drm_crtc *crtc); | 302 | bool drm_crtc_handle_vblank(struct drm_crtc *crtc); |
| 303 | int drm_crtc_vblank_get(struct drm_crtc *crtc); | 303 | int drm_crtc_vblank_get(struct drm_crtc *crtc); |
| 304 | void drm_crtc_vblank_put(struct drm_crtc *crtc); | 304 | void drm_crtc_vblank_put(struct drm_crtc *crtc); |
| 305 | void drm_wait_one_vblank(struct drm_device *dev, unsigned int pipe); | 305 | int drm_crtc_wait_one_vblank(struct drm_crtc *crtc); |
| 306 | void drm_crtc_wait_one_vblank(struct drm_crtc *crtc); | ||
| 307 | void drm_crtc_vblank_off(struct drm_crtc *crtc); | 306 | void drm_crtc_vblank_off(struct drm_crtc *crtc); |
| 308 | void drm_crtc_vblank_reset(struct drm_crtc *crtc); | 307 | void drm_crtc_vblank_reset(struct drm_crtc *crtc); |
| 309 | void drm_crtc_vblank_on_config(struct drm_crtc *crtc, | 308 | void drm_crtc_vblank_on_config(struct drm_crtc *crtc, |
| @@ -364,11 +364,12 @@ static inline void dma_fence_end_signalling(bool cookie) {} · 363 unmodified lines | |||
| 364 | static inline void __dma_fence_might_wait(void) {} | 364 | static inline void __dma_fence_might_wait(void) {} |
| 365 | #endif | 365 | #endif |
| 366 | 366 | ||
| 367 | int dma_fence_signal(struct dma_fence *fence); | 367 | void dma_fence_signal(struct dma_fence *fence); |
| 368 | int dma_fence_signal_locked(struct dma_fence *fence); | 368 | bool dma_fence_check_and_signal(struct dma_fence *fence); |
| 369 | int dma_fence_signal_timestamp(struct dma_fence *fence, ktime_t timestamp); | 369 | bool dma_fence_check_and_signal_locked(struct dma_fence *fence); |
| 370 | int dma_fence_signal_timestamp_locked(struct dma_fence *fence, | 370 | void dma_fence_signal_locked(struct dma_fence *fence); |
| 371 | ktime_t timestamp); | 371 | void dma_fence_signal_timestamp(struct dma_fence *fence, ktime_t timestamp); |
| 372 | void dma_fence_signal_timestamp_locked(struct dma_fence *fence, ktime_t timestamp); | ||
| 372 | signed long dma_fence_default_wait(struct dma_fence *fence, | 373 | signed long dma_fence_default_wait(struct dma_fence *fence, |
| 373 | bool intr, signed long timeout); | 374 | bool intr, signed long timeout); |
| 374 | int dma_fence_add_callback(struct dma_fence *fence, | 375 | int dma_fence_add_callback(struct dma_fence *fence, |
| @@ -401,6 +402,26 @@ void dma_fence_enable_sw_signaling(struct dma_fence *fence); · 26 unmodified lines | |||
| 401 | const char __rcu *dma_fence_driver_name(struct dma_fence *fence); | 402 | const char __rcu *dma_fence_driver_name(struct dma_fence *fence); |
| 402 | const char __rcu *dma_fence_timeline_name(struct dma_fence *fence); | 403 | const char __rcu *dma_fence_timeline_name(struct dma_fence *fence); |
| 403 | 404 | ||
| 405 | /* | ||
| 406 | * dma_fence_test_signaled_flag - Only check whether a fence is signaled yet. | ||
| 407 | * @fence: the fence to check | ||
| 408 | * | ||
| 409 | * This function just checks whether @fence is signaled, without interacting | ||
| 410 | * with the fence in any way. The user must, therefore, ensure through other | ||
| 411 | * means that fences get signaled eventually. | ||
| 412 | * | ||
| 413 | * This function uses test_bit(), which is thread-safe. Naturally, this function | ||
| 414 | * should be used opportunistically; a fence could get signaled at any moment | ||
| 415 | * after the check is done. | ||
| 416 | * | ||
| 417 | * Return: true if signaled, false otherwise. | ||
| 418 | */ | ||
| 419 | static inline bool | ||
| 420 | dma_fence_test_signaled_flag(struct dma_fence *fence) | ||
| 421 | { | ||
| 422 | return test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags); | ||
| 423 | } | ||
| 424 | |||
| 404 | /** | 425 | /** |
| 405 | * dma_fence_is_signaled_locked - Return an indication if the fence | 426 | * dma_fence_is_signaled_locked - Return an indication if the fence |
| 406 | * is signaled yet. | 427 | * is signaled yet. |
| @@ -418,7 +439,7 @@ const char __rcu *dma_fence_timeline_name(struct dma_fence *fence); · 11 unmodified lines | |||
| 418 | static inline bool | 439 | static inline bool |
| 419 | dma_fence_is_signaled_locked(struct dma_fence *fence) | 440 | dma_fence_is_signaled_locked(struct dma_fence *fence) |
| 420 | { | 441 | { |
| 421 | if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) | 442 | if (dma_fence_test_signaled_flag(fence)) |
| 422 | return true; | 443 | return true; |
| 423 | 444 | ||
| 424 | if (fence->ops->signaled && fence->ops->signaled(fence)) { | 445 | if (fence->ops->signaled && fence->ops->signaled(fence)) { |
| @@ -448,7 +469,7 @@ dma_fence_is_signaled_locked(struct dma_fence *fence) · 23 unmodified lines | |||
| 448 | static inline bool | 469 | static inline bool |
| 449 | dma_fence_is_signaled(struct dma_fence *fence) | 470 | dma_fence_is_signaled(struct dma_fence *fence) |
| 450 | { | 471 | { |
| 451 | if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) | 472 | if (dma_fence_test_signaled_flag(fence)) |
| 452 | return true; | 473 | return true; |
| 453 | 474 | ||
| 454 | if (fence->ops->signaled && fence->ops->signaled(fence)) { | 475 | if (fence->ops->signaled && fence->ops->signaled(fence)) { |
| @@ -304,10 +304,6 @@ struct fb_ops { · 303 unmodified lines | |||
| 304 | 304 | ||
| 305 | /* teardown any resources to do with this framebuffer */ | 305 | /* teardown any resources to do with this framebuffer */ |
| 306 | void (*fb_destroy)(struct fb_info *info); | 306 | void (*fb_destroy)(struct fb_info *info); |
| 307 | |||
| 308 | /* called at KDB enter and leave time to prepare the console */ | ||
| 309 | int (*fb_debug_enter)(struct fb_info *info); | ||
| 310 | int (*fb_debug_leave)(struct fb_info *info); | ||
| 311 | }; | 307 | }; |
| 312 | 308 | ||
| 313 | #ifdef CONFIG_FB_TILEBLITTING | 309 | #ifdef CONFIG_FB_TILEBLITTING |
| @@ -24,6 +24,8 @@ extern "C" { · 23 unmodified lines | |||
| 24 | #define DRM_PANFROST_SET_LABEL_BO 0x09 | 24 | #define DRM_PANFROST_SET_LABEL_BO 0x09 |
| 25 | #define DRM_PANFROST_JM_CTX_CREATE 0x0a | 25 | #define DRM_PANFROST_JM_CTX_CREATE 0x0a |
| 26 | #define DRM_PANFROST_JM_CTX_DESTROY 0x0b | 26 | #define DRM_PANFROST_JM_CTX_DESTROY 0x0b |
| 27 | #define DRM_PANFROST_SYNC_BO 0x0c | ||
| 28 | #define DRM_PANFROST_QUERY_BO_INFO 0x0d | ||
| 27 | 29 | ||
| 28 | #define DRM_IOCTL_PANFROST_SUBMIT DRM_IOW(DRM_COMMAND_BASE + DRM_PANFROST_SUBMIT, struct drm_panfrost_submit) | 30 | #define DRM_IOCTL_PANFROST_SUBMIT DRM_IOW(DRM_COMMAND_BASE + DRM_PANFROST_SUBMIT, struct drm_panfrost_submit) |
| 29 | #define DRM_IOCTL_PANFROST_WAIT_BO DRM_IOW(DRM_COMMAND_BASE + DRM_PANFROST_WAIT_BO, struct drm_panfrost_wait_bo) | 31 | #define DRM_IOCTL_PANFROST_WAIT_BO DRM_IOW(DRM_COMMAND_BASE + DRM_PANFROST_WAIT_BO, struct drm_panfrost_wait_bo) |
| @@ -35,6 +37,8 @@ extern "C" { · 5 unmodified lines | |||
| 35 | #define DRM_IOCTL_PANFROST_SET_LABEL_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_PANFROST_SET_LABEL_BO, struct drm_panfrost_set_label_bo) | 37 | #define DRM_IOCTL_PANFROST_SET_LABEL_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_PANFROST_SET_LABEL_BO, struct drm_panfrost_set_label_bo) |
| 36 | #define DRM_IOCTL_PANFROST_JM_CTX_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_PANFROST_JM_CTX_CREATE, struct drm_panfrost_jm_ctx_create) | 38 | #define DRM_IOCTL_PANFROST_JM_CTX_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_PANFROST_JM_CTX_CREATE, struct drm_panfrost_jm_ctx_create) |
| 37 | #define DRM_IOCTL_PANFROST_JM_CTX_DESTROY DRM_IOWR(DRM_COMMAND_BASE + DRM_PANFROST_JM_CTX_DESTROY, struct drm_panfrost_jm_ctx_destroy) | 39 | #define DRM_IOCTL_PANFROST_JM_CTX_DESTROY DRM_IOWR(DRM_COMMAND_BASE + DRM_PANFROST_JM_CTX_DESTROY, struct drm_panfrost_jm_ctx_destroy) |
| 40 | #define DRM_IOCTL_PANFROST_SYNC_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_PANFROST_SYNC_BO, struct drm_panfrost_sync_bo) | ||
| 41 | #define DRM_IOCTL_PANFROST_QUERY_BO_INFO DRM_IOWR(DRM_COMMAND_BASE + DRM_PANFROST_QUERY_BO_INFO, struct drm_panfrost_query_bo_info) | ||
| 38 | 42 | ||
| 39 | /* | 43 | /* |
| 40 | * Unstable ioctl(s): only exposed when the unsafe unstable_ioctls module | 44 | * Unstable ioctl(s): only exposed when the unsafe unstable_ioctls module |
| @@ -120,9 +124,12 @@ struct drm_panfrost_wait_bo { · 79 unmodified lines | |||
| 120 | __s64 timeout_ns; | 124 | __s64 timeout_ns; |
| 121 | }; | 125 | }; |
| 122 | 126 | ||
| 123 | /* Valid flags to pass to drm_panfrost_create_bo */ | 127 | /* Valid flags to pass to drm_panfrost_create_bo. |
| 128 | * PANFROST_BO_WB_MMAP can't be set if PANFROST_BO_HEAP is. | ||
| 129 | */ | ||
| 124 | #define PANFROST_BO_NOEXEC 1 | 130 | #define PANFROST_BO_NOEXEC 1 |
| 125 | #define PANFROST_BO_HEAP 2 | 131 | #define PANFROST_BO_HEAP 2 |
| 132 | #define PANFROST_BO_WB_MMAP 4 | ||
| 126 | 133 | ||
| 127 | /** | 134 | /** |
| 128 | * struct drm_panfrost_create_bo - ioctl argument for creating Panfrost BOs. | 135 | * struct drm_panfrost_create_bo - ioctl argument for creating Panfrost BOs. |
| @@ -228,6 +235,13 @@ enum drm_panfrost_param { · 99 unmodified lines | |||
| 228 | DRM_PANFROST_PARAM_SYSTEM_TIMESTAMP, | 235 | DRM_PANFROST_PARAM_SYSTEM_TIMESTAMP, |
| 229 | DRM_PANFROST_PARAM_SYSTEM_TIMESTAMP_FREQUENCY, | 236 | DRM_PANFROST_PARAM_SYSTEM_TIMESTAMP_FREQUENCY, |
| 230 | DRM_PANFROST_PARAM_ALLOWED_JM_CTX_PRIORITIES, | 237 | DRM_PANFROST_PARAM_ALLOWED_JM_CTX_PRIORITIES, |
| 238 | DRM_PANFROST_PARAM_SELECTED_COHERENCY, | ||
| 239 | }; | ||
| 240 | |||
| 241 | enum drm_panfrost_gpu_coherency { | ||
| 242 | DRM_PANFROST_GPU_COHERENCY_ACE_LITE = 0, | ||
| 243 | DRM_PANFROST_GPU_COHERENCY_ACE = 1, | ||
| 244 | DRM_PANFROST_GPU_COHERENCY_NONE = 31, | ||
| 231 | }; | 245 | }; |
| 232 | 246 | ||
| 233 | struct drm_panfrost_get_param { | 247 | struct drm_panfrost_get_param { |
| @@ -301,6 +315,66 @@ struct drm_panfrost_set_label_bo { · 67 unmodified lines | |||
| 301 | __u64 label; | 315 | __u64 label; |
| 302 | }; | 316 | }; |
| 303 | 317 | ||
| 318 | /* Valid flags to pass to drm_panfrost_bo_sync_op */ | ||
| 319 | #define PANFROST_BO_SYNC_CPU_CACHE_FLUSH 0 | ||
| 320 | #define PANFROST_BO_SYNC_CPU_CACHE_FLUSH_AND_INVALIDATE 1 | ||
| 321 | |||
| 322 | /** | ||
| 323 | * struct drm_panthor_bo_flush_map_op - BO map sync op | ||
| 324 | */ | ||
| 325 | struct drm_panfrost_bo_sync_op { | ||
| 326 | /** @handle: Handle of the buffer object to sync. */ | ||
| 327 | __u32 handle; | ||
| 328 | |||
| 329 | /** @type: Type of sync operation. */ | ||
| 330 | __u32 type; | ||
| 331 | |||
| 332 | /** | ||
| 333 | * @offset: Offset into the BO at which the sync range starts. | ||
| 334 | * | ||
| 335 | * This will be rounded down to the nearest cache line as needed. | ||
| 336 | */ | ||
| 337 | __u32 offset; | ||
| 338 | |||
| 339 | /** | ||
| 340 | * @size: Size of the range to sync | ||
| 341 | * | ||
| 342 | * @size + @offset will be rounded up to the nearest cache line as | ||
| 343 | * needed. | ||
| 344 | */ | ||
| 345 | __u32 size; | ||
| 346 | }; | ||
| 347 | |||
| 348 | /** | ||
| 349 | * struct drm_panfrost_sync_bo - ioctl argument for syncing BO maps | ||
| 350 | */ | ||
| 351 | struct drm_panfrost_sync_bo { | ||
| 352 | /** Array of struct drm_panfrost_bo_sync_op */ | ||
| 353 | __u64 ops; | ||
| 354 | |||
| 355 | /** Number of BO sync ops */ | ||
| 356 | __u32 op_count; | ||
| 357 | |||
| 358 | __u32 pad; | ||
| 359 | }; | ||
| 360 | |||
| 361 | /** BO comes from a different subsystem. */ | ||
| 362 | #define DRM_PANFROST_BO_IS_IMPORTED (1 << 0) | ||
| 363 | |||
| 364 | struct drm_panfrost_query_bo_info { | ||
| 365 | /** Handle of the object being queried. */ | ||
| 366 | __u32 handle; | ||
| 367 | |||
| 368 | /** Extra flags that are not coming from the BO_CREATE ioctl(). */ | ||
| 369 | __u32 extra_flags; | ||
| 370 | |||
| 371 | /** Flags passed at creation time. */ | ||
| 372 | __u32 create_flags; | ||
| 373 | |||
| 374 | /** Will be zero on return. */ | ||
| 375 | __u32 pad; | ||
| 376 | }; | ||
| 377 | |||
| 304 | /* Definitions for coredump decoding in user space */ | 378 | /* Definitions for coredump decoding in user space */ |
| 305 | #define PANFROSTDUMP_MAJOR 1 | 379 | #define PANFROSTDUMP_MAJOR 1 |
| 306 | #define PANFROSTDUMP_MINOR 0 | 380 | #define PANFROSTDUMP_MINOR 0 |
| @@ -144,6 +144,16 @@ enum drm_panthor_ioctl_id { · 143 unmodified lines | |||
| 144 | * pgoff_t size. | 144 | * pgoff_t size. |
| 145 | */ | 145 | */ |
| 146 | DRM_PANTHOR_SET_USER_MMIO_OFFSET, | 146 | DRM_PANTHOR_SET_USER_MMIO_OFFSET, |
| 147 | |||
| 148 | /** @DRM_PANTHOR_BO_SYNC: Sync BO data to/from the device */ | ||
| 149 | DRM_PANTHOR_BO_SYNC, | ||
| 150 | |||
| 151 | /** | ||
| 152 | * @DRM_PANTHOR_BO_QUERY_INFO: Query information about a BO. | ||
| 153 | * | ||
| 154 | * This is useful for imported BOs. | ||
| 155 | */ | ||
| 156 | DRM_PANTHOR_BO_QUERY_INFO, | ||
| 147 | }; | 157 | }; |
| 148 | 158 | ||
| 149 | /** | 159 | /** |
| @@ -245,6 +255,26 @@ enum drm_panthor_dev_query_type { · 95 unmodified lines | |||
| 245 | DRM_PANTHOR_DEV_QUERY_GROUP_PRIORITIES_INFO, | 255 | DRM_PANTHOR_DEV_QUERY_GROUP_PRIORITIES_INFO, |
| 246 | }; | 256 | }; |
| 247 | 257 | ||
| 258 | /** | ||
| 259 | * enum drm_panthor_gpu_coherency: Type of GPU coherency | ||
| 260 | */ | ||
| 261 | enum drm_panthor_gpu_coherency { | ||
| 262 | /** | ||
| 263 | * @DRM_PANTHOR_GPU_COHERENCY_ACE_LITE: ACE Lite coherency. | ||
| 264 | */ | ||
| 265 | DRM_PANTHOR_GPU_COHERENCY_ACE_LITE = 0, | ||
| 266 | |||
| 267 | /** | ||
| 268 | * @DRM_PANTHOR_GPU_COHERENCY_ACE: ACE coherency. | ||
| 269 | */ | ||
| 270 | DRM_PANTHOR_GPU_COHERENCY_ACE = 1, | ||
| 271 | |||
| 272 | /** | ||
| 273 | * @DRM_PANTHOR_GPU_COHERENCY_NONE: No coherency. | ||
| 274 | */ | ||
| 275 | DRM_PANTHOR_GPU_COHERENCY_NONE = 31, | ||
| 276 | }; | ||
| 277 | |||
| 248 | /** | 278 | /** |
| 249 | * struct drm_panthor_gpu_info - GPU information | 279 | * struct drm_panthor_gpu_info - GPU information |
| 250 | * | 280 | * |
| @@ -301,7 +331,16 @@ struct drm_panthor_gpu_info { · 50 unmodified lines | |||
| 301 | */ | 331 | */ |
| 302 | __u32 thread_max_barrier_size; | 332 | __u32 thread_max_barrier_size; |
| 303 | 333 | ||
| 304 | /** @coherency_features: Coherency features. */ | 334 | /** |
| 335 | * @coherency_features: Coherency features. | ||
| 336 | * | ||
| 337 | * Combination of drm_panthor_gpu_coherency flags. | ||
| 338 | * | ||
| 339 | * Note that this is just what the coherency protocols supported by the | ||
| 340 | * GPU, but the actual coherency in place depends on the SoC | ||
| 341 | * integration and is reflected by | ||
| 342 | * drm_panthor_gpu_info::selected_coherency. | ||
| 343 | */ | ||
| 305 | __u32 coherency_features; | 344 | __u32 coherency_features; |
| 306 | 345 | ||
| 307 | /** @texture_features: Texture features. */ | 346 | /** @texture_features: Texture features. */ |
| @@ -310,8 +349,12 @@ struct drm_panthor_gpu_info { · 2 unmodified lines | |||
| 310 | /** @as_present: Bitmask encoding the number of address-space exposed by the MMU. */ | 349 | /** @as_present: Bitmask encoding the number of address-space exposed by the MMU. */ |
| 311 | __u32 as_present; | 350 | __u32 as_present; |
| 312 | 351 | ||
| 313 | /** @pad0: MBZ. */ | 352 | /** |
| 314 | __u32 pad0; | 353 | * @select_coherency: Coherency selected for this device. |
| 354 | * | ||
| 355 | * One of drm_panthor_gpu_coherency. | ||
| 356 | */ | ||
| 357 | __u32 selected_coherency; | ||
| 315 | 358 | ||
| 316 | /** @shader_present: Bitmask encoding the shader cores exposed by the GPU. */ | 359 | /** @shader_present: Bitmask encoding the shader cores exposed by the GPU. */ |
| 317 | __u64 shader_present; | 360 | __u64 shader_present; |
| @@ -638,6 +681,15 @@ struct drm_panthor_vm_get_state { · 320 unmodified lines | |||
| 638 | enum drm_panthor_bo_flags { | 681 | enum drm_panthor_bo_flags { |
| 639 | /** @DRM_PANTHOR_BO_NO_MMAP: The buffer object will never be CPU-mapped in userspace. */ | 682 | /** @DRM_PANTHOR_BO_NO_MMAP: The buffer object will never be CPU-mapped in userspace. */ |
| 640 | DRM_PANTHOR_BO_NO_MMAP = (1 << 0), | 683 | DRM_PANTHOR_BO_NO_MMAP = (1 << 0), |
| 684 | |||
| 685 | /** | ||
| 686 | * @DRM_PANTHOR_BO_WB_MMAP: Force "Write-Back Cacheable" CPU mapping. | ||
| 687 | * | ||
| 688 | * CPU map the buffer object in userspace by forcing the "Write-Back | ||
| 689 | * Cacheable" cacheability attribute. The mapping otherwise uses the | ||
| 690 | * "Non-Cacheable" attribute if the GPU is not IO coherent. | ||
| 691 | */ | ||
| 692 | DRM_PANTHOR_BO_WB_MMAP = (1 << 1), | ||
| 641 | }; | 693 | }; |
| 642 | 694 | ||
| 643 | /** | 695 | /** |
| @@ -1040,6 +1092,101 @@ struct drm_panthor_set_user_mmio_offset { · 396 unmodified lines | |||
| 1040 | __u64 offset; | 1092 | __u64 offset; |
| 1041 | }; | 1093 | }; |
| 1042 | 1094 | ||
| 1095 | /** | ||
| 1096 | * enum drm_panthor_bo_sync_op_type - BO sync type | ||
| 1097 | */ | ||
| 1098 | enum drm_panthor_bo_sync_op_type { | ||
| 1099 | /** @DRM_PANTHOR_BO_SYNC_CPU_CACHE_FLUSH: Flush CPU caches. */ | ||
| 1100 | DRM_PANTHOR_BO_SYNC_CPU_CACHE_FLUSH = 0, | ||
| 1101 | |||
| 1102 | /** @DRM_PANTHOR_BO_SYNC_CPU_CACHE_FLUSH_AND_INVALIDATE: Flush and invalidate CPU caches. */ | ||
| 1103 | DRM_PANTHOR_BO_SYNC_CPU_CACHE_FLUSH_AND_INVALIDATE = 1, | ||
| 1104 | }; | ||
| 1105 | |||
| 1106 | /** | ||
| 1107 | * struct drm_panthor_bo_sync_op - BO map sync op | ||
| 1108 | */ | ||
| 1109 | struct drm_panthor_bo_sync_op { | ||
| 1110 | /** @handle: Handle of the buffer object to sync. */ | ||
| 1111 | __u32 handle; | ||
| 1112 | |||
| 1113 | /** @type: Type of operation. */ | ||
| 1114 | __u32 type; | ||
| 1115 | |||
| 1116 | /** | ||
| 1117 | * @offset: Offset into the BO at which the sync range starts. | ||
| 1118 | * | ||
| 1119 | * This will be rounded down to the nearest cache line as needed. | ||
| 1120 | */ | ||
| 1121 | __u64 offset; | ||
| 1122 | |||
| 1123 | /** | ||
| 1124 | * @size: Size of the range to sync | ||
| 1125 | * | ||
| 1126 | * @size + @offset will be rounded up to the nearest cache line as | ||
| 1127 | * needed. | ||
| 1128 | */ | ||
| 1129 | __u64 size; | ||
| 1130 | }; | ||
| 1131 | |||
| 1132 | /** | ||
| 1133 | * struct drm_panthor_bo_sync - BO map sync request | ||
| 1134 | */ | ||
| 1135 | struct drm_panthor_bo_sync { | ||
| 1136 | /** | ||
| 1137 | * @ops: Array of struct drm_panthor_bo_sync_op sync operations. | ||
| 1138 | */ | ||
| 1139 | struct drm_panthor_obj_array ops; | ||
| 1140 | }; | ||
| 1141 | |||
| 1142 | /** | ||
| 1143 | * enum drm_panthor_bo_extra_flags - Set of flags returned on a BO_QUERY_INFO request | ||
| 1144 | * | ||
| 1145 | * Those are flags reflecting BO properties that are not directly coming from the flags | ||
| 1146 | * passed are creation time, or information on BOs that were imported from other drivers. | ||
| 1147 | */ | ||
| 1148 | enum drm_panthor_bo_extra_flags { | ||
| 1149 | /** | ||
| 1150 | * @DRM_PANTHOR_BO_IS_IMPORTED: BO has been imported from an external driver. | ||
| 1151 | * | ||
| 1152 | * Note that imported dma-buf handles are not flagged as imported if they | ||
| 1153 | * where exported by panthor. Only buffers that are coming from other drivers | ||
| 1154 | * (dma heaps, other GPUs, display controllers, V4L, ...). | ||
| 1155 | * | ||
| 1156 | * It's also important to note that all imported BOs are mapped cached and can't | ||
| 1157 | * be considered IO-coherent even if the GPU is. This means they require explicit | ||
| 1158 | * syncs that must go through the DRM_PANTHOR_BO_SYNC ioctl (userland cache | ||
| 1159 | * maintenance is not allowed in that case, because extra operations might be | ||
| 1160 | * needed to make changes visible to the CPU/device, like buffer migration when the | ||
| 1161 | * exporter is a GPU with its own VRAM). | ||
| 1162 | */ | ||
| 1163 | DRM_PANTHOR_BO_IS_IMPORTED = (1 << 0), | ||
| 1164 | }; | ||
| 1165 | |||
| 1166 | /** | ||
| 1167 | * struct drm_panthor_bo_query_info - Query BO info | ||
| 1168 | */ | ||
| 1169 | struct drm_panthor_bo_query_info { | ||
| 1170 | /** @handle: Handle of the buffer object to query flags on. */ | ||
| 1171 | __u32 handle; | ||
| 1172 | |||
| 1173 | /** | ||
| 1174 | * @extra_flags: Combination of enum drm_panthor_bo_extra_flags flags. | ||
| 1175 | */ | ||
| 1176 | __u32 extra_flags; | ||
| 1177 | |||
| 1178 | /** | ||
| 1179 | * @create_flags: Flags passed at creation time. | ||
| 1180 | * | ||
| 1181 | * Combination of enum drm_panthor_bo_flags flags. | ||
| 1182 | * Will be zero if the buffer comes from a different driver. | ||
| 1183 | */ | ||
| 1184 | __u32 create_flags; | ||
| 1185 | |||
| 1186 | /** @pad: Will be zero on return. */ | ||
| 1187 | __u32 pad; | ||
| 1188 | }; | ||
| 1189 | |||
| 1043 | /** | 1190 | /** |
| 1044 | * DRM_IOCTL_PANTHOR() - Build a Panthor IOCTL number | 1191 | * DRM_IOCTL_PANTHOR() - Build a Panthor IOCTL number |
| 1045 | * @__access: Access type. Must be R, W or RW. | 1192 | * @__access: Access type. Must be R, W or RW. |
| @@ -1086,6 +1233,10 @@ enum { · 40 unmodified lines | |||
| 1086 | DRM_IOCTL_PANTHOR(WR, BO_SET_LABEL, bo_set_label), | 1233 | DRM_IOCTL_PANTHOR(WR, BO_SET_LABEL, bo_set_label), |
| 1087 | DRM_IOCTL_PANTHOR_SET_USER_MMIO_OFFSET = | 1234 | DRM_IOCTL_PANTHOR_SET_USER_MMIO_OFFSET = |
| 1088 | DRM_IOCTL_PANTHOR(WR, SET_USER_MMIO_OFFSET, set_user_mmio_offset), | 1235 | DRM_IOCTL_PANTHOR(WR, SET_USER_MMIO_OFFSET, set_user_mmio_offset), |
| 1236 | DRM_IOCTL_PANTHOR_BO_SYNC = | ||
| 1237 | DRM_IOCTL_PANTHOR(WR, BO_SYNC, bo_sync), | ||
| 1238 | DRM_IOCTL_PANTHOR_BO_QUERY_INFO = | ||
| 1239 | DRM_IOCTL_PANTHOR(WR, BO_QUERY_INFO, bo_query_info), | ||
| 1089 | }; | 1240 | }; |
| 1090 | 1241 | ||
| 1091 | #if defined(__cplusplus) | 1242 | #if defined(__cplusplus) |