1 // Copyright 2016 The Fuchsia Authors 2 // Copyright (c) 2016, Google, Inc. All rights reserved 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 9 #pragma once 10 11 #include <dev/interrupt.h> 12 #include <dev/pci_common.h> 13 #include <zircon/compiler.h> 14 #include <zircon/errors.h> 15 #include <sys/types.h> 16 17 #ifdef __cplusplus 18 19 #include <fbl/ref_counted.h> 20 21 // PciePlatformInterface 22 // 23 // The definitions of an interface responsible for managing runtime platform 24 // resource allocation. In particular, blocks of MSI interrupts. Platforms 25 // must provide an implementation of this interface to the PcieBusDriver when it 26 // gets instantiated. 27 // 28 // TODO(johngro): If/when the kernel interface to interrupt management becomes 29 // more standardized (and includes the concept of MSI IRQ blocks), this 30 // interface can be eliminated and the PCI bus driver can interact with the 31 // omnipresent interrupt management interface instead of an implementation of 32 // this interface. 33 // 34 class PciePlatformInterface { 35 public: ~PciePlatformInterface()36 virtual ~PciePlatformInterface() { } 37 38 /** 39 * Methods used to determine if a platform supports MSI or not, and if so, 40 * whether or not the platform can mask individual MSI vectors at the 41 * platform level. 42 * 43 * If the platform supports MSI, it must supply valid implementations of 44 * Alloc/FreeMsiBlock, and RegisterMsiHandler. 45 * 46 * If the platform supports MSI masking, it must supply a valid 47 * implementation of MaskUnmaskMsi. 48 */ supports_msi()49 bool supports_msi() const { return supports_msi_; } supports_msi_masking()50 bool supports_msi_masking() const { return supports_msi_masking_; } 51 52 /** 53 * Method used for platform allocation of blocks of MSI and MSI-X compatible 54 * IRQ targets. 55 * 56 * @param requested_irqs The total number of irqs being requested. 57 * @param can_target_64bit True if the target address of the MSI block can 58 * be located past the 4GB boundary. False if the target address must be 59 * in low memory. 60 * @param is_msix True if this request is for an MSI-X compatible block. False 61 * for plain old MSI. 62 * @param out_block A pointer to the allocation bookkeeping to be filled out 63 * upon successful allocation of the requested block of IRQs. 64 * 65 * @return A status code indicating the success or failure of the operation. 66 */ AllocMsiBlock(uint requested_irqs,bool can_target_64bit,bool is_msix,msi_block_t * out_block)67 virtual zx_status_t AllocMsiBlock(uint requested_irqs, 68 bool can_target_64bit, 69 bool is_msix, 70 msi_block_t* out_block) { 71 // Bus driver code should not be calling this if the platform does not 72 // indicate support for MSI. 73 DEBUG_ASSERT(false); 74 return ZX_ERR_NOT_SUPPORTED; 75 } 76 77 /** 78 * Method used by the bus driver to return a block of MSI IRQs previously 79 * allocated with a call to a AllocMsiBlock implementation to the platform 80 * pool. 81 * 82 * @param block A pointer to the block to be returned. 83 */ FreeMsiBlock(msi_block_t * block)84 virtual void FreeMsiBlock(msi_block_t* block) { 85 // Bus driver code should not be calling this if the platform does not 86 // indicate support for MSI. 87 DEBUG_ASSERT(false); 88 } 89 90 /** 91 * Method used for registration of MSI handlers with the platform. 92 * 93 * @param block A pointer to a block of MSIs allocated using a platform supplied 94 * platform_msi_alloc_block_t callback. 95 * @param msi_id The ID (indexed from 0) with the block of MSIs to register a 96 * handler for. 97 * @param handler A pointer to the handler to register, or NULL to unregister. 98 * @param ctx A context pointer to be supplied when the handler is invoked. 99 */ RegisterMsiHandler(const msi_block_t * block,uint msi_id,int_handler handler,void * ctx)100 virtual void RegisterMsiHandler(const msi_block_t* block, 101 uint msi_id, 102 int_handler handler, 103 void* ctx) { 104 // Bus driver code should not be calling this if the platform does not 105 // indicate support for MSI. 106 DEBUG_ASSERT(false); 107 } 108 109 /** 110 * Method used for masking/unmasking of MSI handlers at the platform level. 111 * 112 * @param block A pointer to a block of MSIs allocated using a platform supplied 113 * platform_msi_alloc_block_t callback. 114 * @param msi_id The ID (indexed from 0) with the block of MSIs to mask or 115 * unmask. 116 * @param mask If true, mask the handler. Otherwise, unmask it. 117 */ MaskUnmaskMsi(const msi_block_t * block,uint msi_id,bool mask)118 virtual void MaskUnmaskMsi(const msi_block_t* block, 119 uint msi_id, 120 bool mask) { 121 // Bus driver code should not be calling this if the platform does not 122 // indicate support for MSI masking. 123 DEBUG_ASSERT(false); 124 } 125 126 DISALLOW_COPY_ASSIGN_AND_MOVE(PciePlatformInterface); 127 protected: 128 enum class MsiSupportLevel { NONE, MSI, MSI_WITH_MASKING }; PciePlatformInterface(MsiSupportLevel msi_support)129 explicit PciePlatformInterface(MsiSupportLevel msi_support) 130 : supports_msi_((msi_support == MsiSupportLevel::MSI) || 131 (msi_support == MsiSupportLevel::MSI_WITH_MASKING)), 132 supports_msi_masking_(msi_support == MsiSupportLevel::MSI_WITH_MASKING) { } 133 134 private: 135 const bool supports_msi_; 136 const bool supports_msi_masking_; 137 }; 138 139 // A thin veneer version that declares no MSI 140 class NoMsiPciePlatformInterface : public PciePlatformInterface { 141 public: NoMsiPciePlatformInterface()142 NoMsiPciePlatformInterface() 143 : PciePlatformInterface(MsiSupportLevel::NONE) {} 144 145 DISALLOW_COPY_ASSIGN_AND_MOVE(NoMsiPciePlatformInterface); 146 }; 147 148 #endif // __cplusplus 149