Merge "msm: sdio: Add tests for the new SDIO_CSVT channel." into msm-3.0
diff --git a/arch/arm/mach-msm/sdio_al_test.c b/arch/arm/mach-msm/sdio_al_test.c
index 9653b9a..bc48821 100644
--- a/arch/arm/mach-msm/sdio_al_test.c
+++ b/arch/arm/mach-msm/sdio_al_test.c
@@ -60,6 +60,7 @@
 #define A2_MIN_PACKET_SIZE 5
 #define RMNT_PACKET_SIZE (4*1024)
 #define DUN_PACKET_SIZE (2*1024)
+#define CSVT_PACKET_SIZE 1700
 
 #define TEST_DBG(x...) if (test_ctx->runtime_debug) pr_info(x)
 
@@ -70,6 +71,9 @@
 #define LPM_TEST_CONFIG_SIGNATURE 0xDEADBABE
 #define LPM_MSG_NAME_SIZE 20
 #define MAX_STR_SIZE	10
+#define MAX_AVG_RTT_TIME_USEC	2500
+#define SDIO_RMNT_RTT_PACKET_SIZE	32
+#define SDIO_CSVT_RTT_PACKET_SIZE	1900
 
 #define A2_HEADER_OVERHEAD 8
 
@@ -143,6 +147,7 @@
 	SDIO_DUN,
 	SDIO_SMEM,
 	SDIO_CIQ,
+	SDIO_CSVT,
 	SDIO_MAX_CHANNELS
 };
 
@@ -240,6 +245,7 @@
 	struct dentry *dun_a2_validation_test;
 	struct dentry *rmnet_a2_perf_test;
 	struct dentry *dun_a2_perf_test;
+	struct dentry *csvt_a2_perf_test;
 	struct dentry *rmnet_dun_a2_perf_test;
 	struct dentry *rpc_sender_rmnet_a2_perf_test;
 	struct dentry *all_channels_test;
@@ -247,6 +253,7 @@
 	struct dentry *host_sender_no_lp_diag_rpc_ciq_test;
 	struct dentry *rmnet_small_packets_test;
 	struct dentry *rmnet_rtt_test;
+	struct dentry *csvt_rtt_test;
 	struct dentry *modem_reset_rpc_test;
 	struct dentry *modem_reset_rmnet_test;
 	struct dentry *modem_reset_channels_4bit_dev_test;
@@ -337,6 +344,11 @@
 {
 	int i = 0;
 
+	if (!test_ctx) {
+		pr_err(TEST_MODULE_NAME ":%s - test_ctx is NULL.\n", __func__);
+		return;
+	}
+
 	for (i = 0 ; i < MAX_NUM_OF_SDIO_DEVICES ; ++i)
 		test_ctx->test_dev_arr[i].sdio_al_device = NULL;
 
@@ -937,6 +949,74 @@
 	.read = dun_a2_perf_test_read,
 };
 
