Add PCI support.
authorkettenis <kettenis@openbsd.org>
Wed, 19 May 2021 19:32:25 +0000 (19:32 +0000)
committerkettenis <kettenis@openbsd.org>
Wed, 19 May 2021 19:32:25 +0000 (19:32 +0000)
ok deraadt@

sys/arch/riscv64/conf/GENERIC
sys/arch/riscv64/conf/files.riscv64
sys/arch/riscv64/dev/pci_machdep.c [new file with mode: 0644]
sys/arch/riscv64/include/pci_machdep.h [new file with mode: 0644]

index 0fdbac8..0bedad7 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: GENERIC,v 1.11 2021/05/12 01:20:52 jsg Exp $
+#      $OpenBSD: GENERIC,v 1.12 2021/05/19 19:32:25 kettenis Exp $
 #
 # For further information on compiling OpenBSD kernels, see the config(8)
 # man page.
@@ -13,6 +13,9 @@ machine               riscv64
 include                "../../../conf/GENERIC"
 maxusers       32
 
+option         PCIVERBOSE
+option         USER_PCICONF
+
 makeoptions    KERNEL_BASE_PHYS="0x00200000"
 makeoptions    KERNEL_BASE_VIRT="0xffffffc000200000"
 #option                DEBUG
@@ -37,6 +40,7 @@ intc0         at cpu0
 com*           at fdt?
 
 virtio*                at fdt?
+virtio*                at pci?
 vio*           at virtio?      # Network
 vioblk*                at virtio?
 vioscsi*       at virtio?      # Disk (SCSI)
@@ -59,6 +63,13 @@ ukphy*               at mii?
 dwmmc*         at fdt?
 sdmmc*         at dwmmc?
 
+pciecam*       at fdt?
+pci*           at pciecam?
+
+# PCI
+ppb*           at pci?         # PCI-PCI bridges
+pci*           at ppb?
+
 scsibus*       at scsi?
 sd*            at scsibus?
 cd*            at scsibus?
index 2ad804c..684f48e 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: files.riscv64,v 1.9 2021/05/12 01:20:52 jsg Exp $
+#      $OpenBSD: files.riscv64,v 1.10 2021/05/19 19:32:25 kettenis Exp $
 
 # Standard stanzas config(8) can't run without
 maxpartitions 16
@@ -42,6 +42,8 @@ file  arch/riscv64/riscv64/db_disasm.c        ddb
 file   arch/riscv64/riscv64/db_interface.c     ddb
 file   arch/riscv64/riscv64/db_trace.c ddb
 
+file   arch/riscv64/dev/pci_machdep.c
+
 pseudo-device  openprom
 file   arch/riscv64/riscv64/openprom.c         openprom needs-flag
 
@@ -114,3 +116,7 @@ include "dev/fdt/files.fdt"
 
 # Machine-independent SCSI drivers
 include "scsi/files.scsi"
