aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/pccbb
diff options
context:
space:
mode:
authorWarner Losh <imp@FreeBSD.org>2015-01-14 05:41:33 +0000
committerWarner Losh <imp@FreeBSD.org>2015-01-14 05:41:33 +0000
commit8b91d5b0086f455a70b1afe8122462766f382cab (patch)
tree03e8b75d5622afe91bdb056f1cb7eeafb54a1f89 /sys/dev/pccbb
parent8bf007e1e6a9d5b82ff18016bf9ca15e5f64671b (diff)
Notes
Diffstat (limited to 'sys/dev/pccbb')
-rw-r--r--sys/dev/pccbb/pccbb.c108
-rw-r--r--sys/dev/pccbb/pccbb_isa.c18
-rw-r--r--sys/dev/pccbb/pccbb_pci.c84
-rw-r--r--sys/dev/pccbb/pccbbvar.h2
4 files changed, 112 insertions, 100 deletions
diff --git a/sys/dev/pccbb/pccbb.c b/sys/dev/pccbb/pccbb.c
index 08ff42772ee34..77a9725026724 100644
--- a/sys/dev/pccbb/pccbb.c
+++ b/sys/dev/pccbb/pccbb.c
@@ -477,7 +477,7 @@ cbb_event_thread(void *arg)
*/
mtx_lock(&Giant);
status = cbb_get(sc, CBB_SOCKET_STATE);
- DPRINTF(("Status is 0x%x\n", status));
+ DEVPRINTF((sc->dev, "Status is %#x\n", status));
if (!CBB_CARD_PRESENT(status)) {
not_a_card = 0; /* We know card type */
cbb_removal(sc);
@@ -800,13 +800,14 @@ 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) &&
@@ -816,19 +817,18 @@ 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. We need not do this for
- * "off" since we don't touch the card after we turn it off.
+ * 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.
*/
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,26 +838,27 @@ 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
- * (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.
+ * 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.
*
- * NB: Topic95B doesn't set the power cycle bit. we assume that
- * both it and the TOPIC95 behave the same.
+ * 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.
*/
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\n");
+ device_printf(sc->dev, "Bad Vcc requested status %#x %dV\n",
+ status, volts);
/*
* Turn off the power, and try again. Retrigger other
* active interrupts via force register. From NetBSD
@@ -1563,61 +1564,6 @@ cbb_write_ivar(device_t brdev, device_t child, int which, uintptr_t value)
}
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);
diff --git a/sys/dev/pccbb/pccbb_isa.c b/sys/dev/pccbb/pccbb_isa.c
index c511062510556..ed31bd06c8329 100644
--- a/sys/dev/pccbb/pccbb_isa.c
+++ b/sys/dev/pccbb/pccbb_isa.c
@@ -203,13 +203,27 @@ 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_suspend),
- DEVMETHOD(device_resume, cbb_resume),
+ DEVMETHOD(device_suspend, cbb_isa_suspend),
+ DEVMETHOD(device_resume, cbb_isa_resume),
/* bus methods */
DEVMETHOD(bus_read_ivar, cbb_read_ivar),
diff --git a/sys/dev/pccbb/pccbb_pci.c b/sys/dev/pccbb/pccbb_pci.c
index 7b4727cc3e7a4..15d382dafe6c9 100644
--- a/sys/dev/pccbb/pccbb_pci.c
+++ b/sys/dev/pccbb/pccbb_pci.c
@@ -301,6 +301,41 @@ 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)
{
@@ -345,11 +380,9 @@ 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);
@@ -427,17 +460,7 @@ cbb_pci_attach(device_t brdev)
goto err;
}
- /* 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));
+ cbb_pci_bridge_init(brdev);
if (bootverbose)
cbb_print_config(brdev);
@@ -877,14 +900,45 @@ cbb_write_config(device_t brdev, u_int b, u_int s, u_int f, u_int reg, uint32_t
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_suspend),
- DEVMETHOD(device_resume, cbb_resume),
+ DEVMETHOD(device_suspend, cbb_pci_suspend),
+ DEVMETHOD(device_resume, cbb_pci_resume),
/* bus methods */
DEVMETHOD(bus_read_ivar, cbb_read_ivar),
diff --git a/sys/dev/pccbb/pccbbvar.h b/sys/dev/pccbb/pccbbvar.h
index c3e2d24b14c69..f19b933ba2de2 100644
--- a/sys/dev/pccbb/pccbbvar.h
+++ b/sys/dev/pccbb/pccbbvar.h
@@ -134,11 +134,9 @@ int cbb_read_ivar(device_t brdev, device_t child, int which,
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,