1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <assert.h>
18 #include <lib/spi/client/spi.h>
19 #include <lib/tipc/tipc.h>
20 #include <lk/compiler.h>
21 #include <lk/macros.h>
22 #include <stdbool.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/auxv.h>
26 #include <trusty/memref.h>
27 #include <uapi/err.h>
28 #include <uapi/mm.h>
29 
30 #define TLOG_TAG "spi-client"
31 #include <trusty_log.h>
32 
33 #define PAGE_SIZE getauxval(AT_PAGESZ)
34 
35 /**
36  * Size of the largest SPI request argument structure. Needs to be updated if we
37  * add larger SPI arguments.
38  */
39 #define SPI_CMD_SHM_ARGS_MAX_SIZE sizeof(struct spi_xfer_args)
40 
send_shm(struct spi_dev * dev,struct spi_msg_req * req,struct spi_shm_map_req * shm_req,handle_t memref)41 static int send_shm(struct spi_dev* dev,
42                     struct spi_msg_req* req,
43                     struct spi_shm_map_req* shm_req,
44                     handle_t memref) {
45     int rc;
46     struct iovec iovs[2] = {
47             {
48                     .iov_base = req,
49                     .iov_len = sizeof(*req),
50             },
51             {
52                     .iov_base = shm_req,
53                     .iov_len = sizeof(*shm_req),
54             },
55     };
56     struct ipc_msg msg = {
57             .iov = iovs,
58             .num_iov = countof(iovs),
59             .handles = &memref,
60             .num_handles = 1,
61     };
62     rc = send_msg(dev->h, &msg);
63     if (rc < 0) {
64         TLOGE("failed (%d) to send memref\n", rc);
65         return rc;
66     }
67     return NO_ERROR;
68 }
69 
handle_shm_resp(handle_t chan)70 static int handle_shm_resp(handle_t chan) {
71     int rc;
72     struct uevent evt;
73     struct spi_msg_resp resp;
74 
75     rc = wait(chan, &evt, INFINITE_TIME);
76     if (rc != NO_ERROR) {
77         TLOGE("failed (%d) to wait for reply\n", rc);
78         return rc;
79     }
80 
81     rc = tipc_recv1(chan, sizeof(resp), &resp, sizeof(resp));
82     if (rc < 0 || (size_t)rc != sizeof(resp)) {
83         TLOGE("failed (%d) to read reply\n", rc);
84         if (rc >= 0) {
85             rc = ERR_BAD_LEN;
86         }
87         return rc;
88     }
89 
90     return translate_srv_err(resp.status);
91 }
92 
shm_map(struct spi_dev * dev,void * shm_base,size_t shm_size)93 static int shm_map(struct spi_dev* dev, void* shm_base, size_t shm_size) {
94     int rc;
95     struct spi_msg_req req;
96     struct spi_shm_map_req shm_req;
97 
98     /* create memref to send to SPI server */
99     rc = memref_create(shm_base, shm_size,
100                        MMAP_FLAG_PROT_READ | MMAP_FLAG_PROT_WRITE);
101     if (rc < 0) {
102         TLOGE("failed (%d) to create memref\n", rc);
103         goto err_memref_create;
104     }
105     handle_t memref = (handle_t)rc;
106 
107     /* send memref to SPI server */
108     req.cmd = SPI_CMD_MSG_OP_SHM_MAP;
109     shm_req.len = shm_size;
110     rc = send_shm(dev, &req, &shm_req, memref);
111     if (rc < 0) {
112         TLOGE("failed (%d) to send memref\n", rc);
113         goto err_send_msg;
114     }
115 
116     /* handle SPI server's response */
117     rc = handle_shm_resp(dev->h);
118     if (rc != NO_ERROR) {
119         TLOGE("failed (%d) to handle shared memory map response\n", rc);
120         goto err_resp;
121     }
122 
123     close(memref);
124     return NO_ERROR;
125 
126 err_resp:
127 err_send_msg:
128     close(memref);
129 err_memref_create:
130     return rc;
131 }
132 
get_shm_size(size_t max_num_cmds,size_t max_total_payload)133 static inline size_t get_shm_size(size_t max_num_cmds,
134                                   size_t max_total_payload) {
135     /* account for space taken up by alignment requirements */
136     size_t max_total_align = max_num_cmds * (SPI_CMD_SHM_ALIGN - 1);
137     size_t cmd_size = round_up(sizeof(struct spi_shm_hdr), SPI_CMD_SHM_ALIGN) +
138                       round_up(SPI_CMD_SHM_ARGS_MAX_SIZE, SPI_CMD_SHM_ALIGN);
139     size_t shm_size =
140             max_num_cmds * cmd_size + max_total_payload + max_total_align;
141 
142     return round_up(shm_size, PAGE_SIZE);
143 }
144 
spi_dev_open(struct spi_dev * dev,const char * name,size_t max_num_cmds,size_t max_total_payload)145 int spi_dev_open(struct spi_dev* dev,
146                  const char* name,
147                  size_t max_num_cmds,
148                  size_t max_total_payload) {
149     int rc;
150     void* shm_base;
151     size_t shm_size;
152 
153     if (!dev || !name || max_num_cmds == 0) {
154         return ERR_INVALID_ARGS;
155     }
156 
157     /* connect to SPI service */
158     rc = tipc_connect(&dev->h, name);
159     if (rc != NO_ERROR) {
160         TLOGE("failed (%d) to connect to service \"%s\"\n", rc, name);
161         goto err_connect;
162     }
163 
164     /* allocate shared memory */
165     shm_size = get_shm_size(max_num_cmds, max_total_payload);
166     shm_base = memalign(PAGE_SIZE, shm_size);
167     if (!shm_base) {
168         TLOGE("failed to allocate shared memory, base: %p, size: %zu\n",
169               shm_base, shm_size);
170         rc = ERR_NO_MEMORY;
171         goto err_shm_alloc;
172     }
173 
174     /* establish shared memory with SPI server*/
175     rc = shm_map(dev, shm_base, shm_size);
176     if (rc != NO_ERROR) {
177         TLOGE("failed (%d) to send shared memory\n", rc);
178         goto err_shm_send;
179     }
180 
181     mb_init(&dev->shm, shm_base, shm_size, SPI_CMD_SHM_ALIGN);
182     mb_resize(&dev->shm, shm_size);
183     dev->max_num_cmds = max_num_cmds;
184     dev->max_total_payload = max_total_payload;
185     spi_clear_cmds(dev);
186     return NO_ERROR;
187 
188 err_shm_send:
189     /*
190      * There is no way to free() shared memory safely once SPI server receives
191      * the memref. At this point in the program, we don't know if shm_map() has
192      * successfully sent the shared memory or not. So we leak the memory in case
193      * it was already shared.
194      * TODO: It may be possible to avoid memory leaks using other ways of
195      * allocating shared memory.
196      */
197 err_shm_alloc:
198     close(dev->h);
199     dev->h = INVALID_IPC_HANDLE;
200 err_connect:
201     return rc;
202 }
203 
is_initialized(struct spi_dev * dev)204 static inline bool is_initialized(struct spi_dev* dev) {
205     return dev && dev->h != INVALID_IPC_HANDLE;
206 }
207 
spi_clear_cmds(struct spi_dev * dev)208 void spi_clear_cmds(struct spi_dev* dev) {
209     assert(is_initialized(dev));
210     mb_rewind_pos(&dev->shm);
211     dev->num_cmds = 0;
212     dev->total_payload = 0;
213     dev->config_err = false;
214 }
215 
send_batch_req(struct spi_dev * dev)216 static int send_batch_req(struct spi_dev* dev) {
217     struct spi_msg_req req = {
218             .cmd = SPI_CMD_MSG_OP_BATCH_EXEC,
219     };
220     struct spi_batch_req batch_req = {
221             .len = mb_curr_pos(&dev->shm),
222             .num_cmds = dev->num_cmds,
223     };
224     int rc = tipc_send2(dev->h, &req, sizeof(req), &batch_req,
225                         sizeof(batch_req));
226     if (rc < 0 || (size_t)rc != sizeof(req) + sizeof(batch_req)) {
227         TLOGE("failed (%d) to send SPI batch request\n", rc);
228         if (rc >= 0) {
229             rc = ERR_BAD_LEN;
230         }
231         return rc;
232     }
233     return NO_ERROR;
234 }
235 
validate_batch_resp(struct spi_batch_resp * batch_resp,struct mem_buf * shm,size_t * failed)236 static int validate_batch_resp(struct spi_batch_resp* batch_resp,
237                                struct mem_buf* shm,
238                                size_t* failed) {
239     int rc = NO_ERROR;
240     struct spi_shm_hdr* shm_hdr;
241     uint32_t shm_hdr_cmd;
242     uint32_t shm_hdr_status;
243     struct spi_xfer_args* xfer_resp;
244     uint32_t xfer_resp_len;
245 
246     /*
247      * length of the response in shared memory must be equal to that of the
248      * request
249      */
250     if (batch_resp->len != mb_curr_pos(shm)) {
251         return ERR_BAD_STATE;
252     }
253 
254     mb_rewind_pos(shm);
255 
256     while (mb_curr_pos(shm) < batch_resp->len) {
257         shm_hdr = mb_advance_pos(shm, sizeof(*shm_hdr));
258         shm_hdr_cmd = READ_ONCE(shm_hdr->cmd);
259         shm_hdr_status = READ_ONCE(shm_hdr->status);
260 
261         if (!(shm_hdr_cmd & SPI_CMD_RESP_BIT)) {
262             TLOGE("invalid response 0x%08x\n", shm_hdr_cmd);
263             return ERR_BAD_STATE;
264         }
265         rc = translate_srv_err(shm_hdr_status);
266         if (rc != NO_ERROR) {
267             return rc;
268         }
269 
270         switch (shm_hdr_cmd & SPI_CMD_OP_MASK) {
271         case SPI_CMD_SHM_OP_XFER:
272             /* skip xfer_resp and payload */
273             xfer_resp = mb_advance_pos(shm, sizeof(*xfer_resp));
274             xfer_resp_len = READ_ONCE(xfer_resp->len);
275             mb_advance_pos(shm, xfer_resp_len);
276             break;
277         case SPI_CMD_SHM_OP_CS_ASSERT:
278         case SPI_CMD_SHM_OP_CS_DEASSERT:
279             break;
280         case SPI_CMD_SHM_OP_SET_CLK:
281             /* skip spi_clk_args */
282             mb_advance_pos(shm, sizeof(struct spi_clk_args));
283             break;
284         case SPI_CMD_SHM_OP_DELAY:
285             /* skip spi_delay_args */
286             mb_advance_pos(shm, sizeof(struct spi_delay_args));
287             break;
288         default:
289             TLOGE("cmd 0x%x: unknown command\n", shm_hdr_cmd);
290             return ERR_CMD_UNKNOWN;
291         }
292         (*failed)++;
293     }
294 
295     return NO_ERROR;
296 }
297 
handle_batch_resp(struct spi_dev * dev,size_t * failed)298 static int handle_batch_resp(struct spi_dev* dev, size_t* failed) {
299     int rc;
300     struct uevent evt;
301     struct spi_msg_resp resp;
302     struct spi_batch_resp batch_resp;
303 
304     rc = wait(dev->h, &evt, INFINITE_TIME);
305     if (rc != NO_ERROR) {
306         TLOGE("failed (%d) to wait for batch response\n", rc);
307         return rc;
308     }
309 
310     rc = tipc_recv2(dev->h, sizeof(resp) + sizeof(batch_resp), &resp,
311                     sizeof(resp), &batch_resp, sizeof(batch_resp));
312     if (rc < 0 || (size_t)rc != sizeof(resp) + sizeof(batch_resp)) {
313         TLOGE("failed (%d) to receive batch response\n", rc);
314         if (rc >= 0) {
315             rc = ERR_BAD_LEN;
316         }
317         return rc;
318     }
319 
320     rc = translate_srv_err(resp.status);
321     if (rc != NO_ERROR) {
322         TLOGE("batch request encountered an error\n");
323         *failed = batch_resp.failed;
324         return rc;
325     }
326 
327     return validate_batch_resp(&batch_resp, &dev->shm, failed);
328 }
329 
spi_exec_cmds(struct spi_dev * dev,size_t * failed)330 int spi_exec_cmds(struct spi_dev* dev, size_t* failed) {
331     int rc;
332     size_t fake_failed;
333 
334     if (!is_initialized(dev)) {
335         return ERR_INVALID_ARGS;
336     }
337 
338     if (!failed) {
339         failed = &fake_failed;
340     }
341     *failed = 0;
342 
343     if (dev->config_err) {
344         rc = ERR_BAD_STATE;
345         *failed = dev->num_cmds;
346         goto out;
347     }
348 
349     rc = send_batch_req(dev);
350     if (rc != NO_ERROR) {
351         goto out;
352     }
353 
354     rc = handle_batch_resp(dev, failed);
355 
356 out:
357     /* reset SPI requests */
358     spi_clear_cmds(dev);
359     return rc;
360 }
361 
spi_add_cmd(struct spi_dev * dev,uint32_t cmd,void ** args,size_t args_len,void ** payload,size_t payload_len)362 static int spi_add_cmd(struct spi_dev* dev,
363                        uint32_t cmd,
364                        void** args,
365                        size_t args_len,
366                        void** payload,
367                        size_t payload_len) {
368     int rc;
369     struct spi_shm_hdr* shm_hdr;
370 
371     assert(args || !args_len);
372     assert(payload || !payload_len);
373     assert(args_len <= SPI_CMD_SHM_ARGS_MAX_SIZE);
374 
375     if (!is_initialized(dev)) {
376         rc = ERR_BAD_HANDLE;
377         goto err_init;
378     }
379     if (dev->config_err) {
380         rc = ERR_BAD_STATE;
381         goto err_config;
382     }
383     if (dev->num_cmds >= dev->max_num_cmds) {
384         rc = ERR_OUT_OF_RANGE;
385         goto err_range;
386     }
387 
388     shm_hdr = mb_advance_pos(&dev->shm, sizeof(*shm_hdr));
389     if (!shm_hdr) {
390         rc = ERR_TOO_BIG;
391         goto err_shm_hdr;
392     }
393     WRITE_ONCE(shm_hdr->cmd, cmd);
394     WRITE_ONCE(shm_hdr->status, 0);
395 
396     if (args) {
397         *args = mb_advance_pos(&dev->shm, args_len);
398         if (!*args) {
399             rc = ERR_TOO_BIG;
400             goto err_args;
401         }
402     }
403     if (payload) {
404         assert(dev->total_payload <= dev->max_total_payload);
405         if (payload_len > dev->max_total_payload - dev->total_payload) {
406             rc = ERR_TOO_BIG;
407             goto err_payload;
408         }
409         dev->total_payload += payload_len;
410 
411         *payload = mb_advance_pos(&dev->shm, payload_len);
412         assert(*payload);
413     }
414 
415     dev->num_cmds++;
416     return NO_ERROR;
417 
418 err_payload:
419     *args = NULL;
420 err_args:
421 err_shm_hdr:
422 err_range:
423     dev->config_err = true;
424 err_config:
425 err_init:
426     return rc;
427 }
428 
spi_add_data_xfer_cmd(struct spi_dev * dev,void ** tx,void ** rx,size_t len)429 int spi_add_data_xfer_cmd(struct spi_dev* dev,
430                           void** tx,
431                           void** rx,
432                           size_t len) {
433     int rc;
434     struct spi_xfer_args* args;
435     uint32_t flags;
436     void* payload;
437 
438     rc = spi_add_cmd(dev, SPI_CMD_SHM_OP_XFER, (void**)&args, sizeof(*args),
439                      &payload, len);
440     if (rc != NO_ERROR) {
441         return rc;
442     }
443 
444     flags = (tx ? SPI_XFER_FLAGS_TX : 0) | (rx ? SPI_XFER_FLAGS_RX : 0);
445     WRITE_ONCE(args->len, len);
446     WRITE_ONCE(args->flags, flags);
447 
448     if (tx) {
449         *tx = payload;
450     }
451     if (rx) {
452         *rx = payload;
453     }
454 
455     return NO_ERROR;
456 }
457 
spi_add_cs_assert_cmd(struct spi_dev * dev)458 int spi_add_cs_assert_cmd(struct spi_dev* dev) {
459     return spi_add_cmd(dev, SPI_CMD_SHM_OP_CS_ASSERT, NULL, 0, NULL, 0);
460 }
461 
spi_add_cs_deassert_cmd(struct spi_dev * dev)462 int spi_add_cs_deassert_cmd(struct spi_dev* dev) {
463     return spi_add_cmd(dev, SPI_CMD_SHM_OP_CS_DEASSERT, NULL, 0, NULL, 0);
464 }
465 
spi_add_set_clk_cmd(struct spi_dev * dev,uint64_t clk_hz_in,uint64_t ** clk_hz_out)466 int spi_add_set_clk_cmd(struct spi_dev* dev,
467                         uint64_t clk_hz_in,
468                         uint64_t** clk_hz_out) {
469     int rc;
470     struct spi_clk_args* args;
471 
472     rc = spi_add_cmd(dev, SPI_CMD_SHM_OP_SET_CLK, (void**)&args, sizeof(*args),
473                      NULL, 0);
474     if (rc != NO_ERROR) {
475         return rc;
476     }
477 
478     WRITE_ONCE(args->clk_hz, clk_hz_in);
479 
480     if (clk_hz_out) {
481         *clk_hz_out = &args->clk_hz;
482     }
483 
484     return NO_ERROR;
485 }
486 
spi_add_delay_cmd(struct spi_dev * dev,uint64_t delay_ns)487 int spi_add_delay_cmd(struct spi_dev* dev, uint64_t delay_ns) {
488     int rc;
489     struct spi_delay_args* args;
490 
491     rc = spi_add_cmd(dev, SPI_CMD_SHM_OP_DELAY, (void**)&args, sizeof(*args),
492                      NULL, 0);
493     if (rc != NO_ERROR) {
494         return rc;
495     }
496 
497     WRITE_ONCE(args->delay_ns, delay_ns);
498 
499     return NO_ERROR;
500 }
501