Loading ipc/apr.c +143 −13 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ #include <linux/platform_device.h> #include <linux/sysfs.h> #include <linux/device.h> #include <linux/of.h> #include <linux/slab.h> #include <linux/ipc_logging.h> #include <soc/qcom/subsystem_restart.h> Loading @@ -42,7 +43,6 @@ static void *apr_pkt_ctx; static wait_queue_head_t dsp_wait; static wait_queue_head_t modem_wait; static bool is_modem_up; static bool is_initial_boot; /* Subsystem restart: QDSP6 data, functions */ static struct workqueue_struct *apr_reset_workqueue; static void apr_reset_deregister(struct work_struct *work); Loading @@ -52,6 +52,21 @@ struct apr_reset_work { struct work_struct work; }; struct apr_chld_device { struct platform_device *pdev; struct list_head node; }; struct apr_private { struct device *dev; spinlock_t apr_lock; bool is_initial_boot; struct work_struct add_chld_dev_work; spinlock_t apr_chld_lock; struct list_head apr_chlds; }; static struct apr_private *apr_priv; static bool apr_cf_debug; #ifdef CONFIG_DEBUG_FS Loading Loading @@ -275,15 +290,65 @@ enum apr_subsys_state apr_cmpxchg_q6_state(enum apr_subsys_state prev, static void apr_adsp_down(unsigned long opcode) { pr_debug("%s: Q6 is Down\n", __func__); apr_set_q6_state(APR_SUBSYS_DOWN); dispatch_event(opcode, APR_DEST_QDSP6); } static void apr_add_child_devices(struct work_struct *work) { int ret; struct device_node *node; struct platform_device *pdev; struct apr_chld_device *apr_chld_dev; for_each_child_of_node(apr_priv->dev->of_node, node) { apr_chld_dev = kzalloc(sizeof(*apr_chld_dev), GFP_KERNEL); if (!apr_chld_dev) continue; pdev = platform_device_alloc(node->name, -1); if (!pdev) { dev_err(apr_priv->dev, "%s: pdev memory alloc failed for %s\n", __func__, node->name); kfree(apr_chld_dev); continue; } pdev->dev.parent = apr_priv->dev; pdev->dev.of_node = node; ret = platform_device_add(pdev); if (ret) { dev_err(apr_priv->dev, "%s: Cannot add platform device %s\n", __func__, node->name); platform_device_put(pdev); kfree(apr_chld_dev); continue; } apr_chld_dev->pdev = pdev; spin_lock(&apr_priv->apr_chld_lock); list_add_tail(&apr_chld_dev->node, &apr_priv->apr_chlds); spin_unlock(&apr_priv->apr_chld_lock); dev_dbg(apr_priv->dev, "%s: Added APR child dev: %s\n", __func__, dev_name(&pdev->dev)); } } static void apr_adsp_up(void) { pr_debug("%s: Q6 is Up\n", __func__); if (apr_cmpxchg_q6_state(APR_SUBSYS_DOWN, APR_SUBSYS_LOADED) == APR_SUBSYS_DOWN) wake_up(&dsp_wait); spin_lock(&apr_priv->apr_lock); if (apr_priv->is_initial_boot) schedule_work(&apr_priv->add_chld_dev_work); spin_unlock(&apr_priv->apr_lock); } int apr_wait_for_device_up(int dest_id) Loading Loading @@ -1044,21 +1109,25 @@ static int apr_notifier_service_cb(struct notifier_block *this, * recovery notifications during initial boot * up since everything is expected to be down. */ if (is_initial_boot) { is_initial_boot = false; spin_lock(&apr_priv->apr_lock); if (apr_priv->is_initial_boot) { spin_unlock(&apr_priv->apr_lock); break; } spin_unlock(&apr_priv->apr_lock); if (cb_data->domain == AUDIO_NOTIFIER_MODEM_DOMAIN) apr_modem_down(opcode); else apr_adsp_down(opcode); break; case AUDIO_NOTIFIER_SERVICE_UP: is_initial_boot = false; if (cb_data->domain == AUDIO_NOTIFIER_MODEM_DOMAIN) apr_modem_up(); else apr_adsp_up(); spin_lock(&apr_priv->apr_lock); apr_priv->is_initial_boot = false; spin_unlock(&apr_priv->apr_lock); break; default: break; Loading Loading @@ -1092,13 +1161,43 @@ static int __init apr_debug_init(void) ) #endif static int __init apr_init(void) static void apr_cleanup(void) { int i, j, k; subsys_notif_deregister("apr_modem"); subsys_notif_deregister("apr_adsp"); if (apr_reset_workqueue) { flush_workqueue(apr_reset_workqueue); destroy_workqueue(apr_reset_workqueue); } mutex_destroy(&q6.lock); for (i = 0; i < APR_DEST_MAX; i++) { for (j = 0; j < APR_CLIENT_MAX; j++) { mutex_destroy(&client[i][j].m_lock); for (k = 0; k < APR_SVC_MAX; k++) mutex_destroy(&client[i][j].svc[k].m_lock); } } } static int apr_probe(struct platform_device *pdev) { int i, j, k; init_waitqueue_head(&dsp_wait); init_waitqueue_head(&modem_wait); apr_priv = devm_kzalloc(&pdev->dev, sizeof(*apr_priv), GFP_KERNEL); if (!apr_priv) return -ENOMEM; apr_priv->dev = &pdev->dev; spin_lock_init(&apr_priv->apr_lock); spin_lock_init(&apr_priv->apr_chld_lock); INIT_LIST_HEAD(&apr_priv->apr_chlds); INIT_WORK(&apr_priv->add_chld_dev_work, apr_add_child_devices); for (i = 0; i < APR_DEST_MAX; i++) for (j = 0; j < APR_CLIENT_MAX; j++) { mutex_init(&client[i][j].m_lock); Loading @@ -1110,15 +1209,19 @@ static int __init apr_init(void) apr_set_subsys_state(); mutex_init(&q6.lock); apr_reset_workqueue = create_singlethread_workqueue("apr_driver"); if (!apr_reset_workqueue) if (!apr_reset_workqueue) { apr_priv = NULL; return -ENOMEM; } apr_pkt_ctx = ipc_log_context_create(APR_PKT_IPC_LOG_PAGE_CNT, "apr", 0); if (!apr_pkt_ctx) pr_err("%s: Unable to create ipc log context\n", __func__); is_initial_boot = true; spin_lock(&apr_priv->apr_lock); apr_priv->is_initial_boot = true; spin_unlock(&apr_priv->apr_lock); subsys_notif_register("apr_adsp", AUDIO_NOTIFIER_ADSP_DOMAIN, &adsp_service_nb); subsys_notif_register("apr_modem", AUDIO_NOTIFIER_MODEM_DOMAIN, Loading @@ -1127,14 +1230,41 @@ static int __init apr_init(void) apr_tal_init(); return apr_debug_init(); } module_init(apr_init); void __exit apr_exit(void) static int apr_remove(struct platform_device *pdev) { subsys_notif_deregister("apr_modem"); subsys_notif_deregister("apr_adsp"); struct apr_chld_device *chld, *tmp; apr_cleanup(); apr_tal_exit(); spin_lock(&apr_priv->apr_chld_lock); list_for_each_entry_safe(chld, tmp, &apr_priv->apr_chlds, node) { platform_device_unregister(chld->pdev); list_del(&chld->node); kfree(chld); } spin_unlock(&apr_priv->apr_chld_lock); apr_priv = NULL; return 0; } static const struct of_device_id apr_machine_of_match[] = { { .compatible = "qcom,msm-audio-apr", }, {}, }; static struct platform_driver apr_driver = { .probe = apr_probe, .remove = apr_remove, .driver = { .name = "audio_apr", .owner = THIS_MODULE, .of_match_table = apr_machine_of_match, } module_exit(apr_exit); MODULE_DESCRIPTION("APR module"); }; module_platform_driver(apr_driver); MODULE_DESCRIPTION("APR DRIVER"); MODULE_LICENSE("GPL v2"); MODULE_DEVICE_TABLE(of, apr_machine_of_match); Loading
ipc/apr.c +143 −13 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ #include <linux/platform_device.h> #include <linux/sysfs.h> #include <linux/device.h> #include <linux/of.h> #include <linux/slab.h> #include <linux/ipc_logging.h> #include <soc/qcom/subsystem_restart.h> Loading @@ -42,7 +43,6 @@ static void *apr_pkt_ctx; static wait_queue_head_t dsp_wait; static wait_queue_head_t modem_wait; static bool is_modem_up; static bool is_initial_boot; /* Subsystem restart: QDSP6 data, functions */ static struct workqueue_struct *apr_reset_workqueue; static void apr_reset_deregister(struct work_struct *work); Loading @@ -52,6 +52,21 @@ struct apr_reset_work { struct work_struct work; }; struct apr_chld_device { struct platform_device *pdev; struct list_head node; }; struct apr_private { struct device *dev; spinlock_t apr_lock; bool is_initial_boot; struct work_struct add_chld_dev_work; spinlock_t apr_chld_lock; struct list_head apr_chlds; }; static struct apr_private *apr_priv; static bool apr_cf_debug; #ifdef CONFIG_DEBUG_FS Loading Loading @@ -275,15 +290,65 @@ enum apr_subsys_state apr_cmpxchg_q6_state(enum apr_subsys_state prev, static void apr_adsp_down(unsigned long opcode) { pr_debug("%s: Q6 is Down\n", __func__); apr_set_q6_state(APR_SUBSYS_DOWN); dispatch_event(opcode, APR_DEST_QDSP6); } static void apr_add_child_devices(struct work_struct *work) { int ret; struct device_node *node; struct platform_device *pdev; struct apr_chld_device *apr_chld_dev; for_each_child_of_node(apr_priv->dev->of_node, node) { apr_chld_dev = kzalloc(sizeof(*apr_chld_dev), GFP_KERNEL); if (!apr_chld_dev) continue; pdev = platform_device_alloc(node->name, -1); if (!pdev) { dev_err(apr_priv->dev, "%s: pdev memory alloc failed for %s\n", __func__, node->name); kfree(apr_chld_dev); continue; } pdev->dev.parent = apr_priv->dev; pdev->dev.of_node = node; ret = platform_device_add(pdev); if (ret) { dev_err(apr_priv->dev, "%s: Cannot add platform device %s\n", __func__, node->name); platform_device_put(pdev); kfree(apr_chld_dev); continue; } apr_chld_dev->pdev = pdev; spin_lock(&apr_priv->apr_chld_lock); list_add_tail(&apr_chld_dev->node, &apr_priv->apr_chlds); spin_unlock(&apr_priv->apr_chld_lock); dev_dbg(apr_priv->dev, "%s: Added APR child dev: %s\n", __func__, dev_name(&pdev->dev)); } } static void apr_adsp_up(void) { pr_debug("%s: Q6 is Up\n", __func__); if (apr_cmpxchg_q6_state(APR_SUBSYS_DOWN, APR_SUBSYS_LOADED) == APR_SUBSYS_DOWN) wake_up(&dsp_wait); spin_lock(&apr_priv->apr_lock); if (apr_priv->is_initial_boot) schedule_work(&apr_priv->add_chld_dev_work); spin_unlock(&apr_priv->apr_lock); } int apr_wait_for_device_up(int dest_id) Loading Loading @@ -1044,21 +1109,25 @@ static int apr_notifier_service_cb(struct notifier_block *this, * recovery notifications during initial boot * up since everything is expected to be down. */ if (is_initial_boot) { is_initial_boot = false; spin_lock(&apr_priv->apr_lock); if (apr_priv->is_initial_boot) { spin_unlock(&apr_priv->apr_lock); break; } spin_unlock(&apr_priv->apr_lock); if (cb_data->domain == AUDIO_NOTIFIER_MODEM_DOMAIN) apr_modem_down(opcode); else apr_adsp_down(opcode); break; case AUDIO_NOTIFIER_SERVICE_UP: is_initial_boot = false; if (cb_data->domain == AUDIO_NOTIFIER_MODEM_DOMAIN) apr_modem_up(); else apr_adsp_up(); spin_lock(&apr_priv->apr_lock); apr_priv->is_initial_boot = false; spin_unlock(&apr_priv->apr_lock); break; default: break; Loading Loading @@ -1092,13 +1161,43 @@ static int __init apr_debug_init(void) ) #endif static int __init apr_init(void) static void apr_cleanup(void) { int i, j, k; subsys_notif_deregister("apr_modem"); subsys_notif_deregister("apr_adsp"); if (apr_reset_workqueue) { flush_workqueue(apr_reset_workqueue); destroy_workqueue(apr_reset_workqueue); } mutex_destroy(&q6.lock); for (i = 0; i < APR_DEST_MAX; i++) { for (j = 0; j < APR_CLIENT_MAX; j++) { mutex_destroy(&client[i][j].m_lock); for (k = 0; k < APR_SVC_MAX; k++) mutex_destroy(&client[i][j].svc[k].m_lock); } } } static int apr_probe(struct platform_device *pdev) { int i, j, k; init_waitqueue_head(&dsp_wait); init_waitqueue_head(&modem_wait); apr_priv = devm_kzalloc(&pdev->dev, sizeof(*apr_priv), GFP_KERNEL); if (!apr_priv) return -ENOMEM; apr_priv->dev = &pdev->dev; spin_lock_init(&apr_priv->apr_lock); spin_lock_init(&apr_priv->apr_chld_lock); INIT_LIST_HEAD(&apr_priv->apr_chlds); INIT_WORK(&apr_priv->add_chld_dev_work, apr_add_child_devices); for (i = 0; i < APR_DEST_MAX; i++) for (j = 0; j < APR_CLIENT_MAX; j++) { mutex_init(&client[i][j].m_lock); Loading @@ -1110,15 +1209,19 @@ static int __init apr_init(void) apr_set_subsys_state(); mutex_init(&q6.lock); apr_reset_workqueue = create_singlethread_workqueue("apr_driver"); if (!apr_reset_workqueue) if (!apr_reset_workqueue) { apr_priv = NULL; return -ENOMEM; } apr_pkt_ctx = ipc_log_context_create(APR_PKT_IPC_LOG_PAGE_CNT, "apr", 0); if (!apr_pkt_ctx) pr_err("%s: Unable to create ipc log context\n", __func__); is_initial_boot = true; spin_lock(&apr_priv->apr_lock); apr_priv->is_initial_boot = true; spin_unlock(&apr_priv->apr_lock); subsys_notif_register("apr_adsp", AUDIO_NOTIFIER_ADSP_DOMAIN, &adsp_service_nb); subsys_notif_register("apr_modem", AUDIO_NOTIFIER_MODEM_DOMAIN, Loading @@ -1127,14 +1230,41 @@ static int __init apr_init(void) apr_tal_init(); return apr_debug_init(); } module_init(apr_init); void __exit apr_exit(void) static int apr_remove(struct platform_device *pdev) { subsys_notif_deregister("apr_modem"); subsys_notif_deregister("apr_adsp"); struct apr_chld_device *chld, *tmp; apr_cleanup(); apr_tal_exit(); spin_lock(&apr_priv->apr_chld_lock); list_for_each_entry_safe(chld, tmp, &apr_priv->apr_chlds, node) { platform_device_unregister(chld->pdev); list_del(&chld->node); kfree(chld); } spin_unlock(&apr_priv->apr_chld_lock); apr_priv = NULL; return 0; } static const struct of_device_id apr_machine_of_match[] = { { .compatible = "qcom,msm-audio-apr", }, {}, }; static struct platform_driver apr_driver = { .probe = apr_probe, .remove = apr_remove, .driver = { .name = "audio_apr", .owner = THIS_MODULE, .of_match_table = apr_machine_of_match, } module_exit(apr_exit); MODULE_DESCRIPTION("APR module"); }; module_platform_driver(apr_driver); MODULE_DESCRIPTION("APR DRIVER"); MODULE_LICENSE("GPL v2"); MODULE_DEVICE_TABLE(of, apr_machine_of_match);