summaryrefslogtreecommitdiffstats
path: root/sys/dev/pccbb
diff options
context:
space:
mode:
authorimp <imp@FreeBSD.org>2008-08-09 04:08:36 +0000
committerimp <imp@FreeBSD.org>2008-08-09 04:08:36 +0000
commitc6148dd1b68274a665db7661a9540f9b399c829d (patch)
treed444c2c598bdc399e1b8fdf97ee61067804bf09c /sys/dev/pccbb
parenta61fcd56a5cc6c9fde0f8d920ed94d0d2fef4d79 (diff)
downloadFreeBSD-src-c6148dd1b68274a665db7661a9540f9b399c829d.zip
FreeBSD-src-c6148dd1b68274a665db7661a9540f9b399c829d.tar.gz
Rather than waiting a fixed amount of time, which might not be enough
and also holds things up, check every 20ms to see if we can read the vendor of device 0.0. It will be 0xffffffff until the card is out of reset. Always wait at least 20ms, for safety. I think this is a better fix to the reset problem. However, I did it as a separate commit in case something bad happens, people can roll back to the commit before this one to see if that gives them reliable behavior. I don't have FreeBSD up on enough machines to do exhaustive testing on all known bridges...
Diffstat (limited to 'sys/dev/pccbb')
-rw-r--r--sys/dev/pccbb/pccbb.c35
1 files changed, 23 insertions, 12 deletions
diff --git a/sys/dev/pccbb/pccbb.c b/sys/dev/pccbb/pccbb.c
index e45d608..f5a3b74 100644
--- a/sys/dev/pccbb/pccbb.c
+++ b/sys/dev/pccbb/pccbb.c
@@ -158,7 +158,7 @@ SYSCTL_ULONG(_hw_cbb, OID_AUTO, debug, CTLFLAG_RW, &cbb_debug, 0,
static void cbb_insert(struct cbb_softc *sc);
static void cbb_removal(struct cbb_softc *sc);
static uint32_t cbb_detect_voltage(device_t brdev);
-static void cbb_cardbus_reset(device_t brdev);
+static void cbb_cardbus_reset(device_t brdev, int on);
static int cbb_cardbus_io_open(device_t brdev, int win, uint32_t start,
uint32_t end);
static int cbb_cardbus_mem_open(device_t brdev, int win,
@@ -927,27 +927,38 @@ cbb_do_power(device_t brdev)
/************************************************************************/
static void
-cbb_cardbus_reset(device_t brdev)
+cbb_cardbus_reset(device_t brdev, int on)
{
struct cbb_softc *sc = device_get_softc(brdev);
- int delay;
+ uint32_t b;
+ int delay, count;
/*
- * 100ms is necessary for most bridges. For some reason, the Ricoh
- * RF5C47x bridges need 400ms. The spec says 20ms, but even some
- * normally sane bridges need longer with some cards.
+ * 20ms is necessary for most bridges. For some reason, the Ricoh
+ * RF5C47x bridges need 400ms.
*/
- delay = sc->chipset == CB_RF5C47X ? 400 : 100;
+ delay = sc->chipset == CB_RF5C47X ? 400 : 20;
PCI_MASK_CONFIG(brdev, CBBR_BRIDGECTRL, |CBBM_BRIDGECTRL_RESET, 2);
pause("cbbP3", hz * delay / 1000);
- /* If a card exists, unreset it! */
- if (CBB_CARD_PRESENT(cbb_get(sc, CBB_SOCKET_STATE))) {
+ /* If a card exists and we're turning it on, unreset it! */
+ if (on && CBB_CARD_PRESENT(cbb_get(sc, CBB_SOCKET_STATE))) {
PCI_MASK_CONFIG(brdev, CBBR_BRIDGECTRL,
&~CBBM_BRIDGECTRL_RESET, 2);
- pause("cbbP4", hz * delay / 1000);
+ /*
+ * Wait up to .5s for the vendor of device 0.0 to become
+ * != 0xffffffff
+ */
+ b = pcib_get_bus(brdev);
+ count = 25;
+ do {
+ pause("cbbP4", hz * 2 / 100);
+ } while (PCIB_READ_CONFIG(brdev, b, 0, 0, PCIR_DEVVENDOR, 4) ==
+ 0xfffffffful && --count >= 0);
+ if (count < 0)
+ device_printf(brdev, "Timeout on reset\n");
}
}
@@ -963,7 +974,7 @@ cbb_cardbus_power_enable_socket(device_t brdev, device_t child)
err = cbb_do_power(brdev);
if (err)
return (err);
- cbb_cardbus_reset(brdev);
+ cbb_cardbus_reset(brdev, 1);
return (0);
}
@@ -971,7 +982,7 @@ static void
cbb_cardbus_power_disable_socket(device_t brdev, device_t child)
{
cbb_power(brdev, CARD_OFF);
- cbb_cardbus_reset(brdev);
+ cbb_cardbus_reset(brdev, 0);
}
/************************************************************************/
OpenPOWER on IntegriCloud