Index: sys/dev/dksubr.c =================================================================== RCS file: /cvsroot/src/sys/dev/dksubr.c,v retrieving revision 1.63 diff -u -p -r1.63 dksubr.c --- sys/dev/dksubr.c 9 May 2015 13:07:20 -0000 1.63 +++ sys/dev/dksubr.c 20 May 2015 12:39:32 -0000 @@ -74,10 +74,31 @@ static int dk_subr_modcmd(modcmd_t, void static void dk_makedisklabel(struct dk_softc *); +static inline void +dk_lock(struct dk_softc *dksc) +{ + if (dksc->sc_iolock) + mutex_enter(dksc->sc_iolock); +} + +static inline void +dk_unlock(struct dk_softc *dksc) +{ + if (dksc->sc_iolock) + mutex_exit(dksc->sc_iolock); +} + +static inline void +dk_assertlock(struct dk_softc *dksc) +{ + if (dksc->sc_iolock) { + KASSERT(mutex_owned(dksc->sc_iolock)); + } +} + void dk_init(struct dk_softc *dksc, device_t dev, int dtype) { - memset(dksc, 0x0, sizeof(*dksc)); dksc->sc_dtype = dtype; dksc->sc_dev = dev; @@ -89,16 +110,20 @@ dk_init(struct dk_softc *dksc, device_t void dk_attach(struct dk_softc *dksc) { + dk_lock(dksc); dksc->sc_flags |= DKF_INITED; #ifdef DIAGNOSTIC dksc->sc_flags |= DKF_WARNLABEL | DKF_LABELSANITY; #endif + dk_unlock(dksc); } void dk_detach(struct dk_softc *dksc) { + dk_lock(dksc); dksc->sc_flags &= ~DKF_INITED; + dk_unlock(dksc); } /* ARGSUSED */ @@ -207,7 +232,7 @@ void dk_strategy(struct dk_softc *dksc, struct buf *bp) { const struct dkdriver *dkd = dksc->sc_dkdev.dk_driver; - int s, part; + int part; int wlabel; daddr_t blkno; struct disklabel *lp; @@ -218,9 +243,13 @@ dk_strategy(struct dk_softc *dksc, struc DPRINTF_FOLLOW(("dk_strategy(%s, %p, %p)\n", dksc->sc_xname, dksc, bp)); + dk_lock(dksc); + + /* Synchronize with init/uninit. */ if (!(dksc->sc_flags & DKF_INITED)) { + dk_unlock(dksc); DPRINTF_FOLLOW(("dk_strategy: not inited\n")); - bp->b_error = ENXIO; + bp->b_error = ENXIO; biodone(bp); return; } @@ -237,15 +266,19 @@ dk_strategy(struct dk_softc *dksc, struc /* * The transfer must be a whole number of blocks and the offset must * not be negative. - */ + */ if ((bp->b_bcount % secsize) != 0 || bp->b_blkno < 0) { + dk_unlock(dksc); + bp->b_error = EINVAL; biodone(bp); return; - } + } /* If there is nothing to do, then we are done */ if (bp->b_bcount == 0) { + dk_unlock(dksc); + biodone(bp); return; } @@ -253,11 +286,13 @@ dk_strategy(struct dk_softc *dksc, struc wlabel = dksc->sc_flags & (DKF_WLABEL|DKF_LABELLING); if (part == RAW_PART) { if (bounds_check_with_mediasize(bp, DEV_BSIZE, numsecs) <= 0) { + dk_unlock(dksc); biodone(bp); return; } } else { if (bounds_check_with_label(&dksc->sc_dkdev, bp, wlabel) <= 0) { + dk_unlock(dksc); biodone(bp); return; } @@ -272,10 +307,9 @@ dk_strategy(struct dk_softc *dksc, struc * Start the unit by calling the start routine * provided by the individual driver. */ - s = splbio(); bufq_put(dksc->sc_bufq, bp); dkd->d_diskstart(dksc->sc_dev); - splx(s); + return; } @@ -284,6 +318,8 @@ dk_done(struct dk_softc *dksc, struct bu { struct disk *dk = &dksc->sc_dkdev; + dk_assertlock(dksc); + if (bp->b_error != 0) { diskerr(bp, dksc->sc_xname, "error", LOG_PRINTF, 0, dk->dk_label); @@ -294,7 +330,9 @@ dk_done(struct dk_softc *dksc, struct bu #ifdef notyet rnd_add_uint(&dksc->sc_rnd_source, bp->b_rawblkno); #endif + dk_unlock(dksc); biodone(bp); + dk_lock(dksc); } int @@ -304,27 +342,31 @@ dk_size(struct dk_softc *dksc, dev_t dev struct disklabel *lp; int is_open; int part; - int size; + int size = -1; - if ((dksc->sc_flags & DKF_INITED) == 0) - return -1; +// dk_lock(dksc); + if ((dksc->sc_flags & DKF_INITED) == 0) { + goto done; + } part = DISKPART(dev); is_open = dksc->sc_dkdev.dk_openmask & (1 << part); if (!is_open && dkd->d_open(dev, 0, S_IFBLK, curlwp)) - return -1; + goto done; lp = dksc->sc_dkdev.dk_label; if (lp->d_partitions[part].p_fstype != FS_SWAP) - size = -1; + goto done; else size = lp->d_partitions[part].p_size * (lp->d_secsize / DEV_BSIZE); if (!is_open && dkd->d_close(dev, 0, S_IFBLK, curlwp)) - return -1; + size = -1; +done: +// dk_unlock(dksc); return size; } @@ -352,12 +394,15 @@ dk_ioctl(struct dk_softc *dksc, dev_t de case ODIOCWDINFO: #endif case DIOCWLABEL: + case DIOCKLABEL: case DIOCAWEDGE: case DIOCDWEDGE: + case DIOCSSTRATEGY: if ((flag & FWRITE) == 0) return EBADF; } + dk_lock(dksc); /* ensure that the pseudo-disk is initialized for these */ switch (cmd) { case DIOCGDINFO: @@ -378,15 +423,17 @@ dk_ioctl(struct dk_softc *dksc, dev_t de case ODIOCWDINFO: case ODIOCGDEFLABEL: #endif - if ((dksc->sc_flags & DKF_INITED) == 0) + if ((dksc->sc_flags & DKF_INITED) == 0) { + dk_unlock(dksc); return ENXIO; + } } error = disk_ioctl(dk, dev, cmd, data, flag, l); if (error != EPASSTHROUGH) - return error; - else - error = 0; + goto done; + + error = 0; switch (cmd) { case DIOCWDINFO: @@ -425,8 +472,6 @@ dk_ioctl(struct dk_softc *dksc, dev_t de break; case DIOCKLABEL: - if ((flag & FWRITE) == 0) - return (EBADF); if (*(int *)data != 0) dksc->sc_flags |= DKF_KLABEL; else @@ -456,27 +501,21 @@ dk_ioctl(struct dk_softc *dksc, dev_t de case DIOCGSTRATEGY: { struct disk_strategy *dks = (void *)data; - int s; - s = splbio(); + /* XXX IPL_VM lock? */ strlcpy(dks->dks_name, bufq_getstrategyname(dksc->sc_bufq), sizeof(dks->dks_name)); - splx(s); dks->dks_paramlen = 0; return 0; } - + case DIOCSSTRATEGY: { struct disk_strategy *dks = (void *)data; struct bufq_state *new; struct bufq_state *old; - int s; - if ((flag & FWRITE) == 0) { - return EBADF; - } if (dks->dks_param != NULL) { return EINVAL; } @@ -486,11 +525,11 @@ dk_ioctl(struct dk_softc *dksc, dev_t de if (error) { return error; } - s = splbio(); + /* XXX IPL_VM lock? */ old = dksc->sc_bufq; bufq_move(new, old); dksc->sc_bufq = new; - splx(s); + bufq_free(old); return 0; @@ -499,7 +538,8 @@ dk_ioctl(struct dk_softc *dksc, dev_t de default: error = ENOTTY; } - +done: + dk_unlock(dksc); return error; } Index: sys/dev/dkvar.h =================================================================== RCS file: /cvsroot/src/sys/dev/dkvar.h,v retrieving revision 1.20 diff -u -p -r1.20 dkvar.h --- sys/dev/dkvar.h 2 May 2015 08:00:08 -0000 1.20 +++ sys/dev/dkvar.h 20 May 2015 12:39:32 -0000 @@ -31,7 +31,8 @@ struct pathbuf; /* from namei.h */ -/* literally this is not a softc, but is intended to be included in +/* + * literally this is not a softc, but is intended to be included in * the pseudo-disk's softc and passed to calls in dksubr.c. It * should include the common elements of the pseudo-disk's softc. * All elements that are included here should describe the external @@ -44,6 +45,7 @@ struct dk_softc { #define DK_XNAME_SIZE 8 char sc_xname[DK_XNAME_SIZE]; /* external name */ struct disk sc_dkdev; /* generic disk info */ + kmutex_t *sc_iolock; /* protects buffer queue */ struct bufq_state *sc_bufq; /* buffer queue */ int sc_dtype; /* disk type */ }; Index: sys/dev/ld.c =================================================================== RCS file: /cvsroot/src/sys/dev/ld.c,v retrieving revision 1.83 diff -u -p -r1.83 ld.c --- sys/dev/ld.c 2 May 2015 08:00:08 -0000 1.83 +++ sys/dev/ld.c 20 May 2015 12:39:33 -0000 @@ -30,7 +30,7 @@ */ /* - * Disk driver for use by RAID controllers. + * Disk driver for use by RAID controllers and SD/MMC devices. */ #include @@ -60,6 +60,16 @@ __KERNEL_RCSID(0, "$NetBSD: ld.c,v 1.83 #include +/* + * Logical Disk driver. + * + * Notes on concurrency: + * + * => sc_mutex serializes access to ld_softc members, and to sc_bufq and disk + * stats of dk_softc if non-NULL. This is a temporary measure while + * all users of ld(4) are updated. + */ + static void ldminphys(struct buf *bp); static bool ld_suspend(device_t, const pmf_qual_t *); static bool ld_shutdown(device_t, int); @@ -90,7 +100,7 @@ const struct bdevsw ld_bdevsw = { .d_dump = lddump, .d_psize = ldsize, .d_discard = nodiscard, - .d_flag = D_DISK + .d_flag = D_DISK | D_MPSAFE }; const struct cdevsw ld_cdevsw = { @@ -105,7 +115,7 @@ const struct cdevsw ld_cdevsw = { .d_mmap = nommap, .d_kqfilter = nokqfilter, .d_discard = nodiscard, - .d_flag = D_DISK + .d_flag = D_DISK | D_MPSAFE }; static struct dkdriver lddkdriver = { @@ -125,14 +135,17 @@ ldattach(struct ld_softc *sc) device_t self = sc->sc_dv; struct dk_softc *dksc = &sc->sc_dksc; - mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_VM); - if ((sc->sc_flags & LDF_ENABLED) == 0) { return; } +// cv_init(&sc->sc_stop, "lddstop"); +// cv_init(&sc->sc_work, "ldwork"); /* Initialise dk and disk structure. */ dk_init(dksc, self, DKTYPE_LD); + /* Could be NULL until all backends are converted */ + dksc->sc_iolock = sc->sc_mutex; + disk_init(&dksc->sc_dkdev, dksc->sc_xname, &lddkdriver); /* Attach the device into the rnd source list. */ @@ -168,11 +181,10 @@ ldattach(struct ld_softc *sc) int ldadjqparam(struct ld_softc *sc, int xmax) { - int s; - s = splbio(); + mutex_enter(sc->sc_mutex); sc->sc_maxqueuecnt = xmax; - splx(s); + mutex_exit(sc->sc_mutex); return (0); } @@ -181,57 +193,60 @@ int ldbegindetach(struct ld_softc *sc, int flags) { struct dk_softc *dksc = &sc->sc_dksc; - int s, rv = 0; + int rv = 0; if ((sc->sc_flags & LDF_ENABLED) == 0) - return (0); + return 0; rv = disk_begindetach(&dksc->sc_dkdev, ld_lastclose, dksc->sc_dev, flags); if (rv != 0) return rv; - s = splbio(); + mutex_enter(sc->sc_mutex); sc->sc_maxqueuecnt = 0; dk_detach(dksc); while (sc->sc_queuecnt > 0) { sc->sc_flags |= LDF_DRAIN; - rv = tsleep(&sc->sc_queuecnt, PRIBIO, "lddrn", 0); + rv = cv_timedwait(&sc->sc_stop, dksc->sc_iolock, hz); if (rv) break; } - splx(s); + mutex_exit(sc->sc_mutex); return (rv); } + void ldenddetach(struct ld_softc *sc) { struct dk_softc *dksc = &sc->sc_dksc; - int s, bmaj, cmaj, i, mn; + int bmaj, cmaj, i, mn; if ((sc->sc_flags & LDF_ENABLED) == 0) return; + mutex_enter(sc->sc_mutex); /* Wait for commands queued with the hardware to complete. */ - if (sc->sc_queuecnt != 0) - if (tsleep(&sc->sc_queuecnt, PRIBIO, "lddtch", 30 * hz)) + while (sc->sc_queuecnt != 0) { + cv_timedwait(&sc->sc_stop, dksc->sc_iolock, hz); + if (false) printf("%s: not drained\n", dksc->sc_xname); - - /* Locate the major numbers. */ - bmaj = bdevsw_lookup_major(&ld_bdevsw); - cmaj = cdevsw_lookup_major(&ld_cdevsw); + } /* Kill off any queued buffers. */ - s = splbio(); bufq_drain(dksc->sc_bufq); - splx(s); + mutex_exit(sc->sc_mutex); bufq_free(dksc->sc_bufq); + /* Locate the major numbers. */ + bmaj = bdevsw_lookup_major(&ld_bdevsw); + cmaj = cdevsw_lookup_major(&ld_cdevsw); + /* Nuke the vnodes for any open instances. */ for (i = 0; i < MAXPARTITIONS; i++) { mn = DISKMINOR(device_unit(dksc->sc_dev), i); @@ -263,7 +278,6 @@ ldenddetach(struct ld_softc *sc) if ((*sc->sc_flush)(sc, 0) != 0) aprint_error_dev(dksc->sc_dev, "unable to flush cache\n"); #endif - mutex_destroy(&sc->sc_mutex); } /* ARGSUSED */ @@ -298,7 +312,8 @@ ldopen(dev_t dev, int flags, int fmt, st unit = DISKUNIT(dev); if ((sc = device_lookup_private(&ld_cd, unit)) == NULL) - return (ENXIO); + return ENXIO; + dksc = &sc->sc_dksc; return dk_open(dksc, dev, flags, fmt, l); @@ -308,12 +323,12 @@ static int ld_lastclose(device_t self) { struct ld_softc *sc = device_private(self); - + if (sc->sc_flush != NULL && (*sc->sc_flush)(sc, 0) != 0) aprint_error_dev(self, "unable to flush cache\n"); - + return 0; -} +} /* ARGSUSED */ static int @@ -358,13 +373,15 @@ ldioctl(dev_t dev, u_long cmd, void *add sc = device_lookup_private(&ld_cd, unit); dksc = &sc->sc_dksc; +// mutex_enter(xxx); + error = disk_ioctl(&dksc->sc_dkdev, dev, cmd, addr, flag, l); if (error != EPASSTHROUGH) - return (error); + return error; error = dk_ioctl(dksc, dev, cmd, addr, flag, l); if (error != EPASSTHROUGH) - return (error); + return error; error = 0; @@ -386,7 +403,7 @@ ldioctl(dev_t dev, u_long cmd, void *add break; } - return (error); + return error; } static void @@ -411,7 +428,7 @@ ld_start(device_t dev) struct buf *bp; int error; - mutex_enter(&sc->sc_mutex); + KASSERT(mutex_owned(dksc->sc_iolock)); while (sc->sc_queuecnt < sc->sc_maxqueuecnt) { /* See if there is work to do. */ @@ -423,8 +440,8 @@ ld_start(device_t dev) if (__predict_true((error = (*sc->sc_start)(sc, bp)) == 0)) { /* - * The back-end is running the job; remove it from - * the queue. + * The back-end is running/will run the job; remove it + * from the queue. */ (void) bufq_get(dksc->sc_bufq); } else { @@ -444,14 +461,14 @@ ld_start(device_t dev) (void) bufq_get(dksc->sc_bufq); bp->b_error = error; bp->b_resid = bp->b_bcount; - mutex_exit(&sc->sc_mutex); + mutex_exit(sc->sc_mutex); biodone(bp); - mutex_enter(&sc->sc_mutex); + return; } } } - mutex_exit(&sc->sc_mutex); + mutex_exit(sc->sc_mutex); } void @@ -459,18 +476,19 @@ lddone(struct ld_softc *sc, struct buf * { struct dk_softc *dksc = &sc->sc_dksc; + KASSERT(mutex_owned(dksc->sc_iolock)); dk_done(dksc, bp); - mutex_enter(&sc->sc_mutex); if (--sc->sc_queuecnt <= sc->sc_maxqueuecnt) { if ((sc->sc_flags & LDF_DRAIN) != 0) { sc->sc_flags &= ~LDF_DRAIN; - wakeup(&sc->sc_queuecnt); + cv_broadcast(&sc->sc_stop); } - mutex_exit(&sc->sc_mutex); + /* releases lock */ ld_start(dksc->sc_dev); - } else - mutex_exit(&sc->sc_mutex); + return; + } + mutex_exit(sc->sc_mutex); } static int @@ -516,7 +534,7 @@ static int ld_dumpblocks(device_t dev, void *va, daddr_t blkno, int nblk) { struct ld_softc *sc = device_private(dev); - + if (sc->sc_dump == NULL) return (ENXIO); Index: sys/dev/ldvar.h =================================================================== RCS file: /cvsroot/src/sys/dev/ldvar.h,v retrieving revision 1.23 diff -u -p -r1.23 ldvar.h --- sys/dev/ldvar.h 2 May 2015 08:00:08 -0000 1.23 +++ sys/dev/ldvar.h 20 May 2015 12:39:33 -0000 @@ -38,29 +38,30 @@ #include /* for dk_softc */ struct ld_softc { - struct dk_softc sc_dksc; - kmutex_t sc_mutex; + struct dk_softc sc_dksc; + kmutex_t *sc_mutex; /* Protects some members of dk_softc */ krndsource_t sc_rnd_source; - int sc_queuecnt; /* current h/w queue depth */ - int sc_ncylinders; /* # cylinders */ - int sc_nheads; /* # heads */ - int sc_nsectors; /* # sectors per track */ + kcondvar_t sc_stop; + int sc_queuecnt; /* current h/w queue depth */ + int sc_ncylinders; /* # cylinders */ + int sc_nheads; /* # heads */ + int sc_nsectors; /* # sectors per track */ uint64_t sc_disksize512; /* * The following are filled by hardware specific attachment code. */ device_t sc_dv; - int sc_flags; /* control flags */ - uint64_t sc_secperunit; /* # sectors in total */ - int sc_secsize; /* sector size in bytes */ - int sc_maxxfer; /* max xfer size in bytes */ - int sc_maxqueuecnt; /* maximum h/w queue depth */ - - int (*sc_dump)(struct ld_softc *, void *, int, int); - int (*sc_flush)(struct ld_softc *, int); - int (*sc_start)(struct ld_softc *, struct buf *); + int sc_flags; /* control flags */ + uint64_t sc_secperunit; /* # sectors in total */ + int sc_secsize; /* sector size in bytes */ + int sc_maxxfer; /* max xfer size in bytes */ + int sc_maxqueuecnt; /* maximum h/w queue depth */ + + int (*sc_dump)(struct ld_softc *, void *, int, int); + int (*sc_flush)(struct ld_softc *, int); + int (*sc_start)(struct ld_softc *, struct buf *); }; /* sc_flags */ Index: sys/dev/sdmmc/ld_sdmmc.c =================================================================== RCS file: /cvsroot/src/sys/dev/sdmmc/ld_sdmmc.c,v retrieving revision 1.15 diff -u -p -r1.15 ld_sdmmc.c --- sys/dev/sdmmc/ld_sdmmc.c 13 Apr 2015 16:33:25 -0000 1.15 +++ sys/dev/sdmmc/ld_sdmmc.c 20 May 2015 12:39:38 -0000 @@ -63,13 +63,14 @@ struct ld_sdmmc_softc; struct ld_sdmmc_task { struct sdmmc_task task; - struct ld_sdmmc_softc *task_sc; + struct ld_softc *task_ld; struct buf *task_bp; callout_t task_callout; }; struct ld_sdmmc_softc { struct ld_softc sc_ld; +// kmutex_t *sc_mutex; int sc_hwunit; struct sdmmc_function *sc_sf; @@ -123,6 +124,12 @@ ld_sdmmc_attach(device_t parent, device_ sc->sc_hwunit = 0; /* always 0? */ sc->sc_sf = sa->sf; + /* + * We're synchronizing against other threads and not interrupt + * handlers? + */ + + ld->sc_mutex = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE); ld->sc_flags = LDF_ENABLED; ld->sc_secperunit = sc->sc_sf->csd.capacity; ld->sc_secsize = SDMMC_SECTOR_SIZE; @@ -178,10 +185,22 @@ ld_sdmmc_detach(device_t dev, int flags) static int ld_sdmmc_start(struct ld_softc *ld, struct buf *bp) { + struct dk_softc *dksc __diagused = &ld->sc_dksc; struct ld_sdmmc_softc *sc = device_private(ld->sc_dv); struct ld_sdmmc_task *task = &sc->sc_task; - task->task_sc = sc; + KASSERT(mutex_owned(dksc->sc_iolock)); + + /* is everything done in terms of blocks? */ + if (bp->b_rawblkno >= sc->sc_sf->csd.capacity) { + /* trying to read or write past end of device */ + aprint_error_dev(sc->sc_ld.sc_dv, + "blkno 0x%" PRIu64 " exceeds capacity %d\n", + bp->b_rawblkno, sc->sc_sf->csd.capacity); + return EINVAL; + } + + task->task_ld = ld; task->task_bp = bp; sdmmc_init_task(&task->task, ld_sdmmc_dobio, task); @@ -194,13 +213,18 @@ ld_sdmmc_start(struct ld_softc *ld, stru static void ld_sdmmc_dobio(void *arg) { - struct ld_sdmmc_task *task = (struct ld_sdmmc_task *)arg; - struct ld_sdmmc_softc *sc = task->task_sc; + struct ld_sdmmc_task *task = arg; + struct ld_softc *ld = task->task_ld; struct buf *bp = task->task_bp; - int error, s; + struct dk_softc *dksc = &ld->sc_dksc; + struct ld_sdmmc_softc *sc = device_private(ld->sc_dv); + int error; callout_stop(&task->task_callout); + /* buf won't be off the queue until we have acquired the lock */ + mutex_enter(dksc->sc_iolock); + /* * I/O operation */ @@ -208,19 +232,6 @@ ld_sdmmc_dobio(void *arg) device_xname(sc->sc_ld.sc_dv), bp->b_flags & B_READ ? "IN" : "OUT", bp->b_rawblkno, bp->b_bcount)); - /* is everything done in terms of blocks? */ - if (bp->b_rawblkno >= sc->sc_sf->csd.capacity) { - /* trying to read or write past end of device */ - aprint_error_dev(sc->sc_ld.sc_dv, - "blkno 0x%" PRIu64 " exceeds capacity %d\n", - bp->b_rawblkno, sc->sc_sf->csd.capacity); - bp->b_error = EINVAL; - bp->b_resid = bp->b_bcount; - lddone(&sc->sc_ld, bp); - return; - } - - s = splbio(); if (bp->b_flags & B_READ) error = sdmmc_mem_read_block(sc->sc_sf, bp->b_rawblkno, bp->b_data, bp->b_bcount); @@ -235,8 +246,8 @@ ld_sdmmc_dobio(void *arg) } else { bp->b_resid = 0; } - splx(s); + /* releases lock */ lddone(&sc->sc_ld, bp); } @@ -244,22 +255,26 @@ static void ld_sdmmc_timeout(void *arg) { struct ld_sdmmc_task *task = (struct ld_sdmmc_task *)arg; - struct ld_sdmmc_softc *sc = task->task_sc; + struct ld_softc *ld = task->task_ld; struct buf *bp = task->task_bp; - int s; + struct dk_softc *dksc = &ld->sc_dksc; + struct ld_sdmmc_softc *sc = device_private(ld->sc_dv); - s = splbio(); + mutex_enter(&sc->sc_sf->sc->sc_tskq_mtx); if (!sdmmc_task_pending(&task->task)) { - splx(s); + mutex_exit(&sc->sc_sf->sc->sc_tskq_mtx); return; } - bp->b_error = EIO; /* XXXX */ - bp->b_resid = bp->b_bcount; - sdmmc_del_task(&task->task); - splx(s); + sdmmc_del_task(&task->task); + mutex_exit(&sc->sc_sf->sc->sc_tskq_mtx); aprint_error_dev(sc->sc_ld.sc_dv, "task timeout"); + mutex_enter(dksc->sc_iolock); + bp->b_error = EIO; /* XXXX */ + bp->b_resid = bp->b_bcount; + + /* releases lock */ lddone(&sc->sc_ld, bp); } Index: sys/dev/sdmmc/sdhc.c =================================================================== RCS file: /cvsroot/src/sys/dev/sdmmc/sdhc.c,v retrieving revision 1.58 diff -u -p -r1.58 sdhc.c --- sys/dev/sdmmc/sdhc.c 3 May 2015 22:37:27 -0000 1.58 +++ sys/dev/sdmmc/sdhc.c 20 May 2015 12:39:43 -0000 @@ -67,7 +67,7 @@ struct sdhc_host { device_t sdmmc; /* generic SD/MMC device */ - struct kmutex host_mtx; + struct kmutex host_mtx; /* Serialize access to host??? */ u_int clkbase; /* base clock frequency in KHz */ int maxblklen; /* maximum block length */ @@ -189,33 +189,32 @@ static void sdhc_write_data_pio(struct s static void esdhc_read_data_pio(struct sdhc_host *, uint8_t *, u_int); static void esdhc_write_data_pio(struct sdhc_host *, uint8_t *, u_int); - static struct sdmmc_chip_functions sdhc_functions = { /* host controller reset */ - sdhc_host_reset, + .host_reset = sdhc_host_reset, /* host controller capabilities */ - sdhc_host_ocr, - sdhc_host_maxblklen, + .host_ocr = sdhc_host_ocr, + .host_maxblklen = sdhc_host_maxblklen, /* card detection */ - sdhc_card_detect, + .card_detect = sdhc_card_detect, /* write protect */ - sdhc_write_protect, + .write_protect = sdhc_write_protect, - /* bus power, clock frequency and width */ - sdhc_bus_power, - sdhc_bus_clock, - sdhc_bus_width, - sdhc_bus_rod, + /* bus power, clock frequency, width and ROD(OpenDrain/PushPull) */ + .bus_power = sdhc_bus_power, + .bus_clock = sdhc_bus_clock, + .bus_width = sdhc_bus_width, + .bus_rod = sdhc_bus_rod, /* command execution */ - sdhc_exec_command, + .exec_command = sdhc_exec_command, /* card interrupt */ - sdhc_card_enable_intr, - sdhc_card_intr_ack + .card_enable_intr = sdhc_card_enable_intr, + .card_intr_ack = sdhc_card_intr_ack }; static int @@ -265,7 +264,7 @@ sdhc_host_found(struct sdhc_softc *sc, b hp->ios = iosize; hp->dmat = sc->sc_dmat; - mutex_init(&hp->host_mtx, MUTEX_DEFAULT, IPL_SDMMC); + mutex_init(&hp->host_mtx, MUTEX_DEFAULT, IPL_NONE); /* IPL_NONE */ mutex_init(&hp->intr_mtx, MUTEX_DEFAULT, IPL_SDMMC); cv_init(&hp->intr_cv, "sdhcintr"); @@ -309,9 +308,9 @@ sdhc_host_found(struct sdhc_softc *sc, b if (ISSET(sc->sc_flags, SDHC_FLAG_HOSTCAPS)) { caps = sc->sc_caps; } else { - mutex_enter(&hp->host_mtx); +// mutex_enter(&hp->host_mtx); caps = HREAD4(hp, SDHC_CAPABILITIES); - mutex_exit(&hp->host_mtx); +// mutex_exit(&hp->host_mtx); } /* @@ -596,7 +595,7 @@ sdhc_host_reset1(sdmmc_chipset_handle_t uint32_t sdhcimask; int error; - /* Don't lock. */ + KASSERT(mutex_owned(&hp->host_mtx)); /* Disable all interrupts. */ if (ISSET(hp->sc->sc_flags, SDHC_FLAG_32BIT_ACCESS)) { @@ -1720,6 +1719,8 @@ sdhc_intr(void *arg) if (hp == NULL) continue; + mutex_enter(&hp->intr_mtx); + if (ISSET(sc->sc_flags, SDHC_FLAG_32BIT_ACCESS)) { /* Find out which interrupts are pending. */ uint32_t xstatus = HREAD4(hp, SDHC_NINTR_STATUS); @@ -1727,16 +1728,24 @@ sdhc_intr(void *arg) error = xstatus >> 16; if (error) xstatus |= SDHC_ERROR_INTERRUPT; - else if (!ISSET(status, SDHC_NINTR_STATUS_MASK)) - continue; /* no interrupt for us */ + else if (!ISSET(status, SDHC_NINTR_STATUS_MASK)) { + /* no interrupt for us */ + mutex_exit(&hp->intr_mtx); + continue; + } + /* Acknowledge the interrupts we are about to handle. */ HWRITE4(hp, SDHC_NINTR_STATUS, xstatus); } else { /* Find out which interrupts are pending. */ error = 0; status = HREAD2(hp, SDHC_NINTR_STATUS); - if (!ISSET(status, SDHC_NINTR_STATUS_MASK)) - continue; /* no interrupt for us */ + if (!ISSET(status, SDHC_NINTR_STATUS_MASK)) { + /* no interrupt for us */ + mutex_exit(&hp->intr_mtx); + continue; + } + /* Acknowledge the interrupts we are about to handle. */ HWRITE2(hp, SDHC_NINTR_STATUS, status); if (ISSET(status, SDHC_ERROR_INTERRUPT)) { @@ -1749,8 +1758,6 @@ sdhc_intr(void *arg) DPRINTF(2,("%s: interrupt status=%x error=%x\n", HDEVNAME(hp), status, error)); - mutex_enter(&hp->intr_mtx); - /* Claim this interrupt. */ done = 1; Index: sys/dev/sdmmc/sdmmc.c =================================================================== RCS file: /cvsroot/src/sys/dev/sdmmc/sdmmc.c,v retrieving revision 1.24 diff -u -p -r1.24 sdmmc.c --- sys/dev/sdmmc/sdmmc.c 27 Feb 2015 16:08:17 -0000 1.24 +++ sys/dev/sdmmc/sdmmc.c 20 May 2015 12:39:45 -0000 @@ -150,8 +150,8 @@ sdmmc_attach(device_t parent, device_t s mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_SDMMC); mutex_init(&sc->sc_tskq_mtx, MUTEX_DEFAULT, IPL_SDMMC); - mutex_init(&sc->sc_discover_task_mtx, MUTEX_DEFAULT, IPL_SDMMC); - mutex_init(&sc->sc_intr_task_mtx, MUTEX_DEFAULT, IPL_SDMMC); +// mutex_init(&sc->sc_discover_task_mtx, MUTEX_DEFAULT, IPL_SDMMC); +// mutex_init(&sc->sc_intr_task_mtx, MUTEX_DEFAULT, IPL_SDMMC); cv_init(&sc->sc_tskq_cv, "mmctaskq"); if (ISSET(sc->sc_caps, SMC_CAPS_POLL_CARD_DET)) { @@ -207,7 +207,7 @@ sdmmc_detach(device_t self, int flags) mutex_destroy(&sc->sc_intr_task_mtx); mutex_destroy(&sc->sc_discover_task_mtx); mutex_destroy(&sc->sc_tskq_mtx); - mutex_destroy(&sc->sc_mtx); + //mutex_destroy(&sc->sc_mtx); return 0; } @@ -217,7 +217,7 @@ sdmmc_doattach(device_t dev) { struct sdmmc_softc *sc = device_private(dev); - if (kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL, + if (kthread_create(PRI_NONE, 0 /*KTHREAD_MPSAFE*/, curcpu()/*NULL*/, sdmmc_task_thread, sc, &sc->sc_tskq_lwp, "%s", device_xname(dev))) { aprint_error_dev(dev, "couldn't create task thread\n"); } @@ -228,10 +228,12 @@ sdmmc_add_task(struct sdmmc_softc *sc, s { mutex_enter(&sc->sc_tskq_mtx); - task->onqueue = 1; - task->sc = sc; - TAILQ_INSERT_TAIL(&sc->sc_tskq, task, next); - cv_broadcast(&sc->sc_tskq_cv); + if (!task->onqueue) { + task->onqueue = 1; + task->sc = sc; + TAILQ_INSERT_TAIL(&sc->sc_tskq, task, next); + cv_broadcast(&sc->sc_tskq_cv); + } mutex_exit(&sc->sc_tskq_mtx); } @@ -239,6 +241,7 @@ static inline void sdmmc_del_task1(struct sdmmc_softc *sc, struct sdmmc_task *task) { + KASSERT(mutex_owned(&sc->sc_tskq_mtx)); TAILQ_REMOVE(&sc->sc_tskq, task, next); task->sc = NULL; task->onqueue = 0; @@ -271,7 +274,9 @@ sdmmc_task_thread(void *arg) if (task != NULL) { sdmmc_del_task1(sc, task); mutex_exit(&sc->sc_tskq_mtx); +// KERNEL_LOCK(1, curlwp); (*task->func)(task->arg); +// KERNEL_UNLOCK_ONE(curlwp); mutex_enter(&sc->sc_tskq_mtx); } else { /* Check for the exit condition. */ @@ -306,8 +311,7 @@ sdmmc_needs_discover(device_t dev) return; mutex_enter(&sc->sc_discover_task_mtx); - if (!sdmmc_task_pending(&sc->sc_discover_task)) - sdmmc_add_task(sc, &sc->sc_discover_task); + sdmmc_add_task(sc, &sc->sc_discover_task); mutex_exit(&sc->sc_discover_task_mtx); } @@ -336,9 +340,8 @@ sdmmc_polling_card(void *arg) { struct sdmmc_softc *sc = (struct sdmmc_softc *)arg; int card_detect; - int s; - s = splsdmmc(); + mutex_enter(&sc->sc_mtx); card_detect = sdmmc_chip_card_detect(sc->sc_sct, sc->sc_sch); if (card_detect) { if (!ISSET(sc->sc_flags, SMF_CARD_PRESENT)) { @@ -349,7 +352,7 @@ sdmmc_polling_card(void *arg) sdmmc_needs_discover(sc->sc_dev); } } - splx(s); + mutex_exit(&sc->sc_mtx); callout_schedule(&sc->sc_card_detect_ch, hz); } Index: sys/dev/sdmmc/sdmmc_io.c =================================================================== RCS file: /cvsroot/src/sys/dev/sdmmc/sdmmc_io.c,v retrieving revision 1.7 diff -u -p -r1.7 sdmmc_io.c --- sys/dev/sdmmc/sdmmc_io.c 1 Feb 2012 22:34:43 -0000 1.7 +++ sys/dev/sdmmc/sdmmc_io.c 20 May 2015 12:39:45 -0000 @@ -627,7 +627,6 @@ sdmmc_intr_establish(device_t dev, int ( { struct sdmmc_softc *sc = device_private(dev); struct sdmmc_intr_handler *ih; - int s; if (sc->sc_sct->card_enable_intr == NULL) return NULL; @@ -647,13 +646,13 @@ sdmmc_intr_establish(device_t dev, int ( ih->ih_fun = fun; ih->ih_arg = arg; - s = splhigh(); + mutex_spin_enter(&sc->sc_mtx); if (TAILQ_EMPTY(&sc->sc_intrq)) { sdmmc_intr_enable(sc->sc_fn0); sdmmc_chip_card_enable_intr(sc->sc_sct, sc->sc_sch, 1); } TAILQ_INSERT_TAIL(&sc->sc_intrq, ih, entry); - splx(s); + mutex_spin_exit(&sc->sc_mtx); return ih; } @@ -666,18 +665,17 @@ sdmmc_intr_disestablish(void *cookie) { struct sdmmc_intr_handler *ih = cookie; struct sdmmc_softc *sc = ih->ih_softc; - int s; if (sc->sc_sct->card_enable_intr == NULL) return; - s = splhigh(); + mutex_spin_enter(&sc->sc_mtx); TAILQ_REMOVE(&sc->sc_intrq, ih, entry); if (TAILQ_EMPTY(&sc->sc_intrq)) { sdmmc_chip_card_enable_intr(sc->sc_sct, sc->sc_sch, 0); sdmmc_intr_disable(sc->sc_fn0); } - splx(s); + mutex_spin_exit(&sc->sc_mtx); free(ih->ih_name, M_DEVBUF); free(ih, M_DEVBUF); @@ -693,12 +691,12 @@ sdmmc_card_intr(device_t dev) { struct sdmmc_softc *sc = device_private(dev); - if (sc->sc_sct->card_enable_intr) { - mutex_enter(&sc->sc_intr_task_mtx); - if (!sdmmc_task_pending(&sc->sc_intr_task)) - sdmmc_add_task(sc, &sc->sc_intr_task); - mutex_exit(&sc->sc_intr_task_mtx); - } + if (sc->sc_sct->card_enable_intr == NULL) + return; + + mutex_enter(&sc->sc_intr_task_mtx); + sdmmc_add_task(sc, &sc->sc_intr_task); + mutex_exit(&sc->sc_intr_task_mtx); } void @@ -706,15 +704,14 @@ sdmmc_intr_task(void *arg) { struct sdmmc_softc *sc = (struct sdmmc_softc *)arg; struct sdmmc_intr_handler *ih; - int s; - s = splsdmmc(); + mutex_spin_enter(&sc->sc_mtx); TAILQ_FOREACH(ih, &sc->sc_intrq, entry) { - splx(s); + mutex_spin_exit(&sc->sc_mtx); /* XXX examine return value and do evcount stuff*/ (void)(*ih->ih_fun)(ih->ih_arg); - s = splsdmmc(); + mutex_spin_enter(&sc->sc_mtx); } sdmmc_chip_card_intr_ack(sc->sc_sct, sc->sc_sch); - splx(s); + mutex_spin_exit(&sc->sc_mtx); }