summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorimp <imp@FreeBSD.org>2005-07-17 07:48:28 +0000
committerimp <imp@FreeBSD.org>2005-07-17 07:48:28 +0000
commit138abbd8431c1b32c758c1ba319651eaee5060bd (patch)
tree466533f39c50fceb5e835957a72a291282f07019
parenta519d1b3a07c559097431d2cc0ed72f0995301f5 (diff)
downloadFreeBSD-src-138abbd8431c1b32c758c1ba319651eaee5060bd.zip
FreeBSD-src-138abbd8431c1b32c758c1ba319651eaee5060bd.tar.gz
The CD interrupt should only be enabled after we've initialized the
card. Mask it while we're doing power things, as the PC Card standard suggests. Also, poll the POWER_CYCLE bit 10x a second as well as providing a timeout for power cycle interrupt to happen. The Ricoh '475 that I have doesn't seem to generate an interrupt for power at the present time, so the polling is necessary for reasons as yet unknown. This results in an interrupt storm warning that I'm still trying to quantify (the o2micro trick doesn't work to mitigate this storm). At the very least, this should help those users that lost pccards on boot with the prior rev of this code. My VAIO PCG-505TS is now happier, but more investigation is necessary.
-rw-r--r--sys/dev/pccbb/pccbb.c48
1 files changed, 38 insertions, 10 deletions
diff --git a/sys/dev/pccbb/pccbb.c b/sys/dev/pccbb/pccbb.c
index 4b32983..e34b2da 100644
--- a/sys/dev/pccbb/pccbb.c
+++ b/sys/dev/pccbb/pccbb.c
@@ -536,6 +536,9 @@ cbb_insert(struct cbb_softc *sc)
if (sc->exca[0].pccarddev) {
sc->flags |= CBB_16BIT_CARD;
exca_insert(&sc->exca[0]);
+ } else {
+ device_printf(sc->dev,
+ "16-bit card inserted, but no pccard bus.\n");
}
} else if (sockstate & CBB_STATE_CB_CARD) {
if (sc->cbdev != NULL) {
@@ -621,13 +624,10 @@ cbb_intr(void *arg)
struct cbb_softc *sc = arg;
uint32_t sockevent;
- /*
- * This ISR needs work XXX
- */
sockevent = cbb_get(sc, CBB_SOCKET_EVENT);
if (sockevent != 0) {
/* ack the interrupt */
- cbb_setb(sc, CBB_SOCKET_EVENT, sockevent);
+ cbb_set(sc, CBB_SOCKET_EVENT, sockevent);
/*
* If anything has happened to the socket, we assume that
@@ -729,6 +729,9 @@ cbb_o2micro_power_hack(struct cbb_softc *sc)
* Selecting IRQ1 will result in INT# NOT being asserted
* (because IRQ1 is selected), and IRQ1 won't be asserted
* because our controllers don't generate IRQ1.
+ *
+ * Other, non O2Micro controllers will generate irq 1 in some
+ * situations, so we can't do this hack for everybody.
*/
reg = exca_getb(&sc->exca[0], EXCA_INTR);
exca_putb(&sc->exca[0], EXCA_INTR, (reg & 0xf0) | 1);
@@ -749,9 +752,9 @@ cbb_o2micro_power_hack2(struct cbb_softc *sc, uint8_t reg)
int
cbb_power(device_t brdev, int volts)
{
- uint32_t status, sock_ctrl;
+ uint32_t status, sock_ctrl, mask;
struct cbb_softc *sc = device_get_softc(brdev);
- int cnt;
+ int cnt, sane;
int retval = 0;
int on = 0;
uint8_t reg = 0;
@@ -792,16 +795,40 @@ cbb_power(device_t brdev, int volts)
if (volts != 0 && sc->chipset == CB_O2MICRO)
reg = cbb_o2micro_power_hack(sc);
- cbb_setb(sc, CBB_SOCKET_MASK, CBB_SOCKET_MASK_POWER);
+ /*
+ * We have to mask the card change detect interrupt while we're
+ * messing with the power. It is allowed to bounce while we're
+ * messing with power as things settle down.
+ */
+ mask = cbb_get(sc, CBB_SOCKET_MASK);
+ mask |= CBB_SOCKET_MASK_POWER;
+ mask &= ~CBB_SOCKET_MASK_CD;
+ cbb_set(sc, CBB_SOCKET_MASK, mask);
cbb_set(sc, CBB_SOCKET_CONTROL, sock_ctrl);
if (on) {
mtx_lock(&sc->mtx);
cnt = sc->powerintr;
- /* XXX timeout needed! */
- while (cnt == sc->powerintr)
- cv_wait(&sc->powercv, &sc->mtx);
+ sane = 200;
+ while (!(cbb_get(sc, CBB_SOCKET_STATE) & CBB_STATE_POWER_CYCLE) &&
+ cnt == sc->powerintr && sane-- > 0)
+ cv_timedwait(&sc->powercv, &sc->mtx, hz / 10);
mtx_unlock(&sc->mtx);
+ if (sane <= 0)
+ device_printf(sc->dev, "power timeout, doom?\n");
}
+
+ /*
+ * 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.
+ */
cbb_clrb(sc, CBB_SOCKET_MASK, CBB_SOCKET_MASK_POWER);
status = cbb_get(sc, CBB_SOCKET_STATE);
if (on) {
@@ -810,6 +837,7 @@ cbb_power(device_t brdev, int volts)
}
if (status & CBB_STATE_BAD_VCC_REQ) {
device_printf(sc->dev, "Bad Vcc requested\n");
+ /* XXX Do we want to do something to mitigate things here? */
goto done;
}
retval = 1;
OpenPOWER on IntegriCloud