blob: 786ad393998e86cc8082547d628702dd134656f5 [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors
// Copyright (c) 2012-2015 Travis Geiselbrecht
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#if WITH_KERNEL_PCIE
#include <dev/interrupt/arm_gicv2m_msi.h>
#include <dev/pcie_bus_driver.h>
#include <dev/pcie_platform.h>
#include <dev/pcie_root.h>
#include <fbl/alloc_checker.h>
#include <fbl/ref_ptr.h>
#include <inttypes.h>
#include <lk/init.h>
#include <pdev/driver.h>
#include <pdev/interrupt.h>
#include <trace.h>
#include <zircon/boot/driver-config.h>
#include <zircon/types.h>
class ArmGicV2PciePlatformSupport : public PciePlatformInterface {
public:
ArmGicV2PciePlatformSupport(bool has_msi_gic)
: PciePlatformInterface(has_msi_gic ? MsiSupportLevel::MSI_WITH_MASKING
: MsiSupportLevel::NONE) {}
zx_status_t AllocMsiBlock(uint requested_irqs,
bool can_target_64bit,
bool is_msix,
msi_block_t* out_block) override {
return arm_gicv2m_msi_alloc_block(requested_irqs, can_target_64bit, is_msix, out_block);
}
void FreeMsiBlock(msi_block_t* block) override {
arm_gicv2m_msi_free_block(block);
}
void RegisterMsiHandler(const msi_block_t* block,
uint msi_id,
int_handler handler,
void* ctx) override {
arm_gicv2m_msi_register_handler(block, msi_id, handler, ctx);
}
void MaskUnmaskMsi(const msi_block_t* block,
uint msi_id,
bool mask) override {
arm_gicv2m_msi_mask_unmask(block, msi_id, mask);
}
};
static void arm_gicv2_pcie_init(const void* driver_data, uint32_t length) {
ASSERT(length >= sizeof(dcfg_arm_gicv2_driver_t));
const dcfg_arm_gicv2_driver_t* driver =
reinterpret_cast<const dcfg_arm_gicv2_driver_t*>(driver_data);
// based on whether or not ZBI says we support MSI, initialize the v2m allocator
zx_status_t res;
bool use_msi;
if (driver->use_msi) {
dprintf(SPEW, "GICv2 MSI init\n");
// Initialize the MSI allocator
res = arm_gicv2m_msi_init();
if (res != ZX_OK) {
TRACEF("Failed to initialize MSI allocator (res = %d). PCI will be "
"restricted to legacy IRQ mode.\n",
res);
}
use_msi = (res == ZX_OK);
} else {
use_msi = false;
}
// Initialize the PCI platform supported based on whether or not we support MSI
static ArmGicV2PciePlatformSupport platform_pcie_support(use_msi);
res = PcieBusDriver::InitializeDriver(platform_pcie_support);
if (res != ZX_OK) {
TRACEF("Failed to initialize PCI bus driver (res %d). "
"PCI will be non-functional.\n",
res);
}
}
LK_PDEV_INIT(arm_gicv2_pcie_init, KDRV_ARM_GIC_V2, arm_gicv2_pcie_init, LK_INIT_LEVEL_PLATFORM);
#endif // if WITH_KERNEL_PCIE