From c51549cf16d39398499445f6b0004cf84d158265 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 28 Jan 2025 10:47:19 +0100 Subject: [PATCH 01/16] dt-bindings: display: renesas,du: add top-level constraints Properties with variable number of items per each device are expected to have widest constraints in top-level "properties:" block and further customized (narrowed) in "if:then:". Add missing top-level constraints for clocks, clock-names, interrupts, resets, reset-names, renesas,cmms and renesas,vsps. Reviewed-by: Laurent Pinchart Acked-by: Conor Dooley Signed-off-by: Krzysztof Kozlowski Reviewed-by: Tomi Valkeinen Signed-off-by: Tomi Valkeinen Link: https://patchwork.freedesktop.org/patch/msgid/20250128094719.63776-2-krzysztof.kozlowski@linaro.org --- .../bindings/display/renesas,du.yaml | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/display/renesas,du.yaml b/Documentation/devicetree/bindings/display/renesas,du.yaml index 88ecabc4348d..c27dfea7fc62 100644 --- a/Documentation/devicetree/bindings/display/renesas,du.yaml +++ b/Documentation/devicetree/bindings/display/renesas,du.yaml @@ -47,12 +47,26 @@ properties: maxItems: 1 # See compatible-specific constraints below. - clocks: true - clock-names: true + clocks: + minItems: 1 + maxItems: 8 + + clock-names: + minItems: 1 + maxItems: 8 + interrupts: + minItems: 1 + maxItems: 4 description: Interrupt specifiers, one per DU channel - resets: true - reset-names: true + + resets: + minItems: 1 + maxItems: 2 + + reset-names: + minItems: 1 + maxItems: 2 power-domains: maxItems: 1 @@ -74,7 +88,7 @@ properties: renesas,cmms: $ref: /schemas/types.yaml#/definitions/phandle-array - minItems: 1 + minItems: 2 maxItems: 4 items: maxItems: 1 -- 2.51.0 From c28f72c6ca98e039c2aa5aac6752c416bc31dbab Mon Sep 17 00:00:00 2001 From: Jocelyn Falempe Date: Fri, 24 Jan 2025 15:11:31 +0100 Subject: [PATCH 02/16] drm/ast: Fix ast_dp connection status ast_dp_is_connected() used to also check for link training success to report the DP connector as connected. Without this check, the physical_status is always connected. So if no monitor is present, it will fail to read the EDID and set the default resolution to 640x480 instead of 1024x768. Signed-off-by: Jocelyn Falempe Fixes: 2281475168d2 ("drm/ast: astdp: Perform link training during atomic_enable") Reported-by: Jerry Hoemann Tested-by: Jose Lopez Cc: Thomas Zimmermann Cc: Dave Airlie Cc: dri-devel@lists.freedesktop.org Cc: # v6.12+ Reviewed-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20250124141142.2434138-1-jfalempe@redhat.com --- drivers/gpu/drm/ast/ast_dp.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/ast/ast_dp.c b/drivers/gpu/drm/ast/ast_dp.c index 0e282b7b167c..30aad5c0112a 100644 --- a/drivers/gpu/drm/ast/ast_dp.c +++ b/drivers/gpu/drm/ast/ast_dp.c @@ -17,6 +17,12 @@ static bool ast_astdp_is_connected(struct ast_device *ast) { if (!ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xDF, AST_IO_VGACRDF_HPD)) return false; + /* + * HPD might be set even if no monitor is connected, so also check that + * the link training was successful. + */ + if (!ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xDC, AST_IO_VGACRDC_LINK_SUCCESS)) + return false; return true; } -- 2.51.0 From d07569ebcbd645e6afac7145b2daea11da5c6384 Mon Sep 17 00:00:00 2001 From: Matthew Leung Date: Fri, 17 Jan 2025 10:09:37 -0700 Subject: [PATCH 03/16] bus: mhi: host: Refactor BHI/BHIe based firmware loading Refactor the firmware loading code to have distinct helper functions for BHI and BHIe operations. This lays the foundation for separating the firmware loading protocol from the firmware being loaded and the EE it is loaded in. Signed-off-by: Matthew Leung Reviewed-by: Youssef Samir Reviewed-by: Jeffrey Hugo Signed-off-by: Jeffrey Hugo Reviewed-by: Manivannan Sadhasivam Link: https://patchwork.freedesktop.org/patch/msgid/20250117170943.2643280-2-quic_jhugo@quicinc.com --- drivers/bus/mhi/host/boot.c | 144 +++++++++++++++++++++++++----------- 1 file changed, 99 insertions(+), 45 deletions(-) diff --git a/drivers/bus/mhi/host/boot.c b/drivers/bus/mhi/host/boot.c index e8c92972f9df..9fe13d3f09f0 100644 --- a/drivers/bus/mhi/host/boot.c +++ b/drivers/bus/mhi/host/boot.c @@ -177,6 +177,36 @@ int mhi_download_rddm_image(struct mhi_controller *mhi_cntrl, bool in_panic) } EXPORT_SYMBOL_GPL(mhi_download_rddm_image); +static void mhi_fw_load_error_dump(struct mhi_controller *mhi_cntrl) +{ + struct device *dev = &mhi_cntrl->mhi_dev->dev; + rwlock_t *pm_lock = &mhi_cntrl->pm_lock; + void __iomem *base = mhi_cntrl->bhi; + int ret, i; + u32 val; + struct { + char *name; + u32 offset; + } error_reg[] = { + { "ERROR_CODE", BHI_ERRCODE }, + { "ERROR_DBG1", BHI_ERRDBG1 }, + { "ERROR_DBG2", BHI_ERRDBG2 }, + { "ERROR_DBG3", BHI_ERRDBG3 }, + { NULL }, + }; + + read_lock_bh(pm_lock); + if (MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) { + for (i = 0; error_reg[i].name; i++) { + ret = mhi_read_reg(mhi_cntrl, base, error_reg[i].offset, &val); + if (ret) + break; + dev_err(dev, "Reg: %s value: 0x%x\n", error_reg[i].name, val); + } + } + read_unlock_bh(pm_lock); +} + static int mhi_fw_load_bhie(struct mhi_controller *mhi_cntrl, const struct mhi_buf *mhi_buf) { @@ -226,24 +256,13 @@ static int mhi_fw_load_bhie(struct mhi_controller *mhi_cntrl, } static int mhi_fw_load_bhi(struct mhi_controller *mhi_cntrl, - dma_addr_t dma_addr, - size_t size) + const struct mhi_buf *mhi_buf) { - u32 tx_status, val, session_id; - int i, ret; - void __iomem *base = mhi_cntrl->bhi; - rwlock_t *pm_lock = &mhi_cntrl->pm_lock; struct device *dev = &mhi_cntrl->mhi_dev->dev; - struct { - char *name; - u32 offset; - } error_reg[] = { - { "ERROR_CODE", BHI_ERRCODE }, - { "ERROR_DBG1", BHI_ERRDBG1 }, - { "ERROR_DBG2", BHI_ERRDBG2 }, - { "ERROR_DBG3", BHI_ERRDBG3 }, - { NULL }, - }; + rwlock_t *pm_lock = &mhi_cntrl->pm_lock; + void __iomem *base = mhi_cntrl->bhi; + u32 tx_status, session_id; + int ret; read_lock_bh(pm_lock); if (!MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) { @@ -255,11 +274,9 @@ static int mhi_fw_load_bhi(struct mhi_controller *mhi_cntrl, dev_dbg(dev, "Starting image download via BHI. Session ID: %u\n", session_id); mhi_write_reg(mhi_cntrl, base, BHI_STATUS, 0); - mhi_write_reg(mhi_cntrl, base, BHI_IMGADDR_HIGH, - upper_32_bits(dma_addr)); - mhi_write_reg(mhi_cntrl, base, BHI_IMGADDR_LOW, - lower_32_bits(dma_addr)); - mhi_write_reg(mhi_cntrl, base, BHI_IMGSIZE, size); + mhi_write_reg(mhi_cntrl, base, BHI_IMGADDR_HIGH, upper_32_bits(mhi_buf->dma_addr)); + mhi_write_reg(mhi_cntrl, base, BHI_IMGADDR_LOW, lower_32_bits(mhi_buf->dma_addr)); + mhi_write_reg(mhi_cntrl, base, BHI_IMGSIZE, mhi_buf->len); mhi_write_reg(mhi_cntrl, base, BHI_IMGTXDB, session_id); read_unlock_bh(pm_lock); @@ -274,18 +291,7 @@ static int mhi_fw_load_bhi(struct mhi_controller *mhi_cntrl, if (tx_status == BHI_STATUS_ERROR) { dev_err(dev, "Image transfer failed\n"); - read_lock_bh(pm_lock); - if (MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) { - for (i = 0; error_reg[i].name; i++) { - ret = mhi_read_reg(mhi_cntrl, base, - error_reg[i].offset, &val); - if (ret) - break; - dev_err(dev, "Reg: %s value: 0x%x\n", - error_reg[i].name, val); - } - } - read_unlock_bh(pm_lock); + mhi_fw_load_error_dump(mhi_cntrl); goto invalid_pm_state; } @@ -296,6 +302,16 @@ invalid_pm_state: return -EIO; } +static void mhi_free_bhi_buffer(struct mhi_controller *mhi_cntrl, + struct image_info *image_info) +{ + struct mhi_buf *mhi_buf = image_info->mhi_buf; + + dma_free_coherent(mhi_cntrl->cntrl_dev, mhi_buf->len, mhi_buf->buf, mhi_buf->dma_addr); + kfree(image_info->mhi_buf); + kfree(image_info); +} + void mhi_free_bhie_table(struct mhi_controller *mhi_cntrl, struct image_info *image_info) { @@ -310,6 +326,45 @@ void mhi_free_bhie_table(struct mhi_controller *mhi_cntrl, kfree(image_info); } +static int mhi_alloc_bhi_buffer(struct mhi_controller *mhi_cntrl, + struct image_info **image_info, + size_t alloc_size) +{ + struct image_info *img_info; + struct mhi_buf *mhi_buf; + + img_info = kzalloc(sizeof(*img_info), GFP_KERNEL); + if (!img_info) + return -ENOMEM; + + /* Allocate memory for entry */ + img_info->mhi_buf = kzalloc(sizeof(*img_info->mhi_buf), GFP_KERNEL); + if (!img_info->mhi_buf) + goto error_alloc_mhi_buf; + + /* Allocate and populate vector table */ + mhi_buf = img_info->mhi_buf; + + mhi_buf->len = alloc_size; + mhi_buf->buf = dma_alloc_coherent(mhi_cntrl->cntrl_dev, mhi_buf->len, + &mhi_buf->dma_addr, GFP_KERNEL); + if (!mhi_buf->buf) + goto error_alloc_segment; + + img_info->bhi_vec = NULL; + img_info->entries = 1; + *image_info = img_info; + + return 0; + +error_alloc_segment: + kfree(mhi_buf); +error_alloc_mhi_buf: + kfree(img_info); + + return -ENOMEM; +} + int mhi_alloc_bhie_table(struct mhi_controller *mhi_cntrl, struct image_info **image_info, size_t alloc_size) @@ -364,9 +419,9 @@ error_alloc_mhi_buf: return -ENOMEM; } -static void mhi_firmware_copy(struct mhi_controller *mhi_cntrl, - const u8 *buf, size_t remainder, - struct image_info *img_info) +static void mhi_firmware_copy_bhie(struct mhi_controller *mhi_cntrl, + const u8 *buf, size_t remainder, + struct image_info *img_info) { size_t to_cpy; struct mhi_buf *mhi_buf = img_info->mhi_buf; @@ -390,10 +445,9 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl) const struct firmware *firmware = NULL; struct device *dev = &mhi_cntrl->mhi_dev->dev; enum mhi_pm_state new_state; + struct image_info *image; const char *fw_name; const u8 *fw_data; - void *buf; - dma_addr_t dma_addr; size_t size, fw_sz; int ret; @@ -452,17 +506,17 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl) fw_sz = firmware->size; skip_req_fw: - buf = dma_alloc_coherent(mhi_cntrl->cntrl_dev, size, &dma_addr, - GFP_KERNEL); - if (!buf) { + ret = mhi_alloc_bhi_buffer(mhi_cntrl, &image, size); + if (ret) { release_firmware(firmware); goto error_fw_load; } + /* Load the firmware into BHI vec table */ + memcpy(image->mhi_buf->buf, fw_data, size); /* Download image using BHI */ - memcpy(buf, fw_data, size); - ret = mhi_fw_load_bhi(mhi_cntrl, dma_addr, size); - dma_free_coherent(mhi_cntrl->cntrl_dev, size, buf, dma_addr); + ret = mhi_fw_load_bhi(mhi_cntrl, image->mhi_buf); + mhi_free_bhi_buffer(mhi_cntrl, image); /* Error or in EDL mode, we're done */ if (ret) { @@ -493,7 +547,7 @@ skip_req_fw: } /* Load the firmware into BHIE vec table */ - mhi_firmware_copy(mhi_cntrl, fw_data, fw_sz, mhi_cntrl->fbc_image); + mhi_firmware_copy_bhie(mhi_cntrl, fw_data, fw_sz, mhi_cntrl->fbc_image); } release_firmware(firmware); -- 2.51.0 From f88f1d0998ea2e5779a44013dde2a3503322c98e Mon Sep 17 00:00:00 2001 From: Matthew Leung Date: Fri, 17 Jan 2025 10:09:38 -0700 Subject: [PATCH 04/16] bus: mhi: host: Add a policy to enable image transfer via BHIe in PBL Currently, MHI host only performs firmware transfer via BHI in PBL and BHIe from SBL. To support BHIe transfer directly from PBL, a policy needs to be added. With this policy, BHIe will be used to transfer firmware in PBL if the MHI controller has BHIe regs, sets seg_len, and does not set fbc_download. The intention is to transfer firmware using BHIe in PBL without further BHIe transfers in SBL. Signed-off-by: Matthew Leung Reviewed-by: Youssef Samir Reviewed-by: Jeffrey Hugo Signed-off-by: Jeffrey Hugo Reviewed-by: Jacek Lawrynowicz Reviewed-by: Manivannan Sadhasivam Link: https://patchwork.freedesktop.org/patch/msgid/20250117170943.2643280-3-quic_jhugo@quicinc.com --- drivers/bus/mhi/host/boot.c | 73 ++++++++++++++++++++++++++------- drivers/bus/mhi/host/init.c | 2 +- drivers/bus/mhi/host/internal.h | 7 ++++ 3 files changed, 66 insertions(+), 16 deletions(-) diff --git a/drivers/bus/mhi/host/boot.c b/drivers/bus/mhi/host/boot.c index 9fe13d3f09f0..a206c3f0fcfd 100644 --- a/drivers/bus/mhi/host/boot.c +++ b/drivers/bus/mhi/host/boot.c @@ -440,12 +440,59 @@ static void mhi_firmware_copy_bhie(struct mhi_controller *mhi_cntrl, } } +static enum mhi_fw_load_type mhi_fw_load_type_get(const struct mhi_controller *mhi_cntrl) +{ + if (mhi_cntrl->fbc_download) { + return MHI_FW_LOAD_FBC; + } else { + if (mhi_cntrl->seg_len) + return MHI_FW_LOAD_BHIE; + else + return MHI_FW_LOAD_BHI; + } +} + +static int mhi_load_image_bhi(struct mhi_controller *mhi_cntrl, const u8 *fw_data, size_t size) +{ + struct image_info *image; + int ret; + + ret = mhi_alloc_bhi_buffer(mhi_cntrl, &image, size); + if (ret) + return ret; + + /* Load the firmware into BHI vec table */ + memcpy(image->mhi_buf->buf, fw_data, size); + + ret = mhi_fw_load_bhi(mhi_cntrl, &image->mhi_buf[image->entries - 1]); + mhi_free_bhi_buffer(mhi_cntrl, image); + + return ret; +} + +static int mhi_load_image_bhie(struct mhi_controller *mhi_cntrl, const u8 *fw_data, size_t size) +{ + struct image_info *image; + int ret; + + ret = mhi_alloc_bhie_table(mhi_cntrl, &image, size); + if (ret) + return ret; + + mhi_firmware_copy_bhie(mhi_cntrl, fw_data, size, image); + + ret = mhi_fw_load_bhie(mhi_cntrl, &image->mhi_buf[image->entries - 1]); + mhi_free_bhie_table(mhi_cntrl, image); + + return ret; +} + void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl) { const struct firmware *firmware = NULL; struct device *dev = &mhi_cntrl->mhi_dev->dev; + enum mhi_fw_load_type fw_load_type; enum mhi_pm_state new_state; - struct image_info *image; const char *fw_name; const u8 *fw_data; size_t size, fw_sz; @@ -506,21 +553,17 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl) fw_sz = firmware->size; skip_req_fw: - ret = mhi_alloc_bhi_buffer(mhi_cntrl, &image, size); - if (ret) { - release_firmware(firmware); - goto error_fw_load; - } - /* Load the firmware into BHI vec table */ - memcpy(image->mhi_buf->buf, fw_data, size); - - /* Download image using BHI */ - ret = mhi_fw_load_bhi(mhi_cntrl, image->mhi_buf); - mhi_free_bhi_buffer(mhi_cntrl, image); + fw_load_type = mhi_fw_load_type_get(mhi_cntrl); + if (fw_load_type == MHI_FW_LOAD_BHIE) + ret = mhi_load_image_bhie(mhi_cntrl, fw_data, size); + else + ret = mhi_load_image_bhi(mhi_cntrl, fw_data, size); /* Error or in EDL mode, we're done */ if (ret) { - dev_err(dev, "MHI did not load image over BHI, ret: %d\n", ret); + dev_err(dev, "MHI did not load image over BHI%s, ret: %d\n", + fw_load_type == MHI_FW_LOAD_BHIE ? "e" : "", + ret); release_firmware(firmware); goto error_fw_load; } @@ -539,7 +582,7 @@ skip_req_fw: * If we're doing fbc, populate vector tables while * device transitioning into MHI READY state */ - if (mhi_cntrl->fbc_download) { + if (fw_load_type == MHI_FW_LOAD_FBC) { ret = mhi_alloc_bhie_table(mhi_cntrl, &mhi_cntrl->fbc_image, fw_sz); if (ret) { release_firmware(firmware); @@ -564,7 +607,7 @@ fw_load_ready_state: return; error_ready_state: - if (mhi_cntrl->fbc_download) { + if (fw_load_type == MHI_FW_LOAD_FBC) { mhi_free_bhie_table(mhi_cntrl, mhi_cntrl->fbc_image); mhi_cntrl->fbc_image = NULL; } diff --git a/drivers/bus/mhi/host/init.c b/drivers/bus/mhi/host/init.c index a9b1f8beee7b..13e7a55f54ff 100644 --- a/drivers/bus/mhi/host/init.c +++ b/drivers/bus/mhi/host/init.c @@ -1144,7 +1144,7 @@ int mhi_prepare_for_power_up(struct mhi_controller *mhi_cntrl) } mhi_cntrl->bhi = mhi_cntrl->regs + bhi_off; - if (mhi_cntrl->fbc_download || mhi_cntrl->rddm_size) { + if (mhi_cntrl->fbc_download || mhi_cntrl->rddm_size || mhi_cntrl->seg_len) { ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->regs, BHIEOFF, &bhie_off); if (ret) { diff --git a/drivers/bus/mhi/host/internal.h b/drivers/bus/mhi/host/internal.h index 3134f111be35..ce566f7d2e92 100644 --- a/drivers/bus/mhi/host/internal.h +++ b/drivers/bus/mhi/host/internal.h @@ -29,6 +29,13 @@ struct bhi_vec_entry { u64 size; }; +enum mhi_fw_load_type { + MHI_FW_LOAD_BHI, /* BHI only in PBL */ + MHI_FW_LOAD_BHIE, /* BHIe only in PBL */ + MHI_FW_LOAD_FBC, /* BHI in PBL followed by BHIe in SBL */ + MHI_FW_LOAD_MAX, +}; + enum mhi_ch_state_type { MHI_CH_STATE_TYPE_RESET, MHI_CH_STATE_TYPE_STOP, -- 2.51.0 From ab73d80836734bb76088be0da4d2dbf0f7914c2d Mon Sep 17 00:00:00 2001 From: Youssef Samir Date: Fri, 17 Jan 2025 10:09:39 -0700 Subject: [PATCH 05/16] accel/qaic: Allocate an exact number of MSIs Devices use 1 MSI vector for the MHI controller and as many vectors as the DMA bridge channels on the device. During the probing of the device, the driver allocates 32 MSI vectors, which is usually more than what is needed for AIC100 devices, which is wasting resources. Allocate only the needed number of MSI vectors per device. Signed-off-by: Youssef Samir Reviewed-by: Troy Hanson Reviewed-by: Jeffrey Hugo Signed-off-by: Jeffrey Hugo Reviewed-by: Lizhi Hou Link: https://patchwork.freedesktop.org/patch/msgid/20250117170943.2643280-4-quic_jhugo@quicinc.com --- drivers/accel/qaic/qaic_drv.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/accel/qaic/qaic_drv.c b/drivers/accel/qaic/qaic_drv.c index 81819b9ef8d4..6e9bed17b3f1 100644 --- a/drivers/accel/qaic/qaic_drv.c +++ b/drivers/accel/qaic/qaic_drv.c @@ -465,12 +465,13 @@ static int init_pci(struct qaic_device *qdev, struct pci_dev *pdev) static int init_msi(struct qaic_device *qdev, struct pci_dev *pdev) { + int irq_count = qdev->num_dbc + 1; int mhi_irq; int ret; int i; /* Managed release since we use pcim_enable_device */ - ret = pci_alloc_irq_vectors(pdev, 32, 32, PCI_IRQ_MSI); + ret = pci_alloc_irq_vectors(pdev, irq_count, irq_count, PCI_IRQ_MSI); if (ret == -ENOSPC) { ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI); if (ret < 0) @@ -485,7 +486,8 @@ static int init_msi(struct qaic_device *qdev, struct pci_dev *pdev) * interrupted, it shouldn't race with itself. */ qdev->single_msi = true; - pci_info(pdev, "Allocating 32 MSIs failed, operating in 1 MSI mode. Performance may be impacted.\n"); + pci_info(pdev, "Allocating %d MSIs failed, operating in 1 MSI mode. Performance may be impacted.\n", + irq_count); } else if (ret < 0) { return ret; } -- 2.51.0 From 0600195ec70a57c3937275e6672927ee6b3c6306 Mon Sep 17 00:00:00 2001 From: Youssef Samir Date: Fri, 17 Jan 2025 10:09:40 -0700 Subject: [PATCH 06/16] accel/qaic: Add support for MSI-X AIC200 device will support MSI-X while AIC100 devices will keep using MSI. pci_alloc_irq_vectors() will try to allocate MSI-X vectors if it is supported by the target device, otherwise, it will fallback to MSI. Add support for MSI-X vectors allocation for AIC200 devices. Signed-off-by: Youssef Samir Reviewed-by: Jeffrey Hugo Signed-off-by: Jeffrey Hugo Reviewed-by: Lizhi Hou Link: https://patchwork.freedesktop.org/patch/msgid/20250117170943.2643280-5-quic_jhugo@quicinc.com --- drivers/accel/qaic/qaic_drv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/accel/qaic/qaic_drv.c b/drivers/accel/qaic/qaic_drv.c index 6e9bed17b3f1..ce0428f6cb82 100644 --- a/drivers/accel/qaic/qaic_drv.c +++ b/drivers/accel/qaic/qaic_drv.c @@ -471,9 +471,9 @@ static int init_msi(struct qaic_device *qdev, struct pci_dev *pdev) int i; /* Managed release since we use pcim_enable_device */ - ret = pci_alloc_irq_vectors(pdev, irq_count, irq_count, PCI_IRQ_MSI); + ret = pci_alloc_irq_vectors(pdev, irq_count, irq_count, PCI_IRQ_MSI | PCI_IRQ_MSIX); if (ret == -ENOSPC) { - ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI); + ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI | PCI_IRQ_MSIX); if (ret < 0) return ret; -- 2.51.0 From 8685520474bfc0fe4be83c3cbfe3fb3e1ca1514a Mon Sep 17 00:00:00 2001 From: Youssef Samir Date: Fri, 17 Jan 2025 10:09:41 -0700 Subject: [PATCH 07/16] accel/qaic: Mask out SR-IOV PCI resources During the initialization of the qaic device, pci_select_bars() is used to fetch a bitmask of the BARs exposed by the device. On devices that have Virtual Functions capabilities, the bitmask includes SR-IOV BARs. Use a mask to filter out SR-IOV BARs if they exist. Signed-off-by: Youssef Samir Reviewed-by: Jeffrey Hugo Signed-off-by: Jeffrey Hugo Reviewed-by: Lizhi Hou Link: https://patchwork.freedesktop.org/patch/msgid/20250117170943.2643280-6-quic_jhugo@quicinc.com --- drivers/accel/qaic/qaic_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/accel/qaic/qaic_drv.c b/drivers/accel/qaic/qaic_drv.c index ce0428f6cb82..00fa07aebacd 100644 --- a/drivers/accel/qaic/qaic_drv.c +++ b/drivers/accel/qaic/qaic_drv.c @@ -431,7 +431,7 @@ static int init_pci(struct qaic_device *qdev, struct pci_dev *pdev) int bars; int ret; - bars = pci_select_bars(pdev, IORESOURCE_MEM); + bars = pci_select_bars(pdev, IORESOURCE_MEM) & 0x3f; /* make sure the device has the expected BARs */ if (bars != (BIT(0) | BIT(2) | BIT(4))) { -- 2.51.0 From 5bbe412bc7937b5cabfe38aa186a2c6890f70df0 Mon Sep 17 00:00:00 2001 From: Jeffrey Hugo Date: Fri, 17 Jan 2025 10:09:42 -0700 Subject: [PATCH 08/16] accel/qaic: Add config structs for supported cards As the number of cards supported by the driver grows, their configurations will differ. The driver needs to become more dynamic to support these configurations. Currently, each card may differ in the exposed BARs, the regions they map to, and the family. Create config structs for each card, and let the driver configure the qaic_device struct based on the configurations passed to the driver. Co-developed-by: Youssef Samir Signed-off-by: Youssef Samir Signed-off-by: Jeffrey Hugo Reviewed-by: Lizhi Hou Link: https://patchwork.freedesktop.org/patch/msgid/20250117170943.2643280-7-quic_jhugo@quicinc.com --- drivers/accel/qaic/qaic.h | 13 +++-- drivers/accel/qaic/qaic_drv.c | 76 ++++++++++++++++++++---------- drivers/accel/qaic/qaic_timesync.c | 2 +- 3 files changed, 61 insertions(+), 30 deletions(-) diff --git a/drivers/accel/qaic/qaic.h b/drivers/accel/qaic/qaic.h index 02561b6cecc6..cf97fd9a7e70 100644 --- a/drivers/accel/qaic/qaic.h +++ b/drivers/accel/qaic/qaic.h @@ -32,6 +32,11 @@ #define to_accel_kdev(qddev) (to_drm(qddev)->accel->kdev) /* Return Linux device of accel node */ #define to_qaic_device(dev) (to_qaic_drm_device((dev))->qdev) +enum aic_families { + FAMILY_AIC100, + FAMILY_MAX, +}; + enum __packed dev_states { /* Device is offline or will be very soon */ QAIC_OFFLINE, @@ -113,10 +118,10 @@ struct qaic_device { struct pci_dev *pdev; /* Req. ID of request that will be queued next in MHI control device */ u32 next_seq_num; - /* Base address of bar 0 */ - void __iomem *bar_0; - /* Base address of bar 2 */ - void __iomem *bar_2; + /* Base address of the MHI bar */ + void __iomem *bar_mhi; + /* Base address of the DBCs bar */ + void __iomem *bar_dbc; /* Controller structure for MHI devices */ struct mhi_controller *mhi_cntrl; /* MHI control channel device */ diff --git a/drivers/accel/qaic/qaic_drv.c b/drivers/accel/qaic/qaic_drv.c index 00fa07aebacd..4e63e475b389 100644 --- a/drivers/accel/qaic/qaic_drv.c +++ b/drivers/accel/qaic/qaic_drv.c @@ -34,13 +34,38 @@ MODULE_IMPORT_NS("DMA_BUF"); -#define PCI_DEV_AIC080 0xa080 -#define PCI_DEV_AIC100 0xa100 +#define PCI_DEVICE_ID_QCOM_AIC080 0xa080 +#define PCI_DEVICE_ID_QCOM_AIC100 0xa100 #define QAIC_NAME "qaic" #define QAIC_DESC "Qualcomm Cloud AI Accelerators" #define CNTL_MAJOR 5 #define CNTL_MINOR 0 +struct qaic_device_config { + /* Indicates the AIC family the device belongs to */ + int family; + /* A bitmask representing the available BARs */ + int bar_mask; + /* An index value used to identify the MHI controller BAR */ + unsigned int mhi_bar_idx; + /* An index value used to identify the DBCs BAR */ + unsigned int dbc_bar_idx; +}; + +static const struct qaic_device_config aic080_config = { + .family = FAMILY_AIC100, + .bar_mask = BIT(0) | BIT(2) | BIT(4), + .mhi_bar_idx = 0, + .dbc_bar_idx = 2, +}; + +static const struct qaic_device_config aic100_config = { + .family = FAMILY_AIC100, + .bar_mask = BIT(0) | BIT(2) | BIT(4), + .mhi_bar_idx = 0, + .dbc_bar_idx = 2, +}; + bool datapath_polling; module_param(datapath_polling, bool, 0400); MODULE_PARM_DESC(datapath_polling, "Operate the datapath in polling mode"); @@ -352,7 +377,8 @@ void qaic_dev_reset_clean_local_state(struct qaic_device *qdev) release_dbc(qdev, i); } -static struct qaic_device *create_qdev(struct pci_dev *pdev, const struct pci_device_id *id) +static struct qaic_device *create_qdev(struct pci_dev *pdev, + const struct qaic_device_config *config) { struct device *dev = &pdev->dev; struct qaic_drm_device *qddev; @@ -365,12 +391,10 @@ static struct qaic_device *create_qdev(struct pci_dev *pdev, const struct pci_de return NULL; qdev->dev_state = QAIC_OFFLINE; - if (id->device == PCI_DEV_AIC080 || id->device == PCI_DEV_AIC100) { - qdev->num_dbc = 16; - qdev->dbc = devm_kcalloc(dev, qdev->num_dbc, sizeof(*qdev->dbc), GFP_KERNEL); - if (!qdev->dbc) - return NULL; - } + 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)) @@ -426,7 +450,8 @@ static struct qaic_device *create_qdev(struct pci_dev *pdev, const struct pci_de return qdev; } -static int init_pci(struct qaic_device *qdev, struct pci_dev *pdev) +static int init_pci(struct qaic_device *qdev, struct pci_dev *pdev, + const struct qaic_device_config *config) { int bars; int ret; @@ -434,9 +459,9 @@ static int init_pci(struct qaic_device *qdev, struct pci_dev *pdev) bars = pci_select_bars(pdev, IORESOURCE_MEM) & 0x3f; /* make sure the device has the expected BARs */ - if (bars != (BIT(0) | BIT(2) | BIT(4))) { - pci_dbg(pdev, "%s: expected BARs 0, 2, and 4 not found in device. Found 0x%x\n", - __func__, bars); + if (bars != config->bar_mask) { + pci_dbg(pdev, "%s: expected BARs %#x not found in device. Found %#x\n", + __func__, config->bar_mask, bars); return -EINVAL; } @@ -449,13 +474,13 @@ static int init_pci(struct qaic_device *qdev, struct pci_dev *pdev) return ret; dma_set_max_seg_size(&pdev->dev, UINT_MAX); - qdev->bar_0 = devm_ioremap_resource(&pdev->dev, &pdev->resource[0]); - if (IS_ERR(qdev->bar_0)) - return PTR_ERR(qdev->bar_0); + qdev->bar_mhi = devm_ioremap_resource(&pdev->dev, &pdev->resource[config->mhi_bar_idx]); + if (IS_ERR(qdev->bar_mhi)) + return PTR_ERR(qdev->bar_mhi); - qdev->bar_2 = devm_ioremap_resource(&pdev->dev, &pdev->resource[2]); - if (IS_ERR(qdev->bar_2)) - return PTR_ERR(qdev->bar_2); + qdev->bar_dbc = devm_ioremap_resource(&pdev->dev, &pdev->resource[config->dbc_bar_idx]); + if (IS_ERR(qdev->bar_dbc)) + return PTR_ERR(qdev->bar_dbc); /* Managed release since we use pcim_enable_device above */ pci_set_master(pdev); @@ -517,21 +542,22 @@ static int init_msi(struct qaic_device *qdev, struct pci_dev *pdev) static int qaic_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { + struct qaic_device_config *config = (struct qaic_device_config *)id->driver_data; struct qaic_device *qdev; int mhi_irq; int ret; int i; - qdev = create_qdev(pdev, id); + qdev = create_qdev(pdev, config); if (!qdev) return -ENOMEM; - ret = init_pci(qdev, pdev); + ret = init_pci(qdev, pdev, config); if (ret) return ret; for (i = 0; i < qdev->num_dbc; ++i) - qdev->dbc[i].dbc_base = qdev->bar_2 + QAIC_DBC_OFF(i); + qdev->dbc[i].dbc_base = qdev->bar_dbc + QAIC_DBC_OFF(i); mhi_irq = init_msi(qdev, pdev); if (mhi_irq < 0) @@ -541,7 +567,7 @@ static int qaic_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (ret) return ret; - qdev->mhi_cntrl = qaic_mhi_register_controller(pdev, qdev->bar_0, mhi_irq, + qdev->mhi_cntrl = qaic_mhi_register_controller(pdev, qdev->bar_mhi, mhi_irq, qdev->single_msi); if (IS_ERR(qdev->mhi_cntrl)) { ret = PTR_ERR(qdev->mhi_cntrl); @@ -609,8 +635,8 @@ static struct mhi_driver qaic_mhi_driver = { }; static const struct pci_device_id qaic_ids[] = { - { PCI_DEVICE(PCI_VENDOR_ID_QCOM, PCI_DEV_AIC080), }, - { PCI_DEVICE(PCI_VENDOR_ID_QCOM, PCI_DEV_AIC100), }, + { PCI_DEVICE_DATA(QCOM, AIC080, (kernel_ulong_t)&aic080_config), }, + { PCI_DEVICE_DATA(QCOM, AIC100, (kernel_ulong_t)&aic100_config), }, { } }; MODULE_DEVICE_TABLE(pci, qaic_ids); diff --git a/drivers/accel/qaic/qaic_timesync.c b/drivers/accel/qaic/qaic_timesync.c index 301f4462d51b..2473c66309d4 100644 --- a/drivers/accel/qaic/qaic_timesync.c +++ b/drivers/accel/qaic/qaic_timesync.c @@ -201,7 +201,7 @@ static int qaic_timesync_probe(struct mhi_device *mhi_dev, const struct mhi_devi goto free_sync_msg; /* Qtimer register pointer */ - mqtsdev->qtimer_addr = qdev->bar_0 + QTIMER_REG_OFFSET; + mqtsdev->qtimer_addr = qdev->bar_mhi + QTIMER_REG_OFFSET; timer_setup(timer, qaic_timesync_timer, 0); timer->expires = jiffies + msecs_to_jiffies(timesync_delay_ms); add_timer(timer); -- 2.51.0 From 7271a88629857dc285d4291055b8e7811f9d3603 Mon Sep 17 00:00:00 2001 From: Jeffrey Hugo Date: Fri, 17 Jan 2025 10:09:43 -0700 Subject: [PATCH 09/16] accel/qaic: Add AIC200 support Add basic support for the new AIC200 product. The PCIe Device ID is 0xa110. With this, we can turn on the lights for AIC200 by leveraging much of the existing driver. Co-developed-by: Youssef Samir Signed-off-by: Youssef Samir Signed-off-by: Jeffrey Hugo Reviewed-by: Lizhi Hou Acked-by: Manivannan Sadhasivam Link: https://patchwork.freedesktop.org/patch/msgid/20250117170943.2643280-8-quic_jhugo@quicinc.com --- drivers/accel/qaic/mhi_controller.c | 360 ++++++++++++++++++++++++++-- drivers/accel/qaic/mhi_controller.h | 2 +- drivers/accel/qaic/qaic.h | 1 + drivers/accel/qaic/qaic_drv.c | 11 +- drivers/accel/qaic/sahara.c | 39 ++- 5 files changed, 395 insertions(+), 18 deletions(-) diff --git a/drivers/accel/qaic/mhi_controller.c b/drivers/accel/qaic/mhi_controller.c index 8ab82e78dd94..13a14c6c6168 100644 --- a/drivers/accel/qaic/mhi_controller.c +++ b/drivers/accel/qaic/mhi_controller.c @@ -20,6 +20,11 @@ static unsigned int mhi_timeout_ms = 2000; /* 2 sec default */ module_param(mhi_timeout_ms, uint, 0600); MODULE_PARM_DESC(mhi_timeout_ms, "MHI controller timeout value"); +static const char *fw_image_paths[FAMILY_MAX] = { + [FAMILY_AIC100] = "qcom/aic100/sbl.bin", + [FAMILY_AIC200] = "qcom/aic200/sbl.bin", +}; + static const struct mhi_channel_config aic100_channels[] = { { .name = "QAIC_LOOPBACK", @@ -439,6 +444,297 @@ static const struct mhi_channel_config aic100_channels[] = { }, }; +static const struct mhi_channel_config aic200_channels[] = { + { + .name = "QAIC_LOOPBACK", + .num = 0, + .num_elements = 32, + .local_elements = 0, + .event_ring = 0, + .dir = DMA_TO_DEVICE, + .ee_mask = MHI_CH_EE_AMSS, + .pollcfg = 0, + .doorbell = MHI_DB_BRST_DISABLE, + .lpm_notify = false, + .offload_channel = false, + .doorbell_mode_switch = false, + .auto_queue = false, + .wake_capable = false, + }, + { + .name = "QAIC_LOOPBACK", + .num = 1, + .num_elements = 32, + .local_elements = 0, + .event_ring = 0, + .dir = DMA_FROM_DEVICE, + .ee_mask = MHI_CH_EE_AMSS, + .pollcfg = 0, + .doorbell = MHI_DB_BRST_DISABLE, + .lpm_notify = false, + .offload_channel = false, + .doorbell_mode_switch = false, + .auto_queue = false, + .wake_capable = false, + }, + { + .name = "QAIC_SAHARA", + .num = 2, + .num_elements = 32, + .local_elements = 0, + .event_ring = 0, + .dir = DMA_TO_DEVICE, + .ee_mask = MHI_CH_EE_SBL, + .pollcfg = 0, + .doorbell = MHI_DB_BRST_DISABLE, + .lpm_notify = false, + .offload_channel = false, + .doorbell_mode_switch = false, + .auto_queue = false, + .wake_capable = false, + }, + { + .name = "QAIC_SAHARA", + .num = 3, + .num_elements = 32, + .local_elements = 0, + .event_ring = 0, + .dir = DMA_FROM_DEVICE, + .ee_mask = MHI_CH_EE_SBL, + .pollcfg = 0, + .doorbell = MHI_DB_BRST_DISABLE, + .lpm_notify = false, + .offload_channel = false, + .doorbell_mode_switch = false, + .auto_queue = false, + .wake_capable = false, + }, + { + .name = "QAIC_SSR", + .num = 6, + .num_elements = 32, + .local_elements = 0, + .event_ring = 0, + .dir = DMA_TO_DEVICE, + .ee_mask = MHI_CH_EE_AMSS, + .pollcfg = 0, + .doorbell = MHI_DB_BRST_DISABLE, + .lpm_notify = false, + .offload_channel = false, + .doorbell_mode_switch = false, + .auto_queue = false, + .wake_capable = false, + }, + { + .name = "QAIC_SSR", + .num = 7, + .num_elements = 32, + .local_elements = 0, + .event_ring = 0, + .dir = DMA_FROM_DEVICE, + .ee_mask = MHI_CH_EE_AMSS, + .pollcfg = 0, + .doorbell = MHI_DB_BRST_DISABLE, + .lpm_notify = false, + .offload_channel = false, + .doorbell_mode_switch = false, + .auto_queue = false, + .wake_capable = false, + }, + { + .name = "QAIC_CONTROL", + .num = 10, + .num_elements = 128, + .local_elements = 0, + .event_ring = 0, + .dir = DMA_TO_DEVICE, + .ee_mask = MHI_CH_EE_AMSS, + .pollcfg = 0, + .doorbell = MHI_DB_BRST_DISABLE, + .lpm_notify = false, + .offload_channel = false, + .doorbell_mode_switch = false, + .auto_queue = false, + .wake_capable = false, + }, + { + .name = "QAIC_CONTROL", + .num = 11, + .num_elements = 128, + .local_elements = 0, + .event_ring = 0, + .dir = DMA_FROM_DEVICE, + .ee_mask = MHI_CH_EE_AMSS, + .pollcfg = 0, + .doorbell = MHI_DB_BRST_DISABLE, + .lpm_notify = false, + .offload_channel = false, + .doorbell_mode_switch = false, + .auto_queue = false, + .wake_capable = false, + }, + { + .name = "QAIC_LOGGING", + .num = 12, + .num_elements = 32, + .local_elements = 0, + .event_ring = 0, + .dir = DMA_TO_DEVICE, + .ee_mask = MHI_CH_EE_SBL, + .pollcfg = 0, + .doorbell = MHI_DB_BRST_DISABLE, + .lpm_notify = false, + .offload_channel = false, + .doorbell_mode_switch = false, + .auto_queue = false, + .wake_capable = false, + }, + { + .name = "QAIC_LOGGING", + .num = 13, + .num_elements = 32, + .local_elements = 0, + .event_ring = 0, + .dir = DMA_FROM_DEVICE, + .ee_mask = MHI_CH_EE_SBL, + .pollcfg = 0, + .doorbell = MHI_DB_BRST_DISABLE, + .lpm_notify = false, + .offload_channel = false, + .doorbell_mode_switch = false, + .auto_queue = false, + .wake_capable = false, + }, + { + .name = "QAIC_STATUS", + .num = 14, + .num_elements = 32, + .local_elements = 0, + .event_ring = 0, + .dir = DMA_TO_DEVICE, + .ee_mask = MHI_CH_EE_AMSS, + .pollcfg = 0, + .doorbell = MHI_DB_BRST_DISABLE, + .lpm_notify = false, + .offload_channel = false, + .doorbell_mode_switch = false, + .auto_queue = false, + .wake_capable = false, + }, + { + .name = "QAIC_STATUS", + .num = 15, + .num_elements = 32, + .local_elements = 0, + .event_ring = 0, + .dir = DMA_FROM_DEVICE, + .ee_mask = MHI_CH_EE_AMSS, + .pollcfg = 0, + .doorbell = MHI_DB_BRST_DISABLE, + .lpm_notify = false, + .offload_channel = false, + .doorbell_mode_switch = false, + .auto_queue = false, + .wake_capable = false, + }, + { + .name = "QAIC_TELEMETRY", + .num = 16, + .num_elements = 32, + .local_elements = 0, + .event_ring = 0, + .dir = DMA_TO_DEVICE, + .ee_mask = MHI_CH_EE_AMSS, + .pollcfg = 0, + .doorbell = MHI_DB_BRST_DISABLE, + .lpm_notify = false, + .offload_channel = false, + .doorbell_mode_switch = false, + .auto_queue = false, + .wake_capable = false, + }, + { + .name = "QAIC_TELEMETRY", + .num = 17, + .num_elements = 32, + .local_elements = 0, + .event_ring = 0, + .dir = DMA_FROM_DEVICE, + .ee_mask = MHI_CH_EE_AMSS, + .pollcfg = 0, + .doorbell = MHI_DB_BRST_DISABLE, + .lpm_notify = false, + .offload_channel = false, + .doorbell_mode_switch = false, + .auto_queue = false, + .wake_capable = false, + }, + { + .name = "QAIC_TIMESYNC_PERIODIC", + .num = 22, + .num_elements = 32, + .local_elements = 0, + .event_ring = 0, + .dir = DMA_TO_DEVICE, + .ee_mask = MHI_CH_EE_AMSS, + .pollcfg = 0, + .doorbell = MHI_DB_BRST_DISABLE, + .lpm_notify = false, + .offload_channel = false, + .doorbell_mode_switch = false, + .auto_queue = false, + .wake_capable = false, + }, + { + .name = "QAIC_TIMESYNC_PERIODIC", + .num = 23, + .num_elements = 32, + .local_elements = 0, + .event_ring = 0, + .dir = DMA_FROM_DEVICE, + .ee_mask = MHI_CH_EE_AMSS, + .pollcfg = 0, + .doorbell = MHI_DB_BRST_DISABLE, + .lpm_notify = false, + .offload_channel = false, + .doorbell_mode_switch = false, + .auto_queue = false, + .wake_capable = false, + }, + { + .name = "IPCR", + .num = 24, + .num_elements = 32, + .local_elements = 0, + .event_ring = 0, + .dir = DMA_TO_DEVICE, + .ee_mask = MHI_CH_EE_AMSS, + .pollcfg = 0, + .doorbell = MHI_DB_BRST_DISABLE, + .lpm_notify = false, + .offload_channel = false, + .doorbell_mode_switch = false, + .auto_queue = false, + .wake_capable = false, + }, + { + .name = "IPCR", + .num = 25, + .num_elements = 32, + .local_elements = 0, + .event_ring = 0, + .dir = DMA_FROM_DEVICE, + .ee_mask = MHI_CH_EE_AMSS, + .pollcfg = 0, + .doorbell = MHI_DB_BRST_DISABLE, + .lpm_notify = false, + .offload_channel = false, + .doorbell_mode_switch = false, + .auto_queue = true, + .wake_capable = false, + }, +}; + static struct mhi_event_config aic100_events[] = { { .num_elements = 32, @@ -454,16 +750,44 @@ static struct mhi_event_config aic100_events[] = { }, }; -static struct mhi_controller_config aic100_config = { - .max_channels = 128, - .timeout_ms = 0, /* controlled by mhi_timeout */ - .buf_len = 0, - .num_channels = ARRAY_SIZE(aic100_channels), - .ch_cfg = aic100_channels, - .num_events = ARRAY_SIZE(aic100_events), - .event_cfg = aic100_events, - .use_bounce_buf = false, - .m2_no_db = false, +static struct mhi_event_config aic200_events[] = { + { + .num_elements = 32, + .irq_moderation_ms = 0, + .irq = 0, + .channel = U32_MAX, + .priority = 1, + .mode = MHI_DB_BRST_DISABLE, + .data_type = MHI_ER_CTRL, + .hardware_event = false, + .client_managed = false, + .offload_channel = false, + }, +}; + +static struct mhi_controller_config mhi_cntrl_configs[] = { + [FAMILY_AIC100] = { + .max_channels = 128, + .timeout_ms = 0, /* controlled by mhi_timeout */ + .buf_len = 0, + .num_channels = ARRAY_SIZE(aic100_channels), + .ch_cfg = aic100_channels, + .num_events = ARRAY_SIZE(aic100_events), + .event_cfg = aic100_events, + .use_bounce_buf = false, + .m2_no_db = false, + }, + [FAMILY_AIC200] = { + .max_channels = 128, + .timeout_ms = 0, /* controlled by mhi_timeout */ + .buf_len = 0, + .num_channels = ARRAY_SIZE(aic200_channels), + .ch_cfg = aic200_channels, + .num_events = ARRAY_SIZE(aic200_events), + .event_cfg = aic200_events, + .use_bounce_buf = false, + .m2_no_db = false, + }, }; static int mhi_read_reg(struct mhi_controller *mhi_cntrl, void __iomem *addr, u32 *out) @@ -545,8 +869,9 @@ static int mhi_reset_and_async_power_up(struct mhi_controller *mhi_cntrl) } struct mhi_controller *qaic_mhi_register_controller(struct pci_dev *pci_dev, void __iomem *mhi_bar, - int mhi_irq, bool shared_msi) + int mhi_irq, bool shared_msi, int family) { + struct mhi_controller_config mhi_config = mhi_cntrl_configs[family]; struct mhi_controller *mhi_cntrl; int ret; @@ -581,11 +906,18 @@ struct mhi_controller *qaic_mhi_register_controller(struct pci_dev *pci_dev, voi if (shared_msi) /* MSI shared with data path, no IRQF_NO_SUSPEND */ mhi_cntrl->irq_flags = IRQF_SHARED; - mhi_cntrl->fw_image = "qcom/aic100/sbl.bin"; + mhi_cntrl->fw_image = fw_image_paths[family]; + + if (family == FAMILY_AIC200) { + mhi_cntrl->name = "AIC200"; + mhi_cntrl->seg_len = SZ_512K; + } else { + mhi_cntrl->name = "AIC100"; + } /* use latest configured timeout */ - aic100_config.timeout_ms = mhi_timeout_ms; - ret = mhi_register_controller(mhi_cntrl, &aic100_config); + mhi_config.timeout_ms = mhi_timeout_ms; + ret = mhi_register_controller(mhi_cntrl, &mhi_config); if (ret) { pci_err(pci_dev, "mhi_register_controller failed %d\n", ret); return ERR_PTR(ret); diff --git a/drivers/accel/qaic/mhi_controller.h b/drivers/accel/qaic/mhi_controller.h index 500e7f4af2af..8939f6ae185e 100644 --- a/drivers/accel/qaic/mhi_controller.h +++ b/drivers/accel/qaic/mhi_controller.h @@ -8,7 +8,7 @@ #define MHICONTROLLERQAIC_H_ struct mhi_controller *qaic_mhi_register_controller(struct pci_dev *pci_dev, void __iomem *mhi_bar, - int mhi_irq, bool shared_msi); + int mhi_irq, bool shared_msi, int family); void qaic_mhi_free_controller(struct mhi_controller *mhi_cntrl, bool link_up); void qaic_mhi_start_reset(struct mhi_controller *mhi_cntrl); void qaic_mhi_reset_done(struct mhi_controller *mhi_cntrl); diff --git a/drivers/accel/qaic/qaic.h b/drivers/accel/qaic/qaic.h index cf97fd9a7e70..0dbb8e32e4b9 100644 --- a/drivers/accel/qaic/qaic.h +++ b/drivers/accel/qaic/qaic.h @@ -34,6 +34,7 @@ enum aic_families { FAMILY_AIC100, + FAMILY_AIC200, FAMILY_MAX, }; diff --git a/drivers/accel/qaic/qaic_drv.c b/drivers/accel/qaic/qaic_drv.c index 4e63e475b389..3b415e2c9431 100644 --- a/drivers/accel/qaic/qaic_drv.c +++ b/drivers/accel/qaic/qaic_drv.c @@ -36,6 +36,7 @@ MODULE_IMPORT_NS("DMA_BUF"); #define PCI_DEVICE_ID_QCOM_AIC080 0xa080 #define PCI_DEVICE_ID_QCOM_AIC100 0xa100 +#define PCI_DEVICE_ID_QCOM_AIC200 0xa110 #define QAIC_NAME "qaic" #define QAIC_DESC "Qualcomm Cloud AI Accelerators" #define CNTL_MAJOR 5 @@ -66,6 +67,13 @@ static const struct qaic_device_config aic100_config = { .dbc_bar_idx = 2, }; +static const struct qaic_device_config aic200_config = { + .family = FAMILY_AIC200, + .bar_mask = BIT(0) | BIT(1) | BIT(2) | BIT(4), + .mhi_bar_idx = 1, + .dbc_bar_idx = 2, +}; + bool datapath_polling; module_param(datapath_polling, bool, 0400); MODULE_PARM_DESC(datapath_polling, "Operate the datapath in polling mode"); @@ -568,7 +576,7 @@ static int qaic_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) return ret; qdev->mhi_cntrl = qaic_mhi_register_controller(pdev, qdev->bar_mhi, mhi_irq, - qdev->single_msi); + qdev->single_msi, config->family); if (IS_ERR(qdev->mhi_cntrl)) { ret = PTR_ERR(qdev->mhi_cntrl); qaic_destroy_drm_device(qdev, QAIC_NO_PARTITION); @@ -637,6 +645,7 @@ static struct mhi_driver qaic_mhi_driver = { static const struct pci_device_id qaic_ids[] = { { PCI_DEVICE_DATA(QCOM, AIC080, (kernel_ulong_t)&aic080_config), }, { PCI_DEVICE_DATA(QCOM, AIC100, (kernel_ulong_t)&aic100_config), }, + { PCI_DEVICE_DATA(QCOM, AIC200, (kernel_ulong_t)&aic200_config), }, { } }; MODULE_DEVICE_TABLE(pci, qaic_ids); diff --git a/drivers/accel/qaic/sahara.c b/drivers/accel/qaic/sahara.c index 09c8b055aa81..3ebcc1f7ff58 100644 --- a/drivers/accel/qaic/sahara.c +++ b/drivers/accel/qaic/sahara.c @@ -188,6 +188,34 @@ static const char * const aic100_image_table[] = { [10] = "qcom/aic100/fw10.bin", }; +static const char * const aic200_image_table[] = { + [5] = "qcom/aic200/uefi.elf", + [12] = "qcom/aic200/aic200-nsp.bin", + [23] = "qcom/aic200/aop.mbn", + [32] = "qcom/aic200/tz.mbn", + [33] = "qcom/aic200/hypvm.mbn", + [39] = "qcom/aic200/aic200_abl.elf", + [40] = "qcom/aic200/apdp.mbn", + [41] = "qcom/aic200/devcfg.mbn", + [42] = "qcom/aic200/sec.elf", + [43] = "qcom/aic200/aic200-hlos.elf", + [49] = "qcom/aic200/shrm.elf", + [50] = "qcom/aic200/cpucp.elf", + [51] = "qcom/aic200/aop_devcfg.mbn", + [57] = "qcom/aic200/cpucp_dtbs.elf", + [62] = "qcom/aic200/uefi_dtbs.elf", + [63] = "qcom/aic200/xbl_ac_config.mbn", + [64] = "qcom/aic200/tz_ac_config.mbn", + [65] = "qcom/aic200/hyp_ac_config.mbn", + [66] = "qcom/aic200/pdp.elf", + [67] = "qcom/aic200/pdp_cdb.elf", + [68] = "qcom/aic200/sdi.mbn", + [69] = "qcom/aic200/dcd.mbn", + [73] = "qcom/aic200/gearvm.mbn", + [74] = "qcom/aic200/sti.bin", + [75] = "qcom/aic200/pvs.bin", +}; + static int sahara_find_image(struct sahara_context *context, u32 image_id) { int ret; @@ -748,8 +776,15 @@ static int sahara_mhi_probe(struct mhi_device *mhi_dev, const struct mhi_device_ context->mhi_dev = mhi_dev; INIT_WORK(&context->fw_work, sahara_processing); INIT_WORK(&context->dump_work, sahara_dump_processing); - context->image_table = aic100_image_table; - context->table_size = ARRAY_SIZE(aic100_image_table); + + if (!strcmp(mhi_dev->mhi_cntrl->name, "AIC200")) { + context->image_table = aic200_image_table; + context->table_size = ARRAY_SIZE(aic200_image_table); + } else { + context->image_table = aic100_image_table; + context->table_size = ARRAY_SIZE(aic100_image_table); + } + context->active_image_id = SAHARA_IMAGE_ID_NONE; dev_set_drvdata(&mhi_dev->dev, context); -- 2.51.0 From 34776963452040f199bf9985ad8a2261a82d8b99 Mon Sep 17 00:00:00 2001 From: Jacek Lawrynowicz Date: Wed, 29 Jan 2025 13:56:31 +0100 Subject: [PATCH 10/16] accel/ivpu: Add support for hardware fault injection Introduces the capability to simulate hardware faults for testing purposes. The new `fail_hw` fault can be injected in `ivpu_hw_reg_poll_fld()`, which is used in various parts of the driver to wait for the hardware to reach a specific state. This allows to test failures during NPU boot and shutdown, IPC message handling and more. Fault injection can be enabled using debugfs or a module parameter. Reviewed-by: Maciej Falkowski Reviewed-by: Jeffrey Hugo Signed-off-by: Jacek Lawrynowicz Link: https://patchwork.freedesktop.org/patch/msgid/20250129125636.1047413-2-jacek.lawrynowicz@linux.intel.com --- drivers/accel/ivpu/ivpu_debugfs.c | 5 +++ drivers/accel/ivpu/ivpu_hw.c | 14 +++++++ drivers/accel/ivpu/ivpu_hw_ip.c | 4 +- drivers/accel/ivpu/ivpu_hw_reg_io.h | 64 +++++++++++++++++------------ 4 files changed, 58 insertions(+), 29 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_debugfs.c b/drivers/accel/ivpu/ivpu_debugfs.c index 8180b95ed69d..e79715c53f2a 100644 --- a/drivers/accel/ivpu/ivpu_debugfs.c +++ b/drivers/accel/ivpu/ivpu_debugfs.c @@ -4,6 +4,7 @@ */ #include +#include #include #include @@ -430,4 +431,8 @@ void ivpu_debugfs_init(struct ivpu_device *vdev) debugfs_root, vdev, &fw_profiling_freq_fops); debugfs_create_file("dct", 0644, debugfs_root, vdev, &ivpu_dct_fops); } + +#ifdef CONFIG_FAULT_INJECTION + fault_create_debugfs_attr("fail_hw", debugfs_root, &ivpu_hw_failure); +#endif } diff --git a/drivers/accel/ivpu/ivpu_hw.c b/drivers/accel/ivpu/ivpu_hw.c index e332f19ab51d..8099ab047bfe 100644 --- a/drivers/accel/ivpu/ivpu_hw.c +++ b/drivers/accel/ivpu/ivpu_hw.c @@ -9,6 +9,15 @@ #include "ivpu_hw_ip.h" #include +#include + +#ifdef CONFIG_FAULT_INJECTION +DECLARE_FAULT_ATTR(ivpu_hw_failure); + +static char *ivpu_fail_hw; +module_param_named_unsafe(fail_hw, ivpu_fail_hw, charp, 0444); +MODULE_PARM_DESC(fail_hw, ",,,"); +#endif static char *platform_to_str(u32 platform) { @@ -247,6 +256,11 @@ int ivpu_hw_init(struct ivpu_device *vdev) timeouts_init(vdev); atomic_set(&vdev->hw->firewall_irq_counter, 0); +#ifdef CONFIG_FAULT_INJECTION + if (ivpu_fail_hw) + setup_fault_attr(&ivpu_hw_failure, ivpu_fail_hw); +#endif + return 0; } diff --git a/drivers/accel/ivpu/ivpu_hw_ip.c b/drivers/accel/ivpu/ivpu_hw_ip.c index 029dd065614b..823f6a57dc54 100644 --- a/drivers/accel/ivpu/ivpu_hw_ip.c +++ b/drivers/accel/ivpu/ivpu_hw_ip.c @@ -968,14 +968,14 @@ void ivpu_hw_ip_wdt_disable(struct ivpu_device *vdev) static u32 ipc_rx_count_get_37xx(struct ivpu_device *vdev) { - u32 count = REGV_RD32_SILENT(VPU_37XX_HOST_SS_TIM_IPC_FIFO_STAT); + u32 count = readl(vdev->regv + VPU_37XX_HOST_SS_TIM_IPC_FIFO_STAT); return REG_GET_FLD(VPU_37XX_HOST_SS_TIM_IPC_FIFO_STAT, FILL_LEVEL, count); } static u32 ipc_rx_count_get_40xx(struct ivpu_device *vdev) { - u32 count = REGV_RD32_SILENT(VPU_40XX_HOST_SS_TIM_IPC_FIFO_STAT); + u32 count = readl(vdev->regv + VPU_40XX_HOST_SS_TIM_IPC_FIFO_STAT); return REG_GET_FLD(VPU_40XX_HOST_SS_TIM_IPC_FIFO_STAT, FILL_LEVEL, count); } diff --git a/drivers/accel/ivpu/ivpu_hw_reg_io.h b/drivers/accel/ivpu/ivpu_hw_reg_io.h index 79b3f441eac4..66259b0ead02 100644 --- a/drivers/accel/ivpu/ivpu_hw_reg_io.h +++ b/drivers/accel/ivpu/ivpu_hw_reg_io.h @@ -7,6 +7,7 @@ #define __IVPU_HW_REG_IO_H__ #include +#include #include #include @@ -16,13 +17,11 @@ #define REG_IO_ERROR 0xffffffff #define REGB_RD32(reg) ivpu_hw_reg_rd32(vdev, vdev->regb, (reg), #reg, __func__) -#define REGB_RD32_SILENT(reg) readl(vdev->regb + (reg)) #define REGB_RD64(reg) ivpu_hw_reg_rd64(vdev, vdev->regb, (reg), #reg, __func__) #define REGB_WR32(reg, val) ivpu_hw_reg_wr32(vdev, vdev->regb, (reg), (val), #reg, __func__) #define REGB_WR64(reg, val) ivpu_hw_reg_wr64(vdev, vdev->regb, (reg), (val), #reg, __func__) #define REGV_RD32(reg) ivpu_hw_reg_rd32(vdev, vdev->regv, (reg), #reg, __func__) -#define REGV_RD32_SILENT(reg) readl(vdev->regv + (reg)) #define REGV_RD64(reg) ivpu_hw_reg_rd64(vdev, vdev->regv, (reg), #reg, __func__) #define REGV_WR32(reg, val) ivpu_hw_reg_wr32(vdev, vdev->regv, (reg), (val), #reg, __func__) #define REGV_WR64(reg, val) ivpu_hw_reg_wr64(vdev, vdev->regv, (reg), (val), #reg, __func__) @@ -47,31 +46,42 @@ #define REG_TEST_FLD_NUM(REG, FLD, num, val) \ ((num) == FIELD_GET(REG##_##FLD##_MASK, val)) -#define REGB_POLL_FLD(reg, fld, val, timeout_us) \ -({ \ - u32 var; \ - int r; \ - ivpu_dbg(vdev, REG, "%s : %s (0x%08x) Polling field %s started (expected 0x%x)\n", \ - __func__, #reg, reg, #fld, val); \ - r = read_poll_timeout(REGB_RD32_SILENT, var, (FIELD_GET(reg##_##fld##_MASK, var) == (val)),\ - REG_POLL_SLEEP_US, timeout_us, false, (reg)); \ - ivpu_dbg(vdev, REG, "%s : %s (0x%08x) Polling field %s %s (reg val 0x%08x)\n", \ - __func__, #reg, reg, #fld, r ? "ETIMEDOUT" : "OK", var); \ - r; \ -}) - -#define REGV_POLL_FLD(reg, fld, val, timeout_us) \ -({ \ - u32 var; \ - int r; \ - ivpu_dbg(vdev, REG, "%s : %s (0x%08x) Polling field %s started (expected 0x%x)\n", \ - __func__, #reg, reg, #fld, val); \ - r = read_poll_timeout(REGV_RD32_SILENT, var, (FIELD_GET(reg##_##fld##_MASK, var) == (val)),\ - REG_POLL_SLEEP_US, timeout_us, false, (reg)); \ - ivpu_dbg(vdev, REG, "%s : %s (0x%08x) Polling field %s %s (reg val 0x%08x)\n", \ - __func__, #reg, reg, #fld, r ? "ETIMEDOUT" : "OK", var); \ - r; \ -}) +#define REGB_POLL_FLD(reg, fld, exp_fld_val, timeout_us) \ + ivpu_hw_reg_poll_fld(vdev, vdev->regb, reg, reg##_##fld##_MASK, \ + FIELD_PREP(reg##_##fld##_MASK, exp_fld_val), timeout_us, \ + __func__, #reg, #fld) + +#define REGV_POLL_FLD(reg, fld, exp_fld_val, timeout_us) \ + ivpu_hw_reg_poll_fld(vdev, vdev->regv, reg, reg##_##fld##_MASK, \ + FIELD_PREP(reg##_##fld##_MASK, exp_fld_val), timeout_us, \ + __func__, #reg, #fld) + +extern struct fault_attr ivpu_hw_failure; + +static inline int __must_check +ivpu_hw_reg_poll_fld(struct ivpu_device *vdev, void __iomem *base, + u32 reg_offset, u32 reg_mask, u32 exp_masked_val, u32 timeout_us, + const char *func_name, const char *reg_name, const char *fld_name) +{ + u32 reg_val; + int ret; + + ivpu_dbg(vdev, REG, "%s : %s (0x%08x) POLL %s started (exp_val 0x%x)\n", + func_name, reg_name, reg_offset, fld_name, exp_masked_val); + + ret = read_poll_timeout(readl, reg_val, (reg_val & reg_mask) == exp_masked_val, + REG_POLL_SLEEP_US, timeout_us, false, base + reg_offset); + +#ifdef CONFIG_FAULT_INJECTION + if (should_fail(&ivpu_hw_failure, 1)) + ret = -ETIMEDOUT; +#endif + + ivpu_dbg(vdev, REG, "%s : %s (0x%08x) POLL %s %s (reg_val 0x%08x)\n", + func_name, reg_name, reg_offset, fld_name, ret ? "ETIMEDOUT" : "OK", reg_val); + + return ret; +} static inline u32 ivpu_hw_reg_rd32(struct ivpu_device *vdev, void __iomem *base, u32 reg, -- 2.51.0 From b8c00323ae65e1bbee9f87a1e66592b589f53b50 Mon Sep 17 00:00:00 2001 From: Jacek Lawrynowicz Date: Wed, 29 Jan 2025 13:56:32 +0100 Subject: [PATCH 11/16] accel/ivpu: Update last_busy in IRQ handler Call pm_runtime_mark_last_busy() in top half of IRQ handler to prevent device from being runtime suspended before bottom half is executed on a workqueue. Reviewed-by: Karol Wachowski Reviewed-by: Jeffrey Hugo Signed-off-by: Jacek Lawrynowicz Link: https://patchwork.freedesktop.org/patch/msgid/20250129125636.1047413-3-jacek.lawrynowicz@linux.intel.com --- drivers/accel/ivpu/ivpu_hw.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_hw.c b/drivers/accel/ivpu/ivpu_hw.c index 8099ab047bfe..4199f0bbb435 100644 --- a/drivers/accel/ivpu/ivpu_hw.c +++ b/drivers/accel/ivpu/ivpu_hw.c @@ -10,6 +10,7 @@ #include #include +#include #ifdef CONFIG_FAULT_INJECTION DECLARE_FAULT_ATTR(ivpu_hw_failure); @@ -331,7 +332,9 @@ irqreturn_t ivpu_hw_irq_handler(int irq, void *ptr) /* Re-enable global interrupts to re-trigger MSI for pending interrupts */ ivpu_hw_btrs_global_int_enable(vdev); - if (ip_handled || btrs_handled) - return IRQ_HANDLED; - return IRQ_NONE; + if (!ip_handled && !btrs_handled) + return IRQ_NONE; + + pm_runtime_mark_last_busy(vdev->drm.dev); + return IRQ_HANDLED; } -- 2.51.0 From 2f5bbea1807a064a1e4c1b385c8cea4f37bb4b17 Mon Sep 17 00:00:00 2001 From: Karol Wachowski Date: Wed, 29 Jan 2025 13:56:33 +0100 Subject: [PATCH 12/16] accel/ivpu: Fix missing MMU events if file_priv is unbound Move the ivpu_mmu_discard_events() function to the common portion of the abort work function. This ensures it is called only once, even if there are no faulty contexts in context_xa, to guarantee that MMU events are discarded and new events are not missed. Reviewed-by: Jacek Lawrynowicz Signed-off-by: Karol Wachowski Reviewed-by: Jeffrey Hugo Signed-off-by: Jacek Lawrynowicz Link: https://patchwork.freedesktop.org/patch/msgid/20250129125636.1047413-4-jacek.lawrynowicz@linux.intel.com --- drivers/accel/ivpu/ivpu_job.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/accel/ivpu/ivpu_job.c b/drivers/accel/ivpu/ivpu_job.c index 3c162ac41a1d..c1013f511efa 100644 --- a/drivers/accel/ivpu/ivpu_job.c +++ b/drivers/accel/ivpu/ivpu_job.c @@ -375,7 +375,6 @@ void ivpu_context_abort_locked(struct ivpu_file_priv *file_priv) ivpu_jsm_context_release(vdev, file_priv->ctx.id); ivpu_mmu_disable_ssid_events(vdev, file_priv->ctx.id); - ivpu_mmu_discard_events(vdev); file_priv->aborted = true; } @@ -980,6 +979,13 @@ void ivpu_context_abort_work_fn(struct work_struct *work) } mutex_unlock(&vdev->context_list_lock); + /* + * We will not receive new MMU event interrupts until existing events are discarded + * however, we want to discard these events only after aborting the faulty context + * to avoid generating new faults from that context + */ + ivpu_mmu_discard_events(vdev); + if (vdev->fw->sched_mode != VPU_SCHEDULING_MODE_HW) return; -- 2.51.0 From 3a40d4f4613e437cf78b9b6a28202c6549227459 Mon Sep 17 00:00:00 2001 From: Karol Wachowski Date: Wed, 29 Jan 2025 13:56:34 +0100 Subject: [PATCH 13/16] accel/ivpu: Turn on HWS by default on all platforms Hardware scheduling (HWS) is supposed to be supported on all existing platform with recent FW including pre-silicon ones. Turn on HWS by default. Reviewed-by: Jacek Lawrynowicz Signed-off-by: Karol Wachowski Signed-off-by: Jacek Lawrynowicz Link: https://patchwork.freedesktop.org/patch/msgid/20250129125636.1047413-5-jacek.lawrynowicz@linux.intel.com --- drivers/accel/ivpu/ivpu_fw.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_fw.c b/drivers/accel/ivpu/ivpu_fw.c index 6cf1fb826d1b..cfe8f79ec5a6 100644 --- a/drivers/accel/ivpu/ivpu_fw.c +++ b/drivers/accel/ivpu/ivpu_fw.c @@ -148,15 +148,7 @@ ivpu_fw_sched_mode_select(struct ivpu_device *vdev, const struct vpu_firmware_he if (IVPU_FW_CHECK_API_VER_LT(vdev, fw_hdr, JSM, 3, 24)) return VPU_SCHEDULING_MODE_OS; - switch (ivpu_device_id(vdev)) { - case PCI_DEVICE_ID_MTL: - case PCI_DEVICE_ID_ARL: - case PCI_DEVICE_ID_LNL: - case PCI_DEVICE_ID_PTL_P: - return VPU_SCHEDULING_MODE_HW; - default: - return VPU_SCHEDULING_MODE_OS; - } + return VPU_SCHEDULING_MODE_HW; } static int ivpu_fw_parse(struct ivpu_device *vdev) -- 2.51.0 From af80fe138bebea8db089c5062bca9833a2602667 Mon Sep 17 00:00:00 2001 From: Tomasz Rusinowicz Date: Wed, 29 Jan 2025 13:56:35 +0100 Subject: [PATCH 14/16] accel/ivpu: Enable recovery and adjust timeouts for fpga Recovery now works on fpga. JSM state dump timeout needs to be really long for the new fpga model releases. Enable punit on fpga. Reviewed-by: Jacek Lawrynowicz Signed-off-by: Tomasz Rusinowicz Reviewed-by: Jeffrey Hugo Signed-off-by: Jacek Lawrynowicz Link: https://patchwork.freedesktop.org/patch/msgid/20250129125636.1047413-6-jacek.lawrynowicz@linux.intel.com --- drivers/accel/ivpu/ivpu_hw.c | 10 +++++----- drivers/accel/ivpu/ivpu_pm.c | 5 ----- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_hw.c b/drivers/accel/ivpu/ivpu_hw.c index 4199f0bbb435..2057907c5aa6 100644 --- a/drivers/accel/ivpu/ivpu_hw.c +++ b/drivers/accel/ivpu/ivpu_hw.c @@ -58,7 +58,7 @@ static void platform_init(struct ivpu_device *vdev) static void wa_init(struct ivpu_device *vdev) { - vdev->wa.punit_disabled = ivpu_is_fpga(vdev); + vdev->wa.punit_disabled = false; vdev->wa.clear_runtime_mem = false; if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL) @@ -87,12 +87,12 @@ static void timeouts_init(struct ivpu_device *vdev) vdev->timeout.autosuspend = -1; vdev->timeout.d0i3_entry_msg = -1; } else if (ivpu_is_fpga(vdev)) { - vdev->timeout.boot = 100000; - vdev->timeout.jsm = 50000; - vdev->timeout.tdr = 2000000; + vdev->timeout.boot = 50; + vdev->timeout.jsm = 15000; + vdev->timeout.tdr = 30000; vdev->timeout.autosuspend = -1; vdev->timeout.d0i3_entry_msg = 500; - vdev->timeout.state_dump_msg = 10; + vdev->timeout.state_dump_msg = 10000; } else if (ivpu_is_simics(vdev)) { vdev->timeout.boot = 50; vdev->timeout.jsm = 500; diff --git a/drivers/accel/ivpu/ivpu_pm.c b/drivers/accel/ivpu/ivpu_pm.c index f41b3bfe40af..8f6222d15720 100644 --- a/drivers/accel/ivpu/ivpu_pm.c +++ b/drivers/accel/ivpu/ivpu_pm.c @@ -161,11 +161,6 @@ void ivpu_pm_trigger_recovery(struct ivpu_device *vdev, const char *reason) return; } - if (ivpu_is_fpga(vdev)) { - ivpu_err(vdev, "Recovery not available on FPGA\n"); - return; - } - /* Trigger recovery if it's not in progress */ if (atomic_cmpxchg(&vdev->pm->reset_pending, 0, 1) == 0) { ivpu_hw_diagnose_failure(vdev); -- 2.51.0 From d24b85df791840089c2df6a25809aca814b1206d Mon Sep 17 00:00:00 2001 From: Karol Wachowski Date: Wed, 29 Jan 2025 13:56:36 +0100 Subject: [PATCH 15/16] accel/ivpu: Move recovery work to system_unbound_wq Recovery work doesn't need to be bound to any specific CPU, so move it to unbound workqueue to improve execution time and system latency. Reviewed-by: Jacek Lawrynowicz Signed-off-by: Karol Wachowski Reviewed-by: Jeffrey Hugo Signed-off-by: Jacek Lawrynowicz Link: https://patchwork.freedesktop.org/patch/msgid/20250129125636.1047413-7-jacek.lawrynowicz@linux.intel.com --- drivers/accel/ivpu/ivpu_pm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/accel/ivpu/ivpu_pm.c b/drivers/accel/ivpu/ivpu_pm.c index 8f6222d15720..d3db944ad864 100644 --- a/drivers/accel/ivpu/ivpu_pm.c +++ b/drivers/accel/ivpu/ivpu_pm.c @@ -165,7 +165,7 @@ void ivpu_pm_trigger_recovery(struct ivpu_device *vdev, const char *reason) if (atomic_cmpxchg(&vdev->pm->reset_pending, 0, 1) == 0) { ivpu_hw_diagnose_failure(vdev); ivpu_hw_irq_disable(vdev); /* Disable IRQ early to protect from IRQ storm */ - queue_work(system_long_wq, &vdev->pm->recovery_work); + queue_work(system_unbound_wq, &vdev->pm->recovery_work); } } -- 2.51.0 From 707e860119d5510e897da89492f8a69ae627762c Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 31 Jan 2025 10:21:01 +0100 Subject: [PATCH 16/16] drm/ast: Remove 1152x864 from list of widescreen resolutions The resolution 1152x864 has a ratio of 4:3 and is already handled as such. Remove it from the list of widescreen resolutions. Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20250131092257.115596-2-tzimmermann@suse.de --- drivers/gpu/drm/ast/ast_mode.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index 9d5321c81e68..b533eb6e233e 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -1035,8 +1035,6 @@ ast_crtc_helper_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode return MODE_OK; if ((mode->hdisplay == 1600) && (mode->vdisplay == 900)) return MODE_OK; - if ((mode->hdisplay == 1152) && (mode->vdisplay == 864)) - return MODE_OK; if ((ast->chip == AST2100) || // GEN2, but not AST1100 (?) (ast->chip == AST2200) || // GEN3, but not AST2150 (?) -- 2.51.0