summaryrefslogtreecommitdiff
path: root/usr/src/uts/sun4u/sys/pci/pci_dma.h
blob: c2a013c68cfad724828f3d0194d9aaf973971766 (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
305
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#ifndef	_SYS_PCI_DMA_H
#define	_SYS_PCI_DMA_H

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#ifdef	__cplusplus
extern "C" {
#endif

typedef	pfn_t iopfn_t;
#define	MAKE_DMA_COOKIE(cp, address, size)	\
	{					\
		(cp)->dmac_notused = 0;		\
		(cp)->dmac_type = 0;		\
		(cp)->dmac_laddress = (address);	\
		(cp)->dmac_size = (size);	\
	}

#define	HAS_REDZONE(mp)	(((mp)->dmai_rflags & DDI_DMA_REDZONE) ? 1 : 0)

#define	PCI_DMA_HAT_NUM_CB_COOKIES	5

typedef struct pci_dma_hdl {
	ddi_dma_impl_t	pdh_ddi_hdl;
	ddi_dma_attr_t	pdh_attr_dev;
	uint64_t	pdh_sync_buf_pa;
	void		*pdh_cbcookie[PCI_DMA_HAT_NUM_CB_COOKIES];
} pci_dma_hdl_t;

struct pci_dma_impl { /* forthdebug only, keep in sync with ddi_dma_impl_t */
	ulong_t		dmai_mapping;
	uint_t		dmai_size;
	off_t		dmai_offset;
	uint_t		dmai_minxfer;
	uint_t		dmai_burstsizes;
	uint_t		dmai_ndvmapages;
	uint_t		dmai_roffset;
	uint_t		dmai_rflags;
	uint_t		dmai_flags;
	uint_t		dmai_nwin;
	uint_t		dmai_winsize;
	caddr_t		dmai_tte_fdvma;
	void		*dmai_pfnlst;
	uint_t		*dmai_pfn0;
	void		*dmai_winlst;
	dev_info_t	*dmai_rdip;
	ddi_dma_obj_t	dmai_object;
	ddi_dma_attr_t	dmai_attr_aug;
	ddi_dma_cookie_t *dmai_cookie;

	int		(*dmai_fault_check)(struct ddi_dma_impl *handle);
	void		(*dmai_fault_notify)(struct ddi_dma_impl *handle);
	int		dmai_fault;

	ddi_dma_attr_t	pdh_attr_dev;
	uint64_t	pdh_sync_buf_pa;
	void		*pdh_cbcookie[PCI_DMA_HAT_NUM_CB_COOKIES];
};

/*
 * flags for overloading dmai_inuse field of the dma request
 * structure:
 */
#define	dmai_flags		dmai_inuse
#define	dmai_tte		dmai_nexus_private
#define	dmai_fdvma		dmai_nexus_private
#define	dmai_pfnlst		dmai_iopte
#define	dmai_winlst		dmai_minfo
#define	dmai_pfn0		dmai_sbi
#define	dmai_roffset		dmai_pool

#define	MP_PFN0(mp)		((iopfn_t)(mp)->dmai_pfn0)
#define	MP_HAT_CB_COOKIE(mp, i)	((i < PCI_DMA_HAT_NUM_CB_COOKIES)? \
	(((pci_dma_hdl_t *)(mp))->pdh_cbcookie[i]) : NULL)
#define	MP_HAT_CB_COOKIE_PTR(mp, i) \
	((i < PCI_DMA_HAT_NUM_CB_COOKIES)? \
	&(((pci_dma_hdl_t *)(mp))->pdh_cbcookie[i]) : NULL)
#define	WINLST(mp)		((pci_dma_win_t *)(mp)->dmai_winlst)
#define	DEV_ATTR(mp)		(&((pci_dma_hdl_t *)(mp))->pdh_attr_dev)
#define	SYNC_BUF_PA(mp)		(((pci_dma_hdl_t *)(mp))->pdh_sync_buf_pa)
#define	SET_DMAATTR(p, lo, hi, nocross, cntmax)	\
	(p)->dma_attr_addr_lo	= (lo); \
	(p)->dma_attr_addr_hi	= (hi); \
	(p)->dma_attr_seg	= (nocross); \
	(p)->dma_attr_count_max	= (cntmax);

#define	SET_DMAALIGN(p, align) \
	(p)->dma_attr_align = (align);

#define	DMAI_FLAGS_INUSE	0x1
#define	DMAI_FLAGS_BYPASSREQ	0x2
#define	DMAI_FLAGS_PEER_ONLY	0x4
#define	DMAI_FLAGS_NOCTX	0x8
#define	DMAI_FLAGS_DVMA		0x10
#define	DMAI_FLAGS_BYPASS	0x20
#define	DMAI_FLAGS_PEER_TO_PEER	0x40
#define	DMAI_FLAGS_DMA		(DMAI_FLAGS_BYPASS | DMAI_FLAGS_PEER_TO_PEER)
#define	DMAI_FLAGS_DMA_TYPE	(DMAI_FLAGS_DMA | DMAI_FLAGS_DVMA)
#define	DMAI_FLAGS_CONTEXT	0x100
#define	DMAI_FLAGS_FASTTRACK	0x200
#define	DMAI_FLAGS_VMEMCACHE	0x400
#define	DMAI_FLAGS_PGPFN	0x800
#define	DMAI_FLAGS_NOSYSLIMIT	0x1000
#define	DMAI_FLAGS_NOFASTLIMIT	0x2000
#define	DMAI_FLAGS_NOSYNC	0x4000
#define	DMAI_FLAGS_RELOC	0x8000
#define	DMAI_FLAGS_MAPPED	0x10000
#define	DMAI_FLAGS_PRESERVE	(DMAI_FLAGS_PEER_ONLY | DMAI_FLAGS_BYPASSREQ | \
	DMAI_FLAGS_NOSYSLIMIT | DMAI_FLAGS_NOFASTLIMIT | DMAI_FLAGS_NOCTX)

