19
19
* struct scmi_mailbox - Structure representing a SCMI mailbox transport
20
20
*
21
21
* @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
23
24
* @cinfo: SCMI channel info
24
25
* @shmem: Transmit/Receive shared memory area
25
26
*/
26
27
struct scmi_mailbox {
27
28
struct mbox_client cl ;
28
29
struct mbox_chan * chan ;
30
+ struct mbox_chan * chan_receiver ;
29
31
struct scmi_chan_info * cinfo ;
30
32
struct scmi_shared_mem __iomem * shmem ;
31
33
};
@@ -48,30 +50,62 @@ static void rx_callback(struct mbox_client *cl, void *m)
48
50
49
51
static bool mailbox_chan_available (struct device_node * of_node , int idx )
50
52
{
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
+
51
64
return !of_parse_phandle_with_args (of_node , "mboxes" ,
52
65
"#mbox-cells" , idx , NULL );
53
66
}
54
67
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 )
56
86
{
57
87
int num_mb , num_sh , ret = 0 ;
58
88
struct device_node * np = cdev -> of_node ;
59
89
60
90
num_mb = of_count_phandle_with_args (np , "mboxes" , "#mbox-cells" );
61
91
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
+
62
94
/* 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 );
66
100
return - EINVAL ;
67
101
}
68
102
103
+ /* Bail out if provided shmem descriptors do not refer distinct areas */
69
104
if (num_sh > 1 ) {
70
105
struct device_node * np_tx , * np_rx ;
71
106
72
107
np_tx = of_parse_phandle (np , "shmem" , 0 );
73
108
np_rx = of_parse_phandle (np , "shmem" , 1 );
74
- /* SCMI Tx and Rx shared mem areas have to be distinct */
75
109
if (!np_tx || !np_rx || np_tx == np_rx ) {
76
110
dev_warn (cdev , "Invalid shmem descriptor for '%s'\n" ,
77
111
of_node_full_name (np ));
@@ -82,6 +116,29 @@ static int mailbox_chan_validate(struct device *cdev)
82
116
of_node_put (np_rx );
83
117
}
84
118
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
+
85
142
return ret ;
86
143
}
87
144
@@ -92,15 +149,18 @@ static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
92
149
struct device * cdev = cinfo -> dev ;
93
150
struct scmi_mailbox * smbox ;
94
151
struct device_node * shmem ;
95
- int ret , idx = tx ? 0 : 1 ;
152
+ int ret , a2p_rx_chan , p2a_chan , idx = tx ? 0 : 1 ;
96
153
struct mbox_client * cl ;
97
154
resource_size_t size ;
98
155
struct resource res ;
99
156
100
- ret = mailbox_chan_validate (cdev );
157
+ ret = mailbox_chan_validate (cdev , & a2p_rx_chan , & p2a_chan );
101
158
if (ret )
102
159
return ret ;
103
160
161
+ if (!tx && !p2a_chan )
162
+ return - ENODEV ;
163
+
104
164
smbox = devm_kzalloc (dev , sizeof (* smbox ), GFP_KERNEL );
105
165
if (!smbox )
106
166
return - ENOMEM ;
@@ -130,15 +190,26 @@ static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
130
190
cl -> tx_block = false;
131
191
cl -> knows_txdone = tx ;
132
192
133
- smbox -> chan = mbox_request_channel (cl , tx ? 0 : 1 );
193
+ smbox -> chan = mbox_request_channel (cl , tx ? 0 : p2a_chan );
134
194
if (IS_ERR (smbox -> chan )) {
135
195
ret = PTR_ERR (smbox -> chan );
136
196
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 );
139
199
return ret ;
140
200
}
141
201
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
+
142
213
cinfo -> transport_info = smbox ;
143
214
smbox -> cinfo = cinfo ;
144
215
@@ -152,8 +223,10 @@ static int mailbox_chan_free(int id, void *p, void *data)
152
223
153
224
if (smbox && !IS_ERR (smbox -> chan )) {
154
225
mbox_free_channel (smbox -> chan );
226
+ mbox_free_channel (smbox -> chan_receiver );
155
227
cinfo -> transport_info = NULL ;
156
228
smbox -> chan = NULL ;
229
+ smbox -> chan_receiver = NULL ;
157
230
smbox -> cinfo = NULL ;
158
231
}
159
232
0 commit comments