bcm4329: sync with kernel tree (b/2249878)
  1798b1b3: Fix wl_iw_set_pmksa() functionality
  05d8e87f: Set 2 retries to config registers access
  9dde2be3: Stop transmit queue in case of firmware failure
  d1d35073: Get IRQ type from platform data

Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/bcm4329/src/bcmsdio/sys/bcmsdh.c b/bcm4329/src/bcmsdio/sys/bcmsdh.c
index 4c62610..c9906e2 100644
--- a/bcm4329/src/bcmsdio/sys/bcmsdh.c
+++ b/bcm4329/src/bcmsdio/sys/bcmsdh.c
@@ -40,6 +40,9 @@
 
 #include <sdio.h>	/* sdio spec */
 
+/* Defines number of access retries to configuration registers */
+#define SDIOH_API_ACCESS_RETRY_LIMIT	2
+
 const uint bcmsdh_msglevel = BCMSDH_ERROR_VAL;
 
 
@@ -207,6 +210,9 @@
 {
 	bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
 	SDIOH_API_RC status;
+#ifdef SDIOH_API_ACCESS_RETRY_LIMIT
+	int32 retry = 0;
+#endif
 	uint8 data = 0;
 
 	if (!bcmsdh)
@@ -214,7 +220,15 @@
 
 	ASSERT(bcmsdh->init_success);
 
+#ifdef SDIOH_API_ACCESS_RETRY_LIMIT
+	do {
+		if (retry)	/* wait for 1 ms till bus get settled down */
+			OSL_DELAY(1000);
+#endif
 	status = sdioh_cfg_read(bcmsdh->sdioh, fnc_num, addr, (uint8 *)&data);
+#ifdef SDIOH_API_ACCESS_RETRY_LIMIT
+	} while (!SDIOH_API_SUCCESS(status) && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT));
+#endif
 	if (err)
 		*err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR);
 
@@ -229,13 +243,24 @@
 {
 	bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
 	SDIOH_API_RC status;
+#ifdef SDIOH_API_ACCESS_RETRY_LIMIT
+	int32 retry = 0;
+#endif
 
 	if (!bcmsdh)
 		bcmsdh = l_bcmsdh;
 
 	ASSERT(bcmsdh->init_success);
 
+#ifdef SDIOH_API_ACCESS_RETRY_LIMIT
+	do {
+		if (retry)	/* wait for 1 ms till bus get settled down */
+			OSL_DELAY(1000);
+#endif
 	status = sdioh_cfg_write(bcmsdh->sdioh, fnc_num, addr, (uint8 *)&data);
+#ifdef SDIOH_API_ACCESS_RETRY_LIMIT
+	} while (!SDIOH_API_SUCCESS(status) && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT));
+#endif
 	if (err)
 		*err = SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR;
 
diff --git a/bcm4329/src/bcmsdio/sys/bcmsdh_linux.c b/bcm4329/src/bcmsdio/sys/bcmsdh_linux.c
index 5742ea5..d7d5b73 100644
--- a/bcm4329/src/bcmsdio/sys/bcmsdh_linux.c
+++ b/bcm4329/src/bcmsdio/sys/bcmsdh_linux.c
@@ -75,6 +75,7 @@
 	bcmsdh_info_t *sdh;		/* SDIO Host Controller handle */
 	void *ch;
 	unsigned int oob_irq;
+	unsigned long oob_flags;
 };
 static bcmsdh_hc_t *sdhcinfo = NULL;
 
@@ -175,6 +176,7 @@
 #endif /* BCMLXSDMMC */
 	int irq = 0;
 	uint32 vendevid;
+	unsigned long irq_flags = IRQF_TRIGGER_FALLING;
 
 #if !defined(BCMLXSDMMC) && defined(BCMPLATFORM_BUS)
 	pdev = to_platform_device(dev);
@@ -185,7 +187,7 @@
 #endif /* BCMLXSDMMC */
 
 #if defined(OOB_INTR_ONLY)
