Author: gber
Date: Fri Sep 14 10:05:01 2012
New Revision: 240492
URL: http://svn.freebsd.org/changeset/base/240492

Log:
  Add support for MSI in interrupt controlller.
  
  MSI are implemented via software interrupt. PCIe cards will write
  into software interrupt register which will cause inbound shared
  interrupt which will be interpreted as a MSI.
  
  Obtained from:        Marvell, Semihalf

Modified:
  head/sys/arm/include/intr.h
  head/sys/arm/mv/mpic.c
  head/sys/arm/mv/mvvar.h
  head/sys/boot/fdt/dts/db78460.dts

Modified: head/sys/arm/include/intr.h
==============================================================================
--- head/sys/arm/include/intr.h Fri Sep 14 10:01:52 2012        (r240491)
+++ head/sys/arm/include/intr.h Fri Sep 14 10:05:01 2012        (r240492)
@@ -55,7 +55,12 @@
 #elif defined(CPU_ARM11)
 #define NIRQ           128
 #elif defined(SOC_MV_ARMADAXP)
-#define NIRQ           148
+#define MAIN_IRQ_NUM           116
+#define ERR_IRQ_NUM            32
+#define ERR_IRQ                        (MAIN_IRQ_NUM)
+#define MSI_IRQ_NUM            32
+#define MSI_IRQ                        (ERR_IRQ + ERR_IRQ_NUM)
+#define NIRQ                   (MAIN_IRQ_NUM + ERR_IRQ_NUM + MSI_IRQ_NUM)
 #else
 #define NIRQ           32
 #endif

