| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * PCI address cache; allows the lookup of PCI devices based on I/O address |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright IBM Corporation 2004 |
|---|
| 5 | 6 | * Copyright Linas Vepstas <linas@austin.ibm.com> 2004 |
|---|
| 6 | | - * |
|---|
| 7 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 8 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 9 | | - * the Free Software Foundation; either version 2 of the License, or |
|---|
| 10 | | - * (at your option) any later version. |
|---|
| 11 | | - * |
|---|
| 12 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 13 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 14 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 15 | | - * GNU General Public License for more details. |
|---|
| 16 | | - * |
|---|
| 17 | | - * You should have received a copy of the GNU General Public License |
|---|
| 18 | | - * along with this program; if not, write to the Free Software |
|---|
| 19 | | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|---|
| 20 | 7 | */ |
|---|
| 21 | 8 | |
|---|
| 22 | 9 | #include <linux/list.h> |
|---|
| .. | .. |
|---|
| 26 | 13 | #include <linux/spinlock.h> |
|---|
| 27 | 14 | #include <linux/atomic.h> |
|---|
| 28 | 15 | #include <asm/pci-bridge.h> |
|---|
| 16 | +#include <asm/debugfs.h> |
|---|
| 29 | 17 | #include <asm/ppc-pci.h> |
|---|
| 30 | 18 | |
|---|
| 31 | 19 | |
|---|
| 32 | 20 | /** |
|---|
| 21 | + * DOC: Overview |
|---|
| 22 | + * |
|---|
| 33 | 23 | * The pci address cache subsystem. This subsystem places |
|---|
| 34 | 24 | * PCI device address resources into a red-black tree, sorted |
|---|
| 35 | 25 | * according to the address range, so that given only an i/o |
|---|
| .. | .. |
|---|
| 46 | 36 | * than any hash algo I could think of for this problem, even |
|---|
| 47 | 37 | * with the penalty of slow pointer chases for d-cache misses). |
|---|
| 48 | 38 | */ |
|---|
| 39 | + |
|---|
| 49 | 40 | struct pci_io_addr_range { |
|---|
| 50 | 41 | struct rb_node rb_node; |
|---|
| 51 | 42 | resource_size_t addr_lo; |
|---|
| .. | .. |
|---|
| 113 | 104 | while (n) { |
|---|
| 114 | 105 | struct pci_io_addr_range *piar; |
|---|
| 115 | 106 | piar = rb_entry(n, struct pci_io_addr_range, rb_node); |
|---|
| 116 | | - pr_debug("PCI: %s addr range %d [%pap-%pap]: %s\n", |
|---|
| 107 | + pr_info("PCI: %s addr range %d [%pap-%pap]: %s\n", |
|---|
| 117 | 108 | (piar->flags & IORESOURCE_IO) ? "i/o" : "mem", cnt, |
|---|
| 118 | 109 | &piar->addr_lo, &piar->addr_hi, pci_name(piar->pcidev)); |
|---|
| 119 | 110 | cnt++; |
|---|
| .. | .. |
|---|
| 157 | 148 | piar->pcidev = dev; |
|---|
| 158 | 149 | piar->flags = flags; |
|---|
| 159 | 150 | |
|---|
| 160 | | -#ifdef DEBUG |
|---|
| 161 | | - pr_debug("PIAR: insert range=[%pap:%pap] dev=%s\n", |
|---|
| 162 | | - &alo, &ahi, pci_name(dev)); |
|---|
| 163 | | -#endif |
|---|
| 151 | + eeh_edev_dbg(piar->edev, "PIAR: insert range=[%pap:%pap]\n", |
|---|
| 152 | + &alo, &ahi); |
|---|
| 164 | 153 | |
|---|
| 165 | 154 | rb_link_node(&piar->rb_node, parent, p); |
|---|
| 166 | 155 | rb_insert_color(&piar->rb_node, &pci_io_addr_cache_root.rb_root); |
|---|
| .. | .. |
|---|
| 170 | 159 | |
|---|
| 171 | 160 | static void __eeh_addr_cache_insert_dev(struct pci_dev *dev) |
|---|
| 172 | 161 | { |
|---|
| 173 | | - struct pci_dn *pdn; |
|---|
| 174 | 162 | struct eeh_dev *edev; |
|---|
| 175 | 163 | int i; |
|---|
| 176 | 164 | |
|---|
| 177 | | - pdn = pci_get_pdn_by_devfn(dev->bus, dev->devfn); |
|---|
| 178 | | - if (!pdn) { |
|---|
| 179 | | - pr_warn("PCI: no pci dn found for dev=%s\n", |
|---|
| 180 | | - pci_name(dev)); |
|---|
| 181 | | - return; |
|---|
| 182 | | - } |
|---|
| 183 | | - |
|---|
| 184 | | - edev = pdn_to_eeh_dev(pdn); |
|---|
| 165 | + edev = pci_dev_to_eeh_dev(dev); |
|---|
| 185 | 166 | if (!edev) { |
|---|
| 186 | 167 | pr_warn("PCI: no EEH dev found for %s\n", |
|---|
| 187 | 168 | pci_name(dev)); |
|---|
| .. | .. |
|---|
| 240 | 221 | piar = rb_entry(n, struct pci_io_addr_range, rb_node); |
|---|
| 241 | 222 | |
|---|
| 242 | 223 | if (piar->pcidev == dev) { |
|---|
| 224 | + eeh_edev_dbg(piar->edev, "PIAR: remove range=[%pap:%pap]\n", |
|---|
| 225 | + &piar->addr_lo, &piar->addr_hi); |
|---|
| 243 | 226 | rb_erase(n, &pci_io_addr_cache_root.rb_root); |
|---|
| 244 | 227 | kfree(piar); |
|---|
| 245 | 228 | goto restart; |
|---|
| .. | .. |
|---|
| 267 | 250 | } |
|---|
| 268 | 251 | |
|---|
| 269 | 252 | /** |
|---|
| 270 | | - * eeh_addr_cache_build - Build a cache of I/O addresses |
|---|
| 253 | + * eeh_addr_cache_init - Initialize a cache of I/O addresses |
|---|
| 271 | 254 | * |
|---|
| 272 | | - * Build a cache of pci i/o addresses. This cache will be used to |
|---|
| 255 | + * Initialize a cache of pci i/o addresses. This cache will be used to |
|---|
| 273 | 256 | * find the pci device that corresponds to a given address. |
|---|
| 274 | | - * This routine scans all pci busses to build the cache. |
|---|
| 275 | | - * Must be run late in boot process, after the pci controllers |
|---|
| 276 | | - * have been scanned for devices (after all device resources are known). |
|---|
| 277 | 257 | */ |
|---|
| 278 | | -void eeh_addr_cache_build(void) |
|---|
| 258 | +void eeh_addr_cache_init(void) |
|---|
| 279 | 259 | { |
|---|
| 280 | | - struct pci_dn *pdn; |
|---|
| 281 | | - struct eeh_dev *edev; |
|---|
| 282 | | - struct pci_dev *dev = NULL; |
|---|
| 283 | | - |
|---|
| 284 | 260 | spin_lock_init(&pci_io_addr_cache_root.piar_lock); |
|---|
| 261 | +} |
|---|
| 285 | 262 | |
|---|
| 286 | | - for_each_pci_dev(dev) { |
|---|
| 287 | | - pdn = pci_get_pdn_by_devfn(dev->bus, dev->devfn); |
|---|
| 288 | | - if (!pdn) |
|---|
| 289 | | - continue; |
|---|
| 263 | +static int eeh_addr_cache_show(struct seq_file *s, void *v) |
|---|
| 264 | +{ |
|---|
| 265 | + struct pci_io_addr_range *piar; |
|---|
| 266 | + struct rb_node *n; |
|---|
| 267 | + unsigned long flags; |
|---|
| 290 | 268 | |
|---|
| 291 | | - edev = pdn_to_eeh_dev(pdn); |
|---|
| 292 | | - if (!edev) |
|---|
| 293 | | - continue; |
|---|
| 269 | + spin_lock_irqsave(&pci_io_addr_cache_root.piar_lock, flags); |
|---|
| 270 | + for (n = rb_first(&pci_io_addr_cache_root.rb_root); n; n = rb_next(n)) { |
|---|
| 271 | + piar = rb_entry(n, struct pci_io_addr_range, rb_node); |
|---|
| 294 | 272 | |
|---|
| 295 | | - dev->dev.archdata.edev = edev; |
|---|
| 296 | | - edev->pdev = dev; |
|---|
| 297 | | - |
|---|
| 298 | | - eeh_addr_cache_insert_dev(dev); |
|---|
| 299 | | - eeh_sysfs_add_device(dev); |
|---|
| 273 | + seq_printf(s, "%s addr range [%pap-%pap]: %s\n", |
|---|
| 274 | + (piar->flags & IORESOURCE_IO) ? "i/o" : "mem", |
|---|
| 275 | + &piar->addr_lo, &piar->addr_hi, pci_name(piar->pcidev)); |
|---|
| 300 | 276 | } |
|---|
| 277 | + spin_unlock_irqrestore(&pci_io_addr_cache_root.piar_lock, flags); |
|---|
| 301 | 278 | |
|---|
| 302 | | -#ifdef DEBUG |
|---|
| 303 | | - /* Verify tree built up above, echo back the list of addrs. */ |
|---|
| 304 | | - eeh_addr_cache_print(&pci_io_addr_cache_root); |
|---|
| 305 | | -#endif |
|---|
| 279 | + return 0; |
|---|
| 280 | +} |
|---|
| 281 | +DEFINE_SHOW_ATTRIBUTE(eeh_addr_cache); |
|---|
| 282 | + |
|---|
| 283 | +void eeh_cache_debugfs_init(void) |
|---|
| 284 | +{ |
|---|
| 285 | + debugfs_create_file_unsafe("eeh_address_cache", 0400, |
|---|
| 286 | + powerpc_debugfs_root, NULL, |
|---|
| 287 | + &eeh_addr_cache_fops); |
|---|
| 306 | 288 | } |
|---|