aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/pccbb/pccbb.c
diff options
context:
space:
mode:
authorWarner Losh <imp@FreeBSD.org>2008-08-09 04:08:36 +0000
committerWarner Losh <imp@FreeBSD.org>2008-08-09 04:08:36 +0000
commitbfd58cce845ab3a95cea53e1a6e1441cd17bf658 (patch)
treed444c2c598bdc399e1b8fdf97ee61067804bf09c /sys/dev/pccbb/pccbb.c
parente33abcc50c70249a1affd259f7311ef262e609ea (diff)
downloadsrc-bfd58cce845ab3a95cea53e1a6e1441cd17bf658.tar.gz
src-bfd58cce845ab3a95cea53e1a6e1441cd17bf658.zip
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...
Notes
Notes: svn path=/head/; revision=181453
Diffstat (limited to 'sys/dev/pccbb/pccbb.c')
-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 e45d608fb034..f5a3b74c15c6 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);
}
/************************************************************************/