1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * New-style PCI core. 4 * 5 * Copyright (c) 2004 - 2009 Paul Mundt 6 * Copyright (c) 2002 M. R. Brown 7 * 8 * Modelled after arch/mips/pci/pci.c: 9 * Copyright (C) 2003, 04 Ralf Baechle (ralf@linux-mips.org) 10 */ 11 #include <linux/kernel.h> 12 #include <linux/mm.h> 13 #include <linux/pci.h> 14 #include <linux/init.h> 15 #include <linux/types.h> 16 #include <linux/io.h> 17 #include <linux/mutex.h> 18 #include <linux/spinlock.h> 19 #include <linux/export.h> 20 21 unsigned long PCIBIOS_MIN_IO = 0x0000; 22 unsigned long PCIBIOS_MIN_MEM = 0; 23 24 /* 25 * The PCI controller list. 26 */ 27 static struct pci_channel *hose_head, **hose_tail = &hose_head; 28 29 static int pci_initialized; 30 31 static void pcibios_scanbus(struct pci_channel *hose) 32 { 33 static int next_busno; 34 static int need_domain_info; 35 LIST_HEAD(resources); 36 struct resource *res; 37 resource_size_t offset; 38 int i, ret; 39 struct pci_host_bridge *bridge; 40 41 bridge = pci_alloc_host_bridge(0); 42 if (!bridge) 43 return; 44 45 for (i = 0; i < hose->nr_resources; i++) { 46 res = hose->resources + i; 47 offset = 0; 48 if (res->flags & IORESOURCE_DISABLED) 49 continue; 50 if (res->flags & IORESOURCE_IO) 51 offset = hose->io_offset; 52 else if (res->flags & IORESOURCE_MEM) 53 offset = hose->mem_offset; 54 pci_add_resource_offset(&resources, res, offset); 55 } 56 57 list_splice_init(&resources, &bridge->windows); 58 bridge->dev.parent = NULL; 59 bridge->sysdata = hose; 60 bridge->busnr = next_busno; 61 bridge->ops = hose->pci_ops; 62 bridge->swizzle_irq = pci_common_swizzle; 63 bridge->map_irq = pcibios_map_platform_irq; 64 65 ret = pci_scan_root_bus_bridge(bridge); 66 if (ret) { 67 pci_free_host_bridge(bridge); 68 return; 69 } 70 71 hose->bus = bridge->bus; 72 73 need_domain_info = need_domain_info || hose->index; 74 hose->need_domain_info = need_domain_info; 75 76 next_busno = hose->bus->busn_res.end + 1; 77 /* Don't allow 8-bit bus number overflow inside the hose - 78 reserve some space for bridges. */ 79 if (next_busno > 224) { 80 next_busno = 0; 81 need_domain_info = 1; 82 } 83 84 pci_bus_size_bridges(hose->bus); 85 pci_bus_assign_resources(hose->bus); 86 pci_bus_add_devices(hose->bus); 87 } 88 89 /* 90 * This interrupt-safe spinlock protects all accesses to PCI 91 * configuration space. 92 */ 93 DEFINE_RAW_SPINLOCK(pci_config_lock); 94 static DEFINE_MUTEX(pci_scan_mutex); 95 96 int register_pci_controller(struct pci_channel *hose) 97 { 98 int i; 99 100 for (i = 0; i < hose->nr_resources; i++) { 101 struct resource *res = hose->resources + i; 102 103 if (res->flags & IORESOURCE_DISABLED) 104 continue; 105 106 if (res->flags & IORESOURCE_IO) { 107 if (request_resource(&ioport_resource, res) < 0) 108 goto out; 109 } else { 110 if (request_resource(&iomem_resource, res) < 0) 111 goto out; 112 } 113 } 114 115 *hose_tail = hose; 116 hose_tail = &hose->next; 117 118 /* 119 * Do not panic here but later - this might happen before console init. 120 */ 121 if (!hose->io_map_base) { 122 pr_warn("registering PCI controller with io_map_base unset\n"); 123 } 124 125 /* 126 * Setup the ERR/PERR and SERR timers, if available. 127 */ 128 pcibios_enable_timers(hose); 129 130 /* 131 * Scan the bus if it is register after the PCI subsystem 132 * initialization. 133 */ 134 if (pci_initialized) { 135 mutex_lock(&pci_scan_mutex); 136 pcibios_scanbus(hose); 137 mutex_unlock(&pci_scan_mutex); 138 } 139 140 return 0; 141 142 out: 143 for (--i; i >= 0; i--) 144 release_resource(&hose->resources[i]); 145 146 pr_warn("Skipping PCI bus scan due to resource conflict\n"); 147 return -1; 148 } 149 150 static int __init pcibios_init(void) 151 { 152 struct pci_channel *hose; 153 154 /* Scan all of the recorded PCI controllers. */ 155 for (hose = hose_head; hose; hose = hose->next) 156 pcibios_scanbus(hose); 157 158 pci_initialized = 1; 159 160 return 0; 161 } 162 subsys_initcall(pcibios_init); 163 164 /* 165 * We need to avoid collisions with `mirrored' VGA ports 166 * and other strange ISA hardware, so we always want the 167 * addresses to be allocated in the 0x000-0x0ff region 168 * modulo 0x400. 169 */ 170 resource_size_t pcibios_align_resource(void *data, const struct resource *res, 171 resource_size_t size, resource_size_t align) 172 { 173 struct pci_dev *dev = data; 174 struct pci_channel *hose = dev->sysdata; 175 resource_size_t start = res->start; 176 177 if (res->flags & IORESOURCE_IO) { 178 if (start < PCIBIOS_MIN_IO + hose->resources[0].start) 179 start = PCIBIOS_MIN_IO + hose->resources[0].start; 180 181 /* 182 * Put everything into 0x00-0xff region modulo 0x400. 183 */ 184 if (start & 0x300) 185 start = (start + 0x3ff) & ~0x3ff; 186 } 187 188 return start; 189 } 190 191 static void __init 192 pcibios_bus_report_status_early(struct pci_channel *hose, 193 int top_bus, int current_bus, 194 unsigned int status_mask, int warn) 195 { 196 unsigned int pci_devfn; 197 u16 status; 198 int ret; 199 200 for (pci_devfn = 0; pci_devfn < 0xff; pci_devfn++) { 201 if (PCI_FUNC(pci_devfn)) 202 continue; 203 ret = early_read_config_word(hose, top_bus, current_bus, 204 pci_devfn, PCI_STATUS, &status); 205 if (ret != PCIBIOS_SUCCESSFUL) 206 continue; 207 if (status == 0xffff) 208 continue; 209 210 early_write_config_word(hose, top_bus, current_bus, 211 pci_devfn, PCI_STATUS, 212 status & status_mask); 213 if (warn) 214 pr_cont("(%02x:%02x: %04X) ", current_bus, pci_devfn, 215 status); 216 } 217 } 218 219 /* 220 * We can't use pci_find_device() here since we are 221 * called from interrupt context. 222 */ 223 static void __ref 224 pcibios_bus_report_status(struct pci_bus *bus, unsigned int status_mask, 225 int warn) 226 { 227 struct pci_dev *dev; 228 229 list_for_each_entry(dev, &bus->devices, bus_list) { 230 u16 status; 231 232 /* 233 * ignore host bridge - we handle 234 * that separately 235 */ 236 if (dev->bus->number == 0 && dev->devfn == 0) 237 continue; 238 239 pci_read_config_word(dev, PCI_STATUS, &status); 240 if (status == 0xffff) 241 continue; 242 243 if ((status & status_mask) == 0) 244 continue; 245 246 /* clear the status errors */ 247 pci_write_config_word(dev, PCI_STATUS, status & status_mask); 248 249 if (warn) 250 pr_cont("(%s: %04X) ", pci_name(dev), status); 251 } 252 253 list_for_each_entry(dev, &bus->devices, bus_list) 254 if (dev->subordinate) 255 pcibios_bus_report_status(dev->subordinate, status_mask, warn); 256 } 257 258 void __ref pcibios_report_status(unsigned int status_mask, int warn) 259 { 260 struct pci_channel *hose; 261 262 for (hose = hose_head; hose; hose = hose->next) { 263 if (unlikely(!hose->bus)) 264 pcibios_bus_report_status_early(hose, hose_head->index, 265 hose->index, status_mask, warn); 266 else 267 pcibios_bus_report_status(hose->bus, status_mask, warn); 268 } 269 } 270 271 #ifndef CONFIG_GENERIC_IOMAP 272 273 void __iomem *__pci_ioport_map(struct pci_dev *dev, 274 unsigned long port, unsigned int nr) 275 { 276 struct pci_channel *chan = dev->sysdata; 277 278 if (unlikely(!chan->io_map_base)) { 279 chan->io_map_base = sh_io_port_base; 280 281 if (pci_domains_supported) 282 panic("To avoid data corruption io_map_base MUST be " 283 "set with multiple PCI domains."); 284 } 285 286 return (void __iomem *)(chan->io_map_base + port); 287 } 288 289 void pci_iounmap(struct pci_dev *dev, void __iomem *addr) 290 { 291 iounmap(addr); 292 } 293 EXPORT_SYMBOL(pci_iounmap); 294 295 #endif /* CONFIG_GENERIC_IOMAP */ 296 297 EXPORT_SYMBOL(PCIBIOS_MIN_IO); 298 EXPORT_SYMBOL(PCIBIOS_MIN_MEM); 299
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.