Path: blob/master/arch/powerpc/platforms/pseries/eeh_cache.c
10818 views
/*1* eeh_cache.c2* PCI address cache; allows the lookup of PCI devices based on I/O address3*4* Copyright IBM Corporation 20045* Copyright Linas Vepstas <[email protected]> 20046*7* This program is free software; you can redistribute it and/or modify8* it under the terms of the GNU General Public License as published by9* the Free Software Foundation; either version 2 of the License, or10* (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 of14* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the15* GNU General Public License for more details.16*17* You should have received a copy of the GNU General Public License18* along with this program; if not, write to the Free Software19* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA20*/2122#include <linux/list.h>23#include <linux/pci.h>24#include <linux/rbtree.h>25#include <linux/slab.h>26#include <linux/spinlock.h>27#include <asm/atomic.h>28#include <asm/pci-bridge.h>29#include <asm/ppc-pci.h>303132/**33* The pci address cache subsystem. This subsystem places34* PCI device address resources into a red-black tree, sorted35* according to the address range, so that given only an i/o36* address, the corresponding PCI device can be **quickly**37* found. It is safe to perform an address lookup in an interrupt38* context; this ability is an important feature.39*40* Currently, the only customer of this code is the EEH subsystem;41* thus, this code has been somewhat tailored to suit EEH better.42* In particular, the cache does *not* hold the addresses of devices43* for which EEH is not enabled.44*45* (Implementation Note: The RB tree seems to be better/faster46* than any hash algo I could think of for this problem, even47* with the penalty of slow pointer chases for d-cache misses).48*/49struct pci_io_addr_range50{51struct rb_node rb_node;52unsigned long addr_lo;53unsigned long addr_hi;54struct pci_dev *pcidev;55unsigned int flags;56};5758static struct pci_io_addr_cache59{60struct rb_root rb_root;61spinlock_t piar_lock;62} pci_io_addr_cache_root;6364static inline struct pci_dev *__pci_get_device_by_addr(unsigned long addr)65{66struct rb_node *n = pci_io_addr_cache_root.rb_root.rb_node;6768while (n) {69struct pci_io_addr_range *piar;70piar = rb_entry(n, struct pci_io_addr_range, rb_node);7172if (addr < piar->addr_lo) {73n = n->rb_left;74} else {75if (addr > piar->addr_hi) {76n = n->rb_right;77} else {78pci_dev_get(piar->pcidev);79return piar->pcidev;80}81}82}8384return NULL;85}8687/**88* pci_get_device_by_addr - Get device, given only address89* @addr: mmio (PIO) phys address or i/o port number90*91* Given an mmio phys address, or a port number, find a pci device92* that implements this address. Be sure to pci_dev_put the device93* when finished. I/O port numbers are assumed to be offset94* from zero (that is, they do *not* have pci_io_addr added in).95* It is safe to call this function within an interrupt.96*/97struct pci_dev *pci_get_device_by_addr(unsigned long addr)98{99struct pci_dev *dev;100unsigned long flags;101102spin_lock_irqsave(&pci_io_addr_cache_root.piar_lock, flags);103dev = __pci_get_device_by_addr(addr);104spin_unlock_irqrestore(&pci_io_addr_cache_root.piar_lock, flags);105return dev;106}107108#ifdef DEBUG109/*110* Handy-dandy debug print routine, does nothing more111* than print out the contents of our addr cache.112*/113static void pci_addr_cache_print(struct pci_io_addr_cache *cache)114{115struct rb_node *n;116int cnt = 0;117118n = rb_first(&cache->rb_root);119while (n) {120struct pci_io_addr_range *piar;121piar = rb_entry(n, struct pci_io_addr_range, rb_node);122printk(KERN_DEBUG "PCI: %s addr range %d [%lx-%lx]: %s\n",123(piar->flags & IORESOURCE_IO) ? "i/o" : "mem", cnt,124piar->addr_lo, piar->addr_hi, pci_name(piar->pcidev));125cnt++;126n = rb_next(n);127}128}129#endif130131/* Insert address range into the rb tree. */132static struct pci_io_addr_range *133pci_addr_cache_insert(struct pci_dev *dev, unsigned long alo,134unsigned long ahi, unsigned int flags)135{136struct rb_node **p = &pci_io_addr_cache_root.rb_root.rb_node;137struct rb_node *parent = NULL;138struct pci_io_addr_range *piar;139140/* Walk tree, find a place to insert into tree */141while (*p) {142parent = *p;143piar = rb_entry(parent, struct pci_io_addr_range, rb_node);144if (ahi < piar->addr_lo) {145p = &parent->rb_left;146} else if (alo > piar->addr_hi) {147p = &parent->rb_right;148} else {149if (dev != piar->pcidev ||150alo != piar->addr_lo || ahi != piar->addr_hi) {151printk(KERN_WARNING "PIAR: overlapping address range\n");152}153return piar;154}155}156piar = kmalloc(sizeof(struct pci_io_addr_range), GFP_ATOMIC);157if (!piar)158return NULL;159160pci_dev_get(dev);161piar->addr_lo = alo;162piar->addr_hi = ahi;163piar->pcidev = dev;164piar->flags = flags;165166#ifdef DEBUG167printk(KERN_DEBUG "PIAR: insert range=[%lx:%lx] dev=%s\n",168alo, ahi, pci_name (dev));169#endif170171rb_link_node(&piar->rb_node, parent, p);172rb_insert_color(&piar->rb_node, &pci_io_addr_cache_root.rb_root);173174return piar;175}176177static void __pci_addr_cache_insert_device(struct pci_dev *dev)178{179struct device_node *dn;180struct pci_dn *pdn;181int i;182183dn = pci_device_to_OF_node(dev);184if (!dn) {185printk(KERN_WARNING "PCI: no pci dn found for dev=%s\n", pci_name(dev));186return;187}188189/* Skip any devices for which EEH is not enabled. */190pdn = PCI_DN(dn);191if (!(pdn->eeh_mode & EEH_MODE_SUPPORTED) ||192pdn->eeh_mode & EEH_MODE_NOCHECK) {193#ifdef DEBUG194printk(KERN_INFO "PCI: skip building address cache for=%s - %s\n",195pci_name(dev), pdn->node->full_name);196#endif197return;198}199200/* Walk resources on this device, poke them into the tree */201for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {202unsigned long start = pci_resource_start(dev,i);203unsigned long end = pci_resource_end(dev,i);204unsigned int flags = pci_resource_flags(dev,i);205206/* We are interested only bus addresses, not dma or other stuff */207if (0 == (flags & (IORESOURCE_IO | IORESOURCE_MEM)))208continue;209if (start == 0 || ~start == 0 || end == 0 || ~end == 0)210continue;211pci_addr_cache_insert(dev, start, end, flags);212}213}214215/**216* pci_addr_cache_insert_device - Add a device to the address cache217* @dev: PCI device whose I/O addresses we are interested in.218*219* In order to support the fast lookup of devices based on addresses,220* we maintain a cache of devices that can be quickly searched.221* This routine adds a device to that cache.222*/223void pci_addr_cache_insert_device(struct pci_dev *dev)224{225unsigned long flags;226227/* Ignore PCI bridges */228if ((dev->class >> 16) == PCI_BASE_CLASS_BRIDGE)229return;230231spin_lock_irqsave(&pci_io_addr_cache_root.piar_lock, flags);232__pci_addr_cache_insert_device(dev);233spin_unlock_irqrestore(&pci_io_addr_cache_root.piar_lock, flags);234}235236static inline void __pci_addr_cache_remove_device(struct pci_dev *dev)237{238struct rb_node *n;239240restart:241n = rb_first(&pci_io_addr_cache_root.rb_root);242while (n) {243struct pci_io_addr_range *piar;244piar = rb_entry(n, struct pci_io_addr_range, rb_node);245246if (piar->pcidev == dev) {247rb_erase(n, &pci_io_addr_cache_root.rb_root);248pci_dev_put(piar->pcidev);249kfree(piar);250goto restart;251}252n = rb_next(n);253}254}255256/**257* pci_addr_cache_remove_device - remove pci device from addr cache258* @dev: device to remove259*260* Remove a device from the addr-cache tree.261* This is potentially expensive, since it will walk262* the tree multiple times (once per resource).263* But so what; device removal doesn't need to be that fast.264*/265void pci_addr_cache_remove_device(struct pci_dev *dev)266{267unsigned long flags;268269spin_lock_irqsave(&pci_io_addr_cache_root.piar_lock, flags);270__pci_addr_cache_remove_device(dev);271spin_unlock_irqrestore(&pci_io_addr_cache_root.piar_lock, flags);272}273274/**275* pci_addr_cache_build - Build a cache of I/O addresses276*277* Build a cache of pci i/o addresses. This cache will be used to278* find the pci device that corresponds to a given address.279* This routine scans all pci busses to build the cache.280* Must be run late in boot process, after the pci controllers281* have been scanned for devices (after all device resources are known).282*/283void __init pci_addr_cache_build(void)284{285struct device_node *dn;286struct pci_dev *dev = NULL;287288spin_lock_init(&pci_io_addr_cache_root.piar_lock);289290for_each_pci_dev(dev) {291pci_addr_cache_insert_device(dev);292293dn = pci_device_to_OF_node(dev);294if (!dn)295continue;296pci_dev_get(dev); /* matching put is in eeh_remove_device() */297PCI_DN(dn)->pcidev = dev;298299eeh_sysfs_add_device(dev);300}301302#ifdef DEBUG303/* Verify tree built up above, echo back the list of addrs. */304pci_addr_cache_print(&pci_io_addr_cache_root);305#endif306}307308309310