Modified: head/sys/arm/mv/mpic.c
==============================================================================
--- head/sys/arm/mv/mpic.c      Fri Sep 14 10:01:52 2012        (r240491)
+++ head/sys/arm/mv/mpic.c      Fri Sep 14 10:05:01 2012        (r240492)
@@ -1,6 +1,7 @@
 /*-
  * Copyright (c) 2006 Benno Rice.
  * Copyright (C) 2007-2011 MARVELL INTERNATIONAL LTD.
+ * Copyright (c) 2012 Semihalf.
  * All rights reserved.
  *
  * Developed by Semihalf.
@@ -46,23 +47,34 @@ __FBSDID("$FreeBSD$");
 #include <machine/cpufunc.h>
 #include <machine/smp.h>
 
+#include <arm/mv/mvvar.h>
+
 #include <dev/ofw/ofw_bus.h>
 #include <dev/ofw/ofw_bus_subr.h>
+#include <dev/fdt/fdt_common.h>
+
+#ifdef DEBUG
+#define debugf(fmt, args...) do { printf("%s(): ", __func__);  \
+    printf(fmt,##args); } while (0)
+#else
+#define debugf(fmt, args...)
+#endif
 
-#define IRQ_ERR                        4
-#define MAIN_IRQS              116
+#define MPIC_INT_ERR                   4
+#define MPIC_INT_MSI                   96
 
 #define IRQ_MASK               0x3ff
 
 #define MPIC_CTRL              0x0
 #define MPIC_SOFT_INT          0x4
+#define MPIC_SOFT_INT_DRBL1    (1 << 5)
 #define MPIC_ERR_CAUSE         0x20
 #define MPIC_ISE               0x30
 #define MPIC_ICE               0x34
 
 
-#define MPIC_IN_DOORBELL       0x78
-#define MPIC_IN_DOORBELL_MASK  0x7c
+#define MPIC_IN_DRBL           0x78
+#define MPIC_IN_DRBL_MASK      0x7c
 #define MPIC_CTP               0xb0
 #define MPIC_CTP               0xb0
 #define MPIC_IIACK             0xb4
@@ -71,16 +83,20 @@ __FBSDID("$FreeBSD$");
 #define MPIC_ERR_MASK          0xec0
 
 struct mv_mpic_softc {
-       struct resource *       mpic_res[2];
+       device_t                sc_dev;
+       struct resource *       mpic_res[3];
        bus_space_tag_t         mpic_bst;
        bus_space_handle_t      mpic_bsh;
        bus_space_tag_t         cpu_bst;
        bus_space_handle_t      cpu_bsh;
+       bus_space_tag_t         drbl_bst;
+       bus_space_handle_t      drbl_bsh;
 };
 
 static struct resource_spec mv_mpic_spec[] = {
        { SYS_RES_MEMORY,       0,      RF_ACTIVE },
        { SYS_RES_MEMORY,       1,      RF_ACTIVE },
+       { SYS_RES_MEMORY,       2,      RF_ACTIVE },
        { -1, 0 }
 };
 
@@ -92,14 +108,21 @@ static int mv_mpic_probe(device_t);
 static int     mv_mpic_attach(device_t);
 uint32_t       mv_mpic_get_cause(void);
 uint32_t       mv_mpic_get_cause_err(void);
+uint32_t       mv_mpic_get_msi(void);
 static void    arm_mask_irq_err(uintptr_t);
 static void    arm_unmask_irq_err(uintptr_t);
+static void    arm_unmask_msi(void);
 
 #define MPIC_CPU_WRITE(softc, reg, val) \
     bus_space_write_4((softc)->cpu_bst, (softc)->cpu_bsh, (reg), (val))
 #define MPIC_CPU_READ(softc, reg) \
     bus_space_read_4((softc)->cpu_bst, (softc)->cpu_bsh, (reg))
 
+#define MPIC_DRBL_WRITE(softc, reg, val) \
+    bus_space_write_4((softc)->drbl_bst, (softc)->drbl_bsh, (reg), (val))
+#define MPIC_DRBL_READ(softc, reg) \
+    bus_space_read_4((softc)->drbl_bst, (softc)->drbl_bsh, (reg))
+
 static int
 mv_mpic_probe(device_t dev)
 {
@@ -123,6 +146,8 @@ mv_mpic_attach(device_t dev)
                return (ENXIO);
        mv_mpic_sc = sc;
 
+       sc->sc_dev = dev;
+
        error = bus_alloc_resources(dev, mv_mpic_spec, sc->mpic_res);
        if (error) {
                device_printf(dev, "could not allocate resources\n");
@@ -135,10 +160,15 @@ mv_mpic_attach(device_t dev)
        sc->cpu_bst = rman_get_bustag(sc->mpic_res[1]);
        sc->cpu_bsh = rman_get_bushandle(sc->mpic_res[1]);
 
+       sc->drbl_bst = rman_get_bustag(sc->mpic_res[2]);
+       sc->drbl_bsh = rman_get_bushandle(sc->mpic_res[2]);
+
        bus_space_write_4(mv_mpic_sc->mpic_bst, mv_mpic_sc->mpic_bsh,
            MPIC_CTRL, 1);
        MPIC_CPU_WRITE(mv_mpic_sc, MPIC_CTP, 0);
 
+       arm_unmask_msi();
+
        return (0);
 }
 
@@ -167,8 +197,10 @@ arm_get_next_irq(int last)
        CTR2(KTR_INTR, "%s: irq:%#x", __func__, irq);
 
        if (irq != IRQ_MASK) {
-               if (irq == IRQ_ERR)
+               if (irq == MPIC_INT_ERR)
                        irq = mv_mpic_get_cause_err();
+               if (irq == MPIC_INT_MSI)
+                       irq = mv_mpic_get_msi();
                next = irq;
        }
 
@@ -186,11 +218,11 @@ arm_mask_irq(uintptr_t nb)
 
        MPIC_CPU_WRITE(mv_mpic_sc, MPIC_CTP, 1);
 
-       if (nb < MAIN_IRQS) {
+       if (nb < ERR_IRQ) {
                bus_space_write_4(mv_mpic_sc->mpic_bst, mv_mpic_sc->mpic_bsh,
                    MPIC_ICE, nb);
                MPIC_CPU_WRITE(mv_mpic_sc, MPIC_ISM, nb);
-       } else
+       } else if (nb < MSI_IRQ)
                arm_mask_irq_err(nb);
 }
 
@@ -201,7 +233,7 @@ arm_mask_irq_err(uintptr_t nb)
        uint32_t mask;
        uint8_t bit_off;
 
-       bit_off = nb - MAIN_IRQS;
+       bit_off = nb - ERR_IRQ;
        mask = MPIC_CPU_READ(mv_mpic_sc, MPIC_ERR_MASK);
        mask &= ~(1 << bit_off);
        MPIC_CPU_WRITE(mv_mpic_sc, MPIC_ERR_MASK, mask);
@@ -213,15 +245,15 @@ arm_unmask_irq(uintptr_t nb)
 
        MPIC_CPU_WRITE(mv_mpic_sc, MPIC_CTP, 0);
 
-       if (nb < MAIN_IRQS) {
+       if (nb < ERR_IRQ) {
                bus_space_write_4(mv_mpic_sc->mpic_bst, mv_mpic_sc->mpic_bsh,
                    MPIC_ISE, nb);
                MPIC_CPU_WRITE(mv_mpic_sc, MPIC_ICM, nb);
-       } else
+       } else if (nb < MSI_IRQ)
                arm_unmask_irq_err(nb);
 
        if (nb == 0)
-               MPIC_CPU_WRITE(mv_mpic_sc, MPIC_IN_DOORBELL_MASK, 0xffffffff);
+               MPIC_CPU_WRITE(mv_mpic_sc, MPIC_IN_DRBL_MASK, 0xffffffff);
 }
 
 void
@@ -231,15 +263,22 @@ arm_unmask_irq_err(uintptr_t nb)
        uint8_t bit_off;
 
        bus_space_write_4(mv_mpic_sc->mpic_bst, mv_mpic_sc->mpic_bsh,
-           MPIC_ISE, IRQ_ERR);
-       MPIC_CPU_WRITE(mv_mpic_sc, MPIC_ICM, IRQ_ERR);
+           MPIC_ISE, MPIC_INT_ERR);
+       MPIC_CPU_WRITE(mv_mpic_sc, MPIC_ICM, MPIC_INT_ERR);
 
-       bit_off = nb - MAIN_IRQS;
+       bit_off = nb - ERR_IRQ;
        mask = MPIC_CPU_READ(mv_mpic_sc, MPIC_ERR_MASK);
        mask |= (1 << bit_off);
        MPIC_CPU_WRITE(mv_mpic_sc, MPIC_ERR_MASK, mask);
 }
 
+static void
+arm_unmask_msi(void)
+{
+
+       arm_unmask_irq(MPIC_INT_MSI);
+}
+
 uint32_t
 mv_mpic_get_cause(void)
 {
@@ -260,7 +299,61 @@ mv_mpic_get_cause_err(void)
                bit_off = ffs(err_cause) - 1;
        else
                return (-1);
-       return (MAIN_IRQS + bit_off);
+
+       debugf("%s: irq:%x cause:%x\n", __func__, bit_off, err_cause);
+       return (ERR_IRQ + bit_off);
+}
+
+uint32_t
+mv_mpic_get_msi(void)
+{
+       uint32_t cause;
+       uint8_t bit_off;
+
+       cause = MPIC_DRBL_READ(mv_mpic_sc, 0);
+
+       if (cause)
+               bit_off = ffs(cause) - 1;
+       else
+               return (-1);
+
+       debugf("%s: irq:%x cause:%x\n", __func__, bit_off, cause);
+
+       cause &= ~(1 << bit_off);
+       MPIC_DRBL_WRITE(mv_mpic_sc, 0, cause);
+
+       return (MSI_IRQ + bit_off);
+}
+
+int
+mv_msi_data(int irq, uint64_t *addr, uint32_t *data)
+{
+       u_long phys, base, size;
+       phandle_t node;
+       int error;
+
+       node = ofw_bus_get_node(mv_mpic_sc->sc_dev);
+
+       /* Get physical addres of register space */
+       error = fdt_get_range(OF_parent(node), 0, &phys, &size);
+       if (error) {
+               printf("%s: Cannot get register physical address, err:%d",
+                   __func__, error);
+               return (error);
+       }
+
+       /* Get offset of MPIC register space */
+       error = fdt_regsize(node, &base, &size);
+       if (error) {
+               printf("%s: Cannot get MPIC register offset, err:%d",
+                   __func__, error);
+               return (error);
+       }
+
+       *addr = phys + base + MPIC_SOFT_INT;
+       *data = MPIC_SOFT_INT_DRBL1 | irq;
+
+       return (0);
 }
 
 #if defined(SMP)