#define	HAS_NOFASTLIMIT(mp)	((mp)->dmai_flags & DMAI_FLAGS_NOFASTLIMIT)
#define	HAS_NOSYSLIMIT(mp)	((mp)->dmai_flags & DMAI_FLAGS_NOSYSLIMIT)
#define	PCI_DMA_ISPEERONLY(mp)	((mp)->dmai_flags & DMAI_FLAGS_PEER_ONLY)
#define	PCI_DMA_ISPGPFN(mp)	((mp)->dmai_flags & DMAI_FLAGS_PGPFN)
#define	PCI_DMA_TYPE(mp)	((mp)->dmai_flags & DMAI_FLAGS_DMA_TYPE)
#define	PCI_DMA_ISDVMA(mp)	(PCI_DMA_TYPE(mp) == DMAI_FLAGS_DVMA)
#define	PCI_DMA_ISBYPASS(mp)	(PCI_DMA_TYPE(mp) == DMAI_FLAGS_BYPASS)
#define	PCI_DMA_ISPTP(mp)	(PCI_DMA_TYPE(mp) == DMAI_FLAGS_PEER_TO_PEER)
#define	PCI_DMA_CANFAST(mp)	(((mp)->dmai_ndvmapages + HAS_REDZONE(mp) \
		<= pci_dvma_page_cache_clustsz) && HAS_NOFASTLIMIT(mp))
#define	PCI_DMA_WINNPGS(mp)	IOMMU_BTOP((mp)->dmai_winsize)
#define	PCI_DMA_CANCACHE(mp)	(!HAS_REDZONE(mp) && \
		(PCI_DMA_WINNPGS(mp) == 1) && HAS_NOSYSLIMIT(mp))
#define	PCI_DMA_CANRELOC(mp)	((mp)->dmai_flags & DMAI_FLAGS_RELOC)
#define	PCI_DMA_ISMAPPED(mp)	((mp)->dmai_flags & DMAI_FLAGS_MAPPED)

#define	PCI_SYNC_FLAG_SZSHIFT	6
#define	PCI_SYNC_FLAG_SIZE	(1 << PCI_SYNC_FLAG_SZSHIFT)
#define	PCI_SYNC_FLAG_FAILED	1
#define	PCI_SYNC_FLAG_LOCKED	2

