1 // SPDX-License-Identifier: GPL-2.0
3 * PCI Endpoint *Controller* Address Space Management
5 * Copyright (C) 2017 Texas Instruments
6 * Author: Kishon Vijay Abraham I <kishon@ti.com>
10 #include <linux/module.h>
11 #include <linux/slab.h>
13 #include <linux/pci-epc.h>
16 * pci_epc_mem_get_order() - determine the allocation order of a memory size
17 * @mem: address space of the endpoint controller
18 * @size: the size for which to get the order
20 * Reimplement get_order() for mem->page_size since the generic get_order
21 * always gets order with a constant PAGE_SIZE.
23 static int pci_epc_mem_get_order(struct pci_epc_mem
*mem
, size_t size
)
26 unsigned int page_shift
= ilog2(mem
->window
.page_size
);
30 #if BITS_PER_LONG == 32
39 * pci_epc_multi_mem_init() - initialize the pci_epc_mem structure
40 * @epc: the EPC device that invoked pci_epc_mem_init
41 * @windows: pointer to windows supported by the device
42 * @num_windows: number of windows device supports
44 * Invoke to initialize the pci_epc_mem structure used by the
45 * endpoint functions to allocate mapped PCI address.
47 int pci_epc_multi_mem_init(struct pci_epc
*epc
,
48 struct pci_epc_mem_window
*windows
,
49 unsigned int num_windows
)
51 struct pci_epc_mem
*mem
= NULL
;
52 unsigned long *bitmap
= NULL
;
53 unsigned int page_shift
;
62 if (!windows
|| !num_windows
)
65 epc
->windows
= kcalloc(num_windows
, sizeof(*epc
->windows
), GFP_KERNEL
);
69 for (i
= 0; i
< num_windows
; i
++) {
70 page_size
= windows
[i
].page_size
;
71 if (page_size
< PAGE_SIZE
)
72 page_size
= PAGE_SIZE
;
73 page_shift
= ilog2(page_size
);
74 pages
= windows
[i
].size
>> page_shift
;
75 bitmap_size
= BITS_TO_LONGS(pages
) * sizeof(long);
77 mem
= kzalloc(sizeof(*mem
), GFP_KERNEL
);
84 bitmap
= kzalloc(bitmap_size
, GFP_KERNEL
);
92 mem
->window
.phys_base
= windows
[i
].phys_base
;
93 mem
->window
.size
= windows
[i
].size
;
94 mem
->window
.page_size
= page_size
;
97 mutex_init(&mem
->lock
);
98 epc
->windows
[i
] = mem
;
101 epc
->mem
= epc
->windows
[0];
102 epc
->num_windows
= num_windows
;
107 for (; i
>= 0; i
--) {
108 mem
= epc
->windows
[i
];
116 EXPORT_SYMBOL_GPL(pci_epc_multi_mem_init
);
118 int pci_epc_mem_init(struct pci_epc
*epc
, phys_addr_t base
,
119 size_t size
, size_t page_size
)
121 struct pci_epc_mem_window mem_window
;
123 mem_window
.phys_base
= base
;
124 mem_window
.size
= size
;
125 mem_window
.page_size
= page_size
;
127 return pci_epc_multi_mem_init(epc
, &mem_window
, 1);
129 EXPORT_SYMBOL_GPL(pci_epc_mem_init
);
132 * pci_epc_mem_exit() - cleanup the pci_epc_mem structure
133 * @epc: the EPC device that invoked pci_epc_mem_exit
135 * Invoke to cleanup the pci_epc_mem structure allocated in
136 * pci_epc_mem_init().
138 void pci_epc_mem_exit(struct pci_epc
*epc
)
140 struct pci_epc_mem
*mem
;
143 if (!epc
->num_windows
)
146 for (i
= 0; i
< epc
->num_windows
; i
++) {
147 mem
= epc
->windows
[i
];
155 epc
->num_windows
= 0;
157 EXPORT_SYMBOL_GPL(pci_epc_mem_exit
);
160 * pci_epc_mem_alloc_addr() - allocate memory address from EPC addr space
161 * @epc: the EPC device on which memory has to be allocated
162 * @phys_addr: populate the allocated physical address here
163 * @size: the size of the address space that has to be allocated
165 * Invoke to allocate memory address from the EPC address space. This
166 * is usually done to map the remote RC address into the local system.
168 void __iomem
*pci_epc_mem_alloc_addr(struct pci_epc
*epc
,
169 phys_addr_t
*phys_addr
, size_t size
)
171 void __iomem
*virt_addr
= NULL
;
172 struct pci_epc_mem
*mem
;
173 unsigned int page_shift
;
179 for (i
= 0; i
< epc
->num_windows
; i
++) {
180 mem
= epc
->windows
[i
];
181 mutex_lock(&mem
->lock
);
182 align_size
= ALIGN(size
, mem
->window
.page_size
);
183 order
= pci_epc_mem_get_order(mem
, align_size
);
185 pageno
= bitmap_find_free_region(mem
->bitmap
, mem
->pages
,
188 page_shift
= ilog2(mem
->window
.page_size
);
189 *phys_addr
= mem
->window
.phys_base
+
190 ((phys_addr_t
)pageno
<< page_shift
);
191 virt_addr
= ioremap(*phys_addr
, align_size
);
193 bitmap_release_region(mem
->bitmap
,
195 mutex_unlock(&mem
->lock
);
198 mutex_unlock(&mem
->lock
);
201 mutex_unlock(&mem
->lock
);
206 EXPORT_SYMBOL_GPL(pci_epc_mem_alloc_addr
);
208 static struct pci_epc_mem
*pci_epc_get_matching_window(struct pci_epc
*epc
,
209 phys_addr_t phys_addr
)
211 struct pci_epc_mem
*mem
;
214 for (i
= 0; i
< epc
->num_windows
; i
++) {
215 mem
= epc
->windows
[i
];
217 if (phys_addr
>= mem
->window
.phys_base
&&
218 phys_addr
< (mem
->window
.phys_base
+ mem
->window
.size
))
226 * pci_epc_mem_free_addr() - free the allocated memory address
227 * @epc: the EPC device on which memory was allocated
228 * @phys_addr: the allocated physical address
229 * @virt_addr: virtual address of the allocated mem space
230 * @size: the size of the allocated address space
232 * Invoke to free the memory allocated using pci_epc_mem_alloc_addr.
234 void pci_epc_mem_free_addr(struct pci_epc
*epc
, phys_addr_t phys_addr
,
235 void __iomem
*virt_addr
, size_t size
)
237 struct pci_epc_mem
*mem
;
238 unsigned int page_shift
;
243 mem
= pci_epc_get_matching_window(epc
, phys_addr
);
245 pr_err("failed to get matching window\n");
249 page_size
= mem
->window
.page_size
;
250 page_shift
= ilog2(page_size
);
252 pageno
= (phys_addr
- mem
->window
.phys_base
) >> page_shift
;
253 size
= ALIGN(size
, page_size
);
254 order
= pci_epc_mem_get_order(mem
, size
);
255 mutex_lock(&mem
->lock
);
256 bitmap_release_region(mem
->bitmap
, pageno
, order
);
257 mutex_unlock(&mem
->lock
);
259 EXPORT_SYMBOL_GPL(pci_epc_mem_free_addr
);
261 MODULE_DESCRIPTION("PCI EPC Address Space Management");
262 MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>");
263 MODULE_LICENSE("GPL v2");