From 86392ca602613d15ca3320765bc0f917ac1bcb12 Mon Sep 17 00:00:00 2001 From: kettenis Date: Wed, 19 May 2021 19:32:25 +0000 Subject: [PATCH] Add PCI support. ok deraadt@ --- sys/arch/riscv64/conf/GENERIC | 13 +- sys/arch/riscv64/conf/files.riscv64 | 8 +- sys/arch/riscv64/dev/pci_machdep.c | 167 +++++++++++++++++++++++++ sys/arch/riscv64/include/pci_machdep.h | 134 ++++++++++++++++++++ 4 files changed, 320 insertions(+), 2 deletions(-) create mode 100644 sys/arch/riscv64/dev/pci_machdep.c create mode 100644 sys/arch/riscv64/include/pci_machdep.h diff --git a/sys/arch/riscv64/conf/GENERIC b/sys/arch/riscv64/conf/GENERIC index 0fdbac8fbec..0bedad70fc9 100644 --- a/sys/arch/riscv64/conf/GENERIC +++ b/sys/arch/riscv64/conf/GENERIC @@ -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? diff --git a/sys/arch/riscv64/conf/files.riscv64 b/sys/arch/riscv64/conf/files.riscv64 index 2ad804c88f0..684f48ef817 100644 --- a/sys/arch/riscv64/conf/files.riscv64 +++ b/sys/arch/riscv64/conf/files.riscv64 @@ -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 index 00000000000..59d08ad7171 --- /dev/null +++ b/sys/arch/riscv64/dev/pci_machdep.c @@ -0,0 +1,167 @@ +/* $OpenBSD: pci_machdep.c,v 1.1 2021/05/19 19:32:25 kettenis Exp $ */ + +/* + * Copyright (c) 2019 Mark Kettenis + * + * 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 +#include + +#include + +#include +#include + +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, ®) == 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, ®) == 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, ®) == 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, ®) == 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, ®) == 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 index 00000000000..40763fc767b --- /dev/null +++ b/sys/arch/riscv64/include/pci_machdep.h @@ -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); -- 2.20.1