dmaengine: qcom_hidma: add MSI interrupt support
Subsystems (5)
v6 cover dmaengine: qcom_hidma: add MSI interrupt support
The new version of the HW supports MSI interrupts instead of wired interrupts. The MSI interrupts are especially useful for the guest machine execution. The wired interrupts usually trap to the hypervisor and then are relayed to the actual interrupt.
The MSI interrupts can be directly fed into the interrupt controller.
Adding a new OF compat string (qcom,hidma-1.1) and ACPI string (QCOM8062) to distinguish newer HW from the older ones.
v6:
* rebase 4.9 kernel
v5:
http://www.spinics.net/lists/arm-kernel/msg537014.html
* dmaengine: qcom_hidma: add MSI support for interrupts
** Return MSI interrupts before calling platform_msi_domain_free_irqs. Also cleanup MSI interrupts on the error path.
** Free the legacy IRQ only if MSI is disabled
* add dmaengine: qcom_hidma: break completion processing on error in order to break the completions if an error is observed while servicing completed work.
* drop dmaengine: qcom_hidma: make error and success path common as the success path assumes that we'll get the number of notifications for the
jobs queued. This is not true under error conditions.
* simplify dmaengine: qcom_hidma: protect common data structures. We just need to protect the TRE processed offset. It is the variable that keeps track
of outstanding requests.
v4:
http://www.spinics.net/lists/devicetree/msg144563.html
* device tree binding update to refer to msi.txt
v3:
* day 0 fix for when ACPI is not compiled in
* https://www.spinics.net/lists/arm-kernel/msg532179.html
v2:
https://patchwork.kernel.org/patch/9326399/
* Documentation update for DT bindings
* Rebased to slave-next
* Dropped dmaengine: qcom_hidma: eliminate processed variables. Replaced it with dmaengine: qcom_hidma: protect common data structures
v1:
http://lists.infradead.org/pipermail/linux-arm-kernel/2016-July/444167.html
* initial implementation
Sinan Kaya (10):
Documentation: DT: qcom_hidma: update binding for MSI
Documentation: DT: qcom_hidma: correct spelling mistakes
of: irq: make of_msi_configure accessible from modules
dmaengine: qcom_hidma: configure DMA and MSI for OF
dmaengine: qcom_hidma: make pending_tre_count atomic
dmaengine: qcom_hidma: bring out interrupt cause
dmaengine: qcom_hidma: add a common API to setup the interrupt
dmaengine: qcom_hidma: protect common data structures
dmaengine: qcom_hidma: break completion processing on error
dmaengine: qcom_hidma: add MSI support for interrupts
.../devicetree/bindings/dma/qcom_hidma_mgmt.txt | 12 +- drivers/dma/qcom/hidma.c | 143 +++++++++++++++++- drivers/dma/qcom/hidma.h | 6 +- drivers/dma/qcom/hidma_dbg.c | 3 +- drivers/dma/qcom/hidma_ll.c | 161 +++++++++++---------- drivers/dma/qcom/hidma_mgmt.c | 9 +- drivers/of/irq.c | 1 + 7 files changed, 250 insertions(+), 85 deletions(-)
Signature · 1 line
1.9.1
PATCH v6 1/10 Documentation: DT: qcom_hidma: update binding for MSI
Adding a new binding for qcom,hidma-1.1 to distinguish HW supporting MSI interrupts from the older revision.
--- Documentation/devicetree/bindings/dma/qcom_hidma_mgmt.txt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
Documentation/devicetree/bindings/dma/qcom_hidma_mgmt.txt +7 -1
@@ -47,12 +47,18 @@ When the OS is not in control of the management interface (i.e. it's a guest), the channel nodes appear on their own, not under a management node. Required properties: -- compatible: must contain "qcom,hidma-1.0" +- compatible: must contain "qcom,hidma-1.0" for initial HW or "qcom,hidma-1.1" +for MSI capable HW. - reg: Addresses for the transfer and event channel - interrupts: Should contain the event interrupt - desc-count: Number of asynchronous requests this channel can handle - iommus: required a iommu node +Optional properties for MSI: +- msi-parent : See the generic MSI binding described in + devicetree/bindings/interrupt-controller/msi.txt for a description of the + msi-parent property. + Example: Hypervisor OS configuration:
Signature · 1 line
1.9.1
Rob Herring
maintainerRe: [PATCH V6 01/10] Documentation: DT: qcom_hidma: update binding for MSI
Quoted 7 lines · Sinan Kaya
Adding a new binding for qcom,hidma-1.1 to distinguish HW supporting MSI interrupts from the older revision.
Signed-off-by Sinan Kaya <[email protected]>--- Documentation/devicetree/bindings/dma/qcom_hidma_mgmt.txt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
Please add acks when posting new versions.
Rob
Re: [PATCH V6 01/10] Documentation: DT: qcom_hidma: update binding for MSI
Quoted 11 lines · Rob Herring
Quoted 7 lines · Sinan Kaya
Adding a new binding for qcom,hidma-1.1 to distinguish HW supporting MSI interrupts from the older revision.
Signed-off-by Sinan Kaya <[email protected]>--- Documentation/devicetree/bindings/dma/qcom_hidma_mgmt.txt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)Please add acks when posting new versions.
Sure, sorry about that. Your acked version already got merged to Vinod's branch. During the merge, Vinod got some merge conflicts for the remainder of the patches.
I was trying to post the remaining patches for Vinod to pick it up. Apologies if it was not clear.
I posted V7 with only four remaining patches without the already merged DT changes.
Quoted 6 lines
Rob
--
To unsubscribe from this list: send the line "unsubscribe dmaengine" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Signature · 3 lines
Sinan Kaya Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.
PATCH v6 2/10 Documentation: DT: qcom_hidma: correct spelling mistakes
In reply to Sinan KayaFix the spelling mistakes and extra and statements in the sentences.
--- Documentation/devicetree/bindings/dma/qcom_hidma_mgmt.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
Documentation/devicetree/bindings/dma/qcom_hidma_mgmt.txt +2 -2
@@ -5,13 +5,13 @@ memcpy and memset capabilities. It has been designed for virtualized environments. Each HIDMA HW instance consists of multiple DMA channels. These channels -share the same bandwidth. The bandwidth utilization can be parititioned +share the same bandwidth. The bandwidth utilization can be partitioned among channels based on the priority and weight assignments. There are only two priority levels and 15 weigh assignments possible. Other parameters here determine how much of the system bus this HIDMA -instance can use like maximum read/write request and and number of bytes to +instance can use like maximum read/write request and number of bytes to read/write in a single burst. Main node required properties:
Signature · 1 line
1.9.1
PATCH v6 3/10 of: irq: make of_msi_configure accessible from modules
In reply to Sinan KayaThe of_msi_configure routine is only accessible by the built-in kernel drivers. Export this function so that modules can use it too.
This function is useful for configuring MSI on child device tree nodes on hierarchical objects.
--- drivers/of/irq.c | 1 + 1 file changed, 1 insertion(+)
drivers/of/irq.c +1 -0
@@ -697,3 +697,4 @@ void of_msi_configure(struct device *dev, struct device_node *np)dev_set_msi_domain (dev,of_msi_get_domain (dev, np,DOMAIN_BUS_PLATFORM_MSI )); } +EXPORT_SYMBOL_GPL (of_msi_configure);
Signature · 1 line
1.9.1
PATCH v6 4/10 dmaengine: qcom_hidma: configure DMA and MSI for OF
In reply to Sinan KayaConfigure the DMA bindings for the device tree based firmware.
--- drivers/dma/qcom/hidma_mgmt.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/dma/qcom/hidma_mgmt.c +8 -1
@@ -375,8 +375,15 @@ static int __init hidma_mgmt_of_populate_channels(struct device_node *np) ret =PTR_ERR (new_pdev); goto out; } +of_node_get (child); + new_pdev->dev.of_node = child;of_dma_configure (&new_pdev->dev, child); - +/* +* It is assumed that calling of_msi_configure is safe on +* platforms with or without MSI support. +*/ +of_msi_configure (&new_pdev->dev, child); +of_node_put (child);kfree (res); res =NULL ; }
Signature · 1 line
1.9.1
PATCH v6 5/10 dmaengine: qcom_hidma: make pending_tre_count atomic
In reply to Sinan KayaGetting ready for the MSI interrupts. The pending_tre_count is used in the interrupt handler to make sure all outstanding requests are serviced.
The driver will allocate 11 MSI interrupts. Each MSI interrupt can be assigned to a different CPU. Then, we have a race condition for common variables as they share the same interrupt handler with a different cause bit and they can potentially be executed in parallel. Making this variable atomic so that it can be updated from multiple processor contexts.
--- drivers/dma/qcom/hidma.h | 2 +- drivers/dma/qcom/hidma_dbg.c | 3 ++- drivers/dma/qcom/hidma_ll.c | 13 ++++++------- 3 files changed, 9 insertions(+), 9 deletions(-)
drivers/dma/qcom/hidma.h +1 -1
@@ -58,7 +58,7 @@ struct hidma_lldev {void __iomem *evca;/* Event Channel address */ struct hidma_tre **pending_tre_list;/* Pointers to pending TREs */ -s32 pending_tre_count;/* Number of TREs pending */ +atomic_t pending_tre_count;/* Number of TREs pending */ void *tre_ring;/* TRE ring */ dma_addr_t tre_dma;/* TRE ring to be shared with HW */
drivers/dma/qcom/hidma_dbg.c +2 -1
@@ -74,7 +74,8 @@ static void hidma_ll_devstats(struct seq_file *s, void *llhndl)seq_printf (s,"tre_ring_handle=%pap\n" , &lldev->tre_dma);seq_printf (s,"tre_ring_size = 0x%x\n" , lldev->tre_ring_size);seq_printf (s,"tre_processed_off = 0x%x\n" , lldev->tre_processed_off); -seq_printf (s,"pending_tre_count=%d\n" , lldev->pending_tre_count); +seq_printf (s,"pending_tre_count=%d\n" , +atomic_read (&lldev->pending_tre_count));seq_printf (s,"evca=%p\n" , lldev->evca);seq_printf (s,"evre_ring=%p\n" , lldev->evre_ring);seq_printf (s,"evre_ring_handle=%pap\n" , &lldev->evre_dma);
drivers/dma/qcom/hidma_ll.c +6 -7
@@ -218,10 +218,9 @@ static int hidma_post_completed(struct hidma_lldev *lldev, int tre_iterator,* Keep track of pending TREs that SW is expecting to receive * from HW. We got one now. Decrement our counter. */ - lldev->pending_tre_count--; -if (lldev->pending_tre_count <0 ) { +if (atomic_dec_return (&lldev->pending_tre_count) <0 ) {dev_warn (lldev->dev,"tre count mismatch on completion" ); - lldev->pending_tre_count =0 ; +atomic_set (&lldev->pending_tre_count,0 ); }spin_unlock_irqrestore (&lldev->lock, flags);
@@ -321,7 +320,7 @@ void hidma_cleanup_pending_tre(struct hidma_lldev *lldev, u8 err_info,u32 tre_read_off; tre_iterator = lldev->tre_processed_off; -while (lldev->pending_tre_count) { +while (atomic_read (&lldev->pending_tre_count)) {if (hidma_post_completed (lldev, tre_iterator, err_info, err_code))break ;
@@ -548,7 +547,7 @@ void hidma_ll_queue_request(struct hidma_lldev *lldev, u32 tre_ch) tre->err_code =0 ; tre->err_info =0 ; tre->queued =1 ; - lldev->pending_tre_count++; +atomic_inc (&lldev->pending_tre_count); lldev->tre_write_offset = (lldev->tre_write_offset +HIDMA_TRE_SIZE ) % lldev->tre_ring_size;spin_unlock_irqrestore (&lldev->lock, flags);
@@ -654,7 +653,7 @@ int hidma_ll_setup(struct hidma_lldev *lldev)u32 val;u32 nr_tres = lldev->nr_tres; - lldev->pending_tre_count =0 ; +atomic_set (&lldev->pending_tre_count,0 ); lldev->tre_processed_off =0 ; lldev->evre_processed_off =0 ; lldev->tre_write_offset =0 ;
@@ -816,7 +815,7 @@ int hidma_ll_uninit(struct hidma_lldev *lldev)tasklet_kill (&lldev->task);memset (lldev->trepool,0 , required_bytes); lldev->trepool =NULL ; - lldev->pending_tre_count =0 ; +atomic_set (&lldev->pending_tre_count,0 ); lldev->tre_write_offset =0 ; rc =hidma_ll_reset (lldev);
Signature · 1 line
1.9.1
PATCH v6 6/10 dmaengine: qcom_hidma: bring out interrupt cause
In reply to Sinan KayaBring out the interrupt cause to the top level so that MSI interrupts can be hooked at a later stage.
--- drivers/dma/qcom/hidma_ll.c | 62 ++++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 29 deletions(-)
drivers/dma/qcom/hidma_ll.c +33 -29
@@ -411,12 +411,24 @@ static int hidma_ll_reset(struct hidma_lldev *lldev)* requests traditionally to the destination, this concept does not apply * here for this HW. */ -irqreturn_t hidma_ll_inthandler (int chirq,void *arg) +static void hidma_ll_int_handler_internal (struct hidma_lldev *lldev,int cause) { -struct hidma_lldev *lldev = arg; -u32 status; -u32 enable; -u32 cause; +if (cause &HIDMA_ERR_INT_MASK ) { +dev_err (lldev->dev,"error 0x%x, disabling...\n" , + cause); + +/* Clear out pending interrupts */ +writel (cause, lldev->evca +HIDMA_EVCA_IRQ_CLR_REG ); + +/* No further submissions. */ +hidma_ll_disable (lldev); + +/* Driver completes the txn and intimates the client.*/ +hidma_cleanup_pending_tre (lldev,0xFF , +HIDMA_EVRE_STATUS_ERROR ); + +return ; + }/* * Fine tuned for this HW...
@@ -425,35 +437,28 @@ irqreturn_t hidma_ll_inthandler(int chirq, void *arg)* read and write accessors are used for performance reasons due to * interrupt delivery guarantees. Do not copy this code blindly and * expect that to work. +* +* Try to consume as many EVREs as possible. */ +hidma_handle_tre_completion (lldev); + +/* We consumed TREs or there are pending TREs or EVREs. */ +writel_relaxed (cause, lldev->evca +HIDMA_EVCA_IRQ_CLR_REG ); +} + +irqreturn_t hidma_ll_inthandler (int chirq,void *arg) +{ +struct hidma_lldev *lldev = arg; +u32 status; +u32 enable; +u32 cause; + status =readl_relaxed (lldev->evca +HIDMA_EVCA_IRQ_STAT_REG ); enable =readl_relaxed (lldev->evca +HIDMA_EVCA_IRQ_EN_REG ); cause = status & enable;while (cause) { -if (cause &HIDMA_ERR_INT_MASK ) { -dev_err (lldev->dev,"error 0x%x, disabling...\n" , - cause); - -/* Clear out pending interrupts */ -writel (cause, lldev->evca +HIDMA_EVCA_IRQ_CLR_REG ); - -/* No further submissions. */ -hidma_ll_disable (lldev); - -/* Driver completes the txn and intimates the client.*/ -hidma_cleanup_pending_tre (lldev,0xFF , -HIDMA_EVRE_STATUS_ERROR ); - goto out; - } - -/* -* Try to consume as many EVREs as possible. -*/ -hidma_handle_tre_completion (lldev); - -/* We consumed TREs or there are pending TREs or EVREs. */ -writel_relaxed (cause, lldev->evca +HIDMA_EVCA_IRQ_CLR_REG ); +hidma_ll_int_handler_internal (lldev, cause);/* * Another interrupt might have arrived while we are
@@ -464,7 +469,6 @@ irqreturn_t hidma_ll_inthandler(int chirq, void *arg) cause = status & enable; } -out:return IRQ_HANDLED ; }
Signature · 1 line
1.9.1
PATCH v6 7/10 dmaengine: qcom_hidma: add a common API to setup the interrupt
In reply to Sinan KayaIntroducing the hidma_ll_setup_irq function to set up the interrupt type externally from the OS interface.
--- drivers/dma/qcom/hidma.h | 2 ++ drivers/dma/qcom/hidma_ll.c | 27 +++++++++++++++++++++++---- 2 files changed, 25 insertions(+), 4 deletions(-)
drivers/dma/qcom/hidma.h +2 -0
@@ -46,6 +46,7 @@ struct hidma_tre { };struct hidma_lldev { +bool msi_support;/* flag indicating MSI support */ bool initialized;/* initialized flag */ u8 trch_state;/* trch_state of the device */ u8 evch_state;/* evch_state of the device */
@@ -148,6 +149,7 @@ int hidma_ll_request(struct hidma_lldev *llhndl, u32 dev_id,int hidma_ll_enable (struct hidma_lldev *llhndl);void hidma_ll_set_transfer_params (struct hidma_lldev *llhndl,u32 tre_ch,dma_addr_t src,dma_addr_t dest,u32 len,u32 flags); +void hidma_ll_setup_irq (struct hidma_lldev *lldev,bool msi);int hidma_ll_setup (struct hidma_lldev *lldev); struct hidma_lldev *hidma_ll_init(struct device *dev, u32 max_channels, void __iomem *trca, void __iomem *evca,
drivers/dma/qcom/hidma_ll.c +23 -4
@@ -694,17 +694,36 @@ int hidma_ll_setup(struct hidma_lldev *lldev)writel (HIDMA_EVRE_SIZE * nr_tres, lldev->evca +HIDMA_EVCA_RING_LEN_REG ); -/* support IRQ only for now */ +/* configure interrupts */ +hidma_ll_setup_irq (lldev, lldev->msi_support); + + rc =hidma_ll_enable (lldev); +if (rc) +return rc; + +return rc; +} + +void hidma_ll_setup_irq (struct hidma_lldev *lldev,bool msi) +{ +u32 val; + + lldev->msi_support = msi; + +/* disable interrupts again after reset */ +writel (0 , lldev->evca +HIDMA_EVCA_IRQ_CLR_REG ); +writel (0 , lldev->evca +HIDMA_EVCA_IRQ_EN_REG ); + +/* support IRQ by default */ val =readl (lldev->evca +HIDMA_EVCA_INTCTRL_REG ); val &= ~0xF ; - val |=0x1 ; +if (!lldev->msi_support) + val = val |0x1 ;writel (val, lldev->evca +HIDMA_EVCA_INTCTRL_REG );/* clear all pending interrupts and enable them */ writel (ENABLE_IRQS , lldev->evca +HIDMA_EVCA_IRQ_CLR_REG );writel (ENABLE_IRQS , lldev->evca +HIDMA_EVCA_IRQ_EN_REG ); - -return hidma_ll_enable (lldev); } struct hidma_lldev *hidma_ll_init(struct device *dev, u32 nr_tres,
Signature · 1 line
1.9.1
PATCH v6 8/10 dmaengine: qcom_hidma: protect common data structures
In reply to Sinan KayaWhen MSI interrupts are supported, error and the transfer interrupt can come from multiple processor contexts.
Each error interrupt is an MSI interrupt. If the channel is disabled by the first error interrupt, the remaining error interrupts will gracefully return in the interrupt handler.
If an error is observed while servicing the completions in success case, the posting of the completions will be aborted as soon as channel disabled state is observed. The error interrupt handler will take it from there and finish the remaining completions. We don't want to create multiple success and error messages to be delivered to the client in mixed order.
--- drivers/dma/qcom/hidma_ll.c | 44 +++++++++++--------------------------------- 1 file changed, 11 insertions(+), 33 deletions(-)
drivers/dma/qcom/hidma_ll.c +11 -33
@@ -198,13 +198,16 @@ static void hidma_ll_tre_complete(unsigned long arg) } } -static int hidma_post_completed (struct hidma_lldev *lldev,int tre_iterator, -u8 err_info,u8 err_code) +static int hidma_post_completed (struct hidma_lldev *lldev,u8 err_info, +u8 err_code) {struct hidma_tre *tre;unsigned long flags; +u32 tre_iterator;spin_lock_irqsave (&lldev->lock, flags); + + tre_iterator = lldev->tre_processed_off; tre = lldev->pending_tre_list[tre_iterator /HIDMA_TRE_SIZE ];if (!tre) {spin_unlock_irqrestore (&lldev->lock, flags);
@@ -223,6 +226,9 @@ static int hidma_post_completed(struct hidma_lldev *lldev, int tre_iterator,atomic_set (&lldev->pending_tre_count,0 ); } +HIDMA_INCREMENT_ITERATOR (tre_iterator,HIDMA_TRE_SIZE , + lldev->tre_ring_size); + lldev->tre_processed_off = tre_iterator;spin_unlock_irqrestore (&lldev->lock, flags); tre->err_info = err_info;
@@ -244,13 +250,11 @@ static int hidma_post_completed(struct hidma_lldev *lldev, int tre_iterator,static int hidma_handle_tre_completion (struct hidma_lldev *lldev) {u32 evre_ring_size = lldev->evre_ring_size; -u32 tre_ring_size = lldev->tre_ring_size;u32 err_info, err_code, evre_write_off; -u32 tre_iterator, evre_iterator; +u32 evre_iterator;u32 num_completed =0 ; evre_write_off =readl_relaxed (lldev->evca +HIDMA_EVCA_WRITE_PTR_REG ); - tre_iterator = lldev->tre_processed_off; evre_iterator = lldev->evre_processed_off; if ((evre_write_off > evre_ring_size) ||
@@ -273,12 +277,9 @@ static int hidma_handle_tre_completion(struct hidma_lldev *lldev) err_code = (cfg >>HIDMA_EVRE_CODE_BIT_POS ) &HIDMA_EVRE_CODE_MASK ; -if (hidma_post_completed (lldev, tre_iterator, err_info, - err_code)) +if (hidma_post_completed (lldev, err_info, err_code))break ; -HIDMA_INCREMENT_ITERATOR (tre_iterator,HIDMA_TRE_SIZE , - tre_ring_size);HIDMA_INCREMENT_ITERATOR (evre_iterator,HIDMA_EVRE_SIZE , evre_ring_size);
@@ -295,16 +296,10 @@ static int hidma_handle_tre_completion(struct hidma_lldev *lldev)if (num_completed) {u32 evre_read_off = (lldev->evre_processed_off +HIDMA_EVRE_SIZE * num_completed); -u32 tre_read_off = (lldev->tre_processed_off + -HIDMA_TRE_SIZE * num_completed); - evre_read_off = evre_read_off % evre_ring_size; - tre_read_off = tre_read_off % tre_ring_size; -writel (evre_read_off, lldev->evca +HIDMA_EVCA_DOORBELL_REG );/* record the last processed tre offset */ - lldev->tre_processed_off = tre_read_off; lldev->evre_processed_off = evre_read_off; }
@@ -314,27 +309,10 @@ static int hidma_handle_tre_completion(struct hidma_lldev *lldev)void hidma_cleanup_pending_tre (struct hidma_lldev *lldev,u8 err_info,u8 err_code) { -u32 tre_iterator; -u32 tre_ring_size = lldev->tre_ring_size; -int num_completed =0 ; -u32 tre_read_off; - - tre_iterator = lldev->tre_processed_off;while (atomic_read (&lldev->pending_tre_count)) { -if (hidma_post_completed (lldev, tre_iterator, err_info, - err_code)) +if (hidma_post_completed (lldev, err_info, err_code))break ; -HIDMA_INCREMENT_ITERATOR (tre_iterator,HIDMA_TRE_SIZE , - tre_ring_size); - num_completed++; } - tre_read_off = (lldev->tre_processed_off + -HIDMA_TRE_SIZE * num_completed); - - tre_read_off = tre_read_off % tre_ring_size; - -/* record the last processed tre offset */ - lldev->tre_processed_off = tre_read_off; }static int hidma_ll_reset (struct hidma_lldev *lldev)
Signature · 1 line
1.9.1
PATCH v6 9/10 dmaengine: qcom_hidma: break completion processing on error
In reply to Sinan KayaWe try to consume as much successful transfers as possible. Now that we support MSI interrupts, an error interrupt might be observed by another processor while we are finishing the successful ones.
Try to abort successful processing if this is the case.
--- drivers/dma/qcom/hidma_ll.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/dma/qcom/hidma_ll.c +7 -0
@@ -291,6 +291,13 @@ static int hidma_handle_tre_completion(struct hidma_lldev *lldev) evre_write_off =readl_relaxed (lldev->evca +HIDMA_EVCA_WRITE_PTR_REG ); num_completed++; + +/* +* An error interrupt might have arrived while we are processing +* the completed interrupt. +*/ +if (!hidma_ll_isenabled (lldev)) +break ; }if (num_completed) {
Signature · 1 line
1.9.1
PATCH v6 10/10 dmaengine: qcom_hidma: add MSI support for interrupts
In reply to Sinan KayaThe interrupts can now be delivered as platform MSI interrupts on newer platforms. The code looks for a new OF and ACPI strings in order to enable the functionality.
--- drivers/dma/qcom/hidma.c | 143 ++++++++++++++++++++++++++++++++++++++++++-- drivers/dma/qcom/hidma.h | 2 + drivers/dma/qcom/hidma_ll.c | 8 +++ 3 files changed, 147 insertions(+), 6 deletions(-)
drivers/dma/qcom/hidma.c +137 -6
@@ -56,6 +56,7 @@#include <linux/irq.h> #include <linux/atomic.h> #include <linux/pm_runtime.h> +#include <linux/msi.h> #include "../dmaengine.h" #include "hidma.h"
@@ -70,6 +71,7 @@#define HIDMA_ERR_INFO_SW 0xFF#define HIDMA_ERR_CODE_UNEXPECTED_TERMINATE 0x0#define HIDMA_NR_DEFAULT_DESC 10 +#define HIDMA_MSI_INTS 11static inline struct hidma_dev *to_hidma_dev (struct dma_device *dmadev) {
@@ -553,6 +555,15 @@ static irqreturn_t hidma_chirq_handler(int chirq, void *arg)return hidma_ll_inthandler (chirq, lldev); } +static irqreturn_t hidma_chirq_handler_msi (int chirq,void *arg) +{ +struct hidma_lldev **lldevp = arg; +struct hidma_dev *dmadev =to_hidma_dev_from_lldev (lldevp); + +return hidma_ll_inthandler_msi (chirq, *lldevp, +1 << (chirq - dmadev->msi_virqbase)); +} +static ssize_t hidma_show_values (struct device *dev,struct device_attribute *attr,char *buf) {
@@ -604,6 +615,104 @@ static int hidma_sysfs_init(struct hidma_dev *dev)return device_create_file (dev->ddev.dev, dev->chid_attrs); } +#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN +static void hidma_write_msi_msg (struct msi_desc *desc,struct msi_msg *msg) +{ +struct device *dev =msi_desc_to_dev (desc); +struct hidma_dev *dmadev =dev_get_drvdata (dev); + +if (!desc->platform.msi_index) { +writel (msg->address_lo, dmadev->dev_evca +0x118 ); +writel (msg->address_hi, dmadev->dev_evca +0x11C ); +writel (msg->data, dmadev->dev_evca +0x120 ); + } +} +#endif + +static void hidma_free_msis (struct hidma_dev *dmadev) +{ +#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN +struct device *dev = dmadev->ddev.dev; +struct msi_desc *desc; + +/* free allocated MSI interrupts above */ +for_each_msi_entry (desc, dev) +devm_free_irq (dev, desc->irq, &dmadev->lldev); + +platform_msi_domain_free_irqs (dev); +#endif +} + +static int hidma_request_msi (struct hidma_dev *dmadev, +struct platform_device *pdev) +{ +#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN +int rc; +struct msi_desc *desc; +struct msi_desc *failed_desc =NULL ; + + rc =platform_msi_domain_alloc_irqs (&pdev->dev,HIDMA_MSI_INTS , + hidma_write_msi_msg); +if (rc) +return rc; + +for_each_msi_entry (desc, &pdev->dev) { +if (!desc->platform.msi_index) + dmadev->msi_virqbase = desc->irq; + + rc =devm_request_irq (&pdev->dev, desc->irq, + hidma_chirq_handler_msi, +0 ,"qcom-hidma-msi" , + &dmadev->lldev); +if (rc) { + failed_desc = desc; +break ; + } + } + +if (rc) { +/* free allocated MSI interrupts above */ +for_each_msi_entry (desc, &pdev->dev) { +if (desc == failed_desc) +break ; +devm_free_irq (&pdev->dev, desc->irq, + &dmadev->lldev); + } + }else { +/* Add callback to free MSIs on teardown */ +hidma_ll_setup_irq (dmadev->lldev, true); + + } +if (rc) +dev_warn (&pdev->dev, +"failed to request MSI irq, falling back to wired IRQ\n" ); +return rc; +#else +return -EINVAL ; +#endif +} + +static bool hidma_msi_capable (struct device *dev) +{ +struct acpi_device *adev =ACPI_COMPANION (dev); +const char *of_compat; +int ret = -EINVAL ; + +if (!adev || acpi_disabled) { + ret =device_property_read_string (dev,"compatible" , + &of_compat); +if (ret) +return false; + + ret =strcmp (of_compat,"qcom,hidma-1.1" ); + }else { +#ifdef CONFIG_ACPI + ret =strcmp (acpi_device_hid (adev),"QCOM8062" ); +#endif + } +return ret ==0 ; +} +static int hidma_probe (struct platform_device *pdev) {struct hidma_dev *dmadev;
@@ -613,6 +722,7 @@ static int hidma_probe(struct platform_device *pdev)void __iomem *evca;void __iomem *trca;int rc; +bool msi;pm_runtime_set_autosuspend_delay (&pdev->dev,HIDMA_AUTOSUSPEND_TIMEOUT );pm_runtime_use_autosuspend (&pdev->dev);
@@ -674,6 +784,12 @@ static int hidma_probe(struct platform_device *pdev) dmadev->ddev.device_terminate_all = hidma_terminate_all; dmadev->ddev.copy_align =8 ; +/* +* Determine the MSI capability of the platform. Old HW doesn't +* support MSI. +*/ + msi =hidma_msi_capable (&pdev->dev); +device_property_read_u32 (&pdev->dev,"desc-count" , &dmadev->nr_descriptors);
@@ -702,10 +818,17 @@ static int hidma_probe(struct platform_device *pdev) goto dmafree; } - rc =devm_request_irq (&pdev->dev, chirq, hidma_chirq_handler,0 , -"qcom-hidma" , dmadev->lldev); -if (rc) - goto uninit; +platform_set_drvdata (pdev, dmadev); +if (msi) + rc =hidma_request_msi (dmadev, pdev); + +if (!msi || rc) { +hidma_ll_setup_irq (dmadev->lldev, false); + rc =devm_request_irq (&pdev->dev, chirq, hidma_chirq_handler, +0 ,"qcom-hidma" , dmadev->lldev); +if (rc) + goto uninit; + }INIT_LIST_HEAD (&dmadev->ddev.channels); rc =hidma_chan_init (dmadev,0 );
@@ -721,12 +844,14 @@ static int hidma_probe(struct platform_device *pdev)hidma_debug_init (dmadev);hidma_sysfs_init (dmadev);dev_info (&pdev->dev,"HI-DMA engine driver registration complete\n" ); -platform_set_drvdata (pdev, dmadev);pm_runtime_mark_last_busy (dmadev->ddev.dev);pm_runtime_put_autosuspend (dmadev->ddev.dev);return 0 ; uninit: +if (msi) +hidma_free_msis (dmadev); +hidma_debug_uninit (dmadev);hidma_ll_uninit (dmadev->lldev); dmafree:
@@ -744,7 +869,11 @@ static int hidma_remove(struct platform_device *pdev)pm_runtime_get_sync (dmadev->ddev.dev);dma_async_device_unregister (&dmadev->ddev); -devm_free_irq (dmadev->ddev.dev, dmadev->irq, dmadev->lldev); +if (!dmadev->lldev->msi_support) +devm_free_irq (dmadev->ddev.dev, dmadev->irq, dmadev->lldev); +else +hidma_free_msis (dmadev); +tasklet_kill (&dmadev->task);hidma_sysfs_uninit (dmadev);hidma_debug_uninit (dmadev);
@@ -761,12 +890,14 @@ static int hidma_remove(struct platform_device *pdev)#if IS_ENABLED (CONFIG_ACPI )static const struct acpi_device_id hidma_acpi_ids[] = { {"QCOM8061" }, + {"QCOM8062" }, {}, };#endif static const struct of_device_id hidma_match[] = { {.compatible ="qcom,hidma-1.0" ,}, + {.compatible ="qcom,hidma-1.1" ,}, {}, };MODULE_DEVICE_TABLE (of, hidma_match);
drivers/dma/qcom/hidma.h +2 -0
@@ -115,6 +115,7 @@ struct hidma_dev {int irq;int chidx;u32 nr_descriptors; +int msi_virqbase;struct hidma_lldev *lldev;void __iomem *dev_trca;
@@ -156,6 +157,7 @@ struct hidma_lldev *hidma_ll_init(struct device *dev, u32 max_channels, u8 chidx);int hidma_ll_uninit (struct hidma_lldev *llhndl);irqreturn_t hidma_ll_inthandler (int irq,void *arg); +irqreturn_t hidma_ll_inthandler_msi (int irq,void *arg,int cause);void hidma_cleanup_pending_tre (struct hidma_lldev *llhndl,u8 err_info,u8 err_code);int hidma_debug_init (struct hidma_dev *dmadev);
drivers/dma/qcom/hidma_ll.c +8 -0
@@ -457,6 +457,14 @@ irqreturn_t hidma_ll_inthandler(int chirq, void *arg)return IRQ_HANDLED ; } +irqreturn_t hidma_ll_inthandler_msi (int chirq,void *arg,int cause) +{ +struct hidma_lldev *lldev = arg; + +hidma_ll_int_handler_internal (lldev, cause); +return IRQ_HANDLED ; +} +int hidma_ll_enable (struct hidma_lldev *lldev) {u32 val;
Signature · 1 line
1.9.1
v6 cover dmaengine: qcom_hidma: add MSI interrupt support
In reply to Sinan KayaQuoted 5 lines · Sinan Kaya
The new version of the HW supports MSI interrupts instead of wired interrupts. The MSI interrupts are especially useful for the guest machine execution. The wired interrupts usually trap to the hypervisor and then are relayed to the actual interrupt.
Quoted 7 lines
The MSI interrupts can be directly fed into the interrupt controller.
Adding a new OF compat string (qcom,hidma-1.1) and ACPI string (QCOM8062) to distinguish newer HW from the older ones.
v6:
* rebase 4.9 kernel
Why???
I already told you that I have applied 6 in the last version, please dont send me stuff which is already applied :(
Signature · 1 line
~Vinod
v6 cover dmaengine: qcom_hidma: add MSI interrupt support
Hi Vinod,
Quoted 4 lines · Vinod Koul
Quoted 2 lines
6:
Quoted 1 line
* rebase 4.9 kernel
Why???
This is more for me. There is nothing special about 4.9 that impacts hidma. It just means that I retested the code against 4.9-rc1 kernel.
Quoted 3 lines
I already told you that I have applied 6 in the last version, please dont send me stuff which is already applied :(
I couldn't find your applied branch on git yesterday. That's why, I sent you the whole thing so that you can pick the last 4 ones. You don't need to reapply the first 6. Better to have everything than missing code.
slave-dma git://git.infradead.org/users/vkoul/slave-dma.git (fetch)
slave-dma git://git.infradead.org/users/vkoul/slave-dma.git (push)
If you prefer a reduced list, please make your current changelist available on one of the branches on git, I can reapply, test and send only the remaining ones.
Sinan
Signature · 3 lines
Sinan Kaya Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.
v6 cover dmaengine: qcom_hidma: add MSI interrupt support
Quoted 15 lines · Sinan Kaya
Hi Vinod,
Quoted 4 lines · Vinod Koul
Quoted 2 lines
6:
Quoted 1 line
* rebase 4.9 kernel
Why???
This is more for me. There is nothing special about 4.9 that impacts hidma. It just means that I retested the code against 4.9-rc1 kernel.
Quoted 3 lines
I already told you that I have applied 6 in the last version, please dont send me stuff which is already applied :(
Quoted 6 lines
I couldn't find your applied branch on git yesterday. That's why, I sent you the whole thing so that you can pick the last 4 ones. You don't need to reapply the first 6. Better to have everything than missing code.
slave-dma
git://git.infradead.org/users/vkoul/slave-dma.git(fetch)
slave-dmagit://git.infradead.org/users/vkoul/slave-dma.git(push)
You seem to have missed topic/qcom which I pushed last night. next would have worked too!!
Quoted 9 lines
If you prefer a reduced list, please make your current changelist available on one of the branches on git, I can reapply, test and send only the remaining ones.
Sinan
Signature · 3 lines
Sinan Kaya Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.
Signature · 1 line
~Vinod
v6 cover dmaengine: qcom_hidma: add MSI interrupt support
Quoted 4 lines · Vinod Koul
Quoted 2 lines
slave-dma
git://git.infradead.org/users/vkoul/slave-dma.git(fetch)Quoted 1 line
slave-dma
git://git.infradead.org/users/vkoul/slave-dma.git(push)You seem to have missed topic/qcom which I pushed last night. next would have worked too!!
OK. Let me pick that up and test.
Signature · 3 lines
Sinan Kaya Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.
v6 cover dmaengine: qcom_hidma: add MSI interrupt support
Hi Vinod,
Quoted 8 lines · Sinan Kaya
Quoted 4 lines · Vinod Koul
Quoted 2 lines
slave-dma
git://git.infradead.org/users/vkoul/slave-dma.git(fetch)Quoted 1 line
slave-dma
git://git.infradead.org/users/vkoul/slave-dma.git(push)You seem to have missed topic/qcom which I pushed last night. next would have worked too!!
OK. Let me pick that up and test.
It looks like patches were applied out of order.
This is the post order
-rw-rw-r-- 1 okaya users 8176 Oct 20 17:44 0010-dmaengine-qcom_hidma-add-MSI-support-for-interrupts.patch -rw-rw-r-- 1 okaya users 1175 Oct 20 17:44 0009-dmaengine-qcom_hidma-break-completion-processing-on-.patch -rw-rw-r-- 1 okaya users 4773 Oct 20 17:44 0008-dmaengine-qcom_hidma-protect-common-data-structures.patch -rw-rw-r-- 1 okaya users 2752 Oct 20 17:44 0007-dmaengine-qcom_hidma-add-a-common-API-to-setup-the-i.patch -rw-rw-r-- 1 okaya users 3225 Oct 20 17:44 0006-dmaengine-qcom_hidma-bring-out-interrupt-cause.patch -rw-rw-r-- 1 okaya users 4284 Oct 20 17:44 0005-dmaengine-qcom_hidma-make-pending_tre_count-atomic.patch -rw-rw-r-- 1 okaya users 1090 Oct 20 17:44 0004-dmaengine-qcom_hidma-configure-DMA-and-MSI-for-OF.patch -rw-rw-r-- 1 okaya users 959 Oct 20 17:44 0003-of-irq-make-of_msi_configure-accessible-from-modules.patch -rw-rw-r-- 1 okaya users 1558 Oct 20 17:44 0002-Documentation-DT-qcom_hidma-correct-spelling-mistake.patch -rw-rw-r-- 1 okaya users 1588 Oct 20 17:44 0001-Documentation-DT-qcom_hidma-update-binding-for-MSI.patch
This is the commit order in topic/dma branch. I added <<< for the patches missing below.
<<< 0010-dmaengine-qcom_hidma-add-MSI-support-for-interrupts.patch <<< 0009-dmaengine-qcom_hidma-break-completion-processing-on-.patch
fc73796 dmaengine: qcom_hidma: break completion processing on error
<<< 0008-dmaengine-qcom_hidma-protect-common-data-structures.patch
d3eab50 dmaengine: qcom_hidma: add a common API to setup the interrupt
<<< 0006-dmaengine-qcom_hidma-bring-out-interrupt-cause.patch <<< 0005-dmaengine-qcom_hidma-make-pending_tre_count-atomic.patch
9da0be8 dmaengine: qcom_hidma: configure DMA and MSI for OF 5282c18 of: irq: make of_msi_configure accessible from modules 13af1c8 Documentation: DT: qcom_hidma: correct spelling mistakes ef6661b Documentation: DT: qcom_hidma: update binding for MSI
I also looked@the binary contents of the patches in topic/dma with what I posted on v6. They match excluding your Signed off lines.
Sinan
Signature · 3 lines
Sinan Kaya Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.
v6 cover dmaengine: qcom_hidma: add MSI interrupt support
Quoted 2 lines · Sinan Kaya
I also looked at the binary contents of the patches in topic/dma with what I posted on v6. They match excluding your Signed off lines.
Correction.
I checkout out topic/qcom not topic/dma from
git://git.infradead.org/users/vkoul/slave-dma.git
Signature · 3 lines
Sinan Kaya Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.
v6 cover dmaengine: qcom_hidma: add MSI interrupt support
In reply to Sinan KayaQuoted 5 lines · Sinan Kaya
Hi Vinod,
Quoted 2 lines · Sinan Kaya
Quoted 1 line · Vinod Koul
Quoted 1 line
slave-dma
git://git.infradead.org/users/vkoul/slave-dma.git(fetch)
Quoted 8 lines
Quoted 6 lines
Quoted 3 lines
Quoted 1 line
Quoted 1 line
slave-dma
git://git.infradead.org/users/vkoul/slave-dma.git(push)You seem to have missed topic/qcom which I pushed last night. next would have worked too!!
OK. Let me pick that up and test.
It looks like patches were applied out of order.
When applying, if I get a conflict I try to skip them. Typically subsequent patches fail, sometimes they apply. I think couple of them did in this case
It built for me, 0day also gave me success report, so unless we have bisect regression, I would like rest of the patches on top of this please..
Quoted 32 lines
(quoted diff) +0
-10-rw-rw-r-- 1 okaya users 8176 Oct 20 17:44 0010-dmaengine-qcom_hidma-add-MSI-support-for-interrupts.patch -rw-rw-r-- 1 okaya users 1175 Oct 20 17:44 0009-dmaengine-qcom_hidma-break-completion-processing-on-.patch -rw-rw-r-- 1 okaya users 4773 Oct 20 17:44 0008-dmaengine-qcom_hidma-protect-common-data-structures.patch -rw-rw-r-- 1 okaya users 2752 Oct 20 17:44 0007-dmaengine-qcom_hidma-add-a-common-API-to-setup-the-i.patch -rw-rw-r-- 1 okaya users 3225 Oct 20 17:44 0006-dmaengine-qcom_hidma-bring-out-interrupt-cause.patch -rw-rw-r-- 1 okaya users 4284 Oct 20 17:44 0005-dmaengine-qcom_hidma-make-pending_tre_count-atomic.patch -rw-rw-r-- 1 okaya users 1090 Oct 20 17:44 0004-dmaengine-qcom_hidma-configure-DMA-and-MSI-for-OF.patch -rw-rw-r-- 1 okaya users 959 Oct 20 17:44 0003-of-irq-make-of_msi_configure-accessible-from-modules.patch -rw-rw-r-- 1 okaya users 1558 Oct 20 17:44 0002-Documentation-DT-qcom_hidma-correct-spelling-mistake.patch -rw-rw-r-- 1 okaya users 1588 Oct 20 17:44 0001-Documentation-DT-qcom_hidma-update-binding-for-MSI.patchThis is the commit order in topic/dma branch. I added <<< for the patches missing below.
<<< 0010-dmaengine-qcom_hidma-add-MSI-support-for-interrupts.patch <<< 0009-dmaengine-qcom_hidma-break-completion-processing-on-.patch
fc73796 dmaengine:
qcom_hidma: break completion processing on error<<< 0008-dmaengine-qcom_hidma-protect-common-data-structures.patch
d3eab50 dmaengine:
qcom_hidma: add a common API to setup the interrupt<<< 0006-dmaengine-qcom_hidma-bring-out-interrupt-cause.patch <<< 0005-dmaengine-qcom_hidma-make-pending_tre_count-atomic.patch
9da0be8 dmaengine:
qcom_hidma: configure DMA and MSI for OF 5282c18 of: irq: makeof_msi_configureaccessible from modules 13af1c8 Documentation: DT:qcom_hidma: correct spelling mistakes ef6661b Documentation: DT:qcom_hidma: update binding for MSII also looked at the binary contents of the patches in topic/dma with what I posted on v6. They match excluding your Signed off lines.
Signature · 1 line
~Vinod
v6 cover dmaengine: qcom_hidma: add MSI interrupt support
Quoted 7 lines · Vinod Koul
Quoted 1 line
It looks like patches were applied out of order.
When applying, if I get a conflict I try to skip them. Typically subsequent patches fail, sometimes they apply. I think couple of them did in this case
It built for me, 0day also gave me success report, so unless we have bisect regression, I would like rest of the patches on top of this please..
OK. Let me work on it.
Signature · 3 lines
Sinan Kaya Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.