Skip to content

Commit 907b6d1

Browse files
committed
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 <[email protected]> Cc: Greg Kroah-Hartman <[email protected]> Signed-off-by: Sudeep Holla <[email protected]>
1 parent fbc4d81 commit 907b6d1

File tree

1 file changed

+42
-12
lines changed

1 file changed

+42
-12
lines changed

drivers/firmware/arm_scmi/driver.c

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ struct scmi_chan_info {
104104
struct mbox_chan *chan;
105105
void __iomem *payload;
106106
struct device *dev;
107+
struct scmi_handle *handle;
107108
};
108109

109110
/**
@@ -115,7 +116,7 @@ struct scmi_chan_info {
115116
* @version: SCMI revision information containing protocol version,
116117
* implementation version and (sub-)vendor identification.
117118
* @minfo: Message info
118-
* @tx_cinfo: Reference to SCMI channel information
119+
* @tx_idr: IDR object to map protocol id to channel info pointer
119120
* @protocols_imp: list of protocols implemented, currently maximum of
120121
* MAX_PROTOCOLS_IMP elements allocated by the base protocol
121122
* @node: list head
@@ -127,7 +128,7 @@ struct scmi_info {
127128
struct scmi_revision_info version;
128129
struct scmi_handle handle;
129130
struct scmi_xfers_info minfo;
130-
struct scmi_chan_info *tx_cinfo;
131+
struct idr tx_idr;
131132
u8 *protocols_imp;
132133
struct list_head node;
133134
int users;
@@ -218,7 +219,7 @@ static void scmi_rx_callback(struct mbox_client *cl, void *m)
218219
struct scmi_xfer *xfer;
219220
struct scmi_chan_info *cinfo = client_to_scmi_chan_info(cl);
220221
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);
222223
struct scmi_xfers_info *minfo = &info->minfo;
223224
struct scmi_shared_mem __iomem *mem = cinfo->payload;
224225

@@ -390,7 +391,11 @@ int scmi_do_xfer(const struct scmi_handle *handle, struct scmi_xfer *xfer)
390391
int timeout;
391392
struct scmi_info *info = handle_to_scmi_info(handle);
392393
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;
394399

395400
ret = mbox_send_message(cinfo->chan, xfer);
396401
if (ret < 0) {
@@ -657,20 +662,26 @@ static int scmi_mailbox_check(struct device_node *np)
657662
return of_parse_phandle_with_args(np, "mboxes", "#mbox-cells", 0, &arg);
658663
}
659664

660-
static int scmi_mbox_free_channel(struct scmi_chan_info *cinfo)
665+
static int scmi_mbox_free_channel(int id, void *p, void *data)
661666
{
667+
struct scmi_chan_info *cinfo = p;
668+
struct idr *idr = data;
669+
662670
if (!IS_ERR_OR_NULL(cinfo->chan)) {
663671
mbox_free_channel(cinfo->chan);
664672
cinfo->chan = NULL;
665673
}
666674

675+
idr_remove(idr, id);
676+
667677
return 0;
668678
}
669679

670680
static int scmi_remove(struct platform_device *pdev)
671681
{
672682
int ret = 0;
673683
struct scmi_info *info = platform_get_drvdata(pdev);
684+
struct idr *idr = &info->tx_idr;
674685

675686
mutex_lock(&scmi_list_mutex);
676687
if (info->users)
@@ -679,28 +690,34 @@ static int scmi_remove(struct platform_device *pdev)
679690
list_del(&info->node);
680691
mutex_unlock(&scmi_list_mutex);
681692

682-
if (!ret)
693+
if (!ret) {
683694
/* 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+
}
685698

686699
return ret;
687700
}
688701

689-
static inline int scmi_mbox_chan_setup(struct scmi_info *info)
702+
static inline int
703+
scmi_mbox_chan_setup(struct scmi_info *info, struct device *dev, int prot_id)
690704
{
691705
int ret;
692706
struct resource res;
693707
resource_size_t size;
694-
struct device *dev = info->dev;
695708
struct device_node *shmem, *np = dev->of_node;
696709
struct scmi_chan_info *cinfo;
697710
struct mbox_client *cl;
698711

712+
if (scmi_mailbox_check(np)) {
713+
cinfo = idr_find(&info->tx_idr, SCMI_PROTOCOL_BASE);
714+
goto idr_alloc;
715+
}
716+
699717
cinfo = devm_kzalloc(info->dev, sizeof(*cinfo), GFP_KERNEL);
700718
if (!cinfo)
701719
return -ENOMEM;
702720

703-
info->tx_cinfo = cinfo;
704721
cinfo->dev = dev;
705722

706723
cl = &cinfo->cl;
@@ -734,6 +751,14 @@ static inline int scmi_mbox_chan_setup(struct scmi_info *info)
734751
return ret;
735752
}
736753

754+
idr_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;
737762
return 0;
738763
}
739764

@@ -750,6 +775,11 @@ scmi_create_protocol_device(struct device_node *np, struct scmi_info *info,
750775
return;
751776
}
752777

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+
753783
/* setup handle now as the transport is ready */
754784
scmi_set_handle(sdev);
755785
}
@@ -784,19 +814,19 @@ static int scmi_probe(struct platform_device *pdev)
784814
return ret;
785815

786816
platform_set_drvdata(pdev, info);
817+
idr_init(&info->tx_idr);
787818

788819
handle = &info->handle;
789820
handle->dev = info->dev;
790821
handle->version = &info->version;
791822

792-
ret = scmi_mbox_chan_setup(info);
823+
ret = scmi_mbox_chan_setup(info, dev, SCMI_PROTOCOL_BASE);
793824
if (ret)
794825
return ret;
795826

796827
ret = scmi_base_protocol_init(handle);
797828
if (ret) {
798829
dev_err(dev, "unable to communicate with SCMI(%d)\n", ret);
799-
scmi_mbox_free_channel(info->tx_cinfo);
800830
return ret;
801831
}
802832

0 commit comments

Comments
 (0)