diff options
Diffstat (limited to 'drivers/pci/dwc/pcie-designware-ep.c')
-rw-r--r-- | drivers/pci/dwc/pcie-designware-ep.c | 61 |
1 files changed, 58 insertions, 3 deletions
diff --git a/drivers/pci/dwc/pcie-designware-ep.c b/drivers/pci/dwc/pcie-designware-ep.c index 7a573d8bb62d..52edcb19da36 100644 --- a/drivers/pci/dwc/pcie-designware-ep.c +++ b/drivers/pci/dwc/pcie-designware-ep.c @@ -30,13 +30,15 @@ void dw_pcie_ep_linkup(struct dw_pcie_ep *ep) pci_epc_linkup(epc); } -static void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar) +void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar) { u32 reg; reg = PCI_BASE_ADDRESS_0 + (4 * bar); + dw_pcie_dbi_ro_wr_en(pci); dw_pcie_writel_dbi2(pci, reg, 0x0); dw_pcie_writel_dbi(pci, reg, 0x0); + dw_pcie_dbi_ro_wr_dis(pci); } static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no, @@ -45,6 +47,7 @@ static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no, struct dw_pcie_ep *ep = epc_get_drvdata(epc); struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + dw_pcie_dbi_ro_wr_en(pci); dw_pcie_writew_dbi(pci, PCI_VENDOR_ID, hdr->vendorid); dw_pcie_writew_dbi(pci, PCI_DEVICE_ID, hdr->deviceid); dw_pcie_writeb_dbi(pci, PCI_REVISION_ID, hdr->revid); @@ -58,6 +61,7 @@ static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no, dw_pcie_writew_dbi(pci, PCI_SUBSYSTEM_ID, hdr->subsys_id); dw_pcie_writeb_dbi(pci, PCI_INTERRUPT_PIN, hdr->interrupt_pin); + dw_pcie_dbi_ro_wr_dis(pci); return 0; } @@ -144,8 +148,10 @@ static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no, if (ret) return ret; + dw_pcie_dbi_ro_wr_en(pci); dw_pcie_writel_dbi2(pci, reg, size - 1); dw_pcie_writel_dbi(pci, reg, flags); + dw_pcie_dbi_ro_wr_dis(pci); return 0; } @@ -224,8 +230,12 @@ static int dw_pcie_ep_set_msi(struct pci_epc *epc, u8 func_no, u8 encode_int) struct dw_pcie_ep *ep = epc_get_drvdata(epc); struct dw_pcie *pci = to_dw_pcie_from_ep(ep); - val = (encode_int << MSI_CAP_MMC_SHIFT); + val = dw_pcie_readw_dbi(pci, MSI_MESSAGE_CONTROL); + val &= ~MSI_CAP_MMC_MASK; + val |= (encode_int << MSI_CAP_MMC_SHIFT) & MSI_CAP_MMC_MASK; + dw_pcie_dbi_ro_wr_en(pci); dw_pcie_writew_dbi(pci, MSI_MESSAGE_CONTROL, val); + dw_pcie_dbi_ro_wr_dis(pci); return 0; } @@ -238,7 +248,7 @@ static int dw_pcie_ep_raise_irq(struct pci_epc *epc, u8 func_no, if (!ep->ops->raise_irq) return -EINVAL; - return ep->ops->raise_irq(ep, type, interrupt_num); + return ep->ops->raise_irq(ep, func_no, type, interrupt_num); } static void dw_pcie_ep_stop(struct pci_epc *epc) @@ -276,10 +286,48 @@ static const struct pci_epc_ops epc_ops = { .stop = dw_pcie_ep_stop, }; +int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, + u8 interrupt_num) +{ + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + struct pci_epc *epc = ep->epc; + u16 msg_ctrl, msg_data; + u32 msg_addr_lower, msg_addr_upper; + u64 msg_addr; + bool has_upper; + int ret; + + /* Raise MSI per the PCI Local Bus Specification Revision 3.0, 6.8.1. */ + msg_ctrl = dw_pcie_readw_dbi(pci, MSI_MESSAGE_CONTROL); + has_upper = !!(msg_ctrl & PCI_MSI_FLAGS_64BIT); + msg_addr_lower = dw_pcie_readl_dbi(pci, MSI_MESSAGE_ADDR_L32); + if (has_upper) { + msg_addr_upper = dw_pcie_readl_dbi(pci, MSI_MESSAGE_ADDR_U32); + msg_data = dw_pcie_readw_dbi(pci, MSI_MESSAGE_DATA_64); + } else { + msg_addr_upper = 0; + msg_data = dw_pcie_readw_dbi(pci, MSI_MESSAGE_DATA_32); + } + msg_addr = ((u64) msg_addr_upper) << 32 | msg_addr_lower; + ret = dw_pcie_ep_map_addr(epc, func_no, ep->msi_mem_phys, msg_addr, + epc->mem->page_size); + if (ret) + return ret; + + writel(msg_data | (interrupt_num - 1), ep->msi_mem); + + dw_pcie_ep_unmap_addr(epc, func_no, ep->msi_mem_phys); + + return 0; +} + void dw_pcie_ep_exit(struct dw_pcie_ep *ep) { struct pci_epc *epc = ep->epc; + pci_epc_mem_free_addr(epc, ep->msi_mem_phys, ep->msi_mem, + epc->mem->page_size); + pci_epc_mem_exit(epc); } @@ -335,6 +383,13 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) return ret; } + ep->msi_mem = pci_epc_mem_alloc_addr(epc, &ep->msi_mem_phys, + epc->mem->page_size); + if (!ep->msi_mem) { + dev_err(dev, "Failed to reserve memory for MSI\n"); + return -ENOMEM; + } + ep->epc = epc; epc_set_drvdata(epc, ep); dw_pcie_setup(pci); |