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
->page_size
);
30 #if BITS_PER_LONG == 32
39 * __pci_epc_mem_init() - initialize the pci_epc_mem structure
40 * @epc: the EPC device that invoked pci_epc_mem_init
41 * @phys_base: the physical address of the base
42 * @size: the size of the address space
43 * @page_size: size of each page
45 * Invoke to initialize the pci_epc_mem structure used by the
46 * endpoint functions to allocate mapped PCI address.
48 int __pci_epc_mem_init(struct pci_epc
*epc
, phys_addr_t phys_base
, size_t size
,
52 struct pci_epc_mem
*mem
;
53 unsigned long *bitmap
;
54 unsigned int page_shift
;
58 if (page_size
< PAGE_SIZE
)
59 page_size
= PAGE_SIZE
;
61 page_shift
= ilog2(page_size
);
62 pages
= size
>> page_shift
;
63 bitmap_size
= BITS_TO_LONGS(pages
) * sizeof(long);
65 mem
= kzalloc(sizeof(*mem
), GFP_KERNEL
);
71 bitmap
= kzalloc(bitmap_size
, GFP_KERNEL
);
78 mem
->phys_base
= phys_base
;
79 mem
->page_size
= page_size
;
82 mutex_init(&mem
->lock
);
94 EXPORT_SYMBOL_GPL(__pci_epc_mem_init
);
97 * pci_epc_mem_exit() - cleanup the pci_epc_mem structure
98 * @epc: the EPC device that invoked pci_epc_mem_exit
100 * Invoke to cleanup the pci_epc_mem structure allocated in
101 * pci_epc_mem_init().
103 void pci_epc_mem_exit(struct pci_epc
*epc
)
105 struct pci_epc_mem
*mem
= epc
->mem
;
111 EXPORT_SYMBOL_GPL(pci_epc_mem_exit
);
114 * pci_epc_mem_alloc_addr() - allocate memory address from EPC addr space
115 * @epc: the EPC device on which memory has to be allocated
116 * @phys_addr: populate the allocated physical address here
117 * @size: the size of the address space that has to be allocated
119 * Invoke to allocate memory address from the EPC address space. This
120 * is usually done to map the remote RC address into the local system.
122 void __iomem
*pci_epc_mem_alloc_addr(struct pci_epc
*epc
,
123 phys_addr_t
*phys_addr
, size_t size
)
126 void __iomem
*virt_addr
= NULL
;
127 struct pci_epc_mem
*mem
= epc
->mem
;
128 unsigned int page_shift
= ilog2(mem
->page_size
);
131 size
= ALIGN(size
, mem
->page_size
);
132 order
= pci_epc_mem_get_order(mem
, size
);
134 mutex_lock(&mem
->lock
);
135 pageno
= bitmap_find_free_region(mem
->bitmap
, mem
->pages
, order
);
139 *phys_addr
= mem
->phys_base
+ ((phys_addr_t
)pageno
<< page_shift
);
140 virt_addr
= ioremap(*phys_addr
, size
);
142 bitmap_release_region(mem
->bitmap
, pageno
, order
);
145 mutex_unlock(&mem
->lock
);
148 EXPORT_SYMBOL_GPL(pci_epc_mem_alloc_addr
);
151 * pci_epc_mem_free_addr() - free the allocated memory address
152 * @epc: the EPC device on which memory was allocated
153 * @phys_addr: the allocated physical address
154 * @virt_addr: virtual address of the allocated mem space
155 * @size: the size of the allocated address space
157 * Invoke to free the memory allocated using pci_epc_mem_alloc_addr.
159 void pci_epc_mem_free_addr(struct pci_epc
*epc
, phys_addr_t phys_addr
,
160 void __iomem
*virt_addr
, size_t size
)
163 struct pci_epc_mem
*mem
= epc
->mem
;
164 unsigned int page_shift
= ilog2(mem
->page_size
);
168 pageno
= (phys_addr
- mem
->phys_base
) >> page_shift
;
169 size
= ALIGN(size
, mem
->page_size
);
170 order
= pci_epc_mem_get_order(mem
, size
);
171 mutex_lock(&mem
->lock
);
172 bitmap_release_region(mem
->bitmap
, pageno
, order
);
173 mutex_unlock(&mem
->lock
);
175 EXPORT_SYMBOL_GPL(pci_epc_mem_free_addr
);
177 MODULE_DESCRIPTION("PCI EPC Address Space Management");
178 MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>");
179 MODULE_LICENSE("GPL v2");