-	irq = dhd_customer_oob_irq_map();
+	irq = dhd_customer_oob_irq_map(&irq_flags);
 	if  (irq < 0) {
 		SDLX_MSG(("%s: Host irq is not defined\n", __FUNCTION__));
 		return 1;
@@ -222,6 +224,7 @@
 #endif /* BCMLXSDMMC */
 	sdhc->sdh = sdh;
 	sdhc->oob_irq = irq;
+	sdhc->oob_flags = irq_flags;
 
 	/* chain SDIO Host Controller info together */
 	sdhc->next = sdhcinfo;
@@ -557,15 +560,15 @@
 
 	sdhcinfo->dev->driver_data = dhdp;
 
-	set_irq_wake(sdhcinfo->oob_irq, 1);
-
 	/* Refer to customer Host IRQ docs about proper irqflags definition */
-	error = request_irq(sdhcinfo->oob_irq, wlan_oob_irq, IRQF_TRIGGER_FALLING,
+	error = request_irq(sdhcinfo->oob_irq, wlan_oob_irq, sdhcinfo->oob_flags,
 		"bcmsdh_sdmmc", NULL);
 
 	if (error)
 		return -ENODEV;
 
+	set_irq_wake(sdhcinfo->oob_irq, 1);
+
 	return 0;
 }
 
diff --git a/bcm4329/src/dhd/sys/dhd.h b/bcm4329/src/dhd/sys/dhd.h
index e05763b..38baa8a 100644
--- a/bcm4329/src/dhd/sys/dhd.h
+++ b/bcm4329/src/dhd/sys/dhd.h
@@ -276,7 +276,7 @@
 extern void dhd_customer_gpio_wlan_ctrl(int onoff);
 extern void dhd_os_sdunlock_sndup_rxq(dhd_pub_t * pub);
 #if defined(OOB_INTR_ONLY)
-extern int dhd_customer_oob_irq_map(void);
+extern int dhd_customer_oob_irq_map(unsigned long *irq_flags_ptr);
 #endif /* defined(OOB_INTR_ONLY) */
 extern void dhd_os_sdtxlock(dhd_pub_t * pub);
 extern void dhd_os_sdtxunlock(dhd_pub_t * pub);
diff --git a/bcm4329/src/dhd/sys/dhd_custom_gpio.c b/bcm4329/src/dhd/sys/dhd_custom_gpio.c
index f39acda..9d655f9 100644
--- a/bcm4329/src/dhd/sys/dhd_custom_gpio.c
+++ b/bcm4329/src/dhd/sys/dhd_custom_gpio.c
@@ -46,7 +46,7 @@
 #ifdef CUSTOMER_HW2
 int wifi_set_carddetect(int on);
 int wifi_set_power(int on, unsigned long msec);
-int wifi_get_irq_number(void);
+int wifi_get_irq_number(unsigned long *irq_flags_ptr);
 #endif
 
 #if defined(OOB_INTR_ONLY)
@@ -61,18 +61,18 @@
 module_param(dhd_oob_gpio_num, int, 0644);
 MODULE_PARM_DESC(dhd_oob_gpio_num, "DHD oob gpio number");
 
-int dhd_customer_oob_irq_map(void)
+int dhd_customer_oob_irq_map(unsigned long *irq_flags_ptr)
 {
 	int  host_oob_irq;
 #ifdef CUSTOMER_HW2
-	host_oob_irq = wifi_get_irq_number();
+	host_oob_irq = wifi_get_irq_number(irq_flags_ptr);
 #else
 #if defined(CUSTOM_OOB_GPIO_NUM)
 	if (dhd_oob_gpio_num < 0) {
 		dhd_oob_gpio_num = CUSTOM_OOB_GPIO_NUM;
 	}
 #endif
-
+	*irq_flags_ptr = IRQF_TRIGGER_FALLING;
 	if (dhd_oob_gpio_num < 0) {
 		WL_ERROR(("%s: ERROR customer specific Host GPIO is NOT defined \n", \
 			             __FUNCTION__));
diff --git a/bcm4329/src/dhd/sys/dhd_linux.c b/bcm4329/src/dhd/sys/dhd_linux.c
index 36f695c..9f5b7bc 100644
--- a/bcm4329/src/dhd/sys/dhd_linux.c
+++ b/bcm4329/src/dhd/sys/dhd_linux.c
@@ -72,10 +72,12 @@
 static struct wifi_platform_data *wifi_control_data = NULL;
 static struct resource *wifi_irqres = NULL;
 
-int wifi_get_irq_number(void)
+int wifi_get_irq_number(unsigned long *irq_flags_ptr)
 {
-	if (wifi_irqres)
+	if (wifi_irqres) {
+		*irq_flags_ptr = wifi_irqres->flags & IRQF_TRIGGER_MASK;
 		return (int)wifi_irqres->start;
+	}
 #ifdef CUSTOM_OOB_GPIO_NUM
 	return CUSTOM_OOB_GPIO_NUM;
 #else
@@ -888,6 +890,7 @@
 	/* Reject if down */
 	if (!dhd->pub.up || (dhd->pub.busstate == DHD_BUS_DOWN)) {
 		DHD_ERROR(("%s: xmit rejected due to dhd bus down status \n", __FUNCTION__));
+		netif_stop_queue(net);
 		return -ENODEV;
 	}
 
diff --git a/bcm4329/src/wl/sys/wl_iw.c b/bcm4329/src/wl/sys/wl_iw.c
index 9f3cebf..3e175b6 100644
--- a/bcm4329/src/wl/sys/wl_iw.c
+++ b/bcm4329/src/wl/sys/wl_iw.c
@@ -53,6 +53,7 @@
 #define WL_ASSOC(x)
 #define WL_INFORM(x)
 #define WL_WSEC(x)
+#define WL_TRACE_PMK(x)
 
 #include <wl_iw.h>
 
@@ -3479,31 +3480,33 @@
 {
 	struct iw_pmksa *iwpmksa;
 	uint i;
+	int ret = 0;
 	char eabuf[ETHER_ADDR_STR_LEN];
 
-	WL_TRACE(("%s: SIOCSIWPMKSA\n", dev->name));
+	WL_TRACE_PMK(("%s: SIOCSIWPMKSA\n", dev->name));
 	iwpmksa = (struct iw_pmksa *)extra;
 	bzero((char *)eabuf, ETHER_ADDR_STR_LEN);
 
 	if (iwpmksa->cmd == IW_PMKSA_FLUSH) {
-		WL_TRACE(("wl_iw_set_pmksa - IW_PMKSA_FLUSH\n"));
+		WL_TRACE_PMK(("wl_iw_set_pmksa - IW_PMKSA_FLUSH\n"));
 		bzero((char *)&pmkid_list, sizeof(pmkid_list));
 	}
 
-	if (iwpmksa->cmd == IW_PMKSA_REMOVE) {
-		pmkid_list_t pmkid, *pmkidptr;
-		pmkidptr = &pmkid;
-
-		bcopy(&iwpmksa->bssid.sa_data[0], &pmkidptr->pmkid[0].BSSID, ETHER_ADDR_LEN);
-		bcopy(&iwpmksa->pmkid[0], &pmkidptr->pmkid[0].PMKID, WPA2_PMKID_LEN);
+	else if (iwpmksa->cmd == IW_PMKSA_REMOVE) {
 		{
+			pmkid_list_t pmkid, *pmkidptr;
 			uint j;
-			WL_TRACE(("wl_iw_set_pmksa,IW_PMKSA_REMOVE - PMKID: %s = ",
+			pmkidptr = &pmkid;
+
+			bcopy(&iwpmksa->bssid.sa_data[0], &pmkidptr->pmkid[0].BSSID, ETHER_ADDR_LEN);
+			bcopy(&iwpmksa->pmkid[0], &pmkidptr->pmkid[0].PMKID, WPA2_PMKID_LEN);
+
+			WL_TRACE_PMK(("wl_iw_set_pmksa,IW_PMKSA_REMOVE - PMKID: %s = ",
 				bcm_ether_ntoa(&pmkidptr->pmkid[0].BSSID,
 				eabuf)));
 			for (j = 0; j < WPA2_PMKID_LEN; j++)
-				WL_TRACE(("%02x ", pmkidptr->pmkid[0].PMKID[j]));
-			WL_TRACE(("\n"));
+				WL_TRACE_PMK(("%02x ", pmkidptr->pmkid[0].PMKID[j]));
+			WL_TRACE_PMK(("\n"));
 		}
 
 		for (i = 0; i < pmkid_list.pmkids.npmkid; i++)
@@ -3511,50 +3514,66 @@
 				ETHER_ADDR_LEN))
 				break;
 
-		for (; i < pmkid_list.pmkids.npmkid; i++) {
-			bcopy(&pmkid_list.pmkids.pmkid[i+1].BSSID,
-				&pmkid_list.pmkids.pmkid[i].BSSID,
-				ETHER_ADDR_LEN);
-			bcopy(&pmkid_list.pmkids.pmkid[i+1].PMKID,
-				&pmkid_list.pmkids.pmkid[i].PMKID,
-				WPA2_PMKID_LEN);
+		if ((pmkid_list.pmkids.npmkid > 0) && (i < pmkid_list.pmkids.npmkid)) {
+			bzero(&pmkid_list.pmkids.pmkid[i], sizeof(pmkid_t));
+			for (; i < (pmkid_list.pmkids.npmkid - 1); i++) {
+				bcopy(&pmkid_list.pmkids.pmkid[i+1].BSSID,
+					&pmkid_list.pmkids.pmkid[i].BSSID,
+					ETHER_ADDR_LEN);
+				bcopy(&pmkid_list.pmkids.pmkid[i+1].PMKID,
+					&pmkid_list.pmkids.pmkid[i].PMKID,
+					WPA2_PMKID_LEN);
+			}
+			pmkid_list.pmkids.npmkid--;
 		}
-		pmkid_list.pmkids.npmkid--;
+		else
+			ret = -EINVAL;
 	}
 
-	if (iwpmksa->cmd == IW_PMKSA_ADD) {
-		bcopy(&iwpmksa->bssid.sa_data[0],
-			&pmkid_list.pmkids.pmkid[pmkid_list.pmkids.npmkid].BSSID,
-			ETHER_ADDR_LEN);
-		bcopy(&iwpmksa->pmkid[0], &pmkid_list.pmkids.pmkid[pmkid_list.pmkids.npmkid].PMKID,
-			WPA2_PMKID_LEN);
+	else if (iwpmksa->cmd == IW_PMKSA_ADD) {
+		for (i = 0; i < pmkid_list.pmkids.npmkid; i++)
+			if (!bcmp(&iwpmksa->bssid.sa_data[0], &pmkid_list.pmkids.pmkid[i].BSSID,
+				ETHER_ADDR_LEN))
+				break;
+		if (i < MAXPMKID) {
+			bcopy(&iwpmksa->bssid.sa_data[0],
+				&pmkid_list.pmkids.pmkid[i].BSSID,
+				ETHER_ADDR_LEN);
+			bcopy(&iwpmksa->pmkid[0], &pmkid_list.pmkids.pmkid[i].PMKID,
+				WPA2_PMKID_LEN);
+			if (i == pmkid_list.pmkids.npmkid)
+				pmkid_list.pmkids.npmkid++;
+		}
+		else
+			ret = -EINVAL;
+
 		{
 			uint j;
 			uint k;
 			k = pmkid_list.pmkids.npmkid;
-			WL_TRACE(("wl_iw_set_pmksa,IW_PMKSA_ADD - PMKID: %s = ",
+			WL_TRACE_PMK(("wl_iw_set_pmksa,IW_PMKSA_ADD - PMKID: %s = ",
 				bcm_ether_ntoa(&pmkid_list.pmkids.pmkid[k].BSSID,
 				eabuf)));
 			for (j = 0; j < WPA2_PMKID_LEN; j++)
-				WL_TRACE(("%02x ", pmkid_list.pmkids.pmkid[k].PMKID[j]));
-			WL_TRACE(("\n"));
+				WL_TRACE_PMK(("%02x ", pmkid_list.pmkids.pmkid[k].PMKID[j]));
+			WL_TRACE_PMK(("\n"));
 		}
-		pmkid_list.pmkids.npmkid++;
 	}
-	WL_TRACE(("PRINTING pmkid LIST - No of elements %d\n", pmkid_list.pmkids.npmkid));
+	WL_TRACE_PMK(("PRINTING pmkid LIST - No of elements %d, ret = %d\n", pmkid_list.pmkids.npmkid, ret));
 	for (i = 0; i < pmkid_list.pmkids.npmkid; i++) {
 		uint j;
-		WL_TRACE(("PMKID[%d]: %s = ", i,
+		WL_TRACE_PMK(("PMKID[%d]: %s = ", i,
 			bcm_ether_ntoa(&pmkid_list.pmkids.pmkid[i].BSSID,
 			eabuf)));
 		for (j = 0; j < WPA2_PMKID_LEN; j++)
-			WL_TRACE(("%02x ", pmkid_list.pmkids.pmkid[i].PMKID[j]));
-		printf("\n");
+			WL_TRACE_PMK(("%02x ", pmkid_list.pmkids.pmkid[i].PMKID[j]));
+		WL_TRACE_PMK(("\n"));
 	}
-	WL_TRACE(("\n"));
+	WL_TRACE_PMK(("\n"));
 
-	dev_wlc_bufvar_set(dev, "pmkid_info", (char *)&pmkid_list, sizeof(pmkid_list));
-	return 0;
+	if (!ret)
+		ret = dev_wlc_bufvar_set(dev, "pmkid_info", (char *)&pmkid_list, sizeof(pmkid_list));
+	return ret;
 }
 #endif 
 #endif