diff options
author | Sarah Sharp <sarah.a.sharp@linux.intel.com> | 2009-08-07 17:04:43 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-09-23 09:46:17 -0400 |
commit | f2217e8edd95b0428d8123d426e0097a5e955f9f (patch) | |
tree | 2364fb618dcae52cc8b6a947ce75152983dc3a9a /drivers/usb/host/xhci-hcd.c | |
parent | 018218d1d9eb06116d24a02dd5e7a390f0353d0f (diff) |
USB: xhci: Configure endpoint code refactoring.
Refactor out the code issue, wait for, and parse the event completion code
for a configure endpoint command. Modify it to support the evaluate
context command, which has a very similar submission process. Add
functions to copy parts of the output context into the input context
(which will be used in the evaluate context command).
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Cc: stable <stable@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/xhci-hcd.c')
-rw-r--r-- | drivers/usb/host/xhci-hcd.c | 169 |
1 files changed, 117 insertions, 52 deletions
diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c index 994f4c0dda24..ddb1a6a118eb 100644 --- a/drivers/usb/host/xhci-hcd.c +++ b/drivers/usb/host/xhci-hcd.c | |||
@@ -942,6 +942,122 @@ static void xhci_zero_in_ctx(struct xhci_hcd *xhci, struct xhci_virt_device *vir | |||
942 | } | 942 | } |
943 | } | 943 | } |
944 | 944 | ||
945 | static int xhci_configure_endpoint_result(struct xhci_hcd *xhci, | ||
946 | struct usb_device *udev, struct xhci_virt_device *virt_dev) | ||
947 | { | ||
948 | int ret; | ||
949 | |||
950 | switch (virt_dev->cmd_status) { | ||
951 | case COMP_ENOMEM: | ||
952 | dev_warn(&udev->dev, "Not enough host controller resources " | ||
953 | "for new device state.\n"); | ||
954 | ret = -ENOMEM; | ||
955 | /* FIXME: can we allocate more resources for the HC? */ | ||
956 | break; | ||
957 | case COMP_BW_ERR: | ||
958 | dev_warn(&udev->dev, "Not enough bandwidth " | ||
959 | "for new device state.\n"); | ||
960 | ret = -ENOSPC; | ||
961 | /* FIXME: can we go back to the old state? */ | ||
962 | break; | ||
963 | case COMP_TRB_ERR: | ||
964 | /* the HCD set up something wrong */ | ||
965 | dev_warn(&udev->dev, "ERROR: Endpoint drop flag = 0, " | ||
966 | "add flag = 1, " | ||
967 | "and endpoint is not disabled.\n"); | ||
968 | ret = -EINVAL; | ||
969 | break; | ||
970 | case COMP_SUCCESS: | ||
971 | dev_dbg(&udev->dev, "Successful Endpoint Configure command\n"); | ||
972 | ret = 0; | ||
973 | break; | ||
974 | default: | ||
975 | xhci_err(xhci, "ERROR: unexpected command completion " | ||
976 | "code 0x%x.\n", virt_dev->cmd_status); | ||
977 | ret = -EINVAL; | ||
978 | break; | ||
979 | } | ||
980 | return ret; | ||
981 | } | ||
982 | |||
983 | static int xhci_evaluate_context_result(struct xhci_hcd *xhci, | ||
984 | struct usb_device *udev, struct xhci_virt_device *virt_dev) | ||
985 | { | ||
986 | int ret; | ||
987 | |||
988 | switch (virt_dev->cmd_status) { | ||
989 | case COMP_EINVAL: | ||
990 | dev_warn(&udev->dev, "WARN: xHCI driver setup invalid evaluate " | ||
991 | "context command.\n"); | ||
992 | ret = -EINVAL; | ||
993 | break; | ||
994 | case COMP_EBADSLT: | ||
995 | dev_warn(&udev->dev, "WARN: slot not enabled for" | ||
996 | "evaluate context command.\n"); | ||
997 | case COMP_CTX_STATE: | ||
998 | dev_warn(&udev->dev, "WARN: invalid context state for " | ||
999 | "evaluate context command.\n"); | ||
1000 | xhci_dbg_ctx(xhci, virt_dev->out_ctx, 1); | ||
1001 | ret = -EINVAL; | ||
1002 | break; | ||
1003 | case COMP_SUCCESS: | ||
1004 | dev_dbg(&udev->dev, "Successful evaluate context command\n"); | ||
1005 | ret = 0; | ||
1006 | break; | ||
1007 | default: | ||
1008 | xhci_err(xhci, "ERROR: unexpected command completion " | ||
1009 | "code 0x%x.\n", virt_dev->cmd_status); | ||
1010 | ret = -EINVAL; | ||
1011 | break; | ||
1012 | } | ||
1013 | return ret; | ||
1014 | } | ||
1015 | |||
1016 | /* Issue a configure endpoint command or evaluate context command | ||
1017 | * and wait for it to finish. | ||
1018 | */ | ||
1019 | static int xhci_configure_endpoint(struct xhci_hcd *xhci, | ||
1020 | struct usb_device *udev, struct xhci_virt_device *virt_dev, | ||
1021 | bool ctx_change) | ||
1022 | { | ||
1023 | int ret; | ||
1024 | int timeleft; | ||
1025 | unsigned long flags; | ||
1026 | |||
1027 | spin_lock_irqsave(&xhci->lock, flags); | ||
1028 | if (!ctx_change) | ||
1029 | ret = xhci_queue_configure_endpoint(xhci, virt_dev->in_ctx->dma, | ||
1030 | udev->slot_id); | ||
1031 | else | ||
1032 | ret = xhci_queue_evaluate_context(xhci, virt_dev->in_ctx->dma, | ||
1033 | udev->slot_id); | ||
1034 | if (ret < 0) { | ||
1035 | spin_unlock_irqrestore(&xhci->lock, flags); | ||
1036 | xhci_dbg(xhci, "FIXME allocate a new ring segment\n"); | ||
1037 | return -ENOMEM; | ||
1038 | } | ||
1039 | xhci_ring_cmd_db(xhci); | ||
1040 | spin_unlock_irqrestore(&xhci->lock, flags); | ||
1041 | |||
1042 | /* Wait for the configure endpoint command to complete */ | ||
1043 | timeleft = wait_for_completion_interruptible_timeout( | ||
1044 | &virt_dev->cmd_completion, | ||
1045 | USB_CTRL_SET_TIMEOUT); | ||
1046 | if (timeleft <= 0) { | ||
1047 | xhci_warn(xhci, "%s while waiting for %s command\n", | ||
1048 | timeleft == 0 ? "Timeout" : "Signal", | ||
1049 | ctx_change == 0 ? | ||
1050 | "configure endpoint" : | ||
1051 | "evaluate context"); | ||
1052 | /* FIXME cancel the configure endpoint command */ | ||
1053 | return -ETIME; | ||
1054 | } | ||
1055 | |||
1056 | if (!ctx_change) | ||
1057 | return xhci_configure_endpoint_result(xhci, udev, virt_dev); | ||
1058 | return xhci_evaluate_context_result(xhci, udev, virt_dev); | ||
1059 | } | ||
1060 | |||
945 | /* Called after one or more calls to xhci_add_endpoint() or | 1061 | /* Called after one or more calls to xhci_add_endpoint() or |
946 | * xhci_drop_endpoint(). If this call fails, the USB core is expected | 1062 | * xhci_drop_endpoint(). If this call fails, the USB core is expected |
947 | * to call xhci_reset_bandwidth(). | 1063 | * to call xhci_reset_bandwidth(). |
@@ -956,8 +1072,6 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) | |||
956 | { | 1072 | { |
957 | int i; | 1073 | int i; |
958 | int ret = 0; | 1074 | int ret = 0; |
959 | int timeleft; | ||
960 | unsigned long flags; | ||
961 | struct xhci_hcd *xhci; | 1075 | struct xhci_hcd *xhci; |
962 | struct xhci_virt_device *virt_dev; | 1076 | struct xhci_virt_device *virt_dev; |
963 | struct xhci_input_control_ctx *ctrl_ctx; | 1077 | struct xhci_input_control_ctx *ctrl_ctx; |
@@ -987,56 +1101,7 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) | |||
987 | xhci_dbg_ctx(xhci, virt_dev->in_ctx, | 1101 | xhci_dbg_ctx(xhci, virt_dev->in_ctx, |
988 | LAST_CTX_TO_EP_NUM(slot_ctx->dev_info)); | 1102 | LAST_CTX_TO_EP_NUM(slot_ctx->dev_info)); |
989 | 1103 | ||
990 | spin_lock_irqsave(&xhci->lock, flags); | 1104 | ret = xhci_configure_endpoint(xhci, udev, virt_dev, false); |
991 | ret = xhci_queue_configure_endpoint(xhci, virt_dev->in_ctx->dma, | ||
992 | udev->slot_id); | ||
993 | if (ret < 0) { | ||
994 | spin_unlock_irqrestore(&xhci->lock, flags); | ||
995 | xhci_dbg(xhci, "FIXME allocate a new ring segment\n"); | ||
996 | return -ENOMEM; | ||
997 | } | ||
998 | xhci_ring_cmd_db(xhci); | ||
999 | spin_unlock_irqrestore(&xhci->lock, flags); | ||
1000 | |||
1001 | /* Wait for the configure endpoint command to complete */ | ||
1002 | timeleft = wait_for_completion_interruptible_timeout( | ||
1003 | &virt_dev->cmd_completion, | ||
1004 | USB_CTRL_SET_TIMEOUT); | ||
1005 | if (timeleft <= 0) { | ||
1006 | xhci_warn(xhci, "%s while waiting for configure endpoint command\n", | ||
1007 | timeleft == 0 ? "Timeout" : "Signal"); | ||
1008 | /* FIXME cancel the configure endpoint command */ | ||
1009 | return -ETIME; | ||
1010 | } | ||
1011 | |||
1012 | switch (virt_dev->cmd_status) { | ||
1013 | case COMP_ENOMEM: | ||
1014 | dev_warn(&udev->dev, "Not enough host controller resources " | ||
1015 | "for new device state.\n"); | ||
1016 | ret = -ENOMEM; | ||
1017 | /* FIXME: can we allocate more resources for the HC? */ | ||
1018 | break; | ||
1019 | case COMP_BW_ERR: | ||
1020 | dev_warn(&udev->dev, "Not enough bandwidth " | ||
1021 | "for new device state.\n"); | ||
1022 | ret = -ENOSPC; | ||
1023 | /* FIXME: can we go back to the old state? */ | ||
1024 | break; | ||
1025 | case COMP_TRB_ERR: | ||
1026 | /* the HCD set up something wrong */ | ||
1027 | dev_warn(&udev->dev, "ERROR: Endpoint drop flag = 0, add flag = 1, " | ||
1028 | "and endpoint is not disabled.\n"); | ||
1029 | ret = -EINVAL; | ||
1030 | break; | ||
1031 | case COMP_SUCCESS: | ||
1032 | dev_dbg(&udev->dev, "Successful Endpoint Configure command\n"); | ||
1033 | break; | ||
1034 | default: | ||
1035 | xhci_err(xhci, "ERROR: unexpected command completion " | ||
1036 | "code 0x%x.\n", virt_dev->cmd_status); | ||
1037 | ret = -EINVAL; | ||
1038 | break; | ||
1039 | } | ||
1040 | if (ret) { | 1105 | if (ret) { |
1041 | /* Callee should call reset_bandwidth() */ | 1106 | /* Callee should call reset_bandwidth() */ |
1042 | return ret; | 1107 | return ret; |