1 /*
2  * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include "esp_crypto_shared_gdma.h"
8 
9 #include "freertos/FreeRTOS.h"
10 #include "freertos/task.h"
11 
12 #include "hal/gdma_ll.h"
13 #include "soc/soc_caps.h"
14 #include "esp_log.h"
15 #include "esp_err.h"
16 #include "esp_crypto_lock.h"
17 
18 #define NEW_CHANNEL_TIMEOUT_MS  1000
19 #define NEW_CHANNEL_DELAY_MS    100
20 
21 static const char *TAG = "crypto_shared_gdma";
22 
23 static gdma_channel_handle_t rx_channel;
24 static gdma_channel_handle_t tx_channel;
25 
26 /* Allocate a new GDMA channel, will keep trying until NEW_CHANNEL_TIMEOUT_MS */
crypto_shared_gdma_new_channel(gdma_channel_alloc_config_t * channel_config,gdma_channel_handle_t * channel)27 static inline esp_err_t crypto_shared_gdma_new_channel(gdma_channel_alloc_config_t *channel_config, gdma_channel_handle_t *channel)
28 {
29     esp_err_t ret;
30     int time_waited_ms = 0;
31 
32     while (1) {
33         ret = gdma_new_channel(channel_config, channel);
34 
35         if (ret == ESP_OK) {
36             break;
37         } else if (time_waited_ms >= NEW_CHANNEL_TIMEOUT_MS) {
38             *channel = NULL;
39             break;
40         }
41 
42         time_waited_ms += NEW_CHANNEL_DELAY_MS;
43         vTaskDelay(NEW_CHANNEL_DELAY_MS / portTICK_PERIOD_MS);
44     }
45     return ret;
46 }
47 
48 /* Initialize GDMA module and channels */
crypto_shared_gdma_init(void)49 static esp_err_t crypto_shared_gdma_init(void)
50 {
51     esp_err_t ret;
52 
53     gdma_channel_alloc_config_t channel_config_tx = {
54         .direction = GDMA_CHANNEL_DIRECTION_TX,
55     };
56 
57     gdma_channel_alloc_config_t channel_config_rx = {
58         .direction = GDMA_CHANNEL_DIRECTION_RX,
59     };
60 
61     gdma_transfer_ability_t transfer_ability = {
62         .sram_trans_align = 1,
63     };
64 
65 
66     ret = crypto_shared_gdma_new_channel(&channel_config_tx, &tx_channel);
67     if (ret != ESP_OK) {
68         goto err;
69     }
70 
71     ret = crypto_shared_gdma_new_channel(&channel_config_rx, &rx_channel);
72     if (ret != ESP_OK) {
73         gdma_del_channel(tx_channel); // Clean up already allocated TX channel
74         goto err;
75     }
76 
77 
78     gdma_set_transfer_ability(tx_channel, &transfer_ability);
79     gdma_set_transfer_ability(rx_channel, &transfer_ability);
80 
81     gdma_connect(rx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_AES, 0));
82     gdma_connect(tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_AES, 0));
83 
84     return ESP_OK;
85 
86 err:
87     ESP_LOGE(TAG, "Failed to acquire DMA channel, Err=%d", ret);
88     tx_channel = NULL;
89     rx_channel = NULL;
90 
91     return ret;
92 }
93 
94 
esp_crypto_shared_gdma_start(const lldesc_t * input,const lldesc_t * output,gdma_trigger_peripheral_t peripheral)95 esp_err_t esp_crypto_shared_gdma_start(const lldesc_t *input, const lldesc_t *output, gdma_trigger_peripheral_t peripheral)
96 {
97     int rx_ch_id = 0;
98     esp_err_t ret = ESP_OK;
99 
100     if (tx_channel == NULL) {
101         /* Allocate a pair of RX and TX for crypto, should only happen the first time we use the GMDA
102            or if user called esp_crypto_shared_gdma_release */
103         ret = crypto_shared_gdma_init();
104     }
105 
106     if (ret != ESP_OK) {
107         return ret;
108     }
109 
110     /* Tx channel is shared between AES and SHA, need to connect to peripheral every time */
111     gdma_disconnect(tx_channel);
112 
113     if (peripheral == GDMA_TRIG_PERIPH_SHA) {
114         gdma_connect(tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_SHA, 0));
115     } else if (peripheral == GDMA_TRIG_PERIPH_AES) {
116         gdma_connect(tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_AES, 0));
117     } else {
118         return ESP_ERR_INVALID_ARG;
119     }
120 
121     /* tx channel is reset by gdma_connect(), also reset rx to ensure a known state */
122     gdma_get_channel_id(rx_channel, &rx_ch_id);
123     gdma_ll_rx_reset_channel(&GDMA, rx_ch_id);
124 
125     gdma_start(tx_channel, (intptr_t)input);
126     gdma_start(rx_channel, (intptr_t)output);
127 
128     return ESP_OK;
129 }
130 
esp_crypto_shared_gdma_free()131 void esp_crypto_shared_gdma_free()
132 {
133     esp_crypto_sha_aes_lock_acquire();
134 
135     if (rx_channel != NULL) {
136         gdma_disconnect(rx_channel);
137         gdma_del_channel(rx_channel);
138         rx_channel = NULL;
139     }
140 
141     if (tx_channel != NULL) {
142         gdma_disconnect(tx_channel);
143         gdma_del_channel(tx_channel);
144         tx_channel = NULL;
145     }
146 
147     esp_crypto_sha_aes_lock_release();
148 }
149