Author: zbb
Date: Thu Feb 11 11:58:27 2016
New Revision: 295515
URL: https://svnweb.freebsd.org/changeset/base/295515

Log:
  Introduce bus_bind_intr method for ARM64
  
  It can be used to bind specific interrupt to a particular CPU.
  Requires PIC support for interrupts binding.
  
  Reviewed by:   wma
  Obtained from: Semihalf
  Sponsored by:  Cavium
  Differential Revision: https://reviews.freebsd.org/D5122

Modified:
  head/sys/arm64/arm64/intr_machdep.c
  head/sys/arm64/arm64/nexus.c
  head/sys/arm64/arm64/pic_if.m
  head/sys/arm64/include/intr.h

Modified: head/sys/arm64/arm64/intr_machdep.c
==============================================================================
--- head/sys/arm64/arm64/intr_machdep.c Thu Feb 11 11:57:13 2016        
(r295514)
+++ head/sys/arm64/arm64/intr_machdep.c Thu Feb 11 11:58:27 2016        
(r295515)
@@ -38,6 +38,7 @@
 __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
+#include <sys/proc.h>
 #include <sys/systm.h>
 #include <sys/bus.h>
 #include <sys/kernel.h>
@@ -84,6 +85,7 @@ struct arm64_intr_entry {
        u_int                   i_hw_irq;       /* Physical interrupt number */
        u_int                   i_cntidx;       /* Index in intrcnt table */
        u_int                   i_handlers;     /* Allocated handlers */
+       u_int                   i_cpu;          /* Assigned CPU */
        u_long                  *i_cntp;        /* Interrupt hit counter */
 };
 
@@ -162,6 +164,8 @@ intr_allocate(u_int hw_irq)
        if (intr == NULL)
                return (NULL);
 
+       /* The default CPU is 0 but can be changed later by bind or shuffle */
+       intr->i_cpu = 0;
        intr->i_event = NULL;
        intr->i_handlers = 0;
        intr->i_trig = INTR_TRIGGER_CONFORM;
@@ -176,6 +180,44 @@ intr_allocate(u_int hw_irq)
        return intr;
 }
 
+static int
+intr_assign_cpu(void *arg, int cpu)
+{
+#ifdef SMP
+       struct arm64_intr_entry *intr;
+       int error;
+
+       if (root_pic == NULL)
+               panic("Cannot assing interrupt to CPU. No PIC configured");
+       /*
+        * Set the interrupt to CPU affinity.
+        * Do not configure this in hardware during early boot.
+        * We will pick up the assignment once the APs are started.
+        */
+       if (cpu != NOCPU) {
+               intr = arg;
+               if (!cold && smp_started) {
+                       /*
+                        * Bind the interrupt immediately
+                        * if SMP is up and running.
+                        */
+                       error = PIC_BIND(root_pic, intr->i_hw_irq, cpu);
+                       if (error == 0)
+                               intr->i_cpu = cpu;
+               } else {
+                       /* Postpone binding until SMP is operational */
+                       intr->i_cpu = cpu;
+                       error = 0;
+               }
+       } else
+               error = 0;
+
+       return (error);
+#else
+       return (EOPNOTSUPP);
+#endif
+}
+
 static void
 intr_pre_ithread(void *arg)
 {
@@ -339,7 +381,7 @@ arm_setup_intr(const char *name, driver_
        if (intr->i_event == NULL) {
                error = intr_event_create(&intr->i_event, (void *)intr, 0,
                    hw_irq, intr_pre_ithread, intr_post_ithread,
-                   intr_post_filter, NULL, "irq%u", hw_irq);
+                   intr_post_filter, intr_assign_cpu, "irq%u", hw_irq);
                if (error)
                        return (error);
        }
@@ -447,6 +489,42 @@ arm_cpu_intr(struct trapframe *tf)
 }
 
 #ifdef SMP
