aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/kpc2000/kpc_dma/kpc_dma_driver.h
blob: 8b9c978257b99b41748339402ad3208e1561434a (plain) (blame)
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
/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef KPC_DMA_DRIVER_H
#define KPC_DMA_DRIVER_H
#include <linux/platform_device.h>
#include <linux/cdev.h>
#include <linux/kfifo.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/sched.h>
#include <linux/miscdevice.h>
#include <linux/rwsem.h>
#include <linux/dma-mapping.h>
#include <linux/dmapool.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#include <linux/bitops.h>
#include "../kpc.h"

struct kp2000_device;
struct kpc_dma_device {
	struct list_head            list;
	struct platform_device     *pldev;
	u32 __iomem                *eng_regs;
	struct device              *kpc_dma_dev;
	struct kobject              kobj;
	char                        name[16];

	int                         dir; // DMA_FROM_DEVICE || DMA_TO_DEVICE
	struct mutex                sem;
	unsigned int                irq;
	struct work_struct          irq_work;

	atomic_t                    open_count;

	size_t                      accumulated_bytes;
	u32                         accumulated_flags;

	// Descriptor "Pool" housekeeping
	u32                         desc_pool_cnt;
	struct dma_pool            *desc_pool;
	struct kpc_dma_descriptor  *desc_pool_first;
	struct kpc_dma_descriptor  *desc_pool_last;

	struct kpc_dma_descriptor  *desc_next;
	struct kpc_dma_descriptor  *desc_completed;
};

struct dev_private_data {
	struct kpc_dma_device      *ldev;
	u64                         card_addr;
	u64                         user_ctl;
	u64                         user_ctl_last;
	u64                         user_sts;
};

struct kpc_dma_device *kpc_dma_lookup_device(int minor);

extern const struct file_operations  kpc_dma_fops;

#define ENG_CAP_PRESENT                 0x00000001
#define ENG_CAP_DIRECTION               0x00000002
#define ENG_CAP_TYPE_MASK               0x000000F0
#define ENG_CAP_NUMBER_MASK             0x0000FF00
#define ENG_CAP_CARD_ADDR_SIZE_MASK     0x007F0000
#define ENG_CAP_DESC_MAX_BYTE_CNT_MASK  0x3F000000
#define ENG_CAP_PERF_SCALE_MASK         0xC0000000

#define ENG_CTL_IRQ_ENABLE              BIT(0)
#define ENG_CTL_IRQ_ACTIVE              BIT(1)
#define ENG_CTL_DESC_COMPLETE           BIT(2)
#define ENG_CTL_DESC_ALIGN_ERR          BIT(3)
#define ENG_CTL_DESC_FETCH_ERR          BIT(4)
#define ENG_CTL_SW_ABORT_ERR            BIT(5)
#define ENG_CTL_DESC_CHAIN_END          BIT(7)
#define ENG_CTL_DMA_ENABLE              BIT(8)
#define ENG_CTL_DMA_RUNNING             BIT(10)
#define ENG_CTL_DMA_WAITING             BIT(11)
#define ENG_CTL_DMA_WAITING_PERSIST     BIT(12)
#define ENG_CTL_DMA_RESET_REQUEST       BIT(14)
#define ENG_CTL_DMA_RESET               BIT(15)
#define ENG_CTL_DESC_FETCH_ERR_CLASS_MASK   0x700000

struct aio_cb_data {
	struct dev_private_data    *priv;
	struct kpc_dma_device      *ldev;
	struct completion  *cpl;
	unsigned char       flags;
	size_t              len;

	unsigned int        page_count;
	struct page       **user_pages;
	struct sg_table     sgt;
	int                 mapped_entry_count;
};

#define ACD_FLAG_DONE               0
#define ACD_FLAG_ABORT              1
#define ACD_FLAG_ENG_ACCUM_ERROR    4
#define ACD_FLAG_ENG_ACCUM_SHORT    5

