From 2a27bd854fbd3407572a86b52e21d95976fc811d Mon Sep 17 00:00:00 2001 From: Lan Honglin Date: Mon, 11 Dec 2023 17:19:33 +0800 Subject: [PATCH 1/4] media: i2c: imx415: fix issues for thunderboot Change-Id: I2f61cba2c5f6a4d7d019d3bc0a8d21f191be943f Signed-off-by: Lan Honglin --- drivers/media/i2c/imx415.c | 45 +++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/drivers/media/i2c/imx415.c b/drivers/media/i2c/imx415.c index 80be9a83b75d..2cf6561e2222 100644 --- a/drivers/media/i2c/imx415.c +++ b/drivers/media/i2c/imx415.c @@ -170,6 +170,7 @@ #define OF_CAMERA_PINCTRL_STATE_DEFAULT "rockchip,camera_default" #define OF_CAMERA_PINCTRL_STATE_SLEEP "rockchip,camera_sleep" +#define RKMODULE_CAMERA_FASTBOOT_ENABLE "rockchip,camera_fastboot" #define IMX415_NAME "imx415" @@ -227,7 +228,7 @@ struct imx415 { struct mutex mutex; bool streaming; bool power_on; - bool is_thunderboot; + u32 is_thunderboot; bool is_thunderboot_ng; bool is_first_streamoff; const struct imx415_mode *supported_modes; @@ -2426,10 +2427,6 @@ int __imx415_power_on(struct imx415 *imx415) { int ret; struct device *dev = &imx415->client->dev; - - if (imx415->is_thunderboot) - return 0; - if (!IS_ERR_OR_NULL(imx415->pins_default)) { ret = pinctrl_select_state(imx415->pinctrl, imx415->pins_default); @@ -2437,22 +2434,24 @@ int __imx415_power_on(struct imx415 *imx415) dev_err(dev, "could not set pins\n"); } - ret = regulator_bulk_enable(IMX415_NUM_SUPPLIES, imx415->supplies); - if (ret < 0) { - dev_err(dev, "Failed to enable regulators\n"); - goto err_pinctrl; - } - if (!IS_ERR(imx415->power_gpio)) - gpiod_direction_output(imx415->power_gpio, 1); - /* At least 500ns between power raising and XCLR */ - /* fix power on timing if insmod this ko */ - usleep_range(10 * 1000, 20 * 1000); - if (!IS_ERR(imx415->reset_gpio)) - gpiod_direction_output(imx415->reset_gpio, 0); + if (!imx415->is_thunderboot) { + ret = regulator_bulk_enable(IMX415_NUM_SUPPLIES, imx415->supplies); + if (ret < 0) { + dev_err(dev, "Failed to enable regulators\n"); + goto err_pinctrl; + } + if (!IS_ERR(imx415->power_gpio)) + gpiod_direction_output(imx415->power_gpio, 1); + /* At least 500ns between power raising and XCLR */ + /* fix power on timing if insmod this ko */ + usleep_range(10 * 1000, 20 * 1000); + if (!IS_ERR(imx415->reset_gpio)) + gpiod_direction_output(imx415->reset_gpio, 0); - /* At least 1us between XCLR and clk */ - /* fix power on timing if insmod this ko */ - usleep_range(10 * 1000, 20 * 1000); + /* At least 1us between XCLR and clk */ + /* fix power on timing if insmod this ko */ + usleep_range(10 * 1000, 20 * 1000); + } ret = clk_set_rate(imx415->xvclk, imx415->cur_mode->xvclk); if (ret < 0) dev_warn(dev, "Failed to set xvclk rate\n"); @@ -2465,7 +2464,8 @@ int __imx415_power_on(struct imx415 *imx415) } /* At least 20us between XCLR and I2C communication */ - usleep_range(20*1000, 30*1000); + if (!imx415->is_thunderboot) + usleep_range(20*1000, 30*1000); return 0; @@ -2960,7 +2960,8 @@ static int imx415_probe(struct i2c_client *client, } } - imx415->is_thunderboot = IS_ENABLED(CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP); + of_property_read_u32(node, RKMODULE_CAMERA_FASTBOOT_ENABLE, + &imx415->is_thunderboot); imx415->xvclk = devm_clk_get(dev, "xvclk"); if (IS_ERR(imx415->xvclk)) { From 47bfce412352affea9f2394b4243f5fa459f1375 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Tue, 12 Dec 2023 09:38:11 +0800 Subject: [PATCH 2/4] arm64: dts: rockchip: Covert ciu-drv to ciu-drive for matching the driver The driver is using ciu-drive instead of ciu-drv. They were converted by: sed -i "s/ciu-drv;/ciu-drive;/g" `grep ciu-drv -rl arch/arm64/boot/dts/rockchip/*` Change-Id: I7e5be98a46d7eb5d29b5b0fe0280ea8b91c60406 Signed-off-by: Shawn Lin --- arch/arm64/boot/dts/rockchip/rk1808-fpga.dts | 4 ++-- arch/arm64/boot/dts/rockchip/rk1808.dtsi | 6 +++--- arch/arm64/boot/dts/rockchip/rk3328.dtsi | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm64/boot/dts/rockchip/rk1808-fpga.dts b/arch/arm64/boot/dts/rockchip/rk1808-fpga.dts index d021918cacd1..d9aad0f21b5f 100644 --- a/arch/arm64/boot/dts/rockchip/rk1808-fpga.dts +++ b/arch/arm64/boot/dts/rockchip/rk1808-fpga.dts @@ -31,7 +31,7 @@ &emmc { max-frequency = <400000>; clocks = <&xin24m>, <&xin24m>, <&xin24m>, <&xin24m>; - clock-names = "biu", "ciu", "ciu-drv", "ciu-sample"; + clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; mmc-hs200-1_8v; no-sdio; no-sd; @@ -46,7 +46,7 @@ &sdmmc { max-frequency = <400000>; clocks = <&xin24m>, <&xin24m>, <&xin24m>, <&xin24m>; - clock-names = "biu", "ciu", "ciu-drv", "ciu-sample"; + clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; no-sdio; no-mmc; status = "okay"; diff --git a/arch/arm64/boot/dts/rockchip/rk1808.dtsi b/arch/arm64/boot/dts/rockchip/rk1808.dtsi index 4ad5f039e571..ed23ddf9381a 100644 --- a/arch/arm64/boot/dts/rockchip/rk1808.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk1808.dtsi @@ -1715,7 +1715,7 @@ reg = <0x0 0xffc60000 0x0 0x4000>; clocks = <&cru HCLK_SDIO>, <&cru SCLK_SDIO>, <&cru SCLK_SDIO_DRV>, <&cru SCLK_SDIO_SAMPLE>; - clock-names = "biu", "ciu", "ciu-drv", "ciu-sample"; + clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; max-frequency = <150000000>; fifo-depth = <0x100>; interrupts = ; @@ -1812,7 +1812,7 @@ reg = <0x0 0xffcf0000 0x0 0x4000>; clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>, <&cru SCLK_SDMMC_DRV>, <&cru SCLK_SDMMC_SAMPLE>; - clock-names = "biu", "ciu", "ciu-drv", "ciu-sample"; + clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; max-frequency = <150000000>; fifo-depth = <0x100>; interrupts = ; @@ -1826,7 +1826,7 @@ reg = <0x0 0xffd00000 0x0 0x4000>; clocks = <&cru HCLK_EMMC>, <&cru SCLK_EMMC>, <&cru SCLK_EMMC_DRV>, <&cru SCLK_EMMC_SAMPLE>; - clock-names = "biu", "ciu", "ciu-drv", "ciu-sample"; + clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; max-frequency = <150000000>; fifo-depth = <0x100>; interrupts = ; diff --git a/arch/arm64/boot/dts/rockchip/rk3328.dtsi b/arch/arm64/boot/dts/rockchip/rk3328.dtsi index 933b4744211a..7dcf177d3d10 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi @@ -1521,7 +1521,7 @@ clock-freq-min-max = <400000 150000000>; clocks = <&cru HCLK_SDMMC_EXT>, <&cru SCLK_SDMMC_EXT>, <&cru SCLK_SDMMC_EXT_DRV>, <&cru SCLK_SDMMC_EXT_SAMPLE>; - clock-names = "biu", "ciu", "ciu-drv", "ciu-sample"; + clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; fifo-depth = <0x100>; interrupts = ; status = "disabled"; From a01ba48fea6925719a7945f5519918364f290f09 Mon Sep 17 00:00:00 2001 From: Jon Lin Date: Mon, 11 Dec 2023 15:47:20 +0800 Subject: [PATCH 3/4] misc: rockchip: pcie-rkep: Change to use pci_request_irq apis. Fix error: [ 517.934944] RIP: 0010:pci_free_cap_save_buffers+0x19/0x30 ... [ 517.935040] ? page_fault_oops+0x136/0x2c0 [ 517.935048] ? search_bpf_extables+0x63/0x80 [ 517.935055] ? pci_free_cap_save_buffers+0x19/0x30 [ 517.935061] ? search_exception_tables+0x5f/0x70 [ 517.935068] ? kernelmode_fixup_or_oops+0xa2/0x120 [ 517.935074] ? __bad_area_nosemaphore+0x15d/0x1a0 [ 517.935080] ? __wake_up_common+0x7e/0x140 Change-Id: Ib0d769dc2ee7428fd289cfbda6a31d28ccb970bd Signed-off-by: Jon Lin --- drivers/misc/rockchip/pcie-rkep.c | 143 +++++++++--------------------- 1 file changed, 41 insertions(+), 102 deletions(-) diff --git a/drivers/misc/rockchip/pcie-rkep.c b/drivers/misc/rockchip/pcie-rkep.c index ee8cf9359471..06caac118e30 100644 --- a/drivers/misc/rockchip/pcie-rkep.c +++ b/drivers/misc/rockchip/pcie-rkep.c @@ -40,8 +40,7 @@ static DEFINE_MUTEX(rkep_mutex); #define BAR_0_SZ SZ_4M -#define RKEP_NUM_MSI_VECTORS 4 -#define RKEP_NUM_MSIX_VECTORS 8 +#define RKEP_NUM_IRQ_VECTORS 4 #define PCIe_CLIENT_MSI_IRQ_OBJ 0 /* rockchip ep object special irq */ @@ -101,10 +100,9 @@ static DEFINE_MUTEX(rkep_mutex); #define PCIE_RK3588_RC_DBI_BASE 0xf5000000 #define PCIE_DBI_SIZE 0x400000 -struct pcie_rkep_msix_context { +struct pcie_rkep_irq_context { struct pci_dev *dev; u16 msg_id; - u8 *name; }; struct pcie_rkep { @@ -113,11 +111,8 @@ struct pcie_rkep { void __iomem *bar2; void __iomem *bar4; int cur_mmap_res; - struct msix_entry msix_entries[RKEP_NUM_MSIX_VECTORS]; - struct pcie_rkep_msix_context msix_ctx[RKEP_NUM_MSIX_VECTORS]; - struct pcie_rkep_msix_context msi_ctx[RKEP_NUM_MSI_VECTORS]; - bool msi_enable; - bool msix_enable; + struct pcie_rkep_irq_context irq_ctx[RKEP_NUM_IRQ_VECTORS]; + int irq_valid; struct miscdevice dev; struct dma_trx_obj *dma_obj; @@ -972,104 +967,69 @@ static int pcie_rkep_obj_handler(struct pcie_rkep *pcie_rkep, struct pci_dev *pd static irqreturn_t pcie_rkep_pcie_interrupt(int irq, void *context) { - struct pcie_rkep_msix_context *ctx = context; + struct pcie_rkep_irq_context *ctx = context; struct pci_dev *pdev = ctx->dev; struct pcie_rkep *pcie_rkep = pci_get_drvdata(pdev); if (!pcie_rkep) return IRQ_HANDLED; - if (pcie_rkep->msix_enable) - dev_info(&pdev->dev, "MSI-X is triggered for 0x%x\n", ctx->msg_id); - - else /* pcie_rkep->msi_enable */ { - /* - * The msi 0 is the dedicated interrupt for obj to issue remote rc device. - */ - if (irq == pci_irq_vector(pcie_rkep->pdev, PCIe_CLIENT_MSI_IRQ_OBJ)) - pcie_rkep_obj_handler(pcie_rkep, pdev); - } + /* + * The irq 0 is the dedicated interrupt for obj to issue remote rc device. + */ + if (irq == pci_irq_vector(pcie_rkep->pdev, PCIe_CLIENT_MSI_IRQ_OBJ)) + pcie_rkep_obj_handler(pcie_rkep, pdev); return IRQ_HANDLED; } -static int __maybe_unused pcie_rkep_request_msi_irq(struct pcie_rkep *pcie_rkep) +static void pcie_rkep_release_irq(struct pcie_rkep *pcie_rkep) { - int nvec, ret = -EINVAL, i, j; + int i; + + if (pcie_rkep->irq_valid) { + for (i = 0; i < pcie_rkep->irq_valid; i++) + pci_free_irq(pcie_rkep->pdev, i, &pcie_rkep->irq_ctx[i]); + + pci_free_irq_vectors(pcie_rkep->pdev); + } + pcie_rkep->irq_valid = 0; +} + +static int pcie_rkep_request_irq(struct pcie_rkep *pcie_rkep, u32 irq_type) +{ + int nvec, ret = -EINVAL, i; /* Using msi as default */ - nvec = pci_alloc_irq_vectors(pcie_rkep->pdev, 1, RKEP_NUM_MSI_VECTORS, PCI_IRQ_MSI); + nvec = pci_alloc_irq_vectors(pcie_rkep->pdev, 1, RKEP_NUM_IRQ_VECTORS, irq_type); if (nvec < 0) return nvec; - if (nvec != RKEP_NUM_MSI_VECTORS) - dev_err(&pcie_rkep->pdev->dev, "only allocate %d msi interrupt\n", nvec); + if (nvec != RKEP_NUM_IRQ_VECTORS) + dev_err(&pcie_rkep->pdev->dev, "only allocate %d irq interrupt, irq_type=%d\n", nvec, irq_type); + pcie_rkep->irq_valid = 0; for (i = 0; i < nvec; i++) { - pcie_rkep->msi_ctx[i].dev = pcie_rkep->pdev; - pcie_rkep->msi_ctx[i].msg_id = i; - pcie_rkep->msi_ctx[i].name = - devm_kzalloc(&pcie_rkep->pdev->dev, RKEP_NUM_MSIX_VECTORS, GFP_KERNEL); - sprintf(pcie_rkep->msi_ctx[i].name, "%s-%d\n", pcie_rkep->dev.name, i); - ret = request_irq(pci_irq_vector(pcie_rkep->pdev, i), - pcie_rkep_pcie_interrupt, IRQF_SHARED, - pcie_rkep->msi_ctx[i].name, &pcie_rkep->msi_ctx[i]); + pcie_rkep->irq_ctx[i].dev = pcie_rkep->pdev; + pcie_rkep->irq_ctx[i].msg_id = i; + ret = pci_request_irq(pcie_rkep->pdev, i, + pcie_rkep_pcie_interrupt, NULL, + &pcie_rkep->irq_ctx[i], "%s-%d", pcie_rkep->dev.name, i); if (ret) break; + pcie_rkep->irq_valid++; } if (ret) { - for (j = 0; j < i; j++) - free_irq(pci_irq_vector(pcie_rkep->pdev, j), &pcie_rkep->msi_ctx[j]); - pci_disable_msi(pcie_rkep->pdev); + pcie_rkep_release_irq(pcie_rkep); dev_err(&pcie_rkep->pdev->dev, "fail to allocate msi interrupt\n"); } else { - pcie_rkep->msi_enable = true; dev_err(&pcie_rkep->pdev->dev, "success to request msi irq\n"); } return ret; } -static int __maybe_unused pcie_rkep_request_msix_irq(struct pcie_rkep *pcie_rkep) -{ - int ret, i, j; - - for (i = 0; i < RKEP_NUM_MSIX_VECTORS; i++) - pcie_rkep->msix_entries[i].entry = i; - - ret = pci_enable_msix_exact(pcie_rkep->pdev, pcie_rkep->msix_entries, - RKEP_NUM_MSIX_VECTORS); - if (ret) - return ret; - - for (i = 0; i < RKEP_NUM_MSIX_VECTORS; i++) { - pcie_rkep->msix_ctx[i].dev = pcie_rkep->pdev; - pcie_rkep->msix_ctx[i].msg_id = i; - pcie_rkep->msix_ctx[i].name = - devm_kzalloc(&pcie_rkep->pdev->dev, RKEP_NUM_MSIX_VECTORS, GFP_KERNEL); - sprintf(pcie_rkep->msix_ctx[i].name, "%s-%d\n", pcie_rkep->dev.name, i); - ret = request_irq(pcie_rkep->msix_entries[i].vector, - pcie_rkep_pcie_interrupt, 0, pcie_rkep->msix_ctx[i].name, - &pcie_rkep->msix_ctx[i]); - - if (ret) - break; - } - - if (ret) { - for (j = 0; j < i; j++) - free_irq(pcie_rkep->msix_entries[j].vector, &pcie_rkep->msix_ctx[j]); - pci_disable_msix(pcie_rkep->pdev); - dev_err(&pcie_rkep->pdev->dev, "fail to allocate msi-x interrupt\n"); - } else { - pcie_rkep->msix_enable = true; - dev_err(&pcie_rkep->pdev->dev, "success to request msi-x irq\n"); - } - - return ret; -} - static int rkep_loadfile(struct device *dev, char *path, void __iomem *bar, int pos) { struct file *p_file = NULL; @@ -1120,7 +1080,7 @@ static DEVICE_ATTR_WO(rkep); static int pcie_rkep_probe(struct pci_dev *pdev, const struct pci_device_id *id) { - int ret, i; + int ret; struct pcie_rkep *pcie_rkep; u8 *name; u16 val; @@ -1192,7 +1152,7 @@ static int pcie_rkep_probe(struct pci_dev *pdev, const struct pci_device_id *id) pci_set_drvdata(pdev, pcie_rkep); - ret = pcie_rkep_request_msi_irq(pcie_rkep); + ret = pcie_rkep_request_irq(pcie_rkep, PCI_IRQ_MSI); if (ret) goto err_register_irq; @@ -1244,18 +1204,7 @@ static int pcie_rkep_probe(struct pci_dev *pdev, const struct pci_device_id *id) return 0; err_register_obj: - if (pcie_rkep->msix_enable) { - for (i = 0; i < RKEP_NUM_MSIX_VECTORS; i++) - free_irq(pcie_rkep->msix_entries[i].vector, &pcie_rkep->msix_ctx[i]); - pci_disable_msix(pdev); - } else if (pcie_rkep->msi_enable) { - for (i = 0; i < RKEP_NUM_MSI_VECTORS; i++) { - if (pcie_rkep->msi_ctx[i].dev) - free_irq(pci_irq_vector(pdev, i), &pcie_rkep->msi_ctx[i]); - } - - pci_disable_msi(pcie_rkep->pdev); - } + pcie_rkep_release_irq(pcie_rkep); err_register_irq: misc_deregister(&pcie_rkep->dev); err_pci_iomap: @@ -1276,7 +1225,6 @@ err_pci_enable_dev: static void pcie_rkep_remove(struct pci_dev *pdev) { struct pcie_rkep *pcie_rkep = pci_get_drvdata(pdev); - int i; if (pcie_rkep->dma_obj) pcie_dw_dmatest_unregister(pcie_rkep->dma_obj); @@ -1285,6 +1233,8 @@ static void pcie_rkep_remove(struct pci_dev *pdev) #if IS_ENABLED(CONFIG_PCIE_FUNC_RKEP_USERPAGES) free_contig_range(page_to_pfn(pcie_rkep->user_pages), RKEP_USER_MEM_SIZE >> PAGE_SHIFT); #endif + pcie_rkep_release_irq(pcie_rkep); + if (pcie_rkep->bar0) pci_iounmap(pdev, pcie_rkep->bar0); if (pcie_rkep->bar2) @@ -1294,17 +1244,6 @@ static void pcie_rkep_remove(struct pci_dev *pdev) pci_release_regions(pdev); pci_disable_device(pdev); misc_deregister(&pcie_rkep->dev); - - if (pcie_rkep->msix_enable) { - for (i = 0; i < RKEP_NUM_MSIX_VECTORS; i++) - free_irq(pcie_rkep->msix_entries[i].vector, &pcie_rkep->msix_ctx[i]); - pci_disable_msix(pdev); - } else if (pcie_rkep->msi_enable) { - for (i = 0; i < RKEP_NUM_MSI_VECTORS; i++) - if (pcie_rkep->msi_ctx[i].dev) - free_irq(pci_irq_vector(pdev, i), &pcie_rkep->msi_ctx[i]); - pci_disable_msi(pcie_rkep->pdev); - } } static const struct pci_device_id pcie_rkep_pcidev_id[] = { From 7f71d2776b12d75dababf4dc1a98ca0d8a3205f4 Mon Sep 17 00:00:00 2001 From: Jon Lin Date: Thu, 30 Nov 2023 16:45:53 +0800 Subject: [PATCH 4/4] PCI: rockchip: dw: Support IRQ user In order to expand the number of interrupts and achieve independent services, a specific IRQ USER concept is proposed. For user: ioctl PCIE_EP_RAISE_IRQ_USER to raise a dedicated IRQ event ioctl PCIE_EP_POLL_IRQ_USER to check IRQ event status Change-Id: I2dd5792a6245d3918dc3d555fccd1601fb9fb22e Signed-off-by: Jon Lin --- drivers/misc/rockchip/pcie-rkep.c | 121 +++++++++++++++--- .../pci/controller/dwc/pcie-dw-ep-rockchip.c | 120 ++++++++++++----- include/uapi/linux/rk-pcie-ep.h | 24 +++- 3 files changed, 212 insertions(+), 53 deletions(-) diff --git a/drivers/misc/rockchip/pcie-rkep.c b/drivers/misc/rockchip/pcie-rkep.c index 06caac118e30..467dcc48534d 100644 --- a/drivers/misc/rockchip/pcie-rkep.c +++ b/drivers/misc/rockchip/pcie-rkep.c @@ -91,9 +91,10 @@ static DEFINE_MUTEX(rkep_mutex); #define RKEP_USER_MEM_SIZE SZ_64M #define PCIE_CFG_ELBI_APP_OFFSET 0xe00 +#define PCIE_CFG_ELBI_USER_DATA_OFF 0x10 + #define PCIE_ELBI_REG_NUM 0x2 -#define RKEP_EP_VIRTUAL_ID_MAX (8 * 4096) #define RKEP_EP_ELBI_TIEMOUT_US 100000 #define PCIE_RK3568_RC_DBI_BASE 0xf6000000 @@ -118,9 +119,10 @@ struct pcie_rkep { struct dma_trx_obj *dma_obj; struct pcie_ep_obj_info *obj_info; struct page *user_pages; /* Allocated physical memory for user space */ - struct fasync_struct *async; struct mutex dev_lock_mutex; DECLARE_BITMAP(virtual_id_bitmap, RKEP_EP_VIRTUAL_ID_MAX); + DECLARE_BITMAP(virtual_id_irq_bitmap, RKEP_EP_VIRTUAL_ID_MAX); + wait_queue_head_t wq_head; }; struct pcie_file { @@ -153,11 +155,11 @@ static int rkep_ep_request_virtual_id(struct pcie_file *pcie_file) mutex_unlock(&pcie_rkep->dev_lock_mutex); return -EINVAL; } - __set_bit(index, pcie_rkep->virtual_id_bitmap); + set_bit(index, pcie_rkep->virtual_id_bitmap); mutex_unlock(&pcie_rkep->dev_lock_mutex); mutex_lock(&pcie_file->file_lock_mutex); - __set_bit(index, pcie_file->child_vid_bitmap); + set_bit(index, pcie_file->child_vid_bitmap); mutex_unlock(&pcie_file->file_lock_mutex); dev_dbg(&pcie_rkep->pdev->dev, "request virtual id %d\n", index); @@ -191,11 +193,13 @@ static int rkep_ep_release_virtual_id(struct pcie_file *pcie_file, int index) return 0; } -static int rkep_ep_raise_elbi_irq_user(struct pcie_rkep *pcie_rkep, u32 interrupt_num) +static int rkep_ep_raise_elbi_irq(struct pcie_file *pcie_file, u32 interrupt_num) { + struct pcie_rkep *pcie_rkep = pcie_file->pcie_rkep; u32 index, off; int i, gap_us = 100; u32 val; + int ret; if (interrupt_num >= (PCIE_ELBI_REG_NUM * 16)) { dev_err(&pcie_rkep->pdev->dev, "elbi int num out of max count\n"); @@ -216,16 +220,57 @@ static int rkep_ep_raise_elbi_irq_user(struct pcie_rkep *pcie_rkep, u32 interrup if (i >= gap_us) dev_err(&pcie_rkep->pdev->dev, "elbi int is not clear, status=%x\n", val); - return pci_write_config_dword(pcie_rkep->pdev, PCIE_CFG_ELBI_APP_OFFSET + 4 * index, + mutex_lock(&pcie_file->file_lock_mutex); + ret = pci_write_config_dword(pcie_rkep->pdev, PCIE_CFG_ELBI_APP_OFFSET + 4 * index, (1 << (off + 16)) | (1 << off)); + mutex_unlock(&pcie_file->file_lock_mutex); + return ret; } -static int pcie_rkep_fasync(int fd, struct file *file, int mode) +static int rkep_ep_raise_irq_user_obj(struct pcie_file *pcie_file, u32 index) { - struct pcie_file *pcie_file = file->private_data; struct pcie_rkep *pcie_rkep = pcie_file->pcie_rkep; + int ret; - return fasync_helper(fd, file, mode, &pcie_rkep->async); + if (index >= RKEP_EP_VIRTUAL_ID_MAX) { + dev_err(&pcie_rkep->pdev->dev, "raise irq_user, virtual id %d out of range\n", index); + + return -EINVAL; + } + + pcie_rkep->obj_info->irq_type_ep = OBJ_IRQ_USER; + pcie_rkep->obj_info->irq_user_data_ep = index; + ret = rkep_ep_raise_elbi_irq(pcie_file, 0); + + return ret; +} + +static int rkep_ep_poll_irq_user(struct pcie_file *pcie_file, struct pcie_ep_obj_poll_virtual_id_cfg *cfg) +{ + struct pcie_rkep *pcie_rkep = pcie_file->pcie_rkep; + u32 index = cfg->virtual_id; + + if (index >= RKEP_EP_VIRTUAL_ID_MAX) { + dev_err(&pcie_rkep->pdev->dev, "poll irq_user, virtual id %d out of range\n", index); + + return -EINVAL; + } + + cfg->poll_status = NSIGPOLL; + if (cfg->sync) { + wait_event_interruptible(pcie_rkep->wq_head, + test_bit(index, pcie_rkep->virtual_id_irq_bitmap)); + } else { + wait_event_interruptible_timeout(pcie_rkep->wq_head, + test_bit(index, pcie_rkep->virtual_id_irq_bitmap), + cfg->timeout_ms); + } + if (test_and_clear_bit(index, pcie_rkep->virtual_id_irq_bitmap)) + cfg->poll_status = POLL_IN; + + dev_dbg(&pcie_rkep->pdev->dev, "poll virtual id %d, ret=%d\n", index, cfg->poll_status); + + return 0; } static int pcie_rkep_open(struct inode *inode, struct file *file) @@ -253,8 +298,6 @@ static int pcie_rkep_release(struct inode *inode, struct file *file) struct pcie_rkep *pcie_rkep = pcie_file->pcie_rkep; int index; - pcie_rkep_fasync(-1, file, 0);//TODO - while (1) { mutex_lock(&pcie_file->file_lock_mutex); index = find_first_bit(pcie_file->child_vid_bitmap, RKEP_EP_VIRTUAL_ID_MAX); @@ -526,6 +569,7 @@ static long pcie_rkep_ioctl(struct file *file, unsigned int cmd, unsigned long a struct pcie_ep_dma_cache_cfg cfg; struct pcie_ep_dma_block_req dma; void __user *uarg = (void __user *)args; + struct pcie_ep_obj_poll_virtual_id_cfg poll_cfg; int mmap_res; int ret; int index; @@ -566,7 +610,8 @@ static long pcie_rkep_ioctl(struct file *file, unsigned int cmd, unsigned long a case PCIE_EP_DMA_XFER_BLOCK: ret = copy_from_user(&dma, uarg, sizeof(dma)); if (ret) { - dev_err(&pcie_rkep->pdev->dev, "failed to get dma_data copy from userspace\n"); + dev_err(&pcie_rkep->pdev->dev, + "failed to get dma_data copy from userspace\n"); return -EFAULT; } ret = rkep_ep_dma_xfer(pcie_rkep, &dma); @@ -589,7 +634,8 @@ static long pcie_rkep_ioctl(struct file *file, unsigned int cmd, unsigned long a case PCIE_EP_RELEASE_VIRTUAL_ID: ret = copy_from_user(&index, uarg, sizeof(index)); if (ret) { - dev_err(&pcie_rkep->pdev->dev, "failed to get dma_data copy from userspace\n"); + dev_err(&pcie_rkep->pdev->dev, + "failed to get release data copy from userspace\n"); return -EFAULT; } ret = rkep_ep_release_virtual_id(pcie_file, index); @@ -600,13 +646,42 @@ static long pcie_rkep_ioctl(struct file *file, unsigned int cmd, unsigned long a return -EFAULT; } break; + case PCIE_EP_RAISE_IRQ_USER: + ret = copy_from_user(&index, uarg, sizeof(index)); + if (ret) { + dev_err(&pcie_rkep->pdev->dev, + "failed to get raise irq data copy from userspace\n"); + return -EFAULT; + } + + ret = rkep_ep_raise_irq_user_obj(pcie_file, index); + if (ret < 0) + return -EFAULT; + break; + case PCIE_EP_POLL_IRQ_USER: + ret = copy_from_user(&poll_cfg, uarg, sizeof(poll_cfg)); + if (ret) { + dev_err(&pcie_rkep->pdev->dev, + "failed to get poll irq data copy from userspace\n"); + + return -EFAULT; + } + + ret = rkep_ep_poll_irq_user(pcie_file, &poll_cfg); + if (ret < 0) + return -EFAULT; + + if (copy_to_user(argp, &poll_cfg, sizeof(poll_cfg))) + return -EFAULT; + break; case PCIE_EP_RAISE_ELBI: ret = copy_from_user(&index, uarg, sizeof(index)); if (ret) { - dev_err(&pcie_rkep->pdev->dev, "failed to get dma_data copy from userspace\n"); + dev_err(&pcie_rkep->pdev->dev, + "failed to get raise elbi data copy from userspace\n"); return -EFAULT; } - ret = rkep_ep_raise_elbi_irq_user(pcie_rkep, index); + ret = rkep_ep_raise_elbi_irq(pcie_file, index); if (ret < 0) { dev_err(&pcie_rkep->pdev->dev, "raise elbi %d failed, ret=%d\n", index, ret); @@ -642,7 +717,6 @@ static const struct file_operations pcie_rkep_fops = { .read = pcie_rkep_read, .unlocked_ioctl = pcie_rkep_ioctl, .mmap = pcie_rkep_mmap, - .fasync = pcie_rkep_fasync, .release = pcie_rkep_release, .llseek = default_llseek, }; @@ -765,7 +839,7 @@ static void pcie_rkep_start_dma_rd(struct dma_trx_obj *obj, struct dma_table *cu pcie_rkep_writel_dbi(pcie_rkep, PCIE_DMA_OFFSET + PCIE_DMA_RD_DOORBELL, cur->start.asdword); } - // pcie_rkep_dma_debug(obj, cur); + /* pcie_rkep_dma_debug(obj, cur); */ } static void pcie_rkep_start_dma_wr(struct dma_trx_obj *obj, struct dma_table *cur, int ctr_off) @@ -808,7 +882,7 @@ static void pcie_rkep_start_dma_wr(struct dma_trx_obj *obj, struct dma_table *cu pcie_rkep_writel_dbi(pcie_rkep, PCIE_DMA_OFFSET + PCIE_DMA_WR_DOORBELL, cur->start.asdword); } - // pcie_rkep_dma_debug(obj, cur); + /* pcie_rkep_dma_debug(obj, cur); */ } static void pcie_rkep_start_dma_dwc(struct dma_trx_obj *obj, struct dma_table *table) @@ -916,8 +990,8 @@ static int pcie_rkep_obj_handler(struct pcie_rkep *pcie_rkep, struct pci_dev *pd u32 irq_type; u32 chn; union int_clear clears; + u32 reg; - kill_fasync(&pcie_rkep->async, SIGIO, POLL_IN); irq_type = pcie_rkep->obj_info->irq_type_rc; if (irq_type == OBJ_IRQ_DMA) { /* DMA helper */ @@ -960,6 +1034,12 @@ static int pcie_rkep_obj_handler(struct pcie_rkep *pcie_rkep, struct pci_dev *pd } } } + } else if (irq_type == OBJ_IRQ_USER) { + reg = pcie_rkep->obj_info->irq_user_data_rc; + if (reg < RKEP_EP_VIRTUAL_ID_MAX) { + set_bit(reg, pcie_rkep->virtual_id_irq_bitmap); + wake_up_interruptible(&pcie_rkep->wq_head); + } } return 0; @@ -1094,7 +1174,7 @@ static int pcie_rkep_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (!name) return -ENOMEM; - __set_bit(0, pcie_rkep->virtual_id_bitmap); + set_bit(0, pcie_rkep->virtual_id_bitmap); ret = pci_enable_device(pdev); if (ret) { @@ -1152,6 +1232,7 @@ static int pcie_rkep_probe(struct pci_dev *pdev, const struct pci_device_id *id) pci_set_drvdata(pdev, pcie_rkep); + init_waitqueue_head(&pcie_rkep->wq_head); ret = pcie_rkep_request_irq(pcie_rkep, PCI_IRQ_MSI); if (ret) goto err_register_irq; diff --git a/drivers/pci/controller/dwc/pcie-dw-ep-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-ep-rockchip.c index 29a8f8ae11d6..1addd6c38875 100644 --- a/drivers/pci/controller/dwc/pcie-dw-ep-rockchip.c +++ b/drivers/pci/controller/dwc/pcie-dw-ep-rockchip.c @@ -94,12 +94,14 @@ #define PCIE_ELBI_LOCAL_BASE 0x200e00 #define PCIE_ELBI_APP_ELBI_INT_GEN0 0x0 -#define PCIE_ELBI_APP_ELBI_INT_GEN0_SIGIO BIT(0) +#define PCIE_ELBI_APP_ELBI_INT_GEN0_IRQ_USER BIT(0) #define PCIE_ELBI_APP_ELBI_INT_GEN1 0x4 #define PCIE_ELBI_LOCAL_ENABLE_OFF 0x8 +#define PCIE_ELBI_USER_DATA_OFF 0x10 + #define PCIE_DIRECT_SPEED_CHANGE BIT(17) #define PCIE_TYPE0_STATUS_COMMAND_REG 0x4 @@ -131,12 +133,14 @@ struct rockchip_pcie { u32 ib_target_size[PCIE_BAR_MAX_NUM]; void *ib_target_base[PCIE_BAR_MAX_NUM]; struct dma_trx_obj *dma_obj; - struct fasync_struct *async; phys_addr_t dbi_base_physical; struct pcie_ep_obj_info *obj_info; enum pcie_ep_mmap_resource cur_mmap_res; struct workqueue_struct *hot_rst_wq; struct work_struct hot_rst_work; + struct mutex file_mutex; + DECLARE_BITMAP(virtual_id_irq_bitmap, RKEP_EP_VIRTUAL_ID_MAX); + wait_queue_head_t wq_head; }; struct rockchip_pcie_misc_dev { @@ -642,6 +646,49 @@ static void rockchip_pcie_raise_msi_irq(struct rockchip_pcie *rockchip, u8 inter rockchip_pcie_writel_apb(rockchip, BIT(interrupt_num), PCIE_CLIENT_MSI_GEN_CON); } +static int rockchip_pcie_raise_irq_user(struct rockchip_pcie *rockchip, u32 index) +{ + if (index >= RKEP_EP_VIRTUAL_ID_MAX) { + dev_err(rockchip->pci.dev, "raise irq_user, virtual id %d out of range\n", index); + + return -EINVAL; + } + + mutex_lock(&rockchip->file_mutex); + rockchip->obj_info->irq_type_rc = OBJ_IRQ_USER; + rockchip->obj_info->irq_user_data_rc = index; + rockchip_pcie_raise_msi_irq(rockchip, PCIe_CLIENT_MSI_OBJ_IRQ); + mutex_unlock(&rockchip->file_mutex); + + return 0; +} + +static int rockchip_pcie_poll_irq_user(struct rockchip_pcie *rockchip, struct pcie_ep_obj_poll_virtual_id_cfg *cfg) +{ + u32 index = cfg->virtual_id; + + if (index >= RKEP_EP_VIRTUAL_ID_MAX) { + dev_err(rockchip->pci.dev, "poll irq_user, virtual id %d out of range\n", index); + + return -EINVAL; + } + + cfg->poll_status = NSIGPOLL; + if (cfg->sync) + wait_event_interruptible(rockchip->wq_head, + test_bit(index, rockchip->virtual_id_irq_bitmap)); + else + wait_event_interruptible_timeout(rockchip->wq_head, + test_bit(index, rockchip->virtual_id_irq_bitmap), + cfg->timeout_ms); + if (test_and_clear_bit(index, rockchip->virtual_id_irq_bitmap)) + cfg->poll_status = POLL_IN; + + dev_dbg(rockchip->pci.dev, "poll virtual id %d, ret=%d\n", index, cfg->poll_status); + + return 0; +} + static irqreturn_t rockchip_pcie_sys_irq_handler(int irq, void *arg) { struct rockchip_pcie *rockchip = arg; @@ -651,14 +698,19 @@ static irqreturn_t rockchip_pcie_sys_irq_handler(int irq, void *arg) union int_status wr_status, rd_status; union int_clear clears; u32 reg, mask; - bool sigio = false; /* ELBI helper, only check the valid bits, and discard the rest interrupts */ elbi_reg = dw_pcie_readl_dbi(pci, PCIE_ELBI_LOCAL_BASE + PCIE_ELBI_APP_ELBI_INT_GEN0); - if (elbi_reg & PCIE_ELBI_APP_ELBI_INT_GEN0_SIGIO) { - sigio = true; - rockchip->obj_info->irq_type_ep = OBJ_IRQ_ELBI; + if (elbi_reg & PCIE_ELBI_APP_ELBI_INT_GEN0_IRQ_USER) { rockchip_pcie_elbi_clear(rockchip); + + if (rockchip->obj_info->irq_type_ep == OBJ_IRQ_USER) { + reg = rockchip->obj_info->irq_user_data_ep; + if (reg < RKEP_EP_VIRTUAL_ID_MAX) { + set_bit(reg, rockchip->virtual_id_irq_bitmap); + wake_up_interruptible(&rockchip->wq_head); + } + } goto out; } @@ -711,15 +763,9 @@ static irqreturn_t rockchip_pcie_sys_irq_handler(int irq, void *arg) rockchip->obj_info->irq_type_ep = OBJ_IRQ_DMA; rockchip->obj_info->dma_status_ep.wr |= wr_status.asdword; rockchip->obj_info->dma_status_ep.rd |= rd_status.asdword; - sigio = true; } out: - if (sigio) { - dev_dbg(rockchip->pci.dev, "SIGIO\n"); - kill_fasync(&rockchip->async, SIGIO, POLL_IN); - } - reg = rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_INTR_STATUS_MISC); if (reg & BIT(2)) queue_work(rockchip->hot_rst_wq, &rockchip->hot_rst_work); @@ -944,13 +990,6 @@ static const struct dw_pcie_ops dw_pcie_ops = { .link_up = rockchip_pcie_link_up, }; -static int pcie_ep_fasync(int fd, struct file *file, int mode) -{ - struct rockchip_pcie *rockchip = (struct rockchip_pcie *)file->private_data; - - return fasync_helper(fd, file, mode, &rockchip->async); -} - static int pcie_ep_open(struct inode *inode, struct file *file) { struct miscdevice *miscdev = file->private_data; @@ -962,18 +1001,14 @@ static int pcie_ep_open(struct inode *inode, struct file *file) return 0; } -static int pcie_ep_release(struct inode *inode, struct file *file) -{ - return pcie_ep_fasync(-1, file, 0); -} - static long pcie_ep_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct rockchip_pcie *rockchip = (struct rockchip_pcie *)file->private_data; struct pcie_ep_dma_cache_cfg cfg; void __user *uarg = (void __user *)arg; - int i, ret; + struct pcie_ep_obj_poll_virtual_id_cfg poll_cfg; enum pcie_ep_mmap_resource mmap_res; + int ret, index; switch (cmd) { case PCIE_DMA_CACHE_INVALIDE: @@ -998,8 +1033,7 @@ static long pcie_ep_ioctl(struct file *file, unsigned int cmd, unsigned long arg dw_pcie_writel_dbi(&rockchip->pci, PCIE_DMA_OFFSET + PCIE_DMA_RD_INT_MASK, 0xffffffff); break; - case PCIE_DMA_RAISE_MSI_OBJ_IRQ_USER: - rockchip->obj_info->irq_type_rc = OBJ_IRQ_USER; + case PCIE_EP_RAISE_MSI: rockchip_pcie_raise_msi_irq(rockchip, PCIe_CLIENT_MSI_OBJ_IRQ); break; case PCIE_EP_SET_MMAP_RESOURCE: @@ -1016,6 +1050,34 @@ static long pcie_ep_ioctl(struct file *file, unsigned int cmd, unsigned long arg rockchip->cur_mmap_res = mmap_res; break; + case PCIE_EP_RAISE_IRQ_USER: + ret = copy_from_user(&index, uarg, sizeof(index)); + if (ret) { + dev_err(rockchip->pci.dev, + "failed to get raise irq data copy from userspace\n"); + return -EFAULT; + } + + ret = rockchip_pcie_raise_irq_user(rockchip, index); + if (ret < 0) + return -EFAULT; + break; + case PCIE_EP_POLL_IRQ_USER: + ret = copy_from_user(&poll_cfg, uarg, sizeof(poll_cfg)); + if (ret) { + dev_err(rockchip->pci.dev, + "failed to get poll irq data copy from userspace\n"); + + return -EFAULT; + } + + ret = rockchip_pcie_poll_irq_user(rockchip, &poll_cfg); + if (ret < 0) + return -EFAULT; + + if (copy_to_user(uarg, &poll_cfg, sizeof(poll_cfg))) + return -EFAULT; + break; default: break; } @@ -1076,9 +1138,7 @@ static int pcie_ep_mmap(struct file *file, struct vm_area_struct *vma) static const struct file_operations pcie_ep_ops = { .owner = THIS_MODULE, .open = pcie_ep_open, - .release = pcie_ep_release, .unlocked_ioctl = pcie_ep_ioctl, - .fasync = pcie_ep_fasync, .mmap = pcie_ep_mmap, }; @@ -1241,12 +1301,14 @@ already_linkup: rockchip->dma_obj->config_dma_func = rockchip_pcie_config_dma_dwc; rockchip->dma_obj->get_dma_status = rockchip_pcie_get_dma_status; } + mutex_init(&rockchip->file_mutex); /* Enable client ELBI interrupt */ rockchip_pcie_writel_apb(rockchip, 0x80000000, PCIE_CLIENT_INTR_MASK); /* Enable ELBI interrupt */ rockchip_pcie_local_elbi_enable(rockchip); + init_waitqueue_head(&rockchip->wq_head); ret = rockchip_pcie_request_sys_irq(rockchip, pdev); if (ret) goto deinit_phy; diff --git a/include/uapi/linux/rk-pcie-ep.h b/include/uapi/linux/rk-pcie-ep.h index fe1e677c1ad4..d89748eed925 100644 --- a/include/uapi/linux/rk-pcie-ep.h +++ b/include/uapi/linux/rk-pcie-ep.h @@ -72,6 +72,9 @@ enum pcie_ep_mmap_resource { PCIE_EP_MMAP_RESOURCE_MAX, }; +#define PCIE_EP_OBJ_INFO_MSI_DATA_NUM 0x8 +#define RKEP_EP_VIRTUAL_ID_MAX (PCIE_EP_OBJ_INFO_MSI_DATA_NUM * 32) /* 256 virtual_id */ + /* * rockchip ep device information which is store in BAR0 */ @@ -82,25 +85,38 @@ struct pcie_ep_obj_info { __u16 mode; __u16 submode; } devmode; - __u32 msi_data[0x8]; - __u8 reserved[0x1D4]; + __u32 msi_data[PCIE_EP_OBJ_INFO_MSI_DATA_NUM]; + __u8 reserved[0x1D0]; __u32 irq_type_rc; /* Generate in ep isr, valid only for rc, clear in rc */ struct pcie_ep_obj_irq_dma_status dma_status_rc; /* Generate in ep isr, valid only for rc, clear in rc */ __u32 irq_type_ep; /* Generate in ep isr, valid only for ep, clear in ep */ struct pcie_ep_obj_irq_dma_status dma_status_ep; /* Generate in ep isr, valid only for ep, clear in ep */ - __u32 obj_irq_user_data; /* OBJ_IRQ_USER userspace data */ + __u32 irq_user_data_rc; /* Generate in ep, valid only for rc, No need to clear */ + __u32 irq_user_data_ep; /* Generate in rc, valid only for ep, No need to clear */ +}; + +/* + * rockchip driver ep_obj poll ioctrl input param + */ +struct pcie_ep_obj_poll_virtual_id_cfg { + __u32 timeout_ms; + __u32 sync; + __u32 virtual_id; + __u32 poll_status; }; #define PCIE_BASE 'P' #define PCIE_DMA_CACHE_INVALIDE _IOW(PCIE_BASE, 1, struct pcie_ep_dma_cache_cfg) #define PCIE_DMA_CACHE_FLUSH _IOW(PCIE_BASE, 2, struct pcie_ep_dma_cache_cfg) #define PCIE_DMA_IRQ_MASK_ALL _IOW(PCIE_BASE, 3, int) -#define PCIE_DMA_RAISE_MSI_OBJ_IRQ_USER _IOW(PCIE_BASE, 4, int) +#define PCIE_EP_RAISE_MSI _IOW(PCIE_BASE, 4, int) #define PCIE_EP_SET_MMAP_RESOURCE _IOW(PCIE_BASE, 6, int) #define PCIE_EP_RAISE_ELBI _IOW(PCIE_BASE, 7, int) #define PCIE_EP_REQUEST_VIRTUAL_ID _IOR(PCIE_BASE, 16, int) #define PCIE_EP_RELEASE_VIRTUAL_ID _IOW(PCIE_BASE, 17, int) +#define PCIE_EP_RAISE_IRQ_USER _IOW(PCIE_BASE, 18, int) +#define PCIE_EP_POLL_IRQ_USER _IOW(PCIE_BASE, 19, struct pcie_ep_obj_poll_virtual_id_cfg) #define PCIE_EP_DMA_XFER_BLOCK _IOW(PCIE_BASE, 32, struct pcie_ep_dma_block_req) #endif