[ALPS02870048] BT Driver: Enable core dump for mt7668

Test: Pass

Change-Id: I11c0b0036367d1c07aee5b10833dbdbe9db27b51
Signed-off-by: can.chen <can.chen@mediatek.com>
Feature: BT Driver(MT7668)
CR-Id: ALPS02870048
diff --git a/btmtk_drv.h b/btmtk_drv.h
index e8feb8e..f3e7f24 100644
--- a/btmtk_drv.h
+++ b/btmtk_drv.h
@@ -19,9 +19,9 @@
 #include <linux/slab.h>
 #include <net/bluetooth/bluetooth.h>
 
-#define SAVE_FW_DUMP_IN_KERNEL	1
+#define SAVE_FW_DUMP_IN_KERNEL 0
 
-#define SUPPORT_FW_DUMP		1
+#define SUPPORT_FW_DUMP 1
 #define BTM_HEADER_LEN                  5
 #define BTM_UPLD_SIZE                   2312
 
@@ -126,6 +126,7 @@
 	struct task_struct *fw_dump_tsk;
 	struct task_struct *fw_dump_end_check_tsk;
 #endif
+	bool no_fw_own;
 };
 
 #define MTK_VENDOR_PKT                 0xFE
@@ -222,13 +223,9 @@
 };
 
 #ifdef CONFIG_DEBUG_FS
-
 #define FIXED_STPBT_MAJOR_DEV_ID 111
 
-
-
 #define FW_DUMP_END_EVENT "coredump end"
-
 #endif
 
 #endif
diff --git a/btmtk_sdio.c b/btmtk_sdio.c
index ad3e466..b2d50de 100644
--- a/btmtk_sdio.c
+++ b/btmtk_sdio.c
@@ -64,6 +64,7 @@
 /*static int btmtk_woble_state = BTMTK_WOBLE_STATE_UNKNOWN;*/
 
 static int need_reset_stack;
+static int need_set_i2s = 0;
 /* The btmtk_sdio_remove() callback function is called
  * when user removes this module from kernel space or ejects
  * the card from the slot. The driver handles these 2 cases
@@ -103,6 +104,7 @@
 static int btmtk_proc_show(struct seq_file *m, void *v);
 static int btmtk_proc_open(struct inode *inode, struct  file *file);
 static void btmtk_proc_create_new_entry(void);
+static int btmtk_sdio_trigger_fw_assert(void);
 
 static char fw_dump_file_name[FW_DUMP_FILE_NAME_SIZE] = {0};
 static char event_need_compare[EVENT_COMPARE_SIZE] = {0};
@@ -110,6 +112,8 @@
 static char event_compare_status;
 /*add special header in the beginning of even, stack won't recognize these event*/
 
+struct _OSAL_UNSLEEPABLE_LOCK_ event_compare_status_lock;
+struct _OSAL_UNSLEEPABLE_LOCK_ tx_function_lock;
 
 
 
@@ -587,38 +591,13 @@
 	return ret;
 }
 
-struct sk_buff *btmtk_create_send_data(struct sk_buff *skb)
+static void btmtk_sdio_set_no_fw_own(struct btmtk_private *priv, bool no_fw_own)
 {
-	struct sk_buff *queue_skb = NULL;
-	u32 sdio_header_len = skb->len + BTM_HEADER_LEN;
-
-	if (skb_headroom(skb) < (BTM_HEADER_LEN)) {
-		queue_skb = bt_skb_alloc(sdio_header_len, GFP_ATOMIC);
-		if (queue_skb == NULL) {
-			pr_err("bt_skb_alloc fail return\n");
-			return 0;
-		}
-
-		queue_skb->data[0] = (sdio_header_len & 0x0000ff);
-		queue_skb->data[1] = (sdio_header_len & 0x00ff00) >> 8;
-		queue_skb->data[2] = 0;
-		queue_skb->data[3] = 0;
-		queue_skb->data[4] = bt_cb(skb)->pkt_type;
-		queue_skb->len = sdio_header_len;
-		memcpy(&queue_skb->data[5], &skb->data[0], skb->len);
-		kfree_skb(skb);
-	} else {
-		queue_skb = skb;
-		skb_push(queue_skb, BTM_HEADER_LEN);
-		queue_skb->data[0] = (sdio_header_len & 0x0000ff);
-		queue_skb->data[1] = (sdio_header_len & 0x00ff00) >> 8;
-		queue_skb->data[2] = 0;
-		queue_skb->data[3] = 0;
-		queue_skb->data[4] = bt_cb(skb)->pkt_type;
-	}
-
-	pr_info("%s end\n", __func__);
-	return queue_skb;
+	if (priv) {
+		priv->no_fw_own = no_fw_own;
+		pr_debug("%s set no_fw_own %d\n", __func__, priv->no_fw_own);
+	} else
+		pr_debug("%s priv is NULL\n", __func__);
 }
 
 static int btmtk_sdio_set_own_back(int owntype)
