Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  1 /*
  2  * ACPI PCI HotPlug PCI configuration space management
  3  *
  4  * Copyright (C) 1995,2001 Compaq Computer Corporation
  5  * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
  6  * Copyright (C) 2001,2002 IBM Corp.
  7  * Copyright (C) 2002 Takayoshi Kochi (t-kochi@bq.jp.nec.com)
  8  * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
  9  * Copyright (C) 2002 NEC Corporation
 10  *
 11  * All rights reserved.
 12  *
 13  * This program is free software; you can redistribute it and/or modify
 14  * it under the terms of the GNU General Public License as published by
 15  * the Free Software Foundation; either version 2 of the License, or (at
 16  * your option) any later version.
 17  *
 18  * This program is distributed in the hope that it will be useful, but
 19  * WITHOUT ANY WARRANTY; without even the implied warranty of
 20  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
 21  * NON INFRINGEMENT.  See the GNU General Public License for more
 22  * details.
 23  *
 24  * You should have received a copy of the GNU General Public License
 25  * along with this program; if not, write to the Free Software
 26  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 27  *
 28  * Send feedback to <t-kochi@bq.jp.nec.com>
 29  *
 30  */
 31 
 32 #include <linux/init.h>
 33 #include <linux/module.h>
 34 
 35 #include <linux/kernel.h>
 36 #include <linux/pci.h>
 37 #include <linux/acpi.h>
 38 #include "../pci.h"
 39 #include "pci_hotplug.h"
 40 #include "acpiphp.h"
 41 
 42 #define MY_NAME "acpiphp_pci"
 43 
 44 
 45 /* allocate mem/pmem/io resource to a new function */
 46 static int init_config_space (struct acpiphp_func *func)
 47 {
 48         u32 bar, len;
 49         u32 address[] = {
 50                 PCI_BASE_ADDRESS_0,
 51                 PCI_BASE_ADDRESS_1,
 52                 PCI_BASE_ADDRESS_2,
 53                 PCI_BASE_ADDRESS_3,
 54                 PCI_BASE_ADDRESS_4,
 55                 PCI_BASE_ADDRESS_5,
 56                 0
 57         };
 58         int count;
 59         struct acpiphp_bridge *bridge;
 60         struct pci_resource *res;
 61         struct pci_bus *pbus;
 62         int bus, device, function;
 63         unsigned int devfn;
 64         u16 tmp;
 65 
 66         bridge = func->slot->bridge;
 67         pbus = bridge->pci_bus;
 68         bus = bridge->bus;
 69         device = func->slot->device;
 70         function = func->function;
 71         devfn = PCI_DEVFN(device, function);
 72 
 73         for (count = 0; address[count]; count++) {      /* for 6 BARs */
 74                 pci_bus_write_config_dword(pbus, devfn,
 75                                            address[count], 0xFFFFFFFF);
 76                 pci_bus_read_config_dword(pbus, devfn, address[count], &bar);
 77 
 78                 if (!bar)       /* This BAR is not implemented */
 79                         continue;
 80 
 81                 dbg("Device %02x.%02x BAR %d wants %x\n", device, function, count, bar);
 82 
 83                 if (bar & PCI_BASE_ADDRESS_SPACE_IO) {
 84                         /* This is IO */
 85 
 86                         len = bar & (PCI_BASE_ADDRESS_IO_MASK & 0xFFFF);
 87                         len = len & ~(len - 1);
 88 
 89                         dbg("len in IO %x, BAR %d\n", len, count);
 90 
 91                         spin_lock(&bridge->res_lock);
 92                         res = acpiphp_get_io_resource(&bridge->io_head, len);
 93                         spin_unlock(&bridge->res_lock);
 94 
 95                         if (!res) {
 96                                 err("cannot allocate requested io for %02x:%02x.%d len %x\n",
 97                                     bus, device, function, len);
 98                                 return -1;
 99                         }
100                         pci_bus_write_config_dword(pbus, devfn,
101                                                    address[count],
102                                                    (u32)res->base);
103                         res->next = func->io_head;
104                         func->io_head = res;
105 
106                 } else {
107                         /* This is Memory */
108                         if (bar & PCI_BASE_ADDRESS_MEM_PREFETCH) {
109                                 /* pfmem */
110 
111                                 len = bar & 0xFFFFFFF0;
112                                 len = ~len + 1;
113 
114                                 dbg("len in PFMEM %x, BAR %d\n", len, count);
115 
116                                 spin_lock(&bridge->res_lock);
117                                 res = acpiphp_get_resource(&bridge->p_mem_head, len);
118                                 spin_unlock(&bridge->res_lock);
119 
120                                 if (!res) {
121                                         err("cannot allocate requested pfmem for %02x:%02x.%d len %x\n",
122                                             bus, device, function, len);
123                                         return -1;
124                                 }
125 
126                                 pci_bus_write_config_dword(pbus, devfn,
127                                                            address[count],
128                                                            (u32)res->base);
129 
130                                 if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) {       /* takes up another dword */
131                                         dbg("inside the pfmem 64 case, count %d\n", count);
132                                         count += 1;
133                                         pci_bus_write_config_dword(pbus, devfn,
134                                                                    address[count],
135                                                                    (u32)(res->base >> 32));
136                                 }
137 
138                                 res->next = func->p_mem_head;
139                                 func->p_mem_head = res;
140 
141                         } else {
142                                 /* regular memory */
143 
144                                 len = bar & 0xFFFFFFF0;
145                                 len = ~len + 1;
146 
147                                 dbg("len in MEM %x, BAR %d\n", len, count);
148 
149                                 spin_lock(&bridge->res_lock);
150                                 res = acpiphp_get_resource(&bridge->mem_head, len);
151                                 spin_unlock(&bridge->res_lock);
152 
153                                 if (!res) {
154                                         err("cannot allocate requested pfmem for %02x:%02x.%d len %x\n",
155                                             bus, device, function, len);
156                                         return -1;
157                                 }
158 
159                                 pci_bus_write_config_dword(pbus, devfn,
160                                                            address[count],
161                                                            (u32)res->base);
162 
163                                 if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) {
164                                         /* takes up another dword */
165                                         dbg("inside mem 64 case, reg. mem, count %d\n", count);
166                                         count += 1;
167                                         pci_bus_write_config_dword(pbus, devfn,
168                                                                    address[count],
169                                                                    (u32)(res->base >> 32));
170                                 }
171 
172                                 res->next = func->mem_head;
173                                 func->mem_head = res;
174 
175                         }
176                 }
177         }
178 
179         /* disable expansion rom */
180         pci_bus_write_config_dword(pbus, devfn, PCI_ROM_ADDRESS, 0x00000000);
181 
182         /* set PCI parameters from _HPP */
183         pci_bus_write_config_byte(pbus, devfn, PCI_CACHE_LINE_SIZE,
184                                   bridge->hpp.cache_line_size);
185         pci_bus_write_config_byte(pbus, devfn, PCI_LATENCY_TIMER,
186                                   bridge->hpp.latency_timer);
187 
188         pci_bus_read_config_word(pbus, devfn, PCI_COMMAND, &tmp);
189         if (bridge->hpp.enable_SERR)
190                 tmp |= PCI_COMMAND_SERR;
191         if (bridge->hpp.enable_PERR)
192                 tmp |= PCI_COMMAND_PARITY;
193         pci_bus_write_config_word(pbus, devfn, PCI_COMMAND, tmp);
194 
195         return 0;
196 }
197 
198 /* detect_used_resource - subtract resource under dev from bridge */
199 static int detect_used_resource (struct acpiphp_bridge *bridge, struct pci_dev *dev)
200 {
201         int count;
202 
203         dbg("Device %s\n", pci_name(dev));
204 
205         for (count = 0; count < DEVICE_COUNT_RESOURCE; count++) {
206                 struct pci_resource *res;
207                 struct pci_resource **head;
208                 unsigned long base = dev->resource[count].start;
209                 unsigned long len = dev->resource[count].end - base + 1;
210                 unsigned long flags = dev->resource[count].flags;
211 
212                 if (!flags)
213                         continue;
214 
215                 dbg("BAR[%d] 0x%lx - 0x%lx (0x%lx)\n", count, base,
216                                 base + len - 1, flags);
217 
218                 if (flags & IORESOURCE_IO) {
219                         head = &bridge->io_head;
220                 } else if (flags & IORESOURCE_PREFETCH) {
221                         head = &bridge->p_mem_head;
222                 } else {
223                         head = &bridge->mem_head;
224                 }
225 
226                 spin_lock(&bridge->res_lock);
227                 res = acpiphp_get_resource_with_base(head, base, len);
228                 spin_unlock(&bridge->res_lock);
229                 if (res)
230                         kfree(res);
231         }
232 
233         return 0;
234 }
235 
236 
237 /**
238  * acpiphp_detect_pci_resource - detect resources under bridge
239  * @bridge: detect all resources already used under this bridge
240  *
241  * collect all resources already allocated for all devices under a bridge.
242  */
243 int acpiphp_detect_pci_resource (struct acpiphp_bridge *bridge)
244 {
245         struct list_head *l;
246         struct pci_dev *dev;
247 
248         list_for_each (l, &bridge->pci_bus->devices) {
249                 dev = pci_dev_b(l);
250                 detect_used_resource(bridge, dev);
251         }
252 
253         return 0;
254 }
255 
256 
257 /**
258  * acpiphp_init_slot_resource - gather resource usage information of a slot
259  * @slot: ACPI slot object to be checked, should have valid pci_dev member
260  *
261  * TBD: PCI-to-PCI bridge case
262  *      use pci_dev->resource[]
263  */
264 int acpiphp_init_func_resource (struct acpiphp_func *func)
265 {
266         u64 base;
267         u32 bar, len;
268         u32 address[] = {
269                 PCI_BASE_ADDRESS_0,
270                 PCI_BASE_ADDRESS_1,
271                 PCI_BASE_ADDRESS_2,
272                 PCI_BASE_ADDRESS_3,
273                 PCI_BASE_ADDRESS_4,
274                 PCI_BASE_ADDRESS_5,
275                 0
276         };
277         int count;
278         struct pci_resource *res;
279         struct pci_dev *dev;
280 
281         dev = func->pci_dev;
282         dbg("Hot-pluggable device %s\n", pci_name(dev));
283 
284         for (count = 0; address[count]; count++) {      /* for 6 BARs */
285                 pci_read_config_dword(dev, address[count], &bar);
286 
287                 if (!bar)       /* This BAR is not implemented */
288                         continue;
289 
290                 pci_write_config_dword(dev, address[count], 0xFFFFFFFF);
291                 pci_read_config_dword(dev, address[count], &len);
292 
293                 if (len & PCI_BASE_ADDRESS_SPACE_IO) {
294                         /* This is IO */
295                         base = bar & 0xFFFFFFFC;
296                         len = len & (PCI_BASE_ADDRESS_IO_MASK & 0xFFFF);
297                         len = len & ~(len - 1);
298 
299                         dbg("BAR[%d] %08x - %08x (IO)\n", count, (u32)base, (u32)base + len - 1);
300 
301                         res = acpiphp_make_resource(base, len);
302                         if (!res)
303                                 goto no_memory;
304 
305                         res->next = func->io_head;
306                         func->io_head = res;
307 
308                 } else {
309                         /* This is Memory */
310                         base = bar & 0xFFFFFFF0;
311                         if (len & PCI_BASE_ADDRESS_MEM_PREFETCH) {
312                                 /* pfmem */
313 
314                                 len &= 0xFFFFFFF0;
315                                 len = ~len + 1;
316 
317                                 if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) {       /* takes up another dword */
318                                         dbg("prefetch mem 64\n");
319                                         count += 1;
320                                 }
321                                 dbg("BAR[%d] %08x - %08x (PMEM)\n", count, (u32)base, (u32)base + len - 1);
322                                 res = acpiphp_make_resource(base, len);
323                                 if (!res)
324                                         goto no_memory;
325 
326                                 res->next = func->p_mem_head;
327                                 func->p_mem_head = res;
328 
329                         } else {
330                                 /* regular memory */
331 
332                                 len &= 0xFFFFFFF0;
333                                 len = ~len + 1;
334 
335                                 if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) {
336                                         /* takes up another dword */
337                                         dbg("mem 64\n");
338                                         count += 1;
339                                 }
340                                 dbg("BAR[%d] %08x - %08x (MEM)\n", count, (u32)base, (u32)base + len - 1);
341                                 res = acpiphp_make_resource(base, len);
342                                 if (!res)
343                                         goto no_memory;
344 
345                                 res->next = func->mem_head;
346                                 func->mem_head = res;
347 
348                         }
349                 }
350 
351                 pci_write_config_dword(dev, address[count], bar);
352         }
353 #if 1
354         acpiphp_dump_func_resource(func);
355 #endif
356 
357         return 0;
358 
359  no_memory:
360         err("out of memory\n");
361         acpiphp_free_resource(&func->io_head);
362         acpiphp_free_resource(&func->mem_head);
363         acpiphp_free_resource(&func->p_mem_head);
364 
365         return -1;
366 }
367 
368 
369 /**
370  * acpiphp_configure_slot - allocate PCI resources
371  * @slot: slot to be configured
372  *
373  * initializes a PCI functions on a device inserted
374  * into the slot
375  *
376  */
377 int acpiphp_configure_slot (struct acpiphp_slot *slot)
378 {
379         struct acpiphp_func *func;
380         struct list_head *l;
381         u8 hdr;
382         u32 dvid;
383         int retval = 0;
384         int is_multi = 0;
385 
386         pci_bus_read_config_byte(slot->bridge->pci_bus,
387                                  PCI_DEVFN(slot->device, 0),
388                                  PCI_HEADER_TYPE, &hdr);
389 
390         if (hdr & 0x80)
391                 is_multi = 1;
392 
393         list_for_each (l, &slot->funcs) {
394                 func = list_entry(l, struct acpiphp_func, sibling);
395                 if (is_multi || func->function == 0) {
396                         pci_bus_read_config_dword(slot->bridge->pci_bus,
397                                                   PCI_DEVFN(slot->device,
398                                                             func->function),
399                                                   PCI_VENDOR_ID, &dvid);
400                         if (dvid != 0xffffffff) {
401                                 retval = init_config_space(func);
402                                 if (retval)
403                                         break;
404                         }
405                 }
406         }
407 
408         return retval;
409 }
410 
411 /**
412  * acpiphp_configure_function - configure PCI function
413  * @func: function to be configured
414  *
415  * initializes a PCI functions on a device inserted
416  * into the slot
417  *
418  */
419 int acpiphp_configure_function (struct acpiphp_func *func)
420 {
421         /* all handled by the pci core now */
422         return 0;
423 }
424 
425 /**
426  * acpiphp_unconfigure_function - unconfigure PCI function
427  * @func: function to be unconfigured
428  *
429  */
430 void acpiphp_unconfigure_function (struct acpiphp_func *func)
431 {
432         struct acpiphp_bridge *bridge;
433 
434         /* if pci_dev is NULL, ignore it */
435         if (!func->pci_dev)
436                 return;
437 
438         pci_remove_bus_device(func->pci_dev);
439 
440         /* free all resources */
441         bridge = func->slot->bridge;
442 
443         spin_lock(&bridge->res_lock);
444         acpiphp_move_resource(&func->io_head, &bridge->io_head);
445         acpiphp_move_resource(&func->mem_head, &bridge->mem_head);
446         acpiphp_move_resource(&func->p_mem_head, &bridge->p_mem_head);
447         acpiphp_move_resource(&func->bus_head, &bridge->bus_head);
448         spin_unlock(&bridge->res_lock);
449 }
450 
  This page was automatically generated by the LXR engine.