66 */
77
88#include <linux/arm-smccc.h>
9+ #include <linux/cpuhotplug.h>
910#include <linux/delay.h>
1011#include <linux/device.h>
1112#include <linux/interrupt.h>
13+ #include <linux/irqdomain.h>
1214#include <linux/io.h>
1315#include <linux/kernel.h>
1416#include <linux/mailbox_controller.h>
1517#include <linux/mailbox/zynqmp-ipi-message.h>
1618#include <linux/module.h>
1719#include <linux/of.h>
1820#include <linux/of_address.h>
21+ #include <linux/of_irq.h>
1922#include <linux/platform_device.h>
2023
2124/* IPI agent ID any */
5962#define DST_BIT_POS 9U
6063#define SRC_BITMASK GENMASK(11, 8)
6164
65+ #define MAX_SGI 16
66+
6267/**
6368 * struct zynqmp_ipi_mchan - Description of a Xilinx ZynqMP IPI mailbox channel
6469 * @is_opened: indicate if the IPI channel is opened
@@ -111,6 +116,7 @@ struct zynqmp_ipi_mbox {
111116 * @irq: IPI agent interrupt ID
112117 * @method: IPI SMC or HVC is going to be used
113118 * @local_id: local IPI agent ID
119+ * @virq_sgi: IRQ number mapped to SGI
114120 * @num_mboxes: number of mailboxes of this IPI agent
115121 * @ipi_mboxes: IPI mailboxes of this IPI agent
116122 */
@@ -119,10 +125,13 @@ struct zynqmp_ipi_pdata {
119125 int irq ;
120126 unsigned int method ;
121127 u32 local_id ;
128+ int virq_sgi ;
122129 int num_mboxes ;
123130 struct zynqmp_ipi_mbox ipi_mboxes [] __counted_by (num_mboxes );
124131};
125132
133+ static DEFINE_PER_CPU (struct zynqmp_ipi_pdata * , per_cpu_pdata ) ;
134+
126135static struct device_driver zynqmp_ipi_mbox_driver = {
127136 .owner = THIS_MODULE ,
128137 .name = "zynqmp-ipi-mbox" ,
@@ -189,6 +198,14 @@ static irqreturn_t zynqmp_ipi_interrupt(int irq, void *data)
189198 return status ;
190199}
191200
201+ static irqreturn_t zynqmp_sgi_interrupt (int irq , void * data )
202+ {
203+ struct zynqmp_ipi_pdata * * pdata_ptr = data ;
204+ struct zynqmp_ipi_pdata * pdata = * pdata_ptr ;
205+
206+ return zynqmp_ipi_interrupt (irq , pdata );
207+ }
208+
192209/**
193210 * zynqmp_ipi_peek_data - Peek to see if there are any rx messages.
194211 *
@@ -748,6 +765,112 @@ static int versal_ipi_setup(struct zynqmp_ipi_mbox *ipi_mbox,
748765 return 0 ;
749766}
750767
768+ static int xlnx_mbox_cpuhp_start (unsigned int cpu )
769+ {
770+ struct zynqmp_ipi_pdata * pdata ;
771+
772+ pdata = get_cpu_var (per_cpu_pdata );
773+ put_cpu_var (per_cpu_pdata );
774+ enable_percpu_irq (pdata -> virq_sgi , IRQ_TYPE_NONE );
775+
776+ return 0 ;
777+ }
778+
779+ static int xlnx_mbox_cpuhp_down (unsigned int cpu )
780+ {
781+ struct zynqmp_ipi_pdata * pdata ;
782+
783+ pdata = get_cpu_var (per_cpu_pdata );
784+ put_cpu_var (per_cpu_pdata );
785+ disable_percpu_irq (pdata -> virq_sgi );
786+
787+ return 0 ;
788+ }
789+
790+ static void xlnx_disable_percpu_irq (void * data )
791+ {
792+ struct zynqmp_ipi_pdata * pdata ;
793+
794+ pdata = * this_cpu_ptr (& per_cpu_pdata );
795+
796+ disable_percpu_irq (pdata -> virq_sgi );
797+ }
798+
799+ static int xlnx_mbox_init_sgi (struct platform_device * pdev ,
800+ int sgi_num ,
801+ struct zynqmp_ipi_pdata * pdata )
802+ {
803+ int ret = 0 ;
804+ int cpu ;
805+
806+ /*
807+ * IRQ related structures are used for the following:
808+ * for each SGI interrupt ensure its mapped by GIC IRQ domain
809+ * and that each corresponding linux IRQ for the HW IRQ has
810+ * a handler for when receiving an interrupt from the remote
811+ * processor.
812+ */
813+ struct irq_domain * domain ;
814+ struct irq_fwspec sgi_fwspec ;
815+ struct device_node * interrupt_parent = NULL ;
816+ struct device * dev = & pdev -> dev ;
817+
818+ /* Find GIC controller to map SGIs. */
819+ interrupt_parent = of_irq_find_parent (dev -> of_node );
820+ if (!interrupt_parent ) {
821+ dev_err (& pdev -> dev , "Failed to find property for Interrupt parent\n" );
822+ return - EINVAL ;
823+ }
824+
825+ /* Each SGI needs to be associated with GIC's IRQ domain. */
826+ domain = irq_find_host (interrupt_parent );
827+ of_node_put (interrupt_parent );
828+
829+ /* Each mapping needs GIC domain when finding IRQ mapping. */
830+ sgi_fwspec .fwnode = domain -> fwnode ;
831+
832+ /*
833+ * When irq domain looks at mapping each arg is as follows:
834+ * 3 args for: interrupt type (SGI), interrupt # (set later), type
835+ */
836+ sgi_fwspec .param_count = 1 ;
837+
838+ /* Set SGI's hwirq */
839+ sgi_fwspec .param [0 ] = sgi_num ;
840+ pdata -> virq_sgi = irq_create_fwspec_mapping (& sgi_fwspec );
841+
842+ for_each_possible_cpu (cpu )
843+ per_cpu (per_cpu_pdata , cpu ) = pdata ;
844+
845+ ret = request_percpu_irq (pdata -> virq_sgi , zynqmp_sgi_interrupt , pdev -> name ,
846+ & per_cpu_pdata );
847+ WARN_ON (ret );
848+ if (ret ) {
849+ irq_dispose_mapping (pdata -> virq_sgi );
850+ return ret ;
851+ }
852+
853+ irq_to_desc (pdata -> virq_sgi );
854+ irq_set_status_flags (pdata -> virq_sgi , IRQ_PER_CPU );
855+
856+ /* Setup function for the CPU hot-plug cases */
857+ cpuhp_setup_state (CPUHP_AP_ONLINE_DYN , "mailbox/sgi:starting" ,
858+ xlnx_mbox_cpuhp_start , xlnx_mbox_cpuhp_down );
859+
860+ return ret ;
861+ }
862+
863+ static void xlnx_mbox_cleanup_sgi (struct zynqmp_ipi_pdata * pdata )
864+ {
865+ cpuhp_remove_state (CPUHP_AP_ONLINE_DYN );
866+
867+ on_each_cpu (xlnx_disable_percpu_irq , NULL , 1 );
868+
869+ irq_clear_status_flags (pdata -> virq_sgi , IRQ_PER_CPU );
870+ free_percpu_irq (pdata -> virq_sgi , & per_cpu_pdata );
871+ irq_dispose_mapping (pdata -> virq_sgi );
872+ }
873+
751874/**
752875 * zynqmp_ipi_free_mboxes - Free IPI mailboxes devices
753876 *
@@ -758,6 +881,9 @@ static void zynqmp_ipi_free_mboxes(struct zynqmp_ipi_pdata *pdata)
758881 struct zynqmp_ipi_mbox * ipi_mbox ;
759882 int i ;
760883
884+ if (pdata -> irq < MAX_SGI )
885+ xlnx_mbox_cleanup_sgi (pdata );
886+
761887 i = pdata -> num_mboxes ;
762888 for (; i >= 0 ; i -- ) {
763889 ipi_mbox = & pdata -> ipi_mboxes [i ];
@@ -773,7 +899,8 @@ static int zynqmp_ipi_probe(struct platform_device *pdev)
773899{
774900 struct device * dev = & pdev -> dev ;
775901 struct device_node * nc , * np = pdev -> dev .of_node ;
776- struct zynqmp_ipi_pdata * pdata ;
902+ struct zynqmp_ipi_pdata __percpu * pdata ;
903+ struct of_phandle_args out_irq ;
777904 struct zynqmp_ipi_mbox * mbox ;
778905 int num_mboxes , ret = - EINVAL ;
779906 setup_ipi_fn ipi_fn ;
@@ -821,14 +948,32 @@ static int zynqmp_ipi_probe(struct platform_device *pdev)
821948 mbox ++ ;
822949 }
823950
824- /* IPI IRQ */
825- ret = platform_get_irq ( pdev , 0 );
826- if ( ret < 0 )
951+ ret = of_irq_parse_one ( dev_of_node ( dev ), 0 , & out_irq );
952+ if ( ret < 0 ) {
953+ dev_err ( dev , "failed to parse interrupts\n" );
827954 goto free_mbox_dev ;
955+ }
956+ ret = out_irq .args [1 ];
957+
958+ /*
959+ * If Interrupt number is in SGI range, then request SGI else request
960+ * IPI system IRQ.
961+ */
962+ if (ret < MAX_SGI ) {
963+ pdata -> irq = ret ;
964+ ret = xlnx_mbox_init_sgi (pdev , pdata -> irq , pdata );
965+ if (ret )
966+ goto free_mbox_dev ;
967+ } else {
968+ ret = platform_get_irq (pdev , 0 );
969+ if (ret < 0 )
970+ goto free_mbox_dev ;
971+
972+ pdata -> irq = ret ;
973+ ret = devm_request_irq (dev , pdata -> irq , zynqmp_ipi_interrupt ,
974+ IRQF_SHARED , dev_name (dev ), pdata );
975+ }
828976
829- pdata -> irq = ret ;
830- ret = devm_request_irq (dev , pdata -> irq , zynqmp_ipi_interrupt ,
831- IRQF_SHARED , dev_name (dev ), pdata );
832977 if (ret ) {
833978 dev_err (dev , "IRQ %d is not requested successfully.\n" ,
834979 pdata -> irq );
0 commit comments