// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#pragma once

#include <assert.h>
#include <zircon/compiler.h>
#include <stdbool.h>
#include <stdint.h>

__BEGIN_CDECLS

#define ZX_IOMMU_MAX_DESC_LEN 4096

// Values for the |type| argument of the zx_iommu_create() syscall.
#define ZX_IOMMU_TYPE_DUMMY 0
#define ZX_IOMMU_TYPE_INTEL 1

// Data structures for creating a dummy IOMMU instance
typedef struct zx_iommu_desc_dummy {
    uint8_t reserved;
} zx_iommu_desc_dummy_t;


// Data structures for creating an Intel IOMMU instance

// This scope represents a single PCI endpoint device
#define ZX_IOMMU_INTEL_SCOPE_ENDPOINT 0
// This scope represents a PCI-PCI bridge.  The bridge and all of its downstream
// devices will be included in this scope.
#define ZX_IOMMU_INTEL_SCOPE_BRIDGE   1

// TODO(teisenbe): Investigate FIDL for this.  Multiple embedded lists seems
// right up its alley.
typedef struct zx_iommu_desc_intel_scope {
    uint8_t type;
    // The bus number of the first bus decoded by the host bridge this scope is attached to.
    uint8_t start_bus;
    // Number of bridges (including the host bridge) between host bridge and the
    // device.
    uint8_t num_hops;
    // The device number and function numbers of the bridges along the way,
    // ending with the device itself.
    // |dev_func[0]| is the address on |start_bus| of the first bridge in the
    // path (excluding the host bridge).  |dev_func[num_hops-1]| is the address
    // of the the device itself.
    uint8_t dev_func[5];
} zx_iommu_desc_intel_scope_t;

typedef struct zx_iommu_desc_intel_reserved_memory {
    uint64_t base_addr; // Physical address of the base of reserved memory.
    uint64_t len; // Number of bytes of reserved memory.

    // The number of bytes of zx_iommu_desc_intel_scope_t's that follow this descriptor.
    uint8_t scope_bytes;

    uint8_t _reserved[7]; // Padding

    // This is a list of all devices that need access to this memory range.
    //
    // zx_iommu_desc_intel_scope_t scopes[num_scopes];
} zx_iommu_desc_intel_reserved_memory_t;

typedef struct zx_iommu_desc_intel {
    uint64_t register_base; // Physical address of registers
    uint16_t pci_segment; // The PCI segment associated with this IOMMU

    // If true, this IOMMU has all PCI devices in its segment under its scope.
    // In this case, the list of scopes acts as a blacklist.
    bool whole_segment;

    // The number of bytes of zx_iommu_desc_intel_scope_t's that follow this descriptor.
    uint8_t scope_bytes;

    // The number of bytes of zx_iommu_desc_intel_reserved_memory_t's that follow the scope
    // list.
    uint16_t reserved_memory_bytes;

    uint8_t _reserved[2]; // Padding

    // If |whole_segment| is false, this is a list of all devices managed by
    // this IOMMU.  If |whole_segment| is true, this is a list of all devices on
    // this segment *not* managed by this IOMMU.  It has a total length in bytes of
    // |scope_bytes|.
    //
    // zx_iommu_desc_intel_scope_t scopes[];

    // A list of all BIOS-reserved memory regions this IOMMU needs to translate.
    // It has a total length in bytes of |reserved_memory_bytes|.
    //
    // zx_iommu_desc_intel_reserved_memory_t reserved_mem[];
} zx_iommu_desc_intel_t;

__END_CDECLS