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// 34class PciePlatformInterface { 35public: 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 */ 49 bool supports_msi() const { return supports_msi_; } 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 reqested block of IRQs. 64 * 65 * @return A status code indicating the success or failure of the operation. 66 */ 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 */ 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 */ 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/unmaskingof 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 */ 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); 127protected: 128 enum class MsiSupportLevel { NONE, MSI, MSI_WITH_MASKING }; 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 134private: 135 const bool supports_msi_; 136 const bool supports_msi_masking_; 137}; 138 139// A thin vaneer version that declares no MSI 140class NoMsiPciePlatformInterface : public PciePlatformInterface { 141public: 142 NoMsiPciePlatformInterface() 143 : PciePlatformInterface(MsiSupportLevel::NONE) {} 144 145 DISALLOW_COPY_ASSIGN_AND_MOVE(NoMsiPciePlatformInterface); 146}; 147 148#endif // __cplusplus 149