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#include <autoconf.h> 13#include <stdio.h> 14#include <stdlib.h> 15#include <string.h> 16#include <pci/pci.h> 17#include <pci/helper.h> 18#include <pci/ioreg.h> 19#include <utils/attribute.h> 20#include <utils/zf_log.h> 21 22#define PCI_DISPLAY_FOUND_DEVICES 23 24libpci_device_t libpci_device_list[PCI_MAX_DEVICES]; 25uint32_t libpci_num_devices = 0; 26static ps_io_port_ops_t global_port_ops; 27 28uint32_t libpci_ioread(uint32_t port_no, uint32_t* val, uint32_t size) { 29 return (uint32_t)ps_io_port_in(&global_port_ops, port_no, (int)size, val); 30} 31 32uint32_t libpci_iowrite(uint32_t port_no, uint32_t val, uint32_t size) { 33 return (uint32_t)ps_io_port_out(&global_port_ops, port_no, (int)size, val); 34} 35 36libpci_device_t* libpci_find_device(uint16_t vendor_id, uint16_t device_id) { 37 for (uint32_t i = 0; i < libpci_num_devices; i++) { 38 if (libpci_device_list[i].vendor_id == vendor_id && 39 libpci_device_list[i].device_id == device_id) { 40 return &libpci_device_list[i]; 41 } 42 } 43 return NULL; 44} 45 46int libpci_find_device_all(uint16_t vendor_id, uint16_t device_id, libpci_device_t** out) { 47 assert(out); 48 int n = 0; 49 for (uint32_t i = 0; i < libpci_num_devices; i++) { 50 if (libpci_device_list[i].vendor_id == vendor_id && 51 libpci_device_list[i].device_id == device_id) { 52 out[n++] = &libpci_device_list[i]; 53 } 54 } 55 return n; 56} 57 58libpci_device_t* libpci_find_device_matching(libpci_device_t *device) { 59 for (uint32_t i = 0; i < libpci_num_devices; i++) { 60 if (libpci_device_list[i].bus == device->bus && 61 libpci_device_list[i].dev == device->dev && 62 libpci_device_list[i].fun == device->fun && 63 libpci_device_list[i].vendor_id == device->vendor_id && 64 libpci_device_list[i].device_id == device->device_id) { 65 return &libpci_device_list[i]; 66 } 67 } 68 return NULL; 69} 70 71libpci_device_t* libpci_find_device_bdf(uint8_t bus, uint8_t dev, uint8_t fun) { 72 for (uint32_t i = 0; i < libpci_num_devices; i++) { 73 if (libpci_device_list[i].bus == bus && 74 libpci_device_list[i].dev == dev && 75 libpci_device_list[i].fun == fun) { 76 return &libpci_device_list[i]; 77 } 78 } 79 return NULL; 80} 81 82static int libpci_add_fun(uint8_t bus, uint8_t dev, uint8_t fun) { 83 uint16_t vendor_id = libpci_read_reg16(bus, dev, fun, PCI_VENDOR_ID); 84 85 if (vendor_id == PCI_VENDOR_ID_INVALID) { 86 /* No device here. */ 87 return 0; 88 } 89 90 ZF_LOGD("PCI :: Device found at BUS %d DEV %d FUN %d:\n", (int)bus, (int)dev, (int)fun); 91 ZF_LOGD(" vendorID = %s [0x%x]\n", libpci_vendorID_str(vendor_id), vendor_id); 92 93 uint16_t device_id = libpci_read_reg16(bus, dev, fun, PCI_DEVICE_ID); 94 ZF_LOGD(" deviceID = %s [0x%x]\n", libpci_deviceID_str(vendor_id, device_id), device_id); 95 96 assert(libpci_num_devices + 1<= PCI_MAX_DEVICES); 97 libpci_device_list[libpci_num_devices].bus = bus; 98 libpci_device_list[libpci_num_devices].dev = dev; 99 libpci_device_list[libpci_num_devices].fun = fun; 100 libpci_device_list[libpci_num_devices].vendor_id = vendor_id; 101 libpci_device_list[libpci_num_devices].device_id = device_id; 102 libpci_device_list[libpci_num_devices].vendor_name = libpci_vendorID_str(vendor_id); 103 libpci_device_list[libpci_num_devices].device_name = libpci_deviceID_str(vendor_id, device_id); 104 libpci_device_list[libpci_num_devices].interrupt_line = libpci_read_reg8(bus, dev, fun, PCI_INTERRUPT_LINE); 105 libpci_device_list[libpci_num_devices].interrupt_pin = libpci_read_reg8(bus, dev, fun, PCI_INTERRUPT_PIN); 106 libpci_device_list[libpci_num_devices].subsystem_id = libpci_read_reg16(bus, dev, fun, PCI_SUBSYSTEM_ID); 107 libpci_read_ioconfig(&libpci_device_list[libpci_num_devices].cfg, bus, dev, fun); 108 109#if (ZF_LOG_LEVEL == ZF_LOG_VERBOSE) 110 libpci_device_iocfg_debug_print(&libpci_device_list[libpci_num_devices].cfg, false); 111#endif 112 113 #ifdef PCI_DISPLAY_FOUND_DEVICES 114 printf("PCI :: %.2x.%.2x.%.2x : %s %s (vid 0x%x did 0x%x) line%d pin%d\n", bus, dev, fun, 115 libpci_vendorID_str(vendor_id), libpci_deviceID_str(vendor_id, device_id), 116 vendor_id, device_id, 117 libpci_read_reg8(bus, dev, fun, PCI_INTERRUPT_LINE), 118 libpci_read_reg8(bus, dev, fun, PCI_INTERRUPT_PIN) 119 ); 120 libpci_device_iocfg_debug_print(&libpci_device_list[libpci_num_devices].cfg, true); 121 #endif 122 123 libpci_num_devices++; 124 125 return 1; 126} 127 128static void lib_pci_scan_bus(int bus); 129 130static void lib_pci_scan_fun(int bus, int dev, int fun) { 131 libpci_add_fun(bus, dev, fun); 132 if ( libpci_read_reg16(bus, dev, fun, PCI_CLASS_DEVICE) == 0x0604) { 133 int new_bus = libpci_read_reg8(bus, dev, fun, PCI_SECONDARY_BUS); 134 printf("%s found additional bus %d from %d %d %d\n", __FUNCTION__, new_bus, bus, dev, fun); 135 lib_pci_scan_bus(new_bus); 136 } 137} 138 139static void lib_pci_scan_dev(int bus, int dev) { 140 uint16_t vendor_id = libpci_read_reg16(bus, dev, 0, PCI_VENDOR_ID); 141 if (vendor_id == PCI_VENDOR_ID_INVALID) { 142 return; 143 } 144 printf("%s found pci device %d %d\n", __FUNCTION__, bus, dev); 145 lib_pci_scan_fun(bus, dev, 0); 146 if ( (libpci_read_reg8(bus, dev, 0, PCI_HEADER_TYPE) & 0x80) != 0) { 147 printf("%s found multi function device %d %d\n", __FUNCTION__, bus, dev); 148 for (int function = 1; function < 8; function++) { 149 if (libpci_read_reg16(bus, dev, function, PCI_VENDOR_ID) != PCI_VENDOR_ID_INVALID) { 150 lib_pci_scan_fun(bus, dev, function); 151 } 152 } 153 } 154} 155 156static void lib_pci_scan_bus(int bus) { 157 for (int dev = 0; dev < 32; dev++) { 158 lib_pci_scan_dev(bus, dev); 159 } 160} 161 162void libpci_scan(ps_io_port_ops_t port_ops) { 163 global_port_ops = port_ops; 164 ZF_LOGD("PCI :: Scanning...\n"); 165 if ( (libpci_read_reg8(0, 0, 0, PCI_HEADER_TYPE) & 0x80) == 0) { 166 printf("Single bus detected\n"); 167 lib_pci_scan_bus(0); 168 } else { 169 for (int function = 0; function < 8; function++) { 170 if (libpci_read_reg16(0, 0, function, PCI_VENDOR_ID) != PCI_VENDOR_ID_INVALID) { 171 printf("%s detected bus %d\n", __FUNCTION__, function); 172 lib_pci_scan_bus(function); 173 } 174 } 175 } 176} 177 178void libpci_read_ioconfig(libpci_device_iocfg_t *cfg, uint8_t bus, uint8_t dev, uint8_t fun) { 179 assert(cfg); 180 memset(cfg, 0, sizeof(libpci_device_iocfg_t)); 181 182 for (int i = 0; i < 6; i++) { 183 // Read and save the base address assigned by the BIOS. 184 uint32_t bios_base_addr = libpci_read_reg32(bus, dev, fun, PCI_BASE_ADDRESS_0 + (i * 4)); 185 cfg->base_addr_raw[i] = bios_base_addr; 186 187 if (cfg->base_addr_64H[i]) { 188 // Don't bother processing further if this is already part of a 64-bit address. 189 cfg->base_addr[i] = cfg->base_addr_raw[i]; 190 cfg->base_addr_size_mask[i] = 0xFFFFFFFF; 191 cfg->base_addr_size[i] = 0; 192 continue; 193 } 194 195 // Write 0xFFFFFFFF to read the configs. 196 libpci_write_reg32(bus, dev, fun, PCI_BASE_ADDRESS_0 + (i * 4), 0xFFFFFFFF); 197 uint32_t cfg_base_addr = libpci_read_reg32(bus, dev, fun, PCI_BASE_ADDRESS_0 + (i * 4)); 198 199 if (cfg_base_addr == 0) 200 /* no device here. */ 201 continue; 202 203 cfg->base_addr_space[i] = cfg_base_addr & PCI_BASE_ADDRESS_SPACE; 204 if (cfg->base_addr_space[i] == PCI_BASE_ADDRESS_SPACE_MEMORY) { 205 cfg->base_addr_type[i] = (cfg_base_addr & PCI_BASE_ADDRESS_MEM_TYPE_MASK); 206 cfg->base_addr_prefetchable[i] = (cfg_base_addr & PCI_BASE_ADDRESS_MEM_PREFETCH) > 0; 207 cfg->base_addr_size_mask[i] = cfg_base_addr & PCI_BASE_ADDRESS_MEM_MASK; 208 if (cfg->base_addr_type[i] == PCI_BASE_ADDRESS_MEM_TYPE_64) { 209 /* Handle 64-bit addresses. */ 210 assert(i < 5); 211 // Set up the next BAR entry to be 64H mode. 212 cfg->base_addr_64H[i + 1] = true; 213 // Set up this BAR entry to be in 64L mode. 214 cfg->base_addr[i] = bios_base_addr & PCI_BASE_ADDRESS_MEM_MASK; 215 } else { 216 cfg->base_addr[i] = bios_base_addr & PCI_BASE_ADDRESS_MEM_MASK; 217 } 218 } else /* PCI_BASE_ADDRESS_SPACE_IO */ { 219 cfg->base_addr[i] = bios_base_addr & PCI_BASE_ADDRESS_IO_MASK; 220 cfg->base_addr_size_mask[i] = cfg_base_addr & PCI_BASE_ADDRESS_IO_MASK; 221 cfg->base_addr_type[i] = PCI_BASE_ADDRESS_MEM_TYPE_32; 222 } 223 224 /* Calculate size from size_mask. */ 225 cfg->base_addr_size[i] = BIT(CTZ(cfg->base_addr_size_mask[i])); 226 227 // Write back the address set by the BIOS. 228 libpci_write_reg32(bus, dev, fun, PCI_BASE_ADDRESS_0 + (i * 4), bios_base_addr); 229 } 230} 231