summaryrefslogtreecommitdiff
path: root/drivers/edgetpu/edgetpu-firmware.h
blob: f24135b148f8d9128496fb9b8307f47bb63961e0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * EdgeTPU firmware loader.
 *
 * Copyright (C) 2020 Google, Inc.
 */
#ifndef __EDGETPU_FIRMWARE_H__
#define __EDGETPU_FIRMWARE_H__

#include <linux/seq_file.h>

#include "edgetpu-internal.h"

enum edgetpu_firmware_flags {
	/* Image is default firmware for the chip */
	FW_DEFAULT = 0x1,
	/* Image is a second-stage bootloader */
	FW_BL1 = 0x2,
	/* Image resides in on-device memory */
	FW_ONDEV = 0x4,
};

enum edgetpu_firmware_status {
	/* No firmware loaded yet, or last firmware failed to run */
	FW_INVALID = 0,
	/* Load in progress */
	FW_LOADING = 1,
	/* Current firmware is valid and can be restarted */
	FW_VALID = 2,
};

/* Firmware flavors returned via KCI FIRMWARE_INFO command. */
enum edgetpu_fw_flavor {
	/* unused value for extending enum storage type */
	FW_FLAVOR_ERROR = -1,
	/* used by host when cannot determine the flavor */
	FW_FLAVOR_UNKNOWN = 0,
	/* second-stage bootloader */
	FW_FLAVOR_BL1 = 1,
	/* systest app image */
	FW_FLAVOR_SYSTEST = 2,
	/* default production app image */
	FW_FLAVOR_PROD_DEFAULT = 3,
	/* custom image produced by other teams */
	FW_FLAVOR_CUSTOM = 4,
};

/* Firmware info filled out via KCI FIRMWARE_INFO command. */
struct edgetpu_fw_info {
	uint64_t fw_build_time;		/* BuildData::Timestamp() */
	uint32_t fw_flavor;		/* enum edgetpu_fw_flavor */
	uint32_t fw_changelist;		/* BuildData::Changelist() */
	uint32_t spare[10];
};

struct edgetpu_firmware_private;

struct edgetpu_firmware {
	struct edgetpu_dev *etdev;
	struct edgetpu_firmware_private *p;
};

struct edgetpu_firmware_buffer {
	/*
	 * fields set by alloc_buffer() handler for using custom allocated
	 * buffer
	 *
	 * edgetpu_firmware framework also updates these fields when using
	 * shared firmware buffer.
	 */
	/*
	 * kernel VA, leave NULL to indicate edgetpu_firmware using shared
	 * firmware buffer.
	 */
	void *vaddr;
	size_t alloc_size;	/* allocated size of @vaddr in bytes */
	size_t used_size_align;	/* firmware size alignment in bytes */

	/* fields set by setup_buffer() handler */
	dma_addr_t dma_addr;	/* DMA handle for downstream IOMMU, if any */

	/* fields set by prepare_run() handler */
	void __iomem *dram_kva;	/* kernel VA of device DRAM image or zero */
	phys_addr_t dram_tpa;	/* tpu phys addr of device DRAM image or zero */

	/* fields modifiable by handlers */
	enum edgetpu_firmware_flags flags;

	/*
	 * fields set by edgetpu_firmware, don't modify the following fields in
	 * the handlers
	 */
	size_t used_size;	/* actual size of firmware image */
	const char *name;	/* the name of this firmware */
};

/*
 * Descriptor for loaded firmware, either in shared buffer mode or carveout mode
 * (non-shared, custom allocated memory).
 */
struct edgetpu_firmware_desc {
	/*
	 * Mode independent buffer information. This is either passed into or
	 * updated by handlers.
	 */
	struct edgetpu_firmware_buffer buf;
	/*
	 * Shared firmware buffer when we're using shared buffer mode. This
	 * pointer to keep and release the reference count on unloading this
	 * shared firmware buffer.
	 *
	 * This is NULL when firmware is loaded in carveout mode.
	 */
	struct edgetpu_shared_fw_buffer *shared_buf;
};

