diff options
-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 | } |