1// Copyright 2016 The Fuchsia Authors 2// Copyright (c) 2012-2015 Travis Geiselbrecht 3// 4// Use of this source code is governed by a MIT-style 5// license that can be found in the LICENSE file or at 6// https://opensource.org/licenses/MIT 7 8#if WITH_KERNEL_PCIE 9#include <dev/interrupt/arm_gicv2m_msi.h> 10#include <dev/pcie_bus_driver.h> 11#include <dev/pcie_platform.h> 12#include <dev/pcie_root.h> 13#include <fbl/alloc_checker.h> 14#include <fbl/ref_ptr.h> 15#include <inttypes.h> 16#include <lk/init.h> 17#include <pdev/driver.h> 18#include <pdev/interrupt.h> 19#include <trace.h> 20#include <zircon/boot/driver-config.h> 21#include <zircon/types.h> 22 23class ArmGicV2PciePlatformSupport : public PciePlatformInterface { 24public: 25 ArmGicV2PciePlatformSupport(bool has_msi_gic) 26 : PciePlatformInterface(has_msi_gic ? MsiSupportLevel::MSI_WITH_MASKING 27 : MsiSupportLevel::NONE) {} 28 29 zx_status_t AllocMsiBlock(uint requested_irqs, 30 bool can_target_64bit, 31 bool is_msix, 32 msi_block_t* out_block) override { 33 return arm_gicv2m_msi_alloc_block(requested_irqs, can_target_64bit, is_msix, out_block); 34 } 35 36 void FreeMsiBlock(msi_block_t* block) override { 37 arm_gicv2m_msi_free_block(block); 38 } 39 40 void RegisterMsiHandler(const msi_block_t* block, 41 uint msi_id, 42 int_handler handler, 43 void* ctx) override { 44 arm_gicv2m_msi_register_handler(block, msi_id, handler, ctx); 45 } 46 47 void MaskUnmaskMsi(const msi_block_t* block, 48 uint msi_id, 49 bool mask) override { 50 arm_gicv2m_msi_mask_unmask(block, msi_id, mask); 51 } 52}; 53 54static void arm_gicv2_pcie_init(const void* driver_data, uint32_t length) { 55 ASSERT(length >= sizeof(dcfg_arm_gicv2_driver_t)); 56 const dcfg_arm_gicv2_driver_t* driver = 57 reinterpret_cast<const dcfg_arm_gicv2_driver_t*>(driver_data); 58 59 // based on whether or not ZBI says we support MSI, initialize the v2m allocator 60 zx_status_t res; 61 bool use_msi; 62 if (driver->use_msi) { 63 dprintf(SPEW, "GICv2 MSI init\n"); 64 65 // Initialize the MSI allocator 66 res = arm_gicv2m_msi_init(); 67 if (res != ZX_OK) { 68 TRACEF("Failed to initialize MSI allocator (res = %d). PCI will be " 69 "restricted to legacy IRQ mode.\n", 70 res); 71 } 72 use_msi = (res == ZX_OK); 73 } else { 74 use_msi = false; 75 } 76 77 // Initialize the PCI platform supported based on whether or not we support MSI 78 static ArmGicV2PciePlatformSupport platform_pcie_support(use_msi); 79 80 res = PcieBusDriver::InitializeDriver(platform_pcie_support); 81 if (res != ZX_OK) { 82 TRACEF("Failed to initialize PCI bus driver (res %d). " 83 "PCI will be non-functional.\n", 84 res); 85 } 86} 87 88LK_PDEV_INIT(arm_gicv2_pcie_init, KDRV_ARM_GIC_V2, arm_gicv2_pcie_init, LK_INIT_LEVEL_PLATFORM); 89 90#endif // if WITH_KERNEL_PCIE 91