struct edgetpu_firmware_chip_data {
	/* Name of default firmware image for this chip. */
	const char *default_firmware_name;

	/*
	 * Chip handlers called by common firmware processing.
	 * Each handler returns 0 to indicate success, non-zero value to
	 * indicate error.
	 */
	int (*after_create)(struct edgetpu_firmware *et_fw);
	/*
	 * Release resource used in platform specific implementation,
	 * including stopping firmware. So that internal cleanup could
	 * invoke teardown_buffer() safely after then.
	 */
	void (*before_destroy)(struct edgetpu_firmware *et_fw);
	/*
	 * Allocate a buffer for loading firmware and filling out the
	 * information into @fw_buf before running. See comments of
	 * edgetpu_firmware_buffer for the details of each field.
	 *
	 * This is invoked for each run.
	 */
	int (*alloc_buffer)(struct edgetpu_firmware *et_fw,
			    struct edgetpu_firmware_buffer *fw_buf);
	/*
	 * Free the buffer allocated by alloc_buffer() handler after running.
	 * See comments of edgetpu_firmware_buffer for the details of each
	 * field.
	 *
	 * This is invoked for each run.
	 */
	void (*free_buffer)(struct edgetpu_firmware *et_fw,
			    struct edgetpu_firmware_buffer *fw_buf);
	/*
	 * Setup for an allocated host buffer, mainly for dma mapping,
	 * for loading firmware and filling out the information into
	 * @fw_buf before running. See comments of
	 * edgetpu_firmware_buffer for the details of each
	 * field.
	 *
	 * This is invoked for each run.
	 */
	int (*setup_buffer)(struct edgetpu_firmware *et_fw,
			    struct edgetpu_firmware_buffer *fw_buf);
	/* Release the resources previously allocated by setup_buffer(). */
	void (*teardown_buffer)(struct edgetpu_firmware *et_fw,
				struct edgetpu_firmware_buffer *fw_buf);
	/*
	 * Platform-specific handling after firmware loaded, before running
	 * the firmware, such as validating the firmware or resetting the
	 * processor.
	 */
	int (*prepare_run)(struct edgetpu_firmware *et_fw,
			   struct edgetpu_firmware_buffer *fw_buf);
	/* Firmware running, after successful handshake. */
	void (*launch_complete)(struct edgetpu_firmware *et_fw);
	/* Firmware load failed or unsuccessful handshake. */
	void (*launch_failed)(struct edgetpu_firmware *et_fw, int ret);

	/*
	 * Optional platform-specific handler to restart an already loaded
	 * firmware.
	 */
	int (*restart)(struct edgetpu_firmware *et_fw, bool force_reset);
};

/*
 * Chip-dependent (actually chip family dependent, mobile vs. MCP) calls
 * for loading/unloading firmware images.  These handle chip-specified carveout
 * buffers vs. shared firmware handling for multi-chip platforms.  Used by the
 * common firmware layer.
 */
int edgetpu_firmware_chip_load_locked(
		struct edgetpu_firmware *et_fw,
		struct edgetpu_firmware_desc *fw_desc, const char *name);
void edgetpu_firmware_chip_unload_locked(
		struct edgetpu_firmware *et_fw,
		struct edgetpu_firmware_desc *fw_desc);

/*
 * Returns the chip-specific IOVA where the firmware is mapped.
 *
 * Debug purpose only.
 */
unsigned long edgetpu_chip_firmware_iova(struct edgetpu_dev *etdev);

/*
 * Load and run firmware.
 * @name: the name passed into underlying request_firmware API
 * @flags: edgetpu_firmware_flags for the image
 * Used internally by the sysfs load interface and by unit tests.
 */
