Commit 8720d27dabf580278a7719fa8b5783d9878e2d42
Committed by
Jesse Barnes
1 parent
e2d4304b7d
Exists in
master
and in
7 other branches
PCI: pciehp: remove slot_list field
Since PCIe downstream port has only one slot at most, we don't need 'slot_list' linked list to manage multiple slots under the port. Acked-by: Alex Chiang <achiang@hp.com> Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Showing 4 changed files with 76 additions and 97 deletions Inline Diff
drivers/pci/hotplug/pciehp.h
1 | /* | 1 | /* |
2 | * PCI Express Hot Plug Controller Driver | 2 | * PCI Express Hot Plug Controller Driver |
3 | * | 3 | * |
4 | * Copyright (C) 1995,2001 Compaq Computer Corporation | 4 | * Copyright (C) 1995,2001 Compaq Computer Corporation |
5 | * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) | 5 | * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) |
6 | * Copyright (C) 2001 IBM Corp. | 6 | * Copyright (C) 2001 IBM Corp. |
7 | * Copyright (C) 2003-2004 Intel Corporation | 7 | * Copyright (C) 2003-2004 Intel Corporation |
8 | * | 8 | * |
9 | * All rights reserved. | 9 | * All rights reserved. |
10 | * | 10 | * |
11 | * This program is free software; you can redistribute it and/or modify | 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 | 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 | 13 | * the Free Software Foundation; either version 2 of the License, or (at |
14 | * your option) any later version. | 14 | * your option) any later version. |
15 | * | 15 | * |
16 | * This program is distributed in the hope that it will be useful, but | 16 | * This program is distributed in the hope that it will be useful, but |
17 | * WITHOUT ANY WARRANTY; without even the implied warranty of | 17 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
18 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | 18 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or |
19 | * NON INFRINGEMENT. See the GNU General Public License for more | 19 | * NON INFRINGEMENT. See the GNU General Public License for more |
20 | * details. | 20 | * details. |
21 | * | 21 | * |
22 | * You should have received a copy of the GNU General Public License | 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 | 23 | * along with this program; if not, write to the Free Software |
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
25 | * | 25 | * |
26 | * Send feedback to <greg@kroah.com>, <kristen.c.accardi@intel.com> | 26 | * Send feedback to <greg@kroah.com>, <kristen.c.accardi@intel.com> |
27 | * | 27 | * |
28 | */ | 28 | */ |
29 | #ifndef _PCIEHP_H | 29 | #ifndef _PCIEHP_H |
30 | #define _PCIEHP_H | 30 | #define _PCIEHP_H |
31 | 31 | ||
32 | #include <linux/types.h> | 32 | #include <linux/types.h> |
33 | #include <linux/pci.h> | 33 | #include <linux/pci.h> |
34 | #include <linux/pci_hotplug.h> | 34 | #include <linux/pci_hotplug.h> |
35 | #include <linux/delay.h> | 35 | #include <linux/delay.h> |
36 | #include <linux/sched.h> /* signal_pending() */ | 36 | #include <linux/sched.h> /* signal_pending() */ |
37 | #include <linux/pcieport_if.h> | 37 | #include <linux/pcieport_if.h> |
38 | #include <linux/mutex.h> | 38 | #include <linux/mutex.h> |
39 | 39 | ||
40 | #define MY_NAME "pciehp" | 40 | #define MY_NAME "pciehp" |
41 | 41 | ||
42 | extern int pciehp_poll_mode; | 42 | extern int pciehp_poll_mode; |
43 | extern int pciehp_poll_time; | 43 | extern int pciehp_poll_time; |
44 | extern int pciehp_debug; | 44 | extern int pciehp_debug; |
45 | extern int pciehp_force; | 45 | extern int pciehp_force; |
46 | extern struct workqueue_struct *pciehp_wq; | 46 | extern struct workqueue_struct *pciehp_wq; |
47 | 47 | ||
48 | #define dbg(format, arg...) \ | 48 | #define dbg(format, arg...) \ |
49 | do { \ | 49 | do { \ |
50 | if (pciehp_debug) \ | 50 | if (pciehp_debug) \ |
51 | printk(KERN_DEBUG "%s: " format, MY_NAME , ## arg); \ | 51 | printk(KERN_DEBUG "%s: " format, MY_NAME , ## arg); \ |
52 | } while (0) | 52 | } while (0) |
53 | #define err(format, arg...) \ | 53 | #define err(format, arg...) \ |
54 | printk(KERN_ERR "%s: " format, MY_NAME , ## arg) | 54 | printk(KERN_ERR "%s: " format, MY_NAME , ## arg) |
55 | #define info(format, arg...) \ | 55 | #define info(format, arg...) \ |
56 | printk(KERN_INFO "%s: " format, MY_NAME , ## arg) | 56 | printk(KERN_INFO "%s: " format, MY_NAME , ## arg) |
57 | #define warn(format, arg...) \ | 57 | #define warn(format, arg...) \ |
58 | printk(KERN_WARNING "%s: " format, MY_NAME , ## arg) | 58 | printk(KERN_WARNING "%s: " format, MY_NAME , ## arg) |
59 | 59 | ||
60 | #define ctrl_dbg(ctrl, format, arg...) \ | 60 | #define ctrl_dbg(ctrl, format, arg...) \ |
61 | do { \ | 61 | do { \ |
62 | if (pciehp_debug) \ | 62 | if (pciehp_debug) \ |
63 | dev_printk(KERN_DEBUG, &ctrl->pcie->device, \ | 63 | dev_printk(KERN_DEBUG, &ctrl->pcie->device, \ |
64 | format, ## arg); \ | 64 | format, ## arg); \ |
65 | } while (0) | 65 | } while (0) |
66 | #define ctrl_err(ctrl, format, arg...) \ | 66 | #define ctrl_err(ctrl, format, arg...) \ |
67 | dev_err(&ctrl->pcie->device, format, ## arg) | 67 | dev_err(&ctrl->pcie->device, format, ## arg) |
68 | #define ctrl_info(ctrl, format, arg...) \ | 68 | #define ctrl_info(ctrl, format, arg...) \ |
69 | dev_info(&ctrl->pcie->device, format, ## arg) | 69 | dev_info(&ctrl->pcie->device, format, ## arg) |
70 | #define ctrl_warn(ctrl, format, arg...) \ | 70 | #define ctrl_warn(ctrl, format, arg...) \ |
71 | dev_warn(&ctrl->pcie->device, format, ## arg) | 71 | dev_warn(&ctrl->pcie->device, format, ## arg) |
72 | 72 | ||
73 | #define SLOT_NAME_SIZE 10 | 73 | #define SLOT_NAME_SIZE 10 |
74 | struct slot { | 74 | struct slot { |
75 | u8 bus; | 75 | u8 bus; |
76 | u8 device; | 76 | u8 device; |
77 | u8 state; | 77 | u8 state; |
78 | u8 hp_slot; | 78 | u8 hp_slot; |
79 | u32 number; | 79 | u32 number; |
80 | struct controller *ctrl; | 80 | struct controller *ctrl; |
81 | struct hpc_ops *hpc_ops; | 81 | struct hpc_ops *hpc_ops; |
82 | struct hotplug_slot *hotplug_slot; | 82 | struct hotplug_slot *hotplug_slot; |
83 | struct list_head slot_list; | ||
84 | struct delayed_work work; /* work for button event */ | 83 | struct delayed_work work; /* work for button event */ |
85 | struct mutex lock; | 84 | struct mutex lock; |
86 | }; | 85 | }; |
87 | 86 | ||
88 | struct event_info { | 87 | struct event_info { |
89 | u32 event_type; | 88 | u32 event_type; |
90 | struct slot *p_slot; | 89 | struct slot *p_slot; |
91 | struct work_struct work; | 90 | struct work_struct work; |
92 | }; | 91 | }; |
93 | 92 | ||
94 | struct controller { | 93 | struct controller { |
95 | struct mutex crit_sect; /* critical section mutex */ | 94 | struct mutex crit_sect; /* critical section mutex */ |
96 | struct mutex ctrl_lock; /* controller lock */ | 95 | struct mutex ctrl_lock; /* controller lock */ |
97 | int num_slots; /* Number of slots on ctlr */ | 96 | int num_slots; /* Number of slots on ctlr */ |
98 | int slot_num_inc; /* 1 or -1 */ | 97 | int slot_num_inc; /* 1 or -1 */ |
99 | struct pci_dev *pci_dev; | 98 | struct pci_dev *pci_dev; |
100 | struct pcie_device *pcie; /* PCI Express port service */ | 99 | struct pcie_device *pcie; /* PCI Express port service */ |
101 | struct list_head slot_list; | 100 | struct slot *slot; |
102 | struct hpc_ops *hpc_ops; | 101 | struct hpc_ops *hpc_ops; |
103 | wait_queue_head_t queue; /* sleep & wake process */ | 102 | wait_queue_head_t queue; /* sleep & wake process */ |
104 | u8 slot_device_offset; | 103 | u8 slot_device_offset; |
105 | u32 first_slot; /* First physical slot number */ /* PCIE only has 1 slot */ | 104 | u32 first_slot; /* First physical slot number */ /* PCIE only has 1 slot */ |
106 | u8 slot_bus; /* Bus where the slots handled by this controller sit */ | 105 | u8 slot_bus; /* Bus where the slots handled by this controller sit */ |
107 | u32 slot_cap; | 106 | u32 slot_cap; |
108 | u8 cap_base; | 107 | u8 cap_base; |
109 | struct timer_list poll_timer; | 108 | struct timer_list poll_timer; |
110 | unsigned int cmd_busy:1; | 109 | unsigned int cmd_busy:1; |
111 | unsigned int no_cmd_complete:1; | 110 | unsigned int no_cmd_complete:1; |
112 | unsigned int link_active_reporting:1; | 111 | unsigned int link_active_reporting:1; |
113 | unsigned int notification_enabled:1; | 112 | unsigned int notification_enabled:1; |
114 | unsigned int power_fault_detected; | 113 | unsigned int power_fault_detected; |
115 | }; | 114 | }; |
116 | 115 | ||
117 | #define INT_BUTTON_IGNORE 0 | 116 | #define INT_BUTTON_IGNORE 0 |
118 | #define INT_PRESENCE_ON 1 | 117 | #define INT_PRESENCE_ON 1 |
119 | #define INT_PRESENCE_OFF 2 | 118 | #define INT_PRESENCE_OFF 2 |
120 | #define INT_SWITCH_CLOSE 3 | 119 | #define INT_SWITCH_CLOSE 3 |
121 | #define INT_SWITCH_OPEN 4 | 120 | #define INT_SWITCH_OPEN 4 |
122 | #define INT_POWER_FAULT 5 | 121 | #define INT_POWER_FAULT 5 |
123 | #define INT_POWER_FAULT_CLEAR 6 | 122 | #define INT_POWER_FAULT_CLEAR 6 |
124 | #define INT_BUTTON_PRESS 7 | 123 | #define INT_BUTTON_PRESS 7 |
125 | #define INT_BUTTON_RELEASE 8 | 124 | #define INT_BUTTON_RELEASE 8 |
126 | #define INT_BUTTON_CANCEL 9 | 125 | #define INT_BUTTON_CANCEL 9 |
127 | 126 | ||
128 | #define STATIC_STATE 0 | 127 | #define STATIC_STATE 0 |
129 | #define BLINKINGON_STATE 1 | 128 | #define BLINKINGON_STATE 1 |
130 | #define BLINKINGOFF_STATE 2 | 129 | #define BLINKINGOFF_STATE 2 |
131 | #define POWERON_STATE 3 | 130 | #define POWERON_STATE 3 |
132 | #define POWEROFF_STATE 4 | 131 | #define POWEROFF_STATE 4 |
133 | 132 | ||
134 | /* Error messages */ | 133 | /* Error messages */ |
135 | #define INTERLOCK_OPEN 0x00000002 | 134 | #define INTERLOCK_OPEN 0x00000002 |
136 | #define ADD_NOT_SUPPORTED 0x00000003 | 135 | #define ADD_NOT_SUPPORTED 0x00000003 |
137 | #define CARD_FUNCTIONING 0x00000005 | 136 | #define CARD_FUNCTIONING 0x00000005 |
138 | #define ADAPTER_NOT_SAME 0x00000006 | 137 | #define ADAPTER_NOT_SAME 0x00000006 |
139 | #define NO_ADAPTER_PRESENT 0x00000009 | 138 | #define NO_ADAPTER_PRESENT 0x00000009 |
140 | #define NOT_ENOUGH_RESOURCES 0x0000000B | 139 | #define NOT_ENOUGH_RESOURCES 0x0000000B |
141 | #define DEVICE_TYPE_NOT_SUPPORTED 0x0000000C | 140 | #define DEVICE_TYPE_NOT_SUPPORTED 0x0000000C |
142 | #define WRONG_BUS_FREQUENCY 0x0000000D | 141 | #define WRONG_BUS_FREQUENCY 0x0000000D |
143 | #define POWER_FAILURE 0x0000000E | 142 | #define POWER_FAILURE 0x0000000E |
144 | 143 | ||
145 | /* Field definitions in Slot Capabilities Register */ | 144 | /* Field definitions in Slot Capabilities Register */ |
146 | #define ATTN_BUTTN_PRSN 0x00000001 | 145 | #define ATTN_BUTTN_PRSN 0x00000001 |
147 | #define PWR_CTRL_PRSN 0x00000002 | 146 | #define PWR_CTRL_PRSN 0x00000002 |
148 | #define MRL_SENS_PRSN 0x00000004 | 147 | #define MRL_SENS_PRSN 0x00000004 |
149 | #define ATTN_LED_PRSN 0x00000008 | 148 | #define ATTN_LED_PRSN 0x00000008 |
150 | #define PWR_LED_PRSN 0x00000010 | 149 | #define PWR_LED_PRSN 0x00000010 |
151 | #define HP_SUPR_RM_SUP 0x00000020 | 150 | #define HP_SUPR_RM_SUP 0x00000020 |
152 | #define EMI_PRSN 0x00020000 | 151 | #define EMI_PRSN 0x00020000 |
153 | #define NO_CMD_CMPL_SUP 0x00040000 | 152 | #define NO_CMD_CMPL_SUP 0x00040000 |
154 | 153 | ||
155 | #define ATTN_BUTTN(ctrl) ((ctrl)->slot_cap & ATTN_BUTTN_PRSN) | 154 | #define ATTN_BUTTN(ctrl) ((ctrl)->slot_cap & ATTN_BUTTN_PRSN) |
156 | #define POWER_CTRL(ctrl) ((ctrl)->slot_cap & PWR_CTRL_PRSN) | 155 | #define POWER_CTRL(ctrl) ((ctrl)->slot_cap & PWR_CTRL_PRSN) |
157 | #define MRL_SENS(ctrl) ((ctrl)->slot_cap & MRL_SENS_PRSN) | 156 | #define MRL_SENS(ctrl) ((ctrl)->slot_cap & MRL_SENS_PRSN) |
158 | #define ATTN_LED(ctrl) ((ctrl)->slot_cap & ATTN_LED_PRSN) | 157 | #define ATTN_LED(ctrl) ((ctrl)->slot_cap & ATTN_LED_PRSN) |
159 | #define PWR_LED(ctrl) ((ctrl)->slot_cap & PWR_LED_PRSN) | 158 | #define PWR_LED(ctrl) ((ctrl)->slot_cap & PWR_LED_PRSN) |
160 | #define HP_SUPR_RM(ctrl) ((ctrl)->slot_cap & HP_SUPR_RM_SUP) | 159 | #define HP_SUPR_RM(ctrl) ((ctrl)->slot_cap & HP_SUPR_RM_SUP) |
161 | #define EMI(ctrl) ((ctrl)->slot_cap & EMI_PRSN) | 160 | #define EMI(ctrl) ((ctrl)->slot_cap & EMI_PRSN) |
162 | #define NO_CMD_CMPL(ctrl) ((ctrl)->slot_cap & NO_CMD_CMPL_SUP) | 161 | #define NO_CMD_CMPL(ctrl) ((ctrl)->slot_cap & NO_CMD_CMPL_SUP) |
163 | 162 | ||
164 | extern int pciehp_sysfs_enable_slot(struct slot *slot); | 163 | extern int pciehp_sysfs_enable_slot(struct slot *slot); |
165 | extern int pciehp_sysfs_disable_slot(struct slot *slot); | 164 | extern int pciehp_sysfs_disable_slot(struct slot *slot); |
166 | extern u8 pciehp_handle_attention_button(struct slot *p_slot); | 165 | extern u8 pciehp_handle_attention_button(struct slot *p_slot); |
167 | extern u8 pciehp_handle_switch_change(struct slot *p_slot); | 166 | extern u8 pciehp_handle_switch_change(struct slot *p_slot); |
168 | extern u8 pciehp_handle_presence_change(struct slot *p_slot); | 167 | extern u8 pciehp_handle_presence_change(struct slot *p_slot); |
169 | extern u8 pciehp_handle_power_fault(struct slot *p_slot); | 168 | extern u8 pciehp_handle_power_fault(struct slot *p_slot); |
170 | extern int pciehp_configure_device(struct slot *p_slot); | 169 | extern int pciehp_configure_device(struct slot *p_slot); |
171 | extern int pciehp_unconfigure_device(struct slot *p_slot); | 170 | extern int pciehp_unconfigure_device(struct slot *p_slot); |
172 | extern void pciehp_queue_pushbutton_work(struct work_struct *work); | 171 | extern void pciehp_queue_pushbutton_work(struct work_struct *work); |
173 | struct controller *pcie_init(struct pcie_device *dev); | 172 | struct controller *pcie_init(struct pcie_device *dev); |
174 | int pcie_init_notification(struct controller *ctrl); | 173 | int pcie_init_notification(struct controller *ctrl); |
175 | int pciehp_enable_slot(struct slot *p_slot); | 174 | int pciehp_enable_slot(struct slot *p_slot); |
176 | int pciehp_disable_slot(struct slot *p_slot); | 175 | int pciehp_disable_slot(struct slot *p_slot); |
177 | int pcie_enable_notification(struct controller *ctrl); | 176 | int pcie_enable_notification(struct controller *ctrl); |
178 | 177 | ||
179 | static inline const char *slot_name(struct slot *slot) | 178 | static inline const char *slot_name(struct slot *slot) |
180 | { | 179 | { |
181 | return hotplug_slot_name(slot->hotplug_slot); | 180 | return hotplug_slot_name(slot->hotplug_slot); |
182 | } | ||
183 | |||
184 | static inline struct slot *pciehp_find_slot(struct controller *ctrl, u8 device) | ||
185 | { | ||
186 | struct slot *slot; | ||
187 | |||
188 | list_for_each_entry(slot, &ctrl->slot_list, slot_list) { | ||
189 | if (slot->device == device) | ||
190 | return slot; | ||
191 | } | ||
192 | |||
193 | ctrl_err(ctrl, "Slot (device=0x%02x) not found\n", device); | ||
194 | return NULL; | ||
195 | } | 181 | } |
196 | 182 | ||
197 | struct hpc_ops { | 183 | struct hpc_ops { |
198 | int (*power_on_slot)(struct slot *slot); | 184 | int (*power_on_slot)(struct slot *slot); |
199 | int (*power_off_slot)(struct slot *slot); | 185 | int (*power_off_slot)(struct slot *slot); |
200 | int (*get_power_status)(struct slot *slot, u8 *status); | 186 | int (*get_power_status)(struct slot *slot, u8 *status); |
201 | int (*get_attention_status)(struct slot *slot, u8 *status); | 187 | int (*get_attention_status)(struct slot *slot, u8 *status); |
202 | int (*set_attention_status)(struct slot *slot, u8 status); | 188 | int (*set_attention_status)(struct slot *slot, u8 status); |
203 | int (*get_latch_status)(struct slot *slot, u8 *status); | 189 | int (*get_latch_status)(struct slot *slot, u8 *status); |
204 | int (*get_adapter_status)(struct slot *slot, u8 *status); | 190 | int (*get_adapter_status)(struct slot *slot, u8 *status); |
205 | int (*get_max_bus_speed)(struct slot *slot, enum pci_bus_speed *speed); | 191 | int (*get_max_bus_speed)(struct slot *slot, enum pci_bus_speed *speed); |
206 | int (*get_cur_bus_speed)(struct slot *slot, enum pci_bus_speed *speed); | 192 | int (*get_cur_bus_speed)(struct slot *slot, enum pci_bus_speed *speed); |
207 | int (*get_max_lnk_width)(struct slot *slot, enum pcie_link_width *val); | 193 | int (*get_max_lnk_width)(struct slot *slot, enum pcie_link_width *val); |
208 | int (*get_cur_lnk_width)(struct slot *slot, enum pcie_link_width *val); | 194 | int (*get_cur_lnk_width)(struct slot *slot, enum pcie_link_width *val); |
209 | int (*query_power_fault)(struct slot *slot); | 195 | int (*query_power_fault)(struct slot *slot); |
210 | void (*green_led_on)(struct slot *slot); | 196 | void (*green_led_on)(struct slot *slot); |
211 | void (*green_led_off)(struct slot *slot); | 197 | void (*green_led_off)(struct slot *slot); |
212 | void (*green_led_blink)(struct slot *slot); | 198 | void (*green_led_blink)(struct slot *slot); |
213 | void (*release_ctlr)(struct controller *ctrl); | 199 | void (*release_ctlr)(struct controller *ctrl); |
214 | int (*check_lnk_status)(struct controller *ctrl); | 200 | int (*check_lnk_status)(struct controller *ctrl); |
215 | }; | 201 | }; |
216 | 202 | ||
217 | #ifdef CONFIG_ACPI | 203 | #ifdef CONFIG_ACPI |
218 | #include <acpi/acpi.h> | 204 | #include <acpi/acpi.h> |
219 | #include <acpi/acpi_bus.h> | 205 | #include <acpi/acpi_bus.h> |
220 | #include <linux/pci-acpi.h> | 206 | #include <linux/pci-acpi.h> |
221 | 207 | ||
222 | extern void __init pciehp_acpi_slot_detection_init(void); | 208 | extern void __init pciehp_acpi_slot_detection_init(void); |
223 | extern int pciehp_acpi_slot_detection_check(struct pci_dev *dev); | 209 | extern int pciehp_acpi_slot_detection_check(struct pci_dev *dev); |
224 | 210 | ||
225 | static inline void pciehp_firmware_init(void) | 211 | static inline void pciehp_firmware_init(void) |
226 | { | 212 | { |
227 | pciehp_acpi_slot_detection_init(); | 213 | pciehp_acpi_slot_detection_init(); |
228 | } | 214 | } |
229 | 215 | ||
230 | static inline int pciehp_get_hp_hw_control_from_firmware(struct pci_dev *dev) | 216 | static inline int pciehp_get_hp_hw_control_from_firmware(struct pci_dev *dev) |
231 | { | 217 | { |
232 | int retval; | 218 | int retval; |
233 | u32 flags = (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL | | 219 | u32 flags = (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL | |
234 | OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); | 220 | OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); |
235 | retval = acpi_get_hp_hw_control_from_firmware(dev, flags); | 221 | retval = acpi_get_hp_hw_control_from_firmware(dev, flags); |
236 | if (retval) | 222 | if (retval) |
237 | return retval; | 223 | return retval; |
238 | return pciehp_acpi_slot_detection_check(dev); | 224 | return pciehp_acpi_slot_detection_check(dev); |
239 | } | 225 | } |
240 | #else | 226 | #else |
241 | #define pciehp_firmware_init() do {} while (0) | 227 | #define pciehp_firmware_init() do {} while (0) |
242 | #define pciehp_get_hp_hw_control_from_firmware(dev) 0 | 228 | #define pciehp_get_hp_hw_control_from_firmware(dev) 0 |
243 | #endif /* CONFIG_ACPI */ | 229 | #endif /* CONFIG_ACPI */ |
244 | #endif /* _PCIEHP_H */ | 230 | #endif /* _PCIEHP_H */ |
245 | 231 |
drivers/pci/hotplug/pciehp_acpi.c
1 | /* | 1 | /* |
2 | * ACPI related functions for PCI Express Hot Plug driver. | 2 | * ACPI related functions for PCI Express Hot Plug driver. |
3 | * | 3 | * |
4 | * Copyright (C) 2008 Kenji Kaneshige | 4 | * Copyright (C) 2008 Kenji Kaneshige |
5 | * Copyright (C) 2008 Fujitsu Limited. | 5 | * Copyright (C) 2008 Fujitsu Limited. |
6 | * | 6 | * |
7 | * All rights reserved. | 7 | * All rights reserved. |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License as published by | 10 | * it under the terms of the GNU General Public License as published by |
11 | * the Free Software Foundation; either version 2 of the License, or (at | 11 | * the Free Software Foundation; either version 2 of the License, or (at |
12 | * your option) any later version. | 12 | * your option) any later version. |
13 | * | 13 | * |
14 | * This program is distributed in the hope that it will be useful, but | 14 | * This program is distributed in the hope that it will be useful, but |
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | 15 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | 16 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or |
17 | * NON INFRINGEMENT. See the GNU General Public License for more | 17 | * NON INFRINGEMENT. See the GNU General Public License for more |
18 | * details. | 18 | * details. |
19 | * | 19 | * |
20 | * You should have received a copy of the GNU General Public License | 20 | * You should have received a copy of the GNU General Public License |
21 | * along with this program; if not, write to the Free Software | 21 | * along with this program; if not, write to the Free Software |
22 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 22 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
23 | * | 23 | * |
24 | */ | 24 | */ |
25 | 25 | ||
26 | #include <linux/acpi.h> | 26 | #include <linux/acpi.h> |
27 | #include <linux/pci.h> | 27 | #include <linux/pci.h> |
28 | #include <linux/pci_hotplug.h> | 28 | #include <linux/pci_hotplug.h> |
29 | #include "pciehp.h" | 29 | #include "pciehp.h" |
30 | 30 | ||
31 | #define PCIEHP_DETECT_PCIE (0) | 31 | #define PCIEHP_DETECT_PCIE (0) |
32 | #define PCIEHP_DETECT_ACPI (1) | 32 | #define PCIEHP_DETECT_ACPI (1) |
33 | #define PCIEHP_DETECT_AUTO (2) | 33 | #define PCIEHP_DETECT_AUTO (2) |
34 | #define PCIEHP_DETECT_DEFAULT PCIEHP_DETECT_AUTO | 34 | #define PCIEHP_DETECT_DEFAULT PCIEHP_DETECT_AUTO |
35 | 35 | ||
36 | struct dummy_slot { | ||
37 | u32 number; | ||
38 | struct list_head list; | ||
39 | }; | ||
40 | |||
36 | static int slot_detection_mode; | 41 | static int slot_detection_mode; |
37 | static char *pciehp_detect_mode; | 42 | static char *pciehp_detect_mode; |
38 | module_param(pciehp_detect_mode, charp, 0444); | 43 | module_param(pciehp_detect_mode, charp, 0444); |
39 | MODULE_PARM_DESC(pciehp_detect_mode, | 44 | MODULE_PARM_DESC(pciehp_detect_mode, |
40 | "Slot detection mode: pcie, acpi, auto\n" | 45 | "Slot detection mode: pcie, acpi, auto\n" |
41 | " pcie - Use PCIe based slot detection\n" | 46 | " pcie - Use PCIe based slot detection\n" |
42 | " acpi - Use ACPI for slot detection\n" | 47 | " acpi - Use ACPI for slot detection\n" |
43 | " auto(default) - Auto select mode. Use acpi option if duplicate\n" | 48 | " auto(default) - Auto select mode. Use acpi option if duplicate\n" |
44 | " slot ids are found. Otherwise, use pcie option\n"); | 49 | " slot ids are found. Otherwise, use pcie option\n"); |
45 | 50 | ||
46 | int pciehp_acpi_slot_detection_check(struct pci_dev *dev) | 51 | int pciehp_acpi_slot_detection_check(struct pci_dev *dev) |
47 | { | 52 | { |
48 | if (slot_detection_mode != PCIEHP_DETECT_ACPI) | 53 | if (slot_detection_mode != PCIEHP_DETECT_ACPI) |
49 | return 0; | 54 | return 0; |
50 | if (acpi_pci_detect_ejectable(DEVICE_ACPI_HANDLE(&dev->dev))) | 55 | if (acpi_pci_detect_ejectable(DEVICE_ACPI_HANDLE(&dev->dev))) |
51 | return 0; | 56 | return 0; |
52 | return -ENODEV; | 57 | return -ENODEV; |
53 | } | 58 | } |
54 | 59 | ||
55 | static int __init parse_detect_mode(void) | 60 | static int __init parse_detect_mode(void) |
56 | { | 61 | { |
57 | if (!pciehp_detect_mode) | 62 | if (!pciehp_detect_mode) |
58 | return PCIEHP_DETECT_DEFAULT; | 63 | return PCIEHP_DETECT_DEFAULT; |
59 | if (!strcmp(pciehp_detect_mode, "pcie")) | 64 | if (!strcmp(pciehp_detect_mode, "pcie")) |
60 | return PCIEHP_DETECT_PCIE; | 65 | return PCIEHP_DETECT_PCIE; |
61 | if (!strcmp(pciehp_detect_mode, "acpi")) | 66 | if (!strcmp(pciehp_detect_mode, "acpi")) |
62 | return PCIEHP_DETECT_ACPI; | 67 | return PCIEHP_DETECT_ACPI; |
63 | if (!strcmp(pciehp_detect_mode, "auto")) | 68 | if (!strcmp(pciehp_detect_mode, "auto")) |
64 | return PCIEHP_DETECT_AUTO; | 69 | return PCIEHP_DETECT_AUTO; |
65 | warn("bad specifier '%s' for pciehp_detect_mode. Use default\n", | 70 | warn("bad specifier '%s' for pciehp_detect_mode. Use default\n", |
66 | pciehp_detect_mode); | 71 | pciehp_detect_mode); |
67 | return PCIEHP_DETECT_DEFAULT; | 72 | return PCIEHP_DETECT_DEFAULT; |
68 | } | 73 | } |
69 | 74 | ||
70 | static int __initdata dup_slot_id; | 75 | static int __initdata dup_slot_id; |
71 | static int __initdata acpi_slot_detected; | 76 | static int __initdata acpi_slot_detected; |
72 | static struct list_head __initdata dummy_slots = LIST_HEAD_INIT(dummy_slots); | 77 | static struct list_head __initdata dummy_slots = LIST_HEAD_INIT(dummy_slots); |
73 | 78 | ||
74 | /* Dummy driver for dumplicate name detection */ | 79 | /* Dummy driver for dumplicate name detection */ |
75 | static int __init dummy_probe(struct pcie_device *dev) | 80 | static int __init dummy_probe(struct pcie_device *dev) |
76 | { | 81 | { |
77 | int pos; | 82 | int pos; |
78 | u32 slot_cap; | 83 | u32 slot_cap; |
79 | acpi_handle handle; | 84 | acpi_handle handle; |
80 | struct slot *slot, *tmp; | 85 | struct dummy_slot *slot, *tmp; |
81 | struct pci_dev *pdev = dev->port; | 86 | struct pci_dev *pdev = dev->port; |
82 | /* Note: pciehp_detect_mode != PCIEHP_DETECT_ACPI here */ | 87 | /* Note: pciehp_detect_mode != PCIEHP_DETECT_ACPI here */ |
83 | if (pciehp_get_hp_hw_control_from_firmware(pdev)) | 88 | if (pciehp_get_hp_hw_control_from_firmware(pdev)) |
84 | return -ENODEV; | 89 | return -ENODEV; |
85 | if (!(pos = pci_find_capability(pdev, PCI_CAP_ID_EXP))) | 90 | if (!(pos = pci_find_capability(pdev, PCI_CAP_ID_EXP))) |
86 | return -ENODEV; | 91 | return -ENODEV; |
87 | pci_read_config_dword(pdev, pos + PCI_EXP_SLTCAP, &slot_cap); | 92 | pci_read_config_dword(pdev, pos + PCI_EXP_SLTCAP, &slot_cap); |
88 | slot = kzalloc(sizeof(*slot), GFP_KERNEL); | 93 | slot = kzalloc(sizeof(*slot), GFP_KERNEL); |
89 | if (!slot) | 94 | if (!slot) |
90 | return -ENOMEM; | 95 | return -ENOMEM; |
91 | slot->number = slot_cap >> 19; | 96 | slot->number = slot_cap >> 19; |
92 | list_for_each_entry(tmp, &dummy_slots, slot_list) { | 97 | list_for_each_entry(tmp, &dummy_slots, list) { |
93 | if (tmp->number == slot->number) | 98 | if (tmp->number == slot->number) |
94 | dup_slot_id++; | 99 | dup_slot_id++; |
95 | } | 100 | } |
96 | list_add_tail(&slot->slot_list, &dummy_slots); | 101 | list_add_tail(&slot->list, &dummy_slots); |
97 | handle = DEVICE_ACPI_HANDLE(&pdev->dev); | 102 | handle = DEVICE_ACPI_HANDLE(&pdev->dev); |
98 | if (!acpi_slot_detected && acpi_pci_detect_ejectable(handle)) | 103 | if (!acpi_slot_detected && acpi_pci_detect_ejectable(handle)) |
99 | acpi_slot_detected = 1; | 104 | acpi_slot_detected = 1; |
100 | return -ENODEV; /* dummy driver always returns error */ | 105 | return -ENODEV; /* dummy driver always returns error */ |
101 | } | 106 | } |
102 | 107 | ||
103 | static struct pcie_port_service_driver __initdata dummy_driver = { | 108 | static struct pcie_port_service_driver __initdata dummy_driver = { |
104 | .name = "pciehp_dummy", | 109 | .name = "pciehp_dummy", |
105 | .port_type = PCIE_ANY_PORT, | 110 | .port_type = PCIE_ANY_PORT, |
106 | .service = PCIE_PORT_SERVICE_HP, | 111 | .service = PCIE_PORT_SERVICE_HP, |
107 | .probe = dummy_probe, | 112 | .probe = dummy_probe, |
108 | }; | 113 | }; |
109 | 114 | ||
110 | static int __init select_detection_mode(void) | 115 | static int __init select_detection_mode(void) |
111 | { | 116 | { |
112 | struct slot *slot, *tmp; | 117 | struct dummy_slot *slot, *tmp; |
113 | pcie_port_service_register(&dummy_driver); | 118 | pcie_port_service_register(&dummy_driver); |
114 | pcie_port_service_unregister(&dummy_driver); | 119 | pcie_port_service_unregister(&dummy_driver); |
115 | list_for_each_entry_safe(slot, tmp, &dummy_slots, slot_list) { | 120 | list_for_each_entry_safe(slot, tmp, &dummy_slots, list) { |
116 | list_del(&slot->slot_list); | 121 | list_del(&slot->list); |
117 | kfree(slot); | 122 | kfree(slot); |
118 | } | 123 | } |
119 | if (acpi_slot_detected && dup_slot_id) | 124 | if (acpi_slot_detected && dup_slot_id) |
120 | return PCIEHP_DETECT_ACPI; | 125 | return PCIEHP_DETECT_ACPI; |
121 | return PCIEHP_DETECT_PCIE; | 126 | return PCIEHP_DETECT_PCIE; |
122 | } | 127 | } |
123 | 128 | ||
124 | void __init pciehp_acpi_slot_detection_init(void) | 129 | void __init pciehp_acpi_slot_detection_init(void) |
125 | { | 130 | { |
126 | slot_detection_mode = parse_detect_mode(); | 131 | slot_detection_mode = parse_detect_mode(); |
127 | if (slot_detection_mode != PCIEHP_DETECT_AUTO) | 132 | if (slot_detection_mode != PCIEHP_DETECT_AUTO) |
128 | goto out; | 133 | goto out; |
129 | slot_detection_mode = select_detection_mode(); | 134 | slot_detection_mode = select_detection_mode(); |
130 | out: | 135 | out: |
131 | if (slot_detection_mode == PCIEHP_DETECT_ACPI) | 136 | if (slot_detection_mode == PCIEHP_DETECT_ACPI) |
132 | info("Using ACPI for slot detection.\n"); | 137 | info("Using ACPI for slot detection.\n"); |
133 | } | 138 | } |
134 | 139 |
drivers/pci/hotplug/pciehp_core.c
1 | /* | 1 | /* |
2 | * PCI Express Hot Plug Controller Driver | 2 | * PCI Express Hot Plug Controller Driver |
3 | * | 3 | * |
4 | * Copyright (C) 1995,2001 Compaq Computer Corporation | 4 | * Copyright (C) 1995,2001 Compaq Computer Corporation |
5 | * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) | 5 | * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) |
6 | * Copyright (C) 2001 IBM Corp. | 6 | * Copyright (C) 2001 IBM Corp. |
7 | * Copyright (C) 2003-2004 Intel Corporation | 7 | * Copyright (C) 2003-2004 Intel Corporation |
8 | * | 8 | * |
9 | * All rights reserved. | 9 | * All rights reserved. |
10 | * | 10 | * |
11 | * This program is free software; you can redistribute it and/or modify | 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 | 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 | 13 | * the Free Software Foundation; either version 2 of the License, or (at |
14 | * your option) any later version. | 14 | * your option) any later version. |
15 | * | 15 | * |
16 | * This program is distributed in the hope that it will be useful, but | 16 | * This program is distributed in the hope that it will be useful, but |
17 | * WITHOUT ANY WARRANTY; without even the implied warranty of | 17 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
18 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | 18 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or |
19 | * NON INFRINGEMENT. See the GNU General Public License for more | 19 | * NON INFRINGEMENT. See the GNU General Public License for more |
20 | * details. | 20 | * details. |
21 | * | 21 | * |
22 | * You should have received a copy of the GNU General Public License | 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 | 23 | * along with this program; if not, write to the Free Software |
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
25 | * | 25 | * |
26 | * Send feedback to <greg@kroah.com>, <kristen.c.accardi@intel.com> | 26 | * Send feedback to <greg@kroah.com>, <kristen.c.accardi@intel.com> |
27 | * | 27 | * |
28 | */ | 28 | */ |
29 | 29 | ||
30 | #include <linux/module.h> | 30 | #include <linux/module.h> |
31 | #include <linux/moduleparam.h> | 31 | #include <linux/moduleparam.h> |
32 | #include <linux/kernel.h> | 32 | #include <linux/kernel.h> |
33 | #include <linux/types.h> | 33 | #include <linux/types.h> |
34 | #include <linux/pci.h> | 34 | #include <linux/pci.h> |
35 | #include "pciehp.h" | 35 | #include "pciehp.h" |
36 | #include <linux/interrupt.h> | 36 | #include <linux/interrupt.h> |
37 | #include <linux/time.h> | 37 | #include <linux/time.h> |
38 | 38 | ||
39 | /* Global variables */ | 39 | /* Global variables */ |
40 | int pciehp_debug; | 40 | int pciehp_debug; |
41 | int pciehp_poll_mode; | 41 | int pciehp_poll_mode; |
42 | int pciehp_poll_time; | 42 | int pciehp_poll_time; |
43 | int pciehp_force; | 43 | int pciehp_force; |
44 | struct workqueue_struct *pciehp_wq; | 44 | struct workqueue_struct *pciehp_wq; |
45 | 45 | ||
46 | #define DRIVER_VERSION "0.4" | 46 | #define DRIVER_VERSION "0.4" |
47 | #define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>" | 47 | #define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>" |
48 | #define DRIVER_DESC "PCI Express Hot Plug Controller Driver" | 48 | #define DRIVER_DESC "PCI Express Hot Plug Controller Driver" |
49 | 49 | ||
50 | MODULE_AUTHOR(DRIVER_AUTHOR); | 50 | MODULE_AUTHOR(DRIVER_AUTHOR); |
51 | MODULE_DESCRIPTION(DRIVER_DESC); | 51 | MODULE_DESCRIPTION(DRIVER_DESC); |
52 | MODULE_LICENSE("GPL"); | 52 | MODULE_LICENSE("GPL"); |
53 | 53 | ||
54 | module_param(pciehp_debug, bool, 0644); | 54 | module_param(pciehp_debug, bool, 0644); |
55 | module_param(pciehp_poll_mode, bool, 0644); | 55 | module_param(pciehp_poll_mode, bool, 0644); |
56 | module_param(pciehp_poll_time, int, 0644); | 56 | module_param(pciehp_poll_time, int, 0644); |
57 | module_param(pciehp_force, bool, 0644); | 57 | module_param(pciehp_force, bool, 0644); |
58 | MODULE_PARM_DESC(pciehp_debug, "Debugging mode enabled or not"); | 58 | MODULE_PARM_DESC(pciehp_debug, "Debugging mode enabled or not"); |
59 | MODULE_PARM_DESC(pciehp_poll_mode, "Using polling mechanism for hot-plug events or not"); | 59 | MODULE_PARM_DESC(pciehp_poll_mode, "Using polling mechanism for hot-plug events or not"); |
60 | MODULE_PARM_DESC(pciehp_poll_time, "Polling mechanism frequency, in seconds"); | 60 | MODULE_PARM_DESC(pciehp_poll_time, "Polling mechanism frequency, in seconds"); |
61 | MODULE_PARM_DESC(pciehp_force, "Force pciehp, even if _OSC and OSHP are missing"); | 61 | MODULE_PARM_DESC(pciehp_force, "Force pciehp, even if _OSC and OSHP are missing"); |
62 | 62 | ||
63 | #define PCIE_MODULE_NAME "pciehp" | 63 | #define PCIE_MODULE_NAME "pciehp" |
64 | 64 | ||
65 | static int set_attention_status (struct hotplug_slot *slot, u8 value); | 65 | static int set_attention_status (struct hotplug_slot *slot, u8 value); |
66 | static int enable_slot (struct hotplug_slot *slot); | 66 | static int enable_slot (struct hotplug_slot *slot); |
67 | static int disable_slot (struct hotplug_slot *slot); | 67 | static int disable_slot (struct hotplug_slot *slot); |
68 | static int get_power_status (struct hotplug_slot *slot, u8 *value); | 68 | static int get_power_status (struct hotplug_slot *slot, u8 *value); |
69 | static int get_attention_status (struct hotplug_slot *slot, u8 *value); | 69 | static int get_attention_status (struct hotplug_slot *slot, u8 *value); |
70 | static int get_latch_status (struct hotplug_slot *slot, u8 *value); | 70 | static int get_latch_status (struct hotplug_slot *slot, u8 *value); |
71 | static int get_adapter_status (struct hotplug_slot *slot, u8 *value); | 71 | static int get_adapter_status (struct hotplug_slot *slot, u8 *value); |
72 | static int get_max_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); | 72 | static int get_max_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); |
73 | static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); | 73 | static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); |
74 | 74 | ||
75 | static struct hotplug_slot_ops pciehp_hotplug_slot_ops = { | 75 | static struct hotplug_slot_ops pciehp_hotplug_slot_ops = { |
76 | .set_attention_status = set_attention_status, | 76 | .set_attention_status = set_attention_status, |
77 | .enable_slot = enable_slot, | 77 | .enable_slot = enable_slot, |
78 | .disable_slot = disable_slot, | 78 | .disable_slot = disable_slot, |
79 | .get_power_status = get_power_status, | 79 | .get_power_status = get_power_status, |
80 | .get_attention_status = get_attention_status, | 80 | .get_attention_status = get_attention_status, |
81 | .get_latch_status = get_latch_status, | 81 | .get_latch_status = get_latch_status, |
82 | .get_adapter_status = get_adapter_status, | 82 | .get_adapter_status = get_adapter_status, |
83 | .get_max_bus_speed = get_max_bus_speed, | 83 | .get_max_bus_speed = get_max_bus_speed, |
84 | .get_cur_bus_speed = get_cur_bus_speed, | 84 | .get_cur_bus_speed = get_cur_bus_speed, |
85 | }; | 85 | }; |
86 | 86 | ||
87 | /** | 87 | /** |
88 | * release_slot - free up the memory used by a slot | 88 | * release_slot - free up the memory used by a slot |
89 | * @hotplug_slot: slot to free | 89 | * @hotplug_slot: slot to free |
90 | */ | 90 | */ |
91 | static void release_slot(struct hotplug_slot *hotplug_slot) | 91 | static void release_slot(struct hotplug_slot *hotplug_slot) |
92 | { | 92 | { |
93 | struct slot *slot = hotplug_slot->private; | 93 | struct slot *slot = hotplug_slot->private; |
94 | 94 | ||
95 | ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", | 95 | ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", |
96 | __func__, hotplug_slot_name(hotplug_slot)); | 96 | __func__, hotplug_slot_name(hotplug_slot)); |
97 | 97 | ||
98 | kfree(hotplug_slot->info); | 98 | kfree(hotplug_slot->info); |
99 | kfree(hotplug_slot); | 99 | kfree(hotplug_slot); |
100 | } | 100 | } |
101 | 101 | ||
102 | static int init_slots(struct controller *ctrl) | 102 | static int init_slot(struct controller *ctrl) |
103 | { | 103 | { |
104 | struct slot *slot; | 104 | struct slot *slot = ctrl->slot; |
105 | struct hotplug_slot *hotplug_slot; | 105 | struct hotplug_slot *hotplug = NULL; |
106 | struct hotplug_slot_info *info; | 106 | struct hotplug_slot_info *info = NULL; |
107 | char name[SLOT_NAME_SIZE]; | 107 | char name[SLOT_NAME_SIZE]; |
108 | int retval = -ENOMEM; | 108 | int retval = -ENOMEM; |
109 | 109 | ||
110 | list_for_each_entry(slot, &ctrl->slot_list, slot_list) { | 110 | hotplug = kzalloc(sizeof(*hotplug), GFP_KERNEL); |
111 | hotplug_slot = kzalloc(sizeof(*hotplug_slot), GFP_KERNEL); | 111 | if (!hotplug) |
112 | if (!hotplug_slot) | 112 | goto out; |
113 | goto error; | ||
114 | 113 | ||
115 | info = kzalloc(sizeof(*info), GFP_KERNEL); | 114 | info = kzalloc(sizeof(*info), GFP_KERNEL); |
116 | if (!info) | 115 | if (!info) |
117 | goto error_hpslot; | 116 | goto out; |
118 | 117 | ||
119 | /* register this slot with the hotplug pci core */ | 118 | /* register this slot with the hotplug pci core */ |
120 | hotplug_slot->info = info; | 119 | hotplug->info = info; |
121 | hotplug_slot->private = slot; | 120 | hotplug->private = slot; |
122 | hotplug_slot->release = &release_slot; | 121 | hotplug->release = &release_slot; |
123 | hotplug_slot->ops = &pciehp_hotplug_slot_ops; | 122 | hotplug->ops = &pciehp_hotplug_slot_ops; |
124 | slot->hotplug_slot = hotplug_slot; | 123 | slot->hotplug_slot = hotplug; |
125 | snprintf(name, SLOT_NAME_SIZE, "%u", slot->number); | 124 | snprintf(name, SLOT_NAME_SIZE, "%u", slot->number); |
126 | 125 | ||
127 | ctrl_dbg(ctrl, "Registering domain:bus:dev=%04x:%02x:%02x " | 126 | ctrl_dbg(ctrl, "Registering domain:bus:dev=%04x:%02x:%02x " |
128 | "hp_slot=%x sun=%x slot_device_offset=%x\n", | 127 | "hp_slot=%x sun=%x slot_device_offset=%x\n", |
129 | pci_domain_nr(ctrl->pci_dev->subordinate), | 128 | pci_domain_nr(ctrl->pci_dev->subordinate), |
130 | slot->bus, slot->device, slot->hp_slot, slot->number, | 129 | slot->bus, slot->device, slot->hp_slot, slot->number, |
131 | ctrl->slot_device_offset); | 130 | ctrl->slot_device_offset); |
132 | retval = pci_hp_register(hotplug_slot, | 131 | retval = pci_hp_register(hotplug, |
133 | ctrl->pci_dev->subordinate, | 132 | ctrl->pci_dev->subordinate, |
134 | slot->device, | 133 | slot->device, |
135 | name); | 134 | name); |
136 | if (retval) { | 135 | if (retval) { |
137 | ctrl_err(ctrl, "pci_hp_register failed with error %d\n", | 136 | ctrl_err(ctrl, |
138 | retval); | 137 | "pci_hp_register failed with error %d\n", retval); |
139 | goto error_info; | 138 | goto out; |
140 | } | ||
141 | get_power_status(hotplug_slot, &info->power_status); | ||
142 | get_attention_status(hotplug_slot, &info->attention_status); | ||
143 | get_latch_status(hotplug_slot, &info->latch_status); | ||
144 | get_adapter_status(hotplug_slot, &info->adapter_status); | ||
145 | } | 139 | } |
146 | 140 | get_power_status(hotplug, &info->power_status); | |
147 | return 0; | 141 | get_attention_status(hotplug, &info->attention_status); |
148 | error_info: | 142 | get_latch_status(hotplug, &info->latch_status); |
149 | kfree(info); | 143 | get_adapter_status(hotplug, &info->adapter_status); |
150 | error_hpslot: | 144 | out: |
151 | kfree(hotplug_slot); | 145 | if (retval) { |
152 | error: | 146 | kfree(info); |
147 | kfree(hotplug); | ||
148 | } | ||
153 | return retval; | 149 | return retval; |
154 | } | 150 | } |
155 | 151 | ||
156 | static void cleanup_slots(struct controller *ctrl) | 152 | static void cleanup_slot(struct controller *ctrl) |
157 | { | 153 | { |
158 | struct slot *slot; | 154 | pci_hp_deregister(ctrl->slot->hotplug_slot); |
159 | list_for_each_entry(slot, &ctrl->slot_list, slot_list) | ||
160 | pci_hp_deregister(slot->hotplug_slot); | ||
161 | } | 155 | } |
162 | 156 | ||
163 | /* | 157 | /* |
164 | * set_attention_status - Turns the Amber LED for a slot on, off or blink | 158 | * set_attention_status - Turns the Amber LED for a slot on, off or blink |
165 | */ | 159 | */ |
166 | static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) | 160 | static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) |
167 | { | 161 | { |
168 | struct slot *slot = hotplug_slot->private; | 162 | struct slot *slot = hotplug_slot->private; |
169 | 163 | ||
170 | ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", | 164 | ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", |
171 | __func__, slot_name(slot)); | 165 | __func__, slot_name(slot)); |
172 | 166 | ||
173 | hotplug_slot->info->attention_status = status; | 167 | hotplug_slot->info->attention_status = status; |
174 | 168 | ||
175 | if (ATTN_LED(slot->ctrl)) | 169 | if (ATTN_LED(slot->ctrl)) |
176 | slot->hpc_ops->set_attention_status(slot, status); | 170 | slot->hpc_ops->set_attention_status(slot, status); |
177 | 171 | ||
178 | return 0; | 172 | return 0; |
179 | } | 173 | } |
180 | 174 | ||
181 | 175 | ||
182 | static int enable_slot(struct hotplug_slot *hotplug_slot) | 176 | static int enable_slot(struct hotplug_slot *hotplug_slot) |
183 | { | 177 | { |
184 | struct slot *slot = hotplug_slot->private; | 178 | struct slot *slot = hotplug_slot->private; |
185 | 179 | ||
186 | ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", | 180 | ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", |
187 | __func__, slot_name(slot)); | 181 | __func__, slot_name(slot)); |
188 | 182 | ||
189 | return pciehp_sysfs_enable_slot(slot); | 183 | return pciehp_sysfs_enable_slot(slot); |
190 | } | 184 | } |
191 | 185 | ||
192 | 186 | ||
193 | static int disable_slot(struct hotplug_slot *hotplug_slot) | 187 | static int disable_slot(struct hotplug_slot *hotplug_slot) |
194 | { | 188 | { |
195 | struct slot *slot = hotplug_slot->private; | 189 | struct slot *slot = hotplug_slot->private; |
196 | 190 | ||
197 | ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", | 191 | ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", |
198 | __func__, slot_name(slot)); | 192 | __func__, slot_name(slot)); |
199 | 193 | ||
200 | return pciehp_sysfs_disable_slot(slot); | 194 | return pciehp_sysfs_disable_slot(slot); |
201 | } | 195 | } |
202 | 196 | ||
203 | static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) | 197 | static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) |
204 | { | 198 | { |
205 | struct slot *slot = hotplug_slot->private; | 199 | struct slot *slot = hotplug_slot->private; |
206 | int retval; | 200 | int retval; |
207 | 201 | ||
208 | ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", | 202 | ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", |
209 | __func__, slot_name(slot)); | 203 | __func__, slot_name(slot)); |
210 | 204 | ||
211 | retval = slot->hpc_ops->get_power_status(slot, value); | 205 | retval = slot->hpc_ops->get_power_status(slot, value); |
212 | if (retval < 0) | 206 | if (retval < 0) |
213 | *value = hotplug_slot->info->power_status; | 207 | *value = hotplug_slot->info->power_status; |
214 | 208 | ||
215 | return 0; | 209 | return 0; |
216 | } | 210 | } |
217 | 211 | ||
218 | static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value) | 212 | static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value) |
219 | { | 213 | { |
220 | struct slot *slot = hotplug_slot->private; | 214 | struct slot *slot = hotplug_slot->private; |
221 | int retval; | 215 | int retval; |
222 | 216 | ||
223 | ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", | 217 | ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", |
224 | __func__, slot_name(slot)); | 218 | __func__, slot_name(slot)); |
225 | 219 | ||
226 | retval = slot->hpc_ops->get_attention_status(slot, value); | 220 | retval = slot->hpc_ops->get_attention_status(slot, value); |
227 | if (retval < 0) | 221 | if (retval < 0) |
228 | *value = hotplug_slot->info->attention_status; | 222 | *value = hotplug_slot->info->attention_status; |
229 | 223 | ||
230 | return 0; | 224 | return 0; |
231 | } | 225 | } |
232 | 226 | ||
233 | static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value) | 227 | static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value) |
234 | { | 228 | { |
235 | struct slot *slot = hotplug_slot->private; | 229 | struct slot *slot = hotplug_slot->private; |
236 | int retval; | 230 | int retval; |
237 | 231 | ||
238 | ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", | 232 | ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", |
239 | __func__, slot_name(slot)); | 233 | __func__, slot_name(slot)); |
240 | 234 | ||
241 | retval = slot->hpc_ops->get_latch_status(slot, value); | 235 | retval = slot->hpc_ops->get_latch_status(slot, value); |
242 | if (retval < 0) | 236 | if (retval < 0) |
243 | *value = hotplug_slot->info->latch_status; | 237 | *value = hotplug_slot->info->latch_status; |
244 | 238 | ||
245 | return 0; | 239 | return 0; |
246 | } | 240 | } |
247 | 241 | ||
248 | static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) | 242 | static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) |
249 | { | 243 | { |
250 | struct slot *slot = hotplug_slot->private; | 244 | struct slot *slot = hotplug_slot->private; |
251 | int retval; | 245 | int retval; |
252 | 246 | ||
253 | ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", | 247 | ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", |
254 | __func__, slot_name(slot)); | 248 | __func__, slot_name(slot)); |
255 | 249 | ||
256 | retval = slot->hpc_ops->get_adapter_status(slot, value); | 250 | retval = slot->hpc_ops->get_adapter_status(slot, value); |
257 | if (retval < 0) | 251 | if (retval < 0) |
258 | *value = hotplug_slot->info->adapter_status; | 252 | *value = hotplug_slot->info->adapter_status; |
259 | 253 | ||
260 | return 0; | 254 | return 0; |
261 | } | 255 | } |
262 | 256 | ||
263 | static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, | 257 | static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, |
264 | enum pci_bus_speed *value) | 258 | enum pci_bus_speed *value) |
265 | { | 259 | { |
266 | struct slot *slot = hotplug_slot->private; | 260 | struct slot *slot = hotplug_slot->private; |
267 | int retval; | 261 | int retval; |
268 | 262 | ||
269 | ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", | 263 | ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", |
270 | __func__, slot_name(slot)); | 264 | __func__, slot_name(slot)); |
271 | 265 | ||
272 | retval = slot->hpc_ops->get_max_bus_speed(slot, value); | 266 | retval = slot->hpc_ops->get_max_bus_speed(slot, value); |
273 | if (retval < 0) | 267 | if (retval < 0) |
274 | *value = PCI_SPEED_UNKNOWN; | 268 | *value = PCI_SPEED_UNKNOWN; |
275 | 269 | ||
276 | return 0; | 270 | return 0; |
277 | } | 271 | } |
278 | 272 | ||
279 | static int get_cur_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) | 273 | static int get_cur_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) |
280 | { | 274 | { |
281 | struct slot *slot = hotplug_slot->private; | 275 | struct slot *slot = hotplug_slot->private; |
282 | int retval; | 276 | int retval; |
283 | 277 | ||
284 | ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", | 278 | ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", |
285 | __func__, slot_name(slot)); | 279 | __func__, slot_name(slot)); |
286 | 280 | ||
287 | retval = slot->hpc_ops->get_cur_bus_speed(slot, value); | 281 | retval = slot->hpc_ops->get_cur_bus_speed(slot, value); |
288 | if (retval < 0) | 282 | if (retval < 0) |
289 | *value = PCI_SPEED_UNKNOWN; | 283 | *value = PCI_SPEED_UNKNOWN; |
290 | 284 | ||
291 | return 0; | 285 | return 0; |
292 | } | 286 | } |
293 | 287 | ||
294 | static int pciehp_probe(struct pcie_device *dev) | 288 | static int pciehp_probe(struct pcie_device *dev) |
295 | { | 289 | { |
296 | int rc; | 290 | int rc; |
297 | struct controller *ctrl; | 291 | struct controller *ctrl; |
298 | struct slot *t_slot; | 292 | struct slot *slot; |
299 | u8 value; | 293 | u8 value; |
300 | struct pci_dev *pdev = dev->port; | 294 | struct pci_dev *pdev = dev->port; |
301 | 295 | ||
302 | if (pciehp_force) | 296 | if (pciehp_force) |
303 | dev_info(&dev->device, | 297 | dev_info(&dev->device, |
304 | "Bypassing BIOS check for pciehp use on %s\n", | 298 | "Bypassing BIOS check for pciehp use on %s\n", |
305 | pci_name(pdev)); | 299 | pci_name(pdev)); |
306 | else if (pciehp_get_hp_hw_control_from_firmware(pdev)) | 300 | else if (pciehp_get_hp_hw_control_from_firmware(pdev)) |
307 | goto err_out_none; | 301 | goto err_out_none; |
308 | 302 | ||
309 | ctrl = pcie_init(dev); | 303 | ctrl = pcie_init(dev); |
310 | if (!ctrl) { | 304 | if (!ctrl) { |
311 | dev_err(&dev->device, "Controller initialization failed\n"); | 305 | dev_err(&dev->device, "Controller initialization failed\n"); |
312 | goto err_out_none; | 306 | goto err_out_none; |
313 | } | 307 | } |
314 | set_service_data(dev, ctrl); | 308 | set_service_data(dev, ctrl); |
315 | 309 | ||
316 | /* Setup the slot information structures */ | 310 | /* Setup the slot information structures */ |
317 | rc = init_slots(ctrl); | 311 | rc = init_slot(ctrl); |
318 | if (rc) { | 312 | if (rc) { |
319 | if (rc == -EBUSY) | 313 | if (rc == -EBUSY) |
320 | ctrl_warn(ctrl, "Slot already registered by another " | 314 | ctrl_warn(ctrl, "Slot already registered by another " |
321 | "hotplug driver\n"); | 315 | "hotplug driver\n"); |
322 | else | 316 | else |
323 | ctrl_err(ctrl, "Slot initialization failed\n"); | 317 | ctrl_err(ctrl, "Slot initialization failed\n"); |
324 | goto err_out_release_ctlr; | 318 | goto err_out_release_ctlr; |
325 | } | 319 | } |
326 | 320 | ||
327 | /* Enable events after we have setup the data structures */ | 321 | /* Enable events after we have setup the data structures */ |
328 | rc = pcie_init_notification(ctrl); | 322 | rc = pcie_init_notification(ctrl); |
329 | if (rc) { | 323 | if (rc) { |
330 | ctrl_err(ctrl, "Notification initialization failed\n"); | 324 | ctrl_err(ctrl, "Notification initialization failed\n"); |
331 | goto err_out_release_ctlr; | 325 | goto err_out_release_ctlr; |
332 | } | 326 | } |
333 | 327 | ||
334 | /* Check if slot is occupied */ | 328 | /* Check if slot is occupied */ |
335 | t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset); | 329 | slot = ctrl->slot; |
336 | t_slot->hpc_ops->get_adapter_status(t_slot, &value); | 330 | slot->hpc_ops->get_adapter_status(slot, &value); |
337 | if (value) { | 331 | if (value) { |
338 | if (pciehp_force) | 332 | if (pciehp_force) |
339 | pciehp_enable_slot(t_slot); | 333 | pciehp_enable_slot(slot); |
340 | } else { | 334 | } else { |
341 | /* Power off slot if not occupied */ | 335 | /* Power off slot if not occupied */ |
342 | if (POWER_CTRL(ctrl)) { | 336 | if (POWER_CTRL(ctrl)) { |
343 | rc = t_slot->hpc_ops->power_off_slot(t_slot); | 337 | rc = slot->hpc_ops->power_off_slot(slot); |
344 | if (rc) | 338 | if (rc) |
345 | goto err_out_free_ctrl_slot; | 339 | goto err_out_free_ctrl_slot; |
346 | } | 340 | } |
347 | } | 341 | } |
348 | 342 | ||
349 | return 0; | 343 | return 0; |
350 | 344 | ||
351 | err_out_free_ctrl_slot: | 345 | err_out_free_ctrl_slot: |
352 | cleanup_slots(ctrl); | 346 | cleanup_slot(ctrl); |
353 | err_out_release_ctlr: | 347 | err_out_release_ctlr: |
354 | ctrl->hpc_ops->release_ctlr(ctrl); | 348 | ctrl->hpc_ops->release_ctlr(ctrl); |
355 | err_out_none: | 349 | err_out_none: |
356 | return -ENODEV; | 350 | return -ENODEV; |
357 | } | 351 | } |
358 | 352 | ||
359 | static void pciehp_remove (struct pcie_device *dev) | 353 | static void pciehp_remove (struct pcie_device *dev) |
360 | { | 354 | { |
361 | struct controller *ctrl = get_service_data(dev); | 355 | struct controller *ctrl = get_service_data(dev); |
362 | 356 | ||
363 | cleanup_slots(ctrl); | 357 | cleanup_slot(ctrl); |
364 | ctrl->hpc_ops->release_ctlr(ctrl); | 358 | ctrl->hpc_ops->release_ctlr(ctrl); |
365 | } | 359 | } |
366 | 360 | ||
367 | #ifdef CONFIG_PM | 361 | #ifdef CONFIG_PM |
368 | static int pciehp_suspend (struct pcie_device *dev) | 362 | static int pciehp_suspend (struct pcie_device *dev) |
369 | { | 363 | { |
370 | dev_info(&dev->device, "%s ENTRY\n", __func__); | 364 | dev_info(&dev->device, "%s ENTRY\n", __func__); |
371 | return 0; | 365 | return 0; |
372 | } | 366 | } |
373 | 367 | ||
374 | static int pciehp_resume (struct pcie_device *dev) | 368 | static int pciehp_resume (struct pcie_device *dev) |
375 | { | 369 | { |
376 | dev_info(&dev->device, "%s ENTRY\n", __func__); | 370 | dev_info(&dev->device, "%s ENTRY\n", __func__); |
377 | if (pciehp_force) { | 371 | if (pciehp_force) { |
378 | struct controller *ctrl = get_service_data(dev); | 372 | struct controller *ctrl = get_service_data(dev); |
379 | struct slot *t_slot; | 373 | struct slot *slot; |
380 | u8 status; | 374 | u8 status; |
381 | 375 | ||
382 | /* reinitialize the chipset's event detection logic */ | 376 | /* reinitialize the chipset's event detection logic */ |
383 | pcie_enable_notification(ctrl); | 377 | pcie_enable_notification(ctrl); |
384 | 378 | ||
385 | t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset); | 379 | slot = ctrl->slot; |
386 | 380 | ||
387 | /* Check if slot is occupied */ | 381 | /* Check if slot is occupied */ |
388 | t_slot->hpc_ops->get_adapter_status(t_slot, &status); | 382 | slot->hpc_ops->get_adapter_status(slot, &status); |
389 | if (status) | 383 | if (status) |
390 | pciehp_enable_slot(t_slot); | 384 | pciehp_enable_slot(slot); |
391 | else | 385 | else |
392 | pciehp_disable_slot(t_slot); | 386 | pciehp_disable_slot(slot); |
393 | } | 387 | } |
394 | return 0; | 388 | return 0; |
395 | } | 389 | } |
396 | #endif /* PM */ | 390 | #endif /* PM */ |
397 | 391 | ||
398 | static struct pcie_port_service_driver hpdriver_portdrv = { | 392 | static struct pcie_port_service_driver hpdriver_portdrv = { |
399 | .name = PCIE_MODULE_NAME, | 393 | .name = PCIE_MODULE_NAME, |
400 | .port_type = PCIE_ANY_PORT, | 394 | .port_type = PCIE_ANY_PORT, |
401 | .service = PCIE_PORT_SERVICE_HP, | 395 | .service = PCIE_PORT_SERVICE_HP, |
402 | 396 | ||
403 | .probe = pciehp_probe, | 397 | .probe = pciehp_probe, |
404 | .remove = pciehp_remove, | 398 | .remove = pciehp_remove, |
405 | 399 | ||
406 | #ifdef CONFIG_PM | 400 | #ifdef CONFIG_PM |
407 | .suspend = pciehp_suspend, | 401 | .suspend = pciehp_suspend, |
408 | .resume = pciehp_resume, | 402 | .resume = pciehp_resume, |
409 | #endif /* PM */ | 403 | #endif /* PM */ |
410 | }; | 404 | }; |
411 | 405 | ||
412 | static int __init pcied_init(void) | 406 | static int __init pcied_init(void) |
413 | { | 407 | { |
414 | int retval = 0; | 408 | int retval = 0; |
415 | 409 | ||
416 | pciehp_firmware_init(); | 410 | pciehp_firmware_init(); |
417 | retval = pcie_port_service_register(&hpdriver_portdrv); | 411 | retval = pcie_port_service_register(&hpdriver_portdrv); |
418 | dbg("pcie_port_service_register = %d\n", retval); | 412 | dbg("pcie_port_service_register = %d\n", retval); |
419 | info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); | 413 | info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); |
420 | if (retval) | 414 | if (retval) |
421 | dbg("Failure to register service\n"); | 415 | dbg("Failure to register service\n"); |
422 | return retval; | 416 | return retval; |
423 | } | 417 | } |
424 | 418 | ||
425 | static void __exit pcied_cleanup(void) | 419 | static void __exit pcied_cleanup(void) |
426 | { | 420 | { |
427 | dbg("unload_pciehpd()\n"); | 421 | dbg("unload_pciehpd()\n"); |
428 | pcie_port_service_unregister(&hpdriver_portdrv); | 422 | pcie_port_service_unregister(&hpdriver_portdrv); |
429 | info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n"); | 423 | info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n"); |
430 | } | 424 | } |
431 | 425 | ||
432 | module_init(pcied_init); | 426 | module_init(pcied_init); |
drivers/pci/hotplug/pciehp_hpc.c
1 | /* | 1 | /* |
2 | * PCI Express PCI Hot Plug Driver | 2 | * PCI Express PCI Hot Plug Driver |
3 | * | 3 | * |
4 | * Copyright (C) 1995,2001 Compaq Computer Corporation | 4 | * Copyright (C) 1995,2001 Compaq Computer Corporation |
5 | * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) | 5 | * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) |
6 | * Copyright (C) 2001 IBM Corp. | 6 | * Copyright (C) 2001 IBM Corp. |
7 | * Copyright (C) 2003-2004 Intel Corporation | 7 | * Copyright (C) 2003-2004 Intel Corporation |
8 | * | 8 | * |
9 | * All rights reserved. | 9 | * All rights reserved. |
10 | * | 10 | * |
11 | * This program is free software; you can redistribute it and/or modify | 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 | 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 | 13 | * the Free Software Foundation; either version 2 of the License, or (at |
14 | * your option) any later version. | 14 | * your option) any later version. |
15 | * | 15 | * |
16 | * This program is distributed in the hope that it will be useful, but | 16 | * This program is distributed in the hope that it will be useful, but |
17 | * WITHOUT ANY WARRANTY; without even the implied warranty of | 17 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
18 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | 18 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or |
19 | * NON INFRINGEMENT. See the GNU General Public License for more | 19 | * NON INFRINGEMENT. See the GNU General Public License for more |
20 | * details. | 20 | * details. |
21 | * | 21 | * |
22 | * You should have received a copy of the GNU General Public License | 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 | 23 | * along with this program; if not, write to the Free Software |
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
25 | * | 25 | * |
26 | * Send feedback to <greg@kroah.com>,<kristen.c.accardi@intel.com> | 26 | * Send feedback to <greg@kroah.com>,<kristen.c.accardi@intel.com> |
27 | * | 27 | * |
28 | */ | 28 | */ |
29 | 29 | ||
30 | #include <linux/kernel.h> | 30 | #include <linux/kernel.h> |
31 | #include <linux/module.h> | 31 | #include <linux/module.h> |
32 | #include <linux/types.h> | 32 | #include <linux/types.h> |
33 | #include <linux/signal.h> | 33 | #include <linux/signal.h> |
34 | #include <linux/jiffies.h> | 34 | #include <linux/jiffies.h> |
35 | #include <linux/timer.h> | 35 | #include <linux/timer.h> |
36 | #include <linux/pci.h> | 36 | #include <linux/pci.h> |
37 | #include <linux/interrupt.h> | 37 | #include <linux/interrupt.h> |
38 | #include <linux/time.h> | 38 | #include <linux/time.h> |
39 | 39 | ||
40 | #include "../pci.h" | 40 | #include "../pci.h" |
41 | #include "pciehp.h" | 41 | #include "pciehp.h" |
42 | 42 | ||
43 | static atomic_t pciehp_num_controllers = ATOMIC_INIT(0); | 43 | static atomic_t pciehp_num_controllers = ATOMIC_INIT(0); |
44 | 44 | ||
45 | static inline int pciehp_readw(struct controller *ctrl, int reg, u16 *value) | 45 | static inline int pciehp_readw(struct controller *ctrl, int reg, u16 *value) |
46 | { | 46 | { |
47 | struct pci_dev *dev = ctrl->pci_dev; | 47 | struct pci_dev *dev = ctrl->pci_dev; |
48 | return pci_read_config_word(dev, ctrl->cap_base + reg, value); | 48 | return pci_read_config_word(dev, ctrl->cap_base + reg, value); |
49 | } | 49 | } |
50 | 50 | ||
51 | static inline int pciehp_readl(struct controller *ctrl, int reg, u32 *value) | 51 | static inline int pciehp_readl(struct controller *ctrl, int reg, u32 *value) |
52 | { | 52 | { |
53 | struct pci_dev *dev = ctrl->pci_dev; | 53 | struct pci_dev *dev = ctrl->pci_dev; |
54 | return pci_read_config_dword(dev, ctrl->cap_base + reg, value); | 54 | return pci_read_config_dword(dev, ctrl->cap_base + reg, value); |
55 | } | 55 | } |
56 | 56 | ||
57 | static inline int pciehp_writew(struct controller *ctrl, int reg, u16 value) | 57 | static inline int pciehp_writew(struct controller *ctrl, int reg, u16 value) |
58 | { | 58 | { |
59 | struct pci_dev *dev = ctrl->pci_dev; | 59 | struct pci_dev *dev = ctrl->pci_dev; |
60 | return pci_write_config_word(dev, ctrl->cap_base + reg, value); | 60 | return pci_write_config_word(dev, ctrl->cap_base + reg, value); |
61 | } | 61 | } |
62 | 62 | ||
63 | static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value) | 63 | static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value) |
64 | { | 64 | { |
65 | struct pci_dev *dev = ctrl->pci_dev; | 65 | struct pci_dev *dev = ctrl->pci_dev; |
66 | return pci_write_config_dword(dev, ctrl->cap_base + reg, value); | 66 | return pci_write_config_dword(dev, ctrl->cap_base + reg, value); |
67 | } | 67 | } |
68 | 68 | ||
69 | /* Power Control Command */ | 69 | /* Power Control Command */ |
70 | #define POWER_ON 0 | 70 | #define POWER_ON 0 |
71 | #define POWER_OFF PCI_EXP_SLTCTL_PCC | 71 | #define POWER_OFF PCI_EXP_SLTCTL_PCC |
72 | 72 | ||
73 | static irqreturn_t pcie_isr(int irq, void *dev_id); | 73 | static irqreturn_t pcie_isr(int irq, void *dev_id); |
74 | static void start_int_poll_timer(struct controller *ctrl, int sec); | 74 | static void start_int_poll_timer(struct controller *ctrl, int sec); |
75 | 75 | ||
76 | /* This is the interrupt polling timeout function. */ | 76 | /* This is the interrupt polling timeout function. */ |
77 | static void int_poll_timeout(unsigned long data) | 77 | static void int_poll_timeout(unsigned long data) |
78 | { | 78 | { |
79 | struct controller *ctrl = (struct controller *)data; | 79 | struct controller *ctrl = (struct controller *)data; |
80 | 80 | ||
81 | /* Poll for interrupt events. regs == NULL => polling */ | 81 | /* Poll for interrupt events. regs == NULL => polling */ |
82 | pcie_isr(0, ctrl); | 82 | pcie_isr(0, ctrl); |
83 | 83 | ||
84 | init_timer(&ctrl->poll_timer); | 84 | init_timer(&ctrl->poll_timer); |
85 | if (!pciehp_poll_time) | 85 | if (!pciehp_poll_time) |
86 | pciehp_poll_time = 2; /* default polling interval is 2 sec */ | 86 | pciehp_poll_time = 2; /* default polling interval is 2 sec */ |
87 | 87 | ||
88 | start_int_poll_timer(ctrl, pciehp_poll_time); | 88 | start_int_poll_timer(ctrl, pciehp_poll_time); |
89 | } | 89 | } |
90 | 90 | ||
91 | /* This function starts the interrupt polling timer. */ | 91 | /* This function starts the interrupt polling timer. */ |
92 | static void start_int_poll_timer(struct controller *ctrl, int sec) | 92 | static void start_int_poll_timer(struct controller *ctrl, int sec) |
93 | { | 93 | { |
94 | /* Clamp to sane value */ | 94 | /* Clamp to sane value */ |
95 | if ((sec <= 0) || (sec > 60)) | 95 | if ((sec <= 0) || (sec > 60)) |
96 | sec = 2; | 96 | sec = 2; |
97 | 97 | ||
98 | ctrl->poll_timer.function = &int_poll_timeout; | 98 | ctrl->poll_timer.function = &int_poll_timeout; |
99 | ctrl->poll_timer.data = (unsigned long)ctrl; | 99 | ctrl->poll_timer.data = (unsigned long)ctrl; |
100 | ctrl->poll_timer.expires = jiffies + sec * HZ; | 100 | ctrl->poll_timer.expires = jiffies + sec * HZ; |
101 | add_timer(&ctrl->poll_timer); | 101 | add_timer(&ctrl->poll_timer); |
102 | } | 102 | } |
103 | 103 | ||
104 | static inline int pciehp_request_irq(struct controller *ctrl) | 104 | static inline int pciehp_request_irq(struct controller *ctrl) |
105 | { | 105 | { |
106 | int retval, irq = ctrl->pcie->irq; | 106 | int retval, irq = ctrl->pcie->irq; |
107 | 107 | ||
108 | /* Install interrupt polling timer. Start with 10 sec delay */ | 108 | /* Install interrupt polling timer. Start with 10 sec delay */ |
109 | if (pciehp_poll_mode) { | 109 | if (pciehp_poll_mode) { |
110 | init_timer(&ctrl->poll_timer); | 110 | init_timer(&ctrl->poll_timer); |
111 | start_int_poll_timer(ctrl, 10); | 111 | start_int_poll_timer(ctrl, 10); |
112 | return 0; | 112 | return 0; |
113 | } | 113 | } |
114 | 114 | ||
115 | /* Installs the interrupt handler */ | 115 | /* Installs the interrupt handler */ |
116 | retval = request_irq(irq, pcie_isr, IRQF_SHARED, MY_NAME, ctrl); | 116 | retval = request_irq(irq, pcie_isr, IRQF_SHARED, MY_NAME, ctrl); |
117 | if (retval) | 117 | if (retval) |
118 | ctrl_err(ctrl, "Cannot get irq %d for the hotplug controller\n", | 118 | ctrl_err(ctrl, "Cannot get irq %d for the hotplug controller\n", |
119 | irq); | 119 | irq); |
120 | return retval; | 120 | return retval; |
121 | } | 121 | } |
122 | 122 | ||
123 | static inline void pciehp_free_irq(struct controller *ctrl) | 123 | static inline void pciehp_free_irq(struct controller *ctrl) |
124 | { | 124 | { |
125 | if (pciehp_poll_mode) | 125 | if (pciehp_poll_mode) |
126 | del_timer_sync(&ctrl->poll_timer); | 126 | del_timer_sync(&ctrl->poll_timer); |
127 | else | 127 | else |
128 | free_irq(ctrl->pcie->irq, ctrl); | 128 | free_irq(ctrl->pcie->irq, ctrl); |
129 | } | 129 | } |
130 | 130 | ||
131 | static int pcie_poll_cmd(struct controller *ctrl) | 131 | static int pcie_poll_cmd(struct controller *ctrl) |
132 | { | 132 | { |
133 | u16 slot_status; | 133 | u16 slot_status; |
134 | int err, timeout = 1000; | 134 | int err, timeout = 1000; |
135 | 135 | ||
136 | err = pciehp_readw(ctrl, PCI_EXP_SLTSTA, &slot_status); | 136 | err = pciehp_readw(ctrl, PCI_EXP_SLTSTA, &slot_status); |
137 | if (!err && (slot_status & PCI_EXP_SLTSTA_CC)) { | 137 | if (!err && (slot_status & PCI_EXP_SLTSTA_CC)) { |
138 | pciehp_writew(ctrl, PCI_EXP_SLTSTA, PCI_EXP_SLTSTA_CC); | 138 | pciehp_writew(ctrl, PCI_EXP_SLTSTA, PCI_EXP_SLTSTA_CC); |
139 | return 1; | 139 | return 1; |
140 | } | 140 | } |
141 | while (timeout > 0) { | 141 | while (timeout > 0) { |
142 | msleep(10); | 142 | msleep(10); |
143 | timeout -= 10; | 143 | timeout -= 10; |
144 | err = pciehp_readw(ctrl, PCI_EXP_SLTSTA, &slot_status); | 144 | err = pciehp_readw(ctrl, PCI_EXP_SLTSTA, &slot_status); |
145 | if (!err && (slot_status & PCI_EXP_SLTSTA_CC)) { | 145 | if (!err && (slot_status & PCI_EXP_SLTSTA_CC)) { |
146 | pciehp_writew(ctrl, PCI_EXP_SLTSTA, PCI_EXP_SLTSTA_CC); | 146 | pciehp_writew(ctrl, PCI_EXP_SLTSTA, PCI_EXP_SLTSTA_CC); |
147 | return 1; | 147 | return 1; |
148 | } | 148 | } |
149 | } | 149 | } |
150 | return 0; /* timeout */ | 150 | return 0; /* timeout */ |
151 | } | 151 | } |
152 | 152 | ||
153 | static void pcie_wait_cmd(struct controller *ctrl, int poll) | 153 | static void pcie_wait_cmd(struct controller *ctrl, int poll) |
154 | { | 154 | { |
155 | unsigned int msecs = pciehp_poll_mode ? 2500 : 1000; | 155 | unsigned int msecs = pciehp_poll_mode ? 2500 : 1000; |
156 | unsigned long timeout = msecs_to_jiffies(msecs); | 156 | unsigned long timeout = msecs_to_jiffies(msecs); |
157 | int rc; | 157 | int rc; |
158 | 158 | ||
159 | if (poll) | 159 | if (poll) |
160 | rc = pcie_poll_cmd(ctrl); | 160 | rc = pcie_poll_cmd(ctrl); |
161 | else | 161 | else |
162 | rc = wait_event_timeout(ctrl->queue, !ctrl->cmd_busy, timeout); | 162 | rc = wait_event_timeout(ctrl->queue, !ctrl->cmd_busy, timeout); |
163 | if (!rc) | 163 | if (!rc) |
164 | ctrl_dbg(ctrl, "Command not completed in 1000 msec\n"); | 164 | ctrl_dbg(ctrl, "Command not completed in 1000 msec\n"); |
165 | } | 165 | } |
166 | 166 | ||
167 | /** | 167 | /** |
168 | * pcie_write_cmd - Issue controller command | 168 | * pcie_write_cmd - Issue controller command |
169 | * @ctrl: controller to which the command is issued | 169 | * @ctrl: controller to which the command is issued |
170 | * @cmd: command value written to slot control register | 170 | * @cmd: command value written to slot control register |
171 | * @mask: bitmask of slot control register to be modified | 171 | * @mask: bitmask of slot control register to be modified |
172 | */ | 172 | */ |
173 | static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask) | 173 | static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask) |
174 | { | 174 | { |
175 | int retval = 0; | 175 | int retval = 0; |
176 | u16 slot_status; | 176 | u16 slot_status; |
177 | u16 slot_ctrl; | 177 | u16 slot_ctrl; |
178 | 178 | ||
179 | mutex_lock(&ctrl->ctrl_lock); | 179 | mutex_lock(&ctrl->ctrl_lock); |
180 | 180 | ||
181 | retval = pciehp_readw(ctrl, PCI_EXP_SLTSTA, &slot_status); | 181 | retval = pciehp_readw(ctrl, PCI_EXP_SLTSTA, &slot_status); |
182 | if (retval) { | 182 | if (retval) { |
183 | ctrl_err(ctrl, "%s: Cannot read SLOTSTATUS register\n", | 183 | ctrl_err(ctrl, "%s: Cannot read SLOTSTATUS register\n", |
184 | __func__); | 184 | __func__); |
185 | goto out; | 185 | goto out; |
186 | } | 186 | } |
187 | 187 | ||
188 | if (slot_status & PCI_EXP_SLTSTA_CC) { | 188 | if (slot_status & PCI_EXP_SLTSTA_CC) { |
189 | if (!ctrl->no_cmd_complete) { | 189 | if (!ctrl->no_cmd_complete) { |
190 | /* | 190 | /* |
191 | * After 1 sec and CMD_COMPLETED still not set, just | 191 | * After 1 sec and CMD_COMPLETED still not set, just |
192 | * proceed forward to issue the next command according | 192 | * proceed forward to issue the next command according |
193 | * to spec. Just print out the error message. | 193 | * to spec. Just print out the error message. |
194 | */ | 194 | */ |
195 | ctrl_dbg(ctrl, "CMD_COMPLETED not clear after 1 sec\n"); | 195 | ctrl_dbg(ctrl, "CMD_COMPLETED not clear after 1 sec\n"); |
196 | } else if (!NO_CMD_CMPL(ctrl)) { | 196 | } else if (!NO_CMD_CMPL(ctrl)) { |
197 | /* | 197 | /* |
198 | * This controller semms to notify of command completed | 198 | * This controller semms to notify of command completed |
199 | * event even though it supports none of power | 199 | * event even though it supports none of power |
200 | * controller, attention led, power led and EMI. | 200 | * controller, attention led, power led and EMI. |
201 | */ | 201 | */ |
202 | ctrl_dbg(ctrl, "Unexpected CMD_COMPLETED. Need to " | 202 | ctrl_dbg(ctrl, "Unexpected CMD_COMPLETED. Need to " |
203 | "wait for command completed event.\n"); | 203 | "wait for command completed event.\n"); |
204 | ctrl->no_cmd_complete = 0; | 204 | ctrl->no_cmd_complete = 0; |
205 | } else { | 205 | } else { |
206 | ctrl_dbg(ctrl, "Unexpected CMD_COMPLETED. Maybe " | 206 | ctrl_dbg(ctrl, "Unexpected CMD_COMPLETED. Maybe " |
207 | "the controller is broken.\n"); | 207 | "the controller is broken.\n"); |
208 | } | 208 | } |
209 | } | 209 | } |
210 | 210 | ||
211 | retval = pciehp_readw(ctrl, PCI_EXP_SLTCTL, &slot_ctrl); | 211 | retval = pciehp_readw(ctrl, PCI_EXP_SLTCTL, &slot_ctrl); |
212 | if (retval) { | 212 | if (retval) { |
213 | ctrl_err(ctrl, "%s: Cannot read SLOTCTRL register\n", __func__); | 213 | ctrl_err(ctrl, "%s: Cannot read SLOTCTRL register\n", __func__); |
214 | goto out; | 214 | goto out; |
215 | } | 215 | } |
216 | 216 | ||
217 | slot_ctrl &= ~mask; | 217 | slot_ctrl &= ~mask; |
218 | slot_ctrl |= (cmd & mask); | 218 | slot_ctrl |= (cmd & mask); |
219 | ctrl->cmd_busy = 1; | 219 | ctrl->cmd_busy = 1; |
220 | smp_mb(); | 220 | smp_mb(); |
221 | retval = pciehp_writew(ctrl, PCI_EXP_SLTCTL, slot_ctrl); | 221 | retval = pciehp_writew(ctrl, PCI_EXP_SLTCTL, slot_ctrl); |
222 | if (retval) | 222 | if (retval) |
223 | ctrl_err(ctrl, "Cannot write to SLOTCTRL register\n"); | 223 | ctrl_err(ctrl, "Cannot write to SLOTCTRL register\n"); |
224 | 224 | ||
225 | /* | 225 | /* |
226 | * Wait for command completion. | 226 | * Wait for command completion. |
227 | */ | 227 | */ |
228 | if (!retval && !ctrl->no_cmd_complete) { | 228 | if (!retval && !ctrl->no_cmd_complete) { |
229 | int poll = 0; | 229 | int poll = 0; |
230 | /* | 230 | /* |
231 | * if hotplug interrupt is not enabled or command | 231 | * if hotplug interrupt is not enabled or command |
232 | * completed interrupt is not enabled, we need to poll | 232 | * completed interrupt is not enabled, we need to poll |
233 | * command completed event. | 233 | * command completed event. |
234 | */ | 234 | */ |
235 | if (!(slot_ctrl & PCI_EXP_SLTCTL_HPIE) || | 235 | if (!(slot_ctrl & PCI_EXP_SLTCTL_HPIE) || |
236 | !(slot_ctrl & PCI_EXP_SLTCTL_CCIE)) | 236 | !(slot_ctrl & PCI_EXP_SLTCTL_CCIE)) |
237 | poll = 1; | 237 | poll = 1; |
238 | pcie_wait_cmd(ctrl, poll); | 238 | pcie_wait_cmd(ctrl, poll); |
239 | } | 239 | } |
240 | out: | 240 | out: |
241 | mutex_unlock(&ctrl->ctrl_lock); | 241 | mutex_unlock(&ctrl->ctrl_lock); |
242 | return retval; | 242 | return retval; |
243 | } | 243 | } |
244 | 244 | ||
245 | static inline int check_link_active(struct controller *ctrl) | 245 | static inline int check_link_active(struct controller *ctrl) |
246 | { | 246 | { |
247 | u16 link_status; | 247 | u16 link_status; |
248 | 248 | ||
249 | if (pciehp_readw(ctrl, PCI_EXP_LNKSTA, &link_status)) | 249 | if (pciehp_readw(ctrl, PCI_EXP_LNKSTA, &link_status)) |
250 | return 0; | 250 | return 0; |
251 | return !!(link_status & PCI_EXP_LNKSTA_DLLLA); | 251 | return !!(link_status & PCI_EXP_LNKSTA_DLLLA); |
252 | } | 252 | } |
253 | 253 | ||
254 | static void pcie_wait_link_active(struct controller *ctrl) | 254 | static void pcie_wait_link_active(struct controller *ctrl) |
255 | { | 255 | { |
256 | int timeout = 1000; | 256 | int timeout = 1000; |
257 | 257 | ||
258 | if (check_link_active(ctrl)) | 258 | if (check_link_active(ctrl)) |
259 | return; | 259 | return; |
260 | while (timeout > 0) { | 260 | while (timeout > 0) { |
261 | msleep(10); | 261 | msleep(10); |
262 | timeout -= 10; | 262 | timeout -= 10; |
263 | if (check_link_active(ctrl)) | 263 | if (check_link_active(ctrl)) |
264 | return; | 264 | return; |
265 | } | 265 | } |
266 | ctrl_dbg(ctrl, "Data Link Layer Link Active not set in 1000 msec\n"); | 266 | ctrl_dbg(ctrl, "Data Link Layer Link Active not set in 1000 msec\n"); |
267 | } | 267 | } |
268 | 268 | ||
269 | static int hpc_check_lnk_status(struct controller *ctrl) | 269 | static int hpc_check_lnk_status(struct controller *ctrl) |
270 | { | 270 | { |
271 | u16 lnk_status; | 271 | u16 lnk_status; |
272 | int retval = 0; | 272 | int retval = 0; |
273 | 273 | ||
274 | /* | 274 | /* |
275 | * Data Link Layer Link Active Reporting must be capable for | 275 | * Data Link Layer Link Active Reporting must be capable for |
276 | * hot-plug capable downstream port. But old controller might | 276 | * hot-plug capable downstream port. But old controller might |
277 | * not implement it. In this case, we wait for 1000 ms. | 277 | * not implement it. In this case, we wait for 1000 ms. |
278 | */ | 278 | */ |
279 | if (ctrl->link_active_reporting){ | 279 | if (ctrl->link_active_reporting){ |
280 | /* Wait for Data Link Layer Link Active bit to be set */ | 280 | /* Wait for Data Link Layer Link Active bit to be set */ |
281 | pcie_wait_link_active(ctrl); | 281 | pcie_wait_link_active(ctrl); |
282 | /* | 282 | /* |
283 | * We must wait for 100 ms after the Data Link Layer | 283 | * We must wait for 100 ms after the Data Link Layer |
284 | * Link Active bit reads 1b before initiating a | 284 | * Link Active bit reads 1b before initiating a |
285 | * configuration access to the hot added device. | 285 | * configuration access to the hot added device. |
286 | */ | 286 | */ |
287 | msleep(100); | 287 | msleep(100); |
288 | } else | 288 | } else |
289 | msleep(1000); | 289 | msleep(1000); |
290 | 290 | ||
291 | retval = pciehp_readw(ctrl, PCI_EXP_LNKSTA, &lnk_status); | 291 | retval = pciehp_readw(ctrl, PCI_EXP_LNKSTA, &lnk_status); |
292 | if (retval) { | 292 | if (retval) { |
293 | ctrl_err(ctrl, "Cannot read LNKSTATUS register\n"); | 293 | ctrl_err(ctrl, "Cannot read LNKSTATUS register\n"); |
294 | return retval; | 294 | return retval; |
295 | } | 295 | } |
296 | 296 | ||
297 | ctrl_dbg(ctrl, "%s: lnk_status = %x\n", __func__, lnk_status); | 297 | ctrl_dbg(ctrl, "%s: lnk_status = %x\n", __func__, lnk_status); |
298 | if ((lnk_status & PCI_EXP_LNKSTA_LT) || | 298 | if ((lnk_status & PCI_EXP_LNKSTA_LT) || |
299 | !(lnk_status & PCI_EXP_LNKSTA_NLW)) { | 299 | !(lnk_status & PCI_EXP_LNKSTA_NLW)) { |
300 | ctrl_err(ctrl, "Link Training Error occurs \n"); | 300 | ctrl_err(ctrl, "Link Training Error occurs \n"); |
301 | retval = -1; | 301 | retval = -1; |
302 | return retval; | 302 | return retval; |
303 | } | 303 | } |
304 | 304 | ||
305 | return retval; | 305 | return retval; |
306 | } | 306 | } |
307 | 307 | ||
308 | static int hpc_get_attention_status(struct slot *slot, u8 *status) | 308 | static int hpc_get_attention_status(struct slot *slot, u8 *status) |
309 | { | 309 | { |
310 | struct controller *ctrl = slot->ctrl; | 310 | struct controller *ctrl = slot->ctrl; |
311 | u16 slot_ctrl; | 311 | u16 slot_ctrl; |
312 | u8 atten_led_state; | 312 | u8 atten_led_state; |
313 | int retval = 0; | 313 | int retval = 0; |
314 | 314 | ||
315 | retval = pciehp_readw(ctrl, PCI_EXP_SLTCTL, &slot_ctrl); | 315 | retval = pciehp_readw(ctrl, PCI_EXP_SLTCTL, &slot_ctrl); |
316 | if (retval) { | 316 | if (retval) { |
317 | ctrl_err(ctrl, "%s: Cannot read SLOTCTRL register\n", __func__); | 317 | ctrl_err(ctrl, "%s: Cannot read SLOTCTRL register\n", __func__); |
318 | return retval; | 318 | return retval; |
319 | } | 319 | } |
320 | 320 | ||
321 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x, value read %x\n", | 321 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x, value read %x\n", |
322 | __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_ctrl); | 322 | __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_ctrl); |
323 | 323 | ||
324 | atten_led_state = (slot_ctrl & PCI_EXP_SLTCTL_AIC) >> 6; | 324 | atten_led_state = (slot_ctrl & PCI_EXP_SLTCTL_AIC) >> 6; |
325 | 325 | ||
326 | switch (atten_led_state) { | 326 | switch (atten_led_state) { |
327 | case 0: | 327 | case 0: |
328 | *status = 0xFF; /* Reserved */ | 328 | *status = 0xFF; /* Reserved */ |
329 | break; | 329 | break; |
330 | case 1: | 330 | case 1: |
331 | *status = 1; /* On */ | 331 | *status = 1; /* On */ |
332 | break; | 332 | break; |
333 | case 2: | 333 | case 2: |
334 | *status = 2; /* Blink */ | 334 | *status = 2; /* Blink */ |
335 | break; | 335 | break; |
336 | case 3: | 336 | case 3: |
337 | *status = 0; /* Off */ | 337 | *status = 0; /* Off */ |
338 | break; | 338 | break; |
339 | default: | 339 | default: |
340 | *status = 0xFF; | 340 | *status = 0xFF; |
341 | break; | 341 | break; |
342 | } | 342 | } |
343 | 343 | ||
344 | return 0; | 344 | return 0; |
345 | } | 345 | } |
346 | 346 | ||
347 | static int hpc_get_power_status(struct slot *slot, u8 *status) | 347 | static int hpc_get_power_status(struct slot *slot, u8 *status) |
348 | { | 348 | { |
349 | struct controller *ctrl = slot->ctrl; | 349 | struct controller *ctrl = slot->ctrl; |
350 | u16 slot_ctrl; | 350 | u16 slot_ctrl; |
351 | u8 pwr_state; | 351 | u8 pwr_state; |
352 | int retval = 0; | 352 | int retval = 0; |
353 | 353 | ||
354 | retval = pciehp_readw(ctrl, PCI_EXP_SLTCTL, &slot_ctrl); | 354 | retval = pciehp_readw(ctrl, PCI_EXP_SLTCTL, &slot_ctrl); |
355 | if (retval) { | 355 | if (retval) { |
356 | ctrl_err(ctrl, "%s: Cannot read SLOTCTRL register\n", __func__); | 356 | ctrl_err(ctrl, "%s: Cannot read SLOTCTRL register\n", __func__); |
357 | return retval; | 357 | return retval; |
358 | } | 358 | } |
359 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x value read %x\n", | 359 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x value read %x\n", |
360 | __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_ctrl); | 360 | __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_ctrl); |
361 | 361 | ||
362 | pwr_state = (slot_ctrl & PCI_EXP_SLTCTL_PCC) >> 10; | 362 | pwr_state = (slot_ctrl & PCI_EXP_SLTCTL_PCC) >> 10; |
363 | 363 | ||
364 | switch (pwr_state) { | 364 | switch (pwr_state) { |
365 | case 0: | 365 | case 0: |
366 | *status = 1; | 366 | *status = 1; |
367 | break; | 367 | break; |
368 | case 1: | 368 | case 1: |
369 | *status = 0; | 369 | *status = 0; |
370 | break; | 370 | break; |
371 | default: | 371 | default: |
372 | *status = 0xFF; | 372 | *status = 0xFF; |
373 | break; | 373 | break; |
374 | } | 374 | } |
375 | 375 | ||
376 | return retval; | 376 | return retval; |
377 | } | 377 | } |
378 | 378 | ||
379 | static int hpc_get_latch_status(struct slot *slot, u8 *status) | 379 | static int hpc_get_latch_status(struct slot *slot, u8 *status) |
380 | { | 380 | { |
381 | struct controller *ctrl = slot->ctrl; | 381 | struct controller *ctrl = slot->ctrl; |
382 | u16 slot_status; | 382 | u16 slot_status; |
383 | int retval; | 383 | int retval; |
384 | 384 | ||
385 | retval = pciehp_readw(ctrl, PCI_EXP_SLTSTA, &slot_status); | 385 | retval = pciehp_readw(ctrl, PCI_EXP_SLTSTA, &slot_status); |
386 | if (retval) { | 386 | if (retval) { |
387 | ctrl_err(ctrl, "%s: Cannot read SLOTSTATUS register\n", | 387 | ctrl_err(ctrl, "%s: Cannot read SLOTSTATUS register\n", |
388 | __func__); | 388 | __func__); |
389 | return retval; | 389 | return retval; |
390 | } | 390 | } |
391 | *status = !!(slot_status & PCI_EXP_SLTSTA_MRLSS); | 391 | *status = !!(slot_status & PCI_EXP_SLTSTA_MRLSS); |
392 | return 0; | 392 | return 0; |
393 | } | 393 | } |
394 | 394 | ||
395 | static int hpc_get_adapter_status(struct slot *slot, u8 *status) | 395 | static int hpc_get_adapter_status(struct slot *slot, u8 *status) |
396 | { | 396 | { |
397 | struct controller *ctrl = slot->ctrl; | 397 | struct controller *ctrl = slot->ctrl; |
398 | u16 slot_status; | 398 | u16 slot_status; |
399 | int retval; | 399 | int retval; |
400 | 400 | ||
401 | retval = pciehp_readw(ctrl, PCI_EXP_SLTSTA, &slot_status); | 401 | retval = pciehp_readw(ctrl, PCI_EXP_SLTSTA, &slot_status); |
402 | if (retval) { | 402 | if (retval) { |
403 | ctrl_err(ctrl, "%s: Cannot read SLOTSTATUS register\n", | 403 | ctrl_err(ctrl, "%s: Cannot read SLOTSTATUS register\n", |
404 | __func__); | 404 | __func__); |
405 | return retval; | 405 | return retval; |
406 | } | 406 | } |
407 | *status = !!(slot_status & PCI_EXP_SLTSTA_PDS); | 407 | *status = !!(slot_status & PCI_EXP_SLTSTA_PDS); |
408 | return 0; | 408 | return 0; |
409 | } | 409 | } |
410 | 410 | ||
411 | static int hpc_query_power_fault(struct slot *slot) | 411 | static int hpc_query_power_fault(struct slot *slot) |
412 | { | 412 | { |
413 | struct controller *ctrl = slot->ctrl; | 413 | struct controller *ctrl = slot->ctrl; |
414 | u16 slot_status; | 414 | u16 slot_status; |
415 | int retval; | 415 | int retval; |
416 | 416 | ||
417 | retval = pciehp_readw(ctrl, PCI_EXP_SLTSTA, &slot_status); | 417 | retval = pciehp_readw(ctrl, PCI_EXP_SLTSTA, &slot_status); |
418 | if (retval) { | 418 | if (retval) { |
419 | ctrl_err(ctrl, "Cannot check for power fault\n"); | 419 | ctrl_err(ctrl, "Cannot check for power fault\n"); |
420 | return retval; | 420 | return retval; |
421 | } | 421 | } |
422 | return !!(slot_status & PCI_EXP_SLTSTA_PFD); | 422 | return !!(slot_status & PCI_EXP_SLTSTA_PFD); |
423 | } | 423 | } |
424 | 424 | ||
425 | static int hpc_set_attention_status(struct slot *slot, u8 value) | 425 | static int hpc_set_attention_status(struct slot *slot, u8 value) |
426 | { | 426 | { |
427 | struct controller *ctrl = slot->ctrl; | 427 | struct controller *ctrl = slot->ctrl; |
428 | u16 slot_cmd; | 428 | u16 slot_cmd; |
429 | u16 cmd_mask; | 429 | u16 cmd_mask; |
430 | int rc; | 430 | int rc; |
431 | 431 | ||
432 | cmd_mask = PCI_EXP_SLTCTL_AIC; | 432 | cmd_mask = PCI_EXP_SLTCTL_AIC; |
433 | switch (value) { | 433 | switch (value) { |
434 | case 0 : /* turn off */ | 434 | case 0 : /* turn off */ |
435 | slot_cmd = 0x00C0; | 435 | slot_cmd = 0x00C0; |
436 | break; | 436 | break; |
437 | case 1: /* turn on */ | 437 | case 1: /* turn on */ |
438 | slot_cmd = 0x0040; | 438 | slot_cmd = 0x0040; |
439 | break; | 439 | break; |
440 | case 2: /* turn blink */ | 440 | case 2: /* turn blink */ |
441 | slot_cmd = 0x0080; | 441 | slot_cmd = 0x0080; |
442 | break; | 442 | break; |
443 | default: | 443 | default: |
444 | return -1; | 444 | return -1; |
445 | } | 445 | } |
446 | rc = pcie_write_cmd(ctrl, slot_cmd, cmd_mask); | 446 | rc = pcie_write_cmd(ctrl, slot_cmd, cmd_mask); |
447 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", | 447 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", |
448 | __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_cmd); | 448 | __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_cmd); |
449 | 449 | ||
450 | return rc; | 450 | return rc; |
451 | } | 451 | } |
452 | 452 | ||
453 | static void hpc_set_green_led_on(struct slot *slot) | 453 | static void hpc_set_green_led_on(struct slot *slot) |
454 | { | 454 | { |
455 | struct controller *ctrl = slot->ctrl; | 455 | struct controller *ctrl = slot->ctrl; |
456 | u16 slot_cmd; | 456 | u16 slot_cmd; |
457 | u16 cmd_mask; | 457 | u16 cmd_mask; |
458 | 458 | ||
459 | slot_cmd = 0x0100; | 459 | slot_cmd = 0x0100; |
460 | cmd_mask = PCI_EXP_SLTCTL_PIC; | 460 | cmd_mask = PCI_EXP_SLTCTL_PIC; |
461 | pcie_write_cmd(ctrl, slot_cmd, cmd_mask); | 461 | pcie_write_cmd(ctrl, slot_cmd, cmd_mask); |
462 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", | 462 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", |
463 | __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_cmd); | 463 | __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_cmd); |
464 | } | 464 | } |
465 | 465 | ||
466 | static void hpc_set_green_led_off(struct slot *slot) | 466 | static void hpc_set_green_led_off(struct slot *slot) |
467 | { | 467 | { |
468 | struct controller *ctrl = slot->ctrl; | 468 | struct controller *ctrl = slot->ctrl; |
469 | u16 slot_cmd; | 469 | u16 slot_cmd; |
470 | u16 cmd_mask; | 470 | u16 cmd_mask; |
471 | 471 | ||
472 | slot_cmd = 0x0300; | 472 | slot_cmd = 0x0300; |
473 | cmd_mask = PCI_EXP_SLTCTL_PIC; | 473 | cmd_mask = PCI_EXP_SLTCTL_PIC; |
474 | pcie_write_cmd(ctrl, slot_cmd, cmd_mask); | 474 | pcie_write_cmd(ctrl, slot_cmd, cmd_mask); |
475 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", | 475 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", |
476 | __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_cmd); | 476 | __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_cmd); |
477 | } | 477 | } |
478 | 478 | ||
479 | static void hpc_set_green_led_blink(struct slot *slot) | 479 | static void hpc_set_green_led_blink(struct slot *slot) |
480 | { | 480 | { |
481 | struct controller *ctrl = slot->ctrl; | 481 | struct controller *ctrl = slot->ctrl; |
482 | u16 slot_cmd; | 482 | u16 slot_cmd; |
483 | u16 cmd_mask; | 483 | u16 cmd_mask; |
484 | 484 | ||
485 | slot_cmd = 0x0200; | 485 | slot_cmd = 0x0200; |
486 | cmd_mask = PCI_EXP_SLTCTL_PIC; | 486 | cmd_mask = PCI_EXP_SLTCTL_PIC; |
487 | pcie_write_cmd(ctrl, slot_cmd, cmd_mask); | 487 | pcie_write_cmd(ctrl, slot_cmd, cmd_mask); |
488 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", | 488 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", |
489 | __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_cmd); | 489 | __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_cmd); |
490 | } | 490 | } |
491 | 491 | ||
492 | static int hpc_power_on_slot(struct slot * slot) | 492 | static int hpc_power_on_slot(struct slot * slot) |
493 | { | 493 | { |
494 | struct controller *ctrl = slot->ctrl; | 494 | struct controller *ctrl = slot->ctrl; |
495 | u16 slot_cmd; | 495 | u16 slot_cmd; |
496 | u16 cmd_mask; | 496 | u16 cmd_mask; |
497 | u16 slot_status; | 497 | u16 slot_status; |
498 | int retval = 0; | 498 | int retval = 0; |
499 | 499 | ||
500 | ctrl_dbg(ctrl, "%s: slot->hp_slot %x\n", __func__, slot->hp_slot); | 500 | ctrl_dbg(ctrl, "%s: slot->hp_slot %x\n", __func__, slot->hp_slot); |
501 | 501 | ||
502 | /* Clear sticky power-fault bit from previous power failures */ | 502 | /* Clear sticky power-fault bit from previous power failures */ |
503 | retval = pciehp_readw(ctrl, PCI_EXP_SLTSTA, &slot_status); | 503 | retval = pciehp_readw(ctrl, PCI_EXP_SLTSTA, &slot_status); |
504 | if (retval) { | 504 | if (retval) { |
505 | ctrl_err(ctrl, "%s: Cannot read SLOTSTATUS register\n", | 505 | ctrl_err(ctrl, "%s: Cannot read SLOTSTATUS register\n", |
506 | __func__); | 506 | __func__); |
507 | return retval; | 507 | return retval; |
508 | } | 508 | } |
509 | slot_status &= PCI_EXP_SLTSTA_PFD; | 509 | slot_status &= PCI_EXP_SLTSTA_PFD; |
510 | if (slot_status) { | 510 | if (slot_status) { |
511 | retval = pciehp_writew(ctrl, PCI_EXP_SLTSTA, slot_status); | 511 | retval = pciehp_writew(ctrl, PCI_EXP_SLTSTA, slot_status); |
512 | if (retval) { | 512 | if (retval) { |
513 | ctrl_err(ctrl, | 513 | ctrl_err(ctrl, |
514 | "%s: Cannot write to SLOTSTATUS register\n", | 514 | "%s: Cannot write to SLOTSTATUS register\n", |
515 | __func__); | 515 | __func__); |
516 | return retval; | 516 | return retval; |
517 | } | 517 | } |
518 | } | 518 | } |
519 | 519 | ||
520 | slot_cmd = POWER_ON; | 520 | slot_cmd = POWER_ON; |
521 | cmd_mask = PCI_EXP_SLTCTL_PCC; | 521 | cmd_mask = PCI_EXP_SLTCTL_PCC; |
522 | if (!pciehp_poll_mode) { | 522 | if (!pciehp_poll_mode) { |
523 | /* Enable power fault detection turned off at power off time */ | 523 | /* Enable power fault detection turned off at power off time */ |
524 | slot_cmd |= PCI_EXP_SLTCTL_PFDE; | 524 | slot_cmd |= PCI_EXP_SLTCTL_PFDE; |
525 | cmd_mask |= PCI_EXP_SLTCTL_PFDE; | 525 | cmd_mask |= PCI_EXP_SLTCTL_PFDE; |
526 | } | 526 | } |
527 | 527 | ||
528 | retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask); | 528 | retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask); |
529 | if (retval) { | 529 | if (retval) { |
530 | ctrl_err(ctrl, "Write %x command failed!\n", slot_cmd); | 530 | ctrl_err(ctrl, "Write %x command failed!\n", slot_cmd); |
531 | return retval; | 531 | return retval; |
532 | } | 532 | } |
533 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", | 533 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", |
534 | __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_cmd); | 534 | __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_cmd); |
535 | 535 | ||
536 | ctrl->power_fault_detected = 0; | 536 | ctrl->power_fault_detected = 0; |
537 | return retval; | 537 | return retval; |
538 | } | 538 | } |
539 | 539 | ||
540 | static inline int pcie_mask_bad_dllp(struct controller *ctrl) | 540 | static inline int pcie_mask_bad_dllp(struct controller *ctrl) |
541 | { | 541 | { |
542 | struct pci_dev *dev = ctrl->pci_dev; | 542 | struct pci_dev *dev = ctrl->pci_dev; |
543 | int pos; | 543 | int pos; |
544 | u32 reg; | 544 | u32 reg; |
545 | 545 | ||
546 | pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); | 546 | pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); |
547 | if (!pos) | 547 | if (!pos) |
548 | return 0; | 548 | return 0; |
549 | pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, ®); | 549 | pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, ®); |
550 | if (reg & PCI_ERR_COR_BAD_DLLP) | 550 | if (reg & PCI_ERR_COR_BAD_DLLP) |
551 | return 0; | 551 | return 0; |
552 | reg |= PCI_ERR_COR_BAD_DLLP; | 552 | reg |= PCI_ERR_COR_BAD_DLLP; |
553 | pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, reg); | 553 | pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, reg); |
554 | return 1; | 554 | return 1; |
555 | } | 555 | } |
556 | 556 | ||
557 | static inline void pcie_unmask_bad_dllp(struct controller *ctrl) | 557 | static inline void pcie_unmask_bad_dllp(struct controller *ctrl) |
558 | { | 558 | { |
559 | struct pci_dev *dev = ctrl->pci_dev; | 559 | struct pci_dev *dev = ctrl->pci_dev; |
560 | u32 reg; | 560 | u32 reg; |
561 | int pos; | 561 | int pos; |
562 | 562 | ||
563 | pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); | 563 | pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); |
564 | if (!pos) | 564 | if (!pos) |
565 | return; | 565 | return; |
566 | pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, ®); | 566 | pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, ®); |
567 | if (!(reg & PCI_ERR_COR_BAD_DLLP)) | 567 | if (!(reg & PCI_ERR_COR_BAD_DLLP)) |
568 | return; | 568 | return; |
569 | reg &= ~PCI_ERR_COR_BAD_DLLP; | 569 | reg &= ~PCI_ERR_COR_BAD_DLLP; |
570 | pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, reg); | 570 | pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, reg); |
571 | } | 571 | } |
572 | 572 | ||
573 | static int hpc_power_off_slot(struct slot * slot) | 573 | static int hpc_power_off_slot(struct slot * slot) |
574 | { | 574 | { |
575 | struct controller *ctrl = slot->ctrl; | 575 | struct controller *ctrl = slot->ctrl; |
576 | u16 slot_cmd; | 576 | u16 slot_cmd; |
577 | u16 cmd_mask; | 577 | u16 cmd_mask; |
578 | int retval = 0; | 578 | int retval = 0; |
579 | int changed; | 579 | int changed; |
580 | 580 | ||
581 | ctrl_dbg(ctrl, "%s: slot->hp_slot %x\n", __func__, slot->hp_slot); | 581 | ctrl_dbg(ctrl, "%s: slot->hp_slot %x\n", __func__, slot->hp_slot); |
582 | 582 | ||
583 | /* | 583 | /* |
584 | * Set Bad DLLP Mask bit in Correctable Error Mask | 584 | * Set Bad DLLP Mask bit in Correctable Error Mask |
585 | * Register. This is the workaround against Bad DLLP error | 585 | * Register. This is the workaround against Bad DLLP error |
586 | * that sometimes happens during turning power off the slot | 586 | * that sometimes happens during turning power off the slot |
587 | * which conforms to PCI Express 1.0a spec. | 587 | * which conforms to PCI Express 1.0a spec. |
588 | */ | 588 | */ |
589 | changed = pcie_mask_bad_dllp(ctrl); | 589 | changed = pcie_mask_bad_dllp(ctrl); |
590 | 590 | ||
591 | slot_cmd = POWER_OFF; | 591 | slot_cmd = POWER_OFF; |
592 | cmd_mask = PCI_EXP_SLTCTL_PCC; | 592 | cmd_mask = PCI_EXP_SLTCTL_PCC; |
593 | if (!pciehp_poll_mode) { | 593 | if (!pciehp_poll_mode) { |
594 | /* Disable power fault detection */ | 594 | /* Disable power fault detection */ |
595 | slot_cmd &= ~PCI_EXP_SLTCTL_PFDE; | 595 | slot_cmd &= ~PCI_EXP_SLTCTL_PFDE; |
596 | cmd_mask |= PCI_EXP_SLTCTL_PFDE; | 596 | cmd_mask |= PCI_EXP_SLTCTL_PFDE; |
597 | } | 597 | } |
598 | 598 | ||
599 | retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask); | 599 | retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask); |
600 | if (retval) { | 600 | if (retval) { |
601 | ctrl_err(ctrl, "Write command failed!\n"); | 601 | ctrl_err(ctrl, "Write command failed!\n"); |
602 | retval = -1; | 602 | retval = -1; |
603 | goto out; | 603 | goto out; |
604 | } | 604 | } |
605 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", | 605 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", |
606 | __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_cmd); | 606 | __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_cmd); |
607 | out: | 607 | out: |
608 | if (changed) | 608 | if (changed) |
609 | pcie_unmask_bad_dllp(ctrl); | 609 | pcie_unmask_bad_dllp(ctrl); |
610 | 610 | ||
611 | return retval; | 611 | return retval; |
612 | } | 612 | } |
613 | 613 | ||
614 | static irqreturn_t pcie_isr(int irq, void *dev_id) | 614 | static irqreturn_t pcie_isr(int irq, void *dev_id) |
615 | { | 615 | { |
616 | struct controller *ctrl = (struct controller *)dev_id; | 616 | struct controller *ctrl = (struct controller *)dev_id; |
617 | struct slot *slot = ctrl->slot; | ||
617 | u16 detected, intr_loc; | 618 | u16 detected, intr_loc; |
618 | struct slot *p_slot; | ||
619 | 619 | ||
620 | /* | 620 | /* |
621 | * In order to guarantee that all interrupt events are | 621 | * In order to guarantee that all interrupt events are |
622 | * serviced, we need to re-inspect Slot Status register after | 622 | * serviced, we need to re-inspect Slot Status register after |
623 | * clearing what is presumed to be the last pending interrupt. | 623 | * clearing what is presumed to be the last pending interrupt. |
624 | */ | 624 | */ |
625 | intr_loc = 0; | 625 | intr_loc = 0; |
626 | do { | 626 | do { |
627 | if (pciehp_readw(ctrl, PCI_EXP_SLTSTA, &detected)) { | 627 | if (pciehp_readw(ctrl, PCI_EXP_SLTSTA, &detected)) { |
628 | ctrl_err(ctrl, "%s: Cannot read SLOTSTATUS\n", | 628 | ctrl_err(ctrl, "%s: Cannot read SLOTSTATUS\n", |
629 | __func__); | 629 | __func__); |
630 | return IRQ_NONE; | 630 | return IRQ_NONE; |
631 | } | 631 | } |
632 | 632 | ||
633 | detected &= (PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD | | 633 | detected &= (PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD | |
634 | PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_PDC | | 634 | PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_PDC | |
635 | PCI_EXP_SLTSTA_CC); | 635 | PCI_EXP_SLTSTA_CC); |
636 | detected &= ~intr_loc; | 636 | detected &= ~intr_loc; |
637 | intr_loc |= detected; | 637 | intr_loc |= detected; |
638 | if (!intr_loc) | 638 | if (!intr_loc) |
639 | return IRQ_NONE; | 639 | return IRQ_NONE; |
640 | if (detected && pciehp_writew(ctrl, PCI_EXP_SLTSTA, intr_loc)) { | 640 | if (detected && pciehp_writew(ctrl, PCI_EXP_SLTSTA, intr_loc)) { |
641 | ctrl_err(ctrl, "%s: Cannot write to SLOTSTATUS\n", | 641 | ctrl_err(ctrl, "%s: Cannot write to SLOTSTATUS\n", |
642 | __func__); | 642 | __func__); |
643 | return IRQ_NONE; | 643 | return IRQ_NONE; |
644 | } | 644 | } |
645 | } while (detected); | 645 | } while (detected); |
646 | 646 | ||
647 | ctrl_dbg(ctrl, "%s: intr_loc %x\n", __func__, intr_loc); | 647 | ctrl_dbg(ctrl, "%s: intr_loc %x\n", __func__, intr_loc); |
648 | 648 | ||
649 | /* Check Command Complete Interrupt Pending */ | 649 | /* Check Command Complete Interrupt Pending */ |
650 | if (intr_loc & PCI_EXP_SLTSTA_CC) { | 650 | if (intr_loc & PCI_EXP_SLTSTA_CC) { |
651 | ctrl->cmd_busy = 0; | 651 | ctrl->cmd_busy = 0; |
652 | smp_mb(); | 652 | smp_mb(); |
653 | wake_up(&ctrl->queue); | 653 | wake_up(&ctrl->queue); |
654 | } | 654 | } |
655 | 655 | ||
656 | if (!(intr_loc & ~PCI_EXP_SLTSTA_CC)) | 656 | if (!(intr_loc & ~PCI_EXP_SLTSTA_CC)) |
657 | return IRQ_HANDLED; | 657 | return IRQ_HANDLED; |
658 | 658 | ||
659 | p_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset); | ||
660 | |||
661 | /* Check MRL Sensor Changed */ | 659 | /* Check MRL Sensor Changed */ |
662 | if (intr_loc & PCI_EXP_SLTSTA_MRLSC) | 660 | if (intr_loc & PCI_EXP_SLTSTA_MRLSC) |
663 | pciehp_handle_switch_change(p_slot); | 661 | pciehp_handle_switch_change(slot); |
664 | 662 | ||
665 | /* Check Attention Button Pressed */ | 663 | /* Check Attention Button Pressed */ |
666 | if (intr_loc & PCI_EXP_SLTSTA_ABP) | 664 | if (intr_loc & PCI_EXP_SLTSTA_ABP) |
667 | pciehp_handle_attention_button(p_slot); | 665 | pciehp_handle_attention_button(slot); |
668 | 666 | ||
669 | /* Check Presence Detect Changed */ | 667 | /* Check Presence Detect Changed */ |
670 | if (intr_loc & PCI_EXP_SLTSTA_PDC) | 668 | if (intr_loc & PCI_EXP_SLTSTA_PDC) |
671 | pciehp_handle_presence_change(p_slot); | 669 | pciehp_handle_presence_change(slot); |
672 | 670 | ||
673 | /* Check Power Fault Detected */ | 671 | /* Check Power Fault Detected */ |
674 | if ((intr_loc & PCI_EXP_SLTSTA_PFD) && !ctrl->power_fault_detected) { | 672 | if ((intr_loc & PCI_EXP_SLTSTA_PFD) && !ctrl->power_fault_detected) { |
675 | ctrl->power_fault_detected = 1; | 673 | ctrl->power_fault_detected = 1; |
676 | pciehp_handle_power_fault(p_slot); | 674 | pciehp_handle_power_fault(slot); |
677 | } | 675 | } |
678 | return IRQ_HANDLED; | 676 | return IRQ_HANDLED; |
679 | } | 677 | } |
680 | 678 | ||
681 | static int hpc_get_max_lnk_speed(struct slot *slot, enum pci_bus_speed *value) | 679 | static int hpc_get_max_lnk_speed(struct slot *slot, enum pci_bus_speed *value) |
682 | { | 680 | { |
683 | struct controller *ctrl = slot->ctrl; | 681 | struct controller *ctrl = slot->ctrl; |
684 | enum pcie_link_speed lnk_speed; | 682 | enum pcie_link_speed lnk_speed; |
685 | u32 lnk_cap; | 683 | u32 lnk_cap; |
686 | int retval = 0; | 684 | int retval = 0; |
687 | 685 | ||
688 | retval = pciehp_readl(ctrl, PCI_EXP_LNKCAP, &lnk_cap); | 686 | retval = pciehp_readl(ctrl, PCI_EXP_LNKCAP, &lnk_cap); |
689 | if (retval) { | 687 | if (retval) { |
690 | ctrl_err(ctrl, "%s: Cannot read LNKCAP register\n", __func__); | 688 | ctrl_err(ctrl, "%s: Cannot read LNKCAP register\n", __func__); |
691 | return retval; | 689 | return retval; |
692 | } | 690 | } |
693 | 691 | ||
694 | switch (lnk_cap & 0x000F) { | 692 | switch (lnk_cap & 0x000F) { |
695 | case 1: | 693 | case 1: |
696 | lnk_speed = PCIE_2_5GB; | 694 | lnk_speed = PCIE_2_5GB; |
697 | break; | 695 | break; |
698 | case 2: | 696 | case 2: |
699 | lnk_speed = PCIE_5_0GB; | 697 | lnk_speed = PCIE_5_0GB; |
700 | break; | 698 | break; |
701 | default: | 699 | default: |
702 | lnk_speed = PCIE_LNK_SPEED_UNKNOWN; | 700 | lnk_speed = PCIE_LNK_SPEED_UNKNOWN; |
703 | break; | 701 | break; |
704 | } | 702 | } |
705 | 703 | ||
706 | *value = lnk_speed; | 704 | *value = lnk_speed; |
707 | ctrl_dbg(ctrl, "Max link speed = %d\n", lnk_speed); | 705 | ctrl_dbg(ctrl, "Max link speed = %d\n", lnk_speed); |
708 | 706 | ||
709 | return retval; | 707 | return retval; |
710 | } | 708 | } |
711 | 709 | ||
712 | static int hpc_get_max_lnk_width(struct slot *slot, | 710 | static int hpc_get_max_lnk_width(struct slot *slot, |
713 | enum pcie_link_width *value) | 711 | enum pcie_link_width *value) |
714 | { | 712 | { |
715 | struct controller *ctrl = slot->ctrl; | 713 | struct controller *ctrl = slot->ctrl; |
716 | enum pcie_link_width lnk_wdth; | 714 | enum pcie_link_width lnk_wdth; |
717 | u32 lnk_cap; | 715 | u32 lnk_cap; |
718 | int retval = 0; | 716 | int retval = 0; |
719 | 717 | ||
720 | retval = pciehp_readl(ctrl, PCI_EXP_LNKCAP, &lnk_cap); | 718 | retval = pciehp_readl(ctrl, PCI_EXP_LNKCAP, &lnk_cap); |
721 | if (retval) { | 719 | if (retval) { |
722 | ctrl_err(ctrl, "%s: Cannot read LNKCAP register\n", __func__); | 720 | ctrl_err(ctrl, "%s: Cannot read LNKCAP register\n", __func__); |
723 | return retval; | 721 | return retval; |
724 | } | 722 | } |
725 | 723 | ||
726 | switch ((lnk_cap & PCI_EXP_LNKSTA_NLW) >> 4){ | 724 | switch ((lnk_cap & PCI_EXP_LNKSTA_NLW) >> 4){ |
727 | case 0: | 725 | case 0: |
728 | lnk_wdth = PCIE_LNK_WIDTH_RESRV; | 726 | lnk_wdth = PCIE_LNK_WIDTH_RESRV; |
729 | break; | 727 | break; |
730 | case 1: | 728 | case 1: |
731 | lnk_wdth = PCIE_LNK_X1; | 729 | lnk_wdth = PCIE_LNK_X1; |
732 | break; | 730 | break; |
733 | case 2: | 731 | case 2: |
734 | lnk_wdth = PCIE_LNK_X2; | 732 | lnk_wdth = PCIE_LNK_X2; |
735 | break; | 733 | break; |
736 | case 4: | 734 | case 4: |
737 | lnk_wdth = PCIE_LNK_X4; | 735 | lnk_wdth = PCIE_LNK_X4; |
738 | break; | 736 | break; |
739 | case 8: | 737 | case 8: |
740 | lnk_wdth = PCIE_LNK_X8; | 738 | lnk_wdth = PCIE_LNK_X8; |
741 | break; | 739 | break; |
742 | case 12: | 740 | case 12: |
743 | lnk_wdth = PCIE_LNK_X12; | 741 | lnk_wdth = PCIE_LNK_X12; |
744 | break; | 742 | break; |
745 | case 16: | 743 | case 16: |
746 | lnk_wdth = PCIE_LNK_X16; | 744 | lnk_wdth = PCIE_LNK_X16; |
747 | break; | 745 | break; |
748 | case 32: | 746 | case 32: |
749 | lnk_wdth = PCIE_LNK_X32; | 747 | lnk_wdth = PCIE_LNK_X32; |
750 | break; | 748 | break; |
751 | default: | 749 | default: |
752 | lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN; | 750 | lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN; |
753 | break; | 751 | break; |
754 | } | 752 | } |
755 | 753 | ||
756 | *value = lnk_wdth; | 754 | *value = lnk_wdth; |
757 | ctrl_dbg(ctrl, "Max link width = %d\n", lnk_wdth); | 755 | ctrl_dbg(ctrl, "Max link width = %d\n", lnk_wdth); |
758 | 756 | ||
759 | return retval; | 757 | return retval; |
760 | } | 758 | } |
761 | 759 | ||
762 | static int hpc_get_cur_lnk_speed(struct slot *slot, enum pci_bus_speed *value) | 760 | static int hpc_get_cur_lnk_speed(struct slot *slot, enum pci_bus_speed *value) |
763 | { | 761 | { |
764 | struct controller *ctrl = slot->ctrl; | 762 | struct controller *ctrl = slot->ctrl; |
765 | enum pcie_link_speed lnk_speed = PCI_SPEED_UNKNOWN; | 763 | enum pcie_link_speed lnk_speed = PCI_SPEED_UNKNOWN; |
766 | int retval = 0; | 764 | int retval = 0; |
767 | u16 lnk_status; | 765 | u16 lnk_status; |
768 | 766 | ||
769 | retval = pciehp_readw(ctrl, PCI_EXP_LNKSTA, &lnk_status); | 767 | retval = pciehp_readw(ctrl, PCI_EXP_LNKSTA, &lnk_status); |
770 | if (retval) { | 768 | if (retval) { |
771 | ctrl_err(ctrl, "%s: Cannot read LNKSTATUS register\n", | 769 | ctrl_err(ctrl, "%s: Cannot read LNKSTATUS register\n", |
772 | __func__); | 770 | __func__); |
773 | return retval; | 771 | return retval; |
774 | } | 772 | } |
775 | 773 | ||
776 | switch (lnk_status & PCI_EXP_LNKSTA_CLS) { | 774 | switch (lnk_status & PCI_EXP_LNKSTA_CLS) { |
777 | case 1: | 775 | case 1: |
778 | lnk_speed = PCIE_2_5GB; | 776 | lnk_speed = PCIE_2_5GB; |
779 | break; | 777 | break; |
780 | case 2: | 778 | case 2: |
781 | lnk_speed = PCIE_5_0GB; | 779 | lnk_speed = PCIE_5_0GB; |
782 | break; | 780 | break; |
783 | default: | 781 | default: |
784 | lnk_speed = PCIE_LNK_SPEED_UNKNOWN; | 782 | lnk_speed = PCIE_LNK_SPEED_UNKNOWN; |
785 | break; | 783 | break; |
786 | } | 784 | } |
787 | 785 | ||
788 | *value = lnk_speed; | 786 | *value = lnk_speed; |
789 | ctrl_dbg(ctrl, "Current link speed = %d\n", lnk_speed); | 787 | ctrl_dbg(ctrl, "Current link speed = %d\n", lnk_speed); |
790 | 788 | ||
791 | return retval; | 789 | return retval; |
792 | } | 790 | } |
793 | 791 | ||
794 | static int hpc_get_cur_lnk_width(struct slot *slot, | 792 | static int hpc_get_cur_lnk_width(struct slot *slot, |
795 | enum pcie_link_width *value) | 793 | enum pcie_link_width *value) |
796 | { | 794 | { |
797 | struct controller *ctrl = slot->ctrl; | 795 | struct controller *ctrl = slot->ctrl; |
798 | enum pcie_link_width lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN; | 796 | enum pcie_link_width lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN; |
799 | int retval = 0; | 797 | int retval = 0; |
800 | u16 lnk_status; | 798 | u16 lnk_status; |
801 | 799 | ||
802 | retval = pciehp_readw(ctrl, PCI_EXP_LNKSTA, &lnk_status); | 800 | retval = pciehp_readw(ctrl, PCI_EXP_LNKSTA, &lnk_status); |
803 | if (retval) { | 801 | if (retval) { |
804 | ctrl_err(ctrl, "%s: Cannot read LNKSTATUS register\n", | 802 | ctrl_err(ctrl, "%s: Cannot read LNKSTATUS register\n", |
805 | __func__); | 803 | __func__); |
806 | return retval; | 804 | return retval; |
807 | } | 805 | } |
808 | 806 | ||
809 | switch ((lnk_status & PCI_EXP_LNKSTA_NLW) >> 4){ | 807 | switch ((lnk_status & PCI_EXP_LNKSTA_NLW) >> 4){ |
810 | case 0: | 808 | case 0: |
811 | lnk_wdth = PCIE_LNK_WIDTH_RESRV; | 809 | lnk_wdth = PCIE_LNK_WIDTH_RESRV; |
812 | break; | 810 | break; |
813 | case 1: | 811 | case 1: |
814 | lnk_wdth = PCIE_LNK_X1; | 812 | lnk_wdth = PCIE_LNK_X1; |
815 | break; | 813 | break; |
816 | case 2: | 814 | case 2: |
817 | lnk_wdth = PCIE_LNK_X2; | 815 | lnk_wdth = PCIE_LNK_X2; |
818 | break; | 816 | break; |
819 | case 4: | 817 | case 4: |
820 | lnk_wdth = PCIE_LNK_X4; | 818 | lnk_wdth = PCIE_LNK_X4; |
821 | break; | 819 | break; |
822 | case 8: | 820 | case 8: |
823 | lnk_wdth = PCIE_LNK_X8; | 821 | lnk_wdth = PCIE_LNK_X8; |
824 | break; | 822 | break; |
825 | case 12: | 823 | case 12: |
826 | lnk_wdth = PCIE_LNK_X12; | 824 | lnk_wdth = PCIE_LNK_X12; |
827 | break; | 825 | break; |
828 | case 16: | 826 | case 16: |
829 | lnk_wdth = PCIE_LNK_X16; | 827 | lnk_wdth = PCIE_LNK_X16; |
830 | break; | 828 | break; |
831 | case 32: | 829 | case 32: |
832 | lnk_wdth = PCIE_LNK_X32; | 830 | lnk_wdth = PCIE_LNK_X32; |
833 | break; | 831 | break; |
834 | default: | 832 | default: |
835 | lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN; | 833 | lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN; |
836 | break; | 834 | break; |
837 | } | 835 | } |
838 | 836 | ||
839 | *value = lnk_wdth; | 837 | *value = lnk_wdth; |
840 | ctrl_dbg(ctrl, "Current link width = %d\n", lnk_wdth); | 838 | ctrl_dbg(ctrl, "Current link width = %d\n", lnk_wdth); |
841 | 839 | ||
842 | return retval; | 840 | return retval; |
843 | } | 841 | } |
844 | 842 | ||
845 | static void pcie_release_ctrl(struct controller *ctrl); | 843 | static void pcie_release_ctrl(struct controller *ctrl); |
846 | static struct hpc_ops pciehp_hpc_ops = { | 844 | static struct hpc_ops pciehp_hpc_ops = { |
847 | .power_on_slot = hpc_power_on_slot, | 845 | .power_on_slot = hpc_power_on_slot, |
848 | .power_off_slot = hpc_power_off_slot, | 846 | .power_off_slot = hpc_power_off_slot, |
849 | .set_attention_status = hpc_set_attention_status, | 847 | .set_attention_status = hpc_set_attention_status, |
850 | .get_power_status = hpc_get_power_status, | 848 | .get_power_status = hpc_get_power_status, |
851 | .get_attention_status = hpc_get_attention_status, | 849 | .get_attention_status = hpc_get_attention_status, |
852 | .get_latch_status = hpc_get_latch_status, | 850 | .get_latch_status = hpc_get_latch_status, |
853 | .get_adapter_status = hpc_get_adapter_status, | 851 | .get_adapter_status = hpc_get_adapter_status, |
854 | 852 | ||
855 | .get_max_bus_speed = hpc_get_max_lnk_speed, | 853 | .get_max_bus_speed = hpc_get_max_lnk_speed, |
856 | .get_cur_bus_speed = hpc_get_cur_lnk_speed, | 854 | .get_cur_bus_speed = hpc_get_cur_lnk_speed, |
857 | .get_max_lnk_width = hpc_get_max_lnk_width, | 855 | .get_max_lnk_width = hpc_get_max_lnk_width, |
858 | .get_cur_lnk_width = hpc_get_cur_lnk_width, | 856 | .get_cur_lnk_width = hpc_get_cur_lnk_width, |
859 | 857 | ||
860 | .query_power_fault = hpc_query_power_fault, | 858 | .query_power_fault = hpc_query_power_fault, |
861 | .green_led_on = hpc_set_green_led_on, | 859 | .green_led_on = hpc_set_green_led_on, |
862 | .green_led_off = hpc_set_green_led_off, | 860 | .green_led_off = hpc_set_green_led_off, |
863 | .green_led_blink = hpc_set_green_led_blink, | 861 | .green_led_blink = hpc_set_green_led_blink, |
864 | 862 | ||
865 | .release_ctlr = pcie_release_ctrl, | 863 | .release_ctlr = pcie_release_ctrl, |
866 | .check_lnk_status = hpc_check_lnk_status, | 864 | .check_lnk_status = hpc_check_lnk_status, |
867 | }; | 865 | }; |
868 | 866 | ||
869 | int pcie_enable_notification(struct controller *ctrl) | 867 | int pcie_enable_notification(struct controller *ctrl) |
870 | { | 868 | { |
871 | u16 cmd, mask; | 869 | u16 cmd, mask; |
872 | 870 | ||
873 | cmd = PCI_EXP_SLTCTL_PDCE; | 871 | cmd = PCI_EXP_SLTCTL_PDCE; |
874 | if (ATTN_BUTTN(ctrl)) | 872 | if (ATTN_BUTTN(ctrl)) |
875 | cmd |= PCI_EXP_SLTCTL_ABPE; | 873 | cmd |= PCI_EXP_SLTCTL_ABPE; |
876 | if (POWER_CTRL(ctrl)) | 874 | if (POWER_CTRL(ctrl)) |
877 | cmd |= PCI_EXP_SLTCTL_PFDE; | 875 | cmd |= PCI_EXP_SLTCTL_PFDE; |
878 | if (MRL_SENS(ctrl)) | 876 | if (MRL_SENS(ctrl)) |
879 | cmd |= PCI_EXP_SLTCTL_MRLSCE; | 877 | cmd |= PCI_EXP_SLTCTL_MRLSCE; |
880 | if (!pciehp_poll_mode) | 878 | if (!pciehp_poll_mode) |
881 | cmd |= PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE; | 879 | cmd |= PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE; |
882 | 880 | ||
883 | mask = (PCI_EXP_SLTCTL_PDCE | PCI_EXP_SLTCTL_ABPE | | 881 | mask = (PCI_EXP_SLTCTL_PDCE | PCI_EXP_SLTCTL_ABPE | |
884 | PCI_EXP_SLTCTL_MRLSCE | PCI_EXP_SLTCTL_PFDE | | 882 | PCI_EXP_SLTCTL_MRLSCE | PCI_EXP_SLTCTL_PFDE | |
885 | PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE); | 883 | PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE); |
886 | 884 | ||
887 | if (pcie_write_cmd(ctrl, cmd, mask)) { | 885 | if (pcie_write_cmd(ctrl, cmd, mask)) { |
888 | ctrl_err(ctrl, "Cannot enable software notification\n"); | 886 | ctrl_err(ctrl, "Cannot enable software notification\n"); |
889 | return -1; | 887 | return -1; |
890 | } | 888 | } |
891 | return 0; | 889 | return 0; |
892 | } | 890 | } |
893 | 891 | ||
894 | static void pcie_disable_notification(struct controller *ctrl) | 892 | static void pcie_disable_notification(struct controller *ctrl) |
895 | { | 893 | { |
896 | u16 mask; | 894 | u16 mask; |
897 | mask = (PCI_EXP_SLTCTL_PDCE | PCI_EXP_SLTCTL_ABPE | | 895 | mask = (PCI_EXP_SLTCTL_PDCE | PCI_EXP_SLTCTL_ABPE | |
898 | PCI_EXP_SLTCTL_MRLSCE | PCI_EXP_SLTCTL_PFDE | | 896 | PCI_EXP_SLTCTL_MRLSCE | PCI_EXP_SLTCTL_PFDE | |
899 | PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE); | 897 | PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE); |
900 | if (pcie_write_cmd(ctrl, 0, mask)) | 898 | if (pcie_write_cmd(ctrl, 0, mask)) |
901 | ctrl_warn(ctrl, "Cannot disable software notification\n"); | 899 | ctrl_warn(ctrl, "Cannot disable software notification\n"); |
902 | } | 900 | } |
903 | 901 | ||
904 | int pcie_init_notification(struct controller *ctrl) | 902 | int pcie_init_notification(struct controller *ctrl) |
905 | { | 903 | { |
906 | if (pciehp_request_irq(ctrl)) | 904 | if (pciehp_request_irq(ctrl)) |
907 | return -1; | 905 | return -1; |
908 | if (pcie_enable_notification(ctrl)) { | 906 | if (pcie_enable_notification(ctrl)) { |
909 | pciehp_free_irq(ctrl); | 907 | pciehp_free_irq(ctrl); |
910 | return -1; | 908 | return -1; |
911 | } | 909 | } |
912 | ctrl->notification_enabled = 1; | 910 | ctrl->notification_enabled = 1; |
913 | return 0; | 911 | return 0; |
914 | } | 912 | } |
915 | 913 | ||
916 | static void pcie_shutdown_notification(struct controller *ctrl) | 914 | static void pcie_shutdown_notification(struct controller *ctrl) |
917 | { | 915 | { |
918 | if (ctrl->notification_enabled) { | 916 | if (ctrl->notification_enabled) { |
919 | pcie_disable_notification(ctrl); | 917 | pcie_disable_notification(ctrl); |
920 | pciehp_free_irq(ctrl); | 918 | pciehp_free_irq(ctrl); |
921 | ctrl->notification_enabled = 0; | 919 | ctrl->notification_enabled = 0; |
922 | } | 920 | } |
923 | } | 921 | } |
924 | 922 | ||
925 | static int pcie_init_slot(struct controller *ctrl) | 923 | static int pcie_init_slot(struct controller *ctrl) |
926 | { | 924 | { |
927 | struct slot *slot; | 925 | struct slot *slot; |
928 | 926 | ||
929 | slot = kzalloc(sizeof(*slot), GFP_KERNEL); | 927 | slot = kzalloc(sizeof(*slot), GFP_KERNEL); |
930 | if (!slot) | 928 | if (!slot) |
931 | return -ENOMEM; | 929 | return -ENOMEM; |
932 | 930 | ||
933 | slot->hp_slot = 0; | 931 | slot->hp_slot = 0; |
934 | slot->ctrl = ctrl; | 932 | slot->ctrl = ctrl; |
935 | slot->bus = ctrl->pci_dev->subordinate->number; | 933 | slot->bus = ctrl->pci_dev->subordinate->number; |
936 | slot->device = ctrl->slot_device_offset + slot->hp_slot; | 934 | slot->device = ctrl->slot_device_offset + slot->hp_slot; |
937 | slot->hpc_ops = ctrl->hpc_ops; | 935 | slot->hpc_ops = ctrl->hpc_ops; |
938 | slot->number = ctrl->first_slot; | 936 | slot->number = ctrl->first_slot; |
939 | mutex_init(&slot->lock); | 937 | mutex_init(&slot->lock); |
940 | INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work); | 938 | INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work); |
941 | list_add(&slot->slot_list, &ctrl->slot_list); | 939 | ctrl->slot = slot; |
942 | return 0; | 940 | return 0; |
943 | } | 941 | } |
944 | 942 | ||
945 | static void pcie_cleanup_slot(struct controller *ctrl) | 943 | static void pcie_cleanup_slot(struct controller *ctrl) |
946 | { | 944 | { |
947 | struct slot *slot; | 945 | struct slot *slot = ctrl->slot; |
948 | slot = list_first_entry(&ctrl->slot_list, struct slot, slot_list); | ||
949 | list_del(&slot->slot_list); | ||
950 | cancel_delayed_work(&slot->work); | 946 | cancel_delayed_work(&slot->work); |
951 | flush_scheduled_work(); | 947 | flush_scheduled_work(); |
952 | flush_workqueue(pciehp_wq); | 948 | flush_workqueue(pciehp_wq); |
953 | kfree(slot); | 949 | kfree(slot); |
954 | } | 950 | } |
955 | 951 | ||
956 | static inline void dbg_ctrl(struct controller *ctrl) | 952 | static inline void dbg_ctrl(struct controller *ctrl) |
957 | { | 953 | { |
958 | int i; | 954 | int i; |
959 | u16 reg16; | 955 | u16 reg16; |
960 | struct pci_dev *pdev = ctrl->pci_dev; | 956 | struct pci_dev *pdev = ctrl->pci_dev; |
961 | 957 | ||
962 | if (!pciehp_debug) | 958 | if (!pciehp_debug) |
963 | return; | 959 | return; |
964 | 960 | ||
965 | ctrl_info(ctrl, "Hotplug Controller:\n"); | 961 | ctrl_info(ctrl, "Hotplug Controller:\n"); |
966 | ctrl_info(ctrl, " Seg/Bus/Dev/Func/IRQ : %s IRQ %d\n", | 962 | ctrl_info(ctrl, " Seg/Bus/Dev/Func/IRQ : %s IRQ %d\n", |
967 | pci_name(pdev), pdev->irq); | 963 | pci_name(pdev), pdev->irq); |
968 | ctrl_info(ctrl, " Vendor ID : 0x%04x\n", pdev->vendor); | 964 | ctrl_info(ctrl, " Vendor ID : 0x%04x\n", pdev->vendor); |
969 | ctrl_info(ctrl, " Device ID : 0x%04x\n", pdev->device); | 965 | ctrl_info(ctrl, " Device ID : 0x%04x\n", pdev->device); |
970 | ctrl_info(ctrl, " Subsystem ID : 0x%04x\n", | 966 | ctrl_info(ctrl, " Subsystem ID : 0x%04x\n", |
971 | pdev->subsystem_device); | 967 | pdev->subsystem_device); |
972 | ctrl_info(ctrl, " Subsystem Vendor ID : 0x%04x\n", | 968 | ctrl_info(ctrl, " Subsystem Vendor ID : 0x%04x\n", |
973 | pdev->subsystem_vendor); | 969 | pdev->subsystem_vendor); |
974 | ctrl_info(ctrl, " PCIe Cap offset : 0x%02x\n", ctrl->cap_base); | 970 | ctrl_info(ctrl, " PCIe Cap offset : 0x%02x\n", ctrl->cap_base); |
975 | for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { | 971 | for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { |
976 | if (!pci_resource_len(pdev, i)) | 972 | if (!pci_resource_len(pdev, i)) |
977 | continue; | 973 | continue; |
978 | ctrl_info(ctrl, " PCI resource [%d] : 0x%llx@0x%llx\n", | 974 | ctrl_info(ctrl, " PCI resource [%d] : 0x%llx@0x%llx\n", |
979 | i, (unsigned long long)pci_resource_len(pdev, i), | 975 | i, (unsigned long long)pci_resource_len(pdev, i), |
980 | (unsigned long long)pci_resource_start(pdev, i)); | 976 | (unsigned long long)pci_resource_start(pdev, i)); |
981 | } | 977 | } |
982 | ctrl_info(ctrl, "Slot Capabilities : 0x%08x\n", ctrl->slot_cap); | 978 | ctrl_info(ctrl, "Slot Capabilities : 0x%08x\n", ctrl->slot_cap); |
983 | ctrl_info(ctrl, " Physical Slot Number : %d\n", ctrl->first_slot); | 979 | ctrl_info(ctrl, " Physical Slot Number : %d\n", ctrl->first_slot); |
984 | ctrl_info(ctrl, " Attention Button : %3s\n", | 980 | ctrl_info(ctrl, " Attention Button : %3s\n", |
985 | ATTN_BUTTN(ctrl) ? "yes" : "no"); | 981 | ATTN_BUTTN(ctrl) ? "yes" : "no"); |
986 | ctrl_info(ctrl, " Power Controller : %3s\n", | 982 | ctrl_info(ctrl, " Power Controller : %3s\n", |
987 | POWER_CTRL(ctrl) ? "yes" : "no"); | 983 | POWER_CTRL(ctrl) ? "yes" : "no"); |
988 | ctrl_info(ctrl, " MRL Sensor : %3s\n", | 984 | ctrl_info(ctrl, " MRL Sensor : %3s\n", |
989 | MRL_SENS(ctrl) ? "yes" : "no"); | 985 | MRL_SENS(ctrl) ? "yes" : "no"); |
990 | ctrl_info(ctrl, " Attention Indicator : %3s\n", | 986 | ctrl_info(ctrl, " Attention Indicator : %3s\n", |
991 | ATTN_LED(ctrl) ? "yes" : "no"); | 987 | ATTN_LED(ctrl) ? "yes" : "no"); |
992 | ctrl_info(ctrl, " Power Indicator : %3s\n", | 988 | ctrl_info(ctrl, " Power Indicator : %3s\n", |
993 | PWR_LED(ctrl) ? "yes" : "no"); | 989 | PWR_LED(ctrl) ? "yes" : "no"); |
994 | ctrl_info(ctrl, " Hot-Plug Surprise : %3s\n", | 990 | ctrl_info(ctrl, " Hot-Plug Surprise : %3s\n", |
995 | HP_SUPR_RM(ctrl) ? "yes" : "no"); | 991 | HP_SUPR_RM(ctrl) ? "yes" : "no"); |
996 | ctrl_info(ctrl, " EMI Present : %3s\n", | 992 | ctrl_info(ctrl, " EMI Present : %3s\n", |
997 | EMI(ctrl) ? "yes" : "no"); | 993 | EMI(ctrl) ? "yes" : "no"); |
998 | ctrl_info(ctrl, " Command Completed : %3s\n", | 994 | ctrl_info(ctrl, " Command Completed : %3s\n", |
999 | NO_CMD_CMPL(ctrl) ? "no" : "yes"); | 995 | NO_CMD_CMPL(ctrl) ? "no" : "yes"); |
1000 | pciehp_readw(ctrl, PCI_EXP_SLTSTA, ®16); | 996 | pciehp_readw(ctrl, PCI_EXP_SLTSTA, ®16); |
1001 | ctrl_info(ctrl, "Slot Status : 0x%04x\n", reg16); | 997 | ctrl_info(ctrl, "Slot Status : 0x%04x\n", reg16); |
1002 | pciehp_readw(ctrl, PCI_EXP_SLTCTL, ®16); | 998 | pciehp_readw(ctrl, PCI_EXP_SLTCTL, ®16); |
1003 | ctrl_info(ctrl, "Slot Control : 0x%04x\n", reg16); | 999 | ctrl_info(ctrl, "Slot Control : 0x%04x\n", reg16); |
1004 | } | 1000 | } |
1005 | 1001 | ||
1006 | struct controller *pcie_init(struct pcie_device *dev) | 1002 | struct controller *pcie_init(struct pcie_device *dev) |
1007 | { | 1003 | { |
1008 | struct controller *ctrl; | 1004 | struct controller *ctrl; |
1009 | u32 slot_cap, link_cap; | 1005 | u32 slot_cap, link_cap; |
1010 | struct pci_dev *pdev = dev->port; | 1006 | struct pci_dev *pdev = dev->port; |
1011 | 1007 | ||
1012 | ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); | 1008 | ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); |
1013 | if (!ctrl) { | 1009 | if (!ctrl) { |
1014 | dev_err(&dev->device, "%s: Out of memory\n", __func__); | 1010 | dev_err(&dev->device, "%s: Out of memory\n", __func__); |
1015 | goto abort; | 1011 | goto abort; |
1016 | } | 1012 | } |
1017 | INIT_LIST_HEAD(&ctrl->slot_list); | ||
1018 | |||
1019 | ctrl->pcie = dev; | 1013 | ctrl->pcie = dev; |
1020 | ctrl->pci_dev = pdev; | 1014 | ctrl->pci_dev = pdev; |
1021 | ctrl->cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP); | 1015 | ctrl->cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP); |
1022 | if (!ctrl->cap_base) { | 1016 | if (!ctrl->cap_base) { |
1023 | ctrl_err(ctrl, "Cannot find PCI Express capability\n"); | 1017 | ctrl_err(ctrl, "Cannot find PCI Express capability\n"); |
1024 | goto abort_ctrl; | 1018 | goto abort_ctrl; |
1025 | } | 1019 | } |
1026 | if (pciehp_readl(ctrl, PCI_EXP_SLTCAP, &slot_cap)) { | 1020 | if (pciehp_readl(ctrl, PCI_EXP_SLTCAP, &slot_cap)) { |
1027 | ctrl_err(ctrl, "Cannot read SLOTCAP register\n"); | 1021 | ctrl_err(ctrl, "Cannot read SLOTCAP register\n"); |
1028 | goto abort_ctrl; | 1022 | goto abort_ctrl; |
1029 | } | 1023 | } |
1030 | 1024 | ||
1031 | ctrl->slot_cap = slot_cap; | 1025 | ctrl->slot_cap = slot_cap; |
1032 | ctrl->first_slot = slot_cap >> 19; | 1026 | ctrl->first_slot = slot_cap >> 19; |
1033 | ctrl->slot_device_offset = 0; | 1027 | ctrl->slot_device_offset = 0; |
1034 | ctrl->num_slots = 1; | 1028 | ctrl->num_slots = 1; |
1035 | ctrl->hpc_ops = &pciehp_hpc_ops; | 1029 | ctrl->hpc_ops = &pciehp_hpc_ops; |
1036 | mutex_init(&ctrl->crit_sect); | 1030 | mutex_init(&ctrl->crit_sect); |
1037 | mutex_init(&ctrl->ctrl_lock); | 1031 | mutex_init(&ctrl->ctrl_lock); |
1038 | init_waitqueue_head(&ctrl->queue); | 1032 | init_waitqueue_head(&ctrl->queue); |
1039 | dbg_ctrl(ctrl); | 1033 | dbg_ctrl(ctrl); |
1040 | /* | 1034 | /* |
1041 | * Controller doesn't notify of command completion if the "No | 1035 | * Controller doesn't notify of command completion if the "No |
1042 | * Command Completed Support" bit is set in Slot Capability | 1036 | * Command Completed Support" bit is set in Slot Capability |
1043 | * register or the controller supports none of power | 1037 | * register or the controller supports none of power |
1044 | * controller, attention led, power led and EMI. | 1038 | * controller, attention led, power led and EMI. |
1045 | */ | 1039 | */ |
1046 | if (NO_CMD_CMPL(ctrl) || | 1040 | if (NO_CMD_CMPL(ctrl) || |
1047 | !(POWER_CTRL(ctrl) | ATTN_LED(ctrl) | PWR_LED(ctrl) | EMI(ctrl))) | 1041 | !(POWER_CTRL(ctrl) | ATTN_LED(ctrl) | PWR_LED(ctrl) | EMI(ctrl))) |
1048 | ctrl->no_cmd_complete = 1; | 1042 | ctrl->no_cmd_complete = 1; |
1049 | 1043 | ||
1050 | /* Check if Data Link Layer Link Active Reporting is implemented */ | 1044 | /* Check if Data Link Layer Link Active Reporting is implemented */ |
1051 | if (pciehp_readl(ctrl, PCI_EXP_LNKCAP, &link_cap)) { | 1045 | if (pciehp_readl(ctrl, PCI_EXP_LNKCAP, &link_cap)) { |
1052 | ctrl_err(ctrl, "%s: Cannot read LNKCAP register\n", __func__); | 1046 | ctrl_err(ctrl, "%s: Cannot read LNKCAP register\n", __func__); |
1053 | goto abort_ctrl; | 1047 | goto abort_ctrl; |
1054 | } | 1048 | } |
1055 | if (link_cap & PCI_EXP_LNKCAP_DLLLARC) { | 1049 | if (link_cap & PCI_EXP_LNKCAP_DLLLARC) { |
1056 | ctrl_dbg(ctrl, "Link Active Reporting supported\n"); | 1050 | ctrl_dbg(ctrl, "Link Active Reporting supported\n"); |
1057 | ctrl->link_active_reporting = 1; | 1051 | ctrl->link_active_reporting = 1; |
1058 | } | 1052 | } |
1059 | 1053 | ||
1060 | /* Clear all remaining event bits in Slot Status register */ | 1054 | /* Clear all remaining event bits in Slot Status register */ |
1061 | if (pciehp_writew(ctrl, PCI_EXP_SLTSTA, 0x1f)) | 1055 | if (pciehp_writew(ctrl, PCI_EXP_SLTSTA, 0x1f)) |
1062 | goto abort_ctrl; | 1056 | goto abort_ctrl; |
1063 | 1057 | ||
1064 | /* Disable sotfware notification */ | 1058 | /* Disable sotfware notification */ |
1065 | pcie_disable_notification(ctrl); | 1059 | pcie_disable_notification(ctrl); |
1066 | 1060 | ||
1067 | /* | 1061 | /* |
1068 | * If this is the first controller to be initialized, | 1062 | * If this is the first controller to be initialized, |
1069 | * initialize the pciehp work queue | 1063 | * initialize the pciehp work queue |
1070 | */ | 1064 | */ |
1071 | if (atomic_add_return(1, &pciehp_num_controllers) == 1) { | 1065 | if (atomic_add_return(1, &pciehp_num_controllers) == 1) { |
1072 | pciehp_wq = create_singlethread_workqueue("pciehpd"); | 1066 | pciehp_wq = create_singlethread_workqueue("pciehpd"); |
1073 | if (!pciehp_wq) | 1067 | if (!pciehp_wq) |
1074 | goto abort_ctrl; | 1068 | goto abort_ctrl; |
1075 | } | 1069 | } |
1076 | 1070 | ||
1077 | ctrl_info(ctrl, "HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", | 1071 | ctrl_info(ctrl, "HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", |
1078 | pdev->vendor, pdev->device, pdev->subsystem_vendor, | 1072 | pdev->vendor, pdev->device, pdev->subsystem_vendor, |
1079 | pdev->subsystem_device); | 1073 | pdev->subsystem_device); |
1080 | 1074 | ||
1081 | if (pcie_init_slot(ctrl)) | 1075 | if (pcie_init_slot(ctrl)) |
1082 | goto abort_ctrl; | 1076 | goto abort_ctrl; |
1083 | 1077 | ||
1084 | return ctrl; | 1078 | return ctrl; |
1085 | 1079 | ||
1086 | abort_ctrl: | 1080 | abort_ctrl: |
1087 | kfree(ctrl); | 1081 | kfree(ctrl); |
1088 | abort: | 1082 | abort: |
1089 | return NULL; | 1083 | return NULL; |
1090 | } | 1084 | } |
1091 | 1085 | ||
1092 | void pcie_release_ctrl(struct controller *ctrl) | 1086 | void pcie_release_ctrl(struct controller *ctrl) |
1093 | { | 1087 | { |
1094 | pcie_shutdown_notification(ctrl); | 1088 | pcie_shutdown_notification(ctrl); |
1095 | pcie_cleanup_slot(ctrl); | 1089 | pcie_cleanup_slot(ctrl); |
1096 | /* | 1090 | /* |
1097 | * If this is the last controller to be released, destroy the | 1091 | * If this is the last controller to be released, destroy the |
1098 | * pciehp work queue | 1092 | * pciehp work queue |
1099 | */ | 1093 | */ |
1100 | if (atomic_dec_and_test(&pciehp_num_controllers)) | 1094 | if (atomic_dec_and_test(&pciehp_num_controllers)) |
1101 | destroy_workqueue(pciehp_wq); | 1095 | destroy_workqueue(pciehp_wq); |
1102 | kfree(ctrl); | 1096 | kfree(ctrl); |
1103 | } | 1097 | } |