@@ -635,6 +614,13 @@
 	if (user_rmmod)
 		set_checkretry = 1;
 
+	if (owntype == FW_OWN && (g_priv)) {
+		if (g_priv->no_fw_own) {
+			pr_debug("%s no_fw_own is on, just return \n", __func__);
+			return ret;
+		}
+	}
+
 	ret = btmtk_sdio_readl(CHLPCR, &u32ReadCRValue);
 
 	pr_debug("%s btmtk_sdio_readl  CHLPCR done\n", __func__);
@@ -1476,8 +1462,7 @@
 		}
 	} while (ret);
 
-	if (priv)
-		priv->btmtk_dev.tx_dnld_rdy = false;
+	priv->btmtk_dev.tx_dnld_rdy = false;
 
 exit:
 
@@ -2135,6 +2120,7 @@
 	u32 dump_len = 0;
 	char *core_dump_end = NULL;
 	int i = 0;
+	u8 reset_event[] =  {0x0E, 0x04, 0x01, 0x03, 0x0C, 0x00};
 	static int print_dump_data_counter;
 
 #if SUPPORT_FW_DUMP
@@ -2177,6 +2163,7 @@
 							fw_dump_file_name,
 							O_RDWR | O_CREAT,
 							0644);
+					btmtk_sdio_set_no_fw_own(g_priv, TRUE);
 					print_dump_data_counter = 0;
 					if (!(IS_ERR(fw_dump_file))) {
 						current_fwdump_file_number =
@@ -2216,7 +2203,7 @@
 				#endif
 
 				/* This is coredump data, save coredump data to picus_queue */
-				pr_debug("%s : Receive coredump data, move data to fwlog queue for picus", __func__);
+				pr_info("%s : Receive coredump data, move data to fwlog queue for picus", __func__);
 				buf_len = rx_length-(MTK_SDIO_PACKET_HEADER_SIZE+1);
 				lock_unsleepable_lock(&(fwlog_metabuffer.spin_lock));
 				fwlog_fops_skb = bt_skb_alloc(buf_len, GFP_ATOMIC);
@@ -2226,12 +2213,13 @@
 				pr_debug("%s fwlog_fops_skb length = %d, buf_len = %d\n",
 					__func__, fwlog_fops_skb->len, buf_len);
 				if (skb_queue_empty(&g_priv->adapter->fwlog_fops_queue))
-					pr_warn("%s fwlog_fops_queue is empty empty\n", __func__);
+					pr_info("%s fwlog_fops_queue is empty empty\n", __func__);
 
 				kfree_skb(skb);
 				wake_up_interruptible(&fw_log_inq);
 				unlock_unsleepable_lock(&(fwlog_metabuffer.spin_lock));
 
+#ifdef CONFIG_DEBUG_FS
 				if (dump_len >= sizeof(FW_DUMP_END_EVENT)) {
 					core_dump_end = strstr(
 						&rxbuf[SDIO_HEADER_LEN+10],
@@ -2241,6 +2229,7 @@
 					if (core_dump_end)
 						btmtk_sdio_for_code_style();
 				}
+#endif
 			}
 		}
 	}
@@ -2315,8 +2304,20 @@
 	case HCI_EVENT_PKT:
 		buf_len = skb->data[1] + 2;
 		break;
+	default:
+		BTSDIO_INFO_RAW(skb->data, (buf_len < 16 ? buf_len : 16), "%s: skb->data(type %d):", __func__, type);
+		/* trigger fw core dump */
+		btmtk_sdio_trigger_fw_assert();
+		ret = -EINVAL;
+		goto exit;
 	}
 
