Lock busdma operations and serialize detach against open/close
Use sx to allow M_WAITOK allocations (suggested by markj). admbugs: 782 Reviewed by: markj
This commit is contained in:
parent
38e220e8df
commit
9f011bca82
@ -1,5 +1,5 @@
|
||||
/*-
|
||||
* Copyright (c) 2014, 2015 Marcel Moolenaar
|
||||
* Copyright (c) 2014, 2015, 2019 Marcel Moolenaar
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -36,7 +36,8 @@
|
||||
#define PROTO_RES_BUSDMA 11
|
||||
|
||||
struct proto_res {
|
||||
int r_type;
|
||||
u_int r_type:8;
|
||||
u_int r_opened:1;
|
||||
int r_rid;
|
||||
union {
|
||||
struct resource *res;
|
||||
@ -47,13 +48,14 @@ struct proto_res {
|
||||
void *cookie;
|
||||
struct cdev *cdev;
|
||||
} r_u;
|
||||
uintptr_t r_opened;
|
||||
};
|
||||
|
||||
struct proto_softc {
|
||||
device_t sc_dev;
|
||||
struct proto_res sc_res[PROTO_RES_MAX];
|
||||
int sc_rescnt;
|
||||
int sc_opencnt;
|
||||
struct mtx sc_mtx;
|
||||
};
|
||||
|
||||
extern devclass_t proto_devclass;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*-
|
||||
* Copyright (c) 2015 Marcel Moolenaar
|
||||
* Copyright (c) 2015, 2019 Marcel Moolenaar
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/queue.h>
|
||||
#include <sys/rman.h>
|
||||
#include <sys/sbuf.h>
|
||||
#include <sys/sx.h>
|
||||
#include <sys/uio.h>
|
||||
#include <vm/vm.h>
|
||||
#include <vm/pmap.h>
|
||||
@ -355,6 +356,7 @@ proto_busdma_attach(struct proto_softc *sc)
|
||||
struct proto_busdma *busdma;
|
||||
|
||||
busdma = malloc(sizeof(*busdma), M_PROTO_BUSDMA, M_WAITOK | M_ZERO);
|
||||
sx_init(&busdma->sxlck, "proto-busdma");
|
||||
return (busdma);
|
||||
}
|
||||
|
||||
@ -363,6 +365,7 @@ proto_busdma_detach(struct proto_softc *sc, struct proto_busdma *busdma)
|
||||
{
|
||||
|
||||
proto_busdma_cleanup(sc, busdma);
|
||||
sx_destroy(&busdma->sxlck);
|
||||
free(busdma, M_PROTO_BUSDMA);
|
||||
return (0);
|
||||
}
|
||||
@ -373,10 +376,12 @@ proto_busdma_cleanup(struct proto_softc *sc, struct proto_busdma *busdma)
|
||||
struct proto_md *md, *md1;
|
||||
struct proto_tag *tag, *tag1;
|
||||
|
||||
sx_xlock(&busdma->sxlck);
|
||||
LIST_FOREACH_SAFE(md, &busdma->mds, mds, md1)
|
||||
proto_busdma_md_destroy_internal(busdma, md);
|
||||
LIST_FOREACH_SAFE(tag, &busdma->tags, tags, tag1)
|
||||
proto_busdma_tag_destroy(busdma, tag);
|
||||
sx_xunlock(&busdma->sxlck);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -388,6 +393,8 @@ proto_busdma_ioctl(struct proto_softc *sc, struct proto_busdma *busdma,
|
||||
struct proto_md *md;
|
||||
int error;
|
||||
|
||||
sx_xlock(&busdma->sxlck);
|
||||
|
||||
error = 0;
|
||||
switch (ioc->request) {
|
||||
case PROTO_IOC_BUSDMA_TAG_CREATE:
|
||||
@ -470,6 +477,9 @@ proto_busdma_ioctl(struct proto_softc *sc, struct proto_busdma *busdma,
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
sx_xunlock(&busdma->sxlck);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
@ -477,11 +487,20 @@ int
|
||||
proto_busdma_mmap_allowed(struct proto_busdma *busdma, vm_paddr_t physaddr)
|
||||
{
|
||||
struct proto_md *md;
|
||||
int result;
|
||||
|
||||
sx_xlock(&busdma->sxlck);
|
||||
|
||||
result = 0;
|
||||
LIST_FOREACH(md, &busdma->mds, mds) {
|
||||
if (physaddr >= trunc_page(md->physaddr) &&
|
||||
physaddr <= trunc_page(md->physaddr + md->tag->maxsz))
|
||||
return (1);
|
||||
physaddr <= trunc_page(md->physaddr + md->tag->maxsz)) {
|
||||
result = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
|
||||
sx_xunlock(&busdma->sxlck);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*-
|
||||
* Copyright (c) 2015 Marcel Moolenaar
|
||||
* Copyright (c) 2015, 2019 Marcel Moolenaar
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -60,6 +60,7 @@ struct proto_busdma {
|
||||
LIST_HEAD(,proto_tag) tags;
|
||||
LIST_HEAD(,proto_md) mds;
|
||||
bus_dma_tag_t bd_roottag;
|
||||
struct sx sxlck;
|
||||
};
|
||||
|
||||
struct proto_busdma *proto_busdma_attach(struct proto_softc *);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*-
|
||||
* Copyright (c) 2014, 2015 Marcel Moolenaar
|
||||
* Copyright (c) 2014, 2015, 2019 Marcel Moolenaar
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -184,6 +184,7 @@ proto_attach(device_t dev)
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
sc->sc_dev = dev;
|
||||
mtx_init(&sc->sc_mtx, "proto-softc", NULL, MTX_DEF);
|
||||
|
||||
for (res = 0; res < sc->sc_rescnt; res++) {
|
||||
r = sc->sc_res + res;
|
||||
@ -231,15 +232,16 @@ proto_detach(device_t dev)
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
/* Don't detach if we have open device files. */
|
||||
for (res = 0; res < sc->sc_rescnt; res++) {
|
||||
r = sc->sc_res + res;
|
||||
if (r->r_opened)
|
||||
return (EBUSY);
|
||||
}
|
||||
mtx_lock(&sc->sc_mtx);
|
||||
if (sc->sc_opencnt == 0)
|
||||
sc->sc_opencnt = -1;
|
||||
mtx_unlock(&sc->sc_mtx);
|
||||
if (sc->sc_opencnt > 0)
|
||||
return (EBUSY);
|
||||
|
||||
for (res = 0; res < sc->sc_rescnt; res++) {
|
||||
r = sc->sc_res + res;
|
||||
|
||||
switch (r->r_type) {
|
||||
case SYS_RES_IRQ:
|
||||
/* XXX TODO */
|
||||
@ -252,21 +254,25 @@ proto_detach(device_t dev)
|
||||
break;
|
||||
case SYS_RES_MEMORY:
|
||||
case SYS_RES_IOPORT:
|
||||
destroy_dev(r->r_u.cdev);
|
||||
bus_release_resource(dev, r->r_type, r->r_rid,
|
||||
r->r_d.res);
|
||||
destroy_dev(r->r_u.cdev);
|
||||
break;
|
||||
case PROTO_RES_PCICFG:
|
||||
destroy_dev(r->r_u.cdev);
|
||||
break;
|
||||
case PROTO_RES_BUSDMA:
|
||||
proto_busdma_detach(sc, r->r_d.busdma);
|
||||
destroy_dev(r->r_u.cdev);
|
||||
proto_busdma_detach(sc, r->r_d.busdma);
|
||||
break;
|
||||
}
|
||||
r->r_type = PROTO_RES_UNUSED;
|
||||
}
|
||||
mtx_lock(&sc->sc_mtx);
|
||||
sc->sc_rescnt = 0;
|
||||
sc->sc_opencnt = 0;
|
||||
mtx_unlock(&sc->sc_mtx);
|
||||
mtx_destroy(&sc->sc_mtx);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -278,11 +284,23 @@ static int
|
||||
proto_open(struct cdev *cdev, int oflags, int devtype, struct thread *td)
|
||||
{
|
||||
struct proto_res *r;
|
||||
struct proto_softc *sc;
|
||||
int error;
|
||||
|
||||
r = cdev->si_drv2;
|
||||
if (!atomic_cmpset_acq_ptr(&r->r_opened, 0UL, (uintptr_t)td->td_proc))
|
||||
return (EBUSY);
|
||||
return (0);
|
||||
sc = cdev->si_drv1;
|
||||
mtx_lock(&sc->sc_mtx);
|
||||
if (sc->sc_opencnt >= 0) {
|
||||
r = cdev->si_drv2;
|
||||
if (!r->r_opened) {
|
||||
r->r_opened = 1;
|
||||
sc->sc_opencnt++;
|
||||
error = 0;
|
||||
} else
|
||||
error = EBUSY;
|
||||
} else
|
||||
error = ENXIO;
|
||||
mtx_unlock(&sc->sc_mtx);
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -290,14 +308,24 @@ proto_close(struct cdev *cdev, int fflag, int devtype, struct thread *td)
|
||||
{
|
||||
struct proto_res *r;
|
||||
struct proto_softc *sc;
|
||||
int error;
|
||||
|
||||
sc = cdev->si_drv1;
|
||||
r = cdev->si_drv2;
|
||||
if (!atomic_cmpset_acq_ptr(&r->r_opened, (uintptr_t)td->td_proc, 0UL))
|
||||
return (ENXIO);
|
||||
if (r->r_type == PROTO_RES_BUSDMA)
|
||||
proto_busdma_cleanup(sc, r->r_d.busdma);
|
||||
return (0);
|
||||
mtx_lock(&sc->sc_mtx);
|
||||
if (sc->sc_opencnt > 0) {
|
||||
r = cdev->si_drv2;
|
||||
if (r->r_opened) {
|
||||
if (r->r_type == PROTO_RES_BUSDMA)
|
||||
proto_busdma_cleanup(sc, r->r_d.busdma);
|
||||
r->r_opened = 0;
|
||||
sc->sc_opencnt--;
|
||||
error = 0;
|
||||
} else
|
||||
error = ENXIO;
|
||||
} else
|
||||
error = ENXIO;
|
||||
mtx_unlock(&sc->sc_mtx);
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
|
Loading…
Reference in New Issue
Block a user