blob: 608872019df518fd9315b7848d309f8ba3ba1924 [file] [log] [blame] [edit]
/* Copyright (c) 2009, 2010 The Regents of the University of California
* See LICENSE for details.
*
* Barret Rhoden <brho@cs.berkeley.edu>
* Original by Paul Pearce <pearce@eecs.berkeley.edu> */
#ifndef ROS_ARCH_PCI_H
#define ROS_ARCH_PCI_H
#include <ros/common.h>
#include <sys/queue.h>
#include <atomic.h>
#define pci_debug(...) printk(__VA_ARGS__)
#define PCI_CONFIG_ADDR 0xCF8
#define PCI_CONFIG_DATA 0xCFC
#define INVALID_VENDOR_ID 0xFFFF
/* TODO: gut this (when the IOAPIC is fixed) */
#define INVALID_BUS 0xFFFF
#define PCI_NOINT 0x00
#define PCI_INTA 0x01
#define PCI_INTB 0x02
#define PCI_INTC 0x03
#define PCI_INTD 0x04
/* PCI Register Config Space */
#define PCI_DEV_VEND_REG 0x00 /* for the 32 bit read of dev/vend */
#define PCI_VENDID_REG 0x00
#define PCI_DEVID_REG 0x02
#define PCI_CMD_REG 0x04
#define PCI_STATUS_REG 0x06
#define PCI_REVID_REG 0x08
#define PCI_PROGIF_REG 0x09
#define PCI_SUBCLASS_REG 0x0a
#define PCI_CLASS_REG 0x0b
#define PCI_CLSZ_REG 0x0c
#define PCI_LATTIM_REG 0x0d
#define PCI_HEADER_REG 0x0e
#define PCI_BIST_REG 0x0f
/* Config space for header type 0x00 (Standard) */
#define PCI_BAR0_STD 0x10
#define PCI_BAR1_STD 0x14
#define PCI_BAR2_STD 0x18
#define PCI_BAR3_STD 0x1c
#define PCI_BAR4_STD 0x20
#define PCI_BAR5_STD 0x24
#define PCI_BAR_OFF 0x04
#define PCI_CARDBUS_STD 0x28
#define PCI_SUBSYSVEN_STD 0x2c
#define PCI_SUBSYSID_STD 0x2e
#define PCI_EXPROM_STD 0x30
#define PCI_CAPAB_STD 0x34
#define PCI_IRQLINE_STD 0x3c
#define PCI_IRQPIN_STD 0x3d
#define PCI_MINGRNT_STD 0x3e
#define PCI_MAXLAT_STD 0x3f
/* Config space for header type 0x01 (PCI-PCI bridge) */
/* None of these have been used, so if you use them, check them against
* http://wiki.osdev.org/PCI#PCI_Device_Structure */
#define PCI_BAR0_BR 0x10
#define PCI_BAR1_BR 0x14
#define PCI_BUS1_BR 0x18
#define PCI_BUS2_BR 0x19
#define PCI_SUBBUS_BR 0x1a
#define PCI_LATTIM2_BR 0x1b
#define PCI_IOBASE_BR 0x1c
#define PCI_IOLIM_BR 0x1d
#define PCI_STATUS2_BR 0x1e
#define PCI_MEMBASE_BR 0x20
#define PCI_MEMLIM_BR 0x22
#define PCI_PREMEMBASE_BR 0x24
#define PCI_PREMEMLIM_BR 0x26
#define PCI_PREBASEUP32_BR 0x28
#define PCI_PRELIMUP32_BR 0x2c
#define PCI_IOBASEUP16_BR 0x30
#define PCI_IOLIMUP16_BR 0x32
#define PCI_CAPAB_BR 0x34
#define PCI_EXPROM_BR 0x38
#define PCI_IRQLINE_BR 0x3c
#define PCI_IRQPIN_BR 0x3d
#define PCI_BDGCTL_BR 0x3e
/* Config space for header type 0x02 (PCI-Cardbus bridge) */
/* None of these have been used, so if you use them, check them against
* http://wiki.osdev.org/PCI#PCI_Device_Structure */
#define PCI_SOC_BASE_CB 0x10
#define PCI_OFF_CAP_CB 0x14
#define PCI_SEC_STAT_CB 0x16
#define PCI_BUS_NR_CB 0x18
#define PCI_CARDBUS_NR_CB 0x19
#define PCI_SUBBUS_NR_CB 0x1a
#define PCI_CARD_LAT_CB 0x1b
#define PCI_MEM_BASE0_CB 0x1c
#define PCI_MEM_LIMIT0_CB 0x20
#define PCI_MEM_BASE1_CB 0x24
#define PCI_MEM_LIMIT1_CB 0x28
#define PCI_IO_BASE0_CB 0x2c
#define PCI_IO_LIMIT0_CB 0x30
#define PCI_IO_BASE1_CB 0x34
#define PCI_IO_LIMIT1_CB 0x38
#define PCI_IRQLINE_CB 0x3c
#define PCI_IRQPIN_CB 0x3d
#define PCI_BDGCTL_CB 0x3e
#define PCI_SUBDEVID_CB 0x40
#define PCI_SUBVENID_CB 0x42
#define PCI_16BIT_CB 0x44
/* Command Register Flags */
#define PCI_CMD_IO_SPC (1 << 0)
#define PCI_CMD_MEM_SPC (1 << 1)
#define PCI_CMD_BUS_MAS (1 << 2)
#define PCI_CMD_SPC_CYC (1 << 3)
#define PCI_CMD_WR_EN (1 << 4)
#define PCI_CMD_VGA (1 << 5)
#define PCI_CMD_PAR_ERR (1 << 6)
/* #define PCI_CMD_XXX (1 << 7) Reserved */
#define PCI_CMD_SERR (1 << 8)
#define PCI_CMD_FAST_EN (1 << 9)
#define PCI_CMD_IRQ_DIS (1 << 10)
/* Status Register Flags (Bits 9 and 10 are one field) */
/* Bits 0, 1, and 2 are reserved */
#define PCI_ST_IRQ_STAT (1 << 3)
#define PCI_ST_CAP_LIST (1 << 4)
#define PCI_ST_66MHZ (1 << 5)
/* #define PCI_CMD_XXX (1 << 6) Reserved */
#define PCI_ST_FAST_CAP (1 << 7)
#define PCI_ST_MASPAR_ERR (1 << 8)
#define PCI_ST_DEVSEL_TIM (3 << 9) /* 2 bits */
#define PCI_ST_SIG_TAR_ABRT (1 << 11)
#define PCI_ST_REC_TAR_ABRT (1 << 12)
#define PCI_ST_REC_MAS_ABRT (1 << 13)
#define PCI_ST_SIG_SYS_ERR (1 << 14)
#define PCI_ST_PAR_ERR (1 << 15)
/* BARS: Base Address Registers */
#define PCI_BAR_IO 0x1 /* 1 == IO, 0 == Mem */
#define PCI_BAR_IO_MASK 0xfffffffc
#define PCI_BAR_MEM_MASK 0xfffffff0
#define PCI_MEMBAR_TYPE (3 << 1)
#define PCI_MEMBAR_32BIT 0x0
#define PCI_MEMBAR_RESV 0x2 /* type 0x1 shifted to MEMBAR_TYPE */
#define PCI_MEMBAR_64BIT 0x4 /* type 0x2 shifted to MEMBAR_TYPE */
#define PCI_MAX_BUS 256
#define PCI_MAX_DEV 32
#define PCI_MAX_FUNC 8
// Run the PCI Code to loop over the PCI BARs. For now we don't use the BARs,
// dont check em.
#define CHECK_BARS 0
#define MAX_PCI_BAR 6
/* Capability lists */
#define PCI_CAP_LIST_ID 0 /* Capability ID */
#define PCI_CAP_ID_PM 0x01 /* Power Management */
#define PCI_CAP_ID_AGP 0x02 /* Accelerated Graphics Port */
#define PCI_CAP_ID_VPD 0x03 /* Vital Product Data */
#define PCI_CAP_ID_SLOTID 0x04 /* Slot Identification */
#define PCI_CAP_ID_MSI 0x05 /* Message Signalled Interrupts */
#define PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */
#define PCI_CAP_ID_PCIX 0x07 /* PCI-X */
#define PCI_CAP_ID_HT 0x08 /* HyperTransport */
#define PCI_CAP_ID_VNDR 0x09 /* Vendor specific */
#define PCI_CAP_ID_DBG 0x0A /* Debug port */
#define PCI_CAP_ID_CCRC 0x0B /* CompactPCI Central Resource Control */
#define PCI_CAP_ID_SHPC 0x0C /* PCI Standard Hot-Plug Controller */
#define PCI_CAP_ID_SSVID 0x0D /* Bridge subsystem vendor/device ID */
#define PCI_CAP_ID_AGP3 0x0E /* AGP Target PCI-PCI bridge */
#define PCI_CAP_ID_SECDEV 0x0F /* Secure Device */
#define PCI_CAP_ID_EXP 0x10 /* PCI Express */
#define PCI_CAP_ID_MSIX 0x11 /* MSI-X */
#define PCI_CAP_ID_SATA 0x12 /* SATA Data/Index Conf. */
#define PCI_CAP_ID_AF 0x13 /* PCI Advanced Features */
#define PCI_CAP_ID_MAX PCI_CAP_ID_AF
#define PCI_CAP_LIST_NEXT 1 /* Next capability in the list */
#define PCI_CAP_FLAGS 2 /* Capability defined flags (16 bits) */
#define PCI_CAP_SIZEOF 4
/* Power Management Registers */
#define PCI_PM_PMC 2 /* PM Capabilities Register */
#define PCI_PM_CAP_VER_MASK 0x0007 /* Version */
#define PCI_PM_CAP_PME_CLOCK 0x0008 /* PME clock required */
#define PCI_PM_CAP_RESERVED 0x0010 /* Reserved field */
#define PCI_PM_CAP_DSI 0x0020 /* Device specific initialization */
#define PCI_PM_CAP_AUX_POWER 0x01C0 /* Auxiliary power support mask */
#define PCI_PM_CAP_D1 0x0200 /* D1 power state support */
#define PCI_PM_CAP_D2 0x0400 /* D2 power state support */
#define PCI_PM_CAP_PME 0x0800 /* PME pin supported */
#define PCI_PM_CAP_PME_MASK 0xF800 /* PME Mask of all supported states */
#define PCI_PM_CAP_PME_D0 0x0800 /* PME# from D0 */
#define PCI_PM_CAP_PME_D1 0x1000 /* PME# from D1 */
#define PCI_PM_CAP_PME_D2 0x2000 /* PME# from D2 */
#define PCI_PM_CAP_PME_D3 0x4000 /* PME# from D3 (hot) */
#define PCI_PM_CAP_PME_D3cold 0x8000 /* PME# from D3 (cold) */
#define PCI_PM_CAP_PME_SHIFT 11 /* Start of the PME Mask in PMC */
#define PCI_PM_CTRL 4 /* PM control and status register */
#define PCI_PM_CTRL_STATE_MASK 0x0003 /* Current power state (D0 to D3) */
#define PCI_PM_CTRL_NO_SOFT_RESET 0x0008 /* No reset for D3hot->D0 */
#define PCI_PM_CTRL_PME_ENABLE 0x0100 /* PME pin enable */
#define PCI_PM_CTRL_DATA_SEL_MASK 0x1e00 /* Data select (??) */
#define PCI_PM_CTRL_DATA_SCALE_MASK 0x6000 /* Data scale (??) */
#define PCI_PM_CTRL_PME_STATUS 0x8000 /* PME pin status */
#define PCI_PM_PPB_EXTENSIONS 6 /* PPB support extensions (??) */
#define PCI_PM_PPB_B2_B3 0x40 /* Stop clock when in D3hot (??) */
#define PCI_PM_BPCC_ENABLE 0x80 /* Bus power/clock control enable (??) */
#define PCI_PM_DATA_REGISTER 7 /* (??) */
#define PCI_PM_SIZEOF 8
/* AGP registers */
#define PCI_AGP_VERSION 2 /* BCD version number */
#define PCI_AGP_RFU 3 /* Rest of capability flags */
#define PCI_AGP_STATUS 4 /* Status register */
#define PCI_AGP_STATUS_RQ_MASK 0xff000000 /* Maximum number of requests - 1 */
#define PCI_AGP_STATUS_SBA 0x0200 /* Sideband addressing supported */
#define PCI_AGP_STATUS_64BIT 0x0020 /* 64-bit addressing supported */
#define PCI_AGP_STATUS_FW 0x0010 /* FW transfers supported */
#define PCI_AGP_STATUS_RATE4 0x0004 /* 4x transfer rate supported */
#define PCI_AGP_STATUS_RATE2 0x0002 /* 2x transfer rate supported */
#define PCI_AGP_STATUS_RATE1 0x0001 /* 1x transfer rate supported */
#define PCI_AGP_COMMAND 8 /* Control register */
#define PCI_AGP_COMMAND_RQ_MASK 0xff000000 /* Master: Maximum number of requests */
#define PCI_AGP_COMMAND_SBA 0x0200 /* Sideband addressing enabled */
#define PCI_AGP_COMMAND_AGP 0x0100 /* Allow processing of AGP transactions */
#define PCI_AGP_COMMAND_64BIT 0x0020 /* Allow processing of 64-bit addresses */
#define PCI_AGP_COMMAND_FW 0x0010 /* Force FW transfers */
#define PCI_AGP_COMMAND_RATE4 0x0004 /* Use 4x rate */
#define PCI_AGP_COMMAND_RATE2 0x0002 /* Use 2x rate */
#define PCI_AGP_COMMAND_RATE1 0x0001 /* Use 1x rate */
#define PCI_AGP_SIZEOF 12
/* Vital Product Data */
#define PCI_VPD_ADDR 2 /* Address to access (15 bits!) */
#define PCI_VPD_ADDR_MASK 0x7fff /* Address mask */
#define PCI_VPD_ADDR_F 0x8000 /* Write 0, 1 indicates completion */
#define PCI_VPD_DATA 4 /* 32-bits of data returned here */
#define PCI_CAP_VPD_SIZEOF 8
/* Slot Identification */
#define PCI_SID_ESR 2 /* Expansion Slot Register */
#define PCI_SID_ESR_NSLOTS 0x1f /* Number of expansion slots available */
#define PCI_SID_ESR_FIC 0x20 /* First In Chassis Flag */
#define PCI_SID_CHASSIS_NR 3 /* Chassis Number */
/* Message Signalled Interrupts registers */
#define PCI_MSI_FLAGS 2 /* Various flags */
#define PCI_MSI_FLAGS_64BIT 0x80 /* 64-bit addresses allowed */
#define PCI_MSI_FLAGS_QSIZE 0x70 /* Message queue size configured */
#define PCI_MSI_FLAGS_QMASK 0x0e /* Maximum queue size available */
#define PCI_MSI_FLAGS_ENABLE 0x01 /* MSI feature enabled */
#define PCI_MSI_FLAGS_MASKBIT 0x100 /* 64-bit mask bits allowed */
#define PCI_MSI_RFU 3 /* Rest of capability flags */
#define PCI_MSI_ADDRESS_LO 4 /* Lower 32 bits */
#define PCI_MSI_ADDRESS_HI 8 /* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */
#define PCI_MSI_DATA_32 8 /* 16 bits of data for 32-bit devices */
#define PCI_MSI_MASK_32 12 /* Mask bits register for 32-bit devices */
#define PCI_MSI_PENDING_32 16 /* Pending intrs for 32-bit devices */
#define PCI_MSI_DATA_64 12 /* 16 bits of data for 64-bit devices */
#define PCI_MSI_MASK_64 16 /* Mask bits register for 64-bit devices */
#define PCI_MSI_PENDING_64 20 /* Pending intrs for 64-bit devices */
/* MSI-X registers */
#define PCI_MSIX_FLAGS 2
#define PCI_MSIX_FLAGS_QSIZE 0x7FF
#define PCI_MSIX_FLAGS_ENABLE (1 << 15)
#define PCI_MSIX_FLAGS_MASKALL (1 << 14)
#define PCI_MSIX_TABLE 4
#define PCI_MSIX_PBA 8
#define PCI_MSIX_FLAGS_BIRMASK (7 << 0)
#define PCI_CAP_MSIX_SIZEOF 12 /* size of MSIX registers */
/* MSI-X entry's format */
#define PCI_MSIX_ENTRY_SIZE 16
#define PCI_MSIX_ENTRY_LOWER_ADDR 0
#define PCI_MSIX_ENTRY_UPPER_ADDR 4
#define PCI_MSIX_ENTRY_DATA 8
#define PCI_MSIX_ENTRY_VECTOR_CTRL 12
#define PCI_MSIX_ENTRY_CTRL_MASKBIT 1
/* CompactPCI Hotswap Register */
#define PCI_CHSWP_CSR 2 /* Control and Status Register */
#define PCI_CHSWP_DHA 0x01 /* Device Hiding Arm */
#define PCI_CHSWP_EIM 0x02 /* ENUM# Signal Mask */
#define PCI_CHSWP_PIE 0x04 /* Pending Insert or Extract */
#define PCI_CHSWP_LOO 0x08 /* LED On / Off */
#define PCI_CHSWP_PI 0x30 /* Programming Interface */
#define PCI_CHSWP_EXT 0x40 /* ENUM# status - extraction */
#define PCI_CHSWP_INS 0x80 /* ENUM# status - insertion */
/* PCI Advanced Feature registers */
#define PCI_AF_LENGTH 2
#define PCI_AF_CAP 3
#define PCI_AF_CAP_TP 0x01
#define PCI_AF_CAP_FLR 0x02
#define PCI_AF_CTRL 4
#define PCI_AF_CTRL_FLR 0x01
#define PCI_AF_STATUS 5
#define PCI_AF_STATUS_TP 0x01
#define PCI_CAP_AF_SIZEOF 6 /* size of AF registers */
struct pci_bar {
uint32_t raw_bar;
uint32_t pio_base;
uint32_t mmio_base32;
uint64_t mmio_base64;
uint32_t mmio_sz;
};
struct pci_device {
STAILQ_ENTRY(pci_device) all_dev; /* list of all devices */
SLIST_ENTRY(pci_device) irq_dev; /* list of all devs off an irq */
spinlock_t lock;
bool in_use; /* prevent double discovery */
uint8_t bus;
uint8_t dev;
uint8_t func;
uint16_t dev_id;
uint16_t ven_id;
uint8_t irqline;
uint8_t irqpin;
char *header_type;
uint8_t class;
uint8_t subclass;
uint8_t progif;
bool msi_ready;
uint32_t msi_msg_addr_hi;
uint32_t msi_msg_addr_lo;
uint32_t msi_msg_data;
uint8_t nr_bars;
struct pci_bar bar[MAX_PCI_BAR];
uint32_t caps[PCI_CAP_ID_MAX + 1];
uintptr_t msix_tbl_paddr;
uintptr_t msix_tbl_vaddr;
uintptr_t msix_pba_paddr;
uintptr_t msix_pba_vaddr;
unsigned int msix_nr_vec;
bool msix_ready;
// Expansion ROM and attached FLASH
int flash_size;
};
struct msix_entry {
uint32_t addr_lo, addr_hi, data, vector;
};
struct msix_irq_vector {
struct pci_device *pcidev;
struct msix_entry *entry;
uint32_t addr_lo;
uint32_t addr_hi;
uint32_t data;
};
/* List of all discovered devices */
STAILQ_HEAD(pcidev_stailq, pci_device);
extern struct pcidev_stailq pci_devices;
/* Sync rules for PCI: once a device is added to the list, it is never removed,
* and its read-only fields can be accessed at any time. There is no need for
* refcnts or things like that.
*
* The device list is built early on when we're single threaded, so I'm not
* bothering with locks for that yet. Append-only, singly-linked-list reads
* don't need a lock either.
*
* Other per-device accesses (like read-modify-writes to config space or MSI
* fields) require the device's lock. If we ever want to unplug, we'll probably
* work out an RCU-like scheme for the pci_devices list.
*
* Note this is in addition to the config space global locking done by every
* pci_read or write call. */
void pci_init(void);
void pcidev_print_info(struct pci_device *pcidev, int verbosity);
uint32_t pci_config_addr(uint8_t bus, uint8_t dev, uint8_t func, uint32_t reg);
/* Read and write helpers (Eventually, we should have these be statics, since no
* device should touch PCI config space). */
uint32_t pci_read32(uint8_t bus, uint8_t dev, uint8_t func, uint32_t offset);
void pci_write32(uint8_t bus, uint8_t dev, uint8_t func, uint32_t offset,
uint32_t value);
uint16_t pci_read16(uint8_t bus, uint8_t dev, uint8_t func, uint32_t offset);
void pci_write16(uint8_t bus, uint8_t dev, uint8_t func, uint32_t offset,
uint16_t value);
uint8_t pci_read8(uint8_t bus, uint8_t dev, uint8_t func, uint32_t offset);
void pci_write8(uint8_t bus, uint8_t dev, uint8_t func, uint32_t offset,
uint8_t value);
uint32_t pcidev_read32(struct pci_device *pcidev, uint32_t offset);
void pcidev_write32(struct pci_device *pcidev, uint32_t offset, uint32_t value);
uint16_t pcidev_read16(struct pci_device *pcidev, uint32_t offset);
void pcidev_write16(struct pci_device *pcidev, uint32_t offset, uint16_t value);
uint8_t pcidev_read8(struct pci_device *pcidev, uint32_t offset);
void pcidev_write8(struct pci_device *pcidev, uint32_t offset, uint8_t value);
/* Other common PCI functions */
void pci_set_bus_master(struct pci_device *pcidev);
void pci_clr_bus_master(struct pci_device *pcidev);
struct pci_device *pci_match_tbdf(int tbdf);
uintptr_t pci_get_membar(struct pci_device *pcidev, int bir);
uintptr_t pci_get_iobar(struct pci_device *pcidev, int bir);
uint16_t pci_get_vendor(struct pci_device *pcidev);
uint16_t pci_get_device(struct pci_device *pcidev);
uint16_t pci_get_subvendor(struct pci_device *pcidev);
uint16_t pci_get_subdevice(struct pci_device *pcidev);
void pci_dump_config(struct pci_device *pcidev, size_t len);
int pci_find_cap(struct pci_device *pcidev, uint8_t cap_id, uint32_t *cap_reg);
/* MSI functions, msi.c */
int pci_msi_enable(struct pci_device *p, uint64_t vec);
struct msix_irq_vector *pci_msix_enable(struct pci_device *p, uint64_t vec);
void pci_msi_mask(struct pci_device *p);
void pci_msi_unmask(struct pci_device *p);
void pci_msi_route(struct pci_device *p, int dest);
void pci_msix_mask_vector(struct msix_irq_vector *linkage);
void pci_msix_unmask_vector(struct msix_irq_vector *linkage);
void pci_msix_route_vector(struct msix_irq_vector *linkage, int dest);
/* TODO: this is quite the Hacke */
#define explode_tbdf(tbdf) {pcidev.bus = tbdf >> 16;\
pcidev.dev = (tbdf>>11)&0x1f;\
pcidev.func = (tbdf>>8)&3;}
#endif /* ROS_ARCH_PCI_H */