| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | *  pci_bind.c - ACPI PCI Device Binding ($Revision: 2 $) | 
|  | 3 | * | 
|  | 4 | *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> | 
|  | 5 | *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> | 
|  | 6 | * | 
|  | 7 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 
|  | 8 | * | 
|  | 9 | *  This program is free software; you can redistribute it and/or modify | 
|  | 10 | *  it under the terms of the GNU General Public License as published by | 
|  | 11 | *  the Free Software Foundation; either version 2 of the License, or (at | 
|  | 12 | *  your option) any later version. | 
|  | 13 | * | 
|  | 14 | *  This program is distributed in the hope that it will be useful, but | 
|  | 15 | *  WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | 16 | *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | 17 | *  General Public License for more details. | 
|  | 18 | * | 
|  | 19 | *  You should have received a copy of the GNU General Public License along | 
|  | 20 | *  with this program; if not, write to the Free Software Foundation, Inc., | 
|  | 21 | *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | 
|  | 22 | * | 
|  | 23 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 
|  | 24 | */ | 
|  | 25 |  | 
|  | 26 | #include <linux/kernel.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 27 | #include <linux/types.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 28 | #include <linux/pci.h> | 
| Rafael J. Wysocki | b67ea76 | 2010-02-17 23:44:09 +0100 | [diff] [blame] | 29 | #include <linux/pci-acpi.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 30 | #include <linux/acpi.h> | 
| Rafael J. Wysocki | b67ea76 | 2010-02-17 23:44:09 +0100 | [diff] [blame] | 31 | #include <linux/pm_runtime.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 32 | #include <acpi/acpi_bus.h> | 
|  | 33 | #include <acpi/acpi_drivers.h> | 
|  | 34 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 35 | #define _COMPONENT		ACPI_PCI_COMPONENT | 
| Len Brown | f52fd66 | 2007-02-12 22:42:12 -0500 | [diff] [blame] | 36 | ACPI_MODULE_NAME("pci_bind"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 37 |  | 
| Alexander Chiang | c22d7f5 | 2009-06-10 19:55:25 +0000 | [diff] [blame] | 38 | static int acpi_pci_unbind(struct acpi_device *device) | 
|  | 39 | { | 
| Alexander Chiang | 499650d | 2009-06-10 19:55:30 +0000 | [diff] [blame] | 40 | struct pci_dev *dev; | 
| Alexander Chiang | c22d7f5 | 2009-06-10 19:55:25 +0000 | [diff] [blame] | 41 |  | 
| Alexander Chiang | 499650d | 2009-06-10 19:55:30 +0000 | [diff] [blame] | 42 | dev = acpi_get_pci_dev(device->handle); | 
| Rafael J. Wysocki | b67ea76 | 2010-02-17 23:44:09 +0100 | [diff] [blame] | 43 | if (!dev) | 
|  | 44 | goto out; | 
|  | 45 |  | 
|  | 46 | device_set_run_wake(&dev->dev, false); | 
|  | 47 | pci_acpi_remove_pm_notifier(device); | 
|  | 48 |  | 
|  | 49 | if (!dev->subordinate) | 
| Alexander Chiang | 97719a8 | 2009-06-10 19:55:45 +0000 | [diff] [blame] | 50 | goto out; | 
| Alexander Chiang | c22d7f5 | 2009-06-10 19:55:25 +0000 | [diff] [blame] | 51 |  | 
| Alexander Chiang | 97719a8 | 2009-06-10 19:55:45 +0000 | [diff] [blame] | 52 | acpi_pci_irq_del_prt(dev->subordinate); | 
| Alexander Chiang | c22d7f5 | 2009-06-10 19:55:25 +0000 | [diff] [blame] | 53 |  | 
| Alexander Chiang | 97719a8 | 2009-06-10 19:55:45 +0000 | [diff] [blame] | 54 | device->ops.bind = NULL; | 
|  | 55 | device->ops.unbind = NULL; | 
|  | 56 |  | 
|  | 57 | out: | 
| Alexander Chiang | 499650d | 2009-06-10 19:55:30 +0000 | [diff] [blame] | 58 | pci_dev_put(dev); | 
|  | 59 | return 0; | 
| Alexander Chiang | c22d7f5 | 2009-06-10 19:55:25 +0000 | [diff] [blame] | 60 | } | 
|  | 61 |  | 
| Alexander Chiang | ce597bb | 2009-06-10 19:55:09 +0000 | [diff] [blame] | 62 | static int acpi_pci_bind(struct acpi_device *device) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 63 | { | 
| Len Brown | 087da3b | 2008-12-30 22:44:33 -0500 | [diff] [blame] | 64 | acpi_status status; | 
| Len Brown | 087da3b | 2008-12-30 22:44:33 -0500 | [diff] [blame] | 65 | acpi_handle handle; | 
| Alexander Chiang | 859a3f8 | 2009-06-10 19:55:35 +0000 | [diff] [blame] | 66 | struct pci_bus *bus; | 
| Alexander Chiang | 499650d | 2009-06-10 19:55:30 +0000 | [diff] [blame] | 67 | struct pci_dev *dev; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 68 |  | 
| Alexander Chiang | 499650d | 2009-06-10 19:55:30 +0000 | [diff] [blame] | 69 | dev = acpi_get_pci_dev(device->handle); | 
|  | 70 | if (!dev) | 
|  | 71 | return 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 72 |  | 
| Rafael J. Wysocki | b67ea76 | 2010-02-17 23:44:09 +0100 | [diff] [blame] | 73 | pci_acpi_add_pm_notifier(device, dev); | 
|  | 74 | if (device->wakeup.flags.run_wake) | 
|  | 75 | device_set_run_wake(&dev->dev, true); | 
|  | 76 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 77 | /* | 
| Alexander Chiang | 499650d | 2009-06-10 19:55:30 +0000 | [diff] [blame] | 78 | * Install the 'bind' function to facilitate callbacks for | 
|  | 79 | * children of the P2P bridge. | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 80 | */ | 
| Alexander Chiang | 499650d | 2009-06-10 19:55:30 +0000 | [diff] [blame] | 81 | if (dev->subordinate) { | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 82 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | 
| Bjorn Helgaas | 21a5328 | 2008-12-08 21:30:05 -0700 | [diff] [blame] | 83 | "Device %04x:%02x:%02x.%d is a PCI bridge\n", | 
| Alexander Chiang | 499650d | 2009-06-10 19:55:30 +0000 | [diff] [blame] | 84 | pci_domain_nr(dev->bus), dev->bus->number, | 
|  | 85 | PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn))); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 86 | device->ops.bind = acpi_pci_bind; | 
|  | 87 | device->ops.unbind = acpi_pci_unbind; | 
|  | 88 | } | 
|  | 89 |  | 
|  | 90 | /* | 
| Alexander Chiang | 499650d | 2009-06-10 19:55:30 +0000 | [diff] [blame] | 91 | * Evaluate and parse _PRT, if exists.  This code allows parsing of | 
|  | 92 | * _PRT objects within the scope of non-bridge devices.  Note that | 
|  | 93 | * _PRTs within the scope of a PCI bridge assume the bridge's | 
|  | 94 | * subordinate bus number. | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 95 | * | 
|  | 96 | * TBD: Can _PRTs exist within the scope of non-bridge PCI devices? | 
|  | 97 | */ | 
|  | 98 | status = acpi_get_handle(device->handle, METHOD_NAME__PRT, &handle); | 
| Alexander Chiang | 499650d | 2009-06-10 19:55:30 +0000 | [diff] [blame] | 99 | if (ACPI_FAILURE(status)) | 
|  | 100 | goto out; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 101 |  | 
| Alexander Chiang | 499650d | 2009-06-10 19:55:30 +0000 | [diff] [blame] | 102 | if (dev->subordinate) | 
| Alexander Chiang | 859a3f8 | 2009-06-10 19:55:35 +0000 | [diff] [blame] | 103 | bus = dev->subordinate; | 
| Alexander Chiang | 499650d | 2009-06-10 19:55:30 +0000 | [diff] [blame] | 104 | else | 
| Alexander Chiang | 859a3f8 | 2009-06-10 19:55:35 +0000 | [diff] [blame] | 105 | bus = dev->bus; | 
| Alexander Chiang | 499650d | 2009-06-10 19:55:30 +0000 | [diff] [blame] | 106 |  | 
| Alexander Chiang | 859a3f8 | 2009-06-10 19:55:35 +0000 | [diff] [blame] | 107 | acpi_pci_irq_add_prt(device->handle, bus); | 
| Alexander Chiang | 499650d | 2009-06-10 19:55:30 +0000 | [diff] [blame] | 108 |  | 
|  | 109 | out: | 
|  | 110 | pci_dev_put(dev); | 
|  | 111 | return 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 112 | } | 
|  | 113 |  | 
| Alexander Chiang | 499650d | 2009-06-10 19:55:30 +0000 | [diff] [blame] | 114 | int acpi_pci_bind_root(struct acpi_device *device) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 115 | { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 116 | device->ops.bind = acpi_pci_bind; | 
|  | 117 | device->ops.unbind = acpi_pci_unbind; | 
|  | 118 |  | 
| Alexander Chiang | 499650d | 2009-06-10 19:55:30 +0000 | [diff] [blame] | 119 | return 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 120 | } |