Loading drivers/mailbox/msm_qmp.c +66 −3 Original line number Diff line number Diff line /* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. /* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -168,6 +168,7 @@ struct qmp_mbox { struct completion ch_complete; struct delayed_work dwork; struct qmp_device *mdev; bool suspend_flag; }; /** Loading Loading @@ -208,6 +209,7 @@ struct qmp_device { u32 rx_irq_count; void *ilc; bool early_boot; }; /** Loading Loading @@ -376,8 +378,14 @@ static int qmp_send_data(struct mbox_chan *chan, void *data) unsigned long flags; int i; if (!mbox || !data || mbox->local_state != CHANNEL_CONNECTED) if (!mbox || !data) return -EINVAL; /* * Return -EAGAIN if client tried to send data after hibernation * and channel is not yet opened */ if (!completion_done(&mbox->ch_complete)) return -EAGAIN; mdev = mbox->mdev; Loading Loading @@ -568,6 +576,16 @@ static void __qmp_rx_worker(struct qmp_mbox *mbox) mbox->local_state = LINK_CONNECTED; complete_all(&mbox->link_complete); QMP_INFO(mdev->ilc, "Set to link connected\n"); /* * If link connection happened after hibernation * manualy trigger the channel open procedure since client * won't try to re-open the channel */ if (mbox->suspend_flag == true) { set_mcore_ch(mbox, QMP_MBOX_CH_CONNECTED); mbox->local_state = LOCAL_CONNECTING; send_irq(mbox->mdev); } break; case LINK_CONNECTED: if (desc.ucore.ch_state == desc.ucore.ch_state_ack) { Loading Loading @@ -851,6 +869,7 @@ static int qmp_mbox_init(struct device_node *n, struct qmp_device *mdev) mbox->tx_sent = false; mbox->num_assigned = 0; INIT_DELAYED_WORK(&mbox->dwork, qmp_notify_timeout); mbox->suspend_flag = false; mdev_add_mbox(mdev, mbox); return 0; Loading Loading @@ -938,6 +957,8 @@ static int qmp_mbox_probe(struct platform_device *pdev) if (ret) return ret; dev_set_drvdata(&pdev->dev, mdev); mdev->ilc = ipc_log_context_create(QMP_IPC_LOG_PAGE_CNT, mdev->name, 0); kthread_init_work(&mdev->kwork, rx_worker); Loading @@ -960,12 +981,53 @@ static int qmp_mbox_probe(struct platform_device *pdev) mdev->rx_irq_line, ret); /* Trigger fake RX in case of missed interrupt */ if (of_property_read_bool(edge_node, "qcom,early-boot")) if (of_property_read_bool(edge_node, "qcom,early-boot")) { mdev->early_boot = true; qmp_irq_handler(0, mdev); } return 0; } static int qmp_mbox_suspend(struct device *dev) { struct qmp_device *mdev = dev_get_drvdata(dev); struct qmp_mbox *mbox; list_for_each_entry(mbox, &mdev->mboxes, list) { mbox->local_state = LINK_DISCONNECTED; init_completion(&mbox->link_complete); init_completion(&mbox->ch_complete); mbox->tx_sent = false; /* * set suspend flag to indicate self channel open is required * after restore operation */ mbox->suspend_flag = true; /* Release rx packet buffer */ if (mbox->rx_pkt.data) { devm_kfree(mdev->dev, mbox->rx_pkt.data); mbox->rx_pkt.data = NULL; } } return 0; } static int qmp_mbox_resume(struct device *dev) { struct qmp_device *mdev = dev_get_drvdata(dev); if (mdev->early_boot) qmp_irq_handler(0, mdev); return 0; } static const struct dev_pm_ops qmp_mbox_pm_ops = { .freeze = qmp_mbox_suspend, .restore = qmp_mbox_resume, }; static struct platform_driver qmp_mbox_driver = { .probe = qmp_mbox_probe, .remove = qmp_mbox_remove, Loading @@ -973,6 +1035,7 @@ static struct platform_driver qmp_mbox_driver = { .name = "qmp_mbox", .owner = THIS_MODULE, .of_match_table = qmp_mbox_match_table, .pm = &qmp_mbox_pm_ops, }, }; Loading Loading
drivers/mailbox/msm_qmp.c +66 −3 Original line number Diff line number Diff line /* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. /* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -168,6 +168,7 @@ struct qmp_mbox { struct completion ch_complete; struct delayed_work dwork; struct qmp_device *mdev; bool suspend_flag; }; /** Loading Loading @@ -208,6 +209,7 @@ struct qmp_device { u32 rx_irq_count; void *ilc; bool early_boot; }; /** Loading Loading @@ -376,8 +378,14 @@ static int qmp_send_data(struct mbox_chan *chan, void *data) unsigned long flags; int i; if (!mbox || !data || mbox->local_state != CHANNEL_CONNECTED) if (!mbox || !data) return -EINVAL; /* * Return -EAGAIN if client tried to send data after hibernation * and channel is not yet opened */ if (!completion_done(&mbox->ch_complete)) return -EAGAIN; mdev = mbox->mdev; Loading Loading @@ -568,6 +576,16 @@ static void __qmp_rx_worker(struct qmp_mbox *mbox) mbox->local_state = LINK_CONNECTED; complete_all(&mbox->link_complete); QMP_INFO(mdev->ilc, "Set to link connected\n"); /* * If link connection happened after hibernation * manualy trigger the channel open procedure since client * won't try to re-open the channel */ if (mbox->suspend_flag == true) { set_mcore_ch(mbox, QMP_MBOX_CH_CONNECTED); mbox->local_state = LOCAL_CONNECTING; send_irq(mbox->mdev); } break; case LINK_CONNECTED: if (desc.ucore.ch_state == desc.ucore.ch_state_ack) { Loading Loading @@ -851,6 +869,7 @@ static int qmp_mbox_init(struct device_node *n, struct qmp_device *mdev) mbox->tx_sent = false; mbox->num_assigned = 0; INIT_DELAYED_WORK(&mbox->dwork, qmp_notify_timeout); mbox->suspend_flag = false; mdev_add_mbox(mdev, mbox); return 0; Loading Loading @@ -938,6 +957,8 @@ static int qmp_mbox_probe(struct platform_device *pdev) if (ret) return ret; dev_set_drvdata(&pdev->dev, mdev); mdev->ilc = ipc_log_context_create(QMP_IPC_LOG_PAGE_CNT, mdev->name, 0); kthread_init_work(&mdev->kwork, rx_worker); Loading @@ -960,12 +981,53 @@ static int qmp_mbox_probe(struct platform_device *pdev) mdev->rx_irq_line, ret); /* Trigger fake RX in case of missed interrupt */ if (of_property_read_bool(edge_node, "qcom,early-boot")) if (of_property_read_bool(edge_node, "qcom,early-boot")) { mdev->early_boot = true; qmp_irq_handler(0, mdev); } return 0; } static int qmp_mbox_suspend(struct device *dev) { struct qmp_device *mdev = dev_get_drvdata(dev); struct qmp_mbox *mbox; list_for_each_entry(mbox, &mdev->mboxes, list) { mbox->local_state = LINK_DISCONNECTED; init_completion(&mbox->link_complete); init_completion(&mbox->ch_complete); mbox->tx_sent = false; /* * set suspend flag to indicate self channel open is required * after restore operation */ mbox->suspend_flag = true; /* Release rx packet buffer */ if (mbox->rx_pkt.data) { devm_kfree(mdev->dev, mbox->rx_pkt.data); mbox->rx_pkt.data = NULL; } } return 0; } static int qmp_mbox_resume(struct device *dev) { struct qmp_device *mdev = dev_get_drvdata(dev); if (mdev->early_boot) qmp_irq_handler(0, mdev); return 0; } static const struct dev_pm_ops qmp_mbox_pm_ops = { .freeze = qmp_mbox_suspend, .restore = qmp_mbox_resume, }; static struct platform_driver qmp_mbox_driver = { .probe = qmp_mbox_probe, .remove = qmp_mbox_remove, Loading @@ -973,6 +1035,7 @@ static struct platform_driver qmp_mbox_driver = { .name = "qmp_mbox", .owner = THIS_MODULE, .of_match_table = qmp_mbox_match_table, .pm = &qmp_mbox_pm_ops, }, }; Loading