blob: 951e6816e2a637df254893296010d199c62a1dbd [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors
//
// 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
#ifndef ZIRCON_KERNEL_OBJECT_INCLUDE_OBJECT_INTERRUPT_DISPATCHER_H_
#define ZIRCON_KERNEL_OBJECT_INCLUDE_OBJECT_INTERRUPT_DISPATCHER_H_
#include <sys/types.h>
#include <zircon/rights.h>
#include <zircon/types.h>
#include <kernel/event.h>
#include <kernel/spinlock.h>
#include <object/dispatcher.h>
#include <object/port_dispatcher.h>
#include <object/vcpu_dispatcher.h>
enum class InterruptState {
WAITING = 0,
DESTROYED = 1,
TRIGGERED = 2,
NEEDACK = 3,
IDLE = 4,
};
// Note that unlike most Dispatcher subclasses, this one is further
// subclassed, and so cannot be final.
class InterruptDispatcher
: public SoloDispatcher<InterruptDispatcher, ZX_DEFAULT_INTERRUPT_RIGHTS> {
public:
InterruptDispatcher& operator=(const InterruptDispatcher&) = delete;
zx_obj_type_t get_type() const final { return ZX_OBJ_TYPE_INTERRUPT; }
uint32_t get_flags() const { return flags_; }
zx_status_t WaitForInterrupt(zx_time_t* out_timestamp);
zx_status_t Trigger(zx_time_t timestamp);
zx_status_t Ack();
zx_status_t Destroy();
void InterruptHandler();
zx_status_t Bind(fbl::RefPtr<PortDispatcher> port_dispatcher, uint64_t key);
zx_status_t Unbind(fbl::RefPtr<PortDispatcher> port_dispatcher);
virtual zx_status_t BindVcpu(fbl::RefPtr<VcpuDispatcher> vcpu_dispatcher) {
return ZX_ERR_NOT_SUPPORTED;
}
void on_zero_handles() final;
protected:
virtual void MaskInterrupt() = 0;
virtual void UnmaskInterrupt() = 0;
virtual void DeactivateInterrupt() = 0;
virtual void UnregisterInterruptHandler() = 0;
virtual bool HasVcpu() const TA_REQ(spinlock_) { return false; }
InterruptDispatcher();
void Signal() { event_.Signal(); }
zx_status_t set_flags(uint32_t flags);
bool SendPacketLocked(zx_time_t timestamp) TA_REQ(spinlock_);
bool HasPort() const TA_REQ(spinlock_) { return !!port_dispatcher_; }
InterruptState state() const TA_REQ(spinlock_) { return state_; }
// Bits for Interrupt.flags
// The interrupt is virtual.
static constexpr uint32_t INTERRUPT_VIRTUAL = (1u << 0);
// The interrupt should be unmasked before waiting on the event.
static constexpr uint32_t INTERRUPT_UNMASK_PREWAIT = (1u << 1);
// The same as |INTERRUPT_UNMASK_PREWAIT| except release the dispatcher
// spinlock before waiting.
static constexpr uint32_t INTERRUPT_UNMASK_PREWAIT_UNLOCKED = (1u << 2);
// The interrupt should be masked following waiting.
static constexpr uint32_t INTERRUPT_MASK_POSTWAIT = (1u << 4);
// Controls the access to Interrupt properties
DECLARE_SPINLOCK(InterruptDispatcher) spinlock_;
private:
AutounsignalEvent event_;
// Interrupt Flags
uint32_t flags_;
zx_time_t timestamp_ TA_GUARDED(spinlock_);
// Current state of the interrupt object
InterruptState state_ TA_GUARDED(spinlock_);
PortInterruptPacket port_packet_ TA_GUARDED(spinlock_) = {};
fbl::RefPtr<PortDispatcher> port_dispatcher_ TA_GUARDED(spinlock_);
};
#endif // ZIRCON_KERNEL_OBJECT_INCLUDE_OBJECT_INTERRUPT_DISPATCHER_H_