summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/dev/pci
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2013-11-04 11:33:00 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2013-11-04 15:28:21 +0100
commitaf5333e0a02b2295304d4e029b15ee15a4fe2b3a (patch)
treec5c43680d374f58b487eeeaf18fb7ec6b84ba074 /freebsd/sys/dev/pci
parentBUS_SPACE(9): Use simple memory model for ARM (diff)
downloadrtems-libbsd-af5333e0a02b2295304d4e029b15ee15a4fe2b3a.tar.bz2
Update to FreeBSD 8.4
Diffstat (limited to 'freebsd/sys/dev/pci')
-rw-r--r--freebsd/sys/dev/pci/pci.c536
-rw-r--r--freebsd/sys/dev/pci/pci_pci.c659
-rw-r--r--freebsd/sys/dev/pci/pci_private.h7
-rw-r--r--freebsd/sys/dev/pci/pci_user.c53
-rw-r--r--freebsd/sys/dev/pci/pcib_private.h31
-rw-r--r--freebsd/sys/dev/pci/pcireg.h331
-rw-r--r--freebsd/sys/dev/pci/pcivar.h28
7 files changed, 1447 insertions, 198 deletions
diff --git a/freebsd/sys/dev/pci/pci.c b/freebsd/sys/dev/pci/pci.c
index 8552fdb7..1a3b2312 100644
--- a/freebsd/sys/dev/pci/pci.c
+++ b/freebsd/sys/dev/pci/pci.c
@@ -82,10 +82,31 @@ __FBSDID("$FreeBSD$");
#define ACPI_PWR_FOR_SLEEP(x, y, z)
#endif
+/*
+ * XXX: Due to a limitation of the bus_dma_tag_create() API, we cannot
+ * specify a 4GB boundary on 32-bit targets. Usually this does not
+ * matter as it is ok to use a boundary of 0 on these systems.
+ * However, in the case of PAE, DMA addresses can cross a 4GB
+ * boundary, so as a workaround use a 2GB boundary.
+ */
+#if (BUS_SPACE_MAXADDR > 0xFFFFFFFF)
+#ifdef PAE
+#define PCI_DMA_BOUNDARY 0x80000000
+#else
+#define PCI_DMA_BOUNDARY 0x100000000
+#endif
+#endif
+
+#define PCIR_IS_BIOS(cfg, reg) \
+ (((cfg)->hdrtype == PCIM_HDRTYPE_NORMAL && reg == PCIR_BIOS) || \
+ ((cfg)->hdrtype == PCIM_HDRTYPE_BRIDGE && reg == PCIR_BIOS_1))
+
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, ...);
@@ -101,10 +122,11 @@ static void pci_load_vendor_data(void);
static int pci_describe_parse_line(char **ptr, int *vendor,
int *device, char **desc);
static char *pci_describe_device(device_t dev);
+static bus_dma_tag_t pci_get_dma_tag(device_t bus, device_t dev);
static int pci_modevent(module_t mod, int what, void *arg);
static void pci_hdrtypedata(device_t pcib, int b, int s, int f,
pcicfgregs *cfg);
-static void pci_read_extcap(device_t pcib, pcicfgregs *cfg);
+static void pci_read_cap(device_t pcib, pcicfgregs *cfg);
static int pci_read_vpd_reg(device_t pcib, pcicfgregs *cfg,
int reg, uint32_t *data);
#if 0
@@ -143,14 +165,16 @@ static device_method_t pci_methods[] = {
DEVMETHOD(bus_setup_intr, pci_setup_intr),
DEVMETHOD(bus_teardown_intr, pci_teardown_intr),
+ DEVMETHOD(bus_get_dma_tag, pci_get_dma_tag),
DEVMETHOD(bus_get_resource_list,pci_get_resource_list),
DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource),
DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource),
DEVMETHOD(bus_delete_resource, pci_delete_resource),
DEVMETHOD(bus_alloc_resource, pci_alloc_resource),
+ DEVMETHOD(bus_adjust_resource, bus_generic_adjust_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),
DEVMETHOD(bus_remap_intr, pci_remap_intr_method),
@@ -175,10 +199,10 @@ static device_method_t pci_methods[] = {
DEVMETHOD(pci_msi_count, pci_msi_count_method),
DEVMETHOD(pci_msix_count, pci_msix_count_method),
- { 0, 0 }
+ DEVMETHOD_END
};
-DEFINE_CLASS_0(pci, pci_driver, pci_methods, 0);
+DEFINE_CLASS_0(pci, pci_driver, pci_methods, sizeof(struct pci_softc));
static devclass_t pci_devclass;
DRIVER_MODULE(pci, pcib, pci_driver, pci_devclass, pci_modevent, 0);
@@ -187,18 +211,18 @@ MODULE_VERSION(pci, 1);
static char *pci_vendordata;
static size_t pci_vendordata_size;
-
struct pci_quirk {
uint32_t devid; /* Vendor/device of the card */
int type;
#define PCI_QUIRK_MAP_REG 1 /* PCI map register in weird place */
#define PCI_QUIRK_DISABLE_MSI 2 /* MSI/MSI-X doesn't work */
#define PCI_QUIRK_ENABLE_MSI_VM 3 /* Older chipset in VM where MSI works */
+#define PCI_QUIRK_UNMAP_REG 4 /* Ignore PCI map register */
int arg1;
int arg2;
};
-struct pci_quirk pci_quirks[] = {
+static const struct pci_quirk pci_quirks[] = {
/* The Intel 82371AB and 82443MX has a map register at offset 0x90. */
{ 0x71138086, PCI_QUIRK_MAP_REG, 0x90, 0 },
{ 0x719b8086, PCI_QUIRK_MAP_REG, 0x90, 0 },
@@ -231,11 +255,28 @@ struct pci_quirk pci_quirks[] = {
{ 0x74501022, PCI_QUIRK_DISABLE_MSI, 0, 0 },
/*
+ * MSI-X allocation doesn't work properly for devices passed through
+ * by VMware up to at least ESXi 5.1.
+ */
+ { 0x079015ad, PCI_QUIRK_DISABLE_MSI, 0, 0 }, /* PCI/PCI-X */
+ { 0x07a015ad, PCI_QUIRK_DISABLE_MSI, 0, 0 }, /* PCIe */
+
+ /*
* Some virtualization environments emulate an older chipset
* but support MSI just fine. QEMU uses the Intel 82440.
*/
{ 0x12378086, PCI_QUIRK_ENABLE_MSI_VM, 0, 0 },
+ /*
+ * HPET MMIO base address may appear in Bar1 for AMD SB600 SMBus
+ * controller depending on SoftPciRst register (PM_IO 0x55 [7]).
+ * It prevents us from attaching hpet(4) when the bit is unset.
+ * Note this quirk only affects SB600 revision A13 and earlier.
+ * For SB600 A21 and later, firmware must set the bit to hide it.
+ * For SB700 and later, it is unused and hardcoded to zero.
+ */
+ { 0x43851002, PCI_QUIRK_UNMAP_REG, 0x14, 0 },
+
{ 0 }
};
@@ -296,7 +337,7 @@ static int pci_usb_takeover = 1;
static int pci_usb_takeover = 0;
#endif
TUNABLE_INT("hw.pci.usb_early_takeover", &pci_usb_takeover);
-SYSCTL_INT(_hw_pci, OID_AUTO, usb_early_takeover, CTLFLAG_RD | CTLFLAG_TUN,
+SYSCTL_INT(_hw_pci, OID_AUTO, usb_early_takeover, CTLFLAG_RDTUN,
&pci_usb_takeover, 1, "Enable early takeover of USB controllers.\n\
Disable this if you depend on BIOS emulation of USB devices, that is\n\
you use USB devices (like keyboard or mouse) but do not load USB drivers");
@@ -348,6 +389,21 @@ pci_find_device(uint16_t vendor, uint16_t device)
}
#endif /* __rtems__ */
+device_t
+pci_find_class(uint8_t class, uint8_t subclass)
+{
+ struct pci_devinfo *dinfo;
+
+ STAILQ_FOREACH(dinfo, &pci_devq, pci_links) {
+ if (dinfo->cfg.baseclass == class &&
+ dinfo->cfg.subclass == subclass) {
+ return (dinfo->cfg.dev);
+ }
+ }
+
+ return (NULL);
+}
+
static int
pci_printf(pcicfgregs *cfg, const char *fmt, ...)
{
@@ -406,6 +462,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
@@ -510,12 +594,13 @@ pci_read_device(device_t pcib, int d, int b, int s, int f, size_t size)
cfg->mfdev = (cfg->hdrtype & PCIM_MFDEV) != 0;
cfg->hdrtype &= ~PCIM_MFDEV;
+ STAILQ_INIT(&cfg->maps);
pci_fixancient(cfg);
pci_hdrtypedata(pcib, b, s, f, cfg);
if (REG(PCIR_STATUS, 2) & PCIM_STATUS_CAPPRESENT)
- pci_read_extcap(pcib, cfg);
+ pci_read_cap(pcib, cfg);
STAILQ_INSERT_TAIL(devlist_head, devlist_entry, pci_links);
@@ -543,7 +628,7 @@ pci_read_device(device_t pcib, int d, int b, int s, int f, size_t size)
}
static void
-pci_read_extcap(device_t pcib, pcicfgregs *cfg)
+pci_read_cap(device_t pcib, pcicfgregs *cfg)
{
#define REG(n, w) PCIB_READ_CONFIG(pcib, cfg->bus, cfg->slot, cfg->func, n, w)
#define WREG(n, v, w) PCIB_WRITE_CONFIG(pcib, cfg->bus, cfg->slot, cfg->func, n, v, w)
@@ -591,10 +676,14 @@ pci_read_extcap(device_t pcib, pcicfgregs *cfg)
cfg->pp.pp_data = ptr + PCIR_POWER_DATA;
}
break;
-#if defined(__i386__) || defined(__amd64__) || defined(__powerpc__)
case PCIY_HT: /* HyperTransport */
/* Determine HT-specific capability type. */
val = REG(ptr + PCIR_HT_COMMAND, 2);
+
+ if ((val & 0xe000) == PCIM_HTCAP_SLAVE)
+ cfg->ht.ht_slave = ptr;
+
+#if defined(__i386__) || defined(__amd64__) || defined(__powerpc__)
switch (val & PCIM_HTCMD_CAP_MASK) {
case PCIM_HTCAP_MSI_MAPPING:
if (!(val & PCIM_HTCMD_MSI_FIXED)) {
@@ -606,7 +695,7 @@ pci_read_extcap(device_t pcib, pcicfgregs *cfg)
4);
if (addr != MSI_INTEL_ADDR_BASE)
device_printf(pcib,
- "HT Bridge at pci%d:%d:%d:%d has non-default MSI window 0x%llx\n",
+ "HT device at pci%d:%d:%d:%d has non-default MSI window 0x%llx\n",
cfg->domain, cfg->bus,
cfg->slot, cfg->func,
(long long)addr);
@@ -618,8 +707,8 @@ pci_read_extcap(device_t pcib, pcicfgregs *cfg)
cfg->ht.ht_msiaddr = addr;
break;
}
- break;
#endif
+ break;
case PCIY_MSI: /* PCI MSI */
cfg->msi.msi_location = ptr;
cfg->msi.msi_ctrl = REG(ptr + PCIR_MSI_CTRL, 2);
@@ -673,6 +762,23 @@ pci_read_extcap(device_t pcib, pcicfgregs *cfg)
break;
}
}
+
+#if defined(__powerpc__)
+ /*
+ * Enable the MSI mapping window for all HyperTransport
+ * slaves. PCI-PCI bridges have their windows enabled via
+ * PCIB_MAP_MSI().
+ */
+ if (cfg->ht.ht_slave != 0 && cfg->ht.ht_msimap != 0 &&
+ !(cfg->ht.ht_msictrl & PCIM_HTCMD_MSI_ENABLE)) {
+ device_printf(pcib,
+ "Enabling MSI window for HyperTransport slave at pci%d:%d:%d:%d\n",
+ cfg->domain, cfg->bus, cfg->slot, cfg->func);
+ cfg->ht.ht_msictrl |= PCIM_HTCMD_MSI_ENABLE;
+ WREG(cfg->ht.ht_msimap + PCIR_HT_COMMAND, cfg->ht.ht_msictrl,
+ 2);
+ }
+#endif
/* REG and WREG use carry through to next functions */
}
@@ -1068,11 +1174,9 @@ pci_get_vpd_readonly_method(device_t dev, device_t child, const char *kw,
if (memcmp(kw, cfg->vpd.vpd_ros[i].keyword,
sizeof(cfg->vpd.vpd_ros[i].keyword)) == 0) {
*vptr = cfg->vpd.vpd_ros[i].value;
+ return (0);
}
- if (i != cfg->vpd.vpd_rocnt)
- return (0);
-
*vptr = NULL;
return (ENXIO);
}
@@ -1286,8 +1390,11 @@ pci_alloc_msix_method(device_t dev, device_t child, int *count)
for (i = 0; i < max; i++) {
/* Allocate a message. */
error = PCIB_ALLOC_MSIX(device_get_parent(dev), child, &irq);
- if (error)
+ if (error) {
+ if (i == 0)
+ return (error);
break;
+ }
resource_list_add(&dinfo->resources, SYS_RES_IRQ, i + 1, irq,
irq, 1);
}
@@ -1620,10 +1727,10 @@ pci_get_max_read_req(device_t dev)
int cap;
uint16_t val;
- if (pci_find_extcap(dev, PCIY_EXPRESS, &cap) != 0)
+ if (pci_find_cap(dev, PCIY_EXPRESS, &cap) != 0)
return (0);
- val = pci_read_config(dev, cap + PCIR_EXPRESS_DEVICE_CTL, 2);
- val &= PCIM_EXP_CTL_MAX_READ_REQUEST;
+ val = pci_read_config(dev, cap + PCIER_DEVICE_CTL, 2);
+ val &= PCIEM_CTL_MAX_READ_REQUEST;
val >>= 12;
return (1 << (val + 7));
}
@@ -1634,17 +1741,17 @@ pci_set_max_read_req(device_t dev, int size)
int cap;
uint16_t val;
- if (pci_find_extcap(dev, PCIY_EXPRESS, &cap) != 0)
+ if (pci_find_cap(dev, PCIY_EXPRESS, &cap) != 0)
return (0);
if (size < 128)
size = 128;
if (size > 4096)
size = 4096;
size = (1 << (fls(size) - 1));
- val = pci_read_config(dev, cap + PCIR_EXPRESS_DEVICE_CTL, 2);
- val &= ~PCIM_EXP_CTL_MAX_READ_REQUEST;
+ val = pci_read_config(dev, cap + PCIER_DEVICE_CTL, 2);
+ val &= ~PCIEM_CTL_MAX_READ_REQUEST;
val |= (fls(size) - 8) << 12;
- pci_write_config(dev, cap + PCIR_EXPRESS_DEVICE_CTL, val, 2);
+ pci_write_config(dev, cap + PCIER_DEVICE_CTL, val, 2);
return (size);
}
@@ -1804,7 +1911,7 @@ pci_remap_intr_method(device_t bus, device_t dev, u_int irq)
int
pci_msi_device_blacklisted(device_t dev)
{
- struct pci_quirk *q;
+ const struct pci_quirk *q;
if (!pci_honor_msi_blacklist)
return (0);
@@ -1824,7 +1931,7 @@ pci_msi_device_blacklisted(device_t dev)
static int
pci_msi_vm_chipset(device_t dev)
{
- struct pci_quirk *q;
+ const struct pci_quirk *q;
for (q = &pci_quirks[0]; q->devid; q++) {
if (q->devid == pci_get_devid(dev) &&
@@ -1918,7 +2025,7 @@ pci_alloc_msi_method(device_t dev, device_t child, int *count)
for (;;) {
/* Try to allocate N messages. */
error = PCIB_ALLOC_MSI(device_get_parent(dev), child, actual,
- cfg->msi.msi_msgnum, irqs);
+ actual, irqs);
if (error == 0)
break;
if (actual == 1)
@@ -2061,6 +2168,7 @@ int
pci_freecfg(struct pci_devinfo *dinfo)
{
struct devlist *devlist_head;
+ struct pci_map *pm, *next;
int i;
devlist_head = &pci_devq;
@@ -2074,6 +2182,9 @@ pci_freecfg(struct pci_devinfo *dinfo)
free(dinfo->cfg.vpd.vpd_w[i].value, M_DEVBUF);
free(dinfo->cfg.vpd.vpd_w, M_DEVBUF);
}
+ STAILQ_FOREACH_SAFE(pm, &dinfo->cfg.maps, pm_link, next) {
+ free(pm, M_DEVBUF);
+ }
STAILQ_REMOVE(devlist_head, dinfo, pci_devinfo, pci_links);
free(dinfo, M_DEVBUF);
@@ -2348,10 +2459,27 @@ pci_memen(device_t dev)
static void
pci_read_bar(device_t dev, int reg, pci_addr_t *mapp, pci_addr_t *testvalp)
{
+ struct pci_devinfo *dinfo;
pci_addr_t map, testval;
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.
+ */
+ dinfo = device_get_ivars(dev);
+ if (PCIR_IS_BIOS(&dinfo->cfg, reg)) {
+ 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)
@@ -2393,16 +2521,100 @@ pci_read_bar(device_t dev, int reg, pci_addr_t *mapp, pci_addr_t *testvalp)
}
static void
-pci_write_bar(device_t dev, int reg, pci_addr_t base)
+pci_write_bar(device_t dev, struct pci_map *pm, pci_addr_t base)
{
- pci_addr_t map;
+ struct pci_devinfo *dinfo;
int ln2range;
- map = pci_read_config(dev, reg, 4);
- ln2range = pci_maprange(map);
- pci_write_config(dev, reg, base, 4);
+ /* The device ROM BAR is always a 32-bit memory BAR. */
+ dinfo = device_get_ivars(dev);
+ if (PCIR_IS_BIOS(&dinfo->cfg, pm->pm_reg))
+ ln2range = 32;
+ else
+ ln2range = pci_maprange(pm->pm_value);
+ pci_write_config(dev, pm->pm_reg, base, 4);
+ if (ln2range == 64)
+ pci_write_config(dev, pm->pm_reg + 4, base >> 32, 4);
+ pm->pm_value = pci_read_config(dev, pm->pm_reg, 4);
if (ln2range == 64)
- pci_write_config(dev, reg + 4, base >> 32, 4);
+ pm->pm_value |= (pci_addr_t)pci_read_config(dev,
+ pm->pm_reg + 4, 4) << 32;
+}
+
+struct pci_map *
+pci_find_bar(device_t dev, int reg)
+{
+ struct pci_devinfo *dinfo;
+ struct pci_map *pm;
+
+ dinfo = device_get_ivars(dev);
+ STAILQ_FOREACH(pm, &dinfo->cfg.maps, pm_link) {
+ if (pm->pm_reg == reg)
+ return (pm);
+ }
+ return (NULL);
+}
+
+int
+pci_bar_enabled(device_t dev, struct pci_map *pm)
+{
+ struct pci_devinfo *dinfo;
+ uint16_t cmd;
+
+ dinfo = device_get_ivars(dev);
+ if (PCIR_IS_BIOS(&dinfo->cfg, pm->pm_reg) &&
+ !(pm->pm_value & PCIM_BIOS_ENABLE))
+ return (0);
+ cmd = pci_read_config(dev, PCIR_COMMAND, 2);
+ if (PCIR_IS_BIOS(&dinfo->cfg, pm->pm_reg) || PCI_BAR_MEM(pm->pm_value))
+ return ((cmd & PCIM_CMD_MEMEN) != 0);
+ else
+ return ((cmd & PCIM_CMD_PORTEN) != 0);
+}
+
+static struct pci_map *
+pci_add_bar(device_t dev, int reg, pci_addr_t value, pci_addr_t size)
+{
+ struct pci_devinfo *dinfo;
+ struct pci_map *pm, *prev;
+
+ dinfo = device_get_ivars(dev);
+ pm = malloc(sizeof(*pm), M_DEVBUF, M_WAITOK | M_ZERO);
+ pm->pm_reg = reg;
+ pm->pm_value = value;
+ pm->pm_size = size;
+ STAILQ_FOREACH(prev, &dinfo->cfg.maps, pm_link) {
+ KASSERT(prev->pm_reg != pm->pm_reg, ("duplicate map %02x",
+ reg));
+ if (STAILQ_NEXT(prev, pm_link) == NULL ||
+ STAILQ_NEXT(prev, pm_link)->pm_reg > pm->pm_reg)
+ break;
+ }
+ if (prev != NULL)
+ STAILQ_INSERT_AFTER(&dinfo->cfg.maps, prev, pm, pm_link);
+ else
+ STAILQ_INSERT_TAIL(&dinfo->cfg.maps, pm, pm_link);
+ return (pm);
+}
+
+static void
+pci_restore_bars(device_t dev)
+{
+ struct pci_devinfo *dinfo;
+ struct pci_map *pm;
+ int ln2range;
+
+ dinfo = device_get_ivars(dev);
+ STAILQ_FOREACH(pm, &dinfo->cfg.maps, pm_link) {
+ if (PCIR_IS_BIOS(&dinfo->cfg, pm->pm_reg))
+ ln2range = 32;
+ else
+ ln2range = pci_maprange(pm->pm_value);
+ pci_write_config(dev, pm->pm_reg, pm->pm_value, 4);
+ if (ln2range == 64)
+ pci_write_config(dev, pm->pm_reg + 4,
+ pm->pm_value >> 32, 4);
+ }
}
/*
@@ -2413,12 +2625,24 @@ static int
pci_add_map(device_t bus, device_t dev, int reg, struct resource_list *rl,
int force, int prefetch)
{
+ struct pci_map *pm;
pci_addr_t base, map, testval;
pci_addr_t start, end, count;
int barlen, basezero, maprange, mapsize, type;
uint16_t cmd;
struct resource *res;
+ /*
+ * The BAR may already exist if the device is a CardBus card
+ * whose CIS is stored in this BAR.
+ */
+ pm = pci_find_bar(dev, reg);
+ if (pm != NULL) {
+ maprange = pci_maprange(pm->pm_value);
+ barlen = maprange == 64 ? 2 : 1;
+ return (barlen);
+ }
+
pci_read_bar(dev, reg, &map, &testval);
if (PCI_BAR_MEM(map)) {
type = SYS_RES_MEMORY;
@@ -2449,6 +2673,8 @@ pci_add_map(device_t bus, device_t dev, int reg, struct resource_list *rl,
(type == SYS_RES_IOPORT && mapsize < 2))
return (barlen);
+ /* Save a record of this BAR. */
+ pm = pci_add_bar(dev, reg, map, mapsize);
if (bootverbose) {
printf("\tmap[%02x]: type %s, range %2d, base %#jx, size %2d",
reg, pci_maptype(map), maprange, (uintmax_t)base, mapsize);
@@ -2507,13 +2733,13 @@ pci_add_map(device_t bus, device_t dev, int reg, struct resource_list *rl,
return (barlen);
}
- count = 1 << mapsize;
+ count = (pci_addr_t)1 << mapsize;
if (basezero || base == pci_mapbase(testval)) {
start = 0; /* Let the parent decide. */
- end = ~0ULL;
+ end = ~0ul;
} else {
start = base;
- end = base + (1 << mapsize) - 1;
+ end = base + count - 1;
}
resource_list_add(rl, type, reg, start, end, count);
@@ -2538,7 +2764,7 @@ pci_add_map(device_t bus, device_t dev, int reg, struct resource_list *rl,
start = rman_get_start(res);
rman_set_device(res, bus);
}
- pci_write_bar(dev, reg, start);
+ pci_write_bar(dev, pm, start);
return (barlen);
}
@@ -2780,12 +3006,18 @@ ehci_early_takeover(device_t self)
void
pci_add_resources(device_t bus, device_t dev, int force, uint32_t prefetchmask)
{
- struct pci_devinfo *dinfo = device_get_ivars(dev);
- pcicfgregs *cfg = &dinfo->cfg;
- struct resource_list *rl = &dinfo->resources;
- struct pci_quirk *q;
+ struct pci_devinfo *dinfo;
+ pcicfgregs *cfg;
+ struct resource_list *rl;
+ const struct pci_quirk *q;
+ uint32_t devid;
int i;
+ dinfo = device_get_ivars(dev);
+ cfg = &dinfo->cfg;
+ rl = &dinfo->resources;
+ devid = (cfg->device << 16) | cfg->vendor;
+
/* ATA devices needs special map treatment */
if ((pci_get_class(dev) == PCIC_STORAGE) &&
(pci_get_subclass(dev) == PCIS_STORAGE_IDE) &&
@@ -2794,18 +3026,29 @@ pci_add_resources(device_t bus, device_t dev, int force, uint32_t prefetchmask)
!pci_read_config(dev, PCIR_BAR(2), 4))) )
pci_ata_maps(bus, dev, rl, force, prefetchmask);
else
- for (i = 0; i < cfg->nummaps;)
+ for (i = 0; i < cfg->nummaps;) {
+ /*
+ * Skip quirked resources.
+ */
+ for (q = &pci_quirks[0]; q->devid != 0; q++)
+ if (q->devid == devid &&
+ q->type == PCI_QUIRK_UNMAP_REG &&
+ q->arg1 == PCIR_BAR(i))
+ break;
+ if (q->devid != 0) {
+ i++;
+ continue;
+ }
i += pci_add_map(bus, dev, PCIR_BAR(i), rl, force,
prefetchmask & (1 << i));
+ }
/*
* Add additional, quirked resources.
*/
- for (q = &pci_quirks[0]; q->devid; q++) {
- if (q->devid == ((cfg->device << 16) | cfg->vendor)
- && q->type == PCI_QUIRK_MAP_REG)
+ for (q = &pci_quirks[0]; q->devid != 0; q++)
+ if (q->devid == devid && q->type == PCI_QUIRK_MAP_REG)
pci_add_map(bus, dev, q->arg1, rl, force, 0);
- }
if (cfg->intpin > 0 && PCI_INTERRUPT_VALID(cfg->intline)) {
#ifdef __PCI_REROUTE_INTERRUPT
@@ -2889,10 +3132,49 @@ pci_probe(device_t dev)
return (BUS_PROBE_GENERIC);
}
+int
+pci_attach_common(device_t dev)
+{
+ struct pci_softc *sc;
+ int busno, domain;
+#ifdef PCI_DMA_BOUNDARY
+ int error, tag_valid;
+#endif
+
+ sc = device_get_softc(dev);
+ domain = pcib_get_domain(dev);
+ busno = pcib_get_bus(dev);
+ if (bootverbose)
+ device_printf(dev, "domain=%d, physical bus=%d\n",
+ domain, busno);
+#ifdef PCI_DMA_BOUNDARY
+ tag_valid = 0;
+ if (device_get_devclass(device_get_parent(device_get_parent(dev))) !=
+ devclass_find("pci")) {
+ error = bus_dma_tag_create(bus_get_dma_tag(dev), 1,
+ PCI_DMA_BOUNDARY, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR,
+ NULL, NULL, BUS_SPACE_MAXSIZE, BUS_SPACE_UNRESTRICTED,
+ BUS_SPACE_MAXSIZE, 0, NULL, NULL, &sc->sc_dma_tag);
+ if (error)
+ device_printf(dev, "Failed to create DMA tag: %d\n",
+ error);
+ else
+ tag_valid = 1;
+ }
+ if (!tag_valid)
+#endif
+ sc->sc_dma_tag = bus_get_dma_tag(dev);
+ return (0);
+}
+
static int
pci_attach(device_t dev)
{
- int busno, domain;
+ int busno, domain, error;
+
+ error = pci_attach_common(dev);
+ if (error)
+ return (error);
/*
* Since there can be multiple independantly numbered PCI
@@ -2902,9 +3184,6 @@ pci_attach(device_t dev)
*/
domain = pcib_get_domain(dev);
busno = pcib_get_bus(dev);
- if (bootverbose)
- device_printf(dev, "domain=%d, physical bus=%d\n",
- domain, busno);
pci_add_children(dev, domain, busno, sizeof(struct pci_devinfo));
return (bus_generic_attach(dev));
}
@@ -2927,7 +3206,7 @@ pci_suspend(device_t dev)
return (error);
for (i = 0; i < numdevs; i++) {
child = devlist[i];
- dinfo = (struct pci_devinfo *) device_get_ivars(child);
+ dinfo = device_get_ivars(child);
pci_cfg_save(child, dinfo, 0);
}
@@ -3215,11 +3494,11 @@ pci_print_child(device_t dev, device_t child)
return (retval);
}
-static struct
+static const struct
{
- int class;
- int subclass;
- char *desc;
+ int class;
+ int subclass;
+ const char *desc;
} pci_nomatch_tab[] = {
{PCIC_OLD, -1, "old"},
{PCIC_OLD, PCIS_OLD_NONVGA, "non-VGA display device"},
@@ -3233,6 +3512,7 @@ static struct
{PCIC_STORAGE, PCIS_STORAGE_ATA_ADMA, "ATA (ADMA)"},
{PCIC_STORAGE, PCIS_STORAGE_SATA, "SATA"},
{PCIC_STORAGE, PCIS_STORAGE_SAS, "SAS"},
+ {PCIC_STORAGE, PCIS_STORAGE_NVM, "NVM"},
{PCIC_NETWORK, -1, "network"},
{PCIC_NETWORK, PCIS_NETWORK_ETHERNET, "ethernet"},
{PCIC_NETWORK, PCIS_NETWORK_TOKENRING, "token ring"},
@@ -3310,8 +3590,9 @@ static struct
void
pci_probe_nomatch(device_t dev, device_t child)
{
- int i;
- char *cp, *scp, *device;
+ int i;
+ const char *cp, *scp;
+ char *device;
/*
* Look for a listing for this device in a loaded device database.
@@ -3343,8 +3624,7 @@ pci_probe_nomatch(device_t dev, device_t child)
}
printf(" at device %d.%d (no driver attached)\n",
pci_get_slot(child), pci_get_function(child));
- pci_cfg_save(child, (struct pci_devinfo *)device_get_ivars(child), 1);
- return;
+ pci_cfg_save(child, device_get_ivars(child), 1);
}
/*
@@ -3590,7 +3870,6 @@ pci_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
}
}
-
#include <rtems/bsd/local/opt_ddb.h>
#ifdef DDB
#include <ddb/ddb.h>
@@ -3649,24 +3928,41 @@ pci_alloc_map(device_t dev, device_t child, int type, int *rid,
struct resource_list *rl = &dinfo->resources;
struct resource_list_entry *rle;
struct resource *res;
+ struct pci_map *pm;
pci_addr_t map, testval;
int mapsize;
- /*
- * Weed out the bogons, and figure out how large the BAR/map
- * is. Bars that read back 0 here are bogus and unimplemented.
- * Note: atapci in legacy mode are special and handled elsewhere
- * in the code. If you have a atapci device in legacy mode and
- * it fails here, that other code is broken.
- */
res = NULL;
- pci_read_bar(child, *rid, &map, &testval);
+ pm = pci_find_bar(child, *rid);
+ if (pm != NULL) {
+ /* This is a BAR that we failed to allocate earlier. */
+ mapsize = pm->pm_size;
+ map = pm->pm_value;
+ } else {
+ /*
+ * Weed out the bogons, and figure out how large the
+ * BAR/map is. BARs that read back 0 here are bogus
+ * and unimplemented. Note: atapci in legacy mode are
+ * special and handled elsewhere in the code. If you
+ * have a atapci device in legacy mode and it fails
+ * here, that other code is broken.
+ */
+ pci_read_bar(child, *rid, &map, &testval);
- /* Ignore a BAR with a base of 0. */
- if (pci_mapbase(testval) == 0)
- goto out;
+ /*
+ * Determine the size of the BAR and ignore BARs with a size
+ * of 0. Device ROM BARs use a different mask value.
+ */
+ if (PCIR_IS_BIOS(&dinfo->cfg, *rid))
+ mapsize = pci_romsize(testval);
+ else
+ mapsize = pci_mapsize(testval);
+ if (mapsize == 0)
+ goto out;
+ pm = pci_add_bar(child, *rid, map, mapsize);
+ }
- if (PCI_BAR_MEM(testval)) {
+ if (PCI_BAR_MEM(map) || PCIR_IS_BIOS(&dinfo->cfg, *rid)) {
if (type != SYS_RES_MEMORY) {
if (bootverbose)
device_printf(dev,
@@ -3693,16 +3989,15 @@ pci_alloc_map(device_t dev, device_t child, int type, int *rid,
* situation where we might allocate the excess to
* another driver, which won't work.
*/
- mapsize = pci_mapsize(testval);
- count = 1UL << mapsize;
+ count = (pci_addr_t)1 << mapsize;
if (RF_ALIGNMENT(flags) < mapsize)
flags = (flags & ~RF_ALIGNMENT_MASK) | RF_ALIGNMENT_LOG2(mapsize);
- if (PCI_BAR_MEM(testval) && (testval & PCIM_BAR_MEM_PREFETCH))
+ if (PCI_BAR_MEM(map) && (map & PCIM_BAR_MEM_PREFETCH))
flags |= RF_PREFETCHABLE;
/*
* Allocate enough resource, and then write back the
- * appropriate bar for that resource.
+ * appropriate BAR for that resource.
*/
res = BUS_ALLOC_RESOURCE(device_get_parent(dev), child, type, rid,
start, end, count, flags & ~RF_ACTIVE);
@@ -3726,12 +4021,11 @@ pci_alloc_map(device_t dev, device_t child, int type, int *rid,
"Lazy allocation of %#lx bytes rid %#x type %d at %#lx\n",
count, *rid, type, rman_get_start(res));
map = rman_get_start(res);
- pci_write_bar(child, *rid, map);
+ pci_write_bar(child, pm, map);
out:;
return (res);
}
-
struct resource *
pci_alloc_resource(device_t dev, device_t child, int type, int *rid,
u_long start, u_long end, u_long count, u_int flags)
@@ -3770,6 +4064,26 @@ pci_alloc_resource(device_t dev, device_t child, int type, int *rid,
break;
case SYS_RES_IOPORT:
case SYS_RES_MEMORY:
+#ifdef NEW_PCIB
+ /*
+ * PCI-PCI bridge I/O window resources are not BARs.
+ * For those allocations just pass the request up the
+ * tree.
+ */
+ if (cfg->hdrtype == PCIM_HDRTYPE_BRIDGE) {
+ switch (*rid) {
+ case PCIR_IOBASEL_1:
+ case PCIR_MEMBASE_1:
+ case PCIR_PMBASEL_1:
+ /*
+ * XXX: Should we bother creating a resource
+ * list entry?
+ */
+ return (bus_generic_alloc_resource(dev, child,
+ type, rid, start, end, count, flags));
+ }
+ }
+#endif
/* Allocate resources for this BAR if needed. */
rle = resource_list_find(rl, type, *rid);
if (rle == NULL) {
@@ -3839,6 +4153,7 @@ int
pci_activate_resource(device_t dev, device_t child, int type, int rid,
struct resource *r)
{
+ struct pci_devinfo *dinfo;
int error;
error = bus_generic_activate_resource(dev, child, type, rid, r);
@@ -3847,6 +4162,11 @@ 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. */
+ dinfo = device_get_ivars(child);
+ if (type == SYS_RES_MEMORY && PCIR_IS_BIOS(&dinfo->cfg, rid))
+ pci_write_bar(child, pci_find_bar(child, rid),
+ rman_get_start(r) | PCIM_BIOS_ENABLE);
switch (type) {
case SYS_RES_IOPORT:
case SYS_RES_MEMORY:
@@ -3857,6 +4177,27 @@ 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)
+{
+ struct pci_devinfo *dinfo;
+ int error;
+
+ error = bus_generic_deactivate_resource(dev, child, type, rid, r);
+ if (error)
+ return (error);
+
+ /* Disable decoding for device ROMs. */
+ if (device_get_parent(child) == dev) {
+ dinfo = device_get_ivars(child);
+ if (type == SYS_RES_MEMORY && PCIR_IS_BIOS(&dinfo->cfg, rid))
+ pci_write_bar(child, pci_find_bar(child, rid),
+ rman_get_start(r));
+ }
+ return (0);
+}
+
void
pci_delete_resource(device_t dev, device_t child, int type, int rid)
{
@@ -3892,7 +4233,7 @@ pci_delete_resource(device_t dev, device_t child, int type, int rid)
switch (type) {
case SYS_RES_IOPORT:
case SYS_RES_MEMORY:
- pci_write_bar(child, rid, 0);
+ pci_write_bar(child, pci_find_bar(child, rid), 0);
break;
}
#endif
@@ -3909,6 +4250,14 @@ pci_get_resource_list (device_t dev, device_t child)
return (&dinfo->resources);
}
+bus_dma_tag_t
+pci_get_dma_tag(device_t bus, device_t dev)
+{
+ struct pci_softc *sc = device_get_softc(bus);
+
+ return (sc->sc_dma_tag);
+}
+
uint32_t
pci_read_config_method(device_t dev, device_t child, int reg, int width)
{
@@ -3991,7 +4340,6 @@ pci_modevent(module_t mod, int what, void *arg)
void
pci_cfg_restore(device_t dev, struct pci_devinfo *dinfo)
{
- int i;
/*
* Only do header type 0 devices. Type 1 devices are bridges,
@@ -4011,12 +4359,9 @@ pci_cfg_restore(device_t dev, struct pci_devinfo *dinfo)
* the noise on boot by doing nothing if we are already in
* state D0.
*/
- if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
+ if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0)
pci_set_powerstate(dev, PCI_POWERSTATE_D0);
- }
- for (i = 0; i < dinfo->cfg.nummaps; i++)
- pci_write_config(dev, PCIR_BAR(i), dinfo->cfg.bar[i], 4);
- pci_write_config(dev, PCIR_BIOS, dinfo->cfg.bios, 4);
+ pci_restore_bars(dev);
pci_write_config(dev, PCIR_COMMAND, dinfo->cfg.cmdreg, 2);
pci_write_config(dev, PCIR_INTLINE, dinfo->cfg.intline, 1);
pci_write_config(dev, PCIR_INTPIN, dinfo->cfg.intpin, 1);
@@ -4037,7 +4382,6 @@ pci_cfg_restore(device_t dev, struct pci_devinfo *dinfo)
void
pci_cfg_save(device_t dev, struct pci_devinfo *dinfo, int setstate)
{
- int i;
uint32_t cls;
int ps;
@@ -4050,9 +4394,6 @@ pci_cfg_save(device_t dev, struct pci_devinfo *dinfo, int setstate)
*/
if (dinfo->cfg.hdrtype != 0)
return;
- for (i = 0; i < dinfo->cfg.nummaps; i++)
- dinfo->cfg.bar[i] = pci_read_config(dev, PCIR_BAR(i), 4);
- dinfo->cfg.bios = pci_read_config(dev, PCIR_BIOS, 4);
/*
* Some drivers apparently write to these registers w/o updating our
@@ -4117,3 +4458,22 @@ pci_cfg_save(device_t dev, struct pci_devinfo *dinfo, int setstate)
if (pci_get_powerstate(dev) != PCI_POWERSTATE_D3)
pci_set_powerstate(dev, PCI_POWERSTATE_D3);
}
+
+/* Wrapper APIs suitable for device driver use. */
+void
+pci_save_state(device_t dev)
+{
+ struct pci_devinfo *dinfo;
+
+ dinfo = device_get_ivars(dev);
+ pci_cfg_save(dev, dinfo, 0);
+}
+
+void
+pci_restore_state(device_t dev)
+{
+ struct pci_devinfo *dinfo;
+
+ dinfo = device_get_ivars(dev);
+ pci_cfg_restore(dev, dinfo);
+}
diff --git a/freebsd/sys/dev/pci/pci_pci.c b/freebsd/sys/dev/pci/pci_pci.c
index 470386a3..432ba7b9 100644
--- a/freebsd/sys/dev/pci/pci_pci.c
+++ b/freebsd/sys/dev/pci/pci_pci.c
@@ -38,14 +38,16 @@ __FBSDID("$FreeBSD$");
*/
#include <rtems/bsd/sys/param.h>
-#include <sys/systm.h>
+#include <sys/bus.h>
#include <sys/kernel.h>
+#include <sys/libkern.h>
+#include <sys/malloc.h>
#include <sys/module.h>
-#include <sys/bus.h>
-#include <machine/bus.h>
#include <sys/rman.h>
#include <sys/sysctl.h>
+#include <sys/systm.h>
+#include <machine/bus.h>
#include <machine/resource.h>
#include <dev/pci/pcivar.h>
@@ -66,11 +68,16 @@ static device_method_t pcib_methods[] = {
DEVMETHOD(device_resume, bus_generic_resume),
/* Bus interface */
- DEVMETHOD(bus_print_child, bus_generic_print_child),
DEVMETHOD(bus_read_ivar, pcib_read_ivar),
DEVMETHOD(bus_write_ivar, pcib_write_ivar),
DEVMETHOD(bus_alloc_resource, pcib_alloc_resource),
+#ifdef NEW_PCIB
+ DEVMETHOD(bus_adjust_resource, pcib_adjust_resource),
+ DEVMETHOD(bus_release_resource, pcib_release_resource),
+#else
+ DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource),
DEVMETHOD(bus_release_resource, bus_generic_release_resource),
+#endif
DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
@@ -87,7 +94,7 @@ static device_method_t pcib_methods[] = {
DEVMETHOD(pcib_release_msix, pcib_release_msix),
DEVMETHOD(pcib_map_msi, pcib_map_msi),
- { 0, 0 }
+ DEVMETHOD_END
};
static devclass_t pcib_devclass;
@@ -95,6 +102,243 @@ static devclass_t pcib_devclass;
DEFINE_CLASS_0(pcib, pcib_driver, pcib_methods, sizeof(struct pcib_softc));
DRIVER_MODULE(pcib, pci, pcib_driver, pcib_devclass, 0, 0);
+#ifdef NEW_PCIB
+/*
+ * XXX Todo:
+ * - properly handle the ISA enable bit. If it is set, we should change
+ * the behavior of the I/O window resource and rman to not allocate the
+ * blocked ranges (upper 768 bytes of each 1K in the first 64k of the
+ * I/O port address space).
+ */
+
+/*
+ * Is a resource from a child device sub-allocated from one of our
+ * resource managers?
+ */
+static int
+pcib_is_resource_managed(struct pcib_softc *sc, int type, struct resource *r)
+{
+
+ switch (type) {
+ case SYS_RES_IOPORT:
+ return (rman_is_region_manager(r, &sc->io.rman));
+ case SYS_RES_MEMORY:
+ /* Prefetchable resources may live in either memory rman. */
+ if (rman_get_flags(r) & RF_PREFETCHABLE &&
+ rman_is_region_manager(r, &sc->pmem.rman))
+ return (1);
+ return (rman_is_region_manager(r, &sc->mem.rman));
+ }
+ return (0);
+}
+
+static int
+pcib_is_window_open(struct pcib_window *pw)
+{
+
+ return (pw->valid && pw->base < pw->limit);
+}
+
+/*
+ * XXX: If RF_ACTIVE did not also imply allocating a bus space tag and
+ * handle for the resource, we could pass RF_ACTIVE up to the PCI bus
+ * when allocating the resource windows and rely on the PCI bus driver
+ * to do this for us.
+ */
+static void
+pcib_activate_window(struct pcib_softc *sc, int type)
+{
+
+ PCI_ENABLE_IO(device_get_parent(sc->dev), sc->dev, type);
+}
+
+static void
+pcib_write_windows(struct pcib_softc *sc, int mask)
+{
+ device_t dev;
+ uint32_t val;
+
+ dev = sc->dev;
+ if (sc->io.valid && mask & WIN_IO) {
+ val = pci_read_config(dev, PCIR_IOBASEL_1, 1);
+ if ((val & PCIM_BRIO_MASK) == PCIM_BRIO_32) {
+ pci_write_config(dev, PCIR_IOBASEH_1,
+ sc->io.base >> 16, 2);
+ pci_write_config(dev, PCIR_IOLIMITH_1,
+ sc->io.limit >> 16, 2);
+ }
+ pci_write_config(dev, PCIR_IOBASEL_1, sc->io.base >> 8, 1);
+ pci_write_config(dev, PCIR_IOLIMITL_1, sc->io.limit >> 8, 1);
+ }
+
+ if (mask & WIN_MEM) {
+ pci_write_config(dev, PCIR_MEMBASE_1, sc->mem.base >> 16, 2);
+ pci_write_config(dev, PCIR_MEMLIMIT_1, sc->mem.limit >> 16, 2);
+ }
+
+ if (sc->pmem.valid && mask & WIN_PMEM) {
+ val = pci_read_config(dev, PCIR_PMBASEL_1, 2);
+ if ((val & PCIM_BRPM_MASK) == PCIM_BRPM_64) {
+ pci_write_config(dev, PCIR_PMBASEH_1,
+ sc->pmem.base >> 32, 4);
+ pci_write_config(dev, PCIR_PMLIMITH_1,
+ sc->pmem.limit >> 32, 4);
+ }
+ pci_write_config(dev, PCIR_PMBASEL_1, sc->pmem.base >> 16, 2);
+ pci_write_config(dev, PCIR_PMLIMITL_1, sc->pmem.limit >> 16, 2);
+ }
+}
+
+static void
+pcib_alloc_window(struct pcib_softc *sc, struct pcib_window *w, int type,
+ int flags, pci_addr_t max_address)
+{
+ char buf[64];
+ int error, rid;
+
+ if (max_address != (u_long)max_address)
+ max_address = ~0ul;
+ w->rman.rm_start = 0;
+ w->rman.rm_end = max_address;
+ w->rman.rm_type = RMAN_ARRAY;
+ snprintf(buf, sizeof(buf), "%s %s window",
+ device_get_nameunit(sc->dev), w->name);
+ w->rman.rm_descr = strdup(buf, M_DEVBUF);
+ error = rman_init(&w->rman);
+ if (error)
+ panic("Failed to initialize %s %s rman",
+ device_get_nameunit(sc->dev), w->name);
+
+ if (!pcib_is_window_open(w))
+ return;
+
+ if (w->base > max_address || w->limit > max_address) {
+ device_printf(sc->dev,
+ "initial %s window has too many bits, ignoring\n", w->name);
+ return;
+ }
+ rid = w->reg;
+ w->res = bus_alloc_resource(sc->dev, type, &rid, w->base, w->limit,
+ w->limit - w->base + 1, flags);
+ if (w->res == NULL) {
+ device_printf(sc->dev,
+ "failed to allocate initial %s window: %#jx-%#jx\n",
+ w->name, (uintmax_t)w->base, (uintmax_t)w->limit);
+ w->base = max_address;
+ w->limit = 0;
+ pcib_write_windows(sc, w->mask);
+ return;
+ }
+ pcib_activate_window(sc, type);
+
+ error = rman_manage_region(&w->rman, rman_get_start(w->res),
+ rman_get_end(w->res));
+ if (error)
+ panic("Failed to initialize rman with resource");
+}
+
+/*
+ * Initialize I/O windows.
+ */
+static void
+pcib_probe_windows(struct pcib_softc *sc)
+{
+ pci_addr_t max;
+ device_t dev;
+ uint32_t val;
+
+ dev = sc->dev;
+
+ /* Determine if the I/O port window is implemented. */
+ val = pci_read_config(dev, PCIR_IOBASEL_1, 1);
+ if (val == 0) {
+ /*
+ * If 'val' is zero, then only 16-bits of I/O space
+ * are supported.
+ */
+ pci_write_config(dev, PCIR_IOBASEL_1, 0xff, 1);
+ if (pci_read_config(dev, PCIR_IOBASEL_1, 1) != 0) {
+ sc->io.valid = 1;
+ pci_write_config(dev, PCIR_IOBASEL_1, 0, 1);
+ }
+ } else
+ sc->io.valid = 1;
+
+ /* Read the existing I/O port window. */
+ if (sc->io.valid) {
+ sc->io.reg = PCIR_IOBASEL_1;
+ sc->io.step = 12;
+ sc->io.mask = WIN_IO;
+ sc->io.name = "I/O port";
+ if ((val & PCIM_BRIO_MASK) == PCIM_BRIO_32) {
+ sc->io.base = PCI_PPBIOBASE(
+ pci_read_config(dev, PCIR_IOBASEH_1, 2), val);
+ sc->io.limit = PCI_PPBIOLIMIT(
+ pci_read_config(dev, PCIR_IOLIMITH_1, 2),
+ pci_read_config(dev, PCIR_IOLIMITL_1, 1));
+ max = 0xffffffff;
+ } else {
+ sc->io.base = PCI_PPBIOBASE(0, val);
+ sc->io.limit = PCI_PPBIOLIMIT(0,
+ pci_read_config(dev, PCIR_IOLIMITL_1, 1));
+ max = 0xffff;
+ }
+ pcib_alloc_window(sc, &sc->io, SYS_RES_IOPORT, 0, max);
+ }
+
+ /* Read the existing memory window. */
+ sc->mem.valid = 1;
+ sc->mem.reg = PCIR_MEMBASE_1;
+ sc->mem.step = 20;
+ sc->mem.mask = WIN_MEM;
+ sc->mem.name = "memory";
+ sc->mem.base = PCI_PPBMEMBASE(0,
+ pci_read_config(dev, PCIR_MEMBASE_1, 2));
+ sc->mem.limit = PCI_PPBMEMLIMIT(0,
+ pci_read_config(dev, PCIR_MEMLIMIT_1, 2));
+ pcib_alloc_window(sc, &sc->mem, SYS_RES_MEMORY, 0, 0xffffffff);
+
+ /* Determine if the prefetchable memory window is implemented. */
+ val = pci_read_config(dev, PCIR_PMBASEL_1, 2);
+ if (val == 0) {
+ /*
+ * If 'val' is zero, then only 32-bits of memory space
+ * are supported.
+ */
+ pci_write_config(dev, PCIR_PMBASEL_1, 0xffff, 2);
+ if (pci_read_config(dev, PCIR_PMBASEL_1, 2) != 0) {
+ sc->pmem.valid = 1;
+ pci_write_config(dev, PCIR_PMBASEL_1, 0, 2);
+ }
+ } else
+ sc->pmem.valid = 1;
+
+ /* Read the existing prefetchable memory window. */
+ if (sc->pmem.valid) {
+ sc->pmem.reg = PCIR_PMBASEL_1;
+ sc->pmem.step = 20;
+ sc->pmem.mask = WIN_PMEM;
+ sc->pmem.name = "prefetch";
+ if ((val & PCIM_BRPM_MASK) == PCIM_BRPM_64) {
+ sc->pmem.base = PCI_PPBMEMBASE(
+ pci_read_config(dev, PCIR_PMBASEH_1, 4), val);
+ sc->pmem.limit = PCI_PPBMEMLIMIT(
+ pci_read_config(dev, PCIR_PMLIMITH_1, 4),
+ pci_read_config(dev, PCIR_PMLIMITL_1, 2));
+ max = 0xffffffffffffffff;
+ } else {
+ sc->pmem.base = PCI_PPBMEMBASE(0, val);
+ sc->pmem.limit = PCI_PPBMEMLIMIT(0,
+ pci_read_config(dev, PCIR_PMLIMITL_1, 2));
+ max = 0xffffffff;
+ }
+ pcib_alloc_window(sc, &sc->pmem, SYS_RES_MEMORY,
+ RF_PREFETCHABLE, max);
+ }
+}
+
+#else
+
/*
* Is the prefetch window open (eg, can we allocate memory in it?)
*/
@@ -121,6 +365,7 @@ pcib_is_io_open(struct pcib_softc *sc)
{
return (sc->iobase > 0 && sc->iobase < sc->iolimit);
}
+#endif
/*
* Generic device interface
@@ -140,7 +385,9 @@ void
pcib_attach_common(device_t dev)
{
struct pcib_softc *sc;
+#ifndef NEW_PCIB
uint8_t iolow;
+#endif
struct sysctl_ctx_list *sctx;
struct sysctl_oid *soid;
@@ -173,6 +420,7 @@ pcib_attach_common(device_t dev)
SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "subbus",
CTLFLAG_RD, &sc->subbus, 0, "Subordinate bus number");
+#ifndef NEW_PCIB
/*
* Determine current I/O decode.
*/
@@ -217,6 +465,7 @@ pcib_attach_common(device_t dev)
sc->pmemlimit = PCI_PPBMEMLIMIT(0,
pci_read_config(dev, PCIR_PMLIMITL_1, 2));
}
+#endif
/*
* Quirk handling.
@@ -289,18 +538,35 @@ pcib_attach_common(device_t dev)
if ((pci_get_devid(dev) & 0xff00ffff) == 0x24008086 ||
pci_read_config(dev, PCIR_PROGIF, 1) == PCIP_BRIDGE_PCI_SUBTRACTIVE)
sc->flags |= PCIB_SUBTRACTIVE;
-
+
+#ifdef NEW_PCIB
+ pcib_probe_windows(sc);
+#endif
if (bootverbose) {
device_printf(dev, " domain %d\n", sc->domain);
device_printf(dev, " secondary bus %d\n", sc->secbus);
device_printf(dev, " subordinate bus %d\n", sc->subbus);
- device_printf(dev, " I/O decode 0x%x-0x%x\n", sc->iobase, sc->iolimit);
+#ifdef NEW_PCIB
+ if (pcib_is_window_open(&sc->io))
+ device_printf(dev, " I/O decode 0x%jx-0x%jx\n",
+ (uintmax_t)sc->io.base, (uintmax_t)sc->io.limit);
+ if (pcib_is_window_open(&sc->mem))
+ device_printf(dev, " memory decode 0x%jx-0x%jx\n",
+ (uintmax_t)sc->mem.base, (uintmax_t)sc->mem.limit);
+ if (pcib_is_window_open(&sc->pmem))
+ device_printf(dev, " prefetched decode 0x%jx-0x%jx\n",
+ (uintmax_t)sc->pmem.base, (uintmax_t)sc->pmem.limit);
+#else
+ if (pcib_is_io_open(sc))
+ device_printf(dev, " I/O decode 0x%x-0x%x\n",
+ sc->iobase, sc->iolimit);
if (pcib_is_nonprefetch_open(sc))
device_printf(dev, " memory decode 0x%jx-0x%jx\n",
(uintmax_t)sc->membase, (uintmax_t)sc->memlimit);
if (pcib_is_prefetch_open(sc))
device_printf(dev, " prefetched decode 0x%jx-0x%jx\n",
(uintmax_t)sc->pmembase, (uintmax_t)sc->pmemlimit);
+#endif
else
device_printf(dev, " no prefetched decode\n");
if (sc->flags & PCIB_SUBTRACTIVE)
@@ -320,6 +586,13 @@ pcib_attach_common(device_t dev)
* would be more widely routed than absolutely necessary. We could
* then do a walk of the tree later and fix it.
*/
+
+ /*
+ * Always enable busmastering on bridges so that transactions
+ * initiated on the secondary bus are passed through to the
+ * primary bus.
+ */
+ pci_enable_busmaster(dev);
}
int
@@ -371,6 +644,377 @@ pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
return(ENOENT);
}
+#ifdef NEW_PCIB
+static const char *
+pcib_child_name(device_t child)
+{
+ static char buf[64];
+
+ if (device_get_nameunit(child) != NULL)
+ return (device_get_nameunit(child));
+ snprintf(buf, sizeof(buf), "pci%d:%d:%d:%d", pci_get_domain(child),
+ pci_get_bus(child), pci_get_slot(child), pci_get_function(child));
+ return (buf);
+}
+
+/*
+ * Attempt to allocate a resource from the existing resources assigned
+ * to a window.
+ */
+static struct resource *
+pcib_suballoc_resource(struct pcib_softc *sc, struct pcib_window *w,
+ device_t child, int type, int *rid, u_long start, u_long end, u_long count,
+ u_int flags)
+{
+ struct resource *res;
+
+ if (!pcib_is_window_open(w))
+ return (NULL);
+
+ res = rman_reserve_resource(&w->rman, start, end, count,
+ flags & ~RF_ACTIVE, child);
+ if (res == NULL)
+ return (NULL);
+
+ if (bootverbose)
+ device_printf(sc->dev,
+ "allocated %s range (%#lx-%#lx) for rid %x of %s\n",
+ w->name, rman_get_start(res), rman_get_end(res), *rid,
+ pcib_child_name(child));
+ rman_set_rid(res, *rid);
+
+ /*
+ * If the resource should be active, pass that request up the
+ * tree. This assumes the parent drivers can handle
+ * activating sub-allocated resources.
+ */
+ if (flags & RF_ACTIVE) {
+ if (bus_activate_resource(child, type, *rid, res) != 0) {
+ rman_release_resource(res);
+ return (NULL);
+ }
+ }
+
+ return (res);
+}
+
+/*
+ * Attempt to grow a window to make room for a given resource request.
+ * The 'step' parameter is log_2 of the desired I/O window's alignment.
+ */
+static int
+pcib_grow_window(struct pcib_softc *sc, struct pcib_window *w, int type,
+ u_long start, u_long end, u_long count, u_int flags)
+{
+ u_long align, start_free, end_free, front, back, wmask;
+ int error, rid;
+
+ /*
+ * Clamp the desired resource range to the maximum address
+ * this window supports. Reject impossible requests.
+ */
+ if (!w->valid)
+ return (EINVAL);
+ if (end > w->rman.rm_end)
+ end = w->rman.rm_end;
+ if (start + count - 1 > end || start + count < start)
+ return (EINVAL);
+ wmask = (1ul << w->step) - 1;
+
+ /*
+ * If there is no resource at all, just try to allocate enough
+ * aligned space for this resource.
+ */
+ if (w->res == NULL) {
+ if (RF_ALIGNMENT(flags) < w->step) {
+ flags &= ~RF_ALIGNMENT_MASK;
+ flags |= RF_ALIGNMENT_LOG2(w->step);
+ }
+ start &= ~wmask;
+ end |= wmask;
+ count = roundup2(count, 1ul << w->step);
+ rid = w->reg;
+ w->res = bus_alloc_resource(sc->dev, type, &rid, start, end,
+ count, flags & ~RF_ACTIVE);
+ if (w->res == NULL) {
+ if (bootverbose)
+ device_printf(sc->dev,
+ "failed to allocate initial %s window (%#lx-%#lx,%#lx)\n",
+ w->name, start, end, count);
+ return (ENXIO);
+ }
+ if (bootverbose)
+ device_printf(sc->dev,
+ "allocated initial %s window of %#lx-%#lx\n",
+ w->name, rman_get_start(w->res),
+ rman_get_end(w->res));
+ error = rman_manage_region(&w->rman, rman_get_start(w->res),
+ rman_get_end(w->res));
+ if (error) {
+ if (bootverbose)
+ device_printf(sc->dev,
+ "failed to add initial %s window to rman\n",
+ w->name);
+ bus_release_resource(sc->dev, type, w->reg, w->res);
+ w->res = NULL;
+ return (error);
+ }
+ pcib_activate_window(sc, type);
+ goto updatewin;
+ }
+
+ /*
+ * See if growing the window would help. Compute the minimum
+ * amount of address space needed on both the front and back
+ * ends of the existing window to satisfy the allocation.
+ *
+ * For each end, build a candidate region adjusting for the
+ * required alignment, etc. If there is a free region at the
+ * edge of the window, grow from the inner edge of the free
+ * region. Otherwise grow from the window boundary.
+ *
+ * XXX: Special case: if w->res is completely empty and the
+ * request size is larger than w->res, we should find the
+ * optimal aligned buffer containing w->res and allocate that.
+ */
+ if (bootverbose)
+ device_printf(sc->dev,
+ "attempting to grow %s window for (%#lx-%#lx,%#lx)\n",
+ w->name, start, end, count);
+ align = 1ul << RF_ALIGNMENT(flags);
+ if (start < rman_get_start(w->res)) {
+ if (rman_first_free_region(&w->rman, &start_free, &end_free) !=
+ 0 || start_free != rman_get_start(w->res))
+ end_free = rman_get_start(w->res);
+ if (end_free > end)
+ end_free = end + 1;
+
+ /* Move end_free down until it is properly aligned. */
+ end_free &= ~(align - 1);
+ end_free--;
+ front = end_free - (count - 1);
+
+ /*
+ * The resource would now be allocated at (front,
+ * end_free). Ensure that fits in the (start, end)
+ * bounds. end_free is checked above. If 'front' is
+ * ok, ensure it is properly aligned for this window.
+ * Also check for underflow.
+ */
+ if (front >= start && front <= end_free) {
+ if (bootverbose)
+ printf("\tfront candidate range: %#lx-%#lx\n",
+ front, end_free);
+ front &= ~wmask;
+ front = rman_get_start(w->res) - front;
+ } else
+ front = 0;
+ } else
+ front = 0;
+ if (end > rman_get_end(w->res)) {
+ if (rman_last_free_region(&w->rman, &start_free, &end_free) !=
+ 0 || end_free != rman_get_end(w->res))
+ start_free = rman_get_end(w->res) + 1;
+ if (start_free < start)
+ start_free = start;
+
+ /* Move start_free up until it is properly aligned. */
+ start_free = roundup2(start_free, align);
+ back = start_free + count - 1;
+
+ /*
+ * The resource would now be allocated at (start_free,
+ * back). Ensure that fits in the (start, end)
+ * bounds. start_free is checked above. If 'back' is
+ * ok, ensure it is properly aligned for this window.
+ * Also check for overflow.
+ */
+ if (back <= end && start_free <= back) {
+ if (bootverbose)
+ printf("\tback candidate range: %#lx-%#lx\n",
+ start_free, back);
+ back |= wmask;
+ back -= rman_get_end(w->res);
+ } else
+ back = 0;
+ } else
+ back = 0;
+
+ /*
+ * Try to allocate the smallest needed region first.
+ * If that fails, fall back to the other region.
+ */
+ error = ENOSPC;
+ while (front != 0 || back != 0) {
+ if (front != 0 && (front <= back || back == 0)) {
+ error = bus_adjust_resource(sc->dev, type, w->res,
+ rman_get_start(w->res) - front,
+ rman_get_end(w->res));
+ if (error == 0)
+ break;
+ front = 0;
+ } else {
+ error = bus_adjust_resource(sc->dev, type, w->res,
+ rman_get_start(w->res),
+ rman_get_end(w->res) + back);
+ if (error == 0)
+ break;
+ back = 0;
+ }
+ }
+
+ if (error)
+ return (error);
+ if (bootverbose)
+ device_printf(sc->dev, "grew %s window to %#lx-%#lx\n",
+ w->name, rman_get_start(w->res), rman_get_end(w->res));
+
+ /* Add the newly allocated region to the resource manager. */
+ if (w->base != rman_get_start(w->res)) {
+ KASSERT(w->limit == rman_get_end(w->res), ("both ends moved"));
+ error = rman_manage_region(&w->rman, rman_get_start(w->res),
+ w->base - 1);
+ } else {
+ KASSERT(w->limit != rman_get_end(w->res),
+ ("neither end moved"));
+ error = rman_manage_region(&w->rman, w->limit + 1,
+ rman_get_end(w->res));
+ }
+ if (error) {
+ if (bootverbose)
+ device_printf(sc->dev,
+ "failed to expand %s resource manager\n", w->name);
+ bus_adjust_resource(sc->dev, type, w->res, w->base, w->limit);
+ return (error);
+ }
+
+updatewin:
+ /* Save the new window. */
+ w->base = rman_get_start(w->res);
+ w->limit = rman_get_end(w->res);
+ KASSERT((w->base & wmask) == 0, ("start address is not aligned"));
+ KASSERT((w->limit & wmask) == wmask, ("end address is not aligned"));
+ pcib_write_windows(sc, w->mask);
+ return (0);
+}
+
+/*
+ * We have to trap resource allocation requests and ensure that the bridge
+ * is set up to, or capable of handling them.
+ */
+struct resource *
+pcib_alloc_resource(device_t dev, device_t child, int type, int *rid,
+ u_long start, u_long end, u_long count, u_int flags)
+{
+ struct pcib_softc *sc;
+ struct resource *r;
+
+ sc = device_get_softc(dev);
+
+ /*
+ * VGA resources are decoded iff the VGA enable bit is set in
+ * the bridge control register. VGA resources do not fall into
+ * the resource windows and are passed up to the parent.
+ */
+ if ((type == SYS_RES_IOPORT && pci_is_vga_ioport_range(start, end)) ||
+ (type == SYS_RES_MEMORY && pci_is_vga_memory_range(start, end))) {
+ if (sc->bridgectl & PCIB_BCR_VGA_ENABLE)
+ return (bus_generic_alloc_resource(dev, child, type,
+ rid, start, end, count, flags));
+ else
+ return (NULL);
+ }
+
+ switch (type) {
+ case SYS_RES_IOPORT:
+ r = pcib_suballoc_resource(sc, &sc->io, child, type, rid, start,
+ end, count, flags);
+ if (r != NULL || (sc->flags & PCIB_SUBTRACTIVE) != 0)
+ break;
+ if (pcib_grow_window(sc, &sc->io, type, start, end, count,
+ flags) == 0)
+ r = pcib_suballoc_resource(sc, &sc->io, child, type,
+ rid, start, end, count, flags);
+ break;
+ case SYS_RES_MEMORY:
+ /*
+ * For prefetchable resources, prefer the prefetchable
+ * memory window, but fall back to the regular memory
+ * window if that fails. Try both windows before
+ * attempting to grow a window in case the firmware
+ * has used a range in the regular memory window to
+ * map a prefetchable BAR.
+ */
+ if (flags & RF_PREFETCHABLE) {
+ r = pcib_suballoc_resource(sc, &sc->pmem, child, type,
+ rid, start, end, count, flags);
+ if (r != NULL)
+ break;
+ }
+ r = pcib_suballoc_resource(sc, &sc->mem, child, type, rid,
+ start, end, count, flags);
+ if (r != NULL || (sc->flags & PCIB_SUBTRACTIVE) != 0)
+ break;
+ if (flags & RF_PREFETCHABLE) {
+ if (pcib_grow_window(sc, &sc->pmem, type, start, end,
+ count, flags) == 0) {
+ r = pcib_suballoc_resource(sc, &sc->pmem, child,
+ type, rid, start, end, count, flags);
+ if (r != NULL)
+ break;
+ }
+ }
+ if (pcib_grow_window(sc, &sc->mem, type, start, end, count,
+ flags & ~RF_PREFETCHABLE) == 0)
+ r = pcib_suballoc_resource(sc, &sc->mem, child, type,
+ rid, start, end, count, flags);
+ break;
+ default:
+ return (bus_generic_alloc_resource(dev, child, type, rid,
+ start, end, count, flags));
+ }
+
+ /*
+ * If attempts to suballocate from the window fail but this is a
+ * subtractive bridge, pass the request up the tree.
+ */
+ if (sc->flags & PCIB_SUBTRACTIVE && r == NULL)
+ return (bus_generic_alloc_resource(dev, child, type, rid,
+ start, end, count, flags));
+ return (r);
+}
+
+int
+pcib_adjust_resource(device_t bus, device_t child, int type, struct resource *r,
+ u_long start, u_long end)
+{
+ struct pcib_softc *sc;
+
+ sc = device_get_softc(bus);
+ if (pcib_is_resource_managed(sc, type, r))
+ return (rman_adjust_resource(r, start, end));
+ return (bus_generic_adjust_resource(bus, child, type, r, start, end));
+}
+
+int
+pcib_release_resource(device_t dev, device_t child, int type, int rid,
+ struct resource *r)
+{
+ struct pcib_softc *sc;
+ int error;
+
+ sc = device_get_softc(dev);
+ if (pcib_is_resource_managed(sc, type, r)) {
+ if (rman_get_flags(r) & RF_ACTIVE) {
+ error = bus_deactivate_resource(child, type, rid, r);
+ if (error)
+ return (error);
+ }
+ return (rman_release_resource(r));
+ }
+ return (bus_generic_release_resource(dev, child, type, rid, r));
+}
+#else
/*
* We have to trap resource allocation requests and ensure that the bridge
* is set up to, or capable of handling them.
@@ -526,6 +1170,7 @@ pcib_alloc_resource(device_t dev, device_t child, int type, int *rid,
return (bus_generic_alloc_resource(dev, child, type, rid, start, end,
count, flags));
}
+#endif
/*
* PCIB interface.
diff --git a/freebsd/sys/dev/pci/pci_private.h b/freebsd/sys/dev/pci/pci_private.h
index e45afb7a..b3ff50d5 100644
--- a/freebsd/sys/dev/pci/pci_private.h
+++ b/freebsd/sys/dev/pci/pci_private.h
@@ -38,11 +38,16 @@
*/
DECLARE_CLASS(pci_driver);
+struct pci_softc {
+ bus_dma_tag_t sc_dma_tag;
+};
+
void pci_add_children(device_t dev, int domain, int busno,
size_t dinfo_size);
void pci_add_child(device_t bus, struct pci_devinfo *dinfo);
void pci_add_resources(device_t bus, device_t dev, int force,
uint32_t prefetchmask);
+int pci_attach_common(device_t dev);
void pci_driver_added(device_t dev, driver_t *driver);
int pci_print_child(device_t dev, device_t child);
void pci_probe_nomatch(device_t dev, device_t child);
@@ -86,6 +91,8 @@ int pci_release_resource(device_t dev, device_t child, int type,
int rid, struct resource *r);
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);
diff --git a/freebsd/sys/dev/pci/pci_user.c b/freebsd/sys/dev/pci/pci_user.c
index e7306476..3df4d73b 100644
--- a/freebsd/sys/dev/pci/pci_user.c
+++ b/freebsd/sys/dev/pci/pci_user.c
@@ -313,8 +313,7 @@ pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *t
struct pci_io *io;
struct pci_bar_io *bio;
struct pci_match_conf *pattern_buf;
- struct resource_list_entry *rle;
- uint32_t value;
+ struct pci_map *pm;
size_t confsz, iolen, pbufsz;
int error, ionum, i, num_patterns;
#ifdef PRE7_COMPAT
@@ -689,54 +688,14 @@ getconfexit:
error = ENODEV;
break;
}
- dinfo = device_get_ivars(pcidev);
-
- /*
- * Look for a resource list entry matching the requested BAR.
- *
- * XXX: This will not find BARs that are not initialized, but
- * maybe that is ok?
- */
- rle = resource_list_find(&dinfo->resources, SYS_RES_MEMORY,
- bio->pbi_reg);
- if (rle == NULL)
- rle = resource_list_find(&dinfo->resources,
- SYS_RES_IOPORT, bio->pbi_reg);
- if (rle == NULL || rle->res == NULL) {
+ pm = pci_find_bar(pcidev, bio->pbi_reg);
+ if (pm == NULL) {
error = EINVAL;
break;
}
-
- /*
- * Ok, we have a resource for this BAR. Read the lower
- * 32 bits to get any flags.
- */
- value = pci_read_config(pcidev, bio->pbi_reg, 4);
- if (PCI_BAR_MEM(value)) {
- if (rle->type != SYS_RES_MEMORY) {
- error = EINVAL;
- break;
- }
- value &= ~PCIM_BAR_MEM_BASE;
- } else {
- if (rle->type != SYS_RES_IOPORT) {
- error = EINVAL;
- break;
- }
- value &= ~PCIM_BAR_IO_BASE;
- }
- bio->pbi_base = rman_get_start(rle->res) | value;
- bio->pbi_length = rman_get_size(rle->res);
-
- /*
- * Check the command register to determine if this BAR
- * is enabled.
- */
- value = pci_read_config(pcidev, PCIR_COMMAND, 2);
- if (rle->type == SYS_RES_MEMORY)
- bio->pbi_enabled = (value & PCIM_CMD_MEMEN) != 0;
- else
- bio->pbi_enabled = (value & PCIM_CMD_PORTEN) != 0;
+ bio->pbi_base = pm->pm_value;
+ bio->pbi_length = (pci_addr_t)1 << pm->pm_size;
+ bio->pbi_enabled = pci_bar_enabled(pcidev, pm);
error = 0;
break;
default:
diff --git a/freebsd/sys/dev/pci/pcib_private.h b/freebsd/sys/dev/pci/pcib_private.h
index 20f8da92..0fbc8df5 100644
--- a/freebsd/sys/dev/pci/pcib_private.h
+++ b/freebsd/sys/dev/pci/pcib_private.h
@@ -37,6 +37,25 @@
* Export portions of generic PCI:PCI bridge support so that it can be
* used by subclasses.
*/
+DECLARE_CLASS(pcib_driver);
+
+#ifdef NEW_PCIB
+#define WIN_IO 0x1
+#define WIN_MEM 0x2
+#define WIN_PMEM 0x4
+
+struct pcib_window {
+ pci_addr_t base; /* base address */
+ pci_addr_t limit; /* topmost address */
+ struct rman rman;
+ struct resource *res;
+ int reg; /* resource id from parent */
+ int valid;
+ int mask; /* WIN_* bitmask of this window */
+ int step; /* log_2 of window granularity */
+ const char *name;
+};
+#endif
/*
* Bridge-specific data.
@@ -52,12 +71,18 @@ struct pcib_softc
u_int pribus; /* primary bus number */
u_int secbus; /* secondary bus number */
u_int subbus; /* subordinate bus number */
+#ifdef NEW_PCIB
+ struct pcib_window io; /* I/O port window */
+ struct pcib_window mem; /* memory window */
+ struct pcib_window pmem; /* prefetchable memory window */
+#else
pci_addr_t pmembase; /* base address of prefetchable memory */
pci_addr_t pmemlimit; /* topmost address of prefetchable memory */
pci_addr_t membase; /* base address of memory window */
pci_addr_t memlimit; /* topmost address of memory window */
uint32_t iobase; /* base address of port window */
uint32_t iolimit; /* topmost address of port window */
+#endif
uint16_t secstat; /* secondary bus status register */
uint16_t bridgectl; /* bridge control register */
uint8_t seclat; /* secondary bus latency timer */
@@ -73,6 +98,12 @@ int pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result);
int pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value);
struct resource *pcib_alloc_resource(device_t dev, device_t child, int type, int *rid,
u_long start, u_long end, u_long count, u_int flags);
+#ifdef NEW_PCIB
+int pcib_adjust_resource(device_t bus, device_t child, int type,
+ struct resource *r, u_long start, u_long end);
+int pcib_release_resource(device_t dev, device_t child, int type, int rid,
+ struct resource *r);
+#endif
int pcib_maxslots(device_t dev);
uint32_t pcib_read_config(device_t dev, u_int b, u_int s, u_int f, u_int reg, int width);
void pcib_write_config(device_t dev, u_int b, u_int s, u_int f, u_int reg, uint32_t val, int width);
diff --git a/freebsd/sys/dev/pci/pcireg.h b/freebsd/sys/dev/pci/pcireg.h
index 9b4ad87b..0127e776 100644
--- a/freebsd/sys/dev/pci/pcireg.h
+++ b/freebsd/sys/dev/pci/pcireg.h
@@ -64,6 +64,7 @@
#define PCIM_CMD_BACKTOBACK 0x0200
#define PCIM_CMD_INTxDIS 0x0400
#define PCIR_STATUS 0x06
+#define PCIM_STATUS_INTxSTATE 0x0008
#define PCIM_STATUS_CAPPRESENT 0x0010
#define PCIM_STATUS_66CAPABLE 0x0020
#define PCIM_STATUS_BACKTOBACK 0x0080
@@ -135,11 +136,22 @@
#define PCIZ_VC 0x0002 /* Virtual Channel */
#define PCIZ_SERNUM 0x0003 /* Device Serial Number */
#define PCIZ_PWRBDGT 0x0004 /* Power Budgeting */
+#define PCIZ_RCLINK_DCL 0x0005 /* Root Complex Link Declaration */
+#define PCIZ_RCLINK_CTL 0x0006 /* Root Complex Internal Link Control */
+#define PCIZ_RCEC_ASSOC 0x0007 /* Root Complex Event Collector Association */
+#define PCIZ_MFVC 0x0008 /* Multi-Function Virtual Channel */
+#define PCIZ_RCRB 0x000a /* RCRB Header */
#define PCIZ_VENDOR 0x000b /* Vendor Unique */
#define PCIZ_ACS 0x000d /* Access Control Services */
#define PCIZ_ARI 0x000e /* Alternative Routing-ID Interpretation */
#define PCIZ_ATS 0x000f /* Address Translation Services */
#define PCIZ_SRIOV 0x0010 /* Single Root IO Virtualization */
+#define PCIZ_MULTICAST 0x0012 /* Multicast */
+#define PCIZ_RESIZE_BAR 0x0015 /* Resizable BAR */
+#define PCIZ_DPA 0x0016 /* Dynamic Power Allocation */
+#define PCIZ_TPH_REQ 0x0017 /* TPH Requester */
+#define PCIZ_LTR 0x0018 /* Latency Tolerance Reporting */
+#define PCIZ_SEC_PCIE 0x0019 /* Secondary PCI Express */
/* config registers for header type 0 devices */
@@ -213,6 +225,7 @@
#define PCIM_BRPM_64 0x1
#define PCIM_BRPM_MASK 0xf
+#define PCIR_BIOS_1 0x38
#define PCIR_BRIDGECTL_1 0x3e
/* config registers for header type 2 (CardBus) devices */
@@ -263,6 +276,9 @@
#define PCIS_STORAGE_SATA 0x06
#define PCIP_STORAGE_SATA_AHCI_1_0 0x01
#define PCIS_STORAGE_SAS 0x07
+#define PCIS_STORAGE_NVM 0x08
+#define PCIP_STORAGE_NVM_NVMHCI_1_0 0x01
+#define PCIP_STORAGE_NVM_ENTERPRISE_NVMHCI_1_0 0x02
#define PCIS_STORAGE_OTHER 0x80
#define PCIC_NETWORK 0x02
@@ -367,6 +383,7 @@
#define PCIP_SERIALBUS_USB_UHCI 0x00
#define PCIP_SERIALBUS_USB_OHCI 0x10
#define PCIP_SERIALBUS_USB_EHCI 0x20
+#define PCIP_SERIALBUS_USB_XHCI 0x30
#define PCIP_SERIALBUS_USB_DEVICE 0xfe
#define PCIS_SERIALBUS_FC 0x04
#define PCIS_SERIALBUS_SMBUS 0x05
@@ -612,56 +629,258 @@
#define PCIR_SUBVENDCAP_ID 0x4
/* PCI Express definitions */
-#define PCIR_EXPRESS_FLAGS 0x2
-#define PCIM_EXP_FLAGS_VERSION 0x000F
-#define PCIM_EXP_FLAGS_TYPE 0x00F0
-#define PCIM_EXP_TYPE_ENDPOINT 0x0000
-#define PCIM_EXP_TYPE_LEGACY_ENDPOINT 0x0010
-#define PCIM_EXP_TYPE_ROOT_PORT 0x0040
-#define PCIM_EXP_TYPE_UPSTREAM_PORT 0x0050
-#define PCIM_EXP_TYPE_DOWNSTREAM_PORT 0x0060
-#define PCIM_EXP_TYPE_PCI_BRIDGE 0x0070
-#define PCIM_EXP_TYPE_PCIE_BRIDGE 0x0080
-#define PCIM_EXP_TYPE_ROOT_INT_EP 0x0090
-#define PCIM_EXP_TYPE_ROOT_EC 0x00a0
-#define PCIM_EXP_FLAGS_SLOT 0x0100
-#define PCIM_EXP_FLAGS_IRQ 0x3e00
-#define PCIR_EXPRESS_DEVICE_CAP 0x4
-#define PCIM_EXP_CAP_MAX_PAYLOAD 0x0007
-#define PCIR_EXPRESS_DEVICE_CTL 0x8
-#define PCIM_EXP_CTL_NFER_ENABLE 0x0002
-#define PCIM_EXP_CTL_FER_ENABLE 0x0004
-#define PCIM_EXP_CTL_URR_ENABLE 0x0008
-#define PCIM_EXP_CTL_RELAXED_ORD_ENABLE 0x0010
-#define PCIM_EXP_CTL_MAX_PAYLOAD 0x00e0
-#define PCIM_EXP_CTL_NOSNOOP_ENABLE 0x0800
-#define PCIM_EXP_CTL_MAX_READ_REQUEST 0x7000
-#define PCIR_EXPRESS_DEVICE_STA 0xa
-#define PCIM_EXP_STA_CORRECTABLE_ERROR 0x0001
-#define PCIM_EXP_STA_NON_FATAL_ERROR 0x0002
-#define PCIM_EXP_STA_FATAL_ERROR 0x0004
-#define PCIM_EXP_STA_UNSUPPORTED_REQ 0x0008
-#define PCIM_EXP_STA_AUX_POWER 0x0010
-#define PCIM_EXP_STA_TRANSACTION_PND 0x0020
-#define PCIR_EXPRESS_LINK_CAP 0xc
-#define PCIM_LINK_CAP_MAX_SPEED 0x0000000f
-#define PCIM_LINK_CAP_MAX_WIDTH 0x000003f0
-#define PCIM_LINK_CAP_ASPM 0x00000c00
-#define PCIM_LINK_CAP_L0S_EXIT 0x00007000
-#define PCIM_LINK_CAP_L1_EXIT 0x00038000
-#define PCIM_LINK_CAP_PORT 0xff000000
-#define PCIR_EXPRESS_LINK_CTL 0x10
-#define PCIR_EXPRESS_LINK_STA 0x12
-#define PCIM_LINK_STA_SPEED 0x000f
-#define PCIM_LINK_STA_WIDTH 0x03f0
-#define PCIM_LINK_STA_TRAINING_ERROR 0x0400
-#define PCIM_LINK_STA_TRAINING 0x0800
-#define PCIM_LINK_STA_SLOT_CLOCK 0x1000
-#define PCIR_EXPRESS_SLOT_CAP 0x14
-#define PCIR_EXPRESS_SLOT_CTL 0x18
-#define PCIR_EXPRESS_SLOT_STA 0x1a
-#define PCIR_EXPRESS_ROOT_CTL 0x1c
-#define PCIR_EXPRESS_ROOT_STA 0x20
+#define PCIER_FLAGS 0x2
+#define PCIEM_FLAGS_VERSION 0x000F
+#define PCIEM_FLAGS_TYPE 0x00F0
+#define PCIEM_TYPE_ENDPOINT 0x0000
+#define PCIEM_TYPE_LEGACY_ENDPOINT 0x0010
+#define PCIEM_TYPE_ROOT_PORT 0x0040
+#define PCIEM_TYPE_UPSTREAM_PORT 0x0050
+#define PCIEM_TYPE_DOWNSTREAM_PORT 0x0060
+#define PCIEM_TYPE_PCI_BRIDGE 0x0070
+#define PCIEM_TYPE_PCIE_BRIDGE 0x0080
+#define PCIEM_TYPE_ROOT_INT_EP 0x0090
+#define PCIEM_TYPE_ROOT_EC 0x00a0
+#define PCIEM_FLAGS_SLOT 0x0100
+#define PCIEM_FLAGS_IRQ 0x3e00
+#define PCIER_DEVICE_CAP 0x4
+#define PCIEM_CAP_MAX_PAYLOAD 0x00000007
+#define PCIEM_CAP_PHANTHOM_FUNCS 0x00000018
+#define PCIEM_CAP_EXT_TAG_FIELD 0x00000020
+#define PCIEM_CAP_L0S_LATENCY 0x000001c0
+#define PCIEM_CAP_L1_LATENCY 0x00000e00
+#define PCIEM_CAP_ROLE_ERR_RPT 0x00008000
+#define PCIEM_CAP_SLOT_PWR_LIM_VAL 0x03fc0000
+#define PCIEM_CAP_SLOT_PWR_LIM_SCALE 0x0c000000
+#define PCIEM_CAP_FLR 0x10000000
+#define PCIER_DEVICE_CTL 0x8
+#define PCIEM_CTL_COR_ENABLE 0x0001
+#define PCIEM_CTL_NFER_ENABLE 0x0002
+#define PCIEM_CTL_FER_ENABLE 0x0004
+#define PCIEM_CTL_URR_ENABLE 0x0008
+#define PCIEM_CTL_RELAXED_ORD_ENABLE 0x0010
+#define PCIEM_CTL_MAX_PAYLOAD 0x00e0
+#define PCIEM_CTL_EXT_TAG_FIELD 0x0100
+#define PCIEM_CTL_PHANTHOM_FUNCS 0x0200
+#define PCIEM_CTL_AUX_POWER_PM 0x0400
+#define PCIEM_CTL_NOSNOOP_ENABLE 0x0800
+#define PCIEM_CTL_MAX_READ_REQUEST 0x7000
+#define PCIEM_CTL_BRDG_CFG_RETRY 0x8000 /* PCI-E - PCI/PCI-X bridges */
+#define PCIEM_CTL_INITIATE_FLR 0x8000 /* FLR capable endpoints */
+#define PCIER_DEVICE_STA 0xa
+#define PCIEM_STA_CORRECTABLE_ERROR 0x0001
+#define PCIEM_STA_NON_FATAL_ERROR 0x0002
+#define PCIEM_STA_FATAL_ERROR 0x0004
+#define PCIEM_STA_UNSUPPORTED_REQ 0x0008
+#define PCIEM_STA_AUX_POWER 0x0010
+#define PCIEM_STA_TRANSACTION_PND 0x0020
+#define PCIER_LINK_CAP 0xc
+#define PCIEM_LINK_CAP_MAX_SPEED 0x0000000f
+#define PCIEM_LINK_CAP_MAX_WIDTH 0x000003f0
+#define PCIEM_LINK_CAP_ASPM 0x00000c00
+#define PCIEM_LINK_CAP_L0S_EXIT 0x00007000
+#define PCIEM_LINK_CAP_L1_EXIT 0x00038000
+#define PCIEM_LINK_CAP_CLOCK_PM 0x00040000
+#define PCIEM_LINK_CAP_SURPRISE_DOWN 0x00080000
+#define PCIEM_LINK_CAP_DL_ACTIVE 0x00100000
+#define PCIEM_LINK_CAP_LINK_BW_NOTIFY 0x00200000
+#define PCIEM_LINK_CAP_ASPM_COMPLIANCE 0x00400000
+#define PCIEM_LINK_CAP_PORT 0xff000000
+#define PCIER_LINK_CTL 0x10
+#define PCIEM_LINK_CTL_ASPMC_DIS 0x0000
+#define PCIEM_LINK_CTL_ASPMC_L0S 0x0001
+#define PCIEM_LINK_CTL_ASPMC_L1 0x0002
+#define PCIEM_LINK_CTL_ASPMC 0x0003
+#define PCIEM_LINK_CTL_RCB 0x0008
+#define PCIEM_LINK_CTL_LINK_DIS 0x0010
+#define PCIEM_LINK_CTL_RETRAIN_LINK 0x0020
+#define PCIEM_LINK_CTL_COMMON_CLOCK 0x0040
+#define PCIEM_LINK_CTL_EXTENDED_SYNC 0x0080
+#define PCIEM_LINK_CTL_ECPM 0x0100
+#define PCIEM_LINK_CTL_HAWD 0x0200
+#define PCIEM_LINK_CTL_LBMIE 0x0400
+#define PCIEM_LINK_CTL_LABIE 0x0800
+#define PCIER_LINK_STA 0x12
+#define PCIEM_LINK_STA_SPEED 0x000f
+#define PCIEM_LINK_STA_WIDTH 0x03f0
+#define PCIEM_LINK_STA_TRAINING_ERROR 0x0400
+#define PCIEM_LINK_STA_TRAINING 0x0800
+#define PCIEM_LINK_STA_SLOT_CLOCK 0x1000
+#define PCIEM_LINK_STA_DL_ACTIVE 0x2000
+#define PCIEM_LINK_STA_LINK_BW_MGMT 0x4000
+#define PCIEM_LINK_STA_LINK_AUTO_BW 0x8000
+#define PCIER_SLOT_CAP 0x14
+#define PCIEM_SLOT_CAP_APB 0x00000001
+#define PCIEM_SLOT_CAP_PCP 0x00000002
+#define PCIEM_SLOT_CAP_MRLSP 0x00000004
+#define PCIEM_SLOT_CAP_AIP 0x00000008
+#define PCIEM_SLOT_CAP_PIP 0x00000010
+#define PCIEM_SLOT_CAP_HPS 0x00000020
+#define PCIEM_SLOT_CAP_HPC 0x00000040
+#define PCIEM_SLOT_CAP_SPLV 0x00007f80
+#define PCIEM_SLOT_CAP_SPLS 0x00018000
+#define PCIEM_SLOT_CAP_EIP 0x00020000
+#define PCIEM_SLOT_CAP_NCCS 0x00040000
+#define PCIEM_SLOT_CAP_PSN 0xfff80000
+#define PCIER_SLOT_CTL 0x18
+#define PCIEM_SLOT_CTL_ABPE 0x0001
+#define PCIEM_SLOT_CTL_PFDE 0x0002
+#define PCIEM_SLOT_CTL_MRLSCE 0x0004
+#define PCIEM_SLOT_CTL_PDCE 0x0008
+#define PCIEM_SLOT_CTL_CCIE 0x0010
+#define PCIEM_SLOT_CTL_HPIE 0x0020
+#define PCIEM_SLOT_CTL_AIC 0x00c0
+#define PCIEM_SLOT_CTL_PIC 0x0300
+#define PCIEM_SLOT_CTL_PCC 0x0400
+#define PCIEM_SLOT_CTL_EIC 0x0800
+#define PCIEM_SLOT_CTL_DLLSCE 0x1000
+#define PCIER_SLOT_STA 0x1a
+#define PCIEM_SLOT_STA_ABP 0x0001
+#define PCIEM_SLOT_STA_PFD 0x0002
+#define PCIEM_SLOT_STA_MRLSC 0x0004
+#define PCIEM_SLOT_STA_PDC 0x0008
+#define PCIEM_SLOT_STA_CC 0x0010
+#define PCIEM_SLOT_STA_MRLSS 0x0020
+#define PCIEM_SLOT_STA_PDS 0x0040
+#define PCIEM_SLOT_STA_EIS 0x0080
+#define PCIEM_SLOT_STA_DLLSC 0x0100
+#define PCIER_ROOT_CTL 0x1c
+#define PCIER_ROOT_CAP 0x1e
+#define PCIER_ROOT_STA 0x20
+#define PCIER_DEVICE_CAP2 0x24
+#define PCIER_DEVICE_CTL2 0x28
+#define PCIEM_CTL2_COMP_TIMEOUT_VAL 0x000f
+#define PCIEM_CTL2_COMP_TIMEOUT_DIS 0x0010
+#define PCIEM_CTL2_ARI 0x0020
+#define PCIEM_CTL2_ATOMIC_REQ_ENABLE 0x0040
+#define PCIEM_CTL2_ATOMIC_EGR_BLOCK 0x0080
+#define PCIEM_CTL2_ID_ORDERED_REQ_EN 0x0100
+#define PCIEM_CTL2_ID_ORDERED_CMP_EN 0x0200
+#define PCIEM_CTL2_LTR_ENABLE 0x0400
+#define PCIEM_CTL2_OBFF 0x6000
+#define PCIEM_OBFF_DISABLE 0x0000
+#define PCIEM_OBFF_MSGA_ENABLE 0x2000
+#define PCIEM_OBFF_MSGB_ENABLE 0x4000
+#define PCIEM_OBFF_WAKE_ENABLE 0x6000
+#define PCIEM_CTL2_END2END_TLP 0x8000
+#define PCIER_DEVICE_STA2 0x2a
+#define PCIER_LINK_CAP2 0x2c
+#define PCIER_LINK_CTL2 0x30
+#define PCIER_LINK_STA2 0x32
+#define PCIER_SLOT_CAP2 0x34
+#define PCIER_SLOT_CTL2 0x38
+#define PCIER_SLOT_STA2 0x3a
+
+/* Old compatibility definitions for PCI Express registers */
+#define PCIR_EXPRESS_FLAGS PCIER_FLAGS
+#define PCIM_EXP_FLAGS_VERSION PCIEM_FLAGS_VERSION
+#define PCIM_EXP_FLAGS_TYPE PCIEM_FLAGS_TYPE
+#define PCIM_EXP_TYPE_ENDPOINT PCIEM_TYPE_ENDPOINT
+#define PCIM_EXP_TYPE_LEGACY_ENDPOINT PCIEM_TYPE_LEGACY_ENDPOINT
+#define PCIM_EXP_TYPE_ROOT_PORT PCIEM_TYPE_ROOT_PORT
+#define PCIM_EXP_TYPE_UPSTREAM_PORT PCIEM_TYPE_UPSTREAM_PORT
+#define PCIM_EXP_TYPE_DOWNSTREAM_PORT PCIEM_TYPE_DOWNSTREAM_PORT
+#define PCIM_EXP_TYPE_PCI_BRIDGE PCIEM_TYPE_PCI_BRIDGE
+#define PCIM_EXP_TYPE_PCIE_BRIDGE PCIEM_TYPE_PCIE_BRIDGE
+#define PCIM_EXP_TYPE_ROOT_INT_EP PCIEM_TYPE_ROOT_INT_EP
+#define PCIM_EXP_TYPE_ROOT_EC PCIEM_TYPE_ROOT_EC
+#define PCIM_EXP_FLAGS_SLOT PCIEM_FLAGS_SLOT
+#define PCIM_EXP_FLAGS_IRQ PCIEM_FLAGS_IRQ
+#define PCIR_EXPRESS_DEVICE_CAP PCIER_DEVICE_CAP
+#define PCIM_EXP_CAP_MAX_PAYLOAD PCIEM_CAP_MAX_PAYLOAD
+#define PCIM_EXP_CAP_PHANTHOM_FUNCS PCIEM_CAP_PHANTHOM_FUNCS
+#define PCIM_EXP_CAP_EXT_TAG_FIELD PCIEM_CAP_EXT_TAG_FIELD
+#define PCIM_EXP_CAP_L0S_LATENCY PCIEM_CAP_L0S_LATENCY
+#define PCIM_EXP_CAP_L1_LATENCY PCIEM_CAP_L1_LATENCY
+#define PCIM_EXP_CAP_ROLE_ERR_RPT PCIEM_CAP_ROLE_ERR_RPT
+#define PCIM_EXP_CAP_SLOT_PWR_LIM_VAL PCIEM_CAP_SLOT_PWR_LIM_VAL
+#define PCIM_EXP_CAP_SLOT_PWR_LIM_SCALE PCIEM_CAP_SLOT_PWR_LIM_SCALE
+#define PCIM_EXP_CAP_FLR PCIEM_CAP_FLR
+#define PCIR_EXPRESS_DEVICE_CTL PCIER_DEVICE_CTL
+#define PCIM_EXP_CTL_COR_ENABLE PCIEM_CTL_COR_ENABLE
+#define PCIM_EXP_CTL_NFER_ENABLE PCIEM_CTL_NFER_ENABLE
+#define PCIM_EXP_CTL_FER_ENABLE PCIEM_CTL_FER_ENABLE
+#define PCIM_EXP_CTL_URR_ENABLE PCIEM_CTL_URR_ENABLE
+#define PCIM_EXP_CTL_RELAXED_ORD_ENABLE PCIEM_CTL_RELAXED_ORD_ENABLE
+#define PCIM_EXP_CTL_MAX_PAYLOAD PCIEM_CTL_MAX_PAYLOAD
+#define PCIM_EXP_CTL_EXT_TAG_FIELD PCIEM_CTL_EXT_TAG_FIELD
+#define PCIM_EXP_CTL_PHANTHOM_FUNCS PCIEM_CTL_PHANTHOM_FUNCS
+#define PCIM_EXP_CTL_AUX_POWER_PM PCIEM_CTL_AUX_POWER_PM
+#define PCIM_EXP_CTL_NOSNOOP_ENABLE PCIEM_CTL_NOSNOOP_ENABLE
+#define PCIM_EXP_CTL_MAX_READ_REQUEST PCIEM_CTL_MAX_READ_REQUEST
+#define PCIM_EXP_CTL_BRDG_CFG_RETRY PCIEM_CTL_BRDG_CFG_RETRY
+#define PCIM_EXP_CTL_INITIATE_FLR PCIEM_CTL_INITIATE_FLR
+#define PCIR_EXPRESS_DEVICE_STA PCIER_DEVICE_STA
+#define PCIM_EXP_STA_CORRECTABLE_ERROR PCIEM_STA_CORRECTABLE_ERROR
+#define PCIM_EXP_STA_NON_FATAL_ERROR PCIEM_STA_NON_FATAL_ERROR
+#define PCIM_EXP_STA_FATAL_ERROR PCIEM_STA_FATAL_ERROR
+#define PCIM_EXP_STA_UNSUPPORTED_REQ PCIEM_STA_UNSUPPORTED_REQ
+#define PCIM_EXP_STA_AUX_POWER PCIEM_STA_AUX_POWER
+#define PCIM_EXP_STA_TRANSACTION_PND PCIEM_STA_TRANSACTION_PND
+#define PCIR_EXPRESS_LINK_CAP PCIER_LINK_CAP
+#define PCIM_LINK_CAP_MAX_SPEED PCIEM_LINK_CAP_MAX_SPEED
+#define PCIM_LINK_CAP_MAX_WIDTH PCIEM_LINK_CAP_MAX_WIDTH
+#define PCIM_LINK_CAP_ASPM PCIEM_LINK_CAP_ASPM
+#define PCIM_LINK_CAP_L0S_EXIT PCIEM_LINK_CAP_L0S_EXIT
+#define PCIM_LINK_CAP_L1_EXIT PCIEM_LINK_CAP_L1_EXIT
+#define PCIM_LINK_CAP_CLOCK_PM PCIEM_LINK_CAP_CLOCK_PM
+#define PCIM_LINK_CAP_SURPRISE_DOWN PCIEM_LINK_CAP_SURPRISE_DOWN
+#define PCIM_LINK_CAP_DL_ACTIVE PCIEM_LINK_CAP_DL_ACTIVE
+#define PCIM_LINK_CAP_LINK_BW_NOTIFY PCIEM_LINK_CAP_LINK_BW_NOTIFY
+#define PCIM_LINK_CAP_ASPM_COMPLIANCE PCIEM_LINK_CAP_ASPM_COMPLIANCE
+#define PCIM_LINK_CAP_PORT PCIEM_LINK_CAP_PORT
+#define PCIR_EXPRESS_LINK_CTL PCIER_LINK_CTL
+#define PCIM_EXP_LINK_CTL_ASPMC_DIS PCIEM_LINK_CTL_ASPMC_DIS
+#define PCIM_EXP_LINK_CTL_ASPMC_L0S PCIEM_LINK_CTL_ASPMC_L0S
+#define PCIM_EXP_LINK_CTL_ASPMC_L1 PCIEM_LINK_CTL_ASPMC_L1
+#define PCIM_EXP_LINK_CTL_ASPMC PCIEM_LINK_CTL_ASPMC
+#define PCIM_EXP_LINK_CTL_RCB PCIEM_LINK_CTL_RCB
+#define PCIM_EXP_LINK_CTL_LINK_DIS PCIEM_LINK_CTL_LINK_DIS
+#define PCIM_EXP_LINK_CTL_RETRAIN_LINK PCIEM_LINK_CTL_RETRAIN_LINK
+#define PCIM_EXP_LINK_CTL_COMMON_CLOCK PCIEM_LINK_CTL_COMMON_CLOCK
+#define PCIM_EXP_LINK_CTL_EXTENDED_SYNC PCIEM_LINK_CTL_EXTENDED_SYNC
+#define PCIM_EXP_LINK_CTL_ECPM PCIEM_LINK_CTL_ECPM
+#define PCIM_EXP_LINK_CTL_HAWD PCIEM_LINK_CTL_HAWD
+#define PCIM_EXP_LINK_CTL_LBMIE PCIEM_LINK_CTL_LBMIE
+#define PCIM_EXP_LINK_CTL_LABIE PCIEM_LINK_CTL_LABIE
+#define PCIR_EXPRESS_LINK_STA PCIER_LINK_STA
+#define PCIM_LINK_STA_SPEED PCIEM_LINK_STA_SPEED
+#define PCIM_LINK_STA_WIDTH PCIEM_LINK_STA_WIDTH
+#define PCIM_LINK_STA_TRAINING_ERROR PCIEM_LINK_STA_TRAINING_ERROR
+#define PCIM_LINK_STA_TRAINING PCIEM_LINK_STA_TRAINING
+#define PCIM_LINK_STA_SLOT_CLOCK PCIEM_LINK_STA_SLOT_CLOCK
+#define PCIM_LINK_STA_DL_ACTIVE PCIEM_LINK_STA_DL_ACTIVE
+#define PCIM_LINK_STA_LINK_BW_MGMT PCIEM_LINK_STA_LINK_BW_MGMT
+#define PCIM_LINK_STA_LINK_AUTO_BW PCIEM_LINK_STA_LINK_AUTO_BW
+#define PCIR_EXPRESS_SLOT_CAP PCIER_SLOT_CAP
+#define PCIR_EXPRESS_SLOT_CTL PCIER_SLOT_CTL
+#define PCIR_EXPRESS_SLOT_STA PCIER_SLOT_STA
+#define PCIR_EXPRESS_ROOT_CTL PCIER_ROOT_CTL
+#define PCIR_EXPRESS_ROOT_CAP PCIER_ROOT_CAP
+#define PCIR_EXPRESS_ROOT_STA PCIER_ROOT_STA
+#define PCIR_EXPRESS_DEVICE_CAP2 PCIER_DEVICE_CAP2
+#define PCIR_EXPRESS_DEVICE_CTL2 PCIER_DEVICE_CTL2
+#define PCIM_EXP_CTL2_COMP_TIMEOUT_VAL PCIEM_CTL2_COMP_TIMEOUT_VAL
+#define PCIM_EXP_CTL2_COMP_TIMEOUT_DIS PCIEM_CTL2_COMP_TIMEOUT_DIS
+#define PCIM_EXP_CTL2_ARI PCIEM_CTL2_ARI
+#define PCIM_EXP_CTL2_ATOMIC_REQ_ENABLE PCIEM_CTL2_ATOMIC_REQ_ENABLE
+#define PCIM_EXP_CTL2_ATOMIC_EGR_BLOCK PCIEM_CTL2_ATOMIC_EGR_BLOCK
+#define PCIM_EXP_CTL2_ID_ORDERED_REQ_EN PCIEM_CTL2_ID_ORDERED_REQ_EN
+#define PCIM_EXP_CTL2_ID_ORDERED_CMP_EN PCIEM_CTL2_ID_ORDERED_CMP_EN
+#define PCIM_EXP_CTL2_LTR_ENABLE PCIEM_CTL2_LTR_ENABLE
+#define PCIM_EXP_CTL2_OBFF PCIEM_CTL2_OBFF
+#define PCIM_EXP_OBFF_DISABLE PCIEM_OBFF_DISABLE
+#define PCIM_EXP_OBFF_MSGA_ENABLE PCIEM_OBFF_MSGA_ENABLE
+#define PCIM_EXP_OBFF_MSGB_ENABLE PCIEM_OBFF_MSGB_ENABLE
+#define PCIM_EXP_OBFF_WAKE_ENABLE PCIEM_OBFF_WAKE_ENABLE
+#define PCIM_EXP_CTL2_END2END_TLP PCIEM_CTL2_END2END_TLP
+#define PCIR_EXPRESS_DEVICE_STA2 PCIER_DEVICE_STA2
+#define PCIR_EXPRESS_LINK_CAP2 PCIER_LINK_CAP2
+#define PCIR_EXPRESS_LINK_CTL2 PCIER_LINK_CTL2
+#define PCIR_EXPRESS_LINK_STA2 PCIER_LINK_STA2
+#define PCIR_EXPRESS_SLOT_CAP2 PCIER_SLOT_CAP2
+#define PCIR_EXPRESS_SLOT_CTL2 PCIER_SLOT_CTL2
+#define PCIR_EXPRESS_SLOT_STA2 PCIER_SLOT_STA2
/* MSI-X definitions */
#define PCIR_MSIX_CTRL 0x2
@@ -692,6 +911,7 @@
#define PCIR_AER_UC_STATUS 0x04
#define PCIM_AER_UC_TRAINING_ERROR 0x00000001
#define PCIM_AER_UC_DL_PROTOCOL_ERROR 0x00000010
+#define PCIM_AER_UC_SURPRISE_LINK_DOWN 0x00000020
#define PCIM_AER_UC_POISONED_TLP 0x00001000
#define PCIM_AER_UC_FC_PROTOCOL_ERROR 0x00002000
#define PCIM_AER_UC_COMPLETION_TIMEOUT 0x00004000
@@ -702,6 +922,10 @@
#define PCIM_AER_UC_ECRC_ERROR 0x00080000
#define PCIM_AER_UC_UNSUPPORTED_REQUEST 0x00100000
#define PCIM_AER_UC_ACS_VIOLATION 0x00200000
+#define PCIM_AER_UC_INTERNAL_ERROR 0x00400000
+#define PCIM_AER_UC_MC_BLOCKED_TLP 0x00800000
+#define PCIM_AER_UC_ATOMIC_EGRESS_BLK 0x01000000
+#define PCIM_AER_UC_TLP_PREFIX_BLOCKED 0x02000000
#define PCIR_AER_UC_MASK 0x08 /* Shares bits with UC_STATUS */
#define PCIR_AER_UC_SEVERITY 0x0c /* Shares bits with UC_STATUS */
#define PCIR_AER_COR_STATUS 0x10
@@ -710,6 +934,9 @@
#define PCIM_AER_COR_BAD_DLLP 0x00000080
#define PCIM_AER_COR_REPLAY_ROLLOVER 0x00000100
#define PCIM_AER_COR_REPLAY_TIMEOUT 0x00001000
+#define PCIM_AER_COR_ADVISORY_NF_ERROR 0x00002000
+#define PCIM_AER_COR_INTERNAL_ERROR 0x00004000
+#define PCIM_AER_COR_HEADER_LOG_OVFLOW 0x00008000
#define PCIR_AER_COR_MASK 0x14 /* Shares bits with COR_STATUS */
#define PCIR_AER_CAP_CONTROL 0x18
#define PCIM_AER_FIRST_ERROR_PTR 0x0000001f
@@ -717,6 +944,9 @@
#define PCIM_AER_ECRC_GEN_ENABLE 0x00000040
#define PCIM_AER_ECRC_CHECK_CAPABLE 0x00000080
#define PCIM_AER_ECRC_CHECK_ENABLE 0x00000100
+#define PCIM_AER_MULT_HDR_CAPABLE 0x00000200
+#define PCIM_AER_MULT_HDR_ENABLE 0x00000400
+#define PCIM_AER_TLP_PREFIX_LOG_PRESENT 0x00000800
#define PCIR_AER_HEADER_LOG 0x1c
#define PCIR_AER_ROOTERR_CMD 0x2c /* Only for root complex ports */
#define PCIM_AER_ROOTERR_COR_ENABLE 0x00000001
@@ -733,6 +963,7 @@
#define PCIM_AER_ROOTERR_INT_MESSAGE 0xf8000000
#define PCIR_AER_COR_SOURCE_ID 0x34 /* Only for root complex ports */
#define PCIR_AER_ERR_SOURCE_ID 0x36 /* Only for root complex ports */
+#define PCIR_AER_TLP_PREFIX_LOG 0x38 /* Only for TLP prefix functions */
/* Virtual Channel definitions */
#define PCIR_VC_CAP1 0x04
diff --git a/freebsd/sys/dev/pci/pcivar.h b/freebsd/sys/dev/pci/pcivar.h
index 8e2da638..63adb09d 100644
--- a/freebsd/sys/dev/pci/pcivar.h
+++ b/freebsd/sys/dev/pci/pcivar.h
@@ -46,7 +46,14 @@ struct pcicfg_pp {
uint8_t pp_pmcsr; /* config space address of PMCSR reg */
uint8_t pp_data; /* config space address of PCI power data reg */
};
-
+
+struct pci_map {
+ pci_addr_t pm_value; /* Raw BAR value */
+ pci_addr_t pm_size;
+ uint8_t pm_reg;
+ STAILQ_ENTRY(pci_map) pm_link;
+};
+
struct vpd_readonly {
char keyword[2];
char *value;
@@ -110,6 +117,7 @@ struct pcicfg_msix {
/* Interesting values for HyperTransport */
struct pcicfg_ht {
+ uint8_t ht_slave; /* Non-zero if device is an HT slave. */
uint8_t ht_msimap; /* Offset of MSI mapping cap registers. */
uint16_t ht_msictrl; /* MSI mapping control */
uint64_t ht_msiaddr; /* MSI mapping base address */
@@ -119,8 +127,7 @@ struct pcicfg_ht {
typedef struct pcicfg {
struct device *dev; /* device which owns this */
- uint32_t bar[PCI_MAXMAPS_0]; /* BARs */
- uint32_t bios; /* BIOS mapping */
+ STAILQ_HEAD(, pci_map) maps; /* BARs */
uint16_t subvendor; /* card vendor ID */
uint16_t subdevice; /* card device ID, assigned by card vendor */
@@ -403,9 +410,15 @@ pci_get_powerstate(device_t dev)
}
static __inline int
+pci_find_cap(device_t dev, int capability, int *capreg)
+{
+ return (PCI_FIND_EXTCAP(device_get_parent(dev), dev, capability, capreg));
+}
+
+static __inline int
pci_find_extcap(device_t dev, int capability, int *capreg)
{
- return PCI_FIND_EXTCAP(device_get_parent(dev), dev, capability, capreg);
+ return (PCI_FIND_EXTCAP(device_get_parent(dev), dev, capability, capreg));
}
static __inline int
@@ -446,9 +459,7 @@ pci_msix_count(device_t dev)
device_t pci_find_bsf(uint8_t, uint8_t, uint8_t);
device_t pci_find_dbsf(uint32_t, uint8_t, uint8_t, uint8_t);
-#ifndef __rtems__
device_t pci_find_device(uint16_t, uint16_t);
-#endif /* __rtems__ */
/* Can be used by drivers to manage the MSI-X table. */
int pci_pending_msix(device_t dev, u_int index);
@@ -458,6 +469,8 @@ int pci_msi_device_blacklisted(device_t dev);
void pci_ht_map_msi(device_t dev, uint64_t addr);
int pci_get_max_read_req(device_t dev);
+void pci_restore_state(device_t dev);
+void pci_save_state(device_t dev);
int pci_set_max_read_req(device_t dev, int size);
#endif /* _SYS_BUS_H_ */
@@ -475,4 +488,7 @@ STAILQ_HEAD(devlist, pci_devinfo);
extern struct devlist pci_devq;
extern uint32_t pci_generation;
+struct pci_map *pci_find_bar(device_t dev, int reg);
+int pci_bar_enabled(device_t dev, struct pci_map *pm);
+
#endif /* _PCIVAR_H_ */