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
This commit is contained in:
John Baldwin 2009-12-30 20:47:14 +00:00
parent f26d7f8e95
commit 4e8790e943
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=201279
3 changed files with 81 additions and 10 deletions

View File

@ -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) {

View File

@ -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)
{

View File

@ -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);