Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/arch/x86 Add some code for grovelling in the PCI configu...
details: https://anonhg.NetBSD.org/src/rev/8e217548b269
branches: trunk
changeset: 768857:8e217548b269
user: dyoung <dyoung%NetBSD.org@localhost>
date: Sun Aug 28 06:04:17 2011 +0000
description:
Add some code for grovelling in the PCI configuration space for all
of the memory & I/O space reserved by the PCI BIOS for PCI devices
(including bridges) and recording that information for later use.
The code takes between 13k and 50k (depends on the architecture and,
bizarrely, the kernel configuration) so I am going to move it from
pci_machdep.c into its own module on Monday.
diffstat:
sys/arch/x86/include/pci_machdep_common.h | 10 +-
sys/arch/x86/pci/pci_machdep.c | 919 +++++++++++++++++++++++++++++-
2 files changed, 924 insertions(+), 5 deletions(-)
diffs (truncated from 970 to 300 lines):
diff -r 67a0f819009e -r 8e217548b269 sys/arch/x86/include/pci_machdep_common.h
--- a/sys/arch/x86/include/pci_machdep_common.h Sun Aug 28 05:32:41 2011 +0000
+++ b/sys/arch/x86/include/pci_machdep_common.h Sun Aug 28 06:04:17 2011 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: pci_machdep_common.h,v 1.7 2011/08/01 11:08:03 drochner Exp $ */
+/* $NetBSD: pci_machdep_common.h,v 1.8 2011/08/28 06:04:17 dyoung Exp $ */
/*
* Copyright (c) 1996 Christopher G. Demetriou. All rights reserved.
@@ -140,7 +140,11 @@
void pci_bridge_foreach(pci_chipset_tag_t, int, int,
void (*) (pci_chipset_tag_t, pcitag_t, void *), void *);
-void pci_mmio_range_infer(pci_chipset_tag_t, int, int, bus_addr_t *,
- bus_size_t *);
+void pci_ranges_infer(pci_chipset_tag_t, int, int, bus_addr_t *,
+ bus_size_t *, bus_addr_t *, bus_size_t *);
+
+extern prop_dictionary_t pci_rsrc_dict;
+prop_dictionary_t pci_rsrc_filter(prop_dictionary_t,
+ bool (*)(void *, prop_dictionary_t), void *arg);
#endif /* _X86_PCI_MACHDEP_COMMON_H_ */
diff -r 67a0f819009e -r 8e217548b269 sys/arch/x86/pci/pci_machdep.c
--- a/sys/arch/x86/pci/pci_machdep.c Sun Aug 28 05:32:41 2011 +0000
+++ b/sys/arch/x86/pci/pci_machdep.c Sun Aug 28 06:04:17 2011 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: pci_machdep.c,v 1.47 2011/08/28 04:59:37 dyoung Exp $ */
+/* $NetBSD: pci_machdep.c,v 1.48 2011/08/28 06:04:18 dyoung Exp $ */
/*-
* Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
@@ -73,7 +73,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pci_machdep.c,v 1.47 2011/08/28 04:59:37 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pci_machdep.c,v 1.48 2011/08/28 06:04:18 dyoung Exp $");
#include <sys/types.h>
#include <sys/param.h>
@@ -85,6 +85,9 @@
#include <sys/cpu.h>
#include <sys/kmem.h>
+#include <prop/proplib.h>
+#include <ppath/ppath.h>
+
#include <uvm/uvm_extern.h>
#include <machine/bus_private.h>
@@ -750,6 +753,918 @@
&bridge_hook);
}
+typedef enum pci_alloc_regtype {
+ PCI_ALLOC_REGTYPE_NONE = 0
+ , PCI_ALLOC_REGTYPE_BAR = 1
+ , PCI_ALLOC_REGTYPE_WIN = 2
+ , PCI_ALLOC_REGTYPE_CBWIN = 3
+ , PCI_ALLOC_REGTYPE_VGA_EN = 4
+} pci_alloc_regtype_t;
+
+typedef enum pci_alloc_space {
+ PCI_ALLOC_SPACE_IO = 0
+ , PCI_ALLOC_SPACE_MEM = 1
+} pci_alloc_space_t;
+
+typedef enum pci_alloc_flags {
+ PCI_ALLOC_F_PREFETCHABLE = 0x1
+} pci_alloc_flags_t;
+
+typedef struct pci_alloc {
+ TAILQ_ENTRY(pci_alloc) pal_link;
+ pcitag_t pal_tag;
+ uint64_t pal_addr;
+ uint64_t pal_size;
+ pci_alloc_regtype_t pal_type;
+ struct pci_alloc_reg {
+ int r_ofs;
+ pcireg_t r_val;
+ pcireg_t r_mask;
+ } pal_reg[3];
+ pci_alloc_space_t pal_space;
+ pci_alloc_flags_t pal_flags;
+} pci_alloc_t;
+
+typedef struct pci_alloc_reg pci_alloc_reg_t;
+
+TAILQ_HEAD(pci_alloc_list, pci_alloc);
+
+typedef struct pci_alloc_list pci_alloc_list_t;
+
+static pci_alloc_t *
+pci_alloc_dup(const pci_alloc_t *pal)
+{
+ pci_alloc_t *npal;
+
+ if ((npal = kmem_alloc(sizeof(*npal), KM_SLEEP)) == NULL)
+ return NULL;
+
+ *npal = *pal;
+
+ return npal;
+}
+
+static bool
+pci_alloc_linkdup(pci_alloc_list_t *pals, const pci_alloc_t *pal)
+{
+ pci_alloc_t *npal;
+
+ if ((npal = pci_alloc_dup(pal)) == NULL)
+ return false;
+
+ TAILQ_INSERT_TAIL(pals, npal, pal_link);
+
+ return true;
+}
+
+struct range_infer_ctx {
+ pci_chipset_tag_t ric_pc;
+ pci_alloc_list_t ric_pals;
+ bus_addr_t ric_mmio_bottom;
+ bus_addr_t ric_mmio_top;
+ bus_addr_t ric_io_bottom;
+ bus_addr_t ric_io_top;
+};
+
+#if 1
+static bool
+io_range_extend(struct range_infer_ctx *ric, const pci_alloc_t *pal)
+{
+ if (ric->ric_io_bottom > pal->pal_addr)
+ ric->ric_io_bottom = pal->pal_addr;
+ if (ric->ric_io_top < pal->pal_addr + pal->pal_size)
+ ric->ric_io_top = pal->pal_addr + pal->pal_size;
+
+ return pci_alloc_linkdup(&ric->ric_pals, pal);
+}
+
+static bool
+io_range_extend_by_bar(struct range_infer_ctx *ric, int bus, int dev, int fun,
+ int ofs, pcireg_t curbar, pcireg_t sizebar)
+{
+ pci_alloc_reg_t *r;
+ pci_alloc_t pal = {
+ .pal_flags = 0
+ , .pal_space = PCI_ALLOC_SPACE_IO
+ , .pal_type = PCI_ALLOC_REGTYPE_BAR
+ , .pal_reg = {{
+ .r_mask = ~(pcireg_t)0
+ }}
+ };
+
+ r = &pal.pal_reg[0];
+
+ pal.pal_tag = pci_make_tag(ric->ric_pc, bus, dev, fun);
+ r->r_ofs = ofs;
+ r->r_val = curbar;
+
+ pal.pal_addr = PCI_MAPREG_IO_ADDR(curbar);
+ pal.pal_size = PCI_MAPREG_IO_SIZE(sizebar);
+
+ aprint_debug("%s: %d.%d.%d base at %" PRIx64 " size %" PRIx64 "\n",
+ __func__, bus, dev, fun, pal.pal_addr, pal.pal_size);
+
+ return (pal.pal_size == 0) || io_range_extend(ric, &pal);
+}
+
+static bool
+io_range_extend_by_vga_enable(struct range_infer_ctx *ric,
+ int bus, int dev, int fun, pcireg_t csr, pcireg_t bcr)
+{
+ pci_alloc_reg_t *r;
+ pci_alloc_t tpal = {
+ .pal_flags = 0
+ , .pal_space = PCI_ALLOC_SPACE_IO
+ , .pal_type = PCI_ALLOC_REGTYPE_VGA_EN
+ , .pal_reg = {{
+ .r_ofs = PCI_COMMAND_STATUS_REG
+ , .r_mask = PCI_COMMAND_IO_ENABLE
+ }, {
+ .r_ofs = PCI_BRIDGE_CONTROL_REG
+ , .r_mask =
+ PCI_BRIDGE_CONTROL_VGA << PCI_BRIDGE_CONTROL_SHIFT
+ }}
+ }, pal[2];
+
+ aprint_debug("%s: %d.%d.%d enter\n", __func__, bus, dev, fun);
+
+ if ((csr & PCI_COMMAND_IO_ENABLE) == 0 ||
+ (bcr & (PCI_BRIDGE_CONTROL_VGA << PCI_BRIDGE_CONTROL_SHIFT)) == 0) {
+ aprint_debug("%s: %d.%d.%d I/O or VGA disabled\n",
+ __func__, bus, dev, fun);
+ return true;
+ }
+
+ r = &tpal.pal_reg[0];
+ tpal.pal_tag = pci_make_tag(ric->ric_pc, bus, dev, fun);
+ r[0].r_val = csr;
+ r[1].r_val = bcr;
+
+ pal[0] = pal[1] = tpal;
+
+ pal[0].pal_addr = 0x3b0;
+ pal[0].pal_size = 0x3bb - 0x3b0 + 1;
+
+ pal[1].pal_addr = 0x3c0;
+ pal[1].pal_size = 0x3df - 0x3c0 + 1;
+
+ /* XXX add aliases for pal[0..1] */
+
+ return io_range_extend(ric, &pal[0]) && io_range_extend(ric, &pal[1]);
+}
+
+static bool
+io_range_extend_by_win(struct range_infer_ctx *ric,
+ int bus, int dev, int fun, int ofs, int ofshigh,
+ pcireg_t io, pcireg_t iohigh)
+{
+ const int fourkb = 4 * 1024;
+ pcireg_t baser, limitr;
+ pci_alloc_reg_t *r;
+ pci_alloc_t pal = {
+ .pal_flags = 0
+ , .pal_space = PCI_ALLOC_SPACE_IO
+ , .pal_type = PCI_ALLOC_REGTYPE_WIN
+ , .pal_reg = {{
+ .r_mask = ~(pcireg_t)0
+ }}
+ };
+
+ r = &pal.pal_reg[0];
+
+ pal.pal_tag = pci_make_tag(ric->ric_pc, bus, dev, fun);
+ r[0].r_ofs = ofs;
+ r[0].r_val = io;
+
+ baser = ((io >> PCI_BRIDGE_STATIO_IOBASE_SHIFT) &
+ PCI_BRIDGE_STATIO_IOBASE_MASK) >> 4;
+ limitr = ((io >> PCI_BRIDGE_STATIO_IOLIMIT_SHIFT) &
+ PCI_BRIDGE_STATIO_IOLIMIT_MASK) >> 4;
+
+ if (PCI_BRIDGE_IO_32BITS(io)) {
+ pcireg_t baseh, limith;
+
+ r[1].r_mask = ~(pcireg_t)0;
+ r[1].r_ofs = ofshigh;
+ r[1].r_val = iohigh;
+
+ baseh = (iohigh >> PCI_BRIDGE_IOHIGH_BASE_SHIFT) & PCI_BRIDGE_IOHIGH_BASE_MASK;
+ limith = (iohigh >> PCI_BRIDGE_IOHIGH_LIMIT_SHIFT) & PCI_BRIDGE_IOHIGH_LIMIT_MASK;
+
+ baser |= baseh << 4;
+ limitr |= limith << 4;
+ }
+
+ /* XXX check with the PCI standard */
+ if (baser > limitr)
+ return true;
+
+ pal.pal_addr = baser * fourkb;
+ pal.pal_size = (limitr - baser + 1) * fourkb;
+
+ aprint_debug("%s: %d.%d.%d window at %" PRIx64 " size %" PRIx64 "\n",
+ __func__, bus, dev, fun, pal.pal_addr, pal.pal_size);
+
+ return io_range_extend(ric, &pal);
+}
+
+static bool
+io_range_extend_by_cbwin(struct range_infer_ctx *ric,
+ int bus, int dev, int fun, int ofs, pcireg_t base0, pcireg_t limit0)
+{
+ pcireg_t base, limit;
+ pci_alloc_reg_t *r;
+ pci_alloc_t pal = {
+ .pal_flags = 0
+ , .pal_space = PCI_ALLOC_SPACE_IO
+ , .pal_type = PCI_ALLOC_REGTYPE_CBWIN
+ , .pal_reg = {{
+ .r_mask = ~(pcireg_t)0
+ }, {
+ .r_mask = ~(pcireg_t)0
+ }}
+ };
+
+ r = &pal.pal_reg[0];
+
+ pal.pal_tag = pci_make_tag(ric->ric_pc, bus, dev, fun);
+ r[0].r_ofs = ofs;
+ r[0].r_val = base0;
+ r[1].r_ofs = ofs + 4;
+ r[1].r_val = limit0;
+
+ base = base0 & __BITS(31, 2);
+ limit = limit0 & __BITS(31, 2);
+
+ if (base > limit)
+ return true;
Home |
Main Index |
Thread Index |
Old Index