svn commit: r277232 - head/sys/dev/pccbb

Warner Losh imp at FreeBSD.org
Fri Jan 16 06:19:10 UTC 2015


Author: imp
Date: Fri Jan 16 06:19:08 2015
New Revision: 277232
URL: https://svnweb.freebsd.org/changeset/base/277232

Log:
  Back out the refactor. It turns out to cause interrupt storms on
  resume sometimes (but not others). On powerup, other wierd issues show
  up (sometimes the card comes up, but with really bogus pci config
  space stuff. There may be more, but given my experience of historical
  fussiness, stick to what works and make more minimal changes to that.

Modified:
  head/sys/dev/pccbb/pccbb.c
  head/sys/dev/pccbb/pccbb_isa.c
  head/sys/dev/pccbb/pccbb_pci.c
  head/sys/dev/pccbb/pccbbvar.h

Modified: head/sys/dev/pccbb/pccbb.c
==============================================================================
--- head/sys/dev/pccbb/pccbb.c	Fri Jan 16 06:19:05 2015	(r277231)
+++ head/sys/dev/pccbb/pccbb.c	Fri Jan 16 06:19:08 2015	(r277232)
@@ -477,7 +477,7 @@ cbb_event_thread(void *arg)
 		 */
 		mtx_lock(&Giant);
 		status = cbb_get(sc, CBB_SOCKET_STATE);
-		DEVPRINTF((sc->dev, "Status is %#x\n", status));
+		DPRINTF(("Status is 0x%x\n", status));
 		if (!CBB_CARD_PRESENT(status)) {
 			not_a_card = 0;		/* We know card type */
 			cbb_removal(sc);
@@ -800,14 +800,13 @@ cbb_power(device_t brdev, int volts)
 	if (on) {
 		mtx_lock(&sc->mtx);
 		cnt = sc->powerintr;
-
 		/*
 		 * We have a shortish timeout of 500ms here.  Some bridges do
-		 * not generate a POWER_CYCLE event for 16-bit cards.  In those
-		 * cases, we have to cope the best we can, and having only a
-		 * short delay is better than the alternatives.  Others raise
-		 * the power cycle a smidge before it is really ready.  We deal
-		 * with those below.
+		 * not generate a POWER_CYCLE event for 16-bit cards.  In
+		 * those cases, we have to cope the best we can, and having
+		 * only a short delay is better than the alternatives.  Others
+		 * raise the power cycle a smidge before it is really ready.
+		 * We deal with those below.
 		 */
 		sane = 10;
 		while (!(cbb_get(sc, CBB_SOCKET_STATE) & CBB_STATE_POWER_CYCLE) &&
@@ -817,18 +816,19 @@ cbb_power(device_t brdev, int volts)
 
 		/*
 		 * Relax for 100ms.  Some bridges appear to assert this signal
-		 * right away, but before the card has stabilized.  Other cards
-		 * need need more time to cope up reliabily.  Experiments with
-		 * troublesome setups show this to be a "cheap" way to enhance
-		 * reliabilty.
+		 * right away, but before the card has stabilized.  Other
+		 * cards need need more time to cope up reliabily.
+		 * Experiments with troublesome setups show this to be a
+		 * "cheap" way to enhance reliabilty.  We need not do this for
+		 * "off" since we don't touch the card after we turn it off.
 		 */
 		pause("cbbPwr", min(hz / 10, 1));
 
 		/*
-		 * The TOPIC95B requires a little bit extra time to get its act
-		 * together, so delay for an additional 100ms.  Also as
-		 * documented below, it doesn't seem to set the POWER_CYCLE bit,
-		 * so don't whine if it never came on.
+		 * The TOPIC95B requires a little bit extra time to get its
+		 * act together, so delay for an additional 100ms.  Also as
+		 * documented below, it doesn't seem to set the POWER_CYCLE
+		 * bit, so don't whine if it never came on.
 		 */
 		if (sc->chipset == CB_TOPIC95)
 			pause("cbb95B", hz / 10);
@@ -838,27 +838,26 @@ cbb_power(device_t brdev, int volts)
 
 	/*
 	 * After the power is good, we can turn off the power interrupt.
-	 * However, the PC Card standard says that we must delay turning the CD
-	 * bit back on for a bit to allow for bouncyness on power down. We just
-	 * pause a little below to cover that. Most bridges don't seem to need
-	 * this delay.
+	 * However, the PC Card standard says that we must delay turning the
+	 * CD bit back on for a bit to allow for bouncyness on power down
+	 * (recall that we don't wait above for a power down, since we don't
+	 * get an interrupt for that).  We're called either from the suspend
+	 * code in which case we don't want to turn card change on again, or
+	 * we're called from the card insertion code, in which case the cbb
+	 * thread will turn it on for us before it waits to be woken by a
+	 * change event.
 	 *
-	 * NB: Topic95B doesn't set the power cycle bit.  We assume that
-	 * both it and the TOPIC95 behave the same, though despite efforts
-	 * to find one, the author never could locate a laptop with a TOPIC95
-	 * in it.
+	 * NB: Topic95B doesn't set the power cycle bit.  we assume that
+	 * both it and the TOPIC95 behave the same.
 	 */
 	cbb_clrb(sc, CBB_SOCKET_MASK, CBB_SOCKET_MASK_POWER);
 	status = cbb_get(sc, CBB_SOCKET_STATE);
 	if (on && sc->chipset != CB_TOPIC95) {
 		if ((status & CBB_STATE_POWER_CYCLE) == 0)
 			device_printf(sc->dev, "Power not on?\n");
-	} else {
-		pause("cbbDwn", hz / 10);
 	}
 	if (status & CBB_STATE_BAD_VCC_REQ) {
-		device_printf(sc->dev, "Bad Vcc requested status %#x %dV\n",
-		    status, volts);	
+		device_printf(sc->dev, "Bad Vcc requested\n");	
 		/*
 		 * Turn off the power, and try again.  Retrigger other
 		 * active interrupts via force register.  From NetBSD
@@ -1564,6 +1563,61 @@ cbb_write_ivar(device_t brdev, device_t 
 }
 
 int
+cbb_suspend(device_t self)
+{
+	int			error = 0;
+	struct cbb_softc	*sc = device_get_softc(self);
+
+	error = bus_generic_suspend(self);
+	if (error != 0)
+		return (error);
+	cbb_set(sc, CBB_SOCKET_MASK, 0);	/* Quiet hardware */
+	sc->cardok = 0;				/* Card is bogus now */
+	return (0);
+}
+
+int
+cbb_resume(device_t self)
+{
+	int	error = 0;
+	struct cbb_softc *sc = (struct cbb_softc *)device_get_softc(self);
+	uint32_t tmp;
+
+	/*
+	 * In the APM and early ACPI era, BIOSes saved the PCI config
+	 * registers. As chips became more complicated, that functionality moved
+	 * into the ACPI code / tables. We must therefore, restore the settings
+	 * we made here to make sure the device come back. Transitions to Dx
+	 * from D0 and back to D0 cause the bridge to lose its config space, so
+	 * all the bus mappings and such are preserved.
+	 *
+	 * For most drivers, the PCI layer handles this saving. However, since
+	 * there's much black magic and arcane art hidden in these few lines of
+	 * code that would be difficult to transition into the PCI
+	 * layer. chipinit was several years of trial and error to write.
+	 */
+	pci_write_config(self, CBBR_SOCKBASE, rman_get_start(sc->base_res), 4);
+	DEVPRINTF((self, "PCI Memory allocated: %08lx\n",
+	    rman_get_start(sc->base_res)));
+
+	sc->chipinit(sc);
+
+	/* reset interrupt -- Do we really need to do this? */
+	tmp = cbb_get(sc, CBB_SOCKET_EVENT);
+	cbb_set(sc, CBB_SOCKET_EVENT, tmp);
+
+	/* CSC Interrupt: Card detect interrupt on */
+	cbb_setb(sc, CBB_SOCKET_MASK, CBB_SOCKET_MASK_CD);
+
+	/* Signal the thread to wakeup. */
+	wakeup(&sc->intrhand);
+
+	error = bus_generic_resume(self);
+
+	return (error);
+}
+
+int
 cbb_child_present(device_t parent, device_t child)
 {
 	struct cbb_softc *sc = (struct cbb_softc *)device_get_softc(parent);

Modified: head/sys/dev/pccbb/pccbb_isa.c
==============================================================================
--- head/sys/dev/pccbb/pccbb_isa.c	Fri Jan 16 06:19:05 2015	(r277231)
+++ head/sys/dev/pccbb/pccbb_isa.c	Fri Jan 16 06:19:08 2015	(r277232)
@@ -203,27 +203,13 @@ cbb_isa_attach(device_t dev)
 	return (ENOMEM);
 }
 
-static int
-cbb_isa_suspend(device_t dev)
-{
-
-	return 0;
-}
-
-static int
-cbb_isa_resume(device_t dev)
-{
-
-	return 0;
-}
-
 static device_method_t cbb_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_probe,			cbb_isa_probe),
 	DEVMETHOD(device_attach,		cbb_isa_attach),
 	DEVMETHOD(device_detach,		cbb_detach),
-	DEVMETHOD(device_suspend,		cbb_isa_suspend),
-	DEVMETHOD(device_resume,		cbb_isa_resume),
+	DEVMETHOD(device_suspend,		cbb_suspend),
+	DEVMETHOD(device_resume,		cbb_resume),
 
 	/* bus methods */
 	DEVMETHOD(bus_read_ivar,		cbb_read_ivar),

Modified: head/sys/dev/pccbb/pccbb_pci.c
==============================================================================
--- head/sys/dev/pccbb/pccbb_pci.c	Fri Jan 16 06:19:05 2015	(r277231)
+++ head/sys/dev/pccbb/pccbb_pci.c	Fri Jan 16 06:19:08 2015	(r277232)
@@ -301,41 +301,6 @@ cbb_print_config(device_t dev)
 	printf("\n");
 }
 
-static void
-cbb_pci_bridge_init(device_t brdev)
-{
-	struct cbb_softc *sc = (struct cbb_softc *)device_get_softc(brdev);
-	u_int32_t membase, irq;
-
-	if (pci_get_powerstate(brdev) != PCI_POWERSTATE_D0) {
-		/* Reset the power state. */
-		device_printf(brdev, "chip is in D%d power mode "
-		    "-- setting to D0\n", pci_get_powerstate(brdev));
-		pci_set_powerstate(brdev, PCI_POWERSTATE_D0);
-	}
-	membase = rman_get_start(sc->base_res);
-	irq = rman_get_start(sc->irq_res);
-
-	pci_write_config(brdev, CBBR_SOCKBASE, membase, 4);
-	pci_write_config(brdev, PCIR_INTLINE, irq, 4);
-	PCI_ENABLE_IO(device_get_parent(brdev), brdev, SYS_RES_MEMORY);
-
-	exca_init(&sc->exca[0], brdev, sc->bst, sc->bsh, CBB_EXCA_OFFSET);
-	sc->chipinit(sc);
-
-	/* reset 16-bit pcmcia bus */
-	exca_clrb(&sc->exca[0], EXCA_INTR, EXCA_INTR_RESET);
-
-	/* turn off power */
-	cbb_power(brdev, CARD_OFF);
-
-	/* CSC Interrupt: Card detect interrupt on */
-	cbb_setb(sc, CBB_SOCKET_MASK, CBB_SOCKET_MASK_CD);
-
-	/* reset interrupt */
-	cbb_set(sc, CBB_SOCKET_EVENT, cbb_get(sc, CBB_SOCKET_EVENT));
-}
-
 static int
 cbb_pci_attach(device_t brdev)
 {
@@ -380,9 +345,11 @@ cbb_pci_attach(device_t brdev)
 
 	sc->bst = rman_get_bustag(sc->base_res);
 	sc->bsh = rman_get_bushandle(sc->base_res);
+	exca_init(&sc->exca[0], brdev, sc->bst, sc->bsh, CBB_EXCA_OFFSET);
 	sc->exca[0].flags |= EXCA_HAS_MEMREG_WIN;
 	sc->exca[0].chipset = EXCA_CARDBUS;
 	sc->chipinit = cbb_chipinit;
+	sc->chipinit(sc);
 
 	/*Sysctls*/
 	sctx = device_get_sysctl_ctx(brdev);
@@ -460,7 +427,17 @@ cbb_pci_attach(device_t brdev)
 		goto err;
 	}
 
-	cbb_pci_bridge_init(brdev);
+	/* reset 16-bit pcmcia bus */
+	exca_clrb(&sc->exca[0], EXCA_INTR, EXCA_INTR_RESET);
+
+	/* turn off power */
+	cbb_power(brdev, CARD_OFF);
+
+	/* CSC Interrupt: Card detect interrupt on */
+	cbb_setb(sc, CBB_SOCKET_MASK, CBB_SOCKET_MASK_CD);
+
+	/* reset interrupt */
+	cbb_set(sc, CBB_SOCKET_EVENT, cbb_get(sc, CBB_SOCKET_EVENT));
 
 	if (bootverbose)
 		cbb_print_config(brdev);
@@ -900,45 +877,14 @@ cbb_write_config(device_t brdev, u_int b
 	    b, s, f, reg, val, width);
 }
 
-static int
-cbb_pci_suspend(device_t brdev)
-{
-	int			error = 0;
-	struct cbb_softc	*sc = device_get_softc(brdev);
-
-	error = bus_generic_suspend(brdev);
-	if (error != 0)
-		return (error);
-	cbb_set(sc, CBB_SOCKET_MASK, 0);	/* Quiet hardware */
-	sc->cardok = 0;				/* Card is bogus now */
-	return (0);
-}
-
-static int
-cbb_pci_resume(device_t brdev)
-{
-	int	error = 0;
-	struct cbb_softc *sc = (struct cbb_softc *)device_get_softc(brdev);
-
-	/* Reinitialize the hardware, ala attach */
-	cbb_pci_bridge_init(brdev);
-
-	/* Signal the thread to wakeup to see if we have any cards to work with. */
-	wakeup(&sc->intrhand);
-
-	error = bus_generic_resume(brdev);
-
-	return (error);
-}
-
 static device_method_t cbb_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_probe,			cbb_pci_probe),
 	DEVMETHOD(device_attach,		cbb_pci_attach),
 	DEVMETHOD(device_detach,		cbb_detach),
 	DEVMETHOD(device_shutdown,		cbb_pci_shutdown),
