2020-05-26 10:03:22 +03:00
|
|
|
/* $NetBSD: uhci.c,v 1.303 2020/05/26 07:03:22 skrll Exp $ */
|
1998-07-12 23:51:55 +04:00
|
|
|
|
|
|
|
/*
|
2020-05-26 10:03:22 +03:00
|
|
|
* Copyright (c) 1998, 2004, 2011, 2012, 2016, 2020 The NetBSD Foundation, Inc.
|
1998-07-12 23:51:55 +04:00
|
|
|
* All rights reserved.
|
|
|
|
*
|
1998-11-26 01:32:04 +03:00
|
|
|
* This code is derived from software contributed to The NetBSD Foundation
|
2000-04-27 19:26:44 +04:00
|
|
|
* by Lennart Augustsson (lennart@augustsson.net) at
|
2020-05-26 10:03:22 +03:00
|
|
|
* Carlstedt Research & Technology, Jared D. McNeill (jmcneill@invisible.ca),
|
|
|
|
* Matthew R. Green (mrg@eterna.com.au) and Nick Hudson.
|
1998-07-12 23:51:55 +04:00
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
|
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
|
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* USB Universal Host Controller driver.
|
1999-05-21 14:15:23 +04:00
|
|
|
* Handles e.g. PIIX3 and PIIX4.
|
1998-07-12 23:51:55 +04:00
|
|
|
*
|
2009-11-01 09:36:44 +03:00
|
|
|
* UHCI spec: http://www.intel.com/technology/usb/spec.htm
|
|
|
|
* USB spec: http://www.usb.org/developers/docs/
|
1999-12-24 16:56:35 +03:00
|
|
|
* PIIXn spec: ftp://download.intel.com/design/intarch/datashts/29055002.pdf
|
|
|
|
* ftp://download.intel.com/design/intarch/datashts/29056201.pdf
|
1998-07-12 23:51:55 +04:00
|
|
|
*/
|
|
|
|
|
2001-11-13 09:24:53 +03:00
|
|
|
#include <sys/cdefs.h>
|
2020-05-26 10:03:22 +03:00
|
|
|
__KERNEL_RCSID(0, "$NetBSD: uhci.c,v 1.303 2020/05/26 07:03:22 skrll Exp $");
|
2016-04-23 13:15:27 +03:00
|
|
|
|
2016-05-10 18:14:03 +03:00
|
|
|
#ifdef _KERNEL_OPT
|
2016-04-23 13:15:27 +03:00
|
|
|
#include "opt_usb.h"
|
2016-05-10 18:14:03 +03:00
|
|
|
#endif
|
2001-11-13 09:24:53 +03:00
|
|
|
|
1998-07-12 23:51:55 +04:00
|
|
|
#include <sys/param.h>
|
2016-04-23 13:15:27 +03:00
|
|
|
|
|
|
|
#include <sys/bus.h>
|
|
|
|
#include <sys/cpu.h>
|
|
|
|
#include <sys/device.h>
|
1998-07-12 23:51:55 +04:00
|
|
|
#include <sys/kernel.h>
|
2012-06-10 10:15:52 +04:00
|
|
|
#include <sys/kmem.h>
|
2016-04-23 13:15:27 +03:00
|
|
|
#include <sys/mutex.h>
|
1998-07-12 23:51:55 +04:00
|
|
|
#include <sys/proc.h>
|
|
|
|
#include <sys/queue.h>
|
2016-04-23 13:15:27 +03:00
|
|
|
#include <sys/select.h>
|
|
|
|
#include <sys/sysctl.h>
|
|
|
|
#include <sys/systm.h>
|
1998-07-12 23:51:55 +04:00
|
|
|
|
1999-08-19 23:52:38 +04:00
|
|
|
#include <machine/endian.h>
|
1998-07-12 23:51:55 +04:00
|
|
|
|
1998-07-25 01:09:07 +04:00
|
|
|
#include <dev/usb/usb.h>
|
1998-07-12 23:51:55 +04:00
|
|
|
#include <dev/usb/usbdi.h>
|
|
|
|
#include <dev/usb/usbdivar.h>
|
1998-07-25 01:09:07 +04:00
|
|
|
#include <dev/usb/usb_mem.h>
|
1998-07-12 23:51:55 +04:00
|
|
|
|
|
|
|
#include <dev/usb/uhcireg.h>
|
|
|
|
#include <dev/usb/uhcivar.h>
|
2016-04-23 13:15:27 +03:00
|
|
|
#include <dev/usb/usbroothub.h>
|
|
|
|
#include <dev/usb/usbhist.h>
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2000-09-24 01:00:10 +04:00
|
|
|
/* Use bandwidth reclamation for control transfers. Some devices choke on it. */
|
|
|
|
/*#define UHCI_CTL_LOOP */
|
|
|
|
|
1999-11-19 02:32:25 +03:00
|
|
|
#ifdef UHCI_DEBUG
|
2000-03-25 01:57:58 +03:00
|
|
|
uhci_softc_t *thesc;
|
2000-09-24 01:00:10 +04:00
|
|
|
int uhcinoloop = 0;
|
1999-10-13 12:10:55 +04:00
|
|
|
#endif
|
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
#ifdef USB_DEBUG
|
|
|
|
#ifndef UHCI_DEBUG
|
|
|
|
#define uhcidebug 0
|
|
|
|
#else
|
|
|
|
static int uhcidebug = 0;
|
|
|
|
|
|
|
|
SYSCTL_SETUP(sysctl_hw_uhci_setup, "sysctl hw.uhci setup")
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
const struct sysctlnode *rnode;
|
|
|
|
const struct sysctlnode *cnode;
|
|
|
|
|
|
|
|
err = sysctl_createv(clog, 0, NULL, &rnode,
|
|
|
|
CTLFLAG_PERMANENT, CTLTYPE_NODE, "uhci",
|
|
|
|
SYSCTL_DESCR("uhci global controls"),
|
|
|
|
NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL);
|
|
|
|
|
|
|
|
if (err)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
/* control debugging printfs */
|
|
|
|
err = sysctl_createv(clog, 0, &rnode, &cnode,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT,
|
|
|
|
"debug", SYSCTL_DESCR("Enable debugging output"),
|
|
|
|
NULL, 0, &uhcidebug, sizeof(uhcidebug), CTL_CREATE, CTL_EOL);
|
|
|
|
if (err)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
return;
|
|
|
|
fail:
|
|
|
|
aprint_error("%s: sysctl_createv failed (err = %d)\n", __func__, err);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* UHCI_DEBUG */
|
|
|
|
#endif /* USB_DEBUG */
|
|
|
|
|
|
|
|
#define DPRINTF(FMT,A,B,C,D) USBHIST_LOGN(uhcidebug,1,FMT,A,B,C,D)
|
|
|
|
#define DPRINTFN(N,FMT,A,B,C,D) USBHIST_LOGN(uhcidebug,N,FMT,A,B,C,D)
|
|
|
|
#define UHCIHIST_FUNC() USBHIST_FUNC()
|
|
|
|
#define UHCIHIST_CALLED(name) USBHIST_CALLED(uhcidebug)
|
|
|
|
|
1999-08-19 23:52:38 +04:00
|
|
|
/*
|
|
|
|
* The UHCI controller is little endian, so on big endian machines
|
2004-07-22 22:45:40 +04:00
|
|
|
* the data stored in memory needs to be swapped.
|
1999-08-19 23:52:38 +04:00
|
|
|
*/
|
|
|
|
|
1998-07-12 23:51:55 +04:00
|
|
|
struct uhci_pipe {
|
|
|
|
struct usbd_pipe pipe;
|
1999-07-12 09:22:50 +04:00
|
|
|
int nexttoggle;
|
2000-03-25 01:57:58 +03:00
|
|
|
|
|
|
|
u_char aborting;
|
2016-04-23 13:15:27 +03:00
|
|
|
struct usbd_xfer *abortstart, abortend;
|
2000-03-25 01:57:58 +03:00
|
|
|
|
1998-07-12 23:51:55 +04:00
|
|
|
/* Info needed for different pipe kinds. */
|
|
|
|
union {
|
|
|
|
/* Control pipe */
|
|
|
|
struct {
|
|
|
|
uhci_soft_qh_t *sqh;
|
1998-07-25 01:09:07 +04:00
|
|
|
usb_dma_t reqdma;
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_soft_td_t *setup;
|
|
|
|
uhci_soft_td_t *stat;
|
|
|
|
} ctrl;
|
1998-07-12 23:51:55 +04:00
|
|
|
/* Interrupt pipe */
|
|
|
|
struct {
|
|
|
|
int npoll;
|
|
|
|
uhci_soft_qh_t **qhs;
|
|
|
|
} intr;
|
|
|
|
/* Bulk pipe */
|
|
|
|
struct {
|
|
|
|
uhci_soft_qh_t *sqh;
|
|
|
|
} bulk;
|
2016-04-23 13:15:27 +03:00
|
|
|
/* Isochronous pipe */
|
|
|
|
struct isoc {
|
1998-12-28 23:13:59 +03:00
|
|
|
uhci_soft_td_t **stds;
|
1999-09-09 16:26:43 +04:00
|
|
|
int next, inuse;
|
2016-04-23 13:15:27 +03:00
|
|
|
} isoc;
|
|
|
|
};
|
1998-07-12 23:51:55 +04:00
|
|
|
};
|
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
typedef TAILQ_HEAD(ux_completeq, uhci_xfer) ux_completeq_t;
|
|
|
|
|
2001-10-25 06:08:13 +04:00
|
|
|
Static void uhci_globalreset(uhci_softc_t *);
|
2002-12-31 05:21:31 +03:00
|
|
|
Static usbd_status uhci_portreset(uhci_softc_t*, int);
|
2001-10-25 06:08:13 +04:00
|
|
|
Static void uhci_reset(uhci_softc_t *);
|
2016-04-23 13:15:27 +03:00
|
|
|
Static usbd_status uhci_run(uhci_softc_t *, int, int);
|
2000-08-13 20:18:09 +04:00
|
|
|
Static uhci_soft_td_t *uhci_alloc_std(uhci_softc_t *);
|
2000-06-01 18:28:57 +04:00
|
|
|
Static void uhci_free_std(uhci_softc_t *, uhci_soft_td_t *);
|
2016-04-23 13:15:27 +03:00
|
|
|
Static void uhci_free_std_locked(uhci_softc_t *, uhci_soft_td_t *);
|
2000-08-13 20:18:09 +04:00
|
|
|
Static uhci_soft_qh_t *uhci_alloc_sqh(uhci_softc_t *);
|
2000-06-01 18:28:57 +04:00
|
|
|
Static void uhci_free_sqh(uhci_softc_t *, uhci_soft_qh_t *);
|
1998-12-28 23:13:59 +03:00
|
|
|
#if 0
|
2000-06-01 18:28:57 +04:00
|
|
|
Static void uhci_enter_ctl_q(uhci_softc_t *, uhci_soft_qh_t *,
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_intr_info_t *);
|
2000-06-01 18:28:57 +04:00
|
|
|
Static void uhci_exit_ctl_q(uhci_softc_t *, uhci_soft_qh_t *);
|
1998-12-28 23:13:59 +03:00
|
|
|
#endif
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
#if 0
|
|
|
|
Static void uhci_free_std_chain(uhci_softc_t *, uhci_soft_td_t *,
|
|
|
|
uhci_soft_td_t *);
|
|
|
|
#endif
|
|
|
|
Static int uhci_alloc_std_chain(uhci_softc_t *, struct usbd_xfer *,
|
|
|
|
int, int, uhci_soft_td_t **);
|
|
|
|
Static void uhci_free_stds(uhci_softc_t *, struct uhci_xfer *);
|
|
|
|
|
|
|
|
Static void uhci_reset_std_chain(uhci_softc_t *, struct usbd_xfer *,
|
|
|
|
int, int, int *, uhci_soft_td_t **);
|
|
|
|
|
2000-06-01 18:28:57 +04:00
|
|
|
Static void uhci_poll_hub(void *);
|
2016-04-23 13:15:27 +03:00
|
|
|
Static void uhci_check_intr(uhci_softc_t *, struct uhci_xfer *,
|
|
|
|
ux_completeq_t *);
|
|
|
|
Static void uhci_idone(struct uhci_xfer *, ux_completeq_t *);
|
2000-06-01 18:28:57 +04:00
|
|
|
|
2020-02-12 19:01:00 +03:00
|
|
|
Static void uhci_abortx(struct usbd_xfer *);
|
2000-06-01 18:28:57 +04:00
|
|
|
|
2000-08-13 20:18:09 +04:00
|
|
|
Static void uhci_add_ls_ctrl(uhci_softc_t *, uhci_soft_qh_t *);
|
|
|
|
Static void uhci_add_hs_ctrl(uhci_softc_t *, uhci_soft_qh_t *);
|
2000-06-01 18:28:57 +04:00
|
|
|
Static void uhci_add_bulk(uhci_softc_t *, uhci_soft_qh_t *);
|
2000-08-13 20:18:09 +04:00
|
|
|
Static void uhci_remove_ls_ctrl(uhci_softc_t *,uhci_soft_qh_t *);
|
|
|
|
Static void uhci_remove_hs_ctrl(uhci_softc_t *,uhci_soft_qh_t *);
|
2000-06-01 18:28:57 +04:00
|
|
|
Static void uhci_remove_bulk(uhci_softc_t *,uhci_soft_qh_t *);
|
2016-04-23 13:15:27 +03:00
|
|
|
Static void uhci_add_loop(uhci_softc_t *);
|
|
|
|
Static void uhci_rem_loop(uhci_softc_t *);
|
2000-06-01 18:28:57 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
Static usbd_status uhci_setup_isoc(struct usbd_pipe *);
|
2000-06-01 18:28:57 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
Static struct usbd_xfer *
|
|
|
|
uhci_allocx(struct usbd_bus *, unsigned int);
|
|
|
|
Static void uhci_freex(struct usbd_bus *, struct usbd_xfer *);
|
2020-02-12 19:01:00 +03:00
|
|
|
Static bool uhci_dying(struct usbd_bus *);
|
2012-06-10 10:15:52 +04:00
|
|
|
Static void uhci_get_lock(struct usbd_bus *, kmutex_t **);
|
2016-04-23 13:15:27 +03:00
|
|
|
Static int uhci_roothub_ctrl(struct usbd_bus *,
|
|
|
|
usb_device_request_t *, void *, int);
|
|
|
|
|
|
|
|
Static int uhci_device_ctrl_init(struct usbd_xfer *);
|
|
|
|
Static void uhci_device_ctrl_fini(struct usbd_xfer *);
|
|
|
|
Static usbd_status uhci_device_ctrl_transfer(struct usbd_xfer *);
|
|
|
|
Static usbd_status uhci_device_ctrl_start(struct usbd_xfer *);
|
|
|
|
Static void uhci_device_ctrl_abort(struct usbd_xfer *);
|
|
|
|
Static void uhci_device_ctrl_close(struct usbd_pipe *);
|
|
|
|
Static void uhci_device_ctrl_done(struct usbd_xfer *);
|
|
|
|
|
|
|
|
Static int uhci_device_intr_init(struct usbd_xfer *);
|
|
|
|
Static void uhci_device_intr_fini(struct usbd_xfer *);
|
|
|
|
Static usbd_status uhci_device_intr_transfer(struct usbd_xfer *);
|
|
|
|
Static usbd_status uhci_device_intr_start(struct usbd_xfer *);
|
|
|
|
Static void uhci_device_intr_abort(struct usbd_xfer *);
|
|
|
|
Static void uhci_device_intr_close(struct usbd_pipe *);
|
|
|
|
Static void uhci_device_intr_done(struct usbd_xfer *);
|
|
|
|
|
|
|
|
Static int uhci_device_bulk_init(struct usbd_xfer *);
|
|
|
|
Static void uhci_device_bulk_fini(struct usbd_xfer *);
|
|
|
|
Static usbd_status uhci_device_bulk_transfer(struct usbd_xfer *);
|
|
|
|
Static usbd_status uhci_device_bulk_start(struct usbd_xfer *);
|
|
|
|
Static void uhci_device_bulk_abort(struct usbd_xfer *);
|
|
|
|
Static void uhci_device_bulk_close(struct usbd_pipe *);
|
|
|
|
Static void uhci_device_bulk_done(struct usbd_xfer *);
|
|
|
|
|
|
|
|
Static int uhci_device_isoc_init(struct usbd_xfer *);
|
|
|
|
Static void uhci_device_isoc_fini(struct usbd_xfer *);
|
|
|
|
Static usbd_status uhci_device_isoc_transfer(struct usbd_xfer *);
|
|
|
|
Static void uhci_device_isoc_abort(struct usbd_xfer *);
|
|
|
|
Static void uhci_device_isoc_close(struct usbd_pipe *);
|
|
|
|
Static void uhci_device_isoc_done(struct usbd_xfer *);
|
|
|
|
|
|
|
|
Static usbd_status uhci_root_intr_transfer(struct usbd_xfer *);
|
|
|
|
Static usbd_status uhci_root_intr_start(struct usbd_xfer *);
|
|
|
|
Static void uhci_root_intr_abort(struct usbd_xfer *);
|
|
|
|
Static void uhci_root_intr_close(struct usbd_pipe *);
|
|
|
|
Static void uhci_root_intr_done(struct usbd_xfer *);
|
|
|
|
|
|
|
|
Static usbd_status uhci_open(struct usbd_pipe *);
|
2000-06-01 18:28:57 +04:00
|
|
|
Static void uhci_poll(struct usbd_bus *);
|
2001-01-21 05:39:52 +03:00
|
|
|
Static void uhci_softintr(void *);
|
2000-06-01 18:28:57 +04:00
|
|
|
|
|
|
|
Static void uhci_add_intr(uhci_softc_t *, uhci_soft_qh_t *);
|
2002-03-17 21:02:52 +03:00
|
|
|
Static void uhci_remove_intr(uhci_softc_t *, uhci_soft_qh_t *);
|
2016-04-23 13:15:27 +03:00
|
|
|
Static usbd_status uhci_device_setintr(uhci_softc_t *,
|
|
|
|
struct uhci_pipe *, int);
|
2000-06-01 18:28:57 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
Static void uhci_device_clear_toggle(struct usbd_pipe *);
|
|
|
|
Static void uhci_noop(struct usbd_pipe *);
|
2000-06-01 18:28:57 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
static inline uhci_soft_qh_t *
|
|
|
|
uhci_find_prev_qh(uhci_soft_qh_t *, uhci_soft_qh_t *);
|
2000-03-25 01:57:58 +03:00
|
|
|
|
1999-10-13 12:10:55 +04:00
|
|
|
#ifdef UHCI_DEBUG
|
2000-06-01 18:28:57 +04:00
|
|
|
Static void uhci_dump_all(uhci_softc_t *);
|
|
|
|
Static void uhci_dumpregs(uhci_softc_t *);
|
|
|
|
Static void uhci_dump_qhs(uhci_soft_qh_t *);
|
|
|
|
Static void uhci_dump_qh(uhci_soft_qh_t *);
|
|
|
|
Static void uhci_dump_tds(uhci_soft_td_t *);
|
|
|
|
Static void uhci_dump_td(uhci_soft_td_t *);
|
2016-04-23 13:15:27 +03:00
|
|
|
Static void uhci_dump_ii(struct uhci_xfer *);
|
2000-06-01 18:28:57 +04:00
|
|
|
void uhci_dump(void);
|
1998-07-12 23:51:55 +04:00
|
|
|
#endif
|
|
|
|
|
2000-04-25 18:28:13 +04:00
|
|
|
#define UBARR(sc) bus_space_barrier((sc)->iot, (sc)->ioh, 0, (sc)->sc_size, \
|
|
|
|
BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE)
|
|
|
|
#define UWRITE1(sc, r, x) \
|
2002-12-31 05:04:49 +03:00
|
|
|
do { UBARR(sc); bus_space_write_1((sc)->iot, (sc)->ioh, (r), (x)); \
|
|
|
|
} while (/*CONSTCOND*/0)
|
2000-04-25 18:28:13 +04:00
|
|
|
#define UWRITE2(sc, r, x) \
|
2002-12-31 05:04:49 +03:00
|
|
|
do { UBARR(sc); bus_space_write_2((sc)->iot, (sc)->ioh, (r), (x)); \
|
|
|
|
} while (/*CONSTCOND*/0)
|
2000-04-25 18:28:13 +04:00
|
|
|
#define UWRITE4(sc, r, x) \
|
2002-12-31 05:04:49 +03:00
|
|
|
do { UBARR(sc); bus_space_write_4((sc)->iot, (sc)->ioh, (r), (x)); \
|
|
|
|
} while (/*CONSTCOND*/0)
|
2016-04-23 13:15:27 +03:00
|
|
|
|
2006-05-12 05:25:00 +04:00
|
|
|
static __inline uint8_t
|
|
|
|
UREAD1(uhci_softc_t *sc, bus_size_t r)
|
|
|
|
{
|
|
|
|
|
|
|
|
UBARR(sc);
|
|
|
|
return bus_space_read_1(sc->iot, sc->ioh, r);
|
|
|
|
}
|
|
|
|
|
|
|
|
static __inline uint16_t
|
|
|
|
UREAD2(uhci_softc_t *sc, bus_size_t r)
|
|
|
|
{
|
|
|
|
|
|
|
|
UBARR(sc);
|
|
|
|
return bus_space_read_2(sc->iot, sc->ioh, r);
|
|
|
|
}
|
|
|
|
|
2013-09-14 17:17:21 +04:00
|
|
|
#ifdef UHCI_DEBUG
|
2006-05-12 05:25:00 +04:00
|
|
|
static __inline uint32_t
|
|
|
|
UREAD4(uhci_softc_t *sc, bus_size_t r)
|
|
|
|
{
|
|
|
|
|
|
|
|
UBARR(sc);
|
|
|
|
return bus_space_read_4(sc->iot, sc->ioh, r);
|
|
|
|
}
|
2013-09-14 17:17:21 +04:00
|
|
|
#endif
|
1998-07-12 23:51:55 +04:00
|
|
|
|
|
|
|
#define UHCICMD(sc, cmd) UWRITE2(sc, UHCI_CMD, cmd)
|
|
|
|
#define UHCISTS(sc) UREAD2(sc, UHCI_STS)
|
|
|
|
|
2001-10-25 06:08:13 +04:00
|
|
|
#define UHCI_RESET_TIMEOUT 100 /* ms, reset timeout */
|
1998-07-12 23:51:55 +04:00
|
|
|
|
|
|
|
#define UHCI_CURFRAME(sc) (UREAD2(sc, UHCI_FRNUM) & UHCI_FRNUM_MASK)
|
|
|
|
|
2007-02-26 16:26:45 +03:00
|
|
|
const struct usbd_bus_methods uhci_bus_methods = {
|
2016-04-23 13:15:27 +03:00
|
|
|
.ubm_open = uhci_open,
|
|
|
|
.ubm_softint = uhci_softintr,
|
|
|
|
.ubm_dopoll = uhci_poll,
|
|
|
|
.ubm_allocx = uhci_allocx,
|
|
|
|
.ubm_freex = uhci_freex,
|
2020-02-12 19:01:00 +03:00
|
|
|
.ubm_abortx = uhci_abortx,
|
|
|
|
.ubm_dying = uhci_dying,
|
2016-04-23 13:15:27 +03:00
|
|
|
.ubm_getlock = uhci_get_lock,
|
|
|
|
.ubm_rhctrl = uhci_roothub_ctrl,
|
1998-07-12 23:51:55 +04:00
|
|
|
};
|
|
|
|
|
2007-02-26 16:26:45 +03:00
|
|
|
const struct usbd_pipe_methods uhci_root_intr_methods = {
|
2016-04-23 13:15:27 +03:00
|
|
|
.upm_transfer = uhci_root_intr_transfer,
|
|
|
|
.upm_start = uhci_root_intr_start,
|
|
|
|
.upm_abort = uhci_root_intr_abort,
|
|
|
|
.upm_close = uhci_root_intr_close,
|
|
|
|
.upm_cleartoggle = uhci_noop,
|
|
|
|
.upm_done = uhci_root_intr_done,
|
1998-07-12 23:51:55 +04:00
|
|
|
};
|
|
|
|
|
2007-02-26 16:26:45 +03:00
|
|
|
const struct usbd_pipe_methods uhci_device_ctrl_methods = {
|
2016-04-23 13:15:27 +03:00
|
|
|
.upm_init = uhci_device_ctrl_init,
|
|
|
|
.upm_fini = uhci_device_ctrl_fini,
|
|
|
|
.upm_transfer = uhci_device_ctrl_transfer,
|
|
|
|
.upm_start = uhci_device_ctrl_start,
|
|
|
|
.upm_abort = uhci_device_ctrl_abort,
|
|
|
|
.upm_close = uhci_device_ctrl_close,
|
|
|
|
.upm_cleartoggle = uhci_noop,
|
|
|
|
.upm_done = uhci_device_ctrl_done,
|
1998-07-12 23:51:55 +04:00
|
|
|
};
|
|
|
|
|
2007-02-26 16:26:45 +03:00
|
|
|
const struct usbd_pipe_methods uhci_device_intr_methods = {
|
2016-04-23 13:15:27 +03:00
|
|
|
.upm_init = uhci_device_intr_init,
|
|
|
|
.upm_fini = uhci_device_intr_fini,
|
|
|
|
.upm_transfer = uhci_device_intr_transfer,
|
|
|
|
.upm_start = uhci_device_intr_start,
|
|
|
|
.upm_abort = uhci_device_intr_abort,
|
|
|
|
.upm_close = uhci_device_intr_close,
|
|
|
|
.upm_cleartoggle = uhci_device_clear_toggle,
|
|
|
|
.upm_done = uhci_device_intr_done,
|
1998-07-12 23:51:55 +04:00
|
|
|
};
|
|
|
|
|
2007-02-26 16:26:45 +03:00
|
|
|
const struct usbd_pipe_methods uhci_device_bulk_methods = {
|
2016-04-23 13:15:27 +03:00
|
|
|
.upm_init = uhci_device_bulk_init,
|
|
|
|
.upm_fini = uhci_device_bulk_fini,
|
|
|
|
.upm_transfer = uhci_device_bulk_transfer,
|
|
|
|
.upm_start = uhci_device_bulk_start,
|
|
|
|
.upm_abort = uhci_device_bulk_abort,
|
|
|
|
.upm_close = uhci_device_bulk_close,
|
|
|
|
.upm_cleartoggle = uhci_device_clear_toggle,
|
|
|
|
.upm_done = uhci_device_bulk_done,
|
1998-07-12 23:51:55 +04:00
|
|
|
};
|
|
|
|
|
2007-02-26 16:26:45 +03:00
|
|
|
const struct usbd_pipe_methods uhci_device_isoc_methods = {
|
2016-04-23 13:15:27 +03:00
|
|
|
.upm_init = uhci_device_isoc_init,
|
|
|
|
.upm_fini = uhci_device_isoc_fini,
|
|
|
|
.upm_transfer = uhci_device_isoc_transfer,
|
|
|
|
.upm_abort = uhci_device_isoc_abort,
|
|
|
|
.upm_close = uhci_device_isoc_close,
|
|
|
|
.upm_cleartoggle = uhci_noop,
|
|
|
|
.upm_done = uhci_device_isoc_done,
|
1998-12-28 23:13:59 +03:00
|
|
|
};
|
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
static inline void
|
|
|
|
uhci_add_intr_list(uhci_softc_t *sc, struct uhci_xfer *ux)
|
|
|
|
{
|
|
|
|
|
|
|
|
TAILQ_INSERT_TAIL(&sc->sc_intrhead, ux, ux_list);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
uhci_del_intr_list(uhci_softc_t *sc, struct uhci_xfer *ux)
|
|
|
|
{
|
|
|
|
|
|
|
|
TAILQ_REMOVE(&sc->sc_intrhead, ux, ux_list);
|
|
|
|
}
|
2000-03-25 01:57:58 +03:00
|
|
|
|
2011-08-07 22:58:52 +04:00
|
|
|
static inline uhci_soft_qh_t *
|
2000-06-01 18:28:57 +04:00
|
|
|
uhci_find_prev_qh(uhci_soft_qh_t *pqh, uhci_soft_qh_t *sqh)
|
2000-03-25 01:57:58 +03:00
|
|
|
{
|
2016-04-23 13:15:27 +03:00
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTFN(15, "pqh=%#jx sqh=%#jx", (uintptr_t)pqh, (uintptr_t)sqh, 0, 0);
|
2000-03-25 01:57:58 +03:00
|
|
|
|
|
|
|
for (; pqh->hlink != sqh; pqh = pqh->hlink) {
|
2002-02-03 21:15:20 +03:00
|
|
|
#if defined(DIAGNOSTIC) || defined(UHCI_DEBUG)
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&pqh->dma,
|
|
|
|
pqh->offs + offsetof(uhci_qh_t, qh_hlink),
|
|
|
|
sizeof(pqh->qh.qh_hlink),
|
|
|
|
BUS_DMASYNC_POSTWRITE);
|
2000-03-25 01:57:58 +03:00
|
|
|
if (le32toh(pqh->qh.qh_hlink) & UHCI_PTR_T) {
|
2016-04-23 13:15:27 +03:00
|
|
|
printf("%s: QH not found\n", __func__);
|
|
|
|
return NULL;
|
2000-03-25 01:57:58 +03:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
2016-04-23 13:15:27 +03:00
|
|
|
return pqh;
|
2000-03-25 01:57:58 +03:00
|
|
|
}
|
|
|
|
|
1998-07-12 23:51:55 +04:00
|
|
|
void
|
2001-10-25 06:08:13 +04:00
|
|
|
uhci_globalreset(uhci_softc_t *sc)
|
1998-07-12 23:51:55 +04:00
|
|
|
{
|
|
|
|
UHCICMD(sc, UHCI_CMD_GRESET); /* global reset */
|
1998-12-30 21:06:25 +03:00
|
|
|
usb_delay_ms(&sc->sc_bus, USB_BUS_RESET_DELAY); /* wait a little */
|
1998-07-12 23:51:55 +04:00
|
|
|
UHCICMD(sc, 0); /* do nothing */
|
|
|
|
}
|
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
int
|
2000-06-01 18:28:57 +04:00
|
|
|
uhci_init(uhci_softc_t *sc)
|
1998-07-12 23:51:55 +04:00
|
|
|
{
|
1999-11-12 03:34:57 +03:00
|
|
|
usbd_status err;
|
1998-07-12 23:51:55 +04:00
|
|
|
int i, j;
|
2000-08-13 20:18:09 +04:00
|
|
|
uhci_soft_qh_t *clsqh, *chsqh, *bsqh, *sqh, *lsqh;
|
1998-07-12 23:51:55 +04:00
|
|
|
uhci_soft_td_t *std;
|
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
1998-07-12 23:51:55 +04:00
|
|
|
|
1999-11-19 02:32:25 +03:00
|
|
|
#ifdef UHCI_DEBUG
|
2000-03-25 01:57:58 +03:00
|
|
|
thesc = sc;
|
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
if (uhcidebug >= 2)
|
1998-07-12 23:51:55 +04:00
|
|
|
uhci_dumpregs(sc);
|
|
|
|
#endif
|
|
|
|
|
2008-06-02 05:02:21 +04:00
|
|
|
sc->sc_suspend = PWR_RESUME;
|
|
|
|
|
1998-07-12 23:51:55 +04:00
|
|
|
UWRITE2(sc, UHCI_INTR, 0); /* disable interrupts */
|
2001-10-25 06:08:13 +04:00
|
|
|
uhci_globalreset(sc); /* reset the controller */
|
|
|
|
uhci_reset(sc);
|
1999-02-21 02:26:16 +03:00
|
|
|
|
1998-07-12 23:51:55 +04:00
|
|
|
/* Allocate and initialize real frame array. */
|
2002-02-03 21:15:20 +03:00
|
|
|
err = usb_allocmem(&sc->sc_bus,
|
2016-04-23 13:15:27 +03:00
|
|
|
UHCI_FRAMELIST_COUNT * sizeof(uhci_physaddr_t),
|
2020-04-05 23:59:38 +03:00
|
|
|
UHCI_FRAMELIST_ALIGN, USBMALLOC_COHERENT, &sc->sc_dma);
|
1999-11-12 03:34:57 +03:00
|
|
|
if (err)
|
2016-04-23 13:15:27 +03:00
|
|
|
return err;
|
2002-05-19 10:24:30 +04:00
|
|
|
sc->sc_pframes = KERNADDR(&sc->sc_dma, 0);
|
2020-03-15 17:58:54 +03:00
|
|
|
/* set frame number to 0 */
|
|
|
|
UWRITE2(sc, UHCI_FRNUM, 0);
|
2020-03-15 18:00:14 +03:00
|
|
|
/* set frame list */
|
2020-03-15 17:58:54 +03:00
|
|
|
UWRITE4(sc, UHCI_FLBASEADDR, DMAADDR(&sc->sc_dma, 0));
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
/* Initialise mutex early for uhci_alloc_* */
|
|
|
|
mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB);
|
|
|
|
mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_USB);
|
|
|
|
|
2002-02-03 21:15:20 +03:00
|
|
|
/*
|
2000-08-13 20:18:09 +04:00
|
|
|
* Allocate a TD, inactive, that hangs from the last QH.
|
|
|
|
* This is to avoid a bug in the PIIX that makes it run berserk
|
|
|
|
* otherwise.
|
|
|
|
*/
|
|
|
|
std = uhci_alloc_std(sc);
|
|
|
|
if (std == NULL)
|
2016-04-23 13:15:27 +03:00
|
|
|
return ENOMEM;
|
2000-08-13 20:18:09 +04:00
|
|
|
std->link.std = NULL;
|
|
|
|
std->td.td_link = htole32(UHCI_PTR_T);
|
|
|
|
std->td.td_status = htole32(0); /* inactive */
|
|
|
|
std->td.td_token = htole32(0);
|
|
|
|
std->td.td_buffer = htole32(0);
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&std->dma, std->offs, sizeof(std->td),
|
|
|
|
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
|
2000-08-13 20:18:09 +04:00
|
|
|
|
|
|
|
/* Allocate the dummy QH marking the end and used for looping the QHs.*/
|
|
|
|
lsqh = uhci_alloc_sqh(sc);
|
|
|
|
if (lsqh == NULL)
|
2016-04-23 13:15:27 +03:00
|
|
|
goto fail1;
|
2000-08-13 20:18:09 +04:00
|
|
|
lsqh->hlink = NULL;
|
|
|
|
lsqh->qh.qh_hlink = htole32(UHCI_PTR_T); /* end of QH chain */
|
|
|
|
lsqh->elink = std;
|
|
|
|
lsqh->qh.qh_elink = htole32(std->physaddr | UHCI_PTR_TD);
|
|
|
|
sc->sc_last_qh = lsqh;
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&lsqh->dma, lsqh->offs, sizeof(lsqh->qh),
|
|
|
|
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
|
2000-08-13 20:18:09 +04:00
|
|
|
|
1998-07-12 23:51:55 +04:00
|
|
|
/* Allocate the dummy QH where bulk traffic will be queued. */
|
|
|
|
bsqh = uhci_alloc_sqh(sc);
|
1999-11-12 03:34:57 +03:00
|
|
|
if (bsqh == NULL)
|
2016-04-23 13:15:27 +03:00
|
|
|
goto fail2;
|
2000-08-13 20:18:09 +04:00
|
|
|
bsqh->hlink = lsqh;
|
|
|
|
bsqh->qh.qh_hlink = htole32(lsqh->physaddr | UHCI_PTR_QH);
|
2000-07-23 23:43:37 +04:00
|
|
|
bsqh->elink = NULL;
|
2000-03-16 15:40:51 +03:00
|
|
|
bsqh->qh.qh_elink = htole32(UHCI_PTR_T);
|
1998-07-12 23:51:55 +04:00
|
|
|
sc->sc_bulk_start = sc->sc_bulk_end = bsqh;
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&bsqh->dma, bsqh->offs, sizeof(bsqh->qh),
|
|
|
|
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2000-08-13 20:18:09 +04:00
|
|
|
/* Allocate dummy QH where high speed control traffic will be queued. */
|
|
|
|
chsqh = uhci_alloc_sqh(sc);
|
|
|
|
if (chsqh == NULL)
|
2016-04-23 13:15:27 +03:00
|
|
|
goto fail3;
|
2000-08-13 20:18:09 +04:00
|
|
|
chsqh->hlink = bsqh;
|
|
|
|
chsqh->qh.qh_hlink = htole32(bsqh->physaddr | UHCI_PTR_QH);
|
|
|
|
chsqh->elink = NULL;
|
|
|
|
chsqh->qh.qh_elink = htole32(UHCI_PTR_T);
|
|
|
|
sc->sc_hctl_start = sc->sc_hctl_end = chsqh;
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&chsqh->dma, chsqh->offs, sizeof(chsqh->qh),
|
|
|
|
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
|
2000-08-13 20:18:09 +04:00
|
|
|
|
|
|
|
/* Allocate dummy QH where control traffic will be queued. */
|
|
|
|
clsqh = uhci_alloc_sqh(sc);
|
|
|
|
if (clsqh == NULL)
|
2016-04-23 13:15:27 +03:00
|
|
|
goto fail4;
|
2008-06-03 00:53:29 +04:00
|
|
|
clsqh->hlink = chsqh;
|
2000-08-13 20:18:09 +04:00
|
|
|
clsqh->qh.qh_hlink = htole32(chsqh->physaddr | UHCI_PTR_QH);
|
|
|
|
clsqh->elink = NULL;
|
|
|
|
clsqh->qh.qh_elink = htole32(UHCI_PTR_T);
|
|
|
|
sc->sc_lctl_start = sc->sc_lctl_end = clsqh;
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&clsqh->dma, clsqh->offs, sizeof(clsqh->qh),
|
|
|
|
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2002-02-03 21:15:20 +03:00
|
|
|
/*
|
1998-07-12 23:51:55 +04:00
|
|
|
* Make all (virtual) frame list pointers point to the interrupt
|
|
|
|
* queue heads and the interrupt queue heads at the control
|
|
|
|
* queue head and point the physical frame list to the virtual.
|
|
|
|
*/
|
2016-03-13 10:01:43 +03:00
|
|
|
for (i = 0; i < UHCI_VFRAMELIST_COUNT; i++) {
|
1998-07-12 23:51:55 +04:00
|
|
|
std = uhci_alloc_std(sc);
|
|
|
|
sqh = uhci_alloc_sqh(sc);
|
1999-11-19 02:32:25 +03:00
|
|
|
if (std == NULL || sqh == NULL)
|
2016-04-23 13:15:27 +03:00
|
|
|
return USBD_NOMEM;
|
1999-08-23 03:19:56 +04:00
|
|
|
std->link.sqh = sqh;
|
2000-07-23 23:43:37 +04:00
|
|
|
std->td.td_link = htole32(sqh->physaddr | UHCI_PTR_QH);
|
2000-03-16 15:40:51 +03:00
|
|
|
std->td.td_status = htole32(UHCI_TD_IOS); /* iso, inactive */
|
|
|
|
std->td.td_token = htole32(0);
|
|
|
|
std->td.td_buffer = htole32(0);
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&std->dma, std->offs, sizeof(std->td),
|
|
|
|
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
|
2000-08-13 20:18:09 +04:00
|
|
|
sqh->hlink = clsqh;
|
|
|
|
sqh->qh.qh_hlink = htole32(clsqh->physaddr | UHCI_PTR_QH);
|
2000-07-23 23:43:37 +04:00
|
|
|
sqh->elink = NULL;
|
2000-03-16 15:40:51 +03:00
|
|
|
sqh->qh.qh_elink = htole32(UHCI_PTR_T);
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh),
|
|
|
|
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
|
1998-07-12 23:51:55 +04:00
|
|
|
sc->sc_vframes[i].htd = std;
|
|
|
|
sc->sc_vframes[i].etd = std;
|
|
|
|
sc->sc_vframes[i].hqh = sqh;
|
|
|
|
sc->sc_vframes[i].eqh = sqh;
|
2002-02-03 21:15:20 +03:00
|
|
|
for (j = i;
|
|
|
|
j < UHCI_FRAMELIST_COUNT;
|
1998-07-12 23:51:55 +04:00
|
|
|
j += UHCI_VFRAMELIST_COUNT)
|
2000-03-16 15:40:51 +03:00
|
|
|
sc->sc_pframes[j] = htole32(std->physaddr);
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&sc->sc_dma, 0,
|
|
|
|
UHCI_FRAMELIST_COUNT * sizeof(uhci_physaddr_t),
|
|
|
|
BUS_DMASYNC_PREWRITE);
|
|
|
|
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
TAILQ_INIT(&sc->sc_intrhead);
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2013-01-29 04:00:15 +04:00
|
|
|
sc->sc_xferpool = pool_cache_init(sizeof(struct uhci_xfer), 0, 0, 0,
|
|
|
|
"uhcixfer", NULL, IPL_USB, NULL, NULL, NULL);
|
2000-01-18 23:11:00 +03:00
|
|
|
|
2012-06-10 10:15:52 +04:00
|
|
|
callout_init(&sc->sc_poll_handle, CALLOUT_MPSAFE);
|
Fix steady state of root intr xfers.
Why?
- Avoid completing a root intr xfer multiple times in races.
- Avoid potential use-after-free in poll_hub callouts (uhci, ahci).
How?
- Use sc->sc_intr_xfer or equivalent to store only a pending xfer
that has not yet completed -- whether successfully, by timeout, or
by synchronous abort. When any of those happens, set it to null
under the lock, so the xfer is completed only once.
- For hci drivers that use a callout to poll the root hub (uhci, ahci):
. Pass the softc pointer, not the xfer, to the callout, so the
callout is not even tempted to use xfer after free -- if the
callout fires, but the xfer is synchronously aborted before the
callout can do anything, the xfer might be freed by the time the
callout starts to examine it.
. Teach the callout to do nothing if it is callout_pending after it
has fired. This way:
1. completion or synchronous abort can just callout_stop
2. start can just callout_schedule
If the callout had already fired before (1), and doesn't acquire
the bus lock until after (2), it may be tempted to abort the new
root intr xfer just after submission, which would be wrong -- so
instead we just have the callout do nothing if it notices it has
been rescheduled, since it will fire again after the appropriate
time has elapsed.
2020-02-12 19:02:01 +03:00
|
|
|
callout_setfunc(&sc->sc_poll_handle, uhci_poll_hub, sc);
|
2012-06-10 10:15:52 +04:00
|
|
|
|
1998-07-12 23:51:55 +04:00
|
|
|
/* Set up the bus struct. */
|
2016-04-23 13:15:27 +03:00
|
|
|
sc->sc_bus.ub_methods = &uhci_bus_methods;
|
|
|
|
sc->sc_bus.ub_pipesize = sizeof(struct uhci_pipe);
|
|
|
|
sc->sc_bus.ub_usedma = true;
|
2020-05-25 16:55:31 +03:00
|
|
|
sc->sc_bus.ub_dmaflags = USBMALLOC_MULTISEG;
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2005-07-18 15:08:00 +04:00
|
|
|
UHCICMD(sc, UHCI_CMD_MAXP); /* Assume 64 byte packets at frame end */
|
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
DPRINTF("Enabling...", 0, 0, 0, 0);
|
2009-03-07 02:40:50 +03:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
err = uhci_run(sc, 1, 0); /* and here we go... */
|
2002-02-03 21:15:20 +03:00
|
|
|
UWRITE2(sc, UHCI_INTR, UHCI_INTR_TOCRCIE | UHCI_INTR_RIE |
|
1998-07-12 23:51:55 +04:00
|
|
|
UHCI_INTR_IOCE | UHCI_INTR_SPIE); /* enable interrupts */
|
2009-03-07 02:40:50 +03:00
|
|
|
return err;
|
2016-04-23 13:15:27 +03:00
|
|
|
|
|
|
|
fail4:
|
|
|
|
uhci_free_sqh(sc, chsqh);
|
|
|
|
fail3:
|
|
|
|
uhci_free_sqh(sc, lsqh);
|
|
|
|
fail2:
|
|
|
|
uhci_free_sqh(sc, lsqh);
|
|
|
|
fail1:
|
|
|
|
uhci_free_std(sc, std);
|
|
|
|
|
|
|
|
return ENOMEM;
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
|
1999-09-15 14:25:30 +04:00
|
|
|
int
|
2008-02-23 02:04:52 +03:00
|
|
|
uhci_activate(device_t self, enum devact act)
|
1999-09-15 14:25:30 +04:00
|
|
|
{
|
2008-02-23 02:04:52 +03:00
|
|
|
struct uhci_softc *sc = device_private(self);
|
1999-09-15 14:25:30 +04:00
|
|
|
|
|
|
|
switch (act) {
|
|
|
|
case DVACT_DEACTIVATE:
|
2007-08-15 08:00:33 +04:00
|
|
|
sc->sc_dying = 1;
|
2009-11-12 22:53:56 +03:00
|
|
|
return 0;
|
|
|
|
default:
|
|
|
|
return EOPNOTSUPP;
|
1999-09-15 14:25:30 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-02-23 02:04:52 +03:00
|
|
|
void
|
|
|
|
uhci_childdet(device_t self, device_t child)
|
|
|
|
{
|
|
|
|
struct uhci_softc *sc = device_private(self);
|
|
|
|
|
|
|
|
KASSERT(sc->sc_child == child);
|
|
|
|
sc->sc_child = NULL;
|
|
|
|
}
|
|
|
|
|
1999-09-15 14:25:30 +04:00
|
|
|
int
|
2000-06-01 18:28:57 +04:00
|
|
|
uhci_detach(struct uhci_softc *sc, int flags)
|
1999-09-15 14:25:30 +04:00
|
|
|
{
|
|
|
|
int rv = 0;
|
|
|
|
|
|
|
|
if (sc->sc_child != NULL)
|
|
|
|
rv = config_detach(sc->sc_child, flags);
|
2002-02-03 21:15:20 +03:00
|
|
|
|
1999-09-15 14:25:30 +04:00
|
|
|
if (rv != 0)
|
2016-04-23 13:15:27 +03:00
|
|
|
return rv;
|
1999-09-15 14:25:30 +04:00
|
|
|
|
2009-04-19 16:32:52 +04:00
|
|
|
callout_halt(&sc->sc_poll_handle, NULL);
|
|
|
|
callout_destroy(&sc->sc_poll_handle);
|
|
|
|
|
2012-06-10 10:15:52 +04:00
|
|
|
mutex_destroy(&sc->sc_lock);
|
|
|
|
mutex_destroy(&sc->sc_intr_lock);
|
|
|
|
|
2013-01-29 23:27:36 +04:00
|
|
|
pool_cache_destroy(sc->sc_xferpool);
|
|
|
|
|
2000-01-18 23:11:00 +03:00
|
|
|
/* XXX free other data structures XXX */
|
1999-09-15 14:25:30 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
return rv;
|
1999-09-09 16:26:43 +04:00
|
|
|
}
|
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
struct usbd_xfer *
|
|
|
|
uhci_allocx(struct usbd_bus *bus, unsigned int nframes)
|
2000-01-18 23:11:00 +03:00
|
|
|
{
|
2016-04-23 13:15:27 +03:00
|
|
|
struct uhci_softc *sc = UHCI_BUS2SC(bus);
|
|
|
|
struct usbd_xfer *xfer;
|
2000-01-18 23:11:00 +03:00
|
|
|
|
2017-11-17 11:22:02 +03:00
|
|
|
xfer = pool_cache_get(sc->sc_xferpool, PR_WAITOK);
|
2000-03-25 01:57:58 +03:00
|
|
|
if (xfer != NULL) {
|
2013-01-29 04:00:15 +04:00
|
|
|
memset(xfer, 0, sizeof(struct uhci_xfer));
|
2016-04-23 13:15:27 +03:00
|
|
|
|
2000-03-25 01:57:58 +03:00
|
|
|
#ifdef DIAGNOSTIC
|
2016-04-23 13:15:27 +03:00
|
|
|
struct uhci_xfer *uxfer = UHCI_XFER2UXFER(xfer);
|
|
|
|
uxfer->ux_isdone = true;
|
|
|
|
xfer->ux_state = XFER_BUSY;
|
2000-03-25 01:57:58 +03:00
|
|
|
#endif
|
|
|
|
}
|
2016-04-23 13:15:27 +03:00
|
|
|
return xfer;
|
2000-01-18 23:11:00 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_freex(struct usbd_bus *bus, struct usbd_xfer *xfer)
|
2000-01-18 23:11:00 +03:00
|
|
|
{
|
2016-04-23 13:15:27 +03:00
|
|
|
struct uhci_softc *sc = UHCI_BUS2SC(bus);
|
|
|
|
struct uhci_xfer *uxfer __diagused = UHCI_XFER2UXFER(xfer);
|
2000-01-18 23:11:00 +03:00
|
|
|
|
2019-02-17 07:17:52 +03:00
|
|
|
KASSERTMSG(xfer->ux_state == XFER_BUSY ||
|
|
|
|
xfer->ux_status == USBD_NOT_STARTED,
|
|
|
|
"xfer %p state %d\n", xfer, xfer->ux_state);
|
|
|
|
KASSERTMSG(uxfer->ux_isdone || xfer->ux_status == USBD_NOT_STARTED,
|
|
|
|
"xfer %p not done\n", xfer);
|
2000-03-25 03:11:21 +03:00
|
|
|
#ifdef DIAGNOSTIC
|
2016-04-23 13:15:27 +03:00
|
|
|
xfer->ux_state = XFER_FREE;
|
2000-03-25 03:11:21 +03:00
|
|
|
#endif
|
2013-01-29 04:00:15 +04:00
|
|
|
pool_cache_put(sc->sc_xferpool, xfer);
|
2000-01-18 23:11:00 +03:00
|
|
|
}
|
|
|
|
|
2020-02-12 19:01:00 +03:00
|
|
|
Static bool
|
|
|
|
uhci_dying(struct usbd_bus *bus)
|
|
|
|
{
|
|
|
|
struct uhci_softc *sc = UHCI_BUS2SC(bus);
|
|
|
|
|
|
|
|
return sc->sc_dying;
|
|
|
|
}
|
|
|
|
|
2012-06-10 10:15:52 +04:00
|
|
|
Static void
|
|
|
|
uhci_get_lock(struct usbd_bus *bus, kmutex_t **lock)
|
|
|
|
{
|
2016-04-23 13:15:27 +03:00
|
|
|
struct uhci_softc *sc = UHCI_BUS2SC(bus);
|
2012-06-10 10:15:52 +04:00
|
|
|
|
|
|
|
*lock = &sc->sc_lock;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-01-16 13:27:51 +03:00
|
|
|
/*
|
2007-12-09 23:27:42 +03:00
|
|
|
* Handle suspend/resume.
|
|
|
|
*
|
|
|
|
* We need to switch to polling mode here, because this routine is
|
|
|
|
* called from an interrupt context. This is all right since we
|
|
|
|
* are almost suspended anyway.
|
2000-01-16 13:27:51 +03:00
|
|
|
*/
|
2007-12-09 23:27:42 +03:00
|
|
|
bool
|
2010-02-25 01:37:54 +03:00
|
|
|
uhci_resume(device_t dv, const pmf_qual_t *qual)
|
2000-01-16 13:27:51 +03:00
|
|
|
{
|
2007-12-09 23:27:42 +03:00
|
|
|
uhci_softc_t *sc = device_private(dv);
|
|
|
|
int cmd;
|
2000-01-16 13:27:51 +03:00
|
|
|
|
2012-06-10 10:15:52 +04:00
|
|
|
mutex_spin_enter(&sc->sc_intr_lock);
|
2007-12-09 23:27:42 +03:00
|
|
|
|
|
|
|
cmd = UREAD2(sc, UHCI_CMD);
|
2016-04-23 13:15:27 +03:00
|
|
|
sc->sc_bus.ub_usepolling++;
|
2008-02-13 03:52:44 +03:00
|
|
|
UWRITE2(sc, UHCI_INTR, 0);
|
|
|
|
uhci_globalreset(sc);
|
|
|
|
uhci_reset(sc);
|
2007-12-09 23:27:42 +03:00
|
|
|
if (cmd & UHCI_CMD_RS)
|
2012-06-24 14:06:34 +04:00
|
|
|
uhci_run(sc, 0, 1);
|
2007-12-09 23:27:42 +03:00
|
|
|
|
|
|
|
/* restore saved state */
|
|
|
|
UWRITE4(sc, UHCI_FLBASEADDR, DMAADDR(&sc->sc_dma, 0));
|
|
|
|
UWRITE2(sc, UHCI_FRNUM, sc->sc_saved_frnum);
|
|
|
|
UWRITE1(sc, UHCI_SOF, sc->sc_saved_sof);
|
|
|
|
|
|
|
|
UHCICMD(sc, cmd | UHCI_CMD_FGR); /* force resume */
|
2012-06-10 10:15:52 +04:00
|
|
|
usb_delay_ms_locked(&sc->sc_bus, USB_RESUME_DELAY, &sc->sc_intr_lock);
|
2007-12-09 23:27:42 +03:00
|
|
|
UHCICMD(sc, cmd & ~UHCI_CMD_EGSM); /* back to normal */
|
|
|
|
UWRITE2(sc, UHCI_INTR, UHCI_INTR_TOCRCIE |
|
|
|
|
UHCI_INTR_RIE | UHCI_INTR_IOCE | UHCI_INTR_SPIE);
|
2008-02-13 03:52:44 +03:00
|
|
|
UHCICMD(sc, UHCI_CMD_MAXP);
|
2012-06-24 14:06:34 +04:00
|
|
|
uhci_run(sc, 1, 1); /* and start traffic again */
|
2012-06-10 10:15:52 +04:00
|
|
|
usb_delay_ms_locked(&sc->sc_bus, USB_RESUME_RECOVERY, &sc->sc_intr_lock);
|
2016-04-23 13:15:27 +03:00
|
|
|
sc->sc_bus.ub_usepolling--;
|
2007-12-09 23:27:42 +03:00
|
|
|
if (sc->sc_intr_xfer != NULL)
|
Fix steady state of root intr xfers.
Why?
- Avoid completing a root intr xfer multiple times in races.
- Avoid potential use-after-free in poll_hub callouts (uhci, ahci).
How?
- Use sc->sc_intr_xfer or equivalent to store only a pending xfer
that has not yet completed -- whether successfully, by timeout, or
by synchronous abort. When any of those happens, set it to null
under the lock, so the xfer is completed only once.
- For hci drivers that use a callout to poll the root hub (uhci, ahci):
. Pass the softc pointer, not the xfer, to the callout, so the
callout is not even tempted to use xfer after free -- if the
callout fires, but the xfer is synchronously aborted before the
callout can do anything, the xfer might be freed by the time the
callout starts to examine it.
. Teach the callout to do nothing if it is callout_pending after it
has fired. This way:
1. completion or synchronous abort can just callout_stop
2. start can just callout_schedule
If the callout had already fired before (1), and doesn't acquire
the bus lock until after (2), it may be tempted to abort the new
root intr xfer just after submission, which would be wrong -- so
instead we just have the callout do nothing if it notices it has
been rescheduled, since it will fire again after the appropriate
time has elapsed.
2020-02-12 19:02:01 +03:00
|
|
|
callout_schedule(&sc->sc_poll_handle, sc->sc_ival);
|
2007-12-09 23:27:42 +03:00
|
|
|
#ifdef UHCI_DEBUG
|
2016-04-23 13:15:27 +03:00
|
|
|
if (uhcidebug >= 2)
|
2007-12-09 23:27:42 +03:00
|
|
|
uhci_dumpregs(sc);
|
|
|
|
#endif
|
|
|
|
|
2008-06-02 05:02:21 +04:00
|
|
|
sc->sc_suspend = PWR_RESUME;
|
2012-06-10 10:15:52 +04:00
|
|
|
mutex_spin_exit(&sc->sc_intr_lock);
|
2007-12-09 23:27:42 +03:00
|
|
|
|
|
|
|
return true;
|
2000-01-16 13:27:51 +03:00
|
|
|
}
|
|
|
|
|
2007-12-09 23:27:42 +03:00
|
|
|
bool
|
2010-02-25 01:37:54 +03:00
|
|
|
uhci_suspend(device_t dv, const pmf_qual_t *qual)
|
1999-06-26 12:30:17 +04:00
|
|
|
{
|
2007-12-09 23:27:42 +03:00
|
|
|
uhci_softc_t *sc = device_private(dv);
|
1999-06-26 12:30:17 +04:00
|
|
|
int cmd;
|
|
|
|
|
2012-06-10 10:15:52 +04:00
|
|
|
mutex_spin_enter(&sc->sc_intr_lock);
|
1999-06-26 12:30:17 +04:00
|
|
|
|
2007-12-09 23:27:42 +03:00
|
|
|
cmd = UREAD2(sc, UHCI_CMD);
|
1999-06-26 12:30:17 +04:00
|
|
|
|
1999-11-19 02:32:25 +03:00
|
|
|
#ifdef UHCI_DEBUG
|
2016-04-23 13:15:27 +03:00
|
|
|
if (uhcidebug >= 2)
|
2007-12-09 23:27:42 +03:00
|
|
|
uhci_dumpregs(sc);
|
1999-06-26 12:30:17 +04:00
|
|
|
#endif
|
2008-06-02 05:02:21 +04:00
|
|
|
sc->sc_suspend = PWR_SUSPEND;
|
Fix steady state of root intr xfers.
Why?
- Avoid completing a root intr xfer multiple times in races.
- Avoid potential use-after-free in poll_hub callouts (uhci, ahci).
How?
- Use sc->sc_intr_xfer or equivalent to store only a pending xfer
that has not yet completed -- whether successfully, by timeout, or
by synchronous abort. When any of those happens, set it to null
under the lock, so the xfer is completed only once.
- For hci drivers that use a callout to poll the root hub (uhci, ahci):
. Pass the softc pointer, not the xfer, to the callout, so the
callout is not even tempted to use xfer after free -- if the
callout fires, but the xfer is synchronously aborted before the
callout can do anything, the xfer might be freed by the time the
callout starts to examine it.
. Teach the callout to do nothing if it is callout_pending after it
has fired. This way:
1. completion or synchronous abort can just callout_stop
2. start can just callout_schedule
If the callout had already fired before (1), and doesn't acquire
the bus lock until after (2), it may be tempted to abort the new
root intr xfer just after submission, which would be wrong -- so
instead we just have the callout do nothing if it notices it has
been rescheduled, since it will fire again after the appropriate
time has elapsed.
2020-02-12 19:02:01 +03:00
|
|
|
if (sc->sc_intr_xfer != NULL)
|
|
|
|
callout_halt(&sc->sc_poll_handle, &sc->sc_intr_lock);
|
2016-04-23 13:15:27 +03:00
|
|
|
sc->sc_bus.ub_usepolling++;
|
2008-06-02 05:02:21 +04:00
|
|
|
|
2012-06-24 14:06:34 +04:00
|
|
|
uhci_run(sc, 0, 1); /* stop the controller */
|
2007-12-09 23:27:42 +03:00
|
|
|
cmd &= ~UHCI_CMD_RS;
|
|
|
|
|
|
|
|
/* save some state if BIOS doesn't */
|
|
|
|
sc->sc_saved_frnum = UREAD2(sc, UHCI_FRNUM);
|
|
|
|
sc->sc_saved_sof = UREAD1(sc, UHCI_SOF);
|
|
|
|
|
|
|
|
UWRITE2(sc, UHCI_INTR, 0); /* disable intrs */
|
|
|
|
|
|
|
|
UHCICMD(sc, cmd | UHCI_CMD_EGSM); /* enter suspend */
|
2012-06-10 10:15:52 +04:00
|
|
|
usb_delay_ms_locked(&sc->sc_bus, USB_RESUME_WAIT, &sc->sc_intr_lock);
|
2016-04-23 13:15:27 +03:00
|
|
|
sc->sc_bus.ub_usepolling--;
|
2007-12-09 23:27:42 +03:00
|
|
|
|
2012-06-10 10:15:52 +04:00
|
|
|
mutex_spin_exit(&sc->sc_intr_lock);
|
2007-12-09 23:27:42 +03:00
|
|
|
|
|
|
|
return true;
|
1999-06-26 12:30:17 +04:00
|
|
|
}
|
|
|
|
|
1999-10-13 12:10:55 +04:00
|
|
|
#ifdef UHCI_DEBUG
|
2000-03-27 16:33:53 +04:00
|
|
|
Static void
|
2000-06-01 18:28:57 +04:00
|
|
|
uhci_dumpregs(uhci_softc_t *sc)
|
1998-07-12 23:51:55 +04:00
|
|
|
{
|
2016-04-23 13:15:27 +03:00
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTF("cmd =%04jx sts =%04jx intr =%04jx frnum =%04jx",
|
2016-04-23 13:15:27 +03:00
|
|
|
UREAD2(sc, UHCI_CMD), UREAD2(sc, UHCI_STS),
|
|
|
|
UREAD2(sc, UHCI_INTR), UREAD2(sc, UHCI_FRNUM));
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTF("sof =%04jx portsc1=%04jx portsc2=%04jx flbase=%08jx",
|
2016-04-23 13:15:27 +03:00
|
|
|
UREAD1(sc, UHCI_SOF), UREAD2(sc, UHCI_PORTSC1),
|
|
|
|
UREAD2(sc, UHCI_PORTSC2), UREAD4(sc, UHCI_FLBASEADDR));
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2000-06-01 18:28:57 +04:00
|
|
|
uhci_dump_td(uhci_soft_td_t *p)
|
1998-07-12 23:51:55 +04:00
|
|
|
{
|
2016-04-23 13:15:27 +03:00
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
2013-01-05 05:30:15 +04:00
|
|
|
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&p->dma, p->offs, sizeof(p->td),
|
|
|
|
BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
|
2016-04-23 13:15:27 +03:00
|
|
|
|
2020-03-14 05:35:33 +03:00
|
|
|
DPRINTF("TD(%#jx) at 0x%08jx", (uintptr_t)p, p->physaddr, 0, 0);
|
|
|
|
DPRINTF(" link=0x%08jx status=0x%08jx "
|
|
|
|
"token=0x%08x buffer=0x%08x",
|
2016-04-23 13:15:27 +03:00
|
|
|
le32toh(p->td.td_link),
|
|
|
|
le32toh(p->td.td_status),
|
|
|
|
le32toh(p->td.td_token),
|
|
|
|
le32toh(p->td.td_buffer));
|
|
|
|
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTF("bitstuff=%jd crcto =%jd nak =%jd babble =%jd",
|
2016-04-23 13:15:27 +03:00
|
|
|
!!(le32toh(p->td.td_status) & UHCI_TD_BITSTUFF),
|
|
|
|
!!(le32toh(p->td.td_status) & UHCI_TD_CRCTO),
|
|
|
|
!!(le32toh(p->td.td_status) & UHCI_TD_NAK),
|
|
|
|
!!(le32toh(p->td.td_status) & UHCI_TD_BABBLE));
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTF("dbuffer =%jd stalled =%jd active =%jd ioc =%jd",
|
2016-04-23 13:15:27 +03:00
|
|
|
!!(le32toh(p->td.td_status) & UHCI_TD_DBUFFER),
|
|
|
|
!!(le32toh(p->td.td_status) & UHCI_TD_STALLED),
|
|
|
|
!!(le32toh(p->td.td_status) & UHCI_TD_ACTIVE),
|
|
|
|
!!(le32toh(p->td.td_status) & UHCI_TD_IOC));
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTF("ios =%jd ls =%jd spd =%jd",
|
2016-04-23 13:15:27 +03:00
|
|
|
!!(le32toh(p->td.td_status) & UHCI_TD_IOS),
|
|
|
|
!!(le32toh(p->td.td_status) & UHCI_TD_LS),
|
|
|
|
!!(le32toh(p->td.td_status) & UHCI_TD_SPD), 0);
|
|
|
|
DPRINTF("errcnt =%d actlen =%d pid=%02x",
|
|
|
|
UHCI_TD_GET_ERRCNT(le32toh(p->td.td_status)),
|
|
|
|
UHCI_TD_GET_ACTLEN(le32toh(p->td.td_status)),
|
|
|
|
UHCI_TD_GET_PID(le32toh(p->td.td_token)), 0);
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTF("addr=%jd endpt=%jd D=%jd maxlen=%jd,",
|
2016-04-23 13:15:27 +03:00
|
|
|
UHCI_TD_GET_DEVADDR(le32toh(p->td.td_token)),
|
|
|
|
UHCI_TD_GET_ENDPT(le32toh(p->td.td_token)),
|
|
|
|
UHCI_TD_GET_DT(le32toh(p->td.td_token)),
|
|
|
|
UHCI_TD_GET_MAXLEN(le32toh(p->td.td_token)));
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2000-06-01 18:28:57 +04:00
|
|
|
uhci_dump_qh(uhci_soft_qh_t *sqh)
|
1998-07-12 23:51:55 +04:00
|
|
|
{
|
2016-04-23 13:15:27 +03:00
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
|
|
|
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh),
|
|
|
|
BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
|
2016-04-23 13:15:27 +03:00
|
|
|
|
2020-03-14 05:35:33 +03:00
|
|
|
DPRINTF("QH(%#jx) at 0x%08jx: hlink=%08jx elink=%08jx", (uintptr_t)sqh,
|
2000-03-16 15:40:51 +03:00
|
|
|
(int)sqh->physaddr, le32toh(sqh->qh.qh_hlink),
|
2016-04-23 13:15:27 +03:00
|
|
|
le32toh(sqh->qh.qh_elink));
|
|
|
|
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), BUS_DMASYNC_PREREAD);
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
|
1998-12-26 15:53:00 +03:00
|
|
|
|
2000-04-14 18:11:36 +04:00
|
|
|
#if 1
|
1998-07-12 23:51:55 +04:00
|
|
|
void
|
2000-06-01 18:28:57 +04:00
|
|
|
uhci_dump(void)
|
1998-07-12 23:51:55 +04:00
|
|
|
{
|
2000-04-14 18:11:36 +04:00
|
|
|
uhci_dump_all(thesc);
|
|
|
|
}
|
|
|
|
#endif
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2000-04-14 18:11:36 +04:00
|
|
|
void
|
2000-06-01 18:28:57 +04:00
|
|
|
uhci_dump_all(uhci_softc_t *sc)
|
2000-04-14 18:11:36 +04:00
|
|
|
{
|
1998-07-12 23:51:55 +04:00
|
|
|
uhci_dumpregs(sc);
|
2000-04-14 18:11:36 +04:00
|
|
|
/*printf("framelist[i].link = %08x\n", sc->sc_framelist[0].link);*/
|
2013-09-29 11:28:20 +04:00
|
|
|
uhci_dump_qhs(sc->sc_lctl_start);
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
|
1999-11-19 02:32:25 +03:00
|
|
|
|
|
|
|
void
|
2000-06-01 18:28:57 +04:00
|
|
|
uhci_dump_qhs(uhci_soft_qh_t *sqh)
|
1999-11-19 02:32:25 +03:00
|
|
|
{
|
2016-04-23 13:15:27 +03:00
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
|
|
|
|
1999-11-19 02:32:25 +03:00
|
|
|
uhci_dump_qh(sqh);
|
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
/*
|
|
|
|
* uhci_dump_qhs displays all the QHs and TDs from the given QH onwards
|
1999-11-19 02:32:25 +03:00
|
|
|
* Traverses sideways first, then down.
|
|
|
|
*
|
|
|
|
* QH1
|
|
|
|
* QH2
|
|
|
|
* No QH
|
|
|
|
* TD2.1
|
|
|
|
* TD2.2
|
|
|
|
* TD1.1
|
|
|
|
* etc.
|
|
|
|
*
|
|
|
|
* TD2.x being the TDs queued at QH2 and QH1 being referenced from QH1.
|
|
|
|
*/
|
|
|
|
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh),
|
|
|
|
BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
|
2000-03-16 15:40:51 +03:00
|
|
|
if (sqh->hlink != NULL && !(le32toh(sqh->qh.qh_hlink) & UHCI_PTR_T))
|
1999-11-19 02:32:25 +03:00
|
|
|
uhci_dump_qhs(sqh->hlink);
|
|
|
|
else
|
2016-04-23 13:15:27 +03:00
|
|
|
DPRINTF("No QH", 0, 0, 0, 0);
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), BUS_DMASYNC_PREREAD);
|
1999-11-19 02:32:25 +03:00
|
|
|
|
2000-03-16 15:40:51 +03:00
|
|
|
if (sqh->elink != NULL && !(le32toh(sqh->qh.qh_elink) & UHCI_PTR_T))
|
1999-11-19 02:32:25 +03:00
|
|
|
uhci_dump_tds(sqh->elink);
|
|
|
|
else
|
2016-04-23 13:15:27 +03:00
|
|
|
DPRINTF("No QH", 0, 0, 0, 0);
|
1999-11-19 02:32:25 +03:00
|
|
|
}
|
|
|
|
|
1998-07-12 23:51:55 +04:00
|
|
|
void
|
2000-06-01 18:28:57 +04:00
|
|
|
uhci_dump_tds(uhci_soft_td_t *std)
|
1998-07-12 23:51:55 +04:00
|
|
|
{
|
1999-11-19 02:32:25 +03:00
|
|
|
uhci_soft_td_t *td;
|
2008-06-28 21:42:53 +04:00
|
|
|
int stop;
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2016-03-13 10:01:43 +03:00
|
|
|
for (td = std; td != NULL; td = td->link.std) {
|
1999-11-19 02:32:25 +03:00
|
|
|
uhci_dump_td(td);
|
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
/*
|
|
|
|
* Check whether the link pointer in this TD marks
|
1999-11-19 02:32:25 +03:00
|
|
|
* the link pointer as end of queue. This avoids
|
|
|
|
* printing the free list in case the queue/TD has
|
|
|
|
* already been moved there (seatbelt).
|
|
|
|
*/
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&td->dma, td->offs + offsetof(uhci_td_t, td_link),
|
|
|
|
sizeof(td->td.td_link),
|
|
|
|
BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
|
|
|
|
stop = (le32toh(td->td.td_link) & UHCI_PTR_T ||
|
|
|
|
le32toh(td->td.td_link) == 0);
|
|
|
|
usb_syncmem(&td->dma, td->offs + offsetof(uhci_td_t, td_link),
|
|
|
|
sizeof(td->td.td_link), BUS_DMASYNC_PREREAD);
|
|
|
|
if (stop)
|
1999-11-19 02:32:25 +03:00
|
|
|
break;
|
|
|
|
}
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
2000-03-25 01:57:58 +03:00
|
|
|
|
2000-03-27 16:33:53 +04:00
|
|
|
Static void
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_dump_ii(struct uhci_xfer *ux)
|
2000-03-25 01:57:58 +03:00
|
|
|
{
|
2016-04-23 13:15:27 +03:00
|
|
|
struct usbd_pipe *pipe;
|
2000-03-25 10:23:12 +03:00
|
|
|
usb_endpoint_descriptor_t *ed;
|
2016-04-23 13:15:27 +03:00
|
|
|
struct usbd_device *dev;
|
2002-02-03 21:15:20 +03:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
if (ux == NULL) {
|
|
|
|
printf("ux NULL\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
pipe = ux->ux_xfer.ux_pipe;
|
|
|
|
if (pipe == NULL) {
|
|
|
|
printf("ux %p: done=%d pipe=NULL\n", ux, ux->ux_isdone);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (pipe->up_endpoint == NULL) {
|
|
|
|
printf("ux %p: done=%d pipe=%p pipe->up_endpoint=NULL\n",
|
|
|
|
ux, ux->ux_isdone, pipe);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (pipe->up_dev == NULL) {
|
|
|
|
printf("ux %p: done=%d pipe=%p pipe->up_dev=NULL\n",
|
|
|
|
ux, ux->ux_isdone, pipe);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ed = pipe->up_endpoint->ue_edesc;
|
|
|
|
dev = pipe->up_dev;
|
2020-03-14 05:35:33 +03:00
|
|
|
printf("ux %p: done=%d dev=%p vid=0x%04x pid=0x%04x addr=%d pipe=%p ep=0x%02x attr=0x%02x\n",
|
2016-04-23 13:15:27 +03:00
|
|
|
ux, ux->ux_isdone, dev,
|
|
|
|
UGETW(dev->ud_ddesc.idVendor),
|
|
|
|
UGETW(dev->ud_ddesc.idProduct),
|
|
|
|
dev->ud_addr, pipe,
|
2000-03-25 01:57:58 +03:00
|
|
|
ed->bEndpointAddress, ed->bmAttributes);
|
|
|
|
}
|
|
|
|
|
2000-06-01 19:51:26 +04:00
|
|
|
void uhci_dump_iis(struct uhci_softc *sc);
|
2000-03-25 01:57:58 +03:00
|
|
|
void
|
2000-06-01 18:28:57 +04:00
|
|
|
uhci_dump_iis(struct uhci_softc *sc)
|
2000-03-25 01:57:58 +03:00
|
|
|
{
|
2016-04-23 13:15:27 +03:00
|
|
|
struct uhci_xfer *ux;
|
2000-03-25 01:57:58 +03:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
printf("interrupt list:\n");
|
|
|
|
TAILQ_FOREACH(ux, &sc->sc_intrhead, ux_list)
|
|
|
|
uhci_dump_ii(ux);
|
2000-03-25 01:57:58 +03:00
|
|
|
}
|
|
|
|
|
2000-06-01 19:51:26 +04:00
|
|
|
void iidump(void);
|
2000-06-01 18:28:57 +04:00
|
|
|
void iidump(void) { uhci_dump_iis(thesc); }
|
2000-03-25 01:57:58 +03:00
|
|
|
|
1998-07-12 23:51:55 +04:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This routine is executed periodically and simulates interrupts
|
|
|
|
* from the root controller interrupt pipe for port status change.
|
|
|
|
*/
|
|
|
|
void
|
2000-06-01 18:28:57 +04:00
|
|
|
uhci_poll_hub(void *addr)
|
1998-07-12 23:51:55 +04:00
|
|
|
{
|
Fix steady state of root intr xfers.
Why?
- Avoid completing a root intr xfer multiple times in races.
- Avoid potential use-after-free in poll_hub callouts (uhci, ahci).
How?
- Use sc->sc_intr_xfer or equivalent to store only a pending xfer
that has not yet completed -- whether successfully, by timeout, or
by synchronous abort. When any of those happens, set it to null
under the lock, so the xfer is completed only once.
- For hci drivers that use a callout to poll the root hub (uhci, ahci):
. Pass the softc pointer, not the xfer, to the callout, so the
callout is not even tempted to use xfer after free -- if the
callout fires, but the xfer is synchronously aborted before the
callout can do anything, the xfer might be freed by the time the
callout starts to examine it.
. Teach the callout to do nothing if it is callout_pending after it
has fired. This way:
1. completion or synchronous abort can just callout_stop
2. start can just callout_schedule
If the callout had already fired before (1), and doesn't acquire
the bus lock until after (2), it may be tempted to abort the new
root intr xfer just after submission, which would be wrong -- so
instead we just have the callout do nothing if it notices it has
been rescheduled, since it will fire again after the appropriate
time has elapsed.
2020-02-12 19:02:01 +03:00
|
|
|
struct uhci_softc *sc = addr;
|
|
|
|
struct usbd_xfer *xfer;
|
1998-07-12 23:51:55 +04:00
|
|
|
u_char *p;
|
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
1998-07-12 23:51:55 +04:00
|
|
|
|
Fix steady state of root intr xfers.
Why?
- Avoid completing a root intr xfer multiple times in races.
- Avoid potential use-after-free in poll_hub callouts (uhci, ahci).
How?
- Use sc->sc_intr_xfer or equivalent to store only a pending xfer
that has not yet completed -- whether successfully, by timeout, or
by synchronous abort. When any of those happens, set it to null
under the lock, so the xfer is completed only once.
- For hci drivers that use a callout to poll the root hub (uhci, ahci):
. Pass the softc pointer, not the xfer, to the callout, so the
callout is not even tempted to use xfer after free -- if the
callout fires, but the xfer is synchronously aborted before the
callout can do anything, the xfer might be freed by the time the
callout starts to examine it.
. Teach the callout to do nothing if it is callout_pending after it
has fired. This way:
1. completion or synchronous abort can just callout_stop
2. start can just callout_schedule
If the callout had already fired before (1), and doesn't acquire
the bus lock until after (2), it may be tempted to abort the new
root intr xfer just after submission, which would be wrong -- so
instead we just have the callout do nothing if it notices it has
been rescheduled, since it will fire again after the appropriate
time has elapsed.
2020-02-12 19:02:01 +03:00
|
|
|
mutex_enter(&sc->sc_lock);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the intr xfer has completed or been synchronously
|
|
|
|
* aborted, we have nothing to do.
|
|
|
|
*/
|
|
|
|
xfer = sc->sc_intr_xfer;
|
|
|
|
if (xfer == NULL)
|
|
|
|
goto out;
|
2020-02-15 04:21:56 +03:00
|
|
|
KASSERT(xfer->ux_status == USBD_IN_PROGRESS);
|
Fix steady state of root intr xfers.
Why?
- Avoid completing a root intr xfer multiple times in races.
- Avoid potential use-after-free in poll_hub callouts (uhci, ahci).
How?
- Use sc->sc_intr_xfer or equivalent to store only a pending xfer
that has not yet completed -- whether successfully, by timeout, or
by synchronous abort. When any of those happens, set it to null
under the lock, so the xfer is completed only once.
- For hci drivers that use a callout to poll the root hub (uhci, ahci):
. Pass the softc pointer, not the xfer, to the callout, so the
callout is not even tempted to use xfer after free -- if the
callout fires, but the xfer is synchronously aborted before the
callout can do anything, the xfer might be freed by the time the
callout starts to examine it.
. Teach the callout to do nothing if it is callout_pending after it
has fired. This way:
1. completion or synchronous abort can just callout_stop
2. start can just callout_schedule
If the callout had already fired before (1), and doesn't acquire
the bus lock until after (2), it may be tempted to abort the new
root intr xfer just after submission, which would be wrong -- so
instead we just have the callout do nothing if it notices it has
been rescheduled, since it will fire again after the appropriate
time has elapsed.
2020-02-12 19:02:01 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If the intr xfer for which we were scheduled is done, and
|
|
|
|
* another intr xfer has been submitted, let that one be dealt
|
|
|
|
* with when the callout fires again.
|
|
|
|
*
|
|
|
|
* The call to callout_pending is racy, but the the transition
|
|
|
|
* from pending to invoking happens atomically. The
|
|
|
|
* callout_ack ensures callout_invoking does not return true
|
|
|
|
* due to this invocation of the callout; the lock ensures the
|
|
|
|
* next invocation of the callout cannot callout_ack (unless it
|
|
|
|
* had already run to completion and nulled sc->sc_intr_xfer,
|
|
|
|
* in which case would have bailed out already).
|
|
|
|
*/
|
|
|
|
callout_ack(&sc->sc_poll_handle);
|
|
|
|
if (callout_pending(&sc->sc_poll_handle) ||
|
|
|
|
callout_invoking(&sc->sc_poll_handle))
|
|
|
|
goto out;
|
1999-08-23 00:12:39 +04:00
|
|
|
|
Fix steady state of root intr xfers.
Why?
- Avoid completing a root intr xfer multiple times in races.
- Avoid potential use-after-free in poll_hub callouts (uhci, ahci).
How?
- Use sc->sc_intr_xfer or equivalent to store only a pending xfer
that has not yet completed -- whether successfully, by timeout, or
by synchronous abort. When any of those happens, set it to null
under the lock, so the xfer is completed only once.
- For hci drivers that use a callout to poll the root hub (uhci, ahci):
. Pass the softc pointer, not the xfer, to the callout, so the
callout is not even tempted to use xfer after free -- if the
callout fires, but the xfer is synchronously aborted before the
callout can do anything, the xfer might be freed by the time the
callout starts to examine it.
. Teach the callout to do nothing if it is callout_pending after it
has fired. This way:
1. completion or synchronous abort can just callout_stop
2. start can just callout_schedule
If the callout had already fired before (1), and doesn't acquire
the bus lock until after (2), it may be tempted to abort the new
root intr xfer just after submission, which would be wrong -- so
instead we just have the callout do nothing if it notices it has
been rescheduled, since it will fire again after the appropriate
time has elapsed.
2020-02-12 19:02:01 +03:00
|
|
|
/*
|
|
|
|
* Check flags for the two interrupt ports, and set them in the
|
|
|
|
* buffer if an interrupt arrived; otherwise arrange .
|
|
|
|
*/
|
2016-04-23 13:15:27 +03:00
|
|
|
p = xfer->ux_buf;
|
1998-07-12 23:51:55 +04:00
|
|
|
p[0] = 0;
|
|
|
|
if (UREAD2(sc, UHCI_PORTSC1) & (UHCI_PORTSC_CSC|UHCI_PORTSC_OCIC))
|
|
|
|
p[0] |= 1<<1;
|
|
|
|
if (UREAD2(sc, UHCI_PORTSC2) & (UHCI_PORTSC_CSC|UHCI_PORTSC_OCIC))
|
|
|
|
p[0] |= 1<<2;
|
Fix steady state of root intr xfers.
Why?
- Avoid completing a root intr xfer multiple times in races.
- Avoid potential use-after-free in poll_hub callouts (uhci, ahci).
How?
- Use sc->sc_intr_xfer or equivalent to store only a pending xfer
that has not yet completed -- whether successfully, by timeout, or
by synchronous abort. When any of those happens, set it to null
under the lock, so the xfer is completed only once.
- For hci drivers that use a callout to poll the root hub (uhci, ahci):
. Pass the softc pointer, not the xfer, to the callout, so the
callout is not even tempted to use xfer after free -- if the
callout fires, but the xfer is synchronously aborted before the
callout can do anything, the xfer might be freed by the time the
callout starts to examine it.
. Teach the callout to do nothing if it is callout_pending after it
has fired. This way:
1. completion or synchronous abort can just callout_stop
2. start can just callout_schedule
If the callout had already fired before (1), and doesn't acquire
the bus lock until after (2), it may be tempted to abort the new
root intr xfer just after submission, which would be wrong -- so
instead we just have the callout do nothing if it notices it has
been rescheduled, since it will fire again after the appropriate
time has elapsed.
2020-02-12 19:02:01 +03:00
|
|
|
if (p[0] == 0) {
|
|
|
|
/*
|
|
|
|
* No change -- try again in a while, unless we're
|
|
|
|
* suspending, in which case we'll try again after
|
|
|
|
* resume.
|
|
|
|
*/
|
|
|
|
if (sc->sc_suspend != PWR_SUSPEND)
|
|
|
|
callout_schedule(&sc->sc_poll_handle, sc->sc_ival);
|
|
|
|
goto out;
|
|
|
|
}
|
1999-08-23 00:12:39 +04:00
|
|
|
|
Fix steady state of root intr xfers.
Why?
- Avoid completing a root intr xfer multiple times in races.
- Avoid potential use-after-free in poll_hub callouts (uhci, ahci).
How?
- Use sc->sc_intr_xfer or equivalent to store only a pending xfer
that has not yet completed -- whether successfully, by timeout, or
by synchronous abort. When any of those happens, set it to null
under the lock, so the xfer is completed only once.
- For hci drivers that use a callout to poll the root hub (uhci, ahci):
. Pass the softc pointer, not the xfer, to the callout, so the
callout is not even tempted to use xfer after free -- if the
callout fires, but the xfer is synchronously aborted before the
callout can do anything, the xfer might be freed by the time the
callout starts to examine it.
. Teach the callout to do nothing if it is callout_pending after it
has fired. This way:
1. completion or synchronous abort can just callout_stop
2. start can just callout_schedule
If the callout had already fired before (1), and doesn't acquire
the bus lock until after (2), it may be tempted to abort the new
root intr xfer just after submission, which would be wrong -- so
instead we just have the callout do nothing if it notices it has
been rescheduled, since it will fire again after the appropriate
time has elapsed.
2020-02-12 19:02:01 +03:00
|
|
|
/*
|
|
|
|
* Interrupt completed, and the xfer has not been completed or
|
|
|
|
* synchronously aborted. Complete the xfer now.
|
|
|
|
*/
|
2016-04-23 13:15:27 +03:00
|
|
|
xfer->ux_actlen = 1;
|
|
|
|
xfer->ux_status = USBD_NORMAL_COMPLETION;
|
2020-02-14 19:47:28 +03:00
|
|
|
#ifdef DIAGNOSTIC
|
|
|
|
UHCI_XFER2UXFER(xfer)->ux_isdone = true;
|
|
|
|
#endif
|
1999-11-12 03:34:57 +03:00
|
|
|
usb_transfer_complete(xfer);
|
Fix steady state of root intr xfers.
Why?
- Avoid completing a root intr xfer multiple times in races.
- Avoid potential use-after-free in poll_hub callouts (uhci, ahci).
How?
- Use sc->sc_intr_xfer or equivalent to store only a pending xfer
that has not yet completed -- whether successfully, by timeout, or
by synchronous abort. When any of those happens, set it to null
under the lock, so the xfer is completed only once.
- For hci drivers that use a callout to poll the root hub (uhci, ahci):
. Pass the softc pointer, not the xfer, to the callout, so the
callout is not even tempted to use xfer after free -- if the
callout fires, but the xfer is synchronously aborted before the
callout can do anything, the xfer might be freed by the time the
callout starts to examine it.
. Teach the callout to do nothing if it is callout_pending after it
has fired. This way:
1. completion or synchronous abort can just callout_stop
2. start can just callout_schedule
If the callout had already fired before (1), and doesn't acquire
the bus lock until after (2), it may be tempted to abort the new
root intr xfer just after submission, which would be wrong -- so
instead we just have the callout do nothing if it notices it has
been rescheduled, since it will fire again after the appropriate
time has elapsed.
2020-02-12 19:02:01 +03:00
|
|
|
|
|
|
|
out: mutex_exit(&sc->sc_lock);
|
1999-08-23 00:12:39 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_root_intr_done(struct usbd_xfer *xfer)
|
2000-01-28 03:44:27 +03:00
|
|
|
{
|
Fix steady state of root intr xfers.
Why?
- Avoid completing a root intr xfer multiple times in races.
- Avoid potential use-after-free in poll_hub callouts (uhci, ahci).
How?
- Use sc->sc_intr_xfer or equivalent to store only a pending xfer
that has not yet completed -- whether successfully, by timeout, or
by synchronous abort. When any of those happens, set it to null
under the lock, so the xfer is completed only once.
- For hci drivers that use a callout to poll the root hub (uhci, ahci):
. Pass the softc pointer, not the xfer, to the callout, so the
callout is not even tempted to use xfer after free -- if the
callout fires, but the xfer is synchronously aborted before the
callout can do anything, the xfer might be freed by the time the
callout starts to examine it.
. Teach the callout to do nothing if it is callout_pending after it
has fired. This way:
1. completion or synchronous abort can just callout_stop
2. start can just callout_schedule
If the callout had already fired before (1), and doesn't acquire
the bus lock until after (2), it may be tempted to abort the new
root intr xfer just after submission, which would be wrong -- so
instead we just have the callout do nothing if it notices it has
been rescheduled, since it will fire again after the appropriate
time has elapsed.
2020-02-12 19:02:01 +03:00
|
|
|
struct uhci_softc *sc = UHCI_XFER2SC(xfer);
|
|
|
|
|
|
|
|
KASSERT(mutex_owned(&sc->sc_lock));
|
|
|
|
|
|
|
|
/* Claim the xfer so it doesn't get completed again. */
|
|
|
|
KASSERT(sc->sc_intr_xfer == xfer);
|
|
|
|
KASSERT(xfer->ux_status != USBD_IN_PROGRESS);
|
|
|
|
sc->sc_intr_xfer = NULL;
|
2000-01-28 03:44:27 +03:00
|
|
|
}
|
|
|
|
|
2000-08-13 20:18:09 +04:00
|
|
|
/*
|
|
|
|
* Let the last QH loop back to the high speed control transfer QH.
|
|
|
|
* This is what intel calls "bandwidth reclamation" and improves
|
|
|
|
* USB performance a lot for some devices.
|
|
|
|
* If we are already looping, just count it.
|
|
|
|
*/
|
1998-07-12 23:51:55 +04:00
|
|
|
void
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_add_loop(uhci_softc_t *sc)
|
|
|
|
{
|
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
|
|
|
|
2000-09-24 01:00:10 +04:00
|
|
|
#ifdef UHCI_DEBUG
|
|
|
|
if (uhcinoloop)
|
|
|
|
return;
|
|
|
|
#endif
|
2000-08-13 20:18:09 +04:00
|
|
|
if (++sc->sc_loops == 1) {
|
2016-04-23 13:15:27 +03:00
|
|
|
DPRINTFN(5, "add loop", 0, 0, 0, 0);
|
2000-08-13 20:18:09 +04:00
|
|
|
/* Note, we don't loop back the soft pointer. */
|
2002-02-03 21:15:20 +03:00
|
|
|
sc->sc_last_qh->qh.qh_hlink =
|
2000-08-13 20:18:09 +04:00
|
|
|
htole32(sc->sc_hctl_start->physaddr | UHCI_PTR_QH);
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&sc->sc_last_qh->dma,
|
|
|
|
sc->sc_last_qh->offs + offsetof(uhci_qh_t, qh_hlink),
|
|
|
|
sizeof(sc->sc_last_qh->qh.qh_hlink),
|
|
|
|
BUS_DMASYNC_PREWRITE);
|
2000-08-13 20:18:09 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_rem_loop(uhci_softc_t *sc)
|
|
|
|
{
|
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
|
|
|
|
2000-09-24 01:00:10 +04:00
|
|
|
#ifdef UHCI_DEBUG
|
|
|
|
if (uhcinoloop)
|
|
|
|
return;
|
|
|
|
#endif
|
2000-08-13 20:18:09 +04:00
|
|
|
if (--sc->sc_loops == 0) {
|
2016-04-23 13:15:27 +03:00
|
|
|
DPRINTFN(5, "remove loop", 0, 0, 0, 0);
|
2000-08-13 20:18:09 +04:00
|
|
|
sc->sc_last_qh->qh.qh_hlink = htole32(UHCI_PTR_T);
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&sc->sc_last_qh->dma,
|
|
|
|
sc->sc_last_qh->offs + offsetof(uhci_qh_t, qh_hlink),
|
|
|
|
sizeof(sc->sc_last_qh->qh.qh_hlink),
|
|
|
|
BUS_DMASYNC_PREWRITE);
|
2000-08-13 20:18:09 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-10 10:15:52 +04:00
|
|
|
/* Add high speed control QH, called with lock held. */
|
2000-08-13 20:18:09 +04:00
|
|
|
void
|
|
|
|
uhci_add_hs_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
|
1998-07-12 23:51:55 +04:00
|
|
|
{
|
1999-08-23 03:19:56 +04:00
|
|
|
uhci_soft_qh_t *eqh;
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
|
|
|
|
2012-06-10 10:15:52 +04:00
|
|
|
KASSERT(mutex_owned(&sc->sc_lock));
|
|
|
|
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTFN(10, "sqh %#jx", (uintptr_t)sqh, 0, 0, 0);
|
2000-08-13 20:18:09 +04:00
|
|
|
eqh = sc->sc_hctl_end;
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&eqh->dma, eqh->offs + offsetof(uhci_qh_t, qh_hlink),
|
|
|
|
sizeof(eqh->qh.qh_hlink),
|
|
|
|
BUS_DMASYNC_POSTWRITE);
|
1999-08-23 03:19:56 +04:00
|
|
|
sqh->hlink = eqh->hlink;
|
|
|
|
sqh->qh.qh_hlink = eqh->qh.qh_hlink;
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh),
|
|
|
|
BUS_DMASYNC_PREWRITE);
|
1999-08-23 03:19:56 +04:00
|
|
|
eqh->hlink = sqh;
|
2000-07-23 23:43:37 +04:00
|
|
|
eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH);
|
2000-08-13 20:18:09 +04:00
|
|
|
sc->sc_hctl_end = sqh;
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&eqh->dma, eqh->offs + offsetof(uhci_qh_t, qh_hlink),
|
|
|
|
sizeof(eqh->qh.qh_hlink), BUS_DMASYNC_PREWRITE);
|
2000-09-24 01:00:10 +04:00
|
|
|
#ifdef UHCI_CTL_LOOP
|
2000-08-13 20:18:09 +04:00
|
|
|
uhci_add_loop(sc);
|
2000-09-24 01:00:10 +04:00
|
|
|
#endif
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
|
2012-06-10 10:15:52 +04:00
|
|
|
/* Remove high speed control QH, called with lock held. */
|
1998-07-12 23:51:55 +04:00
|
|
|
void
|
2000-08-13 20:18:09 +04:00
|
|
|
uhci_remove_hs_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
|
1998-07-12 23:51:55 +04:00
|
|
|
{
|
|
|
|
uhci_soft_qh_t *pqh;
|
2013-02-01 16:53:47 +04:00
|
|
|
uint32_t elink;
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2016-05-06 23:12:54 +03:00
|
|
|
KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
|
2012-06-10 10:15:52 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTFN(10, "sqh %#jx", (uintptr_t)sqh, 0, 0, 0);
|
2000-09-24 01:00:10 +04:00
|
|
|
#ifdef UHCI_CTL_LOOP
|
2000-08-13 20:18:09 +04:00
|
|
|
uhci_rem_loop(sc);
|
2000-09-24 01:00:10 +04:00
|
|
|
#endif
|
2000-08-13 22:20:14 +04:00
|
|
|
/*
|
|
|
|
* The T bit should be set in the elink of the QH so that the HC
|
|
|
|
* doesn't follow the pointer. This condition may fail if the
|
|
|
|
* the transferred packet was short so that the QH still points
|
|
|
|
* at the last used TD.
|
|
|
|
* In this case we set the T bit and wait a little for the HC
|
|
|
|
* to stop looking at the TD.
|
2008-06-28 21:42:53 +04:00
|
|
|
* Note that if the TD chain is large enough, the controller
|
|
|
|
* may still be looking at the chain at the end of this function.
|
|
|
|
* uhci_free_std_chain() will make sure the controller stops
|
|
|
|
* looking at it quickly, but until then we should not change
|
|
|
|
* sqh->hlink.
|
2000-08-13 22:20:14 +04:00
|
|
|
*/
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&sqh->dma, sqh->offs + offsetof(uhci_qh_t, qh_elink),
|
|
|
|
sizeof(sqh->qh.qh_elink),
|
|
|
|
BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
|
2013-02-01 16:53:47 +04:00
|
|
|
elink = le32toh(sqh->qh.qh_elink);
|
|
|
|
usb_syncmem(&sqh->dma, sqh->offs + offsetof(uhci_qh_t, qh_elink),
|
|
|
|
sizeof(sqh->qh.qh_elink), BUS_DMASYNC_PREREAD);
|
|
|
|
if (!(elink & UHCI_PTR_T)) {
|
2000-08-13 22:20:14 +04:00
|
|
|
sqh->qh.qh_elink = htole32(UHCI_PTR_T);
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&sqh->dma,
|
|
|
|
sqh->offs + offsetof(uhci_qh_t, qh_elink),
|
|
|
|
sizeof(sqh->qh.qh_elink),
|
|
|
|
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
|
2000-08-13 22:20:14 +04:00
|
|
|
delay(UHCI_QH_REMOVE_DELAY);
|
|
|
|
}
|
|
|
|
|
2000-08-13 20:18:09 +04:00
|
|
|
pqh = uhci_find_prev_qh(sc->sc_hctl_start, sqh);
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&sqh->dma, sqh->offs + offsetof(uhci_qh_t, qh_hlink),
|
|
|
|
sizeof(sqh->qh.qh_hlink), BUS_DMASYNC_POSTWRITE);
|
2002-02-03 21:15:20 +03:00
|
|
|
pqh->hlink = sqh->hlink;
|
1999-08-23 03:19:56 +04:00
|
|
|
pqh->qh.qh_hlink = sqh->qh.qh_hlink;
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&pqh->dma, pqh->offs + offsetof(uhci_qh_t, qh_hlink),
|
2016-05-06 23:12:54 +03:00
|
|
|
sizeof(pqh->qh.qh_hlink), BUS_DMASYNC_PREWRITE);
|
2000-08-13 22:20:14 +04:00
|
|
|
delay(UHCI_QH_REMOVE_DELAY);
|
2000-08-13 20:18:09 +04:00
|
|
|
if (sc->sc_hctl_end == sqh)
|
|
|
|
sc->sc_hctl_end = pqh;
|
|
|
|
}
|
|
|
|
|
2012-06-10 10:15:52 +04:00
|
|
|
/* Add low speed control QH, called with lock held. */
|
2000-08-13 20:18:09 +04:00
|
|
|
void
|
|
|
|
uhci_add_ls_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
|
|
|
|
{
|
|
|
|
uhci_soft_qh_t *eqh;
|
|
|
|
|
2012-06-10 10:15:52 +04:00
|
|
|
KASSERT(mutex_owned(&sc->sc_lock));
|
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTFN(10, "sqh %#jx", (uintptr_t)sqh, 0, 0, 0);
|
2016-04-23 13:15:27 +03:00
|
|
|
|
2000-08-13 20:18:09 +04:00
|
|
|
eqh = sc->sc_lctl_end;
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&eqh->dma, eqh->offs + offsetof(uhci_qh_t, qh_hlink),
|
|
|
|
sizeof(eqh->qh.qh_hlink), BUS_DMASYNC_POSTWRITE);
|
2002-02-03 21:15:20 +03:00
|
|
|
sqh->hlink = eqh->hlink;
|
2000-08-13 20:18:09 +04:00
|
|
|
sqh->qh.qh_hlink = eqh->qh.qh_hlink;
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh),
|
|
|
|
BUS_DMASYNC_PREWRITE);
|
2002-02-03 21:15:20 +03:00
|
|
|
eqh->hlink = sqh;
|
2000-08-13 20:18:09 +04:00
|
|
|
eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH);
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&eqh->dma, eqh->offs + offsetof(uhci_qh_t, qh_hlink),
|
|
|
|
sizeof(eqh->qh.qh_hlink), BUS_DMASYNC_PREWRITE);
|
2000-08-13 20:18:09 +04:00
|
|
|
sc->sc_lctl_end = sqh;
|
|
|
|
}
|
|
|
|
|
2012-06-10 10:15:52 +04:00
|
|
|
/* Remove low speed control QH, called with lock held. */
|
2000-08-13 20:18:09 +04:00
|
|
|
void
|
|
|
|
uhci_remove_ls_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
|
|
|
|
{
|
|
|
|
uhci_soft_qh_t *pqh;
|
2013-02-01 16:53:47 +04:00
|
|
|
uint32_t elink;
|
2000-08-13 20:18:09 +04:00
|
|
|
|
2016-05-06 23:12:54 +03:00
|
|
|
KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
|
2012-06-10 10:15:52 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTFN(10, "sqh %#jx", (uintptr_t)sqh, 0, 0, 0);
|
2016-04-23 13:15:27 +03:00
|
|
|
|
2000-08-13 22:20:14 +04:00
|
|
|
/* See comment in uhci_remove_hs_ctrl() */
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&sqh->dma, sqh->offs + offsetof(uhci_qh_t, qh_elink),
|
|
|
|
sizeof(sqh->qh.qh_elink),
|
|
|
|
BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
|
2013-02-01 16:53:47 +04:00
|
|
|
elink = le32toh(sqh->qh.qh_elink);
|
|
|
|
usb_syncmem(&sqh->dma, sqh->offs + offsetof(uhci_qh_t, qh_elink),
|
|
|
|
sizeof(sqh->qh.qh_elink), BUS_DMASYNC_PREREAD);
|
|
|
|
if (!(elink & UHCI_PTR_T)) {
|
2000-08-13 22:20:14 +04:00
|
|
|
sqh->qh.qh_elink = htole32(UHCI_PTR_T);
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&sqh->dma,
|
|
|
|
sqh->offs + offsetof(uhci_qh_t, qh_elink),
|
|
|
|
sizeof(sqh->qh.qh_elink),
|
|
|
|
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
|
2000-08-13 22:20:14 +04:00
|
|
|
delay(UHCI_QH_REMOVE_DELAY);
|
|
|
|
}
|
2000-08-13 20:18:09 +04:00
|
|
|
pqh = uhci_find_prev_qh(sc->sc_lctl_start, sqh);
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&sqh->dma, sqh->offs + offsetof(uhci_qh_t, qh_hlink),
|
|
|
|
sizeof(sqh->qh.qh_hlink), BUS_DMASYNC_POSTWRITE);
|
2002-02-03 21:15:20 +03:00
|
|
|
pqh->hlink = sqh->hlink;
|
2000-08-13 20:18:09 +04:00
|
|
|
pqh->qh.qh_hlink = sqh->qh.qh_hlink;
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&pqh->dma, pqh->offs + offsetof(uhci_qh_t, qh_hlink),
|
|
|
|
sizeof(pqh->qh.qh_hlink),
|
|
|
|
BUS_DMASYNC_PREWRITE);
|
2000-08-13 22:20:14 +04:00
|
|
|
delay(UHCI_QH_REMOVE_DELAY);
|
2000-08-13 20:18:09 +04:00
|
|
|
if (sc->sc_lctl_end == sqh)
|
|
|
|
sc->sc_lctl_end = pqh;
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
|
2012-06-10 10:15:52 +04:00
|
|
|
/* Add bulk QH, called with lock held. */
|
1998-07-12 23:51:55 +04:00
|
|
|
void
|
2000-06-01 18:28:57 +04:00
|
|
|
uhci_add_bulk(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
|
1998-07-12 23:51:55 +04:00
|
|
|
{
|
1999-08-23 03:19:56 +04:00
|
|
|
uhci_soft_qh_t *eqh;
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2012-06-10 10:15:52 +04:00
|
|
|
KASSERT(mutex_owned(&sc->sc_lock));
|
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTFN(10, "sqh %#jx", (uintptr_t)sqh, 0, 0, 0);
|
2016-04-23 13:15:27 +03:00
|
|
|
|
1999-08-23 03:19:56 +04:00
|
|
|
eqh = sc->sc_bulk_end;
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&eqh->dma, eqh->offs + offsetof(uhci_qh_t, qh_hlink),
|
|
|
|
sizeof(eqh->qh.qh_hlink), BUS_DMASYNC_POSTWRITE);
|
2002-02-03 21:15:20 +03:00
|
|
|
sqh->hlink = eqh->hlink;
|
1999-08-23 03:19:56 +04:00
|
|
|
sqh->qh.qh_hlink = eqh->qh.qh_hlink;
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh),
|
|
|
|
BUS_DMASYNC_PREWRITE);
|
2002-02-03 21:15:20 +03:00
|
|
|
eqh->hlink = sqh;
|
2000-07-23 23:43:37 +04:00
|
|
|
eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH);
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&eqh->dma, eqh->offs + offsetof(uhci_qh_t, qh_hlink),
|
|
|
|
sizeof(eqh->qh.qh_hlink), BUS_DMASYNC_PREWRITE);
|
1998-07-12 23:51:55 +04:00
|
|
|
sc->sc_bulk_end = sqh;
|
2000-08-13 20:18:09 +04:00
|
|
|
uhci_add_loop(sc);
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
|
2012-06-10 10:15:52 +04:00
|
|
|
/* Remove bulk QH, called with lock held. */
|
1998-07-12 23:51:55 +04:00
|
|
|
void
|
2000-06-01 18:28:57 +04:00
|
|
|
uhci_remove_bulk(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
|
1998-07-12 23:51:55 +04:00
|
|
|
{
|
|
|
|
uhci_soft_qh_t *pqh;
|
|
|
|
|
2012-06-10 10:15:52 +04:00
|
|
|
KASSERT(mutex_owned(&sc->sc_lock));
|
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTFN(10, "sqh %#jx", (uintptr_t)sqh, 0, 0, 0);
|
2016-04-23 13:15:27 +03:00
|
|
|
|
2000-08-13 20:18:09 +04:00
|
|
|
uhci_rem_loop(sc);
|
2000-08-13 22:20:14 +04:00
|
|
|
/* See comment in uhci_remove_hs_ctrl() */
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&sqh->dma, sqh->offs + offsetof(uhci_qh_t, qh_elink),
|
|
|
|
sizeof(sqh->qh.qh_elink),
|
|
|
|
BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
|
2000-08-13 22:20:14 +04:00
|
|
|
if (!(sqh->qh.qh_elink & htole32(UHCI_PTR_T))) {
|
|
|
|
sqh->qh.qh_elink = htole32(UHCI_PTR_T);
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&sqh->dma,
|
|
|
|
sqh->offs + offsetof(uhci_qh_t, qh_elink),
|
|
|
|
sizeof(sqh->qh.qh_elink),
|
|
|
|
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
|
2000-08-13 22:20:14 +04:00
|
|
|
delay(UHCI_QH_REMOVE_DELAY);
|
|
|
|
}
|
2000-03-25 01:57:58 +03:00
|
|
|
pqh = uhci_find_prev_qh(sc->sc_bulk_start, sqh);
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&sqh->dma, sqh->offs + offsetof(uhci_qh_t, qh_hlink),
|
|
|
|
sizeof(sqh->qh.qh_hlink), BUS_DMASYNC_POSTWRITE);
|
1999-08-23 03:19:56 +04:00
|
|
|
pqh->hlink = sqh->hlink;
|
|
|
|
pqh->qh.qh_hlink = sqh->qh.qh_hlink;
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&pqh->dma, pqh->offs + offsetof(uhci_qh_t, qh_hlink),
|
|
|
|
sizeof(pqh->qh.qh_hlink), BUS_DMASYNC_PREWRITE);
|
2000-08-13 22:20:14 +04:00
|
|
|
delay(UHCI_QH_REMOVE_DELAY);
|
1998-07-12 23:51:55 +04:00
|
|
|
if (sc->sc_bulk_end == sqh)
|
|
|
|
sc->sc_bulk_end = pqh;
|
|
|
|
}
|
|
|
|
|
2001-10-25 01:04:04 +04:00
|
|
|
Static int uhci_intr1(uhci_softc_t *);
|
|
|
|
|
1998-07-12 23:51:55 +04:00
|
|
|
int
|
2000-06-01 18:28:57 +04:00
|
|
|
uhci_intr(void *arg)
|
1998-07-12 23:51:55 +04:00
|
|
|
{
|
1999-09-02 22:11:41 +04:00
|
|
|
uhci_softc_t *sc = arg;
|
2012-06-10 10:15:52 +04:00
|
|
|
int ret = 0;
|
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
|
|
|
|
2012-06-10 10:15:52 +04:00
|
|
|
mutex_spin_enter(&sc->sc_intr_lock);
|
2001-10-25 01:04:04 +04:00
|
|
|
|
2008-03-28 20:14:45 +03:00
|
|
|
if (sc->sc_dying || !device_has_power(sc->sc_dev))
|
2012-06-10 10:15:52 +04:00
|
|
|
goto done;
|
2001-11-21 00:12:46 +03:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
if (sc->sc_bus.ub_usepolling || UREAD2(sc, UHCI_INTR) == 0) {
|
|
|
|
DPRINTFN(16, "ignored interrupt while polling", 0, 0, 0, 0);
|
2012-06-10 10:15:52 +04:00
|
|
|
goto done;
|
2001-10-25 01:04:04 +04:00
|
|
|
}
|
2004-06-29 07:56:04 +04:00
|
|
|
|
2012-06-10 10:15:52 +04:00
|
|
|
ret = uhci_intr1(sc);
|
|
|
|
|
|
|
|
done:
|
|
|
|
mutex_spin_exit(&sc->sc_intr_lock);
|
|
|
|
return ret;
|
2001-10-25 01:04:04 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
uhci_intr1(uhci_softc_t *sc)
|
|
|
|
{
|
1999-09-02 22:11:41 +04:00
|
|
|
int status;
|
|
|
|
int ack;
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
|
|
|
|
1999-11-19 02:32:25 +03:00
|
|
|
#ifdef UHCI_DEBUG
|
2016-04-23 13:15:27 +03:00
|
|
|
if (uhcidebug >= 15) {
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTF("sc %#jx", (uintptr_t)sc, 0, 0, 0);
|
1998-07-12 23:51:55 +04:00
|
|
|
uhci_dumpregs(sc);
|
|
|
|
}
|
|
|
|
#endif
|
1999-09-02 22:11:41 +04:00
|
|
|
|
2012-06-10 10:15:52 +04:00
|
|
|
KASSERT(mutex_owned(&sc->sc_intr_lock));
|
|
|
|
|
2002-02-11 14:40:33 +03:00
|
|
|
status = UREAD2(sc, UHCI_STS) & UHCI_STS_ALLINTRS;
|
2016-04-23 13:15:27 +03:00
|
|
|
/* Check if the interrupt was for us. */
|
|
|
|
if (status == 0)
|
|
|
|
return 0;
|
2000-11-22 08:50:59 +03:00
|
|
|
|
2000-05-30 13:26:06 +04:00
|
|
|
if (sc->sc_suspend != PWR_RESUME) {
|
2006-09-26 02:15:15 +04:00
|
|
|
#ifdef DIAGNOSTIC
|
2000-05-30 13:26:06 +04:00
|
|
|
printf("%s: interrupt while not operating ignored\n",
|
2008-03-28 20:14:45 +03:00
|
|
|
device_xname(sc->sc_dev));
|
2006-09-26 02:15:15 +04:00
|
|
|
#endif
|
2001-03-26 02:52:21 +04:00
|
|
|
UWRITE2(sc, UHCI_STS, status); /* acknowledge the ints */
|
2016-04-23 13:15:27 +03:00
|
|
|
return 0;
|
2000-05-30 13:26:06 +04:00
|
|
|
}
|
|
|
|
|
1999-09-02 22:11:41 +04:00
|
|
|
ack = 0;
|
|
|
|
if (status & UHCI_STS_USBINT)
|
|
|
|
ack |= UHCI_STS_USBINT;
|
|
|
|
if (status & UHCI_STS_USBEI)
|
|
|
|
ack |= UHCI_STS_USBEI;
|
1998-07-12 23:51:55 +04:00
|
|
|
if (status & UHCI_STS_RD) {
|
1999-09-02 22:11:41 +04:00
|
|
|
ack |= UHCI_STS_RD;
|
2000-05-30 20:56:54 +04:00
|
|
|
#ifdef UHCI_DEBUG
|
2008-03-28 20:14:45 +03:00
|
|
|
printf("%s: resume detect\n", device_xname(sc->sc_dev));
|
2000-05-30 20:56:54 +04:00
|
|
|
#endif
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
if (status & UHCI_STS_HSE) {
|
1999-09-02 22:11:41 +04:00
|
|
|
ack |= UHCI_STS_HSE;
|
2008-03-28 20:14:45 +03:00
|
|
|
printf("%s: host system error\n", device_xname(sc->sc_dev));
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
if (status & UHCI_STS_HCPE) {
|
1999-09-02 22:11:41 +04:00
|
|
|
ack |= UHCI_STS_HCPE;
|
2002-02-03 21:15:20 +03:00
|
|
|
printf("%s: host controller process error\n",
|
2008-03-28 20:14:45 +03:00
|
|
|
device_xname(sc->sc_dev));
|
1999-09-02 22:11:41 +04:00
|
|
|
}
|
2010-06-29 08:02:07 +04:00
|
|
|
|
|
|
|
/* When HCHalted=1 and Run/Stop=0 , it is normal */
|
|
|
|
if ((status & UHCI_STS_HCH) && (UREAD2(sc, UHCI_CMD) & UHCI_CMD_RS)) {
|
1999-09-02 22:11:41 +04:00
|
|
|
/* no acknowledge needed */
|
2001-07-11 18:11:00 +04:00
|
|
|
if (!sc->sc_dying) {
|
2002-02-03 21:15:20 +03:00
|
|
|
printf("%s: host controller halted\n",
|
2008-03-28 20:14:45 +03:00
|
|
|
device_xname(sc->sc_dev));
|
2000-04-14 18:11:36 +04:00
|
|
|
#ifdef UHCI_DEBUG
|
2001-07-11 18:11:00 +04:00
|
|
|
uhci_dump_all(sc);
|
2000-04-14 18:11:36 +04:00
|
|
|
#endif
|
2001-07-11 18:11:00 +04:00
|
|
|
}
|
|
|
|
sc->sc_dying = 1;
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
1999-09-02 22:11:41 +04:00
|
|
|
|
2001-01-21 02:36:02 +03:00
|
|
|
if (!ack)
|
2016-04-23 13:15:27 +03:00
|
|
|
return 0; /* nothing to acknowledge */
|
2001-01-21 02:36:02 +03:00
|
|
|
UWRITE2(sc, UHCI_STS, ack); /* acknowledge the ints */
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2000-02-22 14:30:54 +03:00
|
|
|
usb_schedsoftintr(&sc->sc_bus);
|
|
|
|
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTFN(15, "sc %#jx done", (uintptr_t)sc, 0, 0, 0);
|
2000-02-22 14:30:54 +03:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
return 1;
|
2000-02-22 14:30:54 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2001-01-21 05:39:52 +03:00
|
|
|
uhci_softintr(void *v)
|
2000-02-22 14:30:54 +03:00
|
|
|
{
|
2008-03-28 20:14:45 +03:00
|
|
|
struct usbd_bus *bus = v;
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_softc_t *sc = UHCI_BUS2SC(bus);
|
|
|
|
struct uhci_xfer *ux, *nextux;
|
|
|
|
ux_completeq_t cq;
|
2000-02-22 14:30:54 +03:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTF("sc %#jx", (uintptr_t)sc, 0, 0, 0);
|
2012-06-10 10:15:52 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
|
1999-09-13 23:18:17 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
TAILQ_INIT(&cq);
|
1998-07-12 23:51:55 +04:00
|
|
|
/*
|
|
|
|
* Interrupts on UHCI really suck. When the host controller
|
|
|
|
* interrupts because a transfer is completed there is no
|
|
|
|
* way of knowing which transfer it was. You can scan down
|
|
|
|
* the TDs and QHs of the previous frame to limit the search,
|
|
|
|
* but that assumes that the interrupt was not delayed by more
|
|
|
|
* than 1 ms, which may not always be true (e.g. after debug
|
|
|
|
* output on a slow console).
|
|
|
|
* We scan all interrupt descriptors to see if any have
|
|
|
|
* completed.
|
|
|
|
*/
|
2016-04-23 13:15:27 +03:00
|
|
|
TAILQ_FOREACH_SAFE(ux, &sc->sc_intrhead, ux_list, nextux) {
|
|
|
|
uhci_check_intr(sc, ux, &cq);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We abuse ux_list for the interrupt and complete lists and
|
|
|
|
* interrupt transfers will get re-added here so use
|
|
|
|
* the _SAFE version of TAILQ_FOREACH.
|
|
|
|
*/
|
|
|
|
TAILQ_FOREACH_SAFE(ux, &cq, ux_list, nextux) {
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTF("ux %#jx", (uintptr_t)ux, 0, 0, 0);
|
2016-04-23 13:15:27 +03:00
|
|
|
usb_transfer_complete(&ux->ux_xfer);
|
2004-03-02 19:32:05 +03:00
|
|
|
}
|
1998-07-12 23:51:55 +04:00
|
|
|
|
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
--
#ifdef DIAGNOSTIC -> KASSERT and add another KASSERT
--
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.
2018-08-09 09:26:47 +03:00
|
|
|
KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for an interrupt. */
|
|
|
|
void
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_check_intr(uhci_softc_t *sc, struct uhci_xfer *ux, ux_completeq_t *cqp)
|
1998-07-12 23:51:55 +04:00
|
|
|
{
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_soft_td_t *std, *fstd = NULL, *lstd = NULL;
|
|
|
|
uint32_t status;
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTFN(15, "ux %#jx", (uintptr_t)ux, 0, 0, 0);
|
2016-04-23 13:15:27 +03:00
|
|
|
|
|
|
|
KASSERT(ux != NULL);
|
|
|
|
|
|
|
|
struct usbd_xfer *xfer = &ux->ux_xfer;
|
|
|
|
if (xfer->ux_status == USBD_CANCELLED ||
|
|
|
|
xfer->ux_status == USBD_TIMEOUT) {
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTF("aborted xfer %#jx", (uintptr_t)xfer, 0, 0, 0);
|
2002-02-27 15:42:41 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
switch (ux->ux_type) {
|
|
|
|
case UX_CTRL:
|
|
|
|
fstd = ux->ux_setup;
|
|
|
|
lstd = ux->ux_stat;
|
|
|
|
break;
|
|
|
|
case UX_BULK:
|
|
|
|
case UX_INTR:
|
|
|
|
case UX_ISOC:
|
|
|
|
fstd = ux->ux_stdstart;
|
|
|
|
lstd = ux->ux_stdend;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
KASSERT(false);
|
|
|
|
break;
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
2016-04-23 13:15:27 +03:00
|
|
|
if (fstd == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
KASSERT(lstd != NULL);
|
|
|
|
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&lstd->dma,
|
|
|
|
lstd->offs + offsetof(uhci_td_t, td_status),
|
|
|
|
sizeof(lstd->td.td_status),
|
|
|
|
BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
|
2013-02-01 16:53:47 +04:00
|
|
|
status = le32toh(lstd->td.td_status);
|
|
|
|
usb_syncmem(&lstd->dma,
|
|
|
|
lstd->offs + offsetof(uhci_td_t, td_status),
|
|
|
|
sizeof(lstd->td.td_status),
|
|
|
|
BUS_DMASYNC_PREREAD);
|
2013-09-07 20:17:12 +04:00
|
|
|
|
|
|
|
/* If the last TD is not marked active we can complete */
|
|
|
|
if (!(status & UHCI_TD_ACTIVE)) {
|
|
|
|
done:
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTFN(12, "ux=%#jx done", (uintptr_t)ux, 0, 0, 0);
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_idone(ux, cqp);
|
1998-07-12 23:51:55 +04:00
|
|
|
return;
|
|
|
|
}
|
2013-09-07 20:17:12 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If the last TD is still active we need to check whether there
|
|
|
|
* is an error somewhere in the middle, or whether there was a
|
|
|
|
* short packet (SPD and not ACTIVE).
|
|
|
|
*/
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTFN(12, "active ux=%#jx", (uintptr_t)ux, 0, 0, 0);
|
2016-04-23 13:15:27 +03:00
|
|
|
for (std = fstd; std != lstd; std = std->link.std) {
|
2013-09-07 20:17:12 +04:00
|
|
|
usb_syncmem(&std->dma,
|
|
|
|
std->offs + offsetof(uhci_td_t, td_status),
|
|
|
|
sizeof(std->td.td_status),
|
|
|
|
BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
|
|
|
|
status = le32toh(std->td.td_status);
|
|
|
|
usb_syncmem(&std->dma,
|
|
|
|
std->offs + offsetof(uhci_td_t, td_status),
|
|
|
|
sizeof(std->td.td_status), BUS_DMASYNC_PREREAD);
|
|
|
|
|
|
|
|
/* If there's an active TD the xfer isn't done. */
|
|
|
|
if (status & UHCI_TD_ACTIVE) {
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTFN(12, "ux=%#jx std=%#jx still active",
|
|
|
|
(uintptr_t)ux, (uintptr_t)std, 0, 0);
|
2013-09-07 20:17:12 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Any kind of error makes the xfer done. */
|
|
|
|
if (status & UHCI_TD_STALLED)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the data phase of a control transfer is short, we need
|
|
|
|
* to complete the status stage
|
|
|
|
*/
|
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
if ((status & UHCI_TD_SPD) && ux->ux_type == UX_CTRL) {
|
2013-09-07 20:17:12 +04:00
|
|
|
struct uhci_pipe *upipe =
|
2016-04-23 13:15:27 +03:00
|
|
|
UHCI_PIPE2UPIPE(xfer->ux_pipe);
|
|
|
|
uhci_soft_qh_t *sqh = upipe->ctrl.sqh;
|
|
|
|
uhci_soft_td_t *stat = upipe->ctrl.stat;
|
2013-09-07 20:17:12 +04:00
|
|
|
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTFN(12, "ux=%#jx std=%#jx control status"
|
|
|
|
"phase needs completion", (uintptr_t)ux,
|
|
|
|
(uintptr_t)ux->ux_stdstart, 0, 0);
|
2013-09-07 20:17:12 +04:00
|
|
|
|
|
|
|
sqh->qh.qh_elink =
|
|
|
|
htole32(stat->physaddr | UHCI_PTR_TD);
|
|
|
|
usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh),
|
|
|
|
BUS_DMASYNC_PREWRITE);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We want short packets, and it is short: it's done */
|
|
|
|
usb_syncmem(&std->dma,
|
|
|
|
std->offs + offsetof(uhci_td_t, td_token),
|
|
|
|
sizeof(std->td.td_token),
|
|
|
|
BUS_DMASYNC_POSTWRITE);
|
|
|
|
|
|
|
|
if ((status & UHCI_TD_SPD) &&
|
|
|
|
UHCI_TD_GET_ACTLEN(status) <
|
|
|
|
UHCI_TD_GET_MAXLEN(le32toh(std->td.td_token))) {
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
|
2012-06-10 10:15:52 +04:00
|
|
|
/* Called with USB lock held. */
|
1998-07-12 23:51:55 +04:00
|
|
|
void
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_idone(struct uhci_xfer *ux, ux_completeq_t *cqp)
|
1998-07-12 23:51:55 +04:00
|
|
|
{
|
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
--
#ifdef DIAGNOSTIC -> KASSERT and add another KASSERT
--
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.
2018-08-09 09:26:47 +03:00
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
2016-04-23 13:15:27 +03:00
|
|
|
struct usbd_xfer *xfer = &ux->ux_xfer;
|
|
|
|
uhci_softc_t *sc __diagused = UHCI_XFER2SC(xfer);
|
|
|
|
struct uhci_pipe *upipe = UHCI_PIPE2UPIPE(xfer->ux_pipe);
|
1998-07-12 23:51:55 +04:00
|
|
|
uhci_soft_td_t *std;
|
2016-04-23 13:15:27 +03:00
|
|
|
uint32_t status = 0, nstatus;
|
2018-09-16 23:21:56 +03:00
|
|
|
const bool polling __diagused = sc->sc_bus.ub_usepolling;
|
1999-05-16 15:43:32 +04:00
|
|
|
int actlen;
|
1998-07-12 23:51:55 +04:00
|
|
|
|
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
--
#ifdef DIAGNOSTIC -> KASSERT and add another KASSERT
--
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.
2018-08-09 09:26:47 +03:00
|
|
|
KASSERT(polling || mutex_owned(&sc->sc_lock));
|
2016-04-23 13:15:27 +03:00
|
|
|
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTFN(12, "ux=%#jx", (uintptr_t)ux, 0, 0, 0);
|
2012-06-10 10:15:52 +04:00
|
|
|
|
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
--
#ifdef DIAGNOSTIC -> KASSERT and add another KASSERT
--
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.
2018-08-09 09:26:47 +03:00
|
|
|
/*
|
2020-02-12 19:01:00 +03:00
|
|
|
* Try to claim this xfer for completion. If it has already
|
|
|
|
* completed or aborted, drop it on the floor.
|
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
--
#ifdef DIAGNOSTIC -> KASSERT and add another KASSERT
--
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.
2018-08-09 09:26:47 +03:00
|
|
|
*/
|
2020-02-12 19:01:00 +03:00
|
|
|
if (!usbd_xfer_trycomplete(xfer))
|
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
--
#ifdef DIAGNOSTIC -> KASSERT and add another KASSERT
--
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.
2018-08-09 09:26:47 +03:00
|
|
|
return;
|
|
|
|
|
1998-07-25 01:09:07 +04:00
|
|
|
#ifdef DIAGNOSTIC
|
2000-03-25 01:57:58 +03:00
|
|
|
#ifdef UHCI_DEBUG
|
2016-04-23 13:15:27 +03:00
|
|
|
if (ux->ux_isdone) {
|
|
|
|
DPRINTF("--- dump start ---", 0, 0, 0, 0);
|
|
|
|
uhci_dump_ii(ux);
|
|
|
|
DPRINTF("--- dump end ---", 0, 0, 0, 0);
|
1998-07-25 01:09:07 +04:00
|
|
|
}
|
|
|
|
#endif
|
2016-04-23 13:15:27 +03:00
|
|
|
KASSERT(!ux->ux_isdone);
|
|
|
|
KASSERTMSG(!ux->ux_isdone, "xfer %p type %d status %d", xfer,
|
|
|
|
ux->ux_type, xfer->ux_status);
|
|
|
|
ux->ux_isdone = true;
|
|
|
|
#endif
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
if (xfer->ux_nframes != 0) {
|
1999-09-09 16:26:43 +04:00
|
|
|
/* Isoc transfer, do things differently. */
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_soft_td_t **stds = upipe->isoc.stds;
|
2000-11-10 17:11:49 +03:00
|
|
|
int i, n, nframes, len;
|
1999-09-09 16:26:43 +04:00
|
|
|
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTFN(5, "ux=%#jx isoc ready", (uintptr_t)ux, 0, 0, 0);
|
1999-09-09 16:26:43 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
nframes = xfer->ux_nframes;
|
1999-09-09 16:26:43 +04:00
|
|
|
actlen = 0;
|
2016-04-23 13:15:27 +03:00
|
|
|
n = ux->ux_curframe;
|
1999-09-09 16:26:43 +04:00
|
|
|
for (i = 0; i < nframes; i++) {
|
|
|
|
std = stds[n];
|
1999-10-13 12:10:55 +04:00
|
|
|
#ifdef UHCI_DEBUG
|
2016-04-23 13:15:27 +03:00
|
|
|
if (uhcidebug >= 5) {
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTF("isoc TD %jd", i, 0, 0, 0);
|
2016-04-23 13:15:27 +03:00
|
|
|
DPRINTF("--- dump start ---", 0, 0, 0, 0);
|
1999-09-09 16:26:43 +04:00
|
|
|
uhci_dump_td(std);
|
2016-04-23 13:15:27 +03:00
|
|
|
DPRINTF("--- dump end ---", 0, 0, 0, 0);
|
1999-09-09 16:26:43 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
if (++n >= UHCI_VFRAMELIST_COUNT)
|
|
|
|
n = 0;
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&std->dma,
|
|
|
|
std->offs + offsetof(uhci_td_t, td_status),
|
|
|
|
sizeof(std->td.td_status),
|
|
|
|
BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
|
2000-03-16 15:40:51 +03:00
|
|
|
status = le32toh(std->td.td_status);
|
2000-11-10 17:11:49 +03:00
|
|
|
len = UHCI_TD_GET_ACTLEN(status);
|
2016-04-23 13:15:27 +03:00
|
|
|
xfer->ux_frlengths[i] = len;
|
2000-11-10 17:11:49 +03:00
|
|
|
actlen += len;
|
1999-09-09 16:26:43 +04:00
|
|
|
}
|
2016-04-23 13:15:27 +03:00
|
|
|
upipe->isoc.inuse -= nframes;
|
|
|
|
xfer->ux_actlen = actlen;
|
|
|
|
xfer->ux_status = USBD_NORMAL_COMPLETION;
|
2001-10-25 00:20:03 +04:00
|
|
|
goto end;
|
1999-09-09 16:26:43 +04:00
|
|
|
}
|
|
|
|
|
1999-10-13 12:10:55 +04:00
|
|
|
#ifdef UHCI_DEBUG
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTFN(10, "ux=%#jx, xfer=%#jx, pipe=%#jx ready", (uintptr_t)ux,
|
|
|
|
(uintptr_t)xfer, (uintptr_t)upipe, 0);
|
2016-04-23 13:15:27 +03:00
|
|
|
if (uhcidebug >= 10) {
|
|
|
|
DPRINTF("--- dump start ---", 0, 0, 0, 0);
|
|
|
|
uhci_dump_tds(ux->ux_stdstart);
|
|
|
|
DPRINTF("--- dump end ---", 0, 0, 0, 0);
|
|
|
|
}
|
1999-09-09 16:26:43 +04:00
|
|
|
#endif
|
|
|
|
|
1999-05-16 15:43:32 +04:00
|
|
|
/* The transfer is done, compute actual length and status. */
|
|
|
|
actlen = 0;
|
2016-04-23 13:15:27 +03:00
|
|
|
for (std = ux->ux_stdstart; std != NULL; std = std->link.std) {
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&std->dma, std->offs, sizeof(std->td),
|
|
|
|
BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
|
2000-03-16 15:40:51 +03:00
|
|
|
nstatus = le32toh(std->td.td_status);
|
1999-11-14 02:58:01 +03:00
|
|
|
if (nstatus & UHCI_TD_ACTIVE)
|
1999-05-16 15:43:32 +04:00
|
|
|
break;
|
1999-11-19 02:32:25 +03:00
|
|
|
|
1999-11-14 02:58:01 +03:00
|
|
|
status = nstatus;
|
2000-03-16 15:40:51 +03:00
|
|
|
if (UHCI_TD_GET_PID(le32toh(std->td.td_token)) !=
|
|
|
|
UHCI_TD_PID_SETUP)
|
1999-05-16 15:43:32 +04:00
|
|
|
actlen += UHCI_TD_GET_ACTLEN(status);
|
2003-11-04 22:11:21 +03:00
|
|
|
else {
|
|
|
|
/*
|
|
|
|
* UHCI will report CRCTO in addition to a STALL or NAK
|
|
|
|
* for a SETUP transaction. See section 3.2.2, "TD
|
|
|
|
* CONTROL AND STATUS".
|
|
|
|
*/
|
|
|
|
if (status & (UHCI_TD_STALLED | UHCI_TD_NAK))
|
|
|
|
status &= ~UHCI_TD_CRCTO;
|
|
|
|
}
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
1999-08-18 00:59:04 +04:00
|
|
|
/* If there are left over TDs we need to update the toggle. */
|
1999-11-12 03:34:57 +03:00
|
|
|
if (std != NULL)
|
2000-03-16 15:40:51 +03:00
|
|
|
upipe->nexttoggle = UHCI_TD_GET_DT(le32toh(std->td.td_token));
|
1999-08-18 00:59:04 +04:00
|
|
|
|
1998-07-12 23:51:55 +04:00
|
|
|
status &= UHCI_TD_ERROR;
|
2020-03-13 21:17:40 +03:00
|
|
|
DPRINTFN(10, "actlen=%jd, status=%#jx", actlen, status, 0, 0);
|
2016-04-23 13:15:27 +03:00
|
|
|
xfer->ux_actlen = actlen;
|
1998-07-12 23:51:55 +04:00
|
|
|
if (status != 0) {
|
2016-04-23 13:15:27 +03:00
|
|
|
|
|
|
|
DPRINTFN((status == UHCI_TD_STALLED) * 10,
|
2020-03-14 05:35:33 +03:00
|
|
|
"error, addr=%jd, endpt=0x%02jx",
|
2016-04-23 13:15:27 +03:00
|
|
|
xfer->ux_pipe->up_dev->ud_addr,
|
|
|
|
xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress,
|
|
|
|
0, 0);
|
|
|
|
DPRINTFN((status == UHCI_TD_STALLED) * 10,
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
"bitstuff=%jd crcto =%jd nak =%jd babble =%jd",
|
2016-04-23 13:15:27 +03:00
|
|
|
!!(status & UHCI_TD_BITSTUFF),
|
|
|
|
!!(status & UHCI_TD_CRCTO),
|
|
|
|
!!(status & UHCI_TD_NAK),
|
|
|
|
!!(status & UHCI_TD_BABBLE));
|
|
|
|
DPRINTFN((status == UHCI_TD_STALLED) * 10,
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
"dbuffer =%jd stalled =%jd active =%jd",
|
2016-04-23 13:15:27 +03:00
|
|
|
!!(status & UHCI_TD_DBUFFER),
|
|
|
|
!!(status & UHCI_TD_STALLED),
|
|
|
|
!!(status & UHCI_TD_ACTIVE),
|
|
|
|
0);
|
2000-08-08 23:51:46 +04:00
|
|
|
|
1998-07-12 23:51:55 +04:00
|
|
|
if (status == UHCI_TD_STALLED)
|
2016-04-23 13:15:27 +03:00
|
|
|
xfer->ux_status = USBD_STALLED;
|
1998-07-12 23:51:55 +04:00
|
|
|
else
|
2016-04-23 13:15:27 +03:00
|
|
|
xfer->ux_status = USBD_IOERROR; /* more info XXX */
|
1998-07-12 23:51:55 +04:00
|
|
|
} else {
|
2016-04-23 13:15:27 +03:00
|
|
|
xfer->ux_status = USBD_NORMAL_COMPLETION;
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
2001-10-25 00:20:03 +04:00
|
|
|
|
|
|
|
end:
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_del_intr_list(sc, ux);
|
|
|
|
if (cqp)
|
|
|
|
TAILQ_INSERT_TAIL(cqp, ux, ux_list);
|
|
|
|
|
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
--
#ifdef DIAGNOSTIC -> KASSERT and add another KASSERT
--
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.
2018-08-09 09:26:47 +03:00
|
|
|
KASSERT(polling || mutex_owned(&sc->sc_lock));
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTFN(12, "ux=%#jx done", (uintptr_t)ux, 0, 0, 0);
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
|
1998-07-26 21:42:48 +04:00
|
|
|
void
|
2000-06-01 18:28:57 +04:00
|
|
|
uhci_poll(struct usbd_bus *bus)
|
1998-07-26 21:42:48 +04:00
|
|
|
{
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_softc_t *sc = UHCI_BUS2SC(bus);
|
1998-07-26 21:42:48 +04:00
|
|
|
|
2012-06-10 10:15:52 +04:00
|
|
|
if (UREAD2(sc, UHCI_STS) & UHCI_STS_USBINT) {
|
|
|
|
mutex_spin_enter(&sc->sc_intr_lock);
|
2001-10-25 01:04:04 +04:00
|
|
|
uhci_intr1(sc);
|
2012-06-10 10:15:52 +04:00
|
|
|
mutex_spin_exit(&sc->sc_intr_lock);
|
|
|
|
}
|
1998-07-26 21:42:48 +04:00
|
|
|
}
|
|
|
|
|
1998-07-12 23:51:55 +04:00
|
|
|
void
|
2000-06-01 18:28:57 +04:00
|
|
|
uhci_reset(uhci_softc_t *sc)
|
1998-07-12 23:51:55 +04:00
|
|
|
{
|
|
|
|
int n;
|
|
|
|
|
|
|
|
UHCICMD(sc, UHCI_CMD_HCRESET);
|
|
|
|
/* The reset bit goes low when the controller is done. */
|
2002-02-03 21:15:20 +03:00
|
|
|
for (n = 0; n < UHCI_RESET_TIMEOUT &&
|
1998-07-12 23:51:55 +04:00
|
|
|
(UREAD2(sc, UHCI_CMD) & UHCI_CMD_HCRESET); n++)
|
2000-03-25 01:57:58 +03:00
|
|
|
usb_delay_ms(&sc->sc_bus, 1);
|
1998-07-12 23:51:55 +04:00
|
|
|
if (n >= UHCI_RESET_TIMEOUT)
|
2002-02-03 21:15:20 +03:00
|
|
|
printf("%s: controller did not reset\n",
|
2008-03-28 20:14:45 +03:00
|
|
|
device_xname(sc->sc_dev));
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
|
1998-12-28 23:13:59 +03:00
|
|
|
usbd_status
|
2012-06-24 14:06:34 +04:00
|
|
|
uhci_run(uhci_softc_t *sc, int run, int locked)
|
1998-07-12 23:51:55 +04:00
|
|
|
{
|
2012-06-10 10:15:52 +04:00
|
|
|
int n, running;
|
2016-04-23 13:15:27 +03:00
|
|
|
uint16_t cmd;
|
|
|
|
|
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
1998-07-12 23:51:55 +04:00
|
|
|
|
|
|
|
run = run != 0;
|
2012-06-24 14:06:34 +04:00
|
|
|
if (!locked)
|
|
|
|
mutex_spin_enter(&sc->sc_intr_lock);
|
2016-04-23 13:15:27 +03:00
|
|
|
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTF("setting run=%jd", run, 0, 0, 0);
|
1999-12-24 16:56:35 +03:00
|
|
|
cmd = UREAD2(sc, UHCI_CMD);
|
|
|
|
if (run)
|
|
|
|
cmd |= UHCI_CMD_RS;
|
|
|
|
else
|
|
|
|
cmd &= ~UHCI_CMD_RS;
|
|
|
|
UHCICMD(sc, cmd);
|
2016-03-13 10:01:43 +03:00
|
|
|
for (n = 0; n < 10; n++) {
|
1998-07-12 23:51:55 +04:00
|
|
|
running = !(UREAD2(sc, UHCI_STS) & UHCI_STS_HCH);
|
|
|
|
/* return when we've entered the state we want */
|
|
|
|
if (run == running) {
|
2012-06-24 14:06:34 +04:00
|
|
|
if (!locked)
|
|
|
|
mutex_spin_exit(&sc->sc_intr_lock);
|
2020-03-13 21:17:40 +03:00
|
|
|
DPRINTF("done cmd=%#jx sts=%#jx",
|
2016-04-23 13:15:27 +03:00
|
|
|
UREAD2(sc, UHCI_CMD), UREAD2(sc, UHCI_STS), 0, 0);
|
|
|
|
return USBD_NORMAL_COMPLETION;
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
2012-06-10 10:15:52 +04:00
|
|
|
usb_delay_ms_locked(&sc->sc_bus, 1, &sc->sc_intr_lock);
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
2012-06-24 14:06:34 +04:00
|
|
|
if (!locked)
|
|
|
|
mutex_spin_exit(&sc->sc_intr_lock);
|
2008-03-28 20:14:45 +03:00
|
|
|
printf("%s: cannot %s\n", device_xname(sc->sc_dev),
|
1998-12-28 05:06:25 +03:00
|
|
|
run ? "start" : "stop");
|
2016-04-23 13:15:27 +03:00
|
|
|
return USBD_IOERROR;
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Memory management routines.
|
|
|
|
* uhci_alloc_std allocates TDs
|
|
|
|
* uhci_alloc_sqh allocates QHs
|
1998-07-25 01:09:07 +04:00
|
|
|
* These two routines do their own free list management,
|
1998-07-12 23:51:55 +04:00
|
|
|
* partly for speed, partly because allocating DMAable memory
|
2016-04-23 13:15:27 +03:00
|
|
|
* has page size granularity so much memory would be wasted if
|
1998-12-28 23:13:59 +03:00
|
|
|
* only one TD/QH (32 bytes) was placed in each allocated chunk.
|
1998-07-12 23:51:55 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
uhci_soft_td_t *
|
2000-06-01 18:28:57 +04:00
|
|
|
uhci_alloc_std(uhci_softc_t *sc)
|
1998-07-12 23:51:55 +04:00
|
|
|
{
|
|
|
|
uhci_soft_td_t *std;
|
1999-11-12 03:34:57 +03:00
|
|
|
usbd_status err;
|
1999-08-23 03:19:56 +04:00
|
|
|
int i, offs;
|
1998-07-25 01:09:07 +04:00
|
|
|
usb_dma_t dma;
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
|
|
|
|
|
|
|
mutex_enter(&sc->sc_lock);
|
1999-11-12 03:34:57 +03:00
|
|
|
if (sc->sc_freetds == NULL) {
|
2016-04-23 13:15:27 +03:00
|
|
|
DPRINTFN(2, "allocating chunk", 0, 0, 0, 0);
|
|
|
|
mutex_exit(&sc->sc_lock);
|
|
|
|
|
1999-11-12 03:34:57 +03:00
|
|
|
err = usb_allocmem(&sc->sc_bus, UHCI_STD_SIZE * UHCI_STD_CHUNK,
|
2020-04-05 23:59:38 +03:00
|
|
|
UHCI_TD_ALIGN, USBMALLOC_COHERENT, &dma);
|
1999-11-12 03:34:57 +03:00
|
|
|
if (err)
|
2016-04-23 13:15:27 +03:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
mutex_enter(&sc->sc_lock);
|
2012-06-10 10:15:52 +04:00
|
|
|
for (i = 0; i < UHCI_STD_CHUNK; i++) {
|
1999-08-23 03:19:56 +04:00
|
|
|
offs = i * UHCI_STD_SIZE;
|
2002-05-19 10:24:30 +04:00
|
|
|
std = KERNADDR(&dma, offs);
|
2002-05-28 16:42:38 +04:00
|
|
|
std->physaddr = DMAADDR(&dma, offs);
|
2008-06-28 21:42:53 +04:00
|
|
|
std->dma = dma;
|
|
|
|
std->offs = offs;
|
1999-08-23 03:19:56 +04:00
|
|
|
std->link.std = sc->sc_freetds;
|
1998-07-12 23:51:55 +04:00
|
|
|
sc->sc_freetds = std;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
std = sc->sc_freetds;
|
1999-08-23 03:19:56 +04:00
|
|
|
sc->sc_freetds = std->link.std;
|
2016-04-23 13:15:27 +03:00
|
|
|
mutex_exit(&sc->sc_lock);
|
|
|
|
|
1999-08-23 03:19:56 +04:00
|
|
|
memset(&std->td, 0, sizeof(uhci_td_t));
|
2016-04-23 13:15:27 +03:00
|
|
|
|
1998-07-12 23:51:55 +04:00
|
|
|
return std;
|
|
|
|
}
|
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
#define TD_IS_FREE 0x12345678
|
|
|
|
|
1998-07-12 23:51:55 +04:00
|
|
|
void
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_free_std_locked(uhci_softc_t *sc, uhci_soft_td_t *std)
|
1998-07-12 23:51:55 +04:00
|
|
|
{
|
2016-04-23 13:15:27 +03:00
|
|
|
KASSERT(mutex_owned(&sc->sc_lock));
|
|
|
|
|
1998-07-25 01:09:07 +04:00
|
|
|
#ifdef DIAGNOSTIC
|
2000-03-16 15:40:51 +03:00
|
|
|
if (le32toh(std->td.td_token) == TD_IS_FREE) {
|
2016-04-23 13:15:27 +03:00
|
|
|
printf("%s: freeing free TD %p\n", __func__, std);
|
1998-07-25 01:09:07 +04:00
|
|
|
return;
|
|
|
|
}
|
2000-03-16 15:40:51 +03:00
|
|
|
std->td.td_token = htole32(TD_IS_FREE);
|
1998-07-25 01:09:07 +04:00
|
|
|
#endif
|
2016-04-23 13:15:27 +03:00
|
|
|
|
1999-08-23 03:19:56 +04:00
|
|
|
std->link.std = sc->sc_freetds;
|
1998-07-12 23:51:55 +04:00
|
|
|
sc->sc_freetds = std;
|
|
|
|
}
|
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
void
|
|
|
|
uhci_free_std(uhci_softc_t *sc, uhci_soft_td_t *std)
|
|
|
|
{
|
|
|
|
mutex_enter(&sc->sc_lock);
|
|
|
|
uhci_free_std_locked(sc, std);
|
|
|
|
mutex_exit(&sc->sc_lock);
|
|
|
|
}
|
|
|
|
|
1998-07-12 23:51:55 +04:00
|
|
|
uhci_soft_qh_t *
|
2000-06-01 18:28:57 +04:00
|
|
|
uhci_alloc_sqh(uhci_softc_t *sc)
|
1998-07-12 23:51:55 +04:00
|
|
|
{
|
|
|
|
uhci_soft_qh_t *sqh;
|
1999-11-12 03:34:57 +03:00
|
|
|
usbd_status err;
|
1998-07-12 23:51:55 +04:00
|
|
|
int i, offs;
|
1998-07-25 01:09:07 +04:00
|
|
|
usb_dma_t dma;
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
|
|
|
|
|
|
|
mutex_enter(&sc->sc_lock);
|
1999-11-12 03:34:57 +03:00
|
|
|
if (sc->sc_freeqhs == NULL) {
|
2016-04-23 13:15:27 +03:00
|
|
|
DPRINTFN(2, "allocating chunk", 0, 0, 0, 0);
|
|
|
|
mutex_exit(&sc->sc_lock);
|
|
|
|
|
1999-11-12 03:34:57 +03:00
|
|
|
err = usb_allocmem(&sc->sc_bus, UHCI_SQH_SIZE * UHCI_SQH_CHUNK,
|
2020-04-05 23:59:38 +03:00
|
|
|
UHCI_QH_ALIGN, USBMALLOC_COHERENT, &dma);
|
1999-11-12 03:34:57 +03:00
|
|
|
if (err)
|
2016-04-23 13:15:27 +03:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
mutex_enter(&sc->sc_lock);
|
2016-03-13 10:01:43 +03:00
|
|
|
for (i = 0; i < UHCI_SQH_CHUNK; i++) {
|
1999-08-23 03:19:56 +04:00
|
|
|
offs = i * UHCI_SQH_SIZE;
|
2002-05-19 10:24:30 +04:00
|
|
|
sqh = KERNADDR(&dma, offs);
|
2002-05-28 16:42:38 +04:00
|
|
|
sqh->physaddr = DMAADDR(&dma, offs);
|
2008-06-28 21:42:53 +04:00
|
|
|
sqh->dma = dma;
|
|
|
|
sqh->offs = offs;
|
1999-08-23 03:19:56 +04:00
|
|
|
sqh->hlink = sc->sc_freeqhs;
|
1998-07-12 23:51:55 +04:00
|
|
|
sc->sc_freeqhs = sqh;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sqh = sc->sc_freeqhs;
|
1999-08-23 03:19:56 +04:00
|
|
|
sc->sc_freeqhs = sqh->hlink;
|
2016-04-23 13:15:27 +03:00
|
|
|
mutex_exit(&sc->sc_lock);
|
|
|
|
|
1999-08-23 03:19:56 +04:00
|
|
|
memset(&sqh->qh, 0, sizeof(uhci_qh_t));
|
2016-04-23 13:15:27 +03:00
|
|
|
|
|
|
|
return sqh;
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2000-06-01 18:28:57 +04:00
|
|
|
uhci_free_sqh(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
|
1998-07-12 23:51:55 +04:00
|
|
|
{
|
2016-04-23 13:15:27 +03:00
|
|
|
KASSERT(mutex_owned(&sc->sc_lock));
|
|
|
|
|
1999-08-23 03:19:56 +04:00
|
|
|
sqh->hlink = sc->sc_freeqhs;
|
1998-07-12 23:51:55 +04:00
|
|
|
sc->sc_freeqhs = sqh;
|
|
|
|
}
|
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
#if 0
|
1998-07-12 23:51:55 +04:00
|
|
|
void
|
2000-06-01 18:28:57 +04:00
|
|
|
uhci_free_std_chain(uhci_softc_t *sc, uhci_soft_td_t *std,
|
|
|
|
uhci_soft_td_t *stdend)
|
1998-07-12 23:51:55 +04:00
|
|
|
{
|
|
|
|
uhci_soft_td_t *p;
|
2013-02-01 16:53:47 +04:00
|
|
|
uint32_t td_link;
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2008-06-28 21:42:53 +04:00
|
|
|
/*
|
|
|
|
* to avoid race condition with the controller which may be looking
|
|
|
|
* at this chain, we need to first invalidate all links, and
|
|
|
|
* then wait for the controller to move to another queue
|
|
|
|
*/
|
|
|
|
for (p = std; p != stdend; p = p->link.std) {
|
|
|
|
usb_syncmem(&p->dma,
|
|
|
|
p->offs + offsetof(uhci_td_t, td_link),
|
|
|
|
sizeof(p->td.td_link),
|
|
|
|
BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
|
2013-02-01 16:53:47 +04:00
|
|
|
td_link = le32toh(p->td.td_link);
|
|
|
|
usb_syncmem(&p->dma,
|
|
|
|
p->offs + offsetof(uhci_td_t, td_link),
|
|
|
|
sizeof(p->td.td_link),
|
|
|
|
BUS_DMASYNC_PREREAD);
|
|
|
|
if ((td_link & UHCI_PTR_T) == 0) {
|
2013-01-30 20:01:45 +04:00
|
|
|
p->td.td_link = htole32(UHCI_PTR_T);
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&p->dma,
|
|
|
|
p->offs + offsetof(uhci_td_t, td_link),
|
|
|
|
sizeof(p->td.td_link),
|
|
|
|
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
delay(UHCI_QH_REMOVE_DELAY);
|
|
|
|
|
1998-07-12 23:51:55 +04:00
|
|
|
for (; std != stdend; std = p) {
|
1999-08-23 03:19:56 +04:00
|
|
|
p = std->link.std;
|
1998-07-12 23:51:55 +04:00
|
|
|
uhci_free_std(sc, std);
|
|
|
|
}
|
|
|
|
}
|
2016-04-23 13:15:27 +03:00
|
|
|
#endif
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
int
|
|
|
|
uhci_alloc_std_chain(uhci_softc_t *sc, struct usbd_xfer *xfer, int len,
|
|
|
|
int rd, uhci_soft_td_t **sp)
|
1998-07-12 23:51:55 +04:00
|
|
|
{
|
2016-04-23 13:15:27 +03:00
|
|
|
struct uhci_xfer *uxfer = UHCI_XFER2UXFER(xfer);
|
|
|
|
uint16_t flags = xfer->ux_flags;
|
|
|
|
uhci_soft_td_t *p;
|
|
|
|
|
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
1998-07-12 23:51:55 +04:00
|
|
|
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTFN(8, "xfer=%#jx pipe=%#jx", (uintptr_t)xfer,
|
|
|
|
(uintptr_t)xfer->ux_pipe, 0, 0);
|
2012-06-10 10:15:52 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
ASSERT_SLEEPABLE();
|
|
|
|
KASSERT(sp);
|
2012-06-10 10:15:52 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
int maxp = UGETW(xfer->ux_pipe->up_endpoint->ue_edesc->wMaxPacketSize);
|
1998-07-12 23:51:55 +04:00
|
|
|
if (maxp == 0) {
|
2016-04-23 13:15:27 +03:00
|
|
|
printf("%s: maxp=0\n", __func__);
|
|
|
|
return EINVAL;
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
2020-03-15 16:59:20 +03:00
|
|
|
size_t ntd = howmany(len, maxp);
|
2020-05-25 16:55:31 +03:00
|
|
|
/*
|
|
|
|
* if our transfer is bigger than PAGE_SIZE and maxp not a factor of
|
|
|
|
* PAGE_SIZE then we will need another TD per page.
|
|
|
|
*/
|
|
|
|
if (len > PAGE_SIZE && (PAGE_SIZE % maxp) != 0) {
|
|
|
|
ntd += howmany(len, PAGE_SIZE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Might need one more TD if we're writing a ZLP
|
|
|
|
*/
|
2016-04-23 13:15:27 +03:00
|
|
|
if (!rd && (flags & USBD_FORCE_SHORT_XFER)) {
|
2000-01-16 16:12:05 +03:00
|
|
|
ntd++;
|
2016-04-23 13:15:27 +03:00
|
|
|
}
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTFN(10, "maxp=%jd ntd=%jd", maxp, ntd, 0, 0);
|
2016-04-23 13:15:27 +03:00
|
|
|
|
|
|
|
uxfer->ux_stds = NULL;
|
|
|
|
uxfer->ux_nstd = ntd;
|
2000-01-16 16:12:05 +03:00
|
|
|
if (ntd == 0) {
|
2016-04-23 13:15:27 +03:00
|
|
|
*sp = NULL;
|
|
|
|
DPRINTF("ntd=0", 0, 0, 0, 0);
|
|
|
|
return 0;
|
2000-01-16 16:12:05 +03:00
|
|
|
}
|
2016-04-23 13:15:27 +03:00
|
|
|
uxfer->ux_stds = kmem_alloc(sizeof(uhci_soft_td_t *) * ntd,
|
|
|
|
KM_SLEEP);
|
|
|
|
|
2017-07-14 13:37:05 +03:00
|
|
|
for (int i = 0; i < ntd; i++) {
|
1998-07-12 23:51:55 +04:00
|
|
|
p = uhci_alloc_std(sc);
|
1999-11-12 03:34:57 +03:00
|
|
|
if (p == NULL) {
|
2017-07-14 13:37:05 +03:00
|
|
|
if (i != 0) {
|
|
|
|
uxfer->ux_nstd = i;
|
|
|
|
uhci_free_stds(sc, uxfer);
|
|
|
|
}
|
2016-04-23 13:15:27 +03:00
|
|
|
kmem_free(uxfer->ux_stds,
|
|
|
|
sizeof(uhci_soft_td_t *) * ntd);
|
|
|
|
return ENOMEM;
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
2016-04-23 13:15:27 +03:00
|
|
|
uxfer->ux_stds[i] = p;
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
*sp = uxfer->ux_stds[0];
|
1999-08-18 00:59:04 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
return 0;
|
1999-08-18 00:59:04 +04:00
|
|
|
}
|
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
Static void
|
|
|
|
uhci_free_stds(uhci_softc_t *sc, struct uhci_xfer *ux)
|
1998-12-28 23:13:59 +03:00
|
|
|
{
|
2016-04-23 13:15:27 +03:00
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
|
|
|
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTFN(8, "ux=%#jx", (uintptr_t)ux, 0, 0, 0);
|
1998-12-28 23:13:59 +03:00
|
|
|
|
2012-06-10 10:15:52 +04:00
|
|
|
mutex_enter(&sc->sc_lock);
|
2016-04-23 13:15:27 +03:00
|
|
|
for (size_t i = 0; i < ux->ux_nstd; i++) {
|
|
|
|
uhci_soft_td_t *std = ux->ux_stds[i];
|
|
|
|
#ifdef DIAGNOSTIC
|
|
|
|
if (le32toh(std->td.td_token) == TD_IS_FREE) {
|
|
|
|
printf("%s: freeing free TD %p\n", __func__, std);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
std->td.td_token = htole32(TD_IS_FREE);
|
|
|
|
#endif
|
|
|
|
ux->ux_stds[i]->link.std = sc->sc_freetds;
|
|
|
|
sc->sc_freetds = std;
|
|
|
|
}
|
2012-06-10 10:15:52 +04:00
|
|
|
mutex_exit(&sc->sc_lock);
|
1998-12-28 23:13:59 +03:00
|
|
|
}
|
|
|
|
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
Static void
|
|
|
|
uhci_reset_std_chain(uhci_softc_t *sc, struct usbd_xfer *xfer,
|
|
|
|
int length, int isread, int *toggle, uhci_soft_td_t **lstd)
|
|
|
|
{
|
|
|
|
struct uhci_xfer *uxfer = UHCI_XFER2UXFER(xfer);
|
|
|
|
struct usbd_pipe *pipe = xfer->ux_pipe;
|
|
|
|
usb_dma_t *dma = &xfer->ux_dmabuf;
|
|
|
|
uint16_t flags = xfer->ux_flags;
|
|
|
|
uhci_soft_td_t *std, *prev;
|
|
|
|
int len = length;
|
|
|
|
int tog = *toggle;
|
|
|
|
int maxp;
|
|
|
|
uint32_t status;
|
2020-05-25 16:55:31 +03:00
|
|
|
size_t i, offs;
|
2000-01-26 13:04:38 +03:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTFN(8, "xfer=%#jx len %jd isread %jd toggle %jd", (uintptr_t)xfer,
|
2016-04-23 13:15:27 +03:00
|
|
|
len, isread, *toggle);
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
KASSERT(len != 0 || (!isread && (flags & USBD_FORCE_SHORT_XFER)));
|
2012-06-10 10:15:52 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
maxp = UGETW(pipe->up_endpoint->ue_edesc->wMaxPacketSize);
|
|
|
|
KASSERT(maxp != 0);
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
int addr = xfer->ux_pipe->up_dev->ud_addr;
|
|
|
|
int endpt = xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress;
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
status = UHCI_TD_ZERO_ACTLEN(UHCI_TD_SET_ERRCNT(3) | UHCI_TD_ACTIVE);
|
|
|
|
if (pipe->up_dev->ud_speed == USB_SPEED_LOW)
|
|
|
|
status |= UHCI_TD_LS;
|
|
|
|
if (flags & USBD_SHORT_XFER_OK)
|
|
|
|
status |= UHCI_TD_SPD;
|
|
|
|
usb_syncmem(dma, 0, len,
|
|
|
|
isread ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
|
|
|
|
std = prev = NULL;
|
2020-05-25 16:55:31 +03:00
|
|
|
for (offs = i = 0; len != 0 && i < uxfer->ux_nstd; i++, prev = std) {
|
2016-04-23 13:15:27 +03:00
|
|
|
int l = len;
|
|
|
|
std = uxfer->ux_stds[i];
|
2020-05-25 16:55:31 +03:00
|
|
|
|
|
|
|
const bus_addr_t sbp = DMAADDR(dma, offs);
|
|
|
|
const bus_addr_t ebp = DMAADDR(dma, offs + l - 1);
|
|
|
|
if (((sbp ^ ebp) & ~PAGE_MASK) != 0)
|
|
|
|
l = PAGE_SIZE - (DMAADDR(dma, offs) & PAGE_MASK);
|
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
if (l > maxp)
|
|
|
|
l = maxp;
|
|
|
|
|
|
|
|
if (prev) {
|
|
|
|
prev->link.std = std;
|
|
|
|
prev->td.td_link = htole32(
|
|
|
|
std->physaddr | UHCI_PTR_VF | UHCI_PTR_TD
|
|
|
|
);
|
|
|
|
usb_syncmem(&prev->dma, prev->offs, sizeof(prev->td),
|
|
|
|
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
|
|
|
|
}
|
|
|
|
|
|
|
|
usb_syncmem(&std->dma, std->offs, sizeof(std->td),
|
|
|
|
BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
|
|
|
|
|
|
|
|
std->td.td_link = htole32(UHCI_PTR_T | UHCI_PTR_VF | UHCI_PTR_TD);
|
|
|
|
std->td.td_status = htole32(status);
|
|
|
|
std->td.td_token = htole32(
|
|
|
|
UHCI_TD_SET_ENDPT(UE_GET_ADDR(endpt)) |
|
|
|
|
UHCI_TD_SET_DEVADDR(addr) |
|
|
|
|
UHCI_TD_SET_PID(isread ? UHCI_TD_PID_IN : UHCI_TD_PID_OUT) |
|
|
|
|
UHCI_TD_SET_DT(tog) |
|
|
|
|
UHCI_TD_SET_MAXLEN(l)
|
|
|
|
);
|
2020-05-25 16:55:31 +03:00
|
|
|
std->td.td_buffer = htole32(DMAADDR(dma, offs));
|
2016-04-23 13:15:27 +03:00
|
|
|
|
|
|
|
std->link.std = NULL;
|
|
|
|
|
|
|
|
usb_syncmem(&std->dma, std->offs, sizeof(std->td),
|
|
|
|
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
|
|
|
|
tog ^= 1;
|
|
|
|
|
2020-05-25 16:55:31 +03:00
|
|
|
offs += l;
|
2016-04-23 13:15:27 +03:00
|
|
|
len -= l;
|
|
|
|
}
|
|
|
|
KASSERTMSG(len == 0, "xfer %p alen %d len %d mps %d ux_nqtd %zu i %zu",
|
|
|
|
xfer, length, len, maxp, uxfer->ux_nstd, i);
|
|
|
|
|
|
|
|
if (!isread &&
|
|
|
|
(flags & USBD_FORCE_SHORT_XFER) &&
|
|
|
|
length % maxp == 0) {
|
|
|
|
/* Force a 0 length transfer at the end. */
|
|
|
|
KASSERTMSG(i < uxfer->ux_nstd, "i=%zu nstd=%zu", i,
|
|
|
|
uxfer->ux_nstd);
|
|
|
|
std = uxfer->ux_stds[i++];
|
|
|
|
|
|
|
|
std->td.td_link = htole32(UHCI_PTR_T | UHCI_PTR_VF | UHCI_PTR_TD);
|
|
|
|
std->td.td_status = htole32(status);
|
|
|
|
std->td.td_token = htole32(
|
|
|
|
UHCI_TD_SET_ENDPT(UE_GET_ADDR(endpt)) |
|
|
|
|
UHCI_TD_SET_DEVADDR(addr) |
|
|
|
|
UHCI_TD_SET_PID(UHCI_TD_PID_OUT) |
|
|
|
|
UHCI_TD_SET_DT(tog) |
|
|
|
|
UHCI_TD_SET_MAXLEN(0)
|
|
|
|
);
|
|
|
|
std->td.td_buffer = 0;
|
|
|
|
usb_syncmem(&std->dma, std->offs, sizeof(std->td),
|
|
|
|
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
|
|
|
|
|
|
|
|
std->link.std = NULL;
|
|
|
|
if (prev) {
|
|
|
|
prev->link.std = std;
|
|
|
|
prev->td.td_link = htole32(
|
|
|
|
std->physaddr | UHCI_PTR_VF | UHCI_PTR_TD
|
|
|
|
);
|
|
|
|
usb_syncmem(&prev->dma, prev->offs, sizeof(prev->td),
|
|
|
|
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
|
|
|
|
}
|
|
|
|
tog ^= 1;
|
|
|
|
}
|
|
|
|
*lstd = std;
|
|
|
|
*toggle = tog;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
uhci_device_clear_toggle(struct usbd_pipe *pipe)
|
|
|
|
{
|
|
|
|
struct uhci_pipe *upipe = UHCI_PIPE2UPIPE(pipe);
|
|
|
|
upipe->nexttoggle = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
uhci_noop(struct usbd_pipe *pipe)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
uhci_device_bulk_init(struct usbd_xfer *xfer)
|
|
|
|
{
|
|
|
|
uhci_softc_t *sc = UHCI_XFER2SC(xfer);
|
|
|
|
struct uhci_xfer *uxfer = UHCI_XFER2UXFER(xfer);
|
|
|
|
usb_endpoint_descriptor_t *ed = xfer->ux_pipe->up_endpoint->ue_edesc;
|
|
|
|
int endpt = ed->bEndpointAddress;
|
|
|
|
int isread = UE_GET_DIR(endpt) == UE_DIR_IN;
|
|
|
|
int len = xfer->ux_bufsize;
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTFN(3, "xfer=%#jx len=%jd flags=%jd", (uintptr_t)xfer, len,
|
|
|
|
xfer->ux_flags, 0);
|
2016-04-23 13:15:27 +03:00
|
|
|
|
|
|
|
if (sc->sc_dying)
|
|
|
|
return USBD_IOERROR;
|
|
|
|
|
|
|
|
KASSERT(!(xfer->ux_rqflags & URQ_REQUEST));
|
|
|
|
|
|
|
|
uxfer->ux_type = UX_BULK;
|
|
|
|
err = uhci_alloc_std_chain(sc, xfer, len, isread, &uxfer->ux_stdstart);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
#ifdef UHCI_DEBUG
|
|
|
|
if (uhcidebug >= 10) {
|
|
|
|
DPRINTF("--- dump start ---", 0, 0, 0, 0);
|
|
|
|
uhci_dump_tds(uxfer->ux_stdstart);
|
|
|
|
DPRINTF("--- dump end ---", 0, 0, 0, 0);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Static void
|
|
|
|
uhci_device_bulk_fini(struct usbd_xfer *xfer)
|
|
|
|
{
|
|
|
|
uhci_softc_t *sc = UHCI_XFER2SC(xfer);
|
|
|
|
struct uhci_xfer *ux = UHCI_XFER2UXFER(xfer);
|
|
|
|
|
|
|
|
KASSERT(ux->ux_type == UX_BULK);
|
|
|
|
|
2017-07-14 13:37:05 +03:00
|
|
|
if (ux->ux_nstd) {
|
|
|
|
uhci_free_stds(sc, ux);
|
2016-04-23 13:15:27 +03:00
|
|
|
kmem_free(ux->ux_stds, sizeof(uhci_soft_td_t *) * ux->ux_nstd);
|
2017-07-14 13:37:05 +03:00
|
|
|
}
|
2016-04-23 13:15:27 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
usbd_status
|
|
|
|
uhci_device_bulk_transfer(struct usbd_xfer *xfer)
|
|
|
|
{
|
|
|
|
uhci_softc_t *sc = UHCI_XFER2SC(xfer);
|
|
|
|
usbd_status err;
|
|
|
|
|
|
|
|
/* Insert last in queue. */
|
|
|
|
mutex_enter(&sc->sc_lock);
|
|
|
|
err = usb_insert_transfer(xfer);
|
|
|
|
mutex_exit(&sc->sc_lock);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Pipe isn't running (otherwise err would be USBD_INPROG),
|
|
|
|
* so start it first.
|
|
|
|
*/
|
|
|
|
return uhci_device_bulk_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
|
|
|
|
}
|
|
|
|
|
|
|
|
usbd_status
|
|
|
|
uhci_device_bulk_start(struct usbd_xfer *xfer)
|
|
|
|
{
|
|
|
|
struct uhci_pipe *upipe = UHCI_PIPE2UPIPE(xfer->ux_pipe);
|
|
|
|
struct uhci_xfer *ux = UHCI_XFER2UXFER(xfer);
|
|
|
|
uhci_softc_t *sc = UHCI_XFER2SC(xfer);
|
|
|
|
uhci_soft_td_t *data, *dataend;
|
|
|
|
uhci_soft_qh_t *sqh;
|
2018-09-16 23:21:56 +03:00
|
|
|
const bool polling = sc->sc_bus.ub_usepolling;
|
2016-04-23 13:15:27 +03:00
|
|
|
int len;
|
|
|
|
int endpt;
|
|
|
|
int isread;
|
|
|
|
|
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTFN(3, "xfer=%#jx len=%jd flags=%jd", (uintptr_t)xfer,
|
|
|
|
xfer->ux_length, xfer->ux_flags, 0);
|
2016-04-23 13:15:27 +03:00
|
|
|
|
|
|
|
if (sc->sc_dying)
|
|
|
|
return USBD_IOERROR;
|
|
|
|
|
|
|
|
KASSERT(!(xfer->ux_rqflags & URQ_REQUEST));
|
|
|
|
KASSERT(xfer->ux_length <= xfer->ux_bufsize);
|
|
|
|
|
|
|
|
len = xfer->ux_length;
|
|
|
|
endpt = upipe->pipe.up_endpoint->ue_edesc->bEndpointAddress;
|
|
|
|
isread = UE_GET_DIR(endpt) == UE_DIR_IN;
|
|
|
|
sqh = upipe->bulk.sqh;
|
|
|
|
|
|
|
|
/* Take lock here to protect nexttoggle */
|
2018-09-16 23:21:56 +03:00
|
|
|
if (!polling)
|
|
|
|
mutex_enter(&sc->sc_lock);
|
2016-04-23 13:15:27 +03:00
|
|
|
|
|
|
|
uhci_reset_std_chain(sc, xfer, len, isread, &upipe->nexttoggle,
|
|
|
|
&dataend);
|
|
|
|
|
|
|
|
data = ux->ux_stdstart;
|
|
|
|
ux->ux_stdend = dataend;
|
2000-03-16 15:40:51 +03:00
|
|
|
dataend->td.td_status |= htole32(UHCI_TD_IOC);
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&dataend->dma,
|
|
|
|
dataend->offs + offsetof(uhci_td_t, td_status),
|
|
|
|
sizeof(dataend->td.td_status),
|
|
|
|
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
|
|
|
|
|
1999-10-13 12:10:55 +04:00
|
|
|
#ifdef UHCI_DEBUG
|
2016-04-23 13:15:27 +03:00
|
|
|
if (uhcidebug >= 10) {
|
|
|
|
DPRINTF("--- dump start ---", 0, 0, 0, 0);
|
|
|
|
DPRINTFN(10, "before transfer", 0, 0, 0, 0);
|
1999-09-16 01:12:29 +04:00
|
|
|
uhci_dump_tds(data);
|
2016-04-23 13:15:27 +03:00
|
|
|
DPRINTF("--- dump end ---", 0, 0, 0, 0);
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
KASSERT(ux->ux_isdone);
|
1998-07-25 01:09:07 +04:00
|
|
|
#ifdef DIAGNOSTIC
|
2016-04-23 13:15:27 +03:00
|
|
|
ux->ux_isdone = false;
|
1998-07-25 01:09:07 +04:00
|
|
|
#endif
|
1998-07-12 23:51:55 +04:00
|
|
|
|
1999-09-16 01:12:29 +04:00
|
|
|
sqh->elink = data;
|
2000-07-23 23:43:37 +04:00
|
|
|
sqh->qh.qh_elink = htole32(data->physaddr | UHCI_PTR_TD);
|
2008-06-28 21:42:53 +04:00
|
|
|
/* uhci_add_bulk() will do usb_syncmem(sqh) */
|
1998-07-12 23:51:55 +04:00
|
|
|
|
|
|
|
uhci_add_bulk(sc, sqh);
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_add_intr_list(sc, ux);
|
2020-02-12 19:01:00 +03:00
|
|
|
usbd_xfer_schedule_timeout(xfer);
|
2016-04-23 13:15:27 +03:00
|
|
|
xfer->ux_status = USBD_IN_PROGRESS;
|
2018-09-16 23:21:56 +03:00
|
|
|
if (!polling)
|
|
|
|
mutex_exit(&sc->sc_lock);
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
return USBD_IN_PROGRESS;
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Abort a device bulk request. */
|
|
|
|
void
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_device_bulk_abort(struct usbd_xfer *xfer)
|
1998-07-12 23:51:55 +04:00
|
|
|
{
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_softc_t *sc __diagused = UHCI_XFER2SC(xfer);
|
2012-06-10 10:15:52 +04:00
|
|
|
|
|
|
|
KASSERT(mutex_owned(&sc->sc_lock));
|
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
|
|
|
|
2020-02-12 19:01:00 +03:00
|
|
|
usbd_xfer_abort(xfer);
|
1999-08-02 23:30:34 +04:00
|
|
|
}
|
|
|
|
|
2000-03-25 01:57:58 +03:00
|
|
|
/*
|
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
--
#ifdef DIAGNOSTIC -> KASSERT and add another KASSERT
--
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.
2018-08-09 09:26:47 +03:00
|
|
|
* To allow the hardware time to notice we simply wait.
|
2000-03-25 01:57:58 +03:00
|
|
|
*/
|
2020-02-12 19:01:00 +03:00
|
|
|
Static void
|
|
|
|
uhci_abortx(struct usbd_xfer *xfer)
|
1999-08-02 23:30:34 +04:00
|
|
|
{
|
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
--
#ifdef DIAGNOSTIC -> KASSERT and add another KASSERT
--
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.
2018-08-09 09:26:47 +03:00
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
2016-04-23 13:15:27 +03:00
|
|
|
struct uhci_xfer *ux = UHCI_XFER2UXFER(xfer);
|
|
|
|
struct uhci_pipe *upipe = UHCI_PIPE2UPIPE(xfer->ux_pipe);
|
|
|
|
uhci_softc_t *sc = UHCI_XFER2SC(xfer);
|
1999-08-02 23:30:34 +04:00
|
|
|
uhci_soft_td_t *std;
|
|
|
|
|
2020-02-12 19:01:00 +03:00
|
|
|
DPRINTFN(1,"xfer=%#jx", (uintptr_t)xfer, 0, 0, 0);
|
2000-03-25 01:57:58 +03:00
|
|
|
|
2012-06-10 10:15:52 +04:00
|
|
|
KASSERT(mutex_owned(&sc->sc_lock));
|
2016-04-23 13:15:27 +03:00
|
|
|
ASSERT_SLEEPABLE();
|
2012-06-10 10:15:52 +04:00
|
|
|
|
2020-02-12 19:01:00 +03:00
|
|
|
KASSERTMSG((xfer->ux_status == USBD_CANCELLED ||
|
|
|
|
xfer->ux_status == USBD_TIMEOUT),
|
|
|
|
"bad abort status: %d", xfer->ux_status);
|
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
--
#ifdef DIAGNOSTIC -> KASSERT and add another KASSERT
--
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.
2018-08-09 09:26:47 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If we're dying, skip the hardware action and just notify the
|
|
|
|
* software that we're done.
|
|
|
|
*/
|
|
|
|
if (sc->sc_dying) {
|
|
|
|
DPRINTFN(4, "xfer %#jx dying %ju", (uintptr_t)xfer,
|
|
|
|
xfer->ux_status, 0, 0);
|
|
|
|
goto dying;
|
2005-04-30 18:38:40 +04:00
|
|
|
}
|
|
|
|
|
2002-02-11 14:40:33 +03:00
|
|
|
/*
|
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
--
#ifdef DIAGNOSTIC -> KASSERT and add another KASSERT
--
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.
2018-08-09 09:26:47 +03:00
|
|
|
* HC Step 1: Make interrupt routine and hardware ignore xfer.
|
2002-02-11 14:40:33 +03:00
|
|
|
*/
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_del_intr_list(sc, ux);
|
|
|
|
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTF("stop ux=%#jx", (uintptr_t)ux, 0, 0, 0);
|
2016-04-23 13:15:27 +03:00
|
|
|
for (std = ux->ux_stdstart; std != NULL; std = std->link.std) {
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&std->dma,
|
|
|
|
std->offs + offsetof(uhci_td_t, td_status),
|
|
|
|
sizeof(std->td.td_status),
|
|
|
|
BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
|
2000-03-29 05:49:13 +04:00
|
|
|
std->td.td_status &= htole32(~(UHCI_TD_ACTIVE | UHCI_TD_IOC));
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&std->dma,
|
|
|
|
std->offs + offsetof(uhci_td_t, td_status),
|
|
|
|
sizeof(std->td.td_status),
|
|
|
|
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
|
|
|
|
}
|
2000-03-25 01:57:58 +03:00
|
|
|
|
2002-07-12 01:14:24 +04:00
|
|
|
/*
|
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
--
#ifdef DIAGNOSTIC -> KASSERT and add another KASSERT
--
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.
2018-08-09 09:26:47 +03:00
|
|
|
* HC Step 2: Wait until we know hardware has finished any possible
|
|
|
|
* use of the xfer.
|
2002-02-11 14:40:33 +03:00
|
|
|
*/
|
2012-06-10 10:15:52 +04:00
|
|
|
/* Hardware finishes in 1ms */
|
2016-04-23 13:15:27 +03:00
|
|
|
usb_delay_ms_locked(upipe->pipe.up_dev->ud_bus, 2, &sc->sc_lock);
|
2002-07-12 01:14:24 +04:00
|
|
|
|
2002-02-11 14:40:33 +03:00
|
|
|
/*
|
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
--
#ifdef DIAGNOSTIC -> KASSERT and add another KASSERT
--
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.
2018-08-09 09:26:47 +03:00
|
|
|
* HC Step 3: Notify completion to waiting xfers.
|
2002-02-11 14:40:33 +03:00
|
|
|
*/
|
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
--
#ifdef DIAGNOSTIC -> KASSERT and add another KASSERT
--
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.
2018-08-09 09:26:47 +03:00
|
|
|
dying:
|
2000-03-27 13:41:36 +04:00
|
|
|
#ifdef DIAGNOSTIC
|
2016-04-23 13:15:27 +03:00
|
|
|
ux->ux_isdone = true;
|
2000-03-27 13:41:36 +04:00
|
|
|
#endif
|
2000-03-29 05:49:13 +04:00
|
|
|
usb_transfer_complete(xfer);
|
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
--
#ifdef DIAGNOSTIC -> KASSERT and add another KASSERT
--
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.
2018-08-09 09:26:47 +03:00
|
|
|
DPRINTFN(14, "end", 0, 0, 0, 0);
|
|
|
|
|
2012-06-10 10:15:52 +04:00
|
|
|
KASSERT(mutex_owned(&sc->sc_lock));
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Close a device bulk pipe. */
|
|
|
|
void
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_device_bulk_close(struct usbd_pipe *pipe)
|
1998-07-12 23:51:55 +04:00
|
|
|
{
|
2016-04-23 13:15:27 +03:00
|
|
|
struct uhci_pipe *upipe = UHCI_PIPE2UPIPE(pipe);
|
|
|
|
uhci_softc_t *sc = UHCI_PIPE2SC(pipe);
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2012-06-10 10:15:52 +04:00
|
|
|
KASSERT(mutex_owned(&sc->sc_lock));
|
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_free_sqh(sc, upipe->bulk.sqh);
|
2011-05-27 21:19:18 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
pipe->up_endpoint->ue_toggle = upipe->nexttoggle;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
uhci_device_ctrl_init(struct usbd_xfer *xfer)
|
|
|
|
{
|
|
|
|
struct uhci_xfer *uxfer = UHCI_XFER2UXFER(xfer);
|
|
|
|
struct uhci_pipe *upipe = UHCI_PIPE2UPIPE(xfer->ux_pipe);
|
|
|
|
usb_device_request_t *req = &xfer->ux_request;
|
|
|
|
struct usbd_device *dev = upipe->pipe.up_dev;
|
|
|
|
uhci_softc_t *sc = dev->ud_bus->ub_hcpriv;
|
2016-04-25 23:06:51 +03:00
|
|
|
uhci_soft_td_t *data = NULL;
|
2016-04-23 13:15:27 +03:00
|
|
|
int len;
|
|
|
|
usbd_status err;
|
|
|
|
int isread;
|
|
|
|
|
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTFN(3, "xfer=%#jx len=%jd, addr=%jd, endpt=%jd",
|
|
|
|
(uintptr_t)xfer, xfer->ux_bufsize, dev->ud_addr,
|
|
|
|
upipe->pipe.up_endpoint->ue_edesc->bEndpointAddress);
|
2016-04-23 13:15:27 +03:00
|
|
|
|
|
|
|
isread = req->bmRequestType & UT_READ;
|
|
|
|
len = xfer->ux_bufsize;
|
|
|
|
|
|
|
|
uxfer->ux_type = UX_CTRL;
|
|
|
|
/* Set up data transaction */
|
|
|
|
if (len != 0) {
|
|
|
|
err = uhci_alloc_std_chain(sc, xfer, len, isread, &data);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
/* Set up interrupt info. */
|
|
|
|
uxfer->ux_setup = upipe->ctrl.setup;
|
|
|
|
uxfer->ux_stat = upipe->ctrl.stat;
|
|
|
|
uxfer->ux_data = data;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Static void
|
|
|
|
uhci_device_ctrl_fini(struct usbd_xfer *xfer)
|
|
|
|
{
|
|
|
|
uhci_softc_t *sc = UHCI_XFER2SC(xfer);
|
|
|
|
struct uhci_xfer *ux = UHCI_XFER2UXFER(xfer);
|
|
|
|
|
|
|
|
KASSERT(ux->ux_type == UX_CTRL);
|
|
|
|
|
2017-07-14 13:37:05 +03:00
|
|
|
if (ux->ux_nstd) {
|
|
|
|
uhci_free_stds(sc, ux);
|
2016-04-23 13:15:27 +03:00
|
|
|
kmem_free(ux->ux_stds, sizeof(uhci_soft_td_t *) * ux->ux_nstd);
|
2017-07-14 13:37:05 +03:00
|
|
|
}
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
usbd_status
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_device_ctrl_transfer(struct usbd_xfer *xfer)
|
1998-12-28 23:13:59 +03:00
|
|
|
{
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_softc_t *sc = UHCI_XFER2SC(xfer);
|
1999-11-12 03:34:57 +03:00
|
|
|
usbd_status err;
|
1998-12-28 23:13:59 +03:00
|
|
|
|
1999-09-14 01:33:25 +04:00
|
|
|
/* Insert last in queue. */
|
2012-06-10 10:15:52 +04:00
|
|
|
mutex_enter(&sc->sc_lock);
|
1999-11-12 03:34:57 +03:00
|
|
|
err = usb_insert_transfer(xfer);
|
2012-06-10 10:15:52 +04:00
|
|
|
mutex_exit(&sc->sc_lock);
|
1999-11-12 03:34:57 +03:00
|
|
|
if (err)
|
2016-04-23 13:15:27 +03:00
|
|
|
return err;
|
1999-09-14 01:33:25 +04:00
|
|
|
|
2002-02-03 21:15:20 +03:00
|
|
|
/*
|
2000-03-25 01:57:58 +03:00
|
|
|
* Pipe isn't running (otherwise err would be USBD_INPROG),
|
|
|
|
* so start it first.
|
1999-11-19 02:32:25 +03:00
|
|
|
*/
|
2016-04-23 13:15:27 +03:00
|
|
|
return uhci_device_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
|
1998-12-28 23:13:59 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
usbd_status
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_device_ctrl_start(struct usbd_xfer *xfer)
|
|
|
|
{
|
|
|
|
uhci_softc_t *sc = UHCI_XFER2SC(xfer);
|
|
|
|
struct uhci_xfer *uxfer = UHCI_XFER2UXFER(xfer);
|
|
|
|
struct uhci_pipe *upipe = UHCI_PIPE2UPIPE(xfer->ux_pipe);
|
|
|
|
usb_device_request_t *req = &xfer->ux_request;
|
|
|
|
struct usbd_device *dev = upipe->pipe.up_dev;
|
|
|
|
int addr = dev->ud_addr;
|
|
|
|
int endpt = upipe->pipe.up_endpoint->ue_edesc->bEndpointAddress;
|
|
|
|
uhci_soft_td_t *setup, *stat, *next, *dataend;
|
|
|
|
uhci_soft_qh_t *sqh;
|
2018-09-16 23:21:56 +03:00
|
|
|
const bool polling = sc->sc_bus.ub_usepolling;
|
2016-04-23 13:15:27 +03:00
|
|
|
int len;
|
|
|
|
int isread;
|
|
|
|
|
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2000-01-26 13:04:38 +03:00
|
|
|
if (sc->sc_dying)
|
2016-04-23 13:15:27 +03:00
|
|
|
return USBD_IOERROR;
|
|
|
|
|
|
|
|
KASSERT(xfer->ux_rqflags & URQ_REQUEST);
|
|
|
|
|
2020-03-14 05:35:33 +03:00
|
|
|
DPRINTFN(3, "type=0x%02jx, request=0x%02jx, "
|
|
|
|
"wValue=0x%04jx, wIndex=0x%04jx",
|
2016-04-23 13:15:27 +03:00
|
|
|
req->bmRequestType, req->bRequest, UGETW(req->wValue),
|
|
|
|
UGETW(req->wIndex));
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTFN(3, "len=%jd, addr=%jd, endpt=%jd",
|
2016-04-23 13:15:27 +03:00
|
|
|
UGETW(req->wLength), dev->ud_addr, endpt, 0);
|
|
|
|
|
|
|
|
isread = req->bmRequestType & UT_READ;
|
|
|
|
len = UGETW(req->wLength);
|
|
|
|
|
|
|
|
setup = upipe->ctrl.setup;
|
|
|
|
stat = upipe->ctrl.stat;
|
|
|
|
sqh = upipe->ctrl.sqh;
|
|
|
|
|
|
|
|
memcpy(KERNADDR(&upipe->ctrl.reqdma, 0), req, sizeof(*req));
|
|
|
|
usb_syncmem(&upipe->ctrl.reqdma, 0, sizeof(*req), BUS_DMASYNC_PREWRITE);
|
|
|
|
|
2018-09-16 23:21:56 +03:00
|
|
|
if (!polling)
|
|
|
|
mutex_enter(&sc->sc_lock);
|
2016-04-23 13:15:27 +03:00
|
|
|
|
|
|
|
/* Set up data transaction */
|
|
|
|
if (len != 0) {
|
|
|
|
upipe->nexttoggle = 1;
|
|
|
|
next = uxfer->ux_data;
|
|
|
|
uhci_reset_std_chain(sc, xfer, len, isread,
|
|
|
|
&upipe->nexttoggle, &dataend);
|
|
|
|
dataend->link.std = stat;
|
|
|
|
dataend->td.td_link = htole32(stat->physaddr | UHCI_PTR_TD);
|
|
|
|
usb_syncmem(&dataend->dma,
|
|
|
|
dataend->offs + offsetof(uhci_td_t, td_link),
|
|
|
|
sizeof(dataend->td.td_link),
|
|
|
|
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
|
|
|
|
} else {
|
|
|
|
next = stat;
|
|
|
|
}
|
|
|
|
|
|
|
|
const uint32_t status = UHCI_TD_ZERO_ACTLEN(
|
|
|
|
UHCI_TD_SET_ERRCNT(3) |
|
|
|
|
UHCI_TD_ACTIVE |
|
|
|
|
(dev->ud_speed == USB_SPEED_LOW ? UHCI_TD_LS : 0)
|
|
|
|
);
|
|
|
|
setup->link.std = next;
|
|
|
|
setup->td.td_link = htole32(next->physaddr | UHCI_PTR_TD);
|
|
|
|
setup->td.td_status = htole32(status);
|
|
|
|
setup->td.td_token = htole32(UHCI_TD_SETUP(sizeof(*req), endpt, addr));
|
|
|
|
setup->td.td_buffer = htole32(DMAADDR(&upipe->ctrl.reqdma, 0));
|
|
|
|
|
|
|
|
usb_syncmem(&setup->dma, setup->offs, sizeof(setup->td),
|
|
|
|
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
|
|
|
|
|
|
|
|
stat->link.std = NULL;
|
|
|
|
stat->td.td_link = htole32(UHCI_PTR_T);
|
|
|
|
stat->td.td_status = htole32(status | UHCI_TD_IOC);
|
|
|
|
stat->td.td_token =
|
|
|
|
htole32(isread ? UHCI_TD_OUT(0, endpt, addr, 1) :
|
|
|
|
UHCI_TD_IN (0, endpt, addr, 1));
|
|
|
|
stat->td.td_buffer = htole32(0);
|
|
|
|
usb_syncmem(&stat->dma, stat->offs, sizeof(stat->td),
|
|
|
|
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
|
|
|
|
|
|
|
|
#ifdef UHCI_DEBUG
|
|
|
|
if (uhcidebug >= 10) {
|
|
|
|
DPRINTF("--- dump start ---", 0, 0, 0, 0);
|
|
|
|
DPRINTF("before transfer", 0, 0, 0, 0);
|
|
|
|
uhci_dump_tds(setup);
|
|
|
|
DPRINTF("--- dump end ---", 0, 0, 0, 0);
|
|
|
|
}
|
|
|
|
#endif
|
2000-01-26 13:04:38 +03:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
/* Set up interrupt info. */
|
|
|
|
uxfer->ux_setup = setup;
|
|
|
|
uxfer->ux_stat = stat;
|
|
|
|
KASSERT(uxfer->ux_isdone);
|
1999-09-09 16:26:43 +04:00
|
|
|
#ifdef DIAGNOSTIC
|
2016-04-23 13:15:27 +03:00
|
|
|
uxfer->ux_isdone = false;
|
1999-09-09 16:26:43 +04:00
|
|
|
#endif
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
sqh->elink = setup;
|
|
|
|
sqh->qh.qh_elink = htole32(setup->physaddr | UHCI_PTR_TD);
|
|
|
|
/* uhci_add_?s_ctrl() will do usb_syncmem(sqh) */
|
|
|
|
|
|
|
|
if (dev->ud_speed == USB_SPEED_LOW)
|
|
|
|
uhci_add_ls_ctrl(sc, sqh);
|
|
|
|
else
|
|
|
|
uhci_add_hs_ctrl(sc, sqh);
|
|
|
|
uhci_add_intr_list(sc, uxfer);
|
|
|
|
#ifdef UHCI_DEBUG
|
|
|
|
if (uhcidebug >= 12) {
|
|
|
|
uhci_soft_td_t *std;
|
|
|
|
uhci_soft_qh_t *xqh;
|
|
|
|
uhci_soft_qh_t *sxqh;
|
|
|
|
int maxqh = 0;
|
|
|
|
uhci_physaddr_t link;
|
|
|
|
DPRINTFN(12, "--- dump start ---", 0, 0, 0, 0);
|
|
|
|
DPRINTFN(12, "follow from [0]", 0, 0, 0, 0);
|
|
|
|
for (std = sc->sc_vframes[0].htd, link = 0;
|
|
|
|
(link & UHCI_PTR_QH) == 0;
|
|
|
|
std = std->link.std) {
|
|
|
|
link = le32toh(std->td.td_link);
|
|
|
|
uhci_dump_td(std);
|
|
|
|
}
|
|
|
|
sxqh = (uhci_soft_qh_t *)std;
|
|
|
|
uhci_dump_qh(sxqh);
|
|
|
|
for (xqh = sxqh;
|
|
|
|
xqh != NULL;
|
|
|
|
xqh = (maxqh++ == 5 || xqh->hlink == sxqh ||
|
|
|
|
xqh->hlink == xqh ? NULL : xqh->hlink)) {
|
|
|
|
uhci_dump_qh(xqh);
|
|
|
|
}
|
|
|
|
DPRINTFN(12, "Enqueued QH:", 0, 0, 0, 0);
|
|
|
|
uhci_dump_qh(sqh);
|
|
|
|
uhci_dump_tds(sqh->elink);
|
|
|
|
DPRINTF("--- dump end ---", 0, 0, 0, 0);
|
|
|
|
}
|
|
|
|
#endif
|
2020-02-12 19:01:00 +03:00
|
|
|
usbd_xfer_schedule_timeout(xfer);
|
2016-04-23 13:15:27 +03:00
|
|
|
xfer->ux_status = USBD_IN_PROGRESS;
|
2018-09-16 23:21:56 +03:00
|
|
|
if (!polling)
|
|
|
|
mutex_exit(&sc->sc_lock);
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
return USBD_IN_PROGRESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
uhci_device_intr_init(struct usbd_xfer *xfer)
|
|
|
|
{
|
|
|
|
uhci_softc_t *sc = UHCI_XFER2SC(xfer);
|
|
|
|
struct uhci_xfer *ux = UHCI_XFER2UXFER(xfer);
|
|
|
|
usb_endpoint_descriptor_t *ed = xfer->ux_pipe->up_endpoint->ue_edesc;
|
|
|
|
int endpt = ed->bEndpointAddress;
|
|
|
|
int isread = UE_GET_DIR(endpt) == UE_DIR_IN;
|
|
|
|
int len = xfer->ux_bufsize;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
|
|
|
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTFN(3, "xfer=%#jx len=%jd flags=%jd", (uintptr_t)xfer,
|
|
|
|
xfer->ux_length, xfer->ux_flags, 0);
|
2016-04-23 13:15:27 +03:00
|
|
|
|
|
|
|
KASSERT(!(xfer->ux_rqflags & URQ_REQUEST));
|
|
|
|
KASSERT(len != 0);
|
|
|
|
|
|
|
|
ux->ux_type = UX_INTR;
|
|
|
|
ux->ux_nstd = 0;
|
|
|
|
err = uhci_alloc_std_chain(sc, xfer, len, isread, &ux->ux_stdstart);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
Static void
|
|
|
|
uhci_device_intr_fini(struct usbd_xfer *xfer)
|
|
|
|
{
|
|
|
|
uhci_softc_t *sc = UHCI_XFER2SC(xfer);
|
|
|
|
struct uhci_xfer *ux = UHCI_XFER2UXFER(xfer);
|
|
|
|
|
|
|
|
KASSERT(ux->ux_type == UX_INTR);
|
|
|
|
|
2017-07-14 13:37:05 +03:00
|
|
|
if (ux->ux_nstd) {
|
|
|
|
uhci_free_stds(sc, ux);
|
2016-04-23 13:15:27 +03:00
|
|
|
kmem_free(ux->ux_stds, sizeof(uhci_soft_td_t *) * ux->ux_nstd);
|
2017-07-14 13:37:05 +03:00
|
|
|
}
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
usbd_status
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_device_intr_transfer(struct usbd_xfer *xfer)
|
1998-12-28 23:13:59 +03:00
|
|
|
{
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_softc_t *sc = UHCI_XFER2SC(xfer);
|
1999-11-12 03:34:57 +03:00
|
|
|
usbd_status err;
|
1998-12-28 23:13:59 +03:00
|
|
|
|
1999-09-14 01:33:25 +04:00
|
|
|
/* Insert last in queue. */
|
2012-06-10 10:15:52 +04:00
|
|
|
mutex_enter(&sc->sc_lock);
|
1999-11-12 03:34:57 +03:00
|
|
|
err = usb_insert_transfer(xfer);
|
2012-06-10 10:15:52 +04:00
|
|
|
mutex_exit(&sc->sc_lock);
|
1999-11-12 03:34:57 +03:00
|
|
|
if (err)
|
2016-04-23 13:15:27 +03:00
|
|
|
return err;
|
1999-09-14 01:33:25 +04:00
|
|
|
|
2002-02-03 21:15:20 +03:00
|
|
|
/*
|
2000-03-25 01:57:58 +03:00
|
|
|
* Pipe isn't running (otherwise err would be USBD_INPROG),
|
|
|
|
* so start it first.
|
1999-11-19 02:32:25 +03:00
|
|
|
*/
|
2016-04-23 13:15:27 +03:00
|
|
|
return uhci_device_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
|
1998-12-28 23:13:59 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
usbd_status
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_device_intr_start(struct usbd_xfer *xfer)
|
1998-07-12 23:51:55 +04:00
|
|
|
{
|
2016-04-23 13:15:27 +03:00
|
|
|
struct uhci_xfer *ux = UHCI_XFER2UXFER(xfer);
|
|
|
|
struct uhci_pipe *upipe = UHCI_PIPE2UPIPE(xfer->ux_pipe);
|
|
|
|
uhci_softc_t *sc = UHCI_XFER2SC(xfer);
|
1999-09-16 01:12:29 +04:00
|
|
|
uhci_soft_td_t *data, *dataend;
|
1998-07-12 23:51:55 +04:00
|
|
|
uhci_soft_qh_t *sqh;
|
2018-09-16 23:21:56 +03:00
|
|
|
const bool polling = sc->sc_bus.ub_usepolling;
|
2005-04-29 23:15:13 +04:00
|
|
|
int isread, endpt;
|
2012-06-10 10:15:52 +04:00
|
|
|
int i;
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2000-01-26 13:04:38 +03:00
|
|
|
if (sc->sc_dying)
|
2016-04-23 13:15:27 +03:00
|
|
|
return USBD_IOERROR;
|
2000-01-26 13:04:38 +03:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
1998-07-12 23:51:55 +04:00
|
|
|
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTFN(3, "xfer=%#jx len=%jd flags=%jd", (uintptr_t)xfer,
|
|
|
|
xfer->ux_length, xfer->ux_flags, 0);
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
KASSERT(!(xfer->ux_rqflags & URQ_REQUEST));
|
|
|
|
KASSERT(xfer->ux_length <= xfer->ux_bufsize);
|
2012-06-10 10:15:52 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
endpt = upipe->pipe.up_endpoint->ue_edesc->bEndpointAddress;
|
2005-04-29 23:15:13 +04:00
|
|
|
isread = UE_GET_DIR(endpt) == UE_DIR_IN;
|
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
data = ux->ux_stdstart;
|
2005-04-29 23:15:13 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
KASSERT(ux->ux_isdone);
|
|
|
|
#ifdef DIAGNOSTIC
|
|
|
|
ux->ux_isdone = false;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Take lock to protect nexttoggle */
|
2018-09-16 23:21:56 +03:00
|
|
|
if (!polling)
|
2017-11-17 00:54:51 +03:00
|
|
|
mutex_enter(&sc->sc_lock);
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_reset_std_chain(sc, xfer, xfer->ux_length, isread,
|
|
|
|
&upipe->nexttoggle, &dataend);
|
2012-06-10 10:15:52 +04:00
|
|
|
|
2000-03-16 15:40:51 +03:00
|
|
|
dataend->td.td_status |= htole32(UHCI_TD_IOC);
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&dataend->dma,
|
|
|
|
dataend->offs + offsetof(uhci_td_t, td_status),
|
|
|
|
sizeof(dataend->td.td_status),
|
|
|
|
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
|
2016-04-23 13:15:27 +03:00
|
|
|
ux->ux_stdend = dataend;
|
1998-07-12 23:51:55 +04:00
|
|
|
|
1999-10-13 12:10:55 +04:00
|
|
|
#ifdef UHCI_DEBUG
|
2016-04-23 13:15:27 +03:00
|
|
|
if (uhcidebug >= 10) {
|
|
|
|
DPRINTF("--- dump start ---", 0, 0, 0, 0);
|
1999-09-16 01:12:29 +04:00
|
|
|
uhci_dump_tds(data);
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_dump_qh(upipe->intr.qhs[0]);
|
|
|
|
DPRINTF("--- dump end ---", 0, 0, 0, 0);
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTFN(10, "qhs[0]=%#jx", (uintptr_t)upipe->intr.qhs[0], 0, 0, 0);
|
2016-04-23 13:15:27 +03:00
|
|
|
for (i = 0; i < upipe->intr.npoll; i++) {
|
|
|
|
sqh = upipe->intr.qhs[i];
|
1999-09-16 01:12:29 +04:00
|
|
|
sqh->elink = data;
|
2000-07-23 23:43:37 +04:00
|
|
|
sqh->qh.qh_elink = htole32(data->physaddr | UHCI_PTR_TD);
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&sqh->dma,
|
|
|
|
sqh->offs + offsetof(uhci_qh_t, qh_elink),
|
|
|
|
sizeof(sqh->qh.qh_elink),
|
|
|
|
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_add_intr_list(sc, ux);
|
|
|
|
xfer->ux_status = USBD_IN_PROGRESS;
|
2018-09-16 23:21:56 +03:00
|
|
|
if (!polling)
|
2017-11-17 00:54:51 +03:00
|
|
|
mutex_exit(&sc->sc_lock);
|
1998-07-12 23:51:55 +04:00
|
|
|
|
1999-10-13 12:10:55 +04:00
|
|
|
#ifdef UHCI_DEBUG
|
2016-04-23 13:15:27 +03:00
|
|
|
if (uhcidebug >= 10) {
|
|
|
|
DPRINTF("--- dump start ---", 0, 0, 0, 0);
|
1999-09-16 01:12:29 +04:00
|
|
|
uhci_dump_tds(data);
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_dump_qh(upipe->intr.qhs[0]);
|
|
|
|
DPRINTF("--- dump end ---", 0, 0, 0, 0);
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
return USBD_IN_PROGRESS;
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Abort a device control request. */
|
|
|
|
void
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_device_ctrl_abort(struct usbd_xfer *xfer)
|
1998-07-12 23:51:55 +04:00
|
|
|
{
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_softc_t *sc __diagused = UHCI_XFER2SC(xfer);
|
2012-06-10 10:15:52 +04:00
|
|
|
|
|
|
|
KASSERT(mutex_owned(&sc->sc_lock));
|
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
2020-02-12 19:01:00 +03:00
|
|
|
usbd_xfer_abort(xfer);
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Close a device control pipe. */
|
|
|
|
void
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_device_ctrl_close(struct usbd_pipe *pipe)
|
1998-07-12 23:51:55 +04:00
|
|
|
{
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_softc_t *sc = UHCI_PIPE2SC(pipe);
|
|
|
|
struct uhci_pipe *upipe = UHCI_PIPE2UPIPE(pipe);
|
|
|
|
|
|
|
|
uhci_free_sqh(sc, upipe->ctrl.sqh);
|
|
|
|
uhci_free_std_locked(sc, upipe->ctrl.setup);
|
|
|
|
uhci_free_std_locked(sc, upipe->ctrl.stat);
|
|
|
|
|
2020-02-21 15:41:29 +03:00
|
|
|
usb_freemem(&sc->sc_bus, &upipe->ctrl.reqdma);
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Abort a device interrupt request. */
|
|
|
|
void
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_device_intr_abort(struct usbd_xfer *xfer)
|
1998-07-12 23:51:55 +04:00
|
|
|
{
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_softc_t *sc __diagused = UHCI_XFER2SC(xfer);
|
2012-06-10 10:15:52 +04:00
|
|
|
|
|
|
|
KASSERT(mutex_owned(&sc->sc_lock));
|
2016-04-23 13:15:27 +03:00
|
|
|
KASSERT(xfer->ux_pipe->up_intrxfer == xfer);
|
2012-06-10 10:15:52 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTF("xfer=%#jx", (uintptr_t)xfer, 0, 0, 0);
|
2014-08-05 10:35:24 +04:00
|
|
|
|
2020-02-12 19:01:00 +03:00
|
|
|
usbd_xfer_abort(xfer);
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Close a device interrupt pipe. */
|
|
|
|
void
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_device_intr_close(struct usbd_pipe *pipe)
|
1998-07-12 23:51:55 +04:00
|
|
|
{
|
2016-04-23 13:15:27 +03:00
|
|
|
struct uhci_pipe *upipe = UHCI_PIPE2UPIPE(pipe);
|
|
|
|
uhci_softc_t *sc = UHCI_PIPE2SC(pipe);
|
2000-03-25 01:57:58 +03:00
|
|
|
int i, npoll;
|
2012-06-10 10:15:52 +04:00
|
|
|
|
|
|
|
KASSERT(mutex_owned(&sc->sc_lock));
|
1998-07-12 23:51:55 +04:00
|
|
|
|
|
|
|
/* Unlink descriptors from controller data structures. */
|
2016-04-23 13:15:27 +03:00
|
|
|
npoll = upipe->intr.npoll;
|
1998-07-12 23:51:55 +04:00
|
|
|
for (i = 0; i < npoll; i++)
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_remove_intr(sc, upipe->intr.qhs[i]);
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2002-02-03 21:15:20 +03:00
|
|
|
/*
|
1998-07-12 23:51:55 +04:00
|
|
|
* We now have to wait for any activity on the physical
|
|
|
|
* descriptors to stop.
|
|
|
|
*/
|
2012-06-10 10:15:52 +04:00
|
|
|
usb_delay_ms_locked(&sc->sc_bus, 2, &sc->sc_lock);
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2016-03-13 10:01:43 +03:00
|
|
|
for (i = 0; i < npoll; i++)
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_free_sqh(sc, upipe->intr.qhs[i]);
|
|
|
|
kmem_free(upipe->intr.qhs, npoll * sizeof(uhci_soft_qh_t *));
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
int
|
|
|
|
uhci_device_isoc_init(struct usbd_xfer *xfer)
|
|
|
|
{
|
|
|
|
struct uhci_xfer *ux = UHCI_XFER2UXFER(xfer);
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
KASSERT(!(xfer->ux_rqflags & URQ_REQUEST));
|
|
|
|
KASSERT(xfer->ux_nframes != 0);
|
|
|
|
KASSERT(ux->ux_isdone);
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
ux->ux_type = UX_ISOC;
|
|
|
|
return 0;
|
|
|
|
}
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
Static void
|
|
|
|
uhci_device_isoc_fini(struct usbd_xfer *xfer)
|
|
|
|
{
|
2016-04-23 16:14:52 +03:00
|
|
|
struct uhci_xfer *ux __diagused = UHCI_XFER2UXFER(xfer);
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
KASSERT(ux->ux_type == UX_ISOC);
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
|
1998-12-28 23:13:59 +03:00
|
|
|
usbd_status
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_device_isoc_transfer(struct usbd_xfer *xfer)
|
1999-09-09 16:26:43 +04:00
|
|
|
{
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_softc_t *sc = UHCI_XFER2SC(xfer);
|
|
|
|
usbd_status err __diagused;
|
1999-09-09 16:26:43 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTFN(5, "xfer=%#jx", (uintptr_t)xfer, 0, 0, 0);
|
1999-09-09 16:26:43 +04:00
|
|
|
|
|
|
|
/* Put it on our queue, */
|
2012-06-10 10:15:52 +04:00
|
|
|
mutex_enter(&sc->sc_lock);
|
1999-11-12 03:34:57 +03:00
|
|
|
err = usb_insert_transfer(xfer);
|
2012-06-10 10:15:52 +04:00
|
|
|
mutex_exit(&sc->sc_lock);
|
1999-09-09 16:26:43 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
KASSERT(err == USBD_NORMAL_COMPLETION);
|
1999-09-09 16:26:43 +04:00
|
|
|
|
|
|
|
/* insert into schedule, */
|
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
struct uhci_pipe *upipe = UHCI_PIPE2UPIPE(xfer->ux_pipe);
|
|
|
|
struct uhci_xfer *ux = UHCI_XFER2UXFER(xfer);
|
|
|
|
struct isoc *isoc = &upipe->isoc;
|
|
|
|
uhci_soft_td_t *std = NULL;
|
|
|
|
uint32_t buf, len, status, offs;
|
2012-06-10 10:15:52 +04:00
|
|
|
int i, next, nframes;
|
2016-04-23 13:15:27 +03:00
|
|
|
int rd = UE_GET_DIR(upipe->pipe.up_endpoint->ue_edesc->bEndpointAddress) == UE_DIR_IN;
|
1999-09-09 16:26:43 +04:00
|
|
|
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTFN(5, "used=%jd next=%jd xfer=%#jx nframes=%jd",
|
|
|
|
isoc->inuse, isoc->next, (uintptr_t)xfer, xfer->ux_nframes);
|
1999-09-09 16:26:43 +04:00
|
|
|
|
2000-01-26 13:04:38 +03:00
|
|
|
if (sc->sc_dying)
|
2016-04-23 13:15:27 +03:00
|
|
|
return USBD_IOERROR;
|
2000-01-26 13:04:38 +03:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
if (xfer->ux_status == USBD_IN_PROGRESS) {
|
1999-09-09 16:26:43 +04:00
|
|
|
/* This request has already been entered into the frame list */
|
2016-04-23 13:15:27 +03:00
|
|
|
printf("%s: xfer=%p in frame list\n", __func__, xfer);
|
1999-11-23 23:36:10 +03:00
|
|
|
/* XXX */
|
1999-09-09 16:26:43 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DIAGNOSTIC
|
2016-04-23 13:15:27 +03:00
|
|
|
if (isoc->inuse >= UHCI_VFRAMELIST_COUNT)
|
|
|
|
printf("%s: overflow!\n", __func__);
|
1998-12-30 16:25:54 +03:00
|
|
|
#endif
|
1998-12-28 23:13:59 +03:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
KASSERT(xfer->ux_nframes != 0);
|
|
|
|
|
2020-05-15 09:15:42 +03:00
|
|
|
if (xfer->ux_length)
|
|
|
|
usb_syncmem(&xfer->ux_dmabuf, 0, xfer->ux_length,
|
|
|
|
rd ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
|
2020-04-05 23:59:38 +03:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
mutex_enter(&sc->sc_lock);
|
|
|
|
next = isoc->next;
|
1999-09-09 16:26:43 +04:00
|
|
|
if (next == -1) {
|
|
|
|
/* Not in use yet, schedule it a few frames ahead. */
|
|
|
|
next = (UREAD2(sc, UHCI_FRNUM) + 3) % UHCI_VFRAMELIST_COUNT;
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTFN(2, "start next=%jd", next, 0, 0, 0);
|
1999-09-09 16:26:43 +04:00
|
|
|
}
|
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
xfer->ux_status = USBD_IN_PROGRESS;
|
|
|
|
ux->ux_curframe = next;
|
1998-12-28 23:13:59 +03:00
|
|
|
|
2008-06-28 21:42:53 +04:00
|
|
|
offs = 0;
|
2000-03-16 15:40:51 +03:00
|
|
|
status = UHCI_TD_ZERO_ACTLEN(UHCI_TD_SET_ERRCNT(0) |
|
|
|
|
UHCI_TD_ACTIVE |
|
|
|
|
UHCI_TD_IOS);
|
2016-04-23 13:15:27 +03:00
|
|
|
nframes = xfer->ux_nframes;
|
1999-09-09 16:26:43 +04:00
|
|
|
for (i = 0; i < nframes; i++) {
|
2020-05-25 16:55:31 +03:00
|
|
|
buf = DMAADDR(&xfer->ux_dmabuf, offs);
|
2016-04-23 13:15:27 +03:00
|
|
|
std = isoc->stds[next];
|
1999-09-09 16:26:43 +04:00
|
|
|
if (++next >= UHCI_VFRAMELIST_COUNT)
|
|
|
|
next = 0;
|
2016-04-23 13:15:27 +03:00
|
|
|
len = xfer->ux_frlengths[i];
|
2020-05-25 16:55:31 +03:00
|
|
|
|
|
|
|
KASSERTMSG(len <= __SHIFTOUT_MASK(UHCI_TD_MAXLEN_MASK),
|
|
|
|
"len %d", len);
|
2000-03-16 15:40:51 +03:00
|
|
|
std->td.td_buffer = htole32(buf);
|
2016-04-23 13:15:27 +03:00
|
|
|
usb_syncmem(&xfer->ux_dmabuf, offs, len,
|
2008-06-28 21:42:53 +04:00
|
|
|
rd ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
|
1999-09-09 16:26:43 +04:00
|
|
|
if (i == nframes - 1)
|
2000-03-16 15:40:51 +03:00
|
|
|
status |= UHCI_TD_IOC;
|
|
|
|
std->td.td_status = htole32(status);
|
|
|
|
std->td.td_token &= htole32(~UHCI_TD_MAXLEN_MASK);
|
|
|
|
std->td.td_token |= htole32(UHCI_TD_SET_MAXLEN(len));
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&std->dma, std->offs, sizeof(std->td),
|
|
|
|
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
|
1999-10-13 12:10:55 +04:00
|
|
|
#ifdef UHCI_DEBUG
|
2016-04-23 13:15:27 +03:00
|
|
|
if (uhcidebug >= 5) {
|
|
|
|
DPRINTF("--- dump start ---", 0, 0, 0, 0);
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTF("TD %jd", i, 0, 0, 0);
|
1999-09-09 16:26:43 +04:00
|
|
|
uhci_dump_td(std);
|
2016-04-23 13:15:27 +03:00
|
|
|
DPRINTF("--- dump end ---", 0, 0, 0, 0);
|
1999-09-09 16:26:43 +04:00
|
|
|
}
|
|
|
|
#endif
|
2008-06-28 21:42:53 +04:00
|
|
|
offs += len;
|
2020-05-25 16:55:31 +03:00
|
|
|
const bus_addr_t bend __diagused =
|
|
|
|
DMAADDR(&xfer->ux_dmabuf, offs - 1);
|
|
|
|
|
|
|
|
KASSERT(((buf ^ bend) & ~PAGE_MASK) == 0);
|
1999-09-09 16:26:43 +04:00
|
|
|
}
|
2016-04-23 13:15:27 +03:00
|
|
|
isoc->next = next;
|
|
|
|
isoc->inuse += xfer->ux_nframes;
|
2000-03-25 21:02:32 +03:00
|
|
|
|
1999-09-09 16:26:43 +04:00
|
|
|
/* Set up interrupt info. */
|
2016-04-23 13:15:27 +03:00
|
|
|
ux->ux_stdstart = std;
|
|
|
|
ux->ux_stdend = std;
|
|
|
|
|
|
|
|
KASSERT(ux->ux_isdone);
|
1999-09-09 16:26:43 +04:00
|
|
|
#ifdef DIAGNOSTIC
|
2016-04-23 13:15:27 +03:00
|
|
|
ux->ux_isdone = false;
|
1999-09-09 16:26:43 +04:00
|
|
|
#endif
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_add_intr_list(sc, ux);
|
2002-02-03 21:15:20 +03:00
|
|
|
|
2012-06-10 10:15:52 +04:00
|
|
|
mutex_exit(&sc->sc_lock);
|
1999-09-09 16:26:43 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
return USBD_IN_PROGRESS;
|
1998-12-28 23:13:59 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_device_isoc_abort(struct usbd_xfer *xfer)
|
1998-12-28 23:13:59 +03:00
|
|
|
{
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_softc_t *sc = UHCI_XFER2SC(xfer);
|
|
|
|
struct uhci_pipe *upipe = UHCI_PIPE2UPIPE(xfer->ux_pipe);
|
|
|
|
struct uhci_xfer *ux = UHCI_XFER2UXFER(xfer);
|
|
|
|
uhci_soft_td_t **stds = upipe->isoc.stds;
|
1999-09-09 16:26:43 +04:00
|
|
|
uhci_soft_td_t *std;
|
2012-06-10 10:15:52 +04:00
|
|
|
int i, n, nframes, maxlen, len;
|
2000-03-25 01:57:58 +03:00
|
|
|
|
2012-06-10 10:15:52 +04:00
|
|
|
KASSERT(mutex_owned(&sc->sc_lock));
|
1999-09-09 16:26:43 +04:00
|
|
|
|
2000-03-25 01:57:58 +03:00
|
|
|
/* Transfer is already done. */
|
2016-04-23 13:15:27 +03:00
|
|
|
if (xfer->ux_status != USBD_NOT_STARTED &&
|
|
|
|
xfer->ux_status != USBD_IN_PROGRESS) {
|
2000-03-25 01:57:58 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Give xfer the requested abort code. */
|
2016-04-23 13:15:27 +03:00
|
|
|
xfer->ux_status = USBD_CANCELLED;
|
1999-09-09 16:26:43 +04:00
|
|
|
|
|
|
|
/* make hardware ignore it, */
|
2016-04-23 13:15:27 +03:00
|
|
|
nframes = xfer->ux_nframes;
|
|
|
|
n = ux->ux_curframe;
|
2000-03-25 01:57:58 +03:00
|
|
|
maxlen = 0;
|
1999-09-09 16:26:43 +04:00
|
|
|
for (i = 0; i < nframes; i++) {
|
|
|
|
std = stds[n];
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&std->dma,
|
|
|
|
std->offs + offsetof(uhci_td_t, td_status),
|
|
|
|
sizeof(std->td.td_status),
|
|
|
|
BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
|
2000-03-16 15:40:51 +03:00
|
|
|
std->td.td_status &= htole32(~(UHCI_TD_ACTIVE | UHCI_TD_IOC));
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&std->dma,
|
|
|
|
std->offs + offsetof(uhci_td_t, td_status),
|
|
|
|
sizeof(std->td.td_status),
|
|
|
|
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
|
|
|
|
usb_syncmem(&std->dma,
|
|
|
|
std->offs + offsetof(uhci_td_t, td_token),
|
|
|
|
sizeof(std->td.td_token),
|
|
|
|
BUS_DMASYNC_POSTWRITE);
|
2000-12-18 18:55:30 +03:00
|
|
|
len = UHCI_TD_GET_MAXLEN(le32toh(std->td.td_token));
|
2000-03-25 01:57:58 +03:00
|
|
|
if (len > maxlen)
|
|
|
|
maxlen = len;
|
1999-09-09 16:26:43 +04:00
|
|
|
if (++n >= UHCI_VFRAMELIST_COUNT)
|
|
|
|
n = 0;
|
|
|
|
}
|
|
|
|
|
2000-03-25 01:57:58 +03:00
|
|
|
/* and wait until we are sure the hardware has finished. */
|
|
|
|
delay(maxlen);
|
1999-09-09 16:26:43 +04:00
|
|
|
|
2000-03-25 21:02:32 +03:00
|
|
|
#ifdef DIAGNOSTIC
|
2016-04-23 13:15:27 +03:00
|
|
|
ux->ux_isdone = true;
|
2000-03-25 21:02:32 +03:00
|
|
|
#endif
|
2016-04-23 13:15:27 +03:00
|
|
|
/* Remove from interrupt list. */
|
|
|
|
uhci_del_intr_list(sc, ux);
|
|
|
|
|
|
|
|
/* Run callback. */
|
2000-03-25 01:57:58 +03:00
|
|
|
usb_transfer_complete(xfer);
|
|
|
|
|
2012-06-10 10:15:52 +04:00
|
|
|
KASSERT(mutex_owned(&sc->sc_lock));
|
1998-12-28 23:13:59 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_device_isoc_close(struct usbd_pipe *pipe)
|
1998-12-28 23:13:59 +03:00
|
|
|
{
|
2016-04-23 13:15:27 +03:00
|
|
|
struct uhci_pipe *upipe = UHCI_PIPE2UPIPE(pipe);
|
|
|
|
uhci_softc_t *sc = UHCI_PIPE2SC(pipe);
|
1999-09-09 16:26:43 +04:00
|
|
|
uhci_soft_td_t *std, *vstd;
|
2016-04-23 13:15:27 +03:00
|
|
|
struct isoc *isoc;
|
2012-06-10 10:15:52 +04:00
|
|
|
int i;
|
|
|
|
|
|
|
|
KASSERT(mutex_owned(&sc->sc_lock));
|
1998-12-28 23:13:59 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Make sure all TDs are marked as inactive.
|
|
|
|
* Wait for completion.
|
|
|
|
* Unschedule.
|
|
|
|
* Deallocate.
|
|
|
|
*/
|
2016-04-23 13:15:27 +03:00
|
|
|
isoc = &upipe->isoc;
|
1998-12-28 23:13:59 +03:00
|
|
|
|
2008-06-28 21:42:53 +04:00
|
|
|
for (i = 0; i < UHCI_VFRAMELIST_COUNT; i++) {
|
2016-04-23 13:15:27 +03:00
|
|
|
std = isoc->stds[i];
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&std->dma,
|
|
|
|
std->offs + offsetof(uhci_td_t, td_status),
|
|
|
|
sizeof(std->td.td_status),
|
|
|
|
BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
|
|
|
|
std->td.td_status &= htole32(~UHCI_TD_ACTIVE);
|
|
|
|
usb_syncmem(&std->dma,
|
|
|
|
std->offs + offsetof(uhci_td_t, td_status),
|
|
|
|
sizeof(std->td.td_status),
|
|
|
|
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
|
|
|
|
}
|
2012-06-10 10:15:52 +04:00
|
|
|
/* wait for completion */
|
|
|
|
usb_delay_ms_locked(&sc->sc_bus, 2, &sc->sc_lock);
|
1998-12-28 23:13:59 +03:00
|
|
|
|
|
|
|
for (i = 0; i < UHCI_VFRAMELIST_COUNT; i++) {
|
2016-04-23 13:15:27 +03:00
|
|
|
std = isoc->stds[i];
|
1999-09-09 16:26:43 +04:00
|
|
|
for (vstd = sc->sc_vframes[i].htd;
|
1999-11-19 02:32:25 +03:00
|
|
|
vstd != NULL && vstd->link.std != std;
|
1999-08-23 03:19:56 +04:00
|
|
|
vstd = vstd->link.std)
|
1998-12-28 23:13:59 +03:00
|
|
|
;
|
1999-11-19 02:32:25 +03:00
|
|
|
if (vstd == NULL) {
|
1998-12-28 23:13:59 +03:00
|
|
|
/*panic*/
|
2016-04-23 13:15:27 +03:00
|
|
|
printf("%s: %p not found\n", __func__, std);
|
2012-06-10 10:15:52 +04:00
|
|
|
mutex_exit(&sc->sc_lock);
|
1998-12-28 23:13:59 +03:00
|
|
|
return;
|
|
|
|
}
|
1999-08-23 03:19:56 +04:00
|
|
|
vstd->link = std->link;
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&std->dma,
|
|
|
|
std->offs + offsetof(uhci_td_t, td_link),
|
|
|
|
sizeof(std->td.td_link),
|
|
|
|
BUS_DMASYNC_POSTWRITE);
|
1999-08-23 03:19:56 +04:00
|
|
|
vstd->td.td_link = std->td.td_link;
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&vstd->dma,
|
|
|
|
vstd->offs + offsetof(uhci_td_t, td_link),
|
|
|
|
sizeof(vstd->td.td_link),
|
|
|
|
BUS_DMASYNC_PREWRITE);
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_free_std_locked(sc, std);
|
1998-12-28 23:13:59 +03:00
|
|
|
}
|
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
kmem_free(isoc->stds, UHCI_VFRAMELIST_COUNT * sizeof(uhci_soft_td_t *));
|
1998-12-28 23:13:59 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
usbd_status
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_setup_isoc(struct usbd_pipe *pipe)
|
1998-12-28 23:13:59 +03:00
|
|
|
{
|
2016-04-23 13:15:27 +03:00
|
|
|
struct uhci_pipe *upipe = UHCI_PIPE2UPIPE(pipe);
|
|
|
|
uhci_softc_t *sc = UHCI_PIPE2SC(pipe);
|
|
|
|
int addr = upipe->pipe.up_dev->ud_addr;
|
|
|
|
int endpt = upipe->pipe.up_endpoint->ue_edesc->bEndpointAddress;
|
1999-09-05 02:26:11 +04:00
|
|
|
int rd = UE_GET_DIR(endpt) == UE_DIR_IN;
|
1999-09-09 16:26:43 +04:00
|
|
|
uhci_soft_td_t *std, *vstd;
|
2016-04-23 13:15:27 +03:00
|
|
|
uint32_t token;
|
|
|
|
struct isoc *isoc;
|
2012-06-10 10:15:52 +04:00
|
|
|
int i;
|
1998-12-28 23:13:59 +03:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
isoc = &upipe->isoc;
|
|
|
|
|
|
|
|
isoc->stds = kmem_alloc(
|
|
|
|
UHCI_VFRAMELIST_COUNT * sizeof(uhci_soft_td_t *), KM_SLEEP);
|
|
|
|
if (isoc->stds == NULL)
|
2012-06-10 10:15:52 +04:00
|
|
|
return USBD_NOMEM;
|
1998-12-28 23:13:59 +03:00
|
|
|
|
2000-03-16 15:40:51 +03:00
|
|
|
token = rd ? UHCI_TD_IN (0, endpt, addr, 0) :
|
|
|
|
UHCI_TD_OUT(0, endpt, addr, 0);
|
1998-12-28 23:13:59 +03:00
|
|
|
|
1999-09-09 16:26:43 +04:00
|
|
|
/* Allocate the TDs and mark as inactive; */
|
1998-12-28 23:13:59 +03:00
|
|
|
for (i = 0; i < UHCI_VFRAMELIST_COUNT; i++) {
|
1999-09-09 16:26:43 +04:00
|
|
|
std = uhci_alloc_std(sc);
|
|
|
|
if (std == 0)
|
|
|
|
goto bad;
|
2000-03-16 15:40:51 +03:00
|
|
|
std->td.td_status = htole32(UHCI_TD_IOS); /* iso, inactive */
|
|
|
|
std->td.td_token = htole32(token);
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&std->dma, std->offs, sizeof(std->td),
|
|
|
|
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
|
2016-04-23 13:15:27 +03:00
|
|
|
isoc->stds[i] = std;
|
1998-12-28 23:13:59 +03:00
|
|
|
}
|
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
mutex_enter(&sc->sc_lock);
|
|
|
|
|
1999-09-09 16:26:43 +04:00
|
|
|
/* Insert TDs into schedule. */
|
1998-12-28 23:13:59 +03:00
|
|
|
for (i = 0; i < UHCI_VFRAMELIST_COUNT; i++) {
|
2016-04-23 13:15:27 +03:00
|
|
|
std = isoc->stds[i];
|
1999-09-09 16:26:43 +04:00
|
|
|
vstd = sc->sc_vframes[i].htd;
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&vstd->dma,
|
|
|
|
vstd->offs + offsetof(uhci_td_t, td_link),
|
|
|
|
sizeof(vstd->td.td_link),
|
|
|
|
BUS_DMASYNC_POSTWRITE);
|
1999-08-23 03:19:56 +04:00
|
|
|
std->link = vstd->link;
|
|
|
|
std->td.td_link = vstd->td.td_link;
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&std->dma,
|
|
|
|
std->offs + offsetof(uhci_td_t, td_link),
|
|
|
|
sizeof(std->td.td_link),
|
|
|
|
BUS_DMASYNC_PREWRITE);
|
1999-08-23 03:19:56 +04:00
|
|
|
vstd->link.std = std;
|
2000-07-23 23:43:37 +04:00
|
|
|
vstd->td.td_link = htole32(std->physaddr | UHCI_PTR_TD);
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&vstd->dma,
|
|
|
|
vstd->offs + offsetof(uhci_td_t, td_link),
|
|
|
|
sizeof(vstd->td.td_link),
|
|
|
|
BUS_DMASYNC_PREWRITE);
|
1998-12-28 23:13:59 +03:00
|
|
|
}
|
2012-06-10 10:15:52 +04:00
|
|
|
mutex_exit(&sc->sc_lock);
|
1998-12-28 23:13:59 +03:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
isoc->next = -1;
|
|
|
|
isoc->inuse = 0;
|
1999-09-09 16:26:43 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
return USBD_NORMAL_COMPLETION;
|
1998-12-28 23:13:59 +03:00
|
|
|
|
1999-09-09 16:26:43 +04:00
|
|
|
bad:
|
1998-12-28 23:13:59 +03:00
|
|
|
while (--i >= 0)
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_free_std(sc, isoc->stds[i]);
|
|
|
|
kmem_free(isoc->stds, UHCI_VFRAMELIST_COUNT * sizeof(uhci_soft_td_t *));
|
|
|
|
return USBD_NOMEM;
|
1998-12-28 23:13:59 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_device_isoc_done(struct usbd_xfer *xfer)
|
1998-12-28 23:13:59 +03:00
|
|
|
{
|
2016-04-23 13:15:27 +03:00
|
|
|
struct uhci_pipe *upipe = UHCI_PIPE2UPIPE(xfer->ux_pipe);
|
|
|
|
struct uhci_xfer *ux = UHCI_XFER2UXFER(xfer);
|
2008-06-28 21:42:53 +04:00
|
|
|
int i, offs;
|
2016-04-23 13:15:27 +03:00
|
|
|
int rd = UE_GET_DIR(upipe->pipe.up_endpoint->ue_edesc->bEndpointAddress) == UE_DIR_IN;
|
1999-09-09 16:26:43 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
2020-03-14 05:35:33 +03:00
|
|
|
DPRINTFN(4, "length=%jd, ux_state=0x%08jx",
|
2016-04-23 13:15:27 +03:00
|
|
|
xfer->ux_actlen, xfer->ux_state, 0, 0);
|
2003-02-19 04:35:04 +03:00
|
|
|
|
2000-03-25 03:11:21 +03:00
|
|
|
#ifdef DIAGNOSTIC
|
2016-04-23 13:15:27 +03:00
|
|
|
if (ux->ux_stdend == NULL) {
|
|
|
|
printf("%s: xfer=%p stdend==NULL\n", __func__, xfer);
|
2000-03-25 03:11:21 +03:00
|
|
|
#ifdef UHCI_DEBUG
|
2016-04-23 13:15:27 +03:00
|
|
|
DPRINTF("--- dump start ---", 0, 0, 0, 0);
|
|
|
|
uhci_dump_ii(ux);
|
|
|
|
DPRINTF("--- dump end ---", 0, 0, 0, 0);
|
2000-03-25 03:11:21 +03:00
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
1999-09-09 16:26:43 +04:00
|
|
|
/* Turn off the interrupt since it is active even if the TD is not. */
|
2016-04-23 13:15:27 +03:00
|
|
|
usb_syncmem(&ux->ux_stdend->dma,
|
|
|
|
ux->ux_stdend->offs + offsetof(uhci_td_t, td_status),
|
|
|
|
sizeof(ux->ux_stdend->td.td_status),
|
2008-06-28 21:42:53 +04:00
|
|
|
BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
|
2016-04-23 13:15:27 +03:00
|
|
|
ux->ux_stdend->td.td_status &= htole32(~UHCI_TD_IOC);
|
|
|
|
usb_syncmem(&ux->ux_stdend->dma,
|
|
|
|
ux->ux_stdend->offs + offsetof(uhci_td_t, td_status),
|
|
|
|
sizeof(ux->ux_stdend->td.td_status),
|
2008-06-28 21:42:53 +04:00
|
|
|
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
|
1999-09-09 16:26:43 +04:00
|
|
|
|
2008-06-28 21:42:53 +04:00
|
|
|
offs = 0;
|
2016-04-23 13:15:27 +03:00
|
|
|
for (i = 0; i < xfer->ux_nframes; i++) {
|
|
|
|
usb_syncmem(&xfer->ux_dmabuf, offs, xfer->ux_frlengths[i],
|
2008-06-28 21:42:53 +04:00
|
|
|
rd ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
|
2016-04-23 13:15:27 +03:00
|
|
|
offs += xfer->ux_frlengths[i];
|
2008-06-28 21:42:53 +04:00
|
|
|
}
|
1998-12-28 23:13:59 +03:00
|
|
|
}
|
|
|
|
|
1998-07-12 23:51:55 +04:00
|
|
|
void
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_device_intr_done(struct usbd_xfer *xfer)
|
1998-07-12 23:51:55 +04:00
|
|
|
{
|
2016-04-23 16:14:52 +03:00
|
|
|
uhci_softc_t *sc __diagused = UHCI_XFER2SC(xfer);
|
2016-04-23 13:15:27 +03:00
|
|
|
struct uhci_pipe *upipe = UHCI_PIPE2UPIPE(xfer->ux_pipe);
|
1998-07-12 23:51:55 +04:00
|
|
|
uhci_soft_qh_t *sqh;
|
2016-04-23 13:15:27 +03:00
|
|
|
int i, npoll;
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTFN(5, "length=%jd", xfer->ux_actlen, 0, 0, 0);
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
|
2012-06-10 10:15:52 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
npoll = upipe->intr.npoll;
|
2016-03-13 10:01:43 +03:00
|
|
|
for (i = 0; i < npoll; i++) {
|
2016-04-23 13:15:27 +03:00
|
|
|
sqh = upipe->intr.qhs[i];
|
2000-07-23 23:43:37 +04:00
|
|
|
sqh->elink = NULL;
|
2000-03-16 15:40:51 +03:00
|
|
|
sqh->qh.qh_elink = htole32(UHCI_PTR_T);
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&sqh->dma,
|
|
|
|
sqh->offs + offsetof(uhci_qh_t, qh_elink),
|
|
|
|
sizeof(sqh->qh.qh_elink),
|
|
|
|
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
2016-04-23 13:15:27 +03:00
|
|
|
const int endpt = upipe->pipe.up_endpoint->ue_edesc->bEndpointAddress;
|
|
|
|
const bool isread = UE_GET_DIR(endpt) == UE_DIR_IN;
|
|
|
|
usb_syncmem(&xfer->ux_dmabuf, 0, xfer->ux_length,
|
2008-06-28 21:42:53 +04:00
|
|
|
isread ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Deallocate request data structures */
|
|
|
|
void
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_device_ctrl_done(struct usbd_xfer *xfer)
|
1998-07-12 23:51:55 +04:00
|
|
|
{
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_softc_t *sc = UHCI_XFER2SC(xfer);
|
|
|
|
struct uhci_pipe *upipe = UHCI_PIPE2UPIPE(xfer->ux_pipe);
|
|
|
|
int len = UGETW(xfer->ux_request.wLength);
|
|
|
|
int isread = (xfer->ux_request.bmRequestType & UT_READ);
|
2012-06-10 10:15:52 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
2003-02-17 02:15:27 +03:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
KASSERT(xfer->ux_rqflags & URQ_REQUEST);
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
/* XXXNH move to uhci_idone??? */
|
|
|
|
if (upipe->pipe.up_dev->ud_speed == USB_SPEED_LOW)
|
|
|
|
uhci_remove_ls_ctrl(sc, upipe->ctrl.sqh);
|
2000-08-13 20:18:09 +04:00
|
|
|
else
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_remove_hs_ctrl(sc, upipe->ctrl.sqh);
|
1999-09-11 12:19:26 +04:00
|
|
|
|
2008-06-28 21:42:53 +04:00
|
|
|
if (len) {
|
2016-04-23 13:15:27 +03:00
|
|
|
usb_syncmem(&xfer->ux_dmabuf, 0, len,
|
2008-06-28 21:42:53 +04:00
|
|
|
isread ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
|
|
|
|
}
|
2016-04-23 13:15:27 +03:00
|
|
|
usb_syncmem(&upipe->ctrl.reqdma, 0,
|
2008-06-28 21:42:53 +04:00
|
|
|
sizeof(usb_device_request_t), BUS_DMASYNC_POSTWRITE);
|
|
|
|
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTF("length=%jd", xfer->ux_actlen, 0, 0, 0);
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Deallocate request data structures */
|
|
|
|
void
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_device_bulk_done(struct usbd_xfer *xfer)
|
1998-07-12 23:51:55 +04:00
|
|
|
{
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_softc_t *sc = UHCI_XFER2SC(xfer);
|
|
|
|
struct uhci_pipe *upipe = UHCI_PIPE2UPIPE(xfer->ux_pipe);
|
|
|
|
usb_endpoint_descriptor_t *ed = xfer->ux_pipe->up_endpoint->ue_edesc;
|
|
|
|
int endpt = ed->bEndpointAddress;
|
|
|
|
int isread = UE_GET_DIR(endpt) == UE_DIR_IN;
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTFN(5, "xfer=%#jx sc=%#jx upipe=%#jx", (uintptr_t)xfer,
|
|
|
|
(uintptr_t)sc, (uintptr_t)upipe, 0);
|
2003-02-17 02:15:27 +03:00
|
|
|
|
2012-06-10 10:15:52 +04:00
|
|
|
KASSERT(mutex_owned(&sc->sc_lock));
|
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_remove_bulk(sc, upipe->bulk.sqh);
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
if (xfer->ux_length) {
|
|
|
|
usb_syncmem(&xfer->ux_dmabuf, 0, xfer->ux_length,
|
|
|
|
isread ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
|
|
|
|
}
|
1999-07-12 09:22:50 +04:00
|
|
|
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTFN(5, "length=%jd", xfer->ux_actlen, 0, 0, 0);
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Add interrupt QH, called with vflock. */
|
|
|
|
void
|
2000-06-01 18:28:57 +04:00
|
|
|
uhci_add_intr(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
|
1998-07-12 23:51:55 +04:00
|
|
|
{
|
2000-03-25 01:57:58 +03:00
|
|
|
struct uhci_vframe *vf = &sc->sc_vframes[sqh->pos];
|
1999-08-23 03:19:56 +04:00
|
|
|
uhci_soft_qh_t *eqh;
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTFN(4, "n=%jd sqh=%#jx", sqh->pos, (uintptr_t)sqh, 0, 0);
|
2000-03-25 01:57:58 +03:00
|
|
|
|
1999-08-23 03:19:56 +04:00
|
|
|
eqh = vf->eqh;
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&eqh->dma, eqh->offs + offsetof(uhci_qh_t, qh_hlink),
|
2019-02-07 15:35:43 +03:00
|
|
|
sizeof(eqh->qh.qh_hlink), BUS_DMASYNC_POSTWRITE);
|
1999-08-23 03:19:56 +04:00
|
|
|
sqh->hlink = eqh->hlink;
|
|
|
|
sqh->qh.qh_hlink = eqh->qh.qh_hlink;
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&sqh->dma, sqh->offs + offsetof(uhci_qh_t, qh_hlink),
|
2019-02-07 15:35:43 +03:00
|
|
|
sizeof(sqh->qh.qh_hlink), BUS_DMASYNC_PREWRITE);
|
1999-08-23 03:19:56 +04:00
|
|
|
eqh->hlink = sqh;
|
2000-07-23 23:43:37 +04:00
|
|
|
eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH);
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&eqh->dma, eqh->offs + offsetof(uhci_qh_t, qh_hlink),
|
2019-02-07 15:35:43 +03:00
|
|
|
sizeof(eqh->qh.qh_hlink), BUS_DMASYNC_PREWRITE);
|
1998-07-12 23:51:55 +04:00
|
|
|
vf->eqh = sqh;
|
|
|
|
vf->bandwidth++;
|
|
|
|
}
|
|
|
|
|
2000-06-01 18:28:57 +04:00
|
|
|
/* Remove interrupt QH. */
|
1998-07-12 23:51:55 +04:00
|
|
|
void
|
2000-06-01 18:28:57 +04:00
|
|
|
uhci_remove_intr(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
|
1998-07-12 23:51:55 +04:00
|
|
|
{
|
2000-03-25 01:57:58 +03:00
|
|
|
struct uhci_vframe *vf = &sc->sc_vframes[sqh->pos];
|
1998-07-12 23:51:55 +04:00
|
|
|
uhci_soft_qh_t *pqh;
|
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTFN(4, "n=%jd sqh=%#jx", sqh->pos, (uintptr_t)sqh, 0, 0);
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2000-08-13 22:20:14 +04:00
|
|
|
/* See comment in uhci_remove_ctrl() */
|
2008-06-28 21:42:53 +04:00
|
|
|
|
|
|
|
usb_syncmem(&sqh->dma, sqh->offs + offsetof(uhci_qh_t, qh_elink),
|
|
|
|
sizeof(sqh->qh.qh_elink),
|
|
|
|
BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
|
2000-08-13 22:20:14 +04:00
|
|
|
if (!(sqh->qh.qh_elink & htole32(UHCI_PTR_T))) {
|
|
|
|
sqh->qh.qh_elink = htole32(UHCI_PTR_T);
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&sqh->dma,
|
|
|
|
sqh->offs + offsetof(uhci_qh_t, qh_elink),
|
|
|
|
sizeof(sqh->qh.qh_elink),
|
|
|
|
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
|
2000-08-13 22:20:14 +04:00
|
|
|
delay(UHCI_QH_REMOVE_DELAY);
|
|
|
|
}
|
|
|
|
|
2000-03-25 01:57:58 +03:00
|
|
|
pqh = uhci_find_prev_qh(vf->hqh, sqh);
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&sqh->dma, sqh->offs + offsetof(uhci_qh_t, qh_hlink),
|
|
|
|
sizeof(sqh->qh.qh_hlink),
|
|
|
|
BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
|
1999-08-23 03:19:56 +04:00
|
|
|
pqh->hlink = sqh->hlink;
|
|
|
|
pqh->qh.qh_hlink = sqh->qh.qh_hlink;
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&pqh->dma, pqh->offs + offsetof(uhci_qh_t, qh_hlink),
|
|
|
|
sizeof(pqh->qh.qh_hlink),
|
|
|
|
BUS_DMASYNC_PREWRITE);
|
2000-08-13 22:20:14 +04:00
|
|
|
delay(UHCI_QH_REMOVE_DELAY);
|
1998-07-12 23:51:55 +04:00
|
|
|
if (vf->eqh == sqh)
|
|
|
|
vf->eqh = pqh;
|
|
|
|
vf->bandwidth--;
|
|
|
|
}
|
|
|
|
|
|
|
|
usbd_status
|
2000-06-01 18:28:57 +04:00
|
|
|
uhci_device_setintr(uhci_softc_t *sc, struct uhci_pipe *upipe, int ival)
|
1998-07-12 23:51:55 +04:00
|
|
|
{
|
|
|
|
uhci_soft_qh_t *sqh;
|
2012-06-10 10:15:52 +04:00
|
|
|
int i, npoll;
|
1998-07-12 23:51:55 +04:00
|
|
|
u_int bestbw, bw, bestoffs, offs;
|
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTFN(2, "pipe=%#jx", (uintptr_t)upipe, 0, 0, 0);
|
1998-07-12 23:51:55 +04:00
|
|
|
if (ival == 0) {
|
2016-04-23 13:15:27 +03:00
|
|
|
printf("%s: 0 interval\n", __func__);
|
|
|
|
return USBD_INVAL;
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ival > UHCI_VFRAMELIST_COUNT)
|
|
|
|
ival = UHCI_VFRAMELIST_COUNT;
|
2020-03-15 16:59:20 +03:00
|
|
|
npoll = howmany(UHCI_VFRAMELIST_COUNT, ival);
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTF("ival=%jd npoll=%jd", ival, npoll, 0, 0);
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
upipe->intr.npoll = npoll;
|
|
|
|
upipe->intr.qhs =
|
2012-06-10 10:15:52 +04:00
|
|
|
kmem_alloc(npoll * sizeof(uhci_soft_qh_t *), KM_SLEEP);
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2002-02-03 21:15:20 +03:00
|
|
|
/*
|
1998-07-12 23:51:55 +04:00
|
|
|
* Figure out which offset in the schedule that has most
|
|
|
|
* bandwidth left over.
|
|
|
|
*/
|
|
|
|
#define MOD(i) ((i) & (UHCI_VFRAMELIST_COUNT-1))
|
|
|
|
for (bestoffs = offs = 0, bestbw = ~0; offs < ival; offs++) {
|
|
|
|
for (bw = i = 0; i < npoll; i++)
|
|
|
|
bw += sc->sc_vframes[MOD(i * ival + offs)].bandwidth;
|
|
|
|
if (bw < bestbw) {
|
|
|
|
bestbw = bw;
|
|
|
|
bestoffs = offs;
|
|
|
|
}
|
|
|
|
}
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTF("bw=%jd offs=%jd", bestbw, bestoffs, 0, 0);
|
2016-03-13 10:01:43 +03:00
|
|
|
for (i = 0; i < npoll; i++) {
|
2016-04-23 13:15:27 +03:00
|
|
|
upipe->intr.qhs[i] = sqh = uhci_alloc_sqh(sc);
|
2000-07-23 23:43:37 +04:00
|
|
|
sqh->elink = NULL;
|
2000-03-16 15:40:51 +03:00
|
|
|
sqh->qh.qh_elink = htole32(UHCI_PTR_T);
|
2008-06-28 21:42:53 +04:00
|
|
|
usb_syncmem(&sqh->dma,
|
|
|
|
sqh->offs + offsetof(uhci_qh_t, qh_elink),
|
|
|
|
sizeof(sqh->qh.qh_elink),
|
|
|
|
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
|
1998-07-12 23:51:55 +04:00
|
|
|
sqh->pos = MOD(i * ival + bestoffs);
|
|
|
|
}
|
|
|
|
#undef MOD
|
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
mutex_enter(&sc->sc_lock);
|
1998-07-12 23:51:55 +04:00
|
|
|
/* Enter QHs into the controller data structures. */
|
2016-03-13 10:01:43 +03:00
|
|
|
for (i = 0; i < npoll; i++)
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_add_intr(sc, upipe->intr.qhs[i]);
|
2012-06-10 10:15:52 +04:00
|
|
|
mutex_exit(&sc->sc_lock);
|
1998-07-12 23:51:55 +04:00
|
|
|
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTFN(5, "returns %#jx", (uintptr_t)upipe, 0, 0, 0);
|
2016-04-23 13:15:27 +03:00
|
|
|
|
|
|
|
return USBD_NORMAL_COMPLETION;
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Open a new pipe. */
|
|
|
|
usbd_status
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_open(struct usbd_pipe *pipe)
|
1998-07-12 23:51:55 +04:00
|
|
|
{
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_softc_t *sc = UHCI_PIPE2SC(pipe);
|
|
|
|
struct usbd_bus *bus = pipe->up_dev->ud_bus;
|
|
|
|
struct uhci_pipe *upipe = UHCI_PIPE2UPIPE(pipe);
|
|
|
|
usb_endpoint_descriptor_t *ed = pipe->up_endpoint->ue_edesc;
|
2012-06-10 10:15:52 +04:00
|
|
|
usbd_status err = USBD_NOMEM;
|
2000-01-19 04:04:26 +03:00
|
|
|
int ival;
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTF("pipe=%#jx, addr=%jd, endpt=%jd (%jd)",
|
|
|
|
(uintptr_t)pipe, pipe->up_dev->ud_addr, ed->bEndpointAddress,
|
|
|
|
bus->ub_rhaddr);
|
2000-03-25 01:57:58 +03:00
|
|
|
|
2012-06-10 10:15:52 +04:00
|
|
|
if (sc->sc_dying)
|
|
|
|
return USBD_IOERROR;
|
|
|
|
|
2000-03-25 01:57:58 +03:00
|
|
|
upipe->aborting = 0;
|
2011-05-27 21:19:18 +04:00
|
|
|
/* toggle state needed for bulk endpoints */
|
2016-04-23 13:15:27 +03:00
|
|
|
upipe->nexttoggle = pipe->up_endpoint->ue_toggle;
|
2000-03-25 01:57:58 +03:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
if (pipe->up_dev->ud_addr == bus->ub_rhaddr) {
|
1998-07-12 23:51:55 +04:00
|
|
|
switch (ed->bEndpointAddress) {
|
|
|
|
case USB_CONTROL_ENDPOINT:
|
2016-04-23 13:15:27 +03:00
|
|
|
pipe->up_methods = &roothub_ctrl_methods;
|
1998-07-12 23:51:55 +04:00
|
|
|
break;
|
2016-04-23 13:15:27 +03:00
|
|
|
case UE_DIR_IN | USBROOTHUB_INTR_ENDPT:
|
|
|
|
pipe->up_methods = &uhci_root_intr_methods;
|
1998-07-12 23:51:55 +04:00
|
|
|
break;
|
|
|
|
default:
|
2016-04-23 13:15:27 +03:00
|
|
|
return USBD_INVAL;
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
switch (ed->bmAttributes & UE_XFERTYPE) {
|
|
|
|
case UE_CONTROL:
|
2016-04-23 13:15:27 +03:00
|
|
|
pipe->up_methods = &uhci_device_ctrl_methods;
|
|
|
|
upipe->ctrl.sqh = uhci_alloc_sqh(sc);
|
|
|
|
if (upipe->ctrl.sqh == NULL)
|
1998-07-23 13:18:37 +04:00
|
|
|
goto bad;
|
2016-04-23 13:15:27 +03:00
|
|
|
upipe->ctrl.setup = uhci_alloc_std(sc);
|
|
|
|
if (upipe->ctrl.setup == NULL) {
|
|
|
|
uhci_free_sqh(sc, upipe->ctrl.sqh);
|
1998-07-23 13:18:37 +04:00
|
|
|
goto bad;
|
|
|
|
}
|
2016-04-23 13:15:27 +03:00
|
|
|
upipe->ctrl.stat = uhci_alloc_std(sc);
|
|
|
|
if (upipe->ctrl.stat == NULL) {
|
|
|
|
uhci_free_sqh(sc, upipe->ctrl.sqh);
|
|
|
|
uhci_free_std(sc, upipe->ctrl.setup);
|
1998-07-23 13:18:37 +04:00
|
|
|
goto bad;
|
|
|
|
}
|
2002-02-03 21:15:20 +03:00
|
|
|
err = usb_allocmem(&sc->sc_bus,
|
2020-04-05 23:59:38 +03:00
|
|
|
sizeof(usb_device_request_t), 0,
|
|
|
|
USBMALLOC_COHERENT, &upipe->ctrl.reqdma);
|
1999-11-12 03:34:57 +03:00
|
|
|
if (err) {
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_free_sqh(sc, upipe->ctrl.sqh);
|
|
|
|
uhci_free_std(sc, upipe->ctrl.setup);
|
|
|
|
uhci_free_std(sc, upipe->ctrl.stat);
|
1998-07-23 13:18:37 +04:00
|
|
|
goto bad;
|
|
|
|
}
|
1998-07-12 23:51:55 +04:00
|
|
|
break;
|
|
|
|
case UE_INTERRUPT:
|
2016-04-23 13:15:27 +03:00
|
|
|
pipe->up_methods = &uhci_device_intr_methods;
|
|
|
|
ival = pipe->up_interval;
|
2000-01-19 04:04:26 +03:00
|
|
|
if (ival == USBD_DEFAULT_INTERVAL)
|
|
|
|
ival = ed->bInterval;
|
2016-04-23 13:15:27 +03:00
|
|
|
return uhci_device_setintr(sc, upipe, ival);
|
1998-07-12 23:51:55 +04:00
|
|
|
case UE_ISOCHRONOUS:
|
2016-04-23 13:15:27 +03:00
|
|
|
pipe->up_serialise = false;
|
|
|
|
pipe->up_methods = &uhci_device_isoc_methods;
|
|
|
|
return uhci_setup_isoc(pipe);
|
1998-07-12 23:51:55 +04:00
|
|
|
case UE_BULK:
|
2016-04-23 13:15:27 +03:00
|
|
|
pipe->up_methods = &uhci_device_bulk_methods;
|
|
|
|
upipe->bulk.sqh = uhci_alloc_sqh(sc);
|
|
|
|
if (upipe->bulk.sqh == NULL)
|
1998-07-23 13:18:37 +04:00
|
|
|
goto bad;
|
1998-07-12 23:51:55 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2016-04-23 13:15:27 +03:00
|
|
|
return USBD_NORMAL_COMPLETION;
|
1998-07-23 13:18:37 +04:00
|
|
|
|
|
|
|
bad:
|
2012-06-10 10:15:52 +04:00
|
|
|
return USBD_NOMEM;
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Data structures and routines to emulate the root hub.
|
|
|
|
*/
|
2002-12-31 05:21:31 +03:00
|
|
|
/*
|
|
|
|
* The USB hub protocol requires that SET_FEATURE(PORT_RESET) also
|
|
|
|
* enables the port, and also states that SET_FEATURE(PORT_ENABLE)
|
|
|
|
* should not be used by the USB subsystem. As we cannot issue a
|
|
|
|
* SET_FEATURE(PORT_ENABLE) externally, we must ensure that the port
|
|
|
|
* will be enabled as part of the reset.
|
|
|
|
*
|
|
|
|
* On the VT83C572, the port cannot be successfully enabled until the
|
|
|
|
* outstanding "port enable change" and "connection status change"
|
|
|
|
* events have been reset.
|
|
|
|
*/
|
|
|
|
Static usbd_status
|
|
|
|
uhci_portreset(uhci_softc_t *sc, int index)
|
|
|
|
{
|
|
|
|
int lim, port, x;
|
2016-04-23 13:15:27 +03:00
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
2002-12-31 05:21:31 +03:00
|
|
|
|
|
|
|
if (index == 1)
|
|
|
|
port = UHCI_PORTSC1;
|
|
|
|
else if (index == 2)
|
|
|
|
port = UHCI_PORTSC2;
|
|
|
|
else
|
2016-04-23 13:15:27 +03:00
|
|
|
return USBD_IOERROR;
|
2002-12-31 05:21:31 +03:00
|
|
|
|
|
|
|
x = URWMASK(UREAD2(sc, port));
|
|
|
|
UWRITE2(sc, port, x | UHCI_PORTSC_PR);
|
|
|
|
|
|
|
|
usb_delay_ms(&sc->sc_bus, USB_PORT_ROOT_RESET_DELAY);
|
|
|
|
|
2020-03-14 05:35:33 +03:00
|
|
|
DPRINTF("uhci port %jd reset, status0 = 0x%04jx", index,
|
2016-04-23 13:15:27 +03:00
|
|
|
UREAD2(sc, port), 0, 0);
|
2002-12-31 05:21:31 +03:00
|
|
|
|
|
|
|
x = URWMASK(UREAD2(sc, port));
|
2008-06-16 14:29:41 +04:00
|
|
|
UWRITE2(sc, port, x & ~(UHCI_PORTSC_PR | UHCI_PORTSC_SUSP));
|
2002-12-31 05:21:31 +03:00
|
|
|
|
|
|
|
delay(100);
|
|
|
|
|
2020-03-14 05:35:33 +03:00
|
|
|
DPRINTF("uhci port %jd reset, status1 = 0x%04jx", index,
|
2016-04-23 13:15:27 +03:00
|
|
|
UREAD2(sc, port), 0, 0);
|
2002-12-31 05:21:31 +03:00
|
|
|
|
|
|
|
x = URWMASK(UREAD2(sc, port));
|
|
|
|
UWRITE2(sc, port, x | UHCI_PORTSC_PE);
|
|
|
|
|
|
|
|
for (lim = 10; --lim > 0;) {
|
|
|
|
usb_delay_ms(&sc->sc_bus, USB_PORT_RESET_DELAY);
|
|
|
|
|
|
|
|
x = UREAD2(sc, port);
|
2020-03-14 05:35:33 +03:00
|
|
|
DPRINTF("uhci port %jd iteration %ju, status = 0x%04jx", index,
|
2016-04-23 13:15:27 +03:00
|
|
|
lim, x, 0);
|
2002-12-31 05:21:31 +03:00
|
|
|
|
|
|
|
if (!(x & UHCI_PORTSC_CCS)) {
|
|
|
|
/*
|
|
|
|
* No device is connected (or was disconnected
|
|
|
|
* during reset). Consider the port reset.
|
|
|
|
* The delay must be long enough to ensure on
|
|
|
|
* the initial iteration that the device
|
|
|
|
* connection will have been registered. 50ms
|
|
|
|
* appears to be sufficient, but 20ms is not.
|
|
|
|
*/
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTFN(3, "uhci port %jd loop %ju, device detached",
|
2016-04-23 13:15:27 +03:00
|
|
|
index, lim, 0, 0);
|
2002-12-31 05:21:31 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (x & (UHCI_PORTSC_POEDC | UHCI_PORTSC_CSC)) {
|
|
|
|
/*
|
|
|
|
* Port enabled changed and/or connection
|
|
|
|
* status changed were set. Reset either or
|
|
|
|
* both raised flags (by writing a 1 to that
|
|
|
|
* bit), and wait again for state to settle.
|
|
|
|
*/
|
|
|
|
UWRITE2(sc, port, URWMASK(x) |
|
|
|
|
(x & (UHCI_PORTSC_POEDC | UHCI_PORTSC_CSC)));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (x & UHCI_PORTSC_PE)
|
|
|
|
/* Port is enabled */
|
|
|
|
break;
|
|
|
|
|
|
|
|
UWRITE2(sc, port, URWMASK(x) | UHCI_PORTSC_PE);
|
|
|
|
}
|
|
|
|
|
2020-03-14 05:35:33 +03:00
|
|
|
DPRINTFN(3, "uhci port %jd reset, status2 = 0x%04jx", index,
|
2016-04-23 13:15:27 +03:00
|
|
|
UREAD2(sc, port), 0, 0);
|
2002-12-31 05:21:31 +03:00
|
|
|
|
|
|
|
if (lim <= 0) {
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTF("uhci port %jd reset timed out", index,
|
2016-04-23 13:15:27 +03:00
|
|
|
0, 0, 0);
|
|
|
|
return USBD_TIMEOUT;
|
2002-12-31 05:21:31 +03:00
|
|
|
}
|
2005-02-27 03:26:58 +03:00
|
|
|
|
2002-12-31 05:21:31 +03:00
|
|
|
sc->sc_isreset = 1;
|
2016-04-23 13:15:27 +03:00
|
|
|
return USBD_NORMAL_COMPLETION;
|
2002-12-31 05:21:31 +03:00
|
|
|
}
|
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
Static int
|
|
|
|
uhci_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
|
|
|
|
void *buf, int buflen)
|
1998-12-28 23:13:59 +03:00
|
|
|
{
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_softc_t *sc = UHCI_BUS2SC(bus);
|
1998-07-12 23:51:55 +04:00
|
|
|
int port, x;
|
2016-04-23 13:15:27 +03:00
|
|
|
int status, change, totlen = 0;
|
|
|
|
uint16_t len, value, index;
|
1998-07-12 23:51:55 +04:00
|
|
|
usb_port_status_t ps;
|
1999-11-12 03:34:57 +03:00
|
|
|
usbd_status err;
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
2000-01-26 13:04:38 +03:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
if (sc->sc_dying)
|
|
|
|
return -1;
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2020-03-14 05:35:33 +03:00
|
|
|
DPRINTF("type=0x%02jx request=%02jx", req->bmRequestType,
|
2016-04-23 13:15:27 +03:00
|
|
|
req->bRequest, 0, 0);
|
1998-07-12 23:51:55 +04:00
|
|
|
|
|
|
|
len = UGETW(req->wLength);
|
|
|
|
value = UGETW(req->wValue);
|
|
|
|
index = UGETW(req->wIndex);
|
1999-09-11 12:19:26 +04:00
|
|
|
|
1998-07-12 23:51:55 +04:00
|
|
|
#define C(x,y) ((x) | ((y) << 8))
|
2016-04-23 13:15:27 +03:00
|
|
|
switch (C(req->bRequest, req->bmRequestType)) {
|
1998-07-12 23:51:55 +04:00
|
|
|
case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
|
2020-03-14 05:35:33 +03:00
|
|
|
DPRINTF("wValue=0x%04jx", value, 0, 0, 0);
|
2006-04-14 20:31:27 +04:00
|
|
|
if (len == 0)
|
|
|
|
break;
|
2016-04-23 13:15:27 +03:00
|
|
|
switch (value) {
|
2008-02-03 13:57:11 +03:00
|
|
|
#define sd ((usb_string_descriptor_t *)buf)
|
2016-04-23 13:15:27 +03:00
|
|
|
case C(2, UDESC_STRING):
|
|
|
|
/* Product */
|
|
|
|
totlen = usb_makestrdesc(sd, len, "UHCI root hub");
|
1998-07-12 23:51:55 +04:00
|
|
|
break;
|
2016-04-23 13:15:27 +03:00
|
|
|
#undef sd
|
1998-07-12 23:51:55 +04:00
|
|
|
default:
|
2016-04-23 13:15:27 +03:00
|
|
|
/* default from usbroothub */
|
|
|
|
return buflen;
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
break;
|
2016-04-23 13:15:27 +03:00
|
|
|
|
1998-07-12 23:51:55 +04:00
|
|
|
/* Hub requests */
|
|
|
|
case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE):
|
|
|
|
break;
|
|
|
|
case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER):
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTF("UR_CLEAR_PORT_FEATURE port=%jd feature=%jd", index,
|
2016-04-23 13:15:27 +03:00
|
|
|
value, 0, 0);
|
1998-07-12 23:51:55 +04:00
|
|
|
if (index == 1)
|
|
|
|
port = UHCI_PORTSC1;
|
|
|
|
else if (index == 2)
|
|
|
|
port = UHCI_PORTSC2;
|
|
|
|
else {
|
2016-04-23 13:15:27 +03:00
|
|
|
return -1;
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
switch(value) {
|
|
|
|
case UHF_PORT_ENABLE:
|
2001-08-06 19:15:08 +04:00
|
|
|
x = URWMASK(UREAD2(sc, port));
|
1998-07-12 23:51:55 +04:00
|
|
|
UWRITE2(sc, port, x & ~UHCI_PORTSC_PE);
|
|
|
|
break;
|
|
|
|
case UHF_PORT_SUSPEND:
|
2001-08-06 19:15:08 +04:00
|
|
|
x = URWMASK(UREAD2(sc, port));
|
2008-06-16 14:29:41 +04:00
|
|
|
if (!(x & UHCI_PORTSC_SUSP)) /* not suspended */
|
|
|
|
break;
|
|
|
|
UWRITE2(sc, port, x | UHCI_PORTSC_RD);
|
|
|
|
/* see USB2 spec ch. 7.1.7.7 */
|
|
|
|
usb_delay_ms(&sc->sc_bus, 20);
|
1998-07-12 23:51:55 +04:00
|
|
|
UWRITE2(sc, port, x & ~UHCI_PORTSC_SUSP);
|
2008-06-16 14:29:41 +04:00
|
|
|
/* 10ms resume delay must be provided by caller */
|
1998-07-12 23:51:55 +04:00
|
|
|
break;
|
|
|
|
case UHF_PORT_RESET:
|
2001-08-06 19:15:08 +04:00
|
|
|
x = URWMASK(UREAD2(sc, port));
|
1998-07-12 23:51:55 +04:00
|
|
|
UWRITE2(sc, port, x & ~UHCI_PORTSC_PR);
|
|
|
|
break;
|
|
|
|
case UHF_C_PORT_CONNECTION:
|
2001-08-06 19:15:08 +04:00
|
|
|
x = URWMASK(UREAD2(sc, port));
|
1998-07-12 23:51:55 +04:00
|
|
|
UWRITE2(sc, port, x | UHCI_PORTSC_CSC);
|
|
|
|
break;
|
|
|
|
case UHF_C_PORT_ENABLE:
|
2001-08-06 19:15:08 +04:00
|
|
|
x = URWMASK(UREAD2(sc, port));
|
1998-07-12 23:51:55 +04:00
|
|
|
UWRITE2(sc, port, x | UHCI_PORTSC_POEDC);
|
|
|
|
break;
|
|
|
|
case UHF_C_PORT_OVER_CURRENT:
|
2001-08-06 19:15:08 +04:00
|
|
|
x = URWMASK(UREAD2(sc, port));
|
1998-07-12 23:51:55 +04:00
|
|
|
UWRITE2(sc, port, x | UHCI_PORTSC_OCIC);
|
|
|
|
break;
|
|
|
|
case UHF_C_PORT_RESET:
|
|
|
|
sc->sc_isreset = 0;
|
2016-04-23 13:15:27 +03:00
|
|
|
break;
|
1998-07-12 23:51:55 +04:00
|
|
|
case UHF_PORT_CONNECTION:
|
|
|
|
case UHF_PORT_OVER_CURRENT:
|
|
|
|
case UHF_PORT_POWER:
|
|
|
|
case UHF_PORT_LOW_SPEED:
|
|
|
|
case UHF_C_PORT_SUSPEND:
|
|
|
|
default:
|
2016-04-23 13:15:27 +03:00
|
|
|
return -1;
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case C(UR_GET_BUS_STATE, UT_READ_CLASS_OTHER):
|
|
|
|
if (index == 1)
|
|
|
|
port = UHCI_PORTSC1;
|
|
|
|
else if (index == 2)
|
|
|
|
port = UHCI_PORTSC2;
|
|
|
|
else {
|
2016-04-23 13:15:27 +03:00
|
|
|
return -1;
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
if (len > 0) {
|
2016-04-23 13:15:27 +03:00
|
|
|
*(uint8_t *)buf =
|
|
|
|
UHCI_PORTSC_GET_LS(UREAD2(sc, port));
|
1998-07-12 23:51:55 +04:00
|
|
|
totlen = 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE):
|
2006-04-14 20:31:27 +04:00
|
|
|
if (len == 0)
|
|
|
|
break;
|
2003-12-29 11:17:10 +03:00
|
|
|
if ((value & 0xff) != 0) {
|
2016-04-23 13:15:27 +03:00
|
|
|
return -1;
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
2016-04-23 13:15:27 +03:00
|
|
|
usb_hub_descriptor_t hubd;
|
|
|
|
|
Rename min/max -> uimin/uimax for better honesty.
These functions are defined on unsigned int. The generic name
min/max should not silently truncate to 32 bits on 64-bit systems.
This is purely a name change -- no functional change intended.
HOWEVER! Some subsystems have
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))
even though our standard name for that is MIN/MAX. Although these
may invite multiple evaluation bugs, these do _not_ cause integer
truncation.
To avoid `fixing' these cases, I first changed the name in libkern,
and then compile-tested every file where min/max occurred in order to
confirm that it failed -- and thus confirm that nothing shadowed
min/max -- before changing it.
I have left a handful of bootloaders that are too annoying to
compile-test, and some dead code:
cobalt ews4800mips hp300 hppa ia64 luna68k vax
acorn32/if_ie.c (not included in any kernels)
macppc/if_gm.c (superseded by gem(4))
It should be easy to fix the fallout once identified -- this way of
doing things fails safe, and the goal here, after all, is to _avoid_
silent integer truncations, not introduce them.
Maybe one day we can reintroduce min/max as type-generic things that
never silently truncate. But we should avoid doing that for a while,
so that existing code has a chance to be detected by the compiler for
conversion to uimin/uimax without changing the semantics until we can
properly audit it all. (Who knows, maybe in some cases integer
truncation is actually intended!)
2018-09-03 19:29:22 +03:00
|
|
|
totlen = uimin(buflen, sizeof(hubd));
|
2016-04-23 13:15:27 +03:00
|
|
|
memcpy(&hubd, buf, totlen);
|
|
|
|
hubd.bNbrPorts = 2;
|
|
|
|
memcpy(buf, &hubd, totlen);
|
1998-07-12 23:51:55 +04:00
|
|
|
break;
|
|
|
|
case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE):
|
|
|
|
if (len != 4) {
|
2016-04-23 13:15:27 +03:00
|
|
|
return -1;
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
memset(buf, 0, len);
|
|
|
|
totlen = len;
|
|
|
|
break;
|
|
|
|
case C(UR_GET_STATUS, UT_READ_CLASS_OTHER):
|
|
|
|
if (index == 1)
|
|
|
|
port = UHCI_PORTSC1;
|
|
|
|
else if (index == 2)
|
|
|
|
port = UHCI_PORTSC2;
|
|
|
|
else {
|
2016-04-23 13:15:27 +03:00
|
|
|
return -1;
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
if (len != 4) {
|
2016-04-23 13:15:27 +03:00
|
|
|
return -1;
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
x = UREAD2(sc, port);
|
|
|
|
status = change = 0;
|
2001-10-25 06:08:13 +04:00
|
|
|
if (x & UHCI_PORTSC_CCS)
|
1998-07-12 23:51:55 +04:00
|
|
|
status |= UPS_CURRENT_CONNECT_STATUS;
|
2002-02-03 21:15:20 +03:00
|
|
|
if (x & UHCI_PORTSC_CSC)
|
1998-07-12 23:51:55 +04:00
|
|
|
change |= UPS_C_CONNECT_STATUS;
|
2002-02-03 21:15:20 +03:00
|
|
|
if (x & UHCI_PORTSC_PE)
|
1998-07-12 23:51:55 +04:00
|
|
|
status |= UPS_PORT_ENABLED;
|
2002-02-03 21:15:20 +03:00
|
|
|
if (x & UHCI_PORTSC_POEDC)
|
1998-07-12 23:51:55 +04:00
|
|
|
change |= UPS_C_PORT_ENABLED;
|
2002-02-03 21:15:20 +03:00
|
|
|
if (x & UHCI_PORTSC_OCI)
|
1998-07-12 23:51:55 +04:00
|
|
|
status |= UPS_OVERCURRENT_INDICATOR;
|
2002-02-03 21:15:20 +03:00
|
|
|
if (x & UHCI_PORTSC_OCIC)
|
1998-07-12 23:51:55 +04:00
|
|
|
change |= UPS_C_OVERCURRENT_INDICATOR;
|
2002-02-03 21:15:20 +03:00
|
|
|
if (x & UHCI_PORTSC_SUSP)
|
1998-07-12 23:51:55 +04:00
|
|
|
status |= UPS_SUSPEND;
|
2002-02-03 21:15:20 +03:00
|
|
|
if (x & UHCI_PORTSC_LSDA)
|
1998-07-12 23:51:55 +04:00
|
|
|
status |= UPS_LOW_SPEED;
|
|
|
|
status |= UPS_PORT_POWER;
|
|
|
|
if (sc->sc_isreset)
|
|
|
|
change |= UPS_C_PORT_RESET;
|
|
|
|
USETW(ps.wPortStatus, status);
|
|
|
|
USETW(ps.wPortChange, change);
|
Rename min/max -> uimin/uimax for better honesty.
These functions are defined on unsigned int. The generic name
min/max should not silently truncate to 32 bits on 64-bit systems.
This is purely a name change -- no functional change intended.
HOWEVER! Some subsystems have
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))
even though our standard name for that is MIN/MAX. Although these
may invite multiple evaluation bugs, these do _not_ cause integer
truncation.
To avoid `fixing' these cases, I first changed the name in libkern,
and then compile-tested every file where min/max occurred in order to
confirm that it failed -- and thus confirm that nothing shadowed
min/max -- before changing it.
I have left a handful of bootloaders that are too annoying to
compile-test, and some dead code:
cobalt ews4800mips hp300 hppa ia64 luna68k vax
acorn32/if_ie.c (not included in any kernels)
macppc/if_gm.c (superseded by gem(4))
It should be easy to fix the fallout once identified -- this way of
doing things fails safe, and the goal here, after all, is to _avoid_
silent integer truncations, not introduce them.
Maybe one day we can reintroduce min/max as type-generic things that
never silently truncate. But we should avoid doing that for a while,
so that existing code has a chance to be detected by the compiler for
conversion to uimin/uimax without changing the semantics until we can
properly audit it all. (Who knows, maybe in some cases integer
truncation is actually intended!)
2018-09-03 19:29:22 +03:00
|
|
|
totlen = uimin(len, sizeof(ps));
|
2016-04-23 13:15:27 +03:00
|
|
|
memcpy(buf, &ps, totlen);
|
1998-07-12 23:51:55 +04:00
|
|
|
break;
|
|
|
|
case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE):
|
2016-04-23 13:15:27 +03:00
|
|
|
return -1;
|
1998-07-12 23:51:55 +04:00
|
|
|
case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE):
|
|
|
|
break;
|
|
|
|
case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER):
|
|
|
|
if (index == 1)
|
|
|
|
port = UHCI_PORTSC1;
|
|
|
|
else if (index == 2)
|
|
|
|
port = UHCI_PORTSC2;
|
|
|
|
else {
|
2016-04-23 13:15:27 +03:00
|
|
|
return -1;
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
switch(value) {
|
|
|
|
case UHF_PORT_ENABLE:
|
2001-08-06 19:15:08 +04:00
|
|
|
x = URWMASK(UREAD2(sc, port));
|
1998-07-12 23:51:55 +04:00
|
|
|
UWRITE2(sc, port, x | UHCI_PORTSC_PE);
|
|
|
|
break;
|
|
|
|
case UHF_PORT_SUSPEND:
|
2001-08-06 19:15:08 +04:00
|
|
|
x = URWMASK(UREAD2(sc, port));
|
1998-07-12 23:51:55 +04:00
|
|
|
UWRITE2(sc, port, x | UHCI_PORTSC_SUSP);
|
|
|
|
break;
|
|
|
|
case UHF_PORT_RESET:
|
2002-12-31 05:21:31 +03:00
|
|
|
err = uhci_portreset(sc, index);
|
2016-04-23 13:15:27 +03:00
|
|
|
if (err != USBD_NORMAL_COMPLETION)
|
|
|
|
return -1;
|
|
|
|
return 0;
|
2000-04-21 19:40:01 +04:00
|
|
|
case UHF_PORT_POWER:
|
|
|
|
/* Pretend we turned on power */
|
2016-04-23 13:15:27 +03:00
|
|
|
return 0;
|
1998-07-12 23:51:55 +04:00
|
|
|
case UHF_C_PORT_CONNECTION:
|
|
|
|
case UHF_C_PORT_ENABLE:
|
|
|
|
case UHF_C_PORT_OVER_CURRENT:
|
|
|
|
case UHF_PORT_CONNECTION:
|
|
|
|
case UHF_PORT_OVER_CURRENT:
|
|
|
|
case UHF_PORT_LOW_SPEED:
|
|
|
|
case UHF_C_PORT_SUSPEND:
|
|
|
|
case UHF_C_PORT_RESET:
|
|
|
|
default:
|
2016-04-23 13:15:27 +03:00
|
|
|
return -1;
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
2016-04-23 13:15:27 +03:00
|
|
|
/* default from usbroothub */
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTF("returning %jd (usbroothub default)",
|
2016-04-23 13:15:27 +03:00
|
|
|
buflen, 0, 0, 0);
|
|
|
|
return buflen;
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTF("returning %jd", totlen, 0, 0, 0);
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
return totlen;
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Abort a root interrupt request. */
|
|
|
|
void
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_root_intr_abort(struct usbd_xfer *xfer)
|
1998-07-12 23:51:55 +04:00
|
|
|
{
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_softc_t *sc = UHCI_XFER2SC(xfer);
|
1999-06-26 12:30:17 +04:00
|
|
|
|
2012-06-10 10:15:52 +04:00
|
|
|
KASSERT(mutex_owned(&sc->sc_lock));
|
2016-04-23 13:15:27 +03:00
|
|
|
KASSERT(xfer->ux_pipe->up_intrxfer == xfer);
|
2012-06-10 10:15:52 +04:00
|
|
|
|
Fix steady state of root intr xfers.
Why?
- Avoid completing a root intr xfer multiple times in races.
- Avoid potential use-after-free in poll_hub callouts (uhci, ahci).
How?
- Use sc->sc_intr_xfer or equivalent to store only a pending xfer
that has not yet completed -- whether successfully, by timeout, or
by synchronous abort. When any of those happens, set it to null
under the lock, so the xfer is completed only once.
- For hci drivers that use a callout to poll the root hub (uhci, ahci):
. Pass the softc pointer, not the xfer, to the callout, so the
callout is not even tempted to use xfer after free -- if the
callout fires, but the xfer is synchronously aborted before the
callout can do anything, the xfer might be freed by the time the
callout starts to examine it.
. Teach the callout to do nothing if it is callout_pending after it
has fired. This way:
1. completion or synchronous abort can just callout_stop
2. start can just callout_schedule
If the callout had already fired before (1), and doesn't acquire
the bus lock until after (2), it may be tempted to abort the new
root intr xfer just after submission, which would be wrong -- so
instead we just have the callout do nothing if it notices it has
been rescheduled, since it will fire again after the appropriate
time has elapsed.
2020-02-12 19:02:01 +03:00
|
|
|
/*
|
|
|
|
* Try to stop the callout before it starts. If we got in too
|
|
|
|
* late, too bad; but if the callout had yet to run and time
|
|
|
|
* out the xfer, cancel it ourselves.
|
|
|
|
*/
|
2010-11-04 01:34:23 +03:00
|
|
|
callout_stop(&sc->sc_poll_handle);
|
Fix steady state of root intr xfers.
Why?
- Avoid completing a root intr xfer multiple times in races.
- Avoid potential use-after-free in poll_hub callouts (uhci, ahci).
How?
- Use sc->sc_intr_xfer or equivalent to store only a pending xfer
that has not yet completed -- whether successfully, by timeout, or
by synchronous abort. When any of those happens, set it to null
under the lock, so the xfer is completed only once.
- For hci drivers that use a callout to poll the root hub (uhci, ahci):
. Pass the softc pointer, not the xfer, to the callout, so the
callout is not even tempted to use xfer after free -- if the
callout fires, but the xfer is synchronously aborted before the
callout can do anything, the xfer might be freed by the time the
callout starts to examine it.
. Teach the callout to do nothing if it is callout_pending after it
has fired. This way:
1. completion or synchronous abort can just callout_stop
2. start can just callout_schedule
If the callout had already fired before (1), and doesn't acquire
the bus lock until after (2), it may be tempted to abort the new
root intr xfer just after submission, which would be wrong -- so
instead we just have the callout do nothing if it notices it has
been rescheduled, since it will fire again after the appropriate
time has elapsed.
2020-02-12 19:02:01 +03:00
|
|
|
if (sc->sc_intr_xfer == NULL)
|
|
|
|
return;
|
1999-10-13 00:02:47 +04:00
|
|
|
|
Fix steady state of root intr xfers.
Why?
- Avoid completing a root intr xfer multiple times in races.
- Avoid potential use-after-free in poll_hub callouts (uhci, ahci).
How?
- Use sc->sc_intr_xfer or equivalent to store only a pending xfer
that has not yet completed -- whether successfully, by timeout, or
by synchronous abort. When any of those happens, set it to null
under the lock, so the xfer is completed only once.
- For hci drivers that use a callout to poll the root hub (uhci, ahci):
. Pass the softc pointer, not the xfer, to the callout, so the
callout is not even tempted to use xfer after free -- if the
callout fires, but the xfer is synchronously aborted before the
callout can do anything, the xfer might be freed by the time the
callout starts to examine it.
. Teach the callout to do nothing if it is callout_pending after it
has fired. This way:
1. completion or synchronous abort can just callout_stop
2. start can just callout_schedule
If the callout had already fired before (1), and doesn't acquire
the bus lock until after (2), it may be tempted to abort the new
root intr xfer just after submission, which would be wrong -- so
instead we just have the callout do nothing if it notices it has
been rescheduled, since it will fire again after the appropriate
time has elapsed.
2020-02-12 19:02:01 +03:00
|
|
|
KASSERT(sc->sc_intr_xfer == xfer);
|
2020-02-14 19:47:11 +03:00
|
|
|
KASSERT(xfer->ux_status == USBD_IN_PROGRESS);
|
2016-04-23 13:15:27 +03:00
|
|
|
xfer->ux_status = USBD_CANCELLED;
|
2000-03-25 21:02:32 +03:00
|
|
|
#ifdef DIAGNOSTIC
|
2016-04-23 13:15:27 +03:00
|
|
|
UHCI_XFER2UXFER(xfer)->ux_isdone = true;
|
2000-03-25 21:02:32 +03:00
|
|
|
#endif
|
1999-11-12 03:34:57 +03:00
|
|
|
usb_transfer_complete(xfer);
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
usbd_status
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_root_intr_transfer(struct usbd_xfer *xfer)
|
1998-12-28 23:13:59 +03:00
|
|
|
{
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_softc_t *sc = UHCI_XFER2SC(xfer);
|
1999-11-12 03:34:57 +03:00
|
|
|
usbd_status err;
|
1998-12-28 23:13:59 +03:00
|
|
|
|
1999-09-14 01:33:25 +04:00
|
|
|
/* Insert last in queue. */
|
2012-06-10 10:15:52 +04:00
|
|
|
mutex_enter(&sc->sc_lock);
|
1999-11-12 03:34:57 +03:00
|
|
|
err = usb_insert_transfer(xfer);
|
2012-06-10 10:15:52 +04:00
|
|
|
mutex_exit(&sc->sc_lock);
|
1999-11-12 03:34:57 +03:00
|
|
|
if (err)
|
2016-04-23 13:15:27 +03:00
|
|
|
return err;
|
1999-09-14 01:33:25 +04:00
|
|
|
|
2005-04-27 11:47:25 +04:00
|
|
|
/*
|
|
|
|
* Pipe isn't running (otherwise err would be USBD_INPROG),
|
1999-11-19 02:32:25 +03:00
|
|
|
* start first
|
|
|
|
*/
|
2016-04-23 13:15:27 +03:00
|
|
|
return uhci_root_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
|
1998-12-28 23:13:59 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Start a transfer on the root interrupt pipe */
|
|
|
|
usbd_status
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_root_intr_start(struct usbd_xfer *xfer)
|
1998-07-12 23:51:55 +04:00
|
|
|
{
|
2016-04-23 13:15:27 +03:00
|
|
|
struct usbd_pipe *pipe = xfer->ux_pipe;
|
|
|
|
uhci_softc_t *sc = UHCI_PIPE2SC(pipe);
|
2003-07-03 15:24:13 +04:00
|
|
|
unsigned int ival;
|
Fix steady state of root intr xfers.
Why?
- Avoid completing a root intr xfer multiple times in races.
- Avoid potential use-after-free in poll_hub callouts (uhci, ahci).
How?
- Use sc->sc_intr_xfer or equivalent to store only a pending xfer
that has not yet completed -- whether successfully, by timeout, or
by synchronous abort. When any of those happens, set it to null
under the lock, so the xfer is completed only once.
- For hci drivers that use a callout to poll the root hub (uhci, ahci):
. Pass the softc pointer, not the xfer, to the callout, so the
callout is not even tempted to use xfer after free -- if the
callout fires, but the xfer is synchronously aborted before the
callout can do anything, the xfer might be freed by the time the
callout starts to examine it.
. Teach the callout to do nothing if it is callout_pending after it
has fired. This way:
1. completion or synchronous abort can just callout_stop
2. start can just callout_schedule
If the callout had already fired before (1), and doesn't acquire
the bus lock until after (2), it may be tempted to abort the new
root intr xfer just after submission, which would be wrong -- so
instead we just have the callout do nothing if it notices it has
been rescheduled, since it will fire again after the appropriate
time has elapsed.
2020-02-12 19:02:01 +03:00
|
|
|
const bool polling = sc->sc_bus.ub_usepolling;
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2016-04-23 13:15:27 +03:00
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
Update the kernhist(9) kernel history code to address issues identified
in PR kern/52639, as well as some general cleaning-up...
(As proposed on tech-kern@ with additional changes and enhancements.)
Details of changes:
* All history arguments are now stored as uintmax_t values[1], both in
the kernel and in the structures used for exporting the history data
to userland via sysctl(9). This avoids problems on some architectures
where passing a 64-bit (or larger) value to printf(3) can cause it to
process the value as multiple arguments. (This can be particularly
problematic when printf()'s format string is not a literal, since in
that case the compiler cannot know how large each argument should be.)
* Update the data structures used for exporting kernel history data to
include a version number as well as the length of history arguments.
* All [2] existing users of kernhist(9) have had their format strings
updated. Each format specifier now includes an explicit length
modifier 'j' to refer to numeric values of the size of uintmax_t.
* All [2] existing users of kernhist(9) have had their format strings
updated to replace uses of "%p" with "%#jx", and the pointer
arguments are now cast to (uintptr_t) before being subsequently cast
to (uintmax_t). This is needed to avoid compiler warnings about
casting "pointer to integer of a different size."
* All [2] existing users of kernhist(9) have had instances of "%s" or
"%c" format strings replaced with numeric formats; several instances
of mis-match between format string and argument list have been fixed.
* vmstat(1) has been modified to handle the new size of arguments in the
history data as exported by sysctl(9).
* vmstat(1) now provides a warning message if the history requested with
the -u option does not exist (previously, this condition was silently
ignored, with only a single blank line being printed).
* vmstat(1) now checks the version and argument length included in the
data exported via sysctl(9) and exits if they do not match the values
with which vmstat was built.
* The kernhist(9) man-page has been updated to note the additional
requirements imposed on the format strings, along with several other
minor changes and enhancements.
[1] It would have been possible to use an explicit length (for example,
uint64_t) for the history arguments. But that would require another
"rototill" of all the users in the future when we add support for an
architecture that supports a larger size. Also, the printf(3) format
specifiers for explicitly-sized values, such as "%"PRIu64, are much
more verbose (and less aesthetically appealing, IMHO) than simply
using "%ju".
[2] I've tried very hard to find "all [the] existing users of kernhist(9)"
but it is possible that I've missed some of them. I would be glad to
update any stragglers that anyone identifies.
2017-10-28 03:37:11 +03:00
|
|
|
DPRINTF("xfer=%#jx len=%jd flags=%jd", (uintptr_t)xfer, xfer->ux_length,
|
2016-04-23 13:15:27 +03:00
|
|
|
xfer->ux_flags, 0);
|
1998-07-12 23:51:55 +04:00
|
|
|
|
2000-01-26 13:04:38 +03:00
|
|
|
if (sc->sc_dying)
|
2016-04-23 13:15:27 +03:00
|
|
|
return USBD_IOERROR;
|
2000-01-26 13:04:38 +03:00
|
|
|
|
Fix steady state of root intr xfers.
Why?
- Avoid completing a root intr xfer multiple times in races.
- Avoid potential use-after-free in poll_hub callouts (uhci, ahci).
How?
- Use sc->sc_intr_xfer or equivalent to store only a pending xfer
that has not yet completed -- whether successfully, by timeout, or
by synchronous abort. When any of those happens, set it to null
under the lock, so the xfer is completed only once.
- For hci drivers that use a callout to poll the root hub (uhci, ahci):
. Pass the softc pointer, not the xfer, to the callout, so the
callout is not even tempted to use xfer after free -- if the
callout fires, but the xfer is synchronously aborted before the
callout can do anything, the xfer might be freed by the time the
callout starts to examine it.
. Teach the callout to do nothing if it is callout_pending after it
has fired. This way:
1. completion or synchronous abort can just callout_stop
2. start can just callout_schedule
If the callout had already fired before (1), and doesn't acquire
the bus lock until after (2), it may be tempted to abort the new
root intr xfer just after submission, which would be wrong -- so
instead we just have the callout do nothing if it notices it has
been rescheduled, since it will fire again after the appropriate
time has elapsed.
2020-02-12 19:02:01 +03:00
|
|
|
if (!polling)
|
|
|
|
mutex_enter(&sc->sc_lock);
|
|
|
|
|
|
|
|
KASSERT(sc->sc_intr_xfer == NULL);
|
|
|
|
|
2003-07-03 15:24:13 +04:00
|
|
|
/* XXX temporary variable needed to avoid gcc3 warning */
|
2016-04-23 13:15:27 +03:00
|
|
|
ival = xfer->ux_pipe->up_endpoint->ue_edesc->bInterval;
|
2003-07-03 15:24:13 +04:00
|
|
|
sc->sc_ival = mstohz(ival);
|
Fix steady state of root intr xfers.
Why?
- Avoid completing a root intr xfer multiple times in races.
- Avoid potential use-after-free in poll_hub callouts (uhci, ahci).
How?
- Use sc->sc_intr_xfer or equivalent to store only a pending xfer
that has not yet completed -- whether successfully, by timeout, or
by synchronous abort. When any of those happens, set it to null
under the lock, so the xfer is completed only once.
- For hci drivers that use a callout to poll the root hub (uhci, ahci):
. Pass the softc pointer, not the xfer, to the callout, so the
callout is not even tempted to use xfer after free -- if the
callout fires, but the xfer is synchronously aborted before the
callout can do anything, the xfer might be freed by the time the
callout starts to examine it.
. Teach the callout to do nothing if it is callout_pending after it
has fired. This way:
1. completion or synchronous abort can just callout_stop
2. start can just callout_schedule
If the callout had already fired before (1), and doesn't acquire
the bus lock until after (2), it may be tempted to abort the new
root intr xfer just after submission, which would be wrong -- so
instead we just have the callout do nothing if it notices it has
been rescheduled, since it will fire again after the appropriate
time has elapsed.
2020-02-12 19:02:01 +03:00
|
|
|
callout_schedule(&sc->sc_poll_handle, sc->sc_ival);
|
2000-03-25 21:02:32 +03:00
|
|
|
sc->sc_intr_xfer = xfer;
|
2020-02-15 04:21:56 +03:00
|
|
|
xfer->ux_status = USBD_IN_PROGRESS;
|
Fix steady state of root intr xfers.
Why?
- Avoid completing a root intr xfer multiple times in races.
- Avoid potential use-after-free in poll_hub callouts (uhci, ahci).
How?
- Use sc->sc_intr_xfer or equivalent to store only a pending xfer
that has not yet completed -- whether successfully, by timeout, or
by synchronous abort. When any of those happens, set it to null
under the lock, so the xfer is completed only once.
- For hci drivers that use a callout to poll the root hub (uhci, ahci):
. Pass the softc pointer, not the xfer, to the callout, so the
callout is not even tempted to use xfer after free -- if the
callout fires, but the xfer is synchronously aborted before the
callout can do anything, the xfer might be freed by the time the
callout starts to examine it.
. Teach the callout to do nothing if it is callout_pending after it
has fired. This way:
1. completion or synchronous abort can just callout_stop
2. start can just callout_schedule
If the callout had already fired before (1), and doesn't acquire
the bus lock until after (2), it may be tempted to abort the new
root intr xfer just after submission, which would be wrong -- so
instead we just have the callout do nothing if it notices it has
been rescheduled, since it will fire again after the appropriate
time has elapsed.
2020-02-12 19:02:01 +03:00
|
|
|
|
|
|
|
if (!polling)
|
|
|
|
mutex_exit(&sc->sc_lock);
|
|
|
|
|
2020-02-15 04:21:56 +03:00
|
|
|
return USBD_IN_PROGRESS;
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Close the root interrupt pipe. */
|
|
|
|
void
|
2016-04-23 13:15:27 +03:00
|
|
|
uhci_root_intr_close(struct usbd_pipe *pipe)
|
1998-07-12 23:51:55 +04:00
|
|
|
{
|
Fix steady state of root intr xfers.
Why?
- Avoid completing a root intr xfer multiple times in races.
- Avoid potential use-after-free in poll_hub callouts (uhci, ahci).
How?
- Use sc->sc_intr_xfer or equivalent to store only a pending xfer
that has not yet completed -- whether successfully, by timeout, or
by synchronous abort. When any of those happens, set it to null
under the lock, so the xfer is completed only once.
- For hci drivers that use a callout to poll the root hub (uhci, ahci):
. Pass the softc pointer, not the xfer, to the callout, so the
callout is not even tempted to use xfer after free -- if the
callout fires, but the xfer is synchronously aborted before the
callout can do anything, the xfer might be freed by the time the
callout starts to examine it.
. Teach the callout to do nothing if it is callout_pending after it
has fired. This way:
1. completion or synchronous abort can just callout_stop
2. start can just callout_schedule
If the callout had already fired before (1), and doesn't acquire
the bus lock until after (2), it may be tempted to abort the new
root intr xfer just after submission, which would be wrong -- so
instead we just have the callout do nothing if it notices it has
been rescheduled, since it will fire again after the appropriate
time has elapsed.
2020-02-12 19:02:01 +03:00
|
|
|
uhci_softc_t *sc __diagused = UHCI_PIPE2SC(pipe);
|
2016-04-23 13:15:27 +03:00
|
|
|
UHCIHIST_FUNC(); UHCIHIST_CALLED();
|
1999-06-26 12:30:17 +04:00
|
|
|
|
2012-06-10 10:15:52 +04:00
|
|
|
KASSERT(mutex_owned(&sc->sc_lock));
|
|
|
|
|
Fix steady state of root intr xfers.
Why?
- Avoid completing a root intr xfer multiple times in races.
- Avoid potential use-after-free in poll_hub callouts (uhci, ahci).
How?
- Use sc->sc_intr_xfer or equivalent to store only a pending xfer
that has not yet completed -- whether successfully, by timeout, or
by synchronous abort. When any of those happens, set it to null
under the lock, so the xfer is completed only once.
- For hci drivers that use a callout to poll the root hub (uhci, ahci):
. Pass the softc pointer, not the xfer, to the callout, so the
callout is not even tempted to use xfer after free -- if the
callout fires, but the xfer is synchronously aborted before the
callout can do anything, the xfer might be freed by the time the
callout starts to examine it.
. Teach the callout to do nothing if it is callout_pending after it
has fired. This way:
1. completion or synchronous abort can just callout_stop
2. start can just callout_schedule
If the callout had already fired before (1), and doesn't acquire
the bus lock until after (2), it may be tempted to abort the new
root intr xfer just after submission, which would be wrong -- so
instead we just have the callout do nothing if it notices it has
been rescheduled, since it will fire again after the appropriate
time has elapsed.
2020-02-12 19:02:01 +03:00
|
|
|
/*
|
|
|
|
* The caller must arrange to have aborted the pipe already, so
|
|
|
|
* there can be no intr xfer in progress. The callout may
|
|
|
|
* still be pending from a prior intr xfer -- if it has already
|
|
|
|
* fired, it will see there is nothing to do, and do nothing.
|
|
|
|
*/
|
|
|
|
KASSERT(sc->sc_intr_xfer == NULL);
|
|
|
|
KASSERT(!callout_pending(&sc->sc_poll_handle));
|
1998-07-12 23:51:55 +04:00
|
|
|
}
|