From 61ccff524d2393a819f7752039df2d427b1cb98b Mon Sep 17 00:00:00 2001 From: jmcneill Date: Thu, 10 Feb 2011 12:37:58 +0000 Subject: [PATCH] pcimmap: if the requested page is marked prefetchable in a child device's BAR, pass the BUS_SPACE_MAP_PREFETCHABLE flag down to bus_space_mmap --- sys/dev/pci/pci.c | 29 +++++++++++++++++++++++++---- sys/dev/pci/pci_usrreq.c | 29 +++++++++++++++++++++++++---- sys/dev/pci/pcivar.h | 9 ++++++++- 3 files changed, 58 insertions(+), 9 deletions(-) diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c index 952846e81ba5..9a01efb63540 100644 --- a/sys/dev/pci/pci.c +++ b/sys/dev/pci/pci.c @@ -1,4 +1,4 @@ -/* $NetBSD: pci.c,v 1.131 2011/02/01 19:37:37 dyoung Exp $ */ +/* $NetBSD: pci.c,v 1.132 2011/02/10 12:37:58 jmcneill Exp $ */ /* * Copyright (c) 1995, 1996, 1997, 1998 @@ -36,7 +36,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: pci.c,v 1.131 2011/02/01 19:37:37 dyoung Exp $"); +__KERNEL_RCSID(0, "$NetBSD: pci.c,v 1.132 2011/02/10 12:37:58 jmcneill Exp $"); #include "opt_pci.h" @@ -272,8 +272,8 @@ pci_probe_device(struct pci_softc *sc, pcitag_t tag, { pci_chipset_tag_t pc = sc->sc_pc; struct pci_attach_args pa; - pcireg_t id, csr, class, intr, bhlcr; - int ret, pin, bus, device, function; + pcireg_t id, csr, class, intr, bhlcr, bar; + int ret, pin, bus, device, function, i, width; int locs[PCICF_NLOCS]; pci_decompose_tag(pc, tag, &bus, &device, &function); @@ -297,6 +297,27 @@ pci_probe_device(struct pci_softc *sc, pcitag_t tag, if (PCI_VENDOR(id) == 0) return 0; + /* Collect memory range info */ + memset(sc->PCI_SC_DEVICESC(device, function).c_range, 0, + sizeof(sc->PCI_SC_DEVICESC(device, function).c_range)); + i = 0; + for (bar = PCI_MAPREG_START; bar < PCI_MAPREG_END; bar += width) { + int type = pci_mapreg_type(pc, tag, bar); + struct pci_range *r; + + width = 4; + if (PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_MEM) { + if (PCI_MAPREG_MEM_TYPE(type) == + PCI_MAPREG_MEM_TYPE_64BIT) + width = 8; + + r = &sc->PCI_SC_DEVICESC(device, function).c_range[i++]; + if (pci_mapreg_info(pc, tag, bar, type, + &r->r_offset, &r->r_size, &r->r_flags) != 0) + break; + } + } + pa.pa_iot = sc->sc_iot; pa.pa_memt = sc->sc_memt; pa.pa_dmat = sc->sc_dmat; diff --git a/sys/dev/pci/pci_usrreq.c b/sys/dev/pci/pci_usrreq.c index 07e120443f63..c18efa627074 100644 --- a/sys/dev/pci/pci_usrreq.c +++ b/sys/dev/pci/pci_usrreq.c @@ -1,4 +1,4 @@ -/* $NetBSD: pci_usrreq.c,v 1.22 2009/07/30 04:38:24 macallan Exp $ */ +/* $NetBSD: pci_usrreq.c,v 1.23 2011/02/10 12:37:58 jmcneill Exp $ */ /* * Copyright 2001 Wasabi Systems, Inc. @@ -40,7 +40,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: pci_usrreq.c,v 1.22 2009/07/30 04:38:24 macallan Exp $"); +__KERNEL_RCSID(0, "$NetBSD: pci_usrreq.c,v 1.23 2011/02/10 12:37:58 jmcneill Exp $"); #include #include @@ -114,6 +114,10 @@ static paddr_t pcimmap(dev_t dev, off_t offset, int prot) { struct pci_softc *sc = device_lookup_private(&pci_cd, minor(dev)); + struct pci_child *c; + struct pci_range *r; + int flags = 0; + int device, range; if (kauth_authorize_generic(kauth_cred_get(), KAUTH_GENERIC_ISSUSER, NULL) != 0) { @@ -124,7 +128,7 @@ pcimmap(dev_t dev, off_t offset, int prot) * take the offset to be the address on the bus, * and pass 0 as the offset into that range. * - * XXX Need a way to deal with linear/prefetchable/etc. + * XXX Need a way to deal with linear/etc. * * XXX we rely on MD mmap() methods to enforce limits since these * are hidden in *_tag_t structs if they exist at all @@ -145,7 +149,24 @@ pcimmap(dev_t dev, off_t offset, int prot) 0, prot, 0); } #endif /* PCI_MAGIC_IO_RANGE */ - return bus_space_mmap(sc->sc_memt, offset, 0, prot, 0); + + for (device = 0; device < __arraycount(sc->sc_devices); device++) { + c = &sc->sc_devices[device]; + if (c->c_dev == NULL) + continue; + for (range = 0; range < __arraycount(c->c_range); range++) { + r = &c->c_range[range]; + if (r->r_size == 0) + break; + if (offset >= r->r_offset && + offset < r->r_offset + r->r_size) { + flags = r->r_flags; + break; + } + } + } + + return bus_space_mmap(sc->sc_memt, offset, 0, prot, flags); } const struct cdevsw pci_cdevsw = { diff --git a/sys/dev/pci/pcivar.h b/sys/dev/pci/pcivar.h index f3b0a991347f..2bc706a466c3 100644 --- a/sys/dev/pci/pcivar.h +++ b/sys/dev/pci/pcivar.h @@ -1,4 +1,4 @@ -/* $NetBSD: pcivar.h,v 1.90 2010/06/09 02:39:32 mrg Exp $ */ +/* $NetBSD: pcivar.h,v 1.91 2011/02/10 12:37:58 jmcneill Exp $ */ /* * Copyright (c) 1996, 1997 Christopher G. Demetriou. All rights reserved. @@ -196,11 +196,18 @@ struct pci_conf_state { pcireg_t reg[16]; }; +struct pci_range { + bus_addr_t r_offset; + bus_size_t r_size; + int r_flags; +}; + struct pci_child { device_t c_dev; bool c_psok; pcireg_t c_powerstate; struct pci_conf_state c_conf; + struct pci_range c_range[8]; }; struct pci_softc {