Comparar commits

...

3 Commits

Autor SHA1 Mensagem Data
Christopher Anderson d0f3f288dd [pci] Add PIIX4 host controller to tolud table
Change-Id: Ic610eee5472ca8d876d2efb9458bb55593403774
2017-08-07 11:15:57 -07:00
Christopher Anderson a6695f3bfc [pci] Wire up PIO bus enumeration
Change-Id: Ic387923e35724a85603e5f24b38d4559356220cf
2017-08-07 11:15:57 -07:00
Christopher Anderson 90da32b181 [pci] Add a way to switch a PCI bus to PIO mode
In our current setup, Bus drivers are created before we know anything
about their roots, and roots reach back into the bus drivers to obtain
device configs while scanning downstream. Since the actual scan work
is done by the bus driver, but the information about the address space
of the tree is in the root, this method is being added. This should be
considered a hideous temporary hack that will go away as we move PCI to
userspace, but is needed in the short term to boostrap legacy PCI
enumeration for virtualized environments that use PIO based config space.

Change-Id: I6ce2c311ecb9c09361aeac8079b00e9354ff5f7a
2017-08-07 11:15:57 -07:00
7 arquivos alterados com 78 adições e 35 exclusões
@@ -99,6 +99,28 @@ public:
// Add a root bus to the driver and attempt to scan it for devices.
status_t AddRoot(mxtl::RefPtr<PcieRoot>&& root);
// Set a bus driver's memory address space to MMIO or IO.
//
// TODO(cja): This is a workaround to get around a problem with the current
// system of initializing PCI. Presently, while PCI is in the kernel,
// we create the PcieBusDriver singleton in a platform specific early
// init hook linked via LK_INIT_HOOK, then after ACPI runs we add roots
// and start the bus driver. It would make more sense to apply the memory
// space to the root, however during downstream scanning we rely on the
// bus driver's ability to call its own GetConfig(). For this reason, since
// we're only surfacing a single root right now anyway we need to mark that
// root as MMIO or PIO in the bus driver itself. When we move to userspace
// and have a bus driver instance for each root, this will no longer be an
// issue.
bool EnablePIOWorkaround(bool enable) {
AutoLock lock(&driver_lock_);
if (roots_.is_empty()) {
is_mmio_ = !enable;
}
return is_mmio_;
}
// Start the driver
//
// Notes about startup:
@@ -224,6 +246,7 @@ private:
RootCollection roots_;
mxtl::SinglyLinkedList<mxtl::RefPtr<PciConfig>> configs_;
bool is_mmio_ = true;
RegionAllocator::RegionPool::RefPtr region_bookkeeping_;
RegionAllocator mmio_lo_regions_;
RegionAllocator mmio_hi_regions_;
+5 -5
Ver Arquivo
@@ -158,18 +158,18 @@ void PciMmioConfig::Write(PciReg32 addr, uint32_t val) const {
mxtl::RefPtr<PciConfig> PciConfig::Create(uintptr_t base, PciAddrSpace addr_type) {
mxtl::AllocChecker ac;
mxtl::RefPtr<PciConfig> cfg;
mxtl::RefPtr<PciConfig> cfg = nullptr;
LTRACEF("base %#" PRIxPTR ", type %s\n", base, (addr_type == PciAddrSpace::PIO) ? "PIO" : "MIO");
if (addr_type == PciAddrSpace::PIO)
PANIC_UNIMPLEMENTED;
else
if (addr_type == PciAddrSpace::PIO) {
cfg = mxtl::AdoptRef(new (&ac) PciPioConfig(base));
} else {
cfg = mxtl::AdoptRef(new (&ac) PciMmioConfig(base));
}
if (!ac.check()) {
TRACEF("failed to allocate memory for PciConfig!\n");
return nullptr;
}
return cfg;
+34 -25
Ver Arquivo
@@ -12,6 +12,7 @@
#include <inttypes.h>
#include <kernel/auto_lock.h>
#include <kernel/vm/vm_aspace.h>
#include <lib/pci/pio.h>
#include <lk/init.h>
#include <mxtl/alloc_checker.h>
#include <mxtl/limits.h>
@@ -490,35 +491,44 @@ const PciConfig* PcieBusDriver::GetConfig(uint bus_id,
DEBUG_ASSERT(dev_id < PCIE_MAX_DEVICES_PER_BUS);
DEBUG_ASSERT(func_id < PCIE_MAX_FUNCTIONS_PER_DEVICE);
// Find the region which would contain this bus_id, if any.
// add does not overlap with any already defined regions.
AutoLock ecam_region_lock(&ecam_region_lock_);
auto iter = ecam_regions_.upper_bound(static_cast<uint8_t>(bus_id));
--iter;
uintptr_t addr;
if (is_mmio_) {
// Find the region which would contain this bus_id, if any.
// add does not overlap with any already defined regions.
AutoLock ecam_region_lock(&ecam_region_lock_);
auto iter = ecam_regions_.upper_bound(static_cast<uint8_t>(bus_id));
--iter;
if (out_cfg_phys)
*out_cfg_phys = 0;
if (out_cfg_phys) {
*out_cfg_phys = 0;
}
if (!iter.IsValid())
return nullptr;
if (!iter.IsValid()) {
return nullptr;
}
if ((bus_id < iter->ecam().bus_start) ||
(bus_id > iter->ecam().bus_end))
return nullptr;
if ((bus_id < iter->ecam().bus_start) ||
(bus_id > iter->ecam().bus_end)) {
return nullptr;
}
bus_id -= iter->ecam().bus_start;
size_t offset = (static_cast<size_t>(bus_id) << 20) |
(static_cast<size_t>(dev_id) << 15) |
(static_cast<size_t>(func_id) << 12);
bus_id -= iter->ecam().bus_start;
size_t offset = (static_cast<size_t>(bus_id) << 20) |
(static_cast<size_t>(dev_id) << 15) |
(static_cast<size_t>(func_id) << 12);
// TODO(cja) The remainder of this method will need to be refactored
// with PIO space in mind in a later commit.
if (out_cfg_phys)
*out_cfg_phys = iter->ecam().phys_base + offset;
if (out_cfg_phys) {
*out_cfg_phys = iter->ecam().phys_base + offset;
}
// TODO(cja): Move to a BDF based associative container for better lookup time
// and insert or find behavior.
addr = reinterpret_cast<uintptr_t>(static_cast<uint8_t*>(iter->vaddr()) + offset);
} else {
addr = Pci::PciBdfAddr(static_cast<uint8_t>(bus_id), static_cast<uint8_t>(dev_id),
static_cast<uint8_t>(func_id), 0);
}
// TODO(cja): Move to a BDF based associative container for better lookup time
// and insert or find behavior.
uintptr_t addr = reinterpret_cast<uintptr_t>(static_cast<uint8_t*>(iter->vaddr()) + offset);
auto cfg_iter = configs_.find_if([addr](const PciConfig& cfg) {
return (cfg.base() == addr);
});
@@ -527,9 +537,8 @@ const PciConfig* PcieBusDriver::GetConfig(uint bus_id,
return &(*cfg_iter);
}
// TODO(cja): PIO support here
// Nothing found, create a new PciConfig for this address
auto cfg = PciConfig::Create(addr, PciAddrSpace::MMIO);
auto cfg = PciConfig::Create(addr, (is_mmio_) ? PciAddrSpace::MMIO : PciAddrSpace::PIO);
configs_.push_front(cfg);
return cfg.get();
}
+5
Ver Arquivo
@@ -74,6 +74,11 @@ void PcieUpstreamNode::ScanDownstream() {
/* If we can find the config, and it has a valid vendor ID, go ahead
* and scan it looking for a valid function. */
auto cfg = driver().GetConfig(managed_bus_id_, dev_id, func_id);
if (cfg == nullptr) {
TRACEF("Warning: bus being scanned is outside ecam region!\n");
return;
}
uint16_t vendor_id = cfg->Read(PciConfig::kVendorId);
bool good_device = cfg && (vendor_id != PCIE_INVALID_VENDOR_ID);
if (good_device) {
+3
Ver Arquivo
@@ -263,6 +263,9 @@ mx_status_t sys_pci_init(mx_handle_t handle, user_ptr<const mx_pci_init_arg_t> _
if (root == nullptr)
return MX_ERR_NO_MEMORY;
// Enable PIO config space if the address window was not MMIO
pcie->EnablePIOWorkaround(!arg->addr_windows[0].is_mmio);
mx_status_t ret = pcie->AddRoot(mxtl::move(root));
if (ret != MX_OK) {
TRACEF("Failed to add root complex to PCIe bus driver! (ret %d)\n", ret);
+2 -1
Ver Arquivo
@@ -45,7 +45,8 @@ static void pcie_tolud_quirk(const mxtl::RefPtr<PcieDevice>& dev) {
} TOLUD_CHIPSET_LUT[] = {
// QEMU's emulation of Intel Q35. No TOLUD register that I know of.
{ .match = 0x808629c0, .mask = 0xFFFFFFFF, .offset = 0x0 },
// PIIX4
{ .match = 0x80861237, .mask = 0xFFFFFFFF, .offset = 0x0 },
// Intel 6th Generation Core Family (Skylake)
{ .match = 0x80861900, .mask = 0xFFFFFF00, .offset = 0xBC },
+6 -4
Ver Arquivo
@@ -19,6 +19,8 @@
#define PCIE_MAX_FUNCTIONS_PER_DEVICE 8
#define PCI_CONFIG_SIZE 256
#define PCIE_EXTENDED_CONFIG_SIZE 4096
#define PCI_HID ((char*)"PNP0A03")
#define PCIE_HID ((char*)"PNP0A08")
#define PANIC_UNIMPLEMENTED __builtin_trap()
@@ -293,7 +295,7 @@ static ACPI_STATUS get_pcie_devices_irq(
*
* @return MX_OK on success
*/
static mx_status_t find_pcie_legacy_irq_mapping(mx_pci_init_arg_t* arg) {
static mx_status_t find_pci_legacy_irq_mapping(mx_pci_init_arg_t* arg) {
unsigned int map_len = sizeof(arg->dev_pin_to_global_irq) / sizeof(uint32_t);
for (unsigned int i = 0; i < map_len; ++i) {
uint32_t* flat_map = (uint32_t*)&arg->dev_pin_to_global_irq;
@@ -302,7 +304,7 @@ static mx_status_t find_pcie_legacy_irq_mapping(mx_pci_init_arg_t* arg) {
arg->num_irqs = 0;
ACPI_STATUS status = AcpiGetDevices(
(char*)"PNP0A08", // PCIe root hub
(arg->addr_windows[0].has_ecam) ? PCIE_HID : PCI_HID,
get_pcie_devices_irq,
arg,
NULL);
@@ -348,7 +350,7 @@ static ACPI_STATUS find_pci_configs_cb(
static mx_status_t find_pci_config(mx_pci_init_arg_t* arg) {
// TODO: Although this will find every PCI legacy root, we're presently
// hardcoding to just use the first at bus 0 dev 0 func 0 segment 0.
return AcpiGetDevices((char*)"PNP0A03", find_pci_configs_cb, arg, NULL);
return AcpiGetDevices(PCI_HID, find_pci_configs_cb, arg, NULL);
}
/* @brief Compute PCIe initialization information
@@ -380,7 +382,7 @@ mx_status_t get_pci_init_arg(mx_pci_init_arg_t** arg, uint32_t* size) {
}
}
status = find_pcie_legacy_irq_mapping(res);
status = find_pci_legacy_irq_mapping(res);
if (status != MX_OK) {
goto fail;
}