1919 * struct scmi_mailbox - Structure representing a SCMI mailbox transport
2020 *
2121 * @cl: Mailbox Client
22- * @chan: Transmit/Receive mailbox channel
22+ * @chan: Transmit/Receive mailbox uni/bi-directional channel
23+ * @chan_receiver: Optional Receiver mailbox unidirectional channel
2324 * @cinfo: SCMI channel info
2425 * @shmem: Transmit/Receive shared memory area
2526 */
2627struct scmi_mailbox {
2728 struct mbox_client cl ;
2829 struct mbox_chan * chan ;
30+ struct mbox_chan * chan_receiver ;
2931 struct scmi_chan_info * cinfo ;
3032 struct scmi_shared_mem __iomem * shmem ;
3133};
@@ -48,30 +50,62 @@ static void rx_callback(struct mbox_client *cl, void *m)
4850
4951static bool mailbox_chan_available (struct device_node * of_node , int idx )
5052{
53+ int num_mb ;
54+
55+ /*
56+ * Just check if bidirrectional channels are involved, and check the
57+ * index accordingly; proper full validation will be made later
58+ * in mailbox_chan_setup().
59+ */
60+ num_mb = of_count_phandle_with_args (of_node , "mboxes" , "#mbox-cells" );
61+ if (num_mb == 3 && idx == 1 )
62+ idx = 2 ;
63+
5164 return !of_parse_phandle_with_args (of_node , "mboxes" ,
5265 "#mbox-cells" , idx , NULL );
5366}
5467
55- static int mailbox_chan_validate (struct device * cdev )
68+ /**
69+ * mailbox_chan_validate - Validate transport configuration and map channels
70+ *
71+ * @cdev: Reference to the underlying transport device carrying the
72+ * of_node descriptor to analyze.
73+ * @a2p_rx_chan: A reference to an optional unidirectional channel to use
74+ * for replies on the a2p channel. Set as zero if not present.
75+ * @p2a_chan: A reference to the optional p2a channel.
76+ * Set as zero if not present.
77+ *
78+ * At first, validate the transport configuration as described in terms of
79+ * 'mboxes' and 'shmem', then determin which mailbox channel indexes are
80+ * appropriate to be use in the current configuration.
81+ *
82+ * Return: 0 on Success or error
83+ */
84+ static int mailbox_chan_validate (struct device * cdev ,
85+ int * a2p_rx_chan , int * p2a_chan )
5686{
5787 int num_mb , num_sh , ret = 0 ;
5888 struct device_node * np = cdev -> of_node ;
5989
6090 num_mb = of_count_phandle_with_args (np , "mboxes" , "#mbox-cells" );
6191 num_sh = of_count_phandle_with_args (np , "shmem" , NULL );
92+ dev_dbg (cdev , "Found %d mboxes and %d shmems !\n" , num_mb , num_sh );
93+
6294 /* Bail out if mboxes and shmem descriptors are inconsistent */
63- if (num_mb <= 0 || num_sh > 2 || num_mb != num_sh ) {
64- dev_warn (cdev , "Invalid channel descriptor for '%s'\n" ,
65- of_node_full_name (np ));
95+ if (num_mb <= 0 || num_sh <= 0 || num_sh > 2 || num_mb > 3 ||
96+ (num_mb == 1 && num_sh != 1 ) || (num_mb == 3 && num_sh != 2 )) {
97+ dev_warn (cdev ,
98+ "Invalid channel descriptor for '%s' - mbs:%d shm:%d\n" ,
99+ of_node_full_name (np ), num_mb , num_sh );
66100 return - EINVAL ;
67101 }
68102
103+ /* Bail out if provided shmem descriptors do not refer distinct areas */
69104 if (num_sh > 1 ) {
70105 struct device_node * np_tx , * np_rx ;
71106
72107 np_tx = of_parse_phandle (np , "shmem" , 0 );
73108 np_rx = of_parse_phandle (np , "shmem" , 1 );
74- /* SCMI Tx and Rx shared mem areas have to be distinct */
75109 if (!np_tx || !np_rx || np_tx == np_rx ) {
76110 dev_warn (cdev , "Invalid shmem descriptor for '%s'\n" ,
77111 of_node_full_name (np ));
@@ -82,6 +116,29 @@ static int mailbox_chan_validate(struct device *cdev)
82116 of_node_put (np_rx );
83117 }
84118
119+ /* Calculate channels IDs to use depending on mboxes/shmem layout */
120+ if (!ret ) {
121+ switch (num_mb ) {
122+ case 1 :
123+ * a2p_rx_chan = 0 ;
124+ * p2a_chan = 0 ;
125+ break ;
126+ case 2 :
127+ if (num_sh == 2 ) {
128+ * a2p_rx_chan = 0 ;
129+ * p2a_chan = 1 ;
130+ } else {
131+ * a2p_rx_chan = 1 ;
132+ * p2a_chan = 0 ;
133+ }
134+ break ;
135+ case 3 :
136+ * a2p_rx_chan = 1 ;
137+ * p2a_chan = 2 ;
138+ break ;
139+ }
140+ }
141+
85142 return ret ;
86143}
87144
@@ -92,15 +149,18 @@ static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
92149 struct device * cdev = cinfo -> dev ;
93150 struct scmi_mailbox * smbox ;
94151 struct device_node * shmem ;
95- int ret , idx = tx ? 0 : 1 ;
152+ int ret , a2p_rx_chan , p2a_chan , idx = tx ? 0 : 1 ;
96153 struct mbox_client * cl ;
97154 resource_size_t size ;
98155 struct resource res ;
99156
100- ret = mailbox_chan_validate (cdev );
157+ ret = mailbox_chan_validate (cdev , & a2p_rx_chan , & p2a_chan );
101158 if (ret )
102159 return ret ;
103160
161+ if (!tx && !p2a_chan )
162+ return - ENODEV ;
163+
104164 smbox = devm_kzalloc (dev , sizeof (* smbox ), GFP_KERNEL );
105165 if (!smbox )
106166 return - ENOMEM ;
@@ -130,15 +190,26 @@ static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
130190 cl -> tx_block = false;
131191 cl -> knows_txdone = tx ;
132192
133- smbox -> chan = mbox_request_channel (cl , tx ? 0 : 1 );
193+ smbox -> chan = mbox_request_channel (cl , tx ? 0 : p2a_chan );
134194 if (IS_ERR (smbox -> chan )) {
135195 ret = PTR_ERR (smbox -> chan );
136196 if (ret != - EPROBE_DEFER )
137- dev_err (cdev , "failed to request SCMI %s mailbox\n" ,
138- tx ? "Tx" : "Rx" );
197+ dev_err (cdev ,
198+ "failed to request SCMI %s mailbox\n" , desc );
139199 return ret ;
140200 }
141201
202+ /* Additional unidirectional channel for TX if needed */
203+ if (tx && a2p_rx_chan ) {
204+ smbox -> chan_receiver = mbox_request_channel (cl , a2p_rx_chan );
205+ if (IS_ERR (smbox -> chan_receiver )) {
206+ ret = PTR_ERR (smbox -> chan_receiver );
207+ if (ret != - EPROBE_DEFER )
208+ dev_err (cdev , "failed to request SCMI Tx Receiver mailbox\n" );
209+ return ret ;
210+ }
211+ }
212+
142213 cinfo -> transport_info = smbox ;
143214 smbox -> cinfo = cinfo ;
144215
@@ -152,8 +223,10 @@ static int mailbox_chan_free(int id, void *p, void *data)
152223
153224 if (smbox && !IS_ERR (smbox -> chan )) {
154225 mbox_free_channel (smbox -> chan );
226+ mbox_free_channel (smbox -> chan_receiver );
155227 cinfo -> transport_info = NULL ;
156228 smbox -> chan = NULL ;
229+ smbox -> chan_receiver = NULL ;
157230 smbox -> cinfo = NULL ;
158231 }
159232
0 commit comments