summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2009-12-30 20:47:14 +0000
committerjhb <jhb@FreeBSD.org>2009-12-30 20:47:14 +0000
commit9b53c8050d11d206fc12ee51b23d56389bd41bd3 (patch)
tree2e18981b24feef6425f28326218e699e93b7e1d7 /sys
parent8c20c2b016bbf46383564d9219cd1f96c9d02af5 (diff)
downloadFreeBSD-src-9b53c8050d11d206fc12ee51b23d56389bd41bd3.zip
FreeBSD-src-9b53c8050d11d206fc12ee51b23d56389bd41bd3.tar.gz
Teach the PCI bus driver to handle PCIR_BIOS BARs properly and remove special
handling for the PCIR_BIOS decoding enable bit from the cardbus driver. The PCIR_BIOS BAR does include type bits like other BARs. Instead, it is always a 32-bit non-prefetchable memory BAR where the low bit is used as a flag to enable decoding. Reviewed by: imp
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/cardbus/cardbus_cis.c6
-rw-r--r--sys/dev/pci/pci.c83
-rw-r--r--sys/dev/pci/pci_private.h2
3 files changed, 81 insertions, 10 deletions
diff --git a/sys/dev/cardbus/cardbus_cis.c b/sys/dev/cardbus/cardbus_cis.c
index 9d443b2..5e52c3b 100644
--- a/sys/dev/cardbus/cardbus_cis.c
+++ b/sys/dev/cardbus/cardbus_cis.c
@@ -430,9 +430,6 @@ cardbus_read_tuple_finish(device_t cbdev, device_t child, int rid,
{
if (res != CIS_CONFIG_SPACE) {
bus_release_resource(child, SYS_RES_MEMORY, rid, res);
- if (rid == PCIM_CIS_ASI_ROM)
- pci_write_config(child, rid, pci_read_config(child,
- rid, 4) & ~PCIR_BIOS, 4);
}
}
@@ -477,9 +474,6 @@ cardbus_read_tuple_init(device_t cbdev, device_t child, uint32_t *start,
return (NULL);
}
DEVPRINTF((cbdev, "CIS Mapped to %#lx\n", rman_get_start(res)));
- if (*rid == PCIR_BIOS)
- pci_write_config(child, *rid,
- rman_get_start(res) | PCIM_BIOS_ENABLE, 4);
/* Flip to the right ROM image if CIS is in ROM */
if (space == PCIM_CIS_ASI_ROM) {
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c
index b4b4051..008377a 100644
--- a/sys/dev/pci/pci.c
+++ b/sys/dev/pci/pci.c
@@ -80,6 +80,8 @@ static pci_addr_t pci_mapbase(uint64_t mapreg);
static const char *pci_maptype(uint64_t mapreg);
static int pci_mapsize(uint64_t testval);
static int pci_maprange(uint64_t mapreg);
+static pci_addr_t pci_rombase(uint64_t mapreg);
+static int pci_romsize(uint64_t testval);
static void pci_fixancient(pcicfgregs *cfg);
static int pci_printf(pcicfgregs *cfg, const char *fmt, ...);
@@ -142,7 +144,7 @@ static device_method_t pci_methods[] = {
DEVMETHOD(bus_alloc_resource, pci_alloc_resource),
DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource),
DEVMETHOD(bus_activate_resource, pci_activate_resource),
- DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+ DEVMETHOD(bus_deactivate_resource, pci_deactivate_resource),
DEVMETHOD(bus_child_pnpinfo_str, pci_child_pnpinfo_str_method),
DEVMETHOD(bus_child_location_str, pci_child_location_str_method),
@@ -388,6 +390,34 @@ pci_mapsize(uint64_t testval)
return (ln2size);
}
+/* return base address of device ROM */
+
+static pci_addr_t
+pci_rombase(uint64_t mapreg)
+{
+
+ return (mapreg & PCIM_BIOS_ADDR_MASK);
+}
+
+/* return log2 of map size decided for device ROM */
+
+static int
+pci_romsize(uint64_t testval)
+{
+ int ln2size;
+
+ testval = pci_rombase(testval);
+ ln2size = 0;
+ if (testval != 0) {
+ while ((testval & 1) == 0)
+ {
+ ln2size++;
+ testval >>= 1;
+ }
+ }
+ return (ln2size);
+}
+
/* return log2 of address range supported by map register */
static int
@@ -2280,6 +2310,21 @@ pci_read_bar(device_t dev, int reg, pci_addr_t *mapp, pci_addr_t *testvalp)
int ln2range;
uint16_t cmd;
+ /*
+ * The device ROM BAR is special. It is always a 32-bit
+ * memory BAR. Bit 0 is special and should not be set when
+ * sizing the BAR.
+ */
+ if (reg == PCIR_BIOS) {
+ map = pci_read_config(dev, reg, 4);
+ pci_write_config(dev, reg, 0xfffffffe, 4);
+ testval = pci_read_config(dev, reg, 4);
+ pci_write_config(dev, reg, map, 4);
+ *mapp = map;
+ *testvalp = testval;
+ return;
+ }
+
map = pci_read_config(dev, reg, 4);
ln2range = pci_maprange(map);
if (ln2range == 64)
@@ -2327,6 +2372,10 @@ pci_write_bar(device_t dev, int reg, pci_addr_t base)
int ln2range;
map = pci_read_config(dev, reg, 4);
+
+ /* The device ROM BAR is always 32-bits. */
+ if (reg == PCIR_BIOS)
+ return;
ln2range = pci_maprange(map);
pci_write_config(dev, reg, base, 4);
if (ln2range == 64)
@@ -3579,10 +3628,11 @@ pci_reserve_map(device_t dev, device_t child, int type, int *rid,
pci_read_bar(child, *rid, &map, &testval);
/* Ignore a BAR with a base of 0. */
- if (pci_mapbase(testval) == 0)
+ if ((*rid == PCIR_BIOS && pci_rombase(testval) == 0) ||
+ pci_mapbase(testval) == 0)
goto out;
- if (PCI_BAR_MEM(testval)) {
+ if (PCI_BAR_MEM(testval) || *rid == PCIR_BIOS) {
if (type != SYS_RES_MEMORY) {
if (bootverbose)
device_printf(dev,
@@ -3608,8 +3658,13 @@ pci_reserve_map(device_t dev, device_t child, int type, int *rid,
* actually uses and we would otherwise have a
* situation where we might allocate the excess to
* another driver, which won't work.
+ *
+ * Device ROM BARs use a different mask value.
*/
- mapsize = pci_mapsize(testval);
+ if (*rid == PCIR_BIOS)
+ mapsize = pci_romsize(testval);
+ else
+ mapsize = pci_mapsize(testval);
count = 1UL << mapsize;
if (RF_ALIGNMENT(flags) < mapsize)
flags = (flags & ~RF_ALIGNMENT_MASK) | RF_ALIGNMENT_LOG2(mapsize);
@@ -3711,6 +3766,10 @@ pci_activate_resource(device_t dev, device_t child, int type, int rid,
/* Enable decoding in the command register when activating BARs. */
if (device_get_parent(child) == dev) {
+ /* Device ROMs need their decoding explicitly enabled. */
+ if (rid == PCIR_BIOS)
+ pci_write_config(child, rid, rman_get_start(r) |
+ PCIM_BIOS_ENABLE, 4);
switch (type) {
case SYS_RES_IOPORT:
case SYS_RES_MEMORY:
@@ -3721,6 +3780,22 @@ pci_activate_resource(device_t dev, device_t child, int type, int rid,
return (error);
}
+int
+pci_deactivate_resource(device_t dev, device_t child, int type,
+ int rid, struct resource *r)
+{
+ int error;
+
+ error = bus_generic_deactivate_resource(dev, child, type, rid, r);
+ if (error)
+ return (error);
+
+ /* Disable decoding for device ROMs. */
+ if (rid == PCIR_BIOS)
+ pci_write_config(child, rid, rman_get_start(r), 4);
+ return (0);
+}
+
void
pci_delete_resource(device_t dev, device_t child, int type, int rid)
{
diff --git a/sys/dev/pci/pci_private.h b/sys/dev/pci/pci_private.h
index d75e457..1cb28e9 100644
--- a/sys/dev/pci/pci_private.h
+++ b/sys/dev/pci/pci_private.h
@@ -84,6 +84,8 @@ struct resource *pci_alloc_resource(device_t dev, device_t child,
u_int flags);
int pci_activate_resource(device_t dev, device_t child, int type,
int rid, struct resource *r);
+int pci_deactivate_resource(device_t dev, device_t child, int type,
+ int rid, struct resource *r);
void pci_delete_resource(device_t dev, device_t child,
int type, int rid);
struct resource_list *pci_get_resource_list (device_t dev, device_t child);
OpenPOWER on IntegriCloud