-	DEVMETHOD(device_suspend,		cbb_pci_suspend),
-	DEVMETHOD(device_resume,		cbb_pci_resume),
+	DEVMETHOD(device_suspend,		cbb_suspend),
+	DEVMETHOD(device_resume,		cbb_resume),
 
 	/* bus methods */
 	DEVMETHOD(bus_read_ivar,		cbb_read_ivar),

Modified: head/sys/dev/pccbb/pccbbvar.h
==============================================================================
--- head/sys/dev/pccbb/pccbbvar.h	Fri Jan 16 06:19:05 2015	(r277231)
+++ head/sys/dev/pccbb/pccbbvar.h	Fri Jan 16 06:19:08 2015	(r277232)
@@ -134,9 +134,11 @@ int	cbb_read_ivar(device_t brdev, device
 	    uintptr_t *result);
 int	cbb_release_resource(device_t brdev, device_t child,
 	    int type, int rid, struct resource *r);
+int	cbb_resume(device_t self);
 int	cbb_setup_intr(device_t dev, device_t child, struct resource *irq,
 	    int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg,
 	    void **cookiep);
+int	cbb_suspend(device_t self);
 int	cbb_teardown_intr(device_t dev, device_t child, struct resource *irq,
 	    void *cookie);
 int	cbb_write_ivar(device_t brdev, device_t child, int which,


More information about the svn-src-all mailing list