xhci: harden xhci_find_next_ext_cap against device removal

xhci_find_next_ext_cap doesn't check for PCI hotplug removal and may use
the PCI master abort bit pattern (~0) to calculate a new PCI address
offset to read/write.  The has lead to reproducable crashes when testing
surprise removal during device initialization on a Stratus platform, at
least after commit d5ddcdf4d6 ("xhci: rework xhci extended capability
list parsing functions").

The crash is repeatable on a Stratus platform when injecting hardware
faults to induce xHCI host controller hotplug during driver
initialization.  If a PCI read in xhci_find_next_ext_cap returns the
master abort pattern, quirk_usb_handoff_xhci may start using a bogus
ext_cap_offset to start searching more bogus PCI addresses.

Signed-off-by: Joe Lawrence <joe.lawrence@stratus.com>
Acked-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Joe Lawrence 2016-02-03 12:51:12 -05:00 коммит произвёл Greg Kroah-Hartman
Родитель 207b08b942
Коммит 89140fdaf1
1 изменённых файлов: 4 добавлений и 0 удалений

Просмотреть файл

@ -112,12 +112,16 @@ static inline int xhci_find_next_ext_cap(void __iomem *base, u32 start, int id)
offset = start; offset = start;
if (!start || start == XHCI_HCC_PARAMS_OFFSET) { if (!start || start == XHCI_HCC_PARAMS_OFFSET) {
val = readl(base + XHCI_HCC_PARAMS_OFFSET); val = readl(base + XHCI_HCC_PARAMS_OFFSET);
if (val == ~0)
return 0;
offset = XHCI_HCC_EXT_CAPS(val) << 2; offset = XHCI_HCC_EXT_CAPS(val) << 2;
if (!offset) if (!offset)
return 0; return 0;
}; };
do { do {
val = readl(base + offset); val = readl(base + offset);
if (val == ~0)
return 0;
if (XHCI_EXT_CAPS_ID(val) == id && offset != start) if (XHCI_EXT_CAPS_ID(val) == id && offset != start)
return offset; return offset;