diff options
author | Mark Johnston <markj@FreeBSD.org> | 2021-11-25 16:27:49 +0000 |
---|---|---|
committer | Mark Johnston <markj@FreeBSD.org> | 2021-11-25 16:36:33 +0000 |
commit | 437ea82ce7fc3e664447b9e7d08f5c135a7e2f31 (patch) | |
tree | 2821409200f31db875d1f5a9a52c588a119cd68b | |
parent | 52d973f52c07b94909a6487be373c269988dc151 (diff) | |
download | src-437ea82ce7fc3e664447b9e7d08f5c135a7e2f31.tar.gz src-437ea82ce7fc3e664447b9e7d08f5c135a7e2f31.zip |
agp: Handle multiple devices more gracefully
Currently agp(4) effectively assumes that only one driver instance
exists, as the generic attach routine attempts to create /dev/agpgart
and triggers a panic if it already exists. Instead, handle this
situation by creating /dev/agpgart<unit> and making /dev/agpgart an
alias of /dev/agpgart0 for compatibility.
PR: 187015
Reviewed by: imp, kib
Tested by: Yoshihiro Ota <ota@j.email.ne.jp> (earlier version)
MFC after: 1 week
Differential Revision: https://reviews.freebsd.org/D33068
-rw-r--r-- | sys/dev/agp/agp.c | 33 | ||||
-rw-r--r-- | sys/dev/agp/agppriv.h | 1 |
2 files changed, 29 insertions, 5 deletions
diff --git a/sys/dev/agp/agp.c b/sys/dev/agp/agp.c index aaae2176f85a..39e9d5dd64e7 100644 --- a/sys/dev/agp/agp.c +++ b/sys/dev/agp/agp.c @@ -205,8 +205,9 @@ agp_set_aperture_resource(device_t dev, int rid) int agp_generic_attach(device_t dev) { + struct make_dev_args mdargs; struct agp_softc *sc = device_get_softc(dev); - int i; + int error, i, unit; u_int memsize; /* @@ -250,11 +251,31 @@ agp_generic_attach(device_t dev) TAILQ_INIT(&sc->as_memory); sc->as_nextid = 1; - sc->as_devnode = make_dev(&agp_cdevsw, - 0, UID_ROOT, GID_WHEEL, 0600, "agpgart"); - sc->as_devnode->si_drv1 = dev; + sc->as_devalias = NULL; - return 0; + make_dev_args_init(&mdargs); + mdargs.mda_devsw = &agp_cdevsw; + mdargs.mda_uid = UID_ROOT; + mdargs.mda_gid = GID_WHEEL; + mdargs.mda_mode = 0600; + mdargs.mda_si_drv1 = sc; + mdargs.mda_si_drv2 = NULL; + + unit = device_get_unit(dev); + error = make_dev_s(&mdargs, &sc->as_devnode, "agpgart%d", unit); + if (error == 0) { + /* + * Create an alias for the first device that shows up. + */ + if (unit == 0) { + (void)make_dev_alias_p(MAKEDEV_CHECKNAME, + &sc->as_devalias, sc->as_devnode, "agpgart"); + } + } else { + agp_free_res(dev); + } + + return error; } void @@ -263,6 +284,8 @@ agp_free_cdev(device_t dev) struct agp_softc *sc = device_get_softc(dev); destroy_dev(sc->as_devnode); + if (sc->as_devalias != NULL) + destroy_dev(sc->as_devalias); } void diff --git a/sys/dev/agp/agppriv.h b/sys/dev/agp/agppriv.h index f6fa3c5526bd..525f4bced245 100644 --- a/sys/dev/agp/agppriv.h +++ b/sys/dev/agp/agppriv.h @@ -76,6 +76,7 @@ struct agp_softc { int as_nextid; /* next memory block id */ int as_isopen; /* user device is open */ struct cdev *as_devnode; /* from make_dev */ + struct cdev *as_devalias; struct mtx as_lock; /* lock for access to GATT */ }; |