~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/ppc64/kernel/pci_dn.c

Version: ~ [ linux-5.8 ] ~ [ linux-5.7.12 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.55 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.136 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.191 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.232 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.232 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.85 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * pci_dn.c
  3  *
  4  * Copyright (C) 2001 Todd Inglett, IBM Corporation
  5  *
  6  * PCI manipulation via device_nodes.
  7  *
  8  * This program is free software; you can redistribute it and/or modify
  9  * it under the terms of the GNU General Public License as published by
 10  * the Free Software Foundation; either version 2 of the License, or
 11  * (at your option) any later version.
 12  *    
 13  * This program is distributed in the hope that it will be useful,
 14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 16  * GNU General Public License for more details.
 17  * 
 18  * You should have received a copy of the GNU General Public License
 19  * along with this program; if not, write to the Free Software
 20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 21  */
 22 
 23 #include <linux/config.h>
 24 #include <linux/kernel.h>
 25 #include <linux/pci.h>
 26 #include <linux/delay.h>
 27 #include <linux/string.h>
 28 #include <linux/init.h>
 29 #include <linux/bootmem.h>
 30 
 31 #include <asm/io.h>
 32 #include <asm/pgtable.h>
 33 #include <asm/irq.h>
 34 #include <asm/prom.h>
 35 #include <asm/machdep.h>
 36 #include <asm/pci-bridge.h>
 37 #include <asm/ppcdebug.h>
 38 #include <asm/naca.h>
 39 #include <asm/pci_dma.h>
 40 
 41 #include "pci.h"
 42 
 43 /* Traverse_func that inits the PCI fields of the device node.
 44  * NOTE: this *must* be done before read/write config to the device.
 45  */
 46 static void * __init
 47 update_dn_pci_info(struct device_node *dn, void *data)
 48 {
 49         struct pci_controller *phb = (struct pci_controller *)data;
 50         u32 *regs;
 51         char *device_type = get_property(dn, "device_type", 0);
 52 
 53         dn->phb = phb;
 54         if (device_type && strcmp(device_type, "pci") == 0 && get_property(dn, "class-code", 0) == 0) {
 55                 /* special case for PHB's.  Sigh. */
 56                 regs = (u32 *)get_property(dn, "bus-range", 0);
 57                 dn->busno = regs[0];
 58                 dn->devfn = 0;  /* assumption */
 59         } else {
 60                 regs = (u32 *)get_property(dn, "reg", 0);
 61                 if (regs) {
 62                         /* First register entry is addr (00BBSS00)  */
 63                         dn->busno = (regs[0] >> 16) & 0xff;
 64                         dn->devfn = (regs[0] >> 8) & 0xff;
 65                 }
 66         }
 67         return NULL;
 68 }
 69 
 70 /******************************************************************
 71  * Traverse a device tree stopping each PCI device in the tree.
 72  * This is done depth first.  As each node is processed, a "pre"
 73  * function is called, the children are processed recursively, and
 74  * then a "post" function is called.
 75  *
 76  * The "pre" and "post" funcs return a value.  If non-zero
 77  * is returned from the "pre" func, the traversal stops and this
 78  * value is returned.  The return value from "post" is not used.
 79  * This return value is useful when using traverse as
 80  * a method of finding a device.
 81  *
 82  * NOTE: we do not run the funcs for devices that do not appear to
 83  * be PCI except for the start node which we assume (this is good
 84  * because the start node is often a phb which may be missing PCI
 85  * properties).
 86  * We use the class-code as an indicator. If we run into
 87  * one of these nodes we also assume its siblings are non-pci for
 88  * performance.
 89  *
 90  ******************************************************************/
 91 void *traverse_pci_devices(struct device_node *start, traverse_func pre, traverse_func post, void *data)
 92 {
 93         struct device_node *dn, *nextdn;
 94         void *ret;
 95 
 96         if (pre && (ret = pre(start, data)) != NULL)
 97                 return ret;
 98         for (dn = start->child; dn; dn = nextdn) {
 99                 nextdn = NULL;
100                 if (get_property(dn, "class-code", 0)) {
101                         if (pre && (ret = pre(dn, data)) != NULL)
102                                 return ret;
103                         if (dn->child) {
104                                 /* Depth first...do children */
105                                 nextdn = dn->child;
106                         } else if (dn->sibling) {
107                                 /* ok, try next sibling instead. */
108                                 nextdn = dn->sibling;
109                         } else {
110                                 /* no more children or siblings...call "post" */
111                                 if (post)
112                                         post(dn, data);
113                         }
114                 }
115                 if (!nextdn) {
116                         /* Walk up to next valid sibling. */
117                         do {
118                                 dn = dn->parent;
119                                 if (dn == start)
120                                         return NULL;
121                         } while (dn->sibling == NULL);
122                         nextdn = dn->sibling;
123                 }
124         }
125         return NULL;
126 }
127 
128 /* Same as traverse_pci_devices except this does it for all phbs.
129  */
130 void *traverse_all_pci_devices(traverse_func pre)
131 {
132         struct pci_controller* phb;
133         void *ret;
134         for (phb=hose_head;phb;phb=phb->next)
135                 if ((ret = traverse_pci_devices((struct device_node *)phb->arch_data, pre, NULL, phb)) != NULL)
136                         return ret;
137         return NULL;
138 }
139 
140 
141 /* Traversal func that looks for a <busno,devfcn> value.
142  * If found, the device_node is returned (thus terminating the traversal).
143  */
144 static void *
145 is_devfn_node(struct device_node *dn, void *data)
146 {
147         int busno = ((unsigned long)data >> 8) & 0xff;
148         int devfn = ((unsigned long)data) & 0xff;
149         return (devfn == dn->devfn && busno == dn->busno) ? dn : NULL;
150 }
151 
152 /* This is the "slow" path for looking up a device_node from a
153  * pci_dev.  It will hunt for the device under its parent's
154  * phb and then update sysdata for a future fastpath.
155  *
156  * It may also do fixups on the actual device since this happens
157  * on the first read/write.
158  *
159  * Note that it also must deal with devices that don't exist.
160  * In this case it may probe for real hardware ("just in case")
161  * and add a device_node to the device tree if necessary.
162  *
163  */
164 struct device_node *fetch_dev_dn(struct pci_dev *dev)
165 {
166         struct device_node *orig_dn = (struct device_node *)dev->sysdata;
167         struct pci_controller *phb = orig_dn->phb; /* assume same phb as orig_dn */
168         struct device_node *phb_dn;
169         struct device_node *dn;
170         unsigned long searchval = (dev->bus->number << 8) | dev->devfn;
171 
172         phb_dn = (struct device_node *)(phb->arch_data);
173         dn = (struct device_node *)traverse_pci_devices(phb_dn, is_devfn_node, NULL, (void *)searchval);
174         if (dn) {
175                 dev->sysdata = dn;
176                 /* ToDo: call some device init hook here */
177         }
178         return dn;
179 }
180 
181 
182 /******************************************************************
183  * Actually initialize the phbs.
184  * The buswalk on this phb has not happened yet.
185  ******************************************************************/
186 void __init
187 pci_devs_phb_init(void)
188 {
189         /* This must be done first so the device nodes have valid pci info! */
190         traverse_all_pci_devices(update_dn_pci_info);
191 }
192 
193 
194 static void __init
195 pci_fixup_bus_sysdata_list(struct list_head *bus_list)
196 {
197         struct list_head *ln;
198         struct pci_bus *bus;
199 
200         for (ln=bus_list->next; ln != bus_list; ln=ln->next) {
201                 bus = pci_bus_b(ln);
202                 if (bus->self)
203                         bus->sysdata = bus->self->sysdata;
204                 pci_fixup_bus_sysdata_list(&bus->children);
205         }
206 }
207 
208 /******************************************************************
209  * Fixup the bus->sysdata ptrs to point to the bus' device_node.
210  * This is done late in pcibios_init().  We do this mostly for
211  * sanity, but pci_dma.c uses these at DMA time so they must be
212  * correct.
213  * To do this we recurse down the bus hierarchy.  Note that PHB's
214  * have bus->self == NULL, but fortunately bus->sysdata is already
215  * correct in this case.
216  ******************************************************************/
217 void __init
218 pci_fix_bus_sysdata(void)
219 {
220         pci_fixup_bus_sysdata_list(&pci_root_buses);
221 }
222 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp