diff options
-rw-r--r-- | drivers/pci/hotplug/pciehp.h | 11 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_core.c | 20 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_ctrl.c | 1 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_hpc.c | 4 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehprm.h | 52 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehprm_acpi.c | 838 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehprm_nonacpi.c | 107 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehprm_nonacpi.h | 56 |
8 files changed, 96 insertions, 993 deletions
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index e9480ddd5abf..e9c09566f851 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h | |||
@@ -49,6 +49,13 @@ extern int pciehp_debug; | |||
49 | #define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg) | 49 | #define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg) |
50 | #define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg) | 50 | #define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg) |
51 | 51 | ||
52 | struct hotplug_params { | ||
53 | u8 cache_line_size; | ||
54 | u8 latency_timer; | ||
55 | u8 enable_serr; | ||
56 | u8 enable_perr; | ||
57 | }; | ||
58 | |||
52 | struct pci_func { | 59 | struct pci_func { |
53 | struct pci_func *next; | 60 | struct pci_func *next; |
54 | u8 bus; | 61 | u8 bus; |
@@ -199,6 +206,10 @@ extern int pciehp_save_config (struct controller *ctrl, int busnumber, int num | |||
199 | extern int pciehp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot); | 206 | extern int pciehp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot); |
200 | extern int pciehp_configure_device (struct slot *ctrl); | 207 | extern int pciehp_configure_device (struct slot *ctrl); |
201 | extern int pciehp_unconfigure_device (struct pci_func* func); | 208 | extern int pciehp_unconfigure_device (struct pci_func* func); |
209 | extern int get_hp_hw_control_from_firmware(struct pci_dev *dev); | ||
210 | extern void get_hp_params_from_firmware(struct pci_dev *dev, | ||
211 | struct hotplug_params *hpp); | ||
212 | |||
202 | 213 | ||
203 | 214 | ||
204 | /* Global variables */ | 215 | /* Global variables */ |
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index 190664e5adf4..e20cf8e42bd9 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c | |||
@@ -39,7 +39,6 @@ | |||
39 | #include <linux/init.h> | 39 | #include <linux/init.h> |
40 | #include <asm/uaccess.h> | 40 | #include <asm/uaccess.h> |
41 | #include "pciehp.h" | 41 | #include "pciehp.h" |
42 | #include "pciehprm.h" | ||
43 | #include <linux/interrupt.h> | 42 | #include <linux/interrupt.h> |
44 | 43 | ||
45 | /* Global variables */ | 44 | /* Global variables */ |
@@ -381,6 +380,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ | |||
381 | dbg("%s: DRV_thread pid = %d\n", __FUNCTION__, current->pid); | 380 | dbg("%s: DRV_thread pid = %d\n", __FUNCTION__, current->pid); |
382 | 381 | ||
383 | pdev = dev->port; | 382 | pdev = dev->port; |
383 | ctrl->pci_dev = pdev; | ||
384 | 384 | ||
385 | rc = pcie_init(ctrl, dev, | 385 | rc = pcie_init(ctrl, dev, |
386 | (php_intr_callback_t) pciehp_handle_attention_button, | 386 | (php_intr_callback_t) pciehp_handle_attention_button, |
@@ -392,8 +392,6 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ | |||
392 | goto err_out_free_ctrl; | 392 | goto err_out_free_ctrl; |
393 | } | 393 | } |
394 | 394 | ||
395 | ctrl->pci_dev = pdev; | ||
396 | |||
397 | pci_set_drvdata(pdev, ctrl); | 395 | pci_set_drvdata(pdev, ctrl); |
398 | 396 | ||
399 | ctrl->pci_bus = kmalloc(sizeof(*ctrl->pci_bus), GFP_KERNEL); | 397 | ctrl->pci_bus = kmalloc(sizeof(*ctrl->pci_bus), GFP_KERNEL); |
@@ -609,18 +607,14 @@ static int __init pcied_init(void) | |||
609 | if (retval) | 607 | if (retval) |
610 | goto error_hpc_init; | 608 | goto error_hpc_init; |
611 | 609 | ||
612 | retval = pciehprm_init(PCI); | 610 | retval = pcie_port_service_register(&hpdriver_portdrv); |
613 | if (!retval) { | 611 | dbg("pcie_port_service_register = %d\n", retval); |
614 | retval = pcie_port_service_register(&hpdriver_portdrv); | 612 | info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); |
615 | dbg("pcie_port_service_register = %d\n", retval); | 613 | if (retval) |
616 | info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); | 614 | dbg("%s: Failure to register service\n", __FUNCTION__); |
617 | if (retval) | ||
618 | dbg("%s: Failure to register service\n", __FUNCTION__); | ||
619 | } | ||
620 | 615 | ||
621 | error_hpc_init: | 616 | error_hpc_init: |
622 | if (retval) { | 617 | if (retval) { |
623 | pciehprm_cleanup(); | ||
624 | pciehp_event_stop_thread(); | 618 | pciehp_event_stop_thread(); |
625 | }; | 619 | }; |
626 | 620 | ||
@@ -632,8 +626,6 @@ static void __exit pcied_cleanup(void) | |||
632 | dbg("unload_pciehpd()\n"); | 626 | dbg("unload_pciehpd()\n"); |
633 | unload_pciehpd(); | 627 | unload_pciehpd(); |
634 | 628 | ||
635 | pciehprm_cleanup(); | ||
636 | |||
637 | dbg("pcie_port_service_unregister\n"); | 629 | dbg("pcie_port_service_unregister\n"); |
638 | pcie_port_service_unregister(&hpdriver_portdrv); | 630 | pcie_port_service_unregister(&hpdriver_portdrv); |
639 | 631 | ||
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index 412783e0ef40..d07d4194bc29 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c | |||
@@ -40,7 +40,6 @@ | |||
40 | #include <linux/pci.h> | 40 | #include <linux/pci.h> |
41 | #include "../pci.h" | 41 | #include "../pci.h" |
42 | #include "pciehp.h" | 42 | #include "pciehp.h" |
43 | #include "pciehprm.h" | ||
44 | 43 | ||
45 | static void interrupt_event_handler(struct controller *ctrl); | 44 | static void interrupt_event_handler(struct controller *ctrl); |
46 | 45 | ||
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 7a0e27f0e063..ef79ca1f38da 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c | |||
@@ -1470,6 +1470,10 @@ int pcie_init(struct controller * ctrl, | |||
1470 | } | 1470 | } |
1471 | dbg("%s: SLOT_STATUS offset %x writes slot_status %x\n", __FUNCTION__, SLOT_STATUS(ctrl->cap_base), temp_word); | 1471 | dbg("%s: SLOT_STATUS offset %x writes slot_status %x\n", __FUNCTION__, SLOT_STATUS(ctrl->cap_base), temp_word); |
1472 | 1472 | ||
1473 | rc = get_hp_hw_control_from_firmware(ctrl->pci_dev); | ||
1474 | if (rc) | ||
1475 | goto abort_free_ctlr; | ||
1476 | |||
1473 | /* Add this HPC instance into the HPC list */ | 1477 | /* Add this HPC instance into the HPC list */ |
1474 | spin_lock(&list_lock); | 1478 | spin_lock(&list_lock); |
1475 | if (php_ctlr_list_head == 0) { | 1479 | if (php_ctlr_list_head == 0) { |
diff --git a/drivers/pci/hotplug/pciehprm.h b/drivers/pci/hotplug/pciehprm.h deleted file mode 100644 index 05f20fbc5f50..000000000000 --- a/drivers/pci/hotplug/pciehprm.h +++ /dev/null | |||
@@ -1,52 +0,0 @@ | |||
1 | /* | ||
2 | * PCIEHPRM : PCIEHP Resource Manager for ACPI/non-ACPI platform | ||
3 | * | ||
4 | * Copyright (C) 1995,2001 Compaq Computer Corporation | ||
5 | * Copyright (C) 2001,2003 Greg Kroah-Hartman (greg@kroah.com) | ||
6 | * Copyright (C) 2001 IBM Corp. | ||
7 | * Copyright (C) 2003-2004 Intel Corporation | ||
8 | * | ||
9 | * All rights reserved. | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; either version 2 of the License, or (at | ||
14 | * your option) any later version. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, but | ||
17 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
19 | * NON INFRINGEMENT. See the GNU General Public License for more | ||
20 | * details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | * | ||
26 | * Send feedback to <greg@kroah.com>, <kristen.c.accardi@intel.com> | ||
27 | * | ||
28 | */ | ||
29 | |||
30 | #ifndef _PCIEHPRM_H_ | ||
31 | #define _PCIEHPRM_H_ | ||
32 | |||
33 | #ifdef CONFIG_HOTPLUG_PCI_PCIE_PHPRM_NONACPI | ||
34 | #include "pciehprm_nonacpi.h" | ||
35 | #endif | ||
36 | |||
37 | int pciehprm_init(enum php_ctlr_type ct); | ||
38 | void pciehprm_cleanup(void); | ||
39 | int pciehprm_print_pirt(void); | ||
40 | int pciehprm_find_available_resources(struct controller *ctrl); | ||
41 | int pciehprm_set_hpp(struct controller *ctrl, struct pci_func *func, u8 card_type); | ||
42 | void pciehprm_enable_card(struct controller *ctrl, struct pci_func *func, u8 card_type); | ||
43 | |||
44 | #ifdef DEBUG | ||
45 | #define RES_CHECK(this, bits) \ | ||
46 | { if (((this) & (bits - 1))) \ | ||
47 | printk("%s:%d ERR: potential res loss!\n", __FUNCTION__, __LINE__); } | ||
48 | #else | ||
49 | #define RES_CHECK(this, bits) | ||
50 | #endif | ||
51 | |||
52 | #endif /* _PCIEHPRM_H_ */ | ||
diff --git a/drivers/pci/hotplug/pciehprm_acpi.c b/drivers/pci/hotplug/pciehprm_acpi.c index 078550ba2708..c823cfa42eec 100644 --- a/drivers/pci/hotplug/pciehprm_acpi.c +++ b/drivers/pci/hotplug/pciehprm_acpi.c | |||
@@ -39,70 +39,11 @@ | |||
39 | #include <acpi/acpi_bus.h> | 39 | #include <acpi/acpi_bus.h> |
40 | #include <acpi/actypes.h> | 40 | #include <acpi/actypes.h> |
41 | #include "pciehp.h" | 41 | #include "pciehp.h" |
42 | #include "pciehprm.h" | ||
43 | |||
44 | #define PCI_MAX_BUS 0x100 | ||
45 | #define ACPI_STA_DEVICE_PRESENT 0x01 | ||
46 | 42 | ||
47 | #define METHOD_NAME__SUN "_SUN" | 43 | #define METHOD_NAME__SUN "_SUN" |
48 | #define METHOD_NAME__HPP "_HPP" | 44 | #define METHOD_NAME__HPP "_HPP" |
49 | #define METHOD_NAME_OSHP "OSHP" | 45 | #define METHOD_NAME_OSHP "OSHP" |
50 | 46 | ||
51 | /* Status code for running acpi method to gain native control */ | ||
52 | #define NC_NOT_RUN 0 | ||
53 | #define OSC_NOT_EXIST 1 | ||
54 | #define OSC_RUN_FAILED 2 | ||
55 | #define OSHP_NOT_EXIST 3 | ||
56 | #define OSHP_RUN_FAILED 4 | ||
57 | #define NC_RUN_SUCCESS 5 | ||
58 | |||
59 | #define PHP_RES_BUS 0xA0 | ||
60 | #define PHP_RES_IO 0xA1 | ||
61 | #define PHP_RES_MEM 0xA2 | ||
62 | #define PHP_RES_PMEM 0xA3 | ||
63 | |||
64 | #define BRIDGE_TYPE_P2P 0x00 | ||
65 | #define BRIDGE_TYPE_HOST 0x01 | ||
66 | |||
67 | /* this should go to drivers/acpi/include/ */ | ||
68 | struct acpi__hpp { | ||
69 | u8 cache_line_size; | ||
70 | u8 latency_timer; | ||
71 | u8 enable_serr; | ||
72 | u8 enable_perr; | ||
73 | }; | ||
74 | |||
75 | struct acpi_php_slot { | ||
76 | struct acpi_php_slot *next; | ||
77 | struct acpi_bridge *bridge; | ||
78 | acpi_handle handle; | ||
79 | int seg; | ||
80 | int bus; | ||
81 | int dev; | ||
82 | int fun; | ||
83 | u32 sun; | ||
84 | void *slot_ops; /* _STA, _EJx, etc */ | ||
85 | struct slot *slot; | ||
86 | }; /* per func */ | ||
87 | |||
88 | struct acpi_bridge { | ||
89 | struct acpi_bridge *parent; | ||
90 | struct acpi_bridge *next; | ||
91 | struct acpi_bridge *child; | ||
92 | acpi_handle handle; | ||
93 | int seg; | ||
94 | int pbus; /* pdev->bus->number */ | ||
95 | int pdevice; /* PCI_SLOT(pdev->devfn) */ | ||
96 | int pfunction; /* PCI_DEVFN(pdev->devfn) */ | ||
97 | int bus; /* pdev->subordinate->number */ | ||
98 | struct acpi__hpp *_hpp; | ||
99 | struct acpi_php_slot *slots; | ||
100 | int scanned; | ||
101 | int type; | ||
102 | }; | ||
103 | |||
104 | static struct acpi_bridge *acpi_bridges_head; | ||
105 | |||
106 | static u8 * acpi_path_name( acpi_handle handle) | 47 | static u8 * acpi_path_name( acpi_handle handle) |
107 | { | 48 | { |
108 | acpi_status status; | 49 | acpi_status status; |
@@ -118,85 +59,43 @@ static u8 * acpi_path_name( acpi_handle handle) | |||
118 | return path_name; | 59 | return path_name; |
119 | } | 60 | } |
120 | 61 | ||
121 | static void acpi_get__hpp ( struct acpi_bridge *ab); | 62 | static acpi_status |
122 | static int acpi_run_oshp ( struct acpi_bridge *ab); | 63 | acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp) |
123 | static int osc_run_status = NC_NOT_RUN; | ||
124 | static int oshp_run_status = NC_NOT_RUN; | ||
125 | |||
126 | static int acpi_add_slot_to_php_slots( | ||
127 | struct acpi_bridge *ab, | ||
128 | int bus_num, | ||
129 | acpi_handle handle, | ||
130 | u32 adr, | ||
131 | u32 sun | ||
132 | ) | ||
133 | { | ||
134 | struct acpi_php_slot *aps; | ||
135 | static long samesun = -1; | ||
136 | |||
137 | aps = (struct acpi_php_slot *) kmalloc (sizeof(struct acpi_php_slot), GFP_KERNEL); | ||
138 | if (!aps) { | ||
139 | err ("acpi_pciehprm: alloc for aps fail\n"); | ||
140 | return -1; | ||
141 | } | ||
142 | memset(aps, 0, sizeof(struct acpi_php_slot)); | ||
143 | |||
144 | aps->handle = handle; | ||
145 | aps->bus = bus_num; | ||
146 | aps->dev = (adr >> 16) & 0xffff; | ||
147 | aps->fun = adr & 0xffff; | ||
148 | aps->sun = sun; | ||
149 | |||
150 | aps->next = ab->slots; /* cling to the bridge */ | ||
151 | aps->bridge = ab; | ||
152 | ab->slots = aps; | ||
153 | |||
154 | ab->scanned += 1; | ||
155 | if (!ab->_hpp) | ||
156 | acpi_get__hpp(ab); | ||
157 | |||
158 | if (osc_run_status == OSC_NOT_EXIST) | ||
159 | oshp_run_status = acpi_run_oshp(ab); | ||
160 | |||
161 | if (sun != samesun) { | ||
162 | info("acpi_pciehprm: Slot sun(%x) at s:b:d:f=0x%02x:%02x:%02x:%02x\n", | ||
163 | aps->sun, ab->seg, aps->bus, aps->dev, aps->fun); | ||
164 | samesun = sun; | ||
165 | } | ||
166 | return 0; | ||
167 | } | ||
168 | |||
169 | static void acpi_get__hpp ( struct acpi_bridge *ab) | ||
170 | { | 64 | { |
171 | acpi_status status; | 65 | acpi_status status; |
172 | u8 nui[4]; | 66 | u8 nui[4]; |
173 | struct acpi_buffer ret_buf = { 0, NULL}; | 67 | struct acpi_buffer ret_buf = { 0, NULL}; |
174 | union acpi_object *ext_obj, *package; | 68 | union acpi_object *ext_obj, *package; |
175 | u8 *path_name = acpi_path_name(ab->handle); | 69 | u8 *path_name = acpi_path_name(handle); |
176 | int i, len = 0; | 70 | int i, len = 0; |
177 | 71 | ||
178 | /* get _hpp */ | 72 | /* get _hpp */ |
179 | status = acpi_evaluate_object(ab->handle, METHOD_NAME__HPP, NULL, &ret_buf); | 73 | status = acpi_evaluate_object(handle, METHOD_NAME__HPP, NULL, &ret_buf); |
180 | switch (status) { | 74 | switch (status) { |
181 | case AE_BUFFER_OVERFLOW: | 75 | case AE_BUFFER_OVERFLOW: |
182 | ret_buf.pointer = kmalloc (ret_buf.length, GFP_KERNEL); | 76 | ret_buf.pointer = kmalloc (ret_buf.length, GFP_KERNEL); |
183 | if (!ret_buf.pointer) { | 77 | if (!ret_buf.pointer) { |
184 | err ("acpi_pciehprm:%s alloc for _HPP fail\n", path_name); | 78 | err ("%s:%s alloc for _HPP fail\n", __FUNCTION__, |
185 | return; | 79 | path_name); |
80 | return AE_NO_MEMORY; | ||
186 | } | 81 | } |
187 | status = acpi_evaluate_object(ab->handle, METHOD_NAME__HPP, NULL, &ret_buf); | 82 | status = acpi_evaluate_object(handle, METHOD_NAME__HPP, |
83 | NULL, &ret_buf); | ||
188 | if (ACPI_SUCCESS(status)) | 84 | if (ACPI_SUCCESS(status)) |
189 | break; | 85 | break; |
190 | default: | 86 | default: |
191 | if (ACPI_FAILURE(status)) { | 87 | if (ACPI_FAILURE(status)) { |
192 | err("acpi_pciehprm:%s _HPP fail=0x%x\n", path_name, status); | 88 | dbg("%s:%s _HPP fail=0x%x\n", __FUNCTION__, |
193 | return; | 89 | path_name, status); |
90 | return status; | ||
194 | } | 91 | } |
195 | } | 92 | } |
196 | 93 | ||
197 | ext_obj = (union acpi_object *) ret_buf.pointer; | 94 | ext_obj = (union acpi_object *) ret_buf.pointer; |
198 | if (ext_obj->type != ACPI_TYPE_PACKAGE) { | 95 | if (ext_obj->type != ACPI_TYPE_PACKAGE) { |
199 | err ("acpi_pciehprm:%s _HPP obj not a package\n", path_name); | 96 | err ("%s:%s _HPP obj not a package\n", __FUNCTION__, |
97 | path_name); | ||
98 | status = AE_ERROR; | ||
200 | goto free_and_return; | 99 | goto free_and_return; |
201 | } | 100 | } |
202 | 101 | ||
@@ -209,689 +108,94 @@ static void acpi_get__hpp ( struct acpi_bridge *ab) | |||
209 | nui[i] = (u8)ext_obj->integer.value; | 108 | nui[i] = (u8)ext_obj->integer.value; |
210 | break; | 109 | break; |
211 | default: | 110 | default: |
212 | err ("acpi_pciehprm:%s _HPP obj type incorrect\n", path_name); | 111 | err ("%s:%s _HPP obj type incorrect\n", __FUNCTION__, |
112 | path_name); | ||
113 | status = AE_ERROR; | ||
213 | goto free_and_return; | 114 | goto free_and_return; |
214 | } | 115 | } |
215 | } | 116 | } |
216 | 117 | ||
217 | ab->_hpp = kmalloc (sizeof (struct acpi__hpp), GFP_KERNEL); | 118 | hpp->cache_line_size = nui[0]; |
218 | if (!ab->_hpp) { | 119 | hpp->latency_timer = nui[1]; |
219 | err ("acpi_pciehprm:%s alloc for _HPP failed\n", path_name); | 120 | hpp->enable_serr = nui[2]; |
220 | goto free_and_return; | 121 | hpp->enable_perr = nui[3]; |
221 | } | ||
222 | memset(ab->_hpp, 0, sizeof(struct acpi__hpp)); | ||
223 | 122 | ||
224 | ab->_hpp->cache_line_size = nui[0]; | 123 | dbg(" _HPP: cache_line_size=0x%x\n", hpp->cache_line_size); |
225 | ab->_hpp->latency_timer = nui[1]; | 124 | dbg(" _HPP: latency timer =0x%x\n", hpp->latency_timer); |
226 | ab->_hpp->enable_serr = nui[2]; | 125 | dbg(" _HPP: enable SERR =0x%x\n", hpp->enable_serr); |
227 | ab->_hpp->enable_perr = nui[3]; | 126 | dbg(" _HPP: enable PERR =0x%x\n", hpp->enable_perr); |
228 | |||
229 | dbg(" _HPP: cache_line_size=0x%x\n", ab->_hpp->cache_line_size); | ||
230 | dbg(" _HPP: latency timer =0x%x\n", ab->_hpp->latency_timer); | ||
231 | dbg(" _HPP: enable SERR =0x%x\n", ab->_hpp->enable_serr); | ||
232 | dbg(" _HPP: enable PERR =0x%x\n", ab->_hpp->enable_perr); | ||
233 | 127 | ||
234 | free_and_return: | 128 | free_and_return: |
235 | kfree(ret_buf.pointer); | 129 | kfree(ret_buf.pointer); |
130 | return status; | ||
236 | } | 131 | } |
237 | 132 | ||
238 | static int acpi_run_oshp ( struct acpi_bridge *ab) | 133 | static acpi_status acpi_run_oshp(acpi_handle handle) |
239 | { | 134 | { |
240 | acpi_status status; | 135 | acpi_status status; |
241 | u8 *path_name = acpi_path_name(ab->handle); | 136 | u8 *path_name = acpi_path_name(handle); |
242 | 137 | ||
243 | /* run OSHP */ | 138 | /* run OSHP */ |
244 | status = acpi_evaluate_object(ab->handle, METHOD_NAME_OSHP, NULL, NULL); | 139 | status = acpi_evaluate_object(handle, METHOD_NAME_OSHP, NULL, NULL); |
245 | if (ACPI_FAILURE(status)) { | 140 | if (ACPI_FAILURE(status)) { |
246 | err("acpi_pciehprm:%s OSHP fails=0x%x\n", path_name, status); | 141 | err("%s:%s OSHP fails=0x%x\n", __FUNCTION__, path_name, |
247 | oshp_run_status = (status == AE_NOT_FOUND) ? OSHP_NOT_EXIST : OSHP_RUN_FAILED; | 142 | status); |
248 | } else { | 143 | } else { |
249 | oshp_run_status = NC_RUN_SUCCESS; | 144 | dbg("%s:%s OSHP passes\n", __FUNCTION__, path_name); |
250 | dbg("acpi_pciehprm:%s OSHP passes =0x%x\n", path_name, status); | ||
251 | dbg("acpi_pciehprm:%s oshp_run_status =0x%x\n", path_name, oshp_run_status); | ||
252 | } | ||
253 | return oshp_run_status; | ||
254 | } | ||
255 | |||
256 | /* find acpi_bridge downword from ab. */ | ||
257 | static struct acpi_bridge * | ||
258 | find_acpi_bridge_by_bus( | ||
259 | struct acpi_bridge *ab, | ||
260 | int seg, | ||
261 | int bus /* pdev->subordinate->number */ | ||
262 | ) | ||
263 | { | ||
264 | struct acpi_bridge *lab = NULL; | ||
265 | |||
266 | if (!ab) | ||
267 | return NULL; | ||
268 | |||
269 | if ((ab->bus == bus) && (ab->seg == seg)) | ||
270 | return ab; | ||
271 | |||
272 | if (ab->child) | ||
273 | lab = find_acpi_bridge_by_bus(ab->child, seg, bus); | ||
274 | |||
275 | if (!lab) | ||
276 | if (ab->next) | ||
277 | lab = find_acpi_bridge_by_bus(ab->next, seg, bus); | ||
278 | |||
279 | return lab; | ||
280 | } | ||
281 | |||
282 | /* | ||
283 | * Build a device tree of ACPI PCI Bridges | ||
284 | */ | ||
285 | static void pciehprm_acpi_register_a_bridge ( | ||
286 | struct acpi_bridge **head, | ||
287 | struct acpi_bridge *pab, /* parent bridge to which child bridge is added */ | ||
288 | struct acpi_bridge *cab /* child bridge to add */ | ||
289 | ) | ||
290 | { | ||
291 | struct acpi_bridge *lpab; | ||
292 | struct acpi_bridge *lcab; | ||
293 | |||
294 | lpab = find_acpi_bridge_by_bus(*head, pab->seg, pab->bus); | ||
295 | if (!lpab) { | ||
296 | if (!(pab->type & BRIDGE_TYPE_HOST)) | ||
297 | warn("PCI parent bridge s:b(%x:%x) not in list.\n", pab->seg, pab->bus); | ||
298 | pab->next = *head; | ||
299 | *head = pab; | ||
300 | lpab = pab; | ||
301 | } | 145 | } |
302 | 146 | return status; | |
303 | if ((cab->type & BRIDGE_TYPE_HOST) && (pab == cab)) | ||
304 | return; | ||
305 | |||
306 | lcab = find_acpi_bridge_by_bus(*head, cab->seg, cab->bus); | ||
307 | if (lcab) { | ||
308 | if ((pab->bus != lcab->parent->bus) || (lcab->bus != cab->bus)) | ||
309 | err("PCI child bridge s:b(%x:%x) in list with diff parent.\n", cab->seg, cab->bus); | ||
310 | return; | ||
311 | } else | ||
312 | lcab = cab; | ||
313 | |||
314 | lcab->parent = lpab; | ||
315 | lcab->next = lpab->child; | ||
316 | lpab->child = lcab; | ||
317 | } | 147 | } |
318 | 148 | ||
319 | static acpi_status pciehprm_acpi_build_php_slots_callback( | 149 | int get_hp_hw_control_from_firmware(struct pci_dev *dev) |
320 | acpi_handle handle, | ||
321 | u32 Level, | ||
322 | void *context, | ||
323 | void **retval | ||
324 | ) | ||
325 | { | 150 | { |
326 | ulong bus_num; | 151 | acpi_status status; |
327 | ulong seg_num; | 152 | /* |
328 | ulong sun, adr; | 153 | * Per PCI firmware specification, we should run the ACPI _OSC |
329 | ulong padr = 0; | 154 | * method to get control of hotplug hardware before using it |
330 | acpi_handle phandle = NULL; | 155 | */ |
331 | struct acpi_bridge *pab = (struct acpi_bridge *)context; | 156 | /* Fixme: run _OSC for a specific host bridge, not all of them */ |
332 | struct acpi_bridge *lab; | 157 | status = pci_osc_control_set(OSC_PCI_EXPRESS_NATIVE_HP_CONTROL); |
333 | acpi_status status; | 158 | |
334 | u8 *path_name = acpi_path_name(handle); | 159 | /* Fixme: fail native hotplug if _OSC does not exist for root ports */ |
335 | 160 | if (status == AE_NOT_FOUND) { | |
336 | /* get _SUN */ | 161 | /* |
337 | status = acpi_evaluate_integer(handle, METHOD_NAME__SUN, NULL, &sun); | 162 | * Some older BIOS's don't support _OSC but support |
338 | switch(status) { | 163 | * OSHP to do the same thing |
339 | case AE_NOT_FOUND: | 164 | */ |
340 | return AE_OK; | 165 | acpi_handle handle = DEVICE_ACPI_HANDLE(&(dev->dev)); |
341 | default: | 166 | if (handle) |
342 | if (ACPI_FAILURE(status)) { | 167 | status = acpi_run_oshp(handle); |
343 | err("acpi_pciehprm:%s _SUN fail=0x%x\n", path_name, status); | ||
344 | return status; | ||
345 | } | ||
346 | } | ||
347 | |||
348 | /* get _ADR. _ADR must exist if _SUN exists */ | ||
349 | status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr); | ||
350 | if (ACPI_FAILURE(status)) { | ||
351 | err("acpi_pciehprm:%s _ADR fail=0x%x\n", path_name, status); | ||
352 | return status; | ||
353 | } | ||
354 | |||
355 | dbg("acpi_pciehprm:%s sun=0x%08x adr=0x%08x\n", path_name, (u32)sun, (u32)adr); | ||
356 | |||
357 | status = acpi_get_parent(handle, &phandle); | ||
358 | if (ACPI_FAILURE(status)) { | ||
359 | err("acpi_pciehprm:%s get_parent fail=0x%x\n", path_name, status); | ||
360 | return (status); | ||
361 | } | ||
362 | |||
363 | bus_num = pab->bus; | ||
364 | seg_num = pab->seg; | ||
365 | |||
366 | if (pab->bus == bus_num) { | ||
367 | lab = pab; | ||
368 | } else { | ||
369 | dbg("WARN: pab is not parent\n"); | ||
370 | lab = find_acpi_bridge_by_bus(pab, seg_num, bus_num); | ||
371 | if (!lab) { | ||
372 | dbg("acpi_pciehprm: alloc new P2P bridge(%x) for sun(%08x)\n", (u32)bus_num, (u32)sun); | ||
373 | lab = (struct acpi_bridge *)kmalloc(sizeof(struct acpi_bridge), GFP_KERNEL); | ||
374 | if (!lab) { | ||
375 | err("acpi_pciehprm: alloc for ab fail\n"); | ||
376 | return AE_NO_MEMORY; | ||
377 | } | ||
378 | memset(lab, 0, sizeof(struct acpi_bridge)); | ||
379 | |||
380 | lab->handle = phandle; | ||
381 | lab->pbus = pab->bus; | ||
382 | lab->pdevice = (int)(padr >> 16) & 0xffff; | ||
383 | lab->pfunction = (int)(padr & 0xffff); | ||
384 | lab->bus = (int)bus_num; | ||
385 | lab->scanned = 0; | ||
386 | lab->type = BRIDGE_TYPE_P2P; | ||
387 | |||
388 | pciehprm_acpi_register_a_bridge (&acpi_bridges_head, pab, lab); | ||
389 | } else | ||
390 | dbg("acpi_pciehprm: found P2P bridge(%x) for sun(%08x)\n", (u32)bus_num, (u32)sun); | ||
391 | } | 168 | } |
392 | |||
393 | acpi_add_slot_to_php_slots(lab, (int)bus_num, handle, (u32)adr, (u32)sun); | ||
394 | |||
395 | return (status); | ||
396 | } | ||
397 | |||
398 | static int pciehprm_acpi_build_php_slots( | ||
399 | struct acpi_bridge *ab, | ||
400 | u32 depth | ||
401 | ) | ||
402 | { | ||
403 | acpi_status status; | ||
404 | u8 *path_name = acpi_path_name(ab->handle); | ||
405 | |||
406 | /* Walk down this pci bridge to get _SUNs if any behind P2P */ | ||
407 | status = acpi_walk_namespace ( ACPI_TYPE_DEVICE, | ||
408 | ab->handle, | ||
409 | depth, | ||
410 | pciehprm_acpi_build_php_slots_callback, | ||
411 | ab, | ||
412 | NULL ); | ||
413 | if (ACPI_FAILURE(status)) { | 169 | if (ACPI_FAILURE(status)) { |
414 | dbg("acpi_pciehprm:%s walk for _SUN on pci bridge seg:bus(%x:%x) fail=0x%x\n", path_name, ab->seg, ab->bus, status); | 170 | err("Cannot get control of hotplug hardware\n"); |
415 | return -1; | 171 | return -1; |
416 | } | 172 | } |
417 | 173 | ||
174 | dbg("Sucess getting control of hotplug hardware\n"); | ||
418 | return 0; | 175 | return 0; |
419 | } | 176 | } |
420 | 177 | ||
421 | static void build_a_bridge( | 178 | void get_hp_params_from_firmware(struct pci_dev *dev, |
422 | struct acpi_bridge *pab, | 179 | struct hotplug_params *hpp) |
423 | struct acpi_bridge *ab | ||
424 | ) | ||
425 | { | ||
426 | u8 *path_name = acpi_path_name(ab->handle); | ||
427 | |||
428 | pciehprm_acpi_register_a_bridge (&acpi_bridges_head, pab, ab); | ||
429 | |||
430 | switch (ab->type) { | ||
431 | case BRIDGE_TYPE_HOST: | ||
432 | dbg("acpi_pciehprm: Registered PCI HOST Bridge(%02x) on s:b:d:f(%02x:%02x:%02x:%02x) [%s]\n", | ||
433 | ab->bus, ab->seg, ab->pbus, ab->pdevice, ab->pfunction, path_name); | ||
434 | break; | ||
435 | case BRIDGE_TYPE_P2P: | ||
436 | dbg("acpi_pciehprm: Registered PCI P2P Bridge(%02x-%02x) on s:b:d:f(%02x:%02x:%02x:%02x) [%s]\n", | ||
437 | ab->pbus, ab->bus, ab->seg, ab->pbus, ab->pdevice, ab->pfunction, path_name); | ||
438 | break; | ||
439 | }; | ||
440 | |||
441 | /* build any immediate PHP slots under this pci bridge */ | ||
442 | pciehprm_acpi_build_php_slots(ab, 1); | ||
443 | } | ||
444 | |||
445 | static struct acpi_bridge * add_p2p_bridge( | ||
446 | acpi_handle handle, | ||
447 | struct acpi_bridge *pab, /* parent */ | ||
448 | ulong adr | ||
449 | ) | ||
450 | { | ||
451 | struct acpi_bridge *ab; | ||
452 | struct pci_dev *pdev; | ||
453 | ulong devnum, funcnum; | ||
454 | u8 *path_name = acpi_path_name(handle); | ||
455 | |||
456 | ab = (struct acpi_bridge *) kmalloc (sizeof(struct acpi_bridge), GFP_KERNEL); | ||
457 | if (!ab) { | ||
458 | err("acpi_pciehprm: alloc for ab fail\n"); | ||
459 | return NULL; | ||
460 | } | ||
461 | memset(ab, 0, sizeof(struct acpi_bridge)); | ||
462 | |||
463 | devnum = (adr >> 16) & 0xffff; | ||
464 | funcnum = adr & 0xffff; | ||
465 | |||
466 | pdev = pci_find_slot(pab->bus, PCI_DEVFN(devnum, funcnum)); | ||
467 | if (!pdev || !pdev->subordinate) { | ||
468 | err("acpi_pciehprm:%s is not a P2P Bridge\n", path_name); | ||
469 | kfree(ab); | ||
470 | return NULL; | ||
471 | } | ||
472 | |||
473 | ab->handle = handle; | ||
474 | ab->seg = pab->seg; | ||
475 | ab->pbus = pab->bus; /* or pdev->bus->number */ | ||
476 | ab->pdevice = devnum; /* or PCI_SLOT(pdev->devfn) */ | ||
477 | ab->pfunction = funcnum; /* or PCI_FUNC(pdev->devfn) */ | ||
478 | ab->bus = pdev->subordinate->number; | ||
479 | ab->scanned = 0; | ||
480 | ab->type = BRIDGE_TYPE_P2P; | ||
481 | |||
482 | dbg("acpi_pciehprm: P2P(%x-%x) on pci=b:d:f(%x:%x:%x) acpi=b:d:f(%x:%x:%x) [%s]\n", | ||
483 | pab->bus, ab->bus, pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), | ||
484 | pab->bus, (u32)devnum, (u32)funcnum, path_name); | ||
485 | |||
486 | build_a_bridge(pab, ab); | ||
487 | |||
488 | return ab; | ||
489 | } | ||
490 | |||
491 | static acpi_status scan_p2p_bridge( | ||
492 | acpi_handle handle, | ||
493 | u32 Level, | ||
494 | void *context, | ||
495 | void **retval | ||
496 | ) | ||
497 | { | ||
498 | struct acpi_bridge *pab = (struct acpi_bridge *)context; | ||
499 | struct acpi_bridge *ab; | ||
500 | acpi_status status; | ||
501 | ulong adr = 0; | ||
502 | u8 *path_name = acpi_path_name(handle); | ||
503 | ulong devnum, funcnum; | ||
504 | struct pci_dev *pdev; | ||
505 | |||
506 | /* get device, function */ | ||
507 | status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr); | ||
508 | if (ACPI_FAILURE(status)) { | ||
509 | if (status != AE_NOT_FOUND) | ||
510 | err("acpi_pciehprm:%s _ADR fail=0x%x\n", path_name, status); | ||
511 | return AE_OK; | ||
512 | } | ||
513 | |||
514 | devnum = (adr >> 16) & 0xffff; | ||
515 | funcnum = adr & 0xffff; | ||
516 | |||
517 | pdev = pci_find_slot(pab->bus, PCI_DEVFN(devnum, funcnum)); | ||
518 | if (!pdev) | ||
519 | return AE_OK; | ||
520 | if (!pdev->subordinate) | ||
521 | return AE_OK; | ||
522 | |||
523 | ab = add_p2p_bridge(handle, pab, adr); | ||
524 | if (ab) { | ||
525 | status = acpi_walk_namespace ( ACPI_TYPE_DEVICE, | ||
526 | handle, | ||
527 | (u32)1, | ||
528 | scan_p2p_bridge, | ||
529 | ab, | ||
530 | NULL); | ||
531 | if (ACPI_FAILURE(status)) | ||
532 | dbg("acpi_pciehprm:%s find_p2p fail=0x%x\n", path_name, status); | ||
533 | } | ||
534 | |||
535 | return AE_OK; | ||
536 | } | ||
537 | |||
538 | static struct acpi_bridge * add_host_bridge( | ||
539 | acpi_handle handle, | ||
540 | ulong segnum, | ||
541 | ulong busnum | ||
542 | ) | ||
543 | { | ||
544 | ulong adr = 0; | ||
545 | acpi_status status; | ||
546 | struct acpi_bridge *ab; | ||
547 | u8 *path_name = acpi_path_name(handle); | ||
548 | |||
549 | /* get device, function: host br adr is always 0000 though. */ | ||
550 | status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr); | ||
551 | if (ACPI_FAILURE(status)) { | ||
552 | err("acpi_pciehprm:%s _ADR fail=0x%x\n", path_name, status); | ||
553 | return NULL; | ||
554 | } | ||
555 | dbg("acpi_pciehprm: ROOT PCI seg(0x%x)bus(0x%x)dev(0x%x)func(0x%x) [%s]\n", (u32)segnum, | ||
556 | (u32)busnum, (u32)(adr >> 16) & 0xffff, (u32)adr & 0xffff, path_name); | ||
557 | |||
558 | ab = (struct acpi_bridge *) kmalloc (sizeof(struct acpi_bridge), GFP_KERNEL); | ||
559 | if (!ab) { | ||
560 | err("acpi_pciehprm: alloc for ab fail\n"); | ||
561 | return NULL; | ||
562 | } | ||
563 | memset(ab, 0, sizeof(struct acpi_bridge)); | ||
564 | |||
565 | ab->handle = handle; | ||
566 | ab->seg = (int)segnum; | ||
567 | ab->bus = ab->pbus = (int)busnum; | ||
568 | ab->pdevice = (int)(adr >> 16) & 0xffff; | ||
569 | ab->pfunction = (int)(adr & 0xffff); | ||
570 | ab->scanned = 0; | ||
571 | ab->type = BRIDGE_TYPE_HOST; | ||
572 | |||
573 | status = pci_osc_control_set (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL); | ||
574 | if (ACPI_FAILURE(status)) { | ||
575 | err("%s: status %x\n", __FUNCTION__, status); | ||
576 | osc_run_status = (status == AE_NOT_FOUND) ? OSC_NOT_EXIST : OSC_RUN_FAILED; | ||
577 | } else { | ||
578 | osc_run_status = NC_RUN_SUCCESS; | ||
579 | } | ||
580 | dbg("%s: osc_run_status %x\n", __FUNCTION__, osc_run_status); | ||
581 | |||
582 | build_a_bridge(ab, ab); | ||
583 | |||
584 | return ab; | ||
585 | } | ||
586 | |||
587 | static acpi_status acpi_scan_from_root_pci_callback ( | ||
588 | acpi_handle handle, | ||
589 | u32 Level, | ||
590 | void *context, | ||
591 | void **retval | ||
592 | ) | ||
593 | { | ||
594 | ulong segnum = 0; | ||
595 | ulong busnum = 0; | ||
596 | acpi_status status; | ||
597 | struct acpi_bridge *ab; | ||
598 | u8 *path_name = acpi_path_name(handle); | ||
599 | |||
600 | /* get bus number of this pci root bridge */ | ||
601 | status = acpi_evaluate_integer(handle, METHOD_NAME__SEG, NULL, &segnum); | ||
602 | if (ACPI_FAILURE(status)) { | ||
603 | if (status != AE_NOT_FOUND) { | ||
604 | err("acpi_pciehprm:%s evaluate _SEG fail=0x%x\n", path_name, status); | ||
605 | return status; | ||
606 | } | ||
607 | segnum = 0; | ||
608 | } | ||
609 | |||
610 | /* get bus number of this pci root bridge */ | ||
611 | status = acpi_evaluate_integer(handle, METHOD_NAME__BBN, NULL, &busnum); | ||
612 | if (ACPI_FAILURE(status)) { | ||
613 | err("acpi_pciehprm:%s evaluate _BBN fail=0x%x\n", path_name, status); | ||
614 | return (status); | ||
615 | } | ||
616 | |||
617 | ab = add_host_bridge(handle, segnum, busnum); | ||
618 | if (ab) { | ||
619 | status = acpi_walk_namespace ( ACPI_TYPE_DEVICE, | ||
620 | handle, | ||
621 | 1, | ||
622 | scan_p2p_bridge, | ||
623 | ab, | ||
624 | NULL); | ||
625 | if (ACPI_FAILURE(status)) | ||
626 | dbg("acpi_pciehprm:%s find_p2p fail=0x%x\n", path_name, status); | ||
627 | } | ||
628 | |||
629 | return AE_OK; | ||
630 | } | ||
631 | |||
632 | static int pciehprm_acpi_scan_pci (void) | ||
633 | { | 180 | { |
634 | acpi_status status; | 181 | acpi_status status = AE_NOT_FOUND; |
182 | struct pci_dev *pdev = dev; | ||
635 | 183 | ||
636 | /* | 184 | /* |
637 | * TBD: traverse LDM device tree with the help of | 185 | * _HPP settings apply to all child buses, until another _HPP is |
638 | * unified ACPI augmented for php device population. | 186 | * encountered. If we don't find an _HPP for the input pci dev, |
187 | * look for it in the parent device scope since that would apply to | ||
188 | * this pci dev. If we don't find any _HPP, use hardcoded defaults | ||
639 | */ | 189 | */ |
640 | status = acpi_get_devices ( PCI_ROOT_HID_STRING, | 190 | while (pdev && (ACPI_FAILURE(status))) { |
641 | acpi_scan_from_root_pci_callback, | 191 | acpi_handle handle = DEVICE_ACPI_HANDLE(&(pdev->dev)); |
642 | NULL, | 192 | if (!handle) |
643 | NULL ); | 193 | break; |
644 | if (ACPI_FAILURE(status)) { | 194 | status = acpi_run_hpp(handle, hpp); |
645 | err("acpi_pciehprm:get_device PCI ROOT HID fail=0x%x\n", status); | 195 | if (!(pdev->bus->parent)) |
646 | return -1; | 196 | break; |
647 | } | 197 | /* Check if a parent object supports _HPP */ |
648 | 198 | pdev = pdev->bus->parent->self; | |
649 | return 0; | ||
650 | } | ||
651 | |||
652 | int pciehprm_init(enum php_ctlr_type ctlr_type) | ||
653 | { | ||
654 | int rc; | ||
655 | |||
656 | if (ctlr_type != PCI) | ||
657 | return -ENODEV; | ||
658 | |||
659 | dbg("pciehprm ACPI init <enter>\n"); | ||
660 | acpi_bridges_head = NULL; | ||
661 | |||
662 | /* construct PCI bus:device tree of acpi_handles */ | ||
663 | rc = pciehprm_acpi_scan_pci(); | ||
664 | if (rc) | ||
665 | return rc; | ||
666 | |||
667 | if ((oshp_run_status != NC_RUN_SUCCESS) && (osc_run_status != NC_RUN_SUCCESS)) { | ||
668 | err("Fails to gain control of native hot-plug\n"); | ||
669 | rc = -ENODEV; | ||
670 | } | ||
671 | |||
672 | dbg("pciehprm ACPI init %s\n", (rc)?"fail":"success"); | ||
673 | return rc; | ||
674 | } | ||
675 | |||
676 | static void free_a_slot(struct acpi_php_slot *aps) | ||
677 | { | ||
678 | dbg(" free a php func of slot(0x%02x) on PCI b:d:f=0x%02x:%02x:%02x\n", aps->sun, aps->bus, aps->dev, aps->fun); | ||
679 | |||
680 | kfree(aps); | ||
681 | } | ||
682 | |||
683 | static void free_a_bridge( struct acpi_bridge *ab) | ||
684 | { | ||
685 | struct acpi_php_slot *aps, *next; | ||
686 | |||
687 | switch (ab->type) { | ||
688 | case BRIDGE_TYPE_HOST: | ||
689 | dbg("Free ACPI PCI HOST Bridge(%x) [%s] on s:b:d:f(%x:%x:%x:%x)\n", | ||
690 | ab->bus, acpi_path_name(ab->handle), ab->seg, ab->pbus, ab->pdevice, ab->pfunction); | ||
691 | break; | ||
692 | case BRIDGE_TYPE_P2P: | ||
693 | dbg("Free ACPI PCI P2P Bridge(%x-%x) [%s] on s:b:d:f(%x:%x:%x:%x)\n", | ||
694 | ab->pbus, ab->bus, acpi_path_name(ab->handle), ab->seg, ab->pbus, ab->pdevice, ab->pfunction); | ||
695 | break; | ||
696 | }; | ||
697 | |||
698 | /* free slots first */ | ||
699 | for (aps = ab->slots; aps; aps = next) { | ||
700 | next = aps->next; | ||
701 | free_a_slot(aps); | ||
702 | } | ||
703 | |||
704 | kfree(ab); | ||
705 | } | ||
706 | |||
707 | static void pciehprm_free_bridges ( struct acpi_bridge *ab) | ||
708 | { | ||
709 | if (!ab) | ||
710 | return; | ||
711 | |||
712 | if (ab->child) | ||
713 | pciehprm_free_bridges (ab->child); | ||
714 | |||
715 | if (ab->next) | ||
716 | pciehprm_free_bridges (ab->next); | ||
717 | |||
718 | free_a_bridge(ab); | ||
719 | } | ||
720 | |||
721 | void pciehprm_cleanup(void) | ||
722 | { | ||
723 | pciehprm_free_bridges (acpi_bridges_head); | ||
724 | } | ||
725 | |||
726 | static int get_number_of_slots ( | ||
727 | struct acpi_bridge *ab, | ||
728 | int selfonly | ||
729 | ) | ||
730 | { | ||
731 | struct acpi_php_slot *aps; | ||
732 | int prev_slot = -1; | ||
733 | int slot_num = 0; | ||
734 | |||
735 | for ( aps = ab->slots; aps; aps = aps->next) | ||
736 | if (aps->dev != prev_slot) { | ||
737 | prev_slot = aps->dev; | ||
738 | slot_num++; | ||
739 | } | ||
740 | |||
741 | if (ab->child) | ||
742 | slot_num += get_number_of_slots (ab->child, 0); | ||
743 | |||
744 | if (selfonly) | ||
745 | return slot_num; | ||
746 | |||
747 | if (ab->next) | ||
748 | slot_num += get_number_of_slots (ab->next, 0); | ||
749 | |||
750 | return slot_num; | ||
751 | } | ||
752 | |||
753 | static struct acpi_php_slot * get_acpi_slot ( | ||
754 | struct acpi_bridge *ab, | ||
755 | u32 sun | ||
756 | ) | ||
757 | { | ||
758 | struct acpi_php_slot *aps = NULL; | ||
759 | |||
760 | for ( aps = ab->slots; aps; aps = aps->next) | ||
761 | if (aps->sun == sun) | ||
762 | return aps; | ||
763 | |||
764 | if (!aps && ab->child) { | ||
765 | aps = (struct acpi_php_slot *)get_acpi_slot (ab->child, sun); | ||
766 | if (aps) | ||
767 | return aps; | ||
768 | } | ||
769 | |||
770 | if (!aps && ab->next) { | ||
771 | aps = (struct acpi_php_slot *)get_acpi_slot (ab->next, sun); | ||
772 | if (aps) | ||
773 | return aps; | ||
774 | } | ||
775 | |||
776 | return aps; | ||
777 | |||
778 | } | ||
779 | |||
780 | #if 0 | ||
781 | void * pciehprm_get_slot(struct slot *slot) | ||
782 | { | ||
783 | struct acpi_bridge *ab = acpi_bridges_head; | ||
784 | struct acpi_php_slot *aps = get_acpi_slot (ab, slot->number); | ||
785 | |||
786 | aps->slot = slot; | ||
787 | |||
788 | dbg("Got acpi slot sun(%x): s:b:d:f(%x:%x:%x:%x)\n", aps->sun, aps->seg, aps->bus, aps->dev, aps->fun); | ||
789 | |||
790 | return (void *)aps; | ||
791 | } | ||
792 | #endif | ||
793 | |||
794 | int pciehprm_set_hpp( | ||
795 | struct controller *ctrl, | ||
796 | struct pci_func *func, | ||
797 | u8 card_type | ||
798 | ) | ||
799 | { | ||
800 | struct acpi_bridge *ab; | ||
801 | struct pci_bus lpci_bus, *pci_bus; | ||
802 | int rc = 0; | ||
803 | unsigned int devfn; | ||
804 | u8 cls= 0x08; /* default cache line size */ | ||
805 | u8 lt = 0x40; /* default latency timer */ | ||
806 | u8 ep = 0; | ||
807 | u8 es = 0; | ||
808 | |||
809 | memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus)); | ||
810 | pci_bus = &lpci_bus; | ||
811 | pci_bus->number = func->bus; | ||
812 | devfn = PCI_DEVFN(func->device, func->function); | ||
813 | |||
814 | ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->bus); | ||
815 | |||
816 | if (ab) { | ||
817 | if (ab->_hpp) { | ||
818 | lt = (u8)ab->_hpp->latency_timer; | ||
819 | cls = (u8)ab->_hpp->cache_line_size; | ||
820 | ep = (u8)ab->_hpp->enable_perr; | ||
821 | es = (u8)ab->_hpp->enable_serr; | ||
822 | } else | ||
823 | dbg("_hpp: no _hpp for B/D/F=%#x/%#x/%#x. use default value\n", func->bus, func->device, func->function); | ||
824 | } else | ||
825 | dbg("_hpp: no acpi bridge for B/D/F = %#x/%#x/%#x. use default value\n", func->bus, func->device, func->function); | ||
826 | |||
827 | |||
828 | if (card_type == PCI_HEADER_TYPE_BRIDGE) { | ||
829 | /* set subordinate Latency Timer */ | ||
830 | rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_SEC_LATENCY_TIMER, lt); | ||
831 | } | 199 | } |
832 | |||
833 | /* set base Latency Timer */ | ||
834 | rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_LATENCY_TIMER, lt); | ||
835 | dbg(" set latency timer =0x%02x: %x\n", lt, rc); | ||
836 | |||
837 | rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_CACHE_LINE_SIZE, cls); | ||
838 | dbg(" set cache_line_size=0x%02x: %x\n", cls, rc); | ||
839 | |||
840 | return rc; | ||
841 | } | 200 | } |
842 | 201 | ||
843 | void pciehprm_enable_card( | ||
844 | struct controller *ctrl, | ||
845 | struct pci_func *func, | ||
846 | u8 card_type) | ||
847 | { | ||
848 | u16 command, cmd, bcommand, bcmd; | ||
849 | struct pci_bus lpci_bus, *pci_bus; | ||
850 | struct acpi_bridge *ab; | ||
851 | unsigned int devfn; | ||
852 | int rc; | ||
853 | |||
854 | memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus)); | ||
855 | pci_bus = &lpci_bus; | ||
856 | pci_bus->number = func->bus; | ||
857 | devfn = PCI_DEVFN(func->device, func->function); | ||
858 | |||
859 | rc = pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &cmd); | ||
860 | |||
861 | if (card_type == PCI_HEADER_TYPE_BRIDGE) { | ||
862 | rc = pci_bus_read_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, &bcmd); | ||
863 | } | ||
864 | |||
865 | command = cmd | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE | ||
866 | | PCI_COMMAND_IO | PCI_COMMAND_MEMORY; | ||
867 | bcommand = bcmd | PCI_BRIDGE_CTL_NO_ISA; | ||
868 | |||
869 | ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->bus); | ||
870 | if (ab) { | ||
871 | if (ab->_hpp) { | ||
872 | if (ab->_hpp->enable_perr) { | ||
873 | command |= PCI_COMMAND_PARITY; | ||
874 | bcommand |= PCI_BRIDGE_CTL_PARITY; | ||
875 | } else { | ||
876 | command &= ~PCI_COMMAND_PARITY; | ||
877 | bcommand &= ~PCI_BRIDGE_CTL_PARITY; | ||
878 | } | ||
879 | if (ab->_hpp->enable_serr) { | ||
880 | command |= PCI_COMMAND_SERR; | ||
881 | bcommand |= PCI_BRIDGE_CTL_SERR; | ||
882 | } else { | ||
883 | command &= ~PCI_COMMAND_SERR; | ||
884 | bcommand &= ~PCI_BRIDGE_CTL_SERR; | ||
885 | } | ||
886 | } else | ||
887 | dbg("no _hpp for B/D/F = %#x/%#x/%#x.\n", func->bus, func->device, func->function); | ||
888 | } else | ||
889 | dbg("no acpi bridge for B/D/F = %#x/%#x/%#x.\n", func->bus, func->device, func->function); | ||
890 | |||
891 | if (command != cmd) { | ||
892 | rc = pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command); | ||
893 | } | ||
894 | if ((card_type == PCI_HEADER_TYPE_BRIDGE) && (bcommand != bcmd)) { | ||
895 | rc = pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, bcommand); | ||
896 | } | ||
897 | } | ||
diff --git a/drivers/pci/hotplug/pciehprm_nonacpi.c b/drivers/pci/hotplug/pciehprm_nonacpi.c index ed68c3dd0f08..32371cd19e34 100644 --- a/drivers/pci/hotplug/pciehprm_nonacpi.c +++ b/drivers/pci/hotplug/pciehprm_nonacpi.c | |||
@@ -37,15 +37,9 @@ | |||
37 | #include <linux/slab.h> | 37 | #include <linux/slab.h> |
38 | #include <asm/uaccess.h> | 38 | #include <asm/uaccess.h> |
39 | #include "pciehp.h" | 39 | #include "pciehp.h" |
40 | #include "pciehprm.h" | ||
41 | #include "pciehprm_nonacpi.h" | 40 | #include "pciehprm_nonacpi.h" |
42 | 41 | ||
43 | 42 | ||
44 | void pciehprm_cleanup(void) | ||
45 | { | ||
46 | return; | ||
47 | } | ||
48 | |||
49 | int pciehprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum) | 43 | int pciehprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum) |
50 | { | 44 | { |
51 | 45 | ||
@@ -53,106 +47,13 @@ int pciehprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busn | |||
53 | return 0; | 47 | return 0; |
54 | } | 48 | } |
55 | 49 | ||
56 | int pciehprm_set_hpp( | 50 | void get_hp_params_from_firmware(struct pci_dev *dev, |
57 | struct controller *ctrl, | 51 | struct hotplug_params *hpp) |
58 | struct pci_func *func, | ||
59 | u8 card_type) | ||
60 | { | ||
61 | u32 rc; | ||
62 | u8 temp_byte; | ||
63 | struct pci_bus lpci_bus, *pci_bus; | ||
64 | unsigned int devfn; | ||
65 | memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus)); | ||
66 | pci_bus = &lpci_bus; | ||
67 | pci_bus->number = func->bus; | ||
68 | devfn = PCI_DEVFN(func->device, func->function); | ||
69 | |||
70 | temp_byte = 0x40; /* hard coded value for LT */ | ||
71 | if (card_type == PCI_HEADER_TYPE_BRIDGE) { | ||
72 | /* set subordinate Latency Timer */ | ||
73 | rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_SEC_LATENCY_TIMER, temp_byte); | ||
74 | |||
75 | if (rc) { | ||
76 | dbg("%s: set secondary LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, | ||
77 | func->bus, func->device, func->function); | ||
78 | return rc; | ||
79 | } | ||
80 | } | ||
81 | |||
82 | /* set base Latency Timer */ | ||
83 | rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_LATENCY_TIMER, temp_byte); | ||
84 | |||
85 | if (rc) { | ||
86 | dbg("%s: set LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, func->device, func->function); | ||
87 | return rc; | ||
88 | } | ||
89 | |||
90 | /* set Cache Line size */ | ||
91 | temp_byte = 0x08; /* hard coded value for CLS */ | ||
92 | |||
93 | rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_CACHE_LINE_SIZE, temp_byte); | ||
94 | |||
95 | if (rc) { | ||
96 | dbg("%s: set CLS error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, func->device, func->function); | ||
97 | } | ||
98 | |||
99 | /* set enable_perr */ | ||
100 | /* set enable_serr */ | ||
101 | |||
102 | return rc; | ||
103 | } | ||
104 | |||
105 | void pciehprm_enable_card( | ||
106 | struct controller *ctrl, | ||
107 | struct pci_func *func, | ||
108 | u8 card_type) | ||
109 | { | 52 | { |
110 | u16 command, bcommand; | 53 | return; |
111 | struct pci_bus lpci_bus, *pci_bus; | ||
112 | unsigned int devfn; | ||
113 | int rc; | ||
114 | |||
115 | memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus)); | ||
116 | pci_bus = &lpci_bus; | ||
117 | pci_bus->number = func->bus; | ||
118 | devfn = PCI_DEVFN(func->device, func->function); | ||
119 | |||
120 | rc = pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &command); | ||
121 | |||
122 | command |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR | ||
123 | | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE | ||
124 | | PCI_COMMAND_IO | PCI_COMMAND_MEMORY; | ||
125 | |||
126 | rc = pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command); | ||
127 | |||
128 | if (card_type == PCI_HEADER_TYPE_BRIDGE) { | ||
129 | |||
130 | rc = pci_bus_read_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, &bcommand); | ||
131 | |||
132 | bcommand |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR | ||
133 | | PCI_BRIDGE_CTL_NO_ISA; | ||
134 | |||
135 | rc = pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, bcommand); | ||
136 | } | ||
137 | } | 54 | } |
138 | 55 | ||
139 | static int legacy_pciehprm_init_pci(void) | 56 | int get_hp_hw_control_from_firmware(struct pci_dev *dev) |
140 | { | 57 | { |
141 | return 0; | 58 | return 0; |
142 | } | 59 | } |
143 | |||
144 | int pciehprm_init(enum php_ctlr_type ctrl_type) | ||
145 | { | ||
146 | int retval; | ||
147 | |||
148 | switch (ctrl_type) { | ||
149 | case PCI: | ||
150 | retval = legacy_pciehprm_init_pci(); | ||
151 | break; | ||
152 | default: | ||
153 | retval = -ENODEV; | ||
154 | break; | ||
155 | } | ||
156 | |||
157 | return retval; | ||
158 | } | ||
diff --git a/drivers/pci/hotplug/pciehprm_nonacpi.h b/drivers/pci/hotplug/pciehprm_nonacpi.h deleted file mode 100644 index b10603b0e958..000000000000 --- a/drivers/pci/hotplug/pciehprm_nonacpi.h +++ /dev/null | |||
@@ -1,56 +0,0 @@ | |||
1 | /* | ||
2 | * PCIEHPRM NONACPI: PHP Resource Manager for Non-ACPI/Legacy platform | ||
3 | * | ||
4 | * Copyright (C) 1995,2001 Compaq Computer Corporation | ||
5 | * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) | ||
6 | * Copyright (C) 2001 IBM Corp. | ||
7 | * Copyright (C) 2003-2004 Intel Corporation | ||
8 | * | ||
9 | * All rights reserved. | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; either version 2 of the License, or (at | ||
14 | * your option) any later version. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, but | ||
17 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
19 | * NON INFRINGEMENT. See the GNU General Public License for more | ||
20 | * details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | * | ||
26 | * Send feedback to <greg@kroah.com>, <kristen.c.accardi@intel.com> | ||
27 | * | ||
28 | */ | ||
29 | |||
30 | #ifndef _PCIEHPRM_NONACPI_H_ | ||
31 | #define _PCIEHPRM_NONACPI_H_ | ||
32 | |||
33 | struct irq_info { | ||
34 | u8 bus, devfn; /* bus, device and function */ | ||
35 | struct { | ||
36 | u8 link; /* IRQ line ID, chipset dependent, 0=not routed */ | ||
37 | u16 bitmap; /* Available IRQs */ | ||
38 | } __attribute__ ((packed)) irq[4]; | ||
39 | u8 slot; /* slot number, 0=onboard */ | ||
40 | u8 rfu; | ||
41 | } __attribute__ ((packed)); | ||
42 | |||
43 | struct irq_routing_table { | ||
44 | u32 signature; /* PIRQ_SIGNATURE should be here */ | ||
45 | u16 version; /* PIRQ_VERSION */ | ||
46 | u16 size; /* Table size in bytes */ | ||
47 | u8 rtr_bus, rtr_devfn; /* Where the interrupt router lies */ | ||
48 | u16 exclusive_irqs; /* IRQs devoted exclusively to PCI usage */ | ||
49 | u16 rtr_vendor, rtr_device; /* Vendor and device ID of interrupt router */ | ||
50 | u32 miniport_data; /* Crap */ | ||
51 | u8 rfu[11]; | ||
52 | u8 checksum; /* Modulo 256 checksum must give zero */ | ||
53 | struct irq_info slots[0]; | ||
54 | } __attribute__ ((packed)); | ||
55 | |||
56 | #endif /* _PCIEHPRM_NONACPI_H_ */ | ||