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 | |
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')
-rw-r--r-- | drivers/usb/host/xhci-hcd.c | 169 | ||||
-rw-r--r-- | drivers/usb/host/xhci-mem.c | 38 | ||||
-rw-r--r-- | drivers/usb/host/xhci-ring.c | 9 | ||||
-rw-r--r-- | drivers/usb/host/xhci.h | 5 |
4 files changed, 169 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; |
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index cb2033879ae3..c5313c83f42e 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c | |||
@@ -601,6 +601,44 @@ void xhci_endpoint_zero(struct xhci_hcd *xhci, | |||
601 | */ | 601 | */ |
602 | } | 602 | } |
603 | 603 | ||
604 | /* Copy output xhci_ep_ctx to the input xhci_ep_ctx copy. | ||
605 | * Useful when you want to change one particular aspect of the endpoint and then | ||
606 | * issue a configure endpoint command. | ||
607 | */ | ||
608 | void xhci_endpoint_copy(struct xhci_hcd *xhci, | ||
609 | struct xhci_virt_device *vdev, unsigned int ep_index) | ||
610 | { | ||
611 | struct xhci_ep_ctx *out_ep_ctx; | ||
612 | struct xhci_ep_ctx *in_ep_ctx; | ||
613 | |||
614 | out_ep_ctx = xhci_get_ep_ctx(xhci, vdev->out_ctx, ep_index); | ||
615 | in_ep_ctx = xhci_get_ep_ctx(xhci, vdev->in_ctx, ep_index); | ||
616 | |||
617 | in_ep_ctx->ep_info = out_ep_ctx->ep_info; | ||
618 | in_ep_ctx->ep_info2 = out_ep_ctx->ep_info2; | ||
619 | in_ep_ctx->deq = out_ep_ctx->deq; | ||
620 | in_ep_ctx->tx_info = out_ep_ctx->tx_info; | ||
621 | } | ||
622 | |||
623 | /* Copy output xhci_slot_ctx to the input xhci_slot_ctx. | ||
624 | * Useful when you want to change one particular aspect of the endpoint and then | ||
625 | * issue a configure endpoint command. Only the context entries field matters, | ||
626 | * but we'll copy the whole thing anyway. | ||
627 | */ | ||
628 | void xhci_slot_copy(struct xhci_hcd *xhci, struct xhci_virt_device *vdev) | ||
629 | { | ||
630 | struct xhci_slot_ctx *in_slot_ctx; | ||
631 | struct xhci_slot_ctx *out_slot_ctx; | ||
632 | |||
633 | in_slot_ctx = xhci_get_slot_ctx(xhci, vdev->in_ctx); | ||
634 | out_slot_ctx = xhci_get_slot_ctx(xhci, vdev->out_ctx); | ||
635 | |||
636 | in_slot_ctx->dev_info = out_slot_ctx->dev_info; | ||
637 | in_slot_ctx->dev_info2 = out_slot_ctx->dev_info2; | ||
638 | in_slot_ctx->tt_info = out_slot_ctx->tt_info; | ||
639 | in_slot_ctx->dev_state = out_slot_ctx->dev_state; | ||
640 | } | ||
641 | |||
604 | /* Set up the scratchpad buffer array and scratchpad buffers, if needed. */ | 642 | /* Set up the scratchpad buffer array and scratchpad buffers, if needed. */ |
605 | static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags) | 643 | static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags) |
606 | { | 644 | { |
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 011458f4d9ce..ac5c662368ed 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c | |||
@@ -1740,6 +1740,15 @@ int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, | |||
1740 | TRB_TYPE(TRB_CONFIG_EP) | SLOT_ID_FOR_TRB(slot_id)); | 1740 | TRB_TYPE(TRB_CONFIG_EP) | SLOT_ID_FOR_TRB(slot_id)); |
1741 | } | 1741 | } |
1742 | 1742 | ||
1743 | /* Queue an evaluate context command TRB */ | ||
1744 | int xhci_queue_evaluate_context(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, | ||
1745 | u32 slot_id) | ||
1746 | { | ||
1747 | return queue_command(xhci, lower_32_bits(in_ctx_ptr), | ||
1748 | upper_32_bits(in_ctx_ptr), 0, | ||
1749 | TRB_TYPE(TRB_EVAL_CONTEXT) | SLOT_ID_FOR_TRB(slot_id)); | ||
1750 | } | ||
1751 | |||
1743 | int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, int slot_id, | 1752 | int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, int slot_id, |
1744 | unsigned int ep_index) | 1753 | unsigned int ep_index) |
1745 | { | 1754 | { |
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 79ea627e8b8a..a8fe21762052 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h | |||
@@ -1168,6 +1168,9 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud | |||
1168 | unsigned int xhci_get_endpoint_index(struct usb_endpoint_descriptor *desc); | 1168 | unsigned int xhci_get_endpoint_index(struct usb_endpoint_descriptor *desc); |
1169 | unsigned int xhci_get_endpoint_flag(struct usb_endpoint_descriptor *desc); | 1169 | unsigned int xhci_get_endpoint_flag(struct usb_endpoint_descriptor *desc); |
1170 | void xhci_endpoint_zero(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, struct usb_host_endpoint *ep); | 1170 | void xhci_endpoint_zero(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, struct usb_host_endpoint *ep); |
1171 | void xhci_endpoint_copy(struct xhci_hcd *xhci, | ||
1172 | struct xhci_virt_device *vdev, unsigned int ep_index); | ||
1173 | void xhci_slot_copy(struct xhci_hcd *xhci, struct xhci_virt_device *vdev); | ||
1171 | int xhci_endpoint_init(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, | 1174 | int xhci_endpoint_init(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, |
1172 | struct usb_device *udev, struct usb_host_endpoint *ep, | 1175 | struct usb_device *udev, struct usb_host_endpoint *ep, |
1173 | gfp_t mem_flags); | 1176 | gfp_t mem_flags); |
@@ -1216,6 +1219,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb, | |||
1216 | int slot_id, unsigned int ep_index); | 1219 | int slot_id, unsigned int ep_index); |
1217 | int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, | 1220 | int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, |
1218 | u32 slot_id); | 1221 | u32 slot_id); |
1222 | int xhci_queue_evaluate_context(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, | ||
1223 | u32 slot_id); | ||
1219 | int xhci_queue_reset_ep(struct xhci_hcd *xhci, int slot_id, | 1224 | int xhci_queue_reset_ep(struct xhci_hcd *xhci, int slot_id, |
1220 | unsigned int ep_index); | 1225 | unsigned int ep_index); |
1221 | void xhci_find_new_dequeue_state(struct xhci_hcd *xhci, | 1226 | void xhci_find_new_dequeue_state(struct xhci_hcd *xhci, |