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