Skip to content

Commit

Permalink
xHCI: BESL calculation based on USB2.0 LPM errata
Browse files Browse the repository at this point in the history
The latest released errata for USB2.0 ECN LPM adds new fields to USB2.0
extension descriptor, defines two BESL values for device: baseline BESL
and deep BESL. Baseline BESL value communicates a nominal power savings
design point and the deep BESL value communicates a significant power
savings design point.

If device indicates BESL value, driver will use a value count in both
host BESL and device BESL. Use baseline BESL value as default.

Signed-off-by: Andiry Xu <andiry.xu@amd.com>
Tested-by: Jason Fan <jcfan@qca.qualcomm.com>
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
  • Loading branch information
Andiry Xu authored and Sarah Sharp committed Mar 12, 2012
1 parent f7a0d42 commit f99298b
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 24 deletions.
51 changes: 27 additions & 24 deletions drivers/usb/host/xhci.c
Original file line number Diff line number Diff line change
Expand Up @@ -3614,26 +3614,38 @@ static int xhci_besl_encoding[16] = {125, 150, 200, 300, 400, 500, 1000, 2000,
3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000};

/* Calculate HIRD/BESL for USB2 PORTPMSC*/
static int xhci_calculate_hird_besl(int u2del, bool use_besl)
static int xhci_calculate_hird_besl(struct xhci_hcd *xhci,
struct usb_device *udev)
{
int hird;
int u2del, besl, besl_host;
int besl_device = 0;
u32 field;

u2del = HCS_U2_LATENCY(xhci->hcs_params3);
field = le32_to_cpu(udev->bos->ext_cap->bmAttributes);

if (use_besl) {
for (hird = 0; hird < 16; hird++) {
if (xhci_besl_encoding[hird] >= u2del)
if (field & USB_BESL_SUPPORT) {
for (besl_host = 0; besl_host < 16; besl_host++) {
if (xhci_besl_encoding[besl_host] >= u2del)
break;
}
/* Use baseline BESL value as default */
if (field & USB_BESL_BASELINE_VALID)
besl_device = USB_GET_BESL_BASELINE(field);
else if (field & USB_BESL_DEEP_VALID)
besl_device = USB_GET_BESL_DEEP(field);
} else {
if (u2del <= 50)
hird = 0;
besl_host = 0;
else
hird = (u2del - 51) / 75 + 1;

if (hird > 15)
hird = 15;
besl_host = (u2del - 51) / 75 + 1;
}

return hird;
besl = besl_host + besl_device;
if (besl > 15)
besl = 15;

return besl;
}

static int xhci_usb2_software_lpm_test(struct usb_hcd *hcd,
Expand All @@ -3646,7 +3658,7 @@ static int xhci_usb2_software_lpm_test(struct usb_hcd *hcd,
u32 temp, dev_id;
unsigned int port_num;
unsigned long flags;
int u2del, hird;
int hird;
int ret;

if (hcd->speed == HCD_USB3 || !xhci->sw_lpm_support ||
Expand Down Expand Up @@ -3692,12 +3704,7 @@ static int xhci_usb2_software_lpm_test(struct usb_hcd *hcd,
* HIRD or BESL shoule be used. See USB2.0 LPM errata.
*/
pm_addr = port_array[port_num] + 1;
u2del = HCS_U2_LATENCY(xhci->hcs_params3);
if (le32_to_cpu(udev->bos->ext_cap->bmAttributes) & (1 << 2))
hird = xhci_calculate_hird_besl(u2del, 1);
else
hird = xhci_calculate_hird_besl(u2del, 0);

hird = xhci_calculate_hird_besl(xhci, udev);
temp = PORT_L1DS(udev->slot_id) | PORT_HIRD(hird);
xhci_writel(xhci, temp, pm_addr);

Expand Down Expand Up @@ -3776,7 +3783,7 @@ int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
u32 temp;
unsigned int port_num;
unsigned long flags;
int u2del, hird;
int hird;

if (hcd->speed == HCD_USB3 || !xhci->hw_lpm_support ||
!udev->lpm_capable)
Expand All @@ -3799,11 +3806,7 @@ int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
xhci_dbg(xhci, "%s port %d USB2 hardware LPM\n",
enable ? "enable" : "disable", port_num);

u2del = HCS_U2_LATENCY(xhci->hcs_params3);
if (le32_to_cpu(udev->bos->ext_cap->bmAttributes) & (1 << 2))
hird = xhci_calculate_hird_besl(u2del, 1);
else
hird = xhci_calculate_hird_besl(u2del, 0);
hird = xhci_calculate_hird_besl(xhci, udev);

if (enable) {
temp &= ~PORT_HIRD_MASK;
Expand Down
5 changes: 5 additions & 0 deletions include/linux/usb/ch9.h
Original file line number Diff line number Diff line change
Expand Up @@ -789,6 +789,11 @@ struct usb_ext_cap_descriptor { /* Link Power Management */
__u8 bDevCapabilityType;
__le32 bmAttributes;
#define USB_LPM_SUPPORT (1 << 1) /* supports LPM */
#define USB_BESL_SUPPORT (1 << 2) /* supports BESL */
#define USB_BESL_BASELINE_VALID (1 << 3) /* Baseline BESL valid*/
#define USB_BESL_DEEP_VALID (1 << 4) /* Deep BESL valid */
#define USB_GET_BESL_BASELINE(p) (((p) & (0xf << 8)) >> 8)
#define USB_GET_BESL_DEEP(p) (((p) & (0xf << 12)) >> 12)
} __attribute__((packed));

#define USB_DT_USB_EXT_CAP_SIZE 7
Expand Down

0 comments on commit f99298b

Please sign in to comment.