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#pragma once 13 14#include <pci/helper.h> 15#include <stdbool.h> 16#include <inttypes.h> 17 18// ref: http://www.acm.uiuc.edu/sigops/roll_your_own/7.c.0.html 19// PCI System Architecture, rev 4 20 21#define PCI_CONFIG_HEADER_SIZE_BYTES PCI_STD_HEADER_SIZEOF 22 23/* Detailed base address information about a device. */ 24struct libpci_device_iocfg { 25 /* PCI_BASE_ADDRESS_MEM address or 26 PCI_BASE_ADDRESS_IO address */ 27 uint32_t base_addr[6]; 28 /* PCI_BASE_ADDRESS_SPACE_IO or 29 PCI_BASE_ADDRESS_SPACE_MEMORY */ 30 uint8_t base_addr_space[6]; 31 /* PCI_BASE_ADDRESS_MEM_TYPE_32 or 32 PCI_BASE_ADDRESS_MEM_TYPE_64 */ 33 uint8_t base_addr_type[6]; 34 /* PCI_BASE_ADDRESS_MEM_PREFETCH */ 35 uint8_t base_addr_prefetchable[6]; 36 /* size */ 37 uint32_t base_addr_size_mask[6]; 38 uint32_t base_addr_size[6]; 39 /* raw addr */ 40 uint32_t base_addr_raw[6]; 41 /* Is this BAR the higher word of a 64-bit address? If true, then this BAR is partial 42 and should not be directly processed in any way. */ 43 bool base_addr_64H[6]; 44}; 45 46typedef struct libpci_device_iocfg libpci_device_iocfg_t; 47 48/* Get the size of a PCI config space element. */ 49static inline int libpci_device_cfg_sizeof(int offset) { 50 switch (offset) { 51 case PCI_VENDOR_ID: return 2; 52 case PCI_DEVICE_ID: return 2; 53 54 case PCI_COMMAND: return 2; 55 case PCI_STATUS: return 2; 56 57 case PCI_CLASS_REVISION: return 1; 58 case PCI_CLASS_PROG: return 1; 59 case PCI_CLASS_DEVICE: return 2; 60 61 case PCI_CACHE_LINE_SIZE: return 1; 62 case PCI_LATENCY_TIMER: return 1; 63 case PCI_HEADER_TYPE: return 1; 64 case PCI_BIST: return 1; 65 66 case PCI_BASE_ADDRESS_0: 67 case PCI_BASE_ADDRESS_1: 68 case PCI_BASE_ADDRESS_2: 69 case PCI_BASE_ADDRESS_3: 70 case PCI_BASE_ADDRESS_4: 71 case PCI_BASE_ADDRESS_5: 72 return 4; 73 74 case PCI_CARDBUS_CIS: return 4; 75 case PCI_SUBSYSTEM_VENDOR_ID: return 2; 76 case PCI_SUBSYSTEM_ID: return 2; 77 case PCI_ROM_ADDRESS: return 4; 78 79 case PCI_INTERRUPT_LINE: return 1; 80 case PCI_INTERRUPT_PIN: return 1; 81 case PCI_MIN_GNT: return 1; 82 case PCI_MAX_LAT: return 1; 83 } 84 return 0; 85} 86 87/* Get the base address at a given index. Will automatically handle split 64-bit addreses. */ 88static inline uint64_t libpci_device_iocfg_get_baseaddr(libpci_device_iocfg_t *cfg, int index) { 89 assert(cfg && index >= 0 && index < 6); 90 if (cfg->base_addr_type[index] != PCI_BASE_ADDRESS_MEM_TYPE_64) 91 return (uint64_t) cfg->base_addr[index]; 92 /* 64-bit mode BARs must have a word after it. */ 93 assert(index < 5); 94 /* And the word before it better be set to 64L mode. */ 95 assert(cfg->base_addr_64H[index + 1]); 96 return ((uint64_t) cfg->base_addr[index]) | (((uint64_t) cfg->base_addr[index + 1]) << 32); 97} 98 99/* Get the 32-bit base address at given index. Will automatically handle split 64-bit addresses, 100 * and cast them (with an assert check that the upper 32-bits are zero). */ 101static inline uint32_t libpci_device_iocfg_get_baseaddr32(libpci_device_iocfg_t *cfg, int index) { 102 uint64_t baddr = libpci_device_iocfg_get_baseaddr(cfg, index); 103 assert((baddr & 0xFFFFFFFFUL) == baddr); 104 if ((baddr & 0xFFFFFFFFUL) != baddr) { 105 printf("WARNING: get_baseaddr32 called for 64-bit address. Address will be truncated.\n"); 106 printf(" This will most likely lead to problems.\n"); 107 assert(!"WARNING. Zap this assert to ignore."); 108 } 109 return (uint32_t)(baddr & 0xFFFFFFFFUL); 110} 111 112/* Returns true if the given device has at least one IO port base addr associated, 113 * false otherwise. */ 114static inline bool libpci_device_iocfg_uses_iomem(libpci_device_iocfg_t *cfg) { 115 assert(cfg); 116 for (int i = 0; i < 6; i++) { 117 if (cfg->base_addr[i] == 0 || cfg->base_addr_64H[i]) continue; 118 return true; 119 } 120 return false; 121} 122 123/* Print out detailed info about a device's base addresses. */ 124static inline void libpci_device_iocfg_debug_print(libpci_device_iocfg_t *cfg, bool compact) { 125 for(int i = 0; i < 6; i++) { 126 if (compact) { 127 /* Display in compact space mode, shoving as much information as possible in a few 128 * lines. This is similar to how the Linux kernel PCI debug displays in dmesg. */ 129 if (cfg->base_addr[i] == 0 || cfg->base_addr_64H[i]) continue; 130 if (cfg->base_addr_space[i] == PCI_BASE_ADDRESS_SPACE_IO) { 131 printf(" BAR%d : [ io 0x%"PRIx64" sz 0x%x szmask 0x%x ]\n", i, 132 libpci_device_iocfg_get_baseaddr(cfg, i), 133 cfg->base_addr_size[i], 134 cfg->base_addr_size_mask[i]); 135 } else { 136 printf(" BAR%d : [ mem 0x%"PRIx64" sz 0x%x szmask 0x%x %s %s ]\n", i, 137 libpci_device_iocfg_get_baseaddr(cfg, i), 138 cfg->base_addr_size[i], 139 cfg->base_addr_size_mask[i], 140 cfg->base_addr_type[i] == PCI_BASE_ADDRESS_MEM_TYPE_64 ? "64bit" : "", 141 cfg->base_addr_prefetchable[i] ? "prefetch" : ""); 142 } 143 } else { 144 /* Very verbose and space wasting debug output. */ 145 printf(" BASE_ADDR[%d] ----\n", i); 146 if (cfg->base_addr[i] == 0 || cfg->base_addr_64H[i]) continue; 147 printf(" base_addr_space[%d]: 0x%x [%s]\n", i, cfg->base_addr_space[i], 148 cfg->base_addr_space[i] ? "PCI_BASE_ADDRESS_SPACE_IO" : 149 "PCI_BASE_ADDRESS_SPACE_MEMORY"); 150 printf(" base_addr_type[%d]: 0x%x [ ", i, cfg->base_addr_type[i]); 151 if (cfg->base_addr_type[i] == PCI_BASE_ADDRESS_MEM_TYPE_32) printf("32bit "); 152 if (cfg->base_addr_type[i] == PCI_BASE_ADDRESS_MEM_TYPE_64) printf("64bit "); 153 if (cfg->base_addr_type[i] == PCI_BASE_ADDRESS_MEM_TYPE_1M) printf("<1M "); 154 printf("]\n"); 155 printf(" base_addr_prefetchable[%d]: %s\n", i, cfg->base_addr_prefetchable[i] 156 ? "yes" : "no"); 157 printf(" base_addr[%d]: 0x%"PRIx64"\n", i, libpci_device_iocfg_get_baseaddr(cfg, i)); 158 printf(" base_addr_size_mask[%d]: 0x%x\n", i, cfg->base_addr_size_mask[i]); 159 } 160 } 161} 162