PCI/ASPM: Remove struct aspm_register_info.l1ss_cap
[linux-2.6-microblaze.git] / drivers / pci / pcie / aspm.c
index 253c30c..d76f239 100644 (file)
@@ -77,8 +77,6 @@ struct pcie_link_state {
 
        /* L1 PM Substate info */
        struct {
-               u32 up_cap_ptr;         /* L1SS cap ptr in upstream dev */
-               u32 dw_cap_ptr;         /* L1SS cap ptr in downstream dev */
                u32 ctl1;               /* value to be programmed in ctl1 */
                u32 ctl2;               /* value to be programmed in ctl2 */
        } l1ss;
@@ -308,8 +306,10 @@ static void pcie_aspm_configure_common_clock(struct pcie_link_state *link)
 }
 
 /* Convert L0s latency encoding to ns */
-static u32 calc_l0s_latency(u32 encoding)
+static u32 calc_l0s_latency(u32 lnkcap)
 {
+       u32 encoding = (lnkcap & PCI_EXP_LNKCAP_L0SEL) >> 12;
+
        if (encoding == 0x7)
                return (5 * 1000);      /* > 4us */
        return (64 << encoding);
@@ -324,8 +324,10 @@ static u32 calc_l0s_acceptable(u32 encoding)
 }
 
 /* Convert L1 latency encoding to ns */
-static u32 calc_l1_latency(u32 encoding)
+static u32 calc_l1_latency(u32 lnkcap)
 {
+       u32 encoding = (lnkcap & PCI_EXP_LNKCAP_L1EL) >> 15;
+
        if (encoding == 0x7)
                return (65 * 1000);     /* > 64us */
        return (1000 << encoding);
@@ -380,58 +382,6 @@ static void encode_l12_threshold(u32 threshold_us, u32 *scale, u32 *value)
        }
 }
 
-struct aspm_register_info {
-       u32 support:2;
-       u32 enabled:2;
-       u32 latency_encoding_l0s;
-       u32 latency_encoding_l1;
-
-       /* L1 substates */
-       u32 l1ss_cap_ptr;
-       u32 l1ss_cap;
-       u32 l1ss_ctl1;
-       u32 l1ss_ctl2;
-};
-
-static void pcie_get_aspm_reg(struct pci_dev *pdev,
-                             struct aspm_register_info *info)
-{
-       u16 reg16;
-       u32 reg32;
-
-       pcie_capability_read_dword(pdev, PCI_EXP_LNKCAP, &reg32);
-       info->support = (reg32 & PCI_EXP_LNKCAP_ASPMS) >> 10;
-       info->latency_encoding_l0s = (reg32 & PCI_EXP_LNKCAP_L0SEL) >> 12;
-       info->latency_encoding_l1  = (reg32 & PCI_EXP_LNKCAP_L1EL) >> 15;
-       pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &reg16);
-       info->enabled = reg16 & PCI_EXP_LNKCTL_ASPMC;
-
-       /* Read L1 PM substate capabilities */
-       info->l1ss_cap = info->l1ss_ctl1 = info->l1ss_ctl2 = 0;
-       info->l1ss_cap_ptr = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS);
-       if (!info->l1ss_cap_ptr)
-               return;
-       pci_read_config_dword(pdev, info->l1ss_cap_ptr + PCI_L1SS_CAP,
-                             &info->l1ss_cap);
-       if (!(info->l1ss_cap & PCI_L1SS_CAP_L1_PM_SS)) {
-               info->l1ss_cap = 0;
-               return;
-       }
-
-       /*
-        * If we don't have LTR for the entire path from the Root Complex
-        * to this device, we can't use ASPM L1.2 because it relies on the
-        * LTR_L1.2_THRESHOLD.  See PCIe r4.0, secs 5.5.4, 6.18.
-        */
-       if (!pdev->ltr_path)
-               info->l1ss_cap &= ~PCI_L1SS_CAP_ASPM_L1_2;
-
-       pci_read_config_dword(pdev, info->l1ss_cap_ptr + PCI_L1SS_CTL1,
-                             &info->l1ss_ctl1);
-       pci_read_config_dword(pdev, info->l1ss_cap_ptr + PCI_L1SS_CTL2,
-                             &info->l1ss_ctl2);
-}
-
 static void pcie_aspm_check_latency(struct pci_dev *endpoint)
 {
        u32 latency, l1_switch_latency = 0;
@@ -493,39 +443,48 @@ static struct pci_dev *pci_function_0(struct pci_bus *linkbus)
        return NULL;
 }
 
