diff options
author | Michael Ellerman <michael@ellerman.id.au> | 2012-02-12 09:28:20 -0500 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2012-02-13 23:01:39 -0500 |
commit | f1c853b53cf2b49eb32791072c8a8ee04f122f58 (patch) | |
tree | 203de9ee9f2ff6157c0f602f9cad0d3e254dff50 /arch/powerpc | |
parent | 6fe5f5f3ffade25aa94526010f219df3be521bf7 (diff) |
powerpc/powernv: Disable interrupts while taking phb->lock
We need to disable interrupts when taking the phb->lock. Otherwise
we could deadlock with pci_lock taken from an interrupt.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/platforms/powernv/pci.c | 22 |
1 files changed, 14 insertions, 8 deletions
diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c index a70bc1e385eb..f92b9ef7340e 100644 --- a/arch/powerpc/platforms/powernv/pci.c +++ b/arch/powerpc/platforms/powernv/pci.c | |||
@@ -52,32 +52,38 @@ static int pnv_msi_check_device(struct pci_dev* pdev, int nvec, int type) | |||
52 | 52 | ||
53 | static unsigned int pnv_get_one_msi(struct pnv_phb *phb) | 53 | static unsigned int pnv_get_one_msi(struct pnv_phb *phb) |
54 | { | 54 | { |
55 | unsigned int id; | 55 | unsigned long flags; |
56 | unsigned int id, rc; | ||
57 | |||
58 | spin_lock_irqsave(&phb->lock, flags); | ||
56 | 59 | ||
57 | spin_lock(&phb->lock); | ||
58 | id = find_next_zero_bit(phb->msi_map, phb->msi_count, phb->msi_next); | 60 | id = find_next_zero_bit(phb->msi_map, phb->msi_count, phb->msi_next); |
59 | if (id >= phb->msi_count && phb->msi_next) | 61 | if (id >= phb->msi_count && phb->msi_next) |
60 | id = find_next_zero_bit(phb->msi_map, phb->msi_count, 0); | 62 | id = find_next_zero_bit(phb->msi_map, phb->msi_count, 0); |
61 | if (id >= phb->msi_count) { | 63 | if (id >= phb->msi_count) { |
62 | spin_unlock(&phb->lock); | 64 | rc = 0; |
63 | return 0; | 65 | goto out; |
64 | } | 66 | } |
65 | __set_bit(id, phb->msi_map); | 67 | __set_bit(id, phb->msi_map); |
66 | spin_unlock(&phb->lock); | 68 | rc = id + phb->msi_base; |
67 | return id + phb->msi_base; | 69 | out: |
70 | spin_unlock_irqrestore(&phb->lock, flags); | ||
71 | return rc; | ||
68 | } | 72 | } |
69 | 73 | ||
70 | static void pnv_put_msi(struct pnv_phb *phb, unsigned int hwirq) | 74 | static void pnv_put_msi(struct pnv_phb *phb, unsigned int hwirq) |
71 | { | 75 | { |
76 | unsigned long flags; | ||
72 | unsigned int id; | 77 | unsigned int id; |
73 | 78 | ||
74 | if (WARN_ON(hwirq < phb->msi_base || | 79 | if (WARN_ON(hwirq < phb->msi_base || |
75 | hwirq >= (phb->msi_base + phb->msi_count))) | 80 | hwirq >= (phb->msi_base + phb->msi_count))) |
76 | return; | 81 | return; |
77 | id = hwirq - phb->msi_base; | 82 | id = hwirq - phb->msi_base; |
78 | spin_lock(&phb->lock); | 83 | |
84 | spin_lock_irqsave(&phb->lock, flags); | ||
79 | __clear_bit(id, phb->msi_map); | 85 | __clear_bit(id, phb->msi_map); |
80 | spin_unlock(&phb->lock); | 86 | spin_unlock_irqrestore(&phb->lock, flags); |
81 | } | 87 | } |
82 | 88 | ||
83 | static int pnv_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) | 89 | static int pnv_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) |