summaryrefslogtreecommitdiffstats
path: root/sys/arch/sparc64/dev/vpci.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/sparc64/dev/vpci.c')
-rw-r--r--sys/arch/sparc64/dev/vpci.c167
1 files changed, 123 insertions, 44 deletions
diff --git a/sys/arch/sparc64/dev/vpci.c b/sys/arch/sparc64/dev/vpci.c
index 069622c41bc..c011129f436 100644
--- a/sys/arch/sparc64/dev/vpci.c
+++ b/sys/arch/sparc64/dev/vpci.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vpci.c,v 1.29 2019/07/26 11:33:05 kettenis Exp $ */
+/* $OpenBSD: vpci.c,v 1.30 2020/06/23 01:21:29 jmatthew Exp $ */
/*
* Copyright (c) 2008 Mark Kettenis <kettenis@openbsd.org>
*
@@ -35,6 +35,8 @@
#include <sparc64/dev/viommuvar.h>
#include <sparc64/dev/msivar.h>
+#define VPCI_DEFAULT_MSI_EQS 36
+
extern struct sparc_pci_chipset _sparc_pci_chipset;
struct vpci_msi_msg {
@@ -61,6 +63,16 @@ struct vpci_range {
u_int32_t size_lo;
};
+struct vpci_eq {
+ char eq_name[16];
+ int eq_id;
+ void *eq_ih;
+ struct msi_eq *eq_meq;
+ struct vpci_pbm *eq_pbm;
+ uint8_t *eq_ring;
+ uint64_t eq_mask;
+};
+
struct vpci_pbm {
struct vpci_softc *vp_sc;
uint64_t vp_devhandle;
@@ -74,12 +86,14 @@ struct vpci_pbm {
bus_dma_tag_t vp_dmat;
struct iommu_state vp_is;
- struct msi_eq *vp_meq;
bus_addr_t vp_msiaddr;
int vp_msibase;
int vp_msinum;
struct intrhand **vp_msi;
+ unsigned int vp_neq;
+ struct vpci_eq *vp_eq;
+
int vp_flags;
};
@@ -118,6 +132,8 @@ paddr_t vpci_bus_mmap(bus_space_tag_t, bus_space_tag_t, bus_addr_t, off_t,
int, int);
void *vpci_intr_establish(bus_space_tag_t, bus_space_tag_t, int, int, int,
int (*)(void *), void *, const char *);
+void *vpci_intr_establish_cpu(bus_space_tag_t, bus_space_tag_t, int, int,
+ int, struct cpu_info *, int (*)(void *), void *, const char *);
void vpci_intr_ack(struct intrhand *);
void vpci_msi_ack(struct intrhand *);
@@ -249,8 +265,14 @@ vpci_init_msi(struct vpci_softc *sc, struct vpci_pbm *pbm)
u_int32_t msi_eq_devino[3] = { 0, 36, 24 };
u_int32_t msi_range[2];
uint64_t sysino;
- int msis, msi_eq_size;
+ int msis, msi_eq_size, num_eq, unit;
+ struct vpci_eq *eq;
int err;
+ CPU_INFO_ITERATOR cii;
+ struct cpu_info *ci;
+
+ /* One eq per cpu, limited by the number of eqs. */
+ num_eq = min(ncpus, getpropint(sc->sc_node, "#msi-eqs", 36));
if (OF_getprop(sc->sc_node, "msi-address-ranges",
msi_addr_range, sizeof(msi_addr_range)) <= 0)
@@ -265,51 +287,85 @@ vpci_init_msi(struct vpci_softc *sc, struct vpci_pbm *pbm)
return;
msi_eq_size = getpropint(sc->sc_node, "msi-eq-size", 256);
- pbm->vp_meq = msi_eq_alloc(sc->sc_dmat, msi_eq_size);
- if (pbm->vp_meq == NULL)
- goto free_table;
if (OF_getprop(sc->sc_node, "msi-ranges",
msi_range, sizeof(msi_range)) <= 0)
goto free_table;
pbm->vp_msibase = msi_range[0];
- err = hv_pci_msiq_conf(pbm->vp_devhandle, 0,
- pbm->vp_meq->meq_map->dm_segs[0].ds_addr,
- pbm->vp_meq->meq_nentries);
- if (err != H_EOK)
- goto free_queue;
+ pbm->vp_neq = num_eq;
+ pbm->vp_eq = mallocarray(num_eq, sizeof(*eq), M_DEVBUF,
+ M_WAITOK | M_ZERO);
- OF_getprop(sc->sc_node, "msi-eq-to-devino",
- msi_eq_devino, sizeof(msi_eq_devino));
- err = sun4v_intr_devino_to_sysino(pbm->vp_devhandle,
- msi_eq_devino[2], &sysino);
- if (err != H_EOK)
- goto disable_queue;
+ CPU_INFO_FOREACH(cii, ci) {
+ unit = CPU_INFO_UNIT(ci);
+ eq = &pbm->vp_eq[unit];
- if (vpci_intr_establish(pbm->vp_memt, pbm->vp_memt, sysino,
- IPL_HIGH, 0, vpci_msi_eq_intr, pbm, sc->sc_dv.dv_xname) == NULL)
- goto disable_queue;
+ if (unit >= num_eq)
+ continue;
- err = hv_pci_msiq_setvalid(pbm->vp_devhandle, 0, PCI_MSIQ_VALID);
- if (err != H_EOK) {
- printf("%s: pci_msiq_setvalid: err %d\n", __func__, err);
- goto disable_queue;
- }
+ eq->eq_id = unit;
+ eq->eq_pbm = pbm;
+ snprintf(eq->eq_name, sizeof(eq->eq_name), "%s:%d",
+ sc->sc_dv.dv_xname, unit);
+
+ eq->eq_meq = msi_eq_alloc(sc->sc_dmat, msi_eq_size, 1);
+ if (eq->eq_meq == NULL)
+ goto free_queues;
+
+ err = hv_pci_msiq_conf(pbm->vp_devhandle, unit,
+ eq->eq_meq->meq_map->dm_segs[0].ds_addr,
+ eq->eq_meq->meq_nentries);
+ if (err != H_EOK)
+ goto free_queues;
+
+ eq->eq_mask = (eq->eq_meq->meq_nentries *
+ sizeof(struct vpci_msi_msg)) - 1;
+
+ OF_getprop(sc->sc_node, "msi-eq-to-devino",
+ msi_eq_devino, sizeof(msi_eq_devino));
+ err = sun4v_intr_devino_to_sysino(pbm->vp_devhandle,
+ msi_eq_devino[2] + unit, &sysino);
+ if (err != H_EOK)
+ goto free_queues;
- err = hv_pci_msiq_setstate(pbm->vp_devhandle, 0, PCI_MSIQSTATE_IDLE);
- if (err != H_EOK) {
- printf("%s: pci_msiq_setstate: err %d\n", __func__, err);
- goto disable_queue;
+ eq->eq_ih = vpci_intr_establish_cpu(pbm->vp_memt, pbm->vp_memt,
+ sysino, IPL_HIGH, BUS_INTR_ESTABLISH_MPSAFE, ci,
+ vpci_msi_eq_intr, eq, eq->eq_name);
+ if (eq->eq_ih == NULL)
+ goto free_queues;
+
+ err = hv_pci_msiq_setvalid(pbm->vp_devhandle, unit,
+ PCI_MSIQ_VALID);
+ if (err != H_EOK) {
+ printf("%s: pci_msiq_setvalid(%d): err %d\n", __func__,
+ unit, err);
+ goto free_queues;
+ }
+
+ err = hv_pci_msiq_setstate(pbm->vp_devhandle, unit,
+ PCI_MSIQSTATE_IDLE);
+ if (err != H_EOK) {
+ printf("%s: pci_msiq_setstate(%d): err %d\n", __func__,
+ unit, err);
+ goto free_queues;
+ }
}
pbm->vp_flags |= PCI_FLAGS_MSI_ENABLED;
return;
-disable_queue:
- hv_pci_msiq_conf(pbm->vp_devhandle, 0, 0, 0);
-free_queue:
- msi_eq_free(sc->sc_dmat, pbm->vp_meq);
+free_queues:
+ CPU_INFO_FOREACH(cii, ci) {
+ unit = CPU_INFO_UNIT(ci);
+ eq = &pbm->vp_eq[unit];
+
+ if (eq->eq_meq != NULL)
+ msi_eq_free(sc->sc_dmat, eq->eq_meq);
+
+ hv_pci_msiq_conf(pbm->vp_devhandle, unit, 0, 0);
+ }
+ free(pbm->vp_eq, M_DEVBUF, num_eq * sizeof(*eq));
free_table:
free(pbm->vp_msi, M_DEVBUF, 0);
}
@@ -418,6 +474,7 @@ vpci_alloc_bus_tag(struct vpci_pbm *pbm, const char *name, int ss,
bt->sparc_bus_map = vpci_bus_map;
bt->sparc_bus_mmap = vpci_bus_mmap;
bt->sparc_intr_establish = vpci_intr_establish;
+ bt->sparc_intr_establish_cpu = vpci_intr_establish_cpu;
return (bt);
}
@@ -547,6 +604,15 @@ void *
vpci_intr_establish(bus_space_tag_t t, bus_space_tag_t t0, int ihandle,
int level, int flags, int (*handler)(void *), void *arg, const char *what)
{
+ return (vpci_intr_establish_cpu(t, t0, ihandle, level, flags, NULL,
+ handler, arg, what));
+}
+
+void *
+vpci_intr_establish_cpu(bus_space_tag_t t, bus_space_tag_t t0, int ihandle,
+ int level, int flags, struct cpu_info *cpu, int (*handler)(void *),
+ void *arg, const char *what)
+{
struct vpci_pbm *pbm = t->cookie;
uint64_t devhandle = pbm->vp_devhandle;
uint64_t sysino = INTVEC(ihandle);
@@ -566,6 +632,7 @@ vpci_intr_establish(bus_space_tag_t t, bus_space_tag_t t0, int ihandle,
pcitag_t tag = PCI_INTR_TAG(ihandle);
int msinum = pbm->vp_msinum++;
int msi = pbm->vp_msibase + msinum;
+ int eq = 0;
evcount_attach(&ih->ih_count, ih->ih_name, NULL);
@@ -584,7 +651,15 @@ vpci_intr_establish(bus_space_tag_t t, bus_space_tag_t t0, int ihandle,
break;
}
- err = hv_pci_msi_setmsiq(devhandle, msi, 0, 0);
+ if (cpu != NULL) {
+ /*
+ * For now, if we have fewer eqs than cpus, map
+ * interrupts for the eq-less cpus onto other cpus.
+ */
+ eq = CPU_INFO_UNIT(cpu) % pbm->vp_neq;
+ }
+
+ err = hv_pci_msi_setmsiq(devhandle, msi, eq, 0);
if (err != H_EOK) {
printf("%s: pci_msi_setmsiq: err %d\n", __func__, err);
return (NULL);
@@ -609,6 +684,7 @@ vpci_intr_establish(bus_space_tag_t t, bus_space_tag_t t0, int ihandle,
if (err != H_EOK)
return (NULL);
+ ih->ih_cpu = cpu;
intr_establish(ih->ih_pil, ih);
ih->ih_ack = vpci_intr_ack;
@@ -647,8 +723,8 @@ vpci_msi_ack(struct intrhand *ih)
int
vpci_msi_eq_intr(void *arg)
{
- struct vpci_pbm *pbm = arg;
- struct msi_eq *meq = pbm->vp_meq;
+ struct vpci_eq *eq = arg;
+ struct vpci_pbm *pbm = eq->eq_pbm;
struct vpci_msi_msg *msg;
uint64_t devhandle = pbm->vp_devhandle;
uint64_t head, tail;
@@ -656,19 +732,21 @@ vpci_msi_eq_intr(void *arg)
int msinum, msi;
int err;
- err = hv_pci_msiq_gethead(devhandle, 0, &head);
+ err = hv_pci_msiq_gethead(devhandle, eq->eq_id, &head);
if (err != H_EOK)
- printf("%s: pci_msiq_gethead: %d\n", __func__, err);
+ printf("%s: pci_msiq_gethead(%d): %d\n", __func__, eq->eq_id,
+ err);
- err = hv_pci_msiq_gettail(devhandle, 0, &tail);
+ err = hv_pci_msiq_gettail(devhandle, eq->eq_id, &tail);
if (err != H_EOK)
- printf("%s: pci_msiq_gettail: %d\n", __func__, err);
+ printf("%s: pci_msiq_gettail(%d): %d\n", __func__, eq->eq_id,
+ err);
if (head == tail)
return (0);
while (head != tail) {
- msg = (struct vpci_msi_msg *)(meq->meq_va + head);
+ msg = (struct vpci_msi_msg *)(eq->eq_meq->meq_va + head);
if (msg->mm_type == 0)
break;
@@ -684,12 +762,13 @@ vpci_msi_eq_intr(void *arg)
send_softint(-1, ih->ih_pil, ih);
head += sizeof(struct vpci_msi_msg);
- head &= ((meq->meq_nentries * sizeof(struct vpci_msi_msg)) - 1);
+ head &= eq->eq_mask;
}
- err = hv_pci_msiq_sethead(devhandle, 0, head);
+ err = hv_pci_msiq_sethead(devhandle, eq->eq_id, head);
if (err != H_EOK)
- printf("%s: pci_msiq_sethead: %d\n", __func__, err);
+ printf("%s: pci_msiq_sethead(%d): %d\n", __func__, eq->eq_id,
+ err);
return (1);
}