+/* CSVT A2 PERFORMANCE TEST */
+static ssize_t csvt_a2_perf_test_write(struct file *file,
+					const char __user *buf,
+					size_t count,
+					loff_t *ppos)
+{
+	int ret = 0;
+	int i = 0;
+	int number = -1;
+
+	pr_info(TEST_MODULE_NAME "-- CSVT A2 PERFORMANCE TEST --\n");
+
+	number = sdio_al_test_extract_number(buf, count);
+
+	if (number < 0) {
+		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
+		       "failed. number = %d\n", __func__, number);
+		return count;
+	}
+
+	for (i = 0 ; i < number ; ++i) {
+		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
+		pr_info(TEST_MODULE_NAME " ===================");
+
+		sdio_al_test_initial_dev_and_chan(test_ctx);
+
+		set_params_a2_perf(test_ctx->test_ch_arr[SDIO_CSVT]);
+
+		ret = test_start();
+
+		if (ret)
+			break;
+	}
+
+	return count;
+}
+
+static ssize_t csvt_a2_perf_test_read(struct file *file,
+				       char __user *buffer,
+				       size_t count,
+				       loff_t *offset)
+{
+	memset((void *)buffer, 0, count);
+
+	snprintf(buffer, count,
+		 "\nCSVT_A2_PERFORMANCE_TEST\n"
+		 "========================\n"
+		 "Description:\n"
+		 "Loopback test on the CSVT Channel, in order to check "
+		 "throughput performance.\n"
+		 "Packet size that are sent on the CSVT channel in this "
+		 "test is %d.bytes\n\n"
+		 "END OF DESCRIPTION\n", CSVT_PACKET_SIZE);
+
+	if (message_repeat == 1) {
+		message_repeat = 0;
+		return strnlen(buffer, count);
+	} else {
+		return 0;
+	}
+}
+
+const struct file_operations csvt_a2_perf_test_ops = {
+	.open = sdio_al_test_open,
+	.write = csvt_a2_perf_test_write,
+	.read = csvt_a2_perf_test_read,
+};
+
 /* RMNET DUN A2 PERFORMANCE TEST */
 static ssize_t rmnet_dun_a2_perf_test_write(struct file *file,
 					     const char __user *buf,
@@ -1101,6 +1181,7 @@
 		set_params_a2_perf(test_ctx->test_ch_arr[SDIO_DUN]);
 		set_params_smem_test(test_ctx->test_ch_arr[SDIO_SMEM]);
 		set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_CIQ]);
+		set_params_a2_perf(test_ctx->test_ch_arr[SDIO_CSVT]);
 
 		ret = test_start();
 
@@ -1399,6 +1480,72 @@
 	.read = rmnet_rtt_test_read,
 };
 
+/* CSVT RTT TEST */
+static ssize_t csvt_rtt_test_write(struct file *file,
+				    const char __user *buf,
+				    size_t count,
+				    loff_t *ppos)
+{
+	int ret = 0;
+	int i = 0;
+	int number = -1;
+
+	pr_info(TEST_MODULE_NAME "-- CSVT RTT TEST --");
+
+	number = sdio_al_test_extract_number(buf, count);
+
+	if (number < 0) {
+		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
+		       "failed. number = %d\n", __func__, number);
+		return count;
+	}
+
+	for (i = 0 ; i < number ; ++i) {
+		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
+		pr_info(TEST_MODULE_NAME " ===================");
+
+		sdio_al_test_initial_dev_and_chan(test_ctx);
+
+		set_params_rtt(test_ctx->test_ch_arr[SDIO_CSVT]);
+
+		ret = test_start();
+
+		if (ret)
+			break;
+	}
+
+	return count;
+}
+
+static ssize_t csvt_rtt_test_read(struct file *file,
+				   char __user *buffer,
+				   size_t count,
+				   loff_t *offset)
+{
+	memset((void *)buffer, 0, count);
+
+	snprintf(buffer, count,
+		 "\nCSVT_RTT_TEST\n"
+		 "==============\n"
+		 "Description:\n"
+		 "In this test the HOST send a message of %d bytes "
+		 "to the CLIENT\n\n"
+		 "END OF DESCRIPTION\n", SDIO_CSVT_RTT_PACKET_SIZE);
+
+	if (message_repeat == 1) {
+		message_repeat = 0;
+		return strnlen(buffer, count);
+	} else {
+		return 0;
+	}
+}
+
+const struct file_operations csvt_rtt_test_ops = {
+	.open = sdio_al_test_open,
+	.write = csvt_rtt_test_write,
+	.read = csvt_rtt_test_read,
+};
+
 /* MODEM RESET RPC TEST */
 static ssize_t modem_reset_rpc_test_write(struct file *file,
 					   const char __user *buf,
@@ -1768,6 +1915,7 @@
 		set_params_loopback_9k_close(ch_arr[SDIO_QMI]);
 		set_params_loopback_9k_close(ch_arr[SDIO_RMNT]);
 		set_params_loopback_9k_close(ch_arr[SDIO_DUN]);
+		set_params_loopback_9k_close(ch_arr[SDIO_CSVT]);
 
 		ret = test_start();
 
@@ -1803,7 +1951,8 @@
 		 "following sequence: Send a random burst of packets on "
 		 "Diag, CIQ and Rmnet channels, read 0 or a random number "
 		 "of packets, close and re-open the channel. At the end of the "
-		 "test, the channel is verified by running a loopback test\n");
+		 "test, the channel is verified by running a loopback test\n\n"
+		 "END OF DESCRIPTION\n");
 
 	if (message_repeat == 1) {
 		message_repeat = 0;
@@ -1873,7 +2022,8 @@
 		 "In this test the host sends 5k packets to the modem in the "
 		 "following sequence: Send a random burst of packets on "
 		 "DUN and Rmnet channels, read 0 or a random number "
-		 "of packets, close and re-open the channel.\n");
+		 "of packets, close and re-open the channel.\n\n"
+		 "END OF DESCRIPTION\n");
 
 	if (message_repeat == 1) {
 		message_repeat = 0;
@@ -2345,6 +2495,13 @@
 				    NULL,
 				    &dun_a2_perf_test_ops);
 