#define	PCI_DMA_SYNC_DDI_FLAGS	((1 << 16) - 1)	/* Look for only DDI flags  */
#define	PCI_DMA_SYNC_EXT	(1 << 30)	/* enable/disable extension */
#define	PCI_DMA_SYNC_UNBIND	(1 << 28)	/* internal: part of unbind */
#define	PCI_DMA_SYNC_BAR	(1 << 26)	/* wait for all posted sync  */
#define	PCI_DMA_SYNC_POST	(1 << 25)	/* post request and return   */
#define	PCI_DMA_SYNC_PRIVATE	(1 << 24)	/* alloc private sync buffer */
#define	PCI_DMA_SYNC_DURING	(1 << 22)	/* sync in-progress dma */
#define	PCI_DMA_SYNC_BEFORE	(1 << 21)	/* before read or write */
#define	PCI_DMA_SYNC_AFTER	(1 << 20)	/* after read or write  */
#define	PCI_DMA_SYNC_WRITE	(1 << 17)	/* data from device to mem */
#define	PCI_DMA_SYNC_READ	(1 << 16)	/* data from memory to dev */

#define	PCI_FLOW_ID_TO_PA(flow_p, flow_id) \
	((flow_p)->flow_buf_pa + ((flow_id) << PCI_SYNC_FLAG_SZSHIFT))

#define	DEV_NOFASTLIMIT(lo, hi, fastlo, fasthi, align_pg) \
	(((lo) <= (fastlo)) && ((hi) >= (fasthi)) && \
	((align_pg) <= pci_dvma_page_cache_clustsz))

#define	DEV_NOSYSLIMIT(lo, hi, syslo, syshi, align_pg) \
	(((lo) <= (syslo)) && ((hi) >= (syshi)) && (align_pg == 1))

#define	PCI_DMA_NOCTX(rdip) (!pci_use_contexts || (pci_ctx_no_active_flush && \
	ddi_prop_exists(DDI_DEV_T_ANY, rdip, \
		DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "active-dma-flush")))
#define	PCI_DMA_USECTX(mp)	(!(mp->dmai_flags & DMAI_FLAGS_NOCTX))

#define	PCI_DMA_BYPASS_PREFIX(mp, pfn) \
	(PCI_DMA_ISBYPASS(mp) ? COMMON_IOMMU_BYPASS_BASE | \
	(pf_is_memory(pfn) ? 0 : COMMON_IOMMU_BYPASS_NONCACHE) : 0)
#define	PCI_DMA_BADPTP(pfn, attrp) \
	((IOMMU_PTOB(pfn) < attrp->dma_attr_addr_lo) || \
	(IOMMU_PTOB(pfn) > attrp->dma_attr_addr_hi))
#define	PCI_DMA_CURWIN(mp) \
	(((mp)->dmai_offset + (mp)->dmai_roffset) / (mp)->dmai_winsize)

#ifdef PCI_DMA_PROF

/* collect fast track failure statistics */
#define	PCI_DVMA_FASTTRAK_PROF(mp) { \
if ((mp->dmai_ndvmapages + HAS_REDZONE(mp)) > pci_dvma_page_cache_clustsz) \
	pci_dvmaft_npages++; \
else if (!HAS_NOFASTLIMIT(mp)) \
	pci_dvmaft_limit++; \
}

#else /* !PCI_DMA_PROF */

#define	PCI_DVMA_FASTTRAK_PROF(mp)

#endif	/* PCI_DMA_PROF */

typedef struct pci_dma_win {
	struct pci_dma_win *win_next;
	uint32_t win_ncookies;
	uint32_t win_curseg;
	uint64_t win_size;
	uint64_t win_offset;
	/* cookie table: sizeof (ddi_dma_cookie_t) * win_ncookies */
} pci_dma_win_t;

/* dvma debug records */
struct dvma_rec {
	char *dvma_addr;
	uint_t len;
	ddi_dma_impl_t *mp;
	struct dvma_rec *next;
};

typedef struct pbm pbm_t;
extern int pci_dma_sync(dev_info_t *dip, dev_info_t *rdip,
	ddi_dma_handle_t handle, off_t off, size_t len, uint32_t sync_flags);

extern int pci_dma_win(dev_info_t *dip, dev_info_t *rdip,
	ddi_dma_handle_t handle, uint_t win, off_t *offp,
	size_t *lenp, ddi_dma_cookie_t *cookiep, uint_t *ccountp);

extern ddi_dma_impl_t *pci_dma_allocmp(dev_info_t *dip, dev_info_t *rdip,
	int (*waitfp)(caddr_t), caddr_t arg);
extern void pci_dma_freemp(ddi_dma_impl_t *mp);
extern void pci_dma_freepfn(ddi_dma_impl_t *mp);
extern ddi_dma_impl_t *pci_dma_lmts2hdl(dev_info_t *dip, dev_info_t *rdip,
	iommu_t *iommu_p, ddi_dma_req_t *dmareq);