+static void pci_clear_and_set_dword(struct pci_dev *pdev, int pos,
+                                   u32 clear, u32 set)
+{
+       u32 val;
+
+       pci_read_config_dword(pdev, pos, &val);
+       val &= ~clear;
+       val |= set;
+       pci_write_config_dword(pdev, pos, val);
+}
+
 /* Calculate L1.2 PM substate timing parameters */
 static void aspm_calc_l1ss_info(struct pcie_link_state *link,
-                               struct aspm_register_info *upreg,
-                               struct aspm_register_info *dwreg)
+                               u32 parent_l1ss_cap, u32 child_l1ss_cap)
 {
+       struct pci_dev *child = link->downstream, *parent = link->pdev;
        u32 val1, val2, scale1, scale2;
        u32 t_common_mode, t_power_on, l1_2_threshold, scale, value;
 
-       link->l1ss.up_cap_ptr = upreg->l1ss_cap_ptr;
-       link->l1ss.dw_cap_ptr = dwreg->l1ss_cap_ptr;
        link->l1ss.ctl1 = link->l1ss.ctl2 = 0;
 
        if (!(link->aspm_support & ASPM_STATE_L1_2_MASK))
                return;
 
        /* Choose the greater of the two Port Common_Mode_Restore_Times */
-       val1 = (upreg->l1ss_cap & PCI_L1SS_CAP_CM_RESTORE_TIME) >> 8;
-       val2 = (dwreg->l1ss_cap & PCI_L1SS_CAP_CM_RESTORE_TIME) >> 8;
+       val1 = (parent_l1ss_cap & PCI_L1SS_CAP_CM_RESTORE_TIME) >> 8;
+       val2 = (child_l1ss_cap & PCI_L1SS_CAP_CM_RESTORE_TIME) >> 8;
        t_common_mode = max(val1, val2);
 
        /* Choose the greater of the two Port T_POWER_ON times */
-       val1   = (upreg->l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_VALUE) >> 19;
-       scale1 = (upreg->l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_SCALE) >> 16;
-       val2   = (dwreg->l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_VALUE) >> 19;
-       scale2 = (dwreg->l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_SCALE) >> 16;
+       val1   = (parent_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_VALUE) >> 19;
+       scale1 = (parent_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_SCALE) >> 16;
+       val2   = (child_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_VALUE) >> 19;
+       scale2 = (child_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_SCALE) >> 16;
 
-       if (calc_l1ss_pwron(link->pdev, scale1, val1) >
-           calc_l1ss_pwron(link->downstream, scale2, val2)) {
+       if (calc_l1ss_pwron(parent, scale1, val1) >
+           calc_l1ss_pwron(child, scale2, val2)) {
                link->l1ss.ctl2 |= scale1 | (val1 << 3);
-               t_power_on = calc_l1ss_pwron(link->pdev, scale1, val1);
+               t_power_on = calc_l1ss_pwron(parent, scale1, val1);
        } else {
                link->l1ss.ctl2 |= scale2 | (val2 << 3);
-               t_power_on = calc_l1ss_pwron(link->downstream, scale2, val2);
+               t_power_on = calc_l1ss_pwron(child, scale2, val2);
        }
 
        /*
@@ -546,8 +505,11 @@ static void aspm_calc_l1ss_info(struct pcie_link_state *link,
 static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
 {
        struct pci_dev *child = link->downstream, *parent = link->pdev;
+       u32 parent_lnkcap, child_lnkcap;
+       u16 parent_lnkctl, child_lnkctl;
+       u32 parent_l1ss_cap, child_l1ss_cap;
+       u32 parent_l1ss_ctl1 = 0, child_l1ss_ctl1 = 0;
        struct pci_bus *linkbus = parent->subordinate;
-       struct aspm_register_info upreg, dwreg;
 
        if (blacklist) {
                /* Set enabled/disable so that we will disable ASPM later */
@@ -556,26 +518,28 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
                return;
        }
 
-       /* Get upstream/downstream components' register state */
-       pcie_get_aspm_reg(parent, &upreg);
-       pcie_get_aspm_reg(child, &dwreg);
-
        /*
         * If ASPM not supported, don't mess with the clocks and link,
         * bail out now.
         */
-       if (!(upreg.support & dwreg.support))
+       pcie_capability_read_dword(parent, PCI_EXP_LNKCAP, &parent_lnkcap);
+       pcie_capability_read_dword(child, PCI_EXP_LNKCAP, &child_lnkcap);
+       if (!(parent_lnkcap & child_lnkcap & PCI_EXP_LNKCAP_ASPMS))
                return;
 
        /* Configure common clock before checking latencies */
        pcie_aspm_configure_common_clock(link);
 
        /*
-        * Re-read upstream/downstream components' register state
-        * after clock configuration
+        * Re-read upstream/downstream components' register state after
+        * clock configuration.  L0s & L1 exit latencies in the otherwise
+        * read-only Link Capabilities may change depending on common clock
+        * configuration (PCIe r5.0, sec 7.5.3.6).
         */
-       pcie_get_aspm_reg(parent, &upreg);
-       pcie_get_aspm_reg(child, &dwreg);
+       pcie_capability_read_dword(parent, PCI_EXP_LNKCAP, &parent_lnkcap);
+       pcie_capability_read_dword(child, PCI_EXP_LNKCAP, &child_lnkcap);
+       pcie_capability_read_word(parent, PCI_EXP_LNKCTL, &parent_lnkctl);
+       pcie_capability_read_word(child, PCI_EXP_LNKCTL, &child_lnkctl);
 
        /*
         * Setup L0s state
@@ -584,44 +548,71 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
         * given link unless components on both sides of the link each
         * support L0s.
         */
-       if (dwreg.support & upreg.support & PCIE_LINK_STATE_L0S)
+       if (parent_lnkcap & child_lnkcap & PCI_EXP_LNKCAP_ASPM_L0S)
                link->aspm_support |= ASPM_STATE_L0S;
-       if (dwreg.enabled & PCIE_LINK_STATE_L0S)
+
+       if (child_lnkctl & PCI_EXP_LNKCTL_ASPM_L0S)
                link->aspm_enabled |= ASPM_STATE_L0S_UP;
-       if (upreg.enabled & PCIE_LINK_STATE_L0S)
+       if (parent_lnkctl & PCI_EXP_LNKCTL_ASPM_L0S)
                link->aspm_enabled |= ASPM_STATE_L0S_DW;
-       link->latency_up.l0s = calc_l0s_latency(upreg.latency_encoding_l0s);
-       link->latency_dw.l0s = calc_l0s_latency(dwreg.latency_encoding_l0s);
+       link->latency_up.l0s = calc_l0s_latency(parent_lnkcap);
+       link->latency_dw.l0s = calc_l0s_latency(child_lnkcap);
 
        /* Setup L1 state */
-       if (upreg.support & dwreg.support & PCIE_LINK_STATE_L1)
+       if (parent_lnkcap & child_lnkcap & PCI_EXP_LNKCAP_ASPM_L1)
                link->aspm_support |= ASPM_STATE_L1;
-       if (upreg.enabled & dwreg.enabled & PCIE_LINK_STATE_L1)
+
+       if (parent_lnkctl & child_lnkctl & PCI_EXP_LNKCTL_ASPM_L1)
                link->aspm_enabled |= ASPM_STATE_L1;
-       link->latency_up.l1 = calc_l1_latency(upreg.latency_encoding_l1);
-       link->latency_dw.l1 = calc_l1_latency(dwreg.latency_encoding_l1);
+       link->latency_up.l1 = calc_l1_latency(parent_lnkcap);
+       link->latency_dw.l1 = calc_l1_latency(child_lnkcap);
 
        /* Setup L1 substate */
-       if (upreg.l1ss_cap & dwreg.l1ss_cap & PCI_L1SS_CAP_ASPM_L1_1)
+       pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CAP,
+                             &parent_l1ss_cap);
+       pci_read_config_dword(child, child->l1ss + PCI_L1SS_CAP,
+                             &child_l1ss_cap);
+
+       if (!(parent_l1ss_cap & PCI_L1SS_CAP_L1_PM_SS))
+               parent_l1ss_cap = 0;
+       if (!(child_l1ss_cap & PCI_L1SS_CAP_L1_PM_SS))
+               child_l1ss_cap = 0;
+
+       /*
+        * If we don't have LTR for the entire path from the Root Complex
+        * to this device, we can't use ASPM L1.2 because it relies on the
+        * LTR_L1.2_THRESHOLD.  See PCIe r4.0, secs 5.5.4, 6.18.
+        */
+       if (!child->ltr_path)
+               child_l1ss_cap &= ~PCI_L1SS_CAP_ASPM_L1_2;
+
+       if (parent_l1ss_cap & child_l1ss_cap & PCI_L1SS_CAP_ASPM_L1_1)
                link->aspm_support |= ASPM_STATE_L1_1;
