1/*
2 * Copyright 2017, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
8 * See "LICENSE_BSD2.txt" for details.
9 *
10 * @TAG(DATA61_BSD)
11 */
12/* Virtual PCI devices - allows rebasing base addresses.
13
14     Example usage:
15        d = libpci_find_device(0x1022, 0x2000); assert(d);
16        v = vpci->vdevice_assign(vpci); assert(v);
17        v->enable(v, d->bus, d->dev, d->fun, d);
18        v->rebase_ioaddr_realdevice(v, 0, 0x3000, d);
19 */
20#pragma once
21
22#include <stdint.h>
23#include <stdbool.h>
24#include <pci/pci.h>
25#include <pci/pci_config.h>
26
27/* Passthrough any config space writes straight onto real device.
28   Make sure vdevice->physical_device_passthrough is set. */
29#define PCI_VDEVICE_MODE_PASSTHROUGH 0
30
31/* Debug mode which asserts and while(1); when read/write is attempted. */
32#define PCI_VDEVICE_MODE_FATAL_ERROR 1
33
34/* Invoke a callback function on read/write to this config space byte. */
35#define PCI_VDEVICE_MODE_CALLBACK 2
36
37/* Only used by rebase_addr_* functions. Rebased addrs and callbacks cannot
38   be used at same time */
39#define PCI_VDEVICE_MODE_REBASED_ADDR 3
40
41struct libpci_vdevice;
42typedef struct libpci_vdevice libpci_vdevice_t;
43
44typedef struct libpci_vdevice_mode {
45    int mode; /* PCI_VDEVICE_MODE_* */
46    uint8_t (*callback_ioread) (libpci_vdevice_t* vdevice, int offset);
47    void (*callback_iowrite) (libpci_vdevice_t* vdevice, int offset, uint8_t val);
48} libpci_vdevice_mode_t;
49
50struct libpci_vdevice {
51    bool enabled;
52    bool allow_extended_pci_config_space;
53
54    uint8_t location_bus;
55    uint8_t location_dev;
56    uint8_t location_fun;
57
58    /* Per-byte device config space virtualisation mode. */
59    libpci_vdevice_mode_t mode[PCI_CONFIG_HEADER_SIZE_BYTES];
60    /* Which physical device to pass through. */
61    libpci_device_t* physical_device_passthrough;
62
63    uint32_t rebased_addr[6];
64    uint32_t rebased_writemask[6];
65    uint32_t rebased_type[6];
66
67    void (*enable) (libpci_vdevice_t* self, uint8_t bus, uint8_t dev, uint8_t fun,
68                    libpci_device_t* pdevice_passthrough /* may be NULL. */);
69
70    void (*disable) (libpci_vdevice_t* self);
71
72    bool (*match) (libpci_vdevice_t* self, uint8_t bus, uint8_t dev, uint8_t fun);
73
74    void (*set_mode) (libpci_vdevice_t* self,
75        int offset, /* 0 ... PCI_STD_HEADER_SIZEOF - 1 */
76        libpci_vdevice_mode_t m /* The mode to set it to */
77    );
78
79    /* implicitly sets physical_device_passthrough to the given device. */
80    void (*rebase_addr_realdevice) (libpci_vdevice_t* self,
81        int base_addr_index, /* 0 ... 5 */
82        uint32_t base_addr, /* correctly aligned new address. */
83        libpci_device_t* dev /* contains physical device info */
84    );
85
86    /* implicitly sets physical_device_passthrough to the given device. */
87    void (*rebase_ioaddr_realdevice) (libpci_vdevice_t* self,
88        int base_addr_index, /* 0 ... 5 */
89        uint32_t base_addr, /* correctly aligned new address. */
90        libpci_device_t* dev /* contains physical device info */
91    );
92
93    void (*rebase_addr_virtdevice) (libpci_vdevice_t* self,
94        int base_addr_index, /* 0 ... 5 */
95        uint32_t base_addr, /* correctly aligned new address. */
96        uint32_t size_mask, /* the size mask. last 3 bits must be 0. */
97        bool prefetch, /* prefetchable? */
98        bool LWord64 /* Is this address the LWORD of a 64-bit address? */
99    );
100
101    void (*rebase_ioaddr_virtdevice) (libpci_vdevice_t* self,
102        int base_addr_index, /* 0 ... 5 */
103        uint32_t base_addr, /* correctly aligned new address. */
104        uint32_t size_mask /* the size mask. last 3 bits must be 0. */
105    );
106
107    uint32_t (*ioread) (libpci_vdevice_t* self,
108                    int offset /* 0 ... PCI_STD_HEADER_SIZEOF - 1 */,
109                    int size /* 1, 2 or 4 */);
110
111    void (*iowrite) (libpci_vdevice_t* self,
112                     int offset /* 0 ... PCI_STD_HEADER_SIZEOF - 1 */,
113                     int size /* 1, 2 or 4 */,
114                     uint32_t val);
115};
116
117void libpci_vdevice_init(libpci_vdevice_t* vd);
118