static NTSTATUS DumpBaseAddressRegister64(u8 bus, u8 slot, u8 func, u8 offset, struct PmemMemoryInfo *info, int len) { u64 base = read_pci_config(bus, slot, func, offset); u32 base_high = read_pci_config(bus, slot, func, offset + sizeof(u32)); u32 mask = 0; u32 mask_high = 0; u64 end = 0; u16 command = read_pci_config_16(bus, slot, func, PCI_COMMAND); // Disable IO and memory bus access. write_pci_config_16(bus, slot, func, PCI_COMMAND, 0); // Check the lower word first. write_pci_config(bus, slot, func, offset, 0xFFFFFFFF); mask = read_pci_config(bus, slot, func, offset) & 0xFFFFFFF0; write_pci_config(bus, slot, func, offset, (u32)base); // Check the upper 32 bit word. write_pci_config(bus, slot, func, offset + sizeof(u32), 0xFFFFFFFF); mask_high = read_pci_config(bus, slot, func, offset + sizeof(u32)); write_pci_config(bus, slot, func, offset + sizeof(u32), (u32)base_high); // Reenable bus access. write_pci_config_16(bus, slot, func, PCI_COMMAND, command); base = ((base & 0xFFFFFFF0) | ((u64)base_high) << 32); end = ~(mask | ((u64)mask_high) << 32) + base; return InsertMemoryHole(info, len, base, end); };
static void __iomem * __init xdbc_map_pci_mmio(u32 bus, u32 dev, u32 func) { u64 val64, sz64, mask64; void __iomem *base; u32 val, sz; u8 byte; val = read_pci_config(bus, dev, func, PCI_BASE_ADDRESS_0); write_pci_config(bus, dev, func, PCI_BASE_ADDRESS_0, ~0); sz = read_pci_config(bus, dev, func, PCI_BASE_ADDRESS_0); write_pci_config(bus, dev, func, PCI_BASE_ADDRESS_0, val); if (val == 0xffffffff || sz == 0xffffffff) { pr_notice("invalid mmio bar\n"); return NULL; } val64 = val & PCI_BASE_ADDRESS_MEM_MASK; sz64 = sz & PCI_BASE_ADDRESS_MEM_MASK; mask64 = PCI_BASE_ADDRESS_MEM_MASK; if ((val & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64) { val = read_pci_config(bus, dev, func, PCI_BASE_ADDRESS_0 + 4); write_pci_config(bus, dev, func, PCI_BASE_ADDRESS_0 + 4, ~0); sz = read_pci_config(bus, dev, func, PCI_BASE_ADDRESS_0 + 4); write_pci_config(bus, dev, func, PCI_BASE_ADDRESS_0 + 4, val); val64 |= (u64)val << 32; sz64 |= (u64)sz << 32; mask64 |= ~0ULL << 32; } sz64 &= mask64; if (!sz64) { pr_notice("invalid mmio address\n"); return NULL; } sz64 = 1ULL << __ffs64(sz64); /* Check if the mem space is enabled: */ byte = read_pci_config_byte(bus, dev, func, PCI_COMMAND); if (!(byte & PCI_COMMAND_MEMORY)) { byte |= PCI_COMMAND_MEMORY; write_pci_config_byte(bus, dev, func, PCI_COMMAND, byte); } xdbc.xhci_start = val64; xdbc.xhci_length = sz64; base = early_ioremap(val64, sz64); return base; }
int __init get_iommu_capabilities(u8 bus, u8 dev, u8 func, u8 cap_ptr, struct amd_iommu *iommu) { u32 cap_header, cap_range; u64 mmio_bar; /* remove it when BIOS available */ write_pci_config(bus, dev, func, cap_ptr + PCI_CAP_MMIO_BAR_HIGH_OFFSET, 0x00000000); write_pci_config(bus, dev, func, cap_ptr + PCI_CAP_MMIO_BAR_LOW_OFFSET, 0x40000001); /* remove it when BIOS available */ mmio_bar = (u64)read_pci_config(bus, dev, func, cap_ptr + PCI_CAP_MMIO_BAR_HIGH_OFFSET) << 32; mmio_bar |= read_pci_config(bus, dev, func, cap_ptr + PCI_CAP_MMIO_BAR_LOW_OFFSET) & PCI_CAP_MMIO_BAR_LOW_MASK; iommu->mmio_base_phys = (unsigned long)mmio_bar; if ( (mmio_bar == 0) || ( (mmio_bar & 0x3FFF) != 0 ) ) { dprintk(XENLOG_ERR , "AMD IOMMU: Invalid MMIO_BAR = 0x%"PRIx64"\n", mmio_bar); return -ENODEV; } cap_header = read_pci_config(bus, dev, func, cap_ptr); iommu->revision = get_field_from_reg_u32(cap_header, PCI_CAP_REV_MASK, PCI_CAP_REV_SHIFT); iommu->iotlb_support = get_field_from_reg_u32(cap_header, PCI_CAP_IOTLB_MASK, PCI_CAP_IOTLB_SHIFT); iommu->ht_tunnel_support = get_field_from_reg_u32(cap_header, PCI_CAP_HT_TUNNEL_MASK, PCI_CAP_HT_TUNNEL_SHIFT); iommu->not_present_cached = get_field_from_reg_u32(cap_header, PCI_CAP_NP_CACHE_MASK, PCI_CAP_NP_CACHE_SHIFT); cap_range = read_pci_config(bus, dev, func, cap_ptr + PCI_CAP_RANGE_OFFSET); iommu->root_bus = get_field_from_reg_u32(cap_range, PCI_CAP_BUS_NUMBER_MASK, PCI_CAP_BUS_NUMBER_SHIFT); iommu->first_devfn = get_field_from_reg_u32(cap_range, PCI_CAP_FIRST_DEVICE_MASK, PCI_CAP_FIRST_DEVICE_SHIFT); iommu->last_devfn = get_field_from_reg_u32(cap_range, PCI_CAP_LAST_DEVICE_MASK, PCI_CAP_LAST_DEVICE_SHIFT); return 0; }
static void __init fix_hypertransport_config(int num, int slot, int func) { u32 htcfg; /* * we found a hypertransport bus * make sure that we are broadcasting * interrupts to all cpus on the ht bus * if we're using extended apic ids */ htcfg = read_pci_config(num, slot, func, 0x68); if (htcfg & (1 << 18)) { printk(KERN_INFO "Detected use of extended apic ids " "on hypertransport bus\n"); if ((htcfg & (1 << 17)) == 0) { printk(KERN_INFO "Enabling hypertransport extended " "apic interrupt broadcast\n"); printk(KERN_INFO "Note this is a bios bug, " "please contact your hw vendor\n"); htcfg |= (1 << 17); write_pci_config(num, slot, func, 0x68, htcfg); } } }
static NTSTATUS DumpBaseAddressRegister32(u8 bus, u8 slot, u8 func, u8 offset, struct PmemMemoryInfo *info, int len) { u32 mask = 0; u32 base = read_pci_config(bus, slot, func, offset); u16 command = read_pci_config_16(bus, slot, func, PCI_COMMAND); // Disable IO and memory bus access. write_pci_config_16(bus, slot, func, PCI_COMMAND, 0); write_pci_config(bus, slot, func, offset, 0xFFFFFFFF); mask = read_pci_config(bus, slot, func, offset) & 0xFFFFFFF0; write_pci_config(bus, slot, func, offset, base); // Reenable bus access. write_pci_config_16(bus, slot, func, PCI_COMMAND, command); base = base & 0xFFFFFFF0; return InsertMemoryHole(info, len, base, ~mask + base); };
ACPI_STATUS AcpiOsWritePciConfiguration ( ACPI_PCI_ID *PciId, UINT32 PciRegister, UINT64 Value, UINT32 Width) { write_pci_config(PciId->Segment, PciId->Bus, PciId->Device, PciId->Function, PciRegister, Value); return (AE_OK); }
u32 get_base_register_size(u8 bus, u8 slot, u8 func, u8 offset) { __int32 base = read_pci_config(bus, slot, func, offset); u32 mask = 0; u16 command =0; if (base == 0) return 0; command = read_pci_config_16(bus, slot, func, PCI_COMMAND); // Disable IO and memory bus access. write_pci_config_16(bus, slot, func, PCI_COMMAND, 0); // Write to config space all 0xFFFFFFFF write_pci_config(bus, slot, func, offset, 0xFFFFFFFF); mask = read_pci_config(bus, slot, func, offset) & 0xFFFFFFF0; write_pci_config(bus, slot, func, offset, base); // Reenable bus access. write_pci_config_16(bus, slot, func, PCI_COMMAND, command); return ~mask + base; };
static u32 __init ati_ixp4x0_rev(int num, int slot, int func) { u32 d; u8 b; b = read_pci_config_byte(num, slot, func, 0xac); b &= ~(1<<5); write_pci_config_byte(num, slot, func, 0xac, b); d = read_pci_config(num, slot, func, 0x70); d |= 1<<8; write_pci_config(num, slot, func, 0x70, d); d = read_pci_config(num, slot, func, 0x8); d &= 0xff; return d; }
/* config_addr size value -- status */ static int rc_write_pcicfg( ulong args[], ulong ret[] ) { pci_addr_t addr; /* printm("RTAS: write_pci_config (%ld:%02lX) + 0x%02lx %08lX [%ld]\n", (args[0]>>16)&0xff, (args[0]>>8)&0xff, args[0]&0xff, args[2], args[1] ); */ if( args[1] == 2 ) args[2] = ld_le32( &args[2] ) >> 16; if( args[1] == 4 ) args[2] = ld_le32( &args[2] ); /* XXX: don't know how to handle different PCI domains... */ addr = PCIADDR_FROM_BUS_DEVFN( 0, (args[0]>>16)&0xff, (args[0]>>8)&0xff ); write_pci_config( addr, args[0]&0xff, args[2], args[1] ); ret[0] = 0; return 0; }