coreboot-kgpe-d16/src/device/pci_ops.c
Kyösti Mälkki aad0747216 Redefine pci_bus_default_ops as function
Taking device_t as a parameter, this allows to alter the PCI config
access handlers. This is useful to add tracing of PCI config writes
for devices having problems to initialise correctly.

On older AMD platform PCI MMIO may not be able to fully configure all
PCI devices/nodes, while MMIO_SUPPORT_DEFAULT would be preferred due
to its atomic nature. So those can be forced to IO config instead.

Change-Id: I2162884185bbfe461b036caf737980b45a51e522
Signed-off-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
Reviewed-on: http://review.coreboot.org/3608
Tested-by: build bot (Jenkins)
Reviewed-by: Aaron Durbin <adurbin@google.com>
2013-07-25 11:35:58 +02:00

170 lines
4.7 KiB
C

/*
* This file is part of the coreboot project.
*
* Copyright (C) 2004 Linux Networx
* (Written by Eric Biederman <ebiederman@lnxi.com> for Linux Networx)
* Copyright (C) 2009 coresystems GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <console/console.h>
#include <arch/pciconf.h>
#include <device/pci.h>
#include <device/pci_ids.h>
#include <device/pci_ops.h>
const struct pci_bus_operations *pci_bus_default_ops(device_t dev)
{
#if CONFIG_MMCONF_SUPPORT_DEFAULT
return &pci_ops_mmconf;
#else
return &pci_cf8_conf1;
#endif
}
static const struct pci_bus_operations *pci_bus_ops(struct bus *bus, device_t dev)
{
const struct pci_bus_operations *bops;
bops = NULL;
if (bus && bus->dev && bus->dev->ops && bus->dev->ops->ops_pci_bus) {
bops = bus->dev->ops->ops_pci_bus(dev);
}
if (!bops)
bops = pci_bus_default_ops(dev);
return bops;
}
/*
* The only consumer of the return value of get_pbus() is pci_bus_ops().
* pci_bus_ops() can handle being passed NULL and auto-picks working ops.
*/
static struct bus *get_pbus(device_t dev)
{
struct bus *pbus = NULL;
if (!dev)
die("get_pbus: dev is NULL!\n");
else
pbus = dev->bus;
while (pbus && pbus->dev && !pci_bus_ops(pbus, dev)) {
if (pbus == pbus->dev->bus) {
printk(BIOS_ALERT, "%s in endless loop looking for a "
"parent bus with pci_bus_ops for %s, breaking "
"out.\n", __func__, dev_path(dev));
break;
}
pbus = pbus->dev->bus;
}
if (!pbus || !pbus->dev || !pbus->dev->ops
|| !pbus->dev->ops->ops_pci_bus) {
/* This can happen before the device tree is fully set up. */
// printk(BIOS_EMERG, "%s: Cannot find PCI bus operations.\n",
// dev_path(dev));
pbus = NULL;
}
return pbus;
}
u8 pci_read_config8(device_t dev, unsigned int where)
{
struct bus *pbus = get_pbus(dev);
return pci_bus_ops(pbus, dev)->read8(pbus, dev->bus->secondary,
dev->path.pci.devfn, where);
}
u16 pci_read_config16(device_t dev, unsigned int where)
{
struct bus *pbus = get_pbus(dev);
return pci_bus_ops(pbus, dev)->read16(pbus, dev->bus->secondary,
dev->path.pci.devfn, where);
}
u32 pci_read_config32(device_t dev, unsigned int where)
{
struct bus *pbus = get_pbus(dev);
return pci_bus_ops(pbus, dev)->read32(pbus, dev->bus->secondary,
dev->path.pci.devfn, where);
}
void pci_write_config8(device_t dev, unsigned int where, u8 val)
{
struct bus *pbus = get_pbus(dev);
pci_bus_ops(pbus, dev)->write8(pbus, dev->bus->secondary,
dev->path.pci.devfn, where, val);
}
void pci_write_config16(device_t dev, unsigned int where, u16 val)
{
struct bus *pbus = get_pbus(dev);
pci_bus_ops(pbus, dev)->write16(pbus, dev->bus->secondary,
dev->path.pci.devfn, where, val);
}
void pci_write_config32(device_t dev, unsigned int where, u32 val)
{
struct bus *pbus = get_pbus(dev);
pci_bus_ops(pbus, dev)->write32(pbus, dev->bus->secondary,
dev->path.pci.devfn, where, val);
}
#if CONFIG_MMCONF_SUPPORT
u8 pci_mmio_read_config8(device_t dev, unsigned int where)
{
struct bus *pbus = get_pbus(dev);
return pci_ops_mmconf.read8(pbus, dev->bus->secondary,
dev->path.pci.devfn, where);
}
u16 pci_mmio_read_config16(device_t dev, unsigned int where)
{
struct bus *pbus = get_pbus(dev);
return pci_ops_mmconf.read16(pbus, dev->bus->secondary,
dev->path.pci.devfn, where);
}
u32 pci_mmio_read_config32(device_t dev, unsigned int where)
{
struct bus *pbus = get_pbus(dev);
return pci_ops_mmconf.read32(pbus, dev->bus->secondary,
dev->path.pci.devfn, where);
}
void pci_mmio_write_config8(device_t dev, unsigned int where, u8 val)
{
struct bus *pbus = get_pbus(dev);
pci_ops_mmconf.write8(pbus, dev->bus->secondary, dev->path.pci.devfn,
where, val);
}
void pci_mmio_write_config16(device_t dev, unsigned int where, u16 val)
{
struct bus *pbus = get_pbus(dev);
pci_ops_mmconf.write16(pbus, dev->bus->secondary, dev->path.pci.devfn,
where, val);
}
void pci_mmio_write_config32(device_t dev, unsigned int where, u32 val)
{
struct bus *pbus = get_pbus(dev);
pci_ops_mmconf.write32(pbus, dev->bus->secondary, dev->path.pci.devfn,
where, val);
}
#endif