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
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
|
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* AMD Passthru DMA device driver
* -- Based on the CCP driver
*
* Copyright (C) 2016,2021 Advanced Micro Devices, Inc.
*
* Author: Sanjay R Mehta <sanju.mehta@amd.com>
* Author: Tom Lendacky <thomas.lendacky@amd.com>
* Author: Gary R Hook <gary.hook@amd.com>
*/
#ifndef __PT_DEV_H__
#define __PT_DEV_H__
#include <linux/device.h>
#include <linux/dmaengine.h>
#include <linux/pci.h>
#include <linux/spinlock.h>
#include <linux/mutex.h>
#include <linux/list.h>
#include <linux/wait.h>
#include <linux/dmapool.h>
#include "../virt-dma.h"
#define MAX_PT_NAME_LEN 16
#define MAX_DMAPOOL_NAME_LEN 32
#define MAX_HW_QUEUES 1
#define MAX_CMD_QLEN 100
#define PT_ENGINE_PASSTHRU 5
/* Register Mappings */
#define IRQ_MASK_REG 0x040
#define IRQ_STATUS_REG 0x200
#define CMD_Q_ERROR(__qs) ((__qs) & 0x0000003f)
#define CMD_QUEUE_PRIO_OFFSET 0x00
#define CMD_REQID_CONFIG_OFFSET 0x04
#define CMD_TIMEOUT_OFFSET 0x08
#define CMD_PT_VERSION 0x10
#define CMD_Q_CONTROL_BASE 0x0000
#define CMD_Q_TAIL_LO_BASE 0x0004
#define CMD_Q_HEAD_LO_BASE 0x0008
#define CMD_Q_INT_ENABLE_BASE 0x000C
#define CMD_Q_INTERRUPT_STATUS_BASE 0x0010
#define CMD_Q_STATUS_BASE 0x0100
#define CMD_Q_INT_STATUS_BASE 0x0104
#define CMD_Q_DMA_STATUS_BASE 0x0108
#define CMD_Q_DMA_READ_STATUS_BASE 0x010C
#define CMD_Q_DMA_WRITE_STATUS_BASE 0x0110
#define CMD_Q_ABORT_BASE 0x0114
#define CMD_Q_AX_CACHE_BASE 0x0118
#define CMD_CONFIG_OFFSET 0x1120
#define CMD_CLK_GATE_CTL_OFFSET 0x6004
#define CMD_DESC_DW0_VAL 0x500012
/* Address offset for virtual queue registers */
#define CMD_Q_STATUS_INCR 0x1000
/* Bit masks */
#define CMD_CONFIG_REQID 0
#define CMD_TIMEOUT_DISABLE 0
#define CMD_CLK_DYN_GATING_DIS 0
#define CMD_CLK_SW_GATE_MODE 0
#define CMD_CLK_GATE_CTL 0
#define CMD_QUEUE_PRIO GENMASK(2, 1)
#define CMD_CONFIG_VHB_EN BIT(0)
#define CMD_CLK_DYN_GATING_EN BIT(0)
#define CMD_CLK_HW_GATE_MODE BIT(0)
#define CMD_CLK_GATE_ON_DELAY BIT(12)
#define CMD_CLK_GATE_OFF_DELAY BIT(12)
#define CMD_CLK_GATE_CONFIG (CMD_CLK_GATE_CTL | \
CMD_CLK_HW_GATE_MODE | \
CMD_CLK_GATE_ON_DELAY | \
CMD_CLK_DYN_GATING_EN | \
CMD_CLK_GATE_OFF_DELAY)
#define CMD_Q_LEN 32
#define CMD_Q_RUN BIT(0)
#define CMD_Q_HALT BIT(1)
#define CMD_Q_MEM_LOCATION BIT(2)
#define CMD_Q_SIZE_MASK GENMASK(4, 0)
#define CMD_Q_SIZE GENMASK(7, 3)
#define CMD_Q_SHIFT GENMASK(1, 0)
#define QUEUE_SIZE_VAL ((ffs(CMD_Q_LEN) - 2) & \
CMD_Q_SIZE_MASK)
#define Q_PTR_MASK (2 << (QUEUE_SIZE_VAL + 5) - 1)
#define Q_DESC_SIZE sizeof(struct ptdma_desc)
#define Q_SIZE(n) (CMD_Q_LEN * (n))
#define INT_COMPLETION BIT(0)
#define INT_ERROR BIT(1)
#define INT_QUEUE_STOPPED BIT(2)
#define INT_EMPTY_QUEUE BIT(3)
#define SUPPORTED_INTERRUPTS (INT_COMPLETION | INT_ERROR)
/****** Local Storage Block ******/
#define LSB_START 0
#define LSB_END 127
#define LSB_COUNT (LSB_END - LSB_START + 1)
#define PT_DMAPOOL_MAX_SIZE 64
#define PT_DMAPOOL_ALIGN BIT(5)
#define PT_PASSTHRU_BLOCKSIZE 512
struct pt_device;
struct pt_tasklet_data {
struct completion completion;
struct pt_cmd *cmd;
};
/*
* struct pt_passthru_engine - pass-through operation
* without performing DMA mapping
* @mask: mask to be applied to data
* @mask_len: length in bytes of mask
* @src_dma: data to be used for this operation
* @dst_dma: data produced by this operation
* @src_len: length in bytes of data used for this operation
*
* Variables required to be set when calling pt_enqueue_cmd():
* - bit_mod, byte_swap, src, dst, src_len
* - mask, mask_len if bit_mod is not PT_PASSTHRU_BITWISE_NOOP
*/
struct pt_passthru_engine {
dma_addr_t mask;
u32 mask_len; /* In bytes */
dma_addr_t src_dma, dst_dma;
u64 src_len; /* In bytes */
};
/*
* struct pt_cmd - PTDMA operation request
* @entry: list element
* @work: work element used for callbacks
* @pt: PT device to be run on
* @ret: operation return code
* @flags: cmd processing flags
* @engine: PTDMA operation to perform (passthru)
* @engine_error: PT engine return code
* @passthru: engine specific structures, refer to specific engine struct below
* @callback: operation completion callback function
* @data: parameter value to be supplied to the callback function
*
* Variables required to be set when calling pt_enqueue_cmd():
* - engine, callback
* - See the operation structures below for what is required for each
* operation.
*/
struct pt_cmd {
struct list_head entry;
struct work_struct work;
struct pt_device *pt;
int ret;
u32 engine;
u32 engine_error;
struct pt_passthru_engine passthru;
/* Completion callback support */
void (*pt_cmd_callback)(void *data, int err);
void *data;
};
struct pt_dma_desc {
struct virt_dma_desc vd;
struct pt_device *pt;
enum dma_status status;
size_t len;
bool issued_to_hw;
struct pt_cmd pt_cmd;
};
struct pt_dma_chan {
struct virt_dma_chan vc;
struct pt_device *pt;
};
struct pt_cmd_queue {
struct pt_device *pt;
/* Queue dma pool */
struct dma_pool *dma_pool;
/* Queue base address (not neccessarily aligned)*/
struct ptdma_desc *qbase;
/* Aligned queue start address (per requirement) */
spinlock_t q_lock ____cacheline_aligned;
unsigned int qidx;
unsigned int qsize;
dma_addr_t qbase_dma;
dma_addr_t qdma_tail;
unsigned int active;
unsigned int suspended;
/* Interrupt flag */
bool int_en;
/* Register addresses for queue */
void __iomem *reg_control;
u32 qcontrol; /* Cached control register */
/* Status values from job */
u32 int_status;
u32 q_status;
u32 q_int_status;
u32 cmd_error;
/* Queue Statistics */
unsigned long total_pt_ops;
} ____cacheline_aligned;
struct pt_device {
struct list_head entry;
unsigned int ord;
char name[MAX_PT_NAME_LEN];
struct device *dev;
/* Bus specific device information */
struct pt_msix *pt_msix;
struct pt_dev_vdata *dev_vdata;
unsigned int pt_irq;
/* I/O area used for device communication */
void __iomem *io_regs;
spinlock_t cmd_lock ____cacheline_aligned;
unsigned int cmd_count;
struct list_head cmd;
/*
* The command queue. This represent the queue available on the
* PTDMA that are available for processing cmds
*/
struct pt_cmd_queue cmd_q;
/* Support for the DMA Engine capabilities */
struct dma_device dma_dev;
struct pt_dma_chan *pt_dma_chan;
struct kmem_cache *dma_cmd_cache;
struct kmem_cache *dma_desc_cache;
wait_queue_head_t lsb_queue;
/* Device Statistics */
unsigned long total_interrupts;
struct pt_tasklet_data tdata;
};
/*
* descriptor for PTDMA commands
* 8 32-bit words:
* word 0: function; engine; control bits
* word 1: length of source data
* word 2: low 32 bits of source pointer
* word 3: upper 16 bits of source pointer; source memory type
* word 4: low 32 bits of destination pointer
* word 5: upper 16 bits of destination pointer; destination memory type
* word 6: reserved 32 bits
* word 7: reserved 32 bits
*/
#define DWORD0_SOC BIT(0)
#define DWORD0_IOC BIT(1)
struct dword3 {
unsigned int src_hi:16;
unsigned int src_mem:2;
unsigned int lsb_cxt_id:8;
unsigned int rsvd1:5;
unsigned int fixed:1;
};
struct dword5 {
unsigned int dst_hi:16;
unsigned int dst_mem:2;
unsigned int rsvd1:13;
unsigned int fixed:1;
};
struct ptdma_desc {
u32 dw0;
u32 length;
u32 src_lo;
struct dword3 dw3;
u32 dst_lo;
struct dword5 dw5;
__le32 rsvd1;
__le32 rsvd2;
};
/* Structure to hold PT device data */
struct pt_dev_vdata {
const unsigned int bar;
};
int pt_dmaengine_register(struct pt_device *pt);
void pt_dmaengine_unregister(struct pt_device *pt);
void ptdma_debugfs_setup(struct pt_device *pt);
int pt_core_init(struct pt_device *pt);
void pt_core_destroy(struct pt_device *pt);
int pt_core_perform_passthru(struct pt_cmd_queue *cmd_q,
struct pt_passthru_engine *pt_engine);
void pt_check_status_trans(struct pt_device *pt, struct pt_cmd_queue *cmd_q);
void pt_start_queue(struct pt_cmd_queue *cmd_q);
void pt_stop_queue(struct pt_cmd_queue *cmd_q);
static inline void pt_core_disable_queue_interrupts(struct pt_device *pt)
{
iowrite32(0, pt->cmd_q.reg_control + 0x000C);
}
static inline void pt_core_enable_queue_interrupts(struct pt_device *pt)
{
iowrite32(SUPPORTED_INTERRUPTS, pt->cmd_q.reg_control + 0x000C);
}
#endif
|