summaryrefslogtreecommitdiff
path: root/drivers/net
diff options
context:
space:
mode:
authorDmitry Shmidt <dimitrysh@google.com>2012-10-30 15:48:43 -0700
committerOm Prakash Singh <omp@nvidia.com>2012-12-19 13:44:37 +0530
commit5c78ab9d30f9568369ef37be55b5a225e2bf08d5 (patch)
treea52c1aae1c741a9fa25bc4100c93d773a6c02816 /drivers/net
parent95b09b2af7884b689870a377c0e9327f93fb7a92 (diff)
net: wireless: bcmdhd: Fix host reodering and CRC error handling
Bug: 7389187 Change-Id: I3c4ed28a20de527b91fd1ef9ae51c59bab276b85 Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/bcmdhd/Makefile3
-rw-r--r--drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c66
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_sdio.c51
-rw-r--r--drivers/net/wireless/bcmdhd/include/sbsdio.h1
4 files changed, 103 insertions, 18 deletions
diff --git a/drivers/net/wireless/bcmdhd/Makefile b/drivers/net/wireless/bcmdhd/Makefile
index bc39caf33167..8ea56af47d2e 100644
--- a/drivers/net/wireless/bcmdhd/Makefile
+++ b/drivers/net/wireless/bcmdhd/Makefile
@@ -17,8 +17,9 @@ DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DBCMDRIVER \
-DKEEP_ALIVE -DGET_CUSTOM_MAC_ENABLE -DPKT_FILTER_SUPPORT \
-DEMBEDDED_PLATFORM -DPNO_SUPPORT \
-DDHD_USE_IDLECOUNT -DSET_RANDOM_MAC_SOFTAP -DROAM_ENABLE -DVSDB \
- -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST -DAMPDU_HOSTREORDER \
+ -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST -DSDIO_CRC_ERROR_FIX \
-DESCAN_RESULT_PATCH -DHT40_GO -DPASS_ARP_PACKET -DSUPPORT_PM2_ONLY \
+ -DCUSTOM_SDIO_F2_BLKSIZE=128 \
-Idrivers/net/wireless/bcmdhd -Idrivers/net/wireless/bcmdhd/include
ifeq ($(CONFIG_BCMDHD_WIFI_CONTROL_FUNC),y)
diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c
index 831f2929f8a0..29d1e5c73165 100644
--- a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c
+++ b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c
@@ -63,12 +63,13 @@ extern int sdio_reset_comm(struct mmc_card *card);
extern PBCMSDH_SDMMC_INSTANCE gInstance;
-uint sd_sdmode = SDIOH_MODE_SD4; /* Use SD4 mode by default */
-#if defined(SDIO_F2_BLKSIZE)
-uint sd_f2_blocksize = SDIO_F2_BLKSIZE;
-#else
-uint sd_f2_blocksize = 512; /* Default blocksize */
+#define DEFAULT_SDIO_F2_BLKSIZE 512
+#ifndef CUSTOM_SDIO_F2_BLKSIZE
+#define CUSTOM_SDIO_F2_BLKSIZE DEFAULT_SDIO_F2_BLKSIZE
#endif
+
+uint sd_sdmode = SDIOH_MODE_SD4; /* Use SD4 mode by default */
+uint sd_f2_blocksize = CUSTOM_SDIO_F2_BLKSIZE;
uint sd_divisor = 2; /* Default 48MHz/2 = 24MHz */
uint sd_power = 1; /* Default to SD Slot powered ON */
@@ -82,6 +83,7 @@ DHD_PM_RESUME_WAIT_INIT(sdioh_request_packet_wait);
DHD_PM_RESUME_WAIT_INIT(sdioh_request_buffer_wait);
#define DMA_ALIGN_MASK 0x03
+#define MMC_SDIO_ABORT_RETRY_LIMIT 5
int sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data);
@@ -790,7 +792,9 @@ extern SDIOH_API_RC
sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *byte)
{
int err_ret;
-
+#if defined(MMC_SDIO_ABORT)
+ int sdio_abort_retry = MMC_SDIO_ABORT_RETRY_LIMIT;
+#endif
sd_info(("%s: rw=%d, func=%d, addr=0x%05x\n", __FUNCTION__, rw, func, regaddr));
DHD_PM_RESUME_WAIT(sdioh_request_byte_wait);
@@ -824,16 +828,20 @@ sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *by
#if defined(MMC_SDIO_ABORT)
/* to allow abort command through F1 */
else if (regaddr == SDIOD_CCCR_IOABORT) {
- if (gInstance->func[func]) {
- sdio_claim_host(gInstance->func[func]);
- /*
- * this sdio_f0_writeb() can be replaced with another api
- * depending upon MMC driver change.
- * As of this time, this is temporaray one
- */
- sdio_writeb(gInstance->func[func],
- *byte, regaddr, &err_ret);
- sdio_release_host(gInstance->func[func]);
+ while (sdio_abort_retry--) {
+ if (gInstance->func[func]) {
+ sdio_claim_host(gInstance->func[func]);
+ /*
+ * this sdio_f0_writeb() can be replaced with
+ * another api depending upon MMC driver change.
+ * As of this time, this is temporaray one
+ */
+ sdio_writeb(gInstance->func[func],
+ *byte, regaddr, &err_ret);
+ sdio_release_host(gInstance->func[func]);
+ }
+ if (!err_ret)
+ break;
}
}
#endif /* MMC_SDIO_ABORT */
@@ -882,6 +890,9 @@ sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint add
uint32 *word, uint nbytes)
{
int err_ret = SDIOH_API_RC_FAIL;
+#if defined(MMC_SDIO_ABORT)
+ int sdio_abort_retry = MMC_SDIO_ABORT_RETRY_LIMIT;
+#endif
if (func == 0) {
sd_err(("%s: Only CMD52 allowed to F0.\n", __FUNCTION__));
@@ -918,8 +929,29 @@ sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint add
sdio_release_host(gInstance->func[func]);
if (err_ret) {
- sd_err(("bcmsdh_sdmmc: Failed to %s word, Err: 0x%08x",
+#if defined(MMC_SDIO_ABORT)
+ /* Any error on CMD53 transaction should abort that function using function 0. */
+ while (sdio_abort_retry--) {
+ if (gInstance->func[0]) {
+ sdio_claim_host(gInstance->func[0]);
+ /*
+ * this sdio_f0_writeb() can be replaced with another api
+ * depending upon MMC driver change.
+ * As of this time, this is temporaray one
+ */
+ sdio_writeb(gInstance->func[0],
+ func, SDIOD_CCCR_IOABORT, &err_ret);
+ sdio_release_host(gInstance->func[0]);
+ }
+ if (!err_ret)
+ break;
+ }
+ if (err_ret)
+#endif /* MMC_SDIO_ABORT */
+ {
+ sd_err(("bcmsdh_sdmmc: Failed to %s word, Err: 0x%08x\n",
rw ? "Write" : "Read", err_ret));
+ }
}
return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
diff --git a/drivers/net/wireless/bcmdhd/dhd_sdio.c b/drivers/net/wireless/bcmdhd/dhd_sdio.c
index ead7d0c1d5ea..a7f2704ae1c2 100644
--- a/drivers/net/wireless/bcmdhd/dhd_sdio.c
+++ b/drivers/net/wireless/bcmdhd/dhd_sdio.c
@@ -391,8 +391,13 @@ static bool sd1idle;
static bool retrydata;
#define RETRYCHAN(chan) (((chan) == SDPCM_EVENT_CHANNEL) || retrydata)
+#if defined(SDIO_CRC_ERROR_FIX)
+static uint watermark = 48;
+static uint mesbusyctrl = 80;
+#else
static const uint watermark = 8;
static const uint mesbusyctrl = 0;
+#endif
static const uint firstread = DHD_FIRSTREAD;
#define HDATLEN (firstread - (SDPCM_HDRLEN))
@@ -2282,6 +2287,10 @@ enum {
IOV_SDALIGN,
IOV_DEVRESET,
IOV_CPU,
+#if defined(SDIO_CRC_ERROR_FIX)
+ IOV_WATERMARK,
+ IOV_MESBUSYCTRL,
+#endif /* SDIO_CRC_ERROR_FIX */
#ifdef SDTEST
IOV_PKTGEN,
IOV_EXTLOOP,
@@ -2342,6 +2351,10 @@ const bcm_iovar_t dhdsdio_iovars[] = {
{"extloop", IOV_EXTLOOP, 0, IOVT_BOOL, 0 },
{"pktgen", IOV_PKTGEN, 0, IOVT_BUFFER, sizeof(dhd_pktgen_t) },
#endif /* SDTEST */
+#if defined(SDIO_CRC_ERROR_FIX)
+ {"watermark", IOV_WATERMARK, 0, IOVT_UINT32, 0 },
+ {"mesbusyctrl", IOV_MESBUSYCTRL, 0, IOVT_UINT32, 0 },
+#endif /* SDIO_CRC_ERROR_FIX */
{"devcap", IOV_DEVCAP, 0, IOVT_UINT32, 0 },
{"dngl_isolation", IOV_DONGLEISOLATION, 0, IOVT_UINT32, 0 },
{"kso", IOV_KSO, 0, IOVT_UINT32, 0 },
@@ -3444,6 +3457,33 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch
break;
#endif /* SDTEST */
+#if defined(SDIO_CRC_ERROR_FIX)
+ case IOV_GVAL(IOV_WATERMARK):
+ int_val = (int32)watermark;
+ bcopy(&int_val, arg, val_size);
+ break;
+
+ case IOV_SVAL(IOV_WATERMARK):
+ watermark = (uint)int_val;
+ watermark = (watermark > SBSDIO_WATERMARK_MASK) ? SBSDIO_WATERMARK_MASK : watermark;
+ DHD_ERROR(("Setting watermark as 0x%x.\n", watermark));
+ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, (uint8)watermark, NULL);
+ break;
+
+ case IOV_GVAL(IOV_MESBUSYCTRL):
+ int_val = (int32)mesbusyctrl;
+ bcopy(&int_val, arg, val_size);
+ break;
+
+ case IOV_SVAL(IOV_MESBUSYCTRL):
+ mesbusyctrl = (uint)int_val;
+ mesbusyctrl = (mesbusyctrl > SBSDIO_MESBUSYCTRL_MASK)
+ ? SBSDIO_MESBUSYCTRL_MASK : mesbusyctrl;
+ DHD_ERROR(("Setting mesbusyctrl as 0x%x.\n", mesbusyctrl));
+ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL,
+ ((uint8)mesbusyctrl | 0x80), NULL);
+ break;
+#endif /* SDIO_CRC_ERROR_FIX */
case IOV_GVAL(IOV_DONGLEISOLATION):
int_val = bus->dhd->dongle_isolation;
@@ -4125,8 +4165,19 @@ dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex)
bus->hostintmask |= I_XMTDATA_AVAIL;
}
W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries);
+#ifdef SDIO_CRC_ERROR_FIX
+ if (bus->blocksize < 512) {
+ mesbusyctrl = watermark = bus->blocksize / 4;
+ }
+#endif /* SDIO_CRC_ERROR_FIX */
bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, (uint8)watermark, &err);
+#ifdef SDIO_CRC_ERROR_FIX
+ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL,
+ (uint8)mesbusyctrl|0x80, &err);
+ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL,
+ SBSDIO_DEVCTL_EN_F2_BLK_WATERMARK, NULL);
+#endif /* SDIO_CRC_ERROR_FIX */
/* Set bus state according to enable result */
dhdp->busstate = DHD_BUS_DATA;
diff --git a/drivers/net/wireless/bcmdhd/include/sbsdio.h b/drivers/net/wireless/bcmdhd/include/sbsdio.h
index 4b5a1cf465fc..211c421863e9 100644
--- a/drivers/net/wireless/bcmdhd/include/sbsdio.h
+++ b/drivers/net/wireless/bcmdhd/include/sbsdio.h
@@ -120,6 +120,7 @@
#define SBSDIO_DEVCTL_RST_CORECTL 0x00 /* Determined by CoreControl bit */
#define SBSDIO_DEVCTL_RST_BPRESET 0x10 /* Force backplane reset */
#define SBSDIO_DEVCTL_RST_NOBPRESET 0x20 /* Force no backplane reset */
+#define SBSDIO_DEVCTL_EN_F2_BLK_WATERMARK 0x10 /* Enable function 2 tx for each block */
/* SBSDIO_FUNC1_CHIPCLKCSR */