[PATCH 2/2] pciehp: poll data link layer link active

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch adds polling mechanism for Data Link Layer Link Active bit
after turning power on, instead of waiting for 1000 msec. This would
reduce the unnecessary long wait.

Signed-off-by: Kenji Kaneshige <kaneshige.kenji@xxxxxxxxxxxxxx>

---
 drivers/pci/hotplug/pciehp.h      |    1 
 drivers/pci/hotplug/pciehp_ctrl.c |    3 --
 drivers/pci/hotplug/pciehp_hpc.c  |   55 +++++++++++++++++++++++++++++++++++++-
 3 files changed, 55 insertions(+), 4 deletions(-)

Index: 20081022/drivers/pci/hotplug/pciehp.h
===================================================================
--- 20081022.orig/drivers/pci/hotplug/pciehp.h
+++ 20081022/drivers/pci/hotplug/pciehp.h
@@ -110,6 +110,7 @@ struct controller {
 	struct timer_list poll_timer;
 	int cmd_busy;
 	unsigned int no_cmd_complete:1;
+	unsigned int link_active_reporting:1;
 };
 
 #define INT_BUTTON_IGNORE		0
Index: 20081022/drivers/pci/hotplug/pciehp_ctrl.c
===================================================================
--- 20081022.orig/drivers/pci/hotplug/pciehp_ctrl.c
+++ 20081022/drivers/pci/hotplug/pciehp_ctrl.c
@@ -226,9 +226,6 @@ static int board_added(struct slot *p_sl
 	if (PWR_LED(ctrl))
 		p_slot->hpc_ops->green_led_blink(p_slot);
 
-	/* Wait for ~1 second */
-	msleep(1000);
-
 	/* Check link training status */
 	retval = p_slot->hpc_ops->check_lnk_status(ctrl);
 	if (retval) {
Index: 20081022/drivers/pci/hotplug/pciehp_hpc.c
===================================================================
--- 20081022.orig/drivers/pci/hotplug/pciehp_hpc.c
+++ 20081022/drivers/pci/hotplug/pciehp_hpc.c
@@ -125,6 +125,7 @@ static inline int pciehp_writel(struct c
 /* Field definitions in Link Capabilities Register */
 #define MAX_LNK_SPEED		0x000F
 #define MAX_LNK_WIDTH		0x03F0
+#define LINK_ACTIVE_REPORTING	0x00100000
 
 /* Link Width Encoding */
 #define LNK_X1		0x01
@@ -141,6 +142,7 @@ static inline int pciehp_writel(struct c
 #define LNK_TRN_ERR	0x0400
 #define	LNK_TRN		0x0800
 #define SLOT_CLK_CONF	0x1000
+#define LINK_ACTIVE	0x2000
 
 /* Field definitions in Slot Capabilities Register */
 #define ATTN_BUTTN_PRSN	0x00000001
@@ -368,11 +370,52 @@ static int pcie_write_cmd(struct control
 	return retval;
 }
 
+static inline int check_link_active(struct controller *ctrl)
+{
+	u16 link_status;
+
+	if (pciehp_readw(ctrl, LNKSTATUS, &link_status))
+		return 0;
+	return !!(link_status & LINK_ACTIVE);
+}
+
+static void pcie_wait_link_active(struct controller *ctrl)
+{
+	int timeout = 1000;
+
+	if (check_link_active(ctrl))
+		return;
+	while (timeout > 0) {
+		msleep(10);
+		timeout -= 10;
+		if (check_link_active(ctrl))
+			return;
+	}
+	ctrl_dbg(ctrl, "Data Link Layer Link Active not set in 1000 msec\n");
+}
+
 static int hpc_check_lnk_status(struct controller *ctrl)
 {
 	u16 lnk_status;
 	int retval = 0;
 
+        /*
+         * Data Link Layer Link Active Reporting must be capable for
+         * hot-plug capable downstream port. But old controller might
+         * not implement it. In this case, we wait for 1000 ms.
+         */
+        if (ctrl->link_active_reporting){
+                /* Wait for Data Link Layer Link Active bit to be set */
+                pcie_wait_link_active(ctrl);
+                /*
+                 * We must wait for 100 ms after the Data Link Layer
+                 * Link Active bit reads 1b before initiating a
+                 * configuration access to the hot added device.
+                 */
+                msleep(100);
+        } else
+                msleep(1000);
+
 	retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
 	if (retval) {
 		ctrl_err(ctrl, "%s: Cannot read LNKSTATUS register\n",
@@ -1131,7 +1174,7 @@ static inline void dbg_ctrl(struct contr
 struct controller *pcie_init(struct pcie_device *dev)
 {
 	struct controller *ctrl;
-	u32 slot_cap;
+	u32 slot_cap, link_cap;
 	struct pci_dev *pdev = dev->port;
 
 	ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
@@ -1173,6 +1216,16 @@ struct controller *pcie_init(struct pcie
 	    !(POWER_CTRL(ctrl) | ATTN_LED(ctrl) | PWR_LED(ctrl) | EMI(ctrl)))
 	    ctrl->no_cmd_complete = 1;
 
+        /* Check if Data Link Layer Link Active Reporting is implemented */
+        if (pciehp_readl(ctrl, LNKCAP, &link_cap)) {
+                ctrl_err(ctrl, "%s: Cannot read LNKCAP register\n", __func__);
+                goto abort_ctrl;
+        }
+        if (link_cap & LINK_ACTIVE_REPORTING) {
+                ctrl_dbg(ctrl, "Link Active Reporting supported\n");
+                ctrl->link_active_reporting = 1;
+        }
+
 	/* Clear all remaining event bits in Slot Status register */
 	if (pciehp_writew(ctrl, SLOTSTATUS, 0x1f))
 		goto abort_ctrl;

--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux