]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blob - drivers/pci/endpoint/pci-epc-mem.c
Merge branch 'pm-tools'
[mirror_ubuntu-bionic-kernel.git] / drivers / pci / endpoint / pci-epc-mem.c
1 /**
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 */
34 static 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 */
59 int __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
94 epc->mem = mem;
95
96 return 0;
97
98 err_mem:
99 kfree(mem);
100
101 err:
102 return ret;
103 }
104 EXPORT_SYMBOL_GPL(__pci_epc_mem_init);
105
106 /**
107 * pci_epc_mem_exit() - cleanup the pci_epc_mem structure
108 * @epc: the EPC device that invoked pci_epc_mem_exit
109 *
110 * Invoke to cleanup the pci_epc_mem structure allocated in
111 * pci_epc_mem_init().
112 */
113 void pci_epc_mem_exit(struct pci_epc *epc)
114 {
115 struct pci_epc_mem *mem = epc->mem;
116
117 epc->mem = NULL;
118 kfree(mem->bitmap);
119 kfree(mem);
120 }
121 EXPORT_SYMBOL_GPL(pci_epc_mem_exit);
122
123 /**
124 * pci_epc_mem_alloc_addr() - allocate memory address from EPC addr space
125 * @epc: the EPC device on which memory has to be allocated
126 * @phys_addr: populate the allocated physical address here
127 * @size: the size of the address space that has to be allocated
128 *
129 * Invoke to allocate memory address from the EPC address space. This
130 * is usually done to map the remote RC address into the local system.
131 */
132 void __iomem *pci_epc_mem_alloc_addr(struct pci_epc *epc,
133 phys_addr_t *phys_addr, size_t size)
134 {
135 int pageno;
136 void __iomem *virt_addr;
137 struct pci_epc_mem *mem = epc->mem;
138 unsigned int page_shift = ilog2(mem->page_size);
139 int order;
140
141 size = ALIGN(size, mem->page_size);
142 order = pci_epc_mem_get_order(mem, size);
143
144 pageno = bitmap_find_free_region(mem->bitmap, mem->pages, order);
145 if (pageno < 0)
146 return NULL;
147
148 *phys_addr = mem->phys_base + (pageno << page_shift);
149 virt_addr = ioremap(*phys_addr, size);
150 if (!virt_addr)
151 bitmap_release_region(mem->bitmap, pageno, order);
152
153 return virt_addr;
154 }
155 EXPORT_SYMBOL_GPL(pci_epc_mem_alloc_addr);
156
157 /**
158 * pci_epc_mem_free_addr() - free the allocated memory address
159 * @epc: the EPC device on which memory was allocated
160 * @phys_addr: the allocated physical address
161 * @virt_addr: virtual address of the allocated mem space
162 * @size: the size of the allocated address space
163 *
164 * Invoke to free the memory allocated using pci_epc_mem_alloc_addr.
165 */
166 void pci_epc_mem_free_addr(struct pci_epc *epc, phys_addr_t phys_addr,
167 void __iomem *virt_addr, size_t size)
168 {
169 int pageno;
170 struct pci_epc_mem *mem = epc->mem;
171 unsigned int page_shift = ilog2(mem->page_size);
172 int order;
173
174 iounmap(virt_addr);
175 pageno = (phys_addr - mem->phys_base) >> page_shift;
176 size = ALIGN(size, mem->page_size);
177 order = pci_epc_mem_get_order(mem, size);
178 bitmap_release_region(mem->bitmap, pageno, order);
179 }
180 EXPORT_SYMBOL_GPL(pci_epc_mem_free_addr);
181
182 MODULE_DESCRIPTION("PCI EPC Address Space Management");
183 MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>");
184 MODULE_LICENSE("GPL v2");