extern int pci_dma_attr2hdl(pci_t *pci_p, ddi_dma_impl_t *mp);
extern uint32_t pci_dma_consist_check(uint32_t req_flags, pbm_t *pbm_p);
extern int pci_dma_type(pci_t *pci_p, ddi_dma_req_t *req, ddi_dma_impl_t *mp);
extern int pci_dma_pfn(pci_t *pci_p, ddi_dma_req_t *req, ddi_dma_impl_t *mp);
extern int pci_dvma_win(pci_t *pci_p, ddi_dma_req_t *r, ddi_dma_impl_t *mp);
extern void pci_dma_freewin(ddi_dma_impl_t *mp);
extern int pci_dvma_map_fast(iommu_t *iommu_p, ddi_dma_impl_t *mp);
extern int pci_dvma_map(ddi_dma_impl_t *mp, ddi_dma_req_t *dmareq,
	iommu_t *iommu_p);
extern void pci_dvma_unmap(iommu_t *iommu_p, ddi_dma_impl_t *mp);
extern void pci_dma_sync_unmap(dev_info_t *dip, dev_info_t *rdip,
	ddi_dma_impl_t *mp);
extern int pci_dma_physwin(pci_t *pci_p, ddi_dma_req_t *dmareq,
	ddi_dma_impl_t *mp);
extern int pci_dvma_ctl(dev_info_t *dip, dev_info_t *rdip,
	ddi_dma_impl_t *mp, enum ddi_dma_ctlops cmd, off_t *offp,
	size_t *lenp, caddr_t *objp, uint_t cache_flags);
extern int pci_dma_ctl(dev_info_t *dip, dev_info_t *rdip,
	ddi_dma_impl_t *mp, enum ddi_dma_ctlops cmd, off_t *offp,
	size_t *lenp, caddr_t *objp, uint_t cache_flags);
extern void pci_vmem_do_free(iommu_t *iommu_p, void *base_addr, size_t npages,
	int vmemcache);

#define	PCI_GET_MP_NCOOKIES(mp)		((mp)->dmai_ncookies)
#define	PCI_SET_MP_NCOOKIES(mp, nc)	((mp)->dmai_ncookies = (nc))
#define	PCI_GET_MP_PFN1_ADDR(mp)	(((iopfn_t *)(mp)->dmai_pfnlst) + 1)

#define	PCI_GET_MP_TTE(tte) \
	(((uint64_t)(uintptr_t)(tte) >> 5) << (32 + 5) | \
	    ((uint32_t)(uintptr_t)(tte)) & 0x12)
#define	PCI_SAVE_MP_TTE(mp, tte)	\
	(mp)->dmai_tte = (caddr_t)(HI32(tte) | ((tte) & 0x12))

#define	PCI_GET_MP_PFN1(mp, page_no) (((iopfn_t *)(mp)->dmai_pfnlst)[page_no])
#define	PCI_GET_MP_PFN(mp, page_no)	((mp)->dmai_ndvmapages == 1 ? \
	(iopfn_t)(mp)->dmai_pfnlst : PCI_GET_MP_PFN1(mp, page_no))

#define	PCI_SET_MP_PFN(mp, page_no, pfn) { \
	if ((mp)->dmai_ndvmapages == 1) { \
		ASSERT(!((page_no) || (mp)->dmai_pfnlst)); \
		(mp)->dmai_pfnlst = (void *)(pfn); \
	} else \
		((iopfn_t *)(mp)->dmai_pfnlst)[page_no] = (iopfn_t)(pfn); \
}
#define	PCI_SET_MP_PFN1(mp, page_no, pfn) { \
	((iopfn_t *)(mp)->dmai_pfnlst)[page_no] = (pfn); \
}

#define	GET_TTE_TEMPLATE(mp) MAKE_TTE_TEMPLATE(PCI_GET_MP_PFN((mp), 0), (mp))

extern int pci_dma_freehdl(dev_info_t *dip, dev_info_t *rdip,
	ddi_dma_handle_t handle);

int pci_dma_handle_clean(dev_info_t *rdip, ddi_dma_handle_t handle);

#if defined(DEBUG)
extern void dump_dma_handle(uint64_t flag, dev_info_t *dip, ddi_dma_impl_t *hp);
#else
#define	dump_dma_handle(flag, dip, hp)
#endif

#ifdef	__cplusplus
}
#endif

#endif	/* _SYS_PCI_DMA_H */