-       if (upreg.l1ss_cap & dwreg.l1ss_cap & PCI_L1SS_CAP_ASPM_L1_2)
+       if (parent_l1ss_cap & child_l1ss_cap & PCI_L1SS_CAP_ASPM_L1_2)
                link->aspm_support |= ASPM_STATE_L1_2;
-       if (upreg.l1ss_cap & dwreg.l1ss_cap & PCI_L1SS_CAP_PCIPM_L1_1)
+       if (parent_l1ss_cap & child_l1ss_cap & PCI_L1SS_CAP_PCIPM_L1_1)
                link->aspm_support |= ASPM_STATE_L1_1_PCIPM;
-       if (upreg.l1ss_cap & dwreg.l1ss_cap & PCI_L1SS_CAP_PCIPM_L1_2)
+       if (parent_l1ss_cap & child_l1ss_cap & PCI_L1SS_CAP_PCIPM_L1_2)
                link->aspm_support |= ASPM_STATE_L1_2_PCIPM;
 
-       if (upreg.l1ss_ctl1 & dwreg.l1ss_ctl1 & PCI_L1SS_CTL1_ASPM_L1_1)
+       if (parent_l1ss_cap)
+               pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
+                                     &parent_l1ss_ctl1);
+       if (child_l1ss_cap)
+               pci_read_config_dword(child, child->l1ss + PCI_L1SS_CTL1,
+                                     &child_l1ss_ctl1);
+
+       if (parent_l1ss_ctl1 & child_l1ss_ctl1 & PCI_L1SS_CTL1_ASPM_L1_1)
                link->aspm_enabled |= ASPM_STATE_L1_1;