+
+device pciecam: pcibus
+attach pciecam at fdt
+file   dev/fdt/pciecam.c                       pciecam
diff --git a/sys/arch/riscv64/dev/pci_machdep.c b/sys/arch/riscv64/dev/pci_machdep.c
new file mode 100644 (file)
index 0000000..59d08ad
--- /dev/null
@@ -0,0 +1,167 @@
+/*     $OpenBSD: pci_machdep.c,v 1.1 2021/05/19 19:32:25 kettenis Exp $        */
+
+/*
+ * Copyright (c) 2019 Mark Kettenis <kettenis@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <machine/bus.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+
+void
+pci_msi_enable(pci_chipset_tag_t pc, pcitag_t tag,
+    bus_addr_t addr, uint32_t data)
+{
+       pcireg_t reg;
+       int off;
+
+       if (pci_get_capability(pc, tag, PCI_CAP_MSI, &off, &reg) == 0)
+               panic("%s: no msi capability", __func__);
+
+       if (reg & PCI_MSI_MC_C64) {
+               pci_conf_write(pc, tag, off + PCI_MSI_MA, addr);
+               pci_conf_write(pc, tag, off + PCI_MSI_MAU32, addr >> 32);
+               pci_conf_write(pc, tag, off + PCI_MSI_MD64, data);
+       } else {
+               pci_conf_write(pc, tag, off + PCI_MSI_MA, addr);
+               pci_conf_write(pc, tag, off + PCI_MSI_MD32, data);
+       }
+       pci_conf_write(pc, tag, off, reg | PCI_MSI_MC_MSIE);
+}
+
+int
+pci_msix_table_map(pci_chipset_tag_t pc, pcitag_t tag,
+    bus_space_tag_t memt, bus_space_handle_t *memh)
+{
+       bus_addr_t base;
+       pcireg_t reg, table, type;
+       int bir, offset;
+       int off, tblsz;
+
+       if (pci_get_capability(pc, tag, PCI_CAP_MSIX, &off, &reg) == 0)
+               panic("%s: no msix capability", __func__);
+
+       table = pci_conf_read(pc, tag, off + PCI_MSIX_TABLE);
+       bir = (table & PCI_MSIX_TABLE_BIR);
+       offset = (table & PCI_MSIX_TABLE_OFF);
+       tblsz = PCI_MSIX_MC_TBLSZ(reg) + 1;
+
+       bir = PCI_MAPREG_START + bir * 4;
+       type = pci_mapreg_type(pc, tag, bir);
+       if (pci_mapreg_info(pc, tag, bir, type, &base, NULL, NULL) ||
+           bus_space_map(memt, base + offset, tblsz * 16, 0, memh))
+               return -1;
+
+       return 0;
+}
+
+void
+pci_msix_table_unmap(pci_chipset_tag_t pc, pcitag_t tag,
+    bus_space_tag_t memt, bus_space_handle_t memh)
+{
+       pcireg_t reg;
+       int tblsz;
+
+       if (pci_get_capability(pc, tag, PCI_CAP_MSIX, NULL, &reg) == 0)
+               panic("%s: no msix capability", __func__);
+
+       tblsz = PCI_MSIX_MC_TBLSZ(reg) + 1;
+       bus_space_unmap(memt, memh, tblsz * 16);
+}
+
+void
+pci_msix_enable(pci_chipset_tag_t pc, pcitag_t tag, bus_space_tag_t memt,
+    int vec, bus_addr_t addr, uint32_t data)
+{
+       bus_space_handle_t memh;
+       pcireg_t reg;
+       uint32_t ctrl;
+       int off;
+
+       if (pci_get_capability(pc, tag, PCI_CAP_MSIX, &off, &reg) == 0)
+               panic("%s: no msix capability", __func__);
+
+       KASSERT(vec <= PCI_MSIX_MC_TBLSZ(reg));
+
+       if (pci_msix_table_map(pc, tag, memt, &memh))
+               panic("%s: cannot map registers", __func__);
+
+       bus_space_write_4(memt, memh, PCI_MSIX_MA(vec), addr);
+       bus_space_write_4(memt, memh, PCI_MSIX_MAU32(vec), addr >> 32);
+       bus_space_write_4(memt, memh, PCI_MSIX_MD(vec), data);
+       bus_space_barrier(memt, memh, PCI_MSIX_MA(vec), 16,
+           BUS_SPACE_BARRIER_WRITE);
+       ctrl = bus_space_read_4(memt, memh, PCI_MSIX_VC(vec));
+       bus_space_write_4(memt, memh, PCI_MSIX_VC(vec),
+           ctrl & ~PCI_MSIX_VC_MASK);
+
+       pci_msix_table_unmap(pc, tag, memt, memh);
+
+       pci_conf_write(pc, tag, off, reg | PCI_MSIX_MC_MSIXE);
+}
+
+int
+_pci_intr_map_msi(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
+{
+       pci_chipset_tag_t pc = pa->pa_pc;
+       pcitag_t tag = pa->pa_tag;
+
+       if ((pa->pa_flags & PCI_FLAGS_MSI_ENABLED) == 0 ||
+           pci_get_capability(pc, tag, PCI_CAP_MSI, NULL, NULL) == 0)
+               return -1;
+
+       ihp->ih_pc = pa->pa_pc;
+       ihp->ih_tag = pa->pa_tag;
+       ihp->ih_type = PCI_MSI;
+       ihp->ih_dmat = pa->pa_dmat;
+
+       return 0;
+}
+
+int
+_pci_intr_map_msix(struct pci_attach_args *pa, int vec,
+    pci_intr_handle_t *ihp)
+{
+       pci_chipset_tag_t pc = pa->pa_pc;
+       pcitag_t tag = pa->pa_tag;
+       pcireg_t reg, table, type;
+       int bir, off;
+
+       if ((pa->pa_flags & PCI_FLAGS_MSI_ENABLED) == 0 ||
+           pci_get_capability(pc, tag, PCI_CAP_MSIX, &off, &reg) == 0)
+               return -1;
+
+       if (vec > PCI_MSIX_MC_TBLSZ(reg))
+               return -1;
+
+       table = pci_conf_read(pc, tag, off + PCI_MSIX_TABLE);
+       bir = PCI_MAPREG_START + (table & PCI_MSIX_TABLE_BIR) * 4;
+       type = pci_mapreg_type(pc, tag, bir);
+       if (pci_mapreg_assign(pa, bir, type, NULL, NULL))
+               return -1;
+
+       ihp->ih_pc = pa->pa_pc;
+       ihp->ih_tag = pa->pa_tag;
+       ihp->ih_intrpin = vec;
+       ihp->ih_type = PCI_MSIX;
+       ihp->ih_dmat = pa->pa_dmat;
+
+       return 0;
+}
+
diff --git a/sys/arch/riscv64/include/pci_machdep.h b/sys/arch/riscv64/include/pci_machdep.h
new file mode 100644 (file)
index 0000000..40763fc
--- /dev/null
@@ -0,0 +1,134 @@
+/*     $OpenBSD: pci_machdep.h,v 1.1 2021/05/19 19:32:25 kettenis Exp $ */
+
+/*
+ * Copyright (c) 2003-2004 Opsycon AB  (www.opsycon.se / www.opsycon.com)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+typedef struct machine_pci_chipset *pci_chipset_tag_t;
+typedef u_long pcitag_t;
+
+/* Supported interrupt types. */
+#define PCI_NONE               0
+#define PCI_INTX               1
+#define PCI_MSI                        2
+#define PCI_MSIX               3
+
+typedef struct {
+       pci_chipset_tag_t       ih_pc;
+       pcitag_t                ih_tag;
+       int                     ih_intrpin;
+       int                     ih_type;
+       bus_dma_tag_t           ih_dmat;
+} pci_intr_handle_t;
+
+struct pci_attach_args;
+
+/*
+ * Machine-specific PCI structure and type definitions.
+ * NOT TO BE USED DIRECTLY BY MACHINE INDEPENDENT CODE.
+ */
+struct machine_pci_chipset {
+       void            *pc_conf_v;
+       void            (*pc_attach_hook)(struct device *,
+                           struct device *, struct pcibus_attach_args *);
+       int             (*pc_bus_maxdevs)(void *, int);
+       pcitag_t        (*pc_make_tag)(void *, int, int, int);
+       void            (*pc_decompose_tag)(void *, pcitag_t, int *,
+                           int *, int *);
+       int             (*pc_conf_size)(void *, pcitag_t);
+       pcireg_t        (*pc_conf_read)(void *, pcitag_t, int);
+       void            (*pc_conf_write)(void *, pcitag_t, int, pcireg_t);
+       int             (*pc_probe_device_hook)(void *, struct pci_attach_args *);
+
+       void            *pc_intr_v;
+       int             (*pc_intr_map)(struct pci_attach_args *,
+                           pci_intr_handle_t *);
+       int             (*pc_intr_map_msi)(struct pci_attach_args *,
+                           pci_intr_handle_t *);
+       int             (*pc_intr_map_msix)(struct pci_attach_args *,
+                           int, pci_intr_handle_t *);
+       const char      *(*pc_intr_string)(void *, pci_intr_handle_t);
+       void            *(*pc_intr_establish)(void *, pci_intr_handle_t,
+                           int, struct cpu_info *, int (*)(void *), void *,
+                           char *);
+       void            (*pc_intr_disestablish)(void *, void *);
+};
+
+/*
+ * Functions provided to machine-independent PCI code.
+ */
+#define        pci_attach_hook(p, s, pba)                                      \
+    (*(pba)->pba_pc->pc_attach_hook)((p), (s), (pba))
+#define        pci_bus_maxdevs(c, b)                                           \
+    (*(c)->pc_bus_maxdevs)((c)->pc_conf_v, (b))
+#define        pci_make_tag(c, b, d, f)                                        \
+    (*(c)->pc_make_tag)((c)->pc_conf_v, (b), (d), (f))
+#define        pci_decompose_tag(c, t, bp, dp, fp)                             \
+    (*(c)->pc_decompose_tag)((c)->pc_conf_v, (t), (bp), (dp), (fp))
+#define        pci_conf_size(c, t)                                             \
+    (*(c)->pc_conf_size)((c)->pc_conf_v, (t))
+#define        pci_conf_read(c, t, r)                                          \
+    (*(c)->pc_conf_read)((c)->pc_conf_v, (t), (r))
+#define        pci_conf_write(c, t, r, v)                                      \
+    (*(c)->pc_conf_write)((c)->pc_conf_v, (t), (r), (v))
+#define        pci_probe_device_hook(c, a)                                     \
+    (*(c)->pc_probe_device_hook)((c)->pc_conf_v, (a))
+#define        pci_intr_map(c, ihp)                                            \
+    (*(c)->pa_pc->pc_intr_map)((c), (ihp))
+#define        pci_intr_map_msi(c, ihp)                                        \
+    (*(c)->pa_pc->pc_intr_map_msi)((c), (ihp))
+#define        pci_intr_map_msix(c, vec, ihp)                                  \
+    (*(c)->pa_pc->pc_intr_map_msix)((c), (vec), (ihp))
+#define        pci_intr_string(c, ih)                                          \
+    (*(c)->pc_intr_string)((c)->pc_intr_v, (ih))
+#define        pci_intr_establish(c, ih, l, h, a, nm)                          \
+    (*(c)->pc_intr_establish)((c)->pc_intr_v, (ih), (l), NULL, (h), (a),\
+       (nm))
+#define        pci_intr_establish_cpu(c, ih, l, ci, h, a, nm)                  \
+    (*(c)->pc_intr_establish)((c)->pc_intr_v, (ih), (l), (ci), (h), (a),\
+       (nm))
+#define        pci_intr_disestablish(c, iv)                                    \
+    (*(c)->pc_intr_disestablish)((c)->pc_intr_v, (iv))
+
+#define        pci_min_powerstate(c, t)        (PCI_PMCSR_STATE_D3)
+#define        pci_set_powerstate_md(c, t, s, p)
+
+#define        pci_dev_postattach(a, b)
+
+void   pci_mcfg_init(bus_space_tag_t, bus_addr_t, int, int, int);
+pci_chipset_tag_t pci_lookup_segment(int);
+
+void   pci_msi_enable(pci_chipset_tag_t, pcitag_t, bus_addr_t, uint32_t);
+void   pci_msix_enable(pci_chipset_tag_t, pcitag_t, bus_space_tag_t,
+           int, bus_addr_t, uint32_t);
+int    _pci_intr_map_msi(struct pci_attach_args *, pci_intr_handle_t *);
+int    _pci_intr_map_msix(struct pci_attach_args *, int, pci_intr_handle_t *);
+
+#define __HAVE_PCI_MSIX
+
+int    pci_msix_table_map(pci_chipset_tag_t, pcitag_t,
+           bus_space_tag_t, bus_space_handle_t *);
+void   pci_msix_table_unmap(pci_chipset_tag_t, pcitag_t,
+           bus_space_tag_t, bus_space_handle_t);