Просмотр исходного кода

qcacld-3.0: Cleanup handling of dynamic mode switching

Cleanup all the interfaces in the present mode before
switching to new mode. Also add support to comeback into
MISSION_MODE from other modes, Set the load/unload flags
during the con_mode switching.

Change-Id: I03f7ec5d27c536ec1a3046d49d34ec421490e0bc
CRs-Fixed: 1075546
Arun Khandavalli 8 лет назад
Родитель
Сommit
16fd1ee609
1 измененных файлов с 175 добавлено и 60 удалено
  1. 175 60
      core/hdd/src/wlan_hdd_main.c

+ 175 - 60
core/hdd/src/wlan_hdd_main.c

@@ -3209,6 +3209,7 @@ hdd_adapter_t *hdd_open_adapter(hdd_context_t *hdd_ctx, uint8_t session_type,
 	case QDF_P2P_DEVICE_MODE:
 	case QDF_OCB_MODE:
 	case QDF_NDI_MODE:
+	case QDF_MONITOR_MODE:
 		adapter = hdd_alloc_station_adapter(hdd_ctx, macAddr,
 						    name_assign_type,
 						    iface_name);
@@ -3223,6 +3224,8 @@ hdd_adapter_t *hdd_open_adapter(hdd_context_t *hdd_ctx, uint8_t session_type,
 			adapter->wdev.iftype = NL80211_IFTYPE_P2P_CLIENT;
 		else if (QDF_P2P_DEVICE_MODE == session_type)
 			adapter->wdev.iftype = NL80211_IFTYPE_P2P_DEVICE;
+		else if (QDF_MONITOR_MODE == session_type)
+			adapter->wdev.iftype = NL80211_IFTYPE_MONITOR;
 		else
 			adapter->wdev.iftype = NL80211_IFTYPE_STATION;
 
@@ -3290,6 +3293,27 @@ hdd_adapter_t *hdd_open_adapter(hdd_context_t *hdd_ctx, uint8_t session_type,
 					     WLAN_NETIF_TX_DISABLE_N_CARRIER,
 					     WLAN_CONTROL_PATH);
 		break;
+	case QDF_FTM_MODE:
+		adapter = hdd_alloc_station_adapter(hdd_ctx, macAddr,
+						    name_assign_type,
+						    "wlan0");
+		if (NULL == adapter) {
+			hdd_err("Failed to allocate adapter for FTM mode");
+			return NULL;
+		}
+		adapter->wdev.iftype = NL80211_IFTYPE_STATION;
+		adapter->device_mode = session_type;
+		status = hdd_register_interface(adapter, rtnl_held);
+		if (QDF_STATUS_SUCCESS != status) {
+			hdd_deinit_adapter(hdd_ctx, adapter, rtnl_held);
+			goto err_free_netdev;
+		}
+		/* Stop the Interface TX queue. */
+		hdd_info("Disabling queues");
+		wlan_hdd_netif_queue_control(adapter,
+					     WLAN_NETIF_TX_DISABLE_N_CARRIER,
+					     WLAN_CONTROL_PATH);
+		break;
 	default:
 		hdd_alert("Invalid session type %d", session_type);
 		QDF_ASSERT(0);
@@ -3390,6 +3414,7 @@ QDF_STATUS hdd_close_adapter(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter,
 		/* Fw will take care incase of concurrency */
 		return QDF_STATUS_SUCCESS;
 	}
+
 	return QDF_STATUS_E_FAILURE;
 }
 
@@ -3412,9 +3437,14 @@ QDF_STATUS hdd_close_all_adapters(hdd_context_t *hdd_ctx, bool rtnl_held)
 	do {
 		status = hdd_remove_front_adapter(hdd_ctx, &pHddAdapterNode);
 		if (pHddAdapterNode && QDF_STATUS_SUCCESS == status) {
+			wlan_hdd_release_intf_addr(hdd_ctx,
+			pHddAdapterNode->pAdapter->macAddressCurrent.bytes);
 			hdd_cleanup_adapter(hdd_ctx, pHddAdapterNode->pAdapter,
 					    rtnl_held);
 			qdf_mem_free(pHddAdapterNode);
+			/* Adapter removed. Decrement vdev count */
+			if (hdd_ctx->current_intf_count != 0)
+				hdd_ctx->current_intf_count--;
 		}
 	} while (NULL != pHddAdapterNode && QDF_STATUS_E_EMPTY != status);
 
@@ -9229,6 +9259,7 @@ static bool is_con_mode_valid(enum tQDF_GLOBAL_CON_MODE mode)
 	case QDF_GLOBAL_MONITOR_MODE:
 	case QDF_GLOBAL_FTM_MODE:
 	case QDF_GLOBAL_EPPING_MODE:
+	case QDF_GLOBAL_MISSION_MODE:
 		return true;
 	default:
 		return false;
@@ -9250,10 +9281,10 @@ static enum tQDF_ADAPTER_MODE hdd_get_adpter_mode(
 		return QDF_STA_MODE;
 	case QDF_GLOBAL_MONITOR_MODE:
 		return QDF_MONITOR_MODE;
-	case QDF_GLOBAL_FTM_MODE:
-		return QDF_FTM_MODE;
 	case QDF_GLOBAL_EPPING_MODE:
 		return QDF_EPPING_MODE;
+	case QDF_GLOBAL_FTM_MODE:
+		return QDF_FTM_MODE;
 	case QDF_GLOBAL_QVIT_MODE:
 		return QDF_QVIT_MODE;
 	default:
@@ -9261,6 +9292,87 @@ static enum tQDF_ADAPTER_MODE hdd_get_adpter_mode(
 	}
 }
 
+static void hdd_cleanup_present_mode(hdd_context_t *hdd_ctx,
+				    enum tQDF_GLOBAL_CON_MODE curr_mode)
+{
+	switch (curr_mode) {
+	case QDF_GLOBAL_MISSION_MODE:
+	case QDF_GLOBAL_MONITOR_MODE:
+	case QDF_GLOBAL_FTM_MODE:
+		hdd_abort_mac_scan_all_adapters(hdd_ctx);
+		hdd_stop_all_adapters(hdd_ctx);
+		hdd_deinit_all_adapters(hdd_ctx, false);
+		hdd_close_all_adapters(hdd_ctx, false);
+		break;
+	case QDF_GLOBAL_EPPING_MODE:
+		epping_disable();
+		epping_close();
+		break;
+	default:
+		return;
+	}
+}
+
+static int hdd_register_req_mode(hdd_context_t *hdd_ctx,
+				 enum tQDF_GLOBAL_CON_MODE mode)
+{
+	hdd_adapter_t *adapter;
+	int ret = 0;
+	bool rtnl_held;
+	qdf_device_t qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
+	QDF_STATUS status;
+
+	if (!qdf_dev) {
+		hdd_err("qdf device context is Null return!");
+		return -EINVAL;
+	}
+
+	rtnl_held = hdd_hold_rtnl_lock();
+	switch (mode) {
+	case QDF_GLOBAL_MISSION_MODE:
+		adapter = hdd_open_interfaces(hdd_ctx, rtnl_held);
+		if (IS_ERR(adapter)) {
+			hdd_alert("Failed to open interface, adapter is NULL");
+			ret = -EINVAL;
+		}
+		break;
+	case QDF_GLOBAL_FTM_MODE:
+		adapter = hdd_open_adapter(hdd_ctx, QDF_FTM_MODE, "wlan%d",
+					   wlan_hdd_get_intf_addr(hdd_ctx),
+					   NET_NAME_UNKNOWN, rtnl_held);
+		if (adapter == NULL)
+			ret = -EINVAL;
+		break;
+	case QDF_GLOBAL_MONITOR_MODE:
+		adapter = hdd_open_adapter(hdd_ctx, QDF_MONITOR_MODE, "wlan%d",
+					   wlan_hdd_get_intf_addr(hdd_ctx),
+					   NET_NAME_UNKNOWN, rtnl_held);
+		if (adapter == NULL)
+			ret = -EINVAL;
+		break;
+	case QDF_GLOBAL_EPPING_MODE:
+		status = epping_open();
+		 if (status != QDF_STATUS_SUCCESS) {
+			hdd_err("Failed to open in eeping mode: %d", status);
+			ret = -EINVAL;
+			break;
+		}
+		ret = epping_enable(qdf_dev->dev);
+		if (ret) {
+			hdd_err("Failed to enable in epping mode : %d", ret);
+			epping_close();
+		}
+		break;
+	default:
+		hdd_info("Mode not supported");
+		ret = -ENOTSUPP;
+		break;
+	}
+	hdd_release_rtnl_lock();
+	rtnl_held = false;
+	return ret;
+}
+
 /**
  * con_mode_handler() - Handles module param con_mode change
  * @kmessage: con mode name on which driver to be bring up
@@ -9271,101 +9383,104 @@ static enum tQDF_ADAPTER_MODE hdd_get_adpter_mode(
  *
  * Return - 0 on success and failure code on failure
  */
-static int con_mode_handler(const char *kmessage, struct kernel_param *kp)
+static int __con_mode_handler(const char *kmessage, struct kernel_param *kp,
+			      hdd_context_t *hdd_ctx)
 {
 	int ret;
-	hdd_context_t *hdd_ctx;
 	hdd_adapter_t *adapter;
-	qdf_device_t qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
 	enum tQDF_GLOBAL_CON_MODE curr_mode;
 	enum tQDF_ADAPTER_MODE adapter_mode;
-	QDF_STATUS status;
+
+	cds_set_load_in_progress(true);
 
 	hdd_info("con_mode handler: %s", kmessage);
 	ret = param_set_int(kmessage, kp);
 
-	if (!qdf_dev) {
-		hdd_err("qdf device context is Null return!");
-		return -EINVAL;
-	}
 
-	hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
-	if (!hdd_ctx) {
-		hdd_err("Hdd context Null return!");
-		return -EINVAL;
-	}
 
 	if (!(is_con_mode_valid(con_mode))) {
 		hdd_err("invlaid con_mode %d", con_mode);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto reset_flags;
 	}
+
 	curr_mode = hdd_get_conparam();
 	if (curr_mode == con_mode) {
 		hdd_err("curr mode: %d is same as user triggered mode %d",
 		       curr_mode, con_mode);
-		return 0;
-	}
-
-	adapter_mode = hdd_get_adpter_mode(curr_mode);
-	if (adapter_mode == QDF_MAX_NO_OF_MODE) {
-		hdd_err("invalid adapter");
-		return -EINVAL;
+		ret = 0;
+		goto reset_flags;
 	}
 
-	hdd_stop_all_adapters(hdd_ctx);
-	hdd_deinit_all_adapters(hdd_ctx, false);
+	/* Cleanup present mode before switching to new mode */
+	hdd_cleanup_present_mode(hdd_ctx, curr_mode);
 
 	ret = hdd_wlan_stop_modules(hdd_ctx);
 	if (ret) {
 		hdd_err("Stop wlan modules failed");
-		return -EINVAL;
+		goto reset_flags;
 	}
 
-	adapter = hdd_get_adapter(hdd_ctx, adapter_mode);
-	if (!adapter) {
-		hdd_err("Failed to get adapter, mode: %d", curr_mode);
-		return -EINVAL;
+	hdd_set_conparam(con_mode);
+
+	/* Register for new con_mode & then kick_start modules again */
+	ret = hdd_register_req_mode(hdd_ctx, con_mode);
+	if (ret) {
+		hdd_err("Failed to register for new mode");
+		goto reset_flags;
 	}
 
-	if (con_mode == QDF_GLOBAL_FTM_MODE) {
-		adapter->device_mode = QDF_FTM_MODE;
-		hdd_set_conparam(QDF_GLOBAL_FTM_MODE);
-	} else if (con_mode == QDF_GLOBAL_MONITOR_MODE) {
-		adapter->wdev.iftype = NL80211_IFTYPE_MONITOR;
-		adapter->device_mode = QDF_MONITOR_MODE;
-		hdd_set_conparam(QDF_GLOBAL_MONITOR_MODE);
-		hdd_set_station_ops(adapter->dev);
-	} else if (con_mode == QDF_GLOBAL_EPPING_MODE) {
-		hdd_set_conparam(QDF_GLOBAL_EPPING_MODE);
-		status = epping_open();
-		if (status != QDF_STATUS_SUCCESS) {
-			hdd_err("Failed to open in eeping mode: %d", status);
-			return -EINVAL;
-		}
-		ret = epping_enable(qdf_dev->dev);
-		if (ret) {
-			hdd_err("Failed to enable in epping mode : %d", ret);
-			epping_close();
-			return -EINVAL;
-		}
-		hdd_info("epping mode successfully enabled");
-		return 0;
+	adapter_mode = hdd_get_adpter_mode(con_mode);
+	if (adapter_mode == QDF_MAX_NO_OF_MODE) {
+		hdd_err("invalid adapter");
+		ret = -EINVAL;
+		goto reset_flags;
+	}
+
+	adapter = hdd_get_adapter(hdd_ctx, adapter_mode);
+	if (!adapter) {
+		hdd_err("Failed to get adapter:%d", adapter_mode);
+		goto reset_flags;
 	}
 
 	ret = hdd_wlan_start_modules(hdd_ctx, adapter, false);
 	if (ret) {
 		hdd_err("Start wlan modules failed: %d", ret);
-		return -EINVAL;
+		goto reset_flags;
 	}
 
-	if (hdd_start_adapter(adapter)) {
-		hdd_err("Failed to start %s adapter", kmessage);
-		return -EINVAL;
-	} else {
-		hdd_info("Mode successfully changed to %s", kmessage);
-		ret = 0;
+	if (con_mode == QDF_GLOBAL_MONITOR_MODE ||
+		con_mode == QDF_GLOBAL_FTM_MODE) {
+		if (hdd_start_adapter(adapter)) {
+			hdd_err("Failed to start %s adapter", kmessage);
+			ret = -EINVAL;
+			goto reset_flags;
+		}
 	}
 
+	hdd_info("Mode successfully changed to %s", kmessage);
+	ret = 0;
+
+reset_flags:
+	cds_set_load_in_progress(false);
+	return ret;
+}
+
+
+static int con_mode_handler(const char *kmessage, struct kernel_param *kp)
+{
+	int ret;
+	hdd_context_t *hdd_ctx;
+
+	hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
+	ret = wlan_hdd_validate_context(hdd_ctx);
+	if (ret)
+		return ret;
+
+	cds_ssr_protect(__func__);
+	ret = __con_mode_handler(kmessage, kp, hdd_ctx);
+	cds_ssr_unprotect(__func__);
+
 	return ret;
 }