-       if (upreg.l1ss_ctl1 & dwreg.l1ss_ctl1 & PCI_L1SS_CTL1_ASPM_L1_2)
+       if (parent_l1ss_ctl1 & child_l1ss_ctl1 & PCI_L1SS_CTL1_ASPM_L1_2)
                link->aspm_enabled |= ASPM_STATE_L1_2;
-       if (upreg.l1ss_ctl1 & dwreg.l1ss_ctl1 & PCI_L1SS_CTL1_PCIPM_L1_1)
+       if (parent_l1ss_ctl1 & child_l1ss_ctl1 & PCI_L1SS_CTL1_PCIPM_L1_1)
                link->aspm_enabled |= ASPM_STATE_L1_1_PCIPM;
-       if (upreg.l1ss_ctl1 & dwreg.l1ss_ctl1 & PCI_L1SS_CTL1_PCIPM_L1_2)
+       if (parent_l1ss_ctl1 & child_l1ss_ctl1 & PCI_L1SS_CTL1_PCIPM_L1_2)
                link->aspm_enabled |= ASPM_STATE_L1_2_PCIPM;
 
        if (link->aspm_support & ASPM_STATE_L1SS)
-               aspm_calc_l1ss_info(link, &upreg, &dwreg);
+               aspm_calc_l1ss_info(link, parent_l1ss_cap, child_l1ss_cap);
 
        /* Save default state */
        link->aspm_default = link->aspm_enabled;
