Pull up following revision(s) (requested by mrg in ticket #1632): sys/dev/usb/usbdivar.h: revision 1.117 sys/external/bsd/dwc2/dwc2.c: revision 1.52 sys/dev/usb/xhcivar.h: revision 1.10 sys/dev/usb/motg.c: revision 1.22 sys/dev/usb/ehci.c: revision 1.260 sys/dev/usb/ehci.c: revision 1.261 sys/dev/usb/xhci.c: revision 1.96 sys/dev/usb/ohci.c: revision 1.282 sys/dev/usb/ohci.c: revision 1.283 sys/dev/usb/ehcivar.h: revision 1.45 sys/dev/usb/uhci.c: revision 1.281 sys/dev/usb/uhci.c: revision 1.282 sys/dev/usb/usbdi.c: revision 1.177 sys/dev/usb/ohcivar.h: revision 1.60 sys/dev/usb/uhcivar.h: revision 1.55 (all via patch) pull across abort fixes from nick-nhusb. add more abort fixes, using ideas from Taylor and Nick, and myself. special thanks to both who inspired much of the code here, if not wrote it directly. among other problems, this assert should no longer trigger: panic: kernel diagnostic assertion "xfer->ux_state == XFER_ONQU" failed: file "/current/src/sys/dev/usb/usbdi.c", line 914 using usbhist i was able to track down my instance of it being related to userland close() beginning, dropping the sc_lock, and then the usb softintr completes the transfer normally, and when it is done, the abort path attempts to re-complete the transfer, and the above assert is tripped. changes from nhusb were commited with these logs: -- Move the struct usb_task to struct usbd_xfer for everyone to use. -- Set device transfer status to USBD_IN_PROGRESS if start methods succeeds -- Actually set the transfer status on transfers in ohci_abort_xfer and the controller is dying -- Don't supply the lock to callout_halt when polling as it won't be held -- Improve transfer abort -- Mark device transfers as USBD_IN_PROGRESS appropriately and improve abort handling -- -- Mark device transfers as USBD_IN_PROGRESS appropriately and improve abort handling -- additional changes include: - initialise the usb abort task in the HCI allocx routine, so that it can be safely usb_rem_task()'d. - rework the handling of softintr vs cancellation vs timeout abort based upon a scheme from Taylor: when completing a transfer normally: - if the status is not in progress, it must be cancelled or timed out, and we should not process this xfer. - set the status as normal. - unconditionallly callout_stop() and usb_rem_task(). they're safe and either aren't running, or will run and do nothing. - finally call usb_transfer_complete(). when aborting a transfer: - status should be cancelled or timed out. - if cancelling, callout_halt and usb_rem_task_wait() to make sure the timer is either done or cancelled. - at this point, the ux_status must not be cancelled or timed out, and if it is not in progress we're done. - set the status. - if the controller is dying, just return. - perform HCI-specific tasks to abort this xfer. - finally call usb_transfer_complete(). for the timeout and timeout task: - if the HCI is not dying, and the ux_status is in progress, then trigger the usb abort task. - remove UXFER_ABORTWAIT and UXFER_ABORTING. tested on: - multiple PC systems with several types of devices: ugen/UPS, ucom, umass with disk, ssd and cdrom backends, kbd, ms, using uhci, ehci and xhci. - erlite3: sd@umass on dwc2. - sunblade2000: kbd/ms and umass disk on ohci. untested: - motg, slhci and ahci. motg has some portion of the new scheme applied, but slhci and ahci require more study. future work includes pushing a lot of the common abort handling into usbdi.c and leaving upm_abort() for HC specific tasks, but this change is pullup-able to netbsd-7 and netbsd-8 as it does not change any external API, as well as removing over 100 lines of code while adding over 30 new asserts. XXX: pullup-7, pullup-8. fix DIAGNOSTIC build by not copying ub_usepolling to stack before use Sprinkle __diaguseddiff -r1.228.2.2 -r1.228.2.3 src/sys/dev/usb/ehci.c
(martin)
--- src/sys/dev/usb/ehci.c 2018/01/03 20:02:37 1.228.2.2
+++ src/sys/dev/usb/ehci.c 2018/08/25 14:57:35 1.228.2.3
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: ehci.c,v 1.228.2.2 2018/01/03 20:02:37 snj Exp $ */ | 1 | /* $NetBSD: ehci.c,v 1.228.2.3 2018/08/25 14:57:35 martin Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 2004-2012 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 2004-2012 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to The NetBSD Foundation | 7 | * This code is derived from software contributed to The NetBSD Foundation | |
8 | * by Lennart Augustsson (lennart@augustsson.net), Charles M. Hannum, | 8 | * by Lennart Augustsson (lennart@augustsson.net), Charles M. Hannum, | |
9 | * Jeremy Morse (jeremy.morse@gmail.com), Jared D. McNeill | 9 | * Jeremy Morse (jeremy.morse@gmail.com), Jared D. McNeill | |
10 | * (jmcneill@invisible.ca) and Matthew R. Green (mrg@eterna.com.au). | 10 | * (jmcneill@invisible.ca) and Matthew R. Green (mrg@eterna.com.au). | |
11 | * | 11 | * | |
12 | * Redistribution and use in source and binary forms, with or without | 12 | * Redistribution and use in source and binary forms, with or without | |
13 | * modification, are permitted provided that the following conditions | 13 | * modification, are permitted provided that the following conditions | |
14 | * are met: | 14 | * are met: | |
@@ -43,27 +43,27 @@ | @@ -43,27 +43,27 @@ | |||
43 | 43 | |||
44 | /* | 44 | /* | |
45 | * TODO: | 45 | * TODO: | |
46 | * 1) hold off explorations by companion controllers until ehci has started. | 46 | * 1) hold off explorations by companion controllers until ehci has started. | |
47 | * | 47 | * | |
48 | * 2) The hub driver needs to handle and schedule the transaction translator, | 48 | * 2) The hub driver needs to handle and schedule the transaction translator, | |
49 | * to assign place in frame where different devices get to go. See chapter | 49 | * to assign place in frame where different devices get to go. See chapter | |
50 | * on hubs in USB 2.0 for details. | 50 | * on hubs in USB 2.0 for details. | |
51 | * | 51 | * | |
52 | * 3) Command failures are not recovered correctly. | 52 | * 3) Command failures are not recovered correctly. | |
53 | */ | 53 | */ | |
54 | 54 | |||
55 | #include <sys/cdefs.h> | 55 | #include <sys/cdefs.h> | |
56 | __KERNEL_RCSID(0, "$NetBSD: ehci.c,v 1.228.2.2 2018/01/03 20:02:37 snj Exp $"); | 56 | __KERNEL_RCSID(0, "$NetBSD: ehci.c,v 1.228.2.3 2018/08/25 14:57:35 martin Exp $"); | |
57 | 57 | |||
58 | #include "ohci.h" | 58 | #include "ohci.h" | |
59 | #include "uhci.h" | 59 | #include "uhci.h" | |
60 | 60 | |||
61 | #ifdef _KERNEL_OPT | 61 | #ifdef _KERNEL_OPT | |
62 | #include "opt_usb.h" | 62 | #include "opt_usb.h" | |
63 | #endif | 63 | #endif | |
64 | 64 | |||
65 | #include <sys/param.h> | 65 | #include <sys/param.h> | |
66 | 66 | |||
67 | #include <sys/bus.h> | 67 | #include <sys/bus.h> | |
68 | #include <sys/cpu.h> | 68 | #include <sys/cpu.h> | |
69 | #include <sys/device.h> | 69 | #include <sys/device.h> | |
@@ -402,28 +402,27 @@ ehci_init(ehci_softc_t *sc) | @@ -402,28 +402,27 @@ ehci_init(ehci_softc_t *sc) | |||
402 | uint32_t vers, sparams, cparams, hcr; | 402 | uint32_t vers, sparams, cparams, hcr; | |
403 | u_int i; | 403 | u_int i; | |
404 | usbd_status err; | 404 | usbd_status err; | |
405 | ehci_soft_qh_t *sqh; | 405 | ehci_soft_qh_t *sqh; | |
406 | u_int ncomp; | 406 | u_int ncomp; | |
407 | 407 | |||
408 | EHCIHIST_FUNC(); EHCIHIST_CALLED(); | 408 | EHCIHIST_FUNC(); EHCIHIST_CALLED(); | |
409 | #ifdef EHCI_DEBUG | 409 | #ifdef EHCI_DEBUG | |
410 | theehci = sc; | 410 | theehci = sc; | |
411 | #endif | 411 | #endif | |
412 | 412 | |||
413 | mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB); | 413 | mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB); | |
414 | mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_USB); | 414 | mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_USB); | |
415 | cv_init(&sc->sc_softwake_cv, "ehciab"); | 415 | cv_init(&sc->sc_doorbell, "ehcidb"); | |
416 | cv_init(&sc->sc_doorbell, "ehcidi"); | |||
417 | 416 | |||
418 | sc->sc_xferpool = pool_cache_init(sizeof(struct ehci_xfer), 0, 0, 0, | 417 | sc->sc_xferpool = pool_cache_init(sizeof(struct ehci_xfer), 0, 0, 0, | |
419 | "ehcixfer", NULL, IPL_USB, NULL, NULL, NULL); | 418 | "ehcixfer", NULL, IPL_USB, NULL, NULL, NULL); | |
420 | 419 | |||
421 | sc->sc_doorbell_si = softint_establish(SOFTINT_USB | SOFTINT_MPSAFE, | 420 | sc->sc_doorbell_si = softint_establish(SOFTINT_USB | SOFTINT_MPSAFE, | |
422 | ehci_doorbell, sc); | 421 | ehci_doorbell, sc); | |
423 | KASSERT(sc->sc_doorbell_si != NULL); | 422 | KASSERT(sc->sc_doorbell_si != NULL); | |
424 | sc->sc_pcd_si = softint_establish(SOFTINT_USB | SOFTINT_MPSAFE, | 423 | sc->sc_pcd_si = softint_establish(SOFTINT_USB | SOFTINT_MPSAFE, | |
425 | ehci_pcd, sc); | 424 | ehci_pcd, sc); | |
426 | KASSERT(sc->sc_pcd_si != NULL); | 425 | KASSERT(sc->sc_pcd_si != NULL); | |
427 | 426 | |||
428 | sc->sc_offs = EREAD1(sc, EHCI_CAPLENGTH); | 427 | sc->sc_offs = EREAD1(sc, EHCI_CAPLENGTH); | |
429 | 428 | |||
@@ -741,26 +740,27 @@ ehci_intr1(ehci_softc_t *sc) | @@ -741,26 +740,27 @@ ehci_intr1(ehci_softc_t *sc) | |||
741 | sc->sc_eintrs &= ~eintrs; | 740 | sc->sc_eintrs &= ~eintrs; | |
742 | EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs); | 741 | EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs); | |
743 | printf("%s: blocking intrs 0x%x\n", | 742 | printf("%s: blocking intrs 0x%x\n", | |
744 | device_xname(sc->sc_dev), eintrs); | 743 | device_xname(sc->sc_dev), eintrs); | |
745 | } | 744 | } | |
746 | 745 | |||
747 | return 1; | 746 | return 1; | |
748 | } | 747 | } | |
749 | 748 | |||
750 | Static void | 749 | Static void | |
751 | ehci_doorbell(void *addr) | 750 | ehci_doorbell(void *addr) | |
752 | { | 751 | { | |
753 | ehci_softc_t *sc = addr; | 752 | ehci_softc_t *sc = addr; | |
753 | EHCIHIST_FUNC(); EHCIHIST_CALLED(); | |||
754 | 754 | |||
755 | mutex_enter(&sc->sc_lock); | 755 | mutex_enter(&sc->sc_lock); | |
756 | cv_broadcast(&sc->sc_doorbell); | 756 | cv_broadcast(&sc->sc_doorbell); | |
757 | mutex_exit(&sc->sc_lock); | 757 | mutex_exit(&sc->sc_lock); | |
758 | } | 758 | } | |
759 | 759 | |||
760 | Static void | 760 | Static void | |
761 | ehci_pcd(void *addr) | 761 | ehci_pcd(void *addr) | |
762 | { | 762 | { | |
763 | ehci_softc_t *sc = addr; | 763 | ehci_softc_t *sc = addr; | |
764 | struct usbd_xfer *xfer; | 764 | struct usbd_xfer *xfer; | |
765 | u_char *p; | 765 | u_char *p; | |
766 | int i, m; | 766 | int i, m; | |
@@ -843,31 +843,26 @@ ehci_softintr(void *v) | @@ -843,31 +843,26 @@ ehci_softintr(void *v) | |||
843 | * We abuse ex_next for the interrupt and complete lists and | 843 | * We abuse ex_next for the interrupt and complete lists and | |
844 | * interrupt transfers will get re-added here so use | 844 | * interrupt transfers will get re-added here so use | |
845 | * the _SAFE version of TAILQ_FOREACH. | 845 | * the _SAFE version of TAILQ_FOREACH. | |
846 | */ | 846 | */ | |
847 | TAILQ_FOREACH_SAFE(ex, &cq, ex_next, nextex) { | 847 | TAILQ_FOREACH_SAFE(ex, &cq, ex_next, nextex) { | |
848 | usb_transfer_complete(&ex->ex_xfer); | 848 | usb_transfer_complete(&ex->ex_xfer); | |
849 | } | 849 | } | |
850 | 850 | |||
851 | /* Schedule a callout to catch any dropped transactions. */ | 851 | /* Schedule a callout to catch any dropped transactions. */ | |
852 | if ((sc->sc_flags & EHCIF_DROPPED_INTR_WORKAROUND) && | 852 | if ((sc->sc_flags & EHCIF_DROPPED_INTR_WORKAROUND) && | |
853 | !TAILQ_EMPTY(&sc->sc_intrhead)) | 853 | !TAILQ_EMPTY(&sc->sc_intrhead)) | |
854 | callout_reset(&sc->sc_tmo_intrlist, | 854 | callout_reset(&sc->sc_tmo_intrlist, | |
855 | hz, ehci_intrlist_timeout, sc); | 855 | hz, ehci_intrlist_timeout, sc); | |
856 | ||||
857 | if (sc->sc_softwake) { | |||
858 | sc->sc_softwake = 0; | |||
859 | cv_broadcast(&sc->sc_softwake_cv); | |||
860 | } | |||
861 | } | 856 | } | |
862 | 857 | |||
863 | Static void | 858 | Static void | |
864 | ehci_check_qh_intr(ehci_softc_t *sc, struct ehci_xfer *ex, ex_completeq_t *cq) | 859 | ehci_check_qh_intr(ehci_softc_t *sc, struct ehci_xfer *ex, ex_completeq_t *cq) | |
865 | { | 860 | { | |
866 | ehci_soft_qtd_t *sqtd, *fsqtd, *lsqtd; | 861 | ehci_soft_qtd_t *sqtd, *fsqtd, *lsqtd; | |
867 | uint32_t status; | 862 | uint32_t status; | |
868 | 863 | |||
869 | EHCIHIST_FUNC(); EHCIHIST_CALLED(); | 864 | EHCIHIST_FUNC(); EHCIHIST_CALLED(); | |
870 | 865 | |||
871 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); | 866 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); | |
872 | 867 | |||
873 | if (ex->ex_type == EX_CTRL) { | 868 | if (ex->ex_type == EX_CTRL) { | |
@@ -929,27 +924,26 @@ ehci_check_qh_intr(ehci_softc_t *sc, str | @@ -929,27 +924,26 @@ ehci_check_qh_intr(ehci_softc_t *sc, str | |||
929 | } | 924 | } | |
930 | } | 925 | } | |
931 | DPRINTFN(10, "ex=%p std=%p still active", ex, ex->ex_sqtdstart, | 926 | DPRINTFN(10, "ex=%p std=%p still active", ex, ex->ex_sqtdstart, | |
932 | 0, 0); | 927 | 0, 0); | |
933 | #ifdef EHCI_DEBUG | 928 | #ifdef EHCI_DEBUG | |
934 | DPRINTFN(5, "--- still active start ---", 0, 0, 0, 0); | 929 | DPRINTFN(5, "--- still active start ---", 0, 0, 0, 0); | |
935 | ehci_dump_sqtds(ex->ex_sqtdstart); | 930 | ehci_dump_sqtds(ex->ex_sqtdstart); | |
936 | DPRINTFN(5, "--- still active end ---", 0, 0, 0, 0); | 931 | DPRINTFN(5, "--- still active end ---", 0, 0, 0, 0); | |
937 | #endif | 932 | #endif | |
938 | return; | 933 | return; | |
939 | } | 934 | } | |
940 | done: | 935 | done: | |
941 | DPRINTFN(10, "ex=%p done", ex, 0, 0, 0); | 936 | DPRINTFN(10, "ex=%p done", ex, 0, 0, 0); | |
942 | callout_stop(&ex->ex_xfer.ux_callout); | |||
943 | ehci_idone(ex, cq); | 937 | ehci_idone(ex, cq); | |
944 | } | 938 | } | |
945 | 939 | |||
946 | Static void | 940 | Static void | |
947 | ehci_check_itd_intr(ehci_softc_t *sc, struct ehci_xfer *ex, ex_completeq_t *cq) | 941 | ehci_check_itd_intr(ehci_softc_t *sc, struct ehci_xfer *ex, ex_completeq_t *cq) | |
948 | { | 942 | { | |
949 | ehci_soft_itd_t *itd; | 943 | ehci_soft_itd_t *itd; | |
950 | int i; | 944 | int i; | |
951 | 945 | |||
952 | EHCIHIST_FUNC(); EHCIHIST_CALLED(); | 946 | EHCIHIST_FUNC(); EHCIHIST_CALLED(); | |
953 | 947 | |||
954 | KASSERT(mutex_owned(&sc->sc_lock)); | 948 | KASSERT(mutex_owned(&sc->sc_lock)); | |
955 | 949 | |||
@@ -975,27 +969,26 @@ ehci_check_itd_intr(ehci_softc_t *sc, st | @@ -975,27 +969,26 @@ ehci_check_itd_intr(ehci_softc_t *sc, st | |||
975 | } | 969 | } | |
976 | 970 | |||
977 | if (i == EHCI_ITD_NUFRAMES) { | 971 | if (i == EHCI_ITD_NUFRAMES) { | |
978 | goto done; /* All 8 descriptors inactive, it's done */ | 972 | goto done; /* All 8 descriptors inactive, it's done */ | |
979 | } | 973 | } | |
980 | 974 | |||
981 | usb_syncmem(&itd->dma, itd->offs + offsetof(ehci_itd_t, itd_ctl), | 975 | usb_syncmem(&itd->dma, itd->offs + offsetof(ehci_itd_t, itd_ctl), | |
982 | sizeof(itd->itd.itd_ctl), BUS_DMASYNC_PREREAD); | 976 | sizeof(itd->itd.itd_ctl), BUS_DMASYNC_PREREAD); | |
983 | 977 | |||
984 | DPRINTFN(10, "ex %p itd %p still active", ex, ex->ex_itdstart, 0, 0); | 978 | DPRINTFN(10, "ex %p itd %p still active", ex, ex->ex_itdstart, 0, 0); | |
985 | return; | 979 | return; | |
986 | done: | 980 | done: | |
987 | DPRINTF("ex %p done", ex, 0, 0, 0); | 981 | DPRINTF("ex %p done", ex, 0, 0, 0); | |
988 | callout_stop(&ex->ex_xfer.ux_callout); | |||
989 | ehci_idone(ex, cq); | 982 | ehci_idone(ex, cq); | |
990 | } | 983 | } | |
991 | 984 | |||
992 | void | 985 | void | |
993 | ehci_check_sitd_intr(ehci_softc_t *sc, struct ehci_xfer *ex, ex_completeq_t *cq) | 986 | ehci_check_sitd_intr(ehci_softc_t *sc, struct ehci_xfer *ex, ex_completeq_t *cq) | |
994 | { | 987 | { | |
995 | ehci_soft_sitd_t *sitd; | 988 | ehci_soft_sitd_t *sitd; | |
996 | 989 | |||
997 | EHCIHIST_FUNC(); EHCIHIST_CALLED(); | 990 | EHCIHIST_FUNC(); EHCIHIST_CALLED(); | |
998 | 991 | |||
999 | KASSERT(mutex_owned(&sc->sc_lock)); | 992 | KASSERT(mutex_owned(&sc->sc_lock)); | |
1000 | 993 | |||
1001 | if (&ex->ex_xfer != SIMPLEQ_FIRST(&ex->ex_xfer.ux_pipe->up_queue)) | 994 | if (&ex->ex_xfer != SIMPLEQ_FIRST(&ex->ex_xfer.ux_pipe->up_queue)) | |
@@ -1013,53 +1006,65 @@ ehci_check_sitd_intr(ehci_softc_t *sc, s | @@ -1013,53 +1006,65 @@ ehci_check_sitd_intr(ehci_softc_t *sc, s | |||
1013 | usb_syncmem(&sitd->dma, sitd->offs + offsetof(ehci_sitd_t, sitd_trans), | 1006 | usb_syncmem(&sitd->dma, sitd->offs + offsetof(ehci_sitd_t, sitd_trans), | |
1014 | sizeof(sitd->sitd.sitd_trans), | 1007 | sizeof(sitd->sitd.sitd_trans), | |
1015 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 1008 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
1016 | 1009 | |||
1017 | bool active = ((le32toh(sitd->sitd.sitd_trans) & EHCI_SITD_ACTIVE) != 0); | 1010 | bool active = ((le32toh(sitd->sitd.sitd_trans) & EHCI_SITD_ACTIVE) != 0); | |
1018 | 1011 | |||
1019 | usb_syncmem(&sitd->dma, sitd->offs + offsetof(ehci_sitd_t, sitd_trans), | 1012 | usb_syncmem(&sitd->dma, sitd->offs + offsetof(ehci_sitd_t, sitd_trans), | |
1020 | sizeof(sitd->sitd.sitd_trans), BUS_DMASYNC_PREREAD); | 1013 | sizeof(sitd->sitd.sitd_trans), BUS_DMASYNC_PREREAD); | |
1021 | 1014 | |||
1022 | if (active) | 1015 | if (active) | |
1023 | return; | 1016 | return; | |
1024 | 1017 | |||
1025 | DPRINTFN(10, "ex=%p done", ex, 0, 0, 0); | 1018 | DPRINTFN(10, "ex=%p done", ex, 0, 0, 0); | |
1026 | callout_stop(&(ex->ex_xfer.ux_callout)); | |||
1027 | ehci_idone(ex, cq); | 1019 | ehci_idone(ex, cq); | |
1028 | } | 1020 | } | |
1029 | 1021 | |||
1030 | 1022 | |||
1031 | Static void | 1023 | Static void | |
1032 | ehci_idone(struct ehci_xfer *ex, ex_completeq_t *cq) | 1024 | ehci_idone(struct ehci_xfer *ex, ex_completeq_t *cq) | |
1033 | { | 1025 | { | |
1026 | EHCIHIST_FUNC(); EHCIHIST_CALLED(); | |||
1034 | struct usbd_xfer *xfer = &ex->ex_xfer; | 1027 | struct usbd_xfer *xfer = &ex->ex_xfer; | |
1035 | struct ehci_pipe *epipe = EHCI_XFER2EPIPE(xfer); | 1028 | struct ehci_pipe *epipe = EHCI_XFER2EPIPE(xfer); | |
1036 | struct ehci_softc *sc = EHCI_XFER2SC(xfer); | 1029 | struct ehci_softc *sc = EHCI_XFER2SC(xfer); | |
1037 | ehci_soft_qtd_t *sqtd, *fsqtd, *lsqtd; | 1030 | ehci_soft_qtd_t *sqtd, *fsqtd, *lsqtd; | |
1038 | uint32_t status = 0, nstatus = 0; | 1031 | uint32_t status = 0, nstatus = 0; | |
1039 | int actlen = 0; | 1032 | int actlen = 0; | |
1040 | 1033 | |||
1041 | EHCIHIST_FUNC(); EHCIHIST_CALLED(); | |||
1042 | ||||
1043 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); | 1034 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); | |
1044 | 1035 | |||
1045 | DPRINTF("ex=%p", ex, 0, 0, 0); | 1036 | DPRINTF("ex=%p", ex, 0, 0, 0); | |
1046 | 1037 | |||
1047 | if (xfer->ux_status == USBD_CANCELLED || | 1038 | /* | |
1048 | xfer->ux_status == USBD_TIMEOUT) { | 1039 | * If software has completed it, either by cancellation | |
1040 | * or timeout, drop it on the floor. | |||
1041 | */ | |||
1042 | if (xfer->ux_status != USBD_IN_PROGRESS) { | |||
1043 | KASSERT(xfer->ux_status == USBD_CANCELLED || | |||
1044 | xfer->ux_status == USBD_TIMEOUT); | |||
1049 | DPRINTF("aborted xfer=%p", xfer, 0, 0, 0); | 1045 | DPRINTF("aborted xfer=%p", xfer, 0, 0, 0); | |
1050 | return; | 1046 | return; | |
1051 | } | 1047 | } | |
1052 | 1048 | |||
1049 | /* | |||
1050 | * Cancel the timeout and the task, which have not yet | |||
1051 | * run. If they have already fired, at worst they are | |||
1052 | * waiting for the lock. They will see that the xfer | |||
1053 | * is no longer in progress and give up. | |||
1054 | */ | |||
1055 | callout_stop(&xfer->ux_callout); | |||
1056 | usb_rem_task(xfer->ux_pipe->up_dev, &xfer->ux_aborttask); | |||
1057 | ||||
1053 | #ifdef DIAGNOSTIC | 1058 | #ifdef DIAGNOSTIC | |
1054 | #ifdef EHCI_DEBUG | 1059 | #ifdef EHCI_DEBUG | |
1055 | if (ex->ex_isdone) { | 1060 | if (ex->ex_isdone) { | |
1056 | DPRINTFN(5, "--- dump start ---", 0, 0, 0, 0); | 1061 | DPRINTFN(5, "--- dump start ---", 0, 0, 0, 0); | |
1057 | ehci_dump_exfer(ex); | 1062 | ehci_dump_exfer(ex); | |
1058 | DPRINTFN(5, "--- dump end ---", 0, 0, 0, 0); | 1063 | DPRINTFN(5, "--- dump end ---", 0, 0, 0, 0); | |
1059 | } | 1064 | } | |
1060 | #endif | 1065 | #endif | |
1061 | KASSERTMSG(!ex->ex_isdone, "xfer %p type %d status %d", xfer, | 1066 | KASSERTMSG(!ex->ex_isdone, "xfer %p type %d status %d", xfer, | |
1062 | ex->ex_type, xfer->ux_status); | 1067 | ex->ex_type, xfer->ux_status); | |
1063 | ex->ex_isdone = true; | 1068 | ex->ex_isdone = true; | |
1064 | #endif | 1069 | #endif | |
1065 | 1070 | |||
@@ -1322,27 +1327,26 @@ ehci_detach(struct ehci_softc *sc, int f | @@ -1322,27 +1327,26 @@ ehci_detach(struct ehci_softc *sc, int f | |||
1322 | rv = config_detach(sc->sc_child, flags); | 1327 | rv = config_detach(sc->sc_child, flags); | |
1323 | 1328 | |||
1324 | if (rv != 0) | 1329 | if (rv != 0) | |
1325 | return rv; | 1330 | return rv; | |
1326 | 1331 | |||
1327 | callout_halt(&sc->sc_tmo_intrlist, NULL); | 1332 | callout_halt(&sc->sc_tmo_intrlist, NULL); | |
1328 | callout_destroy(&sc->sc_tmo_intrlist); | 1333 | callout_destroy(&sc->sc_tmo_intrlist); | |
1329 | 1334 | |||
1330 | /* XXX free other data structures XXX */ | 1335 | /* XXX free other data structures XXX */ | |
1331 | if (sc->sc_softitds) | 1336 | if (sc->sc_softitds) | |
1332 | kmem_free(sc->sc_softitds, | 1337 | kmem_free(sc->sc_softitds, | |
1333 | sc->sc_flsize * sizeof(ehci_soft_itd_t *)); | 1338 | sc->sc_flsize * sizeof(ehci_soft_itd_t *)); | |
1334 | cv_destroy(&sc->sc_doorbell); | 1339 | cv_destroy(&sc->sc_doorbell); | |
1335 | cv_destroy(&sc->sc_softwake_cv); | |||
1336 | 1340 | |||
1337 | #if 0 | 1341 | #if 0 | |
1338 | /* XXX destroyed in ehci_pci.c as it controls ehci_intr access */ | 1342 | /* XXX destroyed in ehci_pci.c as it controls ehci_intr access */ | |
1339 | 1343 | |||
1340 | softint_disestablish(sc->sc_doorbell_si); | 1344 | softint_disestablish(sc->sc_doorbell_si); | |
1341 | softint_disestablish(sc->sc_pcd_si); | 1345 | softint_disestablish(sc->sc_pcd_si); | |
1342 | 1346 | |||
1343 | mutex_destroy(&sc->sc_lock); | 1347 | mutex_destroy(&sc->sc_lock); | |
1344 | mutex_destroy(&sc->sc_intr_lock); | 1348 | mutex_destroy(&sc->sc_intr_lock); | |
1345 | #endif | 1349 | #endif | |
1346 | 1350 | |||
1347 | pool_cache_destroy(sc->sc_xferpool); | 1351 | pool_cache_destroy(sc->sc_xferpool); | |
1348 | 1352 | |||
@@ -1501,26 +1505,30 @@ ehci_shutdown(device_t self, int flags) | @@ -1501,26 +1505,30 @@ ehci_shutdown(device_t self, int flags) | |||
1501 | EOWRITE4(sc, EHCI_USBCMD, EHCI_CMD_HCRESET); | 1505 | EOWRITE4(sc, EHCI_USBCMD, EHCI_CMD_HCRESET); | |
1502 | return true; | 1506 | return true; | |
1503 | } | 1507 | } | |
1504 | 1508 | |||
1505 | Static struct usbd_xfer * | 1509 | Static struct usbd_xfer * | |
1506 | ehci_allocx(struct usbd_bus *bus, unsigned int nframes) | 1510 | ehci_allocx(struct usbd_bus *bus, unsigned int nframes) | |
1507 | { | 1511 | { | |
1508 | struct ehci_softc *sc = EHCI_BUS2SC(bus); | 1512 | struct ehci_softc *sc = EHCI_BUS2SC(bus); | |
1509 | struct usbd_xfer *xfer; | 1513 | struct usbd_xfer *xfer; | |
1510 | 1514 | |||
1511 | xfer = pool_cache_get(sc->sc_xferpool, PR_WAITOK); | 1515 | xfer = pool_cache_get(sc->sc_xferpool, PR_WAITOK); | |
1512 | if (xfer != NULL) { | 1516 | if (xfer != NULL) { | |
1513 | memset(xfer, 0, sizeof(struct ehci_xfer)); | 1517 | memset(xfer, 0, sizeof(struct ehci_xfer)); | |
1518 | ||||
1519 | /* Initialise this always so we can call remove on it. */ | |||
1520 | usb_init_task(&xfer->ux_aborttask, ehci_timeout_task, xfer, | |||
1521 | USB_TASKQ_MPSAFE); | |||
1514 | #ifdef DIAGNOSTIC | 1522 | #ifdef DIAGNOSTIC | |
1515 | struct ehci_xfer *ex = EHCI_XFER2EXFER(xfer); | 1523 | struct ehci_xfer *ex = EHCI_XFER2EXFER(xfer); | |
1516 | ex->ex_isdone = true; | 1524 | ex->ex_isdone = true; | |
1517 | xfer->ux_state = XFER_BUSY; | 1525 | xfer->ux_state = XFER_BUSY; | |
1518 | #endif | 1526 | #endif | |
1519 | } | 1527 | } | |
1520 | return xfer; | 1528 | return xfer; | |
1521 | } | 1529 | } | |
1522 | 1530 | |||
1523 | Static void | 1531 | Static void | |
1524 | ehci_freex(struct usbd_bus *bus, struct usbd_xfer *xfer) | 1532 | ehci_freex(struct usbd_bus *bus, struct usbd_xfer *xfer) | |
1525 | { | 1533 | { | |
1526 | struct ehci_softc *sc = EHCI_BUS2SC(bus); | 1534 | struct ehci_softc *sc = EHCI_BUS2SC(bus); | |
@@ -2148,26 +2156,27 @@ ehci_set_qh_qtd(ehci_soft_qh_t *sqh, ehc | @@ -2148,26 +2156,27 @@ ehci_set_qh_qtd(ehci_soft_qh_t *sqh, ehc | |||
2148 | Static void | 2156 | Static void | |
2149 | ehci_sync_hc(ehci_softc_t *sc) | 2157 | ehci_sync_hc(ehci_softc_t *sc) | |
2150 | { | 2158 | { | |
2151 | int error __diagused; | 2159 | int error __diagused; | |
2152 | 2160 | |||
2153 | KASSERT(mutex_owned(&sc->sc_lock)); | 2161 | KASSERT(mutex_owned(&sc->sc_lock)); | |
2154 | 2162 | |||
2155 | EHCIHIST_FUNC(); EHCIHIST_CALLED(); | 2163 | EHCIHIST_FUNC(); EHCIHIST_CALLED(); | |
2156 | 2164 | |||
2157 | if (sc->sc_dying) { | 2165 | if (sc->sc_dying) { | |
2158 | DPRINTF("dying", 0, 0, 0, 0); | 2166 | DPRINTF("dying", 0, 0, 0, 0); | |
2159 | return; | 2167 | return; | |
2160 | } | 2168 | } | |
2169 | ||||
2161 | /* ask for doorbell */ | 2170 | /* ask for doorbell */ | |
2162 | EOWRITE4(sc, EHCI_USBCMD, EOREAD4(sc, EHCI_USBCMD) | EHCI_CMD_IAAD); | 2171 | EOWRITE4(sc, EHCI_USBCMD, EOREAD4(sc, EHCI_USBCMD) | EHCI_CMD_IAAD); | |
2163 | DPRINTF("cmd = 0x%08x sts = 0x%08x", | 2172 | DPRINTF("cmd = 0x%08x sts = 0x%08x", | |
2164 | EOREAD4(sc, EHCI_USBCMD), EOREAD4(sc, EHCI_USBSTS), 0, 0); | 2173 | EOREAD4(sc, EHCI_USBCMD), EOREAD4(sc, EHCI_USBSTS), 0, 0); | |
2165 | 2174 | |||
2166 | error = cv_timedwait(&sc->sc_doorbell, &sc->sc_lock, hz); /* bell wait */ | 2175 | error = cv_timedwait(&sc->sc_doorbell, &sc->sc_lock, hz); /* bell wait */ | |
2167 | 2176 | |||
2168 | DPRINTF("cmd = 0x%08x sts = 0x%08x ... done", | 2177 | DPRINTF("cmd = 0x%08x sts = 0x%08x ... done", | |
2169 | EOREAD4(sc, EHCI_USBCMD), EOREAD4(sc, EHCI_USBSTS), 0, 0); | 2178 | EOREAD4(sc, EHCI_USBCMD), EOREAD4(sc, EHCI_USBSTS), 0, 0); | |
2170 | #ifdef DIAGNOSTIC | 2179 | #ifdef DIAGNOSTIC | |
2171 | if (error == EWOULDBLOCK) { | 2180 | if (error == EWOULDBLOCK) { | |
2172 | printf("ehci_sync_hc: timed out\n"); | 2181 | printf("ehci_sync_hc: timed out\n"); | |
2173 | } else if (error) { | 2182 | } else if (error) { | |
@@ -3085,90 +3094,105 @@ Static void | @@ -3085,90 +3094,105 @@ Static void | |||
3085 | ehci_close_pipe(struct usbd_pipe *pipe, ehci_soft_qh_t *head) | 3094 | ehci_close_pipe(struct usbd_pipe *pipe, ehci_soft_qh_t *head) | |
3086 | { | 3095 | { | |
3087 | struct ehci_pipe *epipe = EHCI_PIPE2EPIPE(pipe); | 3096 | struct ehci_pipe *epipe = EHCI_PIPE2EPIPE(pipe); | |
3088 | ehci_softc_t *sc = EHCI_PIPE2SC(pipe); | 3097 | ehci_softc_t *sc = EHCI_PIPE2SC(pipe); | |
3089 | ehci_soft_qh_t *sqh = epipe->sqh; | 3098 | ehci_soft_qh_t *sqh = epipe->sqh; | |
3090 | 3099 | |||
3091 | KASSERT(mutex_owned(&sc->sc_lock)); | 3100 | KASSERT(mutex_owned(&sc->sc_lock)); | |
3092 | 3101 | |||
3093 | ehci_rem_qh(sc, sqh, head); | 3102 | ehci_rem_qh(sc, sqh, head); | |
3094 | ehci_free_sqh(sc, epipe->sqh); | 3103 | ehci_free_sqh(sc, epipe->sqh); | |
3095 | } | 3104 | } | |
3096 | 3105 | |||
3097 | /* | 3106 | /* | |
3098 | * Abort a device request. | 3107 | * Cancel or timeout a device request. We have two cases to deal with | |
3099 | * If this routine is called at splusb() it guarantees that the request | 3108 | * | |
3100 | * will be removed from the hardware scheduling and that the callback | 3109 | * 1) A driver wants to stop scheduled or inflight transfers | |
3101 | * for it will be called with USBD_CANCELLED status. | 3110 | * 2) A transfer has timed out | |
3102 | * It's impossible to guarantee that the requested transfer will not | 3111 | * | |
3103 | * have happened since the hardware runs concurrently. | 3112 | * have (partially) happened since the hardware runs concurrently. | |
3104 | * If the transaction has already happened we rely on the ordinary | 3113 | * | |
3105 | * interrupt processing to process it. | 3114 | * Transfer state is protected by the bus lock and we set the transfer status | |
3106 | * XXX This is most probably wrong. | 3115 | * as soon as either of the above happens (with bus lock held). | |
3107 | * XXXMRG this doesn't make sense anymore. | 3116 | * | |
3117 | * Then we arrange for the hardware to tells us that it is not still | |||
3118 | * processing the TDs by setting the QH halted bit and wait for the ehci | |||
3119 | * door bell | |||
3108 | */ | 3120 | */ | |
3109 | Static void | 3121 | Static void | |
3110 | ehci_abort_xfer(struct usbd_xfer *xfer, usbd_status status) | 3122 | ehci_abort_xfer(struct usbd_xfer *xfer, usbd_status status) | |
3111 | { | 3123 | { | |
3124 | EHCIHIST_FUNC(); EHCIHIST_CALLED(); | |||
3112 | struct ehci_pipe *epipe = EHCI_XFER2EPIPE(xfer); | 3125 | struct ehci_pipe *epipe = EHCI_XFER2EPIPE(xfer); | |
3113 | struct ehci_xfer *exfer = EHCI_XFER2EXFER(xfer); | 3126 | struct ehci_xfer *exfer = EHCI_XFER2EXFER(xfer); | |
3114 | ehci_softc_t *sc = EHCI_XFER2SC(xfer); | 3127 | ehci_softc_t *sc = EHCI_XFER2SC(xfer); | |
3115 | ehci_soft_qh_t *sqh = epipe->sqh; | 3128 | ehci_soft_qh_t *sqh = epipe->sqh; | |
3116 | ehci_soft_qtd_t *sqtd, *fsqtd, *lsqtd; | 3129 | ehci_soft_qtd_t *sqtd, *fsqtd, *lsqtd; | |
3117 | ehci_physaddr_t cur; | 3130 | ehci_physaddr_t cur; | |
3118 | uint32_t qhstatus; | 3131 | uint32_t qhstatus; | |
3119 | int hit; | 3132 | int hit; | |
3120 | int wake; | |||
3121 | 3133 | |||
3122 | EHCIHIST_FUNC(); EHCIHIST_CALLED(); | 3134 | KASSERTMSG((status == USBD_CANCELLED || status == USBD_TIMEOUT), | |
3135 | "invalid status for abort: %d", (int)status); | |||
3123 | 3136 | |||
3124 | DPRINTF("xfer=%p pipe=%p", xfer, epipe, 0, 0); | 3137 | DPRINTF("xfer=%p pipe=%p", xfer, epipe, 0, 0); | |
3125 | 3138 | |||
3126 | KASSERT(mutex_owned(&sc->sc_lock)); | 3139 | KASSERT(mutex_owned(&sc->sc_lock)); | |
3127 | ASSERT_SLEEPABLE(); | 3140 | ASSERT_SLEEPABLE(); | |
3128 | 3141 | |||
3129 | if (sc->sc_dying) { | 3142 | if (status == USBD_CANCELLED) { | |
3130 | /* If we're dying, just do the software part. */ | 3143 | /* | |
3131 | xfer->ux_status = status; /* make software ignore it */ | 3144 | * We are synchronously aborting. Try to stop the | |
3132 | callout_stop(&xfer->ux_callout); | 3145 | * callout and task, but if we can't, wait for them to | |
3133 | usb_transfer_complete(xfer); | 3146 | * complete. | |
3134 | return; | 3147 | */ | |
3148 | callout_halt(&xfer->ux_callout, &sc->sc_lock); | |||
3149 | usb_rem_task_wait(xfer->ux_pipe->up_dev, &xfer->ux_aborttask, | |||
3150 | USB_TASKQ_HC, &sc->sc_lock); | |||
3151 | } else { | |||
3152 | /* Otherwise, we are timing out. */ | |||
3153 | KASSERT(status == USBD_TIMEOUT); | |||
3135 | } | 3154 | } | |
3136 | 3155 | |||
3137 | /* | 3156 | /* | |
3138 | * If an abort is already in progress then just wait for it to | 3157 | * The xfer cannot have been cancelled already. It is the | |
3139 | * complete and return. | 3158 | * responsibility of the caller of usbd_abort_pipe not to try | |
3159 | * to abort a pipe multiple times, whether concurrently or | |||
3160 | * sequentially. | |||
3140 | */ | 3161 | */ | |
3141 | if (xfer->ux_hcflags & UXFER_ABORTING) { | 3162 | ||
3142 | DPRINTF("already aborting", 0, 0, 0, 0); | 3163 | KASSERT(xfer->ux_status != USBD_CANCELLED); | |
3143 | #ifdef DIAGNOSTIC | 3164 | ||
3144 | if (status == USBD_TIMEOUT) | 3165 | /* Only the timeout, which runs only once, can time it out. */ | |
3145 | printf("ehci_abort_xfer: TIMEOUT while aborting\n"); | 3166 | KASSERT(xfer->ux_status != USBD_TIMEOUT); | |
3146 | #endif | 3167 | ||
3147 | /* Override the status which might be USBD_TIMEOUT. */ | 3168 | /* If anyone else beat us, we're done. */ | |
3148 | xfer->ux_status = status; | 3169 | if (xfer->ux_status != USBD_IN_PROGRESS) | |
3149 | DPRINTF("waiting for abort to finish", 0, 0, 0, 0); | |||
3150 | xfer->ux_hcflags |= UXFER_ABORTWAIT; | |||
3151 | while (xfer->ux_hcflags & UXFER_ABORTING) | |||
3152 | cv_wait(&xfer->ux_hccv, &sc->sc_lock); | |||
3153 | return; | 3170 | return; | |
3171 | ||||
3172 | /* We beat everyone else. Claim the status. */ | |||
3173 | xfer->ux_status = status; | |||
3174 | ||||
3175 | /* | |||
3176 | * If we're dying, skip the hardware action and just notify the | |||
3177 | * software that we're done. | |||
3178 | */ | |||
3179 | if (sc->sc_dying) { | |||
3180 | goto dying; | |||
3154 | } | 3181 | } | |
3155 | xfer->ux_hcflags |= UXFER_ABORTING; | |||
3156 | 3182 | |||
3157 | /* | 3183 | /* | |
3158 | * Step 1: Make interrupt routine and hardware ignore xfer. | 3184 | * HC Step 1: Make interrupt routine and hardware ignore xfer. | |
3159 | */ | 3185 | */ | |
3160 | xfer->ux_status = status; /* make software ignore it */ | |||
3161 | callout_stop(&xfer->ux_callout); | |||
3162 | ehci_del_intr_list(sc, exfer); | 3186 | ehci_del_intr_list(sc, exfer); | |
3163 | 3187 | |||
3164 | usb_syncmem(&sqh->dma, | 3188 | usb_syncmem(&sqh->dma, | |
3165 | sqh->offs + offsetof(ehci_qh_t, qh_qtd.qtd_status), | 3189 | sqh->offs + offsetof(ehci_qh_t, qh_qtd.qtd_status), | |
3166 | sizeof(sqh->qh.qh_qtd.qtd_status), | 3190 | sizeof(sqh->qh.qh_qtd.qtd_status), | |
3167 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 3191 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
3168 | qhstatus = sqh->qh.qh_qtd.qtd_status; | 3192 | qhstatus = sqh->qh.qh_qtd.qtd_status; | |
3169 | sqh->qh.qh_qtd.qtd_status = qhstatus | htole32(EHCI_QTD_HALTED); | 3193 | sqh->qh.qh_qtd.qtd_status = qhstatus | htole32(EHCI_QTD_HALTED); | |
3170 | usb_syncmem(&sqh->dma, | 3194 | usb_syncmem(&sqh->dma, | |
3171 | sqh->offs + offsetof(ehci_qh_t, qh_qtd.qtd_status), | 3195 | sqh->offs + offsetof(ehci_qh_t, qh_qtd.qtd_status), | |
3172 | sizeof(sqh->qh.qh_qtd.qtd_status), | 3196 | sizeof(sqh->qh.qh_qtd.qtd_status), | |
3173 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 3197 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
3174 | 3198 | |||
@@ -3184,37 +3208,33 @@ ehci_abort_xfer(struct usbd_xfer *xfer, | @@ -3184,37 +3208,33 @@ ehci_abort_xfer(struct usbd_xfer *xfer, | |||
3184 | sqtd->offs + offsetof(ehci_qtd_t, qtd_status), | 3208 | sqtd->offs + offsetof(ehci_qtd_t, qtd_status), | |
3185 | sizeof(sqtd->qtd.qtd_status), | 3209 | sizeof(sqtd->qtd.qtd_status), | |
3186 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 3210 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
3187 | sqtd->qtd.qtd_status |= htole32(EHCI_QTD_HALTED); | 3211 | sqtd->qtd.qtd_status |= htole32(EHCI_QTD_HALTED); | |
3188 | usb_syncmem(&sqtd->dma, | 3212 | usb_syncmem(&sqtd->dma, | |
3189 | sqtd->offs + offsetof(ehci_qtd_t, qtd_status), | 3213 | sqtd->offs + offsetof(ehci_qtd_t, qtd_status), | |
3190 | sizeof(sqtd->qtd.qtd_status), | 3214 | sizeof(sqtd->qtd.qtd_status), | |
3191 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 3215 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
3192 | if (sqtd == lsqtd) | 3216 | if (sqtd == lsqtd) | |
3193 | break; | 3217 | break; | |
3194 | } | 3218 | } | |
3195 | 3219 | |||
3196 | /* | 3220 | /* | |
3197 | * Step 2: Wait until we know hardware has finished any possible | 3221 | * HC Step 2: Wait until we know hardware has finished any possible | |
3198 | * use of the xfer. Also make sure the soft interrupt routine | 3222 | * use of the xfer. | |
3199 | * has run. | |||
3200 | */ | 3223 | */ | |
3201 | ehci_sync_hc(sc); | 3224 | ehci_sync_hc(sc); | |
3202 | sc->sc_softwake = 1; | |||
3203 | usb_schedsoftintr(&sc->sc_bus); | |||
3204 | cv_wait(&sc->sc_softwake_cv, &sc->sc_lock); | |||
3205 | 3225 | |||
3206 | /* | 3226 | /* | |
3207 | * Step 3: Remove any vestiges of the xfer from the hardware. | 3227 | * HC Step 3: Remove any vestiges of the xfer from the hardware. | |
3208 | * The complication here is that the hardware may have executed | 3228 | * The complication here is that the hardware may have executed | |
3209 | * beyond the xfer we're trying to abort. So as we're scanning | 3229 | * beyond the xfer we're trying to abort. So as we're scanning | |
3210 | * the TDs of this xfer we check if the hardware points to | 3230 | * the TDs of this xfer we check if the hardware points to | |
3211 | * any of them. | 3231 | * any of them. | |
3212 | */ | 3232 | */ | |
3213 | 3233 | |||
3214 | usb_syncmem(&sqh->dma, | 3234 | usb_syncmem(&sqh->dma, | |
3215 | sqh->offs + offsetof(ehci_qh_t, qh_curqtd), | 3235 | sqh->offs + offsetof(ehci_qh_t, qh_curqtd), | |
3216 | sizeof(sqh->qh.qh_curqtd), | 3236 | sizeof(sqh->qh.qh_curqtd), | |
3217 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 3237 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
3218 | cur = EHCI_LINK_ADDR(le32toh(sqh->qh.qh_curqtd)); | 3238 | cur = EHCI_LINK_ADDR(le32toh(sqh->qh.qh_curqtd)); | |
3219 | hit = 0; | 3239 | hit = 0; | |
3220 | for (sqtd = fsqtd; ; sqtd = sqtd->nextqtd) { | 3240 | for (sqtd = fsqtd; ; sqtd = sqtd->nextqtd) { | |
@@ -3235,86 +3255,88 @@ ehci_abort_xfer(struct usbd_xfer *xfer, | @@ -3235,86 +3255,88 @@ ehci_abort_xfer(struct usbd_xfer *xfer, | |||
3235 | usb_syncmem(&sqh->dma, | 3255 | usb_syncmem(&sqh->dma, | |
3236 | sqh->offs + offsetof(ehci_qh_t, qh_qtd.qtd_status), | 3256 | sqh->offs + offsetof(ehci_qh_t, qh_qtd.qtd_status), | |
3237 | sizeof(sqh->qh.qh_qtd.qtd_status), | 3257 | sizeof(sqh->qh.qh_qtd.qtd_status), | |
3238 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 3258 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
3239 | } else { | 3259 | } else { | |
3240 | DPRINTF("no hit", 0, 0, 0, 0); | 3260 | DPRINTF("no hit", 0, 0, 0, 0); | |
3241 | usb_syncmem(&sqh->dma, | 3261 | usb_syncmem(&sqh->dma, | |
3242 | sqh->offs + offsetof(ehci_qh_t, qh_curqtd), | 3262 | sqh->offs + offsetof(ehci_qh_t, qh_curqtd), | |
3243 | sizeof(sqh->qh.qh_curqtd), | 3263 | sizeof(sqh->qh.qh_curqtd), | |
3244 | BUS_DMASYNC_PREREAD); | 3264 | BUS_DMASYNC_PREREAD); | |
3245 | } | 3265 | } | |
3246 | 3266 | |||
3247 | /* | 3267 | /* | |
3248 | * Step 4: Execute callback. | 3268 | * Final step: Notify completion to waiting xfers. | |
3249 | */ | 3269 | */ | |
3270 | dying: | |||
3250 | #ifdef DIAGNOSTIC | 3271 | #ifdef DIAGNOSTIC | |
3251 | exfer->ex_isdone = true; | 3272 | exfer->ex_isdone = true; | |
3252 | #endif | 3273 | #endif | |
3253 | wake = xfer->ux_hcflags & UXFER_ABORTWAIT; | |||
3254 | xfer->ux_hcflags &= ~(UXFER_ABORTING | UXFER_ABORTWAIT); | |||
3255 | usb_transfer_complete(xfer); | 3274 | usb_transfer_complete(xfer); | |
3256 | if (wake) { | 3275 | DPRINTFN(14, "end", 0, 0, 0, 0); | |
3257 | cv_broadcast(&xfer->ux_hccv); | |||
3258 | } | |||
3259 | 3276 | |||
3260 | KASSERT(mutex_owned(&sc->sc_lock)); | 3277 | KASSERT(mutex_owned(&sc->sc_lock)); | |
3261 | } | 3278 | } | |
3262 | 3279 | |||
3263 | Static void | 3280 | Static void | |
3264 | ehci_abort_isoc_xfer(struct usbd_xfer *xfer, usbd_status status) | 3281 | ehci_abort_isoc_xfer(struct usbd_xfer *xfer, usbd_status status) | |
3265 | { | 3282 | { | |
3283 | EHCIHIST_FUNC(); EHCIHIST_CALLED(); | |||
3266 | ehci_isoc_trans_t trans_status; | 3284 | ehci_isoc_trans_t trans_status; | |
3267 | struct ehci_xfer *exfer; | 3285 | struct ehci_xfer *exfer; | |
3268 | ehci_softc_t *sc; | 3286 | ehci_softc_t *sc; | |
3269 | struct ehci_soft_itd *itd; | 3287 | struct ehci_soft_itd *itd; | |
3270 | struct ehci_soft_sitd *sitd; | 3288 | struct ehci_soft_sitd *sitd; | |
3271 | int i, wake; | 3289 | int i; | |
3272 | 3290 | |||
3273 | EHCIHIST_FUNC(); EHCIHIST_CALLED(); | 3291 | KASSERTMSG(status == USBD_CANCELLED, | |
3292 | "invalid status for abort: %d", (int)status); | |||
3274 | 3293 | |||
3275 | exfer = EHCI_XFER2EXFER(xfer); | 3294 | exfer = EHCI_XFER2EXFER(xfer); | |
3276 | sc = EHCI_XFER2SC(xfer); | 3295 | sc = EHCI_XFER2SC(xfer); | |
3277 | 3296 | |||
3278 | DPRINTF("xfer %p pipe %p", xfer, xfer->ux_pipe, 0, 0); | 3297 | DPRINTF("xfer %p pipe %p", xfer, xfer->ux_pipe, 0, 0); | |
3279 | 3298 | |||
3280 | KASSERT(mutex_owned(&sc->sc_lock)); | 3299 | KASSERT(mutex_owned(&sc->sc_lock)); | |
3300 | ASSERT_SLEEPABLE(); | |||
3281 | 3301 | |||
3282 | if (sc->sc_dying) { | 3302 | /* No timeout or task here. */ | |
3283 | xfer->ux_status = status; | |||
3284 | callout_stop(&xfer->ux_callout); | |||
3285 | usb_transfer_complete(xfer); | |||
3286 | return; | |||
3287 | } | |||
3288 | 3303 | |||
3289 | if (xfer->ux_hcflags & UXFER_ABORTING) { | 3304 | /* | |
3290 | DPRINTF("already aborting", 0, 0, 0, 0); | 3305 | * The xfer cannot have been cancelled already. It is the | |
3306 | * responsibility of the caller of usbd_abort_pipe not to try | |||
3307 | * to abort a pipe multiple times, whether concurrently or | |||
3308 | * sequentially. | |||
3309 | */ | |||
3310 | KASSERT(xfer->ux_status != USBD_CANCELLED); | |||
3291 | 3311 | |||
3292 | #ifdef DIAGNOSTIC | 3312 | /* If anyone else beat us, we're done. */ | |
3293 | if (status == USBD_TIMEOUT) | 3313 | if (xfer->ux_status != USBD_IN_PROGRESS) | |
3294 | printf("ehci_abort_isoc_xfer: TIMEOUT while aborting\n"); | 3314 | return; | |
3295 | #endif | |||
3296 | 3315 | |||
3297 | xfer->ux_status = status; | 3316 | /* We beat everyone else. Claim the status. */ | |
3298 | DPRINTF("waiting for abort to finish", 0, 0, 0, 0); | 3317 | xfer->ux_status = status; | |
3299 | xfer->ux_hcflags |= UXFER_ABORTWAIT; | 3318 | ||
3300 | while (xfer->ux_hcflags & UXFER_ABORTING) | 3319 | /* | |
3301 | cv_wait(&xfer->ux_hccv, &sc->sc_lock); | 3320 | * If we're dying, skip the hardware action and just notify the | |
3302 | goto done; | 3321 | * software that we're done. | |
3322 | */ | |||
3323 | if (sc->sc_dying) { | |||
3324 | goto dying; | |||
3303 | } | 3325 | } | |
3304 | xfer->ux_hcflags |= UXFER_ABORTING; | |||
3305 | 3326 | |||
3306 | xfer->ux_status = status; | 3327 | /* | |
3307 | callout_stop(&xfer->ux_callout); | 3328 | * HC Step 1: Make interrupt routine and hardware ignore xfer. | |
3329 | */ | |||
3308 | ehci_del_intr_list(sc, exfer); | 3330 | ehci_del_intr_list(sc, exfer); | |
3309 | 3331 | |||
3310 | if (xfer->ux_pipe->up_dev->ud_speed == USB_SPEED_HIGH) { | 3332 | if (xfer->ux_pipe->up_dev->ud_speed == USB_SPEED_HIGH) { | |
3311 | for (itd = exfer->ex_itdstart; itd != NULL; | 3333 | for (itd = exfer->ex_itdstart; itd != NULL; | |
3312 | itd = itd->xfer_next) { | 3334 | itd = itd->xfer_next) { | |
3313 | usb_syncmem(&itd->dma, | 3335 | usb_syncmem(&itd->dma, | |
3314 | itd->offs + offsetof(ehci_itd_t, itd_ctl), | 3336 | itd->offs + offsetof(ehci_itd_t, itd_ctl), | |
3315 | sizeof(itd->itd.itd_ctl), | 3337 | sizeof(itd->itd.itd_ctl), | |
3316 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 3338 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
3317 | 3339 | |||
3318 | for (i = 0; i < 8; i++) { | 3340 | for (i = 0; i < 8; i++) { | |
3319 | trans_status = le32toh(itd->itd.itd_ctl[i]); | 3341 | trans_status = le32toh(itd->itd.itd_ctl[i]); | |
3320 | trans_status &= ~EHCI_ITD_ACTIVE; | 3342 | trans_status &= ~EHCI_ITD_ACTIVE; | |
@@ -3335,73 +3357,56 @@ ehci_abort_isoc_xfer(struct usbd_xfer *x | @@ -3335,73 +3357,56 @@ ehci_abort_isoc_xfer(struct usbd_xfer *x | |||
3335 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 3357 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
3336 | 3358 | |||
3337 | trans_status = le32toh(sitd->sitd.sitd_trans); | 3359 | trans_status = le32toh(sitd->sitd.sitd_trans); | |
3338 | trans_status &= ~EHCI_SITD_ACTIVE; | 3360 | trans_status &= ~EHCI_SITD_ACTIVE; | |
3339 | sitd->sitd.sitd_trans = htole32(trans_status); | 3361 | sitd->sitd.sitd_trans = htole32(trans_status); | |
3340 | 3362 | |||
3341 | usb_syncmem(&sitd->dma, | 3363 | usb_syncmem(&sitd->dma, | |
3342 | sitd->offs + offsetof(ehci_sitd_t, sitd_buffer), | 3364 | sitd->offs + offsetof(ehci_sitd_t, sitd_buffer), | |
3343 | sizeof(sitd->sitd.sitd_buffer), | 3365 | sizeof(sitd->sitd.sitd_buffer), | |
3344 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 3366 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
3345 | } | 3367 | } | |
3346 | } | 3368 | } | |
3347 | 3369 | |||
3348 | sc->sc_softwake = 1; | 3370 | dying: | |
3349 | usb_schedsoftintr(&sc->sc_bus); | |||
3350 | cv_wait(&sc->sc_softwake_cv, &sc->sc_lock); | |||
3351 | ||||
3352 | #ifdef DIAGNOSTIC | 3371 | #ifdef DIAGNOSTIC | |
3353 | exfer->ex_isdone = true; | 3372 | exfer->ex_isdone = true; | |
3354 | #endif | 3373 | #endif | |
3355 | wake = xfer->ux_hcflags & UXFER_ABORTWAIT; | |||
3356 | xfer->ux_hcflags &= ~(UXFER_ABORTING | UXFER_ABORTWAIT); | |||
3357 | usb_transfer_complete(xfer); | 3374 | usb_transfer_complete(xfer); | |
3358 | if (wake) { | 3375 | DPRINTFN(14, "end", 0, 0, 0, 0); | |
3359 | cv_broadcast(&xfer->ux_hccv); | |||
3360 | } | |||
3361 | 3376 | |||
3362 | done: | |||
3363 | KASSERT(mutex_owned(&sc->sc_lock)); | 3377 | KASSERT(mutex_owned(&sc->sc_lock)); | |
3364 | return; | |||
3365 | } | 3378 | } | |
3366 | 3379 | |||
3367 | Static void | 3380 | Static void | |
3368 | ehci_timeout(void *addr) | 3381 | ehci_timeout(void *addr) | |
3369 | { | 3382 | { | |
3383 | EHCIHIST_FUNC(); EHCIHIST_CALLED(); | |||
3370 | struct usbd_xfer *xfer = addr; | 3384 | struct usbd_xfer *xfer = addr; | |
3371 | struct ehci_xfer *exfer = EHCI_XFER2EXFER(xfer); | |||
3372 | struct usbd_pipe *pipe = xfer->ux_pipe; | |||
3373 | struct usbd_device *dev = pipe->up_dev; | |||
3374 | ehci_softc_t *sc = EHCI_XFER2SC(xfer); | 3385 | ehci_softc_t *sc = EHCI_XFER2SC(xfer); | |
3386 | struct usbd_device *dev = xfer->ux_pipe->up_dev; | |||
3375 | 3387 | |||
3376 | EHCIHIST_FUNC(); EHCIHIST_CALLED(); | 3388 | DPRINTF("xfer %p", xfer, 0, 0, 0); | |
3377 | ||||
3378 | DPRINTF("exfer %p", exfer, 0, 0, 0); | |||
3379 | #ifdef EHCI_DEBUG | 3389 | #ifdef EHCI_DEBUG | |
3380 | if (ehcidebug >= 2) | 3390 | if (ehcidebug >= 2) { | |
3391 | struct usbd_pipe *pipe = xfer->ux_pipe; | |||
3381 | usbd_dump_pipe(pipe); | 3392 | usbd_dump_pipe(pipe); | |
3382 | #endif | |||
3383 | ||||
3384 | if (sc->sc_dying) { | |||
3385 | mutex_enter(&sc->sc_lock); | |||
3386 | ehci_abort_xfer(xfer, USBD_TIMEOUT); | |||
3387 | mutex_exit(&sc->sc_lock); | |||
3388 | return; | |||
3389 | } | 3393 | } | |
3394 | #endif | |||
3390 | 3395 | |||
3391 | /* Execute the abort in a process context. */ | 3396 | mutex_enter(&sc->sc_lock); | |
3392 | usb_init_task(&exfer->ex_aborttask, ehci_timeout_task, xfer, | 3397 | if (!sc->sc_dying && xfer->ux_status == USBD_IN_PROGRESS) | |
3393 | USB_TASKQ_MPSAFE); | 3398 | usb_add_task(dev, &xfer->ux_aborttask, USB_TASKQ_HC); | |
3394 | usb_add_task(dev, &exfer->ex_aborttask, USB_TASKQ_HC); | 3399 | mutex_exit(&sc->sc_lock); | |
3395 | } | 3400 | } | |
3396 | 3401 | |||
3397 | Static void | 3402 | Static void | |
3398 | ehci_timeout_task(void *addr) | 3403 | ehci_timeout_task(void *addr) | |
3399 | { | 3404 | { | |
3400 | struct usbd_xfer *xfer = addr; | 3405 | struct usbd_xfer *xfer = addr; | |
3401 | ehci_softc_t *sc = EHCI_XFER2SC(xfer); | 3406 | ehci_softc_t *sc = EHCI_XFER2SC(xfer); | |
3402 | 3407 | |||
3403 | EHCIHIST_FUNC(); EHCIHIST_CALLED(); | 3408 | EHCIHIST_FUNC(); EHCIHIST_CALLED(); | |
3404 | 3409 | |||
3405 | DPRINTF("xfer=%p", xfer, 0, 0, 0); | 3410 | DPRINTF("xfer=%p", xfer, 0, 0, 0); | |
3406 | 3411 | |||
3407 | mutex_enter(&sc->sc_lock); | 3412 | mutex_enter(&sc->sc_lock); | |
@@ -4448,27 +4453,26 @@ ehci_device_fs_isoc_transfer(struct usbd | @@ -4448,27 +4453,26 @@ ehci_device_fs_isoc_transfer(struct usbd | |||
4448 | sitd->slot = frindex; | 4453 | sitd->slot = frindex; | |
4449 | sitd->frame_list.prev = NULL; | 4454 | sitd->frame_list.prev = NULL; | |
4450 | 4455 | |||
4451 | frindex += i; | 4456 | frindex += i; | |
4452 | if (frindex >= sc->sc_flsize) | 4457 | if (frindex >= sc->sc_flsize) | |
4453 | frindex -= sc->sc_flsize; | 4458 | frindex -= sc->sc_flsize; | |
4454 | } | 4459 | } | |
4455 | 4460 | |||
4456 | epipe->isoc.cur_xfers++; | 4461 | epipe->isoc.cur_xfers++; | |
4457 | epipe->isoc.next_frame = frindex; | 4462 | epipe->isoc.next_frame = frindex; | |
4458 | 4463 | |||
4459 | ehci_add_intr_list(sc, exfer); | 4464 | ehci_add_intr_list(sc, exfer); | |
4460 | xfer->ux_status = USBD_IN_PROGRESS; | 4465 | xfer->ux_status = USBD_IN_PROGRESS; | |
4461 | ||||
4462 | mutex_exit(&sc->sc_lock); | 4466 | mutex_exit(&sc->sc_lock); | |
4463 | 4467 | |||
4464 | return USBD_IN_PROGRESS; | 4468 | return USBD_IN_PROGRESS; | |
4465 | } | 4469 | } | |
4466 | 4470 | |||
4467 | Static void | 4471 | Static void | |
4468 | ehci_device_fs_isoc_abort(struct usbd_xfer *xfer) | 4472 | ehci_device_fs_isoc_abort(struct usbd_xfer *xfer) | |
4469 | { | 4473 | { | |
4470 | EHCIHIST_FUNC(); EHCIHIST_CALLED(); | 4474 | EHCIHIST_FUNC(); EHCIHIST_CALLED(); | |
4471 | 4475 | |||
4472 | DPRINTF("xfer = %p", xfer, 0, 0, 0); | 4476 | DPRINTF("xfer = %p", xfer, 0, 0, 0); | |
4473 | ehci_abort_isoc_xfer(xfer, USBD_CANCELLED); | 4477 | ehci_abort_isoc_xfer(xfer, USBD_CANCELLED); | |
4474 | } | 4478 | } | |
@@ -4842,27 +4846,26 @@ ehci_device_isoc_transfer(struct usbd_xf | @@ -4842,27 +4846,26 @@ ehci_device_isoc_transfer(struct usbd_xf | |||
4842 | 4846 | |||
4843 | frindex += i; | 4847 | frindex += i; | |
4844 | if (frindex >= sc->sc_flsize) | 4848 | if (frindex >= sc->sc_flsize) | |
4845 | frindex -= sc->sc_flsize; | 4849 | frindex -= sc->sc_flsize; | |
4846 | 4850 | |||
4847 | itd = itd->xfer_next; | 4851 | itd = itd->xfer_next; | |
4848 | } | 4852 | } | |
4849 | 4853 | |||
4850 | epipe->isoc.cur_xfers++; | 4854 | epipe->isoc.cur_xfers++; | |
4851 | epipe->isoc.next_frame = frindex; | 4855 | epipe->isoc.next_frame = frindex; | |
4852 | 4856 | |||
4853 | ehci_add_intr_list(sc, exfer); | 4857 | ehci_add_intr_list(sc, exfer); | |
4854 | xfer->ux_status = USBD_IN_PROGRESS; | 4858 | xfer->ux_status = USBD_IN_PROGRESS; | |
4855 | ||||
4856 | mutex_exit(&sc->sc_lock); | 4859 | mutex_exit(&sc->sc_lock); | |
4857 | 4860 | |||
4858 | return USBD_IN_PROGRESS; | 4861 | return USBD_IN_PROGRESS; | |
4859 | } | 4862 | } | |
4860 | 4863 | |||
4861 | Static void | 4864 | Static void | |
4862 | ehci_device_isoc_abort(struct usbd_xfer *xfer) | 4865 | ehci_device_isoc_abort(struct usbd_xfer *xfer) | |
4863 | { | 4866 | { | |
4864 | EHCIHIST_FUNC(); EHCIHIST_CALLED(); | 4867 | EHCIHIST_FUNC(); EHCIHIST_CALLED(); | |
4865 | 4868 | |||
4866 | DPRINTF("xfer = %p", xfer, 0, 0, 0); | 4869 | DPRINTF("xfer = %p", xfer, 0, 0, 0); | |
4867 | ehci_abort_isoc_xfer(xfer, USBD_CANCELLED); | 4870 | ehci_abort_isoc_xfer(xfer, USBD_CANCELLED); | |
4868 | } | 4871 | } |
--- src/sys/dev/usb/ehcivar.h 2017/04/05 19:54:19 1.42.12.1
+++ src/sys/dev/usb/ehcivar.h 2018/08/25 14:57:35 1.42.12.2
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: ehcivar.h,v 1.42.12.1 2017/04/05 19:54:19 snj Exp $ */ | 1 | /* $NetBSD: ehcivar.h,v 1.42.12.2 2018/08/25 14:57:35 martin Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 2001 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 2001 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to The NetBSD Foundation | 7 | * This code is derived from software contributed to The NetBSD Foundation | |
8 | * by Lennart Augustsson (lennart@augustsson.net). | 8 | * by Lennart Augustsson (lennart@augustsson.net). | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
@@ -81,27 +81,26 @@ typedef struct ehci_soft_itd { | @@ -81,27 +81,26 @@ typedef struct ehci_soft_itd { | |||
81 | struct timeval t; /* store free time */ | 81 | struct timeval t; /* store free time */ | |
82 | } ehci_soft_itd_t; | 82 | } ehci_soft_itd_t; | |
83 | #define EHCI_ITD_SIZE ((sizeof(struct ehci_soft_itd) + EHCI_QH_ALIGN - 1) / EHCI_ITD_ALIGN * EHCI_ITD_ALIGN) | 83 | #define EHCI_ITD_SIZE ((sizeof(struct ehci_soft_itd) + EHCI_QH_ALIGN - 1) / EHCI_ITD_ALIGN * EHCI_ITD_ALIGN) | |
84 | #define EHCI_ITD_CHUNK (EHCI_PAGE_SIZE / EHCI_ITD_SIZE) | 84 | #define EHCI_ITD_CHUNK (EHCI_PAGE_SIZE / EHCI_ITD_SIZE) | |
85 | 85 | |||
86 | #define ehci_soft_sitd_t ehci_soft_itd_t | 86 | #define ehci_soft_sitd_t ehci_soft_itd_t | |
87 | #define ehci_soft_sitd ehci_soft_itd | 87 | #define ehci_soft_sitd ehci_soft_itd | |
88 | #define sc_softsitds sc_softitds | 88 | #define sc_softsitds sc_softitds | |
89 | #define EHCI_SITD_SIZE ((sizeof(struct ehci_soft_sitd) + EHCI_QH_ALIGN - 1) / EHCI_SITD_ALIGN * EHCI_SITD_ALIGN) | 89 | #define EHCI_SITD_SIZE ((sizeof(struct ehci_soft_sitd) + EHCI_QH_ALIGN - 1) / EHCI_SITD_ALIGN * EHCI_SITD_ALIGN) | |
90 | #define EHCI_SITD_CHUNK (EHCI_PAGE_SIZE / EHCI_SITD_SIZE) | 90 | #define EHCI_SITD_CHUNK (EHCI_PAGE_SIZE / EHCI_SITD_SIZE) | |
91 | 91 | |||
92 | struct ehci_xfer { | 92 | struct ehci_xfer { | |
93 | struct usbd_xfer ex_xfer; | 93 | struct usbd_xfer ex_xfer; | |
94 | struct usb_task ex_aborttask; | |||
95 | TAILQ_ENTRY(ehci_xfer) ex_next; /* list of active xfers */ | 94 | TAILQ_ENTRY(ehci_xfer) ex_next; /* list of active xfers */ | |
96 | enum { | 95 | enum { | |
97 | EX_NONE, | 96 | EX_NONE, | |
98 | EX_CTRL, | 97 | EX_CTRL, | |
99 | EX_BULK, | 98 | EX_BULK, | |
100 | EX_INTR, | 99 | EX_INTR, | |
101 | EX_ISOC, | 100 | EX_ISOC, | |
102 | EX_FS_ISOC | 101 | EX_FS_ISOC | |
103 | } ex_type; | 102 | } ex_type; | |
104 | /* ctrl/bulk/intr */ | 103 | /* ctrl/bulk/intr */ | |
105 | struct { | 104 | struct { | |
106 | ehci_soft_qtd_t **ex_sqtds; | 105 | ehci_soft_qtd_t **ex_sqtds; | |
107 | size_t ex_nsqtd; | 106 | size_t ex_nsqtd; | |
@@ -201,28 +200,26 @@ typedef struct ehci_softc { | @@ -201,28 +200,26 @@ typedef struct ehci_softc { | |||
201 | 200 | |||
202 | TAILQ_HEAD(, ehci_xfer) sc_intrhead; | 201 | TAILQ_HEAD(, ehci_xfer) sc_intrhead; | |
203 | 202 | |||
204 | ehci_soft_qh_t *sc_freeqhs; | 203 | ehci_soft_qh_t *sc_freeqhs; | |
205 | ehci_soft_qtd_t *sc_freeqtds; | 204 | ehci_soft_qtd_t *sc_freeqtds; | |
206 | LIST_HEAD(sc_freeitds, ehci_soft_itd) sc_freeitds; | 205 | LIST_HEAD(sc_freeitds, ehci_soft_itd) sc_freeitds; | |
207 | LIST_HEAD(sc_freesitds, ehci_soft_sitd) sc_freesitds; | 206 | LIST_HEAD(sc_freesitds, ehci_soft_sitd) sc_freesitds; | |
208 | 207 | |||
209 | int sc_noport; | 208 | int sc_noport; | |
210 | uint8_t sc_hasppc; /* has Port Power Control */ | 209 | uint8_t sc_hasppc; /* has Port Power Control */ | |
211 | uint8_t sc_istthreshold; /* ISOC Scheduling Threshold (uframes) */ | 210 | uint8_t sc_istthreshold; /* ISOC Scheduling Threshold (uframes) */ | |
212 | struct usbd_xfer *sc_intrxfer; | 211 | struct usbd_xfer *sc_intrxfer; | |
213 | char sc_isreset[EHCI_MAX_PORTS]; | 212 | char sc_isreset[EHCI_MAX_PORTS]; | |
214 | char sc_softwake; | |||
215 | kcondvar_t sc_softwake_cv; | |||
216 | 213 | |||
217 | uint32_t sc_eintrs; | 214 | uint32_t sc_eintrs; | |
218 | ehci_soft_qh_t *sc_async_head; | 215 | ehci_soft_qh_t *sc_async_head; | |
219 | 216 | |||
220 | pool_cache_t sc_xferpool; /* free xfer pool */ | 217 | pool_cache_t sc_xferpool; /* free xfer pool */ | |
221 | 218 | |||
222 | struct callout sc_tmo_intrlist; | 219 | struct callout sc_tmo_intrlist; | |
223 | 220 | |||
224 | device_t sc_child; /* /dev/usb# device */ | 221 | device_t sc_child; /* /dev/usb# device */ | |
225 | char sc_dying; | 222 | char sc_dying; | |
226 | 223 | |||
227 | void (*sc_vendor_init)(struct ehci_softc *); | 224 | void (*sc_vendor_init)(struct ehci_softc *); | |
228 | int (*sc_vendor_port_status)(struct ehci_softc *, uint32_t, int); | 225 | int (*sc_vendor_port_status)(struct ehci_softc *, uint32_t, int); |
--- src/sys/dev/usb/motg.c 2018/01/03 20:02:37 1.6.4.4
+++ src/sys/dev/usb/motg.c 2018/08/25 14:57:35 1.6.4.5
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: motg.c,v 1.6.4.4 2018/01/03 20:02:37 snj Exp $ */ | 1 | /* $NetBSD: motg.c,v 1.6.4.5 2018/08/25 14:57:35 martin Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 1998, 2004, 2011, 2012, 2014 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 1998, 2004, 2011, 2012, 2014 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to The NetBSD Foundation | 7 | * This code is derived from software contributed to The NetBSD Foundation | |
8 | * by Lennart Augustsson (lennart@augustsson.net) at | 8 | * by Lennart Augustsson (lennart@augustsson.net) at | |
9 | * Carlstedt Research & Technology, Jared D. McNeill (jmcneill@invisible.ca), | 9 | * Carlstedt Research & Technology, Jared D. McNeill (jmcneill@invisible.ca), | |
10 | * Matthew R. Green (mrg@eterna.com.au), and Manuel Bouyer (bouyer@netbsd.org). | 10 | * Matthew R. Green (mrg@eterna.com.au), and Manuel Bouyer (bouyer@netbsd.org). | |
11 | * | 11 | * | |
12 | * Redistribution and use in source and binary forms, with or without | 12 | * Redistribution and use in source and binary forms, with or without | |
13 | * modification, are permitted provided that the following conditions | 13 | * modification, are permitted provided that the following conditions | |
14 | * are met: | 14 | * are met: | |
@@ -30,27 +30,27 @@ | @@ -30,27 +30,27 @@ | |||
30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
31 | * POSSIBILITY OF SUCH DAMAGE. | 31 | * POSSIBILITY OF SUCH DAMAGE. | |
32 | */ | 32 | */ | |
33 | 33 | |||
34 | 34 | |||
35 | /* | 35 | /* | |
36 | * This file contains the driver for the Mentor Graphics Inventra USB | 36 | * This file contains the driver for the Mentor Graphics Inventra USB | |
37 | * 2.0 High Speed Dual-Role controller. | 37 | * 2.0 High Speed Dual-Role controller. | |
38 | * | 38 | * | |
39 | * NOTE: The current implementation only supports Device Side Mode! | 39 | * NOTE: The current implementation only supports Device Side Mode! | |
40 | */ | 40 | */ | |
41 | 41 | |||
42 | #include <sys/cdefs.h> | 42 | #include <sys/cdefs.h> | |
43 | __KERNEL_RCSID(0, "$NetBSD: motg.c,v 1.6.4.4 2018/01/03 20:02:37 snj Exp $"); | 43 | __KERNEL_RCSID(0, "$NetBSD: motg.c,v 1.6.4.5 2018/08/25 14:57:35 martin Exp $"); | |
44 | 44 | |||
45 | #ifdef _KERNEL_OPT | 45 | #ifdef _KERNEL_OPT | |
46 | #include "opt_motg.h" | 46 | #include "opt_motg.h" | |
47 | #include "opt_usb.h" | 47 | #include "opt_usb.h" | |
48 | #endif | 48 | #endif | |
49 | 49 | |||
50 | #include <sys/param.h> | 50 | #include <sys/param.h> | |
51 | 51 | |||
52 | #include <sys/bus.h> | 52 | #include <sys/bus.h> | |
53 | #include <sys/cpu.h> | 53 | #include <sys/cpu.h> | |
54 | #include <sys/device.h> | 54 | #include <sys/device.h> | |
55 | #include <sys/kernel.h> | 55 | #include <sys/kernel.h> | |
56 | #include <sys/kmem.h> | 56 | #include <sys/kmem.h> | |
@@ -2150,42 +2150,66 @@ motg_device_data_done(struct usbd_xfer * | @@ -2150,42 +2150,66 @@ motg_device_data_done(struct usbd_xfer * | |||
2150 | } | 2150 | } | |
2151 | 2151 | |||
2152 | void | 2152 | void | |
2153 | motg_device_clear_toggle(struct usbd_pipe *pipe) | 2153 | motg_device_clear_toggle(struct usbd_pipe *pipe) | |
2154 | { | 2154 | { | |
2155 | struct motg_pipe *otgpipe = MOTG_PIPE2MPIPE(pipe); | 2155 | struct motg_pipe *otgpipe = MOTG_PIPE2MPIPE(pipe); | |
2156 | otgpipe->nexttoggle = 0; | 2156 | otgpipe->nexttoggle = 0; | |
2157 | } | 2157 | } | |
2158 | 2158 | |||
2159 | /* Abort a device control request. */ | 2159 | /* Abort a device control request. */ | |
2160 | static void | 2160 | static void | |
2161 | motg_device_xfer_abort(struct usbd_xfer *xfer) | 2161 | motg_device_xfer_abort(struct usbd_xfer *xfer) | |
2162 | { | 2162 | { | |
2163 | int wake; | 2163 | MOTGHIST_FUNC(); MOTGHIST_CALLED(); | |
2164 | uint8_t csr; | 2164 | uint8_t csr; | |
2165 | struct motg_softc *sc = MOTG_XFER2SC(xfer); | 2165 | struct motg_softc *sc = MOTG_XFER2SC(xfer); | |
2166 | struct motg_pipe *otgpipe = MOTG_PIPE2MPIPE(xfer->ux_pipe); | 2166 | struct motg_pipe *otgpipe = MOTG_PIPE2MPIPE(xfer->ux_pipe); | |
2167 | ||||
2167 | KASSERT(mutex_owned(&sc->sc_lock)); | 2168 | KASSERT(mutex_owned(&sc->sc_lock)); | |
2169 | ASSERT_SLEEPABLE(); | |||
2168 | 2170 | |||
2169 | MOTGHIST_FUNC(); MOTGHIST_CALLED(); | 2171 | /* | |
2172 | * We are synchronously aborting. Try to stop the | |||
2173 | * callout and task, but if we can't, wait for them to | |||
2174 | * complete. | |||
2175 | */ | |||
2176 | callout_halt(&xfer->ux_callout, &sc->sc_lock); | |||
2177 | usb_rem_task_wait(xfer->ux_pipe->up_dev, &xfer->ux_aborttask, | |||
2178 | USB_TASKQ_HC, &sc->sc_lock); | |||
2179 | ||||
2180 | /* | |||
2181 | * The xfer cannot have been cancelled already. It is the | |||
2182 | * responsibility of the caller of usbd_abort_pipe not to try | |||
2183 | * to abort a pipe multiple times, whether concurrently or | |||
2184 | * sequentially. | |||
2185 | */ | |||
2186 | KASSERT(xfer->ux_status != USBD_CANCELLED); | |||
2170 | 2187 | |||
2171 | if (xfer->ux_hcflags & UXFER_ABORTING) { | 2188 | /* If anyone else beat us, we're done. */ | |
2172 | DPRINTF("already aborting", 0, 0, 0, 0); | 2189 | if (xfer->ux_status != USBD_IN_PROGRESS) | |
2173 | xfer->ux_hcflags |= UXFER_ABORTWAIT; | |||
2174 | while (xfer->ux_hcflags & UXFER_ABORTING) | |||
2175 | cv_wait(&xfer->ux_hccv, &sc->sc_lock); | |||
2176 | return; | 2190 | return; | |
2191 | ||||
2192 | /* We beat everyone else. Claim the status. */ | |||
2193 | xfer->ux_status = USBD_CANCELLED; | |||
2194 | ||||
2195 | /* | |||
2196 | * If we're dying, skip the hardware action and just notify the | |||
2197 | * software that we're done. | |||
2198 | */ | |||
2199 | if (sc->sc_dying) { | |||
2200 | goto dying; | |||
2177 | } | 2201 | } | |
2178 | xfer->ux_hcflags |= UXFER_ABORTING; | 2202 | ||
2179 | if (otgpipe->hw_ep->xfer == xfer) { | 2203 | if (otgpipe->hw_ep->xfer == xfer) { | |
2180 | KASSERT(xfer->ux_status == USBD_IN_PROGRESS); | 2204 | KASSERT(xfer->ux_status == USBD_IN_PROGRESS); | |
2181 | otgpipe->hw_ep->xfer = NULL; | 2205 | otgpipe->hw_ep->xfer = NULL; | |
2182 | if (otgpipe->hw_ep->ep_number > 0) { | 2206 | if (otgpipe->hw_ep->ep_number > 0) { | |
2183 | /* select endpoint */ | 2207 | /* select endpoint */ | |
2184 | UWRITE1(sc, MUSB2_REG_EPINDEX, | 2208 | UWRITE1(sc, MUSB2_REG_EPINDEX, | |
2185 | otgpipe->hw_ep->ep_number); | 2209 | otgpipe->hw_ep->ep_number); | |
2186 | if (otgpipe->hw_ep->phase == DATA_OUT) { | 2210 | if (otgpipe->hw_ep->phase == DATA_OUT) { | |
2187 | csr = UREAD1(sc, MUSB2_REG_TXCSRL); | 2211 | csr = UREAD1(sc, MUSB2_REG_TXCSRL); | |
2188 | while (csr & MUSB2_MASK_CSRL_TXFIFONEMPTY) { | 2212 | while (csr & MUSB2_MASK_CSRL_TXFIFONEMPTY) { | |
2189 | csr |= MUSB2_MASK_CSRL_TXFFLUSH; | 2213 | csr |= MUSB2_MASK_CSRL_TXFFLUSH; | |
2190 | UWRITE1(sc, MUSB2_REG_TXCSRL, csr); | 2214 | UWRITE1(sc, MUSB2_REG_TXCSRL, csr); | |
2191 | csr = UREAD1(sc, MUSB2_REG_TXCSRL); | 2215 | csr = UREAD1(sc, MUSB2_REG_TXCSRL); | |
@@ -2193,20 +2217,17 @@ motg_device_xfer_abort(struct usbd_xfer | @@ -2193,20 +2217,17 @@ motg_device_xfer_abort(struct usbd_xfer | |||
2193 | UWRITE1(sc, MUSB2_REG_TXCSRL, 0); | 2217 | UWRITE1(sc, MUSB2_REG_TXCSRL, 0); | |
2194 | } else if (otgpipe->hw_ep->phase == DATA_IN) { | 2218 | } else if (otgpipe->hw_ep->phase == DATA_IN) { | |
2195 | csr = UREAD1(sc, MUSB2_REG_RXCSRL); | 2219 | csr = UREAD1(sc, MUSB2_REG_RXCSRL); | |
2196 | while (csr & MUSB2_MASK_CSRL_RXPKTRDY) { | 2220 | while (csr & MUSB2_MASK_CSRL_RXPKTRDY) { | |
2197 | csr |= MUSB2_MASK_CSRL_RXFFLUSH; | 2221 | csr |= MUSB2_MASK_CSRL_RXFFLUSH; | |
2198 | UWRITE1(sc, MUSB2_REG_RXCSRL, csr); | 2222 | UWRITE1(sc, MUSB2_REG_RXCSRL, csr); | |
2199 | csr = UREAD1(sc, MUSB2_REG_RXCSRL); | 2223 | csr = UREAD1(sc, MUSB2_REG_RXCSRL); | |
2200 | } | 2224 | } | |
2201 | UWRITE1(sc, MUSB2_REG_RXCSRL, 0); | 2225 | UWRITE1(sc, MUSB2_REG_RXCSRL, 0); | |
2202 | } | 2226 | } | |
2203 | otgpipe->hw_ep->phase = IDLE; | 2227 | otgpipe->hw_ep->phase = IDLE; | |
2204 | } | 2228 | } | |
2205 | } | 2229 | } | |
2206 | xfer->ux_status = USBD_CANCELLED; /* make software ignore it */ | 2230 | dying: | |
2207 | wake = xfer->ux_hcflags & UXFER_ABORTWAIT; | |||
2208 | xfer->ux_hcflags &= ~(UXFER_ABORTING | UXFER_ABORTWAIT); | |||
2209 | usb_transfer_complete(xfer); | 2231 | usb_transfer_complete(xfer); | |
2210 | if (wake) | 2232 | KASSERT(mutex_owned(&sc->sc_lock)); | |
2211 | cv_broadcast(&xfer->ux_hccv); | |||
2212 | } | 2233 | } |
--- src/sys/dev/usb/ohci.c 2018/01/03 20:02:37 1.253.2.4
+++ src/sys/dev/usb/ohci.c 2018/08/25 14:57:35 1.253.2.5
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: ohci.c,v 1.253.2.4 2018/01/03 20:02:37 snj Exp $ */ | 1 | /* $NetBSD: ohci.c,v 1.253.2.5 2018/08/25 14:57:35 martin Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 1998, 2004, 2005, 2012 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 1998, 2004, 2005, 2012 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to The NetBSD Foundation | 7 | * This code is derived from software contributed to The NetBSD Foundation | |
8 | * by Lennart Augustsson (lennart@augustsson.net) at | 8 | * by Lennart Augustsson (lennart@augustsson.net) at | |
9 | * Carlstedt Research & Technology, Jared D. McNeill (jmcneill@invisible.ca) | 9 | * Carlstedt Research & Technology, Jared D. McNeill (jmcneill@invisible.ca) | |
10 | * and Matthew R. Green (mrg@eterna.com.au). | 10 | * and Matthew R. Green (mrg@eterna.com.au). | |
11 | * This code is derived from software contributed to The NetBSD Foundation | 11 | * This code is derived from software contributed to The NetBSD Foundation | |
12 | * by Charles M. Hannum. | 12 | * by Charles M. Hannum. | |
13 | * | 13 | * | |
14 | * Redistribution and use in source and binary forms, with or without | 14 | * Redistribution and use in source and binary forms, with or without | |
@@ -31,27 +31,27 @@ | @@ -31,27 +31,27 @@ | |||
31 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 31 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
32 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 32 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
33 | * POSSIBILITY OF SUCH DAMAGE. | 33 | * POSSIBILITY OF SUCH DAMAGE. | |
34 | */ | 34 | */ | |
35 | 35 | |||
36 | /* | 36 | /* | |
37 | * USB Open Host Controller driver. | 37 | * USB Open Host Controller driver. | |
38 | * | 38 | * | |
39 | * OHCI spec: http://www.compaq.com/productinfo/development/openhci.html | 39 | * OHCI spec: http://www.compaq.com/productinfo/development/openhci.html | |
40 | * USB spec: http://www.usb.org/developers/docs/ | 40 | * USB spec: http://www.usb.org/developers/docs/ | |
41 | */ | 41 | */ | |
42 | 42 | |||
43 | #include <sys/cdefs.h> | 43 | #include <sys/cdefs.h> | |
44 | __KERNEL_RCSID(0, "$NetBSD: ohci.c,v 1.253.2.4 2018/01/03 20:02:37 snj Exp $"); | 44 | __KERNEL_RCSID(0, "$NetBSD: ohci.c,v 1.253.2.5 2018/08/25 14:57:35 martin Exp $"); | |
45 | 45 | |||
46 | #ifdef _KERNEL_OPT | 46 | #ifdef _KERNEL_OPT | |
47 | #include "opt_usb.h" | 47 | #include "opt_usb.h" | |
48 | #endif | 48 | #endif | |
49 | 49 | |||
50 | #include <sys/param.h> | 50 | #include <sys/param.h> | |
51 | 51 | |||
52 | #include <sys/cpu.h> | 52 | #include <sys/cpu.h> | |
53 | #include <sys/device.h> | 53 | #include <sys/device.h> | |
54 | #include <sys/kernel.h> | 54 | #include <sys/kernel.h> | |
55 | #include <sys/kmem.h> | 55 | #include <sys/kmem.h> | |
56 | #include <sys/proc.h> | 56 | #include <sys/proc.h> | |
57 | #include <sys/queue.h> | 57 | #include <sys/queue.h> | |
@@ -374,28 +374,26 @@ ohci_detach(struct ohci_softc *sc, int f | @@ -374,28 +374,26 @@ ohci_detach(struct ohci_softc *sc, int f | |||
374 | if (sc->sc_child != NULL) | 374 | if (sc->sc_child != NULL) | |
375 | rv = config_detach(sc->sc_child, flags); | 375 | rv = config_detach(sc->sc_child, flags); | |
376 | 376 | |||
377 | if (rv != 0) | 377 | if (rv != 0) | |
378 | return rv; | 378 | return rv; | |
379 | 379 | |||
380 | callout_halt(&sc->sc_tmo_rhsc, &sc->sc_lock); | 380 | callout_halt(&sc->sc_tmo_rhsc, &sc->sc_lock); | |
381 | 381 | |||
382 | usb_delay_ms(&sc->sc_bus, 300); /* XXX let stray task complete */ | 382 | usb_delay_ms(&sc->sc_bus, 300); /* XXX let stray task complete */ | |
383 | callout_destroy(&sc->sc_tmo_rhsc); | 383 | callout_destroy(&sc->sc_tmo_rhsc); | |
384 | 384 | |||
385 | softint_disestablish(sc->sc_rhsc_si); | 385 | softint_disestablish(sc->sc_rhsc_si); | |
386 | 386 | |||
387 | cv_destroy(&sc->sc_softwake_cv); | |||
388 | ||||
389 | mutex_destroy(&sc->sc_lock); | 387 | mutex_destroy(&sc->sc_lock); | |
390 | mutex_destroy(&sc->sc_intr_lock); | 388 | mutex_destroy(&sc->sc_intr_lock); | |
391 | 389 | |||
392 | if (sc->sc_hcca != NULL) | 390 | if (sc->sc_hcca != NULL) | |
393 | usb_freemem(&sc->sc_bus, &sc->sc_hccadma); | 391 | usb_freemem(&sc->sc_bus, &sc->sc_hccadma); | |
394 | pool_cache_destroy(sc->sc_xferpool); | 392 | pool_cache_destroy(sc->sc_xferpool); | |
395 | 393 | |||
396 | return rv; | 394 | return rv; | |
397 | } | 395 | } | |
398 | 396 | |||
399 | ohci_soft_ed_t * | 397 | ohci_soft_ed_t * | |
400 | ohci_alloc_sed(ohci_softc_t *sc) | 398 | ohci_alloc_sed(ohci_softc_t *sc) | |
401 | { | 399 | { | |
@@ -776,27 +774,26 @@ ohci_init(ohci_softc_t *sc) | @@ -776,27 +774,26 @@ ohci_init(ohci_softc_t *sc) | |||
776 | usbd_status err; | 774 | usbd_status err; | |
777 | int i; | 775 | int i; | |
778 | uint32_t s, ctl, rwc, ival, hcr, fm, per, rev, desca /*, descb */; | 776 | uint32_t s, ctl, rwc, ival, hcr, fm, per, rev, desca /*, descb */; | |
779 | 777 | |||
780 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | 778 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | |
781 | 779 | |||
782 | aprint_normal_dev(sc->sc_dev, ""); | 780 | aprint_normal_dev(sc->sc_dev, ""); | |
783 | 781 | |||
784 | sc->sc_hcca = NULL; | 782 | sc->sc_hcca = NULL; | |
785 | callout_init(&sc->sc_tmo_rhsc, CALLOUT_MPSAFE); | 783 | callout_init(&sc->sc_tmo_rhsc, CALLOUT_MPSAFE); | |
786 | 784 | |||
787 | mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB); | 785 | mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB); | |
788 | mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_USB); | 786 | mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_USB); | |
789 | cv_init(&sc->sc_softwake_cv, "ohciab"); | |||
790 | 787 | |||
791 | sc->sc_rhsc_si = softint_establish(SOFTINT_USB | SOFTINT_MPSAFE, | 788 | sc->sc_rhsc_si = softint_establish(SOFTINT_USB | SOFTINT_MPSAFE, | |
792 | ohci_rhsc_softint, sc); | 789 | ohci_rhsc_softint, sc); | |
793 | 790 | |||
794 | for (i = 0; i < OHCI_HASH_SIZE; i++) | 791 | for (i = 0; i < OHCI_HASH_SIZE; i++) | |
795 | LIST_INIT(&sc->sc_hash_tds[i]); | 792 | LIST_INIT(&sc->sc_hash_tds[i]); | |
796 | for (i = 0; i < OHCI_HASH_SIZE; i++) | 793 | for (i = 0; i < OHCI_HASH_SIZE; i++) | |
797 | LIST_INIT(&sc->sc_hash_itds[i]); | 794 | LIST_INIT(&sc->sc_hash_itds[i]); | |
798 | 795 | |||
799 | sc->sc_xferpool = pool_cache_init(sizeof(struct ohci_xfer), 0, 0, 0, | 796 | sc->sc_xferpool = pool_cache_init(sizeof(struct ohci_xfer), 0, 0, 0, | |
800 | "ohcixfer", NULL, IPL_USB, NULL, NULL, NULL); | 797 | "ohcixfer", NULL, IPL_USB, NULL, NULL, NULL); | |
801 | 798 | |||
802 | rev = OREAD4(sc, OHCI_REVISION); | 799 | rev = OREAD4(sc, OHCI_REVISION); | |
@@ -1058,26 +1055,30 @@ ohci_init(ohci_softc_t *sc) | @@ -1058,26 +1055,30 @@ ohci_init(ohci_softc_t *sc) | |||
1058 | sc->sc_hcca = NULL; | 1055 | sc->sc_hcca = NULL; | |
1059 | return err; | 1056 | return err; | |
1060 | } | 1057 | } | |
1061 | 1058 | |||
1062 | struct usbd_xfer * | 1059 | struct usbd_xfer * | |
1063 | ohci_allocx(struct usbd_bus *bus, unsigned int nframes) | 1060 | ohci_allocx(struct usbd_bus *bus, unsigned int nframes) | |
1064 | { | 1061 | { | |
1065 | ohci_softc_t *sc = OHCI_BUS2SC(bus); | 1062 | ohci_softc_t *sc = OHCI_BUS2SC(bus); | |
1066 | struct usbd_xfer *xfer; | 1063 | struct usbd_xfer *xfer; | |
1067 | 1064 | |||
1068 | xfer = pool_cache_get(sc->sc_xferpool, PR_WAITOK); | 1065 | xfer = pool_cache_get(sc->sc_xferpool, PR_WAITOK); | |
1069 | if (xfer != NULL) { | 1066 | if (xfer != NULL) { | |
1070 | memset(xfer, 0, sizeof(struct ohci_xfer)); | 1067 | memset(xfer, 0, sizeof(struct ohci_xfer)); | |
1068 | ||||
1069 | /* Initialise this always so we can call remove on it. */ | |||
1070 | usb_init_task(&xfer->ux_aborttask, ohci_timeout_task, xfer, | |||
1071 | USB_TASKQ_MPSAFE); | |||
1071 | #ifdef DIAGNOSTIC | 1072 | #ifdef DIAGNOSTIC | |
1072 | xfer->ux_state = XFER_BUSY; | 1073 | xfer->ux_state = XFER_BUSY; | |
1073 | #endif | 1074 | #endif | |
1074 | } | 1075 | } | |
1075 | return xfer; | 1076 | return xfer; | |
1076 | } | 1077 | } | |
1077 | 1078 | |||
1078 | void | 1079 | void | |
1079 | ohci_freex(struct usbd_bus *bus, struct usbd_xfer *xfer) | 1080 | ohci_freex(struct usbd_bus *bus, struct usbd_xfer *xfer) | |
1080 | { | 1081 | { | |
1081 | ohci_softc_t *sc = OHCI_BUS2SC(bus); | 1082 | ohci_softc_t *sc = OHCI_BUS2SC(bus); | |
1082 | 1083 | |||
1083 | KASSERTMSG(xfer->ux_state == XFER_BUSY, | 1084 | KASSERTMSG(xfer->ux_state == XFER_BUSY, | |
@@ -1443,33 +1444,45 @@ ohci_softintr(void *v) | @@ -1443,33 +1444,45 @@ ohci_softintr(void *v) | |||
1443 | xfer = std->xfer; | 1444 | xfer = std->xfer; | |
1444 | stdnext = std->dnext; | 1445 | stdnext = std->dnext; | |
1445 | DPRINTFN(10, "std=%p xfer=%p hcpriv=%p", std, xfer, | 1446 | DPRINTFN(10, "std=%p xfer=%p hcpriv=%p", std, xfer, | |
1446 | xfer ? xfer->ux_hcpriv : 0, 0); | 1447 | xfer ? xfer->ux_hcpriv : 0, 0); | |
1447 | if (xfer == NULL) { | 1448 | if (xfer == NULL) { | |
1448 | /* | 1449 | /* | |
1449 | * xfer == NULL: There seems to be no xfer associated | 1450 | * xfer == NULL: There seems to be no xfer associated | |
1450 | * with this TD. It is tailp that happened to end up on | 1451 | * with this TD. It is tailp that happened to end up on | |
1451 | * the done queue. | 1452 | * the done queue. | |
1452 | * Shouldn't happen, but some chips are broken(?). | 1453 | * Shouldn't happen, but some chips are broken(?). | |
1453 | */ | 1454 | */ | |
1454 | continue; | 1455 | continue; | |
1455 | } | 1456 | } | |
1456 | if (xfer->ux_status == USBD_CANCELLED || | 1457 | ||
1457 | xfer->ux_status == USBD_TIMEOUT) { | 1458 | /* | |
1458 | DPRINTF("cancel/timeout %p", xfer, 0, 0, 0); | 1459 | * If software has completed it, either by cancellation | |
1459 | /* Handled by abort routine. */ | 1460 | * or timeout, drop it on the floor. | |
1461 | */ | |||
1462 | if (xfer->ux_status != USBD_IN_PROGRESS) { | |||
1463 | KASSERT(xfer->ux_status == USBD_CANCELLED || | |||
1464 | xfer->ux_status == USBD_TIMEOUT); | |||
1460 | continue; | 1465 | continue; | |
1461 | } | 1466 | } | |
1467 | ||||
1468 | /* | |||
1469 | * Cancel the timeout and the task, which have not yet | |||
1470 | * run. If they have already fired, at worst they are | |||
1471 | * waiting for the lock. They will see that the xfer | |||
1472 | * is no longer in progress and give up. | |||
1473 | */ | |||
1462 | callout_stop(&xfer->ux_callout); | 1474 | callout_stop(&xfer->ux_callout); | |
1475 | usb_rem_task(xfer->ux_pipe->up_dev, &xfer->ux_aborttask); | |||
1463 | 1476 | |||
1464 | len = std->len; | 1477 | len = std->len; | |
1465 | if (std->td.td_cbp != 0) | 1478 | if (std->td.td_cbp != 0) | |
1466 | len -= O32TOH(std->td.td_be) - | 1479 | len -= O32TOH(std->td.td_be) - | |
1467 | O32TOH(std->td.td_cbp) + 1; | 1480 | O32TOH(std->td.td_cbp) + 1; | |
1468 | DPRINTFN(10, "len=%d, flags=0x%x", len, std->flags, 0, 0); | 1481 | DPRINTFN(10, "len=%d, flags=0x%x", len, std->flags, 0, 0); | |
1469 | if (std->flags & OHCI_ADD_LEN) | 1482 | if (std->flags & OHCI_ADD_LEN) | |
1470 | xfer->ux_actlen += len; | 1483 | xfer->ux_actlen += len; | |
1471 | 1484 | |||
1472 | cc = OHCI_TD_GET_CC(O32TOH(std->td.td_flags)); | 1485 | cc = OHCI_TD_GET_CC(O32TOH(std->td.td_flags)); | |
1473 | if (cc == OHCI_CC_NO_ERROR) { | 1486 | if (cc == OHCI_CC_NO_ERROR) { | |
1474 | ohci_hash_rem_td(sc, std); | 1487 | ohci_hash_rem_td(sc, std); | |
1475 | if (std->flags & OHCI_CALL_DONE) { | 1488 | if (std->flags & OHCI_CALL_DONE) { | |
@@ -1519,32 +1532,46 @@ ohci_softintr(void *v) | @@ -1519,32 +1532,46 @@ ohci_softintr(void *v) | |||
1519 | for (sitd = sidone; sitd; sitd = sitd->dnext) | 1532 | for (sitd = sidone; sitd; sitd = sitd->dnext) | |
1520 | ohci_dump_itd(sc, sitd); | 1533 | ohci_dump_itd(sc, sitd); | |
1521 | } | 1534 | } | |
1522 | #endif | 1535 | #endif | |
1523 | DPRINTFN(10, "--- ITD dump end ---", 0, 0, 0, 0); | 1536 | DPRINTFN(10, "--- ITD dump end ---", 0, 0, 0, 0); | |
1524 | 1537 | |||
1525 | for (sitd = sidone; sitd != NULL; sitd = sitdnext) { | 1538 | for (sitd = sidone; sitd != NULL; sitd = sitdnext) { | |
1526 | xfer = sitd->xfer; | 1539 | xfer = sitd->xfer; | |
1527 | sitdnext = sitd->dnext; | 1540 | sitdnext = sitd->dnext; | |
1528 | DPRINTFN(1, "sitd=%p xfer=%p hcpriv=%p", sitd, xfer, | 1541 | DPRINTFN(1, "sitd=%p xfer=%p hcpriv=%p", sitd, xfer, | |
1529 | xfer ? xfer->ux_hcpriv : 0, 0); | 1542 | xfer ? xfer->ux_hcpriv : 0, 0); | |
1530 | if (xfer == NULL) | 1543 | if (xfer == NULL) | |
1531 | continue; | 1544 | continue; | |
1532 | if (xfer->ux_status == USBD_CANCELLED || | 1545 | ||
1533 | xfer->ux_status == USBD_TIMEOUT) { | 1546 | /* | |
1534 | DPRINTF("cancel/timeout %p", xfer, 0, 0, 0); | 1547 | * If software has completed it, either by cancellation | |
1535 | /* Handled by abort routine. */ | 1548 | * or timeout, drop it on the floor. | |
1549 | */ | |||
1550 | if (xfer->ux_status != USBD_IN_PROGRESS) { | |||
1551 | KASSERT(xfer->ux_status == USBD_CANCELLED || | |||
1552 | xfer->ux_status == USBD_TIMEOUT); | |||
1536 | continue; | 1553 | continue; | |
1537 | } | 1554 | } | |
1555 | ||||
1556 | /* | |||
1557 | * Cancel the timeout and the task, which have not yet | |||
1558 | * run. If they have already fired, at worst they are | |||
1559 | * waiting for the lock. They will see that the xfer | |||
1560 | * is no longer in progress and give up. | |||
1561 | */ | |||
1562 | callout_stop(&xfer->ux_callout); | |||
1563 | usb_rem_task(xfer->ux_pipe->up_dev, &xfer->ux_aborttask); | |||
1564 | ||||
1538 | KASSERT(!sitd->isdone); | 1565 | KASSERT(!sitd->isdone); | |
1539 | #ifdef DIAGNOSTIC | 1566 | #ifdef DIAGNOSTIC | |
1540 | sitd->isdone = true; | 1567 | sitd->isdone = true; | |
1541 | #endif | 1568 | #endif | |
1542 | if (sitd->flags & OHCI_CALL_DONE) { | 1569 | if (sitd->flags & OHCI_CALL_DONE) { | |
1543 | ohci_soft_itd_t *next; | 1570 | ohci_soft_itd_t *next; | |
1544 | 1571 | |||
1545 | opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); | 1572 | opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); | |
1546 | opipe->isoc.inuse -= xfer->ux_nframes; | 1573 | opipe->isoc.inuse -= xfer->ux_nframes; | |
1547 | uedir = UE_GET_DIR(xfer->ux_pipe->up_endpoint->ue_edesc-> | 1574 | uedir = UE_GET_DIR(xfer->ux_pipe->up_endpoint->ue_edesc-> | |
1548 | bEndpointAddress); | 1575 | bEndpointAddress); | |
1549 | xfer->ux_status = USBD_NORMAL_COMPLETION; | 1576 | xfer->ux_status = USBD_NORMAL_COMPLETION; | |
1550 | actlen = 0; | 1577 | actlen = 0; | |
@@ -1578,32 +1605,28 @@ ohci_softintr(void *v) | @@ -1578,32 +1605,28 @@ ohci_softintr(void *v) | |||
1578 | ohci_hash_rem_itd(sc, sitd); | 1605 | ohci_hash_rem_itd(sc, sitd); | |
1579 | 1606 | |||
1580 | } | 1607 | } | |
1581 | ohci_hash_rem_itd(sc, sitd); | 1608 | ohci_hash_rem_itd(sc, sitd); | |
1582 | if (uedir == UE_DIR_IN && | 1609 | if (uedir == UE_DIR_IN && | |
1583 | xfer->ux_status == USBD_NORMAL_COMPLETION) | 1610 | xfer->ux_status == USBD_NORMAL_COMPLETION) | |
1584 | xfer->ux_actlen = actlen; | 1611 | xfer->ux_actlen = actlen; | |
1585 | xfer->ux_hcpriv = NULL; | 1612 | xfer->ux_hcpriv = NULL; | |
1586 | 1613 | |||
1587 | usb_transfer_complete(xfer); | 1614 | usb_transfer_complete(xfer); | |
1588 | } | 1615 | } | |
1589 | } | 1616 | } | |
1590 | 1617 | |||
1591 | if (sc->sc_softwake) { | |||
1592 | sc->sc_softwake = 0; | |||
1593 | cv_broadcast(&sc->sc_softwake_cv); | |||
1594 | } | |||
1595 | ||||
1596 | DPRINTFN(10, "done", 0, 0, 0, 0); | 1618 | DPRINTFN(10, "done", 0, 0, 0, 0); | |
1619 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); | |||
1597 | } | 1620 | } | |
1598 | 1621 | |||
1599 | void | 1622 | void | |
1600 | ohci_device_ctrl_done(struct usbd_xfer *xfer) | 1623 | ohci_device_ctrl_done(struct usbd_xfer *xfer) | |
1601 | { | 1624 | { | |
1602 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); | 1625 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); | |
1603 | ohci_softc_t *sc __diagused = OHCI_XFER2SC(xfer); | 1626 | ohci_softc_t *sc __diagused = OHCI_XFER2SC(xfer); | |
1604 | int len = UGETW(xfer->ux_request.wLength); | 1627 | int len = UGETW(xfer->ux_request.wLength); | |
1605 | int isread = (xfer->ux_request.bmRequestType & UT_READ); | 1628 | int isread = (xfer->ux_request.bmRequestType & UT_READ); | |
1606 | 1629 | |||
1607 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | 1630 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | |
1608 | DPRINTFN(10, "xfer=%p", xfer, 0, 0, 0); | 1631 | DPRINTFN(10, "xfer=%p", xfer, 0, 0, 0); | |
1609 | 1632 | |||
@@ -1866,45 +1889,37 @@ ohci_hash_find_itd(ohci_softc_t *sc, ohc | @@ -1866,45 +1889,37 @@ ohci_hash_find_itd(ohci_softc_t *sc, ohc | |||
1866 | ohci_soft_itd_t *sitd; | 1889 | ohci_soft_itd_t *sitd; | |
1867 | 1890 | |||
1868 | for (sitd = LIST_FIRST(&sc->sc_hash_itds[h]); | 1891 | for (sitd = LIST_FIRST(&sc->sc_hash_itds[h]); | |
1869 | sitd != NULL; | 1892 | sitd != NULL; | |
1870 | sitd = LIST_NEXT(sitd, hnext)) | 1893 | sitd = LIST_NEXT(sitd, hnext)) | |
1871 | if (sitd->physaddr == a) | 1894 | if (sitd->physaddr == a) | |
1872 | return sitd; | 1895 | return sitd; | |
1873 | return NULL; | 1896 | return NULL; | |
1874 | } | 1897 | } | |
1875 | 1898 | |||
1876 | void | 1899 | void | |
1877 | ohci_timeout(void *addr) | 1900 | ohci_timeout(void *addr) | |
1878 | { | 1901 | { | |
1902 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | |||
1879 | struct usbd_xfer *xfer = addr; | 1903 | struct usbd_xfer *xfer = addr; | |
1880 | struct ohci_xfer *oxfer = OHCI_XFER2OXFER(xfer); | |||
1881 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | 1904 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | |
1905 | struct usbd_device *dev = xfer->ux_pipe->up_dev; | |||
1882 | 1906 | |||
1883 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | 1907 | DPRINTF("xfer=%p", xfer, 0, 0, 0); | |
1884 | DPRINTF("oxfer=%p", oxfer, 0, 0, 0); | |||
1885 | ||||
1886 | if (sc->sc_dying) { | |||
1887 | mutex_enter(&sc->sc_lock); | |||
1888 | ohci_abort_xfer(xfer, USBD_TIMEOUT); | |||
1889 | mutex_exit(&sc->sc_lock); | |||
1890 | return; | |||
1891 | } | |||
1892 | 1908 | |||
1893 | /* Execute the abort in a process context. */ | 1909 | mutex_enter(&sc->sc_lock); | |
1894 | usb_init_task(&oxfer->abort_task, ohci_timeout_task, addr, | 1910 | if (!sc->sc_dying && xfer->ux_status == USBD_IN_PROGRESS) | |
1895 | USB_TASKQ_MPSAFE); | 1911 | usb_add_task(dev, &xfer->ux_aborttask, USB_TASKQ_HC); | |
1896 | usb_add_task(xfer->ux_pipe->up_dev, &oxfer->abort_task, | 1912 | mutex_exit(&sc->sc_lock); | |
1897 | USB_TASKQ_HC); | |||
1898 | } | 1913 | } | |
1899 | 1914 | |||
1900 | void | 1915 | void | |
1901 | ohci_timeout_task(void *addr) | 1916 | ohci_timeout_task(void *addr) | |
1902 | { | 1917 | { | |
1903 | struct usbd_xfer *xfer = addr; | 1918 | struct usbd_xfer *xfer = addr; | |
1904 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | 1919 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | |
1905 | 1920 | |||
1906 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | 1921 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | |
1907 | 1922 | |||
1908 | DPRINTF("xfer=%p", xfer, 0, 0, 0); | 1923 | DPRINTF("xfer=%p", xfer, 0, 0, 0); | |
1909 | 1924 | |||
1910 | mutex_enter(&sc->sc_lock); | 1925 | mutex_enter(&sc->sc_lock); | |
@@ -2174,109 +2189,133 @@ ohci_close_pipe(struct usbd_pipe *pipe, | @@ -2174,109 +2189,133 @@ ohci_close_pipe(struct usbd_pipe *pipe, | |||
2174 | (O32TOH(sed->ed.ed_headp) & OHCI_HEADMASK)) | 2189 | (O32TOH(sed->ed.ed_headp) & OHCI_HEADMASK)) | |
2175 | printf("ohci_close_pipe: pipe still not empty\n"); | 2190 | printf("ohci_close_pipe: pipe still not empty\n"); | |
2176 | } | 2191 | } | |
2177 | #endif | 2192 | #endif | |
2178 | ohci_rem_ed(sc, sed, head); | 2193 | ohci_rem_ed(sc, sed, head); | |
2179 | /* Make sure the host controller is not touching this ED */ | 2194 | /* Make sure the host controller is not touching this ED */ | |
2180 | usb_delay_ms(&sc->sc_bus, 1); | 2195 | usb_delay_ms(&sc->sc_bus, 1); | |
2181 | pipe->up_endpoint->ue_toggle = | 2196 | pipe->up_endpoint->ue_toggle = | |
2182 | (O32TOH(sed->ed.ed_headp) & OHCI_TOGGLECARRY) ? 1 : 0; | 2197 | (O32TOH(sed->ed.ed_headp) & OHCI_TOGGLECARRY) ? 1 : 0; | |
2183 | ohci_free_sed_locked(sc, opipe->sed); | 2198 | ohci_free_sed_locked(sc, opipe->sed); | |
2184 | } | 2199 | } | |
2185 | 2200 | |||
2186 | /* | 2201 | /* | |
2187 | * Abort a device request. | 2202 | * Cancel or timeout a device request. We have two cases to deal with | |
2188 | * If this routine is called at splusb() it guarantees that the request | 2203 | * | |
2189 | * will be removed from the hardware scheduling and that the callback | 2204 | * 1) A driver wants to stop scheduled or inflight transfers | |
2190 | * for it will be called with USBD_CANCELLED status. | 2205 | * 2) A transfer has timed out | |
2206 | * | |||
2191 | * It's impossible to guarantee that the requested transfer will not | 2207 | * It's impossible to guarantee that the requested transfer will not | |
2192 | * have happened since the hardware runs concurrently. | 2208 | * have (partially) happened since the hardware runs concurrently. | |
2193 | * If the transaction has already happened we rely on the ordinary | 2209 | * | |
2194 | * interrupt processing to process it. | 2210 | * Transfer state is protected by the bus lock and we set the transfer status | |
2195 | * XXX This is most probably wrong. | 2211 | * as soon as either of the above happens (with bus lock held). | |
2196 | * XXXMRG this doesn't make sense anymore. | 2212 | * | |
2213 | * Then we arrange for the hardware to tells us that it is not still | |||
2214 | * processing the TDs by setting the sKip bit and requesting a SOF interrupt | |||
2215 | * | |||
2216 | * Once we see the SOF interrupt we can check the transfer TDs/iTDs to see if | |||
2217 | * they've been processed and either | |||
2218 | * a) if they're unused recover them for later use, or | |||
2219 | * b) if they've been used allocate new TD/iTDs to replace those | |||
2220 | * used. The softint handler will free the old ones. | |||
2197 | */ | 2221 | */ | |
2198 | void | 2222 | void | |
2199 | ohci_abort_xfer(struct usbd_xfer *xfer, usbd_status status) | 2223 | ohci_abort_xfer(struct usbd_xfer *xfer, usbd_status status) | |
2200 | { | 2224 | { | |
2225 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | |||
2201 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); | 2226 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); | |
2202 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | 2227 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | |
2203 | ohci_soft_ed_t *sed = opipe->sed; | 2228 | ohci_soft_ed_t *sed = opipe->sed; | |
2204 | ohci_soft_td_t *p, *n; | 2229 | ohci_soft_td_t *p, *n; | |
2205 | ohci_physaddr_t headp; | 2230 | ohci_physaddr_t headp; | |
2206 | int hit; | 2231 | int hit; | |
2207 | int wake; | |||
2208 | 2232 | |||
2209 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | 2233 | KASSERTMSG((status == USBD_CANCELLED || status == USBD_TIMEOUT), | |
2234 | "invalid status for abort: %d", (int)status); | |||
2235 | ||||
2210 | DPRINTF("xfer=%p pipe=%p sed=%p", xfer, opipe,sed, 0); | 2236 | DPRINTF("xfer=%p pipe=%p sed=%p", xfer, opipe,sed, 0); | |
2211 | 2237 | |||
2212 | KASSERT(mutex_owned(&sc->sc_lock)); | 2238 | KASSERT(mutex_owned(&sc->sc_lock)); | |
2213 | ASSERT_SLEEPABLE(); | 2239 | ASSERT_SLEEPABLE(); | |
2214 | 2240 | |||
2215 | if (sc->sc_dying) { | 2241 | if (status == USBD_CANCELLED) { | |
2216 | /* If we're dying, just do the software part. */ | 2242 | /* | |
2217 | xfer->ux_status = status; /* make software ignore it */ | 2243 | * We are synchronously aborting. Try to stop the | |
2244 | * callout and task, but if we can't, wait for them to | |||
2245 | * complete. | |||
2246 | */ | |||
2218 | callout_halt(&xfer->ux_callout, &sc->sc_lock); | 2247 | callout_halt(&xfer->ux_callout, &sc->sc_lock); | |
2219 | usb_transfer_complete(xfer); | 2248 | usb_rem_task_wait(xfer->ux_pipe->up_dev, &xfer->ux_aborttask, | |
2220 | return; | 2249 | USB_TASKQ_HC, &sc->sc_lock); | |
2250 | } else { | |||
2251 | /* Otherwise, we are timing out. */ | |||
2252 | KASSERT(status == USBD_TIMEOUT); | |||
2221 | } | 2253 | } | |
2222 | 2254 | |||
2223 | /* | 2255 | /* | |
2224 | * If an abort is already in progress then just wait for it to | 2256 | * The xfer cannot have been cancelled already. It is the | |
2225 | * complete and return. | 2257 | * responsibility of the caller of usbd_abort_pipe not to try | |
2258 | * to abort a pipe multiple times, whether concurrently or | |||
2259 | * sequentially. | |||
2226 | */ | 2260 | */ | |
2227 | if (xfer->ux_hcflags & UXFER_ABORTING) { | 2261 | KASSERT(xfer->ux_status != USBD_CANCELLED); | |
2228 | DPRINTFN(2, "already aborting", 0, 0, 0, 0); | 2262 | ||
2229 | #ifdef DIAGNOSTIC | 2263 | /* Only the timeout, which runs only once, can time it out. */ | |
2230 | if (status == USBD_TIMEOUT) | 2264 | KASSERT(xfer->ux_status != USBD_TIMEOUT); | |
2231 | printf("%s: TIMEOUT while aborting\n", __func__); | 2265 | ||
2232 | #endif | 2266 | /* If anyone else beat us, we're done. */ | |
2233 | /* Override the status which might be USBD_TIMEOUT. */ | 2267 | if (xfer->ux_status != USBD_IN_PROGRESS) | |
2234 | xfer->ux_status = status; | 2268 | return; | |
2235 | DPRINTFN(2, "waiting for abort to finish", 0, 0, 0, 0); | 2269 | ||
2236 | xfer->ux_hcflags |= UXFER_ABORTWAIT; | 2270 | /* We beat everyone else. Claim the status. */ | |
2237 | while (xfer->ux_hcflags & UXFER_ABORTING) | 2271 | xfer->ux_status = status; | |
2238 | cv_wait(&xfer->ux_hccv, &sc->sc_lock); | 2272 | ||
2239 | goto done; | 2273 | /* | |
2274 | * If we're dying, skip the hardware action and just notify the | |||
2275 | * software that we're done. | |||
2276 | */ | |||
2277 | if (sc->sc_dying) { | |||
2278 | DPRINTFN(4, "xfer %#jx dying %ju", (uintptr_t)xfer, | |||
2279 | xfer->ux_status, 0, 0); | |||
2280 | goto dying; | |||
2240 | } | 2281 | } | |
2241 | xfer->ux_hcflags |= UXFER_ABORTING; | |||
2242 | 2282 | |||
2243 | /* | 2283 | /* | |
2244 | * Step 1: Make interrupt routine and hardware ignore xfer. | 2284 | * HC Step 1: Unless the endpoint is already halted, we set the endpoint | |
2285 | * descriptor sKip bit and wait for hardware to complete processing. | |||
2286 | * | |||
2287 | * This includes ensuring that any TDs of the transfer that got onto | |||
2288 | * the done list are also removed. We ensure this by waiting for | |||
2289 | * both a WDH and SOF interrupt. | |||
2245 | */ | 2290 | */ | |
2246 | xfer->ux_status = status; /* make software ignore it */ | |||
2247 | callout_stop(&xfer->ux_callout); | |||
2248 | DPRINTFN(1, "stop ed=%p", sed, 0, 0, 0); | 2291 | DPRINTFN(1, "stop ed=%p", sed, 0, 0, 0); | |
2249 | usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags), | 2292 | usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags), | |
2250 | sizeof(sed->ed.ed_flags), | 2293 | sizeof(sed->ed.ed_flags), | |
2251 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 2294 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
2252 | sed->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); /* force hardware skip */ | 2295 | sed->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); /* force hardware skip */ | |
2253 | usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags), | 2296 | usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags), | |
2254 | sizeof(sed->ed.ed_flags), | 2297 | sizeof(sed->ed.ed_flags), | |
2255 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 2298 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
2256 | 2299 | |||
2257 | /* | 2300 | /* | |
2258 | * Step 2: Wait until we know hardware has finished any possible | 2301 | * HC Step 2: Wait until we know hardware has finished any possible | |
2259 | * use of the xfer. Also make sure the soft interrupt routine | 2302 | * use of the xfer. | |
2260 | * has run. | |||
2261 | */ | 2303 | */ | |
2262 | /* Hardware finishes in 1ms */ | 2304 | /* Hardware finishes in 1ms */ | |
2263 | usb_delay_ms_locked(opipe->pipe.up_dev->ud_bus, 20, &sc->sc_lock); | 2305 | usb_delay_ms_locked(opipe->pipe.up_dev->ud_bus, 20, &sc->sc_lock); | |
2264 | sc->sc_softwake = 1; | |||
2265 | usb_schedsoftintr(&sc->sc_bus); | |||
2266 | cv_wait(&sc->sc_softwake_cv, &sc->sc_lock); | |||
2267 | 2306 | |||
2268 | /* | 2307 | /* | |
2269 | * Step 3: Remove any vestiges of the xfer from the hardware. | 2308 | * HC Step 3: Remove any vestiges of the xfer from the hardware. | |
2270 | * The complication here is that the hardware may have executed | 2309 | * The complication here is that the hardware may have executed | |
2271 | * beyond the xfer we're trying to abort. So as we're scanning | 2310 | * beyond the xfer we're trying to abort. So as we're scanning | |
2272 | * the TDs of this xfer we check if the hardware points to | 2311 | * the TDs of this xfer we check if the hardware points to | |
2273 | * any of them. | 2312 | * any of them. | |
2274 | */ | 2313 | */ | |
2275 | p = xfer->ux_hcpriv; | 2314 | p = xfer->ux_hcpriv; | |
2276 | KASSERT(p); | 2315 | KASSERT(p); | |
2277 | 2316 | |||
2278 | #ifdef OHCI_DEBUG | 2317 | #ifdef OHCI_DEBUG | |
2279 | DPRINTF("--- dump start ---", 0, 0, 0, 0); | 2318 | DPRINTF("--- dump start ---", 0, 0, 0, 0); | |
2280 | 2319 | |||
2281 | if (ohcidebug >= 2) { | 2320 | if (ohcidebug >= 2) { | |
2282 | DPRINTF("sed:", 0, 0, 0, 0); | 2321 | DPRINTF("sed:", 0, 0, 0, 0); | |
@@ -2296,46 +2335,43 @@ ohci_abort_xfer(struct usbd_xfer *xfer, | @@ -2296,46 +2335,43 @@ ohci_abort_xfer(struct usbd_xfer *xfer, | |||
2296 | if (hit) { | 2335 | if (hit) { | |
2297 | DPRINTFN(1, "set hd=0x%08x, tl=0x%08x", (int)p->physaddr, | 2336 | DPRINTFN(1, "set hd=0x%08x, tl=0x%08x", (int)p->physaddr, | |
2298 | (int)O32TOH(sed->ed.ed_tailp), 0, 0); | 2337 | (int)O32TOH(sed->ed.ed_tailp), 0, 0); | |
2299 | sed->ed.ed_headp = HTOO32(p->physaddr); /* unlink TDs */ | 2338 | sed->ed.ed_headp = HTOO32(p->physaddr); /* unlink TDs */ | |
2300 | usb_syncmem(&sed->dma, | 2339 | usb_syncmem(&sed->dma, | |
2301 | sed->offs + offsetof(ohci_ed_t, ed_headp), | 2340 | sed->offs + offsetof(ohci_ed_t, ed_headp), | |
2302 | sizeof(sed->ed.ed_headp), | 2341 | sizeof(sed->ed.ed_headp), | |
2303 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 2342 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
2304 | } else { | 2343 | } else { | |
2305 | DPRINTFN(1, "no hit", 0, 0, 0, 0); | 2344 | DPRINTFN(1, "no hit", 0, 0, 0, 0); | |
2306 | } | 2345 | } | |
2307 | 2346 | |||
2308 | /* | 2347 | /* | |
2309 | * Step 4: Turn on hardware again. | 2348 | * HC Step 4: Turn on hardware again. | |
2310 | */ | 2349 | */ | |
2311 | usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags), | 2350 | usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags), | |
2312 | sizeof(sed->ed.ed_flags), | 2351 | sizeof(sed->ed.ed_flags), | |
2313 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 2352 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
2314 | sed->ed.ed_flags &= HTOO32(~OHCI_ED_SKIP); /* remove hardware skip */ | 2353 | sed->ed.ed_flags &= HTOO32(~OHCI_ED_SKIP); /* remove hardware skip */ | |
2315 | usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags), | 2354 | usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags), | |
2316 | sizeof(sed->ed.ed_flags), | 2355 | sizeof(sed->ed.ed_flags), | |
2317 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 2356 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
2318 | 2357 | |||
2319 | /* | 2358 | /* | |
2320 | * Step 5: Execute callback. | 2359 | * Final step: Notify completion to waiting xfers. | |
2321 | */ | 2360 | */ | |
2322 | wake = xfer->ux_hcflags & UXFER_ABORTWAIT; | 2361 | dying: | |
2323 | xfer->ux_hcflags &= ~(UXFER_ABORTING | UXFER_ABORTWAIT); | |||
2324 | usb_transfer_complete(xfer); | 2362 | usb_transfer_complete(xfer); | |
2325 | if (wake) | 2363 | DPRINTFN(14, "end", 0, 0, 0, 0); | |
2326 | cv_broadcast(&xfer->ux_hccv); | |||
2327 | 2364 | |||
2328 | done: | |||
2329 | KASSERT(mutex_owned(&sc->sc_lock)); | 2365 | KASSERT(mutex_owned(&sc->sc_lock)); | |
2330 | } | 2366 | } | |
2331 | 2367 | |||
2332 | /* | 2368 | /* | |
2333 | * Data structures and routines to emulate the root hub. | 2369 | * Data structures and routines to emulate the root hub. | |
2334 | */ | 2370 | */ | |
2335 | Static int | 2371 | Static int | |
2336 | ohci_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req, | 2372 | ohci_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req, | |
2337 | void *buf, int buflen) | 2373 | void *buf, int buflen) | |
2338 | { | 2374 | { | |
2339 | ohci_softc_t *sc = OHCI_BUS2SC(bus); | 2375 | ohci_softc_t *sc = OHCI_BUS2SC(bus); | |
2340 | usb_port_status_t ps; | 2376 | usb_port_status_t ps; | |
2341 | uint16_t len, value, index; | 2377 | uint16_t len, value, index; | |
@@ -2830,26 +2866,27 @@ ohci_device_ctrl_start(struct usbd_xfer | @@ -2830,26 +2866,27 @@ ohci_device_ctrl_start(struct usbd_xfer | |||
2830 | sed->ed.ed_tailp = HTOO32(tail->physaddr); | 2866 | sed->ed.ed_tailp = HTOO32(tail->physaddr); | |
2831 | usb_syncmem(&sed->dma, | 2867 | usb_syncmem(&sed->dma, | |
2832 | sed->offs + offsetof(ohci_ed_t, ed_tailp), | 2868 | sed->offs + offsetof(ohci_ed_t, ed_tailp), | |
2833 | sizeof(sed->ed.ed_tailp), | 2869 | sizeof(sed->ed.ed_tailp), | |
2834 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 2870 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
2835 | OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF); | 2871 | OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF); | |
2836 | if (xfer->ux_timeout && !sc->sc_bus.ub_usepolling) { | 2872 | if (xfer->ux_timeout && !sc->sc_bus.ub_usepolling) { | |
2837 | callout_reset(&xfer->ux_callout, mstohz(xfer->ux_timeout), | 2873 | callout_reset(&xfer->ux_callout, mstohz(xfer->ux_timeout), | |
2838 | ohci_timeout, xfer); | 2874 | ohci_timeout, xfer); | |
2839 | } | 2875 | } | |
2840 | 2876 | |||
2841 | DPRINTF("done", 0, 0, 0, 0); | 2877 | DPRINTF("done", 0, 0, 0, 0); | |
2842 | 2878 | |||
2879 | xfer->ux_status = USBD_IN_PROGRESS; | |||
2843 | mutex_exit(&sc->sc_lock); | 2880 | mutex_exit(&sc->sc_lock); | |
2844 | 2881 | |||
2845 | return USBD_IN_PROGRESS; | 2882 | return USBD_IN_PROGRESS; | |
2846 | } | 2883 | } | |
2847 | 2884 | |||
2848 | /* Abort a device control request. */ | 2885 | /* Abort a device control request. */ | |
2849 | Static void | 2886 | Static void | |
2850 | ohci_device_ctrl_abort(struct usbd_xfer *xfer) | 2887 | ohci_device_ctrl_abort(struct usbd_xfer *xfer) | |
2851 | { | 2888 | { | |
2852 | ohci_softc_t *sc __diagused = OHCI_XFER2SC(xfer); | 2889 | ohci_softc_t *sc __diagused = OHCI_XFER2SC(xfer); | |
2853 | 2890 | |||
2854 | KASSERT(mutex_owned(&sc->sc_lock)); | 2891 | KASSERT(mutex_owned(&sc->sc_lock)); | |
2855 | 2892 | |||
@@ -3037,26 +3074,28 @@ ohci_device_bulk_start(struct usbd_xfer | @@ -3037,26 +3074,28 @@ ohci_device_bulk_start(struct usbd_xfer | |||
3037 | KASSERT(tdp->xfer == xfer); | 3074 | KASSERT(tdp->xfer == xfer); | |
3038 | } | 3075 | } | |
3039 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), | 3076 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), | |
3040 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 3077 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
3041 | sed->ed.ed_tailp = HTOO32(tail->physaddr); | 3078 | sed->ed.ed_tailp = HTOO32(tail->physaddr); | |
3042 | sed->ed.ed_flags &= HTOO32(~OHCI_ED_SKIP); | 3079 | sed->ed.ed_flags &= HTOO32(~OHCI_ED_SKIP); | |
3043 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), | 3080 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), | |
3044 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 3081 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
3045 | OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_BLF); | 3082 | OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_BLF); | |
3046 | if (xfer->ux_timeout && !sc->sc_bus.ub_usepolling) { | 3083 | if (xfer->ux_timeout && !sc->sc_bus.ub_usepolling) { | |
3047 | callout_reset(&xfer->ux_callout, mstohz(xfer->ux_timeout), | 3084 | callout_reset(&xfer->ux_callout, mstohz(xfer->ux_timeout), | |
3048 | ohci_timeout, xfer); | 3085 | ohci_timeout, xfer); | |
3049 | } | 3086 | } | |
3087 | ||||
3088 | xfer->ux_status = USBD_IN_PROGRESS; | |||
3050 | mutex_exit(&sc->sc_lock); | 3089 | mutex_exit(&sc->sc_lock); | |
3051 | 3090 | |||
3052 | return USBD_IN_PROGRESS; | 3091 | return USBD_IN_PROGRESS; | |
3053 | } | 3092 | } | |
3054 | 3093 | |||
3055 | Static void | 3094 | Static void | |
3056 | ohci_device_bulk_abort(struct usbd_xfer *xfer) | 3095 | ohci_device_bulk_abort(struct usbd_xfer *xfer) | |
3057 | { | 3096 | { | |
3058 | ohci_softc_t *sc __diagused = OHCI_XFER2SC(xfer); | 3097 | ohci_softc_t *sc __diagused = OHCI_XFER2SC(xfer); | |
3059 | 3098 | |||
3060 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | 3099 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | |
3061 | 3100 | |||
3062 | KASSERT(mutex_owned(&sc->sc_lock)); | 3101 | KASSERT(mutex_owned(&sc->sc_lock)); | |
@@ -3221,26 +3260,27 @@ ohci_device_intr_start(struct usbd_xfer | @@ -3221,26 +3260,27 @@ ohci_device_intr_start(struct usbd_xfer | |||
3221 | ohci_dump_tds(sc, data); | 3260 | ohci_dump_tds(sc, data); | |
3222 | } | 3261 | } | |
3223 | DPRINTFN(5, "--- dump end ---", 0, 0, 0, 0); | 3262 | DPRINTFN(5, "--- dump end ---", 0, 0, 0, 0); | |
3224 | #endif | 3263 | #endif | |
3225 | 3264 | |||
3226 | /* Insert ED in schedule */ | 3265 | /* Insert ED in schedule */ | |
3227 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), | 3266 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), | |
3228 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 3267 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
3229 | sed->ed.ed_tailp = HTOO32(tail->physaddr); | 3268 | sed->ed.ed_tailp = HTOO32(tail->physaddr); | |
3230 | sed->ed.ed_flags &= HTOO32(~OHCI_ED_SKIP); | 3269 | sed->ed.ed_flags &= HTOO32(~OHCI_ED_SKIP); | |
3231 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), | 3270 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), | |
3232 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 3271 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
3233 | 3272 | |||
3273 | xfer->ux_status = USBD_IN_PROGRESS; | |||
3234 | mutex_exit(&sc->sc_lock); | 3274 | mutex_exit(&sc->sc_lock); | |
3235 | 3275 | |||
3236 | return USBD_IN_PROGRESS; | 3276 | return USBD_IN_PROGRESS; | |
3237 | } | 3277 | } | |
3238 | 3278 | |||
3239 | /* Abort a device interrupt request. */ | 3279 | /* Abort a device interrupt request. */ | |
3240 | Static void | 3280 | Static void | |
3241 | ohci_device_intr_abort(struct usbd_xfer *xfer) | 3281 | ohci_device_intr_abort(struct usbd_xfer *xfer) | |
3242 | { | 3282 | { | |
3243 | ohci_softc_t *sc __diagused = OHCI_XFER2SC(xfer); | 3283 | ohci_softc_t *sc __diagused = OHCI_XFER2SC(xfer); | |
3244 | 3284 | |||
3245 | KASSERT(mutex_owned(&sc->sc_lock)); | 3285 | KASSERT(mutex_owned(&sc->sc_lock)); | |
3246 | KASSERT(xfer->ux_pipe->up_intrxfer == xfer); | 3286 | KASSERT(xfer->ux_pipe->up_intrxfer == xfer); |
--- src/sys/dev/usb/ohcivar.h 2017/04/05 19:54:19 1.55.4.1
+++ src/sys/dev/usb/ohcivar.h 2018/08/25 14:57:35 1.55.4.2
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: ohcivar.h,v 1.55.4.1 2017/04/05 19:54:19 snj Exp $ */ | 1 | /* $NetBSD: ohcivar.h,v 1.55.4.2 2018/08/25 14:57:35 martin Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 1998 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 1998 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to The NetBSD Foundation | 7 | * This code is derived from software contributed to The NetBSD Foundation | |
8 | * by Lennart Augustsson (lennart@augustsson.net) at | 8 | * by Lennart Augustsson (lennart@augustsson.net) at | |
9 | * Carlstedt Research & Technology. | 9 | * Carlstedt Research & Technology. | |
10 | * | 10 | * | |
11 | * Redistribution and use in source and binary forms, with or without | 11 | * Redistribution and use in source and binary forms, with or without | |
12 | * modification, are permitted provided that the following conditions | 12 | * modification, are permitted provided that the following conditions | |
13 | * are met: | 13 | * are met: | |
14 | * 1. Redistributions of source code must retain the above copyright | 14 | * 1. Redistributions of source code must retain the above copyright | |
@@ -108,54 +108,50 @@ typedef struct ohci_softc { | @@ -108,54 +108,50 @@ typedef struct ohci_softc { | |||
108 | LIST_HEAD(, ohci_soft_td) sc_hash_tds[OHCI_HASH_SIZE]; | 108 | LIST_HEAD(, ohci_soft_td) sc_hash_tds[OHCI_HASH_SIZE]; | |
109 | LIST_HEAD(, ohci_soft_itd) sc_hash_itds[OHCI_HASH_SIZE]; | 109 | LIST_HEAD(, ohci_soft_itd) sc_hash_itds[OHCI_HASH_SIZE]; | |
110 | 110 | |||
111 | int sc_noport; | 111 | int sc_noport; | |
112 | 112 | |||
113 | int sc_endian; | 113 | int sc_endian; | |
114 | #define OHCI_LITTLE_ENDIAN 0 /* typical (uninitialized default) */ | 114 | #define OHCI_LITTLE_ENDIAN 0 /* typical (uninitialized default) */ | |
115 | #define OHCI_BIG_ENDIAN 1 /* big endian OHCI? never seen it */ | 115 | #define OHCI_BIG_ENDIAN 1 /* big endian OHCI? never seen it */ | |
116 | #define OHCI_HOST_ENDIAN 2 /* if OHCI always matches CPU */ | 116 | #define OHCI_HOST_ENDIAN 2 /* if OHCI always matches CPU */ | |
117 | 117 | |||
118 | int sc_flags; | 118 | int sc_flags; | |
119 | #define OHCIF_SUPERIO 0x0001 | 119 | #define OHCIF_SUPERIO 0x0001 | |
120 | 120 | |||
121 | char sc_softwake; | |||
122 | kcondvar_t sc_softwake_cv; | |||
123 | ||||
124 | ohci_soft_ed_t *sc_freeeds; | 121 | ohci_soft_ed_t *sc_freeeds; | |
125 | ohci_soft_td_t *sc_freetds; | 122 | ohci_soft_td_t *sc_freetds; | |
126 | ohci_soft_itd_t *sc_freeitds; | 123 | ohci_soft_itd_t *sc_freeitds; | |
127 | 124 | |||
128 | pool_cache_t sc_xferpool; /* free xfer pool */ | 125 | pool_cache_t sc_xferpool; /* free xfer pool */ | |
129 | 126 | |||
130 | struct usbd_xfer *sc_intrxfer; | 127 | struct usbd_xfer *sc_intrxfer; | |
131 | 128 | |||
132 | char sc_vendor[32]; | 129 | char sc_vendor[32]; | |
133 | int sc_id_vendor; | 130 | int sc_id_vendor; | |
134 | 131 | |||
135 | uint32_t sc_control; /* Preserved during suspend/standby */ | 132 | uint32_t sc_control; /* Preserved during suspend/standby */ | |
136 | uint32_t sc_intre; | 133 | uint32_t sc_intre; | |
137 | 134 | |||
138 | u_int sc_overrun_cnt; | 135 | u_int sc_overrun_cnt; | |
139 | struct timeval sc_overrun_ntc; | 136 | struct timeval sc_overrun_ntc; | |
140 | 137 | |||
141 | struct callout sc_tmo_rhsc; | 138 | struct callout sc_tmo_rhsc; | |
142 | device_t sc_child; | 139 | device_t sc_child; | |
143 | char sc_dying; | 140 | char sc_dying; | |
144 | } ohci_softc_t; | 141 | } ohci_softc_t; | |
145 | 142 | |||
146 | struct ohci_xfer { | 143 | struct ohci_xfer { | |
147 | struct usbd_xfer xfer; | 144 | struct usbd_xfer xfer; | |
148 | struct usb_task abort_task; | |||
149 | /* ctrl */ | 145 | /* ctrl */ | |
150 | ohci_soft_td_t *ox_setup; | 146 | ohci_soft_td_t *ox_setup; | |
151 | ohci_soft_td_t *ox_stat; | 147 | ohci_soft_td_t *ox_stat; | |
152 | union { | 148 | union { | |
153 | /* ctrl/bulk/intr */ | 149 | /* ctrl/bulk/intr */ | |
154 | struct { | 150 | struct { | |
155 | ohci_soft_td_t **ox_stds; | 151 | ohci_soft_td_t **ox_stds; | |
156 | size_t ox_nstd; | 152 | size_t ox_nstd; | |
157 | }; | 153 | }; | |
158 | /* isoc */ | 154 | /* isoc */ | |
159 | struct { | 155 | struct { | |
160 | ohci_soft_itd_t **ox_sitds; | 156 | ohci_soft_itd_t **ox_sitds; | |
161 | size_t ox_nsitd; | 157 | size_t ox_nsitd; |
--- src/sys/dev/usb/uhci.c 2018/01/03 20:02:37 1.264.2.3
+++ src/sys/dev/usb/uhci.c 2018/08/25 14:57:35 1.264.2.4
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: uhci.c,v 1.264.2.3 2018/01/03 20:02:37 snj Exp $ */ | 1 | /* $NetBSD: uhci.c,v 1.264.2.4 2018/08/25 14:57:35 martin Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 1998, 2004, 2011, 2012 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 1998, 2004, 2011, 2012 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to The NetBSD Foundation | 7 | * This code is derived from software contributed to The NetBSD Foundation | |
8 | * by Lennart Augustsson (lennart@augustsson.net) at | 8 | * by Lennart Augustsson (lennart@augustsson.net) at | |
9 | * Carlstedt Research & Technology, Jared D. McNeill (jmcneill@invisible.ca) | 9 | * Carlstedt Research & Technology, Jared D. McNeill (jmcneill@invisible.ca) | |
10 | * and Matthew R. Green (mrg@eterna.com.au). | 10 | * and Matthew R. Green (mrg@eterna.com.au). | |
11 | * | 11 | * | |
12 | * Redistribution and use in source and binary forms, with or without | 12 | * Redistribution and use in source and binary forms, with or without | |
13 | * modification, are permitted provided that the following conditions | 13 | * modification, are permitted provided that the following conditions | |
14 | * are met: | 14 | * are met: | |
@@ -32,27 +32,27 @@ | @@ -32,27 +32,27 @@ | |||
32 | */ | 32 | */ | |
33 | 33 | |||
34 | /* | 34 | /* | |
35 | * USB Universal Host Controller driver. | 35 | * USB Universal Host Controller driver. | |
36 | * Handles e.g. PIIX3 and PIIX4. | 36 | * Handles e.g. PIIX3 and PIIX4. | |
37 | * | 37 | * | |
38 | * UHCI spec: http://www.intel.com/technology/usb/spec.htm | 38 | * UHCI spec: http://www.intel.com/technology/usb/spec.htm | |
39 | * USB spec: http://www.usb.org/developers/docs/ | 39 | * USB spec: http://www.usb.org/developers/docs/ | |
40 | * PIIXn spec: ftp://download.intel.com/design/intarch/datashts/29055002.pdf | 40 | * PIIXn spec: ftp://download.intel.com/design/intarch/datashts/29055002.pdf | |
41 | * ftp://download.intel.com/design/intarch/datashts/29056201.pdf | 41 | * ftp://download.intel.com/design/intarch/datashts/29056201.pdf | |
42 | */ | 42 | */ | |
43 | 43 | |||
44 | #include <sys/cdefs.h> | 44 | #include <sys/cdefs.h> | |
45 | __KERNEL_RCSID(0, "$NetBSD: uhci.c,v 1.264.2.3 2018/01/03 20:02:37 snj Exp $"); | 45 | __KERNEL_RCSID(0, "$NetBSD: uhci.c,v 1.264.2.4 2018/08/25 14:57:35 martin Exp $"); | |
46 | 46 | |||
47 | #ifdef _KERNEL_OPT | 47 | #ifdef _KERNEL_OPT | |
48 | #include "opt_usb.h" | 48 | #include "opt_usb.h" | |
49 | #endif | 49 | #endif | |
50 | 50 | |||
51 | #include <sys/param.h> | 51 | #include <sys/param.h> | |
52 | 52 | |||
53 | #include <sys/bus.h> | 53 | #include <sys/bus.h> | |
54 | #include <sys/cpu.h> | 54 | #include <sys/cpu.h> | |
55 | #include <sys/device.h> | 55 | #include <sys/device.h> | |
56 | #include <sys/kernel.h> | 56 | #include <sys/kernel.h> | |
57 | #include <sys/kmem.h> | 57 | #include <sys/kmem.h> | |
58 | #include <sys/mutex.h> | 58 | #include <sys/mutex.h> | |
@@ -564,28 +564,26 @@ uhci_init(uhci_softc_t *sc) | @@ -564,28 +564,26 @@ uhci_init(uhci_softc_t *sc) | |||
564 | } | 564 | } | |
565 | usb_syncmem(&sc->sc_dma, 0, | 565 | usb_syncmem(&sc->sc_dma, 0, | |
566 | UHCI_FRAMELIST_COUNT * sizeof(uhci_physaddr_t), | 566 | UHCI_FRAMELIST_COUNT * sizeof(uhci_physaddr_t), | |
567 | BUS_DMASYNC_PREWRITE); | 567 | BUS_DMASYNC_PREWRITE); | |
568 | 568 | |||
569 | 569 | |||
570 | TAILQ_INIT(&sc->sc_intrhead); | 570 | TAILQ_INIT(&sc->sc_intrhead); | |
571 | 571 | |||
572 | sc->sc_xferpool = pool_cache_init(sizeof(struct uhci_xfer), 0, 0, 0, | 572 | sc->sc_xferpool = pool_cache_init(sizeof(struct uhci_xfer), 0, 0, 0, | |
573 | "uhcixfer", NULL, IPL_USB, NULL, NULL, NULL); | 573 | "uhcixfer", NULL, IPL_USB, NULL, NULL, NULL); | |
574 | 574 | |||
575 | callout_init(&sc->sc_poll_handle, CALLOUT_MPSAFE); | 575 | callout_init(&sc->sc_poll_handle, CALLOUT_MPSAFE); | |
576 | 576 | |||
577 | cv_init(&sc->sc_softwake_cv, "uhciab"); | |||
578 | ||||
579 | /* Set up the bus struct. */ | 577 | /* Set up the bus struct. */ | |
580 | sc->sc_bus.ub_methods = &uhci_bus_methods; | 578 | sc->sc_bus.ub_methods = &uhci_bus_methods; | |
581 | sc->sc_bus.ub_pipesize = sizeof(struct uhci_pipe); | 579 | sc->sc_bus.ub_pipesize = sizeof(struct uhci_pipe); | |
582 | sc->sc_bus.ub_usedma = true; | 580 | sc->sc_bus.ub_usedma = true; | |
583 | 581 | |||
584 | UHCICMD(sc, UHCI_CMD_MAXP); /* Assume 64 byte packets at frame end */ | 582 | UHCICMD(sc, UHCI_CMD_MAXP); /* Assume 64 byte packets at frame end */ | |
585 | 583 | |||
586 | DPRINTF("Enabling...", 0, 0, 0, 0); | 584 | DPRINTF("Enabling...", 0, 0, 0, 0); | |
587 | 585 | |||
588 | err = uhci_run(sc, 1, 0); /* and here we go... */ | 586 | err = uhci_run(sc, 1, 0); /* and here we go... */ | |
589 | UWRITE2(sc, UHCI_INTR, UHCI_INTR_TOCRCIE | UHCI_INTR_RIE | | 587 | UWRITE2(sc, UHCI_INTR, UHCI_INTR_TOCRCIE | UHCI_INTR_RIE | | |
590 | UHCI_INTR_IOCE | UHCI_INTR_SPIE); /* enable interrupts */ | 588 | UHCI_INTR_IOCE | UHCI_INTR_SPIE); /* enable interrupts */ | |
591 | return err; | 589 | return err; | |
@@ -629,48 +627,49 @@ int | @@ -629,48 +627,49 @@ int | |||
629 | uhci_detach(struct uhci_softc *sc, int flags) | 627 | uhci_detach(struct uhci_softc *sc, int flags) | |
630 | { | 628 | { | |
631 | int rv = 0; | 629 | int rv = 0; | |
632 | 630 | |||
633 | if (sc->sc_child != NULL) | 631 | if (sc->sc_child != NULL) | |
634 | rv = config_detach(sc->sc_child, flags); | 632 | rv = config_detach(sc->sc_child, flags); | |
635 | 633 | |||
636 | if (rv != 0) | 634 | if (rv != 0) | |
637 | return rv; | 635 | return rv; | |
638 | 636 | |||
639 | callout_halt(&sc->sc_poll_handle, NULL); | 637 | callout_halt(&sc->sc_poll_handle, NULL); | |
640 | callout_destroy(&sc->sc_poll_handle); | 638 | callout_destroy(&sc->sc_poll_handle); | |
641 | 639 | |||
642 | cv_destroy(&sc->sc_softwake_cv); | |||
643 | ||||
644 | mutex_destroy(&sc->sc_lock); | 640 | mutex_destroy(&sc->sc_lock); | |
645 | mutex_destroy(&sc->sc_intr_lock); | 641 | mutex_destroy(&sc->sc_intr_lock); | |
646 | 642 | |||
647 | pool_cache_destroy(sc->sc_xferpool); | 643 | pool_cache_destroy(sc->sc_xferpool); | |
648 | 644 | |||
649 | /* XXX free other data structures XXX */ | 645 | /* XXX free other data structures XXX */ | |
650 | 646 | |||
651 | return rv; | 647 | return rv; | |
652 | } | 648 | } | |
653 | 649 | |||
654 | struct usbd_xfer * | 650 | struct usbd_xfer * | |
655 | uhci_allocx(struct usbd_bus *bus, unsigned int nframes) | 651 | uhci_allocx(struct usbd_bus *bus, unsigned int nframes) | |
656 | { | 652 | { | |
657 | struct uhci_softc *sc = UHCI_BUS2SC(bus); | 653 | struct uhci_softc *sc = UHCI_BUS2SC(bus); | |
658 | struct usbd_xfer *xfer; | 654 | struct usbd_xfer *xfer; | |
659 | 655 | |||
660 | xfer = pool_cache_get(sc->sc_xferpool, PR_WAITOK); | 656 | xfer = pool_cache_get(sc->sc_xferpool, PR_WAITOK); | |
661 | if (xfer != NULL) { | 657 | if (xfer != NULL) { | |
662 | memset(xfer, 0, sizeof(struct uhci_xfer)); | 658 | memset(xfer, 0, sizeof(struct uhci_xfer)); | |
663 | 659 | |||
660 | /* Initialise this always so we can call remove on it. */ | |||
661 | usb_init_task(&xfer->ux_aborttask, uhci_timeout_task, xfer, | |||
662 | USB_TASKQ_MPSAFE); | |||
664 | #ifdef DIAGNOSTIC | 663 | #ifdef DIAGNOSTIC | |
665 | struct uhci_xfer *uxfer = UHCI_XFER2UXFER(xfer); | 664 | struct uhci_xfer *uxfer = UHCI_XFER2UXFER(xfer); | |
666 | uxfer->ux_isdone = true; | 665 | uxfer->ux_isdone = true; | |
667 | xfer->ux_state = XFER_BUSY; | 666 | xfer->ux_state = XFER_BUSY; | |
668 | #endif | 667 | #endif | |
669 | } | 668 | } | |
670 | return xfer; | 669 | return xfer; | |
671 | } | 670 | } | |
672 | 671 | |||
673 | void | 672 | void | |
674 | uhci_freex(struct usbd_bus *bus, struct usbd_xfer *xfer) | 673 | uhci_freex(struct usbd_bus *bus, struct usbd_xfer *xfer) | |
675 | { | 674 | { | |
676 | struct uhci_softc *sc = UHCI_BUS2SC(bus); | 675 | struct uhci_softc *sc = UHCI_BUS2SC(bus); | |
@@ -1413,30 +1412,27 @@ uhci_softintr(void *v) | @@ -1413,30 +1412,27 @@ uhci_softintr(void *v) | |||
1413 | uhci_check_intr(sc, ux, &cq); | 1412 | uhci_check_intr(sc, ux, &cq); | |
1414 | } | 1413 | } | |
1415 | 1414 | |||
1416 | /* | 1415 | /* | |
1417 | * We abuse ux_list for the interrupt and complete lists and | 1416 | * We abuse ux_list for the interrupt and complete lists and | |
1418 | * interrupt transfers will get re-added here so use | 1417 | * interrupt transfers will get re-added here so use | |
1419 | * the _SAFE version of TAILQ_FOREACH. | 1418 | * the _SAFE version of TAILQ_FOREACH. | |
1420 | */ | 1419 | */ | |
1421 | TAILQ_FOREACH_SAFE(ux, &cq, ux_list, nextux) { | 1420 | TAILQ_FOREACH_SAFE(ux, &cq, ux_list, nextux) { | |
1422 | DPRINTF("ux %p", ux, 0, 0, 0); | 1421 | DPRINTF("ux %p", ux, 0, 0, 0); | |
1423 | usb_transfer_complete(&ux->ux_xfer); | 1422 | usb_transfer_complete(&ux->ux_xfer); | |
1424 | } | 1423 | } | |
1425 | 1424 | |||
1426 | if (sc->sc_softwake) { | 1425 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); | |
1427 | sc->sc_softwake = 0; | |||
1428 | cv_broadcast(&sc->sc_softwake_cv); | |||
1429 | } | |||
1430 | } | 1426 | } | |
1431 | 1427 | |||
1432 | /* Check for an interrupt. */ | 1428 | /* Check for an interrupt. */ | |
1433 | void | 1429 | void | |
1434 | uhci_check_intr(uhci_softc_t *sc, struct uhci_xfer *ux, ux_completeq_t *cqp) | 1430 | uhci_check_intr(uhci_softc_t *sc, struct uhci_xfer *ux, ux_completeq_t *cqp) | |
1435 | { | 1431 | { | |
1436 | uhci_soft_td_t *std, *fstd = NULL, *lstd = NULL; | 1432 | uhci_soft_td_t *std, *fstd = NULL, *lstd = NULL; | |
1437 | uint32_t status; | 1433 | uint32_t status; | |
1438 | 1434 | |||
1439 | UHCIHIST_FUNC(); UHCIHIST_CALLED(); | 1435 | UHCIHIST_FUNC(); UHCIHIST_CALLED(); | |
1440 | DPRINTFN(15, "ux %p", ux, 0, 0, 0); | 1436 | DPRINTFN(15, "ux %p", ux, 0, 0, 0); | |
1441 | 1437 | |||
1442 | KASSERT(ux != NULL); | 1438 | KASSERT(ux != NULL); | |
@@ -1472,28 +1468,26 @@ uhci_check_intr(uhci_softc_t *sc, struct | @@ -1472,28 +1468,26 @@ uhci_check_intr(uhci_softc_t *sc, struct | |||
1472 | lstd->offs + offsetof(uhci_td_t, td_status), | 1468 | lstd->offs + offsetof(uhci_td_t, td_status), | |
1473 | sizeof(lstd->td.td_status), | 1469 | sizeof(lstd->td.td_status), | |
1474 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 1470 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
1475 | status = le32toh(lstd->td.td_status); | 1471 | status = le32toh(lstd->td.td_status); | |
1476 | usb_syncmem(&lstd->dma, | 1472 | usb_syncmem(&lstd->dma, | |
1477 | lstd->offs + offsetof(uhci_td_t, td_status), | 1473 | lstd->offs + offsetof(uhci_td_t, td_status), | |
1478 | sizeof(lstd->td.td_status), | 1474 | sizeof(lstd->td.td_status), | |
1479 | BUS_DMASYNC_PREREAD); | 1475 | BUS_DMASYNC_PREREAD); | |
1480 | 1476 | |||
1481 | /* If the last TD is not marked active we can complete */ | 1477 | /* If the last TD is not marked active we can complete */ | |
1482 | if (!(status & UHCI_TD_ACTIVE)) { | 1478 | if (!(status & UHCI_TD_ACTIVE)) { | |
1483 | done: | 1479 | done: | |
1484 | DPRINTFN(12, "ux=%p done", ux, 0, 0, 0); | 1480 | DPRINTFN(12, "ux=%p done", ux, 0, 0, 0); | |
1485 | ||||
1486 | callout_stop(&xfer->ux_callout); | |||
1487 | uhci_idone(ux, cqp); | 1481 | uhci_idone(ux, cqp); | |
1488 | return; | 1482 | return; | |
1489 | } | 1483 | } | |
1490 | 1484 | |||
1491 | /* | 1485 | /* | |
1492 | * If the last TD is still active we need to check whether there | 1486 | * If the last TD is still active we need to check whether there | |
1493 | * is an error somewhere in the middle, or whether there was a | 1487 | * is an error somewhere in the middle, or whether there was a | |
1494 | * short packet (SPD and not ACTIVE). | 1488 | * short packet (SPD and not ACTIVE). | |
1495 | */ | 1489 | */ | |
1496 | DPRINTFN(12, "active ux=%p", ux, 0, 0, 0); | 1490 | DPRINTFN(12, "active ux=%p", ux, 0, 0, 0); | |
1497 | for (std = fstd; std != lstd; std = std->link.std) { | 1491 | for (std = fstd; std != lstd; std = std->link.std) { | |
1498 | usb_syncmem(&std->dma, | 1492 | usb_syncmem(&std->dma, | |
1499 | std->offs + offsetof(uhci_td_t, td_status), | 1493 | std->offs + offsetof(uhci_td_t, td_status), | |
@@ -1544,38 +1538,58 @@ uhci_check_intr(uhci_softc_t *sc, struct | @@ -1544,38 +1538,58 @@ uhci_check_intr(uhci_softc_t *sc, struct | |||
1544 | 1538 | |||
1545 | if ((status & UHCI_TD_SPD) && | 1539 | if ((status & UHCI_TD_SPD) && | |
1546 | UHCI_TD_GET_ACTLEN(status) < | 1540 | UHCI_TD_GET_ACTLEN(status) < | |
1547 | UHCI_TD_GET_MAXLEN(le32toh(std->td.td_token))) { | 1541 | UHCI_TD_GET_MAXLEN(le32toh(std->td.td_token))) { | |
1548 | goto done; | 1542 | goto done; | |
1549 | } | 1543 | } | |
1550 | } | 1544 | } | |
1551 | } | 1545 | } | |
1552 | 1546 | |||
1553 | /* Called with USB lock held. */ | 1547 | /* Called with USB lock held. */ | |
1554 | void | 1548 | void | |
1555 | uhci_idone(struct uhci_xfer *ux, ux_completeq_t *cqp) | 1549 | uhci_idone(struct uhci_xfer *ux, ux_completeq_t *cqp) | |
1556 | { | 1550 | { | |
1551 | UHCIHIST_FUNC(); UHCIHIST_CALLED(); | |||
1557 | struct usbd_xfer *xfer = &ux->ux_xfer; | 1552 | struct usbd_xfer *xfer = &ux->ux_xfer; | |
1558 | uhci_softc_t *sc __diagused = UHCI_XFER2SC(xfer); | 1553 | uhci_softc_t *sc __diagused = UHCI_XFER2SC(xfer); | |
1559 | struct uhci_pipe *upipe = UHCI_PIPE2UPIPE(xfer->ux_pipe); | 1554 | struct uhci_pipe *upipe = UHCI_PIPE2UPIPE(xfer->ux_pipe); | |
1560 | uhci_soft_td_t *std; | 1555 | uhci_soft_td_t *std; | |
1561 | uint32_t status = 0, nstatus; | 1556 | uint32_t status = 0, nstatus; | |
1562 | int actlen; | 1557 | int actlen; | |
1563 | 1558 | |||
1564 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); | 1559 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); | |
1565 | 1560 | |||
1566 | UHCIHIST_FUNC(); UHCIHIST_CALLED(); | |||
1567 | DPRINTFN(12, "ux=%p", ux, 0, 0, 0); | 1561 | DPRINTFN(12, "ux=%p", ux, 0, 0, 0); | |
1568 | 1562 | |||
1563 | /* | |||
1564 | * If software has completed it, either by cancellation | |||
1565 | * or timeout, drop it on the floor. | |||
1566 | */ | |||
1567 | if (xfer->ux_status != USBD_IN_PROGRESS) { | |||
1568 | KASSERT(xfer->ux_status == USBD_CANCELLED || | |||
1569 | xfer->ux_status == USBD_TIMEOUT); | |||
1570 | DPRINTF("aborted xfer=%#jx", (uintptr_t)xfer, 0, 0, 0); | |||
1571 | return; | |||
1572 | } | |||
1573 | ||||
1574 | /* | |||
1575 | * Cancel the timeout and the task, which have not yet | |||
1576 | * run. If they have already fired, at worst they are | |||
1577 | * waiting for the lock. They will see that the xfer | |||
1578 | * is no longer in progress and give up. | |||
1579 | */ | |||
1580 | callout_stop(&xfer->ux_callout); | |||
1581 | usb_rem_task(xfer->ux_pipe->up_dev, &xfer->ux_aborttask); | |||
1582 | ||||
1569 | #ifdef DIAGNOSTIC | 1583 | #ifdef DIAGNOSTIC | |
1570 | #ifdef UHCI_DEBUG | 1584 | #ifdef UHCI_DEBUG | |
1571 | if (ux->ux_isdone) { | 1585 | if (ux->ux_isdone) { | |
1572 | DPRINTF("--- dump start ---", 0, 0, 0, 0); | 1586 | DPRINTF("--- dump start ---", 0, 0, 0, 0); | |
1573 | uhci_dump_ii(ux); | 1587 | uhci_dump_ii(ux); | |
1574 | DPRINTF("--- dump end ---", 0, 0, 0, 0); | 1588 | DPRINTF("--- dump end ---", 0, 0, 0, 0); | |
1575 | } | 1589 | } | |
1576 | #endif | 1590 | #endif | |
1577 | KASSERT(!ux->ux_isdone); | 1591 | KASSERT(!ux->ux_isdone); | |
1578 | KASSERTMSG(!ux->ux_isdone, "xfer %p type %d status %d", xfer, | 1592 | KASSERTMSG(!ux->ux_isdone, "xfer %p type %d status %d", xfer, | |
1579 | ux->ux_type, xfer->ux_status); | 1593 | ux->ux_type, xfer->ux_status); | |
1580 | ux->ux_isdone = true; | 1594 | ux->ux_isdone = true; | |
1581 | #endif | 1595 | #endif | |
@@ -1689,46 +1703,37 @@ uhci_idone(struct uhci_xfer *ux, ux_comp | @@ -1689,46 +1703,37 @@ uhci_idone(struct uhci_xfer *ux, ux_comp | |||
1689 | if (cqp) | 1703 | if (cqp) | |
1690 | TAILQ_INSERT_TAIL(cqp, ux, ux_list); | 1704 | TAILQ_INSERT_TAIL(cqp, ux, ux_list); | |
1691 | 1705 | |||
1692 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); | 1706 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); | |
1693 | DPRINTFN(12, "ux=%p done", ux, 0, 0, 0); | 1707 | DPRINTFN(12, "ux=%p done", ux, 0, 0, 0); | |
1694 | } | 1708 | } | |
1695 | 1709 | |||
1696 | /* | 1710 | /* | |
1697 | * Called when a request does not complete. | 1711 | * Called when a request does not complete. | |
1698 | */ | 1712 | */ | |
1699 | void | 1713 | void | |
1700 | uhci_timeout(void *addr) | 1714 | uhci_timeout(void *addr) | |
1701 | { | 1715 | { | |
1716 | UHCIHIST_FUNC(); UHCIHIST_CALLED(); | |||
1702 | struct usbd_xfer *xfer = addr; | 1717 | struct usbd_xfer *xfer = addr; | |
1703 | struct uhci_xfer *uxfer = UHCI_XFER2UXFER(xfer); | |||
1704 | uhci_softc_t *sc = UHCI_XFER2SC(xfer); | 1718 | uhci_softc_t *sc = UHCI_XFER2SC(xfer); | |
1719 | struct usbd_device *dev = xfer->ux_pipe->up_dev; | |||
1705 | 1720 | |||
1706 | UHCIHIST_FUNC(); UHCIHIST_CALLED(); | 1721 | DPRINTF("xfer %p", xfer, 0, 0, 0); | |
1707 | ||||
1708 | DPRINTF("uxfer %p", uxfer, 0, 0, 0); | |||
1709 | 1722 | |||
1710 | if (sc->sc_dying) { | 1723 | mutex_enter(&sc->sc_lock); | |
1711 | mutex_enter(&sc->sc_lock); | 1724 | if (!sc->sc_dying && xfer->ux_status == USBD_IN_PROGRESS) | |
1712 | uhci_abort_xfer(xfer, USBD_TIMEOUT); | 1725 | usb_add_task(dev, &xfer->ux_aborttask, USB_TASKQ_HC); | |
1713 | mutex_exit(&sc->sc_lock); | 1726 | mutex_exit(&sc->sc_lock); | |
1714 | return; | |||
1715 | } | |||
1716 | ||||
1717 | /* Execute the abort in a process context. */ | |||
1718 | usb_init_task(&uxfer->ux_aborttask, uhci_timeout_task, xfer, | |||
1719 | USB_TASKQ_MPSAFE); | |||
1720 | usb_add_task(uxfer->ux_xfer.ux_pipe->up_dev, &uxfer->ux_aborttask, | |||
1721 | USB_TASKQ_HC); | |||
1722 | } | 1727 | } | |
1723 | 1728 | |||
1724 | void | 1729 | void | |
1725 | uhci_timeout_task(void *addr) | 1730 | uhci_timeout_task(void *addr) | |
1726 | { | 1731 | { | |
1727 | struct usbd_xfer *xfer = addr; | 1732 | struct usbd_xfer *xfer = addr; | |
1728 | uhci_softc_t *sc = UHCI_XFER2SC(xfer); | 1733 | uhci_softc_t *sc = UHCI_XFER2SC(xfer); | |
1729 | 1734 | |||
1730 | UHCIHIST_FUNC(); UHCIHIST_CALLED(); | 1735 | UHCIHIST_FUNC(); UHCIHIST_CALLED(); | |
1731 | 1736 | |||
1732 | DPRINTF("xfer=%p", xfer, 0, 0, 0); | 1737 | DPRINTF("xfer=%p", xfer, 0, 0, 0); | |
1733 | 1738 | |||
1734 | mutex_enter(&sc->sc_lock); | 1739 | mutex_enter(&sc->sc_lock); | |
@@ -2315,125 +2320,133 @@ uhci_device_bulk_start(struct usbd_xfer | @@ -2315,125 +2320,133 @@ uhci_device_bulk_start(struct usbd_xfer | |||
2315 | void | 2320 | void | |
2316 | uhci_device_bulk_abort(struct usbd_xfer *xfer) | 2321 | uhci_device_bulk_abort(struct usbd_xfer *xfer) | |
2317 | { | 2322 | { | |
2318 | uhci_softc_t *sc __diagused = UHCI_XFER2SC(xfer); | 2323 | uhci_softc_t *sc __diagused = UHCI_XFER2SC(xfer); | |
2319 | 2324 | |||
2320 | KASSERT(mutex_owned(&sc->sc_lock)); | 2325 | KASSERT(mutex_owned(&sc->sc_lock)); | |
2321 | 2326 | |||
2322 | UHCIHIST_FUNC(); UHCIHIST_CALLED(); | 2327 | UHCIHIST_FUNC(); UHCIHIST_CALLED(); | |
2323 | 2328 | |||
2324 | uhci_abort_xfer(xfer, USBD_CANCELLED); | 2329 | uhci_abort_xfer(xfer, USBD_CANCELLED); | |
2325 | } | 2330 | } | |
2326 | 2331 | |||
2327 | /* | 2332 | /* | |
2328 | * Abort a device request. | 2333 | * Cancel or timeout a device request. We have two cases to deal with | |
2329 | * If this routine is called at splusb() it guarantees that the request | 2334 | * | |
2330 | * will be removed from the hardware scheduling and that the callback | 2335 | * 1) A driver wants to stop scheduled or inflight transfers | |
2331 | * for it will be called with USBD_CANCELLED status. | 2336 | * 2) A transfer has timed out | |
2337 | * | |||
2332 | * It's impossible to guarantee that the requested transfer will not | 2338 | * It's impossible to guarantee that the requested transfer will not | |
2333 | * have happened since the hardware runs concurrently. | 2339 | * have (partially) happened since the hardware runs concurrently. | |
2334 | * If the transaction has already happened we rely on the ordinary | 2340 | * | |
2335 | * interrupt processing to process it. | 2341 | * Transfer state is protected by the bus lock and we set the transfer status | |
2336 | * XXX This is most probably wrong. | 2342 | * as soon as either of the above happens (with bus lock held). | |
2337 | * XXXMRG this doesn't make sense anymore. | 2343 | * | |
2344 | * To allow the hardware time to notice we simply wait. | |||
2338 | */ | 2345 | */ | |
2339 | void | 2346 | void | |
2340 | uhci_abort_xfer(struct usbd_xfer *xfer, usbd_status status) | 2347 | uhci_abort_xfer(struct usbd_xfer *xfer, usbd_status status) | |
2341 | { | 2348 | { | |
2349 | UHCIHIST_FUNC(); UHCIHIST_CALLED(); | |||
2342 | struct uhci_xfer *ux = UHCI_XFER2UXFER(xfer); | 2350 | struct uhci_xfer *ux = UHCI_XFER2UXFER(xfer); | |
2343 | struct uhci_pipe *upipe = UHCI_PIPE2UPIPE(xfer->ux_pipe); | 2351 | struct uhci_pipe *upipe = UHCI_PIPE2UPIPE(xfer->ux_pipe); | |
2344 | uhci_softc_t *sc = UHCI_XFER2SC(xfer); | 2352 | uhci_softc_t *sc = UHCI_XFER2SC(xfer); | |
2345 | uhci_soft_td_t *std; | 2353 | uhci_soft_td_t *std; | |
2346 | int wake; | |||
2347 | 2354 | |||
2348 | UHCIHIST_FUNC(); UHCIHIST_CALLED(); | 2355 | KASSERTMSG((status == USBD_CANCELLED || status == USBD_TIMEOUT), | |
2356 | "invalid status for abort: %d", (int)status); | |||
2357 | ||||
2349 | DPRINTFN(1,"xfer=%p, status=%d", xfer, status, 0, 0); | 2358 | DPRINTFN(1,"xfer=%p, status=%d", xfer, status, 0, 0); | |
2350 | 2359 | |||
2351 | KASSERT(mutex_owned(&sc->sc_lock)); | 2360 | KASSERT(mutex_owned(&sc->sc_lock)); | |
2352 | ASSERT_SLEEPABLE(); | 2361 | ASSERT_SLEEPABLE(); | |
2353 | 2362 | |||
2354 | if (sc->sc_dying) { | 2363 | if (status == USBD_CANCELLED) { | |
2355 | /* If we're dying, just do the software part. */ | 2364 | /* | |
2356 | xfer->ux_status = status; /* make software ignore it */ | 2365 | * We are synchronously aborting. Try to stop the | |
2357 | callout_stop(&xfer->ux_callout); | 2366 | * callout and task, but if we can't, wait for them to | |
2358 | usb_transfer_complete(xfer); | 2367 | * complete. | |
2359 | return; | 2368 | */ | |
2369 | callout_halt(&xfer->ux_callout, &sc->sc_lock); | |||
2370 | usb_rem_task_wait(xfer->ux_pipe->up_dev, &xfer->ux_aborttask, | |||
2371 | USB_TASKQ_HC, &sc->sc_lock); | |||
2372 | } else { | |||
2373 | /* Otherwise, we are timing out. */ | |||
2374 | KASSERT(status == USBD_TIMEOUT); | |||
2360 | } | 2375 | } | |
2361 | 2376 | |||
2362 | /* | 2377 | /* | |
2363 | * If an abort is already in progress then just wait for it to | 2378 | * The xfer cannot have been cancelled already. It is the | |
2364 | * complete and return. | 2379 | * responsibility of the caller of usbd_abort_pipe not to try | |
2380 | * to abort a pipe multiple times, whether concurrently or | |||
2381 | * sequentially. | |||
2365 | */ | 2382 | */ | |
2366 | if (xfer->ux_hcflags & UXFER_ABORTING) { | 2383 | KASSERT(xfer->ux_status != USBD_CANCELLED); | |
2367 | DPRINTFN(2, "already aborting", 0, 0, 0, 0); | 2384 | ||
2368 | #ifdef DIAGNOSTIC | 2385 | /* Only the timeout, which runs only once, can time it out. */ | |
2369 | if (status == USBD_TIMEOUT) | 2386 | KASSERT(xfer->ux_status != USBD_TIMEOUT); | |
2370 | printf("%s: TIMEOUT while aborting\n", __func__); | 2387 | ||
2371 | #endif | 2388 | /* If anyone else beat us, we're done. */ | |
2372 | /* Override the status which might be USBD_TIMEOUT. */ | 2389 | if (xfer->ux_status != USBD_IN_PROGRESS) | |
2373 | xfer->ux_status = status; | 2390 | return; | |
2374 | DPRINTFN(2, "waiting for abort to finish", 0, 0, 0, 0); | 2391 | ||
2375 | xfer->ux_hcflags |= UXFER_ABORTWAIT; | 2392 | /* We beat everyone else. Claim the status. */ | |
2376 | while (xfer->ux_hcflags & UXFER_ABORTING) | 2393 | xfer->ux_status = status; | |
2377 | cv_wait(&xfer->ux_hccv, &sc->sc_lock); | 2394 | ||
2378 | goto done; | 2395 | /* | |
2396 | * If we're dying, skip the hardware action and just notify the | |||
2397 | * software that we're done. | |||
2398 | */ | |||
2399 | if (sc->sc_dying) { | |||
2400 | DPRINTFN(4, "xfer %#jx dying %ju", (uintptr_t)xfer, | |||
2401 | xfer->ux_status, 0, 0); | |||
2402 | goto dying; | |||
2379 | } | 2403 | } | |
2380 | xfer->ux_hcflags |= UXFER_ABORTING; | |||
2381 | 2404 | |||
2382 | /* | 2405 | /* | |
2383 | * Step 1: Make interrupt routine and hardware ignore xfer. | 2406 | * HC Step 1: Make interrupt routine and hardware ignore xfer. | |
2384 | */ | 2407 | */ | |
2385 | xfer->ux_status = status; /* make software ignore it */ | |||
2386 | callout_stop(&xfer->ux_callout); | |||
2387 | uhci_del_intr_list(sc, ux); | 2408 | uhci_del_intr_list(sc, ux); | |
2388 | 2409 | |||
2389 | DPRINTF("stop ux=%p", ux, 0, 0, 0); | 2410 | DPRINTF("stop ux=%p", ux, 0, 0, 0); | |
2390 | for (std = ux->ux_stdstart; std != NULL; std = std->link.std) { | 2411 | for (std = ux->ux_stdstart; std != NULL; std = std->link.std) { | |
2391 | usb_syncmem(&std->dma, | 2412 | usb_syncmem(&std->dma, | |
2392 | std->offs + offsetof(uhci_td_t, td_status), | 2413 | std->offs + offsetof(uhci_td_t, td_status), | |
2393 | sizeof(std->td.td_status), | 2414 | sizeof(std->td.td_status), | |
2394 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 2415 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
2395 | std->td.td_status &= htole32(~(UHCI_TD_ACTIVE | UHCI_TD_IOC)); | 2416 | std->td.td_status &= htole32(~(UHCI_TD_ACTIVE | UHCI_TD_IOC)); | |
2396 | usb_syncmem(&std->dma, | 2417 | usb_syncmem(&std->dma, | |
2397 | std->offs + offsetof(uhci_td_t, td_status), | 2418 | std->offs + offsetof(uhci_td_t, td_status), | |
2398 | sizeof(std->td.td_status), | 2419 | sizeof(std->td.td_status), | |
2399 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 2420 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
2400 | } | 2421 | } | |
2401 | 2422 | |||
2402 | /* | 2423 | /* | |
2403 | * Step 2: Wait until we know hardware has finished any possible | 2424 | * HC Step 2: Wait until we know hardware has finished any possible | |
2404 | * use of the xfer. Also make sure the soft interrupt routine | 2425 | * use of the xfer. | |
2405 | * has run. | |||
2406 | */ | 2426 | */ | |
2407 | /* Hardware finishes in 1ms */ | 2427 | /* Hardware finishes in 1ms */ | |
2408 | usb_delay_ms_locked(upipe->pipe.up_dev->ud_bus, 2, &sc->sc_lock); | 2428 | usb_delay_ms_locked(upipe->pipe.up_dev->ud_bus, 2, &sc->sc_lock); | |
2409 | sc->sc_softwake = 1; | |||
2410 | usb_schedsoftintr(&sc->sc_bus); | |||
2411 | DPRINTF("cv_wait", 0, 0, 0, 0); | |||
2412 | cv_wait(&sc->sc_softwake_cv, &sc->sc_lock); | |||
2413 | 2429 | |||
2414 | /* | 2430 | /* | |
2415 | * Step 3: Execute callback. | 2431 | * HC Step 3: Notify completion to waiting xfers. | |
2416 | */ | 2432 | */ | |
2417 | DPRINTF("callback", 0, 0, 0, 0); | 2433 | dying: | |
2418 | #ifdef DIAGNOSTIC | 2434 | #ifdef DIAGNOSTIC | |
2419 | ux->ux_isdone = true; | 2435 | ux->ux_isdone = true; | |
2420 | #endif | 2436 | #endif | |
2421 | wake = xfer->ux_hcflags & UXFER_ABORTWAIT; | |||
2422 | xfer->ux_hcflags &= ~(UXFER_ABORTING | UXFER_ABORTWAIT); | |||
2423 | usb_transfer_complete(xfer); | 2437 | usb_transfer_complete(xfer); | |
2424 | if (wake) | 2438 | DPRINTFN(14, "end", 0, 0, 0, 0); | |
2425 | cv_broadcast(&xfer->ux_hccv); | 2439 | ||
2426 | done: | |||
2427 | KASSERT(mutex_owned(&sc->sc_lock)); | 2440 | KASSERT(mutex_owned(&sc->sc_lock)); | |
2428 | } | 2441 | } | |
2429 | 2442 | |||
2430 | /* Close a device bulk pipe. */ | 2443 | /* Close a device bulk pipe. */ | |
2431 | void | 2444 | void | |
2432 | uhci_device_bulk_close(struct usbd_pipe *pipe) | 2445 | uhci_device_bulk_close(struct usbd_pipe *pipe) | |
2433 | { | 2446 | { | |
2434 | struct uhci_pipe *upipe = UHCI_PIPE2UPIPE(pipe); | 2447 | struct uhci_pipe *upipe = UHCI_PIPE2UPIPE(pipe); | |
2435 | uhci_softc_t *sc = UHCI_PIPE2SC(pipe); | 2448 | uhci_softc_t *sc = UHCI_PIPE2SC(pipe); | |
2436 | 2449 | |||
2437 | KASSERT(mutex_owned(&sc->sc_lock)); | 2450 | KASSERT(mutex_owned(&sc->sc_lock)); | |
2438 | 2451 | |||
2439 | uhci_free_sqh(sc, upipe->bulk.sqh); | 2452 | uhci_free_sqh(sc, upipe->bulk.sqh); |
--- src/sys/dev/usb/uhcivar.h 2017/04/05 19:54:20 1.52.12.1
+++ src/sys/dev/usb/uhcivar.h 2018/08/25 14:57:35 1.52.12.2
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: uhcivar.h,v 1.52.12.1 2017/04/05 19:54:20 snj Exp $ */ | 1 | /* $NetBSD: uhcivar.h,v 1.52.12.2 2018/08/25 14:57:35 martin Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 1998 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 1998 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to The NetBSD Foundation | 7 | * This code is derived from software contributed to The NetBSD Foundation | |
8 | * by Lennart Augustsson (lennart@augustsson.net) at | 8 | * by Lennart Augustsson (lennart@augustsson.net) at | |
9 | * Carlstedt Research & Technology. | 9 | * Carlstedt Research & Technology. | |
10 | * | 10 | * | |
11 | * Redistribution and use in source and binary forms, with or without | 11 | * Redistribution and use in source and binary forms, with or without | |
12 | * modification, are permitted provided that the following conditions | 12 | * modification, are permitted provided that the following conditions | |
13 | * are met: | 13 | * are met: | |
14 | * 1. Redistributions of source code must retain the above copyright | 14 | * 1. Redistributions of source code must retain the above copyright | |
@@ -51,27 +51,26 @@ | @@ -51,27 +51,26 @@ | |||
51 | */ | 51 | */ | |
52 | #define UHCI_VFRAMELIST_COUNT 128 | 52 | #define UHCI_VFRAMELIST_COUNT 128 | |
53 | 53 | |||
54 | typedef struct uhci_soft_qh uhci_soft_qh_t; | 54 | typedef struct uhci_soft_qh uhci_soft_qh_t; | |
55 | typedef struct uhci_soft_td uhci_soft_td_t; | 55 | typedef struct uhci_soft_td uhci_soft_td_t; | |
56 | 56 | |||
57 | typedef union { | 57 | typedef union { | |
58 | struct uhci_soft_qh *sqh; | 58 | struct uhci_soft_qh *sqh; | |
59 | struct uhci_soft_td *std; | 59 | struct uhci_soft_td *std; | |
60 | } uhci_soft_td_qh_t; | 60 | } uhci_soft_td_qh_t; | |
61 | 61 | |||
62 | struct uhci_xfer { | 62 | struct uhci_xfer { | |
63 | struct usbd_xfer ux_xfer; | 63 | struct usbd_xfer ux_xfer; | |
64 | struct usb_task ux_aborttask; | |||
65 | enum { | 64 | enum { | |
66 | UX_NONE, UX_CTRL, UX_BULK, UX_INTR, UX_ISOC | 65 | UX_NONE, UX_CTRL, UX_BULK, UX_INTR, UX_ISOC | |
67 | } ux_type; | 66 | } ux_type; | |
68 | /* ctrl/bulk/intr */ | 67 | /* ctrl/bulk/intr */ | |
69 | struct { | 68 | struct { | |
70 | uhci_soft_td_t **ux_stds; | 69 | uhci_soft_td_t **ux_stds; | |
71 | size_t ux_nstd; | 70 | size_t ux_nstd; | |
72 | }; | 71 | }; | |
73 | union { | 72 | union { | |
74 | /* ctrl */ | 73 | /* ctrl */ | |
75 | struct { | 74 | struct { | |
76 | uhci_soft_td_t *ux_setup; | 75 | uhci_soft_td_t *ux_setup; | |
77 | uhci_soft_td_t *ux_data; | 76 | uhci_soft_td_t *ux_data; | |
@@ -142,51 +141,48 @@ struct uhci_vframe { | @@ -142,51 +141,48 @@ struct uhci_vframe { | |||
142 | uhci_soft_qh_t *eqh; /* pointer to last QH */ | 141 | uhci_soft_qh_t *eqh; /* pointer to last QH */ | |
143 | u_int bandwidth; /* max bandwidth used by this frame */ | 142 | u_int bandwidth; /* max bandwidth used by this frame */ | |
144 | }; | 143 | }; | |
145 | 144 | |||
146 | typedef struct uhci_softc { | 145 | typedef struct uhci_softc { | |
147 | device_t sc_dev; | 146 | device_t sc_dev; | |
148 | struct usbd_bus sc_bus; | 147 | struct usbd_bus sc_bus; | |
149 | bus_space_tag_t iot; | 148 | bus_space_tag_t iot; | |
150 | bus_space_handle_t ioh; | 149 | bus_space_handle_t ioh; | |
151 | bus_size_t sc_size; | 150 | bus_size_t sc_size; | |
152 | 151 | |||
153 | kmutex_t sc_lock; | 152 | kmutex_t sc_lock; | |
154 | kmutex_t sc_intr_lock; | 153 | kmutex_t sc_intr_lock; | |
155 | kcondvar_t sc_softwake_cv; | |||
156 | 154 | |||
157 | uhci_physaddr_t *sc_pframes; | 155 | uhci_physaddr_t *sc_pframes; | |
158 | usb_dma_t sc_dma; | 156 | usb_dma_t sc_dma; | |
159 | struct uhci_vframe sc_vframes[UHCI_VFRAMELIST_COUNT]; | 157 | struct uhci_vframe sc_vframes[UHCI_VFRAMELIST_COUNT]; | |
160 | 158 | |||
161 | uhci_soft_qh_t *sc_lctl_start; /* dummy QH for low speed control */ | 159 | uhci_soft_qh_t *sc_lctl_start; /* dummy QH for low speed control */ | |
162 | uhci_soft_qh_t *sc_lctl_end; /* last control QH */ | 160 | uhci_soft_qh_t *sc_lctl_end; /* last control QH */ | |
163 | uhci_soft_qh_t *sc_hctl_start; /* dummy QH for high speed control */ | 161 | uhci_soft_qh_t *sc_hctl_start; /* dummy QH for high speed control */ | |
164 | uhci_soft_qh_t *sc_hctl_end; /* last control QH */ | 162 | uhci_soft_qh_t *sc_hctl_end; /* last control QH */ | |
165 | uhci_soft_qh_t *sc_bulk_start; /* dummy QH for bulk */ | 163 | uhci_soft_qh_t *sc_bulk_start; /* dummy QH for bulk */ | |
166 | uhci_soft_qh_t *sc_bulk_end; /* last bulk transfer */ | 164 | uhci_soft_qh_t *sc_bulk_end; /* last bulk transfer */ | |
167 | uhci_soft_qh_t *sc_last_qh; /* dummy QH at the end */ | 165 | uhci_soft_qh_t *sc_last_qh; /* dummy QH at the end */ | |
168 | uint32_t sc_loops; /* number of QHs that wants looping */ | 166 | uint32_t sc_loops; /* number of QHs that wants looping */ | |
169 | 167 | |||
170 | uhci_soft_td_t *sc_freetds; /* TD free list */ | 168 | uhci_soft_td_t *sc_freetds; /* TD free list */ | |
171 | uhci_soft_qh_t *sc_freeqhs; /* QH free list */ | 169 | uhci_soft_qh_t *sc_freeqhs; /* QH free list */ | |
172 | 170 | |||
173 | pool_cache_t sc_xferpool; /* free xfer pool */ | 171 | pool_cache_t sc_xferpool; /* free xfer pool */ | |
174 | 172 | |||
175 | uint8_t sc_saved_sof; | 173 | uint8_t sc_saved_sof; | |
176 | uint16_t sc_saved_frnum; | 174 | uint16_t sc_saved_frnum; | |
177 | 175 | |||
178 | char sc_softwake; | |||
179 | ||||
180 | char sc_isreset; | 176 | char sc_isreset; | |
181 | char sc_suspend; | 177 | char sc_suspend; | |
182 | char sc_dying; | 178 | char sc_dying; | |
183 | 179 | |||
184 | TAILQ_HEAD(, uhci_xfer) sc_intrhead; | 180 | TAILQ_HEAD(, uhci_xfer) sc_intrhead; | |
185 | 181 | |||
186 | /* Info for the root hub interrupt "pipe". */ | 182 | /* Info for the root hub interrupt "pipe". */ | |
187 | int sc_ival; /* time between root hub intrs */ | 183 | int sc_ival; /* time between root hub intrs */ | |
188 | struct usbd_xfer *sc_intr_xfer; /* root hub interrupt transfer */ | 184 | struct usbd_xfer *sc_intr_xfer; /* root hub interrupt transfer */ | |
189 | struct callout sc_poll_handle; | 185 | struct callout sc_poll_handle; | |
190 | 186 | |||
191 | char sc_vendor[32]; /* vendor string for root hub */ | 187 | char sc_vendor[32]; /* vendor string for root hub */ | |
192 | int sc_id_vendor; /* vendor ID for root hub */ | 188 | int sc_id_vendor; /* vendor ID for root hub */ |
--- src/sys/dev/usb/usbdi.c 2017/04/05 19:54:21 1.161.2.2
+++ src/sys/dev/usb/usbdi.c 2018/08/25 14:57:35 1.161.2.3
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: usbdi.c,v 1.161.2.2 2017/04/05 19:54:21 snj Exp $ */ | 1 | /* $NetBSD: usbdi.c,v 1.161.2.3 2018/08/25 14:57:35 martin Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 1998, 2012, 2015 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 1998, 2012, 2015 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to The NetBSD Foundation | 7 | * This code is derived from software contributed to The NetBSD Foundation | |
8 | * by Lennart Augustsson (lennart@augustsson.net) at | 8 | * by Lennart Augustsson (lennart@augustsson.net) at | |
9 | * Carlstedt Research & Technology, Matthew R. Green (mrg@eterna.com.au), | 9 | * Carlstedt Research & Technology, Matthew R. Green (mrg@eterna.com.au), | |
10 | * and Nick Hudson. | 10 | * and Nick Hudson. | |
11 | * | 11 | * | |
12 | * Redistribution and use in source and binary forms, with or without | 12 | * Redistribution and use in source and binary forms, with or without | |
13 | * modification, are permitted provided that the following conditions | 13 | * modification, are permitted provided that the following conditions | |
14 | * are met: | 14 | * are met: | |
@@ -22,27 +22,27 @@ | @@ -22,27 +22,27 @@ | |||
22 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | 22 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
23 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 23 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
24 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | 24 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |
25 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 25 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
29 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 29 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
31 | * POSSIBILITY OF SUCH DAMAGE. | 31 | * POSSIBILITY OF SUCH DAMAGE. | |
32 | */ | 32 | */ | |
33 | 33 | |||
34 | #include <sys/cdefs.h> | 34 | #include <sys/cdefs.h> | |
35 | __KERNEL_RCSID(0, "$NetBSD: usbdi.c,v 1.161.2.2 2017/04/05 19:54:21 snj Exp $"); | 35 | __KERNEL_RCSID(0, "$NetBSD: usbdi.c,v 1.161.2.3 2018/08/25 14:57:35 martin Exp $"); | |
36 | 36 | |||
37 | #ifdef _KERNEL_OPT | 37 | #ifdef _KERNEL_OPT | |
38 | #include "opt_usb.h" | 38 | #include "opt_usb.h" | |
39 | #include "opt_compat_netbsd.h" | 39 | #include "opt_compat_netbsd.h" | |
40 | #include "usb_dma.h" | 40 | #include "usb_dma.h" | |
41 | #endif | 41 | #endif | |
42 | 42 | |||
43 | #include <sys/param.h> | 43 | #include <sys/param.h> | |
44 | #include <sys/systm.h> | 44 | #include <sys/systm.h> | |
45 | #include <sys/kernel.h> | 45 | #include <sys/kernel.h> | |
46 | #include <sys/device.h> | 46 | #include <sys/device.h> | |
47 | #include <sys/kmem.h> | 47 | #include <sys/kmem.h> | |
48 | #include <sys/proc.h> | 48 | #include <sys/proc.h> | |
@@ -269,26 +269,27 @@ usbd_close_pipe(struct usbd_pipe *pipe) | @@ -269,26 +269,27 @@ usbd_close_pipe(struct usbd_pipe *pipe) | |||
269 | 269 | |||
270 | usbd_status | 270 | usbd_status | |
271 | usbd_transfer(struct usbd_xfer *xfer) | 271 | usbd_transfer(struct usbd_xfer *xfer) | |
272 | { | 272 | { | |
273 | struct usbd_pipe *pipe = xfer->ux_pipe; | 273 | struct usbd_pipe *pipe = xfer->ux_pipe; | |
274 | usbd_status err; | 274 | usbd_status err; | |
275 | unsigned int size, flags; | 275 | unsigned int size, flags; | |
276 | 276 | |||
277 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); | 277 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); | |
278 | 278 | |||
279 | USBHIST_LOG(usbdebug, | 279 | USBHIST_LOG(usbdebug, | |
280 | "xfer = %p, flags = %#x, pipe = %p, running = %d", | 280 | "xfer = %p, flags = %#x, pipe = %p, running = %d", | |
281 | xfer, xfer->ux_flags, pipe, pipe->up_running); | 281 | xfer, xfer->ux_flags, pipe, pipe->up_running); | |
282 | KASSERT(xfer->ux_status == USBD_NOT_STARTED); | |||
282 | 283 | |||
283 | #ifdef USB_DEBUG | 284 | #ifdef USB_DEBUG | |
284 | if (usbdebug > 5) | 285 | if (usbdebug > 5) | |
285 | usbd_dump_queue(pipe); | 286 | usbd_dump_queue(pipe); | |
286 | #endif | 287 | #endif | |
287 | xfer->ux_done = 0; | 288 | xfer->ux_done = 0; | |
288 | 289 | |||
289 | if (pipe->up_aborting) { | 290 | if (pipe->up_aborting) { | |
290 | USBHIST_LOG(usbdebug, "<- done xfer %p, aborting", xfer, 0, 0, | 291 | USBHIST_LOG(usbdebug, "<- done xfer %p, aborting", xfer, 0, 0, | |
291 | 0); | 292 | 0); | |
292 | return USBD_CANCELLED; | 293 | return USBD_CANCELLED; | |
293 | } | 294 | } | |
294 | 295 | |||
@@ -333,27 +334,27 @@ usbd_transfer(struct usbd_xfer *xfer) | @@ -333,27 +334,27 @@ usbd_transfer(struct usbd_xfer *xfer) | |||
333 | SIMPLEQ_REMOVE_HEAD(&pipe->up_queue, ux_next); | 334 | SIMPLEQ_REMOVE_HEAD(&pipe->up_queue, ux_next); | |
334 | if (pipe->up_serialise) | 335 | if (pipe->up_serialise) | |
335 | usbd_start_next(pipe); | 336 | usbd_start_next(pipe); | |
336 | usbd_unlock_pipe(pipe); | 337 | usbd_unlock_pipe(pipe); | |
337 | } | 338 | } | |
338 | 339 | |||
339 | if (!(flags & USBD_SYNCHRONOUS)) { | 340 | if (!(flags & USBD_SYNCHRONOUS)) { | |
340 | USBHIST_LOG(usbdebug, "<- done xfer %p, not sync (err %d)", | 341 | USBHIST_LOG(usbdebug, "<- done xfer %p, not sync (err %d)", | |
341 | xfer, err, 0, 0); | 342 | xfer, err, 0, 0); | |
342 | return err; | 343 | return err; | |
343 | } | 344 | } | |
344 | 345 | |||
345 | if (err != USBD_IN_PROGRESS) { | 346 | if (err != USBD_IN_PROGRESS) { | |
346 | USBHIST_LOG(usbdebug, "<- done xfer %p, err %d (complete/error)", xfer, | 347 | USBHIST_LOG(usbdebug, "<- done xfer %p, sync err %d (complete/error)", xfer, | |
347 | err, 0, 0); | 348 | err, 0, 0); | |
348 | return err; | 349 | return err; | |
349 | } | 350 | } | |
350 | 351 | |||
351 | /* Sync transfer, wait for completion. */ | 352 | /* Sync transfer, wait for completion. */ | |
352 | usbd_lock_pipe(pipe); | 353 | usbd_lock_pipe(pipe); | |
353 | while (!xfer->ux_done) { | 354 | while (!xfer->ux_done) { | |
354 | if (pipe->up_dev->ud_bus->ub_usepolling) | 355 | if (pipe->up_dev->ud_bus->ub_usepolling) | |
355 | panic("usbd_transfer: not done"); | 356 | panic("usbd_transfer: not done"); | |
356 | USBHIST_LOG(usbdebug, "<- sleeping on xfer %p", xfer, 0, 0, 0); | 357 | USBHIST_LOG(usbdebug, "<- sleeping on xfer %p", xfer, 0, 0, 0); | |
357 | 358 | |||
358 | err = 0; | 359 | err = 0; | |
359 | if ((flags & USBD_SYNCHRONOUS_SIG) != 0) { | 360 | if ((flags & USBD_SYNCHRONOUS_SIG) != 0) { | |
@@ -465,50 +466,48 @@ usbd_alloc_xfer(struct usbd_device *dev, | @@ -465,50 +466,48 @@ usbd_alloc_xfer(struct usbd_device *dev, | |||
465 | { | 466 | { | |
466 | struct usbd_xfer *xfer; | 467 | struct usbd_xfer *xfer; | |
467 | 468 | |||
468 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); | 469 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); | |
469 | 470 | |||
470 | ASSERT_SLEEPABLE(); | 471 | ASSERT_SLEEPABLE(); | |
471 | 472 | |||
472 | xfer = dev->ud_bus->ub_methods->ubm_allocx(dev->ud_bus, nframes); | 473 | xfer = dev->ud_bus->ub_methods->ubm_allocx(dev->ud_bus, nframes); | |
473 | if (xfer == NULL) | 474 | if (xfer == NULL) | |
474 | return NULL; | 475 | return NULL; | |
475 | xfer->ux_bus = dev->ud_bus; | 476 | xfer->ux_bus = dev->ud_bus; | |
476 | callout_init(&xfer->ux_callout, CALLOUT_MPSAFE); | 477 | callout_init(&xfer->ux_callout, CALLOUT_MPSAFE); | |
477 | cv_init(&xfer->ux_cv, "usbxfer"); | 478 | cv_init(&xfer->ux_cv, "usbxfer"); | |
478 | cv_init(&xfer->ux_hccv, "usbhcxfer"); | |||
479 | 479 | |||
480 | USBHIST_LOG(usbdebug, "returns %p", xfer, 0, 0, 0); | 480 | USBHIST_LOG(usbdebug, "returns %p", xfer, 0, 0, 0); | |
481 | 481 | |||
482 | return xfer; | 482 | return xfer; | |
483 | } | 483 | } | |
484 | 484 | |||
485 | static usbd_status | 485 | static usbd_status | |
486 | usbd_free_xfer(struct usbd_xfer *xfer) | 486 | usbd_free_xfer(struct usbd_xfer *xfer) | |
487 | { | 487 | { | |
488 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); | 488 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); | |
489 | 489 | |||
490 | USBHIST_LOG(usbdebug, "%p", xfer, 0, 0, 0); | 490 | USBHIST_LOG(usbdebug, "%p", xfer, 0, 0, 0); | |
491 | if (xfer->ux_buf) { | 491 | if (xfer->ux_buf) { | |
492 | usbd_free_buffer(xfer); | 492 | usbd_free_buffer(xfer); | |
493 | } | 493 | } | |
494 | #if defined(DIAGNOSTIC) | 494 | #if defined(DIAGNOSTIC) | |
495 | if (callout_pending(&xfer->ux_callout)) { | 495 | if (callout_pending(&xfer->ux_callout)) { | |
496 | callout_stop(&xfer->ux_callout); | 496 | callout_stop(&xfer->ux_callout); | |
497 | printf("usbd_free_xfer: timeout_handle pending\n"); | 497 | printf("usbd_free_xfer: timeout_handle pending\n"); | |
498 | } | 498 | } | |
499 | #endif | 499 | #endif | |
500 | cv_destroy(&xfer->ux_cv); | 500 | cv_destroy(&xfer->ux_cv); | |
501 | cv_destroy(&xfer->ux_hccv); | |||
502 | xfer->ux_bus->ub_methods->ubm_freex(xfer->ux_bus, xfer); | 501 | xfer->ux_bus->ub_methods->ubm_freex(xfer->ux_bus, xfer); | |
503 | return USBD_NORMAL_COMPLETION; | 502 | return USBD_NORMAL_COMPLETION; | |
504 | } | 503 | } | |
505 | 504 | |||
506 | int | 505 | int | |
507 | usbd_create_xfer(struct usbd_pipe *pipe, size_t len, unsigned int flags, | 506 | usbd_create_xfer(struct usbd_pipe *pipe, size_t len, unsigned int flags, | |
508 | unsigned int nframes, struct usbd_xfer **xp) | 507 | unsigned int nframes, struct usbd_xfer **xp) | |
509 | { | 508 | { | |
510 | KASSERT(xp != NULL); | 509 | KASSERT(xp != NULL); | |
511 | void *buf = NULL; | 510 | void *buf = NULL; | |
512 | 511 | |||
513 | struct usbd_xfer *xfer = usbd_alloc_xfer(pipe->up_dev, nframes); | 512 | struct usbd_xfer *xfer = usbd_alloc_xfer(pipe->up_dev, nframes); | |
514 | if (xfer == NULL) | 513 | if (xfer == NULL) | |
@@ -897,27 +896,28 @@ usb_transfer_complete(struct usbd_xfer * | @@ -897,27 +896,28 @@ usb_transfer_complete(struct usbd_xfer * | |||
897 | int sync = xfer->ux_flags & USBD_SYNCHRONOUS; | 896 | int sync = xfer->ux_flags & USBD_SYNCHRONOUS; | |
898 | int erred = | 897 | int erred = | |
899 | xfer->ux_status == USBD_CANCELLED || | 898 | xfer->ux_status == USBD_CANCELLED || | |
900 | xfer->ux_status == USBD_TIMEOUT; | 899 | xfer->ux_status == USBD_TIMEOUT; | |
901 | int polling = bus->ub_usepolling; | 900 | int polling = bus->ub_usepolling; | |
902 | int repeat = pipe->up_repeat; | 901 | int repeat = pipe->up_repeat; | |
903 | 902 | |||
904 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); | 903 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); | |
905 | 904 | |||
906 | USBHIST_LOG(usbdebug, "pipe = %p xfer = %p status = %d actlen = %d", | 905 | USBHIST_LOG(usbdebug, "pipe = %p xfer = %p status = %d actlen = %d", | |
907 | pipe, xfer, xfer->ux_status, xfer->ux_actlen); | 906 | pipe, xfer, xfer->ux_status, xfer->ux_actlen); | |
908 | 907 | |||
909 | KASSERT(polling || mutex_owned(pipe->up_dev->ud_bus->ub_lock)); | 908 | KASSERT(polling || mutex_owned(pipe->up_dev->ud_bus->ub_lock)); | |
910 | KASSERT(xfer->ux_state == XFER_ONQU); | 909 | KASSERTMSG(xfer->ux_state == XFER_ONQU, "xfer %p state is %x", xfer, | |
910 | xfer->ux_state); | |||
911 | KASSERT(pipe != NULL); | 911 | KASSERT(pipe != NULL); | |
912 | 912 | |||
913 | if (!repeat) { | 913 | if (!repeat) { | |
914 | /* Remove request from queue. */ | 914 | /* Remove request from queue. */ | |
915 | 915 | |||
916 | KASSERTMSG(!SIMPLEQ_EMPTY(&pipe->up_queue), | 916 | KASSERTMSG(!SIMPLEQ_EMPTY(&pipe->up_queue), | |
917 | "pipe %p is empty, but xfer %p wants to complete", pipe, | 917 | "pipe %p is empty, but xfer %p wants to complete", pipe, | |
918 | xfer); | 918 | xfer); | |
919 | KASSERTMSG(xfer == SIMPLEQ_FIRST(&pipe->up_queue), | 919 | KASSERTMSG(xfer == SIMPLEQ_FIRST(&pipe->up_queue), | |
920 | "xfer %p is not start of queue (%p is at start)", xfer, | 920 | "xfer %p is not start of queue (%p is at start)", xfer, | |
921 | SIMPLEQ_FIRST(&pipe->up_queue)); | 921 | SIMPLEQ_FIRST(&pipe->up_queue)); | |
922 | 922 | |||
923 | #ifdef DIAGNOSTIC | 923 | #ifdef DIAGNOSTIC |
--- src/sys/dev/usb/usbdivar.h 2017/04/05 19:54:21 1.107.4.2
+++ src/sys/dev/usb/usbdivar.h 2018/08/25 14:57:35 1.107.4.3
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: usbdivar.h,v 1.107.4.2 2017/04/05 19:54:21 snj Exp $ */ | 1 | /* $NetBSD: usbdivar.h,v 1.107.4.3 2018/08/25 14:57:35 martin Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 1998, 2012 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 1998, 2012 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to The NetBSD Foundation | 7 | * This code is derived from software contributed to The NetBSD Foundation | |
8 | * by Lennart Augustsson (lennart@augustsson.net) at | 8 | * by Lennart Augustsson (lennart@augustsson.net) at | |
9 | * Carlstedt Research & Technology and Matthew R. Green (mrg@eterna.com.au). | 9 | * Carlstedt Research & Technology and Matthew R. Green (mrg@eterna.com.au). | |
10 | * | 10 | * | |
11 | * Redistribution and use in source and binary forms, with or without | 11 | * Redistribution and use in source and binary forms, with or without | |
12 | * modification, are permitted provided that the following conditions | 12 | * modification, are permitted provided that the following conditions | |
13 | * are met: | 13 | * are met: | |
14 | * 1. Redistributions of source code must retain the above copyright | 14 | * 1. Redistributions of source code must retain the above copyright | |
@@ -274,31 +274,28 @@ struct usbd_xfer { | @@ -274,31 +274,28 @@ struct usbd_xfer { | |||
274 | /* For memory allocation and softc */ | 274 | /* For memory allocation and softc */ | |
275 | struct usbd_bus *ux_bus; | 275 | struct usbd_bus *ux_bus; | |
276 | usb_dma_t ux_dmabuf; | 276 | usb_dma_t ux_dmabuf; | |
277 | void *ux_buf; | 277 | void *ux_buf; | |
278 | uint32_t ux_bufsize; | 278 | uint32_t ux_bufsize; | |
279 | 279 | |||
280 | uint8_t ux_rqflags; | 280 | uint8_t ux_rqflags; | |
281 | #define URQ_REQUEST 0x01 | 281 | #define URQ_REQUEST 0x01 | |
282 | 282 | |||
283 | SIMPLEQ_ENTRY(usbd_xfer) | 283 | SIMPLEQ_ENTRY(usbd_xfer) | |
284 | ux_next; | 284 | ux_next; | |
285 | 285 | |||
286 | void *ux_hcpriv; /* private use by the HC driver */ | 286 | void *ux_hcpriv; /* private use by the HC driver */ | |
287 | uint8_t ux_hcflags; /* private use by the HC driver */ | |||
288 | #define UXFER_ABORTING 0x01 /* xfer is aborting. */ | |||
289 | #define UXFER_ABORTWAIT 0x02 /* abort completion is being awaited. */ | |||
290 | kcondvar_t ux_hccv; /* private use by the HC driver */ | |||
291 | 287 | |||
288 | struct usb_task ux_aborttask; | |||
292 | struct callout ux_callout; | 289 | struct callout ux_callout; | |
293 | }; | 290 | }; | |
294 | 291 | |||
295 | void usbd_init(void); | 292 | void usbd_init(void); | |
296 | void usbd_finish(void); | 293 | void usbd_finish(void); | |
297 | 294 | |||
298 | #if defined(USB_DEBUG) | 295 | #if defined(USB_DEBUG) | |
299 | void usbd_dump_iface(struct usbd_interface *); | 296 | void usbd_dump_iface(struct usbd_interface *); | |
300 | void usbd_dump_device(struct usbd_device *); | 297 | void usbd_dump_device(struct usbd_device *); | |
301 | void usbd_dump_endpoint(struct usbd_endpoint *); | 298 | void usbd_dump_endpoint(struct usbd_endpoint *); | |
302 | void usbd_dump_queue(struct usbd_pipe *); | 299 | void usbd_dump_queue(struct usbd_pipe *); | |
303 | void usbd_dump_pipe(struct usbd_pipe *); | 300 | void usbd_dump_pipe(struct usbd_pipe *); | |
304 | #endif | 301 | #endif |
--- src/sys/dev/usb/xhci.c 2018/01/03 20:02:37 1.23.2.7
+++ src/sys/dev/usb/xhci.c 2018/08/25 14:57:35 1.23.2.8
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: xhci.c,v 1.23.2.7 2018/01/03 20:02:37 snj Exp $ */ | 1 | /* $NetBSD: xhci.c,v 1.23.2.8 2018/08/25 14:57:35 martin Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 2013 Jonathan A. Kollasch | 4 | * Copyright (c) 2013 Jonathan A. Kollasch | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | 7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | 8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | 9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | 10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | 11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | 13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | 14 | * documentation and/or other materials provided with the distribution. | |
@@ -24,27 +24,27 @@ | @@ -24,27 +24,27 @@ | |||
24 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR | 24 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR | |
25 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF | 25 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF | |
26 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
27 | */ | 27 | */ | |
28 | 28 | |||
29 | /* | 29 | /* | |
30 | * USB rev 2.0 and rev 3.1 specification | 30 | * USB rev 2.0 and rev 3.1 specification | |
31 | * http://www.usb.org/developers/docs/ | 31 | * http://www.usb.org/developers/docs/ | |
32 | * xHCI rev 1.1 specification | 32 | * xHCI rev 1.1 specification | |
33 | * http://www.intel.com/technology/usb/spec.htm | 33 | * http://www.intel.com/technology/usb/spec.htm | |
34 | */ | 34 | */ | |
35 | 35 | |||
36 | #include <sys/cdefs.h> | 36 | #include <sys/cdefs.h> | |
37 | __KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.23.2.7 2018/01/03 20:02:37 snj Exp $"); | 37 | __KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.23.2.8 2018/08/25 14:57:35 martin Exp $"); | |
38 | 38 | |||
39 | #ifdef _KERNEL_OPT | 39 | #ifdef _KERNEL_OPT | |
40 | #include "opt_usb.h" | 40 | #include "opt_usb.h" | |
41 | #endif | 41 | #endif | |
42 | 42 | |||
43 | #include <sys/param.h> | 43 | #include <sys/param.h> | |
44 | #include <sys/systm.h> | 44 | #include <sys/systm.h> | |
45 | #include <sys/kernel.h> | 45 | #include <sys/kernel.h> | |
46 | #include <sys/kmem.h> | 46 | #include <sys/kmem.h> | |
47 | #include <sys/device.h> | 47 | #include <sys/device.h> | |
48 | #include <sys/select.h> | 48 | #include <sys/select.h> | |
49 | #include <sys/proc.h> | 49 | #include <sys/proc.h> | |
50 | #include <sys/queue.h> | 50 | #include <sys/queue.h> | |
@@ -1650,105 +1650,111 @@ xhci_close_pipe(struct usbd_pipe *pipe) | @@ -1650,105 +1650,111 @@ xhci_close_pipe(struct usbd_pipe *pipe) | |||
1650 | XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_CONFIGURE_EP); | 1650 | XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_CONFIGURE_EP); | |
1651 | 1651 | |||
1652 | (void)xhci_do_command_locked(sc, &trb, USBD_DEFAULT_TIMEOUT); | 1652 | (void)xhci_do_command_locked(sc, &trb, USBD_DEFAULT_TIMEOUT); | |
1653 | usb_syncmem(&xs->xs_dc_dma, 0, sc->sc_pgsz, BUS_DMASYNC_POSTREAD); | 1653 | usb_syncmem(&xs->xs_dc_dma, 0, sc->sc_pgsz, BUS_DMASYNC_POSTREAD); | |
1654 | } | 1654 | } | |
1655 | 1655 | |||
1656 | /* | 1656 | /* | |
1657 | * Abort transfer. | 1657 | * Abort transfer. | |
1658 | * Should be called with sc_lock held. | 1658 | * Should be called with sc_lock held. | |
1659 | */ | 1659 | */ | |
1660 | static void | 1660 | static void | |
1661 | xhci_abort_xfer(struct usbd_xfer *xfer, usbd_status status) | 1661 | xhci_abort_xfer(struct usbd_xfer *xfer, usbd_status status) | |
1662 | { | 1662 | { | |
1663 | XHCIHIST_FUNC(); XHCIHIST_CALLED(); | |||
1663 | struct xhci_softc * const sc = XHCI_XFER2SC(xfer); | 1664 | struct xhci_softc * const sc = XHCI_XFER2SC(xfer); | |
1664 | struct xhci_slot * const xs = xfer->ux_pipe->up_dev->ud_hcpriv; | 1665 | struct xhci_slot * const xs = xfer->ux_pipe->up_dev->ud_hcpriv; | |
1665 | const u_int dci = xhci_ep_get_dci(xfer->ux_pipe->up_endpoint->ue_edesc); | 1666 | const u_int dci = xhci_ep_get_dci(xfer->ux_pipe->up_endpoint->ue_edesc); | |
1666 | 1667 | |||
1667 | XHCIHIST_FUNC(); XHCIHIST_CALLED(); | 1668 | KASSERTMSG((status == USBD_CANCELLED || status == USBD_TIMEOUT), | |
1669 | "invalid status for abort: %d", (int)status); | |||
1670 | ||||
1668 | DPRINTFN(4, "xfer %p pipe %p status %d", | 1671 | DPRINTFN(4, "xfer %p pipe %p status %d", | |
1669 | xfer, xfer->ux_pipe, status, 0); | 1672 | xfer, xfer->ux_pipe, status, 0); | |
1670 | 1673 | |||
1671 | KASSERT(mutex_owned(&sc->sc_lock)); | 1674 | KASSERT(mutex_owned(&sc->sc_lock)); | |
1675 | ASSERT_SLEEPABLE(); | |||
1672 | 1676 | |||
1673 | if (sc->sc_dying) { | 1677 | if (status == USBD_CANCELLED) { | |
1674 | /* If we're dying, just do the software part. */ | 1678 | /* | |
1675 | DPRINTFN(4, "xfer %p dying %u", xfer, xfer->ux_status, 0, 0); | 1679 | * We are synchronously aborting. Try to stop the | |
1676 | xfer->ux_status = status; | 1680 | * callout and task, but if we can't, wait for them to | |
1677 | callout_stop(&xfer->ux_callout); | 1681 | * complete. | |
1678 | usb_transfer_complete(xfer); | 1682 | */ | |
1679 | return; | 1683 | callout_halt(&xfer->ux_callout, &sc->sc_lock); | |
1684 | usb_rem_task_wait(xfer->ux_pipe->up_dev, &xfer->ux_aborttask, | |||
1685 | USB_TASKQ_HC, &sc->sc_lock); | |||
1686 | } else { | |||
1687 | /* Otherwise, we are timing out. */ | |||
1688 | KASSERT(status == USBD_TIMEOUT); | |||
1680 | } | 1689 | } | |
1681 | 1690 | |||
1682 | /* | 1691 | /* | |
1683 | * If an abort is already in progress then just wait for it to | 1692 | * The xfer cannot have been cancelled already. It is the | |
1684 | * complete and return. | 1693 | * responsibility of the caller of usbd_abort_pipe not to try | |
1694 | * to abort a pipe multiple times, whether concurrently or | |||
1695 | * sequentially. | |||
1685 | */ | 1696 | */ | |
1686 | if (xfer->ux_hcflags & UXFER_ABORTING) { | 1697 | KASSERT(xfer->ux_status != USBD_CANCELLED); | |
1687 | DPRINTFN(4, "already aborting", 0, 0, 0, 0); | 1698 | ||
1688 | #ifdef DIAGNOSTIC | 1699 | /* Only the timeout, which runs only once, can time it out. */ | |
1689 | if (status == USBD_TIMEOUT) | 1700 | KASSERT(xfer->ux_status != USBD_TIMEOUT); | |
1690 | DPRINTFN(4, "TIMEOUT while aborting", 0, 0, 0, 0); | 1701 | ||
1691 | #endif | 1702 | /* If anyone else beat us, we're done. */ | |
1692 | /* Override the status which might be USBD_TIMEOUT. */ | 1703 | if (xfer->ux_status != USBD_IN_PROGRESS) | |
1693 | xfer->ux_status = status; | 1704 | return; | |
1694 | DPRINTFN(4, "xfer %p waiting for abort to finish", xfer, 0, 0, | 1705 | ||
1695 | 0); | 1706 | /* We beat everyone else. Claim the status. */ | |
1696 | xfer->ux_hcflags |= UXFER_ABORTWAIT; | 1707 | xfer->ux_status = status; | |
1697 | while (xfer->ux_hcflags & UXFER_ABORTING) | |||
1698 | cv_wait(&xfer->ux_hccv, &sc->sc_lock); | |||
1699 | return; | |||
1700 | } | |||
1701 | xfer->ux_hcflags |= UXFER_ABORTING; | |||
1702 | 1708 | |||
1703 | /* | 1709 | /* | |
1704 | * Step 1: Stop xfer timeout timer. | 1710 | * If we're dying, skip the hardware action and just notify the | |
1711 | * software that we're done. | |||
1705 | */ | 1712 | */ | |
1706 | xfer->ux_status = status; | 1713 | if (sc->sc_dying) { | |
1707 | callout_stop(&xfer->ux_callout); | 1714 | DPRINTFN(4, "xfer %#jx dying %ju", (uintptr_t)xfer, | |
1715 | xfer->ux_status, 0, 0); | |||
1716 | goto dying; | |||
1717 | } | |||
1708 | 1718 | |||
1709 | /* | 1719 | /* | |
1710 | * Step 2: Stop execution of TD on the ring. | 1720 | * HC Step 1: Stop execution of TD on the ring. | |
1711 | */ | 1721 | */ | |
1712 | switch (xhci_get_epstate(sc, xs, dci)) { | 1722 | switch (xhci_get_epstate(sc, xs, dci)) { | |
1713 | case XHCI_EPSTATE_HALTED: | 1723 | case XHCI_EPSTATE_HALTED: | |
1714 | (void)xhci_reset_endpoint_locked(xfer->ux_pipe); | 1724 | (void)xhci_reset_endpoint_locked(xfer->ux_pipe); | |
1715 | break; | 1725 | break; | |
1716 | case XHCI_EPSTATE_STOPPED: | 1726 | case XHCI_EPSTATE_STOPPED: | |
1717 | break; | 1727 | break; | |
1718 | default: | 1728 | default: | |
1719 | (void)xhci_stop_endpoint(xfer->ux_pipe); | 1729 | (void)xhci_stop_endpoint(xfer->ux_pipe); | |
1720 | break; | 1730 | break; | |
1721 | } | 1731 | } | |
1722 | #ifdef DIAGNOSTIC | 1732 | #ifdef DIAGNOSTIC | |
1723 | uint32_t epst = xhci_get_epstate(sc, xs, dci); | 1733 | uint32_t epst = xhci_get_epstate(sc, xs, dci); | |
1724 | if (epst != XHCI_EPSTATE_STOPPED) | 1734 | if (epst != XHCI_EPSTATE_STOPPED) | |
1725 | DPRINTFN(4, "dci %u not stopped %u", dci, epst, 0, 0); | 1735 | DPRINTFN(4, "dci %u not stopped %u", dci, epst, 0, 0); | |
1726 | #endif | 1736 | #endif | |
1727 | 1737 | |||
1728 | /* | 1738 | /* | |
1729 | * Step 3: Remove any vestiges of the xfer from the ring. | 1739 | * HC Step 2: Remove any vestiges of the xfer from the ring. | |
1730 | */ | 1740 | */ | |
1731 | xhci_set_dequeue_locked(xfer->ux_pipe); | 1741 | xhci_set_dequeue_locked(xfer->ux_pipe); | |
1732 | 1742 | |||
1733 | /* | 1743 | /* | |
1734 | * Step 4: Notify completion to waiting xfers. | 1744 | * Final Step: Notify completion to waiting xfers. | |
1735 | */ | 1745 | */ | |
1736 | int wake = xfer->ux_hcflags & UXFER_ABORTWAIT; | 1746 | dying: | |
1737 | xfer->ux_hcflags &= ~(UXFER_ABORTING | UXFER_ABORTWAIT); | |||
1738 | usb_transfer_complete(xfer); | 1747 | usb_transfer_complete(xfer); | |
1739 | if (wake) { | |||
1740 | cv_broadcast(&xfer->ux_hccv); | |||
1741 | } | |||
1742 | DPRINTFN(14, "end", 0, 0, 0, 0); | 1748 | DPRINTFN(14, "end", 0, 0, 0, 0); | |
1743 | 1749 | |||
1744 | KASSERT(mutex_owned(&sc->sc_lock)); | 1750 | KASSERT(mutex_owned(&sc->sc_lock)); | |
1745 | } | 1751 | } | |
1746 | 1752 | |||
1747 | static void | 1753 | static void | |
1748 | xhci_host_dequeue(struct xhci_ring * const xr) | 1754 | xhci_host_dequeue(struct xhci_ring * const xr) | |
1749 | { | 1755 | { | |
1750 | /* When dequeueing the controller, update our struct copy too */ | 1756 | /* When dequeueing the controller, update our struct copy too */ | |
1751 | memset(xr->xr_trb, 0, xr->xr_ntrb * XHCI_TRB_SIZE); | 1757 | memset(xr->xr_trb, 0, xr->xr_ntrb * XHCI_TRB_SIZE); | |
1752 | usb_syncmem(&xr->xr_dma, 0, xr->xr_ntrb * XHCI_TRB_SIZE, | 1758 | usb_syncmem(&xr->xr_dma, 0, xr->xr_ntrb * XHCI_TRB_SIZE, | |
1753 | BUS_DMASYNC_PREWRITE); | 1759 | BUS_DMASYNC_PREWRITE); | |
1754 | memset(xr->xr_cookies, 0, xr->xr_ntrb * sizeof(*xr->xr_cookies)); | 1760 | memset(xr->xr_cookies, 0, xr->xr_ntrb * sizeof(*xr->xr_cookies)); | |
@@ -1957,68 +1963,96 @@ xhci_event_transfer(struct xhci_softc * | @@ -1957,68 +1963,96 @@ xhci_event_transfer(struct xhci_softc * | |||
1957 | } | 1963 | } | |
1958 | } else if ((trb_0 & 0x3) == 0x3) { | 1964 | } else if ((trb_0 & 0x3) == 0x3) { | |
1959 | return; | 1965 | return; | |
1960 | } | 1966 | } | |
1961 | err = USBD_NORMAL_COMPLETION; | 1967 | err = USBD_NORMAL_COMPLETION; | |
1962 | break; | 1968 | break; | |
1963 | case XHCI_TRB_ERROR_STOPPED: | 1969 | case XHCI_TRB_ERROR_STOPPED: | |
1964 | case XHCI_TRB_ERROR_LENGTH: | 1970 | case XHCI_TRB_ERROR_LENGTH: | |
1965 | case XHCI_TRB_ERROR_STOPPED_SHORT: | 1971 | case XHCI_TRB_ERROR_STOPPED_SHORT: | |
1966 | /* | 1972 | /* | |
1967 | * don't complete the transfer being aborted | 1973 | * don't complete the transfer being aborted | |
1968 | * as abort_xfer does instead. | 1974 | * as abort_xfer does instead. | |
1969 | */ | 1975 | */ | |
1970 | if (xfer->ux_hcflags & UXFER_ABORTING) { | 1976 | if (xfer->ux_status == USBD_CANCELLED || | |
1977 | xfer->ux_status == USBD_TIMEOUT) { | |||
1971 | DPRINTFN(14, "ignore aborting xfer %p", xfer, 0, 0, 0); | 1978 | DPRINTFN(14, "ignore aborting xfer %p", xfer, 0, 0, 0); | |
1972 | return; | 1979 | return; | |
1973 | } | 1980 | } | |
1974 | err = USBD_CANCELLED; | 1981 | err = USBD_CANCELLED; | |
1975 | break; | 1982 | break; | |
1976 | case XHCI_TRB_ERROR_STALL: | 1983 | case XHCI_TRB_ERROR_STALL: | |
1977 | case XHCI_TRB_ERROR_BABBLE: | 1984 | case XHCI_TRB_ERROR_BABBLE: | |
1978 | DPRINTFN(1, "ERR %u slot %u dci %u", trbcode, slot, dci, 0); | 1985 | DPRINTFN(1, "ERR %u slot %u dci %u", trbcode, slot, dci, 0); | |
1979 | xr->is_halted = true; | 1986 | xr->is_halted = true; | |
1980 | err = USBD_STALLED; | |||
1981 | /* | 1987 | /* | |
1982 | * Stalled endpoints can be recoverd by issuing | 1988 | * Stalled endpoints can be recoverd by issuing | |
1983 | * command TRB TYPE_RESET_EP on xHCI instead of | 1989 | * command TRB TYPE_RESET_EP on xHCI instead of | |
1984 | * issuing request CLEAR_FEATURE UF_ENDPOINT_HALT | 1990 | * issuing request CLEAR_FEATURE UF_ENDPOINT_HALT | |
1985 | * on the endpoint. However, this function may be | 1991 | * on the endpoint. However, this function may be | |
1986 | * called from softint context (e.g. from umass), | 1992 | * called from softint context (e.g. from umass), | |
1987 | * in that case driver gets KASSERT in cv_timedwait | 1993 | * in that case driver gets KASSERT in cv_timedwait | |
1988 | * in xhci_do_command. | 1994 | * in xhci_do_command. | |
1989 | * To avoid this, this runs reset_endpoint and | 1995 | * To avoid this, this runs reset_endpoint and | |
1990 | * usb_transfer_complete in usb task thread | 1996 | * usb_transfer_complete in usb task thread | |
1991 | * asynchronously (and then umass issues clear | 1997 | * asynchronously (and then umass issues clear | |
1992 | * UF_ENDPOINT_HALT). | 1998 | * UF_ENDPOINT_HALT). | |
1993 | */ | 1999 | */ | |
1994 | xfer->ux_status = err; | 2000 | ||
2001 | /* Override the status. */ | |||
2002 | xfer->ux_status = USBD_STALLED; | |||
2003 | ||||
2004 | /* | |||
2005 | * Cancel the timeout and the task, which have not yet | |||
2006 | * run. If they have already fired, at worst they are | |||
2007 | * waiting for the lock. They will see that the xfer | |||
2008 | * is no longer in progress and give up. | |||
2009 | */ | |||
1995 | callout_stop(&xfer->ux_callout); | 2010 | callout_stop(&xfer->ux_callout); | |
2011 | usb_rem_task(xfer->ux_pipe->up_dev, &xfer->ux_aborttask); | |||
2012 | ||||
1996 | xhci_clear_endpoint_stall_async(xfer); | 2013 | xhci_clear_endpoint_stall_async(xfer); | |
1997 | return; | 2014 | return; | |
1998 | default: | 2015 | default: | |
1999 | DPRINTFN(1, "ERR %u slot %u dci %u", trbcode, slot, dci, 0); | 2016 | DPRINTFN(1, "ERR %u slot %u dci %u", trbcode, slot, dci, 0); | |
2000 | err = USBD_IOERROR; | 2017 | err = USBD_IOERROR; | |
2001 | break; | 2018 | break; | |
2002 | } | 2019 | } | |
2020 | ||||
2021 | /* | |||
2022 | * If software has completed it, either by cancellation | |||
2023 | * or timeout, drop it on the floor. | |||
2024 | */ | |||
2025 | if (xfer->ux_status != USBD_IN_PROGRESS) { | |||
2026 | KASSERTMSG((xfer->ux_status == USBD_CANCELLED || | |||
2027 | xfer->ux_status == USBD_TIMEOUT), | |||
2028 | "xfer %p status %x", xfer, xfer->ux_status); | |||
2029 | return;; | |||
2030 | } | |||
2031 | ||||
2032 | /* Otherwise, set the status. */ | |||
2003 | xfer->ux_status = err; | 2033 | xfer->ux_status = err; | |
2004 | 2034 | |||
2005 | if ((trb_3 & XHCI_TRB_3_ED_BIT) != 0) { | 2035 | /* | |
2006 | if ((trb_0 & 0x3) == 0x0) { | 2036 | * Cancel the timeout and the task, which have not yet | |
2007 | callout_stop(&xfer->ux_callout); | 2037 | * run. If they have already fired, at worst they are | |
2008 | usb_transfer_complete(xfer); | 2038 | * waiting for the lock. They will see that the xfer | |
2009 | } | 2039 | * is no longer in progress and give up. | |
2010 | } else { | 2040 | */ | |
2011 | callout_stop(&xfer->ux_callout); | 2041 | callout_stop(&xfer->ux_callout); | |
2042 | usb_rem_task(xfer->ux_pipe->up_dev, &xfer->ux_aborttask); | |||
2043 | ||||
2044 | if ((trb_3 & XHCI_TRB_3_ED_BIT) == 0 || | |||
2045 | (trb_0 & 0x3) == 0x0) { | |||
2012 | usb_transfer_complete(xfer); | 2046 | usb_transfer_complete(xfer); | |
2013 | } | 2047 | } | |
2014 | } | 2048 | } | |
2015 | 2049 | |||
2016 | /* Process Command complete events */ | 2050 | /* Process Command complete events */ | |
2017 | static void | 2051 | static void | |
2018 | xhci_event_cmd(struct xhci_softc * const sc, const struct xhci_trb * const trb) | 2052 | xhci_event_cmd(struct xhci_softc * const sc, const struct xhci_trb * const trb) | |
2019 | { | 2053 | { | |
2020 | uint64_t trb_0; | 2054 | uint64_t trb_0; | |
2021 | uint32_t trb_2, trb_3; | 2055 | uint32_t trb_2, trb_3; | |
2022 | 2056 | |||
2023 | XHCIHIST_FUNC(); XHCIHIST_CALLED(); | 2057 | XHCIHIST_FUNC(); XHCIHIST_CALLED(); | |
2024 | 2058 | |||
@@ -2161,26 +2195,28 @@ xhci_poll(struct usbd_bus *bus) | @@ -2161,26 +2195,28 @@ xhci_poll(struct usbd_bus *bus) | |||
2161 | } | 2195 | } | |
2162 | 2196 | |||
2163 | static struct usbd_xfer * | 2197 | static struct usbd_xfer * | |
2164 | xhci_allocx(struct usbd_bus *bus, unsigned int nframes) | 2198 | xhci_allocx(struct usbd_bus *bus, unsigned int nframes) | |
2165 | { | 2199 | { | |
2166 | struct xhci_softc * const sc = XHCI_BUS2SC(bus); | 2200 | struct xhci_softc * const sc = XHCI_BUS2SC(bus); | |
2167 | struct usbd_xfer *xfer; | 2201 | struct usbd_xfer *xfer; | |
2168 | 2202 | |||
2169 | XHCIHIST_FUNC(); XHCIHIST_CALLED(); | 2203 | XHCIHIST_FUNC(); XHCIHIST_CALLED(); | |
2170 | 2204 | |||
2171 | xfer = pool_cache_get(sc->sc_xferpool, PR_WAITOK); | 2205 | xfer = pool_cache_get(sc->sc_xferpool, PR_WAITOK); | |
2172 | if (xfer != NULL) { | 2206 | if (xfer != NULL) { | |
2173 | memset(xfer, 0, sizeof(struct xhci_xfer)); | 2207 | memset(xfer, 0, sizeof(struct xhci_xfer)); | |
2208 | usb_init_task(&xfer->ux_aborttask, xhci_timeout_task, xfer, | |||
2209 | USB_TASKQ_MPSAFE); | |||
2174 | #ifdef DIAGNOSTIC | 2210 | #ifdef DIAGNOSTIC | |
2175 | xfer->ux_state = XFER_BUSY; | 2211 | xfer->ux_state = XFER_BUSY; | |
2176 | #endif | 2212 | #endif | |
2177 | } | 2213 | } | |
2178 | 2214 | |||
2179 | return xfer; | 2215 | return xfer; | |
2180 | } | 2216 | } | |
2181 | 2217 | |||
2182 | static void | 2218 | static void | |
2183 | xhci_freex(struct usbd_bus *bus, struct usbd_xfer *xfer) | 2219 | xhci_freex(struct usbd_bus *bus, struct usbd_xfer *xfer) | |
2184 | { | 2220 | { | |
2185 | struct xhci_softc * const sc = XHCI_BUS2SC(bus); | 2221 | struct xhci_softc * const sc = XHCI_BUS2SC(bus); | |
2186 | 2222 | |||
@@ -3762,26 +3798,27 @@ xhci_device_ctrl_start(struct usbd_xfer | @@ -3762,26 +3798,27 @@ xhci_device_ctrl_start(struct usbd_xfer | |||
3762 | XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_DATA_STAGE) | | 3798 | XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_DATA_STAGE) | | |
3763 | (usbd_xfer_isread(xfer) ? XHCI_TRB_3_ISP_BIT : 0) | | 3799 | (usbd_xfer_isread(xfer) ? XHCI_TRB_3_ISP_BIT : 0) | | |
3764 | XHCI_TRB_3_IOC_BIT; | 3800 | XHCI_TRB_3_IOC_BIT; | |
3765 | xhci_trb_put(&xx->xx_trb[i++], parameter, status, control); | 3801 | xhci_trb_put(&xx->xx_trb[i++], parameter, status, control); | |
3766 | } | 3802 | } | |
3767 | 3803 | |||
3768 | parameter = 0; | 3804 | parameter = 0; | |
3769 | status = XHCI_TRB_2_IRQ_SET(0); | 3805 | status = XHCI_TRB_2_IRQ_SET(0); | |
3770 | /* the status stage has inverted direction */ | 3806 | /* the status stage has inverted direction */ | |
3771 | control = ((isread && (len > 0)) ? 0 : XHCI_TRB_3_DIR_IN) | | 3807 | control = ((isread && (len > 0)) ? 0 : XHCI_TRB_3_DIR_IN) | | |
3772 | XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_STATUS_STAGE) | | 3808 | XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_STATUS_STAGE) | | |
3773 | XHCI_TRB_3_IOC_BIT; | 3809 | XHCI_TRB_3_IOC_BIT; | |
3774 | xhci_trb_put(&xx->xx_trb[i++], parameter, status, control); | 3810 | xhci_trb_put(&xx->xx_trb[i++], parameter, status, control); | |
3811 | xfer->ux_status = USBD_IN_PROGRESS; | |||
3775 | 3812 | |||
3776 | mutex_enter(&tr->xr_lock); | 3813 | mutex_enter(&tr->xr_lock); | |
3777 | xhci_ring_put(sc, tr, xfer, xx->xx_trb, i); | 3814 | xhci_ring_put(sc, tr, xfer, xx->xx_trb, i); | |
3778 | mutex_exit(&tr->xr_lock); | 3815 | mutex_exit(&tr->xr_lock); | |
3779 | 3816 | |||
3780 | xhci_db_write_4(sc, XHCI_DOORBELL(xs->xs_idx), dci); | 3817 | xhci_db_write_4(sc, XHCI_DOORBELL(xs->xs_idx), dci); | |
3781 | 3818 | |||
3782 | if (xfer->ux_timeout && !sc->sc_bus.ub_usepolling) { | 3819 | if (xfer->ux_timeout && !sc->sc_bus.ub_usepolling) { | |
3783 | callout_reset(&xfer->ux_callout, mstohz(xfer->ux_timeout), | 3820 | callout_reset(&xfer->ux_callout, mstohz(xfer->ux_timeout), | |
3784 | xhci_timeout, xfer); | 3821 | xhci_timeout, xfer); | |
3785 | } | 3822 | } | |
3786 | 3823 | |||
3787 | return USBD_IN_PROGRESS; | 3824 | return USBD_IN_PROGRESS; | |
@@ -3878,26 +3915,27 @@ xhci_device_bulk_start(struct usbd_xfer | @@ -3878,26 +3915,27 @@ xhci_device_bulk_start(struct usbd_xfer | |||
3878 | * blocks needed to complete the transfer. | 3915 | * blocks needed to complete the transfer. | |
3879 | * Setting it to 1 in the last TRB causes an extra zero-length | 3916 | * Setting it to 1 in the last TRB causes an extra zero-length | |
3880 | * data block be sent. | 3917 | * data block be sent. | |
3881 | * The earlier documentation differs, I don't know how it behaves. | 3918 | * The earlier documentation differs, I don't know how it behaves. | |
3882 | */ | 3919 | */ | |
3883 | KASSERTMSG(len <= 0x10000, "len %d", len); | 3920 | KASSERTMSG(len <= 0x10000, "len %d", len); | |
3884 | status = XHCI_TRB_2_IRQ_SET(0) | | 3921 | status = XHCI_TRB_2_IRQ_SET(0) | | |
3885 | XHCI_TRB_2_TDSZ_SET(1) | | 3922 | XHCI_TRB_2_TDSZ_SET(1) | | |
3886 | XHCI_TRB_2_BYTES_SET(len); | 3923 | XHCI_TRB_2_BYTES_SET(len); | |
3887 | control = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_NORMAL) | | 3924 | control = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_NORMAL) | | |
3888 | (usbd_xfer_isread(xfer) ? XHCI_TRB_3_ISP_BIT : 0) | | 3925 | (usbd_xfer_isread(xfer) ? XHCI_TRB_3_ISP_BIT : 0) | | |
3889 | XHCI_TRB_3_IOC_BIT; | 3926 | XHCI_TRB_3_IOC_BIT; | |
3890 | xhci_trb_put(&xx->xx_trb[i++], parameter, status, control); | 3927 | xhci_trb_put(&xx->xx_trb[i++], parameter, status, control); | |
3928 | xfer->ux_status = USBD_IN_PROGRESS; | |||
3891 | 3929 | |||
3892 | mutex_enter(&tr->xr_lock); | 3930 | mutex_enter(&tr->xr_lock); | |
3893 | xhci_ring_put(sc, tr, xfer, xx->xx_trb, i); | 3931 | xhci_ring_put(sc, tr, xfer, xx->xx_trb, i); | |
3894 | mutex_exit(&tr->xr_lock); | 3932 | mutex_exit(&tr->xr_lock); | |
3895 | 3933 | |||
3896 | xhci_db_write_4(sc, XHCI_DOORBELL(xs->xs_idx), dci); | 3934 | xhci_db_write_4(sc, XHCI_DOORBELL(xs->xs_idx), dci); | |
3897 | 3935 | |||
3898 | if (xfer->ux_timeout && !sc->sc_bus.ub_usepolling) { | 3936 | if (xfer->ux_timeout && !sc->sc_bus.ub_usepolling) { | |
3899 | callout_reset(&xfer->ux_callout, mstohz(xfer->ux_timeout), | 3937 | callout_reset(&xfer->ux_callout, mstohz(xfer->ux_timeout), | |
3900 | xhci_timeout, xfer); | 3938 | xhci_timeout, xfer); | |
3901 | } | 3939 | } | |
3902 | 3940 | |||
3903 | return USBD_IN_PROGRESS; | 3941 | return USBD_IN_PROGRESS; | |
@@ -3984,26 +4022,27 @@ xhci_device_intr_start(struct usbd_xfer | @@ -3984,26 +4022,27 @@ xhci_device_intr_start(struct usbd_xfer | |||
3984 | return USBD_IOERROR; | 4022 | return USBD_IOERROR; | |
3985 | 4023 | |||
3986 | KASSERT((xfer->ux_rqflags & URQ_REQUEST) == 0); | 4024 | KASSERT((xfer->ux_rqflags & URQ_REQUEST) == 0); | |
3987 | 4025 | |||
3988 | parameter = DMAADDR(dma, 0); | 4026 | parameter = DMAADDR(dma, 0); | |
3989 | KASSERTMSG(len <= 0x10000, "len %d", len); | 4027 | KASSERTMSG(len <= 0x10000, "len %d", len); | |
3990 | status = XHCI_TRB_2_IRQ_SET(0) | | 4028 | status = XHCI_TRB_2_IRQ_SET(0) | | |
3991 | XHCI_TRB_2_TDSZ_SET(1) | | 4029 | XHCI_TRB_2_TDSZ_SET(1) | | |
3992 | XHCI_TRB_2_BYTES_SET(len); | 4030 | XHCI_TRB_2_BYTES_SET(len); | |
3993 | control = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_NORMAL) | | 4031 | control = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_NORMAL) | | |
3994 | (usbd_xfer_isread(xfer) ? XHCI_TRB_3_ISP_BIT : 0) | | 4032 | (usbd_xfer_isread(xfer) ? XHCI_TRB_3_ISP_BIT : 0) | | |
3995 | XHCI_TRB_3_IOC_BIT; | 4033 | XHCI_TRB_3_IOC_BIT; | |
3996 | xhci_trb_put(&xx->xx_trb[i++], parameter, status, control); | 4034 | xhci_trb_put(&xx->xx_trb[i++], parameter, status, control); | |
4035 | xfer->ux_status = USBD_IN_PROGRESS; | |||
3997 | 4036 | |||
3998 | mutex_enter(&tr->xr_lock); | 4037 | mutex_enter(&tr->xr_lock); | |
3999 | xhci_ring_put(sc, tr, xfer, xx->xx_trb, i); | 4038 | xhci_ring_put(sc, tr, xfer, xx->xx_trb, i); | |
4000 | mutex_exit(&tr->xr_lock); | 4039 | mutex_exit(&tr->xr_lock); | |
4001 | 4040 | |||
4002 | xhci_db_write_4(sc, XHCI_DOORBELL(xs->xs_idx), dci); | 4041 | xhci_db_write_4(sc, XHCI_DOORBELL(xs->xs_idx), dci); | |
4003 | 4042 | |||
4004 | if (xfer->ux_timeout && !sc->sc_bus.ub_usepolling) { | 4043 | if (xfer->ux_timeout && !sc->sc_bus.ub_usepolling) { | |
4005 | callout_reset(&xfer->ux_callout, mstohz(xfer->ux_timeout), | 4044 | callout_reset(&xfer->ux_callout, mstohz(xfer->ux_timeout), | |
4006 | xhci_timeout, xfer); | 4045 | xhci_timeout, xfer); | |
4007 | } | 4046 | } | |
4008 | 4047 | |||
4009 | return USBD_IN_PROGRESS; | 4048 | return USBD_IN_PROGRESS; | |
@@ -4048,41 +4087,36 @@ xhci_device_intr_close(struct usbd_pipe | @@ -4048,41 +4087,36 @@ xhci_device_intr_close(struct usbd_pipe | |||
4048 | //struct xhci_softc * const sc = XHCI_PIPE2SC(pipe); | 4087 | //struct xhci_softc * const sc = XHCI_PIPE2SC(pipe); | |
4049 | 4088 | |||
4050 | XHCIHIST_FUNC(); XHCIHIST_CALLED(); | 4089 | XHCIHIST_FUNC(); XHCIHIST_CALLED(); | |
4051 | DPRINTFN(15, "%p", pipe, 0, 0, 0); | 4090 | DPRINTFN(15, "%p", pipe, 0, 0, 0); | |
4052 | 4091 | |||
4053 | xhci_close_pipe(pipe); | 4092 | xhci_close_pipe(pipe); | |
4054 | } | 4093 | } | |
4055 | 4094 | |||
4056 | /* ------------ */ | 4095 | /* ------------ */ | |
4057 | 4096 | |||
4058 | static void | 4097 | static void | |
4059 | xhci_timeout(void *addr) | 4098 | xhci_timeout(void *addr) | |
4060 | { | 4099 | { | |
4100 | XHCIHIST_FUNC(); XHCIHIST_CALLED(); | |||
4061 | struct xhci_xfer * const xx = addr; | 4101 | struct xhci_xfer * const xx = addr; | |
4062 | struct usbd_xfer * const xfer = &xx->xx_xfer; | 4102 | struct usbd_xfer * const xfer = &xx->xx_xfer; | |
4063 | struct xhci_softc * const sc = XHCI_XFER2SC(xfer); | 4103 | struct xhci_softc * const sc = XHCI_XFER2SC(xfer); | |
4104 | struct usbd_device *dev = xfer->ux_pipe->up_dev; | |||
4064 | 4105 | |||
4065 | XHCIHIST_FUNC(); XHCIHIST_CALLED(); | 4106 | mutex_enter(&sc->sc_lock); | |
4066 | 4107 | if (!sc->sc_dying && xfer->ux_status == USBD_IN_PROGRESS) | ||
4067 | if (sc->sc_dying) { | 4108 | usb_add_task(dev, &xfer->ux_aborttask, USB_TASKQ_HC); | |
4068 | return; | 4109 | mutex_exit(&sc->sc_lock); | |
4069 | } | |||
4070 | ||||
4071 | usb_init_task(&xx->xx_abort_task, xhci_timeout_task, addr, | |||
4072 | USB_TASKQ_MPSAFE); | |||
4073 | usb_add_task(xx->xx_xfer.ux_pipe->up_dev, &xx->xx_abort_task, | |||
4074 | USB_TASKQ_HC); | |||
4075 | } | 4110 | } | |
4076 | 4111 | |||
4077 | static void | 4112 | static void | |
4078 | xhci_timeout_task(void *addr) | 4113 | xhci_timeout_task(void *addr) | |
4079 | { | 4114 | { | |
4115 | XHCIHIST_FUNC(); XHCIHIST_CALLED(); | |||
4080 | struct usbd_xfer * const xfer = addr; | 4116 | struct usbd_xfer * const xfer = addr; | |
4081 | struct xhci_softc * const sc = XHCI_XFER2SC(xfer); | 4117 | struct xhci_softc * const sc = XHCI_XFER2SC(xfer); | |
4082 | 4118 | |||
4083 | XHCIHIST_FUNC(); XHCIHIST_CALLED(); | |||
4084 | ||||
4085 | mutex_enter(&sc->sc_lock); | 4119 | mutex_enter(&sc->sc_lock); | |
4086 | xhci_abort_xfer(xfer, USBD_TIMEOUT); | 4120 | xhci_abort_xfer(xfer, USBD_TIMEOUT); | |
4087 | mutex_exit(&sc->sc_lock); | 4121 | mutex_exit(&sc->sc_lock); | |
4088 | } | 4122 | } |
--- src/sys/dev/usb/xhcivar.h 2017/04/05 19:54:21 1.4.8.1
+++ src/sys/dev/usb/xhcivar.h 2018/08/25 14:57:35 1.4.8.2
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: xhcivar.h,v 1.4.8.1 2017/04/05 19:54:21 snj Exp $ */ | 1 | /* $NetBSD: xhcivar.h,v 1.4.8.2 2018/08/25 14:57:35 martin Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 2013 Jonathan A. Kollasch | 4 | * Copyright (c) 2013 Jonathan A. Kollasch | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | 7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | 8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | 9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | 10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | 11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | 13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | 14 | * documentation and/or other materials provided with the distribution. | |
@@ -25,27 +25,26 @@ | @@ -25,27 +25,26 @@ | |||
25 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF | 25 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF | |
26 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
27 | */ | 27 | */ | |
28 | 28 | |||
29 | #ifndef _DEV_USB_XHCIVAR_H_ | 29 | #ifndef _DEV_USB_XHCIVAR_H_ | |
30 | #define _DEV_USB_XHCIVAR_H_ | 30 | #define _DEV_USB_XHCIVAR_H_ | |
31 | 31 | |||
32 | #include <sys/pool.h> | 32 | #include <sys/pool.h> | |
33 | 33 | |||
34 | #define XHCI_XFER_NTRB 20 | 34 | #define XHCI_XFER_NTRB 20 | |
35 | 35 | |||
36 | struct xhci_xfer { | 36 | struct xhci_xfer { | |
37 | struct usbd_xfer xx_xfer; | 37 | struct usbd_xfer xx_xfer; | |
38 | struct usb_task xx_abort_task; | |||
39 | struct xhci_trb xx_trb[XHCI_XFER_NTRB]; | 38 | struct xhci_trb xx_trb[XHCI_XFER_NTRB]; | |
40 | }; | 39 | }; | |
41 | 40 | |||
42 | #define XHCI_BUS2SC(bus) ((bus)->ub_hcpriv) | 41 | #define XHCI_BUS2SC(bus) ((bus)->ub_hcpriv) | |
43 | #define XHCI_PIPE2SC(pipe) XHCI_BUS2SC((pipe)->up_dev->ud_bus) | 42 | #define XHCI_PIPE2SC(pipe) XHCI_BUS2SC((pipe)->up_dev->ud_bus) | |
44 | #define XHCI_XFER2SC(xfer) XHCI_BUS2SC((xfer)->ux_bus) | 43 | #define XHCI_XFER2SC(xfer) XHCI_BUS2SC((xfer)->ux_bus) | |
45 | #define XHCI_XFER2BUS(xfer) ((xfer)->ux_bus) | 44 | #define XHCI_XFER2BUS(xfer) ((xfer)->ux_bus) | |
46 | #define XHCI_XPIPE2SC(d) XHCI_BUS2SC((d)->xp_pipe.up_dev->ud_bus) | 45 | #define XHCI_XPIPE2SC(d) XHCI_BUS2SC((d)->xp_pipe.up_dev->ud_bus) | |
47 | 46 | |||
48 | #define XHCI_XFER2XXFER(xfer) ((struct xhci_xfer *)(xfer)) | 47 | #define XHCI_XFER2XXFER(xfer) ((struct xhci_xfer *)(xfer)) | |
49 | 48 | |||
50 | struct xhci_ring { | 49 | struct xhci_ring { | |
51 | usb_dma_t xr_dma; | 50 | usb_dma_t xr_dma; | |
@@ -75,27 +74,26 @@ struct xhci_softc { | @@ -75,27 +74,26 @@ struct xhci_softc { | |||
75 | device_t sc_child2; | 74 | device_t sc_child2; | |
76 | bus_size_t sc_ios; | 75 | bus_size_t sc_ios; | |
77 | bus_space_tag_t sc_iot; | 76 | bus_space_tag_t sc_iot; | |
78 | bus_space_handle_t sc_ioh; /* Base */ | 77 | bus_space_handle_t sc_ioh; /* Base */ | |
79 | bus_space_handle_t sc_cbh; /* Capability Base */ | 78 | bus_space_handle_t sc_cbh; /* Capability Base */ | |
80 | bus_space_handle_t sc_obh; /* Operational Base */ | 79 | bus_space_handle_t sc_obh; /* Operational Base */ | |
81 | bus_space_handle_t sc_rbh; /* Runtime Base */ | 80 | bus_space_handle_t sc_rbh; /* Runtime Base */ | |
82 | bus_space_handle_t sc_dbh; /* Doorbell Registers */ | 81 | bus_space_handle_t sc_dbh; /* Doorbell Registers */ | |
83 | struct usbd_bus sc_bus; /* USB 3 bus */ | 82 | struct usbd_bus sc_bus; /* USB 3 bus */ | |
84 | struct usbd_bus sc_bus2; /* USB 2 bus */ | 83 | struct usbd_bus sc_bus2; /* USB 2 bus */ | |
85 | 84 | |||
86 | kmutex_t sc_lock; | 85 | kmutex_t sc_lock; | |
87 | kmutex_t sc_intr_lock; | 86 | kmutex_t sc_intr_lock; | |
88 | kcondvar_t sc_softwake_cv; | |||
89 | 87 | |||
90 | char sc_vendor[32]; /* vendor string for root hub */ | 88 | char sc_vendor[32]; /* vendor string for root hub */ | |
91 | int sc_id_vendor; /* vendor ID for root hub */ | 89 | int sc_id_vendor; /* vendor ID for root hub */ | |
92 | 90 | |||
93 | pool_cache_t sc_xferpool; | 91 | pool_cache_t sc_xferpool; | |
94 | 92 | |||
95 | bus_size_t sc_pgsz; /* xHCI page size */ | 93 | bus_size_t sc_pgsz; /* xHCI page size */ | |
96 | uint32_t sc_ctxsz; | 94 | uint32_t sc_ctxsz; | |
97 | int sc_maxslots; | 95 | int sc_maxslots; | |
98 | int sc_maxintrs; | 96 | int sc_maxintrs; | |
99 | int sc_maxspbuf; | 97 | int sc_maxspbuf; | |
100 | 98 | |||
101 | /* | 99 | /* |
--- src/sys/external/bsd/dwc2/dwc2.c 2018/01/03 20:02:37 1.31.2.3
+++ src/sys/external/bsd/dwc2/dwc2.c 2018/08/25 14:57:35 1.31.2.4
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: dwc2.c,v 1.31.2.3 2018/01/03 20:02:37 snj Exp $ */ | 1 | /* $NetBSD: dwc2.c,v 1.31.2.4 2018/08/25 14:57:35 martin Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2013 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 2013 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to The NetBSD Foundation | 7 | * This code is derived from software contributed to The NetBSD Foundation | |
8 | * by Nick Hudson | 8 | * by Nick Hudson | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
@@ -20,27 +20,27 @@ | @@ -20,27 +20,27 @@ | |||
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
29 | * POSSIBILITY OF SUCH DAMAGE. | 29 | * POSSIBILITY OF SUCH DAMAGE. | |
30 | */ | 30 | */ | |
31 | 31 | |||
32 | #include <sys/cdefs.h> | 32 | #include <sys/cdefs.h> | |
33 | __KERNEL_RCSID(0, "$NetBSD: dwc2.c,v 1.31.2.3 2018/01/03 20:02:37 snj Exp $"); | 33 | __KERNEL_RCSID(0, "$NetBSD: dwc2.c,v 1.31.2.4 2018/08/25 14:57:35 martin Exp $"); | |
34 | 34 | |||
35 | #include "opt_usb.h" | 35 | #include "opt_usb.h" | |
36 | 36 | |||
37 | #include <sys/param.h> | 37 | #include <sys/param.h> | |
38 | #include <sys/systm.h> | 38 | #include <sys/systm.h> | |
39 | #include <sys/kmem.h> | 39 | #include <sys/kmem.h> | |
40 | #include <sys/kernel.h> | 40 | #include <sys/kernel.h> | |
41 | #include <sys/device.h> | 41 | #include <sys/device.h> | |
42 | #include <sys/select.h> | 42 | #include <sys/select.h> | |
43 | #include <sys/proc.h> | 43 | #include <sys/proc.h> | |
44 | #include <sys/queue.h> | 44 | #include <sys/queue.h> | |
45 | #include <sys/cpu.h> | 45 | #include <sys/cpu.h> | |
46 | 46 | |||
@@ -193,37 +193,42 @@ Static const struct usbd_pipe_methods dw | @@ -193,37 +193,42 @@ Static const struct usbd_pipe_methods dw | |||
193 | Static const struct usbd_pipe_methods dwc2_device_isoc_methods = { | 193 | Static const struct usbd_pipe_methods dwc2_device_isoc_methods = { | |
194 | .upm_transfer = dwc2_device_isoc_transfer, | 194 | .upm_transfer = dwc2_device_isoc_transfer, | |
195 | .upm_abort = dwc2_device_isoc_abort, | 195 | .upm_abort = dwc2_device_isoc_abort, | |
196 | .upm_close = dwc2_device_isoc_close, | 196 | .upm_close = dwc2_device_isoc_close, | |
197 | .upm_cleartoggle = dwc2_noop, | 197 | .upm_cleartoggle = dwc2_noop, | |
198 | .upm_done = dwc2_device_isoc_done, | 198 | .upm_done = dwc2_device_isoc_done, | |
199 | }; | 199 | }; | |
200 | 200 | |||
201 | struct usbd_xfer * | 201 | struct usbd_xfer * | |
202 | dwc2_allocx(struct usbd_bus *bus, unsigned int nframes) | 202 | dwc2_allocx(struct usbd_bus *bus, unsigned int nframes) | |
203 | { | 203 | { | |
204 | struct dwc2_softc *sc = DWC2_BUS2SC(bus); | 204 | struct dwc2_softc *sc = DWC2_BUS2SC(bus); | |
205 | struct dwc2_xfer *dxfer; | 205 | struct dwc2_xfer *dxfer; | |
206 | struct usbd_xfer *xfer; | |||
206 | 207 | |||
207 | DPRINTFN(10, "\n"); | 208 | DPRINTFN(10, "\n"); | |
208 | 209 | |||
209 | DWC2_EVCNT_INCR(sc->sc_ev_xferpoolget); | 210 | DWC2_EVCNT_INCR(sc->sc_ev_xferpoolget); | |
210 | dxfer = pool_cache_get(sc->sc_xferpool, PR_WAITOK); | 211 | dxfer = pool_cache_get(sc->sc_xferpool, PR_WAITOK); | |
212 | xfer = (struct usbd_xfer *)dxfer; | |||
211 | if (dxfer != NULL) { | 213 | if (dxfer != NULL) { | |
212 | memset(dxfer, 0, sizeof(*dxfer)); | 214 | memset(dxfer, 0, sizeof(*dxfer)); | |
213 | 215 | |||
214 | dxfer->urb = dwc2_hcd_urb_alloc(sc->sc_hsotg, | 216 | dxfer->urb = dwc2_hcd_urb_alloc(sc->sc_hsotg, | |
215 | nframes, GFP_KERNEL); | 217 | nframes, GFP_KERNEL); | |
216 | 218 | |||
219 | /* Initialise this always so we can call remove on it. */ | |||
220 | usb_init_task(&xfer->ux_aborttask, dwc2_timeout_task, xfer, | |||
221 | USB_TASKQ_MPSAFE); | |||
217 | #ifdef DIAGNOSTIC | 222 | #ifdef DIAGNOSTIC | |
218 | dxfer->xfer.ux_state = XFER_BUSY; | 223 | dxfer->xfer.ux_state = XFER_BUSY; | |
219 | #endif | 224 | #endif | |
220 | } | 225 | } | |
221 | return (struct usbd_xfer *)dxfer; | 226 | return (struct usbd_xfer *)dxfer; | |
222 | } | 227 | } | |
223 | 228 | |||
224 | void | 229 | void | |
225 | dwc2_freex(struct usbd_bus *bus, struct usbd_xfer *xfer) | 230 | dwc2_freex(struct usbd_bus *bus, struct usbd_xfer *xfer) | |
226 | { | 231 | { | |
227 | struct dwc2_xfer *dxfer = DWC2_XFER2DXFER(xfer); | 232 | struct dwc2_xfer *dxfer = DWC2_XFER2DXFER(xfer); | |
228 | struct dwc2_softc *sc = DWC2_BUS2SC(bus); | 233 | struct dwc2_softc *sc = DWC2_BUS2SC(bus); | |
229 | 234 | |||
@@ -288,62 +293,53 @@ dwc2_softintr(void *v) | @@ -288,62 +293,53 @@ dwc2_softintr(void *v) | |||
288 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); | 293 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); | |
289 | 294 | |||
290 | mutex_spin_enter(&hsotg->lock); | 295 | mutex_spin_enter(&hsotg->lock); | |
291 | while ((dxfer = TAILQ_FIRST(&sc->sc_complete)) != NULL) { | 296 | while ((dxfer = TAILQ_FIRST(&sc->sc_complete)) != NULL) { | |
292 | 297 | |||
293 | KASSERTMSG(!callout_pending(&dxfer->xfer.ux_callout), | 298 | KASSERTMSG(!callout_pending(&dxfer->xfer.ux_callout), | |
294 | "xfer %p pipe %p\n", dxfer, dxfer->xfer.ux_pipe); | 299 | "xfer %p pipe %p\n", dxfer, dxfer->xfer.ux_pipe); | |
295 | 300 | |||
296 | /* | 301 | /* | |
297 | * dwc2_abort_xfer will remove this transfer from the | 302 | * dwc2_abort_xfer will remove this transfer from the | |
298 | * sc_complete queue | 303 | * sc_complete queue | |
299 | */ | 304 | */ | |
300 | /*XXXNH not tested */ | 305 | /*XXXNH not tested */ | |
301 | if (dxfer->xfer.ux_hcflags & UXFER_ABORTING) { | 306 | if (dxfer->xfer.ux_status == USBD_CANCELLED || | |
302 | cv_broadcast(&dxfer->xfer.ux_hccv); | 307 | dxfer->xfer.ux_status == USBD_TIMEOUT) { | |
303 | continue; | 308 | continue; | |
304 | } | 309 | } | |
305 | 310 | |||
306 | TAILQ_REMOVE(&sc->sc_complete, dxfer, xnext); | 311 | TAILQ_REMOVE(&sc->sc_complete, dxfer, xnext); | |
307 | 312 | |||
308 | mutex_spin_exit(&hsotg->lock); | 313 | mutex_spin_exit(&hsotg->lock); | |
309 | usb_transfer_complete(&dxfer->xfer); | 314 | usb_transfer_complete(&dxfer->xfer); | |
310 | mutex_spin_enter(&hsotg->lock); | 315 | mutex_spin_enter(&hsotg->lock); | |
311 | } | 316 | } | |
312 | mutex_spin_exit(&hsotg->lock); | 317 | mutex_spin_exit(&hsotg->lock); | |
313 | } | 318 | } | |
314 | 319 | |||
315 | Static void | 320 | Static void | |
316 | dwc2_timeout(void *addr) | 321 | dwc2_timeout(void *addr) | |
317 | { | 322 | { | |
318 | struct usbd_xfer *xfer = addr; | 323 | struct usbd_xfer *xfer = addr; | |
319 | struct dwc2_xfer *dxfer = DWC2_XFER2DXFER(xfer); | |||
320 | // struct dwc2_pipe *dpipe = DWC2_XFER2DPIPE(xfer); | |||
321 | struct dwc2_softc *sc = DWC2_XFER2SC(xfer); | 324 | struct dwc2_softc *sc = DWC2_XFER2SC(xfer); | |
325 | struct usbd_device *dev = xfer->ux_pipe->up_dev; | |||
322 | 326 | |||
323 | DPRINTF("dxfer=%p\n", dxfer); | 327 | DPRINTF("dxfer=%p\n", dxfer); | |
324 | 328 | |||
325 | if (sc->sc_dying) { | 329 | mutex_enter(&sc->sc_lock); | |
326 | mutex_enter(&sc->sc_lock); | 330 | if (!sc->sc_dying && xfer->ux_status == USBD_IN_PROGRESS) | |
327 | dwc2_abort_xfer(&dxfer->xfer, USBD_TIMEOUT); | 331 | usb_add_task(dev, &xfer->ux_aborttask, USB_TASKQ_HC); | |
328 | mutex_exit(&sc->sc_lock); | 332 | mutex_exit(&sc->sc_lock); | |
329 | return; | |||
330 | } | |||
331 | ||||
332 | /* Execute the abort in a process context. */ | |||
333 | usb_init_task(&dxfer->abort_task, dwc2_timeout_task, addr, | |||
334 | USB_TASKQ_MPSAFE); | |||
335 | usb_add_task(dxfer->xfer.ux_pipe->up_dev, &dxfer->abort_task, | |||
336 | USB_TASKQ_HC); | |||
337 | } | 333 | } | |
338 | 334 | |||
339 | Static void | 335 | Static void | |
340 | dwc2_timeout_task(void *addr) | 336 | dwc2_timeout_task(void *addr) | |
341 | { | 337 | { | |
342 | struct usbd_xfer *xfer = addr; | 338 | struct usbd_xfer *xfer = addr; | |
343 | struct dwc2_softc *sc = DWC2_XFER2SC(xfer); | 339 | struct dwc2_softc *sc = DWC2_XFER2SC(xfer); | |
344 | 340 | |||
345 | DPRINTF("xfer=%p\n", xfer); | 341 | DPRINTF("xfer=%p\n", xfer); | |
346 | 342 | |||
347 | mutex_enter(&sc->sc_lock); | 343 | mutex_enter(&sc->sc_lock); | |
348 | dwc2_abort_xfer(xfer, USBD_TIMEOUT); | 344 | dwc2_abort_xfer(xfer, USBD_TIMEOUT); | |
349 | mutex_exit(&sc->sc_lock); | 345 | mutex_exit(&sc->sc_lock); | |
@@ -439,86 +435,103 @@ dwc2_close_pipe(struct usbd_pipe *pipe) | @@ -439,86 +435,103 @@ dwc2_close_pipe(struct usbd_pipe *pipe) | |||
439 | KASSERT(mutex_owned(&sc->sc_lock)); | 435 | KASSERT(mutex_owned(&sc->sc_lock)); | |
440 | } | 436 | } | |
441 | 437 | |||
442 | /* | 438 | /* | |
443 | * Abort a device request. | 439 | * Abort a device request. | |
444 | */ | 440 | */ | |
445 | Static void | 441 | Static void | |
446 | dwc2_abort_xfer(struct usbd_xfer *xfer, usbd_status status) | 442 | dwc2_abort_xfer(struct usbd_xfer *xfer, usbd_status status) | |
447 | { | 443 | { | |
448 | struct dwc2_xfer *dxfer = DWC2_XFER2DXFER(xfer); | 444 | struct dwc2_xfer *dxfer = DWC2_XFER2DXFER(xfer); | |
449 | struct dwc2_softc *sc = DWC2_XFER2SC(xfer); | 445 | struct dwc2_softc *sc = DWC2_XFER2SC(xfer); | |
450 | struct dwc2_hsotg *hsotg = sc->sc_hsotg; | 446 | struct dwc2_hsotg *hsotg = sc->sc_hsotg; | |
451 | struct dwc2_xfer *d, *tmp; | 447 | struct dwc2_xfer *d, *tmp; | |
452 | bool wake; | |||
453 | int err; | 448 | int err; | |
454 | 449 | |||
455 | DPRINTF("xfer=%p\n", xfer); | 450 | KASSERTMSG((status == USBD_CANCELLED || status == USBD_TIMEOUT), | |
451 | "invalid status for abort: %d", (int)status); | |||
452 | ||||
453 | DPRINTF("xfer %pjx pipe %pjx status %jd", xfer, xfer->ux_pipe, status); | |||
456 | 454 | |||
457 | KASSERT(mutex_owned(&sc->sc_lock)); | 455 | KASSERT(mutex_owned(&sc->sc_lock)); | |
458 | KASSERT(!cpu_intr_p() && !cpu_softintr_p()); | 456 | ASSERT_SLEEPABLE(); | |
459 | 457 | |||
460 | if (sc->sc_dying) { | 458 | if (status == USBD_CANCELLED) { | |
461 | xfer->ux_status = status; | 459 | /* | |
462 | callout_stop(&xfer->ux_callout); | 460 | * We are synchronously aborting. Try to stop the | |
463 | usb_transfer_complete(xfer); | 461 | * callout and task, but if we can't, wait for them to | |
464 | return; | 462 | * complete. | |
463 | */ | |||
464 | callout_halt(&xfer->ux_callout, &sc->sc_lock); | |||
465 | usb_rem_task_wait(xfer->ux_pipe->up_dev, &xfer->ux_aborttask, | |||
466 | USB_TASKQ_HC, &sc->sc_lock); | |||
467 | } else { | |||
468 | /* Otherwise, we are timing out. */ | |||
469 | KASSERT(status == USBD_TIMEOUT); | |||
465 | } | 470 | } | |
466 | 471 | |||
467 | /* | 472 | /* | |
468 | * If an abort is already in progress then just wait for it to | 473 | * The xfer cannot have been cancelled already. It is the | |
469 | * complete and return. | 474 | * responsibility of the caller of usbd_abort_pipe not to try | |
475 | * to abort a pipe multiple times, whether concurrently or | |||
476 | * sequentially. | |||
470 | */ | 477 | */ | |
471 | if (xfer->ux_hcflags & UXFER_ABORTING) { | 478 | KASSERT(xfer->ux_status != USBD_CANCELLED); | |
472 | xfer->ux_status = status; | 479 | ||
473 | xfer->ux_hcflags |= UXFER_ABORTWAIT; | 480 | /* Only the timeout, which runs only once, can time it out. */ | |
474 | while (xfer->ux_hcflags & UXFER_ABORTING) | 481 | KASSERT(xfer->ux_status != USBD_TIMEOUT); | |
475 | cv_wait(&xfer->ux_hccv, &sc->sc_lock); | 482 | ||
483 | /* If anyone else beat us, we're done. */ | |||
484 | if (xfer->ux_status != USBD_IN_PROGRESS) | |||
476 | return; | 485 | return; | |
486 | ||||
487 | /* We beat everyone else. Claim the status. */ | |||
488 | xfer->ux_status = status; | |||
489 | ||||
490 | /* | |||
491 | * If we're dying, skip the hardware action and just notify the | |||
492 | * software that we're done. | |||
493 | */ | |||
494 | if (sc->sc_dying) { | |||
495 | DPRINTFN(4, "xfer %#jx dying %ju", (uintptr_t)xfer, | |||
496 | xfer->ux_status, 0, 0); | |||
497 | goto dying; | |||
477 | } | 498 | } | |
478 | 499 | |||
479 | /* | 500 | /* | |
480 | * Step 1: Make the stack ignore it and stop the callout. | 501 | * HC Step 1: Handle the hardware. | |
481 | */ | 502 | */ | |
482 | mutex_spin_enter(&hsotg->lock); | 503 | mutex_spin_enter(&hsotg->lock); | |
483 | xfer->ux_hcflags |= UXFER_ABORTING; | |||
484 | ||||
485 | xfer->ux_status = status; /* make software ignore it */ | |||
486 | callout_stop(&xfer->ux_callout); | |||
487 | ||||
488 | /* XXXNH suboptimal */ | 504 | /* XXXNH suboptimal */ | |
489 | TAILQ_FOREACH_SAFE(d, &sc->sc_complete, xnext, tmp) { | 505 | TAILQ_FOREACH_SAFE(d, &sc->sc_complete, xnext, tmp) { | |
490 | if (d == dxfer) { | 506 | if (d == dxfer) { | |
491 | TAILQ_REMOVE(&sc->sc_complete, dxfer, xnext); | 507 | TAILQ_REMOVE(&sc->sc_complete, dxfer, xnext); | |
508 | break; | |||
492 | } | 509 | } | |
493 | } | 510 | } | |
494 | 511 | |||
495 | err = dwc2_hcd_urb_dequeue(hsotg, dxfer->urb); | 512 | err = dwc2_hcd_urb_dequeue(hsotg, dxfer->urb); | |
496 | if (err) { | 513 | if (err) { | |
497 | DPRINTF("dwc2_hcd_urb_dequeue failed\n"); | 514 | DPRINTF("dwc2_hcd_urb_dequeue failed\n"); | |
498 | } | 515 | } | |
499 | 516 | |||
500 | mutex_spin_exit(&hsotg->lock); | 517 | mutex_spin_exit(&hsotg->lock); | |
501 | 518 | |||
502 | /* | 519 | /* | |
503 | * Step 2: Execute callback. | 520 | * Final Step: Notify completion to waiting xfers. | |
504 | */ | 521 | */ | |
505 | wake = xfer->ux_hcflags & UXFER_ABORTWAIT; | 522 | dying: | |
506 | xfer->ux_hcflags &= ~(UXFER_ABORTING | UXFER_ABORTWAIT); | |||
507 | ||||
508 | usb_transfer_complete(xfer); | 523 | usb_transfer_complete(xfer); | |
509 | if (wake) { | 524 | KASSERT(mutex_owned(&sc->sc_lock)); | |
510 | cv_broadcast(&xfer->ux_hccv); | |||
511 | } | |||
512 | } | 525 | } | |
513 | 526 | |||
514 | Static void | 527 | Static void | |
515 | dwc2_noop(struct usbd_pipe *pipe) | 528 | dwc2_noop(struct usbd_pipe *pipe) | |
516 | { | 529 | { | |
517 | 530 | |||
518 | } | 531 | } | |
519 | 532 | |||
520 | Static void | 533 | Static void | |
521 | dwc2_device_clear_toggle(struct usbd_pipe *pipe) | 534 | dwc2_device_clear_toggle(struct usbd_pipe *pipe) | |
522 | { | 535 | { | |
523 | 536 | |||
524 | DPRINTF("toggle %d -> 0", pipe->up_endpoint->ue_toggle); | 537 | DPRINTF("toggle %d -> 0", pipe->up_endpoint->ue_toggle); | |
@@ -1108,27 +1121,27 @@ dwc2_device_start(struct usbd_xfer *xfer | @@ -1108,27 +1121,27 @@ dwc2_device_start(struct usbd_xfer *xfer | |||
1108 | 1121 | |||
1109 | if (alloc_bandwidth) { | 1122 | if (alloc_bandwidth) { | |
1110 | dwc2_allocate_bus_bandwidth(hsotg, | 1123 | dwc2_allocate_bus_bandwidth(hsotg, | |
1111 | dwc2_hcd_get_ep_bandwidth(hsotg, dpipe), | 1124 | dwc2_hcd_get_ep_bandwidth(hsotg, dpipe), | |
1112 | xfer); | 1125 | xfer); | |
1113 | } | 1126 | } | |
1114 | 1127 | |||
1115 | mutex_spin_exit(&hsotg->lock); | 1128 | mutex_spin_exit(&hsotg->lock); | |
1116 | // mutex_exit(&sc->sc_lock); | 1129 | // mutex_exit(&sc->sc_lock); | |
1117 | 1130 | |||
1118 | return USBD_IN_PROGRESS; | 1131 | return USBD_IN_PROGRESS; | |
1119 | 1132 | |||
1120 | fail2: | 1133 | fail2: | |
1121 | callout_stop(&xfer->ux_callout); | 1134 | callout_halt(&xfer->ux_callout, &hsotg->lock); | |
1122 | dwc2_urb->priv = NULL; | 1135 | dwc2_urb->priv = NULL; | |
1123 | mutex_spin_exit(&hsotg->lock); | 1136 | mutex_spin_exit(&hsotg->lock); | |
1124 | pool_cache_put(sc->sc_qtdpool, qtd); | 1137 | pool_cache_put(sc->sc_qtdpool, qtd); | |
1125 | 1138 | |||
1126 | fail1: | 1139 | fail1: | |
1127 | if (qh_allocated) { | 1140 | if (qh_allocated) { | |
1128 | dpipe->priv = NULL; | 1141 | dpipe->priv = NULL; | |
1129 | dwc2_hcd_qh_free(hsotg, qh); | 1142 | dwc2_hcd_qh_free(hsotg, qh); | |
1130 | } | 1143 | } | |
1131 | fail: | 1144 | fail: | |
1132 | 1145 | |||
1133 | switch (retval) { | 1146 | switch (retval) { | |
1134 | case -EINVAL: | 1147 | case -EINVAL: | |
@@ -1416,26 +1429,45 @@ void dwc2_host_complete(struct dwc2_hsot | @@ -1416,26 +1429,45 @@ void dwc2_host_complete(struct dwc2_hsot | |||
1416 | } | 1429 | } | |
1417 | 1430 | |||
1418 | if (!qtd->urb) { | 1431 | if (!qtd->urb) { | |
1419 | dev_dbg(hsotg->dev, "## %s: qtd->urb is NULL ##\n", __func__); | 1432 | dev_dbg(hsotg->dev, "## %s: qtd->urb is NULL ##\n", __func__); | |
1420 | return; | 1433 | return; | |
1421 | } | 1434 | } | |
1422 | 1435 | |||
1423 | xfer = qtd->urb->priv; | 1436 | xfer = qtd->urb->priv; | |
1424 | if (!xfer) { | 1437 | if (!xfer) { | |
1425 | dev_dbg(hsotg->dev, "## %s: urb->priv is NULL ##\n", __func__); | 1438 | dev_dbg(hsotg->dev, "## %s: urb->priv is NULL ##\n", __func__); | |
1426 | return; | 1439 | return; | |
1427 | } | 1440 | } | |
1428 | 1441 | |||
1442 | /* | |||
1443 | * If software has completed it, either by cancellation | |||
1444 | * or timeout, drop it on the floor. | |||
1445 | */ | |||
1446 | if (xfer->ux_status != USBD_IN_PROGRESS) { | |||
1447 | KASSERT(xfer->ux_status == USBD_CANCELLED || | |||
1448 | xfer->ux_status == USBD_TIMEOUT); | |||
1449 | return; | |||
1450 | } | |||
1451 | ||||
1452 | /* | |||
1453 | * Cancel the timeout and the task, which have not yet | |||
1454 | * run. If they have already fired, at worst they are | |||
1455 | * waiting for the lock. They will see that the xfer | |||
1456 | * is no longer in progress and give up. | |||
1457 | */ | |||
1458 | callout_stop(&xfer->ux_callout); | |||
1459 | usb_rem_task(xfer->ux_pipe->up_dev, &xfer->ux_aborttask); | |||
1460 | ||||
1429 | dxfer = DWC2_XFER2DXFER(xfer); | 1461 | dxfer = DWC2_XFER2DXFER(xfer); | |
1430 | sc = DWC2_XFER2SC(xfer); | 1462 | sc = DWC2_XFER2SC(xfer); | |
1431 | ed = xfer->ux_pipe->up_endpoint->ue_edesc; | 1463 | ed = xfer->ux_pipe->up_endpoint->ue_edesc; | |
1432 | xfertype = UE_GET_XFERTYPE(ed->bmAttributes); | 1464 | xfertype = UE_GET_XFERTYPE(ed->bmAttributes); | |
1433 | 1465 | |||
1434 | struct dwc2_hcd_urb *urb = qtd->urb; | 1466 | struct dwc2_hcd_urb *urb = qtd->urb; | |
1435 | xfer->ux_actlen = dwc2_hcd_urb_get_actual_length(urb); | 1467 | xfer->ux_actlen = dwc2_hcd_urb_get_actual_length(urb); | |
1436 | 1468 | |||
1437 | DPRINTFN(3, "xfer=%p actlen=%d\n", xfer, xfer->ux_actlen); | 1469 | DPRINTFN(3, "xfer=%p actlen=%d\n", xfer, xfer->ux_actlen); | |
1438 | 1470 | |||
1439 | if (xfertype == UE_ISOCHRONOUS) { | 1471 | if (xfertype == UE_ISOCHRONOUS) { | |
1440 | int i; | 1472 | int i; | |
1441 | 1473 | |||
@@ -1500,28 +1532,26 @@ void dwc2_host_complete(struct dwc2_hsot | @@ -1500,28 +1532,26 @@ void dwc2_host_complete(struct dwc2_hsot | |||
1500 | } | 1532 | } | |
1501 | } | 1533 | } | |
1502 | 1534 | |||
1503 | if (xfertype == UE_ISOCHRONOUS || | 1535 | if (xfertype == UE_ISOCHRONOUS || | |
1504 | xfertype == UE_INTERRUPT) { | 1536 | xfertype == UE_INTERRUPT) { | |
1505 | struct dwc2_pipe *dpipe = DWC2_XFER2DPIPE(xfer); | 1537 | struct dwc2_pipe *dpipe = DWC2_XFER2DPIPE(xfer); | |
1506 | 1538 | |||
1507 | dwc2_free_bus_bandwidth(hsotg, | 1539 | dwc2_free_bus_bandwidth(hsotg, | |
1508 | dwc2_hcd_get_ep_bandwidth(hsotg, dpipe), | 1540 | dwc2_hcd_get_ep_bandwidth(hsotg, dpipe), | |
1509 | xfer); | 1541 | xfer); | |
1510 | } | 1542 | } | |
1511 | 1543 | |||
1512 | qtd->urb = NULL; | 1544 | qtd->urb = NULL; | |
1513 | callout_stop(&xfer->ux_callout); | |||
1514 | ||||
1515 | KASSERT(mutex_owned(&hsotg->lock)); | 1545 | KASSERT(mutex_owned(&hsotg->lock)); | |
1516 | 1546 | |||
1517 | TAILQ_INSERT_TAIL(&sc->sc_complete, dxfer, xnext); | 1547 | TAILQ_INSERT_TAIL(&sc->sc_complete, dxfer, xnext); | |
1518 | 1548 | |||
1519 | mutex_spin_exit(&hsotg->lock); | 1549 | mutex_spin_exit(&hsotg->lock); | |
1520 | usb_schedsoftintr(&sc->sc_bus); | 1550 | usb_schedsoftintr(&sc->sc_bus); | |
1521 | mutex_spin_enter(&hsotg->lock); | 1551 | mutex_spin_enter(&hsotg->lock); | |
1522 | } | 1552 | } | |
1523 | 1553 | |||
1524 | 1554 | |||
1525 | int | 1555 | int | |
1526 | _dwc2_hcd_start(struct dwc2_hsotg *hsotg) | 1556 | _dwc2_hcd_start(struct dwc2_hsotg *hsotg) | |
1527 | { | 1557 | { |