Hi, Mathias Nyman <[email protected]> writes: > the tt_info provided by a HS hub might be in use to by a child device > Make sure we free the devices in the correct order. > > This is needed in special cases such as when xhci controller is > reset when resuming from hibernate, and all virt_devices are freed. > > Also free the virt_devices starting from max slot_id as children > more commonly have higher slot_id than parent. > > CC: <[email protected]> > Signed-off-by: Mathias Nyman <[email protected]> > > --- > > Guenter Roeck, does this work for you? > > A rework of how tt_info is stored and used might be needed, > but that will take some time and won't go to stable as easily. > --- > drivers/usb/host/xhci-mem.c | 38 ++++++++++++++++++++++++++++++++++++-- > 1 file changed, 36 insertions(+), 2 deletions(-) > > diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c > index 6afe323..b3a5cd8 100644 > --- a/drivers/usb/host/xhci-mem.c > +++ b/drivers/usb/host/xhci-mem.c > @@ -979,6 +979,40 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int > slot_id) > xhci->devs[slot_id] = NULL; > } > > +/* > + * Free a virt_device structure. > + * If the virt_device added a tt_info (a hub) and has children pointing to > + * that tt_info, then free the child first. Recursive. > + * We can't rely on udev at this point to find child-parent relationships. > + */ > +void xhci_free_virt_devices_depth_first(struct xhci_hcd *xhci, int slot_id) > +{ > + struct xhci_virt_device *vdev; > + struct list_head *tt_list_head; > + struct xhci_tt_bw_info *tt_info, *next; > + int i; > + > + vdev = xhci->devs[slot_id]; > + if (!vdev) > + return; > + > + tt_list_head = &(xhci->rh_bw[vdev->real_port - 1].tts); > + list_for_each_entry_safe(tt_info, next, tt_list_head, tt_list) { > + /* is this a hub device that added a tt_info to the tts list */ > + if (tt_info->slot_id == slot_id) {
if (tt_info->slot_id != slot_id)
continue;
> + /* are any devices using this tt_info? */
> + for (i = 1; i < HCS_MAX_SLOTS(xhci->hcs_params1); i++) {
off-by-one here ? Why is i starting from 1?
> + vdev = xhci->devs[i];
> + if (vdev && (vdev->tt_info == tt_info))
if (!vdev || vdev->tt_info != tt_info)
continue;
> + xhci_free_virt_devices_depth_first(
> + xhci, i);
> + }
> + }
> + }
> + /* we are now at a leaf device */
> + xhci_free_virt_device(xhci, slot_id);
> +}
> +
> int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,
> struct usb_device *udev, gfp_t flags)
> {
> @@ -1829,8 +1863,8 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
> }
> }
>
> - for (i = 1; i < MAX_HC_SLOTS; ++i)
> - xhci_free_virt_device(xhci, i);
> + for (i = HCS_MAX_SLOTS(xhci->hcs_params1); i > 0; i--)
converting MAX_HC_SLOTS to HCS_MAX_SLOTS(xhci->hcs_params1) seems
unrelated to $subject. Perhaps just mention on commit log?
--
balbi
signature.asc
Description: PGP signature
