diff options
Diffstat (limited to 'sys/dev')
29 files changed, 534 insertions, 723 deletions
diff --git a/sys/dev/ata/ata-all.c b/sys/dev/ata/ata-all.c index 2e46808..80bb804 100644 --- a/sys/dev/ata/ata-all.c +++ b/sys/dev/ata/ata-all.c @@ -64,18 +64,15 @@ static void ata_cam_end_transaction(device_t dev, struct ata_request *request); static void ata_cam_request_sense(device_t dev, struct ata_request *request); static int ata_check_ids(device_t dev, union ccb *ccb); static void ata_conn_event(void *context, int dummy); -static void ata_init(void); static void ata_interrupt_locked(void *data); static int ata_module_event_handler(module_t mod, int what, void *arg); static void ata_periodic_poll(void *data); static int ata_str2mode(const char *str); -static void ata_uninit(void); /* global vars */ MALLOC_DEFINE(M_ATA, "ata_generic", "ATA driver generic layer"); int (*ata_raid_ioctl_func)(u_long cmd, caddr_t data) = NULL; devclass_t ata_devclass; -uma_zone_t ata_request_zone; int ata_dma_check_80pin = 1; /* sysctl vars */ @@ -651,12 +648,7 @@ ata_cam_begin_transaction(device_t dev, union ccb *ccb) struct ata_channel *ch = device_get_softc(dev); struct ata_request *request; - if (!(request = ata_alloc_request())) { - device_printf(dev, "FAILURE - out of memory in start\n"); - ccb->ccb_h.status = CAM_REQ_INVALID; - xpt_done(ccb); - return; - } + request = &ch->request; bzero(request, sizeof(*request)); /* setup request */ @@ -795,7 +787,6 @@ ata_cam_process_sense(device_t dev, struct ata_request *request) ccb->ccb_h.status |= CAM_AUTOSENSE_FAIL; } - ata_free_request(request); xpt_done(ccb); /* Do error recovery if needed. */ if (fatalerr) @@ -866,10 +857,8 @@ ata_cam_end_transaction(device_t dev, struct ata_request *request) if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_SCSI_STATUS_ERROR && (ccb->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0) ata_cam_request_sense(dev, request); - else { - ata_free_request(request); + else xpt_done(ccb); - } /* Do error recovery if needed. */ if (fatalerr) ata_reinit(dev); @@ -1149,18 +1138,3 @@ static moduledata_t ata_moduledata = { "ata", ata_module_event_handler, NULL }; DECLARE_MODULE(ata, ata_moduledata, SI_SUB_CONFIGURE, SI_ORDER_SECOND); MODULE_VERSION(ata, 1); MODULE_DEPEND(ata, cam, 1, 1, 1); - -static void -ata_init(void) -{ - ata_request_zone = uma_zcreate("ata_request", sizeof(struct ata_request), - NULL, NULL, NULL, NULL, 0, 0); -} -SYSINIT(ata_register, SI_SUB_DRIVERS, SI_ORDER_SECOND, ata_init, NULL); - -static void -ata_uninit(void) -{ - uma_zdestroy(ata_request_zone); -} -SYSUNINIT(ata_unregister, SI_SUB_DRIVERS, SI_ORDER_SECOND, ata_uninit, NULL); diff --git a/sys/dev/ata/ata-all.h b/sys/dev/ata/ata-all.h index 19cb7ef..cf8ed78 100644 --- a/sys/dev/ata/ata-all.h +++ b/sys/dev/ata/ata-all.h @@ -450,6 +450,7 @@ struct ata_channel { struct ata_cam_device curr[16]; /* Current settings */ int requestsense; /* CCB waiting for SENSE. */ struct callout poll_callout; /* Periodic status poll. */ + struct ata_request request; }; /* disk bay/enclosure related */ @@ -507,14 +508,6 @@ int ata_sata_getrev(device_t dev, int target); int ata_request2fis_h2d(struct ata_request *request, u_int8_t *fis); void ata_pm_identify(device_t dev); -/* macros for alloc/free of struct ata_request */ -extern uma_zone_t ata_request_zone; -#define ata_alloc_request() uma_zalloc(ata_request_zone, M_NOWAIT | M_ZERO) -#define ata_free_request(request) { \ - if (!(request->flags & ATA_R_DANGER2)) \ - uma_zfree(ata_request_zone, request); \ - } - MALLOC_DECLARE(M_ATA); /* misc newbus defines */ diff --git a/sys/dev/ciss/ciss.c b/sys/dev/ciss/ciss.c index cfb24c9..a465fac 100644 --- a/sys/dev/ciss/ciss.c +++ b/sys/dev/ciss/ciss.c @@ -4018,8 +4018,7 @@ static void ciss_notify_logical(struct ciss_softc *sc, struct ciss_notify *cn) { struct ciss_ldrive *ld; - int bus, target; - int rescan_ld; + int ostatus, bus, target; debug_called(2); @@ -4042,6 +4041,7 @@ ciss_notify_logical(struct ciss_softc *sc, struct ciss_notify *cn) /* * Update our idea of the drive's status. */ + ostatus = ciss_decode_ldrive_status(cn->data.logical_status.previous_state); ld->cl_status = ciss_decode_ldrive_status(cn->data.logical_status.new_state); if (ld->cl_lstatus != NULL) ld->cl_lstatus->status = cn->data.logical_status.new_state; @@ -4049,9 +4049,7 @@ ciss_notify_logical(struct ciss_softc *sc, struct ciss_notify *cn) /* * Have CAM rescan the drive if its status has changed. */ - rescan_ld = (cn->data.logical_status.previous_state != - cn->data.logical_status.new_state) ? 1 : 0; - if (rescan_ld) { + if (ostatus != ld->cl_status) { ld->cl_update = 1; ciss_notify_rescan_logical(sc); } diff --git a/sys/dev/filemon/filemon.c b/sys/dev/filemon/filemon.c index c711e3d..f8a698f 100644 --- a/sys/dev/filemon/filemon.c +++ b/sys/dev/filemon/filemon.c @@ -1,6 +1,7 @@ /*- * Copyright (c) 2011, David E. O'Brien. * Copyright (c) 2009-2011, Juniper Networks, Inc. + * Copyright (c) 2015, EMC Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -39,12 +40,14 @@ __FBSDID("$FreeBSD$"); #include <sys/fcntl.h> #include <sys/ioccom.h> #include <sys/kernel.h> +#include <sys/lock.h> #include <sys/malloc.h> #include <sys/module.h> #include <sys/mutex.h> #include <sys/poll.h> #include <sys/proc.h> #include <sys/queue.h> +#include <sys/sx.h> #include <sys/syscall.h> #include <sys/sysent.h> #include <sys/sysproto.h> @@ -85,12 +88,8 @@ MALLOC_DEFINE(M_FILEMON, "filemon", "File access monitor"); struct filemon { TAILQ_ENTRY(filemon) link; /* Link into the in-use list. */ - struct mtx mtx; /* Lock mutex for this filemon. */ - struct cv cv; /* Lock condition variable for this - filemon. */ + struct sx lock; /* Lock mutex for this filemon. */ struct file *fp; /* Output file pointer. */ - struct thread *locker; /* Ptr to the thread locking this - filemon. */ pid_t pid; /* The process ID being monitored. */ char fname1[MAXPATHLEN]; /* Temporary filename buffer. */ char fname2[MAXPATHLEN]; /* Temporary filename buffer. */ @@ -99,11 +98,7 @@ struct filemon { static TAILQ_HEAD(, filemon) filemons_inuse = TAILQ_HEAD_INITIALIZER(filemons_inuse); static TAILQ_HEAD(, filemon) filemons_free = TAILQ_HEAD_INITIALIZER(filemons_free); -static int n_readers = 0; -static struct mtx access_mtx; -static struct cv access_cv; -static struct thread *access_owner = NULL; -static struct thread *access_requester = NULL; +static struct sx access_lock; static struct cdev *filemon_dev; @@ -203,8 +198,7 @@ filemon_open(struct cdev *dev, int oflags __unused, int devtype __unused, filemon->fp = NULL; - mtx_init(&filemon->mtx, "filemon", "filemon", MTX_DEF); - cv_init(&filemon->cv, "filemon"); + sx_init(&filemon->lock, "filemon"); } filemon->pid = curproc->p_pid; @@ -234,8 +228,7 @@ filemon_close(struct cdev *dev __unused, int flag __unused, int fmt __unused, static void filemon_load(void *dummy __unused) { - mtx_init(&access_mtx, "filemon", "filemon", MTX_DEF); - cv_init(&access_cv, "filemon"); + sx_init(&access_lock, "filemons_inuse"); /* Install the syscall wrappers. */ filemon_wrapper_install(); @@ -270,14 +263,12 @@ filemon_unload(void) filemon_lock_write(); while ((filemon = TAILQ_FIRST(&filemons_free)) != NULL) { TAILQ_REMOVE(&filemons_free, filemon, link); - mtx_destroy(&filemon->mtx); - cv_destroy(&filemon->cv); + sx_destroy(&filemon->lock); free(filemon, M_FILEMON); } filemon_unlock_write(); - mtx_destroy(&access_mtx); - cv_destroy(&access_cv); + sx_destroy(&access_lock); } return (error); diff --git a/sys/dev/filemon/filemon_lock.c b/sys/dev/filemon/filemon_lock.c index 6e836d1..a0347000 100644 --- a/sys/dev/filemon/filemon_lock.c +++ b/sys/dev/filemon/filemon_lock.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2009-2011, Juniper Networks, Inc. + * Copyright (c) 2015, EMC Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,96 +28,44 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -static void +static __inline void filemon_filemon_lock(struct filemon *filemon) { - mtx_lock(&filemon->mtx); - while (filemon->locker != NULL && filemon->locker != curthread) - cv_wait(&filemon->cv, &filemon->mtx); - - filemon->locker = curthread; - - mtx_unlock(&filemon->mtx); + sx_xlock(&filemon->lock); } -static void +static __inline void filemon_filemon_unlock(struct filemon *filemon) { - mtx_lock(&filemon->mtx); - - if (filemon->locker == curthread) - filemon->locker = NULL; - - /* Wake up threads waiting. */ - cv_broadcast(&filemon->cv); - mtx_unlock(&filemon->mtx); + sx_xunlock(&filemon->lock); } -static void +static __inline void filemon_lock_read(void) { - mtx_lock(&access_mtx); - - while (access_owner != NULL || access_requester != NULL) - cv_wait(&access_cv, &access_mtx); - - n_readers++; - - /* Wake up threads waiting. */ - cv_broadcast(&access_cv); - mtx_unlock(&access_mtx); + sx_slock(&access_lock); } -static void +static __inline void filemon_unlock_read(void) { - mtx_lock(&access_mtx); - if (n_readers > 0) - n_readers--; - - /* Wake up a thread waiting. */ - cv_broadcast(&access_cv); - - mtx_unlock(&access_mtx); + sx_sunlock(&access_lock); } -static void +static __inline void filemon_lock_write(void) { - mtx_lock(&access_mtx); - - while (access_owner != curthread) { - if (access_owner == NULL && - (access_requester == NULL || - access_requester == curthread)) { - access_owner = curthread; - access_requester = NULL; - } else { - if (access_requester == NULL) - access_requester = curthread; - cv_wait(&access_cv, &access_mtx); - } - } - - mtx_unlock(&access_mtx); + sx_xlock(&access_lock); } -static void +static __inline void filemon_unlock_write(void) { - mtx_lock(&access_mtx); - - /* Sanity check that the current thread actually has the write lock. */ - if (access_owner == curthread) - access_owner = NULL; - - /* Wake up a thread waiting. */ - cv_broadcast(&access_cv); - mtx_unlock(&access_mtx); + sx_xunlock(&access_lock); } diff --git a/sys/dev/filemon/filemon_wrapper.c b/sys/dev/filemon/filemon_wrapper.c index 4a1259a..d107a40 100644 --- a/sys/dev/filemon/filemon_wrapper.c +++ b/sys/dev/filemon/filemon_wrapper.c @@ -1,6 +1,7 @@ /*- * Copyright (c) 2011, David E. O'Brien. * Copyright (c) 2009-2011, Juniper Networks, Inc. + * Copyright (c) 2015, EMC Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -86,17 +87,25 @@ filemon_pid_check(struct proc *p) { struct filemon *filemon; + filemon_lock_read(); + if (TAILQ_EMPTY(&filemons_inuse)) { + filemon_unlock_read(); + return (NULL); + } sx_slock(&proctree_lock); while (p != initproc) { TAILQ_FOREACH(filemon, &filemons_inuse, link) { if (p->p_pid == filemon->pid) { sx_sunlock(&proctree_lock); + filemon_filemon_lock(filemon); + filemon_unlock_read(); return (filemon); } } p = proc_realparent(p); } sx_sunlock(&proctree_lock); + filemon_unlock_read(); return (NULL); } @@ -109,9 +118,6 @@ filemon_comment(struct filemon *filemon) /* Load timestamp before locking. Less accurate but less contention. */ getmicrotime(&now); - /* Grab a read lock on the filemon inuse list. */ - filemon_lock_read(); - /* Lock the found filemon structure. */ filemon_filemon_lock(filemon); @@ -124,9 +130,6 @@ filemon_comment(struct filemon *filemon) /* Unlock the found filemon structure. */ filemon_filemon_unlock(filemon); - - /* Release the read lock. */ - filemon_unlock_read(); } static int @@ -138,13 +141,7 @@ filemon_wrapper_chdir(struct thread *td, struct chdir_args *uap) struct filemon *filemon; if ((ret = sys_chdir(td, uap)) == 0) { - /* Grab a read lock on the filemon inuse list. */ - filemon_lock_read(); - if ((filemon = filemon_pid_check(curproc)) != NULL) { - /* Lock the found filemon structure. */ - filemon_filemon_lock(filemon); - copyinstr(uap->path, filemon->fname1, sizeof(filemon->fname1), &done); @@ -157,9 +154,6 @@ filemon_wrapper_chdir(struct thread *td, struct chdir_args *uap) /* Unlock the found filemon structure. */ filemon_filemon_unlock(filemon); } - - /* Release the read lock. */ - filemon_unlock_read(); } return (ret); @@ -177,13 +171,7 @@ filemon_wrapper_execve(struct thread *td, struct execve_args *uap) copyinstr(uap->fname, fname, sizeof(fname), &done); if ((ret = sys_execve(td, uap)) == 0) { - /* Grab a read lock on the filemon inuse list. */ - filemon_lock_read(); - if ((filemon = filemon_pid_check(curproc)) != NULL) { - /* Lock the found filemon structure. */ - filemon_filemon_lock(filemon); - len = snprintf(filemon->msgbufr, sizeof(filemon->msgbufr), "E %d %s\n", curproc->p_pid, fname); @@ -193,9 +181,6 @@ filemon_wrapper_execve(struct thread *td, struct execve_args *uap) /* Unlock the found filemon structure. */ filemon_filemon_unlock(filemon); } - - /* Release the read lock. */ - filemon_unlock_read(); } return (ret); @@ -215,13 +200,7 @@ filemon_wrapper_freebsd32_execve(struct thread *td, copyinstr(uap->fname, fname, sizeof(fname), &done); if ((ret = freebsd32_execve(td, uap)) == 0) { - /* Grab a read lock on the filemon inuse list. */ - filemon_lock_read(); - if ((filemon = filemon_pid_check(curproc)) != NULL) { - /* Lock the found filemon structure. */ - filemon_filemon_lock(filemon); - len = snprintf(filemon->msgbufr, sizeof(filemon->msgbufr), "E %d %s\n", curproc->p_pid, fname); @@ -231,9 +210,6 @@ filemon_wrapper_freebsd32_execve(struct thread *td, /* Unlock the found filemon structure. */ filemon_filemon_unlock(filemon); } - - /* Release the read lock. */ - filemon_unlock_read(); } return (ret); @@ -248,13 +224,7 @@ filemon_wrapper_fork(struct thread *td, struct fork_args *uap) struct filemon *filemon; if ((ret = sys_fork(td, uap)) == 0) { - /* Grab a read lock on the filemon inuse list. */ - filemon_lock_read(); - if ((filemon = filemon_pid_check(curproc)) != NULL) { - /* Lock the found filemon structure. */ - filemon_filemon_lock(filemon); - len = snprintf(filemon->msgbufr, sizeof(filemon->msgbufr), "F %d %ld\n", curproc->p_pid, (long)curthread->td_retval[0]); @@ -264,9 +234,6 @@ filemon_wrapper_fork(struct thread *td, struct fork_args *uap) /* Unlock the found filemon structure. */ filemon_filemon_unlock(filemon); } - - /* Release the read lock. */ - filemon_unlock_read(); } return (ret); @@ -281,13 +248,7 @@ filemon_wrapper_open(struct thread *td, struct open_args *uap) struct filemon *filemon; if ((ret = sys_open(td, uap)) == 0) { - /* Grab a read lock on the filemon inuse list. */ - filemon_lock_read(); - if ((filemon = filemon_pid_check(curproc)) != NULL) { - /* Lock the found filemon structure. */ - filemon_filemon_lock(filemon); - copyinstr(uap->path, filemon->fname1, sizeof(filemon->fname1), &done); @@ -313,9 +274,6 @@ filemon_wrapper_open(struct thread *td, struct open_args *uap) /* Unlock the found filemon structure. */ filemon_filemon_unlock(filemon); } - - /* Release the read lock. */ - filemon_unlock_read(); } return (ret); @@ -330,13 +288,7 @@ filemon_wrapper_openat(struct thread *td, struct openat_args *uap) struct filemon *filemon; if ((ret = sys_openat(td, uap)) == 0) { - /* Grab a read lock on the filemon inuse list. */ - filemon_lock_read(); - if ((filemon = filemon_pid_check(curproc)) != NULL) { - /* Lock the found filemon structure. */ - filemon_filemon_lock(filemon); - copyinstr(uap->path, filemon->fname1, sizeof(filemon->fname1), &done); @@ -375,9 +327,6 @@ filemon_wrapper_openat(struct thread *td, struct openat_args *uap) /* Unlock the found filemon structure. */ filemon_filemon_unlock(filemon); } - - /* Release the read lock. */ - filemon_unlock_read(); } return (ret); @@ -392,13 +341,7 @@ filemon_wrapper_rename(struct thread *td, struct rename_args *uap) struct filemon *filemon; if ((ret = sys_rename(td, uap)) == 0) { - /* Grab a read lock on the filemon inuse list. */ - filemon_lock_read(); - if ((filemon = filemon_pid_check(curproc)) != NULL) { - /* Lock the found filemon structure. */ - filemon_filemon_lock(filemon); - copyinstr(uap->from, filemon->fname1, sizeof(filemon->fname1), &done); copyinstr(uap->to, filemon->fname2, @@ -413,9 +356,6 @@ filemon_wrapper_rename(struct thread *td, struct rename_args *uap) /* Unlock the found filemon structure. */ filemon_filemon_unlock(filemon); } - - /* Release the read lock. */ - filemon_unlock_read(); } return (ret); @@ -430,13 +370,7 @@ filemon_wrapper_link(struct thread *td, struct link_args *uap) struct filemon *filemon; if ((ret = sys_link(td, uap)) == 0) { - /* Grab a read lock on the filemon inuse list. */ - filemon_lock_read(); - if ((filemon = filemon_pid_check(curproc)) != NULL) { - /* Lock the found filemon structure. */ - filemon_filemon_lock(filemon); - copyinstr(uap->path, filemon->fname1, sizeof(filemon->fname1), &done); copyinstr(uap->link, filemon->fname2, @@ -451,9 +385,6 @@ filemon_wrapper_link(struct thread *td, struct link_args *uap) /* Unlock the found filemon structure. */ filemon_filemon_unlock(filemon); } - - /* Release the read lock. */ - filemon_unlock_read(); } return (ret); @@ -468,13 +399,7 @@ filemon_wrapper_symlink(struct thread *td, struct symlink_args *uap) struct filemon *filemon; if ((ret = sys_symlink(td, uap)) == 0) { - /* Grab a read lock on the filemon inuse list. */ - filemon_lock_read(); - if ((filemon = filemon_pid_check(curproc)) != NULL) { - /* Lock the found filemon structure. */ - filemon_filemon_lock(filemon); - copyinstr(uap->path, filemon->fname1, sizeof(filemon->fname1), &done); copyinstr(uap->link, filemon->fname2, @@ -489,9 +414,6 @@ filemon_wrapper_symlink(struct thread *td, struct symlink_args *uap) /* Unlock the found filemon structure. */ filemon_filemon_unlock(filemon); } - - /* Release the read lock. */ - filemon_unlock_read(); } return (ret); @@ -507,13 +429,7 @@ filemon_wrapper_linkat(struct thread *td, struct linkat_args *uap) struct filemon *filemon; if ((ret = sys_linkat(td, uap)) == 0) { - /* Grab a read lock on the filemon inuse list. */ - filemon_lock_read(); - if ((filemon = filemon_pid_check(curproc)) != NULL) { - /* Lock the found filemon structure. */ - filemon_filemon_lock(filemon); - copyinstr(uap->path1, filemon->fname1, sizeof(filemon->fname1), &done); copyinstr(uap->path2, filemon->fname2, @@ -528,9 +444,6 @@ filemon_wrapper_linkat(struct thread *td, struct linkat_args *uap) /* Unlock the found filemon structure. */ filemon_filemon_unlock(filemon); } - - /* Release the read lock. */ - filemon_unlock_read(); } return (ret); @@ -546,13 +459,7 @@ filemon_wrapper_stat(struct thread *td, struct stat_args *uap) struct filemon *filemon; if ((ret = sys_stat(td, uap)) == 0) { - /* Grab a read lock on the filemon inuse list. */ - filemon_lock_read(); - if ((filemon = filemon_pid_check(curproc)) != NULL) { - /* Lock the found filemon structure. */ - filemon_filemon_lock(filemon); - copyinstr(uap->path, filemon->fname1, sizeof(filemon->fname1), &done); @@ -565,9 +472,6 @@ filemon_wrapper_stat(struct thread *td, struct stat_args *uap) /* Unlock the found filemon structure. */ filemon_filemon_unlock(filemon); } - - /* Release the read lock. */ - filemon_unlock_read(); } return (ret); @@ -584,13 +488,7 @@ filemon_wrapper_freebsd32_stat(struct thread *td, struct filemon *filemon; if ((ret = freebsd32_stat(td, uap)) == 0) { - /* Grab a read lock on the filemon inuse list. */ - filemon_lock_read(); - if ((filemon = filemon_pid_check(curproc)) != NULL) { - /* Lock the found filemon structure. */ - filemon_filemon_lock(filemon); - copyinstr(uap->path, filemon->fname1, sizeof(filemon->fname1), &done); @@ -603,9 +501,6 @@ filemon_wrapper_freebsd32_stat(struct thread *td, /* Unlock the found filemon structure. */ filemon_filemon_unlock(filemon); } - - /* Release the read lock. */ - filemon_unlock_read(); } return (ret); @@ -622,13 +517,7 @@ filemon_wrapper_sys_exit(struct thread *td, struct sys_exit_args *uap) /* Get timestamp before locking. */ getmicrotime(&now); - /* Grab a read lock on the filemon inuse list. */ - filemon_lock_read(); - if ((filemon = filemon_pid_check(curproc)) != NULL) { - /* Lock the found filemon structure. */ - filemon_filemon_lock(filemon); - len = snprintf(filemon->msgbufr, sizeof(filemon->msgbufr), "X %d %d\n", curproc->p_pid, uap->rval); @@ -649,9 +538,6 @@ filemon_wrapper_sys_exit(struct thread *td, struct sys_exit_args *uap) filemon_filemon_unlock(filemon); } - /* Release the read lock. */ - filemon_unlock_read(); - sys_sys_exit(td, uap); } @@ -664,13 +550,7 @@ filemon_wrapper_unlink(struct thread *td, struct unlink_args *uap) struct filemon *filemon; if ((ret = sys_unlink(td, uap)) == 0) { - /* Grab a read lock on the filemon inuse list. */ - filemon_lock_read(); - if ((filemon = filemon_pid_check(curproc)) != NULL) { - /* Lock the found filemon structure. */ - filemon_filemon_lock(filemon); - copyinstr(uap->path, filemon->fname1, sizeof(filemon->fname1), &done); @@ -683,9 +563,6 @@ filemon_wrapper_unlink(struct thread *td, struct unlink_args *uap) /* Unlock the found filemon structure. */ filemon_filemon_unlock(filemon); } - - /* Release the read lock. */ - filemon_unlock_read(); } return (ret); @@ -699,13 +576,7 @@ filemon_wrapper_vfork(struct thread *td, struct vfork_args *uap) struct filemon *filemon; if ((ret = sys_vfork(td, uap)) == 0) { - /* Grab a read lock on the filemon inuse list. */ - filemon_lock_read(); - if ((filemon = filemon_pid_check(curproc)) != NULL) { - /* Lock the found filemon structure. */ - filemon_filemon_lock(filemon); - len = snprintf(filemon->msgbufr, sizeof(filemon->msgbufr), "F %d %ld\n", curproc->p_pid, (long)curthread->td_retval[0]); @@ -715,9 +586,6 @@ filemon_wrapper_vfork(struct thread *td, struct vfork_args *uap) /* Unlock the found filemon structure. */ filemon_filemon_unlock(filemon); } - - /* Release the read lock. */ - filemon_unlock_read(); } return (ret); diff --git a/sys/dev/ipmi/ipmi.c b/sys/dev/ipmi/ipmi.c index a1edbf6..8101717 100644 --- a/sys/dev/ipmi/ipmi.c +++ b/sys/dev/ipmi/ipmi.c @@ -756,17 +756,22 @@ ipmi_startup(void *arg) } device_printf(dev, "Number of channels %d\n", i); - /* probe for watchdog */ - IPMI_INIT_DRIVER_REQUEST(req, IPMI_ADDR(IPMI_APP_REQUEST, 0), - IPMI_GET_WDOG, 0, 0); + /* + * Probe for watchdog, but only for backends which support + * polled driver requests. + */ + if (sc->ipmi_driver_requests_polled) { + IPMI_INIT_DRIVER_REQUEST(req, IPMI_ADDR(IPMI_APP_REQUEST, 0), + IPMI_GET_WDOG, 0, 0); - ipmi_submit_driver_request(sc, req, 0); + ipmi_submit_driver_request(sc, req, 0); - if (req->ir_compcode == 0x00) { - device_printf(dev, "Attached watchdog\n"); - /* register the watchdog event handler */ - sc->ipmi_watchdog_tag = EVENTHANDLER_REGISTER(watchdog_list, - ipmi_wd_event, sc, 0); + if (req->ir_compcode == 0x00) { + device_printf(dev, "Attached watchdog\n"); + /* register the watchdog event handler */ + sc->ipmi_watchdog_tag = EVENTHANDLER_REGISTER( + watchdog_list, ipmi_wd_event, sc, 0); + } } sc->ipmi_cdev = make_dev(&ipmi_cdevsw, device_get_unit(dev), diff --git a/sys/dev/ipmi/ipmi_kcs.c b/sys/dev/ipmi/ipmi_kcs.c index 1c58646..864e9a0 100644 --- a/sys/dev/ipmi/ipmi_kcs.c +++ b/sys/dev/ipmi/ipmi_kcs.c @@ -520,6 +520,7 @@ ipmi_kcs_attach(struct ipmi_softc *sc) sc->ipmi_startup = kcs_startup; sc->ipmi_enqueue_request = ipmi_polled_enqueue_request; sc->ipmi_driver_request = kcs_driver_request; + sc->ipmi_driver_requests_polled = 1; /* See if we can talk to the controller. */ status = INB(sc, KCS_CTL_STS); diff --git a/sys/dev/ipmi/ipmi_smic.c b/sys/dev/ipmi/ipmi_smic.c index 4e26553..92cf14e 100644 --- a/sys/dev/ipmi/ipmi_smic.c +++ b/sys/dev/ipmi/ipmi_smic.c @@ -415,6 +415,7 @@ ipmi_smic_attach(struct ipmi_softc *sc) sc->ipmi_startup = smic_startup; sc->ipmi_enqueue_request = ipmi_polled_enqueue_request; sc->ipmi_driver_request = smic_driver_request; + sc->ipmi_driver_requests_polled = 1; /* See if we can talk to the controller. */ flags = INB(sc, SMIC_FLAGS); diff --git a/sys/dev/ipmi/ipmivars.h b/sys/dev/ipmi/ipmivars.h index 9d7dc32..9a0b435 100644 --- a/sys/dev/ipmi/ipmivars.h +++ b/sys/dev/ipmi/ipmivars.h @@ -105,6 +105,7 @@ struct ipmi_softc { int ipmi_opened; struct cdev *ipmi_cdev; TAILQ_HEAD(,ipmi_request) ipmi_pending_requests; + int ipmi_driver_requests_polled; eventhandler_tag ipmi_watchdog_tag; int ipmi_watchdog_active; struct intr_config_hook ipmi_ich; diff --git a/sys/dev/isci/isci.c b/sys/dev/isci/isci.c index 2f0727d..5a1066c 100644 --- a/sys/dev/isci/isci.c +++ b/sys/dev/isci/isci.c @@ -163,6 +163,7 @@ isci_attach(device_t device) g_isci = isci; isci->device = device; + pci_enable_busmaster(device); isci_allocate_pci_memory(isci); @@ -272,6 +273,7 @@ isci_detach(device_t device) pci_release_msi(device); } + pci_disable_busmaster(device); return (0); } diff --git a/sys/dev/isci/isci_interrupt.c b/sys/dev/isci/isci_interrupt.c index 52c64f7..b56fd3a 100644 --- a/sys/dev/isci/isci_interrupt.c +++ b/sys/dev/isci/isci_interrupt.c @@ -136,8 +136,8 @@ isci_interrupt_setup(struct isci_softc *isci) pci_msix_count(isci->device) >= max_msix_messages) { isci->num_interrupts = max_msix_messages; - pci_alloc_msix(isci->device, &isci->num_interrupts); - if (isci->num_interrupts == max_msix_messages) + if (pci_alloc_msix(isci->device, &isci->num_interrupts) == 0 && + isci->num_interrupts == max_msix_messages) use_msix = TRUE; } diff --git a/sys/dev/ixgbe/if_ix.c b/sys/dev/ixgbe/if_ix.c index 78f25f0..a2e71e1 100644 --- a/sys/dev/ixgbe/if_ix.c +++ b/sys/dev/ixgbe/if_ix.c @@ -768,9 +768,9 @@ ixgbe_ioctl(struct ifnet * ifp, u_long command, caddr_t data) struct ifreq *ifr = (struct ifreq *) data; #if defined(INET) || defined(INET6) struct ifaddr *ifa = (struct ifaddr *)data; - bool avoid_reset = FALSE; #endif int error = 0; + bool avoid_reset = FALSE; switch (command) { @@ -783,7 +783,6 @@ ixgbe_ioctl(struct ifnet * ifp, u_long command, caddr_t data) if (ifa->ifa_addr->sa_family == AF_INET6) avoid_reset = TRUE; #endif -#if defined(INET) || defined(INET6) /* ** Calling init results in link renegotiation, ** so we avoid doing it when possible. @@ -792,11 +791,12 @@ ixgbe_ioctl(struct ifnet * ifp, u_long command, caddr_t data) ifp->if_flags |= IFF_UP; if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) ixgbe_init(adapter); +#if defined(INET) if (!(ifp->if_flags & IFF_NOARP)) arp_ifinit(ifp, ifa); +#endif } else error = ether_ioctl(ifp, command, data); -#endif break; case SIOCSIFMTU: IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)"); diff --git a/sys/dev/md/md.c b/sys/dev/md/md.c index b1d579f..a2c7a78 100644 --- a/sys/dev/md/md.c +++ b/sys/dev/md/md.c @@ -89,6 +89,7 @@ #include <sys/vnode.h> #include <geom/geom.h> +#include <geom/geom_int.h> #include <vm/vm.h> #include <vm/vm_param.h> @@ -1621,9 +1622,11 @@ g_md_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, "read-only"); sbuf_printf(sb, "%s<type>%s</type>\n", indent, type); - if (mp->type == MD_VNODE && mp->vnode != NULL) - sbuf_printf(sb, "%s<file>%s</file>\n", - indent, mp->file); + if (mp->type == MD_VNODE && mp->vnode != NULL) { + sbuf_printf(sb, "%s<file>", indent); + g_conf_printf_escaped(sb, "%s", mp->file); + sbuf_printf(sb, "</file>\n"); + } } } } diff --git a/sys/dev/nvme/nvme.c b/sys/dev/nvme/nvme.c index 329c5e5..cc14d34 100644 --- a/sys/dev/nvme/nvme.c +++ b/sys/dev/nvme/nvme.c @@ -390,6 +390,15 @@ nvme_notify_fail_consumers(struct nvme_controller *ctrlr) struct nvme_consumer *cons; uint32_t i; + /* + * This controller failed during initialization (i.e. IDENTIFY + * command failed or timed out). Do not notify any nvme + * consumers of the failure here, since the consumer does not + * even know about the controller yet. + */ + if (!ctrlr->is_initialized) + return; + for (i = 0; i < NVME_MAX_CONSUMERS; i++) { cons = &nvme_consumer[i]; if (cons->id != INVALID_CONSUMER_ID && cons->fail_fn != NULL) diff --git a/sys/dev/sound/midi/midi.c b/sys/dev/sound/midi/midi.c index 5537d62..f95218b 100644 --- a/sys/dev/sound/midi/midi.c +++ b/sys/dev/sound/midi/midi.c @@ -403,7 +403,7 @@ midi_uninit(struct snd_midi *m) { int err; - err = ENXIO; + err = EBUSY; mtx_lock(&midistat_lock); mtx_lock(&m->lock); if (m->busy) { diff --git a/sys/dev/usb/controller/dwc_otg.c b/sys/dev/usb/controller/dwc_otg.c index 4f4abf2..744321b 100644 --- a/sys/dev/usb/controller/dwc_otg.c +++ b/sys/dev/usb/controller/dwc_otg.c @@ -1,6 +1,7 @@ /* $FreeBSD$ */ /*- - * Copyright (c) 2012 Hans Petter Selasky. All rights reserved. + * Copyright (c) 2015 Daisuke Aoyama. All rights reserved. + * Copyright (c) 2012-2015 Hans Petter Selasky. All rights reserved. * Copyright (c) 2010-2011 Aleksandr Rybalko. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -152,7 +153,6 @@ static void dwc_otg_do_poll(struct usb_bus *); static void dwc_otg_standard_done(struct usb_xfer *); static void dwc_otg_root_intr(struct dwc_otg_softc *); static void dwc_otg_interrupt_poll_locked(struct dwc_otg_softc *); -static void dwc_otg_host_channel_disable(struct dwc_otg_softc *, uint8_t); /* * Here is a configuration that the chip supports. @@ -225,7 +225,7 @@ dwc_otg_init_fifo(struct dwc_otg_softc *sc, uint8_t mode) /* split equally for IN and OUT */ fifo_size /= 2; - /* align to 4 bytes boundary */ + /* Align to 4 bytes boundary (refer to PGM) */ fifo_size &= ~3; /* set global receive FIFO size */ @@ -238,13 +238,6 @@ dwc_otg_init_fifo(struct dwc_otg_softc *sc, uint8_t mode) return (EINVAL); } - /* disable any leftover host channels */ - for (x = 0; x != sc->sc_host_ch_max; x++) { - if (sc->sc_chan_state[x].wait_sof == 0) - continue; - dwc_otg_host_channel_disable(sc, x); - } - if (mode == DWC_MODE_HOST) { /* reset active endpoints */ @@ -253,6 +246,8 @@ dwc_otg_init_fifo(struct dwc_otg_softc *sc, uint8_t mode) /* split equally for periodic and non-periodic */ fifo_size /= 2; + DPRINTF("PTX/NPTX FIFO=%u\n", fifo_size); + /* align to 4 bytes boundary */ fifo_size &= ~3; @@ -263,7 +258,7 @@ dwc_otg_init_fifo(struct dwc_otg_softc *sc, uint8_t mode) tx_start += fifo_size; for (x = 0; x != sc->sc_host_ch_max; x++) { - /* disable all host interrupts */ + /* enable all host interrupts */ DWC_OTG_WRITE_4(sc, DOTG_HCINTMSK(x), HCINT_DEFAULT_MASK); } @@ -275,13 +270,6 @@ dwc_otg_init_fifo(struct dwc_otg_softc *sc, uint8_t mode) /* reset host channel state */ memset(sc->sc_chan_state, 0, sizeof(sc->sc_chan_state)); - /* reset FIFO TX levels */ - sc->sc_tx_cur_p_level = 0; - sc->sc_tx_cur_np_level = 0; - - /* store maximum periodic and non-periodic FIFO TX size */ - sc->sc_tx_max_size = fifo_size; - /* enable all host channel interrupts */ DWC_OTG_WRITE_4(sc, DOTG_HAINTMSK, (1U << sc->sc_host_ch_max) - 1U); @@ -314,32 +302,29 @@ dwc_otg_init_fifo(struct dwc_otg_softc *sc, uint8_t mode) if (x < sc->sc_dev_in_ep_max) { uint32_t limit; - limit = (x == 1) ? DWC_OTG_MAX_TXN : - (DWC_OTG_MAX_TXN / 2); + limit = (x == 1) ? MIN(DWC_OTG_TX_MAX_FIFO_SIZE, + DWC_OTG_MAX_TXN) : MIN(DWC_OTG_MAX_TXN / 2, + DWC_OTG_TX_MAX_FIFO_SIZE); - if (fifo_size >= limit) { - DWC_OTG_WRITE_4(sc, DOTG_DIEPTXF(x), - ((limit / 4) << 16) | - (tx_start / 4)); - tx_start += limit; - fifo_size -= limit; - pf->usb.max_in_frame_size = 0x200; - pf->usb.support_in = 1; + /* see if there is enough FIFO space */ + if (limit <= fifo_size) { pf->max_buffer = limit; - - } else if (fifo_size >= 0x80) { - DWC_OTG_WRITE_4(sc, DOTG_DIEPTXF(x), - ((0x80 / 4) << 16) | (tx_start / 4)); - tx_start += 0x80; - fifo_size -= 0x80; - pf->usb.max_in_frame_size = 0x40; pf->usb.support_in = 1; - } else { - pf->usb.is_simplex = 1; - DWC_OTG_WRITE_4(sc, DOTG_DIEPTXF(x), - (0x0 << 16) | (tx_start / 4)); + limit = MIN(DWC_OTG_TX_MAX_FIFO_SIZE, 0x40); + if (limit <= fifo_size) { + pf->usb.support_in = 1; + } else { + pf->usb.is_simplex = 1; + limit = 0; + } } + /* set FIFO size */ + DWC_OTG_WRITE_4(sc, DOTG_DIEPTXF(x), + ((limit / 4) << 16) | (tx_start / 4)); + tx_start += limit; + fifo_size -= limit; + pf->usb.max_in_frame_size = limit; } else { pf->usb.is_simplex = 1; } @@ -362,15 +347,8 @@ dwc_otg_init_fifo(struct dwc_otg_softc *sc, uint8_t mode) /* reset active endpoints */ sc->sc_active_rx_ep = 0; - /* reset periodic and non-periodic FIFO TX size */ - sc->sc_tx_max_size = fifo_size; - /* reset host channel state */ memset(sc->sc_chan_state, 0, sizeof(sc->sc_chan_state)); - - /* reset FIFO TX levels */ - sc->sc_tx_cur_p_level = 0; - sc->sc_tx_cur_np_level = 0; } return (0); } @@ -476,8 +454,12 @@ static void dwc_otg_enable_sof_irq(struct dwc_otg_softc *sc) { /* In device mode we don't use the SOF interrupt */ - if (sc->sc_flags.status_device_mode != 0 || - (sc->sc_irq_mask & GINTMSK_SOFMSK) != 0) + if (sc->sc_flags.status_device_mode != 0) + return; + /* Ensure the SOF interrupt is not disabled */ + sc->sc_needsof = 1; + /* Check if the SOF interrupt is already enabled */ + if ((sc->sc_irq_mask & GINTMSK_SOFMSK) != 0) return; sc->sc_irq_mask |= GINTMSK_SOFMSK; DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask); @@ -616,13 +598,48 @@ dwc_otg_clear_hcint(struct dwc_otg_softc *sc, uint8_t x) } static uint8_t -dwc_otg_host_channel_alloc(struct dwc_otg_softc *sc, struct dwc_otg_td *td, uint8_t is_out) +dwc_otg_host_check_tx_fifo_empty(struct dwc_otg_softc *sc, struct dwc_otg_td *td) +{ + uint32_t temp; + + temp = DWC_OTG_READ_4(sc, DOTG_GINTSTS); + + if (td->ep_type == UE_ISOCHRONOUS) { + /* + * NOTE: USB INTERRUPT transactions are executed like + * USB CONTROL transactions! See the setup standard + * chain function for more information. + */ + if (!(temp & GINTSTS_PTXFEMP)) { + DPRINTF("Periodic TX FIFO is not empty\n"); + if (!(sc->sc_irq_mask & GINTMSK_PTXFEMPMSK)) { + sc->sc_irq_mask |= GINTMSK_PTXFEMPMSK; + DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask); + } + return (1); /* busy */ + } + } else { + if (!(temp & GINTSTS_NPTXFEMP)) { + DPRINTF("Non-periodic TX FIFO is not empty\n"); + if (!(sc->sc_irq_mask & GINTMSK_NPTXFEMPMSK)) { + sc->sc_irq_mask |= GINTMSK_NPTXFEMPMSK; + DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask); + } + return (1); /* busy */ + } + } + return (0); /* ready for transmit */ +} + +static uint8_t +dwc_otg_host_channel_alloc(struct dwc_otg_softc *sc, + struct dwc_otg_td *td, uint8_t is_out) { - uint32_t tx_p_size; - uint32_t tx_np_size; uint8_t x; + uint8_t y; + uint8_t z; - if (td->channel < DWC_OTG_MAX_CHANNELS) + if (td->channel[0] < DWC_OTG_MAX_CHANNELS) return (0); /* already allocated */ /* check if device is suspended */ @@ -631,45 +648,41 @@ dwc_otg_host_channel_alloc(struct dwc_otg_softc *sc, struct dwc_otg_td *td, uint /* compute needed TX FIFO size */ if (is_out != 0) { - if (td->ep_type == UE_ISOCHRONOUS) { - tx_p_size = td->max_packet_size; - tx_np_size = 0; - if (td->hcsplt != 0 && tx_p_size > HCSPLT_XACTLEN_BURST) - tx_p_size = HCSPLT_XACTLEN_BURST; - if ((sc->sc_tx_cur_p_level + tx_p_size) > sc->sc_tx_max_size) { - DPRINTF("Too little FIFO space\n"); - return (1); /* too little FIFO */ - } - } else { - tx_p_size = 0; - tx_np_size = td->max_packet_size; - if (td->hcsplt != 0 && tx_np_size > HCSPLT_XACTLEN_BURST) - tx_np_size = HCSPLT_XACTLEN_BURST; - if ((sc->sc_tx_cur_np_level + tx_np_size) > sc->sc_tx_max_size) { - DPRINTF("Too little FIFO space\n"); - return (1); /* too little FIFO */ - } - } - } else { - /* not a TX transaction */ - tx_p_size = 0; - tx_np_size = 0; + if (dwc_otg_host_check_tx_fifo_empty(sc, td) != 0) + return (1); /* busy - cannot transfer data */ } - - for (x = 0; x != sc->sc_host_ch_max; x++) { + z = td->max_packet_count; + for (x = y = 0; x != sc->sc_host_ch_max; x++) { + /* check if channel is allocated */ if (sc->sc_chan_state[x].allocated != 0) continue; /* check if channel is still enabled */ - if (sc->sc_chan_state[x].wait_sof != 0) + if (sc->sc_chan_state[x].wait_halted != 0) continue; + /* store channel number */ + td->channel[y++] = x; + /* check if we got all channels */ + if (y == z) + break; + } + if (y != z) { + /* reset channel variable */ + td->channel[0] = DWC_OTG_MAX_CHANNELS; + td->channel[1] = DWC_OTG_MAX_CHANNELS; + td->channel[2] = DWC_OTG_MAX_CHANNELS; + /* wait a bit */ + dwc_otg_enable_sof_irq(sc); + return (1); /* busy - not enough channels */ + } + + for (y = 0; y != z; y++) { + x = td->channel[y]; + /* set allocated */ sc->sc_chan_state[x].allocated = 1; - sc->sc_chan_state[x].tx_p_size = tx_p_size; - sc->sc_chan_state[x].tx_np_size = tx_np_size; - /* keep track of used TX FIFO, if any */ - sc->sc_tx_cur_p_level += tx_p_size; - sc->sc_tx_cur_np_level += tx_np_size; + /* set wait halted */ + sc->sc_chan_state[x].wait_halted = 1; /* clear interrupts */ dwc_otg_clear_hcint(sc, x); @@ -679,45 +692,29 @@ dwc_otg_host_channel_alloc(struct dwc_otg_softc *sc, struct dwc_otg_td *td, uint /* set active channel */ sc->sc_active_rx_ep |= (1 << x); - - /* set channel */ - td->channel = x; - - return (0); /* allocated */ } - /* wait a bit */ - dwc_otg_enable_sof_irq(sc); - return (1); /* busy */ + return (0); /* allocated */ } static void -dwc_otg_host_channel_free(struct dwc_otg_softc *sc, struct dwc_otg_td *td) +dwc_otg_host_channel_free_sub(struct dwc_otg_softc *sc, struct dwc_otg_td *td, uint8_t index) { + uint32_t hcchar; uint8_t x; - if (td->channel >= DWC_OTG_MAX_CHANNELS) + if (td->channel[index] >= DWC_OTG_MAX_CHANNELS) return; /* already freed */ /* free channel */ - x = td->channel; - td->channel = DWC_OTG_MAX_CHANNELS; + x = td->channel[index]; + td->channel[index] = DWC_OTG_MAX_CHANNELS; DPRINTF("CH=%d\n", x); /* * We need to let programmed host channels run till complete - * else the host channel will stop functioning. Assume that - * after a fixed given amount of time the host channel is no - * longer doing any USB traffic: + * else the host channel will stop functioning. */ - if (td->ep_type == UE_ISOCHRONOUS) { - /* double buffered */ - sc->sc_chan_state[x].wait_sof = DWC_OTG_SLOT_IDLE_MAX; - } else { - /* single buffered */ - sc->sc_chan_state[x].wait_sof = DWC_OTG_SLOT_IDLE_MIN; - } - sc->sc_chan_state[x].allocated = 0; /* ack any pending messages */ @@ -728,17 +725,43 @@ dwc_otg_host_channel_free(struct dwc_otg_softc *sc, struct dwc_otg_td *td) /* clear active channel */ sc->sc_active_rx_ep &= ~(1 << x); + + /* check if already halted */ + if (sc->sc_chan_state[x].wait_halted == 0) + return; + + /* disable host channel */ + hcchar = DWC_OTG_READ_4(sc, DOTG_HCCHAR(x)); + if (hcchar & HCCHAR_CHENA) { + DPRINTF("Halting channel %d\n", x); + DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(x), + hcchar | HCCHAR_CHDIS); + /* don't write HCCHAR until the channel is halted */ + } else { + sc->sc_chan_state[x].wait_halted = 0; + } +} + +static void +dwc_otg_host_channel_free(struct dwc_otg_softc *sc, struct dwc_otg_td *td) +{ + uint8_t x; + for (x = 0; x != td->max_packet_count; x++) + dwc_otg_host_channel_free_sub(sc, td, x); } static void dwc_otg_host_dump_rx(struct dwc_otg_softc *sc, struct dwc_otg_td *td) { + uint8_t x; /* dump any pending messages */ - if (sc->sc_last_rx_status != 0) { - if (td->channel < DWC_OTG_MAX_CHANNELS && - td->channel == GRXSTSRD_CHNUM_GET(sc->sc_last_rx_status)) { - dwc_otg_common_rx_ack(sc); - } + if (sc->sc_last_rx_status == 0) + return; + for (x = 0; x != td->max_packet_count; x++) { + if (td->channel[x] >= DWC_OTG_MAX_CHANNELS || + td->channel[x] != GRXSTSRD_CHNUM_GET(sc->sc_last_rx_status)) + continue; + dwc_otg_common_rx_ack(sc); } } @@ -752,13 +775,13 @@ dwc_otg_host_setup_tx(struct dwc_otg_softc *sc, struct dwc_otg_td *td) dwc_otg_host_dump_rx(sc, td); - if (td->channel < DWC_OTG_MAX_CHANNELS) { - hcint = sc->sc_chan_state[td->channel].hcint; + if (td->channel[0] < DWC_OTG_MAX_CHANNELS) { + hcint = sc->sc_chan_state[td->channel[0]].hcint; DPRINTF("CH=%d ST=%d HCINT=0x%08x HCCHAR=0x%08x HCTSIZ=0x%08x\n", - td->channel, td->state, hcint, - DWC_OTG_READ_4(sc, DOTG_HCCHAR(td->channel)), - DWC_OTG_READ_4(sc, DOTG_HCTSIZ(td->channel))); + td->channel[0], td->state, hcint, + DWC_OTG_READ_4(sc, DOTG_HCCHAR(td->channel[0])), + DWC_OTG_READ_4(sc, DOTG_HCTSIZ(td->channel[0]))); } else { hcint = 0; goto check_state; @@ -768,12 +791,12 @@ dwc_otg_host_setup_tx(struct dwc_otg_softc *sc, struct dwc_otg_td *td) HCINT_ACK | HCINT_NYET)) { /* give success bits priority over failure bits */ } else if (hcint & HCINT_STALL) { - DPRINTF("CH=%d STALL\n", td->channel); + DPRINTF("CH=%d STALL\n", td->channel[0]); td->error_stall = 1; td->error_any = 1; goto complete; } else if (hcint & HCINT_ERRORS) { - DPRINTF("CH=%d ERROR\n", td->channel); + DPRINTF("CH=%d ERROR\n", td->channel[0]); td->errcnt++; if (td->hcsplt != 0 || td->errcnt >= 3) { td->error_any = 1; @@ -794,7 +817,7 @@ check_state: case DWC_CHAN_ST_WAIT_ANE: if (hcint & (HCINT_RETRY | HCINT_ERRORS)) { - td->did_nak++; + td->did_nak = 1; td->tt_scheduled = 0; goto send_pkt; } else if (hcint & (HCINT_ACK | HCINT_NYET)) { @@ -808,7 +831,7 @@ check_state: case DWC_CHAN_ST_WAIT_S_ANE: if (hcint & (HCINT_RETRY | HCINT_ERRORS)) { - td->did_nak++; + td->did_nak = 1; td->tt_scheduled = 0; goto send_pkt; } else if (hcint & (HCINT_ACK | HCINT_NYET)) { @@ -820,7 +843,7 @@ check_state: if (hcint & HCINT_NYET) { goto send_cpkt; } else if (hcint & (HCINT_RETRY | HCINT_ERRORS)) { - td->did_nak++; + td->did_nak = 1; td->tt_scheduled = 0; goto send_pkt; } else if (hcint & HCINT_ACK) { @@ -878,23 +901,23 @@ send_pkt: usbd_copy_out(td->pc, 0, &req, sizeof(req)); - DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(td->channel), + DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(td->channel[0]), (sizeof(req) << HCTSIZ_XFERSIZE_SHIFT) | (1 << HCTSIZ_PKTCNT_SHIFT) | (HCTSIZ_PID_SETUP << HCTSIZ_PID_SHIFT)); - DWC_OTG_WRITE_4(sc, DOTG_HCSPLT(td->channel), td->hcsplt); + DWC_OTG_WRITE_4(sc, DOTG_HCSPLT(td->channel[0]), td->hcsplt); hcchar = td->hcchar; hcchar &= ~(HCCHAR_EPDIR_IN | HCCHAR_EPTYPE_MASK); hcchar |= UE_CONTROL << HCCHAR_EPTYPE_SHIFT; /* must enable channel before writing data to FIFO */ - DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(td->channel), hcchar); + DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(td->channel[0]), hcchar); /* transfer data into FIFO */ bus_space_write_region_4(sc->sc_io_tag, sc->sc_io_hdl, - DOTG_DFIFO(td->channel), (uint32_t *)&req, sizeof(req) / 4); + DOTG_DFIFO(td->channel[0]), (uint32_t *)&req, sizeof(req) / 4); /* wait until next slot before trying complete split */ td->tt_complete_slot = sc->sc_last_frame_num + 1; @@ -931,17 +954,17 @@ send_cpkt: td->hcsplt |= HCSPLT_COMPSPLT; td->state = DWC_CHAN_ST_WAIT_C_ANE; - DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(td->channel), + DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(td->channel[0]), (HCTSIZ_PID_SETUP << HCTSIZ_PID_SHIFT)); - DWC_OTG_WRITE_4(sc, DOTG_HCSPLT(td->channel), td->hcsplt); + DWC_OTG_WRITE_4(sc, DOTG_HCSPLT(td->channel[0]), td->hcsplt); hcchar = td->hcchar; hcchar &= ~(HCCHAR_EPDIR_IN | HCCHAR_EPTYPE_MASK); hcchar |= UE_CONTROL << HCCHAR_EPTYPE_SHIFT; /* must enable channel before writing data to FIFO */ - DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(td->channel), hcchar); + DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(td->channel[0]), hcchar); busy: return (1); /* busy */ @@ -1075,41 +1098,51 @@ dwc_otg_host_rate_check_interrupt(struct dwc_otg_softc *sc, struct dwc_otg_td *t static uint8_t dwc_otg_host_rate_check(struct dwc_otg_softc *sc, struct dwc_otg_td *td) { + uint8_t frame_num = (uint8_t)sc->sc_last_frame_num; + if (td->ep_type == UE_ISOCHRONOUS) { /* non TT isochronous traffic */ - if ((td->tmr_val != 0) || - (sc->sc_last_frame_num & (td->tmr_res - 1))) { + if (frame_num & (td->tmr_res - 1)) goto busy; - } - td->tmr_val = 1; /* executed */ + if ((frame_num ^ td->tmr_val) & td->tmr_res) + goto busy; + td->tmr_val = td->tmr_res + sc->sc_last_frame_num; td->toggle = 0; - + return (0); } else if (td->ep_type == UE_INTERRUPT) { if (!td->tt_scheduled) goto busy; td->tt_scheduled = 0; - } else if (td->did_nak >= DWC_OTG_NAK_MAX) { - goto busy; + return (0); + } else if (td->did_nak != 0) { + /* check if we should pause sending queries for 125us */ + if (td->tmr_res == frame_num) { + /* wait a bit */ + dwc_otg_enable_sof_irq(sc); + goto busy; + } } else if (td->set_toggle) { td->set_toggle = 0; td->toggle = 1; } + /* query for data one more time */ + td->tmr_res = frame_num; + td->did_nak = 0; return (0); busy: return (1); } static uint8_t -dwc_otg_host_data_rx_sub(struct dwc_otg_softc *sc, struct dwc_otg_td *td) +dwc_otg_host_data_rx_sub(struct dwc_otg_softc *sc, struct dwc_otg_td *td, + uint8_t channel) { uint32_t count; - uint8_t channel; /* check endpoint status */ if (sc->sc_last_rx_status == 0) goto busy; - channel = td->channel; if (channel >= DWC_OTG_MAX_CHANNELS) goto busy; @@ -1134,21 +1167,22 @@ dwc_otg_host_data_rx_sub(struct dwc_otg_softc *sc, struct dwc_otg_td *td) /* get the packet byte count */ count = GRXSTSRD_BCNT_GET(sc->sc_last_rx_status); - /* check for isochronous transfer or high-speed bandwidth endpoint */ - if (td->ep_type == UE_ISOCHRONOUS || td->max_packet_count > 1) { - if ((sc->sc_last_rx_status & GRXSTSRD_DPID_MASK) != GRXSTSRD_DPID_DATA0) { + /* check for ISOCHRONOUS endpoint */ + if (td->ep_type == UE_ISOCHRONOUS) { + if ((sc->sc_last_rx_status & GRXSTSRD_DPID_MASK) != + GRXSTSRD_DPID_DATA0) { + /* more data to be received */ td->tt_xactpos = HCSPLT_XACTPOS_MIDDLE; } else { + /* all data received */ td->tt_xactpos = HCSPLT_XACTPOS_BEGIN; - /* verify the packet byte count */ - if (count < td->max_packet_size) { + if (count != td->remainder) { /* we have a short packet */ td->short_pkt = 1; td->got_short = 1; } } - td->toggle = 0; } else { /* verify the packet byte count */ if (count != td->max_packet_size) { @@ -1200,15 +1234,17 @@ complete: static uint8_t dwc_otg_host_data_rx(struct dwc_otg_softc *sc, struct dwc_otg_td *td) { - uint32_t hcint; + uint32_t hcint = 0; uint32_t hcchar; uint8_t delta; uint8_t channel; + uint8_t x; - channel = td->channel; - - if (channel < DWC_OTG_MAX_CHANNELS) { - hcint = sc->sc_chan_state[channel].hcint; + for (x = 0; x != td->max_packet_count; x++) { + channel = td->channel[x]; + if (channel >= DWC_OTG_MAX_CHANNELS) + continue; + hcint |= sc->sc_chan_state[channel].hcint; DPRINTF("CH=%d ST=%d HCINT=0x%08x HCCHAR=0x%08x HCTSIZ=0x%08x\n", channel, td->state, hcint, @@ -1236,19 +1272,17 @@ dwc_otg_host_data_rx(struct dwc_otg_softc *sc, struct dwc_otg_td *td) } /* check channels for data, if any */ - if (dwc_otg_host_data_rx_sub(sc, td)) + if (dwc_otg_host_data_rx_sub(sc, td, channel)) goto complete; /* refresh interrupt status */ - hcint = sc->sc_chan_state[channel].hcint; + hcint |= sc->sc_chan_state[channel].hcint; if (hcint & (HCINT_ERRORS | HCINT_RETRY | HCINT_ACK | HCINT_NYET)) { if (!(hcint & HCINT_ERRORS)) td->errcnt = 0; } - } else { - hcint = 0; } switch (td->state) { @@ -1275,8 +1309,10 @@ dwc_otg_host_data_rx(struct dwc_otg_softc *sc, struct dwc_otg_td *td) td->toggle ^= 1; goto receive_pkt; } + } else if (td->ep_type == UE_ISOCHRONOUS) { + goto complete; } - td->did_nak++; + td->did_nak = 1; td->tt_scheduled = 0; if (td->hcsplt != 0) goto receive_spkt; @@ -1298,12 +1334,12 @@ dwc_otg_host_data_rx(struct dwc_otg_softc *sc, struct dwc_otg_td *td) if (td->ep_type == UE_ISOCHRONOUS) { /* check if we are complete */ - if ((td->remainder == 0) || - (td->tt_xactpos == HCSPLT_XACTPOS_BEGIN)) { + if (td->tt_xactpos == HCSPLT_XACTPOS_BEGIN) { goto complete; + } else { + /* get more packets */ + goto busy; } - /* get another packet */ - goto receive_pkt; } else { /* check if we are complete */ if ((td->remainder == 0) || (td->got_short != 0)) { @@ -1331,7 +1367,7 @@ dwc_otg_host_data_rx(struct dwc_otg_softc *sc, struct dwc_otg_td *td) * case of interrupt and isochronous transfers: */ if (hcint & (HCINT_RETRY | HCINT_ERRORS)) { - td->did_nak++; + td->did_nak = 1; td->tt_scheduled = 0; goto receive_spkt; } else if (hcint & HCINT_NYET) { @@ -1371,8 +1407,7 @@ receive_pkt: } /* complete split */ td->hcsplt |= HCSPLT_COMPSPLT; - } else if (td->tt_xactpos == HCSPLT_XACTPOS_BEGIN && - dwc_otg_host_rate_check(sc, td)) { + } else if (dwc_otg_host_rate_check(sc, td)) { td->state = DWC_CHAN_ST_WAIT_C_PKT; goto busy; } @@ -1383,8 +1418,6 @@ receive_pkt: goto busy; } - channel = td->channel; - /* set toggle, if any */ if (td->set_toggle) { td->set_toggle = 0; @@ -1393,27 +1426,31 @@ receive_pkt: td->state = DWC_CHAN_ST_WAIT_ANE; - /* receive one packet */ - DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(channel), - (td->max_packet_size << HCTSIZ_XFERSIZE_SHIFT) | - (1 << HCTSIZ_PKTCNT_SHIFT) | - (td->toggle ? (HCTSIZ_PID_DATA1 << HCTSIZ_PID_SHIFT) : - (HCTSIZ_PID_DATA0 << HCTSIZ_PID_SHIFT))); + for (x = 0; x != td->max_packet_count; x++) { + channel = td->channel[x]; - DWC_OTG_WRITE_4(sc, DOTG_HCSPLT(channel), td->hcsplt); + /* receive one packet */ + DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(channel), + (td->max_packet_size << HCTSIZ_XFERSIZE_SHIFT) | + (1 << HCTSIZ_PKTCNT_SHIFT) | + (td->toggle ? (HCTSIZ_PID_DATA1 << HCTSIZ_PID_SHIFT) : + (HCTSIZ_PID_DATA0 << HCTSIZ_PID_SHIFT))); - hcchar = td->hcchar; - hcchar |= HCCHAR_EPDIR_IN; + DWC_OTG_WRITE_4(sc, DOTG_HCSPLT(channel), td->hcsplt); - /* receive complete split ASAP */ - if ((sc->sc_last_frame_num & 1) != 0) - hcchar |= HCCHAR_ODDFRM; - else - hcchar &= ~HCCHAR_ODDFRM; + hcchar = td->hcchar; + hcchar |= HCCHAR_EPDIR_IN; - /* must enable channel before data can be received */ - DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(channel), hcchar); + /* receive complete split ASAP */ + if ((sc->sc_last_frame_num & 1) != 0 && + td->ep_type == UE_ISOCHRONOUS) + hcchar |= HCCHAR_ODDFRM; + else + hcchar &= ~HCCHAR_ODDFRM; + /* must enable channel before data can be received */ + DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(channel), hcchar); + } /* wait until next slot before trying complete split */ td->tt_complete_slot = sc->sc_last_frame_num + 1; @@ -1442,7 +1479,7 @@ receive_spkt: goto busy; } - channel = td->channel; + channel = td->channel[0]; td->hcsplt &= ~HCSPLT_COMPSPLT; td->state = DWC_CHAN_ST_WAIT_S_ANE; @@ -1454,7 +1491,8 @@ receive_spkt: DWC_OTG_WRITE_4(sc, DOTG_HCSPLT(channel), td->hcsplt); /* send after next SOF event */ - if ((sc->sc_last_frame_num & 1) == 0) + if ((sc->sc_last_frame_num & 1) == 0 && + td->ep_type == UE_ISOCHRONOUS) td->hcchar |= HCCHAR_ODDFRM; else td->hcchar &= ~HCCHAR_ODDFRM; @@ -1609,10 +1647,12 @@ dwc_otg_host_data_tx(struct dwc_otg_softc *sc, struct dwc_otg_td *td) uint32_t hcchar; uint8_t delta; uint8_t channel; + uint8_t x; dwc_otg_host_dump_rx(sc, td); - channel = td->channel; + /* check that last channel is complete */ + channel = td->channel[td->npkt]; if (channel < DWC_OTG_MAX_CHANNELS) { hcint = sc->sc_chan_state[channel].hcint; @@ -1655,14 +1695,18 @@ dwc_otg_host_data_tx(struct dwc_otg_softc *sc, struct dwc_otg_td *td) case DWC_CHAN_ST_WAIT_ANE: if (hcint & (HCINT_RETRY | HCINT_ERRORS)) { - td->did_nak++; + td->did_nak = 1; td->tt_scheduled = 0; goto send_pkt; } else if (hcint & (HCINT_ACK | HCINT_NYET)) { td->offset += td->tx_bytes; td->remainder -= td->tx_bytes; td->toggle ^= 1; - td->did_nak = 0; + /* check if next response will be a NAK */ + if (hcint & HCINT_NYET) + td->did_nak = 1; + else + td->did_nak = 0; td->tt_scheduled = 0; /* check remainder */ @@ -1681,7 +1725,7 @@ dwc_otg_host_data_tx(struct dwc_otg_softc *sc, struct dwc_otg_td *td) case DWC_CHAN_ST_WAIT_S_ANE: if (hcint & (HCINT_RETRY | HCINT_ERRORS)) { - td->did_nak++; + td->did_nak = 1; td->tt_scheduled = 0; goto send_pkt; } else if (hcint & (HCINT_ACK | HCINT_NYET)) { @@ -1694,7 +1738,7 @@ dwc_otg_host_data_tx(struct dwc_otg_softc *sc, struct dwc_otg_td *td) if (hcint & HCINT_NYET) { goto send_cpkt; } else if (hcint & (HCINT_RETRY | HCINT_ERRORS)) { - td->did_nak++; + td->did_nak = 1; td->tt_scheduled = 0; goto send_pkt; } else if (hcint & HCINT_ACK) { @@ -1719,33 +1763,13 @@ dwc_otg_host_data_tx(struct dwc_otg_softc *sc, struct dwc_otg_td *td) goto send_cpkt; case DWC_CHAN_ST_TX_WAIT_ISOC: - - /* Check if isochronous OUT traffic is complete */ + /* Check if ISOCHRONOUS OUT traffic is complete */ if ((hcint & HCINT_HCH_DONE_MASK) == 0) break; td->offset += td->tx_bytes; td->remainder -= td->tx_bytes; - - if (td->hcsplt != 0 || td->remainder == 0) - goto complete; - - /* check for next packet */ - if (td->max_packet_count > 1) - td->tt_xactpos++; - - /* free existing channel, if any */ - dwc_otg_host_channel_free(sc, td); - - td->state = DWC_CHAN_ST_TX_PKT_ISOC; - - /* FALLTHROUGH */ - - case DWC_CHAN_ST_TX_PKT_ISOC: - if (dwc_otg_host_channel_alloc(sc, td, 1)) - break; - channel = td->channel; - goto send_isoc_pkt; + goto complete; default: break; } @@ -1779,8 +1803,6 @@ send_pkt: goto busy; } - channel = td->channel; - /* set toggle, if any */ if (td->set_toggle) { td->set_toggle = 0; @@ -1788,8 +1810,7 @@ send_pkt: } if (td->ep_type == UE_ISOCHRONOUS) { -send_isoc_pkt: - /* Isochronous OUT transfers don't have any ACKs */ + /* ISOCHRONOUS OUT transfers don't have any ACKs */ td->state = DWC_CHAN_ST_TX_WAIT_ISOC; td->hcsplt &= ~HCSPLT_COMPSPLT; if (td->hcsplt != 0) { @@ -1803,122 +1824,110 @@ send_isoc_pkt: /* Update transaction position */ td->hcsplt &= ~HCSPLT_XACTPOS_MASK; td->hcsplt |= (HCSPLT_XACTPOS_ALL << HCSPLT_XACTPOS_SHIFT); - } else { - /* send one packet at a time */ - count = td->max_packet_size; - if (td->remainder < count) { - /* we have a short packet */ - td->short_pkt = 1; - count = td->remainder; - } } } else if (td->hcsplt != 0) { - td->hcsplt &= ~HCSPLT_COMPSPLT; - /* Wait for ACK/NAK/ERR from TT */ td->state = DWC_CHAN_ST_WAIT_S_ANE; - - /* send one packet at a time */ - count = td->max_packet_size; - if (td->remainder < count) { - /* we have a short packet */ - td->short_pkt = 1; - count = td->remainder; - } } else { /* Wait for ACK/NAK/STALL from device */ td->state = DWC_CHAN_ST_WAIT_ANE; + } + + td->tx_bytes = 0; + + for (x = 0; x != td->max_packet_count; x++) { + uint32_t rem_bytes; + + channel = td->channel[x]; /* send one packet at a time */ count = td->max_packet_size; - if (td->remainder < count) { + rem_bytes = td->remainder - td->tx_bytes; + if (rem_bytes < count) { /* we have a short packet */ td->short_pkt = 1; - count = td->remainder; + count = rem_bytes; } - } - - /* check for High-Speed multi-packets */ - if ((td->hcsplt == 0) && (td->max_packet_count > 1)) { - if (td->npkt == 0) { - if (td->remainder >= (3 * td->max_packet_size)) - td->npkt = 3; - else if (td->remainder >= (2 * td->max_packet_size)) - td->npkt = 2; - else - td->npkt = 1; - - if (td->npkt > td->max_packet_count) - td->npkt = td->max_packet_count; - - td->tt_xactpos = 1; /* overload */ - } - if (td->tt_xactpos == td->npkt) { - if (td->npkt == 1) { + if (count == rem_bytes) { + /* last packet */ + switch (x) { + case 0: DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(channel), (count << HCTSIZ_XFERSIZE_SHIFT) | (1 << HCTSIZ_PKTCNT_SHIFT) | - (HCTSIZ_PID_DATA0 << HCTSIZ_PID_SHIFT)); - } else if (td->npkt == 2) { + (td->toggle ? (HCTSIZ_PID_DATA1 << HCTSIZ_PID_SHIFT) : + (HCTSIZ_PID_DATA0 << HCTSIZ_PID_SHIFT))); + break; + case 1: DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(channel), (count << HCTSIZ_XFERSIZE_SHIFT) | (1 << HCTSIZ_PKTCNT_SHIFT) | (HCTSIZ_PID_DATA1 << HCTSIZ_PID_SHIFT)); - } else { + break; + default: DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(channel), (count << HCTSIZ_XFERSIZE_SHIFT) | (1 << HCTSIZ_PKTCNT_SHIFT) | (HCTSIZ_PID_DATA2 << HCTSIZ_PID_SHIFT)); + break; } - td->npkt = 0; - } else { + } else if (td->ep_type == UE_ISOCHRONOUS && + td->max_packet_count > 1) { + /* ISOCHRONOUS multi packet */ DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(channel), (count << HCTSIZ_XFERSIZE_SHIFT) | (1 << HCTSIZ_PKTCNT_SHIFT) | (HCTSIZ_PID_MDATA << HCTSIZ_PID_SHIFT)); + } else { + /* TODO: HCTSIZ_DOPNG */ + /* standard BULK/INTERRUPT/CONTROL packet */ + DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(channel), + (count << HCTSIZ_XFERSIZE_SHIFT) | + (1 << HCTSIZ_PKTCNT_SHIFT) | + (td->toggle ? (HCTSIZ_PID_DATA1 << HCTSIZ_PID_SHIFT) : + (HCTSIZ_PID_DATA0 << HCTSIZ_PID_SHIFT))); } - } else { - /* TODO: HCTSIZ_DOPNG */ - DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(channel), - (count << HCTSIZ_XFERSIZE_SHIFT) | - (1 << HCTSIZ_PKTCNT_SHIFT) | - (td->toggle ? (HCTSIZ_PID_DATA1 << HCTSIZ_PID_SHIFT) : - (HCTSIZ_PID_DATA0 << HCTSIZ_PID_SHIFT))); - } + DWC_OTG_WRITE_4(sc, DOTG_HCSPLT(channel), td->hcsplt); - DWC_OTG_WRITE_4(sc, DOTG_HCSPLT(channel), td->hcsplt); + hcchar = td->hcchar; + hcchar &= ~HCCHAR_EPDIR_IN; - hcchar = td->hcchar; - hcchar &= ~HCCHAR_EPDIR_IN; + /* send after next SOF event */ + if ((sc->sc_last_frame_num & 1) == 0 && + td->ep_type == UE_ISOCHRONOUS) + hcchar |= HCCHAR_ODDFRM; + else + hcchar &= ~HCCHAR_ODDFRM; - /* send after next SOF event */ - if ((sc->sc_last_frame_num & 1) == 0) - hcchar |= HCCHAR_ODDFRM; - else - hcchar &= ~HCCHAR_ODDFRM; + /* must enable before writing data to FIFO */ + DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(channel), hcchar); - /* must enable before writing data to FIFO */ - DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(channel), hcchar); + if (count != 0) { + /* clear topmost word before copy */ + sc->sc_tx_bounce_buffer[(count - 1) / 4] = 0; - if (count != 0) { + /* copy out data */ + usbd_copy_out(td->pc, td->offset + td->tx_bytes, + sc->sc_tx_bounce_buffer, count); - /* clear topmost word before copy */ - sc->sc_tx_bounce_buffer[(count - 1) / 4] = 0; + /* transfer data into FIFO */ + bus_space_write_region_4(sc->sc_io_tag, sc->sc_io_hdl, + DOTG_DFIFO(channel), + sc->sc_tx_bounce_buffer, (count + 3) / 4); + } - /* copy out data */ - usbd_copy_out(td->pc, td->offset, - sc->sc_tx_bounce_buffer, count); + /* store number of bytes transmitted */ + td->tx_bytes += count; - /* transfer data into FIFO */ - bus_space_write_region_4(sc->sc_io_tag, sc->sc_io_hdl, - DOTG_DFIFO(channel), - sc->sc_tx_bounce_buffer, (count + 3) / 4); + /* store last packet index */ + td->npkt = x; + + /* check for last packet */ + if (count == rem_bytes) + break; } - - /* store number of bytes transmitted */ - td->tx_bytes = count; goto busy; send_cpkt: @@ -1944,7 +1953,7 @@ send_cpkt: goto busy; } - channel = td->channel; + channel = td->channel[0]; td->hcsplt |= HCSPLT_COMPSPLT; td->state = DWC_CHAN_ST_WAIT_C_ANE; @@ -1958,7 +1967,8 @@ send_cpkt: hcchar &= ~HCCHAR_EPDIR_IN; /* receive complete split ASAP */ - if ((sc->sc_last_frame_num & 1) != 0) + if ((sc->sc_last_frame_num & 1) != 0 && + td->ep_type == UE_ISOCHRONOUS) hcchar |= HCCHAR_ODDFRM; else hcchar &= ~HCCHAR_ODDFRM; @@ -2295,8 +2305,6 @@ static void dwc_otg_timer(void *_sc) { struct dwc_otg_softc *sc = _sc; - struct usb_xfer *xfer; - struct dwc_otg_td *td; USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); @@ -2307,14 +2315,6 @@ dwc_otg_timer(void *_sc) /* increment timer value */ sc->sc_tmr_val++; - TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { - td = xfer->td_transfer_cache; - if (td != NULL) { - /* reset NAK counter */ - td->did_nak = 0; - } - } - /* enable SOF interrupt, which will poll jobs */ dwc_otg_enable_sof_irq(sc); @@ -2354,31 +2354,6 @@ dwc_otg_timer_stop(struct dwc_otg_softc *sc) usb_callout_stop(&sc->sc_timer); } -static void -dwc_otg_host_channel_disable(struct dwc_otg_softc *sc, uint8_t x) -{ - uint32_t hcchar; - - hcchar = DWC_OTG_READ_4(sc, DOTG_HCCHAR(x)); - - /* disable host channel, if any */ - if (hcchar & (HCCHAR_CHENA | HCCHAR_CHDIS)) { - /* disable channel */ - DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(x), - HCCHAR_CHENA | HCCHAR_CHDIS); - /* wait for chip to get its brains in order */ - sc->sc_chan_state[x].wait_sof = 2; - } - - /* release TX FIFO usage, if any */ - sc->sc_tx_cur_p_level -= sc->sc_chan_state[x].tx_p_size; - sc->sc_tx_cur_np_level -= sc->sc_chan_state[x].tx_np_size; - - /* don't release TX FIFO usage twice */ - sc->sc_chan_state[x].tx_p_size = 0; - sc->sc_chan_state[x].tx_np_size = 0; -} - static uint16_t dwc_otg_compute_isoc_rx_tt_slot(struct dwc_otg_tt_info *pinfo) { @@ -2396,7 +2371,6 @@ dwc_otg_update_host_transfer_schedule_locked(struct dwc_otg_softc *sc) struct dwc_otg_td *td; uint16_t temp; uint16_t slot; - uint8_t x; temp = DWC_OTG_READ_4(sc, DOTG_HFNUM) & DWC_OTG_FRAME_MASK; @@ -2407,15 +2381,6 @@ dwc_otg_update_host_transfer_schedule_locked(struct dwc_otg_softc *sc) TAILQ_INIT(&head); - for (x = 0; x != sc->sc_host_ch_max; x++) { - if (sc->sc_chan_state[x].wait_sof == 0) - continue; - - sc->sc_needsof = 1; - if (--(sc->sc_chan_state[x].wait_sof) == 0) - dwc_otg_host_channel_disable(sc, x); - } - if ((temp & 7) == 0) { /* reset the schedule */ @@ -2430,9 +2395,6 @@ dwc_otg_update_host_transfer_schedule_locked(struct dwc_otg_softc *sc) if ((td->hcchar & HCCHAR_EPDIR_IN) != 0) continue; - /* execute more frames */ - td->tmr_val = 0; - sc->sc_needsof = 1; if (td->hcsplt == 0 || td->tt_scheduled != 0) @@ -2464,9 +2426,6 @@ dwc_otg_update_host_transfer_schedule_locked(struct dwc_otg_softc *sc) if ((td->hcchar & HCCHAR_EPDIR_IN) == 0) continue; - /* execute more frames */ - td->tmr_val = 0; - sc->sc_needsof = 1; if (td->hcsplt == 0 || td->tt_scheduled != 0) @@ -2509,8 +2468,7 @@ dwc_otg_update_host_transfer_schedule_locked(struct dwc_otg_softc *sc) TAILQ_FOREACH_SAFE(xfer, &sc->sc_bus.intr_q.head, wait_entry, xfer_next) { td = xfer->td_transfer_cache; if (td == NULL || - td->ep_type != UE_CONTROL || - td->did_nak >= DWC_OTG_NAK_MAX) { + td->ep_type != UE_CONTROL) { continue; } @@ -2530,8 +2488,7 @@ dwc_otg_update_host_transfer_schedule_locked(struct dwc_otg_softc *sc) TAILQ_FOREACH_SAFE(xfer, &sc->sc_bus.intr_q.head, wait_entry, xfer_next) { td = xfer->td_transfer_cache; if (td == NULL || - td->ep_type != UE_BULK || - td->did_nak >= DWC_OTG_NAK_MAX) { + td->ep_type != UE_BULK) { continue; } @@ -2562,10 +2519,10 @@ dwc_otg_update_host_transfer_schedule_locked(struct dwc_otg_softc *sc) TAILQ_CONCAT(&head, &sc->sc_bus.intr_q.head, wait_entry); TAILQ_CONCAT(&sc->sc_bus.intr_q.head, &head, wait_entry); - /* put non-TT BULK transfers last */ + /* put non-TT non-ISOCHRONOUS transfers last */ TAILQ_FOREACH_SAFE(xfer, &sc->sc_bus.intr_q.head, wait_entry, xfer_next) { td = xfer->td_transfer_cache; - if (td == NULL || td->hcsplt != 0 || td->ep_type != UE_BULK) + if (td == NULL || td->hcsplt != 0 || td->ep_type == UE_ISOCHRONOUS) continue; TAILQ_REMOVE(&sc->sc_bus.intr_q.head, xfer, wait_entry); TAILQ_INSERT_TAIL(&head, xfer, wait_entry); @@ -2600,12 +2557,26 @@ static void dwc_otg_interrupt_poll_locked(struct dwc_otg_softc *sc) { struct usb_xfer *xfer; + uint32_t count; uint32_t temp; uint8_t got_rx_status; uint8_t x; + if (sc->sc_flags.status_device_mode == 0) { + /* + * Update host transfer schedule, so that new + * transfers can be issued: + */ + dwc_otg_update_host_transfer_schedule_locked(sc); + } + count = 0; repeat: - /* get all channel interrupts */ + if (++count == 16) { + /* give other interrupts a chance */ + DPRINTF("Yield\n"); + return; + } + /* get all host channel interrupts */ for (x = 0; x != sc->sc_host_ch_max; x++) { temp = DWC_OTG_READ_4(sc, DOTG_HCINT(x)); if (temp != 0) { @@ -2635,6 +2606,12 @@ repeat: if (temp != GRXSTSRD_STP_DATA && temp != GRXSTSRD_STP_COMPLETE && temp != GRXSTSRD_OUT_DATA) { + /* check for halted channel */ + if (temp == GRXSTSRH_HALTED) { + ep_no = GRXSTSRD_CHNUM_GET(sc->sc_last_rx_status); + sc->sc_chan_state[ep_no].wait_halted = 0; + DPRINTFN(5, "channel halt complete ch=%u\n", ep_no); + } dwc_otg_common_rx_ack(sc); goto repeat; } @@ -2696,12 +2673,6 @@ repeat: sc->sc_irq_mask &= ~GINTMSK_RXFLVLMSK; DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask); } - - if (sc->sc_flags.status_device_mode == 0 && sc->sc_xfer_complete == 0) { - /* update host transfer schedule, so that new transfers can be issued */ - if (dwc_otg_update_host_transfer_schedule_locked(sc)) - goto repeat; - } } static void @@ -2763,6 +2734,12 @@ dwc_otg_filter_interrupt(void *arg) if ((status & DWC_OTG_MSK_GINT_THREAD_IRQ) != 0) retval = FILTER_SCHEDULE_THREAD; + /* clear FIFO empty interrupts */ + if (status & sc->sc_irq_mask & + (GINTSTS_PTXFEMP | GINTSTS_NPTXFEMP)) { + sc->sc_irq_mask &= ~(GINTSTS_PTXFEMP | GINTSTS_NPTXFEMP); + DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask); + } /* clear all IN endpoint interrupts */ if (status & GINTSTS_IEPINT) { uint32_t temp; @@ -2970,12 +2947,6 @@ dwc_otg_interrupt(void *arg) /* complete FIFOs, if any */ dwc_otg_interrupt_complete_locked(sc); - - if (sc->sc_flags.status_device_mode == 0) { - /* update host transfer schedule, so that new transfers can be issued */ - if (dwc_otg_update_host_transfer_schedule_locked(sc)) - dwc_otg_interrupt_poll_locked(sc); - } } USB_BUS_SPIN_UNLOCK(&sc->sc_bus); USB_BUS_UNLOCK(&sc->sc_bus); @@ -3008,7 +2979,9 @@ dwc_otg_setup_standard_chain_sub(struct dwc_otg_std_temp *temp) td->set_toggle = 0; td->got_short = 0; td->did_nak = 0; - td->channel = DWC_OTG_MAX_CHANNELS; + td->channel[0] = DWC_OTG_MAX_CHANNELS; + td->channel[1] = DWC_OTG_MAX_CHANNELS; + td->channel[2] = DWC_OTG_MAX_CHANNELS; td->state = 0; td->errcnt = 0; td->tt_scheduled = 0; @@ -3273,21 +3246,21 @@ dwc_otg_setup_standard_chain(struct usb_xfer *xfer) td->tmr_val = sc->sc_tmr_val + ival; td->tmr_res = ival; } else if (td->ep_type == UE_ISOCHRONOUS) { - td->tmr_val = 0; td->tmr_res = 1; + td->tmr_val = sc->sc_last_frame_num; + if (td->hcchar & HCCHAR_EPDIR_IN) + td->tmr_val++; } else { td->tmr_val = 0; - td->tmr_res = 0; + td->tmr_res = (uint8_t)sc->sc_last_frame_num; } break; case USB_SPEED_HIGH: hcsplt = 0; if (td->ep_type == UE_INTERRUPT) { uint32_t ival; -#if 0 hcchar |= ((xfer->max_packet_count & 3) << HCCHAR_MC_SHIFT); -#endif ival = xfer->interval / DWC_OTG_HOST_TIMER_RATE; if (ival == 0) ival = 1; @@ -3298,11 +3271,14 @@ dwc_otg_setup_standard_chain(struct usb_xfer *xfer) } else if (td->ep_type == UE_ISOCHRONOUS) { hcchar |= ((xfer->max_packet_count & 3) << HCCHAR_MC_SHIFT); - td->tmr_val = 0; td->tmr_res = 1 << usbd_xfer_get_fps_shift(xfer); + td->tmr_val = sc->sc_last_frame_num; + if (td->hcchar & HCCHAR_EPDIR_IN) + td->tmr_val += td->tmr_res; + } else { td->tmr_val = 0; - td->tmr_res = 0; + td->tmr_res = (uint8_t)sc->sc_last_frame_num; } break; default: @@ -3342,8 +3318,6 @@ static void dwc_otg_start_standard_chain(struct usb_xfer *xfer) { struct dwc_otg_softc *sc = DWC_OTG_BUS2SC(xfer->xroot->bus); - struct usb_xfer_root *xroot; - struct dwc_otg_td *td; DPRINTFN(9, "\n"); @@ -3358,6 +3332,19 @@ dwc_otg_start_standard_chain(struct usb_xfer *xfer) dwc_otg_xfer_do_fifo(sc, xfer); if (dwc_otg_xfer_do_complete_locked(sc, xfer)) goto done; + } else { + struct dwc_otg_td *td = xfer->td_transfer_cache; + if (td->ep_type == UE_ISOCHRONOUS && + (td->hcchar & HCCHAR_EPDIR_IN) == 0) { + /* + * Need to start ISOCHRONOUS OUT transfer ASAP + * because execution is delayed by one 125us + * microframe: + */ + dwc_otg_xfer_do_fifo(sc, xfer); + if (dwc_otg_xfer_do_complete_locked(sc, xfer)) + goto done; + } } /* put transfer on interrupt queue */ @@ -3374,24 +3361,6 @@ dwc_otg_start_standard_chain(struct usb_xfer *xfer) /* enable SOF interrupt, if any */ dwc_otg_enable_sof_irq(sc); - - td = xfer->td_transfer_cache; - if (td->ep_type != UE_BULK) - goto done; - - xroot = xfer->xroot; - - /* - * Optimise the ping-pong effect by waking up other BULK - * transfers belonging to the same device group: - */ - TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { - td = xfer->td_transfer_cache; - if (td == NULL || td->ep_type != UE_BULK || xfer->xroot != xroot) - continue; - /* reset NAK counter */ - td->did_nak = 0; - } done: USB_BUS_SPIN_UNLOCK(&sc->sc_bus); } @@ -3996,11 +3965,6 @@ dwc_otg_do_poll(struct usb_bus *bus) USB_BUS_SPIN_LOCK(&sc->sc_bus); dwc_otg_interrupt_poll_locked(sc); dwc_otg_interrupt_complete_locked(sc); - if (sc->sc_flags.status_device_mode == 0) { - /* update host transfer schedule, so that new transfers can be issued */ - if (dwc_otg_update_host_transfer_schedule_locked(sc)) - dwc_otg_interrupt_poll_locked(sc); - } USB_BUS_SPIN_UNLOCK(&sc->sc_bus); USB_BUS_UNLOCK(&sc->sc_bus); } @@ -4774,6 +4738,9 @@ dwc_otg_xfer_setup(struct usb_setup_params *parm) /* init TD */ td->max_packet_size = xfer->max_packet_size; td->max_packet_count = xfer->max_packet_count; + /* range check */ + if (td->max_packet_count == 0 || td->max_packet_count > 3) + td->max_packet_count = 1; td->ep_no = ep_no; td->ep_type = ep_type; td->obj_next = last_obj; @@ -4812,12 +4779,13 @@ dwc_otg_ep_init(struct usb_device *udev, struct usb_endpoint_descriptor *edesc, return; } } else { - if (udev->speed == USB_SPEED_HIGH) { - if ((UGETW(edesc->wMaxPacketSize) >> 11) & 3) { - /* high bandwidth endpoint - not tested */ - DPRINTF("High Bandwidth Endpoint - not tested\n"); - return; - } + if (udev->speed == USB_SPEED_HIGH && + (edesc->wMaxPacketSize[1] & 0x18) != 0 && + (edesc->bmAttributes & UE_XFERTYPE) != UE_ISOCHRONOUS) { + /* not supported */ + DPRINTFN(-1, "Non-isochronous high bandwidth " + "endpoint not supported\n"); + return; } } if ((edesc->bmAttributes & UE_XFERTYPE) == UE_ISOCHRONOUS) diff --git a/sys/dev/usb/controller/dwc_otg.h b/sys/dev/usb/controller/dwc_otg.h index 1fa1bbf..f5e9887 100644 --- a/sys/dev/usb/controller/dwc_otg.h +++ b/sys/dev/usb/controller/dwc_otg.h @@ -37,7 +37,9 @@ #define DWC_OTG_TT_SLOT_MAX 8 #define DWC_OTG_SLOT_IDLE_MAX 3 #define DWC_OTG_SLOT_IDLE_MIN 2 -#define DWC_OTG_NAK_MAX 8 /* 1 ms */ +#ifndef DWC_OTG_TX_MAX_FIFO_SIZE +#define DWC_OTG_TX_MAX_FIFO_SIZE DWC_OTG_MAX_TXN +#endif #define DWC_OTG_READ_4(sc, reg) \ bus_space_read_4((sc)->sc_io_tag, (sc)->sc_io_hdl, reg) @@ -65,10 +67,9 @@ struct dwc_otg_td { uint8_t errcnt; uint8_t tmr_res; uint8_t tmr_val; - uint8_t did_nak; /* NAK counter */ uint8_t ep_no; uint8_t ep_type; - uint8_t channel; + uint8_t channel[3]; uint8_t tt_index; /* TT data */ uint8_t tt_start_slot; /* TT data */ uint8_t tt_complete_slot; /* TT data */ @@ -79,8 +80,7 @@ struct dwc_otg_td { #define DWC_CHAN_ST_WAIT_S_ANE 2 #define DWC_CHAN_ST_WAIT_C_ANE 3 #define DWC_CHAN_ST_WAIT_C_PKT 4 -#define DWC_CHAN_ST_TX_PKT_ISOC 5 -#define DWC_CHAN_ST_TX_WAIT_ISOC 6 +#define DWC_CHAN_ST_TX_WAIT_ISOC 5 uint8_t error_any:1; uint8_t error_stall:1; uint8_t alt_next:1; @@ -90,6 +90,7 @@ struct dwc_otg_td { uint8_t set_toggle:1; uint8_t got_short:1; uint8_t tt_scheduled:1; + uint8_t did_nak:1; }; struct dwc_otg_tt_info { @@ -153,10 +154,8 @@ struct dwc_otg_profile { struct dwc_otg_chan_state { uint16_t allocated; - uint16_t wait_sof; + uint16_t wait_halted; uint32_t hcint; - uint16_t tx_p_size; /* periodic */ - uint16_t tx_np_size; /* non-periodic */ }; struct dwc_otg_softc { @@ -178,9 +177,6 @@ struct dwc_otg_softc { uint32_t sc_tx_bounce_buffer[MAX(512 * DWC_OTG_MAX_TXP, 1024) / 4]; uint32_t sc_fifo_size; - uint32_t sc_tx_max_size; - uint32_t sc_tx_cur_p_level; /* periodic */ - uint32_t sc_tx_cur_np_level; /* non-periodic */ uint32_t sc_irq_mask; uint32_t sc_last_rx_status; uint32_t sc_out_ctl[DWC_OTG_MAX_ENDPOINTS]; diff --git a/sys/dev/usb/controller/dwc_otgreg.h b/sys/dev/usb/controller/dwc_otgreg.h index 8ab3582..8b9538a 100644 --- a/sys/dev/usb/controller/dwc_otgreg.h +++ b/sys/dev/usb/controller/dwc_otgreg.h @@ -47,6 +47,8 @@ #define DOTG_GGPIO 0x0038 #define DOTG_GUID 0x003C #define DOTG_GSNPSID 0x0040 +#define DOTG_GSNPSID_REV_2_80a 0x4f54280a /* RPi model B/RPi2 */ +#define DOTG_GSNPSID_REV_3_10a 0x4f54310a /* ODROID-C1 */ #define DOTG_GHWCFG1 0x0044 #define DOTG_GHWCFG2 0x0048 #define DOTG_GHWCFG3 0x004C diff --git a/sys/dev/usb/controller/usb_controller.c b/sys/dev/usb/controller/usb_controller.c index f67c94d..1852467 100644 --- a/sys/dev/usb/controller/usb_controller.c +++ b/sys/dev/usb/controller/usb_controller.c @@ -233,7 +233,8 @@ usb_detach(device_t dev) /* Get rid of USB callback processes */ usb_proc_free(USB_BUS_GIANT_PROC(bus)); - usb_proc_free(USB_BUS_NON_GIANT_PROC(bus)); + usb_proc_free(USB_BUS_NON_GIANT_ISOC_PROC(bus)); + usb_proc_free(USB_BUS_NON_GIANT_BULK_PROC(bus)); /* Get rid of USB explore process */ @@ -397,7 +398,8 @@ usb_bus_explore(struct usb_proc_msg *pm) */ usb_proc_rewakeup(USB_BUS_CONTROL_XFER_PROC(bus)); usb_proc_rewakeup(USB_BUS_GIANT_PROC(bus)); - usb_proc_rewakeup(USB_BUS_NON_GIANT_PROC(bus)); + usb_proc_rewakeup(USB_BUS_NON_GIANT_ISOC_PROC(bus)); + usb_proc_rewakeup(USB_BUS_NON_GIANT_BULK_PROC(bus)); #endif USB_BUS_UNLOCK(bus); @@ -862,9 +864,13 @@ usb_attach_sub(device_t dev, struct usb_bus *bus) &bus->bus_mtx, device_get_nameunit(dev), USB_PRI_MED)) { device_printf(dev, "WARNING: Creation of USB Giant " "callback process failed.\n"); - } else if (usb_proc_create(USB_BUS_NON_GIANT_PROC(bus), + } else if (usb_proc_create(USB_BUS_NON_GIANT_ISOC_PROC(bus), + &bus->bus_mtx, device_get_nameunit(dev), USB_PRI_HIGHEST)) { + device_printf(dev, "WARNING: Creation of USB non-Giant ISOC " + "callback process failed.\n"); + } else if (usb_proc_create(USB_BUS_NON_GIANT_BULK_PROC(bus), &bus->bus_mtx, device_get_nameunit(dev), USB_PRI_HIGH)) { - device_printf(dev, "WARNING: Creation of USB non-Giant " + device_printf(dev, "WARNING: Creation of USB non-Giant BULK " "callback process failed.\n"); } else if (usb_proc_create(USB_BUS_EXPLORE_PROC(bus), &bus->bus_mtx, device_get_nameunit(dev), USB_PRI_MED)) { diff --git a/sys/dev/usb/serial/u3g.c b/sys/dev/usb/serial/u3g.c index aba96dc..1c8f3b5 100644 --- a/sys/dev/usb/serial/u3g.c +++ b/sys/dev/usb/serial/u3g.c @@ -492,6 +492,7 @@ static const STRUCT_USB_HOST_ID u3g_devs[] = { U3G_DEV(SIERRA, AC595U, 0), U3G_DEV(SIERRA, AC313U, 0), U3G_DEV(SIERRA, AC597E, 0), + U3G_DEV(SIERRA, AC875, 0), U3G_DEV(SIERRA, AC875E, 0), U3G_DEV(SIERRA, AC875U, 0), U3G_DEV(SIERRA, AC875U_2, 0), @@ -506,7 +507,6 @@ static const STRUCT_USB_HOST_ID u3g_devs[] = { U3G_DEV(SIERRA, AC885U, 0), U3G_DEV(SIERRA, AIRCARD580, 0), U3G_DEV(SIERRA, AIRCARD595, 0), - U3G_DEV(SIERRA, AIRCARD875, 0), U3G_DEV(SIERRA, C22, 0), U3G_DEV(SIERRA, C597, 0), U3G_DEV(SIERRA, C888, 0), diff --git a/sys/dev/usb/usb_bus.h b/sys/dev/usb/usb_bus.h index afc20f4..e9d4048 100644 --- a/sys/dev/usb/usb_bus.h +++ b/sys/dev/usb/usb_bus.h @@ -57,19 +57,26 @@ struct usb_bus { struct root_hold_token *bus_roothold; #endif +/* convenience macros */ +#define USB_BUS_TT_PROC(bus) USB_BUS_NON_GIANT_ISOC_PROC(bus) +#define USB_BUS_CS_PROC(bus) USB_BUS_NON_GIANT_ISOC_PROC(bus) + #if USB_HAVE_PER_BUS_PROCESS #define USB_BUS_GIANT_PROC(bus) (&(bus)->giant_callback_proc) -#define USB_BUS_NON_GIANT_PROC(bus) (&(bus)->non_giant_callback_proc) +#define USB_BUS_NON_GIANT_ISOC_PROC(bus) (&(bus)->non_giant_isoc_callback_proc) +#define USB_BUS_NON_GIANT_BULK_PROC(bus) (&(bus)->non_giant_bulk_callback_proc) #define USB_BUS_EXPLORE_PROC(bus) (&(bus)->explore_proc) #define USB_BUS_CONTROL_XFER_PROC(bus) (&(bus)->control_xfer_proc) - /* - * There are two callback processes. One for Giant locked - * callbacks. One for non-Giant locked callbacks. This should - * avoid congestion and reduce response time in most cases. + * There are three callback processes. One for Giant locked + * callbacks. One for non-Giant locked non-periodic callbacks + * and one for non-Giant locked periodic callbacks. This + * should avoid congestion and reduce response time in most + * cases. */ struct usb_process giant_callback_proc; - struct usb_process non_giant_callback_proc; + struct usb_process non_giant_isoc_callback_proc; + struct usb_process non_giant_bulk_callback_proc; /* Explore process */ struct usb_process explore_proc; diff --git a/sys/dev/usb/usb_device.c b/sys/dev/usb/usb_device.c index c3936f6..3e29aa4 100644 --- a/sys/dev/usb/usb_device.c +++ b/sys/dev/usb/usb_device.c @@ -2184,7 +2184,7 @@ usb_free_device(struct usb_device *udev, uint8_t flag) * anywhere: */ USB_BUS_LOCK(udev->bus); - usb_proc_mwait(USB_BUS_NON_GIANT_PROC(udev->bus), + usb_proc_mwait(USB_BUS_CS_PROC(udev->bus), &udev->cs_msg[0], &udev->cs_msg[1]); USB_BUS_UNLOCK(udev->bus); diff --git a/sys/dev/usb/usb_hub.c b/sys/dev/usb/usb_hub.c index 1c8682b..354e62d 100644 --- a/sys/dev/usb/usb_hub.c +++ b/sys/dev/usb/usb_hub.c @@ -349,7 +349,7 @@ uhub_tt_buffer_reset_async_locked(struct usb_device *child, struct usb_endpoint } up->req_reset_tt = req; /* get reset transfer started */ - usb_proc_msignal(USB_BUS_NON_GIANT_PROC(udev->bus), + usb_proc_msignal(USB_BUS_TT_PROC(udev->bus), &hub->tt_msg[0], &hub->tt_msg[1]); } #endif @@ -1592,7 +1592,7 @@ uhub_detach(device_t dev) #if USB_HAVE_TT_SUPPORT /* Make sure our TT messages are not queued anywhere */ USB_BUS_LOCK(bus); - usb_proc_mwait(USB_BUS_NON_GIANT_PROC(bus), + usb_proc_mwait(USB_BUS_TT_PROC(bus), &hub->tt_msg[0], &hub->tt_msg[1]); USB_BUS_UNLOCK(bus); #endif diff --git a/sys/dev/usb/usb_pf.c b/sys/dev/usb/usb_pf.c index 27ab5f7..8c47e79 100644 --- a/sys/dev/usb/usb_pf.c +++ b/sys/dev/usb/usb_pf.c @@ -220,7 +220,13 @@ usbpf_clone_destroy(struct if_clone *ifc, struct ifnet *ifp) ubus = ifp->if_softc; unit = ifp->if_dunit; + /* + * Lock USB before clearing the "ifp" pointer, to avoid + * clearing the pointer in the middle of a TAP operation: + */ + USB_BUS_LOCK(ubus); ubus->ifp = NULL; + USB_BUS_UNLOCK(ubus); bpfdetach(ifp); if_detach(ifp); if_free(ifp); diff --git a/sys/dev/usb/usb_process.h b/sys/dev/usb/usb_process.h index c12cdc4..dd20afd 100644 --- a/sys/dev/usb/usb_process.h +++ b/sys/dev/usb/usb_process.h @@ -34,6 +34,7 @@ #endif /* defines */ +#define USB_PRI_HIGHEST PI_SWI(SWI_TTY) #define USB_PRI_HIGH PI_SWI(SWI_NET) #define USB_PRI_MED PI_SWI(SWI_CAMBIO) diff --git a/sys/dev/usb/usb_transfer.c b/sys/dev/usb/usb_transfer.c index c5815f7..53face6 100644 --- a/sys/dev/usb/usb_transfer.c +++ b/sys/dev/usb/usb_transfer.c @@ -872,6 +872,19 @@ done: } } +static uint8_t +usbd_transfer_setup_has_bulk(const struct usb_config *setup_start, + uint16_t n_setup) +{ + while (n_setup--) { + uint8_t type = setup_start[n_setup].type; + if (type == UE_BULK || type == UE_BULK_INTR || + type == UE_TYPE_ANY) + return (1); + } + return (0); +} + /*------------------------------------------------------------------------* * usbd_transfer_setup - setup an array of USB transfers * @@ -1013,9 +1026,12 @@ usbd_transfer_setup(struct usb_device *udev, else if (xfer_mtx == &Giant) info->done_p = USB_BUS_GIANT_PROC(udev->bus); + else if (usbd_transfer_setup_has_bulk(setup_start, n_setup)) + info->done_p = + USB_BUS_NON_GIANT_BULK_PROC(udev->bus); else info->done_p = - USB_BUS_NON_GIANT_PROC(udev->bus); + USB_BUS_NON_GIANT_ISOC_PROC(udev->bus); } /* reset sizes */ @@ -2280,10 +2296,8 @@ usbd_callback_ss_done_defer(struct usb_xfer *xfer) * will have a Lock Order Reversal, LOR, if we try to * proceed ! */ - if (usb_proc_msignal(info->done_p, - &info->done_m[0], &info->done_m[1])) { - /* ignore */ - } + (void) usb_proc_msignal(info->done_p, + &info->done_m[0], &info->done_m[1]); } else { /* clear second recurse flag */ pq->recurse_2 = 0; @@ -2307,23 +2321,26 @@ usbd_callback_wrapper(struct usb_xfer_queue *pq) struct usb_xfer_root *info = xfer->xroot; USB_BUS_LOCK_ASSERT(info->bus, MA_OWNED); - if (!mtx_owned(info->xfer_mtx) && !SCHEDULER_STOPPED()) { + if ((pq->recurse_3 != 0 || mtx_owned(info->xfer_mtx) == 0) && + SCHEDULER_STOPPED() == 0) { /* * Cases that end up here: * * 5) HW interrupt done callback or other source. + * 6) HW completed transfer during callback */ - DPRINTFN(3, "case 5\n"); + DPRINTFN(3, "case 5 and 6\n"); /* * We have to postpone the callback due to the fact we * will have a Lock Order Reversal, LOR, if we try to - * proceed ! + * proceed! + * + * Postponing the callback also ensures that other USB + * transfer queues get a chance. */ - if (usb_proc_msignal(info->done_p, - &info->done_m[0], &info->done_m[1])) { - /* ignore */ - } + (void) usb_proc_msignal(info->done_p, + &info->done_m[0], &info->done_m[1]); return; } /* @@ -2381,8 +2398,11 @@ usbd_callback_wrapper(struct usb_xfer_queue *pq) } #if USB_HAVE_PF - if (xfer->usb_state != USB_ST_SETUP) + if (xfer->usb_state != USB_ST_SETUP) { + USB_BUS_LOCK(info->bus); usbpf_xfertap(xfer, USBPF_XFERTAP_DONE); + USB_BUS_UNLOCK(info->bus); + } #endif /* call processing routine */ (xfer->callback) (xfer, xfer->error); @@ -2694,7 +2714,7 @@ usbd_pipe_start(struct usb_xfer_queue *pq) } else if (udev->ctrl_xfer[1]) { info = udev->ctrl_xfer[1]->xroot; usb_proc_msignal( - USB_BUS_NON_GIANT_PROC(info->bus), + USB_BUS_CS_PROC(info->bus), &udev->cs_msg[0], &udev->cs_msg[1]); } else { /* should not happen */ @@ -3019,9 +3039,11 @@ usb_command_wrapper(struct usb_xfer_queue *pq, struct usb_xfer *xfer) if (!pq->recurse_1) { - do { + /* clear third recurse flag */ + pq->recurse_3 = 0; - /* set both recurse flags */ + do { + /* set two first recurse flags */ pq->recurse_1 = 1; pq->recurse_2 = 1; @@ -3040,6 +3062,12 @@ usb_command_wrapper(struct usb_xfer_queue *pq, struct usb_xfer *xfer) (pq->command) (pq); DPRINTFN(6, "cb %p (leave)\n", pq->curr); + /* + * Set third recurse flag to indicate + * recursion happened: + */ + pq->recurse_3 = 1; + } while (!pq->recurse_2); /* clear first recurse flag */ @@ -3315,7 +3343,8 @@ usbd_transfer_poll(struct usb_xfer **ppxfer, uint16_t max) USB_BUS_CONTROL_XFER_PROC(udev->bus)->up_msleep = 0; USB_BUS_EXPLORE_PROC(udev->bus)->up_msleep = 0; USB_BUS_GIANT_PROC(udev->bus)->up_msleep = 0; - USB_BUS_NON_GIANT_PROC(udev->bus)->up_msleep = 0; + USB_BUS_NON_GIANT_ISOC_PROC(udev->bus)->up_msleep = 0; + USB_BUS_NON_GIANT_BULK_PROC(udev->bus)->up_msleep = 0; /* poll USB hardware */ (udev->bus->methods->xfer_poll) (udev->bus); diff --git a/sys/dev/usb/usbdevs b/sys/dev/usb/usbdevs index e4dfd37..04cfd54 100644 --- a/sys/dev/usb/usbdevs +++ b/sys/dev/usb/usbdevs @@ -4009,8 +4009,7 @@ product SIERRA C22 0x6891 C22 product SIERRA E6892 0x6892 E6892 product SIERRA E6893 0x6893 E6893 product SIERRA MC8700 0x68A3 MC8700 -product SIERRA MC7354 0x6820 MC7354 -product SIERRA AIRCARD875 0x6820 Aircard 875 HSDPA +product SIERRA MC7354 0x68C0 MC7354 product SIERRA AC313U 0x68aa Sierra Wireless AirCard 313U product SIERRA TRUINSTALL 0x0fff Aircard Tru Installer diff --git a/sys/dev/usb/usbdi.h b/sys/dev/usb/usbdi.h index f3930ff..a125184 100644 --- a/sys/dev/usb/usbdi.h +++ b/sys/dev/usb/usbdi.h @@ -128,6 +128,8 @@ struct usb_xfer_queue { void (*command) (struct usb_xfer_queue *pq); uint8_t recurse_1:1; uint8_t recurse_2:1; + uint8_t recurse_3:1; + uint8_t reserved:5; }; /* |