blob: 60fbfe92e0ef8249cc5057f2d9a2bf1d48df58a0 [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001/**
2 * PCI Endpoint *Controller* Address Space Management
3 *
4 * Copyright (C) 2017 Texas Instruments
5 * Author: Kishon Vijay Abraham I <kishon@ti.com>
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 of
9 * the License as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <linux/io.h>
21#include <linux/module.h>
22#include <linux/slab.h>
23
24#include <linux/pci-epc.h>
25
26/**
27 * pci_epc_mem_get_order() - determine the allocation order of a memory size
28 * @mem: address space of the endpoint controller
29 * @size: the size for which to get the order
30 *
31 * Reimplement get_order() for mem->page_size since the generic get_order
32 * always gets order with a constant PAGE_SIZE.
33 */
34static int pci_epc_mem_get_order(struct pci_epc_mem *mem, size_t size)
35{
36 int order;
37 unsigned int page_shift = ilog2(mem->page_size);
38
39 size--;
40 size >>= page_shift;
41#if BITS_PER_LONG == 32
42 order = fls(size);
43#else
44 order = fls64(size);
45#endif
46 return order;
47}
48
49/**
50 * __pci_epc_mem_init() - initialize the pci_epc_mem structure
51 * @epc: the EPC device that invoked pci_epc_mem_init
52 * @phys_base: the physical address of the base
53 * @size: the size of the address space
54 * @page_size: size of each page
55 *
56 * Invoke to initialize the pci_epc_mem structure used by the
57 * endpoint functions to allocate mapped PCI address.
58 */
59int __pci_epc_mem_init(struct pci_epc *epc, phys_addr_t phys_base, size_t size,
60 size_t page_size)
61{
62 int ret;
63 struct pci_epc_mem *mem;
64 unsigned long *bitmap;
65 unsigned int page_shift;
66 int pages;
67 int bitmap_size;
68
69 if (page_size < PAGE_SIZE)
70 page_size = PAGE_SIZE;
71
72 page_shift = ilog2(page_size);
73 pages = size >> page_shift;
74 bitmap_size = BITS_TO_LONGS(pages) * sizeof(long);
75
76 mem = kzalloc(sizeof(*mem), GFP_KERNEL);
77 if (!mem) {
78 ret = -ENOMEM;
79 goto err;
80 }
81
82 bitmap = kzalloc(bitmap_size, GFP_KERNEL);
83 if (!bitmap) {
84 ret = -ENOMEM;
85 goto err_mem;
86 }
87
88 mem->bitmap = bitmap;
89 mem->phys_base = phys_base;
90 mem->page_size = page_size;
91 mem->pages = pages;
92 mem->size = size;
93 mutex_init(&mem->lock);
94
95 epc->mem = mem;
96
97 return 0;
98
99err_mem:
100 kfree(mem);
101
102err:
103return ret;
104}
105EXPORT_SYMBOL_GPL(__pci_epc_mem_init);
106
107/**
108 * pci_epc_mem_exit() - cleanup the pci_epc_mem structure
109 * @epc: the EPC device that invoked pci_epc_mem_exit
110 *
111 * Invoke to cleanup the pci_epc_mem structure allocated in
112 * pci_epc_mem_init().
113 */
114void pci_epc_mem_exit(struct pci_epc *epc)
115{
116 struct pci_epc_mem *mem = epc->mem;
117
118 epc->mem = NULL;
119 kfree(mem->bitmap);
120 kfree(mem);
121}
122EXPORT_SYMBOL_GPL(pci_epc_mem_exit);
123
124/**
125 * pci_epc_mem_alloc_addr() - allocate memory address from EPC addr space
126 * @epc: the EPC device on which memory has to be allocated
127 * @phys_addr: populate the allocated physical address here
128 * @size: the size of the address space that has to be allocated
129 *
130 * Invoke to allocate memory address from the EPC address space. This
131 * is usually done to map the remote RC address into the local system.
132 */
133void __iomem *pci_epc_mem_alloc_addr(struct pci_epc *epc,
134 phys_addr_t *phys_addr, size_t size)
135{
136 int pageno;
137 void __iomem *virt_addr = NULL;
138 struct pci_epc_mem *mem = epc->mem;
139 unsigned int page_shift = ilog2(mem->page_size);
140 int order;
141
142 size = ALIGN(size, mem->page_size);
143 order = pci_epc_mem_get_order(mem, size);
144
145 mutex_lock(&mem->lock);
146 pageno = bitmap_find_free_region(mem->bitmap, mem->pages, order);
147 if (pageno < 0)
148 goto ret;
149
150 *phys_addr = mem->phys_base + (pageno << page_shift);
151 virt_addr = ioremap(*phys_addr, size);
152 if (!virt_addr)
153 bitmap_release_region(mem->bitmap, pageno, order);
154
155ret:
156 mutex_unlock(&mem->lock);
157 return virt_addr;
158}
159EXPORT_SYMBOL_GPL(pci_epc_mem_alloc_addr);
160
161/**
162 * pci_epc_mem_free_addr() - free the allocated memory address
163 * @epc: the EPC device on which memory was allocated
164 * @phys_addr: the allocated physical address
165 * @virt_addr: virtual address of the allocated mem space
166 * @size: the size of the allocated address space
167 *
168 * Invoke to free the memory allocated using pci_epc_mem_alloc_addr.
169 */
170void pci_epc_mem_free_addr(struct pci_epc *epc, phys_addr_t phys_addr,
171 void __iomem *virt_addr, size_t size)
172{
173 int pageno;
174 struct pci_epc_mem *mem = epc->mem;
175 unsigned int page_shift = ilog2(mem->page_size);
176 int order;
177
178 iounmap(virt_addr);
179 pageno = (phys_addr - mem->phys_base) >> page_shift;
180 size = ALIGN(size, mem->page_size);
181 order = pci_epc_mem_get_order(mem, size);
182 mutex_lock(&mem->lock);
183 bitmap_release_region(mem->bitmap, pageno, order);
184 mutex_unlock(&mem->lock);
185}
186EXPORT_SYMBOL_GPL(pci_epc_mem_free_addr);
187
188MODULE_DESCRIPTION("PCI EPC Address Space Management");
189MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>");
190MODULE_LICENSE("GPL v2");