summaryrefslogtreecommitdiff
path: root/sys/arch/sparc64
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2011-07-06 05:48:58 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2011-07-06 05:48:58 +0000
commit2983bcf429439931d4a9b7cab7a51b5206f78216 (patch)
treed8351dca74c604a7dc0ff21d5e5a9da61c6173a6 /sys/arch/sparc64
parentc3a60f6a2203e487a9cab88ae4892126da058e8f (diff)
Add MSI support to pyro(4). Tested on a v215 with the on-board mpi(4).
Diffstat (limited to 'sys/arch/sparc64')
-rw-r--r--sys/arch/sparc64/conf/files.sparc644
-rw-r--r--sys/arch/sparc64/dev/pyro.c184
-rw-r--r--sys/arch/sparc64/dev/pyrovar.h17
3 files changed, 198 insertions, 7 deletions
diff --git a/sys/arch/sparc64/conf/files.sparc64 b/sys/arch/sparc64/conf/files.sparc64
index 07cb5dcf5b0..76a1b8eeab2 100644
--- a/sys/arch/sparc64/conf/files.sparc64
+++ b/sys/arch/sparc64/conf/files.sparc64
@@ -1,4 +1,4 @@
-# $OpenBSD: files.sparc64,v 1.133 2011/07/06 05:35:53 kettenis Exp $
+# $OpenBSD: files.sparc64,v 1.134 2011/07/06 05:48:57 kettenis Exp $
# $NetBSD: files.sparc64,v 1.50 2001/08/10 20:53:50 eeh Exp $
# maxpartitions must be first item in files.${ARCH}
@@ -119,7 +119,7 @@ device schizo: pcibus, iommu
attach schizo at mainbus
file arch/sparc64/dev/schizo.c schizo
-device pyro: pcibus, iommu
+device pyro: pcibus, iommu, msi
attach pyro at mainbus
file arch/sparc64/dev/pyro.c pyro
diff --git a/sys/arch/sparc64/dev/pyro.c b/sys/arch/sparc64/dev/pyro.c
index 77cc1b4e17c..86ef994d775 100644
--- a/sys/arch/sparc64/dev/pyro.c
+++ b/sys/arch/sparc64/dev/pyro.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pyro.c,v 1.21 2011/06/26 20:32:36 kettenis Exp $ */
+/* $OpenBSD: pyro.c,v 1.22 2011/07/06 05:48:57 kettenis Exp $ */
/*
* Copyright (c) 2002 Jason L. Wright (jason@thought.net)
@@ -37,6 +37,7 @@
#define _SPARC_BUS_DMA_PRIVATE
#include <machine/bus.h>
#include <machine/autoconf.h>
+#include <machine/openfirm.h>
#ifdef DDB
#include <machine/db_machdep.h>
@@ -47,6 +48,7 @@
#include <sparc64/dev/iommureg.h>
#include <sparc64/dev/iommuvar.h>
+#include <sparc64/dev/msivar.h>
#include <sparc64/dev/pyrovar.h>
#ifdef DEBUG
@@ -60,9 +62,27 @@ int pyro_debug = ~0;
#define DPRINTF(l, s)
#endif
+#define FIRE_EQ_BASE_ADDR 0x10000
+#define FIRE_EQ_CNTRL_SET 0x11000
+#define FIRE_EQ_CTRL_SET_EN 0x0000100000000000UL
+#define FIRE_EQ_CNTRL_CLEAR 0x11200
+#define FIRE_EQ_STATE 0x11400
+#define FIRE_EQ_TAIL 0x11600
+#define FIRE_EQ_HEAD 0x11800
+#define FIRE_MSI_MAP 0x20000
+#define FIRE_MSI_MAP_V 0x8000000000000000UL
+#define FIRE_MSI_MAP_EQWR_N 0x4000000000000000UL
+#define FIRE_MSI_MAP_EQNUM 0x000000000000003fUL
+#define FIRE_MSI_CLEAR 0x28000
+#define FIRE_MSI_CLEAR_EQWR_N 0x4000000000000000UL
+#define FIRE_INTRMONDO_DATA0 0x2c000
+#define FIRE_INTRMONDO_DATA1 0x2c008
+#define FIRE_MSI32_ADDR 0x34000
+#define FIRE_MSI64_ADDR 0x34008
+
#define FIRE_RESET_GEN 0x7010
-#define FIRE_RESET_GEN_XIR 0x0000000000000002L
+#define FIRE_RESET_GEN_XIR 0x0000000000000002UL
#define FIRE_INTRMAP_INT_CNTRL_NUM_MASK 0x000003c0
#define FIRE_INTRMAP_INT_CNTRL_NUM0 0x00000040
@@ -81,6 +101,7 @@ int pyro_match(struct device *, void *, void *);
void pyro_attach(struct device *, struct device *, void *);
void pyro_init(struct pyro_softc *, int);
void pyro_init_iommu(struct pyro_softc *, struct pyro_pbm *);
+void pyro_init_msi(struct pyro_softc *, struct pyro_pbm *);
int pyro_print(void *, const char *);
pci_chipset_tag_t pyro_alloc_chipset(struct pyro_pbm *, int,
@@ -103,6 +124,9 @@ paddr_t _pyro_bus_mmap(bus_space_tag_t, bus_space_tag_t, bus_addr_t, off_t,
int, int);
void *_pyro_intr_establish(bus_space_tag_t, bus_space_tag_t, int, int, int,
int (*)(void *), void *, const char *);
+void pyro_msi_ack(struct intrhand *);
+
+int pyro_msi_eq_intr(void *);
int pyro_dmamap_create(bus_dma_tag_t, bus_dma_tag_t, bus_size_t, int,
bus_size_t, bus_size_t, int, bus_dmamap_t *);
@@ -202,6 +226,8 @@ pyro_init(struct pyro_softc *sc, int busa)
pbm->pp_cfgt = pyro_alloc_config_tag(pbm);
pbm->pp_dmat = pyro_alloc_dma_tag(pbm);
+ pyro_init_msi(sc, pbm);
+
if (bus_space_map(pbm->pp_cfgt, 0, 0x10000000, 0, &pbm->pp_cfgh))
panic("pyro: can't map config space");
@@ -215,9 +241,7 @@ pyro_init(struct pyro_softc *sc, int busa)
pba.pba_domain = pci_ndomains++;
pba.pba_bus = busranges[0];
pba.pba_pc = pbm->pp_pc;
-#if 0
pba.pba_flags = pbm->pp_flags;
-#endif
pba.pba_dmat = pbm->pp_dmat;
pba.pba_memt = pbm->pp_memt;
pba.pba_iot = pbm->pp_iot;
@@ -265,6 +289,71 @@ pyro_init_iommu(struct pyro_softc *sc, struct pyro_pbm *pbm)
iommu_init(name, is, tsbsize, iobase);
}
+void
+pyro_init_msi(struct pyro_softc *sc, struct pyro_pbm *pbm)
+{
+ u_int32_t msi_addr_range[3];
+ u_int32_t msi_eq_devino[3] = { 0, 36, 24 };
+ int ihandle;
+ int msis, msi_eq_size;
+
+ /* Don't do MSI on Oberon for now. */
+ if (sc->sc_oberon)
+ return;
+
+ if (OF_getprop(sc->sc_node, "msi-address-ranges",
+ msi_addr_range, sizeof(msi_addr_range)) <= 0)
+ return;
+ pbm->pp_msiaddr = msi_addr_range[1];
+ pbm->pp_msiaddr |= ((bus_addr_t)msi_addr_range[0]) << 32;
+
+ msis = getpropint(sc->sc_node, "#msi", 256);
+ pbm->pp_msi = malloc(msis * sizeof(*pbm->pp_msi),
+ M_DEVBUF, M_NOWAIT | M_ZERO);
+ if (pbm->pp_msi == NULL)
+ return;
+
+ msi_eq_size = getpropint(sc->sc_node, "msi-eq-size", 256);
+ pbm->pp_meq = msi_eq_alloc(pbm->pp_dmat, msi_eq_size);
+ if (pbm->pp_meq == NULL)
+ goto free_table;
+
+ bzero(pbm->pp_meq->meq_va,
+ pbm->pp_meq->meq_nentries * sizeof(struct pyro_msi_msg));
+
+ bus_space_write_8(sc->sc_bust, sc->sc_csrh, FIRE_EQ_BASE_ADDR,
+ pbm->pp_meq->meq_map->dm_segs[0].ds_addr);
+
+ bus_space_write_8(sc->sc_bust, sc->sc_csrh,
+ FIRE_INTRMONDO_DATA0, sc->sc_ign);
+ bus_space_write_8(sc->sc_bust, sc->sc_csrh,
+ FIRE_INTRMONDO_DATA1, 0);
+
+ bus_space_write_8(sc->sc_bust, sc->sc_csrh, FIRE_MSI32_ADDR,
+ pbm->pp_msiaddr);
+
+ bus_space_write_8(sc->sc_bust, sc->sc_csrh, FIRE_EQ_HEAD, 0);
+ bus_space_write_8(sc->sc_bust, sc->sc_csrh, FIRE_EQ_TAIL, 0);
+
+ OF_getprop(sc->sc_node, "msi-eq-to-devino",
+ msi_eq_devino, sizeof(msi_eq_devino));
+
+ ihandle = msi_eq_devino[2] | sc->sc_ign;
+ if (_pyro_intr_establish(pbm->pp_memt, sc->sc_bust, ihandle,
+ IPL_HIGH, 0, pyro_msi_eq_intr, pbm, sc->sc_dv.dv_xname) == NULL)
+ goto free_table;
+
+ /* Enable EQ. */
+ bus_space_write_8(sc->sc_bust, sc->sc_csrh, FIRE_EQ_CNTRL_SET,
+ FIRE_EQ_CTRL_SET_EN);
+
+ pbm->pp_flags |= PCI_FLAGS_MSI_ENABLED;
+ return;
+
+free_table:
+ free(pbm->pp_msi, M_DEVBUF);
+}
+
int
pyro_print(void *aux, const char *p)
{
@@ -512,6 +601,48 @@ _pyro_intr_establish(bus_space_tag_t t, bus_space_tag_t t0, int ihandle,
volatile u_int64_t *intrmapptr = NULL, *intrclrptr = NULL;
int ino;
+ if (ihandle & PCI_INTR_MSI) {
+ pci_chipset_tag_t pc = pbm->pp_pc;
+ pcitag_t tag = ihandle & ~PCI_INTR_MSI;
+ int msinum = pbm->pp_msinum++;
+ u_int64_t reg;
+
+ ih = bus_intr_allocate(t0, handler, arg, ihandle, level,
+ NULL, NULL, what);
+ if (ih == NULL)
+ return (NULL);
+
+ if (ih->ih_name)
+ evcount_attach(&ih->ih_count, ih->ih_name, NULL);
+ else
+ evcount_attach(&ih->ih_count, "unknown", NULL);
+
+ ih->ih_ack = pyro_msi_ack;
+
+ pbm->pp_msi[msinum] = ih;
+ ih->ih_number = msinum;
+
+ pci_msi_enable(pc, tag, pbm->pp_msiaddr, msinum);
+
+ /* Map MSI to the right EQ and mark it as valid. */
+ reg = bus_space_read_8(sc->sc_bust, sc->sc_csrh,
+ FIRE_MSI_MAP + msinum * 8);
+ reg &= ~FIRE_MSI_MAP_EQNUM;
+ bus_space_write_8(sc->sc_bust, sc->sc_csrh,
+ FIRE_MSI_MAP + msinum * 8, reg);
+
+ bus_space_write_8(sc->sc_bust, sc->sc_csrh,
+ FIRE_MSI_CLEAR + msinum * 8, FIRE_MSI_CLEAR_EQWR_N);
+
+ reg = bus_space_read_8(sc->sc_bust, sc->sc_csrh,
+ FIRE_MSI_MAP + msinum * 8);
+ reg |= FIRE_MSI_MAP_V;
+ bus_space_write_8(sc->sc_bust, sc->sc_csrh,
+ FIRE_MSI_MAP + msinum * 8, reg);
+
+ return (ih);
+ }
+
ino = INTINO(ihandle);
if (level == IPL_NONE)
@@ -561,6 +692,51 @@ _pyro_intr_establish(bus_space_tag_t t, bus_space_tag_t t0, int ihandle,
return (ih);
}
+void
+pyro_msi_ack(struct intrhand *ih)
+{
+}
+
+int
+pyro_msi_eq_intr(void *arg)
+{
+ struct pyro_pbm *pbm = arg;
+ struct pyro_softc *sc = pbm->pp_sc;
+ struct msi_eq *meq = pbm->pp_meq;
+ struct pyro_msi_msg *msg;
+ uint64_t head, tail;
+ struct intrhand *ih;
+ int msinum;
+
+ head = bus_space_read_8(sc->sc_bust, sc->sc_csrh, FIRE_EQ_HEAD);
+ tail = bus_space_read_8(sc->sc_bust, sc->sc_csrh, FIRE_EQ_TAIL);
+
+ if (head == tail)
+ return (0);
+
+ while (head != tail) {
+ msg = (struct pyro_msi_msg *)meq->meq_va;
+
+ if (msg[head].mm_type == 0)
+ break;
+ msg[head].mm_type = 0;
+
+ msinum = msg[head].mm_data;
+ ih = pbm->pp_msi[msinum];
+ bus_space_write_8(sc->sc_bust, sc->sc_csrh,
+ FIRE_MSI_CLEAR + msinum * 8, FIRE_MSI_CLEAR_EQWR_N);
+
+ send_softint(-1, ih->ih_pil, ih);
+
+ head += 1;
+ head &= (meq->meq_nentries - 1);
+ }
+
+ bus_space_write_8(sc->sc_bust, sc->sc_csrh, FIRE_EQ_HEAD, head);
+
+ return (1);
+}
+
#ifdef DDB
void
pyro_xir(void *arg, int cpu)
diff --git a/sys/arch/sparc64/dev/pyrovar.h b/sys/arch/sparc64/dev/pyrovar.h
index a4f8384a1c9..d68dea65476 100644
--- a/sys/arch/sparc64/dev/pyrovar.h
+++ b/sys/arch/sparc64/dev/pyrovar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pyrovar.h,v 1.3 2007/04/03 19:59:01 kettenis Exp $ */
+/* $OpenBSD: pyrovar.h,v 1.4 2011/07/06 05:48:57 kettenis Exp $ */
/*
* Copyright (c) 2007 Mark Kettenis
@@ -26,6 +26,14 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
+struct pyro_msi_msg {
+ uint8_t mm_type;
+ uint8_t mm_reserved[3];
+ uint16_t mm_reqid;
+ uint16_t mm_data;
+ uint64_t mm_reserved2[7];
+};
+
struct pyro_range {
u_int32_t cspace;
u_int32_t child_hi;
@@ -51,6 +59,13 @@ struct pyro_pbm {
int pp_bus_a;
struct iommu_state pp_is;
struct strbuf_ctl pp_sb;
+
+ struct msi_eq *pp_meq;
+ bus_addr_t pp_msiaddr;
+ int pp_msinum;
+ struct intrhand **pp_msi;
+
+ int pp_flags;
};
struct pyro_softc {