qcacld-3.0: Move hdd_register_notifiers()/hdd_unregister_notifiers() calls

PM QoS notifier is not getting deregistered during module stop and is
racing with module start as a result. Move hdd_register_notifiers()
and hdd_unregister_notifiers() calls to hdd_wlan_start_module() and
hdd_wlan_stop_module() to do proper registration and de-registration.

Change-Id: I4d47393d600c2c162b54e16ecdf06b286f1b93bc
CRs-Fixed: 2626126
This commit is contained in:
Alan Chen 2020-02-20 12:05:02 -08:00 • committed by nshrivas
commit bc2dfe86c1

View file

@ -3325,6 +3325,184 @@ static void wlan_hdd_deinit_tx_rx_histogram(struct hdd_context *hdd_ctx)
hdd_ctx->hdd_txrx_hist = NULL;
}
#ifdef WLAN_NS_OFFLOAD
/**
* hdd_wlan_unregister_ip6_notifier() - unregister IPv6 change notifier
* @hdd_ctx: Pointer to hdd context
*
* Unregister for IPv6 address change notifications.
*
* Return: None
*/
static void hdd_wlan_unregister_ip6_notifier(struct hdd_context *hdd_ctx)
{
unregister_inet6addr_notifier(&hdd_ctx->ipv6_notifier);
}
/**
* hdd_wlan_register_ip6_notifier() - register IPv6 change notifier
* @hdd_ctx: Pointer to hdd context
*
* Register for IPv6 address change notifications.
*
* Return: 0 on success and errno on failure.
*/
static int hdd_wlan_register_ip6_notifier(struct hdd_context *hdd_ctx)
{
int ret;
hdd_ctx->ipv6_notifier.notifier_call = wlan_hdd_ipv6_changed;
ret = register_inet6addr_notifier(&hdd_ctx->ipv6_notifier);
if (ret) {
hdd_err("Failed to register IPv6 notifier: %d", ret);
goto out;
}
hdd_debug("Registered IPv6 notifier");
out:
return ret;
}
#else
/**
* hdd_wlan_unregister_ip6_notifier() - unregister IPv6 change notifier
* @hdd_ctx: Pointer to hdd context
*
* Unregister for IPv6 address change notifications.
*
* Return: None
*/
static void hdd_wlan_unregister_ip6_notifier(struct hdd_context *hdd_ctx)
{
}
/**
* hdd_wlan_register_ip6_notifier() - register IPv6 change notifier
* @hdd_ctx: Pointer to hdd context
*
* Register for IPv6 address change notifications.
*
* Return: None
*/
static int hdd_wlan_register_ip6_notifier(struct hdd_context *hdd_ctx)
{
return 0;
}
#endif
#ifdef FEATURE_RUNTIME_PM
/**
* hdd_wlan_register_pm_qos_notifier() - register PM QOS notifier
* @hdd_ctx: Pointer to hdd context
*
* Register for PM QOS change notifications.
*
* Return: None
*/
static int hdd_wlan_register_pm_qos_notifier(struct hdd_context *hdd_ctx)
{
int ret;
/* if gRuntimePM is 1 then feature is enabled without CXPC */
if (hdd_ctx->config->runtime_pm != hdd_runtime_pm_dynamic) {
hdd_debug("Dynamic Runtime PM disabled");
return 0;
}
qdf_spinlock_create(&hdd_ctx->pm_qos_lock);
hdd_ctx->pm_qos_notifier.notifier_call = wlan_hdd_pm_qos_notify;
ret = pm_qos_add_notifier(PM_QOS_CPU_DMA_LATENCY,
&hdd_ctx->pm_qos_notifier);
if (ret)
hdd_err("Failed to register PM_QOS notifier: %d", ret);
else
hdd_debug("PM QOS Notifier registered");
return ret;
}
/**
* hdd_wlan_unregister_pm_qos_notifier() - unregister PM QOS notifier
* @hdd_ctx: Pointer to hdd context
*
* Unregister for PM QOS change notifications.
*
* Return: None
*/
static void hdd_wlan_unregister_pm_qos_notifier(struct hdd_context *hdd_ctx)
{
int ret;
ret = pm_qos_remove_notifier(PM_QOS_CPU_DMA_LATENCY,
&hdd_ctx->pm_qos_notifier);
if (ret)
hdd_warn("Failed to remove qos notifier, err = %d\n", ret);
qdf_spin_lock_irqsave(&hdd_ctx->pm_qos_lock);
if (hdd_ctx->runtime_pm_prevented) {
pm_runtime_put_noidle(hdd_ctx->parent_dev);
hdd_ctx->runtime_pm_prevented = false;
}
qdf_spin_unlock_irqrestore(&hdd_ctx->pm_qos_lock);
}
#else
static int hdd_wlan_register_pm_qos_notifier(struct hdd_context *hdd_ctx)
{
return 0;
}
static void hdd_wlan_unregister_pm_qos_notifier(struct hdd_context *hdd_ctx)
{
}
#endif
/**
* hdd_register_notifiers - Register netdev notifiers.
* @hdd_ctx: HDD context
*
* Register netdev notifiers like IPv4 and IPv6.
*
* Return: 0 on success and errno on failure
*/
static int hdd_register_notifiers(struct hdd_context *hdd_ctx)
{
int ret;
ret = hdd_wlan_register_ip6_notifier(hdd_ctx);
if (ret)
goto out;
hdd_ctx->ipv4_notifier.notifier_call = wlan_hdd_ipv4_changed;
ret = register_inetaddr_notifier(&hdd_ctx->ipv4_notifier);
if (ret) {
hdd_err("Failed to register IPv4 notifier: %d", ret);
goto unregister_ip6_notifier;
}
ret = hdd_nud_register_netevent_notifier(hdd_ctx);
if (ret) {
hdd_err("Failed to register netevent notifier: %d",
ret);
goto unregister_inetaddr_notifier;
}
ret = hdd_wlan_register_pm_qos_notifier(hdd_ctx);
if (ret)
goto unregister_nud_notifier;
return 0;
unregister_nud_notifier:
hdd_nud_unregister_netevent_notifier(hdd_ctx);
unregister_inetaddr_notifier:
unregister_inetaddr_notifier(&hdd_ctx->ipv4_notifier);
unregister_ip6_notifier:
hdd_wlan_unregister_ip6_notifier(hdd_ctx);
out:
return ret;
}
int hdd_wlan_start_modules(struct hdd_context *hdd_ctx, bool reinit)
{
int ret = 0;
@ -3477,6 +3655,10 @@ int hdd_wlan_start_modules(struct hdd_context *hdd_ctx, bool reinit)
goto cds_txrx_free;
}
ret = hdd_register_notifiers(hdd_ctx);
if (ret)
goto deregister_cb;
/*
* NAN compoenet requires certian operations like, open adapter,
* close adapter, etc. to be initiated by HDD, for those
@ -3490,7 +3672,7 @@ int hdd_wlan_start_modules(struct hdd_context *hdd_ctx, bool reinit)
if (!QDF_IS_STATUS_SUCCESS(status)) {
hdd_err("Failed to pre-enable CDS; status: %d", status);
ret = qdf_status_to_os_return(status);
goto deregister_cb;
goto unregister_notifiers;
}
hdd_register_policy_manager_callback(
@ -3551,6 +3733,9 @@ destroy_driver_sysfs:
hdd_sysfs_destroy_driver_root_obj();
cds_post_disable();
unregister_notifiers:
hdd_unregister_notifiers(hdd_ctx);
deregister_cb:
hdd_deregister_cb(hdd_ctx);
@ -7622,70 +7807,6 @@ static QDF_STATUS hdd_abort_sched_scan_all_adapters(struct hdd_context *hdd_ctx)
return QDF_STATUS_SUCCESS;
}
#ifdef WLAN_NS_OFFLOAD
/**
* hdd_wlan_unregister_ip6_notifier() - unregister IPv6 change notifier
* @hdd_ctx: Pointer to hdd context
*
* Unregister for IPv6 address change notifications.
*
* Return: None
*/
static void hdd_wlan_unregister_ip6_notifier(struct hdd_context *hdd_ctx)
{
unregister_inet6addr_notifier(&hdd_ctx->ipv6_notifier);
}
/**
* hdd_wlan_register_ip6_notifier() - register IPv6 change notifier
* @hdd_ctx: Pointer to hdd context
*
* Register for IPv6 address change notifications.
*
* Return: 0 on success and errno on failure.
*/
static int hdd_wlan_register_ip6_notifier(struct hdd_context *hdd_ctx)
{
int ret;
hdd_ctx->ipv6_notifier.notifier_call = wlan_hdd_ipv6_changed;
ret = register_inet6addr_notifier(&hdd_ctx->ipv6_notifier);
if (ret) {
hdd_err("Failed to register IPv6 notifier: %d", ret);
goto out;
}
hdd_debug("Registered IPv6 notifier");
out:
return ret;
}
#else
/**
* hdd_wlan_unregister_ip6_notifier() - unregister IPv6 change notifier
* @hdd_ctx: Pointer to hdd context
*
* Unregister for IPv6 address change notifications.
*
* Return: None
*/
static void hdd_wlan_unregister_ip6_notifier(struct hdd_context *hdd_ctx)
{
}
/**
* hdd_wlan_register_ip6_notifier() - register IPv6 change notifier
* @hdd_ctx: Pointer to hdd context
*
* Register for IPv6 address change notifications.
*
* Return: None
*/
static int hdd_wlan_register_ip6_notifier(struct hdd_context *hdd_ctx)
{
return 0;
}
#endif
void hdd_set_disconnect_status(struct hdd_adapter *adapter, bool status)
{
qdf_mutex_acquire(&adapter->disconnection_status_lock);
@ -7693,120 +7814,6 @@ void hdd_set_disconnect_status(struct hdd_adapter *adapter, bool status)
qdf_mutex_release(&adapter->disconnection_status_lock);
}
#ifdef FEATURE_RUNTIME_PM
/**
* hdd_wlan_register_pm_qos_notifier() - register PM QOS notifier
* @hdd_ctx: Pointer to hdd context
*
* Register for PM QOS change notifications.
*
* Return: None
*/
static int hdd_wlan_register_pm_qos_notifier(struct hdd_context *hdd_ctx)
{
int ret;
/* if gRuntimePM is 1 then feature is enabled without CXPC */
if (hdd_ctx->config->runtime_pm != hdd_runtime_pm_dynamic) {
hdd_debug("Dynamic Runtime PM disabled");
return 0;
}
qdf_spinlock_create(&hdd_ctx->pm_qos_lock);
hdd_ctx->pm_qos_notifier.notifier_call = wlan_hdd_pm_qos_notify;
ret = pm_qos_add_notifier(PM_QOS_CPU_DMA_LATENCY,
&hdd_ctx->pm_qos_notifier);
if (ret)
hdd_err("Failed to register PM_QOS notifier: %d", ret);
else
hdd_debug("PM QOS Notifier registered");
return ret;
}
/**
* hdd_wlan_unregister_pm_qos_notifier() - unregister PM QOS notifier
* @hdd_ctx: Pointer to hdd context
*
* Unregister for PM QOS change notifications.
*
* Return: None
*/
static void hdd_wlan_unregister_pm_qos_notifier(struct hdd_context *hdd_ctx)
{
int ret;
ret = pm_qos_remove_notifier(PM_QOS_CPU_DMA_LATENCY,
&hdd_ctx->pm_qos_notifier);
if (ret)
hdd_warn("Failed to remove qos notifier, err = %d\n", ret);
qdf_spin_lock_irqsave(&hdd_ctx->pm_qos_lock);
if (hdd_ctx->runtime_pm_prevented) {
pm_runtime_put_noidle(hdd_ctx->parent_dev);
hdd_ctx->runtime_pm_prevented = false;
}
qdf_spin_unlock_irqrestore(&hdd_ctx->pm_qos_lock);
}
#else
static int hdd_wlan_register_pm_qos_notifier(struct hdd_context *hdd_ctx)
{
return 0;
}
static void hdd_wlan_unregister_pm_qos_notifier(struct hdd_context *hdd_ctx)
{
}
#endif
/**
* hdd_register_notifiers - Register netdev notifiers.
* @hdd_ctx: HDD context
*
* Register netdev notifiers like IPv4 and IPv6.
*
* Return: 0 on success and errno on failure
*/
static int hdd_register_notifiers(struct hdd_context *hdd_ctx)
{
int ret;
ret = hdd_wlan_register_ip6_notifier(hdd_ctx);
if (ret)
goto out;
hdd_ctx->ipv4_notifier.notifier_call = wlan_hdd_ipv4_changed;
ret = register_inetaddr_notifier(&hdd_ctx->ipv4_notifier);
if (ret) {
hdd_err("Failed to register IPv4 notifier: %d", ret);
goto unregister_ip6_notifier;
}
ret = hdd_nud_register_netevent_notifier(hdd_ctx);
if (ret) {
hdd_err("Failed to register netevent notifier: %d",
ret);
goto unregister_inetaddr_notifier;
}
ret = hdd_wlan_register_pm_qos_notifier(hdd_ctx);
if (ret)
goto unregister_nud_notifier;
return 0;
unregister_nud_notifier:
hdd_nud_unregister_netevent_notifier(hdd_ctx);
unregister_inetaddr_notifier:
unregister_inetaddr_notifier(&hdd_ctx->ipv4_notifier);
unregister_ip6_notifier:
hdd_wlan_unregister_ip6_notifier(hdd_ctx);
out:
return ret;
}
/**
* hdd_unregister_notifiers - Unregister netdev notifiers.
* @hdd_ctx: HDD context
@ -8010,8 +8017,6 @@ void hdd_wlan_exit(struct hdd_context *hdd_ctx)
hdd_debugfs_mws_coex_info_deinit(hdd_ctx);
hdd_psoc_idle_timer_stop(hdd_ctx);
hdd_unregister_notifiers(hdd_ctx);
/*
* Powersave Offload Case
* Disable Idle Power Save Mode
@ -12534,6 +12539,7 @@ int hdd_wlan_stop_modules(struct hdd_context *hdd_ctx, bool ftm_mode)
QDF_ASSERT(0);
}
hdd_unregister_notifiers(hdd_ctx);
/* De-register the SME callbacks */
hdd_deregister_cb(hdd_ctx);
@ -13104,10 +13110,6 @@ int hdd_wlan_startup(struct hdd_context *hdd_ctx)
hdd_lpass_notify_wlan_version(hdd_ctx);
errno = hdd_register_notifiers(hdd_ctx);
if (errno)
goto unregister_netdev;
status = wlansap_global_init();
if (QDF_IS_STATUS_ERROR(status))
goto unregister_notifiers;
@ -13123,9 +13125,6 @@ int hdd_wlan_startup(struct hdd_context *hdd_ctx)
return 0;
unregister_notifiers:
hdd_unregister_notifiers(hdd_ctx);
unregister_netdev:
unregister_netdevice_notifier(&hdd_netdev_notifier);
unregister_wiphy: