OpenWrt – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | From c503e92983f2e18c1e18e21b15d5bedd6d0be8ac Mon Sep 17 00:00:00 2001 |
2 | From: Biwen Li <biwen.li@nxp.com> |
||
3 | Date: Tue, 30 Oct 2018 18:26:56 +0800 |
||
4 | Subject: [PATCH 33/40] pcie: support layerscape |
||
5 | This is an integrated patch of pcie for layerscape |
||
6 | |||
7 | Signed-off-by: Bao Xiaowei <xiaowei.bao@nxp.com> |
||
8 | Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> |
||
9 | Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com> |
||
10 | Signed-off-by: Minghuan Lian <Minghuan.Lian@nxp.com> |
||
11 | Signed-off-by: Po Liu <po.liu@nxp.com> |
||
12 | Signed-off-by: Zhang Ying-22455 <ying.zhang22455@nxp.com> |
||
13 | Signed-off-by: Biwen Li <biwen.li@nxp.com> |
||
14 | --- |
||
15 | .../bindings/pci/layerscape-pci.txt | 14 +- |
||
16 | arch/arm/kernel/bios32.c | 43 ++++++ |
||
17 | arch/arm64/kernel/pci.c | 43 ++++++ |
||
18 | drivers/misc/pci_endpoint_test.c | 20 +-- |
||
19 | drivers/pci/dwc/Kconfig | 8 ++ |
||
20 | drivers/pci/dwc/pci-layerscape.c | 132 +++++++++++++++++- |
||
21 | drivers/pci/endpoint/functions/pci-epf-test.c | 2 +- |
||
22 | drivers/pci/endpoint/pci-epf-core.c | 8 +- |
||
23 | drivers/pci/pcie/portdrv_core.c | 29 ++++ |
||
24 | drivers/pci/quirks.c | 15 ++ |
||
25 | include/linux/pci.h | 1 + |
||
26 | 11 files changed, 292 insertions(+), 23 deletions(-) |
||
27 | |||
28 | --- a/Documentation/devicetree/bindings/pci/layerscape-pci.txt |
||
29 | +++ b/Documentation/devicetree/bindings/pci/layerscape-pci.txt |
||
30 | @@ -18,11 +18,16 @@ Required properties: |
||
31 | "fsl,ls2088a-pcie" |
||
32 | "fsl,ls1088a-pcie" |
||
33 | "fsl,ls1046a-pcie" |
||
34 | + "fsl,ls1012a-pcie" |
||
35 | - reg: base addresses and lengths of the PCIe controller register blocks. |
||
36 | - interrupts: A list of interrupt outputs of the controller. Must contain an |
||
37 | entry for each entry in the interrupt-names property. |
||
38 | -- interrupt-names: Must include the following entries: |
||
39 | - "intr": The interrupt that is asserted for controller interrupts |
||
40 | +- interrupt-names: It could include the following entries: |
||
41 | + "aer": Asserted for aer interrupt when chip support the aer interrupt with |
||
42 | + none MSI/MSI-X/INTx mode,but there is interrupt line for aer. |
||
43 | + "pme": Asserted for pme interrupt when chip support the pme interrupt with |
||
44 | + none MSI/MSI-X/INTx mode,but there is interrupt line for pme. |
||
45 | + ...... |
||
46 | - fsl,pcie-scfg: Must include two entries. |
||
47 | The first entry must be a link to the SCFG device node |
||
48 | The second entry must be '0' or '1' based on physical PCIe controller index. |
||
49 | @@ -38,8 +43,9 @@ Example: |
||
50 | reg = <0x00 0x03400000 0x0 0x00010000 /* controller registers */ |
||
51 | 0x40 0x00000000 0x0 0x00002000>; /* configuration space */ |
||
52 | reg-names = "regs", "config"; |
||
53 | - interrupts = <GIC_SPI 177 IRQ_TYPE_LEVEL_HIGH>; /* controller interrupt */ |
||
54 | - interrupt-names = "intr"; |
||
55 | + interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>, /* aer interrupt */ |
||
56 | + <GIC_SPI 177 IRQ_TYPE_LEVEL_HIGH>; /* pme interrupt */ |
||
57 | + interrupt-names = "aer", "pme"; |
||
58 | fsl,pcie-scfg = <&scfg 0>; |
||
59 | #address-cells = <3>; |
||
60 | #size-cells = <2>; |
||
61 | --- a/arch/arm/kernel/bios32.c |
||
62 | +++ b/arch/arm/kernel/bios32.c |
||
63 | @@ -12,6 +12,8 @@ |
||
64 | #include <linux/slab.h> |
||
65 | #include <linux/init.h> |
||
66 | #include <linux/io.h> |
||
67 | +#include <linux/of_irq.h> |
||
68 | +#include <linux/pcieport_if.h> |
||
69 | |||
70 | #include <asm/mach-types.h> |
||
71 | #include <asm/mach/map.h> |
||
72 | @@ -65,6 +67,47 @@ void pcibios_report_status(u_int status_ |
||
73 | } |
||
74 | |||
75 | /* |
||
76 | + * Check device tree if the service interrupts are there |
||
77 | + */ |
||
78 | +int pcibios_check_service_irqs(struct pci_dev *dev, int *irqs, int mask) |
||
79 | +{ |
||
80 | + int ret, count = 0; |
||
81 | + struct device_node *np = NULL; |
||
82 | + |
||
83 | + if (dev->bus->dev.of_node) |
||
84 | + np = dev->bus->dev.of_node; |
||
85 | + |
||
86 | + if (np == NULL) |
||
87 | + return 0; |
||
88 | + |
||
89 | + if (!IS_ENABLED(CONFIG_OF_IRQ)) |
||
90 | + return 0; |
||
91 | + |
||
92 | + /* If root port doesn't support MSI/MSI-X/INTx in RC mode, |
||
93 | + * request irq for aer |
||
94 | + */ |
||
95 | + if (mask & PCIE_PORT_SERVICE_AER) { |
||
96 | + ret = of_irq_get_byname(np, "aer"); |
||
97 | + if (ret > 0) { |
||
98 | + irqs[PCIE_PORT_SERVICE_AER_SHIFT] = ret; |
||
99 | + count++; |
||
100 | + } |
||
101 | + } |
||
102 | + |
||
103 | + if (mask & PCIE_PORT_SERVICE_PME) { |
||
104 | + ret = of_irq_get_byname(np, "pme"); |
||
105 | + if (ret > 0) { |
||
106 | + irqs[PCIE_PORT_SERVICE_PME_SHIFT] = ret; |
||
107 | + count++; |
||
108 | + } |
||
109 | + } |
||
110 | + |
||
111 | + /* TODO: add more service interrupts if there it is in the device tree*/ |
||
112 | + |
||
113 | + return count; |
||
114 | +} |
||
115 | + |
||
116 | +/* |
||
117 | * We don't use this to fix the device, but initialisation of it. |
||
118 | * It's not the correct use for this, but it works. |
||
119 | * Note that the arbiter/ISA bridge appears to be buggy, specifically in |
||
120 | --- a/arch/arm64/kernel/pci.c |
||
121 | +++ b/arch/arm64/kernel/pci.c |
||
122 | @@ -17,6 +17,8 @@ |
||
123 | #include <linux/mm.h> |
||
124 | #include <linux/of_pci.h> |
||
125 | #include <linux/of_platform.h> |
||
126 | +#include <linux/of_irq.h> |
||
127 | +#include <linux/pcieport_if.h> |
||
128 | #include <linux/pci.h> |
||
129 | #include <linux/pci-acpi.h> |
||
130 | #include <linux/pci-ecam.h> |
||
131 | @@ -36,6 +38,47 @@ int pcibios_alloc_irq(struct pci_dev *de |
||
132 | #endif |
||
133 | |||
134 | /* |
||
135 | + * Check device tree if the service interrupts are there |
||
136 | + */ |
||
137 | +int pcibios_check_service_irqs(struct pci_dev *dev, int *irqs, int mask) |
||
138 | +{ |
||
139 | + int ret, count = 0; |
||
140 | + struct device_node *np = NULL; |
||
141 | + |
||
142 | + if (dev->bus->dev.of_node) |
||
143 | + np = dev->bus->dev.of_node; |
||
144 | + |
||
145 | + if (np == NULL) |
||
146 | + return 0; |
||
147 | + |
||
148 | + if (!IS_ENABLED(CONFIG_OF_IRQ)) |
||
149 | + return 0; |
||
150 | + |
||
151 | + /* If root port doesn't support MSI/MSI-X/INTx in RC mode, |
||
152 | + * request irq for aer |
||
153 | + */ |
||
154 | + if (mask & PCIE_PORT_SERVICE_AER) { |
||
155 | + ret = of_irq_get_byname(np, "aer"); |
||
156 | + if (ret > 0) { |
||
157 | + irqs[PCIE_PORT_SERVICE_AER_SHIFT] = ret; |
||
158 | + count++; |
||
159 | + } |
||
160 | + } |
||
161 | + |
||
162 | + if (mask & PCIE_PORT_SERVICE_PME) { |
||
163 | + ret = of_irq_get_byname(np, "pme"); |
||
164 | + if (ret > 0) { |
||
165 | + irqs[PCIE_PORT_SERVICE_PME_SHIFT] = ret; |
||
166 | + count++; |
||
167 | + } |
||
168 | + } |
||
169 | + |
||
170 | + /* TODO: add more service interrupts if there it is in the device tree*/ |
||
171 | + |
||
172 | + return count; |
||
173 | +} |
||
174 | + |
||
175 | +/* |
||
176 | * raw_pci_read/write - Platform-specific PCI config space access. |
||
177 | */ |
||
178 | int raw_pci_read(unsigned int domain, unsigned int bus, |
||
179 | --- a/drivers/misc/pci_endpoint_test.c |
||
180 | +++ b/drivers/misc/pci_endpoint_test.c |
||
181 | @@ -97,6 +97,8 @@ struct pci_endpoint_test { |
||
182 | struct miscdevice miscdev; |
||
183 | enum pci_barno test_reg_bar; |
||
184 | size_t alignment; |
||
185 | + char name[20]; |
||
186 | + int irq_num; |
||
187 | }; |
||
188 | |||
189 | struct pci_endpoint_test_data { |
||
190 | @@ -454,9 +456,7 @@ static int pci_endpoint_test_probe(struc |
||
191 | { |
||
192 | int i; |
||
193 | int err; |
||
194 | - int irq = 0; |
||
195 | int id; |
||
196 | - char name[20]; |
||
197 | enum pci_barno bar; |
||
198 | void __iomem *base; |
||
199 | struct device *dev = &pdev->dev; |
||
200 | @@ -501,19 +501,19 @@ static int pci_endpoint_test_probe(struc |
||
201 | pci_set_master(pdev); |
||
202 | |||
203 | if (!no_msi) { |
||
204 | - irq = pci_alloc_irq_vectors(pdev, 1, 32, PCI_IRQ_MSI); |
||
205 | - if (irq < 0) |
||
206 | + test->irq_num = pci_alloc_irq_vectors(pdev, 1, 32, PCI_IRQ_MSI); |
||
207 | + if (test->irq_num < 0) |
||
208 | dev_err(dev, "failed to get MSI interrupts\n"); |
||
209 | } |
||
210 | |||
211 | - err = devm_request_irq(dev, pdev->irq, pci_endpoint_test_irqhandler, |
||
212 | + err = request_irq(pdev->irq, pci_endpoint_test_irqhandler, |
||
213 | IRQF_SHARED, DRV_MODULE_NAME, test); |
||
214 | if (err) { |
||
215 | dev_err(dev, "failed to request IRQ %d\n", pdev->irq); |
||
216 | goto err_disable_msi; |
||
217 | } |
||
218 | |||
219 | - for (i = 1; i < irq; i++) { |
||
220 | + for (i = 1; i < test->irq_num; i++) { |
||
221 | err = devm_request_irq(dev, pdev->irq + i, |
||
222 | pci_endpoint_test_irqhandler, |
||
223 | IRQF_SHARED, DRV_MODULE_NAME, test); |
||
224 | @@ -548,10 +548,10 @@ static int pci_endpoint_test_probe(struc |
||
225 | goto err_iounmap; |
||
226 | } |
||
227 | |||
228 | - snprintf(name, sizeof(name), DRV_MODULE_NAME ".%d", id); |
||
229 | + snprintf(test->name, sizeof(test->name), DRV_MODULE_NAME ".%d", id); |
||
230 | misc_device = &test->miscdev; |
||
231 | misc_device->minor = MISC_DYNAMIC_MINOR; |
||
232 | - misc_device->name = name; |
||
233 | + misc_device->name = test->name; |
||
234 | misc_device->fops = &pci_endpoint_test_fops, |
||
235 | |||
236 | err = misc_register(misc_device); |
||
237 | @@ -584,6 +584,7 @@ err_disable_pdev: |
||
238 | static void pci_endpoint_test_remove(struct pci_dev *pdev) |
||
239 | { |
||
240 | int id; |
||
241 | + int i; |
||
242 | enum pci_barno bar; |
||
243 | struct pci_endpoint_test *test = pci_get_drvdata(pdev); |
||
244 | struct miscdevice *misc_device = &test->miscdev; |
||
245 | @@ -599,6 +600,8 @@ static void pci_endpoint_test_remove(str |
||
246 | if (test->bar[bar]) |
||
247 | pci_iounmap(pdev, test->bar[bar]); |
||
248 | } |
||
249 | + for (i = 0; i < test->irq_num; i++) |
||
250 | + free_irq(pdev->irq + i, test); |
||
251 | pci_disable_msi(pdev); |
||
252 | pci_release_regions(pdev); |
||
253 | pci_disable_device(pdev); |
||
254 | @@ -607,6 +610,7 @@ static void pci_endpoint_test_remove(str |
||
255 | static const struct pci_device_id pci_endpoint_test_tbl[] = { |
||
256 | { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA74x) }, |
||
257 | { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA72x) }, |
||
258 | + { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, PCI_ANY_ID) }, |
||
259 | { } |
||
260 | }; |
||
261 | MODULE_DEVICE_TABLE(pci, pci_endpoint_test_tbl); |
||
262 | --- a/drivers/pci/dwc/Kconfig |
||
263 | +++ b/drivers/pci/dwc/Kconfig |
||
264 | @@ -111,6 +111,14 @@ config PCI_LAYERSCAPE |
||
265 | help |
||
266 | Say Y here if you want PCIe controller support on Layerscape SoCs. |
||
267 | |||
268 | +config PCI_LAYERSCAPE_EP |
||
269 | + bool "PCI layerscape Endpoint Mode" |
||
270 | + depends on PCI_ENDPOINT |
||
271 | + select PCIE_DW_EP |
||
272 | + help |
||
273 | + Enables support for the PCIe controller in the layerscape SoC to work in |
||
274 | + endpoint mode. |
||
275 | + |
||
276 | config PCI_HISI |
||
277 | depends on OF && ARM64 |
||
278 | bool "HiSilicon Hip05 and Hip06 SoCs PCIe controllers" |
||
279 | --- a/drivers/pci/dwc/pci-layerscape.c |
||
280 | +++ b/drivers/pci/dwc/pci-layerscape.c |
||
281 | @@ -33,8 +33,15 @@ |
||
282 | |||
283 | /* PEX Internal Configuration Registers */ |
||
284 | #define PCIE_STRFMR1 0x71c /* Symbol Timer & Filter Mask Register1 */ |
||
285 | +#define PCIE_ABSERR 0x8d0 /* Bridge Slave Error Response Register */ |
||
286 | +#define PCIE_ABSERR_SETTING 0x9401 /* Forward error of non-posted request */ |
||
287 | |||
288 | +#define PCIE_DBI2_BASE 0x1000 /* DBI2 base address*/ |
||
289 | +#define PCIE_MSI_MSG_DATA_OFF 0x5c /* MSI Data register address*/ |
||
290 | +#define PCIE_MSI_OB_SIZE 4096 |
||
291 | +#define PCIE_MSI_ADDR_OFFSET (1024 * 1024) |
||
292 | #define PCIE_IATU_NUM 6 |
||
293 | +#define PCIE_EP_ADDR_SPACE_SIZE 0x100000000 |
||
294 | |||
295 | struct ls_pcie_drvdata { |
||
296 | u32 lut_offset; |
||
297 | @@ -44,12 +51,20 @@ struct ls_pcie_drvdata { |
||
298 | const struct dw_pcie_ops *dw_pcie_ops; |
||
299 | }; |
||
300 | |||
301 | +struct ls_pcie_ep { |
||
302 | + dma_addr_t msi_phys_addr; |
||
303 | + void __iomem *msi_virt_addr; |
||
304 | + u64 msi_msg_addr; |
||
305 | + u16 msi_msg_data; |
||
306 | +}; |
||
307 | + |
||
308 | struct ls_pcie { |
||
309 | struct dw_pcie *pci; |
||
310 | void __iomem *lut; |
||
311 | struct regmap *scfg; |
||
312 | const struct ls_pcie_drvdata *drvdata; |
||
313 | int index; |
||
314 | + struct ls_pcie_ep *pcie_ep; |
||
315 | }; |
||
316 | |||
317 | #define to_ls_pcie(x) dev_get_drvdata((x)->dev) |
||
318 | @@ -124,6 +139,14 @@ static int ls_pcie_link_up(struct dw_pci |
||
319 | return 1; |
||
320 | } |
||
321 | |||
322 | +/* Forward error response of outbound non-posted requests */ |
||
323 | +static void ls_pcie_fix_error_response(struct ls_pcie *pcie) |
||
324 | +{ |
||
325 | + struct dw_pcie *pci = pcie->pci; |
||
326 | + |
||
327 | + iowrite32(PCIE_ABSERR_SETTING, pci->dbi_base + PCIE_ABSERR); |
||
328 | +} |
||
329 | + |
||
330 | static int ls_pcie_host_init(struct pcie_port *pp) |
||
331 | { |
||
332 | struct dw_pcie *pci = to_dw_pcie_from_pp(pp); |
||
333 | @@ -135,6 +158,7 @@ static int ls_pcie_host_init(struct pcie |
||
334 | * dw_pcie_setup_rc() will reconfigure the outbound windows. |
||
335 | */ |
||
336 | ls_pcie_disable_outbound_atus(pcie); |
||
337 | + ls_pcie_fix_error_response(pcie); |
||
338 | |||
339 | dw_pcie_dbi_ro_wr_en(pci); |
||
340 | ls_pcie_clear_multifunction(pcie); |
||
341 | @@ -253,6 +277,7 @@ static struct ls_pcie_drvdata ls2088_drv |
||
342 | }; |
||
343 | |||
344 | static const struct of_device_id ls_pcie_of_match[] = { |
||
345 | + { .compatible = "fsl,ls1012a-pcie", .data = &ls1046_drvdata }, |
||
346 | { .compatible = "fsl,ls1021a-pcie", .data = &ls1021_drvdata }, |
||
347 | { .compatible = "fsl,ls1043a-pcie", .data = &ls1043_drvdata }, |
||
348 | { .compatible = "fsl,ls1046a-pcie", .data = &ls1046_drvdata }, |
||
349 | @@ -263,6 +288,99 @@ static const struct of_device_id ls_pcie |
||
350 | { }, |
||
351 | }; |
||
352 | |||
353 | +static void ls_pcie_raise_msi_irq(struct ls_pcie_ep *pcie_ep) |
||
354 | +{ |
||
355 | + iowrite32(pcie_ep->msi_msg_data, pcie_ep->msi_virt_addr); |
||
356 | +} |
||
357 | + |
||
358 | +static int ls_pcie_raise_irq(struct dw_pcie_ep *ep, |
||
359 | + enum pci_epc_irq_type type, u8 interrupt_num) |
||
360 | +{ |
||
361 | + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); |
||
362 | + struct ls_pcie *pcie = to_ls_pcie(pci); |
||
363 | + struct ls_pcie_ep *pcie_ep = pcie->pcie_ep; |
||
364 | + u32 free_win; |
||
365 | + |
||
366 | + /* get the msi message address and msi message data */ |
||
367 | + pcie_ep->msi_msg_addr = ioread32(pci->dbi_base + MSI_MESSAGE_ADDR_L32) | |
||
368 | + (((u64)ioread32(pci->dbi_base + MSI_MESSAGE_ADDR_U32)) << 32); |
||
369 | + pcie_ep->msi_msg_data = ioread16(pci->dbi_base + PCIE_MSI_MSG_DATA_OFF); |
||
370 | + |
||
371 | + /* request and config the outband window for msi */ |
||
372 | + free_win = find_first_zero_bit(&ep->ob_window_map, |
||
373 | + sizeof(ep->ob_window_map)); |
||
374 | + if (free_win >= ep->num_ob_windows) { |
||
375 | + dev_err(pci->dev, "no free outbound window\n"); |
||
376 | + return -ENOMEM; |
||
377 | + } |
||
378 | + |
||
379 | + dw_pcie_prog_outbound_atu(pci, free_win, PCIE_ATU_TYPE_MEM, |
||
380 | + pcie_ep->msi_phys_addr, |
||
381 | + pcie_ep->msi_msg_addr, |
||
382 | + PCIE_MSI_OB_SIZE); |
||
383 | + |
||
384 | + set_bit(free_win, &ep->ob_window_map); |
||
385 | + |
||
386 | + /* generate the msi interrupt */ |
||
387 | + ls_pcie_raise_msi_irq(pcie_ep); |
||
388 | + |
||
389 | + /* release the outband window of msi */ |
||
390 | + dw_pcie_disable_atu(pci, free_win, DW_PCIE_REGION_OUTBOUND); |
||
391 | + clear_bit(free_win, &ep->ob_window_map); |
||
392 | + |
||
393 | + return 0; |
||
394 | +} |
||
395 | + |
||
396 | +static struct dw_pcie_ep_ops pcie_ep_ops = { |
||
397 | + .raise_irq = ls_pcie_raise_irq, |
||
398 | +}; |
||
399 | + |
||
400 | +static int __init ls_add_pcie_ep(struct ls_pcie *pcie, |
||
401 | + struct platform_device *pdev) |
||
402 | +{ |
||
403 | + struct dw_pcie *pci = pcie->pci; |
||
404 | + struct device *dev = pci->dev; |
||
405 | + struct dw_pcie_ep *ep; |
||
406 | + struct ls_pcie_ep *pcie_ep; |
||
407 | + struct resource *cfg_res; |
||
408 | + int ret; |
||
409 | + |
||
410 | + ep = &pci->ep; |
||
411 | + ep->ops = &pcie_ep_ops; |
||
412 | + |
||
413 | + pcie_ep = devm_kzalloc(dev, sizeof(*pcie_ep), GFP_KERNEL); |
||
414 | + if (!pcie_ep) |
||
415 | + return -ENOMEM; |
||
416 | + |
||
417 | + pcie->pcie_ep = pcie_ep; |
||
418 | + |
||
419 | + cfg_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config"); |
||
420 | + if (cfg_res) { |
||
421 | + ep->phys_base = cfg_res->start; |
||
422 | + ep->addr_size = PCIE_EP_ADDR_SPACE_SIZE; |
||
423 | + } else { |
||
424 | + dev_err(dev, "missing *config* space\n"); |
||
425 | + return -ENODEV; |
||
426 | + } |
||
427 | + |
||
428 | + pcie_ep->msi_phys_addr = ep->phys_base + PCIE_MSI_ADDR_OFFSET; |
||
429 | + |
||
430 | + pcie_ep->msi_virt_addr = ioremap(pcie_ep->msi_phys_addr, |
||
431 | + PCIE_MSI_OB_SIZE); |
||
432 | + if (!pcie_ep->msi_virt_addr) { |
||
433 | + dev_err(dev, "failed to map MSI outbound region\n"); |
||
434 | + return -ENOMEM; |
||
435 | + } |
||
436 | + |
||
437 | + ret = dw_pcie_ep_init(ep); |
||
438 | + if (ret) { |
||
439 | + dev_err(dev, "failed to initialize endpoint\n"); |
||
440 | + return ret; |
||
441 | + } |
||
442 | + |
||
443 | + return 0; |
||
444 | +} |
||
445 | + |
||
446 | static int __init ls_add_pcie_port(struct ls_pcie *pcie) |
||
447 | { |
||
448 | struct dw_pcie *pci = pcie->pci; |
||
449 | @@ -309,18 +427,18 @@ static int __init ls_pcie_probe(struct p |
||
450 | if (IS_ERR(pci->dbi_base)) |
||
451 | return PTR_ERR(pci->dbi_base); |
||
452 | |||
453 | - pcie->lut = pci->dbi_base + pcie->drvdata->lut_offset; |
||
454 | + pci->dbi_base2 = pci->dbi_base + PCIE_DBI2_BASE; |
||
455 | |||
456 | - if (!ls_pcie_is_bridge(pcie)) |
||
457 | - return -ENODEV; |
||
458 | + pcie->lut = pci->dbi_base + pcie->drvdata->lut_offset; |
||
459 | |||
460 | platform_set_drvdata(pdev, pcie); |
||
461 | |||
462 | - ret = ls_add_pcie_port(pcie); |
||
463 | - if (ret < 0) |
||
464 | - return ret; |
||
465 | + if (!ls_pcie_is_bridge(pcie)) |
||
466 | + ret = ls_add_pcie_ep(pcie, pdev); |
||
467 | + else |
||
468 | + ret = ls_add_pcie_port(pcie); |
||
469 | |||
470 | - return 0; |
||
471 | + return ret; |
||
472 | } |
||
473 | |||
474 | static struct platform_driver ls_pcie_driver = { |
||
475 | --- a/drivers/pci/endpoint/functions/pci-epf-test.c |
||
476 | +++ b/drivers/pci/endpoint/functions/pci-epf-test.c |
||
477 | @@ -471,7 +471,7 @@ static int pci_epf_test_probe(struct pci |
||
478 | const struct pci_epf_device_id *match; |
||
479 | struct pci_epf_test_data *data; |
||
480 | enum pci_barno test_reg_bar = BAR_0; |
||
481 | - bool linkup_notifier = true; |
||
482 | + bool linkup_notifier = false; |
||
483 | |||
484 | match = pci_epf_match_device(pci_epf_test_ids, epf); |
||
485 | data = (struct pci_epf_test_data *)match->driver_data; |
||
486 | --- a/drivers/pci/endpoint/pci-epf-core.c |
||
487 | +++ b/drivers/pci/endpoint/pci-epf-core.c |
||
488 | @@ -104,8 +104,8 @@ void pci_epf_free_space(struct pci_epf * |
||
489 | if (!addr) |
||
490 | return; |
||
491 | |||
492 | - dma_free_coherent(dev, epf->bar[bar].size, addr, |
||
493 | - epf->bar[bar].phys_addr); |
||
494 | + free_pages((unsigned long)addr, |
||
495 | + get_order(epf->bar[bar].size)); |
||
496 | |||
497 | epf->bar[bar].phys_addr = 0; |
||
498 | epf->bar[bar].size = 0; |
||
499 | @@ -129,7 +129,9 @@ void *pci_epf_alloc_space(struct pci_epf |
||
500 | size = 128; |
||
501 | size = roundup_pow_of_two(size); |
||
502 | |||
503 | - space = dma_alloc_coherent(dev, size, &phys_addr, GFP_KERNEL); |
||
504 | + space = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, |
||
505 | + get_order(size)); |
||
506 | + phys_addr = virt_to_phys(space); |
||
507 | if (!space) { |
||
508 | dev_err(dev, "failed to allocate mem space\n"); |
||
509 | return NULL; |
||
510 | --- a/drivers/pci/pcie/portdrv_core.c |
||
511 | +++ b/drivers/pci/pcie/portdrv_core.c |
||
512 | @@ -45,6 +45,20 @@ static void release_pcie_device(struct d |
||
513 | } |
||
514 | |||
515 | /** |
||
516 | + * pcibios_check_service_irqs - check irqs in the device tree |
||
517 | + * @dev: PCI Express port to handle |
||
518 | + * @irqs: Array of irqs to populate |
||
519 | + * @mask: Bitmask of port capabilities returned by get_port_device_capability() |
||
520 | + * |
||
521 | + * Return value: 0 means no service irqs in the device tree |
||
522 | + * |
||
523 | + */ |
||
524 | +int __weak pcibios_check_service_irqs(struct pci_dev *dev, int *irqs, int mask) |
||
525 | +{ |
||
526 | + return 0; |
||
527 | +} |
||
528 | + |
||
529 | +/** |
||
530 | * pcie_port_enable_irq_vec - try to set up MSI-X or MSI as interrupt mode |
||
531 | * for given port |
||
532 | * @dev: PCI Express port to handle |
||
533 | @@ -185,10 +199,25 @@ out_free_irqs: |
||
534 | static int pcie_init_service_irqs(struct pci_dev *dev, int *irqs, int mask) |
||
535 | { |
||
536 | int ret, i; |
||
537 | + int irq = -1; |
||
538 | |||
539 | for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) |
||
540 | irqs[i] = -1; |
||
541 | |||
542 | + /* Check if some platforms owns independent irq pins for AER/PME etc. |
||
543 | + * Some platforms may own independent AER/PME interrupts and set |
||
544 | + * them in the device tree file. |
||
545 | + */ |
||
546 | + ret = pcibios_check_service_irqs(dev, irqs, mask); |
||
547 | + if (ret) { |
||
548 | + if (dev->irq) |
||
549 | + irq = dev->irq; |
||
550 | + for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) |
||
551 | + if (irqs[i] == -1 && i != PCIE_PORT_SERVICE_VC_SHIFT) |
||
552 | + irqs[i] = irq; |
||
553 | + return 0; |
||
554 | + } |
||
555 | + |
||
556 | /* |
||
557 | * If we support PME or hotplug, but we can't use MSI/MSI-X for |
||
558 | * them, we have to fall back to INTx or other interrupts, e.g., a |
||
559 | --- a/drivers/pci/quirks.c |
||
560 | +++ b/drivers/pci/quirks.c |
||
561 | @@ -3376,6 +3376,13 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_A |
||
562 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x003c, quirk_no_bus_reset); |
||
563 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0033, quirk_no_bus_reset); |
||
564 | |||
565 | +/* |
||
566 | + * NXP (Freescale Vendor ID) LS1088 chips do not behave correctly after |
||
567 | + * bus reset. Link state of device does not comes UP and so config space |
||
568 | + * never accessible again. |
||
569 | + */ |
||
570 | +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_FREESCALE, 0x80c0, quirk_no_bus_reset); |
||
571 | + |
||
572 | static void quirk_no_pm_reset(struct pci_dev *dev) |
||
573 | { |
||
574 | /* |
||
575 | @@ -4857,3 +4864,11 @@ static void quirk_no_ats(struct pci_dev |
||
576 | /* AMD Stoney platform GPU */ |
||
577 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x98e4, quirk_no_ats); |
||
578 | #endif /* CONFIG_PCI_ATS */ |
||
579 | + |
||
580 | +/* Freescale PCIe doesn't support MSI in RC mode */ |
||
581 | +static void quirk_fsl_no_msi(struct pci_dev *pdev) |
||
582 | +{ |
||
583 | + if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT) |
||
584 | + pdev->no_msi = 1; |
||
585 | +} |
||
586 | +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_FREESCALE, PCI_ANY_ID, quirk_fsl_no_msi); |
||
587 | --- a/include/linux/pci.h |
||
588 | +++ b/include/linux/pci.h |
||
589 | @@ -1944,6 +1944,7 @@ void pcibios_release_device(struct pci_d |
||
590 | void pcibios_penalize_isa_irq(int irq, int active); |
||
591 | int pcibios_alloc_irq(struct pci_dev *dev); |
||
592 | void pcibios_free_irq(struct pci_dev *dev); |
||
593 | +int pcibios_check_service_irqs(struct pci_dev *dev, int *irqs, int mask); |
||
594 | |||
595 | #ifdef CONFIG_HIBERNATE_CALLBACKS |
||
596 | extern struct dev_pm_ops pcibios_pm_ops; |