@@ -283,7 +376,7 @@ pic_ipi_get(int i __unused)
 {
        uint32_t val;
 
-       val = MPIC_CPU_READ(mv_mpic_sc, MPIC_IN_DOORBELL);
+       val = MPIC_CPU_READ(mv_mpic_sc, MPIC_IN_DRBL);
        if (val)
                return (ffs(val) - 1);
 
@@ -296,7 +389,7 @@ pic_ipi_clear(int ipi)
        uint32_t val;
 
        val = ~(1 << ipi);
-       MPIC_CPU_WRITE(mv_mpic_sc, MPIC_IN_DOORBELL, val);
+       MPIC_CPU_WRITE(mv_mpic_sc, MPIC_IN_DRBL, val);
 }
 
 #endif

Modified: head/sys/arm/mv/mvvar.h
==============================================================================
--- head/sys/arm/mv/mvvar.h     Fri Sep 14 10:01:52 2012        (r240491)
+++ head/sys/arm/mv/mvvar.h     Fri Sep 14 10:05:01 2012        (r240492)
@@ -134,4 +134,6 @@ uint32_t mv_drbl_get_cause(int dir, int 
 void   mv_drbl_set_msg(uint32_t val, int mnr, int dir, int unit);
 uint32_t mv_drbl_get_msg(int mnr, int dir, int unit);
 
+int    mv_msi_data(int irq, uint64_t *addr, uint32_t *data);
+
 #endif /* _MVVAR_H_ */

Modified: head/sys/boot/fdt/dts/db78460.dts
==============================================================================
--- head/sys/boot/fdt/dts/db78460.dts   Fri Sep 14 10:01:52 2012        
(r240491)
+++ head/sys/boot/fdt/dts/db78460.dts   Fri Sep 14 10:05:01 2012        
(r240492)
@@ -75,7 +75,7 @@
                        interrupt-controller;
                        #address-cells = <0>;
                        #interrupt-cells = <1>;
-                       reg = <0x20a00 0x500 0x21000 0x800>;
+                       reg = <0x20a00 0x500 0x21000 0x800 0x20400 0x100>;
                        compatible = "mrvl,mpic";
                };
 
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to