diff options
author | Bjorn Helgaas <bhelgaas@google.com> | 2014-10-01 16:45:01 -0600 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2014-10-01 16:45:01 -0600 |
commit | b9c9c2558ba366d59dc242872da883a879b8ffc6 (patch) | |
tree | b2c15a99796161df92eb27ce80ec6b52cb7ca12f /drivers/pci | |
parent | 5d85142b9e5264a925e4d582c3b0d7297d9c2713 (diff) | |
parent | c8df6ac9452e8f47a6f660993c526d13e858a6f3 (diff) | |
download | linux-b9c9c2558ba366d59dc242872da883a879b8ffc6.tar.bz2 |
Merge branch 'pci/host-designware' into next
* pci/host-designware:
PCI: designware: Remove open-coded bitmap operations
PCI: designware: Setup and clear exactly one MSI at a time
Conflicts:
drivers/pci/host/pcie-designware.c
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/host/pcie-designware.c | 97 |
1 files changed, 14 insertions, 83 deletions
diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c index f72744599d12..dfed00aa3ac0 100644 --- a/drivers/pci/host/pcie-designware.c +++ b/drivers/pci/host/pcie-designware.c @@ -196,30 +196,6 @@ void dw_pcie_msi_init(struct pcie_port *pp) 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 void dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq) { unsigned int res, bit, val; @@ -238,13 +214,14 @@ static void clear_irq_range(struct pcie_port *pp, unsigned int irq_base, for (i = 0; i < nvec; i++) { irq_set_msi_desc_off(irq_base, i, NULL); - clear_bit(pos + i, pp->msi_irq_in_use); /* Disable corresponding interrupt on MSI controller */ if (pp->ops->msi_clear_irq) pp->ops->msi_clear_irq(pp, pos + i); else dw_pcie_msi_clear_irq(pp, pos + i); } + + bitmap_release_region(pp->msi_irq_in_use, pos, order_base_2(nvec)); } static void dw_pcie_msi_set_irq(struct pcie_port *pp, int irq) @@ -260,26 +237,13 @@ static void dw_pcie_msi_set_irq(struct pcie_port *pp, int irq) static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos) { - int irq, pos0, pos1, i; + int irq, pos0, i; struct pcie_port *pp = sys_to_pcie(desc->dev->bus->sysdata); - 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); - } - } + pos0 = bitmap_find_free_region(pp->msi_irq_in_use, MAX_MSI_IRQS, + order_base_2(no_irqs)); + if (pos0 < 0) + goto no_valid_irq; irq = irq_find_mapping(pp->irq_domain, pos0); if (!irq) @@ -297,7 +261,6 @@ static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos) clear_irq_range(pp, irq, i, pos0); goto no_valid_irq; } - set_bit(pos0 + i, pp->msi_irq_in_use); /*Enable corresponding interrupt in MSI interrupt controller */ if (pp->ops->msi_set_irq) pp->ops->msi_set_irq(pp, pos0 + i); @@ -313,53 +276,17 @@ no_valid_irq: return -ENOSPC; } -static void clear_irq(unsigned int irq) -{ - unsigned int pos, nvec; - struct msi_desc *msi; - struct pcie_port *pp; - struct irq_data *data = irq_get_irq_data(irq); - - /* get the port structure */ - msi = irq_data_get_msi(data); - pp = sys_to_pcie(msi->dev->bus->sysdata); - - /* undo what was done in assign_irq */ - pos = data->hwirq; - nvec = 1 << msi->msi_attrib.multiple; - - clear_irq_range(pp, irq, nvec, pos); - - /* all irqs cleared; reset attributes */ - msi->irq = 0; - msi->msi_attrib.multiple = 0; -} - 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; + int irq, pos; struct msi_msg msg; struct pcie_port *pp = sys_to_pcie(pdev->bus->sysdata); - pci_read_config_word(pdev, pdev->msi_cap + 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); + irq = assign_irq(1, desc, &pos); if (irq < 0) return irq; - /* - * write_msi_msg() will update PCI_MSI_FLAGS so there is - * no need to explicitly call pci_write_config_word(). - */ - desc->msi_attrib.multiple = msgvec; - if (pp->ops->get_msi_addr) msg.address_lo = pp->ops->get_msi_addr(pp); else @@ -378,7 +305,11 @@ static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev, static void dw_msi_teardown_irq(struct msi_chip *chip, unsigned int irq) { - clear_irq(irq); + struct irq_data *data = irq_get_irq_data(irq); + struct msi_desc *msi = irq_data_get_msi(data); + struct pcie_port *pp = sys_to_pcie(msi->dev->bus->sysdata); + + clear_irq_range(pp, irq, 1, data->hwirq); } static struct msi_chip dw_pcie_msi_chip = { |