blob: 72df87132f67ffbc61dc01ed07c3a72d1e9ce50e [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors
// Copyright (c) 2016, Google, Inc. All rights reserved
//
// 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
#pragma once
#include <dev/interrupt.h>
#include <dev/pci_common.h>
#include <zircon/compiler.h>
#include <zircon/errors.h>
#include <sys/types.h>
#ifdef __cplusplus
#include <fbl/ref_counted.h>
// PciePlatformInterface
//
// The definitions of an interface responsible for managing runtime platform
// resource allocation. In particular, blocks of MSI interrupts. Platforms
// must provide an implementation of this interface to the PcieBusDriver when it
// gets instantiated.
//
// TODO(johngro): If/when the kernel interface to interrupt management becomes
// more standardized (and includes the concept of MSI IRQ blocks), this
// interface can be eliminated and the PCI bus driver can interact with the
// omnipresent interrupt management interface instead of an implementation of
// this interface.
//
class PciePlatformInterface {
public:
virtual ~PciePlatformInterface() { }
/**
* Methods used to determine if a platform supports MSI or not, and if so,
* whether or not the platform can mask individual MSI vectors at the
* platform level.
*
* If the platform supports MSI, it must supply valid implementations of
* Alloc/FreeMsiBlock, and RegisterMsiHandler.
*
* If the platform supports MSI masking, it must supply a valid
* implementation of MaskUnmaskMsi.
*/
bool supports_msi() const { return supports_msi_; }
bool supports_msi_masking() const { return supports_msi_masking_; }
/**
* Method used for platform allocation of blocks of MSI and MSI-X compatible
* IRQ targets.
*
* @param requested_irqs The total number of irqs being requested.
* @param can_target_64bit True if the target address of the MSI block can
* be located past the 4GB boundary. False if the target address must be
* in low memory.
* @param is_msix True if this request is for an MSI-X compatible block. False
* for plain old MSI.
* @param out_block A pointer to the allocation bookkeeping to be filled out
* upon successful allocation of the requested block of IRQs.
*
* @return A status code indicating the success or failure of the operation.
*/
virtual zx_status_t AllocMsiBlock(uint requested_irqs,
bool can_target_64bit,
bool is_msix,
msi_block_t* out_block) {
// Bus driver code should not be calling this if the platform does not
// indicate support for MSI.
DEBUG_ASSERT(false);
return ZX_ERR_NOT_SUPPORTED;
}
/**
* Method used by the bus driver to return a block of MSI IRQs previously
* allocated with a call to a AllocMsiBlock implementation to the platform
* pool.
*
* @param block A pointer to the block to be returned.
*/
virtual void FreeMsiBlock(msi_block_t* block) {
// Bus driver code should not be calling this if the platform does not
// indicate support for MSI.
DEBUG_ASSERT(false);
}
/**
* Method used for registration of MSI handlers with the platform.
*
* @param block A pointer to a block of MSIs allocated using a platform supplied
* platform_msi_alloc_block_t callback.
* @param msi_id The ID (indexed from 0) with the block of MSIs to register a
* handler for.
* @param handler A pointer to the handler to register, or NULL to unregister.
* @param ctx A context pointer to be supplied when the handler is invoked.
*/
virtual void RegisterMsiHandler(const msi_block_t* block,
uint msi_id,
int_handler handler,
void* ctx) {
// Bus driver code should not be calling this if the platform does not
// indicate support for MSI.
DEBUG_ASSERT(false);
}
/**
* Method used for masking/unmasking of MSI handlers at the platform level.
*
* @param block A pointer to a block of MSIs allocated using a platform supplied
* platform_msi_alloc_block_t callback.
* @param msi_id The ID (indexed from 0) with the block of MSIs to mask or
* unmask.
* @param mask If true, mask the handler. Otherwise, unmask it.
*/
virtual void MaskUnmaskMsi(const msi_block_t* block,
uint msi_id,
bool mask) {
// Bus driver code should not be calling this if the platform does not
// indicate support for MSI masking.
DEBUG_ASSERT(false);
}
DISALLOW_COPY_ASSIGN_AND_MOVE(PciePlatformInterface);
protected:
enum class MsiSupportLevel { NONE, MSI, MSI_WITH_MASKING };
explicit PciePlatformInterface(MsiSupportLevel msi_support)
: supports_msi_((msi_support == MsiSupportLevel::MSI) ||
(msi_support == MsiSupportLevel::MSI_WITH_MASKING)),
supports_msi_masking_(msi_support == MsiSupportLevel::MSI_WITH_MASKING) { }
private:
const bool supports_msi_;
const bool supports_msi_masking_;
};
// A thin veneer version that declares no MSI
class NoMsiPciePlatformInterface : public PciePlatformInterface {
public:
NoMsiPciePlatformInterface()
: PciePlatformInterface(MsiSupportLevel::NONE) {}
DISALLOW_COPY_ASSIGN_AND_MOVE(NoMsiPciePlatformInterface);
};
#endif // __cplusplus