+	test_ctx->debug.csvt_a2_perf_test =
+		debugfs_create_file("71_csvt_a2_perf_test",
+				    S_IRUGO | S_IWUGO,
+				    test_ctx->debug.debug_root,
+				    NULL,
+				    &csvt_a2_perf_test_ops);
+
 	test_ctx->debug.rmnet_dun_a2_perf_test =
 		debugfs_create_file("70_rmnet_dun_a2_perf_test",
 				    S_IRUGO | S_IWUGO,
@@ -2408,6 +2565,13 @@
 				     NULL,
 				     &rmnet_rtt_test_ops);
 
+	test_ctx->debug.csvt_rtt_test =
+		debugfs_create_file("191_csvt_rtt_test",
+				     S_IRUGO | S_IWUGO,
+				     test_ctx->debug.debug_root,
+				     NULL,
+				     &csvt_rtt_test_ops);
+
 	test_ctx->debug.modem_reset_rpc_test =
 		debugfs_create_file("220_modem_reset_rpc_test",
 				     S_IRUGO | S_IWUGO,
@@ -2535,6 +2699,9 @@
 	else if (!strncmp(name, "SDIO_CIQ_TEST",
 			  strnlen("SDIO_CIQ_TEST", TEST_CH_NAME_SIZE)))
 		return SDIO_CIQ;
+	else if (!strncmp(name, "SDIO_CSVT_TEST",
+			  strnlen("SDIO_CSVT_TEST", TEST_CH_NAME_SIZE)))
+		return SDIO_CSVT;
 	else
 		return SDIO_MAX_CHANNELS;
 
@@ -4095,10 +4262,17 @@
 		   total_bytes , (int) time_msec, test_ch->name);
 
 	if (!test_ch->random_packet_size) {
-		throughput = (total_bytes / time_msec) * 8 / 1000;
-		pr_err(TEST_MODULE_NAME ":Performance = %d Mbit/sec for "
-					"chan %s\n",
-		       throughput, test_ch->name);
+		if (time_msec) {
+			throughput = (total_bytes / time_msec) * 8 / 1000;
+			pr_err(TEST_MODULE_NAME ": %s - Performance = "
+			       "%d Mbit/sec for chan %s\n",
+			       __func__, throughput, test_ch->name);
+		} else {
+			pr_err(TEST_MODULE_NAME ": %s - time_msec = 0 Couldn't "
+			       "calculate performence for chan %s\n",
+			   __func__, test_ch->name);
+		}
+
 	}
 
 #ifdef CONFIG_DEBUG_FS
@@ -4199,10 +4373,10 @@
 	u32 write_avail = 0;
 	int tx_packet_count = 0;
 	int rx_packet_count = 0;
-	u16 *buf16 = (u16 *) test_ch->buf;
+	u16 *buf16 = NULL;
 	int i;
-	int max_packets = test_ch->config_msg.num_packets;
-	u32 packet_size = test_ch->packet_length;
+	int max_packets = 0;
+	u32 packet_size = 0;
 	s64 start_time, end_time;
 	int delta_usec = 0;
 	int time_average = 0;
@@ -4210,6 +4384,24 @@
 	int max_delta_usec = 0;
 	int total_time = 0;
 	int expected_read_size = 0;
