diff options
author | Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> | 2008-10-22 01:31:44 -0400 |
---|---|---|
committer | Jesse Barnes <jbarnes@virtuousgeek.org> | 2008-10-22 19:42:45 -0400 |
commit | f18e9625e02bb3e5ba9e81104f14e9d904ab28c4 (patch) | |
tree | 688eb9985ec1f85e2c1869a7252004789fb09a14 /drivers | |
parent | b84346ef74cf76793070762b933387729c5df1ed (diff) |
PCI hotplug: pciehp: poll data link layer link active
This patch adds polling mechanism for Data Link Layer Link Active bit
after turning power on, instead of waiting for 1000 msec. This reduces
reduce the unnecessary long wait.
Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/pci/hotplug/pciehp.h | 1 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_ctrl.c | 3 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_hpc.c | 55 |
3 files changed, 55 insertions, 4 deletions
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 394f99852e6d..a4817a841fae 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h | |||
@@ -110,6 +110,7 @@ struct controller { | |||
110 | struct timer_list poll_timer; | 110 | struct timer_list poll_timer; |
111 | int cmd_busy; | 111 | int cmd_busy; |
112 | unsigned int no_cmd_complete:1; | 112 | unsigned int no_cmd_complete:1; |
113 | unsigned int link_active_reporting:1; | ||
113 | }; | 114 | }; |
114 | 115 | ||
115 | #define INT_BUTTON_IGNORE 0 | 116 | #define INT_BUTTON_IGNORE 0 |
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index cce6e5f659e8..d6c5eb297753 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c | |||
@@ -226,9 +226,6 @@ static int board_added(struct slot *p_slot) | |||
226 | if (PWR_LED(ctrl)) | 226 | if (PWR_LED(ctrl)) |
227 | p_slot->hpc_ops->green_led_blink(p_slot); | 227 | p_slot->hpc_ops->green_led_blink(p_slot); |
228 | 228 | ||
229 | /* Wait for ~1 second */ | ||
230 | msleep(1000); | ||
231 | |||
232 | /* Check link training status */ | 229 | /* Check link training status */ |
233 | retval = p_slot->hpc_ops->check_lnk_status(ctrl); | 230 | retval = p_slot->hpc_ops->check_lnk_status(ctrl); |
234 | if (retval) { | 231 | if (retval) { |
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 4b921226f888..58c72d2cc217 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c | |||
@@ -125,6 +125,7 @@ static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value) | |||
125 | /* Field definitions in Link Capabilities Register */ | 125 | /* Field definitions in Link Capabilities Register */ |
126 | #define MAX_LNK_SPEED 0x000F | 126 | #define MAX_LNK_SPEED 0x000F |
127 | #define MAX_LNK_WIDTH 0x03F0 | 127 | #define MAX_LNK_WIDTH 0x03F0 |
128 | #define LINK_ACTIVE_REPORTING 0x00100000 | ||
128 | 129 | ||
129 | /* Link Width Encoding */ | 130 | /* Link Width Encoding */ |
130 | #define LNK_X1 0x01 | 131 | #define LNK_X1 0x01 |
@@ -141,6 +142,7 @@ static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value) | |||
141 | #define LNK_TRN_ERR 0x0400 | 142 | #define LNK_TRN_ERR 0x0400 |
142 | #define LNK_TRN 0x0800 | 143 | #define LNK_TRN 0x0800 |
143 | #define SLOT_CLK_CONF 0x1000 | 144 | #define SLOT_CLK_CONF 0x1000 |
145 | #define LINK_ACTIVE 0x2000 | ||
144 | 146 | ||
145 | /* Field definitions in Slot Capabilities Register */ | 147 | /* Field definitions in Slot Capabilities Register */ |
146 | #define ATTN_BUTTN_PRSN 0x00000001 | 148 | #define ATTN_BUTTN_PRSN 0x00000001 |
@@ -368,11 +370,52 @@ static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask) | |||
368 | return retval; | 370 | return retval; |
369 | } | 371 | } |
370 | 372 | ||
373 | static inline int check_link_active(struct controller *ctrl) | ||
374 | { | ||
375 | u16 link_status; | ||
376 | |||
377 | if (pciehp_readw(ctrl, LNKSTATUS, &link_status)) | ||
378 | return 0; | ||
379 | return !!(link_status & LINK_ACTIVE); | ||
380 | } | ||
381 | |||
382 | static void pcie_wait_link_active(struct controller *ctrl) | ||
383 | { | ||
384 | int timeout = 1000; | ||
385 | |||
386 | if (check_link_active(ctrl)) | ||
387 | return; | ||
388 | while (timeout > 0) { | ||
389 | msleep(10); | ||
390 | timeout -= 10; | ||
391 | if (check_link_active(ctrl)) | ||
392 | return; | ||
393 | } | ||
394 | ctrl_dbg(ctrl, "Data Link Layer Link Active not set in 1000 msec\n"); | ||
395 | } | ||
396 | |||
371 | static int hpc_check_lnk_status(struct controller *ctrl) | 397 | static int hpc_check_lnk_status(struct controller *ctrl) |
372 | { | 398 | { |
373 | u16 lnk_status; | 399 | u16 lnk_status; |
374 | int retval = 0; | 400 | int retval = 0; |
375 | 401 | ||
402 | /* | ||
403 | * Data Link Layer Link Active Reporting must be capable for | ||
404 | * hot-plug capable downstream port. But old controller might | ||
405 | * not implement it. In this case, we wait for 1000 ms. | ||
406 | */ | ||
407 | if (ctrl->link_active_reporting){ | ||
408 | /* Wait for Data Link Layer Link Active bit to be set */ | ||
409 | pcie_wait_link_active(ctrl); | ||
410 | /* | ||
411 | * We must wait for 100 ms after the Data Link Layer | ||
412 | * Link Active bit reads 1b before initiating a | ||
413 | * configuration access to the hot added device. | ||
414 | */ | ||
415 | msleep(100); | ||
416 | } else | ||
417 | msleep(1000); | ||
418 | |||
376 | retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status); | 419 | retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status); |
377 | if (retval) { | 420 | if (retval) { |
378 | ctrl_err(ctrl, "%s: Cannot read LNKSTATUS register\n", | 421 | ctrl_err(ctrl, "%s: Cannot read LNKSTATUS register\n", |
@@ -1131,7 +1174,7 @@ static inline void dbg_ctrl(struct controller *ctrl) | |||
1131 | struct controller *pcie_init(struct pcie_device *dev) | 1174 | struct controller *pcie_init(struct pcie_device *dev) |
1132 | { | 1175 | { |
1133 | struct controller *ctrl; | 1176 | struct controller *ctrl; |
1134 | u32 slot_cap; | 1177 | u32 slot_cap, link_cap; |
1135 | struct pci_dev *pdev = dev->port; | 1178 | struct pci_dev *pdev = dev->port; |
1136 | 1179 | ||
1137 | ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); | 1180 | ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); |
@@ -1173,6 +1216,16 @@ struct controller *pcie_init(struct pcie_device *dev) | |||
1173 | !(POWER_CTRL(ctrl) | ATTN_LED(ctrl) | PWR_LED(ctrl) | EMI(ctrl))) | 1216 | !(POWER_CTRL(ctrl) | ATTN_LED(ctrl) | PWR_LED(ctrl) | EMI(ctrl))) |
1174 | ctrl->no_cmd_complete = 1; | 1217 | ctrl->no_cmd_complete = 1; |
1175 | 1218 | ||
1219 | /* Check if Data Link Layer Link Active Reporting is implemented */ | ||
1220 | if (pciehp_readl(ctrl, LNKCAP, &link_cap)) { | ||
1221 | ctrl_err(ctrl, "%s: Cannot read LNKCAP register\n", __func__); | ||
1222 | goto abort_ctrl; | ||
1223 | } | ||
1224 | if (link_cap & LINK_ACTIVE_REPORTING) { | ||
1225 | ctrl_dbg(ctrl, "Link Active Reporting supported\n"); | ||
1226 | ctrl->link_active_reporting = 1; | ||
1227 | } | ||
1228 | |||
1176 | /* Clear all remaining event bits in Slot Status register */ | 1229 | /* Clear all remaining event bits in Slot Status register */ |
1177 | if (pciehp_writew(ctrl, SLOTSTATUS, 0x1f)) | 1230 | if (pciehp_writew(ctrl, SLOTSTATUS, 0x1f)) |
1178 | goto abort_ctrl; | 1231 | goto abort_ctrl; |