aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/controller/dwc
diff options
context:
space:
mode:
authorGustavo Pimentel <gustavo.pimentel@synopsys.com>2018-07-19 04:32:14 -0400
committerLorenzo Pieralisi <lorenzo.pieralisi@arm.com>2018-07-19 06:37:27 -0400
commitbeb4641a787df79a1423a8789d185b6b78fcbfea (patch)
tree3ba6f2780dc71ce4b623e6ea094e3681ad5deed0 /drivers/pci/controller/dwc
parentd3c70a98d7d63cae02d50ebfafea04264a767401 (diff)
PCI: dwc: Add MSI-X callbacks handler
Add PCIe config space capability search function. Add sysfs set/get interface to allow the change of EP MSI-X maximum number. Add EP MSI-X callback for triggering interruptions. Signed-off-by: Gustavo Pimentel <gustavo.pimentel@synopsys.com> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> Acked-by: Kishon Vijay Abraham I <kishon@ti.com>
Diffstat (limited to 'drivers/pci/controller/dwc')
-rw-r--r--drivers/pci/controller/dwc/pcie-designware-ep.c137
-rw-r--r--drivers/pci/controller/dwc/pcie-designware-plat.c2
-rw-r--r--drivers/pci/controller/dwc/pcie-designware.h10
3 files changed, 148 insertions, 1 deletions
diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
index 69d039de2af6..23be2c0249ee 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
43static 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
62static 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
43static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no, 76static 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{
@@ -241,6 +274,45 @@ static int dw_pcie_ep_set_msi(struct pci_epc *epc, u8 func_no, u8 encode_int)
241 return 0; 274 return 0;
242} 275}
243 276
277static int dw_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no)
278{
279 struct dw_pcie_ep *ep = epc_get_drvdata(epc);
280 struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
281 u32 val, reg;
282
283 if (!ep->msix_cap)
284 return -EINVAL;
285
286 reg = ep->msix_cap + PCI_MSIX_FLAGS;
287 val = dw_pcie_readw_dbi(pci, reg);
288 if (!(val & PCI_MSIX_FLAGS_ENABLE))
289 return -EINVAL;
290
291 val &= PCI_MSIX_FLAGS_QSIZE;
292
293 return val;
294}
295
296static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u16 interrupts)
297{
298 struct dw_pcie_ep *ep = epc_get_drvdata(epc);
299 struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
300 u32 val, reg;
301
302 if (!ep->msix_cap)
303 return -EINVAL;
304
305 reg = ep->msix_cap + PCI_MSIX_FLAGS;
306 val = dw_pcie_readw_dbi(pci, reg);
307 val &= ~PCI_MSIX_FLAGS_QSIZE;
308 val |= interrupts;
309 dw_pcie_dbi_ro_wr_en(pci);
310 dw_pcie_writew_dbi(pci, reg, val);
311 dw_pcie_dbi_ro_wr_dis(pci);
312
313 return 0;
314}
315
244static int dw_pcie_ep_raise_irq(struct pci_epc *epc, u8 func_no, 316static int dw_pcie_ep_raise_irq(struct pci_epc *epc, u8 func_no,
245 enum pci_epc_irq_type type, u16 interrupt_num) 317 enum pci_epc_irq_type type, u16 interrupt_num)
246{ 318{
@@ -282,6 +354,8 @@ static const struct pci_epc_ops epc_ops = {
282 .unmap_addr = dw_pcie_ep_unmap_addr, 354 .unmap_addr = dw_pcie_ep_unmap_addr,
283 .set_msi = dw_pcie_ep_set_msi, 355 .set_msi = dw_pcie_ep_set_msi,
284 .get_msi = dw_pcie_ep_get_msi, 356 .get_msi = dw_pcie_ep_get_msi,
357 .set_msix = dw_pcie_ep_set_msix,
358 .get_msix = dw_pcie_ep_get_msix,
285 .raise_irq = dw_pcie_ep_raise_irq, 359 .raise_irq = dw_pcie_ep_raise_irq,
286 .start = dw_pcie_ep_start, 360 .start = dw_pcie_ep_start,
287 .stop = dw_pcie_ep_stop, 361 .stop = dw_pcie_ep_stop,
@@ -322,6 +396,64 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
322 return 0; 396 return 0;
323} 397}
324 398
399int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
400 u16 interrupt_num)
401{
402 struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
403 struct pci_epc *epc = ep->epc;
404 u16 tbl_offset, bir;
405 u32 bar_addr_upper, bar_addr_lower;
406 u32 msg_addr_upper, msg_addr_lower;
407 u32 reg, msg_data, vec_ctrl;
408 u64 tbl_addr, msg_addr, reg_u64;
409 void __iomem *msix_tbl;
410 int ret;
411
412 reg = ep->msix_cap + PCI_MSIX_TABLE;
413 tbl_offset = dw_pcie_readl_dbi(pci, reg);
414 bir = (tbl_offset & PCI_MSIX_TABLE_BIR);
415 tbl_offset &= PCI_MSIX_TABLE_OFFSET;
416 tbl_offset >>= 3;
417
418 reg = PCI_BASE_ADDRESS_0 + (4 * bir);
419 bar_addr_upper = 0;
420 bar_addr_lower = dw_pcie_readl_dbi(pci, reg);
421 reg_u64 = (bar_addr_lower & PCI_BASE_ADDRESS_MEM_TYPE_MASK);
422 if (reg_u64 == PCI_BASE_ADDRESS_MEM_TYPE_64)
423 bar_addr_upper = dw_pcie_readl_dbi(pci, reg + 4);
424
425 tbl_addr = ((u64) bar_addr_upper) << 32 | bar_addr_lower;
426 tbl_addr += (tbl_offset + ((interrupt_num - 1) * PCI_MSIX_ENTRY_SIZE));
427 tbl_addr &= PCI_BASE_ADDRESS_MEM_MASK;
428
429 msix_tbl = ioremap_nocache(ep->phys_base + tbl_addr,
430 PCI_MSIX_ENTRY_SIZE);
431 if (!msix_tbl)
432 return -EINVAL;
433
434 msg_addr_lower = readl(msix_tbl + PCI_MSIX_ENTRY_LOWER_ADDR);
435 msg_addr_upper = readl(msix_tbl + PCI_MSIX_ENTRY_UPPER_ADDR);
436 msg_addr = ((u64) msg_addr_upper) << 32 | msg_addr_lower;
437 msg_data = readl(msix_tbl + PCI_MSIX_ENTRY_DATA);
438 vec_ctrl = readl(msix_tbl + PCI_MSIX_ENTRY_VECTOR_CTRL);
439
440 iounmap(msix_tbl);
441
442 if (vec_ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT)
443 return -EPERM;
444
445 ret = dw_pcie_ep_map_addr(epc, func_no, ep->msi_mem_phys, msg_addr,
446 epc->mem->page_size);
447 if (ret)
448 return ret;
449
450 writel(msg_data, ep->msi_mem);
451
452 dw_pcie_ep_unmap_addr(epc, func_no, ep->msi_mem_phys);
453
454 return 0;
455}
456
325void dw_pcie_ep_exit(struct dw_pcie_ep *ep) 457void dw_pcie_ep_exit(struct dw_pcie_ep *ep)
326{ 458{
327 struct pci_epc *epc = ep->epc; 459 struct pci_epc *epc = ep->epc;
@@ -412,9 +544,12 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
412 ep->msi_mem = pci_epc_mem_alloc_addr(epc, &ep->msi_mem_phys, 544 ep->msi_mem = pci_epc_mem_alloc_addr(epc, &ep->msi_mem_phys,
413 epc->mem->page_size); 545 epc->mem->page_size);
414 if (!ep->msi_mem) { 546 if (!ep->msi_mem) {
415 dev_err(dev, "Failed to reserve memory for MSI\n"); 547 dev_err(dev, "Failed to reserve memory for MSI/MSI-X\n");
416 return -ENOMEM; 548 return -ENOMEM;
417 } 549 }
550 ep->msi_cap = dw_pcie_ep_find_capability(pci, PCI_CAP_ID_MSI);
551
552 ep->msix_cap = dw_pcie_ep_find_capability(pci, PCI_CAP_ID_MSIX);
418 553
419 dw_pcie_setup(pci); 554 dw_pcie_setup(pci);
420 555
diff --git a/drivers/pci/controller/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c
index cca69ac63319..35d2291c6ba5 100644
--- a/drivers/pci/controller/dwc/pcie-designware-plat.c
+++ b/drivers/pci/controller/dwc/pcie-designware-plat.c
@@ -91,6 +91,8 @@ static int dw_plat_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
91 return -EINVAL; 91 return -EINVAL;
92 case PCI_EPC_IRQ_MSI: 92 case PCI_EPC_IRQ_MSI:
93 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);
94 default: 96 default:
95 dev_err(pci->dev, "UNKNOWN IRQ type\n"); 97 dev_err(pci->dev, "UNKNOWN IRQ type\n");
96 } 98 }
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index 9d581c077329..00ac4197c457 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -208,6 +208,8 @@ struct dw_pcie_ep {
208 u32 num_ob_windows; 208 u32 num_ob_windows;
209 void __iomem *msi_mem; 209 void __iomem *msi_mem;
210 phys_addr_t msi_mem_phys; 210 phys_addr_t msi_mem_phys;
211 u8 msi_cap; /* MSI capability offset */
212 u8 msix_cap; /* MSI-X capability offset */
211}; 213};
212 214
213struct dw_pcie_ops { 215struct dw_pcie_ops {
@@ -359,6 +361,8 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep);
359void dw_pcie_ep_exit(struct dw_pcie_ep *ep); 361void dw_pcie_ep_exit(struct dw_pcie_ep *ep);
360int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, 362int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
361 u8 interrupt_num); 363 u8 interrupt_num);
364int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
365 u16 interrupt_num);
362void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar); 366void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar);
363#else 367#else
364static inline void dw_pcie_ep_linkup(struct dw_pcie_ep *ep) 368static inline void dw_pcie_ep_linkup(struct dw_pcie_ep *ep)
@@ -380,6 +384,12 @@ static inline int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
380 return 0; 384 return 0;
381} 385}
382 386
387static inline int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
388 u16 interrupt_num)
389{
390 return 0;
391}
392
383static inline void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar) 393static inline void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar)
384{ 394{
385} 395}