1 /* 2 * Copyright (C) 2013, Red Hat Inc, Michael S. Tsirkin <mst@redhat.com> 3 * 4 * This work is licensed under the terms of the GNU LGPL, version 2. 5 */ 6 #include <linux/pci_regs.h> 7 #include "pci.h" 8 #include "asm/pci.h" 9 10 void pci_cap_walk(struct pci_dev *dev, pci_cap_handler_t handler) 11 { 12 uint8_t cap_offset; 13 uint8_t cap_id; 14 int count = 0; 15 16 cap_offset = pci_config_readb(dev->bdf, PCI_CAPABILITY_LIST); 17 while (cap_offset) { 18 cap_id = pci_config_readb(dev->bdf, cap_offset); 19 printf("PCI detected cap 0x%x\n", cap_id); 20 assert(cap_id < PCI_CAP_ID_MAX + 1); 21 handler(dev, cap_offset, cap_id); 22 cap_offset = pci_config_readb(dev->bdf, cap_offset + 1); 23 /* Avoid dead loop during cap walk */ 24 assert(++count <= 255); 25 } 26 } 27 28 void pci_msi_set_enable(struct pci_dev *dev, bool enabled) 29 { 30 uint16_t msi_control; 31 uint16_t offset; 32 33 offset = dev->msi_offset; 34 msi_control = pci_config_readw(dev->bdf, offset + PCI_MSI_FLAGS); 35 36 if (enabled) 37 msi_control |= PCI_MSI_FLAGS_ENABLE; 38 else 39 msi_control &= ~PCI_MSI_FLAGS_ENABLE; 40 41 pci_config_writew(dev->bdf, offset + PCI_MSI_FLAGS, msi_control); 42 } 43 44 bool pci_setup_msi(struct pci_dev *dev, uint64_t msi_addr, uint32_t msi_data) 45 { 46 uint16_t msi_control; 47 uint16_t offset; 48 pcidevaddr_t addr; 49 50 assert(dev); 51 52 if (!dev->msi_offset) { 53 printf("MSI: dev 0x%x does not support MSI.\n", dev->bdf); 54 return false; 55 } 56 57 addr = dev->bdf; 58 offset = dev->msi_offset; 59 msi_control = pci_config_readw(addr, offset + PCI_MSI_FLAGS); 60 pci_config_writel(addr, offset + PCI_MSI_ADDRESS_LO, 61 msi_addr & 0xffffffff); 62 63 if (msi_control & PCI_MSI_FLAGS_64BIT) { 64 pci_config_writel(addr, offset + PCI_MSI_ADDRESS_HI, 65 (uint32_t)(msi_addr >> 32)); 66 pci_config_writel(addr, offset + PCI_MSI_DATA_64, msi_data); 67 printf("MSI: dev 0x%x init 64bit address: ", addr); 68 } else { 69 pci_config_writel(addr, offset + PCI_MSI_DATA_32, msi_data); 70 printf("MSI: dev 0x%x init 32bit address: ", addr); 71 } 72 printf("addr=0x%" PRIx64 ", data=0x%x\n", msi_addr, msi_data); 73 74 pci_msi_set_enable(dev, true); 75 76 return true; 77 } 78 79 void pci_cmd_set_clr(struct pci_dev *dev, uint16_t set, uint16_t clr) 80 { 81 uint16_t val = pci_config_readw(dev->bdf, PCI_COMMAND); 82 83 /* No overlap is allowed */ 84 assert((set & clr) == 0); 85 val |= set; 86 val &= ~clr; 87 88 pci_config_writew(dev->bdf, PCI_COMMAND, val); 89 } 90 91 bool pci_dev_exists(pcidevaddr_t dev) 92 { 93 return (pci_config_readw(dev, PCI_VENDOR_ID) != 0xffff && 94 pci_config_readw(dev, PCI_DEVICE_ID) != 0xffff); 95 } 96 97 void pci_dev_init(struct pci_dev *dev, pcidevaddr_t bdf) 98 { 99 memset(dev, 0, sizeof(*dev)); 100 dev->bdf = bdf; 101 } 102 103 /* Scan bus look for a specific device. Only bus 0 scanned for now. */ 104 pcidevaddr_t pci_find_dev(uint16_t vendor_id, uint16_t device_id) 105 { 106 pcidevaddr_t dev; 107 108 for (dev = 0; dev < PCI_DEVFN_MAX; ++dev) { 109 if (pci_config_readw(dev, PCI_VENDOR_ID) == vendor_id && 110 pci_config_readw(dev, PCI_DEVICE_ID) == device_id) 111 return dev; 112 } 113 114 return PCIDEVADDR_INVALID; 115 } 116 117 uint32_t pci_bar_mask(uint32_t bar) 118 { 119 return (bar & PCI_BASE_ADDRESS_SPACE_IO) ? 120 PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK; 121 } 122 123 uint32_t pci_bar_get(struct pci_dev *dev, int bar_num) 124 { 125 return pci_config_readl(dev->bdf, PCI_BASE_ADDRESS_0 + 126 bar_num * 4); 127 } 128 129 phys_addr_t pci_bar_get_addr(struct pci_dev *dev, int bar_num) 130 { 131 uint32_t bar = pci_bar_get(dev, bar_num); 132 uint32_t mask = pci_bar_mask(bar); 133 uint64_t addr = bar & mask; 134 phys_addr_t phys_addr; 135 136 if (pci_bar_is64(dev, bar_num)) 137 addr |= (uint64_t)pci_bar_get(dev, bar_num + 1) << 32; 138 139 phys_addr = pci_translate_addr(dev->bdf, addr); 140 assert(phys_addr != INVALID_PHYS_ADDR); 141 142 return phys_addr; 143 } 144 145 void pci_bar_set_addr(struct pci_dev *dev, int bar_num, phys_addr_t addr) 146 { 147 int off = PCI_BASE_ADDRESS_0 + bar_num * 4; 148 149 pci_config_writel(dev->bdf, off, (uint32_t)addr); 150 151 if (pci_bar_is64(dev, bar_num)) 152 pci_config_writel(dev->bdf, off + 4, 153 (uint32_t)(addr >> 32)); 154 } 155 156 /* 157 * To determine the amount of address space needed by a PCI device, 158 * one must save the original value of the BAR, write a value of 159 * all 1's to the register, and then read it back. The amount of 160 * memory can be then determined by masking the information bits, 161 * performing a bitwise NOT, and incrementing the value by 1. 162 * 163 * The following pci_bar_size_helper() and pci_bar_size() functions 164 * implement the algorithm. 165 */ 166 static uint32_t pci_bar_size_helper(struct pci_dev *dev, int bar_num) 167 { 168 int off = PCI_BASE_ADDRESS_0 + bar_num * 4; 169 uint16_t bdf = dev->bdf; 170 uint32_t bar, val; 171 172 bar = pci_config_readl(bdf, off); 173 pci_config_writel(bdf, off, ~0u); 174 val = pci_config_readl(bdf, off); 175 pci_config_writel(bdf, off, bar); 176 177 return val; 178 } 179 180 phys_addr_t pci_bar_size(struct pci_dev *dev, int bar_num) 181 { 182 uint32_t bar, size; 183 184 size = pci_bar_size_helper(dev, bar_num); 185 if (!size) 186 return 0; 187 188 bar = pci_bar_get(dev, bar_num); 189 size &= pci_bar_mask(bar); 190 191 if (pci_bar_is64(dev, bar_num)) { 192 phys_addr_t size64 = pci_bar_size_helper(dev, bar_num + 1); 193 size64 = (size64 << 32) | size; 194 195 return ~size64 + 1; 196 } else { 197 return ~size + 1; 198 } 199 } 200 201 bool pci_bar_is_memory(struct pci_dev *dev, int bar_num) 202 { 203 uint32_t bar = pci_bar_get(dev, bar_num); 204 205 return !(bar & PCI_BASE_ADDRESS_SPACE_IO); 206 } 207 208 bool pci_bar_is_valid(struct pci_dev *dev, int bar_num) 209 { 210 return pci_bar_get(dev, bar_num); 211 } 212 213 bool pci_bar_is64(struct pci_dev *dev, int bar_num) 214 { 215 uint32_t bar = pci_bar_get(dev, bar_num); 216 217 if (bar & PCI_BASE_ADDRESS_SPACE_IO) 218 return false; 219 220 return (bar & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == 221 PCI_BASE_ADDRESS_MEM_TYPE_64; 222 } 223 224 void pci_bar_print(struct pci_dev *dev, int bar_num) 225 { 226 phys_addr_t size, start, end; 227 uint32_t bar; 228 229 size = pci_bar_size(dev, bar_num); 230 if (!size) 231 return; 232 233 bar = pci_bar_get(dev, bar_num); 234 start = pci_bar_get_addr(dev, bar_num); 235 end = start + size - 1; 236 237 if (pci_bar_is64(dev, bar_num)) { 238 printf("BAR#%d,%d [%" PRIx64 "-%" PRIx64 " ", 239 bar_num, bar_num + 1, start, end); 240 } else { 241 printf("BAR#%d [%02x-%02x ", 242 bar_num, (uint32_t)start, (uint32_t)end); 243 } 244 245 if (bar & PCI_BASE_ADDRESS_SPACE_IO) { 246 printf("PIO"); 247 } else { 248 printf("MEM"); 249 switch (bar & PCI_BASE_ADDRESS_MEM_TYPE_MASK) { 250 case PCI_BASE_ADDRESS_MEM_TYPE_32: 251 printf("32"); 252 break; 253 case PCI_BASE_ADDRESS_MEM_TYPE_1M: 254 printf("1M"); 255 break; 256 case PCI_BASE_ADDRESS_MEM_TYPE_64: 257 printf("64"); 258 break; 259 default: 260 assert(0); 261 } 262 } 263 264 if (bar & PCI_BASE_ADDRESS_MEM_PREFETCH) 265 printf("/p"); 266 267 printf("]"); 268 } 269 270 void pci_dev_print_id(pcidevaddr_t dev) 271 { 272 printf("00.%02x.%1x %04x:%04x", dev / 8, dev % 8, 273 pci_config_readw(dev, PCI_VENDOR_ID), 274 pci_config_readw(dev, PCI_DEVICE_ID)); 275 } 276 277 void pci_dev_print(pcidevaddr_t dev) 278 { 279 uint8_t header = pci_config_readb(dev, PCI_HEADER_TYPE); 280 uint8_t progif = pci_config_readb(dev, PCI_CLASS_PROG); 281 uint8_t subclass = pci_config_readb(dev, PCI_CLASS_DEVICE); 282 uint8_t class = pci_config_readb(dev, PCI_CLASS_DEVICE + 1); 283 struct pci_dev pci_dev; 284 int i; 285 286 pci_dev_init(&pci_dev, dev); 287 288 pci_dev_print_id(dev); 289 printf(" type %02x progif %02x class %02x subclass %02x\n", 290 header, progif, class, subclass); 291 292 if ((header & PCI_HEADER_TYPE_MASK) != PCI_HEADER_TYPE_NORMAL) 293 return; 294 295 for (i = 0; i < PCI_BAR_NUM; i++) { 296 if (pci_bar_size(&pci_dev, i)) { 297 printf("\t"); 298 pci_bar_print(&pci_dev, i); 299 printf("\n"); 300 } 301 if (pci_bar_is64(&pci_dev, i)) 302 i++; 303 } 304 } 305 306 void pci_print(void) 307 { 308 pcidevaddr_t dev; 309 310 for (dev = 0; dev < PCI_DEVFN_MAX; ++dev) { 311 if (pci_dev_exists(dev)) 312 pci_dev_print(dev); 313 } 314 } 315 316 void pci_scan_bars(struct pci_dev *dev) 317 { 318 int i; 319 320 for (i = 0; i < PCI_BAR_NUM; i++) { 321 if (!pci_bar_is_valid(dev, i)) 322 continue; 323 dev->resource[i] = pci_bar_get_addr(dev, i); 324 if (pci_bar_is64(dev, i)) { 325 i++; 326 dev->resource[i] = (phys_addr_t)0; 327 } 328 } 329 } 330 331 uint8_t pci_intx_line(struct pci_dev *dev) 332 { 333 return pci_config_readb(dev->bdf, PCI_INTERRUPT_LINE); 334 } 335 336 static void pci_cap_setup(struct pci_dev *dev, int cap_offset, int cap_id) 337 { 338 switch (cap_id) { 339 case PCI_CAP_ID_MSI: 340 printf("Detected MSI for device 0x%x offset 0x%x\n", 341 dev->bdf, cap_offset); 342 dev->msi_offset = cap_offset; 343 break; 344 } 345 } 346 347 void pci_enable_defaults(struct pci_dev *dev) 348 { 349 pci_scan_bars(dev); 350 /* Enable device DMA operations */ 351 pci_cmd_set_clr(dev, PCI_COMMAND_MASTER, 0); 352 pci_cap_walk(dev, pci_cap_setup); 353 } 354