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