blob: f2be9afd8d4372f317016cc381bcf495f76a015b [file] [log] [blame]
/*
* Copyright 2017, Data61, CSIRO (ABN 41 687 119 230)
*
* SPDX-License-Identifier: BSD-2-Clause
*/
/* Virtual PCI devices - allows rebasing base addresses.
Example usage:
d = libpci_find_device(0x1022, 0x2000); assert(d);
v = vpci->vdevice_assign(vpci); assert(v);
v->enable(v, d->bus, d->dev, d->fun, d);
v->rebase_ioaddr_realdevice(v, 0, 0x3000, d);
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <pci/pci.h>
#include <pci/pci_config.h>
/* Passthrough any config space writes straight onto real device.
Make sure vdevice->physical_device_passthrough is set. */
#define PCI_VDEVICE_MODE_PASSTHROUGH 0
/* Debug mode which asserts and while(1); when read/write is attempted. */
#define PCI_VDEVICE_MODE_FATAL_ERROR 1
/* Invoke a callback function on read/write to this config space byte. */
#define PCI_VDEVICE_MODE_CALLBACK 2
/* Only used by rebase_addr_* functions. Rebased addrs and callbacks cannot
be used at same time */
#define PCI_VDEVICE_MODE_REBASED_ADDR 3
struct libpci_vdevice;
typedef struct libpci_vdevice libpci_vdevice_t;
typedef struct libpci_vdevice_mode {
int mode; /* PCI_VDEVICE_MODE_* */
uint8_t (*callback_ioread) (libpci_vdevice_t* vdevice, int offset);
void (*callback_iowrite) (libpci_vdevice_t* vdevice, int offset, uint8_t val);
} libpci_vdevice_mode_t;
struct libpci_vdevice {
bool enabled;
bool allow_extended_pci_config_space;
uint8_t location_bus;
uint8_t location_dev;
uint8_t location_fun;
/* Per-byte device config space virtualisation mode. */
libpci_vdevice_mode_t mode[PCI_CONFIG_HEADER_SIZE_BYTES];
/* Which physical device to pass through. */
libpci_device_t* physical_device_passthrough;
uint32_t rebased_addr[6];
uint32_t rebased_writemask[6];
uint32_t rebased_type[6];
void (*enable) (libpci_vdevice_t* self, uint8_t bus, uint8_t dev, uint8_t fun,
libpci_device_t* pdevice_passthrough /* may be NULL. */);
void (*disable) (libpci_vdevice_t* self);
bool (*match) (libpci_vdevice_t* self, uint8_t bus, uint8_t dev, uint8_t fun);
void (*set_mode) (libpci_vdevice_t* self,
int offset, /* 0 ... PCI_STD_HEADER_SIZEOF - 1 */
libpci_vdevice_mode_t m /* The mode to set it to */
);
/* implicitly sets physical_device_passthrough to the given device. */
void (*rebase_addr_realdevice) (libpci_vdevice_t* self,
int base_addr_index, /* 0 ... 5 */
uint32_t base_addr, /* correctly aligned new address. */
libpci_device_t* dev /* contains physical device info */
);
/* implicitly sets physical_device_passthrough to the given device. */
void (*rebase_ioaddr_realdevice) (libpci_vdevice_t* self,
int base_addr_index, /* 0 ... 5 */
uint32_t base_addr, /* correctly aligned new address. */
libpci_device_t* dev /* contains physical device info */
);
void (*rebase_addr_virtdevice) (libpci_vdevice_t* self,
int base_addr_index, /* 0 ... 5 */
uint32_t base_addr, /* correctly aligned new address. */
uint32_t size_mask, /* the size mask. last 3 bits must be 0. */
bool prefetch, /* prefetchable? */
bool LWord64 /* Is this address the LWORD of a 64-bit address? */
);
void (*rebase_ioaddr_virtdevice) (libpci_vdevice_t* self,
int base_addr_index, /* 0 ... 5 */
uint32_t base_addr, /* correctly aligned new address. */
uint32_t size_mask /* the size mask. last 3 bits must be 0. */
);
uint32_t (*ioread) (libpci_vdevice_t* self,
int offset /* 0 ... PCI_STD_HEADER_SIZEOF - 1 */,
int size /* 1, 2 or 4 */);
void (*iowrite) (libpci_vdevice_t* self,
int offset /* 0 ... PCI_STD_HEADER_SIZEOF - 1 */,
int size /* 1, 2 or 4 */,
uint32_t val);
};
void libpci_vdevice_init(libpci_vdevice_t* vd);