diff options
author | Uwe Stuehler <uwe@cvs.openbsd.org> | 2007-06-02 01:30:38 +0000 |
---|---|---|
committer | Uwe Stuehler <uwe@cvs.openbsd.org> | 2007-06-02 01:30:38 +0000 |
commit | a312a494f51438e870e2ed702d06e8a3695c2b3b (patch) | |
tree | 648503cbffb253be8367a7274f08d7683d1c6ace /sys/dev/sdmmc | |
parent | 01acd14e84aa80dc43b4a04c42224541bf77a5ec (diff) |
retry reading HCI packets a few times before giving up
Diffstat (limited to 'sys/dev/sdmmc')
-rw-r--r-- | sys/dev/sdmmc/sbt.c | 43 |
1 files changed, 30 insertions, 13 deletions
diff --git a/sys/dev/sdmmc/sbt.c b/sys/dev/sdmmc/sbt.c index c4a3ad1566b..eac93695343 100644 --- a/sys/dev/sdmmc/sbt.c +++ b/sys/dev/sdmmc/sbt.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sbt.c,v 1.3 2007/05/31 23:37:21 uwe Exp $ */ +/* $OpenBSD: sbt.c,v 1.4 2007/06/02 01:30:37 uwe Exp $ */ /* * Copyright (c) 2007 Uwe Stuehler <uwe@openbsd.org> @@ -37,6 +37,7 @@ #define SBT_REG_DAT 0x00 /* receiver/transmitter data */ #define SBT_REG_RPC 0x10 /* read packet control */ +#define RPC_PCRRT (1<<0) /* packet read retry */ #define SBT_REG_WPC 0x11 /* write packet control */ #define WPC_PCWRT (1<<0) /* packet write retry */ #define SBT_REG_RC 0x12 /* retry control status/set */ @@ -47,7 +48,8 @@ #define SBT_REG_BTMODE 0x20 /* SDIO Bluetooth card mode */ #define BTMODE_TYPEB (1<<0) /* 1=Type-B, 0=Type-A */ -#define SBT_BUFSIZ_HCI 65535 +#define SBT_BUFSIZ_HCI 65540 +#define SBT_RXTRY_MAX 5 struct sbt_softc { struct device sc_dev; /* base device */ @@ -57,6 +59,7 @@ struct sbt_softc { int sc_dying; /* shutdown in progress */ void *sc_ih; u_char *sc_buf; + int sc_rxtry; }; int sbt_match(struct device *, void *, void *); @@ -240,29 +243,41 @@ again: int sbt_read_packet(struct sbt_softc *sc, u_char *buf, size_t *lenp) { - int error, retry = 3; u_char hdr[3]; size_t len; - -again: - if (retry-- == 0) - return error; + int error; error = sdmmc_io_read_multi_1(sc->sc_sf, SBT_REG_DAT, hdr, 3); if (error) { DPRINTF(("sbt_read_packet: failed to read length\n")); - goto again; + goto out; } len = (hdr[0] | (hdr[1] << 8) | (hdr[2] << 16)) - 3; if (len > *lenp) { - error = ENOMEM; - goto again; + DPRINTF(("sbt_read_packet: len %u > %u\n", len, *lenp)); + error = ENOBUFS; + goto out; } + DPRINTF(("sbt_read_packet: reading len %u bytes\n", len)); error = sdmmc_io_read_multi_1(sc->sc_sf, SBT_REG_DAT, buf, len); if (error) { DPRINTF(("sbt_read_packet: failed to read packet data\n")); - goto again; + goto out; + } + +out: + if (error) { + if (sc->sc_rxtry >= SBT_RXTRY_MAX) { + /* Drop and request the next packet. */ + sc->sc_rxtry = 0; + CSR_WRITE_1(sc, SBT_REG_RPC, 0); + } else { + /* Request the current packet again. */ + sc->sc_rxtry++; + CSR_WRITE_1(sc, SBT_REG_RPC, RPC_PCRRT); + } + return error; } /* acknowledge read packet */ @@ -317,9 +332,11 @@ sbt_intr(void *arg) } eoi: - if (m != NULL) + if (m != NULL) { + DPRINTF(("%s: recv 0x%x packet (%d bytes)\n", + DEVNAME(sc), sc->sc_buf[0], m->m_pkthdr.len)); hci_input_event(&sc->sc_unit, m); - else + } else sc->sc_unit.hci_stats.err_rx++; splx(s); |