diff options
Diffstat (limited to 'sys')
57 files changed, 852 insertions, 929 deletions
diff --git a/sys/boot/usb/bsd_kernel.h b/sys/boot/usb/bsd_kernel.h index cb947dd..74bccd6 100644 --- a/sys/boot/usb/bsd_kernel.h +++ b/sys/boot/usb/bsd_kernel.h @@ -42,7 +42,8 @@ #define M_USBDEV 0 #define USB_PROC_MAX 3 #define USB_BUS_GIANT_PROC(bus) (usb_process + 2) -#define USB_BUS_NON_GIANT_PROC(bus) (usb_process + 2) +#define USB_BUS_NON_GIANT_BULK_PROC(bus) (usb_process + 2) +#define USB_BUS_NON_GIANT_ISOC_PROC(bus) (usb_process + 2) #define USB_BUS_EXPLORE_PROC(bus) (usb_process + 0) #define USB_BUS_CONTROL_XFER_PROC(bus) (usb_process + 1) #define SYSCTL_DECL(...) diff --git a/sys/cam/ata/ata_da.c b/sys/cam/ata/ata_da.c index 925dba9..ed8eb4d 100644 --- a/sys/cam/ata/ata_da.c +++ b/sys/cam/ata/ata_da.c @@ -1535,9 +1535,7 @@ adastart(struct cam_periph *periph, union ccb *start_ccb) } else { /* This can happen if DMA was disabled. */ bioq_remove(&softc->trim_queue, bp); - bp->bio_error = EOPNOTSUPP; - bp->bio_flags |= BIO_ERROR; - biodone(bp); + biofinish(bp, NULL, EOPNOTSUPP); xpt_release_ccb(start_ccb); adaschedule(periph); return; @@ -1602,9 +1600,7 @@ adastart(struct cam_periph *periph, union ccb *start_ccb) } } if (fail) { - bp->bio_error = EIO; - bp->bio_flags |= BIO_ERROR; - biodone(bp); + biofinish(bp, NULL, EIO); xpt_release_ccb(start_ccb); adaschedule(periph); return; diff --git a/sys/cam/ctl/ctl.c b/sys/cam/ctl/ctl.c index 8f3dd95..e07e2d0 100644 --- a/sys/cam/ctl/ctl.c +++ b/sys/cam/ctl/ctl.c @@ -9473,7 +9473,7 @@ ctl_report_luns(struct ctl_scsiio *ctsio) */ if (request_lun != NULL) { mtx_lock(&lun->lun_lock); - ctl_clr_ua(lun, initidx, CTL_UA_RES_RELEASE); + ctl_clr_ua(lun, initidx, CTL_UA_LUN_CHANGE); mtx_unlock(&lun->lun_lock); } } diff --git a/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c b/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c index 0a38cff..1955984 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c +++ b/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c @@ -3510,7 +3510,6 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v, */ if (DTRACE_ANCHORED(mstate->dtms_probe) && CPU_ON_INTR(CPU)) return ((uint64_t)p0.p_cred->cr_uid); -#endif /* * It is always safe to dereference one's own t_procp pointer: @@ -3522,6 +3521,9 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v, * credential, since this is never NULL after process birth. */ return ((uint64_t)curthread->t_procp->p_cred->cr_uid); +#else + return ((uint64_t)curthread->td_ucred->cr_uid); +#endif case DIF_VAR_GID: if (!dtrace_priv_proc(state)) @@ -3533,7 +3535,6 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v, */ if (DTRACE_ANCHORED(mstate->dtms_probe) && CPU_ON_INTR(CPU)) return ((uint64_t)p0.p_cred->cr_gid); -#endif /* * It is always safe to dereference one's own t_procp pointer: @@ -3545,6 +3546,9 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v, * credential, since this is never NULL after process birth. */ return ((uint64_t)curthread->t_procp->p_cred->cr_gid); +#else + return ((uint64_t)curthread->td_ucred->cr_gid); +#endif case DIF_VAR_ERRNO: { #if defined(sun) diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c index 85defb0..30aac16 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c @@ -1823,7 +1823,7 @@ arc_hdr_destroy(arc_buf_hdr_t *hdr) if (l2hdr != NULL) { trim_map_free(l2hdr->b_dev->l2ad_vdev, l2hdr->b_daddr, - hdr->b_size, 0); + l2hdr->b_asize, 0); list_remove(l2hdr->b_dev->l2ad_buflist, hdr); arc_buf_l2_cdata_free(hdr); ARCSTAT_INCR(arcstat_l2_size, -hdr->b_size); @@ -3822,7 +3822,7 @@ arc_release(arc_buf_t *buf, void *tag) vdev_space_update(l2hdr->b_dev->l2ad_vdev, -l2hdr->b_asize, 0, 0); trim_map_free(l2hdr->b_dev->l2ad_vdev, l2hdr->b_daddr, - hdr->b_size, 0); + l2hdr->b_asize, 0); kmem_free(l2hdr, sizeof (l2arc_buf_hdr_t)); ARCSTAT_INCR(arcstat_l2_size, -buf_size); mutex_exit(&l2arc_buflist_mtx); @@ -4761,7 +4761,7 @@ l2arc_write_done(zio_t *zio) bytes_dropped += abl2->b_asize; hdr->b_l2hdr = NULL; trim_map_free(abl2->b_dev->l2ad_vdev, abl2->b_daddr, - hdr->b_size, 0); + abl2->b_asize, 0); kmem_free(abl2, sizeof (l2arc_buf_hdr_t)); ARCSTAT_INCR(arcstat_l2_size, -hdr->b_size); } @@ -5062,8 +5062,7 @@ l2arc_write_buffers(spa_t *spa, l2arc_dev_t *dev, uint64_t target_sz, { arc_buf_hdr_t *hdr, *hdr_prev, *head; list_t *list; - uint64_t write_asize, write_psize, write_sz, headroom, - buf_compress_minsz; + uint64_t write_asize, write_sz, headroom, buf_compress_minsz; void *buf_data; kmutex_t *list_lock; boolean_t full; @@ -5079,7 +5078,7 @@ l2arc_write_buffers(spa_t *spa, l2arc_dev_t *dev, uint64_t target_sz, *headroom_boost = B_FALSE; pio = NULL; - write_sz = write_asize = write_psize = 0; + write_sz = write_asize = 0; full = B_FALSE; head = kmem_cache_alloc(hdr_cache, KM_PUSHPAGE); head->b_flags |= ARC_FLAG_L2_WRITE_HEAD; @@ -5122,6 +5121,7 @@ l2arc_write_buffers(spa_t *spa, l2arc_dev_t *dev, uint64_t target_sz, l2arc_buf_hdr_t *l2hdr; kmutex_t *hash_lock; uint64_t buf_sz; + uint64_t buf_a_sz; if (arc_warm == B_FALSE) hdr_prev = list_next(list, hdr); @@ -5153,7 +5153,15 @@ l2arc_write_buffers(spa_t *spa, l2arc_dev_t *dev, uint64_t target_sz, continue; } - if ((write_sz + hdr->b_size) > target_sz) { + /* + * Assume that the buffer is not going to be compressed + * and could take more space on disk because of a larger + * disk block size. + */ + buf_sz = hdr->b_size; + buf_a_sz = vdev_psize_to_asize(dev->l2ad_vdev, buf_sz); + + if ((write_asize + buf_a_sz) > target_sz) { full = B_TRUE; mutex_exit(hash_lock); ARCSTAT_BUMP(arcstat_l2_write_full); @@ -5196,7 +5204,6 @@ l2arc_write_buffers(spa_t *spa, l2arc_dev_t *dev, uint64_t target_sz, l2hdr->b_asize = hdr->b_size; l2hdr->b_tmp_cdata = hdr->b_buf->b_data; - buf_sz = hdr->b_size; hdr->b_l2hdr = l2hdr; list_insert_head(dev->l2ad_buflist, hdr); @@ -5211,6 +5218,7 @@ l2arc_write_buffers(spa_t *spa, l2arc_dev_t *dev, uint64_t target_sz, mutex_exit(hash_lock); write_sz += buf_sz; + write_asize += buf_a_sz; } mutex_exit(list_lock); @@ -5228,6 +5236,19 @@ l2arc_write_buffers(spa_t *spa, l2arc_dev_t *dev, uint64_t target_sz, } /* + * Note that elsewhere in this file arcstat_l2_asize + * and the used space on l2ad_vdev are updated using b_asize, + * which is not necessarily rounded up to the device block size. + * Too keep accounting consistent we do the same here as well: + * stats_size accumulates the sum of b_asize of the written buffers, + * while write_asize accumulates the sum of b_asize rounded up + * to the device block size. + * The latter sum is used only to validate the corectness of the code. + */ + uint64_t stats_size = 0; + write_asize = 0; + + /* * Now start writing the buffers. We're starting at the write head * and work backwards, retracing the course of the buffer selector * loop above. @@ -5275,7 +5296,7 @@ l2arc_write_buffers(spa_t *spa, l2arc_dev_t *dev, uint64_t target_sz, /* Compression may have squashed the buffer to zero length. */ if (buf_sz != 0) { - uint64_t buf_p_sz; + uint64_t buf_a_sz; wzio = zio_write_phys(pio, dev->l2ad_vdev, dev->l2ad_hand, buf_sz, buf_data, ZIO_CHECKSUM_OFF, @@ -5286,13 +5307,13 @@ l2arc_write_buffers(spa_t *spa, l2arc_dev_t *dev, uint64_t target_sz, zio_t *, wzio); (void) zio_nowait(wzio); - write_asize += buf_sz; + stats_size += buf_sz; /* * Keep the clock hand suitably device-aligned. */ - buf_p_sz = vdev_psize_to_asize(dev->l2ad_vdev, buf_sz); - write_psize += buf_p_sz; - dev->l2ad_hand += buf_p_sz; + buf_a_sz = vdev_psize_to_asize(dev->l2ad_vdev, buf_sz); + write_asize += buf_a_sz; + dev->l2ad_hand += buf_a_sz; } } @@ -5302,8 +5323,8 @@ l2arc_write_buffers(spa_t *spa, l2arc_dev_t *dev, uint64_t target_sz, ARCSTAT_BUMP(arcstat_l2_writes_sent); ARCSTAT_INCR(arcstat_l2_write_bytes, write_asize); ARCSTAT_INCR(arcstat_l2_size, write_sz); - ARCSTAT_INCR(arcstat_l2_asize, write_asize); - vdev_space_update(dev->l2ad_vdev, write_psize, 0, 0); + ARCSTAT_INCR(arcstat_l2_asize, stats_size); + vdev_space_update(dev->l2ad_vdev, stats_size, 0, 0); /* * Bump device hand to the device start if it is approaching the end. diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c index af4a50f..c07737e 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c @@ -4129,6 +4129,8 @@ spa_import_rootpool(const char *name) &spa->spa_ubsync.ub_version) != 0) spa->spa_ubsync.ub_version = SPA_VERSION_INITIAL; } else if ((spa = spa_lookup(name)) == NULL) { + mutex_exit(&spa_namespace_lock); + nvlist_free(config); cmn_err(CE_NOTE, "Cannot find the pool label for '%s'", name); return (EIO); diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c index 0ebc234..b690b69 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c @@ -466,6 +466,19 @@ zfs_register_callbacks(vfs_t *vfsp) } /* + * We need to enter pool configuration here, so that we can use + * dsl_prop_get_int_ds() to handle the special nbmand property below. + * dsl_prop_get_integer() can not be used, because it has to acquire + * spa_namespace_lock and we can not do that because we already hold + * z_teardown_lock. The problem is that spa_config_sync() is called + * with spa_namespace_lock held and the function calls ZFS vnode + * operations to write the cache file and thus z_teardown_lock is + * acquired after spa_namespace_lock. + */ + ds = dmu_objset_ds(os); + dsl_pool_config_enter(dmu_objset_pool(os), FTAG); + + /* * nbmand is a special property. It can only be changed at * mount time. * @@ -476,14 +489,9 @@ zfs_register_callbacks(vfs_t *vfsp) nbmand = B_FALSE; } else if (vfs_optionisset(vfsp, MNTOPT_NBMAND, NULL)) { nbmand = B_TRUE; - } else { - char osname[MAXNAMELEN]; - - dmu_objset_name(os, osname); - if (error = dsl_prop_get_integer(osname, "nbmand", &nbmand, - NULL)) { - return (error); - } + } else if (error = dsl_prop_get_int_ds(ds, "nbmand", &nbmand) != 0) { + dsl_pool_config_exit(dmu_objset_pool(os), FTAG); + return (error); } /* @@ -493,8 +501,6 @@ zfs_register_callbacks(vfs_t *vfsp) * the first prop_register(), but I guess I like to go * overboard... */ - ds = dmu_objset_ds(os); - dsl_pool_config_enter(dmu_objset_pool(os), FTAG); error = dsl_prop_register(ds, zfs_prop_to_name(ZFS_PROP_ATIME), atime_changed_cb, zfsvfs); error = error ? error : dsl_prop_register(ds, @@ -1700,9 +1706,19 @@ zfs_mount(vfs_t *vfsp) * according to those options set in the current VFS options. */ if (vfsp->vfs_flag & MS_REMOUNT) { - /* refresh mount options */ - zfs_unregister_callbacks(vfsp->vfs_data); + zfsvfs_t *zfsvfs = vfsp->vfs_data; + + /* + * Refresh mount options with z_teardown_lock blocking I/O while + * the filesystem is in an inconsistent state. + * The lock also serializes this code with filesystem + * manipulations between entry to zfs_suspend_fs() and return + * from zfs_resume_fs(). + */ + rrm_enter(&zfsvfs->z_teardown_lock, RW_WRITER, FTAG); + zfs_unregister_callbacks(zfsvfs); error = zfs_register_callbacks(vfsp); + rrm_exit(&zfsvfs->z_teardown_lock, FTAG); goto out; } 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; }; /* diff --git a/sys/fs/nfsserver/nfs_nfsdstate.c b/sys/fs/nfsserver/nfs_nfsdstate.c index 7f58cd9..c6d9448 100644 --- a/sys/fs/nfsserver/nfs_nfsdstate.c +++ b/sys/fs/nfsserver/nfs_nfsdstate.c @@ -406,9 +406,12 @@ nfsrv_setclient(struct nfsrv_descript *nd, struct nfsclient **new_clpp, } /* For NFSv4.1, mark that we found a confirmed clientid. */ - if ((nd->nd_flag & ND_NFSV41) != 0) + if ((nd->nd_flag & ND_NFSV41) != 0) { + clientidp->lval[0] = clp->lc_clientid.lval[0]; + clientidp->lval[1] = clp->lc_clientid.lval[1]; + confirmp->lval[0] = 0; /* Ignored by client */ confirmp->lval[1] = 1; - else { + } else { /* * id and verifier match, so update the net address info * and get rid of any existing callback authentication diff --git a/sys/fs/procfs/procfs_ctl.c b/sys/fs/procfs/procfs_ctl.c index 5a32863..15679e3 100644 --- a/sys/fs/procfs/procfs_ctl.c +++ b/sys/fs/procfs/procfs_ctl.c @@ -143,8 +143,8 @@ procfs_control(struct thread *td, struct proc *p, int op) p->p_flag |= P_TRACED; faultin(p); p->p_xstat = 0; /* XXX ? */ + p->p_oppid = p->p_pptr->p_pid; if (p->p_pptr != td->td_proc) { - p->p_oppid = p->p_pptr->p_pid; proc_reparent(p, td->td_proc); } kern_psignal(p, SIGSTOP); diff --git a/sys/geom/geom_io.c b/sys/geom/geom_io.c index e72e709..f1edc70 100644 --- a/sys/geom/geom_io.c +++ b/sys/geom/geom_io.c @@ -71,7 +71,17 @@ static struct g_bioq g_bio_run_down; static struct g_bioq g_bio_run_up; static struct g_bioq g_bio_run_task; -static u_int pace; +/* + * Pace is a hint that we've had some trouble recently allocating + * bios, so we should back off trying to send I/O down the stack + * a bit to let the problem resolve. When pacing, we also turn + * off direct dispatch to also reduce memory pressure from I/Os + * there, at the expxense of some added latency while the memory + * pressures exist. See g_io_schedule_down() for more details + * and limitations. + */ +static volatile u_int pace; + static uma_zone_t biozone; /* @@ -521,7 +531,8 @@ g_io_request(struct bio *bp, struct g_consumer *cp) (pp->flags & G_PF_DIRECT_RECEIVE) != 0 && !g_is_geom_thread(curthread) && ((pp->flags & G_PF_ACCEPT_UNMAPPED) != 0 || - (bp->bio_flags & BIO_UNMAPPED) == 0 || THREAD_CAN_SLEEP()); + (bp->bio_flags & BIO_UNMAPPED) == 0 || THREAD_CAN_SLEEP()) && + pace == 0; if (direct) { /* Block direct execution if less then half of stack left. */ size_t st, su; @@ -688,7 +699,7 @@ g_io_deliver(struct bio *bp, int error) bp->bio_driver2 = NULL; bp->bio_pflags = 0; g_io_request(bp, cp); - pace++; + pace = 1; return; } @@ -777,10 +788,33 @@ g_io_schedule_down(struct thread *tp __unused) } CTR0(KTR_GEOM, "g_down has work to do"); g_bioq_unlock(&g_bio_run_down); - if (pace > 0) { - CTR1(KTR_GEOM, "g_down pacing self (pace %d)", pace); - pause("g_down", hz/10); - pace--; + if (pace != 0) { + /* + * There has been at least one memory allocation + * failure since the last I/O completed. Pause 1ms to + * give the system a chance to free up memory. We only + * do this once because a large number of allocations + * can fail in the direct dispatch case and there's no + * relationship between the number of these failures and + * the length of the outage. If there's still an outage, + * we'll pause again and again until it's + * resolved. Older versions paused longer and once per + * allocation failure. This was OK for a single threaded + * g_down, but with direct dispatch would lead to max of + * 10 IOPs for minutes at a time when transient memory + * issues prevented allocation for a batch of requests + * from the upper layers. + * + * XXX This pacing is really lame. It needs to be solved + * by other methods. This is OK only because the worst + * case scenario is so rare. In the worst case scenario + * all memory is tied up waiting for I/O to complete + * which can never happen since we can't allocate bios + * for that I/O. + */ + CTR0(KTR_GEOM, "g_down pacing self"); + pause("g_down", min(hz/1000, 1)); + pace = 0; } CTR2(KTR_GEOM, "g_down processing bp %p provider %s", bp, bp->bio_to->name); diff --git a/sys/gnu/fs/reiserfs/reiserfs_vfsops.c b/sys/gnu/fs/reiserfs/reiserfs_vfsops.c index 496a6ad..ad2aab0 100644 --- a/sys/gnu/fs/reiserfs/reiserfs_vfsops.c +++ b/sys/gnu/fs/reiserfs/reiserfs_vfsops.c @@ -960,8 +960,8 @@ uint32_t find_hash_out(struct reiserfs_mount *rmp) key.on_disk_key.k_objectid, key.on_disk_key.k_dir_id); retval = search_by_entry_key(sbi, &key, &path, &de); if (retval == IO_ERROR) { - pathrelse(&path); - return (UNSET_HASH); + hash = UNSET_HASH; + break; } if (retval == NAME_NOT_FOUND) de.de_entry_num--; diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index a7b0526..23b4a6d 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -115,6 +115,10 @@ int bootverbose = BOOTVERBOSE; SYSCTL_INT(_debug, OID_AUTO, bootverbose, CTLFLAG_RW, &bootverbose, 0, "Control the output of verbose kernel messages"); +#ifdef INVARIANTS +FEATURE(invariants, "Kernel compiled with INVARIANTS, may affect performance"); +#endif + /* * This ensures that there is at least one entry so that the sysinit_set * symbol is not undefined. A sybsystem ID of SI_SUB_DUMMY is never diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index d4ed909..8846ae4 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -857,13 +857,13 @@ proc_reap(struct thread *td, struct proc *p, int *status, int options) PROC_LOCK(q); sigqueue_take(p->p_ksi); PROC_UNLOCK(q); - PROC_UNLOCK(p); /* * If we got the child via a ptrace 'attach', we need to give it back * to the old parent. */ - if (p->p_oppid != 0) { + if (p->p_oppid != 0 && p->p_oppid != p->p_pptr->p_pid) { + PROC_UNLOCK(p); t = proc_realparent(p); PROC_LOCK(t); PROC_LOCK(p); @@ -880,6 +880,8 @@ proc_reap(struct thread *td, struct proc *p, int *status, int options) sx_xunlock(&proctree_lock); return; } + p->p_oppid = 0; + PROC_UNLOCK(p); /* * Remove other references to this process to ensure we have an @@ -962,7 +964,8 @@ proc_reap(struct thread *td, struct proc *p, int *status, int options) static int proc_to_reap(struct thread *td, struct proc *p, idtype_t idtype, id_t id, - int *status, int options, struct __wrusage *wrusage, siginfo_t *siginfo) + int *status, int options, struct __wrusage *wrusage, siginfo_t *siginfo, + int check_only) { struct rusage *rup; @@ -1098,7 +1101,7 @@ proc_to_reap(struct thread *td, struct proc *p, idtype_t idtype, id_t id, calccru(p, &rup->ru_utime, &rup->ru_stime); } - if (p->p_state == PRS_ZOMBIE) { + if (p->p_state == PRS_ZOMBIE && !check_only) { proc_reap(td, p, status, options); return (-1); } @@ -1192,7 +1195,7 @@ loop: sx_xlock(&proctree_lock); LIST_FOREACH(p, &q->p_children, p_sibling) { ret = proc_to_reap(td, p, idtype, id, status, options, - wrusage, siginfo); + wrusage, siginfo, 0); if (ret == 0) continue; else if (ret == 1) @@ -1294,15 +1297,17 @@ loop: * for. By maintaining a list of orphans we allow the parent * to successfully wait until the child becomes a zombie. */ - LIST_FOREACH(p, &q->p_orphans, p_orphan) { - ret = proc_to_reap(td, p, idtype, id, status, options, - wrusage, siginfo); - if (ret == 0) - continue; - else if (ret == 1) - nfound++; - else - return (0); + if (nfound == 0) { + LIST_FOREACH(p, &q->p_orphans, p_orphan) { + ret = proc_to_reap(td, p, idtype, id, NULL, options, + NULL, NULL, 1); + if (ret != 0) { + KASSERT(ret != -1, ("reaped an orphan (pid %d)", + (int)td->td_retval[0])); + nfound++; + break; + } + } } if (nfound == 0) { sx_xunlock(&proctree_lock); diff --git a/sys/kern/kern_timeout.c b/sys/kern/kern_timeout.c index 155d1f9..9f23558 100644 --- a/sys/kern/kern_timeout.c +++ b/sys/kern/kern_timeout.c @@ -1001,7 +1001,7 @@ callout_reset_sbt_on(struct callout *c, sbintime_t sbt, sbintime_t precision, * currently in progress. If there is a lock then we * can cancel the callout if it has not really started. */ - if (c->c_lock != NULL && cc_exec_cancel(cc, direct)) + if (c->c_lock != NULL && !cc_exec_cancel(cc, direct)) cancelled = cc_exec_cancel(cc, direct) = true; if (cc_exec_waiting(cc, direct)) { /* diff --git a/sys/kern/ksched.c b/sys/kern/ksched.c index efb673e..27aea72 100644 --- a/sys/kern/ksched.c +++ b/sys/kern/ksched.c @@ -30,8 +30,7 @@ * SUCH DAMAGE. */ -/* ksched: Soft real time scheduling based on "rtprio". - */ +/* ksched: Soft real time scheduling based on "rtprio". */ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); @@ -51,8 +50,7 @@ __FBSDID("$FreeBSD$"); FEATURE(kposix_priority_scheduling, "POSIX P1003.1B realtime extensions"); -/* ksched: Real-time extension to support POSIX priority scheduling. - */ +/* ksched: Real-time extension to support POSIX priority scheduling. */ struct ksched { struct timespec rr_interval; @@ -61,21 +59,21 @@ struct ksched { int ksched_attach(struct ksched **p) { - struct ksched *ksched= p31b_malloc(sizeof(*ksched)); + struct ksched *ksched; + ksched = malloc(sizeof(*ksched), M_P31B, M_WAITOK); ksched->rr_interval.tv_sec = 0; ksched->rr_interval.tv_nsec = 1000000000L / hz * sched_rr_interval(); - *p = ksched; - return 0; + return (0); } int ksched_detach(struct ksched *ks) { - p31b_free(ks); - return 0; + free(ks, M_P31B); + return (0); } /* @@ -108,47 +106,39 @@ static __inline int getscheduler(struct ksched *ksched, struct thread *td, int *policy) { struct rtprio rtp; - int e = 0; + int e; + e = 0; pri_to_rtp(td, &rtp); - switch (rtp.type) - { - case RTP_PRIO_FIFO: + switch (rtp.type) { + case RTP_PRIO_FIFO: *policy = SCHED_FIFO; break; - - case RTP_PRIO_REALTIME: + case RTP_PRIO_REALTIME: *policy = SCHED_RR; break; - - default: + default: *policy = SCHED_OTHER; break; } - - return e; + return (e); } int ksched_setparam(struct ksched *ksched, struct thread *td, const struct sched_param *param) { - int policy; - int e; + int e, policy; e = getscheduler(ksched, td, &policy); - if (e == 0) - { - e = ksched_setscheduler(ksched, td, policy, param); - } - - return e; + e = ksched_setscheduler(ksched, td, policy, param); + return (e); } int -ksched_getparam(struct ksched *ksched, - struct thread *td, struct sched_param *param) +ksched_getparam(struct ksched *ksched, struct thread *td, + struct sched_param *param) { struct rtprio rtp; @@ -159,13 +149,14 @@ ksched_getparam(struct ksched *ksched, if (PRI_MIN_TIMESHARE < rtp.prio) /* * The interactive score has it to min realtime - * so we must show max (64 most likely + * so we must show max (64 most likely). */ - param->sched_priority = (PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE); + param->sched_priority = PRI_MAX_TIMESHARE - + PRI_MIN_TIMESHARE; else param->sched_priority = tsprio_to_p4prio(rtp.prio); } - return 0; + return (0); } /* @@ -176,117 +167,106 @@ ksched_getparam(struct ksched *ksched, * */ int -ksched_setscheduler(struct ksched *ksched, - struct thread *td, int policy, const struct sched_param *param) +ksched_setscheduler(struct ksched *ksched, struct thread *td, int policy, + const struct sched_param *param) { - int e = 0; struct rtprio rtp; + int e; - switch(policy) - { - case SCHED_RR: - case SCHED_FIFO: - + e = 0; + switch(policy) { + case SCHED_RR: + case SCHED_FIFO: if (param->sched_priority >= P1B_PRIO_MIN && - param->sched_priority <= P1B_PRIO_MAX) - { + param->sched_priority <= P1B_PRIO_MAX) { rtp.prio = p4prio_to_rtpprio(param->sched_priority); - rtp.type = (policy == SCHED_FIFO) - ? RTP_PRIO_FIFO : RTP_PRIO_REALTIME; - + rtp.type = (policy == SCHED_FIFO) ? RTP_PRIO_FIFO : + RTP_PRIO_REALTIME; rtp_to_pri(&rtp, td); - } - else + } else { e = EPERM; - - + } break; - - case SCHED_OTHER: - if (param->sched_priority >= 0 && - param->sched_priority <= (PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE)) { + case SCHED_OTHER: + if (param->sched_priority >= 0 && param->sched_priority <= + (PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE)) { rtp.type = RTP_PRIO_NORMAL; rtp.prio = p4prio_to_tsprio(param->sched_priority); rtp_to_pri(&rtp, td); - } else + } else { e = EINVAL; - + } + break; + default: + e = EINVAL; break; - - default: - e = EINVAL; - break; } - - return e; + return (e); } int ksched_getscheduler(struct ksched *ksched, struct thread *td, int *policy) { - return getscheduler(ksched, td, policy); + + return (getscheduler(ksched, td, policy)); } -/* ksched_yield: Yield the CPU. - */ +/* ksched_yield: Yield the CPU. */ int ksched_yield(struct ksched *ksched) { + sched_relinquish(curthread); - return 0; + return (0); } int ksched_get_priority_max(struct ksched *ksched, int policy, int *prio) { - int e = 0; + int e; - switch (policy) - { - case SCHED_FIFO: - case SCHED_RR: - *prio = RTP_PRIO_MAX; + e = 0; + switch (policy) { + case SCHED_FIFO: + case SCHED_RR: + *prio = P1B_PRIO_MAX; break; - - case SCHED_OTHER: + case SCHED_OTHER: *prio = PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE; break; - - default: + default: e = EINVAL; + break; } - - return e; + return (e); } int ksched_get_priority_min(struct ksched *ksched, int policy, int *prio) { - int e = 0; + int e; - switch (policy) - { - case SCHED_FIFO: - case SCHED_RR: + e = 0; + switch (policy) { + case SCHED_FIFO: + case SCHED_RR: *prio = P1B_PRIO_MIN; break; - - case SCHED_OTHER: + case SCHED_OTHER: *prio = 0; break; - - default: + default: e = EINVAL; + break; } - - return e; + return (e); } int -ksched_rr_get_interval(struct ksched *ksched, - struct thread *td, struct timespec *timespec) +ksched_rr_get_interval(struct ksched *ksched, struct thread *td, + struct timespec *timespec) { - *timespec = ksched->rr_interval; - return 0; + *timespec = ksched->rr_interval; + return (0); } diff --git a/sys/kern/subr_witness.c b/sys/kern/subr_witness.c index 122a246..bd54f57 100644 --- a/sys/kern/subr_witness.c +++ b/sys/kern/subr_witness.c @@ -1221,7 +1221,7 @@ witness_checkorder(struct lock_object *lock, int flags, const char *file, for (j = 0, lle = lock_list; lle != NULL; lle = lle->ll_next) { for (i = lle->ll_count - 1; i >= 0; i--, j++) { - MPASS(j < WITNESS_COUNT); + MPASS(j < LOCK_CHILDCOUNT * LOCK_NCHILDREN); lock1 = &lle->ll_children[i]; /* diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c index 09a43f4..6ad4694 100644 --- a/sys/kern/sys_process.c +++ b/sys/kern/sys_process.c @@ -946,7 +946,15 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data) } break; case PT_DETACH: - /* reset process parent */ + /* + * Reset the process parent. + * + * NB: This clears P_TRACED before reparenting + * a detached process back to its original + * parent. Otherwise the debugee will be set + * as an orphan of the debugger. + */ + p->p_flag &= ~(P_TRACED | P_WAITED | P_FOLLOWFORK); if (p->p_oppid != p->p_pptr->p_pid) { PROC_LOCK(p->p_pptr); sigqueue_take(p->p_ksi); @@ -962,7 +970,6 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data) } else CTR1(KTR_PTRACE, "PT_DETACH: pid %d", p->p_pid); p->p_oppid = 0; - p->p_flag &= ~(P_TRACED | P_WAITED | P_FOLLOWFORK); p->p_stops = 0; /* should we send SIGCHLD? */ diff --git a/sys/net/if_epair.c b/sys/net/if_epair.c index 42a8a7a..540f06c 100644 --- a/sys/net/if_epair.c +++ b/sys/net/if_epair.c @@ -100,7 +100,7 @@ static int epair_clone_destroy(struct if_clone *, struct ifnet *); static const char epairname[] = "epair"; -/* Netisr realted definitions and sysctl. */ +/* Netisr related definitions and sysctl. */ static struct netisr_handler epair_nh = { .nh_name = epairname, .nh_proto = NETISR_EPAIR, @@ -171,7 +171,8 @@ STAILQ_HEAD(eid_list, epair_ifp_drain); static MALLOC_DEFINE(M_EPAIR, epairname, "Pair of virtual cross-over connected Ethernet-like interfaces"); -static struct if_clone *epair_cloner; +static VNET_DEFINE(struct if_clone *, epair_cloner); +#define V_epair_cloner VNET(epair_cloner) /* * DPCPU area and functions. @@ -759,10 +760,17 @@ epair_clone_create(struct if_clone *ifc, char *name, size_t len, caddr_t params) ifc_free_unit(ifc, unit); return (ENOSPC); } - *dp = 'a'; + *dp = 'b'; /* Must not change dp so we can replace 'a' by 'b' later. */ *(dp+1) = '\0'; + /* Check if 'a' and 'b' interfaces already exist. */ + if (ifunit(name) != NULL) + return (EEXIST); + *dp = 'a'; + if (ifunit(name) != NULL) + return (EEXIST); + /* Allocate memory for both [ab] interfaces */ sca = malloc(sizeof(struct epair_softc), M_EPAIR, M_WAITOK | M_ZERO); EPAIR_REFCOUNT_INIT(&sca->refcount, 1); @@ -800,6 +808,14 @@ epair_clone_create(struct if_clone *ifc, char *name, size_t len, caddr_t params) netisr_get_cpuid(sca->ifp->if_index % netisr_get_cpucount()); scb->cpuid = netisr_get_cpuid(scb->ifp->if_index % netisr_get_cpucount()); + + /* Initialise pseudo media types. */ + ifmedia_init(&sca->media, 0, epair_media_change, epair_media_status); + ifmedia_add(&sca->media, IFM_ETHER | IFM_10G_T, 0, NULL); + ifmedia_set(&sca->media, IFM_ETHER | IFM_10G_T); + ifmedia_init(&scb->media, 0, epair_media_change, epair_media_status); + ifmedia_add(&scb->media, IFM_ETHER | IFM_10G_T, 0, NULL); + ifmedia_set(&scb->media, IFM_ETHER | IFM_10G_T); /* Finish initialization of interface <n>a. */ ifp = sca->ifp; @@ -858,14 +874,6 @@ epair_clone_create(struct if_clone *ifc, char *name, size_t len, caddr_t params) strlcpy(name, sca->ifp->if_xname, len); DPRINTF("name='%s/%db' created sca=%p scb=%p\n", name, unit, sca, scb); - /* Initialise pseudo media types. */ - ifmedia_init(&sca->media, 0, epair_media_change, epair_media_status); - ifmedia_add(&sca->media, IFM_ETHER | IFM_10G_T, 0, NULL); - ifmedia_set(&sca->media, IFM_ETHER | IFM_10G_T); - ifmedia_init(&scb->media, 0, epair_media_change, epair_media_status); - ifmedia_add(&scb->media, IFM_ETHER | IFM_10G_T, 0, NULL); - ifmedia_set(&scb->media, IFM_ETHER | IFM_10G_T); - /* Tell the world, that we are ready to rock. */ sca->ifp->if_drv_flags |= IFF_DRV_RUNNING; scb->ifp->if_drv_flags |= IFF_DRV_RUNNING; @@ -943,6 +951,25 @@ epair_clone_destroy(struct if_clone *ifc, struct ifnet *ifp) return (0); } +static void +vnet_epair_init(const void *unused __unused) +{ + + V_epair_cloner = if_clone_advanced(epairname, 0, + epair_clone_match, epair_clone_create, epair_clone_destroy); +} +VNET_SYSINIT(vnet_epair_init, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY, + vnet_epair_init, NULL); + +static void +vnet_epair_uninit(const void *unused __unused) +{ + + if_clone_detach(V_epair_cloner); +} +VNET_SYSUNINIT(vnet_epair_uninit, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY, + vnet_epair_uninit, NULL); + static int epair_modevent(module_t mod, int type, void *data) { @@ -956,13 +983,10 @@ epair_modevent(module_t mod, int type, void *data) if (TUNABLE_INT_FETCH("net.link.epair.netisr_maxqlen", &qlimit)) epair_nh.nh_qlimit = qlimit; netisr_register(&epair_nh); - epair_cloner = if_clone_advanced(epairname, 0, - epair_clone_match, epair_clone_create, epair_clone_destroy); if (bootverbose) printf("%s initialized.\n", epairname); break; case MOD_UNLOAD: - if_clone_detach(epair_cloner); netisr_unregister(&epair_nh); epair_dpcpu_detach(); if (bootverbose) diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c index be603b7..4a809c8 100644 --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -6653,7 +6653,17 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp) M_ASSERTPKTHDR(m); - if (dir == PF_OUT && m->m_pkthdr.rcvif && ifp != m->m_pkthdr.rcvif) + /* Detect packet forwarding. + * If the input interface is different from the output interface we're + * forwarding. + * We do need to be careful about bridges. If the + * net.link.bridge.pfil_bridge sysctl is set we can be filtering on a + * bridge, so if the input interface is a bridge member and the output + * interface is its bridge we're not actually forwarding but bridging. + */ + if (dir == PF_OUT && m->m_pkthdr.rcvif && ifp != m->m_pkthdr.rcvif + && (m->m_pkthdr.rcvif->if_bridge == NULL + || m->m_pkthdr.rcvif->if_bridge != ifp->if_softc)) fwdir = PF_FWD; if (!V_pf_status.running) diff --git a/sys/ofed/include/linux/in.h b/sys/ofed/include/linux/in.h index d3e8add..102563f 100644 --- a/sys/ofed/include/linux/in.h +++ b/sys/ofed/include/linux/in.h @@ -37,7 +37,7 @@ #include <netinet/in.h> #include <asm/byteorder.h> -#define ipv4_is_zeronet IN_ZERONET -#define ipv4_is_loopback IN_LOOPBACK +#define ipv4_is_zeronet(be) IN_ZERONET(ntohl(be)) +#define ipv4_is_loopback(be) IN_LOOPBACK(ntohl(be)) #endif /* _LINUX_IN_H_ */ diff --git a/sys/ofed/include/linux/linux_compat.c b/sys/ofed/include/linux/linux_compat.c index f428fc8..e9cc0c6 100644 --- a/sys/ofed/include/linux/linux_compat.c +++ b/sys/ofed/include/linux/linux_compat.c @@ -33,6 +33,7 @@ #include <sys/kernel.h> #include <sys/sysctl.h> #include <sys/proc.h> +#include <sys/sglist.h> #include <sys/sleepqueue.h> #include <sys/lock.h> #include <sys/mutex.h> @@ -414,16 +415,6 @@ linux_dev_poll(struct cdev *dev, int events, struct thread *td) } static int -linux_dev_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, - int nprot, vm_memattr_t *memattr) -{ - - /* XXX memattr not honored. */ - *paddr = offset; - return (0); -} - -static int linux_dev_mmap_single(struct cdev *dev, vm_ooffset_t *offset, vm_size_t size, struct vm_object **object, int nprot) { @@ -431,36 +422,41 @@ linux_dev_mmap_single(struct cdev *dev, vm_ooffset_t *offset, struct linux_file *filp; struct file *file; struct vm_area_struct vma; - vm_paddr_t paddr; - vm_page_t m; int error; file = curthread->td_fpop; ldev = dev->si_drv1; if (ldev == NULL) return (ENODEV); - if (size != PAGE_SIZE) - return (EINVAL); if ((error = devfs_get_cdevpriv((void **)&filp)) != 0) return (error); filp->f_flags = file->f_flag; vma.vm_start = 0; - vma.vm_end = PAGE_SIZE; + vma.vm_end = size; vma.vm_pgoff = *offset / PAGE_SIZE; vma.vm_pfn = 0; vma.vm_page_prot = 0; if (filp->f_op->mmap) { error = -filp->f_op->mmap(filp, &vma); if (error == 0) { - paddr = (vm_paddr_t)vma.vm_pfn << PAGE_SHIFT; - *offset = paddr; - m = PHYS_TO_VM_PAGE(paddr); - *object = vm_pager_allocate(OBJT_DEVICE, dev, - PAGE_SIZE, nprot, *offset, curthread->td_ucred); - if (*object == NULL) - return (EINVAL); - if (vma.vm_page_prot != VM_MEMATTR_DEFAULT) - pmap_page_set_memattr(m, vma.vm_page_prot); + struct sglist *sg; + + sg = sglist_alloc(1, M_WAITOK); + sglist_append_phys(sg, + (vm_paddr_t)vma.vm_pfn << PAGE_SHIFT, vma.vm_len); + *object = vm_pager_allocate(OBJT_SG, sg, vma.vm_len, + nprot, 0, curthread->td_ucred); + if (*object == NULL) { + sglist_free(sg); + return (EINVAL); + } + *offset = 0; + if (vma.vm_page_prot != VM_MEMATTR_DEFAULT) { + VM_OBJECT_WLOCK(*object); + vm_object_set_memattr(*object, + vma.vm_page_prot); + VM_OBJECT_WUNLOCK(*object); + } } } else error = ENODEV; @@ -477,7 +473,6 @@ struct cdevsw linuxcdevsw = { .d_write = linux_dev_write, .d_ioctl = linux_dev_ioctl, .d_mmap_single = linux_dev_mmap_single, - .d_mmap = linux_dev_mmap, .d_poll = linux_dev_poll, }; diff --git a/sys/ofed/include/linux/mm.h b/sys/ofed/include/linux/mm.h index 80d59e8..b1a575c 100644 --- a/sys/ofed/include/linux/mm.h +++ b/sys/ofed/include/linux/mm.h @@ -40,6 +40,7 @@ struct vm_area_struct { vm_offset_t vm_end; vm_offset_t vm_pgoff; vm_paddr_t vm_pfn; /* PFN For mmap. */ + vm_size_t vm_len; /* length for mmap. */ vm_memattr_t vm_page_prot; }; @@ -78,6 +79,7 @@ io_remap_pfn_range(struct vm_area_struct *vma, { vma->vm_page_prot = prot; vma->vm_pfn = pfn; + vma->vm_len = size; return (0); } diff --git a/sys/rpc/rpc_generic.c b/sys/rpc/rpc_generic.c index 4643bf5..28aa849 100644 --- a/sys/rpc/rpc_generic.c +++ b/sys/rpc/rpc_generic.c @@ -703,7 +703,9 @@ __rpc_sockisbound(struct socket *so) struct sockaddr *sa; int error, bound; + CURVNET_SET(so->so_vnet); error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa); + CURVNET_RESTORE(); if (error) return (0); @@ -791,7 +793,9 @@ bindresvport(struct socket *so, struct sockaddr *sa) socklen_t salen; if (sa == NULL) { + CURVNET_SET(so->so_vnet); error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa); + CURVNET_RESTORE(); if (error) return (error); freesa = TRUE; diff --git a/sys/rpc/svc_vc.c b/sys/rpc/svc_vc.c index fb40a34..be8e04e 100644 --- a/sys/rpc/svc_vc.c +++ b/sys/rpc/svc_vc.c @@ -150,7 +150,9 @@ svc_vc_create(SVCPOOL *pool, struct socket *so, size_t sendsize, SOCK_LOCK(so); if (so->so_state & (SS_ISCONNECTED|SS_ISDISCONNECTED)) { SOCK_UNLOCK(so); + CURVNET_SET(so->so_vnet); error = so->so_proto->pr_usrreqs->pru_peeraddr(so, &sa); + CURVNET_RESTORE(); if (error) return (NULL); xprt = svc_vc_create_conn(pool, so, sa); @@ -167,7 +169,9 @@ svc_vc_create(SVCPOOL *pool, struct socket *so, size_t sendsize, xprt->xp_p2 = NULL; xprt->xp_ops = &svc_vc_rendezvous_ops; + CURVNET_SET(so->so_vnet); error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa); + CURVNET_RESTORE(); if (error) { goto cleanup_svc_vc_create; } @@ -249,7 +253,9 @@ svc_vc_create_conn(SVCPOOL *pool, struct socket *so, struct sockaddr *raddr) memcpy(&xprt->xp_rtaddr, raddr, raddr->sa_len); + CURVNET_SET(so->so_vnet); error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa); + CURVNET_RESTORE(); if (error) goto cleanup_svc_vc_create; diff --git a/sys/sys/posix4.h b/sys/sys/posix4.h index 25dbeae..8dcf36d 100644 --- a/sys/sys/posix4.h +++ b/sys/sys/posix4.h @@ -56,9 +56,6 @@ int sys_ ## SC (struct thread *td, struct SC##_args *uap) \ MALLOC_DECLARE(M_P31B); -#define p31b_malloc(SIZE) malloc((SIZE), M_P31B, M_WAITOK) -#define p31b_free(P) free((P), M_P31B) - int p31b_proc(struct proc *, pid_t, struct proc **); void p31b_setcfg(int, int); diff --git a/sys/sys/socketvar.h b/sys/sys/socketvar.h index 9090340..0afafc5 100644 --- a/sys/sys/socketvar.h +++ b/sys/sys/socketvar.h @@ -76,7 +76,7 @@ struct socket { short so_state; /* (b) internal state flags SS_* */ int so_qstate; /* (e) internal state flags SQ_* */ void *so_pcb; /* protocol control block */ - struct vnet *so_vnet; /* network stack instance */ + struct vnet *so_vnet; /* (a) network stack instance */ struct protosw *so_proto; /* (a) protocol handle */ /* * Variables for connection queuing. diff --git a/sys/x86/include/specialreg.h b/sys/x86/include/specialreg.h index 8148f14..1de4f1f 100644 --- a/sys/x86/include/specialreg.h +++ b/sys/x86/include/specialreg.h @@ -157,6 +157,7 @@ #define CPUID2_TM2 0x00000100 #define CPUID2_SSSE3 0x00000200 #define CPUID2_CNXTID 0x00000400 +#define CPUID2_SDBG 0x00000800 #define CPUID2_FMA 0x00001000 #define CPUID2_CX16 0x00002000 #define CPUID2_XTPR 0x00004000 diff --git a/sys/x86/x86/identcpu.c b/sys/x86/x86/identcpu.c index 8e5f5c3..1804595 100644 --- a/sys/x86/x86/identcpu.c +++ b/sys/x86/x86/identcpu.c @@ -781,7 +781,7 @@ printcpuinfo(void) "\011TM2" /* Thermal Monitor 2 */ "\012SSSE3" /* SSSE3 */ "\013CNXT-ID" /* L1 context ID available */ - "\014<b11>" + "\014SDBG" /* IA32 silicon debug */ "\015FMA" /* Fused Multiply Add */ "\016CX16" /* CMPXCHG16B Instruction */ "\017xTPR" /* Send Task Priority Messages*/ |