Loading drivers/soc/qcom/smp2p.c +100 −6 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2015, Sony Mobile Communications AB. * Copyright (c) 2012-2013, 2018-2019 The Linux Foundation. All rights reserved. * Copyright (c) 2012-2013, 2018-2020 The Linux Foundation. All rights reserved. */ #include <linux/interrupt.h> Loading Loading @@ -632,7 +632,7 @@ static int qcom_smp2p_probe(struct platform_device *pdev) goto release_mbox; for_each_available_child_of_node(pdev->dev.of_node, node) { entry = devm_kzalloc(&pdev->dev, sizeof(*entry), GFP_KERNEL); entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) { ret = -ENOMEM; goto unwind_interfaces; Loading Loading @@ -686,11 +686,15 @@ static int qcom_smp2p_probe(struct platform_device *pdev) wakeup_source_unregister(smp2p->ws); unwind_interfaces: list_for_each_entry(entry, &smp2p->inbound, node) list_for_each_entry(entry, &smp2p->inbound, node) { irq_domain_remove(entry->domain); kfree(entry); } list_for_each_entry(entry, &smp2p->outbound, node) list_for_each_entry(entry, &smp2p->outbound, node) { qcom_smem_state_unregister(entry->state); kfree(entry); } smp2p->out->valid_entries = 0; Loading @@ -711,11 +715,15 @@ static int qcom_smp2p_remove(struct platform_device *pdev) wakeup_source_unregister(smp2p->ws); list_for_each_entry(entry, &smp2p->inbound, node) list_for_each_entry(entry, &smp2p->inbound, node) { irq_domain_remove(entry->domain); kfree(entry); } list_for_each_entry(entry, &smp2p->outbound, node) list_for_each_entry(entry, &smp2p->outbound, node) { qcom_smem_state_unregister(entry->state); kfree(entry); } mbox_free_channel(smp2p->mbox_chan); Loading @@ -724,6 +732,91 @@ static int qcom_smp2p_remove(struct platform_device *pdev) return 0; } static int qcom_smp2p_restore(struct device *dev) { int ret = 0; struct qcom_smp2p *smp2p = dev_get_drvdata(dev); struct smp2p_entry *entry; struct device_node *node; struct platform_device *pdev = container_of(dev, struct platform_device, dev); ret = qcom_smp2p_alloc_outbound_item(smp2p); if (ret < 0) goto print_err; for_each_available_child_of_node(pdev->dev.of_node, node) { entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) { ret = -ENOMEM; goto print_err; } entry->smp2p = smp2p; spin_lock_init(&entry->lock); ret = of_property_read_string(node, "qcom,entry-name", &entry->name); if (ret < 0) goto rel_entry; if (!of_property_read_bool(node, "interrupt-controller")) { ret = qcom_smp2p_outbound_entry(smp2p, entry, node); if (ret < 0) goto rel_entry; list_add(&entry->node, &smp2p->outbound); } else { kfree(entry); } } smp2p->ws = wakeup_source_register(&pdev->dev, "smp2p"); enable_irq_wake(smp2p->irq); /* Kick the outgoing edge after allocating entries */ qcom_smp2p_kick(smp2p); rel_entry: kfree(entry); print_err: if (ret < 0 && ret != -EEXIST) dev_err(dev, "failed to alloc items ret = %d\n", ret); return ret; } static int qcom_smp2p_freeze(struct device *dev) { struct qcom_smp2p *smp2p = dev_get_drvdata(dev); struct smp2p_entry *entry; struct smp2p_entry *next_entry; disable_irq_wake(smp2p->irq); /* Walk through the out bound list and release state and entry */ list_for_each_entry_safe(entry, next_entry, &smp2p->outbound, node) { qcom_smem_state_unregister(entry->state); list_del(&entry->node); kfree(entry); } INIT_LIST_HEAD(&smp2p->outbound); /* Walk through the in bound list and reset last value */ list_for_each_entry_safe(entry, next_entry, &smp2p->inbound, node) { entry->last_value = 0; } /* make null to point it to valid smem item during first interrupt */ smp2p->in = NULL; smp2p->valid_entries = 0; /* remove wakeup source */ wakeup_source_unregister(smp2p->ws); return 0; } static const struct dev_pm_ops qcom_smp2p_pm_ops = { .freeze = qcom_smp2p_freeze, .restore = qcom_smp2p_restore, .thaw = qcom_smp2p_restore, }; static const struct of_device_id qcom_smp2p_of_match[] = { { .compatible = "qcom,smp2p" }, {} Loading @@ -736,6 +829,7 @@ static struct platform_driver qcom_smp2p_driver = { .driver = { .name = "qcom_smp2p", .of_match_table = qcom_smp2p_of_match, .pm = &qcom_smp2p_pm_ops, }, }; module_platform_driver(qcom_smp2p_driver); Loading Loading
drivers/soc/qcom/smp2p.c +100 −6 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2015, Sony Mobile Communications AB. * Copyright (c) 2012-2013, 2018-2019 The Linux Foundation. All rights reserved. * Copyright (c) 2012-2013, 2018-2020 The Linux Foundation. All rights reserved. */ #include <linux/interrupt.h> Loading Loading @@ -632,7 +632,7 @@ static int qcom_smp2p_probe(struct platform_device *pdev) goto release_mbox; for_each_available_child_of_node(pdev->dev.of_node, node) { entry = devm_kzalloc(&pdev->dev, sizeof(*entry), GFP_KERNEL); entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) { ret = -ENOMEM; goto unwind_interfaces; Loading Loading @@ -686,11 +686,15 @@ static int qcom_smp2p_probe(struct platform_device *pdev) wakeup_source_unregister(smp2p->ws); unwind_interfaces: list_for_each_entry(entry, &smp2p->inbound, node) list_for_each_entry(entry, &smp2p->inbound, node) { irq_domain_remove(entry->domain); kfree(entry); } list_for_each_entry(entry, &smp2p->outbound, node) list_for_each_entry(entry, &smp2p->outbound, node) { qcom_smem_state_unregister(entry->state); kfree(entry); } smp2p->out->valid_entries = 0; Loading @@ -711,11 +715,15 @@ static int qcom_smp2p_remove(struct platform_device *pdev) wakeup_source_unregister(smp2p->ws); list_for_each_entry(entry, &smp2p->inbound, node) list_for_each_entry(entry, &smp2p->inbound, node) { irq_domain_remove(entry->domain); kfree(entry); } list_for_each_entry(entry, &smp2p->outbound, node) list_for_each_entry(entry, &smp2p->outbound, node) { qcom_smem_state_unregister(entry->state); kfree(entry); } mbox_free_channel(smp2p->mbox_chan); Loading @@ -724,6 +732,91 @@ static int qcom_smp2p_remove(struct platform_device *pdev) return 0; } static int qcom_smp2p_restore(struct device *dev) { int ret = 0; struct qcom_smp2p *smp2p = dev_get_drvdata(dev); struct smp2p_entry *entry; struct device_node *node; struct platform_device *pdev = container_of(dev, struct platform_device, dev); ret = qcom_smp2p_alloc_outbound_item(smp2p); if (ret < 0) goto print_err; for_each_available_child_of_node(pdev->dev.of_node, node) { entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) { ret = -ENOMEM; goto print_err; } entry->smp2p = smp2p; spin_lock_init(&entry->lock); ret = of_property_read_string(node, "qcom,entry-name", &entry->name); if (ret < 0) goto rel_entry; if (!of_property_read_bool(node, "interrupt-controller")) { ret = qcom_smp2p_outbound_entry(smp2p, entry, node); if (ret < 0) goto rel_entry; list_add(&entry->node, &smp2p->outbound); } else { kfree(entry); } } smp2p->ws = wakeup_source_register(&pdev->dev, "smp2p"); enable_irq_wake(smp2p->irq); /* Kick the outgoing edge after allocating entries */ qcom_smp2p_kick(smp2p); rel_entry: kfree(entry); print_err: if (ret < 0 && ret != -EEXIST) dev_err(dev, "failed to alloc items ret = %d\n", ret); return ret; } static int qcom_smp2p_freeze(struct device *dev) { struct qcom_smp2p *smp2p = dev_get_drvdata(dev); struct smp2p_entry *entry; struct smp2p_entry *next_entry; disable_irq_wake(smp2p->irq); /* Walk through the out bound list and release state and entry */ list_for_each_entry_safe(entry, next_entry, &smp2p->outbound, node) { qcom_smem_state_unregister(entry->state); list_del(&entry->node); kfree(entry); } INIT_LIST_HEAD(&smp2p->outbound); /* Walk through the in bound list and reset last value */ list_for_each_entry_safe(entry, next_entry, &smp2p->inbound, node) { entry->last_value = 0; } /* make null to point it to valid smem item during first interrupt */ smp2p->in = NULL; smp2p->valid_entries = 0; /* remove wakeup source */ wakeup_source_unregister(smp2p->ws); return 0; } static const struct dev_pm_ops qcom_smp2p_pm_ops = { .freeze = qcom_smp2p_freeze, .restore = qcom_smp2p_restore, .thaw = qcom_smp2p_restore, }; static const struct of_device_id qcom_smp2p_of_match[] = { { .compatible = "qcom,smp2p" }, {} Loading @@ -736,6 +829,7 @@ static struct platform_driver qcom_smp2p_driver = { .driver = { .name = "qcom_smp2p", .of_match_table = qcom_smp2p_of_match, .pm = &qcom_smp2p_pm_ops, }, }; module_platform_driver(qcom_smp2p_driver); Loading