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 
23 class ArmGicV2PciePlatformSupport : public PciePlatformInterface {
24 public:
ArmGicV2PciePlatformSupport(bool has_msi_gic)25     ArmGicV2PciePlatformSupport(bool has_msi_gic)
26         : PciePlatformInterface(has_msi_gic ? MsiSupportLevel::MSI_WITH_MASKING
27                                             : MsiSupportLevel::NONE) {}
28 
AllocMsiBlock(uint requested_irqs,bool can_target_64bit,bool is_msix,msi_block_t * out_block)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 
FreeMsiBlock(msi_block_t * block)36     void FreeMsiBlock(msi_block_t* block) override {
37         arm_gicv2m_msi_free_block(block);
38     }
39 
RegisterMsiHandler(const msi_block_t * block,uint msi_id,int_handler handler,void * ctx)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 
MaskUnmaskMsi(const msi_block_t * block,uint msi_id,bool mask)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 
arm_gicv2_pcie_init(const void * driver_data,uint32_t length)54 static 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 
88 LK_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