diff options
| author | Dave Airlie <airlied@redhat.com> | 2026-05-15 12:10:39 +1000 |
|---|---|---|
| committer | Dave Airlie <airlied@redhat.com> | 2026-05-15 12:14:25 +1000 |
| commit | 15342d4aebcb4c02c37a62c9222ac5056eab6faf (patch) | |
| tree | 0d2d34c1e860c86bfc652621b34d5ce20c9ec795 | |
| parent | e53bf933163f88eb31762052e63c5bec50c35afb (diff) | |
| parent | 4c26e162947f91aa78ba57dd4fddd38fc80e7d60 (diff) | |
Merge tag 'drm-misc-next-2026-05-14' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-next
drm-misc-next for v7.2-rc1:
UAPI Changes:
- Update fourcc descriptions of BG(R) floating formats.
- Add deferred mapping support to virtio.
Cross-subsystem Changes:
- Update lontium lt9211 bindings.
Core Changes:
- Bugfixes and cleanups to pagemap, dp/mst.
- Add lockdep annotations to gpu buddy manager.
- Updates to drm/dp for PR + VRR.
- Improve documentation's table of contents.
- Bump fpfn and lpfn in ttm to 64-bits.
Driver Changes:
- Assorted bugfixes, cleanups and updates to panthor, nouveau, qaic,
hisilicon.
- Add support for CMN N116BCN-EA1, CMN N140HCA-EEK, IVO M140NWFQ R5, IVO
R140NWFW R0, BOE NT140*, BOE NV133FHM-N4F, AUO B140*, AUO B133HAN06.6 and AUO B116XTN02.3 eDP panels.
- More implementation of AIE4 in amdxdna.
- Update panels to use refcounts instead of devm_kzalloc to make
drm_panel_init static.
- Add support for the RCade Display Adapter to gud.
Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: https://patch.msgid.link/98788814-e462-4950-bb2a-ea493c30d0c0@linux.intel.com
77 files changed, 1458 insertions, 439 deletions
diff --git a/Documentation/devicetree/bindings/display/bridge/lontium,lt9211.yaml b/Documentation/devicetree/bindings/display/bridge/lontium,lt9211.yaml index 9a6e9b25d14a..7cfe92a8bcd7 100644 --- a/Documentation/devicetree/bindings/display/bridge/lontium,lt9211.yaml +++ b/Documentation/devicetree/bindings/display/bridge/lontium,lt9211.yaml @@ -36,18 +36,56 @@ properties: properties: port@0: - $ref: /schemas/graph.yaml#/properties/port + $ref: /schemas/graph.yaml#/$defs/port-base + unevaluatedProperties: false description: Primary MIPI DSI port-1 for MIPI input or LVDS port-1 for LVDS input or DPI input. + properties: + endpoint: + $ref: /schemas/media/video-interfaces.yaml# + unevaluatedProperties: false + + properties: + data-lanes: + description: array of physical DSI data lane indexes. + minItems: 1 + items: + - const: 1 + - const: 2 + - const: 3 + - const: 4 + + required: + - data-lanes + port@1: - $ref: /schemas/graph.yaml#/properties/port + $ref: /schemas/graph.yaml#/$defs/port-base + unevaluatedProperties: false description: Additional MIPI port-2 for MIPI input or LVDS port-2 for LVDS input. Used in combination with primary port-1 to drive higher resolution displays + properties: + endpoint: + $ref: /schemas/media/video-interfaces.yaml# + unevaluatedProperties: false + + properties: + data-lanes: + description: array of physical DSI data lane indexes. + minItems: 1 + items: + - const: 1 + - const: 2 + - const: 3 + - const: 4 + + required: + - data-lanes + port@2: $ref: /schemas/graph.yaml#/properties/port description: @@ -99,6 +137,7 @@ examples: reg = <0>; endpoint { + data-lanes = <1 2 3 4>; remote-endpoint = <&dsi0_out>; }; }; diff --git a/Documentation/gpu/driver-uapi.rst b/Documentation/gpu/driver-uapi.rst index 1f15a8ca1265..627fc68c7a21 100644 --- a/Documentation/gpu/driver-uapi.rst +++ b/Documentation/gpu/driver-uapi.rst @@ -2,6 +2,8 @@ DRM Driver uAPI =============== +.. contents:: + drm/i915 uAPI ============= diff --git a/Documentation/gpu/drm-internals.rst b/Documentation/gpu/drm-internals.rst index 94f93fd3b8a0..a3ce25a36f1d 100644 --- a/Documentation/gpu/drm-internals.rst +++ b/Documentation/gpu/drm-internals.rst @@ -18,6 +18,8 @@ event handling, memory management, output management, framebuffer management, command submission & fencing, suspend/resume support, and DMA services. +.. contents:: + Driver Initialization ===================== diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst index b4a9e5ae81f6..80453dda33b8 100644 --- a/Documentation/gpu/drm-kms-helpers.rst +++ b/Documentation/gpu/drm-kms-helpers.rst @@ -33,6 +33,8 @@ There are a few areas these helpers can grouped into: pipeline: Planes, handling rectangles for visibility checking and scissoring, flip queues and assorted bits. +.. contents:: + Modeset Helper Reference for Common Vtables =========================================== diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index fbe0583eb84c..d22817fdf9aa 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -15,6 +15,8 @@ be setup by initializing the following fields. - struct drm_mode_config_funcs \*funcs; Mode setting functions. +.. contents:: + Overview ======== diff --git a/Documentation/gpu/drm-mm.rst b/Documentation/gpu/drm-mm.rst index 32fb506db05b..2dea94f77d52 100644 --- a/Documentation/gpu/drm-mm.rst +++ b/Documentation/gpu/drm-mm.rst @@ -25,6 +25,8 @@ share it. GEM has simpler initialization and execution requirements than TTM, but has no video RAM management capabilities and is thus limited to UMA devices. +.. contents:: + The Translation Table Manager (TTM) =================================== diff --git a/Documentation/gpu/drm-ras.rst b/Documentation/gpu/drm-ras.rst index 4636e68f5678..83c21853b74b 100644 --- a/Documentation/gpu/drm-ras.rst +++ b/Documentation/gpu/drm-ras.rst @@ -24,6 +24,8 @@ Key Goals: nodes for different IP blocks, sub-blocks, or other logical subdivisions as applicable. +.. contents:: + Nodes ===== diff --git a/Documentation/gpu/drm-uapi.rst b/Documentation/gpu/drm-uapi.rst index 32206ce62931..2c2f939322fb 100644 --- a/Documentation/gpu/drm-uapi.rst +++ b/Documentation/gpu/drm-uapi.rst @@ -16,6 +16,8 @@ management, and output management. Cover generic ioctls and sysfs layout here. We only need high-level info, since man pages should cover the rest. +.. contents:: + libdrm Device Lookup ==================== @@ -765,4 +767,4 @@ Stable uAPI events From ``drivers/gpu/drm/scheduler/gpu_scheduler_trace.h`` .. kernel-doc:: drivers/gpu/drm/scheduler/gpu_scheduler_trace.h - :doc: uAPI trace events
\ No newline at end of file + :doc: uAPI trace events diff --git a/Documentation/gpu/drm-usage-stats.rst b/Documentation/gpu/drm-usage-stats.rst index 24d3012ca7a6..70b7cfcc194f 100644 --- a/Documentation/gpu/drm-usage-stats.rst +++ b/Documentation/gpu/drm-usage-stats.rst @@ -16,6 +16,8 @@ output is split between common and driver specific parts. Having said that, wherever possible effort should still be made to standardise as much as possible. +.. contents:: + File format specification ========================= diff --git a/Documentation/gpu/index.rst b/Documentation/gpu/index.rst index 5d708a106b3f..65bf3b26e4f4 100644 --- a/Documentation/gpu/index.rst +++ b/Documentation/gpu/index.rst @@ -3,6 +3,7 @@ GPU Driver Developer's Guide ============================ .. toctree:: + :maxdepth: 2 introduction drm-internals diff --git a/Documentation/gpu/introduction.rst b/Documentation/gpu/introduction.rst index d8f519693fc2..64074ac22d9b 100644 --- a/Documentation/gpu/introduction.rst +++ b/Documentation/gpu/introduction.rst @@ -16,6 +16,8 @@ found in current kernels. [Insert diagram of typical DRM stack here] +.. contents:: + Style Guidelines ================ diff --git a/Documentation/gpu/rfc/index.rst b/Documentation/gpu/rfc/index.rst index ef19b0ba2a3e..26a7ebe6fb44 100644 --- a/Documentation/gpu/rfc/index.rst +++ b/Documentation/gpu/rfc/index.rst @@ -18,23 +18,9 @@ host such documentation: .. toctree:: - gpusvm.rst - -.. toctree:: - - i915_gem_lmem.rst - -.. toctree:: - - i915_scheduler.rst - -.. toctree:: - - i915_small_bar.rst - -.. toctree:: - - i915_vm_bind.rst - -.. toctree:: - color_pipeline.rst
\ No newline at end of file + gpusvm + i915_gem_lmem + i915_scheduler + i915_small_bar + i915_vm_bind + color_pipeline diff --git a/drivers/accel/amdxdna/Makefile b/drivers/accel/amdxdna/Makefile index d7720c8c8a98..05cce0a38692 100644 --- a/drivers/accel/amdxdna/Makefile +++ b/drivers/accel/amdxdna/Makefile @@ -10,6 +10,7 @@ amdxdna-y := \ aie2_pci.o \ aie2_pm.o \ aie2_solver.o \ + aie4_ctx.o \ aie4_message.o \ aie4_pci.o \ amdxdna_cbuf.o \ diff --git a/drivers/accel/amdxdna/aie.c b/drivers/accel/amdxdna/aie.c index 66849ba9026a..dd6f36f222c7 100644 --- a/drivers/accel/amdxdna/aie.c +++ b/drivers/accel/amdxdna/aie.c @@ -117,3 +117,51 @@ void amdxdna_vbnv_init(struct amdxdna_dev *xdna) amdxdna_update_vbnv(xdna, info->rev_vbnv_tbl, rev); } + +int amdxdna_get_metadata(struct aie_device *aie, + struct amdxdna_client *client, + struct amdxdna_drm_get_info *args) +{ + int ret = 0; + u32 buf_sz; + + buf_sz = min(args->buffer_size, sizeof(aie->metadata)); + if (copy_to_user(u64_to_user_ptr(args->buffer), &aie->metadata, buf_sz)) + ret = -EFAULT; + + return ret; +} + +void *amdxdna_alloc_msg_buffer(struct amdxdna_dev *xdna, u32 *size, + dma_addr_t *dma_addr) +{ + void *vaddr; + int order; + + *size = max_t(u32, *size, SZ_8K); + order = get_order(*size); + if (order > MAX_PAGE_ORDER) + return ERR_PTR(-EINVAL); + *size = PAGE_SIZE << order; + + if (amdxdna_iova_on(xdna)) + return amdxdna_iommu_alloc(xdna, *size, dma_addr); + + vaddr = dma_alloc_noncoherent(xdna->ddev.dev, *size, dma_addr, + DMA_FROM_DEVICE, GFP_KERNEL); + if (!vaddr) + return ERR_PTR(-ENOMEM); + + return vaddr; +} + +void amdxdna_free_msg_buffer(struct amdxdna_dev *xdna, size_t size, + void *cpu_addr, dma_addr_t dma_addr) +{ + if (amdxdna_iova_on(xdna)) { + amdxdna_iommu_free(xdna, size, cpu_addr, dma_addr); + return; + } + + dma_free_noncoherent(xdna->ddev.dev, size, cpu_addr, dma_addr, DMA_FROM_DEVICE); +} diff --git a/drivers/accel/amdxdna/aie.h b/drivers/accel/amdxdna/aie.h index 7a68b114f235..0483d582b7f8 100644 --- a/drivers/accel/amdxdna/aie.h +++ b/drivers/accel/amdxdna/aie.h @@ -5,6 +5,7 @@ #ifndef _AIE_H_ #define _AIE_H_ +#include <drm/amdxdna_accel.h> #include "amdxdna_pci_drv.h" #include "amdxdna_mailbox.h" @@ -26,6 +27,8 @@ struct aie_device { struct psp_device *psp_hdl; struct smu_device *smu_hdl; + + struct amdxdna_drm_query_aie_metadata metadata; }; #define DECLARE_AIE_MSG(name, op) \ @@ -94,6 +97,12 @@ void aie_destroy_chann(struct aie_device *aie, struct mailbox_channel **chann); int aie_send_mgmt_msg_wait(struct aie_device *aie, struct xdna_mailbox_msg *msg); int aie_check_protocol(struct aie_device *aie, u32 fw_major, u32 fw_minor); void amdxdna_vbnv_init(struct amdxdna_dev *xdna); +int amdxdna_get_metadata(struct aie_device *aie, struct amdxdna_client *client, + struct amdxdna_drm_get_info *args); +void *amdxdna_alloc_msg_buffer(struct amdxdna_dev *xdna, u32 *size, + dma_addr_t *dma_addr); +void amdxdna_free_msg_buffer(struct amdxdna_dev *xdna, size_t size, + void *cpu_addr, dma_addr_t dma_addr); /* aie_psp.c */ struct psp_device *aiem_psp_create(struct drm_device *ddev, struct psp_config *conf); diff --git a/drivers/accel/amdxdna/aie2_ctx.c b/drivers/accel/amdxdna/aie2_ctx.c index 139825ac8515..7d6094aefb6f 100644 --- a/drivers/accel/amdxdna/aie2_ctx.c +++ b/drivers/accel/amdxdna/aie2_ctx.c @@ -489,12 +489,12 @@ static int aie2_hwctx_col_list(struct amdxdna_hwctx *hwctx) } ndev = xdna->dev_handle; - if (unlikely(!ndev->metadata.core.row_count)) { + if (unlikely(!ndev->aie.metadata.core.row_count)) { XDNA_WARN(xdna, "Core tile row count is zero"); return -EINVAL; } - hwctx->num_col = hwctx->num_tiles / ndev->metadata.core.row_count; + hwctx->num_col = hwctx->num_tiles / ndev->aie.metadata.core.row_count; if (!hwctx->num_col || hwctx->num_col > ndev->total_col) { XDNA_ERR(xdna, "Invalid num_col %d", hwctx->num_col); return -EINVAL; diff --git a/drivers/accel/amdxdna/aie2_error.c b/drivers/accel/amdxdna/aie2_error.c index 70007b4363cd..babdac0157ab 100644 --- a/drivers/accel/amdxdna/aie2_error.c +++ b/drivers/accel/amdxdna/aie2_error.c @@ -11,6 +11,7 @@ #include <linux/kthread.h> #include <linux/kernel.h> +#include "aie.h" #include "aie2_msg_priv.h" #include "aie2_pci.h" #include "amdxdna_error.h" @@ -338,7 +339,7 @@ void aie2_error_async_events_free(struct amdxdna_dev_hdl *ndev) destroy_workqueue(events->wq); mutex_lock(&xdna->dev_lock); - aie2_free_msg_buffer(ndev, events->size, events->buf, events->addr); + amdxdna_free_msg_buffer(xdna, events->size, events->buf, events->addr); kfree(events); } @@ -354,7 +355,7 @@ int aie2_error_async_events_alloc(struct amdxdna_dev_hdl *ndev) if (!events) return -ENOMEM; - events->buf = aie2_alloc_msg_buffer(ndev, &total_size, &events->addr); + events->buf = amdxdna_alloc_msg_buffer(xdna, &total_size, &events->addr); if (IS_ERR(events->buf)) { ret = PTR_ERR(events->buf); goto free_events; @@ -394,7 +395,7 @@ int aie2_error_async_events_alloc(struct amdxdna_dev_hdl *ndev) free_wq: destroy_workqueue(events->wq); free_buf: - aie2_free_msg_buffer(ndev, events->size, events->buf, events->addr); + amdxdna_free_msg_buffer(xdna, events->size, events->buf, events->addr); free_events: kfree(events); return ret; diff --git a/drivers/accel/amdxdna/aie2_message.c b/drivers/accel/amdxdna/aie2_message.c index 6e98af7b74db..1504295a21e4 100644 --- a/drivers/accel/amdxdna/aie2_message.c +++ b/drivers/accel/amdxdna/aie2_message.c @@ -27,43 +27,6 @@ #define EXEC_MSG_OPS(xdna) ((xdna)->dev_handle->exec_msg_ops) -void *aie2_alloc_msg_buffer(struct amdxdna_dev_hdl *ndev, u32 *size, - dma_addr_t *dma_addr) -{ - struct amdxdna_dev *xdna = ndev->aie.xdna; - void *vaddr; - int order; - - *size = max(*size, SZ_8K); - order = get_order(*size); - if (order > MAX_PAGE_ORDER) - return ERR_PTR(-EINVAL); - *size = PAGE_SIZE << order; - - if (amdxdna_iova_on(xdna)) - return amdxdna_iommu_alloc(xdna, *size, dma_addr); - - vaddr = dma_alloc_noncoherent(xdna->ddev.dev, *size, dma_addr, - DMA_FROM_DEVICE, GFP_KERNEL); - if (!vaddr) - return ERR_PTR(-ENOMEM); - - return vaddr; -} - -void aie2_free_msg_buffer(struct amdxdna_dev_hdl *ndev, size_t size, - void *cpu_addr, dma_addr_t dma_addr) -{ - struct amdxdna_dev *xdna = ndev->aie.xdna; - - if (amdxdna_iova_on(xdna)) { - amdxdna_iommu_free(xdna, size, cpu_addr, dma_addr); - return; - } - - dma_free_noncoherent(xdna->ddev.dev, size, cpu_addr, dma_addr, DMA_FROM_DEVICE); -} - int aie2_suspend_fw(struct amdxdna_dev_hdl *ndev) { DECLARE_AIE_MSG(suspend, MSG_OP_SUSPEND); @@ -127,7 +90,8 @@ int aie2_assign_mgmt_pasid(struct amdxdna_dev_hdl *ndev, u16 pasid) return aie_send_mgmt_msg_wait(&ndev->aie, &msg); } -int aie2_query_aie_version(struct amdxdna_dev_hdl *ndev, struct aie_version *version) +int aie2_query_aie_version(struct amdxdna_dev_hdl *ndev, + struct amdxdna_drm_query_aie_version *version) { DECLARE_AIE_MSG(aie_version_info, MSG_OP_QUERY_AIE_VERSION); struct amdxdna_dev *xdna = ndev->aie.xdna; @@ -146,7 +110,8 @@ int aie2_query_aie_version(struct amdxdna_dev_hdl *ndev, struct aie_version *ver return 0; } -int aie2_query_aie_metadata(struct amdxdna_dev_hdl *ndev, struct aie_metadata *metadata) +int aie2_query_aie_metadata(struct amdxdna_dev_hdl *ndev, + struct amdxdna_drm_query_aie_metadata *metadata) { DECLARE_AIE_MSG(aie_tile_info, MSG_OP_QUERY_AIE_TILE_INFO); int ret; @@ -155,7 +120,7 @@ int aie2_query_aie_metadata(struct amdxdna_dev_hdl *ndev, struct aie_metadata *m if (ret) return ret; - metadata->size = resp.info.size; + metadata->col_size = resp.info.size; metadata->cols = resp.info.cols; metadata->rows = resp.info.rows; @@ -375,8 +340,8 @@ int aie2_query_status(struct amdxdna_dev_hdl *ndev, char __user *buf, u8 *buff_addr; int ret; - buf_sz = ndev->metadata.cols * ndev->metadata.size; - buff_addr = aie2_alloc_msg_buffer(ndev, &buf_sz, &dma_addr); + buf_sz = ndev->aie.metadata.cols * ndev->aie.metadata.col_size; + buff_addr = amdxdna_alloc_msg_buffer(xdna, &buf_sz, &dma_addr); if (IS_ERR(buff_addr)) return PTR_ERR(buff_addr); @@ -390,7 +355,7 @@ int aie2_query_status(struct amdxdna_dev_hdl *ndev, char __user *buf, req.num_cols = hweight32(aie_bitmap); req.aie_bitmap = aie_bitmap; - drm_clflush_virt_range(buff_addr, size); /* device can access */ + drm_clflush_virt_range(buff_addr, req.dump_buff_size); /* device can access */ ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg); if (ret) { XDNA_ERR(xdna, "Error during NPU query, status %d", ret); @@ -415,7 +380,7 @@ int aie2_query_status(struct amdxdna_dev_hdl *ndev, char __user *buf, *cols_filled = aie_bitmap; fail: - aie2_free_msg_buffer(ndev, buf_sz, buff_addr, dma_addr); + amdxdna_free_msg_buffer(xdna, buf_sz, buff_addr, dma_addr); return ret; } @@ -434,7 +399,7 @@ int aie2_query_telemetry(struct amdxdna_dev_hdl *ndev, return -EINVAL; buf_sz = min(size, SZ_4M); - addr = aie2_alloc_msg_buffer(ndev, &buf_sz, &dma_addr); + addr = amdxdna_alloc_msg_buffer(xdna, &buf_sz, &dma_addr); if (IS_ERR(addr)) return PTR_ERR(addr); @@ -442,7 +407,7 @@ int aie2_query_telemetry(struct amdxdna_dev_hdl *ndev, req.buf_size = buf_sz; req.type = header->type; - drm_clflush_virt_range(addr, size); /* device can access */ + drm_clflush_virt_range(addr, req.buf_size); /* device can access */ ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg); if (ret) { XDNA_ERR(xdna, "Query telemetry failed, status %d", ret); @@ -466,7 +431,7 @@ int aie2_query_telemetry(struct amdxdna_dev_hdl *ndev, header->minor = resp.minor; free_buf: - aie2_free_msg_buffer(ndev, buf_sz, addr, dma_addr); + amdxdna_free_msg_buffer(xdna, buf_sz, addr, dma_addr); return ret; } @@ -1176,7 +1141,7 @@ int aie2_query_app_health(struct amdxdna_dev_hdl *ndev, u32 context_id, } buf_size = sizeof(*report); - buf = aie2_alloc_msg_buffer(ndev, &buf_size, &dma_addr); + buf = amdxdna_alloc_msg_buffer(xdna, &buf_size, &dma_addr); if (IS_ERR(buf)) { XDNA_ERR(xdna, "Failed to allocate buffer for app health"); return PTR_ERR(buf); @@ -1186,7 +1151,7 @@ int aie2_query_app_health(struct amdxdna_dev_hdl *ndev, u32 context_id, req.context_id = context_id; req.buf_size = buf_size; - drm_clflush_virt_range(buf, sizeof(*report)); + drm_clflush_virt_range(buf, req.buf_size); ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg); if (ret) { XDNA_ERR(xdna, "Get app health failed, ret %d status 0x%x", ret, resp.status); @@ -1197,7 +1162,7 @@ int aie2_query_app_health(struct amdxdna_dev_hdl *ndev, u32 context_id, memcpy(report, buf, sizeof(*report)); free_buf: - aie2_free_msg_buffer(ndev, buf_size, buf, dma_addr); + amdxdna_free_msg_buffer(xdna, buf_size, buf, dma_addr); return ret; } diff --git a/drivers/accel/amdxdna/aie2_pci.c b/drivers/accel/amdxdna/aie2_pci.c index f0ddb843eb21..6c8a0f70b73d 100644 --- a/drivers/accel/amdxdna/aie2_pci.c +++ b/drivers/accel/amdxdna/aie2_pci.c @@ -219,13 +219,13 @@ static int aie2_mgmt_fw_query(struct amdxdna_dev_hdl *ndev) return ret; } - ret = aie2_query_aie_metadata(ndev, &ndev->metadata); + ret = aie2_query_aie_metadata(ndev, &ndev->aie.metadata); if (ret) { XDNA_ERR(ndev->aie.xdna, "Query AIE metadata failed"); return ret; } - ndev->total_col = min(aie2_max_col, ndev->metadata.cols); + ndev->total_col = min(aie2_max_col, ndev->aie.metadata.cols); return 0; } @@ -658,53 +658,6 @@ static int aie2_get_aie_status(struct amdxdna_client *client, return 0; } -static int aie2_get_aie_metadata(struct amdxdna_client *client, - struct amdxdna_drm_get_info *args) -{ - struct amdxdna_drm_query_aie_metadata *meta; - struct amdxdna_dev *xdna = client->xdna; - struct amdxdna_dev_hdl *ndev; - int ret = 0; - u32 buf_sz; - - ndev = xdna->dev_handle; - meta = kzalloc_obj(*meta); - if (!meta) - return -ENOMEM; - - meta->col_size = ndev->metadata.size; - meta->cols = ndev->metadata.cols; - meta->rows = ndev->metadata.rows; - - meta->version.major = ndev->metadata.version.major; - meta->version.minor = ndev->metadata.version.minor; - - meta->core.row_count = ndev->metadata.core.row_count; - meta->core.row_start = ndev->metadata.core.row_start; - meta->core.dma_channel_count = ndev->metadata.core.dma_channel_count; - meta->core.lock_count = ndev->metadata.core.lock_count; - meta->core.event_reg_count = ndev->metadata.core.event_reg_count; - - meta->mem.row_count = ndev->metadata.mem.row_count; - meta->mem.row_start = ndev->metadata.mem.row_start; - meta->mem.dma_channel_count = ndev->metadata.mem.dma_channel_count; - meta->mem.lock_count = ndev->metadata.mem.lock_count; - meta->mem.event_reg_count = ndev->metadata.mem.event_reg_count; - - meta->shim.row_count = ndev->metadata.shim.row_count; - meta->shim.row_start = ndev->metadata.shim.row_start; - meta->shim.dma_channel_count = ndev->metadata.shim.dma_channel_count; - meta->shim.lock_count = ndev->metadata.shim.lock_count; - meta->shim.event_reg_count = ndev->metadata.shim.event_reg_count; - - buf_sz = min(args->buffer_size, sizeof(*meta)); - if (copy_to_user(u64_to_user_ptr(args->buffer), meta, buf_sz)) - ret = -EFAULT; - - kfree(meta); - return ret; -} - static int aie2_get_aie_version(struct amdxdna_client *client, struct amdxdna_drm_get_info *args) { @@ -1039,6 +992,7 @@ static int aie2_get_preempt_state(struct amdxdna_client *client, static int aie2_get_info(struct amdxdna_client *client, struct amdxdna_drm_get_info *args) { struct amdxdna_dev *xdna = client->xdna; + struct amdxdna_dev_hdl *ndev = xdna->dev_handle; int ret, idx; if (!drm_dev_enter(&xdna->ddev, &idx)) @@ -1053,7 +1007,7 @@ static int aie2_get_info(struct amdxdna_client *client, struct amdxdna_drm_get_i ret = aie2_get_aie_status(client, args); break; case DRM_AMDXDNA_QUERY_AIE_METADATA: - ret = aie2_get_aie_metadata(client, args); + ret = amdxdna_get_metadata(&ndev->aie, client, args); break; case DRM_AMDXDNA_QUERY_AIE_VERSION: ret = aie2_get_aie_version(client, args); diff --git a/drivers/accel/amdxdna/aie2_pci.h b/drivers/accel/amdxdna/aie2_pci.h index f12073175676..84bdb3f8b8f9 100644 --- a/drivers/accel/amdxdna/aie2_pci.h +++ b/drivers/accel/amdxdna/aie2_pci.h @@ -77,29 +77,6 @@ struct amdxdna_fw_ver; struct amdxdna_hwctx; struct amdxdna_sched_job; -struct aie_version { - u16 major; - u16 minor; -}; - -struct aie_tile_metadata { - u16 row_count; - u16 row_start; - u16 dma_channel_count; - u16 lock_count; - u16 event_reg_count; -}; - -struct aie_metadata { - u32 size; - u16 cols; - u16 rows; - struct aie_version version; - struct aie_tile_metadata core; - struct aie_tile_metadata mem; - struct aie_tile_metadata shim; -}; - enum rt_config_category { AIE2_RT_CFG_INIT, AIE2_RT_CFG_CLK_GATING, @@ -177,8 +154,7 @@ struct amdxdna_dev_hdl { void __iomem *mbox_base; u32 total_col; - struct aie_version version; - struct aie_metadata metadata; + struct amdxdna_drm_query_aie_version version; struct aie2_exec_msg_ops *exec_msg_ops; /* power management and clock*/ @@ -283,8 +259,10 @@ int aie2_resume_fw(struct amdxdna_dev_hdl *ndev); int aie2_set_runtime_cfg(struct amdxdna_dev_hdl *ndev, u32 type, u64 value); int aie2_get_runtime_cfg(struct amdxdna_dev_hdl *ndev, u32 type, u64 *value); int aie2_assign_mgmt_pasid(struct amdxdna_dev_hdl *ndev, u16 pasid); -int aie2_query_aie_version(struct amdxdna_dev_hdl *ndev, struct aie_version *version); -int aie2_query_aie_metadata(struct amdxdna_dev_hdl *ndev, struct aie_metadata *metadata); +int aie2_query_aie_version(struct amdxdna_dev_hdl *ndev, + struct amdxdna_drm_query_aie_version *version); +int aie2_query_aie_metadata(struct amdxdna_dev_hdl *ndev, + struct amdxdna_drm_query_aie_metadata *metadata); int aie2_query_firmware_version(struct amdxdna_dev_hdl *ndev, struct amdxdna_fw_ver *fw_ver); int aie2_query_app_health(struct amdxdna_dev_hdl *ndev, u32 context_id, @@ -314,10 +292,6 @@ int aie2_sync_bo(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *job, int aie2_config_debug_bo(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *job, int (*notify_cb)(void *, void __iomem *, size_t)); int aie2_update_prop_time_quota(struct amdxdna_dev_hdl *ndev, u32 us); -void *aie2_alloc_msg_buffer(struct amdxdna_dev_hdl *ndev, u32 *size, - dma_addr_t *dma_addr); -void aie2_free_msg_buffer(struct amdxdna_dev_hdl *ndev, size_t size, - void *cpu_addr, dma_addr_t dma_addr); /* aie2_hwctx.c */ int aie2_hwctx_init(struct amdxdna_hwctx *hwctx); diff --git a/drivers/accel/amdxdna/aie4_ctx.c b/drivers/accel/amdxdna/aie4_ctx.c new file mode 100644 index 000000000000..8408b0d2696f --- /dev/null +++ b/drivers/accel/amdxdna/aie4_ctx.c @@ -0,0 +1,333 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026, Advanced Micro Devices, Inc. + */ + +#include <drm/amdxdna_accel.h> +#include <drm/drm_device.h> +#include <drm/drm_gem.h> +#include <drm/drm_gem_shmem_helper.h> +#include <drm/drm_print.h> +#include <drm/gpu_scheduler.h> +#include <linux/types.h> + +#include "aie.h" +#include "aie4_host_queue.h" +#include "aie4_msg_priv.h" +#include "aie4_pci.h" +#include "amdxdna_ctx.h" +#include "amdxdna_gem.h" +#include "amdxdna_mailbox.h" +#include "amdxdna_mailbox_helper.h" +#include "amdxdna_pci_drv.h" + +static irqreturn_t cert_comp_isr(int irq, void *p) +{ + struct cert_comp *cert_comp = p; + + wake_up_all(&cert_comp->waitq); + return IRQ_HANDLED; +} + +static struct cert_comp *aie4_lookup_cert_comp(struct amdxdna_dev_hdl *ndev, u32 msix_idx) +{ + struct amdxdna_dev *xdna = ndev->aie.xdna; + struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev); + struct cert_comp *cert_comp; + int ret; + + guard(mutex)(&ndev->cert_comp_lock); + + cert_comp = xa_load(&ndev->cert_comp_xa, msix_idx); + if (cert_comp) { + kref_get(&cert_comp->kref); + return cert_comp; + } + + cert_comp = kzalloc_obj(*cert_comp); + if (!cert_comp) + return NULL; + + cert_comp->ndev = ndev; + cert_comp->msix_idx = msix_idx; + init_waitqueue_head(&cert_comp->waitq); + kref_init(&cert_comp->kref); + + ret = pci_irq_vector(pdev, cert_comp->msix_idx); + if (ret < 0) { + XDNA_ERR(xdna, "MSI-X idx %u is invalid, ret:%d", msix_idx, ret); + goto free_cert_comp; + } + cert_comp->irq = ret; + + ret = request_irq(cert_comp->irq, cert_comp_isr, 0, "xdna_hsa", cert_comp); + if (ret) { + XDNA_ERR(xdna, "request irq %d failed %d", cert_comp->irq, ret); + goto free_cert_comp; + } + + ret = xa_err(xa_store(&ndev->cert_comp_xa, msix_idx, cert_comp, GFP_KERNEL)); + if (ret) { + XDNA_ERR(xdna, "store cert_comp for msix idx %d failed %d", msix_idx, ret); + goto free_irq; + } + + return cert_comp; + +free_irq: + free_irq(cert_comp->irq, cert_comp); +free_cert_comp: + kfree(cert_comp); + return NULL; +} + +static void cert_comp_release(struct kref *kref) +{ + struct cert_comp *cert_comp = container_of(kref, struct cert_comp, kref); + struct amdxdna_dev_hdl *ndev = cert_comp->ndev; + + drm_WARN_ON(&ndev->aie.xdna->ddev, !mutex_is_locked(&ndev->cert_comp_lock)); + + xa_erase(&ndev->cert_comp_xa, cert_comp->msix_idx); + free_irq(cert_comp->irq, cert_comp); + kfree(cert_comp); +} + +static void aie4_put_cert_comp(struct cert_comp *cert_comp) +{ + struct amdxdna_dev_hdl *ndev; + + ndev = cert_comp->ndev; + guard(mutex)(&ndev->cert_comp_lock); + kref_put(&cert_comp->kref, cert_comp_release); +} + +static int aie4_msg_destroy_context(struct amdxdna_dev_hdl *ndev, u32 hw_context_id) +{ + DECLARE_AIE_MSG(aie4_msg_destroy_hw_context, AIE4_MSG_OP_DESTROY_HW_CONTEXT); + + req.hw_context_id = hw_context_id; + return aie_send_mgmt_msg_wait(&ndev->aie, &msg); +} + +static int aie4_hwctx_create(struct amdxdna_hwctx *hwctx) +{ + DECLARE_AIE_MSG(aie4_msg_create_hw_context, AIE4_MSG_OP_CREATE_HW_CONTEXT); + struct amdxdna_client *client = hwctx->client; + struct amdxdna_hwctx_priv *priv = hwctx->priv; + struct amdxdna_dev *xdna = hwctx->client->xdna; + struct amdxdna_dev_hdl *ndev = xdna->dev_handle; + int ret; + + drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock)); + + if (!ndev->partition_id || !hwctx->num_tiles) { + XDNA_ERR(xdna, "invalid request partition_id %d, num_tiles %d", + ndev->partition_id, hwctx->num_tiles); + return -EINVAL; + } + + req.partition_id = ndev->partition_id; + req.request_num_tiles = hwctx->num_tiles; + req.pasid = FIELD_PREP(AIE4_MSG_PASID, client->pasid) | + FIELD_PREP(AIE4_MSG_PASID_VLD, 1); + req.priority_band = hwctx->qos.priority; + + req.hsa_addr_high = upper_32_bits(amdxdna_gem_dev_addr(priv->umq_bo)); + req.hsa_addr_low = lower_32_bits(amdxdna_gem_dev_addr(priv->umq_bo)); + + XDNA_DBG(xdna, "pasid 0x%x, num_tiles %d, hsa[0x%x 0x%x]", + req.pasid, req.request_num_tiles, req.hsa_addr_high, req.hsa_addr_low); + + ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg); + if (ret) { + XDNA_ERR(xdna, "create ctx failed: %d", ret); + return ret; + } + + XDNA_DBG(xdna, "resp msix: %d, ctx id: %d, doorbell: %d", + resp.job_complete_msix_idx, + resp.hw_context_id, + resp.doorbell_offset); + + /* setup interrupt completion per msix index */ + priv->cert_comp = aie4_lookup_cert_comp(ndev, resp.job_complete_msix_idx); + if (!priv->cert_comp) { + aie4_msg_destroy_context(ndev, resp.hw_context_id); + return -EINVAL; + } + + priv->hw_ctx_id = resp.hw_context_id; + hwctx->doorbell_offset = resp.doorbell_offset; + + return 0; +} + +static void aie4_hwctx_destroy(struct amdxdna_hwctx *hwctx) +{ + struct amdxdna_client *client = hwctx->client; + struct amdxdna_hwctx_priv *priv = hwctx->priv; + struct amdxdna_dev *xdna = client->xdna; + struct amdxdna_dev_hdl *ndev = xdna->dev_handle; + + drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock)); + + aie4_msg_destroy_context(ndev, priv->hw_ctx_id); + aie4_put_cert_comp(priv->cert_comp); +} + +static void aie4_hwctx_umq_fini(struct amdxdna_hwctx *hwctx) +{ + if (hwctx->priv && hwctx->priv->umq_bo) + amdxdna_gem_put_obj(hwctx->priv->umq_bo); +} + +static int aie4_hwctx_umq_init(struct amdxdna_hwctx *hwctx) +{ + struct amdxdna_hwctx_priv *priv = hwctx->priv; + struct amdxdna_dev *xdna = hwctx->client->xdna; + struct amdxdna_gem_obj *umq_bo; + struct host_queue_header *qhdr; + int ret; + + umq_bo = amdxdna_gem_get_obj(hwctx->client, hwctx->umq_bo_hdl, AMDXDNA_BO_SHARE); + if (!umq_bo) { + XDNA_ERR(xdna, "cannot find umq_bo handle %d", hwctx->umq_bo_hdl); + return -ENOENT; + } + if (umq_bo->mem.size < sizeof(*qhdr)) { + XDNA_ERR(xdna, "umq_bo size is too small"); + ret = -EINVAL; + goto put_umq_bo; + } + + /* get kva address for host queue read index and write index */ + qhdr = amdxdna_gem_vmap(umq_bo); + if (!qhdr) { + ret = -ENOMEM; + goto put_umq_bo; + } + + priv->umq_bo = umq_bo; + priv->umq_read_index = &qhdr->read_index; + priv->umq_write_index = &qhdr->write_index; + + return 0; + +put_umq_bo: + amdxdna_gem_put_obj(umq_bo); + return ret; +} + +int aie4_hwctx_init(struct amdxdna_hwctx *hwctx) +{ + struct amdxdna_client *client = hwctx->client; + struct amdxdna_dev *xdna = client->xdna; + struct amdxdna_hwctx_priv *priv; + int ret; + + priv = kzalloc_obj(*priv); + if (!priv) + return -ENOMEM; + hwctx->priv = priv; + + ret = aie4_hwctx_umq_init(hwctx); + if (ret) + goto free_priv; + + ret = aie4_hwctx_create(hwctx); + if (ret) + goto umq_fini; + + XDNA_DBG(xdna, "hwctx %s init completed", hwctx->name); + return 0; + +umq_fini: + aie4_hwctx_umq_fini(hwctx); +free_priv: + kfree(priv); + hwctx->priv = NULL; + return ret; +} + +void aie4_hwctx_fini(struct amdxdna_hwctx *hwctx) +{ + aie4_hwctx_destroy(hwctx); + aie4_hwctx_umq_fini(hwctx); + kfree(hwctx->priv); +} + +static inline bool valid_queue_index(u64 read, u64 write, u32 capacity) +{ + return (write >= read) && ((write - read) <= capacity); +} + +static u64 get_read_index(struct amdxdna_hwctx *hwctx) +{ + u64 wi = READ_ONCE(*hwctx->priv->umq_write_index); + u64 ri = READ_ONCE(*hwctx->priv->umq_read_index); + struct amdxdna_dev *xdna = hwctx->client->xdna; + + /* + * CERT cannot update read index as uint64 atomically. Driver may read + * half-updated read index when it has bits in high 32bit. In case read + * index is not valid, wait for some time and retry once. It should + * allow CERT to complete the read index update. + */ + if (!valid_queue_index(ri, wi, CTX_MAX_CMDS)) { + XDNA_WARN(xdna, "Invalid index, ri %llu, wi %llu", ri, wi); + usleep_range(100, 200); + ri = READ_ONCE(*hwctx->priv->umq_read_index); + if (!valid_queue_index(ri, wi, CTX_MAX_CMDS)) { + XDNA_ERR(xdna, "Invalid index after retry, ri %llu, wi %llu", ri, wi); + ri = 0; + } + } + + return ri; +} + +static inline bool check_cmd_done(struct amdxdna_hwctx *hwctx, u64 seq) +{ + u64 read_idx = get_read_index(hwctx); + + return read_idx > seq; +} + +int aie4_cmd_wait(struct amdxdna_hwctx *hwctx, u64 seq, u32 timeout) +{ + unsigned long wait_jifs = MAX_SCHEDULE_TIMEOUT; + struct amdxdna_hwctx_priv *priv = hwctx->priv; + struct cert_comp *cert_comp = priv->cert_comp; + long ret; + + if (timeout) + wait_jifs = msecs_to_jiffies(timeout); + + ret = wait_event_interruptible_timeout(cert_comp->waitq, + (check_cmd_done(hwctx, seq)), + wait_jifs); + + if (!ret) + ret = -ETIME; + + return ret <= 0 ? ret : 0; +} + +int aie4_hwctx_valid_doorbell(struct amdxdna_client *client, u32 vm_pgoff) +{ + struct amdxdna_hwctx *hwctx; + unsigned long hwctx_id; + int idx; + + idx = srcu_read_lock(&client->hwctx_srcu); + amdxdna_for_each_hwctx(client, hwctx_id, hwctx) { + if (vm_pgoff == (hwctx->doorbell_offset >> PAGE_SHIFT)) { + srcu_read_unlock(&client->hwctx_srcu, idx); + return 1; + } + } + srcu_read_unlock(&client->hwctx_srcu, idx); + + return 0; +} diff --git a/drivers/accel/amdxdna/aie4_host_queue.h b/drivers/accel/amdxdna/aie4_host_queue.h new file mode 100644 index 000000000000..1b33eda3f727 --- /dev/null +++ b/drivers/accel/amdxdna/aie4_host_queue.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2026, Advanced Micro Devices, Inc. + */ + +#ifndef _AIE4_HOST_QUEUE_H_ +#define _AIE4_HOST_QUEUE_H_ + +#include <linux/types.h> + +#define CTX_MAX_CMDS 32 + +struct host_queue_header { + __u64 read_index; + struct { + __u16 major; + __u16 minor; + } version; + __u32 capacity; /* Queue capacity, must be power of two. */ + __u64 write_index; + __u64 data_address; /* The xdna dev addr for payload. */ +}; + +#endif /* _AIE4_HOST_QUEUE_H_ */ diff --git a/drivers/accel/amdxdna/aie4_message.c b/drivers/accel/amdxdna/aie4_message.c index d621dd32ac40..88037edbb02a 100644 --- a/drivers/accel/amdxdna/aie4_message.c +++ b/drivers/accel/amdxdna/aie4_message.c @@ -25,3 +25,59 @@ int aie4_suspend_fw(struct amdxdna_dev_hdl *ndev) return ret; } + +int aie4_query_aie_metadata(struct amdxdna_dev_hdl *ndev, + struct amdxdna_drm_query_aie_metadata *metadata) +{ + DECLARE_AIE_MSG(aie4_msg_aie4_tile_info, AIE4_MSG_OP_AIE_TILE_INFO); + int ret; + + ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg); + if (ret) + return ret; + + metadata->col_size = resp.info.size; + metadata->cols = resp.info.cols; + metadata->rows = resp.info.rows; + + metadata->version.major = resp.info.major; + metadata->version.minor = resp.info.minor; + + metadata->core.row_count = resp.info.core_rows; + metadata->core.row_start = resp.info.core_row_start; + metadata->core.dma_channel_count = resp.info.core_dma_channels; + metadata->core.lock_count = resp.info.core_locks; + metadata->core.event_reg_count = resp.info.core_events; + + metadata->mem.row_count = resp.info.mem_rows; + metadata->mem.row_start = resp.info.mem_row_start; + metadata->mem.dma_channel_count = resp.info.mem_dma_channels; + metadata->mem.lock_count = resp.info.mem_locks; + metadata->mem.event_reg_count = resp.info.mem_events; + + metadata->shim.row_count = resp.info.shim_rows; + metadata->shim.row_start = resp.info.shim_row_start; + metadata->shim.dma_channel_count = resp.info.shim_dma_channels; + metadata->shim.lock_count = resp.info.shim_locks; + metadata->shim.event_reg_count = resp.info.shim_events; + + return 0; +} + +int aie4_attach_work_buffer(struct amdxdna_dev_hdl *ndev) +{ + DECLARE_AIE_MSG(aie4_msg_attach_work_buffer, AIE4_MSG_OP_ATTACH_WORK_BUFFER); + struct amdxdna_dev *xdna = ndev->aie.xdna; + int ret; + + req.buff_addr = ndev->work_buf_addr; + req.buff_size = AIE4_WORK_BUFFER_MIN_SIZE; + + ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg); + if (ret) + XDNA_ERR(xdna, "Failed to attach work buffer, ret %d", ret); + else + XDNA_DBG(xdna, "Attached work buffer"); + + return ret; +} diff --git a/drivers/accel/amdxdna/aie4_msg_priv.h b/drivers/accel/amdxdna/aie4_msg_priv.h index 88463cc3a98a..af0866045b91 100644 --- a/drivers/accel/amdxdna/aie4_msg_priv.h +++ b/drivers/accel/amdxdna/aie4_msg_priv.h @@ -6,13 +6,21 @@ #ifndef _AIE4_MSG_PRIV_H_ #define _AIE4_MSG_PRIV_H_ +#include <linux/sizes.h> #include <linux/types.h> enum aie4_msg_opcode { AIE4_MSG_OP_SUSPEND = 0x10003, + AIE4_MSG_OP_ATTACH_WORK_BUFFER = 0x1000D, AIE4_MSG_OP_CREATE_VFS = 0x20001, AIE4_MSG_OP_DESTROY_VFS = 0x20002, + + AIE4_MSG_OP_CREATE_PARTITION = 0x30001, + AIE4_MSG_OP_DESTROY_PARTITION = 0x30002, + AIE4_MSG_OP_CREATE_HW_CONTEXT = 0x30003, + AIE4_MSG_OP_DESTROY_HW_CONTEXT = 0x30004, + AIE4_MSG_OP_AIE_TILE_INFO = 0x30006, }; enum aie4_msg_status { @@ -46,4 +54,94 @@ struct aie4_msg_destroy_vfs_resp { enum aie4_msg_status status; } __packed; +struct aie4_msg_create_partition_req { + __u32 partition_col_start; + __u32 partition_col_count; +} __packed; + +struct aie4_msg_create_partition_resp { + enum aie4_msg_status status; + __u32 partition_id; +} __packed; + +struct aie4_msg_destroy_partition_req { + __u32 partition_id; +} __packed; + +struct aie4_msg_destroy_partition_resp { + enum aie4_msg_status status; +} __packed; + +struct aie4_msg_create_hw_context_req { + __u32 partition_id; + __u32 request_num_tiles; + __u32 hsa_addr_high; + __u32 hsa_addr_low; +#define AIE4_MSG_PASID GENMASK(19, 0) +#define AIE4_MSG_PASID_VLD GENMASK(31, 31) + __u32 pasid; + __u32 priority_band; +} __packed; + +struct aie4_msg_create_hw_context_resp { + enum aie4_msg_status status; + __u32 hw_context_id; + __u32 doorbell_offset; + __u32 job_complete_msix_idx; +} __packed; + +struct aie4_msg_destroy_hw_context_req { + __u32 hw_context_id; + __u32 resvd1; +} __packed; + +struct aie4_msg_destroy_hw_context_resp { + enum aie4_msg_status status; +} __packed; + +struct aie4_tile_info { + __u32 size; + __u16 major; + __u16 minor; + __u16 cols; + __u16 rows; + __u16 core_rows; + __u16 mem_rows; + __u16 shim_rows; + __u16 core_row_start; + __u16 mem_row_start; + __u16 shim_row_start; + __u16 core_dma_channels; + __u16 mem_dma_channels; + __u16 shim_dma_channels; + __u16 core_locks; + __u16 mem_locks; + __u16 shim_locks; + __u16 core_events; + __u16 mem_events; + __u16 shim_events; + __u16 resvd; +} __packed; + +struct aie4_msg_aie4_tile_info_req { + __u32 resvd; +} __packed; + +struct aie4_msg_aie4_tile_info_resp { + enum aie4_msg_status status; + struct aie4_tile_info info; +} __packed; + +#define AIE4_WORK_BUFFER_MIN_SIZE SZ_4M + +struct aie4_msg_attach_work_buffer_req { + __u64 buff_addr; + __u32 reserved; + __u32 buff_size; +} __packed; + +struct aie4_msg_attach_work_buffer_resp { + enum aie4_msg_status status; +} __packed; + #endif /* _AIE4_MSG_PRIV_H_ */ diff --git a/drivers/accel/amdxdna/aie4_pci.c b/drivers/accel/amdxdna/aie4_pci.c index 87f80f804f91..a58a83af42a4 100644 --- a/drivers/accel/amdxdna/aie4_pci.c +++ b/drivers/accel/amdxdna/aie4_pci.c @@ -9,11 +9,16 @@ #include <linux/firmware.h> #include <linux/sizes.h> +#include "aie.h" +#include "aie4_msg_priv.h" #include "aie4_pci.h" +#include "amdxdna_mailbox.h" +#include "amdxdna_mailbox_helper.h" #include "amdxdna_pci_drv.h" #define NO_IOHUB 0 #define PSP_NOTIFY_INTR 0xD007BE11 +#define AIE4_TOTAL_COLUMN 3 /* * The management mailbox channel is allocated by firmware. @@ -196,8 +201,9 @@ free_channel: return ret; } -static int aie4_mailbox_init(struct amdxdna_dev *xdna) +static int aie4_mailbox_init(struct amdxdna_dev_hdl *ndev) { + struct amdxdna_dev *xdna = ndev->aie.xdna; struct mailbox_info mbox_info; int ret; @@ -208,13 +214,13 @@ static int aie4_mailbox_init(struct amdxdna_dev *xdna) return aie4_mailbox_start(xdna, &mbox_info); } -static void aie4_fw_unload(struct amdxdna_dev_hdl *ndev) +static void aie4_fw_stop(struct amdxdna_dev_hdl *ndev) { aie_psp_stop(ndev->aie.psp_hdl); aie_smu_fini(ndev->aie.smu_hdl); } -static int aie4_fw_load(struct amdxdna_dev_hdl *ndev) +static int aie4_fw_start(struct amdxdna_dev_hdl *ndev) { int ret; @@ -233,49 +239,109 @@ static int aie4_fw_load(struct amdxdna_dev_hdl *ndev) return ret; } -static int aie4_hw_start(struct amdxdna_dev *xdna) +static int aie4_partition_init(struct amdxdna_dev_hdl *ndev) { - struct amdxdna_dev_hdl *ndev = xdna->dev_handle; + DECLARE_AIE_MSG(aie4_msg_create_partition, AIE4_MSG_OP_CREATE_PARTITION); + struct amdxdna_dev *xdna = ndev->aie.xdna; int ret; - ret = aie4_fw_load(ndev); + req.partition_col_start = 0; + req.partition_col_count = AIE4_TOTAL_COLUMN; + ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg); + if (ret) { + XDNA_ERR(xdna, "partition init failed: %d", ret); + return ret; + } + + ndev->partition_id = resp.partition_id; + return 0; +} + +static void aie4_partition_fini(struct amdxdna_dev_hdl *ndev) +{ + DECLARE_AIE_MSG(aie4_msg_destroy_partition, AIE4_MSG_OP_DESTROY_PARTITION); + struct amdxdna_dev *xdna = ndev->aie.xdna; + int ret; + + req.partition_id = ndev->partition_id; + ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg); + if (ret) + XDNA_ERR(xdna, "partition fini failed: %d", ret); +} + +static int aie4_query(struct amdxdna_dev_hdl *ndev) +{ + return aie4_query_aie_metadata(ndev, &ndev->aie.metadata); +} + +static int aie4_pf_hw_start(struct amdxdna_dev_hdl *ndev) +{ + int ret; + + ret = aie4_fw_start(ndev); if (ret) return ret; - ret = aie4_mailbox_init(xdna); + ret = aie4_mailbox_init(ndev); if (ret) - goto fw_unload; + goto stop_fw; + + ret = aie4_attach_work_buffer(ndev); + if (ret) + goto mbox_fini; return 0; -fw_unload: - aie4_fw_unload(ndev); +mbox_fini: + aie4_mailbox_fini(ndev); +stop_fw: + aie4_fw_stop(ndev); return ret; } -static void aie4_mgmt_fw_fini(struct amdxdna_dev_hdl *ndev) +static void aie4_pf_hw_stop(struct amdxdna_dev_hdl *ndev) +{ + struct amdxdna_dev *xdna = ndev->aie.xdna; + + drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock)); + + aie4_suspend_fw(ndev); + aie4_mailbox_fini(ndev); + aie4_fw_stop(ndev); +} + +static int aie4_vf_hw_start(struct amdxdna_dev_hdl *ndev) { int ret; - /* No paired resume needed, fw is stateless */ - ret = aie4_suspend_fw(ndev); + ret = aie4_mailbox_init(ndev); + if (ret) + return ret; + + ret = aie4_query(ndev); if (ret) - XDNA_ERR(ndev->aie.xdna, "suspend_fw failed, ret %d", ret); - else - XDNA_DBG(ndev->aie.xdna, "npu firmware suspended"); + goto mailbox_fini; + + ret = aie4_partition_init(ndev); + if (ret) + goto mailbox_fini; + + return 0; + +mailbox_fini: + aie4_mailbox_fini(ndev); + return ret; } -static void aie4_hw_stop(struct amdxdna_dev *xdna) +static void aie4_vf_hw_stop(struct amdxdna_dev_hdl *ndev) { - struct amdxdna_dev_hdl *ndev = xdna->dev_handle; + struct amdxdna_dev *xdna = ndev->aie.xdna; drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock)); - aie4_mgmt_fw_fini(ndev); + aie4_partition_fini(ndev); aie4_mailbox_fini(ndev); - - aie4_fw_unload(ndev); } static int aie4_request_firmware(struct amdxdna_dev_hdl *ndev, @@ -365,15 +431,44 @@ static int aie4_prepare_firmware(struct amdxdna_dev_hdl *ndev, return 0; } -static int aie4_pcidev_init(struct amdxdna_dev_hdl *ndev) +static int aie4_load_fw(struct amdxdna_dev_hdl *ndev, + void __iomem *tbl[PCI_NUM_RESOURCES]) +{ + const struct firmware *npufw, *certfw; + int ret; + + if (!ndev->priv->npufw_path && !ndev->priv->certfw_path) + return 0; + + ret = aie4_request_firmware(ndev, &npufw, &certfw); + if (ret) + return ret; + + ret = aie4_prepare_firmware(ndev, npufw, certfw, tbl); + aie4_release_firmware(ndev, npufw, certfw); + + return ret; +} + +static int aie4m_pcidev_init(struct amdxdna_dev *xdna) { - struct amdxdna_dev *xdna = ndev->aie.xdna; struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev); + struct amdxdna_dev_hdl *ndev; void __iomem *tbl[PCI_NUM_RESOURCES] = {0}; - const struct firmware *npufw, *certfw; unsigned long bars = 0; int ret, i; + ndev = drmm_kzalloc(&xdna->ddev, sizeof(*ndev), GFP_KERNEL); + if (!ndev) + return -ENOMEM; + + ndev->priv = xdna->dev_info->dev_priv; + ndev->aie.xdna = xdna; + xdna->dev_handle = ndev; + + xa_init_flags(&ndev->cert_comp_xa, XA_FLAGS_ALLOC); + mutex_init(&ndev->cert_comp_lock); + /* Enable managed PCI device */ ret = pcim_enable_device(pdev); if (ret) { @@ -409,75 +504,164 @@ static int aie4_pcidev_init(struct amdxdna_dev_hdl *ndev) pci_set_master(pdev); - ret = aie4_request_firmware(ndev, &npufw, &certfw); - if (ret) - goto clear_master; - - ret = aie4_prepare_firmware(ndev, npufw, certfw, tbl); - aie4_release_firmware(ndev, npufw, certfw); + ret = aie4_load_fw(ndev, tbl); if (ret) - goto clear_master; + return ret; ret = aie4_irq_init(xdna); if (ret) - goto clear_master; + return ret; - ret = aie4_hw_start(xdna); - if (ret) - goto clear_master; + amdxdna_vbnv_init(xdna); + XDNA_DBG(xdna, "init finished"); return 0; +} -clear_master: - pci_clear_master(pdev); +static int aie4_doorbell_mmap(struct amdxdna_client *client, struct vm_area_struct *vma) +{ + struct amdxdna_dev *xdna = client->xdna; + struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev); + const struct amdxdna_dev_priv *npriv = xdna->dev_info->dev_priv; + phys_addr_t res_start; + unsigned long pfn; + int ret; + + if (!aie4_hwctx_valid_doorbell(client, vma->vm_pgoff)) { + XDNA_ERR(xdna, "Invalid doorbell page offset 0x%lx", vma->vm_pgoff); + return -EINVAL; + } + + if (vma_pages(vma) != 1) { + XDNA_ERR(xdna, "can only map one page, got %ld", vma_pages(vma)); + return -EINVAL; + } + + res_start = pci_resource_start(pdev, xdna->dev_info->doorbell_bar) + npriv->doorbell_off; + pfn = PHYS_PFN(res_start) + vma->vm_pgoff; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + vm_flags_set(vma, VM_IO | VM_DONTEXPAND | VM_DONTDUMP); + ret = io_remap_pfn_range(vma, vma->vm_start, + pfn, + PAGE_SIZE, + vma->vm_page_prot); + + XDNA_DBG(xdna, "doorbell ret %d", ret); + return ret; +} + +static int aie4_get_info(struct amdxdna_client *client, struct amdxdna_drm_get_info *args) +{ + struct amdxdna_dev *xdna = client->xdna; + struct amdxdna_dev_hdl *ndev = xdna->dev_handle; + int ret; + + switch (args->param) { + case DRM_AMDXDNA_QUERY_AIE_METADATA: + ret = amdxdna_get_metadata(&ndev->aie, client, args); + break; + default: + XDNA_ERR(xdna, "Not supported request parameter %u", args->param); + ret = -EOPNOTSUPP; + } + + XDNA_DBG(xdna, "Got param %d", args->param); return ret; } -static void aie4_pcidev_fini(struct amdxdna_dev_hdl *ndev) +static int aie4_alloc_work_buffer(struct amdxdna_dev_hdl *ndev) { struct amdxdna_dev *xdna = ndev->aie.xdna; - struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev); + u32 buf_size = AIE4_WORK_BUFFER_MIN_SIZE; - aie4_hw_stop(xdna); + ndev->work_buf = amdxdna_alloc_msg_buffer(xdna, &buf_size, + &ndev->work_buf_addr); + if (IS_ERR(ndev->work_buf)) { + int ret = PTR_ERR(ndev->work_buf); - pci_clear_master(pdev); + XDNA_ERR(xdna, "Failed to alloc work buffer, size 0x%x", + AIE4_WORK_BUFFER_MIN_SIZE); + ndev->work_buf = NULL; + return ret; + } + + ndev->work_buf_size = buf_size; + XDNA_DBG(xdna, "Work buffer allocated: size 0x%x", buf_size); + + return 0; } -static void aie4_fini(struct amdxdna_dev *xdna) +static void aie4_free_work_buffer(struct amdxdna_dev_hdl *ndev) { - struct amdxdna_dev_hdl *ndev = xdna->dev_handle; + struct amdxdna_dev *xdna = ndev->aie.xdna; + + if (!ndev->work_buf) + return; - aie4_sriov_stop(ndev); - aie4_pcidev_fini(ndev); + amdxdna_free_msg_buffer(xdna, ndev->work_buf_size, ndev->work_buf, + ndev->work_buf_addr); + ndev->work_buf = NULL; } -static int aie4_init(struct amdxdna_dev *xdna) +static int aie4_pf_init(struct amdxdna_dev *xdna) { - struct amdxdna_dev_hdl *ndev; int ret; - ndev = drmm_kzalloc(&xdna->ddev, sizeof(*ndev), GFP_KERNEL); - if (!ndev) - return -ENOMEM; - - ndev->priv = xdna->dev_info->dev_priv; - ndev->aie.xdna = xdna; - xdna->dev_handle = ndev; + ret = aie4m_pcidev_init(xdna); + if (ret) + return ret; - ret = aie4_pcidev_init(ndev); - if (ret) { - XDNA_ERR(xdna, "Setup PCI device failed, ret %d", ret); + ret = aie4_alloc_work_buffer(xdna->dev_handle); + if (ret) return ret; - } - amdxdna_vbnv_init(xdna); - XDNA_DBG(xdna, "aie4 init finished"); + ret = aie4_pf_hw_start(xdna->dev_handle); + if (ret) + goto free_work_buf; + return 0; + +free_work_buf: + aie4_free_work_buffer(xdna->dev_handle); + return ret; +} + +static int aie4_vf_init(struct amdxdna_dev *xdna) +{ + int ret; + + ret = aie4m_pcidev_init(xdna); + if (ret) + return ret; + + return aie4_vf_hw_start(xdna->dev_handle); } -const struct amdxdna_dev_ops aie4_ops = { - .init = aie4_init, - .fini = aie4_fini, +static void aie4_pf_fini(struct amdxdna_dev *xdna) +{ + aie4_sriov_stop(xdna->dev_handle); + aie4_pf_hw_stop(xdna->dev_handle); + aie4_free_work_buffer(xdna->dev_handle); +} + +static void aie4_vf_fini(struct amdxdna_dev *xdna) +{ + aie4_vf_hw_stop(xdna->dev_handle); +} + +const struct amdxdna_dev_ops aie4_pf_ops = { + .init = aie4_pf_init, + .fini = aie4_pf_fini, .sriov_configure = aie4_sriov_configure, }; + +const struct amdxdna_dev_ops aie4_vf_ops = { + .init = aie4_vf_init, + .fini = aie4_vf_fini, + .hwctx_init = aie4_hwctx_init, + .hwctx_fini = aie4_hwctx_fini, + .mmap = aie4_doorbell_mmap, + .cmd_wait = aie4_cmd_wait, + .get_aie_info = aie4_get_info, +}; diff --git a/drivers/accel/amdxdna/aie4_pci.h b/drivers/accel/amdxdna/aie4_pci.h index aa1495c3370b..3fd5eace3ed7 100644 --- a/drivers/accel/amdxdna/aie4_pci.h +++ b/drivers/accel/amdxdna/aie4_pci.h @@ -13,12 +13,30 @@ #include "aie.h" #include "amdxdna_mailbox.h" +struct cert_comp { + struct amdxdna_dev_hdl *ndev; + u32 msix_idx; + int irq; + struct kref kref; + wait_queue_head_t waitq; +}; + +struct amdxdna_hwctx_priv { + struct amdxdna_gem_obj *umq_bo; + u64 *umq_read_index; + u64 *umq_write_index; + + struct cert_comp *cert_comp; + u32 hw_ctx_id; +}; + struct amdxdna_dev_priv { const char *npufw_path; const char *certfw_path; u32 mbox_bar; u32 mbox_rbuf_bar; u64 mbox_info_off; + u32 doorbell_off; struct aie_bar_off_pair psp_regs_off[PSP_MAX_REGS]; struct aie_bar_off_pair smu_regs_off[SMU_MAX_REGS]; @@ -31,10 +49,27 @@ struct amdxdna_dev_hdl { void __iomem *rbuf_base; struct mailbox *mbox; + u32 partition_id; + + struct xarray cert_comp_xa; /* device level indexed by msix id */ + struct mutex cert_comp_lock; /* protects cert_comp operations*/ + + void *work_buf; + dma_addr_t work_buf_addr; + u32 work_buf_size; }; /* aie4_message.c */ +int aie4_query_aie_metadata(struct amdxdna_dev_hdl *ndev, + struct amdxdna_drm_query_aie_metadata *metadata); int aie4_suspend_fw(struct amdxdna_dev_hdl *ndev); +int aie4_attach_work_buffer(struct amdxdna_dev_hdl *ndev); + +/* aie4_ctx.c */ +int aie4_hwctx_init(struct amdxdna_hwctx *hwctx); +void aie4_hwctx_fini(struct amdxdna_hwctx *hwctx); +int aie4_cmd_wait(struct amdxdna_hwctx *hwctx, u64 seq, u32 timeout); +int aie4_hwctx_valid_doorbell(struct amdxdna_client *client, u32 vm_pgoff); /* aie4_sriov.c */ #if IS_ENABLED(CONFIG_PCI_IOV) @@ -48,6 +83,7 @@ static inline int aie4_sriov_stop(struct amdxdna_dev_hdl *ndev) } #endif -extern const struct amdxdna_dev_ops aie4_ops; +extern const struct amdxdna_dev_ops aie4_pf_ops; +extern const struct amdxdna_dev_ops aie4_vf_ops; #endif /* _AIE4_PCI_H_ */ diff --git a/drivers/accel/amdxdna/amdxdna_ctx.c b/drivers/accel/amdxdna/amdxdna_ctx.c index 2c2c21992c87..b79229a63af3 100644 --- a/drivers/accel/amdxdna/amdxdna_ctx.c +++ b/drivers/accel/amdxdna/amdxdna_ctx.c @@ -207,6 +207,9 @@ int amdxdna_drm_create_hwctx_ioctl(struct drm_device *dev, void *data, struct dr if (args->ext || args->ext_flags) return -EINVAL; + if (!xdna->dev_info->ops->hwctx_init) + return -EOPNOTSUPP; + hwctx = kzalloc_obj(*hwctx); if (!hwctx) return -ENOMEM; @@ -220,6 +223,8 @@ int amdxdna_drm_create_hwctx_ioctl(struct drm_device *dev, void *data, struct dr hwctx->client = client; hwctx->fw_ctx_id = -1; hwctx->num_tiles = args->num_tiles; + hwctx->umq_bo_hdl = args->umq_bo; + hwctx->doorbell_offset = AMDXDNA_INVALID_DOORBELL_OFFSET; hwctx->mem_size = args->mem_size; hwctx->max_opc = args->max_opc; @@ -252,6 +257,7 @@ int amdxdna_drm_create_hwctx_ioctl(struct drm_device *dev, void *data, struct dr args->handle = hwctx->id; args->syncobj_handle = hwctx->syncobj_hdl; + args->umq_doorbell = hwctx->doorbell_offset; atomic64_set(&hwctx->job_submit_cnt, 0); atomic64_set(&hwctx->job_free_cnt, 0); @@ -621,3 +627,37 @@ int amdxdna_drm_submit_cmd_ioctl(struct drm_device *dev, void *data, struct drm_ XDNA_ERR(client->xdna, "Invalid command type %d", args->type); return -EINVAL; } + +int amdxdna_drm_wait_cmd_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) +{ + struct amdxdna_client *client = filp->driver_priv; + struct amdxdna_dev *xdna = to_xdna_dev(dev); + struct amdxdna_drm_wait_cmd *args = data; + struct amdxdna_hwctx *hwctx; + int ret, idx; + + XDNA_DBG(xdna, "PID %d ctx %d timeout set %d ms for cmd %llu", + client->pid, args->hwctx, args->timeout, args->seq); + + if (!xdna->dev_info->ops->cmd_wait) + return -EOPNOTSUPP; + + idx = srcu_read_lock(&client->hwctx_srcu); + hwctx = xa_load(&client->hwctx_xa, args->hwctx); + if (!hwctx) { + XDNA_DBG(xdna, "PID %d failed to get ctx %d", client->pid, args->hwctx); + ret = -EINVAL; + goto unlock_ctx_srcu; + } + + ret = xdna->dev_info->ops->cmd_wait(hwctx, args->seq, args->timeout); + + XDNA_DBG(xdna, "PID %d ctx %d cmd %lld wait finished, ret %d", + client->pid, args->hwctx, args->seq, ret); + + trace_amdxdna_debug_point(current->comm, args->seq, "job returned to user"); + +unlock_ctx_srcu: + srcu_read_unlock(&client->hwctx_srcu, idx); + return ret; +} diff --git a/drivers/accel/amdxdna/amdxdna_ctx.h b/drivers/accel/amdxdna/amdxdna_ctx.h index 355798687376..6e3c6371a088 100644 --- a/drivers/accel/amdxdna/amdxdna_ctx.h +++ b/drivers/accel/amdxdna/amdxdna_ctx.h @@ -14,6 +14,7 @@ struct amdxdna_hwctx_priv; enum ert_cmd_opcode { ERT_START_CU = 0, + ERT_START_DPU = 18, ERT_CMD_CHAIN = 19, ERT_START_NPU = 20, ERT_START_NPU_PREEMPT = 21, @@ -105,6 +106,8 @@ struct amdxdna_hwctx { u32 *col_list; u32 start_col; u32 num_col; + u32 umq_bo_hdl; + u32 doorbell_offset; u32 num_unused_col; struct amdxdna_qos_info qos; @@ -208,12 +211,10 @@ int amdxdna_cmd_submit(struct amdxdna_client *client, u32 *arg_bo_hdls, u32 arg_bo_cnt, u32 hwctx_hdl, u64 *seq); -int amdxdna_cmd_wait(struct amdxdna_client *client, u32 hwctx_hdl, - u64 seq, u32 timeout); - int amdxdna_drm_create_hwctx_ioctl(struct drm_device *dev, void *data, struct drm_file *filp); int amdxdna_drm_config_hwctx_ioctl(struct drm_device *dev, void *data, struct drm_file *filp); int amdxdna_drm_destroy_hwctx_ioctl(struct drm_device *dev, void *data, struct drm_file *filp); int amdxdna_drm_submit_cmd_ioctl(struct drm_device *dev, void *data, struct drm_file *filp); +int amdxdna_drm_wait_cmd_ioctl(struct drm_device *dev, void *data, struct drm_file *filp); #endif /* _AMDXDNA_CTX_H_ */ diff --git a/drivers/accel/amdxdna/amdxdna_gem.c b/drivers/accel/amdxdna/amdxdna_gem.c index ebfc472aa9e7..319d2064fafa 100644 --- a/drivers/accel/amdxdna/amdxdna_gem.c +++ b/drivers/accel/amdxdna/amdxdna_gem.c @@ -212,7 +212,8 @@ static bool amdxdna_hmm_invalidate(struct mmu_interval_notifier *mni, mmu_interval_set_seq(&mapp->notifier, cur_seq); up_write(&xdna->notifier_lock); - xdna->dev_info->ops->hmm_invalidate(abo, cur_seq); + if (xdna->dev_info->ops->hmm_invalidate) + xdna->dev_info->ops->hmm_invalidate(abo, cur_seq); if (range->event == MMU_NOTIFY_UNMAP) { down_write(&xdna->notifier_lock); @@ -295,7 +296,7 @@ static int amdxdna_hmm_register(struct amdxdna_gem_obj *abo, u32 nr_pages; int ret; - if (!xdna->dev_info->ops->hmm_invalidate) + if (!amdxdna_pasid_on(abo->client)) return 0; mapp = kzalloc_obj(*mapp); diff --git a/drivers/accel/amdxdna/amdxdna_pci_drv.c b/drivers/accel/amdxdna/amdxdna_pci_drv.c index 1b08a08343cf..a6e9be7960c2 100644 --- a/drivers/accel/amdxdna/amdxdna_pci_drv.c +++ b/drivers/accel/amdxdna/amdxdna_pci_drv.c @@ -40,9 +40,10 @@ MODULE_FIRMWARE("amdnpu/17f0_11/npu_7.sbin"); * 0.7: Support getting power and utilization data * 0.8: Support BO usage query * 0.9: Add new device type AMDXDNA_DEV_TYPE_PF + * 0.10: Support AIE4 UMQ */ #define AMDXDNA_DRIVER_MAJOR 0 -#define AMDXDNA_DRIVER_MINOR 9 +#define AMDXDNA_DRIVER_MINOR 10 /* * Bind the driver base on (vendor_id, device_id) pair and later use the @@ -53,7 +54,9 @@ static const struct pci_device_id pci_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x1502) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x17f0) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x17f2) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x17f3) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x1B0B) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x1B0C) }, {0} }; @@ -65,7 +68,9 @@ static const struct amdxdna_device_id amdxdna_ids[] = { { 0x17f0, 0x11, &dev_npu5_info }, { 0x17f0, 0x20, &dev_npu6_info }, { 0x17f2, 0x10, &dev_npu3_pf_info }, + { 0x17f3, 0x10, &dev_npu3_vf_info }, { 0x1B0B, 0x10, &dev_npu3_pf_info }, + { 0x1B0C, 0x10, &dev_npu3_vf_info }, {0} }; @@ -220,6 +225,21 @@ static int amdxdna_drm_set_state_ioctl(struct drm_device *dev, void *data, struc return ret; } +static int amdxdna_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) +{ + struct drm_file *drm_filp = filp->private_data; + struct amdxdna_client *client = drm_filp->driver_priv; + struct amdxdna_dev *xdna = client->xdna; + + if (likely(vma->vm_pgoff >= DRM_FILE_PAGE_OFFSET_START)) + return drm_gem_mmap(filp, vma); + + if (!xdna->dev_info->ops->mmap) + return -EOPNOTSUPP; + + return xdna->dev_info->ops->mmap(client, vma); +} + static const struct drm_ioctl_desc amdxdna_drm_ioctls[] = { /* Context */ DRM_IOCTL_DEF_DRV(AMDXDNA_CREATE_HWCTX, amdxdna_drm_create_hwctx_ioctl, 0), @@ -231,6 +251,7 @@ static const struct drm_ioctl_desc amdxdna_drm_ioctls[] = { DRM_IOCTL_DEF_DRV(AMDXDNA_SYNC_BO, amdxdna_drm_sync_bo_ioctl, 0), /* Execution */ DRM_IOCTL_DEF_DRV(AMDXDNA_EXEC_CMD, amdxdna_drm_submit_cmd_ioctl, 0), + DRM_IOCTL_DEF_DRV(AMDXDNA_WAIT_CMD, amdxdna_drm_wait_cmd_ioctl, 0), /* AIE hardware */ DRM_IOCTL_DEF_DRV(AMDXDNA_GET_INFO, amdxdna_drm_get_info_ioctl, 0), DRM_IOCTL_DEF_DRV(AMDXDNA_GET_ARRAY, amdxdna_drm_get_array_ioctl, 0), @@ -277,7 +298,7 @@ static const struct file_operations amdxdna_fops = { .poll = drm_poll, .read = drm_read, .llseek = noop_llseek, - .mmap = drm_gem_mmap, + .mmap = amdxdna_drm_gem_mmap, .show_fdinfo = drm_show_fdinfo, .fop_flags = FOP_UNSIGNED_OFFSET, }; diff --git a/drivers/accel/amdxdna/amdxdna_pci_drv.h b/drivers/accel/amdxdna/amdxdna_pci_drv.h index b1548cf16f59..471b72299aee 100644 --- a/drivers/accel/amdxdna/amdxdna_pci_drv.h +++ b/drivers/accel/amdxdna/amdxdna_pci_drv.h @@ -56,12 +56,14 @@ struct amdxdna_dev_ops { int (*resume)(struct amdxdna_dev *xdna); int (*suspend)(struct amdxdna_dev *xdna); int (*sriov_configure)(struct amdxdna_dev *xdna, int num_vfs); + int (*mmap)(struct amdxdna_client *client, struct vm_area_struct *vma); int (*hwctx_init)(struct amdxdna_hwctx *hwctx); void (*hwctx_fini)(struct amdxdna_hwctx *hwctx); int (*hwctx_config)(struct amdxdna_hwctx *hwctx, u32 type, u64 value, void *buf, u32 size); int (*hwctx_sync_debug_bo)(struct amdxdna_hwctx *hwctx, u32 debug_bo_hdl); void (*hmm_invalidate)(struct amdxdna_gem_obj *abo, unsigned long cur_seq); int (*cmd_submit)(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *job, u64 *seq); + int (*cmd_wait)(struct amdxdna_hwctx *hwctx, u64 seq, u32 timeout); int (*get_aie_info)(struct amdxdna_client *client, struct amdxdna_drm_get_info *args); int (*set_aie_state)(struct amdxdna_client *client, struct amdxdna_drm_set_state *args); int (*get_array)(struct amdxdna_client *client, struct amdxdna_drm_get_array *args); @@ -85,6 +87,7 @@ struct amdxdna_dev_info { int sram_bar; int psp_bar; int smu_bar; + int doorbell_bar; int device_type; int first_col; u32 dev_mem_buf_shift; @@ -167,6 +170,7 @@ struct amdxdna_client { /* Add device info below */ extern const struct amdxdna_dev_info dev_npu1_info; extern const struct amdxdna_dev_info dev_npu3_pf_info; +extern const struct amdxdna_dev_info dev_npu3_vf_info; extern const struct amdxdna_dev_info dev_npu4_info; extern const struct amdxdna_dev_info dev_npu5_info; extern const struct amdxdna_dev_info dev_npu6_info; diff --git a/drivers/accel/amdxdna/npu3_regs.c b/drivers/accel/amdxdna/npu3_regs.c index acece0faddf2..d76b2e99c308 100644 --- a/drivers/accel/amdxdna/npu3_regs.c +++ b/drivers/accel/amdxdna/npu3_regs.c @@ -14,6 +14,9 @@ #define NPU3_MBOX_BUFFER_BAR 2 #define NPU3_MBOX_INFO_OFF 0x0 +#define NPU3_DOORBELL_BAR 2 +#define NPU3_DOORBELL_OFF 0x0 + /* PCIe BAR Index for NPU3 */ #define NPU3_REG_BAR_INDEX 0 #define NPU3_PSP_BAR_INDEX 4 @@ -45,6 +48,7 @@ static const struct amdxdna_dev_priv npu3_dev_priv = { .mbox_bar = NPU3_MBOX_BAR, .mbox_rbuf_bar = NPU3_MBOX_BUFFER_BAR, .mbox_info_off = NPU3_MBOX_INFO_OFF, + .doorbell_off = NPU3_DOORBELL_OFF, .psp_regs_off = { DEFINE_BAR_OFFSET(PSP_CMD_REG, NPU3_PSP, MPASP_C2PMSG_123_ALT_1), DEFINE_BAR_OFFSET(PSP_ARG0_REG, NPU3_PSP, MPASP_C2PMSG_156_ALT_1), @@ -64,6 +68,14 @@ static const struct amdxdna_dev_priv npu3_dev_priv = { }, }; +static const struct amdxdna_dev_priv npu3_dev_vf_priv = { + /* vf device does not load firmware */ + .mbox_bar = NPU3_MBOX_BAR, + .mbox_rbuf_bar = NPU3_MBOX_BUFFER_BAR, + .mbox_info_off = NPU3_MBOX_INFO_OFF, + /* vf device does not have smu and psp */ +}; + const struct amdxdna_dev_info dev_npu3_pf_info = { .mbox_bar = NPU3_MBOX_BAR, .sram_bar = NPU3_MBOX_BUFFER_BAR, @@ -73,5 +85,16 @@ const struct amdxdna_dev_info dev_npu3_pf_info = { .device_type = AMDXDNA_DEV_TYPE_PF, .dev_priv = &npu3_dev_priv, .fw_feature_tbl = npu3_fw_feature_table, - .ops = &aie4_ops, + .ops = &aie4_pf_ops, +}; + +const struct amdxdna_dev_info dev_npu3_vf_info = { + .mbox_bar = NPU3_MBOX_BAR, + .sram_bar = NPU3_MBOX_BUFFER_BAR, + .doorbell_bar = NPU3_DOORBELL_BAR, + .default_vbnv = "RyzenAI-npu3-vf", + .device_type = AMDXDNA_DEV_TYPE_UMQ, + .dev_priv = &npu3_dev_vf_priv, + .fw_feature_tbl = npu3_fw_feature_table, + .ops = &aie4_vf_ops, }; diff --git a/drivers/accel/qaic/qaic.h b/drivers/accel/qaic/qaic.h index 83948358ada1..02ca99000e2a 100644 --- a/drivers/accel/qaic/qaic.h +++ b/drivers/accel/qaic/qaic.h @@ -151,8 +151,6 @@ struct qaic_device { struct list_head cntl_xfer_list; /* Synchronizes MHI control device transactions and its xfer list */ struct mutex cntl_mutex; - /* Array of DBC struct of this device */ - struct dma_bridge_chan *dbc; /* Work queue for tasks related to MHI control device */ struct workqueue_struct *cntl_wq; /* Synchronizes all the users of device during cleanup */ @@ -205,6 +203,8 @@ struct qaic_device { void *ssr_mhi_buf; /* DBC which is under SSR. Sentinel U32_MAX would mean that no SSR in progress */ u32 ssr_dbc; + /* Array of DBC struct of this device */ + struct dma_bridge_chan dbc[] __counted_by(num_dbc); }; struct qaic_drm_device { diff --git a/drivers/accel/qaic/qaic_drv.c b/drivers/accel/qaic/qaic_drv.c index 1c7c57dabcd6..0acf6cdd44f8 100644 --- a/drivers/accel/qaic/qaic_drv.c +++ b/drivers/accel/qaic/qaic_drv.c @@ -43,6 +43,7 @@ MODULE_IMPORT_NS("DMA_BUF"); #define QAIC_DESC "Qualcomm Cloud AI Accelerators" #define CNTL_MAJOR 5 #define CNTL_MINOR 0 +#define DBC_NUM 16 struct qaic_device_config { /* Indicates the AIC family the device belongs to */ @@ -405,15 +406,12 @@ static struct qaic_device *create_qdev(struct pci_dev *pdev, struct drm_device *drm; int i, ret; - qdev = devm_kzalloc(dev, sizeof(*qdev), GFP_KERNEL); + qdev = devm_kzalloc(dev, struct_size(qdev, dbc, DBC_NUM), GFP_KERNEL); if (!qdev) return NULL; + qdev->num_dbc = DBC_NUM; qdev->dev_state = QAIC_OFFLINE; - qdev->num_dbc = 16; - qdev->dbc = devm_kcalloc(dev, qdev->num_dbc, sizeof(*qdev->dbc), GFP_KERNEL); - if (!qdev->dbc) - return NULL; qddev = devm_drm_dev_alloc(&pdev->dev, &qaic_accel_driver, struct qaic_drm_device, drm); if (IS_ERR(qddev)) diff --git a/drivers/gpu/buddy.c b/drivers/gpu/buddy.c index 52686672e99f..eb1457376307 100644 --- a/drivers/gpu/buddy.c +++ b/drivers/gpu/buddy.c @@ -437,6 +437,9 @@ int gpu_buddy_init(struct gpu_buddy *mm, u64 size, u64 chunk_size) root_count++; } while (size); +#ifdef CONFIG_LOCKDEP + mm->lock_dep_map = NULL; +#endif return 0; out_free_roots: @@ -538,6 +541,7 @@ void gpu_buddy_reset_clear(struct gpu_buddy *mm, bool is_clear) unsigned int order; int i; + gpu_buddy_driver_lock_held(mm); size = mm->size; for (i = 0; i < mm->n_roots; ++i) { order = ilog2(size) - ilog2(mm->chunk_size); @@ -580,6 +584,7 @@ EXPORT_SYMBOL(gpu_buddy_reset_clear); void gpu_buddy_free_block(struct gpu_buddy *mm, struct gpu_buddy_block *block) { + gpu_buddy_driver_lock_held(mm); BUG_ON(!gpu_buddy_block_is_allocated(block)); mm->avail += gpu_buddy_block_size(mm, block); if (gpu_buddy_block_is_clear(block)) @@ -633,6 +638,7 @@ void gpu_buddy_free_list(struct gpu_buddy *mm, { bool mark_clear = flags & GPU_BUDDY_CLEARED; + gpu_buddy_driver_lock_held(mm); __gpu_buddy_free_list(mm, objects, mark_clear, !mark_clear); } EXPORT_SYMBOL(gpu_buddy_free_list); @@ -1172,6 +1178,8 @@ int gpu_buddy_block_trim(struct gpu_buddy *mm, u64 new_start; int err; + gpu_buddy_driver_lock_held(mm); + if (!list_is_singular(blocks)) return -EINVAL; @@ -1287,6 +1295,8 @@ int gpu_buddy_alloc_blocks(struct gpu_buddy *mm, unsigned long pages; int err; + gpu_buddy_driver_lock_held(mm); + if (size < mm->chunk_size) return -EINVAL; @@ -1475,6 +1485,7 @@ void gpu_buddy_print(struct gpu_buddy *mm) { int order; + gpu_buddy_driver_lock_held(mm); pr_info("chunk_size: %lluKiB, total: %lluMiB, free: %lluMiB, clear_free: %lluMiB\n", mm->chunk_size >> 10, mm->size >> 20, mm->avail >> 20, mm->clear_avail >> 20); diff --git a/drivers/gpu/drm/display/drm_dp_helper.c b/drivers/gpu/drm/display/drm_dp_helper.c index a697cc227e28..a6067471dd56 100644 --- a/drivers/gpu/drm/display/drm_dp_helper.c +++ b/drivers/gpu/drm/display/drm_dp_helper.c @@ -3487,31 +3487,64 @@ static const char *dp_content_type_get_name(enum dp_content_type content_type) } } +static const char *dp_sdp_type_get_name(unsigned char type) +{ + switch (type) { + case DP_SDP_AUDIO_TIMESTAMP: + return "Audio_TimeStamp"; + case DP_SDP_AUDIO_STREAM: + return "Audio_Stream"; + case DP_SDP_EXTENSION: + return "Extension"; + case DP_SDP_AUDIO_COPYMANAGEMENT: + return "Audio_CopyManagement"; + case DP_SDP_ISRC: + return "ISRC"; + case DP_SDP_VSC: + return "VSC"; + case DP_SDP_PPS: + return "PPS"; + case DP_SDP_VSC_EXT_VESA: + return "VSC_EXT_VESA"; + case DP_SDP_VSC_EXT_CEA: + return "VSC_EXT_CEA"; + case DP_SDP_ADAPTIVE_SYNC: + return "Adaptive-Sync"; + default: + return "Unknown"; + } +} + void drm_dp_vsc_sdp_log(struct drm_printer *p, const struct drm_dp_vsc_sdp *vsc) { - drm_printf(p, "DP SDP: VSC, revision %u, length %u\n", - vsc->revision, vsc->length); - drm_printf(p, " pixelformat: %s\n", - dp_pixelformat_get_name(vsc->pixelformat)); - drm_printf(p, " colorimetry: %s\n", - dp_colorimetry_get_name(vsc->pixelformat, vsc->colorimetry)); - drm_printf(p, " bpc: %u\n", vsc->bpc); - drm_printf(p, " dynamic range: %s\n", - dp_dynamic_range_get_name(vsc->dynamic_range)); - drm_printf(p, " content type: %s\n", - dp_content_type_get_name(vsc->content_type)); + drm_printf(p, "DP SDP: %s, revision %u, length %u\n", + dp_sdp_type_get_name(vsc->sdp_type), vsc->revision, vsc->length); + + drm_printf_indent(p, 1, "pixelformat: %s\n", + dp_pixelformat_get_name(vsc->pixelformat)); + drm_printf_indent(p, 1, "colorimetry: %s\n", + dp_colorimetry_get_name(vsc->pixelformat, vsc->colorimetry)); + drm_printf_indent(p, 1, "bpc: %u\n", vsc->bpc); + drm_printf_indent(p, 1, "dynamic range: %s\n", + dp_dynamic_range_get_name(vsc->dynamic_range)); + drm_printf_indent(p, 1, "content type: %s\n", + dp_content_type_get_name(vsc->content_type)); } EXPORT_SYMBOL(drm_dp_vsc_sdp_log); void drm_dp_as_sdp_log(struct drm_printer *p, const struct drm_dp_as_sdp *as_sdp) { - drm_printf(p, "DP SDP: AS_SDP, revision %u, length %u\n", - as_sdp->revision, as_sdp->length); - drm_printf(p, " vtotal: %d\n", as_sdp->vtotal); - drm_printf(p, " target_rr: %d\n", as_sdp->target_rr); - drm_printf(p, " duration_incr_ms: %d\n", as_sdp->duration_incr_ms); - drm_printf(p, " duration_decr_ms: %d\n", as_sdp->duration_decr_ms); - drm_printf(p, " operation_mode: %d\n", as_sdp->mode); + drm_printf(p, "DP SDP: %s, revision %u, length %u\n", + dp_sdp_type_get_name(as_sdp->sdp_type), as_sdp->revision, as_sdp->length); + + drm_printf_indent(p, 1, "vtotal: %d\n", as_sdp->vtotal); + drm_printf_indent(p, 1, "target rr: %d\n", as_sdp->target_rr); + drm_printf_indent(p, 1, "duration increase ms: %d\n", as_sdp->duration_incr_ms); + drm_printf_indent(p, 1, "duration decrease ms: %d\n", as_sdp->duration_decr_ms); + drm_printf_indent(p, 1, "operation mode: %d\n", as_sdp->mode); + drm_printf_indent(p, 1, "target rr divider: %s\n", + as_sdp->target_rr_divider ? "1.001" : "1.000"); + drm_printf_indent(p, 1, "coasting vtotal: %d\n", as_sdp->coasting_vtotal); } EXPORT_SYMBOL(drm_dp_as_sdp_log); @@ -4626,8 +4659,6 @@ static const struct backlight_ops dp_aux_bl_ops = { * Backlight will then be handled transparently without requiring * any intervention from the driver. * - * drm_panel_dp_aux_backlight() must be called after the call to drm_panel_init(). - * * Return: 0 on success or a negative error code on failure. */ int drm_panel_dp_aux_backlight(struct drm_panel *panel, struct drm_dp_aux *aux) diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c index 35dc4f24ae53..fe72245fb9ca 100644 --- a/drivers/gpu/drm/display/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c @@ -789,6 +789,12 @@ static bool drm_dp_sideband_append_payload(struct drm_dp_sideband_msg_rx *msg, { u8 crc4; + /* curchunk_len must be >= 1 (min 1 CRC byte) and fit in chunk[] */ + if (!msg->curchunk_len || + msg->curchunk_len > ARRAY_SIZE(msg->chunk) || + msg->curchunk_idx + replybuflen > ARRAY_SIZE(msg->chunk)) + return false; + memcpy(&msg->chunk[msg->curchunk_idx], replybuf, replybuflen); msg->curchunk_idx += replybuflen; @@ -799,6 +805,9 @@ static bool drm_dp_sideband_append_payload(struct drm_dp_sideband_msg_rx *msg, print_hex_dump(KERN_DEBUG, "wrong crc", DUMP_PREFIX_NONE, 16, 1, msg->chunk, msg->curchunk_len, false); + /* Guard against accumulated msg[] overflow */ + if (msg->curlen + msg->curchunk_len - 1 > ARRAY_SIZE(msg->msg)) + return false; /* copy chunk into bigger msg */ memcpy(&msg->msg[msg->curlen], msg->chunk, msg->curchunk_len - 1); msg->curlen += msg->curchunk_len - 1; diff --git a/drivers/gpu/drm/drm_buddy.c b/drivers/gpu/drm/drm_buddy.c index 841f3de5f307..faa025498de4 100644 --- a/drivers/gpu/drm/drm_buddy.c +++ b/drivers/gpu/drm/drm_buddy.c @@ -42,6 +42,7 @@ void drm_buddy_print(struct gpu_buddy *mm, struct drm_printer *p) { int order; + gpu_buddy_driver_lock_held(mm); drm_printf(p, "chunk_size: %lluKiB, total: %lluMiB, free: %lluMiB, clear_free: %lluMiB\n", mm->chunk_size >> 10, mm->size >> 20, mm->avail >> 20, mm->clear_avail >> 20); diff --git a/drivers/gpu/drm/drm_gpusvm.c b/drivers/gpu/drm/drm_gpusvm.c index 365a9c0b522a..958cb605aedd 100644 --- a/drivers/gpu/drm/drm_gpusvm.c +++ b/drivers/gpu/drm/drm_gpusvm.c @@ -1556,10 +1556,7 @@ map_pages: if (!i) dma_iova_try_alloc(gpusvm->drm->dev, state, - npages * PAGE_SIZE >= - HPAGE_PMD_SIZE ? - HPAGE_PMD_SIZE : 0, - npages * PAGE_SIZE); + 0, npages * PAGE_SIZE); if (dma_use_iova(state)) { err = dma_iova_link(gpusvm->drm->dev, state, diff --git a/drivers/gpu/drm/drm_pagemap.c b/drivers/gpu/drm/drm_pagemap.c index d82ea7ccb8da..15c78eca180b 100644 --- a/drivers/gpu/drm/drm_pagemap.c +++ b/drivers/gpu/drm/drm_pagemap.c @@ -347,10 +347,7 @@ drm_pagemap_migrate_map_system_pages(struct device *dev, if (!try_alloc) { dma_iova_try_alloc(dev, &state->dma_state, - (npages - i) * PAGE_SIZE >= - HPAGE_PMD_SIZE ? - HPAGE_PMD_SIZE : 0, - npages * PAGE_SIZE); + 0, npages * PAGE_SIZE); try_alloc = true; } diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c index a6029b699b73..04f4a31ed27a 100644 --- a/drivers/gpu/drm/drm_panel.c +++ b/drivers/gpu/drm/drm_panel.c @@ -56,8 +56,9 @@ static LIST_HEAD(panel_list); * Initialize the panel structure for subsequent registration with * drm_panel_add(). */ -void drm_panel_init(struct drm_panel *panel, struct device *dev, - const struct drm_panel_funcs *funcs, int connector_type) +static void drm_panel_init(struct drm_panel *panel, struct device *dev, + const struct drm_panel_funcs *funcs, + int connector_type) { if (connector_type == DRM_MODE_CONNECTOR_Unknown) DRM_WARN("%s: %s: a valid connector type is required!\n", __func__, dev_name(dev)); @@ -69,7 +70,6 @@ void drm_panel_init(struct drm_panel *panel, struct device *dev, panel->funcs = funcs; panel->connector_type = connector_type; } -EXPORT_SYMBOL(drm_panel_init); /** * drm_panel_add - add a panel to the global registry @@ -731,7 +731,6 @@ EXPORT_SYMBOL(devm_drm_panel_add_follower); * A typical implementation for a panel driver supporting device tree * will call this function at probe time. Backlight will then be handled * transparently without requiring any intervention from the driver. - * drm_panel_of_backlight() must be called after the call to drm_panel_init(). * * Return: 0 on success or a negative error code on failure. */ diff --git a/drivers/gpu/drm/gud/gud_drv.c b/drivers/gpu/drm/gud/gud_drv.c index 17c2dead2c13..89bd6ca36003 100644 --- a/drivers/gpu/drm/gud/gud_drv.c +++ b/drivers/gpu/drm/gud/gud_drv.c @@ -684,6 +684,7 @@ static int gud_resume(struct usb_interface *intf) static const struct usb_device_id gud_id_table[] = { { USB_DEVICE_INTERFACE_CLASS(0x1d50, 0x614d, USB_CLASS_VENDOR_SPEC) }, { USB_DEVICE_INTERFACE_CLASS(0x16d0, 0x10a9, USB_CLASS_VENDOR_SPEC) }, + { USB_DEVICE_INTERFACE_CLASS(0x1209, 0x4fb3, USB_CLASS_VENDOR_SPEC) }, { } }; diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_comm.h b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_comm.h index f9ee7ebfec55..f53dac256ee0 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_comm.h +++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_comm.h @@ -69,5 +69,6 @@ int hibmc_dp_link_training(struct hibmc_dp_dev *dp); int hibmc_dp_serdes_init(struct hibmc_dp_dev *dp); int hibmc_dp_serdes_rate_switch(u8 rate, struct hibmc_dp_dev *dp); int hibmc_dp_serdes_set_tx_cfg(struct hibmc_dp_dev *dp, u8 train_set[HIBMC_DP_LANE_NUM_MAX]); +void hibmc_dp_update_caps(struct hibmc_dp_dev *dp); #endif diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h index 31316fe1ea8d..0f3662d8737e 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h +++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h @@ -55,6 +55,7 @@ struct hibmc_dp { struct drm_dp_aux aux; struct hibmc_dp_cbar_cfg cfg; u32 irq_status; + int phys_status; }; int hibmc_dp_hw_init(struct hibmc_dp *dp); diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_link.c b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_link.c index 0726cb5b736e..8c53f16db516 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_link.c +++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_link.c @@ -325,7 +325,7 @@ static int hibmc_dp_link_downgrade_training_eq(struct hibmc_dp_dev *dp) return hibmc_dp_link_reduce_rate(dp); } -static void hibmc_dp_update_caps(struct hibmc_dp_dev *dp) +void hibmc_dp_update_caps(struct hibmc_dp_dev *dp) { dp->link.cap.link_rate = dp->dpcd[DP_MAX_LINK_RATE]; if (dp->link.cap.link_rate > DP_LINK_BW_8_1 || !dp->link.cap.link_rate) diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c index e276b8ca213c..3066dc9ebc64 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c @@ -32,26 +32,43 @@ struct hibmc_display_panel_pll { struct hibmc_dislay_pll_config { u64 hdisplay; u64 vdisplay; + int clock; u32 pll1_config_value; u32 pll2_config_value; }; static const struct hibmc_dislay_pll_config hibmc_pll_table[] = { - {640, 480, CRT_PLL1_HS_25MHZ, CRT_PLL2_HS_25MHZ}, - {800, 600, CRT_PLL1_HS_40MHZ, CRT_PLL2_HS_40MHZ}, - {1024, 768, CRT_PLL1_HS_65MHZ, CRT_PLL2_HS_65MHZ}, - {1152, 864, CRT_PLL1_HS_80MHZ_1152, CRT_PLL2_HS_80MHZ}, - {1280, 768, CRT_PLL1_HS_80MHZ, CRT_PLL2_HS_80MHZ}, - {1280, 720, CRT_PLL1_HS_74MHZ, CRT_PLL2_HS_74MHZ}, - {1280, 960, CRT_PLL1_HS_108MHZ, CRT_PLL2_HS_108MHZ}, - {1280, 1024, CRT_PLL1_HS_108MHZ, CRT_PLL2_HS_108MHZ}, - {1440, 900, CRT_PLL1_HS_106MHZ, CRT_PLL2_HS_106MHZ}, - {1600, 900, CRT_PLL1_HS_108MHZ, CRT_PLL2_HS_108MHZ}, - {1600, 1200, CRT_PLL1_HS_162MHZ, CRT_PLL2_HS_162MHZ}, - {1920, 1080, CRT_PLL1_HS_148MHZ, CRT_PLL2_HS_148MHZ}, - {1920, 1200, CRT_PLL1_HS_193MHZ, CRT_PLL2_HS_193MHZ}, + {640, 480, 25000, CRT_PLL1_HS_25MHZ, CRT_PLL2_HS_25MHZ}, + {800, 600, 40000, CRT_PLL1_HS_40MHZ, CRT_PLL2_HS_40MHZ}, + {1024, 768, 65000, CRT_PLL1_HS_65MHZ, CRT_PLL2_HS_65MHZ}, + {1152, 864, 78750, CRT_PLL1_HS_80MHZ_1152, CRT_PLL2_HS_80MHZ}, + {1280, 768, 80000, CRT_PLL1_HS_80MHZ, CRT_PLL2_HS_80MHZ}, + {1280, 720, 74375, CRT_PLL1_HS_74MHZ, CRT_PLL2_HS_74MHZ}, + {1280, 960, 108000, CRT_PLL1_HS_108MHZ, CRT_PLL2_HS_108MHZ}, + {1280, 1024, 108000, CRT_PLL1_HS_108MHZ, CRT_PLL2_HS_108MHZ}, + {1440, 900, 105952, CRT_PLL1_HS_106MHZ, CRT_PLL2_HS_106MHZ}, + {1600, 900, 108000, CRT_PLL1_HS_108MHZ, CRT_PLL2_HS_108MHZ}, + {1600, 1200, 162500, CRT_PLL1_HS_162MHZ, CRT_PLL2_HS_162MHZ}, + {1920, 1080, 148750, CRT_PLL1_HS_148MHZ, CRT_PLL2_HS_148MHZ}, + {1920, 1200, 193750, CRT_PLL1_HS_193MHZ, CRT_PLL2_HS_193MHZ}, }; +static int hibmc_get_best_clock_idx(const struct drm_display_mode *mode) +{ + int i, diff; + + for (i = 0; i < ARRAY_SIZE(hibmc_pll_table); i++) { + if (hibmc_pll_table[i].hdisplay == mode->hdisplay && + hibmc_pll_table[i].vdisplay == mode->vdisplay) { + diff = abs(mode->clock - hibmc_pll_table[i].clock); + if (diff < mode->clock / 100) /* tolerance 1/100 */ + return i; + } + } + + return -MODE_CLOCK_RANGE; +} + static int hibmc_plane_atomic_check(struct drm_plane *plane, struct drm_atomic_commit *state) { @@ -214,19 +231,15 @@ static enum drm_mode_status hibmc_crtc_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode) { - size_t i = 0; int vrefresh = drm_mode_vrefresh(mode); if (vrefresh < 59 || vrefresh > 61) return MODE_NOCLOCK; - for (i = 0; i < ARRAY_SIZE(hibmc_pll_table); i++) { - if (hibmc_pll_table[i].hdisplay == mode->hdisplay && - hibmc_pll_table[i].vdisplay == mode->vdisplay) - return MODE_OK; - } + if (hibmc_get_best_clock_idx(mode) >= 0) + return MODE_OK; - return MODE_BAD; + return MODE_CLOCK_RANGE; } static u32 format_pll_reg(void) @@ -281,23 +294,20 @@ static void set_vclock_hisilicon(struct drm_device *dev, u64 pll) writel(val, priv->mmio + CRT_PLL1_HS); } -static void get_pll_config(u64 x, u64 y, u32 *pll1, u32 *pll2) +static void get_pll_config(struct drm_display_mode *mode, u32 *pll1, u32 *pll2) { - size_t i; - size_t count = ARRAY_SIZE(hibmc_pll_table); - - for (i = 0; i < count; i++) { - if (hibmc_pll_table[i].hdisplay == x && - hibmc_pll_table[i].vdisplay == y) { - *pll1 = hibmc_pll_table[i].pll1_config_value; - *pll2 = hibmc_pll_table[i].pll2_config_value; - return; - } + int idx; + + idx = hibmc_get_best_clock_idx(mode); + if (idx < 0) { + /* if found none, we use default value */ + *pll1 = CRT_PLL1_HS_25MHZ; + *pll2 = CRT_PLL2_HS_25MHZ; + return; } - /* if found none, we use default value */ - *pll1 = CRT_PLL1_HS_25MHZ; - *pll2 = CRT_PLL2_HS_25MHZ; + *pll1 = hibmc_pll_table[idx].pll1_config_value; + *pll2 = hibmc_pll_table[idx].pll2_config_value; } /* @@ -319,7 +329,7 @@ static u32 display_ctrl_adjust(struct drm_device *dev, x = mode->hdisplay; y = mode->vdisplay; - get_pll_config(x, y, &pll1, &pll2); + get_pll_config(mode, &pll1, &pll2); writel(pll2, priv->mmio + CRT_PLL2_HS); set_vclock_hisilicon(dev, pll1); diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c index 2da04ac89d4d..2e9403b8bf3c 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c @@ -41,6 +41,8 @@ static bool hibmc_dp_get_dpcd(struct hibmc_dp_dev *dp_dev) if (ret) return false; + hibmc_dp_update_caps(dp_dev); + dp_dev->is_branch = drm_dp_is_branch(dp_dev->dpcd); ret = drm_dp_read_desc(dp_dev->aux, &dp_dev->desc, dp_dev->is_branch); @@ -59,27 +61,38 @@ static int hibmc_dp_detect(struct drm_connector *connector, { struct hibmc_dp *dp = to_hibmc_dp(connector); struct hibmc_dp_dev *dp_dev = dp->dp_dev; - int ret; + int ret = connector_status_disconnected; if (dp->irq_status) { - if (dp_dev->hpd_status != HIBMC_HPD_IN) - return connector_status_disconnected; + if (dp_dev->hpd_status != HIBMC_HPD_IN) { + ret = connector_status_disconnected; + goto exit; + } } - if (!hibmc_dp_get_dpcd(dp_dev)) - return connector_status_disconnected; + if (!hibmc_dp_get_dpcd(dp_dev)) { + ret = connector_status_disconnected; + goto exit; + } - if (!dp_dev->is_branch) - return connector_status_connected; + if (!dp_dev->is_branch) { + ret = connector_status_connected; + goto exit; + } if (drm_dp_read_sink_count_cap(connector, dp_dev->dpcd, &dp_dev->desc) && dp_dev->downstream_ports[0] & DP_DS_PORT_HPD) { ret = drm_dp_read_sink_count(dp_dev->aux); - if (ret > 0) - return connector_status_connected; + if (ret > 0) { + ret = connector_status_connected; + goto exit; + } } - return connector_status_disconnected; +exit: + dp->phys_status = ret; + + return ret; } static int hibmc_dp_mode_valid(struct drm_connector *connector, @@ -241,5 +254,7 @@ int hibmc_dp_init(struct hibmc_drm_private *priv) connector->polled = DRM_CONNECTOR_POLL_HPD; + dp->phys_status = connector_status_disconnected; + return 0; } diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c index 289304500ab0..99b36de1fe13 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c @@ -24,6 +24,7 @@ #include <drm/drm_managed.h> #include <drm/drm_module.h> #include <drm/drm_vblank.h> +#include <drm/drm_probe_helper.h> #include "hibmc_drm_drv.h" #include "hibmc_drm_regs.h" @@ -214,6 +215,15 @@ void hibmc_set_current_gate(struct hibmc_drm_private *priv, unsigned int gate) writel(gate, mmio + gate_reg); } +static void hibmc_display_ctrl(struct hibmc_drm_private *priv) +{ + u32 reg; + + reg = readl(priv->mmio + HIBMC_DISPLAY_CONTROL_HISILE); + reg |= HIBMC_DISPLAY_CONTROL_PANELDATE(1); + writel(reg, priv->mmio + HIBMC_DISPLAY_CONTROL_HISILE); +} + static void hibmc_hw_config(struct hibmc_drm_private *priv) { u32 reg; @@ -245,6 +255,8 @@ static void hibmc_hw_config(struct hibmc_drm_private *priv) reg |= HIBMC_MSCCTL_LOCALMEM_RESET(1); writel(reg, priv->mmio + HIBMC_MISC_CTRL); + + hibmc_display_ctrl(priv); } static int hibmc_hw_map(struct hibmc_drm_private *priv) @@ -355,6 +367,8 @@ static int hibmc_load(struct drm_device *dev) /* reset all the states of crtc/plane/encoder/connector */ drm_mode_config_reset(dev); + drmm_kms_helper_poll_init(dev); + return 0; err: diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h index ca8502e2760c..cd3a3fca1fe6 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h @@ -31,6 +31,7 @@ struct hibmc_vdac { struct drm_connector connector; struct i2c_adapter adapter; struct i2c_algo_bit_data bit_data; + int phys_status; }; struct hibmc_drm_private { diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c index 841e81f47b68..b9bd6d33fb0f 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c @@ -24,28 +24,21 @@ static int hibmc_connector_get_modes(struct drm_connector *connector) { + struct drm_mode_config *mode_config = &connector->dev->mode_config; struct hibmc_vdac *vdac = to_hibmc_vdac(connector); - const struct drm_edid *drm_edid; int count; - drm_edid = drm_edid_read_ddc(connector, &vdac->adapter); - - drm_edid_connector_update(connector, drm_edid); - - if (drm_edid) { - count = drm_edid_connector_add_modes(connector); + if (vdac->phys_status == connector_status_connected) { + count = drm_connector_helper_get_modes(connector); + } else { + drm_edid_connector_update(connector, NULL); + count = drm_add_modes_noedid(connector, + mode_config->max_width, + mode_config->max_height); if (count) - goto out; + drm_set_preferred_mode(connector, 1024, 768); } - count = drm_add_modes_noedid(connector, - connector->dev->mode_config.max_width, - connector->dev->mode_config.max_height); - drm_set_preferred_mode(connector, 1024, 768); - -out: - drm_edid_free(drm_edid); - return count; } @@ -57,10 +50,34 @@ static void hibmc_connector_destroy(struct drm_connector *connector) drm_connector_cleanup(connector); } +static int hibmc_vdac_detect(struct drm_connector *connector, + struct drm_modeset_acquire_ctx *ctx, + bool force) +{ + struct hibmc_drm_private *priv = to_hibmc_drm_private(connector->dev); + int status = drm_connector_helper_detect_from_ddc(connector, ctx, + force); + struct hibmc_vdac *vdac = to_hibmc_vdac(connector); + + if (priv->dp.phys_status == connector_status_connected) { + vdac->phys_status = status; + return status; + } + + if (status != vdac->phys_status) + ++connector->epoch_counter; + vdac->phys_status = status; + + /* When both the DP and VDAC physical status are disconnected, + * the "connected" status is returned to support KVM display. + */ + return connector_status_connected; +} + static const struct drm_connector_helper_funcs hibmc_connector_helper_funcs = { .get_modes = hibmc_connector_get_modes, - .detect_ctx = drm_connector_helper_detect_from_ddc, + .detect_ctx = hibmc_vdac_detect, }; static const struct drm_connector_funcs hibmc_connector_funcs = { @@ -71,26 +88,6 @@ static const struct drm_connector_funcs hibmc_connector_funcs = { .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; -static void hibmc_encoder_mode_set(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adj_mode) -{ - u32 reg; - struct drm_device *dev = encoder->dev; - struct hibmc_drm_private *priv = to_hibmc_drm_private(dev); - - reg = readl(priv->mmio + HIBMC_DISPLAY_CONTROL_HISILE); - reg |= HIBMC_DISPLAY_CONTROL_FPVDDEN(1); - reg |= HIBMC_DISPLAY_CONTROL_PANELDATE(1); - reg |= HIBMC_DISPLAY_CONTROL_FPEN(1); - reg |= HIBMC_DISPLAY_CONTROL_VBIASEN(1); - writel(reg, priv->mmio + HIBMC_DISPLAY_CONTROL_HISILE); -} - -static const struct drm_encoder_helper_funcs hibmc_encoder_helper_funcs = { - .mode_set = hibmc_encoder_mode_set, -}; - int hibmc_vdac_init(struct hibmc_drm_private *priv) { struct drm_device *dev = &priv->dev; @@ -113,8 +110,6 @@ int hibmc_vdac_init(struct hibmc_drm_private *priv) goto err; } - drm_encoder_helper_add(encoder, &hibmc_encoder_helper_funcs); - ret = drm_connector_init_with_ddc(dev, connector, &hibmc_connector_funcs, DRM_MODE_CONNECTOR_VGA, @@ -130,6 +125,8 @@ int hibmc_vdac_init(struct hibmc_drm_private *priv) connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; + vdac->phys_status = connector_status_disconnected; + return 0; err: diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 86123614b7ba..ed17f6beae9a 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -5374,8 +5374,8 @@ int intel_dp_as_sdp_unpack(struct drm_dp_as_sdp *as_sdp, if ((sdp->sdp_header.HB3 & 0x3F) != 9) return -EINVAL; - as_sdp->length = sdp->sdp_header.HB3 & DP_ADAPTIVE_SYNC_SDP_LENGTH; - as_sdp->mode = sdp->db[0] & DP_ADAPTIVE_SYNC_SDP_OPERATION_MODE; + as_sdp->length = sdp->sdp_header.HB3 & DP_AS_SDP_LENGTH_MASK; + as_sdp->mode = sdp->db[0] & DP_AS_SDP_OPERATION_MODE_MASK; as_sdp->vtotal = (sdp->db[2] << 8) | sdp->db[1]; as_sdp->target_rr = (u64)sdp->db[3] | ((u64)sdp->db[4] & 0x3); as_sdp->target_rr_divider = sdp->db[4] & 0x20 ? true : false; diff --git a/drivers/gpu/drm/nouveau/dispnv50/crc.c b/drivers/gpu/drm/nouveau/dispnv50/crc.c index e736318fb0dc..cb74bbec5e9c 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/crc.c +++ b/drivers/gpu/drm/nouveau/dispnv50/crc.c @@ -16,7 +16,6 @@ #include "nouveau_drv.h" #include "core.h" #include "head.h" -#include "wndw.h" #include "handles.h" #include "crc.h" diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/disp.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/disp.c index 6e63df816d85..1155f079b0c3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/disp.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/disp.c @@ -1734,7 +1734,8 @@ r535_disp_new(const struct nvkm_disp_func *hw, struct nvkm_device *device, struct nvkm_disp_func *rm; int ret; - if (!(rm = kzalloc(sizeof(*rm) + 6 * sizeof(rm->user[0]), GFP_KERNEL))) + rm = kzalloc_flex(*rm, user, 6); + if (!rm) return -ENOMEM; rm->dtor = r535_disp_dtor; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c index 958fd78080bd..107bdb642f22 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c @@ -53,7 +53,8 @@ nvkm_vmm_pt_new(const struct nvkm_vmm_desc *desc, bool sparse, } } - if (!(pgt = kzalloc(sizeof(*pgt) + (sizeof(pgt->pte[0]) * lpte), GFP_KERNEL))) + pgt = kzalloc_flex(*pgt, pte, lpte); + if (!pgt) return NULL; pgt->page = page ? page->shift : 0; pgt->sparse = sparse; diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c index f3cdaea89b29..241915e9f495 100644 --- a/drivers/gpu/drm/panel/panel-edp.c +++ b/drivers/gpu/drm/panel/panel-edp.c @@ -1918,6 +1918,7 @@ static const struct panel_delay delay_80_500_e50_d50 = { * Sort first by vendor, then by product ID. */ static const struct edp_panel_entry edp_panels[] = { + EDP_PANEL_ENTRY('A', 'U', 'O', 0x0290, &delay_200_500_e50, "B140XTN07.5"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x04a4, &delay_200_500_e50, "B122UAN01.0"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x0ba4, &delay_200_500_e50, "B140QAX01.H"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x105c, &delay_200_500_e50, "B116XTN01.0"), @@ -1934,17 +1935,20 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('A', 'U', 'O', 0x239b, &delay_200_500_e50, "B116XAN06.1"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x255c, &delay_200_500_e50, "B116XTN02.5"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x30ed, &delay_200_500_e50, "G156HAN03.0"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x3c9f, &delay_200_500_e50, "B140HAK03.5"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x403d, &delay_200_500_e50, "B140HAN04.0"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, &auo_b116xak01.delay, "B116XAN04.0"), EDP_PANEL_ENTRY2('A', 'U', 'O', 0x405c, &auo_b116xak01.delay, "B116XAK01.0", &auo_b116xa3_mode), EDP_PANEL_ENTRY('A', 'U', 'O', 0x435c, &delay_200_500_e50, "Unknown"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x49ba, &delay_200_500_e50, "B116XTN02.3"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x52b0, &delay_200_500_e50, "B116XAK02.0"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x582d, &delay_200_500_e50, "B133UAN01.0"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x615c, &delay_200_500_e50, "B116XAN06.1"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x635c, &delay_200_500_e50, "B116XAN06.3"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x639c, &delay_200_500_e50, "B140HAK02.7"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x643d, &delay_200_500_e50, "B140HAN06.4"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x67a8, &delay_200_500_e50, "B140XTK02.4"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x723c, &delay_200_500_e50, "B140XTN07.2"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x73aa, &delay_200_500_e50, "B116XTN02.3"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x8594, &delay_200_500_e50, "B133UAN01.0"), @@ -1954,7 +1958,9 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('A', 'U', 'O', 0xa7b3, &delay_200_500_e50, "B140UAN04.4"), EDP_PANEL_ENTRY('A', 'U', 'O', 0xb7a9, &delay_200_500_e50, "B140HAK03.3"), EDP_PANEL_ENTRY('A', 'U', 'O', 0xc4b4, &delay_200_500_e50, "B116XAT04.1"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0xc7ad, &delay_200_500_e50, "B140HAN07.7"), EDP_PANEL_ENTRY('A', 'U', 'O', 0xc9a8, &delay_200_500_e50, "B140QAN08.H"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0xcb8f, &delay_200_500_e50, "B133HAN06.6"), EDP_PANEL_ENTRY('A', 'U', 'O', 0xcdba, &delay_200_500_e50, "B140UAX01.2"), EDP_PANEL_ENTRY('A', 'U', 'O', 0xd497, &delay_200_500_e50, "B120XAN01.0"), EDP_PANEL_ENTRY('A', 'U', 'O', 0xf390, &delay_200_500_e50, "B140XTN07.7"), @@ -1990,6 +1996,7 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('B', 'O', 'E', 0x08b2, &delay_200_500_e200, "NT140WHM-N49"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0848, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0849, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x090d, &delay_200_500_e50, "NT140WHM-N4T"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x09c3, &delay_200_500_e50, "NT116WHM-N21,836X2"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x094b, &delay_200_500_e50, "NT116WHM-N21"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0951, &delay_200_500_e80, "NV116WHM-N47"), @@ -2003,6 +2010,7 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('B', 'O', 'E', 0x09ae, &delay_200_500_e200, "NT140FHM-N45"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x09dd, &delay_200_500_e50, "NT116WHM-N21"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a1b, &delay_200_500_e50, "NV133WUM-N63"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a25, &delay_200_500_e50_po2e200, "NV133FHM-N4F V8.0"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a36, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a3e, &delay_200_500_e80_d50, "NV116WHM-N49"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a5d, &delay_200_500_e50, "NV116WHM-N45"), @@ -2016,8 +2024,10 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b43, &delay_200_500_e200, "NV140FHM-T09"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b56, &delay_200_500_e80, "NT140FHM-N47"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b66, &delay_200_500_e80, "NE140WUM-N6G"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b85, &delay_200_500_e50, "NT140WHM-T05"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0c20, &delay_200_500_e80, "NT140FHM-N47"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0c26, &delay_200_500_p2e200, "NV140WUM-T08"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0c6f, &delay_200_500_e50, "NV140FHM-N40"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0c93, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0cb6, &delay_200_500_e200, "NT116WHM-N44"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0cf2, &delay_200_500_e200, "NV156FHM-N4S"), @@ -2048,6 +2058,7 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('C', 'M', 'N', 0x1160, &delay_200_500_e80_d50, "N116BCJ-EAK"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1161, &delay_200_500_e80, "N116BCP-EA2"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1163, &delay_200_500_e80_d50, "N116BCJ-EAK"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x1169, &delay_200_500_e80_d50, "N116BCN-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x117a, &delay_200_500_e80_d50, "N116BCL-EAK"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1247, &delay_200_500_e80_d50, "N120ACA-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x124c, &delay_200_500_e80_d50, "N122JCA-ENK"), @@ -2058,8 +2069,9 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('C', 'M', 'N', 0x1468, &delay_200_500_e80, "N140HGA-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x148f, &delay_200_500_e80, "N140HCA-EAC"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x14a8, &delay_200_500_e80, "N140JCA-ELP"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x14c7, &delay_200_500_e80, "N140HCA-EEK"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x14d4, &delay_200_500_e80_d50, "N140HCA-EAC"), - EDP_PANEL_ENTRY('C', 'M', 'N', 0x14d6, &delay_200_500_e80_d50, "N140BGA-EA4"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x14d6, &delay_200_500_e80, "N140BGA-E54"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x14e5, &delay_200_500_e80_d50, "N140HGA-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1565, &delay_200_500_e80, "N156HCA-EAB"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x156b, &delay_200_500_e80_d50, "N153JCA-ELK"), @@ -2095,6 +2107,8 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('I', 'V', 'O', 0x854a, &delay_200_500_p2e100, "M133NW4J"), EDP_PANEL_ENTRY('I', 'V', 'O', 0x854b, &delay_200_500_p2e100, "R133NW4K-R0"), EDP_PANEL_ENTRY('I', 'V', 'O', 0x8c4d, &delay_200_150_e200, "R140NWFM R1"), + EDP_PANEL_ENTRY('I', 'V', 'O', 0x8cd5, &delay_200_500_e200_d10, "M140NWFQ R5"), + EDP_PANEL_ENTRY('I', 'V', 'O', 0x8ce6, &delay_200_500_e200, "R140NWFW R0"), EDP_PANEL_ENTRY('K', 'D', 'B', 0x044f, &delay_200_500_e80_d50, "Unknown"), EDP_PANEL_ENTRY('K', 'D', 'B', 0x0624, &kingdisplay_kd116n21_30nv_a010.delay, "116N21-30NV-A010"), diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9806e-core.c b/drivers/gpu/drm/panel/panel-ilitek-ili9806e-core.c index be2cf1440155..53e25d1086db 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9806e-core.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9806e-core.c @@ -78,9 +78,11 @@ int ili9806e_probe(struct device *dev, void *transport, bool set_prepare_prev_first = false; int ret; - ctx = devm_kzalloc(dev, sizeof(struct ili9806e), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(dev, __typeof(*ctx), panel, + funcs, connector_type); + + if (IS_ERR(ctx)) + return PTR_ERR(ctx); dev_set_drvdata(dev, ctx); ctx->transport = transport; @@ -103,8 +105,6 @@ int ili9806e_probe(struct device *dev, void *transport, return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "Failed to get reset-gpios\n"); - drm_panel_init(&ctx->panel, dev, funcs, connector_type); - ret = drm_panel_of_backlight(&ctx->panel); if (ret) return dev_err_probe(dev, ret, "Failed to get backlight\n"); diff --git a/drivers/gpu/drm/panel/panel-lxd-m9189a.c b/drivers/gpu/drm/panel/panel-lxd-m9189a.c index 68019e1e43a9..baaf170779e0 100644 --- a/drivers/gpu/drm/panel/panel-lxd-m9189a.c +++ b/drivers/gpu/drm/panel/panel-lxd-m9189a.c @@ -165,9 +165,12 @@ static int lxd_m9189_probe(struct mipi_dsi_device *dsi) struct m9189_panel *m9189; int ret; - m9189 = devm_kzalloc(dev, sizeof(*m9189), GFP_KERNEL); - if (!m9189) - return -ENOMEM; + m9189 = devm_drm_panel_alloc(dev, __typeof(*m9189), panel, + &m9189_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + + if (IS_ERR(m9189)) + return PTR_ERR(m9189); m9189->supply = devm_regulator_get(dev, "power"); if (IS_ERR(m9189->supply)) @@ -191,8 +194,6 @@ static int lxd_m9189_probe(struct mipi_dsi_device *dsi) dsi->format = MIPI_DSI_FMT_RGB888; dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST; - drm_panel_init(&m9189->panel, dev, &m9189_panel_funcs, - DRM_MODE_CONNECTOR_DSI); m9189->panel.prepare_prev_first = true; ret = drm_panel_of_backlight(&m9189->panel); diff --git a/drivers/gpu/drm/panel/panel-novatek-nt37700f.c b/drivers/gpu/drm/panel/panel-novatek-nt37700f.c index 74f46a268c0f..c221dd498fed 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt37700f.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt37700f.c @@ -225,9 +225,12 @@ static int nt37700f_tianma_probe(struct mipi_dsi_device *dsi) struct nt37700f_tianma *ctx; int ret; - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(dev, __typeof(*ctx), panel, + &nt37700f_tianma_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + + if (IS_ERR(ctx)) + return PTR_ERR(ctx); ctx->supply = devm_regulator_get(dev, "power"); if (IS_ERR(ctx->supply)) @@ -247,8 +250,6 @@ static int nt37700f_tianma_probe(struct mipi_dsi_device *dsi) dsi->mode_flags = MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM; - drm_panel_init(&ctx->panel, dev, &nt37700f_tianma_panel_funcs, - DRM_MODE_CONNECTOR_DSI); ctx->panel.prepare_prev_first = true; ctx->panel.backlight = nt37700f_tianma_create_backlight(dsi); diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e63m0.c b/drivers/gpu/drm/panel/panel-samsung-s6e63m0.c index ea241c89593b..997115b1e541 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e63m0.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6e63m0.c @@ -677,9 +677,13 @@ int s6e63m0_probe(struct device *dev, void *trsp, u32 max_brightness; int ret; - ctx = devm_kzalloc(dev, sizeof(struct s6e63m0), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(dev, __typeof(*ctx), panel, + &s6e63m0_drm_funcs, + dsi_mode ? DRM_MODE_CONNECTOR_DSI : + DRM_MODE_CONNECTOR_DPI); + + if (IS_ERR(ctx)) + return PTR_ERR(ctx); ctx->transport_data = trsp; ctx->dsi_mode = dsi_mode; @@ -712,10 +716,6 @@ int s6e63m0_probe(struct device *dev, void *trsp, return PTR_ERR(ctx->reset_gpio); } - drm_panel_init(&ctx->panel, dev, &s6e63m0_drm_funcs, - dsi_mode ? DRM_MODE_CONNECTOR_DSI : - DRM_MODE_CONNECTOR_DPI); - ret = s6e63m0_backlight_register(ctx, max_brightness); if (ret < 0) return ret; diff --git a/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c b/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c index dd1eaba23ad3..989b030ea22d 100644 --- a/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c +++ b/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c @@ -199,8 +199,6 @@ static int sharp_nt_panel_add(struct sharp_nt_panel *sharp_nt) gpiod_set_value(sharp_nt->reset_gpio, 0); } - drm_panel_init(&sharp_nt->base, &sharp_nt->dsi->dev, - &sharp_nt_panel_funcs, DRM_MODE_CONNECTOR_DSI); sharp_nt->base.prepare_prev_first = true; ret = drm_panel_of_backlight(&sharp_nt->base); @@ -231,9 +229,12 @@ static int sharp_nt_panel_probe(struct mipi_dsi_device *dsi) MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_NO_EOT_PACKET; - sharp_nt = devm_kzalloc(&dsi->dev, sizeof(*sharp_nt), GFP_KERNEL); - if (!sharp_nt) - return -ENOMEM; + sharp_nt = devm_drm_panel_alloc(&dsi->dev, __typeof(*sharp_nt), base, + &sharp_nt_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + + if (IS_ERR(sharp_nt)) + return PTR_ERR(sharp_nt); mipi_dsi_set_drvdata(dsi, sharp_nt); diff --git a/drivers/gpu/drm/panel/panel-startek-kd070fhfid015.c b/drivers/gpu/drm/panel/panel-startek-kd070fhfid015.c index c0c95355b743..7f04b7b404e7 100644 --- a/drivers/gpu/drm/panel/panel-startek-kd070fhfid015.c +++ b/drivers/gpu/drm/panel/panel-startek-kd070fhfid015.c @@ -286,9 +286,6 @@ static int stk_panel_add(struct stk_panel *stk) return ret; } - drm_panel_init(&stk->base, &stk->dsi->dev, &stk_panel_funcs, - DRM_MODE_CONNECTOR_DSI); - drm_panel_add(&stk->base); return 0; @@ -303,9 +300,12 @@ static int stk_panel_probe(struct mipi_dsi_device *dsi) dsi->format = MIPI_DSI_FMT_RGB888; dsi->mode_flags = (MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM); - stk = devm_kzalloc(&dsi->dev, sizeof(*stk), GFP_KERNEL); - if (!stk) - return -ENOMEM; + stk = devm_drm_panel_alloc(&dsi->dev, __typeof(*stk), base, + &stk_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + + if (IS_ERR(stk)) + return PTR_ERR(stk); mipi_dsi_set_drvdata(dsi, stk); diff --git a/drivers/gpu/drm/panel/panel-tdo-tl070wsh30.c b/drivers/gpu/drm/panel/panel-tdo-tl070wsh30.c index 227f97f9b136..13cfe252a838 100644 --- a/drivers/gpu/drm/panel/panel-tdo-tl070wsh30.c +++ b/drivers/gpu/drm/panel/panel-tdo-tl070wsh30.c @@ -162,9 +162,6 @@ static int tdo_tl070wsh30_panel_add(struct tdo_tl070wsh30_panel *tdo_tl070wsh30) return err; } - drm_panel_init(&tdo_tl070wsh30->base, &tdo_tl070wsh30->link->dev, - &tdo_tl070wsh30_panel_funcs, DRM_MODE_CONNECTOR_DSI); - err = drm_panel_of_backlight(&tdo_tl070wsh30->base); if (err) return err; @@ -183,10 +180,13 @@ static int tdo_tl070wsh30_panel_probe(struct mipi_dsi_device *dsi) dsi->format = MIPI_DSI_FMT_RGB888; dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_LPM; - tdo_tl070wsh30 = devm_kzalloc(&dsi->dev, sizeof(*tdo_tl070wsh30), - GFP_KERNEL); - if (!tdo_tl070wsh30) - return -ENOMEM; + tdo_tl070wsh30 = devm_drm_panel_alloc(&dsi->dev, + __typeof(*tdo_tl070wsh30), base, + &tdo_tl070wsh30_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + + if (IS_ERR(tdo_tl070wsh30)) + return PTR_ERR(tdo_tl070wsh30); mipi_dsi_set_drvdata(dsi, tdo_tl070wsh30); tdo_tl070wsh30->link = dsi; diff --git a/drivers/gpu/drm/panel/panel-truly-nt35597.c b/drivers/gpu/drm/panel/panel-truly-nt35597.c index d447db912a61..f740b9257c09 100644 --- a/drivers/gpu/drm/panel/panel-truly-nt35597.c +++ b/drivers/gpu/drm/panel/panel-truly-nt35597.c @@ -476,8 +476,6 @@ static int truly_nt35597_panel_add(struct truly_nt35597 *ctx) /* dual port */ gpiod_set_value(ctx->mode_gpio, 0); - drm_panel_init(&ctx->panel, dev, &truly_nt35597_drm_funcs, - DRM_MODE_CONNECTOR_DSI); drm_panel_add(&ctx->panel); return 0; @@ -523,10 +521,12 @@ static int truly_nt35597_probe(struct mipi_dsi_device *dsi) .node = NULL, }; - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); + ctx = devm_drm_panel_alloc(dev, __typeof(*ctx), panel, + &truly_nt35597_drm_funcs, + DRM_MODE_CONNECTOR_DSI); - if (!ctx) - return -ENOMEM; + if (IS_ERR(ctx)) + return PTR_ERR(ctx); /* * This device represents itself as one with two input ports which are diff --git a/drivers/gpu/drm/panel/panel-visionox-g2647fb105.c b/drivers/gpu/drm/panel/panel-visionox-g2647fb105.c index 413849f7b4de..d5555a173157 100644 --- a/drivers/gpu/drm/panel/panel-visionox-g2647fb105.c +++ b/drivers/gpu/drm/panel/panel-visionox-g2647fb105.c @@ -207,9 +207,12 @@ static int visionox_g2647fb105_probe(struct mipi_dsi_device *dsi) struct visionox_g2647fb105 *ctx; int ret; - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = devm_drm_panel_alloc(dev, __typeof(*ctx), panel, + &visionox_g2647fb105_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + + if (IS_ERR(ctx)) + return PTR_ERR(ctx); ret = devm_regulator_bulk_get_const(dev, ARRAY_SIZE(visionox_g2647fb105_supplies), @@ -233,10 +236,6 @@ static int visionox_g2647fb105_probe(struct mipi_dsi_device *dsi) ctx->panel.prepare_prev_first = true; - drm_panel_init(&ctx->panel, dev, &visionox_g2647fb105_panel_funcs, - DRM_MODE_CONNECTOR_DSI); - ctx->panel.prepare_prev_first = true; - ctx->panel.backlight = visionox_g2647fb105_create_backlight(dsi); if (IS_ERR(ctx->panel.backlight)) return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight), diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c index a7ee14986849..452d0b6d4668 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu.c +++ b/drivers/gpu/drm/panthor/panthor_mmu.c @@ -2377,14 +2377,20 @@ int panthor_vm_evict_bo_mappings_locked(struct panthor_gem_object *bo) struct panthor_vm *vm = container_of(vm_bo->vm, struct panthor_vm, base); struct drm_gpuva *va; - /* Skip already evicted GPU mappings. */ - if (vm_bo->evicted) - continue; - if (!mutex_trylock(&vm->op_lock)) return -EDEADLK; - drm_gpuvm_bo_evict(vm_bo, true); + /* It can be that the vm_bo was already evicted but a new + * mapping pointing to this BO got created in the meantime, + * thus turning the vm_bo in partially evicted state. In that case + * we don't call drm_gpuvm_bo_evict() again because this would + * mess up with the internal gpuvm lists, but we do walk the + * VAs on this vm_bo to make sure the non-evicted ones are + * torn down. + */ + if (!vm_bo->evicted) + drm_gpuvm_bo_evict(vm_bo, true); + drm_gpuvm_bo_for_each_va(va, vm_bo) { struct panthor_vma *vma = container_of(va, struct panthor_vma, base); diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h index f17660a71a3e..6f49213e23f8 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.h +++ b/drivers/gpu/drm/virtio/virtgpu_drv.h @@ -84,6 +84,7 @@ struct virtio_gpu_object_params { uint32_t blob_mem; uint32_t blob_flags; uint64_t blob_id; + uint32_t blob_hints; }; struct virtio_gpu_object { @@ -507,6 +508,7 @@ struct sg_table *virtio_gpu_vram_map_dma_buf(struct virtio_gpu_object *bo, void virtio_gpu_vram_unmap_dma_buf(struct device *dev, struct sg_table *sgt, enum dma_data_direction dir); +void virtio_gpu_vram_map_deferred(struct virtio_gpu_object_vram *vram); /* virtgpu_submit.c */ int virtio_gpu_execbuffer_ioctl(struct drm_device *dev, void *data, diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c index c33c057365f8..01daa72b1310 100644 --- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c +++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c @@ -489,6 +489,7 @@ static int verify_blob(struct virtio_gpu_device *vgdev, params->size = rc_blob->size; params->blob = true; params->blob_flags = rc_blob->blob_flags; + params->blob_hints = rc_blob->blob_hints; return 0; } diff --git a/drivers/gpu/drm/virtio/virtgpu_vram.c b/drivers/gpu/drm/virtio/virtgpu_vram.c index 084e80227433..4ae3cbc35dd3 100644 --- a/drivers/gpu/drm/virtio/virtgpu_vram.c +++ b/drivers/gpu/drm/virtio/virtgpu_vram.c @@ -3,6 +3,8 @@ #include <linux/dma-mapping.h> +static DEFINE_MUTEX(map_lock); + static void virtio_gpu_vram_free(struct drm_gem_object *obj) { struct virtio_gpu_object *bo = gem_to_virtio_gpu_obj(obj); @@ -42,6 +44,11 @@ static int virtio_gpu_vram_mmap(struct drm_gem_object *obj, if (!(bo->blob_flags & VIRTGPU_BLOB_FLAG_USE_MAPPABLE)) return -EINVAL; + virtio_gpu_vram_map_deferred(vram); + + if (vram->map_state == STATE_INITIALIZING) + virtio_gpu_notify(vgdev); + wait_event(vgdev->resp_wq, vram->map_state != STATE_INITIALIZING); if (vram->map_state != STATE_OK) return -EINVAL; @@ -218,14 +225,27 @@ int virtio_gpu_vram_create(struct virtio_gpu_device *vgdev, virtio_gpu_cmd_resource_create_blob(vgdev, &vram->base, params, NULL, 0); - if (params->blob_flags & VIRTGPU_BLOB_FLAG_USE_MAPPABLE) { - ret = virtio_gpu_vram_map(&vram->base); - if (ret) { - virtio_gpu_vram_free(obj); - return ret; + if (!(params->blob_hints & DRM_VIRTGPU_BLOB_FLAG_HINT_DEFER_MAPPING)) { + if (params->blob_flags & VIRTGPU_BLOB_FLAG_USE_MAPPABLE) { + ret = virtio_gpu_vram_map(&vram->base); + if (ret) { + virtio_gpu_vram_free(obj); + return ret; + } } } *bo_ptr = &vram->base; return 0; } + +void virtio_gpu_vram_map_deferred(struct virtio_gpu_object_vram *vram) +{ + if (!(vram->base.blob_flags & VIRTGPU_BLOB_FLAG_USE_MAPPABLE)) + return; + + mutex_lock(&map_lock); + if (!drm_mm_node_allocated(&vram->vram_node)) + virtio_gpu_vram_map(&vram->base); + mutex_unlock(&map_lock); +} diff --git a/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c b/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c index 6ba47996bc7c..9f67df646955 100644 --- a/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c +++ b/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c @@ -322,6 +322,7 @@ int __xe_ttm_vram_mgr_init(struct xe_device *xe, struct xe_ttm_vram_mgr *mgr, if (err) return err; + gpu_buddy_driver_set_lock(&mgr->mm, &mgr->lock); ttm_set_driver_manager(&xe->ttm, mem_type, &mgr->manager); ttm_resource_manager_set_used(&mgr->manager, true); diff --git a/include/drm/display/drm_dp.h b/include/drm/display/drm_dp.h index 8b15d3eeb716..829e4d98d61c 100644 --- a/include/drm/display/drm_dp.h +++ b/include/drm/display/drm_dp.h @@ -718,6 +718,12 @@ #define DP_EXTENDED_DPRX_SLEEP_WAKE_TIMEOUT_GRANT 0x119 /* 1.4a */ # define DP_DPRX_SLEEP_WAKE_TIMEOUT_PERIOD_GRANTED (1 << 0) +#define PANEL_REPLAY_CONFIG3 0x11a /* DP 2.1 */ +# define DP_PR_AS_SDP_SETUP_TIME_MASK (3 << 6) +# define DP_PR_AS_SDP_SETUP_TIME_T1 (0 << 6) +# define DP_PR_AS_SDP_SETUP_TIME_DYNAMIC (1 << 6) /* DP 2.1 Table 2-227 */ +# define DP_PR_AS_SDP_SETUP_TIME_T2 (2 << 6) + #define DP_FEC_CONFIGURATION 0x120 /* 1.4 */ # define DP_FEC_READY (1 << 0) # define DP_FEC_ERR_COUNT_SEL_MASK (7 << 1) @@ -1202,12 +1208,11 @@ # define DP_DPRX_SLEEP_WAKE_TIMEOUT_PERIOD_80_MS 0x04 # define DP_DPRX_SLEEP_WAKE_TIMEOUT_PERIOD_100_MS 0x05 -#define DP_DPRX_FEATURE_ENUMERATION_LIST_CONT_1 0x2214 /* 2.0 E11 */ -# define DP_ADAPTIVE_SYNC_SDP_SUPPORTED (1 << 0) -# define DP_ADAPTIVE_SYNC_SDP_OPERATION_MODE GENMASK(1, 0) -# define DP_ADAPTIVE_SYNC_SDP_LENGTH GENMASK(5, 0) -# define DP_AS_SDP_FIRST_HALF_LINE_OR_3840_PIXEL_CYCLE_WINDOW_NOT_SUPPORTED (1 << 1) -# define DP_VSC_EXT_SDP_FRAMEWORK_VERSION_1_SUPPORTED (1 << 4) +#define DP_DPRX_FEATURE_ENUMERATION_LIST_CONT_1 0x2214 /* 2.0 E11 */ +# define DP_ADAPTIVE_SYNC_SDP_SUPPORTED BIT(0) +# define DP_AS_SDP_FIRST_HALF_LINE_OR_3840_PIXEL_CYCLE_WINDOW_NOT_SUPPORTED BIT(1) +# define DP_AS_SDP_FAVT_PAYLOAD_FIELDS_PARSING_SUPPORTED BIT(2) /* 2.1 */ +# define DP_VSC_EXT_SDP_FRAMEWORK_VERSION_1_SUPPORTED BIT(4) #define DP_128B132B_SUPPORTED_LINK_RATES 0x2215 /* 2.0 */ # define DP_UHBR10 (1 << 0) @@ -1870,4 +1875,7 @@ enum operation_mode { DP_AS_SDP_FAVT_TRR_REACHED = 0x03 }; +#define DP_AS_SDP_OPERATION_MODE_MASK GENMASK(1, 0) +#define DP_AS_SDP_LENGTH_MASK GENMASK(5, 0) + #endif /* _DRM_DP_H_ */ diff --git a/include/drm/display/drm_dp_helper.h b/include/drm/display/drm_dp_helper.h index 1d0acd58f486..8c2d77a032f0 100644 --- a/include/drm/display/drm_dp_helper.h +++ b/include/drm/display/drm_dp_helper.h @@ -126,6 +126,7 @@ struct drm_dp_as_sdp { int duration_decr_ms; bool target_rr_divider; enum operation_mode mode; + int coasting_vtotal; }; void drm_dp_as_sdp_log(struct drm_printer *p, diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h index 1fb9148dd095..86b3f9c65c92 100644 --- a/include/drm/drm_panel.h +++ b/include/drm/drm_panel.h @@ -320,10 +320,6 @@ void *__devm_drm_panel_alloc(struct device *dev, size_t size, size_t offset, offsetof(type, member), funcs, \ connector_type)) -void drm_panel_init(struct drm_panel *panel, struct device *dev, - const struct drm_panel_funcs *funcs, - int connector_type); - struct drm_panel *drm_panel_get(struct drm_panel *panel); void drm_panel_put(struct drm_panel *panel); diff --git a/include/drm/ttm/ttm_placement.h b/include/drm/ttm/ttm_placement.h index b510a4812609..ab2639e42c54 100644 --- a/include/drm/ttm/ttm_placement.h +++ b/include/drm/ttm/ttm_placement.h @@ -81,8 +81,8 @@ * Structure indicating a possible place to put an object. */ struct ttm_place { - unsigned fpfn; - unsigned lpfn; + uint64_t fpfn; + uint64_t lpfn; uint32_t mem_type; uint32_t flags; }; diff --git a/include/linux/gpu_buddy.h b/include/linux/gpu_buddy.h index 5fa917ba5450..71941a039648 100644 --- a/include/linux/gpu_buddy.h +++ b/include/linux/gpu_buddy.h @@ -154,6 +154,7 @@ struct gpu_buddy_block { * @avail: Total free space currently available for allocation in bytes. * @clear_avail: Free space available in the clear tree (zeroed memory) in bytes. * This is a subset of @avail. + * @lock_dep_map: Annotates gpu_buddy API with a driver provided lock. */ struct gpu_buddy { /* private: */ @@ -179,8 +180,48 @@ struct gpu_buddy { u64 size; u64 avail; u64 clear_avail; +#ifdef CONFIG_LOCKDEP + struct lockdep_map *lock_dep_map; +#endif }; +#ifdef CONFIG_LOCKDEP +/** + * gpu_buddy_driver_set_lock() - Set the lock protecting accesses to GPU BUDDY + * @mm: Pointer to GPU buddy structure. + * @lock: the lock used to protect the gpu buddy. The locking primitive + * must contain a dep_map field. + * + * Call this to annotate gpu_buddy APIs which access/modify gpu_buddy manager + */ +#define gpu_buddy_driver_set_lock(mm, lock) \ + do { \ + struct gpu_buddy *__mm = (mm); \ + if (!WARN(__mm->lock_dep_map, "GPU BUDDY MM lock should be set only once.")) \ + __mm->lock_dep_map = &(lock)->dep_map; \ + } while (0) +#else +#define gpu_buddy_driver_set_lock(mm, lock) do { (void)(mm); (void)(lock); } while (0) +#endif + +#ifdef CONFIG_LOCKDEP +/** + * gpu_buddy_driver_lock_held() - Assert GPU BUDDY manager lock is held + * @mm: Pointer to the GPU BUDDY structure. + * + * Ensure driver lock is held. + */ +static inline void gpu_buddy_driver_lock_held(struct gpu_buddy *mm) +{ + if (mm->lock_dep_map) + lockdep_assert(lock_is_held_type(mm->lock_dep_map, 0)); +} +#else +static inline void gpu_buddy_driver_lock_held(struct gpu_buddy *mm) +{ +} +#endif + static inline u64 gpu_buddy_block_offset(const struct gpu_buddy_block *block) { diff --git a/include/uapi/drm/amdxdna_accel.h b/include/uapi/drm/amdxdna_accel.h index 0b11e8e3ea5d..51a507561df6 100644 --- a/include/uapi/drm/amdxdna_accel.h +++ b/include/uapi/drm/amdxdna_accel.h @@ -18,6 +18,7 @@ extern "C" { #define AMDXDNA_INVALID_CTX_HANDLE 0 #define AMDXDNA_INVALID_BO_HANDLE 0 #define AMDXDNA_INVALID_FENCE_HANDLE 0 +#define AMDXDNA_INVALID_DOORBELL_OFFSET (~0U) /* * Define hardware context priority @@ -30,6 +31,7 @@ extern "C" { enum amdxdna_device_type { AMDXDNA_DEV_TYPE_UNKNOWN = -1, AMDXDNA_DEV_TYPE_KMQ = 0, + AMDXDNA_DEV_TYPE_UMQ = 1, AMDXDNA_DEV_TYPE_PF = 2, }; @@ -43,7 +45,8 @@ enum amdxdna_drm_ioctl_id { DRM_AMDXDNA_EXEC_CMD, DRM_AMDXDNA_GET_INFO, DRM_AMDXDNA_SET_STATE, - DRM_AMDXDNA_GET_ARRAY = 10, + DRM_AMDXDNA_WAIT_CMD, + DRM_AMDXDNA_GET_ARRAY, }; /** @@ -273,6 +276,21 @@ struct amdxdna_drm_exec_cmd { }; /** + * struct amdxdna_drm_wait_cmd - Wait execution command. + * + * @hwctx: Context handle. + * @timeout: timeout in ms, 0 implies infinite wait. + * @seq: sequence number of the command returned by execute command. + * + * Wait a command specified by seq to be completed. + */ +struct amdxdna_drm_wait_cmd { + __u32 hwctx; + __u32 timeout; + __u64 seq; +}; + +/** * struct amdxdna_drm_query_aie_status - Query the status of the AIE hardware * @buffer: The user space buffer that will return the AIE status. * @buffer_size: The size of the user space buffer. @@ -737,6 +755,10 @@ struct amdxdna_drm_set_power_mode { DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDXDNA_GET_ARRAY, \ struct amdxdna_drm_get_array) +#define DRM_IOCTL_AMDXDNA_WAIT_CMD \ + DRM_IOW(DRM_COMMAND_BASE + DRM_AMDXDNA_WAIT_CMD, \ + struct amdxdna_drm_wait_cmd) + #if defined(__cplusplus) } /* extern c end */ #endif diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h index 15aa0a8f44b0..3a4d4dc635bf 100644 --- a/include/uapi/drm/drm_fourcc.h +++ b/include/uapi/drm/drm_fourcc.h @@ -224,9 +224,9 @@ extern "C" { * [31:0] sign:exponent:mantissa 1:8:23 */ #define DRM_FORMAT_R32F fourcc_code('R', ' ', ' ', 'F') /* [31:0] R 32 little endian */ -#define DRM_FORMAT_GR3232F fourcc_code('G', 'R', ' ', 'F') /* [63:0] R:G 32:32 little endian */ -#define DRM_FORMAT_BGR323232F fourcc_code('B', 'G', 'R', 'F') /* [95:0] R:G:B 32:32:32 little endian */ -#define DRM_FORMAT_ABGR32323232F fourcc_code('A', 'B', '8', 'F') /* [127:0] R:G:B:A 32:32:32:32 little endian */ +#define DRM_FORMAT_GR3232F fourcc_code('G', 'R', ' ', 'F') /* [63:0] G:R 32:32 little endian */ +#define DRM_FORMAT_BGR323232F fourcc_code('B', 'G', 'R', 'F') /* [95:0] B:G:R 32:32:32 little endian */ +#define DRM_FORMAT_ABGR32323232F fourcc_code('A', 'B', '8', 'F') /* [127:0] A:B:G:R 32:32:32:32 little endian */ /* * RGBA format with 10-bit components packed in 64-bit per pixel, with 6 bits diff --git a/include/uapi/drm/virtgpu_drm.h b/include/uapi/drm/virtgpu_drm.h index 9debb320c34b..ba09a4ee3e77 100644 --- a/include/uapi/drm/virtgpu_drm.h +++ b/include/uapi/drm/virtgpu_drm.h @@ -200,6 +200,10 @@ struct drm_virtgpu_resource_create_blob { __u32 cmd_size; __u64 cmd; __u64 blob_id; + +#define DRM_VIRTGPU_BLOB_FLAG_HINT_DEFER_MAPPING 0x0001 + __u32 blob_hints; + __u32 pad2; }; #define VIRTGPU_CONTEXT_PARAM_CAPSET_ID 0x0001 |
