From 623e7e358d44c343bb20b5c00594446cac99ac51 Mon Sep 17 00:00:00 2001 From: Dustin Brown Date: Wed, 5 Sep 2018 14:27:50 -0700 Subject: [PATCH] qcacld-3.0: Integrate DSC (psoc probe/remove) The Driver Synchronization Core (DSC) is a set of synchronization primitives for use by the driver's orchestration layer. It provides APIs for ensuring safe state transitions (including bring up and tear down) of major driver objects: a single driver, associated psocs, and their associated vdevs. As part of integrating the DSC APIs into HDD, protect psoc probe and remove. Change-Id: I5db13fb321695f535b5765c637ee638396e5ca6f CRs-Fixed: 2347016 --- core/hdd/inc/wlan_hdd_main.h | 47 +++++++++++- core/hdd/src/wlan_hdd_driver_ops.c | 109 +++++++++++++++++++++++--- core/hdd/src/wlan_hdd_main.c | 118 ++++++++++------------------- 3 files changed, 184 insertions(+), 90 deletions(-) diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index e91c29098acc..89b35421cf92 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -1716,14 +1716,35 @@ struct hdd_driver { struct hdd_driver *hdd_driver_get(void); +enum hdd_psoc_state { + psoc_state_uninit, + psoc_state_deinit, + psoc_state_active, /* historically "ENABLED" */ + psoc_state_idle, /* historically "CLOSED" */ +}; + +/** + * struct hdd_psoc - HDD psoc-level context information + * @hdd_driver: pointer to parent HDD driver context + * @dsc_psoc: driver synchronization psoc context handle + * @state: the current stable state of the psoc + */ +struct hdd_psoc { + struct hdd_driver *hdd_driver; + struct dsc_psoc *dsc_psoc; + enum hdd_psoc_state state; +}; + /** * struct hdd_context - hdd shared driver and psoc/device context + * @hdd_psoc: hdd psoc context * @psoc: object manager psoc context * @pdev: object manager pdev context * @g_event_flags: a bitmap of hdd_driver_flags * @psoc_idle_timeout_work: delayed work for psoc idle shutdown */ struct hdd_context { + struct hdd_psoc *hdd_psoc; struct wlan_objmgr_psoc *psoc; struct wlan_objmgr_pdev *pdev; mac_handle_t mac_handle; @@ -2391,12 +2412,11 @@ void hdd_deinit(void); /** * hdd_wlan_startup() - HDD init function - * @dev: pointer to the underlying device - * @out_hdd_ctx: output hdd context pointer for the newly created context + * hdd_ctx: the HDD context corresponding to the psoc to startup * * Return: Errno */ -int hdd_wlan_startup(struct device *dev, struct hdd_context **out_hdd_ctx); +int hdd_wlan_startup(struct hdd_context *hdd_ctx); /** * hdd_wlan_exit() - HDD WLAN exit function @@ -2414,6 +2434,27 @@ void hdd_wlan_exit(struct hdd_context *hdd_ctx); */ QDF_STATUS hdd_psoc_create_vdevs(struct hdd_context *hdd_ctx); +/* + * hdd_context_create() - Allocate and inialize HDD context. + * @dev: Device Pointer to the underlying device + * + * Allocate and initialize HDD context. HDD context is allocated as part of + * wiphy allocation and then context is initialized. + * + * Return: HDD context on success and ERR_PTR on failure + */ +struct hdd_context *hdd_context_create(struct device *dev); + +/** + * hdd_context_destroy() - Destroy HDD context + * @hdd_ctx: HDD context to be destroyed. + * + * Free config and HDD context as well as destroy all the resources. + * + * Return: None + */ +void hdd_context_destroy(struct hdd_context *hdd_ctx); + int hdd_wlan_notify_modem_power_state(int state); #ifdef QCA_HT_2040_COEX /** diff --git a/core/hdd/src/wlan_hdd_driver_ops.c b/core/hdd/src/wlan_hdd_driver_ops.c index d3e766e1a232..535a3cc6cb8b 100644 --- a/core/hdd/src/wlan_hdd_driver_ops.c +++ b/core/hdd/src/wlan_hdd_driver_ops.c @@ -356,6 +356,56 @@ static int check_for_probe_defer(int ret) } #endif +static QDF_STATUS hdd_psoc_ctx_create(struct hdd_psoc **out_hdd_psoc) +{ + QDF_STATUS status; + struct hdd_driver *hdd_driver = hdd_driver_get(); + struct hdd_psoc *hdd_psoc; + + QDF_BUG(out_hdd_psoc); + if (!out_hdd_psoc) + return QDF_STATUS_E_INVAL; + + hdd_psoc = qdf_mem_malloc(sizeof(*hdd_psoc)); + if (!hdd_psoc) + return QDF_STATUS_E_NOMEM; + + hdd_psoc->hdd_driver = hdd_driver; + hdd_psoc->state = psoc_state_uninit; + + status = dsc_psoc_create(hdd_driver->dsc_driver, &hdd_psoc->dsc_psoc); + if (QDF_IS_STATUS_ERROR(status)) + goto free_ctx; + + *out_hdd_psoc = hdd_psoc; + + return QDF_STATUS_SUCCESS; + +free_ctx: + qdf_mem_free(hdd_psoc); + + return status; +} + +static void hdd_psoc_ctx_destroy(struct hdd_psoc **out_hdd_psoc) +{ + struct hdd_psoc *hdd_psoc; + + QDF_BUG(out_hdd_psoc); + if (!out_hdd_psoc) + return; + + hdd_psoc = *out_hdd_psoc; + QDF_BUG(hdd_psoc); + if (!hdd_psoc) + return; + + *out_hdd_psoc = NULL; + + dsc_psoc_destroy(&hdd_psoc->dsc_psoc); + qdf_mem_free(hdd_psoc); +} + static void hdd_soc_load_lock(struct device *dev, int load_op) { mutex_lock(&hdd_init_deinit_lock); @@ -390,11 +440,23 @@ static int hdd_soc_probe(struct device *dev, enum qdf_bus_type bus_type) { struct hdd_context *hdd_ctx; + struct hdd_psoc *hdd_psoc; QDF_STATUS status; int errno; hdd_info("probing driver"); + status = hdd_psoc_ctx_create(&hdd_psoc); + if (QDF_IS_STATUS_ERROR(status)) + return qdf_status_to_os_return(status); + + status = dsc_psoc_trans_start(hdd_psoc->dsc_psoc, "probe"); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to start transition; probe, status:%u", status); + errno = qdf_status_to_os_return(status); + goto free_psoc; + } + hdd_soc_load_lock(dev, eHDD_DRV_OP_PROBE); cds_set_load_in_progress(true); cds_set_driver_in_bad_state(false); @@ -403,9 +465,17 @@ static int hdd_soc_probe(struct device *dev, if (errno) goto unlock; - errno = hdd_wlan_startup(dev, &hdd_ctx); - if (errno) + hdd_ctx = hdd_context_create(dev); + if (IS_ERR(hdd_ctx)) { + errno = PTR_ERR(hdd_ctx); goto assert_fail_count; + } + + hdd_ctx->hdd_psoc = hdd_psoc; + + errno = hdd_wlan_startup(hdd_ctx); + if (errno) + goto hdd_context_destroy; status = hdd_psoc_create_vdevs(hdd_ctx); if (QDF_IS_STATUS_ERROR(status)) { @@ -415,16 +485,22 @@ static int hdd_soc_probe(struct device *dev, probe_fail_cnt = 0; cds_set_driver_loaded(true); - hdd_start_complete(0); cds_set_load_in_progress(false); + hdd_start_complete(0); hdd_soc_load_unlock(dev); + hdd_psoc->state = psoc_state_active; + dsc_psoc_trans_stop(hdd_psoc->dsc_psoc); + return 0; wlan_exit: hdd_wlan_exit(hdd_ctx); +hdd_context_destroy: + hdd_context_destroy(hdd_ctx); + assert_fail_count: probe_fail_cnt++; hdd_err("consecutive probe failures:%u", probe_fail_cnt); @@ -434,6 +510,11 @@ unlock: cds_set_load_in_progress(false); hdd_soc_load_unlock(dev); + dsc_psoc_trans_stop(hdd_psoc->dsc_psoc); + +free_psoc: + hdd_psoc_ctx_destroy(&hdd_psoc); + return check_for_probe_defer(errno); } @@ -505,9 +586,16 @@ unlock: */ static void hdd_soc_remove(struct device *dev) { + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct hdd_psoc *hdd_psoc = hdd_ctx->hdd_psoc; + pr_info("%s: Removing driver v%s\n", WLAN_MODULE_NAME, QWLAN_VERSIONSTR); + /* remove is triggered by rmmod, so assert we are protected by rmmod */ + dsc_psoc_assert_trans_protected(hdd_psoc->dsc_psoc); + dsc_psoc_wait_for_ops(hdd_psoc->dsc_psoc); + cds_set_driver_loaded(false); cds_set_unload_in_progress(true); @@ -523,14 +611,8 @@ static void hdd_soc_remove(struct device *dev) epping_disable(); epping_close(); } else { - struct hdd_context *hdd_ctx; - - hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); - if (hdd_ctx) - hdd_wlan_exit(hdd_ctx); - else - hdd_err("invalid hdd context"); - + hdd_wlan_exit(hdd_ctx); + hdd_context_destroy(hdd_ctx); } hdd_stop_driver_ops_timer(); mutex_unlock(&hdd_init_deinit_lock); @@ -538,6 +620,11 @@ static void hdd_soc_remove(struct device *dev) cds_set_driver_in_bad_state(false); cds_set_unload_in_progress(false); + hdd_psoc->state = psoc_state_deinit; + dsc_psoc_assert_trans_protected(hdd_psoc->dsc_psoc); + + hdd_psoc_ctx_destroy(&hdd_psoc); + pr_info("%s: Driver De-initialized\n", WLAN_MODULE_NAME); } diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 91c183e65f44..46b744dcb0df 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -6876,18 +6876,11 @@ static int hdd_context_deinit(struct hdd_context *hdd_ctx) return 0; } -/** - * hdd_context_destroy() - Destroy HDD context - * @hdd_ctx: HDD context to be destroyed. - * - * Free config and HDD context as well as destroy all the resources. - * - * Return: None - */ -static void hdd_context_destroy(struct hdd_context *hdd_ctx) +void hdd_context_destroy(struct hdd_context *hdd_ctx) { cds_set_context(QDF_MODULE_ID_HDD, NULL); + hdd_exit_netlink_services(hdd_ctx); wlan_hdd_deinit_tx_rx_histogram(hdd_ctx); hdd_context_deinit(hdd_ctx); @@ -6896,7 +6889,6 @@ static void hdd_context_destroy(struct hdd_context *hdd_ctx) qdf_mem_free(hdd_ctx->config); hdd_ctx->config = NULL; - cfg_release(); wiphy_free(hdd_ctx->wiphy); @@ -7041,8 +7033,6 @@ void hdd_wlan_exit(struct hdd_context *hdd_ctx) #ifdef FEATURE_WLAN_CH_AVOID mutex_destroy(&hdd_ctx->avoid_freq_lock); #endif - - hdd_context_destroy(hdd_ctx); } #ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE @@ -9037,16 +9027,7 @@ static void hdd_cfg_params_init(struct hdd_context *hdd_ctx) hdd_dp_cfg_update(psoc, hdd_ctx); } -/** - * hdd_context_create() - Allocate and inialize HDD context. - * @dev: Device Pointer to the underlying device - * - * Allocate and initialize HDD context. HDD context is allocated as part of - * wiphy allocation and then context is initialized. - * - * Return: HDD context on success and ERR_PTR on failure - */ -static struct hdd_context *hdd_context_create(struct device *dev) +struct hdd_context *hdd_context_create(struct device *dev) { QDF_STATUS status; int ret = 0; @@ -11226,14 +11207,14 @@ void hdd_dp_trace_init(struct hdd_config *config) #endif #ifdef DISABLE_CHANNEL_LIST -static int wlan_hdd_cache_chann_mutex_create(struct hdd_context *hdd_ctx) +static QDF_STATUS wlan_hdd_cache_chann_mutex_create(struct hdd_context *hdd_ctx) { return qdf_mutex_create(&hdd_ctx->cache_channel_lock); } #else -static int wlan_hdd_cache_chann_mutex_create(struct hdd_context *hdd_ctx) +static QDF_STATUS wlan_hdd_cache_chann_mutex_create(struct hdd_context *hdd_ctx) { - return 0; + return QDF_STATUS_SUCCESS; } #endif @@ -11357,26 +11338,20 @@ static QDF_STATUS hdd_open_adapters_for_mode(struct hdd_context *hdd_ctx, return status; } -int hdd_wlan_startup(struct device *dev, struct hdd_context **out_hdd_ctx) +int hdd_wlan_startup(struct hdd_context *hdd_ctx) { QDF_STATUS status; - struct hdd_context *hdd_ctx; - int ret; - mac_handle_t mac_handle; + int errno; hdd_enter(); - hdd_ctx = hdd_context_create(dev); - if (IS_ERR(hdd_ctx)) - return PTR_ERR(hdd_ctx); - hdd_action_oui_config(hdd_ctx); qdf_nbuf_init_replenish_timer(); - ret = wlan_hdd_cache_chann_mutex_create(hdd_ctx); - if (QDF_IS_STATUS_ERROR(ret)) - goto err_hdd_free_context; + status = wlan_hdd_cache_chann_mutex_create(hdd_ctx); + if (QDF_IS_STATUS_ERROR(status)) + return qdf_status_to_os_return(status); #ifdef FEATURE_WLAN_CH_AVOID mutex_init(&hdd_ctx->avoid_freq_lock); @@ -11387,41 +11362,40 @@ int hdd_wlan_startup(struct device *dev, struct hdd_context **out_hdd_ctx) hdd_driver_memdump_init(); hdd_bus_bandwidth_init(hdd_ctx); - ret = hdd_wlan_start_modules(hdd_ctx, false); - if (ret) { - hdd_err("Failed to start modules: %d", ret); - goto err_memdump_deinit; + errno = hdd_wlan_start_modules(hdd_ctx, false); + if (errno) { + hdd_err("Failed to start modules; errno:%d", errno); + goto memdump_deinit; } wlan_hdd_update_wiphy(hdd_ctx); - mac_handle = cds_get_context(QDF_MODULE_ID_SME); - hdd_ctx->mac_handle = mac_handle; - if (!mac_handle) { + hdd_ctx->mac_handle = cds_get_context(QDF_MODULE_ID_SME); + if (!hdd_ctx->mac_handle) { hdd_err("Mac Handle is null"); - goto err_stop_modules; + goto stop_modules; } - ret = hdd_wiphy_init(hdd_ctx); - if (ret) { - hdd_err("Failed to initialize wiphy: %d", ret); - goto err_stop_modules; + errno = hdd_wiphy_init(hdd_ctx); + if (errno) { + hdd_err("Failed to initialize wiphy; errno:%d", errno); + goto stop_modules; } hdd_dp_trace_init(hdd_ctx->config); hdd_initialize_mac_address(hdd_ctx); - ret = register_netdevice_notifier(&hdd_netdev_notifier); - if (ret) { - hdd_err("register_netdevice_notifier failed: %d", ret); - goto err_wiphy_unregister; + errno = register_netdevice_notifier(&hdd_netdev_notifier); + if (errno) { + hdd_err("register_netdevice_notifier failed; errno:%d", errno); + goto unregister_wiphy; } - ret = register_reboot_notifier(&system_reboot_notifier); - if (ret) { - hdd_err("Failed to register reboot notifier: %d", ret); - goto err_unregister_netdev; + errno = register_reboot_notifier(&system_reboot_notifier); + if (errno) { + hdd_err("Failed to register reboot notifier; errno:%d", errno); + goto unregister_netdev; } wlan_hdd_update_11n_mode(hdd_ctx->config); @@ -11439,9 +11413,9 @@ int hdd_wlan_startup(struct device *dev, struct hdd_context **out_hdd_ctx) hdd_lpass_notify_wlan_version(hdd_ctx); - ret = hdd_register_notifiers(hdd_ctx); - if (ret) - goto err_close_adapters; + errno = hdd_register_notifiers(hdd_ctx); + if (errno) + goto unregister_reboot; status = wlansap_global_init(); if (QDF_IS_STATUS_ERROR(status)) @@ -11449,8 +11423,6 @@ int hdd_wlan_startup(struct device *dev, struct hdd_context **out_hdd_ctx) hdd_set_idle_ps_config(hdd_ctx, hdd_ctx->config->fIsImpsEnabled); - *out_hdd_ctx = hdd_ctx; - hdd_exit(); return 0; @@ -11458,40 +11430,33 @@ int hdd_wlan_startup(struct device *dev, struct hdd_context **out_hdd_ctx) unregister_notifiers: hdd_unregister_notifiers(hdd_ctx); -err_close_adapters: - hdd_close_all_adapters(hdd_ctx, false); - +unregister_reboot: unregister_reboot_notifier(&system_reboot_notifier); -err_unregister_netdev: +unregister_netdev: unregister_netdevice_notifier(&hdd_netdev_notifier); -err_wiphy_unregister: +unregister_wiphy: qdf_dp_trace_deinit(); wiphy_unregister(hdd_ctx->wiphy); -err_stop_modules: +stop_modules: hdd_wlan_stop_modules(hdd_ctx, false); -err_memdump_deinit: +memdump_deinit: hdd_bus_bandwidth_deinit(hdd_ctx); hdd_driver_memdump_deinit(); - osif_request_manager_deinit(); - hdd_exit_netlink_services(hdd_ctx); + qdf_nbuf_deinit_replenish_timer(); -err_hdd_free_context: if (cds_is_fw_down()) hdd_err("Not setting the complete event as fw is down"); else - hdd_start_complete(ret); - - qdf_nbuf_deinit_replenish_timer(); - hdd_context_destroy(hdd_ctx); + hdd_start_complete(errno); hdd_exit(); - return ret; + return errno; } QDF_STATUS hdd_psoc_create_vdevs(struct hdd_context *hdd_ctx) @@ -13049,6 +13014,7 @@ static void hdd_driver_unload(void) hdd_driver->state = driver_state_deinit; dsc_driver_trans_stop(hdd_driver->dsc_driver); + hdd_driver_ctx_deinit(hdd_driver); hdd_qdf_deinit();