.. | .. |
---|
52 | 52 | "#mbox-cells", idx, NULL); |
---|
53 | 53 | } |
---|
54 | 54 | |
---|
| 55 | +static int mailbox_chan_validate(struct device *cdev) |
---|
| 56 | +{ |
---|
| 57 | + int num_mb, num_sh, ret = 0; |
---|
| 58 | + struct device_node *np = cdev->of_node; |
---|
| 59 | + |
---|
| 60 | + num_mb = of_count_phandle_with_args(np, "mboxes", "#mbox-cells"); |
---|
| 61 | + num_sh = of_count_phandle_with_args(np, "shmem", NULL); |
---|
| 62 | + /* 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)); |
---|
| 66 | + return -EINVAL; |
---|
| 67 | + } |
---|
| 68 | + |
---|
| 69 | + if (num_sh > 1) { |
---|
| 70 | + struct device_node *np_tx, *np_rx; |
---|
| 71 | + |
---|
| 72 | + np_tx = of_parse_phandle(np, "shmem", 0); |
---|
| 73 | + np_rx = of_parse_phandle(np, "shmem", 1); |
---|
| 74 | + /* SCMI Tx and Rx shared mem areas have to be distinct */ |
---|
| 75 | + if (!np_tx || !np_rx || np_tx == np_rx) { |
---|
| 76 | + dev_warn(cdev, "Invalid shmem descriptor for '%s'\n", |
---|
| 77 | + of_node_full_name(np)); |
---|
| 78 | + ret = -EINVAL; |
---|
| 79 | + } |
---|
| 80 | + |
---|
| 81 | + of_node_put(np_tx); |
---|
| 82 | + of_node_put(np_rx); |
---|
| 83 | + } |
---|
| 84 | + |
---|
| 85 | + return ret; |
---|
| 86 | +} |
---|
| 87 | + |
---|
55 | 88 | static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, |
---|
56 | 89 | bool tx) |
---|
57 | 90 | { |
---|
.. | .. |
---|
63 | 96 | struct mbox_client *cl; |
---|
64 | 97 | resource_size_t size; |
---|
65 | 98 | struct resource res; |
---|
| 99 | + |
---|
| 100 | + ret = mailbox_chan_validate(cdev); |
---|
| 101 | + if (ret) |
---|
| 102 | + return ret; |
---|
66 | 103 | |
---|
67 | 104 | smbox = devm_kzalloc(dev, sizeof(*smbox), GFP_KERNEL); |
---|
68 | 105 | if (!smbox) |
---|
.. | .. |
---|
110 | 147 | struct scmi_chan_info *cinfo = p; |
---|
111 | 148 | struct scmi_mailbox *smbox = cinfo->transport_info; |
---|
112 | 149 | |
---|
113 | | - if (!IS_ERR(smbox->chan)) { |
---|
| 150 | + if (smbox && !IS_ERR(smbox->chan)) { |
---|
114 | 151 | mbox_free_channel(smbox->chan); |
---|
115 | 152 | cinfo->transport_info = NULL; |
---|
116 | 153 | smbox->chan = NULL; |
---|
.. | .. |
---|
158 | 195 | shmem_fetch_response(smbox->shmem, xfer); |
---|
159 | 196 | } |
---|
160 | 197 | |
---|
| 198 | +static void mailbox_fetch_notification(struct scmi_chan_info *cinfo, |
---|
| 199 | + size_t max_len, struct scmi_xfer *xfer) |
---|
| 200 | +{ |
---|
| 201 | + struct scmi_mailbox *smbox = cinfo->transport_info; |
---|
| 202 | + |
---|
| 203 | + shmem_fetch_notification(smbox->shmem, max_len, xfer); |
---|
| 204 | +} |
---|
| 205 | + |
---|
| 206 | +static void mailbox_clear_channel(struct scmi_chan_info *cinfo) |
---|
| 207 | +{ |
---|
| 208 | + struct scmi_mailbox *smbox = cinfo->transport_info; |
---|
| 209 | + |
---|
| 210 | + shmem_clear_channel(smbox->shmem); |
---|
| 211 | +} |
---|
| 212 | + |
---|
161 | 213 | static bool |
---|
162 | 214 | mailbox_poll_done(struct scmi_chan_info *cinfo, struct scmi_xfer *xfer) |
---|
163 | 215 | { |
---|
.. | .. |
---|
166 | 218 | return shmem_poll_done(smbox->shmem, xfer); |
---|
167 | 219 | } |
---|
168 | 220 | |
---|
169 | | -static struct scmi_transport_ops scmi_mailbox_ops = { |
---|
| 221 | +static const struct scmi_transport_ops scmi_mailbox_ops = { |
---|
170 | 222 | .chan_available = mailbox_chan_available, |
---|
171 | 223 | .chan_setup = mailbox_chan_setup, |
---|
172 | 224 | .chan_free = mailbox_chan_free, |
---|
173 | 225 | .send_message = mailbox_send_message, |
---|
174 | 226 | .mark_txdone = mailbox_mark_txdone, |
---|
175 | 227 | .fetch_response = mailbox_fetch_response, |
---|
| 228 | + .fetch_notification = mailbox_fetch_notification, |
---|
| 229 | + .clear_channel = mailbox_clear_channel, |
---|
176 | 230 | .poll_done = mailbox_poll_done, |
---|
177 | 231 | }; |
---|
178 | 232 | |
---|