diff options
author | Bjorn Helgaas <bhelgaas@google.com> | 2018-08-15 15:59:11 -0400 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2018-08-15 15:59:11 -0400 |
commit | 0c38011aba35b2cdca263c0ba4d28e2e727b5acb (patch) | |
tree | a16ebcc1edc74087fb074368f00f23cb25c99508 /drivers/pci/controller/dwc | |
parent | 37f0e311bca66e9fe74703887c9bb4965914cabf (diff) | |
parent | 15c972dfb3954569e7d17ebadf1b10d0a0c3baa3 (diff) |
Merge branch 'remotes/lorenzo/pci/dwc'
- Add Kirin MSI support (Xiaowei Song)
- Drop unnecessary root_bus_nr setting from exynos, imx6, keystone,
armada8k, artpec6, designware-plat, histb, qcom, spear13xx (Shawn Guo)
- Move link notification settings from DesignWare core to individual
drivers (Gustavo Pimentel)
- Add endpoint library MSI-X interfaces (Gustavo Pimentel)
- Correct signature of endpoint library IRQ interfaces (Gustavo Pimentel)
- Add DesignWare endpoint library MSI-X callbacks (Gustavo Pimentel)
- Add endpoint library MSI-X test support (Gustavo Pimentel)
* remotes/lorenzo/pci/dwc:
PCI: endpoint: Add MSI set maximum restriction
tools: PCI: Add MSI-X support
pci_endpoint_test: Add 2 ioctl commands
pci-epf-test/pci_endpoint_test: Add MSI-X support
pci-epf-test/pci_endpoint_test: Use irq_type module parameter
pci-epf-test/pci_endpoint_test: Cleanup PCI_ENDPOINT_TEST memspace
PCI: dwc: Add legacy interrupt callback handler
PCI: dwc: Rework MSI callbacks handler
PCI: dwc: Add MSI-X callbacks handler
PCI: Update xxx_pcie_ep_raise_irq() and pci_epc_raise_irq() signatures
PCI: endpoint: Add MSI-X interfaces
PCI: dwc: Fix EP link notification implementation
PCI: spear13xx: Drop unnecessary root_bus_nr setting
PCI: qcom: Drop unnecessary root_bus_nr setting
PCI: histb: Drop unnecessary root_bus_nr setting
PCI: designware-plat: Drop unnecessary root_bus_nr setting
PCI: artpec6: Drop unnecessary root_bus_nr setting
PCI: armada8k: Drop unnecessary root_bus_nr setting
PCI: keystone: Drop unnecessary root_bus_nr setting
PCI: imx6: Drop unnecessary root_bus_nr setting
PCI: exynos: Drop unnecessary root_bus_nr setting
PCI: kirin: Add MSI support
Diffstat (limited to 'drivers/pci/controller/dwc')
-rw-r--r-- | drivers/pci/controller/dwc/pci-dra7xx.c | 2 | ||||
-rw-r--r-- | drivers/pci/controller/dwc/pci-exynos.c | 1 | ||||
-rw-r--r-- | drivers/pci/controller/dwc/pci-imx6.c | 1 | ||||
-rw-r--r-- | drivers/pci/controller/dwc/pci-keystone.c | 1 | ||||
-rw-r--r-- | drivers/pci/controller/dwc/pcie-armada8k.c | 1 | ||||
-rw-r--r-- | drivers/pci/controller/dwc/pcie-artpec6.c | 3 | ||||
-rw-r--r-- | drivers/pci/controller/dwc/pcie-designware-ep.c | 210 | ||||
-rw-r--r-- | drivers/pci/controller/dwc/pcie-designware-plat.c | 12 | ||||
-rw-r--r-- | drivers/pci/controller/dwc/pcie-designware.h | 29 | ||||
-rw-r--r-- | drivers/pci/controller/dwc/pcie-histb.c | 1 | ||||
-rw-r--r-- | drivers/pci/controller/dwc/pcie-kirin.c | 28 | ||||
-rw-r--r-- | drivers/pci/controller/dwc/pcie-qcom.c | 1 | ||||
-rw-r--r-- | drivers/pci/controller/dwc/pcie-spear13xx.c | 1 |
13 files changed, 240 insertions, 51 deletions
diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c index 345aab56ce8b..ce9224a36f62 100644 --- a/drivers/pci/controller/dwc/pci-dra7xx.c +++ b/drivers/pci/controller/dwc/pci-dra7xx.c | |||
@@ -370,7 +370,7 @@ static void dra7xx_pcie_raise_msi_irq(struct dra7xx_pcie *dra7xx, | |||
370 | } | 370 | } |
371 | 371 | ||
372 | static int dra7xx_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no, | 372 | static int dra7xx_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no, |
373 | enum pci_epc_irq_type type, u8 interrupt_num) | 373 | enum pci_epc_irq_type type, u16 interrupt_num) |
374 | { | 374 | { |
375 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | 375 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); |
376 | struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci); | 376 | struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci); |
diff --git a/drivers/pci/controller/dwc/pci-exynos.c b/drivers/pci/controller/dwc/pci-exynos.c index 4cc1e5df8c79..cee5f2f590e2 100644 --- a/drivers/pci/controller/dwc/pci-exynos.c +++ b/drivers/pci/controller/dwc/pci-exynos.c | |||
@@ -421,7 +421,6 @@ static int __init exynos_add_pcie_port(struct exynos_pcie *ep, | |||
421 | } | 421 | } |
422 | } | 422 | } |
423 | 423 | ||
424 | pp->root_bus_nr = -1; | ||
425 | pp->ops = &exynos_pcie_host_ops; | 424 | pp->ops = &exynos_pcie_host_ops; |
426 | 425 | ||
427 | ret = dw_pcie_host_init(pp); | 426 | ret = dw_pcie_host_init(pp); |
diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 80f604602783..4a9a673b4777 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c | |||
@@ -667,7 +667,6 @@ static int imx6_add_pcie_port(struct imx6_pcie *imx6_pcie, | |||
667 | } | 667 | } |
668 | } | 668 | } |
669 | 669 | ||
670 | pp->root_bus_nr = -1; | ||
671 | pp->ops = &imx6_pcie_host_ops; | 670 | pp->ops = &imx6_pcie_host_ops; |
672 | 671 | ||
673 | ret = dw_pcie_host_init(pp); | 672 | ret = dw_pcie_host_init(pp); |
diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 3722a5f31e5e..e88bd221fffe 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c | |||
@@ -347,7 +347,6 @@ static int __init ks_add_pcie_port(struct keystone_pcie *ks_pcie, | |||
347 | } | 347 | } |
348 | } | 348 | } |
349 | 349 | ||
350 | pp->root_bus_nr = -1; | ||
351 | pp->ops = &keystone_pcie_host_ops; | 350 | pp->ops = &keystone_pcie_host_ops; |
352 | ret = ks_dw_pcie_host_init(ks_pcie, ks_pcie->msi_intc_np); | 351 | ret = ks_dw_pcie_host_init(ks_pcie, ks_pcie->msi_intc_np); |
353 | if (ret) { | 352 | if (ret) { |
diff --git a/drivers/pci/controller/dwc/pcie-armada8k.c b/drivers/pci/controller/dwc/pcie-armada8k.c index 072fd7ecc29f..0c389a30ef5d 100644 --- a/drivers/pci/controller/dwc/pcie-armada8k.c +++ b/drivers/pci/controller/dwc/pcie-armada8k.c | |||
@@ -172,7 +172,6 @@ static int armada8k_add_pcie_port(struct armada8k_pcie *pcie, | |||
172 | struct device *dev = &pdev->dev; | 172 | struct device *dev = &pdev->dev; |
173 | int ret; | 173 | int ret; |
174 | 174 | ||
175 | pp->root_bus_nr = -1; | ||
176 | pp->ops = &armada8k_pcie_host_ops; | 175 | pp->ops = &armada8k_pcie_host_ops; |
177 | 176 | ||
178 | pp->irq = platform_get_irq(pdev, 0); | 177 | pp->irq = platform_get_irq(pdev, 0); |
diff --git a/drivers/pci/controller/dwc/pcie-artpec6.c b/drivers/pci/controller/dwc/pcie-artpec6.c index 321b56cfd5d0..dba83abfe764 100644 --- a/drivers/pci/controller/dwc/pcie-artpec6.c +++ b/drivers/pci/controller/dwc/pcie-artpec6.c | |||
@@ -399,7 +399,6 @@ static int artpec6_add_pcie_port(struct artpec6_pcie *artpec6_pcie, | |||
399 | } | 399 | } |
400 | } | 400 | } |
401 | 401 | ||
402 | pp->root_bus_nr = -1; | ||
403 | pp->ops = &artpec6_pcie_host_ops; | 402 | pp->ops = &artpec6_pcie_host_ops; |
404 | 403 | ||
405 | ret = dw_pcie_host_init(pp); | 404 | ret = dw_pcie_host_init(pp); |
@@ -428,7 +427,7 @@ static void artpec6_pcie_ep_init(struct dw_pcie_ep *ep) | |||
428 | } | 427 | } |
429 | 428 | ||
430 | static int artpec6_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no, | 429 | static int artpec6_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no, |
431 | enum pci_epc_irq_type type, u8 interrupt_num) | 430 | enum pci_epc_irq_type type, u16 interrupt_num) |
432 | { | 431 | { |
433 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | 432 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); |
434 | 433 | ||
diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 8650416f6f9e..1e7b02221eac 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c | |||
@@ -40,6 +40,39 @@ void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar) | |||
40 | __dw_pcie_ep_reset_bar(pci, bar, 0); | 40 | __dw_pcie_ep_reset_bar(pci, bar, 0); |
41 | } | 41 | } |
42 | 42 | ||
43 | static u8 __dw_pcie_ep_find_next_cap(struct dw_pcie *pci, u8 cap_ptr, | ||
44 | u8 cap) | ||
45 | { | ||
46 | u8 cap_id, next_cap_ptr; | ||
47 | u16 reg; | ||
48 | |||
49 | reg = dw_pcie_readw_dbi(pci, cap_ptr); | ||
50 | next_cap_ptr = (reg & 0xff00) >> 8; | ||
51 | cap_id = (reg & 0x00ff); | ||
52 | |||
53 | if (!next_cap_ptr || cap_id > PCI_CAP_ID_MAX) | ||
54 | return 0; | ||
55 | |||
56 | if (cap_id == cap) | ||
57 | return cap_ptr; | ||
58 | |||
59 | return __dw_pcie_ep_find_next_cap(pci, next_cap_ptr, cap); | ||
60 | } | ||
61 | |||
62 | static u8 dw_pcie_ep_find_capability(struct dw_pcie *pci, u8 cap) | ||
63 | { | ||
64 | u8 next_cap_ptr; | ||
65 | u16 reg; | ||
66 | |||
67 | reg = dw_pcie_readw_dbi(pci, PCI_CAPABILITY_LIST); | ||
68 | next_cap_ptr = (reg & 0x00ff); | ||
69 | |||
70 | if (!next_cap_ptr) | ||
71 | return 0; | ||
72 | |||
73 | return __dw_pcie_ep_find_next_cap(pci, next_cap_ptr, cap); | ||
74 | } | ||
75 | |||
43 | static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no, | 76 | static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no, |
44 | struct pci_epf_header *hdr) | 77 | struct pci_epf_header *hdr) |
45 | { | 78 | { |
@@ -213,36 +246,84 @@ static int dw_pcie_ep_map_addr(struct pci_epc *epc, u8 func_no, | |||
213 | 246 | ||
214 | static int dw_pcie_ep_get_msi(struct pci_epc *epc, u8 func_no) | 247 | static int dw_pcie_ep_get_msi(struct pci_epc *epc, u8 func_no) |
215 | { | 248 | { |
216 | int val; | ||
217 | struct dw_pcie_ep *ep = epc_get_drvdata(epc); | 249 | struct dw_pcie_ep *ep = epc_get_drvdata(epc); |
218 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | 250 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); |
251 | u32 val, reg; | ||
252 | |||
253 | if (!ep->msi_cap) | ||
254 | return -EINVAL; | ||
255 | |||
256 | reg = ep->msi_cap + PCI_MSI_FLAGS; | ||
257 | val = dw_pcie_readw_dbi(pci, reg); | ||
258 | if (!(val & PCI_MSI_FLAGS_ENABLE)) | ||
259 | return -EINVAL; | ||
260 | |||
261 | val = (val & PCI_MSI_FLAGS_QSIZE) >> 4; | ||
262 | |||
263 | return val; | ||
264 | } | ||
265 | |||
266 | static int dw_pcie_ep_set_msi(struct pci_epc *epc, u8 func_no, u8 interrupts) | ||
267 | { | ||
268 | struct dw_pcie_ep *ep = epc_get_drvdata(epc); | ||
269 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | ||
270 | u32 val, reg; | ||
271 | |||
272 | if (!ep->msi_cap) | ||
273 | return -EINVAL; | ||
274 | |||
275 | reg = ep->msi_cap + PCI_MSI_FLAGS; | ||
276 | val = dw_pcie_readw_dbi(pci, reg); | ||
277 | val &= ~PCI_MSI_FLAGS_QMASK; | ||
278 | val |= (interrupts << 1) & PCI_MSI_FLAGS_QMASK; | ||
279 | dw_pcie_dbi_ro_wr_en(pci); | ||
280 | dw_pcie_writew_dbi(pci, reg, val); | ||
281 | dw_pcie_dbi_ro_wr_dis(pci); | ||
282 | |||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | static int dw_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no) | ||
287 | { | ||
288 | struct dw_pcie_ep *ep = epc_get_drvdata(epc); | ||
289 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | ||
290 | u32 val, reg; | ||
219 | 291 | ||
220 | val = dw_pcie_readw_dbi(pci, MSI_MESSAGE_CONTROL); | 292 | if (!ep->msix_cap) |
221 | if (!(val & MSI_CAP_MSI_EN_MASK)) | ||
222 | return -EINVAL; | 293 | return -EINVAL; |
223 | 294 | ||
224 | val = (val & MSI_CAP_MME_MASK) >> MSI_CAP_MME_SHIFT; | 295 | reg = ep->msix_cap + PCI_MSIX_FLAGS; |
296 | val = dw_pcie_readw_dbi(pci, reg); | ||
297 | if (!(val & PCI_MSIX_FLAGS_ENABLE)) | ||
298 | return -EINVAL; | ||
299 | |||
300 | val &= PCI_MSIX_FLAGS_QSIZE; | ||
301 | |||
225 | return val; | 302 | return val; |
226 | } | 303 | } |
227 | 304 | ||
228 | static int dw_pcie_ep_set_msi(struct pci_epc *epc, u8 func_no, u8 encode_int) | 305 | static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u16 interrupts) |
229 | { | 306 | { |
230 | int val; | ||
231 | struct dw_pcie_ep *ep = epc_get_drvdata(epc); | 307 | struct dw_pcie_ep *ep = epc_get_drvdata(epc); |
232 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | 308 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); |
309 | u32 val, reg; | ||
310 | |||
311 | if (!ep->msix_cap) | ||
312 | return -EINVAL; | ||
233 | 313 | ||
234 | val = dw_pcie_readw_dbi(pci, MSI_MESSAGE_CONTROL); | 314 | reg = ep->msix_cap + PCI_MSIX_FLAGS; |
235 | val &= ~MSI_CAP_MMC_MASK; | 315 | val = dw_pcie_readw_dbi(pci, reg); |
236 | val |= (encode_int << MSI_CAP_MMC_SHIFT) & MSI_CAP_MMC_MASK; | 316 | val &= ~PCI_MSIX_FLAGS_QSIZE; |
317 | val |= interrupts; | ||
237 | dw_pcie_dbi_ro_wr_en(pci); | 318 | dw_pcie_dbi_ro_wr_en(pci); |
238 | dw_pcie_writew_dbi(pci, MSI_MESSAGE_CONTROL, val); | 319 | dw_pcie_writew_dbi(pci, reg, val); |
239 | dw_pcie_dbi_ro_wr_dis(pci); | 320 | dw_pcie_dbi_ro_wr_dis(pci); |
240 | 321 | ||
241 | return 0; | 322 | return 0; |
242 | } | 323 | } |
243 | 324 | ||
244 | static int dw_pcie_ep_raise_irq(struct pci_epc *epc, u8 func_no, | 325 | static int dw_pcie_ep_raise_irq(struct pci_epc *epc, u8 func_no, |
245 | enum pci_epc_irq_type type, u8 interrupt_num) | 326 | enum pci_epc_irq_type type, u16 interrupt_num) |
246 | { | 327 | { |
247 | struct dw_pcie_ep *ep = epc_get_drvdata(epc); | 328 | struct dw_pcie_ep *ep = epc_get_drvdata(epc); |
248 | 329 | ||
@@ -282,32 +363,52 @@ static const struct pci_epc_ops epc_ops = { | |||
282 | .unmap_addr = dw_pcie_ep_unmap_addr, | 363 | .unmap_addr = dw_pcie_ep_unmap_addr, |
283 | .set_msi = dw_pcie_ep_set_msi, | 364 | .set_msi = dw_pcie_ep_set_msi, |
284 | .get_msi = dw_pcie_ep_get_msi, | 365 | .get_msi = dw_pcie_ep_get_msi, |
366 | .set_msix = dw_pcie_ep_set_msix, | ||
367 | .get_msix = dw_pcie_ep_get_msix, | ||
285 | .raise_irq = dw_pcie_ep_raise_irq, | 368 | .raise_irq = dw_pcie_ep_raise_irq, |
286 | .start = dw_pcie_ep_start, | 369 | .start = dw_pcie_ep_start, |
287 | .stop = dw_pcie_ep_stop, | 370 | .stop = dw_pcie_ep_stop, |
288 | }; | 371 | }; |
289 | 372 | ||
373 | int dw_pcie_ep_raise_legacy_irq(struct dw_pcie_ep *ep, u8 func_no) | ||
374 | { | ||
375 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | ||
376 | struct device *dev = pci->dev; | ||
377 | |||
378 | dev_err(dev, "EP cannot trigger legacy IRQs\n"); | ||
379 | |||
380 | return -EINVAL; | ||
381 | } | ||
382 | |||
290 | int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, | 383 | int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, |
291 | u8 interrupt_num) | 384 | u8 interrupt_num) |
292 | { | 385 | { |
293 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | 386 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); |
294 | struct pci_epc *epc = ep->epc; | 387 | struct pci_epc *epc = ep->epc; |
295 | u16 msg_ctrl, msg_data; | 388 | u16 msg_ctrl, msg_data; |
296 | u32 msg_addr_lower, msg_addr_upper; | 389 | u32 msg_addr_lower, msg_addr_upper, reg; |
297 | u64 msg_addr; | 390 | u64 msg_addr; |
298 | bool has_upper; | 391 | bool has_upper; |
299 | int ret; | 392 | int ret; |
300 | 393 | ||
394 | if (!ep->msi_cap) | ||
395 | return -EINVAL; | ||
396 | |||
301 | /* Raise MSI per the PCI Local Bus Specification Revision 3.0, 6.8.1. */ | 397 | /* Raise MSI per the PCI Local Bus Specification Revision 3.0, 6.8.1. */ |
302 | msg_ctrl = dw_pcie_readw_dbi(pci, MSI_MESSAGE_CONTROL); | 398 | reg = ep->msi_cap + PCI_MSI_FLAGS; |
399 | msg_ctrl = dw_pcie_readw_dbi(pci, reg); | ||
303 | has_upper = !!(msg_ctrl & PCI_MSI_FLAGS_64BIT); | 400 | has_upper = !!(msg_ctrl & PCI_MSI_FLAGS_64BIT); |
304 | msg_addr_lower = dw_pcie_readl_dbi(pci, MSI_MESSAGE_ADDR_L32); | 401 | reg = ep->msi_cap + PCI_MSI_ADDRESS_LO; |
402 | msg_addr_lower = dw_pcie_readl_dbi(pci, reg); | ||
305 | if (has_upper) { | 403 | if (has_upper) { |
306 | msg_addr_upper = dw_pcie_readl_dbi(pci, MSI_MESSAGE_ADDR_U32); | 404 | reg = ep->msi_cap + PCI_MSI_ADDRESS_HI; |
307 | msg_data = dw_pcie_readw_dbi(pci, MSI_MESSAGE_DATA_64); | 405 | msg_addr_upper = dw_pcie_readl_dbi(pci, reg); |
406 | reg = ep->msi_cap + PCI_MSI_DATA_64; | ||
407 | msg_data = dw_pcie_readw_dbi(pci, reg); | ||
308 | } else { | 408 | } else { |
309 | msg_addr_upper = 0; | 409 | msg_addr_upper = 0; |
310 | msg_data = dw_pcie_readw_dbi(pci, MSI_MESSAGE_DATA_32); | 410 | reg = ep->msi_cap + PCI_MSI_DATA_32; |
411 | msg_data = dw_pcie_readw_dbi(pci, reg); | ||
311 | } | 412 | } |
312 | msg_addr = ((u64) msg_addr_upper) << 32 | msg_addr_lower; | 413 | msg_addr = ((u64) msg_addr_upper) << 32 | msg_addr_lower; |
313 | ret = dw_pcie_ep_map_addr(epc, func_no, ep->msi_mem_phys, msg_addr, | 414 | ret = dw_pcie_ep_map_addr(epc, func_no, ep->msi_mem_phys, msg_addr, |
@@ -322,6 +423,64 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, | |||
322 | return 0; | 423 | return 0; |
323 | } | 424 | } |
324 | 425 | ||
426 | int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no, | ||
427 | u16 interrupt_num) | ||
428 | { | ||
429 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | ||
430 | struct pci_epc *epc = ep->epc; | ||
431 | u16 tbl_offset, bir; | ||
432 | u32 bar_addr_upper, bar_addr_lower; | ||
433 | u32 msg_addr_upper, msg_addr_lower; | ||
434 | u32 reg, msg_data, vec_ctrl; | ||
435 | u64 tbl_addr, msg_addr, reg_u64; | ||
436 | void __iomem *msix_tbl; | ||
437 | int ret; | ||
438 | |||
439 | reg = ep->msix_cap + PCI_MSIX_TABLE; | ||
440 | tbl_offset = dw_pcie_readl_dbi(pci, reg); | ||
441 | bir = (tbl_offset & PCI_MSIX_TABLE_BIR); | ||
442 | tbl_offset &= PCI_MSIX_TABLE_OFFSET; | ||
443 | tbl_offset >>= 3; | ||
444 | |||
445 | reg = PCI_BASE_ADDRESS_0 + (4 * bir); | ||
446 | bar_addr_upper = 0; | ||
447 | bar_addr_lower = dw_pcie_readl_dbi(pci, reg); | ||
448 | reg_u64 = (bar_addr_lower & PCI_BASE_ADDRESS_MEM_TYPE_MASK); | ||
449 | if (reg_u64 == PCI_BASE_ADDRESS_MEM_TYPE_64) | ||
450 | bar_addr_upper = dw_pcie_readl_dbi(pci, reg + 4); | ||
451 | |||
452 | tbl_addr = ((u64) bar_addr_upper) << 32 | bar_addr_lower; | ||
453 | tbl_addr += (tbl_offset + ((interrupt_num - 1) * PCI_MSIX_ENTRY_SIZE)); | ||
454 | tbl_addr &= PCI_BASE_ADDRESS_MEM_MASK; | ||
455 | |||
456 | msix_tbl = ioremap_nocache(ep->phys_base + tbl_addr, | ||
457 | PCI_MSIX_ENTRY_SIZE); | ||
458 | if (!msix_tbl) | ||
459 | return -EINVAL; | ||
460 | |||
461 | msg_addr_lower = readl(msix_tbl + PCI_MSIX_ENTRY_LOWER_ADDR); | ||
462 | msg_addr_upper = readl(msix_tbl + PCI_MSIX_ENTRY_UPPER_ADDR); | ||
463 | msg_addr = ((u64) msg_addr_upper) << 32 | msg_addr_lower; | ||
464 | msg_data = readl(msix_tbl + PCI_MSIX_ENTRY_DATA); | ||
465 | vec_ctrl = readl(msix_tbl + PCI_MSIX_ENTRY_VECTOR_CTRL); | ||
466 | |||
467 | iounmap(msix_tbl); | ||
468 | |||
469 | if (vec_ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT) | ||
470 | return -EPERM; | ||
471 | |||
472 | ret = dw_pcie_ep_map_addr(epc, func_no, ep->msi_mem_phys, msg_addr, | ||
473 | epc->mem->page_size); | ||
474 | if (ret) | ||
475 | return ret; | ||
476 | |||
477 | writel(msg_data, ep->msi_mem); | ||
478 | |||
479 | dw_pcie_ep_unmap_addr(epc, func_no, ep->msi_mem_phys); | ||
480 | |||
481 | return 0; | ||
482 | } | ||
483 | |||
325 | void dw_pcie_ep_exit(struct dw_pcie_ep *ep) | 484 | void dw_pcie_ep_exit(struct dw_pcie_ep *ep) |
326 | { | 485 | { |
327 | struct pci_epc *epc = ep->epc; | 486 | struct pci_epc *epc = ep->epc; |
@@ -386,15 +545,18 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) | |||
386 | return -ENOMEM; | 545 | return -ENOMEM; |
387 | ep->outbound_addr = addr; | 546 | ep->outbound_addr = addr; |
388 | 547 | ||
389 | if (ep->ops->ep_init) | ||
390 | ep->ops->ep_init(ep); | ||
391 | |||
392 | epc = devm_pci_epc_create(dev, &epc_ops); | 548 | epc = devm_pci_epc_create(dev, &epc_ops); |
393 | if (IS_ERR(epc)) { | 549 | if (IS_ERR(epc)) { |
394 | dev_err(dev, "Failed to create epc device\n"); | 550 | dev_err(dev, "Failed to create epc device\n"); |
395 | return PTR_ERR(epc); | 551 | return PTR_ERR(epc); |
396 | } | 552 | } |
397 | 553 | ||
554 | ep->epc = epc; | ||
555 | epc_set_drvdata(epc, ep); | ||
556 | |||
557 | if (ep->ops->ep_init) | ||
558 | ep->ops->ep_init(ep); | ||
559 | |||
398 | ret = of_property_read_u8(np, "max-functions", &epc->max_functions); | 560 | ret = of_property_read_u8(np, "max-functions", &epc->max_functions); |
399 | if (ret < 0) | 561 | if (ret < 0) |
400 | epc->max_functions = 1; | 562 | epc->max_functions = 1; |
@@ -409,15 +571,13 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) | |||
409 | ep->msi_mem = pci_epc_mem_alloc_addr(epc, &ep->msi_mem_phys, | 571 | ep->msi_mem = pci_epc_mem_alloc_addr(epc, &ep->msi_mem_phys, |
410 | epc->mem->page_size); | 572 | epc->mem->page_size); |
411 | if (!ep->msi_mem) { | 573 | if (!ep->msi_mem) { |
412 | dev_err(dev, "Failed to reserve memory for MSI\n"); | 574 | dev_err(dev, "Failed to reserve memory for MSI/MSI-X\n"); |
413 | return -ENOMEM; | 575 | return -ENOMEM; |
414 | } | 576 | } |
577 | ep->msi_cap = dw_pcie_ep_find_capability(pci, PCI_CAP_ID_MSI); | ||
415 | 578 | ||
416 | epc->features = EPC_FEATURE_NO_LINKUP_NOTIFIER; | 579 | ep->msix_cap = dw_pcie_ep_find_capability(pci, PCI_CAP_ID_MSIX); |
417 | EPC_FEATURE_SET_BAR(epc->features, BAR_0); | ||
418 | 580 | ||
419 | ep->epc = epc; | ||
420 | epc_set_drvdata(epc, ep); | ||
421 | dw_pcie_setup(pci); | 581 | dw_pcie_setup(pci); |
422 | 582 | ||
423 | return 0; | 583 | return 0; |
diff --git a/drivers/pci/controller/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c index 5937fed4c938..c12bf794d69c 100644 --- a/drivers/pci/controller/dwc/pcie-designware-plat.c +++ b/drivers/pci/controller/dwc/pcie-designware-plat.c | |||
@@ -70,24 +70,29 @@ static const struct dw_pcie_ops dw_pcie_ops = { | |||
70 | static void dw_plat_pcie_ep_init(struct dw_pcie_ep *ep) | 70 | static void dw_plat_pcie_ep_init(struct dw_pcie_ep *ep) |
71 | { | 71 | { |
72 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | 72 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); |
73 | struct pci_epc *epc = ep->epc; | ||
73 | enum pci_barno bar; | 74 | enum pci_barno bar; |
74 | 75 | ||
75 | for (bar = BAR_0; bar <= BAR_5; bar++) | 76 | for (bar = BAR_0; bar <= BAR_5; bar++) |
76 | dw_pcie_ep_reset_bar(pci, bar); | 77 | dw_pcie_ep_reset_bar(pci, bar); |
78 | |||
79 | epc->features |= EPC_FEATURE_NO_LINKUP_NOTIFIER; | ||
80 | epc->features |= EPC_FEATURE_MSIX_AVAILABLE; | ||
77 | } | 81 | } |
78 | 82 | ||
79 | static int dw_plat_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, | 83 | static int dw_plat_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, |
80 | enum pci_epc_irq_type type, | 84 | enum pci_epc_irq_type type, |
81 | u8 interrupt_num) | 85 | u16 interrupt_num) |
82 | { | 86 | { |
83 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | 87 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); |
84 | 88 | ||
85 | switch (type) { | 89 | switch (type) { |
86 | case PCI_EPC_IRQ_LEGACY: | 90 | case PCI_EPC_IRQ_LEGACY: |
87 | dev_err(pci->dev, "EP cannot trigger legacy IRQs\n"); | 91 | return dw_pcie_ep_raise_legacy_irq(ep, func_no); |
88 | return -EINVAL; | ||
89 | case PCI_EPC_IRQ_MSI: | 92 | case PCI_EPC_IRQ_MSI: |
90 | return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num); | 93 | return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num); |
94 | case PCI_EPC_IRQ_MSIX: | ||
95 | return dw_pcie_ep_raise_msix_irq(ep, func_no, interrupt_num); | ||
91 | default: | 96 | default: |
92 | dev_err(pci->dev, "UNKNOWN IRQ type\n"); | 97 | dev_err(pci->dev, "UNKNOWN IRQ type\n"); |
93 | } | 98 | } |
@@ -118,7 +123,6 @@ static int dw_plat_add_pcie_port(struct dw_plat_pcie *dw_plat_pcie, | |||
118 | return pp->msi_irq; | 123 | return pp->msi_irq; |
119 | } | 124 | } |
120 | 125 | ||
121 | pp->root_bus_nr = -1; | ||
122 | pp->ops = &dw_plat_pcie_host_ops; | 126 | pp->ops = &dw_plat_pcie_host_ops; |
123 | 127 | ||
124 | ret = dw_pcie_host_init(pp); | 128 | ret = dw_pcie_host_init(pp); |
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index bee4e2535a61..96126fd8403c 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h | |||
@@ -96,17 +96,6 @@ | |||
96 | #define PCIE_GET_ATU_INB_UNR_REG_OFFSET(region) \ | 96 | #define PCIE_GET_ATU_INB_UNR_REG_OFFSET(region) \ |
97 | ((0x3 << 20) | ((region) << 9) | (0x1 << 8)) | 97 | ((0x3 << 20) | ((region) << 9) | (0x1 << 8)) |
98 | 98 | ||
99 | #define MSI_MESSAGE_CONTROL 0x52 | ||
100 | #define MSI_CAP_MMC_SHIFT 1 | ||
101 | #define MSI_CAP_MMC_MASK (7 << MSI_CAP_MMC_SHIFT) | ||
102 | #define MSI_CAP_MME_SHIFT 4 | ||
103 | #define MSI_CAP_MSI_EN_MASK 0x1 | ||
104 | #define MSI_CAP_MME_MASK (7 << MSI_CAP_MME_SHIFT) | ||
105 | #define MSI_MESSAGE_ADDR_L32 0x54 | ||
106 | #define MSI_MESSAGE_ADDR_U32 0x58 | ||
107 | #define MSI_MESSAGE_DATA_32 0x58 | ||
108 | #define MSI_MESSAGE_DATA_64 0x5C | ||
109 | |||
110 | #define MAX_MSI_IRQS 256 | 99 | #define MAX_MSI_IRQS 256 |
111 | #define MAX_MSI_IRQS_PER_CTRL 32 | 100 | #define MAX_MSI_IRQS_PER_CTRL 32 |
112 | #define MAX_MSI_CTRLS (MAX_MSI_IRQS / MAX_MSI_IRQS_PER_CTRL) | 101 | #define MAX_MSI_CTRLS (MAX_MSI_IRQS / MAX_MSI_IRQS_PER_CTRL) |
@@ -191,7 +180,7 @@ enum dw_pcie_as_type { | |||
191 | struct dw_pcie_ep_ops { | 180 | struct dw_pcie_ep_ops { |
192 | void (*ep_init)(struct dw_pcie_ep *ep); | 181 | void (*ep_init)(struct dw_pcie_ep *ep); |
193 | int (*raise_irq)(struct dw_pcie_ep *ep, u8 func_no, | 182 | int (*raise_irq)(struct dw_pcie_ep *ep, u8 func_no, |
194 | enum pci_epc_irq_type type, u8 interrupt_num); | 183 | enum pci_epc_irq_type type, u16 interrupt_num); |
195 | }; | 184 | }; |
196 | 185 | ||
197 | struct dw_pcie_ep { | 186 | struct dw_pcie_ep { |
@@ -208,6 +197,8 @@ struct dw_pcie_ep { | |||
208 | u32 num_ob_windows; | 197 | u32 num_ob_windows; |
209 | void __iomem *msi_mem; | 198 | void __iomem *msi_mem; |
210 | phys_addr_t msi_mem_phys; | 199 | phys_addr_t msi_mem_phys; |
200 | u8 msi_cap; /* MSI capability offset */ | ||
201 | u8 msix_cap; /* MSI-X capability offset */ | ||
211 | }; | 202 | }; |
212 | 203 | ||
213 | struct dw_pcie_ops { | 204 | struct dw_pcie_ops { |
@@ -357,8 +348,11 @@ static inline int dw_pcie_allocate_domains(struct pcie_port *pp) | |||
357 | void dw_pcie_ep_linkup(struct dw_pcie_ep *ep); | 348 | void dw_pcie_ep_linkup(struct dw_pcie_ep *ep); |
358 | int dw_pcie_ep_init(struct dw_pcie_ep *ep); | 349 | int dw_pcie_ep_init(struct dw_pcie_ep *ep); |
359 | void dw_pcie_ep_exit(struct dw_pcie_ep *ep); | 350 | void dw_pcie_ep_exit(struct dw_pcie_ep *ep); |
351 | int dw_pcie_ep_raise_legacy_irq(struct dw_pcie_ep *ep, u8 func_no); | ||
360 | int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, | 352 | int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, |
361 | u8 interrupt_num); | 353 | u8 interrupt_num); |
354 | int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no, | ||
355 | u16 interrupt_num); | ||
362 | void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar); | 356 | void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar); |
363 | #else | 357 | #else |
364 | static inline void dw_pcie_ep_linkup(struct dw_pcie_ep *ep) | 358 | static inline void dw_pcie_ep_linkup(struct dw_pcie_ep *ep) |
@@ -374,12 +368,23 @@ static inline void dw_pcie_ep_exit(struct dw_pcie_ep *ep) | |||
374 | { | 368 | { |
375 | } | 369 | } |
376 | 370 | ||
371 | static inline int dw_pcie_ep_raise_legacy_irq(struct dw_pcie_ep *ep, u8 func_no) | ||
372 | { | ||
373 | return 0; | ||
374 | } | ||
375 | |||
377 | static inline int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, | 376 | static inline int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, |
378 | u8 interrupt_num) | 377 | u8 interrupt_num) |
379 | { | 378 | { |
380 | return 0; | 379 | return 0; |
381 | } | 380 | } |
382 | 381 | ||
382 | static inline int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no, | ||
383 | u16 interrupt_num) | ||
384 | { | ||
385 | return 0; | ||
386 | } | ||
387 | |||
383 | static inline void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar) | 388 | static inline void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar) |
384 | { | 389 | { |
385 | } | 390 | } |
diff --git a/drivers/pci/controller/dwc/pcie-histb.c b/drivers/pci/controller/dwc/pcie-histb.c index 3611d6ce9a92..7b32e619b959 100644 --- a/drivers/pci/controller/dwc/pcie-histb.c +++ b/drivers/pci/controller/dwc/pcie-histb.c | |||
@@ -420,7 +420,6 @@ static int histb_pcie_probe(struct platform_device *pdev) | |||
420 | phy_init(hipcie->phy); | 420 | phy_init(hipcie->phy); |
421 | } | 421 | } |
422 | 422 | ||
423 | pp->root_bus_nr = -1; | ||
424 | pp->ops = &histb_pcie_host_ops; | 423 | pp->ops = &histb_pcie_host_ops; |
425 | 424 | ||
426 | platform_set_drvdata(pdev, hipcie); | 425 | platform_set_drvdata(pdev, hipcie); |
diff --git a/drivers/pci/controller/dwc/pcie-kirin.c b/drivers/pci/controller/dwc/pcie-kirin.c index d2970a009eb5..5352e0c3be82 100644 --- a/drivers/pci/controller/dwc/pcie-kirin.c +++ b/drivers/pci/controller/dwc/pcie-kirin.c | |||
@@ -430,6 +430,9 @@ static int kirin_pcie_host_init(struct pcie_port *pp) | |||
430 | { | 430 | { |
431 | kirin_pcie_establish_link(pp); | 431 | kirin_pcie_establish_link(pp); |
432 | 432 | ||
433 | if (IS_ENABLED(CONFIG_PCI_MSI)) | ||
434 | dw_pcie_msi_init(pp); | ||
435 | |||
433 | return 0; | 436 | return 0; |
434 | } | 437 | } |
435 | 438 | ||
@@ -445,9 +448,34 @@ static const struct dw_pcie_host_ops kirin_pcie_host_ops = { | |||
445 | .host_init = kirin_pcie_host_init, | 448 | .host_init = kirin_pcie_host_init, |
446 | }; | 449 | }; |
447 | 450 | ||
451 | static int kirin_pcie_add_msi(struct dw_pcie *pci, | ||
452 | struct platform_device *pdev) | ||
453 | { | ||
454 | int irq; | ||
455 | |||
456 | if (IS_ENABLED(CONFIG_PCI_MSI)) { | ||
457 | irq = platform_get_irq(pdev, 0); | ||
458 | if (irq < 0) { | ||
459 | dev_err(&pdev->dev, | ||
460 | "failed to get MSI IRQ (%d)\n", irq); | ||
461 | return irq; | ||
462 | } | ||
463 | |||
464 | pci->pp.msi_irq = irq; | ||
465 | } | ||
466 | |||
467 | return 0; | ||
468 | } | ||
469 | |||
448 | static int __init kirin_add_pcie_port(struct dw_pcie *pci, | 470 | static int __init kirin_add_pcie_port(struct dw_pcie *pci, |
449 | struct platform_device *pdev) | 471 | struct platform_device *pdev) |
450 | { | 472 | { |
473 | int ret; | ||
474 | |||
475 | ret = kirin_pcie_add_msi(pci, pdev); | ||
476 | if (ret) | ||
477 | return ret; | ||
478 | |||
451 | pci->pp.ops = &kirin_pcie_host_ops; | 479 | pci->pp.ops = &kirin_pcie_host_ops; |
452 | 480 | ||
453 | return dw_pcie_host_init(&pci->pp); | 481 | return dw_pcie_host_init(&pci->pp); |
diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index a1d0198081a6..4352c1cb926d 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c | |||
@@ -1251,7 +1251,6 @@ static int qcom_pcie_probe(struct platform_device *pdev) | |||
1251 | if (ret) | 1251 | if (ret) |
1252 | return ret; | 1252 | return ret; |
1253 | 1253 | ||
1254 | pp->root_bus_nr = -1; | ||
1255 | pp->ops = &qcom_pcie_dw_ops; | 1254 | pp->ops = &qcom_pcie_dw_ops; |
1256 | 1255 | ||
1257 | if (IS_ENABLED(CONFIG_PCI_MSI)) { | 1256 | if (IS_ENABLED(CONFIG_PCI_MSI)) { |
diff --git a/drivers/pci/controller/dwc/pcie-spear13xx.c b/drivers/pci/controller/dwc/pcie-spear13xx.c index ecb58f7b7566..7d0cdfd8138b 100644 --- a/drivers/pci/controller/dwc/pcie-spear13xx.c +++ b/drivers/pci/controller/dwc/pcie-spear13xx.c | |||
@@ -210,7 +210,6 @@ static int spear13xx_add_pcie_port(struct spear13xx_pcie *spear13xx_pcie, | |||
210 | return ret; | 210 | return ret; |
211 | } | 211 | } |
212 | 212 | ||
213 | pp->root_bus_nr = -1; | ||
214 | pp->ops = &spear13xx_pcie_host_ops; | 213 | pp->ops = &spear13xx_pcie_host_ops; |
215 | 214 | ||
216 | ret = dw_pcie_host_init(pp); | 215 | ret = dw_pcie_host_init(pp); |