diff options
Diffstat (limited to 'drivers/fpga')
-rw-r--r-- | drivers/fpga/Kconfig | 103 | ||||
-rw-r--r-- | drivers/fpga/Makefile | 1 | ||||
-rw-r--r-- | drivers/fpga/fpga-bridge.c | 113 | ||||
-rw-r--r-- | drivers/fpga/fpga-mgr.c | 123 | ||||
-rw-r--r-- | drivers/fpga/fpga-region.c | 464 | ||||
-rw-r--r-- | drivers/fpga/of-fpga-region.c | 504 | ||||
-rw-r--r-- | drivers/fpga/socfpga-a10.c | 8 |
7 files changed, 795 insertions, 521 deletions
diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index ad5448f718b3..f47ef848bcd0 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig | |||
@@ -11,25 +11,30 @@ menuconfig FPGA | |||
11 | 11 | ||
12 | if FPGA | 12 | if FPGA |
13 | 13 | ||
14 | config FPGA_REGION | 14 | config FPGA_MGR_SOCFPGA |
15 | tristate "FPGA Region" | 15 | tristate "Altera SOCFPGA FPGA Manager" |
16 | depends on OF && FPGA_BRIDGE | 16 | depends on ARCH_SOCFPGA || COMPILE_TEST |
17 | help | 17 | help |
18 | FPGA Regions allow loading FPGA images under control of | 18 | FPGA manager driver support for Altera SOCFPGA. |
19 | the Device Tree. | ||
20 | 19 | ||
21 | config FPGA_MGR_ICE40_SPI | 20 | config FPGA_MGR_SOCFPGA_A10 |
22 | tristate "Lattice iCE40 SPI" | 21 | tristate "Altera SoCFPGA Arria10" |
23 | depends on OF && SPI | 22 | depends on ARCH_SOCFPGA || COMPILE_TEST |
23 | select REGMAP_MMIO | ||
24 | help | 24 | help |
25 | FPGA manager driver support for Lattice iCE40 FPGAs over SPI. | 25 | FPGA manager driver support for Altera Arria10 SoCFPGA. |
26 | 26 | ||
27 | config FPGA_MGR_ALTERA_CVP | 27 | config ALTERA_PR_IP_CORE |
28 | tristate "Altera Arria-V/Cyclone-V/Stratix-V CvP FPGA Manager" | 28 | tristate "Altera Partial Reconfiguration IP Core" |
29 | depends on PCI | 29 | help |
30 | Core driver support for Altera Partial Reconfiguration IP component | ||
31 | |||
32 | config ALTERA_PR_IP_CORE_PLAT | ||
33 | tristate "Platform support of Altera Partial Reconfiguration IP Core" | ||
34 | depends on ALTERA_PR_IP_CORE && OF && HAS_IOMEM | ||
30 | help | 35 | help |
31 | FPGA manager driver support for Arria-V, Cyclone-V, Stratix-V | 36 | Platform driver support for Altera Partial Reconfiguration IP |
32 | and Arria 10 Altera FPGAs using the CvP interface over PCIe. | 37 | component |
33 | 38 | ||
34 | config FPGA_MGR_ALTERA_PS_SPI | 39 | config FPGA_MGR_ALTERA_PS_SPI |
35 | tristate "Altera FPGA Passive Serial over SPI" | 40 | tristate "Altera FPGA Passive Serial over SPI" |
@@ -38,25 +43,19 @@ config FPGA_MGR_ALTERA_PS_SPI | |||
38 | FPGA manager driver support for Altera Arria/Cyclone/Stratix | 43 | FPGA manager driver support for Altera Arria/Cyclone/Stratix |
39 | using the passive serial interface over SPI. | 44 | using the passive serial interface over SPI. |
40 | 45 | ||
41 | config FPGA_MGR_SOCFPGA | 46 | config FPGA_MGR_ALTERA_CVP |
42 | tristate "Altera SOCFPGA FPGA Manager" | 47 | tristate "Altera Arria-V/Cyclone-V/Stratix-V CvP FPGA Manager" |
43 | depends on ARCH_SOCFPGA || COMPILE_TEST | 48 | depends on PCI |
44 | help | ||
45 | FPGA manager driver support for Altera SOCFPGA. | ||
46 | |||
47 | config FPGA_MGR_SOCFPGA_A10 | ||
48 | tristate "Altera SoCFPGA Arria10" | ||
49 | depends on ARCH_SOCFPGA || COMPILE_TEST | ||
50 | select REGMAP_MMIO | ||
51 | help | 49 | help |
52 | FPGA manager driver support for Altera Arria10 SoCFPGA. | 50 | FPGA manager driver support for Arria-V, Cyclone-V, Stratix-V |
51 | and Arria 10 Altera FPGAs using the CvP interface over PCIe. | ||
53 | 52 | ||
54 | config FPGA_MGR_TS73XX | 53 | config FPGA_MGR_ZYNQ_FPGA |
55 | tristate "Technologic Systems TS-73xx SBC FPGA Manager" | 54 | tristate "Xilinx Zynq FPGA" |
56 | depends on ARCH_EP93XX && MACH_TS72XX | 55 | depends on ARCH_ZYNQ || COMPILE_TEST |
56 | depends on HAS_DMA | ||
57 | help | 57 | help |
58 | FPGA manager driver support for the Altera Cyclone II FPGA | 58 | FPGA manager driver support for Xilinx Zynq FPGAs. |
59 | present on the TS-73xx SBC boards. | ||
60 | 59 | ||
61 | config FPGA_MGR_XILINX_SPI | 60 | config FPGA_MGR_XILINX_SPI |
62 | tristate "Xilinx Configuration over Slave Serial (SPI)" | 61 | tristate "Xilinx Configuration over Slave Serial (SPI)" |
@@ -65,16 +64,21 @@ config FPGA_MGR_XILINX_SPI | |||
65 | FPGA manager driver support for Xilinx FPGA configuration | 64 | FPGA manager driver support for Xilinx FPGA configuration |
66 | over slave serial interface. | 65 | over slave serial interface. |
67 | 66 | ||
68 | config FPGA_MGR_ZYNQ_FPGA | 67 | config FPGA_MGR_ICE40_SPI |
69 | tristate "Xilinx Zynq FPGA" | 68 | tristate "Lattice iCE40 SPI" |
70 | depends on ARCH_ZYNQ || COMPILE_TEST | 69 | depends on OF && SPI |
71 | depends on HAS_DMA | ||
72 | help | 70 | help |
73 | FPGA manager driver support for Xilinx Zynq FPGAs. | 71 | FPGA manager driver support for Lattice iCE40 FPGAs over SPI. |
72 | |||
73 | config FPGA_MGR_TS73XX | ||
74 | tristate "Technologic Systems TS-73xx SBC FPGA Manager" | ||
75 | depends on ARCH_EP93XX && MACH_TS72XX | ||
76 | help | ||
77 | FPGA manager driver support for the Altera Cyclone II FPGA | ||
78 | present on the TS-73xx SBC boards. | ||
74 | 79 | ||
75 | config FPGA_BRIDGE | 80 | config FPGA_BRIDGE |
76 | tristate "FPGA Bridge Framework" | 81 | tristate "FPGA Bridge Framework" |
77 | depends on OF | ||
78 | help | 82 | help |
79 | Say Y here if you want to support bridges connected between host | 83 | Say Y here if you want to support bridges connected between host |
80 | processors and FPGAs or between FPGAs. | 84 | processors and FPGAs or between FPGAs. |
@@ -95,18 +99,6 @@ config ALTERA_FREEZE_BRIDGE | |||
95 | isolate one region of the FPGA from the busses while that | 99 | isolate one region of the FPGA from the busses while that |
96 | region is being reprogrammed. | 100 | region is being reprogrammed. |
97 | 101 | ||
98 | config ALTERA_PR_IP_CORE | ||
99 | tristate "Altera Partial Reconfiguration IP Core" | ||
100 | help | ||
101 | Core driver support for Altera Partial Reconfiguration IP component | ||
102 | |||
103 | config ALTERA_PR_IP_CORE_PLAT | ||
104 | tristate "Platform support of Altera Partial Reconfiguration IP Core" | ||
105 | depends on ALTERA_PR_IP_CORE && OF && HAS_IOMEM | ||
106 | help | ||
107 | Platform driver support for Altera Partial Reconfiguration IP | ||
108 | component | ||
109 | |||
110 | config XILINX_PR_DECOUPLER | 102 | config XILINX_PR_DECOUPLER |
111 | tristate "Xilinx LogiCORE PR Decoupler" | 103 | tristate "Xilinx LogiCORE PR Decoupler" |
112 | depends on FPGA_BRIDGE | 104 | depends on FPGA_BRIDGE |
@@ -117,4 +109,19 @@ config XILINX_PR_DECOUPLER | |||
117 | region of the FPGA from the busses while that region is | 109 | region of the FPGA from the busses while that region is |
118 | being reprogrammed during partial reconfig. | 110 | being reprogrammed during partial reconfig. |
119 | 111 | ||
112 | config FPGA_REGION | ||
113 | tristate "FPGA Region" | ||
114 | depends on FPGA_BRIDGE | ||
115 | help | ||
116 | FPGA Region common code. A FPGA Region controls a FPGA Manager | ||
117 | and the FPGA Bridges associated with either a reconfigurable | ||
118 | region of an FPGA or a whole FPGA. | ||
119 | |||
120 | config OF_FPGA_REGION | ||
121 | tristate "FPGA Region Device Tree Overlay Support" | ||
122 | depends on OF && FPGA_REGION | ||
123 | help | ||
124 | Support for loading FPGA images by applying a Device Tree | ||
125 | overlay. | ||
126 | |||
120 | endif # FPGA | 127 | endif # FPGA |
diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile index f98dcf1d89e1..3cb276a0f88d 100644 --- a/drivers/fpga/Makefile +++ b/drivers/fpga/Makefile | |||
@@ -26,3 +26,4 @@ obj-$(CONFIG_XILINX_PR_DECOUPLER) += xilinx-pr-decoupler.o | |||
26 | 26 | ||
27 | # High Level Interfaces | 27 | # High Level Interfaces |
28 | obj-$(CONFIG_FPGA_REGION) += fpga-region.o | 28 | obj-$(CONFIG_FPGA_REGION) += fpga-region.o |
29 | obj-$(CONFIG_OF_FPGA_REGION) += of-fpga-region.o | ||
diff --git a/drivers/fpga/fpga-bridge.c b/drivers/fpga/fpga-bridge.c index 9651aa56244a..31bd2c59c305 100644 --- a/drivers/fpga/fpga-bridge.c +++ b/drivers/fpga/fpga-bridge.c | |||
@@ -2,6 +2,7 @@ | |||
2 | * FPGA Bridge Framework Driver | 2 | * FPGA Bridge Framework Driver |
3 | * | 3 | * |
4 | * Copyright (C) 2013-2016 Altera Corporation, All Rights Reserved. | 4 | * Copyright (C) 2013-2016 Altera Corporation, All Rights Reserved. |
5 | * Copyright (C) 2017 Intel Corporation | ||
5 | * | 6 | * |
6 | * This program is free software; you can redistribute it and/or modify it | 7 | * This program is free software; you can redistribute it and/or modify it |
7 | * under the terms and conditions of the GNU General Public License, | 8 | * under the terms and conditions of the GNU General Public License, |
@@ -70,32 +71,13 @@ int fpga_bridge_disable(struct fpga_bridge *bridge) | |||
70 | } | 71 | } |
71 | EXPORT_SYMBOL_GPL(fpga_bridge_disable); | 72 | EXPORT_SYMBOL_GPL(fpga_bridge_disable); |
72 | 73 | ||
73 | /** | 74 | static struct fpga_bridge *__fpga_bridge_get(struct device *dev, |
74 | * of_fpga_bridge_get - get an exclusive reference to a fpga bridge | 75 | struct fpga_image_info *info) |
75 | * | ||
76 | * @np: node pointer of a FPGA bridge | ||
77 | * @info: fpga image specific information | ||
78 | * | ||
79 | * Return fpga_bridge struct if successful. | ||
80 | * Return -EBUSY if someone already has a reference to the bridge. | ||
81 | * Return -ENODEV if @np is not a FPGA Bridge. | ||
82 | */ | ||
83 | struct fpga_bridge *of_fpga_bridge_get(struct device_node *np, | ||
84 | struct fpga_image_info *info) | ||
85 | |||
86 | { | 76 | { |
87 | struct device *dev; | ||
88 | struct fpga_bridge *bridge; | 77 | struct fpga_bridge *bridge; |
89 | int ret = -ENODEV; | 78 | int ret = -ENODEV; |
90 | 79 | ||
91 | dev = class_find_device(fpga_bridge_class, NULL, np, | ||
92 | fpga_bridge_of_node_match); | ||
93 | if (!dev) | ||
94 | goto err_dev; | ||
95 | |||
96 | bridge = to_fpga_bridge(dev); | 80 | bridge = to_fpga_bridge(dev); |
97 | if (!bridge) | ||
98 | goto err_dev; | ||
99 | 81 | ||
100 | bridge->info = info; | 82 | bridge->info = info; |
101 | 83 | ||
@@ -117,8 +99,58 @@ err_dev: | |||
117 | put_device(dev); | 99 | put_device(dev); |
118 | return ERR_PTR(ret); | 100 | return ERR_PTR(ret); |
119 | } | 101 | } |
102 | |||
103 | /** | ||
104 | * of_fpga_bridge_get - get an exclusive reference to a fpga bridge | ||
105 | * | ||
106 | * @np: node pointer of a FPGA bridge | ||
107 | * @info: fpga image specific information | ||
108 | * | ||
109 | * Return fpga_bridge struct if successful. | ||
110 | * Return -EBUSY if someone already has a reference to the bridge. | ||
111 | * Return -ENODEV if @np is not a FPGA Bridge. | ||
112 | */ | ||
113 | struct fpga_bridge *of_fpga_bridge_get(struct device_node *np, | ||
114 | struct fpga_image_info *info) | ||
115 | { | ||
116 | struct device *dev; | ||
117 | |||
118 | dev = class_find_device(fpga_bridge_class, NULL, np, | ||
119 | fpga_bridge_of_node_match); | ||
120 | if (!dev) | ||
121 | return ERR_PTR(-ENODEV); | ||
122 | |||
123 | return __fpga_bridge_get(dev, info); | ||
124 | } | ||
120 | EXPORT_SYMBOL_GPL(of_fpga_bridge_get); | 125 | EXPORT_SYMBOL_GPL(of_fpga_bridge_get); |
121 | 126 | ||
127 | static int fpga_bridge_dev_match(struct device *dev, const void *data) | ||
128 | { | ||
129 | return dev->parent == data; | ||
130 | } | ||
131 | |||
132 | /** | ||
133 | * fpga_bridge_get - get an exclusive reference to a fpga bridge | ||
134 | * @dev: parent device that fpga bridge was registered with | ||
135 | * | ||
136 | * Given a device, get an exclusive reference to a fpga bridge. | ||
137 | * | ||
138 | * Return: fpga manager struct or IS_ERR() condition containing error code. | ||
139 | */ | ||
140 | struct fpga_bridge *fpga_bridge_get(struct device *dev, | ||
141 | struct fpga_image_info *info) | ||
142 | { | ||
143 | struct device *bridge_dev; | ||
144 | |||
145 | bridge_dev = class_find_device(fpga_bridge_class, NULL, dev, | ||
146 | fpga_bridge_dev_match); | ||
147 | if (!bridge_dev) | ||
148 | return ERR_PTR(-ENODEV); | ||
149 | |||
150 | return __fpga_bridge_get(bridge_dev, info); | ||
151 | } | ||
152 | EXPORT_SYMBOL_GPL(fpga_bridge_get); | ||
153 | |||
122 | /** | 154 | /** |
123 | * fpga_bridge_put - release a reference to a bridge | 155 | * fpga_bridge_put - release a reference to a bridge |
124 | * | 156 | * |
@@ -206,7 +238,7 @@ void fpga_bridges_put(struct list_head *bridge_list) | |||
206 | EXPORT_SYMBOL_GPL(fpga_bridges_put); | 238 | EXPORT_SYMBOL_GPL(fpga_bridges_put); |
207 | 239 | ||
208 | /** | 240 | /** |
209 | * fpga_bridges_get_to_list - get a bridge, add it to a list | 241 | * of_fpga_bridge_get_to_list - get a bridge, add it to a list |
210 | * | 242 | * |
211 | * @np: node pointer of a FPGA bridge | 243 | * @np: node pointer of a FPGA bridge |
212 | * @info: fpga image specific information | 244 | * @info: fpga image specific information |
@@ -216,14 +248,44 @@ EXPORT_SYMBOL_GPL(fpga_bridges_put); | |||
216 | * | 248 | * |
217 | * Return 0 for success, error code from of_fpga_bridge_get() othewise. | 249 | * Return 0 for success, error code from of_fpga_bridge_get() othewise. |
218 | */ | 250 | */ |
219 | int fpga_bridge_get_to_list(struct device_node *np, | 251 | int of_fpga_bridge_get_to_list(struct device_node *np, |
252 | struct fpga_image_info *info, | ||
253 | struct list_head *bridge_list) | ||
254 | { | ||
255 | struct fpga_bridge *bridge; | ||
256 | unsigned long flags; | ||
257 | |||
258 | bridge = of_fpga_bridge_get(np, info); | ||
259 | if (IS_ERR(bridge)) | ||
260 | return PTR_ERR(bridge); | ||
261 | |||
262 | spin_lock_irqsave(&bridge_list_lock, flags); | ||
263 | list_add(&bridge->node, bridge_list); | ||
264 | spin_unlock_irqrestore(&bridge_list_lock, flags); | ||
265 | |||
266 | return 0; | ||
267 | } | ||
268 | EXPORT_SYMBOL_GPL(of_fpga_bridge_get_to_list); | ||
269 | |||
270 | /** | ||
271 | * fpga_bridge_get_to_list - given device, get a bridge, add it to a list | ||
272 | * | ||
273 | * @dev: FPGA bridge device | ||
274 | * @info: fpga image specific information | ||
275 | * @bridge_list: list of FPGA bridges | ||
276 | * | ||
277 | * Get an exclusive reference to the bridge and and it to the list. | ||
278 | * | ||
279 | * Return 0 for success, error code from fpga_bridge_get() othewise. | ||
280 | */ | ||
281 | int fpga_bridge_get_to_list(struct device *dev, | ||
220 | struct fpga_image_info *info, | 282 | struct fpga_image_info *info, |
221 | struct list_head *bridge_list) | 283 | struct list_head *bridge_list) |
222 | { | 284 | { |
223 | struct fpga_bridge *bridge; | 285 | struct fpga_bridge *bridge; |
224 | unsigned long flags; | 286 | unsigned long flags; |
225 | 287 | ||
226 | bridge = of_fpga_bridge_get(np, info); | 288 | bridge = fpga_bridge_get(dev, info); |
227 | if (IS_ERR(bridge)) | 289 | if (IS_ERR(bridge)) |
228 | return PTR_ERR(bridge); | 290 | return PTR_ERR(bridge); |
229 | 291 | ||
@@ -303,6 +365,7 @@ int fpga_bridge_register(struct device *dev, const char *name, | |||
303 | bridge->priv = priv; | 365 | bridge->priv = priv; |
304 | 366 | ||
305 | device_initialize(&bridge->dev); | 367 | device_initialize(&bridge->dev); |
368 | bridge->dev.groups = br_ops->groups; | ||
306 | bridge->dev.class = fpga_bridge_class; | 369 | bridge->dev.class = fpga_bridge_class; |
307 | bridge->dev.parent = dev; | 370 | bridge->dev.parent = dev; |
308 | bridge->dev.of_node = dev->of_node; | 371 | bridge->dev.of_node = dev->of_node; |
@@ -381,7 +444,7 @@ static void __exit fpga_bridge_dev_exit(void) | |||
381 | } | 444 | } |
382 | 445 | ||
383 | MODULE_DESCRIPTION("FPGA Bridge Driver"); | 446 | MODULE_DESCRIPTION("FPGA Bridge Driver"); |
384 | MODULE_AUTHOR("Alan Tull <atull@opensource.altera.com>"); | 447 | MODULE_AUTHOR("Alan Tull <atull@kernel.org>"); |
385 | MODULE_LICENSE("GPL v2"); | 448 | MODULE_LICENSE("GPL v2"); |
386 | 449 | ||
387 | subsys_initcall(fpga_bridge_dev_init); | 450 | subsys_initcall(fpga_bridge_dev_init); |
diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c index 188ffefa3cc3..9939d2cbc9a6 100644 --- a/drivers/fpga/fpga-mgr.c +++ b/drivers/fpga/fpga-mgr.c | |||
@@ -2,6 +2,7 @@ | |||
2 | * FPGA Manager Core | 2 | * FPGA Manager Core |
3 | * | 3 | * |
4 | * Copyright (C) 2013-2015 Altera Corporation | 4 | * Copyright (C) 2013-2015 Altera Corporation |
5 | * Copyright (C) 2017 Intel Corporation | ||
5 | * | 6 | * |
6 | * With code from the mailing list: | 7 | * With code from the mailing list: |
7 | * Copyright (C) 2013 Xilinx, Inc. | 8 | * Copyright (C) 2013 Xilinx, Inc. |
@@ -31,6 +32,40 @@ | |||
31 | static DEFINE_IDA(fpga_mgr_ida); | 32 | static DEFINE_IDA(fpga_mgr_ida); |
32 | static struct class *fpga_mgr_class; | 33 | static struct class *fpga_mgr_class; |
33 | 34 | ||
35 | struct fpga_image_info *fpga_image_info_alloc(struct device *dev) | ||
36 | { | ||
37 | struct fpga_image_info *info; | ||
38 | |||
39 | get_device(dev); | ||
40 | |||
41 | info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); | ||
42 | if (!info) { | ||
43 | put_device(dev); | ||
44 | return NULL; | ||
45 | } | ||
46 | |||
47 | info->dev = dev; | ||
48 | |||
49 | return info; | ||
50 | } | ||
51 | EXPORT_SYMBOL_GPL(fpga_image_info_alloc); | ||
52 | |||
53 | void fpga_image_info_free(struct fpga_image_info *info) | ||
54 | { | ||
55 | struct device *dev; | ||
56 | |||
57 | if (!info) | ||
58 | return; | ||
59 | |||
60 | dev = info->dev; | ||
61 | if (info->firmware_name) | ||
62 | devm_kfree(dev, info->firmware_name); | ||
63 | |||
64 | devm_kfree(dev, info); | ||
65 | put_device(dev); | ||
66 | } | ||
67 | EXPORT_SYMBOL_GPL(fpga_image_info_free); | ||
68 | |||
34 | /* | 69 | /* |
35 | * Call the low level driver's write_init function. This will do the | 70 | * Call the low level driver's write_init function. This will do the |
36 | * device-specific things to get the FPGA into the state where it is ready to | 71 | * device-specific things to get the FPGA into the state where it is ready to |
@@ -137,8 +172,9 @@ static int fpga_mgr_write_complete(struct fpga_manager *mgr, | |||
137 | * | 172 | * |
138 | * Return: 0 on success, negative error code otherwise. | 173 | * Return: 0 on success, negative error code otherwise. |
139 | */ | 174 | */ |
140 | int fpga_mgr_buf_load_sg(struct fpga_manager *mgr, struct fpga_image_info *info, | 175 | static int fpga_mgr_buf_load_sg(struct fpga_manager *mgr, |
141 | struct sg_table *sgt) | 176 | struct fpga_image_info *info, |
177 | struct sg_table *sgt) | ||
142 | { | 178 | { |
143 | int ret; | 179 | int ret; |
144 | 180 | ||
@@ -170,7 +206,6 @@ int fpga_mgr_buf_load_sg(struct fpga_manager *mgr, struct fpga_image_info *info, | |||
170 | 206 | ||
171 | return fpga_mgr_write_complete(mgr, info); | 207 | return fpga_mgr_write_complete(mgr, info); |
172 | } | 208 | } |
173 | EXPORT_SYMBOL_GPL(fpga_mgr_buf_load_sg); | ||
174 | 209 | ||
175 | static int fpga_mgr_buf_load_mapped(struct fpga_manager *mgr, | 210 | static int fpga_mgr_buf_load_mapped(struct fpga_manager *mgr, |
176 | struct fpga_image_info *info, | 211 | struct fpga_image_info *info, |
@@ -210,8 +245,9 @@ static int fpga_mgr_buf_load_mapped(struct fpga_manager *mgr, | |||
210 | * | 245 | * |
211 | * Return: 0 on success, negative error code otherwise. | 246 | * Return: 0 on success, negative error code otherwise. |
212 | */ | 247 | */ |
213 | int fpga_mgr_buf_load(struct fpga_manager *mgr, struct fpga_image_info *info, | 248 | static int fpga_mgr_buf_load(struct fpga_manager *mgr, |
214 | const char *buf, size_t count) | 249 | struct fpga_image_info *info, |
250 | const char *buf, size_t count) | ||
215 | { | 251 | { |
216 | struct page **pages; | 252 | struct page **pages; |
217 | struct sg_table sgt; | 253 | struct sg_table sgt; |
@@ -266,7 +302,6 @@ int fpga_mgr_buf_load(struct fpga_manager *mgr, struct fpga_image_info *info, | |||
266 | 302 | ||
267 | return rc; | 303 | return rc; |
268 | } | 304 | } |
269 | EXPORT_SYMBOL_GPL(fpga_mgr_buf_load); | ||
270 | 305 | ||
271 | /** | 306 | /** |
272 | * fpga_mgr_firmware_load - request firmware and load to fpga | 307 | * fpga_mgr_firmware_load - request firmware and load to fpga |
@@ -282,9 +317,9 @@ EXPORT_SYMBOL_GPL(fpga_mgr_buf_load); | |||
282 | * | 317 | * |
283 | * Return: 0 on success, negative error code otherwise. | 318 | * Return: 0 on success, negative error code otherwise. |
284 | */ | 319 | */ |
285 | int fpga_mgr_firmware_load(struct fpga_manager *mgr, | 320 | static int fpga_mgr_firmware_load(struct fpga_manager *mgr, |
286 | struct fpga_image_info *info, | 321 | struct fpga_image_info *info, |
287 | const char *image_name) | 322 | const char *image_name) |
288 | { | 323 | { |
289 | struct device *dev = &mgr->dev; | 324 | struct device *dev = &mgr->dev; |
290 | const struct firmware *fw; | 325 | const struct firmware *fw; |
@@ -307,7 +342,18 @@ int fpga_mgr_firmware_load(struct fpga_manager *mgr, | |||
307 | 342 | ||
308 | return ret; | 343 | return ret; |
309 | } | 344 | } |
310 | EXPORT_SYMBOL_GPL(fpga_mgr_firmware_load); | 345 | |
346 | int fpga_mgr_load(struct fpga_manager *mgr, struct fpga_image_info *info) | ||
347 | { | ||
348 | if (info->sgt) | ||
349 | return fpga_mgr_buf_load_sg(mgr, info, info->sgt); | ||
350 | if (info->buf && info->count) | ||
351 | return fpga_mgr_buf_load(mgr, info, info->buf, info->count); | ||
352 | if (info->firmware_name) | ||
353 | return fpga_mgr_firmware_load(mgr, info, info->firmware_name); | ||
354 | return -EINVAL; | ||
355 | } | ||
356 | EXPORT_SYMBOL_GPL(fpga_mgr_load); | ||
311 | 357 | ||
312 | static const char * const state_str[] = { | 358 | static const char * const state_str[] = { |
313 | [FPGA_MGR_STATE_UNKNOWN] = "unknown", | 359 | [FPGA_MGR_STATE_UNKNOWN] = "unknown", |
@@ -364,28 +410,17 @@ ATTRIBUTE_GROUPS(fpga_mgr); | |||
364 | static struct fpga_manager *__fpga_mgr_get(struct device *dev) | 410 | static struct fpga_manager *__fpga_mgr_get(struct device *dev) |
365 | { | 411 | { |
366 | struct fpga_manager *mgr; | 412 | struct fpga_manager *mgr; |
367 | int ret = -ENODEV; | ||
368 | 413 | ||
369 | mgr = to_fpga_manager(dev); | 414 | mgr = to_fpga_manager(dev); |
370 | if (!mgr) | ||
371 | goto err_dev; | ||
372 | |||
373 | /* Get exclusive use of fpga manager */ | ||
374 | if (!mutex_trylock(&mgr->ref_mutex)) { | ||
375 | ret = -EBUSY; | ||
376 | goto err_dev; | ||
377 | } | ||
378 | 415 | ||
379 | if (!try_module_get(dev->parent->driver->owner)) | 416 | if (!try_module_get(dev->parent->driver->owner)) |
380 | goto err_ll_mod; | 417 | goto err_dev; |
381 | 418 | ||
382 | return mgr; | 419 | return mgr; |
383 | 420 | ||
384 | err_ll_mod: | ||
385 | mutex_unlock(&mgr->ref_mutex); | ||
386 | err_dev: | 421 | err_dev: |
387 | put_device(dev); | 422 | put_device(dev); |
388 | return ERR_PTR(ret); | 423 | return ERR_PTR(-ENODEV); |
389 | } | 424 | } |
390 | 425 | ||
391 | static int fpga_mgr_dev_match(struct device *dev, const void *data) | 426 | static int fpga_mgr_dev_match(struct device *dev, const void *data) |
@@ -394,10 +429,10 @@ static int fpga_mgr_dev_match(struct device *dev, const void *data) | |||
394 | } | 429 | } |
395 | 430 | ||
396 | /** | 431 | /** |
397 | * fpga_mgr_get - get an exclusive reference to a fpga mgr | 432 | * fpga_mgr_get - get a reference to a fpga mgr |
398 | * @dev: parent device that fpga mgr was registered with | 433 | * @dev: parent device that fpga mgr was registered with |
399 | * | 434 | * |
400 | * Given a device, get an exclusive reference to a fpga mgr. | 435 | * Given a device, get a reference to a fpga mgr. |
401 | * | 436 | * |
402 | * Return: fpga manager struct or IS_ERR() condition containing error code. | 437 | * Return: fpga manager struct or IS_ERR() condition containing error code. |
403 | */ | 438 | */ |
@@ -418,10 +453,10 @@ static int fpga_mgr_of_node_match(struct device *dev, const void *data) | |||
418 | } | 453 | } |
419 | 454 | ||
420 | /** | 455 | /** |
421 | * of_fpga_mgr_get - get an exclusive reference to a fpga mgr | 456 | * of_fpga_mgr_get - get a reference to a fpga mgr |
422 | * @node: device node | 457 | * @node: device node |
423 | * | 458 | * |
424 | * Given a device node, get an exclusive reference to a fpga mgr. | 459 | * Given a device node, get a reference to a fpga mgr. |
425 | * | 460 | * |
426 | * Return: fpga manager struct or IS_ERR() condition containing error code. | 461 | * Return: fpga manager struct or IS_ERR() condition containing error code. |
427 | */ | 462 | */ |
@@ -445,12 +480,41 @@ EXPORT_SYMBOL_GPL(of_fpga_mgr_get); | |||
445 | void fpga_mgr_put(struct fpga_manager *mgr) | 480 | void fpga_mgr_put(struct fpga_manager *mgr) |
446 | { | 481 | { |
447 | module_put(mgr->dev.parent->driver->owner); | 482 | module_put(mgr->dev.parent->driver->owner); |
448 | mutex_unlock(&mgr->ref_mutex); | ||
449 | put_device(&mgr->dev); | 483 | put_device(&mgr->dev); |
450 | } | 484 | } |
451 | EXPORT_SYMBOL_GPL(fpga_mgr_put); | 485 | EXPORT_SYMBOL_GPL(fpga_mgr_put); |
452 | 486 | ||
453 | /** | 487 | /** |
488 | * fpga_mgr_lock - Lock FPGA manager for exclusive use | ||
489 | * @mgr: fpga manager | ||
490 | * | ||
491 | * Given a pointer to FPGA Manager (from fpga_mgr_get() or | ||
492 | * of_fpga_mgr_put()) attempt to get the mutex. | ||
493 | * | ||
494 | * Return: 0 for success or -EBUSY | ||
495 | */ | ||
496 | int fpga_mgr_lock(struct fpga_manager *mgr) | ||
497 | { | ||
498 | if (!mutex_trylock(&mgr->ref_mutex)) { | ||
499 | dev_err(&mgr->dev, "FPGA manager is in use.\n"); | ||
500 | return -EBUSY; | ||
501 | } | ||
502 | |||
503 | return 0; | ||
504 | } | ||
505 | EXPORT_SYMBOL_GPL(fpga_mgr_lock); | ||
506 | |||
507 | /** | ||
508 | * fpga_mgr_unlock - Unlock FPGA manager | ||
509 | * @mgr: fpga manager | ||
510 | */ | ||
511 | void fpga_mgr_unlock(struct fpga_manager *mgr) | ||
512 | { | ||
513 | mutex_unlock(&mgr->ref_mutex); | ||
514 | } | ||
515 | EXPORT_SYMBOL_GPL(fpga_mgr_unlock); | ||
516 | |||
517 | /** | ||
454 | * fpga_mgr_register - register a low level fpga manager driver | 518 | * fpga_mgr_register - register a low level fpga manager driver |
455 | * @dev: fpga manager device from pdev | 519 | * @dev: fpga manager device from pdev |
456 | * @name: fpga manager name | 520 | * @name: fpga manager name |
@@ -503,6 +567,7 @@ int fpga_mgr_register(struct device *dev, const char *name, | |||
503 | 567 | ||
504 | device_initialize(&mgr->dev); | 568 | device_initialize(&mgr->dev); |
505 | mgr->dev.class = fpga_mgr_class; | 569 | mgr->dev.class = fpga_mgr_class; |
570 | mgr->dev.groups = mops->groups; | ||
506 | mgr->dev.parent = dev; | 571 | mgr->dev.parent = dev; |
507 | mgr->dev.of_node = dev->of_node; | 572 | mgr->dev.of_node = dev->of_node; |
508 | mgr->dev.id = id; | 573 | mgr->dev.id = id; |
@@ -578,7 +643,7 @@ static void __exit fpga_mgr_class_exit(void) | |||
578 | ida_destroy(&fpga_mgr_ida); | 643 | ida_destroy(&fpga_mgr_ida); |
579 | } | 644 | } |
580 | 645 | ||
581 | MODULE_AUTHOR("Alan Tull <atull@opensource.altera.com>"); | 646 | MODULE_AUTHOR("Alan Tull <atull@kernel.org>"); |
582 | MODULE_DESCRIPTION("FPGA manager framework"); | 647 | MODULE_DESCRIPTION("FPGA manager framework"); |
583 | MODULE_LICENSE("GPL v2"); | 648 | MODULE_LICENSE("GPL v2"); |
584 | 649 | ||
diff --git a/drivers/fpga/fpga-region.c b/drivers/fpga/fpga-region.c index d9ab7c75b14f..edab2a2e03ef 100644 --- a/drivers/fpga/fpga-region.c +++ b/drivers/fpga/fpga-region.c | |||
@@ -2,6 +2,7 @@ | |||
2 | * FPGA Region - Device Tree support for FPGA programming under Linux | 2 | * FPGA Region - Device Tree support for FPGA programming under Linux |
3 | * | 3 | * |
4 | * Copyright (C) 2013-2016 Altera Corporation | 4 | * Copyright (C) 2013-2016 Altera Corporation |
5 | * Copyright (C) 2017 Intel Corporation | ||
5 | * | 6 | * |
6 | * This program is free software; you can redistribute it and/or modify it | 7 | * This program is free software; you can redistribute it and/or modify it |
7 | * under the terms and conditions of the GNU General Public License, | 8 | * under the terms and conditions of the GNU General Public License, |
@@ -18,61 +19,30 @@ | |||
18 | 19 | ||
19 | #include <linux/fpga/fpga-bridge.h> | 20 | #include <linux/fpga/fpga-bridge.h> |
20 | #include <linux/fpga/fpga-mgr.h> | 21 | #include <linux/fpga/fpga-mgr.h> |
22 | #include <linux/fpga/fpga-region.h> | ||
21 | #include <linux/idr.h> | 23 | #include <linux/idr.h> |
22 | #include <linux/kernel.h> | 24 | #include <linux/kernel.h> |
23 | #include <linux/list.h> | 25 | #include <linux/list.h> |
24 | #include <linux/module.h> | 26 | #include <linux/module.h> |
25 | #include <linux/of_platform.h> | ||
26 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
27 | #include <linux/spinlock.h> | 28 | #include <linux/spinlock.h> |
28 | 29 | ||
29 | /** | ||
30 | * struct fpga_region - FPGA Region structure | ||
31 | * @dev: FPGA Region device | ||
32 | * @mutex: enforces exclusive reference to region | ||
33 | * @bridge_list: list of FPGA bridges specified in region | ||
34 | * @info: fpga image specific information | ||
35 | */ | ||
36 | struct fpga_region { | ||
37 | struct device dev; | ||
38 | struct mutex mutex; /* for exclusive reference to region */ | ||
39 | struct list_head bridge_list; | ||
40 | struct fpga_image_info *info; | ||
41 | }; | ||
42 | |||
43 | #define to_fpga_region(d) container_of(d, struct fpga_region, dev) | ||
44 | |||
45 | static DEFINE_IDA(fpga_region_ida); | 30 | static DEFINE_IDA(fpga_region_ida); |
46 | static struct class *fpga_region_class; | 31 | static struct class *fpga_region_class; |
47 | 32 | ||
48 | static const struct of_device_id fpga_region_of_match[] = { | 33 | struct fpga_region *fpga_region_class_find( |
49 | { .compatible = "fpga-region", }, | 34 | struct device *start, const void *data, |
50 | {}, | 35 | int (*match)(struct device *, const void *)) |
51 | }; | ||
52 | MODULE_DEVICE_TABLE(of, fpga_region_of_match); | ||
53 | |||
54 | static int fpga_region_of_node_match(struct device *dev, const void *data) | ||
55 | { | ||
56 | return dev->of_node == data; | ||
57 | } | ||
58 | |||
59 | /** | ||
60 | * fpga_region_find - find FPGA region | ||
61 | * @np: device node of FPGA Region | ||
62 | * Caller will need to put_device(®ion->dev) when done. | ||
63 | * Returns FPGA Region struct or NULL | ||
64 | */ | ||
65 | static struct fpga_region *fpga_region_find(struct device_node *np) | ||
66 | { | 36 | { |
67 | struct device *dev; | 37 | struct device *dev; |
68 | 38 | ||
69 | dev = class_find_device(fpga_region_class, NULL, np, | 39 | dev = class_find_device(fpga_region_class, start, data, match); |
70 | fpga_region_of_node_match); | ||
71 | if (!dev) | 40 | if (!dev) |
72 | return NULL; | 41 | return NULL; |
73 | 42 | ||
74 | return to_fpga_region(dev); | 43 | return to_fpga_region(dev); |
75 | } | 44 | } |
45 | EXPORT_SYMBOL_GPL(fpga_region_class_find); | ||
76 | 46 | ||
77 | /** | 47 | /** |
78 | * fpga_region_get - get an exclusive reference to a fpga region | 48 | * fpga_region_get - get an exclusive reference to a fpga region |
@@ -94,15 +64,13 @@ static struct fpga_region *fpga_region_get(struct fpga_region *region) | |||
94 | } | 64 | } |
95 | 65 | ||
96 | get_device(dev); | 66 | get_device(dev); |
97 | of_node_get(dev->of_node); | ||
98 | if (!try_module_get(dev->parent->driver->owner)) { | 67 | if (!try_module_get(dev->parent->driver->owner)) { |
99 | of_node_put(dev->of_node); | ||
100 | put_device(dev); | 68 | put_device(dev); |
101 | mutex_unlock(®ion->mutex); | 69 | mutex_unlock(®ion->mutex); |
102 | return ERR_PTR(-ENODEV); | 70 | return ERR_PTR(-ENODEV); |
103 | } | 71 | } |
104 | 72 | ||
105 | dev_dbg(®ion->dev, "get\n"); | 73 | dev_dbg(dev, "get\n"); |
106 | 74 | ||
107 | return region; | 75 | return region; |
108 | } | 76 | } |
@@ -116,403 +84,99 @@ static void fpga_region_put(struct fpga_region *region) | |||
116 | { | 84 | { |
117 | struct device *dev = ®ion->dev; | 85 | struct device *dev = ®ion->dev; |
118 | 86 | ||
119 | dev_dbg(®ion->dev, "put\n"); | 87 | dev_dbg(dev, "put\n"); |
120 | 88 | ||
121 | module_put(dev->parent->driver->owner); | 89 | module_put(dev->parent->driver->owner); |
122 | of_node_put(dev->of_node); | ||
123 | put_device(dev); | 90 | put_device(dev); |
124 | mutex_unlock(®ion->mutex); | 91 | mutex_unlock(®ion->mutex); |
125 | } | 92 | } |
126 | 93 | ||
127 | /** | 94 | /** |
128 | * fpga_region_get_manager - get exclusive reference for FPGA manager | ||
129 | * @region: FPGA region | ||
130 | * | ||
131 | * Get FPGA Manager from "fpga-mgr" property or from ancestor region. | ||
132 | * | ||
133 | * Caller should call fpga_mgr_put() when done with manager. | ||
134 | * | ||
135 | * Return: fpga manager struct or IS_ERR() condition containing error code. | ||
136 | */ | ||
137 | static struct fpga_manager *fpga_region_get_manager(struct fpga_region *region) | ||
138 | { | ||
139 | struct device *dev = ®ion->dev; | ||
140 | struct device_node *np = dev->of_node; | ||
141 | struct device_node *mgr_node; | ||
142 | struct fpga_manager *mgr; | ||
143 | |||
144 | of_node_get(np); | ||
145 | while (np) { | ||
146 | if (of_device_is_compatible(np, "fpga-region")) { | ||
147 | mgr_node = of_parse_phandle(np, "fpga-mgr", 0); | ||
148 | if (mgr_node) { | ||
149 | mgr = of_fpga_mgr_get(mgr_node); | ||
150 | of_node_put(np); | ||
151 | return mgr; | ||
152 | } | ||
153 | } | ||
154 | np = of_get_next_parent(np); | ||
155 | } | ||
156 | of_node_put(np); | ||
157 | |||
158 | return ERR_PTR(-EINVAL); | ||
159 | } | ||
160 | |||
161 | /** | ||
162 | * fpga_region_get_bridges - create a list of bridges | ||
163 | * @region: FPGA region | ||
164 | * @overlay: device node of the overlay | ||
165 | * | ||
166 | * Create a list of bridges including the parent bridge and the bridges | ||
167 | * specified by "fpga-bridges" property. Note that the | ||
168 | * fpga_bridges_enable/disable/put functions are all fine with an empty list | ||
169 | * if that happens. | ||
170 | * | ||
171 | * Caller should call fpga_bridges_put(®ion->bridge_list) when | ||
172 | * done with the bridges. | ||
173 | * | ||
174 | * Return 0 for success (even if there are no bridges specified) | ||
175 | * or -EBUSY if any of the bridges are in use. | ||
176 | */ | ||
177 | static int fpga_region_get_bridges(struct fpga_region *region, | ||
178 | struct device_node *overlay) | ||
179 | { | ||
180 | struct device *dev = ®ion->dev; | ||
181 | struct device_node *region_np = dev->of_node; | ||
182 | struct device_node *br, *np, *parent_br = NULL; | ||
183 | int i, ret; | ||
184 | |||
185 | /* If parent is a bridge, add to list */ | ||
186 | ret = fpga_bridge_get_to_list(region_np->parent, region->info, | ||
187 | ®ion->bridge_list); | ||
188 | if (ret == -EBUSY) | ||
189 | return ret; | ||
190 | |||
191 | if (!ret) | ||
192 | parent_br = region_np->parent; | ||
193 | |||
194 | /* If overlay has a list of bridges, use it. */ | ||
195 | if (of_parse_phandle(overlay, "fpga-bridges", 0)) | ||
196 | np = overlay; | ||
197 | else | ||
198 | np = region_np; | ||
199 | |||
200 | for (i = 0; ; i++) { | ||
201 | br = of_parse_phandle(np, "fpga-bridges", i); | ||
202 | if (!br) | ||
203 | break; | ||
204 | |||
205 | /* If parent bridge is in list, skip it. */ | ||
206 | if (br == parent_br) | ||
207 | continue; | ||
208 | |||
209 | /* If node is a bridge, get it and add to list */ | ||
210 | ret = fpga_bridge_get_to_list(br, region->info, | ||
211 | ®ion->bridge_list); | ||
212 | |||
213 | /* If any of the bridges are in use, give up */ | ||
214 | if (ret == -EBUSY) { | ||
215 | fpga_bridges_put(®ion->bridge_list); | ||
216 | return -EBUSY; | ||
217 | } | ||
218 | } | ||
219 | |||
220 | return 0; | ||
221 | } | ||
222 | |||
223 | /** | ||
224 | * fpga_region_program_fpga - program FPGA | 95 | * fpga_region_program_fpga - program FPGA |
225 | * @region: FPGA region | 96 | * @region: FPGA region |
226 | * @firmware_name: name of FPGA image firmware file | 97 | * Program an FPGA using fpga image info (region->info). |
227 | * @overlay: device node of the overlay | ||
228 | * Program an FPGA using information in the device tree. | ||
229 | * Function assumes that there is a firmware-name property. | ||
230 | * Return 0 for success or negative error code. | 98 | * Return 0 for success or negative error code. |
231 | */ | 99 | */ |
232 | static int fpga_region_program_fpga(struct fpga_region *region, | 100 | int fpga_region_program_fpga(struct fpga_region *region) |
233 | const char *firmware_name, | ||
234 | struct device_node *overlay) | ||
235 | { | 101 | { |
236 | struct fpga_manager *mgr; | 102 | struct device *dev = ®ion->dev; |
103 | struct fpga_image_info *info = region->info; | ||
237 | int ret; | 104 | int ret; |
238 | 105 | ||
239 | region = fpga_region_get(region); | 106 | region = fpga_region_get(region); |
240 | if (IS_ERR(region)) { | 107 | if (IS_ERR(region)) { |
241 | pr_err("failed to get fpga region\n"); | 108 | dev_err(dev, "failed to get FPGA region\n"); |
242 | return PTR_ERR(region); | 109 | return PTR_ERR(region); |
243 | } | 110 | } |
244 | 111 | ||
245 | mgr = fpga_region_get_manager(region); | 112 | ret = fpga_mgr_lock(region->mgr); |
246 | if (IS_ERR(mgr)) { | 113 | if (ret) { |
247 | pr_err("failed to get fpga region manager\n"); | 114 | dev_err(dev, "FPGA manager is busy\n"); |
248 | ret = PTR_ERR(mgr); | ||
249 | goto err_put_region; | 115 | goto err_put_region; |
250 | } | 116 | } |
251 | 117 | ||
252 | ret = fpga_region_get_bridges(region, overlay); | 118 | /* |
253 | if (ret) { | 119 | * In some cases, we already have a list of bridges in the |
254 | pr_err("failed to get fpga region bridges\n"); | 120 | * fpga region struct. Or we don't have any bridges. |
255 | goto err_put_mgr; | 121 | */ |
122 | if (region->get_bridges) { | ||
123 | ret = region->get_bridges(region); | ||
124 | if (ret) { | ||
125 | dev_err(dev, "failed to get fpga region bridges\n"); | ||
126 | goto err_unlock_mgr; | ||
127 | } | ||
256 | } | 128 | } |
257 | 129 | ||
258 | ret = fpga_bridges_disable(®ion->bridge_list); | 130 | ret = fpga_bridges_disable(®ion->bridge_list); |
259 | if (ret) { | 131 | if (ret) { |
260 | pr_err("failed to disable region bridges\n"); | 132 | dev_err(dev, "failed to disable bridges\n"); |
261 | goto err_put_br; | 133 | goto err_put_br; |
262 | } | 134 | } |
263 | 135 | ||
264 | ret = fpga_mgr_firmware_load(mgr, region->info, firmware_name); | 136 | ret = fpga_mgr_load(region->mgr, info); |
265 | if (ret) { | 137 | if (ret) { |
266 | pr_err("failed to load fpga image\n"); | 138 | dev_err(dev, "failed to load FPGA image\n"); |
267 | goto err_put_br; | 139 | goto err_put_br; |
268 | } | 140 | } |
269 | 141 | ||
270 | ret = fpga_bridges_enable(®ion->bridge_list); | 142 | ret = fpga_bridges_enable(®ion->bridge_list); |
271 | if (ret) { | 143 | if (ret) { |
272 | pr_err("failed to enable region bridges\n"); | 144 | dev_err(dev, "failed to enable region bridges\n"); |
273 | goto err_put_br; | 145 | goto err_put_br; |
274 | } | 146 | } |
275 | 147 | ||
276 | fpga_mgr_put(mgr); | 148 | fpga_mgr_unlock(region->mgr); |
277 | fpga_region_put(region); | 149 | fpga_region_put(region); |
278 | 150 | ||
279 | return 0; | 151 | return 0; |
280 | 152 | ||
281 | err_put_br: | 153 | err_put_br: |
282 | fpga_bridges_put(®ion->bridge_list); | 154 | if (region->get_bridges) |
283 | err_put_mgr: | 155 | fpga_bridges_put(®ion->bridge_list); |
284 | fpga_mgr_put(mgr); | 156 | err_unlock_mgr: |
157 | fpga_mgr_unlock(region->mgr); | ||
285 | err_put_region: | 158 | err_put_region: |
286 | fpga_region_put(region); | 159 | fpga_region_put(region); |
287 | 160 | ||
288 | return ret; | 161 | return ret; |
289 | } | 162 | } |
163 | EXPORT_SYMBOL_GPL(fpga_region_program_fpga); | ||
290 | 164 | ||
291 | /** | 165 | int fpga_region_register(struct device *dev, struct fpga_region *region) |
292 | * child_regions_with_firmware | ||
293 | * @overlay: device node of the overlay | ||
294 | * | ||
295 | * If the overlay adds child FPGA regions, they are not allowed to have | ||
296 | * firmware-name property. | ||
297 | * | ||
298 | * Return 0 for OK or -EINVAL if child FPGA region adds firmware-name. | ||
299 | */ | ||
300 | static int child_regions_with_firmware(struct device_node *overlay) | ||
301 | { | ||
302 | struct device_node *child_region; | ||
303 | const char *child_firmware_name; | ||
304 | int ret = 0; | ||
305 | |||
306 | of_node_get(overlay); | ||
307 | |||
308 | child_region = of_find_matching_node(overlay, fpga_region_of_match); | ||
309 | while (child_region) { | ||
310 | if (!of_property_read_string(child_region, "firmware-name", | ||
311 | &child_firmware_name)) { | ||
312 | ret = -EINVAL; | ||
313 | break; | ||
314 | } | ||
315 | child_region = of_find_matching_node(child_region, | ||
316 | fpga_region_of_match); | ||
317 | } | ||
318 | |||
319 | of_node_put(child_region); | ||
320 | |||
321 | if (ret) | ||
322 | pr_err("firmware-name not allowed in child FPGA region: %pOF", | ||
323 | child_region); | ||
324 | |||
325 | return ret; | ||
326 | } | ||
327 | |||
328 | /** | ||
329 | * fpga_region_notify_pre_apply - pre-apply overlay notification | ||
330 | * | ||
331 | * @region: FPGA region that the overlay was applied to | ||
332 | * @nd: overlay notification data | ||
333 | * | ||
334 | * Called after when an overlay targeted to a FPGA Region is about to be | ||
335 | * applied. Function will check the properties that will be added to the FPGA | ||
336 | * region. If the checks pass, it will program the FPGA. | ||
337 | * | ||
338 | * The checks are: | ||
339 | * The overlay must add either firmware-name or external-fpga-config property | ||
340 | * to the FPGA Region. | ||
341 | * | ||
342 | * firmware-name : program the FPGA | ||
343 | * external-fpga-config : FPGA is already programmed | ||
344 | * encrypted-fpga-config : FPGA bitstream is encrypted | ||
345 | * | ||
346 | * The overlay can add other FPGA regions, but child FPGA regions cannot have a | ||
347 | * firmware-name property since those regions don't exist yet. | ||
348 | * | ||
349 | * If the overlay that breaks the rules, notifier returns an error and the | ||
350 | * overlay is rejected before it goes into the main tree. | ||
351 | * | ||
352 | * Returns 0 for success or negative error code for failure. | ||
353 | */ | ||
354 | static int fpga_region_notify_pre_apply(struct fpga_region *region, | ||
355 | struct of_overlay_notify_data *nd) | ||
356 | { | 166 | { |
357 | const char *firmware_name = NULL; | ||
358 | struct fpga_image_info *info; | ||
359 | int ret; | ||
360 | |||
361 | info = devm_kzalloc(®ion->dev, sizeof(*info), GFP_KERNEL); | ||
362 | if (!info) | ||
363 | return -ENOMEM; | ||
364 | |||
365 | region->info = info; | ||
366 | |||
367 | /* Reject overlay if child FPGA Regions have firmware-name property */ | ||
368 | ret = child_regions_with_firmware(nd->overlay); | ||
369 | if (ret) | ||
370 | return ret; | ||
371 | |||
372 | /* Read FPGA region properties from the overlay */ | ||
373 | if (of_property_read_bool(nd->overlay, "partial-fpga-config")) | ||
374 | info->flags |= FPGA_MGR_PARTIAL_RECONFIG; | ||
375 | |||
376 | if (of_property_read_bool(nd->overlay, "external-fpga-config")) | ||
377 | info->flags |= FPGA_MGR_EXTERNAL_CONFIG; | ||
378 | |||
379 | if (of_property_read_bool(nd->overlay, "encrypted-fpga-config")) | ||
380 | info->flags |= FPGA_MGR_ENCRYPTED_BITSTREAM; | ||
381 | |||
382 | of_property_read_string(nd->overlay, "firmware-name", &firmware_name); | ||
383 | |||
384 | of_property_read_u32(nd->overlay, "region-unfreeze-timeout-us", | ||
385 | &info->enable_timeout_us); | ||
386 | |||
387 | of_property_read_u32(nd->overlay, "region-freeze-timeout-us", | ||
388 | &info->disable_timeout_us); | ||
389 | |||
390 | of_property_read_u32(nd->overlay, "config-complete-timeout-us", | ||
391 | &info->config_complete_timeout_us); | ||
392 | |||
393 | /* If FPGA was externally programmed, don't specify firmware */ | ||
394 | if ((info->flags & FPGA_MGR_EXTERNAL_CONFIG) && firmware_name) { | ||
395 | pr_err("error: specified firmware and external-fpga-config"); | ||
396 | return -EINVAL; | ||
397 | } | ||
398 | |||
399 | /* FPGA is already configured externally. We're done. */ | ||
400 | if (info->flags & FPGA_MGR_EXTERNAL_CONFIG) | ||
401 | return 0; | ||
402 | |||
403 | /* If we got this far, we should be programming the FPGA */ | ||
404 | if (!firmware_name) { | ||
405 | pr_err("should specify firmware-name or external-fpga-config\n"); | ||
406 | return -EINVAL; | ||
407 | } | ||
408 | |||
409 | return fpga_region_program_fpga(region, firmware_name, nd->overlay); | ||
410 | } | ||
411 | |||
412 | /** | ||
413 | * fpga_region_notify_post_remove - post-remove overlay notification | ||
414 | * | ||
415 | * @region: FPGA region that was targeted by the overlay that was removed | ||
416 | * @nd: overlay notification data | ||
417 | * | ||
418 | * Called after an overlay has been removed if the overlay's target was a | ||
419 | * FPGA region. | ||
420 | */ | ||
421 | static void fpga_region_notify_post_remove(struct fpga_region *region, | ||
422 | struct of_overlay_notify_data *nd) | ||
423 | { | ||
424 | fpga_bridges_disable(®ion->bridge_list); | ||
425 | fpga_bridges_put(®ion->bridge_list); | ||
426 | devm_kfree(®ion->dev, region->info); | ||
427 | region->info = NULL; | ||
428 | } | ||
429 | |||
430 | /** | ||
431 | * of_fpga_region_notify - reconfig notifier for dynamic DT changes | ||
432 | * @nb: notifier block | ||
433 | * @action: notifier action | ||
434 | * @arg: reconfig data | ||
435 | * | ||
436 | * This notifier handles programming a FPGA when a "firmware-name" property is | ||
437 | * added to a fpga-region. | ||
438 | * | ||
439 | * Returns NOTIFY_OK or error if FPGA programming fails. | ||
440 | */ | ||
441 | static int of_fpga_region_notify(struct notifier_block *nb, | ||
442 | unsigned long action, void *arg) | ||
443 | { | ||
444 | struct of_overlay_notify_data *nd = arg; | ||
445 | struct fpga_region *region; | ||
446 | int ret; | ||
447 | |||
448 | switch (action) { | ||
449 | case OF_OVERLAY_PRE_APPLY: | ||
450 | pr_debug("%s OF_OVERLAY_PRE_APPLY\n", __func__); | ||
451 | break; | ||
452 | case OF_OVERLAY_POST_APPLY: | ||
453 | pr_debug("%s OF_OVERLAY_POST_APPLY\n", __func__); | ||
454 | return NOTIFY_OK; /* not for us */ | ||
455 | case OF_OVERLAY_PRE_REMOVE: | ||
456 | pr_debug("%s OF_OVERLAY_PRE_REMOVE\n", __func__); | ||
457 | return NOTIFY_OK; /* not for us */ | ||
458 | case OF_OVERLAY_POST_REMOVE: | ||
459 | pr_debug("%s OF_OVERLAY_POST_REMOVE\n", __func__); | ||
460 | break; | ||
461 | default: /* should not happen */ | ||
462 | return NOTIFY_OK; | ||
463 | } | ||
464 | |||
465 | region = fpga_region_find(nd->target); | ||
466 | if (!region) | ||
467 | return NOTIFY_OK; | ||
468 | |||
469 | ret = 0; | ||
470 | switch (action) { | ||
471 | case OF_OVERLAY_PRE_APPLY: | ||
472 | ret = fpga_region_notify_pre_apply(region, nd); | ||
473 | break; | ||
474 | |||
475 | case OF_OVERLAY_POST_REMOVE: | ||
476 | fpga_region_notify_post_remove(region, nd); | ||
477 | break; | ||
478 | } | ||
479 | |||
480 | put_device(®ion->dev); | ||
481 | |||
482 | if (ret) | ||
483 | return notifier_from_errno(ret); | ||
484 | |||
485 | return NOTIFY_OK; | ||
486 | } | ||
487 | |||
488 | static struct notifier_block fpga_region_of_nb = { | ||
489 | .notifier_call = of_fpga_region_notify, | ||
490 | }; | ||
491 | |||
492 | static int fpga_region_probe(struct platform_device *pdev) | ||
493 | { | ||
494 | struct device *dev = &pdev->dev; | ||
495 | struct device_node *np = dev->of_node; | ||
496 | struct fpga_region *region; | ||
497 | int id, ret = 0; | 167 | int id, ret = 0; |
498 | 168 | ||
499 | region = kzalloc(sizeof(*region), GFP_KERNEL); | ||
500 | if (!region) | ||
501 | return -ENOMEM; | ||
502 | |||
503 | id = ida_simple_get(&fpga_region_ida, 0, 0, GFP_KERNEL); | 169 | id = ida_simple_get(&fpga_region_ida, 0, 0, GFP_KERNEL); |
504 | if (id < 0) { | 170 | if (id < 0) |
505 | ret = id; | 171 | return id; |
506 | goto err_kfree; | ||
507 | } | ||
508 | 172 | ||
509 | mutex_init(®ion->mutex); | 173 | mutex_init(®ion->mutex); |
510 | INIT_LIST_HEAD(®ion->bridge_list); | 174 | INIT_LIST_HEAD(®ion->bridge_list); |
511 | |||
512 | device_initialize(®ion->dev); | 175 | device_initialize(®ion->dev); |
176 | region->dev.groups = region->groups; | ||
513 | region->dev.class = fpga_region_class; | 177 | region->dev.class = fpga_region_class; |
514 | region->dev.parent = dev; | 178 | region->dev.parent = dev; |
515 | region->dev.of_node = np; | 179 | region->dev.of_node = dev->of_node; |
516 | region->dev.id = id; | 180 | region->dev.id = id; |
517 | dev_set_drvdata(dev, region); | 181 | dev_set_drvdata(dev, region); |
518 | 182 | ||
@@ -524,44 +188,27 @@ static int fpga_region_probe(struct platform_device *pdev) | |||
524 | if (ret) | 188 | if (ret) |
525 | goto err_remove; | 189 | goto err_remove; |
526 | 190 | ||
527 | of_platform_populate(np, fpga_region_of_match, NULL, ®ion->dev); | ||
528 | |||
529 | dev_info(dev, "FPGA Region probed\n"); | ||
530 | |||
531 | return 0; | 191 | return 0; |
532 | 192 | ||
533 | err_remove: | 193 | err_remove: |
534 | ida_simple_remove(&fpga_region_ida, id); | 194 | ida_simple_remove(&fpga_region_ida, id); |
535 | err_kfree: | ||
536 | kfree(region); | ||
537 | |||
538 | return ret; | 195 | return ret; |
539 | } | 196 | } |
197 | EXPORT_SYMBOL_GPL(fpga_region_register); | ||
540 | 198 | ||
541 | static int fpga_region_remove(struct platform_device *pdev) | 199 | int fpga_region_unregister(struct fpga_region *region) |
542 | { | 200 | { |
543 | struct fpga_region *region = platform_get_drvdata(pdev); | ||
544 | |||
545 | device_unregister(®ion->dev); | 201 | device_unregister(®ion->dev); |
546 | 202 | ||
547 | return 0; | 203 | return 0; |
548 | } | 204 | } |
549 | 205 | EXPORT_SYMBOL_GPL(fpga_region_unregister); | |
550 | static struct platform_driver fpga_region_driver = { | ||
551 | .probe = fpga_region_probe, | ||
552 | .remove = fpga_region_remove, | ||
553 | .driver = { | ||
554 | .name = "fpga-region", | ||
555 | .of_match_table = of_match_ptr(fpga_region_of_match), | ||
556 | }, | ||
557 | }; | ||
558 | 206 | ||
559 | static void fpga_region_dev_release(struct device *dev) | 207 | static void fpga_region_dev_release(struct device *dev) |
560 | { | 208 | { |
561 | struct fpga_region *region = to_fpga_region(dev); | 209 | struct fpga_region *region = to_fpga_region(dev); |
562 | 210 | ||
563 | ida_simple_remove(&fpga_region_ida, region->dev.id); | 211 | ida_simple_remove(&fpga_region_ida, region->dev.id); |
564 | kfree(region); | ||
565 | } | 212 | } |
566 | 213 | ||
567 | /** | 214 | /** |
@@ -570,36 +217,17 @@ static void fpga_region_dev_release(struct device *dev) | |||
570 | */ | 217 | */ |
571 | static int __init fpga_region_init(void) | 218 | static int __init fpga_region_init(void) |
572 | { | 219 | { |
573 | int ret; | ||
574 | |||
575 | fpga_region_class = class_create(THIS_MODULE, "fpga_region"); | 220 | fpga_region_class = class_create(THIS_MODULE, "fpga_region"); |
576 | if (IS_ERR(fpga_region_class)) | 221 | if (IS_ERR(fpga_region_class)) |
577 | return PTR_ERR(fpga_region_class); | 222 | return PTR_ERR(fpga_region_class); |
578 | 223 | ||
579 | fpga_region_class->dev_release = fpga_region_dev_release; | 224 | fpga_region_class->dev_release = fpga_region_dev_release; |
580 | 225 | ||
581 | ret = of_overlay_notifier_register(&fpga_region_of_nb); | ||
582 | if (ret) | ||
583 | goto err_class; | ||
584 | |||
585 | ret = platform_driver_register(&fpga_region_driver); | ||
586 | if (ret) | ||
587 | goto err_plat; | ||
588 | |||
589 | return 0; | 226 | return 0; |
590 | |||
591 | err_plat: | ||
592 | of_overlay_notifier_unregister(&fpga_region_of_nb); | ||
593 | err_class: | ||
594 | class_destroy(fpga_region_class); | ||
595 | ida_destroy(&fpga_region_ida); | ||
596 | return ret; | ||
597 | } | 227 | } |
598 | 228 | ||
599 | static void __exit fpga_region_exit(void) | 229 | static void __exit fpga_region_exit(void) |
600 | { | 230 | { |
601 | platform_driver_unregister(&fpga_region_driver); | ||
602 | of_overlay_notifier_unregister(&fpga_region_of_nb); | ||
603 | class_destroy(fpga_region_class); | 231 | class_destroy(fpga_region_class); |
604 | ida_destroy(&fpga_region_ida); | 232 | ida_destroy(&fpga_region_ida); |
605 | } | 233 | } |
@@ -608,5 +236,5 @@ subsys_initcall(fpga_region_init); | |||
608 | module_exit(fpga_region_exit); | 236 | module_exit(fpga_region_exit); |
609 | 237 | ||
610 | MODULE_DESCRIPTION("FPGA Region"); | 238 | MODULE_DESCRIPTION("FPGA Region"); |
611 | MODULE_AUTHOR("Alan Tull <atull@opensource.altera.com>"); | 239 | MODULE_AUTHOR("Alan Tull <atull@kernel.org>"); |
612 | MODULE_LICENSE("GPL v2"); | 240 | MODULE_LICENSE("GPL v2"); |
diff --git a/drivers/fpga/of-fpga-region.c b/drivers/fpga/of-fpga-region.c new file mode 100644 index 000000000000..119ff75522f1 --- /dev/null +++ b/drivers/fpga/of-fpga-region.c | |||
@@ -0,0 +1,504 @@ | |||
1 | /* | ||
2 | * FPGA Region - Device Tree support for FPGA programming under Linux | ||
3 | * | ||
4 | * Copyright (C) 2013-2016 Altera Corporation | ||
5 | * Copyright (C) 2017 Intel Corporation | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms and conditions of the GNU General Public License, | ||
9 | * version 2, as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
14 | * more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along with | ||
17 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | |||
20 | #include <linux/fpga/fpga-bridge.h> | ||
21 | #include <linux/fpga/fpga-mgr.h> | ||
22 | #include <linux/fpga/fpga-region.h> | ||
23 | #include <linux/idr.h> | ||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/list.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/of_platform.h> | ||
28 | #include <linux/slab.h> | ||
29 | #include <linux/spinlock.h> | ||
30 | |||
31 | static const struct of_device_id fpga_region_of_match[] = { | ||
32 | { .compatible = "fpga-region", }, | ||
33 | {}, | ||
34 | }; | ||
35 | MODULE_DEVICE_TABLE(of, fpga_region_of_match); | ||
36 | |||
37 | static int fpga_region_of_node_match(struct device *dev, const void *data) | ||
38 | { | ||
39 | return dev->of_node == data; | ||
40 | } | ||
41 | |||
42 | /** | ||
43 | * of_fpga_region_find - find FPGA region | ||
44 | * @np: device node of FPGA Region | ||
45 | * | ||
46 | * Caller will need to put_device(®ion->dev) when done. | ||
47 | * | ||
48 | * Returns FPGA Region struct or NULL | ||
49 | */ | ||
50 | static struct fpga_region *of_fpga_region_find(struct device_node *np) | ||
51 | { | ||
52 | return fpga_region_class_find(NULL, np, fpga_region_of_node_match); | ||
53 | } | ||
54 | |||
55 | /** | ||
56 | * of_fpga_region_get_mgr - get reference for FPGA manager | ||
57 | * @np: device node of FPGA region | ||
58 | * | ||
59 | * Get FPGA Manager from "fpga-mgr" property or from ancestor region. | ||
60 | * | ||
61 | * Caller should call fpga_mgr_put() when done with manager. | ||
62 | * | ||
63 | * Return: fpga manager struct or IS_ERR() condition containing error code. | ||
64 | */ | ||
65 | static struct fpga_manager *of_fpga_region_get_mgr(struct device_node *np) | ||
66 | { | ||
67 | struct device_node *mgr_node; | ||
68 | struct fpga_manager *mgr; | ||
69 | |||
70 | of_node_get(np); | ||
71 | while (np) { | ||
72 | if (of_device_is_compatible(np, "fpga-region")) { | ||
73 | mgr_node = of_parse_phandle(np, "fpga-mgr", 0); | ||
74 | if (mgr_node) { | ||
75 | mgr = of_fpga_mgr_get(mgr_node); | ||
76 | of_node_put(mgr_node); | ||
77 | of_node_put(np); | ||
78 | return mgr; | ||
79 | } | ||
80 | } | ||
81 | np = of_get_next_parent(np); | ||
82 | } | ||
83 | of_node_put(np); | ||
84 | |||
85 | return ERR_PTR(-EINVAL); | ||
86 | } | ||
87 | |||
88 | /** | ||
89 | * of_fpga_region_get_bridges - create a list of bridges | ||
90 | * @region: FPGA region | ||
91 | * | ||
92 | * Create a list of bridges including the parent bridge and the bridges | ||
93 | * specified by "fpga-bridges" property. Note that the | ||
94 | * fpga_bridges_enable/disable/put functions are all fine with an empty list | ||
95 | * if that happens. | ||
96 | * | ||
97 | * Caller should call fpga_bridges_put(®ion->bridge_list) when | ||
98 | * done with the bridges. | ||
99 | * | ||
100 | * Return 0 for success (even if there are no bridges specified) | ||
101 | * or -EBUSY if any of the bridges are in use. | ||
102 | */ | ||
103 | static int of_fpga_region_get_bridges(struct fpga_region *region) | ||
104 | { | ||
105 | struct device *dev = ®ion->dev; | ||
106 | struct device_node *region_np = dev->of_node; | ||
107 | struct fpga_image_info *info = region->info; | ||
108 | struct device_node *br, *np, *parent_br = NULL; | ||
109 | int i, ret; | ||
110 | |||
111 | /* If parent is a bridge, add to list */ | ||
112 | ret = of_fpga_bridge_get_to_list(region_np->parent, info, | ||
113 | ®ion->bridge_list); | ||
114 | |||
115 | /* -EBUSY means parent is a bridge that is under use. Give up. */ | ||
116 | if (ret == -EBUSY) | ||
117 | return ret; | ||
118 | |||
119 | /* Zero return code means parent was a bridge and was added to list. */ | ||
120 | if (!ret) | ||
121 | parent_br = region_np->parent; | ||
122 | |||
123 | /* If overlay has a list of bridges, use it. */ | ||
124 | br = of_parse_phandle(info->overlay, "fpga-bridges", 0); | ||
125 | if (br) { | ||
126 | of_node_put(br); | ||
127 | np = info->overlay; | ||
128 | } else { | ||
129 | np = region_np; | ||
130 | } | ||
131 | |||
132 | for (i = 0; ; i++) { | ||
133 | br = of_parse_phandle(np, "fpga-bridges", i); | ||
134 | if (!br) | ||
135 | break; | ||
136 | |||
137 | /* If parent bridge is in list, skip it. */ | ||
138 | if (br == parent_br) { | ||
139 | of_node_put(br); | ||
140 | continue; | ||
141 | } | ||
142 | |||
143 | /* If node is a bridge, get it and add to list */ | ||
144 | ret = of_fpga_bridge_get_to_list(br, info, | ||
145 | ®ion->bridge_list); | ||
146 | of_node_put(br); | ||
147 | |||
148 | /* If any of the bridges are in use, give up */ | ||
149 | if (ret == -EBUSY) { | ||
150 | fpga_bridges_put(®ion->bridge_list); | ||
151 | return -EBUSY; | ||
152 | } | ||
153 | } | ||
154 | |||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | /** | ||
159 | * child_regions_with_firmware | ||
160 | * @overlay: device node of the overlay | ||
161 | * | ||
162 | * If the overlay adds child FPGA regions, they are not allowed to have | ||
163 | * firmware-name property. | ||
164 | * | ||
165 | * Return 0 for OK or -EINVAL if child FPGA region adds firmware-name. | ||
166 | */ | ||
167 | static int child_regions_with_firmware(struct device_node *overlay) | ||
168 | { | ||
169 | struct device_node *child_region; | ||
170 | const char *child_firmware_name; | ||
171 | int ret = 0; | ||
172 | |||
173 | of_node_get(overlay); | ||
174 | |||
175 | child_region = of_find_matching_node(overlay, fpga_region_of_match); | ||
176 | while (child_region) { | ||
177 | if (!of_property_read_string(child_region, "firmware-name", | ||
178 | &child_firmware_name)) { | ||
179 | ret = -EINVAL; | ||
180 | break; | ||
181 | } | ||
182 | child_region = of_find_matching_node(child_region, | ||
183 | fpga_region_of_match); | ||
184 | } | ||
185 | |||
186 | of_node_put(child_region); | ||
187 | |||
188 | if (ret) | ||
189 | pr_err("firmware-name not allowed in child FPGA region: %pOF", | ||
190 | child_region); | ||
191 | |||
192 | return ret; | ||
193 | } | ||
194 | |||
195 | /** | ||
196 | * of_fpga_region_parse_ov - parse and check overlay applied to region | ||
197 | * | ||
198 | * @region: FPGA region | ||
199 | * @overlay: overlay applied to the FPGA region | ||
200 | * | ||
201 | * Given an overlay applied to a FPGA region, parse the FPGA image specific | ||
202 | * info in the overlay and do some checking. | ||
203 | * | ||
204 | * Returns: | ||
205 | * NULL if overlay doesn't direct us to program the FPGA. | ||
206 | * fpga_image_info struct if there is an image to program. | ||
207 | * error code for invalid overlay. | ||
208 | */ | ||
209 | static struct fpga_image_info *of_fpga_region_parse_ov( | ||
210 | struct fpga_region *region, | ||
211 | struct device_node *overlay) | ||
212 | { | ||
213 | struct device *dev = ®ion->dev; | ||
214 | struct fpga_image_info *info; | ||
215 | const char *firmware_name; | ||
216 | int ret; | ||
217 | |||
218 | if (region->info) { | ||
219 | dev_err(dev, "Region already has overlay applied.\n"); | ||
220 | return ERR_PTR(-EINVAL); | ||
221 | } | ||
222 | |||
223 | /* | ||
224 | * Reject overlay if child FPGA Regions added in the overlay have | ||
225 | * firmware-name property (would mean that an FPGA region that has | ||
226 | * not been added to the live tree yet is doing FPGA programming). | ||
227 | */ | ||
228 | ret = child_regions_with_firmware(overlay); | ||
229 | if (ret) | ||
230 | return ERR_PTR(ret); | ||
231 | |||
232 | info = fpga_image_info_alloc(dev); | ||
233 | if (!info) | ||
234 | return ERR_PTR(-ENOMEM); | ||
235 | |||
236 | info->overlay = overlay; | ||
237 | |||
238 | /* Read FPGA region properties from the overlay */ | ||
239 | if (of_property_read_bool(overlay, "partial-fpga-config")) | ||
240 | info->flags |= FPGA_MGR_PARTIAL_RECONFIG; | ||
241 | |||
242 | if (of_property_read_bool(overlay, "external-fpga-config")) | ||
243 | info->flags |= FPGA_MGR_EXTERNAL_CONFIG; | ||
244 | |||
245 | if (of_property_read_bool(overlay, "encrypted-fpga-config")) | ||
246 | info->flags |= FPGA_MGR_ENCRYPTED_BITSTREAM; | ||
247 | |||
248 | if (!of_property_read_string(overlay, "firmware-name", | ||
249 | &firmware_name)) { | ||
250 | info->firmware_name = devm_kstrdup(dev, firmware_name, | ||
251 | GFP_KERNEL); | ||
252 | if (!info->firmware_name) | ||
253 | return ERR_PTR(-ENOMEM); | ||
254 | } | ||
255 | |||
256 | of_property_read_u32(overlay, "region-unfreeze-timeout-us", | ||
257 | &info->enable_timeout_us); | ||
258 | |||
259 | of_property_read_u32(overlay, "region-freeze-timeout-us", | ||
260 | &info->disable_timeout_us); | ||
261 | |||
262 | of_property_read_u32(overlay, "config-complete-timeout-us", | ||
263 | &info->config_complete_timeout_us); | ||
264 | |||
265 | /* If overlay is not programming the FPGA, don't need FPGA image info */ | ||
266 | if (!info->firmware_name) { | ||
267 | ret = 0; | ||
268 | goto ret_no_info; | ||
269 | } | ||
270 | |||
271 | /* | ||
272 | * If overlay informs us FPGA was externally programmed, specifying | ||
273 | * firmware here would be ambiguous. | ||
274 | */ | ||
275 | if (info->flags & FPGA_MGR_EXTERNAL_CONFIG) { | ||
276 | dev_err(dev, "error: specified firmware and external-fpga-config"); | ||
277 | ret = -EINVAL; | ||
278 | goto ret_no_info; | ||
279 | } | ||
280 | |||
281 | return info; | ||
282 | ret_no_info: | ||
283 | fpga_image_info_free(info); | ||
284 | return ERR_PTR(ret); | ||
285 | } | ||
286 | |||
287 | /** | ||
288 | * of_fpga_region_notify_pre_apply - pre-apply overlay notification | ||
289 | * | ||
290 | * @region: FPGA region that the overlay was applied to | ||
291 | * @nd: overlay notification data | ||
292 | * | ||
293 | * Called when an overlay targeted to a FPGA Region is about to be applied. | ||
294 | * Parses the overlay for properties that influence how the FPGA will be | ||
295 | * programmed and does some checking. If the checks pass, programs the FPGA. | ||
296 | * If the checks fail, overlay is rejected and does not get added to the | ||
297 | * live tree. | ||
298 | * | ||
299 | * Returns 0 for success or negative error code for failure. | ||
300 | */ | ||
301 | static int of_fpga_region_notify_pre_apply(struct fpga_region *region, | ||
302 | struct of_overlay_notify_data *nd) | ||
303 | { | ||
304 | struct device *dev = ®ion->dev; | ||
305 | struct fpga_image_info *info; | ||
306 | int ret; | ||
307 | |||
308 | info = of_fpga_region_parse_ov(region, nd->overlay); | ||
309 | if (IS_ERR(info)) | ||
310 | return PTR_ERR(info); | ||
311 | |||
312 | /* If overlay doesn't program the FPGA, accept it anyway. */ | ||
313 | if (!info) | ||
314 | return 0; | ||
315 | |||
316 | if (region->info) { | ||
317 | dev_err(dev, "Region already has overlay applied.\n"); | ||
318 | return -EINVAL; | ||
319 | } | ||
320 | |||
321 | region->info = info; | ||
322 | ret = fpga_region_program_fpga(region); | ||
323 | if (ret) { | ||
324 | /* error; reject overlay */ | ||
325 | fpga_image_info_free(info); | ||
326 | region->info = NULL; | ||
327 | } | ||
328 | |||
329 | return ret; | ||
330 | } | ||
331 | |||
332 | /** | ||
333 | * of_fpga_region_notify_post_remove - post-remove overlay notification | ||
334 | * | ||
335 | * @region: FPGA region that was targeted by the overlay that was removed | ||
336 | * @nd: overlay notification data | ||
337 | * | ||
338 | * Called after an overlay has been removed if the overlay's target was a | ||
339 | * FPGA region. | ||
340 | */ | ||
341 | static void of_fpga_region_notify_post_remove(struct fpga_region *region, | ||
342 | struct of_overlay_notify_data *nd) | ||
343 | { | ||
344 | fpga_bridges_disable(®ion->bridge_list); | ||
345 | fpga_bridges_put(®ion->bridge_list); | ||
346 | fpga_image_info_free(region->info); | ||
347 | region->info = NULL; | ||
348 | } | ||
349 | |||
350 | /** | ||
351 | * of_fpga_region_notify - reconfig notifier for dynamic DT changes | ||
352 | * @nb: notifier block | ||
353 | * @action: notifier action | ||
354 | * @arg: reconfig data | ||
355 | * | ||
356 | * This notifier handles programming a FPGA when a "firmware-name" property is | ||
357 | * added to a fpga-region. | ||
358 | * | ||
359 | * Returns NOTIFY_OK or error if FPGA programming fails. | ||
360 | */ | ||
361 | static int of_fpga_region_notify(struct notifier_block *nb, | ||
362 | unsigned long action, void *arg) | ||
363 | { | ||
364 | struct of_overlay_notify_data *nd = arg; | ||
365 | struct fpga_region *region; | ||
366 | int ret; | ||
367 | |||
368 | switch (action) { | ||
369 | case OF_OVERLAY_PRE_APPLY: | ||
370 | pr_debug("%s OF_OVERLAY_PRE_APPLY\n", __func__); | ||
371 | break; | ||
372 | case OF_OVERLAY_POST_APPLY: | ||
373 | pr_debug("%s OF_OVERLAY_POST_APPLY\n", __func__); | ||
374 | return NOTIFY_OK; /* not for us */ | ||
375 | case OF_OVERLAY_PRE_REMOVE: | ||
376 | pr_debug("%s OF_OVERLAY_PRE_REMOVE\n", __func__); | ||
377 | return NOTIFY_OK; /* not for us */ | ||
378 | case OF_OVERLAY_POST_REMOVE: | ||
379 | pr_debug("%s OF_OVERLAY_POST_REMOVE\n", __func__); | ||
380 | break; | ||
381 | default: /* should not happen */ | ||
382 | return NOTIFY_OK; | ||
383 | } | ||
384 | |||
385 | region = of_fpga_region_find(nd->target); | ||
386 | if (!region) | ||
387 | return NOTIFY_OK; | ||
388 | |||
389 | ret = 0; | ||
390 | switch (action) { | ||
391 | case OF_OVERLAY_PRE_APPLY: | ||
392 | ret = of_fpga_region_notify_pre_apply(region, nd); | ||
393 | break; | ||
394 | |||
395 | case OF_OVERLAY_POST_REMOVE: | ||
396 | of_fpga_region_notify_post_remove(region, nd); | ||
397 | break; | ||
398 | } | ||
399 | |||
400 | put_device(®ion->dev); | ||
401 | |||
402 | if (ret) | ||
403 | return notifier_from_errno(ret); | ||
404 | |||
405 | return NOTIFY_OK; | ||
406 | } | ||
407 | |||
408 | static struct notifier_block fpga_region_of_nb = { | ||
409 | .notifier_call = of_fpga_region_notify, | ||
410 | }; | ||
411 | |||
412 | static int of_fpga_region_probe(struct platform_device *pdev) | ||
413 | { | ||
414 | struct device *dev = &pdev->dev; | ||
415 | struct device_node *np = dev->of_node; | ||
416 | struct fpga_region *region; | ||
417 | struct fpga_manager *mgr; | ||
418 | int ret; | ||
419 | |||
420 | /* Find the FPGA mgr specified by region or parent region. */ | ||
421 | mgr = of_fpga_region_get_mgr(np); | ||
422 | if (IS_ERR(mgr)) | ||
423 | return -EPROBE_DEFER; | ||
424 | |||
425 | region = devm_kzalloc(dev, sizeof(*region), GFP_KERNEL); | ||
426 | if (!region) { | ||
427 | ret = -ENOMEM; | ||
428 | goto eprobe_mgr_put; | ||
429 | } | ||
430 | |||
431 | region->mgr = mgr; | ||
432 | |||
433 | /* Specify how to get bridges for this type of region. */ | ||
434 | region->get_bridges = of_fpga_region_get_bridges; | ||
435 | |||
436 | ret = fpga_region_register(dev, region); | ||
437 | if (ret) | ||
438 | goto eprobe_mgr_put; | ||
439 | |||
440 | of_platform_populate(np, fpga_region_of_match, NULL, ®ion->dev); | ||
441 | |||
442 | dev_info(dev, "FPGA Region probed\n"); | ||
443 | |||
444 | return 0; | ||
445 | |||
446 | eprobe_mgr_put: | ||
447 | fpga_mgr_put(mgr); | ||
448 | return ret; | ||
449 | } | ||
450 | |||
451 | static int of_fpga_region_remove(struct platform_device *pdev) | ||
452 | { | ||
453 | struct fpga_region *region = platform_get_drvdata(pdev); | ||
454 | |||
455 | fpga_region_unregister(region); | ||
456 | fpga_mgr_put(region->mgr); | ||
457 | |||
458 | return 0; | ||
459 | } | ||
460 | |||
461 | static struct platform_driver of_fpga_region_driver = { | ||
462 | .probe = of_fpga_region_probe, | ||
463 | .remove = of_fpga_region_remove, | ||
464 | .driver = { | ||
465 | .name = "of-fpga-region", | ||
466 | .of_match_table = of_match_ptr(fpga_region_of_match), | ||
467 | }, | ||
468 | }; | ||
469 | |||
470 | /** | ||
471 | * fpga_region_init - init function for fpga_region class | ||
472 | * Creates the fpga_region class and registers a reconfig notifier. | ||
473 | */ | ||
474 | static int __init of_fpga_region_init(void) | ||
475 | { | ||
476 | int ret; | ||
477 | |||
478 | ret = of_overlay_notifier_register(&fpga_region_of_nb); | ||
479 | if (ret) | ||
480 | return ret; | ||
481 | |||
482 | ret = platform_driver_register(&of_fpga_region_driver); | ||
483 | if (ret) | ||
484 | goto err_plat; | ||
485 | |||
486 | return 0; | ||
487 | |||
488 | err_plat: | ||
489 | of_overlay_notifier_unregister(&fpga_region_of_nb); | ||
490 | return ret; | ||
491 | } | ||
492 | |||
493 | static void __exit of_fpga_region_exit(void) | ||
494 | { | ||
495 | platform_driver_unregister(&of_fpga_region_driver); | ||
496 | of_overlay_notifier_unregister(&fpga_region_of_nb); | ||
497 | } | ||
498 | |||
499 | subsys_initcall(of_fpga_region_init); | ||
500 | module_exit(of_fpga_region_exit); | ||
501 | |||
502 | MODULE_DESCRIPTION("FPGA Region"); | ||
503 | MODULE_AUTHOR("Alan Tull <atull@kernel.org>"); | ||
504 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/fpga/socfpga-a10.c b/drivers/fpga/socfpga-a10.c index f8770af0f6b5..a46e343a5b72 100644 --- a/drivers/fpga/socfpga-a10.c +++ b/drivers/fpga/socfpga-a10.c | |||
@@ -519,8 +519,14 @@ static int socfpga_a10_fpga_probe(struct platform_device *pdev) | |||
519 | return -EBUSY; | 519 | return -EBUSY; |
520 | } | 520 | } |
521 | 521 | ||
522 | return fpga_mgr_register(dev, "SoCFPGA Arria10 FPGA Manager", | 522 | ret = fpga_mgr_register(dev, "SoCFPGA Arria10 FPGA Manager", |
523 | &socfpga_a10_fpga_mgr_ops, priv); | 523 | &socfpga_a10_fpga_mgr_ops, priv); |
524 | if (ret) { | ||
525 | clk_disable_unprepare(priv->clk); | ||
526 | return ret; | ||
527 | } | ||
528 | |||
529 | return 0; | ||
524 | } | 530 | } |
525 | 531 | ||
526 | static int socfpga_a10_fpga_remove(struct platform_device *pdev) | 532 | static int socfpga_a10_fpga_remove(struct platform_device *pdev) |