diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-05-08 22:03:25 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-05-08 22:03:25 -0400 |
commit | 857f8640147c9fb43f20e43cbca6452710e1ca5d (patch) | |
tree | 76a92068d703b8001ca790ffa096d435fa24ae81 /drivers/pci/endpoint | |
parent | 8f3207c7eab9d885cc64c778416537034a7d9c5b (diff) | |
parent | 3146c8f4de9b0858794a902f273aec13f168596e (diff) |
Merge tag 'pci-v4.12-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci
Pull PCI updates from Bjorn Helgaas:
- add framework for supporting PCIe devices in Endpoint mode (Kishon
Vijay Abraham I)
- use non-postable PCI config space mappings when possible (Lorenzo
Pieralisi)
- clean up and unify mmap of PCI BARs (David Woodhouse)
- export and unify Function Level Reset support (Christoph Hellwig)
- avoid FLR for Intel 82579 NICs (Sasha Neftin)
- add pci_request_irq() and pci_free_irq() helpers (Christoph Hellwig)
- short-circuit config access failures for disconnected devices (Keith
Busch)
- remove D3 sleep delay when possible (Adrian Hunter)
- freeze PME scan before suspending devices (Lukas Wunner)
- stop disabling MSI/MSI-X in pci_device_shutdown() (Prarit Bhargava)
- disable boot interrupt quirk for ASUS M2N-LR (Stefan Assmann)
- add arch-specific alignment control to improve device passthrough by
avoiding multiple BARs in a page (Yongji Xie)
- add sysfs sriov_drivers_autoprobe to control VF driver binding
(Bodong Wang)
- allow slots below PCI-to-PCIe "reverse bridges" (Bjorn Helgaas)
- fix crashes when unbinding host controllers that don't support
removal (Brian Norris)
- add driver for MicroSemi Switchtec management interface (Logan
Gunthorpe)
- add driver for Faraday Technology FTPCI100 host bridge (Linus
Walleij)
- add i.MX7D support (Andrey Smirnov)
- use generic MSI support for Aardvark (Thomas Petazzoni)
- make Rockchip driver modular (Brian Norris)
- advertise 128-byte Read Completion Boundary support for Rockchip
(Shawn Lin)
- advertise PCI_EXP_LNKSTA_SLC for Rockchip root port (Shawn Lin)
- convert atomic_t to refcount_t in HV driver (Elena Reshetova)
- add CPU IRQ affinity in HV driver (K. Y. Srinivasan)
- fix PCI bus removal in HV driver (Long Li)
- add support for ThunderX2 DMA alias topology (Jayachandran C)
- add ThunderX pass2.x 2nd node MCFG quirk (Tomasz Nowicki)
- add ITE 8893 bridge DMA alias quirk (Jarod Wilson)
- restrict Cavium ACS quirk only to CN81xx/CN83xx/CN88xx devices
(Manish Jaggi)
* tag 'pci-v4.12-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci: (146 commits)
PCI: Don't allow unbinding host controllers that aren't prepared
ARM: DRA7: clockdomain: Change the CLKTRCTRL of CM_PCIE_CLKSTCTRL to SW_WKUP
MAINTAINERS: Add PCI Endpoint maintainer
Documentation: PCI: Add userguide for PCI endpoint test function
tools: PCI: Add sample test script to invoke pcitest
tools: PCI: Add a userspace tool to test PCI endpoint
Documentation: misc-devices: Add Documentation for pci-endpoint-test driver
misc: Add host side PCI driver for PCI test function device
PCI: Add device IDs for DRA74x and DRA72x
dt-bindings: PCI: dra7xx: Add DT bindings to enable unaligned access
PCI: dwc: dra7xx: Workaround for errata id i870
dt-bindings: PCI: dra7xx: Add DT bindings for PCI dra7xx EP mode
PCI: dwc: dra7xx: Add EP mode support
PCI: dwc: dra7xx: Facilitate wrapper and MSI interrupts to be enabled independently
dt-bindings: PCI: Add DT bindings for PCI designware EP mode
PCI: dwc: designware: Add EP mode support
Documentation: PCI: Add binding documentation for pci-test endpoint function
ixgbe: Use pcie_flr() instead of duplicating it
IB/hfi1: Use pcie_flr() instead of duplicating it
PCI: imx6: Fix spelling mistake: "contol" -> "control"
...
Diffstat (limited to 'drivers/pci/endpoint')
-rw-r--r-- | drivers/pci/endpoint/Kconfig | 31 | ||||
-rw-r--r-- | drivers/pci/endpoint/Makefile | 7 | ||||
-rw-r--r-- | drivers/pci/endpoint/functions/Kconfig | 12 | ||||
-rw-r--r-- | drivers/pci/endpoint/functions/Makefile | 5 | ||||
-rw-r--r-- | drivers/pci/endpoint/functions/pci-epf-test.c | 510 | ||||
-rw-r--r-- | drivers/pci/endpoint/pci-ep-cfs.c | 509 | ||||
-rw-r--r-- | drivers/pci/endpoint/pci-epc-core.c | 580 | ||||
-rw-r--r-- | drivers/pci/endpoint/pci-epc-mem.c | 143 | ||||
-rw-r--r-- | drivers/pci/endpoint/pci-epf-core.c | 359 |
9 files changed, 2156 insertions, 0 deletions
diff --git a/drivers/pci/endpoint/Kconfig b/drivers/pci/endpoint/Kconfig new file mode 100644 index 000000000000..c23f146fb5a6 --- /dev/null +++ b/drivers/pci/endpoint/Kconfig | |||
@@ -0,0 +1,31 @@ | |||
1 | # | ||
2 | # PCI Endpoint Support | ||
3 | # | ||
4 | |||
5 | menu "PCI Endpoint" | ||
6 | |||
7 | config PCI_ENDPOINT | ||
8 | bool "PCI Endpoint Support" | ||
9 | help | ||
10 | Enable this configuration option to support configurable PCI | ||
11 | endpoint. This should be enabled if the platform has a PCI | ||
12 | controller that can operate in endpoint mode. | ||
13 | |||
14 | Enabling this option will build the endpoint library, which | ||
15 | includes endpoint controller library and endpoint function | ||
16 | library. | ||
17 | |||
18 | If in doubt, say "N" to disable Endpoint support. | ||
19 | |||
20 | config PCI_ENDPOINT_CONFIGFS | ||
21 | bool "PCI Endpoint Configfs Support" | ||
22 | depends on PCI_ENDPOINT | ||
23 | select CONFIGFS_FS | ||
24 | help | ||
25 | This will enable the configfs entry that can be used to | ||
26 | configure the endpoint function and used to bind the | ||
27 | function with a endpoint controller. | ||
28 | |||
29 | source "drivers/pci/endpoint/functions/Kconfig" | ||
30 | |||
31 | endmenu | ||
diff --git a/drivers/pci/endpoint/Makefile b/drivers/pci/endpoint/Makefile new file mode 100644 index 000000000000..1041f80a4645 --- /dev/null +++ b/drivers/pci/endpoint/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | # | ||
2 | # Makefile for PCI Endpoint Support | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_PCI_ENDPOINT_CONFIGFS) += pci-ep-cfs.o | ||
6 | obj-$(CONFIG_PCI_ENDPOINT) += pci-epc-core.o pci-epf-core.o\ | ||
7 | pci-epc-mem.o functions/ | ||
diff --git a/drivers/pci/endpoint/functions/Kconfig b/drivers/pci/endpoint/functions/Kconfig new file mode 100644 index 000000000000..175edad42d2f --- /dev/null +++ b/drivers/pci/endpoint/functions/Kconfig | |||
@@ -0,0 +1,12 @@ | |||
1 | # | ||
2 | # PCI Endpoint Functions | ||
3 | # | ||
4 | |||
5 | config PCI_EPF_TEST | ||
6 | tristate "PCI Endpoint Test driver" | ||
7 | depends on PCI_ENDPOINT | ||
8 | help | ||
9 | Enable this configuration option to enable the test driver | ||
10 | for PCI Endpoint. | ||
11 | |||
12 | If in doubt, say "N" to disable Endpoint test driver. | ||
diff --git a/drivers/pci/endpoint/functions/Makefile b/drivers/pci/endpoint/functions/Makefile new file mode 100644 index 000000000000..6d94a4801838 --- /dev/null +++ b/drivers/pci/endpoint/functions/Makefile | |||
@@ -0,0 +1,5 @@ | |||
1 | # | ||
2 | # Makefile for PCI Endpoint Functions | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_PCI_EPF_TEST) += pci-epf-test.o | ||
diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c new file mode 100644 index 000000000000..53fff8030337 --- /dev/null +++ b/drivers/pci/endpoint/functions/pci-epf-test.c | |||
@@ -0,0 +1,510 @@ | |||
1 | /** | ||
2 | * Test driver to test endpoint functionality | ||
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/crc32.h> | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/io.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/pci_ids.h> | ||
26 | #include <linux/random.h> | ||
27 | |||
28 | #include <linux/pci-epc.h> | ||
29 | #include <linux/pci-epf.h> | ||
30 | #include <linux/pci_regs.h> | ||
31 | |||
32 | #define COMMAND_RAISE_LEGACY_IRQ BIT(0) | ||
33 | #define COMMAND_RAISE_MSI_IRQ BIT(1) | ||
34 | #define MSI_NUMBER_SHIFT 2 | ||
35 | #define MSI_NUMBER_MASK (0x3f << MSI_NUMBER_SHIFT) | ||
36 | #define COMMAND_READ BIT(8) | ||
37 | #define COMMAND_WRITE BIT(9) | ||
38 | #define COMMAND_COPY BIT(10) | ||
39 | |||
40 | #define STATUS_READ_SUCCESS BIT(0) | ||
41 | #define STATUS_READ_FAIL BIT(1) | ||
42 | #define STATUS_WRITE_SUCCESS BIT(2) | ||
43 | #define STATUS_WRITE_FAIL BIT(3) | ||
44 | #define STATUS_COPY_SUCCESS BIT(4) | ||
45 | #define STATUS_COPY_FAIL BIT(5) | ||
46 | #define STATUS_IRQ_RAISED BIT(6) | ||
47 | #define STATUS_SRC_ADDR_INVALID BIT(7) | ||
48 | #define STATUS_DST_ADDR_INVALID BIT(8) | ||
49 | |||
50 | #define TIMER_RESOLUTION 1 | ||
51 | |||
52 | static struct workqueue_struct *kpcitest_workqueue; | ||
53 | |||
54 | struct pci_epf_test { | ||
55 | void *reg[6]; | ||
56 | struct pci_epf *epf; | ||
57 | struct delayed_work cmd_handler; | ||
58 | }; | ||
59 | |||
60 | struct pci_epf_test_reg { | ||
61 | u32 magic; | ||
62 | u32 command; | ||
63 | u32 status; | ||
64 | u64 src_addr; | ||
65 | u64 dst_addr; | ||
66 | u32 size; | ||
67 | u32 checksum; | ||
68 | } __packed; | ||
69 | |||
70 | static struct pci_epf_header test_header = { | ||
71 | .vendorid = PCI_ANY_ID, | ||
72 | .deviceid = PCI_ANY_ID, | ||
73 | .baseclass_code = PCI_CLASS_OTHERS, | ||
74 | .interrupt_pin = PCI_INTERRUPT_INTA, | ||
75 | }; | ||
76 | |||
77 | static int bar_size[] = { 512, 1024, 16384, 131072, 1048576 }; | ||
78 | |||
79 | static int pci_epf_test_copy(struct pci_epf_test *epf_test) | ||
80 | { | ||
81 | int ret; | ||
82 | void __iomem *src_addr; | ||
83 | void __iomem *dst_addr; | ||
84 | phys_addr_t src_phys_addr; | ||
85 | phys_addr_t dst_phys_addr; | ||
86 | struct pci_epf *epf = epf_test->epf; | ||
87 | struct device *dev = &epf->dev; | ||
88 | struct pci_epc *epc = epf->epc; | ||
89 | struct pci_epf_test_reg *reg = epf_test->reg[0]; | ||
90 | |||
91 | src_addr = pci_epc_mem_alloc_addr(epc, &src_phys_addr, reg->size); | ||
92 | if (!src_addr) { | ||
93 | dev_err(dev, "failed to allocate source address\n"); | ||
94 | reg->status = STATUS_SRC_ADDR_INVALID; | ||
95 | ret = -ENOMEM; | ||
96 | goto err; | ||
97 | } | ||
98 | |||
99 | ret = pci_epc_map_addr(epc, src_phys_addr, reg->src_addr, reg->size); | ||
100 | if (ret) { | ||
101 | dev_err(dev, "failed to map source address\n"); | ||
102 | reg->status = STATUS_SRC_ADDR_INVALID; | ||
103 | goto err_src_addr; | ||
104 | } | ||
105 | |||
106 | dst_addr = pci_epc_mem_alloc_addr(epc, &dst_phys_addr, reg->size); | ||
107 | if (!dst_addr) { | ||
108 | dev_err(dev, "failed to allocate destination address\n"); | ||
109 | reg->status = STATUS_DST_ADDR_INVALID; | ||
110 | ret = -ENOMEM; | ||
111 | goto err_src_map_addr; | ||
112 | } | ||
113 | |||
114 | ret = pci_epc_map_addr(epc, dst_phys_addr, reg->dst_addr, reg->size); | ||
115 | if (ret) { | ||
116 | dev_err(dev, "failed to map destination address\n"); | ||
117 | reg->status = STATUS_DST_ADDR_INVALID; | ||
118 | goto err_dst_addr; | ||
119 | } | ||
120 | |||
121 | memcpy(dst_addr, src_addr, reg->size); | ||
122 | |||
123 | pci_epc_unmap_addr(epc, dst_phys_addr); | ||
124 | |||
125 | err_dst_addr: | ||
126 | pci_epc_mem_free_addr(epc, dst_phys_addr, dst_addr, reg->size); | ||
127 | |||
128 | err_src_map_addr: | ||
129 | pci_epc_unmap_addr(epc, src_phys_addr); | ||
130 | |||
131 | err_src_addr: | ||
132 | pci_epc_mem_free_addr(epc, src_phys_addr, src_addr, reg->size); | ||
133 | |||
134 | err: | ||
135 | return ret; | ||
136 | } | ||
137 | |||
138 | static int pci_epf_test_read(struct pci_epf_test *epf_test) | ||
139 | { | ||
140 | int ret; | ||
141 | void __iomem *src_addr; | ||
142 | void *buf; | ||
143 | u32 crc32; | ||
144 | phys_addr_t phys_addr; | ||
145 | struct pci_epf *epf = epf_test->epf; | ||
146 | struct device *dev = &epf->dev; | ||
147 | struct pci_epc *epc = epf->epc; | ||
148 | struct pci_epf_test_reg *reg = epf_test->reg[0]; | ||
149 | |||
150 | src_addr = pci_epc_mem_alloc_addr(epc, &phys_addr, reg->size); | ||
151 | if (!src_addr) { | ||
152 | dev_err(dev, "failed to allocate address\n"); | ||
153 | reg->status = STATUS_SRC_ADDR_INVALID; | ||
154 | ret = -ENOMEM; | ||
155 | goto err; | ||
156 | } | ||
157 | |||
158 | ret = pci_epc_map_addr(epc, phys_addr, reg->src_addr, reg->size); | ||
159 | if (ret) { | ||
160 | dev_err(dev, "failed to map address\n"); | ||
161 | reg->status = STATUS_SRC_ADDR_INVALID; | ||
162 | goto err_addr; | ||
163 | } | ||
164 | |||
165 | buf = kzalloc(reg->size, GFP_KERNEL); | ||
166 | if (!buf) { | ||
167 | ret = -ENOMEM; | ||
168 | goto err_map_addr; | ||
169 | } | ||
170 | |||
171 | memcpy(buf, src_addr, reg->size); | ||
172 | |||
173 | crc32 = crc32_le(~0, buf, reg->size); | ||
174 | if (crc32 != reg->checksum) | ||
175 | ret = -EIO; | ||
176 | |||
177 | kfree(buf); | ||
178 | |||
179 | err_map_addr: | ||
180 | pci_epc_unmap_addr(epc, phys_addr); | ||
181 | |||
182 | err_addr: | ||
183 | pci_epc_mem_free_addr(epc, phys_addr, src_addr, reg->size); | ||
184 | |||
185 | err: | ||
186 | return ret; | ||
187 | } | ||
188 | |||
189 | static int pci_epf_test_write(struct pci_epf_test *epf_test) | ||
190 | { | ||
191 | int ret; | ||
192 | void __iomem *dst_addr; | ||
193 | void *buf; | ||
194 | phys_addr_t phys_addr; | ||
195 | struct pci_epf *epf = epf_test->epf; | ||
196 | struct device *dev = &epf->dev; | ||
197 | struct pci_epc *epc = epf->epc; | ||
198 | struct pci_epf_test_reg *reg = epf_test->reg[0]; | ||
199 | |||
200 | dst_addr = pci_epc_mem_alloc_addr(epc, &phys_addr, reg->size); | ||
201 | if (!dst_addr) { | ||
202 | dev_err(dev, "failed to allocate address\n"); | ||
203 | reg->status = STATUS_DST_ADDR_INVALID; | ||
204 | ret = -ENOMEM; | ||
205 | goto err; | ||
206 | } | ||
207 | |||
208 | ret = pci_epc_map_addr(epc, phys_addr, reg->dst_addr, reg->size); | ||
209 | if (ret) { | ||
210 | dev_err(dev, "failed to map address\n"); | ||
211 | reg->status = STATUS_DST_ADDR_INVALID; | ||
212 | goto err_addr; | ||
213 | } | ||
214 | |||
215 | buf = kzalloc(reg->size, GFP_KERNEL); | ||
216 | if (!buf) { | ||
217 | ret = -ENOMEM; | ||
218 | goto err_map_addr; | ||
219 | } | ||
220 | |||
221 | get_random_bytes(buf, reg->size); | ||
222 | reg->checksum = crc32_le(~0, buf, reg->size); | ||
223 | |||
224 | memcpy(dst_addr, buf, reg->size); | ||
225 | |||
226 | /* | ||
227 | * wait 1ms inorder for the write to complete. Without this delay L3 | ||
228 | * error in observed in the host system. | ||
229 | */ | ||
230 | mdelay(1); | ||
231 | |||
232 | kfree(buf); | ||
233 | |||
234 | err_map_addr: | ||
235 | pci_epc_unmap_addr(epc, phys_addr); | ||
236 | |||
237 | err_addr: | ||
238 | pci_epc_mem_free_addr(epc, phys_addr, dst_addr, reg->size); | ||
239 | |||
240 | err: | ||
241 | return ret; | ||
242 | } | ||
243 | |||
244 | static void pci_epf_test_raise_irq(struct pci_epf_test *epf_test) | ||
245 | { | ||
246 | u8 irq; | ||
247 | u8 msi_count; | ||
248 | struct pci_epf *epf = epf_test->epf; | ||
249 | struct pci_epc *epc = epf->epc; | ||
250 | struct pci_epf_test_reg *reg = epf_test->reg[0]; | ||
251 | |||
252 | reg->status |= STATUS_IRQ_RAISED; | ||
253 | msi_count = pci_epc_get_msi(epc); | ||
254 | irq = (reg->command & MSI_NUMBER_MASK) >> MSI_NUMBER_SHIFT; | ||
255 | if (irq > msi_count || msi_count <= 0) | ||
256 | pci_epc_raise_irq(epc, PCI_EPC_IRQ_LEGACY, 0); | ||
257 | else | ||
258 | pci_epc_raise_irq(epc, PCI_EPC_IRQ_MSI, irq); | ||
259 | } | ||
260 | |||
261 | static void pci_epf_test_cmd_handler(struct work_struct *work) | ||
262 | { | ||
263 | int ret; | ||
264 | u8 irq; | ||
265 | u8 msi_count; | ||
266 | struct pci_epf_test *epf_test = container_of(work, struct pci_epf_test, | ||
267 | cmd_handler.work); | ||
268 | struct pci_epf *epf = epf_test->epf; | ||
269 | struct pci_epc *epc = epf->epc; | ||
270 | struct pci_epf_test_reg *reg = epf_test->reg[0]; | ||
271 | |||
272 | if (!reg->command) | ||
273 | goto reset_handler; | ||
274 | |||
275 | if (reg->command & COMMAND_RAISE_LEGACY_IRQ) { | ||
276 | reg->status = STATUS_IRQ_RAISED; | ||
277 | pci_epc_raise_irq(epc, PCI_EPC_IRQ_LEGACY, 0); | ||
278 | goto reset_handler; | ||
279 | } | ||
280 | |||
281 | if (reg->command & COMMAND_WRITE) { | ||
282 | ret = pci_epf_test_write(epf_test); | ||
283 | if (ret) | ||
284 | reg->status |= STATUS_WRITE_FAIL; | ||
285 | else | ||
286 | reg->status |= STATUS_WRITE_SUCCESS; | ||
287 | pci_epf_test_raise_irq(epf_test); | ||
288 | goto reset_handler; | ||
289 | } | ||
290 | |||
291 | if (reg->command & COMMAND_READ) { | ||
292 | ret = pci_epf_test_read(epf_test); | ||
293 | if (!ret) | ||
294 | reg->status |= STATUS_READ_SUCCESS; | ||
295 | else | ||
296 | reg->status |= STATUS_READ_FAIL; | ||
297 | pci_epf_test_raise_irq(epf_test); | ||
298 | goto reset_handler; | ||
299 | } | ||
300 | |||
301 | if (reg->command & COMMAND_COPY) { | ||
302 | ret = pci_epf_test_copy(epf_test); | ||
303 | if (!ret) | ||
304 | reg->status |= STATUS_COPY_SUCCESS; | ||
305 | else | ||
306 | reg->status |= STATUS_COPY_FAIL; | ||
307 | pci_epf_test_raise_irq(epf_test); | ||
308 | goto reset_handler; | ||
309 | } | ||
310 | |||
311 | if (reg->command & COMMAND_RAISE_MSI_IRQ) { | ||
312 | msi_count = pci_epc_get_msi(epc); | ||
313 | irq = (reg->command & MSI_NUMBER_MASK) >> MSI_NUMBER_SHIFT; | ||
314 | if (irq > msi_count || msi_count <= 0) | ||
315 | goto reset_handler; | ||
316 | reg->status = STATUS_IRQ_RAISED; | ||
317 | pci_epc_raise_irq(epc, PCI_EPC_IRQ_MSI, irq); | ||
318 | goto reset_handler; | ||
319 | } | ||
320 | |||
321 | reset_handler: | ||
322 | reg->command = 0; | ||
323 | |||
324 | queue_delayed_work(kpcitest_workqueue, &epf_test->cmd_handler, | ||
325 | msecs_to_jiffies(1)); | ||
326 | } | ||
327 | |||
328 | static void pci_epf_test_linkup(struct pci_epf *epf) | ||
329 | { | ||
330 | struct pci_epf_test *epf_test = epf_get_drvdata(epf); | ||
331 | |||
332 | queue_delayed_work(kpcitest_workqueue, &epf_test->cmd_handler, | ||
333 | msecs_to_jiffies(1)); | ||
334 | } | ||
335 | |||
336 | static void pci_epf_test_unbind(struct pci_epf *epf) | ||
337 | { | ||
338 | struct pci_epf_test *epf_test = epf_get_drvdata(epf); | ||
339 | struct pci_epc *epc = epf->epc; | ||
340 | int bar; | ||
341 | |||
342 | cancel_delayed_work(&epf_test->cmd_handler); | ||
343 | pci_epc_stop(epc); | ||
344 | for (bar = BAR_0; bar <= BAR_5; bar++) { | ||
345 | if (epf_test->reg[bar]) { | ||
346 | pci_epf_free_space(epf, epf_test->reg[bar], bar); | ||
347 | pci_epc_clear_bar(epc, bar); | ||
348 | } | ||
349 | } | ||
350 | } | ||
351 | |||
352 | static int pci_epf_test_set_bar(struct pci_epf *epf) | ||
353 | { | ||
354 | int flags; | ||
355 | int bar; | ||
356 | int ret; | ||
357 | struct pci_epf_bar *epf_bar; | ||
358 | struct pci_epc *epc = epf->epc; | ||
359 | struct device *dev = &epf->dev; | ||
360 | struct pci_epf_test *epf_test = epf_get_drvdata(epf); | ||
361 | |||
362 | flags = PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_32; | ||
363 | if (sizeof(dma_addr_t) == 0x8) | ||
364 | flags |= PCI_BASE_ADDRESS_MEM_TYPE_64; | ||
365 | |||
366 | for (bar = BAR_0; bar <= BAR_5; bar++) { | ||
367 | epf_bar = &epf->bar[bar]; | ||
368 | ret = pci_epc_set_bar(epc, bar, epf_bar->phys_addr, | ||
369 | epf_bar->size, flags); | ||
370 | if (ret) { | ||
371 | pci_epf_free_space(epf, epf_test->reg[bar], bar); | ||
372 | dev_err(dev, "failed to set BAR%d\n", bar); | ||
373 | if (bar == BAR_0) | ||
374 | return ret; | ||
375 | } | ||
376 | } | ||
377 | |||
378 | return 0; | ||
379 | } | ||
380 | |||
381 | static int pci_epf_test_alloc_space(struct pci_epf *epf) | ||
382 | { | ||
383 | struct pci_epf_test *epf_test = epf_get_drvdata(epf); | ||
384 | struct device *dev = &epf->dev; | ||
385 | void *base; | ||
386 | int bar; | ||
387 | |||
388 | base = pci_epf_alloc_space(epf, sizeof(struct pci_epf_test_reg), | ||
389 | BAR_0); | ||
390 | if (!base) { | ||
391 | dev_err(dev, "failed to allocated register space\n"); | ||
392 | return -ENOMEM; | ||
393 | } | ||
394 | epf_test->reg[0] = base; | ||
395 | |||
396 | for (bar = BAR_1; bar <= BAR_5; bar++) { | ||
397 | base = pci_epf_alloc_space(epf, bar_size[bar - 1], bar); | ||
398 | if (!base) | ||
399 | dev_err(dev, "failed to allocate space for BAR%d\n", | ||
400 | bar); | ||
401 | epf_test->reg[bar] = base; | ||
402 | } | ||
403 | |||
404 | return 0; | ||
405 | } | ||
406 | |||
407 | static int pci_epf_test_bind(struct pci_epf *epf) | ||
408 | { | ||
409 | int ret; | ||
410 | struct pci_epf_header *header = epf->header; | ||
411 | struct pci_epc *epc = epf->epc; | ||
412 | struct device *dev = &epf->dev; | ||
413 | |||
414 | if (WARN_ON_ONCE(!epc)) | ||
415 | return -EINVAL; | ||
416 | |||
417 | ret = pci_epc_write_header(epc, header); | ||
418 | if (ret) { | ||
419 | dev_err(dev, "configuration header write failed\n"); | ||
420 | return ret; | ||
421 | } | ||
422 | |||
423 | ret = pci_epf_test_alloc_space(epf); | ||
424 | if (ret) | ||
425 | return ret; | ||
426 | |||
427 | ret = pci_epf_test_set_bar(epf); | ||
428 | if (ret) | ||
429 | return ret; | ||
430 | |||
431 | ret = pci_epc_set_msi(epc, epf->msi_interrupts); | ||
432 | if (ret) | ||
433 | return ret; | ||
434 | |||
435 | return 0; | ||
436 | } | ||
437 | |||
438 | static int pci_epf_test_probe(struct pci_epf *epf) | ||
439 | { | ||
440 | struct pci_epf_test *epf_test; | ||
441 | struct device *dev = &epf->dev; | ||
442 | |||
443 | epf_test = devm_kzalloc(dev, sizeof(*epf_test), GFP_KERNEL); | ||
444 | if (!epf_test) | ||
445 | return -ENOMEM; | ||
446 | |||
447 | epf->header = &test_header; | ||
448 | epf_test->epf = epf; | ||
449 | |||
450 | INIT_DELAYED_WORK(&epf_test->cmd_handler, pci_epf_test_cmd_handler); | ||
451 | |||
452 | epf_set_drvdata(epf, epf_test); | ||
453 | return 0; | ||
454 | } | ||
455 | |||
456 | static int pci_epf_test_remove(struct pci_epf *epf) | ||
457 | { | ||
458 | struct pci_epf_test *epf_test = epf_get_drvdata(epf); | ||
459 | |||
460 | kfree(epf_test); | ||
461 | return 0; | ||
462 | } | ||
463 | |||
464 | static struct pci_epf_ops ops = { | ||
465 | .unbind = pci_epf_test_unbind, | ||
466 | .bind = pci_epf_test_bind, | ||
467 | .linkup = pci_epf_test_linkup, | ||
468 | }; | ||
469 | |||
470 | static const struct pci_epf_device_id pci_epf_test_ids[] = { | ||
471 | { | ||
472 | .name = "pci_epf_test", | ||
473 | }, | ||
474 | {}, | ||
475 | }; | ||
476 | |||
477 | static struct pci_epf_driver test_driver = { | ||
478 | .driver.name = "pci_epf_test", | ||
479 | .probe = pci_epf_test_probe, | ||
480 | .remove = pci_epf_test_remove, | ||
481 | .id_table = pci_epf_test_ids, | ||
482 | .ops = &ops, | ||
483 | .owner = THIS_MODULE, | ||
484 | }; | ||
485 | |||
486 | static int __init pci_epf_test_init(void) | ||
487 | { | ||
488 | int ret; | ||
489 | |||
490 | kpcitest_workqueue = alloc_workqueue("kpcitest", | ||
491 | WQ_MEM_RECLAIM | WQ_HIGHPRI, 0); | ||
492 | ret = pci_epf_register_driver(&test_driver); | ||
493 | if (ret) { | ||
494 | pr_err("failed to register pci epf test driver --> %d\n", ret); | ||
495 | return ret; | ||
496 | } | ||
497 | |||
498 | return 0; | ||
499 | } | ||
500 | module_init(pci_epf_test_init); | ||
501 | |||
502 | static void __exit pci_epf_test_exit(void) | ||
503 | { | ||
504 | pci_epf_unregister_driver(&test_driver); | ||
505 | } | ||
506 | module_exit(pci_epf_test_exit); | ||
507 | |||
508 | MODULE_DESCRIPTION("PCI EPF TEST DRIVER"); | ||
509 | MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>"); | ||
510 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/pci/endpoint/pci-ep-cfs.c b/drivers/pci/endpoint/pci-ep-cfs.c new file mode 100644 index 000000000000..424fdd6ed1ca --- /dev/null +++ b/drivers/pci/endpoint/pci-ep-cfs.c | |||
@@ -0,0 +1,509 @@ | |||
1 | /** | ||
2 | * configfs to configure the PCI endpoint | ||
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/module.h> | ||
21 | #include <linux/slab.h> | ||
22 | |||
23 | #include <linux/pci-epc.h> | ||
24 | #include <linux/pci-epf.h> | ||
25 | #include <linux/pci-ep-cfs.h> | ||
26 | |||
27 | static struct config_group *functions_group; | ||
28 | static struct config_group *controllers_group; | ||
29 | |||
30 | struct pci_epf_group { | ||
31 | struct config_group group; | ||
32 | struct pci_epf *epf; | ||
33 | }; | ||
34 | |||
35 | struct pci_epc_group { | ||
36 | struct config_group group; | ||
37 | struct pci_epc *epc; | ||
38 | bool start; | ||
39 | unsigned long function_num_map; | ||
40 | }; | ||
41 | |||
42 | static inline struct pci_epf_group *to_pci_epf_group(struct config_item *item) | ||
43 | { | ||
44 | return container_of(to_config_group(item), struct pci_epf_group, group); | ||
45 | } | ||
46 | |||
47 | static inline struct pci_epc_group *to_pci_epc_group(struct config_item *item) | ||
48 | { | ||
49 | return container_of(to_config_group(item), struct pci_epc_group, group); | ||
50 | } | ||
51 | |||
52 | static ssize_t pci_epc_start_store(struct config_item *item, const char *page, | ||
53 | size_t len) | ||
54 | { | ||
55 | int ret; | ||
56 | bool start; | ||
57 | struct pci_epc *epc; | ||
58 | struct pci_epc_group *epc_group = to_pci_epc_group(item); | ||
59 | |||
60 | epc = epc_group->epc; | ||
61 | |||
62 | ret = kstrtobool(page, &start); | ||
63 | if (ret) | ||
64 | return ret; | ||
65 | |||
66 | if (!start) { | ||
67 | pci_epc_stop(epc); | ||
68 | return len; | ||
69 | } | ||
70 | |||
71 | ret = pci_epc_start(epc); | ||
72 | if (ret) { | ||
73 | dev_err(&epc->dev, "failed to start endpoint controller\n"); | ||
74 | return -EINVAL; | ||
75 | } | ||
76 | |||
77 | epc_group->start = start; | ||
78 | |||
79 | return len; | ||
80 | } | ||
81 | |||
82 | static ssize_t pci_epc_start_show(struct config_item *item, char *page) | ||
83 | { | ||
84 | return sprintf(page, "%d\n", | ||
85 | to_pci_epc_group(item)->start); | ||
86 | } | ||
87 | |||
88 | CONFIGFS_ATTR(pci_epc_, start); | ||
89 | |||
90 | static struct configfs_attribute *pci_epc_attrs[] = { | ||
91 | &pci_epc_attr_start, | ||
92 | NULL, | ||
93 | }; | ||
94 | |||
95 | static int pci_epc_epf_link(struct config_item *epc_item, | ||
96 | struct config_item *epf_item) | ||
97 | { | ||
98 | int ret; | ||
99 | u32 func_no = 0; | ||
100 | struct pci_epc *epc; | ||
101 | struct pci_epf *epf; | ||
102 | struct pci_epf_group *epf_group = to_pci_epf_group(epf_item); | ||
103 | struct pci_epc_group *epc_group = to_pci_epc_group(epc_item); | ||
104 | |||
105 | epc = epc_group->epc; | ||
106 | epf = epf_group->epf; | ||
107 | ret = pci_epc_add_epf(epc, epf); | ||
108 | if (ret) | ||
109 | goto err_add_epf; | ||
110 | |||
111 | func_no = find_first_zero_bit(&epc_group->function_num_map, | ||
112 | sizeof(epc_group->function_num_map)); | ||
113 | set_bit(func_no, &epc_group->function_num_map); | ||
114 | epf->func_no = func_no; | ||
115 | |||
116 | ret = pci_epf_bind(epf); | ||
117 | if (ret) | ||
118 | goto err_epf_bind; | ||
119 | |||
120 | return 0; | ||
121 | |||
122 | err_epf_bind: | ||
123 | pci_epc_remove_epf(epc, epf); | ||
124 | |||
125 | err_add_epf: | ||
126 | clear_bit(func_no, &epc_group->function_num_map); | ||
127 | |||
128 | return ret; | ||
129 | } | ||
130 | |||
131 | static void pci_epc_epf_unlink(struct config_item *epc_item, | ||
132 | struct config_item *epf_item) | ||
133 | { | ||
134 | struct pci_epc *epc; | ||
135 | struct pci_epf *epf; | ||
136 | struct pci_epf_group *epf_group = to_pci_epf_group(epf_item); | ||
137 | struct pci_epc_group *epc_group = to_pci_epc_group(epc_item); | ||
138 | |||
139 | WARN_ON_ONCE(epc_group->start); | ||
140 | |||
141 | epc = epc_group->epc; | ||
142 | epf = epf_group->epf; | ||
143 | clear_bit(epf->func_no, &epc_group->function_num_map); | ||
144 | pci_epf_unbind(epf); | ||
145 | pci_epc_remove_epf(epc, epf); | ||
146 | } | ||
147 | |||
148 | static struct configfs_item_operations pci_epc_item_ops = { | ||
149 | .allow_link = pci_epc_epf_link, | ||
150 | .drop_link = pci_epc_epf_unlink, | ||
151 | }; | ||
152 | |||
153 | static struct config_item_type pci_epc_type = { | ||
154 | .ct_item_ops = &pci_epc_item_ops, | ||
155 | .ct_attrs = pci_epc_attrs, | ||
156 | .ct_owner = THIS_MODULE, | ||
157 | }; | ||
158 | |||
159 | struct config_group *pci_ep_cfs_add_epc_group(const char *name) | ||
160 | { | ||
161 | int ret; | ||
162 | struct pci_epc *epc; | ||
163 | struct config_group *group; | ||
164 | struct pci_epc_group *epc_group; | ||
165 | |||
166 | epc_group = kzalloc(sizeof(*epc_group), GFP_KERNEL); | ||
167 | if (!epc_group) { | ||
168 | ret = -ENOMEM; | ||
169 | goto err; | ||
170 | } | ||
171 | |||
172 | group = &epc_group->group; | ||
173 | |||
174 | config_group_init_type_name(group, name, &pci_epc_type); | ||
175 | ret = configfs_register_group(controllers_group, group); | ||
176 | if (ret) { | ||
177 | pr_err("failed to register configfs group for %s\n", name); | ||
178 | goto err_register_group; | ||
179 | } | ||
180 | |||
181 | epc = pci_epc_get(name); | ||
182 | if (IS_ERR(epc)) { | ||
183 | ret = PTR_ERR(epc); | ||
184 | goto err_epc_get; | ||
185 | } | ||
186 | |||
187 | epc_group->epc = epc; | ||
188 | |||
189 | return group; | ||
190 | |||
191 | err_epc_get: | ||
192 | configfs_unregister_group(group); | ||
193 | |||
194 | err_register_group: | ||
195 | kfree(epc_group); | ||
196 | |||
197 | err: | ||
198 | return ERR_PTR(ret); | ||
199 | } | ||
200 | EXPORT_SYMBOL(pci_ep_cfs_add_epc_group); | ||
201 | |||
202 | void pci_ep_cfs_remove_epc_group(struct config_group *group) | ||
203 | { | ||
204 | struct pci_epc_group *epc_group; | ||
205 | |||
206 | if (!group) | ||
207 | return; | ||
208 | |||
209 | epc_group = container_of(group, struct pci_epc_group, group); | ||
210 | pci_epc_put(epc_group->epc); | ||
211 | configfs_unregister_group(&epc_group->group); | ||
212 | kfree(epc_group); | ||
213 | } | ||
214 | EXPORT_SYMBOL(pci_ep_cfs_remove_epc_group); | ||
215 | |||
216 | #define PCI_EPF_HEADER_R(_name) \ | ||
217 | static ssize_t pci_epf_##_name##_show(struct config_item *item, char *page) \ | ||
218 | { \ | ||
219 | struct pci_epf *epf = to_pci_epf_group(item)->epf; \ | ||
220 | if (WARN_ON_ONCE(!epf->header)) \ | ||
221 | return -EINVAL; \ | ||
222 | return sprintf(page, "0x%04x\n", epf->header->_name); \ | ||
223 | } | ||
224 | |||
225 | #define PCI_EPF_HEADER_W_u32(_name) \ | ||
226 | static ssize_t pci_epf_##_name##_store(struct config_item *item, \ | ||
227 | const char *page, size_t len) \ | ||
228 | { \ | ||
229 | u32 val; \ | ||
230 | int ret; \ | ||
231 | struct pci_epf *epf = to_pci_epf_group(item)->epf; \ | ||
232 | if (WARN_ON_ONCE(!epf->header)) \ | ||
233 | return -EINVAL; \ | ||
234 | ret = kstrtou32(page, 0, &val); \ | ||
235 | if (ret) \ | ||
236 | return ret; \ | ||
237 | epf->header->_name = val; \ | ||
238 | return len; \ | ||
239 | } | ||
240 | |||
241 | #define PCI_EPF_HEADER_W_u16(_name) \ | ||
242 | static ssize_t pci_epf_##_name##_store(struct config_item *item, \ | ||
243 | const char *page, size_t len) \ | ||
244 | { \ | ||
245 | u16 val; \ | ||
246 | int ret; \ | ||
247 | struct pci_epf *epf = to_pci_epf_group(item)->epf; \ | ||
248 | if (WARN_ON_ONCE(!epf->header)) \ | ||
249 | return -EINVAL; \ | ||
250 | ret = kstrtou16(page, 0, &val); \ | ||
251 | if (ret) \ | ||
252 | return ret; \ | ||
253 | epf->header->_name = val; \ | ||
254 | return len; \ | ||
255 | } | ||
256 | |||
257 | #define PCI_EPF_HEADER_W_u8(_name) \ | ||
258 | static ssize_t pci_epf_##_name##_store(struct config_item *item, \ | ||
259 | const char *page, size_t len) \ | ||
260 | { \ | ||
261 | u8 val; \ | ||
262 | int ret; \ | ||
263 | struct pci_epf *epf = to_pci_epf_group(item)->epf; \ | ||
264 | if (WARN_ON_ONCE(!epf->header)) \ | ||
265 | return -EINVAL; \ | ||
266 | ret = kstrtou8(page, 0, &val); \ | ||
267 | if (ret) \ | ||
268 | return ret; \ | ||
269 | epf->header->_name = val; \ | ||
270 | return len; \ | ||
271 | } | ||
272 | |||
273 | static ssize_t pci_epf_msi_interrupts_store(struct config_item *item, | ||
274 | const char *page, size_t len) | ||
275 | { | ||
276 | u8 val; | ||
277 | int ret; | ||
278 | |||
279 | ret = kstrtou8(page, 0, &val); | ||
280 | if (ret) | ||
281 | return ret; | ||
282 | |||
283 | to_pci_epf_group(item)->epf->msi_interrupts = val; | ||
284 | |||
285 | return len; | ||
286 | } | ||
287 | |||
288 | static ssize_t pci_epf_msi_interrupts_show(struct config_item *item, | ||
289 | char *page) | ||
290 | { | ||
291 | return sprintf(page, "%d\n", | ||
292 | to_pci_epf_group(item)->epf->msi_interrupts); | ||
293 | } | ||
294 | |||
295 | PCI_EPF_HEADER_R(vendorid) | ||
296 | PCI_EPF_HEADER_W_u16(vendorid) | ||
297 | |||
298 | PCI_EPF_HEADER_R(deviceid) | ||
299 | PCI_EPF_HEADER_W_u16(deviceid) | ||
300 | |||
301 | PCI_EPF_HEADER_R(revid) | ||
302 | PCI_EPF_HEADER_W_u8(revid) | ||
303 | |||
304 | PCI_EPF_HEADER_R(progif_code) | ||
305 | PCI_EPF_HEADER_W_u8(progif_code) | ||
306 | |||
307 | PCI_EPF_HEADER_R(subclass_code) | ||
308 | PCI_EPF_HEADER_W_u8(subclass_code) | ||
309 | |||
310 | PCI_EPF_HEADER_R(baseclass_code) | ||
311 | PCI_EPF_HEADER_W_u8(baseclass_code) | ||
312 | |||
313 | PCI_EPF_HEADER_R(cache_line_size) | ||
314 | PCI_EPF_HEADER_W_u8(cache_line_size) | ||
315 | |||
316 | PCI_EPF_HEADER_R(subsys_vendor_id) | ||
317 | PCI_EPF_HEADER_W_u16(subsys_vendor_id) | ||
318 | |||
319 | PCI_EPF_HEADER_R(subsys_id) | ||
320 | PCI_EPF_HEADER_W_u16(subsys_id) | ||
321 | |||
322 | PCI_EPF_HEADER_R(interrupt_pin) | ||
323 | PCI_EPF_HEADER_W_u8(interrupt_pin) | ||
324 | |||
325 | CONFIGFS_ATTR(pci_epf_, vendorid); | ||
326 | CONFIGFS_ATTR(pci_epf_, deviceid); | ||
327 | CONFIGFS_ATTR(pci_epf_, revid); | ||
328 | CONFIGFS_ATTR(pci_epf_, progif_code); | ||
329 | CONFIGFS_ATTR(pci_epf_, subclass_code); | ||
330 | CONFIGFS_ATTR(pci_epf_, baseclass_code); | ||
331 | CONFIGFS_ATTR(pci_epf_, cache_line_size); | ||
332 | CONFIGFS_ATTR(pci_epf_, subsys_vendor_id); | ||
333 | CONFIGFS_ATTR(pci_epf_, subsys_id); | ||
334 | CONFIGFS_ATTR(pci_epf_, interrupt_pin); | ||
335 | CONFIGFS_ATTR(pci_epf_, msi_interrupts); | ||
336 | |||
337 | static struct configfs_attribute *pci_epf_attrs[] = { | ||
338 | &pci_epf_attr_vendorid, | ||
339 | &pci_epf_attr_deviceid, | ||
340 | &pci_epf_attr_revid, | ||
341 | &pci_epf_attr_progif_code, | ||
342 | &pci_epf_attr_subclass_code, | ||
343 | &pci_epf_attr_baseclass_code, | ||
344 | &pci_epf_attr_cache_line_size, | ||
345 | &pci_epf_attr_subsys_vendor_id, | ||
346 | &pci_epf_attr_subsys_id, | ||
347 | &pci_epf_attr_interrupt_pin, | ||
348 | &pci_epf_attr_msi_interrupts, | ||
349 | NULL, | ||
350 | }; | ||
351 | |||
352 | static void pci_epf_release(struct config_item *item) | ||
353 | { | ||
354 | struct pci_epf_group *epf_group = to_pci_epf_group(item); | ||
355 | |||
356 | pci_epf_destroy(epf_group->epf); | ||
357 | kfree(epf_group); | ||
358 | } | ||
359 | |||
360 | static struct configfs_item_operations pci_epf_ops = { | ||
361 | .release = pci_epf_release, | ||
362 | }; | ||
363 | |||
364 | static struct config_item_type pci_epf_type = { | ||
365 | .ct_item_ops = &pci_epf_ops, | ||
366 | .ct_attrs = pci_epf_attrs, | ||
367 | .ct_owner = THIS_MODULE, | ||
368 | }; | ||
369 | |||
370 | static struct config_group *pci_epf_make(struct config_group *group, | ||
371 | const char *name) | ||
372 | { | ||
373 | struct pci_epf_group *epf_group; | ||
374 | struct pci_epf *epf; | ||
375 | |||
376 | epf_group = kzalloc(sizeof(*epf_group), GFP_KERNEL); | ||
377 | if (!epf_group) | ||
378 | return ERR_PTR(-ENOMEM); | ||
379 | |||
380 | config_group_init_type_name(&epf_group->group, name, &pci_epf_type); | ||
381 | |||
382 | epf = pci_epf_create(group->cg_item.ci_name); | ||
383 | if (IS_ERR(epf)) { | ||
384 | pr_err("failed to create endpoint function device\n"); | ||
385 | return ERR_PTR(-EINVAL); | ||
386 | } | ||
387 | |||
388 | epf_group->epf = epf; | ||
389 | |||
390 | return &epf_group->group; | ||
391 | } | ||
392 | |||
393 | static void pci_epf_drop(struct config_group *group, struct config_item *item) | ||
394 | { | ||
395 | config_item_put(item); | ||
396 | } | ||
397 | |||
398 | static struct configfs_group_operations pci_epf_group_ops = { | ||
399 | .make_group = &pci_epf_make, | ||
400 | .drop_item = &pci_epf_drop, | ||
401 | }; | ||
402 | |||
403 | static struct config_item_type pci_epf_group_type = { | ||
404 | .ct_group_ops = &pci_epf_group_ops, | ||
405 | .ct_owner = THIS_MODULE, | ||
406 | }; | ||
407 | |||
408 | struct config_group *pci_ep_cfs_add_epf_group(const char *name) | ||
409 | { | ||
410 | struct config_group *group; | ||
411 | |||
412 | group = configfs_register_default_group(functions_group, name, | ||
413 | &pci_epf_group_type); | ||
414 | if (IS_ERR(group)) | ||
415 | pr_err("failed to register configfs group for %s function\n", | ||
416 | name); | ||
417 | |||
418 | return group; | ||
419 | } | ||
420 | EXPORT_SYMBOL(pci_ep_cfs_add_epf_group); | ||
421 | |||
422 | void pci_ep_cfs_remove_epf_group(struct config_group *group) | ||
423 | { | ||
424 | if (IS_ERR_OR_NULL(group)) | ||
425 | return; | ||
426 | |||
427 | configfs_unregister_default_group(group); | ||
428 | } | ||
429 | EXPORT_SYMBOL(pci_ep_cfs_remove_epf_group); | ||
430 | |||
431 | static struct config_item_type pci_functions_type = { | ||
432 | .ct_owner = THIS_MODULE, | ||
433 | }; | ||
434 | |||
435 | static struct config_item_type pci_controllers_type = { | ||
436 | .ct_owner = THIS_MODULE, | ||
437 | }; | ||
438 | |||
439 | static struct config_item_type pci_ep_type = { | ||
440 | .ct_owner = THIS_MODULE, | ||
441 | }; | ||
442 | |||
443 | static struct configfs_subsystem pci_ep_cfs_subsys = { | ||
444 | .su_group = { | ||
445 | .cg_item = { | ||
446 | .ci_namebuf = "pci_ep", | ||
447 | .ci_type = &pci_ep_type, | ||
448 | }, | ||
449 | }, | ||
450 | .su_mutex = __MUTEX_INITIALIZER(pci_ep_cfs_subsys.su_mutex), | ||
451 | }; | ||
452 | |||
453 | static int __init pci_ep_cfs_init(void) | ||
454 | { | ||
455 | int ret; | ||
456 | struct config_group *root = &pci_ep_cfs_subsys.su_group; | ||
457 | |||
458 | config_group_init(root); | ||
459 | |||
460 | ret = configfs_register_subsystem(&pci_ep_cfs_subsys); | ||
461 | if (ret) { | ||
462 | pr_err("Error %d while registering subsystem %s\n", | ||
463 | ret, root->cg_item.ci_namebuf); | ||
464 | goto err; | ||
465 | } | ||
466 | |||
467 | functions_group = configfs_register_default_group(root, "functions", | ||
468 | &pci_functions_type); | ||
469 | if (IS_ERR(functions_group)) { | ||
470 | ret = PTR_ERR(functions_group); | ||
471 | pr_err("Error %d while registering functions group\n", | ||
472 | ret); | ||
473 | goto err_functions_group; | ||
474 | } | ||
475 | |||
476 | controllers_group = | ||
477 | configfs_register_default_group(root, "controllers", | ||
478 | &pci_controllers_type); | ||
479 | if (IS_ERR(controllers_group)) { | ||
480 | ret = PTR_ERR(controllers_group); | ||
481 | pr_err("Error %d while registering controllers group\n", | ||
482 | ret); | ||
483 | goto err_controllers_group; | ||
484 | } | ||
485 | |||
486 | return 0; | ||
487 | |||
488 | err_controllers_group: | ||
489 | configfs_unregister_default_group(functions_group); | ||
490 | |||
491 | err_functions_group: | ||
492 | configfs_unregister_subsystem(&pci_ep_cfs_subsys); | ||
493 | |||
494 | err: | ||
495 | return ret; | ||
496 | } | ||
497 | module_init(pci_ep_cfs_init); | ||
498 | |||
499 | static void __exit pci_ep_cfs_exit(void) | ||
500 | { | ||
501 | configfs_unregister_default_group(controllers_group); | ||
502 | configfs_unregister_default_group(functions_group); | ||
503 | configfs_unregister_subsystem(&pci_ep_cfs_subsys); | ||
504 | } | ||
505 | module_exit(pci_ep_cfs_exit); | ||
506 | |||
507 | MODULE_DESCRIPTION("PCI EP CONFIGFS"); | ||
508 | MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>"); | ||
509 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c new file mode 100644 index 000000000000..caa7be10e473 --- /dev/null +++ b/drivers/pci/endpoint/pci-epc-core.c | |||
@@ -0,0 +1,580 @@ | |||
1 | /** | ||
2 | * PCI Endpoint *Controller* (EPC) library | ||
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/device.h> | ||
21 | #include <linux/dma-mapping.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/module.h> | ||
24 | |||
25 | #include <linux/pci-epc.h> | ||
26 | #include <linux/pci-epf.h> | ||
27 | #include <linux/pci-ep-cfs.h> | ||
28 | |||
29 | static struct class *pci_epc_class; | ||
30 | |||
31 | static void devm_pci_epc_release(struct device *dev, void *res) | ||
32 | { | ||
33 | struct pci_epc *epc = *(struct pci_epc **)res; | ||
34 | |||
35 | pci_epc_destroy(epc); | ||
36 | } | ||
37 | |||
38 | static int devm_pci_epc_match(struct device *dev, void *res, void *match_data) | ||
39 | { | ||
40 | struct pci_epc **epc = res; | ||
41 | |||
42 | return *epc == match_data; | ||
43 | } | ||
44 | |||
45 | /** | ||
46 | * pci_epc_put() - release the PCI endpoint controller | ||
47 | * @epc: epc returned by pci_epc_get() | ||
48 | * | ||
49 | * release the refcount the caller obtained by invoking pci_epc_get() | ||
50 | */ | ||
51 | void pci_epc_put(struct pci_epc *epc) | ||
52 | { | ||
53 | if (!epc || IS_ERR(epc)) | ||
54 | return; | ||
55 | |||
56 | module_put(epc->ops->owner); | ||
57 | put_device(&epc->dev); | ||
58 | } | ||
59 | EXPORT_SYMBOL_GPL(pci_epc_put); | ||
60 | |||
61 | /** | ||
62 | * pci_epc_get() - get the PCI endpoint controller | ||
63 | * @epc_name: device name of the endpoint controller | ||
64 | * | ||
65 | * Invoke to get struct pci_epc * corresponding to the device name of the | ||
66 | * endpoint controller | ||
67 | */ | ||
68 | struct pci_epc *pci_epc_get(const char *epc_name) | ||
69 | { | ||
70 | int ret = -EINVAL; | ||
71 | struct pci_epc *epc; | ||
72 | struct device *dev; | ||
73 | struct class_dev_iter iter; | ||
74 | |||
75 | class_dev_iter_init(&iter, pci_epc_class, NULL, NULL); | ||
76 | while ((dev = class_dev_iter_next(&iter))) { | ||
77 | if (strcmp(epc_name, dev_name(dev))) | ||
78 | continue; | ||
79 | |||
80 | epc = to_pci_epc(dev); | ||
81 | if (!try_module_get(epc->ops->owner)) { | ||
82 | ret = -EINVAL; | ||
83 | goto err; | ||
84 | } | ||
85 | |||
86 | class_dev_iter_exit(&iter); | ||
87 | get_device(&epc->dev); | ||
88 | return epc; | ||
89 | } | ||
90 | |||
91 | err: | ||
92 | class_dev_iter_exit(&iter); | ||
93 | return ERR_PTR(ret); | ||
94 | } | ||
95 | EXPORT_SYMBOL_GPL(pci_epc_get); | ||
96 | |||
97 | /** | ||
98 | * pci_epc_stop() - stop the PCI link | ||
99 | * @epc: the link of the EPC device that has to be stopped | ||
100 | * | ||
101 | * Invoke to stop the PCI link | ||
102 | */ | ||
103 | void pci_epc_stop(struct pci_epc *epc) | ||
104 | { | ||
105 | unsigned long flags; | ||
106 | |||
107 | if (IS_ERR(epc) || !epc->ops->stop) | ||
108 | return; | ||
109 | |||
110 | spin_lock_irqsave(&epc->lock, flags); | ||
111 | epc->ops->stop(epc); | ||
112 | spin_unlock_irqrestore(&epc->lock, flags); | ||
113 | } | ||
114 | EXPORT_SYMBOL_GPL(pci_epc_stop); | ||
115 | |||
116 | /** | ||
117 | * pci_epc_start() - start the PCI link | ||
118 | * @epc: the link of *this* EPC device has to be started | ||
119 | * | ||
120 | * Invoke to start the PCI link | ||
121 | */ | ||
122 | int pci_epc_start(struct pci_epc *epc) | ||
123 | { | ||
124 | int ret; | ||
125 | unsigned long flags; | ||
126 | |||
127 | if (IS_ERR(epc)) | ||
128 | return -EINVAL; | ||
129 | |||
130 | if (!epc->ops->start) | ||
131 | return 0; | ||
132 | |||
133 | spin_lock_irqsave(&epc->lock, flags); | ||
134 | ret = epc->ops->start(epc); | ||
135 | spin_unlock_irqrestore(&epc->lock, flags); | ||
136 | |||
137 | return ret; | ||
138 | } | ||
139 | EXPORT_SYMBOL_GPL(pci_epc_start); | ||
140 | |||
141 | /** | ||
142 | * pci_epc_raise_irq() - interrupt the host system | ||
143 | * @epc: the EPC device which has to interrupt the host | ||
144 | * @type: specify the type of interrupt; legacy or MSI | ||
145 | * @interrupt_num: the MSI interrupt number | ||
146 | * | ||
147 | * Invoke to raise an MSI or legacy interrupt | ||
148 | */ | ||
149 | int pci_epc_raise_irq(struct pci_epc *epc, enum pci_epc_irq_type type, | ||
150 | u8 interrupt_num) | ||
151 | { | ||
152 | int ret; | ||
153 | unsigned long flags; | ||
154 | |||
155 | if (IS_ERR(epc)) | ||
156 | return -EINVAL; | ||
157 | |||
158 | if (!epc->ops->raise_irq) | ||
159 | return 0; | ||
160 | |||
161 | spin_lock_irqsave(&epc->lock, flags); | ||
162 | ret = epc->ops->raise_irq(epc, type, interrupt_num); | ||
163 | spin_unlock_irqrestore(&epc->lock, flags); | ||
164 | |||
165 | return ret; | ||
166 | } | ||
167 | EXPORT_SYMBOL_GPL(pci_epc_raise_irq); | ||
168 | |||
169 | /** | ||
170 | * pci_epc_get_msi() - get the number of MSI interrupt numbers allocated | ||
171 | * @epc: the EPC device to which MSI interrupts was requested | ||
172 | * | ||
173 | * Invoke to get the number of MSI interrupts allocated by the RC | ||
174 | */ | ||
175 | int pci_epc_get_msi(struct pci_epc *epc) | ||
176 | { | ||
177 | int interrupt; | ||
178 | unsigned long flags; | ||
179 | |||
180 | if (IS_ERR(epc)) | ||
181 | return 0; | ||
182 | |||
183 | if (!epc->ops->get_msi) | ||
184 | return 0; | ||
185 | |||
186 | spin_lock_irqsave(&epc->lock, flags); | ||
187 | interrupt = epc->ops->get_msi(epc); | ||
188 | spin_unlock_irqrestore(&epc->lock, flags); | ||
189 | |||
190 | if (interrupt < 0) | ||
191 | return 0; | ||
192 | |||
193 | interrupt = 1 << interrupt; | ||
194 | |||
195 | return interrupt; | ||
196 | } | ||
197 | EXPORT_SYMBOL_GPL(pci_epc_get_msi); | ||
198 | |||
199 | /** | ||
200 | * pci_epc_set_msi() - set the number of MSI interrupt numbers required | ||
201 | * @epc: the EPC device on which MSI has to be configured | ||
202 | * @interrupts: number of MSI interrupts required by the EPF | ||
203 | * | ||
204 | * Invoke to set the required number of MSI interrupts. | ||
205 | */ | ||
206 | int pci_epc_set_msi(struct pci_epc *epc, u8 interrupts) | ||
207 | { | ||
208 | int ret; | ||
209 | u8 encode_int; | ||
210 | unsigned long flags; | ||
211 | |||
212 | if (IS_ERR(epc)) | ||
213 | return -EINVAL; | ||
214 | |||
215 | if (!epc->ops->set_msi) | ||
216 | return 0; | ||
217 | |||
218 | encode_int = order_base_2(interrupts); | ||
219 | |||
220 | spin_lock_irqsave(&epc->lock, flags); | ||
221 | ret = epc->ops->set_msi(epc, encode_int); | ||
222 | spin_unlock_irqrestore(&epc->lock, flags); | ||
223 | |||
224 | return ret; | ||
225 | } | ||
226 | EXPORT_SYMBOL_GPL(pci_epc_set_msi); | ||
227 | |||
228 | /** | ||
229 | * pci_epc_unmap_addr() - unmap CPU address from PCI address | ||
230 | * @epc: the EPC device on which address is allocated | ||
231 | * @phys_addr: physical address of the local system | ||
232 | * | ||
233 | * Invoke to unmap the CPU address from PCI address. | ||
234 | */ | ||
235 | void pci_epc_unmap_addr(struct pci_epc *epc, phys_addr_t phys_addr) | ||
236 | { | ||
237 | unsigned long flags; | ||
238 | |||
239 | if (IS_ERR(epc)) | ||
240 | return; | ||
241 | |||
242 | if (!epc->ops->unmap_addr) | ||
243 | return; | ||
244 | |||
245 | spin_lock_irqsave(&epc->lock, flags); | ||
246 | epc->ops->unmap_addr(epc, phys_addr); | ||
247 | spin_unlock_irqrestore(&epc->lock, flags); | ||
248 | } | ||
249 | EXPORT_SYMBOL_GPL(pci_epc_unmap_addr); | ||
250 | |||
251 | /** | ||
252 | * pci_epc_map_addr() - map CPU address to PCI address | ||
253 | * @epc: the EPC device on which address is allocated | ||
254 | * @phys_addr: physical address of the local system | ||
255 | * @pci_addr: PCI address to which the physical address should be mapped | ||
256 | * @size: the size of the allocation | ||
257 | * | ||
258 | * Invoke to map CPU address with PCI address. | ||
259 | */ | ||
260 | int pci_epc_map_addr(struct pci_epc *epc, phys_addr_t phys_addr, | ||
261 | u64 pci_addr, size_t size) | ||
262 | { | ||
263 | int ret; | ||
264 | unsigned long flags; | ||
265 | |||
266 | if (IS_ERR(epc)) | ||
267 | return -EINVAL; | ||
268 | |||
269 | if (!epc->ops->map_addr) | ||
270 | return 0; | ||
271 | |||
272 | spin_lock_irqsave(&epc->lock, flags); | ||
273 | ret = epc->ops->map_addr(epc, phys_addr, pci_addr, size); | ||
274 | spin_unlock_irqrestore(&epc->lock, flags); | ||
275 | |||
276 | return ret; | ||
277 | } | ||
278 | EXPORT_SYMBOL_GPL(pci_epc_map_addr); | ||
279 | |||
280 | /** | ||
281 | * pci_epc_clear_bar() - reset the BAR | ||
282 | * @epc: the EPC device for which the BAR has to be cleared | ||
283 | * @bar: the BAR number that has to be reset | ||
284 | * | ||
285 | * Invoke to reset the BAR of the endpoint device. | ||
286 | */ | ||
287 | void pci_epc_clear_bar(struct pci_epc *epc, int bar) | ||
288 | { | ||
289 | unsigned long flags; | ||
290 | |||
291 | if (IS_ERR(epc)) | ||
292 | return; | ||
293 | |||
294 | if (!epc->ops->clear_bar) | ||
295 | return; | ||
296 | |||
297 | spin_lock_irqsave(&epc->lock, flags); | ||
298 | epc->ops->clear_bar(epc, bar); | ||
299 | spin_unlock_irqrestore(&epc->lock, flags); | ||
300 | } | ||
301 | EXPORT_SYMBOL_GPL(pci_epc_clear_bar); | ||
302 | |||
303 | /** | ||
304 | * pci_epc_set_bar() - configure BAR in order for host to assign PCI addr space | ||
305 | * @epc: the EPC device on which BAR has to be configured | ||
306 | * @bar: the BAR number that has to be configured | ||
307 | * @size: the size of the addr space | ||
308 | * @flags: specify memory allocation/io allocation/32bit address/64 bit address | ||
309 | * | ||
310 | * Invoke to configure the BAR of the endpoint device. | ||
311 | */ | ||
312 | int pci_epc_set_bar(struct pci_epc *epc, enum pci_barno bar, | ||
313 | dma_addr_t bar_phys, size_t size, int flags) | ||
314 | { | ||
315 | int ret; | ||
316 | unsigned long irq_flags; | ||
317 | |||
318 | if (IS_ERR(epc)) | ||
319 | return -EINVAL; | ||
320 | |||
321 | if (!epc->ops->set_bar) | ||
322 | return 0; | ||
323 | |||
324 | spin_lock_irqsave(&epc->lock, irq_flags); | ||
325 | ret = epc->ops->set_bar(epc, bar, bar_phys, size, flags); | ||
326 | spin_unlock_irqrestore(&epc->lock, irq_flags); | ||
327 | |||
328 | return ret; | ||
329 | } | ||
330 | EXPORT_SYMBOL_GPL(pci_epc_set_bar); | ||
331 | |||
332 | /** | ||
333 | * pci_epc_write_header() - write standard configuration header | ||
334 | * @epc: the EPC device to which the configuration header should be written | ||
335 | * @header: standard configuration header fields | ||
336 | * | ||
337 | * Invoke to write the configuration header to the endpoint controller. Every | ||
338 | * endpoint controller will have a dedicated location to which the standard | ||
339 | * configuration header would be written. The callback function should write | ||
340 | * the header fields to this dedicated location. | ||
341 | */ | ||
342 | int pci_epc_write_header(struct pci_epc *epc, struct pci_epf_header *header) | ||
343 | { | ||
344 | int ret; | ||
345 | unsigned long flags; | ||
346 | |||
347 | if (IS_ERR(epc)) | ||
348 | return -EINVAL; | ||
349 | |||
350 | if (!epc->ops->write_header) | ||
351 | return 0; | ||
352 | |||
353 | spin_lock_irqsave(&epc->lock, flags); | ||
354 | ret = epc->ops->write_header(epc, header); | ||
355 | spin_unlock_irqrestore(&epc->lock, flags); | ||
356 | |||
357 | return ret; | ||
358 | } | ||
359 | EXPORT_SYMBOL_GPL(pci_epc_write_header); | ||
360 | |||
361 | /** | ||
362 | * pci_epc_add_epf() - bind PCI endpoint function to an endpoint controller | ||
363 | * @epc: the EPC device to which the endpoint function should be added | ||
364 | * @epf: the endpoint function to be added | ||
365 | * | ||
366 | * A PCI endpoint device can have one or more functions. In the case of PCIe, | ||
367 | * the specification allows up to 8 PCIe endpoint functions. Invoke | ||
368 | * pci_epc_add_epf() to add a PCI endpoint function to an endpoint controller. | ||
369 | */ | ||
370 | int pci_epc_add_epf(struct pci_epc *epc, struct pci_epf *epf) | ||
371 | { | ||
372 | unsigned long flags; | ||
373 | |||
374 | if (epf->epc) | ||
375 | return -EBUSY; | ||
376 | |||
377 | if (IS_ERR(epc)) | ||
378 | return -EINVAL; | ||
379 | |||
380 | if (epf->func_no > epc->max_functions - 1) | ||
381 | return -EINVAL; | ||
382 | |||
383 | epf->epc = epc; | ||
384 | dma_set_coherent_mask(&epf->dev, epc->dev.coherent_dma_mask); | ||
385 | epf->dev.dma_mask = epc->dev.dma_mask; | ||
386 | |||
387 | spin_lock_irqsave(&epc->lock, flags); | ||
388 | list_add_tail(&epf->list, &epc->pci_epf); | ||
389 | spin_unlock_irqrestore(&epc->lock, flags); | ||
390 | |||
391 | return 0; | ||
392 | } | ||
393 | EXPORT_SYMBOL_GPL(pci_epc_add_epf); | ||
394 | |||
395 | /** | ||
396 | * pci_epc_remove_epf() - remove PCI endpoint function from endpoint controller | ||
397 | * @epc: the EPC device from which the endpoint function should be removed | ||
398 | * @epf: the endpoint function to be removed | ||
399 | * | ||
400 | * Invoke to remove PCI endpoint function from the endpoint controller. | ||
401 | */ | ||
402 | void pci_epc_remove_epf(struct pci_epc *epc, struct pci_epf *epf) | ||
403 | { | ||
404 | unsigned long flags; | ||
405 | |||
406 | if (!epc || IS_ERR(epc)) | ||
407 | return; | ||
408 | |||
409 | spin_lock_irqsave(&epc->lock, flags); | ||
410 | list_del(&epf->list); | ||
411 | spin_unlock_irqrestore(&epc->lock, flags); | ||
412 | } | ||
413 | EXPORT_SYMBOL_GPL(pci_epc_remove_epf); | ||
414 | |||
415 | /** | ||
416 | * pci_epc_linkup() - Notify the EPF device that EPC device has established a | ||
417 | * connection with the Root Complex. | ||
418 | * @epc: the EPC device which has established link with the host | ||
419 | * | ||
420 | * Invoke to Notify the EPF device that the EPC device has established a | ||
421 | * connection with the Root Complex. | ||
422 | */ | ||
423 | void pci_epc_linkup(struct pci_epc *epc) | ||
424 | { | ||
425 | unsigned long flags; | ||
426 | struct pci_epf *epf; | ||
427 | |||
428 | if (!epc || IS_ERR(epc)) | ||
429 | return; | ||
430 | |||
431 | spin_lock_irqsave(&epc->lock, flags); | ||
432 | list_for_each_entry(epf, &epc->pci_epf, list) | ||
433 | pci_epf_linkup(epf); | ||
434 | spin_unlock_irqrestore(&epc->lock, flags); | ||
435 | } | ||
436 | EXPORT_SYMBOL_GPL(pci_epc_linkup); | ||
437 | |||
438 | /** | ||
439 | * pci_epc_destroy() - destroy the EPC device | ||
440 | * @epc: the EPC device that has to be destroyed | ||
441 | * | ||
442 | * Invoke to destroy the PCI EPC device | ||
443 | */ | ||
444 | void pci_epc_destroy(struct pci_epc *epc) | ||
445 | { | ||
446 | pci_ep_cfs_remove_epc_group(epc->group); | ||
447 | device_unregister(&epc->dev); | ||
448 | kfree(epc); | ||
449 | } | ||
450 | EXPORT_SYMBOL_GPL(pci_epc_destroy); | ||
451 | |||
452 | /** | ||
453 | * devm_pci_epc_destroy() - destroy the EPC device | ||
454 | * @dev: device that wants to destroy the EPC | ||
455 | * @epc: the EPC device that has to be destroyed | ||
456 | * | ||
457 | * Invoke to destroy the devres associated with this | ||
458 | * pci_epc and destroy the EPC device. | ||
459 | */ | ||
460 | void devm_pci_epc_destroy(struct device *dev, struct pci_epc *epc) | ||
461 | { | ||
462 | int r; | ||
463 | |||
464 | r = devres_destroy(dev, devm_pci_epc_release, devm_pci_epc_match, | ||
465 | epc); | ||
466 | dev_WARN_ONCE(dev, r, "couldn't find PCI EPC resource\n"); | ||
467 | } | ||
468 | EXPORT_SYMBOL_GPL(devm_pci_epc_destroy); | ||
469 | |||
470 | /** | ||
471 | * __pci_epc_create() - create a new endpoint controller (EPC) device | ||
472 | * @dev: device that is creating the new EPC | ||
473 | * @ops: function pointers for performing EPC operations | ||
474 | * @owner: the owner of the module that creates the EPC device | ||
475 | * | ||
476 | * Invoke to create a new EPC device and add it to pci_epc class. | ||
477 | */ | ||
478 | struct pci_epc * | ||
479 | __pci_epc_create(struct device *dev, const struct pci_epc_ops *ops, | ||
480 | struct module *owner) | ||
481 | { | ||
482 | int ret; | ||
483 | struct pci_epc *epc; | ||
484 | |||
485 | if (WARN_ON(!dev)) { | ||
486 | ret = -EINVAL; | ||
487 | goto err_ret; | ||
488 | } | ||
489 | |||
490 | epc = kzalloc(sizeof(*epc), GFP_KERNEL); | ||
491 | if (!epc) { | ||
492 | ret = -ENOMEM; | ||
493 | goto err_ret; | ||
494 | } | ||
495 | |||
496 | spin_lock_init(&epc->lock); | ||
497 | INIT_LIST_HEAD(&epc->pci_epf); | ||
498 | |||
499 | device_initialize(&epc->dev); | ||
500 | dma_set_coherent_mask(&epc->dev, dev->coherent_dma_mask); | ||
501 | epc->dev.class = pci_epc_class; | ||
502 | epc->dev.dma_mask = dev->dma_mask; | ||
503 | epc->ops = ops; | ||
504 | |||
505 | ret = dev_set_name(&epc->dev, "%s", dev_name(dev)); | ||
506 | if (ret) | ||
507 | goto put_dev; | ||
508 | |||
509 | ret = device_add(&epc->dev); | ||
510 | if (ret) | ||
511 | goto put_dev; | ||
512 | |||
513 | epc->group = pci_ep_cfs_add_epc_group(dev_name(dev)); | ||
514 | |||
515 | return epc; | ||
516 | |||
517 | put_dev: | ||
518 | put_device(&epc->dev); | ||
519 | kfree(epc); | ||
520 | |||
521 | err_ret: | ||
522 | return ERR_PTR(ret); | ||
523 | } | ||
524 | EXPORT_SYMBOL_GPL(__pci_epc_create); | ||
525 | |||
526 | /** | ||
527 | * __devm_pci_epc_create() - create a new endpoint controller (EPC) device | ||
528 | * @dev: device that is creating the new EPC | ||
529 | * @ops: function pointers for performing EPC operations | ||
530 | * @owner: the owner of the module that creates the EPC device | ||
531 | * | ||
532 | * Invoke to create a new EPC device and add it to pci_epc class. | ||
533 | * While at that, it also associates the device with the pci_epc using devres. | ||
534 | * On driver detach, release function is invoked on the devres data, | ||
535 | * then, devres data is freed. | ||
536 | */ | ||
537 | struct pci_epc * | ||
538 | __devm_pci_epc_create(struct device *dev, const struct pci_epc_ops *ops, | ||
539 | struct module *owner) | ||
540 | { | ||
541 | struct pci_epc **ptr, *epc; | ||
542 | |||
543 | ptr = devres_alloc(devm_pci_epc_release, sizeof(*ptr), GFP_KERNEL); | ||
544 | if (!ptr) | ||
545 | return ERR_PTR(-ENOMEM); | ||
546 | |||
547 | epc = __pci_epc_create(dev, ops, owner); | ||
548 | if (!IS_ERR(epc)) { | ||
549 | *ptr = epc; | ||
550 | devres_add(dev, ptr); | ||
551 | } else { | ||
552 | devres_free(ptr); | ||
553 | } | ||
554 | |||
555 | return epc; | ||
556 | } | ||
557 | EXPORT_SYMBOL_GPL(__devm_pci_epc_create); | ||
558 | |||
559 | static int __init pci_epc_init(void) | ||
560 | { | ||
561 | pci_epc_class = class_create(THIS_MODULE, "pci_epc"); | ||
562 | if (IS_ERR(pci_epc_class)) { | ||
563 | pr_err("failed to create pci epc class --> %ld\n", | ||
564 | PTR_ERR(pci_epc_class)); | ||
565 | return PTR_ERR(pci_epc_class); | ||
566 | } | ||
567 | |||
568 | return 0; | ||
569 | } | ||
570 | module_init(pci_epc_init); | ||
571 | |||
572 | static void __exit pci_epc_exit(void) | ||
573 | { | ||
574 | class_destroy(pci_epc_class); | ||
575 | } | ||
576 | module_exit(pci_epc_exit); | ||
577 | |||
578 | MODULE_DESCRIPTION("PCI EPC Library"); | ||
579 | MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>"); | ||
580 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/pci/endpoint/pci-epc-mem.c b/drivers/pci/endpoint/pci-epc-mem.c new file mode 100644 index 000000000000..3a94cc1caf22 --- /dev/null +++ b/drivers/pci/endpoint/pci-epc-mem.c | |||
@@ -0,0 +1,143 @@ | |||
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"); | ||
diff --git a/drivers/pci/endpoint/pci-epf-core.c b/drivers/pci/endpoint/pci-epf-core.c new file mode 100644 index 000000000000..6877d6a5bcc9 --- /dev/null +++ b/drivers/pci/endpoint/pci-epf-core.c | |||
@@ -0,0 +1,359 @@ | |||
1 | /** | ||
2 | * PCI Endpoint *Function* (EPF) library | ||
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/device.h> | ||
21 | #include <linux/dma-mapping.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/module.h> | ||
24 | |||
25 | #include <linux/pci-epc.h> | ||
26 | #include <linux/pci-epf.h> | ||
27 | #include <linux/pci-ep-cfs.h> | ||
28 | |||
29 | static struct bus_type pci_epf_bus_type; | ||
30 | static struct device_type pci_epf_type; | ||
31 | |||
32 | /** | ||
33 | * pci_epf_linkup() - Notify the function driver that EPC device has | ||
34 | * established a connection with the Root Complex. | ||
35 | * @epf: the EPF device bound to the EPC device which has established | ||
36 | * the connection with the host | ||
37 | * | ||
38 | * Invoke to notify the function driver that EPC device has established | ||
39 | * a connection with the Root Complex. | ||
40 | */ | ||
41 | void pci_epf_linkup(struct pci_epf *epf) | ||
42 | { | ||
43 | if (!epf->driver) { | ||
44 | dev_WARN(&epf->dev, "epf device not bound to driver\n"); | ||
45 | return; | ||
46 | } | ||
47 | |||
48 | epf->driver->ops->linkup(epf); | ||
49 | } | ||
50 | EXPORT_SYMBOL_GPL(pci_epf_linkup); | ||
51 | |||
52 | /** | ||
53 | * pci_epf_unbind() - Notify the function driver that the binding between the | ||
54 | * EPF device and EPC device has been lost | ||
55 | * @epf: the EPF device which has lost the binding with the EPC device | ||
56 | * | ||
57 | * Invoke to notify the function driver that the binding between the EPF device | ||
58 | * and EPC device has been lost. | ||
59 | */ | ||
60 | void pci_epf_unbind(struct pci_epf *epf) | ||
61 | { | ||
62 | if (!epf->driver) { | ||
63 | dev_WARN(&epf->dev, "epf device not bound to driver\n"); | ||
64 | return; | ||
65 | } | ||
66 | |||
67 | epf->driver->ops->unbind(epf); | ||
68 | module_put(epf->driver->owner); | ||
69 | } | ||
70 | EXPORT_SYMBOL_GPL(pci_epf_unbind); | ||
71 | |||
72 | /** | ||
73 | * pci_epf_bind() - Notify the function driver that the EPF device has been | ||
74 | * bound to a EPC device | ||
75 | * @epf: the EPF device which has been bound to the EPC device | ||
76 | * | ||
77 | * Invoke to notify the function driver that it has been bound to a EPC device | ||
78 | */ | ||
79 | int pci_epf_bind(struct pci_epf *epf) | ||
80 | { | ||
81 | if (!epf->driver) { | ||
82 | dev_WARN(&epf->dev, "epf device not bound to driver\n"); | ||
83 | return -EINVAL; | ||
84 | } | ||
85 | |||
86 | if (!try_module_get(epf->driver->owner)) | ||
87 | return -EAGAIN; | ||
88 | |||
89 | return epf->driver->ops->bind(epf); | ||
90 | } | ||
91 | EXPORT_SYMBOL_GPL(pci_epf_bind); | ||
92 | |||
93 | /** | ||
94 | * pci_epf_free_space() - free the allocated PCI EPF register space | ||
95 | * @addr: the virtual address of the PCI EPF register space | ||
96 | * @bar: the BAR number corresponding to the register space | ||
97 | * | ||
98 | * Invoke to free the allocated PCI EPF register space. | ||
99 | */ | ||
100 | void pci_epf_free_space(struct pci_epf *epf, void *addr, enum pci_barno bar) | ||
101 | { | ||
102 | struct device *dev = &epf->dev; | ||
103 | |||
104 | if (!addr) | ||
105 | return; | ||
106 | |||
107 | dma_free_coherent(dev, epf->bar[bar].size, addr, | ||
108 | epf->bar[bar].phys_addr); | ||
109 | |||
110 | epf->bar[bar].phys_addr = 0; | ||
111 | epf->bar[bar].size = 0; | ||
112 | } | ||
113 | EXPORT_SYMBOL_GPL(pci_epf_free_space); | ||
114 | |||
115 | /** | ||
116 | * pci_epf_alloc_space() - allocate memory for the PCI EPF register space | ||
117 | * @size: the size of the memory that has to be allocated | ||
118 | * @bar: the BAR number corresponding to the allocated register space | ||
119 | * | ||
120 | * Invoke to allocate memory for the PCI EPF register space. | ||
121 | */ | ||
122 | void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar) | ||
123 | { | ||
124 | void *space; | ||
125 | struct device *dev = &epf->dev; | ||
126 | dma_addr_t phys_addr; | ||
127 | |||
128 | if (size < 128) | ||
129 | size = 128; | ||
130 | size = roundup_pow_of_two(size); | ||
131 | |||
132 | space = dma_alloc_coherent(dev, size, &phys_addr, GFP_KERNEL); | ||
133 | if (!space) { | ||
134 | dev_err(dev, "failed to allocate mem space\n"); | ||
135 | return NULL; | ||
136 | } | ||
137 | |||
138 | epf->bar[bar].phys_addr = phys_addr; | ||
139 | epf->bar[bar].size = size; | ||
140 | |||
141 | return space; | ||
142 | } | ||
143 | EXPORT_SYMBOL_GPL(pci_epf_alloc_space); | ||
144 | |||
145 | /** | ||
146 | * pci_epf_unregister_driver() - unregister the PCI EPF driver | ||
147 | * @driver: the PCI EPF driver that has to be unregistered | ||
148 | * | ||
149 | * Invoke to unregister the PCI EPF driver. | ||
150 | */ | ||
151 | void pci_epf_unregister_driver(struct pci_epf_driver *driver) | ||
152 | { | ||
153 | pci_ep_cfs_remove_epf_group(driver->group); | ||
154 | driver_unregister(&driver->driver); | ||
155 | } | ||
156 | EXPORT_SYMBOL_GPL(pci_epf_unregister_driver); | ||
157 | |||
158 | /** | ||
159 | * __pci_epf_register_driver() - register a new PCI EPF driver | ||
160 | * @driver: structure representing PCI EPF driver | ||
161 | * @owner: the owner of the module that registers the PCI EPF driver | ||
162 | * | ||
163 | * Invoke to register a new PCI EPF driver. | ||
164 | */ | ||
165 | int __pci_epf_register_driver(struct pci_epf_driver *driver, | ||
166 | struct module *owner) | ||
167 | { | ||
168 | int ret; | ||
169 | |||
170 | if (!driver->ops) | ||
171 | return -EINVAL; | ||
172 | |||
173 | if (!driver->ops->bind || !driver->ops->unbind || !driver->ops->linkup) | ||
174 | return -EINVAL; | ||
175 | |||
176 | driver->driver.bus = &pci_epf_bus_type; | ||
177 | driver->driver.owner = owner; | ||
178 | |||
179 | ret = driver_register(&driver->driver); | ||
180 | if (ret) | ||
181 | return ret; | ||
182 | |||
183 | driver->group = pci_ep_cfs_add_epf_group(driver->driver.name); | ||
184 | |||
185 | return 0; | ||
186 | } | ||
187 | EXPORT_SYMBOL_GPL(__pci_epf_register_driver); | ||
188 | |||
189 | /** | ||
190 | * pci_epf_destroy() - destroy the created PCI EPF device | ||
191 | * @epf: the PCI EPF device that has to be destroyed. | ||
192 | * | ||
193 | * Invoke to destroy the PCI EPF device created by invoking pci_epf_create(). | ||
194 | */ | ||
195 | void pci_epf_destroy(struct pci_epf *epf) | ||
196 | { | ||
197 | device_unregister(&epf->dev); | ||
198 | } | ||
199 | EXPORT_SYMBOL_GPL(pci_epf_destroy); | ||
200 | |||
201 | /** | ||
202 | * pci_epf_create() - create a new PCI EPF device | ||
203 | * @name: the name of the PCI EPF device. This name will be used to bind the | ||
204 | * the EPF device to a EPF driver | ||
205 | * | ||
206 | * Invoke to create a new PCI EPF device by providing the name of the function | ||
207 | * device. | ||
208 | */ | ||
209 | struct pci_epf *pci_epf_create(const char *name) | ||
210 | { | ||
211 | int ret; | ||
212 | struct pci_epf *epf; | ||
213 | struct device *dev; | ||
214 | char *func_name; | ||
215 | char *buf; | ||
216 | |||
217 | epf = kzalloc(sizeof(*epf), GFP_KERNEL); | ||
218 | if (!epf) { | ||
219 | ret = -ENOMEM; | ||
220 | goto err_ret; | ||
221 | } | ||
222 | |||
223 | buf = kstrdup(name, GFP_KERNEL); | ||
224 | if (!buf) { | ||
225 | ret = -ENOMEM; | ||
226 | goto free_epf; | ||
227 | } | ||
228 | |||
229 | func_name = buf; | ||
230 | buf = strchrnul(buf, '.'); | ||
231 | *buf = '\0'; | ||
232 | |||
233 | epf->name = kstrdup(func_name, GFP_KERNEL); | ||
234 | if (!epf->name) { | ||
235 | ret = -ENOMEM; | ||
236 | goto free_func_name; | ||
237 | } | ||
238 | |||
239 | dev = &epf->dev; | ||
240 | device_initialize(dev); | ||
241 | dev->bus = &pci_epf_bus_type; | ||
242 | dev->type = &pci_epf_type; | ||
243 | |||
244 | ret = dev_set_name(dev, "%s", name); | ||
245 | if (ret) | ||
246 | goto put_dev; | ||
247 | |||
248 | ret = device_add(dev); | ||
249 | if (ret) | ||
250 | goto put_dev; | ||
251 | |||
252 | kfree(func_name); | ||
253 | return epf; | ||
254 | |||
255 | put_dev: | ||
256 | put_device(dev); | ||
257 | kfree(epf->name); | ||
258 | |||
259 | free_func_name: | ||
260 | kfree(func_name); | ||
261 | |||
262 | free_epf: | ||
263 | kfree(epf); | ||
264 | |||
265 | err_ret: | ||
266 | return ERR_PTR(ret); | ||
267 | } | ||
268 | EXPORT_SYMBOL_GPL(pci_epf_create); | ||
269 | |||
270 | static void pci_epf_dev_release(struct device *dev) | ||
271 | { | ||
272 | struct pci_epf *epf = to_pci_epf(dev); | ||
273 | |||
274 | kfree(epf->name); | ||
275 | kfree(epf); | ||
276 | } | ||
277 | |||
278 | static struct device_type pci_epf_type = { | ||
279 | .release = pci_epf_dev_release, | ||
280 | }; | ||
281 | |||
282 | static int | ||
283 | pci_epf_match_id(const struct pci_epf_device_id *id, const struct pci_epf *epf) | ||
284 | { | ||
285 | while (id->name[0]) { | ||
286 | if (strcmp(epf->name, id->name) == 0) | ||
287 | return true; | ||
288 | id++; | ||
289 | } | ||
290 | |||
291 | return false; | ||
292 | } | ||
293 | |||
294 | static int pci_epf_device_match(struct device *dev, struct device_driver *drv) | ||
295 | { | ||
296 | struct pci_epf *epf = to_pci_epf(dev); | ||
297 | struct pci_epf_driver *driver = to_pci_epf_driver(drv); | ||
298 | |||
299 | if (driver->id_table) | ||
300 | return pci_epf_match_id(driver->id_table, epf); | ||
301 | |||
302 | return !strcmp(epf->name, drv->name); | ||
303 | } | ||
304 | |||
305 | static int pci_epf_device_probe(struct device *dev) | ||
306 | { | ||
307 | struct pci_epf *epf = to_pci_epf(dev); | ||
308 | struct pci_epf_driver *driver = to_pci_epf_driver(dev->driver); | ||
309 | |||
310 | if (!driver->probe) | ||
311 | return -ENODEV; | ||
312 | |||
313 | epf->driver = driver; | ||
314 | |||
315 | return driver->probe(epf); | ||
316 | } | ||
317 | |||
318 | static int pci_epf_device_remove(struct device *dev) | ||
319 | { | ||
320 | int ret; | ||
321 | struct pci_epf *epf = to_pci_epf(dev); | ||
322 | struct pci_epf_driver *driver = to_pci_epf_driver(dev->driver); | ||
323 | |||
324 | ret = driver->remove(epf); | ||
325 | epf->driver = NULL; | ||
326 | |||
327 | return ret; | ||
328 | } | ||
329 | |||
330 | static struct bus_type pci_epf_bus_type = { | ||
331 | .name = "pci-epf", | ||
332 | .match = pci_epf_device_match, | ||
333 | .probe = pci_epf_device_probe, | ||
334 | .remove = pci_epf_device_remove, | ||
335 | }; | ||
336 | |||
337 | static int __init pci_epf_init(void) | ||
338 | { | ||
339 | int ret; | ||
340 | |||
341 | ret = bus_register(&pci_epf_bus_type); | ||
342 | if (ret) { | ||
343 | pr_err("failed to register pci epf bus --> %d\n", ret); | ||
344 | return ret; | ||
345 | } | ||
346 | |||
347 | return 0; | ||
348 | } | ||
349 | module_init(pci_epf_init); | ||
350 | |||
351 | static void __exit pci_epf_exit(void) | ||
352 | { | ||
353 | bus_unregister(&pci_epf_bus_type); | ||
354 | } | ||
355 | module_exit(pci_epf_exit); | ||
356 | |||
357 | MODULE_DESCRIPTION("PCI EPF Library"); | ||
358 | MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>"); | ||
359 | MODULE_LICENSE("GPL v2"); | ||