summaryrefslogtreecommitdiff
path: root/drivers/edgetpu/edgetpu-mapping.h
blob: 668142729924a7b214c7b98ba886a8c3d35ab4d1 (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
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Records the mapped TPU IOVA in a device group.
 *
 * Copyright (C) 2019 Google, Inc.
 */
#ifndef __EDGETPU_MAPPING_H__
#define __EDGETPU_MAPPING_H__

#include <linux/dma-direction.h>
#include <linux/iommu.h>
#include <linux/mutex.h>
#include <linux/rbtree.h>
#include <linux/scatterlist.h>
#include <linux/seq_file.h>
#include <linux/types.h>

#include "edgetpu-internal.h"

struct edgetpu_mapping_root {
	struct rb_root rb;
	struct mutex lock;
	size_t count;
};

/*
 * Use this constant for die index if the mapping is mapped to all dies in a
 * device group.
 */
#define ALL_DIES ((u32)~0)

struct edgetpu_mapping {
	struct rb_node node;
	u64 host_address;
	u32 die_index; /* this mapping is mapped on the @die_index-th die */
	tpu_addr_t device_address;
	/*
	 * The size used for allocating @alloc_iova in bytes. This field may be
	 * set by edgetpu_mmu_map().
	 */
	size_t alloc_size;
	/*
	 * This might be different from @device_address since edgetpu_mmu_map()
	 * may allocate more space than the size requested in the reason of
	 * alignment. This field and @alloc_size are expected to be used in
	 * edgetpu_mmu_unmap() and/or to reserve the IOVA space before calling
	 * edgetpu_mmu_map_iova_sgt().
	 */
	tpu_addr_t alloc_iova;
	edgetpu_map_flag_t flags; /* the flag passed by the runtime */
	/* DMA attributes to be performed for dma_(un)map calls. */
	unsigned long dma_attrs;
	struct sg_table sgt;
	enum dma_data_direction dir;
	/* Private data set by whom created this mapping. */
	void *priv;
	/*
	 * This callback will be called when the mappings in
	 * edgetpu_mapping_root are wiped out, i.e. in edgetpu_mapping_clear().
	 * Release/un-map allocated TPU address in this callback.
	 *
	 * The lock of edgetpu_mapping_root is held when calling this callback.
	 *
	 * This callback is called after @map is unlinked from the RB tree, it's
	 * safe to free @map here.
	 *
	 * Note: edgetpu_mapping_unlink() will NOT call this callback.
	 *
	 * This field is mandatory.
	 */
	void (*release)(struct edgetpu_mapping *map);
	/*
	 * Callback for showing the map.
	 *
	 * The lock of edgetpu_mapping_root is held when calling this callback.
	 *
	 * This callback is optional. If this callback is not set, the mapping
	 * will be skipped on showing.
	 */
	void (*show)(struct edgetpu_mapping *map, struct seq_file *s);
};

static inline void edgetpu_mapping_lock(struct edgetpu_mapping_root *root)
{
	mutex_lock(&root->lock);
}

static inline void edgetpu_mapping_unlock(struct edgetpu_mapping_root *root)
{
	mutex_unlock(&root->lock);
}

/* Initializes the mapping structure. */
void edgetpu_mapping_init(struct edgetpu_mapping_root *mappings);

/*
 * Inserts @map into @mappings.
 *
 * Returns 0 on success.
 * Returns -EBUSY if the map already exists.
 */
int edgetpu_mapping_add(struct edgetpu_mapping_root *mappings,
			struct edgetpu_mapping *map);
/*
 * Finds the mapping previously added with edgetpu_mapping_add().
 *
 * Caller holds the mappings lock.
 *
 * Returns NULL if the mapping is not found.
 */
struct edgetpu_mapping *
edgetpu_mapping_find_locked(struct edgetpu_mapping_root *mappings,
			    u32 die_index, tpu_addr_t iova);

/*
 * Removes @map from @mappings.
 *
 * Caller holds the mappings lock.
 */
void edgetpu_mapping_unlink(struct edgetpu_mapping_root *mappings,
			    struct edgetpu_mapping *map);

/*
 * Returns the first map in @mappings.
 *
 * Caller holds the mappings lock.
 *
 * Returns NULL if @mappings is empty.
 */
struct edgetpu_mapping *
edgetpu_mapping_first_locked(struct edgetpu_mapping_root *mappings);

/*
 * Clears added mappings.
 */
void edgetpu_mapping_clear(struct edgetpu_mapping_root *mappings);

/* dump mappings to seq file @s */
void edgetpu_mappings_show(struct edgetpu_mapping_root *mappings,
			   struct seq_file *s);

static inline int __dma_dir_to_iommu_prot(enum dma_data_direction dir)
{
	int prot = 0;

#ifdef EDGETPU_IS_IO_COHERENT
	prot = IOMMU_CACHE;
#endif
	switch (dir) {
	case DMA_BIDIRECTIONAL:
		return prot | IOMMU_READ | IOMMU_WRITE;
	case DMA_TO_DEVICE:
		return prot | IOMMU_READ;
	case DMA_FROM_DEVICE:
		return prot | IOMMU_WRITE;
	default:
		return 0;
	}
}

#endif /* __EDGETPU_MAPPING_H__ */