# HG changeset patch # Parent c3a8c6186fadbe0ba8ada6e02f5e165551edfe63 Cache a copy of the CIS when we're parsing it for use by /dev/pccardX so we don't run into races between the configuration thread and users of /dev/pccardX diff -r c3a8c6186fad -r cd77d1bab8d9 sys/dev/pccard/pccard.c --- a/sys/dev/pccard/pccard.c +++ b/sys/dev/pccard/pccard.c @@ -246,6 +246,10 @@ pccard_attach_card(device_t dev) pf->dev = child; pccard_probe_and_attach_child(dev, child, pf); } + + DEVPRINTF((dev, "stash CIS for /dev/card\n")); + pccard_device_card_attached(sc); + return (0); } @@ -357,6 +361,9 @@ pccard_detach_card(device_t dev) free(pf, M_DEVBUF); } STAILQ_INIT(&sc->card.pf_head); + + pccard_device_card_detached(sc); + return (0); } diff -r c3a8c6186fad -r cd77d1bab8d9 sys/dev/pccard/pccard_device.c --- a/sys/dev/pccard/pccard_device.c +++ b/sys/dev/pccard/pccard_device.c @@ -58,26 +58,6 @@ static struct cdevsw pccard_cdevsw = { .d_name = "pccard" }; -int -pccard_device_create(struct pccard_softc *sc) -{ - uint32_t minor; - - minor = device_get_unit(sc->dev) << 16; - sc->cisdev = make_dev(&pccard_cdevsw, minor, 0, 0, 0666, - "pccard%u.cis", device_get_unit(sc->dev)); - sc->cisdev->si_drv1 = sc; - return (0); -} - -int -pccard_device_destroy(struct pccard_softc *sc) -{ - if (sc->cisdev) - destroy_dev(sc->cisdev); - return (0); -} - static int pccard_build_cis(const struct pccard_tuple *tuple, void *argp) { @@ -106,36 +86,78 @@ pccard_build_cis(const struct pccard_tup return (0); } -static int -pccard_open(struct cdev *dev, int oflags, int devtype, struct thread *td) +int +pccard_device_card_attached(struct pccard_softc *sc) { device_t parent, child; device_t *kids; int cnt, err; + + /* + * If there's no children, there's no CIS to read. + */ + parent = sc->dev; + err = device_get_children(parent, &kids, &cnt); + if (err) { + pccard_device_destroy(sc); + return err; + } + child = kids[0]; + free(kids, M_TEMP); + if (cnt == 0) + return 0; + + /* + * Read the CIS when we make the device to avoid racing with + * other things. The device creation will serialize access + * since it is done as part of a single-threaded config + * process. + */ + sc->cis = malloc(sizeof(*sc->cis), M_TEMP, M_ZERO | M_WAITOK); + err = pccard_scan_cis(parent, child, pccard_build_cis, sc->cis); + if (err) { + free(sc->cis, M_TEMP); + sc->cis = NULL; + } + return (err); +} + +int +pccard_device_card_detached(struct pccard_softc *sc) +{ + free(sc->cis, M_TEMP); + sc->cis = NULL; + return 0; +} + +int +pccard_device_create(struct pccard_softc *sc) +{ + uint32_t minor; + + minor = device_get_unit(sc->dev) << 16; + sc->cisdev = make_dev(&pccard_cdevsw, minor, 0, 0, 0666, + "pccard%u.cis", device_get_unit(sc->dev)); + sc->cisdev->si_drv1 = sc; + return 0; +} + +int +pccard_device_destroy(struct pccard_softc *sc) +{ + if (sc->cisdev) + destroy_dev(sc->cisdev); + return (0); +} + +static int +pccard_open(struct cdev *dev, int oflags, int devtype, struct thread *td) +{ struct pccard_softc *sc; sc = dev->si_drv1; if (sc->cis_open) return (EBUSY); - parent = sc->dev; - err = device_get_children(parent, &kids, &cnt); - if (err) - return err; - if (cnt == 0) { - free(kids, M_TEMP); - sc->cis_open++; - sc->cis = NULL; - return (0); - } - child = kids[0]; - free(kids, M_TEMP); - sc->cis = malloc(sizeof(*sc->cis), M_TEMP, M_ZERO | M_WAITOK); - err = pccard_scan_cis(parent, child, pccard_build_cis, sc->cis); - if (err) { - free(sc->cis, M_TEMP); - sc->cis = NULL; - return (err); - } sc->cis_open++; return (0); } @@ -146,8 +168,6 @@ pccard_close(struct cdev *dev, int fflag struct pccard_softc *sc; sc = dev->si_drv1; - free(sc->cis, M_TEMP); - sc->cis = NULL; sc->cis_open = 0; return (0); } diff -r c3a8c6186fad -r cd77d1bab8d9 sys/dev/pccard/pccardvarp.h --- a/sys/dev/pccard/pccardvarp.h +++ b/sys/dev/pccard/pccardvarp.h @@ -189,6 +189,8 @@ void pccard_check_cis_quirks(device_t); void pccard_print_cis(device_t); int pccard_scan_cis(device_t, device_t, pccard_scan_t, void *); +int pccard_device_card_attached(struct pccard_softc *); +int pccard_device_card_detached(struct pccard_softc *); int pccard_device_create(struct pccard_softc *); int pccard_device_destroy(struct pccard_softc *);