+static void
+arm_intr_smp_init(void *dummy __unused)
+{
+       struct arm64_intr_entry *intr;
+       int error;
+
+       if (root_pic == NULL)
+               panic("Cannot assing interrupts to CPUs. No PIC configured");
+
+       mtx_lock_spin(&intr_list_lock);
+       SLIST_FOREACH(intr, &irq_slist_head, entries) {
+               mtx_unlock_spin(&intr_list_lock);
+               error = PIC_BIND(root_pic, intr->i_hw_irq, intr->i_cpu);
+               if (error != 0)
+                       intr->i_cpu = 0;
+               mtx_lock_spin(&intr_list_lock);
+       }
+       mtx_unlock_spin(&intr_list_lock);
+}
+SYSINIT(arm_intr_smp_init, SI_SUB_SMP, SI_ORDER_ANY, arm_intr_smp_init, NULL);
+
+/* Attempt to bind the specified IRQ to the specified CPU. */
+int
+arm_intr_bind(u_int hw_irq, int cpu)
+{
+       struct arm64_intr_entry *intr;
+
+       mtx_lock_spin(&intr_list_lock);
+       intr = intr_lookup_locked(hw_irq);
+       mtx_unlock_spin(&intr_list_lock);
+       if (intr == NULL)
+               return (EINVAL);
+
+       return (intr_event_bind(intr->i_event, cpu));
+}
+
 void
 arm_setup_ipihandler(driver_filter_t *filt, u_int ipi)
 {

Modified: head/sys/arm64/arm64/nexus.c
==============================================================================
--- head/sys/arm64/arm64/nexus.c        Thu Feb 11 11:57:13 2016        
(r295514)
+++ head/sys/arm64/arm64/nexus.c        Thu Feb 11 11:58:27 2016        
(r295515)
@@ -113,6 +113,9 @@ static      int nexus_deactivate_resource(dev
 static int nexus_setup_intr(device_t dev, device_t child, struct resource *res,
     int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg, void 
**cookiep);
 static int nexus_teardown_intr(device_t, device_t, struct resource *, void *);
+#ifdef SMP
+static int nexus_bind_intr(device_t, device_t, struct resource *, int);
+#endif
 
 #ifdef FDT
 static int nexus_ofw_map_intr(device_t dev, device_t child, phandle_t iparent,
@@ -131,7 +134,9 @@ static device_method_t nexus_methods[] =
        DEVMETHOD(bus_deactivate_resource,      nexus_deactivate_resource),
        DEVMETHOD(bus_setup_intr,       nexus_setup_intr),
        DEVMETHOD(bus_teardown_intr,    nexus_teardown_intr),
-
+#ifdef SMP
+       DEVMETHOD(bus_bind_intr,        nexus_bind_intr),
+#endif
        { 0, 0 }
 };
 
@@ -293,6 +298,15 @@ nexus_teardown_intr(device_t dev, device
        return (arm_teardown_intr(ih));
 }
 
+#ifdef SMP
+static int
+nexus_bind_intr(device_t dev, device_t child, struct resource *irq, int cpu)
+{
+
+       return (arm_intr_bind(rman_get_start(irq), cpu));
+}
+#endif
+
 static int
 nexus_activate_resource(device_t bus, device_t child, int type, int rid,
     struct resource *r)

Modified: head/sys/arm64/arm64/pic_if.m
==============================================================================
--- head/sys/arm64/arm64/pic_if.m       Thu Feb 11 11:57:13 2016        
(r295514)
+++ head/sys/arm64/arm64/pic_if.m       Thu Feb 11 11:58:27 2016        
(r295515)
@@ -34,7 +34,11 @@
 INTERFACE pic;
 
 CODE {
-       static pic_translate_code_t pic_translate_code_default;
+       static int pic_bind_default(device_t dev, u_int irq, u_int cpu)
+       {
+
+               return (EOPNOTSUPP);
+       }
 
        static void pic_translate_code_default(device_t dev, u_int irq,
            int code, enum intr_trigger *trig, enum intr_polarity *pol)
@@ -60,11 +64,11 @@ CODE {
        }
 };
 
-METHOD void bind {
+METHOD int bind {
        device_t        dev;
        u_int           irq;
-       cpuset_t        cpumask;
-};
+       u_int           cpu;
+} DEFAULT pic_bind_default;
 
 METHOD void translate_code {
        device_t        dev;

Modified: head/sys/arm64/include/intr.h
==============================================================================
--- head/sys/arm64/include/intr.h       Thu Feb 11 11:57:13 2016        
(r295514)
+++ head/sys/arm64/include/intr.h       Thu Feb 11 11:58:27 2016        
(r295515)
@@ -49,6 +49,7 @@ void  arm_unmask_irq(u_int);
 
 #ifdef SMP
 void   arm_init_secondary(void);
+int    arm_intr_bind(u_int, int);
 void   arm_setup_ipihandler(driver_filter_t *, u_int);
 void   arm_unmask_ipi(u_int);
 #endif
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to