]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/pci/endpoint/pci-epc-mem.c
Merge tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
[karo-tx-linux.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_init() - initialize the pci_epc_mem structure
28  * @epc: the EPC device that invoked pci_epc_mem_init
29  * @phys_base: the physical address of the base
30  * @size: the size of the address space
31  *
32  * Invoke to initialize the pci_epc_mem structure used by the
33  * endpoint functions to allocate mapped PCI address.
34  */
35 int pci_epc_mem_init(struct pci_epc *epc, phys_addr_t phys_base, size_t size)
36 {
37         int ret;
38         struct pci_epc_mem *mem;
39         unsigned long *bitmap;
40         int pages = size >> PAGE_SHIFT;
41         int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long);
42
43         mem = kzalloc(sizeof(*mem), GFP_KERNEL);
44         if (!mem) {
45                 ret = -ENOMEM;
46                 goto err;
47         }
48
49         bitmap = kzalloc(bitmap_size, GFP_KERNEL);
50         if (!bitmap) {
51                 ret = -ENOMEM;
52                 goto err_mem;
53         }
54
55         mem->bitmap = bitmap;
56         mem->phys_base = phys_base;
57         mem->pages = pages;
58         mem->size = size;
59
60         epc->mem = mem;
61
62         return 0;
63
64 err_mem:
65         kfree(mem);
66
67 err:
68 return ret;
69 }
70 EXPORT_SYMBOL_GPL(pci_epc_mem_init);
71
72 /**
73  * pci_epc_mem_exit() - cleanup the pci_epc_mem structure
74  * @epc: the EPC device that invoked pci_epc_mem_exit
75  *
76  * Invoke to cleanup the pci_epc_mem structure allocated in
77  * pci_epc_mem_init().
78  */
79 void pci_epc_mem_exit(struct pci_epc *epc)
80 {
81         struct pci_epc_mem *mem = epc->mem;
82
83         epc->mem = NULL;
84         kfree(mem->bitmap);
85         kfree(mem);
86 }
87 EXPORT_SYMBOL_GPL(pci_epc_mem_exit);
88
89 /**
90  * pci_epc_mem_alloc_addr() - allocate memory address from EPC addr space
91  * @epc: the EPC device on which memory has to be allocated
92  * @phys_addr: populate the allocated physical address here
93  * @size: the size of the address space that has to be allocated
94  *
95  * Invoke to allocate memory address from the EPC address space. This
96  * is usually done to map the remote RC address into the local system.
97  */
98 void __iomem *pci_epc_mem_alloc_addr(struct pci_epc *epc,
99                                      phys_addr_t *phys_addr, size_t size)
100 {
101         int pageno;
102         void __iomem *virt_addr;
103         struct pci_epc_mem *mem = epc->mem;
104         int order = get_order(size);
105
106         pageno = bitmap_find_free_region(mem->bitmap, mem->pages, order);
107         if (pageno < 0)
108                 return NULL;
109
110         *phys_addr = mem->phys_base + (pageno << PAGE_SHIFT);
111         virt_addr = ioremap(*phys_addr, size);
112         if (!virt_addr)
113                 bitmap_release_region(mem->bitmap, pageno, order);
114
115         return virt_addr;
116 }
117 EXPORT_SYMBOL_GPL(pci_epc_mem_alloc_addr);
118
119 /**
120  * pci_epc_mem_free_addr() - free the allocated memory address
121  * @epc: the EPC device on which memory was allocated
122  * @phys_addr: the allocated physical address
123  * @virt_addr: virtual address of the allocated mem space
124  * @size: the size of the allocated address space
125  *
126  * Invoke to free the memory allocated using pci_epc_mem_alloc_addr.
127  */
128 void pci_epc_mem_free_addr(struct pci_epc *epc, phys_addr_t phys_addr,
129                            void __iomem *virt_addr, size_t size)
130 {
131         int pageno;
132         int order = get_order(size);
133         struct pci_epc_mem *mem = epc->mem;
134
135         iounmap(virt_addr);
136         pageno = (phys_addr - mem->phys_base) >> PAGE_SHIFT;
137         bitmap_release_region(mem->bitmap, pageno, order);
138 }
139 EXPORT_SYMBOL_GPL(pci_epc_mem_free_addr);
140
141 MODULE_DESCRIPTION("PCI EPC Address Space Management");
142 MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>");
143 MODULE_LICENSE("GPL v2");