+	int delay_ms = 0;
+	int slow_rtt_counter = 0;
+	int read_avail_so_far = 0;
+
+	if (test_ch) {
+		/*
+		 * Cleanup the pending RX data (such as loopback of the
+		 * config msg)
+		 */
+		rx_cleanup(test_ch, &rx_packet_count);
+		rx_packet_count = 0;
+	} else {
+		return;
+	}
+
+	max_packets = test_ch->config_msg.num_packets;
+	packet_size = test_ch->packet_length;
+	buf16 = (u16 *) test_ch->buf;
 
 	for (i = 0; i < packet_size / 2; i++)
 		buf16[i] = (u16) (i & 0xFFFF);
@@ -4217,9 +4409,18 @@
 	pr_info(TEST_MODULE_NAME ": A2 RTT TEST START for chan %s\n",
 		test_ch->name);
 
-	/* Cleanup the pending RX data (such as loopback of te config msg) */
-	rx_cleanup(test_ch, &rx_packet_count);
-	rx_packet_count = 0;
+	switch (test_ch->ch_id) {
+	case SDIO_RMNT:
+		delay_ms = 100;
+		break;
+	case SDIO_CSVT:
+		delay_ms = 0;
+		break;
+	default:
+		pr_err(TEST_MODULE_NAME ": %s - ch_id invalid.\n",
+		       __func__);
+		return;
+	}
 
 	while (tx_packet_count < max_packets) {
 		if (test_ctx->exit_flag) {
@@ -4228,11 +4429,10 @@
 		}
 		start_time = 0;
 		end_time = 0;
+		read_avail_so_far = 0;
 
-		/* Allow sdio_al to go to sleep to change the read_threshold
-		 *  to 1
-		 */
-		msleep(100);
+		if (delay_ms)
+			msleep(delay_ms);
 
 		/* wait for data ready event */
 		write_avail = sdio_write_avail(test_ch->ch);
@@ -4272,38 +4472,53 @@
 
 		expected_read_size = packet_size + A2_HEADER_OVERHEAD;
 
-		read_avail = sdio_read_avail(test_ch->ch);
-		TEST_DBG(TEST_MODULE_NAME ":channel %s, read_avail=%d\n",
-			 test_ch->name, read_avail);
-		while (read_avail < expected_read_size) {
-			wait_event(test_ch->wait_q,
-				   atomic_read(&test_ch->rx_notify_count));
-			atomic_dec(&test_ch->rx_notify_count);
-			read_avail = sdio_read_avail(test_ch->ch);
-		}
+		while (read_avail_so_far < expected_read_size) {
 
-		if (read_avail >= expected_read_size) {
-			pr_debug(TEST_MODULE_NAME ":read_avail=%d for ch %s.\n",
-				 read_avail, test_ch->name);
+			read_avail = sdio_read_avail(test_ch->ch);
+
+			if (!read_avail) {
+				wait_event(test_ch->wait_q,
+					   atomic_read(&test_ch->
+						       rx_notify_count));
+
+				atomic_dec(&test_ch->rx_notify_count);
+				continue;
+			}
+
+			read_avail_so_far += read_avail;
+
+			if (read_avail_so_far > expected_read_size) {
+				pr_err(TEST_MODULE_NAME ": %s - Invalid "
+				       "read_avail(%d)  read_avail_so_far(%d) "
+				       "can't be larger than "
+				       "expected_read_size(%d).",
+				       __func__,
+				       read_avail,
+				       read_avail_so_far,
+				       expected_read_size);
+				goto exit_err;
+			}
+
+			/*
+			 * must read entire pending bytes, so later, we will
+			 * get a notification when more data arrives
+			 */
 			ret = sdio_read(test_ch->ch, test_ch->buf,
-					expected_read_size);
+					read_avail);
+
 			if (ret) {
 				pr_info(TEST_MODULE_NAME ": sdio_read size %d "
 					" err=%d for chan %s\n",
-					expected_read_size, -ret,
+					read_avail, -ret,
 					test_ch->name);
 				goto exit_err;
 			}
-			end_time = ktime_to_us(ktime_get());
-			rx_packet_count++;
-			test_ch->rx_bytes += expected_read_size;
-		} else {
-				pr_info(TEST_MODULE_NAME ": Invalid read_avail "
-							 "%d for chan %s\n",
-					read_avail, test_ch->name);
-				goto exit_err;
 		}
 
+		end_time = ktime_to_us(ktime_get());
+		rx_packet_count++;
+		test_ch->rx_bytes += expected_read_size;
+
 		delta_usec = (int)(end_time - start_time);
 		total_time += delta_usec;
 		if (delta_usec < min_delta_usec)
@@ -4311,24 +4526,47 @@
 		if (delta_usec > max_delta_usec)
 				max_delta_usec = delta_usec;
 
+		/* checking the RTT per channel criteria */
+		if (delta_usec > MAX_AVG_RTT_TIME_USEC) {
+			pr_err(TEST_MODULE_NAME ": %s - "
+			       "msg # %d - rtt time (%d usec) is "
+			       "longer than %d usec\n",
+			       __func__,
+			       tx_packet_count,
+			       delta_usec,
+			       MAX_AVG_RTT_TIME_USEC);
+			slow_rtt_counter++;
+		}
+
 		TEST_DBG(TEST_MODULE_NAME
 			 ":RTT time=%d for packet #%d for chan %s\n",
 			 delta_usec, tx_packet_count, test_ch->name);
-
 	} /* while (tx_packet_count < max_packets ) */
 
