summaryrefslogtreecommitdiffstats
path: root/sys/dev/cardbus/cardbus_cis.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/cardbus/cardbus_cis.c')
-rw-r--r--sys/dev/cardbus/cardbus_cis.c26
1 files changed, 22 insertions, 4 deletions
diff --git a/sys/dev/cardbus/cardbus_cis.c b/sys/dev/cardbus/cardbus_cis.c
index 204749f..2b8e2b2 100644
--- a/sys/dev/cardbus/cardbus_cis.c
+++ b/sys/dev/cardbus/cardbus_cis.c
@@ -393,7 +393,7 @@ decode_tuple_bar(device_t cbdev, device_t child, int id,
struct cardbus_devinfo *dinfo = device_get_ivars(child);
int type;
uint8_t reg;
- uint32_t bar;
+ uint32_t bar, pci_bar;
if (len != 6) {
device_printf(cbdev, "CIS BAR length not 6 (%d)\n", len);
@@ -416,16 +416,33 @@ decode_tuple_bar(device_t cbdev, device_t child, int id,
/* XXX Should we try to map in Option ROMs? */
return (0);
}
-
+
+ /* Convert from BAR type to BAR offset */
bar = CARDBUS_BASE0_REG + (bar - 1) * 4;
if (type == SYS_RES_MEMORY) {
- if (bar & TPL_BAR_REG_PREFETCHABLE)
+ if (reg & TPL_BAR_REG_PREFETCHABLE)
dinfo->mprefetchable |= BARBIT(bar);
- if (bar & TPL_BAR_REG_BELOW1MB)
+ if (reg & TPL_BAR_REG_BELOW1MB)
dinfo->mbelow1mb |= BARBIT(bar);
}
+ /*
+ * Sanity check the BAR length reported in the CIS with the length
+ * encoded in the PCI BAR. The latter seems to be more reliable.
+ * XXX - This probably belongs elsewhere.
+ */
+ pci_write_config(child, bar, 0xffffffff, 4);
+ pci_bar = pci_read_config(child, bar, 4);
+ if ((pci_bar != 0x0) && (pci_bar != 0xffffffff)) {
+ if (type == SYS_RES_MEMORY) {
+ pci_bar &= ~0xf;
+ } else {
+ pci_bar &= ~0x3;
+ }
+ len = 1 << (ffs(pci_bar) - 1);
+ }
+
DEVPRINTF((cbdev, "Opening BAR: type=%s, bar=%02x, len=%04x%s%s\n",
(type == SYS_RES_MEMORY) ? "MEM" : "IO", bar, len,
(type == SYS_RES_MEMORY && dinfo->mprefetchable & BARBIT(bar)) ?
@@ -439,6 +456,7 @@ decode_tuple_bar(device_t cbdev, device_t child, int id,
* device drivers will know which type of BARs can be used.
*/
pci_enable_io(child, type);
+
return (0);
}
OpenPOWER on IntegriCloud