Comparar commits
3 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| d0f3f288dd | |||
| a6695f3bfc | |||
| 90da32b181 |
@@ -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_;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 },
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário