summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
authorRenato Botelho <renato@netgate.com>2015-09-11 15:21:16 -0300
committerRenato Botelho <renato@netgate.com>2015-09-11 15:21:16 -0300
commit8400c0790e456038fbca4995d032d4e3d44c3d31 (patch)
treef83f0b852f452a91d21059a9a70ff02f129eafa6 /sys/dev
parentb05262eae8651c5f280c6fadf2e22f70af66d6ca (diff)
parent6561e98b4c105596a44efb53466ecf8be2a3bbf3 (diff)
downloadFreeBSD-src-8400c0790e456038fbca4995d032d4e3d44c3d31.zip
FreeBSD-src-8400c0790e456038fbca4995d032d4e3d44c3d31.tar.gz
Merge branch 'stable/10' into devel
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/ata/ata-all.c30
-rw-r--r--sys/dev/ata/ata-all.h9
-rw-r--r--sys/dev/ciss/ciss.c8
-rw-r--r--sys/dev/filemon/filemon.c27
-rw-r--r--sys/dev/filemon/filemon_lock.c77
-rw-r--r--sys/dev/filemon/filemon_wrapper.c150
-rw-r--r--sys/dev/ipmi/ipmi.c23
-rw-r--r--sys/dev/ipmi/ipmi_kcs.c1
-rw-r--r--sys/dev/ipmi/ipmi_smic.c1
-rw-r--r--sys/dev/ipmi/ipmivars.h1
-rw-r--r--sys/dev/isci/isci.c2
-rw-r--r--sys/dev/isci/isci_interrupt.c4
-rw-r--r--sys/dev/ixgbe/if_ix.c6
-rw-r--r--sys/dev/md/md.c9
-rw-r--r--sys/dev/nvme/nvme.c9
-rw-r--r--sys/dev/sound/midi/midi.c2
-rw-r--r--sys/dev/usb/controller/dwc_otg.c762
-rw-r--r--sys/dev/usb/controller/dwc_otg.h18
-rw-r--r--sys/dev/usb/controller/dwc_otgreg.h2
-rw-r--r--sys/dev/usb/controller/usb_controller.c14
-rw-r--r--sys/dev/usb/serial/u3g.c2
-rw-r--r--sys/dev/usb/usb_bus.h19
-rw-r--r--sys/dev/usb/usb_device.c2
-rw-r--r--sys/dev/usb/usb_hub.c4
-rw-r--r--sys/dev/usb/usb_pf.c6
-rw-r--r--sys/dev/usb/usb_process.h1
-rw-r--r--sys/dev/usb/usb_transfer.c63
-rw-r--r--sys/dev/usb/usbdevs3
-rw-r--r--sys/dev/usb/usbdi.h2
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;
};
/*
OpenPOWER on IntegriCloud