struct kpc_dma_descriptor {
	struct {
		volatile u32  DescByteCount              :20;
		volatile u32  DescStatusErrorFlags       :4;
		volatile u32  DescStatusFlags            :8;
	};
		volatile u32  DescUserControlLS;
		volatile u32  DescUserControlMS;
		volatile u32  DescCardAddrLS;
	struct {
		volatile u32  DescBufferByteCount        :20;
		volatile u32  DescCardAddrMS             :4;
		volatile u32  DescControlFlags           :8;
	};
		volatile u32  DescSystemAddrLS;
		volatile u32  DescSystemAddrMS;
		volatile u32  DescNextDescPtr;

		dma_addr_t    MyDMAAddr;
		struct kpc_dma_descriptor   *Next;

		struct aio_cb_data  *acd;
} __attribute__((packed));
// DescControlFlags:
#define DMA_DESC_CTL_SOP            BIT(7)
#define DMA_DESC_CTL_EOP            BIT(6)
#define DMA_DESC_CTL_AFIFO          BIT(2)
#define DMA_DESC_CTL_IRQONERR       BIT(1)
#define DMA_DESC_CTL_IRQONDONE      BIT(0)
// DescStatusFlags:
#define DMA_DESC_STS_SOP            BIT(7)
#define DMA_DESC_STS_EOP            BIT(6)
#define DMA_DESC_STS_ERROR          BIT(4)
#define DMA_DESC_STS_USMSZ          BIT(3)
#define DMA_DESC_STS_USLSZ          BIT(2)
#define DMA_DESC_STS_SHORT          BIT(1)
#define DMA_DESC_STS_COMPLETE       BIT(0)
// DescStatusErrorFlags:
#define DMA_DESC_ESTS_ECRC          BIT(2)
#define DMA_DESC_ESTS_POISON        BIT(1)
#define DMA_DESC_ESTS_UNSUCCESSFUL  BIT(0)

#define DMA_DESC_ALIGNMENT          0x20

static inline
u32  GetEngineCapabilities(struct kpc_dma_device *eng)
{
	return readl(eng->eng_regs + 0);
}

static inline
void  WriteEngineControl(struct kpc_dma_device *eng, u32 value)
{
	writel(value, eng->eng_regs + 1);
}

static inline
u32  GetEngineControl(struct kpc_dma_device *eng)
{
	return readl(eng->eng_regs + 1);
}

static inline
void  SetClearEngineControl(struct kpc_dma_device *eng, u32 set_bits, u32 clear_bits)
{
	u32 val = GetEngineControl(eng);

	val |= set_bits;
	val &= ~clear_bits;
	WriteEngineControl(eng, val);
}

static inline
void  SetEngineNextPtr(struct kpc_dma_device *eng, struct kpc_dma_descriptor *desc)
{
	writel(desc->MyDMAAddr, eng->eng_regs + 2);
}

static inline
void  SetEngineSWPtr(struct kpc_dma_device *eng, struct kpc_dma_descriptor *desc)
{
	writel(desc->MyDMAAddr, eng->eng_regs + 3);
}

static inline
void  ClearEngineCompletePtr(struct kpc_dma_device *eng)
{
	writel(0, eng->eng_regs + 4);
}

static inline
u32  GetEngineCompletePtr(struct kpc_dma_device *eng)
{
	return readl(eng->eng_regs + 4);
}

static inline
void  lock_engine(struct kpc_dma_device *eng)
{
	BUG_ON(!eng);
	mutex_lock(&eng->sem);
}

static inline
void  unlock_engine(struct kpc_dma_device *eng)
{
	BUG_ON(!eng);
	mutex_unlock(&eng->sem);
}

/// Shared Functions
void  start_dma_engine(struct kpc_dma_device *eng);
int   setup_dma_engine(struct kpc_dma_device *eng, u32 desc_cnt);
void  stop_dma_engine(struct kpc_dma_device *eng);
void  destroy_dma_engine(struct kpc_dma_device *eng);
void  clear_desc(struct kpc_dma_descriptor *desc);
int   count_descriptors_available(struct kpc_dma_device *eng);
void  transfer_complete_cb(struct aio_cb_data *acd, size_t xfr_count, u32 flags);

#endif /* KPC_DMA_DRIVER_H */