diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-04 21:04:29 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-04 21:04:29 -0400 |
commit | 89661adaaee2f85116b399e642129ccd4dafd195 (patch) | |
tree | 86a0bea62ef1ebbd454d5daa4deef1534ab5a222 /drivers/pci | |
parent | 6adae5d9e69743aede91b274224751811f7174f1 (diff) | |
parent | 9890b12a4a65a7b3181dd963421740edf0e14d69 (diff) |
Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/pci-2.6
* master.kernel.org:/pub/scm/linux/kernel/git/gregkh/pci-2.6: (59 commits)
PCI: Free resource files in error path of pci_create_sysfs_dev_files()
pci-quirks: disable MSI on RS400-200 and RS480
PCI hotplug: Use menuconfig objects
PCI: ZT5550 CPCI Hotplug driver fix
PCI: rpaphp: Remove semaphores
PCI: rpaphp: Ensure more pcibios_add/pcibios_remove symmetry
PCI: rpaphp: Use pcibios_remove_pci_devices() symmetrically
PCI: rpaphp: Document is_php_dn()
PCI: rpaphp: Document find_php_slot()
PCI: rpaphp: Rename rpaphp_register_pci_slot() to rpaphp_enable_slot()
PCI: rpaphp: refactor tail call to rpaphp_register_slot()
PCI: rpaphp: remove rpaphp_set_attention_status()
PCI: rpaphp: remove print_slot_pci_funcs()
PCI: rpaphp: Remove setup_pci_slot()
PCI: rpaphp: remove a call that does nothing but a pointer lookup
PCI: rpaphp: Remove another wrappered function
PCI: rpaphp: Remve another call that is a wrapper
PCI: rpaphp: remove a function that does nothing but wrap debug printks
PCI: rpaphp: Remove un-needed goto
PCI: rpaphp: Fix a memleak; slot->location string was never freed
...
Diffstat (limited to 'drivers/pci')
27 files changed, 787 insertions, 1025 deletions
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 5ea5bc70cb82..7a1d6d512837 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig | |||
@@ -1,10 +1,14 @@ | |||
1 | # | 1 | # |
2 | # PCI configuration | 2 | # PCI configuration |
3 | # | 3 | # |
4 | config ARCH_SUPPORTS_MSI | ||
5 | bool | ||
6 | default n | ||
7 | |||
4 | config PCI_MSI | 8 | config PCI_MSI |
5 | bool "Message Signaled Interrupts (MSI and MSI-X)" | 9 | bool "Message Signaled Interrupts (MSI and MSI-X)" |
6 | depends on PCI | 10 | depends on PCI |
7 | depends on (X86_LOCAL_APIC && X86_IO_APIC) || IA64 || SPARC64 | 11 | depends on ARCH_SUPPORTS_MSI |
8 | help | 12 | help |
9 | This allows device drivers to enable MSI (Message Signaled | 13 | This allows device drivers to enable MSI (Message Signaled |
10 | Interrupts). Message Signaled Interrupts enable a device to | 14 | Interrupts). Message Signaled Interrupts enable a device to |
@@ -17,31 +21,6 @@ config PCI_MSI | |||
17 | 21 | ||
18 | If you don't know what to do here, say N. | 22 | If you don't know what to do here, say N. |
19 | 23 | ||
20 | config PCI_MULTITHREAD_PROBE | ||
21 | bool "PCI Multi-threaded probe (EXPERIMENTAL)" | ||
22 | depends on PCI && EXPERIMENTAL && BROKEN | ||
23 | help | ||
24 | Say Y here if you want the PCI core to spawn a new thread for | ||
25 | every PCI device that is probed. This can cause a huge | ||
26 | speedup in boot times on multiprocessor machines, and even a | ||
27 | smaller speedup on single processor machines. | ||
28 | |||
29 | But it can also cause lots of bad things to happen. A number | ||
30 | of PCI drivers cannot properly handle running in this way, | ||
31 | some will just not work properly at all, while others might | ||
32 | decide to blow up power supplies with a huge load all at once, | ||
33 | so use this option at your own risk. | ||
34 | |||
35 | It is very unwise to use this option if you are not using a | ||
36 | boot process that can handle devices being created in any | ||
37 | order. A program that can create persistent block and network | ||
38 | device names (like udev) is a good idea if you wish to use | ||
39 | this option. | ||
40 | |||
41 | Again, use this option at your own risk, you have been warned! | ||
42 | |||
43 | When in doubt, say N. | ||
44 | |||
45 | config PCI_DEBUG | 24 | config PCI_DEBUG |
46 | bool "PCI Debugging" | 25 | bool "PCI Debugging" |
47 | depends on PCI && DEBUG_KERNEL | 26 | depends on PCI && DEBUG_KERNEL |
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index aadaa3c8096b..9e5ea074ad20 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c | |||
@@ -77,7 +77,7 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, | |||
77 | * This adds a single pci device to the global | 77 | * This adds a single pci device to the global |
78 | * device list and adds sysfs and procfs entries | 78 | * device list and adds sysfs and procfs entries |
79 | */ | 79 | */ |
80 | int __devinit pci_bus_add_device(struct pci_dev *dev) | 80 | int pci_bus_add_device(struct pci_dev *dev) |
81 | { | 81 | { |
82 | int retval; | 82 | int retval; |
83 | retval = device_add(&dev->dev); | 83 | retval = device_add(&dev->dev); |
@@ -105,7 +105,7 @@ int __devinit pci_bus_add_device(struct pci_dev *dev) | |||
105 | * | 105 | * |
106 | * Call hotplug for each new devices. | 106 | * Call hotplug for each new devices. |
107 | */ | 107 | */ |
108 | void __devinit pci_bus_add_devices(struct pci_bus *bus) | 108 | void pci_bus_add_devices(struct pci_bus *bus) |
109 | { | 109 | { |
110 | struct pci_dev *dev; | 110 | struct pci_dev *dev; |
111 | int retval; | 111 | int retval; |
diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig index be92695a7833..63d62752fb91 100644 --- a/drivers/pci/hotplug/Kconfig +++ b/drivers/pci/hotplug/Kconfig | |||
@@ -2,9 +2,7 @@ | |||
2 | # PCI Hotplug support | 2 | # PCI Hotplug support |
3 | # | 3 | # |
4 | 4 | ||
5 | menu "PCI Hotplug Support" | 5 | menuconfig HOTPLUG_PCI |
6 | |||
7 | config HOTPLUG_PCI | ||
8 | tristate "Support for PCI Hotplug (EXPERIMENTAL)" | 6 | tristate "Support for PCI Hotplug (EXPERIMENTAL)" |
9 | depends on PCI && EXPERIMENTAL && HOTPLUG | 7 | depends on PCI && EXPERIMENTAL && HOTPLUG |
10 | ---help--- | 8 | ---help--- |
@@ -17,9 +15,10 @@ config HOTPLUG_PCI | |||
17 | 15 | ||
18 | When in doubt, say N. | 16 | When in doubt, say N. |
19 | 17 | ||
18 | if HOTPLUG_PCI | ||
19 | |||
20 | config HOTPLUG_PCI_FAKE | 20 | config HOTPLUG_PCI_FAKE |
21 | tristate "Fake PCI Hotplug driver" | 21 | tristate "Fake PCI Hotplug driver" |
22 | depends on HOTPLUG_PCI | ||
23 | help | 22 | help |
24 | Say Y here if you want to use the fake PCI hotplug driver. It can | 23 | Say Y here if you want to use the fake PCI hotplug driver. It can |
25 | be used to simulate PCI hotplug events if even if your system is | 24 | be used to simulate PCI hotplug events if even if your system is |
@@ -42,7 +41,7 @@ config HOTPLUG_PCI_FAKE | |||
42 | 41 | ||
43 | config HOTPLUG_PCI_COMPAQ | 42 | config HOTPLUG_PCI_COMPAQ |
44 | tristate "Compaq PCI Hotplug driver" | 43 | tristate "Compaq PCI Hotplug driver" |
45 | depends on HOTPLUG_PCI && X86 && PCI_BIOS | 44 | depends on X86 && PCI_BIOS |
46 | help | 45 | help |
47 | Say Y here if you have a motherboard with a Compaq PCI Hotplug | 46 | Say Y here if you have a motherboard with a Compaq PCI Hotplug |
48 | controller. | 47 | controller. |
@@ -64,7 +63,7 @@ config HOTPLUG_PCI_COMPAQ_NVRAM | |||
64 | 63 | ||
65 | config HOTPLUG_PCI_IBM | 64 | config HOTPLUG_PCI_IBM |
66 | tristate "IBM PCI Hotplug driver" | 65 | tristate "IBM PCI Hotplug driver" |
67 | depends on HOTPLUG_PCI && X86_IO_APIC && X86 && PCI_BIOS | 66 | depends on X86_IO_APIC && X86 && PCI_BIOS |
68 | help | 67 | help |
69 | Say Y here if you have a motherboard with a IBM PCI Hotplug | 68 | Say Y here if you have a motherboard with a IBM PCI Hotplug |
70 | controller. | 69 | controller. |
@@ -76,7 +75,6 @@ config HOTPLUG_PCI_IBM | |||
76 | 75 | ||
77 | config HOTPLUG_PCI_ACPI | 76 | config HOTPLUG_PCI_ACPI |
78 | tristate "ACPI PCI Hotplug driver" | 77 | tristate "ACPI PCI Hotplug driver" |
79 | depends on HOTPLUG_PCI | ||
80 | depends on (!ACPI_DOCK && ACPI) || (ACPI_DOCK) | 78 | depends on (!ACPI_DOCK && ACPI) || (ACPI_DOCK) |
81 | help | 79 | help |
82 | Say Y here if you have a system that supports PCI Hotplug using | 80 | Say Y here if you have a system that supports PCI Hotplug using |
@@ -101,7 +99,6 @@ config HOTPLUG_PCI_ACPI_IBM | |||
101 | 99 | ||
102 | config HOTPLUG_PCI_CPCI | 100 | config HOTPLUG_PCI_CPCI |
103 | bool "CompactPCI Hotplug driver" | 101 | bool "CompactPCI Hotplug driver" |
104 | depends on HOTPLUG_PCI | ||
105 | help | 102 | help |
106 | Say Y here if you have a CompactPCI system card with CompactPCI | 103 | Say Y here if you have a CompactPCI system card with CompactPCI |
107 | hotswap support per the PICMG 2.1 specification. | 104 | hotswap support per the PICMG 2.1 specification. |
@@ -110,7 +107,7 @@ config HOTPLUG_PCI_CPCI | |||
110 | 107 | ||
111 | config HOTPLUG_PCI_CPCI_ZT5550 | 108 | config HOTPLUG_PCI_CPCI_ZT5550 |
112 | tristate "Ziatech ZT5550 CompactPCI Hotplug driver" | 109 | tristate "Ziatech ZT5550 CompactPCI Hotplug driver" |
113 | depends on HOTPLUG_PCI && HOTPLUG_PCI_CPCI && X86 | 110 | depends on HOTPLUG_PCI_CPCI && X86 |
114 | help | 111 | help |
115 | Say Y here if you have an Performance Technologies (formerly Intel, | 112 | Say Y here if you have an Performance Technologies (formerly Intel, |
116 | formerly just Ziatech) Ziatech ZT5550 CompactPCI system card. | 113 | formerly just Ziatech) Ziatech ZT5550 CompactPCI system card. |
@@ -122,7 +119,7 @@ config HOTPLUG_PCI_CPCI_ZT5550 | |||
122 | 119 | ||
123 | config HOTPLUG_PCI_CPCI_GENERIC | 120 | config HOTPLUG_PCI_CPCI_GENERIC |
124 | tristate "Generic port I/O CompactPCI Hotplug driver" | 121 | tristate "Generic port I/O CompactPCI Hotplug driver" |
125 | depends on HOTPLUG_PCI && HOTPLUG_PCI_CPCI && X86 | 122 | depends on HOTPLUG_PCI_CPCI && X86 |
126 | help | 123 | help |
127 | Say Y here if you have a CompactPCI system card that exposes the #ENUM | 124 | Say Y here if you have a CompactPCI system card that exposes the #ENUM |
128 | hotswap signal as a bit in a system register that can be read through | 125 | hotswap signal as a bit in a system register that can be read through |
@@ -135,7 +132,6 @@ config HOTPLUG_PCI_CPCI_GENERIC | |||
135 | 132 | ||
136 | config HOTPLUG_PCI_SHPC | 133 | config HOTPLUG_PCI_SHPC |
137 | tristate "SHPC PCI Hotplug driver" | 134 | tristate "SHPC PCI Hotplug driver" |
138 | depends on HOTPLUG_PCI | ||
139 | help | 135 | help |
140 | Say Y here if you have a motherboard with a SHPC PCI Hotplug | 136 | Say Y here if you have a motherboard with a SHPC PCI Hotplug |
141 | controller. | 137 | controller. |
@@ -147,7 +143,7 @@ config HOTPLUG_PCI_SHPC | |||
147 | 143 | ||
148 | config HOTPLUG_PCI_RPA | 144 | config HOTPLUG_PCI_RPA |
149 | tristate "RPA PCI Hotplug driver" | 145 | tristate "RPA PCI Hotplug driver" |
150 | depends on HOTPLUG_PCI && PPC_PSERIES && PPC64 && !HOTPLUG_PCI_FAKE | 146 | depends on PPC_PSERIES && PPC64 && !HOTPLUG_PCI_FAKE |
151 | help | 147 | help |
152 | Say Y here if you have a RPA system that supports PCI Hotplug. | 148 | Say Y here if you have a RPA system that supports PCI Hotplug. |
153 | 149 | ||
@@ -170,12 +166,11 @@ config HOTPLUG_PCI_RPA_DLPAR | |||
170 | 166 | ||
171 | config HOTPLUG_PCI_SGI | 167 | config HOTPLUG_PCI_SGI |
172 | tristate "SGI PCI Hotplug Support" | 168 | tristate "SGI PCI Hotplug Support" |
173 | depends on HOTPLUG_PCI && (IA64_SGI_SN2 || IA64_GENERIC) | 169 | depends on IA64_SGI_SN2 || IA64_GENERIC |
174 | help | 170 | help |
175 | Say Y here if you want to use the SGI Altix Hotplug | 171 | Say Y here if you want to use the SGI Altix Hotplug |
176 | Driver for PCI devices. | 172 | Driver for PCI devices. |
177 | 173 | ||
178 | When in doubt, say N. | 174 | When in doubt, say N. |
179 | 175 | ||
180 | endmenu | 176 | endif # HOTPLUG_PCI |
181 | |||
diff --git a/drivers/pci/hotplug/cpcihp_zt5550.c b/drivers/pci/hotplug/cpcihp_zt5550.c index 1c12e9171097..41f6a8d79c81 100644 --- a/drivers/pci/hotplug/cpcihp_zt5550.c +++ b/drivers/pci/hotplug/cpcihp_zt5550.c | |||
@@ -296,13 +296,17 @@ static struct pci_driver zt5550_hc_driver = { | |||
296 | static int __init zt5550_init(void) | 296 | static int __init zt5550_init(void) |
297 | { | 297 | { |
298 | struct resource* r; | 298 | struct resource* r; |
299 | int rc; | ||
299 | 300 | ||
300 | info(DRIVER_DESC " version: " DRIVER_VERSION); | 301 | info(DRIVER_DESC " version: " DRIVER_VERSION); |
301 | r = request_region(ENUM_PORT, 1, "#ENUM hotswap signal register"); | 302 | r = request_region(ENUM_PORT, 1, "#ENUM hotswap signal register"); |
302 | if(!r) | 303 | if(!r) |
303 | return -EBUSY; | 304 | return -EBUSY; |
304 | 305 | ||
305 | return pci_register_driver(&zt5550_hc_driver); | 306 | rc = pci_register_driver(&zt5550_hc_driver); |
307 | if(rc < 0) | ||
308 | release_region(ENUM_PORT, 1); | ||
309 | return rc; | ||
306 | } | 310 | } |
307 | 311 | ||
308 | static void __exit | 312 | static void __exit |
diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c index e27907c91d92..027f6865d7e3 100644 --- a/drivers/pci/hotplug/fakephp.c +++ b/drivers/pci/hotplug/fakephp.c | |||
@@ -238,7 +238,7 @@ static void pci_rescan_bus(const struct pci_bus *bus) | |||
238 | { | 238 | { |
239 | unsigned int devfn; | 239 | unsigned int devfn; |
240 | struct pci_dev *dev; | 240 | struct pci_dev *dev; |
241 | dev = kzalloc(sizeof(struct pci_dev), GFP_KERNEL); | 241 | dev = alloc_pci_dev(); |
242 | if (!dev) | 242 | if (!dev) |
243 | return; | 243 | return; |
244 | 244 | ||
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index d19fcae8a7c0..ccc57627201e 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h | |||
@@ -43,6 +43,7 @@ extern int pciehp_poll_mode; | |||
43 | extern int pciehp_poll_time; | 43 | extern int pciehp_poll_time; |
44 | extern int pciehp_debug; | 44 | extern int pciehp_debug; |
45 | extern int pciehp_force; | 45 | extern int pciehp_force; |
46 | extern struct workqueue_struct *pciehp_wq; | ||
46 | 47 | ||
47 | #define dbg(format, arg...) \ | 48 | #define dbg(format, arg...) \ |
48 | do { \ | 49 | do { \ |
@@ -70,14 +71,16 @@ struct slot { | |||
70 | struct list_head slot_list; | 71 | struct list_head slot_list; |
71 | char name[SLOT_NAME_SIZE]; | 72 | char name[SLOT_NAME_SIZE]; |
72 | unsigned long last_emi_toggle; | 73 | unsigned long last_emi_toggle; |
74 | struct delayed_work work; /* work for button event */ | ||
75 | struct mutex lock; | ||
73 | }; | 76 | }; |
74 | 77 | ||
75 | struct event_info { | 78 | struct event_info { |
76 | u32 event_type; | 79 | u32 event_type; |
77 | u8 hp_slot; | 80 | struct slot *p_slot; |
81 | struct work_struct work; | ||
78 | }; | 82 | }; |
79 | 83 | ||
80 | #define MAX_EVENTS 10 | ||
81 | struct controller { | 84 | struct controller { |
82 | struct controller *next; | 85 | struct controller *next; |
83 | struct mutex crit_sect; /* critical section mutex */ | 86 | struct mutex crit_sect; /* critical section mutex */ |
@@ -86,11 +89,9 @@ struct controller { | |||
86 | int slot_num_inc; /* 1 or -1 */ | 89 | int slot_num_inc; /* 1 or -1 */ |
87 | struct pci_dev *pci_dev; | 90 | struct pci_dev *pci_dev; |
88 | struct list_head slot_list; | 91 | struct list_head slot_list; |
89 | struct event_info event_queue[MAX_EVENTS]; | ||
90 | struct slot *slot; | 92 | struct slot *slot; |
91 | struct hpc_ops *hpc_ops; | 93 | struct hpc_ops *hpc_ops; |
92 | wait_queue_head_t queue; /* sleep & wake process */ | 94 | wait_queue_head_t queue; /* sleep & wake process */ |
93 | u8 next_event; | ||
94 | u8 bus; | 95 | u8 bus; |
95 | u8 device; | 96 | u8 device; |
96 | u8 function; | 97 | u8 function; |
@@ -149,21 +150,17 @@ struct controller { | |||
149 | #define HP_SUPR_RM(cap) (cap & HP_SUPR_RM_SUP) | 150 | #define HP_SUPR_RM(cap) (cap & HP_SUPR_RM_SUP) |
150 | #define EMI(cap) (cap & EMI_PRSN) | 151 | #define EMI(cap) (cap & EMI_PRSN) |
151 | 152 | ||
152 | extern int pciehp_event_start_thread(void); | 153 | extern int pciehp_sysfs_enable_slot(struct slot *slot); |
153 | extern void pciehp_event_stop_thread(void); | 154 | extern int pciehp_sysfs_disable_slot(struct slot *slot); |
154 | extern int pciehp_enable_slot(struct slot *slot); | ||
155 | extern int pciehp_disable_slot(struct slot *slot); | ||
156 | extern u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl); | 155 | extern u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl); |
157 | extern u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl); | 156 | extern u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl); |
158 | extern u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl); | 157 | extern u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl); |
159 | extern u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl); | 158 | extern u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl); |
160 | extern int pciehp_configure_device(struct slot *p_slot); | 159 | extern int pciehp_configure_device(struct slot *p_slot); |
161 | extern int pciehp_unconfigure_device(struct slot *p_slot); | 160 | extern int pciehp_unconfigure_device(struct slot *p_slot); |
161 | extern void pciehp_queue_pushbutton_work(struct work_struct *work); | ||
162 | int pcie_init(struct controller *ctrl, struct pcie_device *dev); | 162 | int pcie_init(struct controller *ctrl, struct pcie_device *dev); |
163 | 163 | ||
164 | /* Global variables */ | ||
165 | extern struct controller *pciehp_ctrl_list; | ||
166 | |||
167 | static inline struct slot *pciehp_find_slot(struct controller *ctrl, u8 device) | 164 | static inline struct slot *pciehp_find_slot(struct controller *ctrl, u8 device) |
168 | { | 165 | { |
169 | struct slot *slot; | 166 | struct slot *slot; |
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index a92eda6e02f6..e5d3f0b4f45a 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c | |||
@@ -41,7 +41,7 @@ int pciehp_debug; | |||
41 | int pciehp_poll_mode; | 41 | int pciehp_poll_mode; |
42 | int pciehp_poll_time; | 42 | int pciehp_poll_time; |
43 | int pciehp_force; | 43 | int pciehp_force; |
44 | struct controller *pciehp_ctrl_list; | 44 | struct workqueue_struct *pciehp_wq; |
45 | 45 | ||
46 | #define DRIVER_VERSION "0.4" | 46 | #define DRIVER_VERSION "0.4" |
47 | #define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>" | 47 | #define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>" |
@@ -62,7 +62,6 @@ MODULE_PARM_DESC(pciehp_force, "Force pciehp, even if _OSC and OSHP are missing" | |||
62 | 62 | ||
63 | #define PCIE_MODULE_NAME "pciehp" | 63 | #define PCIE_MODULE_NAME "pciehp" |
64 | 64 | ||
65 | static int pcie_start_thread (void); | ||
66 | static int set_attention_status (struct hotplug_slot *slot, u8 value); | 65 | static int set_attention_status (struct hotplug_slot *slot, u8 value); |
67 | static int enable_slot (struct hotplug_slot *slot); | 66 | static int enable_slot (struct hotplug_slot *slot); |
68 | static int disable_slot (struct hotplug_slot *slot); | 67 | static int disable_slot (struct hotplug_slot *slot); |
@@ -229,6 +228,8 @@ static int init_slots(struct controller *ctrl) | |||
229 | slot->device = ctrl->slot_device_offset + i; | 228 | slot->device = ctrl->slot_device_offset + i; |
230 | slot->hpc_ops = ctrl->hpc_ops; | 229 | slot->hpc_ops = ctrl->hpc_ops; |
231 | slot->number = ctrl->first_slot; | 230 | slot->number = ctrl->first_slot; |
231 | mutex_init(&slot->lock); | ||
232 | INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work); | ||
232 | 233 | ||
233 | /* register this slot with the hotplug pci core */ | 234 | /* register this slot with the hotplug pci core */ |
234 | hotplug_slot->private = slot; | 235 | hotplug_slot->private = slot; |
@@ -286,6 +287,9 @@ static void cleanup_slots(struct controller *ctrl) | |||
286 | if (EMI(ctrl->ctrlcap)) | 287 | if (EMI(ctrl->ctrlcap)) |
287 | sysfs_remove_file(&slot->hotplug_slot->kobj, | 288 | sysfs_remove_file(&slot->hotplug_slot->kobj, |
288 | &hotplug_slot_attr_lock.attr); | 289 | &hotplug_slot_attr_lock.attr); |
290 | cancel_delayed_work(&slot->work); | ||
291 | flush_scheduled_work(); | ||
292 | flush_workqueue(pciehp_wq); | ||
289 | pci_hp_deregister(slot->hotplug_slot); | 293 | pci_hp_deregister(slot->hotplug_slot); |
290 | } | 294 | } |
291 | } | 295 | } |
@@ -314,7 +318,7 @@ static int enable_slot(struct hotplug_slot *hotplug_slot) | |||
314 | 318 | ||
315 | dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); | 319 | dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); |
316 | 320 | ||
317 | return pciehp_enable_slot(slot); | 321 | return pciehp_sysfs_enable_slot(slot); |
318 | } | 322 | } |
319 | 323 | ||
320 | 324 | ||
@@ -324,7 +328,7 @@ static int disable_slot(struct hotplug_slot *hotplug_slot) | |||
324 | 328 | ||
325 | dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); | 329 | dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); |
326 | 330 | ||
327 | return pciehp_disable_slot(slot); | 331 | return pciehp_sysfs_disable_slot(slot); |
328 | } | 332 | } |
329 | 333 | ||
330 | static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) | 334 | static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) |
@@ -466,17 +470,6 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ | |||
466 | 470 | ||
467 | t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset); | 471 | t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset); |
468 | 472 | ||
469 | /* Finish setting up the hot plug ctrl device */ | ||
470 | ctrl->next_event = 0; | ||
471 | |||
472 | if (!pciehp_ctrl_list) { | ||
473 | pciehp_ctrl_list = ctrl; | ||
474 | ctrl->next = NULL; | ||
475 | } else { | ||
476 | ctrl->next = pciehp_ctrl_list; | ||
477 | pciehp_ctrl_list = ctrl; | ||
478 | } | ||
479 | |||
480 | t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */ | 473 | t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */ |
481 | if ((POWER_CTRL(ctrl->ctrlcap)) && !value) { | 474 | if ((POWER_CTRL(ctrl->ctrlcap)) && !value) { |
482 | rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/ | 475 | rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/ |
@@ -496,48 +489,14 @@ err_out_none: | |||
496 | return -ENODEV; | 489 | return -ENODEV; |
497 | } | 490 | } |
498 | 491 | ||
499 | 492 | static void pciehp_remove (struct pcie_device *dev) | |
500 | static int pcie_start_thread(void) | ||
501 | { | 493 | { |
502 | int retval = 0; | 494 | struct pci_dev *pdev = dev->port; |
503 | 495 | struct controller *ctrl = pci_get_drvdata(pdev); | |
504 | dbg("Initialize + Start the notification/polling mechanism \n"); | ||
505 | |||
506 | retval = pciehp_event_start_thread(); | ||
507 | if (retval) { | ||
508 | dbg("pciehp_event_start_thread() failed\n"); | ||
509 | return retval; | ||
510 | } | ||
511 | |||
512 | return retval; | ||
513 | } | ||
514 | |||
515 | static void __exit unload_pciehpd(void) | ||
516 | { | ||
517 | struct controller *ctrl; | ||
518 | struct controller *tctrl; | ||
519 | |||
520 | ctrl = pciehp_ctrl_list; | ||
521 | |||
522 | while (ctrl) { | ||
523 | cleanup_slots(ctrl); | ||
524 | 496 | ||
525 | ctrl->hpc_ops->release_ctlr(ctrl); | 497 | cleanup_slots(ctrl); |
526 | 498 | ctrl->hpc_ops->release_ctlr(ctrl); | |
527 | tctrl = ctrl; | 499 | kfree(ctrl); |
528 | ctrl = ctrl->next; | ||
529 | |||
530 | kfree(tctrl); | ||
531 | } | ||
532 | |||
533 | /* Stop the notification mechanism */ | ||
534 | pciehp_event_stop_thread(); | ||
535 | |||
536 | } | ||
537 | |||
538 | static void pciehp_remove (struct pcie_device *device) | ||
539 | { | ||
540 | /* XXX - Needs to be adapted to device driver model */ | ||
541 | } | 500 | } |
542 | 501 | ||
543 | #ifdef CONFIG_PM | 502 | #ifdef CONFIG_PM |
@@ -585,31 +544,18 @@ static int __init pcied_init(void) | |||
585 | pciehp_poll_mode = 1; | 544 | pciehp_poll_mode = 1; |
586 | #endif | 545 | #endif |
587 | 546 | ||
588 | retval = pcie_start_thread(); | ||
589 | if (retval) | ||
590 | goto error_hpc_init; | ||
591 | |||
592 | retval = pcie_port_service_register(&hpdriver_portdrv); | 547 | retval = pcie_port_service_register(&hpdriver_portdrv); |
593 | dbg("pcie_port_service_register = %d\n", retval); | 548 | dbg("pcie_port_service_register = %d\n", retval); |
594 | info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); | 549 | info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); |
595 | if (retval) | 550 | if (retval) |
596 | dbg("%s: Failure to register service\n", __FUNCTION__); | 551 | dbg("%s: Failure to register service\n", __FUNCTION__); |
597 | |||
598 | error_hpc_init: | ||
599 | if (retval) { | ||
600 | pciehp_event_stop_thread(); | ||
601 | }; | ||
602 | |||
603 | return retval; | 552 | return retval; |
604 | } | 553 | } |
605 | 554 | ||
606 | static void __exit pcied_cleanup(void) | 555 | static void __exit pcied_cleanup(void) |
607 | { | 556 | { |
608 | dbg("unload_pciehpd()\n"); | 557 | dbg("unload_pciehpd()\n"); |
609 | unload_pciehpd(); | ||
610 | |||
611 | pcie_port_service_unregister(&hpdriver_portdrv); | 558 | pcie_port_service_unregister(&hpdriver_portdrv); |
612 | |||
613 | info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n"); | 559 | info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n"); |
614 | } | 560 | } |
615 | 561 | ||
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index 4283ef56dbd9..7f22caa70178 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c | |||
@@ -32,92 +32,61 @@ | |||
32 | #include <linux/types.h> | 32 | #include <linux/types.h> |
33 | #include <linux/smp_lock.h> | 33 | #include <linux/smp_lock.h> |
34 | #include <linux/pci.h> | 34 | #include <linux/pci.h> |
35 | #include <linux/workqueue.h> | ||
35 | #include "../pci.h" | 36 | #include "../pci.h" |
36 | #include "pciehp.h" | 37 | #include "pciehp.h" |
37 | 38 | ||
38 | static void interrupt_event_handler(struct controller *ctrl); | 39 | static void interrupt_event_handler(struct work_struct *work); |
40 | static int pciehp_enable_slot(struct slot *p_slot); | ||
41 | static int pciehp_disable_slot(struct slot *p_slot); | ||
39 | 42 | ||
40 | static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */ | 43 | static int queue_interrupt_event(struct slot *p_slot, u32 event_type) |
41 | static struct semaphore event_exit; /* guard ensure thread has exited before calling it quits */ | ||
42 | static int event_finished; | ||
43 | static unsigned long pushbutton_pending; /* = 0 */ | ||
44 | static unsigned long surprise_rm_pending; /* = 0 */ | ||
45 | |||
46 | static inline char *slot_name(struct slot *p_slot) | ||
47 | { | 44 | { |
48 | return p_slot->hotplug_slot->name; | 45 | struct event_info *info; |
46 | |||
47 | info = kmalloc(sizeof(*info), GFP_ATOMIC); | ||
48 | if (!info) | ||
49 | return -ENOMEM; | ||
50 | |||
51 | info->event_type = event_type; | ||
52 | info->p_slot = p_slot; | ||
53 | INIT_WORK(&info->work, interrupt_event_handler); | ||
54 | |||
55 | schedule_work(&info->work); | ||
56 | |||
57 | return 0; | ||
49 | } | 58 | } |
50 | 59 | ||
51 | u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl) | 60 | u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl) |
52 | { | 61 | { |
53 | struct slot *p_slot; | 62 | struct slot *p_slot; |
54 | u8 rc = 0; | 63 | u32 event_type; |
55 | u8 getstatus; | ||
56 | struct event_info *taskInfo; | ||
57 | 64 | ||
58 | /* Attention Button Change */ | 65 | /* Attention Button Change */ |
59 | dbg("pciehp: Attention button interrupt received.\n"); | 66 | dbg("pciehp: Attention button interrupt received.\n"); |
60 | |||
61 | /* This is the structure that tells the worker thread what to do */ | ||
62 | taskInfo = &(ctrl->event_queue[ctrl->next_event]); | ||
63 | p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); | ||
64 | |||
65 | p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); | ||
66 | |||
67 | ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS; | ||
68 | taskInfo->hp_slot = hp_slot; | ||
69 | 67 | ||
70 | rc++; | 68 | p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); |
71 | 69 | ||
72 | /* | 70 | /* |
73 | * Button pressed - See if need to TAKE ACTION!!! | 71 | * Button pressed - See if need to TAKE ACTION!!! |
74 | */ | 72 | */ |
75 | info("Button pressed on Slot(%s)\n", slot_name(p_slot)); | 73 | info("Button pressed on Slot(%s)\n", p_slot->name); |
76 | taskInfo->event_type = INT_BUTTON_PRESS; | 74 | event_type = INT_BUTTON_PRESS; |
77 | |||
78 | if ((p_slot->state == BLINKINGON_STATE) | ||
79 | || (p_slot->state == BLINKINGOFF_STATE)) { | ||
80 | /* Cancel if we are still blinking; this means that we press the | ||
81 | * attention again before the 5 sec. limit expires to cancel hot-add | ||
82 | * or hot-remove | ||
83 | */ | ||
84 | taskInfo->event_type = INT_BUTTON_CANCEL; | ||
85 | info("Button cancel on Slot(%s)\n", slot_name(p_slot)); | ||
86 | } else if ((p_slot->state == POWERON_STATE) | ||
87 | || (p_slot->state == POWEROFF_STATE)) { | ||
88 | /* Ignore if the slot is on power-on or power-off state; this | ||
89 | * means that the previous attention button action to hot-add or | ||
90 | * hot-remove is undergoing | ||
91 | */ | ||
92 | taskInfo->event_type = INT_BUTTON_IGNORE; | ||
93 | info("Button ignore on Slot(%s)\n", slot_name(p_slot)); | ||
94 | } | ||
95 | 75 | ||
96 | if (rc) | 76 | queue_interrupt_event(p_slot, event_type); |
97 | up(&event_semaphore); /* signal event thread that new event is posted */ | ||
98 | 77 | ||
99 | return 0; | 78 | return 0; |
100 | |||
101 | } | 79 | } |
102 | 80 | ||
103 | u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl) | 81 | u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl) |
104 | { | 82 | { |
105 | struct slot *p_slot; | 83 | struct slot *p_slot; |
106 | u8 rc = 0; | ||
107 | u8 getstatus; | 84 | u8 getstatus; |
108 | struct event_info *taskInfo; | 85 | u32 event_type; |
109 | 86 | ||
110 | /* Switch Change */ | 87 | /* Switch Change */ |
111 | dbg("pciehp: Switch interrupt received.\n"); | 88 | dbg("pciehp: Switch interrupt received.\n"); |
112 | 89 | ||
113 | /* This is the structure that tells the worker thread | ||
114 | * what to do | ||
115 | */ | ||
116 | taskInfo = &(ctrl->event_queue[ctrl->next_event]); | ||
117 | ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS; | ||
118 | taskInfo->hp_slot = hp_slot; | ||
119 | |||
120 | rc++; | ||
121 | p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); | 90 | p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); |
122 | p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); | 91 | p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); |
123 | 92 | ||
@@ -125,39 +94,30 @@ u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl) | |||
125 | /* | 94 | /* |
126 | * Switch opened | 95 | * Switch opened |
127 | */ | 96 | */ |
128 | info("Latch open on Slot(%s)\n", slot_name(p_slot)); | 97 | info("Latch open on Slot(%s)\n", p_slot->name); |
129 | taskInfo->event_type = INT_SWITCH_OPEN; | 98 | event_type = INT_SWITCH_OPEN; |
130 | } else { | 99 | } else { |
131 | /* | 100 | /* |
132 | * Switch closed | 101 | * Switch closed |
133 | */ | 102 | */ |
134 | info("Latch close on Slot(%s)\n", slot_name(p_slot)); | 103 | info("Latch close on Slot(%s)\n", p_slot->name); |
135 | taskInfo->event_type = INT_SWITCH_CLOSE; | 104 | event_type = INT_SWITCH_CLOSE; |
136 | } | 105 | } |
137 | 106 | ||
138 | if (rc) | 107 | queue_interrupt_event(p_slot, event_type); |
139 | up(&event_semaphore); /* signal event thread that new event is posted */ | ||
140 | 108 | ||
141 | return rc; | 109 | return 1; |
142 | } | 110 | } |
143 | 111 | ||
144 | u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl) | 112 | u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl) |
145 | { | 113 | { |
146 | struct slot *p_slot; | 114 | struct slot *p_slot; |
147 | u8 presence_save, rc = 0; | 115 | u32 event_type; |
148 | struct event_info *taskInfo; | 116 | u8 presence_save; |
149 | 117 | ||
150 | /* Presence Change */ | 118 | /* Presence Change */ |
151 | dbg("pciehp: Presence/Notify input change.\n"); | 119 | dbg("pciehp: Presence/Notify input change.\n"); |
152 | 120 | ||
153 | /* This is the structure that tells the worker thread | ||
154 | * what to do | ||
155 | */ | ||
156 | taskInfo = &(ctrl->event_queue[ctrl->next_event]); | ||
157 | ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS; | ||
158 | taskInfo->hp_slot = hp_slot; | ||
159 | |||
160 | rc++; | ||
161 | p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); | 121 | p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); |
162 | 122 | ||
163 | /* Switch is open, assume a presence change | 123 | /* Switch is open, assume a presence change |
@@ -168,59 +128,49 @@ u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl) | |||
168 | /* | 128 | /* |
169 | * Card Present | 129 | * Card Present |
170 | */ | 130 | */ |
171 | info("Card present on Slot(%s)\n", slot_name(p_slot)); | 131 | info("Card present on Slot(%s)\n", p_slot->name); |
172 | taskInfo->event_type = INT_PRESENCE_ON; | 132 | event_type = INT_PRESENCE_ON; |
173 | } else { | 133 | } else { |
174 | /* | 134 | /* |
175 | * Not Present | 135 | * Not Present |
176 | */ | 136 | */ |
177 | info("Card not present on Slot(%s)\n", slot_name(p_slot)); | 137 | info("Card not present on Slot(%s)\n", p_slot->name); |
178 | taskInfo->event_type = INT_PRESENCE_OFF; | 138 | event_type = INT_PRESENCE_OFF; |
179 | } | 139 | } |
180 | 140 | ||
181 | if (rc) | 141 | queue_interrupt_event(p_slot, event_type); |
182 | up(&event_semaphore); /* signal event thread that new event is posted */ | ||
183 | 142 | ||
184 | return rc; | 143 | return 1; |
185 | } | 144 | } |
186 | 145 | ||
187 | u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl) | 146 | u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl) |
188 | { | 147 | { |
189 | struct slot *p_slot; | 148 | struct slot *p_slot; |
190 | u8 rc = 0; | 149 | u32 event_type; |
191 | struct event_info *taskInfo; | ||
192 | 150 | ||
193 | /* power fault */ | 151 | /* power fault */ |
194 | dbg("pciehp: Power fault interrupt received.\n"); | 152 | dbg("pciehp: Power fault interrupt received.\n"); |
195 | 153 | ||
196 | /* this is the structure that tells the worker thread | ||
197 | * what to do | ||
198 | */ | ||
199 | taskInfo = &(ctrl->event_queue[ctrl->next_event]); | ||
200 | ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS; | ||
201 | taskInfo->hp_slot = hp_slot; | ||
202 | |||
203 | rc++; | ||
204 | p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); | 154 | p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); |
205 | 155 | ||
206 | if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) { | 156 | if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) { |
207 | /* | 157 | /* |
208 | * power fault Cleared | 158 | * power fault Cleared |
209 | */ | 159 | */ |
210 | info("Power fault cleared on Slot(%s)\n", slot_name(p_slot)); | 160 | info("Power fault cleared on Slot(%s)\n", p_slot->name); |
211 | taskInfo->event_type = INT_POWER_FAULT_CLEAR; | 161 | event_type = INT_POWER_FAULT_CLEAR; |
212 | } else { | 162 | } else { |
213 | /* | 163 | /* |
214 | * power fault | 164 | * power fault |
215 | */ | 165 | */ |
216 | info("Power fault on Slot(%s)\n", slot_name(p_slot)); | 166 | info("Power fault on Slot(%s)\n", p_slot->name); |
217 | taskInfo->event_type = INT_POWER_FAULT; | 167 | event_type = INT_POWER_FAULT; |
218 | info("power fault bit %x set\n", hp_slot); | 168 | info("power fault bit %x set\n", hp_slot); |
219 | } | 169 | } |
220 | if (rc) | ||
221 | up(&event_semaphore); /* signal event thread that new event is posted */ | ||
222 | 170 | ||
223 | return rc; | 171 | queue_interrupt_event(p_slot, event_type); |
172 | |||
173 | return 1; | ||
224 | } | 174 | } |
225 | 175 | ||
226 | /* The following routines constitute the bulk of the | 176 | /* The following routines constitute the bulk of the |
@@ -357,13 +307,10 @@ static int remove_board(struct slot *p_slot) | |||
357 | return 0; | 307 | return 0; |
358 | } | 308 | } |
359 | 309 | ||
360 | 310 | struct power_work_info { | |
361 | static void pushbutton_helper_thread(unsigned long data) | 311 | struct slot *p_slot; |
362 | { | 312 | struct work_struct work; |
363 | pushbutton_pending = data; | 313 | }; |
364 | |||
365 | up(&event_semaphore); | ||
366 | } | ||
367 | 314 | ||
368 | /** | 315 | /** |
369 | * pciehp_pushbutton_thread | 316 | * pciehp_pushbutton_thread |
@@ -372,276 +319,214 @@ static void pushbutton_helper_thread(unsigned long data) | |||
372 | * Handles all pending events and exits. | 319 | * Handles all pending events and exits. |
373 | * | 320 | * |
374 | */ | 321 | */ |
375 | static void pciehp_pushbutton_thread(unsigned long slot) | 322 | static void pciehp_power_thread(struct work_struct *work) |
376 | { | 323 | { |
377 | struct slot *p_slot = (struct slot *) slot; | 324 | struct power_work_info *info = |
378 | u8 getstatus; | 325 | container_of(work, struct power_work_info, work); |
379 | 326 | struct slot *p_slot = info->p_slot; | |
380 | pushbutton_pending = 0; | 327 | |
381 | 328 | mutex_lock(&p_slot->lock); | |
382 | if (!p_slot) { | 329 | switch (p_slot->state) { |
383 | dbg("%s: Error! slot NULL\n", __FUNCTION__); | 330 | case POWEROFF_STATE: |
384 | return; | 331 | mutex_unlock(&p_slot->lock); |
385 | } | 332 | dbg("%s: disabling bus:device(%x:%x)\n", |
386 | 333 | __FUNCTION__, p_slot->bus, p_slot->device); | |
387 | p_slot->hpc_ops->get_power_status(p_slot, &getstatus); | ||
388 | if (getstatus) { | ||
389 | p_slot->state = POWEROFF_STATE; | ||
390 | dbg("%s: disabling bus:device(%x:%x)\n", __FUNCTION__, | ||
391 | p_slot->bus, p_slot->device); | ||
392 | |||
393 | pciehp_disable_slot(p_slot); | 334 | pciehp_disable_slot(p_slot); |
335 | mutex_lock(&p_slot->lock); | ||
394 | p_slot->state = STATIC_STATE; | 336 | p_slot->state = STATIC_STATE; |
395 | } else { | 337 | break; |
396 | p_slot->state = POWERON_STATE; | 338 | case POWERON_STATE: |
397 | dbg("%s: adding bus:device(%x:%x)\n", __FUNCTION__, | 339 | mutex_unlock(&p_slot->lock); |
398 | p_slot->bus, p_slot->device); | ||
399 | |||
400 | if (pciehp_enable_slot(p_slot) && | 340 | if (pciehp_enable_slot(p_slot) && |
401 | PWR_LED(p_slot->ctrl->ctrlcap)) | 341 | PWR_LED(p_slot->ctrl->ctrlcap)) |
402 | p_slot->hpc_ops->green_led_off(p_slot); | 342 | p_slot->hpc_ops->green_led_off(p_slot); |
403 | 343 | mutex_lock(&p_slot->lock); | |
404 | p_slot->state = STATIC_STATE; | 344 | p_slot->state = STATIC_STATE; |
345 | break; | ||
346 | default: | ||
347 | break; | ||
405 | } | 348 | } |
349 | mutex_unlock(&p_slot->lock); | ||
406 | 350 | ||
407 | return; | 351 | kfree(info); |
408 | } | 352 | } |
409 | 353 | ||
410 | /** | 354 | void pciehp_queue_pushbutton_work(struct work_struct *work) |
411 | * pciehp_surprise_rm_thread | ||
412 | * | ||
413 | * Scheduled procedure to handle blocking stuff for the surprise removal | ||
414 | * Handles all pending events and exits. | ||
415 | * | ||
416 | */ | ||
417 | static void pciehp_surprise_rm_thread(unsigned long slot) | ||
418 | { | 355 | { |
419 | struct slot *p_slot = (struct slot *) slot; | 356 | struct slot *p_slot = container_of(work, struct slot, work.work); |
420 | u8 getstatus; | 357 | struct power_work_info *info; |
421 | |||
422 | surprise_rm_pending = 0; | ||
423 | 358 | ||
424 | if (!p_slot) { | 359 | info = kmalloc(sizeof(*info), GFP_KERNEL); |
425 | dbg("%s: Error! slot NULL\n", __FUNCTION__); | 360 | if (!info) { |
361 | err("%s: Cannot allocate memory\n", __FUNCTION__); | ||
426 | return; | 362 | return; |
427 | } | 363 | } |
364 | info->p_slot = p_slot; | ||
365 | INIT_WORK(&info->work, pciehp_power_thread); | ||
428 | 366 | ||
429 | p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); | 367 | mutex_lock(&p_slot->lock); |
430 | if (!getstatus) { | 368 | switch (p_slot->state) { |
369 | case BLINKINGOFF_STATE: | ||
431 | p_slot->state = POWEROFF_STATE; | 370 | p_slot->state = POWEROFF_STATE; |
432 | dbg("%s: removing bus:device(%x:%x)\n", | 371 | break; |
433 | __FUNCTION__, p_slot->bus, p_slot->device); | 372 | case BLINKINGON_STATE: |
434 | |||
435 | pciehp_disable_slot(p_slot); | ||
436 | p_slot->state = STATIC_STATE; | ||
437 | } else { | ||
438 | p_slot->state = POWERON_STATE; | 373 | p_slot->state = POWERON_STATE; |
439 | dbg("%s: adding bus:device(%x:%x)\n", | 374 | break; |
440 | __FUNCTION__, p_slot->bus, p_slot->device); | 375 | default: |
441 | 376 | goto out; | |
442 | if (pciehp_enable_slot(p_slot) && | ||
443 | PWR_LED(p_slot->ctrl->ctrlcap)) | ||
444 | p_slot->hpc_ops->green_led_off(p_slot); | ||
445 | |||
446 | p_slot->state = STATIC_STATE; | ||
447 | } | 377 | } |
448 | 378 | queue_work(pciehp_wq, &info->work); | |
449 | return; | 379 | out: |
380 | mutex_unlock(&p_slot->lock); | ||
450 | } | 381 | } |
451 | 382 | ||
452 | |||
453 | |||
454 | /* this is the main worker thread */ | ||
455 | static int event_thread(void* data) | ||
456 | { | ||
457 | struct controller *ctrl; | ||
458 | lock_kernel(); | ||
459 | daemonize("pciehpd_event"); | ||
460 | |||
461 | unlock_kernel(); | ||
462 | |||
463 | while (1) { | ||
464 | dbg("!!!!event_thread sleeping\n"); | ||
465 | down_interruptible (&event_semaphore); | ||
466 | dbg("event_thread woken finished = %d\n", event_finished); | ||
467 | if (event_finished || signal_pending(current)) | ||
468 | break; | ||
469 | /* Do stuff here */ | ||
470 | if (pushbutton_pending) | ||
471 | pciehp_pushbutton_thread(pushbutton_pending); | ||
472 | else if (surprise_rm_pending) | ||
473 | pciehp_surprise_rm_thread(surprise_rm_pending); | ||
474 | else | ||
475 | for (ctrl = pciehp_ctrl_list; ctrl; ctrl=ctrl->next) | ||
476 | interrupt_event_handler(ctrl); | ||
477 | } | ||
478 | dbg("event_thread signals exit\n"); | ||
479 | up(&event_exit); | ||
480 | return 0; | ||
481 | } | ||
482 | |||
483 | int pciehp_event_start_thread(void) | ||
484 | { | ||
485 | int pid; | ||
486 | |||
487 | /* initialize our semaphores */ | ||
488 | init_MUTEX_LOCKED(&event_exit); | ||
489 | event_finished=0; | ||
490 | |||
491 | init_MUTEX_LOCKED(&event_semaphore); | ||
492 | pid = kernel_thread(event_thread, NULL, 0); | ||
493 | |||
494 | if (pid < 0) { | ||
495 | err ("Can't start up our event thread\n"); | ||
496 | return -1; | ||
497 | } | ||
498 | return 0; | ||
499 | } | ||
500 | |||
501 | |||
502 | void pciehp_event_stop_thread(void) | ||
503 | { | ||
504 | event_finished = 1; | ||
505 | up(&event_semaphore); | ||
506 | down(&event_exit); | ||
507 | } | ||
508 | |||
509 | |||
510 | static int update_slot_info(struct slot *slot) | 383 | static int update_slot_info(struct slot *slot) |
511 | { | 384 | { |
512 | struct hotplug_slot_info *info; | 385 | struct hotplug_slot_info *info; |
513 | /* char buffer[SLOT_NAME_SIZE]; */ | ||
514 | int result; | 386 | int result; |
515 | 387 | ||
516 | info = kmalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL); | 388 | info = kmalloc(sizeof(*info), GFP_KERNEL); |
517 | if (!info) | 389 | if (!info) |
518 | return -ENOMEM; | 390 | return -ENOMEM; |
519 | 391 | ||
520 | /* make_slot_name (&buffer[0], SLOT_NAME_SIZE, slot); */ | ||
521 | |||
522 | slot->hpc_ops->get_power_status(slot, &(info->power_status)); | 392 | slot->hpc_ops->get_power_status(slot, &(info->power_status)); |
523 | slot->hpc_ops->get_attention_status(slot, &(info->attention_status)); | 393 | slot->hpc_ops->get_attention_status(slot, &(info->attention_status)); |
524 | slot->hpc_ops->get_latch_status(slot, &(info->latch_status)); | 394 | slot->hpc_ops->get_latch_status(slot, &(info->latch_status)); |
525 | slot->hpc_ops->get_adapter_status(slot, &(info->adapter_status)); | 395 | slot->hpc_ops->get_adapter_status(slot, &(info->adapter_status)); |
526 | 396 | ||
527 | /* result = pci_hp_change_slot_info(buffer, info); */ | ||
528 | result = pci_hp_change_slot_info(slot->hotplug_slot, info); | 397 | result = pci_hp_change_slot_info(slot->hotplug_slot, info); |
529 | kfree (info); | 398 | kfree (info); |
530 | return result; | 399 | return result; |
531 | } | 400 | } |
532 | 401 | ||
533 | static void interrupt_event_handler(struct controller *ctrl) | 402 | /* |
403 | * Note: This function must be called with slot->lock held | ||
404 | */ | ||
405 | static void handle_button_press_event(struct slot *p_slot) | ||
534 | { | 406 | { |
535 | int loop = 0; | 407 | struct controller *ctrl = p_slot->ctrl; |
536 | int change = 1; | ||
537 | u8 hp_slot; | ||
538 | u8 getstatus; | 408 | u8 getstatus; |
539 | struct slot *p_slot; | ||
540 | 409 | ||
541 | while (change) { | 410 | switch (p_slot->state) { |
542 | change = 0; | 411 | case STATIC_STATE: |
543 | 412 | p_slot->hpc_ops->get_power_status(p_slot, &getstatus); | |
544 | for (loop = 0; loop < MAX_EVENTS; loop++) { | 413 | if (getstatus) { |
545 | if (ctrl->event_queue[loop].event_type != 0) { | 414 | p_slot->state = BLINKINGOFF_STATE; |
546 | hp_slot = ctrl->event_queue[loop].hp_slot; | 415 | info("PCI slot #%s - powering off due to button " |
547 | 416 | "press.\n", p_slot->name); | |
548 | p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); | 417 | } else { |
549 | 418 | p_slot->state = BLINKINGON_STATE; | |
550 | if (ctrl->event_queue[loop].event_type == INT_BUTTON_CANCEL) { | 419 | info("PCI slot #%s - powering on due to button " |
551 | dbg("button cancel\n"); | 420 | "press.\n", p_slot->name); |
552 | del_timer(&p_slot->task_event); | 421 | } |
553 | 422 | /* blink green LED and turn off amber */ | |
554 | switch (p_slot->state) { | 423 | if (PWR_LED(ctrl->ctrlcap)) |
555 | case BLINKINGOFF_STATE: | 424 | p_slot->hpc_ops->green_led_blink(p_slot); |
556 | if (PWR_LED(ctrl->ctrlcap)) | 425 | if (ATTN_LED(ctrl->ctrlcap)) |
557 | p_slot->hpc_ops->green_led_on(p_slot); | 426 | p_slot->hpc_ops->set_attention_status(p_slot, 0); |
558 | 427 | ||
559 | if (ATTN_LED(ctrl->ctrlcap)) | 428 | schedule_delayed_work(&p_slot->work, 5*HZ); |
560 | p_slot->hpc_ops->set_attention_status(p_slot, 0); | 429 | break; |
561 | break; | 430 | case BLINKINGOFF_STATE: |
562 | case BLINKINGON_STATE: | 431 | case BLINKINGON_STATE: |
563 | if (PWR_LED(ctrl->ctrlcap)) | 432 | /* |
564 | p_slot->hpc_ops->green_led_off(p_slot); | 433 | * Cancel if we are still blinking; this means that we |
565 | 434 | * press the attention again before the 5 sec. limit | |
566 | if (ATTN_LED(ctrl->ctrlcap)) | 435 | * expires to cancel hot-add or hot-remove |
567 | p_slot->hpc_ops->set_attention_status(p_slot, 0); | 436 | */ |
568 | break; | 437 | info("Button cancel on Slot(%s)\n", p_slot->name); |
569 | default: | 438 | dbg("%s: button cancel\n", __FUNCTION__); |
570 | warn("Not a valid state\n"); | 439 | cancel_delayed_work(&p_slot->work); |
571 | return; | 440 | if (p_slot->state == BLINKINGOFF_STATE) { |
572 | } | 441 | if (PWR_LED(ctrl->ctrlcap)) |
573 | info("PCI slot #%s - action canceled due to button press.\n", slot_name(p_slot)); | 442 | p_slot->hpc_ops->green_led_on(p_slot); |
574 | p_slot->state = STATIC_STATE; | 443 | } else { |
575 | } | 444 | if (PWR_LED(ctrl->ctrlcap)) |
576 | /* ***********Button Pressed (No action on 1st press...) */ | 445 | p_slot->hpc_ops->green_led_off(p_slot); |
577 | else if (ctrl->event_queue[loop].event_type == INT_BUTTON_PRESS) { | 446 | } |
578 | 447 | if (ATTN_LED(ctrl->ctrlcap)) | |
579 | if (ATTN_BUTTN(ctrl->ctrlcap)) { | 448 | p_slot->hpc_ops->set_attention_status(p_slot, 0); |
580 | dbg("Button pressed\n"); | 449 | info("PCI slot #%s - action canceled due to button press\n", |
581 | p_slot->hpc_ops->get_power_status(p_slot, &getstatus); | 450 | p_slot->name); |
582 | if (getstatus) { | 451 | p_slot->state = STATIC_STATE; |
583 | /* slot is on */ | 452 | break; |
584 | dbg("slot is on\n"); | 453 | case POWEROFF_STATE: |
585 | p_slot->state = BLINKINGOFF_STATE; | 454 | case POWERON_STATE: |
586 | info("PCI slot #%s - powering off due to button press.\n", slot_name(p_slot)); | 455 | /* |
587 | } else { | 456 | * Ignore if the slot is on power-on or power-off state; |
588 | /* slot is off */ | 457 | * this means that the previous attention button action |
589 | dbg("slot is off\n"); | 458 | * to hot-add or hot-remove is undergoing |
590 | p_slot->state = BLINKINGON_STATE; | 459 | */ |
591 | info("PCI slot #%s - powering on due to button press.\n", slot_name(p_slot)); | 460 | info("Button ignore on Slot(%s)\n", p_slot->name); |
592 | } | 461 | update_slot_info(p_slot); |
593 | 462 | break; | |
594 | /* blink green LED and turn off amber */ | 463 | default: |
595 | if (PWR_LED(ctrl->ctrlcap)) | 464 | warn("Not a valid state\n"); |
596 | p_slot->hpc_ops->green_led_blink(p_slot); | 465 | break; |
597 | |||
598 | if (ATTN_LED(ctrl->ctrlcap)) | ||
599 | p_slot->hpc_ops->set_attention_status(p_slot, 0); | ||
600 | |||
601 | init_timer(&p_slot->task_event); | ||
602 | p_slot->task_event.expires = jiffies + 5 * HZ; /* 5 second delay */ | ||
603 | p_slot->task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread; | ||
604 | p_slot->task_event.data = (unsigned long) p_slot; | ||
605 | |||
606 | add_timer(&p_slot->task_event); | ||
607 | } | ||
608 | } | ||
609 | /***********POWER FAULT********************/ | ||
610 | else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) { | ||
611 | if (POWER_CTRL(ctrl->ctrlcap)) { | ||
612 | dbg("power fault\n"); | ||
613 | if (ATTN_LED(ctrl->ctrlcap)) | ||
614 | p_slot->hpc_ops->set_attention_status(p_slot, 1); | ||
615 | |||
616 | if (PWR_LED(ctrl->ctrlcap)) | ||
617 | p_slot->hpc_ops->green_led_off(p_slot); | ||
618 | } | ||
619 | } | ||
620 | /***********SURPRISE REMOVAL********************/ | ||
621 | else if ((ctrl->event_queue[loop].event_type == INT_PRESENCE_ON) || | ||
622 | (ctrl->event_queue[loop].event_type == INT_PRESENCE_OFF)) { | ||
623 | if (HP_SUPR_RM(ctrl->ctrlcap)) { | ||
624 | dbg("Surprise Removal\n"); | ||
625 | if (p_slot) { | ||
626 | surprise_rm_pending = (unsigned long) p_slot; | ||
627 | up(&event_semaphore); | ||
628 | update_slot_info(p_slot); | ||
629 | } | ||
630 | } | ||
631 | } else { | ||
632 | /* refresh notification */ | ||
633 | if (p_slot) | ||
634 | update_slot_info(p_slot); | ||
635 | } | ||
636 | |||
637 | ctrl->event_queue[loop].event_type = 0; | ||
638 | |||
639 | change = 1; | ||
640 | } | ||
641 | } /* End of FOR loop */ | ||
642 | } | 466 | } |
643 | } | 467 | } |
644 | 468 | ||
469 | /* | ||
470 | * Note: This function must be called with slot->lock held | ||
471 | */ | ||
472 | static void handle_surprise_event(struct slot *p_slot) | ||
473 | { | ||
474 | u8 getstatus; | ||
475 | struct power_work_info *info; | ||
476 | |||
477 | info = kmalloc(sizeof(*info), GFP_KERNEL); | ||
478 | if (!info) { | ||
479 | err("%s: Cannot allocate memory\n", __FUNCTION__); | ||
480 | return; | ||
481 | } | ||
482 | info->p_slot = p_slot; | ||
483 | INIT_WORK(&info->work, pciehp_power_thread); | ||
484 | |||
485 | p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); | ||
486 | if (!getstatus) | ||
487 | p_slot->state = POWEROFF_STATE; | ||
488 | else | ||
489 | p_slot->state = POWERON_STATE; | ||
490 | |||
491 | queue_work(pciehp_wq, &info->work); | ||
492 | } | ||
493 | |||
494 | static void interrupt_event_handler(struct work_struct *work) | ||
495 | { | ||
496 | struct event_info *info = container_of(work, struct event_info, work); | ||
497 | struct slot *p_slot = info->p_slot; | ||
498 | struct controller *ctrl = p_slot->ctrl; | ||
499 | |||
500 | mutex_lock(&p_slot->lock); | ||
501 | switch (info->event_type) { | ||
502 | case INT_BUTTON_PRESS: | ||
503 | handle_button_press_event(p_slot); | ||
504 | break; | ||
505 | case INT_POWER_FAULT: | ||
506 | if (!POWER_CTRL(ctrl->ctrlcap)) | ||
507 | break; | ||
508 | if (ATTN_LED(ctrl->ctrlcap)) | ||
509 | p_slot->hpc_ops->set_attention_status(p_slot, 1); | ||
510 | if (PWR_LED(ctrl->ctrlcap)) | ||
511 | p_slot->hpc_ops->green_led_off(p_slot); | ||
512 | break; | ||
513 | case INT_PRESENCE_ON: | ||
514 | case INT_PRESENCE_OFF: | ||
515 | if (!HP_SUPR_RM(ctrl->ctrlcap)) | ||
516 | break; | ||
517 | dbg("Surprise Removal\n"); | ||
518 | update_slot_info(p_slot); | ||
519 | handle_surprise_event(p_slot); | ||
520 | break; | ||
521 | default: | ||
522 | update_slot_info(p_slot); | ||
523 | break; | ||
524 | } | ||
525 | mutex_unlock(&p_slot->lock); | ||
526 | |||
527 | kfree(info); | ||
528 | } | ||
529 | |||
645 | int pciehp_enable_slot(struct slot *p_slot) | 530 | int pciehp_enable_slot(struct slot *p_slot) |
646 | { | 531 | { |
647 | u8 getstatus = 0; | 532 | u8 getstatus = 0; |
@@ -653,7 +538,7 @@ int pciehp_enable_slot(struct slot *p_slot) | |||
653 | rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); | 538 | rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); |
654 | if (rc || !getstatus) { | 539 | if (rc || !getstatus) { |
655 | info("%s: no adapter on slot(%s)\n", __FUNCTION__, | 540 | info("%s: no adapter on slot(%s)\n", __FUNCTION__, |
656 | slot_name(p_slot)); | 541 | p_slot->name); |
657 | mutex_unlock(&p_slot->ctrl->crit_sect); | 542 | mutex_unlock(&p_slot->ctrl->crit_sect); |
658 | return -ENODEV; | 543 | return -ENODEV; |
659 | } | 544 | } |
@@ -661,7 +546,7 @@ int pciehp_enable_slot(struct slot *p_slot) | |||
661 | rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); | 546 | rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); |
662 | if (rc || getstatus) { | 547 | if (rc || getstatus) { |
663 | info("%s: latch open on slot(%s)\n", __FUNCTION__, | 548 | info("%s: latch open on slot(%s)\n", __FUNCTION__, |
664 | slot_name(p_slot)); | 549 | p_slot->name); |
665 | mutex_unlock(&p_slot->ctrl->crit_sect); | 550 | mutex_unlock(&p_slot->ctrl->crit_sect); |
666 | return -ENODEV; | 551 | return -ENODEV; |
667 | } | 552 | } |
@@ -671,7 +556,7 @@ int pciehp_enable_slot(struct slot *p_slot) | |||
671 | rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); | 556 | rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); |
672 | if (rc || getstatus) { | 557 | if (rc || getstatus) { |
673 | info("%s: already enabled on slot(%s)\n", __FUNCTION__, | 558 | info("%s: already enabled on slot(%s)\n", __FUNCTION__, |
674 | slot_name(p_slot)); | 559 | p_slot->name); |
675 | mutex_unlock(&p_slot->ctrl->crit_sect); | 560 | mutex_unlock(&p_slot->ctrl->crit_sect); |
676 | return -EINVAL; | 561 | return -EINVAL; |
677 | } | 562 | } |
@@ -706,7 +591,7 @@ int pciehp_disable_slot(struct slot *p_slot) | |||
706 | ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); | 591 | ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); |
707 | if (ret || !getstatus) { | 592 | if (ret || !getstatus) { |
708 | info("%s: no adapter on slot(%s)\n", __FUNCTION__, | 593 | info("%s: no adapter on slot(%s)\n", __FUNCTION__, |
709 | slot_name(p_slot)); | 594 | p_slot->name); |
710 | mutex_unlock(&p_slot->ctrl->crit_sect); | 595 | mutex_unlock(&p_slot->ctrl->crit_sect); |
711 | return -ENODEV; | 596 | return -ENODEV; |
712 | } | 597 | } |
@@ -716,7 +601,7 @@ int pciehp_disable_slot(struct slot *p_slot) | |||
716 | ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); | 601 | ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); |
717 | if (ret || getstatus) { | 602 | if (ret || getstatus) { |
718 | info("%s: latch open on slot(%s)\n", __FUNCTION__, | 603 | info("%s: latch open on slot(%s)\n", __FUNCTION__, |
719 | slot_name(p_slot)); | 604 | p_slot->name); |
720 | mutex_unlock(&p_slot->ctrl->crit_sect); | 605 | mutex_unlock(&p_slot->ctrl->crit_sect); |
721 | return -ENODEV; | 606 | return -ENODEV; |
722 | } | 607 | } |
@@ -726,7 +611,7 @@ int pciehp_disable_slot(struct slot *p_slot) | |||
726 | ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); | 611 | ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); |
727 | if (ret || !getstatus) { | 612 | if (ret || !getstatus) { |
728 | info("%s: already disabled slot(%s)\n", __FUNCTION__, | 613 | info("%s: already disabled slot(%s)\n", __FUNCTION__, |
729 | slot_name(p_slot)); | 614 | p_slot->name); |
730 | mutex_unlock(&p_slot->ctrl->crit_sect); | 615 | mutex_unlock(&p_slot->ctrl->crit_sect); |
731 | return -EINVAL; | 616 | return -EINVAL; |
732 | } | 617 | } |
@@ -739,3 +624,66 @@ int pciehp_disable_slot(struct slot *p_slot) | |||
739 | return ret; | 624 | return ret; |
740 | } | 625 | } |
741 | 626 | ||
627 | int pciehp_sysfs_enable_slot(struct slot *p_slot) | ||
628 | { | ||
629 | int retval = -ENODEV; | ||
630 | |||
631 | mutex_lock(&p_slot->lock); | ||
632 | switch (p_slot->state) { | ||
633 | case BLINKINGON_STATE: | ||
634 | cancel_delayed_work(&p_slot->work); | ||
635 | case STATIC_STATE: | ||
636 | p_slot->state = POWERON_STATE; | ||
637 | mutex_unlock(&p_slot->lock); | ||
638 | retval = pciehp_enable_slot(p_slot); | ||
639 | mutex_lock(&p_slot->lock); | ||
640 | p_slot->state = STATIC_STATE; | ||
641 | break; | ||
642 | case POWERON_STATE: | ||
643 | info("Slot %s is already in powering on state\n", | ||
644 | p_slot->name); | ||
645 | break; | ||
646 | case BLINKINGOFF_STATE: | ||
647 | case POWEROFF_STATE: | ||
648 | info("Already enabled on slot %s\n", p_slot->name); | ||
649 | break; | ||
650 | default: | ||
651 | err("Not a valid state on slot %s\n", p_slot->name); | ||
652 | break; | ||
653 | } | ||
654 | mutex_unlock(&p_slot->lock); | ||
655 | |||
656 | return retval; | ||
657 | } | ||
658 | |||
659 | int pciehp_sysfs_disable_slot(struct slot *p_slot) | ||
660 | { | ||
661 | int retval = -ENODEV; | ||
662 | |||
663 | mutex_lock(&p_slot->lock); | ||
664 | switch (p_slot->state) { | ||
665 | case BLINKINGOFF_STATE: | ||
666 | cancel_delayed_work(&p_slot->work); | ||
667 | case STATIC_STATE: | ||
668 | p_slot->state = POWEROFF_STATE; | ||
669 | mutex_unlock(&p_slot->lock); | ||
670 | retval = pciehp_disable_slot(p_slot); | ||
671 | mutex_lock(&p_slot->lock); | ||
672 | p_slot->state = STATIC_STATE; | ||
673 | break; | ||
674 | case POWEROFF_STATE: | ||
675 | info("Slot %s is already in powering off state\n", | ||
676 | p_slot->name); | ||
677 | break; | ||
678 | case BLINKINGON_STATE: | ||
679 | case POWERON_STATE: | ||
680 | info("Already disabled on slot %s\n", p_slot->name); | ||
681 | break; | ||
682 | default: | ||
683 | err("Not a valid state on slot %s\n", p_slot->name); | ||
684 | break; | ||
685 | } | ||
686 | mutex_unlock(&p_slot->lock); | ||
687 | |||
688 | return retval; | ||
689 | } | ||
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index fbc64aa2dd68..9aac6a87eb53 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c | |||
@@ -71,6 +71,8 @@ | |||
71 | #define DBG_LEAVE_ROUTINE | 71 | #define DBG_LEAVE_ROUTINE |
72 | #endif /* DEBUG */ | 72 | #endif /* DEBUG */ |
73 | 73 | ||
74 | static atomic_t pciehp_num_controllers = ATOMIC_INIT(0); | ||
75 | |||
74 | struct ctrl_reg { | 76 | struct ctrl_reg { |
75 | u8 cap_id; | 77 | u8 cap_id; |
76 | u8 nxt_ptr; | 78 | u8 nxt_ptr; |
@@ -219,10 +221,7 @@ static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value) | |||
219 | #define EMI_STATE 0x0080 | 221 | #define EMI_STATE 0x0080 |
220 | #define EMI_STATUS_BIT 7 | 222 | #define EMI_STATUS_BIT 7 |
221 | 223 | ||
222 | static spinlock_t hpc_event_lock; | ||
223 | |||
224 | DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */ | 224 | DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */ |
225 | static int ctlr_seq_num = 0; /* Controller sequence # */ | ||
226 | 225 | ||
227 | static irqreturn_t pcie_isr(int irq, void *dev_id); | 226 | static irqreturn_t pcie_isr(int irq, void *dev_id); |
228 | static void start_int_poll_timer(struct controller *ctrl, int sec); | 227 | static void start_int_poll_timer(struct controller *ctrl, int sec); |
@@ -656,6 +655,13 @@ static void hpc_release_ctlr(struct controller *ctrl) | |||
656 | else | 655 | else |
657 | free_irq(ctrl->pci_dev->irq, ctrl); | 656 | free_irq(ctrl->pci_dev->irq, ctrl); |
658 | 657 | ||
658 | /* | ||
659 | * If this is the last controller to be released, destroy the | ||
660 | * pciehp work queue | ||
661 | */ | ||
662 | if (atomic_dec_and_test(&pciehp_num_controllers)) | ||
663 | destroy_workqueue(pciehp_wq); | ||
664 | |||
659 | DBG_LEAVE_ROUTINE | 665 | DBG_LEAVE_ROUTINE |
660 | } | 666 | } |
661 | 667 | ||
@@ -1152,7 +1158,6 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev) | |||
1152 | int pcie_init(struct controller * ctrl, struct pcie_device *dev) | 1158 | int pcie_init(struct controller * ctrl, struct pcie_device *dev) |
1153 | { | 1159 | { |
1154 | int rc; | 1160 | int rc; |
1155 | static int first = 1; | ||
1156 | u16 temp_word; | 1161 | u16 temp_word; |
1157 | u16 cap_reg; | 1162 | u16 cap_reg; |
1158 | u16 intr_enable = 0; | 1163 | u16 intr_enable = 0; |
@@ -1221,11 +1226,6 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) | |||
1221 | dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n", | 1226 | dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n", |
1222 | __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl); | 1227 | __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl); |
1223 | 1228 | ||
1224 | if (first) { | ||
1225 | spin_lock_init(&hpc_event_lock); | ||
1226 | first = 0; | ||
1227 | } | ||
1228 | |||
1229 | for ( rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++) | 1229 | for ( rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++) |
1230 | if (pci_resource_len(pdev, rc) > 0) | 1230 | if (pci_resource_len(pdev, rc) > 0) |
1231 | dbg("pci resource[%d] start=0x%llx(len=0x%llx)\n", rc, | 1231 | dbg("pci resource[%d] start=0x%llx(len=0x%llx)\n", rc, |
@@ -1286,7 +1286,8 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) | |||
1286 | rc = request_irq(ctrl->pci_dev->irq, pcie_isr, IRQF_SHARED, | 1286 | rc = request_irq(ctrl->pci_dev->irq, pcie_isr, IRQF_SHARED, |
1287 | MY_NAME, (void *)ctrl); | 1287 | MY_NAME, (void *)ctrl); |
1288 | dbg("%s: request_irq %d for hpc%d (returns %d)\n", | 1288 | dbg("%s: request_irq %d for hpc%d (returns %d)\n", |
1289 | __FUNCTION__, ctrl->pci_dev->irq, ctlr_seq_num, rc); | 1289 | __FUNCTION__, ctrl->pci_dev->irq, |
1290 | atomic_read(&pciehp_num_controllers), rc); | ||
1290 | if (rc) { | 1291 | if (rc) { |
1291 | err("Can't get irq %d for the hotplug controller\n", | 1292 | err("Can't get irq %d for the hotplug controller\n", |
1292 | ctrl->pci_dev->irq); | 1293 | ctrl->pci_dev->irq); |
@@ -1296,6 +1297,18 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) | |||
1296 | dbg("pciehp ctrl b:d:f:irq=0x%x:%x:%x:%x\n", pdev->bus->number, | 1297 | dbg("pciehp ctrl b:d:f:irq=0x%x:%x:%x:%x\n", pdev->bus->number, |
1297 | PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), dev->irq); | 1298 | PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), dev->irq); |
1298 | 1299 | ||
1300 | /* | ||
1301 | * If this is the first controller to be initialized, | ||
1302 | * initialize the pciehp work queue | ||
1303 | */ | ||
1304 | if (atomic_add_return(1, &pciehp_num_controllers) == 1) { | ||
1305 | pciehp_wq = create_singlethread_workqueue("pciehpd"); | ||
1306 | if (!pciehp_wq) { | ||
1307 | rc = -ENOMEM; | ||
1308 | goto abort_free_irq; | ||
1309 | } | ||
1310 | } | ||
1311 | |||
1299 | rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); | 1312 | rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); |
1300 | if (rc) { | 1313 | if (rc) { |
1301 | err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); | 1314 | err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); |
@@ -1349,7 +1362,6 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) | |||
1349 | goto abort_disable_intr; | 1362 | goto abort_disable_intr; |
1350 | } | 1363 | } |
1351 | 1364 | ||
1352 | ctlr_seq_num++; | ||
1353 | ctrl->hpc_ops = &pciehp_hpc_ops; | 1365 | ctrl->hpc_ops = &pciehp_hpc_ops; |
1354 | 1366 | ||
1355 | DBG_LEAVE_ROUTINE | 1367 | DBG_LEAVE_ROUTINE |
diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c index 72383467a0d5..bb3c101c2c5a 100644 --- a/drivers/pci/hotplug/rpadlpar_core.c +++ b/drivers/pci/hotplug/rpadlpar_core.c | |||
@@ -98,7 +98,15 @@ static struct device_node *find_dlpar_node(char *drc_name, int *node_type) | |||
98 | return NULL; | 98 | return NULL; |
99 | } | 99 | } |
100 | 100 | ||
101 | static struct slot *find_slot(struct device_node *dn) | 101 | /** |
102 | * find_php_slot - return hotplug slot structure for device node | ||
103 | * | ||
104 | * This routine will return the hotplug slot structure | ||
105 | * for a given device node. Note that built-in PCI slots | ||
106 | * may be dlpar-able, but not hot-pluggable, so this routine | ||
107 | * will return NULL for built-in PCI slots. | ||
108 | */ | ||
109 | static struct slot *find_php_slot(struct device_node *dn) | ||
102 | { | 110 | { |
103 | struct list_head *tmp, *n; | 111 | struct list_head *tmp, *n; |
104 | struct slot *slot; | 112 | struct slot *slot; |
@@ -224,9 +232,9 @@ static int dlpar_remove_phb(char *drc_name, struct device_node *dn) | |||
224 | if (!pcibios_find_pci_bus(dn)) | 232 | if (!pcibios_find_pci_bus(dn)) |
225 | return -EINVAL; | 233 | return -EINVAL; |
226 | 234 | ||
227 | slot = find_slot(dn); | 235 | /* If pci slot is hotplugable, use hotplug to remove it */ |
236 | slot = find_php_slot(dn); | ||
228 | if (slot) { | 237 | if (slot) { |
229 | /* Remove hotplug slot */ | ||
230 | if (rpaphp_deregister_slot(slot)) { | 238 | if (rpaphp_deregister_slot(slot)) { |
231 | printk(KERN_ERR | 239 | printk(KERN_ERR |
232 | "%s: unable to remove hotplug slot %s\n", | 240 | "%s: unable to remove hotplug slot %s\n", |
@@ -370,22 +378,17 @@ int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn) | |||
370 | if (!bus) | 378 | if (!bus) |
371 | return -EINVAL; | 379 | return -EINVAL; |
372 | 380 | ||
373 | slot = find_slot(dn); | 381 | /* If pci slot is hotplugable, use hotplug to remove it */ |
382 | slot = find_php_slot(dn); | ||
374 | if (slot) { | 383 | if (slot) { |
375 | /* Remove hotplug slot */ | ||
376 | if (rpaphp_deregister_slot(slot)) { | 384 | if (rpaphp_deregister_slot(slot)) { |
377 | printk(KERN_ERR | 385 | printk(KERN_ERR |
378 | "%s: unable to remove hotplug slot %s\n", | 386 | "%s: unable to remove hotplug slot %s\n", |
379 | __FUNCTION__, drc_name); | 387 | __FUNCTION__, drc_name); |
380 | return -EIO; | 388 | return -EIO; |
381 | } | 389 | } |
382 | } else { | 390 | } else |
383 | struct pci_dev *dev, *tmp; | 391 | pcibios_remove_pci_devices(bus); |
384 | list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) { | ||
385 | eeh_remove_bus_device(dev); | ||
386 | pci_remove_bus_device(dev); | ||
387 | } | ||
388 | } | ||
389 | 392 | ||
390 | if (unmap_bus_range(bus)) { | 393 | if (unmap_bus_range(bus)) { |
391 | printk(KERN_ERR "%s: failed to unmap bus range\n", | 394 | printk(KERN_ERR "%s: failed to unmap bus range\n", |
diff --git a/drivers/pci/hotplug/rpaphp.h b/drivers/pci/hotplug/rpaphp.h index 2e7accf0f734..c822a779653f 100644 --- a/drivers/pci/hotplug/rpaphp.h +++ b/drivers/pci/hotplug/rpaphp.h | |||
@@ -83,19 +83,15 @@ struct slot { | |||
83 | 83 | ||
84 | extern struct hotplug_slot_ops rpaphp_hotplug_slot_ops; | 84 | extern struct hotplug_slot_ops rpaphp_hotplug_slot_ops; |
85 | extern struct list_head rpaphp_slot_head; | 85 | extern struct list_head rpaphp_slot_head; |
86 | extern int num_slots; | ||
87 | 86 | ||
88 | /* function prototypes */ | 87 | /* function prototypes */ |
89 | 88 | ||
90 | /* rpaphp_pci.c */ | 89 | /* rpaphp_pci.c */ |
91 | extern int rpaphp_enable_pci_slot(struct slot *slot); | 90 | extern int rpaphp_enable_slot(struct slot *slot); |
92 | extern int rpaphp_register_pci_slot(struct slot *slot); | ||
93 | extern int rpaphp_get_pci_adapter_status(struct slot *slot, int is_init, u8 * value); | ||
94 | extern int rpaphp_get_sensor_state(struct slot *slot, int *state); | 91 | extern int rpaphp_get_sensor_state(struct slot *slot, int *state); |
95 | 92 | ||
96 | /* rpaphp_core.c */ | 93 | /* rpaphp_core.c */ |
97 | extern int rpaphp_add_slot(struct device_node *dn); | 94 | extern int rpaphp_add_slot(struct device_node *dn); |
98 | extern int rpaphp_remove_slot(struct slot *slot); | ||
99 | extern int rpaphp_get_drc_props(struct device_node *dn, int *drc_index, | 95 | extern int rpaphp_get_drc_props(struct device_node *dn, int *drc_index, |
100 | char **drc_name, char **drc_type, int *drc_power_domain); | 96 | char **drc_name, char **drc_type, int *drc_power_domain); |
101 | 97 | ||
@@ -104,7 +100,5 @@ extern void dealloc_slot_struct(struct slot *slot); | |||
104 | extern struct slot *alloc_slot_struct(struct device_node *dn, int drc_index, char *drc_name, int power_domain); | 100 | extern struct slot *alloc_slot_struct(struct device_node *dn, int drc_index, char *drc_name, int power_domain); |
105 | extern int rpaphp_register_slot(struct slot *slot); | 101 | extern int rpaphp_register_slot(struct slot *slot); |
106 | extern int rpaphp_deregister_slot(struct slot *slot); | 102 | extern int rpaphp_deregister_slot(struct slot *slot); |
107 | extern int rpaphp_get_power_status(struct slot *slot, u8 * value); | ||
108 | extern int rpaphp_set_attention_status(struct slot *slot, u8 status); | ||
109 | 103 | ||
110 | #endif /* _PPC64PHP_H */ | 104 | #endif /* _PPC64PHP_H */ |
diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c index 71a2cb8baa4a..847936fe327e 100644 --- a/drivers/pci/hotplug/rpaphp_core.c +++ b/drivers/pci/hotplug/rpaphp_core.c | |||
@@ -39,9 +39,7 @@ | |||
39 | #include "rpaphp.h" | 39 | #include "rpaphp.h" |
40 | 40 | ||
41 | int debug; | 41 | int debug; |
42 | static struct semaphore rpaphp_sem; | ||
43 | LIST_HEAD(rpaphp_slot_head); | 42 | LIST_HEAD(rpaphp_slot_head); |
44 | int num_slots; | ||
45 | 43 | ||
46 | #define DRIVER_VERSION "0.1" | 44 | #define DRIVER_VERSION "0.1" |
47 | #define DRIVER_AUTHOR "Linda Xie <lxie@us.ibm.com>" | 45 | #define DRIVER_AUTHOR "Linda Xie <lxie@us.ibm.com>" |
@@ -55,11 +53,6 @@ MODULE_LICENSE("GPL"); | |||
55 | 53 | ||
56 | module_param(debug, bool, 0644); | 54 | module_param(debug, bool, 0644); |
57 | 55 | ||
58 | static int rpaphp_get_attention_status(struct slot *slot) | ||
59 | { | ||
60 | return slot->hotplug_slot->info->attention_status; | ||
61 | } | ||
62 | |||
63 | /** | 56 | /** |
64 | * set_attention_status - set attention LED | 57 | * set_attention_status - set attention LED |
65 | * echo 0 > attention -- set LED OFF | 58 | * echo 0 > attention -- set LED OFF |
@@ -69,79 +62,75 @@ static int rpaphp_get_attention_status(struct slot *slot) | |||
69 | */ | 62 | */ |
70 | static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 value) | 63 | static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 value) |
71 | { | 64 | { |
72 | int retval = 0; | 65 | int rc; |
73 | struct slot *slot = (struct slot *)hotplug_slot->private; | 66 | struct slot *slot = (struct slot *)hotplug_slot->private; |
74 | 67 | ||
75 | down(&rpaphp_sem); | ||
76 | switch (value) { | 68 | switch (value) { |
77 | case 0: | 69 | case 0: |
78 | retval = rpaphp_set_attention_status(slot, LED_OFF); | ||
79 | hotplug_slot->info->attention_status = 0; | ||
80 | break; | ||
81 | case 1: | 70 | case 1: |
82 | default: | ||
83 | retval = rpaphp_set_attention_status(slot, LED_ON); | ||
84 | hotplug_slot->info->attention_status = 1; | ||
85 | break; | ||
86 | case 2: | 71 | case 2: |
87 | retval = rpaphp_set_attention_status(slot, LED_ID); | 72 | break; |
88 | hotplug_slot->info->attention_status = 2; | 73 | default: |
74 | value = 1; | ||
89 | break; | 75 | break; |
90 | } | 76 | } |
91 | up(&rpaphp_sem); | 77 | |
92 | return retval; | 78 | rc = rtas_set_indicator(DR_INDICATOR, slot->index, value); |
79 | if (!rc) | ||
80 | hotplug_slot->info->attention_status = value; | ||
81 | |||
82 | return rc; | ||
93 | } | 83 | } |
94 | 84 | ||
95 | /** | 85 | /** |
96 | * get_power_status - get power status of a slot | 86 | * get_power_status - get power status of a slot |
97 | * @hotplug_slot: slot to get status | 87 | * @hotplug_slot: slot to get status |
98 | * @value: pointer to store status | 88 | * @value: pointer to store status |
99 | * | ||
100 | * | ||
101 | */ | 89 | */ |
102 | static int get_power_status(struct hotplug_slot *hotplug_slot, u8 * value) | 90 | static int get_power_status(struct hotplug_slot *hotplug_slot, u8 * value) |
103 | { | 91 | { |
104 | int retval; | 92 | int retval, level; |
105 | struct slot *slot = (struct slot *)hotplug_slot->private; | 93 | struct slot *slot = (struct slot *)hotplug_slot->private; |
106 | 94 | ||
107 | down(&rpaphp_sem); | 95 | retval = rtas_get_power_level (slot->power_domain, &level); |
108 | retval = rpaphp_get_power_status(slot, value); | 96 | if (!retval) |
109 | up(&rpaphp_sem); | 97 | *value = level; |
110 | return retval; | 98 | return retval; |
111 | } | 99 | } |
112 | 100 | ||
113 | /** | 101 | /** |
114 | * get_attention_status - get attention LED status | 102 | * get_attention_status - get attention LED status |
115 | * | ||
116 | * | ||
117 | */ | 103 | */ |
118 | static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 * value) | 104 | static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 * value) |
119 | { | 105 | { |
120 | int retval = 0; | ||
121 | struct slot *slot = (struct slot *)hotplug_slot->private; | 106 | struct slot *slot = (struct slot *)hotplug_slot->private; |
122 | 107 | *value = slot->hotplug_slot->info->attention_status; | |
123 | down(&rpaphp_sem); | 108 | return 0; |
124 | *value = rpaphp_get_attention_status(slot); | ||
125 | up(&rpaphp_sem); | ||
126 | return retval; | ||
127 | } | 109 | } |
128 | 110 | ||
129 | static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 * value) | 111 | static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 * value) |
130 | { | 112 | { |
131 | struct slot *slot = (struct slot *)hotplug_slot->private; | 113 | struct slot *slot = (struct slot *)hotplug_slot->private; |
132 | int retval = 0; | 114 | int rc, state; |
133 | 115 | ||
134 | down(&rpaphp_sem); | 116 | rc = rpaphp_get_sensor_state(slot, &state); |
135 | retval = rpaphp_get_pci_adapter_status(slot, 0, value); | 117 | |
136 | up(&rpaphp_sem); | 118 | *value = NOT_VALID; |
137 | return retval; | 119 | if (rc) |
120 | return rc; | ||
121 | |||
122 | if (state == EMPTY) | ||
123 | *value = EMPTY; | ||
124 | else if (state == PRESENT) | ||
125 | *value = slot->state; | ||
126 | |||
127 | return 0; | ||
138 | } | 128 | } |
139 | 129 | ||
140 | static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) | 130 | static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) |
141 | { | 131 | { |
142 | struct slot *slot = (struct slot *)hotplug_slot->private; | 132 | struct slot *slot = (struct slot *)hotplug_slot->private; |
143 | 133 | ||
144 | down(&rpaphp_sem); | ||
145 | switch (slot->type) { | 134 | switch (slot->type) { |
146 | case 1: | 135 | case 1: |
147 | case 2: | 136 | case 2: |
@@ -172,7 +161,6 @@ static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_spe | |||
172 | break; | 161 | break; |
173 | 162 | ||
174 | } | 163 | } |
175 | up(&rpaphp_sem); | ||
176 | return 0; | 164 | return 0; |
177 | } | 165 | } |
178 | 166 | ||
@@ -265,6 +253,14 @@ static int is_php_type(char *drc_type) | |||
265 | return 1; | 253 | return 1; |
266 | } | 254 | } |
267 | 255 | ||
256 | /** | ||
257 | * is_php_dn() - return 1 if this is a hotpluggable pci slot, else 0 | ||
258 | * | ||
259 | * This routine will return true only if the device node is | ||
260 | * a hotpluggable slot. This routine will return false | ||
261 | * for built-in pci slots (even when the built-in slots are | ||
262 | * dlparable.) | ||
263 | */ | ||
268 | static int is_php_dn(struct device_node *dn, const int **indexes, | 264 | static int is_php_dn(struct device_node *dn, const int **indexes, |
269 | const int **names, const int **types, const int **power_domains) | 265 | const int **names, const int **types, const int **power_domains) |
270 | { | 266 | { |
@@ -272,24 +268,31 @@ static int is_php_dn(struct device_node *dn, const int **indexes, | |||
272 | int rc; | 268 | int rc; |
273 | 269 | ||
274 | rc = get_children_props(dn, indexes, names, &drc_types, power_domains); | 270 | rc = get_children_props(dn, indexes, names, &drc_types, power_domains); |
275 | if (rc >= 0) { | 271 | if (rc < 0) |
276 | if (is_php_type((char *) &drc_types[1])) { | 272 | return 0; |
277 | *types = drc_types; | ||
278 | return 1; | ||
279 | } | ||
280 | } | ||
281 | 273 | ||
282 | return 0; | 274 | if (!is_php_type((char *) &drc_types[1])) |
275 | return 0; | ||
276 | |||
277 | *types = drc_types; | ||
278 | return 1; | ||
283 | } | 279 | } |
284 | 280 | ||
285 | /** | 281 | /** |
286 | * rpaphp_add_slot -- add hotplug or dlpar slot | 282 | * rpaphp_add_slot -- declare a hotplug slot to the hotplug subsystem. |
283 | * @dn device node of slot | ||
284 | * | ||
285 | * This subroutine will register a hotplugable slot with the | ||
286 | * PCI hotplug infrastructure. This routine is typicaly called | ||
287 | * during boot time, if the hotplug slots are present at boot time, | ||
288 | * or is called later, by the dlpar add code, if the slot is | ||
289 | * being dynamically added during runtime. | ||
290 | * | ||
291 | * If the device node points at an embedded (built-in) slot, this | ||
292 | * routine will just return without doing anything, since embedded | ||
293 | * slots cannot be hotplugged. | ||
287 | * | 294 | * |
288 | * rpaphp not only registers PCI hotplug slots(HOTPLUG), | 295 | * To remove a slot, it suffices to call rpaphp_deregister_slot() |
289 | * but also logical DR slots(EMBEDDED). | ||
290 | * HOTPLUG slot: An adapter can be physically added/removed. | ||
291 | * EMBEDDED slot: An adapter can be logically removed/added | ||
292 | * from/to a partition with the slot. | ||
293 | */ | 296 | */ |
294 | int rpaphp_add_slot(struct device_node *dn) | 297 | int rpaphp_add_slot(struct device_node *dn) |
295 | { | 298 | { |
@@ -299,34 +302,42 @@ int rpaphp_add_slot(struct device_node *dn) | |||
299 | const int *indexes, *names, *types, *power_domains; | 302 | const int *indexes, *names, *types, *power_domains; |
300 | char *name, *type; | 303 | char *name, *type; |
301 | 304 | ||
305 | if (!dn->name || strcmp(dn->name, "pci")) | ||
306 | return 0; | ||
307 | |||
308 | /* If this is not a hotplug slot, return without doing anything. */ | ||
309 | if (!is_php_dn(dn, &indexes, &names, &types, &power_domains)) | ||
310 | return 0; | ||
311 | |||
302 | dbg("Entry %s: dn->full_name=%s\n", __FUNCTION__, dn->full_name); | 312 | dbg("Entry %s: dn->full_name=%s\n", __FUNCTION__, dn->full_name); |
303 | 313 | ||
304 | /* register PCI devices */ | 314 | /* register PCI devices */ |
305 | if (dn->name != 0 && strcmp(dn->name, "pci") == 0) { | 315 | name = (char *) &names[1]; |
306 | if (!is_php_dn(dn, &indexes, &names, &types, &power_domains)) | 316 | type = (char *) &types[1]; |
307 | goto exit; | 317 | for (i = 0; i < indexes[0]; i++) { |
308 | 318 | ||
309 | name = (char *) &names[1]; | 319 | slot = alloc_slot_struct(dn, indexes[i + 1], name, power_domains[i + 1]); |
310 | type = (char *) &types[1]; | 320 | if (!slot) |
311 | for (i = 0; i < indexes[0]; i++, | 321 | return -ENOMEM; |
312 | name += (strlen(name) + 1), type += (strlen(type) + 1)) { | 322 | |
313 | 323 | slot->type = simple_strtoul(type, NULL, 10); | |
314 | if (!(slot = alloc_slot_struct(dn, indexes[i + 1], name, | ||
315 | power_domains[i + 1]))) { | ||
316 | retval = -ENOMEM; | ||
317 | goto exit; | ||
318 | } | ||
319 | slot->type = simple_strtoul(type, NULL, 10); | ||
320 | 324 | ||
321 | dbg("Found drc-index:0x%x drc-name:%s drc-type:%s\n", | 325 | dbg("Found drc-index:0x%x drc-name:%s drc-type:%s\n", |
322 | indexes[i + 1], name, type); | 326 | indexes[i + 1], name, type); |
323 | 327 | ||
324 | retval = rpaphp_register_pci_slot(slot); | 328 | retval = rpaphp_enable_slot(slot); |
325 | } | 329 | if (!retval) |
330 | retval = rpaphp_register_slot(slot); | ||
331 | |||
332 | if (retval) | ||
333 | dealloc_slot_struct(slot); | ||
334 | |||
335 | name += strlen(name) + 1; | ||
336 | type += strlen(type) + 1; | ||
326 | } | 337 | } |
327 | exit: | 338 | dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval); |
328 | dbg("%s - Exit: num_slots=%d rc[%d]\n", | 339 | |
329 | __FUNCTION__, num_slots, retval); | 340 | /* XXX FIXME: reports a failure only if last entry in loop failed */ |
330 | return retval; | 341 | return retval; |
331 | } | 342 | } |
332 | 343 | ||
@@ -354,7 +365,6 @@ static int __init rpaphp_init(void) | |||
354 | struct device_node *dn = NULL; | 365 | struct device_node *dn = NULL; |
355 | 366 | ||
356 | info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); | 367 | info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); |
357 | init_MUTEX(&rpaphp_sem); | ||
358 | 368 | ||
359 | while ((dn = of_find_node_by_name(dn, "pci"))) | 369 | while ((dn = of_find_node_by_name(dn, "pci"))) |
360 | rpaphp_add_slot(dn); | 370 | rpaphp_add_slot(dn); |
@@ -367,8 +377,9 @@ static void __exit rpaphp_exit(void) | |||
367 | cleanup_slots(); | 377 | cleanup_slots(); |
368 | } | 378 | } |
369 | 379 | ||
370 | static int __enable_slot(struct slot *slot) | 380 | static int enable_slot(struct hotplug_slot *hotplug_slot) |
371 | { | 381 | { |
382 | struct slot *slot = (struct slot *)hotplug_slot->private; | ||
372 | int state; | 383 | int state; |
373 | int retval; | 384 | int retval; |
374 | 385 | ||
@@ -392,46 +403,17 @@ static int __enable_slot(struct slot *slot) | |||
392 | return 0; | 403 | return 0; |
393 | } | 404 | } |
394 | 405 | ||
395 | static int enable_slot(struct hotplug_slot *hotplug_slot) | 406 | static int disable_slot(struct hotplug_slot *hotplug_slot) |
396 | { | 407 | { |
397 | int retval; | ||
398 | struct slot *slot = (struct slot *)hotplug_slot->private; | 408 | struct slot *slot = (struct slot *)hotplug_slot->private; |
399 | |||
400 | down(&rpaphp_sem); | ||
401 | retval = __enable_slot(slot); | ||
402 | up(&rpaphp_sem); | ||
403 | |||
404 | return retval; | ||
405 | } | ||
406 | |||
407 | static int __disable_slot(struct slot *slot) | ||
408 | { | ||
409 | struct pci_dev *dev, *tmp; | ||
410 | |||
411 | if (slot->state == NOT_CONFIGURED) | 409 | if (slot->state == NOT_CONFIGURED) |
412 | return -EINVAL; | 410 | return -EINVAL; |
413 | 411 | ||
414 | list_for_each_entry_safe(dev, tmp, &slot->bus->devices, bus_list) { | 412 | pcibios_remove_pci_devices(slot->bus); |
415 | eeh_remove_bus_device(dev); | ||
416 | pci_remove_bus_device(dev); | ||
417 | } | ||
418 | |||
419 | slot->state = NOT_CONFIGURED; | 413 | slot->state = NOT_CONFIGURED; |
420 | return 0; | 414 | return 0; |
421 | } | 415 | } |
422 | 416 | ||
423 | static int disable_slot(struct hotplug_slot *hotplug_slot) | ||
424 | { | ||
425 | struct slot *slot = (struct slot *)hotplug_slot->private; | ||
426 | int retval; | ||
427 | |||
428 | down(&rpaphp_sem); | ||
429 | retval = __disable_slot (slot); | ||
430 | up(&rpaphp_sem); | ||
431 | |||
432 | return retval; | ||
433 | } | ||
434 | |||
435 | struct hotplug_slot_ops rpaphp_hotplug_slot_ops = { | 417 | struct hotplug_slot_ops rpaphp_hotplug_slot_ops = { |
436 | .owner = THIS_MODULE, | 418 | .owner = THIS_MODULE, |
437 | .enable_slot = enable_slot, | 419 | .enable_slot = enable_slot, |
diff --git a/drivers/pci/hotplug/rpaphp_pci.c b/drivers/pci/hotplug/rpaphp_pci.c index 6f6cbede5135..54ca8650d511 100644 --- a/drivers/pci/hotplug/rpaphp_pci.c +++ b/drivers/pci/hotplug/rpaphp_pci.c | |||
@@ -64,75 +64,6 @@ int rpaphp_get_sensor_state(struct slot *slot, int *state) | |||
64 | return rc; | 64 | return rc; |
65 | } | 65 | } |
66 | 66 | ||
67 | /** | ||
68 | * get_pci_adapter_status - get the status of a slot | ||
69 | * | ||
70 | * 0-- slot is empty | ||
71 | * 1-- adapter is configured | ||
72 | * 2-- adapter is not configured | ||
73 | * 3-- not valid | ||
74 | */ | ||
75 | int rpaphp_get_pci_adapter_status(struct slot *slot, int is_init, u8 * value) | ||
76 | { | ||
77 | struct pci_bus *bus; | ||
78 | int state, rc; | ||
79 | |||
80 | *value = NOT_VALID; | ||
81 | rc = rpaphp_get_sensor_state(slot, &state); | ||
82 | if (rc) | ||
83 | goto exit; | ||
84 | |||
85 | if (state == EMPTY) | ||
86 | *value = EMPTY; | ||
87 | else if (state == PRESENT) { | ||
88 | if (!is_init) { | ||
89 | /* at run-time slot->state can be changed by */ | ||
90 | /* config/unconfig adapter */ | ||
91 | *value = slot->state; | ||
92 | } else { | ||
93 | bus = pcibios_find_pci_bus(slot->dn); | ||
94 | if (bus && !list_empty(&bus->devices)) | ||
95 | *value = CONFIGURED; | ||
96 | else | ||
97 | *value = NOT_CONFIGURED; | ||
98 | } | ||
99 | } | ||
100 | exit: | ||
101 | return rc; | ||
102 | } | ||
103 | |||
104 | static void print_slot_pci_funcs(struct pci_bus *bus) | ||
105 | { | ||
106 | struct device_node *dn; | ||
107 | struct pci_dev *dev; | ||
108 | |||
109 | dn = pci_bus_to_OF_node(bus); | ||
110 | if (!dn) | ||
111 | return; | ||
112 | |||
113 | dbg("%s: pci_devs of slot[%s]\n", __FUNCTION__, dn->full_name); | ||
114 | list_for_each_entry (dev, &bus->devices, bus_list) | ||
115 | dbg("\t%s\n", pci_name(dev)); | ||
116 | return; | ||
117 | } | ||
118 | |||
119 | static int setup_pci_hotplug_slot_info(struct slot *slot) | ||
120 | { | ||
121 | struct hotplug_slot_info *hotplug_slot_info = slot->hotplug_slot->info; | ||
122 | |||
123 | dbg("%s Initilize the PCI slot's hotplug->info structure ...\n", | ||
124 | __FUNCTION__); | ||
125 | rpaphp_get_power_status(slot, &hotplug_slot_info->power_status); | ||
126 | rpaphp_get_pci_adapter_status(slot, 1, | ||
127 | &hotplug_slot_info->adapter_status); | ||
128 | if (hotplug_slot_info->adapter_status == NOT_VALID) { | ||
129 | err("%s: NOT_VALID: skip dn->full_name=%s\n", | ||
130 | __FUNCTION__, slot->dn->full_name); | ||
131 | return -EINVAL; | ||
132 | } | ||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | static void set_slot_name(struct slot *slot) | 67 | static void set_slot_name(struct slot *slot) |
137 | { | 68 | { |
138 | struct pci_bus *bus = slot->bus; | 69 | struct pci_bus *bus = slot->bus; |
@@ -146,69 +77,73 @@ static void set_slot_name(struct slot *slot) | |||
146 | bus->number); | 77 | bus->number); |
147 | } | 78 | } |
148 | 79 | ||
149 | static int setup_pci_slot(struct slot *slot) | 80 | /** |
81 | * rpaphp_enable_slot - record slot state, config pci device | ||
82 | * | ||
83 | * Initialize values in the slot, and the hotplug_slot info | ||
84 | * structures to indicate if there is a pci card plugged into | ||
85 | * the slot. If the slot is not empty, run the pcibios routine | ||
86 | * to get pcibios stuff correctly set up. | ||
87 | */ | ||
88 | int rpaphp_enable_slot(struct slot *slot) | ||
150 | { | 89 | { |
151 | struct device_node *dn = slot->dn; | 90 | int rc, level, state; |
152 | struct pci_bus *bus; | 91 | struct pci_bus *bus; |
92 | struct hotplug_slot_info *info = slot->hotplug_slot->info; | ||
93 | |||
94 | info->adapter_status = NOT_VALID; | ||
95 | slot->state = EMPTY; | ||
96 | |||
97 | /* Find out if the power is turned on for the slot */ | ||
98 | rc = rtas_get_power_level(slot->power_domain, &level); | ||
99 | if (rc) | ||
100 | return rc; | ||
101 | info->power_status = level; | ||
102 | |||
103 | /* Figure out if there is an adapter in the slot */ | ||
104 | rc = rpaphp_get_sensor_state(slot, &state); | ||
105 | if (rc) | ||
106 | return rc; | ||
153 | 107 | ||
154 | BUG_ON(!dn); | 108 | bus = pcibios_find_pci_bus(slot->dn); |
155 | bus = pcibios_find_pci_bus(dn); | ||
156 | if (!bus) { | 109 | if (!bus) { |
157 | err("%s: no pci_bus for dn %s\n", __FUNCTION__, dn->full_name); | 110 | err("%s: no pci_bus for dn %s\n", __FUNCTION__, slot->dn->full_name); |
158 | goto exit_rc; | 111 | return -EINVAL; |
159 | } | 112 | } |
160 | 113 | ||
114 | info->adapter_status = EMPTY; | ||
161 | slot->bus = bus; | 115 | slot->bus = bus; |
162 | slot->pci_devs = &bus->devices; | 116 | slot->pci_devs = &bus->devices; |
163 | set_slot_name(slot); | 117 | set_slot_name(slot); |
164 | 118 | ||
165 | /* find slot's pci_dev if it's not empty */ | 119 | /* if there's an adapter in the slot, go add the pci devices */ |
166 | if (slot->hotplug_slot->info->adapter_status == EMPTY) { | 120 | if (state == PRESENT) { |
167 | slot->state = EMPTY; /* slot is empty */ | 121 | info->adapter_status = NOT_CONFIGURED; |
168 | } else { | 122 | slot->state = NOT_CONFIGURED; |
169 | /* slot is occupied */ | 123 | |
170 | if (!dn->child) { | 124 | /* non-empty slot has to have child */ |
171 | /* non-empty slot has to have child */ | 125 | if (!slot->dn->child) { |
172 | err("%s: slot[%s]'s device_node doesn't have child for adapter\n", | 126 | err("%s: slot[%s]'s device_node doesn't have child for adapter\n", |
173 | __FUNCTION__, slot->name); | 127 | __FUNCTION__, slot->name); |
174 | goto exit_rc; | 128 | return -EINVAL; |
175 | } | 129 | } |
176 | 130 | ||
177 | if (slot->hotplug_slot->info->adapter_status == NOT_CONFIGURED) { | 131 | if (list_empty(&bus->devices)) |
178 | dbg("%s CONFIGURING pci adapter in slot[%s]\n", | 132 | pcibios_add_pci_devices(bus); |
179 | __FUNCTION__, slot->name); | ||
180 | pcibios_add_pci_devices(slot->bus); | ||
181 | 133 | ||
182 | } else if (slot->hotplug_slot->info->adapter_status != CONFIGURED) { | 134 | if (!list_empty(&bus->devices)) { |
183 | err("%s: slot[%s]'s adapter_status is NOT_VALID.\n", | 135 | info->adapter_status = CONFIGURED; |
184 | __FUNCTION__, slot->name); | ||
185 | goto exit_rc; | ||
186 | } | ||
187 | print_slot_pci_funcs(slot->bus); | ||
188 | if (!list_empty(slot->pci_devs)) { | ||
189 | slot->state = CONFIGURED; | 136 | slot->state = CONFIGURED; |
190 | } else { | 137 | } |
191 | /* DLPAR add as opposed to | 138 | |
192 | * boot time */ | 139 | if (debug) { |
193 | slot->state = NOT_CONFIGURED; | 140 | struct pci_dev *dev; |
141 | dbg("%s: pci_devs of slot[%s]\n", __FUNCTION__, slot->dn->full_name); | ||
142 | list_for_each_entry (dev, &bus->devices, bus_list) | ||
143 | dbg("\t%s\n", pci_name(dev)); | ||
194 | } | 144 | } |
195 | } | 145 | } |
196 | return 0; | ||
197 | exit_rc: | ||
198 | dealloc_slot_struct(slot); | ||
199 | return -EINVAL; | ||
200 | } | ||
201 | 146 | ||
202 | int rpaphp_register_pci_slot(struct slot *slot) | 147 | return 0; |
203 | { | ||
204 | int rc = -EINVAL; | ||
205 | |||
206 | if (setup_pci_hotplug_slot_info(slot)) | ||
207 | goto exit_rc; | ||
208 | if (setup_pci_slot(slot)) | ||
209 | goto exit_rc; | ||
210 | rc = rpaphp_register_slot(slot); | ||
211 | exit_rc: | ||
212 | return rc; | ||
213 | } | 148 | } |
214 | 149 | ||
diff --git a/drivers/pci/hotplug/rpaphp_slot.c b/drivers/pci/hotplug/rpaphp_slot.c index 3009193f0058..d4ee8723fcb3 100644 --- a/drivers/pci/hotplug/rpaphp_slot.c +++ b/drivers/pci/hotplug/rpaphp_slot.c | |||
@@ -56,7 +56,6 @@ static struct hotplug_slot_attribute php_attr_location = { | |||
56 | static void rpaphp_release_slot(struct hotplug_slot *hotplug_slot) | 56 | static void rpaphp_release_slot(struct hotplug_slot *hotplug_slot) |
57 | { | 57 | { |
58 | struct slot *slot = (struct slot *) hotplug_slot->private; | 58 | struct slot *slot = (struct slot *) hotplug_slot->private; |
59 | |||
60 | dealloc_slot_struct(slot); | 59 | dealloc_slot_struct(slot); |
61 | } | 60 | } |
62 | 61 | ||
@@ -65,12 +64,12 @@ void dealloc_slot_struct(struct slot *slot) | |||
65 | kfree(slot->hotplug_slot->info); | 64 | kfree(slot->hotplug_slot->info); |
66 | kfree(slot->hotplug_slot->name); | 65 | kfree(slot->hotplug_slot->name); |
67 | kfree(slot->hotplug_slot); | 66 | kfree(slot->hotplug_slot); |
67 | kfree(slot->location); | ||
68 | kfree(slot); | 68 | kfree(slot); |
69 | return; | ||
70 | } | 69 | } |
71 | 70 | ||
72 | struct slot *alloc_slot_struct(struct device_node *dn, int drc_index, char *drc_name, | 71 | struct slot *alloc_slot_struct(struct device_node *dn, |
73 | int power_domain) | 72 | int drc_index, char *drc_name, int power_domain) |
74 | { | 73 | { |
75 | struct slot *slot; | 74 | struct slot *slot; |
76 | 75 | ||
@@ -115,7 +114,7 @@ error_nomem: | |||
115 | 114 | ||
116 | static int is_registered(struct slot *slot) | 115 | static int is_registered(struct slot *slot) |
117 | { | 116 | { |
118 | struct slot *tmp_slot; | 117 | struct slot *tmp_slot; |
119 | 118 | ||
120 | list_for_each_entry(tmp_slot, &rpaphp_slot_head, rpaphp_slot_list) { | 119 | list_for_each_entry(tmp_slot, &rpaphp_slot_head, rpaphp_slot_list) { |
121 | if (!strcmp(tmp_slot->name, slot->name)) | 120 | if (!strcmp(tmp_slot->name, slot->name)) |
@@ -140,8 +139,6 @@ int rpaphp_deregister_slot(struct slot *slot) | |||
140 | retval = pci_hp_deregister(php_slot); | 139 | retval = pci_hp_deregister(php_slot); |
141 | if (retval) | 140 | if (retval) |
142 | err("Problem unregistering a slot %s\n", slot->name); | 141 | err("Problem unregistering a slot %s\n", slot->name); |
143 | else | ||
144 | num_slots--; | ||
145 | 142 | ||
146 | dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval); | 143 | dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval); |
147 | return retval; | 144 | return retval; |
@@ -160,14 +157,13 @@ int rpaphp_register_slot(struct slot *slot) | |||
160 | /* should not try to register the same slot twice */ | 157 | /* should not try to register the same slot twice */ |
161 | if (is_registered(slot)) { | 158 | if (is_registered(slot)) { |
162 | err("rpaphp_register_slot: slot[%s] is already registered\n", slot->name); | 159 | err("rpaphp_register_slot: slot[%s] is already registered\n", slot->name); |
163 | retval = -EAGAIN; | 160 | return -EAGAIN; |
164 | goto register_fail; | ||
165 | } | 161 | } |
166 | 162 | ||
167 | retval = pci_hp_register(php_slot); | 163 | retval = pci_hp_register(php_slot); |
168 | if (retval) { | 164 | if (retval) { |
169 | err("pci_hp_register failed with error %d\n", retval); | 165 | err("pci_hp_register failed with error %d\n", retval); |
170 | goto register_fail; | 166 | return retval; |
171 | } | 167 | } |
172 | 168 | ||
173 | /* create "phy_location" file */ | 169 | /* create "phy_location" file */ |
@@ -181,43 +177,10 @@ int rpaphp_register_slot(struct slot *slot) | |||
181 | list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head); | 177 | list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head); |
182 | info("Slot [%s](PCI location=%s) registered\n", slot->name, | 178 | info("Slot [%s](PCI location=%s) registered\n", slot->name, |
183 | slot->location); | 179 | slot->location); |
184 | num_slots++; | ||
185 | return 0; | 180 | return 0; |
186 | 181 | ||
187 | sysfs_fail: | 182 | sysfs_fail: |
188 | pci_hp_deregister(php_slot); | 183 | pci_hp_deregister(php_slot); |
189 | register_fail: | ||
190 | rpaphp_release_slot(php_slot); | ||
191 | return retval; | 184 | return retval; |
192 | } | 185 | } |
193 | 186 | ||
194 | int rpaphp_get_power_status(struct slot *slot, u8 * value) | ||
195 | { | ||
196 | int rc = 0, level; | ||
197 | |||
198 | rc = rtas_get_power_level(slot->power_domain, &level); | ||
199 | if (rc < 0) { | ||
200 | err("failed to get power-level for slot(%s), rc=0x%x\n", | ||
201 | slot->location, rc); | ||
202 | return rc; | ||
203 | } | ||
204 | |||
205 | dbg("%s the power level of slot %s(pwd-domain:0x%x) is %d\n", | ||
206 | __FUNCTION__, slot->name, slot->power_domain, level); | ||
207 | *value = level; | ||
208 | |||
209 | return rc; | ||
210 | } | ||
211 | |||
212 | int rpaphp_set_attention_status(struct slot *slot, u8 status) | ||
213 | { | ||
214 | int rc; | ||
215 | |||
216 | /* status: LED_OFF or LED_ON */ | ||
217 | rc = rtas_set_indicator(DR_INDICATOR, slot->index, status); | ||
218 | if (rc < 0) | ||
219 | err("slot(name=%s location=%s index=0x%x) set attention-status(%d) failed! rc=0x%x\n", | ||
220 | slot->name, slot->location, slot->index, status, rc); | ||
221 | |||
222 | return rc; | ||
223 | } | ||
diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h index 01d31a1f697c..37ed0884b972 100644 --- a/drivers/pci/hotplug/shpchp.h +++ b/drivers/pci/hotplug/shpchp.h | |||
@@ -166,7 +166,7 @@ extern u8 shpchp_handle_power_fault(u8 hp_slot, struct controller *ctrl); | |||
166 | extern int shpchp_configure_device(struct slot *p_slot); | 166 | extern int shpchp_configure_device(struct slot *p_slot); |
167 | extern int shpchp_unconfigure_device(struct slot *p_slot); | 167 | extern int shpchp_unconfigure_device(struct slot *p_slot); |
168 | extern void cleanup_slots(struct controller *ctrl); | 168 | extern void cleanup_slots(struct controller *ctrl); |
169 | extern void queue_pushbutton_work(struct work_struct *work); | 169 | extern void shpchp_queue_pushbutton_work(struct work_struct *work); |
170 | extern int shpc_init( struct controller *ctrl, struct pci_dev *pdev); | 170 | extern int shpc_init( struct controller *ctrl, struct pci_dev *pdev); |
171 | 171 | ||
172 | #ifdef CONFIG_ACPI | 172 | #ifdef CONFIG_ACPI |
diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index 5f4bc08a633a..80dec9796b31 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c | |||
@@ -136,7 +136,7 @@ static int init_slots(struct controller *ctrl) | |||
136 | slot->hpc_ops = ctrl->hpc_ops; | 136 | slot->hpc_ops = ctrl->hpc_ops; |
137 | slot->number = ctrl->first_slot + (ctrl->slot_num_inc * i); | 137 | slot->number = ctrl->first_slot + (ctrl->slot_num_inc * i); |
138 | mutex_init(&slot->lock); | 138 | mutex_init(&slot->lock); |
139 | INIT_DELAYED_WORK(&slot->work, queue_pushbutton_work); | 139 | INIT_DELAYED_WORK(&slot->work, shpchp_queue_pushbutton_work); |
140 | 140 | ||
141 | /* register this slot with the hotplug pci core */ | 141 | /* register this slot with the hotplug pci core */ |
142 | hotplug_slot->private = slot; | 142 | hotplug_slot->private = slot; |
diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c index b746bd265bc6..2c94d44279a3 100644 --- a/drivers/pci/hotplug/shpchp_ctrl.c +++ b/drivers/pci/hotplug/shpchp_ctrl.c | |||
@@ -433,7 +433,7 @@ static void shpchp_pushbutton_thread(struct work_struct *work) | |||
433 | kfree(info); | 433 | kfree(info); |
434 | } | 434 | } |
435 | 435 | ||
436 | void queue_pushbutton_work(struct work_struct *work) | 436 | void shpchp_queue_pushbutton_work(struct work_struct *work) |
437 | { | 437 | { |
438 | struct slot *p_slot = container_of(work, struct slot, work.work); | 438 | struct slot *p_slot = container_of(work, struct slot, work.work); |
439 | struct pushbutton_work_info *info; | 439 | struct pushbutton_work_info *info; |
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 435c1958a7b7..9e1321d0d5e6 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c | |||
@@ -24,20 +24,8 @@ | |||
24 | #include "pci.h" | 24 | #include "pci.h" |
25 | #include "msi.h" | 25 | #include "msi.h" |
26 | 26 | ||
27 | static struct kmem_cache* msi_cachep; | ||
28 | |||
29 | static int pci_msi_enable = 1; | 27 | static int pci_msi_enable = 1; |
30 | 28 | ||
31 | static int msi_cache_init(void) | ||
32 | { | ||
33 | msi_cachep = kmem_cache_create("msi_cache", sizeof(struct msi_desc), | ||
34 | 0, SLAB_HWCACHE_ALIGN, NULL, NULL); | ||
35 | if (!msi_cachep) | ||
36 | return -ENOMEM; | ||
37 | |||
38 | return 0; | ||
39 | } | ||
40 | |||
41 | static void msi_set_enable(struct pci_dev *dev, int enable) | 29 | static void msi_set_enable(struct pci_dev *dev, int enable) |
42 | { | 30 | { |
43 | int pos; | 31 | int pos; |
@@ -68,6 +56,29 @@ static void msix_set_enable(struct pci_dev *dev, int enable) | |||
68 | } | 56 | } |
69 | } | 57 | } |
70 | 58 | ||
59 | static void msix_flush_writes(unsigned int irq) | ||
60 | { | ||
61 | struct msi_desc *entry; | ||
62 | |||
63 | entry = get_irq_msi(irq); | ||
64 | BUG_ON(!entry || !entry->dev); | ||
65 | switch (entry->msi_attrib.type) { | ||
66 | case PCI_CAP_ID_MSI: | ||
67 | /* nothing to do */ | ||
68 | break; | ||
69 | case PCI_CAP_ID_MSIX: | ||
70 | { | ||
71 | int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + | ||
72 | PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET; | ||
73 | readl(entry->mask_base + offset); | ||
74 | break; | ||
75 | } | ||
76 | default: | ||
77 | BUG(); | ||
78 | break; | ||
79 | } | ||
80 | } | ||
81 | |||
71 | static void msi_set_mask_bit(unsigned int irq, int flag) | 82 | static void msi_set_mask_bit(unsigned int irq, int flag) |
72 | { | 83 | { |
73 | struct msi_desc *entry; | 84 | struct msi_desc *entry; |
@@ -187,41 +198,28 @@ void write_msi_msg(unsigned int irq, struct msi_msg *msg) | |||
187 | void mask_msi_irq(unsigned int irq) | 198 | void mask_msi_irq(unsigned int irq) |
188 | { | 199 | { |
189 | msi_set_mask_bit(irq, 1); | 200 | msi_set_mask_bit(irq, 1); |
201 | msix_flush_writes(irq); | ||
190 | } | 202 | } |
191 | 203 | ||
192 | void unmask_msi_irq(unsigned int irq) | 204 | void unmask_msi_irq(unsigned int irq) |
193 | { | 205 | { |
194 | msi_set_mask_bit(irq, 0); | 206 | msi_set_mask_bit(irq, 0); |
207 | msix_flush_writes(irq); | ||
195 | } | 208 | } |
196 | 209 | ||
197 | static int msi_free_irq(struct pci_dev* dev, int irq); | 210 | static int msi_free_irqs(struct pci_dev* dev); |
198 | |||
199 | static int msi_init(void) | ||
200 | { | ||
201 | static int status = -ENOMEM; | ||
202 | |||
203 | if (!status) | ||
204 | return status; | ||
205 | 211 | ||
206 | status = msi_cache_init(); | ||
207 | if (status < 0) { | ||
208 | pci_msi_enable = 0; | ||
209 | printk(KERN_WARNING "PCI: MSI cache init failed\n"); | ||
210 | return status; | ||
211 | } | ||
212 | |||
213 | return status; | ||
214 | } | ||
215 | 212 | ||
216 | static struct msi_desc* alloc_msi_entry(void) | 213 | static struct msi_desc* alloc_msi_entry(void) |
217 | { | 214 | { |
218 | struct msi_desc *entry; | 215 | struct msi_desc *entry; |
219 | 216 | ||
220 | entry = kmem_cache_zalloc(msi_cachep, GFP_KERNEL); | 217 | entry = kzalloc(sizeof(struct msi_desc), GFP_KERNEL); |
221 | if (!entry) | 218 | if (!entry) |
222 | return NULL; | 219 | return NULL; |
223 | 220 | ||
224 | entry->link.tail = entry->link.head = 0; /* single message */ | 221 | INIT_LIST_HEAD(&entry->list); |
222 | entry->irq = 0; | ||
225 | entry->dev = NULL; | 223 | entry->dev = NULL; |
226 | 224 | ||
227 | return entry; | 225 | return entry; |
@@ -256,7 +254,6 @@ static void __pci_restore_msi_state(struct pci_dev *dev) | |||
256 | static void __pci_restore_msix_state(struct pci_dev *dev) | 254 | static void __pci_restore_msix_state(struct pci_dev *dev) |
257 | { | 255 | { |
258 | int pos; | 256 | int pos; |
259 | int irq, head, tail = 0; | ||
260 | struct msi_desc *entry; | 257 | struct msi_desc *entry; |
261 | u16 control; | 258 | u16 control; |
262 | 259 | ||
@@ -266,18 +263,15 @@ static void __pci_restore_msix_state(struct pci_dev *dev) | |||
266 | /* route the table */ | 263 | /* route the table */ |
267 | pci_intx(dev, 0); /* disable intx */ | 264 | pci_intx(dev, 0); /* disable intx */ |
268 | msix_set_enable(dev, 0); | 265 | msix_set_enable(dev, 0); |
269 | irq = head = dev->first_msi_irq; | ||
270 | entry = get_irq_msi(irq); | ||
271 | pos = entry->msi_attrib.pos; | ||
272 | while (head != tail) { | ||
273 | entry = get_irq_msi(irq); | ||
274 | write_msi_msg(irq, &entry->msg); | ||
275 | msi_set_mask_bit(irq, entry->msi_attrib.masked); | ||
276 | 266 | ||
277 | tail = entry->link.tail; | 267 | list_for_each_entry(entry, &dev->msi_list, list) { |
278 | irq = tail; | 268 | write_msi_msg(entry->irq, &entry->msg); |
269 | msi_set_mask_bit(entry->irq, entry->msi_attrib.masked); | ||
279 | } | 270 | } |
280 | 271 | ||
272 | BUG_ON(list_empty(&dev->msi_list)); | ||
273 | entry = list_entry(dev->msi_list.next, struct msi_desc, list); | ||
274 | pos = entry->msi_attrib.pos; | ||
281 | pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control); | 275 | pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control); |
282 | control &= ~PCI_MSIX_FLAGS_MASKALL; | 276 | control &= ~PCI_MSIX_FLAGS_MASKALL; |
283 | control |= PCI_MSIX_FLAGS_ENABLE; | 277 | control |= PCI_MSIX_FLAGS_ENABLE; |
@@ -303,7 +297,7 @@ void pci_restore_msi_state(struct pci_dev *dev) | |||
303 | static int msi_capability_init(struct pci_dev *dev) | 297 | static int msi_capability_init(struct pci_dev *dev) |
304 | { | 298 | { |
305 | struct msi_desc *entry; | 299 | struct msi_desc *entry; |
306 | int pos, irq; | 300 | int pos, ret; |
307 | u16 control; | 301 | u16 control; |
308 | 302 | ||
309 | msi_set_enable(dev, 0); /* Ensure msi is disabled as I set it up */ | 303 | msi_set_enable(dev, 0); /* Ensure msi is disabled as I set it up */ |
@@ -340,23 +334,21 @@ static int msi_capability_init(struct pci_dev *dev) | |||
340 | msi_mask_bits_reg(pos, is_64bit_address(control)), | 334 | msi_mask_bits_reg(pos, is_64bit_address(control)), |
341 | maskbits); | 335 | maskbits); |
342 | } | 336 | } |
337 | list_add(&entry->list, &dev->msi_list); | ||
338 | |||
343 | /* Configure MSI capability structure */ | 339 | /* Configure MSI capability structure */ |
344 | irq = arch_setup_msi_irq(dev, entry); | 340 | ret = arch_setup_msi_irqs(dev, 1, PCI_CAP_ID_MSI); |
345 | if (irq < 0) { | 341 | if (ret) { |
346 | kmem_cache_free(msi_cachep, entry); | 342 | msi_free_irqs(dev); |
347 | return irq; | 343 | return ret; |
348 | } | 344 | } |
349 | entry->link.head = irq; | ||
350 | entry->link.tail = irq; | ||
351 | dev->first_msi_irq = irq; | ||
352 | set_irq_msi(irq, entry); | ||
353 | 345 | ||
354 | /* Set MSI enabled bits */ | 346 | /* Set MSI enabled bits */ |
355 | pci_intx(dev, 0); /* disable intx */ | 347 | pci_intx(dev, 0); /* disable intx */ |
356 | msi_set_enable(dev, 1); | 348 | msi_set_enable(dev, 1); |
357 | dev->msi_enabled = 1; | 349 | dev->msi_enabled = 1; |
358 | 350 | ||
359 | dev->irq = irq; | 351 | dev->irq = entry->irq; |
360 | return 0; | 352 | return 0; |
361 | } | 353 | } |
362 | 354 | ||
@@ -373,8 +365,8 @@ static int msi_capability_init(struct pci_dev *dev) | |||
373 | static int msix_capability_init(struct pci_dev *dev, | 365 | static int msix_capability_init(struct pci_dev *dev, |
374 | struct msix_entry *entries, int nvec) | 366 | struct msix_entry *entries, int nvec) |
375 | { | 367 | { |
376 | struct msi_desc *head = NULL, *tail = NULL, *entry = NULL; | 368 | struct msi_desc *entry; |
377 | int irq, pos, i, j, nr_entries, temp = 0; | 369 | int pos, i, j, nr_entries, ret; |
378 | unsigned long phys_addr; | 370 | unsigned long phys_addr; |
379 | u32 table_offset; | 371 | u32 table_offset; |
380 | u16 control; | 372 | u16 control; |
@@ -413,44 +405,34 @@ static int msix_capability_init(struct pci_dev *dev, | |||
413 | entry->dev = dev; | 405 | entry->dev = dev; |
414 | entry->mask_base = base; | 406 | entry->mask_base = base; |
415 | 407 | ||
416 | /* Configure MSI-X capability structure */ | 408 | list_add(&entry->list, &dev->msi_list); |
417 | irq = arch_setup_msi_irq(dev, entry); | ||
418 | if (irq < 0) { | ||
419 | kmem_cache_free(msi_cachep, entry); | ||
420 | break; | ||
421 | } | ||
422 | entries[i].vector = irq; | ||
423 | if (!head) { | ||
424 | entry->link.head = irq; | ||
425 | entry->link.tail = irq; | ||
426 | head = entry; | ||
427 | } else { | ||
428 | entry->link.head = temp; | ||
429 | entry->link.tail = tail->link.tail; | ||
430 | tail->link.tail = irq; | ||
431 | head->link.head = irq; | ||
432 | } | ||
433 | temp = irq; | ||
434 | tail = entry; | ||
435 | |||
436 | set_irq_msi(irq, entry); | ||
437 | } | 409 | } |
438 | if (i != nvec) { | 410 | |
439 | int avail = i - 1; | 411 | ret = arch_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSIX); |
440 | i--; | 412 | if (ret) { |
441 | for (; i >= 0; i--) { | 413 | int avail = 0; |
442 | irq = (entries + i)->vector; | 414 | list_for_each_entry(entry, &dev->msi_list, list) { |
443 | msi_free_irq(dev, irq); | 415 | if (entry->irq != 0) { |
444 | (entries + i)->vector = 0; | 416 | avail++; |
417 | } | ||
445 | } | 418 | } |
419 | |||
420 | msi_free_irqs(dev); | ||
421 | |||
446 | /* If we had some success report the number of irqs | 422 | /* If we had some success report the number of irqs |
447 | * we succeeded in setting up. | 423 | * we succeeded in setting up. |
448 | */ | 424 | */ |
449 | if (avail <= 0) | 425 | if (avail == 0) |
450 | avail = -EBUSY; | 426 | avail = ret; |
451 | return avail; | 427 | return avail; |
452 | } | 428 | } |
453 | dev->first_msi_irq = entries[0].vector; | 429 | |
430 | i = 0; | ||
431 | list_for_each_entry(entry, &dev->msi_list, list) { | ||
432 | entries[i].vector = entry->irq; | ||
433 | set_irq_msi(entry->irq, entry); | ||
434 | i++; | ||
435 | } | ||
454 | /* Set MSI-X enabled bits */ | 436 | /* Set MSI-X enabled bits */ |
455 | pci_intx(dev, 0); /* disable intx */ | 437 | pci_intx(dev, 0); /* disable intx */ |
456 | msix_set_enable(dev, 1); | 438 | msix_set_enable(dev, 1); |
@@ -460,21 +442,32 @@ static int msix_capability_init(struct pci_dev *dev, | |||
460 | } | 442 | } |
461 | 443 | ||
462 | /** | 444 | /** |
463 | * pci_msi_supported - check whether MSI may be enabled on device | 445 | * pci_msi_check_device - check whether MSI may be enabled on a device |
464 | * @dev: pointer to the pci_dev data structure of MSI device function | 446 | * @dev: pointer to the pci_dev data structure of MSI device function |
447 | * @nvec: how many MSIs have been requested ? | ||
448 | * @type: are we checking for MSI or MSI-X ? | ||
465 | * | 449 | * |
466 | * Look at global flags, the device itself, and its parent busses | 450 | * Look at global flags, the device itself, and its parent busses |
467 | * to return 0 if MSI are supported for the device. | 451 | * to determine if MSI/-X are supported for the device. If MSI/-X is |
452 | * supported return 0, else return an error code. | ||
468 | **/ | 453 | **/ |
469 | static | 454 | static int pci_msi_check_device(struct pci_dev* dev, int nvec, int type) |
470 | int pci_msi_supported(struct pci_dev * dev) | ||
471 | { | 455 | { |
472 | struct pci_bus *bus; | 456 | struct pci_bus *bus; |
457 | int ret; | ||
473 | 458 | ||
474 | /* MSI must be globally enabled and supported by the device */ | 459 | /* MSI must be globally enabled and supported by the device */ |
475 | if (!pci_msi_enable || !dev || dev->no_msi) | 460 | if (!pci_msi_enable || !dev || dev->no_msi) |
476 | return -EINVAL; | 461 | return -EINVAL; |
477 | 462 | ||
463 | /* | ||
464 | * You can't ask to have 0 or less MSIs configured. | ||
465 | * a) it's stupid .. | ||
466 | * b) the list manipulation code assumes nvec >= 1. | ||
467 | */ | ||
468 | if (nvec < 1) | ||
469 | return -ERANGE; | ||
470 | |||
478 | /* Any bridge which does NOT route MSI transactions from it's | 471 | /* Any bridge which does NOT route MSI transactions from it's |
479 | * secondary bus to it's primary bus must set NO_MSI flag on | 472 | * secondary bus to it's primary bus must set NO_MSI flag on |
480 | * the secondary pci_bus. | 473 | * the secondary pci_bus. |
@@ -485,6 +478,13 @@ int pci_msi_supported(struct pci_dev * dev) | |||
485 | if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) | 478 | if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) |
486 | return -EINVAL; | 479 | return -EINVAL; |
487 | 480 | ||
481 | ret = arch_msi_check_device(dev, nvec, type); | ||
482 | if (ret) | ||
483 | return ret; | ||
484 | |||
485 | if (!pci_find_capability(dev, type)) | ||
486 | return -EINVAL; | ||
487 | |||
488 | return 0; | 488 | return 0; |
489 | } | 489 | } |
490 | 490 | ||
@@ -500,19 +500,12 @@ int pci_msi_supported(struct pci_dev * dev) | |||
500 | **/ | 500 | **/ |
501 | int pci_enable_msi(struct pci_dev* dev) | 501 | int pci_enable_msi(struct pci_dev* dev) |
502 | { | 502 | { |
503 | int pos, status; | 503 | int status; |
504 | |||
505 | if (pci_msi_supported(dev) < 0) | ||
506 | return -EINVAL; | ||
507 | 504 | ||
508 | status = msi_init(); | 505 | status = pci_msi_check_device(dev, 1, PCI_CAP_ID_MSI); |
509 | if (status < 0) | 506 | if (status) |
510 | return status; | 507 | return status; |
511 | 508 | ||
512 | pos = pci_find_capability(dev, PCI_CAP_ID_MSI); | ||
513 | if (!pos) | ||
514 | return -EINVAL; | ||
515 | |||
516 | WARN_ON(!!dev->msi_enabled); | 509 | WARN_ON(!!dev->msi_enabled); |
517 | 510 | ||
518 | /* Check whether driver already requested for MSI-X irqs */ | 511 | /* Check whether driver already requested for MSI-X irqs */ |
@@ -525,69 +518,54 @@ int pci_enable_msi(struct pci_dev* dev) | |||
525 | status = msi_capability_init(dev); | 518 | status = msi_capability_init(dev); |
526 | return status; | 519 | return status; |
527 | } | 520 | } |
521 | EXPORT_SYMBOL(pci_enable_msi); | ||
528 | 522 | ||
529 | void pci_disable_msi(struct pci_dev* dev) | 523 | void pci_disable_msi(struct pci_dev* dev) |
530 | { | 524 | { |
531 | struct msi_desc *entry; | 525 | struct msi_desc *entry; |
532 | int default_irq; | 526 | int default_irq; |
533 | 527 | ||
534 | if (!pci_msi_enable) | 528 | if (!pci_msi_enable || !dev || !dev->msi_enabled) |
535 | return; | ||
536 | if (!dev) | ||
537 | return; | ||
538 | |||
539 | if (!dev->msi_enabled) | ||
540 | return; | 529 | return; |
541 | 530 | ||
542 | msi_set_enable(dev, 0); | 531 | msi_set_enable(dev, 0); |
543 | pci_intx(dev, 1); /* enable intx */ | 532 | pci_intx(dev, 1); /* enable intx */ |
544 | dev->msi_enabled = 0; | 533 | dev->msi_enabled = 0; |
545 | 534 | ||
546 | entry = get_irq_msi(dev->first_msi_irq); | 535 | BUG_ON(list_empty(&dev->msi_list)); |
547 | if (!entry || !entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) { | 536 | entry = list_entry(dev->msi_list.next, struct msi_desc, list); |
537 | if (!entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) { | ||
548 | return; | 538 | return; |
549 | } | 539 | } |
550 | if (irq_has_action(dev->first_msi_irq)) { | 540 | |
551 | printk(KERN_WARNING "PCI: %s: pci_disable_msi() called without " | 541 | default_irq = entry->msi_attrib.default_irq; |
552 | "free_irq() on MSI irq %d\n", | 542 | msi_free_irqs(dev); |
553 | pci_name(dev), dev->first_msi_irq); | 543 | |
554 | BUG_ON(irq_has_action(dev->first_msi_irq)); | 544 | /* Restore dev->irq to its default pin-assertion irq */ |
555 | } else { | 545 | dev->irq = default_irq; |
556 | default_irq = entry->msi_attrib.default_irq; | ||
557 | msi_free_irq(dev, dev->first_msi_irq); | ||
558 | |||
559 | /* Restore dev->irq to its default pin-assertion irq */ | ||
560 | dev->irq = default_irq; | ||
561 | } | ||
562 | dev->first_msi_irq = 0; | ||
563 | } | 546 | } |
547 | EXPORT_SYMBOL(pci_disable_msi); | ||
564 | 548 | ||
565 | static int msi_free_irq(struct pci_dev* dev, int irq) | 549 | static int msi_free_irqs(struct pci_dev* dev) |
566 | { | 550 | { |
567 | struct msi_desc *entry; | 551 | struct msi_desc *entry, *tmp; |
568 | int head, entry_nr, type; | ||
569 | void __iomem *base; | ||
570 | 552 | ||
571 | entry = get_irq_msi(irq); | 553 | list_for_each_entry(entry, &dev->msi_list, list) |
572 | if (!entry || entry->dev != dev) { | 554 | BUG_ON(irq_has_action(entry->irq)); |
573 | return -EINVAL; | 555 | |
574 | } | 556 | arch_teardown_msi_irqs(dev); |
575 | type = entry->msi_attrib.type; | 557 | |
576 | entry_nr = entry->msi_attrib.entry_nr; | 558 | list_for_each_entry_safe(entry, tmp, &dev->msi_list, list) { |
577 | head = entry->link.head; | 559 | if (entry->msi_attrib.type == PCI_CAP_ID_MSIX) { |
578 | base = entry->mask_base; | 560 | if (list_is_last(&entry->list, &dev->msi_list)) |
579 | get_irq_msi(entry->link.head)->link.tail = entry->link.tail; | 561 | iounmap(entry->mask_base); |
580 | get_irq_msi(entry->link.tail)->link.head = entry->link.head; | 562 | |
581 | 563 | writel(1, entry->mask_base + entry->msi_attrib.entry_nr | |
582 | arch_teardown_msi_irq(irq); | 564 | * PCI_MSIX_ENTRY_SIZE |
583 | kmem_cache_free(msi_cachep, entry); | 565 | + PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET); |
584 | 566 | } | |
585 | if (type == PCI_CAP_ID_MSIX) { | 567 | list_del(&entry->list); |
586 | writel(1, base + entry_nr * PCI_MSIX_ENTRY_SIZE + | 568 | kfree(entry); |
587 | PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET); | ||
588 | |||
589 | if (head == irq) | ||
590 | iounmap(base); | ||
591 | } | 569 | } |
592 | 570 | ||
593 | return 0; | 571 | return 0; |
@@ -614,17 +592,14 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) | |||
614 | int i, j; | 592 | int i, j; |
615 | u16 control; | 593 | u16 control; |
616 | 594 | ||
617 | if (!entries || pci_msi_supported(dev) < 0) | 595 | if (!entries) |
618 | return -EINVAL; | 596 | return -EINVAL; |
619 | 597 | ||
620 | status = msi_init(); | 598 | status = pci_msi_check_device(dev, nvec, PCI_CAP_ID_MSIX); |
621 | if (status < 0) | 599 | if (status) |
622 | return status; | 600 | return status; |
623 | 601 | ||
624 | pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); | 602 | pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); |
625 | if (!pos) | ||
626 | return -EINVAL; | ||
627 | |||
628 | pci_read_config_word(dev, msi_control_reg(pos), &control); | 603 | pci_read_config_word(dev, msi_control_reg(pos), &control); |
629 | nr_entries = multi_msix_capable(control); | 604 | nr_entries = multi_msix_capable(control); |
630 | if (nvec > nr_entries) | 605 | if (nvec > nr_entries) |
@@ -651,41 +626,25 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) | |||
651 | status = msix_capability_init(dev, entries, nvec); | 626 | status = msix_capability_init(dev, entries, nvec); |
652 | return status; | 627 | return status; |
653 | } | 628 | } |
629 | EXPORT_SYMBOL(pci_enable_msix); | ||
654 | 630 | ||
655 | void pci_disable_msix(struct pci_dev* dev) | 631 | static void msix_free_all_irqs(struct pci_dev *dev) |
656 | { | 632 | { |
657 | int irq, head, tail = 0, warning = 0; | 633 | msi_free_irqs(dev); |
658 | 634 | } | |
659 | if (!pci_msi_enable) | ||
660 | return; | ||
661 | if (!dev) | ||
662 | return; | ||
663 | 635 | ||
664 | if (!dev->msix_enabled) | 636 | void pci_disable_msix(struct pci_dev* dev) |
637 | { | ||
638 | if (!pci_msi_enable || !dev || !dev->msix_enabled) | ||
665 | return; | 639 | return; |
666 | 640 | ||
667 | msix_set_enable(dev, 0); | 641 | msix_set_enable(dev, 0); |
668 | pci_intx(dev, 1); /* enable intx */ | 642 | pci_intx(dev, 1); /* enable intx */ |
669 | dev->msix_enabled = 0; | 643 | dev->msix_enabled = 0; |
670 | 644 | ||
671 | irq = head = dev->first_msi_irq; | 645 | msix_free_all_irqs(dev); |
672 | while (head != tail) { | ||
673 | tail = get_irq_msi(irq)->link.tail; | ||
674 | if (irq_has_action(irq)) | ||
675 | warning = 1; | ||
676 | else if (irq != head) /* Release MSI-X irq */ | ||
677 | msi_free_irq(dev, irq); | ||
678 | irq = tail; | ||
679 | } | ||
680 | msi_free_irq(dev, irq); | ||
681 | if (warning) { | ||
682 | printk(KERN_WARNING "PCI: %s: pci_disable_msix() called without " | ||
683 | "free_irq() on all MSI-X irqs\n", | ||
684 | pci_name(dev)); | ||
685 | BUG_ON(warning > 0); | ||
686 | } | ||
687 | dev->first_msi_irq = 0; | ||
688 | } | 646 | } |
647 | EXPORT_SYMBOL(pci_disable_msix); | ||
689 | 648 | ||
690 | /** | 649 | /** |
691 | * msi_remove_pci_irq_vectors - reclaim MSI(X) irqs to unused state | 650 | * msi_remove_pci_irq_vectors - reclaim MSI(X) irqs to unused state |
@@ -701,38 +660,11 @@ void msi_remove_pci_irq_vectors(struct pci_dev* dev) | |||
701 | if (!pci_msi_enable || !dev) | 660 | if (!pci_msi_enable || !dev) |
702 | return; | 661 | return; |
703 | 662 | ||
704 | if (dev->msi_enabled) { | 663 | if (dev->msi_enabled) |
705 | if (irq_has_action(dev->first_msi_irq)) { | 664 | msi_free_irqs(dev); |
706 | printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() " | 665 | |
707 | "called without free_irq() on MSI irq %d\n", | 666 | if (dev->msix_enabled) |
708 | pci_name(dev), dev->first_msi_irq); | 667 | msix_free_all_irqs(dev); |
709 | BUG_ON(irq_has_action(dev->first_msi_irq)); | ||
710 | } else /* Release MSI irq assigned to this device */ | ||
711 | msi_free_irq(dev, dev->first_msi_irq); | ||
712 | } | ||
713 | if (dev->msix_enabled) { | ||
714 | int irq, head, tail = 0, warning = 0; | ||
715 | void __iomem *base = NULL; | ||
716 | |||
717 | irq = head = dev->first_msi_irq; | ||
718 | while (head != tail) { | ||
719 | tail = get_irq_msi(irq)->link.tail; | ||
720 | base = get_irq_msi(irq)->mask_base; | ||
721 | if (irq_has_action(irq)) | ||
722 | warning = 1; | ||
723 | else if (irq != head) /* Release MSI-X irq */ | ||
724 | msi_free_irq(dev, irq); | ||
725 | irq = tail; | ||
726 | } | ||
727 | msi_free_irq(dev, irq); | ||
728 | if (warning) { | ||
729 | iounmap(base); | ||
730 | printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() " | ||
731 | "called without free_irq() on all MSI-X irqs\n", | ||
732 | pci_name(dev)); | ||
733 | BUG_ON(warning > 0); | ||
734 | } | ||
735 | } | ||
736 | } | 668 | } |
737 | 669 | ||
738 | void pci_no_msi(void) | 670 | void pci_no_msi(void) |
@@ -740,7 +672,53 @@ void pci_no_msi(void) | |||
740 | pci_msi_enable = 0; | 672 | pci_msi_enable = 0; |
741 | } | 673 | } |
742 | 674 | ||
743 | EXPORT_SYMBOL(pci_enable_msi); | 675 | void pci_msi_init_pci_dev(struct pci_dev *dev) |
744 | EXPORT_SYMBOL(pci_disable_msi); | 676 | { |
745 | EXPORT_SYMBOL(pci_enable_msix); | 677 | INIT_LIST_HEAD(&dev->msi_list); |
746 | EXPORT_SYMBOL(pci_disable_msix); | 678 | } |
679 | |||
680 | |||
681 | /* Arch hooks */ | ||
682 | |||
683 | int __attribute__ ((weak)) | ||
684 | arch_msi_check_device(struct pci_dev* dev, int nvec, int type) | ||
685 | { | ||
686 | return 0; | ||
687 | } | ||
688 | |||
689 | int __attribute__ ((weak)) | ||
690 | arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *entry) | ||
691 | { | ||
692 | return 0; | ||
693 | } | ||
694 | |||
695 | int __attribute__ ((weak)) | ||
696 | arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | ||
697 | { | ||
698 | struct msi_desc *entry; | ||
699 | int ret; | ||
700 | |||
701 | list_for_each_entry(entry, &dev->msi_list, list) { | ||
702 | ret = arch_setup_msi_irq(dev, entry); | ||
703 | if (ret) | ||
704 | return ret; | ||
705 | } | ||
706 | |||
707 | return 0; | ||
708 | } | ||
709 | |||
710 | void __attribute__ ((weak)) arch_teardown_msi_irq(unsigned int irq) | ||
711 | { | ||
712 | return; | ||
713 | } | ||
714 | |||
715 | void __attribute__ ((weak)) | ||
716 | arch_teardown_msi_irqs(struct pci_dev *dev) | ||
717 | { | ||
718 | struct msi_desc *entry; | ||
719 | |||
720 | list_for_each_entry(entry, &dev->msi_list, list) { | ||
721 | if (entry->irq != 0) | ||
722 | arch_teardown_msi_irq(entry->irq); | ||
723 | } | ||
724 | } | ||
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 39e80fcef4b3..3bb7739d26a5 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c | |||
@@ -14,20 +14,6 @@ | |||
14 | #include "pci.h" | 14 | #include "pci.h" |
15 | 15 | ||
16 | /* | 16 | /* |
17 | * Registration of PCI drivers and handling of hot-pluggable devices. | ||
18 | */ | ||
19 | |||
20 | /* multithreaded probe logic */ | ||
21 | static int pci_multithread_probe = | ||
22 | #ifdef CONFIG_PCI_MULTITHREAD_PROBE | ||
23 | 1; | ||
24 | #else | ||
25 | 0; | ||
26 | #endif | ||
27 | __module_param_call("", pci_multithread_probe, param_set_bool, param_get_bool, &pci_multithread_probe, 0644); | ||
28 | |||
29 | |||
30 | /* | ||
31 | * Dynamic device IDs are disabled for !CONFIG_HOTPLUG | 17 | * Dynamic device IDs are disabled for !CONFIG_HOTPLUG |
32 | */ | 18 | */ |
33 | 19 | ||
@@ -52,7 +38,7 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count) | |||
52 | { | 38 | { |
53 | struct pci_dynid *dynid; | 39 | struct pci_dynid *dynid; |
54 | struct pci_driver *pdrv = to_pci_driver(driver); | 40 | struct pci_driver *pdrv = to_pci_driver(driver); |
55 | __u32 vendor=PCI_ANY_ID, device=PCI_ANY_ID, subvendor=PCI_ANY_ID, | 41 | __u32 vendor, device, subvendor=PCI_ANY_ID, |
56 | subdevice=PCI_ANY_ID, class=0, class_mask=0; | 42 | subdevice=PCI_ANY_ID, class=0, class_mask=0; |
57 | unsigned long driver_data=0; | 43 | unsigned long driver_data=0; |
58 | int fields=0; | 44 | int fields=0; |
@@ -61,7 +47,7 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count) | |||
61 | fields = sscanf(buf, "%x %x %x %x %x %x %lux", | 47 | fields = sscanf(buf, "%x %x %x %x %x %x %lux", |
62 | &vendor, &device, &subvendor, &subdevice, | 48 | &vendor, &device, &subvendor, &subdevice, |
63 | &class, &class_mask, &driver_data); | 49 | &class, &class_mask, &driver_data); |
64 | if (fields < 0) | 50 | if (fields < 2) |
65 | return -EINVAL; | 51 | return -EINVAL; |
66 | 52 | ||
67 | dynid = kzalloc(sizeof(*dynid), GFP_KERNEL); | 53 | dynid = kzalloc(sizeof(*dynid), GFP_KERNEL); |
@@ -569,7 +555,6 @@ struct bus_type pci_bus_type = { | |||
569 | 555 | ||
570 | static int __init pci_driver_init(void) | 556 | static int __init pci_driver_init(void) |
571 | { | 557 | { |
572 | pci_bus_type.multithread_probe = pci_multithread_probe; | ||
573 | return bus_register(&pci_bus_type); | 558 | return bus_register(&pci_bus_type); |
574 | } | 559 | } |
575 | 560 | ||
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index cd913a2a416f..284e83a527f9 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c | |||
@@ -620,7 +620,8 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev) | |||
620 | goto err_bin_file; | 620 | goto err_bin_file; |
621 | 621 | ||
622 | /* If the device has a ROM, try to expose it in sysfs. */ | 622 | /* If the device has a ROM, try to expose it in sysfs. */ |
623 | if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) { | 623 | if (pci_resource_len(pdev, PCI_ROM_RESOURCE) || |
624 | (pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW)) { | ||
624 | rom_attr = kzalloc(sizeof(*rom_attr), GFP_ATOMIC); | 625 | rom_attr = kzalloc(sizeof(*rom_attr), GFP_ATOMIC); |
625 | if (rom_attr) { | 626 | if (rom_attr) { |
626 | pdev->rom_attr = rom_attr; | 627 | pdev->rom_attr = rom_attr; |
@@ -635,7 +636,7 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev) | |||
635 | goto err_rom; | 636 | goto err_rom; |
636 | } else { | 637 | } else { |
637 | retval = -ENOMEM; | 638 | retval = -ENOMEM; |
638 | goto err_bin_file; | 639 | goto err_resource_files; |
639 | } | 640 | } |
640 | } | 641 | } |
641 | /* add platform-specific attributes */ | 642 | /* add platform-specific attributes */ |
@@ -645,6 +646,8 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev) | |||
645 | 646 | ||
646 | err_rom: | 647 | err_rom: |
647 | kfree(rom_attr); | 648 | kfree(rom_attr); |
649 | err_resource_files: | ||
650 | pci_remove_resource_files(pdev); | ||
648 | err_bin_file: | 651 | err_bin_file: |
649 | if (pdev->cfg_size < 4096) | 652 | if (pdev->cfg_size < 4096) |
650 | sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr); | 653 | sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr); |
@@ -695,4 +698,4 @@ static int __init pci_sysfs_init(void) | |||
695 | return 0; | 698 | return 0; |
696 | } | 699 | } |
697 | 700 | ||
698 | __initcall(pci_sysfs_init); | 701 | late_initcall(pci_sysfs_init); |
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 2a458279327a..fd47ac0c4730 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
@@ -35,8 +35,7 @@ unsigned long pci_cardbus_mem_size = DEFAULT_CARDBUS_MEM_SIZE; | |||
35 | * Given a PCI bus, returns the highest PCI bus number present in the set | 35 | * Given a PCI bus, returns the highest PCI bus number present in the set |
36 | * including the given PCI bus and its list of child PCI buses. | 36 | * including the given PCI bus and its list of child PCI buses. |
37 | */ | 37 | */ |
38 | unsigned char __devinit | 38 | unsigned char pci_bus_max_busnr(struct pci_bus* bus) |
39 | pci_bus_max_busnr(struct pci_bus* bus) | ||
40 | { | 39 | { |
41 | struct list_head *tmp; | 40 | struct list_head *tmp; |
42 | unsigned char max, n; | 41 | unsigned char max, n; |
@@ -892,6 +891,34 @@ pci_disable_device(struct pci_dev *dev) | |||
892 | } | 891 | } |
893 | 892 | ||
894 | /** | 893 | /** |
894 | * pcibios_set_pcie_reset_state - set reset state for device dev | ||
895 | * @dev: the PCI-E device reset | ||
896 | * @state: Reset state to enter into | ||
897 | * | ||
898 | * | ||
899 | * Sets the PCI-E reset state for the device. This is the default | ||
900 | * implementation. Architecture implementations can override this. | ||
901 | */ | ||
902 | int __attribute__ ((weak)) pcibios_set_pcie_reset_state(struct pci_dev *dev, | ||
903 | enum pcie_reset_state state) | ||
904 | { | ||
905 | return -EINVAL; | ||
906 | } | ||
907 | |||
908 | /** | ||
909 | * pci_set_pcie_reset_state - set reset state for device dev | ||
910 | * @dev: the PCI-E device reset | ||
911 | * @state: Reset state to enter into | ||
912 | * | ||
913 | * | ||
914 | * Sets the PCI reset state for the device. | ||
915 | */ | ||
916 | int pci_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state) | ||
917 | { | ||
918 | return pcibios_set_pcie_reset_state(dev, state); | ||
919 | } | ||
920 | |||
921 | /** | ||
895 | * pci_enable_wake - enable PCI device as wakeup event source | 922 | * pci_enable_wake - enable PCI device as wakeup event source |
896 | * @dev: PCI device affected | 923 | * @dev: PCI device affected |
897 | * @state: PCI state from which device will issue wakeup events | 924 | * @state: PCI state from which device will issue wakeup events |
@@ -1295,7 +1322,7 @@ pci_intx(struct pci_dev *pdev, int enable) | |||
1295 | 1322 | ||
1296 | /** | 1323 | /** |
1297 | * pci_msi_off - disables any msi or msix capabilities | 1324 | * pci_msi_off - disables any msi or msix capabilities |
1298 | * @pdev: the PCI device to operate on | 1325 | * @dev: the PCI device to operate on |
1299 | * | 1326 | * |
1300 | * If you want to use msi see pci_enable_msi and friends. | 1327 | * If you want to use msi see pci_enable_msi and friends. |
1301 | * This is a lower level primitive that allows us to disable | 1328 | * This is a lower level primitive that allows us to disable |
@@ -1427,4 +1454,5 @@ EXPORT_SYMBOL(pci_set_power_state); | |||
1427 | EXPORT_SYMBOL(pci_save_state); | 1454 | EXPORT_SYMBOL(pci_save_state); |
1428 | EXPORT_SYMBOL(pci_restore_state); | 1455 | EXPORT_SYMBOL(pci_restore_state); |
1429 | EXPORT_SYMBOL(pci_enable_wake); | 1456 | EXPORT_SYMBOL(pci_enable_wake); |
1457 | EXPORT_SYMBOL_GPL(pci_set_pcie_reset_state); | ||
1430 | 1458 | ||
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 62ea04c8af64..3fec13d3add7 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h | |||
@@ -47,8 +47,10 @@ extern unsigned int pci_pm_d3_delay; | |||
47 | 47 | ||
48 | #ifdef CONFIG_PCI_MSI | 48 | #ifdef CONFIG_PCI_MSI |
49 | void pci_no_msi(void); | 49 | void pci_no_msi(void); |
50 | extern void pci_msi_init_pci_dev(struct pci_dev *dev); | ||
50 | #else | 51 | #else |
51 | static inline void pci_no_msi(void) { } | 52 | static inline void pci_no_msi(void) { } |
53 | static inline void pci_msi_init_pci_dev(struct pci_dev *dev) { } | ||
52 | #endif | 54 | #endif |
53 | 55 | ||
54 | #if defined(CONFIG_PCI_MSI) && defined(CONFIG_PM) | 56 | #if defined(CONFIG_PCI_MSI) && defined(CONFIG_PM) |
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 2fe1d690eb13..e48fcf089621 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c | |||
@@ -364,7 +364,7 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child) | |||
364 | } | 364 | } |
365 | } | 365 | } |
366 | 366 | ||
367 | static struct pci_bus * __devinit pci_alloc_bus(void) | 367 | static struct pci_bus * pci_alloc_bus(void) |
368 | { | 368 | { |
369 | struct pci_bus *b; | 369 | struct pci_bus *b; |
370 | 370 | ||
@@ -432,7 +432,7 @@ error_register: | |||
432 | return NULL; | 432 | return NULL; |
433 | } | 433 | } |
434 | 434 | ||
435 | struct pci_bus * __devinit pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr) | 435 | struct pci_bus *pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr) |
436 | { | 436 | { |
437 | struct pci_bus *child; | 437 | struct pci_bus *child; |
438 | 438 | ||
@@ -461,7 +461,7 @@ static void pci_enable_crs(struct pci_dev *dev) | |||
461 | pci_write_config_word(dev, rpcap + PCI_EXP_RTCTL, rpctl); | 461 | pci_write_config_word(dev, rpcap + PCI_EXP_RTCTL, rpctl); |
462 | } | 462 | } |
463 | 463 | ||
464 | static void __devinit pci_fixup_parent_subordinate_busnr(struct pci_bus *child, int max) | 464 | static void pci_fixup_parent_subordinate_busnr(struct pci_bus *child, int max) |
465 | { | 465 | { |
466 | struct pci_bus *parent = child->parent; | 466 | struct pci_bus *parent = child->parent; |
467 | 467 | ||
@@ -477,7 +477,7 @@ static void __devinit pci_fixup_parent_subordinate_busnr(struct pci_bus *child, | |||
477 | } | 477 | } |
478 | } | 478 | } |
479 | 479 | ||
480 | unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus); | 480 | unsigned int pci_scan_child_bus(struct pci_bus *bus); |
481 | 481 | ||
482 | /* | 482 | /* |
483 | * If it's a bridge, configure it and scan the bus behind it. | 483 | * If it's a bridge, configure it and scan the bus behind it. |
@@ -489,7 +489,7 @@ unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus); | |||
489 | * them, we proceed to assigning numbers to the remaining buses in | 489 | * them, we proceed to assigning numbers to the remaining buses in |
490 | * order to avoid overlaps between old and new bus numbers. | 490 | * order to avoid overlaps between old and new bus numbers. |
491 | */ | 491 | */ |
492 | int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass) | 492 | int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass) |
493 | { | 493 | { |
494 | struct pci_bus *child; | 494 | struct pci_bus *child; |
495 | int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS); | 495 | int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS); |
@@ -846,6 +846,23 @@ static void pci_release_bus_bridge_dev(struct device *dev) | |||
846 | kfree(dev); | 846 | kfree(dev); |
847 | } | 847 | } |
848 | 848 | ||
849 | struct pci_dev *alloc_pci_dev(void) | ||
850 | { | ||
851 | struct pci_dev *dev; | ||
852 | |||
853 | dev = kzalloc(sizeof(struct pci_dev), GFP_KERNEL); | ||
854 | if (!dev) | ||
855 | return NULL; | ||
856 | |||
857 | INIT_LIST_HEAD(&dev->global_list); | ||
858 | INIT_LIST_HEAD(&dev->bus_list); | ||
859 | |||
860 | pci_msi_init_pci_dev(dev); | ||
861 | |||
862 | return dev; | ||
863 | } | ||
864 | EXPORT_SYMBOL(alloc_pci_dev); | ||
865 | |||
849 | /* | 866 | /* |
850 | * Read the config data for a PCI device, sanity-check it | 867 | * Read the config data for a PCI device, sanity-check it |
851 | * and fill in the dev structure... | 868 | * and fill in the dev structure... |
@@ -885,7 +902,7 @@ pci_scan_device(struct pci_bus *bus, int devfn) | |||
885 | if (pci_bus_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &hdr_type)) | 902 | if (pci_bus_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &hdr_type)) |
886 | return NULL; | 903 | return NULL; |
887 | 904 | ||
888 | dev = kzalloc(sizeof(struct pci_dev), GFP_KERNEL); | 905 | dev = alloc_pci_dev(); |
889 | if (!dev) | 906 | if (!dev) |
890 | return NULL; | 907 | return NULL; |
891 | 908 | ||
@@ -912,7 +929,7 @@ pci_scan_device(struct pci_bus *bus, int devfn) | |||
912 | return dev; | 929 | return dev; |
913 | } | 930 | } |
914 | 931 | ||
915 | void __devinit pci_device_add(struct pci_dev *dev, struct pci_bus *bus) | 932 | void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) |
916 | { | 933 | { |
917 | device_initialize(&dev->dev); | 934 | device_initialize(&dev->dev); |
918 | dev->dev.release = pci_release_dev; | 935 | dev->dev.release = pci_release_dev; |
@@ -935,8 +952,7 @@ void __devinit pci_device_add(struct pci_dev *dev, struct pci_bus *bus) | |||
935 | up_write(&pci_bus_sem); | 952 | up_write(&pci_bus_sem); |
936 | } | 953 | } |
937 | 954 | ||
938 | struct pci_dev * __devinit | 955 | struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn) |
939 | pci_scan_single_device(struct pci_bus *bus, int devfn) | ||
940 | { | 956 | { |
941 | struct pci_dev *dev; | 957 | struct pci_dev *dev; |
942 | 958 | ||
@@ -958,7 +974,7 @@ pci_scan_single_device(struct pci_bus *bus, int devfn) | |||
958 | * discovered devices to the @bus->devices list. New devices | 974 | * discovered devices to the @bus->devices list. New devices |
959 | * will have an empty dev->global_list head. | 975 | * will have an empty dev->global_list head. |
960 | */ | 976 | */ |
961 | int __devinit pci_scan_slot(struct pci_bus *bus, int devfn) | 977 | int pci_scan_slot(struct pci_bus *bus, int devfn) |
962 | { | 978 | { |
963 | int func, nr = 0; | 979 | int func, nr = 0; |
964 | int scan_all_fns; | 980 | int scan_all_fns; |
@@ -991,7 +1007,7 @@ int __devinit pci_scan_slot(struct pci_bus *bus, int devfn) | |||
991 | return nr; | 1007 | return nr; |
992 | } | 1008 | } |
993 | 1009 | ||
994 | unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus) | 1010 | unsigned int pci_scan_child_bus(struct pci_bus *bus) |
995 | { | 1011 | { |
996 | unsigned int devfn, pass, max = bus->secondary; | 1012 | unsigned int devfn, pass, max = bus->secondary; |
997 | struct pci_dev *dev; | 1013 | struct pci_dev *dev; |
@@ -1041,7 +1057,7 @@ unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus) | |||
1041 | return max; | 1057 | return max; |
1042 | } | 1058 | } |
1043 | 1059 | ||
1044 | struct pci_bus * __devinit pci_create_bus(struct device *parent, | 1060 | struct pci_bus * pci_create_bus(struct device *parent, |
1045 | int bus, struct pci_ops *ops, void *sysdata) | 1061 | int bus, struct pci_ops *ops, void *sysdata) |
1046 | { | 1062 | { |
1047 | int error; | 1063 | int error; |
@@ -1119,7 +1135,7 @@ err_out: | |||
1119 | } | 1135 | } |
1120 | EXPORT_SYMBOL_GPL(pci_create_bus); | 1136 | EXPORT_SYMBOL_GPL(pci_create_bus); |
1121 | 1137 | ||
1122 | struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent, | 1138 | struct pci_bus *pci_scan_bus_parented(struct device *parent, |
1123 | int bus, struct pci_ops *ops, void *sysdata) | 1139 | int bus, struct pci_ops *ops, void *sysdata) |
1124 | { | 1140 | { |
1125 | struct pci_bus *b; | 1141 | struct pci_bus *b; |
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 3411483240cd..147d86f8edbf 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c | |||
@@ -1648,6 +1648,8 @@ static void __devinit quirk_disable_msi(struct pci_dev *dev) | |||
1648 | } | 1648 | } |
1649 | } | 1649 | } |
1650 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_disable_msi); | 1650 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_disable_msi); |
1651 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS400_200, quirk_disable_msi); | ||
1652 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS480, quirk_disable_msi); | ||
1651 | 1653 | ||
1652 | /* Go through the list of Hypertransport capabilities and | 1654 | /* Go through the list of Hypertransport capabilities and |
1653 | * return 1 if a HT MSI capability is found and enabled */ | 1655 | * return 1 if a HT MSI capability is found and enabled */ |
diff --git a/drivers/pci/search.c b/drivers/pci/search.c index 2dd8681d6b31..b137a27472c7 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c | |||
@@ -15,8 +15,7 @@ | |||
15 | 15 | ||
16 | DECLARE_RWSEM(pci_bus_sem); | 16 | DECLARE_RWSEM(pci_bus_sem); |
17 | 17 | ||
18 | static struct pci_bus * | 18 | static struct pci_bus *pci_do_find_bus(struct pci_bus *bus, unsigned char busnr) |
19 | pci_do_find_bus(struct pci_bus* bus, unsigned char busnr) | ||
20 | { | 19 | { |
21 | struct pci_bus* child; | 20 | struct pci_bus* child; |
22 | struct list_head *tmp; | 21 | struct list_head *tmp; |
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 3554f3948814..5ec297d7a5b4 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c | |||
@@ -36,8 +36,7 @@ | |||
36 | 36 | ||
37 | #define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1)) | 37 | #define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1)) |
38 | 38 | ||
39 | static void __devinit | 39 | static void pbus_assign_resources_sorted(struct pci_bus *bus) |
40 | pbus_assign_resources_sorted(struct pci_bus *bus) | ||
41 | { | 40 | { |
42 | struct pci_dev *dev; | 41 | struct pci_dev *dev; |
43 | struct resource *res; | 42 | struct resource *res; |
@@ -220,8 +219,7 @@ pci_setup_bridge(struct pci_bus *bus) | |||
220 | /* Check whether the bridge supports optional I/O and | 219 | /* Check whether the bridge supports optional I/O and |
221 | prefetchable memory ranges. If not, the respective | 220 | prefetchable memory ranges. If not, the respective |
222 | base/limit registers must be read-only and read as 0. */ | 221 | base/limit registers must be read-only and read as 0. */ |
223 | static void __devinit | 222 | static void pci_bridge_check_ranges(struct pci_bus *bus) |
224 | pci_bridge_check_ranges(struct pci_bus *bus) | ||
225 | { | 223 | { |
226 | u16 io; | 224 | u16 io; |
227 | u32 pmem; | 225 | u32 pmem; |
@@ -259,8 +257,7 @@ pci_bridge_check_ranges(struct pci_bus *bus) | |||
259 | bus resource of a given type. Note: we intentionally skip | 257 | bus resource of a given type. Note: we intentionally skip |
260 | the bus resources which have already been assigned (that is, | 258 | the bus resources which have already been assigned (that is, |
261 | have non-NULL parent resource). */ | 259 | have non-NULL parent resource). */ |
262 | static struct resource * __devinit | 260 | static struct resource *find_free_bus_resource(struct pci_bus *bus, unsigned long type) |
263 | find_free_bus_resource(struct pci_bus *bus, unsigned long type) | ||
264 | { | 261 | { |
265 | int i; | 262 | int i; |
266 | struct resource *r; | 263 | struct resource *r; |
@@ -281,8 +278,7 @@ find_free_bus_resource(struct pci_bus *bus, unsigned long type) | |||
281 | since these windows have 4K granularity and the IO ranges | 278 | since these windows have 4K granularity and the IO ranges |
282 | of non-bridge PCI devices are limited to 256 bytes. | 279 | of non-bridge PCI devices are limited to 256 bytes. |
283 | We must be careful with the ISA aliasing though. */ | 280 | We must be careful with the ISA aliasing though. */ |
284 | static void __devinit | 281 | static void pbus_size_io(struct pci_bus *bus) |
285 | pbus_size_io(struct pci_bus *bus) | ||
286 | { | 282 | { |
287 | struct pci_dev *dev; | 283 | struct pci_dev *dev; |
288 | struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO); | 284 | struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO); |
@@ -326,8 +322,7 @@ pbus_size_io(struct pci_bus *bus) | |||
326 | 322 | ||
327 | /* Calculate the size of the bus and minimal alignment which | 323 | /* Calculate the size of the bus and minimal alignment which |
328 | guarantees that all child resources fit in this size. */ | 324 | guarantees that all child resources fit in this size. */ |
329 | static int __devinit | 325 | static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long type) |
330 | pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long type) | ||
331 | { | 326 | { |
332 | struct pci_dev *dev; | 327 | struct pci_dev *dev; |
333 | unsigned long min_align, align, size; | 328 | unsigned long min_align, align, size; |
@@ -447,8 +442,7 @@ pci_bus_size_cardbus(struct pci_bus *bus) | |||
447 | } | 442 | } |
448 | } | 443 | } |
449 | 444 | ||
450 | void __devinit | 445 | void pci_bus_size_bridges(struct pci_bus *bus) |
451 | pci_bus_size_bridges(struct pci_bus *bus) | ||
452 | { | 446 | { |
453 | struct pci_dev *dev; | 447 | struct pci_dev *dev; |
454 | unsigned long mask, prefmask; | 448 | unsigned long mask, prefmask; |
@@ -498,8 +492,7 @@ pci_bus_size_bridges(struct pci_bus *bus) | |||
498 | } | 492 | } |
499 | EXPORT_SYMBOL(pci_bus_size_bridges); | 493 | EXPORT_SYMBOL(pci_bus_size_bridges); |
500 | 494 | ||
501 | void __devinit | 495 | void pci_bus_assign_resources(struct pci_bus *bus) |
502 | pci_bus_assign_resources(struct pci_bus *bus) | ||
503 | { | 496 | { |
504 | struct pci_bus *b; | 497 | struct pci_bus *b; |
505 | struct pci_dev *dev; | 498 | struct pci_dev *dev; |
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index cb4ced3560e9..6dfd86167e39 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c | |||
@@ -101,8 +101,7 @@ pci_update_resource(struct pci_dev *dev, struct resource *res, int resno) | |||
101 | new & ~PCI_REGION_FLAG_MASK); | 101 | new & ~PCI_REGION_FLAG_MASK); |
102 | } | 102 | } |
103 | 103 | ||
104 | int __devinit | 104 | int pci_claim_resource(struct pci_dev *dev, int resource) |
105 | pci_claim_resource(struct pci_dev *dev, int resource) | ||
106 | { | 105 | { |
107 | struct resource *res = &dev->resource[resource]; | 106 | struct resource *res = &dev->resource[resource]; |
108 | struct resource *root = NULL; | 107 | struct resource *root = NULL; |
@@ -212,8 +211,7 @@ EXPORT_SYMBOL_GPL(pci_assign_resource_fixed); | |||
212 | #endif | 211 | #endif |
213 | 212 | ||
214 | /* Sort resources by alignment */ | 213 | /* Sort resources by alignment */ |
215 | void __devinit | 214 | void pdev_sort_resources(struct pci_dev *dev, struct resource_list *head) |
216 | pdev_sort_resources(struct pci_dev *dev, struct resource_list *head) | ||
217 | { | 215 | { |
218 | int i; | 216 | int i; |
219 | 217 | ||