Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

xhci: rework xhci extended capability list parsing functions

Replace the existing two extended capability parsing helper functions with
one called xhci_find_next_ext_cap().

The extended capabilities are read both in pci-quirks before xhci driver is
loaded, and inside the xhci driver when adding ports. The existing helpers
did not suit well for these cases and a lot of custom parsing code was
needed.

The new helper function simplifies these two cases a lot.

The motivation for this rework was that code to support xhci debug
capability needed to parse extended capabilities, and it included
yet another capability parsing helper specific for its needs. With
this solution it debug capability code can use this new helper as well

Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Mathias Nyman and committed by
Greg Kroah-Hartman
d5ddcdf4 a5da9568

+62 -115
+9 -16
drivers/usb/host/pci-quirks.c
··· 984 984 * Find the Legacy Support Capability register - 985 985 * this is optional for xHCI host controllers. 986 986 */ 987 - ext_cap_offset = xhci_find_next_cap_offset(base, XHCI_HCC_PARAMS_OFFSET); 988 - do { 989 - if ((ext_cap_offset + sizeof(val)) > len) { 990 - /* We're reading garbage from the controller */ 991 - dev_warn(&pdev->dev, 992 - "xHCI controller failing to respond"); 993 - return; 994 - } 987 + ext_cap_offset = xhci_find_next_ext_cap(base, 0, XHCI_EXT_CAPS_LEGACY); 995 988 996 - if (!ext_cap_offset) 997 - /* We've reached the end of the extended capabilities */ 998 - goto hc_init; 989 + if (!ext_cap_offset) 990 + goto hc_init; 999 991 1000 - val = readl(base + ext_cap_offset); 1001 - if (XHCI_EXT_CAPS_ID(val) == XHCI_EXT_CAPS_LEGACY) 1002 - break; 1003 - ext_cap_offset = xhci_find_next_cap_offset(base, ext_cap_offset); 1004 - } while (1); 992 + if ((ext_cap_offset + sizeof(val)) > len) { 993 + /* We're reading garbage from the controller */ 994 + dev_warn(&pdev->dev, "xHCI controller failing to respond"); 995 + return; 996 + } 997 + val = readl(base + ext_cap_offset); 1005 998 1006 999 /* If the BIOS owns the HC, signal that the OS wants it, and wait */ 1007 1000 if (val & XHCI_HC_BIOS_OWNED) {
+27 -54
drivers/usb/host/xhci-ext-caps.h
··· 91 91 #include <linux/io.h> 92 92 93 93 /** 94 - * Return the next extended capability pointer register. 95 - * 96 - * @base PCI register base address. 97 - * 98 - * @ext_offset Offset of the 32-bit register that contains the extended 99 - * capabilites pointer. If searching for the first extended capability, pass 100 - * in XHCI_HCC_PARAMS_OFFSET. If searching for the next extended capability, 101 - * pass in the offset of the current extended capability register. 102 - * 103 - * Returns 0 if there is no next extended capability register or returns the register offset 104 - * from the PCI registers base address. 105 - */ 106 - static inline int xhci_find_next_cap_offset(void __iomem *base, int ext_offset) 107 - { 108 - u32 next; 109 - 110 - next = readl(base + ext_offset); 111 - 112 - if (ext_offset == XHCI_HCC_PARAMS_OFFSET) { 113 - /* Find the first extended capability */ 114 - next = XHCI_HCC_EXT_CAPS(next); 115 - ext_offset = 0; 116 - } else { 117 - /* Find the next extended capability */ 118 - next = XHCI_EXT_CAPS_NEXT(next); 119 - } 120 - 121 - if (!next) 122 - return 0; 123 - /* 124 - * Address calculation from offset of extended capabilities 125 - * (or HCCPARAMS) register - see section 5.3.6 and section 7. 126 - */ 127 - return ext_offset + (next << 2); 128 - } 129 - 130 - /** 131 94 * Find the offset of the extended capabilities with capability ID id. 132 95 * 133 - * @base PCI MMIO registers base address. 134 - * @ext_offset Offset from base of the first extended capability to look at, 135 - * or the address of HCCPARAMS. 136 - * @id Extended capability ID to search for. 96 + * @base PCI MMIO registers base address. 97 + * @start address at which to start looking, (0 or HCC_PARAMS to start at 98 + * beginning of list) 99 + * @id Extended capability ID to search for. 137 100 * 138 - * This uses an arbitrary limit of XHCI_MAX_EXT_CAPS extended capabilities 139 - * to make sure that the list doesn't contain a loop. 101 + * Returns the offset of the next matching extended capability structure. 102 + * Some capabilities can occur several times, e.g., the XHCI_EXT_CAPS_PROTOCOL, 103 + * and this provides a way to find them all. 140 104 */ 141 - static inline int xhci_find_ext_cap_by_id(void __iomem *base, int ext_offset, int id) 105 + 106 + static inline int xhci_find_next_ext_cap(void __iomem *base, u32 start, int id) 142 107 { 143 108 u32 val; 144 - int limit = XHCI_MAX_EXT_CAPS; 109 + u32 next; 110 + u32 offset; 145 111 146 - while (ext_offset && limit > 0) { 147 - val = readl(base + ext_offset); 148 - if (XHCI_EXT_CAPS_ID(val) == id) 149 - break; 150 - ext_offset = xhci_find_next_cap_offset(base, ext_offset); 151 - limit--; 152 - } 153 - if (limit > 0) 154 - return ext_offset; 112 + offset = start; 113 + if (!start || start == XHCI_HCC_PARAMS_OFFSET) { 114 + val = readl(base + XHCI_HCC_PARAMS_OFFSET); 115 + offset = XHCI_HCC_EXT_CAPS(val) << 2; 116 + if (!offset) 117 + return 0; 118 + }; 119 + do { 120 + val = readl(base + offset); 121 + if (XHCI_EXT_CAPS_ID(val) == id && offset != start) 122 + return offset; 123 + 124 + next = XHCI_EXT_CAPS_NEXT(val); 125 + offset += next << 2; 126 + } while (next); 127 + 155 128 return 0; 156 129 }
+26 -45
drivers/usb/host/xhci-mem.c
··· 2064 2064 } 2065 2065 2066 2066 static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, 2067 - __le32 __iomem *addr, u8 major_revision, int max_caps) 2067 + __le32 __iomem *addr, int max_caps) 2068 2068 { 2069 2069 u32 temp, port_offset, port_count; 2070 2070 int i; 2071 + u8 major_revision; 2071 2072 struct xhci_hub *rhub; 2072 2073 2073 2074 temp = readl(addr); 2075 + major_revision = XHCI_EXT_PORT_MAJOR(temp); 2074 2076 2075 - if (XHCI_EXT_PORT_MAJOR(temp) == 0x03) { 2077 + if (major_revision == 0x03) { 2076 2078 rhub = &xhci->usb3_rhub; 2077 - } else if (XHCI_EXT_PORT_MAJOR(temp) <= 0x02) { 2079 + } else if (major_revision <= 0x02) { 2078 2080 rhub = &xhci->usb2_rhub; 2079 2081 } else { 2080 2082 xhci_warn(xhci, "Ignoring unknown port speed, " ··· 2192 2190 */ 2193 2191 static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags) 2194 2192 { 2195 - __le32 __iomem *addr, *tmp_addr; 2196 - u32 offset, tmp_offset; 2193 + void __iomem *base; 2194 + u32 offset; 2197 2195 unsigned int num_ports; 2198 2196 int i, j, port_index; 2199 2197 int cap_count = 0; 2200 - 2201 - addr = &xhci->cap_regs->hcc_params; 2202 - offset = XHCI_HCC_EXT_CAPS(readl(addr)); 2203 - if (offset == 0) { 2204 - xhci_err(xhci, "No Extended Capability registers, " 2205 - "unable to set up roothub.\n"); 2206 - return -ENODEV; 2207 - } 2198 + u32 cap_start; 2208 2199 2209 2200 num_ports = HCS_MAX_PORTS(xhci->hcs_params1); 2210 2201 xhci->port_array = kzalloc(sizeof(*xhci->port_array)*num_ports, flags); ··· 2215 2220 for (j = 0; j < XHCI_MAX_INTERVAL; j++) 2216 2221 INIT_LIST_HEAD(&bw_table->interval_bw[j].endpoints); 2217 2222 } 2223 + base = &xhci->cap_regs->hc_capbase; 2218 2224 2219 - /* 2220 - * For whatever reason, the first capability offset is from the 2221 - * capability register base, not from the HCCPARAMS register. 2222 - * See section 5.3.6 for offset calculation. 2223 - */ 2224 - addr = &xhci->cap_regs->hc_capbase + offset; 2225 + cap_start = xhci_find_next_ext_cap(base, 0, XHCI_EXT_CAPS_PROTOCOL); 2226 + if (!cap_start) { 2227 + xhci_err(xhci, "No Extended Capability registers, unable to set up roothub\n"); 2228 + return -ENODEV; 2229 + } 2225 2230 2226 - tmp_addr = addr; 2227 - tmp_offset = offset; 2228 - 2231 + offset = cap_start; 2229 2232 /* count extended protocol capability entries for later caching */ 2230 - do { 2231 - u32 cap_id; 2232 - cap_id = readl(tmp_addr); 2233 - if (XHCI_EXT_CAPS_ID(cap_id) == XHCI_EXT_CAPS_PROTOCOL) 2234 - cap_count++; 2235 - tmp_offset = XHCI_EXT_CAPS_NEXT(cap_id); 2236 - tmp_addr += tmp_offset; 2237 - } while (tmp_offset); 2233 + while (offset) { 2234 + cap_count++; 2235 + offset = xhci_find_next_ext_cap(base, offset, 2236 + XHCI_EXT_CAPS_PROTOCOL); 2237 + } 2238 2238 2239 2239 xhci->ext_caps = kzalloc(sizeof(*xhci->ext_caps) * cap_count, flags); 2240 2240 if (!xhci->ext_caps) 2241 2241 return -ENOMEM; 2242 2242 2243 - while (1) { 2244 - u32 cap_id; 2243 + offset = cap_start; 2245 2244 2246 - cap_id = readl(addr); 2247 - if (XHCI_EXT_CAPS_ID(cap_id) == XHCI_EXT_CAPS_PROTOCOL) 2248 - xhci_add_in_port(xhci, num_ports, addr, 2249 - (u8) XHCI_EXT_PORT_MAJOR(cap_id), 2250 - cap_count); 2251 - offset = XHCI_EXT_CAPS_NEXT(cap_id); 2252 - if (!offset || (xhci->num_usb2_ports + xhci->num_usb3_ports) 2253 - == num_ports) 2245 + while (offset) { 2246 + xhci_add_in_port(xhci, num_ports, base + offset, cap_count); 2247 + if (xhci->num_usb2_ports + xhci->num_usb3_ports == num_ports) 2254 2248 break; 2255 - /* 2256 - * Once you're into the Extended Capabilities, the offset is 2257 - * always relative to the register holding the offset. 2258 - */ 2259 - addr += offset; 2249 + offset = xhci_find_next_ext_cap(base, offset, 2250 + XHCI_EXT_CAPS_PROTOCOL); 2260 2251 } 2261 2252 2262 2253 if (xhci->num_usb2_ports == 0 && xhci->num_usb3_ports == 0) {