diff options
author | Andiry Xu <andiry.xu@amd.com> | 2010-10-14 10:22:45 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-10-22 13:22:11 -0400 |
commit | 64927730c66333c9d5987aa72a0e6d44ed91cec7 (patch) | |
tree | edc1da4d69cbd66d9ba1cff75a5738900d2e8cef /drivers/usb/host | |
parent | ac9dfe9cdda4eb42ecaa9f13b0fee518e0b6518e (diff) |
USB: xHCI: Add pointer to udev in struct xhci_virt_device
Add a pointer to udev in struct xhci_virt_device. When allocate a new
virt_device, make the pointer point to the corresponding udev.
Modify xhci_check_args(), check if virt_dev->udev matches the target udev,
to make sure command is issued to the right device.
Signed-off-by: Andiry Xu <andiry.xu@amd.com>
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host')
-rw-r--r-- | drivers/usb/host/xhci-mem.c | 1 | ||||
-rw-r--r-- | drivers/usb/host/xhci.c | 83 | ||||
-rw-r--r-- | drivers/usb/host/xhci.h | 1 |
3 files changed, 36 insertions, 49 deletions
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 4e51343ddffc..be901808e474 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c | |||
@@ -778,6 +778,7 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, | |||
778 | 778 | ||
779 | init_completion(&dev->cmd_completion); | 779 | init_completion(&dev->cmd_completion); |
780 | INIT_LIST_HEAD(&dev->cmd_list); | 780 | INIT_LIST_HEAD(&dev->cmd_list); |
781 | dev->udev = udev; | ||
781 | 782 | ||
782 | /* Point to output device context in dcbaa. */ | 783 | /* Point to output device context in dcbaa. */ |
783 | xhci->dcbaa->dev_context_ptrs[slot_id] = dev->out_ctx->dma; | 784 | xhci->dcbaa->dev_context_ptrs[slot_id] = dev->out_ctx->dma; |
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index d5c550ea3e68..0bec04070334 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c | |||
@@ -607,7 +607,11 @@ unsigned int xhci_last_valid_endpoint(u32 added_ctxs) | |||
607 | * returns 0 this is a root hub; returns -EINVAL for NULL pointers. | 607 | * returns 0 this is a root hub; returns -EINVAL for NULL pointers. |
608 | */ | 608 | */ |
609 | int xhci_check_args(struct usb_hcd *hcd, struct usb_device *udev, | 609 | int xhci_check_args(struct usb_hcd *hcd, struct usb_device *udev, |
610 | struct usb_host_endpoint *ep, int check_ep, const char *func) { | 610 | struct usb_host_endpoint *ep, int check_ep, bool check_virt_dev, |
611 | const char *func) { | ||
612 | struct xhci_hcd *xhci; | ||
613 | struct xhci_virt_device *virt_dev; | ||
614 | |||
611 | if (!hcd || (check_ep && !ep) || !udev) { | 615 | if (!hcd || (check_ep && !ep) || !udev) { |
612 | printk(KERN_DEBUG "xHCI %s called with invalid args\n", | 616 | printk(KERN_DEBUG "xHCI %s called with invalid args\n", |
613 | func); | 617 | func); |
@@ -618,11 +622,24 @@ int xhci_check_args(struct usb_hcd *hcd, struct usb_device *udev, | |||
618 | func); | 622 | func); |
619 | return 0; | 623 | return 0; |
620 | } | 624 | } |
621 | if (!udev->slot_id) { | 625 | |
622 | printk(KERN_DEBUG "xHCI %s called with unaddressed device\n", | 626 | if (check_virt_dev) { |
623 | func); | 627 | xhci = hcd_to_xhci(hcd); |
624 | return -EINVAL; | 628 | if (!udev->slot_id || !xhci->devs |
629 | || !xhci->devs[udev->slot_id]) { | ||
630 | printk(KERN_DEBUG "xHCI %s called with unaddressed " | ||
631 | "device\n", func); | ||
632 | return -EINVAL; | ||
633 | } | ||
634 | |||
635 | virt_dev = xhci->devs[udev->slot_id]; | ||
636 | if (virt_dev->udev != udev) { | ||
637 | printk(KERN_DEBUG "xHCI %s called with udev and " | ||
638 | "virt_dev does not match\n", func); | ||
639 | return -EINVAL; | ||
640 | } | ||
625 | } | 641 | } |
642 | |||
626 | return 1; | 643 | return 1; |
627 | } | 644 | } |
628 | 645 | ||
@@ -704,18 +721,13 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags) | |||
704 | struct urb_priv *urb_priv; | 721 | struct urb_priv *urb_priv; |
705 | int size, i; | 722 | int size, i; |
706 | 723 | ||
707 | if (!urb || xhci_check_args(hcd, urb->dev, urb->ep, true, __func__) <= 0) | 724 | if (!urb || xhci_check_args(hcd, urb->dev, urb->ep, |
725 | true, true, __func__) <= 0) | ||
708 | return -EINVAL; | 726 | return -EINVAL; |
709 | 727 | ||
710 | slot_id = urb->dev->slot_id; | 728 | slot_id = urb->dev->slot_id; |
711 | ep_index = xhci_get_endpoint_index(&urb->ep->desc); | 729 | ep_index = xhci_get_endpoint_index(&urb->ep->desc); |
712 | 730 | ||
713 | if (!xhci->devs || !xhci->devs[slot_id]) { | ||
714 | if (!in_interrupt()) | ||
715 | dev_warn(&urb->dev->dev, "WARN: urb submitted for dev with no Slot ID\n"); | ||
716 | ret = -EINVAL; | ||
717 | goto exit; | ||
718 | } | ||
719 | if (!HCD_HW_ACCESSIBLE(hcd)) { | 731 | if (!HCD_HW_ACCESSIBLE(hcd)) { |
720 | if (!in_interrupt()) | 732 | if (!in_interrupt()) |
721 | xhci_dbg(xhci, "urb submitted during PCI suspend\n"); | 733 | xhci_dbg(xhci, "urb submitted during PCI suspend\n"); |
@@ -991,7 +1003,7 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, | |||
991 | u32 new_add_flags, new_drop_flags, new_slot_info; | 1003 | u32 new_add_flags, new_drop_flags, new_slot_info; |
992 | int ret; | 1004 | int ret; |
993 | 1005 | ||
994 | ret = xhci_check_args(hcd, udev, ep, 1, __func__); | 1006 | ret = xhci_check_args(hcd, udev, ep, 1, true, __func__); |
995 | if (ret <= 0) | 1007 | if (ret <= 0) |
996 | return ret; | 1008 | return ret; |
997 | xhci = hcd_to_xhci(hcd); | 1009 | xhci = hcd_to_xhci(hcd); |
@@ -1004,12 +1016,6 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, | |||
1004 | return 0; | 1016 | return 0; |
1005 | } | 1017 | } |
1006 | 1018 | ||
1007 | if (!xhci->devs || !xhci->devs[udev->slot_id]) { | ||
1008 | xhci_warn(xhci, "xHCI %s called with unaddressed device\n", | ||
1009 | __func__); | ||
1010 | return -EINVAL; | ||
1011 | } | ||
1012 | |||
1013 | in_ctx = xhci->devs[udev->slot_id]->in_ctx; | 1019 | in_ctx = xhci->devs[udev->slot_id]->in_ctx; |
1014 | out_ctx = xhci->devs[udev->slot_id]->out_ctx; | 1020 | out_ctx = xhci->devs[udev->slot_id]->out_ctx; |
1015 | ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx); | 1021 | ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx); |
@@ -1078,7 +1084,7 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, | |||
1078 | u32 new_add_flags, new_drop_flags, new_slot_info; | 1084 | u32 new_add_flags, new_drop_flags, new_slot_info; |
1079 | int ret = 0; | 1085 | int ret = 0; |
1080 | 1086 | ||
1081 | ret = xhci_check_args(hcd, udev, ep, 1, __func__); | 1087 | ret = xhci_check_args(hcd, udev, ep, 1, true, __func__); |
1082 | if (ret <= 0) { | 1088 | if (ret <= 0) { |
1083 | /* So we won't queue a reset ep command for a root hub */ | 1089 | /* So we won't queue a reset ep command for a root hub */ |
1084 | ep->hcpriv = NULL; | 1090 | ep->hcpriv = NULL; |
@@ -1098,12 +1104,6 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, | |||
1098 | return 0; | 1104 | return 0; |
1099 | } | 1105 | } |
1100 | 1106 | ||
1101 | if (!xhci->devs || !xhci->devs[udev->slot_id]) { | ||
1102 | xhci_warn(xhci, "xHCI %s called with unaddressed device\n", | ||
1103 | __func__); | ||
1104 | return -EINVAL; | ||
1105 | } | ||
1106 | |||
1107 | in_ctx = xhci->devs[udev->slot_id]->in_ctx; | 1107 | in_ctx = xhci->devs[udev->slot_id]->in_ctx; |
1108 | out_ctx = xhci->devs[udev->slot_id]->out_ctx; | 1108 | out_ctx = xhci->devs[udev->slot_id]->out_ctx; |
1109 | ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx); | 1109 | ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx); |
@@ -1346,16 +1346,11 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) | |||
1346 | struct xhci_input_control_ctx *ctrl_ctx; | 1346 | struct xhci_input_control_ctx *ctrl_ctx; |
1347 | struct xhci_slot_ctx *slot_ctx; | 1347 | struct xhci_slot_ctx *slot_ctx; |
1348 | 1348 | ||
1349 | ret = xhci_check_args(hcd, udev, NULL, 0, __func__); | 1349 | ret = xhci_check_args(hcd, udev, NULL, 0, true, __func__); |
1350 | if (ret <= 0) | 1350 | if (ret <= 0) |
1351 | return ret; | 1351 | return ret; |
1352 | xhci = hcd_to_xhci(hcd); | 1352 | xhci = hcd_to_xhci(hcd); |
1353 | 1353 | ||
1354 | if (!udev->slot_id || !xhci->devs || !xhci->devs[udev->slot_id]) { | ||
1355 | xhci_warn(xhci, "xHCI %s called with unaddressed device\n", | ||
1356 | __func__); | ||
1357 | return -EINVAL; | ||
1358 | } | ||
1359 | xhci_dbg(xhci, "%s called for udev %p\n", __func__, udev); | 1354 | xhci_dbg(xhci, "%s called for udev %p\n", __func__, udev); |
1360 | virt_dev = xhci->devs[udev->slot_id]; | 1355 | virt_dev = xhci->devs[udev->slot_id]; |
1361 | 1356 | ||
@@ -1405,16 +1400,11 @@ void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) | |||
1405 | struct xhci_virt_device *virt_dev; | 1400 | struct xhci_virt_device *virt_dev; |
1406 | int i, ret; | 1401 | int i, ret; |
1407 | 1402 | ||
1408 | ret = xhci_check_args(hcd, udev, NULL, 0, __func__); | 1403 | ret = xhci_check_args(hcd, udev, NULL, 0, true, __func__); |
1409 | if (ret <= 0) | 1404 | if (ret <= 0) |
1410 | return; | 1405 | return; |
1411 | xhci = hcd_to_xhci(hcd); | 1406 | xhci = hcd_to_xhci(hcd); |
1412 | 1407 | ||
1413 | if (!xhci->devs || !xhci->devs[udev->slot_id]) { | ||
1414 | xhci_warn(xhci, "xHCI %s called with unaddressed device\n", | ||
1415 | __func__); | ||
1416 | return; | ||
1417 | } | ||
1418 | xhci_dbg(xhci, "%s called for udev %p\n", __func__, udev); | 1408 | xhci_dbg(xhci, "%s called for udev %p\n", __func__, udev); |
1419 | virt_dev = xhci->devs[udev->slot_id]; | 1409 | virt_dev = xhci->devs[udev->slot_id]; |
1420 | /* Free any rings allocated for added endpoints */ | 1410 | /* Free any rings allocated for added endpoints */ |
@@ -1575,7 +1565,7 @@ static int xhci_check_streams_endpoint(struct xhci_hcd *xhci, | |||
1575 | 1565 | ||
1576 | if (!ep) | 1566 | if (!ep) |
1577 | return -EINVAL; | 1567 | return -EINVAL; |
1578 | ret = xhci_check_args(xhci_to_hcd(xhci), udev, ep, 1, __func__); | 1568 | ret = xhci_check_args(xhci_to_hcd(xhci), udev, ep, 1, true, __func__); |
1579 | if (ret <= 0) | 1569 | if (ret <= 0) |
1580 | return -EINVAL; | 1570 | return -EINVAL; |
1581 | if (ep->ss_ep_comp.bmAttributes == 0) { | 1571 | if (ep->ss_ep_comp.bmAttributes == 0) { |
@@ -1965,17 +1955,12 @@ int xhci_reset_device(struct usb_hcd *hcd, struct usb_device *udev) | |||
1965 | int timeleft; | 1955 | int timeleft; |
1966 | int last_freed_endpoint; | 1956 | int last_freed_endpoint; |
1967 | 1957 | ||
1968 | ret = xhci_check_args(hcd, udev, NULL, 0, __func__); | 1958 | ret = xhci_check_args(hcd, udev, NULL, 0, true, __func__); |
1969 | if (ret <= 0) | 1959 | if (ret <= 0) |
1970 | return ret; | 1960 | return ret; |
1971 | xhci = hcd_to_xhci(hcd); | 1961 | xhci = hcd_to_xhci(hcd); |
1972 | slot_id = udev->slot_id; | 1962 | slot_id = udev->slot_id; |
1973 | virt_dev = xhci->devs[slot_id]; | 1963 | virt_dev = xhci->devs[slot_id]; |
1974 | if (!virt_dev) { | ||
1975 | xhci_dbg(xhci, "%s called with invalid slot ID %u\n", | ||
1976 | __func__, slot_id); | ||
1977 | return -EINVAL; | ||
1978 | } | ||
1979 | 1964 | ||
1980 | xhci_dbg(xhci, "Resetting device with slot ID %u\n", slot_id); | 1965 | xhci_dbg(xhci, "Resetting device with slot ID %u\n", slot_id); |
1981 | /* Allocate the command structure that holds the struct completion. | 1966 | /* Allocate the command structure that holds the struct completion. |
@@ -2077,13 +2062,13 @@ void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev) | |||
2077 | struct xhci_virt_device *virt_dev; | 2062 | struct xhci_virt_device *virt_dev; |
2078 | unsigned long flags; | 2063 | unsigned long flags; |
2079 | u32 state; | 2064 | u32 state; |
2080 | int i; | 2065 | int i, ret; |
2081 | 2066 | ||
2082 | if (udev->slot_id == 0) | 2067 | ret = xhci_check_args(hcd, udev, NULL, 0, true, __func__); |
2068 | if (ret <= 0) | ||
2083 | return; | 2069 | return; |
2070 | |||
2084 | virt_dev = xhci->devs[udev->slot_id]; | 2071 | virt_dev = xhci->devs[udev->slot_id]; |
2085 | if (!virt_dev) | ||
2086 | return; | ||
2087 | 2072 | ||
2088 | /* Stop any wayward timer functions (which may grab the lock) */ | 2073 | /* Stop any wayward timer functions (which may grab the lock) */ |
2089 | for (i = 0; i < 31; ++i) { | 2074 | for (i = 0; i < 31; ++i) { |
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 34a60d9f056a..f03f140a7d9a 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h | |||
@@ -731,6 +731,7 @@ struct xhci_virt_ep { | |||
731 | }; | 731 | }; |
732 | 732 | ||
733 | struct xhci_virt_device { | 733 | struct xhci_virt_device { |
734 | struct usb_device *udev; | ||
734 | /* | 735 | /* |
735 | * Commands to the hardware are passed an "input context" that | 736 | * Commands to the hardware are passed an "input context" that |
736 | * tells the hardware what to change in its data structures. | 737 | * tells the hardware what to change in its data structures. |