+	if ((g_priv->adapter->fops_mode == true) &&
+		memcmp(skb->data, reset_event, sizeof(reset_event)) == 0)
+	{
+		pr_debug("%s get reset complete event!\n", __func__);
+		need_set_i2s = 1;
+	}
 	if (event_compare_status == BTMTK_SDIO_EVENT_COMPARE_STATE_NEED_COMPARE)
 		BTSDIO_DEBUG_RAW(skb->data, buf_len, "%s: skb->data :", __func__);
 
@@ -2348,7 +2349,10 @@
 			if (buf_len >= event_need_compare_len) {
 				if (memcmp(skb->data, event_need_compare, event_need_compare_len) == 0) {
 					event_compare_status = BTMTK_SDIO_EVENT_COMPARE_STATE_COMPARE_SUCCESS;
-					pr_debug("%s compare success\n", __func__);
+					pr_info("%s compare success and goto exit !\n", __func__);
+					/* for VTS loopback mode test, the command send by driver event should not report to stack */
+					kfree_skb(skb);
+					goto exit;
 				} else {
 					pr_debug("%s compare fail\n", __func__);
 					BTSDIO_DEBUG_RAW(event_need_compare, event_need_compare_len,
@@ -2409,6 +2413,12 @@
 	u32 u32ReadCRValue = 0;
 
 	ret = btmtk_sdio_readl(CHISR, &u32ReadCRValue);
+	pr_debug("%s CHISR 0x%08x\n", __func__, u32ReadCRValue);
+	if (u32ReadCRValue & FIRMWARE_INT_BIT15) {
+		btmtk_sdio_set_no_fw_own(g_priv, TRUE);
+		btmtk_sdio_writel(CHISR, FIRMWARE_INT_BIT15);
+	}
+
 	pr_debug("%s check TX_EMPTY CHISR 0x%08x\n", __func__, u32ReadCRValue);
 	if (TX_EMPTY&u32ReadCRValue) {
 		ret = btmtk_sdio_writel(CHISR, (TX_EMPTY | TX_COMPLETE_COUNT));
@@ -2420,12 +2430,14 @@
 		ret = btmtk_sdio_recv_rx_data();
 
 	if (ret == 0) {
+		lock_unsleepable_lock(&event_compare_status_lock);
 		while (rx_length > (MTK_SDIO_PACKET_HEADER_SIZE)) {
 			btmtk_sdio_card_to_host(priv, NULL, -1, 0);
 			u32rxdatacount++;
 			pr_debug("%s u32rxdatacount %d\n",
 				__func__, u32rxdatacount);
 		}
+		unlock_unsleepable_lock(&event_compare_status_lock);
 	}
 
 	btmtk_sdio_enable_interrupt(1);
@@ -2909,7 +2921,8 @@
 	btmtk_sdio_set_i2s();
 	/* Move from btmtk_fops_open() */
 	spin_lock_init(&(metabuffer.spin_lock.lock));
-	spin_lock_init(&(fwlog_metabuffer.spin_lock.lock));
+	spin_lock_init(&(event_compare_status_lock.lock));
+	spin_lock_init(&(tx_function_lock.lock));
 	pr_debug("%s spin_lock_init end\n", __func__);
 
 	priv = btmtk_add_card(card);
@@ -3085,6 +3098,34 @@
 	return ret;
 }
 
+static int btmtk_sdio_trigger_fw_assert(void)
+{
+	int ret = 0;
+	u8 cmd[] = { 0x5b, 0xfd, 0x00 };
+
+	pr_info("%s begin\n", __func__);
+	ret = btmtk_sdio_send_hci_cmd(HCI_COMMAND_PKT, cmd,
+		sizeof(cmd),
+		NULL, 0, WOBLE_COMP_EVENT_TIMO, 1);
+	if (ret != 0)
+		pr_info("%s ret = %d \n", __func__, ret);
+	return ret;
+}
+
+static int btmtk_sdio_send_set_i2s_slave(void)
+{
+	int ret = 0;
+	u8 comp_event[] = {0xE, 0x04, 0x01, 0x72, 0xFC, 0x00 };
+	u8 cmd[] = { 0x72, 0xFC, 4, 03, 0x10, 0x00, 0x02 };
+
+	ret = btmtk_sdio_send_hci_cmd(HCI_COMMAND_PKT, cmd,
+		sizeof(cmd),
+		comp_event, sizeof(comp_event), WOBLE_COMP_EVENT_TIMO, 1);
+	if (ret != 0)
+		pr_info("%s ret = %d \n", __func__, ret);
+	return ret;
+}
+
 static int btmtk_sdio_send_get_vendor_cap(void)
 {
 	int ret = -1;
@@ -3499,7 +3540,6 @@
 		pr_info("%s:irq_enable count:%d\n", __func__, atomic_read(&(g_card->irq_enable_count)));
 #endif
 
-
 	if (func) {
 		pm_flags = sdio_get_host_pm_caps(func);
 		pr_debug("%s: suspend: PM flags = 0x%x\n",
@@ -3568,6 +3608,21 @@
 	}
 };
 
+static int btmtk_sdio_send_hci_reset(void)
+{
+	int ret = 0;
+	u8 comp_event[] = {0x0e, 0x04, 0x01, 0x03, 0x0c, 0x00 };
+	u8 cmd[] = { 0x03, 0x0c, 0x00 };
+
+	pr_info("%s begin\n", __func__);
+	ret = btmtk_sdio_send_hci_cmd(HCI_COMMAND_PKT, cmd,
+		sizeof(cmd),
+		comp_event, sizeof(comp_event), WOBLE_COMP_EVENT_TIMO, 1);
+	if (ret != 0)
+		pr_info("%s ret = %d \n", __func__, ret);
+	return ret;
+}
+
 static int btmtk_clean_queue(void)
 {
 	struct sk_buff *skb = NULL;
@@ -3640,6 +3695,8 @@
 	if (g_priv)
 		g_priv->adapter->fops_mode = false;
 
+	/* for VTS loopback mode test */
+	btmtk_sdio_send_hci_reset();
 	btmtk_clean_queue();
 
 	pr_info("%s fops_mode=%d end\n", __func__, g_priv->adapter->fops_mode);
@@ -3846,6 +3903,12 @@
 		}
 	}
 
+	if (need_set_i2s == 1) {
+		pr_info("%s get reset complete and set I2S !\n",__func__ );
+		btmtk_sdio_send_set_i2s_slave();
+		need_set_i2s = 0;
+	}
+
 	lock_unsleepable_lock(&(metabuffer.spin_lock));
 	if (skb_queue_empty(&g_priv->adapter->fops_queue)) {
 		/* if (filp->f_flags & O_NONBLOCK) { */
@@ -4051,8 +4114,6 @@
 		return -EFAULT;
 	}
 
-	btmtk_sdio_set_own_back(DRIVER_OWN);
-
 	if (g_priv == NULL) {
 		pr_info("%s g_priv is NULL\n", __func__);
 		goto exit;
@@ -4390,12 +4451,12 @@
 	dev_t devIDfwlog = g_devIDfwlog;
 
 	pr_info("%s\n", __func__);
-
-	if (g_proc_dir != NULL) {
+	if (g_proc_dir != 0) {
+		g_proc_dir = 0;
 		remove_proc_entry("bt_fw_version", g_proc_dir);
 		remove_proc_entry("stpbt", NULL);
-		g_proc_dir = NULL;
 		pr_info("proc device node and folder removed!!");
+		return;
 	}
 
 	if (g_card) {
@@ -4440,6 +4501,9 @@
 	cdev_del(&BTMTK_cdev);
 	pr_info("%s 10\n", __func__);
 	unregister_chrdev_region(dev, 1);
+
+	cdev_del(&BT_cdevfwlog);
+	unregister_chrdev_region(devIDfwlog, 1);
 	pr_info("%s driver removed.\n", BT_DRIVER_NAME);
 }
 
diff --git a/btmtk_sdio.h b/btmtk_sdio.h
index 6674d95..486daff 100644
--- a/btmtk_sdio.h
+++ b/btmtk_sdio.h
@@ -19,7 +19,7 @@
 #endif
 
 
-#define VERSION "v0.0.0.51_2018031901_YOCTO"
+#define VERSION "v0.0.0.52_2018070901_YOCTO"
 
 #define SDIO_HEADER_LEN                 4
 
@@ -224,6 +224,7 @@
 /*CHISR*/
 #define RX_PKT_LEN             0xFFFF0000
 #define FIRMWARE_INT             0x0000FE00
+#define FIRMWARE_INT_BIT15       0x00008000/*FW inform driver don't change to fw own for dore dump*/
 #define TX_FIFO_OVERFLOW         0x00000100
 #define FW_INT_IND_INDICATOR        0x00000080
 #define TX_COMPLETE_COUNT         0x00000070