@@ -651,24 +642,11 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
        }
 }
 
-static void pci_clear_and_set_dword(struct pci_dev *pdev, int pos,
-                                   u32 clear, u32 set)
-{
-       u32 val;
-
-       pci_read_config_dword(pdev, pos, &val);
-       val &= ~clear;
-       val |= set;
-       pci_write_config_dword(pdev, pos, val);
-}
-
 /* Configure the ASPM L1 substates */
 static void pcie_config_aspm_l1ss(struct pcie_link_state *link, u32 state)
 {
        u32 val, enable_req;
        struct pci_dev *child = link->downstream, *parent = link->pdev;
-       u32 up_cap_ptr = link->l1ss.up_cap_ptr;
-       u32 dw_cap_ptr = link->l1ss.dw_cap_ptr;
 
        enable_req = (link->aspm_enabled ^ state) & state;
 
@@ -686,9 +664,9 @@ static void pcie_config_aspm_l1ss(struct pcie_link_state *link, u32 state)
         */
 
        /* Disable all L1 substates */
-       pci_clear_and_set_dword(child, dw_cap_ptr + PCI_L1SS_CTL1,
+       pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1,
                                PCI_L1SS_CTL1_L1SS_MASK, 0);
-       pci_clear_and_set_dword(parent, up_cap_ptr + PCI_L1SS_CTL1,
+       pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
                                PCI_L1SS_CTL1_L1SS_MASK, 0);
        /*
         * If needed, disable L1, and it gets enabled later
@@ -704,22 +682,22 @@ static void pcie_config_aspm_l1ss(struct pcie_link_state *link, u32 state)
        if (enable_req & ASPM_STATE_L1_2_MASK) {
 
                /* Program T_POWER_ON times in both ports */
-               pci_write_config_dword(parent, up_cap_ptr + PCI_L1SS_CTL2,
+               pci_write_config_dword(parent, parent->l1ss + PCI_L1SS_CTL2,
                                       link->l1ss.ctl2);
-               pci_write_config_dword(child, dw_cap_ptr + PCI_L1SS_CTL2,
+               pci_write_config_dword(child, child->l1ss + PCI_L1SS_CTL2,
                                       link->l1ss.ctl2);
 
                /* Program Common_Mode_Restore_Time in upstream device */
-               pci_clear_and_set_dword(parent, up_cap_ptr + PCI_L1SS_CTL1,
+               pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
                                        PCI_L1SS_CTL1_CM_RESTORE_TIME,
                                        link->l1ss.ctl1);
 
                /* Program LTR_L1.2_THRESHOLD time in both ports */
-               pci_clear_and_set_dword(parent, up_cap_ptr + PCI_L1SS_CTL1,
+               pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
                                        PCI_L1SS_CTL1_LTR_L12_TH_VALUE |
                                        PCI_L1SS_CTL1_LTR_L12_TH_SCALE,
                                        link->l1ss.ctl1);
-               pci_clear_and_set_dword(child, dw_cap_ptr + PCI_L1SS_CTL1,
+               pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1,
                                        PCI_L1SS_CTL1_LTR_L12_TH_VALUE |
                                        PCI_L1SS_CTL1_LTR_L12_TH_SCALE,
                                        link->l1ss.ctl1);
@@ -736,9 +714,9 @@ static void pcie_config_aspm_l1ss(struct pcie_link_state *link, u32 state)
                val |= PCI_L1SS_CTL1_PCIPM_L1_2;
 
        /* Enable what we need to enable */
-       pci_clear_and_set_dword(parent, up_cap_ptr + PCI_L1SS_CTL1,
+       pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
                                PCI_L1SS_CTL1_L1SS_MASK, val);
-       pci_clear_and_set_dword(child, dw_cap_ptr + PCI_L1SS_CTL1,
+       pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1,
                                PCI_L1SS_CTL1_L1SS_MASK, val);
 }