diff options
author | rajesh.shah@intel.com <rajesh.shah@intel.com> | 2005-10-13 15:05:38 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2005-10-28 18:37:00 -0400 |
commit | 424600f9706b20a8a33ad928d3d0326bd88679bc (patch) | |
tree | 364509b512ff4f522b38329df582553a9c8fb6ff /drivers/pci | |
parent | 7e88ed199689f333668b62348051202706b6a74a (diff) |
[PATCH] shpchp: reduce dependence on ACPI
Reduce the SHPC hotplug driver's dependence on ACPI. We don't
walk the acpi namespace anymore to build a list of bridges and
devices. The remaining interaction with ACPI is to run the
_OSHP method to transition control of hotplug hardware from
system BIOS to the shpc hotplug driver, and to run the _HPP
method to get hotplug device parameters like cache line size,
latency timer and SERR/PERR enable from BIOS.
Note that one of the side effects of this patch is that shpchp
does not enable the hot-added device or its DMA bus mastering
automatically now. It expects the device driver to do that.
This may break some drivers and we will have to fix them as
they are reported.
Signed-off-by: Rajesh Shah <rajesh.shah@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/hotplug/shpchp.h | 12 | ||||
-rw-r--r-- | drivers/pci/hotplug/shpchp_core.c | 13 | ||||
-rw-r--r-- | drivers/pci/hotplug/shpchp_ctrl.c | 1 | ||||
-rw-r--r-- | drivers/pci/hotplug/shpchp_hpc.c | 2 | ||||
-rw-r--r-- | drivers/pci/hotplug/shpchp_pci.c | 52 | ||||
-rw-r--r-- | drivers/pci/hotplug/shpchprm.h | 43 | ||||
-rw-r--r-- | drivers/pci/hotplug/shpchprm_acpi.c | 794 | ||||
-rw-r--r-- | drivers/pci/hotplug/shpchprm_legacy.c | 97 | ||||
-rw-r--r-- | drivers/pci/hotplug/shpchprm_nonacpi.c | 108 |
9 files changed, 138 insertions, 984 deletions
diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h index deea56c73cf2..1b345ae81ddb 100644 --- a/drivers/pci/hotplug/shpchp.h +++ b/drivers/pci/hotplug/shpchp.h | |||
@@ -122,6 +122,13 @@ struct controller { | |||
122 | u16 vendor_id; | 122 | u16 vendor_id; |
123 | }; | 123 | }; |
124 | 124 | ||
125 | struct hotplug_params { | ||
126 | u8 cache_line_size; | ||
127 | u8 latency_timer; | ||
128 | u8 enable_serr; | ||
129 | u8 enable_perr; | ||
130 | }; | ||
131 | |||
125 | /* Define AMD SHPC ID */ | 132 | /* Define AMD SHPC ID */ |
126 | #define PCI_DEVICE_ID_AMD_GOLAM_7450 0x7450 | 133 | #define PCI_DEVICE_ID_AMD_GOLAM_7450 0x7450 |
127 | 134 | ||
@@ -192,6 +199,11 @@ extern int shpchp_save_config(struct controller *ctrl, int busnumber, int num_ct | |||
192 | extern int shpchp_save_slot_config(struct controller *ctrl, struct pci_func * new_slot); | 199 | extern int shpchp_save_slot_config(struct controller *ctrl, struct pci_func * new_slot); |
193 | extern int shpchp_configure_device(struct slot *p_slot); | 200 | extern int shpchp_configure_device(struct slot *p_slot); |
194 | extern int shpchp_unconfigure_device(struct pci_func* func); | 201 | extern int shpchp_unconfigure_device(struct pci_func* func); |
202 | extern void get_hp_hw_control_from_firmware(struct pci_dev *dev); | ||
203 | extern void get_hp_params_from_firmware(struct pci_dev *dev, | ||
204 | struct hotplug_params *hpp); | ||
205 | extern int shpchprm_get_physical_slot_number(struct controller *ctrl, | ||
206 | u32 *sun, u8 busnum, u8 devnum); | ||
195 | 207 | ||
196 | 208 | ||
197 | /* Global variables */ | 209 | /* Global variables */ |
diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index 8f5da504df34..e3c0c17295da 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_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 "shpchp.h" | 41 | #include "shpchp.h" |
42 | #include "shpchprm.h" | ||
43 | 42 | ||
44 | /* Global variables */ | 43 | /* Global variables */ |
45 | int shpchp_debug; | 44 | int shpchp_debug; |
@@ -566,16 +565,12 @@ static int __init shpcd_init(void) | |||
566 | if (retval) | 565 | if (retval) |
567 | goto error_hpc_init; | 566 | goto error_hpc_init; |
568 | 567 | ||
569 | retval = shpchprm_init(PCI); | 568 | retval = pci_register_driver(&shpc_driver); |
570 | if (!retval) { | 569 | dbg("%s: pci_register_driver = %d\n", __FUNCTION__, retval); |
571 | retval = pci_register_driver(&shpc_driver); | 570 | info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); |
572 | dbg("%s: pci_register_driver = %d\n", __FUNCTION__, retval); | ||
573 | info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); | ||
574 | } | ||
575 | 571 | ||
576 | error_hpc_init: | 572 | error_hpc_init: |
577 | if (retval) { | 573 | if (retval) { |
578 | shpchprm_cleanup(); | ||
579 | shpchp_event_stop_thread(); | 574 | shpchp_event_stop_thread(); |
580 | } | 575 | } |
581 | return retval; | 576 | return retval; |
@@ -586,8 +581,6 @@ static void __exit shpcd_cleanup(void) | |||
586 | dbg("unload_shpchpd()\n"); | 581 | dbg("unload_shpchpd()\n"); |
587 | unload_shpchpd(); | 582 | unload_shpchpd(); |
588 | 583 | ||
589 | shpchprm_cleanup(); | ||
590 | |||
591 | dbg("pci_unregister_driver\n"); | 584 | dbg("pci_unregister_driver\n"); |
592 | pci_unregister_driver(&shpc_driver); | 585 | pci_unregister_driver(&shpc_driver); |
593 | 586 | ||
diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c index aa507e453e49..23dd61c4c66c 100644 --- a/drivers/pci/hotplug/shpchp_ctrl.c +++ b/drivers/pci/hotplug/shpchp_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 "shpchp.h" | 42 | #include "shpchp.h" |
43 | #include "shpchprm.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/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index 8d98410bf1c0..d55a9a7f8d2b 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c | |||
@@ -1566,8 +1566,8 @@ int shpc_init(struct controller * ctrl, | |||
1566 | err("Can't get irq %d for the hotplug controller\n", php_ctlr->irq); | 1566 | err("Can't get irq %d for the hotplug controller\n", php_ctlr->irq); |
1567 | goto abort_free_ctlr; | 1567 | goto abort_free_ctlr; |
1568 | } | 1568 | } |
1569 | /* Execute OSHP method here */ | ||
1570 | } | 1569 | } |
1570 | get_hp_hw_control_from_firmware(pdev); | ||
1571 | dbg("%s: Before adding HPC to HPC list\n", __FUNCTION__); | 1571 | dbg("%s: Before adding HPC to HPC list\n", __FUNCTION__); |
1572 | 1572 | ||
1573 | /* Add this HPC instance into the HPC list */ | 1573 | /* Add this HPC instance into the HPC list */ |
diff --git a/drivers/pci/hotplug/shpchp_pci.c b/drivers/pci/hotplug/shpchp_pci.c index 89e404805777..6209972313f3 100644 --- a/drivers/pci/hotplug/shpchp_pci.c +++ b/drivers/pci/hotplug/shpchp_pci.c | |||
@@ -38,6 +38,55 @@ | |||
38 | #include "../pci.h" | 38 | #include "../pci.h" |
39 | #include "shpchp.h" | 39 | #include "shpchp.h" |
40 | 40 | ||
41 | void program_fw_provided_values(struct pci_dev *dev) | ||
42 | { | ||
43 | u16 pci_cmd, pci_bctl; | ||
44 | struct pci_dev *cdev; | ||
45 | struct hotplug_params hpp = {0x8, 0x40, 0, 0}; /* defaults */ | ||
46 | |||
47 | /* Program hpp values for this device */ | ||
48 | if (!(dev->hdr_type == PCI_HEADER_TYPE_NORMAL || | ||
49 | (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE && | ||
50 | (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI))) | ||
51 | return; | ||
52 | |||
53 | get_hp_params_from_firmware(dev, &hpp); | ||
54 | |||
55 | pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, hpp.cache_line_size); | ||
56 | pci_write_config_byte(dev, PCI_LATENCY_TIMER, hpp.latency_timer); | ||
57 | pci_read_config_word(dev, PCI_COMMAND, &pci_cmd); | ||
58 | if (hpp.enable_serr) | ||
59 | pci_cmd |= PCI_COMMAND_SERR; | ||
60 | else | ||
61 | pci_cmd &= ~PCI_COMMAND_SERR; | ||
62 | if (hpp.enable_perr) | ||
63 | pci_cmd |= PCI_COMMAND_PARITY; | ||
64 | else | ||
65 | pci_cmd &= ~PCI_COMMAND_PARITY; | ||
66 | pci_write_config_word(dev, PCI_COMMAND, pci_cmd); | ||
67 | |||
68 | /* Program bridge control value and child devices */ | ||
69 | if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { | ||
70 | pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, | ||
71 | hpp.latency_timer); | ||
72 | pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &pci_bctl); | ||
73 | if (hpp.enable_serr) | ||
74 | pci_bctl |= PCI_BRIDGE_CTL_SERR; | ||
75 | else | ||
76 | pci_bctl &= ~PCI_BRIDGE_CTL_SERR; | ||
77 | if (hpp.enable_perr) | ||
78 | pci_bctl |= PCI_BRIDGE_CTL_PARITY; | ||
79 | else | ||
80 | pci_bctl &= ~PCI_BRIDGE_CTL_PARITY; | ||
81 | pci_write_config_word(dev, PCI_BRIDGE_CONTROL, pci_bctl); | ||
82 | if (dev->subordinate) { | ||
83 | list_for_each_entry(cdev, &dev->subordinate->devices, | ||
84 | bus_list) | ||
85 | program_fw_provided_values(cdev); | ||
86 | } | ||
87 | } | ||
88 | } | ||
89 | |||
41 | int shpchp_configure_device(struct slot *p_slot) | 90 | int shpchp_configure_device(struct slot *p_slot) |
42 | { | 91 | { |
43 | struct pci_dev *dev; | 92 | struct pci_dev *dev; |
@@ -90,8 +139,7 @@ int shpchp_configure_device(struct slot *p_slot) | |||
90 | child->subordinate = pci_do_scan_bus(child); | 139 | child->subordinate = pci_do_scan_bus(child); |
91 | pci_bus_size_bridges(child); | 140 | pci_bus_size_bridges(child); |
92 | } | 141 | } |
93 | /* TBD: program firmware provided _HPP values */ | 142 | program_fw_provided_values(dev); |
94 | /* program_fw_provided_values(dev); */ | ||
95 | } | 143 | } |
96 | 144 | ||
97 | pci_bus_assign_resources(parent); | 145 | pci_bus_assign_resources(parent); |
diff --git a/drivers/pci/hotplug/shpchprm.h b/drivers/pci/hotplug/shpchprm.h deleted file mode 100644 index df474b27d6e8..000000000000 --- a/drivers/pci/hotplug/shpchprm.h +++ /dev/null | |||
@@ -1,43 +0,0 @@ | |||
1 | /* | ||
2 | * SHPCHPRM : SHPCHP Resource Manager for ACPI/non-ACPI 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 _SHPCHPRM_H_ | ||
31 | #define _SHPCHPRM_H_ | ||
32 | |||
33 | #ifdef CONFIG_HOTPLUG_PCI_SHPC_PHPRM_LEGACY | ||
34 | #include "shpchprm_legacy.h" | ||
35 | #endif | ||
36 | |||
37 | int shpchprm_init(enum php_ctlr_type ct); | ||
38 | void shpchprm_cleanup(void); | ||
39 | int shpchprm_set_hpp(struct controller *ctrl, struct pci_func *func, u8 card_type); | ||
40 | void shpchprm_enable_card(struct controller *ctrl, struct pci_func *func, u8 card_type); | ||
41 | int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum); | ||
42 | |||
43 | #endif /* _SHPCHPRM_H_ */ | ||
diff --git a/drivers/pci/hotplug/shpchprm_acpi.c b/drivers/pci/hotplug/shpchprm_acpi.c index 3d2f9c5269c7..3be518c7d47a 100644 --- a/drivers/pci/hotplug/shpchprm_acpi.c +++ b/drivers/pci/hotplug/shpchprm_acpi.c | |||
@@ -38,62 +38,11 @@ | |||
38 | #include <acpi/acpi_bus.h> | 38 | #include <acpi/acpi_bus.h> |
39 | #include <acpi/actypes.h> | 39 | #include <acpi/actypes.h> |
40 | #include "shpchp.h" | 40 | #include "shpchp.h" |
41 | #include "shpchprm.h" | ||
42 | |||
43 | #define PCI_MAX_BUS 0x100 | ||
44 | #define ACPI_STA_DEVICE_PRESENT 0x01 | ||
45 | 41 | ||
46 | #define METHOD_NAME__SUN "_SUN" | 42 | #define METHOD_NAME__SUN "_SUN" |
47 | #define METHOD_NAME__HPP "_HPP" | 43 | #define METHOD_NAME__HPP "_HPP" |
48 | #define METHOD_NAME_OSHP "OSHP" | 44 | #define METHOD_NAME_OSHP "OSHP" |
49 | 45 | ||
50 | #define PHP_RES_BUS 0xA0 | ||
51 | #define PHP_RES_IO 0xA1 | ||
52 | #define PHP_RES_MEM 0xA2 | ||
53 | #define PHP_RES_PMEM 0xA3 | ||
54 | |||
55 | #define BRIDGE_TYPE_P2P 0x00 | ||
56 | #define BRIDGE_TYPE_HOST 0x01 | ||
57 | |||
58 | /* this should go to drivers/acpi/include/ */ | ||
59 | struct acpi__hpp { | ||
60 | u8 cache_line_size; | ||
61 | u8 latency_timer; | ||
62 | u8 enable_serr; | ||
63 | u8 enable_perr; | ||
64 | }; | ||
65 | |||
66 | struct acpi_php_slot { | ||
67 | struct acpi_php_slot *next; | ||
68 | struct acpi_bridge *bridge; | ||
69 | acpi_handle handle; | ||
70 | int seg; | ||
71 | int bus; | ||
72 | int dev; | ||
73 | int fun; | ||
74 | u32 sun; | ||
75 | void *slot_ops; /* _STA, _EJx, etc */ | ||
76 | struct slot *slot; | ||
77 | }; /* per func */ | ||
78 | |||
79 | struct acpi_bridge { | ||
80 | struct acpi_bridge *parent; | ||
81 | struct acpi_bridge *next; | ||
82 | struct acpi_bridge *child; | ||
83 | acpi_handle handle; | ||
84 | int seg; | ||
85 | int pbus; /* pdev->bus->number */ | ||
86 | int pdevice; /* PCI_SLOT(pdev->devfn) */ | ||
87 | int pfunction; /* PCI_DEVFN(pdev->devfn) */ | ||
88 | int bus; /* pdev->subordinate->number */ | ||
89 | struct acpi__hpp *_hpp; | ||
90 | struct acpi_php_slot *slots; | ||
91 | int scanned; | ||
92 | int type; | ||
93 | }; | ||
94 | |||
95 | static struct acpi_bridge *acpi_bridges_head; | ||
96 | |||
97 | static u8 * acpi_path_name( acpi_handle handle) | 46 | static u8 * acpi_path_name( acpi_handle handle) |
98 | { | 47 | { |
99 | acpi_status status; | 48 | acpi_status status; |
@@ -109,82 +58,43 @@ static u8 * acpi_path_name( acpi_handle handle) | |||
109 | return path_name; | 58 | return path_name; |
110 | } | 59 | } |
111 | 60 | ||
112 | static void acpi_get__hpp ( struct acpi_bridge *ab); | 61 | static acpi_status |
113 | static void acpi_run_oshp ( struct acpi_bridge *ab); | 62 | acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp) |
114 | |||
115 | static int acpi_add_slot_to_php_slots( | ||
116 | struct acpi_bridge *ab, | ||
117 | int bus_num, | ||
118 | acpi_handle handle, | ||
119 | u32 adr, | ||
120 | u32 sun | ||
121 | ) | ||
122 | { | ||
123 | struct acpi_php_slot *aps; | ||
124 | static long samesun = -1; | ||
125 | |||
126 | aps = (struct acpi_php_slot *) kmalloc (sizeof(struct acpi_php_slot), GFP_KERNEL); | ||
127 | if (!aps) { | ||
128 | err ("acpi_shpchprm: alloc for aps fail\n"); | ||
129 | return -1; | ||
130 | } | ||
131 | memset(aps, 0, sizeof(struct acpi_php_slot)); | ||
132 | |||
133 | aps->handle = handle; | ||
134 | aps->bus = bus_num; | ||
135 | aps->dev = (adr >> 16) & 0xffff; | ||
136 | aps->fun = adr & 0xffff; | ||
137 | aps->sun = sun; | ||
138 | |||
139 | aps->next = ab->slots; /* cling to the bridge */ | ||
140 | aps->bridge = ab; | ||
141 | ab->slots = aps; | ||
142 | |||
143 | ab->scanned += 1; | ||
144 | if (!ab->_hpp) | ||
145 | acpi_get__hpp(ab); | ||
146 | |||
147 | acpi_run_oshp(ab); | ||
148 | |||
149 | if (sun != samesun) { | ||
150 | info("acpi_shpchprm: Slot sun(%x) at s:b:d:f=0x%02x:%02x:%02x:%02x\n", aps->sun, ab->seg, | ||
151 | aps->bus, aps->dev, aps->fun); | ||
152 | samesun = sun; | ||
153 | } | ||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | static void acpi_get__hpp ( struct acpi_bridge *ab) | ||
158 | { | 63 | { |
159 | acpi_status status; | 64 | acpi_status status; |
160 | u8 nui[4]; | 65 | u8 nui[4]; |
161 | struct acpi_buffer ret_buf = { 0, NULL}; | 66 | struct acpi_buffer ret_buf = { 0, NULL}; |
162 | union acpi_object *ext_obj, *package; | 67 | union acpi_object *ext_obj, *package; |
163 | u8 *path_name = acpi_path_name(ab->handle); | 68 | u8 *path_name = acpi_path_name(handle); |
164 | int i, len = 0; | 69 | int i, len = 0; |
165 | 70 | ||
166 | /* get _hpp */ | 71 | /* get _hpp */ |
167 | status = acpi_evaluate_object(ab->handle, METHOD_NAME__HPP, NULL, &ret_buf); | 72 | status = acpi_evaluate_object(handle, METHOD_NAME__HPP, NULL, &ret_buf); |
168 | switch (status) { | 73 | switch (status) { |
169 | case AE_BUFFER_OVERFLOW: | 74 | case AE_BUFFER_OVERFLOW: |
170 | ret_buf.pointer = kmalloc (ret_buf.length, GFP_KERNEL); | 75 | ret_buf.pointer = kmalloc (ret_buf.length, GFP_KERNEL); |
171 | if (!ret_buf.pointer) { | 76 | if (!ret_buf.pointer) { |
172 | err ("acpi_shpchprm:%s alloc for _HPP fail\n", path_name); | 77 | err ("%s:%s alloc for _HPP fail\n", __FUNCTION__, |
173 | return; | 78 | path_name); |
79 | return AE_NO_MEMORY; | ||
174 | } | 80 | } |
175 | status = acpi_evaluate_object(ab->handle, METHOD_NAME__HPP, NULL, &ret_buf); | 81 | status = acpi_evaluate_object(handle, METHOD_NAME__HPP, |
82 | NULL, &ret_buf); | ||
176 | if (ACPI_SUCCESS(status)) | 83 | if (ACPI_SUCCESS(status)) |
177 | break; | 84 | break; |
178 | default: | 85 | default: |
179 | if (ACPI_FAILURE(status)) { | 86 | if (ACPI_FAILURE(status)) { |
180 | err("acpi_shpchprm:%s _HPP fail=0x%x\n", path_name, status); | 87 | dbg("%s:%s _HPP fail=0x%x\n", __FUNCTION__, |
181 | return; | 88 | path_name, status); |
89 | return status; | ||
182 | } | 90 | } |
183 | } | 91 | } |
184 | 92 | ||
185 | ext_obj = (union acpi_object *) ret_buf.pointer; | 93 | ext_obj = (union acpi_object *) ret_buf.pointer; |
186 | if (ext_obj->type != ACPI_TYPE_PACKAGE) { | 94 | if (ext_obj->type != ACPI_TYPE_PACKAGE) { |
187 | err ("acpi_shpchprm:%s _HPP obj not a package\n", path_name); | 95 | err ("%s:%s _HPP obj not a package\n", __FUNCTION__, |
96 | path_name); | ||
97 | status = AE_ERROR; | ||
188 | goto free_and_return; | 98 | goto free_and_return; |
189 | } | 99 | } |
190 | 100 | ||
@@ -197,553 +107,41 @@ static void acpi_get__hpp ( struct acpi_bridge *ab) | |||
197 | nui[i] = (u8)ext_obj->integer.value; | 107 | nui[i] = (u8)ext_obj->integer.value; |
198 | break; | 108 | break; |
199 | default: | 109 | default: |
200 | err ("acpi_shpchprm:%s _HPP obj type incorrect\n", path_name); | 110 | err ("%s:%s _HPP obj type incorrect\n", __FUNCTION__, |
111 | path_name); | ||
112 | status = AE_ERROR; | ||
201 | goto free_and_return; | 113 | goto free_and_return; |
202 | } | 114 | } |
203 | } | 115 | } |
204 | 116 | ||
205 | ab->_hpp = kmalloc (sizeof (struct acpi__hpp), GFP_KERNEL); | 117 | hpp->cache_line_size = nui[0]; |
206 | if (!ab->_hpp) { | 118 | hpp->latency_timer = nui[1]; |
207 | err ("acpi_shpchprm:%s alloc for _HPP failed\n", path_name); | 119 | hpp->enable_serr = nui[2]; |
208 | goto free_and_return; | 120 | hpp->enable_perr = nui[3]; |
209 | } | ||
210 | memset(ab->_hpp, 0, sizeof(struct acpi__hpp)); | ||
211 | |||
212 | ab->_hpp->cache_line_size = nui[0]; | ||
213 | ab->_hpp->latency_timer = nui[1]; | ||
214 | ab->_hpp->enable_serr = nui[2]; | ||
215 | ab->_hpp->enable_perr = nui[3]; | ||
216 | 121 | ||
217 | dbg(" _HPP: cache_line_size=0x%x\n", ab->_hpp->cache_line_size); | 122 | dbg(" _HPP: cache_line_size=0x%x\n", hpp->cache_line_size); |
218 | dbg(" _HPP: latency timer =0x%x\n", ab->_hpp->latency_timer); | 123 | dbg(" _HPP: latency timer =0x%x\n", hpp->latency_timer); |
219 | dbg(" _HPP: enable SERR =0x%x\n", ab->_hpp->enable_serr); | 124 | dbg(" _HPP: enable SERR =0x%x\n", hpp->enable_serr); |
220 | dbg(" _HPP: enable PERR =0x%x\n", ab->_hpp->enable_perr); | 125 | dbg(" _HPP: enable PERR =0x%x\n", hpp->enable_perr); |
221 | 126 | ||
222 | free_and_return: | 127 | free_and_return: |
223 | kfree(ret_buf.pointer); | 128 | kfree(ret_buf.pointer); |
129 | return status; | ||
224 | } | 130 | } |
225 | 131 | ||
226 | static void acpi_run_oshp ( struct acpi_bridge *ab) | 132 | static void acpi_run_oshp(acpi_handle handle) |
227 | { | ||
228 | acpi_status status; | ||
229 | u8 *path_name = acpi_path_name(ab->handle); | ||
230 | |||
231 | /* run OSHP */ | ||
232 | status = acpi_evaluate_object(ab->handle, METHOD_NAME_OSHP, NULL, NULL); | ||
233 | if (ACPI_FAILURE(status)) { | ||
234 | err("acpi_pciehprm:%s OSHP fails=0x%x\n", path_name, status); | ||
235 | } else | ||
236 | dbg("acpi_pciehprm:%s OSHP passes =0x%x\n", path_name, status); | ||
237 | return; | ||
238 | } | ||
239 | |||
240 | /* find acpi_bridge downword from ab. */ | ||
241 | static struct acpi_bridge * | ||
242 | find_acpi_bridge_by_bus( | ||
243 | struct acpi_bridge *ab, | ||
244 | int seg, | ||
245 | int bus /* pdev->subordinate->number */ | ||
246 | ) | ||
247 | { | ||
248 | struct acpi_bridge *lab = NULL; | ||
249 | |||
250 | if (!ab) | ||
251 | return NULL; | ||
252 | |||
253 | if ((ab->bus == bus) && (ab->seg == seg)) | ||
254 | return ab; | ||
255 | |||
256 | if (ab->child) | ||
257 | lab = find_acpi_bridge_by_bus(ab->child, seg, bus); | ||
258 | |||
259 | if (!lab) | ||
260 | if (ab->next) | ||
261 | lab = find_acpi_bridge_by_bus(ab->next, seg, bus); | ||
262 | |||
263 | return lab; | ||
264 | } | ||
265 | |||
266 | /* | ||
267 | * Build a device tree of ACPI PCI Bridges | ||
268 | */ | ||
269 | static void shpchprm_acpi_register_a_bridge ( | ||
270 | struct acpi_bridge **head, | ||
271 | struct acpi_bridge *pab, /* parent bridge to which child bridge is added */ | ||
272 | struct acpi_bridge *cab /* child bridge to add */ | ||
273 | ) | ||
274 | { | ||
275 | struct acpi_bridge *lpab; | ||
276 | struct acpi_bridge *lcab; | ||
277 | |||
278 | lpab = find_acpi_bridge_by_bus(*head, pab->seg, pab->bus); | ||
279 | if (!lpab) { | ||
280 | if (!(pab->type & BRIDGE_TYPE_HOST)) | ||
281 | warn("PCI parent bridge s:b(%x:%x) not in list.\n", pab->seg, pab->bus); | ||
282 | pab->next = *head; | ||
283 | *head = pab; | ||
284 | lpab = pab; | ||
285 | } | ||
286 | |||
287 | if ((cab->type & BRIDGE_TYPE_HOST) && (pab == cab)) | ||
288 | return; | ||
289 | |||
290 | lcab = find_acpi_bridge_by_bus(*head, cab->seg, cab->bus); | ||
291 | if (lcab) { | ||
292 | if ((pab->bus != lcab->parent->bus) || (lcab->bus != cab->bus)) | ||
293 | err("PCI child bridge s:b(%x:%x) in list with diff parent.\n", cab->seg, cab->bus); | ||
294 | return; | ||
295 | } else | ||
296 | lcab = cab; | ||
297 | |||
298 | lcab->parent = lpab; | ||
299 | lcab->next = lpab->child; | ||
300 | lpab->child = lcab; | ||
301 | } | ||
302 | |||
303 | static acpi_status shpchprm_acpi_build_php_slots_callback( | ||
304 | acpi_handle handle, | ||
305 | u32 Level, | ||
306 | void *context, | ||
307 | void **retval | ||
308 | ) | ||
309 | { | 133 | { |
310 | ulong bus_num; | ||
311 | ulong seg_num; | ||
312 | ulong sun, adr; | ||
313 | ulong padr = 0; | ||
314 | acpi_handle phandle = NULL; | ||
315 | struct acpi_bridge *pab = (struct acpi_bridge *)context; | ||
316 | struct acpi_bridge *lab; | ||
317 | acpi_status status; | 134 | acpi_status status; |
318 | u8 *path_name = acpi_path_name(handle); | 135 | u8 *path_name = acpi_path_name(handle); |
319 | 136 | ||
320 | /* get _SUN */ | 137 | /* run OSHP */ |
321 | status = acpi_evaluate_integer(handle, METHOD_NAME__SUN, NULL, &sun); | 138 | status = acpi_evaluate_object(handle, METHOD_NAME_OSHP, NULL, NULL); |
322 | switch(status) { | ||
323 | case AE_NOT_FOUND: | ||
324 | return AE_OK; | ||
325 | default: | ||
326 | if (ACPI_FAILURE(status)) { | ||
327 | err("acpi_shpchprm:%s _SUN fail=0x%x\n", path_name, status); | ||
328 | return status; | ||
329 | } | ||
330 | } | ||
331 | |||
332 | /* get _ADR. _ADR must exist if _SUN exists */ | ||
333 | status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr); | ||
334 | if (ACPI_FAILURE(status)) { | ||
335 | err("acpi_shpchprm:%s _ADR fail=0x%x\n", path_name, status); | ||
336 | return status; | ||
337 | } | ||
338 | |||
339 | dbg("acpi_shpchprm:%s sun=0x%08x adr=0x%08x\n", path_name, (u32)sun, (u32)adr); | ||
340 | |||
341 | status = acpi_get_parent(handle, &phandle); | ||
342 | if (ACPI_FAILURE(status)) { | 139 | if (ACPI_FAILURE(status)) { |
343 | err("acpi_shpchprm:%s get_parent fail=0x%x\n", path_name, status); | 140 | err("%s:%s OSHP fails=0x%x\n", __FUNCTION__, path_name, |
344 | return (status); | 141 | status); |
345 | } | ||
346 | |||
347 | bus_num = pab->bus; | ||
348 | seg_num = pab->seg; | ||
349 | |||
350 | if (pab->bus == bus_num) { | ||
351 | lab = pab; | ||
352 | } else { | 142 | } else { |
353 | dbg("WARN: pab is not parent\n"); | 143 | dbg("%s:%s OSHP passes\n", __FUNCTION__, path_name); |
354 | lab = find_acpi_bridge_by_bus(pab, seg_num, bus_num); | ||
355 | if (!lab) { | ||
356 | dbg("acpi_shpchprm: alloc new P2P bridge(%x) for sun(%08x)\n", (u32)bus_num, (u32)sun); | ||
357 | lab = (struct acpi_bridge *)kmalloc(sizeof(struct acpi_bridge), GFP_KERNEL); | ||
358 | if (!lab) { | ||
359 | err("acpi_shpchprm: alloc for ab fail\n"); | ||
360 | return AE_NO_MEMORY; | ||
361 | } | ||
362 | memset(lab, 0, sizeof(struct acpi_bridge)); | ||
363 | |||
364 | lab->handle = phandle; | ||
365 | lab->pbus = pab->bus; | ||
366 | lab->pdevice = (int)(padr >> 16) & 0xffff; | ||
367 | lab->pfunction = (int)(padr & 0xffff); | ||
368 | lab->bus = (int)bus_num; | ||
369 | lab->scanned = 0; | ||
370 | lab->type = BRIDGE_TYPE_P2P; | ||
371 | |||
372 | shpchprm_acpi_register_a_bridge (&acpi_bridges_head, pab, lab); | ||
373 | } else | ||
374 | dbg("acpi_shpchprm: found P2P bridge(%x) for sun(%08x)\n", (u32)bus_num, (u32)sun); | ||
375 | } | ||
376 | |||
377 | acpi_add_slot_to_php_slots(lab, (int)bus_num, handle, (u32)adr, (u32)sun); | ||
378 | return (status); | ||
379 | } | ||
380 | |||
381 | static int shpchprm_acpi_build_php_slots( | ||
382 | struct acpi_bridge *ab, | ||
383 | u32 depth | ||
384 | ) | ||
385 | { | ||
386 | acpi_status status; | ||
387 | u8 *path_name = acpi_path_name(ab->handle); | ||
388 | |||
389 | /* Walk down this pci bridge to get _SUNs if any behind P2P */ | ||
390 | status = acpi_walk_namespace ( ACPI_TYPE_DEVICE, | ||
391 | ab->handle, | ||
392 | depth, | ||
393 | shpchprm_acpi_build_php_slots_callback, | ||
394 | ab, | ||
395 | NULL ); | ||
396 | if (ACPI_FAILURE(status)) { | ||
397 | dbg("acpi_shpchprm:%s walk for _SUN on pci bridge seg:bus(%x:%x) fail=0x%x\n", path_name, ab->seg, ab->bus, status); | ||
398 | return -1; | ||
399 | } | ||
400 | |||
401 | return 0; | ||
402 | } | ||
403 | |||
404 | static void build_a_bridge( | ||
405 | struct acpi_bridge *pab, | ||
406 | struct acpi_bridge *ab | ||
407 | ) | ||
408 | { | ||
409 | u8 *path_name = acpi_path_name(ab->handle); | ||
410 | |||
411 | shpchprm_acpi_register_a_bridge (&acpi_bridges_head, pab, ab); | ||
412 | |||
413 | switch (ab->type) { | ||
414 | case BRIDGE_TYPE_HOST: | ||
415 | dbg("acpi_shpchprm: Registered PCI HOST Bridge(%02x) on s:b:d:f(%02x:%02x:%02x:%02x) [%s]\n", | ||
416 | ab->bus, ab->seg, ab->pbus, ab->pdevice, ab->pfunction, path_name); | ||
417 | break; | ||
418 | case BRIDGE_TYPE_P2P: | ||
419 | dbg("acpi_shpchprm: Registered PCI P2P Bridge(%02x-%02x) on s:b:d:f(%02x:%02x:%02x:%02x) [%s]\n", | ||
420 | ab->pbus, ab->bus, ab->seg, ab->pbus, ab->pdevice, ab->pfunction, path_name); | ||
421 | break; | ||
422 | }; | ||
423 | |||
424 | /* build any immediate PHP slots under this pci bridge */ | ||
425 | shpchprm_acpi_build_php_slots(ab, 1); | ||
426 | } | ||
427 | |||
428 | static struct acpi_bridge * add_p2p_bridge( | ||
429 | acpi_handle handle, | ||
430 | struct acpi_bridge *pab, /* parent */ | ||
431 | ulong adr | ||
432 | ) | ||
433 | { | ||
434 | struct acpi_bridge *ab; | ||
435 | struct pci_dev *pdev; | ||
436 | ulong devnum, funcnum; | ||
437 | u8 *path_name = acpi_path_name(handle); | ||
438 | |||
439 | ab = (struct acpi_bridge *) kmalloc (sizeof(struct acpi_bridge), GFP_KERNEL); | ||
440 | if (!ab) { | ||
441 | err("acpi_shpchprm: alloc for ab fail\n"); | ||
442 | return NULL; | ||
443 | } | ||
444 | memset(ab, 0, sizeof(struct acpi_bridge)); | ||
445 | |||
446 | devnum = (adr >> 16) & 0xffff; | ||
447 | funcnum = adr & 0xffff; | ||
448 | |||
449 | pdev = pci_find_slot(pab->bus, PCI_DEVFN(devnum, funcnum)); | ||
450 | if (!pdev || !pdev->subordinate) { | ||
451 | err("acpi_shpchprm:%s is not a P2P Bridge\n", path_name); | ||
452 | kfree(ab); | ||
453 | return NULL; | ||
454 | } | ||
455 | |||
456 | ab->handle = handle; | ||
457 | ab->seg = pab->seg; | ||
458 | ab->pbus = pab->bus; /* or pdev->bus->number */ | ||
459 | ab->pdevice = devnum; /* or PCI_SLOT(pdev->devfn) */ | ||
460 | ab->pfunction = funcnum; /* or PCI_FUNC(pdev->devfn) */ | ||
461 | ab->bus = pdev->subordinate->number; | ||
462 | ab->scanned = 0; | ||
463 | ab->type = BRIDGE_TYPE_P2P; | ||
464 | |||
465 | dbg("acpi_shpchprm: P2P(%x-%x) on pci=b:d:f(%x:%x:%x) acpi=b:d:f(%x:%x:%x) [%s]\n", | ||
466 | pab->bus, ab->bus, pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), | ||
467 | pab->bus, (u32)devnum, (u32)funcnum, path_name); | ||
468 | |||
469 | build_a_bridge(pab, ab); | ||
470 | |||
471 | return ab; | ||
472 | } | ||
473 | |||
474 | static acpi_status scan_p2p_bridge( | ||
475 | acpi_handle handle, | ||
476 | u32 Level, | ||
477 | void *context, | ||
478 | void **retval | ||
479 | ) | ||
480 | { | ||
481 | struct acpi_bridge *pab = (struct acpi_bridge *)context; | ||
482 | struct acpi_bridge *ab; | ||
483 | acpi_status status; | ||
484 | ulong adr = 0; | ||
485 | u8 *path_name = acpi_path_name(handle); | ||
486 | ulong devnum, funcnum; | ||
487 | struct pci_dev *pdev; | ||
488 | |||
489 | /* get device, function */ | ||
490 | status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr); | ||
491 | if (ACPI_FAILURE(status)) { | ||
492 | if (status != AE_NOT_FOUND) | ||
493 | err("acpi_shpchprm:%s _ADR fail=0x%x\n", path_name, status); | ||
494 | return AE_OK; | ||
495 | } | 144 | } |
496 | |||
497 | devnum = (adr >> 16) & 0xffff; | ||
498 | funcnum = adr & 0xffff; | ||
499 | |||
500 | pdev = pci_find_slot(pab->bus, PCI_DEVFN(devnum, funcnum)); | ||
501 | if (!pdev) | ||
502 | return AE_OK; | ||
503 | if (!pdev->subordinate) | ||
504 | return AE_OK; | ||
505 | |||
506 | ab = add_p2p_bridge(handle, pab, adr); | ||
507 | if (ab) { | ||
508 | status = acpi_walk_namespace ( ACPI_TYPE_DEVICE, | ||
509 | handle, | ||
510 | (u32)1, | ||
511 | scan_p2p_bridge, | ||
512 | ab, | ||
513 | NULL); | ||
514 | if (ACPI_FAILURE(status)) | ||
515 | dbg("acpi_shpchprm:%s find_p2p fail=0x%x\n", path_name, status); | ||
516 | } | ||
517 | |||
518 | return AE_OK; | ||
519 | } | ||
520 | |||
521 | static struct acpi_bridge * add_host_bridge( | ||
522 | acpi_handle handle, | ||
523 | ulong segnum, | ||
524 | ulong busnum | ||
525 | ) | ||
526 | { | ||
527 | ulong adr = 0; | ||
528 | acpi_status status; | ||
529 | struct acpi_bridge *ab; | ||
530 | u8 *path_name = acpi_path_name(handle); | ||
531 | |||
532 | /* get device, function: host br adr is always 0000 though. */ | ||
533 | status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr); | ||
534 | if (ACPI_FAILURE(status)) { | ||
535 | err("acpi_shpchprm:%s _ADR fail=0x%x\n", path_name, status); | ||
536 | return NULL; | ||
537 | } | ||
538 | dbg("acpi_shpchprm: ROOT PCI seg(0x%x)bus(0x%x)dev(0x%x)func(0x%x) [%s]\n", (u32)segnum, (u32)busnum, | ||
539 | (u32)(adr >> 16) & 0xffff, (u32)adr & 0xffff, path_name); | ||
540 | |||
541 | ab = (struct acpi_bridge *) kmalloc (sizeof(struct acpi_bridge), GFP_KERNEL); | ||
542 | if (!ab) { | ||
543 | err("acpi_shpchprm: alloc for ab fail\n"); | ||
544 | return NULL; | ||
545 | } | ||
546 | memset(ab, 0, sizeof(struct acpi_bridge)); | ||
547 | |||
548 | ab->handle = handle; | ||
549 | ab->seg = (int)segnum; | ||
550 | ab->bus = ab->pbus = (int)busnum; | ||
551 | ab->pdevice = (int)(adr >> 16) & 0xffff; | ||
552 | ab->pfunction = (int)(adr & 0xffff); | ||
553 | ab->scanned = 0; | ||
554 | ab->type = BRIDGE_TYPE_HOST; | ||
555 | |||
556 | build_a_bridge(ab, ab); | ||
557 | |||
558 | return ab; | ||
559 | } | ||
560 | |||
561 | static acpi_status acpi_scan_from_root_pci_callback ( | ||
562 | acpi_handle handle, | ||
563 | u32 Level, | ||
564 | void *context, | ||
565 | void **retval | ||
566 | ) | ||
567 | { | ||
568 | ulong segnum = 0; | ||
569 | ulong busnum = 0; | ||
570 | acpi_status status; | ||
571 | struct acpi_bridge *ab; | ||
572 | u8 *path_name = acpi_path_name(handle); | ||
573 | |||
574 | /* get bus number of this pci root bridge */ | ||
575 | status = acpi_evaluate_integer(handle, METHOD_NAME__SEG, NULL, &segnum); | ||
576 | if (ACPI_FAILURE(status)) { | ||
577 | if (status != AE_NOT_FOUND) { | ||
578 | err("acpi_shpchprm:%s evaluate _SEG fail=0x%x\n", path_name, status); | ||
579 | return status; | ||
580 | } | ||
581 | segnum = 0; | ||
582 | } | ||
583 | |||
584 | /* get bus number of this pci root bridge */ | ||
585 | status = acpi_evaluate_integer(handle, METHOD_NAME__BBN, NULL, &busnum); | ||
586 | if (ACPI_FAILURE(status)) { | ||
587 | err("acpi_shpchprm:%s evaluate _BBN fail=0x%x\n", path_name, status); | ||
588 | return (status); | ||
589 | } | ||
590 | |||
591 | ab = add_host_bridge(handle, segnum, busnum); | ||
592 | if (ab) { | ||
593 | status = acpi_walk_namespace ( ACPI_TYPE_DEVICE, | ||
594 | handle, | ||
595 | 1, | ||
596 | scan_p2p_bridge, | ||
597 | ab, | ||
598 | NULL); | ||
599 | if (ACPI_FAILURE(status)) | ||
600 | dbg("acpi_shpchprm:%s find_p2p fail=0x%x\n", path_name, status); | ||
601 | } | ||
602 | |||
603 | return AE_OK; | ||
604 | } | ||
605 | |||
606 | static int shpchprm_acpi_scan_pci (void) | ||
607 | { | ||
608 | acpi_status status; | ||
609 | |||
610 | /* | ||
611 | * TBD: traverse LDM device tree with the help of | ||
612 | * unified ACPI augmented for php device population. | ||
613 | */ | ||
614 | status = acpi_get_devices ( PCI_ROOT_HID_STRING, | ||
615 | acpi_scan_from_root_pci_callback, | ||
616 | NULL, | ||
617 | NULL ); | ||
618 | if (ACPI_FAILURE(status)) { | ||
619 | err("acpi_shpchprm:get_device PCI ROOT HID fail=0x%x\n", status); | ||
620 | return -1; | ||
621 | } | ||
622 | |||
623 | return 0; | ||
624 | } | ||
625 | |||
626 | int shpchprm_init(enum php_ctlr_type ctlr_type) | ||
627 | { | ||
628 | int rc; | ||
629 | |||
630 | if (ctlr_type != PCI) | ||
631 | return -ENODEV; | ||
632 | |||
633 | dbg("shpchprm ACPI init <enter>\n"); | ||
634 | acpi_bridges_head = NULL; | ||
635 | |||
636 | /* construct PCI bus:device tree of acpi_handles */ | ||
637 | rc = shpchprm_acpi_scan_pci(); | ||
638 | if (rc) | ||
639 | return rc; | ||
640 | |||
641 | dbg("shpchprm ACPI init %s\n", (rc)?"fail":"success"); | ||
642 | return rc; | ||
643 | } | ||
644 | |||
645 | static void free_a_slot(struct acpi_php_slot *aps) | ||
646 | { | ||
647 | 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); | ||
648 | |||
649 | kfree(aps); | ||
650 | } | ||
651 | |||
652 | static void free_a_bridge( struct acpi_bridge *ab) | ||
653 | { | ||
654 | struct acpi_php_slot *aps, *next; | ||
655 | |||
656 | switch (ab->type) { | ||
657 | case BRIDGE_TYPE_HOST: | ||
658 | dbg("Free ACPI PCI HOST Bridge(%x) [%s] on s:b:d:f(%x:%x:%x:%x)\n", | ||
659 | ab->bus, acpi_path_name(ab->handle), ab->seg, ab->pbus, ab->pdevice, ab->pfunction); | ||
660 | break; | ||
661 | case BRIDGE_TYPE_P2P: | ||
662 | dbg("Free ACPI PCI P2P Bridge(%x-%x) [%s] on s:b:d:f(%x:%x:%x:%x)\n", | ||
663 | ab->pbus, ab->bus, acpi_path_name(ab->handle), ab->seg, ab->pbus, ab->pdevice, ab->pfunction); | ||
664 | break; | ||
665 | }; | ||
666 | |||
667 | /* free slots first */ | ||
668 | for (aps = ab->slots; aps; aps = next) { | ||
669 | next = aps->next; | ||
670 | free_a_slot(aps); | ||
671 | } | ||
672 | |||
673 | kfree(ab); | ||
674 | } | ||
675 | |||
676 | static void shpchprm_free_bridges ( struct acpi_bridge *ab) | ||
677 | { | ||
678 | if (!ab) | ||
679 | return; | ||
680 | |||
681 | if (ab->child) | ||
682 | shpchprm_free_bridges (ab->child); | ||
683 | |||
684 | if (ab->next) | ||
685 | shpchprm_free_bridges (ab->next); | ||
686 | |||
687 | free_a_bridge(ab); | ||
688 | } | ||
689 | |||
690 | void shpchprm_cleanup(void) | ||
691 | { | ||
692 | shpchprm_free_bridges (acpi_bridges_head); | ||
693 | } | ||
694 | |||
695 | static int get_number_of_slots ( | ||
696 | struct acpi_bridge *ab, | ||
697 | int selfonly | ||
698 | ) | ||
699 | { | ||
700 | struct acpi_php_slot *aps; | ||
701 | int prev_slot = -1; | ||
702 | int slot_num = 0; | ||
703 | |||
704 | for ( aps = ab->slots; aps; aps = aps->next) | ||
705 | if (aps->dev != prev_slot) { | ||
706 | prev_slot = aps->dev; | ||
707 | slot_num++; | ||
708 | } | ||
709 | |||
710 | if (ab->child) | ||
711 | slot_num += get_number_of_slots (ab->child, 0); | ||
712 | |||
713 | if (selfonly) | ||
714 | return slot_num; | ||
715 | |||
716 | if (ab->next) | ||
717 | slot_num += get_number_of_slots (ab->next, 0); | ||
718 | |||
719 | return slot_num; | ||
720 | } | ||
721 | |||
722 | static struct acpi_php_slot * get_acpi_slot ( | ||
723 | struct acpi_bridge *ab, | ||
724 | u32 sun | ||
725 | ) | ||
726 | { | ||
727 | struct acpi_php_slot *aps = NULL; | ||
728 | |||
729 | for ( aps = ab->slots; aps; aps = aps->next) | ||
730 | if (aps->sun == sun) | ||
731 | return aps; | ||
732 | |||
733 | if (!aps && ab->child) { | ||
734 | aps = (struct acpi_php_slot *)get_acpi_slot (ab->child, sun); | ||
735 | if (aps) | ||
736 | return aps; | ||
737 | } | ||
738 | |||
739 | if (!aps && ab->next) { | ||
740 | aps = (struct acpi_php_slot *)get_acpi_slot (ab->next, sun); | ||
741 | if (aps) | ||
742 | return aps; | ||
743 | } | ||
744 | |||
745 | return aps; | ||
746 | |||
747 | } | 145 | } |
748 | 146 | ||
749 | int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum) | 147 | int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum) |
@@ -755,108 +153,40 @@ int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busn | |||
755 | return 0; | 153 | return 0; |
756 | } | 154 | } |
757 | 155 | ||
758 | int shpchprm_set_hpp( | 156 | void get_hp_hw_control_from_firmware(struct pci_dev *dev) |
759 | struct controller *ctrl, | ||
760 | struct pci_func *func, | ||
761 | u8 card_type | ||
762 | ) | ||
763 | { | 157 | { |
764 | struct acpi_bridge *ab; | 158 | /* |
765 | struct pci_bus lpci_bus, *pci_bus; | 159 | * OSHP is an optional ACPI firmware control method. If present, |
766 | int rc = 0; | 160 | * we need to run it to inform BIOS that we will control SHPC |
767 | unsigned int devfn; | 161 | * hardware from now on. |
768 | u8 cls= 0x08; /* default cache line size */ | 162 | */ |
769 | u8 lt = 0x40; /* default latency timer */ | 163 | acpi_handle handle = DEVICE_ACPI_HANDLE(&(dev->dev)); |
770 | u8 ep = 0; | 164 | if (!handle) |
771 | u8 es = 0; | 165 | return; |
772 | 166 | acpi_run_oshp(handle); | |
773 | memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus)); | ||
774 | pci_bus = &lpci_bus; | ||
775 | pci_bus->number = func->bus; | ||
776 | devfn = PCI_DEVFN(func->device, func->function); | ||
777 | |||
778 | ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->slot_bus); | ||
779 | |||
780 | if (ab) { | ||
781 | if (ab->_hpp) { | ||
782 | lt = (u8)ab->_hpp->latency_timer; | ||
783 | cls = (u8)ab->_hpp->cache_line_size; | ||
784 | ep = (u8)ab->_hpp->enable_perr; | ||
785 | es = (u8)ab->_hpp->enable_serr; | ||
786 | } else | ||
787 | dbg("_hpp: no _hpp for B/D/F=%#x/%#x/%#x. use default value\n", func->bus, func->device, func->function); | ||
788 | } else | ||
789 | dbg("_hpp: no acpi bridge for B/D/F = %#x/%#x/%#x. use default value\n", func->bus, func->device, func->function); | ||
790 | |||
791 | |||
792 | if (card_type == PCI_HEADER_TYPE_BRIDGE) { | ||
793 | /* set subordinate Latency Timer */ | ||
794 | rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_SEC_LATENCY_TIMER, lt); | ||
795 | } | ||
796 | |||
797 | /* set base Latency Timer */ | ||
798 | rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_LATENCY_TIMER, lt); | ||
799 | dbg(" set latency timer =0x%02x: %x\n", lt, rc); | ||
800 | |||
801 | rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_CACHE_LINE_SIZE, cls); | ||
802 | dbg(" set cache_line_size=0x%02x: %x\n", cls, rc); | ||
803 | |||
804 | return rc; | ||
805 | } | 167 | } |
806 | 168 | ||
807 | void shpchprm_enable_card( | 169 | void get_hp_params_from_firmware(struct pci_dev *dev, |
808 | struct controller *ctrl, | 170 | struct hotplug_params *hpp) |
809 | struct pci_func *func, | ||
810 | u8 card_type) | ||
811 | { | 171 | { |
812 | u16 command, cmd, bcommand, bcmd; | 172 | acpi_status status = AE_NOT_FOUND; |
813 | struct pci_bus lpci_bus, *pci_bus; | 173 | struct pci_dev *pdev = dev; |
814 | struct acpi_bridge *ab; | ||
815 | unsigned int devfn; | ||
816 | int rc; | ||
817 | |||
818 | memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus)); | ||
819 | pci_bus = &lpci_bus; | ||
820 | pci_bus->number = func->bus; | ||
821 | devfn = PCI_DEVFN(func->device, func->function); | ||
822 | |||
823 | rc = pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &command); | ||
824 | |||
825 | if (card_type == PCI_HEADER_TYPE_BRIDGE) { | ||
826 | rc = pci_bus_read_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, &bcommand); | ||
827 | } | ||
828 | |||
829 | cmd = command = command | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE | ||
830 | | PCI_COMMAND_IO | PCI_COMMAND_MEMORY; | ||
831 | bcmd = bcommand = bcommand | PCI_BRIDGE_CTL_NO_ISA; | ||
832 | 174 | ||
833 | ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->slot_bus); | 175 | /* |
834 | if (ab) { | 176 | * _HPP settings apply to all child buses, until another _HPP is |
835 | if (ab->_hpp) { | 177 | * encountered. If we don't find an _HPP for the input pci dev, |
836 | if (ab->_hpp->enable_perr) { | 178 | * look for it in the parent device scope since that would apply to |
837 | command |= PCI_COMMAND_PARITY; | 179 | * this pci dev. If we don't find any _HPP, use hardcoded defaults |
838 | bcommand |= PCI_BRIDGE_CTL_PARITY; | 180 | */ |
839 | } else { | 181 | while (pdev && (ACPI_FAILURE(status))) { |
840 | command &= ~PCI_COMMAND_PARITY; | 182 | acpi_handle handle = DEVICE_ACPI_HANDLE(&(pdev->dev)); |
841 | bcommand &= ~PCI_BRIDGE_CTL_PARITY; | 183 | if (!handle) |
842 | } | 184 | break; |
843 | if (ab->_hpp->enable_serr) { | 185 | status = acpi_run_hpp(handle, hpp); |
844 | command |= PCI_COMMAND_SERR; | 186 | if (!(pdev->bus->parent)) |
845 | bcommand |= PCI_BRIDGE_CTL_SERR; | 187 | break; |
846 | } else { | 188 | /* Check if a parent object supports _HPP */ |
847 | command &= ~PCI_COMMAND_SERR; | 189 | pdev = pdev->bus->parent->self; |
848 | bcommand &= ~PCI_BRIDGE_CTL_SERR; | ||
849 | } | ||
850 | } else | ||
851 | dbg("no _hpp for B/D/F = %#x/%#x/%#x.\n", func->bus, func->device, func->function); | ||
852 | } else | ||
853 | dbg("no acpi bridge for B/D/F = %#x/%#x/%#x.\n", func->bus, func->device, func->function); | ||
854 | |||
855 | if (command != cmd) { | ||
856 | rc = pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command); | ||
857 | } | ||
858 | if ((card_type == PCI_HEADER_TYPE_BRIDGE) && (bcommand != bcmd)) { | ||
859 | rc = pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, bcommand); | ||
860 | } | 190 | } |
861 | } | 191 | } |
862 | 192 | ||
diff --git a/drivers/pci/hotplug/shpchprm_legacy.c b/drivers/pci/hotplug/shpchprm_legacy.c index 6c27debe9522..cfc6092e2afd 100644 --- a/drivers/pci/hotplug/shpchprm_legacy.c +++ b/drivers/pci/hotplug/shpchprm_legacy.c | |||
@@ -37,10 +37,6 @@ | |||
37 | #include "shpchp.h" | 37 | #include "shpchp.h" |
38 | #include "shpchprm.h" | 38 | #include "shpchprm.h" |
39 | 39 | ||
40 | void shpchprm_cleanup(void) | ||
41 | { | ||
42 | } | ||
43 | |||
44 | int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum) | 40 | int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum) |
45 | { | 41 | { |
46 | int offset = devnum - ctrl->slot_device_offset; | 42 | int offset = devnum - ctrl->slot_device_offset; |
@@ -49,97 +45,14 @@ int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busn | |||
49 | return 0; | 45 | return 0; |
50 | } | 46 | } |
51 | 47 | ||
52 | int shpchprm_set_hpp( | 48 | void get_hp_params_from_firmware(struct pci_dev *dev, |
53 | struct controller *ctrl, | 49 | struct hotplug_params *hpp) |
54 | struct pci_func *func, | ||
55 | u8 card_type) | ||
56 | { | 50 | { |
57 | u32 rc; | 51 | return; |
58 | u8 temp_byte; | ||
59 | struct pci_bus lpci_bus, *pci_bus; | ||
60 | unsigned int devfn; | ||
61 | memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus)); | ||
62 | pci_bus = &lpci_bus; | ||
63 | pci_bus->number = func->bus; | ||
64 | devfn = PCI_DEVFN(func->device, func->function); | ||
65 | |||
66 | temp_byte = 0x40; /* hard coded value for LT */ | ||
67 | if (card_type == PCI_HEADER_TYPE_BRIDGE) { | ||
68 | /* set subordinate Latency Timer */ | ||
69 | rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_SEC_LATENCY_TIMER, temp_byte); | ||
70 | if (rc) { | ||
71 | dbg("%s: set secondary LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, | ||
72 | func->device, func->function); | ||
73 | return rc; | ||
74 | } | ||
75 | } | ||
76 | |||
77 | /* set base Latency Timer */ | ||
78 | rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_LATENCY_TIMER, temp_byte); | ||
79 | if (rc) { | ||
80 | dbg("%s: set LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, func->device, func->function); | ||
81 | return rc; | ||
82 | } | ||
83 | |||
84 | /* set Cache Line size */ | ||
85 | temp_byte = 0x08; /* hard coded value for CLS */ | ||
86 | rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_CACHE_LINE_SIZE, temp_byte); | ||
87 | if (rc) { | ||
88 | dbg("%s: set CLS error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, func->device, func->function); | ||
89 | } | ||
90 | |||
91 | /* set enable_perr */ | ||
92 | /* set enable_serr */ | ||
93 | |||
94 | return rc; | ||
95 | } | 52 | } |
96 | 53 | ||
97 | void shpchprm_enable_card( | 54 | void get_hp_hw_control_from_firmware(struct pci_dev *dev) |
98 | struct controller *ctrl, | ||
99 | struct pci_func *func, | ||
100 | u8 card_type) | ||
101 | { | 55 | { |
102 | u16 command, bcommand; | 56 | return; |
103 | struct pci_bus lpci_bus, *pci_bus; | ||
104 | unsigned int devfn; | ||
105 | int rc; | ||
106 | |||
107 | memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus)); | ||
108 | pci_bus = &lpci_bus; | ||
109 | pci_bus->number = func->bus; | ||
110 | devfn = PCI_DEVFN(func->device, func->function); | ||
111 | |||
112 | rc = pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &command); | ||
113 | command |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR | ||
114 | | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE | ||
115 | | PCI_COMMAND_IO | PCI_COMMAND_MEMORY; | ||
116 | rc = pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command); | ||
117 | |||
118 | if (card_type == PCI_HEADER_TYPE_BRIDGE) { | ||
119 | rc = pci_bus_read_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, &bcommand); | ||
120 | bcommand |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR | ||
121 | | PCI_BRIDGE_CTL_NO_ISA; | ||
122 | rc = pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, bcommand); | ||
123 | } | ||
124 | } | ||
125 | |||
126 | static int legacy_shpchprm_init_pci(void) | ||
127 | { | ||
128 | return 0; | ||
129 | } | 57 | } |
130 | 58 | ||
131 | int shpchprm_init(enum php_ctlr_type ctrl_type) | ||
132 | { | ||
133 | int retval; | ||
134 | |||
135 | switch (ctrl_type) { | ||
136 | case PCI: | ||
137 | retval = legacy_shpchprm_init_pci(); | ||
138 | break; | ||
139 | default: | ||
140 | retval = -ENODEV; | ||
141 | break; | ||
142 | } | ||
143 | |||
144 | return retval; | ||
145 | } | ||
diff --git a/drivers/pci/hotplug/shpchprm_nonacpi.c b/drivers/pci/hotplug/shpchprm_nonacpi.c index 9d4ccae5f78e..f36c188c23eb 100644 --- a/drivers/pci/hotplug/shpchprm_nonacpi.c +++ b/drivers/pci/hotplug/shpchprm_nonacpi.c | |||
@@ -37,11 +37,6 @@ | |||
37 | #include "shpchp.h" | 37 | #include "shpchp.h" |
38 | #include "shpchprm.h" | 38 | #include "shpchprm.h" |
39 | 39 | ||
40 | void shpchprm_cleanup(void) | ||
41 | { | ||
42 | return; | ||
43 | } | ||
44 | |||
45 | int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum) | 40 | int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum) |
46 | { | 41 | { |
47 | int offset = devnum - ctrl->slot_device_offset; | 42 | int offset = devnum - ctrl->slot_device_offset; |
@@ -51,106 +46,13 @@ int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busn | |||
51 | return 0; | 46 | return 0; |
52 | } | 47 | } |
53 | 48 | ||
54 | int shpchprm_set_hpp( | 49 | void get_hp_params_from_firmware(struct pci_dev *dev, |
55 | struct controller *ctrl, | 50 | struct hotplug_params *hpp) |
56 | struct pci_func *func, | ||
57 | u8 card_type) | ||
58 | { | ||
59 | u32 rc; | ||
60 | u8 temp_byte; | ||
61 | struct pci_bus lpci_bus, *pci_bus; | ||
62 | unsigned int devfn; | ||
63 | memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus)); | ||
64 | pci_bus = &lpci_bus; | ||
65 | pci_bus->number = func->bus; | ||
66 | devfn = PCI_DEVFN(func->device, func->function); | ||
67 | |||
68 | temp_byte = 0x40; /* hard coded value for LT */ | ||
69 | if (card_type == PCI_HEADER_TYPE_BRIDGE) { | ||
70 | /* set subordinate Latency Timer */ | ||
71 | rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_SEC_LATENCY_TIMER, temp_byte); | ||
72 | |||
73 | if (rc) { | ||
74 | dbg("%s: set secondary LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, | ||
75 | func->device, func->function); | ||
76 | return rc; | ||
77 | } | ||
78 | } | ||
79 | |||
80 | /* set base Latency Timer */ | ||
81 | rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_LATENCY_TIMER, temp_byte); | ||
82 | |||
83 | if (rc) { | ||
84 | dbg("%s: set LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, func->device, func->function); | ||
85 | return rc; | ||
86 | } | ||
87 | |||
88 | /* set Cache Line size */ | ||
89 | temp_byte = 0x08; /* hard coded value for CLS */ | ||
90 | |||
91 | rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_CACHE_LINE_SIZE, temp_byte); | ||
92 | |||
93 | if (rc) { | ||
94 | dbg("%s: set CLS error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, func->device, func->function); | ||
95 | } | ||
96 | |||
97 | /* set enable_perr */ | ||
98 | /* set enable_serr */ | ||
99 | |||
100 | return rc; | ||
101 | } | ||
102 | |||
103 | void shpchprm_enable_card( | ||
104 | struct controller *ctrl, | ||
105 | struct pci_func *func, | ||
106 | u8 card_type) | ||
107 | { | 51 | { |
108 | u16 command, bcommand; | 52 | return; |
109 | struct pci_bus lpci_bus, *pci_bus; | ||
110 | unsigned int devfn; | ||
111 | int rc; | ||
112 | |||
113 | memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus)); | ||
114 | pci_bus = &lpci_bus; | ||
115 | pci_bus->number = func->bus; | ||
116 | devfn = PCI_DEVFN(func->device, func->function); | ||
117 | |||
118 | rc = pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &command); | ||
119 | |||
120 | command |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR | ||
121 | | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE | ||
122 | | PCI_COMMAND_IO | PCI_COMMAND_MEMORY; | ||
123 | |||
124 | rc = pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command); | ||
125 | |||
126 | if (card_type == PCI_HEADER_TYPE_BRIDGE) { | ||
127 | |||
128 | rc = pci_bus_read_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, &bcommand); | ||
129 | |||
130 | bcommand |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR | ||
131 | | PCI_BRIDGE_CTL_NO_ISA; | ||
132 | |||
133 | rc = pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, bcommand); | ||
134 | } | ||
135 | } | ||
136 | |||
137 | static int legacy_shpchprm_init_pci(void) | ||
138 | { | ||
139 | return 0; | ||
140 | } | 53 | } |
141 | 54 | ||
142 | int shpchprm_init(enum php_ctlr_type ctrl_type) | 55 | void get_hp_hw_control_from_firmware(struct pci_dev *dev) |
143 | { | 56 | { |
144 | int retval; | 57 | return; |
145 | |||
146 | switch (ctrl_type) { | ||
147 | case PCI: | ||
148 | retval = legacy_shpchprm_init_pci(); | ||
149 | break; | ||
150 | default: | ||
151 | retval = -ENODEV; | ||
152 | break; | ||
153 | } | ||
154 | |||
155 | return retval; | ||
156 | } | 58 | } |