Subject: Re: PnP weirdness
To: None <is@jocelyn.rhein.de>
From: Chris Torek <torek@BSDI.COM>
List: tech-kern
Date: 08/05/1998 10:29:40
>... we see the logical boards next to each other ...
>I guess there is no method to attach a device instance two (or
>more) parent devices at the same time, right?

Right.  The "esp" driver on the SPARC has the same problem, in some
configurations: the "dma" and "esp" chips, which work in tandem,
are listed separately on the sbus.  (In other configurations they
are chained together, and as an "fas" on an Ultrasparc, you get
one device with two register sets, rather than two separate devices,
from the PROM -- but there are still those sun4c's out there with
separate "esp" and "dma".)

There is no general solution, and I do not think there can be one,
because there are too many ways people can build broken hardware.

In the esp driver, the code (well, mine anyway) ends up doing this
at the end of espattach():

	/*
	 * Try to pair up with the appropriate DMA registers.  This is
	 * easy if we have them here ("fas" devices) or are a child of
	 * an espdma, but if we are an esp and a child of the sbus, we
	 * must search for a "dma" device in the same Sbus slot, and it
	 * might not have been configured yet.
	 */
	if (dma != NULL) {
		/* DMA is on-chip; construct a local (fake) dma_softc. */
		dc = malloc(sizeof *dc, M_DEVBUF, M_WAITOK);
		dc->dc_dev = sc->sc_dev;	/* close enough */
		dc->dc_dma = dma;
		dc->dc_rev = DMA_REV(dma->dma_csr);
		dc->dc_fmt = DMA_HME_BITS;
		aprint_debug("%s (fas): DMA rev = 0x%x (expecting 0x%x)\n",
		    sc->sc_dev.dv_xname, dc->dc_rev, DMAREV_HME);
	} else if (parent_is_sbus) {
		/* Search for same-slot DMA. */
		for (t = 0;; t++) {
			if (t >= dmacd.cd_ndevs)
				return;
			if ((ed = dmacd.cd_devs[t]) != NULL &&
			    ed->ed_dc.dc_dev.dv_parent == parent &&
			    ed->ed_slot == sc->sc_slot) {
				dc = &ed->ed_dc;
				break;
			}
		}
	} else {
		/* Parent device is the DMA chip. */
		dc = (struct dma_softc *)parent;
	}
	esp_probe(sc, dc);

The dmaattach() code also has a similar loop:

	/* Check for "old-style" esp (see espattach()). */
	for (unit = 0; unit < espcd.cd_ndevs; unit++) {
		if ((sc = espcd.cd_devs[unit]) != NULL &&
		    sc->sc_dev.dv_parent == parent &&
		    sc->sc_slot == slot &&
		    sc->sc_dc == NULL) {
			esp_probe(sc, &ed->ed_dc);
			break;
		}
	}

Here the driver matches "esp" and "dma" chips by sbus slot, this
being the most bullet-proof method I could think of.

Chris