xref: /OK3568_Linux_fs/kernel/drivers/dma-buf/heaps/rk_system_heap.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * DMABUF System heap exporter for Rockchip
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2011 Google, Inc.
6*4882a593Smuzhiyun  * Copyright (C) 2019, 2020 Linaro Ltd.
7*4882a593Smuzhiyun  * Copyright (c) 2021, 2022 Rockchip Electronics Co. Ltd.
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * Portions based off of Andrew Davis' SRAM heap:
10*4882a593Smuzhiyun  * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
11*4882a593Smuzhiyun  *	Andrew F. Davis <afd@ti.com>
12*4882a593Smuzhiyun  */
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun #include <linux/dma-buf.h>
15*4882a593Smuzhiyun #include <linux/dma-mapping.h>
16*4882a593Smuzhiyun #include <linux/dma-heap.h>
17*4882a593Smuzhiyun #include <linux/err.h>
18*4882a593Smuzhiyun #include <linux/highmem.h>
19*4882a593Smuzhiyun #include <linux/mm.h>
20*4882a593Smuzhiyun #include <linux/module.h>
21*4882a593Smuzhiyun #include <linux/scatterlist.h>
22*4882a593Smuzhiyun #include <linux/slab.h>
23*4882a593Smuzhiyun #include <linux/swiotlb.h>
24*4882a593Smuzhiyun #include <linux/vmalloc.h>
25*4882a593Smuzhiyun #include <linux/rockchip/rockchip_sip.h>
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun #include "page_pool.h"
28*4882a593Smuzhiyun #include "deferred-free-helper.h"
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun static struct dma_heap *sys_heap;
31*4882a593Smuzhiyun static struct dma_heap *sys_dma32_heap;
32*4882a593Smuzhiyun static struct dma_heap *sys_uncached_heap;
33*4882a593Smuzhiyun static struct dma_heap *sys_uncached_dma32_heap;
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun /* Default setting */
36*4882a593Smuzhiyun static u32 bank_bit_first = 12;
37*4882a593Smuzhiyun static u32 bank_bit_mask = 0x7;
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun struct system_heap_buffer {
40*4882a593Smuzhiyun 	struct dma_heap *heap;
41*4882a593Smuzhiyun 	struct list_head attachments;
42*4882a593Smuzhiyun 	struct mutex lock;
43*4882a593Smuzhiyun 	unsigned long len;
44*4882a593Smuzhiyun 	struct sg_table sg_table;
45*4882a593Smuzhiyun 	int vmap_cnt;
46*4882a593Smuzhiyun 	void *vaddr;
47*4882a593Smuzhiyun 	struct deferred_freelist_item deferred_free;
48*4882a593Smuzhiyun 	struct dmabuf_page_pool **pools;
49*4882a593Smuzhiyun 	bool uncached;
50*4882a593Smuzhiyun };
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun struct dma_heap_attachment {
53*4882a593Smuzhiyun 	struct device *dev;
54*4882a593Smuzhiyun 	struct sg_table *table;
55*4882a593Smuzhiyun 	struct list_head list;
56*4882a593Smuzhiyun 	bool mapped;
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun 	bool uncached;
59*4882a593Smuzhiyun };
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun #define LOW_ORDER_GFP (GFP_HIGHUSER | __GFP_ZERO)
62*4882a593Smuzhiyun #define HIGH_ORDER_GFP  (((GFP_HIGHUSER | __GFP_ZERO | __GFP_NOWARN \
63*4882a593Smuzhiyun 				| __GFP_NORETRY) & ~__GFP_RECLAIM) \
64*4882a593Smuzhiyun 				| __GFP_COMP)
65*4882a593Smuzhiyun static gfp_t order_flags[] = {HIGH_ORDER_GFP, HIGH_ORDER_GFP, LOW_ORDER_GFP};
66*4882a593Smuzhiyun /*
67*4882a593Smuzhiyun  * The selection of the orders used for allocation (1MB, 64K, 4K) is designed
68*4882a593Smuzhiyun  * to match with the sizes often found in IOMMUs. Using order 4 pages instead
69*4882a593Smuzhiyun  * of order 0 pages can significantly improve the performance of many IOMMUs
70*4882a593Smuzhiyun  * by reducing TLB pressure and time spent updating page tables.
71*4882a593Smuzhiyun  */
72*4882a593Smuzhiyun static unsigned int orders[] = {8, 4, 0};
73*4882a593Smuzhiyun #define NUM_ORDERS ARRAY_SIZE(orders)
74*4882a593Smuzhiyun struct dmabuf_page_pool *pools[NUM_ORDERS];
75*4882a593Smuzhiyun struct dmabuf_page_pool *dma32_pools[NUM_ORDERS];
76*4882a593Smuzhiyun 
dup_sg_table(struct sg_table * table)77*4882a593Smuzhiyun static struct sg_table *dup_sg_table(struct sg_table *table)
78*4882a593Smuzhiyun {
79*4882a593Smuzhiyun 	struct sg_table *new_table;
80*4882a593Smuzhiyun 	int ret, i;
81*4882a593Smuzhiyun 	struct scatterlist *sg, *new_sg;
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun 	new_table = kzalloc(sizeof(*new_table), GFP_KERNEL);
84*4882a593Smuzhiyun 	if (!new_table)
85*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	ret = sg_alloc_table(new_table, table->orig_nents, GFP_KERNEL);
88*4882a593Smuzhiyun 	if (ret) {
89*4882a593Smuzhiyun 		kfree(new_table);
90*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
91*4882a593Smuzhiyun 	}
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	new_sg = new_table->sgl;
94*4882a593Smuzhiyun 	for_each_sgtable_sg(table, sg, i) {
95*4882a593Smuzhiyun 		sg_set_page(new_sg, sg_page(sg), sg->length, sg->offset);
96*4882a593Smuzhiyun 		new_sg = sg_next(new_sg);
97*4882a593Smuzhiyun 	}
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 	return new_table;
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun 
system_heap_attach(struct dma_buf * dmabuf,struct dma_buf_attachment * attachment)102*4882a593Smuzhiyun static int system_heap_attach(struct dma_buf *dmabuf,
103*4882a593Smuzhiyun 			      struct dma_buf_attachment *attachment)
104*4882a593Smuzhiyun {
105*4882a593Smuzhiyun 	struct system_heap_buffer *buffer = dmabuf->priv;
106*4882a593Smuzhiyun 	struct dma_heap_attachment *a;
107*4882a593Smuzhiyun 	struct sg_table *table;
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	a = kzalloc(sizeof(*a), GFP_KERNEL);
110*4882a593Smuzhiyun 	if (!a)
111*4882a593Smuzhiyun 		return -ENOMEM;
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	table = dup_sg_table(&buffer->sg_table);
114*4882a593Smuzhiyun 	if (IS_ERR(table)) {
115*4882a593Smuzhiyun 		kfree(a);
116*4882a593Smuzhiyun 		return -ENOMEM;
117*4882a593Smuzhiyun 	}
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	a->table = table;
120*4882a593Smuzhiyun 	a->dev = attachment->dev;
121*4882a593Smuzhiyun 	INIT_LIST_HEAD(&a->list);
122*4882a593Smuzhiyun 	a->mapped = false;
123*4882a593Smuzhiyun 	a->uncached = buffer->uncached;
124*4882a593Smuzhiyun 	attachment->priv = a;
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun 	mutex_lock(&buffer->lock);
127*4882a593Smuzhiyun 	list_add(&a->list, &buffer->attachments);
128*4882a593Smuzhiyun 	mutex_unlock(&buffer->lock);
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	return 0;
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun 
system_heap_detach(struct dma_buf * dmabuf,struct dma_buf_attachment * attachment)133*4882a593Smuzhiyun static void system_heap_detach(struct dma_buf *dmabuf,
134*4882a593Smuzhiyun 			       struct dma_buf_attachment *attachment)
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun 	struct system_heap_buffer *buffer = dmabuf->priv;
137*4882a593Smuzhiyun 	struct dma_heap_attachment *a = attachment->priv;
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	mutex_lock(&buffer->lock);
140*4882a593Smuzhiyun 	list_del(&a->list);
141*4882a593Smuzhiyun 	mutex_unlock(&buffer->lock);
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	sg_free_table(a->table);
144*4882a593Smuzhiyun 	kfree(a->table);
145*4882a593Smuzhiyun 	kfree(a);
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun 
system_heap_map_dma_buf(struct dma_buf_attachment * attachment,enum dma_data_direction direction)148*4882a593Smuzhiyun static struct sg_table *system_heap_map_dma_buf(struct dma_buf_attachment *attachment,
149*4882a593Smuzhiyun 						enum dma_data_direction direction)
150*4882a593Smuzhiyun {
151*4882a593Smuzhiyun 	struct dma_heap_attachment *a = attachment->priv;
152*4882a593Smuzhiyun 	struct sg_table *table = a->table;
153*4882a593Smuzhiyun 	int attr = attachment->dma_map_attrs;
154*4882a593Smuzhiyun 	int ret;
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	if (a->uncached)
157*4882a593Smuzhiyun 		attr |= DMA_ATTR_SKIP_CPU_SYNC;
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	ret = dma_map_sgtable(attachment->dev, table, direction, attr);
160*4882a593Smuzhiyun 	if (ret)
161*4882a593Smuzhiyun 		return ERR_PTR(ret);
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 	a->mapped = true;
164*4882a593Smuzhiyun 	return table;
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun 
system_heap_unmap_dma_buf(struct dma_buf_attachment * attachment,struct sg_table * table,enum dma_data_direction direction)167*4882a593Smuzhiyun static void system_heap_unmap_dma_buf(struct dma_buf_attachment *attachment,
168*4882a593Smuzhiyun 				      struct sg_table *table,
169*4882a593Smuzhiyun 				      enum dma_data_direction direction)
170*4882a593Smuzhiyun {
171*4882a593Smuzhiyun 	struct dma_heap_attachment *a = attachment->priv;
172*4882a593Smuzhiyun 	int attr = attachment->dma_map_attrs;
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	if (a->uncached)
175*4882a593Smuzhiyun 		attr |= DMA_ATTR_SKIP_CPU_SYNC;
176*4882a593Smuzhiyun 	a->mapped = false;
177*4882a593Smuzhiyun 	dma_unmap_sgtable(attachment->dev, table, direction, attr);
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun 
system_heap_dma_buf_begin_cpu_access(struct dma_buf * dmabuf,enum dma_data_direction direction)180*4882a593Smuzhiyun static int system_heap_dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
181*4882a593Smuzhiyun 						enum dma_data_direction direction)
182*4882a593Smuzhiyun {
183*4882a593Smuzhiyun 	struct system_heap_buffer *buffer = dmabuf->priv;
184*4882a593Smuzhiyun 	struct dma_heap_attachment *a;
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 	mutex_lock(&buffer->lock);
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	if (buffer->vmap_cnt)
189*4882a593Smuzhiyun 		invalidate_kernel_vmap_range(buffer->vaddr, buffer->len);
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	if (!buffer->uncached) {
192*4882a593Smuzhiyun 		list_for_each_entry(a, &buffer->attachments, list) {
193*4882a593Smuzhiyun 			if (!a->mapped)
194*4882a593Smuzhiyun 				continue;
195*4882a593Smuzhiyun 			dma_sync_sgtable_for_cpu(a->dev, a->table, direction);
196*4882a593Smuzhiyun 		}
197*4882a593Smuzhiyun 	}
198*4882a593Smuzhiyun 	mutex_unlock(&buffer->lock);
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 	return 0;
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun 
system_heap_dma_buf_end_cpu_access(struct dma_buf * dmabuf,enum dma_data_direction direction)203*4882a593Smuzhiyun static int system_heap_dma_buf_end_cpu_access(struct dma_buf *dmabuf,
204*4882a593Smuzhiyun 					      enum dma_data_direction direction)
205*4882a593Smuzhiyun {
206*4882a593Smuzhiyun 	struct system_heap_buffer *buffer = dmabuf->priv;
207*4882a593Smuzhiyun 	struct dma_heap_attachment *a;
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 	mutex_lock(&buffer->lock);
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 	if (buffer->vmap_cnt)
212*4882a593Smuzhiyun 		flush_kernel_vmap_range(buffer->vaddr, buffer->len);
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun 	if (!buffer->uncached) {
215*4882a593Smuzhiyun 		list_for_each_entry(a, &buffer->attachments, list) {
216*4882a593Smuzhiyun 			if (!a->mapped)
217*4882a593Smuzhiyun 				continue;
218*4882a593Smuzhiyun 			dma_sync_sgtable_for_device(a->dev, a->table, direction);
219*4882a593Smuzhiyun 		}
220*4882a593Smuzhiyun 	}
221*4882a593Smuzhiyun 	mutex_unlock(&buffer->lock);
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 	return 0;
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun 
system_heap_sgl_sync_range(struct device * dev,struct sg_table * sgt,unsigned int offset,unsigned int length,enum dma_data_direction dir,bool for_cpu)226*4882a593Smuzhiyun static int system_heap_sgl_sync_range(struct device *dev,
227*4882a593Smuzhiyun 				      struct sg_table *sgt,
228*4882a593Smuzhiyun 				      unsigned int offset,
229*4882a593Smuzhiyun 				      unsigned int length,
230*4882a593Smuzhiyun 				      enum dma_data_direction dir,
231*4882a593Smuzhiyun 				      bool for_cpu)
232*4882a593Smuzhiyun {
233*4882a593Smuzhiyun 	struct scatterlist *sg;
234*4882a593Smuzhiyun 	unsigned int len = 0;
235*4882a593Smuzhiyun 	dma_addr_t sg_dma_addr;
236*4882a593Smuzhiyun 	int i;
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 	for_each_sgtable_sg(sgt, sg, i) {
239*4882a593Smuzhiyun 		unsigned int sg_offset, sg_left, size = 0;
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 		sg_dma_addr = sg_phys(sg);
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 		len += sg->length;
244*4882a593Smuzhiyun 		if (len <= offset)
245*4882a593Smuzhiyun 			continue;
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 		sg_left = len - offset;
248*4882a593Smuzhiyun 		sg_offset = sg->length - sg_left;
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun 		size = (length < sg_left) ? length : sg_left;
251*4882a593Smuzhiyun 		if (for_cpu)
252*4882a593Smuzhiyun 			dma_sync_single_range_for_cpu(dev, sg_dma_addr,
253*4882a593Smuzhiyun 						      sg_offset, size, dir);
254*4882a593Smuzhiyun 		else
255*4882a593Smuzhiyun 			dma_sync_single_range_for_device(dev, sg_dma_addr,
256*4882a593Smuzhiyun 							 sg_offset, size, dir);
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun 		offset += size;
259*4882a593Smuzhiyun 		length -= size;
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 		if (length == 0)
262*4882a593Smuzhiyun 			break;
263*4882a593Smuzhiyun 	}
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	return 0;
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun static int __maybe_unused
system_heap_dma_buf_begin_cpu_access_partial(struct dma_buf * dmabuf,enum dma_data_direction direction,unsigned int offset,unsigned int len)269*4882a593Smuzhiyun system_heap_dma_buf_begin_cpu_access_partial(struct dma_buf *dmabuf,
270*4882a593Smuzhiyun 					     enum dma_data_direction direction,
271*4882a593Smuzhiyun 					     unsigned int offset,
272*4882a593Smuzhiyun 					     unsigned int len)
273*4882a593Smuzhiyun {
274*4882a593Smuzhiyun 	struct system_heap_buffer *buffer = dmabuf->priv;
275*4882a593Smuzhiyun 	struct dma_heap *heap = buffer->heap;
276*4882a593Smuzhiyun 	struct sg_table *table = &buffer->sg_table;
277*4882a593Smuzhiyun 	int ret;
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun 	if (direction == DMA_TO_DEVICE)
280*4882a593Smuzhiyun 		return 0;
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun 	mutex_lock(&buffer->lock);
283*4882a593Smuzhiyun 	if (buffer->vmap_cnt)
284*4882a593Smuzhiyun 		invalidate_kernel_vmap_range(buffer->vaddr, buffer->len);
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	if (buffer->uncached) {
287*4882a593Smuzhiyun 		mutex_unlock(&buffer->lock);
288*4882a593Smuzhiyun 		return 0;
289*4882a593Smuzhiyun 	}
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	ret = system_heap_sgl_sync_range(dma_heap_get_dev(heap), table,
292*4882a593Smuzhiyun 					 offset, len, direction, true);
293*4882a593Smuzhiyun 	mutex_unlock(&buffer->lock);
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 	return ret;
296*4882a593Smuzhiyun }
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun static int __maybe_unused
system_heap_dma_buf_end_cpu_access_partial(struct dma_buf * dmabuf,enum dma_data_direction direction,unsigned int offset,unsigned int len)299*4882a593Smuzhiyun system_heap_dma_buf_end_cpu_access_partial(struct dma_buf *dmabuf,
300*4882a593Smuzhiyun 					   enum dma_data_direction direction,
301*4882a593Smuzhiyun 					   unsigned int offset,
302*4882a593Smuzhiyun 					   unsigned int len)
303*4882a593Smuzhiyun {
304*4882a593Smuzhiyun 	struct system_heap_buffer *buffer = dmabuf->priv;
305*4882a593Smuzhiyun 	struct dma_heap *heap = buffer->heap;
306*4882a593Smuzhiyun 	struct sg_table *table = &buffer->sg_table;
307*4882a593Smuzhiyun 	int ret;
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 	mutex_lock(&buffer->lock);
310*4882a593Smuzhiyun 	if (buffer->vmap_cnt)
311*4882a593Smuzhiyun 		flush_kernel_vmap_range(buffer->vaddr, buffer->len);
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun 	if (buffer->uncached) {
314*4882a593Smuzhiyun 		mutex_unlock(&buffer->lock);
315*4882a593Smuzhiyun 		return 0;
316*4882a593Smuzhiyun 	}
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun 	ret = system_heap_sgl_sync_range(dma_heap_get_dev(heap), table,
319*4882a593Smuzhiyun 					 offset, len, direction, false);
320*4882a593Smuzhiyun 	mutex_unlock(&buffer->lock);
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun 	return ret;
323*4882a593Smuzhiyun }
324*4882a593Smuzhiyun 
system_heap_mmap(struct dma_buf * dmabuf,struct vm_area_struct * vma)325*4882a593Smuzhiyun static int system_heap_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
326*4882a593Smuzhiyun {
327*4882a593Smuzhiyun 	struct system_heap_buffer *buffer = dmabuf->priv;
328*4882a593Smuzhiyun 	struct sg_table *table = &buffer->sg_table;
329*4882a593Smuzhiyun 	unsigned long addr = vma->vm_start;
330*4882a593Smuzhiyun 	struct sg_page_iter piter;
331*4882a593Smuzhiyun 	int ret;
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun 	if (buffer->uncached)
334*4882a593Smuzhiyun 		vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 	for_each_sgtable_page(table, &piter, vma->vm_pgoff) {
337*4882a593Smuzhiyun 		struct page *page = sg_page_iter_page(&piter);
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 		ret = remap_pfn_range(vma, addr, page_to_pfn(page), PAGE_SIZE,
340*4882a593Smuzhiyun 				      vma->vm_page_prot);
341*4882a593Smuzhiyun 		if (ret)
342*4882a593Smuzhiyun 			return ret;
343*4882a593Smuzhiyun 		addr += PAGE_SIZE;
344*4882a593Smuzhiyun 		if (addr >= vma->vm_end)
345*4882a593Smuzhiyun 			return 0;
346*4882a593Smuzhiyun 	}
347*4882a593Smuzhiyun 	return 0;
348*4882a593Smuzhiyun }
349*4882a593Smuzhiyun 
system_heap_do_vmap(struct system_heap_buffer * buffer)350*4882a593Smuzhiyun static void *system_heap_do_vmap(struct system_heap_buffer *buffer)
351*4882a593Smuzhiyun {
352*4882a593Smuzhiyun 	struct sg_table *table = &buffer->sg_table;
353*4882a593Smuzhiyun 	int npages = PAGE_ALIGN(buffer->len) / PAGE_SIZE;
354*4882a593Smuzhiyun 	struct page **pages = vmalloc(sizeof(struct page *) * npages);
355*4882a593Smuzhiyun 	struct page **tmp = pages;
356*4882a593Smuzhiyun 	struct sg_page_iter piter;
357*4882a593Smuzhiyun 	pgprot_t pgprot = PAGE_KERNEL;
358*4882a593Smuzhiyun 	void *vaddr;
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun 	if (!pages)
361*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun 	if (buffer->uncached)
364*4882a593Smuzhiyun 		pgprot = pgprot_writecombine(PAGE_KERNEL);
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 	for_each_sgtable_page(table, &piter, 0) {
367*4882a593Smuzhiyun 		WARN_ON(tmp - pages >= npages);
368*4882a593Smuzhiyun 		*tmp++ = sg_page_iter_page(&piter);
369*4882a593Smuzhiyun 	}
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun 	vaddr = vmap(pages, npages, VM_MAP, pgprot);
372*4882a593Smuzhiyun 	vfree(pages);
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 	if (!vaddr)
375*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun 	return vaddr;
378*4882a593Smuzhiyun }
379*4882a593Smuzhiyun 
system_heap_vmap(struct dma_buf * dmabuf)380*4882a593Smuzhiyun static void *system_heap_vmap(struct dma_buf *dmabuf)
381*4882a593Smuzhiyun {
382*4882a593Smuzhiyun 	struct system_heap_buffer *buffer = dmabuf->priv;
383*4882a593Smuzhiyun 	void *vaddr;
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 	mutex_lock(&buffer->lock);
386*4882a593Smuzhiyun 	if (buffer->vmap_cnt) {
387*4882a593Smuzhiyun 		buffer->vmap_cnt++;
388*4882a593Smuzhiyun 		vaddr = buffer->vaddr;
389*4882a593Smuzhiyun 		goto out;
390*4882a593Smuzhiyun 	}
391*4882a593Smuzhiyun 
392*4882a593Smuzhiyun 	vaddr = system_heap_do_vmap(buffer);
393*4882a593Smuzhiyun 	if (IS_ERR(vaddr))
394*4882a593Smuzhiyun 		goto out;
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun 	buffer->vaddr = vaddr;
397*4882a593Smuzhiyun 	buffer->vmap_cnt++;
398*4882a593Smuzhiyun out:
399*4882a593Smuzhiyun 	mutex_unlock(&buffer->lock);
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	return vaddr;
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun 
system_heap_vunmap(struct dma_buf * dmabuf,void * vaddr)404*4882a593Smuzhiyun static void system_heap_vunmap(struct dma_buf *dmabuf, void *vaddr)
405*4882a593Smuzhiyun {
406*4882a593Smuzhiyun 	struct system_heap_buffer *buffer = dmabuf->priv;
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun 	mutex_lock(&buffer->lock);
409*4882a593Smuzhiyun 	if (!--buffer->vmap_cnt) {
410*4882a593Smuzhiyun 		vunmap(buffer->vaddr);
411*4882a593Smuzhiyun 		buffer->vaddr = NULL;
412*4882a593Smuzhiyun 	}
413*4882a593Smuzhiyun 	mutex_unlock(&buffer->lock);
414*4882a593Smuzhiyun }
415*4882a593Smuzhiyun 
system_heap_zero_buffer(struct system_heap_buffer * buffer)416*4882a593Smuzhiyun static int system_heap_zero_buffer(struct system_heap_buffer *buffer)
417*4882a593Smuzhiyun {
418*4882a593Smuzhiyun 	struct sg_table *sgt = &buffer->sg_table;
419*4882a593Smuzhiyun 	struct sg_page_iter piter;
420*4882a593Smuzhiyun 	struct page *p;
421*4882a593Smuzhiyun 	void *vaddr;
422*4882a593Smuzhiyun 	int ret = 0;
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 	for_each_sgtable_page(sgt, &piter, 0) {
425*4882a593Smuzhiyun 		p = sg_page_iter_page(&piter);
426*4882a593Smuzhiyun 		vaddr = kmap_atomic(p);
427*4882a593Smuzhiyun 		memset(vaddr, 0, PAGE_SIZE);
428*4882a593Smuzhiyun 		kunmap_atomic(vaddr);
429*4882a593Smuzhiyun 	}
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun 	return ret;
432*4882a593Smuzhiyun }
433*4882a593Smuzhiyun 
system_heap_buf_free(struct deferred_freelist_item * item,enum df_reason reason)434*4882a593Smuzhiyun static void system_heap_buf_free(struct deferred_freelist_item *item,
435*4882a593Smuzhiyun 				 enum df_reason reason)
436*4882a593Smuzhiyun {
437*4882a593Smuzhiyun 	struct system_heap_buffer *buffer;
438*4882a593Smuzhiyun 	struct sg_table *table;
439*4882a593Smuzhiyun 	struct scatterlist *sg;
440*4882a593Smuzhiyun 	int i, j;
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun 	buffer = container_of(item, struct system_heap_buffer, deferred_free);
443*4882a593Smuzhiyun 	/* Zero the buffer pages before adding back to the pool */
444*4882a593Smuzhiyun 	if (reason == DF_NORMAL)
445*4882a593Smuzhiyun 		if (system_heap_zero_buffer(buffer))
446*4882a593Smuzhiyun 			reason = DF_UNDER_PRESSURE; // On failure, just free
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun 	table = &buffer->sg_table;
449*4882a593Smuzhiyun 	for_each_sgtable_sg(table, sg, i) {
450*4882a593Smuzhiyun 		struct page *page = sg_page(sg);
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun 		if (reason == DF_UNDER_PRESSURE) {
453*4882a593Smuzhiyun 			__free_pages(page, compound_order(page));
454*4882a593Smuzhiyun 		} else {
455*4882a593Smuzhiyun 			for (j = 0; j < NUM_ORDERS; j++) {
456*4882a593Smuzhiyun 				if (compound_order(page) == orders[j])
457*4882a593Smuzhiyun 					break;
458*4882a593Smuzhiyun 			}
459*4882a593Smuzhiyun 			dmabuf_page_pool_free(buffer->pools[j], page);
460*4882a593Smuzhiyun 		}
461*4882a593Smuzhiyun 	}
462*4882a593Smuzhiyun 	sg_free_table(table);
463*4882a593Smuzhiyun 	kfree(buffer);
464*4882a593Smuzhiyun }
465*4882a593Smuzhiyun 
system_heap_dma_buf_release(struct dma_buf * dmabuf)466*4882a593Smuzhiyun static void system_heap_dma_buf_release(struct dma_buf *dmabuf)
467*4882a593Smuzhiyun {
468*4882a593Smuzhiyun 	struct system_heap_buffer *buffer = dmabuf->priv;
469*4882a593Smuzhiyun 	int npages = PAGE_ALIGN(buffer->len) / PAGE_SIZE;
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun 	deferred_free(&buffer->deferred_free, system_heap_buf_free, npages);
472*4882a593Smuzhiyun }
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun static const struct dma_buf_ops system_heap_buf_ops = {
475*4882a593Smuzhiyun 	.attach = system_heap_attach,
476*4882a593Smuzhiyun 	.detach = system_heap_detach,
477*4882a593Smuzhiyun 	.map_dma_buf = system_heap_map_dma_buf,
478*4882a593Smuzhiyun 	.unmap_dma_buf = system_heap_unmap_dma_buf,
479*4882a593Smuzhiyun 	.begin_cpu_access = system_heap_dma_buf_begin_cpu_access,
480*4882a593Smuzhiyun 	.end_cpu_access = system_heap_dma_buf_end_cpu_access,
481*4882a593Smuzhiyun #ifdef CONFIG_DMABUF_PARTIAL
482*4882a593Smuzhiyun 	.begin_cpu_access_partial = system_heap_dma_buf_begin_cpu_access_partial,
483*4882a593Smuzhiyun 	.end_cpu_access_partial = system_heap_dma_buf_end_cpu_access_partial,
484*4882a593Smuzhiyun #endif
485*4882a593Smuzhiyun 	.mmap = system_heap_mmap,
486*4882a593Smuzhiyun 	.vmap = system_heap_vmap,
487*4882a593Smuzhiyun 	.vunmap = system_heap_vunmap,
488*4882a593Smuzhiyun 	.release = system_heap_dma_buf_release,
489*4882a593Smuzhiyun };
490*4882a593Smuzhiyun 
system_heap_alloc_largest_available(struct dma_heap * heap,struct dmabuf_page_pool ** pool,unsigned long size,unsigned int max_order)491*4882a593Smuzhiyun static struct page *system_heap_alloc_largest_available(struct dma_heap *heap,
492*4882a593Smuzhiyun 							struct dmabuf_page_pool **pool,
493*4882a593Smuzhiyun 							unsigned long size,
494*4882a593Smuzhiyun 							unsigned int max_order)
495*4882a593Smuzhiyun {
496*4882a593Smuzhiyun 	struct page *page;
497*4882a593Smuzhiyun 	int i;
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun 	for (i = 0; i < NUM_ORDERS; i++) {
500*4882a593Smuzhiyun 		if (size <  (PAGE_SIZE << orders[i]))
501*4882a593Smuzhiyun 			continue;
502*4882a593Smuzhiyun 		if (max_order < orders[i])
503*4882a593Smuzhiyun 			continue;
504*4882a593Smuzhiyun 		page = dmabuf_page_pool_alloc(pool[i]);
505*4882a593Smuzhiyun 		if (!page)
506*4882a593Smuzhiyun 			continue;
507*4882a593Smuzhiyun 		return page;
508*4882a593Smuzhiyun 	}
509*4882a593Smuzhiyun 	return NULL;
510*4882a593Smuzhiyun }
511*4882a593Smuzhiyun 
system_heap_do_allocate(struct dma_heap * heap,unsigned long len,unsigned long fd_flags,unsigned long heap_flags,bool uncached)512*4882a593Smuzhiyun static struct dma_buf *system_heap_do_allocate(struct dma_heap *heap,
513*4882a593Smuzhiyun 					       unsigned long len,
514*4882a593Smuzhiyun 					       unsigned long fd_flags,
515*4882a593Smuzhiyun 					       unsigned long heap_flags,
516*4882a593Smuzhiyun 					       bool uncached)
517*4882a593Smuzhiyun {
518*4882a593Smuzhiyun 	struct system_heap_buffer *buffer;
519*4882a593Smuzhiyun 	DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
520*4882a593Smuzhiyun 	unsigned long size_remaining = len;
521*4882a593Smuzhiyun 	unsigned int max_order = orders[0];
522*4882a593Smuzhiyun 	struct dma_buf *dmabuf;
523*4882a593Smuzhiyun 	struct sg_table *table;
524*4882a593Smuzhiyun 	struct scatterlist *sg;
525*4882a593Smuzhiyun 	struct list_head pages;
526*4882a593Smuzhiyun 	struct page *page, *tmp_page;
527*4882a593Smuzhiyun 	int i, ret = -ENOMEM;
528*4882a593Smuzhiyun 	struct list_head lists[8];
529*4882a593Smuzhiyun 	unsigned int block_index[8] = {0};
530*4882a593Smuzhiyun 	unsigned int block_1M = 0;
531*4882a593Smuzhiyun 	unsigned int block_64K = 0;
532*4882a593Smuzhiyun 	unsigned int maximum;
533*4882a593Smuzhiyun 	int j;
534*4882a593Smuzhiyun 
535*4882a593Smuzhiyun 	buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
536*4882a593Smuzhiyun 	if (!buffer)
537*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun 	INIT_LIST_HEAD(&buffer->attachments);
540*4882a593Smuzhiyun 	mutex_init(&buffer->lock);
541*4882a593Smuzhiyun 	buffer->heap = heap;
542*4882a593Smuzhiyun 	buffer->len = len;
543*4882a593Smuzhiyun 	buffer->uncached = uncached;
544*4882a593Smuzhiyun 	buffer->pools = strstr(dma_heap_get_name(heap), "dma32") ? dma32_pools : pools;
545*4882a593Smuzhiyun 
546*4882a593Smuzhiyun 	INIT_LIST_HEAD(&pages);
547*4882a593Smuzhiyun 	for (i = 0; i < 8; i++)
548*4882a593Smuzhiyun 		INIT_LIST_HEAD(&lists[i]);
549*4882a593Smuzhiyun 	i = 0;
550*4882a593Smuzhiyun 	while (size_remaining > 0) {
551*4882a593Smuzhiyun 		/*
552*4882a593Smuzhiyun 		 * Avoid trying to allocate memory if the process
553*4882a593Smuzhiyun 		 * has been killed by SIGKILL
554*4882a593Smuzhiyun 		 */
555*4882a593Smuzhiyun 		if (fatal_signal_pending(current))
556*4882a593Smuzhiyun 			goto free_buffer;
557*4882a593Smuzhiyun 
558*4882a593Smuzhiyun 		page = system_heap_alloc_largest_available(heap, buffer->pools,
559*4882a593Smuzhiyun 							   size_remaining,
560*4882a593Smuzhiyun 							   max_order);
561*4882a593Smuzhiyun 		if (!page)
562*4882a593Smuzhiyun 			goto free_buffer;
563*4882a593Smuzhiyun 
564*4882a593Smuzhiyun 		size_remaining -= page_size(page);
565*4882a593Smuzhiyun 		max_order = compound_order(page);
566*4882a593Smuzhiyun 		if (max_order) {
567*4882a593Smuzhiyun 			if (max_order == 8)
568*4882a593Smuzhiyun 				block_1M++;
569*4882a593Smuzhiyun 			if (max_order == 4)
570*4882a593Smuzhiyun 				block_64K++;
571*4882a593Smuzhiyun 			list_add_tail(&page->lru, &pages);
572*4882a593Smuzhiyun 		} else {
573*4882a593Smuzhiyun 			dma_addr_t phys = page_to_phys(page);
574*4882a593Smuzhiyun 			unsigned int bit_index = ((phys >> bank_bit_first) & bank_bit_mask) & 0x7;
575*4882a593Smuzhiyun 
576*4882a593Smuzhiyun 			list_add_tail(&page->lru, &lists[bit_index]);
577*4882a593Smuzhiyun 			block_index[bit_index]++;
578*4882a593Smuzhiyun 		}
579*4882a593Smuzhiyun 		i++;
580*4882a593Smuzhiyun 	}
581*4882a593Smuzhiyun 
582*4882a593Smuzhiyun 	table = &buffer->sg_table;
583*4882a593Smuzhiyun 	if (sg_alloc_table(table, i, GFP_KERNEL))
584*4882a593Smuzhiyun 		goto free_buffer;
585*4882a593Smuzhiyun 
586*4882a593Smuzhiyun 	maximum = block_index[0];
587*4882a593Smuzhiyun 	for (i = 1; i < 8; i++)
588*4882a593Smuzhiyun 		maximum = max(maximum, block_index[i]);
589*4882a593Smuzhiyun 	sg = table->sgl;
590*4882a593Smuzhiyun 	list_for_each_entry_safe(page, tmp_page, &pages, lru) {
591*4882a593Smuzhiyun 		sg_set_page(sg, page, page_size(page), 0);
592*4882a593Smuzhiyun 		sg = sg_next(sg);
593*4882a593Smuzhiyun 		list_del(&page->lru);
594*4882a593Smuzhiyun 	}
595*4882a593Smuzhiyun 	for (i = 0; i < maximum; i++) {
596*4882a593Smuzhiyun 		for (j = 0; j < 8; j++) {
597*4882a593Smuzhiyun 			if (!list_empty(&lists[j])) {
598*4882a593Smuzhiyun 				page = list_first_entry(&lists[j], struct page, lru);
599*4882a593Smuzhiyun 				sg_set_page(sg, page, PAGE_SIZE, 0);
600*4882a593Smuzhiyun 				sg = sg_next(sg);
601*4882a593Smuzhiyun 				list_del(&page->lru);
602*4882a593Smuzhiyun 			}
603*4882a593Smuzhiyun 		}
604*4882a593Smuzhiyun 	}
605*4882a593Smuzhiyun 
606*4882a593Smuzhiyun 	/* create the dmabuf */
607*4882a593Smuzhiyun 	exp_info.exp_name = dma_heap_get_name(heap);
608*4882a593Smuzhiyun 	exp_info.ops = &system_heap_buf_ops;
609*4882a593Smuzhiyun 	exp_info.size = buffer->len;
610*4882a593Smuzhiyun 	exp_info.flags = fd_flags;
611*4882a593Smuzhiyun 	exp_info.priv = buffer;
612*4882a593Smuzhiyun 	dmabuf = dma_buf_export(&exp_info);
613*4882a593Smuzhiyun 	if (IS_ERR(dmabuf)) {
614*4882a593Smuzhiyun 		ret = PTR_ERR(dmabuf);
615*4882a593Smuzhiyun 		goto free_pages;
616*4882a593Smuzhiyun 	}
617*4882a593Smuzhiyun 
618*4882a593Smuzhiyun 	/*
619*4882a593Smuzhiyun 	 * For uncached buffers, we need to initially flush cpu cache, since
620*4882a593Smuzhiyun 	 * the __GFP_ZERO on the allocation means the zeroing was done by the
621*4882a593Smuzhiyun 	 * cpu and thus it is likely cached. Map (and implicitly flush) and
622*4882a593Smuzhiyun 	 * unmap it now so we don't get corruption later on.
623*4882a593Smuzhiyun 	 */
624*4882a593Smuzhiyun 	if (buffer->uncached) {
625*4882a593Smuzhiyun 		dma_map_sgtable(dma_heap_get_dev(heap), table, DMA_BIDIRECTIONAL, 0);
626*4882a593Smuzhiyun 		dma_unmap_sgtable(dma_heap_get_dev(heap), table, DMA_BIDIRECTIONAL, 0);
627*4882a593Smuzhiyun 	}
628*4882a593Smuzhiyun 
629*4882a593Smuzhiyun 	return dmabuf;
630*4882a593Smuzhiyun 
631*4882a593Smuzhiyun free_pages:
632*4882a593Smuzhiyun 	for_each_sgtable_sg(table, sg, i) {
633*4882a593Smuzhiyun 		struct page *p = sg_page(sg);
634*4882a593Smuzhiyun 
635*4882a593Smuzhiyun 		__free_pages(p, compound_order(p));
636*4882a593Smuzhiyun 	}
637*4882a593Smuzhiyun 	sg_free_table(table);
638*4882a593Smuzhiyun free_buffer:
639*4882a593Smuzhiyun 	list_for_each_entry_safe(page, tmp_page, &pages, lru)
640*4882a593Smuzhiyun 		__free_pages(page, compound_order(page));
641*4882a593Smuzhiyun 	for (i = 0; i < 8; i++) {
642*4882a593Smuzhiyun 		list_for_each_entry_safe(page, tmp_page, &lists[i], lru)
643*4882a593Smuzhiyun 			__free_pages(page, compound_order(page));
644*4882a593Smuzhiyun 	}
645*4882a593Smuzhiyun 	kfree(buffer);
646*4882a593Smuzhiyun 
647*4882a593Smuzhiyun 	return ERR_PTR(ret);
648*4882a593Smuzhiyun }
649*4882a593Smuzhiyun 
system_heap_allocate(struct dma_heap * heap,unsigned long len,unsigned long fd_flags,unsigned long heap_flags)650*4882a593Smuzhiyun static struct dma_buf *system_heap_allocate(struct dma_heap *heap,
651*4882a593Smuzhiyun 					    unsigned long len,
652*4882a593Smuzhiyun 					    unsigned long fd_flags,
653*4882a593Smuzhiyun 					    unsigned long heap_flags)
654*4882a593Smuzhiyun {
655*4882a593Smuzhiyun 	return system_heap_do_allocate(heap, len, fd_flags, heap_flags, false);
656*4882a593Smuzhiyun }
657*4882a593Smuzhiyun 
system_get_pool_size(struct dma_heap * heap)658*4882a593Smuzhiyun static long system_get_pool_size(struct dma_heap *heap)
659*4882a593Smuzhiyun {
660*4882a593Smuzhiyun 	int i;
661*4882a593Smuzhiyun 	long num_pages = 0;
662*4882a593Smuzhiyun 	struct dmabuf_page_pool **pool;
663*4882a593Smuzhiyun 
664*4882a593Smuzhiyun 	pool = strstr(dma_heap_get_name(heap), "dma32") ? dma32_pools : pools;
665*4882a593Smuzhiyun 	for (i = 0; i < NUM_ORDERS; i++, pool++) {
666*4882a593Smuzhiyun 		num_pages += ((*pool)->count[POOL_LOWPAGE] +
667*4882a593Smuzhiyun 			      (*pool)->count[POOL_HIGHPAGE]) << (*pool)->order;
668*4882a593Smuzhiyun 	}
669*4882a593Smuzhiyun 
670*4882a593Smuzhiyun 	return num_pages << PAGE_SHIFT;
671*4882a593Smuzhiyun }
672*4882a593Smuzhiyun 
673*4882a593Smuzhiyun static const struct dma_heap_ops system_heap_ops = {
674*4882a593Smuzhiyun 	.allocate = system_heap_allocate,
675*4882a593Smuzhiyun 	.get_pool_size = system_get_pool_size,
676*4882a593Smuzhiyun };
677*4882a593Smuzhiyun 
system_uncached_heap_allocate(struct dma_heap * heap,unsigned long len,unsigned long fd_flags,unsigned long heap_flags)678*4882a593Smuzhiyun static struct dma_buf *system_uncached_heap_allocate(struct dma_heap *heap,
679*4882a593Smuzhiyun 						     unsigned long len,
680*4882a593Smuzhiyun 						     unsigned long fd_flags,
681*4882a593Smuzhiyun 						     unsigned long heap_flags)
682*4882a593Smuzhiyun {
683*4882a593Smuzhiyun 	return system_heap_do_allocate(heap, len, fd_flags, heap_flags, true);
684*4882a593Smuzhiyun }
685*4882a593Smuzhiyun 
686*4882a593Smuzhiyun /* Dummy function to be used until we can call coerce_mask_and_coherent */
system_uncached_heap_not_initialized(struct dma_heap * heap,unsigned long len,unsigned long fd_flags,unsigned long heap_flags)687*4882a593Smuzhiyun static struct dma_buf *system_uncached_heap_not_initialized(struct dma_heap *heap,
688*4882a593Smuzhiyun 							    unsigned long len,
689*4882a593Smuzhiyun 							    unsigned long fd_flags,
690*4882a593Smuzhiyun 							    unsigned long heap_flags)
691*4882a593Smuzhiyun {
692*4882a593Smuzhiyun 	return ERR_PTR(-EBUSY);
693*4882a593Smuzhiyun }
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun static struct dma_heap_ops system_uncached_heap_ops = {
696*4882a593Smuzhiyun 	/* After system_heap_create is complete, we will swap this */
697*4882a593Smuzhiyun 	.allocate = system_uncached_heap_not_initialized,
698*4882a593Smuzhiyun };
699*4882a593Smuzhiyun 
set_heap_dev_dma(struct device * heap_dev)700*4882a593Smuzhiyun static int set_heap_dev_dma(struct device *heap_dev)
701*4882a593Smuzhiyun {
702*4882a593Smuzhiyun 	int err = 0;
703*4882a593Smuzhiyun 
704*4882a593Smuzhiyun 	if (!heap_dev)
705*4882a593Smuzhiyun 		return -EINVAL;
706*4882a593Smuzhiyun 
707*4882a593Smuzhiyun 	dma_coerce_mask_and_coherent(heap_dev, DMA_BIT_MASK(64));
708*4882a593Smuzhiyun 
709*4882a593Smuzhiyun 	if (!heap_dev->dma_parms) {
710*4882a593Smuzhiyun 		heap_dev->dma_parms = devm_kzalloc(heap_dev,
711*4882a593Smuzhiyun 						   sizeof(*heap_dev->dma_parms),
712*4882a593Smuzhiyun 						   GFP_KERNEL);
713*4882a593Smuzhiyun 		if (!heap_dev->dma_parms)
714*4882a593Smuzhiyun 			return -ENOMEM;
715*4882a593Smuzhiyun 
716*4882a593Smuzhiyun 		err = dma_set_max_seg_size(heap_dev, (unsigned int)DMA_BIT_MASK(64));
717*4882a593Smuzhiyun 		if (err) {
718*4882a593Smuzhiyun 			devm_kfree(heap_dev, heap_dev->dma_parms);
719*4882a593Smuzhiyun 			dev_err(heap_dev, "Failed to set DMA segment size, err:%d\n", err);
720*4882a593Smuzhiyun 			return err;
721*4882a593Smuzhiyun 		}
722*4882a593Smuzhiyun 	}
723*4882a593Smuzhiyun 
724*4882a593Smuzhiyun 	return 0;
725*4882a593Smuzhiyun }
726*4882a593Smuzhiyun 
system_heap_create(void)727*4882a593Smuzhiyun static int system_heap_create(void)
728*4882a593Smuzhiyun {
729*4882a593Smuzhiyun 	struct dma_heap_export_info exp_info;
730*4882a593Smuzhiyun 	int i, err = 0;
731*4882a593Smuzhiyun 	struct dram_addrmap_info *ddr_map_info;
732*4882a593Smuzhiyun 
733*4882a593Smuzhiyun 	/*
734*4882a593Smuzhiyun 	 * Since swiotlb has memory size limitation, this will calculate
735*4882a593Smuzhiyun 	 * the maximum size locally.
736*4882a593Smuzhiyun 	 *
737*4882a593Smuzhiyun 	 * Once swiotlb_max_segment() return not '0', means that the totalram size
738*4882a593Smuzhiyun 	 * is larger than 4GiB and swiotlb is not force mode, in this case, system
739*4882a593Smuzhiyun 	 * heap should limit largest allocation.
740*4882a593Smuzhiyun 	 *
741*4882a593Smuzhiyun 	 * FIX: fix the orders[] as a workaround.
742*4882a593Smuzhiyun 	 */
743*4882a593Smuzhiyun 	if (swiotlb_max_segment()) {
744*4882a593Smuzhiyun 		unsigned int max_size = (1 << IO_TLB_SHIFT) * IO_TLB_SEGSIZE;
745*4882a593Smuzhiyun 		int max_order = MAX_ORDER;
746*4882a593Smuzhiyun 		int i;
747*4882a593Smuzhiyun 
748*4882a593Smuzhiyun 		max_size = max_t(unsigned int, max_size, PAGE_SIZE) >> PAGE_SHIFT;
749*4882a593Smuzhiyun 		max_order = min(max_order, ilog2(max_size));
750*4882a593Smuzhiyun 		for (i = 0; i < NUM_ORDERS; i++) {
751*4882a593Smuzhiyun 			if (max_order < orders[i])
752*4882a593Smuzhiyun 				orders[i] = max_order;
753*4882a593Smuzhiyun 			pr_info("system_heap: orders[%d] = %u\n", i, orders[i]);
754*4882a593Smuzhiyun 		}
755*4882a593Smuzhiyun 	}
756*4882a593Smuzhiyun 
757*4882a593Smuzhiyun 	for (i = 0; i < NUM_ORDERS; i++) {
758*4882a593Smuzhiyun 		pools[i] = dmabuf_page_pool_create(order_flags[i], orders[i]);
759*4882a593Smuzhiyun 
760*4882a593Smuzhiyun 		if (!pools[i]) {
761*4882a593Smuzhiyun 			int j;
762*4882a593Smuzhiyun 
763*4882a593Smuzhiyun 			pr_err("%s: page pool creation failed!\n", __func__);
764*4882a593Smuzhiyun 			for (j = 0; j < i; j++)
765*4882a593Smuzhiyun 				dmabuf_page_pool_destroy(pools[j]);
766*4882a593Smuzhiyun 			return -ENOMEM;
767*4882a593Smuzhiyun 		}
768*4882a593Smuzhiyun 	}
769*4882a593Smuzhiyun 
770*4882a593Smuzhiyun 	for (i = 0; i < NUM_ORDERS; i++) {
771*4882a593Smuzhiyun 		dma32_pools[i] = dmabuf_page_pool_create(order_flags[i] | GFP_DMA32, orders[i]);
772*4882a593Smuzhiyun 
773*4882a593Smuzhiyun 		if (!dma32_pools[i]) {
774*4882a593Smuzhiyun 			int j;
775*4882a593Smuzhiyun 
776*4882a593Smuzhiyun 			pr_err("%s: page dma32 pool creation failed!\n", __func__);
777*4882a593Smuzhiyun 			for (j = 0; j < i; j++)
778*4882a593Smuzhiyun 				dmabuf_page_pool_destroy(dma32_pools[j]);
779*4882a593Smuzhiyun 			goto err_dma32_pool;
780*4882a593Smuzhiyun 		}
781*4882a593Smuzhiyun 	}
782*4882a593Smuzhiyun 
783*4882a593Smuzhiyun 	exp_info.name = "system";
784*4882a593Smuzhiyun 	exp_info.ops = &system_heap_ops;
785*4882a593Smuzhiyun 	exp_info.priv = NULL;
786*4882a593Smuzhiyun 
787*4882a593Smuzhiyun 	sys_heap = dma_heap_add(&exp_info);
788*4882a593Smuzhiyun 	if (IS_ERR(sys_heap))
789*4882a593Smuzhiyun 		return PTR_ERR(sys_heap);
790*4882a593Smuzhiyun 
791*4882a593Smuzhiyun 	exp_info.name = "system-dma32";
792*4882a593Smuzhiyun 	exp_info.ops = &system_heap_ops;
793*4882a593Smuzhiyun 	exp_info.priv = NULL;
794*4882a593Smuzhiyun 
795*4882a593Smuzhiyun 	sys_dma32_heap = dma_heap_add(&exp_info);
796*4882a593Smuzhiyun 	if (IS_ERR(sys_dma32_heap))
797*4882a593Smuzhiyun 		return PTR_ERR(sys_dma32_heap);
798*4882a593Smuzhiyun 
799*4882a593Smuzhiyun 	exp_info.name = "system-uncached";
800*4882a593Smuzhiyun 	exp_info.ops = &system_uncached_heap_ops;
801*4882a593Smuzhiyun 	exp_info.priv = NULL;
802*4882a593Smuzhiyun 
803*4882a593Smuzhiyun 	sys_uncached_heap = dma_heap_add(&exp_info);
804*4882a593Smuzhiyun 	if (IS_ERR(sys_uncached_heap))
805*4882a593Smuzhiyun 		return PTR_ERR(sys_uncached_heap);
806*4882a593Smuzhiyun 
807*4882a593Smuzhiyun 	err = set_heap_dev_dma(dma_heap_get_dev(sys_uncached_heap));
808*4882a593Smuzhiyun 	if (err)
809*4882a593Smuzhiyun 		return err;
810*4882a593Smuzhiyun 
811*4882a593Smuzhiyun 	exp_info.name = "system-uncached-dma32";
812*4882a593Smuzhiyun 	exp_info.ops = &system_uncached_heap_ops;
813*4882a593Smuzhiyun 	exp_info.priv = NULL;
814*4882a593Smuzhiyun 
815*4882a593Smuzhiyun 	sys_uncached_dma32_heap = dma_heap_add(&exp_info);
816*4882a593Smuzhiyun 	if (IS_ERR(sys_uncached_dma32_heap))
817*4882a593Smuzhiyun 		return PTR_ERR(sys_uncached_dma32_heap);
818*4882a593Smuzhiyun 
819*4882a593Smuzhiyun 	err = set_heap_dev_dma(dma_heap_get_dev(sys_uncached_dma32_heap));
820*4882a593Smuzhiyun 	if (err)
821*4882a593Smuzhiyun 		return err;
822*4882a593Smuzhiyun 	dma_coerce_mask_and_coherent(dma_heap_get_dev(sys_uncached_dma32_heap), DMA_BIT_MASK(32));
823*4882a593Smuzhiyun 
824*4882a593Smuzhiyun 	mb(); /* make sure we only set allocate after dma_mask is set */
825*4882a593Smuzhiyun 	system_uncached_heap_ops.allocate = system_uncached_heap_allocate;
826*4882a593Smuzhiyun 
827*4882a593Smuzhiyun 	ddr_map_info = sip_smc_get_dram_map();
828*4882a593Smuzhiyun 	if (ddr_map_info) {
829*4882a593Smuzhiyun 		bank_bit_first = ddr_map_info->bank_bit_first;
830*4882a593Smuzhiyun 		bank_bit_mask = ddr_map_info->bank_bit_mask;
831*4882a593Smuzhiyun 	}
832*4882a593Smuzhiyun 
833*4882a593Smuzhiyun 	return 0;
834*4882a593Smuzhiyun err_dma32_pool:
835*4882a593Smuzhiyun 	for (i = 0; i < NUM_ORDERS; i++)
836*4882a593Smuzhiyun 		dmabuf_page_pool_destroy(pools[i]);
837*4882a593Smuzhiyun 
838*4882a593Smuzhiyun 	return -ENOMEM;
839*4882a593Smuzhiyun }
840*4882a593Smuzhiyun module_init(system_heap_create);
841*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
842