aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSudeep Holla <sudeep.holla@arm.com>2017-07-31 10:43:27 -0400
committerSudeep Holla <sudeep.holla@arm.com>2018-02-28 11:37:57 -0500
commit907b6d14911db047e6e29979895d29daf2ec1e5f (patch)
tree26802fc7b0e8ed0453ac4b56dc0e59c7a3bd50ab
parentfbc4d81ad28545714a1e367963aaf2ffd9be5239 (diff)
firmware: arm_scmi: add per-protocol channels support using idr objects
In order to maintain the channel information per protocol, we need some sort of list or hashtable to hold all this information. IDR provides sparse array mapping of small integer ID numbers onto arbitrary pointers. In this case the arbitrary pointers can be pointers to the channel information. This patch adds support for per-protocol channels using those idr objects. Cc: Arnd Bergmann <arnd@arndb.de> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
-rw-r--r--drivers/firmware/arm_scmi/driver.c54
1 files changed, 42 insertions, 12 deletions
diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index 82171ec2b7a5..14b147135a0c 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -104,6 +104,7 @@ struct scmi_chan_info {
104 struct mbox_chan *chan; 104 struct mbox_chan *chan;
105 void __iomem *payload; 105 void __iomem *payload;
106 struct device *dev; 106 struct device *dev;
107 struct scmi_handle *handle;
107}; 108};
108 109
109/** 110/**
@@ -115,7 +116,7 @@ struct scmi_chan_info {
115 * @version: SCMI revision information containing protocol version, 116 * @version: SCMI revision information containing protocol version,
116 * implementation version and (sub-)vendor identification. 117 * implementation version and (sub-)vendor identification.
117 * @minfo: Message info 118 * @minfo: Message info
118 * @tx_cinfo: Reference to SCMI channel information 119 * @tx_idr: IDR object to map protocol id to channel info pointer
119 * @protocols_imp: list of protocols implemented, currently maximum of 120 * @protocols_imp: list of protocols implemented, currently maximum of
120 * MAX_PROTOCOLS_IMP elements allocated by the base protocol 121 * MAX_PROTOCOLS_IMP elements allocated by the base protocol
121 * @node: list head 122 * @node: list head
@@ -127,7 +128,7 @@ struct scmi_info {
127 struct scmi_revision_info version; 128 struct scmi_revision_info version;
128 struct scmi_handle handle; 129 struct scmi_handle handle;
129 struct scmi_xfers_info minfo; 130 struct scmi_xfers_info minfo;
130 struct scmi_chan_info *tx_cinfo; 131 struct idr tx_idr;
131 u8 *protocols_imp; 132 u8 *protocols_imp;
132 struct list_head node; 133 struct list_head node;
133 int users; 134 int users;
@@ -218,7 +219,7 @@ static void scmi_rx_callback(struct mbox_client *cl, void *m)
218 struct scmi_xfer *xfer; 219 struct scmi_xfer *xfer;
219 struct scmi_chan_info *cinfo = client_to_scmi_chan_info(cl); 220 struct scmi_chan_info *cinfo = client_to_scmi_chan_info(cl);
220 struct device *dev = cinfo->dev; 221 struct device *dev = cinfo->dev;
221 struct scmi_info *info = dev_get_drvdata(dev); 222 struct scmi_info *info = handle_to_scmi_info(cinfo->handle);
222 struct scmi_xfers_info *minfo = &info->minfo; 223 struct scmi_xfers_info *minfo = &info->minfo;
223 struct scmi_shared_mem __iomem *mem = cinfo->payload; 224 struct scmi_shared_mem __iomem *mem = cinfo->payload;
224 225
@@ -390,7 +391,11 @@ int scmi_do_xfer(const struct scmi_handle *handle, struct scmi_xfer *xfer)
390 int timeout; 391 int timeout;
391 struct scmi_info *info = handle_to_scmi_info(handle); 392 struct scmi_info *info = handle_to_scmi_info(handle);
392 struct device *dev = info->dev; 393 struct device *dev = info->dev;
393 struct scmi_chan_info *cinfo = info->tx_cinfo; 394 struct scmi_chan_info *cinfo;
395
396 cinfo = idr_find(&info->tx_idr, xfer->hdr.protocol_id);
397 if (unlikely(!cinfo))
398 return -EINVAL;
394 399
395 ret = mbox_send_message(cinfo->chan, xfer); 400 ret = mbox_send_message(cinfo->chan, xfer);
396 if (ret < 0) { 401 if (ret < 0) {
@@ -657,13 +662,18 @@ static int scmi_mailbox_check(struct device_node *np)
657 return of_parse_phandle_with_args(np, "mboxes", "#mbox-cells", 0, &arg); 662 return of_parse_phandle_with_args(np, "mboxes", "#mbox-cells", 0, &arg);
658} 663}
659 664
660static int scmi_mbox_free_channel(struct scmi_chan_info *cinfo) 665static int scmi_mbox_free_channel(int id, void *p, void *data)
661{ 666{
667 struct scmi_chan_info *cinfo = p;
668 struct idr *idr = data;
669
662 if (!IS_ERR_OR_NULL(cinfo->chan)) { 670 if (!IS_ERR_OR_NULL(cinfo->chan)) {
663 mbox_free_channel(cinfo->chan); 671 mbox_free_channel(cinfo->chan);
664 cinfo->chan = NULL; 672 cinfo->chan = NULL;
665 } 673 }
666 674
675 idr_remove(idr, id);
676
667 return 0; 677 return 0;
668} 678}
669 679
@@ -671,6 +681,7 @@ static int scmi_remove(struct platform_device *pdev)
671{ 681{
672 int ret = 0; 682 int ret = 0;
673 struct scmi_info *info = platform_get_drvdata(pdev); 683 struct scmi_info *info = platform_get_drvdata(pdev);
684 struct idr *idr = &info->tx_idr;
674 685
675 mutex_lock(&scmi_list_mutex); 686 mutex_lock(&scmi_list_mutex);
676 if (info->users) 687 if (info->users)
@@ -679,28 +690,34 @@ static int scmi_remove(struct platform_device *pdev)
679 list_del(&info->node); 690 list_del(&info->node);
680 mutex_unlock(&scmi_list_mutex); 691 mutex_unlock(&scmi_list_mutex);
681 692
682 if (!ret) 693 if (!ret) {
683 /* Safe to free channels since no more users */ 694 /* Safe to free channels since no more users */
684 return scmi_mbox_free_channel(info->tx_cinfo); 695 ret = idr_for_each(idr, scmi_mbox_free_channel, idr);
696 idr_destroy(&info->tx_idr);
697 }
685 698
686 return ret; 699 return ret;
687} 700}
688 701
689static inline int scmi_mbox_chan_setup(struct scmi_info *info) 702static inline int
703scmi_mbox_chan_setup(struct scmi_info *info, struct device *dev, int prot_id)
690{ 704{
691 int ret; 705 int ret;
692 struct resource res; 706 struct resource res;
693 resource_size_t size; 707 resource_size_t size;
694 struct device *dev = info->dev;
695 struct device_node *shmem, *np = dev->of_node; 708 struct device_node *shmem, *np = dev->of_node;
696 struct scmi_chan_info *cinfo; 709 struct scmi_chan_info *cinfo;
697 struct mbox_client *cl; 710 struct mbox_client *cl;
698 711
712 if (scmi_mailbox_check(np)) {
713 cinfo = idr_find(&info->tx_idr, SCMI_PROTOCOL_BASE);
714 goto idr_alloc;
715 }
716
699 cinfo = devm_kzalloc(info->dev, sizeof(*cinfo), GFP_KERNEL); 717 cinfo = devm_kzalloc(info->dev, sizeof(*cinfo), GFP_KERNEL);
700 if (!cinfo) 718 if (!cinfo)
701 return -ENOMEM; 719 return -ENOMEM;
702 720
703 info->tx_cinfo = cinfo;
704 cinfo->dev = dev; 721 cinfo->dev = dev;
705 722
706 cl = &cinfo->cl; 723 cl = &cinfo->cl;
@@ -734,6 +751,14 @@ static inline int scmi_mbox_chan_setup(struct scmi_info *info)
734 return ret; 751 return ret;
735 } 752 }
736 753
754idr_alloc:
755 ret = idr_alloc(&info->tx_idr, cinfo, prot_id, prot_id + 1, GFP_KERNEL);
756 if (ret != prot_id) {
757 dev_err(dev, "unable to allocate SCMI idr slot err %d\n", ret);
758 return ret;
759 }
760
761 cinfo->handle = &info->handle;
737 return 0; 762 return 0;
738} 763}
739 764
@@ -750,6 +775,11 @@ scmi_create_protocol_device(struct device_node *np, struct scmi_info *info,
750 return; 775 return;
751 } 776 }
752 777
778 if (scmi_mbox_chan_setup(info, &sdev->dev, prot_id)) {
779 dev_err(&sdev->dev, "failed to setup transport\n");
780 scmi_device_destroy(sdev);
781 }
782
753 /* setup handle now as the transport is ready */ 783 /* setup handle now as the transport is ready */
754 scmi_set_handle(sdev); 784 scmi_set_handle(sdev);
755} 785}
@@ -784,19 +814,19 @@ static int scmi_probe(struct platform_device *pdev)
784 return ret; 814 return ret;
785 815
786 platform_set_drvdata(pdev, info); 816 platform_set_drvdata(pdev, info);
817 idr_init(&info->tx_idr);
787 818
788 handle = &info->handle; 819 handle = &info->handle;
789 handle->dev = info->dev; 820 handle->dev = info->dev;
790 handle->version = &info->version; 821 handle->version = &info->version;
791 822
792 ret = scmi_mbox_chan_setup(info); 823 ret = scmi_mbox_chan_setup(info, dev, SCMI_PROTOCOL_BASE);
793 if (ret) 824 if (ret)
794 return ret; 825 return ret;
795 826
796 ret = scmi_base_protocol_init(handle); 827 ret = scmi_base_protocol_init(handle);
797 if (ret) { 828 if (ret) {
798 dev_err(dev, "unable to communicate with SCMI(%d)\n", ret); 829 dev_err(dev, "unable to communicate with SCMI(%d)\n", ret);
799 scmi_mbox_free_channel(info->tx_cinfo);
800 return ret; 830 return ret;
801 } 831 }
802 832