int edgetpu_firmware_run(struct edgetpu_dev *etdev, const char *name,
			 enum edgetpu_firmware_flags flags);

/* Load and run the default firmware name for the chip. */
int edgetpu_firmware_run_default(struct edgetpu_dev *etdev);

/* Runs default firmware for the chip, caller holds FW/PM locks */
int edgetpu_firmware_run_default_locked(struct edgetpu_dev *etdev);

/*
 * Private data set and used by handlers. It is expected to
 * allocate and set the data on after_create() and release on
 * before_destroy().
 */
void edgetpu_firmware_set_data(struct edgetpu_firmware *et_fw, void *data);
void *edgetpu_firmware_get_data(struct edgetpu_firmware *et_fw);

int edgetpu_firmware_create(struct edgetpu_dev *etdev,
			    const struct edgetpu_firmware_chip_data *chip_fw);
void edgetpu_firmware_destroy(struct edgetpu_dev *etdev);
void edgetpu_firmware_mappings_show(struct edgetpu_dev *etdev,
				    struct seq_file *s);

/*
 * These functions grab and release the internal firmware lock and must be used
 * before calling the helper functions suffixed with _locked below.
 */

int edgetpu_firmware_lock(struct edgetpu_dev *etdev);
int edgetpu_firmware_trylock(struct edgetpu_dev *etdev);
void edgetpu_firmware_unlock(struct edgetpu_dev *etdev);

/* Returns whether the firmware loading work is ongoing. */
bool edgetpu_firmware_is_loading(struct edgetpu_dev *etdev);

/*
 * Returns the state of the firmware image currently loaded for this device.
 * Caller must hold firmware lock.
 */
enum edgetpu_firmware_status
edgetpu_firmware_status_locked(struct edgetpu_dev *etdev);

/* Caller must hold firmware lock. For unit tests. */
void
edgetpu_firmware_set_status_locked(struct edgetpu_dev *etdev,
				   enum edgetpu_firmware_status status);

/*
 * Restarts the last firmware image loaded
 * Intended for power managed devices to re-run the firmware without a full
 * reload from the file system.
 * Optionally, force a CPU reset to recover from a bad firmware state.
 */
int edgetpu_firmware_restart_locked(struct edgetpu_dev *etdev,
				    bool force_reset);

/*
 * Loads and runs the specified firmware assuming the required locks have been
 * acquired.  Used to run second-stage bootloader.
 */
int edgetpu_firmware_run_locked(struct edgetpu_firmware *et_fw,
				const char *name,
				enum edgetpu_firmware_flags flags);

/* Returns the current firmware image name. */
ssize_t edgetpu_firmware_get_name(struct edgetpu_dev *etdev, char *buf,
				  size_t buflen);

/* Returns the firmware image flavor loaded on the device. */
enum edgetpu_fw_flavor
edgetpu_firmware_get_flavor(struct edgetpu_firmware *et_fw);

/* Returns the changelist ID of the image loaded on the device. */
uint32_t edgetpu_firmware_get_cl(struct edgetpu_firmware *et_fw);

/* Returns the build time of the image in seconds since 1970. */
uint64_t edgetpu_firmware_get_build_time(struct edgetpu_firmware *et_fw);

/*
 * Kernel verify firmware signature (if EDGETPU_FEATURE_FW_SIG enabled).
 *
 * @etdev:      the edgetpu_dev for which the initial load of a (probably
 *              shared) firmware image is requested
 * @name:       name of the image being validated (request_firmware path)
 * @image_data: passes in the pointer to the raw image with signature, returns
 *              pointer to the firmware code image.
 * @image_size: passes in the size of the raw image with signature, returns
 *              size of the firmware code image.
 */
bool edgetpu_firmware_verify_signature(struct edgetpu_dev *etdev,
				       const char *name,
				       void **image_data, size_t *image_size);


#endif /* __EDGETPU_FIRMWARE_H__ */