| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | *	$Id: pci.c,v 1.91 1999/01/21 13:34:01 davem Exp $ | 
|  | 3 | * | 
|  | 4 | *	PCI Bus Services, see include/linux/pci.h for further explanation. | 
|  | 5 | * | 
|  | 6 | *	Copyright 1993 -- 1997 Drew Eckhardt, Frederic Potter, | 
|  | 7 | *	David Mosberger-Tang | 
|  | 8 | * | 
|  | 9 | *	Copyright 1997 -- 2000 Martin Mares <mj@ucw.cz> | 
|  | 10 | */ | 
|  | 11 |  | 
|  | 12 | #include <linux/kernel.h> | 
|  | 13 | #include <linux/delay.h> | 
|  | 14 | #include <linux/init.h> | 
|  | 15 | #include <linux/pci.h> | 
|  | 16 | #include <linux/module.h> | 
|  | 17 | #include <linux/spinlock.h> | 
| Tim Schmielau | 4e57b68 | 2005-10-30 15:03:48 -0800 | [diff] [blame] | 18 | #include <linux/string.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 19 | #include <asm/dma.h>	/* isa_dma_bridge_buggy */ | 
| Greg KH | bc56b9e | 2005-04-08 14:53:31 +0900 | [diff] [blame] | 20 | #include "pci.h" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 21 |  | 
| Kristen Carlson Accardi | ffadcc2 | 2006-07-12 08:59:00 -0700 | [diff] [blame] | 22 | unsigned int pci_pm_d3_delay = 10; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 23 |  | 
| Atsushi Nemoto | 4516a61 | 2007-02-05 16:36:06 -0800 | [diff] [blame] | 24 | #define DEFAULT_CARDBUS_IO_SIZE		(256) | 
|  | 25 | #define DEFAULT_CARDBUS_MEM_SIZE	(64*1024*1024) | 
|  | 26 | /* pci=cbmemsize=nnM,cbiosize=nn can override this */ | 
|  | 27 | unsigned long pci_cardbus_io_size = DEFAULT_CARDBUS_IO_SIZE; | 
|  | 28 | unsigned long pci_cardbus_mem_size = DEFAULT_CARDBUS_MEM_SIZE; | 
|  | 29 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 30 | /** | 
|  | 31 | * pci_bus_max_busnr - returns maximum PCI bus number of given bus' children | 
|  | 32 | * @bus: pointer to PCI bus structure to search | 
|  | 33 | * | 
|  | 34 | * Given a PCI bus, returns the highest PCI bus number present in the set | 
|  | 35 | * including the given PCI bus and its list of child PCI buses. | 
|  | 36 | */ | 
|  | 37 | unsigned char __devinit | 
|  | 38 | pci_bus_max_busnr(struct pci_bus* bus) | 
|  | 39 | { | 
|  | 40 | struct list_head *tmp; | 
|  | 41 | unsigned char max, n; | 
|  | 42 |  | 
| Kristen Accardi | b82db5c | 2006-01-17 16:56:56 -0800 | [diff] [blame] | 43 | max = bus->subordinate; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 44 | list_for_each(tmp, &bus->children) { | 
|  | 45 | n = pci_bus_max_busnr(pci_bus_b(tmp)); | 
|  | 46 | if(n > max) | 
|  | 47 | max = n; | 
|  | 48 | } | 
|  | 49 | return max; | 
|  | 50 | } | 
| Kristen Accardi | b82db5c | 2006-01-17 16:56:56 -0800 | [diff] [blame] | 51 | EXPORT_SYMBOL_GPL(pci_bus_max_busnr); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 52 |  | 
| Kristen Accardi | b82db5c | 2006-01-17 16:56:56 -0800 | [diff] [blame] | 53 | #if 0 | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 54 | /** | 
|  | 55 | * pci_max_busnr - returns maximum PCI bus number | 
|  | 56 | * | 
|  | 57 | * Returns the highest PCI bus number present in the system global list of | 
|  | 58 | * PCI buses. | 
|  | 59 | */ | 
|  | 60 | unsigned char __devinit | 
|  | 61 | pci_max_busnr(void) | 
|  | 62 | { | 
|  | 63 | struct pci_bus *bus = NULL; | 
|  | 64 | unsigned char max, n; | 
|  | 65 |  | 
|  | 66 | max = 0; | 
|  | 67 | while ((bus = pci_find_next_bus(bus)) != NULL) { | 
|  | 68 | n = pci_bus_max_busnr(bus); | 
|  | 69 | if(n > max) | 
|  | 70 | max = n; | 
|  | 71 | } | 
|  | 72 | return max; | 
|  | 73 | } | 
|  | 74 |  | 
| Adrian Bunk | 54c762f | 2005-12-22 01:08:52 +0100 | [diff] [blame] | 75 | #endif  /*  0  */ | 
|  | 76 |  | 
| Michael Ellerman | 687d5fe | 2006-11-22 18:26:18 +1100 | [diff] [blame] | 77 | #define PCI_FIND_CAP_TTL	48 | 
|  | 78 |  | 
|  | 79 | static int __pci_find_next_cap_ttl(struct pci_bus *bus, unsigned int devfn, | 
|  | 80 | u8 pos, int cap, int *ttl) | 
| Roland Dreier | 24a4e37 | 2005-10-28 17:35:34 -0700 | [diff] [blame] | 81 | { | 
|  | 82 | u8 id; | 
| Roland Dreier | 24a4e37 | 2005-10-28 17:35:34 -0700 | [diff] [blame] | 83 |  | 
| Michael Ellerman | 687d5fe | 2006-11-22 18:26:18 +1100 | [diff] [blame] | 84 | while ((*ttl)--) { | 
| Roland Dreier | 24a4e37 | 2005-10-28 17:35:34 -0700 | [diff] [blame] | 85 | pci_bus_read_config_byte(bus, devfn, pos, &pos); | 
|  | 86 | if (pos < 0x40) | 
|  | 87 | break; | 
|  | 88 | pos &= ~3; | 
|  | 89 | pci_bus_read_config_byte(bus, devfn, pos + PCI_CAP_LIST_ID, | 
|  | 90 | &id); | 
|  | 91 | if (id == 0xff) | 
|  | 92 | break; | 
|  | 93 | if (id == cap) | 
|  | 94 | return pos; | 
|  | 95 | pos += PCI_CAP_LIST_NEXT; | 
|  | 96 | } | 
|  | 97 | return 0; | 
|  | 98 | } | 
|  | 99 |  | 
| Michael Ellerman | 687d5fe | 2006-11-22 18:26:18 +1100 | [diff] [blame] | 100 | static int __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn, | 
|  | 101 | u8 pos, int cap) | 
|  | 102 | { | 
|  | 103 | int ttl = PCI_FIND_CAP_TTL; | 
|  | 104 |  | 
|  | 105 | return __pci_find_next_cap_ttl(bus, devfn, pos, cap, &ttl); | 
|  | 106 | } | 
|  | 107 |  | 
| Roland Dreier | 24a4e37 | 2005-10-28 17:35:34 -0700 | [diff] [blame] | 108 | int pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap) | 
|  | 109 | { | 
|  | 110 | return __pci_find_next_cap(dev->bus, dev->devfn, | 
|  | 111 | pos + PCI_CAP_LIST_NEXT, cap); | 
|  | 112 | } | 
|  | 113 | EXPORT_SYMBOL_GPL(pci_find_next_capability); | 
|  | 114 |  | 
| Michael Ellerman | d3bac118 | 2006-11-22 18:26:16 +1100 | [diff] [blame] | 115 | static int __pci_bus_find_cap_start(struct pci_bus *bus, | 
|  | 116 | unsigned int devfn, u8 hdr_type) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 117 | { | 
|  | 118 | u16 status; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 119 |  | 
|  | 120 | pci_bus_read_config_word(bus, devfn, PCI_STATUS, &status); | 
|  | 121 | if (!(status & PCI_STATUS_CAP_LIST)) | 
|  | 122 | return 0; | 
|  | 123 |  | 
|  | 124 | switch (hdr_type) { | 
|  | 125 | case PCI_HEADER_TYPE_NORMAL: | 
|  | 126 | case PCI_HEADER_TYPE_BRIDGE: | 
| Michael Ellerman | d3bac118 | 2006-11-22 18:26:16 +1100 | [diff] [blame] | 127 | return PCI_CAPABILITY_LIST; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 128 | case PCI_HEADER_TYPE_CARDBUS: | 
| Michael Ellerman | d3bac118 | 2006-11-22 18:26:16 +1100 | [diff] [blame] | 129 | return PCI_CB_CAPABILITY_LIST; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 130 | default: | 
|  | 131 | return 0; | 
|  | 132 | } | 
| Michael Ellerman | d3bac118 | 2006-11-22 18:26:16 +1100 | [diff] [blame] | 133 |  | 
|  | 134 | return 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 135 | } | 
|  | 136 |  | 
|  | 137 | /** | 
|  | 138 | * pci_find_capability - query for devices' capabilities | 
|  | 139 | * @dev: PCI device to query | 
|  | 140 | * @cap: capability code | 
|  | 141 | * | 
|  | 142 | * Tell if a device supports a given PCI capability. | 
|  | 143 | * Returns the address of the requested capability structure within the | 
|  | 144 | * device's PCI configuration space or 0 in case the device does not | 
|  | 145 | * support it.  Possible values for @cap: | 
|  | 146 | * | 
|  | 147 | *  %PCI_CAP_ID_PM           Power Management | 
|  | 148 | *  %PCI_CAP_ID_AGP          Accelerated Graphics Port | 
|  | 149 | *  %PCI_CAP_ID_VPD          Vital Product Data | 
|  | 150 | *  %PCI_CAP_ID_SLOTID       Slot Identification | 
|  | 151 | *  %PCI_CAP_ID_MSI          Message Signalled Interrupts | 
|  | 152 | *  %PCI_CAP_ID_CHSWP        CompactPCI HotSwap | 
|  | 153 | *  %PCI_CAP_ID_PCIX         PCI-X | 
|  | 154 | *  %PCI_CAP_ID_EXP          PCI Express | 
|  | 155 | */ | 
|  | 156 | int pci_find_capability(struct pci_dev *dev, int cap) | 
|  | 157 | { | 
| Michael Ellerman | d3bac118 | 2006-11-22 18:26:16 +1100 | [diff] [blame] | 158 | int pos; | 
|  | 159 |  | 
|  | 160 | pos = __pci_bus_find_cap_start(dev->bus, dev->devfn, dev->hdr_type); | 
|  | 161 | if (pos) | 
|  | 162 | pos = __pci_find_next_cap(dev->bus, dev->devfn, pos, cap); | 
|  | 163 |  | 
|  | 164 | return pos; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 165 | } | 
|  | 166 |  | 
|  | 167 | /** | 
|  | 168 | * pci_bus_find_capability - query for devices' capabilities | 
|  | 169 | * @bus:   the PCI bus to query | 
|  | 170 | * @devfn: PCI device to query | 
|  | 171 | * @cap:   capability code | 
|  | 172 | * | 
|  | 173 | * Like pci_find_capability() but works for pci devices that do not have a | 
|  | 174 | * pci_dev structure set up yet. | 
|  | 175 | * | 
|  | 176 | * Returns the address of the requested capability structure within the | 
|  | 177 | * device's PCI configuration space or 0 in case the device does not | 
|  | 178 | * support it. | 
|  | 179 | */ | 
|  | 180 | int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap) | 
|  | 181 | { | 
| Michael Ellerman | d3bac118 | 2006-11-22 18:26:16 +1100 | [diff] [blame] | 182 | int pos; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 183 | u8 hdr_type; | 
|  | 184 |  | 
|  | 185 | pci_bus_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &hdr_type); | 
|  | 186 |  | 
| Michael Ellerman | d3bac118 | 2006-11-22 18:26:16 +1100 | [diff] [blame] | 187 | pos = __pci_bus_find_cap_start(bus, devfn, hdr_type & 0x7f); | 
|  | 188 | if (pos) | 
|  | 189 | pos = __pci_find_next_cap(bus, devfn, pos, cap); | 
|  | 190 |  | 
|  | 191 | return pos; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 192 | } | 
|  | 193 |  | 
|  | 194 | /** | 
|  | 195 | * pci_find_ext_capability - Find an extended capability | 
|  | 196 | * @dev: PCI device to query | 
|  | 197 | * @cap: capability code | 
|  | 198 | * | 
|  | 199 | * Returns the address of the requested extended capability structure | 
|  | 200 | * within the device's PCI configuration space or 0 if the device does | 
|  | 201 | * not support it.  Possible values for @cap: | 
|  | 202 | * | 
|  | 203 | *  %PCI_EXT_CAP_ID_ERR		Advanced Error Reporting | 
|  | 204 | *  %PCI_EXT_CAP_ID_VC		Virtual Channel | 
|  | 205 | *  %PCI_EXT_CAP_ID_DSN		Device Serial Number | 
|  | 206 | *  %PCI_EXT_CAP_ID_PWR		Power Budgeting | 
|  | 207 | */ | 
|  | 208 | int pci_find_ext_capability(struct pci_dev *dev, int cap) | 
|  | 209 | { | 
|  | 210 | u32 header; | 
|  | 211 | int ttl = 480; /* 3840 bytes, minimum 8 bytes per capability */ | 
|  | 212 | int pos = 0x100; | 
|  | 213 |  | 
|  | 214 | if (dev->cfg_size <= 256) | 
|  | 215 | return 0; | 
|  | 216 |  | 
|  | 217 | if (pci_read_config_dword(dev, pos, &header) != PCIBIOS_SUCCESSFUL) | 
|  | 218 | return 0; | 
|  | 219 |  | 
|  | 220 | /* | 
|  | 221 | * If we have no capabilities, this is indicated by cap ID, | 
|  | 222 | * cap version and next pointer all being 0. | 
|  | 223 | */ | 
|  | 224 | if (header == 0) | 
|  | 225 | return 0; | 
|  | 226 |  | 
|  | 227 | while (ttl-- > 0) { | 
|  | 228 | if (PCI_EXT_CAP_ID(header) == cap) | 
|  | 229 | return pos; | 
|  | 230 |  | 
|  | 231 | pos = PCI_EXT_CAP_NEXT(header); | 
|  | 232 | if (pos < 0x100) | 
|  | 233 | break; | 
|  | 234 |  | 
|  | 235 | if (pci_read_config_dword(dev, pos, &header) != PCIBIOS_SUCCESSFUL) | 
|  | 236 | break; | 
|  | 237 | } | 
|  | 238 |  | 
|  | 239 | return 0; | 
|  | 240 | } | 
| Brice Goglin | 3a720d7 | 2006-05-23 06:10:01 -0400 | [diff] [blame] | 241 | EXPORT_SYMBOL_GPL(pci_find_ext_capability); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 242 |  | 
| Michael Ellerman | 687d5fe | 2006-11-22 18:26:18 +1100 | [diff] [blame] | 243 | static int __pci_find_next_ht_cap(struct pci_dev *dev, int pos, int ht_cap) | 
|  | 244 | { | 
|  | 245 | int rc, ttl = PCI_FIND_CAP_TTL; | 
|  | 246 | u8 cap, mask; | 
|  | 247 |  | 
|  | 248 | if (ht_cap == HT_CAPTYPE_SLAVE || ht_cap == HT_CAPTYPE_HOST) | 
|  | 249 | mask = HT_3BIT_CAP_MASK; | 
|  | 250 | else | 
|  | 251 | mask = HT_5BIT_CAP_MASK; | 
|  | 252 |  | 
|  | 253 | pos = __pci_find_next_cap_ttl(dev->bus, dev->devfn, pos, | 
|  | 254 | PCI_CAP_ID_HT, &ttl); | 
|  | 255 | while (pos) { | 
|  | 256 | rc = pci_read_config_byte(dev, pos + 3, &cap); | 
|  | 257 | if (rc != PCIBIOS_SUCCESSFUL) | 
|  | 258 | return 0; | 
|  | 259 |  | 
|  | 260 | if ((cap & mask) == ht_cap) | 
|  | 261 | return pos; | 
|  | 262 |  | 
| Brice Goglin | 47a4d5b | 2007-01-10 23:15:29 -0800 | [diff] [blame] | 263 | pos = __pci_find_next_cap_ttl(dev->bus, dev->devfn, | 
|  | 264 | pos + PCI_CAP_LIST_NEXT, | 
| Michael Ellerman | 687d5fe | 2006-11-22 18:26:18 +1100 | [diff] [blame] | 265 | PCI_CAP_ID_HT, &ttl); | 
|  | 266 | } | 
|  | 267 |  | 
|  | 268 | return 0; | 
|  | 269 | } | 
|  | 270 | /** | 
|  | 271 | * pci_find_next_ht_capability - query a device's Hypertransport capabilities | 
|  | 272 | * @dev: PCI device to query | 
|  | 273 | * @pos: Position from which to continue searching | 
|  | 274 | * @ht_cap: Hypertransport capability code | 
|  | 275 | * | 
|  | 276 | * To be used in conjunction with pci_find_ht_capability() to search for | 
|  | 277 | * all capabilities matching @ht_cap. @pos should always be a value returned | 
|  | 278 | * from pci_find_ht_capability(). | 
|  | 279 | * | 
|  | 280 | * NB. To be 100% safe against broken PCI devices, the caller should take | 
|  | 281 | * steps to avoid an infinite loop. | 
|  | 282 | */ | 
|  | 283 | int pci_find_next_ht_capability(struct pci_dev *dev, int pos, int ht_cap) | 
|  | 284 | { | 
|  | 285 | return __pci_find_next_ht_cap(dev, pos + PCI_CAP_LIST_NEXT, ht_cap); | 
|  | 286 | } | 
|  | 287 | EXPORT_SYMBOL_GPL(pci_find_next_ht_capability); | 
|  | 288 |  | 
|  | 289 | /** | 
|  | 290 | * pci_find_ht_capability - query a device's Hypertransport capabilities | 
|  | 291 | * @dev: PCI device to query | 
|  | 292 | * @ht_cap: Hypertransport capability code | 
|  | 293 | * | 
|  | 294 | * Tell if a device supports a given Hypertransport capability. | 
|  | 295 | * Returns an address within the device's PCI configuration space | 
|  | 296 | * or 0 in case the device does not support the request capability. | 
|  | 297 | * The address points to the PCI capability, of type PCI_CAP_ID_HT, | 
|  | 298 | * which has a Hypertransport capability matching @ht_cap. | 
|  | 299 | */ | 
|  | 300 | int pci_find_ht_capability(struct pci_dev *dev, int ht_cap) | 
|  | 301 | { | 
|  | 302 | int pos; | 
|  | 303 |  | 
|  | 304 | pos = __pci_bus_find_cap_start(dev->bus, dev->devfn, dev->hdr_type); | 
|  | 305 | if (pos) | 
|  | 306 | pos = __pci_find_next_ht_cap(dev, pos, ht_cap); | 
|  | 307 |  | 
|  | 308 | return pos; | 
|  | 309 | } | 
|  | 310 | EXPORT_SYMBOL_GPL(pci_find_ht_capability); | 
|  | 311 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 312 | /** | 
|  | 313 | * pci_find_parent_resource - return resource region of parent bus of given region | 
|  | 314 | * @dev: PCI device structure contains resources to be searched | 
|  | 315 | * @res: child resource record for which parent is sought | 
|  | 316 | * | 
|  | 317 | *  For given resource region of given device, return the resource | 
|  | 318 | *  region of parent bus the given region is contained in or where | 
|  | 319 | *  it should be allocated from. | 
|  | 320 | */ | 
|  | 321 | struct resource * | 
|  | 322 | pci_find_parent_resource(const struct pci_dev *dev, struct resource *res) | 
|  | 323 | { | 
|  | 324 | const struct pci_bus *bus = dev->bus; | 
|  | 325 | int i; | 
|  | 326 | struct resource *best = NULL; | 
|  | 327 |  | 
|  | 328 | for(i = 0; i < PCI_BUS_NUM_RESOURCES; i++) { | 
|  | 329 | struct resource *r = bus->resource[i]; | 
|  | 330 | if (!r) | 
|  | 331 | continue; | 
|  | 332 | if (res->start && !(res->start >= r->start && res->end <= r->end)) | 
|  | 333 | continue;	/* Not contained */ | 
|  | 334 | if ((res->flags ^ r->flags) & (IORESOURCE_IO | IORESOURCE_MEM)) | 
|  | 335 | continue;	/* Wrong type */ | 
|  | 336 | if (!((res->flags ^ r->flags) & IORESOURCE_PREFETCH)) | 
|  | 337 | return r;	/* Exact match */ | 
|  | 338 | if ((res->flags & IORESOURCE_PREFETCH) && !(r->flags & IORESOURCE_PREFETCH)) | 
|  | 339 | best = r;	/* Approximating prefetchable by non-prefetchable */ | 
|  | 340 | } | 
|  | 341 | return best; | 
|  | 342 | } | 
|  | 343 |  | 
|  | 344 | /** | 
| John W. Linville | 064b53d | 2005-07-27 10:19:44 -0400 | [diff] [blame] | 345 | * pci_restore_bars - restore a devices BAR values (e.g. after wake-up) | 
|  | 346 | * @dev: PCI device to have its BARs restored | 
|  | 347 | * | 
|  | 348 | * Restore the BAR values for a given device, so as to make it | 
|  | 349 | * accessible by its driver. | 
|  | 350 | */ | 
|  | 351 | void | 
|  | 352 | pci_restore_bars(struct pci_dev *dev) | 
|  | 353 | { | 
|  | 354 | int i, numres; | 
|  | 355 |  | 
|  | 356 | switch (dev->hdr_type) { | 
|  | 357 | case PCI_HEADER_TYPE_NORMAL: | 
|  | 358 | numres = 6; | 
|  | 359 | break; | 
|  | 360 | case PCI_HEADER_TYPE_BRIDGE: | 
|  | 361 | numres = 2; | 
|  | 362 | break; | 
|  | 363 | case PCI_HEADER_TYPE_CARDBUS: | 
|  | 364 | numres = 1; | 
|  | 365 | break; | 
|  | 366 | default: | 
|  | 367 | /* Should never get here, but just in case... */ | 
|  | 368 | return; | 
|  | 369 | } | 
|  | 370 |  | 
|  | 371 | for (i = 0; i < numres; i ++) | 
|  | 372 | pci_update_resource(dev, &dev->resource[i], i); | 
|  | 373 | } | 
|  | 374 |  | 
| Randy Dunlap | 8f7020d | 2005-10-23 11:57:38 -0700 | [diff] [blame] | 375 | int (*platform_pci_set_power_state)(struct pci_dev *dev, pci_power_t t); | 
|  | 376 |  | 
| John W. Linville | 064b53d | 2005-07-27 10:19:44 -0400 | [diff] [blame] | 377 | /** | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 378 | * pci_set_power_state - Set the power state of a PCI device | 
|  | 379 | * @dev: PCI device to be suspended | 
|  | 380 | * @state: PCI power state (D0, D1, D2, D3hot, D3cold) we're entering | 
|  | 381 | * | 
|  | 382 | * Transition a device to a new power state, using the Power Management | 
|  | 383 | * Capabilities in the device's config space. | 
|  | 384 | * | 
|  | 385 | * RETURN VALUE: | 
|  | 386 | * -EINVAL if trying to enter a lower state than we're already in. | 
|  | 387 | * 0 if we're already in the requested state. | 
|  | 388 | * -EIO if device does not support PCI PM. | 
|  | 389 | * 0 if we can successfully change the power state. | 
|  | 390 | */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 391 | int | 
|  | 392 | pci_set_power_state(struct pci_dev *dev, pci_power_t state) | 
|  | 393 | { | 
| John W. Linville | 064b53d | 2005-07-27 10:19:44 -0400 | [diff] [blame] | 394 | int pm, need_restore = 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 395 | u16 pmcsr, pmc; | 
|  | 396 |  | 
|  | 397 | /* bound the state we're entering */ | 
|  | 398 | if (state > PCI_D3hot) | 
|  | 399 | state = PCI_D3hot; | 
|  | 400 |  | 
| Pavel Machek | e36c455 | 2007-01-16 12:17:13 +0100 | [diff] [blame] | 401 | /* | 
|  | 402 | * If the device or the parent bridge can't support PCI PM, ignore | 
|  | 403 | * the request if we're doing anything besides putting it into D0 | 
|  | 404 | * (which would only happen on boot). | 
|  | 405 | */ | 
|  | 406 | if ((state == PCI_D1 || state == PCI_D2) && pci_no_d1d2(dev)) | 
|  | 407 | return 0; | 
|  | 408 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 409 | /* Validate current state: | 
|  | 410 | * Can enter D0 from any state, but if we can only go deeper | 
|  | 411 | * to sleep if we're already in a low power state | 
|  | 412 | */ | 
| Andrew Morton | 0266949 | 2006-03-23 01:38:34 -0800 | [diff] [blame] | 413 | if (state != PCI_D0 && dev->current_state > state) { | 
|  | 414 | printk(KERN_ERR "%s(): %s: state=%d, current state=%d\n", | 
|  | 415 | __FUNCTION__, pci_name(dev), state, dev->current_state); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 416 | return -EINVAL; | 
| Andrew Morton | 0266949 | 2006-03-23 01:38:34 -0800 | [diff] [blame] | 417 | } else if (dev->current_state == state) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 418 | return 0;        /* we're already there */ | 
|  | 419 |  | 
| Kristen Carlson Accardi | ffadcc2 | 2006-07-12 08:59:00 -0700 | [diff] [blame] | 420 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 421 | /* find PCI PM capability in list */ | 
|  | 422 | pm = pci_find_capability(dev, PCI_CAP_ID_PM); | 
|  | 423 |  | 
|  | 424 | /* abort if the device doesn't support PM capabilities */ | 
|  | 425 | if (!pm) | 
|  | 426 | return -EIO; | 
|  | 427 |  | 
|  | 428 | pci_read_config_word(dev,pm + PCI_PM_PMC,&pmc); | 
| Daniel Ritz | 3fe9d19 | 2005-08-17 15:32:19 -0700 | [diff] [blame] | 429 | if ((pmc & PCI_PM_CAP_VER_MASK) > 3) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 430 | printk(KERN_DEBUG | 
|  | 431 | "PCI: %s has unsupported PM cap regs version (%u)\n", | 
|  | 432 | pci_name(dev), pmc & PCI_PM_CAP_VER_MASK); | 
|  | 433 | return -EIO; | 
|  | 434 | } | 
|  | 435 |  | 
|  | 436 | /* check if this device supports the desired state */ | 
| Daniel Ritz | 3fe9d19 | 2005-08-17 15:32:19 -0700 | [diff] [blame] | 437 | if (state == PCI_D1 && !(pmc & PCI_PM_CAP_D1)) | 
|  | 438 | return -EIO; | 
|  | 439 | else if (state == PCI_D2 && !(pmc & PCI_PM_CAP_D2)) | 
|  | 440 | return -EIO; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 441 |  | 
| John W. Linville | 064b53d | 2005-07-27 10:19:44 -0400 | [diff] [blame] | 442 | pci_read_config_word(dev, pm + PCI_PM_CTRL, &pmcsr); | 
|  | 443 |  | 
| John W. Linville | 32a3658 | 2005-09-14 09:52:42 -0400 | [diff] [blame] | 444 | /* If we're (effectively) in D3, force entire word to 0. | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 445 | * This doesn't affect PME_Status, disables PME_En, and | 
|  | 446 | * sets PowerState to 0. | 
|  | 447 | */ | 
| John W. Linville | 32a3658 | 2005-09-14 09:52:42 -0400 | [diff] [blame] | 448 | switch (dev->current_state) { | 
| John W. Linville | d3535fb | 2005-09-28 17:50:51 -0400 | [diff] [blame] | 449 | case PCI_D0: | 
|  | 450 | case PCI_D1: | 
|  | 451 | case PCI_D2: | 
|  | 452 | pmcsr &= ~PCI_PM_CTRL_STATE_MASK; | 
|  | 453 | pmcsr |= state; | 
|  | 454 | break; | 
| John W. Linville | 32a3658 | 2005-09-14 09:52:42 -0400 | [diff] [blame] | 455 | case PCI_UNKNOWN: /* Boot-up */ | 
|  | 456 | if ((pmcsr & PCI_PM_CTRL_STATE_MASK) == PCI_D3hot | 
|  | 457 | && !(pmcsr & PCI_PM_CTRL_NO_SOFT_RESET)) | 
| John W. Linville | 064b53d | 2005-07-27 10:19:44 -0400 | [diff] [blame] | 458 | need_restore = 1; | 
| John W. Linville | 32a3658 | 2005-09-14 09:52:42 -0400 | [diff] [blame] | 459 | /* Fall-through: force to D0 */ | 
| John W. Linville | 32a3658 | 2005-09-14 09:52:42 -0400 | [diff] [blame] | 460 | default: | 
| John W. Linville | d3535fb | 2005-09-28 17:50:51 -0400 | [diff] [blame] | 461 | pmcsr = 0; | 
| John W. Linville | 32a3658 | 2005-09-14 09:52:42 -0400 | [diff] [blame] | 462 | break; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 463 | } | 
|  | 464 |  | 
|  | 465 | /* enter specified state */ | 
|  | 466 | pci_write_config_word(dev, pm + PCI_PM_CTRL, pmcsr); | 
|  | 467 |  | 
|  | 468 | /* Mandatory power management transition delays */ | 
|  | 469 | /* see PCI PM 1.1 5.6.1 table 18 */ | 
|  | 470 | if (state == PCI_D3hot || dev->current_state == PCI_D3hot) | 
| Kristen Carlson Accardi | ffadcc2 | 2006-07-12 08:59:00 -0700 | [diff] [blame] | 471 | msleep(pci_pm_d3_delay); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 472 | else if (state == PCI_D2 || dev->current_state == PCI_D2) | 
|  | 473 | udelay(200); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 474 |  | 
| David Shaohua Li | b913100 | 2005-03-19 00:16:18 -0500 | [diff] [blame] | 475 | /* | 
|  | 476 | * Give firmware a chance to be called, such as ACPI _PRx, _PSx | 
| Andreas Mohr | d6e05ed | 2006-06-26 18:35:02 +0200 | [diff] [blame] | 477 | * Firmware method after native method ? | 
| David Shaohua Li | b913100 | 2005-03-19 00:16:18 -0500 | [diff] [blame] | 478 | */ | 
|  | 479 | if (platform_pci_set_power_state) | 
|  | 480 | platform_pci_set_power_state(dev, state); | 
|  | 481 |  | 
|  | 482 | dev->current_state = state; | 
| John W. Linville | 064b53d | 2005-07-27 10:19:44 -0400 | [diff] [blame] | 483 |  | 
|  | 484 | /* According to section 5.4.1 of the "PCI BUS POWER MANAGEMENT | 
|  | 485 | * INTERFACE SPECIFICATION, REV. 1.2", a device transitioning | 
|  | 486 | * from D3hot to D0 _may_ perform an internal reset, thereby | 
|  | 487 | * going to "D0 Uninitialized" rather than "D0 Initialized". | 
|  | 488 | * For example, at least some versions of the 3c905B and the | 
|  | 489 | * 3c556B exhibit this behaviour. | 
|  | 490 | * | 
|  | 491 | * At least some laptop BIOSen (e.g. the Thinkpad T21) leave | 
|  | 492 | * devices in a D3hot state at boot.  Consequently, we need to | 
|  | 493 | * restore at least the BARs so that the device will be | 
|  | 494 | * accessible to its driver. | 
|  | 495 | */ | 
|  | 496 | if (need_restore) | 
|  | 497 | pci_restore_bars(dev); | 
|  | 498 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 499 | return 0; | 
|  | 500 | } | 
|  | 501 |  | 
| Greg Kroah-Hartman | f165b10 | 2005-03-30 21:23:19 -0500 | [diff] [blame] | 502 | int (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state); | 
| David Shaohua Li | 0f64474 | 2005-03-19 00:15:48 -0500 | [diff] [blame] | 503 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 504 | /** | 
|  | 505 | * pci_choose_state - Choose the power state of a PCI device | 
|  | 506 | * @dev: PCI device to be suspended | 
|  | 507 | * @state: target sleep state for the whole system. This is the value | 
|  | 508 | *	that is passed to suspend() function. | 
|  | 509 | * | 
|  | 510 | * Returns PCI power state suitable for given device and given system | 
|  | 511 | * message. | 
|  | 512 | */ | 
|  | 513 |  | 
|  | 514 | pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state) | 
|  | 515 | { | 
| David Shaohua Li | 0f64474 | 2005-03-19 00:15:48 -0500 | [diff] [blame] | 516 | int ret; | 
|  | 517 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 518 | if (!pci_find_capability(dev, PCI_CAP_ID_PM)) | 
|  | 519 | return PCI_D0; | 
|  | 520 |  | 
| David Shaohua Li | 0f64474 | 2005-03-19 00:15:48 -0500 | [diff] [blame] | 521 | if (platform_pci_choose_state) { | 
|  | 522 | ret = platform_pci_choose_state(dev, state); | 
|  | 523 | if (ret >= 0) | 
| Pavel Machek | ca078ba | 2005-09-03 15:56:57 -0700 | [diff] [blame] | 524 | state.event = ret; | 
| David Shaohua Li | 0f64474 | 2005-03-19 00:15:48 -0500 | [diff] [blame] | 525 | } | 
| Pavel Machek | ca078ba | 2005-09-03 15:56:57 -0700 | [diff] [blame] | 526 |  | 
|  | 527 | switch (state.event) { | 
|  | 528 | case PM_EVENT_ON: | 
|  | 529 | return PCI_D0; | 
|  | 530 | case PM_EVENT_FREEZE: | 
| David Brownell | b887d2e | 2006-08-14 23:11:05 -0700 | [diff] [blame] | 531 | case PM_EVENT_PRETHAW: | 
|  | 532 | /* REVISIT both freeze and pre-thaw "should" use D0 */ | 
| Pavel Machek | ca078ba | 2005-09-03 15:56:57 -0700 | [diff] [blame] | 533 | case PM_EVENT_SUSPEND: | 
|  | 534 | return PCI_D3hot; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 535 | default: | 
| David Brownell | b887d2e | 2006-08-14 23:11:05 -0700 | [diff] [blame] | 536 | printk("Unrecognized suspend event %d\n", state.event); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 537 | BUG(); | 
|  | 538 | } | 
|  | 539 | return PCI_D0; | 
|  | 540 | } | 
|  | 541 |  | 
|  | 542 | EXPORT_SYMBOL(pci_choose_state); | 
|  | 543 |  | 
| Michael S. Tsirkin | b56a5a2 | 2006-08-21 16:22:22 +0300 | [diff] [blame] | 544 | static int pci_save_pcie_state(struct pci_dev *dev) | 
|  | 545 | { | 
|  | 546 | int pos, i = 0; | 
|  | 547 | struct pci_cap_saved_state *save_state; | 
|  | 548 | u16 *cap; | 
|  | 549 |  | 
|  | 550 | pos = pci_find_capability(dev, PCI_CAP_ID_EXP); | 
|  | 551 | if (pos <= 0) | 
|  | 552 | return 0; | 
|  | 553 |  | 
| Eric W. Biederman | 9f35575 | 2007-03-08 13:06:13 -0700 | [diff] [blame] | 554 | save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP); | 
|  | 555 | if (!save_state) | 
|  | 556 | save_state = kzalloc(sizeof(*save_state) + sizeof(u16) * 4, GFP_KERNEL); | 
| Michael S. Tsirkin | b56a5a2 | 2006-08-21 16:22:22 +0300 | [diff] [blame] | 557 | if (!save_state) { | 
|  | 558 | dev_err(&dev->dev, "Out of memory in pci_save_pcie_state\n"); | 
|  | 559 | return -ENOMEM; | 
|  | 560 | } | 
|  | 561 | cap = (u16 *)&save_state->data[0]; | 
|  | 562 |  | 
|  | 563 | pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &cap[i++]); | 
|  | 564 | pci_read_config_word(dev, pos + PCI_EXP_LNKCTL, &cap[i++]); | 
|  | 565 | pci_read_config_word(dev, pos + PCI_EXP_SLTCTL, &cap[i++]); | 
|  | 566 | pci_read_config_word(dev, pos + PCI_EXP_RTCTL, &cap[i++]); | 
|  | 567 | pci_add_saved_cap(dev, save_state); | 
|  | 568 | return 0; | 
|  | 569 | } | 
|  | 570 |  | 
|  | 571 | static void pci_restore_pcie_state(struct pci_dev *dev) | 
|  | 572 | { | 
|  | 573 | int i = 0, pos; | 
|  | 574 | struct pci_cap_saved_state *save_state; | 
|  | 575 | u16 *cap; | 
|  | 576 |  | 
|  | 577 | save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP); | 
|  | 578 | pos = pci_find_capability(dev, PCI_CAP_ID_EXP); | 
|  | 579 | if (!save_state || pos <= 0) | 
|  | 580 | return; | 
|  | 581 | cap = (u16 *)&save_state->data[0]; | 
|  | 582 |  | 
|  | 583 | pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, cap[i++]); | 
|  | 584 | pci_write_config_word(dev, pos + PCI_EXP_LNKCTL, cap[i++]); | 
|  | 585 | pci_write_config_word(dev, pos + PCI_EXP_SLTCTL, cap[i++]); | 
|  | 586 | pci_write_config_word(dev, pos + PCI_EXP_RTCTL, cap[i++]); | 
| Michael S. Tsirkin | b56a5a2 | 2006-08-21 16:22:22 +0300 | [diff] [blame] | 587 | } | 
|  | 588 |  | 
| Stephen Hemminger | cc692a5 | 2006-11-08 16:17:15 -0800 | [diff] [blame] | 589 |  | 
|  | 590 | static int pci_save_pcix_state(struct pci_dev *dev) | 
|  | 591 | { | 
|  | 592 | int pos, i = 0; | 
|  | 593 | struct pci_cap_saved_state *save_state; | 
|  | 594 | u16 *cap; | 
|  | 595 |  | 
|  | 596 | pos = pci_find_capability(dev, PCI_CAP_ID_PCIX); | 
|  | 597 | if (pos <= 0) | 
|  | 598 | return 0; | 
|  | 599 |  | 
| Eric W. Biederman | 9f35575 | 2007-03-08 13:06:13 -0700 | [diff] [blame] | 600 | save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP); | 
|  | 601 | if (!save_state) | 
|  | 602 | save_state = kzalloc(sizeof(*save_state) + sizeof(u16), GFP_KERNEL); | 
| Stephen Hemminger | cc692a5 | 2006-11-08 16:17:15 -0800 | [diff] [blame] | 603 | if (!save_state) { | 
|  | 604 | dev_err(&dev->dev, "Out of memory in pci_save_pcie_state\n"); | 
|  | 605 | return -ENOMEM; | 
|  | 606 | } | 
|  | 607 | cap = (u16 *)&save_state->data[0]; | 
|  | 608 |  | 
|  | 609 | pci_read_config_word(dev, pos + PCI_X_CMD, &cap[i++]); | 
|  | 610 | pci_add_saved_cap(dev, save_state); | 
|  | 611 | return 0; | 
|  | 612 | } | 
|  | 613 |  | 
|  | 614 | static void pci_restore_pcix_state(struct pci_dev *dev) | 
|  | 615 | { | 
|  | 616 | int i = 0, pos; | 
|  | 617 | struct pci_cap_saved_state *save_state; | 
|  | 618 | u16 *cap; | 
|  | 619 |  | 
|  | 620 | save_state = pci_find_saved_cap(dev, PCI_CAP_ID_PCIX); | 
|  | 621 | pos = pci_find_capability(dev, PCI_CAP_ID_PCIX); | 
|  | 622 | if (!save_state || pos <= 0) | 
|  | 623 | return; | 
|  | 624 | cap = (u16 *)&save_state->data[0]; | 
|  | 625 |  | 
|  | 626 | pci_write_config_word(dev, pos + PCI_X_CMD, cap[i++]); | 
| Stephen Hemminger | cc692a5 | 2006-11-08 16:17:15 -0800 | [diff] [blame] | 627 | } | 
|  | 628 |  | 
|  | 629 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 630 | /** | 
|  | 631 | * pci_save_state - save the PCI configuration space of a device before suspending | 
|  | 632 | * @dev: - PCI device that we're dealing with | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 633 | */ | 
|  | 634 | int | 
|  | 635 | pci_save_state(struct pci_dev *dev) | 
|  | 636 | { | 
|  | 637 | int i; | 
|  | 638 | /* XXX: 100% dword access ok here? */ | 
|  | 639 | for (i = 0; i < 16; i++) | 
|  | 640 | pci_read_config_dword(dev, i * 4,&dev->saved_config_space[i]); | 
| Michael S. Tsirkin | b56a5a2 | 2006-08-21 16:22:22 +0300 | [diff] [blame] | 641 | if ((i = pci_save_pcie_state(dev)) != 0) | 
|  | 642 | return i; | 
| Stephen Hemminger | cc692a5 | 2006-11-08 16:17:15 -0800 | [diff] [blame] | 643 | if ((i = pci_save_pcix_state(dev)) != 0) | 
|  | 644 | return i; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 645 | return 0; | 
|  | 646 | } | 
|  | 647 |  | 
|  | 648 | /** | 
|  | 649 | * pci_restore_state - Restore the saved state of a PCI device | 
|  | 650 | * @dev: - PCI device that we're dealing with | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 651 | */ | 
|  | 652 | int | 
|  | 653 | pci_restore_state(struct pci_dev *dev) | 
|  | 654 | { | 
|  | 655 | int i; | 
| Dave Jones | 04d9c1a | 2006-04-18 21:06:51 -0700 | [diff] [blame] | 656 | int val; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 657 |  | 
| Michael S. Tsirkin | b56a5a2 | 2006-08-21 16:22:22 +0300 | [diff] [blame] | 658 | /* PCI Express register must be restored first */ | 
|  | 659 | pci_restore_pcie_state(dev); | 
|  | 660 |  | 
| Yu, Luming | 8b8c8d2 | 2006-04-25 00:00:34 -0700 | [diff] [blame] | 661 | /* | 
|  | 662 | * The Base Address register should be programmed before the command | 
|  | 663 | * register(s) | 
|  | 664 | */ | 
|  | 665 | for (i = 15; i >= 0; i--) { | 
| Dave Jones | 04d9c1a | 2006-04-18 21:06:51 -0700 | [diff] [blame] | 666 | pci_read_config_dword(dev, i * 4, &val); | 
|  | 667 | if (val != dev->saved_config_space[i]) { | 
|  | 668 | printk(KERN_DEBUG "PM: Writing back config space on " | 
|  | 669 | "device %s at offset %x (was %x, writing %x)\n", | 
|  | 670 | pci_name(dev), i, | 
|  | 671 | val, (int)dev->saved_config_space[i]); | 
|  | 672 | pci_write_config_dword(dev,i * 4, | 
|  | 673 | dev->saved_config_space[i]); | 
|  | 674 | } | 
|  | 675 | } | 
| Stephen Hemminger | cc692a5 | 2006-11-08 16:17:15 -0800 | [diff] [blame] | 676 | pci_restore_pcix_state(dev); | 
| Shaohua Li | 41017f0 | 2006-02-08 17:11:38 +0800 | [diff] [blame] | 677 | pci_restore_msi_state(dev); | 
| Michael Ellerman | 8fed4b6 | 2007-01-25 19:34:08 +1100 | [diff] [blame] | 678 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 679 | return 0; | 
|  | 680 | } | 
|  | 681 |  | 
| Hidetoshi Seto | 38cc130 | 2006-12-18 10:30:00 +0900 | [diff] [blame] | 682 | static int do_pci_enable_device(struct pci_dev *dev, int bars) | 
|  | 683 | { | 
|  | 684 | int err; | 
|  | 685 |  | 
|  | 686 | err = pci_set_power_state(dev, PCI_D0); | 
|  | 687 | if (err < 0 && err != -EIO) | 
|  | 688 | return err; | 
|  | 689 | err = pcibios_enable_device(dev, bars); | 
|  | 690 | if (err < 0) | 
|  | 691 | return err; | 
|  | 692 | pci_fixup_device(pci_fixup_enable, dev); | 
|  | 693 |  | 
|  | 694 | return 0; | 
|  | 695 | } | 
|  | 696 |  | 
|  | 697 | /** | 
|  | 698 | * __pci_reenable_device - Resume abandoned device | 
|  | 699 | * @dev: PCI device to be resumed | 
|  | 700 | * | 
|  | 701 | *  Note this function is a backend of pci_default_resume and is not supposed | 
|  | 702 | *  to be called by normal code, write proper resume handler and use it instead. | 
|  | 703 | */ | 
|  | 704 | int | 
|  | 705 | __pci_reenable_device(struct pci_dev *dev) | 
|  | 706 | { | 
|  | 707 | if (atomic_read(&dev->enable_cnt)) | 
|  | 708 | return do_pci_enable_device(dev, (1 << PCI_NUM_RESOURCES) - 1); | 
|  | 709 | return 0; | 
|  | 710 | } | 
|  | 711 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 712 | /** | 
|  | 713 | * pci_enable_device_bars - Initialize some of a device for use | 
|  | 714 | * @dev: PCI device to be initialized | 
|  | 715 | * @bars: bitmask of BAR's that must be configured | 
|  | 716 | * | 
|  | 717 | *  Initialize device before it's used by a driver. Ask low-level code | 
| Hidetoshi Seto | 9fb625c | 2006-12-18 10:28:43 +0900 | [diff] [blame] | 718 | *  to enable selected I/O and memory resources. Wake up the device if it | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 719 | *  was suspended. Beware, this function can fail. | 
|  | 720 | */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 721 | int | 
|  | 722 | pci_enable_device_bars(struct pci_dev *dev, int bars) | 
|  | 723 | { | 
|  | 724 | int err; | 
|  | 725 |  | 
| Hidetoshi Seto | 9fb625c | 2006-12-18 10:28:43 +0900 | [diff] [blame] | 726 | if (atomic_add_return(1, &dev->enable_cnt) > 1) | 
|  | 727 | return 0;		/* already enabled */ | 
|  | 728 |  | 
| Hidetoshi Seto | 38cc130 | 2006-12-18 10:30:00 +0900 | [diff] [blame] | 729 | err = do_pci_enable_device(dev, bars); | 
| Greg Kroah-Hartman | 95a6296 | 2005-07-28 11:37:33 -0700 | [diff] [blame] | 730 | if (err < 0) | 
| Hidetoshi Seto | 38cc130 | 2006-12-18 10:30:00 +0900 | [diff] [blame] | 731 | atomic_dec(&dev->enable_cnt); | 
| Hidetoshi Seto | 9fb625c | 2006-12-18 10:28:43 +0900 | [diff] [blame] | 732 | return err; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 733 | } | 
|  | 734 |  | 
|  | 735 | /** | 
|  | 736 | * pci_enable_device - Initialize device before it's used by a driver. | 
|  | 737 | * @dev: PCI device to be initialized | 
|  | 738 | * | 
|  | 739 | *  Initialize device before it's used by a driver. Ask low-level code | 
|  | 740 | *  to enable I/O and memory. Wake up the device if it was suspended. | 
|  | 741 | *  Beware, this function can fail. | 
| Inaky Perez-Gonzalez | bae94d0 | 2006-11-22 12:40:31 -0800 | [diff] [blame] | 742 | * | 
|  | 743 | *  Note we don't actually enable the device many times if we call | 
|  | 744 | *  this function repeatedly (we just increment the count). | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 745 | */ | 
| Inaky Perez-Gonzalez | bae94d0 | 2006-11-22 12:40:31 -0800 | [diff] [blame] | 746 | int pci_enable_device(struct pci_dev *dev) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 747 | { | 
| Hidetoshi Seto | 9fb625c | 2006-12-18 10:28:43 +0900 | [diff] [blame] | 748 | return pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 749 | } | 
|  | 750 |  | 
| Tejun Heo | 9ac7849 | 2007-01-20 16:00:26 +0900 | [diff] [blame] | 751 | /* | 
|  | 752 | * Managed PCI resources.  This manages device on/off, intx/msi/msix | 
|  | 753 | * on/off and BAR regions.  pci_dev itself records msi/msix status, so | 
|  | 754 | * there's no need to track it separately.  pci_devres is initialized | 
|  | 755 | * when a device is enabled using managed PCI device enable interface. | 
|  | 756 | */ | 
|  | 757 | struct pci_devres { | 
| Tejun Heo | 7f375f3 | 2007-02-25 04:36:01 -0800 | [diff] [blame] | 758 | unsigned int enabled:1; | 
|  | 759 | unsigned int pinned:1; | 
| Tejun Heo | 9ac7849 | 2007-01-20 16:00:26 +0900 | [diff] [blame] | 760 | unsigned int orig_intx:1; | 
|  | 761 | unsigned int restore_intx:1; | 
|  | 762 | u32 region_mask; | 
|  | 763 | }; | 
|  | 764 |  | 
|  | 765 | static void pcim_release(struct device *gendev, void *res) | 
|  | 766 | { | 
|  | 767 | struct pci_dev *dev = container_of(gendev, struct pci_dev, dev); | 
|  | 768 | struct pci_devres *this = res; | 
|  | 769 | int i; | 
|  | 770 |  | 
|  | 771 | if (dev->msi_enabled) | 
|  | 772 | pci_disable_msi(dev); | 
|  | 773 | if (dev->msix_enabled) | 
|  | 774 | pci_disable_msix(dev); | 
|  | 775 |  | 
|  | 776 | for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) | 
|  | 777 | if (this->region_mask & (1 << i)) | 
|  | 778 | pci_release_region(dev, i); | 
|  | 779 |  | 
|  | 780 | if (this->restore_intx) | 
|  | 781 | pci_intx(dev, this->orig_intx); | 
|  | 782 |  | 
| Tejun Heo | 7f375f3 | 2007-02-25 04:36:01 -0800 | [diff] [blame] | 783 | if (this->enabled && !this->pinned) | 
| Tejun Heo | 9ac7849 | 2007-01-20 16:00:26 +0900 | [diff] [blame] | 784 | pci_disable_device(dev); | 
|  | 785 | } | 
|  | 786 |  | 
|  | 787 | static struct pci_devres * get_pci_dr(struct pci_dev *pdev) | 
|  | 788 | { | 
|  | 789 | struct pci_devres *dr, *new_dr; | 
|  | 790 |  | 
|  | 791 | dr = devres_find(&pdev->dev, pcim_release, NULL, NULL); | 
|  | 792 | if (dr) | 
|  | 793 | return dr; | 
|  | 794 |  | 
|  | 795 | new_dr = devres_alloc(pcim_release, sizeof(*new_dr), GFP_KERNEL); | 
|  | 796 | if (!new_dr) | 
|  | 797 | return NULL; | 
|  | 798 | return devres_get(&pdev->dev, new_dr, NULL, NULL); | 
|  | 799 | } | 
|  | 800 |  | 
|  | 801 | static struct pci_devres * find_pci_dr(struct pci_dev *pdev) | 
|  | 802 | { | 
|  | 803 | if (pci_is_managed(pdev)) | 
|  | 804 | return devres_find(&pdev->dev, pcim_release, NULL, NULL); | 
|  | 805 | return NULL; | 
|  | 806 | } | 
|  | 807 |  | 
|  | 808 | /** | 
|  | 809 | * pcim_enable_device - Managed pci_enable_device() | 
|  | 810 | * @pdev: PCI device to be initialized | 
|  | 811 | * | 
|  | 812 | * Managed pci_enable_device(). | 
|  | 813 | */ | 
|  | 814 | int pcim_enable_device(struct pci_dev *pdev) | 
|  | 815 | { | 
|  | 816 | struct pci_devres *dr; | 
|  | 817 | int rc; | 
|  | 818 |  | 
|  | 819 | dr = get_pci_dr(pdev); | 
|  | 820 | if (unlikely(!dr)) | 
|  | 821 | return -ENOMEM; | 
| Tejun Heo | 7f375f3 | 2007-02-25 04:36:01 -0800 | [diff] [blame] | 822 | WARN_ON(!!dr->enabled); | 
| Tejun Heo | 9ac7849 | 2007-01-20 16:00:26 +0900 | [diff] [blame] | 823 |  | 
|  | 824 | rc = pci_enable_device(pdev); | 
|  | 825 | if (!rc) { | 
|  | 826 | pdev->is_managed = 1; | 
| Tejun Heo | 7f375f3 | 2007-02-25 04:36:01 -0800 | [diff] [blame] | 827 | dr->enabled = 1; | 
| Tejun Heo | 9ac7849 | 2007-01-20 16:00:26 +0900 | [diff] [blame] | 828 | } | 
|  | 829 | return rc; | 
|  | 830 | } | 
|  | 831 |  | 
|  | 832 | /** | 
|  | 833 | * pcim_pin_device - Pin managed PCI device | 
|  | 834 | * @pdev: PCI device to pin | 
|  | 835 | * | 
|  | 836 | * Pin managed PCI device @pdev.  Pinned device won't be disabled on | 
|  | 837 | * driver detach.  @pdev must have been enabled with | 
|  | 838 | * pcim_enable_device(). | 
|  | 839 | */ | 
|  | 840 | void pcim_pin_device(struct pci_dev *pdev) | 
|  | 841 | { | 
|  | 842 | struct pci_devres *dr; | 
|  | 843 |  | 
|  | 844 | dr = find_pci_dr(pdev); | 
| Tejun Heo | 7f375f3 | 2007-02-25 04:36:01 -0800 | [diff] [blame] | 845 | WARN_ON(!dr || !dr->enabled); | 
| Tejun Heo | 9ac7849 | 2007-01-20 16:00:26 +0900 | [diff] [blame] | 846 | if (dr) | 
| Tejun Heo | 7f375f3 | 2007-02-25 04:36:01 -0800 | [diff] [blame] | 847 | dr->pinned = 1; | 
| Tejun Heo | 9ac7849 | 2007-01-20 16:00:26 +0900 | [diff] [blame] | 848 | } | 
|  | 849 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 850 | /** | 
|  | 851 | * pcibios_disable_device - disable arch specific PCI resources for device dev | 
|  | 852 | * @dev: the PCI device to disable | 
|  | 853 | * | 
|  | 854 | * Disables architecture specific PCI resources for the device. This | 
|  | 855 | * is the default implementation. Architecture implementations can | 
|  | 856 | * override this. | 
|  | 857 | */ | 
|  | 858 | void __attribute__ ((weak)) pcibios_disable_device (struct pci_dev *dev) {} | 
|  | 859 |  | 
|  | 860 | /** | 
|  | 861 | * pci_disable_device - Disable PCI device after use | 
|  | 862 | * @dev: PCI device to be disabled | 
|  | 863 | * | 
|  | 864 | * Signal to the system that the PCI device is not in use by the system | 
|  | 865 | * anymore.  This only involves disabling PCI bus-mastering, if active. | 
| Inaky Perez-Gonzalez | bae94d0 | 2006-11-22 12:40:31 -0800 | [diff] [blame] | 866 | * | 
|  | 867 | * Note we don't actually disable the device until all callers of | 
|  | 868 | * pci_device_enable() have called pci_device_disable(). | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 869 | */ | 
|  | 870 | void | 
|  | 871 | pci_disable_device(struct pci_dev *dev) | 
|  | 872 | { | 
| Tejun Heo | 9ac7849 | 2007-01-20 16:00:26 +0900 | [diff] [blame] | 873 | struct pci_devres *dr; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 874 | u16 pci_command; | 
| Shaohua Li | 99dc804 | 2006-05-26 10:58:27 +0800 | [diff] [blame] | 875 |  | 
| Tejun Heo | 9ac7849 | 2007-01-20 16:00:26 +0900 | [diff] [blame] | 876 | dr = find_pci_dr(dev); | 
|  | 877 | if (dr) | 
| Tejun Heo | 7f375f3 | 2007-02-25 04:36:01 -0800 | [diff] [blame] | 878 | dr->enabled = 0; | 
| Tejun Heo | 9ac7849 | 2007-01-20 16:00:26 +0900 | [diff] [blame] | 879 |  | 
| Inaky Perez-Gonzalez | bae94d0 | 2006-11-22 12:40:31 -0800 | [diff] [blame] | 880 | if (atomic_sub_return(1, &dev->enable_cnt) != 0) | 
|  | 881 | return; | 
|  | 882 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 883 | pci_read_config_word(dev, PCI_COMMAND, &pci_command); | 
|  | 884 | if (pci_command & PCI_COMMAND_MASTER) { | 
|  | 885 | pci_command &= ~PCI_COMMAND_MASTER; | 
|  | 886 | pci_write_config_word(dev, PCI_COMMAND, pci_command); | 
|  | 887 | } | 
| Kenji Kaneshige | ceb4374 | 2005-04-08 14:53:31 +0900 | [diff] [blame] | 888 | dev->is_busmaster = 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 889 |  | 
|  | 890 | pcibios_disable_device(dev); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 891 | } | 
|  | 892 |  | 
|  | 893 | /** | 
|  | 894 | * pci_enable_wake - enable device to generate PME# when suspended | 
|  | 895 | * @dev: - PCI device to operate on | 
|  | 896 | * @state: - Current state of device. | 
|  | 897 | * @enable: - Flag to enable or disable generation | 
|  | 898 | * | 
|  | 899 | * Set the bits in the device's PM Capabilities to generate PME# when | 
|  | 900 | * the system is suspended. | 
|  | 901 | * | 
|  | 902 | * -EIO is returned if device doesn't have PM Capabilities. | 
|  | 903 | * -EINVAL is returned if device supports it, but can't generate wake events. | 
|  | 904 | * 0 if operation is successful. | 
|  | 905 | * | 
|  | 906 | */ | 
|  | 907 | int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable) | 
|  | 908 | { | 
|  | 909 | int pm; | 
|  | 910 | u16 value; | 
|  | 911 |  | 
|  | 912 | /* find PCI PM capability in list */ | 
|  | 913 | pm = pci_find_capability(dev, PCI_CAP_ID_PM); | 
|  | 914 |  | 
|  | 915 | /* If device doesn't support PM Capabilities, but request is to disable | 
|  | 916 | * wake events, it's a nop; otherwise fail */ | 
|  | 917 | if (!pm) | 
|  | 918 | return enable ? -EIO : 0; | 
|  | 919 |  | 
|  | 920 | /* Check device's ability to generate PME# */ | 
|  | 921 | pci_read_config_word(dev,pm+PCI_PM_PMC,&value); | 
|  | 922 |  | 
|  | 923 | value &= PCI_PM_CAP_PME_MASK; | 
|  | 924 | value >>= ffs(PCI_PM_CAP_PME_MASK) - 1;   /* First bit of mask */ | 
|  | 925 |  | 
|  | 926 | /* Check if it can generate PME# from requested state. */ | 
|  | 927 | if (!value || !(value & (1 << state))) | 
|  | 928 | return enable ? -EINVAL : 0; | 
|  | 929 |  | 
|  | 930 | pci_read_config_word(dev, pm + PCI_PM_CTRL, &value); | 
|  | 931 |  | 
|  | 932 | /* Clear PME_Status by writing 1 to it and enable PME# */ | 
|  | 933 | value |= PCI_PM_CTRL_PME_STATUS | PCI_PM_CTRL_PME_ENABLE; | 
|  | 934 |  | 
|  | 935 | if (!enable) | 
|  | 936 | value &= ~PCI_PM_CTRL_PME_ENABLE; | 
|  | 937 |  | 
|  | 938 | pci_write_config_word(dev, pm + PCI_PM_CTRL, value); | 
|  | 939 |  | 
|  | 940 | return 0; | 
|  | 941 | } | 
|  | 942 |  | 
|  | 943 | int | 
|  | 944 | pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge) | 
|  | 945 | { | 
|  | 946 | u8 pin; | 
|  | 947 |  | 
| Kristen Accardi | 514d207 | 2005-11-02 16:24:39 -0800 | [diff] [blame] | 948 | pin = dev->pin; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 949 | if (!pin) | 
|  | 950 | return -1; | 
|  | 951 | pin--; | 
|  | 952 | while (dev->bus->self) { | 
|  | 953 | pin = (pin + PCI_SLOT(dev->devfn)) % 4; | 
|  | 954 | dev = dev->bus->self; | 
|  | 955 | } | 
|  | 956 | *bridge = dev; | 
|  | 957 | return pin; | 
|  | 958 | } | 
|  | 959 |  | 
|  | 960 | /** | 
|  | 961 | *	pci_release_region - Release a PCI bar | 
|  | 962 | *	@pdev: PCI device whose resources were previously reserved by pci_request_region | 
|  | 963 | *	@bar: BAR to release | 
|  | 964 | * | 
|  | 965 | *	Releases the PCI I/O and memory resources previously reserved by a | 
|  | 966 | *	successful call to pci_request_region.  Call this function only | 
|  | 967 | *	after all use of the PCI regions has ceased. | 
|  | 968 | */ | 
|  | 969 | void pci_release_region(struct pci_dev *pdev, int bar) | 
|  | 970 | { | 
| Tejun Heo | 9ac7849 | 2007-01-20 16:00:26 +0900 | [diff] [blame] | 971 | struct pci_devres *dr; | 
|  | 972 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 973 | if (pci_resource_len(pdev, bar) == 0) | 
|  | 974 | return; | 
|  | 975 | if (pci_resource_flags(pdev, bar) & IORESOURCE_IO) | 
|  | 976 | release_region(pci_resource_start(pdev, bar), | 
|  | 977 | pci_resource_len(pdev, bar)); | 
|  | 978 | else if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM) | 
|  | 979 | release_mem_region(pci_resource_start(pdev, bar), | 
|  | 980 | pci_resource_len(pdev, bar)); | 
| Tejun Heo | 9ac7849 | 2007-01-20 16:00:26 +0900 | [diff] [blame] | 981 |  | 
|  | 982 | dr = find_pci_dr(pdev); | 
|  | 983 | if (dr) | 
|  | 984 | dr->region_mask &= ~(1 << bar); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 985 | } | 
|  | 986 |  | 
|  | 987 | /** | 
|  | 988 | *	pci_request_region - Reserved PCI I/O and memory resource | 
|  | 989 | *	@pdev: PCI device whose resources are to be reserved | 
|  | 990 | *	@bar: BAR to be reserved | 
|  | 991 | *	@res_name: Name to be associated with resource. | 
|  | 992 | * | 
|  | 993 | *	Mark the PCI region associated with PCI device @pdev BR @bar as | 
|  | 994 | *	being reserved by owner @res_name.  Do not access any | 
|  | 995 | *	address inside the PCI regions unless this call returns | 
|  | 996 | *	successfully. | 
|  | 997 | * | 
|  | 998 | *	Returns 0 on success, or %EBUSY on error.  A warning | 
|  | 999 | *	message is also printed on failure. | 
|  | 1000 | */ | 
| Jeff Garzik | 3c990e9 | 2006-03-04 21:52:42 -0500 | [diff] [blame] | 1001 | int pci_request_region(struct pci_dev *pdev, int bar, const char *res_name) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1002 | { | 
| Tejun Heo | 9ac7849 | 2007-01-20 16:00:26 +0900 | [diff] [blame] | 1003 | struct pci_devres *dr; | 
|  | 1004 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1005 | if (pci_resource_len(pdev, bar) == 0) | 
|  | 1006 | return 0; | 
|  | 1007 |  | 
|  | 1008 | if (pci_resource_flags(pdev, bar) & IORESOURCE_IO) { | 
|  | 1009 | if (!request_region(pci_resource_start(pdev, bar), | 
|  | 1010 | pci_resource_len(pdev, bar), res_name)) | 
|  | 1011 | goto err_out; | 
|  | 1012 | } | 
|  | 1013 | else if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM) { | 
|  | 1014 | if (!request_mem_region(pci_resource_start(pdev, bar), | 
|  | 1015 | pci_resource_len(pdev, bar), res_name)) | 
|  | 1016 | goto err_out; | 
|  | 1017 | } | 
| Tejun Heo | 9ac7849 | 2007-01-20 16:00:26 +0900 | [diff] [blame] | 1018 |  | 
|  | 1019 | dr = find_pci_dr(pdev); | 
|  | 1020 | if (dr) | 
|  | 1021 | dr->region_mask |= 1 << bar; | 
|  | 1022 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1023 | return 0; | 
|  | 1024 |  | 
|  | 1025 | err_out: | 
| Greg Kroah-Hartman | 1396a8c | 2006-06-12 15:14:29 -0700 | [diff] [blame] | 1026 | printk (KERN_WARNING "PCI: Unable to reserve %s region #%d:%llx@%llx " | 
|  | 1027 | "for device %s\n", | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1028 | pci_resource_flags(pdev, bar) & IORESOURCE_IO ? "I/O" : "mem", | 
|  | 1029 | bar + 1, /* PCI BAR # */ | 
| Greg Kroah-Hartman | 1396a8c | 2006-06-12 15:14:29 -0700 | [diff] [blame] | 1030 | (unsigned long long)pci_resource_len(pdev, bar), | 
|  | 1031 | (unsigned long long)pci_resource_start(pdev, bar), | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1032 | pci_name(pdev)); | 
|  | 1033 | return -EBUSY; | 
|  | 1034 | } | 
|  | 1035 |  | 
| Hidetoshi Seto | c87deff | 2006-12-18 10:31:06 +0900 | [diff] [blame] | 1036 | /** | 
|  | 1037 | * pci_release_selected_regions - Release selected PCI I/O and memory resources | 
|  | 1038 | * @pdev: PCI device whose resources were previously reserved | 
|  | 1039 | * @bars: Bitmask of BARs to be released | 
|  | 1040 | * | 
|  | 1041 | * Release selected PCI I/O and memory resources previously reserved. | 
|  | 1042 | * Call this function only after all use of the PCI regions has ceased. | 
|  | 1043 | */ | 
|  | 1044 | void pci_release_selected_regions(struct pci_dev *pdev, int bars) | 
|  | 1045 | { | 
|  | 1046 | int i; | 
|  | 1047 |  | 
|  | 1048 | for (i = 0; i < 6; i++) | 
|  | 1049 | if (bars & (1 << i)) | 
|  | 1050 | pci_release_region(pdev, i); | 
|  | 1051 | } | 
|  | 1052 |  | 
|  | 1053 | /** | 
|  | 1054 | * pci_request_selected_regions - Reserve selected PCI I/O and memory resources | 
|  | 1055 | * @pdev: PCI device whose resources are to be reserved | 
|  | 1056 | * @bars: Bitmask of BARs to be requested | 
|  | 1057 | * @res_name: Name to be associated with resource | 
|  | 1058 | */ | 
|  | 1059 | int pci_request_selected_regions(struct pci_dev *pdev, int bars, | 
|  | 1060 | const char *res_name) | 
|  | 1061 | { | 
|  | 1062 | int i; | 
|  | 1063 |  | 
|  | 1064 | for (i = 0; i < 6; i++) | 
|  | 1065 | if (bars & (1 << i)) | 
|  | 1066 | if(pci_request_region(pdev, i, res_name)) | 
|  | 1067 | goto err_out; | 
|  | 1068 | return 0; | 
|  | 1069 |  | 
|  | 1070 | err_out: | 
|  | 1071 | while(--i >= 0) | 
|  | 1072 | if (bars & (1 << i)) | 
|  | 1073 | pci_release_region(pdev, i); | 
|  | 1074 |  | 
|  | 1075 | return -EBUSY; | 
|  | 1076 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1077 |  | 
|  | 1078 | /** | 
|  | 1079 | *	pci_release_regions - Release reserved PCI I/O and memory resources | 
|  | 1080 | *	@pdev: PCI device whose resources were previously reserved by pci_request_regions | 
|  | 1081 | * | 
|  | 1082 | *	Releases all PCI I/O and memory resources previously reserved by a | 
|  | 1083 | *	successful call to pci_request_regions.  Call this function only | 
|  | 1084 | *	after all use of the PCI regions has ceased. | 
|  | 1085 | */ | 
|  | 1086 |  | 
|  | 1087 | void pci_release_regions(struct pci_dev *pdev) | 
|  | 1088 | { | 
| Hidetoshi Seto | c87deff | 2006-12-18 10:31:06 +0900 | [diff] [blame] | 1089 | pci_release_selected_regions(pdev, (1 << 6) - 1); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1090 | } | 
|  | 1091 |  | 
|  | 1092 | /** | 
|  | 1093 | *	pci_request_regions - Reserved PCI I/O and memory resources | 
|  | 1094 | *	@pdev: PCI device whose resources are to be reserved | 
|  | 1095 | *	@res_name: Name to be associated with resource. | 
|  | 1096 | * | 
|  | 1097 | *	Mark all PCI regions associated with PCI device @pdev as | 
|  | 1098 | *	being reserved by owner @res_name.  Do not access any | 
|  | 1099 | *	address inside the PCI regions unless this call returns | 
|  | 1100 | *	successfully. | 
|  | 1101 | * | 
|  | 1102 | *	Returns 0 on success, or %EBUSY on error.  A warning | 
|  | 1103 | *	message is also printed on failure. | 
|  | 1104 | */ | 
| Jeff Garzik | 3c990e9 | 2006-03-04 21:52:42 -0500 | [diff] [blame] | 1105 | int pci_request_regions(struct pci_dev *pdev, const char *res_name) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1106 | { | 
| Hidetoshi Seto | c87deff | 2006-12-18 10:31:06 +0900 | [diff] [blame] | 1107 | return pci_request_selected_regions(pdev, ((1 << 6) - 1), res_name); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1108 | } | 
|  | 1109 |  | 
|  | 1110 | /** | 
|  | 1111 | * pci_set_master - enables bus-mastering for device dev | 
|  | 1112 | * @dev: the PCI device to enable | 
|  | 1113 | * | 
|  | 1114 | * Enables bus-mastering on the device and calls pcibios_set_master() | 
|  | 1115 | * to do the needed arch specific settings. | 
|  | 1116 | */ | 
|  | 1117 | void | 
|  | 1118 | pci_set_master(struct pci_dev *dev) | 
|  | 1119 | { | 
|  | 1120 | u16 cmd; | 
|  | 1121 |  | 
|  | 1122 | pci_read_config_word(dev, PCI_COMMAND, &cmd); | 
|  | 1123 | if (! (cmd & PCI_COMMAND_MASTER)) { | 
|  | 1124 | pr_debug("PCI: Enabling bus mastering for device %s\n", pci_name(dev)); | 
|  | 1125 | cmd |= PCI_COMMAND_MASTER; | 
|  | 1126 | pci_write_config_word(dev, PCI_COMMAND, cmd); | 
|  | 1127 | } | 
|  | 1128 | dev->is_busmaster = 1; | 
|  | 1129 | pcibios_set_master(dev); | 
|  | 1130 | } | 
|  | 1131 |  | 
| Matthew Wilcox | edb2d97 | 2006-10-10 08:01:21 -0600 | [diff] [blame] | 1132 | #ifdef PCI_DISABLE_MWI | 
|  | 1133 | int pci_set_mwi(struct pci_dev *dev) | 
|  | 1134 | { | 
|  | 1135 | return 0; | 
|  | 1136 | } | 
|  | 1137 |  | 
|  | 1138 | void pci_clear_mwi(struct pci_dev *dev) | 
|  | 1139 | { | 
|  | 1140 | } | 
|  | 1141 |  | 
|  | 1142 | #else | 
| Matthew Wilcox | ebf5a24 | 2006-10-10 08:01:20 -0600 | [diff] [blame] | 1143 |  | 
|  | 1144 | #ifndef PCI_CACHE_LINE_BYTES | 
|  | 1145 | #define PCI_CACHE_LINE_BYTES L1_CACHE_BYTES | 
|  | 1146 | #endif | 
|  | 1147 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1148 | /* This can be overridden by arch code. */ | 
| Matthew Wilcox | ebf5a24 | 2006-10-10 08:01:20 -0600 | [diff] [blame] | 1149 | /* Don't forget this is measured in 32-bit words, not bytes */ | 
|  | 1150 | u8 pci_cache_line_size = PCI_CACHE_LINE_BYTES / 4; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1151 |  | 
|  | 1152 | /** | 
| Matthew Wilcox | edb2d97 | 2006-10-10 08:01:21 -0600 | [diff] [blame] | 1153 | * pci_set_cacheline_size - ensure the CACHE_LINE_SIZE register is programmed | 
|  | 1154 | * @dev: the PCI device for which MWI is to be enabled | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1155 | * | 
| Matthew Wilcox | edb2d97 | 2006-10-10 08:01:21 -0600 | [diff] [blame] | 1156 | * Helper function for pci_set_mwi. | 
|  | 1157 | * Originally copied from drivers/net/acenic.c. | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1158 | * Copyright 1998-2001 by Jes Sorensen, <jes@trained-monkey.org>. | 
|  | 1159 | * | 
|  | 1160 | * RETURNS: An appropriate -ERRNO error value on error, or zero for success. | 
|  | 1161 | */ | 
|  | 1162 | static int | 
| Matthew Wilcox | edb2d97 | 2006-10-10 08:01:21 -0600 | [diff] [blame] | 1163 | pci_set_cacheline_size(struct pci_dev *dev) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1164 | { | 
|  | 1165 | u8 cacheline_size; | 
|  | 1166 |  | 
|  | 1167 | if (!pci_cache_line_size) | 
|  | 1168 | return -EINVAL;		/* The system doesn't support MWI. */ | 
|  | 1169 |  | 
|  | 1170 | /* Validate current setting: the PCI_CACHE_LINE_SIZE must be | 
|  | 1171 | equal to or multiple of the right value. */ | 
|  | 1172 | pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &cacheline_size); | 
|  | 1173 | if (cacheline_size >= pci_cache_line_size && | 
|  | 1174 | (cacheline_size % pci_cache_line_size) == 0) | 
|  | 1175 | return 0; | 
|  | 1176 |  | 
|  | 1177 | /* Write the correct value. */ | 
|  | 1178 | pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, pci_cache_line_size); | 
|  | 1179 | /* Read it back. */ | 
|  | 1180 | pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &cacheline_size); | 
|  | 1181 | if (cacheline_size == pci_cache_line_size) | 
|  | 1182 | return 0; | 
|  | 1183 |  | 
|  | 1184 | printk(KERN_DEBUG "PCI: cache line size of %d is not supported " | 
|  | 1185 | "by device %s\n", pci_cache_line_size << 2, pci_name(dev)); | 
|  | 1186 |  | 
|  | 1187 | return -EINVAL; | 
|  | 1188 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1189 |  | 
|  | 1190 | /** | 
|  | 1191 | * pci_set_mwi - enables memory-write-invalidate PCI transaction | 
|  | 1192 | * @dev: the PCI device for which MWI is enabled | 
|  | 1193 | * | 
|  | 1194 | * Enables the Memory-Write-Invalidate transaction in %PCI_COMMAND, | 
|  | 1195 | * and then calls @pcibios_set_mwi to do the needed arch specific | 
|  | 1196 | * operations or a generic mwi-prep function. | 
|  | 1197 | * | 
|  | 1198 | * RETURNS: An appropriate -ERRNO error value on error, or zero for success. | 
|  | 1199 | */ | 
|  | 1200 | int | 
|  | 1201 | pci_set_mwi(struct pci_dev *dev) | 
|  | 1202 | { | 
|  | 1203 | int rc; | 
|  | 1204 | u16 cmd; | 
|  | 1205 |  | 
| Matthew Wilcox | edb2d97 | 2006-10-10 08:01:21 -0600 | [diff] [blame] | 1206 | rc = pci_set_cacheline_size(dev); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1207 | if (rc) | 
|  | 1208 | return rc; | 
|  | 1209 |  | 
|  | 1210 | pci_read_config_word(dev, PCI_COMMAND, &cmd); | 
|  | 1211 | if (! (cmd & PCI_COMMAND_INVALIDATE)) { | 
|  | 1212 | pr_debug("PCI: Enabling Mem-Wr-Inval for device %s\n", pci_name(dev)); | 
|  | 1213 | cmd |= PCI_COMMAND_INVALIDATE; | 
|  | 1214 | pci_write_config_word(dev, PCI_COMMAND, cmd); | 
|  | 1215 | } | 
|  | 1216 |  | 
|  | 1217 | return 0; | 
|  | 1218 | } | 
|  | 1219 |  | 
|  | 1220 | /** | 
|  | 1221 | * pci_clear_mwi - disables Memory-Write-Invalidate for device dev | 
|  | 1222 | * @dev: the PCI device to disable | 
|  | 1223 | * | 
|  | 1224 | * Disables PCI Memory-Write-Invalidate transaction on the device | 
|  | 1225 | */ | 
|  | 1226 | void | 
|  | 1227 | pci_clear_mwi(struct pci_dev *dev) | 
|  | 1228 | { | 
|  | 1229 | u16 cmd; | 
|  | 1230 |  | 
|  | 1231 | pci_read_config_word(dev, PCI_COMMAND, &cmd); | 
|  | 1232 | if (cmd & PCI_COMMAND_INVALIDATE) { | 
|  | 1233 | cmd &= ~PCI_COMMAND_INVALIDATE; | 
|  | 1234 | pci_write_config_word(dev, PCI_COMMAND, cmd); | 
|  | 1235 | } | 
|  | 1236 | } | 
| Matthew Wilcox | edb2d97 | 2006-10-10 08:01:21 -0600 | [diff] [blame] | 1237 | #endif /* ! PCI_DISABLE_MWI */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1238 |  | 
| Brett M Russ | a04ce0f | 2005-08-15 15:23:41 -0400 | [diff] [blame] | 1239 | /** | 
|  | 1240 | * pci_intx - enables/disables PCI INTx for device dev | 
| Randy Dunlap | 8f7020d | 2005-10-23 11:57:38 -0700 | [diff] [blame] | 1241 | * @pdev: the PCI device to operate on | 
|  | 1242 | * @enable: boolean: whether to enable or disable PCI INTx | 
| Brett M Russ | a04ce0f | 2005-08-15 15:23:41 -0400 | [diff] [blame] | 1243 | * | 
|  | 1244 | * Enables/disables PCI INTx for device dev | 
|  | 1245 | */ | 
|  | 1246 | void | 
|  | 1247 | pci_intx(struct pci_dev *pdev, int enable) | 
|  | 1248 | { | 
|  | 1249 | u16 pci_command, new; | 
|  | 1250 |  | 
|  | 1251 | pci_read_config_word(pdev, PCI_COMMAND, &pci_command); | 
|  | 1252 |  | 
|  | 1253 | if (enable) { | 
|  | 1254 | new = pci_command & ~PCI_COMMAND_INTX_DISABLE; | 
|  | 1255 | } else { | 
|  | 1256 | new = pci_command | PCI_COMMAND_INTX_DISABLE; | 
|  | 1257 | } | 
|  | 1258 |  | 
|  | 1259 | if (new != pci_command) { | 
| Tejun Heo | 9ac7849 | 2007-01-20 16:00:26 +0900 | [diff] [blame] | 1260 | struct pci_devres *dr; | 
|  | 1261 |  | 
| Brett M Russ | 2fd9d74 | 2005-09-09 10:02:22 -0700 | [diff] [blame] | 1262 | pci_write_config_word(pdev, PCI_COMMAND, new); | 
| Tejun Heo | 9ac7849 | 2007-01-20 16:00:26 +0900 | [diff] [blame] | 1263 |  | 
|  | 1264 | dr = find_pci_dr(pdev); | 
|  | 1265 | if (dr && !dr->restore_intx) { | 
|  | 1266 | dr->restore_intx = 1; | 
|  | 1267 | dr->orig_intx = !enable; | 
|  | 1268 | } | 
| Brett M Russ | a04ce0f | 2005-08-15 15:23:41 -0400 | [diff] [blame] | 1269 | } | 
|  | 1270 | } | 
|  | 1271 |  | 
| Eric W. Biederman | f5f2b13 | 2007-03-05 00:30:07 -0800 | [diff] [blame] | 1272 | /** | 
|  | 1273 | * pci_msi_off - disables any msi or msix capabilities | 
|  | 1274 | * @pdev: the PCI device to operate on | 
|  | 1275 | * | 
|  | 1276 | * If you want to use msi see pci_enable_msi and friends. | 
|  | 1277 | * This is a lower level primitive that allows us to disable | 
|  | 1278 | * msi operation at the device level. | 
|  | 1279 | */ | 
|  | 1280 | void pci_msi_off(struct pci_dev *dev) | 
|  | 1281 | { | 
|  | 1282 | int pos; | 
|  | 1283 | u16 control; | 
|  | 1284 |  | 
|  | 1285 | pos = pci_find_capability(dev, PCI_CAP_ID_MSI); | 
|  | 1286 | if (pos) { | 
|  | 1287 | pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control); | 
|  | 1288 | control &= ~PCI_MSI_FLAGS_ENABLE; | 
|  | 1289 | pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control); | 
|  | 1290 | } | 
|  | 1291 | pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); | 
|  | 1292 | if (pos) { | 
|  | 1293 | pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control); | 
|  | 1294 | control &= ~PCI_MSIX_FLAGS_ENABLE; | 
|  | 1295 | pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control); | 
|  | 1296 | } | 
|  | 1297 | } | 
|  | 1298 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1299 | #ifndef HAVE_ARCH_PCI_SET_DMA_MASK | 
|  | 1300 | /* | 
|  | 1301 | * These can be overridden by arch-specific implementations | 
|  | 1302 | */ | 
|  | 1303 | int | 
|  | 1304 | pci_set_dma_mask(struct pci_dev *dev, u64 mask) | 
|  | 1305 | { | 
|  | 1306 | if (!pci_dma_supported(dev, mask)) | 
|  | 1307 | return -EIO; | 
|  | 1308 |  | 
|  | 1309 | dev->dma_mask = mask; | 
|  | 1310 |  | 
|  | 1311 | return 0; | 
|  | 1312 | } | 
|  | 1313 |  | 
|  | 1314 | int | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1315 | pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask) | 
|  | 1316 | { | 
|  | 1317 | if (!pci_dma_supported(dev, mask)) | 
|  | 1318 | return -EIO; | 
|  | 1319 |  | 
|  | 1320 | dev->dev.coherent_dma_mask = mask; | 
|  | 1321 |  | 
|  | 1322 | return 0; | 
|  | 1323 | } | 
|  | 1324 | #endif | 
| Hidetoshi Seto | c87deff | 2006-12-18 10:31:06 +0900 | [diff] [blame] | 1325 |  | 
|  | 1326 | /** | 
|  | 1327 | * pci_select_bars - Make BAR mask from the type of resource | 
| Randy Dunlap | f95d882 | 2007-02-10 14:41:56 -0800 | [diff] [blame] | 1328 | * @dev: the PCI device for which BAR mask is made | 
| Hidetoshi Seto | c87deff | 2006-12-18 10:31:06 +0900 | [diff] [blame] | 1329 | * @flags: resource type mask to be selected | 
|  | 1330 | * | 
|  | 1331 | * This helper routine makes bar mask from the type of resource. | 
|  | 1332 | */ | 
|  | 1333 | int pci_select_bars(struct pci_dev *dev, unsigned long flags) | 
|  | 1334 | { | 
|  | 1335 | int i, bars = 0; | 
|  | 1336 | for (i = 0; i < PCI_NUM_RESOURCES; i++) | 
|  | 1337 | if (pci_resource_flags(dev, i) & flags) | 
|  | 1338 | bars |= (1 << i); | 
|  | 1339 | return bars; | 
|  | 1340 | } | 
|  | 1341 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1342 | static int __devinit pci_init(void) | 
|  | 1343 | { | 
|  | 1344 | struct pci_dev *dev = NULL; | 
|  | 1345 |  | 
|  | 1346 | while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { | 
|  | 1347 | pci_fixup_device(pci_fixup_final, dev); | 
|  | 1348 | } | 
|  | 1349 | return 0; | 
|  | 1350 | } | 
|  | 1351 |  | 
|  | 1352 | static int __devinit pci_setup(char *str) | 
|  | 1353 | { | 
|  | 1354 | while (str) { | 
|  | 1355 | char *k = strchr(str, ','); | 
|  | 1356 | if (k) | 
|  | 1357 | *k++ = 0; | 
|  | 1358 | if (*str && (str = pcibios_setup(str)) && *str) { | 
| Matthew Wilcox | 309e57d | 2006-03-05 22:33:34 -0700 | [diff] [blame] | 1359 | if (!strcmp(str, "nomsi")) { | 
|  | 1360 | pci_no_msi(); | 
| Atsushi Nemoto | 4516a61 | 2007-02-05 16:36:06 -0800 | [diff] [blame] | 1361 | } else if (!strncmp(str, "cbiosize=", 9)) { | 
|  | 1362 | pci_cardbus_io_size = memparse(str + 9, &str); | 
|  | 1363 | } else if (!strncmp(str, "cbmemsize=", 10)) { | 
|  | 1364 | pci_cardbus_mem_size = memparse(str + 10, &str); | 
| Matthew Wilcox | 309e57d | 2006-03-05 22:33:34 -0700 | [diff] [blame] | 1365 | } else { | 
|  | 1366 | printk(KERN_ERR "PCI: Unknown option `%s'\n", | 
|  | 1367 | str); | 
|  | 1368 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1369 | } | 
|  | 1370 | str = k; | 
|  | 1371 | } | 
| Andi Kleen | 0637a70 | 2006-09-26 10:52:41 +0200 | [diff] [blame] | 1372 | return 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1373 | } | 
| Andi Kleen | 0637a70 | 2006-09-26 10:52:41 +0200 | [diff] [blame] | 1374 | early_param("pci", pci_setup); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1375 |  | 
|  | 1376 | device_initcall(pci_init); | 
|  | 1377 |  | 
| John W. Linville | 064b53d | 2005-07-27 10:19:44 -0400 | [diff] [blame] | 1378 | EXPORT_SYMBOL_GPL(pci_restore_bars); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1379 | EXPORT_SYMBOL(pci_enable_device_bars); | 
|  | 1380 | EXPORT_SYMBOL(pci_enable_device); | 
| Tejun Heo | 9ac7849 | 2007-01-20 16:00:26 +0900 | [diff] [blame] | 1381 | EXPORT_SYMBOL(pcim_enable_device); | 
|  | 1382 | EXPORT_SYMBOL(pcim_pin_device); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1383 | EXPORT_SYMBOL(pci_disable_device); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1384 | EXPORT_SYMBOL(pci_find_capability); | 
|  | 1385 | EXPORT_SYMBOL(pci_bus_find_capability); | 
|  | 1386 | EXPORT_SYMBOL(pci_release_regions); | 
|  | 1387 | EXPORT_SYMBOL(pci_request_regions); | 
|  | 1388 | EXPORT_SYMBOL(pci_release_region); | 
|  | 1389 | EXPORT_SYMBOL(pci_request_region); | 
| Hidetoshi Seto | c87deff | 2006-12-18 10:31:06 +0900 | [diff] [blame] | 1390 | EXPORT_SYMBOL(pci_release_selected_regions); | 
|  | 1391 | EXPORT_SYMBOL(pci_request_selected_regions); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1392 | EXPORT_SYMBOL(pci_set_master); | 
|  | 1393 | EXPORT_SYMBOL(pci_set_mwi); | 
|  | 1394 | EXPORT_SYMBOL(pci_clear_mwi); | 
| Brett M Russ | a04ce0f | 2005-08-15 15:23:41 -0400 | [diff] [blame] | 1395 | EXPORT_SYMBOL_GPL(pci_intx); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1396 | EXPORT_SYMBOL(pci_set_dma_mask); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1397 | EXPORT_SYMBOL(pci_set_consistent_dma_mask); | 
|  | 1398 | EXPORT_SYMBOL(pci_assign_resource); | 
|  | 1399 | EXPORT_SYMBOL(pci_find_parent_resource); | 
| Hidetoshi Seto | c87deff | 2006-12-18 10:31:06 +0900 | [diff] [blame] | 1400 | EXPORT_SYMBOL(pci_select_bars); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1401 |  | 
|  | 1402 | EXPORT_SYMBOL(pci_set_power_state); | 
|  | 1403 | EXPORT_SYMBOL(pci_save_state); | 
|  | 1404 | EXPORT_SYMBOL(pci_restore_state); | 
|  | 1405 | EXPORT_SYMBOL(pci_enable_wake); | 
|  | 1406 |  |