summaryrefslogtreecommitdiff
path: root/drivers/pci/host/pcie-designware.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/host/pcie-designware.c')
-rw-r--r--drivers/pci/host/pcie-designware.c257
1 files changed, 8 insertions, 249 deletions
diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index e33b68b..c10e9ac 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -11,11 +11,8 @@
* published by the Free Software Foundation.
*/
-#include <linux/irq.h>
-#include <linux/irqdomain.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/msi.h>
#include <linux/of_address.h>
#include <linux/pci.h>
#include <linux/pci_regs.h>
@@ -67,7 +64,7 @@
static struct hw_pci dw_pci;
-static unsigned long global_io_offset;
+unsigned long global_io_offset;
static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys)
{
@@ -118,8 +115,8 @@ static inline void dw_pcie_writel_rc(struct pcie_port *pp, u32 val, u32 reg)
writel(val, pp->dbi_base + reg);
}
-static int dw_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
- u32 *val)
+int dw_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
+ u32 *val)
{
int ret;
@@ -131,8 +128,8 @@ static int dw_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
return ret;
}
-static int dw_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
- u32 val)
+int dw_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
+ u32 val)
{
int ret;
@@ -145,205 +142,6 @@ static int dw_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
return ret;
}
-static struct irq_chip dw_msi_irq_chip = {
- .name = "PCI-MSI",
- .irq_enable = unmask_msi_irq,
- .irq_disable = mask_msi_irq,
- .irq_mask = mask_msi_irq,
- .irq_unmask = unmask_msi_irq,
-};
-
-/* MSI int handler */
-void dw_handle_msi_irq(struct pcie_port *pp)
-{
- unsigned long val;
- int i, pos, irq;
-
- for (i = 0; i < MAX_MSI_CTRLS; i++) {
- dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_STATUS + i * 12, 4,
- (u32 *)&val);
- if (val) {
- pos = 0;
- while ((pos = find_next_bit(&val, 32, pos)) != 32) {
- irq = irq_find_mapping(pp->irq_domain,
- i * 32 + pos);
- generic_handle_irq(irq);
- pos++;
- }
- }
- dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_STATUS + i * 12, 4, val);
- }
-}
-
-void dw_pcie_msi_init(struct pcie_port *pp)
-{
- pp->msi_data = __get_free_pages(GFP_KERNEL, 0);
-
- /* program the msi_data */
- dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_LO, 4,
- virt_to_phys((void *)pp->msi_data));
- dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_HI, 4, 0);
-}
-
-static int find_valid_pos0(struct pcie_port *pp, int msgvec, int pos, int *pos0)
-{
- int flag = 1;
-
- do {
- pos = find_next_zero_bit(pp->msi_irq_in_use,
- MAX_MSI_IRQS, pos);
- /*if you have reached to the end then get out from here.*/
- if (pos == MAX_MSI_IRQS)
- return -ENOSPC;
- /*
- * Check if this position is at correct offset.nvec is always a
- * power of two. pos0 must be nvec bit aligned.
- */
- if (pos % msgvec)
- pos += msgvec - (pos % msgvec);
- else
- flag = 0;
- } while (flag);
-
- *pos0 = pos;
- return 0;
-}
-
-static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
-{
- int res, bit, irq, pos0, pos1, i;
- u32 val;
- struct pcie_port *pp = sys_to_pcie(desc->dev->bus->sysdata);
-
- if (!pp) {
- BUG();
- return -EINVAL;
- }
-
- pos0 = find_first_zero_bit(pp->msi_irq_in_use,
- MAX_MSI_IRQS);
- if (pos0 % no_irqs) {
- if (find_valid_pos0(pp, no_irqs, pos0, &pos0))
- goto no_valid_irq;
- }
- if (no_irqs > 1) {
- pos1 = find_next_bit(pp->msi_irq_in_use,
- MAX_MSI_IRQS, pos0);
- /* there must be nvec number of consecutive free bits */
- while ((pos1 - pos0) < no_irqs) {
- if (find_valid_pos0(pp, no_irqs, pos1, &pos0))
- goto no_valid_irq;
- pos1 = find_next_bit(pp->msi_irq_in_use,
- MAX_MSI_IRQS, pos0);
- }
- }
-
- irq = irq_find_mapping(pp->irq_domain, pos0);
- if (!irq)
- goto no_valid_irq;
-
- i = 0;
- while (i < no_irqs) {
- set_bit(pos0 + i, pp->msi_irq_in_use);
- irq_alloc_descs((irq + i), (irq + i), 1, 0);
- irq_set_msi_desc(irq + i, desc);
- /*Enable corresponding interrupt in MSI interrupt controller */
- res = ((pos0 + i) / 32) * 12;
- bit = (pos0 + i) % 32;
- dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
- val |= 1 << bit;
- dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
- i++;
- }
-
- *pos = pos0;
- return irq;
-
-no_valid_irq:
- *pos = pos0;
- return -ENOSPC;
-}
-
-static void clear_irq(unsigned int irq)
-{
- int res, bit, val, pos;
- struct irq_desc *desc;
- struct msi_desc *msi;
- struct pcie_port *pp;
- struct irq_data *data = irq_get_irq_data(irq);
-
- /* get the port structure */
- desc = irq_to_desc(irq);
- msi = irq_desc_get_msi_desc(desc);
- pp = sys_to_pcie(msi->dev->bus->sysdata);
- if (!pp) {
- BUG();
- return;
- }
-
- pos = data->hwirq;
-
- irq_free_desc(irq);
-
- clear_bit(pos, pp->msi_irq_in_use);
-
- /* Disable corresponding interrupt on MSI interrupt controller */
- res = (pos / 32) * 12;
- bit = pos % 32;
- dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
- val &= ~(1 << bit);
- dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
-}
-
-static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
- struct msi_desc *desc)
-{
- int irq, pos, msgvec;
- u16 msg_ctr;
- struct msi_msg msg;
- struct pcie_port *pp = sys_to_pcie(pdev->bus->sysdata);
-
- if (!pp) {
- BUG();
- return -EINVAL;
- }
-
- pci_read_config_word(pdev, desc->msi_attrib.pos+PCI_MSI_FLAGS,
- &msg_ctr);
- msgvec = (msg_ctr&PCI_MSI_FLAGS_QSIZE) >> 4;
- if (msgvec == 0)
- msgvec = (msg_ctr & PCI_MSI_FLAGS_QMASK) >> 1;
- if (msgvec > 5)
- msgvec = 0;
-
- irq = assign_irq((1 << msgvec), desc, &pos);
- if (irq < 0)
- return irq;
-
- msg_ctr &= ~PCI_MSI_FLAGS_QSIZE;
- msg_ctr |= msgvec << 4;
- pci_write_config_word(pdev, desc->msi_attrib.pos + PCI_MSI_FLAGS,
- msg_ctr);
- desc->msi_attrib.multiple = msgvec;
-
- msg.address_lo = virt_to_phys((void *)pp->msi_data);
- msg.address_hi = 0x0;
- msg.data = pos;
- write_msi_msg(irq, &msg);
-
- return 0;
-}
-
-static void dw_msi_teardown_irq(struct msi_chip *chip, unsigned int irq)
-{
- clear_irq(irq);
-}
-
-static struct msi_chip dw_pcie_msi_chip = {
- .setup_irq = dw_msi_setup_irq,
- .teardown_irq = dw_msi_teardown_irq,
-};
-
int dw_pcie_link_up(struct pcie_port *pp)
{
if (pp->ops->link_up)
@@ -352,27 +150,12 @@ int dw_pcie_link_up(struct pcie_port *pp)
return 0;
}
-static int dw_pcie_msi_map(struct irq_domain *domain, unsigned int irq,
- irq_hw_number_t hwirq)
-{
- irq_set_chip_and_handler(irq, &dw_msi_irq_chip, handle_simple_irq);
- irq_set_chip_data(irq, domain->host_data);
- set_irq_flags(irq, IRQF_VALID);
-
- return 0;
-}
-
-static const struct irq_domain_ops msi_domain_ops = {
- .map = dw_pcie_msi_map,
-};
-
int __init dw_pcie_host_init(struct pcie_port *pp)
{
struct device_node *np = pp->dev->of_node;
struct of_pci_range range;
struct of_pci_range_parser parser;
u32 val;
- int i;
if (of_pci_range_parser_init(&parser, np)) {
dev_err(pp->dev, "missing ranges property\n");
@@ -440,19 +223,6 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
return -EINVAL;
}
- if (IS_ENABLED(CONFIG_PCI_MSI)) {
- pp->irq_domain = irq_domain_add_linear(pp->dev->of_node,
- MAX_MSI_IRQS, &msi_domain_ops,
- &dw_pcie_msi_chip);
- if (!pp->irq_domain) {
- dev_err(pp->dev, "irq domain init failed\n");
- return -ENXIO;
- }
-
- for (i = 0; i < MAX_MSI_IRQS; i++)
- irq_create_mapping(pp->irq_domain, i);
- }
-
if (pp->ops->host_init)
pp->ops->host_init(pp);
@@ -668,7 +438,7 @@ static struct pci_ops dw_pcie_ops = {
.write = dw_pcie_wr_conf,
};
-static int dw_pcie_setup(int nr, struct pci_sys_data *sys)
+int dw_pcie_setup(int nr, struct pci_sys_data *sys)
{
struct pcie_port *pp;
@@ -691,7 +461,7 @@ static int dw_pcie_setup(int nr, struct pci_sys_data *sys)
return 1;
}
-static struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
+struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
{
struct pci_bus *bus;
struct pcie_port *pp = sys_to_pcie(sys);
@@ -708,28 +478,17 @@ static struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
return bus;
}
-static int dw_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+int dw_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
{
struct pcie_port *pp = sys_to_pcie(dev->bus->sysdata);
return pp->irq;
}
-static void dw_pcie_add_bus(struct pci_bus *bus)
-{
- if (IS_ENABLED(CONFIG_PCI_MSI)) {
- struct pcie_port *pp = sys_to_pcie(bus->sysdata);
-
- dw_pcie_msi_chip.dev = pp->dev;
- bus->msi = &dw_pcie_msi_chip;
- }
-}
-
static struct hw_pci dw_pci = {
.setup = dw_pcie_setup,
.scan = dw_pcie_scan_bus,
.map_irq = dw_pcie_map_irq,
- .add_bus = dw_pcie_add_bus,
};
void dw_pcie_setup_rc(struct pcie_port *pp)