diff options
Diffstat (limited to 'drivers/pci/pcie/aspm.c')
| -rw-r--r-- | drivers/pci/pcie/aspm.c | 94 | 
1 files changed, 43 insertions, 51 deletions
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 52c74682601a..a96b7424c9bc 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -41,11 +41,6 @@  #define ASPM_STATE_ALL		(ASPM_STATE_L0S | ASPM_STATE_L1 |	\  				 ASPM_STATE_L1SS) -struct aspm_latency { -	u32 l0s;			/* L0s latency (nsec) */ -	u32 l1;				/* L1 latency (nsec) */ -}; -  struct pcie_link_state {  	struct pci_dev *pdev;		/* Upstream component of the Link */  	struct pci_dev *downstream;	/* Downstream component, function 0 */ @@ -65,15 +60,6 @@ struct pcie_link_state {  	u32 clkpm_enabled:1;		/* Current Clock PM state */  	u32 clkpm_default:1;		/* Default Clock PM state by BIOS */  	u32 clkpm_disable:1;		/* Clock PM disabled */ - -	/* Exit latencies */ -	struct aspm_latency latency_up;	/* Upstream direction exit latency */ -	struct aspm_latency latency_dw;	/* Downstream direction exit latency */ -	/* -	 * Endpoint acceptable latencies. A pcie downstream port only -	 * has one slot under it, so at most there are 8 functions. -	 */ -	struct aspm_latency acceptable[8];  };  static int aspm_disabled, aspm_force; @@ -105,6 +91,20 @@ static const char *policy_str[] = {  #define LINK_RETRAIN_TIMEOUT HZ +/* + * The L1 PM substate capability is only implemented in function 0 in a + * multi function device. + */ +static struct pci_dev *pci_function_0(struct pci_bus *linkbus) +{ +	struct pci_dev *child; + +	list_for_each_entry(child, &linkbus->devices, bus_list) +		if (PCI_FUNC(child->devfn) == 0) +			return child; +	return NULL; +} +  static int policy_to_aspm_state(struct pcie_link_state *link)  {  	switch (aspm_policy) { @@ -378,8 +378,10 @@ static void encode_l12_threshold(u32 threshold_us, u32 *scale, u32 *value)  static void pcie_aspm_check_latency(struct pci_dev *endpoint)  { -	u32 latency, l1_switch_latency = 0; -	struct aspm_latency *acceptable; +	u32 latency, encoding, lnkcap_up, lnkcap_dw; +	u32 l1_switch_latency = 0, latency_up_l0s; +	u32 latency_up_l1, latency_dw_l0s, latency_dw_l1; +	u32 acceptable_l0s, acceptable_l1;  	struct pcie_link_state *link;  	/* Device not in D0 doesn't need latency check */ @@ -388,17 +390,36 @@ static void pcie_aspm_check_latency(struct pci_dev *endpoint)  		return;  	link = endpoint->bus->self->link_state; -	acceptable = &link->acceptable[PCI_FUNC(endpoint->devfn)]; + +	/* Calculate endpoint L0s acceptable latency */ +	encoding = (endpoint->devcap & PCI_EXP_DEVCAP_L0S) >> 6; +	acceptable_l0s = calc_l0s_acceptable(encoding); + +	/* Calculate endpoint L1 acceptable latency */ +	encoding = (endpoint->devcap & PCI_EXP_DEVCAP_L1) >> 9; +	acceptable_l1 = calc_l1_acceptable(encoding);  	while (link) { +		struct pci_dev *dev = pci_function_0(link->pdev->subordinate); + +		/* Read direction exit latencies */ +		pcie_capability_read_dword(link->pdev, PCI_EXP_LNKCAP, +					   &lnkcap_up); +		pcie_capability_read_dword(dev, PCI_EXP_LNKCAP, +					   &lnkcap_dw); +		latency_up_l0s = calc_l0s_latency(lnkcap_up); +		latency_up_l1 = calc_l1_latency(lnkcap_up); +		latency_dw_l0s = calc_l0s_latency(lnkcap_dw); +		latency_dw_l1 = calc_l1_latency(lnkcap_dw); +  		/* Check upstream direction L0s latency */  		if ((link->aspm_capable & ASPM_STATE_L0S_UP) && -		    (link->latency_up.l0s > acceptable->l0s)) +		    (latency_up_l0s > acceptable_l0s))  			link->aspm_capable &= ~ASPM_STATE_L0S_UP;  		/* Check downstream direction L0s latency */  		if ((link->aspm_capable & ASPM_STATE_L0S_DW) && -		    (link->latency_dw.l0s > acceptable->l0s)) +		    (latency_dw_l0s > acceptable_l0s))  			link->aspm_capable &= ~ASPM_STATE_L0S_DW;  		/*  		 * Check L1 latency. @@ -413,9 +434,9 @@ static void pcie_aspm_check_latency(struct pci_dev *endpoint)  		 * L1 exit latencies advertised by a device include L1  		 * substate latencies (and hence do not do any check).  		 */ -		latency = max_t(u32, link->latency_up.l1, link->latency_dw.l1); +		latency = max_t(u32, latency_up_l1, latency_dw_l1);  		if ((link->aspm_capable & ASPM_STATE_L1) && -		    (latency + l1_switch_latency > acceptable->l1)) +		    (latency + l1_switch_latency > acceptable_l1))  			link->aspm_capable &= ~ASPM_STATE_L1;  		l1_switch_latency += 1000; @@ -423,20 +444,6 @@ static void pcie_aspm_check_latency(struct pci_dev *endpoint)  	}  } -/* - * The L1 PM substate capability is only implemented in function 0 in a - * multi function device. - */ -static struct pci_dev *pci_function_0(struct pci_bus *linkbus) -{ -	struct pci_dev *child; - -	list_for_each_entry(child, &linkbus->devices, bus_list) -		if (PCI_FUNC(child->devfn) == 0) -			return child; -	return NULL; -} -  static void pci_clear_and_set_dword(struct pci_dev *pdev, int pos,  				    u32 clear, u32 set)  { @@ -496,6 +503,7 @@ static void aspm_calc_l1ss_info(struct pcie_link_state *link,  	encode_l12_threshold(l1_2_threshold, &scale, &value);  	ctl1 |= t_common_mode << 8 | scale << 29 | value << 16; +	/* Some broken devices only support dword access to L1 SS */  	pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1, &pctl1);  	pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CTL2, &pctl2);  	pci_read_config_dword(child, child->l1ss + PCI_L1SS_CTL1, &cctl1); @@ -593,8 +601,6 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)  		link->aspm_enabled |= ASPM_STATE_L0S_UP;  	if (parent_lnkctl & PCI_EXP_LNKCTL_ASPM_L0S)  		link->aspm_enabled |= ASPM_STATE_L0S_DW; -	link->latency_up.l0s = calc_l0s_latency(parent_lnkcap); -	link->latency_dw.l0s = calc_l0s_latency(child_lnkcap);  	/* Setup L1 state */  	if (parent_lnkcap & child_lnkcap & PCI_EXP_LNKCAP_ASPM_L1) @@ -602,8 +608,6 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)  	if (parent_lnkctl & child_lnkctl & PCI_EXP_LNKCTL_ASPM_L1)  		link->aspm_enabled |= ASPM_STATE_L1; -	link->latency_up.l1 = calc_l1_latency(parent_lnkcap); -	link->latency_dw.l1 = calc_l1_latency(child_lnkcap);  	/* Setup L1 substate */  	pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CAP, @@ -660,22 +664,10 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)  	/* Get and check endpoint acceptable latencies */  	list_for_each_entry(child, &linkbus->devices, bus_list) { -		u32 reg32, encoding; -		struct aspm_latency *acceptable = -			&link->acceptable[PCI_FUNC(child->devfn)]; -  		if (pci_pcie_type(child) != PCI_EXP_TYPE_ENDPOINT &&  		    pci_pcie_type(child) != PCI_EXP_TYPE_LEG_END)  			continue; -		pcie_capability_read_dword(child, PCI_EXP_DEVCAP, ®32); -		/* Calculate endpoint L0s acceptable latency */ -		encoding = (reg32 & PCI_EXP_DEVCAP_L0S) >> 6; -		acceptable->l0s = calc_l0s_acceptable(encoding); -		/* Calculate endpoint L1 acceptable latency */ -		encoding = (reg32 & PCI_EXP_DEVCAP_L1) >> 9; -		acceptable->l1 = calc_l1_acceptable(encoding); -  		pcie_aspm_check_latency(child);  	}  }  |