+	pr_info(TEST_MODULE_NAME ": %s - tx_packet_count = %d\n",
+		__func__, tx_packet_count);
 
-	pr_info(TEST_MODULE_NAME ":total rx bytes = 0x%x , rx_packet#=%d for"
-				 " chan %s.\n",
-		test_ch->rx_bytes, rx_packet_count, test_ch->name);
-	pr_info(TEST_MODULE_NAME ":total tx bytes = 0x%x , tx_packet#=%d"
-				 " for chan %s.\n",
-		test_ch->tx_bytes, tx_packet_count, test_ch->name);
+	pr_info(TEST_MODULE_NAME ": %s - total rx bytes = 0x%x, "
+		"rx_packet# = %d for chan %s.\n",
+		__func__, test_ch->rx_bytes, rx_packet_count, test_ch->name);
 
-	time_average = total_time / tx_packet_count;
+	pr_info(TEST_MODULE_NAME ": %s - total tx bytes = 0x%x, "
+		"tx_packet# = %d for chan %s.\n",
+		__func__, test_ch->tx_bytes, tx_packet_count, test_ch->name);
 
-	pr_info(TEST_MODULE_NAME ":Average RTT time = %d for chan %s\n",
+	pr_info(TEST_MODULE_NAME ": %s - slow_rtt_counter = %d for "
+		"chan %s.\n",
+		__func__, slow_rtt_counter, test_ch->name);
+
+	if (tx_packet_count) {
+		time_average = total_time / tx_packet_count;
+		pr_info(TEST_MODULE_NAME ":Average RTT time = %d for chan %s\n",
 		   time_average, test_ch->name);
+	} else {
+		pr_err(TEST_MODULE_NAME ": %s - tx_packet_count=0. couldn't "
+		       "calculate average rtt time", __func__);
+	}
+
 	pr_info(TEST_MODULE_NAME ":MIN RTT time = %d for chan %s\n",
 		   min_delta_usec, test_ch->name);
 	pr_info(TEST_MODULE_NAME ":MAX RTT time = %d for chan %s\n",
@@ -4337,6 +4575,17 @@
 	pr_info(TEST_MODULE_NAME ": A2 RTT TEST END for chan %s.\n",
 	       test_ch->name);
 
+	if (ret)
+		goto exit_err;
+
+	if (time_average == 0 || time_average > MAX_AVG_RTT_TIME_USEC) {
+		pr_err(TEST_MODULE_NAME ": %s - average_time = %d. Invalid "
+		       "value",
+		       __func__, time_average);
+		goto exit_err;
+
+	}
+
 	pr_info(TEST_MODULE_NAME ": TEST PASS for chan %s\n", test_ch->name);
 	test_ch->test_completed = 1;
 	test_ch->test_result = TEST_PASSED;
@@ -4351,7 +4600,6 @@
 	return;
 }
 
-
 /**
  * Process Rx Data - Helper for A2 Validation Test
  * @test_ch(in/out) : Test channel that contains Rx data buffer to process.
@@ -5599,11 +5847,22 @@
 	tch->test_type = SDIO_TEST_PERF;
 	tch->config_msg.signature = TEST_CONFIG_SIGNATURE;
 	tch->config_msg.test_case = SDIO_TEST_LOOPBACK_CLIENT;
-	tch->packet_length = MAX_XFER_SIZE;
-	if (tch->ch_id == SDIO_DIAG)
+
+	switch (tch->ch_id) {
+	case SDIO_DIAG:
 		tch->packet_length = 512;
-	else if (tch->ch_id == SDIO_DUN)
-			tch->packet_length = DUN_PACKET_SIZE;
+		break;
+	case SDIO_DUN:
+		tch->packet_length = DUN_PACKET_SIZE;
+		break;
+	case SDIO_CSVT:
+		tch->packet_length = CSVT_PACKET_SIZE;
+		break;
+	default:
+		tch->packet_length = MAX_XFER_SIZE;
+		break;
+	}
+
 	pr_info(TEST_MODULE_NAME ": %s: packet_length=%d", __func__,
 			tch->packet_length);
 
@@ -5626,7 +5885,21 @@
 	tch->test_type = SDIO_TEST_RTT;
 	tch->config_msg.signature = TEST_CONFIG_SIGNATURE;
 	tch->config_msg.test_case = SDIO_TEST_LOOPBACK_CLIENT;
-	tch->packet_length = 32;
+
+	switch (tch->ch_id) {
+	case SDIO_RMNT:
+		tch->packet_length = SDIO_RMNT_RTT_PACKET_SIZE;
+		break;
+	case SDIO_CSVT:
+		tch->packet_length = SDIO_CSVT_RTT_PACKET_SIZE;
+		break;
+	default:
+		pr_err(TEST_MODULE_NAME ": %s - ch_id invalid.\n", __func__);
+		return -EINVAL;
+	}
+
+	pr_info(TEST_MODULE_NAME ": %s: packet_length=%d", __func__,
+			tch->packet_length);
 
 	tch->config_msg.num_packets = 200;
 	tch->config_msg.num_iterations = 1;
@@ -5816,6 +6089,12 @@
 	struct test_channel *tch = NULL;
 	tch = test_ctx->test_ch_arr[channel_num];
 
+	if (!tch) {
+		pr_info(TEST_MODULE_NAME ":%s ch#%d is NULL\n",
+			__func__, channel_num);
+		return 0;
+	}
+
 	ret = open_sdio_ch(tch);
 	if (ret) {
 		pr_err(TEST_MODULE_NAME":%s open channel %s"
@@ -6108,6 +6387,15 @@
 	},
 };
 
+static struct platform_driver sdio_csvt_drv = {
+	.probe		= sdio_test_channel_probe,
+	.remove		= sdio_test_channel_remove,
+	.driver		= {
+		.name	= "SDIO_CSVT_TEST",
+		.owner	= THIS_MODULE,
+	},
+};
+
 static struct class *test_class;
 
 const struct file_operations test_fops = {
@@ -6177,6 +6465,7 @@
 	platform_driver_register(&sdio_rmnt_drv);
 	platform_driver_register(&sdio_dun_drv);
 	platform_driver_register(&sdio_ciq_drv);
+	platform_driver_register(&sdio_csvt_drv);
 
 	return ret;
 }
@@ -6205,6 +6494,7 @@
 	platform_driver_unregister(&sdio_rmnt_drv);
 	platform_driver_unregister(&sdio_dun_drv);
 	platform_driver_unregister(&sdio_ciq_drv);
+	platform_driver_unregister(&sdio_csvt_drv);
 
 	for (i = 0; i < SDIO_MAX_CHANNELS; i++) {
 		struct test_channel *tch = test_ctx->test_ch_arr[i];