/* * QUIRK to workaround cantiga VT-d buffer flush issue. * The workaround is to force write buffer flush even if * VT-d capability indicates it is not required. */ static void cantiga_b3_errata_init(void) { u16 vid; u8 did_hi, rid; vid = pci_conf_read16(0, IGD_DEV, 0, 0); if ( vid != 0x8086 ) return; did_hi = pci_conf_read8(0, IGD_DEV, 0, 3); rid = pci_conf_read8(0, IGD_DEV, 0, 8); if ( (did_hi == 0x2A) && (rid == 0x7) ) is_cantiga_b3 = 1; }
static void check_pdev(const struct pci_dev *pdev) { #define PCI_STATUS_CHECK \ (PCI_STATUS_PARITY | PCI_STATUS_SIG_TARGET_ABORT | \ PCI_STATUS_REC_TARGET_ABORT | PCI_STATUS_REC_MASTER_ABORT | \ PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY) u16 seg = pdev->seg; u8 bus = pdev->bus; u8 dev = PCI_SLOT(pdev->devfn); u8 func = PCI_FUNC(pdev->devfn); u16 val; if ( command_mask ) { val = pci_conf_read16(seg, bus, dev, func, PCI_COMMAND); if ( val & command_mask ) pci_conf_write16(seg, bus, dev, func, PCI_COMMAND, val & ~command_mask); val = pci_conf_read16(seg, bus, dev, func, PCI_STATUS); if ( val & PCI_STATUS_CHECK ) { printk(XENLOG_INFO "%04x:%02x:%02x.%u status %04x -> %04x\n", seg, bus, dev, func, val, val & ~PCI_STATUS_CHECK); pci_conf_write16(seg, bus, dev, func, PCI_STATUS, val & PCI_STATUS_CHECK); } } switch ( pci_conf_read8(seg, bus, dev, func, PCI_HEADER_TYPE) & 0x7f ) { case PCI_HEADER_TYPE_BRIDGE: if ( !bridge_ctl_mask ) break; val = pci_conf_read16(seg, bus, dev, func, PCI_BRIDGE_CONTROL); if ( val & bridge_ctl_mask ) pci_conf_write16(seg, bus, dev, func, PCI_BRIDGE_CONTROL, val & ~bridge_ctl_mask); val = pci_conf_read16(seg, bus, dev, func, PCI_SEC_STATUS); if ( val & PCI_STATUS_CHECK ) { printk(XENLOG_INFO "%04x:%02x:%02x.%u secondary status %04x -> %04x\n", seg, bus, dev, func, val, val & ~PCI_STATUS_CHECK); pci_conf_write16(seg, bus, dev, func, PCI_SEC_STATUS, val & PCI_STATUS_CHECK); } break; case PCI_HEADER_TYPE_CARDBUS: /* TODO */ break; } #undef PCI_STATUS_CHECK }
/* 5500/5520/X58 Chipset Interrupt remapping errata, for stepping B-3. * Fixed in stepping C-2. */ static void __init tylersburg_intremap_quirk(void) { uint32_t bus, device; uint8_t rev; for ( bus = 0; bus < 0x100; bus++ ) { /* Match on System Management Registers on Device 20 Function 0 */ device = pci_conf_read32(bus, 20, 0, PCI_VENDOR_ID); rev = pci_conf_read8(bus, 20, 0, PCI_REVISION_ID); if ( rev == 0x13 && device == 0x342e8086 ) { printk(XENLOG_WARNING VTDPREFIX "Disabling IOMMU due to Intel 5500/5520/X58 Chipset errata #47, #53\n"); iommu_enabled = 0; break; } } }
static struct pci_dev *alloc_pdev(struct pci_seg *pseg, u8 bus, u8 devfn) { struct pci_dev *pdev; list_for_each_entry ( pdev, &pseg->alldevs_list, alldevs_list ) if ( pdev->bus == bus && pdev->devfn == devfn ) return pdev; pdev = xzalloc(struct pci_dev); if ( !pdev ) return NULL; *(u16*) &pdev->seg = pseg->nr; *((u8*) &pdev->bus) = bus; *((u8*) &pdev->devfn) = devfn; pdev->domain = NULL; INIT_LIST_HEAD(&pdev->msi_list); if ( pci_find_cap_offset(pseg->nr, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), PCI_CAP_ID_MSIX) ) { struct arch_msix *msix = xzalloc(struct arch_msix); if ( !msix ) { xfree(pdev); return NULL; } spin_lock_init(&msix->table_lock); pdev->msix = msix; } list_add(&pdev->alldevs_list, &pseg->alldevs_list); /* update bus2bridge */ switch ( pdev->type = pdev_type(pseg->nr, bus, devfn) ) { int pos; u16 cap; u8 sec_bus, sub_bus; case DEV_TYPE_PCIe2PCI_BRIDGE: case DEV_TYPE_LEGACY_PCI_BRIDGE: sec_bus = pci_conf_read8(pseg->nr, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), PCI_SECONDARY_BUS); sub_bus = pci_conf_read8(pseg->nr, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), PCI_SUBORDINATE_BUS); spin_lock(&pseg->bus2bridge_lock); for ( ; sec_bus <= sub_bus; sec_bus++ ) { pseg->bus2bridge[sec_bus].map = 1; pseg->bus2bridge[sec_bus].bus = bus; pseg->bus2bridge[sec_bus].devfn = devfn; } spin_unlock(&pseg->bus2bridge_lock); break; case DEV_TYPE_PCIe_ENDPOINT: pos = pci_find_cap_offset(pseg->nr, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), PCI_CAP_ID_EXP); BUG_ON(!pos); cap = pci_conf_read16(pseg->nr, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), pos + PCI_EXP_DEVCAP); if ( cap & PCI_EXP_DEVCAP_PHANTOM ) { pdev->phantom_stride = 8 >> MASK_EXTR(cap, PCI_EXP_DEVCAP_PHANTOM); if ( PCI_FUNC(devfn) >= pdev->phantom_stride ) pdev->phantom_stride = 0; } else {
void __init vga_endboot(void) { if ( vga_puts == vga_noop_puts ) return; printk("Xen is %s VGA console.\n", vgacon_keep ? "keeping" : "relinquishing"); if ( !vgacon_keep ) vga_puts = vga_noop_puts; else { int bus, devfn; for ( bus = 0; bus < 256; ++bus ) for ( devfn = 0; devfn < 256; ++devfn ) { const struct pci_dev *pdev; u8 b = bus, df = devfn, sb; spin_lock(&pcidevs_lock); pdev = pci_get_pdev(0, bus, devfn); spin_unlock(&pcidevs_lock); if ( !pdev || pci_conf_read16(0, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), PCI_CLASS_DEVICE) != 0x0300 || !(pci_conf_read16(0, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), PCI_COMMAND) & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) ) continue; while ( b ) { switch ( find_upstream_bridge(0, &b, &df, &sb) ) { case 0: b = 0; break; case 1: switch ( pci_conf_read8(0, b, PCI_SLOT(df), PCI_FUNC(df), PCI_HEADER_TYPE) ) { case PCI_HEADER_TYPE_BRIDGE: case PCI_HEADER_TYPE_CARDBUS: if ( pci_conf_read16(0, b, PCI_SLOT(df), PCI_FUNC(df), PCI_BRIDGE_CONTROL) & PCI_BRIDGE_CTL_VGA ) continue; break; } break; } break; } if ( !b ) { printk(XENLOG_INFO "Boot video device %02x:%02x.%u\n", bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); pci_hide_device(bus, devfn); } } } switch ( vga_console_info.video_type ) { case XEN_VGATYPE_TEXT_MODE_3: if ( !vgacon_keep ) memset(video, 0, columns * lines * 2); break; case XEN_VGATYPE_VESA_LFB: case XEN_VGATYPE_EFI_LFB: vesa_endboot(vgacon_keep); break; default: BUG(); } }
static void pcie_scanbus(struct pci_tegra_device *dev_parent) { u8 subordinate_bus; u8 hdr_type; u8 next_bus_number; u32 device = 0; u32 id; struct pci_tegra_device *dev; u32 retry_count; next_bus_number = dev_parent->sec_bus; next_device: retry_count = 6; if (device == 0x20) { /* Termination condition: Max number of devices reached. * PCIe bus segment can only have 32 devices. * */ dev_parent->sub_bus = next_bus_number; if (!dev_parent->root_port) { /* Change the subordinate bus-number to the actual * value of all buses on the hierarcy. * * Do this execpt for the root port. */ pci_conf_write8(dev_parent->bus, dev_parent->devfn, PCI_SUBORDINATE_BUS, next_bus_number); } return; } if (dev_parent->root_port && device != 0) { /* Sepcial Exit condition for root port. * Root port only connect to one bridge or device. */ dev_parent->sub_bus = dev_parent->sec_bus; return; } while (--retry_count) { id = pci_conf_read32(dev_parent->sec_bus, PCI_DEVFN(device, 0), 0); if (id != 0xFFFFFFFF) { /* Found a valid device, break. Otherwise, retry a couple of * times. It is possible that the bridges can take some time * to settle and it will take couple of transcations to find * the devcies behind the bridge. * */ /* FIXME: What should be the delay? */ msleep(100); break; } } if (id == 0xFFFFFFFF) { /* Invalid device. Skip that one and look for next device */ device++; goto next_device; } dev = alloc_pci_tegra_device(); /* Fill the device information */ dev->parent = dev_parent; dev->id = id; dev->bus = dev_parent->sec_bus; dev->devfn = PCI_DEVFN(device, 0); if (dev_parent->child == NULL) { dev_parent->child = dev; dev->prev = NULL; } else { /* Add dev to the list of devices on the same bus */ struct pci_tegra_device *temp; temp = dev_parent->child; BUG_ON(temp != NULL); while (temp->next != NULL) temp = temp->next; temp->next = dev; dev->prev = temp; } hdr_type = pci_conf_read8(dev->bus, dev->devfn, PCI_HEADER_TYPE); if ((hdr_type & 0x7f) == 0x1) { /* Bridge device */ /* Temporarily assign 0xff for the subordinate bus number as * we don't * know how many devices are present behind this * bridge. * */ subordinate_bus = 0xff; dev->sec_bus = next_bus_number + 1; pci_conf_write8(dev->bus, dev->devfn, PCI_PRIMARY_BUS, dev_parent->sec_bus); pci_conf_write8(dev->bus, dev->devfn, PCI_SECONDARY_BUS, dev->sec_bus); pci_conf_write8(dev->bus, dev->devfn, PCI_SUBORDINATE_BUS, subordinate_bus); /* Scan all the buses behind this bridge */ pcie_scanbus(dev); next_bus_number = dev->sub_bus; } else if ((hdr_type & 0x7f) == 0x0) { /* PCI endpoint - Can be single function or multie function */ pr_info("PCI endpoint (0x%x) is on bus = %d, device = %d\n", id, dev_parent->sec_bus, device); } else if ((hdr_type & 0x7f) == 0x2) { /* PC card device - Not handled */ BUG(); } else { BUG(); } device++; goto next_device; }